// by jeremie miller - 2014 // public domain or MIT license, contributions/improvements welcome via github at https://github.com/quartzjer/js0n #include // one strncmp() is used to do key comparison, and a strlen(key) if no len passed in // gcc started warning for the init syntax used here, is not helpful so don't generate the spam, supressing the warning is really inconsistently supported across versions #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) #pragma GCC diagnostic push #endif #pragma GCC diagnostic ignored "-Wunknown-pragmas" #pragma GCC diagnostic ignored "-Wpragmas" #pragma GCC diagnostic ignored "-Winitializer-overrides" #pragma GCC diagnostic ignored "-Woverride-init" // only at depth 1, track start pointers to match key/value #define PUSH(i) if(depth == 1) { if(!index) { val = cur+i; }else{ if(klen && index == 1) start = cur+i; else index--; } } // determine if key matches or value is complete #define CAP(i) if(depth == 1) { if(val && !index) {*vlen = (size_t)((cur+i+1) - val); return val;}; if(klen && start) {index = (klen == (size_t)(cur-start) && strncmp(key,start,klen)==0) ? 0 : 2; start = 0;} } // this makes a single pass across the json bytes, using each byte as an index into a jump table to build an index and transition state const char *js0n(const char *key, size_t klen, const char *json, size_t jlen, size_t *vlen) { const char *val = 0; const char *cur, *end, *start; size_t index = 1; int depth = 0; int utf8_remain = 0; static void *gostruct[] = { [0 ... 255] = &&l_bad, ['\t'] = &&l_loop, [' '] = &&l_loop, ['\r'] = &&l_loop, ['\n'] = &&l_loop, ['"'] = &&l_qup, [':'] = &&l_loop,[','] = &&l_loop, ['['] = &&l_up, [']'] = &&l_down, // tracking [] and {} individually would allow fuller validation but is really messy ['{'] = &&l_up, ['}'] = &&l_down, ['-'] = &&l_bare, [48 ... 57] = &&l_bare, // 0-9 [65 ... 90] = &&l_bare, // A-Z [97 ... 122] = &&l_bare // a-z }; static void *gobare[] = { [0 ... 31] = &&l_bad, [32 ... 126] = &&l_loop, // could be more pedantic/validation-checking ['\t'] = &&l_unbare, [' '] = &&l_unbare, ['\r'] = &&l_unbare, ['\n'] = &&l_unbare, [','] = &&l_unbare, [']'] = &&l_unbare, ['}'] = &&l_unbare, [':'] = &&l_unbare, [127 ... 255] = &&l_bad }; static void *gostring[] = { [0 ... 31] = &&l_bad, [127] = &&l_bad, [32 ... 126] = &&l_loop, ['\\'] = &&l_esc, ['"'] = &&l_qdown, [128 ... 191] = &&l_bad, [192 ... 223] = &&l_utf8_2, [224 ... 239] = &&l_utf8_3, [240 ... 247] = &&l_utf8_4, [248 ... 255] = &&l_bad }; static void *goutf8_continue[] = { [0 ... 127] = &&l_bad, [128 ... 191] = &&l_utf_continue, [192 ... 255] = &&l_bad }; static void *goesc[] = { [0 ... 255] = &&l_bad, ['"'] = &&l_unesc, ['\\'] = &&l_unesc, ['/'] = &&l_unesc, ['b'] = &&l_unesc, ['f'] = &&l_unesc, ['n'] = &&l_unesc, ['r'] = &&l_unesc, ['t'] = &&l_unesc, ['u'] = &&l_unesc }; void **go = gostruct; if(!json || jlen <= 0 || !vlen) return 0; *vlen = 0; // no key is array mode, klen provides requested index if(!key) { index = klen; klen = 0; }else{ if(klen <= 0) klen = strlen(key); // convenience } for(start=cur=json,end=cur+jlen; cur 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) #pragma GCC diagnostic pop #endif