9#error "jsmn-find.h should be included after jsmn.h"
20typedef struct jsmnf_pair {
28 struct jsmnf_pair *fields;
39typedef struct jsmnf_loader {
49JSMN_API void jsmnf_init(jsmnf_loader *loader);
64JSMN_API int jsmnf_load(jsmnf_loader *loader,
81JSMN_API jsmnf_pair *jsmnf_find(
const jsmnf_pair *head,
96JSMN_API jsmnf_pair *jsmnf_find_path(
const jsmnf_pair *head,
118JSMN_API int jsmnf_load_auto(jsmnf_loader *loader,
122 jsmnf_pair **p_pairs,
123 unsigned *num_pairs);
141 unsigned *num_tokens);
153JSMN_API long jsmnf_unescape(
char buf[],
165#define CHASH_KEY_FIELD k
167#define CHASH_VALUE_FIELD v
169#define CHASH_BUCKETS_FIELD fields
171#define CHASH_LENGTH_FIELD size
175#define _jsmnf_key_hash(key, hash) \
178 unsigned __CHASH_HINDEX; \
179 for (__CHASH_HINDEX = 0; __CHASH_HINDEX < (key).len; \
180 ++__CHASH_HINDEX) { \
181 (hash) = (((hash) << 1) + (hash)) \
182 + _JSMNF_STRING_B[(key).pos + __CHASH_HINDEX]; \
187#define _jsmnf_key_compare(cmp_a, cmp_b) \
188 ((cmp_a).len == (cmp_b).len \
189 && !strncmp(_JSMNF_STRING_B + (cmp_a).pos, \
190 _JSMNF_STRING_A + (cmp_b).pos, (cmp_a).len))
192#define _JSMNF_TABLE_HEAP 0
193#define _JSMNF_TABLE_BUCKET struct jsmnf_pair
194#define _JSMNF_TABLE_FREE_KEY(_key)
195#define _JSMNF_TABLE_HASH(_key, _hash) _jsmnf_key_hash(_key, _hash)
196#define _JSMNF_TABLE_FREE_VALUE(_value)
197#define _JSMNF_TABLE_COMPARE(_cmp_a, _cmp_b) _jsmnf_key_compare(_cmp_a, _cmp_b)
198#define _JSMNF_TABLE_INIT(_bucket, _key, _value) \
199 chash_default_init(_bucket, _key, _value)
202jsmnf_init(jsmnf_loader *loader)
204 loader->pairnext = 0;
207#define _JSMNF_STRING_A js
208#define _JSMNF_STRING_B js
211_jsmnf_load_pairs(
struct jsmnf_loader *loader,
213 struct jsmnf_pair *curr,
216 struct jsmnf_pair *pairs,
221 if (!num_tokens)
return 0;
229 const unsigned top_idx = loader->pairnext + (1 + tok->
size),
230 bottom_idx = loader->pairnext;
233 if (tok->
size > (
int)(num_pairs - bottom_idx)
234 || top_idx > (num_pairs - bottom_idx))
239 loader->pairnext = top_idx;
245 while (curr->size < tok->
size) {
246 const struct jsmntok *_key = tok + 1 + offset;
247 struct jsmnftok key, value = { 0 };
249 key.pos = _key->
start;
256 if (_key->
size > 0) {
257 const struct jsmntok *_value = tok + 1 + offset;
258 struct jsmnf_pair *found = NULL;
260 value.pos = _value->
start;
261 value.len = _value->
end - _value->
start;
266 ret = _jsmnf_load_pairs(loader, js, found, _value,
267 num_tokens - offset, pairs,
269 if (ret < 0)
return ret;
279 for (; curr->size < tok->
size; ++curr->size) {
280 const struct jsmntok *_value = tok + 1 + offset;
281 struct jsmnf_pair *element = curr->fields + curr->
size;
282 struct jsmnftok value;
284 value.pos = _value->
start;
285 value.len = _value->
end - _value->
start;
294 ret = _jsmnf_load_pairs(loader, js, element, _value,
295 num_tokens - offset, pairs, num_pairs);
296 if (ret < 0)
return ret;
305 fputs(
"Error: JSMN_UNDEFINED token detected, jsmn_parse() failure\n",
310 curr->type = tok->
type;
315#undef _JSMNF_STRING_A
316#undef _JSMNF_STRING_B
319jsmnf_load(
struct jsmnf_loader *loader,
323 struct jsmnf_pair pairs[],
328 if (!loader->pairnext) {
329 static const struct jsmnf_pair blank_pair = { 0 };
332 for (; i < num_pairs; ++i)
333 pairs[i] = blank_pair;
335 pairs[0].v.pos = tokens->
start;
336 pairs[0].v.len = tokens->
end - tokens->
start;
341 ret = _jsmnf_load_pairs(loader, js, pairs, tokens, num_tokens, pairs,
346 if (ret < 0) loader->pairnext = 0;
350#define _JSMNF_STRING_A js
351#define _JSMNF_STRING_B key
354jsmnf_find(
const struct jsmnf_pair *head,
359 struct jsmnf_pair *found = NULL;
361 if (!key || !head)
return NULL;
364 struct jsmnftok _key;
377 int idx = (int)strtol(key, &endptr, 10);
378 if (endptr != key && idx < head->size) found = head->fields + idx;
383#undef _JSMNF_STRING_A
384#undef _JSMNF_STRING_B
387jsmnf_find_path(
const struct jsmnf_pair *head,
392 const struct jsmnf_pair *iter = head;
393 struct jsmnf_pair *found = NULL;
396 for (i = 0; i < depth; ++i) {
398 found = jsmnf_find(iter, js, path[i], strlen(path[i]));
405#define RECALLOC_OR_ERROR(ptr, prev_size) \
407 const unsigned new_size = *(prev_size)*2; \
408 void *tmp = realloc((ptr), new_size * sizeof *(ptr)); \
409 if (!tmp) return JSMN_ERROR_NOMEM; \
411 memset((ptr) + *(prev_size), 0, \
412 (new_size - *(prev_size)) * sizeof *(ptr)); \
413 *(prev_size) = new_size; \
421 unsigned *num_tokens)
425 if (NULL == *p_tokens || 0 == *num_tokens) {
426 *p_tokens = calloc(1,
sizeof **p_tokens);
430 == (ret =
jsmn_parse(parser, js, length, *p_tokens, *num_tokens)))
432 RECALLOC_OR_ERROR(*p_tokens, num_tokens);
438jsmnf_load_auto(
struct jsmnf_loader *loader,
442 struct jsmnf_pair **p_pairs,
447 if (NULL == *p_pairs || 0 == *num_pairs) {
448 *p_pairs = calloc(1,
sizeof **p_pairs);
452 == (ret = jsmnf_load(loader, js, tokens, num_tokens, *p_pairs,
455 RECALLOC_OR_ERROR(*p_pairs, num_pairs);
460#undef RECALLOC_OR_ERROR
463_jsmnf_read_4_digits(
char *s,
const char *end,
unsigned *p_hex)
470 for (i = 0; i < 4; i++) {
472 if ((
'0' <= s[i] && s[i] <=
'9') || (
'A' <= s[i] && s[i] <=
'F')
473 || (
'a' <= s[i] && s[i] <=
'f'))
480 *p_hex = (unsigned)strtoul(buf, NULL, 16);
485#define _JSMNF_UTF16_IS_FIRST_SURROGATE(c) \
486 (0xD800 <= (unsigned)c && (unsigned)c <= 0xDBFF)
487#define _JSMNF_UTF16_IS_SECOND_SURROGATE(c) \
488 (0xDC00 <= (unsigned)c && (unsigned)c <= 0xDFFF)
489#define _JSMNF_UTF16_JOIN_SURROGATE(c1, c2) \
490 (((((unsigned long)c1 & 0x3FF) << 10) | ((unsigned)c2 & 0x3FF)) + 0x10000)
491#define _JSMNF_UTF8_IS_VALID(c) \
492 (((unsigned long)c <= 0x10FFFF) \
493 && ((unsigned long)c < 0xD800 || (unsigned long)c > 0xDFFF))
494#define _JSMNF_UTF8_IS_TRAIL(c) (((unsigned char)c & 0xC0) == 0x80)
495#define _JSMNF_UTF_ILLEGAL 0xFFFFFFFFu
498_jsmnf_utf8_trail_length(
unsigned char c)
500 if (c < 128)
return 0;
501 if (c < 194)
return -1;
502 if (c < 224)
return 1;
503 if (c < 240)
return 2;
504 if (c <= 244)
return 3;
509_jsmnf_utf8_width(
unsigned long value)
511 if (value <= 0x7F)
return 1;
512 if (value <= 0x7FF)
return 2;
513 if (value <= 0xFFFF)
return 3;
520_jsmnf_utf8_next(
char **p,
const char *end)
522 unsigned char lead, tmp;
526 if (*p == end)
return _JSMNF_UTF_ILLEGAL;
532 trail_size = _jsmnf_utf8_trail_length(lead);
534 if (trail_size < 0)
return _JSMNF_UTF_ILLEGAL;
537 if (trail_size == 0)
return lead;
539 c = lead & ((1 << (6 - trail_size)) - 1);
542 switch (trail_size) {
544 if (*p == end)
return _JSMNF_UTF_ILLEGAL;
547 if (!_JSMNF_UTF8_IS_TRAIL(tmp))
return _JSMNF_UTF_ILLEGAL;
548 c = (c << 6) | (tmp & 0x3F);
551 if (*p == end)
return _JSMNF_UTF_ILLEGAL;
554 if (!_JSMNF_UTF8_IS_TRAIL(tmp))
return _JSMNF_UTF_ILLEGAL;
555 c = (c << 6) | (tmp & 0x3F);
558 if (*p == end)
return _JSMNF_UTF_ILLEGAL;
561 if (!_JSMNF_UTF8_IS_TRAIL(tmp))
return _JSMNF_UTF_ILLEGAL;
562 c = (c << 6) | (tmp & 0x3F);
566 if (!_JSMNF_UTF8_IS_VALID(c))
return _JSMNF_UTF_ILLEGAL;
569 if (_jsmnf_utf8_width(c) != trail_size + 1)
return _JSMNF_UTF_ILLEGAL;
575_jsmnf_utf8_validate(
char *p,
const char *end)
577 const char *start = p;
579 if (_jsmnf_utf8_next(&p, end) == _JSMNF_UTF_ILLEGAL)
582 return (
long)(end - start);
586_jsmnf_utf8_encode(
unsigned long value,
char utf8_seq[4])
592 if (value <= 0x7FF) {
593 utf8_seq[0] = (value >> 6) | 0xC0;
594 utf8_seq[1] = (value & 0x3F) | 0x80;
597 if (value <= 0xFFFF) {
598 utf8_seq[0] = (value >> 12) | 0xE0;
599 utf8_seq[1] = ((value >> 6) & 0x3F) | 0x80;
600 utf8_seq[2] = (value & 0x3F) | 0x80;
603 utf8_seq[0] = (value >> 18) | 0xF0;
604 utf8_seq[1] = ((value >> 12) & 0x3F) | 0x80;
605 utf8_seq[2] = ((value >> 6) & 0x3F) | 0x80;
606 utf8_seq[3] = (value & 0x3F) | 0x80;
611_jsmnf_utf8_append(
unsigned long hex,
char *buf_tok,
const char *buf_end)
614 unsigned utf8_seqlen = _jsmnf_utf8_encode(hex, utf8_seq);
619 for (i = 0; i < utf8_seqlen; ++i)
620 buf_tok[i] = utf8_seq[i];
624#define BUF_PUSH(buf_tok, c, buf_end) \
626 if (buf_tok >= buf_end) return JSMN_ERROR_NOMEM; \
631jsmnf_unescape(
char buf[],
size_t bufsize,
const char src[],
size_t len)
633 char *src_tok = (
char *)src, *
const src_end = src_tok + len;
634 char *buf_tok = buf, *
const buf_end = buf + bufsize;
635 int second_surrogate_expected = 0;
636 unsigned first_surrogate = 0;
638 while (*src_tok && src_tok < src_end) {
645 BUF_PUSH(buf_tok, c, buf_end);
660 BUF_PUSH(buf_tok, c, buf_end);
663 BUF_PUSH(buf_tok,
'\b', buf_end);
666 BUF_PUSH(buf_tok,
'\f', buf_end);
669 BUF_PUSH(buf_tok,
'\n', buf_end);
672 BUF_PUSH(buf_tok,
'\r', buf_end);
675 BUF_PUSH(buf_tok,
'\t', buf_end);
679 int ret = _jsmnf_read_4_digits(src_tok, src_end, &hex);
681 if (ret != 4)
return ret;
685 if (second_surrogate_expected) {
686 if (!_JSMNF_UTF16_IS_SECOND_SURROGATE(hex))
689 ret = _jsmnf_utf8_append(
690 _JSMNF_UTF16_JOIN_SURROGATE(first_surrogate, hex), buf_tok,
692 if (ret < 0)
return ret;
696 second_surrogate_expected = 0;
698 else if (_JSMNF_UTF16_IS_FIRST_SURROGATE(hex)) {
699 second_surrogate_expected = 1;
700 first_surrogate = hex;
703 ret = _jsmnf_utf8_append(hex, buf_tok, buf_end);
704 if (ret < 0)
return ret;
713 return _jsmnf_utf8_validate(buf, buf_tok);
#define chash_init_stack(hashtable, buffer, _length, namespace)
Definition: chash.h:282
#define chash_contains(hashtable, _key, storage, namespace)
Definition: chash.h:378
#define CHASH_FILLED
Definition: chash.h:104
#define chash_lookup_bucket(hashtable, _key, storage, namespace)
Definition: chash.h:396
#define chash_assign(hashtable, _key, _value, namespace)
Definition: chash.h:297
jsmntype_t
Definition: jsmn.h:46
@ JSMN_PRIMITIVE
Definition: jsmn.h:51
@ JSMN_OBJECT
Definition: jsmn.h:48
@ JSMN_UNDEFINED
Definition: jsmn.h:47
@ JSMN_ARRAY
Definition: jsmn.h:49
@ JSMN_STRING
Definition: jsmn.h:50
#define JSMN_API
Definition: jsmn.h:36
int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len, jsmntok_t *tokens, const unsigned int num_tokens)
Definition: jsmn.h:268
@ JSMN_ERROR_INVAL
Definition: jsmn.h:58
@ JSMN_ERROR_PART
Definition: jsmn.h:60
@ JSMN_ERROR_NOMEM
Definition: jsmn.h:56
int end
Definition: jsmn.h:72
int size
Definition: jsmn.h:73
int start
Definition: jsmn.h:71
jsmntype_t type
Definition: jsmn.h:70