diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/dump.c | 22 | ||||
-rw-r--r-- | src/hashtable.c | 13 | ||||
-rw-r--r-- | src/hashtable.h | 2 | ||||
-rw-r--r-- | src/hashtable_seed.c | 2 | ||||
-rw-r--r-- | src/jansson.def | 5 | ||||
-rw-r--r-- | src/jansson.h | 26 | ||||
-rw-r--r-- | src/jansson_config.h.in | 2 | ||||
-rw-r--r-- | src/jansson_private.h | 10 | ||||
-rw-r--r-- | src/load.c | 106 | ||||
-rw-r--r-- | src/lookup3.h | 2 | ||||
-rw-r--r-- | src/memory.c | 19 | ||||
-rw-r--r-- | src/pack_unpack.c | 74 | ||||
-rw-r--r-- | src/strbuffer.c | 2 | ||||
-rw-r--r-- | src/strbuffer.h | 2 | ||||
-rw-r--r-- | src/strconv.c | 4 | ||||
-rw-r--r-- | src/utf.c | 29 | ||||
-rw-r--r-- | src/utf.h | 14 | ||||
-rw-r--r-- | src/value.c | 113 |
18 files changed, 302 insertions, 145 deletions
@@ -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 @@ -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 @@ -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)) @@ -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); } |