From 9fbf91db06a6d4f4b5cd8bb45389a731bb86bf22 Mon Sep 17 00:00:00 2001 From: Richard Date: Sun, 13 Apr 2025 18:48:02 +0100 Subject: initial --- site/udo/json.udo | 562 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 562 insertions(+) create mode 100755 site/udo/json.udo (limited to 'site/udo/json.udo') diff --git a/site/udo/json.udo b/site/udo/json.udo new file mode 100755 index 0000000..b0bdcd1 --- /dev/null +++ b/site/udo/json.udo @@ -0,0 +1,562 @@ +#ifndef UDO_JSON +#define UDO_JSON ## +/* + JSON formatting and parsing + + This file is part of the SONICS UDO collection by Richard Knight 2022 + License: GPL-2.0-or-later + http://1bpm.net + +*/ + +#include "/string_tools.udo" +#include "/array_tools.udo" + + +/* + Create a new empty JSON string + + Sjson json_init + + Sout empty JSON object/string +*/ +opcode json_init, S, 0 + xout "{}" +endop + + +/* + Append raw string to JSON string + + Sout json_append Sjson, StoAppend + + Sout string with appendage + Sjson input string to append to + StoAppend string to append +*/ +opcode json_append, S, SS + Sjson, StoAppend xin + ilen strlen Sjson + + Sjson = (ilen < 2) ? "{" : strsub(Sjson, 0, ilen-1) + Sout = sprintf("%s%s%s}", Sjson, (strlen(Sjson) == 1) ? "" : ",", StoAppend) + + xout Sout +endop + + +/* + Append JSON object string to JSON object string with key + + Sout json_appendobject Sjson, Skey, Svalue + + Sout string with appendage + Sjson input string to append to + Skey key for appending + Svalue value for appending +*/ +opcode json_appendobject, S, SSS + Sjson, Skey, Svalue xin + Sout = json_append(Sjson, sprintf("\"%s\":%s", Skey, Svalue)) + xout Sout +endop + + +/* + Append string to JSON object string with key + + Sout json_appendstring Sjson, Skey, Svalue + + Sout string with quoted appendage + Sjson input string to append to + Skey key for appending + Svalue value for appending +*/ +opcode json_appendstring, S, SSS + Sjson, Skey, Svalue xin + Sout = json_append(Sjson, sprintf("\"%s\":\"%s\"", Skey, Svalue)) + xout Sout +endop + + +/* + Append numeric value to JSON object string with key + + Sout json_appendvalue Sjson, Skey, ivalue + + Sout string with appendage + Sjson input string to append to + Skey key for appending + ivalue value for appending +*/ +opcode json_appendvalue, S, SSi + Sjson, Skey, ivalue xin + Sformat = (frac(ivalue) == 0) ? "\"%s\":%d" : "\"%s\":%f" + Sout = json_append(Sjson, sprintf(Sformat, Skey, ivalue)) + xout Sout +endop + + +/* + Append numeric array to JSON object string with key + + Sout json_appendarray Sjson, Skey, iarray[] + + Sout string with appendage + Sjson input string to append to + Skey key for appending + iarray[] array for appending +*/ +opcode json_appendarray, S, SSi[]o + Sjson, Skey, iarray[] xin + Sformatted = "" + ilen = lenarray(iarray) + index = 0 + while (index < ilen) do + ivalue = iarray[index] + Sformat = (frac(ivalue) == 0) ? "%d" : "%f" + Sformatted strcat Sformatted, sprintf(Sformat, ivalue) + if (index != ilen - 1) then + Sformatted strcat Sformatted, "," + endif + index += 1 + od + Sout = json_appendobject(Sjson, Skey, sprintf("[%s]", Sformatted)) + xout Sout +endop + + + +/* + Append string array to JSON object string with key + + Sout json_appendarray Sjson, Skey, Sarray[] + + Sout string with appendage + Sjson input string to append to + Skey key for appending + Sarray[] array for appending + iomitempty leave out empty strings +*/ +opcode json_appendarray, S, SSS[]o + Sjson, Skey, Sarray[], iomitempty xin + Sformatted = "" + ilen = lenarray(Sarray) + index = 0 + while (index < ilen) do + isempty = (strcmp(Sarray[index], "") == 0) ? 1 : 0 + if ((iomitempty == 0 && isempty == 1) || isempty == 0) then + Sformatted strcat Sformatted, sprintf("\"%s\",", Sarray[index]) + endif + index += 1 + od + + Sout = json_appendobject(Sjson, Skey, sprintf("[%s]", strsub(Sformatted, 0, strlen(Sformatted) - 1))) + xout Sout +endop + + +/* + Append f-table to JSON object string with key + + Sout json_appendtable Sjson, Skey, ifn + + Sout string with appendage + Sjson input string to append to + Skey key for appending + ifn f-table number +*/ +opcode json_appendtable, S, SSi + Sjson, Skey, ifn xin + Sformatted = "" + ilen = ftlen(ifn) + index = 0 + while (index < ilen) do + ivalue = table:i(index, ifn) + Sformat = (frac(ivalue) == 0) ? "%d" : "%f" + Sformatted strcat Sformatted, sprintf(Sformat, ivalue) + if (index != ilen - 1) then + Sformatted strcat Sformatted, "," + endif + index += 1 + od + Sout = json_appendobject(Sjson, Skey, sprintf("[%s]", Sformatted)) + xout Sout +endop + + + + +/* + Obtain an object, array or value from a json object given a string key + + itype, Stringvalue, inumericvalue json_parse Sjson, Skey + + itype type of returned value: 0=string, 1=object, 2=array, 3=numeric (1 and 2 are returned as strings for further parsing) + Stringvalue the requested value as a string + inumericvalue the numeric value if itype is 3 , otherwise -1 + + Sjson the json to parse + Skey the key to lookup +*/ +opcode json_parse, iSi, SS + Sjson, Skey xin + itype = -1 + index = 0 + idepth = 0 + idepthrequest = -1 + iobjectstart = -1 + inval = 0 + instring = 0 + inrequested = 0 + while (index < strlen(Sjson)) do + Schar = strsub(Sjson, index, index + 1) + if (strcmp(Schar, "[") == 0 && instring == 0) then + idepth += 1 + if (inrequested == 1 && iobjectstart == -1) then + iobjectstart = index + endif + + elseif (strcmp(Schar, "]") == 0 && instring == 0) then + idepth -= 1 + if (idepthrequest == idepth) then + itype = 2 + goto complete + endif + + elseif (strcmp(Schar, "{") == 0 && instring == 0) then + idepth += 1 + if (inrequested == 1 && iobjectstart == -1) then + iobjectstart = index + endif + + elseif (strcmp(Schar, "}") == 0 && instring == 0) then + idepth -= 1 + if (idepthrequest == idepth) then + itype = 1 + goto complete + endif + + elseif (strcmp(Schar, ":") == 0 && instring == 0) then + inval = 1 + iobjectstart = index + 1 + elseif (strcmp(Schar, ",") == 0 && instring == 0) then + if (inval == 1) then + inval = 0 + if (inrequested == 1 && idepthrequest == idepth) then + index -= 1 + itype = 3 + goto complete + endif + endif + elseif (strcmp(Schar, "\"") == 0) then + instring = 1 - instring + if (instring == 1) then + istringstart = index + 1 + else + String = strsub(Sjson, istringstart, index) + if (inrequested == 1 && idepthrequest == idepth) then + iobjectstart = istringstart + index -= 1 + itype = 0 + goto complete + elseif (strcmp(String, Skey) == 0) then + idepthrequest = idepth + inrequested = 1 + endif + endif + endif + index += 1 + od + +complete: + + Stringvalue = strsub(Sjson, iobjectstart, index+1) ; +1 required? + if (itype == 3) then + ivalid, inumericvalue try_strtod strstrip(Stringvalue) + itype = (ivalid == 1) ? 3 : 0 + endif + + + xout itype, Stringvalue, inumericvalue +endop + + +; itype: 0=S, 1=i +opcode _json_getarray, S[]i[], Si + Sjson, itype xin + index = 0 + instring = 0 + iobjectstart = -1 + iobjectcount = 0 + iwriteindex = 0 + + while (index < strlen(Sjson)) do + Schar = strsub(Sjson, index, index + 1) + if (strcmp(Schar, ",") == 0 && instring == 0) then + iobjectcount += 1 + elseif (strcmp(Schar, "\"") == 0) then + instring = 1 - instring + endif + index += 1 + od + + if (itype == 0) then + Soutput[] init iobjectcount + 1 + ioutput[] init 1 + else + Soutput[] init 1 + ioutput[] init iobjectcount + 1 + endif + index = 0 + instring = 0 + + while (index < strlen(Sjson)) do + Schar = strsub(Sjson, index, index + 1) + if (strcmp(Schar, ",") == 0 && instring == 0) then + if (itype == 1) then + ioutput[iwriteindex] = strtod(strsub(Sjson, iobjectstart, index)) + iobjectstart = index + 1 + endif + iwriteindex += 1 + elseif (strcmp(Schar, "[") == 0 && instring == 0) then + iobjectstart = index + 1 + elseif (strcmp(Schar, "]") == 0 && instring == 0) then + if (itype == 1) then + ioutput[iwriteindex] = strtod(strsub(Sjson, iobjectstart, index)) + endif + elseif (strcmp(Schar, "\"") == 0) then + if (instring == 0) then + iobjectstart = index + 1 + elseif (itype == 0) then + Svalue = strsub(Sjson, iobjectstart, index) + Soutput[iwriteindex] = Svalue + endif + instring = 1 - instring + endif + index += 1 + od + xout Soutput, ioutput +endop + +opcode json_getstringarray, S[], S + Sjson xin + Soutput[], i_[] _json_getarray Sjson, 0 + xout Soutput +endop + +opcode json_getnumericarray, i[], S + Sjson xin + S_[], ioutput[] _json_getarray Sjson, 1 + xout ioutput +endop + +/* + Obtain an object, array or value from a json array given an index + + itype, Stringvalue, inumericvalue json_parsearray Sjson, irequestindex + + itype type of returned value: 0=string, 1=object, 2=array, 3=numeric (1 and 2 are returned as strings for further parsing) + Stringvalue the requested value as a string + inumericvalue the numeric value if itype is 3 , otherwise -1 + + Sjson the json to parse + irequestindex index in the array to obtain +*/ +opcode json_parsearray, iSi, Si + Sjson, irequestindex xin + itype = -1 + inmainarray = 0 + index = 0 + iobjectstart = 0 + iscanindex = 0 + instring = 0 + idepth = 0 + while (index < strlen(Sjson)) do + Schar = strsub(Sjson, index, index + 1) + + if (strcmp(Schar, "[") == 0 && instring == 0) then + if (inmainarray == 0) then + inmainarray = 1 + iobjectstart = index + 1 + else + idepth += 1 + endif + + elseif (strcmp(Schar, "]") == 0 && instring == 0) then + if (inmainarray == 1 && idepth == 0) then + itype = 0 + goto complete + else + idepth -= 1 + itype = 2 + endif + + elseif (strcmp(Schar, "{") == 0 && inmainarray == 1 && instring == 0) then + idepth += 1 + + elseif (strcmp(Schar, "}") == 0 && inmainarray == 1 && instring == 0) then + idepth -= 1 + itype = 1 + + elseif (strcmp(Schar, ",") == 0 && idepth == 0 && inmainarray == 1 && instring == 0) then + if (iscanindex == irequestindex) then + itype = 0 + goto complete + endif + iobjectstart = index + 1 + iscanindex += 1 + + elseif (strcmp(Schar, "\"") == 0 && idepth == 0 && inmainarray == 1 && iscanindex == irequestindex) then + instring = 1 - instring + if (instring == 1) then + iobjectstart = index + 1 + else + itype = 0 + goto complete + endif + endif + + index += 1 + od + +complete: + + Stringvalue = strsub(Sjson, iobjectstart, index) + if (itype == 0) then + ivalid, inumericvalue try_strtod strstrip(Stringvalue) + itype = (ivalid == 1) ? 3 : 0 + endif + + + xout itype, Stringvalue, inumericvalue +endop + + + +/* + Get the length of a json array + + ilength json_arraylength Sjson + + ilength length determined + Sjson input array +*/ +opcode json_arraylength, i, S + Sjson xin + idepth = -1 + idepthmax = -1 + ihasitems = 0 + instring = 0 + index = 0 + itemnum = 0 + + while (index < strlen(Sjson)) do + Schar = strsub(Sjson, index, index + 1) + if (strcmp(Schar, "[") == 0 && instring == 0) then + idepth += 1 + idepthmax += 1 + + elseif (strcmp(Schar, "]") == 0 && instring == 0) then + idepth -= 1 + if (idepth < 0) then + goto complete + endif + + elseif (strcmp(Schar, "{") == 0 && instring == 0 && idepth >= 0) then + idepth += 1 + idepthmax += 1 + + elseif (strcmp(Schar, "}") == 0 && instring == 0 && idepth >= 0) then + idepth -= 1 + + elseif (strcmp(Schar, ",") == 0 && instring == 0 && idepth == 0) then + itemnum += 1 + + elseif (strcmp(Schar, "\"") == 0) then + if (idepth == 0) then + ihasitems = 1 + endif + instring = 1 - instring + endif + index += 1 + od + +complete: + if (idepthmax != 0 || ihasitems == 1) then + itemnum += 1 + endif + xout itemnum + +endop + + + + +/* + Get the keys from an object + + Skeys[] json_getkeys Sjson + + Skeys[] the keys found + Sjson input json +*/ +opcode json_getkeys, S[], S + Sjson xin + Stemp[] init 999 + + itempindex init 0 + idepth = -1 + instring = 0 + index = 0 + inmainobject = 0 + iskey = 1 + + while (index < strlen(Sjson)) do + Schar = strsub(Sjson, index, index + 1) + if (strcmp(Schar, "[") == 0 && instring == 0 && idepth >= 0) then + idepth += 1 + + elseif (strcmp(Schar, "]") == 0 && instring == 0 && idepth >= 0) then + idepth -= 1 + + elseif (strcmp(Schar, "{") == 0 && instring == 0) then + idepth += 1 + + elseif (strcmp(Schar, "}") == 0 && instring == 0) then + idepth -= 1 + if (idepth < 0) then + goto complete + endif + + elseif (strcmp(Schar, ":") == 0 && instring == 0 && idepth == 0) then + iskey = 0 + + elseif (strcmp(Schar, ",") == 0 && instring == 0 && idepth == 0) then + iskey = 1 + + elseif (strcmp(Schar, "\"") == 0 && idepth == 0) then + instring = 1 - instring + if (instring == 1) then + istringstart = index + 1 + elseif (iskey == 1) then + Stemp[itempindex] = strsub(Sjson, istringstart, index) + itempindex += 1 + endif + endif + index += 1 + od + +complete: + Skeys[] init itempindex ;+ 1 + index = 0 + while (index < itempindex) do + Skeys[index] = Stemp[index] + index += 1 + od + + xout Skeys +endop + + +#end -- cgit v1.2.3