aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPetri Lehtinen <petri@digip.org>2017-01-31 08:45:40 +0200
committerGitHub <noreply@github.com>2017-01-31 08:45:40 +0200
commit3c51112063a09151390e93916a4637a7e0427b32 (patch)
tree97ea7f5edc6348c3b669985ccfbbca13a4cc6a38
parent746c2c3a996a7f6e80bd19fe3de438637e6363e1 (diff)
parent1672bb5a65b711d84c8adb12144bb997a4da02d4 (diff)
downloadjansson-3c51112063a09151390e93916a4637a7e0427b32.zip
jansson-3c51112063a09151390e93916a4637a7e0427b32.tar.gz
jansson-3c51112063a09151390e93916a4637a7e0427b32.tar.bz2
Merge pull request #328 from npmccallum/master
Helper functions for network IO
-rw-r--r--doc/apiref.rst70
-rw-r--r--src/dump.c48
-rw-r--r--src/jansson.def3
-rw-r--r--src/jansson.h3
-rw-r--r--src/jansson_private.h1
-rw-r--r--src/load.c45
-rw-r--r--test/suites/api/test_dump.c74
-rw-r--r--test/suites/api/test_load.c6
8 files changed, 243 insertions, 7 deletions
diff --git a/doc/apiref.rst b/doc/apiref.rst
index ca38bbf..f104ad5 100644
--- a/doc/apiref.rst
+++ b/doc/apiref.rst
@@ -948,6 +948,28 @@ These functions output UTF-8:
error. *flags* is described above. The return value must be freed
by the caller using :func:`free()`.
+.. function:: size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags)
+
+ Writes the JSON representation of *json* to the *buffer* of
+ *size* bytes. Returns the number of bytes that would be written
+ or 0 on error. *flags* is described above. *buffer* is not
+ null-terminated.
+
+ This function never writes more than *size* bytes. If the return
+ value is greater than *size*, the contents of the *buffer* are
+ undefined. This behavior enables you to specify a NULL *buffer*
+ to determine the length of the encoding. For example::
+
+ size_t size = json_dumpb(json, NULL, 0, 0);
+ if (size == 0)
+ return -1;
+
+ char *buf = alloca(size);
+
+ size = json_dumpb(json, buf, size, 0);
+
+ .. versionadded:: 2.10
+
.. function:: int json_dumpf(const json_t *json, FILE *output, size_t flags)
Write the JSON representation of *json* to the stream *output*.
@@ -956,6 +978,23 @@ These functions output UTF-8:
*output*. In this case, the output is undefined and most likely not
valid JSON.
+.. function:: int json_dumpfd(const json_t *json, int output, size_t flags)
+
+ Write the JSON representation of *json* to the stream *output*.
+ *flags* is described above. Returns 0 on success and -1 on error.
+ If an error occurs, something may have already been written to
+ *output*. In this case, the output is undefined and most likely not
+ valid JSON.
+
+ It is important to note that this function can only succeed on stream
+ file descriptors (such as SOCK_STREAM). Using this function on a
+ non-stream file descriptor will result in undefined behavior. For
+ non-stream file descriptors, see instead :func:`json_dumpb()`.
+
+ This function requires POSIX and fails on all non-POSIX systems.
+
+ .. versionadded:: 2.10
+
.. function:: int json_dump_file(const json_t *json, const char *path, size_t flags)
Write the JSON representation of *json* to the file *path*. If
@@ -1111,7 +1150,7 @@ If no error or position information is needed, you can pass *NULL*.
above.
This function will start reading the input from whatever position
- the input file was, without attempting to seek first. If an error
+ the input file was in, without attempting to seek first. If an error
occurs, the file position will be left indeterminate. On success,
the file position will be at EOF, unless ``JSON_DISABLE_EOF_CHECK``
flag was used. In this case, the file position will be at the first
@@ -1120,6 +1159,35 @@ If no error or position information is needed, you can pass *NULL*.
multiple times, if the input consists of consecutive JSON texts,
possibly separated by whitespace.
+.. function:: json_t *json_loadfd(int input, size_t flags, json_error_t *error)
+
+ .. refcounting:: new
+
+ Decodes the JSON text in stream *input* and returns the array or
+ object it contains, or *NULL* on error, in which case *error* is
+ filled with information about the error. *flags* is described
+ above.
+
+ This function will start reading the input from whatever position
+ the input file descriptor was in, without attempting to seek first.
+ If an error occurs, the file position will be left indeterminate.
+ On success, the file position will be at EOF, unless
+ ``JSON_DISABLE_EOF_CHECK`` flag was used. In this case, the file
+ descriptor's position will be at the first character after the last
+ ``]`` or ``}`` in the JSON input. This allows calling
+ :func:`json_loadfd()` on the same file descriptor multiple times,
+ if the input consists of consecutive JSON texts, possibly separated
+ by whitespace.
+
+ It is important to note that this function can only succeed on stream
+ file descriptors (such as SOCK_STREAM). Using this function on a
+ non-stream file descriptor will result in undefined behavior. For
+ non-stream file descriptors, see instead :func:`json_loadb()`.
+
+ This function requires POSIX and fails on all non-POSIX systems.
+
+ .. versionadded:: 2.10
+
.. function:: json_t *json_load_file(const char *path, size_t flags, json_error_t *error)
.. refcounting:: new
diff --git a/src/dump.c b/src/dump.c
index 6b1aabd..cac2790 100644
--- a/src/dump.c
+++ b/src/dump.c
@@ -9,13 +9,17 @@
#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 "jansson_private.h"
#include "strbuffer.h"
#include "utf.h"
@@ -25,11 +29,28 @@
#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;
@@ -38,6 +59,16 @@ static int dump_to_file(const char *buffer, size_t size, void *data)
return 0;
}
+static int dump_to_fd(const char *buffer, size_t size, void *data)
+{
+ int *dest = (int *)data;
+#ifdef HAVE_UNISTD_H
+ if(write(*dest, buffer, size) == (ssize_t)size)
+ return 0;
+#endif
+ return -1;
+}
+
/* 32 spaces (the maximum indentation size) */
static const char whitespace[] = " ";
@@ -416,11 +447,26 @@ char *json_dumps(const json_t *json, size_t flags)
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;
diff --git a/src/jansson.def b/src/jansson.def
index c43eb07..cbebefb 100644
--- a/src/jansson.def
+++ b/src/jansson.def
@@ -48,12 +48,15 @@ EXPORTS
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
diff --git a/src/jansson.h b/src/jansson.h
index 591f2a9..b5a4d15 100644
--- a/src/jansson.h
+++ b/src/jansson.h
@@ -273,6 +273,7 @@ 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);
@@ -292,7 +293,9 @@ json_t *json_load_callback(json_load_callback_t callback, void *data, size_t fla
typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data);
char *json_dumps(const json_t *json, size_t flags);
+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);
diff --git a/src/jansson_private.h b/src/jansson_private.h
index 4a4927b..5ed9615 100644
--- a/src/jansson_private.h
+++ b/src/jansson_private.h
@@ -8,6 +8,7 @@
#ifndef JANSSON_PRIVATE_H
#define JANSSON_PRIVATE_H
+#include "jansson_private_config.h"
#include <stddef.h>
#include "jansson.h"
#include "hashtable.h"
diff --git a/src/load.c b/src/load.c
index 7a50743..c212489 100644
--- a/src/load.c
+++ b/src/load.c
@@ -9,15 +9,19 @@
#define _GNU_SOURCE
#endif
+#include "jansson_private.h"
+
#include <errno.h>
#include <limits.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 "jansson_private.h"
#include "strbuffer.h"
#include "utf.h"
@@ -1028,6 +1032,45 @@ json_t *json_loadf(FILE *input, size_t flags, json_error_t *error)
return result;
}
+static int fd_get_func(int *fd)
+{
+ uint8_t c;
+#ifdef HAVE_UNISTD_H
+ if (read(*fd, &c, 1) == 1)
+ return c;
+#endif
+ return EOF;
+}
+
+json_t *json_loadfd(int input, size_t flags, json_error_t *error)
+{
+ lex_t lex;
+ const char *source;
+ json_t *result;
+
+#ifdef HAVE_UNISTD_H
+ if(input == STDIN_FILENO)
+ source = "<stdin>";
+ else
+#endif
+ source = "<stream>";
+
+ jsonp_error_init(error, source);
+
+ if (input < 0) {
+ error_set(error, NULL, "wrong arguments");
+ return NULL;
+ }
+
+ if(lex_init(&lex, (get_func)fd_get_func, flags, &input))
+ return NULL;
+
+ result = parse_json(&lex, flags, error);
+
+ lex_close(&lex);
+ return result;
+}
+
json_t *json_load_file(const char *path, size_t flags, json_error_t *error)
{
json_t *result;
diff --git a/test/suites/api/test_dump.c b/test/suites/api/test_dump.c
index 3591fa5..8d59d40 100644
--- a/test/suites/api/test_dump.c
+++ b/test/suites/api/test_dump.c
@@ -5,8 +5,13 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
+#include "jansson_private_config.h"
+
#include <jansson.h>
#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
#include "util.h"
static int encode_null_callback(const char *buffer, size_t size, void *data)
@@ -22,9 +27,17 @@ static void encode_null()
if(json_dumps(NULL, JSON_ENCODE_ANY) != NULL)
fail("json_dumps didn't fail for NULL");
+ if(json_dumpb(NULL, NULL, 0, JSON_ENCODE_ANY) != 0)
+ fail("json_dumps didn't fail for NULL");
+
if(json_dumpf(NULL, stderr, JSON_ENCODE_ANY) != -1)
fail("json_dumpf didn't fail for NULL");
+#ifdef HAVE_UNISTD_H
+ if(json_dumpfd(NULL, STDERR_FILENO, JSON_ENCODE_ANY) != -1)
+ fail("json_dumpfd didn't fail for NULL");
+#endif
+
/* Don't test json_dump_file to avoid creating a file */
if(json_dump_callback(NULL, encode_null_callback, NULL, JSON_ENCODE_ANY) != -1)
@@ -124,14 +137,15 @@ static void encode_other_than_array_or_object()
* succeed if the JSON_ENCODE_ANY flag is used */
json_t *json;
- FILE *fp = NULL;
char *result;
json = json_string("foo");
if(json_dumps(json, 0) != NULL)
fail("json_dumps encoded a string!");
- if(json_dumpf(json, fp, 0) == 0)
+ if(json_dumpf(json, NULL, 0) == 0)
fail("json_dumpf encoded a string!");
+ if(json_dumpfd(json, -1, 0) == 0)
+ fail("json_dumpfd encoded a string!");
result = json_dumps(json, JSON_ENCODE_ANY);
if(!result || strcmp(result, "\"foo\"") != 0)
@@ -143,8 +157,10 @@ static void encode_other_than_array_or_object()
json = json_integer(42);
if(json_dumps(json, 0) != NULL)
fail("json_dumps encoded an integer!");
- if(json_dumpf(json, fp, 0) == 0)
+ if(json_dumpf(json, NULL, 0) == 0)
fail("json_dumpf encoded an integer!");
+ if(json_dumpfd(json, -1, 0) == 0)
+ fail("json_dumpfd encoded an integer!");
result = json_dumps(json, JSON_ENCODE_ANY);
if(!result || strcmp(result, "42") != 0)
@@ -212,6 +228,56 @@ static void dump_file()
remove("json_dump_file.json");
}
+static void dumpb()
+{
+ char buf[2];
+ json_t *obj;
+ size_t size;
+
+ obj = json_object();
+
+ size = json_dumpb(obj, buf, sizeof(buf), 0);
+ if(size != 2 || strncmp(buf, "{}", 2))
+ fail("json_dumpb failed");
+
+ json_decref(obj);
+ obj = json_pack("{s:s}", "foo", "bar");
+
+ size = json_dumpb(obj, buf, sizeof(buf), JSON_COMPACT);
+ if(size != 13)
+ fail("json_dumpb size check failed");
+
+ json_decref(obj);
+}
+
+static void dumpfd()
+{
+#ifdef HAVE_UNISTD_H
+ int fds[2] = {-1, -1};
+ json_t *a, *b;
+
+ if(pipe(fds))
+ fail("pipe() failed");
+
+ a = json_pack("{s:s}", "foo", "bar");
+
+ if(json_dumpfd(a, fds[1], 0))
+ 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
+}
+
static void run_tests()
{
encode_null();
@@ -221,4 +287,6 @@ static void run_tests()
escape_slashes();
encode_nul_byte();
dump_file();
+ dumpb();
+ dumpfd();
}
diff --git a/test/suites/api/test_load.c b/test/suites/api/test_load.c
index 9b9f5f4..3416af1 100644
--- a/test/suites/api/test_load.c
+++ b/test/suites/api/test_load.c
@@ -180,9 +180,13 @@ static void load_wrong_args()
if (json)
fail("json_loadf should return NULL if the first argument is NULL");
+ json = json_loadfd(-1, 0, &error);
+ if (json)
+ fail("json_loadfd should return NULL if the first argument is < 0");
+
json = json_load_file(NULL, 0, &error);
if (json)
- fail("json_loadf should return NULL if the first argument is NULL");
+ fail("json_load_file should return NULL if the first argument is NULL");
}
static void position()