]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/lib/json.qc
Transifex autosync
[xonotic/xonotic-data.pk3dir.git] / qcsrc / lib / json.qc
index bb541ed74000e597d0f73e8e17307c22710b7a67..b477fe15e59124924662e4c463030ff7016ca94e 100644 (file)
@@ -17,6 +17,7 @@ bool _json_parse_value();
     bool _json_parse_null();
 bool _json_parse_string(bool add);
 bool _json_parse_number();
+    bool _json_parse_float();
     bool _json_parse_int();
 
 #define JSON_BEGIN() int __i = STRING_ITERATOR_SAVE(_json)
@@ -31,6 +32,7 @@ string _json_ns;
 // Current keys
 int _json_keys;
 
+ERASEABLE
 bool _json_parse_object() {
     JSON_BEGIN();
     if (STRING_ITERATOR_GET(_json) != '{') JSON_FAIL("expected '{'");
@@ -39,6 +41,7 @@ bool _json_parse_object() {
     JSON_END();
 }
 
+    ERASEABLE
     bool _json_parse_members() {
         JSON_BEGIN();
         for (;;) {
@@ -52,6 +55,7 @@ bool _json_parse_object() {
         JSON_END();
     }
 
+        ERASEABLE
         bool _json_parse_pair() {
             JSON_BEGIN();
             if (!_json_parse_string(false)) JSON_FAIL("expected string");
@@ -65,17 +69,23 @@ bool _json_parse_object() {
             JSON_END();
         }
 
+ERASEABLE
 bool _json_parse_array() {
     JSON_BEGIN();
     if (STRING_ITERATOR_GET(_json) != '[') JSON_FAIL("expected '['");
     int len = bufstr_add(_json_buffer, "0", 0);
-    bufstr_set(_json_buffer, len - 1, strcat(bufstr_get(_json_buffer, len - 1), ".length"));
-    int n = -1;
+    if (len) bufstr_set(_json_buffer, len - 1, strcat(bufstr_get(_json_buffer, len - 1), ".length"));
     bool required = false;
-    for (;;) {
-        bufstr_set(_json_buffer, len, ftos(++n));
-        if (!_json_parse_value()) if (required) JSON_FAIL("expected value"); else break;
-        bufstr_add(_json_buffer, strcat(_json_ns, ".", ftos(n)), 0);
+    for (int n = 0; ; n++) {
+        string key = ftos(n);
+        key = _json_ns ? strcat(_json_ns, ".", key) : key;
+        int it = bufstr_add(_json_buffer, key, 0);
+        bool ret = false; WITH(string, _json_ns, key, ret = _json_parse_value());
+        if (!ret) {
+            bufstr_free(_json_buffer, it);
+            if (required) JSON_FAIL("expected value"); else break;
+        }
+        bufstr_set(_json_buffer, len, ftos(n + 1));
         if (STRING_ITERATOR_PEEK(_json) == ',') {
             STRING_ITERATOR_NEXT(_json);
             required = true;
@@ -87,6 +97,7 @@ bool _json_parse_array() {
     JSON_END();
 }
 
+ERASEABLE
 bool _json_parse_value() {
     JSON_BEGIN();
     if (!(_json_parse_string(true)
@@ -99,6 +110,7 @@ bool _json_parse_value() {
     JSON_END();
 }
 
+    ERASEABLE
     bool _json_parse_true() {
         JSON_BEGIN();
         if (!(STRING_ITERATOR_GET(_json) == 't'
@@ -110,6 +122,7 @@ bool _json_parse_value() {
         JSON_END();
     }
 
+    ERASEABLE
     bool _json_parse_false() {
         JSON_BEGIN();
         if (!(STRING_ITERATOR_GET(_json) == 'f'
@@ -122,6 +135,7 @@ bool _json_parse_value() {
         JSON_END();
     }
 
+    ERASEABLE
     bool _json_parse_null() {
         JSON_BEGIN();
         if (!(STRING_ITERATOR_GET(_json) == 'n'
@@ -133,6 +147,7 @@ bool _json_parse_value() {
         JSON_END();
     }
 
+ERASEABLE
 bool _json_parse_string(bool add) {
     JSON_BEGIN();
     if (STRING_ITERATOR_GET(_json) != '"') JSON_FAIL("expected opening '\"'");
@@ -150,6 +165,8 @@ bool _json_parse_string(bool add) {
                 case '\\': esc = "\\"; break;
                 case 'n': esc = "\n"; break;
                 case 't': esc = "\t"; break;
+                case 'u': esc = "\\u"; break; // TODO
+                case '/': esc = "/"; break;
             }
             s = strcat(s, esc);
         } else {
@@ -162,12 +179,36 @@ bool _json_parse_string(bool add) {
     JSON_END();
 }
 
+ERASEABLE
 bool _json_parse_number() {
     JSON_BEGIN();
-    if (!_json_parse_int()) JSON_FAIL("expected number");
+    if (!(_json_parse_float() || _json_parse_int())) JSON_FAIL("expected number");
     JSON_END();
 }
 
+    ERASEABLE
+    bool _json_parse_float() {
+        JSON_BEGIN();
+        string s = "";
+        bool needdot = true;
+        for (int c; (c = STRING_ITERATOR_GET(_json)); ) {
+            if (!(c >= '0' && c <= '9')) {
+                if (c == '.' && needdot) {
+                    // fine
+                    needdot = false;
+                } else {
+                    STRING_ITERATOR_UNGET(_json);
+                    break;
+                }
+            }
+            s = strcat(s, chr2str(c));
+        }
+        if (s == "") JSON_FAIL("expected float");
+        bufstr_add(_json_buffer, s, 0);
+        JSON_END();
+    }
+
+    ERASEABLE
     bool _json_parse_int() {
         JSON_BEGIN();
         string s = "";
@@ -185,7 +226,8 @@ bool _json_parse_number() {
         JSON_END();
     }
 
-int json_parse(string in) {
+ERASEABLE
+int json_parse(string in, bool() func) {
     string trimmed = "";
     LABEL(trim) {
         int o = strstrofs(in, "\"", 0);
@@ -222,7 +264,7 @@ int json_parse(string in) {
 
     STRING_ITERATOR_SET(_json, trimmed, 0);
     _json_buffer = buf_create();
-    bool ret = _json_parse_object();
+    bool ret = func();
     if (!ret) {
         buf_del(_json_buffer);
         _json_buffer = -1;
@@ -230,6 +272,29 @@ int json_parse(string in) {
     return _json_buffer;
 }
 
+ERASEABLE
+string json_get(int buf, string key)
+{
+    for (int i = 1, n = buf_getsize(buf); i < n; i += 2) {
+        if (bufstr_get(buf, i) == key) return bufstr_get(buf, i + 1);
+    }
+    return string_null;
+}
+
+ERASEABLE
+void json_del(int buf)
+{
+    buf_del(buf);
+}
+
+ERASEABLE
+void json_dump(int buf)
+{
+    for (int i = 0, n = buf_getsize(buf); i < n; ++i) {
+        print(bufstr_get(buf, i), "\n");
+    }
+}
+
 #undef JSON_BEGIN
 #undef JSON_FAIL
 #undef JSON_END
@@ -244,10 +309,8 @@ TEST(json, Parse)
     \"m_obj\": { },\n\
     \"m_arr\": [ ]\n}"; // "
     print(s, "\n");
-    int buf = json_parse(s);
+    int buf = json_parse(s, _json_parse_object);
     EXPECT_NE(-1, buf);
-    for (int i = 0, n = buf_getsize(buf); i < n; ++i) {
-        print(bufstr_get(buf, i), "\n");
-    }
-       SUCCEED();
+    json_dump(buf);
+    SUCCEED();
 }