co.c 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906
  1. /*
  2. WARNING: THIS FILE IS MODIFIED FOR U8G2 (BOM DETECTION REMOVED)
  3. co.c
  4. C Object Library
  5. (c) 2024 Oliver Kraus
  6. https://github.com/olikraus/c-object
  7. CC BY-SA 3.0 https://creativecommons.org/licenses/by-sa/3.0/
  8. -DCO_USE_ZLIB
  9. will enable autodetection of .gz compressed input files (this will require
  10. linking against "-lz")
  11. 28 apr 2024: fixed coMapClone(): Removed strdup(key) because strdup() is
  12. already applied internally
  13. */
  14. #include "co.h"
  15. #include <assert.h>
  16. #include <ctype.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. /*===================================================================*/
  20. /* Generic Public Functions */
  21. /*===================================================================*/
  22. /* print the object, only used for debugging, does not print any \n */
  23. void coPrint(cco o) {
  24. if (o != NULL)
  25. o->fn->print(o);
  26. }
  27. /* Delete the object and all child objects, this will also handle o==NULL */
  28. void coDelete(co o) {
  29. if (o != NULL) {
  30. o->fn->destroy(o);
  31. free(o);
  32. }
  33. }
  34. /* Do a deep clone of the object and return the new objects. Flags are set to
  35. * CO_NONE for the new object tree. */
  36. co coClone(cco o) {
  37. if (o == NULL)
  38. return NULL;
  39. return o->fn->clone(o);
  40. }
  41. long coSize(cco o) {
  42. if (o == NULL)
  43. return 0L;
  44. return o->fn->size(o);
  45. }
  46. /*===================================================================*/
  47. /* Local Helper Functions */
  48. /*===================================================================*/
  49. static co coNewWithData(coFn t, unsigned flags, void *data) {
  50. co o = (co)malloc(sizeof(struct coStruct));
  51. if (o == NULL)
  52. return NULL;
  53. o->fn = t;
  54. o->flags = flags;
  55. if (t->init(o, data) == 0)
  56. return free(o), NULL;
  57. return o;
  58. }
  59. static co coNew(coFn t, unsigned flags) {
  60. return coNewWithData(t, flags, NULL);
  61. }
  62. /*===================================================================*/
  63. /* Dummy / Blank (probably obsolete) */
  64. /*===================================================================*/
  65. int cobInit(co o, void *data);
  66. long cobSize(cco o);
  67. void cobPrint(cco o);
  68. void cobDestroy(co o);
  69. co cobClone(cco o);
  70. struct coFnStruct cobStruct = {cobInit, cobSize, cobPrint, cobDestroy,
  71. cobClone};
  72. coFn coBlankType = &cobStruct;
  73. co coNewBlank() { return coNew(coBlankType, 0); }
  74. int cobInit(co o, void *data) {
  75. o->fn = coBlankType;
  76. return 1;
  77. }
  78. long cobSize(cco o) { return 0; }
  79. void cobPrint(cco o) {}
  80. void cobDestroy(co o) {}
  81. co cobClone(cco o) { return coNew(o->fn, o->flags); }
  82. /*===================================================================*/
  83. /* Vector / Arry Object */
  84. /*===================================================================*/
  85. int coVectorInit(co o, void *data); // data: not used
  86. long coVectorAdd(co o, cco p); // returns the index of the added element or -1
  87. long coVectorSize(cco o);
  88. cco coVectorGet(cco o, long idx);
  89. int coVectorForEach(cco o, coVectorForEachCB cb, void *data);
  90. void coVectorPrint(cco o);
  91. static void coVectorDestroy(co o);
  92. co coVectorMap(cco o, coVectorMapCB cb, void *data);
  93. co coVectorClone(cco o);
  94. struct coFnStruct coVectorStruct = {coVectorInit, coVectorSize, coVectorPrint,
  95. coVectorDestroy, coVectorClone};
  96. coFn coVectorType = &coVectorStruct;
  97. co coNewVector(unsigned flags) { return coNew(coVectorType, flags); }
  98. #define COV_EXTEND 32
  99. int coVectorInit(co o, void *data) {
  100. void *ptr = malloc(COV_EXTEND * sizeof(struct coStruct));
  101. if (ptr == NULL)
  102. return 0;
  103. o->fn = coVectorType;
  104. o->v.list = (cco *)ptr;
  105. o->v.max = COV_EXTEND;
  106. o->v.cnt = 0;
  107. return 1;
  108. }
  109. /*
  110. p will be moved, so maybe a clone is required
  111. returns -1 in case of memory error
  112. otherwise it returns the position where the element was added
  113. */
  114. long coVectorAdd(co o, cco p) {
  115. void *ptr;
  116. assert(coIsVector(o));
  117. while (o->v.max <= o->v.cnt) {
  118. ptr = realloc(o->v.list, (o->v.cnt + COV_EXTEND) * sizeof(co));
  119. if (ptr == NULL)
  120. return -1;
  121. o->v.list = (cco *)ptr;
  122. o->v.max += COV_EXTEND;
  123. }
  124. o->v.list[o->v.cnt] = p;
  125. o->v.cnt++;
  126. return o->v.cnt - 1;
  127. }
  128. long coVectorSize(cco o) {
  129. if (o == NULL)
  130. return 0;
  131. assert(coIsVector(o));
  132. return o->v.cnt;
  133. }
  134. cco coVectorGet(cco o, long idx) {
  135. if (o == NULL)
  136. return NULL;
  137. assert(coIsVector(o));
  138. if (idx < 0)
  139. return NULL;
  140. if (idx >= o->v.cnt)
  141. return NULL;
  142. return o->v.list[idx];
  143. }
  144. /* returns 1 (success) or 0 (no success) */
  145. int coVectorForEach(cco o, coVectorForEachCB cb, void *data) {
  146. long i;
  147. long cnt = o->v.cnt; // not sure what todo if v.cnt is modified...
  148. if (o == NULL)
  149. return 0;
  150. assert(coIsVector(o));
  151. for (i = 0; i < cnt; i++)
  152. if (cb(o, i, o->v.list[i], data) == 0)
  153. return 0;
  154. return 1;
  155. }
  156. static int coVectorPrintCB(cco o, long i, cco e, void *data) {
  157. if (i > 0)
  158. printf(", ");
  159. e->fn->print(e);
  160. return 1;
  161. }
  162. void coVectorPrint(cco o) {
  163. assert(coIsVector(o));
  164. printf("[");
  165. coVectorForEach(o, coVectorPrintCB, NULL);
  166. printf("]");
  167. }
  168. static int coVectorDestroyCB(cco o, long i, cco e, void *data) {
  169. coDelete((co)e); // it is ok to discard the const keyword, really delete here
  170. return 1;
  171. }
  172. static void coVectorDestroy(co o) {
  173. assert(coIsVector(o));
  174. if (o->flags & CO_FREE_VALS)
  175. coVectorForEach(o, coVectorDestroyCB, NULL);
  176. else if ((o->flags & CO_FREE_FIRST) != 0 && o->v.cnt > 0)
  177. coDelete((co)o->v.list[0]);
  178. free(o->v.list);
  179. o->v.list = NULL;
  180. o->v.max = 0;
  181. o->v.cnt = 0;
  182. }
  183. void coVectorClear(co o) {
  184. assert(coIsVector(o));
  185. if (o->flags & CO_FREE_VALS)
  186. coVectorForEach(o, coVectorDestroyCB, NULL);
  187. else if ((o->flags & CO_FREE_FIRST) != 0 && o->v.cnt > 0)
  188. coDelete((co)o->v.list[0]);
  189. o->v.cnt = 0;
  190. }
  191. int coVectorEmpty(cco o) {
  192. assert(coIsVector(o));
  193. if (o->v.cnt == 0)
  194. return 1;
  195. return 0;
  196. }
  197. co coVectorMap(cco o, coVectorMapCB cb, void *data) {
  198. co v = coNewVector(CO_FREE_VALS);
  199. co e;
  200. long i;
  201. assert(coIsVector(o));
  202. for (i = 0; i < o->v.cnt; i++) {
  203. e = cb(o, i, o->v.list[i], data);
  204. if (e == NULL) // memory error?
  205. {
  206. coVectorDestroy(v);
  207. return NULL;
  208. }
  209. if (coVectorAdd(v, e) < 0) // memory error?
  210. {
  211. coVectorDestroy(v);
  212. return NULL;
  213. }
  214. }
  215. return v;
  216. }
  217. co coVectorCloneCB(cco o, long i, cco e, void *data) { return coClone(e); }
  218. co coVectorClone(cco o) { return coVectorMap(o, coVectorCloneCB, NULL); }
  219. /*===================================================================*/
  220. /* special vector functions */
  221. /*===================================================================*/
  222. /*
  223. Replace element inside a vector.
  224. The existing element is free'd according to the flags.
  225. The same will be true with the new element 'e'.
  226. The new element 'e' can be the NULL pointer.
  227. 'i' must be a valid entry into the vector
  228. */
  229. void coVectorSet(co v, long i, cco e) {
  230. assert(coIsVector(v));
  231. assert(i < v->v.cnt);
  232. assert(i >= 0);
  233. if (v->flags & CO_FREE_VALS) {
  234. coDelete((co)(v->v.list[i])); // delete the element, NULL is handled within
  235. // coDelete
  236. } else if ((v->flags & CO_FREE_FIRST) != 0 &&
  237. i == 0) // consider the case, where only the first element needs to
  238. // be deleted
  239. {
  240. coDelete((co)v->v.list[0]);
  241. }
  242. v->v.list[i] = e;
  243. }
  244. /* delete an element in the vector. Size is reduced by 1 */
  245. void coVectorErase(co v, long i) {
  246. if (i >= v->v.cnt)
  247. return; // do nothing, index is outside the vecor
  248. // note: v->cnt > 0 at this point
  249. if (v->flags & CO_FREE_VALS) {
  250. coDelete((co)(v->v.list[i])); // delete the element
  251. } else if ((v->flags & CO_FREE_FIRST) != 0 &&
  252. i == 0) // consider the case, where only the first element needs to
  253. // be deleted
  254. {
  255. coDelete((co)v->v.list[0]);
  256. v->flags &= ~CO_FREE_FIRST; // reset the FRE_FIRST flag, because the other
  257. // elements must not be deleted
  258. }
  259. i++;
  260. while (i < v->v.cnt)
  261. v->v.list[i - 1] = v->v.list[i];
  262. v->v.cnt--;
  263. }
  264. static int coVectorAppendVectorCB(cco o, long idx, cco element, void *data) {
  265. co c = coClone(element);
  266. if (c == NULL)
  267. return 0;
  268. if (coVectorAdd((co)data, c) < 0)
  269. return 0;
  270. return 1;
  271. }
  272. /*
  273. append elements from src to v
  274. src can be vector or map
  275. elements from src are cloned
  276. */
  277. int coVectorAppendVector(co v, cco src) {
  278. if (v->fn == coVectorType) {
  279. long oldCnt = v->v.cnt;
  280. if (src->fn == coVectorType) {
  281. if (coVectorForEach(src, coVectorAppendVectorCB, v) == 0) {
  282. long i = v->v.cnt;
  283. while (i > oldCnt) {
  284. i--;
  285. coVectorErase(v, i);
  286. }
  287. }
  288. return 1;
  289. }
  290. }
  291. return 0; // first / seconad arg is NOT a vector
  292. }
  293. /*===================================================================*/
  294. /* String */
  295. /*===================================================================*/
  296. int coStrInit(co o, void *data); // optional data: const char *
  297. long coStrSize(cco o);
  298. void coStrPrint(cco o);
  299. void coStrDestroy(co o);
  300. co coStrClone(cco o);
  301. struct coFnStruct coStrStruct = {coStrInit, coStrSize, coStrPrint, coStrDestroy,
  302. coStrClone};
  303. coFn coStrType = &coStrStruct;
  304. co coNewStr(unsigned flags, const char *s) {
  305. co o = coNewWithData(coStrType, flags, (void *)s);
  306. if (o == NULL)
  307. return NULL;
  308. return o;
  309. }
  310. int coStrInit(co o, void *data) {
  311. static char empty_string[2] = "";
  312. char *s = (char *)data;
  313. o->fn = coStrType;
  314. if (s == NULL)
  315. s = empty_string;
  316. if (o->flags & CO_STRDUP) {
  317. o->s.str = strdup(s);
  318. o->flags |= CO_STRFREE;
  319. } else
  320. o->s.str = s;
  321. o->s.len = strlen(o->s.str);
  322. o->s.memlen = 0; // not used for string
  323. return 1;
  324. }
  325. int coStrAdd(co o, const char *s) {
  326. assert(coIsStr(o));
  327. assert(o->s.str != NULL);
  328. if (o->flags & CO_STRDUP) {
  329. size_t len = strlen(s);
  330. char *p = (char *)realloc(o->s.str, o->s.len + len + 1);
  331. if (p == NULL)
  332. return 0;
  333. o->s.str = p;
  334. strcpy(o->s.str + o->s.len, s);
  335. o->s.len += len;
  336. return 1;
  337. }
  338. return 0; // static string, can not add another string
  339. }
  340. long coStrSize(cco o) { return (long)o->s.len; }
  341. const char *coStrToString(cco o) {
  342. assert(coIsStr(o));
  343. return o->s.str;
  344. }
  345. const char *coStrGet(cco o) {
  346. if (o == NULL)
  347. return "";
  348. assert(coIsStr(o));
  349. return o->s.str;
  350. }
  351. void coStrPrint(cco o) { printf("%s", o->s.str); }
  352. void coStrDestroy(co o) {
  353. if (o->flags & CO_STRFREE)
  354. free(o->s.str);
  355. o->s.str = NULL;
  356. }
  357. co coStrClone(cco o) {
  358. return coNewStr(o->flags | CO_STRDUP | CO_STRFREE, o->s.str);
  359. }
  360. /*
  361. Close the string object and return a string pointer with the content.
  362. The return value points to allocated memory and must be freed
  363. */
  364. char *coStrDeleteAndGetAllocatedStringContent(co o) {
  365. assert(coIsStr(o));
  366. char *s;
  367. if (o->flags & CO_STRFREE)
  368. s = o->s.str;
  369. else
  370. s = strdup(o->s.str);
  371. o->flags &=
  372. ~CO_STRFREE; // clear the strfree flag so that the memory is not released
  373. coDelete(o); // close the object itself
  374. return s; // and finally return the allocated string
  375. }
  376. /*===================================================================*/
  377. /* Binary Memory Block */
  378. /*===================================================================*/
  379. int coMemInit(co o, void *data); // optional data: const char *
  380. long coMemSize(cco o);
  381. void coMemPrint(cco o);
  382. void coMemDestroy(co o);
  383. co coMemClone(cco o);
  384. struct coFnStruct coMemStruct = {coMemInit, coMemSize, coMemPrint, coMemDestroy,
  385. coMemClone};
  386. coFn coMemType = &coMemStruct;
  387. co coNewMem(void) {
  388. co o = coNewWithData(coMemType, 0, NULL);
  389. if (o == NULL)
  390. return NULL;
  391. return o;
  392. }
  393. int coMemInit(co o, void *data) {
  394. o->fn = coMemType;
  395. o->s.str = NULL;
  396. o->s.len = 0;
  397. o->s.memlen = 0;
  398. return 1;
  399. }
  400. #define CO_MEM_MIN_EXTEND (16 * 1024)
  401. #define CO_MEM_MAX_EXTEND (1024 * 1024)
  402. int coMemAdd(co o, const void *mem, size_t len) {
  403. void *m;
  404. size_t extend;
  405. extend = o->s.memlen; // double the memory...
  406. if (extend < CO_MEM_MIN_EXTEND)
  407. extend = CO_MEM_MIN_EXTEND;
  408. if (extend >
  409. CO_MEM_MAX_EXTEND) // ... but only the max extend value is reached
  410. extend = CO_MEM_MAX_EXTEND;
  411. if (extend < len)
  412. extend = len;
  413. assert(coIsMem(o));
  414. if (mem == NULL || len == 0)
  415. return 1;
  416. if (o->s.str == NULL) {
  417. o->s.memlen = extend;
  418. m = malloc(o->s.memlen);
  419. o->s.len = 0;
  420. } else if (o->s.len + len > o->s.memlen) {
  421. o->s.memlen = o->s.len + extend;
  422. m = realloc(o->s.str, o->s.memlen);
  423. } else {
  424. m = o->s.str;
  425. }
  426. if (m == NULL)
  427. return 0;
  428. memcpy(m + o->s.len, mem, len);
  429. o->s.str = (char *)m;
  430. o->s.len += len;
  431. return 1;
  432. }
  433. const void *coMemGet(cco o) { return (const void *)o->s.str; }
  434. long coMemSize(cco o) {
  435. assert(coIsMem(o));
  436. return (long)o->s.len;
  437. }
  438. void coMemPrint(cco o) { printf("<%zd bytes>", o->s.len); }
  439. void coMemDestroy(co o) {
  440. if (o->s.str != NULL)
  441. free(o->s.str);
  442. o->s.str = NULL;
  443. }
  444. co coMemClone(cco o) {
  445. co new_o;
  446. assert(coIsMem(o));
  447. new_o = coNewMem();
  448. if (new_o == NULL)
  449. return NULL;
  450. if (coMemAdd(new_o, o->s.str, o->s.len) != 0)
  451. return new_o;
  452. coMemDestroy(new_o);
  453. return NULL;
  454. }
  455. /*===================================================================*/
  456. /* Double */
  457. /*===================================================================*/
  458. int coDblInit(co o, void *data); // optional data: const double *
  459. long coDblSize(cco o);
  460. void coDblPrint(cco o);
  461. void coDblDestroy(co o);
  462. co coDblClone(cco o);
  463. struct coFnStruct coDblStruct = {coDblInit, coDblSize, coDblPrint, coDblDestroy,
  464. coDblClone};
  465. coFn coDblType = &coDblStruct;
  466. co coNewDbl(double n) {
  467. co o = coNewWithData(coDblType, CO_NONE, (void *)&n);
  468. if (o == NULL)
  469. return NULL;
  470. return o;
  471. }
  472. int coDblInit(co o, void *data) {
  473. o->fn = coDblType;
  474. if (data == NULL)
  475. o->d.n = 0.0;
  476. else
  477. o->d.n = *(double *)data;
  478. return 1;
  479. }
  480. long coDblSize(cco o) { return 1; }
  481. void coDblPrint(cco o) { printf("%.9g", o->d.n); }
  482. void coDblDestroy(co o) { o->d.n = 0.0; }
  483. co coDblClone(cco o) { return coNewDbl(o->d.n); }
  484. double coDblGet(cco o) {
  485. if (o == NULL)
  486. return 0.0;
  487. assert(coIsDbl(o));
  488. return o->d.n;
  489. }
  490. /*===================================================================*/
  491. /* Map */
  492. /* based on https://rosettacode.org/wiki/AVL_tree/C */
  493. /*===================================================================*/
  494. static struct co_avl_node_struct avl_dummy = {
  495. NULL, NULL, {&avl_dummy, &avl_dummy}, 0};
  496. static struct co_avl_node_struct *avl_nnil =
  497. &avl_dummy; // internally, avl_nnil is the new nul
  498. typedef void (*avl_free_fn)(void *p);
  499. static void avl_free_value(void *value) { coDelete((co)value); }
  500. static void avl_keep_value(void *value) {}
  501. static void avl_free_key(void *key) { free(key); }
  502. static void avl_keep_key(void *key) {}
  503. static struct co_avl_node_struct *avl_new_node(const char *key, void *value) {
  504. struct co_avl_node_struct *n = malloc(sizeof(struct co_avl_node_struct));
  505. if (n == NULL)
  506. return avl_nnil;
  507. n->key = key;
  508. n->value = value;
  509. n->height = 1;
  510. n->kid[0] = avl_nnil;
  511. n->kid[1] = avl_nnil;
  512. return n;
  513. }
  514. static void avl_delete_node(struct co_avl_node_struct *n, avl_free_fn free_key,
  515. avl_free_fn free_value) {
  516. free_key((void *)(n->key));
  517. if (n->value != NULL)
  518. free_value(n->value);
  519. n->value = NULL;
  520. n->kid[0] = NULL;
  521. n->kid[1] = NULL;
  522. free(n);
  523. }
  524. static int avl_max(int a, int b) { return a > b ? a : b; }
  525. static void avl_set_height(struct co_avl_node_struct *n) {
  526. n->height = 1 + avl_max(n->kid[0]->height, n->kid[1]->height);
  527. }
  528. static int avl_get_ballance_diff(struct co_avl_node_struct *n) {
  529. return n->kid[0]->height - n->kid[1]->height;
  530. }
  531. // rotate a subtree according to dir; if new root is nil, old root is freed
  532. static struct co_avl_node_struct *avl_rotate(struct co_avl_node_struct **rootp,
  533. int dir, avl_free_fn free_key,
  534. avl_free_fn free_value) {
  535. struct co_avl_node_struct *old_r = *rootp;
  536. struct co_avl_node_struct *new_r = old_r->kid[dir];
  537. *rootp = new_r; // replace root with the selected child
  538. if (avl_nnil == *rootp) {
  539. avl_delete_node(old_r, free_key, free_value);
  540. } else {
  541. old_r->kid[dir] = new_r->kid[!dir];
  542. avl_set_height(old_r);
  543. new_r->kid[!dir] = old_r;
  544. }
  545. return new_r;
  546. }
  547. static void avl_adjust_balance(struct co_avl_node_struct **rootp,
  548. avl_free_fn free_key, avl_free_fn free_value) {
  549. struct co_avl_node_struct *root = *rootp;
  550. int b = avl_get_ballance_diff(root) / 2;
  551. if (b != 0) {
  552. int dir = (1 - b) / 2;
  553. if (avl_get_ballance_diff(root->kid[dir]) == -b) {
  554. avl_rotate(&root->kid[dir], !dir, free_key, free_value);
  555. }
  556. root = avl_rotate(rootp, dir, free_key, free_value);
  557. }
  558. if (root != avl_nnil)
  559. avl_set_height(root);
  560. }
  561. // find the node that contains the given key; or returns NULL (which is a little
  562. // bit inconsistent)
  563. struct co_avl_node_struct *avl_query(struct co_avl_node_struct *root,
  564. const char *key) {
  565. int c;
  566. if (key == NULL)
  567. return NULL;
  568. if (root == avl_nnil)
  569. return NULL;
  570. c = strcmp(key, root->key);
  571. if (c == 0)
  572. return root;
  573. return avl_query(root->kid[c > 0], key);
  574. }
  575. /* returns NULL for any allocation error, otherwise the pointer to the internal
  576. * key */
  577. /* the return value is identical to the key argument if the key doesn't yet
  578. * exist otherwise it is a pointer to the existing key in the tree */
  579. static const char *avl_insert(struct co_avl_node_struct **rootp,
  580. const char *key, void *value,
  581. avl_free_fn free_key, avl_free_fn free_value) {
  582. struct co_avl_node_struct *root = *rootp;
  583. int c;
  584. if (key == NULL)
  585. return NULL; // illegal key
  586. if (root == avl_nnil) {
  587. *rootp = avl_new_node(key, value);
  588. if (*rootp == avl_nnil) // memory error
  589. return NULL;
  590. return key;
  591. }
  592. c = strcmp(key, root->key);
  593. if (c == 0) {
  594. // key already exists: replace value
  595. free_key((void *)key);
  596. if (root->value != NULL)
  597. free_value(root->value);
  598. root->value = value;
  599. key = root->key; // return the internal key
  600. } else {
  601. key = avl_insert(&root->kid[c > 0], key, value, free_key, free_value);
  602. if (key == NULL)
  603. return NULL;
  604. avl_adjust_balance(rootp, free_key, free_value);
  605. }
  606. return key;
  607. }
  608. static void avl_delete(struct co_avl_node_struct **rootp, const char *key,
  609. avl_free_fn free_key, avl_free_fn free_value) {
  610. struct co_avl_node_struct *root = *rootp;
  611. if (key == NULL)
  612. return; // illegal key
  613. if (root == avl_nnil)
  614. return; // not found
  615. // if this is the node we want, rotate until off the tree
  616. if (strcmp(key, root->key) == 0) {
  617. root = avl_rotate(rootp, avl_get_ballance_diff(root) < 0, free_key,
  618. free_value);
  619. if (avl_nnil == root) {
  620. return;
  621. }
  622. }
  623. avl_delete(&root->kid[strcmp(key, root->key) > 0], key, free_key, free_value);
  624. avl_adjust_balance(rootp, free_key, free_value);
  625. }
  626. static int avl_for_each(cco o, struct co_avl_node_struct *n,
  627. coMapForEachCB visitCB, long *idx, void *data) {
  628. if (n == avl_nnil)
  629. return 1;
  630. avl_for_each(o, n->kid[0], visitCB, idx, data);
  631. if (visitCB(o, *idx, n->key, (cco)(n->value), data) == 0)
  632. return 0;
  633. (*idx)++;
  634. avl_for_each(o, n->kid[1], visitCB, idx, data);
  635. return 1;
  636. }
  637. /*
  638. after calling avl_delete_all the "n" argument is illegal and points to
  639. avl_nnil
  640. */
  641. static void avl_delete_all(struct co_avl_node_struct **n, avl_free_fn free_key,
  642. avl_free_fn free_value) {
  643. if (*n == avl_nnil)
  644. return;
  645. avl_delete_all(&((*n)->kid[0]), free_key, free_value);
  646. avl_delete_all(&((*n)->kid[1]), free_key, free_value);
  647. avl_delete_node(*n, free_key, free_value);
  648. *n = avl_nnil;
  649. }
  650. static int avl_get_size_cb(cco o, long idx, const char *key, cco value,
  651. void *data) {
  652. return 1;
  653. }
  654. /* warning: this has O(n) runtime */
  655. static long avl_get_size(struct co_avl_node_struct *n) {
  656. long cnt = 0;
  657. avl_for_each(NULL, n, avl_get_size_cb, &cnt, NULL);
  658. return cnt;
  659. }
  660. int coMapInit(co o, void *data);
  661. long coMapSize(cco o);
  662. void coMapPrint(cco o);
  663. void coMapClear(co o);
  664. int coMapEmpty(cco o);
  665. co coMapClone(cco o);
  666. struct coFnStruct coMapStruct = {
  667. coMapInit, coMapSize, coMapPrint,
  668. coMapClear, // destroy function is identical to clear function
  669. coMapClone};
  670. coFn coMapType = &coMapStruct;
  671. co coNewMap(unsigned flags) { return coNew(coMapType, flags); }
  672. int coMapInit(co o, void *data) {
  673. assert(coIsMap(o));
  674. o->m.root = avl_nnil;
  675. if (o->flags & CO_STRDUP)
  676. o->flags |= CO_STRFREE;
  677. return 1;
  678. }
  679. const char *coMapAdd(co o, const char *key, cco value) {
  680. const char *k;
  681. assert(coIsMap(o));
  682. assert(key != NULL);
  683. if (o->flags & CO_STRDUP)
  684. k = strdup(key);
  685. else
  686. k = key;
  687. if (k == NULL)
  688. return 0;
  689. return avl_insert(&(o->m.root), k, (void *)value,
  690. (o->flags & CO_STRFREE) ? avl_free_key : avl_keep_key,
  691. (o->flags & CO_FREE_VALS) ? avl_free_value
  692. : avl_keep_value);
  693. }
  694. // Add a key and also store the key as a value
  695. // returns the value (string object) if successful
  696. // the provided map must have CO_FREE_VALS enabled
  697. // Whether CO_STRDUP is enabled for the map, doesn't matter and will be taken
  698. // care the return value belongs to the map and must not be free'd somewhere
  699. // else
  700. cco coMapAddValueKey(co o, const char *key) {
  701. const char *k;
  702. cco cv;
  703. co v;
  704. assert(coIsMap(o));
  705. assert(key != NULL);
  706. assert((o->flags & CO_FREE_VALS) != 0);
  707. cv = coMapGet(o, key);
  708. if (cv != NULL)
  709. return cv; // if the key exists, just return the string object with the key
  710. // (which is also the value)
  711. // otherwise create a new entry in the map
  712. if (o->flags & CO_STRDUP) {
  713. k = strdup(key);
  714. v = coNewStr(CO_NONE, k);
  715. if (avl_insert(&(o->m.root), k, (void *)v,
  716. (o->flags & CO_STRFREE) ? avl_free_key : avl_keep_key,
  717. (o->flags & CO_FREE_VALS) ? avl_free_value
  718. : avl_keep_value) == NULL)
  719. return coDelete(v), free((void *)k), NULL;
  720. } else {
  721. assert((o->flags & CO_STRFREE) == 0);
  722. v = coNewStr(CO_STRDUP, key);
  723. k = coStrGet(v);
  724. if (avl_insert(&(o->m.root), k, (void *)v,
  725. (o->flags & CO_STRFREE) ? avl_free_key : avl_keep_key,
  726. (o->flags & CO_FREE_VALS) ? avl_free_value
  727. : avl_keep_value) == NULL)
  728. return coDelete(v), NULL;
  729. }
  730. return v;
  731. }
  732. long coMapSize(cco o) {
  733. assert(coIsMap(o));
  734. return avl_get_size(o->m.root); // O(n) !
  735. }
  736. static int avl_co_map_print_cb(cco o, long idx, const char *key, cco value,
  737. void *data) {
  738. if (idx > 0)
  739. printf(", ");
  740. printf("%s:", key);
  741. coPrint(value);
  742. return 1;
  743. }
  744. void coMapPrint(cco o) {
  745. long cnt = 0;
  746. assert(coIsMap(o));
  747. printf("{");
  748. avl_for_each(o, o->m.root, avl_co_map_print_cb, &cnt, NULL);
  749. printf("}");
  750. }
  751. void coMapClear(co o) {
  752. assert(coIsMap(o));
  753. avl_delete_all(&(o->m.root),
  754. (o->flags & CO_STRFREE) ? avl_free_key : avl_keep_key,
  755. (o->flags & CO_FREE_VALS) ? avl_free_value : avl_keep_value);
  756. }
  757. int coMapEmpty(cco o) {
  758. assert(coIsMap(o));
  759. if (o->m.root == avl_nnil)
  760. return 1;
  761. return 0;
  762. }
  763. static int avl_co_map_clone_cb(cco o, long idx, const char *key, cco value,
  764. void *data) {
  765. // strdup() will be applied to key, because CO_STRDUP is active for the map
  766. return coMapAdd((co)data, key, coClone((co)(value))) == NULL ? 0 : 1;
  767. }
  768. co coMapClone(cco o) {
  769. long cnt = 0;
  770. co new_obj = coNewMap(o->flags | CO_FREE_VALS | CO_STRDUP | CO_STRFREE);
  771. assert(coIsMap(o));
  772. if (avl_for_each(o, o->m.root, avl_co_map_clone_cb, &cnt, new_obj) == 0) {
  773. coDelete(new_obj);
  774. return NULL;
  775. }
  776. return new_obj;
  777. }
  778. int coMapExists(cco o, const char *key) {
  779. struct co_avl_node_struct *n;
  780. assert(coIsMap(o));
  781. n = avl_query(o->m.root, key);
  782. if (n == NULL)
  783. return 0;
  784. return 1;
  785. }
  786. /* return the internal pointer to the key for a given string key, returns NULL
  787. * if the key doesn't exist */
  788. const char *coMapGetKey(cco o, const char *key) {
  789. struct co_avl_node_struct *n;
  790. assert(coIsMap(o));
  791. n = avl_query(o->m.root, key);
  792. if (n == NULL)
  793. return NULL;
  794. return n->key;
  795. }
  796. /* return the value for a given key */
  797. cco coMapGet(cco o, const char *key) {
  798. struct co_avl_node_struct *n;
  799. assert(coIsMap(o));
  800. n = avl_query(o->m.root, key);
  801. if (n == NULL)
  802. return NULL;
  803. return (cco)(n->value);
  804. }
  805. void coMapErase(co o, const char *key) {
  806. assert(coIsMap(o));
  807. avl_delete(&(o->m.root), key,
  808. (o->flags & CO_STRFREE) ? avl_free_key : avl_keep_key,
  809. (o->flags & CO_FREE_VALS) ? avl_free_value : avl_keep_value);
  810. }
  811. int coMapForEach(cco o, coMapForEachCB cb, void *data) {
  812. long cnt = 0;
  813. assert(coIsMap(o));
  814. return avl_for_each(o, o->m.root, cb, &cnt, data);
  815. }
  816. static int avl_loop_sub(coMapIterator *iter) {
  817. while (iter->depth > 0 || iter->current_node != avl_nnil) {
  818. if (iter->current_node != avl_nnil) {
  819. iter->node[iter->depth] = iter->current_node;
  820. iter->current_node = iter->current_node->kid[0];
  821. iter->depth++;
  822. assert(iter->depth < CO_AVL_STACK_MAX_DEPTH);
  823. } else {
  824. iter->depth--;
  825. iter->current_node = iter->node[iter->depth];
  826. return 1; // process current_node
  827. }
  828. }
  829. return 0;
  830. }
  831. int coMapLoopFirst(coMapIterator *iter, cco o) {
  832. // puts("coMapLoopFirst");
  833. assert(coIsMap(o));
  834. iter->depth = 0;
  835. iter->current_node = o->m.root;
  836. return avl_loop_sub(iter);
  837. }
  838. int coMapLoopNext(coMapIterator *iter) {
  839. iter->current_node = iter->current_node->kid[1];
  840. return avl_loop_sub(iter);
  841. }
  842. /*
  843. coMapIterator iter;
  844. if ( coMapLoopFirst(&iter, o) )
  845. {
  846. do {
  847. coMapLoopKey(&iter); // return the key of the current key/value
  848. pair (const char *)
  849. coMapLoopValue(&iter); // return the value of the current
  850. key/value pair (cco) } while( coMapLoopNext(&iter) );
  851. }
  852. */
  853. /*===================================================================*/
  854. /* Publlic Utility Functions */
  855. /*===================================================================*/
  856. static int coVectorByMapCB(cco o, long idx, const char *key, cco value,
  857. void *data) {
  858. co parent = (co)data;
  859. co key_value_vector =
  860. coNewVector(CO_FREE_FIRST); // the first element is a string object, which
  861. // must be freed
  862. assert(coIsMap(o));
  863. assert(key != NULL);
  864. if (key_value_vector == NULL)
  865. return 0;
  866. if (coVectorAdd(key_value_vector, coNewStr(CO_NONE, key)) <
  867. 0) // do not free the key-string, it belongs to the map
  868. return coDelete(key_value_vector), 0;
  869. if (coVectorAdd(key_value_vector, value) <
  870. 0) // do not free the value, it belongs to the map
  871. return coDelete(key_value_vector), 0;
  872. if (coVectorAdd(parent, key_value_vector) <
  873. 0) // add the key value vector to the parent vector
  874. return coDelete(key_value_vector), 0;
  875. return 1;
  876. }
  877. /*
  878. Return a vector, where each element is a vector with two elements: Key and
  879. value from the map: [ [key, value], [key, value], ..., [key, value] ] key and
  880. value refer to the map, this means, the return value must be deleted before
  881. the map is deleted.
  882. */
  883. co coNewVectorByMap(cco map) {
  884. co vector = coNewVector(
  885. CO_FREE_VALS); // the inner vectors (key, value pairs) should be free'd
  886. if (coMapForEach(map, coVectorByMapCB, vector) == 0)
  887. return coDelete(vector), NULL;
  888. return vector;
  889. }
  890. /*
  891. Search for index position within a sorted vector.
  892. Assumes a vector with key/value pairs: [ [key, value], [key, value], ...,
  893. [key, value] ] (=return value from coNewVectorByMap()) The vector must be
  894. sorted according to "key". Returns an index for which the key is lower or
  895. equal to the provided "search_key" argument. The returned index is the
  896. predecessor for the given "search_key": The position of the element, which is
  897. lower or equal to "search_key". The returned index can be -1 if there is no
  898. predecessor element. This means "search_key" is smaller than any other element
  899. in the vector. The returned index is always smaller than coVectorSize() The
  900. returned index is -1 if the vector is empty
  901. [] search 1 --> result -1
  902. [2] search 1 --> result -1
  903. [2] search 2 --> result 0
  904. [2] search 3 --> result 0
  905. [2, 4] search 1 --> result -1
  906. [2, 4] search 2 --> result 0
  907. [2, 4] search 3 --> result 0
  908. [2, 4] search 4 --> result 1
  909. [2, 4] search 5 --> result 1
  910. [2, 4, 6] search 1 --> result -1
  911. [2, 4, 6] search 2 --> result 0
  912. [2, 4, 6] search 3 --> result 0
  913. [2, 4, 6] search 4 --> result 1
  914. [2, 4, 6] search 5 --> result 1
  915. [2, 4, 6] search 6 --> result 2
  916. [2, 4, 6] search 7 --> result 2
  917. */
  918. long coVectorPredecessorBinarySearch(cco v, const char *search_key) {
  919. long lower_pos = 0;
  920. long upper_pos = coVectorSize(v);
  921. long mid_pos;
  922. const char *mid_str;
  923. while (lower_pos < upper_pos) {
  924. mid_pos = (upper_pos + lower_pos) / 2;
  925. mid_str = coStrGet(coVectorGet(coVectorGet(v, mid_pos), 0));
  926. assert(mid_str != NULL);
  927. if (strcmp(mid_str, search_key) > 0) {
  928. upper_pos = mid_pos;
  929. } else {
  930. lower_pos = mid_pos + 1;
  931. }
  932. }
  933. return upper_pos - 1;
  934. }
  935. /*===================================================================*/
  936. /* FILE/String Reader */
  937. /*===================================================================*/
  938. static int bom_read_and_skip(FILE *fp) {
  939. int c;
  940. c = fgetc(fp);
  941. if (c == 0xEF) {
  942. if (fgetc(fp) == 0xBB)
  943. if (fgetc(fp) == 0xBF)
  944. return BOM_UTF8;
  945. fseek(fp, 0, SEEK_SET);
  946. return BOM_NONE;
  947. }
  948. if (c == 0xFE) {
  949. if (fgetc(fp) == 0xFF)
  950. return BOM_UTF16BE;
  951. } else if (c == 0xFF) {
  952. if (fgetc(fp) == 0xFE) {
  953. if (fgetc(fp) != 0x00) {
  954. fseek(fp, 2, SEEK_SET);
  955. return BOM_UTF16LE;
  956. }
  957. if (fgetc(fp) == 0x00) // second 0x00?
  958. return BOM_UTF32LE;
  959. }
  960. } else if (c == 0x00) {
  961. if (fgetc(fp) == 0x00)
  962. if (fgetc(fp) == 0xFE)
  963. if (fgetc(fp) == 0xFF)
  964. return BOM_UTF32BE;
  965. }
  966. fseek(fp, 0, SEEK_SET);
  967. return BOM_NONE;
  968. }
  969. void coReaderErr(coReader r, const char *msg) {
  970. printf("JSON Parser error '%s', current char='%c'\n", msg, r->curr);
  971. /* removed, because we can't print fpos_t */
  972. /*
  973. if ( r->fp != NULL )
  974. {
  975. fpos_t pos;
  976. fgetpos(r->fp, &pos);
  977. printf("JSON Parser error at file pos %lld\n", (long long int)(pos));
  978. }
  979. */
  980. }
  981. static void coReaderStringNext(coReader r) {
  982. if (r->curr < 0)
  983. return;
  984. (r->reader_string)++;
  985. r->curr = *(r->reader_string);
  986. if (r->curr == '\0')
  987. r->curr = -1; // code below will check for <0
  988. }
  989. static void coReaderFileNext(coReader r) {
  990. if (r->curr < 0)
  991. return;
  992. r->curr = getc(
  993. r->fp); // may return EOF, which is -1, but code below will check for <0
  994. }
  995. /*
  996. return the size of the UTF8 sequence
  997. store the OTF8 sequence in reverse order (for the stack in coReader)
  998. */
  999. static int coEncodeUTF8(uint32_t codepoint, uint8_t *utf8) {
  1000. if (codepoint <= 0x7F) {
  1001. utf8[0] = codepoint & 0x7F;
  1002. return 1;
  1003. } else if (codepoint <= 0x7FF) {
  1004. utf8[1] = 0xC0 | ((codepoint >> 6) & 0x1F);
  1005. utf8[0] = 0x80 | (codepoint & 0x3F);
  1006. return 2;
  1007. } else if (codepoint <= 0xFFFF) {
  1008. utf8[2] = 0xE0 | ((codepoint >> 12) & 0x0F);
  1009. utf8[1] = 0x80 | ((codepoint >> 6) & 0x3F);
  1010. utf8[0] = 0x80 | (codepoint & 0x3F);
  1011. return 3;
  1012. } else if (codepoint <= 0x10FFFF) {
  1013. utf8[3] = 0xF0 | ((codepoint >> 18) & 0x07);
  1014. utf8[2] = 0x80 | ((codepoint >> 12) & 0x3F);
  1015. utf8[1] = 0x80 | ((codepoint >> 6) & 0x3F);
  1016. utf8[0] = 0x80 | (codepoint & 0x3F);
  1017. return 4;
  1018. }
  1019. return -1; // invalid codepoint
  1020. }
  1021. static uint32_t coGetCodepointFromUTF16(unsigned high, unsigned low) {
  1022. if (high >= 0xD800 && high <= 0xDBFF && low >= 0xDC00 && low <= 0xDFFF) {
  1023. return (uint32_t)0x10000 + (((uint32_t)(high - 0xD800) << 10) | (uint32_t)(low - 0xDC00));
  1024. }
  1025. return high; // Not a surrogate pair, just return the ascii value
  1026. }
  1027. static void coReaderFileNext16LE(coReader r) {
  1028. if (r->curr < 0)
  1029. return;
  1030. if ( r->stack_pos > 0 )
  1031. {
  1032. r->stack_pos--;
  1033. r->curr = r->stack_memory[r->stack_pos];
  1034. }
  1035. else
  1036. {
  1037. /*
  1038. r->curr = getc(r->fp); // lower byte comes first
  1039. if (r->curr < 0)
  1040. return;
  1041. r->curr |= (getc(r->fp) << 8); // higher byte
  1042. */
  1043. int low, high; // not sure whether low/high naming makes sense here
  1044. low = getc(r->fp);
  1045. if ( low < 0 )
  1046. {
  1047. r->curr = -1;
  1048. return;
  1049. }
  1050. high = getc(r->fp);
  1051. if ( high < 0 )
  1052. {
  1053. r->curr = -1;
  1054. return;
  1055. }
  1056. r->stack_pos = coEncodeUTF8( coGetCodepointFromUTF16(low, high), r->stack_memory ); // low/high sequence tested
  1057. if ( r->stack_pos < 1)
  1058. {
  1059. r->curr = -1;
  1060. return;
  1061. }
  1062. r->stack_pos--;
  1063. r->curr = r->stack_memory[r->stack_pos];
  1064. }
  1065. }
  1066. static void coReaderFileNext16BE(coReader r) {
  1067. if (r->curr < 0)
  1068. return;
  1069. if ( r->stack_pos > 0 )
  1070. {
  1071. r->stack_pos--;
  1072. r->curr = r->stack_memory[r->stack_pos];
  1073. }
  1074. else
  1075. {
  1076. /*
  1077. r->curr = getc(r->fp); // higher byte comes first
  1078. if (r->curr < 0)
  1079. return;
  1080. r->curr <<= 8;
  1081. r->curr |= getc(r->fp); // lower byte
  1082. */
  1083. int low, high; // not sure whether low/high naming makes sense here
  1084. low = getc(r->fp);
  1085. if ( low < 0 )
  1086. {
  1087. r->curr = -1;
  1088. return;
  1089. }
  1090. high = getc(r->fp);
  1091. if ( high < 0 )
  1092. {
  1093. r->curr = -1;
  1094. return;
  1095. }
  1096. r->stack_pos = coEncodeUTF8( coGetCodepointFromUTF16(high, low), r->stack_memory ); // bytes are swapped here
  1097. if ( r->stack_pos < 1)
  1098. {
  1099. r->curr = -1;
  1100. return;
  1101. }
  1102. r->stack_pos--;
  1103. r->curr = r->stack_memory[r->stack_pos];
  1104. }
  1105. }
  1106. #ifdef CO_USE_ZLIB
  1107. static int coReaderGZInit(coReader r) {
  1108. int ret;
  1109. /* allocate inflate state */
  1110. r->have = 0;
  1111. r->pos = 0;
  1112. r->strm.zalloc = Z_NULL;
  1113. r->strm.zfree = Z_NULL;
  1114. r->strm.opaque = Z_NULL;
  1115. r->strm.avail_in = 0;
  1116. r->strm.avail_out = 0;
  1117. r->strm.next_in = r->in;
  1118. r->strm.next_out = r->out;
  1119. ret = inflateInit2(
  1120. &(r->strm),
  1121. 32 +
  1122. MAX_WBITS); // https://stackoverflow.com/questions/1838699/how-can-i-decompress-a-gzip-stream-with-zlib
  1123. if (ret != Z_OK)
  1124. return 0;
  1125. return 1;
  1126. }
  1127. #define STRINGIZE(x) STRINGIZE2(x)
  1128. #define STRINGIZE2(x) #x
  1129. #define LINE STRINGIZE(__LINE__)
  1130. static void coReaderGZFileNext(coReader r) {
  1131. /* https://chromium.googlesource.com/native_client/nacl-gcc/+/master/zlib/examples/zpipe.c
  1132. */
  1133. int ret;
  1134. if (r->pos >= r->have) {
  1135. // printf(LINE " GZ: pos=%d have=%d strm.avail_in=%d strm.avail_out=%d\n",
  1136. // r->pos, r->have, r->strm.avail_in, r->strm.avail_out);
  1137. if (r->strm.avail_in ==
  1138. 0) // initially avail_in is 0, later we will only execute the if body if
  1139. // further reads are required
  1140. {
  1141. r->strm.avail_in = fread(r->in, 1, CHUNK, r->fp);
  1142. // printf(LINE " GZ: fread strm.avail_in=%d\n", r->strm.avail_in);
  1143. r->strm.next_in = r->in;
  1144. if (ferror(r->fp)) {
  1145. inflateEnd(&(r->strm));
  1146. coReaderErr(r, "File Read Error");
  1147. r->curr = -1;
  1148. return;
  1149. }
  1150. if (r->strm.avail_in == 0) {
  1151. r->curr = -1;
  1152. inflateEnd(&(r->strm));
  1153. return;
  1154. }
  1155. }
  1156. r->strm.avail_out = CHUNK;
  1157. r->strm.next_out = r->out;
  1158. ret = inflate(&(r->strm), Z_NO_FLUSH);
  1159. // printf(LINE " GZ: ret=%d strm.avail_out=%d\n", ret, r->strm.avail_out);
  1160. switch (ret) {
  1161. case Z_NEED_DICT:
  1162. coReaderErr(r, "ZLIB Decompression NEED_DICT Error");
  1163. inflateEnd(&(r->strm));
  1164. r->curr = -1;
  1165. return;
  1166. case Z_DATA_ERROR:
  1167. coReaderErr(r, "ZLIB Decompression DATA Error");
  1168. inflateEnd(&(r->strm));
  1169. r->curr = -1;
  1170. return;
  1171. case Z_MEM_ERROR:
  1172. coReaderErr(r, "ZLIB Decompression MEM Error");
  1173. inflateEnd(&(r->strm));
  1174. r->curr = -1;
  1175. return;
  1176. case Z_BUF_ERROR:
  1177. coReaderErr(
  1178. r, "ZLIB Decompression BUF Error (missing binary mode for fopen?)");
  1179. inflateEnd(&(r->strm));
  1180. r->curr = -1;
  1181. return;
  1182. case Z_STREAM_END:
  1183. if (CHUNK - r->strm.avail_out > 0)
  1184. break;
  1185. // printf(LINE " GZ: STREAM_END\n");
  1186. inflateEnd(&(r->strm));
  1187. r->curr = -1;
  1188. return;
  1189. }
  1190. r->have = CHUNK - r->strm.avail_out;
  1191. r->pos = 0;
  1192. // printf(LINE " GZ: have=%d\n", r->have);
  1193. }
  1194. r->curr = r->out[r->pos];
  1195. r->pos++;
  1196. }
  1197. #endif /* CO_USE_ZLIB */
  1198. int coReaderInitByString(coReader reader, const char *s) {
  1199. if (reader == NULL || s == NULL)
  1200. return 0;
  1201. reader->bom = BOM_NONE;
  1202. reader->reader_string = s;
  1203. reader->fp = NULL;
  1204. reader->next_cb = coReaderStringNext;
  1205. reader->curr = reader->reader_string[0];
  1206. if (reader->curr == '\0')
  1207. reader->curr = -1;
  1208. coReaderSkipWhiteSpace(reader);
  1209. return 1;
  1210. }
  1211. int coReaderInitByFP(coReader reader, FILE *fp) {
  1212. if (reader == NULL || fp == NULL)
  1213. return 0;
  1214. reader->curr = 32;
  1215. reader->stack_pos = 0;
  1216. reader->next_cb = coReaderFileNext; // assign some default
  1217. reader->reader_string = NULL;
  1218. reader->fp = fp;
  1219. reader->bom = BOM_UTF8;
  1220. /*
  1221. reader->bom = bom_read_and_skip(fp);
  1222. if (reader->bom == BOM_NONE)
  1223. reader->next_cb = coReaderFileNext; // all good, contine with GZ test
  1224. else if (reader->bom == BOM_UTF8)
  1225. reader->next_cb = coReaderFileNext;
  1226. else if (reader->bom == BOM_UTF16LE)
  1227. reader->next_cb = coReaderFileNext16LE;
  1228. else if (reader->bom == BOM_UTF16BE)
  1229. reader->next_cb = coReaderFileNext16BE;
  1230. else
  1231. return 0; // unsupported BOM (like BOM_UTF32BE for example)
  1232. */
  1233. #ifdef CO_USE_ZLIB
  1234. if (reader->bom == BOM_NONE) // check for GZIP
  1235. {
  1236. reader->curr = getc(fp);
  1237. if (reader->curr == 0x1f) // GZIP IDs: 0x1f 0x8b, see
  1238. // https://www.rfc-editor.org/rfc/rfc1952#page-5
  1239. {
  1240. fseek(fp, 0, SEEK_SET);
  1241. coReaderGZInit(reader);
  1242. reader->next_cb = coReaderGZFileNext; // this is a UTF8 BOM reader!
  1243. coReaderNext(reader); // read the first byte
  1244. // detect and skip UTF8 BOM if present
  1245. // Warning: at the moment only UTF8 BOM is supported for gzip
  1246. if (coReaderCurr(reader) == 0xEF) // UTF8 BOM?
  1247. {
  1248. coReaderNext(reader);
  1249. if (coReaderCurr(reader) == 0xBB) {
  1250. coReaderNext(reader);
  1251. if (coReaderCurr(reader) == 0xBF) {
  1252. coReaderNext(reader);
  1253. reader->bom = BOM_UTF8;
  1254. } else {
  1255. reader->pos = 0;
  1256. coReaderNext(reader); // read the first byte
  1257. }
  1258. } else {
  1259. reader->pos = 0;
  1260. coReaderNext(reader); // read the first byte
  1261. }
  1262. }
  1263. }
  1264. }
  1265. // ToDo: is the initial call to coReaderNext() missing in case that this is not GZIP? shouldn't here be al #else also with an initial read???
  1266. #endif /* CO_USE_ZLIB */
  1267. coReaderSkipWhiteSpace(reader);
  1268. return 1;
  1269. }
  1270. /*===================================================================*/
  1271. /* JSON Parser */
  1272. /*===================================================================*/
  1273. co coJSONGetValue(coReader reader); // forward declaration
  1274. #define COJ_STR_BUF 1024
  1275. const char *coJSONGetIdentifier(coReader reader) {
  1276. static char buf[COJ_STR_BUF + 16]; // extra data for UTF-8 sequence and \0
  1277. size_t idx = 0;
  1278. int c = 0;
  1279. for (;;) {
  1280. c = coReaderCurr(reader);
  1281. if (isalpha(c) == 0)
  1282. break;
  1283. if (idx < COJ_STR_BUF - 1)
  1284. buf[idx++] = c;
  1285. coReaderNext(reader);
  1286. }
  1287. buf[idx] = '\0';
  1288. coReaderSkipWhiteSpace(reader);
  1289. return buf;
  1290. }
  1291. char *coJSONGetStr(coReader reader) {
  1292. static char buf[COJ_STR_BUF + 16]; // extra data for UTF-8 sequence and \0
  1293. char *s = NULL; // upcoming return value (allocated string)
  1294. size_t len = 0; // len == strlen(s)
  1295. size_t idx = 0;
  1296. int c = 0;
  1297. if (coReaderCurr(reader) != '\"')
  1298. return coReaderErr(reader, "Internal error, double quote missing"), NULL;
  1299. coReaderNext(reader); // skip initial double quote
  1300. for (;;) {
  1301. c = coReaderCurr(reader);
  1302. if (c < 0) // unexpected end of stream
  1303. return coReaderErr(reader, "Unexpected end of string"), NULL;
  1304. if (c == '\"')
  1305. break; // regular end
  1306. if (c == '\\') {
  1307. coReaderNext(reader); // skip back slash
  1308. c = coReaderCurr(reader);
  1309. if (c == 'u') {
  1310. unsigned long u = 0;
  1311. int i;
  1312. for (i = 0; i < 4; i++) // read the \uXXXX hex number
  1313. {
  1314. coReaderNext(reader); // skip 'u' or any of the hex chars
  1315. c = coReaderCurr(reader);
  1316. if (c < 0) {
  1317. return coReaderErr(reader, "Unexpected end within \\uXXXX"),
  1318. NULL; // todo: we might need to free(s)
  1319. }
  1320. if (c >= '0' && c <= '9') {
  1321. u <<= 4;
  1322. u += c - '0';
  1323. continue;
  1324. }
  1325. if (c >= 'a' && c <= 'f') {
  1326. u <<= 4;
  1327. u += c - 'a' + 10;
  1328. continue;
  1329. }
  1330. if (c >= 'A' && c <= 'F') {
  1331. u <<= 4;
  1332. u += c - 'A' + 10;
  1333. continue;
  1334. }
  1335. // if we reach this point, then the \u arg is not a hex number
  1336. return coReaderErr(reader, "Not a hex number with \\uXXXX"),
  1337. NULL; // todo: we might need to free(s)
  1338. }
  1339. coReaderNext(reader); // skip last hex char
  1340. // convert the code point to UTF-8
  1341. if (u < 0x80UL) {
  1342. buf[idx++] = u;
  1343. } else if (u < 0x800UL) {
  1344. buf[idx++] = (0xC0 | (u >> 6));
  1345. buf[idx++] = (0x80 | (u & 0x3F));
  1346. } else if (u < 0x10000UL) {
  1347. buf[idx++] = (0xE0 | (u >> 12));
  1348. buf[idx++] = (0x80 | ((u >> 6) & 0x3F));
  1349. buf[idx++] = (0x80 | (u & 0x3F));
  1350. } else if (u < 0x200000UL) // hmmm... we will never arive here
  1351. {
  1352. buf[idx++] = (0xE0 | (u >> 18));
  1353. buf[idx++] = (0x80 | ((u >> 12) & 0x3F));
  1354. buf[idx++] = (0x80 | ((u >> 6) & 0x3F));
  1355. buf[idx++] = (0x80 | (u & 0x3F));
  1356. } else {
  1357. return coReaderErr(reader, "Internal error"),
  1358. NULL; // I don't think, that this code is reachable, todo: we
  1359. // might need to free(s)
  1360. }
  1361. } // slash u
  1362. else if (c == 'n') {
  1363. coReaderNext(reader);
  1364. buf[idx++] = '\n';
  1365. } else if (c == 't') {
  1366. coReaderNext(reader);
  1367. buf[idx++] = '\t';
  1368. } else if (c == 'b') {
  1369. coReaderNext(reader);
  1370. buf[idx++] = '\b';
  1371. } else if (c == 'f') {
  1372. coReaderNext(reader);
  1373. buf[idx++] = '\f';
  1374. } else if (c == 'r') {
  1375. coReaderNext(reader);
  1376. buf[idx++] = '\r';
  1377. } else {
  1378. coReaderNext(reader);
  1379. buf[idx++] = c;
  1380. } // treat escaped char as it is (this will handle both slashes ...
  1381. } // escape
  1382. else {
  1383. coReaderNext(reader);
  1384. buf[idx++] = c; // handle normal char
  1385. }
  1386. // check whether we need to flush the buffer to the string object
  1387. if (idx > COJ_STR_BUF) {
  1388. buf[idx] = '\0';
  1389. if (s == NULL) {
  1390. s = strdup(buf);
  1391. len = idx;
  1392. if (s == NULL)
  1393. return coReaderErr(reader, "Memory error inside string parser"), NULL;
  1394. } else {
  1395. char *t = (char *)realloc(s, len + idx + 1);
  1396. if (t == NULL)
  1397. return coReaderErr(reader, "Memory error inside string parser"),
  1398. free(s), NULL; // memory error
  1399. s = t;
  1400. strcpy(s + len, buf);
  1401. len += idx;
  1402. }
  1403. idx = 0; // buf is stored in the string object: reset the buffer counter
  1404. // to 0
  1405. } // handle buffer flash
  1406. }
  1407. coReaderNext(reader); // skip final double quote
  1408. coReaderSkipWhiteSpace(reader);
  1409. buf[idx] = '\0';
  1410. if (s == NULL) {
  1411. s = strdup(buf);
  1412. len = idx;
  1413. if (s == NULL)
  1414. return coReaderErr(reader, "Memory error inside string parser"), NULL;
  1415. } else {
  1416. char *t = (char *)realloc(s, len + idx + 1);
  1417. if (t == NULL)
  1418. return coReaderErr(reader, "Memory error inside string parser"), free(s),
  1419. NULL; // memory error
  1420. s = t;
  1421. strcpy(s + len, buf);
  1422. len += idx;
  1423. }
  1424. return s;
  1425. }
  1426. #define COJ_DBL_BUF 64
  1427. co coJSONGetDbl(coReader reader) {
  1428. char buf[COJ_DBL_BUF + 2];
  1429. int i = 0;
  1430. int c;
  1431. for (;;) {
  1432. c = coReaderCurr(reader);
  1433. if ((c >= '0' && c <= '9') || c == '-' || c == '+' || c == 'e' ||
  1434. c == 'E' || c == '.') {
  1435. if (i < COJ_DBL_BUF)
  1436. buf[i++] = c;
  1437. coReaderNext(reader);
  1438. } else {
  1439. break;
  1440. }
  1441. }
  1442. coReaderSkipWhiteSpace(reader);
  1443. buf[i] = '\0';
  1444. return coNewDbl(strtod(buf, NULL));
  1445. }
  1446. co coJSONGetArray(coReader reader) {
  1447. int c;
  1448. co array_obj;
  1449. co element;
  1450. // printf("array start\n");
  1451. if (coReaderCurr(reader) != '[')
  1452. return coReaderErr(reader, "Internal error"), NULL;
  1453. array_obj = coNewVector(CO_FREE_VALS);
  1454. coReaderNext(reader);
  1455. coReaderSkipWhiteSpace(reader);
  1456. for (;;) {
  1457. c = coReaderCurr(reader);
  1458. if (c == ']')
  1459. break;
  1460. if (c < 0)
  1461. return coReaderErr(reader, "Missing ']'"), coDelete(array_obj), NULL;
  1462. if (coVectorEmpty(array_obj) == 0) // expect a ',' after the first element
  1463. if (c == ',') {
  1464. coReaderNext(reader);
  1465. coReaderSkipWhiteSpace(reader);
  1466. }
  1467. element = coJSONGetValue(reader);
  1468. // if ( element == NULL )
  1469. // return coReaderErr(reader, "'null' element for 'array'"),
  1470. // coDelete(array_obj), NULL;
  1471. if (coVectorAdd(array_obj, element) < 0)
  1472. return coReaderErr(reader, "Memory error inside 'array'"),
  1473. coDelete(array_obj), NULL;
  1474. }
  1475. coReaderNext(reader); // skip ']'
  1476. coReaderSkipWhiteSpace(reader);
  1477. assert(array_obj != NULL);
  1478. // printf("array end, array_obj=%p\n", array_obj);
  1479. return array_obj;
  1480. }
  1481. co coJSONGetMap(coReader reader) {
  1482. int c;
  1483. co map_obj;
  1484. co element;
  1485. char *key;
  1486. if (coReaderCurr(reader) != '{')
  1487. return coReaderErr(reader, "Internal error"), NULL;
  1488. map_obj = coNewMap(
  1489. CO_FREE_VALS |
  1490. CO_STRFREE); // do not duplicate keys, because they are already allocated
  1491. if (map_obj == NULL)
  1492. return coReaderErr(reader, "Memory error with map create"), NULL;
  1493. coReaderNext(reader); // skip '{'
  1494. coReaderSkipWhiteSpace(reader);
  1495. for (;;) {
  1496. c = coReaderCurr(reader);
  1497. if (c == '}')
  1498. break;
  1499. if (c < 0)
  1500. return coReaderErr(reader, "Missing '}'"), NULL;
  1501. if (coMapEmpty(map_obj) == 0) // expect a ',' after the first key/value pair
  1502. if (c == ',') {
  1503. coReaderNext(reader);
  1504. coReaderSkipWhiteSpace(reader);
  1505. }
  1506. key =
  1507. coJSONGetStr(reader); // key will contain a pointer to allocated memory
  1508. if (key == NULL)
  1509. return coDelete(map_obj), NULL;
  1510. coReaderSkipWhiteSpace(reader);
  1511. if (coReaderCurr(reader) != ':')
  1512. return coReaderErr(reader, "Missng ':'"), free(key), coDelete(map_obj),
  1513. NULL;
  1514. coReaderNext(reader);
  1515. coReaderSkipWhiteSpace(reader);
  1516. element = coJSONGetValue(reader); // may return NULL for the "null" element
  1517. // if ( element == NULL )
  1518. // return coReaderErr(reader, "Memory error with map element"), free(key),
  1519. // coDelete(map_obj), NULL;
  1520. /*
  1521. printf("key=%s element=", key);
  1522. coPrint(element);
  1523. printf("\n");
  1524. */
  1525. if (coMapAdd(map_obj, key, element) == 0)
  1526. return coReaderErr(reader, "Memory error with map update"), free(key),
  1527. coDelete(map_obj),
  1528. NULL; // ToDo: do we need to close 'element' here?
  1529. }
  1530. coReaderNext(reader); // skip '}'
  1531. coReaderSkipWhiteSpace(reader);
  1532. assert(map_obj != NULL);
  1533. return map_obj;
  1534. }
  1535. co coJSONGetValue(coReader reader) {
  1536. const char *identifier;
  1537. int c = coReaderCurr(reader);
  1538. if (c == '[')
  1539. return coJSONGetArray(reader);
  1540. if (c == '{')
  1541. return coJSONGetMap(reader);
  1542. if (c == '\"')
  1543. return coNewStr(
  1544. CO_STRFREE,
  1545. coJSONGetStr(reader)); // return value of coJSONGetStr() is a pointer to
  1546. // allocated memory, so don't use CO_STRDUP
  1547. if ((c >= '0' && c <= '9') || c == '-' || c == '+' || c == 'e' || c == 'E' ||
  1548. c == '.')
  1549. return coJSONGetDbl(reader);
  1550. identifier = coJSONGetIdentifier(reader);
  1551. if (strcmp(identifier, "null") == 0)
  1552. return NULL;
  1553. // todo: handle true, false
  1554. return NULL;
  1555. }
  1556. co coReadJSONByString(const char *json) {
  1557. struct co_reader_struct reader;
  1558. if (coReaderInitByString(&reader, json) == 0)
  1559. return NULL;
  1560. return coJSONGetValue(&reader);
  1561. }
  1562. co coReadJSONByFP(FILE *fp) {
  1563. struct co_reader_struct reader;
  1564. if (coReaderInitByFP(&reader, fp) == 0)
  1565. return NULL;
  1566. return coJSONGetValue(&reader);
  1567. }
  1568. /*===================================================================*/
  1569. /* JSON File Write */
  1570. /*===================================================================*/
  1571. static void coWriteJSONTraverse(cco o, int depth, int isUTF8,
  1572. FILE *fp); // forward declaration
  1573. static void writeIndent(int depth, FILE *fp) {
  1574. while (depth > 0) {
  1575. fprintf(fp, " ");
  1576. depth--;
  1577. }
  1578. }
  1579. static void writeString(const char *s, int isUTF8, FILE *fp) {
  1580. while (*s != '\0') {
  1581. if (*s == '\"' || *s == '/' || *s == '\\') {
  1582. fputc('\\', fp);
  1583. fputc(*s, fp);
  1584. } else if (*s == '\n') {
  1585. fputc('\\', fp);
  1586. fputc('n', fp);
  1587. } else if (*s == '\r') {
  1588. fputc('\\', fp);
  1589. fputc('r', fp);
  1590. } else if (*s == '\t') {
  1591. fputc('\\', fp);
  1592. fputc('t', fp);
  1593. } else if (*s == '\f') {
  1594. fputc('\\', fp);
  1595. fputc('f', fp);
  1596. } else if (*s == '\b') {
  1597. fputc('\\', fp);
  1598. fputc('b', fp);
  1599. } else if (*(unsigned char *)s < 32) {
  1600. fprintf(fp, "\\u%04x", *(unsigned char *)s);
  1601. } else if (isUTF8 == 0 && *(unsigned char *)s >= 128) {
  1602. fprintf(fp, "\\u%04x", *(unsigned char *)s);
  1603. } else {
  1604. fputc(*s, fp);
  1605. }
  1606. s++;
  1607. }
  1608. }
  1609. struct json_traverse_struct {
  1610. int depth;
  1611. int isUTF8;
  1612. FILE *fp;
  1613. long size;
  1614. };
  1615. static int coMapForEachJSONTraverseCB(cco o, long idx, const char *key,
  1616. cco value, void *data) {
  1617. struct json_traverse_struct *jts = (struct json_traverse_struct *)data;
  1618. writeIndent(jts->depth, jts->fp);
  1619. fputc('\"', jts->fp);
  1620. writeString(key, jts->isUTF8, jts->fp);
  1621. fputc('\"', jts->fp);
  1622. fputc(':', jts->fp);
  1623. coWriteJSONTraverse(value, jts->depth + 1, jts->isUTF8, jts->fp);
  1624. if (idx + 1 != jts->size)
  1625. fputc(',', jts->fp);
  1626. if (jts->depth >= 0)
  1627. fputc('\n', jts->fp);
  1628. return 1;
  1629. }
  1630. static void coWriteJSONTraverse(cco o, int depth, int isUTF8, FILE *fp) {
  1631. if (o == NULL) {
  1632. fprintf(fp, "null");
  1633. } else if (coIsStr(o)) {
  1634. fputc('\"', fp);
  1635. writeString(coStrGet(o), isUTF8, fp);
  1636. fputc('\"', fp);
  1637. } else if (coIsDbl(o)) {
  1638. fprintf(fp, "%.9g", coDblGet(o));
  1639. } else if (coIsVector(o)) {
  1640. long i;
  1641. long cnt = coVectorSize(o);
  1642. fputc('[', fp);
  1643. if (depth >= 0)
  1644. fputc('\n', fp);
  1645. for (i = 0; i < cnt; i++) {
  1646. writeIndent(depth + 1, fp);
  1647. coWriteJSONTraverse(coVectorGet(o, i), depth + 1, isUTF8, fp);
  1648. if (i + 1 != cnt)
  1649. fputc(',', fp);
  1650. if (depth >= 0)
  1651. fputc('\n', fp);
  1652. }
  1653. writeIndent(depth, fp);
  1654. fputc(']', fp);
  1655. } else if (coIsMap(o)) {
  1656. struct json_traverse_struct jts;
  1657. jts.size = coMapSize(o);
  1658. jts.fp = fp;
  1659. jts.depth = depth + 1;
  1660. jts.isUTF8 = isUTF8;
  1661. fputc('{', fp);
  1662. if (depth >= 0)
  1663. fputc('\n', fp);
  1664. coMapForEach(o, coMapForEachJSONTraverseCB, &jts);
  1665. writeIndent(depth, fp);
  1666. fputc('}', fp);
  1667. } else if (coIsMem(o)) // this will NOT generate proper JSON
  1668. {
  1669. unsigned char *ptr = (unsigned char *)coMemGet(o);
  1670. long cnt = coMemSize(o);
  1671. long i;
  1672. fputc('\"', fp);
  1673. for (i = 0; i < cnt; i++) {
  1674. if (i % 64 == 0)
  1675. fputc('\n', fp);
  1676. fprintf(fp, "%02x", ptr[i]);
  1677. }
  1678. fputc('\n', fp);
  1679. fputc('\"', fp);
  1680. }
  1681. }
  1682. void coWriteJSON(cco o, int isCompact, int isUTF8, FILE *fp) {
  1683. if (isCompact) {
  1684. coWriteJSONTraverse(o, -10000, isUTF8, fp);
  1685. } else {
  1686. coWriteJSONTraverse(o, 0, isUTF8, fp);
  1687. }
  1688. }