Jump to content
Tuts 4 You

How to read JSON correctly?


LCF-AT

Recommended Posts

Posted

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

Posted

Which language do you prefer ?

  • Like 1
Posted

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

  • Like 1
Posted

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

Posted (edited)

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
  • Like 1
Posted

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
Posted

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

Posted

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

Posted

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
Posted

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

Posted

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
Posted (edited)

wsprintf doesn't support floating point!

try swprintf

Edited by Kurapica
  • Like 1
Posted

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

Posted

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

Posted

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

Posted (edited)

spacer.png

spacer.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

Edited by fearless
update image links
  • Like 2
  • 1 year later...
Posted

I've updated the cjson (https://github.com/DaveGamble/cJSON) (previously libcjson v1.6.0) compiled static libraries to v1.7.12: https://github.com/mrfearless/libraries/tree/master/cJSON

Also I've moved the cjsontree x86 demo program to it's own repository: https://github.com/mrfearless/cjsontree (todo: x64 version)

Fixed a few bugs, and got it to output text based json for export and/or save using the cJSON_PrintBuffered api call. Previously I was trying to do this manually myself and it proved to be troublesome and overly complicated - for some reason I didn't see or know about the cJSON_Print api's.

 

  • Like 1
Posted

Hi fearless,

thanks for update.The save / export function is still not working in your example app to get changed / added stuff out.But for reading json files its really good tool I am also using.

PS: Is there also a download link only for that libs...

https://github.com/mrfearless/libraries/tree/master/cJSON

....without downloading all libs again?Just see there a DL button.

greetz

Posted

Ok thanks.

So if you just load any json into then change any entry to something else.Now if you save or export to file or clipboard then you still see the original entrys.Only if I add any new string with any text then it will saved but without the text I did entered.Only saved as <string> like this.Just test it a little with any json you have.Edit / add / delete etc and then save / export / clipboard and check the content.

greetz

Posted

Ok I think I know whats happening, the new JSON item is added to the previous stuff, but the assigned value of the integer, text or logical isnt being added or updated into the item. So edits wont show up and new items wont show anything cept the object but not its value.

Posted

tools tested&working with JSON :

  • Altova.XML Spy              altova.com/xmlspy-xml-editor
  • JSONBuddy              json-buddy.com
  • JSONedit              tomeko.net/software/JSONedit/
  • Mitec.JSON Viewer              mitec.cz/jsonv.html
  • XML ValidatorBuddy           xml-buddy.com/ValidatorBuddy.htm  

 

some online @ google.com/search?q=JSONedit

Posted (edited)

Ok so I fixed a few issues, was a good few more than I realized and maybe I added some more capability :D. Hopefully its in a better shape now. Still lots of features that I would like to add, in particular editing long string values - I had thought to display an edit box below the treeview when the item strings where larger than what the treeview natively displays for an item (256 characters max from what I recall), but we will see if I ever get round to adding in that.

Still likely there may be more bugs, but hopefully its a big more stable and capable. I consider cjsontree more of a demo/example program with source code to show how one might use the CJSON library:  https://github.com/DaveGamble/cJSON

Download and changelog for cjsontree is here: https://github.com/mrfearless/cjsontree/releases

Edited by fearless
paragraph
  • Like 2

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...