123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511 |
- #ifndef _XS_JSON_H
- #define _XS_JSON_H
- xs_str *xs_json_dumps_pp(const xs_val *data, int indent);
- #define xs_json_dumps(data) xs_json_dumps_pp(data, 0)
- xs_val *xs_json_loads(const xs_str *json);
- #ifdef XS_IMPLEMENTATION
- static xs_str *_xs_json_dumps_str(xs_str *s, const char *data)
- {
- unsigned char c;
- s = xs_str_cat(s, "\"");
- while ((c = *data)) {
- if (c == '\n')
- s = xs_str_cat(s, "\\n");
- else
- if (c == '\r')
- s = xs_str_cat(s, "\\r");
- else
- if (c == '\t')
- s = xs_str_cat(s, "\\t");
- else
- if (c == '\\')
- s = xs_str_cat(s, "\\\\");
- else
- if (c == '"')
- s = xs_str_cat(s, "\\\"");
- else
- if (c < 32) {
- char tmp[10];
- snprintf(tmp, sizeof(tmp), "\\u%04x", (unsigned int) c);
- s = xs_str_cat(s, tmp);
- }
- else
- s = xs_append_m(s, data, 1);
- data++;
- }
- s = xs_str_cat(s, "\"");
- return s;
- }
- static xs_str *_xs_json_indent(xs_str *s, int level, int indent)
- {
- if (indent) {
- int n;
- s = xs_str_cat(s, "\n");
- for (n = 0; n < level * indent; n++)
- s = xs_str_cat(s, " ");
- }
- return s;
- }
- static xs_str *_xs_json_dumps(xs_str *s, const xs_val *s_data, int level, int indent)
- {
- int c = 0;
- xs_val *v;
- xs_val *data = (xs_val *)s_data;
- switch (xs_type(data)) {
- case XSTYPE_NULL:
- s = xs_str_cat(s, "null");
- break;
- case XSTYPE_TRUE:
- s = xs_str_cat(s, "true");
- break;
- case XSTYPE_FALSE:
- s = xs_str_cat(s, "false");
- break;
- case XSTYPE_NUMBER:
- s = xs_str_cat(s, xs_number_str(data));
- break;
- case XSTYPE_LIST:
- s = xs_str_cat(s, "[");
- while (xs_list_iter(&data, &v)) {
- if (c != 0)
- s = xs_str_cat(s, ",");
- s = _xs_json_indent(s, level + 1, indent);
- s = _xs_json_dumps(s, v, level + 1, indent);
- c++;
- }
- s = _xs_json_indent(s, level, indent);
- s = xs_str_cat(s, "]");
- break;
- case XSTYPE_DICT:
- s = xs_str_cat(s, "{");
- xs_str *k;
- while (xs_dict_iter(&data, &k, &v)) {
- if (c != 0)
- s = xs_str_cat(s, ",");
- s = _xs_json_indent(s, level + 1, indent);
- s = _xs_json_dumps_str(s, k);
- s = xs_str_cat(s, ":");
- if (indent)
- s = xs_str_cat(s, " ");
- s = _xs_json_dumps(s, v, level + 1, indent);
- c++;
- }
- s = _xs_json_indent(s, level, indent);
- s = xs_str_cat(s, "}");
- break;
- case XSTYPE_STRING:
- s = _xs_json_dumps_str(s, data);
- break;
- default:
- break;
- }
- return s;
- }
- xs_str *xs_json_dumps_pp(const xs_val *data, int indent)
- {
- xstype t = xs_type(data);
- xs_str *s = NULL;
- if (t == XSTYPE_LIST || t == XSTYPE_DICT) {
- s = xs_str_new(NULL);
- s = _xs_json_dumps(s, data, 0, indent);
- }
- return s;
- }
- typedef enum {
- JS_ERROR = -1,
- JS_INCOMPLETE,
- JS_OCURLY,
- JS_OBRACK,
- JS_CCURLY,
- JS_CBRACK,
- JS_COMMA,
- JS_COLON,
- JS_VALUE,
- JS_STRING,
- JS_INTEGER,
- JS_REAL,
- JS_TRUE,
- JS_FALSE,
- JS_NULL,
- JS_ARRAY,
- JS_OBJECT
- } js_type;
- static xs_val *_xs_json_loads_lexer(const char **json, js_type *t)
- {
- char c;
- const char *s = *json;
- xs_val *v = NULL;
-
- while (*s == L' ' || *s == L'\t' || *s == L'\n' || *s == L'\r')
- s++;
- c = *s++;
- if (c == '{')
- *t = JS_OCURLY;
- else
- if (c == '}')
- *t = JS_CCURLY;
- else
- if (c == '[')
- *t = JS_OBRACK;
- else
- if (c == ']')
- *t = JS_CBRACK;
- else
- if (c == ',')
- *t = JS_COMMA;
- else
- if (c == ':')
- *t = JS_COLON;
- else
- if (c == '"') {
- *t = JS_STRING;
- v = xs_str_new(NULL);
- while ((c = *s) != '"' && c != '\0') {
- char tmp[5];
- int cp, i;
- if (c == '\\') {
- s++;
- c = *s;
- switch (c) {
- case 'n': c = '\n'; break;
- case 'r': c = '\r'; break;
- case 't': c = '\t'; break;
- case 'u':
- s++;
- memcpy(tmp, s, 4);
- s += 3;
- tmp[4] = '\0';
- sscanf(tmp, "%04x", &i);
- if (i >= 0xd800 && i <= 0xdfff) {
-
- cp = (i & 0x3ff) << 10;
-
- s += 3;
- memcpy(tmp, s, 4);
- s += 3;
- sscanf(tmp, "%04x", &i);
- cp |= (i & 0x3ff);
- cp += 0x10000;
- }
- else
- cp = i;
-
- if (cp >= '\0' && cp < ' ' && !strchr("\r\n\t", cp))
- cp += 0x2400;
- v = xs_utf8_enc(v, cp);
- c = '\0';
- break;
- }
- }
- if (c)
- v = xs_append_m(v, &c, 1);
- s++;
- }
- if (c != '\0')
- s++;
- }
- else
- if (c == '-' || (c >= '0' && c <= '9') || c == '.') {
- xs *vn = NULL;
- *t = JS_INTEGER;
- vn = xs_str_new(NULL);
- vn = xs_append_m(vn, &c, 1);
- while (((c = *s) >= '0' && c <= '9') || c == '.') {
- if (c == '.')
- *t = JS_REAL;
- vn = xs_append_m(vn, &c, 1);
- s++;
- }
-
- v = xs_number_new(atof(vn));
- }
- else
- if (c == 't' && strncmp(s, "rue", 3) == 0) {
- s += 3;
- *t = JS_TRUE;
- v = xs_val_new(XSTYPE_TRUE);
- }
- else
- if (c == 'f' && strncmp(s, "alse", 4) == 0) {
- s += 4;
- *t = JS_FALSE;
- v = xs_val_new(XSTYPE_FALSE);
- }
- else
- if (c == 'n' && strncmp(s, "ull", 3) == 0) {
- s += 3;
- *t = JS_NULL;
- v = xs_val_new(XSTYPE_NULL);
- }
- else
- *t = JS_ERROR;
- *json = s;
- return v;
- }
- static xs_list *_xs_json_loads_array(const char **json, js_type *t);
- static xs_dict *_xs_json_loads_object(const char **json, js_type *t);
- static xs_val *_xs_json_loads_value(const char **json, js_type *t, xs_val *v)
- {
- if (*t == JS_OBRACK)
- v = _xs_json_loads_array(json, t);
- else
- if (*t == JS_OCURLY)
- v = _xs_json_loads_object(json, t);
- if (*t >= JS_VALUE)
- *t = JS_VALUE;
- else
- *t = JS_ERROR;
- return v;
- }
- static xs_list *_xs_json_loads_array(const char **json, js_type *t)
- {
- const char *s = *json;
- xs *v;
- xs_list *l;
- js_type tt;
- l = xs_list_new();
- *t = JS_INCOMPLETE;
- v = _xs_json_loads_lexer(&s, &tt);
- if (tt == JS_CBRACK)
- *t = JS_ARRAY;
- else {
- v = _xs_json_loads_value(&s, &tt, v);
- if (tt == JS_VALUE) {
- l = xs_list_append(l, v);
- while (*t == JS_INCOMPLETE) {
- xs_free(_xs_json_loads_lexer(&s, &tt));
- if (tt == JS_CBRACK)
- *t = JS_ARRAY;
- else
- if (tt == JS_COMMA) {
- xs *v2;
- v2 = _xs_json_loads_lexer(&s, &tt);
- v2 = _xs_json_loads_value(&s, &tt, v2);
- if (tt == JS_VALUE)
- l = xs_list_append(l, v2);
- else
- *t = JS_ERROR;
- }
- else
- *t = JS_ERROR;
- }
- }
- else
- *t = JS_ERROR;
- }
- if (*t == JS_ERROR)
- l = xs_free(l);
- *json = s;
- return l;
- }
- static xs_dict *_xs_json_loads_object(const char **json, js_type *t)
- {
- const char *s = *json;
- xs *k1;
- xs_dict *d;
- js_type tt;
- d = xs_dict_new();
- *t = JS_INCOMPLETE;
- k1 = _xs_json_loads_lexer(&s, &tt);
- if (tt == JS_CCURLY)
- *t = JS_OBJECT;
- else
- if (tt == JS_STRING) {
- xs_free(_xs_json_loads_lexer(&s, &tt));
- if (tt == JS_COLON) {
- xs *v1;
- v1 = _xs_json_loads_lexer(&s, &tt);
- v1 = _xs_json_loads_value(&s, &tt, v1);
- if (tt == JS_VALUE) {
- d = xs_dict_append(d, k1, v1);
- while (*t == JS_INCOMPLETE) {
- xs_free(_xs_json_loads_lexer(&s, &tt));
- if (tt == JS_CCURLY)
- *t = JS_OBJECT;
- else
- if (tt == JS_COMMA) {
- xs *k = _xs_json_loads_lexer(&s, &tt);
- if (tt == JS_STRING) {
- xs_free(_xs_json_loads_lexer(&s, &tt));
- if (tt == JS_COLON) {
- xs *v;
- v = _xs_json_loads_lexer(&s, &tt);
- v = _xs_json_loads_value(&s, &tt, v);
- if (tt == JS_VALUE)
- d = xs_dict_append(d, k, v);
- else
- *t = JS_ERROR;
- }
- else
- *t = JS_ERROR;
- }
- else
- *t = JS_ERROR;
- }
- else
- *t = JS_ERROR;
- }
- }
- else
- *t = JS_ERROR;
- }
- else
- *t = JS_ERROR;
- }
- else
- *t = JS_ERROR;
- if (*t == JS_ERROR)
- d = xs_free(d);
- *json = s;
- return d;
- }
- xs_val *xs_json_loads(const xs_str *json)
- {
- xs_val *v = NULL;
- js_type t;
- xs_free(_xs_json_loads_lexer(&json, &t));
- if (t == JS_OBRACK)
- v = _xs_json_loads_array(&json, &t);
- else
- if (t == JS_OCURLY)
- v = _xs_json_loads_object(&json, &t);
- else
- t = JS_ERROR;
- return v;
- }
- #endif
- #endif
|