123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- /*
- * jsonc.c
- *
- * Copyright (C) 2018 bzt (bztsrc@gitlab)
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * @brief Memory allocation-free, extremely fast JSON parser in pure ANSI C
- *
- */
- #include <stdlib.h>
- #include <string.h>
- #define JSON_MAXPATHLEVEL 32
- /**
- * jsonstr: zero terminated UTF-8 string
- * key: path to a value, like "0.6.0.1" or "result.items.0.name"
- * returns the value in a malloc'd string or NULL
- */
- __attribute_malloc__ char *json_get(const char *jsonstr, char *key)
- {
- char *m=key, *ret=NULL;
- unsigned char *c=(unsigned char*)jsonstr,*k[JSON_MAXPATHLEVEL+1];
- unsigned char *v,*s=NULL,*e=NULL;
- int l=0, j=1, i, n, x[JSON_MAXPATHLEVEL+1]={0};
- if(!jsonstr || !jsonstr[0] || !key) return NULL;
- while(1) {
- /* skip white spaces */
- while(*c && *c<=' ') c++;
- if(j) { j=0; k[l]=v=c; }
- switch(*c) {
- /* string literals */
- case '\"': c++; while(*c && *c!='\"'){if(*c=='\\'){c++;} c++;} break;
- /* field names */
- case ':': c++; while(*c && *c<=' ') { c++; } v=c--; break;
- /* control blocks */
- case 0: case ',': case '{': case '[': case '}': case ']':
- if(*v!=','&&*v!='{'&&*v!='['&&*v!=']'&&*v!='}') {
- /* skip index for topmost object */
- n=k[0][0]=='{'?1:0;
- /* match the path */
- m=key;
- for(i=n;i<=l && *m;i++) {
- if(i!=n) { if(*m=='.') m++; else break; }
- if(k[i][0]=='\"' && k[i]!=v && (*m<'0'||*m>'9')) {
- s=e=k[i]+1;
- while(*e&&*e!='\"') { if(*e=='\\') { e++; } e++; }
- if(memcmp(m,s,e-s)) break;
- m+=e-s;
- } else {
- if(atoi(m)!=x[i]) break;
- while(*m && *m!='.') m++;
- }
- }
- /* find start and end of the return value */
- if(!*m) {
- switch(*v) {
- case '\"':
- s=e=v+1;
- while(*e&&*e!='\"') { if(*e=='\\') { e++; } e++; }
- break;
- case 'n': return NULL;
- default:
- s=e=v;
- while(*e&&*e>' '&&*e!=','&&*e!=']'&&*e!='}') e++;
- break;
- }
- /* we can't break the loop inside a switch in ANSI C */
- goto end;
- }
- }
- switch(*c) {
- case 0: return NULL;
- case '{': case '[': x[++l]=0; if(l>=(int)sizeof(x)-1) return NULL; break;
- case '}': case ']': l--; break;
- case ',': x[l]++; break;
- }
- j++;
- break;
- }
- c++;
- }
- /* copy a zero terminated string of the value if any */
- end:if(!*m && e>s) {
- ret=malloc(e-s+1);
- if(ret) { memcpy(ret,s,e-s); ret[e-s]=0; }
- }
- return ret;
- }
|