summaryrefslogtreecommitdiff
path: root/src/jansson/load.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/jansson/load.c')
-rw-r--r--src/jansson/load.c123
1 files changed, 87 insertions, 36 deletions
diff --git a/src/jansson/load.c b/src/jansson/load.c
index d88a704..56c8ee3 100644
--- a/src/jansson/load.c
+++ b/src/jansson/load.c
@@ -1,11 +1,14 @@
/*
- * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
+#ifndef _GNU_SOURCE
#define _GNU_SOURCE
+#endif
+
#include <errno.h>
#include <limits.h>
#include <stdio.h>
@@ -37,7 +40,7 @@
#define l_isalpha(c) (l_isupper(c) || l_islower(c))
#define l_isdigit(c) ('0' <= (c) && (c) <= '9')
#define l_isxdigit(c) \
- (l_isdigit(c) || 'A' <= (c) || (c) <= 'F' || 'a' <= (c) || (c) <= 'f')
+ (l_isdigit(c) || ('A' <= (c) && (c) <= 'F') || ('a' <= (c) && (c) <= 'f'))
/* Read one byte from stream, convert to unsigned char, then int, and
return. return EOF on end of file. This corresponds to the
@@ -60,7 +63,10 @@ typedef struct {
strbuffer_t saved_text;
int token;
union {
- char *string;
+ struct {
+ char *val;
+ size_t len;
+ } string;
json_int_t integer;
double real;
} value;
@@ -250,9 +256,18 @@ static void lex_unget(lex_t *lex, int c)
static void lex_unget_unsave(lex_t *lex, int c)
{
if(c != STREAM_STATE_EOF && c != STREAM_STATE_ERROR) {
+ /* Since we treat warnings as errors, when assertions are turned
+ * off the "d" variable would be set but never used. Which is
+ * treated as an error by GCC.
+ */
+ #ifndef NDEBUG
char d;
+ #endif
stream_unget(&lex->stream, c);
- d = strbuffer_pop(&lex->saved_text);
+ #ifndef NDEBUG
+ d =
+ #endif
+ strbuffer_pop(&lex->saved_text);
assert(c == d);
}
}
@@ -267,6 +282,13 @@ static void lex_save_cached(lex_t *lex)
}
}
+static void lex_free_string(lex_t *lex)
+{
+ jsonp_free(lex->value.string.val);
+ lex->value.string.val = NULL;
+ lex->value.string.len = 0;
+}
+
/* assumes that str points to 'u' plus at least 4 valid hex digits */
static int32_t decode_unicode_escape(const char *str)
{
@@ -285,7 +307,7 @@ static int32_t decode_unicode_escape(const char *str)
else if(l_isupper(c))
value += c - 'A' + 10;
else
- assert(0);
+ return -1;
}
return value;
@@ -298,7 +320,7 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
char *t;
int i;
- lex->value.string = NULL;
+ lex->value.string.val = NULL;
lex->token = TOKEN_INVALID;
c = lex_get_save(lex, error);
@@ -353,14 +375,12 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
- two \uXXXX escapes (length 12) forming an UTF-16 surrogate pair
are converted to 4 bytes
*/
- lex->value.string = jsonp_malloc(lex->saved_text.length + 1);
- if(!lex->value.string) {
+ t = jsonp_malloc(lex->saved_text.length + 1);
+ if(!t) {
/* this is not very nice, since TOKEN_INVALID is returned */
goto out;
}
-
- /* the target */
- t = lex->value.string;
+ lex->value.string.val = t;
/* + 1 to skip the " */
p = strbuffer_value(&lex->saved_text) + 1;
@@ -369,17 +389,24 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
if(*p == '\\') {
p++;
if(*p == 'u') {
- char buffer[4];
- int length;
+ size_t length;
int32_t value;
value = decode_unicode_escape(p);
+ if(value < 0) {
+ error_set(error, lex, "invalid Unicode escape '%.6s'", p - 1);
+ goto out;
+ }
p += 5;
if(0xD800 <= value && value <= 0xDBFF) {
/* surrogate pair */
if(*p == '\\' && *(p + 1) == 'u') {
int32_t value2 = decode_unicode_escape(++p);
+ if(value2 < 0) {
+ error_set(error, lex, "invalid Unicode escape '%.6s'", p - 1);
+ goto out;
+ }
p += 5;
if(0xDC00 <= value2 && value2 <= 0xDFFF) {
@@ -408,16 +435,9 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
error_set(error, lex, "invalid Unicode '\\u%04X'", value);
goto out;
}
- else if(value == 0)
- {
- error_set(error, lex, "\\u0000 is not allowed");
- goto out;
- }
- if(utf8_encode(value, buffer, &length))
+ if(utf8_encode(value, t, &length))
assert(0);
-
- memcpy(t, buffer, length);
t += length;
}
else {
@@ -439,15 +459,17 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
*(t++) = *(p++);
}
*t = '\0';
+ lex->value.string.len = t - lex->value.string.val;
lex->token = TOKEN_STRING;
return;
out:
- jsonp_free(lex->value.string);
+ lex_free_string(lex);
}
+#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */
#if JSON_INTEGER_IS_LONG_LONG
-#ifdef _MSC_VER // Microsoft Visual Studio
+#ifdef _MSC_VER /* Microsoft Visual Studio */
#define json_strtoint _strtoi64
#else
#define json_strtoint strtoll
@@ -455,6 +477,7 @@ out:
#else
#define json_strtoint strtol
#endif
+#endif
static int lex_scan_number(lex_t *lex, int c, json_error_t *error)
{
@@ -557,10 +580,8 @@ static int lex_scan(lex_t *lex, json_error_t *error)
strbuffer_clear(&lex->saved_text);
- if(lex->token == TOKEN_STRING) {
- jsonp_free(lex->value.string);
- lex->value.string = NULL;
- }
+ if(lex->token == TOKEN_STRING)
+ lex_free_string(lex);
c = lex_get(lex, error);
while(c == ' ' || c == '\t' || c == '\n' || c == '\r')
@@ -621,13 +642,14 @@ out:
return lex->token;
}
-static char *lex_steal_string(lex_t *lex)
+static char *lex_steal_string(lex_t *lex, size_t *out_len)
{
char *result = NULL;
- if(lex->token == TOKEN_STRING)
- {
- result = lex->value.string;
- lex->value.string = NULL;
+ if(lex->token == TOKEN_STRING) {
+ result = lex->value.string.val;
+ *out_len = lex->value.string.len;
+ lex->value.string.val = NULL;
+ lex->value.string.len = 0;
}
return result;
}
@@ -645,7 +667,7 @@ static int lex_init(lex_t *lex, get_func get, void *data)
static void lex_close(lex_t *lex)
{
if(lex->token == TOKEN_STRING)
- jsonp_free(lex->value.string);
+ lex_free_string(lex);
strbuffer_close(&lex->saved_text);
}
@@ -666,6 +688,7 @@ static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error)
while(1) {
char *key;
+ size_t len;
json_t *value;
if(lex->token != TOKEN_STRING) {
@@ -673,9 +696,14 @@ static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error)
goto error;
}
- key = lex_steal_string(lex);
+ key = lex_steal_string(lex, &len);
if(!key)
return NULL;
+ if (memchr(key, '\0', len)) {
+ jsonp_free(key);
+ error_set(error, lex, "NUL byte in object key not supported");
+ goto error;
+ }
if(flags & JSON_REJECT_DUPLICATES) {
if(json_object_get(object, key)) {
@@ -770,15 +798,38 @@ error:
static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error)
{
json_t *json;
+ double value;
switch(lex->token) {
case TOKEN_STRING: {
- json = json_string_nocheck(lex->value.string);
+ const char *value = lex->value.string.val;
+ size_t len = lex->value.string.len;
+
+ if(!(flags & JSON_ALLOW_NUL)) {
+ if(memchr(value, '\0', len)) {
+ error_set(error, lex, "\\u0000 is not allowed without JSON_ALLOW_NUL");
+ return NULL;
+ }
+ }
+
+ json = jsonp_stringn_nocheck_own(value, len);
+ if(json) {
+ lex->value.string.val = NULL;
+ lex->value.string.len = 0;
+ }
break;
}
case TOKEN_INTEGER: {
- json = json_integer(lex->value.integer);
+ if (flags & JSON_DECODE_INT_AS_REAL) {
+ if(jsonp_strtod(&lex->saved_text, &value)) {
+ error_set(error, lex, "real number overflow");
+ return NULL;
+ }
+ json = json_real(value);
+ } else {
+ json = json_integer(lex->value.integer);
+ }
break;
}