From cf1566e11647a3958cc7edc7dc308a764b463e72 Mon Sep 17 00:00:00 2001 From: cpq Date: Wed, 31 Aug 2022 17:59:04 +0100 Subject: [PATCH] Add more comments in json code --- mongoose.c | 51 +++++++++++++++++++-------------------------------- src/json.c | 46 +++++++++++++++++++++++----------------------- 2 files changed, 42 insertions(+), 55 deletions(-) diff --git a/mongoose.c b/mongoose.c index 8c6628d7..9e3bbabe 100644 --- a/mongoose.c +++ b/mongoose.c @@ -2475,26 +2475,17 @@ int mg_json_get(struct mg_str json, const char *path, int *toklen) { int len = (int) json.len; enum { S_VALUE, S_KEY, S_COLON, S_COMMA_OR_EOO } expecting = S_VALUE; unsigned char nesting[MG_JSON_MAX_DEPTH]; - int i, j = 0, depth = 0; - int pos = 1; // Current position in path + int i = 0; // Current offset in `s` + int j = 0; // Offset in `s` we're looking for (return value) + int depth = 0; // Current depth (nesting level) int ed = 0; // Expected depth + int pos = 1; // Current position in `path` int ci = -1, ei = -1; // Current and expected index in array if (path[0] != '$') return MG_JSON_INVALID; -#if 0 -#define MG_DBGP(x) \ - do { \ - printf("%c %.*s j=%d i=%d pos=%d depth=%d ed=%d ci=%d ei=%d\n", x, len, s, \ - j, i, pos, depth, ed, ci, ei); \ - } while (0) -#else -#define MG_DBGP(x) -#endif - #define MG_CHECKRET(x) \ do { \ - MG_DBGP(x); \ if (depth == ed && path[pos] == '\0' && ci == ei) { \ if (toklen) *toklen = i - j + 1; \ return j; \ @@ -2514,17 +2505,18 @@ int mg_json_get(struct mg_str json, const char *path, int *toklen) { for (i = 0; i < len; i++) { unsigned char c = ((unsigned char *) s)[i]; if (c == ' ' || c == '\t' || c == '\n' || c == '\r') continue; - MG_DBGP('-'); switch (expecting) { case S_VALUE: - if ( depth == ed && ei == ci && c != '[' && path[pos] == '[' ) return MG_JSON_NOT_FOUND; + if (depth == ed && ei == ci && c != '[' && path[pos] == '[') { + // Expecting array start, but got something else + return MG_JSON_NOT_FOUND; + } if (depth == ed) j = i; if (c == '{') { if (depth >= (int) sizeof(nesting)) return MG_JSON_TOO_DEEP; - if (depth == ed && (ci == ei || ci < 0) && path[pos] == '.') { - ed++, pos++; - ci = -1; - ei = -1; + if (depth == ed && path[pos] == '.' && (ci == ei || ci < 0)) { + // If we start the object, reset array indices + ed++, pos++, ci = ei = -1; } nesting[depth++] = c; expecting = S_KEY; @@ -2542,7 +2534,7 @@ int mg_json_get(struct mg_str json, const char *path, int *toklen) { nesting[depth++] = c; break; } else if (c == ']' && depth > 0) { // Empty array - if (depth == ed) ci = -1; + if (depth == ed) ci = -1; // Array ends. Reset current index MG_EOO(']'); } else if (c == 't' && i + 3 < len && memcmp(&s[i], "true", 4) == 0) { i += 3; @@ -2566,20 +2558,20 @@ int mg_json_get(struct mg_str json, const char *path, int *toklen) { ci++; if (ci > ei) return MG_JSON_NOT_FOUND; } - expecting = S_COMMA_OR_EOO; break; case S_KEY: if (c == '"') { int n = mg_pass_string(&s[i + 1], len - i - 1); - // printf("K %s %d %d %d [%.*s]\n", path, pos, n, i, n + 2, s + i); + // printf("K1 %s %d %d %d [%.*s]\n", path, pos, n, i, n + 2, s + i); if (n < 0) return n; if (i + 1 + n >= len) return MG_JSON_NOT_FOUND; - // printf("K %s [%.*s] %d %d %d\n", path, n, &s[i + 1], n, depth, ed); - // NOTE(cpq): in the check sequence below is important. - // strncmp() must go first: it fails fast if the remaining length of - // the path is smaller than `n`. + // printf("K2 %s [%.*s] %d %d %d\n", path, n, &s[i + 1], n, depth, + // ed); + // NOTE(cpq): in the check sequence below is important. + // strncmp() must go first: it fails fast if the remaining length of + // the path is smaller than `n`. if (depth == ed && path[pos - 1] == '.' && strncmp(&s[i + 1], &path[pos], (size_t) n) == 0 && (path[pos + n] == '\0' || path[pos + n] == '.' || @@ -2609,19 +2601,14 @@ int mg_json_get(struct mg_str json, const char *path, int *toklen) { return MG_JSON_INVALID; } else if (c == ',') { expecting = (nesting[depth - 1] == '{') ? S_KEY : S_VALUE; - // MG_CHECKRET('C'); } else if (c == ']' || c == '}') { MG_EOO('O'); - if (depth == ed && ei >= 0) { - ci++; - if (ci > ei) return MG_JSON_NOT_FOUND; - } + if (depth == ed && ei >= 0) ci++; } else { return MG_JSON_INVALID; } break; } - MG_DBGP('E'); } return MG_JSON_NOT_FOUND; } diff --git a/src/json.c b/src/json.c index 1565e02f..85b46b73 100644 --- a/src/json.c +++ b/src/json.c @@ -79,26 +79,17 @@ int mg_json_get(struct mg_str json, const char *path, int *toklen) { int len = (int) json.len; enum { S_VALUE, S_KEY, S_COLON, S_COMMA_OR_EOO } expecting = S_VALUE; unsigned char nesting[MG_JSON_MAX_DEPTH]; - int i, j = 0, depth = 0; - int pos = 1; // Current position in path + int i = 0; // Current offset in `s` + int j = 0; // Offset in `s` we're looking for (return value) + int depth = 0; // Current depth (nesting level) int ed = 0; // Expected depth + int pos = 1; // Current position in `path` int ci = -1, ei = -1; // Current and expected index in array if (path[0] != '$') return MG_JSON_INVALID; -#if 0 -#define MG_DBGP(x) \ - do { \ - printf("%c %.*s j=%d i=%d pos=%d depth=%d ed=%d ci=%d ei=%d\n", x, len, s, \ - j, i, pos, depth, ed, ci, ei); \ - } while (0) -#else -#define MG_DBGP(x) -#endif - #define MG_CHECKRET(x) \ do { \ - MG_DBGP(x); \ if (depth == ed && path[pos] == '\0' && ci == ei) { \ if (toklen) *toklen = i - j + 1; \ return j; \ @@ -118,13 +109,19 @@ int mg_json_get(struct mg_str json, const char *path, int *toklen) { for (i = 0; i < len; i++) { unsigned char c = ((unsigned char *) s)[i]; if (c == ' ' || c == '\t' || c == '\n' || c == '\r') continue; - MG_DBGP('-'); switch (expecting) { case S_VALUE: + if (depth == ed && ei == ci && c != '[' && path[pos] == '[') { + // Expecting array start, but got something else + return MG_JSON_NOT_FOUND; + } if (depth == ed) j = i; if (c == '{') { if (depth >= (int) sizeof(nesting)) return MG_JSON_TOO_DEEP; - if (depth == ed && path[pos] == '.') ed++, pos++; + if (depth == ed && path[pos] == '.' && (ci == ei || ci < 0)) { + // If we start the object, reset array indices + ed++, pos++, ci = ei = -1; + } nesting[depth++] = c; expecting = S_KEY; break; @@ -141,6 +138,7 @@ int mg_json_get(struct mg_str json, const char *path, int *toklen) { nesting[depth++] = c; break; } else if (c == ']' && depth > 0) { // Empty array + if (depth == ed) ci = -1; // Array ends. Reset current index MG_EOO(']'); } else if (c == 't' && i + 3 < len && memcmp(&s[i], "true", 4) == 0) { i += 3; @@ -160,20 +158,24 @@ int mg_json_get(struct mg_str json, const char *path, int *toklen) { return MG_JSON_INVALID; } MG_CHECKRET('V'); - if (depth == ed && ei >= 0) ci++; + if (depth == ed && ei >= 0) { + ci++; + if (ci > ei) return MG_JSON_NOT_FOUND; + } expecting = S_COMMA_OR_EOO; break; case S_KEY: if (c == '"') { int n = mg_pass_string(&s[i + 1], len - i - 1); - // printf("K %s %d %d %d [%.*s]\n", path, pos, n, i, n + 2, s + i); + // printf("K1 %s %d %d %d [%.*s]\n", path, pos, n, i, n + 2, s + i); if (n < 0) return n; if (i + 1 + n >= len) return MG_JSON_NOT_FOUND; - // printf("K %s [%.*s] %d %d %d\n", path, n, &s[i + 1], n, depth, ed); - // NOTE(cpq): in the check sequence below is important. - // strncmp() must go first: it fails fast if the remaining length of - // the path is smaller than `n`. + // printf("K2 %s [%.*s] %d %d %d\n", path, n, &s[i + 1], n, depth, + // ed); + // NOTE(cpq): in the check sequence below is important. + // strncmp() must go first: it fails fast if the remaining length of + // the path is smaller than `n`. if (depth == ed && path[pos - 1] == '.' && strncmp(&s[i + 1], &path[pos], (size_t) n) == 0 && (path[pos + n] == '\0' || path[pos + n] == '.' || @@ -203,7 +205,6 @@ int mg_json_get(struct mg_str json, const char *path, int *toklen) { return MG_JSON_INVALID; } else if (c == ',') { expecting = (nesting[depth - 1] == '{') ? S_KEY : S_VALUE; - // MG_CHECKRET('C'); } else if (c == ']' || c == '}') { MG_EOO('O'); if (depth == ed && ei >= 0) ci++; @@ -212,7 +213,6 @@ int mg_json_get(struct mg_str json, const char *path, int *toklen) { } break; } - MG_DBGP('E'); } return MG_JSON_NOT_FOUND; }