Commit bda05d93 authored by Marko Mikulicic's avatar Marko Mikulicic

Import frozen

    PUBLISHED_FROM=9f6f38e92b5952b9571d73569c2752b6805f15c5
parent 59bc2af4
......@@ -543,7 +543,7 @@ double cs_time() {
* See the GNU General Public License for more details.
*
* Alternatively, you can license this library under a commercial
* license, as set out in <https://www.cesanta.com/license>.
* license, as set out in <http://cesanta.com/products.html>.
*/
#define _CRT_SECURE_NO_WARNINGS /* Disable deprecation warning in VS2005+ */
......@@ -578,8 +578,15 @@ struct frozen {
static int parse_object(struct frozen *f);
static int parse_value(struct frozen *f);
#define EXPECT(cond, err_code) do { if (!(cond)) return (err_code); } while (0)
#define TRY(expr) do { int _n = expr; if (_n < 0) return _n; } while (0)
#define EXPECT(cond, err_code) \
do { \
if (!(cond)) return (err_code); \
} while (0)
#define TRY(expr) \
do { \
int _n = expr; \
if (_n < 0) return _n; \
} while (0)
#define END_OF_STRING (-1)
static int left(const struct frozen *f) {
......@@ -596,12 +603,23 @@ static void skip_whitespaces(struct frozen *f) {
static int cur(struct frozen *f) {
skip_whitespaces(f);
return f->cur >= f->end ? END_OF_STRING : * (unsigned char *) f->cur;
return f->cur >= f->end ? END_OF_STRING : *(unsigned char *) f->cur;
}
static int test_and_skip(struct frozen *f, int expected) {
int ch = cur(f);
if (ch == expected) { f->cur++; return 0; }
if (ch == expected) {
f->cur++;
return 0;
}
return ch == END_OF_STRING ? JSON_STRING_INCOMPLETE : JSON_STRING_INVALID;
}
static int test_no_skip(struct frozen *f, int expected) {
int ch = cur(f);
if (ch == expected) {
return 0;
}
return ch == END_OF_STRING ? JSON_STRING_INCOMPLETE : JSON_STRING_INVALID;
}
......@@ -620,11 +638,19 @@ static int is_hex_digit(int ch) {
static int get_escape_len(const char *s, int len) {
switch (*s) {
case 'u':
return len < 6 ? JSON_STRING_INCOMPLETE :
is_hex_digit(s[1]) && is_hex_digit(s[2]) &&
is_hex_digit(s[3]) && is_hex_digit(s[4]) ? 5 : JSON_STRING_INVALID;
case '"': case '\\': case '/': case 'b':
case 'f': case 'n': case 'r': case 't':
return len < 6 ? JSON_STRING_INCOMPLETE
: is_hex_digit(s[1]) && is_hex_digit(s[2]) &&
is_hex_digit(s[3]) && is_hex_digit(s[4])
? 5
: JSON_STRING_INVALID;
case '"':
case '\\':
case '/':
case 'b':
case 'f':
case 'n':
case 'r':
case 't':
return len < 2 ? JSON_STRING_INCOMPLETE : 1;
default:
return JSON_STRING_INVALID;
......@@ -670,9 +696,12 @@ static int parse_identifier(struct frozen *f) {
static int get_utf8_char_len(unsigned char ch) {
if ((ch & 0x80) == 0) return 1;
switch (ch & 0xf0) {
case 0xf0: return 4;
case 0xe0: return 3;
default: return 2;
case 0xf0:
return 4;
case 0xe0:
return 3;
default:
return 2;
}
}
......@@ -682,9 +711,9 @@ static int parse_string(struct frozen *f) {
TRY(test_and_skip(f, '"'));
TRY(capture_ptr(f, f->cur, JSON_TYPE_STRING));
for (; f->cur < f->end; f->cur += len) {
ch = * (unsigned char *) f->cur;
ch = *(unsigned char *) f->cur;
len = get_utf8_char_len((unsigned char) ch);
EXPECT(ch >= 32 && len > 0, JSON_STRING_INVALID); /* No control chars */
EXPECT(ch >= 32 && len > 0, JSON_STRING_INVALID); /* No control chars */
EXPECT(len < left(f), JSON_STRING_INCOMPLETE);
if (ch == '\\') {
EXPECT((n = get_escape_len(f->cur + 1, left(f))) > 0, n);
......@@ -764,14 +793,35 @@ static int parse_value(struct frozen *f) {
int ch = cur(f);
switch (ch) {
case '"': TRY(parse_string(f)); break;
case '{': TRY(parse_object(f)); break;
case '[': TRY(parse_array(f)); break;
case 'n': TRY(expect(f, "null", 4, JSON_TYPE_NULL)); break;
case 't': TRY(expect(f, "true", 4, JSON_TYPE_TRUE)); break;
case 'f': TRY(expect(f, "false", 5, JSON_TYPE_FALSE)); break;
case '-': case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '"':
TRY(parse_string(f));
break;
case '{':
TRY(parse_object(f));
break;
case '[':
TRY(parse_array(f));
break;
case 'n':
TRY(expect(f, "null", 4, JSON_TYPE_NULL));
break;
case 't':
TRY(expect(f, "true", 4, JSON_TYPE_TRUE));
break;
case 'f':
TRY(expect(f, "false", 5, JSON_TYPE_FALSE));
break;
case '-':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
TRY(parse_number(f));
break;
default:
......@@ -821,9 +871,19 @@ static int parse_object(struct frozen *f) {
}
static int doit(struct frozen *f) {
int ret = 0;
if (f->cur == 0 || f->end < f->cur) return JSON_STRING_INVALID;
if (f->end == f->cur) return JSON_STRING_INCOMPLETE;
TRY(parse_object(f));
if (0 == (ret = test_no_skip(f, '{'))) {
TRY(parse_object(f));
} else if (0 == (ret = test_no_skip(f, '['))) {
TRY(parse_array(f));
} else {
return ret;
}
TRY(capture_ptr(f, f->cur, JSON_TYPE_EOF));
capture_len(f, f->num_tokens, f->cur);
return 0;
......@@ -876,8 +936,9 @@ struct json_token *find_json_token(struct json_token *toks, const char *path) {
ind += path[n] - '0';
}
if (path[n++] != ']') return 0;
skip = 1; /* In objects, we skip 2 elems while iterating, in arrays 1. */
} else if (toks->type != JSON_TYPE_OBJECT) return 0;
skip = 1; /* In objects, we skip 2 elems while iterating, in arrays 1. */
} else if (toks->type != JSON_TYPE_OBJECT)
return 0;
toks++;
for (i = 0; i < toks[-1].num_desc; i += skip, ind2++) {
/* ind == -1 indicated that we're iterating an array, not object */
......@@ -919,20 +980,46 @@ int json_emit_quoted_str(char *s, int s_len, const char *str, int len) {
const char *begin = s, *end = s + s_len, *str_end = str + len;
char ch;
#define EMIT(x) do { if (s < end) *s = x; s++; } while (0)
#define EMIT(x) \
do { \
if (s < end) *s = x; \
s++; \
} while (0)
EMIT('"');
while (str < str_end) {
ch = *str++;
switch (ch) {
case '"': EMIT('\\'); EMIT('"'); break;
case '\\': EMIT('\\'); EMIT('\\'); break;
case '\b': EMIT('\\'); EMIT('b'); break;
case '\f': EMIT('\\'); EMIT('f'); break;
case '\n': EMIT('\\'); EMIT('n'); break;
case '\r': EMIT('\\'); EMIT('r'); break;
case '\t': EMIT('\\'); EMIT('t'); break;
default: EMIT(ch);
case '"':
EMIT('\\');
EMIT('"');
break;
case '\\':
EMIT('\\');
EMIT('\\');
break;
case '\b':
EMIT('\\');
EMIT('b');
break;
case '\f':
EMIT('\\');
EMIT('f');
break;
case '\n':
EMIT('\\');
EMIT('n');
break;
case '\r':
EMIT('\\');
EMIT('r');
break;
case '\t':
EMIT('\\');
EMIT('t');
break;
default:
EMIT(ch);
}
}
EMIT('"');
......@@ -960,18 +1047,26 @@ int json_emit_va(char *s, int s_len, const char *fmt, va_list ap) {
while (*fmt != '\0') {
switch (*fmt) {
case '[': case ']': case '{': case '}': case ',': case ':':
case ' ': case '\r': case '\n': case '\t':
case '[':
case ']':
case '{':
case '}':
case ',':
case ':':
case ' ':
case '\r':
case '\n':
case '\t':
if (s < end) {
*s = *fmt;
}
s++;
break;
case 'i':
s += json_emit_long(s, end - s, va_arg(ap, long));
s += json_emit_long(s, end - s, va_arg(ap, long) );
break;
case 'f':
s += json_emit_double(s, end - s, va_arg(ap, double));
s += json_emit_double(s, end - s, va_arg(ap, double) );
break;
case 'v':
str = va_arg(ap, char *);
......
......@@ -840,7 +840,7 @@ size_t strnlen(const char *s, size_t maxlen);
* See the GNU General Public License for more details.
*
* Alternatively, you can license this library under a commercial
* license, as set out in <https://www.cesanta.com/license>.
* license, as set out in <http://cesanta.com/products.html>.
*/
#ifndef FROZEN_HEADER_INCLUDED
......@@ -853,27 +853,27 @@ extern "C" {
#include <stdarg.h>
enum json_type {
JSON_TYPE_EOF = 0, /* End of parsed tokens marker */
JSON_TYPE_STRING = 1,
JSON_TYPE_NUMBER = 2,
JSON_TYPE_OBJECT = 3,
JSON_TYPE_TRUE = 4,
JSON_TYPE_FALSE = 5,
JSON_TYPE_NULL = 6,
JSON_TYPE_ARRAY = 7
JSON_TYPE_EOF = 0, /* End of parsed tokens marker */
JSON_TYPE_STRING = 1,
JSON_TYPE_NUMBER = 2,
JSON_TYPE_OBJECT = 3,
JSON_TYPE_TRUE = 4,
JSON_TYPE_FALSE = 5,
JSON_TYPE_NULL = 6,
JSON_TYPE_ARRAY = 7
};
struct json_token {
const char *ptr; /* Points to the beginning of the token */
int len; /* Token length */
int num_desc; /* For arrays and object, total number of descendants */
enum json_type type; /* Type of the token, possible values above */
const char *ptr; /* Points to the beginning of the token */
int len; /* Token length */
int num_desc; /* For arrays and object, total number of descendants */
enum json_type type; /* Type of the token, possible values above */
};
/* Error codes */
#define JSON_STRING_INVALID -1
#define JSON_STRING_INCOMPLETE -2
#define JSON_TOKEN_ARRAY_TOO_SMALL -3
#define JSON_STRING_INVALID -1
#define JSON_STRING_INCOMPLETE -2
#define JSON_TOKEN_ARRAY_TOO_SMALL -3
int parse_json(const char *json_string, int json_string_length,
struct json_token *tokens_array, int size_of_tokens_array);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment