Reorder client src directories

This commit is contained in:
Bjoern Kerler 2020-04-16 10:25:29 +02:00
commit 81bc0bc2b9
387 changed files with 73 additions and 106 deletions

View file

@ -0,0 +1,21 @@
MYSRCPATHS =
MYINCLUDES = -I.
MYCFLAGS = -std=c99 -D_ISOC99_SOURCE -Wno-unused-function
MYDEFS = -DHAVE_STDINT_H
MYSRCS = \
dump.c \
error.c \
hashtable.c \
hashtable_seed.c \
load.c \
memory.c \
pack_unpack.c \
strbuffer.c \
strconv.c \
utf.c \
path.c \
value.c
LIB_A = libjansson.a
include ../../../Makefile.host

472
client/deps/jansson/dump.c Normal file
View file

@ -0,0 +1,472 @@
/*
* Copyright (c) 2009-2016 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 "jansson_private.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "jansson.h"
#include "strbuffer.h"
#include "utf.h"
#define MAX_INTEGER_STR_LENGTH 100
#define MAX_REAL_STR_LENGTH 100
#define FLAGS_TO_INDENT(f) ((f) & 0x1F)
#define FLAGS_TO_PRECISION(f) (((f) >> 11) & 0x1F)
struct buffer {
const size_t size;
size_t used;
char *data;
};
static int dump_to_strbuffer(const char *buffer, size_t size, void *data) {
return strbuffer_append_bytes((strbuffer_t *)data, buffer, size);
}
static int dump_to_buffer(const char *buffer, size_t size, void *data) {
struct buffer *buf = (struct buffer *)data;
if (buf->used + size <= buf->size)
memcpy(&buf->data[buf->used], buffer, size);
buf->used += size;
return 0;
}
static int dump_to_file(const char *buffer, size_t size, void *data) {
FILE *dest = (FILE *)data;
if (fwrite(buffer, size, 1, dest) != 1)
return -1;
return 0;
}
static int dump_to_fd(const char *buffer, size_t size, void *data) {
#ifdef HAVE_UNISTD_H
int *dest = (int *)data;
if (write(*dest, buffer, size) == (ssize_t)size)
return 0;
#endif
return -1;
}
/* 32 spaces (the maximum indentation size) */
static const char whitespace[] = " ";
static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump, void *data) {
if (FLAGS_TO_INDENT(flags) > 0) {
unsigned int ws_count = FLAGS_TO_INDENT(flags), n_spaces = depth * ws_count;
if (dump("\n", 1, data))
return -1;
while (n_spaces > 0) {
int cur_n = n_spaces < sizeof whitespace - 1 ? n_spaces : sizeof whitespace - 1;
if (dump(whitespace, cur_n, data))
return -1;
n_spaces -= cur_n;
}
} else if (space && !(flags & JSON_COMPACT)) {
return dump(" ", 1, data);
}
return 0;
}
static int dump_string(const char *str, size_t len, json_dump_callback_t dump, void *data, size_t flags) {
const char *pos, *end, *lim;
int32_t codepoint = 0;
if (dump("\"", 1, data))
return -1;
end = pos = str;
lim = str + len;
while (1) {
const char *text;
char seq[13];
int length;
while (end < lim) {
end = utf8_iterate(pos, lim - pos, &codepoint);
if (!end)
return -1;
/* mandatory escape or control char */
if (codepoint == '\\' || codepoint == '"' || codepoint < 0x20)
break;
/* slash */
if ((flags & JSON_ESCAPE_SLASH) && codepoint == '/')
break;
/* non-ASCII */
if ((flags & JSON_ENSURE_ASCII) && codepoint > 0x7F)
break;
pos = end;
}
if (pos != str) {
if (dump(str, pos - str, data))
return -1;
}
if (end == pos)
break;
/* handle \, /, ", and control codes */
length = 2;
switch (codepoint) {
case '\\':
text = "\\\\";
break;
case '\"':
text = "\\\"";
break;
case '\b':
text = "\\b";
break;
case '\f':
text = "\\f";
break;
case '\n':
text = "\\n";
break;
case '\r':
text = "\\r";
break;
case '\t':
text = "\\t";
break;
case '/':
text = "\\/";
break;
default: {
/* codepoint is in BMP */
if (codepoint < 0x10000) {
snprintf(seq, sizeof(seq), "\\u%04X", (unsigned int)codepoint);
length = 6;
}
/* not in BMP -> construct a UTF-16 surrogate pair */
else {
int32_t first, last;
codepoint -= 0x10000;
first = 0xD800 | ((codepoint & 0xffc00) >> 10);
last = 0xDC00 | (codepoint & 0x003ff);
snprintf(seq, sizeof(seq), "\\u%04X\\u%04X", (unsigned int)first, (unsigned int)last);
length = 12;
}
text = seq;
break;
}
}
if (dump(text, length, data))
return -1;
str = pos = end;
}
return dump("\"", 1, data);
}
static int compare_keys(const void *key1, const void *key2) {
return strcmp(*(const char **)key1, *(const char **)key2);
}
static int loop_check(hashtable_t *parents, const json_t *json, char *key, size_t key_size) {
snprintf(key, key_size, "%p", json);
if (hashtable_get(parents, key))
return -1;
return hashtable_set(parents, key, json_null());
}
static int do_dump(const json_t *json, size_t flags, int depth,
hashtable_t *parents, json_dump_callback_t dump, void *data) {
int embed = flags & JSON_EMBED;
flags &= ~JSON_EMBED;
if (!json)
return -1;
switch (json_typeof(json)) {
case JSON_NULL:
return dump("null", 4, data);
case JSON_TRUE:
return dump("true", 4, data);
case JSON_FALSE:
return dump("false", 5, data);
case JSON_INTEGER: {
char buffer[MAX_INTEGER_STR_LENGTH];
int size;
size = snprintf(buffer, MAX_INTEGER_STR_LENGTH,
"%" JSON_INTEGER_FORMAT,
json_integer_value(json));
if (size < 0 || size >= MAX_INTEGER_STR_LENGTH)
return -1;
return dump(buffer, size, data);
}
case JSON_REAL: {
char buffer[MAX_REAL_STR_LENGTH];
int size;
double value = json_real_value(json);
size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value,
FLAGS_TO_PRECISION(flags));
if (size < 0)
return -1;
return dump(buffer, size, data);
}
case JSON_STRING:
return dump_string(json_string_value(json), json_string_length(json), dump, data, flags);
case JSON_ARRAY: {
size_t n;
size_t i;
/* Space for "0x", double the sizeof a pointer for the hex and a terminator. */
char key[2 + (sizeof(json) * 2) + 1];
/* detect circular references */
if (loop_check(parents, json, key, sizeof(key)))
return -1;
n = json_array_size(json);
if (!embed && dump("[", 1, data))
return -1;
if (n == 0) {
hashtable_del(parents, key);
return embed ? 0 : dump("]", 1, data);
}
if (dump_indent(flags, depth + 1, 0, dump, data))
return -1;
for (i = 0; i < n; ++i) {
if (do_dump(json_array_get(json, i), flags, depth + 1,
parents, dump, data))
return -1;
if (i < n - 1) {
if (dump(",", 1, data) ||
dump_indent(flags, depth + 1, 1, dump, data))
return -1;
} else {
if (dump_indent(flags, depth, 0, dump, data))
return -1;
}
}
hashtable_del(parents, key);
return embed ? 0 : dump("]", 1, data);
}
case JSON_OBJECT: {
void *iter;
const char *separator;
int separator_length;
/* Space for "0x", double the sizeof a pointer for the hex and a terminator. */
char loop_key[2 + (sizeof(json) * 2) + 1];
if (flags & JSON_COMPACT) {
separator = ":";
separator_length = 1;
} else {
separator = ": ";
separator_length = 2;
}
/* detect circular references */
if (loop_check(parents, json, loop_key, sizeof(loop_key)))
return -1;
iter = json_object_iter((json_t *)json);
if (!embed && dump("{", 1, data))
return -1;
if (!iter) {
hashtable_del(parents, loop_key);
return embed ? 0 : dump("}", 1, data);
}
if (dump_indent(flags, depth + 1, 0, dump, data))
return -1;
if (flags & JSON_SORT_KEYS) {
const char **keys;
size_t size, i;
size = json_object_size(json);
keys = jsonp_malloc(size * sizeof(const char *));
if (!keys)
return -1;
i = 0;
while (iter) {
keys[i] = json_object_iter_key(iter);
iter = json_object_iter_next((json_t *)json, iter);
i++;
}
assert(i == size);
qsort(keys, size, sizeof(const char *), compare_keys);
for (i = 0; i < size; i++) {
const char *key;
json_t *value;
key = keys[i];
value = json_object_get(json, key);
assert(value);
dump_string(key, strlen(key), dump, data, flags);
if (dump(separator, separator_length, data) ||
do_dump(value, flags, depth + 1, parents, dump, data)) {
jsonp_free(keys);
return -1;
}
if (i < size - 1) {
if (dump(",", 1, data) ||
dump_indent(flags, depth + 1, 1, dump, data)) {
jsonp_free(keys);
return -1;
}
} else {
if (dump_indent(flags, depth, 0, dump, data)) {
jsonp_free(keys);
return -1;
}
}
}
jsonp_free(keys);
} else {
/* Don't sort keys */
while (iter) {
void *next = json_object_iter_next((json_t *)json, iter);
const char *key = json_object_iter_key(iter);
dump_string(key, strlen(key), dump, data, flags);
if (dump(separator, separator_length, data) ||
do_dump(json_object_iter_value(iter), flags, depth + 1,
parents, dump, data))
return -1;
if (next) {
if (dump(",", 1, data) ||
dump_indent(flags, depth + 1, 1, dump, data))
return -1;
} else {
if (dump_indent(flags, depth, 0, dump, data))
return -1;
}
iter = next;
}
}
hashtable_del(parents, loop_key);
return embed ? 0 : dump("}", 1, data);
}
default:
/* not reached */
return -1;
}
}
char *json_dumps(const json_t *json, size_t flags) {
strbuffer_t strbuff;
char *result;
if (strbuffer_init(&strbuff))
return NULL;
if (json_dump_callback(json, dump_to_strbuffer, (void *)&strbuff, flags))
result = NULL;
else
result = jsonp_strdup(strbuffer_value(&strbuff));
strbuffer_close(&strbuff);
return result;
}
size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags) {
struct buffer buf = { size, 0, buffer };
if (json_dump_callback(json, dump_to_buffer, (void *)&buf, flags))
return 0;
return buf.used;
}
int json_dumpf(const json_t *json, FILE *output, size_t flags) {
return json_dump_callback(json, dump_to_file, (void *)output, flags);
}
int json_dumpfd(const json_t *json, int output, size_t flags) {
return json_dump_callback(json, dump_to_fd, (void *)&output, flags);
}
int json_dump_file(const json_t *json, const char *path, size_t flags) {
int result;
FILE *output = fopen(path, "w");
if (!output)
return -1;
result = json_dumpf(json, output, flags);
if (fclose(output) != 0)
return -1;
return result;
}
int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags) {
int res;
hashtable_t parents_set;
if (!(flags & JSON_ENCODE_ANY)) {
if (!json_is_array(json) && !json_is_object(json))
return -1;
}
if (hashtable_init(&parents_set))
return -1;
res = do_dump(json, flags, 0, &parents_set, callback, data);
hashtable_close(&parents_set);
return res;
}

View file

@ -0,0 +1,60 @@
#include <string.h>
#include "jansson_private.h"
void jsonp_error_init(json_error_t *error, const char *source) {
if (error) {
error->text[0] = '\0';
error->line = -1;
error->column = -1;
error->position = 0;
if (source)
jsonp_error_set_source(error, source);
else
error->source[0] = '\0';
}
}
void jsonp_error_set_source(json_error_t *error, const char *source) {
size_t length;
if (!error || !source)
return;
length = strlen(source);
if (length < JSON_ERROR_SOURCE_LENGTH) {
strncpy(error->source, source, JSON_ERROR_SOURCE_LENGTH - 1);
} else {
size_t extra = length - JSON_ERROR_SOURCE_LENGTH + 4;
memcpy(error->source, "...", 3);
strncpy(error->source + 3, source + extra, length - extra + 1);
}
}
void jsonp_error_set(json_error_t *error, int line, int column,
size_t position, enum json_error_code code,
const char *msg, ...) {
va_list ap;
va_start(ap, msg);
jsonp_error_vset(error, line, column, position, code, msg, ap);
va_end(ap);
}
void jsonp_error_vset(json_error_t *error, int line, int column,
size_t position, enum json_error_code code,
const char *msg, va_list ap) {
if (!error)
return;
if (error->text[0] != '\0') {
/* error already set */
return;
}
error->line = line;
error->column = column;
error->position = (int)position;
vsnprintf(error->text, JSON_ERROR_TEXT_LENGTH - 1, msg, ap);
error->text[JSON_ERROR_TEXT_LENGTH - 2] = '\0';
error->text[JSON_ERROR_TEXT_LENGTH - 1] = code;
}

View file

@ -0,0 +1,324 @@
/*
* Copyright (c) 2009-2016 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"
#ifndef INITIAL_HASHTABLE_ORDER
#define INITIAL_HASHTABLE_ORDER 3
#endif
typedef struct hashtable_list list_t;
typedef struct hashtable_pair pair_t;
typedef struct hashtable_bucket bucket_t;
extern volatile uint32_t hashtable_seed;
/* Implementation of the hash function */
#include "lookup3.h"
#define list_to_pair(list_) container_of(list_, pair_t, list)
#define ordered_list_to_pair(list_) container_of(list_, pair_t, ordered_list)
#define hash_str(key) ((size_t)hashlittle((key), strlen(key), hashtable_seed))
static JSON_INLINE void list_init(list_t *list) {
list->next = list;
list->prev = list;
}
static JSON_INLINE void list_insert(list_t *list, list_t *node) {
node->next = list;
node->prev = list->prev;
list->prev->next = node;
list->prev = node;
}
static JSON_INLINE void list_remove(list_t *list) {
list->prev->next = list->next;
list->next->prev = list->prev;
}
static JSON_INLINE int bucket_is_empty(hashtable_t *hashtable, bucket_t *bucket) {
return bucket->first == &hashtable->list && bucket->first == bucket->last;
}
static void insert_to_bucket(hashtable_t *hashtable, bucket_t *bucket,
list_t *list) {
if (bucket_is_empty(hashtable, bucket)) {
list_insert(&hashtable->list, list);
bucket->first = bucket->last = list;
} else {
list_insert(bucket->first, list);
bucket->first = list;
}
}
static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
const char *key, size_t hash) {
list_t *list;
pair_t *pair;
if (bucket_is_empty(hashtable, bucket))
return NULL;
list = bucket->first;
while (1) {
pair = list_to_pair(list);
if (pair->hash == hash && strcmp(pair->key, key) == 0)
return pair;
if (list == bucket->last)
break;
list = list->next;
}
return NULL;
}
/* returns 0 on success, -1 if key was not found */
static int hashtable_do_del(hashtable_t *hashtable,
const char *key, size_t hash) {
pair_t *pair;
bucket_t *bucket;
size_t index;
index = hash & hashmask(hashtable->order);
bucket = &hashtable->buckets[index];
pair = hashtable_find_pair(hashtable, bucket, key, hash);
if (!pair)
return -1;
if (&pair->list == bucket->first && &pair->list == bucket->last)
bucket->first = bucket->last = &hashtable->list;
else if (&pair->list == bucket->first)
bucket->first = pair->list.next;
else if (&pair->list == bucket->last)
bucket->last = pair->list.prev;
list_remove(&pair->list);
list_remove(&pair->ordered_list);
json_decref(pair->value);
jsonp_free(pair);
hashtable->size--;
return 0;
}
static void hashtable_do_clear(hashtable_t *hashtable) {
list_t *list, *next;
pair_t *pair;
for (list = hashtable->list.next; list != &hashtable->list; list = next) {
next = list->next;
pair = list_to_pair(list);
json_decref(pair->value);
jsonp_free(pair);
}
}
static int hashtable_do_rehash(hashtable_t *hashtable) {
list_t *list, *next;
pair_t *pair;
size_t i, index, new_size, new_order;
struct hashtable_bucket *new_buckets;
new_order = hashtable->order + 1;
new_size = hashsize(new_order);
new_buckets = jsonp_malloc(new_size * sizeof(bucket_t));
if (!new_buckets)
return -1;
jsonp_free(hashtable->buckets);
hashtable->buckets = new_buckets;
hashtable->order = new_order;
for (i = 0; i < hashsize(hashtable->order); i++) {
hashtable->buckets[i].first = hashtable->buckets[i].last =
&hashtable->list;
}
list = hashtable->list.next;
list_init(&hashtable->list);
for (; list != &hashtable->list; list = next) {
next = list->next;
pair = list_to_pair(list);
index = pair->hash % new_size;
insert_to_bucket(hashtable, &hashtable->buckets[index], &pair->list);
}
return 0;
}
int hashtable_init(hashtable_t *hashtable) {
size_t i;
hashtable->size = 0;
hashtable->order = INITIAL_HASHTABLE_ORDER;
hashtable->buckets = jsonp_malloc(hashsize(hashtable->order) * sizeof(bucket_t));
if (!hashtable->buckets)
return -1;
list_init(&hashtable->list);
list_init(&hashtable->ordered_list);
for (i = 0; i < hashsize(hashtable->order); i++) {
hashtable->buckets[i].first = hashtable->buckets[i].last =
&hashtable->list;
}
return 0;
}
void hashtable_close(hashtable_t *hashtable) {
hashtable_do_clear(hashtable);
jsonp_free(hashtable->buckets);
}
int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value) {
pair_t *pair;
bucket_t *bucket;
size_t hash, index;
/* rehash if the load ratio exceeds 1 */
if (hashtable->size >= hashsize(hashtable->order))
if (hashtable_do_rehash(hashtable))
return -1;
hash = hash_str(key);
index = hash & hashmask(hashtable->order);
bucket = &hashtable->buckets[index];
pair = hashtable_find_pair(hashtable, bucket, key, hash);
if (pair) {
json_decref(pair->value);
pair->value = value;
} else {
/* offsetof(...) returns the size of pair_t without the last,
flexible member. This way, the correct amount is
allocated. */
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;
pair->hash = hash;
strncpy(pair->key, key, len + 1);
pair->value = value;
list_init(&pair->list);
list_init(&pair->ordered_list);
insert_to_bucket(hashtable, bucket, &pair->list);
list_insert(&hashtable->ordered_list, &pair->ordered_list);
hashtable->size++;
}
return 0;
}
void *hashtable_get(hashtable_t *hashtable, const char *key) {
pair_t *pair;
size_t hash;
bucket_t *bucket;
hash = hash_str(key);
bucket = &hashtable->buckets[hash & hashmask(hashtable->order)];
pair = hashtable_find_pair(hashtable, bucket, key, hash);
if (!pair)
return NULL;
return pair->value;
}
int hashtable_del(hashtable_t *hashtable, const char *key) {
size_t hash = hash_str(key);
return hashtable_do_del(hashtable, key, hash);
}
void hashtable_clear(hashtable_t *hashtable) {
size_t i;
hashtable_do_clear(hashtable);
for (i = 0; i < hashsize(hashtable->order); i++) {
hashtable->buckets[i].first = hashtable->buckets[i].last =
&hashtable->list;
}
list_init(&hashtable->list);
list_init(&hashtable->ordered_list);
hashtable->size = 0;
}
void *hashtable_iter(hashtable_t *hashtable) {
return hashtable_iter_next(hashtable, &hashtable->ordered_list);
}
void *hashtable_iter_at(hashtable_t *hashtable, const char *key) {
pair_t *pair;
size_t hash;
bucket_t *bucket;
hash = hash_str(key);
bucket = &hashtable->buckets[hash & hashmask(hashtable->order)];
pair = hashtable_find_pair(hashtable, bucket, key, hash);
if (!pair)
return NULL;
return &pair->ordered_list;
}
void *hashtable_iter_next(hashtable_t *hashtable, void *iter) {
list_t *list = (list_t *)iter;
if (list->next == &hashtable->ordered_list)
return NULL;
return list->next;
}
void *hashtable_iter_key(void *iter) {
pair_t *pair = ordered_list_to_pair((list_t *)iter);
return pair->key;
}
void *hashtable_iter_value(void *iter) {
pair_t *pair = ordered_list_to_pair((list_t *)iter);
return pair->value;
}
void hashtable_iter_set(void *iter, json_t *value) {
pair_t *pair = ordered_list_to_pair((list_t *)iter);
json_decref(pair->value);
pair->value = value;
}

View file

@ -0,0 +1,176 @@
/*
* Copyright (c) 2009-2016 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.
*/
#ifndef HASHTABLE_H
#define HASHTABLE_H
#include <stdlib.h>
#include "jansson.h"
struct hashtable_list {
struct hashtable_list *prev;
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_list list;
struct hashtable_list ordered_list;
size_t hash;
json_t *value;
char key[1];
};
struct hashtable_bucket {
struct hashtable_list *first;
struct hashtable_list *last;
};
typedef struct hashtable {
size_t size;
struct hashtable_bucket *buckets;
size_t order; /* hashtable has pow(2, order) buckets */
struct hashtable_list list;
struct hashtable_list ordered_list;
} hashtable_t;
#define hashtable_key_to_iter(key_) \
(&(container_of(key_, struct hashtable_pair, key)->ordered_list))
/**
* hashtable_init - Initialize a hashtable object
*
* @hashtable: The (statically allocated) hashtable object
*
* Initializes a statically allocated hashtable object. The object
* should be cleared with hashtable_close when it's no longer used.
*
* Returns 0 on success, -1 on error (out of memory).
*/
int hashtable_init(hashtable_t *hashtable) JANSSON_ATTRS(warn_unused_result);
/**
* hashtable_close - Release all resources used by a hashtable object
*
* @hashtable: The hashtable
*
* Destroys a statically allocated hashtable object.
*/
void hashtable_close(hashtable_t *hashtable);
/**
* hashtable_set - Add/modify value in hashtable
*
* @hashtable: The hashtable object
* @key: The key
* @serial: For addition order of keys
* @value: The value
*
* If a value with the given key already exists, its value is replaced
* with the new value. Value is "stealed" in the sense that hashtable
* doesn't increment its refcount but decreases the refcount when the
* value is no longer needed.
*
* Returns 0 on success, -1 on failure (out of memory).
*/
int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value);
/**
* hashtable_get - Get a value associated with a key
*
* @hashtable: The hashtable object
* @key: The key
*
* Returns value if it is found, or NULL otherwise.
*/
void *hashtable_get(hashtable_t *hashtable, const char *key);
/**
* hashtable_del - Remove a value from the hashtable
*
* @hashtable: The hashtable object
* @key: The key
*
* Returns 0 on success, or -1 if the key was not found.
*/
int hashtable_del(hashtable_t *hashtable, const char *key);
/**
* hashtable_clear - Clear hashtable
*
* @hashtable: The hashtable object
*
* Removes all items from the hashtable.
*/
void hashtable_clear(hashtable_t *hashtable);
/**
* hashtable_iter - Iterate over hashtable
*
* @hashtable: The hashtable object
*
* Returns an opaque iterator to the first element in the hashtable.
* The iterator should be passed to hashtable_iter_* functions.
* The hashtable items are not iterated over in any particular order.
*
* There's no need to free the iterator in any way. The iterator is
* valid as long as the item that is referenced by the iterator is not
* deleted. Other values may be added or deleted. In particular,
* hashtable_iter_next() may be called on an iterator, and after that
* the key/value pair pointed by the old iterator may be deleted.
*/
void *hashtable_iter(hashtable_t *hashtable);
/**
* hashtable_iter_at - Return an iterator at a specific key
*
* @hashtable: The hashtable object
* @key: The key that the iterator should point to
*
* Like hashtable_iter() but returns an iterator pointing to a
* specific key.
*/
void *hashtable_iter_at(hashtable_t *hashtable, const char *key);
/**
* hashtable_iter_next - Advance an iterator
*
* @hashtable: The hashtable object
* @iter: The iterator
*
* Returns a new iterator pointing to the next element in the
* hashtable or NULL if the whole hastable has been iterated over.
*/
void *hashtable_iter_next(hashtable_t *hashtable, void *iter);
/**
* hashtable_iter_key - Retrieve the key pointed by an iterator
*
* @iter: The iterator
*/
void *hashtable_iter_key(void *iter);
/**
* hashtable_iter_value - Retrieve the value pointed by an iterator
*
* @iter: The iterator
*/
void *hashtable_iter_value(void *iter);
/**
* hashtable_iter_set - Set the value pointed by an iterator
*
* @iter: The iterator
* @value: The value to set
*/
void hashtable_iter_set(void *iter, json_t *value);
#endif

View file

@ -0,0 +1,276 @@
/* 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 = 0;
int done = 0;
#if !defined(_WIN32) && defined(USE_URANDOM)
if (seed_from_urandom(&seed) == 0)
done = 1;
#endif
#if defined(_WIN32) && defined(USE_WINDOWS_CRYPTOAPI)
if (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

View file

@ -0,0 +1,75 @@
EXPORTS
json_delete
json_true
json_false
json_null
json_sprintf
json_vsprintf
json_string
json_stringn
json_string_nocheck
json_stringn_nocheck
json_string_value
json_string_length
json_string_set
json_string_setn
json_string_set_nocheck
json_string_setn_nocheck
json_integer
json_integer_value
json_integer_set
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_object_seed
json_dumps
json_dumpb
json_dumpf
json_dumpfd
json_dump_file
json_dump_callback
json_loads
json_loadb
json_loadf
json_loadfd
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
json_get_alloc_funcs

View file

@ -0,0 +1,365 @@
/*
* Copyright (c) 2009-2016 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 JANSSON_H
#define JANSSON_H
#include <stdio.h>
#include <stdlib.h> /* for size_t */
#include <stdarg.h>
#include "jansson_config.h"
#ifdef __cplusplus
extern "C" {
#endif
/* version */
#define JANSSON_MAJOR_VERSION 2
#define JANSSON_MINOR_VERSION 12
#define JANSSON_MICRO_VERSION 0
/* Micro version is omitted if it's 0 */
#define JANSSON_VERSION "2.12"
/* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this
for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */
#define JANSSON_VERSION_HEX ((JANSSON_MAJOR_VERSION << 16) | \
(JANSSON_MINOR_VERSION << 8) | \
(JANSSON_MICRO_VERSION << 0))
/* If __atomic or __sync builtins are available the library is thread
* safe for all read-only functions plus reference counting. */
#if JSON_HAVE_ATOMIC_BUILTINS || JSON_HAVE_SYNC_BUILTINS
#define JANSSON_THREAD_SAFE_REFCOUNT 1
#endif
#if defined(__GNUC__) || defined(__clang__)
#define JANSSON_ATTRS(...) __attribute__((__VA_ARGS__))
#else
#define JANSSON_ATTRS(...)
#endif
/* types */
typedef enum {
JSON_OBJECT,
JSON_ARRAY,
JSON_STRING,
JSON_INTEGER,
JSON_REAL,
JSON_TRUE,
JSON_FALSE,
JSON_NULL
} json_type;
typedef struct json_t {
json_type type;
volatile 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"
#else
#define JSON_INTEGER_FORMAT "lld"
#endif
typedef long long json_int_t;
#else
#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_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_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)
/* 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);
json_t *json_false(void);
#define json_boolean(val) ((val) ? json_true() : json_false())
json_t *json_null(void);
/* do not call JSON_INTERNAL_INCREF or JSON_INTERNAL_DECREF directly */
#if JSON_HAVE_ATOMIC_BUILTINS
#define JSON_INTERNAL_INCREF(json) __atomic_add_fetch(&json->refcount, 1, __ATOMIC_ACQUIRE)
#define JSON_INTERNAL_DECREF(json) __atomic_sub_fetch(&json->refcount, 1, __ATOMIC_RELEASE)
#elif JSON_HAVE_SYNC_BUILTINS
#define JSON_INTERNAL_INCREF(json) __sync_add_and_fetch(&json->refcount, 1)
#define JSON_INTERNAL_DECREF(json) __sync_sub_and_fetch(&json->refcount, 1)
#else
#define JSON_INTERNAL_INCREF(json) (++json->refcount)
#define JSON_INTERNAL_DECREF(json) (--json->refcount)
#endif
static JSON_INLINE
json_t *json_incref(json_t *json) {
if (json && json->refcount != (size_t) - 1)
JSON_INTERNAL_INCREF(json);
return json;
}
/* do not call json_delete directly */
void json_delete(json_t *json);
static JSON_INLINE
void json_decref(json_t *json) {
if (json && json->refcount != (size_t) - 1 && JSON_INTERNAL_DECREF(json) == 0)
json_delete(json);
}
#if defined(__GNUC__) || defined(__clang__)
static JSON_INLINE
void json_decrefp(json_t **json) {
if (json) {
json_decref(*json);
*json = NULL;
}
}
#define json_auto_t json_t __attribute__((cleanup(json_decrefp)))
#endif
/* error reporting */
#define JSON_ERROR_TEXT_LENGTH 160
#define JSON_ERROR_SOURCE_LENGTH 80
typedef struct json_error_t {
int line;
int column;
int position;
char source[JSON_ERROR_SOURCE_LENGTH];
char text[JSON_ERROR_TEXT_LENGTH];
} json_error_t;
enum json_error_code {
json_error_unknown,
json_error_out_of_memory,
json_error_stack_overflow,
json_error_cannot_open_file,
json_error_invalid_argument,
json_error_invalid_utf8,
json_error_premature_end_of_input,
json_error_end_of_input_expected,
json_error_invalid_syntax,
json_error_invalid_format,
json_error_wrong_type,
json_error_null_character,
json_error_null_value,
json_error_null_byte_in_key,
json_error_duplicate_key,
json_error_numeric_overflow,
json_error_item_not_found,
json_error_index_out_of_range
};
static JSON_INLINE enum json_error_code json_error_code(const json_error_t *e) {
return (enum json_error_code)e->text[JSON_ERROR_TEXT_LENGTH - 1];
}
/* getters, setters, manipulation */
void json_object_seed(size_t seed);
size_t json_object_size(const json_t *json);
json_t *json_object_get(const json_t *json, const char *key) JANSSON_ATTRS(warn_unused_result);
int json_object_set_new(json_t *json, const char *key, json_t *value);
int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value);
int json_object_del(json_t *json, const char *key);
int json_object_clear(json_t *json);
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 *json);
void *json_object_iter_at(json_t *json, const char *key);
void *json_object_key_to_iter(const char *key);
void *json_object_iter_next(json_t *json, void *iter);
const char *json_object_iter_key(void *iter);
json_t *json_object_iter_value(void *iter);
int json_object_iter_set_new(json_t *json, 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))))
#define json_object_foreach_safe(object, n, key, value) \
for(key = json_object_iter_key(json_object_iter(object)), \
n = json_object_iter_next(object, json_object_key_to_iter(key)); \
key && (value = json_object_iter_value(json_object_key_to_iter(key))); \
key = json_object_iter_key(n), \
n = 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) {
return json_object_set_new(object, key, json_incref(value));
}
static JSON_INLINE
int json_object_set_nocheck(json_t *object, const char *key, json_t *value) {
return json_object_set_new_nocheck(object, key, json_incref(value));
}
static JSON_INLINE
int json_object_iter_set(json_t *object, void *iter, json_t *value) {
return json_object_iter_set_new(object, iter, json_incref(value));
}
size_t json_array_size(const json_t *json);
json_t *json_array_get(const json_t *json, size_t index) JANSSON_ATTRS(warn_unused_result);
int json_array_set_new(json_t *json, size_t index, json_t *value);
int json_array_append_new(json_t *json, json_t *value);
int json_array_insert_new(json_t *json, size_t index, json_t *value);
int json_array_remove(json_t *json, size_t index);
int json_array_clear(json_t *json);
int json_array_extend(json_t *json, json_t *other_json);
static JSON_INLINE
int json_array_set(json_t *array, size_t ind, json_t *value) {
return json_array_set_new(array, ind, json_incref(value));
}
static JSON_INLINE
int json_array_append(json_t *array, json_t *value) {
return json_array_append_new(array, json_incref(value));
}
static JSON_INLINE
int json_array_insert(json_t *array, size_t ind, json_t *value) {
return json_array_insert_new(array, ind, json_incref(value));
}
const char *json_string_value(const json_t *json);
size_t json_string_length(const json_t *json);
json_int_t json_integer_value(const json_t *json);
double json_real_value(const json_t *json);
double json_number_value(const json_t *json);
int json_string_set(json_t *json, const char *value);
int json_string_setn(json_t *json, const char *value, size_t len);
int json_string_set_nocheck(json_t *json, const char *value);
int json_string_setn_nocheck(json_t *json, const char *value, size_t len);
int json_integer_set(json_t *json, json_int_t value);
int json_real_set(json_t *json, double value);
/* pack, unpack */
json_t *json_pack(const char *fmt, ...) JANSSON_ATTRS(warn_unused_result);
json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...) JANSSON_ATTRS(warn_unused_result);
json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap) JANSSON_ATTRS(warn_unused_result);
#define JSON_VALIDATE_ONLY 0x1
#define JSON_STRICT 0x2
int json_unpack(json_t *root, const char *fmt, ...);
int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...);
int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, va_list ap);
/* sprintf */
json_t *json_sprintf(const char *fmt, ...) JANSSON_ATTRS(warn_unused_result, format(printf, 1, 2));
json_t *json_vsprintf(const char *fmt, va_list ap) JANSSON_ATTRS(warn_unused_result, format(printf, 1, 0));
/* equality */
int json_equal(const json_t *json1, const json_t *json2);
/* copying */
json_t *json_copy(json_t *json) JANSSON_ATTRS(warn_unused_result);
json_t *json_deep_copy(const json_t *json) JANSSON_ATTRS(warn_unused_result);
json_t *json_path_get(const json_t *json, const char *path);
int json_path_set_new(json_t *json, const char *path, json_t *value, size_t flags, json_error_t *error);
static JSON_INLINE
int json_path_set(json_t *json, const char *path, json_t *value, size_t flags, json_error_t *error) {
return json_path_set_new(json, path, json_incref(value), flags, error);
}
/* decoding */
#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);
json_t *json_loads(const char *string, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result);
json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result);
json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result);
json_t *json_loadfd(int input, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result);
json_t *json_load_file(const char *path, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result);
json_t *json_load_callback(json_load_callback_t callback, void *arg, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result);
/* encoding */
#define JSON_MAX_INDENT 0x1F
#define JSON_INDENT(n) ((n) & JSON_MAX_INDENT)
#define JSON_COMPACT 0x20
#define JSON_ENSURE_ASCII 0x40
#define JSON_SORT_KEYS 0x80
#define JSON_PRESERVE_ORDER 0x100
#define JSON_ENCODE_ANY 0x200
#define JSON_ESCAPE_SLASH 0x400
#define JSON_REAL_PRECISION(n) (((n) & 0x1F) << 11)
#define JSON_EMBED 0x10000
typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data);
char *json_dumps(const json_t *json, size_t flags) JANSSON_ATTRS(warn_unused_result);
size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags);
int json_dumpf(const json_t *json, FILE *output, size_t flags);
int json_dumpfd(const json_t *json, int output, 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 */
typedef void *(*json_malloc_t)(size_t);
typedef void (*json_free_t)(void *);
void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn);
void json_get_alloc_funcs(json_malloc_t *malloc_fn, json_free_t *free_fn);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2010-2016 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.
*
*
* This file specifies a part of the site-specific configuration for
* 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.
*/
#ifndef JANSSON_CONFIG_H
#define JANSSON_CONFIG_H
/* If your compiler supports the inline keyword in C, JSON_INLINE is
defined to `inline', otherwise empty. In C++, the inline is always
supported. */
#ifdef __cplusplus
#define JSON_INLINE inline
#else
#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_HAVE_LOCALECONV 1
/* If __atomic builtins are available they will be used to manage
reference counts of json_t. */
#define JSON_HAVE_ATOMIC_BUILTINS 1
/* If __atomic builtins are not available we try using __sync builtins
to manage reference counts of json_t. */
#define JSON_HAVE_SYNC_BUILTINS 1
/* Maximum recursion depth for parsing JSON input.
This limits the depth of e.g. array-within-array constructions. */
#define JSON_PARSER_MAX_DEPTH 2048
#endif

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2010-2016 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.
*
*
* This file specifies a part of the site-specific configuration for
* 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.
*/
#ifndef JANSSON_CONFIG_H
#define JANSSON_CONFIG_H
/* If your compiler supports the inline keyword in C, JSON_INLINE is
defined to `inline', otherwise empty. In C++, the inline is always
supported. */
#ifdef __cplusplus
#define JSON_INLINE inline
#else
#define JSON_INLINE @json_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 @json_have_long_long@
/* If locale.h and localeconv() are available, define to 1,
otherwise to 0. */
#define JSON_HAVE_LOCALECONV @json_have_localeconv@
/* If __atomic builtins are available they will be used to manage
reference counts of json_t. */
#define JSON_HAVE_ATOMIC_BUILTINS @json_have_atomic_builtins@
/* If __atomic builtins are not available we try using __sync builtins
to manage reference counts of json_t. */
#define JSON_HAVE_SYNC_BUILTINS @json_have_sync_builtins@
/* Maximum recursion depth for parsing JSON input.
This limits the depth of e.g. array-within-array constructions. */
#define JSON_PARSER_MAX_DEPTH 2048
#endif

View file

@ -0,0 +1,111 @@
/*
* Copyright (c) 2009-2016 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 JANSSON_PRIVATE_H
#define JANSSON_PRIVATE_H
#ifdef HAVE_CONFIG_H
#include <jansson_private_config.h>
#endif
#include <stddef.h>
#include "jansson.h"
#include "hashtable.h"
#include "strbuffer.h"
#define container_of(ptr_, type_, member_) \
((type_ *)((char *)ptr_ - offsetof(type_, member_)))
/* On some platforms, max() may already be defined */
#ifndef max
#define max(a, b) ((a) > (b) ? (a) : (b))
#endif
/* va_copy is a C99 feature. In C89 implementations, it's sometimes
available as __va_copy. If not, memcpy() should do the trick. */
#ifndef va_copy
#ifdef __va_copy
#define va_copy __va_copy
#else
#define va_copy(a, b) memcpy(&(a), &(b), sizeof(va_list))
#endif
#endif
typedef struct {
json_t json;
hashtable_t hashtable;
} json_object_t;
typedef struct {
json_t json;
size_t size;
size_t entries;
json_t **table;
} json_array_t;
typedef struct {
json_t json;
char *value;
size_t length;
} json_string_t;
typedef struct {
json_t json;
double value;
} json_real_t;
typedef struct {
json_t json;
json_int_t value;
} json_integer_t;
#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_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,
size_t position, enum json_error_code code,
const char *msg, ...);
void jsonp_error_vset(json_error_t *error, int line, int column,
size_t position, enum json_error_code code,
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, int precision);
/* Wrappers for custom memory functions */
void *jsonp_malloc(size_t size) JANSSON_ATTRS(warn_unused_result);
void jsonp_free(void *ptr);
char *jsonp_strdup(const char *str) JANSSON_ATTRS(warn_unused_result);
char *jsonp_strndup(const char *str, size_t len) JANSSON_ATTRS(warn_unused_result);
/* Windows compatibility */
#if defined(_WIN32) || defined(WIN32)
# if defined(_MSC_VER) /* MS compiller */
# if (_MSC_VER < 1900) && !defined(snprintf) /* snprintf not defined yet & not introduced */
# define snprintf _snprintf
# endif
# if (_MSC_VER < 1500) && !defined(vsnprintf) /* vsnprintf not defined yet & not introduced */
# define vsnprintf(b,c,f,a) _vsnprintf(b,c,f,a)
# endif
# else /* Other Windows compiller, old definition */
# define snprintf _snprintf
# define vsnprintf _vsnprintf
# endif
#endif
#endif

1115
client/deps/jansson/load.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,460 @@
/*
-------------------------------------------------------------------------------
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.
-------------------------------------------------------------------------------
*/
#ifndef LOOKUP3_H
#define LOOKUP3_H
#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 */
/* Detect Valgrind or AddressSanitizer */
#ifdef VALGRIND
# define NO_MASKING_TRICK 1
#else
# if defined(__has_feature) /* Clang */
# if __has_feature(address_sanitizer) /* is ASAN enabled? */
# define NO_MASKING_TRICK 1
# endif
# else
# if defined(__SANITIZE_ADDRESS__) /* GCC 4.8.x, is ASAN enabled? */
# define NO_MASKING_TRICK 1
# endif
# endif
#endif
#ifdef NO_MASKING_TRICK
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 NO_MASKING_TRICK
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; /* fall through */
case 11:
c += ((uint32_t)k[10]) << 16; /* fall through */
case 10:
c += ((uint32_t)k[9]) << 8; /* fall through */
case 9 :
c += k[8]; /* fall through */
case 8 :
b += ((uint32_t)k[7]) << 24; /* fall through */
case 7 :
b += ((uint32_t)k[6]) << 16; /* fall through */
case 6 :
b += ((uint32_t)k[5]) << 8; /* fall through */
case 5 :
b += k[4]; /* fall through */
case 4 :
a += ((uint32_t)k[3]) << 24; /* fall through */
case 3 :
a += ((uint32_t)k[2]) << 16; /* fall through */
case 2 :
a += ((uint32_t)k[1]) << 8; /* fall through */
case 1 :
a += k[0];
break;
case 0 :
return c;
}
}
final(a, b, c);
return c;
}
#endif

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2009-2016 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
* under the terms of the MIT license. See LICENSE for details.
*/
#include <stdlib.h>
#include <string.h>
#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;
void *jsonp_malloc(size_t size) {
if (!size)
return NULL;
return (*do_malloc)(size);
}
void jsonp_free(void *ptr) {
if (!ptr)
return;
(*do_free)(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(len + 1);
if (!new_str)
return NULL;
memcpy(new_str, str, len);
new_str[len] = '\0';
return new_str;
}
void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn) {
do_malloc = malloc_fn;
do_free = free_fn;
}
void json_get_alloc_funcs(json_malloc_t *malloc_fn, json_free_t *free_fn) {
if (malloc_fn)
*malloc_fn = do_malloc;
if (free_fn)
*free_fn = do_free;
}

View file

@ -0,0 +1,929 @@
/*
* Copyright (c) 2009-2016 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 {
int line;
int column;
size_t pos;
char token;
} token_t;
typedef struct {
const char *start;
const char *fmt;
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;
int has_error;
} scanner_t;
#define token(scanner) ((scanner)->token.token)
static const char *const 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;
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;
s->has_error = 0;
}
static void next_token(scanner_t *s) {
const char *t;
s->prev_token = s->token;
if (s->next_token.line) {
s->token = s->next_token;
s->next_token.line = 0;
return;
}
if (!token(s) && !*s->fmt)
return;
t = s->fmt;
s->column++;
s->pos++;
/* skip space and ignored chars */
while (*t == ' ' || *t == '\t' || *t == '\n' || *t == ',' || *t == ':') {
if (*t == '\n') {
s->line++;
s->column = 1;
} else
s->column++;
s->pos++;
t++;
}
s->token.token = *t;
s->token.line = s->line;
s->token.column = s->column;
s->token.pos = s->pos;
if (*t) 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, enum json_error_code code,
const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
jsonp_error_vset(s->error, s->token.line, s->token.column, s->token.pos,
code, fmt, ap);
jsonp_error_set_source(s->error, source);
va_end(ap);
}
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, int optional) {
char t;
strbuffer_t strbuff;
const char *str;
size_t length;
next_token(s);
t = token(s);
prev_token(s);
*ours = 0;
if (t != '#' && t != '%' && t != '+') {
/* Optimize the simple case */
str = va_arg(*ap, const char *);
if (!str) {
if (!optional) {
set_error(s, "<args>", json_error_null_value, "NULL %s", purpose);
s->has_error = 1;
}
return NULL;
}
length = strlen(str);
if (!utf8_check_string(str, length)) {
set_error(s, "<args>", json_error_invalid_utf8, "Invalid UTF-8 %s", purpose);
s->has_error = 1;
return NULL;
}
*out_len = length;
return (char *)str;
} else if (optional) {
set_error(s, "<format>", json_error_invalid_format, "Cannot use '%c' on optional strings", t);
s->has_error = 1;
return NULL;
}
if (strbuffer_init(&strbuff)) {
set_error(s, "<internal>", json_error_out_of_memory, "Out of memory");
s->has_error = 1;
}
while (1) {
str = va_arg(*ap, const char *);
if (!str) {
set_error(s, "<args>", json_error_null_value, "NULL %s", purpose);
s->has_error = 1;
}
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 = s->has_error ? 0 : strlen(str);
}
if (!s->has_error && strbuffer_append_bytes(&strbuff, str, length) == -1) {
set_error(s, "<internal>", json_error_out_of_memory, "Out of memory");
s->has_error = 1;
}
next_token(s);
if (token(s) != '+') {
prev_token(s);
break;
}
}
if (s->has_error) {
strbuffer_close(&strbuff);
return NULL;
}
if (!utf8_check_string(strbuff.value, strbuff.length)) {
set_error(s, "<args>", json_error_invalid_utf8, "Invalid UTF-8 %s", purpose);
strbuffer_close(&strbuff);
s->has_error = 1;
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 (token(s) != '}') {
char *key;
size_t len;
int ours;
json_t *value;
char valueOptional;
if (!token(s)) {
set_error(s, "<format>", json_error_invalid_format, "Unexpected end of format string");
goto error;
}
if (token(s) != 's') {
set_error(s, "<format>", json_error_invalid_format, "Expected format 's', got '%c'", token(s));
goto error;
}
key = read_string(s, ap, "object key", &len, &ours, 0);
next_token(s);
next_token(s);
valueOptional = token(s);
prev_token(s);
value = pack(s, ap);
if (!value) {
if (ours)
jsonp_free(key);
if (valueOptional != '*') {
set_error(s, "<args>", json_error_null_value, "NULL object value");
s->has_error = 1;
}
next_token(s);
continue;
}
if (s->has_error)
json_decref(value);
if (!s->has_error && json_object_set_new_nocheck(object, key, value)) {
set_error(s, "<internal>", json_error_out_of_memory, "Unable to add key \"%s\"", key);
s->has_error = 1;
}
if (ours)
jsonp_free(key);
next_token(s);
}
if (!s->has_error)
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 (token(s) != ']') {
json_t *value;
char valueOptional;
if (!token(s)) {
set_error(s, "<format>", json_error_invalid_format, "Unexpected end of format string");
/* Format string errors are unrecoverable. */
goto error;
}
next_token(s);
valueOptional = token(s);
prev_token(s);
value = pack(s, ap);
if (!value) {
if (valueOptional != '*') {
s->has_error = 1;
}
next_token(s);
continue;
}
if (s->has_error)
json_decref(value);
if (!s->has_error && json_array_append_new(array, value)) {
set_error(s, "<internal>", json_error_out_of_memory, "Unable to append to array");
s->has_error = 1;
}
next_token(s);
}
if (!s->has_error)
return array;
error:
json_decref(array);
return NULL;
}
static json_t *pack_string(scanner_t *s, va_list *ap) {
char *str;
char t;
size_t len;
int ours;
int optional;
next_token(s);
t = token(s);
optional = t == '?' || t == '*';
if (!optional)
prev_token(s);
str = read_string(s, ap, "string", &len, &ours, optional);
if (!str)
return t == '?' && !s->has_error ? json_null() : NULL;
if (s->has_error) {
/* It's impossible to reach this point if ours != 0, do not free str. */
return NULL;
}
if (ours)
return jsonp_stringn_nocheck_own(str, len);
return json_stringn_nocheck(str, len);
}
static json_t *pack_object_inter(scanner_t *s, va_list *ap, int need_incref) {
json_t *json;
char ntoken;
next_token(s);
ntoken = token(s);
if (ntoken != '?' && ntoken != '*')
prev_token(s);
json = va_arg(*ap, json_t *);
if (json)
return need_incref ? json_incref(json) : json;
switch (ntoken) {
case '?':
return json_null();
case '*':
return NULL;
default:
break;
}
set_error(s, "<args>", json_error_null_value, "NULL object");
s->has_error = 1;
return NULL;
}
static json_t *pack_integer(scanner_t *s, json_int_t value) {
json_t *json = json_integer(value);
if (!json) {
set_error(s, "<internal>", json_error_out_of_memory, "Out of memory");
s->has_error = 1;
}
return json;
}
static json_t *pack_real(scanner_t *s, double value) {
/* Allocate without setting value so we can identify OOM error. */
json_t *json = json_real(0.0);
if (!json) {
set_error(s, "<internal>", json_error_out_of_memory, "Out of memory");
s->has_error = 1;
return NULL;
}
if (json_real_set(json, value)) {
json_decref(json);
set_error(s, "<args>", json_error_numeric_overflow, "Invalid floating point value");
s->has_error = 1;
return NULL;
}
return json;
}
static json_t *pack(scanner_t *s, va_list *ap) {
switch (token(s)) {
case '{':
return pack_object(s, ap);
case '[':
return pack_array(s, ap);
case 's': /* string */
return pack_string(s, ap);
case 'n': /* null */
return json_null();
case 'b': /* boolean */
return va_arg(*ap, int) ? json_true() : json_false();
case 'i': /* integer from int */
return pack_integer(s, va_arg(*ap, int));
case 'I': /* integer from json_int_t */
return pack_integer(s, va_arg(*ap, json_int_t));
case 'f': /* real */
return pack_real(s, va_arg(*ap, double));
case 'O': /* a json_t object; increments refcount */
return pack_object_inter(s, ap, 1);
case 'o': /* a json_t object; doesn't increment refcount */
return pack_object_inter(s, ap, 0);
default:
set_error(s, "<format>", json_error_invalid_format, "Unexpected format character '%c'",
token(s));
s->has_error = 1;
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;
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
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>", json_error_out_of_memory, "Out of memory");
return -1;
}
if (root && !json_is_object(root)) {
set_error(s,
"<validation>",
json_error_wrong_type,
"Expected object, got %s",
(root) ? type_name(root) : "NULL"
);
goto out;
}
next_token(s);
while (token(s) != '}') {
const char *key;
json_t *value;
int opt = 0;
if (strict != 0) {
set_error(s, "<format>", json_error_invalid_format, "Expected '}' after '%c', got '%c'",
(strict == 1 ? '!' : '*'), token(s));
goto out;
}
if (!token(s)) {
set_error(s, "<format>", json_error_invalid_format, "Unexpected end of format string");
goto out;
}
if (token(s) == '!' || token(s) == '*') {
strict = (token(s) == '!' ? 1 : -1);
next_token(s);
continue;
}
if (token(s) != 's') {
set_error(s, "<format>", json_error_invalid_format, "Expected format 's', got '%c'", token(s));
goto out;
}
key = va_arg(*ap, const char *);
if (!key) {
set_error(s, "<args>", json_error_null_value, "NULL object key");
goto out;
}
next_token(s);
if (token(s) == '?') {
opt = gotopt = 1;
next_token(s);
}
if (!root) {
/* skipping */
value = NULL;
} else {
value = json_object_get(root, key);
if (!value && !opt) {
set_error(s, "<validation>", json_error_item_not_found, "Object item not found: %s", key);
goto out;
}
}
if (unpack(s, value, ap))
goto out;
hashtable_set(&key_set, key, json_null());
next_token(s);
}
if (strict == 0 && (s->flags & JSON_STRICT))
strict = 1;
if (root && strict == 1) {
/* We need to check that all non optional items have been parsed */
const char *key;
/* keys_res is 1 for uninitialized, 0 for success, -1 for error. */
int keys_res = 1;
strbuffer_t unrecognized_keys;
json_t *value;
long unpacked = 0;
if (gotopt || json_object_size(root) != key_set.size) {
json_object_foreach(root, key, value) {
if (!hashtable_get(&key_set, key)) {
unpacked++;
/* Save unrecognized keys for the error message */
if (keys_res == 1) {
keys_res = strbuffer_init(&unrecognized_keys);
} else if (!keys_res) {
keys_res = strbuffer_append_bytes(&unrecognized_keys, ", ", 2);
}
if (!keys_res)
keys_res = strbuffer_append_bytes(&unrecognized_keys, key, strlen(key));
}
}
}
if (unpacked) {
set_error(s, "<validation>", json_error_end_of_input_expected,
"%li object item(s) left unpacked: %s",
unpacked,
keys_res ? "<unknown>" : strbuffer_value(&unrecognized_keys));
strbuffer_close(&unrecognized_keys);
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>", json_error_wrong_type, "Expected array, got %s", type_name(root));
return -1;
}
next_token(s);
while (token(s) != ']') {
json_t *value;
if (strict != 0) {
set_error(s, "<format>", json_error_invalid_format, "Expected ']' after '%c', got '%c'",
(strict == 1 ? '!' : '*'),
token(s));
return -1;
}
if (!token(s)) {
set_error(s, "<format>", json_error_invalid_format, "Unexpected end of format string");
return -1;
}
if (token(s) == '!' || token(s) == '*') {
strict = (token(s) == '!' ? 1 : -1);
next_token(s);
continue;
}
if (!strchr(unpack_value_starters, token(s))) {
set_error(s, "<format>", json_error_invalid_format, "Unexpected format character '%c'",
token(s));
return -1;
}
if (!root) {
/* skipping */
value = NULL;
} else {
value = json_array_get(root, i);
if (!value) {
set_error(s, "<validation>", json_error_index_out_of_range, "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>", json_error_end_of_input_expected, "%li array item(s) left unpacked", diff);
return -1;
}
return 0;
}
static int unpack(scanner_t *s, json_t *root, va_list *ap) {
switch (token(s)) {
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>", json_error_wrong_type, "Expected string, got %s",
type_name(root));
return -1;
}
if (!(s->flags & JSON_VALIDATE_ONLY)) {
const char **str_target;
size_t *len_target = NULL;
str_target = va_arg(*ap, const char **);
if (!str_target) {
set_error(s, "<args>", json_error_null_value, "NULL string argument");
return -1;
}
next_token(s);
if (token(s) == '%') {
len_target = va_arg(*ap, size_t *);
if (!len_target) {
set_error(s, "<args>", json_error_null_value, "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;
case 'i':
if (root && !json_is_integer(root)) {
set_error(s, "<validation>", json_error_wrong_type, "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>", json_error_wrong_type, "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>", json_error_wrong_type, "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>", json_error_wrong_type, "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>", json_error_wrong_type, "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>", json_error_wrong_type, "Expected null, got %s",
type_name(root));
return -1;
}
return 0;
default:
set_error(s, "<format>", json_error_invalid_format, "Unexpected format character '%c'",
token(s));
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, json_error_invalid_argument, "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);
/* This will cover all situations where s.has_error is true */
if (!value)
return NULL;
next_token(&s);
if (token(&s)) {
json_decref(value);
set_error(&s, "<format>", json_error_invalid_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, json_error_null_value, "NULL root value");
return -1;
}
if (!fmt || !*fmt) {
jsonp_error_init(error, "<format>");
jsonp_error_set(error, -1, -1, 0, json_error_invalid_argument, "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 (token(&s)) {
set_error(&s, "<format>", json_error_invalid_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;
}

197
client/deps/jansson/path.c Normal file
View file

@ -0,0 +1,197 @@
/*
* Copyright (c) 2012 Rogerz Zhang <rogerz.zhang@gmail.com>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*
* source here https://github.com/rogerz/jansson/blob/json_path/src/path.c
*/
#include <string.h>
#include <assert.h>
#include "jansson.h"
#include "jansson_private.h"
json_t *json_path_get(const json_t *json, const char *path) {
static const char root_chr = '$', array_open = '[';
static const char *path_delims = ".[", *array_close = "]";
const json_t *cursor;
char *token, *buf, *peek, *endptr, delim = '\0';
const char *expect;
if (!json || !path || path[0] != root_chr)
return NULL;
else
buf = jsonp_strdup(path);
peek = buf + 1;
cursor = json;
token = NULL;
expect = path_delims;
while (peek && *peek && cursor) {
char *last_peek = peek;
peek = strpbrk(peek, expect);
if (peek) {
if (!token && peek != last_peek)
goto fail;
delim = *peek;
*peek++ = '\0';
} else if (expect != path_delims || !token) {
goto fail;
}
if (expect == path_delims) {
if (token) {
cursor = json_object_get(cursor, token);
}
expect = (delim == array_open ? array_close : path_delims);
token = peek;
} else if (expect == array_close) {
size_t index = strtol(token, &endptr, 0);
if (*endptr)
goto fail;
cursor = json_array_get(cursor, index);
token = NULL;
expect = path_delims;
} else {
goto fail;
}
}
jsonp_free(buf);
return (json_t *)cursor;
fail:
jsonp_free(buf);
return NULL;
}
int json_path_set_new(json_t *json, const char *path, json_t *value, size_t flags, json_error_t *error) {
static const char root_chr = '$', array_open = '[', object_delim = '.';
static const char *const path_delims = ".[", *array_close = "]";
json_t *cursor, *parent = NULL;
char *token, *buf = NULL, *peek, delim = '\0';
const char *expect;
int index_saved = -1;
jsonp_error_init(error, "<path>");
if (!json || !path || flags || !value) {
jsonp_error_set(error, -1, -1, 0, json_error_invalid_argument, "invalid argument");
goto fail;
} else {
buf = jsonp_strdup(path);
}
if (buf[0] != root_chr) {
jsonp_error_set(error, -1, -1, 0, json_error_invalid_format, "path should start with $");
goto fail;
}
peek = buf + 1;
cursor = json;
token = NULL;
expect = path_delims;
while (peek && *peek && cursor) {
char *last_peek = peek;
peek = strpbrk(last_peek, expect);
if (peek) {
if (!token && peek != last_peek) {
jsonp_error_set(error, -1, -1, last_peek - buf, json_error_invalid_format, "unexpected trailing chars");
goto fail;
}
delim = *peek;
*peek++ = '\0';
} else { // end of path
if (expect == path_delims) {
break;
} else {
jsonp_error_set(error, -1, -1, last_peek - buf, json_error_invalid_format, "missing ']'?");
goto fail;
}
}
if (expect == path_delims) {
if (token) {
if (token[0] == '\0') {
jsonp_error_set(error, -1, -1, peek - buf, json_error_invalid_format, "empty token");
goto fail;
}
parent = cursor;
cursor = json_object_get(parent, token);
if (!cursor) {
if (!json_is_object(parent)) {
jsonp_error_set(error, -1, -1, peek - buf, json_error_item_not_found, "object expected");
goto fail;
}
if (delim == object_delim) {
cursor = json_object();
json_object_set_new(parent, token, cursor);
} else {
jsonp_error_set(error, -1, -1, peek - buf, json_error_item_not_found, "new array is not allowed");
goto fail;
}
}
}
expect = (delim == array_open ? array_close : path_delims);
token = peek;
} else if (expect == array_close) {
char *endptr;
size_t index;
parent = cursor;
if (!json_is_array(parent)) {
jsonp_error_set(error, -1, -1, peek - buf, json_error_item_not_found, "array expected");
goto fail;
}
index = strtol(token, &endptr, 0);
if (*endptr) {
jsonp_error_set(error, -1, -1, peek - buf, json_error_item_not_found, "invalid array index");
goto fail;
}
cursor = json_array_get(parent, index);
if (!cursor) {
jsonp_error_set(error, -1, -1, peek - buf, json_error_item_not_found, "array index out of bound");
goto fail;
}
index_saved = index;
token = NULL;
expect = path_delims;
} else {
assert(1);
jsonp_error_set(error, -1, -1, peek - buf, json_error_unknown, "unexpected error in path move");
goto fail;
}
}
if (token) {
if (json_is_object(cursor)) {
json_object_set(cursor, token, value);
} else {
jsonp_error_set(error, -1, -1, peek - buf, json_error_item_not_found, "object expected");
goto fail;
}
cursor = json_object_get(cursor, token);
} else if (index_saved != -1 && json_is_array(parent)) {
json_array_set(parent, index_saved, value);
cursor = json_array_get(parent, index_saved);
} else {
jsonp_error_set(error, -1, -1, 0, json_error_item_not_found, "invalid path");
goto fail;
}
json_decref(value);
jsonp_free(buf);
return 0;
fail:
json_decref(value);
jsonp_free(buf);
return -1;
}

View file

@ -0,0 +1,101 @@
/*
* Copyright (c) 2009-2016 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"
#include "strbuffer.h"
#define STRBUFFER_MIN_SIZE 16
#define STRBUFFER_FACTOR 2
#define STRBUFFER_SIZE_MAX ((size_t)-1)
int strbuffer_init(strbuffer_t *strbuff) {
strbuff->size = STRBUFFER_MIN_SIZE;
strbuff->length = 0;
strbuff->value = jsonp_malloc(strbuff->size);
if (!strbuff->value)
return -1;
/* initialize to empty */
strbuff->value[0] = '\0';
return 0;
}
void strbuffer_close(strbuffer_t *strbuff) {
if (strbuff->value)
jsonp_free(strbuff->value);
strbuff->size = 0;
strbuff->length = 0;
strbuff->value = NULL;
}
void strbuffer_clear(strbuffer_t *strbuff) {
strbuff->length = 0;
strbuff->value[0] = '\0';
}
const char *strbuffer_value(const strbuffer_t *strbuff) {
return strbuff->value;
}
char *strbuffer_steal_value(strbuffer_t *strbuff) {
char *result = strbuff->value;
strbuff->value = NULL;
return result;
}
int strbuffer_append_byte(strbuffer_t *strbuff, char byte) {
return strbuffer_append_bytes(strbuff, &byte, 1);
}
int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size) {
if (size >= strbuff->size - strbuff->length) {
size_t new_size;
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,
strbuff->length + size + 1);
new_value = jsonp_malloc(new_size);
if (!new_value)
return -1;
memcpy(new_value, strbuff->value, strbuff->length);
jsonp_free(strbuff->value);
strbuff->value = new_value;
strbuff->size = new_size;
}
memcpy(strbuff->value + strbuff->length, data, size);
strbuff->length += size;
strbuff->value[strbuff->length] = '\0';
return 0;
}
char strbuffer_pop(strbuffer_t *strbuff) {
if (strbuff->length > 0) {
char c = strbuff->value[--strbuff->length];
strbuff->value[strbuff->length] = '\0';
return c;
} else
return '\0';
}

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2009-2016 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 STRBUFFER_H
#define STRBUFFER_H
#include <stdlib.h>
typedef struct {
char *value;
size_t length; /* bytes used */
size_t size; /* bytes allocated */
} strbuffer_t;
int strbuffer_init(strbuffer_t *strbuff) JANSSON_ATTRS(warn_unused_result);
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_byte(strbuffer_t *strbuff, char byte);
int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size);
char strbuffer_pop(strbuffer_t *strbuff);
#endif

View file

@ -0,0 +1,140 @@
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#ifdef __MINGW32__
#undef __NO_ISOCEXT /* ensure stdlib.h will declare prototypes for mingw own 'strtod' replacement, called '__strtod' */
#endif
#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
#ifdef __MINGW32__
#define strtod __strtod
#endif
#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 ((value == HUGE_VAL || value == -HUGE_VAL) && errno == ERANGE) {
/* Overflow */
return -1;
}
*out = value;
return 0;
}
int jsonp_dtostr(char *buffer, size_t size, double value, int precision) {
int ret;
char *start, *end;
size_t length;
if (precision == 0)
precision = 17;
ret = snprintf(buffer, size, "%.*g", precision, 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;
}

160
client/deps/jansson/utf.c Normal file
View file

@ -0,0 +1,160 @@
/*
* Copyright (c) 2009-2016 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.
*/
#include <string.h>
#include "utf.h"
int utf8_encode(int32_t codepoint, char *buffer, size_t *size) {
if (codepoint < 0)
return -1;
else if (codepoint < 0x80) {
buffer[0] = (char)codepoint;
*size = 1;
} else if (codepoint < 0x800) {
buffer[0] = 0xC0 + ((codepoint & 0x7C0) >> 6);
buffer[1] = 0x80 + ((codepoint & 0x03F));
*size = 2;
} else if (codepoint < 0x10000) {
buffer[0] = 0xE0 + ((codepoint & 0xF000) >> 12);
buffer[1] = 0x80 + ((codepoint & 0x0FC0) >> 6);
buffer[2] = 0x80 + ((codepoint & 0x003F));
*size = 3;
} else if (codepoint <= 0x10FFFF) {
buffer[0] = 0xF0 + ((codepoint & 0x1C0000) >> 18);
buffer[1] = 0x80 + ((codepoint & 0x03F000) >> 12);
buffer[2] = 0x80 + ((codepoint & 0x000FC0) >> 6);
buffer[3] = 0x80 + ((codepoint & 0x00003F));
*size = 4;
} else
return -1;
return 0;
}
size_t utf8_check_first(char byte) {
unsigned char u = (unsigned char)byte;
if (u < 0x80)
return 1;
if (0x80 <= u && u <= 0xBF) {
/* second, third or fourth byte of a multi-byte
sequence, i.e. a "continuation byte" */
return 0;
} else if (u == 0xC0 || u == 0xC1) {
/* overlong encoding of an ASCII byte */
return 0;
} else if (0xC2 <= u && u <= 0xDF) {
/* 2-byte sequence */
return 2;
}
else if (0xE0 <= u && u <= 0xEF) {
/* 3-byte sequence */
return 3;
} else if (0xF0 <= u && u <= 0xF4) {
/* 4-byte sequence */
return 4;
} else { /* u >= 0xF5 */
/* Restricted (start of 4-, 5- or 6-byte sequence) or invalid
UTF-8 */
return 0;
}
}
size_t utf8_check_full(const char *buffer, size_t size, int32_t *codepoint) {
size_t i;
int32_t value = 0;
unsigned char u = (unsigned char)buffer[0];
if (size == 2) {
value = u & 0x1F;
} else if (size == 3) {
value = u & 0xF;
} else if (size == 4) {
value = u & 0x7;
} else
return 0;
for (i = 1; i < size; i++) {
u = (unsigned char)buffer[i];
if (u < 0x80 || u > 0xBF) {
/* not a continuation byte */
return 0;
}
value = (value << 6) + (u & 0x3F);
}
if (value > 0x10FFFF) {
/* not in Unicode range */
return 0;
}
else if (0xD800 <= value && value <= 0xDFFF) {
/* invalid code point (UTF-16 surrogate halves) */
return 0;
}
else if ((size == 2 && value < 0x80) ||
(size == 3 && value < 0x800) ||
(size == 4 && value < 0x10000)) {
/* overlong encoding */
return 0;
}
if (codepoint)
*codepoint = value;
return 1;
}
const char *utf8_iterate(const char *buffer, size_t bufsize, int32_t *codepoint) {
size_t count;
int32_t value;
if (!bufsize)
return buffer;
count = utf8_check_first(buffer[0]);
if (count == 0)
return NULL;
if (count == 1)
value = (unsigned char)buffer[0];
else {
if (count > bufsize || !utf8_check_full(buffer, count, &value))
return NULL;
}
if (codepoint)
*codepoint = value;
return buffer + count;
}
int utf8_check_string(const char *string, size_t length) {
size_t i;
for (i = 0; i < length; i++) {
size_t count = utf8_check_first(string[i]);
if (count == 0)
return 0;
else if (count > 1) {
if (count > length - i)
return 0;
if (!utf8_check_full(&string[i], count, NULL))
return 0;
i += count - 1;
}
}
return 1;
}

27
client/deps/jansson/utf.h Normal file
View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2009-2016 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 UTF_H
#define UTF_H
#ifdef HAVE_CONFIG_H
#include <jansson_private_config.h>
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
int utf8_encode(int32_t codepoint, char *buffer, size_t *size);
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 bufsize, int32_t *codepoint);
int utf8_check_string(const char *string, size_t length);
#endif

991
client/deps/jansson/value.c Normal file
View file

@ -0,0 +1,991 @@
/*
* Copyright (c) 2009-2016 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"
#include "utf.h"
/* Work around nonstandard isnan() and isinf() implementations */
#ifndef isnan
#ifndef __sun
static JSON_INLINE int isnan(double x) { return x != x; }
#endif
#endif
#ifndef isinf
static JSON_INLINE int isinf(double x) { return !isnan(x) && isnan(x - x); }
#endif
static JSON_INLINE void json_init(json_t *json, json_type type) {
json->type = type;
json->refcount = 1;
}
/*** 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)) {
jsonp_free(object);
return NULL;
}
return &object->json;
}
static void json_delete_object(json_object_t *object) {
hashtable_close(&object->hashtable);
jsonp_free(object);
}
size_t json_object_size(const json_t *json) {
json_object_t *object;
if (!json_is_object(json))
return 0;
object = json_to_object(json);
return object->hashtable.size;
}
json_t *json_object_get(const json_t *json, const char *key) {
json_object_t *object;
if (!key || !json_is_object(json))
return NULL;
object = json_to_object(json);
return hashtable_get(&object->hashtable, key);
}
int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value) {
json_object_t *object;
if (!value)
return -1;
if (!key || !json_is_object(json) || json == value) {
json_decref(value);
return -1;
}
object = json_to_object(json);
if (hashtable_set(&object->hashtable, key, value)) {
json_decref(value);
return -1;
}
return 0;
}
int json_object_set_new(json_t *json, const char *key, json_t *value) {
if (!key || !utf8_check_string(key, strlen(key))) {
json_decref(value);
return -1;
}
return json_object_set_new_nocheck(json, key, value);
}
int json_object_del(json_t *json, const char *key) {
json_object_t *object;
if (!key || !json_is_object(json))
return -1;
object = json_to_object(json);
return hashtable_del(&object->hashtable, key);
}
int json_object_clear(json_t *json) {
json_object_t *object;
if (!json_is_object(json))
return -1;
object = json_to_object(json);
hashtable_clear(&object->hashtable);
return 0;
}
int json_object_update(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_set_nocheck(object, key, value))
return -1;
}
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;
}
void *json_object_iter(json_t *json) {
json_object_t *object;
if (!json_is_object(json))
return NULL;
object = json_to_object(json);
return hashtable_iter(&object->hashtable);
}
void *json_object_iter_at(json_t *json, const char *key) {
json_object_t *object;
if (!key || !json_is_object(json))
return NULL;
object = json_to_object(json);
return hashtable_iter_at(&object->hashtable, key);
}
void *json_object_iter_next(json_t *json, void *iter) {
json_object_t *object;
if (!json_is_object(json) || iter == NULL)
return NULL;
object = json_to_object(json);
return hashtable_iter_next(&object->hashtable, iter);
}
const char *json_object_iter_key(void *iter) {
if (!iter)
return NULL;
return hashtable_iter_key(iter);
}
json_t *json_object_iter_value(void *iter) {
if (!iter)
return NULL;
return (json_t *)hashtable_iter_value(iter);
}
int json_object_iter_set_new(json_t *json, void *iter, json_t *value) {
if (!json_is_object(json) || !iter || !value) {
json_decref(value);
return -1;
}
hashtable_iter_set(iter, value);
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(const json_t *object1, const json_t *object2) {
const char *key;
const json_t *value1, *value2;
if (json_object_size(object1) != json_object_size(object2))
return 0;
json_object_foreach((json_t *)object1, key, value1) {
value2 = json_object_get(object2, key);
if (!json_equal(value1, value2))
return 0;
}
return 1;
}
static json_t *json_object_copy(json_t *object) {
json_t *result;
const char *key;
json_t *value;
result = json_object();
if (!result)
return NULL;
json_object_foreach(object, key, value)
json_object_set_nocheck(result, key, value);
return result;
}
static json_t *json_object_deep_copy(const json_t *object) {
json_t *result;
void *iter;
result = json_object();
if (!result)
return NULL;
/* 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;
}
/*** array ***/
json_t *json_array(void) {
json_array_t *array = jsonp_malloc(sizeof(json_array_t));
if (!array)
return NULL;
json_init(&array->json, JSON_ARRAY);
array->entries = 0;
array->size = 8;
array->table = jsonp_malloc(array->size * sizeof(json_t *));
if (!array->table) {
jsonp_free(array);
return NULL;
}
return &array->json;
}
static void json_delete_array(json_array_t *array) {
size_t i;
for (i = 0; i < array->entries; i++)
json_decref(array->table[i]);
jsonp_free(array->table);
jsonp_free(array);
}
size_t json_array_size(const json_t *json) {
if (!json_is_array(json))
return 0;
return json_to_array(json)->entries;
}
json_t *json_array_get(const json_t *json, size_t index) {
json_array_t *array;
if (!json_is_array(json))
return NULL;
array = json_to_array(json);
if (index >= array->entries)
return NULL;
return array->table[index];
}
int json_array_set_new(json_t *json, size_t index, json_t *value) {
json_array_t *array;
if (!value)
return -1;
if (!json_is_array(json) || json == value) {
json_decref(value);
return -1;
}
array = json_to_array(json);
if (index >= array->entries) {
json_decref(value);
return -1;
}
json_decref(array->table[index]);
array->table[index] = value;
return 0;
}
static void array_move(json_array_t *array, size_t dest,
size_t src, size_t count) {
memmove(&array->table[dest], &array->table[src], count * sizeof(json_t *));
}
static void array_copy(json_t **dest, size_t dpos,
json_t **src, size_t spos,
size_t count) {
memcpy(&dest[dpos], &src[spos], count * sizeof(json_t *));
}
static json_t **json_array_grow(json_array_t *array,
size_t amount,
int copy) {
size_t new_size;
json_t **old_table, **new_table;
if (array->entries + amount <= array->size)
return array->table;
old_table = array->table;
new_size = max(array->size + amount, array->size * 2);
new_table = jsonp_malloc(new_size * sizeof(json_t *));
if (!new_table)
return NULL;
array->size = new_size;
array->table = new_table;
if (copy) {
array_copy(array->table, 0, old_table, 0, array->entries);
jsonp_free(old_table);
return array->table;
}
return old_table;
}
int json_array_append_new(json_t *json, json_t *value) {
json_array_t *array;
if (!value)
return -1;
if (!json_is_array(json) || json == value) {
json_decref(value);
return -1;
}
array = json_to_array(json);
if (!json_array_grow(array, 1, 1)) {
json_decref(value);
return -1;
}
array->table[array->entries] = value;
array->entries++;
return 0;
}
int json_array_insert_new(json_t *json, size_t index, json_t *value) {
json_array_t *array;
json_t **old_table;
if (!value)
return -1;
if (!json_is_array(json) || json == value) {
json_decref(value);
return -1;
}
array = json_to_array(json);
if (index > array->entries) {
json_decref(value);
return -1;
}
old_table = json_array_grow(array, 1, 0);
if (!old_table) {
json_decref(value);
return -1;
}
if (old_table != array->table) {
array_copy(array->table, 0, old_table, 0, index);
array_copy(array->table, index + 1, old_table, index,
array->entries - index);
jsonp_free(old_table);
} else
array_move(array, index + 1, index, array->entries - index);
array->table[index] = value;
array->entries++;
return 0;
}
int json_array_remove(json_t *json, size_t index) {
json_array_t *array;
if (!json_is_array(json))
return -1;
array = json_to_array(json);
if (index >= array->entries)
return -1;
json_decref(array->table[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;
}
int json_array_clear(json_t *json) {
json_array_t *array;
size_t i;
if (!json_is_array(json))
return -1;
array = json_to_array(json);
for (i = 0; i < array->entries; i++)
json_decref(array->table[i]);
array->entries = 0;
return 0;
}
int json_array_extend(json_t *json, json_t *other_json) {
json_array_t *array, *other;
size_t i;
if (!json_is_array(json) || !json_is_array(other_json))
return -1;
array = json_to_array(json);
other = json_to_array(other_json);
if (!json_array_grow(array, other->entries, 1))
return -1;
for (i = 0; i < other->entries; i++)
json_incref(other->table[i]);
array_copy(array->table, array->entries, other->table, 0, other->entries);
array->entries += other->entries;
return 0;
}
static int json_array_equal(const json_t *array1, const json_t *array2) {
size_t i, size;
size = json_array_size(array1);
if (size != json_array_size(array2))
return 0;
for (i = 0; i < size; i++) {
json_t *value1, *value2;
value1 = json_array_get(array1, i);
value2 = json_array_get(array2, i);
if (!json_equal(value1, value2))
return 0;
}
return 1;
}
static json_t *json_array_copy(json_t *array) {
json_t *result;
size_t i;
result = json_array();
if (!result)
return NULL;
for (i = 0; i < json_array_size(array); i++)
json_array_append(result, json_array_get(array, i));
return result;
}
static json_t *json_array_deep_copy(const json_t *array) {
json_t *result;
size_t i;
result = json_array();
if (!result)
return NULL;
for (i = 0; i < json_array_size(array); i++)
json_array_append_new(result, json_deep_copy(json_array_get(array, i)));
return result;
}
/*** string ***/
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) {
jsonp_free(v);
return NULL;
}
json_init(&string->json, JSON_STRING);
string->value = v;
string->length = len;
return &string->json;
}
json_t *json_string_nocheck(const char *value) {
if (!value)
return NULL;
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)
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_stringn_nocheck(value, len);
}
const char *json_string_value(const json_t *json) {
if (!json_is_string(json))
return NULL;
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_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)
return -1;
return json_string_setn(json, value, strlen(value));
}
int json_string_setn(json_t *json, const char *value, size_t len) {
if (!value || !utf8_check_string(value, len))
return -1;
return json_string_setn_nocheck(json, value, len);
}
static void json_delete_string(json_string_t *string) {
jsonp_free(string->value);
jsonp_free(string);
}
static int json_string_equal(const json_t *string1, const json_t *string2) {
json_string_t *s1, *s2;
s1 = json_to_string(string1);
s2 = json_to_string(string2);
return s1->length == s2->length && !memcmp(s1->value, s2->value, s1->length);
}
static json_t *json_string_copy(const json_t *string) {
json_string_t *s;
s = json_to_string(string);
return json_stringn_nocheck(s->value, s->length);
}
json_t *json_vsprintf(const char *fmt, va_list ap) {
json_t *json = NULL;
int length;
char *buf;
va_list aq;
va_copy(aq, ap);
length = vsnprintf(NULL, 0, fmt, ap);
if (length == 0) {
json = json_string("");
goto out;
}
buf = jsonp_malloc(length + 1);
if (!buf)
goto out;
vsnprintf(buf, length + 1, fmt, aq);
if (!utf8_check_string(buf, length)) {
jsonp_free(buf);
goto out;
}
json = jsonp_stringn_nocheck_own(buf, length);
out:
va_end(aq);
return json;
}
json_t *json_sprintf(const char *fmt, ...) {
json_t *result;
va_list ap;
va_start(ap, fmt);
result = json_vsprintf(fmt, ap);
va_end(ap);
return result;
}
/*** integer ***/
json_t *json_integer(json_int_t value) {
json_integer_t *integer = jsonp_malloc(sizeof(json_integer_t));
if (!integer)
return NULL;
json_init(&integer->json, JSON_INTEGER);
integer->value = value;
return &integer->json;
}
json_int_t json_integer_value(const json_t *json) {
if (!json_is_integer(json))
return 0;
return json_to_integer(json)->value;
}
int json_integer_set(json_t *json, json_int_t value) {
if (!json_is_integer(json))
return -1;
json_to_integer(json)->value = value;
return 0;
}
static void json_delete_integer(json_integer_t *integer) {
jsonp_free(integer);
}
static int json_integer_equal(const json_t *integer1, const json_t *integer2) {
return json_integer_value(integer1) == json_integer_value(integer2);
}
static json_t *json_integer_copy(const json_t *integer) {
return json_integer(json_integer_value(integer));
}
/*** real ***/
json_t *json_real(double value) {
json_real_t *real;
if (isnan(value) || isinf(value))
return NULL;
real = jsonp_malloc(sizeof(json_real_t));
if (!real)
return NULL;
json_init(&real->json, JSON_REAL);
real->value = value;
return &real->json;
}
double json_real_value(const json_t *json) {
if (!json_is_real(json))
return 0;
return json_to_real(json)->value;
}
int json_real_set(json_t *json, double value) {
if (!json_is_real(json) || isnan(value) || isinf(value))
return -1;
json_to_real(json)->value = value;
return 0;
}
static void json_delete_real(json_real_t *real) {
jsonp_free(real);
}
static int json_real_equal(const json_t *real1, const json_t *real2) {
return json_real_value(real1) == json_real_value(real2);
}
static json_t *json_real_copy(const json_t *real) {
return json_real(json_real_value(real));
}
/*** number ***/
double json_number_value(const json_t *json) {
if (json_is_integer(json))
return (double)json_integer_value(json);
else if (json_is_real(json))
return json_real_value(json);
else
return 0.0;
}
/*** simple values ***/
json_t *json_true(void) {
static json_t the_true = {JSON_TRUE, (size_t) - 1};
return &the_true;
}
json_t *json_false(void) {
static json_t the_false = {JSON_FALSE, (size_t) - 1};
return &the_false;
}
json_t *json_null(void) {
static json_t the_null = {JSON_NULL, (size_t) - 1};
return &the_null;
}
/*** deletion ***/
void json_delete(json_t *json) {
if (!json)
return;
switch (json_typeof(json)) {
case JSON_OBJECT:
json_delete_object(json_to_object(json));
break;
case JSON_ARRAY:
json_delete_array(json_to_array(json));
break;
case JSON_STRING:
json_delete_string(json_to_string(json));
break;
case JSON_INTEGER:
json_delete_integer(json_to_integer(json));
break;
case JSON_REAL:
json_delete_real(json_to_real(json));
break;
default:
return;
}
/* json_delete is not called for true, false or null */
}
/*** equality ***/
int json_equal(const json_t *json1, const json_t *json2) {
if (!json1 || !json2)
return 0;
if (json_typeof(json1) != json_typeof(json2))
return 0;
/* this covers true, false and null as they are singletons */
if (json1 == json2)
return 1;
switch (json_typeof(json1)) {
case JSON_OBJECT:
return json_object_equal(json1, json2);
case JSON_ARRAY:
return json_array_equal(json1, json2);
case JSON_STRING:
return json_string_equal(json1, json2);
case JSON_INTEGER:
return json_integer_equal(json1, json2);
case JSON_REAL:
return json_real_equal(json1, json2);
default:
return 0;
}
}
/*** copying ***/
json_t *json_copy(json_t *json) {
if (!json)
return NULL;
switch (json_typeof(json)) {
case JSON_OBJECT:
return json_object_copy(json);
case JSON_ARRAY:
return json_array_copy(json);
case JSON_STRING:
return json_string_copy(json);
case JSON_INTEGER:
return json_integer_copy(json);
case JSON_REAL:
return json_real_copy(json);
case JSON_TRUE:
case JSON_FALSE:
case JSON_NULL:
return json;
default:
return NULL;
}
}
json_t *json_deep_copy(const json_t *json) {
if (!json)
return NULL;
switch (json_typeof(json)) {
case JSON_OBJECT:
return json_object_deep_copy(json);
case JSON_ARRAY:
return json_array_deep_copy(json);
/* for the rest of the types, deep copying doesn't differ from
shallow copying */
case JSON_STRING:
return json_string_copy(json);
case JSON_INTEGER:
return json_integer_copy(json);
case JSON_REAL:
return json_real_copy(json);
case JSON_TRUE:
case JSON_FALSE:
case JSON_NULL:
return (json_t *)json;
default:
return NULL;
}
}