jsmn.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. #include "jsmn.h"
  2. /**
  3. * Allocates a fresh unused token from the token pull.
  4. */
  5. static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
  6. jsmntok_t *tokens, size_t num_tokens) {
  7. jsmntok_t *tok;
  8. if (parser->toknext >= num_tokens) {
  9. return NULL;
  10. }
  11. tok = &tokens[parser->toknext++];
  12. tok->start = tok->end = -1;
  13. tok->size = 0;
  14. #ifdef JSMN_PARENT_LINKS
  15. tok->parent = -1;
  16. #endif
  17. return tok;
  18. }
  19. /**
  20. * Fills token type and boundaries.
  21. */
  22. static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
  23. int start, int end) {
  24. token->type = type;
  25. token->start = start;
  26. token->end = end;
  27. token->size = 0;
  28. }
  29. /**
  30. * Fills next available token with JSON primitive.
  31. */
  32. static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
  33. size_t len, jsmntok_t *tokens, size_t num_tokens) {
  34. jsmntok_t *token;
  35. int start;
  36. start = parser->pos;
  37. for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
  38. switch (js[parser->pos]) {
  39. #ifndef JSMN_STRICT
  40. /* In strict mode primitive must be followed by "," or "}" or "]" */
  41. case ':':
  42. #endif
  43. case '\t' : case '\r' : case '\n' : case ' ' :
  44. case ',' : case ']' : case '}' :
  45. goto found;
  46. }
  47. if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
  48. parser->pos = start;
  49. return JSMN_ERROR_INVAL;
  50. }
  51. }
  52. #ifdef JSMN_STRICT
  53. /* In strict mode primitive must be followed by a comma/object/array */
  54. parser->pos = start;
  55. return JSMN_ERROR_PART;
  56. #endif
  57. found:
  58. if (tokens == NULL) {
  59. parser->pos--;
  60. return 0;
  61. }
  62. token = jsmn_alloc_token(parser, tokens, num_tokens);
  63. if (token == NULL) {
  64. parser->pos = start;
  65. return JSMN_ERROR_NOMEM;
  66. }
  67. jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
  68. #ifdef JSMN_PARENT_LINKS
  69. token->parent = parser->toksuper;
  70. #endif
  71. parser->pos--;
  72. return 0;
  73. }
  74. /**
  75. * Fills next token with JSON string.
  76. */
  77. static int jsmn_parse_string(jsmn_parser *parser, const char *js,
  78. size_t len, jsmntok_t *tokens, size_t num_tokens) {
  79. jsmntok_t *token;
  80. int start = parser->pos;
  81. parser->pos++;
  82. /* Skip starting quote */
  83. for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
  84. char c = js[parser->pos];
  85. /* Quote: end of string */
  86. if (c == '\"') {
  87. if (tokens == NULL) {
  88. return 0;
  89. }
  90. token = jsmn_alloc_token(parser, tokens, num_tokens);
  91. if (token == NULL) {
  92. parser->pos = start;
  93. return JSMN_ERROR_NOMEM;
  94. }
  95. jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
  96. #ifdef JSMN_PARENT_LINKS
  97. token->parent = parser->toksuper;
  98. #endif
  99. return 0;
  100. }
  101. /* Backslash: Quoted symbol expected */
  102. if (c == '\\' && parser->pos + 1 < len) {
  103. int i;
  104. parser->pos++;
  105. switch (js[parser->pos]) {
  106. /* Allowed escaped symbols */
  107. case '\"': case '/' : case '\\' : case 'b' :
  108. case 'f' : case 'r' : case 'n' : case 't' :
  109. break;
  110. /* Allows escaped symbol \uXXXX */
  111. case 'u':
  112. parser->pos++;
  113. for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
  114. /* If it isn't a hex character we have an error */
  115. if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
  116. (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
  117. (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
  118. parser->pos = start;
  119. return JSMN_ERROR_INVAL;
  120. }
  121. parser->pos++;
  122. }
  123. parser->pos--;
  124. break;
  125. /* Unexpected symbol */
  126. default:
  127. parser->pos = start;
  128. return JSMN_ERROR_INVAL;
  129. }
  130. }
  131. }
  132. parser->pos = start;
  133. return JSMN_ERROR_PART;
  134. }
  135. /**
  136. * Parse JSON string and fill tokens.
  137. */
  138. int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
  139. jsmntok_t *tokens, unsigned int num_tokens) {
  140. int r;
  141. int i;
  142. jsmntok_t *token;
  143. int count = parser->toknext;
  144. for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
  145. char c;
  146. jsmntype_t type;
  147. c = js[parser->pos];
  148. switch (c) {
  149. case '{': case '[':
  150. count++;
  151. if (tokens == NULL) {
  152. break;
  153. }
  154. token = jsmn_alloc_token(parser, tokens, num_tokens);
  155. if (token == NULL)
  156. return JSMN_ERROR_NOMEM;
  157. if (parser->toksuper != -1) {
  158. tokens[parser->toksuper].size++;
  159. #ifdef JSMN_PARENT_LINKS
  160. token->parent = parser->toksuper;
  161. #endif
  162. }
  163. token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
  164. token->start = parser->pos;
  165. parser->toksuper = parser->toknext - 1;
  166. break;
  167. case '}': case ']':
  168. if (tokens == NULL)
  169. break;
  170. type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
  171. #ifdef JSMN_PARENT_LINKS
  172. if (parser->toknext < 1) {
  173. return JSMN_ERROR_INVAL;
  174. }
  175. token = &tokens[parser->toknext - 1];
  176. for (;;) {
  177. if (token->start != -1 && token->end == -1) {
  178. if (token->type != type) {
  179. return JSMN_ERROR_INVAL;
  180. }
  181. token->end = parser->pos + 1;
  182. parser->toksuper = token->parent;
  183. break;
  184. }
  185. if (token->parent == -1) {
  186. break;
  187. }
  188. token = &tokens[token->parent];
  189. }
  190. #else
  191. for (i = parser->toknext - 1; i >= 0; i--) {
  192. token = &tokens[i];
  193. if (token->start != -1 && token->end == -1) {
  194. if (token->type != type) {
  195. return JSMN_ERROR_INVAL;
  196. }
  197. parser->toksuper = -1;
  198. token->end = parser->pos + 1;
  199. break;
  200. }
  201. }
  202. /* Error if unmatched closing bracket */
  203. if (i == -1) return JSMN_ERROR_INVAL;
  204. for (; i >= 0; i--) {
  205. token = &tokens[i];
  206. if (token->start != -1 && token->end == -1) {
  207. parser->toksuper = i;
  208. break;
  209. }
  210. }
  211. #endif
  212. break;
  213. case '\"':
  214. r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
  215. if (r < 0) return r;
  216. count++;
  217. if (parser->toksuper != -1 && tokens != NULL)
  218. tokens[parser->toksuper].size++;
  219. break;
  220. case '\t' : case '\r' : case '\n' : case ' ':
  221. break;
  222. case ':':
  223. parser->toksuper = parser->toknext - 1;
  224. break;
  225. case ',':
  226. if (tokens != NULL && parser->toksuper != -1 &&
  227. tokens[parser->toksuper].type != JSMN_ARRAY &&
  228. tokens[parser->toksuper].type != JSMN_OBJECT) {
  229. #ifdef JSMN_PARENT_LINKS
  230. parser->toksuper = tokens[parser->toksuper].parent;
  231. #else
  232. for (i = parser->toknext - 1; i >= 0; i--) {
  233. if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
  234. if (tokens[i].start != -1 && tokens[i].end == -1) {
  235. parser->toksuper = i;
  236. break;
  237. }
  238. }
  239. }
  240. #endif
  241. }
  242. break;
  243. #ifdef JSMN_STRICT
  244. /* In strict mode primitives are: numbers and booleans */
  245. case '-': case '0': case '1' : case '2': case '3' : case '4':
  246. case '5': case '6': case '7' : case '8': case '9':
  247. case 't': case 'f': case 'n' :
  248. /* And they must not be keys of the object */
  249. if (tokens != NULL && parser->toksuper != -1) {
  250. jsmntok_t *t = &tokens[parser->toksuper];
  251. if (t->type == JSMN_OBJECT ||
  252. (t->type == JSMN_STRING && t->size != 0)) {
  253. return JSMN_ERROR_INVAL;
  254. }
  255. }
  256. #else
  257. /* In non-strict mode every unquoted value is a primitive */
  258. default:
  259. #endif
  260. r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
  261. if (r < 0) return r;
  262. count++;
  263. if (parser->toksuper != -1 && tokens != NULL)
  264. tokens[parser->toksuper].size++;
  265. break;
  266. #ifdef JSMN_STRICT
  267. /* Unexpected char in strict mode */
  268. default:
  269. return JSMN_ERROR_INVAL;
  270. #endif
  271. }
  272. }
  273. if (tokens != NULL) {
  274. for (i = parser->toknext - 1; i >= 0; i--) {
  275. /* Unmatched opened object or array */
  276. if (tokens[i].start != -1 && tokens[i].end == -1) {
  277. return JSMN_ERROR_PART;
  278. }
  279. }
  280. }
  281. return count;
  282. }
  283. /**
  284. * Creates a new parser based over a given buffer with an array of tokens
  285. * available.
  286. */
  287. void jsmn_init(jsmn_parser *parser) {
  288. parser->pos = 0;
  289. parser->toknext = 0;
  290. parser->toksuper = -1;
  291. }
  292. /**
  293. * Compare a token string with a token, returns the token value
  294. */
  295. int jsoneq(const char *json, jsmntok_t *tok, const char *s) {
  296. if (tok->type == JSMN_STRING && (int) strlen(s) == tok->end - tok->start &&
  297. strncmp(json + tok->start, s, tok->end - tok->start) == 0) {
  298. return 0;
  299. }
  300. return -1;
  301. }