Fixes GH-29.
*path* already exists, it is overwritten. *flags* is described
above. Returns 0 on success and -1 on error.
+.. type:: json_dump_callback_t
+
+ A typedef for a function that's called by
+ :func:`json_dump_callback()`::
+
+ typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data);
+
+ *buffer* points to a buffer containing a chunk of output, *size* is
+ the length of the buffer, and *data* is the corresponding
+ :func:`json_dump_callback()` argument passed through.
+
+ On error, the function should return -1 to stop the encoding
+ process. On success, it should return 0.
+
+.. function:: int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags)
+
+ Call *callback* repeatedly, passing a chunk of the JSON
+ representation of *root* each time. *flags* is described above.
+ Returns 0 on success and -1 on error.
+
.. _apiref-decoding:
#define MAX_INTEGER_STR_LENGTH 100
#define MAX_REAL_STR_LENGTH 100
-typedef int (*dump_func)(const char *buffer, int size, void *data);
-
struct string
{
char *buffer;
int size;
};
-static int dump_to_strbuffer(const char *buffer, int size, void *data)
+static int dump_to_strbuffer(const char *buffer, size_t size, void *data)
{
return strbuffer_append_bytes((strbuffer_t *)data, buffer, size);
}
-static int dump_to_file(const char *buffer, int size, void *data)
+static int dump_to_file(const char *buffer, size_t size, void *data)
{
FILE *dest = (FILE *)data;
if(fwrite(buffer, size, 1, dest) != 1)
/* 32 spaces (the maximum indentation size) */
static char whitespace[] = " ";
-static int dump_indent(size_t flags, int depth, int space, dump_func dump, void *data)
+static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump, void *data)
{
if(JSON_INDENT(flags) > 0)
{
return 0;
}
-static int dump_string(const char *str, int ascii, dump_func dump, void *data)
+static int dump_string(const char *str, int ascii, json_dump_callback_t dump, void *data)
{
const char *pos, *end;
int32_t codepoint;
}
static int do_dump(const json_t *json, size_t flags, int depth,
- dump_func dump, void *data)
+ json_dump_callback_t dump, void *data)
{
int ascii = flags & JSON_ENSURE_ASCII ? 1 : 0;
fclose(output);
return result;
}
+
+int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags)
+{
+ if(!(flags & JSON_ENCODE_ANY)) {
+ if(!json_is_array(json) && !json_is_object(json))
+ return -1;
+ }
+
+ return do_dump(json, flags, 0, callback, data);
+}
#define JSON_PRESERVE_ORDER 0x100
#define JSON_ENCODE_ANY 0x200
+typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data);
+
char *json_dumps(const json_t *json, size_t flags);
int json_dumpf(const json_t *json, FILE *output, size_t flags);
int json_dump_file(const json_t *json, const char *path, size_t flags);
-
+int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags);
/* custom memory allocation */
#define STRBUFFER_MIN_SIZE 16
#define STRBUFFER_FACTOR 2
+#define STRBUFFER_SIZE_MAX ((size_t)-1)
int strbuffer_init(strbuffer_t *strbuff)
{
return strbuffer_append_bytes(strbuff, &byte, 1);
}
-int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, int size)
+int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size)
{
- if(strbuff->length + size >= strbuff->size)
+ if(size >= strbuff->size - strbuff->length)
{
size_t new_size;
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);
typedef struct {
char *value;
- int length; /* bytes used */
- int size; /* bytes allocated */
+ size_t length; /* bytes used */
+ size_t size; /* bytes allocated */
} strbuffer_t;
int strbuffer_init(strbuffer_t *strbuff);
int strbuffer_append(strbuffer_t *strbuff, const char *string);
int strbuffer_append_byte(strbuffer_t *strbuff, char byte);
-int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, int size);
+int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size);
char strbuffer_pop(strbuffer_t *strbuff);
suites/api/test_copy
suites/api/test_cpp
suites/api/test_dump
+suites/api/test_dump_callback
suites/api/test_equal
suites/api/test_load
suites/api/test_loadb
test_array \
test_copy \
test_dump \
+ test_dump_callback \
test_equal \
test_load \
test_loadb \
test_array_SOURCES = test_array.c util.h
test_copy_SOURCES = test_copy.c util.h
test_dump_SOURCES = test_dump.c util.h
+test_dump_callback_SOURCES = test_dump_callback.c util.h
test_load_SOURCES = test_load.c util.h
test_loadb_SOURCES = test_loadb.c util.h
test_memory_funcs_SOURCES = test_memory_funcs.c util.h
json_dumps
json_dumpf
json_dump_file
+json_dump_callback
json_loads
json_loadf
json_load_file
--- /dev/null
+/*
+ * Copyright (c) 2009-2011 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 <jansson.h>
+#include <string.h>
+#include <stdlib.h>
+#include "util.h"
+
+struct my_sink {
+ char *buf;
+ size_t off;
+ size_t cap;
+};
+
+static int my_writer(const char *buffer, size_t len, void *data) {
+ struct my_sink *s = data;
+ if (len > s->cap - s->off) {
+ return -1;
+ }
+ memcpy(s->buf + s->off, buffer, len);
+ s->off += len;
+ return 0;
+}
+
+int main(void)
+{
+ struct my_sink s;
+ json_t *json;
+ const char str[] = "[\"A\", {\"B\": \"C\", \"e\": false}, 1, null, \"foo\"]";
+ char *dumped_to_string;
+
+ json = json_loads(str, 0, NULL);
+ if(!json) {
+ fail("json_loads failed");
+ }
+
+ dumped_to_string = json_dumps(json, 0);
+ if (!dumped_to_string) {
+ json_decref(json);
+ fail("json_dumps failed");
+ }
+
+ s.off = 0;
+ s.cap = strlen(dumped_to_string);
+ s.buf = malloc(s.cap);
+ if (!s.buf) {
+ json_decref(json);
+ free(dumped_to_string);
+ fail("malloc failed");
+ }
+
+ if (json_dump_callback(json, my_writer, &s, 0) == -1) {
+ json_decref(json);
+ free(dumped_to_string);
+ free(s.buf);
+ fail("json_dump_callback failed on an exact-length sink buffer");
+ }
+
+ if (strncmp(dumped_to_string, s.buf, s.off) != 0) {
+ json_decref(json);
+ free(dumped_to_string);
+ free(s.buf);
+ fail("json_dump_callback and json_dumps did not produce identical output");
+ }
+
+ s.off = 1;
+ if (json_dump_callback(json, my_writer, &s, 0) != -1) {
+ json_decref(json);
+ free(dumped_to_string);
+ free(s.buf);
+ fail("json_dump_callback succeeded on a short buffer when it should have failed");
+ }
+
+ json_decref(json);
+ free(dumped_to_string);
+ free(s.buf);
+ return EXIT_SUCCESS;
+}
+