aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dump.c22
-rw-r--r--src/hashtable.c13
-rw-r--r--src/hashtable.h2
-rw-r--r--src/hashtable_seed.c2
-rw-r--r--src/jansson.def5
-rw-r--r--src/jansson.h26
-rw-r--r--src/jansson_config.h.in2
-rw-r--r--src/jansson_private.h10
-rw-r--r--src/load.c106
-rw-r--r--src/lookup3.h2
-rw-r--r--src/memory.c19
-rw-r--r--src/pack_unpack.c74
-rw-r--r--src/strbuffer.c2
-rw-r--r--src/strbuffer.h2
-rw-r--r--src/strconv.c4
-rw-r--r--src/utf.c29
-rw-r--r--src/utf.h14
-rw-r--r--src/value.c113
18 files changed, 302 insertions, 145 deletions
diff --git a/src/dump.c b/src/dump.c
index 3b19c73..7eddd5a 100644
--- a/src/dump.c
+++ b/src/dump.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 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.
@@ -65,24 +65,25 @@ static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t
return 0;
}
-static int dump_string(const char *str, json_dump_callback_t dump, void *data, size_t flags)
+static int dump_string(const char *str, size_t len, json_dump_callback_t dump, void *data, size_t flags)
{
- const char *pos, *end;
+ const char *pos, *end, *lim;
int32_t codepoint;
if(dump("\"", 1, data))
return -1;
end = pos = str;
+ lim = str + len;
while(1)
{
const char *text;
char seq[13];
int length;
- while(*end)
+ while(end < lim)
{
- end = utf8_iterate(pos, &codepoint);
+ end = utf8_iterate(pos, lim - pos, &codepoint);
if(!end)
return -1;
@@ -126,7 +127,7 @@ static int dump_string(const char *str, json_dump_callback_t dump, void *data, s
/* codepoint is in BMP */
if(codepoint < 0x10000)
{
- sprintf(seq, "\\u%04x", codepoint);
+ sprintf(seq, "\\u%04X", codepoint);
length = 6;
}
@@ -139,7 +140,7 @@ static int dump_string(const char *str, json_dump_callback_t dump, void *data, s
first = 0xD800 | ((codepoint & 0xffc00) >> 10);
last = 0xDC00 | (codepoint & 0x003ff);
- sprintf(seq, "\\u%04x\\u%04x", first, last);
+ sprintf(seq, "\\u%04X\\u%04X", first, last);
length = 12;
}
@@ -215,7 +216,7 @@ static int do_dump(const json_t *json, size_t flags, int depth,
}
case JSON_STRING:
- return dump_string(json_string_value(json), dump, data, flags);
+ return dump_string(json_string_value(json), json_string_length(json), dump, data, flags);
case JSON_ARRAY:
{
@@ -336,7 +337,7 @@ static int do_dump(const json_t *json, size_t flags, int depth,
value = json_object_get(json, key);
assert(value);
- dump_string(key, dump, data, flags);
+ dump_string(key, strlen(key), dump, data, flags);
if(dump(separator, separator_length, data) ||
do_dump(value, flags, depth + 1, dump, data))
{
@@ -372,8 +373,9 @@ static int do_dump(const json_t *json, size_t flags, int depth,
while(iter)
{
void *next = json_object_iter_next((json_t *)json, iter);
+ const char *key = json_object_iter_key(iter);
- dump_string(json_object_iter_key(iter), dump, data, flags);
+ dump_string(key, strlen(key), dump, data, flags);
if(dump(separator, separator_length, data) ||
do_dump(json_object_iter_value(iter), flags, depth + 1,
dump, data))
diff --git a/src/hashtable.c b/src/hashtable.c
index abd4bf1..4c4b565 100644
--- a/src/hashtable.c
+++ b/src/hashtable.c
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#if HAVE_CONFIG_H
-#include <config.h>
+#include <jansson_private_config.h>
#endif
#include <stdlib.h>
@@ -234,7 +234,14 @@ int hashtable_set(hashtable_t *hashtable,
/* offsetof(...) returns the size of pair_t without the last,
flexible member. This way, the correct amount is
allocated. */
- pair = jsonp_malloc(offsetof(pair_t, key) + strlen(key) + 1);
+
+ size_t len = strlen(key);
+ if(len >= (size_t)-1 - offsetof(pair_t, key)) {
+ /* Avoid an overflow if the key is very long */
+ return -1;
+ }
+
+ pair = jsonp_malloc(offsetof(pair_t, key) + len + 1);
if(!pair)
return -1;
diff --git a/src/hashtable.h b/src/hashtable.h
index 469c6ec..f54c3fe 100644
--- a/src/hashtable.h
+++ b/src/hashtable.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
diff --git a/src/hashtable_seed.c b/src/hashtable_seed.c
index 7ee8001..751e0e3 100644
--- a/src/hashtable_seed.c
+++ b/src/hashtable_seed.c
@@ -3,7 +3,7 @@
*/
#ifdef HAVE_CONFIG_H
-#include <config.h>
+#include <jansson_private_config.h>
#endif
#include <stdio.h>
diff --git a/src/jansson.def b/src/jansson.def
index 19096d4..da4cfd4 100644
--- a/src/jansson.def
+++ b/src/jansson.def
@@ -4,10 +4,15 @@ EXPORTS
json_false
json_null
json_string
+ json_stringn
json_string_nocheck
+ json_stringn_nocheck
json_string_value
+ json_string_length
json_string_set
+ json_string_setn
json_string_set_nocheck
+ json_string_setn_nocheck
json_integer
json_integer_value
json_integer_set
diff --git a/src/jansson.h b/src/jansson.h
index 3f67edf..85215f4 100644
--- a/src/jansson.h
+++ b/src/jansson.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 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.
@@ -67,23 +67,26 @@ typedef long json_int_t;
#endif
#define json_typeof(json) ((json)->type)
-#define json_is_object(json) (json && json_typeof(json) == JSON_OBJECT)
-#define json_is_array(json) (json && json_typeof(json) == JSON_ARRAY)
-#define json_is_string(json) (json && json_typeof(json) == JSON_STRING)
-#define json_is_integer(json) (json && json_typeof(json) == JSON_INTEGER)
-#define json_is_real(json) (json && json_typeof(json) == JSON_REAL)
+#define json_is_object(json) ((json) && json_typeof(json) == JSON_OBJECT)
+#define json_is_array(json) ((json) && json_typeof(json) == JSON_ARRAY)
+#define json_is_string(json) ((json) && json_typeof(json) == JSON_STRING)
+#define json_is_integer(json) ((json) && json_typeof(json) == JSON_INTEGER)
+#define json_is_real(json) ((json) && json_typeof(json) == JSON_REAL)
#define json_is_number(json) (json_is_integer(json) || json_is_real(json))
-#define json_is_true(json) (json && json_typeof(json) == JSON_TRUE)
-#define json_is_false(json) (json && json_typeof(json) == JSON_FALSE)
+#define json_is_true(json) ((json) && json_typeof(json) == JSON_TRUE)
+#define json_is_false(json) ((json) && json_typeof(json) == JSON_FALSE)
+#define json_boolean_value json_is_true
#define json_is_boolean(json) (json_is_true(json) || json_is_false(json))
-#define json_is_null(json) (json && json_typeof(json) == JSON_NULL)
+#define json_is_null(json) ((json) && json_typeof(json) == JSON_NULL)
/* construction, destruction, reference counting */
json_t *json_object(void);
json_t *json_array(void);
json_t *json_string(const char *value);
+json_t *json_stringn(const char *value, size_t len);
json_t *json_string_nocheck(const char *value);
+json_t *json_stringn_nocheck(const char *value, size_t len);
json_t *json_integer(json_int_t value);
json_t *json_real(double value);
json_t *json_true(void);
@@ -200,16 +203,18 @@ int json_array_insert(json_t *array, size_t ind, json_t *value)
}
const char *json_string_value(const json_t *string);
+size_t json_string_length(const json_t *string);
json_int_t json_integer_value(const json_t *integer);
double json_real_value(const json_t *real);
double json_number_value(const json_t *json);
int json_string_set(json_t *string, const char *value);
+int json_string_setn(json_t *string, const char *value, size_t len);
int json_string_set_nocheck(json_t *string, const char *value);
+int json_string_setn_nocheck(json_t *string, const char *value, size_t len);
int json_integer_set(json_t *integer, json_int_t value);
int json_real_set(json_t *real, double value);
-
/* pack, unpack */
json_t *json_pack(const char *fmt, ...);
@@ -241,6 +246,7 @@ json_t *json_deep_copy(const json_t *value);
#define JSON_DISABLE_EOF_CHECK 0x2
#define JSON_DECODE_ANY 0x4
#define JSON_DECODE_INT_AS_REAL 0x8
+#define JSON_ALLOW_NUL 0x10
typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data);
diff --git a/src/jansson_config.h.in b/src/jansson_config.h.in
index 785801f..12580a0 100644
--- a/src/jansson_config.h.in
+++ b/src/jansson_config.h.in
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2010-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.
diff --git a/src/jansson_private.h b/src/jansson_private.h
index 403b53a..c6f437c 100644
--- a/src/jansson_private.h
+++ b/src/jansson_private.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 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.
@@ -49,6 +49,7 @@ typedef struct {
typedef struct {
json_t json;
char *value;
+ size_t length;
} json_string_t;
typedef struct {
@@ -64,9 +65,13 @@ typedef struct {
#define json_to_object(json_) container_of(json_, json_object_t, json)
#define json_to_array(json_) container_of(json_, json_array_t, json)
#define json_to_string(json_) container_of(json_, json_string_t, json)
-#define json_to_real(json_) container_of(json_, json_real_t, json)
+#define json_to_real(json_) container_of(json_, json_real_t, json)
#define json_to_integer(json_) container_of(json_, json_integer_t, json)
+/* Create a string by taking ownership of an existing buffer */
+json_t *jsonp_stringn_nocheck_own(const char *value, size_t len);
+
+/* Error message formatting */
void jsonp_error_init(json_error_t *error, const char *source);
void jsonp_error_set_source(json_error_t *error, const char *source);
void jsonp_error_set(json_error_t *error, int line, int column,
@@ -83,6 +88,7 @@ void* jsonp_malloc(size_t size);
void jsonp_free(void *ptr);
char *jsonp_strndup(const char *str, size_t length);
char *jsonp_strdup(const char *str);
+char *jsonp_strndup(const char *str, size_t len);
/* Windows compatibility */
#ifdef _WIN32
diff --git a/src/load.c b/src/load.c
index c5536f5..722f2d7 100644
--- a/src/load.c
+++ b/src/load.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 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.
@@ -63,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;
@@ -279,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)
{
@@ -297,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;
@@ -310,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);
@@ -365,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;
@@ -381,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) {
@@ -420,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 {
@@ -451,11 +459,12 @@ 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 */
@@ -474,7 +483,7 @@ static int lex_scan_number(lex_t *lex, int c, json_error_t *error)
{
const char *saved_text;
char *end;
- double value;
+ double doubleval;
lex->token = TOKEN_INVALID;
@@ -499,16 +508,16 @@ static int lex_scan_number(lex_t *lex, int c, json_error_t *error)
}
if(c != '.' && c != 'E' && c != 'e') {
- json_int_t value;
+ json_int_t intval;
lex_unget_unsave(lex, c);
saved_text = strbuffer_value(&lex->saved_text);
errno = 0;
- value = json_strtoint(saved_text, &end, 10);
+ intval = json_strtoint(saved_text, &end, 10);
if(errno == ERANGE) {
- if(value < 0)
+ if(intval < 0)
error_set(error, lex, "too big negative integer");
else
error_set(error, lex, "too big integer");
@@ -518,7 +527,7 @@ static int lex_scan_number(lex_t *lex, int c, json_error_t *error)
assert(end == saved_text + lex->saved_text.length);
lex->token = TOKEN_INTEGER;
- lex->value.integer = value;
+ lex->value.integer = intval;
return 0;
}
@@ -552,13 +561,13 @@ static int lex_scan_number(lex_t *lex, int c, json_error_t *error)
lex_unget_unsave(lex, c);
- if(jsonp_strtod(&lex->saved_text, &value)) {
+ if(jsonp_strtod(&lex->saved_text, &doubleval)) {
error_set(error, lex, "real number overflow");
goto out;
}
lex->token = TOKEN_REAL;
- lex->value.real = value;
+ lex->value.real = doubleval;
return 0;
out:
@@ -571,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')
@@ -635,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;
}
@@ -659,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);
}
@@ -680,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) {
@@ -687,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)) {
@@ -788,7 +802,21 @@ static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error)
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;
}
diff --git a/src/lookup3.h b/src/lookup3.h
index dc76138..8847483 100644
--- a/src/lookup3.h
+++ b/src/lookup3.h
@@ -37,7 +37,7 @@ on 1 byte), but shoehorning those bytes into integers efficiently is messy.
#include <stdlib.h>
#ifdef HAVE_CONFIG_H
-#include <config.h>
+#include <jansson_private_config.h>
#endif
#ifdef HAVE_STDINT_H
diff --git a/src/memory.c b/src/memory.c
index eb6cec5..ca44d6b 100644
--- a/src/memory.c
+++ b/src/memory.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2011-2012 Basile Starynkevitch <basile@starynkevitch.net>
*
* Jansson is free software; you can redistribute it and/or modify it
@@ -12,6 +12,10 @@
#include "jansson.h"
#include "jansson_private.h"
+/* C89 allows these to be macros */
+#undef malloc
+#undef free
+
/* memory function pointers */
static json_malloc_t do_malloc = malloc;
static json_free_t do_free = free;
@@ -34,18 +38,19 @@ void jsonp_free(void *ptr)
char *jsonp_strdup(const char *str)
{
- char *new_str;
- size_t len;
+ return jsonp_strndup(str, strlen(str));
+}
- len = strlen(str);
- if(len == (size_t)-1)
- return NULL;
+char *jsonp_strndup(const char *str, size_t len)
+{
+ char *new_str;
new_str = jsonp_malloc(len + 1);
if(!new_str)
return NULL;
- memcpy(new_str, str, len + 1);
+ memcpy(new_str, str, len);
+ new_str[len] = '\0';
return new_str;
}
diff --git a/src/pack_unpack.c b/src/pack_unpack.c
index 842fc98..af381a5 100644
--- a/src/pack_unpack.c
+++ b/src/pack_unpack.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2011-2012 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
*
* Jansson is free software; you can redistribute it and/or modify
@@ -125,19 +125,18 @@ static json_t *pack(scanner_t *s, va_list *ap);
/* ours will be set to 1 if jsonp_free() must be called for the result
afterwards */
static char *read_string(scanner_t *s, va_list *ap,
- const char *purpose, int *ours)
+ const char *purpose, size_t *out_len, int *ours)
{
char t;
strbuffer_t strbuff;
const char *str;
size_t length;
- char *result;
next_token(s);
t = token(s);
prev_token(s);
- if(t != '#' && t != '+') {
+ if(t != '#' && t != '%' && t != '+') {
/* Optimize the simple case */
str = va_arg(*ap, const char *);
@@ -146,11 +145,14 @@ static char *read_string(scanner_t *s, va_list *ap,
return NULL;
}
- if(!utf8_check_string(str, -1)) {
+ length = strlen(str);
+
+ if(!utf8_check_string(str, length)) {
set_error(s, "<args>", "Invalid UTF-8 %s", purpose);
return NULL;
}
+ *out_len = length;
*ours = 0;
return (char *)str;
}
@@ -170,6 +172,9 @@ static char *read_string(scanner_t *s, va_list *ap,
if(token(s) == '#') {
length = va_arg(*ap, int);
}
+ else if(token(s) == '%') {
+ length = va_arg(*ap, size_t);
+ }
else {
prev_token(s);
length = strlen(str);
@@ -188,15 +193,15 @@ static char *read_string(scanner_t *s, va_list *ap,
}
}
- result = strbuffer_steal_value(&strbuff);
-
- if(!utf8_check_string(result, -1)) {
+ if(!utf8_check_string(strbuff.value, strbuff.length)) {
set_error(s, "<args>", "Invalid UTF-8 %s", purpose);
+ strbuffer_close(&strbuff);
return NULL;
}
+ *out_len = strbuff.length;
*ours = 1;
- return result;
+ return strbuffer_steal_value(&strbuff);
}
static json_t *pack_object(scanner_t *s, va_list *ap)
@@ -206,6 +211,7 @@ static json_t *pack_object(scanner_t *s, va_list *ap)
while(token(s) != '}') {
char *key;
+ size_t len;
int ours;
json_t *value;
@@ -219,15 +225,19 @@ static json_t *pack_object(scanner_t *s, va_list *ap)
goto error;
}
- key = read_string(s, ap, "object key", &ours);
+ key = read_string(s, ap, "object key", &len, &ours);
if(!key)
goto error;
next_token(s);
value = pack(s, ap);
- if(!value)
+ if(!value) {
+ if(ours)
+ jsonp_free(key);
+
goto error;
+ }
if(json_object_set_new_nocheck(object, key, value)) {
if(ours)
@@ -290,20 +300,20 @@ static json_t *pack(scanner_t *s, va_list *ap)
case '[':
return pack_array(s, ap);
- case 's': { /* string */
+ case 's': /* string */
+ {
char *str;
+ size_t len;
int ours;
- json_t *result;
- str = read_string(s, ap, "string", &ours);
+ str = read_string(s, ap, "string", &len, &ours);
if(!str)
return NULL;
- result = json_string_nocheck(str);
- if(ours)
- jsonp_free(str);
-
- return result;
+ if (ours)
+ return jsonp_stringn_nocheck_own(str, len);
+ else
+ return json_stringn_nocheck(str, len);
}
case 'n': /* null */
@@ -540,16 +550,32 @@ static int unpack(scanner_t *s, json_t *root, va_list *ap)
}
if(!(s->flags & JSON_VALIDATE_ONLY)) {
- const char **target;
+ const char **str_target;
+ size_t *len_target = NULL;
- target = va_arg(*ap, const char **);
- if(!target) {
+ str_target = va_arg(*ap, const char **);
+ if(!str_target) {
set_error(s, "<args>", "NULL string argument");
return -1;
}
- if(root)
- *target = json_string_value(root);
+ next_token(s);
+
+ if(token(s) == '%') {
+ len_target = va_arg(*ap, size_t *);
+ if(!len_target) {
+ set_error(s, "<args>", "NULL string length argument");
+ return -1;
+ }
+ }
+ else
+ prev_token(s);
+
+ if(root) {
+ *str_target = json_string_value(root);
+ if(len_target)
+ *len_target = json_string_length(root);
+ }
}
return 0;
diff --git a/src/strbuffer.c b/src/strbuffer.c
index 2d6ff31..b3ddd0e 100644
--- a/src/strbuffer.c
+++ b/src/strbuffer.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 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.
diff --git a/src/strbuffer.h b/src/strbuffer.h
index 06fd065..fc11ec0 100644
--- a/src/strbuffer.h
+++ b/src/strbuffer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 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.
diff --git a/src/strconv.c b/src/strconv.c
index 3e2cb7c..3a70c6f 100644
--- a/src/strconv.c
+++ b/src/strconv.c
@@ -5,9 +5,9 @@
#include "jansson_private.h"
#include "strbuffer.h"
-/* need config.h to get the correct snprintf */
+/* need jansson_private_config.h to get the correct snprintf */
#ifdef HAVE_CONFIG_H
-#include <config.h>
+#include <jansson_private_config.h>
#endif
#if JSON_HAVE_LOCALECONV
diff --git a/src/utf.c b/src/utf.c
index 65b849b..b56e125 100644
--- a/src/utf.c
+++ b/src/utf.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 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.
@@ -8,7 +8,7 @@
#include <string.h>
#include "utf.h"
-int utf8_encode(int32_t codepoint, char *buffer, int *size)
+int utf8_encode(int32_t codepoint, char *buffer, size_t *size)
{
if(codepoint < 0)
return -1;
@@ -44,7 +44,7 @@ int utf8_encode(int32_t codepoint, char *buffer, int *size)
return 0;
}
-int utf8_check_first(char byte)
+size_t utf8_check_first(char byte)
{
unsigned char u = (unsigned char)byte;
@@ -80,9 +80,9 @@ int utf8_check_first(char byte)
}
}
-int utf8_check_full(const char *buffer, int size, int32_t *codepoint)
+size_t utf8_check_full(const char *buffer, size_t size, int32_t *codepoint)
{
- int i;
+ size_t i;
int32_t value = 0;
unsigned char u = (unsigned char)buffer[0];
@@ -136,12 +136,12 @@ int utf8_check_full(const char *buffer, int size, int32_t *codepoint)
return 1;
}
-const char *utf8_iterate(const char *buffer, int32_t *codepoint)
+const char *utf8_iterate(const char *buffer, size_t bufsize, int32_t *codepoint)
{
- int count;
+ size_t count;
int32_t value;
- if(!*buffer)
+ if(!bufsize)
return buffer;
count = utf8_check_first(buffer[0]);
@@ -152,7 +152,7 @@ const char *utf8_iterate(const char *buffer, int32_t *codepoint)
value = (unsigned char)buffer[0];
else
{
- if(!utf8_check_full(buffer, count, &value))
+ if(count > bufsize || !utf8_check_full(buffer, count, &value))
return NULL;
}
@@ -162,21 +162,18 @@ const char *utf8_iterate(const char *buffer, int32_t *codepoint)
return buffer + count;
}
-int utf8_check_string(const char *string, int length)
+int utf8_check_string(const char *string, size_t length)
{
- int i;
-
- if(length == -1)
- length = strlen(string);
+ size_t i;
for(i = 0; i < length; i++)
{
- int count = utf8_check_first(string[i]);
+ size_t count = utf8_check_first(string[i]);
if(count == 0)
return 0;
else if(count > 1)
{
- if(i + count > length)
+ if(count > length - i)
return 0;
if(!utf8_check_full(&string[i], count, NULL))
diff --git a/src/utf.h b/src/utf.h
index b4f1091..2cebea0 100644
--- a/src/utf.h
+++ b/src/utf.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 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.
@@ -9,19 +9,19 @@
#define UTF_H
#ifdef HAVE_CONFIG_H
-#include <config.h>
+#include <jansson_private_config.h>
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
-int utf8_encode(int codepoint, char *buffer, int *size);
+int utf8_encode(int32_t codepoint, char *buffer, size_t *size);
-int utf8_check_first(char byte);
-int utf8_check_full(const char *buffer, int size, int32_t *codepoint);
-const char *utf8_iterate(const char *buffer, int32_t *codepoint);
+size_t utf8_check_first(char byte);
+size_t utf8_check_full(const char *buffer, size_t size, int32_t *codepoint);
+const char *utf8_iterate(const char *buffer, size_t size, int32_t *codepoint);
-int utf8_check_string(const char *string, int length);
+int utf8_check_string(const char *string, size_t length);
#endif
diff --git a/src/value.c b/src/value.c
index 1b02d90..333d0af 100644
--- a/src/value.c
+++ b/src/value.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 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.
@@ -10,7 +10,7 @@
#endif
#ifdef HAVE_CONFIG_H
-#include <config.h>
+#include <jansson_private_config.h>
#endif
#include <stddef.h>
@@ -29,8 +29,10 @@
/* Work around nonstandard isnan() and isinf() implementations */
#ifndef isnan
+#ifndef __sun
static JSON_INLINE int isnan(double x) { return x != x; }
#endif
+#endif
#ifndef isinf
static JSON_INLINE int isinf(double x) { return !isnan(x) && isnan(x - x); }
#endif
@@ -92,7 +94,7 @@ json_t *json_object_get(const json_t *json, const char *key)
{
json_object_t *object;
- if(!json_is_object(json))
+ if(!key || !json_is_object(json))
return NULL;
object = json_to_object(json);
@@ -124,7 +126,7 @@ int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value)
int json_object_set_new(json_t *json, const char *key, json_t *value)
{
- if(!key || !utf8_check_string(key, -1))
+ if(!key || !utf8_check_string(key, strlen(key)))
{
json_decref(value);
return -1;
@@ -137,7 +139,7 @@ int json_object_del(json_t *json, const char *key)
{
json_object_t *object;
- if(!json_is_object(json))
+ if(!key || !json_is_object(json))
return -1;
object = json_to_object(json);
@@ -636,33 +638,68 @@ static json_t *json_array_deep_copy(const json_t *array)
/*** string ***/
-json_t *json_string_nocheck(const char *value)
+static json_t *string_create(const char *value, size_t len, int own)
{
+ char *v;
json_string_t *string;
if(!value)
return NULL;
+ if(own)
+ v = (char *)value;
+ else {
+ v = jsonp_strndup(value, len);
+ if(!v)
+ return NULL;
+ }
+
string = jsonp_malloc(sizeof(json_string_t));
- if(!string)
+ if(!string) {
+ if(!own)
+ jsonp_free(v);
return NULL;
+ }
json_init(&string->json, JSON_STRING);
+ string->value = v;
+ string->length = len;
- string->value = jsonp_strdup(value);
- if(!string->value) {
- jsonp_free(string);
+ return &string->json;
+}
+
+json_t *json_string_nocheck(const char *value)
+{
+ if(!value)
return NULL;
- }
- return &string->json;
+ return string_create(value, strlen(value), 0);
+}
+
+json_t *json_stringn_nocheck(const char *value, size_t len)
+{
+ return string_create(value, len, 0);
+}
+
+/* this is private; "steal" is not a public API concept */
+json_t *jsonp_stringn_nocheck_own(const char *value, size_t len)
+{
+ return string_create(value, len, 1);
}
json_t *json_string(const char *value)
{
- if(!value || !utf8_check_string(value, -1))
+ if(!value)
return NULL;
- return json_string_nocheck(value);
+ return json_stringn(value, strlen(value));
+}
+
+json_t *json_stringn(const char *value, size_t len)
+{
+ if(!value || !utf8_check_string(value, len))
+ return NULL;
+
+ return json_stringn_nocheck(value, len);
}
const char *json_string_value(const json_t *json)
@@ -673,31 +710,56 @@ const char *json_string_value(const json_t *json)
return json_to_string(json)->value;
}
+size_t json_string_length(const json_t *json)
+{
+ if(!json_is_string(json))
+ return 0;
+
+ return json_to_string(json)->length;
+}
+
int json_string_set_nocheck(json_t *json, const char *value)
{
+ if(!value)
+ return -1;
+
+ return json_string_setn_nocheck(json, value, strlen(value));
+}
+
+int json_string_setn_nocheck(json_t *json, const char *value, size_t len)
+{
char *dup;
json_string_t *string;
if(!json_is_string(json) || !value)
return -1;
- dup = jsonp_strdup(value);
+ dup = jsonp_strndup(value, len);
if(!dup)
return -1;
string = json_to_string(json);
jsonp_free(string->value);
string->value = dup;
+ string->length = len;
return 0;
}
int json_string_set(json_t *json, const char *value)
{
- if(!value || !utf8_check_string(value, -1))
+ if(!value)
+ return -1;
+
+ return json_string_setn(json, value, strlen(value));
+}
+
+int json_string_setn(json_t *json, const char *value, size_t len)
+{
+ if(!value || !utf8_check_string(value, len))
return -1;
- return json_string_set_nocheck(json, value);
+ return json_string_setn_nocheck(json, value, len);
}
static void json_delete_string(json_string_t *string)
@@ -708,12 +770,25 @@ static void json_delete_string(json_string_t *string)
static int json_string_equal(json_t *string1, json_t *string2)
{
- return strcmp(json_string_value(string1), json_string_value(string2)) == 0;
+ json_string_t *s1, *s2;
+
+ if(!json_is_string(string1) || !json_is_string(string2))
+ return 0;
+
+ s1 = json_to_string(string1);
+ s2 = json_to_string(string2);
+ return s1->length == s2->length && !memcmp(s1->value, s2->value, s1->length);
}
static json_t *json_string_copy(const json_t *string)
{
- return json_string_nocheck(json_string_value(string));
+ json_string_t *s;
+
+ if(!json_is_string(string))
+ return NULL;
+
+ s = json_to_string(string);
+ return json_stringn_nocheck(s->value, s->length);
}