/* We opened an input stream string */
bool string_stream:1; /* API state */
bool string_stream_written:1; /* write state */
+ /* We opened an input stream JSON-text */
+ bool text_stream:1; /* API state */
};
static int json_generator_flush_string_input(struct json_generator *generator);
+static int json_generator_flush_text_input(struct json_generator *generator);
static struct json_generator *
json_generator_new(enum json_generator_flags flags)
}
generator->write_state = JSON_GENERATOR_STATE_VALUE_END;
}
+ /* flush string stream */
+ if (generator->text_stream) {
+ i_assert(generator->value_input != NULL);
+ /* flush the stream */
+ ret = json_generator_flush_text_input(generator);
+ if (ret <= 0)
+ return ret;
+ generator->text_stream = FALSE;
+ generator->write_state = JSON_GENERATOR_STATE_VALUE_END;
+ }
return 1;
}
strlen(str));
}
+static int
+json_generator_flush_text_input(struct json_generator *generator)
+{
+ const unsigned char *data;
+ size_t size;
+ ssize_t sret;
+ int ret;
+
+ while ((ret = i_stream_read_more(generator->value_input,
+ &data, &size)) > 0) {
+ sret = json_generate_text_write_data(generator, data,
+ size, FALSE);
+ if (sret < 0)
+ return -1;
+ if (sret == 0)
+ return 0;
+ i_stream_skip(generator->value_input, (size_t)sret);
+ }
+ if (ret < 0) {
+ if (generator->value_input->stream_errno != 0)
+ return -1;
+
+ i_assert(!i_stream_have_bytes_left(generator->value_input));
+ i_stream_unref(&generator->value_input);
+ return 1;
+ }
+ return 0;
+}
+
+int json_generate_text_stream(struct json_generator *generator,
+ struct istream *input)
+{
+ i_assert(generator->value_input == NULL);
+ json_generator_value_begin(generator);
+ generator->value_input = input;
+ i_stream_ref(input);
+ generator->text_stream = TRUE;
+ if (generator->write_state == JSON_GENERATOR_STATE_VALUE_END)
+ generator->write_state = JSON_GENERATOR_STATE_VALUE_NEXT;
+ if (generator->level_stack_pos == 0)
+ generator->state = JSON_GENERATOR_STATE_END;
+ else if (generator->object_level)
+ generator->state = JSON_GENERATOR_STATE_OBJECT_MEMBER;
+ else
+ generator->state = JSON_GENERATOR_STATE_VALUE;
+ if (json_generator_flush(generator) < 0)
+ return -1;
+ return 1;
+}
+
/*
* value
*/
return json_generate_text_data(
generator, value->content.data->data,
value->content.data->size);
+ case JSON_CONTENT_TYPE_STREAM:
+ return json_generate_text_stream(
+ generator, value->content.stream);
default:
break;
}
str_truncate(buffer, 0);
output->offset = 0;
+ /* <JSON-text> - input stream */
+ test_begin("json write <JSON-text> - input stream");
+ generator = json_generator_init(output, 0);
+ data = "[\"frop!\",\"friep!\",\"frml!\"]";
+ input = i_stream_create_from_data(data, strlen(data));
+ ret = json_generate_text_stream(generator, input);
+ test_assert(ret > 0);
+ i_stream_unref(&input);
+ json_generator_flush(generator);
+ test_assert(ret > 0);
+ json_generator_deinit(&generator);
+ test_assert(strcmp(data, str_c(buffer)) == 0);
+ test_end();
+ str_truncate(buffer, 0);
+ output->offset = 0;
+
/* [ ] */
test_begin("json write array - [ ]");
generator = json_generator_init(output, 0);
str_truncate(buffer, 0);
output->offset = 0;
+ /* array - <JSON-text> input stream nested */
+ test_begin("json write array - <JSON-text> input stream nested");
+ generator = json_generator_init(output, 0);
+ data = "[\"frop!\",\"friep!\",\"frml!\"]";
+ input = i_stream_create_from_data(data, strlen(data));
+ json_generate_array_open(generator);
+ ret = json_generate_text_stream(generator, input);
+ test_assert(ret > 0);
+ i_stream_unref(&input);
+ ret = json_generate_array_close(generator);
+ test_assert(ret > 0);
+ json_generator_flush(generator);
+ test_assert(ret > 0);
+ json_generator_deinit(&generator);
+ test_assert(strcmp("[[\"frop!\",\"friep!\",\"frml!\"]]",
+ str_c(buffer)) == 0);
+ test_end();
+ str_truncate(buffer, 0);
+ output->offset = 0;
+
+ /* array - <JSON-text> input stream nested, second */
+ test_begin("json write array - <JSON-text> input stream nested, second");
+ generator = json_generator_init(output, 0);
+ data = "[\"frop!\",\"friep!\",\"frml!\"]";
+ input = i_stream_create_from_data(data, strlen(data));
+ json_generate_array_open(generator);
+ ret = json_generate_string(generator, "frop");
+ test_assert(ret > 0);
+ ret = json_generate_text_stream(generator, input);
+ test_assert(ret > 0);
+ i_stream_unref(&input);
+ ret = json_generate_array_close(generator);
+ test_assert(ret > 0);
+ json_generator_flush(generator);
+ test_assert(ret > 0);
+ json_generator_deinit(&generator);
+ test_assert(strcmp("[\"frop\",[\"frop!\",\"friep!\",\"frml!\"]]",
+ str_c(buffer)) == 0);
+ test_end();
+ str_truncate(buffer, 0);
+ output->offset = 0;
+
/* { } */
test_begin("json write object - { }");
generator = json_generator_init(output, 0);
str_truncate(buffer, 0);
output->offset = 0;
+ /* object - <JSON-text> input stream nested */
+ test_begin("json write object - <JSON-text> input stream nested");
+ generator = json_generator_init(output, 0);
+ data = "[\"frop!\",\"friep!\",\"frml!\"]";
+ input = i_stream_create_from_data(data, strlen(data));
+ json_generate_object_open(generator);
+ ret = json_generate_object_member(generator, "a");
+ test_assert(ret > 0);
+ ret = json_generate_text_stream(generator, input);
+ test_assert(ret > 0);
+ i_stream_unref(&input);
+ ret = json_generate_object_close(generator);
+ test_assert(ret > 0);
+ json_generator_flush(generator);
+ test_assert(ret > 0);
+ json_generator_deinit(&generator);
+ test_assert(strcmp("{\"a\":[\"frop!\",\"friep!\",\"frml!\"]}",
+ str_c(buffer)) == 0);
+ test_end();
+ str_truncate(buffer, 0);
+ output->offset = 0;
+
/* trickle [1] */
test_begin("json write object - trickle[1]");
o_stream_set_max_buffer_size(output, 0);
str_truncate(buffer, 0);
output->offset = 0;
+ /* trickle [5] */
+ test_begin("json write object - trickle[5]");
+ o_stream_set_max_buffer_size(output, 0);
+ generator = json_generator_init(output, 0);
+ json_generate_object_open(generator);
+ state = 0;
+ for (pos = 0; pos < 65535 && state <= 15; pos++) {
+ o_stream_set_max_buffer_size(output, pos);
+ switch (state) {
+ case 0:
+ ret = json_generate_object_member(generator, "aaaaaa");
+ test_assert(ret >= 0);
+ if (ret == 0) break;
+ json_generate_array_open(generator);
+ json_generate_object_open(generator);
+ state++;
+ continue;
+ case 1:
+ ret = json_generate_object_member(generator, "dddddd");
+ test_assert(ret >= 0);
+ if (ret == 0) break;
+ state++;
+ continue;
+ case 2:
+ data = "[\"GGGGG\"]";
+ input = i_stream_create_from_data(data, strlen(data));
+ ret = json_generate_text_stream(generator, input);
+ test_assert(ret > 0);
+ i_stream_unref(&input);
+ state++;
+ continue;
+ case 3:
+ ret = json_generate_object_close(generator);
+ test_assert(ret >= 0);
+ if (ret == 0) break;
+ state++;
+ continue;
+ case 4:
+ ret = json_generate_array_close(generator);
+ test_assert(ret >= 0);
+ if (ret == 0) break;
+ state++;
+ continue;
+ case 5:
+ ret = json_generate_object_member(generator, "bbbbbb");
+ test_assert(ret >= 0);
+ if (ret == 0) break;
+ json_generate_array_open(generator);
+ json_generate_object_open(generator);
+ state++;
+ continue;
+ case 6:
+ ret = json_generate_object_member(generator, "eeeeee");
+ test_assert(ret >= 0);
+ if (ret == 0) break;
+ state++;
+ continue;
+ case 7:
+ data = "[\"HHHHH\"]";
+ input = i_stream_create_from_data(data, strlen(data));
+ ret = json_generate_text_stream(generator, input);
+ test_assert(ret > 0);
+ i_stream_unref(&input);
+ state++;
+ continue;
+ case 8:
+ ret = json_generate_object_close(generator);
+ test_assert(ret >= 0);
+ if (ret == 0) break;
+ state++;
+ continue;
+ case 9:
+ ret = json_generate_array_close(generator);
+ test_assert(ret >= 0);
+ if (ret == 0) break;
+ state++;
+ continue;
+ case 10:
+ ret = json_generate_object_member(generator, "cccccc");
+ test_assert(ret >= 0);
+ if (ret == 0) break;
+ json_generate_array_open(generator);
+ json_generate_object_open(generator);
+ state++;
+ continue;
+ case 11:
+ ret = json_generate_object_member(generator, "ffffff");
+ test_assert(ret >= 0);
+ if (ret == 0) break;
+ state++;
+ continue;
+ case 12:
+ data = "[\"IIIII\"]";
+ input = i_stream_create_from_data(data, strlen(data));
+ ret = json_generate_text_stream(generator, input);
+ test_assert(ret > 0);
+ i_stream_unref(&input);
+ state++;
+ continue;
+ case 13:
+ ret = json_generate_object_close(generator);
+ test_assert(ret >= 0);
+ if (ret == 0) break;
+ state++;
+ continue;
+ case 14:
+ ret = json_generate_array_close(generator);
+ test_assert(ret >= 0);
+ if (ret == 0) break;
+ state++;
+ continue;
+ case 15:
+ ret = json_generate_object_close(generator);
+ test_assert(ret >= 0);
+ if (ret == 0) break;
+ state++;
+ continue;
+ }
+ }
+ json_generator_deinit(&generator);
+ test_assert(state == 16);
+ test_assert(strcmp("{\"aaaaaa\":[{\"dddddd\":[\"GGGGG\"]}],"
+ "\"bbbbbb\":[{\"eeeeee\":[\"HHHHH\"]}],"
+ "\"cccccc\":[{\"ffffff\":[\"IIIII\"]}]}",
+ str_c(buffer)) == 0);
+ test_end();
+ str_truncate(buffer, 0);
+ output->offset = 0;
+
o_stream_destroy(&output);
str_free(&buffer);
}