dovecot-2.2: JSON parser fixes

dovecot at dovecot.org dovecot at dovecot.org
Thu Nov 29 07:31:26 EET 2012


details:   http://hg.dovecot.org/dovecot-2.2/rev/9a31c44c1184
changeset: 15436:9a31c44c1184
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Nov 29 07:30:23 2012 +0200
description:
JSON parser fixes

diffstat:

 src/lib/json-parser.c      |  89 +++++++++++++++++++++++++++------------------
 src/lib/test-json-parser.c |   9 +++-
 2 files changed, 59 insertions(+), 39 deletions(-)

diffs (238 lines):

diff -r 86572582647e -r 9a31c44c1184 src/lib/json-parser.c
--- a/src/lib/json-parser.c	Thu Nov 29 06:26:29 2012 +0200
+++ b/src/lib/json-parser.c	Thu Nov 29 07:30:23 2012 +0200
@@ -148,11 +148,11 @@
 	parser->data++;
 
 	str_truncate(parser->value, 0);
-	for (; parser->data !=  parser->end; parser->data++) {
+	for (; parser->data != parser->end; parser->data++) {
 		if (*parser->data == '"') {
 			parser->data++;
 			*value_r = str_c(parser->value);
-			return 0;
+			return 1;
 		}
 		if (*parser->data != '\\')
 			str_append_c(parser->value, *parser->data);
@@ -179,8 +179,12 @@
 				str_append_c(parser->value, '\t');
 				break;
 			case 'u':
-				if (parser->end - parser->data < 4)
-					return -1;
+				parser->data++;
+				if (parser->end - parser->data < 4) {
+					/* wait for more data */
+					parser->data = parser->end;
+					return 0;
+				}
 				uni_ucs4_to_utf8_c(hex2dec(parser->data, 4),
 						   parser->value);
 				parser->data += 3;
@@ -190,64 +194,69 @@
 			}
 		}
 	}
-	return -1;
+	return 0;
 }
 
 static int
 json_parse_digits(struct json_parser *parser)
 {
-	if (parser->data == parser->end ||
-	    *parser->data < '0' || *parser->data > '9')
+	if (parser->data == parser->end)
+		return 0;
+	if (*parser->data < '0' || *parser->data > '9')
 		return -1;
 
 	while (parser->data != parser->end &&
 	       *parser->data >= '0' && *parser->data <= '9')
 		str_append_c(parser->value, *parser->data++);
-	return 0;
+	return 1;
 }
 
 static int json_parse_int(struct json_parser *parser)
 {
+	int ret;
+
 	if (*parser->data == '-') {
 		str_append_c(parser->value, *parser->data++);
 		if (parser->data == parser->end)
-			return -1;
+			return 0;
 	}
 	if (*parser->data == '0')
 		str_append_c(parser->value, *parser->data++);
 	else {
-		if (json_parse_digits(parser) < 0)
-			return -1;
+		if ((ret = json_parse_digits(parser)) <= 0)
+			return ret;
 	}
-	return 0;
+	return 1;
 }
 
 static int json_parse_number(struct json_parser *parser, const char **value_r)
 {
+	int ret;
+
 	str_truncate(parser->value, 0);
-	if (json_parse_int(parser) < 0)
-		return -1;
+	if ((ret = json_parse_int(parser)) <= 0)
+		return ret;
 	if (parser->data != parser->end && *parser->data == '.') {
 		/* frac */
 		str_append_c(parser->value, *parser->data++);
-		if (json_parse_digits(parser) < 0)
-			return -1;
+		if ((ret = json_parse_digits(parser)) <= 0)
+			return ret;
 	}
 	if (parser->data != parser->end &&
 	    (*parser->data == 'e' || *parser->data == 'E')) {
 		/* exp */
 		str_append_c(parser->value, *parser->data++);
 		if (parser->data == parser->end)
-			return -1;
+			return 0;
 		if (*parser->data == '+' || *parser->data == '-')
 			str_append_c(parser->value, *parser->data++);
-		if (json_parse_digits(parser) < 0)
-			return -1;
+		if ((ret = json_parse_digits(parser)) <= 0)
+			return ret;
 	}
 	if (parser->data == parser->end && !parser->input->eof)
-		return -1;
+		return 0;
 	*value_r = str_c(parser->value);
-	return 0;
+	return 1;
 }
 
 static int json_parse_atom(struct json_parser *parser, const char *atom)
@@ -256,16 +265,17 @@
 
 	avail = parser->end - parser->data;
 	if (avail < len) {
-		if (memcmp(parser->data, atom, avail) == 0) {
-			/* everything matches so far, but we need more data */
-			parser->data += avail;
-		}
-		return -1;
+		if (memcmp(parser->data, atom, avail) != 0)
+			return -1;
+
+		/* everything matches so far, but we need more data */
+		parser->data += avail;
+		return 0;
 	}
 	if (memcmp(parser->data, atom, len) != 0)
 		return -1;
 	parser->data += len;
-	return 0;
+	return 1;
 }
 
 static int
@@ -290,6 +300,8 @@
 json_try_parse_next(struct json_parser *parser, enum json_type *type_r,
 		    const char **value_r)
 {
+	int ret;
+
 	if (!json_parse_whitespace(parser))
 		return -1;
 
@@ -304,11 +316,7 @@
 		json_parser_update_input_pos(parser);
 		return json_try_parse_next(parser, type_r, value_r);
 	case JSON_STATE_OBJECT_VALUE:
-		if (json_parse_string(parser, value_r) == 0)
-			*type_r = JSON_TYPE_STRING;
-		else if (json_parse_number(parser, value_r) == 0)
-			*type_r = JSON_TYPE_NUMBER;
-		else if (*parser->data == '[') {
+		if (*parser->data == '[') {
 			parser->error = "Arrays not supported";
 			return -1;
 		} else if (*parser->data == '{') {
@@ -318,19 +326,28 @@
 			json_parser_update_input_pos(parser);
 			*type_r = JSON_TYPE_OBJECT;
 			return 0;
-		} else if (json_parse_atom(parser, "true") == 0) {
+		}
+		if ((ret = json_parse_string(parser, value_r)) >= 0) {
+			*type_r = JSON_TYPE_STRING;
+		} else if ((ret = json_parse_number(parser, value_r)) >= 0) {
+			*type_r = JSON_TYPE_NUMBER;
+		} else if ((ret = json_parse_atom(parser, "true")) >= 0) {
 			*type_r = JSON_TYPE_TRUE;
 			*value_r = "true";
-		} else if (json_parse_atom(parser, "false") == 0) {
+		} else if ((ret = json_parse_atom(parser, "false")) >= 0) {
 			*type_r = JSON_TYPE_FALSE;
 			*value_r = "false";
-		} else if (json_parse_atom(parser, "null") == 0) {
+		} else if ((ret = json_parse_atom(parser, "null")) >= 0) {
 			*type_r = JSON_TYPE_NULL;
 			*value_r = NULL;
 		} else {
 			parser->error = "Invalid data as value";
 			return -1;
 		}
+		if (ret == 0) {
+			i_assert(parser->data == parser->end);
+			return -1;
+		}
 		parser->state = parser->state == JSON_STATE_ROOT ?
 			JSON_STATE_DONE :
 			JSON_STATE_OBJECT_VALUE_NEXT;
@@ -341,7 +358,7 @@
 		parser->state = JSON_STATE_OBJECT_KEY;
 		/* fall through */
 	case JSON_STATE_OBJECT_KEY:
-		if (json_parse_string(parser, value_r) < 0) {
+		if (json_parse_string(parser, value_r) <= 0) {
 			parser->error = "Expected string as object key";
 			return -1;
 		}
diff -r 86572582647e -r 9a31c44c1184 src/lib/test-json-parser.c
--- a/src/lib/test-json-parser.c	Thu Nov 29 06:26:29 2012 +0200
+++ b/src/lib/test-json-parser.c	Thu Nov 29 07:30:23 2012 +0200
@@ -20,7 +20,8 @@
 	"  \"sub2\":-12.456,\n"
 	"  \"sub3\":12.456e9,\n"
 	"  \"sub4\":0.456e-789"
-	"}"
+	"},"
+	"\"key9\": \"\\\\\\\"\\b\\f\\n\\r\\t\\u0001\uffff\""
 	"}\n";
 
 static struct {
@@ -53,7 +54,9 @@
 	{ JSON_TYPE_NUMBER, "12.456e9" },
 	{ JSON_TYPE_OBJECT_KEY, "sub4" },
 	{ JSON_TYPE_NUMBER, "0.456e-789" },
-	{ JSON_TYPE_OBJECT_END, NULL }
+	{ JSON_TYPE_OBJECT_END, NULL },
+	{ JSON_TYPE_OBJECT_KEY, "key9" },
+	{ JSON_TYPE_STRING, "\\\"\b\f\n\r\t\001\xef\xbf\xbf" }
 };
 
 static void test_json_parser_success(bool full_size)
@@ -93,6 +96,6 @@
 
 void test_json_parser(void)
 {
+	test_json_parser_success(FALSE);
 	test_json_parser_success(TRUE);
-	test_json_parser_success(FALSE);
 }


More information about the dovecot-cvs mailing list