Merge branch 'issue-29'
Fixes GH-29.
This commit is contained in:
@@ -765,6 +765,26 @@ is in UTF-8.
|
||||
*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:
|
||||
|
||||
|
||||
22
src/dump.c
22
src/dump.c
@@ -19,8 +19,6 @@
|
||||
#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;
|
||||
@@ -28,12 +26,12 @@ struct string
|
||||
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)
|
||||
@@ -44,7 +42,7 @@ static int dump_to_file(const char *buffer, int size, void *data)
|
||||
/* 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)
|
||||
{
|
||||
@@ -66,7 +64,7 @@ static int dump_indent(size_t flags, int depth, int space, dump_func dump, void
|
||||
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;
|
||||
@@ -166,7 +164,7 @@ static int object_key_compare_serials(const void *key1, const void *key2)
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -463,3 +461,13 @@ int json_dump_file(const json_t *json, const char *path, size_t flags)
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -234,10 +234,12 @@ json_t *json_load_file(const char *path, size_t flags, json_error_t *error);
|
||||
#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 */
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#define STRBUFFER_MIN_SIZE 16
|
||||
#define STRBUFFER_FACTOR 2
|
||||
#define STRBUFFER_SIZE_MAX ((size_t)-1)
|
||||
|
||||
int strbuffer_init(strbuffer_t *strbuff)
|
||||
{
|
||||
@@ -64,13 +65,19 @@ 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, 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);
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
|
||||
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);
|
||||
@@ -24,7 +24,7 @@ char *strbuffer_steal_value(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);
|
||||
|
||||
|
||||
1
test/.gitignore
vendored
1
test/.gitignore
vendored
@@ -4,6 +4,7 @@ suites/api/test_array
|
||||
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
|
||||
|
||||
@@ -4,6 +4,7 @@ check_PROGRAMS = \
|
||||
test_array \
|
||||
test_copy \
|
||||
test_dump \
|
||||
test_dump_callback \
|
||||
test_equal \
|
||||
test_load \
|
||||
test_loadb \
|
||||
@@ -17,6 +18,7 @@ check_PROGRAMS = \
|
||||
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
|
||||
|
||||
@@ -47,6 +47,7 @@ json_object_iter_set_new
|
||||
json_dumps
|
||||
json_dumpf
|
||||
json_dump_file
|
||||
json_dump_callback
|
||||
json_loads
|
||||
json_loadf
|
||||
json_load_file
|
||||
|
||||
83
test/suites/api/test_dump_callback.c
Normal file
83
test/suites/api/test_dump_callback.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user