libcm is a C development framework with an emphasis on audio signal processing applications.
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080
  1. //| Copyright: (C) 2009-2020 Kevin Larke <contact AT larke DOT org>
  2. //| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file.
  3. #include "cmPrefix.h"
  4. #include "cmGlobal.h"
  5. #include "cmFloatTypes.h"
  6. #include "cmRpt.h"
  7. #include "cmErr.h"
  8. #include "cmCtx.h"
  9. #include "cmJson.h"
  10. #include "cmMem.h"
  11. #include "cmMallocDebug.h"
  12. #include "cmLex.h"
  13. #include "cmLinkedHeap.h"
  14. #include "cmFile.h"
  15. enum
  16. {
  17. kLCurlyLexTId = kUserLexTId+1,
  18. kRCurlyLexTId,
  19. kLHardLexTId,
  20. kRHardLexTId,
  21. kColonLexTId,
  22. kCommaLexTId,
  23. kTrueLexTId,
  24. kFalseLexTId,
  25. kNullLexTId
  26. };
  27. typedef struct
  28. {
  29. unsigned id;
  30. const char* text;
  31. } cmJsToken_t;
  32. // serialization buffer header
  33. typedef struct
  34. {
  35. unsigned id; // always set to 'json'
  36. unsigned byteCnt; // count of bytes following this field (total buf bytes = byteCnt + (2*sizeof(unsigned)))
  37. unsigned nodeCnt; // count of nodes in this buffer
  38. unsigned version; // buffer serialization version number
  39. } cmJsSerialHdr_t;
  40. // serialization helper record
  41. typedef struct
  42. {
  43. cmJsSerialHdr_t hdr;
  44. char* basePtr;
  45. char* nextPtr;
  46. char* endPtr;
  47. } cmJsSerial_t;
  48. // deserialization helper record
  49. typedef struct
  50. {
  51. unsigned nodeCnt;
  52. unsigned nodeIdx;
  53. const char* nextPtr;
  54. const char* endPtr;
  55. } cmJsDeserial_t;
  56. typedef struct
  57. {
  58. cmErr_t err; //
  59. cmLexH lexH; // parsing lexer
  60. cmLHeapH_t heapH; // linked heap stores all node memory
  61. cmJsonNode_t* rootPtr; // root of internal node tree
  62. cmJsonNode_t* basePtr; // base of parsing stack
  63. cmJsonNode_t* lastPtr; // top of parsing stack
  64. cmJsRC_t rc; // last error code
  65. char* serialBufPtr; // serial buffer pointer
  66. unsigned serialByteCnt; // count of bytes in serialBuf[]
  67. bool reportErrPosnFl;// report the file posn of syntax errors
  68. bool modifiedFl; // the tree has been modified since it was created.
  69. } cmJs_t;
  70. cmJsToken_t _cmJsTokenArray[] =
  71. {
  72. { kLCurlyLexTId, "{" },
  73. { kRCurlyLexTId, "}" },
  74. { kLHardLexTId, "[" },
  75. { kRHardLexTId, "]" },
  76. { kColonLexTId, ":" },
  77. { kCommaLexTId, "," },
  78. { kTrueLexTId, "true"},
  79. { kFalseLexTId, "false"},
  80. { kNullLexTId, "null" },
  81. { kErrorLexTId,""}
  82. };
  83. cmJsToken_t _cmJsNodeTypeLabel[] =
  84. {
  85. { kObjectTId, "object" },
  86. { kPairTId, "pair" },
  87. { kArrayTId, "array" },
  88. { kStringTId, "string" },
  89. { kIntTId, "int" },
  90. { kRealTId, "real" },
  91. { kNullTId, "null" },
  92. { kTrueTId, "true" },
  93. { kFalseTId, "false" },
  94. { kInvalidTId,"invalid"}
  95. };
  96. cmJsonH_t cmJsonNullHandle = cmSTATIC_NULL_HANDLE;
  97. cmJsRC_t _cmJsonRemoveNode( cmJs_t* p, cmJsonNode_t* np, bool freeFl, bool balancePairsFl );
  98. void _cmJsonFreeNode( cmJs_t* p, cmJsonNode_t* np);
  99. const char* _cmJsonNodeTypeIdToLabel( unsigned nodeTypeId )
  100. {
  101. unsigned i;
  102. for(i=0; _cmJsNodeTypeLabel[i].id != kInvalidTId; ++i)
  103. if( _cmJsNodeTypeLabel[i].id == nodeTypeId )
  104. break;
  105. return _cmJsNodeTypeLabel[i].text;
  106. }
  107. unsigned _cmJsonNodeTypeLabelToId( const char* typeLabel )
  108. {
  109. unsigned i;
  110. for(i=0; _cmJsNodeTypeLabel[i].id != kInvalidTId; ++i)
  111. if( strcmp(_cmJsNodeTypeLabel[i].text,typeLabel) == 0 )
  112. break;
  113. return _cmJsNodeTypeLabel[i].id;
  114. }
  115. cmJs_t* _cmJsonHandleToPtr( cmJsonH_t h )
  116. {
  117. cmJs_t* p = (cmJs_t*)h.h;
  118. assert(p != NULL);
  119. p->rc = kOkJsRC;
  120. return p;
  121. }
  122. cmJsRC_t _cmJsonError( cmJs_t* p, cmJsRC_t rc, const char* fmt, ... )
  123. {
  124. va_list vl;
  125. va_start(vl,fmt);
  126. rc = cmErrVMsg(&p->err,rc,fmt,vl);
  127. va_end(vl);
  128. return rc;
  129. }
  130. cmJsRC_t _cmJsonSyntaxError( cmJs_t* p, const char* fmt, ... )
  131. {
  132. int bn = 1024;
  133. char buf[bn+1];
  134. buf[0]=0;
  135. buf[bn]=0;
  136. va_list vl;
  137. va_start(vl,fmt);
  138. if( p->reportErrPosnFl )
  139. snprintf(buf,bn,"Syntax error on line:%i column:%i. ",cmLexCurrentLineNumber(p->lexH),cmLexCurrentColumnNumber(p->lexH));
  140. int n = strlen(buf);
  141. vsnprintf(buf+n,bn-n,fmt,vl);
  142. va_end(vl);
  143. return cmErrMsg(&p->err,kSyntaxErrJsRC,"%s",buf);
  144. }
  145. // Note that the stack is formed by a linked list
  146. // which is chained together using the nodes parentPtr.
  147. // This works beacause the parentPtr for object,array,
  148. // and pair nodes (the only nodes on the stack) is not
  149. // needed as long as the node is on the stack. Once the
  150. // node is popped the parentPtr is then set from the
  151. // new stack top.
  152. cmJsRC_t _cmJsonPushNode( cmJs_t* p, cmJsonNode_t* np )
  153. {
  154. np->ownerPtr = p->lastPtr;
  155. p->lastPtr = np;
  156. if( p->basePtr == NULL )
  157. p->basePtr = np;
  158. return kOkJsRC;
  159. }
  160. cmJsRC_t _cmJsonPopNode( cmJs_t* p )
  161. {
  162. if( p->lastPtr == NULL )
  163. return _cmJsonSyntaxError(p,"A parser stack underlow signalled a syntax error.");
  164. cmJsonNode_t* t = p->lastPtr;
  165. // remove the top element
  166. p->lastPtr = p->lastPtr->ownerPtr;
  167. // set the parent of the popped node
  168. t->ownerPtr = p->lastPtr;
  169. if( p->lastPtr == NULL )
  170. p->basePtr = NULL;
  171. return kOkJsRC;
  172. }
  173. cmJsRC_t cmJsonInitialize( cmJsonH_t* hp, cmCtx_t* ctx )
  174. {
  175. cmJsRC_t rc;
  176. cmJs_t* p;
  177. unsigned i;
  178. // finalize before initialize
  179. if((rc = cmJsonFinalize(hp)) != kOkJsRC )
  180. return rc;
  181. // allocate the main object record
  182. if((p = cmMemAllocZ( cmJs_t, 1 )) == NULL )
  183. return cmErrMsg(&ctx->err,kMemAllocErrJsRC,"Object memory allocation failed.");
  184. cmErrSetup(&p->err,&ctx->rpt,"JSON Parser");
  185. // allocate the linked heap mgr
  186. if( cmLHeapIsValid(p->heapH = cmLHeapCreate(1024,ctx)) == false )
  187. {
  188. rc = _cmJsonError(p,kMemAllocErrJsRC,"Linked heap object allocation failed.");
  189. goto errLabel;
  190. }
  191. // allocate the lexer
  192. if(cmLexIsValid(p->lexH = cmLexInit(NULL,0,0,&ctx->rpt)) == false )
  193. {
  194. rc = _cmJsonError(p,kLexErrJsRC,"Lex allocation failed.");
  195. goto errLabel;
  196. }
  197. // register json specific tokens with the lexer
  198. for(i=0; _cmJsTokenArray[i].id != kErrorLexTId; ++i)
  199. {
  200. cmRC_t lexRC;
  201. if( (lexRC = cmLexRegisterToken(p->lexH, _cmJsTokenArray[i].id, _cmJsTokenArray[i].text )) != kOkLexRC )
  202. {
  203. rc = _cmJsonError(p,kLexErrJsRC,"Lex token registration failed for:'%s'.\nLexer Error:%s",_cmJsTokenArray[i].text, cmLexRcToMsg(lexRC) );
  204. goto errLabel;
  205. }
  206. }
  207. hp->h = p;
  208. return kOkJsRC;
  209. errLabel:
  210. cmMemPtrFree(&p);
  211. if( cmLHeapIsValid(p->heapH) )
  212. cmLHeapDestroy(&p->heapH);
  213. if( cmLexIsValid(p->lexH) )
  214. cmLexFinal(&p->lexH);
  215. return rc;
  216. }
  217. cmJsRC_t cmJsonInitializeFromFile( cmJsonH_t* hp, const char* fn, cmCtx_t* ctx )
  218. {
  219. cmJsRC_t jsRC;
  220. if((jsRC = cmJsonInitialize(hp,ctx)) != kOkJsRC )
  221. return jsRC;
  222. if((jsRC = cmJsonParseFile(*hp,fn,NULL)) != kOkJsRC )
  223. cmJsonFinalize(hp);
  224. return jsRC;
  225. }
  226. cmJsRC_t cmJsonInitializeFromBuf( cmJsonH_t* hp, cmCtx_t* ctx, const char* buf, unsigned bufByteCnt )
  227. {
  228. cmJsRC_t jsRC;
  229. if((jsRC = cmJsonInitialize(hp,ctx)) != kOkJsRC )
  230. return jsRC;
  231. if((jsRC = cmJsonParse(*hp,buf,bufByteCnt,NULL)) != kOkJsRC )
  232. cmJsonFinalize(hp);
  233. return jsRC;
  234. }
  235. cmJsRC_t cmJsonFinalize( cmJsonH_t* hp )
  236. {
  237. cmRC_t lexRC;
  238. if( hp == NULL || hp->h == NULL )
  239. return kOkJsRC;
  240. cmJs_t* p = _cmJsonHandleToPtr(*hp);
  241. // free the internal heap object
  242. cmLHeapDestroy( &p->heapH );
  243. // free the lexer
  244. if( cmLexIsValid(p->lexH) )
  245. if((lexRC = cmLexFinal(&p->lexH)) != kOkLexRC )
  246. return _cmJsonError(p,kLexErrJsRC,"Lexer finalization failed.\nLexer Error:%s",cmLexRcToMsg(lexRC));
  247. cmMemPtrFree(&p->serialBufPtr);
  248. // free the handle
  249. cmMemPtrFree(&hp->h);
  250. return kOkJsRC;
  251. }
  252. bool cmJsonIsValid( cmJsonH_t h )
  253. { return h.h != NULL; }
  254. bool cmJsonIsModified( cmJsonH_t h )
  255. {
  256. cmJs_t* p = _cmJsonHandleToPtr(h);
  257. return p->modifiedFl;
  258. }
  259. cmJsRC_t _cmJsonLinkInChild( cmJs_t* p, cmJsonNode_t* parentPtr, cmJsonNode_t* np )
  260. {
  261. cmJsRC_t rc = kOkJsRC;
  262. np->ownerPtr = parentPtr;
  263. switch( parentPtr->typeId )
  264. {
  265. case kObjectTId:
  266. case kArrayTId:
  267. case kPairTId:
  268. {
  269. // if the parent is an 'object' then the child must be a 'pair'
  270. if( parentPtr->typeId == kObjectTId && np->typeId != kPairTId )
  271. rc = _cmJsonSyntaxError(p,"Expect only 'pair' nodes as children of 'objects'.");
  272. // if the parent is a 'pair' then is may have a max of two children
  273. if( parentPtr->typeId == kPairTId && cmJsonChildCount(parentPtr) >= 2 )
  274. rc = _cmJsonSyntaxError(p,"'pair' nodes may only have 2 children.");
  275. // insert the new node into the parent child list
  276. // if the new node is the first child
  277. if( parentPtr->u.childPtr == NULL )
  278. parentPtr->u.childPtr = np;
  279. else
  280. {
  281. // if the new node is the second or greater child
  282. cmJsonNode_t* lp = parentPtr->u.childPtr;
  283. while( lp->siblingPtr != NULL )
  284. lp = lp->siblingPtr;
  285. lp->siblingPtr = np;
  286. }
  287. }
  288. break;
  289. default:
  290. rc = _cmJsonSyntaxError(p,"'%s' nodes cannot be parent nodes.",_cmJsonNodeTypeIdToLabel(parentPtr->typeId));
  291. break;
  292. }
  293. return rc;
  294. }
  295. // This function creates nodes it also:
  296. // 1. inserts array elments into their parents child list
  297. // 2. inserts pairs into their parents member list
  298. // 3. assigns values to pairs
  299. cmJsRC_t _cmJsonCreateNode( cmJs_t* p, cmJsonNode_t* parentPtr, unsigned newNodeTypeId, cmJsonNode_t** npp )
  300. {
  301. cmJsRC_t rc = kOkJsRC;
  302. cmJsonNode_t* np;
  303. assert( npp != NULL );
  304. *npp = NULL;
  305. // allocate the new node
  306. if((np = cmLHeapAllocZ( p->heapH, sizeof(cmJsonNode_t) )) == NULL )
  307. return _cmJsonError(p,kMemAllocErrJsRC,"Error allocating node memory.");
  308. // set the new node type
  309. np->typeId = newNodeTypeId;
  310. np->ownerPtr = parentPtr;
  311. if( parentPtr == NULL )
  312. {
  313. if( newNodeTypeId != kObjectTId && newNodeTypeId != kArrayTId )
  314. rc = _cmJsonSyntaxError(p,"'%s' nodes must have a parent node.",_cmJsonNodeTypeIdToLabel(newNodeTypeId));
  315. }
  316. else
  317. {
  318. // if the parent is an 'object', 'array', or 'pair' then the
  319. // new node must be a child - insert it into the parent child list
  320. if((rc = _cmJsonLinkInChild( p, parentPtr, np )) != kOkJsRC )
  321. return rc;
  322. switch( newNodeTypeId )
  323. {
  324. case kObjectTId:
  325. case kArrayTId:
  326. break;
  327. case kPairTId:
  328. if( parentPtr == NULL || parentPtr->typeId != kObjectTId )
  329. rc = _cmJsonSyntaxError(p,"'pair' nodes must be the child of an object 'node'.");
  330. break;
  331. default:
  332. if( parentPtr == NULL )
  333. rc = _cmJsonSyntaxError(p,"'%s' nodes must have parent nodes.",_cmJsonNodeTypeIdToLabel(newNodeTypeId));
  334. }
  335. }
  336. // assign the return value
  337. *npp = np;
  338. if( p->rootPtr == NULL)
  339. {
  340. if( np->typeId != kObjectTId && np->typeId != kArrayTId )
  341. rc = _cmJsonSyntaxError(p,"The root object must be an 'object' or 'array'.");
  342. p->rootPtr = np;
  343. }
  344. p->modifiedFl = true;
  345. return rc;
  346. }
  347. cmJsRC_t _cmJsonCreateNumber( cmJs_t* p, cmJsonNode_t* parentPtr, unsigned nodeTId, cmJsonNode_t** npp )
  348. {
  349. // numbers may only occurr as children of a 'pair' or element of an 'array'
  350. if( (parentPtr==NULL) || (parentPtr->typeId != kPairTId && parentPtr->typeId != kArrayTId) )
  351. return _cmJsonSyntaxError(p, "The parent of scalar:%*s is not a 'pair' or 'array'.", cmLexTokenCharCount(p->lexH), cmLexTokenText(p->lexH) );
  352. return _cmJsonCreateNode(p,parentPtr,nodeTId,npp);
  353. }
  354. cmJsRC_t _cmJsonCreateReal(cmJs_t* p, cmJsonNode_t* parentPtr, double v, cmJsonNode_t** newNodePtrPtr )
  355. {
  356. cmJsRC_t rc;
  357. cmJsonNode_t* np = NULL;
  358. if( newNodePtrPtr != NULL )
  359. *newNodePtrPtr = NULL;
  360. if((rc= _cmJsonCreateNumber(p,parentPtr,kRealTId,&np)) == kOkJsRC )
  361. {
  362. np->u.realVal = v;
  363. if( newNodePtrPtr != NULL)
  364. *newNodePtrPtr = np;
  365. }
  366. return rc;
  367. }
  368. cmJsRC_t _cmJsonCreateInt(cmJs_t* p, cmJsonNode_t* parentPtr, int v, cmJsonNode_t** newNodePtrPtr )
  369. {
  370. cmJsRC_t rc;
  371. cmJsonNode_t* np = NULL;
  372. if( newNodePtrPtr != NULL )
  373. *newNodePtrPtr = NULL;
  374. if((rc= _cmJsonCreateNumber(p,parentPtr,kIntTId,&np)) == kOkJsRC )
  375. {
  376. np->u.intVal = v;
  377. if( newNodePtrPtr != NULL )
  378. *newNodePtrPtr = np;
  379. }
  380. return rc;
  381. }
  382. cmJsRC_t _cmJsonCreateBool(cmJs_t* p, cmJsonNode_t* parentPtr, bool fl, cmJsonNode_t** newNodePtrPtr )
  383. {
  384. cmJsRC_t rc;
  385. cmJsonNode_t* np = NULL;
  386. if( newNodePtrPtr != NULL )
  387. *newNodePtrPtr = NULL;
  388. if((rc= _cmJsonCreateNumber(p,parentPtr,fl?kTrueTId:kFalseTId,&np)) == kOkJsRC )
  389. {
  390. np->u.boolVal = fl;
  391. if( newNodePtrPtr != NULL )
  392. *newNodePtrPtr = np;
  393. }
  394. return rc;
  395. }
  396. cmJsRC_t _cmJsonCreateNull(cmJs_t* p, cmJsonNode_t* parentPtr, cmJsonNode_t** newNodePtrPtr )
  397. {
  398. cmJsRC_t rc;
  399. cmJsonNode_t* np = NULL;
  400. if( newNodePtrPtr != NULL )
  401. *newNodePtrPtr = NULL;
  402. if((rc = _cmJsonCreateNumber(p,parentPtr,kNullTId,&np)) == kOkJsRC )
  403. {
  404. if( newNodePtrPtr != NULL )
  405. *newNodePtrPtr = np;
  406. }
  407. return rc;
  408. }
  409. cmJsRC_t _cmJsonEscapeInt( cmJs_t* p, const char* sp, unsigned i, unsigned n, unsigned hexDigitCnt, char* rp )
  410. {
  411. char buf[hexDigitCnt+1];
  412. memset(buf,0,hexDigitCnt+1);
  413. // fill buf[] with the next two characters
  414. unsigned j;
  415. for(j=0; i<n && j<hexDigitCnt; ++i,++j)
  416. buf[j] = sp[i];
  417. // be sure the buffer was filled - we must get exactly two characters
  418. if( i == n )
  419. return _cmJsonError(p,kInvalidHexEscapeJsRC,"An invalid hex escape code was encountered.");
  420. // do the text to int conversion
  421. errno = 0;
  422. long val = strtol(buf,NULL,16);
  423. // validate the conversion
  424. if( errno != 0 )
  425. return _cmJsonError(p,kInvalidHexEscapeJsRC,"Hex escape value conversion failed.");
  426. // convert the long to a character
  427. if( val > 0xff )
  428. return _cmJsonError(p,kInvalidHexEscapeJsRC,"Hex escape value is out of range (0x00-0xff).");
  429. *rp = (char)val;
  430. return kOkJsRC;
  431. }
  432. cmJsRC_t _cmJsonEscapeString( cmJs_t* p, char* dp, const char* sp, unsigned n )
  433. {
  434. cmJsRC_t rc;
  435. unsigned hexDigCnt = 2; // count of digits in \u notation
  436. unsigned i,j;
  437. for(i=0,j=0; i<n; ++i,++j)
  438. {
  439. if( (sp[i] == '\\') && (i<(n-1) ))
  440. {
  441. switch( sp[i+1] )
  442. {
  443. case 'b': dp[j] = '\b'; break;
  444. case 'f': dp[j] = '\f'; break;
  445. case 'n': dp[j] = '\n'; break;
  446. case 'r': dp[j] = '\r'; break;
  447. case 't': dp[j] = '\t'; break;
  448. case 'u':
  449. {
  450. if((rc = _cmJsonEscapeInt( p, sp, i+2, n, hexDigCnt, dp+j )) != kOkJsRC )
  451. return rc;
  452. i += hexDigCnt; // skip hex digits
  453. }
  454. break;
  455. default:
  456. dp[j] = sp[i+1];
  457. break;
  458. }
  459. ++i; // skip the escape character '\'
  460. }
  461. else
  462. {
  463. dp[j] = sp[i];
  464. }
  465. }
  466. if( j < n )
  467. dp[j] = 0;
  468. return kOkJsRC;
  469. }
  470. // if 'cp' is NULL or 'cn' is 0 then the current string is dealloc'd
  471. // and the internal string value is left as NULL.
  472. cmJsRC_t _cmJsonSetString( cmJs_t* p, cmJsonNode_t* np, const char* cp, unsigned cn )
  473. {
  474. assert( np->typeId == kStringTId );
  475. cmJsRC_t rc = kOkJsRC;
  476. // deallocate the current string
  477. if( np->u.stringVal != NULL )
  478. {
  479. cmLHeapFree(p->heapH,np->u.stringVal);
  480. np->u.stringVal = NULL;
  481. }
  482. if( cp != NULL && cn>0 )
  483. {
  484. // allocate the node data memory to hold the string
  485. if((np->u.stringVal = cmLHeapAllocZ(p->heapH,cn+1)) == NULL )
  486. return _cmJsonError(p,kMemAllocErrJsRC,"Unable to allocate stirng memory.");
  487. // copy the string into the node data memory
  488. if((rc = _cmJsonEscapeString(p, np->u.stringVal, cp, cn)) != kOkJsRC )
  489. return rc;
  490. np->u.stringVal[cn]=0;
  491. }
  492. return rc;
  493. }
  494. cmJsRC_t _cmJsonCreateString(cmJs_t* p, cmJsonNode_t* parentPtr, const char* cp, unsigned cn, cmJsonNode_t** newNodePtrPtr )
  495. {
  496. cmJsRC_t rc;
  497. cmJsonNode_t* np = NULL;
  498. if( newNodePtrPtr != NULL )
  499. *newNodePtrPtr = NULL;
  500. // strings may only occurr as children of a 'pair' or element of an 'array'
  501. if( (parentPtr->typeId != kPairTId && parentPtr->typeId != kArrayTId ) )
  502. return _cmJsonSyntaxError(p, "The parent of string:%*s is not a 'pair', 'array', or 'object'.", cn,cp);
  503. // create the new node
  504. if((rc = _cmJsonCreateNode(p,parentPtr,kStringTId,&np)) != kOkJsRC )
  505. return rc;
  506. if((rc = _cmJsonSetString(p,np,cp,cn)) != kOkJsRC )
  507. return rc;
  508. /*
  509. // allocate the node data memory to hold the string
  510. if((np->u.stringVal = cmLHeapAllocZ(p->heapH,cn+1)) == NULL )
  511. return _cmJsonError(p,kMemAllocErrJsRC,"Unable to allocate stirng memory.");
  512. if((rc = _cmJsonEscapeString(p, np->u.stringVal, cp, cn)) != kOkJsRC )
  513. return rc;
  514. // copy the string into the node data memory
  515. //strncpy(np->u.stringVal,cp,cn);
  516. np->u.stringVal[cn]=0;
  517. */
  518. if( newNodePtrPtr != NULL )
  519. *newNodePtrPtr = np;
  520. return rc;
  521. }
  522. cmJsRC_t _cmJsonCreatePair( cmJs_t* p, cmJsonNode_t* parentPtr, const char* label, cmJsonNode_t** newNodePtrPtr )
  523. {
  524. cmJsRC_t rc;
  525. if((rc = _cmJsonCreateNode(p,parentPtr,kPairTId,newNodePtrPtr)) != kOkJsRC )
  526. return rc;
  527. return _cmJsonCreateString( p, *newNodePtrPtr, label, strlen(label), NULL);
  528. }
  529. // if fn == NULL then the buffer must contain the text to parse
  530. cmJsRC_t _cmJsonParse(cmJsonH_t h, const char* buf, unsigned bufCharCnt, const cmChar_t* fn, cmJsonNode_t* altRootPtr )
  531. {
  532. unsigned lexTId = kErrorLexTId;
  533. cmJs_t* p = _cmJsonHandleToPtr(h);
  534. cmJsonNode_t* cnp = altRootPtr == p->rootPtr ? altRootPtr : p->rootPtr;
  535. cmJsonNode_t* nnp = NULL;
  536. cmJsRC_t rc;
  537. p->reportErrPosnFl = true;
  538. // assign the text buffer and reset the lexer
  539. if( fn == NULL )
  540. rc = cmLexSetTextBuffer( p->lexH, buf, bufCharCnt );
  541. else
  542. rc = cmLexSetFile( p->lexH, fn );
  543. if( rc != kOkLexRC )
  544. return _cmJsonError( p, kLexErrJsRC, "Error setting lexer buffer.");
  545. // get the next token
  546. while( (lexTId = cmLexGetNextToken( p->lexH )) != kErrorLexTId && (lexTId != kEofLexTId ) && (rc==kOkJsRC) )
  547. {
  548. cnp = p->lastPtr;
  549. // if cnp is a pair and it's value has been assigned
  550. if( cnp != NULL && cnp->typeId == kPairTId && cmJsonChildCount(cnp)==2 )
  551. {
  552. if((rc = _cmJsonPopNode(p)) != kOkJsRC )
  553. break;
  554. cnp = p->lastPtr;
  555. }
  556. switch( lexTId )
  557. {
  558. case kRealLexTId: // real number
  559. rc = _cmJsonCreateReal(p, cnp, cmLexTokenDouble( p->lexH ), NULL);
  560. break;
  561. case kHexLexTId: // hexidecimal integer
  562. // allow hex integers to be equivalent to decimal integers
  563. case kIntLexTId: // decimal integer
  564. rc = _cmJsonCreateInt(p, cnp, cmLexTokenInt( p->lexH ), NULL );
  565. break;
  566. case kTrueLexTId: // true
  567. rc = _cmJsonCreateBool(p, cnp, true, NULL );
  568. break;
  569. case kFalseLexTId: // false
  570. rc = _cmJsonCreateBool(p, cnp, false, NULL );
  571. break;
  572. case kNullLexTId: // null
  573. rc = _cmJsonCreateNull(p, cnp, NULL );
  574. break;
  575. case kIdentLexTId: // identifier
  576. // allow identifiers to be equivalent to strings.
  577. case kQStrLexTId: // quoted string
  578. if( cnp == NULL )
  579. rc = _cmJsonSyntaxError(p,"Encountered a 'string' with no parent.");
  580. else
  581. if( cnp->typeId == kObjectTId )
  582. {
  583. if((rc = _cmJsonCreateNode(p,cnp,kPairTId,&nnp)) == kOkJsRC )
  584. {
  585. _cmJsonPushNode(p,nnp);
  586. cnp = nnp;
  587. }
  588. //if((rc = _cmJsonCreateNewParent(p,cnp,kPairTId)) == kOkJsRC )
  589. // cnp = p->lastPtr;
  590. }
  591. if( rc == kOkJsRC )
  592. rc = _cmJsonCreateString(p, cnp, cmLexTokenText(p->lexH), cmLexTokenCharCount(p->lexH), NULL);
  593. break;
  594. case kColonLexTId:
  595. if( cnp->typeId != kPairTId )
  596. rc = _cmJsonSyntaxError(p,"A colon was found outside of a 'pair' element.");
  597. break;
  598. case kLCurlyLexTId: // {
  599. //rc = _cmJsonCreateNewParent(p, cnp, kObjectTId );
  600. if((rc = _cmJsonCreateNode(p,cnp,kObjectTId,&nnp)) == kOkJsRC )
  601. _cmJsonPushNode(p,nnp);
  602. break;
  603. case kRCurlyLexTId: // }
  604. if( cnp == NULL || cnp->typeId != kObjectTId )
  605. rc = _cmJsonSyntaxError(p,"A '}' was found without an accompanying opening bracket.");
  606. else
  607. rc = _cmJsonPopNode(p);
  608. break;
  609. case kLHardLexTId: // [
  610. //rc = _cmJsonCreateNewParent(p, cnp, kArrayTId);
  611. if((rc = _cmJsonCreateNode(p,cnp,kArrayTId,&nnp)) == kOkJsRC )
  612. _cmJsonPushNode(p,nnp);
  613. break;
  614. case kRHardLexTId: // ]
  615. if( cnp == NULL || cnp->typeId != kArrayTId )
  616. rc = _cmJsonSyntaxError(p,"A ']' was found without an accompanying opening bracket.");
  617. else
  618. rc = _cmJsonPopNode(p);
  619. break;
  620. case kCommaLexTId: // ,
  621. if( (cnp==NULL) || (cnp->typeId != kArrayTId && cnp->typeId != kObjectTId) )
  622. rc = _cmJsonSyntaxError(p,"Commas may only occur in 'array' and 'object' nodes.");
  623. break;
  624. case kSpaceLexTId: // white space
  625. case kBlockCmtLexTId: // block comment
  626. case kLineCmtLexTId: // line comment
  627. assert(0);
  628. break;
  629. default:
  630. break;
  631. }
  632. }
  633. if( lexTId == kErrorLexTId )
  634. rc = _cmJsonSyntaxError( p, "The lexer failed: %s.", cmLexRcToMsg(cmLexErrorRC(p->lexH)));
  635. p->reportErrPosnFl = false;
  636. p->modifiedFl = false;
  637. return rc;
  638. }
  639. cmJsRC_t cmJsonParse( cmJsonH_t h, const char* buf, unsigned bufCharCnt, cmJsonNode_t* altRootPtr )
  640. { return _cmJsonParse(h,buf,bufCharCnt,NULL,altRootPtr); }
  641. cmJsRC_t cmJsonParseFile( cmJsonH_t h, const char* fn, cmJsonNode_t* altRootPtr )
  642. { return _cmJsonParse(h,NULL,0,fn,altRootPtr); }
  643. cmJsonNode_t* cmJsonRoot( cmJsonH_t h )
  644. {
  645. cmJs_t* p = _cmJsonHandleToPtr(h);
  646. return p->rootPtr;
  647. }
  648. cmJsRC_t cmJsonClearTree( cmJsonH_t h )
  649. {
  650. cmJs_t* p = _cmJsonHandleToPtr(h);
  651. p->rootPtr = NULL;
  652. p->basePtr = NULL;
  653. p->lastPtr = NULL;
  654. cmLHeapClear(p->heapH,true);
  655. return kOkJsRC;
  656. }
  657. bool cmJsonIsObject( const cmJsonNode_t* np ) { return cmIsFlag(np->typeId,kObjectTId); }
  658. bool cmJsonIsArray( const cmJsonNode_t* np ) { return cmIsFlag(np->typeId,kArrayTId); }
  659. bool cmJsonIsPair( const cmJsonNode_t* np ) { return cmIsFlag(np->typeId,kPairTId); }
  660. bool cmJsonIsString( const cmJsonNode_t* np ) { return cmIsFlag(np->typeId,kStringTId); }
  661. bool cmJsonIsInt( const cmJsonNode_t* np ) { return cmIsFlag(np->typeId,kIntTId); }
  662. bool cmJsonIsReal( const cmJsonNode_t* np ) { return cmIsFlag(np->typeId,kRealTId); }
  663. bool cmJsonIsBool( const cmJsonNode_t* np ) { return cmIsFlag(np->typeId,kTrueTId | kFalseTId); }
  664. unsigned cmJsonChildCount( const cmJsonNode_t* np )
  665. {
  666. if( np == NULL )
  667. return 0;
  668. unsigned n = 0;
  669. switch( np->typeId )
  670. {
  671. case kObjectTId:
  672. case kArrayTId:
  673. case kPairTId:
  674. {
  675. const cmJsonNode_t* lp = np->u.childPtr;
  676. while( lp != NULL )
  677. {
  678. ++n;
  679. lp = lp->siblingPtr;
  680. }
  681. }
  682. break;
  683. default:
  684. break;
  685. }
  686. return n;
  687. }
  688. cmJsonNode_t* cmJsonArrayElement( cmJsonNode_t* np, unsigned index )
  689. {
  690. unsigned i;
  691. assert( index < cmJsonChildCount(np));
  692. np = np->u.childPtr;
  693. for(i=0; i<index; ++i)
  694. np = np->siblingPtr;
  695. return np;
  696. }
  697. const cmJsonNode_t* cmJsonArrayElementC( const cmJsonNode_t* np, unsigned index )
  698. { return cmJsonArrayElement( (cmJsonNode_t*)np, index ); }
  699. const char* cmJsonPairLabel( const cmJsonNode_t* pairPtr )
  700. {
  701. assert( pairPtr->typeId == kPairTId );
  702. if( pairPtr->typeId != kPairTId )
  703. return NULL;
  704. return pairPtr->u.childPtr->u.stringVal;
  705. }
  706. unsigned cmJsonPairTypeId( const cmJsonNode_t* pairPtr )
  707. {
  708. assert( pairPtr->typeId == kPairTId );
  709. return pairPtr->u.childPtr->siblingPtr->typeId;
  710. }
  711. cmJsonNode_t* cmJsonPairValue( cmJsonNode_t* pairPtr )
  712. {
  713. assert( pairPtr->typeId == kPairTId );
  714. if( pairPtr->typeId != kPairTId )
  715. return NULL;
  716. return pairPtr->u.childPtr->siblingPtr;
  717. }
  718. cmJsonNode_t* cmJsonFindValue( cmJsonH_t h, const char* label, const cmJsonNode_t* np, unsigned keyTypeMask )
  719. {
  720. cmJs_t* p = _cmJsonHandleToPtr(h);
  721. if( np == NULL )
  722. np = p->rootPtr;
  723. if( np == NULL )
  724. return NULL;
  725. // we are only interested in pairs
  726. if( np->typeId == kPairTId )
  727. {
  728. // pairs must have exactly two nodes - the first must be a string
  729. assert(np->u.childPtr != NULL && np->u.childPtr->typeId == kStringTId && np->u.childPtr->siblingPtr != NULL );
  730. if( strcmp(cmJsonPairLabel(np),label) == 0 )
  731. {
  732. if( (keyTypeMask==kInvalidTId) || (keyTypeMask & np->u.childPtr->siblingPtr->typeId) )
  733. return np->u.childPtr->siblingPtr;
  734. }
  735. }
  736. // if the node is an object,array, or pair ...
  737. if( np->typeId==kObjectTId || np->typeId==kArrayTId || np->typeId==kPairTId )
  738. {
  739. // ... then recurse on its children
  740. cmJsonNode_t* cnp = np->u.childPtr;
  741. while(cnp != NULL)
  742. {
  743. cmJsonNode_t* rp;
  744. if((rp = cmJsonFindValue(h,label,cnp,keyTypeMask)) != NULL )
  745. return rp;
  746. cnp = cnp->siblingPtr;
  747. }
  748. }
  749. return NULL;
  750. }
  751. cmJsRC_t _cmJsonFindPathValue( cmJs_t* p, const char* pathPrefix, const char* path, const cmJsonNode_t* rp, const cmJsonNode_t** rpp )
  752. {
  753. cmJsRC_t rc = kOkJsRC;
  754. if( rp == NULL )
  755. rp = p->rootPtr;
  756. if( rp == NULL )
  757. return kOkJsRC;
  758. assert( cmJsonIsObject(rp));
  759. assert( rpp != NULL );
  760. *rpp = NULL;
  761. // create a copy of the path
  762. unsigned i,j;
  763. unsigned sn = (pathPrefix==NULL ? 0 : strlen(pathPrefix)) + strlen(path) + 1; // add one for the possible extra seperator
  764. char ss[ 1024 ];
  765. char* sp = NULL;
  766. char* sm = NULL;
  767. char* sb = ss;
  768. // don't put more than 1k on the stack
  769. if( sn + 1 > 1024 )
  770. {
  771. sm = cmMemAllocZ(char,sn+1);
  772. sb = sm;
  773. }
  774. sp = sb;
  775. sp[0] = 0;
  776. if(pathPrefix != NULL )
  777. {
  778. strcpy(sp,pathPrefix);
  779. // if pathPrefix does not end in a '/' then insert one
  780. if( sp[ strlen(sp)-1 ] != '/' )
  781. strcat(sp,"/");
  782. }
  783. // the '/' has already been inserted - skip any leading '/' character in path
  784. strcat(sp,path[0]=='/' ? path+1 : path );
  785. // terminate each path label with a '/0'.
  786. sp = ss;
  787. for(i=0,j=0; sp < ss + sn; ++sp, ++i )
  788. if( *sp == '/' )
  789. {
  790. *sp = 0;
  791. ++j;
  792. }
  793. if( i > 0 )
  794. {
  795. sp = sb;
  796. while( sp < sb + sn )
  797. {
  798. // labeled values are always associated with pairs and
  799. // pairs only exist as the children of objects.
  800. if( cmJsonIsObject(rp) == false )
  801. {
  802. rc = cmErrMsg(&p->err,kInvalidNodeTypeJsRC,"A non-object node was encountered on a object path.");
  803. break;
  804. }
  805. // get the count of pairs in this object
  806. unsigned cn = cmJsonChildCount( rp );
  807. cmJsonNode_t* cp = rp->u.childPtr;
  808. unsigned k;
  809. for(k=0; k<cn; ++k)
  810. {
  811. // all children of an object must be pairs
  812. assert( cp != NULL && cmJsonIsPair(cp) );
  813. // if this is the labeled pair we are looking for
  814. if( strcmp(cmJsonPairLabel(cp),sp) == 0 )
  815. break;
  816. cp = cp->siblingPtr;
  817. }
  818. // if the search failed
  819. if( k == cn || cp == NULL )
  820. {
  821. rc = cmErrMsg(&p->err,kNodeNotFoundJsRC,"The path label '%s' could not be found.",cmStringNullGuard(sp));
  822. break;
  823. }
  824. // take the value of the located pair to continue the search
  825. rp = cmJsonPairValue(cp);
  826. // advance to the next label
  827. sp += strlen(sp) + 1;
  828. }
  829. }
  830. cmMemPtrFree(&sm);
  831. *rpp = rp;
  832. return rc;
  833. }
  834. cmJsRC_t _cmJsonPathToValueError( cmJs_t* p, cmJsRC_t rc, const char* pathPrefix, const char* path, const char* typeLabel )
  835. {
  836. if( pathPrefix != NULL )
  837. cmErrMsg(&p->err,rc,"The JSON value at '%s/%s' could not be converted to a '%s'.",cmStringNullGuard(pathPrefix),cmStringNullGuard(path),cmStringNullGuard(typeLabel));
  838. else
  839. cmErrMsg(&p->err,rc,"The JSON value at '%s' could not be converted to a '%s'.",cmStringNullGuard(path),cmStringNullGuard(typeLabel));
  840. return rc;
  841. }
  842. cmJsRC_t cmJsonPathToValueNode( cmJsonH_t h, const cmJsonNode_t* objectNodePtr, const char* pathPrefix, const char* path, const cmJsonNode_t** nodePtrPtr )
  843. {
  844. cmJsRC_t rc = kOkJsRC;
  845. cmJs_t* p = _cmJsonHandleToPtr(h);
  846. if( objectNodePtr == NULL )
  847. objectNodePtr = p->rootPtr;
  848. if((rc = _cmJsonFindPathValue(p,pathPrefix,path,objectNodePtr,nodePtrPtr)) != kOkJsRC )
  849. return rc;
  850. return rc;
  851. }
  852. cmJsRC_t cmJsonPathToBool( cmJsonH_t h, const cmJsonNode_t* objectNodePtr, const char* pathPrefix, const char* path, bool* retValPtr )
  853. {
  854. const cmJsonNode_t* rp;
  855. cmJsRC_t rc = kOkJsRC;
  856. cmJs_t* p = _cmJsonHandleToPtr(h);
  857. if((rc = _cmJsonFindPathValue(p,pathPrefix,path,objectNodePtr,&rp)) != kOkJsRC )
  858. return rc;
  859. if((rc = cmJsonBoolValue(rp,retValPtr)) != kOkJsRC )
  860. return _cmJsonPathToValueError(p,rc,pathPrefix,path,"bool");
  861. return rc;
  862. }
  863. cmJsRC_t cmJsonPathToInt( cmJsonH_t h, const cmJsonNode_t* objectNodePtr, const char* pathPrefix, const char* path, int* retValPtr )
  864. {
  865. const cmJsonNode_t* rp;
  866. cmJsRC_t rc = kOkJsRC;
  867. cmJs_t* p = _cmJsonHandleToPtr(h);
  868. if((rc = _cmJsonFindPathValue(p,pathPrefix,path,objectNodePtr,&rp)) != kOkJsRC )
  869. return rc;
  870. if((rc = cmJsonIntValue(rp,retValPtr)) != kOkJsRC )
  871. return _cmJsonPathToValueError(p,rc,pathPrefix,path,"bool");
  872. return rc;
  873. }
  874. cmJsRC_t cmJsonPathToUInt( cmJsonH_t h, const cmJsonNode_t* objectNodePtr, const char* pathPrefix, const char* path, unsigned* retValPtr )
  875. {
  876. const cmJsonNode_t* rp;
  877. cmJsRC_t rc = kOkJsRC;
  878. cmJs_t* p = _cmJsonHandleToPtr(h);
  879. if((rc = _cmJsonFindPathValue(p,pathPrefix,path,objectNodePtr,&rp)) != kOkJsRC )
  880. return rc;
  881. if((rc = cmJsonUIntValue(rp,retValPtr)) != kOkJsRC )
  882. return _cmJsonPathToValueError(p,rc,pathPrefix,path,"unsigned integer");
  883. return rc;
  884. }
  885. cmJsRC_t cmJsonPathToReal( cmJsonH_t h, const cmJsonNode_t* objectNodePtr, const char* pathPrefix, const char* path, double* retValPtr )
  886. {
  887. const cmJsonNode_t* rp;
  888. cmJsRC_t rc = kOkJsRC;
  889. cmJs_t* p = _cmJsonHandleToPtr(h);
  890. if((rc = _cmJsonFindPathValue(p,pathPrefix,path,objectNodePtr,&rp)) != kOkJsRC )
  891. return rc;
  892. if((rc = cmJsonRealValue(rp,retValPtr)) != kOkJsRC )
  893. return _cmJsonPathToValueError(p,rc,pathPrefix,path,"real");
  894. return rc;
  895. }
  896. cmJsRC_t cmJsonPathToString( cmJsonH_t h, const cmJsonNode_t* objectNodePtr, const char* pathPrefix, const char* path, const char** retValPtr )
  897. {
  898. const cmJsonNode_t* rp = NULL;
  899. cmJsRC_t rc = kOkJsRC;
  900. cmJs_t* p = _cmJsonHandleToPtr(h);
  901. if((rc = _cmJsonFindPathValue(p,pathPrefix,path,objectNodePtr,&rp)) != kOkJsRC )
  902. return rc;
  903. if((rc = cmJsonStringValue(rp,retValPtr)) != kOkJsRC )
  904. return _cmJsonPathToValueError(p,rc,pathPrefix,path,"string");
  905. return rc;
  906. }
  907. cmJsRC_t cmJsonPathToPair( cmJsonH_t h, const cmJsonNode_t* objectNodePtr, const char* pathPrefix, const char* path, cmJsonNode_t** retValPtr )
  908. {
  909. const cmJsonNode_t* rp;
  910. cmJsRC_t rc = kOkJsRC;
  911. cmJs_t* p = _cmJsonHandleToPtr(h);
  912. if((rc = _cmJsonFindPathValue(p,pathPrefix,path,objectNodePtr,&rp)) != kOkJsRC )
  913. return rc;
  914. if((rc = cmJsonPairNode(rp,retValPtr)) != kOkJsRC )
  915. return _cmJsonPathToValueError(p,rc,pathPrefix,path,"pair");
  916. return rc;
  917. }
  918. cmJsRC_t cmJsonPathToArray( cmJsonH_t h, const cmJsonNode_t* objectNodePtr, const char* pathPrefix, const char* path, cmJsonNode_t** retValPtr )
  919. {
  920. const cmJsonNode_t* rp;
  921. cmJsRC_t rc = kOkJsRC;
  922. cmJs_t* p = _cmJsonHandleToPtr(h);
  923. if((rc = _cmJsonFindPathValue(p,pathPrefix,path,objectNodePtr,&rp)) != kOkJsRC )
  924. return rc;
  925. if((rc = cmJsonArrayNode(rp,retValPtr)) != kOkJsRC )
  926. return _cmJsonPathToValueError(p,rc,pathPrefix,path,"array");
  927. return rc;
  928. }
  929. cmJsRC_t cmJsonPathToObject( cmJsonH_t h, const cmJsonNode_t* objectNodePtr, const char* pathPrefix, const char* path, cmJsonNode_t** retValPtr )
  930. {
  931. const cmJsonNode_t* rp;
  932. cmJsRC_t rc = kOkJsRC;
  933. cmJs_t* p = _cmJsonHandleToPtr(h);
  934. if((rc = _cmJsonFindPathValue(p,pathPrefix,path,objectNodePtr,&rp)) != kOkJsRC )
  935. return rc;
  936. if((rc = cmJsonObjectNode(rp,retValPtr)) != kOkJsRC )
  937. return _cmJsonPathToValueError(p,rc,pathPrefix,path,"object");
  938. return rc;
  939. }
  940. const cmJsonNode_t* cmJsonFindPathValueC( cmJsonH_t h, const char* path, const cmJsonNode_t* np, unsigned typeIdMask )
  941. {
  942. cmJs_t* p = _cmJsonHandleToPtr(h);
  943. const cmJsonNode_t* rp = NULL;
  944. cmJsRC_t rc = kOkJsRC;
  945. if((rc = _cmJsonFindPathValue(p,NULL,path,np,&rp)) != kOkJsRC )
  946. {
  947. // validate the return type
  948. if( rp != NULL )
  949. if( (typeIdMask!=kInvalidTId) && (typeIdMask & rp->typeId)==0 )
  950. {
  951. cmErrMsg(&p->err,kInvalidNodeTypeJsRC,"The value at the end of the path '%s' did not match the requested type.",cmStringNullGuard(path));
  952. rp = NULL;
  953. }
  954. }
  955. return rp;
  956. }
  957. cmJsonNode_t* cmJsonFindPathValue( cmJsonH_t h, const char* path, const cmJsonNode_t* np, unsigned typeIdMask )
  958. { return (cmJsonNode_t*)cmJsonFindPathValueC(h,path,np,typeIdMask ); }
  959. cmJsRC_t _cmJsonFindMemberValue( const cmJsonNode_t* np, const char* label, unsigned keyTypeId, cmJsonNode_t** npp )
  960. {
  961. *npp = NULL;
  962. // the src node must be an object
  963. if( np->typeId != kObjectTId )
  964. return kNodeNotFoundJsRC;
  965. // for each member pair
  966. const cmJsonNode_t* cnp = np->u.childPtr;
  967. while( cnp != NULL )
  968. {
  969. assert( (cnp->typeId & kMaskTId) == kPairTId );
  970. // if the labels match ...
  971. if( strcmp( label, cmJsonPairLabel(cnp)) == 0 )
  972. {
  973. // ... and the type flags match ...
  974. if( (keyTypeId==kInvalidTId || cmIsFlag(cnp->u.childPtr->siblingPtr->typeId,keyTypeId) ) )
  975. {
  976. *npp = cnp->u.childPtr->siblingPtr;
  977. return kOkJsRC; // ... then the key was found.
  978. }
  979. // ... label match but wrong type ... this is considered an error
  980. return kNodeCannotCvtJsRC;
  981. }
  982. cnp = cnp->siblingPtr;
  983. }
  984. return kNodeNotFoundJsRC;
  985. }
  986. cmJsRC_t cmJsonUIntValue( const cmJsonNode_t* vp, unsigned* retPtr )
  987. {
  988. cmJsRC_t rc = kOkJsRC;
  989. if( vp == NULL )
  990. return kNodeCannotCvtJsRC;
  991. switch(vp->typeId)
  992. {
  993. case kIntTId: *retPtr = vp->u.intVal; break;
  994. case kRealTId: *retPtr = (unsigned)vp->u.realVal; break;
  995. case kTrueTId: *retPtr = 1; break;
  996. case kFalseTId: *retPtr = 0; break;
  997. default:
  998. rc = kNodeCannotCvtJsRC;
  999. }
  1000. return rc;
  1001. }
  1002. cmJsRC_t cmJsonIntValue( const cmJsonNode_t* vp, int* retPtr )
  1003. {
  1004. cmJsRC_t rc = kOkJsRC;
  1005. if( vp == NULL )
  1006. return kNodeCannotCvtJsRC;
  1007. switch(vp->typeId)
  1008. {
  1009. case kIntTId: *retPtr = vp->u.intVal; break;
  1010. case kRealTId: *retPtr = (int)vp->u.realVal; break;
  1011. case kTrueTId: *retPtr = 1; break;
  1012. case kFalseTId: *retPtr = 0; break;
  1013. default:
  1014. rc = kNodeCannotCvtJsRC;
  1015. }
  1016. return rc;
  1017. }
  1018. cmJsRC_t cmJsonRealValue( const cmJsonNode_t* vp, double* retPtr )
  1019. {
  1020. cmJsRC_t rc = kOkJsRC;
  1021. if( vp == NULL )
  1022. return kNodeCannotCvtJsRC;
  1023. switch(vp->typeId)
  1024. {
  1025. case kIntTId: *retPtr = vp->u.intVal; break;
  1026. case kRealTId: *retPtr = vp->u.realVal; break;
  1027. case kTrueTId: *retPtr = 1; break;
  1028. case kFalseTId: *retPtr = 0; break;
  1029. default:
  1030. rc = kNodeCannotCvtJsRC;
  1031. }
  1032. return rc;
  1033. }
  1034. cmJsRC_t cmJsonBoolValue( const cmJsonNode_t* vp, bool* retPtr )
  1035. {
  1036. cmJsRC_t rc = kOkJsRC;
  1037. if( vp == NULL )
  1038. return kNodeCannotCvtJsRC;
  1039. switch(vp->typeId)
  1040. {
  1041. case kIntTId: *retPtr = vp->u.intVal != 0; break;
  1042. case kRealTId: *retPtr = (int)vp->u.realVal != 0; break;
  1043. case kTrueTId: *retPtr = 1; break;
  1044. case kFalseTId: *retPtr = 0; break;
  1045. default:
  1046. rc = kNodeCannotCvtJsRC;
  1047. }
  1048. return rc;
  1049. }
  1050. cmJsRC_t cmJsonStringValue( const cmJsonNode_t* vp, const char **retPtrPtr )
  1051. {
  1052. cmJsRC_t rc = kOkJsRC;
  1053. if( vp == NULL || vp->typeId != kStringTId )
  1054. return kNodeCannotCvtJsRC;
  1055. *retPtrPtr = vp->u.stringVal;
  1056. return rc;
  1057. }
  1058. cmJsRC_t cmJsonPairNode( const cmJsonNode_t* vp, cmJsonNode_t **retPtrPtr )
  1059. {
  1060. cmJsRC_t rc = kOkJsRC;
  1061. if( !cmJsonIsPair(vp) )
  1062. return kNodeCannotCvtJsRC;
  1063. *retPtrPtr = (cmJsonNode_t*)vp;
  1064. return rc;
  1065. }
  1066. cmJsRC_t cmJsonArrayNode( const cmJsonNode_t* vp, cmJsonNode_t **retPtrPtr )
  1067. {
  1068. cmJsRC_t rc = kOkJsRC;
  1069. if( !cmJsonIsArray(vp) )
  1070. return kNodeCannotCvtJsRC;
  1071. *retPtrPtr = (cmJsonNode_t*)vp;
  1072. return rc;
  1073. }
  1074. cmJsRC_t cmJsonObjectNode( const cmJsonNode_t* vp, cmJsonNode_t **retPtrPtr )
  1075. {
  1076. cmJsRC_t rc = kOkJsRC;
  1077. if( !cmJsonIsObject(vp) )
  1078. return kNodeCannotCvtJsRC;
  1079. *retPtrPtr = (cmJsonNode_t*)vp;
  1080. return rc;
  1081. }
  1082. cmJsonNode_t* cmJsonFindPair( const cmJsonNode_t* np, const char* label )
  1083. {
  1084. cmJsRC_t rc = kOkJsRC;
  1085. cmJsonNode_t* vnp = NULL;
  1086. if((rc = _cmJsonFindMemberValue( np, label, kInvalidTId, &vnp )) != kOkJsRC )
  1087. return NULL;
  1088. assert( vnp != NULL );
  1089. return vnp->ownerPtr;
  1090. }
  1091. cmJsRC_t cmJsonMemberType( const cmJsonNode_t* np, const char* label, unsigned* typeIdRef )
  1092. {
  1093. cmJsRC_t rc = kOkJsRC;
  1094. cmJsonNode_t* vnp = NULL;
  1095. if( typeIdRef != NULL )
  1096. *typeIdRef = kInvalidTId;
  1097. if((rc = _cmJsonFindMemberValue( np, label, kInvalidTId, &vnp )) != kOkJsRC )
  1098. return rc;
  1099. assert( vnp != NULL );
  1100. if( typeIdRef != NULL )
  1101. *typeIdRef = vnp->typeId & kMaskTId;
  1102. return rc;
  1103. }
  1104. cmJsonNode_t* cmJsonMemberAtIndex( cmJsonNode_t* objNodePtr, unsigned idx )
  1105. {
  1106. cmJsonNode_t* cnp = cmJsonArrayElement( objNodePtr, idx );
  1107. assert( cmJsonIsPair(cnp) );
  1108. return cnp;
  1109. }
  1110. cmJsRC_t cmJsonUIntMember( const cmJsonNode_t* np, const char* label, unsigned* retPtr )
  1111. {
  1112. cmJsonNode_t* vp;
  1113. cmJsRC_t rc;
  1114. if((rc = _cmJsonFindMemberValue(np,label,kNumericTId,&vp)) != kOkJsRC )
  1115. return rc;
  1116. return cmJsonUIntValue(vp,retPtr);
  1117. }
  1118. cmJsRC_t cmJsonIntMember( const cmJsonNode_t* np, const char* label, int* retPtr )
  1119. {
  1120. cmJsonNode_t* vp;
  1121. cmJsRC_t rc;
  1122. if((rc = _cmJsonFindMemberValue(np,label,kNumericTId,&vp)) != kOkJsRC )
  1123. return rc;
  1124. return cmJsonIntValue(vp,retPtr);
  1125. }
  1126. cmJsRC_t cmJsonRealMember( const cmJsonNode_t* np, const char* label, double* retPtr )
  1127. {
  1128. cmJsonNode_t* vp;
  1129. cmJsRC_t rc;
  1130. if((rc = _cmJsonFindMemberValue(np,label,kNumericTId,&vp)) != kOkJsRC )
  1131. return rc;
  1132. return cmJsonRealValue(vp,retPtr);
  1133. }
  1134. cmJsRC_t cmJsonBoolMember( const cmJsonNode_t* np, const char* label, bool* retPtr )
  1135. {
  1136. cmJsonNode_t* vp;
  1137. cmJsRC_t rc;
  1138. if((rc = _cmJsonFindMemberValue(np,label,kNumericTId,&vp)) != kOkJsRC )
  1139. return rc;
  1140. return cmJsonBoolValue(vp,retPtr);
  1141. }
  1142. cmJsRC_t cmJsonStringMember( const cmJsonNode_t* np, const char* label, const char** retPtrPtr )
  1143. {
  1144. cmJsonNode_t* vp;
  1145. cmJsRC_t rc;
  1146. *retPtrPtr = NULL;
  1147. if((rc = _cmJsonFindMemberValue(np,label,kStringTId,&vp)) != kOkJsRC )
  1148. return rc;
  1149. return cmJsonStringValue(vp,retPtrPtr);
  1150. }
  1151. cmJsRC_t cmJsonNodeMember( const cmJsonNode_t* np, const char* label, cmJsonNode_t** retPtrPtr )
  1152. {
  1153. cmJsonNode_t* vp;
  1154. cmJsRC_t rc;
  1155. *retPtrPtr = NULL;
  1156. if((rc = _cmJsonFindMemberValue(np,label,kArrayTId|kObjectTId,&vp)) != kOkJsRC )
  1157. return rc;
  1158. *retPtrPtr = vp;
  1159. return rc;
  1160. }
  1161. cmJsonNode_t* cmJsonNodeMemberValue( const cmJsonNode_t* np, const char* label )
  1162. {
  1163. assert( cmJsonIsObject(np) );
  1164. unsigned n = cmJsonChildCount(np);
  1165. unsigned j = 0;
  1166. for(; j<n; ++j)
  1167. {
  1168. const cmJsonNode_t* cnp = cmJsonArrayElementC(np,j);
  1169. assert( cnp != NULL && cmJsonIsPair(cnp) );
  1170. if( strcmp(label,cmJsonPairLabel(cnp))==0 )
  1171. return cmJsonPairValue((cmJsonNode_t*)cnp);
  1172. }
  1173. return NULL;
  1174. }
  1175. cmJsRC_t cmJsonVMemberValues( const cmJsonNode_t* objectNodePtr, const char** errLabelPtrPtr, va_list vl )
  1176. {
  1177. unsigned typeId;
  1178. cmJsRC_t rc = kOkJsRC;
  1179. if( errLabelPtrPtr != NULL )
  1180. *errLabelPtrPtr = NULL;
  1181. const char* label;
  1182. while( ((label = va_arg(vl,const char*)) != NULL) && (rc==kOkJsRC) )
  1183. {
  1184. typeId = va_arg(vl,unsigned);
  1185. switch( typeId & kMaskTId )
  1186. {
  1187. case kObjectTId:
  1188. case kPairTId:
  1189. case kArrayTId:
  1190. {
  1191. cmJsonNode_t** nodePtrPtr = va_arg(vl, cmJsonNode_t**);
  1192. if((rc = cmJsonNodeMember(objectNodePtr,label,nodePtrPtr )) == kOkJsRC )
  1193. {
  1194. cmJsonNode_t* np = *nodePtrPtr;
  1195. if( (np->typeId & kMaskTId) != (typeId&kMaskTId) )
  1196. rc = kNodeCannotCvtJsRC;
  1197. }
  1198. }
  1199. break;
  1200. case kIntTId:
  1201. {
  1202. int* ip = va_arg(vl, int* );
  1203. assert(ip != NULL);
  1204. rc = cmJsonIntMember(objectNodePtr, label, ip);
  1205. }
  1206. break;
  1207. case kRealTId:
  1208. {
  1209. double* dp = va_arg(vl, double*);
  1210. assert(dp != NULL);
  1211. rc = cmJsonRealMember(objectNodePtr, label, dp);
  1212. }
  1213. break;
  1214. case kStringTId:
  1215. {
  1216. const char** cpp = va_arg(vl, const char**);
  1217. assert(cpp != NULL);
  1218. rc = cmJsonStringMember(objectNodePtr, label, cpp);
  1219. }
  1220. break;
  1221. case kTrueTId:
  1222. case kFalseTId:
  1223. case kBoolTId:
  1224. {
  1225. bool* bp = va_arg(vl, bool* );
  1226. rc = cmJsonBoolMember(objectNodePtr, label, bp);
  1227. }
  1228. break;
  1229. default:
  1230. // missing terminating NULL on the var args list???
  1231. assert(0);
  1232. break;
  1233. }
  1234. if( (rc == kNodeNotFoundJsRC) && cmIsFlag(typeId,kOptArgJsFl) )
  1235. rc = kOkJsRC;
  1236. if( rc != kOkJsRC && errLabelPtrPtr != NULL )
  1237. *errLabelPtrPtr = label;
  1238. }
  1239. return rc;
  1240. }
  1241. cmJsRC_t cmJsonMemberValues( const cmJsonNode_t* objectNodePtr, const char** errLabelPtrPtr, ...)
  1242. {
  1243. va_list vl;
  1244. va_start(vl,errLabelPtrPtr);
  1245. cmJsRC_t rc = cmJsonVMemberValues(objectNodePtr,errLabelPtrPtr,vl);
  1246. va_end(vl);
  1247. return rc;
  1248. }
  1249. cmJsRC_t cmJsonVPathValues( cmJsonH_t h, const char* pathPrefix, const cmJsonNode_t* objNodePtr, const char** errLabelPtrPtr, va_list vl )
  1250. {
  1251. cmJsRC_t rc = kOkJsRC;
  1252. cmJs_t* p = _cmJsonHandleToPtr(h);
  1253. if( errLabelPtrPtr != NULL )
  1254. *errLabelPtrPtr = NULL;
  1255. const char* path;
  1256. while( ((path = va_arg(vl,const char*)) != NULL) && (rc==kOkJsRC) )
  1257. {
  1258. unsigned typeId;
  1259. const cmJsonNode_t* vnp;
  1260. typeId = va_arg(vl,unsigned);
  1261. // find the requested pair value
  1262. if((rc = _cmJsonFindPathValue(p,pathPrefix,path,objNodePtr,&vnp)) != kOkJsRC )
  1263. break;
  1264. switch( typeId & kMaskTId )
  1265. {
  1266. case kObjectTId:
  1267. case kPairTId:
  1268. case kArrayTId:
  1269. {
  1270. const cmJsonNode_t** nodePtrPtr = va_arg(vl, const cmJsonNode_t**);
  1271. if( (vnp->typeId & kMaskTId) != (typeId & kMaskTId) )
  1272. rc = kNodeCannotCvtJsRC;
  1273. else
  1274. *nodePtrPtr = vnp;
  1275. }
  1276. break;
  1277. case kIntTId:
  1278. {
  1279. int* ip = va_arg(vl, int* );
  1280. assert(ip != NULL);
  1281. rc = cmJsonIntValue(vnp, ip);
  1282. }
  1283. break;
  1284. case kRealTId:
  1285. {
  1286. double* dp = va_arg(vl, double*);
  1287. assert(dp != NULL);
  1288. rc = cmJsonRealValue(vnp, dp);
  1289. }
  1290. break;
  1291. case kStringTId:
  1292. {
  1293. const char** cpp = va_arg(vl, const char**);
  1294. assert(cpp != NULL);
  1295. rc = cmJsonStringValue(vnp, cpp);
  1296. }
  1297. break;
  1298. case kTrueTId:
  1299. case kFalseTId:
  1300. {
  1301. bool* bp = va_arg(vl, bool* );
  1302. rc = cmJsonBoolValue(vnp, bp);
  1303. }
  1304. break;
  1305. default:
  1306. // missing terminating NULL on the var args list???
  1307. assert(0);
  1308. break;
  1309. }
  1310. if( (rc == kNodeNotFoundJsRC) && cmIsFlag(typeId,kOptArgJsFl) )
  1311. rc = kOkJsRC;
  1312. if( rc != kOkJsRC && errLabelPtrPtr != NULL )
  1313. *errLabelPtrPtr = path;
  1314. }
  1315. return rc;
  1316. }
  1317. cmJsRC_t cmJsonPathValues( cmJsonH_t h, const char* pathPrefix, const cmJsonNode_t* objectNodePtr, const char** errLabelPtrPtr, ... )
  1318. {
  1319. va_list vl;
  1320. va_start(vl,errLabelPtrPtr);
  1321. cmJsRC_t rc = cmJsonVPathValues(h,pathPrefix,objectNodePtr,errLabelPtrPtr,vl);
  1322. va_end(vl);
  1323. return rc;
  1324. }
  1325. cmJsonNode_t* _cmJsonCreateNode2( cmJsonH_t h, unsigned newNodeTypeId, cmJsonNode_t* parentPtr )
  1326. {
  1327. cmJs_t* p = _cmJsonHandleToPtr(h);
  1328. cmJsonNode_t* np = NULL;
  1329. if((p->rc = _cmJsonCreateNode(p,parentPtr,newNodeTypeId,&np)) != kOkJsRC )
  1330. return NULL;
  1331. return np;
  1332. }
  1333. cmJsRC_t cmJsonCreate( cmJsonH_t h, cmJsonNode_t* parentPtr, unsigned typeId, const char* sv, int iv, double dv, cmJsonNode_t** rpp )
  1334. {
  1335. cmJsonNode_t* rp = NULL;
  1336. cmJsRC_t rc = kOkJsRC;
  1337. cmJs_t* p = _cmJsonHandleToPtr(h);
  1338. if( rpp != NULL )
  1339. *rpp = NULL;
  1340. switch( typeId )
  1341. {
  1342. case kObjectTId:
  1343. case kArrayTId:
  1344. if((rp = _cmJsonCreateNode2(h,typeId,parentPtr)) == NULL)
  1345. rc = p->rc;
  1346. else
  1347. {
  1348. if( rpp != NULL )
  1349. *rpp = rp;
  1350. }
  1351. break;
  1352. case kPairTId: rc = _cmJsonCreatePair(p,parentPtr,sv,rpp); break;
  1353. case kIntTId: rc = _cmJsonCreateInt(p,parentPtr,iv,rpp); break;
  1354. case kRealTId: rc = _cmJsonCreateReal(p,parentPtr,dv,rpp); break;
  1355. case kTrueTId: rc = _cmJsonCreateBool(p,parentPtr,true,rpp); break;
  1356. case kFalseTId: rc = _cmJsonCreateBool(p,parentPtr,false,rpp); break;
  1357. case kNullTId: rc = _cmJsonCreateNull(p,parentPtr,rpp); break;
  1358. case kStringTId: rc = _cmJsonCreateString(p,parentPtr,sv,strlen(sv),rpp); break;
  1359. default:
  1360. assert(0);
  1361. break;
  1362. }
  1363. return rc;
  1364. }
  1365. cmJsonNode_t* cmJsonCreateObject( cmJsonH_t h, cmJsonNode_t* parentPtr )
  1366. { return _cmJsonCreateNode2(h,kObjectTId,parentPtr); }
  1367. cmJsonNode_t* cmJsonCreateArray( cmJsonH_t h, cmJsonNode_t* parentPtr )
  1368. { return _cmJsonCreateNode2(h,kArrayTId,parentPtr); }
  1369. cmJsonNode_t* cmJsonCreatePair( cmJsonH_t h, cmJsonNode_t* parentPtr, const char* label )
  1370. {
  1371. cmJsonNode_t* np;
  1372. cmJs_t* p = _cmJsonHandleToPtr(h);
  1373. if((_cmJsonCreatePair(p,parentPtr,label,&np)) != kOkJsRC )
  1374. return NULL;
  1375. return np;
  1376. }
  1377. cmJsRC_t cmJsonCreateString( cmJsonH_t h, cmJsonNode_t* parentPtr, const char* stringValue )
  1378. {
  1379. cmJs_t* p = _cmJsonHandleToPtr(h);
  1380. return _cmJsonCreateString( p, parentPtr, stringValue, strlen(stringValue),NULL);;
  1381. }
  1382. cmJsRC_t cmJsonCreateStringN(cmJsonH_t h, cmJsonNode_t* parentPtr, const char* stringValue, unsigned stringCharCnt )
  1383. {
  1384. cmJs_t* p = _cmJsonHandleToPtr(h);
  1385. return _cmJsonCreateString( p, parentPtr, stringValue, stringCharCnt,NULL);;
  1386. }
  1387. cmJsRC_t cmJsonCreateInt( cmJsonH_t h, cmJsonNode_t* parentPtr, int value )
  1388. {
  1389. cmJs_t* p = _cmJsonHandleToPtr(h);
  1390. return _cmJsonCreateInt( p, parentPtr, value, NULL );
  1391. }
  1392. cmJsRC_t cmJsonCreateReal( cmJsonH_t h, cmJsonNode_t* parentPtr, double value )
  1393. {
  1394. cmJs_t* p = _cmJsonHandleToPtr(h);
  1395. return _cmJsonCreateReal( p, parentPtr, value, NULL );
  1396. }
  1397. cmJsRC_t cmJsonCreateBool( cmJsonH_t h, cmJsonNode_t* parentPtr, bool value )
  1398. {
  1399. cmJs_t* p = _cmJsonHandleToPtr(h);
  1400. return _cmJsonCreateBool( p, parentPtr, value,NULL );
  1401. }
  1402. cmJsRC_t cmJsonCreateNull( cmJsonH_t h, cmJsonNode_t* parentPtr )
  1403. {
  1404. cmJs_t* p = _cmJsonHandleToPtr(h);
  1405. return _cmJsonCreateNull( p, parentPtr, NULL );
  1406. }
  1407. cmJsRC_t cmJsonCreateStringArray( cmJsonH_t h, cmJsonNode_t* parentPtr, unsigned n, const char** value )
  1408. {
  1409. cmJs_t* p = _cmJsonHandleToPtr(h);
  1410. cmJsRC_t rc = kOkJsRC;
  1411. cmJsonNode_t* np;
  1412. unsigned i;
  1413. if((np = cmJsonCreateArray(h,parentPtr)) == NULL )
  1414. return _cmJsonError(p,cmErrLastRC(&p->err),"Unable to create 'bool' array.");
  1415. for(i=0; i<n; ++i)
  1416. if((rc = cmJsonCreateString(h,np,value[i])) != kOkJsRC )
  1417. return _cmJsonError(p,rc,"Unable to create 'bool' array element at index %i.",i);
  1418. return rc;
  1419. }
  1420. cmJsRC_t cmJsonCreateIntArray( cmJsonH_t h, cmJsonNode_t* parentPtr, unsigned n, const int* value )
  1421. {
  1422. cmJs_t* p = _cmJsonHandleToPtr(h);
  1423. cmJsRC_t rc = kOkJsRC;
  1424. cmJsonNode_t* np;
  1425. unsigned i;
  1426. if((np = cmJsonCreateArray(h,parentPtr)) == NULL )
  1427. return _cmJsonError(p,cmErrLastRC(&p->err),"Unable to create 'int' array.");
  1428. for(i=0; i<n; ++i)
  1429. if((rc = cmJsonCreateInt(h,np,value[i])) != kOkJsRC )
  1430. return _cmJsonError(p,rc,"Unable to create 'int' array element at index %i.",i);
  1431. return rc;
  1432. }
  1433. cmJsRC_t cmJsonCreateRealArray( cmJsonH_t h, cmJsonNode_t* parentPtr, unsigned n, const double* value )
  1434. {
  1435. cmJs_t* p = _cmJsonHandleToPtr(h);
  1436. cmJsRC_t rc = kOkJsRC;
  1437. cmJsonNode_t* np;
  1438. unsigned i;
  1439. if((np = cmJsonCreateArray(h,parentPtr)) == NULL )
  1440. return _cmJsonError(p,cmErrLastRC(&p->err),"Unable to create 'real' array.");
  1441. for(i=0; i<n; ++i)
  1442. if((rc = cmJsonCreateReal(h,np,value[i])) != kOkJsRC )
  1443. return _cmJsonError(p,rc,"Unable to create 'real' array element at index %i.",i);
  1444. return rc;
  1445. }
  1446. cmJsRC_t cmJsonCreateBoolArray( cmJsonH_t h, cmJsonNode_t* parentPtr, unsigned n, const bool* value )
  1447. {
  1448. cmJs_t* p = _cmJsonHandleToPtr(h);
  1449. cmJsRC_t rc = kOkJsRC;
  1450. cmJsonNode_t* np;
  1451. unsigned i;
  1452. if((np = cmJsonCreateArray(h,parentPtr)) == NULL )
  1453. return _cmJsonError(p,cmErrLastRC(&p->err),"Unable to create 'bool' array.");
  1454. for(i=0; i<n; ++i)
  1455. if((rc = cmJsonCreateBool(h,np,value[i])) != kOkJsRC )
  1456. return _cmJsonError(p,rc,"Unable to create 'bool' array element at index %i.",i);
  1457. return rc;
  1458. }
  1459. cmJsRC_t cmJsonSetInt( cmJsonH_t h, cmJsonNode_t* np, int ival )
  1460. {
  1461. cmJs_t* p = _cmJsonHandleToPtr(h);
  1462. if( np->typeId != kIntTId )
  1463. return _cmJsonError(p,kInvalidNodeTypeJsRC,"Cannot assign type 'int' to node type '%s'.",_cmJsonNodeTypeIdToLabel(np->typeId));
  1464. np->u.intVal = ival;
  1465. p->modifiedFl = true;
  1466. return kOkJsRC;
  1467. }
  1468. cmJsRC_t cmJsonSetReal( cmJsonH_t h, cmJsonNode_t * np, double rval )
  1469. {
  1470. cmJs_t* p = _cmJsonHandleToPtr(h);
  1471. if( np->typeId != kRealTId )
  1472. return _cmJsonError(p,kInvalidNodeTypeJsRC,"Cannot assign type 'real' to node type '%s'.",_cmJsonNodeTypeIdToLabel(np->typeId));
  1473. np->u.realVal = rval;
  1474. p->modifiedFl = true;
  1475. return kOkJsRC;
  1476. }
  1477. cmJsRC_t cmJsonSetBool( cmJsonH_t h, cmJsonNode_t * np, bool bval )
  1478. {
  1479. cmJs_t* p = _cmJsonHandleToPtr(h);
  1480. if( np->typeId == kTrueTId || np->typeId==kFalseTId )
  1481. return _cmJsonError(p,kInvalidNodeTypeJsRC,"Cannot assign type 'bool' to node type '%s'.",_cmJsonNodeTypeIdToLabel(np->typeId));
  1482. np->u.boolVal = bval;
  1483. p->modifiedFl = true;
  1484. return kOkJsRC;
  1485. }
  1486. cmJsRC_t cmJsonSetString( cmJsonH_t h, cmJsonNode_t* np, const char* sval )
  1487. {
  1488. cmJs_t* p = _cmJsonHandleToPtr(h);
  1489. if( np->typeId != kStringTId )
  1490. return _cmJsonError(p,kInvalidNodeTypeJsRC,"Cannot assign type 'string' to node type '%s'.",_cmJsonNodeTypeIdToLabel(np->typeId));
  1491. unsigned sn = strlen(sval);
  1492. if( np->u.stringVal != NULL && strlen(np->u.stringVal) <= sn )
  1493. strcpy(np->u.stringVal,sval);
  1494. else
  1495. return _cmJsonSetString(p,np,sval,sn);
  1496. p->modifiedFl = true;
  1497. return kOkJsRC;
  1498. }
  1499. cmJsonNode_t* cmJsonInsertPair( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned typeId, const char* sv, int iv, double dv )
  1500. {
  1501. assert( objectNodePtr->typeId == kObjectTId );
  1502. cmJsRC_t rc;
  1503. cmJsonNode_t* pairNodePtr;
  1504. cmJs_t* p = _cmJsonHandleToPtr(h);
  1505. if((rc = _cmJsonCreatePair(p,objectNodePtr,label,&pairNodePtr)) != kOkJsRC )
  1506. return NULL;
  1507. assert( pairNodePtr != NULL );
  1508. if((rc = cmJsonCreate(h,pairNodePtr,typeId,sv,iv,dv,NULL)) != kOkJsRC )
  1509. return NULL;
  1510. return pairNodePtr;
  1511. }
  1512. cmJsonNode_t* cmJsonInsertPairObject( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label )
  1513. {
  1514. assert( objectNodePtr->typeId == kObjectTId );
  1515. cmJsonNode_t* pairNodePtr;
  1516. if((pairNodePtr = cmJsonCreatePair(h,objectNodePtr,label)) == NULL )
  1517. return NULL;
  1518. return cmJsonCreateObject(h,pairNodePtr);
  1519. }
  1520. cmJsonNode_t* cmJsonInsertPairArray( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label )
  1521. {
  1522. assert( objectNodePtr->typeId == kObjectTId );
  1523. cmJsonNode_t* pairNodePtr;
  1524. if((pairNodePtr = cmJsonCreatePair(h,objectNodePtr,label)) == NULL )
  1525. return NULL;
  1526. return cmJsonCreateArray(h,pairNodePtr);
  1527. }
  1528. cmJsonNode_t* cmJsonInsertPairPair( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, const char* pairLabel )
  1529. {
  1530. assert( objectNodePtr->typeId == kObjectTId );
  1531. cmJsonNode_t* pairNodePtr;
  1532. if((pairNodePtr = cmJsonCreatePair(h,objectNodePtr,label)) == NULL )
  1533. return NULL;
  1534. return cmJsonCreatePair(h,pairNodePtr,pairLabel);
  1535. }
  1536. cmJsRC_t cmJsonInsertPairInt( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, int intVal )
  1537. {
  1538. assert( objectNodePtr->typeId == kObjectTId );
  1539. cmJsonNode_t* pairNodePtr;
  1540. if((pairNodePtr = cmJsonCreatePair(h,objectNodePtr,label)) == NULL )
  1541. return cmJsonErrorCode(h);
  1542. return cmJsonCreateInt(h,pairNodePtr,intVal);
  1543. }
  1544. cmJsRC_t cmJsonInsertPairReal( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, double realVal )
  1545. {
  1546. assert( objectNodePtr->typeId == kObjectTId );
  1547. cmJsonNode_t* pairNodePtr;
  1548. if((pairNodePtr = cmJsonCreatePair(h,objectNodePtr,label)) == NULL )
  1549. return cmJsonErrorCode(h);
  1550. return cmJsonCreateReal(h,pairNodePtr,realVal);
  1551. }
  1552. cmJsRC_t cmJsonInsertPairString( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, const char* stringVal )
  1553. { return cmJsonInsertPairStringN(h,objectNodePtr,label,stringVal,stringVal==NULL ? 0 : strlen(stringVal)); }
  1554. cmJsRC_t cmJsonInsertPairStringN( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, const char* stringVal, unsigned stringCharCnt )
  1555. {
  1556. assert( objectNodePtr->typeId == kObjectTId );
  1557. cmJsonNode_t* pairNodePtr;
  1558. if((pairNodePtr = cmJsonCreatePair(h,objectNodePtr,label)) == NULL )
  1559. return cmJsonErrorCode(h);
  1560. return cmJsonCreateStringN(h,pairNodePtr,stringVal,stringCharCnt);
  1561. }
  1562. cmJsRC_t cmJsonInsertPairBool( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, bool boolVal )
  1563. {
  1564. assert( objectNodePtr->typeId == kObjectTId );
  1565. cmJsonNode_t* pairNodePtr;
  1566. if((pairNodePtr = cmJsonCreatePair(h,objectNodePtr,label)) == NULL )
  1567. return cmJsonErrorCode(h);
  1568. return cmJsonCreateBool(h,pairNodePtr,boolVal);
  1569. }
  1570. cmJsRC_t cmJsonInsertPairNull( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label )
  1571. {
  1572. assert( objectNodePtr->typeId == kObjectTId );
  1573. cmJsonNode_t* pairNodePtr;
  1574. if((pairNodePtr = cmJsonCreatePair(h,objectNodePtr,label)) == NULL )
  1575. return cmJsonErrorCode(h);
  1576. return cmJsonCreateNull(h,pairNodePtr);
  1577. }
  1578. cmJsRC_t cmJsonInsertPairIntArray( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned n, const int* values )
  1579. {
  1580. assert( objectNodePtr->typeId == kObjectTId );
  1581. cmJsonNode_t* pairNodePtr;
  1582. if((pairNodePtr = cmJsonCreatePair(h,objectNodePtr,label)) == NULL )
  1583. return cmJsonErrorCode(h);
  1584. return cmJsonCreateIntArray(h,pairNodePtr,n,values);
  1585. }
  1586. cmJsRC_t cmJsonInsertPairRealArray( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned n, const double* values )
  1587. {
  1588. assert( objectNodePtr->typeId == kObjectTId );
  1589. cmJsonNode_t* pairNodePtr;
  1590. if((pairNodePtr = cmJsonCreatePair(h,objectNodePtr,label)) == NULL )
  1591. return cmJsonErrorCode(h);
  1592. return cmJsonCreateRealArray(h,pairNodePtr,n,values);
  1593. }
  1594. cmJsRC_t cmJsonInsertPairStringArray( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned n, const char** values )
  1595. {
  1596. assert( objectNodePtr->typeId == kObjectTId );
  1597. cmJsonNode_t* pairNodePtr;
  1598. if((pairNodePtr = cmJsonCreatePair(h,objectNodePtr,label)) == NULL )
  1599. return cmJsonErrorCode(h);
  1600. return cmJsonCreateStringArray(h,pairNodePtr,n,values);
  1601. }
  1602. cmJsRC_t cmJsonInsertPairBoolArray( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned n, const bool* values )
  1603. {
  1604. assert( objectNodePtr->typeId == kObjectTId );
  1605. cmJsonNode_t* pairNodePtr;
  1606. if((pairNodePtr = cmJsonCreatePair(h,objectNodePtr,label)) == NULL )
  1607. return cmJsonErrorCode(h);
  1608. return cmJsonCreateBoolArray(h,pairNodePtr,n,values);
  1609. }
  1610. cmJsonNode_t* cmJsonInsertPairIntArray2( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned n, const int* values )
  1611. {
  1612. assert( objectNodePtr->typeId == kObjectTId );
  1613. cmJsonNode_t* pairNodePtr;
  1614. if((pairNodePtr = cmJsonCreatePair(h,objectNodePtr,label)) != NULL )
  1615. if( cmJsonCreateIntArray(h,pairNodePtr,n,values) != kOkJsRC )
  1616. return NULL;
  1617. return pairNodePtr;
  1618. }
  1619. cmJsonNode_t* cmJsonInsertPairRealArray2( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned n, const double* values )
  1620. {
  1621. assert( objectNodePtr->typeId == kObjectTId );
  1622. cmJsonNode_t* pairNodePtr;
  1623. if((pairNodePtr = cmJsonCreatePair(h,objectNodePtr,label)) != NULL )
  1624. if( cmJsonCreateRealArray(h,pairNodePtr,n,values) != kOkJsRC )
  1625. return NULL;
  1626. return pairNodePtr;
  1627. }
  1628. cmJsonNode_t* cmJsonInsertPairStringArray2( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned n, const char** values )
  1629. {
  1630. assert( objectNodePtr->typeId == kObjectTId );
  1631. cmJsonNode_t* pairNodePtr;
  1632. if((pairNodePtr = cmJsonCreatePair(h,objectNodePtr,label)) != NULL )
  1633. if( cmJsonCreateStringArray(h,pairNodePtr,n,values) != kOkJsRC )
  1634. return NULL;
  1635. return pairNodePtr;
  1636. }
  1637. cmJsonNode_t* cmJsonInsertPairBoolArray2( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned n, const bool* values )
  1638. {
  1639. assert( objectNodePtr->typeId == kObjectTId );
  1640. cmJsonNode_t* pairNodePtr;
  1641. if((pairNodePtr = cmJsonCreatePair(h,objectNodePtr,label)) != NULL )
  1642. if( cmJsonCreateBoolArray(h,pairNodePtr,n,values) != kOkJsRC )
  1643. return NULL;
  1644. return pairNodePtr;
  1645. }
  1646. cmJsRC_t _cmJsonInsertOrReplacePair( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned matchTypeMask, unsigned newTypeId, const char* sv, int iv, double dv, cmJsonNode_t* nv, bool insertFl, cmJsonNode_t** retNodePtrPtr )
  1647. {
  1648. cmJsRC_t rc = kOkJsRC;
  1649. cmJs_t* p = _cmJsonHandleToPtr(h);
  1650. cmJsonNode_t* valNodePtr = NULL;
  1651. cmJsonNode_t* pairNodePtr = NULL;
  1652. assert( objectNodePtr->typeId == kObjectTId );
  1653. if( retNodePtrPtr != NULL )
  1654. *retNodePtrPtr = NULL;
  1655. // if a matching pair was not found ....
  1656. if(( valNodePtr = cmJsonFindValue(h,label,objectNodePtr,matchTypeMask)) == NULL )
  1657. {
  1658. // ... and insertion is not allowed then return error
  1659. if( insertFl == false )
  1660. return kNodeNotFoundJsRC;
  1661. // ... otherwise insert a new pair and return a pointer to it
  1662. pairNodePtr = cmJsonInsertPair(h,objectNodePtr,label,newTypeId,sv,iv,dv);
  1663. goto errLabel;
  1664. }
  1665. // ... otherwise a match was found to at least the pair label.
  1666. // If matchTypeMask was set to kInvalidTId then the type id
  1667. // of the found pair may not be the same as newTypeId. To handle
  1668. // this case we proceed by first deallocating all resources held
  1669. // by the found node and then proceeding by either creating
  1670. // deleting the found node and creating a replacement node
  1671. // (object,array,pair) or forcing the found node to a new
  1672. // type (int,real,true,false,string,null).
  1673. assert( valNodePtr != NULL);
  1674. pairNodePtr = valNodePtr->ownerPtr;
  1675. // release any resources held by the found node
  1676. switch( valNodePtr->typeId )
  1677. {
  1678. case kObjectTId:
  1679. case kArrayTId:
  1680. case kPairTId:
  1681. // remove the pair value node and replace it with a 'null' node.
  1682. if((rc =_cmJsonRemoveNode( p, valNodePtr, true, true )) != kOkJsRC )
  1683. goto errLabel;
  1684. break;
  1685. case kStringTId:
  1686. // deallocate string memory
  1687. _cmJsonSetString( p, valNodePtr, NULL, 0 );
  1688. break;
  1689. }
  1690. // relace the found node with the new node
  1691. switch( newTypeId )
  1692. {
  1693. case kObjectTId:
  1694. case kArrayTId:
  1695. case kPairTId:
  1696. {
  1697. cmJsonNode_t* newValueNodePtr = NULL;
  1698. // remove the current pair value ....
  1699. if((rc =_cmJsonRemoveNode( p, valNodePtr, true, false )) != kOkJsRC )
  1700. goto errLabel;
  1701. // new pair nodes should have the pair label in 'sv'
  1702. assert( newTypeId!=kPairTId || (newTypeId==kPairTId && sv != NULL ));
  1703. // if no new value was given or the new value is a pair then ...
  1704. if( nv == NULL || newTypeId == kPairTId )
  1705. {
  1706. // ... create a new blank array,obj or pair
  1707. if((rc = cmJsonCreate( h, pairNodePtr, newTypeId, sv, 0, 0, &newValueNodePtr )) != kOkJsRC )
  1708. goto errLabel;
  1709. }
  1710. // if the new value is a pair and no value node was given then set the
  1711. // new pairs value node to NULL
  1712. if( nv == NULL && newTypeId == kPairTId )
  1713. {
  1714. if((rc = _cmJsonCreateNull(p,newValueNodePtr,NULL)) != kOkJsRC )
  1715. goto errLabel;
  1716. }
  1717. // if a new value node was given
  1718. if( nv != NULL )
  1719. {
  1720. // the new child node should not already be linked to a parent
  1721. assert( nv->ownerPtr == NULL );
  1722. // if the new value is an obj or array then the new
  1723. // value node type id should be the same
  1724. assert( newTypeId==kPairTId || newTypeId==nv->typeId );
  1725. //
  1726. cmJsonNode_t* pp = newTypeId==kPairTId ? newValueNodePtr : pairNodePtr;
  1727. assert( pp->typeId == kPairTId );
  1728. // link in the child to the pair
  1729. if((rc = _cmJsonLinkInChild(p,pp,nv)) != kOkJsRC )
  1730. goto errLabel;
  1731. }
  1732. }
  1733. break;
  1734. // All cases below follow the same pattern:
  1735. // 1. Set the type id to the replacement value type id
  1736. // 2. Assign the value to the node.
  1737. // This sequence is safe because all resources were freed
  1738. // by the earlier switch.
  1739. case kStringTId:
  1740. valNodePtr->typeId = kStringTId;
  1741. _cmJsonSetString( p, valNodePtr, sv, strlen(sv) );
  1742. break;
  1743. case kIntTId:
  1744. valNodePtr->typeId =kIntTId;
  1745. valNodePtr->u.intVal = iv;
  1746. break;
  1747. case kRealTId:
  1748. valNodePtr->typeId = kRealTId;
  1749. valNodePtr->u.realVal = dv;
  1750. break;
  1751. case kTrueTId:
  1752. valNodePtr->typeId = kTrueTId;
  1753. valNodePtr->u.boolVal = true;
  1754. break;
  1755. case kFalseTId:
  1756. valNodePtr->typeId = kFalseTId;
  1757. valNodePtr->u.boolVal = false;
  1758. break;
  1759. case kNullTId:
  1760. valNodePtr->typeId = kNullTId;
  1761. break;
  1762. default:
  1763. { assert(0); }
  1764. }
  1765. errLabel:
  1766. if( rc == kOkJsRC )
  1767. {
  1768. if( retNodePtrPtr != NULL )
  1769. *retNodePtrPtr = pairNodePtr;
  1770. p->modifiedFl = true;
  1771. }
  1772. return rc;
  1773. }
  1774. cmJsonNode_t* cmJsonInsertOrReplacePair( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned matchTypeMask, unsigned typeId, const char* sv, int iv, double dv, cmJsonNode_t* nv )
  1775. {
  1776. cmJsonNode_t* retNodePtr = NULL;
  1777. _cmJsonInsertOrReplacePair(h,objectNodePtr,label,matchTypeMask,typeId,sv,iv,dv,nv,true,&retNodePtr );
  1778. return retNodePtr;
  1779. }
  1780. cmJsonNode_t* cmJsonInsertOrReplacePairObject( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned matchTypeMask, cmJsonNode_t* newObjNodePtr )
  1781. {
  1782. cmJsonNode_t* pairPtr;
  1783. if((pairPtr = cmJsonInsertOrReplacePair(h,objectNodePtr,label,matchTypeMask,kObjectTId,NULL,0,0,newObjNodePtr)) == NULL )
  1784. return NULL;
  1785. return pairPtr->u.childPtr->siblingPtr;
  1786. }
  1787. cmJsonNode_t* cmJsonInsertOrReplacePairArray( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned matchTypeMask, cmJsonNode_t* newArrayNodePtr )
  1788. {
  1789. cmJsonNode_t* pairPtr;
  1790. if((pairPtr = cmJsonInsertOrReplacePair(h,objectNodePtr,label,matchTypeMask,kArrayTId,NULL,0,0,newArrayNodePtr)) == NULL )
  1791. return NULL;
  1792. return pairPtr->u.childPtr->siblingPtr;
  1793. }
  1794. cmJsonNode_t* cmJsonInsertOrReplacePairPair( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned matchTypeMask, const char* newPairLabel, cmJsonNode_t* newPairValNodePtr )
  1795. {
  1796. cmJsonNode_t* pairPtr;
  1797. if((pairPtr = cmJsonInsertOrReplacePair(h,objectNodePtr,label,matchTypeMask,kPairTId,newPairLabel,0,0,newPairValNodePtr)) == NULL )
  1798. return NULL;
  1799. return pairPtr->u.childPtr->siblingPtr;
  1800. }
  1801. cmJsRC_t cmJsonInsertOrReplacePairInt( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned matchTypeMask, int intVal )
  1802. { return cmJsonInsertOrReplacePair(h,objectNodePtr,label,matchTypeMask,kIntTId,NULL,intVal,0,NULL) == NULL ? cmJsonErrorCode(h) : kOkJsRC; }
  1803. cmJsRC_t cmJsonInsertOrReplacePairReal( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned matchTypeMask, double realVal )
  1804. { return cmJsonInsertOrReplacePair(h,objectNodePtr,label,matchTypeMask,kRealTId,NULL,0,realVal,NULL) == NULL ? cmJsonErrorCode(h) : kOkJsRC; }
  1805. cmJsRC_t cmJsonInsertOrReplacePairString( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned matchTypeMask, const char* stringVal )
  1806. { return cmJsonInsertOrReplacePair(h,objectNodePtr,label,matchTypeMask,kStringTId,stringVal,0,0,NULL) == NULL ? cmJsonErrorCode(h) : kOkJsRC; }
  1807. cmJsRC_t cmJsonInsertOrReplacePairBool( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned matchTypeMask, bool boolVal )
  1808. { return cmJsonInsertOrReplacePair(h,objectNodePtr,label,matchTypeMask,boolVal ? kTrueTId : kFalseTId,NULL,0,0,NULL) == NULL ? cmJsonErrorCode(h) : kOkJsRC; }
  1809. cmJsRC_t cmJsonInsertOrReplacePairNull( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned matchTypeMask )
  1810. { return cmJsonInsertOrReplacePair(h,objectNodePtr,label,matchTypeMask,kNullTId,NULL,0,0,NULL) == NULL ? cmJsonErrorCode(h) : kOkJsRC; }
  1811. cmJsonNode_t* cmJsonReplacePair( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned matchTypeMask, unsigned newTypeId, const char* sv, int iv, double dv, cmJsonNode_t* nv )
  1812. {
  1813. cmJsonNode_t* retNodePtr = NULL;
  1814. _cmJsonInsertOrReplacePair(h,objectNodePtr,label,matchTypeMask,newTypeId,sv,iv,dv,nv,false,&retNodePtr );
  1815. return retNodePtr;
  1816. }
  1817. cmJsonNode_t* cmJsonReplacePairObject( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned matchTypeMask, cmJsonNode_t* newPairNodePtr )
  1818. {
  1819. cmJsonNode_t* pairPtr;
  1820. if((pairPtr = cmJsonReplacePair(h,objectNodePtr,label,matchTypeMask,kObjectTId,NULL,0,0,newPairNodePtr)) == NULL )
  1821. return NULL;
  1822. return pairPtr->u.childPtr->siblingPtr;
  1823. }
  1824. cmJsonNode_t* cmJsonReplacePairArray( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned matchTypeMask, cmJsonNode_t* newArrayNodePtr )
  1825. {
  1826. cmJsonNode_t* pairPtr;
  1827. if((pairPtr = cmJsonReplacePair(h,objectNodePtr,label,matchTypeMask,kArrayTId,NULL,0,0,newArrayNodePtr)) == NULL )
  1828. return NULL;
  1829. return pairPtr->u.childPtr->siblingPtr;
  1830. }
  1831. cmJsonNode_t* cmJsonReplacePairPair( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned matchTypeMask, const char* newPairLabel, cmJsonNode_t* newPairValNodePtr )
  1832. {
  1833. cmJsonNode_t* pairPtr;
  1834. if((pairPtr = cmJsonReplacePair(h,objectNodePtr,label,matchTypeMask,kPairTId,newPairLabel,0,0,newPairValNodePtr)) == NULL )
  1835. return NULL;
  1836. return pairPtr->u.childPtr->siblingPtr;
  1837. }
  1838. cmJsRC_t cmJsonReplacePairInt( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned matchTypeMask, int intVal )
  1839. { return cmJsonReplacePair(h,objectNodePtr,label,matchTypeMask,kIntTId,NULL,intVal,0,NULL) == NULL ? cmJsonErrorCode(h) : kOkJsRC; }
  1840. cmJsRC_t cmJsonReplacePairReal( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned matchTypeMask, double realVal )
  1841. { return cmJsonReplacePair(h,objectNodePtr,label,matchTypeMask,kRealTId,NULL,0,realVal,NULL) == NULL ? cmJsonErrorCode(h) : kOkJsRC; }
  1842. cmJsRC_t cmJsonReplacePairString( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned matchTypeMask, const char* stringVal )
  1843. { return cmJsonReplacePair(h,objectNodePtr,label,matchTypeMask,kStringTId,stringVal,0,0,NULL) == NULL ? cmJsonErrorCode(h) : kOkJsRC; }
  1844. cmJsRC_t cmJsonReplacePairBool( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned matchTypeMask, bool boolVal )
  1845. { return cmJsonReplacePair(h,objectNodePtr,label,matchTypeMask,boolVal ? kTrueTId : kFalseTId,NULL,0,0,NULL) == NULL ? cmJsonErrorCode(h) : kOkJsRC; }
  1846. cmJsRC_t cmJsonReplacePairNull( cmJsonH_t h, cmJsonNode_t* objectNodePtr, const char* label, unsigned matchTypeMask )
  1847. { return cmJsonReplacePair(h,objectNodePtr,label,matchTypeMask,kNullTId,NULL,0,0,NULL) == NULL ? cmJsonErrorCode(h) : kOkJsRC; }
  1848. cmJsRC_t cmJsonVInsertPairs( cmJsonH_t h, cmJsonNode_t* objNodePtr, va_list vl )
  1849. {
  1850. cmJsRC_t rc = kOkJsRC;
  1851. assert( objNodePtr->typeId == kObjectTId );
  1852. const char* label;
  1853. while( ((label = va_arg(vl,const char*)) != NULL) && (rc == kOkJsRC) )
  1854. {
  1855. unsigned sel = va_arg(vl,unsigned);
  1856. switch( sel )
  1857. {
  1858. case kObjectTId:
  1859. if( cmJsonInsertPairObject(h,objNodePtr,label) == NULL )
  1860. rc = cmJsonErrorCode(h);
  1861. break;
  1862. case kArrayTId:
  1863. if( cmJsonInsertPairArray(h,objNodePtr,label) == NULL )
  1864. rc = cmJsonErrorCode(h);
  1865. break;
  1866. case kPairTId:
  1867. if( cmJsonInsertPairPair(h,objNodePtr,label, va_arg(vl,const char*)) == NULL )
  1868. rc = cmJsonErrorCode(h);
  1869. break;
  1870. case kIntTId:
  1871. rc = cmJsonInsertPairInt(h,objNodePtr,label, va_arg(vl,int) );
  1872. break;
  1873. case kRealTId:
  1874. rc = cmJsonInsertPairReal(h,objNodePtr,label, va_arg(vl,double) );
  1875. break;
  1876. case kStringTId:
  1877. rc = cmJsonInsertPairString(h,objNodePtr,label, va_arg(vl,const char *) );
  1878. break;
  1879. case kTrueTId:
  1880. case kFalseTId:
  1881. case kBoolTId:
  1882. rc = cmJsonInsertPairBool(h,objNodePtr,label, va_arg(vl,int) );
  1883. break;
  1884. case kNullTId:
  1885. rc = cmJsonInsertPairNull(h,objNodePtr,label );
  1886. break;
  1887. default:
  1888. // missing terminating NULL on the var args list???
  1889. assert(0);
  1890. break;
  1891. }
  1892. }
  1893. return rc;
  1894. }
  1895. cmJsRC_t cmJsonInsertPairs( cmJsonH_t h, cmJsonNode_t* objectNodePtr, ... )
  1896. {
  1897. va_list vl;
  1898. va_start(vl,objectNodePtr);
  1899. cmJsRC_t rc = cmJsonVInsertPairs(h,objectNodePtr,vl);
  1900. va_end(vl);
  1901. return rc;
  1902. }
  1903. cmJsonNode_t* cmJsonVCreateFilledObject( cmJsonH_t h, cmJsonNode_t* parentPtr, va_list vl )
  1904. {
  1905. cmJsonNode_t* np;
  1906. if((np = cmJsonCreateObject(h,parentPtr)) == NULL)
  1907. return NULL;
  1908. if( cmJsonVInsertPairs(h,np,vl) != kOkJsRC )
  1909. {
  1910. cmJsonRemoveNode(h,np,true);
  1911. return NULL;
  1912. }
  1913. return np;
  1914. }
  1915. cmJsonNode_t* cmJsonCreateFilledObject( cmJsonH_t h, cmJsonNode_t* parentPtr, ... )
  1916. {
  1917. va_list vl;
  1918. va_start(vl,parentPtr);
  1919. cmJsonNode_t* np = cmJsonVCreateFilledObject(h,parentPtr,vl);
  1920. va_end(vl);
  1921. return np;
  1922. }
  1923. void _cmJsonFreeNode( cmJs_t* p, cmJsonNode_t* np )
  1924. {
  1925. switch( np->typeId )
  1926. {
  1927. case kObjectTId:
  1928. case kPairTId:
  1929. case kArrayTId:
  1930. {
  1931. cmJsonNode_t* cnp = np->u.childPtr;
  1932. while( cnp != NULL )
  1933. {
  1934. cmJsonNode_t* nnp = cnp->siblingPtr;
  1935. _cmJsonFreeNode(p,cnp);
  1936. cnp = nnp;
  1937. }
  1938. }
  1939. break;
  1940. case kStringTId:
  1941. if( np->u.stringVal != NULL )
  1942. cmLHeapFree(p->heapH,np->u.stringVal);
  1943. break;
  1944. }
  1945. cmLHeapFree(p->heapH,np);
  1946. }
  1947. cmJsRC_t _cmJsonRemoveNode( cmJs_t* p, cmJsonNode_t* np, bool freeFl, bool balancePairsFl )
  1948. {
  1949. if(np == NULL )
  1950. return kOkJsRC;
  1951. cmJsonNode_t* parentPtr = np->ownerPtr;
  1952. // if np is the root ...
  1953. if( np == p->rootPtr )
  1954. {
  1955. // ... we only need to set the root to null to remove the node.
  1956. p->rootPtr = NULL;
  1957. }
  1958. else
  1959. {
  1960. if( parentPtr != NULL )
  1961. {
  1962. // get the parents first child
  1963. cmJsonNode_t* cnp = parentPtr->u.childPtr;
  1964. // if np is the first child then make the second child the first child
  1965. if( cnp == np )
  1966. {
  1967. if( parentPtr->typeId == kPairTId )
  1968. return _cmJsonError( p, kCannotRemoveLabelJsRC, "Cannot remove pair label nodes because this would invalidate the tree structure.");
  1969. parentPtr->u.childPtr = cnp->siblingPtr;
  1970. }
  1971. else
  1972. {
  1973. // otherwise unlink it from the child chain
  1974. while( cnp != NULL )
  1975. {
  1976. if( cnp->siblingPtr == np )
  1977. {
  1978. cnp->siblingPtr = np->siblingPtr;
  1979. // if the parent is a pair then the removed node is a
  1980. // 'pair value' which must be replaced with a null node in order
  1981. // to maintain a valid tree.
  1982. if( (parentPtr->typeId == kPairTId) && balancePairsFl)
  1983. _cmJsonCreateNull( p, parentPtr, NULL );
  1984. break;
  1985. }
  1986. cnp = cnp->siblingPtr;
  1987. }
  1988. assert( cnp != NULL );
  1989. }
  1990. }
  1991. }
  1992. // if the memory assoc'd with the removed node should be released
  1993. if( freeFl )
  1994. {
  1995. _cmJsonFreeNode(p,np);
  1996. /*
  1997. if( np->typeId == kStringTId )
  1998. {
  1999. cmLHeapFree(p->heapH,np->u.stringVal);
  2000. np->u.stringVal = NULL;
  2001. }
  2002. cmLHeapFree(p->heapH,np);
  2003. */
  2004. }
  2005. p->modifiedFl = true;
  2006. return kOkJsRC;
  2007. }
  2008. cmJsRC_t cmJsonRemoveNode( cmJsonH_t h, cmJsonNode_t* np, bool freeFl )
  2009. {
  2010. cmJs_t* p = _cmJsonHandleToPtr(h);
  2011. return _cmJsonRemoveNode( p, np, freeFl, true );
  2012. }
  2013. cmJsRC_t _cmJsonValidateErr( cmJs_t* p, const char* text )
  2014. {
  2015. if( p != NULL )
  2016. return _cmJsonSyntaxError(p,text);
  2017. return kValidateFailJsRC;
  2018. }
  2019. // 'p' is optional. If 'p' is set to NULL the function will return kValidFailJsRC if the
  2020. // tree rooted at 'np' is invalid and will not print an error message.
  2021. cmJsRC_t _cmJsonValidateNode( cmJs_t* p, const cmJsonNode_t* np, const cmJsonNode_t* parentPtr )
  2022. {
  2023. cmJsRC_t rc = kOkJsRC;
  2024. if( parentPtr != np->ownerPtr )
  2025. return _cmJsonValidateErr(p,"A child->parent link does not agree with a parent->child link.");
  2026. if( parentPtr == NULL )
  2027. {
  2028. if( np->typeId != kArrayTId && np->typeId != kObjectTId )
  2029. return _cmJsonValidateErr(p,"Only 'array' and 'object' nodes may be the root element.");
  2030. }
  2031. else
  2032. {
  2033. if( parentPtr->typeId != kArrayTId && parentPtr->typeId != kObjectTId && parentPtr->typeId != kPairTId )
  2034. return _cmJsonValidateErr(p,"Parent nodes must be either 'object','array' or 'pair' nodes.");
  2035. }
  2036. switch( np->typeId )
  2037. {
  2038. case kPairTId:
  2039. if( cmJsonChildCount(np) != 2 )
  2040. return _cmJsonValidateErr(p,"'pair' nodes must have exactly two children.");
  2041. if( np->u.childPtr->typeId != kStringTId )
  2042. return _cmJsonValidateErr(p,"The first child of 'pair' nodes must be a 'string' node.");
  2043. // fall through
  2044. case kObjectTId:
  2045. case kArrayTId:
  2046. {
  2047. // validate each child node
  2048. cmJsonNode_t* cnp = np->u.childPtr;
  2049. while(cnp != NULL)
  2050. {
  2051. if( cnp->ownerPtr != np )
  2052. return _cmJsonValidateErr(p,"A parent->child pointer was not validated with a child->parent pointer.");
  2053. if( np->typeId == kObjectTId && cnp->typeId != kPairTId )
  2054. return _cmJsonValidateErr(p,"All 'object' child nodes must be 'pair' nodes.");
  2055. if((rc = _cmJsonValidateNode(p,cnp,np)) != kOkJsRC )
  2056. return rc;
  2057. cnp = cnp->siblingPtr;
  2058. }
  2059. }
  2060. break;
  2061. case kStringTId:
  2062. case kIntTId:
  2063. case kRealTId:
  2064. case kNullTId:
  2065. case kTrueTId:
  2066. case kFalseTId:
  2067. default:
  2068. break;
  2069. }
  2070. return rc;
  2071. }
  2072. cmJsRC_t cmJsonValidateTree( cmJsonH_t h )
  2073. {
  2074. cmJs_t* p = _cmJsonHandleToPtr(h);
  2075. return _cmJsonValidateNode(p,p->rootPtr,NULL);
  2076. }
  2077. cmJsRC_t cmJsonValidate( const cmJsonNode_t* np )
  2078. { return _cmJsonValidateNode(NULL,np,np->ownerPtr); }
  2079. cmJsonNode_t* _cmJsonDuplicateNode( cmJs_t* p, const cmJsonNode_t* np, cmJsonNode_t* parentPtr )
  2080. {
  2081. cmJsonNode_t* newParentPtr = NULL;
  2082. cmJsonNode_t* newNodePtr = NULL;
  2083. cmJsRC_t rc = kOkJsRC;
  2084. switch( np->typeId )
  2085. {
  2086. case kObjectTId:
  2087. case kArrayTId:
  2088. rc = _cmJsonCreateNode(p,parentPtr,np->typeId,&newParentPtr);
  2089. break;
  2090. case kPairTId:
  2091. rc = _cmJsonCreatePair(p,parentPtr,np->u.childPtr->u.stringVal,&newParentPtr);
  2092. break;
  2093. case kIntTId:
  2094. rc = _cmJsonCreateInt(p,parentPtr,np->u.intVal,&newNodePtr);
  2095. break;
  2096. case kRealTId:
  2097. rc = _cmJsonCreateReal(p,parentPtr,np->u.realVal,&newNodePtr);
  2098. break;
  2099. case kStringTId:
  2100. rc = _cmJsonCreateString(p,parentPtr,np->u.stringVal,strlen(np->u.stringVal),&newNodePtr);
  2101. break;
  2102. case kTrueTId:
  2103. case kFalseTId:
  2104. rc = _cmJsonCreateBool(p,parentPtr,np->u.boolVal,&newNodePtr);
  2105. break;
  2106. case kNullTId:
  2107. rc = _cmJsonCreateNull(p,parentPtr,&newNodePtr);
  2108. }
  2109. if( rc != kOkJsRC )
  2110. return NULL;
  2111. if( newParentPtr != NULL )
  2112. {
  2113. newNodePtr = newParentPtr;
  2114. cmJsonNode_t* cnp = np->u.childPtr;
  2115. if(np->typeId == kPairTId)
  2116. cnp = np->u.childPtr->siblingPtr;
  2117. while( cnp != NULL )
  2118. {
  2119. if( _cmJsonDuplicateNode(p,cnp,newParentPtr) != kOkJsRC )
  2120. return NULL;
  2121. cnp = cnp->siblingPtr;
  2122. }
  2123. }
  2124. return newNodePtr;
  2125. }
  2126. cmJsonNode_t* cmJsonDuplicateNode( cmJsonH_t h, const cmJsonNode_t* np, cmJsonNode_t* parentPtr )
  2127. {
  2128. cmJs_t* p = _cmJsonHandleToPtr(h);
  2129. assert( _cmJsonValidateNode(p,np,NULL) == kOkJsRC );
  2130. return _cmJsonDuplicateNode(p,np,parentPtr);
  2131. }
  2132. cmJsRC_t cmJsonMergeObjectNodes( cmJsonH_t h, cmJsonNode_t* dstObjNodePtr, const cmJsonNode_t* srcObjNodePtr )
  2133. {
  2134. assert( dstObjNodePtr!=NULL && dstObjNodePtr->typeId == kObjectTId );
  2135. assert( srcObjNodePtr!=NULL && srcObjNodePtr->typeId == kObjectTId );
  2136. cmJsRC_t rc = kOkJsRC;
  2137. cmJs_t* p = _cmJsonHandleToPtr(h);
  2138. cmJsonNode_t* cnp = NULL;
  2139. const cmJsonNode_t* snp = srcObjNodePtr->u.childPtr;
  2140. while( snp!=NULL && rc==kOkJsRC )
  2141. {
  2142. cmJsonNode_t* dnp;
  2143. assert( snp->typeId == kPairTId );
  2144. // if the src pair was not found in the dst object ...
  2145. if((rc = _cmJsonFindMemberValue(dstObjNodePtr, cmJsonPairLabel(snp), snp->u.childPtr->siblingPtr->typeId, &dnp )) != kOkJsRC )
  2146. {
  2147. cmJsonNode_t* newPairNodePtr;
  2148. // the only acceptable error is kNodeNotFoundJsRC
  2149. // (in particular we reject kNodeCannotCvtJsRC to avoid duplicating
  2150. // pairs with the same name but different types)
  2151. if( rc != kNodeNotFoundJsRC )
  2152. goto errLabel;
  2153. // create the new pair and attach it to the dst obj node
  2154. if((rc = _cmJsonCreatePair(p,dstObjNodePtr,cmJsonPairLabel(snp),&newPairNodePtr)) != kOkJsRC )
  2155. goto errLabel;
  2156. // duplicate the src pair value node and attcmh it to the new dst node
  2157. if( _cmJsonDuplicateNode(p,snp->u.childPtr->siblingPtr,newPairNodePtr) == NULL )
  2158. rc = p->rc;
  2159. // set kTempJsFl on the new node to use possible cleanup on error later
  2160. newPairNodePtr->typeId = cmSetFlag(newPairNodePtr->typeId,kTempJsFl);
  2161. }
  2162. snp = snp->siblingPtr;
  2163. }
  2164. errLabel:
  2165. // for each dst obj pair
  2166. cnp = dstObjNodePtr->u.childPtr;
  2167. while( cnp != NULL)
  2168. {
  2169. // if this child is a new node
  2170. if( cmIsFlag(cnp->typeId,kTempJsFl) )
  2171. {
  2172. // clear the temp fl
  2173. cnp->typeId = cmClrFlag(cnp->typeId,kTempJsFl);
  2174. // if there was an error remove all new pairs
  2175. if( rc != kOkJsRC )
  2176. cmJsonRemoveNode(h,cnp,true);
  2177. }
  2178. cnp = cnp->siblingPtr;
  2179. }
  2180. return rc;
  2181. }
  2182. void _cmJsonSerialCopy( cmJsSerial_t* rp, const void* sp, unsigned sn )
  2183. {
  2184. assert( rp->nextPtr + sn <= rp->endPtr );
  2185. memcpy(rp->nextPtr,sp,sn);
  2186. rp->nextPtr += sn;
  2187. }
  2188. cmJsRC_t _cmJsonSerializeNode( const cmJsonNode_t* np, cmJsSerial_t* rp )
  2189. {
  2190. cmJsRC_t rc = kOkJsRC;
  2191. // on the first pass rp->basePtr will be NULL so collect size information
  2192. // on the second pass rp->basePtr will be set so copy out data
  2193. // write the type id of this node
  2194. if( rp->basePtr != NULL )
  2195. _cmJsonSerialCopy(rp,&np->typeId,sizeof(np->typeId));
  2196. else
  2197. rp->hdr.byteCnt += sizeof(np->typeId);
  2198. rp->hdr.nodeCnt++;
  2199. switch( np->typeId )
  2200. {
  2201. // write the child count
  2202. case kObjectTId:
  2203. case kArrayTId:
  2204. if( rp->basePtr == NULL )
  2205. rp->hdr.byteCnt += sizeof(unsigned);
  2206. else
  2207. {
  2208. unsigned n = cmJsonChildCount( np );
  2209. _cmJsonSerialCopy(rp,&n,sizeof(unsigned));
  2210. }
  2211. // fall through
  2212. case kPairTId:
  2213. {
  2214. cmJsonNode_t* cnp = np->u.childPtr;
  2215. while(cnp != NULL )
  2216. {
  2217. _cmJsonSerializeNode(cnp,rp);
  2218. cnp = cnp->siblingPtr;
  2219. }
  2220. }
  2221. break;
  2222. case kStringTId:
  2223. // write the string contents
  2224. if( rp->basePtr == NULL )
  2225. rp->hdr.byteCnt += strlen(np->u.stringVal) + 1;
  2226. else
  2227. _cmJsonSerialCopy( rp, np->u.stringVal, strlen(np->u.stringVal)+1 );
  2228. break;
  2229. case kIntTId:
  2230. // write the int value
  2231. if( rp->basePtr == NULL )
  2232. rp->hdr.byteCnt += sizeof(np->u.intVal);
  2233. else
  2234. _cmJsonSerialCopy(rp,&np->u.intVal,sizeof(np->u.intVal));
  2235. break;
  2236. case kRealTId:
  2237. // write the real value
  2238. if( rp->basePtr == NULL )
  2239. rp->hdr.byteCnt += sizeof(np->u.realVal);
  2240. else
  2241. _cmJsonSerialCopy(rp, &np->u.realVal, sizeof(np->u.realVal));
  2242. break;
  2243. }
  2244. return rc;
  2245. }
  2246. unsigned cmJsonSerialByteCount( const cmJsonNode_t* np )
  2247. {
  2248. cmJsRC_t rc;
  2249. cmJsSerial_t vr;
  2250. memset(&vr,0,sizeof(vr));
  2251. // make a first pass to determine the size of the buffer
  2252. if((rc = _cmJsonSerializeNode(np,&vr)) != kOkJsRC )
  2253. return rc;
  2254. // increment the buffer size to include the buffer header
  2255. return (4*sizeof(unsigned)) + vr.hdr.byteCnt;
  2256. }
  2257. cmJsRC_t cmJsonSerialize( const cmJsonNode_t* np, void* buf, unsigned bufByteCnt )
  2258. {
  2259. cmJsRC_t rc = kOkJsRC;
  2260. cmJsSerial_t vr;
  2261. memset(&vr,0,sizeof(vr));
  2262. // setup the serial buffer
  2263. vr.hdr.id = 'json';
  2264. vr.hdr.byteCnt = bufByteCnt - (2*sizeof(unsigned));
  2265. vr.hdr.version = 0;
  2266. vr.basePtr = buf;
  2267. vr.nextPtr = vr.basePtr;
  2268. vr.endPtr = vr.basePtr + bufByteCnt;
  2269. // write the header recd
  2270. _cmJsonSerialCopy(&vr, &vr.hdr.id, sizeof(unsigned));
  2271. _cmJsonSerialCopy(&vr, &vr.hdr.byteCnt, sizeof(unsigned));
  2272. _cmJsonSerialCopy(&vr, &vr.hdr.nodeCnt, sizeof(unsigned));
  2273. _cmJsonSerialCopy(&vr, &vr.hdr.version, sizeof(unsigned));
  2274. // copy the node data into the serial buffer
  2275. if((rc = _cmJsonSerializeNode(np,&vr)) != kOkJsRC )
  2276. return rc;
  2277. vr.basePtr = buf;
  2278. vr.nextPtr = vr.basePtr;
  2279. _cmJsonSerialCopy(&vr, &vr.hdr.id, sizeof(unsigned));
  2280. _cmJsonSerialCopy(&vr, &vr.hdr.byteCnt, sizeof(unsigned));
  2281. _cmJsonSerialCopy(&vr, &vr.hdr.nodeCnt, sizeof(unsigned));
  2282. return rc;
  2283. }
  2284. cmJsRC_t cmJsonSerializeTree( cmJsonH_t h, const cmJsonNode_t* np, void** bufPtrPtr, unsigned* bufByteCntPtr)
  2285. {
  2286. cmJsRC_t rc;
  2287. cmJsSerial_t vr;
  2288. memset(&vr,0,sizeof(vr));
  2289. cmJs_t* p = _cmJsonHandleToPtr(h);
  2290. assert( bufPtrPtr != NULL && bufByteCntPtr != NULL );
  2291. *bufPtrPtr = NULL;
  2292. *bufByteCntPtr = 0;
  2293. if( np == NULL )
  2294. np = p->rootPtr;
  2295. // validate the tree
  2296. if((rc = _cmJsonValidateNode(p,np,np->ownerPtr)) != kOkJsRC )
  2297. return rc;
  2298. // increment the buffer size to include the buffer header
  2299. p->serialByteCnt = cmJsonSerialByteCount(np);
  2300. // allocate the serial buffer memory
  2301. p->serialBufPtr = cmMemResize( char, p->serialBufPtr, p->serialByteCnt );
  2302. // serialize the tree
  2303. if((rc = cmJsonSerialize(np, p->serialBufPtr, p->serialByteCnt )) != kOkJsRC )
  2304. return rc;
  2305. *bufPtrPtr = p->serialBufPtr;
  2306. *bufByteCntPtr = p->serialByteCnt;
  2307. return rc;
  2308. }
  2309. const void* _cmJsonDeserialAdv( cmJsDeserial_t* rp, unsigned n )
  2310. {
  2311. const void* vp = rp->nextPtr;
  2312. rp->nextPtr += n;
  2313. assert(rp->nextPtr <= rp->endPtr);
  2314. assert(rp->nodeIdx <= rp->nodeCnt);
  2315. return vp;
  2316. }
  2317. int _cmJsonDeserialInt( cmJsDeserial_t* rp )
  2318. { return *(const int*)_cmJsonDeserialAdv(rp,sizeof(int)); }
  2319. unsigned _cmJsonDeserialUint( cmJsDeserial_t* rp )
  2320. { return *(const unsigned*)_cmJsonDeserialAdv(rp,sizeof(unsigned)); }
  2321. double _cmJsonDeserialReal( cmJsDeserial_t* rp )
  2322. { return *(const double*)_cmJsonDeserialAdv(rp,sizeof(double)); }
  2323. cmJsRC_t _cmJsonDeserializeNode( cmJs_t* p, cmJsonNode_t* parentPtr, cmJsDeserial_t* rp )
  2324. {
  2325. cmJsRC_t rc = kOkJsRC;
  2326. unsigned typeId = _cmJsonDeserialUint(rp);
  2327. unsigned childCnt = 0;
  2328. cmJsonNode_t* newParentPtr = NULL;
  2329. rp->nodeIdx++;
  2330. switch( typeId )
  2331. {
  2332. case kPairTId:
  2333. rc = _cmJsonCreateNode(p,parentPtr,typeId,&newParentPtr);
  2334. childCnt = 2;
  2335. break;
  2336. case kObjectTId:
  2337. case kArrayTId:
  2338. rc = _cmJsonCreateNode(p,parentPtr,typeId,&newParentPtr);
  2339. childCnt = _cmJsonDeserialUint(rp);
  2340. break;
  2341. case kStringTId:
  2342. {
  2343. unsigned sn = strlen(rp->nextPtr);
  2344. rc = _cmJsonCreateString( p, parentPtr, rp->nextPtr, sn,NULL);
  2345. _cmJsonDeserialAdv(rp,sn+1);
  2346. }
  2347. break;
  2348. case kIntTId:
  2349. {
  2350. int v = _cmJsonDeserialInt(rp);
  2351. rc = _cmJsonCreateInt( p, parentPtr, v, NULL );
  2352. }
  2353. break;
  2354. case kRealTId:
  2355. {
  2356. double v = _cmJsonDeserialReal(rp);
  2357. rc = _cmJsonCreateReal( p, parentPtr, v, NULL );
  2358. }
  2359. break;
  2360. case kNullTId:
  2361. rc = _cmJsonCreateNull( p, parentPtr, NULL );
  2362. break;
  2363. case kTrueTId:
  2364. rc = _cmJsonCreateBool( p, parentPtr, true, NULL );
  2365. break;
  2366. case kFalseTId:
  2367. rc = _cmJsonCreateBool( p, parentPtr, false, NULL );
  2368. break;
  2369. default:
  2370. assert(0);
  2371. break;
  2372. }
  2373. if( rc != kOkJsRC )
  2374. return rc;
  2375. // if the current node is a parent
  2376. if( childCnt > 0 )
  2377. {
  2378. unsigned i;
  2379. assert( newParentPtr != NULL );
  2380. for(i=0; i<childCnt; ++i)
  2381. if((rc= _cmJsonDeserializeNode( p, newParentPtr, rp )) != kOkJsRC )
  2382. return rc;
  2383. }
  2384. return rc;
  2385. }
  2386. cmJsRC_t _cmJsonDeserialize( cmJs_t* p, const void* vbuf, cmJsonNode_t* altRootPtr )
  2387. {
  2388. cmJsDeserial_t r;
  2389. cmJsonNode_t* rootPtr = altRootPtr == NULL ? p->rootPtr : altRootPtr;
  2390. const char* buf = (const char*)vbuf;
  2391. memset(&r,0,sizeof(r));
  2392. r.nextPtr = buf;
  2393. r.endPtr = buf + (4*sizeof(unsigned)); // the buf must at least contain a header
  2394. // read the buffer header
  2395. unsigned hdrId = _cmJsonDeserialUint(&r);
  2396. unsigned byteCnt = _cmJsonDeserialUint(&r);
  2397. r.nodeCnt = _cmJsonDeserialUint(&r);
  2398. /*unsigned version =*/ _cmJsonDeserialUint(&r);
  2399. if( hdrId != 'json' )
  2400. return _cmJsonError(p,kSerialErrJsRC,"The buffer does not have the correct header.");
  2401. if( byteCnt < (4*sizeof(unsigned)) )
  2402. return _cmJsonError(p,kSerialErrJsRC,"The buffer is too small to be contain any information.");
  2403. // change the buffer end pointer to the correct size based
  2404. // on the the byte count stored in the buffer
  2405. r.endPtr = buf + byteCnt + (2*sizeof(unsigned));
  2406. return _cmJsonDeserializeNode(p, rootPtr, &r );
  2407. }
  2408. cmJsRC_t cmJsonDeserialize( cmJsonH_t h, const void* bufPtr, cmJsonNode_t* altRootPtr )
  2409. {
  2410. cmJs_t* p = _cmJsonHandleToPtr(h);
  2411. return _cmJsonDeserialize(p,bufPtr,altRootPtr);
  2412. }
  2413. cmJsRC_t cmJsonLeafToString( const cmJsonNode_t* np, cmChar_t* buf, unsigned bufCharCnt )
  2414. {
  2415. const char* cp = NULL;
  2416. unsigned n = 0;
  2417. assert( buf!=NULL && bufCharCnt > 0 );
  2418. switch(np->typeId & kMaskTId )
  2419. {
  2420. case kStringTId:
  2421. cp = np->u.stringVal==NULL ? "" : np->u.stringVal;
  2422. break;
  2423. case kNullTId:
  2424. cp = "null";
  2425. break;
  2426. case kTrueTId:
  2427. cp = "true";
  2428. break;
  2429. case kFalseTId:
  2430. cp = "false";
  2431. break;
  2432. case kIntTId:
  2433. n = snprintf(buf,bufCharCnt,"%i",np->u.intVal)+1;
  2434. break;
  2435. case kRealTId:
  2436. n = snprintf(buf,bufCharCnt,"%f",np->u.realVal)+1;
  2437. break;
  2438. default:
  2439. assert(0);
  2440. return kInvalidNodeTypeJsRC;
  2441. }
  2442. if( cp != NULL )
  2443. {
  2444. n = strlen(cp)+1;
  2445. if( bufCharCnt < n )
  2446. n = bufCharCnt;
  2447. strncpy(buf,cp,n);
  2448. /*
  2449. n = strlen(np->u.stringVal)+1;
  2450. if( bufCharCnt < n )
  2451. n = bufCharCnt;
  2452. strncpy(buf,np->u.stringVal,n);
  2453. */
  2454. }
  2455. buf[bufCharCnt-1]=0;
  2456. assert( n>0 && n < bufCharCnt );
  2457. return n == bufCharCnt ? kBufTooSmallJsRC : kOkJsRC ;
  2458. }
  2459. cmJsRC_t _cmJsonRptCsvTokErr( cmJs_t* p, unsigned lineNo, cmLexH lexH, const char* iFn )
  2460. {
  2461. unsigned n = cmMin(31,cmLexTokenCharCount(lexH));
  2462. char b[n+1];
  2463. strncpy(b,cmLexTokenText(lexH),n);
  2464. b[n]=0;
  2465. return _cmJsonError( p, kCsvErrJsRC, "Unexpected token '%s' during CSV parse on line %i of '%s'.",b,cmLexCurrentLineNumber(lexH),cmStringNullGuard(iFn));
  2466. }
  2467. cmJsRC_t _cmJsonRptCsvTypeErr( cmJs_t* p, unsigned lineNo, cmLexH lexH, const char* iFn, const char* actualTypeStr, unsigned expTypeId )
  2468. {
  2469. unsigned n = cmMin(31,cmLexTokenCharCount(lexH));
  2470. char b[n+1];
  2471. strncpy(b,cmLexTokenText(lexH),n);
  2472. b[n]=0;
  2473. return _cmJsonError( p, kCsvErrJsRC, "Unexpected token '%s' during CSV parse on line %i of '%s'.\nExpected type:%s actual type:%s",b,cmLexCurrentLineNumber(lexH),cmStringNullGuard(iFn),_cmJsonNodeTypeIdToLabel(expTypeId),actualTypeStr);
  2474. }
  2475. cmJsRC_t cmJsonFromCSV( cmJsonH_t h, const char* iFn, cmJsonNode_t* parentNodePtr, cmJsonNode_t** arrayNodePtrPtr )
  2476. {
  2477. enum
  2478. {
  2479. kCommaTokId = kUserLexTId+1,
  2480. kIntTokId,
  2481. kRealTokId,
  2482. kTrueTokId,
  2483. kFalseTokId,
  2484. kStringTokId,
  2485. kBoolTokId
  2486. };
  2487. typedef struct field_str
  2488. {
  2489. char* fieldLabel;
  2490. unsigned typeId;
  2491. struct field_str* linkPtr;
  2492. } field_t;
  2493. cmJsRC_t rc = kOkJsRC;
  2494. cmJs_t* p = _cmJsonHandleToPtr(h);
  2495. cmLexH lexH = cmLexInit( NULL, 0, 0, p->err.rpt );
  2496. field_t* fieldList = NULL;
  2497. cmJsonNode_t* arrayNodePtr = NULL;
  2498. cmJsonNode_t* objNodePtr = NULL;
  2499. unsigned lineNo = 0;
  2500. field_t* fieldPtr = NULL;
  2501. field_t* lp = NULL;
  2502. unsigned tokId;
  2503. unsigned fieldIdx = 0;
  2504. // validate the init state of the lexer
  2505. if( cmLexIsValid(lexH) == false )
  2506. {
  2507. rc = _cmJsonError( p, kLexErrJsRC, "Lexer initialization failed on CSV parse of '%s'.",cmStringNullGuard(iFn));
  2508. goto errLabel;
  2509. }
  2510. // register CSV specific tokens
  2511. cmLexRegisterToken( lexH, kCommaTokId, ",");
  2512. cmLexRegisterToken( lexH, kIntTokId, "int");
  2513. cmLexRegisterToken( lexH, kRealTokId, "real");
  2514. cmLexRegisterToken( lexH, kTrueTokId, "true");
  2515. cmLexRegisterToken( lexH, kFalseTokId, "false");
  2516. cmLexRegisterToken( lexH, kStringTokId, "string");
  2517. cmLexRegisterToken( lexH, kBoolTokId, "bool");
  2518. // lex the file
  2519. if( cmLexSetFile( lexH, iFn ) != kOkLexRC )
  2520. {
  2521. rc = _cmJsonError( p, kLexErrJsRC, "Lex failed on CSV parse of '%s'.",cmStringNullGuard(iFn));
  2522. goto errLabel;
  2523. }
  2524. // create the parent array
  2525. if((arrayNodePtr = cmJsonCreateArray( h, parentNodePtr )) == NULL )
  2526. {
  2527. rc = _cmJsonError( p, kCsvErrJsRC, "CSV array create failed during parse of '%s'.",cmStringNullGuard(iFn));
  2528. goto errLabel;
  2529. }
  2530. // iterate through the lexer file
  2531. while(((tokId = cmLexGetNextToken(lexH)) != kErrorLexTId) && (tokId != kEofLexTId) )
  2532. {
  2533. unsigned fieldTypeTokId = kInvalidTId;
  2534. switch( cmLexCurrentLineNumber(lexH) )
  2535. {
  2536. // line 1 contains the field type labels (e.g. int,real,string,true,false,bool)
  2537. case 1:
  2538. switch(tokId)
  2539. {
  2540. case kCommaTokId:
  2541. break;
  2542. case kIntTokId:
  2543. fieldTypeTokId = (fieldTypeTokId==kInvalidTId) ? kIntTId : fieldTypeTokId;
  2544. case kRealTokId:
  2545. fieldTypeTokId = (fieldTypeTokId==kInvalidTId) ? kRealTId : fieldTypeTokId;
  2546. case kTrueTokId:
  2547. fieldTypeTokId = (fieldTypeTokId==kInvalidTId) ? kTrueTId : fieldTypeTokId;
  2548. case kFalseTokId:
  2549. fieldTypeTokId = (fieldTypeTokId==kInvalidTId) ? kFalseTId : fieldTypeTokId;
  2550. case kBoolTokId:
  2551. fieldTypeTokId = (fieldTypeTokId==kInvalidTId) ? kFalseTId : fieldTypeTokId;
  2552. case kStringTokId:
  2553. fieldTypeTokId = (fieldTypeTokId==kInvalidTId) ? kStringTId : fieldTypeTokId;
  2554. // create and intitialize a new field
  2555. field_t* rp = cmMemAllocZ( field_t, 1 );
  2556. rp->fieldLabel = NULL;
  2557. rp->typeId = fieldTypeTokId;
  2558. rp->linkPtr = NULL;
  2559. // and add it to the end of the field list
  2560. if( fieldList == NULL )
  2561. fieldList = rp;
  2562. else
  2563. fieldPtr->linkPtr = rp;
  2564. // fieldPtr points to the end of the list
  2565. fieldPtr = rp;
  2566. break;
  2567. default:
  2568. rc = _cmJsonRptCsvTokErr( p, 1, lexH, iFn );
  2569. goto errLabel;
  2570. }
  2571. break;
  2572. // line 2 contains the field labels
  2573. case 2:
  2574. if( fieldIdx == 0 )
  2575. fieldPtr = fieldList;
  2576. ++fieldIdx;
  2577. switch(tokId)
  2578. {
  2579. case kCommaTokId:
  2580. break;
  2581. // all line 2 tokens must be identifiers or q-strings
  2582. case kIdentLexTId:
  2583. case kQStrLexTId:
  2584. if( fieldPtr == NULL )
  2585. {
  2586. rc = _cmJsonError( p, kCsvErrJsRC, "More fields on line 2 than type specifiers on line 1 of '%s'.",cmStringNullGuard(iFn));
  2587. goto errLabel;
  2588. }
  2589. else
  2590. {
  2591. // set the field name in the field list
  2592. unsigned n = cmLexTokenCharCount(lexH);
  2593. fieldPtr->fieldLabel = cmMemAllocZ( char, n+1 );
  2594. strncpy(fieldPtr->fieldLabel,cmLexTokenText(lexH),n);
  2595. fieldPtr->fieldLabel[n] = 0;
  2596. fieldPtr = fieldPtr->linkPtr;
  2597. }
  2598. break;
  2599. default:
  2600. rc = _cmJsonRptCsvTokErr( p, 2, lexH, iFn );
  2601. goto errLabel;
  2602. }
  2603. break;
  2604. // lines 3 to end of file contain data
  2605. default:
  2606. {
  2607. int ival = 0;
  2608. cmReal_t rval = 0;
  2609. // if we are starting a new line in the CSV file
  2610. if( lineNo != cmLexCurrentLineNumber(lexH) )
  2611. {
  2612. // verify that field ptr is pointing to the end of the field list
  2613. if( fieldPtr != NULL )
  2614. {
  2615. rc = _cmJsonError( p, kCsvErrJsRC, "Missing columns were detected on line %i in CSV file '%s'.", lineNo, cmStringNullGuard(iFn));
  2616. goto errLabel;
  2617. }
  2618. fieldPtr = fieldList;
  2619. lineNo = cmLexCurrentLineNumber(lexH);
  2620. // create the object to hold the fields on this line
  2621. if((objNodePtr = cmJsonCreateObject( h, arrayNodePtr )) == NULL )
  2622. {
  2623. rc = _cmJsonError( p, kCsvErrJsRC, "Object node create failed on line %i in CSV file '%s'.",lineNo,cmStringNullGuard(iFn));
  2624. goto errLabel;
  2625. }
  2626. }
  2627. if( tokId == kCommaTokId )
  2628. continue;
  2629. if( fieldPtr == NULL )
  2630. {
  2631. rc = _cmJsonError( p, kCsvErrJsRC, "More columns than fields on line %i in CSV file '%s'.", lineNo,cmStringNullGuard(iFn));
  2632. goto errLabel;
  2633. }
  2634. // given the tokens type convert the token string into a value
  2635. switch(tokId)
  2636. {
  2637. case kRealLexTId:
  2638. #ifdef CM_FLOAT_REAL
  2639. rval = cmLexTokenFloat(lexH);
  2640. #else
  2641. rval = cmLexTokenDouble(lexH);
  2642. #endif
  2643. ival = (int)rval;
  2644. if( fieldPtr->typeId == kStringTId )
  2645. {
  2646. rc = _cmJsonRptCsvTypeErr(p, lineNo, lexH, iFn, "numeric", fieldPtr->typeId );
  2647. goto errLabel;
  2648. }
  2649. break;
  2650. case kIntLexTId:
  2651. case kHexLexTId:
  2652. ival = cmLexTokenInt(lexH);
  2653. rval = ival;
  2654. if( fieldPtr->typeId == kStringTId )
  2655. {
  2656. rc = _cmJsonRptCsvTypeErr(p, lineNo, lexH, iFn, "numeric", fieldPtr->typeId );
  2657. goto errLabel;
  2658. }
  2659. break;
  2660. case kTrueTokId:
  2661. ival = 1;
  2662. rval = 1.0;
  2663. break;
  2664. case kFalseTokId:
  2665. ival = 0;
  2666. rval = 0.0;
  2667. break;
  2668. case kIdentLexTId:
  2669. case kQStrLexTId:
  2670. if( fieldPtr->typeId != kStringTId )
  2671. {
  2672. rc = _cmJsonRptCsvTypeErr(p, lineNo, lexH, iFn, "string", fieldPtr->typeId );
  2673. goto errLabel;
  2674. }
  2675. break;
  2676. default:
  2677. rc = _cmJsonRptCsvTokErr( p, lineNo, lexH, iFn );
  2678. goto errLabel;
  2679. }
  2680. // create the pair object from the current field label and value
  2681. switch(fieldPtr->typeId)
  2682. {
  2683. case kIntTId:
  2684. rc = cmJsonInsertPairInt( h, objNodePtr, fieldPtr->fieldLabel, ival );
  2685. break;
  2686. case kRealTId:
  2687. rc = cmJsonInsertPairReal( h, objNodePtr, fieldPtr->fieldLabel, rval );
  2688. break;
  2689. case kTrueTId:
  2690. case kFalseTId:
  2691. rc = cmJsonInsertPairBool( h, objNodePtr, fieldPtr->fieldLabel, ival );
  2692. break;
  2693. case kStringTId:
  2694. rc = cmJsonInsertPairStringN( h, objNodePtr, fieldPtr->fieldLabel, cmLexTokenText(lexH), cmLexTokenCharCount(lexH) );
  2695. break;
  2696. default:
  2697. {
  2698. assert(0);
  2699. goto errLabel;
  2700. }
  2701. }
  2702. if( rc != kOkJsRC )
  2703. goto errLabel;
  2704. fieldPtr = fieldPtr->linkPtr;
  2705. }
  2706. break;
  2707. }
  2708. }
  2709. errLabel:
  2710. if( cmLexFinal(&lexH) != kOkLexRC )
  2711. {
  2712. rc = _cmJsonError( p, kLexErrJsRC, "Lexer finalize failed on CSV parse of '%s'.",cmStringNullGuard(iFn));
  2713. goto errLabel;
  2714. }
  2715. lp = fieldList;
  2716. while( lp!=NULL )
  2717. {
  2718. field_t* pp = lp->linkPtr;
  2719. cmMemPtrFree(&lp->fieldLabel);
  2720. cmMemPtrFree(&lp);
  2721. lp = pp;
  2722. }
  2723. if( rc != kOkJsRC )
  2724. _cmJsonRemoveNode( p, arrayNodePtr, true, true );
  2725. if( rc == kOkJsRC && arrayNodePtrPtr != NULL )
  2726. *arrayNodePtrPtr = arrayNodePtr;
  2727. return rc;
  2728. }
  2729. cmJsRC_t cmJsonToCSV( cmJsonH_t h, const char* oFn, const cmJsonNode_t* arrayNodePtr )
  2730. {
  2731. assert( arrayNodePtr->typeId == kArrayTId );
  2732. typedef struct r_str
  2733. {
  2734. const char* fieldLabel;
  2735. unsigned typeId;
  2736. struct r_str* linkPtr;
  2737. } field_t;
  2738. cmJs_t* p = _cmJsonHandleToPtr(h);
  2739. cmJsRC_t rc = kOkJsRC;
  2740. unsigned arrayCnt = cmJsonChildCount(arrayNodePtr);
  2741. field_t* fieldList = NULL;
  2742. FILE* fp = NULL;
  2743. field_t* lp = NULL;
  2744. unsigned i,j;
  2745. // for each object in the array
  2746. for(i=0; i<arrayCnt; ++i)
  2747. {
  2748. const cmJsonNode_t* objNodePtr = cmJsonArrayElementC( arrayNodePtr, i );
  2749. assert( objNodePtr->typeId == kObjectTId );
  2750. // for each pair in the object
  2751. for(j=0; j<cmJsonChildCount(objNodePtr); ++j)
  2752. {
  2753. const cmJsonNode_t* pairNodePtr = cmJsonArrayElementC( objNodePtr, j );
  2754. const char* pairLabel = cmJsonPairLabel(pairNodePtr);
  2755. lp = fieldList;
  2756. // find this field in the field list
  2757. for(; lp != NULL; lp = lp->linkPtr )
  2758. if( strcmp(lp->fieldLabel,pairLabel) == 0)
  2759. {
  2760. unsigned typeId = cmJsonPairTypeId(pairNodePtr);
  2761. switch( typeId )
  2762. {
  2763. case kIntTId:
  2764. case kRealTId:
  2765. case kTrueTId:
  2766. case kFalseTId:
  2767. case kStringTId:
  2768. break;
  2769. default:
  2770. rc = _cmJsonError( p, kInvalidNodeTypeJsRC, "Field '%s' has type '%s' which cannot be written by cmJsonToCSV().",cmStringNullGuard(pairLabel),_cmJsonNodeTypeIdToLabel(typeId) );
  2771. goto errLabel;
  2772. }
  2773. if( typeId != lp->typeId )
  2774. {
  2775. rc = _cmJsonError( p, kInvalidNodeTypeJsRC, "All nodes for a field label '%s' do not have the same type. '%s' != '%s'",cmStringNullGuard(pairLabel), _cmJsonNodeTypeIdToLabel(typeId), _cmJsonNodeTypeIdToLabel(lp->typeId) );
  2776. goto errLabel;
  2777. }
  2778. break;
  2779. }
  2780. // if this field was not found then insert it
  2781. if( lp == NULL )
  2782. {
  2783. field_t* rp = (field_t*)cmLHeapAlloc(p->heapH,sizeof(field_t));
  2784. rp->fieldLabel = pairLabel;
  2785. rp->linkPtr = fieldList;
  2786. rp->typeId = cmJsonPairTypeId(pairNodePtr);
  2787. fieldList = rp;
  2788. }
  2789. }
  2790. }
  2791. // create the output file
  2792. if((fp = fopen(oFn,"wt")) == NULL )
  2793. {
  2794. rc = _cmJsonError( p, kFileCreateErrJsRC, "CSV file '%s' create failed.", oFn );
  2795. goto errLabel;
  2796. }
  2797. // write the field type
  2798. lp = fieldList;
  2799. for(; lp!=NULL; lp=lp->linkPtr)
  2800. {
  2801. fprintf(fp,"%s", _cmJsonNodeTypeIdToLabel(lp->typeId));
  2802. if( lp->linkPtr != NULL )
  2803. fprintf(fp,",");
  2804. }
  2805. fprintf(fp,"\n");
  2806. // write the field label
  2807. lp = fieldList;
  2808. for(; lp!=NULL; lp=lp->linkPtr)
  2809. {
  2810. fprintf(fp,"\"%s\"", lp->fieldLabel);
  2811. if( lp->linkPtr != NULL )
  2812. fprintf(fp,",");
  2813. }
  2814. fprintf(fp,"\n");
  2815. // for each object in the array
  2816. for(i=0; i<arrayCnt; ++i)
  2817. {
  2818. unsigned j;
  2819. const cmJsonNode_t* objNodePtr = cmJsonArrayElementC( arrayNodePtr, i );
  2820. unsigned fieldCnt = cmJsonChildCount(objNodePtr);
  2821. lp = fieldList;
  2822. // for each field ...
  2823. for(j=0; lp!=NULL; lp=lp->linkPtr,++j)
  2824. {
  2825. cmJsonNode_t* valNodePtr;
  2826. // ... locate the pair given the field label
  2827. if((valNodePtr = cmJsonFindValue(h,lp->fieldLabel, objNodePtr, lp->typeId )) == NULL)
  2828. {
  2829. // no pair was found for the field label - output a NULL value
  2830. switch( lp->typeId )
  2831. {
  2832. case kIntTId:
  2833. fprintf(fp,"%i",0);
  2834. break;
  2835. case kRealTId:
  2836. fprintf(fp,"%f",0.0);
  2837. break;
  2838. case kTrueTId:
  2839. case kFalseTId:
  2840. fprintf(fp,"%i",0);
  2841. break;
  2842. case kStringTId:
  2843. fprintf(fp,"\"\"");
  2844. break;
  2845. default:
  2846. assert(0);
  2847. break;
  2848. }
  2849. //rc = _cmJsonError( p, kNodeNotFoundJsRC,"No field with label '%s' was found.", lp->fieldLabel);
  2850. //goto errLabel;
  2851. }
  2852. else
  2853. {
  2854. switch( valNodePtr->typeId )
  2855. {
  2856. case kIntTId:
  2857. fprintf(fp,"%i", valNodePtr->u.intVal);
  2858. break;
  2859. case kRealTId:
  2860. fprintf(fp,"%e", valNodePtr->u.realVal);
  2861. break;
  2862. case kTrueTId:
  2863. case kFalseTId:
  2864. fprintf(fp,"%i", valNodePtr->u.boolVal);
  2865. break;
  2866. case kStringTId:
  2867. fprintf(fp,"\"%s\"", valNodePtr->u.stringVal);
  2868. break;
  2869. default:
  2870. assert(0);
  2871. break;
  2872. }
  2873. }
  2874. if( j < fieldCnt-1 )
  2875. fprintf(fp,",");
  2876. }
  2877. fprintf(fp,"\n");
  2878. }
  2879. errLabel:
  2880. if( fp != NULL )
  2881. fclose(fp);
  2882. lp = fieldList;
  2883. while( lp!=NULL )
  2884. {
  2885. field_t* pp = lp->linkPtr;
  2886. cmLHeapFree(p->heapH,lp);
  2887. lp = pp;
  2888. }
  2889. return rc;
  2890. }
  2891. void _cmJsonPrintIndent( cmRpt_t* rpt, unsigned indent )
  2892. {
  2893. if( indent )
  2894. {
  2895. char spaces[indent+1];
  2896. spaces[indent]=0;
  2897. memset(spaces,' ',indent);
  2898. cmRptPrint(rpt,spaces);
  2899. }
  2900. }
  2901. void _cmJsonPrintNode( const cmJsonNode_t* np, cmRpt_t* rpt, unsigned indent )
  2902. {
  2903. unsigned childCnt = 0;
  2904. char eoObjStr[] = "}";
  2905. char eoArrStr[] = "]";
  2906. char eoPairStr[] = "\n";
  2907. char commaStr[] = ",\n";
  2908. char colonStr[] = ": ";
  2909. const char* eleStr = NULL;
  2910. const char* lastEleStr = NULL;
  2911. const char* eoStr = NULL;
  2912. unsigned localIndent = 0;
  2913. switch(np->typeId)
  2914. {
  2915. case kObjectTId:
  2916. cmRptPrint(rpt,"\n");
  2917. _cmJsonPrintIndent(rpt,indent);
  2918. cmRptPrint(rpt,"{\n");
  2919. childCnt = cmJsonChildCount(np);
  2920. eoStr = eoObjStr;
  2921. localIndent = 2;
  2922. break;
  2923. case kArrayTId:
  2924. cmRptPrint(rpt,"\n");
  2925. _cmJsonPrintIndent(rpt,indent);
  2926. cmRptPrint(rpt,"[\n");
  2927. childCnt = cmJsonChildCount(np);
  2928. eoStr = eoArrStr;
  2929. localIndent = 2;
  2930. eleStr = commaStr;
  2931. lastEleStr = "\n";
  2932. break;
  2933. case kPairTId:
  2934. childCnt = cmJsonChildCount(np);
  2935. eleStr = colonStr;
  2936. eoStr = eoPairStr;
  2937. break;
  2938. case kStringTId:
  2939. {
  2940. const char* fmt0 = "\"%s\" ";
  2941. const char* fmt1 = "%s";
  2942. const char* fmt = fmt0;
  2943. // if this string is the label part of a pair
  2944. if( np->u.stringVal != NULL && np->ownerPtr != NULL && cmJsonIsPair(np->ownerPtr) && np->ownerPtr->u.childPtr == np )
  2945. {
  2946. // and the label has no white space
  2947. char* cp = np->u.stringVal;
  2948. while( *cp!=0 && isspace(*cp)==false )
  2949. ++cp;
  2950. // then print without quotes
  2951. if( *cp == 0 )
  2952. fmt = fmt1;
  2953. }
  2954. cmRptPrintf(rpt,fmt,np->u.stringVal==NULL ? "" : np->u.stringVal);
  2955. }
  2956. break;
  2957. case kIntTId:
  2958. cmRptPrintf(rpt,"%i ",np->u.intVal);
  2959. break;
  2960. case kRealTId:
  2961. cmRptPrintf(rpt,"%f ",np->u.realVal);
  2962. break;
  2963. case kNullTId:
  2964. cmRptPrint(rpt,"null ");
  2965. break;
  2966. case kTrueTId:
  2967. cmRptPrint(rpt,"true ");
  2968. break;
  2969. case kFalseTId:
  2970. cmRptPrint(rpt,"false ");
  2971. break;
  2972. }
  2973. if( childCnt )
  2974. {
  2975. indent += localIndent;
  2976. unsigned i;
  2977. cmJsonNode_t* cnp = np->u.childPtr;
  2978. for(i=0; i<childCnt; ++i)
  2979. {
  2980. assert(cnp != NULL);
  2981. if( np->typeId != kPairTId )
  2982. _cmJsonPrintIndent(rpt,indent);
  2983. _cmJsonPrintNode(cnp,rpt,indent);
  2984. cnp = cnp->siblingPtr;
  2985. if( i < childCnt-1 && eleStr != NULL )
  2986. cmRptPrint(rpt,eleStr);
  2987. if( i == childCnt-1 && lastEleStr != NULL )
  2988. cmRptPrint(rpt,lastEleStr);
  2989. }
  2990. indent -= localIndent;
  2991. }
  2992. if( eoStr != NULL )
  2993. {
  2994. _cmJsonPrintIndent(rpt,indent);
  2995. cmRptPrint(rpt,eoStr);
  2996. }
  2997. }
  2998. void cmJsonPrintTree( const cmJsonNode_t* np, cmRpt_t* rpt )
  2999. {
  3000. _cmJsonPrintNode(np,rpt,0);
  3001. }
  3002. void _cmJsPrintFile(void* cmRptUserPtr, const cmChar_t* text)
  3003. {
  3004. cmFileH_t* hp = (cmFileH_t*)cmRptUserPtr;
  3005. cmFilePrint(*hp,text);
  3006. }
  3007. cmJsRC_t cmJsonWrite( cmJsonH_t h, const cmJsonNode_t* np, const cmChar_t* fn )
  3008. {
  3009. cmRpt_t rpt;
  3010. cmFileH_t fh = cmFileNullHandle;
  3011. cmJs_t* p = _cmJsonHandleToPtr(h);
  3012. if( np == NULL )
  3013. np = cmJsonRoot(h);
  3014. // create the output file
  3015. if( cmFileOpen(&fh,fn,kWriteFileFl,p->err.rpt) != kOkFileRC )
  3016. return _cmJsonError( p, kFileCreateErrJsRC, "Output file '%s' create failed.", fn );
  3017. // setup a reporter to write to the file
  3018. cmRptSetup(&rpt,_cmJsPrintFile,_cmJsPrintFile,&fh);
  3019. // print the tree to the file
  3020. cmJsonPrintTree(np,&rpt);
  3021. // close the file
  3022. if( cmFileClose(&fh) != kOkFileRC )
  3023. return _cmJsonError( p, kFileCloseErrJsRC, "Output file '%s' close failed.", fn );
  3024. return kOkJsRC;
  3025. }
  3026. cmJsRC_t cmJsonReport( cmJsonH_t h )
  3027. {
  3028. cmJsRC_t rc;
  3029. cmJs_t* p = _cmJsonHandleToPtr(h);
  3030. if((rc = cmJsonValidateTree(h)) != kOkJsRC )
  3031. return rc;
  3032. if(p->rootPtr != NULL )
  3033. _cmJsonPrintNode(p->rootPtr,p->err.rpt,0);
  3034. return rc;
  3035. }
  3036. cmJsRC_t cmJsonErrorCode( cmJsonH_t h )
  3037. {
  3038. cmJs_t* p = _cmJsonHandleToPtr(h);
  3039. return p->rc;
  3040. }
  3041. void cmJsonClearErrorCode( cmJsonH_t h )
  3042. {
  3043. cmJs_t* p = _cmJsonHandleToPtr(h);
  3044. p->rc = kOkJsRC;
  3045. }
  3046. void _cmJsonTestVPrint( void* rptDataPtr, const char* fmt, va_list vl )
  3047. {
  3048. vfprintf(stdout,fmt,vl);
  3049. }
  3050. void _cmJsonTestPrint( void* userPtr, const cmChar_t* text )
  3051. {
  3052. fputs(text,stdout);
  3053. }
  3054. //( { label:cmJsonEx }
  3055. //
  3056. // cmJsonTest() demonstrates some JSON tree operations.
  3057. //
  3058. cmJsRC_t cmJsonTest( const char* fn, cmCtx_t* ctx )
  3059. {
  3060. cmJsRC_t rc = kOkJsRC;
  3061. cmJsRC_t rc1 = kOkJsRC;
  3062. cmJsonH_t h = cmJsonNullHandle;
  3063. cmJsonH_t h1 = cmJsonNullHandle;
  3064. void* sbp = NULL;
  3065. unsigned sbn = 0;
  3066. cmJsonNode_t* np = NULL;
  3067. cmRpt_t* rpt = &ctx->rpt;
  3068. // initialize an empty JSON tree
  3069. if((rc = cmJsonInitialize(&h,ctx)) != kOkJsRC )
  3070. goto errLabel;
  3071. // load the tree from a file
  3072. if((rc = cmJsonParseFile(h,fn,NULL)) != kOkJsRC )
  3073. goto errLabel;
  3074. // print the tree
  3075. cmJsonReport(h);
  3076. // find an array member named 'mem14'
  3077. if((np = cmJsonFindValue(h,"mem14",NULL,kArrayTId)) == NULL )
  3078. cmRptPrint(rpt,"'mem14' not found.\n");
  3079. else
  3080. {
  3081. cmRptPrint(rpt,"'mem14' found.\n");
  3082. cmJsonPrintTree(np,rpt);
  3083. }
  3084. // remove the array node from the tree
  3085. cmJsonRemoveNode(h,np, true);
  3086. cmRptPrint(rpt,"mem14 removed.\n");
  3087. // print the tree with the array node removed
  3088. cmJsonPrintTree( cmJsonRoot(h), rpt );
  3089. // serialize the tree into a dynamically allocated
  3090. // buffer sbp[sbn].
  3091. if((rc = cmJsonSerializeTree(h,NULL,&sbp,&sbn)) != kOkJsRC )
  3092. goto errLabel;
  3093. else
  3094. cmRptPrint(rpt,"***Serialize Ok.****\n");
  3095. // initialize an empty JSON tree
  3096. if((rc = cmJsonInitialize(&h1,ctx)) != kOkJsRC )
  3097. goto errLabel;
  3098. // deserialize sbp[sbn] into the empty tree
  3099. if((rc = cmJsonDeserialize(h1,sbp,NULL)) != kOkJsRC )
  3100. goto errLabel;
  3101. else
  3102. {
  3103. cmJsonPrintTree( cmJsonRoot(h1),rpt);
  3104. cmRptPrint(rpt,"***Deserialize Ok.****\n");
  3105. }
  3106. // find an member node named 'mem5'
  3107. if((np = cmJsonFindValue(h,"mem5",NULL,0)) == NULL )
  3108. cmRptPrint(rpt,"mem5 not found.");
  3109. // merge two sub-trees
  3110. if( cmJsonMergeObjectNodes( h, np->u.childPtr,
  3111. np->u.childPtr->siblingPtr) != kOkJsRC )
  3112. {
  3113. cmRptPrint(rpt,"merge failed.");
  3114. }
  3115. else
  3116. {
  3117. cmJsonReport(h);
  3118. }
  3119. errLabel:
  3120. // release the JSON trees
  3121. rc = cmJsonFinalize(&h);
  3122. rc1 = cmJsonFinalize(&h1);
  3123. return rc == kOkJsRC ? rc1 : rc;
  3124. }
  3125. //)