diff options
author | Aaron Plattner <aplattner@nvidia.com> | 2014-04-11 10:18:17 -0700 |
---|---|---|
committer | Aaron Plattner <aplattner@nvidia.com> | 2014-04-11 10:18:17 -0700 |
commit | e3ce465d6a1968f341da16e6c65d3540a301fef2 (patch) | |
tree | d6ae9382d163a714082c6fdc40c6b0225c0fdb1f | |
parent | 5c353a9cec52c64411343d05a8a87930d6d43579 (diff) |
331.67331.67
-rw-r--r-- | doc/version.mk | 2 | ||||
-rw-r--r-- | samples/version.mk | 2 | ||||
-rw-r--r-- | src/Makefile | 5 | ||||
-rw-r--r-- | src/gtk+-2.x/ctkappprofile.c | 6 | ||||
-rw-r--r-- | src/gtk+-2.x/ctkcolorcorrection.c | 48 | ||||
-rw-r--r-- | src/jansson/dump.c | 30 | ||||
-rw-r--r-- | src/jansson/hashtable.c | 78 | ||||
-rw-r--r-- | src/jansson/hashtable.h | 5 | ||||
-rw-r--r-- | src/jansson/hashtable_seed.c | 277 | ||||
-rw-r--r-- | src/jansson/jansson.h | 57 | ||||
-rw-r--r-- | src/jansson/jansson_config.h | 47 | ||||
-rw-r--r-- | src/jansson/jansson_private.h | 11 | ||||
-rw-r--r-- | src/jansson/jansson_private_config.h | 57 | ||||
-rw-r--r-- | src/jansson/load.c | 123 | ||||
-rw-r--r-- | src/jansson/lookup3.h | 366 | ||||
-rw-r--r-- | src/jansson/memory.c | 16 | ||||
-rw-r--r-- | src/jansson/pack_unpack.c | 290 | ||||
-rw-r--r-- | src/jansson/strbuffer.c | 11 | ||||
-rw-r--r-- | src/jansson/strbuffer.h | 4 | ||||
-rw-r--r-- | src/jansson/strconv.c | 5 | ||||
-rw-r--r-- | src/jansson/utf.c | 29 | ||||
-rw-r--r-- | src/jansson/utf.h | 34 | ||||
-rw-r--r-- | src/jansson/value.c | 168 | ||||
-rw-r--r-- | src/src.mk | 23 | ||||
-rw-r--r-- | src/version.mk | 2 | ||||
-rw-r--r-- | version.mk | 2 |
26 files changed, 1406 insertions, 292 deletions
diff --git a/doc/version.mk b/doc/version.mk index 1012493..bb1a5bc 100644 --- a/doc/version.mk +++ b/doc/version.mk @@ -1 +1 @@ -NVIDIA_VERSION = 331.49 +NVIDIA_VERSION = 331.67 diff --git a/samples/version.mk b/samples/version.mk index 1012493..bb1a5bc 100644 --- a/samples/version.mk +++ b/samples/version.mk @@ -1 +1 @@ -NVIDIA_VERSION = 331.49 +NVIDIA_VERSION = 331.67 diff --git a/src/Makefile b/src/Makefile index 1790b4f..c299491 100644 --- a/src/Makefile +++ b/src/Makefile @@ -60,7 +60,10 @@ ifndef VDPAU_CFLAGS endif ifndef JANSSON_CFLAGS - JANSSON_CFLAGS = -Wno-cast-qual + JANSSON_CFLAGS = -Wno-cast-qual + JANSSON_CFLAGS += -Wno-strict-prototypes + JANSSON_CFLAGS += -Wno-unused-function + JANSSON_CFLAGS += -DHAVE_CONFIG_H ifeq ($(TARGET_ARCH),armv7l) JANSSON_CFLAGS += -Wno-unused-but-set-variable endif diff --git a/src/gtk+-2.x/ctkappprofile.c b/src/gtk+-2.x/ctkappprofile.c index 939634b..3bf0e09 100644 --- a/src/gtk+-2.x/ctkappprofile.c +++ b/src/gtk+-2.x/ctkappprofile.c @@ -221,11 +221,7 @@ typedef struct _TreeViewColumnTemplate { const gchar *extended_help_text; } TreeViewColumnTemplate; -#if JSON_INTEGER_IS_LONG_LONG -# define JSON_INTEGER_HEX_FORMAT "llx" -#else -# define JSON_INTEGER_HEX_FORMAT "lx" -#endif +#define JSON_INTEGER_HEX_FORMAT "llx" /* * Function prototypes diff --git a/src/gtk+-2.x/ctkcolorcorrection.c b/src/gtk+-2.x/ctkcolorcorrection.c index 6afb93f..5ed46cf 100644 --- a/src/gtk+-2.x/ctkcolorcorrection.c +++ b/src/gtk+-2.x/ctkcolorcorrection.c @@ -83,6 +83,8 @@ flush_attribute_channel_values (CtkColorCorrection *, gint, gint); static void ctk_color_correction_class_init(CtkColorCorrectionClass *); +static void ctk_color_correction_finalize(GObject *); + static void apply_parsed_attribute_list(CtkColorCorrection *, ParsedAttribute *); @@ -158,6 +160,8 @@ static void ctk_color_correction_class_init(CtkColorCorrectionClass *ctk_color_correction_class) { + GObjectClass *gobject_class = (GObjectClass *)ctk_color_correction_class; + signals[CHANGED] = g_signal_new("changed", G_OBJECT_CLASS_TYPE(ctk_color_correction_class), @@ -166,6 +170,50 @@ ctk_color_correction_class_init(CtkColorCorrectionClass NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + gobject_class->finalize = ctk_color_correction_finalize; +} + + +static void ctk_color_correction_finalize(GObject *object) +{ + CtkColorCorrection *ctk_color_correction = CTK_COLOR_CORRECTION(object); + + if (ctk_color_correction->confirm_timer) { + /* + * This situation comes, if user perform VT-switching + * without confirmation of color-correction settings. + */ + gint attr, ch; + unsigned int channels = 0; + unsigned int attributes = 0; + + /* kill the timer */ + g_source_remove(ctk_color_correction->confirm_timer); + ctk_color_correction->confirm_timer = 0; + + /* + * Reset color settings to previous state, + * since user did not confirm settings yet. + */ + for (attr = CONTRAST_INDEX; attr <= GAMMA_INDEX; attr++) { + for (ch = RED; ch <= ALL_CHANNELS_INDEX; ch++) { + /* Check for attribute channel value change. */ + int index = attr - CONTRAST_INDEX; + + ctk_color_correction->cur_slider_val[index][ch] = + ctk_color_correction->prev_slider_val[index][ch]; + + attributes |= (1 << attr); + channels |= (1 << ch); + } + } + + NvCtrlSetColorAttributes(ctk_color_correction->handle, + ctk_color_correction->cur_slider_val[CONTRAST], + ctk_color_correction->cur_slider_val[BRIGHTNESS], + ctk_color_correction->cur_slider_val[GAMMA], + attributes | channels); + } } diff --git a/src/jansson/dump.c b/src/jansson/dump.c index 2c7dee9..7eddd5a 100644 --- a/src/jansson/dump.c +++ b/src/jansson/dump.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 <stdio.h> #include <stdlib.h> #include <string.h> @@ -38,7 +41,7 @@ static int dump_to_file(const char *buffer, size_t size, void *data) } /* 32 spaces (the maximum indentation size) */ -static char whitespace[] = " "; +static const char whitespace[] = " "; static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump, void *data) { @@ -62,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; @@ -123,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; } @@ -136,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; } @@ -171,6 +175,9 @@ static int object_key_compare_serials(const void *key1, const void *key2) static int do_dump(const json_t *json, size_t flags, int depth, json_dump_callback_t dump, void *data) { + if(!json) + return -1; + switch(json_typeof(json)) { case JSON_NULL: return dump("null", 4, data); @@ -209,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: { @@ -330,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)) { @@ -366,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/jansson/hashtable.c b/src/jansson/hashtable.c index bcbaa8c..4c4b565 100644 --- a/src/jansson/hashtable.c +++ b/src/jansson/hashtable.c @@ -1,12 +1,21 @@ /* - * Copyright (c) 2009-2012 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 <jansson_private_config.h> +#endif + #include <stdlib.h> #include <string.h> + +#if HAVE_STDINT_H +#include <stdint.h> +#endif + #include <jansson_config.h> /* for JSON_INLINE */ #include "jansson_private.h" /* for container_of() */ #include "hashtable.h" @@ -15,24 +24,13 @@ typedef struct hashtable_list list_t; typedef struct hashtable_pair pair_t; typedef struct hashtable_bucket bucket_t; -#define list_to_pair(list_) container_of(list_, pair_t, list) - -/* From http://www.cse.yorku.ca/~oz/hash.html */ -static size_t hash_str(const void *ptr) -{ - const char *str = (const char *)ptr; +extern volatile uint32_t hashtable_seed; - size_t hash = 5381; - size_t c; +/* Implementation of the hash function */ +#include "lookup3.h" - while((c = (size_t)*str)) - { - hash = ((hash << 5) + hash) + c; - str++; - } - - return hash; -} +#define list_to_pair(list_) container_of(list_, pair_t, list) +#define hash_str(key) ((size_t)hashlittle((key), strlen(key), hashtable_seed)) static JSON_INLINE void list_init(list_t *list) { @@ -74,19 +72,6 @@ static void insert_to_bucket(hashtable_t *hashtable, bucket_t *bucket, } } -static const size_t primes[] = { - 5, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, - 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, - 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, - 805306457, 1610612741 -}; - -static JSON_INLINE size_t num_buckets(hashtable_t *hashtable) -{ - return primes[hashtable->num_buckets]; -} - - static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket, const char *key, size_t hash) { @@ -120,7 +105,7 @@ static int hashtable_do_del(hashtable_t *hashtable, bucket_t *bucket; size_t index; - index = hash % num_buckets(hashtable); + index = hash & hashmask(hashtable->order); bucket = &hashtable->buckets[index]; pair = hashtable_find_pair(hashtable, bucket, key, hash); @@ -167,14 +152,14 @@ static int hashtable_do_rehash(hashtable_t *hashtable) jsonp_free(hashtable->buckets); - hashtable->num_buckets++; - new_size = num_buckets(hashtable); + hashtable->order++; + new_size = hashsize(hashtable->order); hashtable->buckets = jsonp_malloc(new_size * sizeof(bucket_t)); if(!hashtable->buckets) return -1; - for(i = 0; i < num_buckets(hashtable); i++) + for(i = 0; i < hashsize(hashtable->order); i++) { hashtable->buckets[i].first = hashtable->buckets[i].last = &hashtable->list; @@ -199,14 +184,14 @@ int hashtable_init(hashtable_t *hashtable) size_t i; hashtable->size = 0; - hashtable->num_buckets = 0; /* index to primes[] */ - hashtable->buckets = jsonp_malloc(num_buckets(hashtable) * sizeof(bucket_t)); + hashtable->order = 3; + hashtable->buckets = jsonp_malloc(hashsize(hashtable->order) * sizeof(bucket_t)); if(!hashtable->buckets) return -1; list_init(&hashtable->list); - for(i = 0; i < num_buckets(hashtable); i++) + for(i = 0; i < hashsize(hashtable->order); i++) { hashtable->buckets[i].first = hashtable->buckets[i].last = &hashtable->list; @@ -230,12 +215,12 @@ int hashtable_set(hashtable_t *hashtable, size_t hash, index; /* rehash if the load ratio exceeds 1 */ - if(hashtable->size >= num_buckets(hashtable)) + if(hashtable->size >= hashsize(hashtable->order)) if(hashtable_do_rehash(hashtable)) return -1; hash = hash_str(key); - index = hash % num_buckets(hashtable); + index = hash & hashmask(hashtable->order); bucket = &hashtable->buckets[index]; pair = hashtable_find_pair(hashtable, bucket, key, hash); @@ -249,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; @@ -273,7 +265,7 @@ void *hashtable_get(hashtable_t *hashtable, const char *key) bucket_t *bucket; hash = hash_str(key); - bucket = &hashtable->buckets[hash % num_buckets(hashtable)]; + bucket = &hashtable->buckets[hash & hashmask(hashtable->order)]; pair = hashtable_find_pair(hashtable, bucket, key, hash); if(!pair) @@ -294,7 +286,7 @@ void hashtable_clear(hashtable_t *hashtable) hashtable_do_clear(hashtable); - for(i = 0; i < num_buckets(hashtable); i++) + for(i = 0; i < hashsize(hashtable->order); i++) { hashtable->buckets[i].first = hashtable->buckets[i].last = &hashtable->list; @@ -316,7 +308,7 @@ void *hashtable_iter_at(hashtable_t *hashtable, const char *key) bucket_t *bucket; hash = hash_str(key); - bucket = &hashtable->buckets[hash % num_buckets(hashtable)]; + bucket = &hashtable->buckets[hash & hashmask(hashtable->order)]; pair = hashtable_find_pair(hashtable, bucket, key, hash); if(!pair) diff --git a/src/jansson/hashtable.h b/src/jansson/hashtable.h index de1df26..f54c3fe 100644 --- a/src/jansson/hashtable.h +++ b/src/jansson/hashtable.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2012 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. @@ -32,7 +32,7 @@ struct hashtable_bucket { typedef struct hashtable { size_t size; struct hashtable_bucket *buckets; - size_t num_buckets; /* index to primes[] */ + size_t order; /* hashtable has pow(2, order) buckets */ struct hashtable_list list; } hashtable_t; @@ -40,6 +40,7 @@ typedef struct hashtable { #define hashtable_key_to_iter(key_) \ (&(container_of(key_, struct hashtable_pair, key)->list)) + /** * hashtable_init - Initialize a hashtable object * diff --git a/src/jansson/hashtable_seed.c b/src/jansson/hashtable_seed.c new file mode 100644 index 0000000..751e0e3 --- /dev/null +++ b/src/jansson/hashtable_seed.c @@ -0,0 +1,277 @@ +/* Generate sizeof(uint32_t) bytes of as random data as possible to seed + the hash function. +*/ + +#ifdef HAVE_CONFIG_H +#include <jansson_private_config.h> +#endif + +#include <stdio.h> +#include <time.h> + +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif + +#ifdef HAVE_SCHED_H +#include <sched.h> +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif + +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#if defined(_WIN32) +/* For GetModuleHandle(), GetProcAddress() and GetCurrentProcessId() */ +#include <windows.h> +#endif + +#include "jansson.h" + + +static uint32_t buf_to_uint32(char *data) { + size_t i; + uint32_t result = 0; + + for (i = 0; i < sizeof(uint32_t); i++) + result = (result << 8) | (unsigned char)data[i]; + + return result; +} + + + +/* /dev/urandom */ +#if !defined(_WIN32) && defined(USE_URANDOM) +static int seed_from_urandom(uint32_t *seed) { + /* Use unbuffered I/O if we have open(), close() and read(). Otherwise + fall back to fopen() */ + + char data[sizeof(uint32_t)]; + int ok; + +#if defined(HAVE_OPEN) && defined(HAVE_CLOSE) && defined(HAVE_READ) + int urandom; + urandom = open("/dev/urandom", O_RDONLY); + if (urandom == -1) + return 1; + + ok = read(urandom, data, sizeof(uint32_t)) == sizeof(uint32_t); + close(urandom); +#else + FILE *urandom; + + urandom = fopen("/dev/urandom", "rb"); + if (!urandom) + return 1; + + ok = fread(data, 1, sizeof(uint32_t), urandom) == sizeof(uint32_t); + fclose(urandom); +#endif + + if (!ok) + return 1; + + *seed = buf_to_uint32(data); + return 0; +} +#endif + +/* Windows Crypto API */ +#if defined(_WIN32) && defined(USE_WINDOWS_CRYPTOAPI) +#include <wincrypt.h> + +typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTA)(HCRYPTPROV *phProv, LPCSTR pszContainer, LPCSTR pszProvider, DWORD dwProvType, DWORD dwFlags); +typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer); +typedef BOOL (WINAPI *CRYPTRELEASECONTEXT)(HCRYPTPROV hProv, DWORD dwFlags); + +static int seed_from_windows_cryptoapi(uint32_t *seed) +{ + HINSTANCE hAdvAPI32 = NULL; + CRYPTACQUIRECONTEXTA pCryptAcquireContext = NULL; + CRYPTGENRANDOM pCryptGenRandom = NULL; + CRYPTRELEASECONTEXT pCryptReleaseContext = NULL; + HCRYPTPROV hCryptProv = 0; + BYTE data[sizeof(uint32_t)]; + int ok; + + hAdvAPI32 = GetModuleHandle(TEXT("advapi32.dll")); + if(hAdvAPI32 == NULL) + return 1; + + pCryptAcquireContext = (CRYPTACQUIRECONTEXTA)GetProcAddress(hAdvAPI32, "CryptAcquireContextA"); + if (!pCryptAcquireContext) + return 1; + + pCryptGenRandom = (CRYPTGENRANDOM)GetProcAddress(hAdvAPI32, "CryptGenRandom"); + if (!pCryptGenRandom) + return 1; + + pCryptReleaseContext = (CRYPTRELEASECONTEXT)GetProcAddress(hAdvAPI32, "CryptReleaseContext"); + if (!pCryptReleaseContext) + return 1; + + if (!pCryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + return 1; + + ok = pCryptGenRandom(hCryptProv, sizeof(uint32_t), data); + pCryptReleaseContext(hCryptProv, 0); + + if (!ok) + return 1; + + *seed = buf_to_uint32((char *)data); + return 0; +} +#endif + +/* gettimeofday() and getpid() */ +static int seed_from_timestamp_and_pid(uint32_t *seed) { +#ifdef HAVE_GETTIMEOFDAY + /* XOR of seconds and microseconds */ + struct timeval tv; + gettimeofday(&tv, NULL); + *seed = (uint32_t)tv.tv_sec ^ (uint32_t)tv.tv_usec; +#else + /* Seconds only */ + *seed = (uint32_t)time(NULL); +#endif + + /* XOR with PID for more randomness */ +#if defined(_WIN32) + *seed ^= (uint32_t)GetCurrentProcessId(); +#elif defined(HAVE_GETPID) + *seed ^= (uint32_t)getpid(); +#endif + + return 0; +} + +static uint32_t generate_seed() { + uint32_t seed; + int done = 0; + +#if !defined(_WIN32) && defined(USE_URANDOM) + if (!done && seed_from_urandom(&seed) == 0) + done = 1; +#endif + +#if defined(_WIN32) && defined(USE_WINDOWS_CRYPTOAPI) + if (!done && seed_from_windows_cryptoapi(&seed) == 0) + done = 1; +#endif + + if (!done) { + /* Fall back to timestamp and PID if no better randomness is + available */ + seed_from_timestamp_and_pid(&seed); + } + + /* Make sure the seed is never zero */ + if (seed == 0) + seed = 1; + + return seed; +} + + +volatile uint32_t hashtable_seed = 0; + +#if defined(HAVE_ATOMIC_BUILTINS) && (defined(HAVE_SCHED_YIELD) || !defined(_WIN32)) +static volatile char seed_initialized = 0; + +void json_object_seed(size_t seed) { + uint32_t new_seed = (uint32_t)seed; + + if (hashtable_seed == 0) { + if (__atomic_test_and_set(&seed_initialized, __ATOMIC_RELAXED) == 0) { + /* Do the seeding ourselves */ + if (new_seed == 0) + new_seed = generate_seed(); + + __atomic_store_n(&hashtable_seed, new_seed, __ATOMIC_RELEASE); + } else { + /* Wait for another thread to do the seeding */ + do { +#ifdef HAVE_SCHED_YIELD + sched_yield(); +#endif + } while(__atomic_load_n(&hashtable_seed, __ATOMIC_ACQUIRE) == 0); + } + } +} +#elif defined(HAVE_SYNC_BUILTINS) && (defined(HAVE_SCHED_YIELD) || !defined(_WIN32)) +void json_object_seed(size_t seed) { + uint32_t new_seed = (uint32_t)seed; + + if (hashtable_seed == 0) { + if (new_seed == 0) { + /* Explicit synchronization fences are not supported by the + __sync builtins, so every thread getting here has to + generate the seed value. + */ + new_seed = generate_seed(); + } + + do { + if (__sync_bool_compare_and_swap(&hashtable_seed, 0, new_seed)) { + /* We were the first to seed */ + break; + } else { + /* Wait for another thread to do the seeding */ +#ifdef HAVE_SCHED_YIELD + sched_yield(); +#endif + } + } while(hashtable_seed == 0); + } +} +#elif defined(_WIN32) +static long seed_initialized = 0; +void json_object_seed(size_t seed) { + uint32_t new_seed = (uint32_t)seed; + + if (hashtable_seed == 0) { + if (InterlockedIncrement(&seed_initialized) == 1) { + /* Do the seeding ourselves */ + if (new_seed == 0) + new_seed = generate_seed(); + + hashtable_seed = new_seed; + } else { + /* Wait for another thread to do the seeding */ + do { + SwitchToThread(); + } while (hashtable_seed == 0); + } + } +} +#else +/* Fall back to a thread-unsafe version */ +void json_object_seed(size_t seed) { + uint32_t new_seed = (uint32_t)seed; + + if (hashtable_seed == 0) { + if (new_seed == 0) + new_seed = generate_seed(); + + hashtable_seed = new_seed; + } +} +#endif diff --git a/src/jansson/jansson.h b/src/jansson/jansson.h index 352c6ce..85215f4 100644 --- a/src/jansson/jansson.h +++ b/src/jansson/jansson.h @@ -1,5 +1,5 @@ /* - * 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. @@ -21,11 +21,11 @@ extern "C" { /* version */ #define JANSSON_MAJOR_VERSION 2 -#define JANSSON_MINOR_VERSION 4 +#define JANSSON_MINOR_VERSION 6 #define JANSSON_MICRO_VERSION 0 /* Micro version is omitted if it's 0 */ -#define JANSSON_VERSION "2.4" +#define JANSSON_VERSION "2.6" /* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */ @@ -47,11 +47,12 @@ typedef enum { JSON_NULL } json_type; -typedef struct { +typedef struct json_t { json_type type; size_t refcount; } json_t; +#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */ #if JSON_INTEGER_IS_LONG_LONG #ifdef _WIN32 #define JSON_INTEGER_FORMAT "I64d" @@ -63,25 +64,29 @@ typedef long long json_int_t; #define JSON_INTEGER_FORMAT "ld" typedef long json_int_t; #endif /* JSON_INTEGER_IS_LONG_LONG */ +#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); @@ -124,6 +129,7 @@ typedef struct { /* getters, setters, manipulation */ +void json_object_seed(size_t seed); size_t json_object_size(const json_t *object); json_t *json_object_get(const json_t *object, const char *key); int json_object_set_new(json_t *object, const char *key, json_t *value); @@ -146,6 +152,11 @@ int json_object_iter_set_new(json_t *object, void *iter, json_t *value); key && (value = json_object_iter_value(json_object_key_to_iter(key))); \ key = json_object_iter_key(json_object_iter_next(object, json_object_key_to_iter(key)))) +#define json_array_foreach(array, index, value) \ + for(index = 0; \ + index < json_array_size(array) && (value = json_array_get(array, index)); \ + index++) + static JSON_INLINE int json_object_set(json_t *object, const char *key, json_t *value) { @@ -174,9 +185,9 @@ int json_array_clear(json_t *array); int json_array_extend(json_t *array, json_t *other); static JSON_INLINE -int json_array_set(json_t *array, size_t index, json_t *value) +int json_array_set(json_t *array, size_t ind, json_t *value) { - return json_array_set_new(array, index, json_incref(value)); + return json_array_set_new(array, ind, json_incref(value)); } static JSON_INLINE @@ -186,22 +197,24 @@ int json_array_append(json_t *array, json_t *value) } static JSON_INLINE -int json_array_insert(json_t *array, size_t index, json_t *value) +int json_array_insert(json_t *array, size_t ind, json_t *value) { - return json_array_insert_new(array, index, json_incref(value)); + return json_array_insert_new(array, ind, json_incref(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, ...); @@ -224,14 +237,16 @@ int json_equal(json_t *value1, json_t *value2); /* copying */ json_t *json_copy(json_t *value); -json_t *json_deep_copy(json_t *value); +json_t *json_deep_copy(const json_t *value); /* decoding */ -#define JSON_REJECT_DUPLICATES 0x1 -#define JSON_DISABLE_EOF_CHECK 0x2 -#define JSON_DECODE_ANY 0x4 +#define JSON_REJECT_DUPLICATES 0x1 +#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/jansson_config.h b/src/jansson/jansson_config.h index e576cd1..31ad6b3 100644 --- a/src/jansson/jansson_config.h +++ b/src/jansson/jansson_config.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2012 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. @@ -9,15 +9,38 @@ * Jansson, namely those things that affect the public API in * jansson.h. * - * The configure script copies this file to jansson_config.h and - * replaces @var@ substitutions by values that fit your system. If you - * cannot run the configure script, you can do the value substitution - * by hand. + * The CMake system will generate the jansson_config.h file and + * copy it to the build and install directories. */ #ifndef JANSSON_CONFIG_H #define JANSSON_CONFIG_H +/* Define this so that we can disable scattered automake configuration in source files */ +#ifndef JANSSON_USING_CMAKE +#define JANSSON_USING_CMAKE +#endif + +/* Note: when using cmake, JSON_INTEGER_IS_LONG_LONG is not defined nor used, + * as we will also check for __int64 etc types. + * (the definition was used in the automake system) */ + +/* Bring in the cmake-detected defines */ +#define HAVE_STDINT_H 1 +/* #undef HAVE_INTTYPES_H */ +#define HAVE_SYS_TYPES_H 1 + +/* Include our standard type header for the integer typedef */ + +#if defined(HAVE_STDINT_H) +# include <stdint.h> +#elif defined(HAVE_INTTYPES_H) +# include <inttypes.h> +#elif defined(HAVE_SYS_TYPES_H) +# include <sys/types.h> +#endif + + /* If your compiler supports the inline keyword in C, JSON_INLINE is defined to `inline', otherwise empty. In C++, the inline is always supported. */ @@ -27,13 +50,15 @@ #define JSON_INLINE inline #endif -/* If your compiler supports the `long long` type and the strtoll() - library function, JSON_INTEGER_IS_LONG_LONG is defined to 1, - otherwise to 0. */ -#define JSON_INTEGER_IS_LONG_LONG 1 -/* If locale.h and localeconv() are available, define to 1, - otherwise to 0. */ +#define json_int_t long long +#define json_strtoint strtoll +#define JSON_INTEGER_FORMAT "lld" + + +/* If locale.h and localeconv() are available, define to 1, otherwise to 0. */ #define JSON_HAVE_LOCALECONV 1 + + #endif diff --git a/src/jansson/jansson_private.h b/src/jansson/jansson_private.h index 7d6d09d..c6f437c 100644 --- a/src/jansson/jansson_private.h +++ b/src/jansson/jansson_private.h @@ -1,5 +1,5 @@ /* - * 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. @@ -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, @@ -81,7 +86,9 @@ int jsonp_dtostr(char *buffer, size_t size, double value); /* Wrappers for custom memory functions */ 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/jansson/jansson_private_config.h b/src/jansson/jansson_private_config.h new file mode 100644 index 0000000..cbff15e --- /dev/null +++ b/src/jansson/jansson_private_config.h @@ -0,0 +1,57 @@ +#if defined(NV_LINUX) +# define HAVE_ENDIAN_H 1 +#endif + +/* Prevent value.c from overriding Solaris's builtin isnan() */ +#if defined(NV_SUNOS) +# define isnan isnan +#endif + +#define HAVE_FCNTL_H 1 +#define HAVE_SCHED_H 1 +#define HAVE_UNISTD_H 1 +#define HAVE_SYS_PARAM_H 1 +#define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_TIME_H 1 +#define HAVE_SYS_TYPES_H 1 +#define HAVE_STDINT_H 1 + +#define HAVE_CLOSE 1 +#define HAVE_GETPID 1 +#define HAVE_GETTIMEOFDAY 1 +#define HAVE_OPEN 1 +#define HAVE_READ 1 +#define HAVE_SCHED_YIELD 1 + +/* #undef HAVE_SYNC_BUILTINS */ +/* #undef HAVE_ATOMIC_BUILTINS */ + +#define HAVE_LOCALE_H 1 +#define HAVE_SETLOCALE 1 + +#define HAVE_INT32_T 1 +#ifndef HAVE_INT32_T +# define int32_t int32_t +#endif + +#define HAVE_UINT32_T 1 +#ifndef HAVE_UINT32_T +# define uint32_t uint32_t +#endif + +#define HAVE_SSIZE_T 1 + +#ifndef HAVE_SSIZE_T +# define ssize_t +#endif + +#define HAVE_SNPRINTF 1 + +#ifndef HAVE_SNPRINTF +# define snprintf snprintf +#endif + +/* #undef HAVE_VSNPRINTF */ + +#define USE_URANDOM 1 +#define USE_WINDOWS_CRYPTOAPI 1 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; } diff --git a/src/jansson/lookup3.h b/src/jansson/lookup3.h new file mode 100644 index 0000000..8847483 --- /dev/null +++ b/src/jansson/lookup3.h @@ -0,0 +1,366 @@ +/* +------------------------------------------------------------------------------- +lookup3.c, by Bob Jenkins, May 2006, Public Domain. + +These are functions for producing 32-bit hashes for hash table lookup. +hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() +are externally useful functions. Routines to test the hash are included +if SELF_TEST is defined. You can use this free for any purpose. It's in +the public domain. It has no warranty. + +You probably want to use hashlittle(). hashlittle() and hashbig() +hash byte arrays. hashlittle() is is faster than hashbig() on +little-endian machines. Intel and AMD are little-endian machines. +On second thought, you probably want hashlittle2(), which is identical to +hashlittle() except it returns two 32-bit hashes for the price of one. +You could implement hashbig2() if you wanted but I haven't bothered here. + +If you want to find a hash of, say, exactly 7 integers, do + a = i1; b = i2; c = i3; + mix(a,b,c); + a += i4; b += i5; c += i6; + mix(a,b,c); + a += i7; + final(a,b,c); +then use c as the hash value. If you have a variable length array of +4-byte integers to hash, use hashword(). If you have a byte array (like +a character string), use hashlittle(). If you have several byte arrays, or +a mix of things, see the comments above hashlittle(). + +Why is this so big? I read 12 bytes at a time into 3 4-byte integers, +then mix those integers. This is fast (you can do a lot more thorough +mixing with 12*3 instructions on 3 integers than you can with 3 instructions +on 1 byte), but shoehorning those bytes into integers efficiently is messy. +------------------------------------------------------------------------------- +*/ + +#include <stdlib.h> + +#ifdef HAVE_CONFIG_H +#include <jansson_private_config.h> +#endif + +#ifdef HAVE_STDINT_H +#include <stdint.h> /* defines uint32_t etc */ +#endif + +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> /* attempt to define endianness */ +#endif + +#ifdef HAVE_ENDIAN_H +# include <endian.h> /* attempt to define endianness */ +#endif + +/* + * My best guess at if you are big-endian or little-endian. This may + * need adjustment. + */ +#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ + __BYTE_ORDER == __LITTLE_ENDIAN) || \ + (defined(i386) || defined(__i386__) || defined(__i486__) || \ + defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL)) +# define HASH_LITTLE_ENDIAN 1 +# define HASH_BIG_ENDIAN 0 +#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ + __BYTE_ORDER == __BIG_ENDIAN) || \ + (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel)) +# define HASH_LITTLE_ENDIAN 0 +# define HASH_BIG_ENDIAN 1 +#else +# define HASH_LITTLE_ENDIAN 0 +# define HASH_BIG_ENDIAN 0 +#endif + +#define hashsize(n) ((uint32_t)1<<(n)) +#define hashmask(n) (hashsize(n)-1) +#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) + +/* +------------------------------------------------------------------------------- +mix -- mix 3 32-bit values reversibly. + +This is reversible, so any information in (a,b,c) before mix() is +still in (a,b,c) after mix(). + +If four pairs of (a,b,c) inputs are run through mix(), or through +mix() in reverse, there are at least 32 bits of the output that +are sometimes the same for one pair and different for another pair. +This was tested for: +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that +satisfy this are + 4 6 8 16 19 4 + 9 15 3 18 27 15 + 14 9 3 7 17 3 +Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing +for "differ" defined as + with a one-bit base and a two-bit delta. I +used http://burtleburtle.net/bob/hash/avalanche.html to choose +the operations, constants, and arrangements of the variables. + +This does not achieve avalanche. There are input bits of (a,b,c) +that fail to affect some output bits of (a,b,c), especially of a. The +most thoroughly mixed value is c, but it doesn't really even achieve +avalanche in c. + +This allows some parallelism. Read-after-writes are good at doubling +the number of bits affected, so the goal of mixing pulls in the opposite +direction as the goal of parallelism. I did what I could. Rotates +seem to cost as much as shifts on every machine I could lay my hands +on, and rotates are much kinder to the top and bottom bits, so I used +rotates. +------------------------------------------------------------------------------- +*/ +#define mix(a,b,c) \ +{ \ + a -= c; a ^= rot(c, 4); c += b; \ + b -= a; b ^= rot(a, 6); a += c; \ + c -= b; c ^= rot(b, 8); b += a; \ + a -= c; a ^= rot(c,16); c += b; \ + b -= a; b ^= rot(a,19); a += c; \ + c -= b; c ^= rot(b, 4); b += a; \ +} + +/* +------------------------------------------------------------------------------- +final -- final mixing of 3 32-bit values (a,b,c) into c + +Pairs of (a,b,c) values differing in only a few bits will usually +produce values of c that look totally different. This was tested for +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +These constants passed: + 14 11 25 16 4 14 24 + 12 14 25 16 4 14 24 +and these came close: + 4 8 15 26 3 22 24 + 10 8 15 26 3 22 24 + 11 8 15 26 3 22 24 +------------------------------------------------------------------------------- +*/ +#define final(a,b,c) \ +{ \ + c ^= b; c -= rot(b,14); \ + a ^= c; a -= rot(c,11); \ + b ^= a; b -= rot(a,25); \ + c ^= b; c -= rot(b,16); \ + a ^= c; a -= rot(c,4); \ + b ^= a; b -= rot(a,14); \ + c ^= b; c -= rot(b,24); \ +} + +/* +------------------------------------------------------------------------------- +hashlittle() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + length : the length of the key, counting by bytes + initval : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Two keys differing by one or two bits will have +totally different hash values. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (uint8_t **)k, do it like this: + for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h); + +By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this +code any way you wish, private, educational, or commercial. It's free. + +Use for hash table lookup, or anything where one collision in 2^^32 is +acceptable. Do NOT use for cryptographic purposes. +------------------------------------------------------------------------------- +*/ + +static uint32_t hashlittle(const void *key, size_t length, uint32_t initval) +{ + uint32_t a,b,c; /* internal state */ + union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */ + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + ((uint32_t)length) + initval; + + u.ptr = key; + if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) { + const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ + +#ifdef VALGRIND + const uint8_t *k8; +#endif + + /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * "k[2]&0xffffff" actually reads beyond the end of the string, but + * then masks off the part it's not allowed to read. Because the + * string is aligned, the masked-off tail is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticably faster for short strings (like English words). + */ +#ifndef VALGRIND + + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; + case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; + case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=k[1]&0xffffff; a+=k[0]; break; + case 6 : b+=k[1]&0xffff; a+=k[0]; break; + case 5 : b+=k[1]&0xff; a+=k[0]; break; + case 4 : a+=k[0]; break; + case 3 : a+=k[0]&0xffffff; break; + case 2 : a+=k[0]&0xffff; break; + case 1 : a+=k[0]&0xff; break; + case 0 : return c; /* zero length strings require no mixing */ + } + +#else /* make valgrind happy */ + + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]; break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ + case 1 : a+=k8[0]; break; + case 0 : return c; + } + +#endif /* !valgrind */ + + } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { + const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*--------------- all but last block: aligned reads and different mixing */ + while (length > 12) + { + a += k[0] + (((uint32_t)k[1])<<16); + b += k[2] + (((uint32_t)k[3])<<16); + c += k[4] + (((uint32_t)k[5])<<16); + mix(a,b,c); + length -= 12; + k += 6; + } + + /*----------------------------- handle the last (probably partial) block */ + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[4]+(((uint32_t)k[5])<<16); + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=k[4]; + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=k[2]; + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=k[0]; + break; + case 1 : a+=k8[0]; + break; + case 0 : return c; /* zero length requires no mixing */ + } + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + a += ((uint32_t)k[1])<<8; + a += ((uint32_t)k[2])<<16; + a += ((uint32_t)k[3])<<24; + b += k[4]; + b += ((uint32_t)k[5])<<8; + b += ((uint32_t)k[6])<<16; + b += ((uint32_t)k[7])<<24; + c += k[8]; + c += ((uint32_t)k[9])<<8; + c += ((uint32_t)k[10])<<16; + c += ((uint32_t)k[11])<<24; + mix(a,b,c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch(length) /* all the case statements fall through */ + { + case 12: c+=((uint32_t)k[11])<<24; + case 11: c+=((uint32_t)k[10])<<16; + case 10: c+=((uint32_t)k[9])<<8; + case 9 : c+=k[8]; + case 8 : b+=((uint32_t)k[7])<<24; + case 7 : b+=((uint32_t)k[6])<<16; + case 6 : b+=((uint32_t)k[5])<<8; + case 5 : b+=k[4]; + case 4 : a+=((uint32_t)k[3])<<24; + case 3 : a+=((uint32_t)k[2])<<16; + case 2 : a+=((uint32_t)k[1])<<8; + case 1 : a+=k[0]; + break; + case 0 : return c; + } + } + + final(a,b,c); + return c; +} diff --git a/src/jansson/memory.c b/src/jansson/memory.c index 543ecc4..ca44d6b 100644 --- a/src/jansson/memory.c +++ b/src/jansson/memory.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2012 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,13 +38,19 @@ void jsonp_free(void *ptr) char *jsonp_strdup(const char *str) { + return jsonp_strndup(str, strlen(str)); +} + +char *jsonp_strndup(const char *str, size_t len) +{ char *new_str; - new_str = jsonp_malloc(strlen(str) + 1); + new_str = jsonp_malloc(len + 1); if(!new_str) return NULL; - strcpy(new_str, str); + memcpy(new_str, str, len); + new_str[len] = '\0'; return new_str; } diff --git a/src/jansson/pack_unpack.c b/src/jansson/pack_unpack.c index 39db9b8..af381a5 100644 --- a/src/jansson/pack_unpack.c +++ b/src/jansson/pack_unpack.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2012 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 @@ -12,16 +12,28 @@ #include "utf.h" typedef struct { + int line; + int column; + size_t pos; + char token; +} token_t; + +typedef struct { const char *start; const char *fmt; - char token; + token_t prev_token; + token_t token; + token_t next_token; json_error_t *error; size_t flags; int line; int column; + size_t pos; } scanner_t; -static const char *type_names[] = { +#define token(scanner) ((scanner)->token.token) + +static const char * const type_names[] = { "object", "array", "string", @@ -34,7 +46,7 @@ static const char *type_names[] = { #define type_name(x) type_names[json_typeof(x)] -static const char *unpack_value_starters = "{[siIbfFOon"; +static const char unpack_value_starters[] = "{[siIbfFOon"; static void scanner_init(scanner_t *s, json_error_t *error, @@ -43,14 +55,28 @@ static void scanner_init(scanner_t *s, json_error_t *error, s->error = error; s->flags = flags; s->fmt = s->start = fmt; + memset(&s->prev_token, 0, sizeof(token_t)); + memset(&s->token, 0, sizeof(token_t)); + memset(&s->next_token, 0, sizeof(token_t)); s->line = 1; s->column = 0; + s->pos = 0; } static void next_token(scanner_t *s) { - const char *t = s->fmt; + const char *t; + s->prev_token = s->token; + + if(s->next_token.line) { + s->token = s->next_token; + s->next_token.line = 0; + return; + } + + t = s->fmt; s->column++; + s->pos++; /* skip space and ignored chars */ while(*t == ' ' || *t == '\t' || *t == '\n' || *t == ',' || *t == ':') { @@ -61,23 +87,32 @@ static void next_token(scanner_t *s) else s->column++; + s->pos++; t++; } - s->token = *t; + s->token.token = *t; + s->token.line = s->line; + s->token.column = s->column; + s->token.pos = s->pos; t++; s->fmt = t; } +static void prev_token(scanner_t *s) +{ + s->next_token = s->token; + s->token = s->prev_token; +} + static void set_error(scanner_t *s, const char *source, const char *fmt, ...) { va_list ap; - size_t pos; va_start(ap, fmt); - pos = (size_t)(s->fmt - s->start); - jsonp_error_vset(s->error, s->line, s->column, pos, fmt, ap); + jsonp_error_vset(s->error, s->token.line, s->token.column, s->token.pos, + fmt, ap); jsonp_error_set_source(s->error, source); @@ -86,47 +121,135 @@ static void set_error(scanner_t *s, const char *source, const char *fmt, ...) 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, size_t *out_len, int *ours) +{ + char t; + strbuffer_t strbuff; + const char *str; + size_t length; + + next_token(s); + t = token(s); + prev_token(s); + + if(t != '#' && t != '%' && t != '+') { + /* Optimize the simple case */ + str = va_arg(*ap, const char *); + + if(!str) { + set_error(s, "<args>", "NULL string argument"); + return NULL; + } + + 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; + } + + strbuffer_init(&strbuff); + + while(1) { + str = va_arg(*ap, const char *); + if(!str) { + set_error(s, "<args>", "NULL string argument"); + strbuffer_close(&strbuff); + return NULL; + } + + next_token(s); + + 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); + } + + if(strbuffer_append_bytes(&strbuff, str, length) == -1) { + set_error(s, "<internal>", "Out of memory"); + strbuffer_close(&strbuff); + return NULL; + } + + next_token(s); + if(token(s) != '+') { + prev_token(s); + break; + } + } + + 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 strbuffer_steal_value(&strbuff); +} + static json_t *pack_object(scanner_t *s, va_list *ap) { json_t *object = json_object(); next_token(s); - while(s->token != '}') { - const char *key; + while(token(s) != '}') { + char *key; + size_t len; + int ours; json_t *value; - if(!s->token) { + if(!token(s)) { set_error(s, "<format>", "Unexpected end of format string"); goto error; } - if(s->token != 's') { - set_error(s, "<format>", "Expected format 's', got '%c'", s->token); - goto error; - } - - key = va_arg(*ap, const char *); - if(!key) { - set_error(s, "<args>", "NULL object key"); + if(token(s) != 's') { + set_error(s, "<format>", "Expected format 's', got '%c'", token(s)); goto error; } - if(!utf8_check_string(key, -1)) { - set_error(s, "<args>", "Invalid UTF-8 in object key"); + 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) + jsonp_free(key); + set_error(s, "<internal>", "Unable to add key \"%s\"", key); goto error; } + if(ours) + jsonp_free(key); + next_token(s); } @@ -142,10 +265,10 @@ static json_t *pack_array(scanner_t *s, va_list *ap) json_t *array = json_array(); next_token(s); - while(s->token != ']') { + while(token(s) != ']') { json_t *value; - if(!s->token) { + if(!token(s)) { set_error(s, "<format>", "Unexpected end of format string"); goto error; } @@ -170,7 +293,7 @@ error: static json_t *pack(scanner_t *s, va_list *ap) { - switch(s->token) { + switch(token(s)) { case '{': return pack_object(s, ap); @@ -179,16 +302,18 @@ static json_t *pack(scanner_t *s, va_list *ap) case 's': /* string */ { - const char *str = va_arg(*ap, const char *); - if(!str) { - set_error(s, "<args>", "NULL string argument"); - return NULL; - } - if(!utf8_check_string(str, -1)) { - set_error(s, "<args>", "Invalid UTF-8 string"); + char *str; + size_t len; + int ours; + + str = read_string(s, ap, "string", &len, &ours); + if(!str) return NULL; - } - return json_string_nocheck(str); + + if (ours) + return jsonp_stringn_nocheck_own(str, len); + else + return json_stringn_nocheck(str, len); } case 'n': /* null */ @@ -214,7 +339,7 @@ static json_t *pack(scanner_t *s, va_list *ap) default: set_error(s, "<format>", "Unexpected format character '%c'", - s->token); + token(s)); return NULL; } } @@ -225,6 +350,7 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) { int ret = -1; int strict = 0; + int gotopt = 0; /* Use a set (emulated by a hashtable) to check that all object keys are accessed. Checking that the correct number of keys @@ -245,30 +371,30 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) } next_token(s); - while(s->token != '}') { + while(token(s) != '}') { const char *key; json_t *value; int opt = 0; if(strict != 0) { set_error(s, "<format>", "Expected '}' after '%c', got '%c'", - (strict == 1 ? '!' : '*'), s->token); + (strict == 1 ? '!' : '*'), token(s)); goto out; } - if(!s->token) { + if(!token(s)) { set_error(s, "<format>", "Unexpected end of format string"); goto out; } - if(s->token == '!' || s->token == '*') { - strict = (s->token == '!' ? 1 : -1); + if(token(s) == '!' || token(s) == '*') { + strict = (token(s) == '!' ? 1 : -1); next_token(s); continue; } - if(s->token != 's') { - set_error(s, "<format>", "Expected format 's', got '%c'", s->token); + if(token(s) != 's') { + set_error(s, "<format>", "Expected format 's', got '%c'", token(s)); goto out; } @@ -280,8 +406,8 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) next_token(s); - if(s->token == '?') { - opt = 1; + if(token(s) == '?') { + opt = gotopt = 1; next_token(s); } @@ -307,10 +433,26 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) if(strict == 0 && (s->flags & JSON_STRICT)) strict = 1; - if(root && strict == 1 && key_set.size != json_object_size(root)) { - long diff = (long)json_object_size(root) - (long)key_set.size; - set_error(s, "<validation>", "%li object item(s) left unpacked", diff); - goto out; + if(root && strict == 1) { + /* We need to check that all non optional items have been parsed */ + const char *key; + json_t *value; + long unpacked = 0; + if (gotopt) { + /* We have optional keys, we need to iter on each key */ + json_object_foreach(root, key, value) { + if(!hashtable_get(&key_set, key)) { + unpacked++; + } + } + } else { + /* No optional keys, we can just compare the number of items */ + unpacked = (long)json_object_size(root) - (long)key_set.size; + } + if (unpacked) { + set_error(s, "<validation>", "%li object item(s) left unpacked", unpacked); + goto out; + } } ret = 0; @@ -331,30 +473,30 @@ static int unpack_array(scanner_t *s, json_t *root, va_list *ap) } next_token(s); - while(s->token != ']') { + while(token(s) != ']') { json_t *value; if(strict != 0) { set_error(s, "<format>", "Expected ']' after '%c', got '%c'", (strict == 1 ? '!' : '*'), - s->token); + token(s)); return -1; } - if(!s->token) { + if(!token(s)) { set_error(s, "<format>", "Unexpected end of format string"); return -1; } - if(s->token == '!' || s->token == '*') { - strict = (s->token == '!' ? 1 : -1); + if(token(s) == '!' || token(s) == '*') { + strict = (token(s) == '!' ? 1 : -1); next_token(s); continue; } - if(!strchr(unpack_value_starters, s->token)) { + if(!strchr(unpack_value_starters, token(s))) { set_error(s, "<format>", "Unexpected format character '%c'", - s->token); + token(s)); return -1; } @@ -392,7 +534,7 @@ static int unpack_array(scanner_t *s, json_t *root, va_list *ap) static int unpack(scanner_t *s, json_t *root, va_list *ap) { - switch(s->token) + switch(token(s)) { case '{': return unpack_object(s, root, ap); @@ -408,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; @@ -521,7 +679,7 @@ static int unpack(scanner_t *s, json_t *root, va_list *ap) default: set_error(s, "<format>", "Unexpected format character '%c'", - s->token); + token(s)); return -1; } } @@ -551,7 +709,7 @@ json_t *json_vpack_ex(json_error_t *error, size_t flags, return NULL; next_token(&s); - if(s.token) { + if(token(&s)) { json_decref(value); set_error(&s, "<format>", "Garbage after format string"); return NULL; @@ -614,7 +772,7 @@ int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, va_end(ap_copy); next_token(&s); - if(s.token) { + if(token(&s)) { set_error(&s, "<format>", "Garbage after format string"); return -1; } diff --git a/src/jansson/strbuffer.c b/src/jansson/strbuffer.c index 6d4edd6..b3ddd0e 100644 --- a/src/jansson/strbuffer.c +++ b/src/jansson/strbuffer.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 <stdlib.h> #include <string.h> #include "jansson_private.h" @@ -31,7 +34,9 @@ int strbuffer_init(strbuffer_t *strbuff) void strbuffer_close(strbuffer_t *strbuff) { - jsonp_free(strbuff->value); + if(strbuff->value) + jsonp_free(strbuff->value); + strbuff->size = 0; strbuff->length = 0; strbuff->value = NULL; @@ -51,7 +56,7 @@ const char *strbuffer_value(const strbuffer_t *strbuff) char *strbuffer_steal_value(strbuffer_t *strbuff) { char *result = strbuff->value; - strbuffer_init(strbuff); + strbuff->value = NULL; return result; } diff --git a/src/jansson/strbuffer.h b/src/jansson/strbuffer.h index 23f8fff..fc11ec0 100644 --- a/src/jansson/strbuffer.h +++ b/src/jansson/strbuffer.h @@ -1,5 +1,5 @@ /* - * 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. @@ -20,6 +20,8 @@ void strbuffer_close(strbuffer_t *strbuff); void strbuffer_clear(strbuffer_t *strbuff); const char *strbuffer_value(const strbuffer_t *strbuff); + +/* Steal the value and close the strbuffer */ char *strbuffer_steal_value(strbuffer_t *strbuff); int strbuffer_append(strbuffer_t *strbuff, const char *string); diff --git a/src/jansson/strconv.c b/src/jansson/strconv.c index caa9ab8..3a70c6f 100644 --- a/src/jansson/strconv.c +++ b/src/jansson/strconv.c @@ -5,6 +5,11 @@ #include "jansson_private.h" #include "strbuffer.h" +/* need jansson_private_config.h to get the correct snprintf */ +#ifdef HAVE_CONFIG_H +#include <jansson_private_config.h> +#endif + #if JSON_HAVE_LOCALECONV #include <locale.h> diff --git a/src/jansson/utf.c b/src/jansson/utf.c index 0359ee2..b56e125 100644 --- a/src/jansson/utf.c +++ b/src/jansson/utf.c @@ -1,5 +1,5 @@ /* - * 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. @@ -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/jansson/utf.h b/src/jansson/utf.h index 2495cdd..2cebea0 100644 --- a/src/jansson/utf.h +++ b/src/jansson/utf.h @@ -1,5 +1,5 @@ /* - * 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. @@ -9,31 +9,19 @@ #define UTF_H #ifdef HAVE_CONFIG_H -#include <config.h> - -#ifdef HAVE_INTTYPES_H -/* inttypes.h includes stdint.h in a standard environment, so there's -no need to include stdint.h separately. If inttypes.h doesn't define -int32_t, it's defined in config.h. */ -#include <inttypes.h> -#endif /* HAVE_INTTYPES_H */ - -#else /* !HAVE_CONFIG_H */ -#ifdef _WIN32 -typedef int int32_t; -#else /* !_WIN32 */ -/* Assume a standard environment */ -#include <inttypes.h> -#endif /* _WIN32 */ +#include <jansson_private_config.h> +#endif -#endif /* HAVE_CONFIG_H */ +#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/jansson/value.c b/src/jansson/value.c index 1a6d902..644bc87 100644 --- a/src/jansson/value.c +++ b/src/jansson/value.c @@ -1,17 +1,27 @@ /* - * 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 + +#ifdef HAVE_CONFIG_H +#include <jansson_private_config.h> +#endif #include <stddef.h> #include <stdlib.h> #include <string.h> #include <math.h> +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif + #include "jansson.h" #include "hashtable.h" #include "jansson_private.h" @@ -19,12 +29,10 @@ /* Work around nonstandard isnan() and isinf() implementations */ #ifndef isnan -static JSON_INLINE int jansson_isnan(double x) { return x != x; } -# define isnan jansson_isnan +static JSON_INLINE int isnan(double x) { return x != x; } #endif #ifndef isinf -static JSON_INLINE int jansson_isinf(double x) { return !isnan(x) && isnan(x - x); } -# define isinf jansson_isinf +static JSON_INLINE int isinf(double x) { return !isnan(x) && isnan(x - x); } #endif static JSON_INLINE void json_init(json_t *json, json_type type) @@ -36,11 +44,19 @@ static JSON_INLINE void json_init(json_t *json, json_type type) /*** object ***/ +extern volatile uint32_t hashtable_seed; + json_t *json_object(void) { json_object_t *object = jsonp_malloc(sizeof(json_object_t)); if(!object) return NULL; + + if (!hashtable_seed) { + /* Autoseed */ + json_object_seed(0); + } + json_init(&object->json, JSON_OBJECT); if(hashtable_init(&object->hashtable)) @@ -76,7 +92,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); @@ -108,7 +124,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; @@ -121,7 +137,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); @@ -292,19 +308,27 @@ static json_t *json_object_copy(json_t *object) return result; } -static json_t *json_object_deep_copy(json_t *object) +static json_t *json_object_deep_copy(const json_t *object) { json_t *result; - - const char *key; - json_t *value; + void *iter; result = json_object(); if(!result) return NULL; - json_object_foreach(object, key, value) + /* Cannot use json_object_foreach because object has to be cast + non-const */ + iter = json_object_iter((json_t *)object); + while(iter) { + const char *key; + const json_t *value; + key = json_object_iter_key(iter); + value = json_object_iter_value(iter); + json_object_set_new_nocheck(result, key, json_deep_copy(value)); + iter = json_object_iter_next((json_t *)object, iter); + } return result; } @@ -511,7 +535,10 @@ int json_array_remove(json_t *json, size_t index) json_decref(array->table[index]); - array_move(array, index, index + 1, array->entries - index); + /* If we're removing the last element, nothing has to be moved */ + if(index < array->entries - 1) + array_move(array, index, index + 1, array->entries - index - 1); + array->entries--; return 0; @@ -592,7 +619,7 @@ static json_t *json_array_copy(json_t *array) return result; } -static json_t *json_array_deep_copy(json_t *array) +static json_t *json_array_deep_copy(const json_t *array) { json_t *result; size_t i; @@ -609,33 +636,68 @@ static json_t *json_array_deep_copy(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; + + return &string->json; +} - string->value = jsonp_strdup(value); - if(!string->value) { - jsonp_free(string); +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_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_string_nocheck(value); + return json_stringn_nocheck(value, len); } const char *json_string_value(const json_t *json) @@ -646,31 +708,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_set_nocheck(json, value); + 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_setn_nocheck(json, value, len); } static void json_delete_string(json_string_t *string) @@ -681,12 +768,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(json_t *string) +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); } @@ -731,7 +831,7 @@ static int json_integer_equal(json_t *integer1, json_t *integer2) return json_integer_value(integer1) == json_integer_value(integer2); } -static json_t *json_integer_copy(json_t *integer) +static json_t *json_integer_copy(const json_t *integer) { return json_integer(json_integer_value(integer)); } @@ -783,7 +883,7 @@ static int json_real_equal(json_t *real1, json_t *real2) return json_real_value(real1) == json_real_value(real2); } -static json_t *json_real_copy(json_t *real) +static json_t *json_real_copy(const json_t *real) { return json_real(json_real_value(real)); } @@ -909,7 +1009,7 @@ json_t *json_copy(json_t *json) return NULL; } -json_t *json_deep_copy(json_t *json) +json_t *json_deep_copy(const json_t *json) { if(!json) return NULL; @@ -933,7 +1033,7 @@ json_t *json_deep_copy(json_t *json) return json_real_copy(json); if(json_is_true(json) || json_is_false(json) || json_is_null(json)) - return json; + return (json_t *)json; return NULL; } @@ -276,25 +276,28 @@ NVIDIA_SETTINGS_EXTRA_DIST += $(GTK_EXTRA_DIST) # # files in the src/jansson directory of nvidia-settings # -JANSSON_SRC += jansson/load.c -JANSSON_SRC += jansson/value.c -JANSSON_SRC += jansson/pack_unpack.c -JANSSON_SRC += jansson/utf.c JANSSON_SRC += jansson/dump.c -JANSSON_SRC += jansson/strconv.c -JANSSON_SRC += jansson/strbuffer.c -JANSSON_SRC += jansson/memory.c JANSSON_SRC += jansson/error.c JANSSON_SRC += jansson/hashtable.c +JANSSON_SRC += jansson/hashtable_seed.c +JANSSON_SRC += jansson/load.c +JANSSON_SRC += jansson/memory.c +JANSSON_SRC += jansson/pack_unpack.c +JANSSON_SRC += jansson/strbuffer.c +JANSSON_SRC += jansson/strconv.c +JANSSON_SRC += jansson/utf.c +JANSSON_SRC += jansson/value.c NVIDIA_SETTINGS_SRC += $(JANSSON_SRC) -JANSSON_EXTRA_DIST += jansson/utf.h +JANSSON_EXTRA_DIST += jansson/hashtable.h JANSSON_EXTRA_DIST += jansson/jansson_config.h -JANSSON_EXTRA_DIST += jansson/strbuffer.h JANSSON_EXTRA_DIST += jansson/jansson.h -JANSSON_EXTRA_DIST += jansson/hashtable.h +JANSSON_EXTRA_DIST += jansson/jansson_private_config.h JANSSON_EXTRA_DIST += jansson/jansson_private.h +JANSSON_EXTRA_DIST += jansson/lookup3.h +JANSSON_EXTRA_DIST += jansson/strbuffer.h +JANSSON_EXTRA_DIST += jansson/utf.h NVIDIA_SETTINGS_EXTRA_DIST += $(JANSSON_EXTRA_DIST) diff --git a/src/version.mk b/src/version.mk index 1012493..bb1a5bc 100644 --- a/src/version.mk +++ b/src/version.mk @@ -1 +1 @@ -NVIDIA_VERSION = 331.49 +NVIDIA_VERSION = 331.67 @@ -1 +1 @@ -NVIDIA_VERSION = 331.49 +NVIDIA_VERSION = 331.67 |