Jump to content
Tuts 4 You
LCF-AT

How to read JSON correctly?

Rate this topic

Recommended Posts

LCF-AT

Hi guys,

I would like to code a JSON viewer and showing the datas as tree.The problem I have is that I dont know how to read the JSON markers inside correctly without to produce any handling errors to check whether its an object or array etc.So should I read the JSON content spot by spot and checking each one by signs { , [ ] } : etc?Or should I use any API etc?Just looking for a parse solution you know.Maybe you can tell me something about this and what could be a good method I could use later.

Thank you

Share this post


Link to post
Share on other sites
Kurapica

Which language do you prefer ?

  • Like 1

Share this post


Link to post
Share on other sites
mrexodia

You can try to use the jansson DLL @LCF-AT the interface is a bit annoying though...

  • Like 1

Share this post


Link to post
Share on other sites
LCF-AT

Hi guys,

which language - MASM. :)

Ok I found that jansson dll in your snapshot_2017-09-05_05-09\release\x32 package exodia.Also found that infos about it...

http://jansson.readthedocs.io/en/2.9/apiref.html

....but looks very massiv for me = Uhm! :) Not sure how to use that with wich API combo etc.

So the question is whether there is already anything I could use as that dll what does parse the whole JSON text for me and I just need to insert them into my treeview via (TVM_INSERTITEM) or etc what ever you know.Or I do it manually anyhow and check for that markers etc.

Example:

{
    "name":"John" ,
    "age":30,
    "cars": [
        { "name":"Ford", "models":[ "Fiesta", "Focus", "Mustang" ] },
        { "name":"BMW", "models":[ "320", "X3", "X5" ] },
        { "name":"Fiat", "models":[ "500", "Panda" ] }
    ]
 } 

So if I check that manually then I need first to check for object or array maker { or [ right.But also later its getting more bad to check for " and  commas + reading the lenght of the entrys + copy them one by one on free location & sending them via  TVM_INSERTITEM etc.So it dosent looks so simple to do that without to produce any possible erros anyhow.No idea so maybe I do think again wrong or just have no plan yet how to handle that smarter.Maybe you guys can show me how its done right / smart etc or something.

greetz

Share this post


Link to post
Share on other sites
atom0s

You can read the full specs/docs for JSON on its parent site here: http://www.json.org/

At the bottom of the main page is a large list of libraries for various languages to read and handle JSON files. I can't say I've ever seen an actual pure ASM implementation of JSON parsing, but you could just compile one of the various libs and just import the features as needed instead.

Edit - This may be useful, not sure of your requirements:

https://2ton.com.au/library_as_html/json.inc.html

Edited by atom0s (see edit history)
  • Like 1

Share this post


Link to post
Share on other sites
Kurapica

as atomo0s said, ?I haven't seen a native assembly implementation of a JSON engine.

you may find this useful too : https://github.com/DaveGamble/cJSON

you can link against it statically in masm.

  • Like 2

Share this post


Link to post
Share on other sites
LCF-AT

Hi again,

I think that dosent help me.No plan what I could use there etc.Only thing what I was looking for is anything like a API I could use pointing with the JSON text and as output I would get the splitet text + info what it is (object / array etc) so that I now just need to use sendmessage API with right paramters in struct to build my tree view.Anyway,so as always its again not a easy task or I dont get it again.I think I will try to parse it manually anyhow.

Does anyonw has a JSON text example what includes all possible stuff,I mean all what could be possible to add also that UNICODE thing etc I could check and test with my code to see whether all is going right later.

greetz

Share this post


Link to post
Share on other sites
fearless

I converted the cJSON.h file to an .inc file for masm usage, and compiled the library to a static one (which requires msvcrt as well - includes in the libcjson.inc file already)

Archive contains libcjson.inc, libcjson.lib, msvcrt.inc, msvcrt14.lib:

https://www.dropbox.com/s/2s59cnrfmu29dsh/libcjson.zip?dl=0

  • Like 2

Share this post


Link to post
Share on other sites
LCF-AT

Thanks for that fearless,but do you also know in which way to use it?

PS: I get that error again....

invoke cJSON_Parse, HEAD
-----------------------------------
error LNK2001: unresolved external symbol _cJSON_Parse
fatal error LNK1120: 1 unresolved externals

I did add inc & lib to my project.

greetz

Share this post


Link to post
Share on other sites
fearless

Ah yes, i forgot to change the PROTO declarations in the inc file (i had only tested cJSON_Version) have updated the inc file in the archive

https://www.dropbox.com/s/2s59cnrfmu29dsh/libcjson.zip?dl=0

 

.data

szSomeJSON              DB '{'
                        DB '    "name": "Jack (\"Bee\") Nimble",'
                        DB '    "format": {'
                        DB '        "type":       "rect",'
                        DB '        "width":      1920,'
                        DB '        "height":     1080,'
                        DB '        "interlace":  false,'
                        DB '        "frame rate": 24'
                        DB '    }'
                        DB '}',0

root                    DD 0
format                  DD 0
framerate_item          DD 0
framerate               DD 0

.code

        Invoke cJSON_Parse, Addr szSomeJSON
        mov root, eax

        Invoke cJSON_GetObjectItemCaseSensitive, root, CTEXT("format")
        mov format, eax

        Invoke cJSON_GetObjectItemCaseSensitive, format, CTEXT("frame rate")
        mov framerate_item, eax

        mov ebx, framerate_item
        mov eax, [ebx].cJSON.valueint
        mov framerate, eax

 

framerate contains 24 (i used donkeys vkim like debug macros to print values to confirm)
 

 

 

 

  • Thanks 1

Share this post


Link to post
Share on other sites
LCF-AT

Hi again,

ok thanks again for that example fearless.So I think in my case I only just need to use the cJSON_Parse function only to get all splitet and using the struct to check what it is etc.Ok,all clear so far about that.So now I have another 2 questions.

1.) So I see I get values as float (valuedouble) back if valueint = -1h.So I did forget again how to use wsprintf API with doubles to get the value as string back.Could you tell me later again?

2.) So if I read now all created structs made by cJSON_Parse function from top till bottom then I can also use sendmessage API & TV_INSERTSTRUCT to insert all entrys in my tree.As retrun I get a parent handle I can use to create another entys in next tree (+ maker you know etc) I can expand etc.Lets say I have 5 of them (trees to expand) during reading the JSON structs and now after that it goes back again where I need to insert new items in the tree before.So how to get the handle of that trees which was made before?

Example:

invoke  GetDlgItem,hWnd,IDC_TREEVIEW
mov edi,eax  ; Handle of tree = root

mov	tvis.hParent, 0
....
invoke	SendMessage, edi, TVM_INSERTITEM, 0, addr tvis
mov	tvis.hParent, eax ; new handle for new sub tree
invoke	SendMessage, edi, TVM_INSERTITEM, 0, addr tvis
mov	tvis.hParent, eax ; new handle for new sub tree
invoke	SendMessage, edi, TVM_INSERTITEM, 0, addr tvis
mov	tvis.hParent, eax ; new handle for new sub tree
invoke	SendMessage, edi, TVM_INSERTITEM, 0, addr tvis

Now above I have created another 3 sub trees into main tree using new handle I got.So what is if I want to get the pre handle or pre pre handle?How to do that?Lets say I do insert a array in any sub tree and if this is finished then I wanna add more stuff after that array in the tree before etc you know what I mean right?So I dont need to store all handles by myself extra or?Maybe you could point me to right direction how to handle that handle thing.Thanks again.

PS: Ok,so I just had removed the C declaration of all functions in the inc file then it works.So your new inc file was same as inc before. :)

greetz

Share this post


Link to post
Share on other sites
fearless

You just need to save the inserted treeview item handle for later reuse
 

; adjust tvis TVITEM for item to be inserted if required, like text etc
...
Invoke SendMessage, edi, TVM_INSERTITEM, 0, Addr tvis
mov hSubRoot1, eax
; adjust tvis TVITEM for item to be inserted if required, like text etc
...
Invoke SendMessage, edi, TVM_INSERTITEM, 0, Addr tvis
mov hSubRoot2, eax
; adjust tvis TVITEM for item to be inserted if required, like text etc
...
Invoke SendMessage, edi, TVM_INSERTITEM, 0, Addr tvis
mov hSubRoot3, eax

...

; later use the handles saved to add additional items under this subroot node
mov eax, hSubRoot2
mov tvis.hParent, eax
; adjust tvis TVITEM for text etc
...
Invoke SendMessage, edi, TVM_INSERTITEM, 0, Addr tvis

 

 

  • Like 1

Share this post


Link to post
Share on other sites
Kurapica

wsprintf doesn't support floating point!

try swprintf

Edited by Kurapica (see edit history)
  • Like 1

Share this post


Link to post
Share on other sites
LCF-AT

Hi again,

hmm good ok but what is if the hSubRoots are tons of them maybe 100?My goal was it not to save all sub handles extra you know.Is there no method to get the parent handle by child handle and getting pre parent by parent handle?If not then it seems I have to create a store array for all handles in a extra section.Of course not nice.

about swprintf API etc.What is the format (%xy?) I need to use?At the moment I use....FloatToStr2

valuedouble                 QWORD ?

cJSON.valuedouble
$ ==>    968A8000
$+4      424BF43C

invoke FloatToStr2,[ebx].cJSON.valuedouble,offset VALUESTRING
=
240123456789

....macro function but if I rememer right then it had any bug.

greetz

Share this post


Link to post
Share on other sites
LCF-AT

Hi,

ok thanks I will test that.

One more question about the cJSON structure.So I am not sure yet which way I should use to do the whole comparing stuff.

$ ==>    003E11A8   00000000 next
$+4      003E11AC   00000000 prev
$+8      003E11B0   003E11D8 child
$+C      003E11B4   00000040 itemtype
$+10     003E11B8   00000000 valuestring
$+14     003E11BC   00000000 valueint  
$+18     003E11C0   00000000 valuedouble
$+1C     003E11C4   00000000
$+20     003E11C8   00000000 itemstring

$ ==>    003E11D8   003E1238
$+4      003E11DC   00000000
$+8      003E11E0   00000000
$+C      003E11E4   00000010
$+10     003E11E8   003E1218  ASCII "Jack ("Bee") Nimble"
$+14     003E11EC   00000000
$+18     003E11F0   00000000
$+1C     003E11F4   00000000
$+20     003E11F8   003E1208  ASCII "name"

$ ==>    003E1238   00000000
$+4      003E123C   003E11D8
$+8      003E1240   003E1278
$+C      003E1244   00000040
$+10     003E1248   00000000
$+14     003E124C   00000000
$+18     003E1250   00000000
$+1C     003E1254   00000000
$+20     003E1258   003E1268  ASCII "format"

$ ==>    003E1278   003E12C8
$+4      003E127C   00000000
$+8      003E1280   00000000
$+C      003E1284   00000010
$+10     003E1288   003E12B8  ASCII "rect"
$+14     003E128C   00000000
$+18     003E1290   00000000
$+1C     003E1294   00000000
$+20     003E1298   003E12A8  ASCII "type"

$ ==>    003E12C8   003E1308
$+4      003E12CC   003E1278
$+8      003E12D0   00000000
$+C      003E12D4   00000008
$+10     003E12D8   00000000
$+14     003E12DC   00000780
$+18     003E12E0   00000000
$+1C     003E12E4   409E0000
$+20     003E12E8   003E12F8  ASCII "width"

$ ==>    003E1308   003E22B0
$+4      003E130C   003E12C8
$+8      003E1310   00000000
$+C      003E1314   00000008
$+10     003E1318   00000000
$+14     003E131C   00000438
$+18     003E1320   00000000
$+1C     003E1324   4090E000
$+20     003E1328   003E22A0  ASCII "height"

$ ==>    003E22B0   003E22F8
$+4      003E22B4   003E1308
$+8      003E22B8   00000000
$+C      003E22BC   00000001
$+10     003E22C0   00000000
$+14     003E22C4   00000000
$+18     003E22C8   00000000
$+1C     003E22CC   00000000
$+20     003E22D0   003E22E0  ASCII "interlace"

$ ==>    003E22F8   00000000
$+4      003E22FC   003E22B0
$+8      003E2300   00000000
$+C      003E2304   00000008
$+10     003E2308   00000000
$+14     003E230C   00000018
$+18     003E2310   00000000
$+1C     003E2314   40380000
$+20     003E2318   003E2328  ASCII "frame rate"

First I check for the itemtype.The first one is cJSON_Object but the rest is empty (does it mean I write nothing in that case?).Then it has a pointer to child starting next struct where I have a cJSON_String item inside etc.So if its an object then I could use...

invoke wsprintf,addr BUFFER,chr$("%s : [Object]"),[esi].cJSON.itemstring

...and for cJSON_String =

invoke wsprintf,addr BUFFER,chr$('%s : "%s"'),[esi].cJSON.itemstring,[esi].cJSON.valuestring

etc right?I am just a litte confused for building a right compare code to do nothing wrong you know.

So what is if I catch cJSON_Invalid = aboard entire process or jumping to next or child pointer if present and work go on?What about cJSON_Raw / cJSON_IsReference & cJSON_StringIsConst?I have no example JSON where I could catch that values after using cJSON_Parse to check out what it is and looks like to find out how to handle that etc.

greetz

Share this post


Link to post
Share on other sites
LCF-AT

Hi again,

ok I see its more complex to handle that compare stuff.Has anyone a idea how to do that during a walk through by all structs?So what about an array in a array etc?How to store all the infos like array counter if I need to handle another sub arrays etc?I am total confused now how to deal with that.I wrote that so far...

        .if     [esi].cJSON.itemtype == cJSON_Invalid
                invoke MessageBox,NULL,chr$("Invalid itemtype!"),chr$("Problem!"),MB_ICONWARNING
                jmp @F
                ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        
        .elseif [esi].cJSON.itemtype == cJSON_False
                invoke wsprintf,addr BUFFER,chr$("%s : false"),[esi].cJSON.itemstring
                lea eax, BUFFER
                m2m		tvis.item.pszText, eax
                invoke	SendMessage, TREEHANDLE, TVM_INSERTITEM, 0, addr tvis
        
        .elseif [esi].cJSON.itemtype == cJSON_True             
                invoke wsprintf,addr BUFFER,chr$("%s : true"),[esi].cJSON.itemstring
                lea eax, BUFFER
                m2m		tvis.item.pszText, eax
                invoke	SendMessage, TREEHANDLE, TVM_INSERTITEM, 0, addr tvis
        .elseif [esi].cJSON.itemtype == cJSON_NULL
                invoke wsprintf,addr BUFFER,chr$("%s : null"),[esi].cJSON.itemstring
                lea eax, BUFFER
                m2m		tvis.item.pszText, eax
                invoke	SendMessage, TREEHANDLE, TVM_INSERTITEM, 0, addr tvis
        
        .elseif [esi].cJSON.itemtype == cJSON_Number
                invoke FloatToStr2,[esi].cJSON.valuedouble,addr VALUEDOUBLE
                invoke wsprintf,addr BUFFER,chr$('%s : "%s"'),[esi].cJSON.itemstring,addr VALUEDOUBLE
                lea eax, BUFFER
                m2m		tvis.item.pszText, eax
                invoke	SendMessage, TREEHANDLE, TVM_INSERTITEM, 0, addr tvis
                
        .elseif [esi].cJSON.itemtype == cJSON_String
                invoke wsprintf,addr BUFFER,chr$('%s : "%s"'),[esi].cJSON.itemstring,[esi].cJSON.valuestring
                lea eax, BUFFER
                m2m		tvis.item.pszText, eax
                invoke	SendMessage, TREEHANDLE, TVM_INSERTITEM, 0, addr tvis
        
        .elseif [esi].cJSON.itemtype == cJSON_Array
                invoke wsprintf,addr BUFFER,chr$("%s : [Array]"),[esi].cJSON.itemstring
                lea eax, BUFFER
                m2m		tvis.item.pszText, eax
                invoke	SendMessage, TREEHANDLE, TVM_INSERTITEM, 0, addr tvis
        
        .elseif [esi].cJSON.itemtype == cJSON_Object
                invoke wsprintf,addr BUFFER,chr$("%s : [Object]"),[esi].cJSON.itemstring
                lea eax, BUFFER
                m2m		tvis.item.pszText, eax
                invoke	SendMessage, TREEHANDLE, TVM_INSERTITEM, 0, addr tvis
                
        
        .elseif [esi].cJSON.itemtype == cJSON_Raw
                nop
        .elseif [esi].cJSON.itemtype == cJSON_IsReference
                nop
        .elseif [esi].cJSON.itemtype == cJSON_StringIsConst
                nop
        .else
            invoke MessageBox,NULL,chr$("Unknown itemtype!"),chr$("Problem!"),MB_ICONWARNING
            jmp @F
        .endif
        
        
        .if     [esi].cJSON.next == NULL && [esi].cJSON.child == NULL && NEXT_COUNTER != 0h
                ; check pre next before and go on
                pop esi
                dec NEXT_COUNTER
                nop
        .elseif [esi].cJSON.next == NULL && [esi].cJSON.child == NULL && NEXT_COUNTER == 0h
                nop ; ende
                jmp @F
        .elseif [esi].cJSON.next != NULL && [esi].cJSON.child != NULL
                push [esi].cJSON.next
                inc NEXT_COUNTER
                push [esi].cJSON.child
                pop esi
        .elseif [esi].cJSON.child != NULL
                push [esi].cJSON.child
                pop esi
        .elseif [esi].cJSON.next != NULL
                push [esi].cJSON.next
                pop esi
        .endif        
        
        
        
        @@:
        invoke cJSON_Delete,ROOT

So I think I am on a wood path. :) Would be nice if anyone could help to build a simple compare code example.

greetz

Share this post


Link to post
Share on other sites
fearless

jsonviewer.png  jsonviewer0.png

I included the two test json files and uploaded the radasm project to dropbox and attached to this post

I commented some of the code to explain roughly whats happening. Might be other more efficient ways of traversing the json stuff and adding treeview items but hopefully it helps.

https://www.dropbox.com/s/7tnc5d8hbnx0sd5/cjsontree.zip?dl=0

cjsontree.zip

  • Like 2

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...