static int dump_to_fd(const char *buffer, size_t size, void *data)
{
- int *dest = (int *)data;
#ifdef HAVE_UNISTD_H
+ int *dest = (int *)data;
if(write(*dest, buffer, size) == (ssize_t)size)
return 0;
#endif
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;
+ int32_t codepoint = 0;
if(dump("\"", 1, data))
return -1;
const char *separator;
int separator_length;
/* Space for "0x", double the sizeof a pointer for the hex and a terminator. */
- char key[2 + (sizeof(json) * 2) + 1];
+ char loop_key[2 + (sizeof(json) * 2) + 1];
if(flags & JSON_COMPACT) {
separator = ":";
}
/* detect circular references */
- if (loop_check(parents, json, key, sizeof(key)))
+ 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, key);
+ hashtable_del(parents, loop_key);
return embed ? 0 : dump("}", 1, data);
}
if(dump_indent(flags, depth + 1, 0, dump, data))
}
}
- hashtable_del(parents, key);
+ hashtable_del(parents, loop_key);
return embed ? 0 : dump("}", 1, data);
}
*
* Returns 0 on success, -1 on error (out of memory).
*/
-int hashtable_init(hashtable_t *hashtable);
+int hashtable_init(hashtable_t *hashtable) JANSSON_ATTRS(warn_unused_result);
/**
* hashtable_close - Release all resources used by a hashtable object
}
static uint32_t generate_seed() {
- uint32_t seed;
+ uint32_t seed = 0;
int done = 0;
#if !defined(_WIN32) && defined(USE_URANDOM)
#define JANSSON_H
#include <stdio.h>
-#include <stdint.h>
#include <stdlib.h> /* for size_t */
#include <stdarg.h>
/* version */
#define JANSSON_MAJOR_VERSION 2
-#define JANSSON_MINOR_VERSION 11
+#define JANSSON_MINOR_VERSION 12
#define JANSSON_MICRO_VERSION 0
/* Micro version is omitted if it's 0 */
-#define JANSSON_VERSION "2.11"
+#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_THREAD_SAFE_REFCOUNT 1
#endif
+#if defined(__GNUC__) || defined(__clang__)
+#define JANSSON_ATTRS(...) __attribute__((__VA_ARGS__))
+#else
+#define JANSSON_ATTRS(...)
+#endif
+
/* types */
typedef enum {
void json_object_seed(size_t seed);
size_t json_object_size(const json_t *object);
-json_t *json_object_get(const json_t *object, const char *key);
+json_t *json_object_get(const json_t *object, const char *key) JANSSON_ATTRS(warn_unused_result);
int json_object_set_new(json_t *object, const char *key, json_t *value);
int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value);
int json_object_del(json_t *object, const char *key);
}
size_t json_array_size(const json_t *array);
-json_t *json_array_get(const json_t *array, size_t index);
+json_t *json_array_get(const json_t *array, size_t index) JANSSON_ATTRS(warn_unused_result);
int json_array_set_new(json_t *array, size_t index, json_t *value);
int json_array_append_new(json_t *array, json_t *value);
int json_array_insert_new(json_t *array, size_t index, json_t *value);
/* pack, unpack */
-json_t *json_pack(const char *fmt, ...);
-json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...);
-json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap);
+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
/* sprintf */
-json_t *json_sprintf(const char *fmt, ...);
-json_t *json_vsprintf(const char *fmt, va_list ap);
+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 */
/* copying */
-json_t *json_copy(json_t *value);
-json_t *json_deep_copy(const json_t *value);
-
-/* path */
+json_t *json_copy(json_t *value) JANSSON_ATTRS(warn_unused_result);
+json_t *json_deep_copy(const json_t *value) 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);
typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data);
-json_t *json_loads(const char *input, size_t flags, json_error_t *error);
-json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error);
-json_t *json_loadf(FILE *input, size_t flags, json_error_t *error);
-json_t *json_loadfd(int input, size_t flags, json_error_t *error);
-json_t *json_load_file(const char *path, size_t flags, json_error_t *error);
-json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error);
+json_t *json_loads(const char *input, 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 *data, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result);
/* encoding */
typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data);
-char *json_dumps(const json_t *json, size_t flags);
+char *json_dumps(const json_t *json, size_t flags) 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 jsonp_dtostr(char *buffer, size_t size, double value, int prec);
/* Wrappers for custom memory functions */
-void* jsonp_malloc(size_t size);
+void* jsonp_malloc(size_t size) JANSSON_ATTRS(warn_unused_result);
void jsonp_free(void *ptr);
-char *jsonp_strndup(const char *str, size_t length);
-char *jsonp_strdup(const char *str);
-char *jsonp_strndup(const char *str, size_t len);
+char *jsonp_strndup(const char *str, size_t length) JANSSON_ATTRS(warn_unused_result);
+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 */
}
json = jsonp_stringn_nocheck_own(value, len);
- if(json) {
- lex->value.string.val = NULL;
- lex->value.string.len = 0;
- }
+ lex->value.string.val = NULL;
+ lex->value.string.len = 0;
break;
}
static int fd_get_func(int *fd)
{
- uint8_t c;
#ifdef HAVE_UNISTD_H
+ uint8_t c;
if (read(*fd, &c, 1) == 1)
return c;
#endif
return;
}
+ if (!token(s) && !*s->fmt)
+ return;
+
t = s->fmt;
s->column++;
s->pos++;
s->token.column = s->column;
s->token.pos = s->pos;
- t++;
+ if (*t) t++;
s->fmt = t;
}
/* 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)
+ const char *purpose, size_t *out_len, int *ours, int optional)
{
char t;
strbuffer_t strbuff;
str = va_arg(*ap, const char *);
if(!str) {
- set_error(s, "<args>", json_error_null_value, "NULL string argument");
+ if (!optional) {
+ set_error(s, "<args>", json_error_null_value, "NULL %s", purpose);
+ s->has_error = 1;
+ }
return NULL;
}
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;
}
- strbuffer_init(&strbuff);
+ 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 string argument");
+ set_error(s, "<args>", json_error_null_value, "NULL %s", purpose);
s->has_error = 1;
}
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;
}
- key = read_string(s, ap, "object key", &len, &ours);
- if (!key)
- s->has_error = 1;
+ 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(strchr("soO", token(s)) && s->next_token.token == '*') {
- next_token(s);
- } else {
+ if(valueOptional != '*') {
+ set_error(s, "<args>", json_error_null_value, "NULL object value");
s->has_error = 1;
}
if(ours)
jsonp_free(key);
- if(strchr("soO", token(s)) && s->next_token.token == '*')
- next_token(s);
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");
goto error;
}
+ next_token(s);
+ valueOptional = token(s);
+ prev_token(s);
+
value = pack(s, ap);
if(!value) {
- if(strchr("soO", token(s)) && s->next_token.token == '*') {
- next_token(s);
- } else {
+ if(valueOptional != '*') {
s->has_error = 1;
}
s->has_error = 1;
}
- if(strchr("soO", token(s)) && s->next_token.token == '*')
- next_token(s);
next_token(s);
}
static json_t *pack_string(scanner_t *s, va_list *ap)
{
char *str;
+ char t;
size_t len;
int ours;
- int nullable;
+ int optional;
next_token(s);
- nullable = token(s) == '?';
- if (!nullable)
+ t = token(s);
+ optional = t == '?' || t == '*';
+ if (!optional)
prev_token(s);
- str = read_string(s, ap, "string", &len, &ours);
- if (!str) {
- return nullable ? json_null() : NULL;
- } else if (ours) {
+ 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);
- } else {
- return json_stringn_nocheck(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)
return va_arg(*ap, int) ? json_true() : json_false();
case 'i': /* integer from int */
- return json_integer(va_arg(*ap, int));
+ return pack_integer(s, va_arg(*ap, int));
case 'I': /* integer from json_int_t */
- return json_integer(va_arg(*ap, json_int_t));
+ return pack_integer(s, va_arg(*ap, json_int_t));
case 'f': /* real */
- return json_real(va_arg(*ap, double));
+ return pack_real(s, va_arg(*ap, double));
case 'O': /* a json_t object; increments refcount */
- {
- int nullable;
- json_t *json;
-
- next_token(s);
- nullable = token(s) == '?';
- if (!nullable)
- prev_token(s);
-
- json = va_arg(*ap, json_t *);
- if (!json && nullable) {
- return json_null();
- } else {
- return json_incref(json);
- }
- }
+ return pack_object_inter(s, ap, 1);
case 'o': /* a json_t object; doesn't increment refcount */
- {
- int nullable;
- json_t *json;
-
- next_token(s);
- nullable = token(s) == '?';
- if (!nullable)
- prev_token(s);
-
- json = va_arg(*ap, json_t *);
- if (!json && nullable) {
- return json_null();
- } else {
- return json;
- }
- }
+ return pack_object_inter(s, ap, 0);
default:
set_error(s, "<format>", json_error_invalid_format, "Unexpected format character '%c'",
if(root && strict == 1) {
/* We need to check that all non optional items have been parsed */
const char *key;
- int have_unrecognized_keys = 0;
+ /* 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) {
- /* We have optional keys, we need to iter on each key */
+
+ 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 (!have_unrecognized_keys) {
- strbuffer_init(&unrecognized_keys);
- have_unrecognized_keys = 1;
- } else {
- strbuffer_append_bytes(&unrecognized_keys, ", ", 2);
+ if (keys_res == 1) {
+ keys_res = strbuffer_init(&unrecognized_keys);
+ } else if (!keys_res) {
+ keys_res = strbuffer_append_bytes(&unrecognized_keys, ", ", 2);
}
- strbuffer_append_bytes(&unrecognized_keys, key, strlen(key));
+
+ if (!keys_res)
+ keys_res = strbuffer_append_bytes(&unrecognized_keys, key, strlen(key));
}
}
- } else {
- /* No optional keys, we can just compare the number of items */
- unpacked = (long)json_object_size(root) - (long)key_set.size;
}
if (unpacked) {
- if (!gotopt) {
- /* Save unrecognized keys for the error message */
- json_object_foreach(root, key, value) {
- if(!hashtable_get(&key_set, key)) {
- if (!have_unrecognized_keys) {
- strbuffer_init(&unrecognized_keys);
- have_unrecognized_keys = 1;
- } else {
- strbuffer_append_bytes(&unrecognized_keys, ", ", 2);
- }
- strbuffer_append_bytes(&unrecognized_keys, key, strlen(key));
- }
- }
- }
set_error(s, "<validation>", json_error_end_of_input_expected,
"%li object item(s) left unpacked: %s",
- unpacked, strbuffer_value(&unrecognized_keys));
+ unpacked,
+ keys_res ? "<unknown>" : strbuffer_value(&unrecognized_keys));
strbuffer_close(&unrecognized_keys);
goto out;
}
value = pack(&s, &ap_copy);
va_end(ap_copy);
+ /* This will cover all situations where s.has_error is true */
if(!value)
return NULL;
set_error(&s, "<format>", json_error_invalid_format, "Garbage after format string");
return NULL;
}
- if(s.has_error) {
- json_decref(value);
- return NULL;
- }
return value;
}
#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 = '[';
size_t size; /* bytes allocated */
} strbuffer_t;
-int strbuffer_init(strbuffer_t *strbuff);
+int strbuffer_init(strbuffer_t *strbuff) JANSSON_ATTRS(warn_unused_result);
void strbuffer_close(strbuffer_t *strbuff);
void strbuffer_clear(strbuffer_t *strbuff);
string = jsonp_malloc(sizeof(json_string_t));
if(!string) {
- if(!own)
- jsonp_free(v);
+ jsonp_free(v);
return NULL;
}
json_init(&string->json, JSON_STRING);
{
json_string_t *s1, *s2;
- if(!json_is_string(string1) || !json_is_string(string2))
- return 0;
-
s1 = json_to_string(string1);
s2 = json_to_string(string2);
return s1->length == s2->length && !memcmp(s1->value, s2->value, s1->length);
{
json_string_t *s;
- if(!json_is_string(string))
- return NULL;
-
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)
- return json_string("");
+ if (length == 0) {
+ json = json_string("");
+ goto out;
+ }
buf = jsonp_malloc(length + 1);
if (!buf)
- return NULL;
+ goto out;
vsnprintf(buf, length + 1, fmt, aq);
if (!utf8_check_string(buf, length)) {
jsonp_free(buf);
- return NULL;
+ goto out;
}
- return jsonp_stringn_nocheck_own(buf, length);
+ json = jsonp_stringn_nocheck_own(buf, length);
+
+out:
+ va_end(aq);
+ return json;
}
json_t *json_sprintf(const char *fmt, ...) {
default:
return NULL;
}
-
- return NULL;
}
json_t *json_deep_copy(const json_t *json)
default:
return NULL;
}
-
- return NULL;
}