2010-05-12 20:41:09 +08:00
|
|
|
/*
|
2016-09-18 19:17:03 +08:00
|
|
|
* Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org>
|
2010-05-12 20:41:09 +08:00
|
|
|
*
|
|
|
|
* Jansson is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the MIT license. See LICENSE for details.
|
|
|
|
*/
|
|
|
|
|
2017-01-27 00:23:31 +08:00
|
|
|
#include "jansson_private_config.h"
|
|
|
|
|
2010-05-12 20:41:09 +08:00
|
|
|
#include <jansson.h>
|
|
|
|
#include <string.h>
|
2017-01-27 00:23:31 +08:00
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
2010-05-12 20:41:09 +08:00
|
|
|
#include "util.h"
|
2019-10-08 16:19:40 +08:00
|
|
|
#ifdef __MINGW32__
|
|
|
|
#include <fcntl.h>
|
|
|
|
#define pipe(fds) _pipe(fds, 1024, _O_BINARY)
|
|
|
|
#endif
|
2010-05-12 20:41:09 +08:00
|
|
|
|
2019-10-17 14:08:51 +08:00
|
|
|
static int encode_null_callback(const char *buffer, size_t size, void *data) {
|
2013-04-15 14:13:29 +08:00
|
|
|
(void)buffer;
|
|
|
|
(void)size;
|
|
|
|
(void)data;
|
2013-04-15 13:42:23 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-10-17 14:08:51 +08:00
|
|
|
static void encode_null() {
|
|
|
|
if (json_dumps(NULL, JSON_ENCODE_ANY) != NULL)
|
2013-04-15 13:42:23 +08:00
|
|
|
fail("json_dumps didn't fail for NULL");
|
|
|
|
|
2019-10-17 14:08:51 +08:00
|
|
|
if (json_dumpb(NULL, NULL, 0, JSON_ENCODE_ANY) != 0)
|
2019-07-22 11:00:31 +08:00
|
|
|
fail("json_dumpb didn't fail for NULL");
|
2017-01-26 16:46:48 +08:00
|
|
|
|
2019-10-17 14:08:51 +08:00
|
|
|
if (json_dumpf(NULL, stderr, JSON_ENCODE_ANY) != -1)
|
2013-04-15 13:42:23 +08:00
|
|
|
fail("json_dumpf didn't fail for NULL");
|
|
|
|
|
2017-01-27 00:23:31 +08:00
|
|
|
#ifdef HAVE_UNISTD_H
|
2019-10-17 14:08:51 +08:00
|
|
|
if (json_dumpfd(NULL, STDERR_FILENO, JSON_ENCODE_ANY) != -1)
|
2017-01-27 00:23:31 +08:00
|
|
|
fail("json_dumpfd didn't fail for NULL");
|
|
|
|
#endif
|
|
|
|
|
2013-04-15 13:42:23 +08:00
|
|
|
/* Don't test json_dump_file to avoid creating a file */
|
|
|
|
|
2019-10-20 01:35:28 +08:00
|
|
|
if (json_dump_callback(NULL, encode_null_callback, NULL, JSON_ENCODE_ANY) != -1)
|
2013-04-15 13:42:23 +08:00
|
|
|
fail("json_dump_callback didn't fail for NULL");
|
|
|
|
}
|
|
|
|
|
2019-10-17 14:08:51 +08:00
|
|
|
static void encode_twice() {
|
2011-05-14 17:56:14 +08:00
|
|
|
/* Encode an empty object/array, add an item, encode again */
|
|
|
|
|
2010-05-12 20:41:09 +08:00
|
|
|
json_t *json;
|
|
|
|
char *result;
|
|
|
|
|
|
|
|
json = json_object();
|
|
|
|
result = json_dumps(json, 0);
|
2019-10-17 14:08:51 +08:00
|
|
|
if (!result || strcmp(result, "{}"))
|
|
|
|
fail("json_dumps failed");
|
2010-06-11 02:15:43 +08:00
|
|
|
free(result);
|
2010-05-12 20:41:09 +08:00
|
|
|
|
|
|
|
json_object_set_new(json, "foo", json_integer(5));
|
|
|
|
result = json_dumps(json, 0);
|
2019-10-17 14:08:51 +08:00
|
|
|
if (!result || strcmp(result, "{\"foo\": 5}"))
|
|
|
|
fail("json_dumps failed");
|
2010-06-11 02:15:43 +08:00
|
|
|
free(result);
|
2010-05-12 20:41:09 +08:00
|
|
|
|
|
|
|
json_decref(json);
|
|
|
|
|
|
|
|
json = json_array();
|
|
|
|
result = json_dumps(json, 0);
|
2019-10-17 14:08:51 +08:00
|
|
|
if (!result || strcmp(result, "[]"))
|
|
|
|
fail("json_dumps failed");
|
2010-05-12 20:41:09 +08:00
|
|
|
free(result);
|
|
|
|
|
|
|
|
json_array_append_new(json, json_integer(5));
|
|
|
|
result = json_dumps(json, 0);
|
2019-10-17 14:08:51 +08:00
|
|
|
if (!result || strcmp(result, "[5]"))
|
|
|
|
fail("json_dumps failed");
|
2010-05-12 20:41:09 +08:00
|
|
|
free(result);
|
|
|
|
|
|
|
|
json_decref(json);
|
2011-05-14 17:56:14 +08:00
|
|
|
}
|
2010-05-12 20:41:09 +08:00
|
|
|
|
2019-10-17 14:08:51 +08:00
|
|
|
static void circular_references() {
|
2010-05-14 13:47:24 +08:00
|
|
|
/* Construct a JSON object/array with a circular reference:
|
|
|
|
|
|
|
|
object: {"a": {"b": {"c": <circular reference to $.a>}}}
|
|
|
|
array: [[[<circular reference to the $[0] array>]]]
|
|
|
|
|
|
|
|
Encode it, remove the circular reference and encode again.
|
|
|
|
*/
|
2011-05-14 17:56:14 +08:00
|
|
|
|
|
|
|
json_t *json;
|
|
|
|
char *result;
|
|
|
|
|
2010-05-14 13:47:24 +08:00
|
|
|
json = json_object();
|
|
|
|
json_object_set_new(json, "a", json_object());
|
|
|
|
json_object_set_new(json_object_get(json, "a"), "b", json_object());
|
|
|
|
json_object_set(json_object_get(json_object_get(json, "a"), "b"), "c",
|
|
|
|
json_object_get(json, "a"));
|
|
|
|
|
2019-10-17 14:08:51 +08:00
|
|
|
if (json_dumps(json, 0))
|
2010-05-14 13:47:24 +08:00
|
|
|
fail("json_dumps encoded a circular reference!");
|
|
|
|
|
|
|
|
json_object_del(json_object_get(json_object_get(json, "a"), "b"), "c");
|
|
|
|
|
|
|
|
result = json_dumps(json, 0);
|
2019-10-17 14:08:51 +08:00
|
|
|
if (!result || strcmp(result, "{\"a\": {\"b\": {}}}"))
|
2010-05-14 13:47:24 +08:00
|
|
|
fail("json_dumps failed!");
|
|
|
|
free(result);
|
|
|
|
|
|
|
|
json_decref(json);
|
|
|
|
|
|
|
|
json = json_array();
|
|
|
|
json_array_append_new(json, json_array());
|
|
|
|
json_array_append_new(json_array_get(json, 0), json_array());
|
|
|
|
json_array_append(json_array_get(json_array_get(json, 0), 0),
|
|
|
|
json_array_get(json, 0));
|
|
|
|
|
2019-10-17 14:08:51 +08:00
|
|
|
if (json_dumps(json, 0))
|
2010-05-14 13:47:24 +08:00
|
|
|
fail("json_dumps encoded a circular reference!");
|
|
|
|
|
|
|
|
json_array_remove(json_array_get(json_array_get(json, 0), 0), 0);
|
|
|
|
|
|
|
|
result = json_dumps(json, 0);
|
2019-10-17 14:08:51 +08:00
|
|
|
if (!result || strcmp(result, "[[[]]]"))
|
2010-05-14 13:47:24 +08:00
|
|
|
fail("json_dumps failed!");
|
|
|
|
free(result);
|
|
|
|
|
|
|
|
json_decref(json);
|
2011-05-14 17:56:14 +08:00
|
|
|
}
|
|
|
|
|
2019-10-17 14:08:51 +08:00
|
|
|
static void encode_other_than_array_or_object() {
|
2011-05-14 17:56:14 +08:00
|
|
|
/* Encoding anything other than array or object should only
|
|
|
|
* succeed if the JSON_ENCODE_ANY flag is used */
|
|
|
|
|
|
|
|
json_t *json;
|
|
|
|
char *result;
|
|
|
|
|
|
|
|
json = json_string("foo");
|
2019-10-17 14:08:51 +08:00
|
|
|
if (json_dumps(json, 0) != NULL)
|
2011-05-14 17:56:14 +08:00
|
|
|
fail("json_dumps encoded a string!");
|
2019-10-17 14:08:51 +08:00
|
|
|
if (json_dumpf(json, NULL, 0) == 0)
|
2011-05-14 17:56:14 +08:00
|
|
|
fail("json_dumpf encoded a string!");
|
2019-10-17 14:08:51 +08:00
|
|
|
if (json_dumpfd(json, -1, 0) == 0)
|
2017-01-27 00:23:31 +08:00
|
|
|
fail("json_dumpfd encoded a string!");
|
2011-05-14 17:56:14 +08:00
|
|
|
|
|
|
|
result = json_dumps(json, JSON_ENCODE_ANY);
|
2019-10-17 14:08:51 +08:00
|
|
|
if (!result || strcmp(result, "\"foo\"") != 0)
|
2011-05-14 17:56:14 +08:00
|
|
|
fail("json_dumps failed to encode a string with JSON_ENCODE_ANY");
|
|
|
|
|
|
|
|
free(result);
|
|
|
|
json_decref(json);
|
|
|
|
|
|
|
|
json = json_integer(42);
|
2019-10-17 14:08:51 +08:00
|
|
|
if (json_dumps(json, 0) != NULL)
|
2011-05-14 17:56:14 +08:00
|
|
|
fail("json_dumps encoded an integer!");
|
2019-10-17 14:08:51 +08:00
|
|
|
if (json_dumpf(json, NULL, 0) == 0)
|
2011-05-14 17:56:14 +08:00
|
|
|
fail("json_dumpf encoded an integer!");
|
2019-10-17 14:08:51 +08:00
|
|
|
if (json_dumpfd(json, -1, 0) == 0)
|
2017-01-27 00:23:31 +08:00
|
|
|
fail("json_dumpfd encoded an integer!");
|
2011-05-14 17:56:14 +08:00
|
|
|
|
|
|
|
result = json_dumps(json, JSON_ENCODE_ANY);
|
2019-10-17 14:08:51 +08:00
|
|
|
if (!result || strcmp(result, "42") != 0)
|
2011-05-14 17:56:14 +08:00
|
|
|
fail("json_dumps failed to encode an integer with JSON_ENCODE_ANY");
|
|
|
|
|
|
|
|
free(result);
|
|
|
|
json_decref(json);
|
|
|
|
}
|
|
|
|
|
2019-10-17 14:08:51 +08:00
|
|
|
static void escape_slashes() {
|
2012-06-29 10:04:36 +08:00
|
|
|
/* Test dump escaping slashes */
|
|
|
|
|
|
|
|
json_t *json;
|
|
|
|
char *result;
|
|
|
|
|
|
|
|
json = json_object();
|
2019-10-20 01:35:28 +08:00
|
|
|
json_object_set_new(json, "url", json_string("https://github.com/akheron/jansson"));
|
2012-06-29 10:04:36 +08:00
|
|
|
|
|
|
|
result = json_dumps(json, 0);
|
2019-10-20 01:35:28 +08:00
|
|
|
if (!result || strcmp(result, "{\"url\": \"https://github.com/akheron/jansson\"}"))
|
2012-06-29 10:04:36 +08:00
|
|
|
fail("json_dumps failed to not escape slashes");
|
|
|
|
|
|
|
|
free(result);
|
|
|
|
|
|
|
|
result = json_dumps(json, JSON_ESCAPE_SLASH);
|
2019-10-17 14:08:51 +08:00
|
|
|
if (!result ||
|
2019-10-20 01:35:28 +08:00
|
|
|
strcmp(result, "{\"url\": \"https:\\/\\/github.com\\/akheron\\/jansson\"}"))
|
2012-06-29 10:04:36 +08:00
|
|
|
fail("json_dumps failed to escape slashes");
|
|
|
|
|
|
|
|
free(result);
|
|
|
|
json_decref(json);
|
|
|
|
}
|
|
|
|
|
2019-10-17 14:08:51 +08:00
|
|
|
static void encode_nul_byte() {
|
2013-09-30 15:44:35 +08:00
|
|
|
json_t *json;
|
|
|
|
char *result;
|
|
|
|
|
|
|
|
json = json_stringn("nul byte \0 in string", 20);
|
|
|
|
result = json_dumps(json, JSON_ENCODE_ANY);
|
2019-10-17 14:08:51 +08:00
|
|
|
if (!result || memcmp(result, "\"nul byte \\u0000 in string\"", 27))
|
2013-09-30 15:44:35 +08:00
|
|
|
fail("json_dumps failed to dump an embedded NUL byte");
|
|
|
|
|
|
|
|
free(result);
|
|
|
|
json_decref(json);
|
|
|
|
}
|
|
|
|
|
2019-10-17 14:08:51 +08:00
|
|
|
static void dump_file() {
|
2014-12-19 14:35:31 +08:00
|
|
|
json_t *json;
|
|
|
|
int result;
|
|
|
|
|
|
|
|
result = json_dump_file(NULL, "", 0);
|
|
|
|
if (result != -1)
|
|
|
|
fail("json_dump_file succeeded with invalid args");
|
|
|
|
|
|
|
|
json = json_object();
|
|
|
|
result = json_dump_file(json, "json_dump_file.json", 0);
|
|
|
|
if (result != 0)
|
|
|
|
fail("json_dump_file failed");
|
|
|
|
|
|
|
|
json_decref(json);
|
|
|
|
remove("json_dump_file.json");
|
|
|
|
}
|
|
|
|
|
2019-10-17 14:08:51 +08:00
|
|
|
static void dumpb() {
|
2017-01-26 16:46:48 +08:00
|
|
|
char buf[2];
|
|
|
|
json_t *obj;
|
|
|
|
size_t size;
|
|
|
|
|
|
|
|
obj = json_object();
|
|
|
|
|
|
|
|
size = json_dumpb(obj, buf, sizeof(buf), 0);
|
2019-10-17 14:08:51 +08:00
|
|
|
if (size != 2 || strncmp(buf, "{}", 2))
|
|
|
|
fail("json_dumpb failed");
|
2017-01-26 16:46:48 +08:00
|
|
|
|
|
|
|
json_decref(obj);
|
|
|
|
obj = json_pack("{s:s}", "foo", "bar");
|
|
|
|
|
|
|
|
size = json_dumpb(obj, buf, sizeof(buf), JSON_COMPACT);
|
2019-10-17 14:08:51 +08:00
|
|
|
if (size != 13)
|
|
|
|
fail("json_dumpb size check failed");
|
2017-01-26 16:46:48 +08:00
|
|
|
|
|
|
|
json_decref(obj);
|
|
|
|
}
|
|
|
|
|
2019-10-17 14:08:51 +08:00
|
|
|
static void dumpfd() {
|
2017-01-27 00:23:31 +08:00
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
int fds[2] = {-1, -1};
|
|
|
|
json_t *a, *b;
|
|
|
|
|
2019-10-17 14:08:51 +08:00
|
|
|
if (pipe(fds))
|
2017-01-27 00:23:31 +08:00
|
|
|
fail("pipe() failed");
|
|
|
|
|
|
|
|
a = json_pack("{s:s}", "foo", "bar");
|
|
|
|
|
2019-10-17 14:08:51 +08:00
|
|
|
if (json_dumpfd(a, fds[1], 0))
|
2017-01-27 00:23:31 +08:00
|
|
|
fail("json_dumpfd() failed");
|
|
|
|
close(fds[1]);
|
|
|
|
|
|
|
|
b = json_loadfd(fds[0], 0, NULL);
|
|
|
|
if (!b)
|
|
|
|
fail("json_loadfd() failed");
|
|
|
|
close(fds[0]);
|
|
|
|
|
|
|
|
if (!json_equal(a, b))
|
|
|
|
fail("json_equal() failed for fd test");
|
|
|
|
|
|
|
|
json_decref(a);
|
|
|
|
json_decref(b);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-10-17 14:08:51 +08:00
|
|
|
static void embed() {
|
2019-10-20 01:35:28 +08:00
|
|
|
static const char *plains[] = {"{\"bar\":[],\"foo\":{}}", "[[],{}]", "{}", "[]",
|
|
|
|
NULL};
|
2017-02-28 03:56:55 +08:00
|
|
|
|
|
|
|
size_t i;
|
|
|
|
|
2019-10-17 14:08:51 +08:00
|
|
|
for (i = 0; plains[i]; i++) {
|
2017-02-28 03:56:55 +08:00
|
|
|
const char *plain = plains[i];
|
|
|
|
json_t *parse = NULL;
|
|
|
|
char *embed = NULL;
|
|
|
|
size_t psize = 0;
|
|
|
|
size_t esize = 0;
|
|
|
|
|
|
|
|
psize = strlen(plain) - 2;
|
|
|
|
embed = calloc(1, psize);
|
|
|
|
parse = json_loads(plain, 0, NULL);
|
2019-10-20 01:35:28 +08:00
|
|
|
esize =
|
|
|
|
json_dumpb(parse, embed, psize, JSON_COMPACT | JSON_SORT_KEYS | JSON_EMBED);
|
2017-02-28 03:56:55 +08:00
|
|
|
json_decref(parse);
|
2019-10-17 14:08:51 +08:00
|
|
|
if (esize != psize)
|
2017-02-28 03:56:55 +08:00
|
|
|
fail("json_dumpb(JSON_EMBED) returned an invalid size");
|
2019-10-17 14:08:51 +08:00
|
|
|
if (strncmp(plain + 1, embed, esize) != 0)
|
2017-02-28 03:56:55 +08:00
|
|
|
fail("json_dumps(JSON_EMBED) returned an invalid value");
|
|
|
|
free(embed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-17 14:08:51 +08:00
|
|
|
static void run_tests() {
|
2013-04-15 13:42:23 +08:00
|
|
|
encode_null();
|
2011-05-14 17:56:14 +08:00
|
|
|
encode_twice();
|
|
|
|
circular_references();
|
|
|
|
encode_other_than_array_or_object();
|
2012-06-29 10:04:36 +08:00
|
|
|
escape_slashes();
|
2013-09-30 15:44:35 +08:00
|
|
|
encode_nul_byte();
|
2014-12-19 14:35:31 +08:00
|
|
|
dump_file();
|
2017-01-26 16:46:48 +08:00
|
|
|
dumpb();
|
2017-01-27 00:23:31 +08:00
|
|
|
dumpfd();
|
2017-02-28 03:56:55 +08:00
|
|
|
embed();
|
2010-05-12 20:41:09 +08:00
|
|
|
}
|