1
0
mirror of https://github.com/GOSTSec/sgminer synced 2025-01-11 07:17:58 +00:00

Update included jansson to v2.4

This commit is contained in:
Con Kolivas 2013-08-26 21:57:29 +10:00
parent 036c7b73f1
commit 647dc35fe6
20 changed files with 1267 additions and 466 deletions

View File

@ -1,21 +1,21 @@
EXTRA_DIST = jansson.def
include_HEADERS = jansson.h jansson_config.h
noinst_LIBRARIES = libjansson.a noinst_LIBRARIES = libjansson.a
libjansson_a_SOURCES = \ libjansson_a_SOURCES = \
config.h \
jansson_config.h \
dump.c \ dump.c \
error.c \
hashtable.c \ hashtable.c \
hashtable.h \ hashtable.h \
jansson.h \
jansson_private.h \ jansson_private.h \
load.c \ load.c \
memory.c \
pack_unpack.c \
strbuffer.c \ strbuffer.c \
strbuffer.h \ strbuffer.h \
strconv.c \
utf.c \ utf.c \
utf.h \ utf.h \
util.h \ value.c
value.c \
memory.c \
error.c

View File

@ -1,73 +0,0 @@
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#define LT_OBJDIR ".libs/"
/* Name of package */
#define PACKAGE "jansson"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "petri@digip.org"
/* Define to the full name of this package. */
#define PACKAGE_NAME "jansson"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "jansson 1.3"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "jansson"
/* Define to the home page for this package. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "1.3"
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Version number of package */
#define VERSION "1.3"
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
/* #undef inline */
#endif
/* Define to the type of a signed integer type of width exactly 32 bits if
such a type exists and the standard includes do not define it. */
/* #undef int32_t */

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org> * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* *
* Jansson is free software; you can redistribute it and/or modify * Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details. * it under the terms of the MIT license. See LICENSE for details.
@ -11,7 +11,7 @@
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <jansson.h> #include "jansson.h"
#include "jansson_private.h" #include "jansson_private.h"
#include "strbuffer.h" #include "strbuffer.h"
#include "utf.h" #include "utf.h"
@ -19,21 +19,17 @@
#define MAX_INTEGER_STR_LENGTH 100 #define MAX_INTEGER_STR_LENGTH 100
#define MAX_REAL_STR_LENGTH 100 #define MAX_REAL_STR_LENGTH 100
typedef int (*dump_func)(const char *buffer, int size, void *data); struct object_key {
size_t serial;
struct string const char *key;
{
char *buffer;
int length;
int size;
}; };
static int dump_to_strbuffer(const char *buffer, int size, void *data) static int dump_to_strbuffer(const char *buffer, size_t size, void *data)
{ {
return strbuffer_append_bytes((strbuffer_t *)data, buffer, size); return strbuffer_append_bytes((strbuffer_t *)data, buffer, size);
} }
static int dump_to_file(const char *buffer, int size, void *data) static int dump_to_file(const char *buffer, size_t size, void *data)
{ {
FILE *dest = (FILE *)data; FILE *dest = (FILE *)data;
if(fwrite(buffer, size, 1, dest) != 1) if(fwrite(buffer, size, 1, dest) != 1)
@ -44,7 +40,7 @@ static int dump_to_file(const char *buffer, int size, void *data)
/* 32 spaces (the maximum indentation size) */ /* 32 spaces (the maximum indentation size) */
static char whitespace[] = " "; static char whitespace[] = " ";
static int dump_indent(size_t flags, int depth, int space, dump_func dump, void *data) static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump, void *data)
{ {
if(JSON_INDENT(flags) > 0) if(JSON_INDENT(flags) > 0)
{ {
@ -66,7 +62,7 @@ static int dump_indent(size_t flags, int depth, int space, dump_func dump, void
return 0; return 0;
} }
static int dump_string(const char *str, int ascii, dump_func dump, void *data) static int dump_string(const char *str, json_dump_callback_t dump, void *data, size_t flags)
{ {
const char *pos, *end; const char *pos, *end;
int32_t codepoint; int32_t codepoint;
@ -91,8 +87,12 @@ static int dump_string(const char *str, int ascii, dump_func dump, void *data)
if(codepoint == '\\' || codepoint == '"' || codepoint < 0x20) if(codepoint == '\\' || codepoint == '"' || codepoint < 0x20)
break; break;
/* slash */
if((flags & JSON_ESCAPE_SLASH) && codepoint == '/')
break;
/* non-ASCII */ /* non-ASCII */
if(ascii && codepoint > 0x7F) if((flags & JSON_ENSURE_ASCII) && codepoint > 0x7F)
break; break;
pos = end; pos = end;
@ -106,7 +106,7 @@ static int dump_string(const char *str, int ascii, dump_func dump, void *data)
if(end == pos) if(end == pos)
break; break;
/* handle \, ", and control codes */ /* handle \, /, ", and control codes */
length = 2; length = 2;
switch(codepoint) switch(codepoint)
{ {
@ -117,6 +117,7 @@ static int dump_string(const char *str, int ascii, dump_func dump, void *data)
case '\n': text = "\\n"; break; case '\n': text = "\\n"; break;
case '\r': text = "\\r"; break; case '\r': text = "\\r"; break;
case '\t': text = "\\t"; break; case '\t': text = "\\t"; break;
case '/': text = "\\/"; break;
default: default:
{ {
/* codepoint is in BMP */ /* codepoint is in BMP */
@ -155,21 +156,21 @@ static int dump_string(const char *str, int ascii, dump_func dump, void *data)
static int object_key_compare_keys(const void *key1, const void *key2) static int object_key_compare_keys(const void *key1, const void *key2)
{ {
return strcmp((*(const object_key_t **)key1)->key, return strcmp(((const struct object_key *)key1)->key,
(*(const object_key_t **)key2)->key); ((const struct object_key *)key2)->key);
} }
static int object_key_compare_serials(const void *key1, const void *key2) static int object_key_compare_serials(const void *key1, const void *key2)
{ {
return (*(const object_key_t **)key1)->serial - size_t a = ((const struct object_key *)key1)->serial;
(*(const object_key_t **)key2)->serial; size_t b = ((const struct object_key *)key2)->serial;
return a < b ? -1 : a == b ? 0 : 1;
} }
static int do_dump(const json_t *json, size_t flags, int depth, static int do_dump(const json_t *json, size_t flags, int depth,
dump_func dump, void *data) json_dump_callback_t dump, void *data)
{ {
int ascii = flags & JSON_ENSURE_ASCII ? 1 : 0;
switch(json_typeof(json)) { switch(json_typeof(json)) {
case JSON_NULL: case JSON_NULL:
return dump("null", 4, data); return dump("null", 4, data);
@ -188,7 +189,7 @@ static int do_dump(const json_t *json, size_t flags, int depth,
size = snprintf(buffer, MAX_INTEGER_STR_LENGTH, size = snprintf(buffer, MAX_INTEGER_STR_LENGTH,
"%" JSON_INTEGER_FORMAT, "%" JSON_INTEGER_FORMAT,
json_integer_value(json)); json_integer_value(json));
if(size >= MAX_INTEGER_STR_LENGTH) if(size < 0 || size >= MAX_INTEGER_STR_LENGTH)
return -1; return -1;
return dump(buffer, size, data); return dump(buffer, size, data);
@ -198,31 +199,17 @@ static int do_dump(const json_t *json, size_t flags, int depth,
{ {
char buffer[MAX_REAL_STR_LENGTH]; char buffer[MAX_REAL_STR_LENGTH];
int size; int size;
double value = json_real_value(json);
size = snprintf(buffer, MAX_REAL_STR_LENGTH, "%.17g", size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value);
json_real_value(json)); if(size < 0)
if(size >= MAX_REAL_STR_LENGTH)
return -1; return -1;
/* Make sure there's a dot or 'e' in the output. Otherwise
a real is converted to an integer when decoding */
if(strchr(buffer, '.') == NULL &&
strchr(buffer, 'e') == NULL)
{
if(size + 2 >= MAX_REAL_STR_LENGTH) {
/* No space to append ".0" */
return -1;
}
buffer[size] = '.';
buffer[size + 1] = '0';
size += 2;
}
return dump(buffer, size, data); return dump(buffer, size, data);
} }
case JSON_STRING: case JSON_STRING:
return dump_string(json_string_value(json), ascii, dump, data); return dump_string(json_string_value(json), dump, data, flags);
case JSON_ARRAY: case JSON_ARRAY:
{ {
@ -308,19 +295,20 @@ static int do_dump(const json_t *json, size_t flags, int depth,
if(flags & JSON_SORT_KEYS || flags & JSON_PRESERVE_ORDER) if(flags & JSON_SORT_KEYS || flags & JSON_PRESERVE_ORDER)
{ {
const object_key_t **keys; struct object_key *keys;
size_t size, i; size_t size, i;
int (*cmp_func)(const void *, const void *); int (*cmp_func)(const void *, const void *);
size = json_object_size(json); size = json_object_size(json);
keys = jsonp_malloc(size * sizeof(object_key_t *)); keys = jsonp_malloc(size * sizeof(struct object_key));
if(!keys) if(!keys)
goto object_error; goto object_error;
i = 0; i = 0;
while(iter) while(iter)
{ {
keys[i] = jsonp_object_iter_fullkey(iter); keys[i].serial = hashtable_iter_serial(iter);
keys[i].key = json_object_iter_key(iter);
iter = json_object_iter_next((json_t *)json, iter); iter = json_object_iter_next((json_t *)json, iter);
i++; i++;
} }
@ -331,18 +319,18 @@ static int do_dump(const json_t *json, size_t flags, int depth,
else else
cmp_func = object_key_compare_serials; cmp_func = object_key_compare_serials;
qsort(keys, size, sizeof(object_key_t *), cmp_func); qsort(keys, size, sizeof(struct object_key), cmp_func);
for(i = 0; i < size; i++) for(i = 0; i < size; i++)
{ {
const char *key; const char *key;
json_t *value; json_t *value;
key = keys[i]->key; key = keys[i].key;
value = json_object_get(json, key); value = json_object_get(json, key);
assert(value); assert(value);
dump_string(key, ascii, dump, data); dump_string(key, dump, data, flags);
if(dump(separator, separator_length, data) || if(dump(separator, separator_length, data) ||
do_dump(value, flags, depth + 1, dump, data)) do_dump(value, flags, depth + 1, dump, data))
{ {
@ -379,7 +367,7 @@ static int do_dump(const json_t *json, size_t flags, int depth,
{ {
void *next = json_object_iter_next((json_t *)json, iter); void *next = json_object_iter_next((json_t *)json, iter);
dump_string(json_object_iter_key(iter), ascii, dump, data); dump_string(json_object_iter_key(iter), dump, data, flags);
if(dump(separator, separator_length, data) || if(dump(separator, separator_length, data) ||
do_dump(json_object_iter_value(iter), flags, depth + 1, do_dump(json_object_iter_value(iter), flags, depth + 1,
dump, data)) dump, data))
@ -415,39 +403,26 @@ static int do_dump(const json_t *json, size_t flags, int depth,
} }
} }
char *json_dumps(const json_t *json, size_t flags) char *json_dumps(const json_t *json, size_t flags)
{ {
strbuffer_t strbuff; strbuffer_t strbuff;
char *result; char *result;
if(!(flags & JSON_ENCODE_ANY)) {
if(!json_is_array(json) && !json_is_object(json))
return NULL;
}
if(strbuffer_init(&strbuff)) if(strbuffer_init(&strbuff))
return NULL; return NULL;
if(do_dump(json, flags, 0, dump_to_strbuffer, (void *)&strbuff)) { if(json_dump_callback(json, dump_to_strbuffer, (void *)&strbuff, flags))
strbuffer_close(&strbuff); result = NULL;
return NULL; else
} result = jsonp_strdup(strbuffer_value(&strbuff));
result = jsonp_strdup(strbuffer_value(&strbuff));
strbuffer_close(&strbuff); strbuffer_close(&strbuff);
return result; return result;
} }
int json_dumpf(const json_t *json, FILE *output, size_t flags) int json_dumpf(const json_t *json, FILE *output, size_t flags)
{ {
if(!(flags & JSON_ENCODE_ANY)) { return json_dump_callback(json, dump_to_file, (void *)output, flags);
if(!json_is_array(json) && !json_is_object(json))
return -1;
}
return do_dump(json, flags, 0, dump_to_file, (void *)output);
} }
int json_dump_file(const json_t *json, const char *path, size_t flags) int json_dump_file(const json_t *json, const char *path, size_t flags)
@ -463,3 +438,13 @@ int json_dump_file(const json_t *json, const char *path, size_t flags)
fclose(output); fclose(output);
return result; return result;
} }
int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags)
{
if(!(flags & JSON_ENCODE_ANY)) {
if(!json_is_array(json) && !json_is_object(json))
return -1;
}
return do_dump(json, flags, 0, callback, data);
}

View File

@ -59,4 +59,5 @@ void jsonp_error_vset(json_error_t *error, int line, int column,
error->position = position; error->position = position;
vsnprintf(error->text, JSON_ERROR_TEXT_LENGTH, msg, ap); vsnprintf(error->text, JSON_ERROR_TEXT_LENGTH, msg, ap);
error->text[JSON_ERROR_TEXT_LENGTH - 1] = '\0';
} }

View File

@ -1,11 +1,12 @@
/* /*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org> * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* *
* This library is free software; you can redistribute it and/or modify * This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details. * it under the terms of the MIT license. See LICENSE for details.
*/ */
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <jansson_config.h> /* for JSON_INLINE */ #include <jansson_config.h> /* for JSON_INLINE */
#include "jansson_private.h" /* for container_of() */ #include "jansson_private.h" /* for container_of() */
#include "hashtable.h" #include "hashtable.h"
@ -16,6 +17,23 @@ typedef struct hashtable_bucket bucket_t;
#define list_to_pair(list_) container_of(list_, pair_t, list) #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;
size_t hash = 5381;
size_t c;
while((c = (size_t)*str))
{
hash = ((hash << 5) + hash) + c;
str++;
}
return hash;
}
static JSON_INLINE void list_init(list_t *list) static JSON_INLINE void list_init(list_t *list)
{ {
list->next = list; list->next = list;
@ -62,7 +80,6 @@ static size_t primes[] = {
12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189,
805306457, 1610612741 805306457, 1610612741
}; };
static const size_t num_primes = sizeof(primes) / sizeof(size_t);
static JSON_INLINE size_t num_buckets(hashtable_t *hashtable) static JSON_INLINE size_t num_buckets(hashtable_t *hashtable)
{ {
@ -71,7 +88,7 @@ static JSON_INLINE size_t num_buckets(hashtable_t *hashtable)
static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket, static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
const void *key, size_t hash) const char *key, size_t hash)
{ {
list_t *list; list_t *list;
pair_t *pair; pair_t *pair;
@ -83,7 +100,7 @@ static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
while(1) while(1)
{ {
pair = list_to_pair(list); pair = list_to_pair(list);
if(pair->hash == hash && hashtable->cmp_keys(pair->key, key)) if(pair->hash == hash && strcmp(pair->key, key) == 0)
return pair; return pair;
if(list == bucket->last) if(list == bucket->last)
@ -97,7 +114,7 @@ static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
/* returns 0 on success, -1 if key was not found */ /* returns 0 on success, -1 if key was not found */
static int hashtable_do_del(hashtable_t *hashtable, static int hashtable_do_del(hashtable_t *hashtable,
const void *key, size_t hash) const char *key, size_t hash)
{ {
pair_t *pair; pair_t *pair;
bucket_t *bucket; bucket_t *bucket;
@ -120,11 +137,7 @@ static int hashtable_do_del(hashtable_t *hashtable,
bucket->last = pair->list.prev; bucket->last = pair->list.prev;
list_remove(&pair->list); list_remove(&pair->list);
json_decref(pair->value);
if(hashtable->free_key)
hashtable->free_key(pair->key);
if(hashtable->free_value)
hashtable->free_value(pair->value);
jsonp_free(pair); jsonp_free(pair);
hashtable->size--; hashtable->size--;
@ -141,10 +154,7 @@ static void hashtable_do_clear(hashtable_t *hashtable)
{ {
next = list->next; next = list->next;
pair = list_to_pair(list); pair = list_to_pair(list);
if(hashtable->free_key) json_decref(pair->value);
hashtable->free_key(pair->key);
if(hashtable->free_value)
hashtable->free_value(pair->value);
jsonp_free(pair); jsonp_free(pair);
} }
} }
@ -184,31 +194,7 @@ static int hashtable_do_rehash(hashtable_t *hashtable)
} }
hashtable_t *hashtable_create(key_hash_fn hash_key, key_cmp_fn cmp_keys, int hashtable_init(hashtable_t *hashtable)
free_fn free_key, free_fn free_value)
{
hashtable_t *hashtable = jsonp_malloc(sizeof(hashtable_t));
if(!hashtable)
return NULL;
if(hashtable_init(hashtable, hash_key, cmp_keys, free_key, free_value))
{
jsonp_free(hashtable);
return NULL;
}
return hashtable;
}
void hashtable_destroy(hashtable_t *hashtable)
{
hashtable_close(hashtable);
jsonp_free(hashtable);
}
int hashtable_init(hashtable_t *hashtable,
key_hash_fn hash_key, key_cmp_fn cmp_keys,
free_fn free_key, free_fn free_value)
{ {
size_t i; size_t i;
@ -220,11 +206,6 @@ int hashtable_init(hashtable_t *hashtable,
list_init(&hashtable->list); list_init(&hashtable->list);
hashtable->hash_key = hash_key;
hashtable->cmp_keys = cmp_keys;
hashtable->free_key = free_key;
hashtable->free_value = free_value;
for(i = 0; i < num_buckets(hashtable); i++) for(i = 0; i < num_buckets(hashtable); i++)
{ {
hashtable->buckets[i].first = hashtable->buckets[i].last = hashtable->buckets[i].first = hashtable->buckets[i].last =
@ -240,7 +221,9 @@ void hashtable_close(hashtable_t *hashtable)
jsonp_free(hashtable->buckets); jsonp_free(hashtable->buckets);
} }
int hashtable_set(hashtable_t *hashtable, void *key, void *value) int hashtable_set(hashtable_t *hashtable,
const char *key, size_t serial,
json_t *value)
{ {
pair_t *pair; pair_t *pair;
bucket_t *bucket; bucket_t *bucket;
@ -251,28 +234,29 @@ int hashtable_set(hashtable_t *hashtable, void *key, void *value)
if(hashtable_do_rehash(hashtable)) if(hashtable_do_rehash(hashtable))
return -1; return -1;
hash = hashtable->hash_key(key); hash = hash_str(key);
index = hash % num_buckets(hashtable); index = hash % num_buckets(hashtable);
bucket = &hashtable->buckets[index]; bucket = &hashtable->buckets[index];
pair = hashtable_find_pair(hashtable, bucket, key, hash); pair = hashtable_find_pair(hashtable, bucket, key, hash);
if(pair) if(pair)
{ {
if(hashtable->free_key) json_decref(pair->value);
hashtable->free_key(key);
if(hashtable->free_value)
hashtable->free_value(pair->value);
pair->value = value; pair->value = value;
} }
else else
{ {
pair = jsonp_malloc(sizeof(pair_t)); /* 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);
if(!pair) if(!pair)
return -1; return -1;
pair->key = key;
pair->value = value;
pair->hash = hash; pair->hash = hash;
pair->serial = serial;
strcpy(pair->key, key);
pair->value = value;
list_init(&pair->list); list_init(&pair->list);
insert_to_bucket(hashtable, bucket, &pair->list); insert_to_bucket(hashtable, bucket, &pair->list);
@ -282,13 +266,13 @@ int hashtable_set(hashtable_t *hashtable, void *key, void *value)
return 0; return 0;
} }
void *hashtable_get(hashtable_t *hashtable, const void *key) void *hashtable_get(hashtable_t *hashtable, const char *key)
{ {
pair_t *pair; pair_t *pair;
size_t hash; size_t hash;
bucket_t *bucket; bucket_t *bucket;
hash = hashtable->hash_key(key); hash = hash_str(key);
bucket = &hashtable->buckets[hash % num_buckets(hashtable)]; bucket = &hashtable->buckets[hash % num_buckets(hashtable)];
pair = hashtable_find_pair(hashtable, bucket, key, hash); pair = hashtable_find_pair(hashtable, bucket, key, hash);
@ -298,9 +282,9 @@ void *hashtable_get(hashtable_t *hashtable, const void *key)
return pair->value; return pair->value;
} }
int hashtable_del(hashtable_t *hashtable, const void *key) int hashtable_del(hashtable_t *hashtable, const char *key)
{ {
size_t hash = hashtable->hash_key(key); size_t hash = hash_str(key);
return hashtable_do_del(hashtable, key, hash); return hashtable_do_del(hashtable, key, hash);
} }
@ -325,13 +309,13 @@ void *hashtable_iter(hashtable_t *hashtable)
return hashtable_iter_next(hashtable, &hashtable->list); return hashtable_iter_next(hashtable, &hashtable->list);
} }
void *hashtable_iter_at(hashtable_t *hashtable, const void *key) void *hashtable_iter_at(hashtable_t *hashtable, const char *key)
{ {
pair_t *pair; pair_t *pair;
size_t hash; size_t hash;
bucket_t *bucket; bucket_t *bucket;
hash = hashtable->hash_key(key); hash = hash_str(key);
bucket = &hashtable->buckets[hash % num_buckets(hashtable)]; bucket = &hashtable->buckets[hash % num_buckets(hashtable)];
pair = hashtable_find_pair(hashtable, bucket, key, hash); pair = hashtable_find_pair(hashtable, bucket, key, hash);
@ -355,18 +339,22 @@ void *hashtable_iter_key(void *iter)
return pair->key; return pair->key;
} }
size_t hashtable_iter_serial(void *iter)
{
pair_t *pair = list_to_pair((list_t *)iter);
return pair->serial;
}
void *hashtable_iter_value(void *iter) void *hashtable_iter_value(void *iter)
{ {
pair_t *pair = list_to_pair((list_t *)iter); pair_t *pair = list_to_pair((list_t *)iter);
return pair->value; return pair->value;
} }
void hashtable_iter_set(hashtable_t *hashtable, void *iter, void *value) void hashtable_iter_set(void *iter, json_t *value)
{ {
pair_t *pair = list_to_pair((list_t *)iter); pair_t *pair = list_to_pair((list_t *)iter);
if(hashtable->free_value) json_decref(pair->value);
hashtable->free_value(pair->value);
pair->value = value; pair->value = value;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org> * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* *
* This library is free software; you can redistribute it and/or modify * This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details. * it under the terms of the MIT license. See LICENSE for details.
@ -8,20 +8,20 @@
#ifndef HASHTABLE_H #ifndef HASHTABLE_H
#define HASHTABLE_H #define HASHTABLE_H
typedef size_t (*key_hash_fn)(const void *key);
typedef int (*key_cmp_fn)(const void *key1, const void *key2);
typedef void (*free_fn)(void *key);
struct hashtable_list { struct hashtable_list {
struct hashtable_list *prev; struct hashtable_list *prev;
struct hashtable_list *next; struct hashtable_list *next;
}; };
/* "pair" may be a bit confusing a name, but think of it as a
key-value pair. In this case, it just encodes some extra data,
too */
struct hashtable_pair { struct hashtable_pair {
void *key;
void *value;
size_t hash; size_t hash;
struct hashtable_list list; struct hashtable_list list;
json_t *value;
size_t serial;
char key[1];
}; };
struct hashtable_bucket { struct hashtable_bucket {
@ -34,56 +34,23 @@ typedef struct hashtable {
struct hashtable_bucket *buckets; struct hashtable_bucket *buckets;
size_t num_buckets; /* index to primes[] */ size_t num_buckets; /* index to primes[] */
struct hashtable_list list; struct hashtable_list list;
key_hash_fn hash_key;
key_cmp_fn cmp_keys; /* returns non-zero for equal keys */
free_fn free_key;
free_fn free_value;
} hashtable_t; } hashtable_t;
/**
* hashtable_create - Create a hashtable object
*
* @hash_key: The key hashing function
* @cmp_keys: The key compare function. Returns non-zero for equal and
* zero for unequal unequal keys
* @free_key: If non-NULL, called for a key that is no longer referenced.
* @free_value: If non-NULL, called for a value that is no longer referenced.
*
* Returns a new hashtable object that should be freed with
* hashtable_destroy when it's no longer used, or NULL on failure (out
* of memory).
*/
hashtable_t *hashtable_create(key_hash_fn hash_key, key_cmp_fn cmp_keys,
free_fn free_key, free_fn free_value);
/** #define hashtable_key_to_iter(key_) \
* hashtable_destroy - Destroy a hashtable object (&(container_of(key_, struct hashtable_pair, key)->list))
*
* @hashtable: The hashtable
*
* Destroys a hashtable created with hashtable_create().
*/
void hashtable_destroy(hashtable_t *hashtable);
/** /**
* hashtable_init - Initialize a hashtable object * hashtable_init - Initialize a hashtable object
* *
* @hashtable: The (statically allocated) hashtable object * @hashtable: The (statically allocated) hashtable object
* @hash_key: The key hashing function
* @cmp_keys: The key compare function. Returns non-zero for equal and
* zero for unequal unequal keys
* @free_key: If non-NULL, called for a key that is no longer referenced.
* @free_value: If non-NULL, called for a value that is no longer referenced.
* *
* Initializes a statically allocated hashtable object. The object * Initializes a statically allocated hashtable object. The object
* should be cleared with hashtable_close when it's no longer used. * should be cleared with hashtable_close when it's no longer used.
* *
* Returns 0 on success, -1 on error (out of memory). * Returns 0 on success, -1 on error (out of memory).
*/ */
int hashtable_init(hashtable_t *hashtable, int hashtable_init(hashtable_t *hashtable);
key_hash_fn hash_key, key_cmp_fn cmp_keys,
free_fn free_key, free_fn free_value);
/** /**
* hashtable_close - Release all resources used by a hashtable object * hashtable_close - Release all resources used by a hashtable object
@ -99,20 +66,19 @@ void hashtable_close(hashtable_t *hashtable);
* *
* @hashtable: The hashtable object * @hashtable: The hashtable object
* @key: The key * @key: The key
* @serial: For addition order of keys
* @value: The value * @value: The value
* *
* If a value with the given key already exists, its value is replaced * If a value with the given key already exists, its value is replaced
* with the new value. * with the new value. Value is "stealed" in the sense that hashtable
* * doesn't increment its refcount but decreases the refcount when the
* Key and value are "stealed" in the sense that hashtable frees them * value is no longer needed.
* automatically when they are no longer used. The freeing is
* accomplished by calling free_key and free_value functions that were
* supplied to hashtable_new. In case one or both of the free
* functions is NULL, the corresponding item is not "stealed".
* *
* Returns 0 on success, -1 on failure (out of memory). * Returns 0 on success, -1 on failure (out of memory).
*/ */
int hashtable_set(hashtable_t *hashtable, void *key, void *value); int hashtable_set(hashtable_t *hashtable,
const char *key, size_t serial,
json_t *value);
/** /**
* hashtable_get - Get a value associated with a key * hashtable_get - Get a value associated with a key
@ -122,7 +88,7 @@ int hashtable_set(hashtable_t *hashtable, void *key, void *value);
* *
* Returns value if it is found, or NULL otherwise. * Returns value if it is found, or NULL otherwise.
*/ */
void *hashtable_get(hashtable_t *hashtable, const void *key); void *hashtable_get(hashtable_t *hashtable, const char *key);
/** /**
* hashtable_del - Remove a value from the hashtable * hashtable_del - Remove a value from the hashtable
@ -132,7 +98,7 @@ void *hashtable_get(hashtable_t *hashtable, const void *key);
* *
* Returns 0 on success, or -1 if the key was not found. * Returns 0 on success, or -1 if the key was not found.
*/ */
int hashtable_del(hashtable_t *hashtable, const void *key); int hashtable_del(hashtable_t *hashtable, const char *key);
/** /**
* hashtable_clear - Clear hashtable * hashtable_clear - Clear hashtable
@ -169,7 +135,7 @@ void *hashtable_iter(hashtable_t *hashtable);
* Like hashtable_iter() but returns an iterator pointing to a * Like hashtable_iter() but returns an iterator pointing to a
* specific key. * specific key.
*/ */
void *hashtable_iter_at(hashtable_t *hashtable, const void *key); void *hashtable_iter_at(hashtable_t *hashtable, const char *key);
/** /**
* hashtable_iter_next - Advance an iterator * hashtable_iter_next - Advance an iterator
@ -189,6 +155,13 @@ void *hashtable_iter_next(hashtable_t *hashtable, void *iter);
*/ */
void *hashtable_iter_key(void *iter); void *hashtable_iter_key(void *iter);
/**
* hashtable_iter_serial - Retrieve the serial number pointed to by an iterator
*
* @iter: The iterator
*/
size_t hashtable_iter_serial(void *iter);
/** /**
* hashtable_iter_value - Retrieve the value pointed by an iterator * hashtable_iter_value - Retrieve the value pointed by an iterator
* *
@ -202,6 +175,6 @@ void *hashtable_iter_value(void *iter);
* @iter: The iterator * @iter: The iterator
* @value: The value to set * @value: The value to set
*/ */
void hashtable_iter_set(hashtable_t *hashtable, void *iter, void *value); void hashtable_iter_set(void *iter, json_t *value);
#endif #endif

View File

@ -0,0 +1,65 @@
LIBRARY "jansson"
EXPORTS
json_delete
json_true
json_false
json_null
json_string
json_string_nocheck
json_string_value
json_string_set
json_string_set_nocheck
json_integer
json_integer_value
json_integer_set
json_real
json_real_value
json_real_set
json_number_value
json_array
json_array_size
json_array_get
json_array_set_new
json_array_append_new
json_array_insert_new
json_array_remove
json_array_clear
json_array_extend
json_object
json_object_size
json_object_get
json_object_set_new
json_object_set_new_nocheck
json_object_del
json_object_clear
json_object_update
json_object_update_existing
json_object_update_missing
json_object_iter
json_object_iter_at
json_object_iter_next
json_object_iter_key
json_object_iter_value
json_object_iter_set_new
json_object_key_to_iter
json_dumps
json_dumpf
json_dump_file
json_dump_callback
json_loads
json_loadb
json_loadf
json_load_file
json_load_callback
json_equal
json_copy
json_deep_copy
json_pack
json_pack_ex
json_vpack_ex
json_unpack
json_unpack_ex
json_vunpack_ex
json_set_alloc_funcs

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org> * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* *
* Jansson is free software; you can redistribute it and/or modify * Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details. * it under the terms of the MIT license. See LICENSE for details.
@ -21,11 +21,11 @@ extern "C" {
/* version */ /* version */
#define JANSSON_MAJOR_VERSION 2 #define JANSSON_MAJOR_VERSION 2
#define JANSSON_MINOR_VERSION 1 #define JANSSON_MINOR_VERSION 4
#define JANSSON_MICRO_VERSION 0 #define JANSSON_MICRO_VERSION 0
/* Micro version is omitted if it's 0 */ /* Micro version is omitted if it's 0 */
#define JANSSON_VERSION "2.1" #define JANSSON_VERSION "2.4"
/* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this /* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this
for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */ for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */
@ -52,8 +52,12 @@ typedef struct {
size_t refcount; size_t refcount;
} json_t; } json_t;
#if JSON_INTEGER_IS_LONG_LONG && (!defined(WIN32)) #if JSON_INTEGER_IS_LONG_LONG
#ifdef _WIN32
#define JSON_INTEGER_FORMAT "I64d"
#else
#define JSON_INTEGER_FORMAT "lld" #define JSON_INTEGER_FORMAT "lld"
#endif
typedef long long json_int_t; typedef long long json_int_t;
#else #else
#define JSON_INTEGER_FORMAT "ld" #define JSON_INTEGER_FORMAT "ld"
@ -82,6 +86,7 @@ json_t *json_integer(json_int_t value);
json_t *json_real(double value); json_t *json_real(double value);
json_t *json_true(void); json_t *json_true(void);
json_t *json_false(void); json_t *json_false(void);
#define json_boolean(val) ((val) ? json_true() : json_false())
json_t *json_null(void); json_t *json_null(void);
static JSON_INLINE static JSON_INLINE
@ -126,13 +131,21 @@ int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value);
int json_object_del(json_t *object, const char *key); int json_object_del(json_t *object, const char *key);
int json_object_clear(json_t *object); int json_object_clear(json_t *object);
int json_object_update(json_t *object, json_t *other); int json_object_update(json_t *object, json_t *other);
int json_object_update_existing(json_t *object, json_t *other);
int json_object_update_missing(json_t *object, json_t *other);
void *json_object_iter(json_t *object); void *json_object_iter(json_t *object);
void *json_object_iter_at(json_t *object, const char *key); void *json_object_iter_at(json_t *object, const char *key);
void *json_object_key_to_iter(const char *key);
void *json_object_iter_next(json_t *object, void *iter); void *json_object_iter_next(json_t *object, void *iter);
const char *json_object_iter_key(void *iter); const char *json_object_iter_key(void *iter);
json_t *json_object_iter_value(void *iter); json_t *json_object_iter_value(void *iter);
int json_object_iter_set_new(json_t *object, void *iter, json_t *value); int json_object_iter_set_new(json_t *object, void *iter, json_t *value);
#define json_object_foreach(object, key, value) \
for(key = json_object_iter_key(json_object_iter(object)); \
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))))
static JSON_INLINE static JSON_INLINE
int json_object_set(json_t *object, const char *key, json_t *value) int json_object_set(json_t *object, const char *key, json_t *value)
{ {
@ -218,11 +231,15 @@ json_t *json_deep_copy(json_t *value);
#define JSON_REJECT_DUPLICATES 0x1 #define JSON_REJECT_DUPLICATES 0x1
#define JSON_DISABLE_EOF_CHECK 0x2 #define JSON_DISABLE_EOF_CHECK 0x2
#define JSON_DECODE_ANY 0x4
typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data);
json_t *json_loads(const char *input, size_t flags, json_error_t *error); json_t *json_loads(const char *input, size_t flags, json_error_t *error);
json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error); json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error);
json_t *json_loadf(FILE *input, size_t flags, json_error_t *error); json_t *json_loadf(FILE *input, size_t flags, json_error_t *error);
json_t *json_load_file(const char *path, size_t flags, json_error_t *error); json_t *json_load_file(const char *path, size_t flags, json_error_t *error);
json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error);
/* encoding */ /* encoding */
@ -233,11 +250,14 @@ json_t *json_load_file(const char *path, size_t flags, json_error_t *error);
#define JSON_SORT_KEYS 0x80 #define JSON_SORT_KEYS 0x80
#define JSON_PRESERVE_ORDER 0x100 #define JSON_PRESERVE_ORDER 0x100
#define JSON_ENCODE_ANY 0x200 #define JSON_ENCODE_ANY 0x200
#define JSON_ESCAPE_SLASH 0x400
typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data);
char *json_dumps(const json_t *json, size_t flags); char *json_dumps(const json_t *json, size_t flags);
int json_dumpf(const json_t *json, FILE *output, size_t flags); int json_dumpf(const json_t *json, FILE *output, size_t flags);
int json_dump_file(const json_t *json, const char *path, size_t flags); int json_dump_file(const json_t *json, const char *path, size_t flags);
int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags);
/* custom memory allocation */ /* custom memory allocation */

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2010-2011 Petri Lehtinen <petri@digip.org> * Copyright (c) 2010-2012 Petri Lehtinen <petri@digip.org>
* *
* Jansson is free software; you can redistribute it and/or modify * Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details. * it under the terms of the MIT license. See LICENSE for details.
@ -27,8 +27,13 @@
#define JSON_INLINE inline #define JSON_INLINE inline
#endif #endif
/* If your compiler supports the `long long` type, /* If your compiler supports the `long long` type and the strtoll()
JSON_INTEGER_IS_LONG_LONG is defined to 1, otherwise to 0. */ library function, JSON_INTEGER_IS_LONG_LONG is defined to 1,
otherwise to 0. */
#define JSON_INTEGER_IS_LONG_LONG 1 #define JSON_INTEGER_IS_LONG_LONG 1
/* If locale.h and localeconv() are available, define to 1,
otherwise to 0. */
#define JSON_HAVE_LOCALECONV 1
#endif #endif

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2010-2011 Petri Lehtinen <petri@digip.org> * Copyright (c) 2010-2012 Petri Lehtinen <petri@digip.org>
* *
* Jansson is free software; you can redistribute it and/or modify * Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details. * it under the terms of the MIT license. See LICENSE for details.
@ -27,8 +27,13 @@
#define JSON_INLINE @json_inline@ #define JSON_INLINE @json_inline@
#endif #endif
/* If your compiler supports the `long long` type, /* If your compiler supports the `long long` type and the strtoll()
JSON_INTEGER_IS_LONG_LONG is defined to 1, otherwise to 0. */ library function, JSON_INTEGER_IS_LONG_LONG is defined to 1,
otherwise to 0. */
#define JSON_INTEGER_IS_LONG_LONG @json_have_long_long@ #define JSON_INTEGER_IS_LONG_LONG @json_have_long_long@
/* If locale.h and localeconv() are available, define to 1,
otherwise to 0. */
#define JSON_HAVE_LOCALECONV @json_have_localeconv@
#endif #endif

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org> * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* *
* Jansson is free software; you can redistribute it and/or modify * Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details. * it under the terms of the MIT license. See LICENSE for details.
@ -11,6 +11,7 @@
#include <stddef.h> #include <stddef.h>
#include "jansson.h" #include "jansson.h"
#include "hashtable.h" #include "hashtable.h"
#include "strbuffer.h"
#define container_of(ptr_, type_, member_) \ #define container_of(ptr_, type_, member_) \
((type_ *)((char *)ptr_ - offsetof(type_, member_))) ((type_ *)((char *)ptr_ - offsetof(type_, member_)))
@ -66,16 +67,6 @@ typedef struct {
#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) #define json_to_integer(json_) container_of(json_, json_integer_t, json)
size_t jsonp_hash_str(const void *ptr);
int jsonp_str_equal(const void *ptr1, const void *ptr2);
typedef struct {
size_t serial;
char key[1];
} object_key_t;
const object_key_t *jsonp_object_iter_fullkey(void *iter);
void jsonp_error_init(json_error_t *error, const char *source); 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_source(json_error_t *error, const char *source);
void jsonp_error_set(json_error_t *error, int line, int column, void jsonp_error_set(json_error_t *error, int line, int column,
@ -83,9 +74,19 @@ void jsonp_error_set(json_error_t *error, int line, int column,
void jsonp_error_vset(json_error_t *error, int line, int column, void jsonp_error_vset(json_error_t *error, int line, int column,
size_t position, const char *msg, va_list ap); size_t position, const char *msg, va_list ap);
/* Locale independent string<->double conversions */
int jsonp_strtod(strbuffer_t *strbuffer, double *out);
int jsonp_dtostr(char *buffer, size_t size, double value);
/* Wrappers for custom memory functions */ /* Wrappers for custom memory functions */
void* jsonp_malloc(size_t size); void* jsonp_malloc(size_t size);
void jsonp_free(void *ptr); void jsonp_free(void *ptr);
char *jsonp_strdup(const char *str); char *jsonp_strdup(const char *str);
/* Windows compatibility */
#ifdef _WIN32
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#endif
#endif #endif

View File

@ -1,12 +1,11 @@
/* /*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org> * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* *
* Jansson is free software; you can redistribute it and/or modify * Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details. * it under the terms of the MIT license. See LICENSE for details.
*/ */
#define _GNU_SOURCE #define _GNU_SOURCE
#include <ctype.h>
#include <errno.h> #include <errno.h>
#include <limits.h> #include <limits.h>
#include <stdio.h> #include <stdio.h>
@ -14,7 +13,7 @@
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <jansson.h> #include "jansson.h"
#include "jansson_private.h" #include "jansson_private.h"
#include "strbuffer.h" #include "strbuffer.h"
#include "utf.h" #include "utf.h"
@ -32,6 +31,14 @@
#define TOKEN_FALSE 260 #define TOKEN_FALSE 260
#define TOKEN_NULL 261 #define TOKEN_NULL 261
/* Locale independent versions of isxxx() functions */
#define l_isupper(c) ('A' <= (c) && (c) <= 'Z')
#define l_islower(c) ('a' <= (c) && (c) <= 'z')
#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')
/* Read one byte from stream, convert to unsigned char, then int, and /* Read one byte from stream, convert to unsigned char, then int, and
return. return EOF on end of file. This corresponds to the return. return EOF on end of file. This corresponds to the
behaviour of fgetc(). */ behaviour of fgetc(). */
@ -41,7 +48,7 @@ typedef struct {
get_func get; get_func get;
void *data; void *data;
char buffer[5]; char buffer[5];
int buffer_pos; size_t buffer_pos;
int state; int state;
int line; int line;
int column, last_column; int column, last_column;
@ -69,6 +76,7 @@ static void error_set(json_error_t *error, const lex_t *lex,
{ {
va_list ap; va_list ap;
char msg_text[JSON_ERROR_TEXT_LENGTH]; char msg_text[JSON_ERROR_TEXT_LENGTH];
char msg_with_context[JSON_ERROR_TEXT_LENGTH];
int line = -1, col = -1; int line = -1, col = -1;
size_t pos = 0; size_t pos = 0;
@ -79,12 +87,12 @@ static void error_set(json_error_t *error, const lex_t *lex,
va_start(ap, msg); va_start(ap, msg);
vsnprintf(msg_text, JSON_ERROR_TEXT_LENGTH, msg, ap); vsnprintf(msg_text, JSON_ERROR_TEXT_LENGTH, msg, ap);
msg_text[JSON_ERROR_TEXT_LENGTH - 1] = '\0';
va_end(ap); va_end(ap);
if(lex) if(lex)
{ {
const char *saved_text = strbuffer_value(&lex->saved_text); const char *saved_text = strbuffer_value(&lex->saved_text);
char msg_with_context[JSON_ERROR_TEXT_LENGTH];
line = lex->stream.line; line = lex->stream.line;
col = lex->stream.column; col = lex->stream.column;
@ -95,6 +103,7 @@ static void error_set(json_error_t *error, const lex_t *lex,
if(lex->saved_text.length <= 20) { if(lex->saved_text.length <= 20) {
snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH, snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH,
"%s near '%s'", msg_text, saved_text); "%s near '%s'", msg_text, saved_text);
msg_with_context[JSON_ERROR_TEXT_LENGTH - 1] = '\0';
result = msg_with_context; result = msg_with_context;
} }
} }
@ -107,6 +116,7 @@ static void error_set(json_error_t *error, const lex_t *lex,
else { else {
snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH, snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH,
"%s near end of file", msg_text); "%s near end of file", msg_text);
msg_with_context[JSON_ERROR_TEXT_LENGTH - 1] = '\0';
result = msg_with_context; result = msg_with_context;
} }
} }
@ -268,11 +278,11 @@ static int32_t decode_unicode_escape(const char *str)
for(i = 1; i <= 4; i++) { for(i = 1; i <= 4; i++) {
char c = str[i]; char c = str[i];
value <<= 4; value <<= 4;
if(isdigit(c)) if(l_isdigit(c))
value += c - '0'; value += c - '0';
else if(islower(c)) else if(l_islower(c))
value += c - 'a' + 10; value += c - 'a' + 10;
else if(isupper(c)) else if(l_isupper(c))
value += c - 'A' + 10; value += c - 'A' + 10;
else else
assert(0); assert(0);
@ -317,7 +327,7 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
if(c == 'u') { if(c == 'u') {
c = lex_get_save(lex, error); c = lex_get_save(lex, error);
for(i = 0; i < 4; i++) { for(i = 0; i < 4; i++) {
if(!isxdigit(c)) { if(!l_isxdigit(c)) {
error_set(error, lex, "invalid escape"); error_set(error, lex, "invalid escape");
goto out; goto out;
} }
@ -437,7 +447,11 @@ out:
} }
#if JSON_INTEGER_IS_LONG_LONG #if JSON_INTEGER_IS_LONG_LONG
#ifdef _MSC_VER // Microsoft Visual Studio
#define json_strtoint _strtoi64
#else
#define json_strtoint strtoll #define json_strtoint strtoll
#endif
#else #else
#define json_strtoint strtol #define json_strtoint strtol
#endif #endif
@ -455,14 +469,14 @@ static int lex_scan_number(lex_t *lex, int c, json_error_t *error)
if(c == '0') { if(c == '0') {
c = lex_get_save(lex, error); c = lex_get_save(lex, error);
if(isdigit(c)) { if(l_isdigit(c)) {
lex_unget_unsave(lex, c); lex_unget_unsave(lex, c);
goto out; goto out;
} }
} }
else if(isdigit(c)) { else if(l_isdigit(c)) {
c = lex_get_save(lex, error); c = lex_get_save(lex, error);
while(isdigit(c)) while(l_isdigit(c))
c = lex_get_save(lex, error); c = lex_get_save(lex, error);
} }
else { else {
@ -496,14 +510,14 @@ static int lex_scan_number(lex_t *lex, int c, json_error_t *error)
if(c == '.') { if(c == '.') {
c = lex_get(lex, error); c = lex_get(lex, error);
if(!isdigit(c)) { if(!l_isdigit(c)) {
lex_unget(lex, c); lex_unget(lex, c);
goto out; goto out;
} }
lex_save(lex, c); lex_save(lex, c);
c = lex_get_save(lex, error); c = lex_get_save(lex, error);
while(isdigit(c)) while(l_isdigit(c))
c = lex_get_save(lex, error); c = lex_get_save(lex, error);
} }
@ -512,24 +526,19 @@ static int lex_scan_number(lex_t *lex, int c, json_error_t *error)
if(c == '+' || c == '-') if(c == '+' || c == '-')
c = lex_get_save(lex, error); c = lex_get_save(lex, error);
if(!isdigit(c)) { if(!l_isdigit(c)) {
lex_unget_unsave(lex, c); lex_unget_unsave(lex, c);
goto out; goto out;
} }
c = lex_get_save(lex, error); c = lex_get_save(lex, error);
while(isdigit(c)) while(l_isdigit(c))
c = lex_get_save(lex, error); c = lex_get_save(lex, error);
} }
lex_unget_unsave(lex, c); lex_unget_unsave(lex, c);
saved_text = strbuffer_value(&lex->saved_text); if(jsonp_strtod(&lex->saved_text, &value)) {
errno = 0;
value = strtod(saved_text, &end);
assert(end == saved_text + lex->saved_text.length);
if(errno == ERANGE && value != 0) {
error_set(error, lex, "real number overflow"); error_set(error, lex, "real number overflow");
goto out; goto out;
} }
@ -575,17 +584,17 @@ static int lex_scan(lex_t *lex, json_error_t *error)
else if(c == '"') else if(c == '"')
lex_scan_string(lex, error); lex_scan_string(lex, error);
else if(isdigit(c) || c == '-') { else if(l_isdigit(c) || c == '-') {
if(lex_scan_number(lex, c, error)) if(lex_scan_number(lex, c, error))
goto out; goto out;
} }
else if(isupper(c) || islower(c)) { else if(l_isalpha(c)) {
/* eat up the whole identifier for clearer error messages */ /* eat up the whole identifier for clearer error messages */
const char *saved_text; const char *saved_text;
c = lex_get_save(lex, error); c = lex_get_save(lex, error);
while(isupper(c) || islower(c)) while(l_isalpha(c))
c = lex_get_save(lex, error); c = lex_get_save(lex, error);
lex_unget_unsave(lex, c); lex_unget_unsave(lex, c);
@ -818,9 +827,11 @@ static json_t *parse_json(lex_t *lex, size_t flags, json_error_t *error)
json_t *result; json_t *result;
lex_scan(lex, error); lex_scan(lex, error);
if(lex->token != '[' && lex->token != '{') { if(!(flags & JSON_DECODE_ANY)) {
error_set(error, lex, "'[' or '{' expected"); if(lex->token != '[' && lex->token != '{') {
return NULL; error_set(error, lex, "'[' or '{' expected");
return NULL;
}
} }
result = parse_value(lex, flags, error); result = parse_value(lex, flags, error);
@ -832,10 +843,15 @@ static json_t *parse_json(lex_t *lex, size_t flags, json_error_t *error)
if(lex->token != TOKEN_EOF) { if(lex->token != TOKEN_EOF) {
error_set(error, lex, "end of file expected"); error_set(error, lex, "end of file expected");
json_decref(result); json_decref(result);
result = NULL; return NULL;
} }
} }
if(error) {
/* Save the position even though there was no error */
error->position = lex->stream.position;
}
return result; return result;
} }
@ -865,13 +881,19 @@ json_t *json_loads(const char *string, size_t flags, json_error_t *error)
json_t *result; json_t *result;
string_data_t stream_data; string_data_t stream_data;
jsonp_error_init(error, "<string>");
if (string == NULL) {
error_set(error, NULL, "wrong arguments");
return NULL;
}
stream_data.data = string; stream_data.data = string;
stream_data.pos = 0; stream_data.pos = 0;
if(lex_init(&lex, string_get, (void *)&stream_data)) if(lex_init(&lex, string_get, (void *)&stream_data))
return NULL; return NULL;
jsonp_error_init(error, "<string>");
result = parse_json(&lex, flags, error); result = parse_json(&lex, flags, error);
lex_close(&lex); lex_close(&lex);
@ -903,6 +925,13 @@ json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t
json_t *result; json_t *result;
buffer_data_t stream_data; buffer_data_t stream_data;
jsonp_error_init(error, "<buffer>");
if (buffer == NULL) {
error_set(error, NULL, "wrong arguments");
return NULL;
}
stream_data.data = buffer; stream_data.data = buffer;
stream_data.pos = 0; stream_data.pos = 0;
stream_data.len = buflen; stream_data.len = buflen;
@ -910,7 +939,6 @@ json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t
if(lex_init(&lex, buffer_get, (void *)&stream_data)) if(lex_init(&lex, buffer_get, (void *)&stream_data))
return NULL; return NULL;
jsonp_error_init(error, "<buffer>");
result = parse_json(&lex, flags, error); result = parse_json(&lex, flags, error);
lex_close(&lex); lex_close(&lex);
@ -923,15 +951,21 @@ json_t *json_loadf(FILE *input, size_t flags, json_error_t *error)
const char *source; const char *source;
json_t *result; json_t *result;
if(lex_init(&lex, (get_func)fgetc, input))
return NULL;
if(input == stdin) if(input == stdin)
source = "<stdin>"; source = "<stdin>";
else else
source = "<stream>"; source = "<stream>";
jsonp_error_init(error, source); jsonp_error_init(error, source);
if (input == NULL) {
error_set(error, NULL, "wrong arguments");
return NULL;
}
if(lex_init(&lex, (get_func)fgetc, input))
return NULL;
result = parse_json(&lex, flags, error); result = parse_json(&lex, flags, error);
lex_close(&lex); lex_close(&lex);
@ -945,7 +979,12 @@ json_t *json_load_file(const char *path, size_t flags, json_error_t *error)
jsonp_error_init(error, path); jsonp_error_init(error, path);
fp = fopen(path, "r"); if (path == NULL) {
error_set(error, NULL, "wrong arguments");
return NULL;
}
fp = fopen(path, "rb");
if(!fp) if(!fp)
{ {
error_set(error, NULL, "unable to open %s: %s", error_set(error, NULL, "unable to open %s: %s",
@ -958,3 +997,58 @@ json_t *json_load_file(const char *path, size_t flags, json_error_t *error)
fclose(fp); fclose(fp);
return result; return result;
} }
#define MAX_BUF_LEN 1024
typedef struct
{
char data[MAX_BUF_LEN];
size_t len;
size_t pos;
json_load_callback_t callback;
void *arg;
} callback_data_t;
static int callback_get(void *data)
{
char c;
callback_data_t *stream = data;
if(stream->pos >= stream->len) {
stream->pos = 0;
stream->len = stream->callback(stream->data, MAX_BUF_LEN, stream->arg);
if(stream->len == 0 || stream->len == (size_t)-1)
return EOF;
}
c = stream->data[stream->pos];
stream->pos++;
return (unsigned char)c;
}
json_t *json_load_callback(json_load_callback_t callback, void *arg, size_t flags, json_error_t *error)
{
lex_t lex;
json_t *result;
callback_data_t stream_data;
memset(&stream_data, 0, sizeof(stream_data));
stream_data.callback = callback;
stream_data.arg = arg;
jsonp_error_init(error, "<callback>");
if (callback == NULL) {
error_set(error, NULL, "wrong arguments");
return NULL;
}
if(lex_init(&lex, (get_func)callback_get, &stream_data))
return NULL;
result = parse_json(&lex, flags, error);
lex_close(&lex);
return result;
}

View File

@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org> * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2011 Basile Starynkevitch <basile@starynkevitch.net> * Copyright (c) 2011-2012 Basile Starynkevitch <basile@starynkevitch.net>
* *
* Jansson is free software; you can redistribute it and/or modify it * Jansson is free software; you can redistribute it and/or modify it
* under the terms of the MIT license. See LICENSE for details. * under the terms of the MIT license. See LICENSE for details.
@ -9,7 +9,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <jansson.h> #include "jansson.h"
#include "jansson_private.h" #include "jansson_private.h"
/* memory function pointers */ /* memory function pointers */

View File

@ -0,0 +1,647 @@
/*
* Copyright (c) 2009-2012 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
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <string.h>
#include "jansson.h"
#include "jansson_private.h"
#include "utf.h"
typedef struct {
const char *start;
const char *fmt;
char token;
json_error_t *error;
size_t flags;
int line;
int column;
} scanner_t;
static const char *type_names[] = {
"object",
"array",
"string",
"integer",
"real",
"true",
"false",
"null"
};
#define type_name(x) type_names[json_typeof(x)]
static const char *unpack_value_starters = "{[siIbfFOon";
static void scanner_init(scanner_t *s, json_error_t *error,
size_t flags, const char *fmt)
{
s->error = error;
s->flags = flags;
s->fmt = s->start = fmt;
s->line = 1;
s->column = 0;
}
static void next_token(scanner_t *s)
{
const char *t = s->fmt;
s->column++;
/* skip space and ignored chars */
while(*t == ' ' || *t == '\t' || *t == '\n' || *t == ',' || *t == ':') {
if(*t == '\n') {
s->line++;
s->column = 1;
}
else
s->column++;
t++;
}
s->token = *t;
t++;
s->fmt = t;
}
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_set_source(s->error, source);
va_end(ap);
}
static json_t *pack(scanner_t *s, va_list *ap);
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;
json_t *value;
if(!s->token) {
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");
goto error;
}
if(!utf8_check_string(key, -1)) {
set_error(s, "<args>", "Invalid UTF-8 in object key");
goto error;
}
next_token(s);
value = pack(s, ap);
if(!value)
goto error;
if(json_object_set_new_nocheck(object, key, value)) {
set_error(s, "<internal>", "Unable to add key \"%s\"", key);
goto error;
}
next_token(s);
}
return object;
error:
json_decref(object);
return NULL;
}
static json_t *pack_array(scanner_t *s, va_list *ap)
{
json_t *array = json_array();
next_token(s);
while(s->token != ']') {
json_t *value;
if(!s->token) {
set_error(s, "<format>", "Unexpected end of format string");
goto error;
}
value = pack(s, ap);
if(!value)
goto error;
if(json_array_append_new(array, value)) {
set_error(s, "<internal>", "Unable to append to array");
goto error;
}
next_token(s);
}
return array;
error:
json_decref(array);
return NULL;
}
static json_t *pack(scanner_t *s, va_list *ap)
{
switch(s->token) {
case '{':
return pack_object(s, ap);
case '[':
return pack_array(s, 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");
return NULL;
}
return json_string_nocheck(str);
}
case 'n': /* null */
return json_null();
case 'b': /* boolean */
return va_arg(*ap, int) ? json_true() : json_false();
case 'i': /* integer from int */
return json_integer(va_arg(*ap, int));
case 'I': /* integer from json_int_t */
return json_integer(va_arg(*ap, json_int_t));
case 'f': /* real */
return json_real(va_arg(*ap, double));
case 'O': /* a json_t object; increments refcount */
return json_incref(va_arg(*ap, json_t *));
case 'o': /* a json_t object; doesn't increment refcount */
return va_arg(*ap, json_t *);
default:
set_error(s, "<format>", "Unexpected format character '%c'",
s->token);
return NULL;
}
}
static int unpack(scanner_t *s, json_t *root, va_list *ap);
static int unpack_object(scanner_t *s, json_t *root, va_list *ap)
{
int ret = -1;
int strict = 0;
/* Use a set (emulated by a hashtable) to check that all object
keys are accessed. Checking that the correct number of keys
were accessed is not enough, as the same key can be unpacked
multiple times.
*/
hashtable_t key_set;
if(hashtable_init(&key_set)) {
set_error(s, "<internal>", "Out of memory");
return -1;
}
if(root && !json_is_object(root)) {
set_error(s, "<validation>", "Expected object, got %s",
type_name(root));
goto out;
}
next_token(s);
while(s->token != '}') {
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);
goto out;
}
if(!s->token) {
set_error(s, "<format>", "Unexpected end of format string");
goto out;
}
if(s->token == '!' || s->token == '*') {
strict = (s->token == '!' ? 1 : -1);
next_token(s);
continue;
}
if(s->token != 's') {
set_error(s, "<format>", "Expected format 's', got '%c'", s->token);
goto out;
}
key = va_arg(*ap, const char *);
if(!key) {
set_error(s, "<args>", "NULL object key");
goto out;
}
next_token(s);
if(s->token == '?') {
opt = 1;
next_token(s);
}
if(!root) {
/* skipping */
value = NULL;
}
else {
value = json_object_get(root, key);
if(!value && !opt) {
set_error(s, "<validation>", "Object item not found: %s", key);
goto out;
}
}
if(unpack(s, value, ap))
goto out;
hashtable_set(&key_set, key, 0, json_null());
next_token(s);
}
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;
}
ret = 0;
out:
hashtable_close(&key_set);
return ret;
}
static int unpack_array(scanner_t *s, json_t *root, va_list *ap)
{
size_t i = 0;
int strict = 0;
if(root && !json_is_array(root)) {
set_error(s, "<validation>", "Expected array, got %s", type_name(root));
return -1;
}
next_token(s);
while(s->token != ']') {
json_t *value;
if(strict != 0) {
set_error(s, "<format>", "Expected ']' after '%c', got '%c'",
(strict == 1 ? '!' : '*'),
s->token);
return -1;
}
if(!s->token) {
set_error(s, "<format>", "Unexpected end of format string");
return -1;
}
if(s->token == '!' || s->token == '*') {
strict = (s->token == '!' ? 1 : -1);
next_token(s);
continue;
}
if(!strchr(unpack_value_starters, s->token)) {
set_error(s, "<format>", "Unexpected format character '%c'",
s->token);
return -1;
}
if(!root) {
/* skipping */
value = NULL;
}
else {
value = json_array_get(root, i);
if(!value) {
set_error(s, "<validation>", "Array index %lu out of range",
(unsigned long)i);
return -1;
}
}
if(unpack(s, value, ap))
return -1;
next_token(s);
i++;
}
if(strict == 0 && (s->flags & JSON_STRICT))
strict = 1;
if(root && strict == 1 && i != json_array_size(root)) {
long diff = (long)json_array_size(root) - (long)i;
set_error(s, "<validation>", "%li array item(s) left unpacked", diff);
return -1;
}
return 0;
}
static int unpack(scanner_t *s, json_t *root, va_list *ap)
{
switch(s->token)
{
case '{':
return unpack_object(s, root, ap);
case '[':
return unpack_array(s, root, ap);
case 's':
if(root && !json_is_string(root)) {
set_error(s, "<validation>", "Expected string, got %s",
type_name(root));
return -1;
}
if(!(s->flags & JSON_VALIDATE_ONLY)) {
const char **target;
target = va_arg(*ap, const char **);
if(!target) {
set_error(s, "<args>", "NULL string argument");
return -1;
}
if(root)
*target = json_string_value(root);
}
return 0;
case 'i':
if(root && !json_is_integer(root)) {
set_error(s, "<validation>", "Expected integer, got %s",
type_name(root));
return -1;
}
if(!(s->flags & JSON_VALIDATE_ONLY)) {
int *target = va_arg(*ap, int*);
if(root)
*target = (int)json_integer_value(root);
}
return 0;
case 'I':
if(root && !json_is_integer(root)) {
set_error(s, "<validation>", "Expected integer, got %s",
type_name(root));
return -1;
}
if(!(s->flags & JSON_VALIDATE_ONLY)) {
json_int_t *target = va_arg(*ap, json_int_t*);
if(root)
*target = json_integer_value(root);
}
return 0;
case 'b':
if(root && !json_is_boolean(root)) {
set_error(s, "<validation>", "Expected true or false, got %s",
type_name(root));
return -1;
}
if(!(s->flags & JSON_VALIDATE_ONLY)) {
int *target = va_arg(*ap, int*);
if(root)
*target = json_is_true(root);
}
return 0;
case 'f':
if(root && !json_is_real(root)) {
set_error(s, "<validation>", "Expected real, got %s",
type_name(root));
return -1;
}
if(!(s->flags & JSON_VALIDATE_ONLY)) {
double *target = va_arg(*ap, double*);
if(root)
*target = json_real_value(root);
}
return 0;
case 'F':
if(root && !json_is_number(root)) {
set_error(s, "<validation>", "Expected real or integer, got %s",
type_name(root));
return -1;
}
if(!(s->flags & JSON_VALIDATE_ONLY)) {
double *target = va_arg(*ap, double*);
if(root)
*target = json_number_value(root);
}
return 0;
case 'O':
if(root && !(s->flags & JSON_VALIDATE_ONLY))
json_incref(root);
/* Fall through */
case 'o':
if(!(s->flags & JSON_VALIDATE_ONLY)) {
json_t **target = va_arg(*ap, json_t**);
if(root)
*target = root;
}
return 0;
case 'n':
/* Never assign, just validate */
if(root && !json_is_null(root)) {
set_error(s, "<validation>", "Expected null, got %s",
type_name(root));
return -1;
}
return 0;
default:
set_error(s, "<format>", "Unexpected format character '%c'",
s->token);
return -1;
}
}
json_t *json_vpack_ex(json_error_t *error, size_t flags,
const char *fmt, va_list ap)
{
scanner_t s;
va_list ap_copy;
json_t *value;
if(!fmt || !*fmt) {
jsonp_error_init(error, "<format>");
jsonp_error_set(error, -1, -1, 0, "NULL or empty format string");
return NULL;
}
jsonp_error_init(error, NULL);
scanner_init(&s, error, flags, fmt);
next_token(&s);
va_copy(ap_copy, ap);
value = pack(&s, &ap_copy);
va_end(ap_copy);
if(!value)
return NULL;
next_token(&s);
if(s.token) {
json_decref(value);
set_error(&s, "<format>", "Garbage after format string");
return NULL;
}
return value;
}
json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...)
{
json_t *value;
va_list ap;
va_start(ap, fmt);
value = json_vpack_ex(error, flags, fmt, ap);
va_end(ap);
return value;
}
json_t *json_pack(const char *fmt, ...)
{
json_t *value;
va_list ap;
va_start(ap, fmt);
value = json_vpack_ex(NULL, 0, fmt, ap);
va_end(ap);
return value;
}
int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags,
const char *fmt, va_list ap)
{
scanner_t s;
va_list ap_copy;
if(!root) {
jsonp_error_init(error, "<root>");
jsonp_error_set(error, -1, -1, 0, "NULL root value");
return -1;
}
if(!fmt || !*fmt) {
jsonp_error_init(error, "<format>");
jsonp_error_set(error, -1, -1, 0, "NULL or empty format string");
return -1;
}
jsonp_error_init(error, NULL);
scanner_init(&s, error, flags, fmt);
next_token(&s);
va_copy(ap_copy, ap);
if(unpack(&s, root, &ap_copy)) {
va_end(ap_copy);
return -1;
}
va_end(ap_copy);
next_token(&s);
if(s.token) {
set_error(&s, "<format>", "Garbage after format string");
return -1;
}
return 0;
}
int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = json_vunpack_ex(root, error, flags, fmt, ap);
va_end(ap);
return ret;
}
int json_unpack(json_t *root, const char *fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = json_vunpack_ex(root, NULL, 0, fmt, ap);
va_end(ap);
return ret;
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org> * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* *
* Jansson is free software; you can redistribute it and/or modify * Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details. * it under the terms of the MIT license. See LICENSE for details.
@ -13,6 +13,7 @@
#define STRBUFFER_MIN_SIZE 16 #define STRBUFFER_MIN_SIZE 16
#define STRBUFFER_FACTOR 2 #define STRBUFFER_FACTOR 2
#define STRBUFFER_SIZE_MAX ((size_t)-1)
int strbuffer_init(strbuffer_t *strbuff) int strbuffer_init(strbuffer_t *strbuff)
{ {
@ -64,13 +65,19 @@ int strbuffer_append_byte(strbuffer_t *strbuff, char byte)
return strbuffer_append_bytes(strbuff, &byte, 1); return strbuffer_append_bytes(strbuff, &byte, 1);
} }
int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, int size) int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size)
{ {
if(strbuff->length + size >= strbuff->size) if(size >= strbuff->size - strbuff->length)
{ {
size_t new_size; size_t new_size;
char *new_value; char *new_value;
/* avoid integer overflow */
if (strbuff->size > STRBUFFER_SIZE_MAX / STRBUFFER_FACTOR
|| size > STRBUFFER_SIZE_MAX - 1
|| strbuff->length > STRBUFFER_SIZE_MAX - 1 - size)
return -1;
new_size = max(strbuff->size * STRBUFFER_FACTOR, new_size = max(strbuff->size * STRBUFFER_FACTOR,
strbuff->length + size + 1); strbuff->length + size + 1);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org> * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* *
* Jansson is free software; you can redistribute it and/or modify * Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details. * it under the terms of the MIT license. See LICENSE for details.
@ -10,8 +10,8 @@
typedef struct { typedef struct {
char *value; char *value;
int length; /* bytes used */ size_t length; /* bytes used */
int size; /* bytes allocated */ size_t size; /* bytes allocated */
} strbuffer_t; } strbuffer_t;
int strbuffer_init(strbuffer_t *strbuff); int strbuffer_init(strbuffer_t *strbuff);
@ -24,7 +24,7 @@ char *strbuffer_steal_value(strbuffer_t *strbuff);
int strbuffer_append(strbuffer_t *strbuff, const char *string); int strbuffer_append(strbuffer_t *strbuff, const char *string);
int strbuffer_append_byte(strbuffer_t *strbuff, char byte); int strbuffer_append_byte(strbuffer_t *strbuff, char byte);
int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, int size); int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size);
char strbuffer_pop(strbuffer_t *strbuff); char strbuffer_pop(strbuffer_t *strbuff);

129
compat/jansson/strconv.c Normal file
View File

@ -0,0 +1,129 @@
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "jansson_private.h"
#include "strbuffer.h"
#if JSON_HAVE_LOCALECONV
#include <locale.h>
/*
- This code assumes that the decimal separator is exactly one
character.
- If setlocale() is called by another thread between the call to
localeconv() and the call to sprintf() or strtod(), the result may
be wrong. setlocale() is not thread-safe and should not be used
this way. Multi-threaded programs should use uselocale() instead.
*/
static void to_locale(strbuffer_t *strbuffer)
{
const char *point;
char *pos;
point = localeconv()->decimal_point;
if(*point == '.') {
/* No conversion needed */
return;
}
pos = strchr(strbuffer->value, '.');
if(pos)
*pos = *point;
}
static void from_locale(char *buffer)
{
const char *point;
char *pos;
point = localeconv()->decimal_point;
if(*point == '.') {
/* No conversion needed */
return;
}
pos = strchr(buffer, *point);
if(pos)
*pos = '.';
}
#endif
int jsonp_strtod(strbuffer_t *strbuffer, double *out)
{
double value;
char *end;
#if JSON_HAVE_LOCALECONV
to_locale(strbuffer);
#endif
errno = 0;
value = strtod(strbuffer->value, &end);
assert(end == strbuffer->value + strbuffer->length);
if(errno == ERANGE && value != 0) {
/* Overflow */
return -1;
}
*out = value;
return 0;
}
int jsonp_dtostr(char *buffer, size_t size, double value)
{
int ret;
char *start, *end;
size_t length;
ret = snprintf(buffer, size, "%.17g", value);
if(ret < 0)
return -1;
length = (size_t)ret;
if(length >= size)
return -1;
#if JSON_HAVE_LOCALECONV
from_locale(buffer);
#endif
/* Make sure there's a dot or 'e' in the output. Otherwise
a real is converted to an integer when decoding */
if(strchr(buffer, '.') == NULL &&
strchr(buffer, 'e') == NULL)
{
if(length + 3 >= size) {
/* No space to append ".0" */
return -1;
}
buffer[length] = '.';
buffer[length + 1] = '0';
buffer[length + 2] = '\0';
length += 2;
}
/* Remove leading '+' from positive exponent. Also remove leading
zeros from exponents (added by some printf() implementations) */
start = strchr(buffer, 'e');
if(start) {
start++;
end = start + 1;
if(*start == '-')
start++;
while(*end == '0')
end++;
if(end != start) {
memmove(start, end, length - (size_t)(end - buffer));
length -= (size_t)(end - start);
}
}
return (int)length;
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org> * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* *
* Jansson is free software; you can redistribute it and/or modify * Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details. * it under the terms of the MIT license. See LICENSE for details.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org> * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* *
* Jansson is free software; you can redistribute it and/or modify * Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details. * it under the terms of the MIT license. See LICENSE for details.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org> * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* *
* Jansson is free software; you can redistribute it and/or modify * Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details. * it under the terms of the MIT license. See LICENSE for details.
@ -10,12 +10,20 @@
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <math.h>
#include <jansson.h> #include "jansson.h"
#include "hashtable.h" #include "hashtable.h"
#include "jansson_private.h" #include "jansson_private.h"
#include "utf.h" #include "utf.h"
/* Work around nonstandard isnan() and isinf() implementations */
#ifndef isnan
static JSON_INLINE int isnan(double x) { return x != x; }
#endif
#ifndef 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) static JSON_INLINE void json_init(json_t *json, json_type type)
{ {
@ -26,50 +34,6 @@ static JSON_INLINE void json_init(json_t *json, json_type type)
/*** object ***/ /*** object ***/
/* From http://www.cse.yorku.ca/~oz/hash.html */
size_t jsonp_hash_str(const void *ptr)
{
const char *str = (const char *)ptr;
size_t hash = 5381;
size_t c;
while((c = (size_t)*str))
{
hash = ((hash << 5) + hash) + c;
str++;
}
return hash;
}
int jsonp_str_equal(const void *ptr1, const void *ptr2)
{
return strcmp((const char *)ptr1, (const char *)ptr2) == 0;
}
/* This macro just returns a pointer that's a few bytes backwards from
string. This makes it possible to pass a pointer to object_key_t
when only the string inside it is used, without actually creating
an object_key_t instance. */
#define string_to_key(string) container_of(string, object_key_t, key)
static size_t hash_key(const void *ptr)
{
return jsonp_hash_str(((const object_key_t *)ptr)->key);
}
static int key_equal(const void *ptr1, const void *ptr2)
{
return jsonp_str_equal(((const object_key_t *)ptr1)->key,
((const object_key_t *)ptr2)->key);
}
static void value_decref(void *value)
{
json_decref((json_t *)value);
}
json_t *json_object(void) json_t *json_object(void)
{ {
json_object_t *object = jsonp_malloc(sizeof(json_object_t)); json_object_t *object = jsonp_malloc(sizeof(json_object_t));
@ -77,9 +41,7 @@ json_t *json_object(void)
return NULL; return NULL;
json_init(&object->json, JSON_OBJECT); json_init(&object->json, JSON_OBJECT);
if(hashtable_init(&object->hashtable, if(hashtable_init(&object->hashtable))
hash_key, key_equal,
jsonp_free, value_decref))
{ {
jsonp_free(object); jsonp_free(object);
return NULL; return NULL;
@ -116,38 +78,24 @@ json_t *json_object_get(const json_t *json, const char *key)
return NULL; return NULL;
object = json_to_object(json); object = json_to_object(json);
return hashtable_get(&object->hashtable, string_to_key(key)); return hashtable_get(&object->hashtable, key);
} }
int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value) int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value)
{ {
json_object_t *object; json_object_t *object;
object_key_t *k;
if(!key || !value) if(!value)
return -1; return -1;
if(!json_is_object(json) || json == value) if(!key || !json_is_object(json) || json == value)
{ {
json_decref(value); json_decref(value);
return -1; return -1;
} }
object = json_to_object(json); object = json_to_object(json);
/* offsetof(...) returns the size of object_key_t without the if(hashtable_set(&object->hashtable, key, object->serial++, value))
last, flexible member. This way, the correct amount is
allocated. */
k = jsonp_malloc(offsetof(object_key_t, key) + strlen(key) + 1);
if(!k)
{
json_decref(value);
return -1;
}
k->serial = object->serial++;
strcpy(k->key, key);
if(hashtable_set(&object->hashtable, k, value))
{ {
json_decref(value); json_decref(value);
return -1; return -1;
@ -175,7 +123,7 @@ int json_object_del(json_t *json, const char *key)
return -1; return -1;
object = json_to_object(json); object = json_to_object(json);
return hashtable_del(&object->hashtable, string_to_key(key)); return hashtable_del(&object->hashtable, key);
} }
int json_object_clear(json_t *json) int json_object_clear(json_t *json)
@ -186,30 +134,56 @@ int json_object_clear(json_t *json)
return -1; return -1;
object = json_to_object(json); object = json_to_object(json);
hashtable_clear(&object->hashtable); hashtable_clear(&object->hashtable);
object->serial = 0;
return 0; return 0;
} }
int json_object_update(json_t *object, json_t *other) int json_object_update(json_t *object, json_t *other)
{ {
void *iter; const char *key;
json_t *value;
if(!json_is_object(object) || !json_is_object(other)) if(!json_is_object(object) || !json_is_object(other))
return -1; return -1;
iter = json_object_iter(other); json_object_foreach(other, key, value) {
while(iter) {
const char *key;
json_t *value;
key = json_object_iter_key(iter);
value = json_object_iter_value(iter);
if(json_object_set_nocheck(object, key, value)) if(json_object_set_nocheck(object, key, value))
return -1; return -1;
}
iter = json_object_iter_next(other, iter); return 0;
}
int json_object_update_existing(json_t *object, json_t *other)
{
const char *key;
json_t *value;
if(!json_is_object(object) || !json_is_object(other))
return -1;
json_object_foreach(other, key, value) {
if(json_object_get(object, key))
json_object_set_nocheck(object, key, value);
}
return 0;
}
int json_object_update_missing(json_t *object, json_t *other)
{
const char *key;
json_t *value;
if(!json_is_object(object) || !json_is_object(other))
return -1;
json_object_foreach(other, key, value) {
if(!json_object_get(object, key))
json_object_set_nocheck(object, key, value);
} }
return 0; return 0;
@ -234,7 +208,7 @@ void *json_object_iter_at(json_t *json, const char *key)
return NULL; return NULL;
object = json_to_object(json); object = json_to_object(json);
return hashtable_iter_at(&object->hashtable, string_to_key(key)); return hashtable_iter_at(&object->hashtable, key);
} }
void *json_object_iter_next(json_t *json, void *iter) void *json_object_iter_next(json_t *json, void *iter)
@ -248,20 +222,12 @@ void *json_object_iter_next(json_t *json, void *iter)
return hashtable_iter_next(&object->hashtable, iter); return hashtable_iter_next(&object->hashtable, iter);
} }
const object_key_t *jsonp_object_iter_fullkey(void *iter)
{
if(!iter)
return NULL;
return hashtable_iter_key(iter);
}
const char *json_object_iter_key(void *iter) const char *json_object_iter_key(void *iter)
{ {
if(!iter) if(!iter)
return NULL; return NULL;
return jsonp_object_iter_fullkey(iter)->key; return hashtable_iter_key(iter);
} }
json_t *json_object_iter_value(void *iter) json_t *json_object_iter_value(void *iter)
@ -274,38 +240,34 @@ json_t *json_object_iter_value(void *iter)
int json_object_iter_set_new(json_t *json, void *iter, json_t *value) int json_object_iter_set_new(json_t *json, void *iter, json_t *value)
{ {
json_object_t *object;
if(!json_is_object(json) || !iter || !value) if(!json_is_object(json) || !iter || !value)
return -1; return -1;
object = json_to_object(json); hashtable_iter_set(iter, value);
hashtable_iter_set(&object->hashtable, iter, value);
return 0; return 0;
} }
void *json_object_key_to_iter(const char *key)
{
if(!key)
return NULL;
return hashtable_key_to_iter(key);
}
static int json_object_equal(json_t *object1, json_t *object2) static int json_object_equal(json_t *object1, json_t *object2)
{ {
void *iter; const char *key;
json_t *value1, *value2;
if(json_object_size(object1) != json_object_size(object2)) if(json_object_size(object1) != json_object_size(object2))
return 0; return 0;
iter = json_object_iter(object1); json_object_foreach(object1, key, value1) {
while(iter)
{
const char *key;
json_t *value1, *value2;
key = json_object_iter_key(iter);
value1 = json_object_iter_value(iter);
value2 = json_object_get(object2, key); value2 = json_object_get(object2, key);
if(!json_equal(value1, value2)) if(!json_equal(value1, value2))
return 0; return 0;
iter = json_object_iter_next(object1, iter);
} }
return 1; return 1;
@ -314,50 +276,34 @@ static int json_object_equal(json_t *object1, json_t *object2)
static json_t *json_object_copy(json_t *object) static json_t *json_object_copy(json_t *object)
{ {
json_t *result; json_t *result;
void *iter;
const char *key;
json_t *value;
result = json_object(); result = json_object();
if(!result) if(!result)
return NULL; return NULL;
iter = json_object_iter(object); json_object_foreach(object, key, value)
while(iter)
{
const char *key;
json_t *value;
key = json_object_iter_key(iter);
value = json_object_iter_value(iter);
json_object_set_nocheck(result, key, value); json_object_set_nocheck(result, key, value);
iter = json_object_iter_next(object, iter);
}
return result; return result;
} }
static json_t *json_object_deep_copy(json_t *object) static json_t *json_object_deep_copy(json_t *object)
{ {
json_t *result; json_t *result;
void *iter;
const char *key;
json_t *value;
result = json_object(); result = json_object();
if(!result) if(!result)
return NULL; return NULL;
iter = json_object_iter(object); json_object_foreach(object, key, value)
while(iter)
{
const char *key;
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)); json_object_set_new_nocheck(result, key, json_deep_copy(value));
iter = json_object_iter_next(object, iter);
}
return result; return result;
} }
@ -703,6 +649,9 @@ int json_string_set_nocheck(json_t *json, const char *value)
char *dup; char *dup;
json_string_t *string; json_string_t *string;
if(!json_is_string(json) || !value)
return -1;
dup = jsonp_strdup(value); dup = jsonp_strdup(value);
if(!dup) if(!dup)
return -1; return -1;
@ -790,7 +739,12 @@ static json_t *json_integer_copy(json_t *integer)
json_t *json_real(double value) json_t *json_real(double value)
{ {
json_real_t *real = jsonp_malloc(sizeof(json_real_t)); json_real_t *real;
if(isnan(value) || isinf(value))
return NULL;
real = jsonp_malloc(sizeof(json_real_t));
if(!real) if(!real)
return NULL; return NULL;
json_init(&real->json, JSON_REAL); json_init(&real->json, JSON_REAL);
@ -809,8 +763,8 @@ double json_real_value(const json_t *json)
int json_real_set(json_t *json, double value) int json_real_set(json_t *json, double value)
{ {
if(!json_is_real(json)) if(!json_is_real(json) || isnan(value) || isinf(value))
return 0; return -1;
json_to_real(json)->value = value; json_to_real(json)->value = value;
@ -838,7 +792,7 @@ static json_t *json_real_copy(json_t *real)
double json_number_value(const json_t *json) double json_number_value(const json_t *json)
{ {
if(json_is_integer(json)) if(json_is_integer(json))
return json_integer_value(json); return (double)json_integer_value(json);
else if(json_is_real(json)) else if(json_is_real(json))
return json_real_value(json); return json_real_value(json);
else else