You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
87 lines
2.8 KiB
87 lines
2.8 KiB
#include "json_flat.h" |
|
#include <string.h> |
|
|
|
#define SKIP_WS(p, end) while ((p) < (end) && (*(p) == ' ' || *(p) == '\t' || *(p) == '\n' || *(p) == '\r')) (p)++ |
|
#define CHECK(p, end) if ((p) >= (end)) return -1 |
|
|
|
static int json_read_string(const char** pp, const char* end, char* out, size_t out_sz) { |
|
const char* p = *pp; |
|
CHECK(p, end); |
|
if (*p != '"') return -1; p++; |
|
size_t n = 0; |
|
while (p < end && *p != '"') { |
|
char ch = *p; |
|
if (*p == '\\') { p++; CHECK(p, end); |
|
switch (*p) { |
|
case '"': ch = '"'; break; |
|
case '\\': ch = '\\'; break; |
|
case '/': ch = '/'; break; |
|
case 'n': ch = '\n'; break; |
|
case 'r': ch = '\r'; break; |
|
case 't': ch = '\t'; break; |
|
default: return -1; |
|
} |
|
} |
|
if (out && n < out_sz - 1) out[n++] = ch; |
|
p++; |
|
} |
|
CHECK(p, end); /* closing quote */ |
|
p++; |
|
if (out && n < out_sz) out[n] = '\0'; |
|
else if (out && out_sz > 0) out[out_sz - 1] = '\0'; |
|
*pp = p; |
|
return 0; |
|
} |
|
|
|
static int json_parse_pair(const char** pp, const char* end, |
|
json_flat_cb cb, void* arg) { |
|
const char* p = *pp; |
|
SKIP_WS(p, end); CHECK(p, end); |
|
if (*p == '}') { *pp = p; return 0; } |
|
|
|
char key[128], val[256]; |
|
if (json_read_string(&p, end, key, sizeof(key)) != 0) return -1; |
|
SKIP_WS(p, end); CHECK(p, end); |
|
if (*p != ':') return -1; p++; |
|
SKIP_WS(p, end); CHECK(p, end); |
|
if (json_read_string(&p, end, val, sizeof(val)) != 0) return -1; |
|
|
|
if (cb && cb(key, val, arg) != 0) { *pp = p; return 1; } |
|
|
|
SKIP_WS(p, end); CHECK(p, end); |
|
if (*p == ',') p++; |
|
|
|
*pp = p; |
|
return 0; |
|
} |
|
|
|
int json_flat_parse(const char* json, json_flat_cb cb, void* arg) { |
|
if (!json) return -1; |
|
const char* p = json, *end = json + strlen(json); |
|
SKIP_WS(p, end); CHECK(p, end); |
|
if (*p != '{') return -1; p++; |
|
|
|
for (;;) { |
|
int rc = json_parse_pair(&p, end, cb, arg); |
|
if (rc < 0) return -1; |
|
if (rc > 0) return 0; /* callback stopped */ |
|
SKIP_WS(p, end); CHECK(p, end); |
|
if (*p == '}') return 0; |
|
} |
|
} |
|
|
|
struct get_ctx { const char* key; char* out; size_t sz; int found; }; |
|
|
|
static int get_cb(const char* k, const char* v, void* arg) { |
|
struct get_ctx* g = (struct get_ctx*)arg; |
|
if (strcmp(k, g->key) == 0) { if (g->out) { size_t vl = strlen(v); |
|
size_t cp = vl < g->sz - 1 ? vl : g->sz - 1; memcpy(g->out, v, cp); g->out[cp] = '\0'; } |
|
g->found = 1; return 1; } |
|
return 0; |
|
} |
|
|
|
int json_flat_get(const char* json, const char* key, char* value_out, size_t value_sz) { |
|
struct get_ctx g = { key, value_out, value_sz, 0 }; |
|
if (json_flat_parse(json, get_cb, &g) != 0) return -1; |
|
return g.found ? 0 : -1; |
|
}
|
|
|