jsmn.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865
  1. /*
  2. * MIT License
  3. *
  4. * Copyright (c) 2010 Serge Zaitsev
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22. * SOFTWARE.
  23. */
  24. #ifndef JSMN_H
  25. #define JSMN_H
  26. #include <stddef.h>
  27. #ifdef __cplusplus
  28. extern "C"
  29. {
  30. #endif
  31. #ifdef JSMN_STATIC
  32. #define JSMN_API static
  33. #else
  34. #define JSMN_API extern
  35. #endif
  36. /**
  37. * JSON type identifier. Basic types are:
  38. * o Object
  39. * o Array
  40. * o String
  41. * o Other primitive: number, boolean (true/false) or null
  42. */
  43. typedef enum
  44. {
  45. JSMN_UNDEFINED = 0,
  46. JSMN_OBJECT = 1 << 0,
  47. JSMN_ARRAY = 1 << 1,
  48. JSMN_STRING = 1 << 2,
  49. JSMN_PRIMITIVE = 1 << 3
  50. } jsmntype_t;
  51. enum jsmnerr
  52. {
  53. /* Not enough tokens were provided */
  54. JSMN_ERROR_NOMEM = -1,
  55. /* Invalid character inside JSON string */
  56. JSMN_ERROR_INVAL = -2,
  57. /* The string is not a full JSON packet, more bytes expected */
  58. JSMN_ERROR_PART = -3
  59. };
  60. /**
  61. * JSON token description.
  62. * type type (object, array, string etc.)
  63. * start start position in JSON data string
  64. * end end position in JSON data string
  65. */
  66. typedef struct jsmntok
  67. {
  68. jsmntype_t type;
  69. int start;
  70. int end;
  71. int size;
  72. #ifdef JSMN_PARENT_LINKS
  73. int parent;
  74. #endif
  75. } jsmntok_t;
  76. /**
  77. * JSON parser. Contains an array of token blocks available. Also stores
  78. * the string being parsed now and current position in that string.
  79. */
  80. typedef struct jsmn_parser
  81. {
  82. unsigned int pos; /* offset in the JSON string */
  83. unsigned int toknext; /* next token to allocate */
  84. int toksuper; /* superior token node, e.g. parent object or array */
  85. } jsmn_parser;
  86. /**
  87. * Create JSON parser over an array of tokens
  88. */
  89. JSMN_API void jsmn_init(jsmn_parser *parser);
  90. /**
  91. * Run JSON parser. It parses a JSON data string into and array of tokens, each
  92. * describing
  93. * a single JSON object.
  94. */
  95. JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,
  96. jsmntok_t *tokens, const unsigned int num_tokens);
  97. #ifndef JSMN_HEADER
  98. /**
  99. * Allocates a fresh unused token from the token pool.
  100. */
  101. static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens,
  102. const size_t num_tokens)
  103. {
  104. jsmntok_t *tok;
  105. if (parser->toknext >= num_tokens)
  106. {
  107. return NULL;
  108. }
  109. tok = &tokens[parser->toknext++];
  110. tok->start = tok->end = -1;
  111. tok->size = 0;
  112. #ifdef JSMN_PARENT_LINKS
  113. tok->parent = -1;
  114. #endif
  115. return tok;
  116. }
  117. /**
  118. * Fills token type and boundaries.
  119. */
  120. static void jsmn_fill_token(jsmntok_t *token, const jsmntype_t type,
  121. const int start, const int end)
  122. {
  123. token->type = type;
  124. token->start = start;
  125. token->end = end;
  126. token->size = 0;
  127. }
  128. /**
  129. * Fills next available token with JSON primitive.
  130. */
  131. static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
  132. const size_t len, jsmntok_t *tokens,
  133. const size_t num_tokens)
  134. {
  135. jsmntok_t *token;
  136. int start;
  137. start = parser->pos;
  138. for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++)
  139. {
  140. switch (js[parser->pos])
  141. {
  142. #ifndef JSMN_STRICT
  143. /* In strict mode primitive must be followed by "," or "}" or "]" */
  144. case ':':
  145. #endif
  146. case '\t':
  147. case '\r':
  148. case '\n':
  149. case ' ':
  150. case ',':
  151. case ']':
  152. case '}':
  153. goto found;
  154. default:
  155. /* to quiet a warning from gcc*/
  156. break;
  157. }
  158. if (js[parser->pos] < 32 || js[parser->pos] >= 127)
  159. {
  160. parser->pos = start;
  161. return JSMN_ERROR_INVAL;
  162. }
  163. }
  164. #ifdef JSMN_STRICT
  165. /* In strict mode primitive must be followed by a comma/object/array */
  166. parser->pos = start;
  167. return JSMN_ERROR_PART;
  168. #endif
  169. found:
  170. if (tokens == NULL)
  171. {
  172. parser->pos--;
  173. return 0;
  174. }
  175. token = jsmn_alloc_token(parser, tokens, num_tokens);
  176. if (token == NULL)
  177. {
  178. parser->pos = start;
  179. return JSMN_ERROR_NOMEM;
  180. }
  181. jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
  182. #ifdef JSMN_PARENT_LINKS
  183. token->parent = parser->toksuper;
  184. #endif
  185. parser->pos--;
  186. return 0;
  187. }
  188. /**
  189. * Fills next token with JSON string.
  190. */
  191. static int jsmn_parse_string(jsmn_parser *parser, const char *js,
  192. const size_t len, jsmntok_t *tokens,
  193. const size_t num_tokens)
  194. {
  195. jsmntok_t *token;
  196. int start = parser->pos;
  197. /* Skip starting quote */
  198. parser->pos++;
  199. for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++)
  200. {
  201. char c = js[parser->pos];
  202. /* Quote: end of string */
  203. if (c == '\"')
  204. {
  205. if (tokens == NULL)
  206. {
  207. return 0;
  208. }
  209. token = jsmn_alloc_token(parser, tokens, num_tokens);
  210. if (token == NULL)
  211. {
  212. parser->pos = start;
  213. return JSMN_ERROR_NOMEM;
  214. }
  215. jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos);
  216. #ifdef JSMN_PARENT_LINKS
  217. token->parent = parser->toksuper;
  218. #endif
  219. return 0;
  220. }
  221. /* Backslash: Quoted symbol expected */
  222. if (c == '\\' && parser->pos + 1 < len)
  223. {
  224. int i;
  225. parser->pos++;
  226. switch (js[parser->pos])
  227. {
  228. /* Allowed escaped symbols */
  229. case '\"':
  230. case '/':
  231. case '\\':
  232. case 'b':
  233. case 'f':
  234. case 'r':
  235. case 'n':
  236. case 't':
  237. break;
  238. /* Allows escaped symbol \uXXXX */
  239. case 'u':
  240. parser->pos++;
  241. for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0';
  242. i++)
  243. {
  244. /* If it isn't a hex character we have an error */
  245. if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
  246. (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
  247. (js[parser->pos] >= 97 && js[parser->pos] <= 102)))
  248. { /* a-f */
  249. parser->pos = start;
  250. return JSMN_ERROR_INVAL;
  251. }
  252. parser->pos++;
  253. }
  254. parser->pos--;
  255. break;
  256. /* Unexpected symbol */
  257. default:
  258. parser->pos = start;
  259. return JSMN_ERROR_INVAL;
  260. }
  261. }
  262. }
  263. parser->pos = start;
  264. return JSMN_ERROR_PART;
  265. }
  266. /**
  267. * Parse JSON string and fill tokens.
  268. */
  269. JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,
  270. jsmntok_t *tokens, const unsigned int num_tokens)
  271. {
  272. int r;
  273. int i;
  274. jsmntok_t *token;
  275. int count = parser->toknext;
  276. for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++)
  277. {
  278. char c;
  279. jsmntype_t type;
  280. c = js[parser->pos];
  281. switch (c)
  282. {
  283. case '{':
  284. case '[':
  285. count++;
  286. if (tokens == NULL)
  287. {
  288. break;
  289. }
  290. token = jsmn_alloc_token(parser, tokens, num_tokens);
  291. if (token == NULL)
  292. {
  293. return JSMN_ERROR_NOMEM;
  294. }
  295. if (parser->toksuper != -1)
  296. {
  297. jsmntok_t *t = &tokens[parser->toksuper];
  298. #ifdef JSMN_STRICT
  299. /* In strict mode an object or array can't become a key */
  300. if (t->type == JSMN_OBJECT)
  301. {
  302. return JSMN_ERROR_INVAL;
  303. }
  304. #endif
  305. t->size++;
  306. #ifdef JSMN_PARENT_LINKS
  307. token->parent = parser->toksuper;
  308. #endif
  309. }
  310. token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
  311. token->start = parser->pos;
  312. parser->toksuper = parser->toknext - 1;
  313. break;
  314. case '}':
  315. case ']':
  316. if (tokens == NULL)
  317. {
  318. break;
  319. }
  320. type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
  321. #ifdef JSMN_PARENT_LINKS
  322. if (parser->toknext < 1)
  323. {
  324. return JSMN_ERROR_INVAL;
  325. }
  326. token = &tokens[parser->toknext - 1];
  327. for (;;)
  328. {
  329. if (token->start != -1 && token->end == -1)
  330. {
  331. if (token->type != type)
  332. {
  333. return JSMN_ERROR_INVAL;
  334. }
  335. token->end = parser->pos + 1;
  336. parser->toksuper = token->parent;
  337. break;
  338. }
  339. if (token->parent == -1)
  340. {
  341. if (token->type != type || parser->toksuper == -1)
  342. {
  343. return JSMN_ERROR_INVAL;
  344. }
  345. break;
  346. }
  347. token = &tokens[token->parent];
  348. }
  349. #else
  350. for (i = parser->toknext - 1; i >= 0; i--)
  351. {
  352. token = &tokens[i];
  353. if (token->start != -1 && token->end == -1)
  354. {
  355. if (token->type != type)
  356. {
  357. return JSMN_ERROR_INVAL;
  358. }
  359. parser->toksuper = -1;
  360. token->end = parser->pos + 1;
  361. break;
  362. }
  363. }
  364. /* Error if unmatched closing bracket */
  365. if (i == -1)
  366. {
  367. return JSMN_ERROR_INVAL;
  368. }
  369. for (; i >= 0; i--)
  370. {
  371. token = &tokens[i];
  372. if (token->start != -1 && token->end == -1)
  373. {
  374. parser->toksuper = i;
  375. break;
  376. }
  377. }
  378. #endif
  379. break;
  380. case '\"':
  381. r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
  382. if (r < 0)
  383. {
  384. return r;
  385. }
  386. count++;
  387. if (parser->toksuper != -1 && tokens != NULL)
  388. {
  389. tokens[parser->toksuper].size++;
  390. }
  391. break;
  392. case '\t':
  393. case '\r':
  394. case '\n':
  395. case ' ':
  396. break;
  397. case ':':
  398. parser->toksuper = parser->toknext - 1;
  399. break;
  400. case ',':
  401. if (tokens != NULL && parser->toksuper != -1 &&
  402. tokens[parser->toksuper].type != JSMN_ARRAY &&
  403. tokens[parser->toksuper].type != JSMN_OBJECT)
  404. {
  405. #ifdef JSMN_PARENT_LINKS
  406. parser->toksuper = tokens[parser->toksuper].parent;
  407. #else
  408. for (i = parser->toknext - 1; i >= 0; i--)
  409. {
  410. if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT)
  411. {
  412. if (tokens[i].start != -1 && tokens[i].end == -1)
  413. {
  414. parser->toksuper = i;
  415. break;
  416. }
  417. }
  418. }
  419. #endif
  420. }
  421. break;
  422. #ifdef JSMN_STRICT
  423. /* In strict mode primitives are: numbers and booleans */
  424. case '-':
  425. case '0':
  426. case '1':
  427. case '2':
  428. case '3':
  429. case '4':
  430. case '5':
  431. case '6':
  432. case '7':
  433. case '8':
  434. case '9':
  435. case 't':
  436. case 'f':
  437. case 'n':
  438. /* And they must not be keys of the object */
  439. if (tokens != NULL && parser->toksuper != -1)
  440. {
  441. const jsmntok_t *t = &tokens[parser->toksuper];
  442. if (t->type == JSMN_OBJECT ||
  443. (t->type == JSMN_STRING && t->size != 0))
  444. {
  445. return JSMN_ERROR_INVAL;
  446. }
  447. }
  448. #else
  449. /* In non-strict mode every unquoted value is a primitive */
  450. default:
  451. #endif
  452. r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
  453. if (r < 0)
  454. {
  455. return r;
  456. }
  457. count++;
  458. if (parser->toksuper != -1 && tokens != NULL)
  459. {
  460. tokens[parser->toksuper].size++;
  461. }
  462. break;
  463. #ifdef JSMN_STRICT
  464. /* Unexpected char in strict mode */
  465. default:
  466. return JSMN_ERROR_INVAL;
  467. #endif
  468. }
  469. }
  470. if (tokens != NULL)
  471. {
  472. for (i = parser->toknext - 1; i >= 0; i--)
  473. {
  474. /* Unmatched opened object or array */
  475. if (tokens[i].start != -1 && tokens[i].end == -1)
  476. {
  477. return JSMN_ERROR_PART;
  478. }
  479. }
  480. }
  481. return count;
  482. }
  483. /**
  484. * Creates a new parser based over a given buffer with an array of tokens
  485. * available.
  486. */
  487. JSMN_API void jsmn_init(jsmn_parser *parser)
  488. {
  489. parser->pos = 0;
  490. parser->toknext = 0;
  491. parser->toksuper = -1;
  492. }
  493. #endif /* JSMN_HEADER */
  494. #ifdef __cplusplus
  495. }
  496. #endif
  497. #endif /* JSMN_H */
  498. #ifndef JB_JSMN_EDIT
  499. #define JB_JSMN_EDIT
  500. /* Added in by JBlanked on 2024-10-16 for use in Flipper Zero SDK*/
  501. #include <string.h>
  502. #include <stdint.h>
  503. #include <stdlib.h>
  504. #include <stdio.h>
  505. #include <stdio.h>
  506. #include <string.h>
  507. #include <furi.h>
  508. // Helper function to create a JSON object
  509. char *jsmn(const char *key, const char *value)
  510. {
  511. int length = strlen(key) + strlen(value) + 8; // Calculate required length
  512. char *result = (char *)malloc(length * sizeof(char)); // Allocate memory
  513. if (result == NULL)
  514. {
  515. return NULL; // Handle memory allocation failure
  516. }
  517. snprintf(result, length, "{\"%s\":\"%s\"}", key, value);
  518. return result; // Caller is responsible for freeing this memory
  519. }
  520. // Helper function to compare JSON keys
  521. int jsoneq(const char *json, jsmntok_t *tok, const char *s)
  522. {
  523. if (tok->type == JSMN_STRING && (int)strlen(s) == tok->end - tok->start &&
  524. strncmp(json + tok->start, s, tok->end - tok->start) == 0)
  525. {
  526. return 0;
  527. }
  528. return -1;
  529. }
  530. // return the value of the key in the JSON data
  531. char *get_json_value(char *key, char *json_data, uint32_t max_tokens)
  532. {
  533. // Parse the JSON feed
  534. if (json_data != NULL)
  535. {
  536. jsmn_parser parser;
  537. jsmn_init(&parser);
  538. // Allocate tokens array on the heap
  539. jsmntok_t *tokens = malloc(sizeof(jsmntok_t) * max_tokens);
  540. if (tokens == NULL)
  541. {
  542. FURI_LOG_E("JSMM.H", "Failed to allocate memory for JSON tokens.");
  543. return NULL;
  544. }
  545. int ret = jsmn_parse(&parser, json_data, strlen(json_data), tokens, max_tokens);
  546. if (ret < 0)
  547. {
  548. // Handle parsing errors
  549. FURI_LOG_E("JSMM.H", "Failed to parse JSON: %d", ret);
  550. free(tokens);
  551. return NULL;
  552. }
  553. // Ensure that the root element is an object
  554. if (ret < 1 || tokens[0].type != JSMN_OBJECT)
  555. {
  556. FURI_LOG_E("JSMM.H", "Root element is not an object.");
  557. free(tokens);
  558. return NULL;
  559. }
  560. // Loop through the tokens to find the key
  561. for (int i = 1; i < ret; i++)
  562. {
  563. if (jsoneq(json_data, &tokens[i], key) == 0)
  564. {
  565. // We found the key. Now, return the associated value.
  566. int length = tokens[i + 1].end - tokens[i + 1].start;
  567. char *value = malloc(length + 1);
  568. if (value == NULL)
  569. {
  570. FURI_LOG_E("JSMM.H", "Failed to allocate memory for value.");
  571. free(tokens);
  572. return NULL;
  573. }
  574. strncpy(value, json_data + tokens[i + 1].start, length);
  575. value[length] = '\0'; // Null-terminate the string
  576. free(tokens); // Free the token array
  577. return value; // Return the extracted value
  578. }
  579. }
  580. // Free the token array if key was not found
  581. free(tokens);
  582. }
  583. else
  584. {
  585. FURI_LOG_E("JSMM.H", "JSON data is NULL");
  586. }
  587. FURI_LOG_E("JSMM.H", "Failed to find the key in the JSON.");
  588. return NULL; // Return NULL if something goes wrong
  589. }
  590. // Revised get_json_array_value function
  591. char *get_json_array_value(char *key, uint32_t index, char *json_data, uint32_t max_tokens)
  592. {
  593. // Retrieve the array string for the given key
  594. char *array_str = get_json_value(key, json_data, max_tokens);
  595. if (array_str == NULL)
  596. {
  597. FURI_LOG_E("JSMM.H", "Failed to get array for key: %s", key);
  598. return NULL;
  599. }
  600. // Initialize the JSON parser
  601. jsmn_parser parser;
  602. jsmn_init(&parser);
  603. // Allocate memory for JSON tokens
  604. jsmntok_t *tokens = malloc(sizeof(jsmntok_t) * max_tokens);
  605. if (tokens == NULL)
  606. {
  607. FURI_LOG_E("JSMM.H", "Failed to allocate memory for JSON tokens.");
  608. free(array_str);
  609. return NULL;
  610. }
  611. // Parse the JSON array
  612. int ret = jsmn_parse(&parser, array_str, strlen(array_str), tokens, max_tokens);
  613. if (ret < 0)
  614. {
  615. FURI_LOG_E("JSMM.H", "Failed to parse JSON array: %d", ret);
  616. free(tokens);
  617. free(array_str);
  618. return NULL;
  619. }
  620. // Ensure the root element is an array
  621. if (ret < 1 || tokens[0].type != JSMN_ARRAY)
  622. {
  623. FURI_LOG_E("JSMM.H", "Value for key '%s' is not an array.", key);
  624. free(tokens);
  625. free(array_str);
  626. return NULL;
  627. }
  628. // Check if the index is within bounds
  629. if (index >= (uint32_t)tokens[0].size)
  630. {
  631. FURI_LOG_E("JSMM.H", "Index %lu out of bounds for array with size %d.", (unsigned long)index, tokens[0].size);
  632. free(tokens);
  633. free(array_str);
  634. return NULL;
  635. }
  636. // Locate the token corresponding to the desired array element
  637. int current_token = 1; // Start after the array token
  638. for (uint32_t i = 0; i < index; i++)
  639. {
  640. if (tokens[current_token].type == JSMN_OBJECT)
  641. {
  642. // For objects, skip all key-value pairs
  643. current_token += 1 + 2 * tokens[current_token].size;
  644. }
  645. else if (tokens[current_token].type == JSMN_ARRAY)
  646. {
  647. // For nested arrays, skip all elements
  648. current_token += 1 + tokens[current_token].size;
  649. }
  650. else
  651. {
  652. // For primitive types, simply move to the next token
  653. current_token += 1;
  654. }
  655. // Safety check to prevent out-of-bounds
  656. if (current_token >= ret)
  657. {
  658. FURI_LOG_E("JSMM.H", "Unexpected end of tokens while traversing array.");
  659. free(tokens);
  660. free(array_str);
  661. return NULL;
  662. }
  663. }
  664. // Extract the array element
  665. jsmntok_t element = tokens[current_token];
  666. int length = element.end - element.start;
  667. char *value = malloc(length + 1);
  668. if (value == NULL)
  669. {
  670. FURI_LOG_E("JSMM.H", "Failed to allocate memory for array element.");
  671. free(tokens);
  672. free(array_str);
  673. return NULL;
  674. }
  675. // Copy the element value to a new string
  676. strncpy(value, array_str + element.start, length);
  677. value[length] = '\0'; // Null-terminate the string
  678. // Clean up
  679. free(tokens);
  680. free(array_str);
  681. return value;
  682. }
  683. // Revised get_json_array_values function with correct token skipping
  684. char **get_json_array_values(char *key, char *json_data, uint32_t max_tokens, int *num_values)
  685. {
  686. // Retrieve the array string for the given key
  687. char *array_str = get_json_value(key, json_data, max_tokens);
  688. if (array_str == NULL)
  689. {
  690. FURI_LOG_E("JSMM.H", "Failed to get array for key: %s", key);
  691. return NULL;
  692. }
  693. // Initialize the JSON parser
  694. jsmn_parser parser;
  695. jsmn_init(&parser);
  696. // Allocate memory for JSON tokens
  697. jsmntok_t *tokens = malloc(sizeof(jsmntok_t) * max_tokens); // Allocate on the heap
  698. if (tokens == NULL)
  699. {
  700. FURI_LOG_E("JSMM.H", "Failed to allocate memory for JSON tokens.");
  701. free(array_str);
  702. return NULL;
  703. }
  704. // Parse the JSON array
  705. int ret = jsmn_parse(&parser, array_str, strlen(array_str), tokens, max_tokens);
  706. if (ret < 0)
  707. {
  708. FURI_LOG_E("JSMM.H", "Failed to parse JSON array: %d", ret);
  709. free(tokens);
  710. free(array_str);
  711. return NULL;
  712. }
  713. // Ensure the root element is an array
  714. if (tokens[0].type != JSMN_ARRAY)
  715. {
  716. FURI_LOG_E("JSMM.H", "Value for key '%s' is not an array.", key);
  717. free(tokens);
  718. free(array_str);
  719. return NULL;
  720. }
  721. // Allocate memory for the array of values (maximum possible)
  722. int array_size = tokens[0].size;
  723. char **values = malloc(array_size * sizeof(char *));
  724. if (values == NULL)
  725. {
  726. FURI_LOG_E("JSMM.H", "Failed to allocate memory for array of values.");
  727. free(tokens);
  728. free(array_str);
  729. return NULL;
  730. }
  731. int actual_num_values = 0;
  732. // Traverse the array and extract all object values
  733. int current_token = 1; // Start after the array token
  734. for (int i = 0; i < array_size; i++)
  735. {
  736. if (current_token >= ret)
  737. {
  738. FURI_LOG_E("JSMM.H", "Unexpected end of tokens while traversing array.");
  739. break;
  740. }
  741. jsmntok_t element = tokens[current_token];
  742. if (element.type != JSMN_OBJECT)
  743. {
  744. FURI_LOG_E("JSMM.H", "Array element %d is not an object, skipping.", i);
  745. // Skip this element
  746. current_token += 1;
  747. continue;
  748. }
  749. int length = element.end - element.start;
  750. // Allocate a new string for the value and copy the data
  751. char *value = malloc(length + 1);
  752. if (value == NULL)
  753. {
  754. FURI_LOG_E("JSMM.H", "Failed to allocate memory for array element.");
  755. for (int j = 0; j < actual_num_values; j++)
  756. {
  757. free(values[j]);
  758. }
  759. free(values);
  760. free(tokens);
  761. free(array_str);
  762. return NULL;
  763. }
  764. strncpy(value, array_str + element.start, length);
  765. value[length] = '\0'; // Null-terminate the string
  766. values[actual_num_values] = value;
  767. actual_num_values++;
  768. // Skip all tokens related to this object to avoid misparsing
  769. current_token += 1 + (2 * element.size); // Each key-value pair consumes two tokens
  770. }
  771. *num_values = actual_num_values;
  772. // Reallocate the values array to actual_num_values if necessary
  773. if (actual_num_values < array_size)
  774. {
  775. char **reduced_values = realloc(values, actual_num_values * sizeof(char *));
  776. if (reduced_values != NULL)
  777. {
  778. values = reduced_values;
  779. }
  780. // Free the remaining values
  781. for (int i = actual_num_values; i < array_size; i++)
  782. {
  783. free(values[i]);
  784. }
  785. }
  786. // Clean up
  787. free(tokens);
  788. free(array_str);
  789. return values;
  790. }
  791. #endif /* JB_JSMN_EDIT */