]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-json: json-ostream - Add support for writing a JSON string from an input stream
authorStephan Bosch <stephan.bosch@open-xchange.com>
Wed, 7 Aug 2019 22:36:17 +0000 (00:36 +0200)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Sat, 18 Nov 2023 18:58:04 +0000 (18:58 +0000)
src/lib-json/json-ostream.c
src/lib-json/json-ostream.h
src/lib-json/test-json-ostream.c

index 89c8193e174b567f16eaf2bae5e245e8ceedfd3a..587185b3eb877050587547dd91c06e723373b827 100644 (file)
@@ -3,6 +3,7 @@
 #include "lib.h"
 #include "str.h"
 #include "array.h"
+#include "istream.h"
 #include "ostream.h"
 
 #include "json-ostream.h"
@@ -635,6 +636,33 @@ void json_ostream_nwritef_string(struct json_ostream *stream,
        va_end(args);
 }
 
+int json_ostream_write_string_stream(struct json_ostream *stream,
+                                    const char *name, struct istream *input)
+{
+       struct json_value jvalue;
+
+       i_zero(&jvalue);
+       jvalue.content_type = JSON_CONTENT_TYPE_STREAM;
+       jvalue.content.stream = input;
+
+       return json_ostream_write_value(stream, name, JSON_TYPE_STRING,
+                                       &jvalue);
+}
+
+void json_ostream_nwrite_string_stream(struct json_ostream *stream,
+                                      const char *name, struct istream *input)
+{
+       struct json_value jvalue;
+
+       i_zero(&jvalue);
+       jvalue.content_type = JSON_CONTENT_TYPE_STREAM;
+       jvalue.content.stream = input;
+
+       json_ostream_nwrite_value(stream, name, JSON_TYPE_STRING, &jvalue);
+       if (input->stream_errno != 0)
+               stream->nfailed = TRUE;
+}
+
 int json_ostream_open_string(struct json_ostream *stream, const char *name)
 {
        int ret;
index de917af508213121d07445caac3e5214bbcc2b62..f2867fe406b8ee9bff1a76403ca05cf935f3d46c 100644 (file)
@@ -169,6 +169,12 @@ void json_ostream_nwrite_string(struct json_ostream *stream,
 void json_ostream_nwritef_string(struct json_ostream *stream,
                                 const char *name,
                                 const char *format, ...) ATTR_FORMAT(3, 4);
+/* Try to write the stream to the output stream as a string. Returns 1
+   if buffered, 0 if not, -1 if error. */
+int json_ostream_write_string_stream(struct json_ostream *stream,
+                                    const char *name, struct istream *input);
+void json_ostream_nwrite_string_stream(struct json_ostream *stream,
+                                       const char *name, struct istream *input);
 
 /* Open a string on the stream, which means that all subsequent string
    write functions are concatenated into a single JSON string value. Note that
index 0fed58408a001ca512e2f9a38917b3fa1490a534..8df070396aa8b55e155ff6c8e7e38ab34cd5b6c8 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "lib.h"
 #include "str.h"
+#include "istream.h"
 #include "ostream.h"
 #include "test-common.h"
 
@@ -14,8 +15,10 @@ static bool debug = FALSE;
 static void test_json_ostream_write(void)
 {
        string_t *buffer;
+       struct istream *input;
        struct ostream *output;
        struct json_ostream *joutput;
+       const char *data;
        unsigned int state, pos;
        int ret;
 
@@ -88,6 +91,24 @@ static void test_json_ostream_write(void)
        str_truncate(buffer, 0);
        output->offset = 0;
 
+       /* string stream */
+       test_begin("json ostream write - string stream");
+       joutput = json_ostream_create(output, 0);
+       data = "AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ";
+       input = i_stream_create_from_data(data, strlen(data));
+       ret = json_ostream_write_string_stream(joutput, NULL, input);
+       i_assert(ret > 0);
+       i_stream_unref(&input);
+       ret = json_ostream_flush(joutput);
+       i_assert(ret > 0);
+       json_ostream_unref(&joutput);
+       test_assert_strcmp(
+               "\"AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ\"",
+               str_c(buffer));
+       test_end();
+       str_truncate(buffer, 0);
+       output->offset = 0;
+
        /* <JSON-text> */
        test_begin("json ostream write - <JSON-text>");
        joutput = json_ostream_create(output, 0);
@@ -133,6 +154,28 @@ static void test_json_ostream_write(void)
        str_truncate(buffer, 0);
        output->offset = 0;
 
+       /* [ string string stream ] */
+       test_begin("json ostream write - array [ string stream ]");
+       joutput = json_ostream_create(output, 0);
+       ret = json_ostream_descend_array(joutput, NULL);
+       i_assert(ret > 0);
+       data = "AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ";
+       input = i_stream_create_from_data(data, strlen(data));
+       ret = json_ostream_write_string_stream(joutput, NULL, input);
+       i_assert(ret > 0);
+       i_stream_unref(&input);
+       ret = json_ostream_ascend_array(joutput);
+       i_assert(ret > 0);
+       ret = json_ostream_flush(joutput);
+       i_assert(ret > 0);
+       json_ostream_unref(&joutput);
+       test_assert_strcmp(
+               "[\"AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ\"]",
+               str_c(buffer));
+       test_end();
+       str_truncate(buffer, 0);
+       output->offset = 0;
+
        /* [ <JSON-text> ] */
        test_begin("json ostream write - array [ <JSON-text> ]");
        joutput = json_ostream_create(output, 0);
@@ -201,6 +244,29 @@ static void test_json_ostream_write(void)
        str_truncate(buffer, 0);
        output->offset = 0;
 
+       /* { "frop": string stream } */
+       test_begin("json ostream write - object { \"frop\": string stream }");
+       joutput = json_ostream_create(output, 0);
+       ret = json_ostream_descend_object(joutput, NULL);
+       i_assert(ret > 0);
+       data = "AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ";
+       input = i_stream_create_from_data(data, strlen(data));
+       ret = json_ostream_write_string_stream(joutput, "frop", input);
+       i_assert(ret > 0);
+       i_stream_unref(&input);
+       ret = json_ostream_ascend_object(joutput);
+       i_assert(ret > 0);
+       ret = json_ostream_flush(joutput);
+       i_assert(ret > 0);
+       json_ostream_unref(&joutput);
+       test_assert_strcmp(
+               "{\"frop\":"
+               "\"AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ\"}",
+               str_c(buffer));
+       test_end();
+       str_truncate(buffer, 0);
+       output->offset = 0;
+
        /* { "a": [{"d": 1}], "b": [{"e": 2}], "c": [{"f": 3}] } */
        test_begin("json ostream write - "
                   "object { \"a\": [{\"d\": 1}], \"b\": [{\"e\": 2}], "
@@ -694,6 +760,156 @@ static void test_json_ostream_write(void)
        str_truncate(buffer, 0);
        output->offset = 0;
 
+       /* trickle[4] */
+       test_begin("json ostream write - object, trickle[4]");
+       o_stream_set_max_buffer_size(output, 0);
+       joutput = json_ostream_create(output, 0);
+       state = 0;
+       for (pos = 0; pos < 400 && state <= 16; pos++) {
+               o_stream_set_max_buffer_size(output, pos);
+               switch (state) {
+               case 0:
+                       ret = json_ostream_descend_object(joutput, NULL);
+                       i_assert(ret >= 0);
+                       if (ret == 0)
+                               break;
+                       state++;
+                       continue;
+               case 1:
+                       ret = json_ostream_descend_array(joutput, "aaaaaa");
+                       i_assert(ret >= 0);
+                       if (ret == 0)
+                               break;
+                       state++;
+                       continue;
+               case 2:
+                       ret = json_ostream_descend_object(joutput, NULL);
+                       i_assert(ret >= 0);
+                       if (ret == 0)
+                               break;
+                       data = "AAAAA";
+                       input = i_stream_create_from_data(data, strlen(data));
+                       state++;
+                       continue;
+               case 3:
+                       ret = json_ostream_write_string_stream(
+                               joutput, "dddddd", input);
+                       i_assert(ret >= 0);
+                       if (ret == 0)
+                               break;
+                       i_stream_unref(&input);
+                       state++;
+                       continue;
+               case 4:
+                       ret = json_ostream_ascend_object(joutput);
+                       i_assert(ret >= 0);
+                       if (ret == 0)
+                               break;
+                       state++;
+                       continue;
+               case 5:
+                       ret = json_ostream_ascend_array(joutput);
+                       i_assert(ret >= 0);
+                       if (ret == 0)
+                               break;
+                       state++;
+                       continue;
+               case 6:
+                       ret = json_ostream_descend_array(joutput, "bbbbbb");
+                       i_assert(ret >= 0);
+                       if (ret == 0)
+                               break;
+                       state++;
+                       continue;
+               case 7:
+                       ret = json_ostream_descend_object(joutput, NULL);
+                       i_assert(ret >= 0);
+                       if (ret == 0)
+                               break;
+                       data = "BBBBB";
+                       input = i_stream_create_from_data(data, strlen(data));
+                       state++;
+                       continue;
+               case 8:
+                       ret = json_ostream_write_string_stream(
+                               joutput, "eeeeee", input);
+                       i_assert(ret >= 0);
+                       if (ret == 0)
+                               break;
+                       i_stream_unref(&input);
+                       state++;
+                       continue;
+               case 9:
+                       ret = json_ostream_ascend_object(joutput);
+                       i_assert(ret >= 0);
+                       if (ret == 0)
+                               break;
+                       state++;
+                       continue;
+               case 10:
+                       ret = json_ostream_ascend_array(joutput);
+                       i_assert(ret >= 0);
+                       if (ret == 0)
+                               break;
+                       state++;
+                       continue;
+               case 11:
+                       ret = json_ostream_descend_array(joutput, "cccccc");
+                       i_assert(ret >= 0);
+                       if (ret == 0)
+                               break;
+                       state++;
+                       continue;
+               case 12:
+                       ret = json_ostream_descend_object(joutput, NULL);
+                       i_assert(ret >= 0);
+                       if (ret == 0)
+                               break;
+                       data = "CCCCC";
+                       input = i_stream_create_from_data(data, strlen(data));
+                       state++;
+                       continue;
+               case 13:
+                       ret = json_ostream_write_string_stream(
+                               joutput, "ffffff", input);
+                       i_assert(ret >= 0);
+                       if (ret == 0)
+                               break;
+                       i_stream_unref(&input);
+                       state++;
+                       continue;
+               case 14:
+                       ret = json_ostream_ascend_object(joutput);
+                       i_assert(ret >= 0);
+                       if (ret == 0)
+                               break;
+                       state++;
+                       continue;
+               case 15:
+                       ret = json_ostream_ascend_array(joutput);
+                       i_assert(ret >= 0);
+                       if (ret == 0)
+                               break;
+                       state++;
+                       continue;
+               case 16:
+                       ret = json_ostream_ascend_object(joutput);
+                       i_assert(ret >= 0);
+                       if (ret == 0)
+                               break;
+                       state++;
+                       continue;
+               }
+       }
+       json_ostream_unref(&joutput);
+       test_assert_strcmp("{\"aaaaaa\":[{\"dddddd\":\"AAAAA\"}],"
+                          "\"bbbbbb\":[{\"eeeeee\":\"BBBBB\"}],"
+                          "\"cccccc\":[{\"ffffff\":\"CCCCC\"}]}",
+                          str_c(buffer));
+       test_end();
+       str_truncate(buffer, 0);
+       output->offset = 0;
+
        o_stream_destroy(&output);
        str_free(&buffer);
 }
@@ -701,8 +917,10 @@ static void test_json_ostream_write(void)
 static void test_json_ostream_nwrite(void)
 {
        string_t *buffer;
+       struct istream *input;
        struct ostream *output;
        struct json_ostream *joutput;
+       const char *data;
 
        buffer = str_new(default_pool, 256);
        output = o_stream_create_buffer(buffer);
@@ -768,6 +986,21 @@ static void test_json_ostream_nwrite(void)
        str_truncate(buffer, 0);
        output->offset = 0;
 
+       /* string stream */
+       test_begin("json ostream nwrite - string stream");
+       joutput = json_ostream_create(output, 0);
+       data = "AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ";
+       input = i_stream_create_from_data(data, strlen(data));
+       json_ostream_nwrite_string_stream(joutput, NULL, input);
+       i_stream_unref(&input);
+       json_ostream_nfinish_destroy(&joutput);
+       test_assert_strcmp(
+               "\"AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ\"",
+               str_c(buffer));
+       test_end();
+       str_truncate(buffer, 0);
+       output->offset = 0;
+
        /* <JSON-text> */
        test_begin("json ostream nwrite - <JSON-text>");
        joutput = json_ostream_create(output, 0);
@@ -801,6 +1034,23 @@ static void test_json_ostream_nwrite(void)
        str_truncate(buffer, 0);
        output->offset = 0;
 
+       /* [ string string stream ] */
+       test_begin("json ostream nwrite - array [ string stream ]");
+       joutput = json_ostream_create(output, 0);
+       json_ostream_ndescend_array(joutput, NULL);
+       data = "AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ";
+       input = i_stream_create_from_data(data, strlen(data));
+       json_ostream_nwrite_string_stream(joutput, NULL, input);
+       i_stream_unref(&input);
+       json_ostream_nascend_array(joutput);
+       json_ostream_nfinish_destroy(&joutput);
+       test_assert_strcmp(
+               "[\"AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ\"]",
+               str_c(buffer));
+       test_end();
+       str_truncate(buffer, 0);
+       output->offset = 0;
+
        /* [ <JSON-text> ] */
        test_begin("json ostream nwrite - array [ <JSON-text> ]");
        joutput = json_ostream_create(output, 0);
@@ -871,6 +1121,24 @@ static void test_json_ostream_nwrite(void)
        str_truncate(buffer, 0);
        output->offset = 0;
 
+       /* { "frop": string stream } */
+       test_begin("json ostream nwrite - object { \"frop\": string stream }");
+       joutput = json_ostream_create(output, 0);
+       json_ostream_ndescend_object(joutput, NULL);
+       data = "AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ";
+       input = i_stream_create_from_data(data, strlen(data));
+       json_ostream_nwrite_string_stream(joutput, "frop", input);
+       i_stream_unref(&input);
+       json_ostream_nascend_object(joutput);
+       json_ostream_nfinish_destroy(&joutput);
+       test_assert_strcmp(
+               "{\"frop\":"
+               "\"AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ\"}",
+               str_c(buffer));
+       test_end();
+       str_truncate(buffer, 0);
+       output->offset = 0;
+
        /* concatenated string */
        test_begin("json ostream nwrite - concatenated string");
        joutput = json_ostream_create(output, 0);