libcm is a C development framework with an emphasis on audio signal processing applications.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

cmJson.c 107KB

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