lejp.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. /*
  2. * Lightweight Embedded JSON Parser
  3. *
  4. * Copyright (C) 2013 Andy Green <andy@warmcat.com>
  5. * This code is licensed under LGPL 2.1
  6. * http://www.gnu.org/licenses/lgpl-2.1.html
  7. */
  8. #include <string.h>
  9. #include "lejp.h"
  10. #include <stdio.h>
  11. /**
  12. * lejp_construct - prepare a struct lejp_ctx for use
  13. *
  14. * \param ctx: pointer to your struct lejp_ctx
  15. * \param callback: your user callback which will received parsed tokens
  16. * \param user: optional user data pointer untouched by lejp
  17. * \param paths: your array of name elements you are interested in
  18. * \param count_paths: ARRAY_SIZE() of @paths
  19. *
  20. * Prepares your context struct for use with lejp
  21. */
  22. void
  23. lejp_construct(struct lejp_ctx *ctx,
  24. char (*callback)(struct lejp_ctx *ctx, char reason), void *user,
  25. const char * const *paths, unsigned char count_paths)
  26. {
  27. ctx->st[0].s = 0;
  28. ctx->st[0].p = 0;
  29. ctx->st[0].i = 0;
  30. ctx->st[0].b = 0;
  31. ctx->sp = 0;
  32. ctx->ipos = 0;
  33. ctx->ppos = 0;
  34. ctx->path_match = 0;
  35. ctx->path[0] = '\0';
  36. ctx->callback = callback;
  37. ctx->user = user;
  38. ctx->paths = paths;
  39. ctx->count_paths = count_paths;
  40. ctx->line = 1;
  41. ctx->callback(ctx, LEJPCB_CONSTRUCTED);
  42. }
  43. /**
  44. * lejp_destruct - retire a previously constructed struct lejp_ctx
  45. *
  46. * \param ctx: pointer to your struct lejp_ctx
  47. *
  48. * lejp does not perform any allocations, but since your user code might, this
  49. * provides a one-time LEJPCB_DESTRUCTED callback at destruction time where
  50. * you can clean up in your callback.
  51. */
  52. void
  53. lejp_destruct(struct lejp_ctx *ctx)
  54. {
  55. /* no allocations... just let callback know what it happening */
  56. ctx->callback(ctx, LEJPCB_DESTRUCTED);
  57. }
  58. /**
  59. * lejp_change_callback - switch to a different callback from now on
  60. *
  61. * \param ctx: pointer to your struct lejp_ctx
  62. * \param callback: your user callback which will received parsed tokens
  63. *
  64. * This tells the old callback it was destroyed, in case you want to take any
  65. * action because that callback "lost focus", then changes to the new
  66. * callback and tells it first that it was constructed, and then started.
  67. *
  68. * Changing callback is a cheap and powerful trick to split out handlers
  69. * according to information earlier in the parse. For example you may have
  70. * a JSON pair "schema" whose value defines what can be expected for the rest
  71. * of the JSON. Rather than having one huge callback for all cases, you can
  72. * have an initial one looking for "schema" which then calls
  73. * lejp_change_callback() to a handler specific for the schema.
  74. *
  75. * Notice that afterwards, you need to construct the context again anyway to
  76. * parse another JSON object, and the callback is reset then to the main,
  77. * schema-interpreting one. The construction action is very lightweight.
  78. */
  79. void
  80. lejp_change_callback(struct lejp_ctx *ctx,
  81. char (*callback)(struct lejp_ctx *ctx, char reason))
  82. {
  83. ctx->callback(ctx, LEJPCB_DESTRUCTED);
  84. ctx->callback = callback;
  85. ctx->callback(ctx, LEJPCB_CONSTRUCTED);
  86. ctx->callback(ctx, LEJPCB_START);
  87. }
  88. static void
  89. lejp_check_path_match(struct lejp_ctx *ctx)
  90. {
  91. const char *p, *q;
  92. int n;
  93. /* we only need to check if a match is not active */
  94. for (n = 0; !ctx->path_match && n < ctx->count_paths; n++) {
  95. ctx->wildcount = 0;
  96. p = ctx->path;
  97. q = ctx->paths[n];
  98. while (*p && *q) {
  99. if (*q != '*') {
  100. if (*p != *q)
  101. break;
  102. p++;
  103. q++;
  104. continue;
  105. }
  106. ctx->wild[ctx->wildcount++] = p - ctx->path;
  107. q++;
  108. /*
  109. * if * has something after it, match to .
  110. * if ends with *, eat everything.
  111. * This implies match sequences must be ordered like
  112. * x.*.*
  113. * x.*
  114. * if both options are possible
  115. */
  116. while (*p && (*p != '.' || !*q))
  117. p++;
  118. }
  119. if (*p || *q)
  120. continue;
  121. ctx->path_match = n + 1;
  122. ctx->path_match_len = ctx->ppos;
  123. return;
  124. }
  125. if (!ctx->path_match)
  126. ctx->wildcount = 0;
  127. }
  128. int
  129. lejp_get_wildcard(struct lejp_ctx *ctx, int wildcard, char *dest, int len)
  130. {
  131. int n;
  132. if (wildcard >= ctx->wildcount || !len)
  133. return 0;
  134. n = ctx->wild[wildcard];
  135. while (--len && n < ctx->ppos && (n == ctx->wild[wildcard] || ctx->path[n] != '.'))
  136. *dest++ = ctx->path[n++];
  137. *dest = '\0';
  138. n++;
  139. return n - ctx->wild[wildcard];
  140. }
  141. /**
  142. * lejp_parse - interpret some more incoming data incrementally
  143. *
  144. * \param ctx: previously constructed parsing context
  145. * \param json: char buffer with the new data to interpret
  146. * \param len: amount of data in the buffer
  147. *
  148. * Because lejp is a stream parser, it incrementally parses as new data
  149. * becomes available, maintaining all state in the context struct. So an
  150. * incomplete JSON is a normal situation, getting you a LEJP_CONTINUE
  151. * return, signalling there's no error but to call again with more data when
  152. * it comes to complete the parsing. Successful parsing completes with a
  153. * 0 or positive integer indicating how much of the last input buffer was
  154. * unused.
  155. */
  156. int
  157. lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
  158. {
  159. unsigned char c, n, s, ret = LEJP_REJECT_UNKNOWN;
  160. static const char esc_char[] = "\"\\/bfnrt";
  161. static const char esc_tran[] = "\"\\/\b\f\n\r\t";
  162. static const char tokens[] = "rue alse ull ";
  163. if (!ctx->sp && !ctx->ppos)
  164. ctx->callback(ctx, LEJPCB_START);
  165. while (len--) {
  166. c = *json++;
  167. s = ctx->st[ctx->sp].s;
  168. /* skip whitespace unless we should care */
  169. if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '#') {
  170. if (c == '\n') {
  171. ctx->line++;
  172. ctx->st[ctx->sp].s &= ~LEJP_FLAG_WS_COMMENTLINE;
  173. }
  174. if (!(s & LEJP_FLAG_WS_KEEP)) {
  175. if (c == '#')
  176. ctx->st[ctx->sp].s |=
  177. LEJP_FLAG_WS_COMMENTLINE;
  178. continue;
  179. }
  180. }
  181. if (ctx->st[ctx->sp].s & LEJP_FLAG_WS_COMMENTLINE)
  182. continue;
  183. switch (s) {
  184. case LEJP_IDLE:
  185. if (c != '{') {
  186. ret = LEJP_REJECT_IDLE_NO_BRACE;
  187. goto reject;
  188. }
  189. if (ctx->callback(ctx, LEJPCB_OBJECT_START)) {
  190. ret = LEJP_REJECT_CALLBACK;
  191. goto reject;
  192. }
  193. ctx->st[ctx->sp].s = LEJP_MEMBERS;
  194. break;
  195. case LEJP_MEMBERS:
  196. if (c == '}') {
  197. ctx->st[ctx->sp].s = LEJP_IDLE;
  198. ret = LEJP_REJECT_MEMBERS_NO_CLOSE;
  199. goto reject;
  200. }
  201. ctx->st[ctx->sp].s = LEJP_M_P;
  202. goto redo_character;
  203. case LEJP_M_P:
  204. if (c != '\"') {
  205. ret = LEJP_REJECT_MP_NO_OPEN_QUOTE;
  206. goto reject;
  207. }
  208. /* push */
  209. ctx->st[ctx->sp].s = LEJP_MP_DELIM;
  210. c = LEJP_MP_STRING;
  211. goto add_stack_level;
  212. case LEJP_MP_STRING:
  213. if (c == '\"') {
  214. if (!ctx->sp) {
  215. ret = LEJP_REJECT_MP_STRING_UNDERRUN;
  216. goto reject;
  217. }
  218. if (ctx->st[ctx->sp - 1].s != LEJP_MP_DELIM) {
  219. ctx->buf[ctx->npos] = '\0';
  220. if (ctx->callback(ctx,
  221. LEJPCB_VAL_STR_END) < 0) {
  222. ret = LEJP_REJECT_CALLBACK;
  223. goto reject;
  224. }
  225. }
  226. /* pop */
  227. ctx->sp--;
  228. break;
  229. }
  230. if (c == '\\') {
  231. ctx->st[ctx->sp].s = LEJP_MP_STRING_ESC;
  232. break;
  233. }
  234. if (c < ' ') {/* "control characters" not allowed */
  235. ret = LEJP_REJECT_MP_ILLEGAL_CTRL;
  236. goto reject;
  237. }
  238. goto emit_string_char;
  239. case LEJP_MP_STRING_ESC:
  240. if (c == 'u') {
  241. ctx->st[ctx->sp].s = LEJP_MP_STRING_ESC_U1;
  242. ctx->uni = 0;
  243. break;
  244. }
  245. for (n = 0; n < sizeof(esc_char); n++) {
  246. if (c != esc_char[n])
  247. continue;
  248. /* found it */
  249. c = esc_tran[n];
  250. ctx->st[ctx->sp].s = LEJP_MP_STRING;
  251. goto emit_string_char;
  252. }
  253. ret = LEJP_REJECT_MP_STRING_ESC_ILLEGAL_ESC;
  254. /* illegal escape char */
  255. goto reject;
  256. case LEJP_MP_STRING_ESC_U1:
  257. case LEJP_MP_STRING_ESC_U2:
  258. case LEJP_MP_STRING_ESC_U3:
  259. case LEJP_MP_STRING_ESC_U4:
  260. ctx->uni <<= 4;
  261. if (c >= '0' && c <= '9')
  262. ctx->uni |= c - '0';
  263. else
  264. if (c >= 'a' && c <= 'f')
  265. ctx->uni = c - 'a' + 10;
  266. else
  267. if (c >= 'A' && c <= 'F')
  268. ctx->uni = c - 'A' + 10;
  269. else {
  270. ret = LEJP_REJECT_ILLEGAL_HEX;
  271. goto reject;
  272. }
  273. ctx->st[ctx->sp].s++;
  274. switch (s) {
  275. case LEJP_MP_STRING_ESC_U2:
  276. if (ctx->uni < 0x08)
  277. break;
  278. /*
  279. * 0x08-0xff (0x0800 - 0xffff)
  280. * emit 3-byte UTF-8
  281. */
  282. c = 0xe0 | ((ctx->uni >> 4) & 0xf);
  283. goto emit_string_char;
  284. case LEJP_MP_STRING_ESC_U3:
  285. if (ctx->uni >= 0x080) {
  286. /*
  287. * 0x080 - 0xfff (0x0800 - 0xffff)
  288. * middle 3-byte seq
  289. * send ....XXXXXX..
  290. */
  291. c = 0x80 | ((ctx->uni >> 2) & 0x3f);
  292. goto emit_string_char;
  293. }
  294. if (ctx->uni < 0x008)
  295. break;
  296. /*
  297. * 0x008 - 0x7f (0x0080 - 0x07ff)
  298. * start 2-byte seq
  299. */
  300. c = 0xc0 | (ctx->uni >> 2);
  301. goto emit_string_char;
  302. case LEJP_MP_STRING_ESC_U4:
  303. if (ctx->uni >= 0x0080)
  304. /* end of 2 or 3-byte seq */
  305. c = 0x80 | (ctx->uni & 0x3f);
  306. else
  307. /* literal */
  308. c = (unsigned char)ctx->uni;
  309. ctx->st[ctx->sp].s = LEJP_MP_STRING;
  310. goto emit_string_char;
  311. default:
  312. break;
  313. }
  314. break;
  315. case LEJP_MP_DELIM:
  316. if (c != ':') {
  317. ret = LEJP_REJECT_MP_DELIM_MISSING_COLON;
  318. goto reject;
  319. }
  320. ctx->st[ctx->sp].s = LEJP_MP_VALUE;
  321. ctx->path[ctx->ppos] = '\0';
  322. lejp_check_path_match(ctx);
  323. if (ctx->callback(ctx, LEJPCB_PAIR_NAME)) {
  324. ret = LEJP_REJECT_CALLBACK;
  325. goto reject;
  326. }
  327. break;
  328. case LEJP_MP_VALUE:
  329. if (c >= '0' && c <= '9') {
  330. ctx->npos = 0;
  331. ctx->dcount = 0;
  332. ctx->f = 0;
  333. ctx->st[ctx->sp].s = LEJP_MP_VALUE_NUM_INT;
  334. goto redo_character;
  335. }
  336. switch (c) {
  337. case'\"':
  338. /* push */
  339. ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
  340. c = LEJP_MP_STRING;
  341. ctx->npos = 0;
  342. ctx->buf[0] = '\0';
  343. if (ctx->callback(ctx, LEJPCB_VAL_STR_START)) {
  344. ret = LEJP_REJECT_CALLBACK;
  345. goto reject;
  346. }
  347. goto add_stack_level;
  348. case '{':
  349. /* push */
  350. ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
  351. c = LEJP_MEMBERS;
  352. lejp_check_path_match(ctx);
  353. if (ctx->callback(ctx, LEJPCB_OBJECT_START)) {
  354. ret = LEJP_REJECT_CALLBACK;
  355. goto reject;
  356. }
  357. ctx->path_match = 0;
  358. goto add_stack_level;
  359. case '[':
  360. /* push */
  361. ctx->st[ctx->sp].s = LEJP_MP_ARRAY_END;
  362. c = LEJP_MP_VALUE;
  363. ctx->path[ctx->ppos++] = '[';
  364. ctx->path[ctx->ppos++] = ']';
  365. ctx->path[ctx->ppos] = '\0';
  366. if (ctx->callback(ctx, LEJPCB_ARRAY_START)) {
  367. ret = LEJP_REJECT_CALLBACK;
  368. goto reject;
  369. }
  370. ctx->i[ctx->ipos++] = 0;
  371. if (ctx->ipos > ARRAY_SIZE(ctx->i)) {
  372. ret = LEJP_REJECT_MP_DELIM_ISTACK;
  373. goto reject;
  374. }
  375. goto add_stack_level;
  376. case 't': /* true */
  377. ctx->uni = 0;
  378. ctx->st[ctx->sp].s = LEJP_MP_VALUE_TOK;
  379. break;
  380. case 'f':
  381. ctx->uni = 4;
  382. ctx->st[ctx->sp].s = LEJP_MP_VALUE_TOK;
  383. break;
  384. case 'n':
  385. ctx->uni = 4 + 5;
  386. ctx->st[ctx->sp].s = LEJP_MP_VALUE_TOK;
  387. break;
  388. default:
  389. ret = LEJP_REJECT_MP_DELIM_BAD_VALUE_START;
  390. goto reject;
  391. }
  392. break;
  393. case LEJP_MP_VALUE_NUM_INT:
  394. if (!ctx->npos && c == '-') {
  395. ctx->f |= LEJP_SEEN_MINUS;
  396. goto append_npos;
  397. }
  398. if (ctx->dcount < 10 && c >= '0' && c <= '9') {
  399. if (ctx->f & LEJP_SEEN_POINT)
  400. ctx->f |= LEJP_SEEN_POST_POINT;
  401. ctx->dcount++;
  402. goto append_npos;
  403. }
  404. if (c == '.') {
  405. if (ctx->dcount || (ctx->f & LEJP_SEEN_POINT)) {
  406. ret = LEJP_REJECT_MP_VAL_NUM_FORMAT;
  407. goto reject;
  408. }
  409. ctx->f |= LEJP_SEEN_POINT;
  410. goto append_npos;
  411. }
  412. /*
  413. * before exponent, if we had . we must have had at
  414. * least one more digit
  415. */
  416. if ((ctx->f &
  417. (LEJP_SEEN_POINT | LEJP_SEEN_POST_POINT)) ==
  418. LEJP_SEEN_POINT) {
  419. ret = LEJP_REJECT_MP_VAL_NUM_INT_NO_FRAC;
  420. goto reject;
  421. }
  422. if (c == 'e' || c == 'E') {
  423. if (ctx->f & LEJP_SEEN_EXP) {
  424. ret = LEJP_REJECT_MP_VAL_NUM_FORMAT;
  425. goto reject;
  426. }
  427. ctx->f |= LEJP_SEEN_EXP;
  428. ctx->st[ctx->sp].s = LEJP_MP_VALUE_NUM_EXP;
  429. goto append_npos;
  430. }
  431. /* if none of the above, did we even have a number? */
  432. if (!ctx->dcount) {
  433. ret = LEJP_REJECT_MP_VAL_NUM_FORMAT;
  434. goto reject;
  435. }
  436. ctx->buf[ctx->npos] = '\0';
  437. if (ctx->f & LEJP_SEEN_POINT) {
  438. if (ctx->callback(ctx, LEJPCB_VAL_NUM_FLOAT)) {
  439. ret = LEJP_REJECT_CALLBACK;
  440. goto reject;
  441. }
  442. } else {
  443. if (ctx->callback(ctx, LEJPCB_VAL_NUM_INT)) {
  444. ret = LEJP_REJECT_CALLBACK;
  445. goto reject;
  446. }
  447. }
  448. /* then this is the post-number character, loop */
  449. ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
  450. goto redo_character;
  451. case LEJP_MP_VALUE_NUM_EXP:
  452. ctx->st[ctx->sp].s = LEJP_MP_VALUE_NUM_INT;
  453. if (c >= '0' && c <= '9')
  454. goto redo_character;
  455. if (c == '+' || c == '-')
  456. goto append_npos;
  457. ret = LEJP_REJECT_MP_VAL_NUM_EXP_BAD_EXP;
  458. goto reject;
  459. case LEJP_MP_VALUE_TOK: /* true, false, null */
  460. if (c != tokens[ctx->uni]) {
  461. ret = LEJP_REJECT_MP_VAL_TOK_UNKNOWN;
  462. goto reject;
  463. }
  464. ctx->uni++;
  465. if (tokens[ctx->uni] != ' ')
  466. break;
  467. switch (ctx->uni) {
  468. case 3:
  469. ctx->buf[0] = '1';
  470. ctx->buf[1] = '\0';
  471. if (ctx->callback(ctx, LEJPCB_VAL_TRUE)) {
  472. ret = LEJP_REJECT_CALLBACK;
  473. goto reject;
  474. }
  475. break;
  476. case 8:
  477. ctx->buf[0] = '0';
  478. ctx->buf[1] = '\0';
  479. if (ctx->callback(ctx, LEJPCB_VAL_FALSE)) {
  480. ret = LEJP_REJECT_CALLBACK;
  481. goto reject;
  482. }
  483. break;
  484. case 12:
  485. ctx->buf[0] = '\0';
  486. if (ctx->callback(ctx, LEJPCB_VAL_NULL)) {
  487. ret = LEJP_REJECT_CALLBACK;
  488. goto reject;
  489. }
  490. break;
  491. }
  492. ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
  493. break;
  494. case LEJP_MP_COMMA_OR_END:
  495. ctx->path[ctx->ppos] = '\0';
  496. if (c == ',') {
  497. /* increment this stack level's index */
  498. ctx->st[ctx->sp].s = LEJP_M_P;
  499. if (!ctx->sp) {
  500. ctx->ppos = 0;
  501. /*
  502. * since we came back to root level,
  503. * no path can still match
  504. */
  505. ctx->path_match = 0;
  506. break;
  507. }
  508. ctx->ppos = ctx->st[ctx->sp - 1].p;
  509. ctx->path[ctx->ppos] = '\0';
  510. if (ctx->path_match &&
  511. ctx->ppos <= ctx->path_match_len)
  512. /*
  513. * we shrank the path to be
  514. * smaller than the matching point
  515. */
  516. ctx->path_match = 0;
  517. if (ctx->st[ctx->sp - 1].s != LEJP_MP_ARRAY_END)
  518. break;
  519. /* top level is definitely an array... */
  520. if (ctx->ipos)
  521. ctx->i[ctx->ipos - 1]++;
  522. ctx->st[ctx->sp].s = LEJP_MP_VALUE;
  523. break;
  524. }
  525. if (c == ']') {
  526. if (!ctx->sp) {
  527. ret = LEJP_REJECT_MP_C_OR_E_UNDERF;
  528. goto reject;
  529. }
  530. /* pop */
  531. ctx->sp--;
  532. if (ctx->st[ctx->sp].s != LEJP_MP_ARRAY_END) {
  533. ret = LEJP_REJECT_MP_C_OR_E_NOTARRAY;
  534. goto reject;
  535. }
  536. /* drop the path [n] bit */
  537. ctx->ppos = ctx->st[ctx->sp - 1].p;
  538. ctx->ipos = ctx->st[ctx->sp - 1].i;
  539. ctx->path[ctx->ppos] = '\0';
  540. if (ctx->path_match &&
  541. ctx->ppos <= ctx->path_match_len)
  542. /*
  543. * we shrank the path to be
  544. * smaller than the matching point
  545. */
  546. ctx->path_match = 0;
  547. /* do LEJP_MP_ARRAY_END processing */
  548. goto redo_character;
  549. }
  550. if (c == '}') {
  551. if (ctx->sp == 0) {
  552. lejp_check_path_match(ctx);
  553. if (ctx->callback(ctx, LEJPCB_OBJECT_END)) {
  554. ret = LEJP_REJECT_CALLBACK;
  555. goto reject;
  556. }
  557. ctx->callback(ctx, LEJPCB_COMPLETE);
  558. /* done, return unused amount */
  559. return len;
  560. }
  561. /* pop */
  562. ctx->sp--;
  563. ctx->ppos = ctx->st[ctx->sp - 1].p;
  564. ctx->ipos = ctx->st[ctx->sp - 1].i;
  565. ctx->path[ctx->ppos] = '\0';
  566. if (ctx->path_match &&
  567. ctx->ppos <= ctx->path_match_len)
  568. /*
  569. * we shrank the path to be
  570. * smaller than the matching point
  571. */
  572. ctx->path_match = 0;
  573. lejp_check_path_match(ctx);
  574. if (ctx->callback(ctx, LEJPCB_OBJECT_END)) {
  575. ret = LEJP_REJECT_CALLBACK;
  576. goto reject;
  577. }
  578. break;
  579. }
  580. ret = LEJP_REJECT_MP_C_OR_E_NEITHER;
  581. goto reject;
  582. case LEJP_MP_ARRAY_END:
  583. ctx->path[ctx->ppos] = '\0';
  584. if (c == ',') {
  585. /* increment this stack level's index */
  586. if (ctx->ipos)
  587. ctx->i[ctx->ipos - 1]++;
  588. ctx->st[ctx->sp].s = LEJP_MP_VALUE;
  589. if (ctx->sp)
  590. ctx->ppos = ctx->st[ctx->sp - 1].p;
  591. ctx->path[ctx->ppos] = '\0';
  592. break;
  593. }
  594. if (c != ']') {
  595. ret = LEJP_REJECT_MP_ARRAY_END_MISSING;
  596. goto reject;
  597. }
  598. ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
  599. ctx->callback(ctx, LEJPCB_ARRAY_END);
  600. break;
  601. }
  602. continue;
  603. emit_string_char:
  604. if (!ctx->sp || ctx->st[ctx->sp - 1].s != LEJP_MP_DELIM) {
  605. /* assemble the string value into chunks */
  606. ctx->buf[ctx->npos++] = c;
  607. if (ctx->npos == sizeof(ctx->buf) - 1) {
  608. if (ctx->callback(ctx, LEJPCB_VAL_STR_CHUNK)) {
  609. ret = LEJP_REJECT_CALLBACK;
  610. goto reject;
  611. }
  612. ctx->npos = 0;
  613. }
  614. continue;
  615. }
  616. /* name part of name:value pair */
  617. ctx->path[ctx->ppos++] = c;
  618. continue;
  619. add_stack_level:
  620. /* push on to the object stack */
  621. if (ctx->ppos && ctx->st[ctx->sp].s != LEJP_MP_COMMA_OR_END &&
  622. ctx->st[ctx->sp].s != LEJP_MP_ARRAY_END)
  623. ctx->path[ctx->ppos++] = '.';
  624. ctx->st[ctx->sp].p = ctx->ppos;
  625. ctx->st[ctx->sp].i = ctx->ipos;
  626. if (++ctx->sp == ARRAY_SIZE(ctx->st)) {
  627. ret = LEJP_REJECT_STACK_OVERFLOW;
  628. goto reject;
  629. }
  630. ctx->path[ctx->ppos] = '\0';
  631. ctx->st[ctx->sp].s = c;
  632. ctx->st[ctx->sp].b = 0;
  633. continue;
  634. append_npos:
  635. if (ctx->npos >= sizeof(ctx->buf)) {
  636. ret = LEJP_REJECT_NUM_TOO_LONG;
  637. goto reject;
  638. }
  639. ctx->buf[ctx->npos++] = c;
  640. continue;
  641. redo_character:
  642. json--;
  643. len++;
  644. }
  645. return LEJP_CONTINUE;
  646. reject:
  647. ctx->callback(ctx, LEJPCB_FAILED);
  648. return ret;
  649. }