JSON parsing library by Andrii Mamchur https://github.com/amamchur/jsonlite
Dependents: M2X_dev MTS_M2x_Example1 MTS_M2x_Example m2x-demo-all ... more
Revision 1:807034181e02, committed 2014-04-25
- Comitter:
- Josh Hollenbeck
- Date:
- Fri Apr 25 02:12:53 2014 -0700
- Parent:
- 0:01a2f8de46c8
- Commit message:
- updated jsonlite to ver 1.1.2
Changed in this revision
jsonlite.c | Show annotated file Show diff for this revision Revisions of this file |
jsonlite.h | Show annotated file Show diff for this revision Revisions of this file |
diff -r 01a2f8de46c8 -r 807034181e02 jsonlite.c --- a/jsonlite.c Thu Oct 24 12:20:56 2013 +0000 +++ b/jsonlite.c Fri Apr 25 02:12:53 2014 -0700 @@ -15,6 +15,590 @@ // See the License for the specific language governing permissions and // limitations under the License +const char *jsonlite_version = "1.1.2"; +// +// Copyright 2012-2013, Andrii Mamchur +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License + +#ifndef JSONLITE_AMALGAMATED +#include "../include/jsonlite_builder.h" +#endif + +#include <stdlib.h> +#include <stddef.h> +#include <string.h> + +#define jsonlite_builder_check_depth() \ +do { \ + if (builder->state >= builder->limit) { \ + return jsonlite_result_depth_limit; \ + } \ +} while (0) + +enum { + jsonlite_accept_object_begin = 0x0001, + jsonlite_accept_object_end = 0x0002, + jsonlite_accept_array_begin = 0x0004, + jsonlite_accept_array_end = 0x0008, + jsonlite_accept_key = 0x0010, + jsonlite_accept_string = 0x0020, + jsonlite_accept_number = 0x0040, + jsonlite_accept_boolean = 0x0080, + jsonlite_accept_null = 0x0100, + jsonlite_accept_values_only = 0x0200, + jsonlite_accept_next = 0x0400, + + jsonlite_accept_value = 0 + | jsonlite_accept_object_begin + | jsonlite_accept_array_begin + | jsonlite_accept_string + | jsonlite_accept_number + | jsonlite_accept_boolean + | jsonlite_accept_null, + jsonlite_accept_continue_object = 0 + | jsonlite_accept_next + | jsonlite_accept_key + | jsonlite_accept_object_end, + jsonlite_accept_continue_array = 0 + | jsonlite_accept_next + | jsonlite_accept_values_only + | jsonlite_accept_value + | jsonlite_accept_array_end +}; + +typedef uint16_t jsonlite_write_state; +typedef struct jsonlite_builder_struct { + jsonlite_write_state *state; + jsonlite_write_state *limit; + jsonlite_write_state *stack; + jsonlite_stream stream; + + size_t indentation; + char *doubleFormat; +} jsonlite_builder_struct; + +static int jsonlite_builder_accept(jsonlite_builder builder, jsonlite_write_state a); +static void jsonlite_builder_pop_state(jsonlite_builder builder); +static void jsonlite_builder_prepare_value_writing(jsonlite_builder builder); +static void jsonlite_builder_raw_char(jsonlite_builder builder, char data); +static void jsonlite_builder_write_uft8(jsonlite_builder builder, const char *data, size_t length); +static void jsonlite_builder_raw(jsonlite_builder builder, const void *data, size_t length); +static void jsonlite_builder_repeat(jsonlite_builder builder, const char ch, size_t count); +static void jsonlite_builder_write_base64(jsonlite_builder builder, const void *data, size_t length); + +jsonlite_builder jsonlite_builder_init(size_t depth, jsonlite_stream stream) { + jsonlite_builder builder; + + depth = depth < 2 ? 2 : depth; + + builder = malloc(sizeof(jsonlite_builder_struct) + depth * sizeof(jsonlite_write_state)); + builder->state = (jsonlite_write_state *)((uint8_t *)builder + sizeof(jsonlite_builder_struct)); + builder->limit = builder->state + depth - 1; + builder->stack = builder->state; + builder->stream = stream; + builder->indentation = 0; + *builder->state = jsonlite_accept_object_begin | jsonlite_accept_array_begin; + jsonlite_builder_set_double_format(builder, "%.16g"); + return builder; +} + +jsonlite_result jsonlite_builder_release(jsonlite_builder builder) { + if (builder == NULL) { + return jsonlite_result_invalid_argument; + } + + free(builder->doubleFormat); + free(builder); + return jsonlite_result_ok; +} + +jsonlite_result jsonlite_builder_set_indentation(jsonlite_builder builder, size_t indentation) { + if (builder != NULL) { + builder->indentation = indentation; + return jsonlite_result_ok; + } + return jsonlite_result_invalid_argument; +} + +jsonlite_result jsonlite_builder_set_double_format(jsonlite_builder builder, const char *format) { + if (builder != NULL && format != NULL) { + builder->doubleFormat = strdup(format); + return jsonlite_result_ok; + } + return jsonlite_result_invalid_argument; +} + +static int jsonlite_builder_accept(jsonlite_builder builder, jsonlite_write_state a) { + return (*builder->state & a) == a; +} + +static void jsonlite_builder_pop_state(jsonlite_builder builder) { + jsonlite_write_state *ws = --builder->state; + if (jsonlite_builder_accept(builder, jsonlite_accept_values_only)) { + *ws = jsonlite_accept_continue_array; + } else { + *ws = jsonlite_accept_continue_object; + } +} + +static void jsonlite_builder_prepare_value_writing(jsonlite_builder builder) { + jsonlite_write_state *ws = builder->state; + if (jsonlite_builder_accept(builder, jsonlite_accept_values_only)) { + if (jsonlite_builder_accept(builder, jsonlite_accept_next)) { + jsonlite_builder_raw_char(builder, ','); + } + + if (builder->indentation != 0) { + jsonlite_builder_raw_char(builder, '\r'); + jsonlite_builder_repeat(builder, ' ', (builder->state - builder->stack) * builder->indentation); + } + } else { + *ws &= ~jsonlite_accept_value; + *ws |= jsonlite_accept_key; + } + *ws |= jsonlite_accept_next; +} + +jsonlite_result jsonlite_builder_object_begin(jsonlite_builder builder) { + if (builder == NULL) { + return jsonlite_result_invalid_argument; + } + + jsonlite_builder_check_depth(); + + if (jsonlite_builder_accept(builder, jsonlite_accept_object_begin)) { + jsonlite_builder_prepare_value_writing(builder); + *++builder->state = jsonlite_accept_object_end | jsonlite_accept_key; + jsonlite_builder_raw_char(builder, '{'); + return jsonlite_result_ok; + } + + return jsonlite_result_not_allowed; +} + +jsonlite_result jsonlite_builder_object_end(jsonlite_builder builder) { + if (builder == NULL) { + return jsonlite_result_invalid_argument; + } + + if (jsonlite_builder_accept(builder, jsonlite_accept_object_end)) { + jsonlite_builder_pop_state(builder); + if (builder->indentation != 0) { + jsonlite_builder_raw_char(builder, '\r'); + jsonlite_builder_repeat(builder, ' ', (builder->state - builder->stack) * builder->indentation); + } + jsonlite_builder_raw_char(builder, '}'); + return jsonlite_result_ok; + } + + return jsonlite_result_not_allowed; +} + +jsonlite_result jsonlite_builder_array_begin(jsonlite_builder builder) { + if (builder == NULL) { + return jsonlite_result_invalid_argument; + } + + jsonlite_builder_check_depth(); + + if (jsonlite_builder_accept(builder, jsonlite_accept_array_begin)) { + jsonlite_builder_prepare_value_writing(builder); + *++builder->state = jsonlite_accept_array_end + | jsonlite_accept_value + | jsonlite_accept_values_only; + jsonlite_builder_raw_char(builder, '['); + return jsonlite_result_ok; + } + + return jsonlite_result_not_allowed; +} + +jsonlite_result jsonlite_builder_array_end(jsonlite_builder builder) { + if (builder == NULL) { + return jsonlite_result_invalid_argument; + } + + if (jsonlite_builder_accept(builder, jsonlite_accept_array_end)) { + jsonlite_builder_pop_state(builder); + if (builder->indentation != 0) { + jsonlite_builder_raw_char(builder, '\r'); + jsonlite_builder_repeat(builder, ' ', (builder->state - builder->stack) * builder->indentation); + } + jsonlite_builder_raw_char(builder, ']'); + return jsonlite_result_ok; + } + + return jsonlite_result_not_allowed; +} + +static void jsonlite_builder_write_uft8(jsonlite_builder builder, const char *data, size_t length) { + char b[2] = {'\\', '?'}; + const char *c = data; + const char *p = data; + const char *l = data + length; + + jsonlite_builder_raw_char(builder, '\"'); +next: + if (c == l) goto end; + switch (*c) { + case '"': b[1] = '"'; goto flush; + case '\\': b[1] = '\\'; goto flush; + case '\b': b[1] = 'b'; goto flush; + case '\f': b[1] = 'f'; goto flush; + case '\n': b[1] = 'n'; goto flush; + case '\r': b[1] = 'r'; goto flush; + case '\t': b[1] = 't'; goto flush; + default: c++; goto next; + } +flush: + jsonlite_stream_write(builder->stream, p, c - p); + jsonlite_stream_write(builder->stream, b, 2); + p = ++c; + goto next; +end: + jsonlite_stream_write(builder->stream, p, c - p); + jsonlite_builder_raw_char(builder, '\"'); +} + +jsonlite_result jsonlite_builder_key(jsonlite_builder builder, const char *data, size_t length) { + if (builder == NULL || data == NULL) { + return jsonlite_result_invalid_argument; + } + + jsonlite_write_state *ws = builder->state; + if (jsonlite_builder_accept(builder, jsonlite_accept_key)) { + if (jsonlite_builder_accept(builder, jsonlite_accept_next)) { + jsonlite_builder_raw_char(builder, ','); + } + + if (builder->indentation != 0) { + jsonlite_builder_raw_char(builder, '\r'); + jsonlite_builder_repeat(builder, ' ', (builder->state - builder->stack) * builder->indentation); + } + + jsonlite_builder_write_uft8(builder, data, length); + if (builder->indentation != 0) { + jsonlite_builder_raw(builder, ": ", 2); + } else { + jsonlite_builder_raw_char(builder, ':'); + } + *ws = jsonlite_accept_value; + return jsonlite_result_ok; + } + + return jsonlite_result_not_allowed; +} + +jsonlite_result jsonlite_builder_string(jsonlite_builder builder, const char *data, size_t length) { + if (builder == NULL || data == NULL) { + return jsonlite_result_invalid_argument; + } + + jsonlite_write_state *ws = builder->state; + if (jsonlite_builder_accept(builder, jsonlite_accept_value)) { + jsonlite_builder_prepare_value_writing(builder); + jsonlite_builder_write_uft8(builder, data, length); + if (jsonlite_builder_accept(builder, jsonlite_accept_values_only)) { + *ws = jsonlite_accept_continue_array; + } else { + *ws = jsonlite_accept_continue_object; + } + return jsonlite_result_ok; + } + + return jsonlite_result_not_allowed; +} + +jsonlite_result jsonlite_builder_int(jsonlite_builder builder, long long value) { + if (builder == NULL) { + return jsonlite_result_invalid_argument; + } + + char buff[64]; + size_t size = 0; + jsonlite_write_state *ws = builder->state; + if (jsonlite_builder_accept(builder, jsonlite_accept_value)) { + jsonlite_builder_prepare_value_writing(builder); + size = sprintf(buff, "%lld", value); + jsonlite_builder_raw(builder, buff, size); + if (jsonlite_builder_accept(builder, jsonlite_accept_values_only)) { + *ws = jsonlite_accept_continue_array; + } else { + *ws = jsonlite_accept_continue_object; + } + return jsonlite_result_ok; + } + + return jsonlite_result_not_allowed; +} + +jsonlite_result jsonlite_builder_double(jsonlite_builder builder, double value) { + if (builder == NULL) { + return jsonlite_result_invalid_argument; + } + + char buff[64]; + size_t size = 0; + jsonlite_write_state *ws = builder->state; + if (jsonlite_builder_accept(builder, jsonlite_accept_value)) { + jsonlite_builder_prepare_value_writing(builder); + size = sprintf(buff, builder->doubleFormat, value); + jsonlite_builder_raw(builder, buff, size); + if (jsonlite_builder_accept(builder, jsonlite_accept_values_only)) { + *ws = jsonlite_accept_continue_array; + } else { + *ws = jsonlite_accept_continue_object; + } + return jsonlite_result_ok; + } + + return jsonlite_result_not_allowed; +} + +jsonlite_result jsonlite_builder_true(jsonlite_builder builder) { + if (builder == NULL) { + return jsonlite_result_invalid_argument; + } + + static const char value[] = "true"; + jsonlite_write_state *ws = builder->state; + if (!(jsonlite_builder_accept(builder, jsonlite_accept_value))) { + + return jsonlite_result_not_allowed; + } + + jsonlite_builder_prepare_value_writing(builder); + jsonlite_builder_raw(builder, (char *)value, sizeof(value) - 1); + if (jsonlite_builder_accept(builder, jsonlite_accept_values_only)) { + *ws = jsonlite_accept_continue_array; + } else { + *ws = jsonlite_accept_continue_object; + } + return jsonlite_result_ok; +} + +jsonlite_result jsonlite_builder_false(jsonlite_builder builder) { + if (builder == NULL) { + return jsonlite_result_invalid_argument; + } + + static const char value[] = "false"; + jsonlite_write_state *ws = builder->state; + if (!(jsonlite_builder_accept(builder, jsonlite_accept_value))) { + return jsonlite_result_not_allowed; + } + + jsonlite_builder_prepare_value_writing(builder); + jsonlite_builder_raw(builder, (char *)value, sizeof(value) - 1); + if (jsonlite_builder_accept(builder, jsonlite_accept_values_only)) { + *ws = jsonlite_accept_continue_array; + } else { + *ws = jsonlite_accept_continue_object; + } + return jsonlite_result_ok; +} + +jsonlite_result jsonlite_builder_null(jsonlite_builder builder) { + if (builder == NULL) { + return jsonlite_result_invalid_argument; + } + + static const char value[] = "null"; + jsonlite_write_state *ws = builder->state; + if (!(jsonlite_builder_accept(builder, jsonlite_accept_value))) { + + return jsonlite_result_not_allowed; + } + + jsonlite_builder_prepare_value_writing(builder); + jsonlite_builder_raw(builder, (char *)value, sizeof(value) - 1); + if (jsonlite_builder_accept(builder, jsonlite_accept_values_only)) { + *ws = jsonlite_accept_continue_array; + } else { + *ws = jsonlite_accept_continue_object; + } + return jsonlite_result_ok; +} + +static void jsonlite_builder_raw(jsonlite_builder builder, const void *data, size_t length) { + jsonlite_stream_write(builder->stream, data, length); +} + +static void jsonlite_builder_repeat(jsonlite_builder builder, const char ch, size_t count) { + ptrdiff_t i = 0; + for (; i < count; i++) { + jsonlite_stream_write(builder->stream, &ch, 1); + } +} + +static void jsonlite_builder_raw_char(jsonlite_builder builder, char data) { + jsonlite_stream_write(builder->stream, &data, 1); +} + +jsonlite_result jsonlite_builder_raw_key(jsonlite_builder builder, const void *data, size_t length) { + if (builder == NULL || data == NULL || length == 0) { + return jsonlite_result_invalid_argument; + } + + jsonlite_write_state *ws = builder->state; + if (jsonlite_builder_accept(builder, jsonlite_accept_key)) { + if (jsonlite_builder_accept(builder, jsonlite_accept_next)) { + jsonlite_builder_raw(builder, ",", 1); + } + + if (builder->indentation != 0) { + jsonlite_builder_raw_char(builder, '\r'); + jsonlite_builder_repeat(builder, ' ', (builder->state - builder->stack) * builder->indentation); + } + + jsonlite_builder_raw_char(builder, '\"'); + jsonlite_builder_raw(builder, data, length); + jsonlite_builder_raw_char(builder, '\"'); + if (builder->indentation != 0) { + jsonlite_builder_raw(builder, ": ", 2); + } else { + jsonlite_builder_raw_char(builder, ':'); + } + *ws = jsonlite_accept_value; + return jsonlite_result_ok; + } + + return jsonlite_result_not_allowed; +} + +jsonlite_result jsonlite_builder_raw_string(jsonlite_builder builder, const void *data, size_t length) { + if (builder == NULL || data == NULL || length == 0) { + return jsonlite_result_invalid_argument; + } + + jsonlite_write_state *ws = builder->state; + if (jsonlite_builder_accept(builder, jsonlite_accept_value)) { + jsonlite_builder_prepare_value_writing(builder); + jsonlite_builder_raw_char(builder, '\"'); + jsonlite_builder_raw(builder, data, length); + jsonlite_builder_raw_char(builder, '\"'); + if (jsonlite_builder_accept(builder, jsonlite_accept_values_only)) { + *ws = jsonlite_accept_continue_array; + } else { + *ws = jsonlite_accept_continue_object; + } + return jsonlite_result_ok; + } + + return jsonlite_result_not_allowed; +} + +jsonlite_result jsonlite_builder_raw_value(jsonlite_builder builder, const void *data, size_t length) { + if (builder == NULL || data == NULL || length == 0) { + return jsonlite_result_invalid_argument; + } + + jsonlite_write_state *ws = builder->state; + if (jsonlite_builder_accept(builder, jsonlite_accept_value)) { + jsonlite_builder_prepare_value_writing(builder); + jsonlite_builder_raw(builder, data, length); + if (jsonlite_builder_accept(builder, jsonlite_accept_values_only)) { + *ws = jsonlite_accept_continue_array; + } else { + *ws = jsonlite_accept_continue_object; + } + return jsonlite_result_ok; + } + + return jsonlite_result_not_allowed; +} + +static void jsonlite_builder_write_base64(jsonlite_builder builder, const void *data, size_t length) { + static const char encode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + char buffer[5] = {0}; + const uint8_t *c = data; + const uint8_t *l = data + length; + uint32_t bits; + jsonlite_stream_write(builder->stream, "\"", 1); +next: + switch (l - c) { + case 0: + goto done; + case 1: + bits = *c++ << 16; + buffer[0] = encode[(bits & 0x00FC0000) >> 18]; + buffer[1] = encode[(bits & 0x0003F000) >> 12]; + buffer[2] = '='; + buffer[3] = '='; + l = c; + goto write; + case 2: + bits = *c++ << 16; + bits |= *c++ << 8; + buffer[0] = encode[(bits & 0x00FC0000) >> 18]; + buffer[1] = encode[(bits & 0x0003F000) >> 12]; + buffer[2] = encode[(bits & 0x00000FC0) >> 6]; + buffer[3] = '='; + l = c; + goto write; + default: + bits = *c++ << 16; + bits |= *c++ << 8; + bits |= *c++; + buffer[0] = encode[(bits & 0x00FC0000) >> 18]; + buffer[1] = encode[(bits & 0x0003F000) >> 12]; + buffer[2] = encode[(bits & 0x00000FC0) >> 6]; + buffer[3] = encode[(bits & 0x0000003F)]; + goto write; + } +write: + jsonlite_stream_write(builder->stream, buffer, 4); + goto next; +done: + jsonlite_stream_write(builder->stream, "\"", 1); +} + +jsonlite_result jsonlite_builder_base64_value(jsonlite_builder builder, const void *data, size_t length) { + if (builder == NULL || data == NULL || length == 0) { + return jsonlite_result_invalid_argument; + } + + jsonlite_write_state *ws = builder->state; + if (jsonlite_builder_accept(builder, jsonlite_accept_value)) { + jsonlite_builder_prepare_value_writing(builder); + jsonlite_builder_write_base64(builder, data, length); + if (jsonlite_builder_accept(builder, jsonlite_accept_values_only)) { + *ws = jsonlite_accept_continue_array; + } else { + *ws = jsonlite_accept_continue_object; + } + return jsonlite_result_ok; + } + + return jsonlite_result_not_allowed; + +} +// +// Copyright 2012-2013, Andrii Mamchur +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License + #ifndef JSONLITE_AMALGAMATED #include "jsonlite_parser.h" #endif @@ -38,23 +622,28 @@ #endif +#define MIN_DEPTH 2 #define CALL_VALUE_CALLBACK(cbs, type, token) (cbs.type(&cbs.context, token)) #define CALL_STATE_CALLBACK(cbs, type) (cbs.type(&cbs.context)) -#define CHECK_HEX(c) \ -if ((c) < 48) goto error_escape; \ -if ((c) > 102) goto error_escape; \ -if (57 < (c) && (c) < 65) goto error_escape; \ -if (70 < (c) && (c) < 97) goto error_escape +#define HEX_CHAR_TO_INT(c, step) \ +if (0x30 <= *c && *c <= 0x39) { \ + hex_value = *c - 0x30; \ +} else if (0x41 <= *c && *c <= 0x46) { \ + hex_value = *c - 0x37; \ +} else if (0x61 <= *c && *c <= 0x66) { \ + hex_value = *c - 0x57; \ +} else goto error_escape; \ +c += step -#define CASE_NUMBER_TOKEN_END \ -case 9: goto found_token; \ -case 10: goto found_token; \ -case 13: goto found_token; \ -case 32: goto found_token; \ -case 44: goto found_token; \ -case 93: goto found_token; \ -case 125: goto found_token +#define CASE_NUMBER_TOKEN_END \ +case 0x09: goto number_parsed; \ +case 0x0A: goto number_parsed; \ +case 0x0D: goto number_parsed; \ +case 0x20: goto number_parsed; \ +case 0x2C: goto number_parsed; \ +case 0x5D: goto number_parsed; \ +case 0x7D: goto number_parsed enum { state_start, @@ -67,30 +656,26 @@ state_key, state_value, state_end, - - state_suspend = 1 << 7 + + state_stop = 1 << 7 }; typedef uint8_t parse_state; struct jsonlite_parser_struct { const uint8_t *cursor; const uint8_t *limit; - const uint8_t *token_start; const uint8_t *buffer; - uint8_t *buffer_own; - uint8_t *rest; - size_t rest_size; - + parse_state *current; - const parse_state *last; - + parse_state *last; + parse_state **control; + jsonlite_result result; jsonlite_parser_callbacks callbacks; } jsonlite_parser_struct; static void jsonlite_do_parse(jsonlite_parser parser); -static void jsonlite_finish_parse(jsonlite_parser parser); static void empty_value_callback(jsonlite_callback_context *ctx, jsonlite_token *t) {} static void empty_state_callback(jsonlite_callback_context *ctx) {} @@ -110,17 +695,18 @@ }; size_t jsonlite_parser_estimate_size(size_t depth) { - depth = depth < 2 ? 32 : depth; + depth = depth < MIN_DEPTH ? 32 : depth; return sizeof(jsonlite_parser_struct) + depth * sizeof(parse_state); } -jsonlite_parser jsonlite_parser_init(size_t depth) { - depth = depth < 2 ? 32 : depth; - - jsonlite_parser parser = (jsonlite_parser)calloc(1, jsonlite_parser_estimate_size(depth)); +static jsonlite_parser jsonlite_parser_configure(void *memory, size_t size) { + size_t depth = (size - sizeof(jsonlite_parser_struct)) / sizeof(parse_state); + jsonlite_parser parser = (jsonlite_parser)memory; parser->result = jsonlite_result_unknown; + parser->buffer_own = NULL; parser->callbacks = jsonlite_default_callbacks; - parser->current = (parse_state *)((uint8_t *)parser + sizeof(jsonlite_parser_struct)); + parser->control = NULL; + parser->current = ((uint8_t *)parser + sizeof(jsonlite_parser_struct)); parser->current[0] = state_end; parser->current[1] = state_start; parser->last = parser->current + depth; @@ -128,6 +714,24 @@ return parser; } +jsonlite_parser jsonlite_parser_init(size_t depth) { + size_t size = jsonlite_parser_estimate_size(depth); + void *memory = malloc(size); + return jsonlite_parser_configure(memory, size); +} + +jsonlite_parser jsonlite_parser_init_memory(void *memory, size_t size) { + if (memory == NULL) { + return NULL; + } + + if (size < jsonlite_parser_estimate_size(MIN_DEPTH)) { + return NULL; + } + + return jsonlite_parser_configure(memory, size); +} + jsonlite_result jsonlite_parser_set_callback(jsonlite_parser parser, const jsonlite_parser_callbacks *cbs) { if (parser == NULL || cbs == NULL) { return jsonlite_result_invalid_argument; @@ -142,7 +746,7 @@ if (parser == NULL) { return jsonlite_result_invalid_argument; } - + return parser->result; } @@ -150,30 +754,26 @@ if (parser == NULL || buffer == NULL || size == 0) { return jsonlite_result_invalid_argument; } - - if (parser->rest != NULL) { - size_t total_size = size + parser->rest_size; + + if (parser->buffer_own != NULL) { + size_t total_size = size + parser->limit - parser->buffer_own; uint8_t *b = (uint8_t *)malloc(total_size); - memcpy(b, parser->rest, parser->rest_size); // LCOV_EXCL_LINE - memcpy(b + parser->rest_size, buffer, size); // LCOV_EXCL_LINE - + memcpy(b, parser->buffer_own, parser->limit - parser->buffer_own); // LCOV_EXCL_LINE + memcpy(b + (parser->limit - parser->buffer_own), buffer, size); // LCOV_EXCL_LINE + free(parser->buffer_own); - free(parser->rest); - + parser->buffer = b; parser->buffer_own = b; - parser->cursor = parser->buffer; - parser->limit = parser->buffer + total_size; - parser->rest = NULL; - parser->rest_size = 0; + parser->cursor = b; + parser->limit = b + total_size; } else { parser->buffer = buffer; parser->cursor = parser->buffer; parser->limit = parser->buffer + size; } - + jsonlite_do_parse(parser); - jsonlite_finish_parse(parser); return parser->result; } @@ -181,37 +781,44 @@ if (parser == NULL) { return jsonlite_result_invalid_argument; } - + if (parser->result != jsonlite_result_suspended) { return jsonlite_result_not_allowed; } - + jsonlite_do_parse(parser); - jsonlite_finish_parse(parser); return parser->result; } jsonlite_result jsonlite_parser_suspend(jsonlite_parser parser) { + return jsonlite_parser_terminate(parser, jsonlite_result_suspended); +} + +jsonlite_result jsonlite_parser_terminate(jsonlite_parser parser, jsonlite_result result) { if (parser == NULL) { return jsonlite_result_invalid_argument; } - - if (parser->result != jsonlite_result_unknown) { + + if (parser->control == NULL) { return jsonlite_result_not_allowed; } - - parser->result = jsonlite_result_suspended; + + parser->result = result; + **parser->control |= state_stop; return jsonlite_result_ok; } void jsonlite_parser_release(jsonlite_parser parser) { + jsonlite_parser_cleanup(parser); + free(parser); +} + +void jsonlite_parser_cleanup(jsonlite_parser parser) { if (parser == NULL) { return; } - + free(parser->buffer_own); - free(parser->rest); - free(parser); } static void jsonlite_do_parse(jsonlite_parser parser) { @@ -220,347 +827,342 @@ const uint8_t *token_start = NULL; const parse_state *last = parser->last; parse_state *state = parser->current; - jsonlite_token token; - parser->result = jsonlite_result_unknown; - goto state_selection; - + jsonlite_token token = {NULL, NULL, NULL, 0}; + jsonlite_result result = jsonlite_result_ok; + uint32_t value, utf32; + uint8_t hex_value; + + *state &= ~state_stop; + parser->control = &state; + goto select_state; + structure_finished: - if (*--state == state_end) goto success; -skip_char_and_spaces: + if (*state == state_end) goto end; +skip_char_and_whitespaces: c++; -state_selection: - if (c == l) goto end_of_stream_space; - if (*c == ' ') goto skip_char_and_spaces; - if (*c == '\n') goto skip_char_and_spaces; - if (*c == '\r') goto skip_char_and_spaces; - if (*c == '\t') goto skip_char_and_spaces; +select_state: + if (c == l) goto end_of_stream_whitespaces; + if (*c == 0x20) goto skip_char_and_whitespaces; + if (*c == 0x0A) goto skip_char_and_whitespaces; + if (*c == 0x0D) goto skip_char_and_whitespaces; + if (*c == 0x09) goto skip_char_and_whitespaces; token_start = c; - - if (parser->result != jsonlite_result_unknown) goto end; + switch (*state) { - case state_value: goto value_type_detection; - case state_key: goto string_token_parsing; - case state_object_key: goto key_checking; - case state_object_key_end: goto key_end_checking; - case state_colon: goto colon_checking; - case state_object_comma_end: goto object_comma_end_checking; - case state_array_value_end: goto array_value_end_checking; - case state_array_comma_end: goto array_comma_end_checking; + case state_value: goto parse_value; + case state_colon: goto parse_colon; + case state_object_comma_end: goto parse_object_comma_end; + case state_object_key: goto parse_key; + case state_object_key_end: goto parse_key_end; + case state_array_comma_end: goto parse_array_comma_end; + case state_array_value_end: goto parse_array_value_end; + case state_key: goto parse_string_token; case state_start: - if (*c == '{') goto object_state_machine; - if (*c == '[') goto array_state_machine; + if (*c == 0x7B) goto parse_object; + if (*c == 0x5B) goto parse_array_state; goto error_exp_ooa; + case state_end: goto end; default: - goto suspend; + result = parser->result; + goto end; } - -object_state_machine: +parse_object: *state = state_object_key_end; CALL_STATE_CALLBACK(parser->callbacks, object_start); - goto skip_char_and_spaces; - -array_state_machine: + goto skip_char_and_whitespaces; +parse_array_state: *state = state_array_value_end; CALL_STATE_CALLBACK(parser->callbacks, array_start); - goto skip_char_and_spaces; - -key_checking: - if (*c != '"') goto error_exp_key; + goto skip_char_and_whitespaces; +parse_key: + if (*c != 0x22) goto error_exp_key; *state = state_colon; *++state = state_key; - goto string_token_parsing; - -colon_checking: - if (*c != ':') goto error_exp_colon; + goto parse_string_token; +parse_colon: + if (*c != 0x3A) goto error_exp_colon; *state = state_object_comma_end; *++state = state_value; - goto skip_char_and_spaces; - -key_end_checking: + goto skip_char_and_whitespaces; +parse_key_end: switch (*c) { - case '"': + case 0x22: *state = state_colon; if (++state == last) goto error_depth; *state = state_key; - goto string_token_parsing; - case '}': + goto parse_string_token; + case 0x7D: + state--; CALL_STATE_CALLBACK(parser->callbacks, object_end); goto structure_finished; + default: goto error_exp_koe; } - goto error_exp_koe; - -object_comma_end_checking: +parse_object_comma_end: switch (*c) { - case ',': + case 0x2C: *state = state_object_key; - goto skip_char_and_spaces; - case '}': + goto skip_char_and_whitespaces; + case 0x7D: + state--; CALL_STATE_CALLBACK(parser->callbacks, object_end); goto structure_finished; + default: goto error_exp_coe; } - goto error_exp_coe; - -array_value_end_checking: +parse_array_value_end: switch (*c) { - case ']': + case 0x5D: + state--; CALL_STATE_CALLBACK(parser->callbacks, array_end); goto structure_finished; default: *state = state_array_comma_end; if (++state == last) goto error_depth; *state = state_value; - goto value_type_detection; + goto parse_value; } - -array_comma_end_checking: +parse_array_comma_end: switch (*c) { - case ',': + case 0x2C: *++state = state_value; - goto skip_char_and_spaces; - case ']': + goto skip_char_and_whitespaces; + case 0x5D: + state--; CALL_STATE_CALLBACK(parser->callbacks, array_end); goto structure_finished; + default: goto error_exp_coe; } - goto error_exp_coe; - -value_type_detection: - if (*c == '-' || ('0' <= *c && *c <= '9')) goto number_parsing; - if (*c == '"') goto string_token_parsing; - if (*c == 't') goto true_token_parsing; - if (*c == 'f') goto false_token_paring; - if (*c == 'n') goto null_token_parsing; - if (*c == '{') goto object_state_machine; - if (*c == '[') goto array_state_machine; +parse_value: + if (0x31 <= *c && *c <= 0x39) goto parse_digit_leading_number; + if (*c == 0x30) goto parse_zero_leading_number; + if (*c == 0x2D) goto parse_negative_number; + if (*c == 0x22) goto parse_string_token; + if (*c == 0x74) goto parse_true_token; + if (*c == 0x66) goto parse_false_token; + if (*c == 0x6E) goto parse_null_token; + if (*c == 0x7B) goto parse_object; + if (*c == 0x5B) goto parse_array_state; goto error_exp_value; - -// State machine for number token parsing. -number_parsing: - { - jsonlite_number_type type = jsonlite_number_int; - token.start = c; - switch (*c) { - case 45: type |= jsonlite_number_negative; goto test_zero_leading; - case 48: type |= jsonlite_number_zero_leading; goto take_exp_frac; - default: type |= jsonlite_number_digit_leading; goto take_digits; - } - - test_zero_leading: - if (++c == l) goto end_of_stream; - if (49 <= *c && *c <= 57) goto take_digits; - if (*c == 48) goto take_exp_frac; - goto error_number; - take_exp_frac: - if (++c == l) goto end_of_stream; - switch (*c) { - CASE_NUMBER_TOKEN_END; - case 46: goto found_fraction; - case 69: goto take_exponent; - case 101: goto take_exponent; - default: goto error_number; - } - found_fraction: - type |= jsonlite_number_frac; - if (++c == l) goto end_of_stream; - if (48 <= *c && *c <= 57) goto take_frac_number; - goto error_number; - take_frac_number: - if (++c == l) goto end_of_stream; - if (48 <= *c && *c <= 57) goto take_frac_number; - switch (*c) { - CASE_NUMBER_TOKEN_END; - case 69: goto take_exponent; - case 101: goto take_exponent; - default: goto error_number; - } - take_exponent: - type |= jsonlite_number_exp; - if (++c == l) goto end_of_stream; - if (48 <= *c && *c <= 57) goto take_exponent_number; - switch(*c) { - case 43: goto take_exponent_sign; - case 45: goto take_exponent_sign; - default: goto error_number; - } - take_exponent_sign: - if (++c == l) goto end_of_stream; - if (48 <= *c && *c <= 57) goto take_exponent_number; - goto error_number; - take_exponent_number: - if (++c == l) goto end_of_stream; - if (48 <= *c && *c <= 57) goto take_exponent_number; - switch(*c) { - CASE_NUMBER_TOKEN_END; - default: goto error_number; - } - take_digits: - if (++c == l) goto end_of_stream; - if (48 <= *c && *c <= 57) goto take_digits; - switch(*c) { - CASE_NUMBER_TOKEN_END; - case 46: goto found_fraction; - case 69: goto take_exponent; - case 101: goto take_exponent; - default: goto error_number; - } - found_token: - token.end = c; - token.number_type = type; - CALL_VALUE_CALLBACK(parser->callbacks, number_found, &token); - state--; - goto state_selection; + +// Number parsing +parse_negative_number: + token.start = c; + token.type.number = jsonlite_number_int | jsonlite_number_negative; + if (++c == l) goto end_of_stream; + if (0x31 <= *c && *c <= 0x39) goto parse_digits; + if (*c == 0x30) goto parse_exponent_fraction; + goto error_number; +parse_zero_leading_number: + token.start = c; + token.type.number = jsonlite_number_int | jsonlite_number_zero_leading; +parse_exponent_fraction: + if (++c == l) goto end_of_stream; + switch (*c) { + CASE_NUMBER_TOKEN_END; + case 0x2E: goto parse_fraction; + case 0x45: goto parse_exponent; + case 0x65: goto parse_exponent; + default: goto error_number; + } +parse_fraction: + token.type.number |= jsonlite_number_frac; + if (++c == l) goto end_of_stream; + if (0x30 <= *c && *c <= 0x39) goto parse_frac_number; + goto error_number; +parse_frac_number: + if (++c == l) goto end_of_stream; + if (0x30 <= *c && *c <= 0x39) goto parse_frac_number; + switch (*c) { + CASE_NUMBER_TOKEN_END; + case 0x45: goto parse_exponent; + case 0x65: goto parse_exponent; + default: goto error_number; + } +parse_exponent: + token.type.number |= jsonlite_number_exp; + if (++c == l) goto end_of_stream; + if (0x30 <= *c && *c <= 0x39) goto parse_exponent_number; + switch(*c) { + case 0x2B: goto parse_exponent_sign; + case 0x2D: goto parse_exponent_sign; + default: goto error_number; + } +parse_exponent_sign: + if (++c == l) goto end_of_stream; + if (0x30 <= *c && *c <= 0x39) goto parse_exponent_number; + goto error_number; +parse_exponent_number: + if (++c == l) goto end_of_stream; + if (0x30 <= *c && *c <= 0x39) goto parse_exponent_number; + switch(*c) { + CASE_NUMBER_TOKEN_END; + default: goto error_number; + } +parse_digit_leading_number: + token.start = c; + token.type.number = jsonlite_number_int | jsonlite_number_digit_leading; +parse_digits: + if (++c == l) goto end_of_stream; + if (0x30 <= *c && *c <= 0x39) goto parse_digits; + switch(*c) { + CASE_NUMBER_TOKEN_END; + case 0x2E: goto parse_fraction; + case 0x45: goto parse_exponent; + case 0x65: goto parse_exponent; + default: goto error_number; } - -// State machine for string token parsing. -string_token_parsing: - { - jsonlite_string_type type = jsonlite_string_ascii; - uint32_t value, utf32; - token.start = c + 1; - next_char: - if (++c == l) goto end_of_stream; - if (*c == '"') goto string_parsed; - if (*c == '\\') goto escaped; - if (*c >= 0x80) goto utf8; - if (*c < 0x20) goto error_token; - goto next_char; - escaped: - type |= jsonlite_string_escape; - if (++c == l) goto end_of_stream; - switch (*c) { - case 34: goto next_char; - case 47: goto next_char; - case 92: goto next_char; - case 98: goto next_char; - case 102: goto next_char; - case 110: goto next_char; - case 114: goto next_char; - case 116: goto next_char; - case 117: goto hex; - } - goto error_escape; - hex: - type |= jsonlite_string_unicode_escape; - if (c++ + 4 >= l) goto end_of_stream; - CHECK_HEX(*c); value = jsonlite_hex_char_to_uint8(*c++); - CHECK_HEX(*c); value = (uint32_t)(value << 4) | jsonlite_hex_char_to_uint8(*c++); - CHECK_HEX(*c); value = (uint32_t)(value << 4) | jsonlite_hex_char_to_uint8(*c++); - CHECK_HEX(*c); value = (uint32_t)(value << 4) | jsonlite_hex_char_to_uint8(*c); - - if ((value & 0xFFFFu) >= 0xFFFEu) goto error_token; - if (value >= 0xFDD0u && value <= 0xFDEFu) goto error_token; - if (0xD800 > value || value > 0xDBFF) goto next_char; - - // UTF-16 Surrogate - utf32 = (value - 0xD800) << 10; - if (c++ + 6 >= l) goto end_of_stream; - if (*c++ != '\\') goto error_escape; - if (*c++ != 'u') goto error_escape; - CHECK_HEX(*c); value = jsonlite_hex_char_to_uint8(*c++); - CHECK_HEX(*c); value = (uint32_t)(value << 4) | jsonlite_hex_char_to_uint8(*c++); - CHECK_HEX(*c); value = (uint32_t)(value << 4) | jsonlite_hex_char_to_uint8(*c++); - CHECK_HEX(*c); value = (uint32_t)(value << 4) | jsonlite_hex_char_to_uint8(*c); +number_parsed: + token.end = c; + state--; + CALL_VALUE_CALLBACK(parser->callbacks, number_found, &token); + goto select_state; + +// String parsing +parse_string_token: + token.type.string = jsonlite_string_ascii; + token.start = c + 1; +next_char: + if (++c == l) goto end_of_stream; + if (*c == 0x22) goto string_parsed; + if (*c == 0x5C) goto escaped; + if (*c > 0x7F) goto utf8; + if (*c < 0x20) goto error_token; + goto next_char; +escaped: + token.type.string |= jsonlite_string_escape; + if (++c == l) goto end_of_stream; + switch (*c) { + case 0x22: goto next_char; // " quotation mark U+0022 + case 0x2F: goto next_char; // / solidus U+002F + case 0x5C: goto next_char; // \ reverse solidus U+005C + case 0x62: goto next_char; // b backspace U+0008 + case 0x66: goto next_char; // f form feed U+000C + case 0x6E: goto next_char; // n line feed U+000A + case 0x72: goto next_char; // r carriage return U+000D + case 0x74: goto next_char; // t tab U+0009 + case 0x75: goto hex; // uXXXX U+XXXX + default: goto error_escape; + } +hex: + token.type.string |= jsonlite_string_unicode_escape; + if (c++ + 4 >= l) goto end_of_stream; + HEX_CHAR_TO_INT(c, 1); value = hex_value; + HEX_CHAR_TO_INT(c, 1); value = (uint32_t)(value << 4) | hex_value; + HEX_CHAR_TO_INT(c, 1); value = (uint32_t)(value << 4) | hex_value; + HEX_CHAR_TO_INT(c, 0); value = (uint32_t)(value << 4) | hex_value; + + if ((value & 0xFFFFu) >= 0xFFFEu) token.type.string |= jsonlite_string_unicode_noncharacter; + if (value >= 0xFDD0u && value <= 0xFDEFu) token.type.string |= jsonlite_string_unicode_noncharacter; + if (0xD800 > value || value > 0xDBFF) goto next_char; + + // UTF-16 Surrogate + utf32 = (value - 0xD800) << 10; + if (c++ + 6 >= l) goto end_of_stream; + if (*c++ != 0x5C) goto error_escape; + if (*c++ != 0x75) goto error_escape; + HEX_CHAR_TO_INT(c, 1); value = hex_value; + HEX_CHAR_TO_INT(c, 1); value = (uint32_t)(value << 4) | hex_value; + HEX_CHAR_TO_INT(c, 1); value = (uint32_t)(value << 4) | hex_value; + HEX_CHAR_TO_INT(c, 0); value = (uint32_t)(value << 4) | hex_value; - if (value < 0xDC00 || value > 0xDFFF) goto error_escape; - utf32 += value - 0xDC00 + 0x10000; - if ((utf32 & 0x0FFFFu) >= 0x0FFFEu) goto error_token; - goto next_char; - utf8: - type |= jsonlite_string_utf8; - int res = jsonlite_clz(((*c) ^ 0xFF) << 0x19); - utf32 = (*c & (0xFF >> (res + 1))); - value = 0xAAAAAAAA; // == 1010... - if (c + res >= l) goto end_of_stream; - switch (res) { - case 3: value = (value << 2) | (*++c >> 6); utf32 = (utf32 << 6) | (*c & 0x3F); - case 2: value = (value << 2) | (*++c >> 6); utf32 = (utf32 << 6) | (*c & 0x3F); - case 1: value = (value << 2) | (*++c >> 6); utf32 = (utf32 << 6) | (*c & 0x3F); - if (value != 0xAAAAAAAA) goto error_utf8; - if ((utf32 & 0xFFFFu) >= 0xFFFEu) goto error_utf8; - if (utf32 >= 0xFDD0u && utf32 <= 0xFDEFu) goto error_utf8; - } - goto next_char; - string_parsed: - token.string_type = type; - token.end = c; - parser->cursor = c + 1; - if (*state == state_value) { - CALL_VALUE_CALLBACK(parser->callbacks, string_found, &token); - } else { - CALL_VALUE_CALLBACK(parser->callbacks, key_found, &token); - } - state--; - goto skip_char_and_spaces; + if (value < 0xDC00 || value > 0xDFFF) goto error_escape; + utf32 += value - 0xDC00 + 0x10000; + if ((utf32 & 0x0FFFFu) >= 0x0FFFEu) token.type.string |= jsonlite_string_unicode_noncharacter; + goto next_char; +utf8: + token.type.string |= jsonlite_string_utf8; + int res = jsonlite_clz((unsigned int)((*c) ^ 0xFF) << 0x19); + utf32 = (*c & (0xFF >> (res + 1))); + value = 0xAAAAAAAA; // == 1010... + if (c + res >= l) goto end_of_stream; + switch (res) { + case 3: value = (value << 2) | (*++c >> 6); utf32 = (utf32 << 6) | (*c & 0x3F); + case 2: value = (value << 2) | (*++c >> 6); utf32 = (utf32 << 6) | (*c & 0x3F); + case 1: value = (value << 2) | (*++c >> 6); utf32 = (utf32 << 6) | (*c & 0x3F); + if (value != 0xAAAAAAAA) goto error_utf8; + if ((utf32 & 0xFFFFu) >= 0xFFFEu) token.type.string |= jsonlite_string_unicode_noncharacter; + if (utf32 >= 0xFDD0u && utf32 <= 0xFDEFu) token.type.string |= jsonlite_string_unicode_noncharacter; } - -// Primitive tokens states. -true_token_parsing: + goto next_char; +string_parsed: + token.end = c; + parser->cursor = c + 1; + if (*state-- == state_value) { + CALL_VALUE_CALLBACK(parser->callbacks, string_found, &token); + } else { + CALL_VALUE_CALLBACK(parser->callbacks, key_found, &token); + } + goto skip_char_and_whitespaces; + +// Primitive tokens +parse_true_token: if (c++ + 3 >= l) goto end_of_stream; - if (*c++ != 'r') goto error_token; - if (*c++ != 'u') goto error_token; - if (*c++ != 'e') goto error_token; + if (*c++ != 0x72) goto error_token; + if (*c++ != 0x75) goto error_token; + if (*c++ != 0x65) goto error_token; + state--; CALL_STATE_CALLBACK(parser->callbacks, true_found); - state--; - goto state_selection; -false_token_paring: + goto select_state; +parse_false_token: if (c++ + 4 >= l) goto end_of_stream; - if (*c++ != 'a') goto error_token; - if (*c++ != 'l') goto error_token; - if (*c++ != 's') goto error_token; - if (*c++ != 'e') goto error_token; + if (*c++ != 0x61) goto error_token; + if (*c++ != 0x6C) goto error_token; + if (*c++ != 0x73) goto error_token; + if (*c++ != 0x65) goto error_token; + state--; CALL_STATE_CALLBACK(parser->callbacks, false_found); - state--; - goto state_selection; -null_token_parsing: + goto select_state; +parse_null_token: if (c++ + 3 >= l) goto end_of_stream; - if (*c++ != 'u') goto error_token; - if (*c++ != 'l') goto error_token; - if (*c++ != 'l') goto error_token; + if (*c++ != 0x75) goto error_token; + if (*c++ != 0x6C) goto error_token; + if (*c++ != 0x6C) goto error_token; + state--; CALL_STATE_CALLBACK(parser->callbacks, null_found); - state--; - goto state_selection; + goto select_state; -// Error handling states. -error_depth: parser->result = jsonlite_result_depth_limit; goto end; -error_exp_ooa: parser->result = jsonlite_result_expected_object_or_array; goto end; -error_exp_value: parser->result = jsonlite_result_expected_value; goto end; -error_exp_koe: parser->result = jsonlite_result_expected_key_or_end; goto end; -error_exp_key: parser->result = jsonlite_result_expected_key; goto end; -error_exp_colon: parser->result = jsonlite_result_expected_colon; goto end; -error_exp_coe: parser->result = jsonlite_result_expected_comma_or_end; goto end; -error_escape: parser->result = jsonlite_result_invalid_escape; goto end; -error_number: parser->result = jsonlite_result_invalid_number; goto end; -error_token: parser->result = jsonlite_result_invalid_token; goto end; -error_utf8: parser->result = jsonlite_result_invalid_utf8; goto end; -suspend: parser->result = jsonlite_result_suspended; goto end; +// Error states. +error_depth: result = jsonlite_result_depth_limit; goto end; +error_exp_ooa: result = jsonlite_result_expected_object_or_array; goto end; +error_exp_value: result = jsonlite_result_expected_value; goto end; +error_exp_koe: result = jsonlite_result_expected_key_or_end; goto end; +error_exp_key: result = jsonlite_result_expected_key; goto end; +error_exp_colon: result = jsonlite_result_expected_colon; goto end; +error_exp_coe: result = jsonlite_result_expected_comma_or_end; goto end; +error_escape: result = jsonlite_result_invalid_escape; goto end; +error_number: result = jsonlite_result_invalid_number; goto end; +error_token: result = jsonlite_result_invalid_token; goto end; +error_utf8: result = jsonlite_result_invalid_utf8; goto end; + // End of stream states. -end_of_stream_space: +end_of_stream_whitespaces: token_start = l; end_of_stream: - parser->result = jsonlite_result_end_of_stream; - goto end; - -success: - parser->result = jsonlite_result_ok; + result = jsonlite_result_end_of_stream; end: - parser->token_start = token_start; + parser->result = result; parser->current = state; + parser->control = NULL; parser->cursor = c; parser->callbacks.parse_finished(&parser->callbacks.context); -} - -static void jsonlite_finish_parse(jsonlite_parser parser) { - if (parser->result == jsonlite_result_suspended) { + if (result != jsonlite_result_end_of_stream) { return; } - - if (*parser->current == state_end) { - return; - } - - parser->rest_size = parser->limit - parser->token_start; - if (parser->rest_size > 0) { - parser->rest = malloc(parser->rest_size); - memcpy(parser->rest, parser->token_start, parser->rest_size); // LCOV_EXCL_LINE + + res = parser->buffer_own != NULL; + if ((parser->limit - token_start) > 0) { + parser->buffer_own = malloc(parser->limit - token_start); // LCOV_EXCL_LINE + parser->limit = parser->buffer_own + (parser->limit - token_start); + memcpy(parser->buffer_own, token_start, parser->limit - parser->buffer_own); + if (res) { + free((void *)parser->buffer); + parser->buffer = parser->buffer_own; + } + } else { + if (res) { + free((void *)parser->buffer_own); + parser->buffer = NULL; + parser->buffer_own = NULL; + } } } // @@ -579,618 +1181,221 @@ // limitations under the License #ifndef JSONLITE_AMALGAMATED -#include "../include/jsonlite_builder.h" +#include "../include/jsonlite_stream.h" #endif #include <stdlib.h> #include <string.h> -#include <stddef.h> -#include <stdint.h> - -#define jsonlite_builder_check_depth() \ -do { \ - if (builder->state - builder->stack >= builder->stack_depth - 1) { \ - return jsonlite_result_depth_limit; \ - } \ -} while (0) - -typedef enum { - jsonlite_accept_object_begin = 0x0001, - jsonlite_accept_object_end = 0x0002, - jsonlite_accept_array_begin = 0x0004, - jsonlite_accept_array_end = 0x0008, - - jsonlite_accept_key = 0x0010, - jsonlite_accept_string = 0x0020, - jsonlite_accept_number = 0x0040, - jsonlite_accept_boolean = 0x0080, - jsonlite_accept_null = 0x0100, - jsonlite_accept_values_only = 0x0200, - jsonlite_accept_next = 0x0400, - - jsonlite_accept_value = 0 - | jsonlite_accept_object_begin - | jsonlite_accept_array_begin - | jsonlite_accept_string - | jsonlite_accept_number - | jsonlite_accept_boolean - | jsonlite_accept_null, - - jsonlite_accept_continue_object = 0 - | jsonlite_accept_next - | jsonlite_accept_key - | jsonlite_accept_object_end, - jsonlite_accept_continue_array = 0 - | jsonlite_accept_next - | jsonlite_accept_values_only - | jsonlite_accept_value - | jsonlite_accept_array_end - -} jsonlite_accept; - -typedef struct jsonlite_write_state { - int accept; -} jsonlite_write_state; -typedef struct jsonlite_builder_buffer { - char data[2048]; - char *cursor; - char *limit; - struct jsonlite_builder_buffer *next; -} jsonlite_builder_buffer; - -typedef struct jsonlite_builder_struct { - jsonlite_builder_buffer *first; - jsonlite_builder_buffer *buffer; - - jsonlite_write_state *stack; - jsonlite_write_state *state; - ptrdiff_t stack_depth; - - char *doubleFormat; - - size_t indentation; -} jsonlite_builder_struct; +struct jsonlite_stream_struct { + jsonlite_stream_write_fn write; + jsonlite_stream_release_fn release; +} jsonlite_stream_struct; -static int jsonlite_builder_accept(jsonlite_builder builder, jsonlite_accept a); -static void jsonlite_builder_pop_state(jsonlite_builder builder); -static void jsonlite_builder_push_buffer(jsonlite_builder builder); -static void jsonlite_builder_prepare_value_writing(jsonlite_builder builder); -static void jsonlite_builder_raw_char(jsonlite_builder builder, char data); -static void jsonlite_builder_write_uft8(jsonlite_builder builder, const char *data, size_t length); -static void jsonlite_builder_raw(jsonlite_builder builder, const void *data, size_t length); -static void jsonlite_builder_repeat(jsonlite_builder builder, const char ch, size_t count); - -jsonlite_builder jsonlite_builder_init(size_t depth) { - jsonlite_builder builder; - - depth = depth < 2 ? 2 : depth; - - builder = (jsonlite_builder)calloc(1, sizeof(jsonlite_builder_struct) + depth * sizeof(jsonlite_write_state)); - builder->first = (jsonlite_builder_buffer *)malloc(sizeof(jsonlite_builder_buffer)); - builder->buffer = builder->first; - builder->buffer->cursor = builder->buffer->data; - builder->buffer->limit = builder->buffer->data + sizeof(builder->buffer->data); - builder->buffer->next = NULL; - - builder->stack = (jsonlite_write_state *)((uint8_t *)builder + sizeof(jsonlite_builder_struct)); - builder->stack_depth = depth; - builder->state = builder->stack; - builder->state->accept = jsonlite_accept_object_begin | jsonlite_accept_array_begin; - - builder->indentation = 0; - jsonlite_builder_set_double_format(builder, "%.16g"); - return builder; +int jsonlite_stream_write(jsonlite_stream stream, const void *data, size_t length) { + return stream->write(stream, data, length); } -jsonlite_result jsonlite_builder_release(jsonlite_builder builder) { - jsonlite_builder_buffer *b = NULL; - void *prev; - - if (builder == NULL) { - return jsonlite_result_invalid_argument; - } - - for (b = builder->first; b != NULL;) { - prev = b; - b = b->next; - free(prev); +void jsonlite_stream_release(jsonlite_stream stream) { + if (stream == NULL) { + return; } - free(builder->doubleFormat); - free(builder); - return jsonlite_result_ok; -} - -jsonlite_result jsonlite_builder_set_indentation(jsonlite_builder builder, size_t indentation) { - if (builder != NULL) { - builder->indentation = indentation; - return jsonlite_result_ok; - } - return jsonlite_result_invalid_argument; -} - -jsonlite_result jsonlite_builder_set_double_format(jsonlite_builder builder, const char *format) { - if (builder != NULL && format != NULL) { - builder->doubleFormat = strdup(format); - return jsonlite_result_ok; - } - return jsonlite_result_invalid_argument; -} - -static int jsonlite_builder_accept(jsonlite_builder builder, jsonlite_accept a) { - return (builder->state->accept & a) == a; -} - -static void jsonlite_builder_push_state(jsonlite_builder builder) { - builder->state++; -} - -static void jsonlite_builder_pop_state(jsonlite_builder builder) { - jsonlite_write_state *ws = --builder->state; - if (jsonlite_builder_accept(builder, jsonlite_accept_values_only) ) { - ws->accept = jsonlite_accept_continue_array; - } else { - ws->accept = jsonlite_accept_continue_object; + if (stream->release != NULL) { + stream->release(stream); } } -static void jsonlite_builder_push_buffer(jsonlite_builder builder) { - jsonlite_builder_buffer *buffer = builder->buffer; - buffer->next = malloc(sizeof(jsonlite_builder_buffer)); - buffer = builder->buffer = buffer->next; - - buffer->cursor = buffer->data; - buffer->limit = buffer->data + sizeof(buffer->data); - buffer->next = NULL; -} - -static void jsonlite_builder_prepare_value_writing(jsonlite_builder builder) { - jsonlite_write_state *ws = builder->state; - if (jsonlite_builder_accept(builder, jsonlite_accept_values_only) ) { - if (jsonlite_builder_accept(builder, jsonlite_accept_next) ) { - jsonlite_builder_raw_char(builder, ','); - } - if (builder->indentation != 0) { - jsonlite_builder_raw_char(builder, '\r'); - jsonlite_builder_repeat(builder, ' ', (builder->state - builder->stack) * builder->indentation); - } - } else { - ws->accept &= ~jsonlite_accept_value; - ws->accept |= jsonlite_accept_key; - } - ws->accept |= jsonlite_accept_next; -} - -jsonlite_result jsonlite_builder_object_begin(jsonlite_builder builder) { - if (builder == NULL) { - return jsonlite_result_invalid_argument; - } - - jsonlite_builder_check_depth(); - - if (jsonlite_builder_accept(builder, jsonlite_accept_object_begin)) { - jsonlite_builder_prepare_value_writing(builder); - jsonlite_builder_push_state(builder); - builder->state->accept = jsonlite_accept_object_end | jsonlite_accept_key; - jsonlite_builder_raw_char(builder, '{'); - return jsonlite_result_ok; - } - - return jsonlite_result_not_allowed; -} - -jsonlite_result jsonlite_builder_object_end(jsonlite_builder builder) { - if (builder == NULL) { - return jsonlite_result_invalid_argument; - } - - if (jsonlite_builder_accept(builder, jsonlite_accept_object_end)) { - jsonlite_builder_pop_state(builder); - if (builder->indentation != 0) { - jsonlite_builder_raw_char(builder, '\r'); - jsonlite_builder_repeat(builder, ' ', (builder->state - builder->stack) * builder->indentation); - } - jsonlite_builder_raw_char(builder, '}'); - return jsonlite_result_ok; - } - - return jsonlite_result_not_allowed; -} - -jsonlite_result jsonlite_builder_array_begin(jsonlite_builder builder) { - if (builder == NULL) { - return jsonlite_result_invalid_argument; - } - - jsonlite_builder_check_depth(); - - if (jsonlite_builder_accept(builder, jsonlite_accept_array_begin)) { - jsonlite_builder_prepare_value_writing(builder); - jsonlite_builder_push_state(builder); - builder->state->accept = jsonlite_accept_array_end - | jsonlite_accept_value - | jsonlite_accept_values_only; - jsonlite_builder_raw_char(builder, '['); - return jsonlite_result_ok; - } - - return jsonlite_result_not_allowed; -} - -jsonlite_result jsonlite_builder_array_end(jsonlite_builder builder) { - if (builder == NULL) { - return jsonlite_result_invalid_argument; - } - - if (jsonlite_builder_accept(builder, jsonlite_accept_array_end)) { - jsonlite_builder_pop_state(builder); - if (builder->indentation != 0) { - jsonlite_builder_raw_char(builder, '\r'); - jsonlite_builder_repeat(builder, ' ', (builder->state - builder->stack) * builder->indentation); - } - jsonlite_builder_raw_char(builder, ']'); - return jsonlite_result_ok; - } - - return jsonlite_result_not_allowed; +static void jsonlite_stream_free_mem(jsonlite_stream stream) { + free((void *)stream); } -static void jsonlite_builder_write_uft8(jsonlite_builder builder, const char *data, size_t length) { - size_t i; - jsonlite_builder_raw_char(builder, '\"'); - for (i = 0; i < length; i++) { - switch (data[i]) { - case '"': - jsonlite_builder_raw(builder, "\\\"", 2); - break; - case '\\': - jsonlite_builder_raw(builder, "\\\\", 2); - break; - case '\b': - jsonlite_builder_raw(builder, "\\b", 2); - break; - case '\f': - jsonlite_builder_raw(builder, "\\f", 2); - break; - case '\n': - jsonlite_builder_raw(builder, "\\n", 2); - break; - case '\r': - jsonlite_builder_raw(builder, "\\r", 2); - break; - case '\t': - jsonlite_builder_raw(builder, "\\t", 2); - break; - default: - jsonlite_builder_raw_char(builder, data[i]); - break; - } +#define CAST_TO_MEM_STREAM(S) (jsonlite_mem_stream *)((uint8_t *)(S) + sizeof(jsonlite_stream_struct)) +#define SIZE_OF_MEM_STREAM() (sizeof(jsonlite_stream_struct) + sizeof(jsonlite_mem_stream)) + +typedef struct jsonlite_mem_stream_block { + struct jsonlite_mem_stream_block *next; + uint8_t *data; +} jsonlite_mem_stream_block; + +typedef struct jsonlite_mem_stream { + size_t block_size; + uint8_t *cursor; + uint8_t *limit; + struct jsonlite_mem_stream_block *current; + struct jsonlite_mem_stream_block *first; +} jsonlite_mem_stream; + +static int jsonlite_mem_stream_write(jsonlite_stream stream, const void *data, size_t length) { + jsonlite_mem_stream *mem_stream = CAST_TO_MEM_STREAM(stream); + size_t write_limit = mem_stream->limit - mem_stream->cursor; + if (write_limit >= length) { + memcpy(mem_stream->cursor, data, length); // LCOV_EXCL_LINE + mem_stream->cursor += length; + } else { + memcpy(mem_stream->cursor, data, write_limit); // LCOV_EXCL_LINE + mem_stream->cursor += write_limit; + + size_t size = sizeof(jsonlite_mem_stream_block) + mem_stream->block_size; + jsonlite_mem_stream_block *block = malloc(size); + block->data = (uint8_t *)block + sizeof(jsonlite_mem_stream_block); + block->next = NULL; + + mem_stream->current->next = block; + mem_stream->current = block; + mem_stream->cursor = block->data; + mem_stream->limit = block->data + mem_stream->block_size; + + jsonlite_mem_stream_write(stream, (char *)data + write_limit, length - write_limit); } - jsonlite_builder_raw_char(builder, '\"'); + + return (int)length; } -jsonlite_result jsonlite_builder_key(jsonlite_builder builder, const char *data, size_t length) { - jsonlite_write_state *ws; - - if (builder == NULL || data == NULL) { - return jsonlite_result_invalid_argument; +static void jsonlite_mem_stream_release(jsonlite_stream stream) { + jsonlite_mem_stream *mem_stream = CAST_TO_MEM_STREAM(stream); + jsonlite_mem_stream_block *block = mem_stream->first; + void *prev; + for (; block != NULL;) { + prev = block; + block = block->next; + free(prev); } - - ws = builder->state; - if (jsonlite_builder_accept(builder, jsonlite_accept_key) ) { - if (jsonlite_builder_accept(builder, jsonlite_accept_next) ) { - jsonlite_builder_raw_char(builder, ','); - } - if (builder->indentation != 0) { - jsonlite_builder_raw_char(builder, '\r'); - jsonlite_builder_repeat(builder, ' ', (builder->state - builder->stack) * builder->indentation); - } - jsonlite_builder_write_uft8(builder, data, length); - if (builder->indentation != 0) { - jsonlite_builder_raw(builder, ": ", 2); - } else { - jsonlite_builder_raw_char(builder, ':'); - } - ws->accept = jsonlite_accept_value; - return jsonlite_result_ok; - } - - return jsonlite_result_not_allowed; + free((void *)stream); } -jsonlite_result jsonlite_builder_string(jsonlite_builder builder, const char *data, size_t length) { - jsonlite_write_state *ws; - - if (builder == NULL || data == NULL) { - return jsonlite_result_invalid_argument; - } - - ws = builder->state; - - if (jsonlite_builder_accept(builder, jsonlite_accept_value) ) { - jsonlite_builder_prepare_value_writing(builder); - jsonlite_builder_write_uft8(builder, data, length); - if (jsonlite_builder_accept(builder, jsonlite_accept_values_only) ) { - ws->accept = jsonlite_accept_continue_array; - } else { - ws->accept = jsonlite_accept_continue_object; - } - return jsonlite_result_ok; - } - - return jsonlite_result_not_allowed; -} +jsonlite_stream jsonlite_mem_stream_init(size_t block_size) { + size_t size = SIZE_OF_MEM_STREAM(); + struct jsonlite_stream_struct *stream = malloc(size); + stream->write = jsonlite_mem_stream_write; + stream->release = jsonlite_mem_stream_release; -jsonlite_result jsonlite_builder_int(jsonlite_builder builder, long long value) { - jsonlite_write_state *ws; - char buff[128]; - int size = 0; - - if (builder == NULL) { - return jsonlite_result_invalid_argument; - } - - ws = builder->state; + jsonlite_mem_stream_block *first = malloc(sizeof(jsonlite_mem_stream_block) + block_size); + first->data = (uint8_t *)first + sizeof(jsonlite_mem_stream_block); + first->next = NULL; - if (jsonlite_builder_accept(builder, jsonlite_accept_value) ) { - jsonlite_builder_prepare_value_writing(builder); - size = sprintf(buff, "%lld", value); - jsonlite_builder_raw(builder, buff, size); - if (jsonlite_builder_accept(builder, jsonlite_accept_values_only) ) { - ws->accept = jsonlite_accept_continue_array; - } else { - ws->accept = jsonlite_accept_continue_object; - } - return jsonlite_result_ok; - } - - return jsonlite_result_not_allowed; + jsonlite_mem_stream *mem_stream = CAST_TO_MEM_STREAM(stream); + mem_stream->block_size = block_size; + mem_stream->cursor = first->data; + mem_stream->limit = first->data + block_size; + mem_stream->current = first; + mem_stream->first = first; + return stream; } -jsonlite_result jsonlite_builder_double(jsonlite_builder builder, double value) { - jsonlite_write_state *ws; - char buff[128]; - int size = 0; - - if (builder == NULL) { - return jsonlite_result_invalid_argument; - } - - ws = builder->state; - - if (jsonlite_builder_accept(builder, jsonlite_accept_value) ) { - jsonlite_builder_prepare_value_writing(builder); - size = sprintf(buff, builder->doubleFormat, value); - jsonlite_builder_raw(builder, buff, size); - if (jsonlite_builder_accept(builder, jsonlite_accept_values_only) ) { - ws->accept = jsonlite_accept_continue_array; - } else { - ws->accept = jsonlite_accept_continue_object; - } - return jsonlite_result_ok; - } - - return jsonlite_result_not_allowed; -} - -jsonlite_result jsonlite_builder_true(jsonlite_builder builder) { - static const char value[] = "true"; - jsonlite_write_state *ws; +size_t jsonlite_mem_stream_data(jsonlite_stream stream, uint8_t **data, size_t extra_bytes) { + jsonlite_mem_stream *mem_stream = CAST_TO_MEM_STREAM(stream); + jsonlite_mem_stream_block *block = NULL; + uint8_t *buff = NULL; + size_t size = 0; - if (builder == NULL) { - return jsonlite_result_invalid_argument; - } - - ws = builder->state; - if (!(jsonlite_builder_accept(builder, jsonlite_accept_value) )) { - - return jsonlite_result_not_allowed; - } - - jsonlite_builder_prepare_value_writing(builder); - jsonlite_builder_raw(builder, (char *)value, sizeof(value) - 1); - if (jsonlite_builder_accept(builder, jsonlite_accept_values_only) ) { - ws->accept = jsonlite_accept_continue_array; - } else { - ws->accept = jsonlite_accept_continue_object; - } - return jsonlite_result_ok; -} - -jsonlite_result jsonlite_builder_false(jsonlite_builder builder) { - static const char value[] = "false"; - jsonlite_write_state *ws; - - if (builder == NULL) { - return jsonlite_result_invalid_argument; - } - - ws = builder->state; - if (!(jsonlite_builder_accept(builder, jsonlite_accept_value) )) { - - return jsonlite_result_not_allowed; + for (block = mem_stream->first; block != NULL; block = block->next) { + if (block->next != NULL) { + size += mem_stream->block_size; + } else { + size += mem_stream->cursor - block->data; + } } - jsonlite_builder_prepare_value_writing(builder); - jsonlite_builder_raw(builder, (char *)value, sizeof(value) - 1); - if (jsonlite_builder_accept(builder, jsonlite_accept_values_only) ) { - ws->accept = jsonlite_accept_continue_array; + if (size == 0) { + *data = NULL; } else { - ws->accept = jsonlite_accept_continue_object; - } - return jsonlite_result_ok; -} - -jsonlite_result jsonlite_builder_null(jsonlite_builder builder) { - static const char value[] = "null"; - jsonlite_write_state *ws; - - if (builder == NULL) { - return jsonlite_result_invalid_argument; - } - - ws = builder->state; - if (!(jsonlite_builder_accept(builder, jsonlite_accept_value) )) { - - return jsonlite_result_not_allowed; + *data = (uint8_t *)malloc(size + extra_bytes); + buff = *data; + for (block = mem_stream->first; block != NULL; block = block->next) { + if (block->next != NULL) { + memcpy(buff, block->data, mem_stream->block_size); // LCOV_EXCL_LINE + buff += mem_stream->block_size; + } else { + memcpy(buff, block->data, mem_stream->cursor - block->data); // LCOV_EXCL_LINE + } + } } - - jsonlite_builder_prepare_value_writing(builder); - jsonlite_builder_raw(builder, (char *)value, sizeof(value) - 1); - if (jsonlite_builder_accept(builder, jsonlite_accept_values_only) ) { - ws->accept = jsonlite_accept_continue_array; - } else { - ws->accept = jsonlite_accept_continue_object; - } - return jsonlite_result_ok; -} - -static void jsonlite_builder_raw(jsonlite_builder builder, const void *data, size_t length) { - jsonlite_builder_buffer *buffer = builder->buffer; - size_t write_limit = buffer->limit - buffer->cursor; - if (write_limit >= length) { - memcpy(buffer->cursor, data, length); // LCOV_EXCL_LINE - buffer->cursor += length; - } else { - memcpy(buffer->cursor, data, write_limit); // LCOV_EXCL_LINE - buffer->cursor += write_limit; - - jsonlite_builder_push_buffer(builder); - jsonlite_builder_raw(builder, (char *)data + write_limit, length - write_limit); - } + + return size; } -static void jsonlite_builder_repeat(jsonlite_builder builder, const char ch, size_t count) { - jsonlite_builder_buffer *buffer = builder->buffer; - size_t write_limit = buffer->limit - buffer->cursor; - if (write_limit >= count) { - memset(buffer->cursor, ch, count); // LCOV_EXCL_LINE - buffer->cursor += count; +#define CAST_TO_STATIC_MEM_STREAM(S) (jsonlite_static_mem_stream *)((uint8_t *)(S) + sizeof(jsonlite_stream_struct)) +#define SIZE_OF_STATIC_MEM_STREAM() (sizeof(jsonlite_stream_struct) + sizeof(jsonlite_static_mem_stream)) + +typedef struct jsonlite_static_mem_stream { + uint8_t *buffer; + size_t size; + size_t written; + uint8_t *limit; + int enabled; +} jsonlite_static_mem_stream; + +static int jsonlite_static_mem_stream_write(jsonlite_stream stream, const void *data, size_t length) { + jsonlite_static_mem_stream *mem_stream = CAST_TO_STATIC_MEM_STREAM(stream); + size_t write_limit = mem_stream->size - mem_stream->written; + if (mem_stream->enabled && write_limit >= length) { + memcpy(mem_stream->buffer + mem_stream->written, data, length); // LCOV_EXCL_LINE + mem_stream->written += length; } else { - memset(buffer->cursor, ch, write_limit); // LCOV_EXCL_LINE - buffer->cursor += write_limit; - - jsonlite_builder_push_buffer(builder); - jsonlite_builder_repeat(builder, ch, count - write_limit); + mem_stream->enabled = 0; + return 0; } -} -static void jsonlite_builder_raw_char(jsonlite_builder builder, char data) { - jsonlite_builder_buffer *buffer = builder->buffer; - if (buffer->cursor >= buffer->limit) { - jsonlite_builder_push_buffer(builder); - } - *builder->buffer->cursor++ = data; + return (int)length; } -jsonlite_result jsonlite_builder_raw_key(jsonlite_builder builder, const void *data, size_t length) { - jsonlite_write_state *ws; +jsonlite_stream jsonlite_static_mem_stream_init(void *buffer, size_t size) { + size_t s = SIZE_OF_STATIC_MEM_STREAM(); + struct jsonlite_stream_struct *stream = malloc(s); + stream->write = jsonlite_static_mem_stream_write; + stream->release = jsonlite_stream_free_mem; - if (builder == NULL || data == NULL || length == 0) { - return jsonlite_result_invalid_argument; - } - - ws = builder->state; - if (jsonlite_builder_accept(builder, jsonlite_accept_key) ) { - if (jsonlite_builder_accept(builder, jsonlite_accept_next) ) { - jsonlite_builder_raw(builder, ",", 1); - } - - if (builder->indentation != 0) { - jsonlite_builder_raw_char(builder, '\r'); - jsonlite_builder_repeat(builder, ' ', (builder->state - builder->stack) * builder->indentation); - } - jsonlite_builder_raw_char(builder, '\"'); - jsonlite_builder_raw(builder, data, length); - jsonlite_builder_raw_char(builder, '\"'); - if (builder->indentation != 0) { - jsonlite_builder_raw(builder, ": ", 2); - } else { - jsonlite_builder_raw_char(builder, ':'); - } - ws->accept = jsonlite_accept_value; - return jsonlite_result_ok; - } - - return jsonlite_result_not_allowed; + jsonlite_static_mem_stream *mem_stream = CAST_TO_STATIC_MEM_STREAM(stream); + mem_stream->buffer = buffer; + mem_stream->size = size; + mem_stream->written = 0; + mem_stream->enabled = 1; + return stream; } -jsonlite_result jsonlite_builder_raw_string(jsonlite_builder builder, const void *data, size_t length) { - jsonlite_write_state *ws; - - if (builder == NULL || data == NULL || length == 0) { - return jsonlite_result_invalid_argument; - } - - ws = builder->state; - - if (jsonlite_builder_accept(builder, jsonlite_accept_value) ) { - jsonlite_builder_prepare_value_writing(builder); - jsonlite_builder_raw_char(builder, '\"'); - jsonlite_builder_raw(builder, data, length); - jsonlite_builder_raw_char(builder, '\"'); - if (jsonlite_builder_accept(builder, jsonlite_accept_values_only) ) { - ws->accept = jsonlite_accept_continue_array; - } else { - ws->accept = jsonlite_accept_continue_object; - } - return jsonlite_result_ok; - } - - return jsonlite_result_not_allowed; +size_t jsonlite_static_mem_stream_written_bytes(jsonlite_stream stream) { + jsonlite_static_mem_stream *mem_stream = CAST_TO_STATIC_MEM_STREAM(stream); + return mem_stream->written; +} + +#define CAST_TO_FILE_STREAM(S) (jsonlite_file_stream *)((uint8_t *)(S) + sizeof(jsonlite_stream_struct)) +#define SIZE_OF_FILE_STREAM() (sizeof(jsonlite_stream_struct) + sizeof(jsonlite_file_stream)) + +typedef struct jsonlite_file_stream { + FILE *file; +} jsonlite_file_stream; + +static int jsonlite_file_stream_write(jsonlite_stream stream, const void *data, size_t length) { + jsonlite_file_stream *file_stream = CAST_TO_FILE_STREAM(stream); + return (int)fwrite(data, 1, length, file_stream->file); } -jsonlite_result jsonlite_builder_raw_value(jsonlite_builder builder, const void *data, size_t length) { - jsonlite_write_state *ws; - - if (builder == NULL || data == NULL || length == 0) { - return jsonlite_result_invalid_argument; - } - - ws = builder->state; +jsonlite_stream jsonlite_file_stream_init(FILE *file) { + size_t size = SIZE_OF_FILE_STREAM(); + struct jsonlite_stream_struct *stream = malloc(size); + stream->write = jsonlite_file_stream_write; + stream->release = jsonlite_stream_free_mem; - if (jsonlite_builder_accept(builder, jsonlite_accept_value) ) { - jsonlite_builder_prepare_value_writing(builder); - jsonlite_builder_raw(builder, data, length); - if (jsonlite_builder_accept(builder, jsonlite_accept_values_only) ) { - ws->accept = jsonlite_accept_continue_array; - } else { - ws->accept = jsonlite_accept_continue_object; - } - return jsonlite_result_ok; - } - - return jsonlite_result_not_allowed; + jsonlite_file_stream *file_stream = CAST_TO_FILE_STREAM(stream); + file_stream->file = file; + return stream; } -jsonlite_result jsonlite_builder_data(jsonlite_builder builder, char **data, size_t *size) { - jsonlite_builder_buffer *b; - char *buff = NULL; +static int jsonlite_null_stream_write(jsonlite_stream stream, const void *data, size_t length) { + return (int)length; +} - if (builder == NULL || data == NULL || size == NULL) { - return jsonlite_result_invalid_argument; - } - - *size = 0; - for (b = builder->first; b != NULL; b = b->next) { - *size += b->cursor - b->data; - } - - if (*size == 0) { - return jsonlite_result_not_allowed; - } - - *data = (char*)calloc(*size, 1); - buff = *data; - for (b = builder->first; b != NULL; b = b->next) { - size_t s = b->cursor - b->data; - memcpy(buff, b->data, s); // LCOV_EXCL_LINE - buff += s; - } - return jsonlite_result_ok; +static int jsonlite_stdout_stream_write(jsonlite_stream stream, const void *data, size_t length) { + return (int)fwrite(data, 1, length, stdout); } + +static struct jsonlite_stream_struct jsonlite_stdout_stream_struct = {jsonlite_stdout_stream_write, NULL}; +static struct jsonlite_stream_struct jsonlite_null_stream_struct = {jsonlite_null_stream_write, NULL}; + +jsonlite_stream jsonlite_stdout_stream = &jsonlite_stdout_stream_struct; +jsonlite_stream jsonlite_null_stream = &jsonlite_null_stream_struct; // // Copyright 2012-2013, Andrii Mamchur // @@ -1227,50 +1432,42 @@ #endif -uint8_t jsonlite_hex_char_to_uint8(uint8_t c) { - uint8_t res = 0xFF; - if (c >= '0' && c <= '9') { - res = c - '0'; - } else if (c >= 'a' && c <= 'f') { - res = c - 'a' + 10; - } else if (c >= 'A' && c <= 'F') { - res = c - 'A' + 10; +static uint8_t jsonlite_hex_char_to_uint8(uint8_t c) { + if (c >= 'a') { + return c - 'a' + 10; } - return res; + + if (c >= 'A') { + return c - 'A' + 10; + } + + return c - '0'; } static int unicode_char_to_utf16(uint32_t ch, uint16_t *utf16) { uint32_t v = ch - 0x10000; uint32_t vh = v >> 10; uint32_t vl = v & 0x3FF; - if (ch <= 0xFFFF) { + if (ch <= 0xFFFF) { *utf16 = (uint16_t)ch; return 1; } - + *utf16++ = (uint16_t)(0xD800 + vh); *utf16 = (uint16_t)(0xDC00 + vl); return 2; } -size_t jsonlite_token_decode_size_for_uft8(jsonlite_token *ts) { - if (ts == NULL) { - return 0; - } - - return ts->end - ts->start + 1; +size_t jsonlite_token_size_of_uft8(jsonlite_token *ts) { + return (size_t)(ts->end - ts->start + 1); } -size_t jsonlite_token_decode_to_uft8(jsonlite_token *ts, uint8_t **buffer) { - size_t size = jsonlite_token_decode_size_for_uft8(ts); - if (size == 0 || buffer == NULL) { - return 0; - } - +size_t jsonlite_token_to_uft8(jsonlite_token *ts, uint8_t **buffer) { + size_t size = jsonlite_token_size_of_uft8(ts); const uint8_t *p = ts->start; const uint8_t *l = ts->end; uint32_t value, utf32; - uint8_t *c = *buffer = (uint8_t *)malloc(size); + uint8_t *c = *buffer = (uint8_t *)malloc(size); int res; step: if (p == l) goto done; @@ -1288,16 +1485,16 @@ case 110: *c++ = '\n'; p++; goto step; case 114: *c++ = '\r'; p++; goto step; case 116: *c++ = '\t'; p++; goto step; - } + } - // UTF-16 + // UTF-16 p++; utf32 = jsonlite_hex_char_to_uint8(*p++); utf32 = (uint32_t)(utf32 << 4) | jsonlite_hex_char_to_uint8(*p++); utf32 = (uint32_t)(utf32 << 4) | jsonlite_hex_char_to_uint8(*p++); utf32 = (uint32_t)(utf32 << 4) | jsonlite_hex_char_to_uint8(*p++); if (0xD800 > utf32 || utf32 > 0xDBFF) goto encode; - + // UTF-16 Surrogate p += 2; utf32 = (utf32 - 0xD800) << 10; @@ -1346,25 +1543,17 @@ return c - *buffer; } -size_t jsonlite_token_decode_size_for_uft16(jsonlite_token *ts) { - if (ts == NULL) { - return 0; - } - +size_t jsonlite_token_size_of_uft16(jsonlite_token *ts) { return (ts->end - ts->start + 1) * sizeof(uint16_t); } -size_t jsonlite_token_decode_to_uft16(jsonlite_token *ts, uint16_t **buffer) { - size_t size = jsonlite_token_decode_size_for_uft16(ts); - if (size == 0 || buffer == NULL) { - return 0; - } - +size_t jsonlite_token_to_uft16(jsonlite_token *ts, uint16_t **buffer) { + size_t size = jsonlite_token_size_of_uft16(ts); const uint8_t *p = ts->start; const uint8_t *l = ts->end; uint16_t utf16; uint16_t *c = *buffer = (uint16_t *)malloc(size); - int res; + int res; step: if (p == l) goto done; if (*p == '\\') goto escaped; @@ -1381,8 +1570,8 @@ case 110: *c++ = '\n'; p++; goto step; case 114: *c++ = '\r'; p++; goto step; case 116: *c++ = '\t'; p++; goto step; - } - + } + // UTF-16 p++; utf16 = jsonlite_hex_char_to_uint8(*p++); @@ -1391,7 +1580,7 @@ utf16 = (uint16_t)(utf16 << 4) | jsonlite_hex_char_to_uint8(*p++); *c++ = utf16; if (0xD800 > utf16 || utf16 > 0xDBFF) goto step; - + // UTF-16 Surrogate p += 2; utf16 = jsonlite_hex_char_to_uint8(*p++); @@ -1409,13 +1598,110 @@ case 1: code = (code << 6) | (*++p & 0x3F); case 0: ++p; } - + c += unicode_char_to_utf16(code, c); goto step; done: *c = 0; return (c - *buffer) * sizeof(uint16_t); } + +size_t jsonlite_token_size_of_base64_binary(jsonlite_token *ts) { + return (((ts->end - ts->start) * 3) / 4 + 3) & ~3; +} + +size_t jsonlite_token_base64_to_binary(jsonlite_token *ts, void **buffer) { + size_t length = 0; + size_t size = jsonlite_token_size_of_base64_binary(ts); + const uint8_t *p = ts->start; + const uint8_t *l = ts->end; + uint8_t *c; + size_t bytes, i; + if (size > 0) { + c = *buffer = (uint16_t *)malloc(size); + } else { + *buffer = NULL; + goto error; + } +next: + bytes = 0; + i = 0; + do { + if (p == l) goto error; + i++; + bytes <<= 6; + if (0x41 <= *p && *p <= 0x5A) { bytes |= *p++ - 0x41; continue; } + if (0x61 <= *p && *p <= 0x7A) { bytes |= *p++ - 0x47; continue; } + if (0x30 <= *p && *p <= 0x39) { bytes |= *p++ + 0x04; continue; } + if (*p == 0x2B) { bytes |= 0x3E; p++; continue; } + if (*p == 0x2F) { bytes |= 0x3F; p++; continue; } + if (*p == '=') { + switch (l - p) { + case 1: + *c++ = (uint8_t)((bytes >> 16) & 0x000000FF); + *c = (uint8_t)((bytes >> 8) & 0x000000FF); + return length + 2; + case 2: + *c = (uint8_t)((bytes >> 10) & 0x000000FF); + return length + 1; + } + } + if (*p == 0x5C && *++p == 0x2F) { bytes |= 0x3F; p++; continue; } + goto error; + } while (i < 4); + + *c++ = (uint8_t)((bytes >> 16) & 0x000000FF); + *c++ = (uint8_t)((bytes >> 8) & 0x000000FF); + *c++ = (uint8_t)((bytes) & 0x000000FF); + length += 3; + + if (p == l) goto done; + goto next; +error: + free(*buffer); + *buffer = NULL; + length = 0; +done: + return length; +} + +long jsonlite_token_to_long(jsonlite_token *token) { + long res = 0; + int negative = (token->type.number & jsonlite_number_negative) == jsonlite_number_negative; + ptrdiff_t length = token->end - token->start - negative; + const uint8_t *c = token->start + negative; + switch (length & 3) { + for (; length > 0; length -= 4) { + case 0: res = res * 10 + *c++ - '0'; + case 3: res = res * 10 + *c++ - '0'; + case 2: res = res * 10 + *c++ - '0'; + case 1: res = res * 10 + *c++ - '0'; + } + } + + return negative ? -res : res; +} + +long long jsonlite_token_to_long_long(jsonlite_token *token) { + long long res = 0; + int negative = (token->type.number & jsonlite_number_negative) == jsonlite_number_negative; + ptrdiff_t length = token->end - token->start - negative; + const uint8_t *c = token->start + negative; + switch (length & 7) { + for (; length > 0; length -= 8) { + case 0: res = res * 10 + *c++ - '0'; + case 7: res = res * 10 + *c++ - '0'; + case 6: res = res * 10 + *c++ - '0'; + case 5: res = res * 10 + *c++ - '0'; + case 4: res = res * 10 + *c++ - '0'; + case 3: res = res * 10 + *c++ - '0'; + case 2: res = res * 10 + *c++ - '0'; + case 1: res = res * 10 + *c++ - '0'; + } + } + + return negative ? -res : res; +} // // Copyright 2012-2013, Andrii Mamchur // @@ -1441,173 +1727,143 @@ #define JSONLITE_TOKEN_POOL_FRONT 0x80 #define JSONLITE_TOKEN_POOL_FRONT_MASK (JSONLITE_TOKEN_POOL_FRONT - 1) -typedef struct content_pool_size { - jsonlite_token_bucket *buckets[JSONLITE_TOKEN_POOL_FRONT]; - size_t buckets_length[JSONLITE_TOKEN_POOL_FRONT]; - size_t buckets_capacity[JSONLITE_TOKEN_POOL_FRONT]; - +typedef struct jsonlite_token_block { + jsonlite_token_bucket *buckets; + size_t capacity; +} jsonlite_token_block; + +typedef struct jsonlite_token_pool_struct { + jsonlite_token_block blocks[JSONLITE_TOKEN_POOL_FRONT]; uint8_t *content_pool; size_t content_pool_size; - jsonlite_token_pool_release_value_fn release_fn; - + } jsonlite_token_pool_struct; -static void jsonlite_extend_capacity(jsonlite_token_pool pool, int index); -static int jsonlite_bucket_not_copied(jsonlite_token_pool pool, jsonlite_token_bucket *b); -static int jsonlite_token_compare(const uint8_t *t1, const uint8_t *t2, size_t length); +static void jsonlite_extend_capacity(jsonlite_token_pool pool, ptrdiff_t index); static uint32_t jsonlite_hash(const uint8_t *data, size_t len); +static jsonlite_token_bucket terminate_bucket = {NULL, NULL, 0, 0, NULL}; jsonlite_token_pool jsonlite_token_pool_create(jsonlite_token_pool_release_value_fn release_fn) { - jsonlite_token_pool pool = (jsonlite_token_pool)calloc(1, sizeof(jsonlite_token_pool_struct)); + jsonlite_token_pool pool = (jsonlite_token_pool)malloc(sizeof(jsonlite_token_pool_struct)); + int i; + for (i = 0; i < JSONLITE_TOKEN_POOL_FRONT; i++) { + pool->blocks[i].buckets = &terminate_bucket; + pool->blocks[i].capacity = 0; + } pool->release_fn = release_fn; + pool->content_pool = NULL; + pool->content_pool_size = 0; return pool; } void jsonlite_token_pool_copy_tokens(jsonlite_token_pool pool) { - jsonlite_token_bucket *b; - size_t size = pool->content_pool_size; + jsonlite_token_bucket *bucket; + size_t size = 0; int i; - for (i = 0; i < JSONLITE_TOKEN_POOL_FRONT; i++) { - b = pool->buckets[i]; - if (jsonlite_bucket_not_copied(pool, b)) { - size += b->end - b->start; + bucket = pool->blocks[i].buckets; + while (bucket->start != NULL) { + size += bucket->end - bucket->start; + bucket++; } } - + if (size == pool->content_pool_size) { return; } - - uint8_t *buffer = (uint8_t *)malloc(size); - ptrdiff_t offset = 0; - if (pool->content_pool != NULL) { - offset = buffer - pool->content_pool; - memcpy(buffer, pool->content_pool, pool->content_pool_size); // LCOV_EXCL_LINE - } - - uint8_t *p = buffer + pool->content_pool_size; + + uint8_t *buffer = (uint8_t *)malloc(size); + uint8_t *p = buffer; for (i = 0; i < JSONLITE_TOKEN_POOL_FRONT; i++) { - b = pool->buckets[i]; - if (b == NULL) { - continue; - } - - if (jsonlite_bucket_not_copied(pool, b)) { - size_t length = b->end - b->start; - memcpy(p, b->start, length); // LCOV_EXCL_LINE - b->start = p, - b->end = p + length, + bucket = pool->blocks[i].buckets; + while (bucket->start != NULL) { + size_t length = bucket->end - bucket->start; + memcpy(p, bucket->start, length); // LCOV_EXCL_LINE + bucket->start = p; + bucket->end = p + length; p += length; - } else { - b->start += offset; - b->end += offset; + bucket++; } } - + free(pool->content_pool); pool->content_pool = buffer; pool->content_pool_size = size; } void jsonlite_token_pool_release(jsonlite_token_pool pool) { - int i, j; - if (pool == NULL) { - return; - } - + int i; for (i = 0; i < JSONLITE_TOKEN_POOL_FRONT; i++) { - jsonlite_token_bucket *bucket = pool->buckets[i]; - if (bucket == NULL) { + jsonlite_token_bucket *bucket = pool->blocks[i].buckets; + if (bucket->start == NULL) { continue; } - + if (pool->release_fn != NULL) { - size_t count = pool->buckets_length[i]; - for (j = 0; j < count; j++, bucket++) { - pool->release_fn((void *)bucket->value); + for (; bucket->start != NULL; bucket++) { + pool->release_fn((void *)bucket->value); } } - free(pool->buckets[i]); + free(pool->blocks[i].buckets); } - + free(pool->content_pool); free(pool); } jsonlite_token_bucket* jsonlite_token_pool_get_bucket(jsonlite_token_pool pool, jsonlite_token *token) { - if (pool == NULL || token == NULL) { - return NULL; - } - - if (token->start == NULL || token->end == NULL) { - return NULL; - } - - size_t length = token->end - token->start; - uint32_t hash = jsonlite_hash(token->start, length); - uint32_t index = hash & JSONLITE_TOKEN_POOL_FRONT_MASK; - jsonlite_token_bucket *bucket = pool->buckets[index]; - size_t count = pool->buckets_length[index]; - for (; count > 0; count--, bucket++) { + ptrdiff_t length = token->end - token->start; + ptrdiff_t hash = jsonlite_hash(token->start, (size_t)length); + ptrdiff_t index = hash & JSONLITE_TOKEN_POOL_FRONT_MASK; + size_t count = 0; + jsonlite_token_bucket *bucket = pool->blocks[index].buckets; + for (; bucket->start != NULL; count++, bucket++) { if (bucket->hash != hash) { continue; } - + if (length != bucket->end - bucket->start) { continue; } - - if (jsonlite_token_compare(token->start, bucket->start, length)) { + + if (memcmp(token->start, bucket->start, (size_t)length) == 0) { return bucket; } } - if (pool->buckets_length[index] >= pool->buckets_capacity[index]) { + size_t capacity = pool->blocks[index].capacity; + if (count + 1 >= capacity) { jsonlite_extend_capacity(pool, index); } - - bucket = pool->buckets[index] + pool->buckets_length[index]++; + + bucket = pool->blocks[index].buckets + count; bucket->hash = hash; bucket->start = token->start; bucket->end = token->end; bucket->value = NULL; + bucket[1].start = NULL; return bucket; } -static int jsonlite_token_compare(const uint8_t *t1, const uint8_t *t2, size_t length) { - return memcmp(t1, t2, length) == 0 ? 1 : 0; -} - -static void jsonlite_extend_capacity(jsonlite_token_pool pool, int index) { - size_t capacity = pool->buckets_capacity[index]; +static void jsonlite_extend_capacity(jsonlite_token_pool pool, ptrdiff_t index) { + size_t capacity = pool->blocks[index].capacity; if (capacity == 0) { capacity = 0x10; } - + size_t size = capacity * sizeof(jsonlite_token_bucket); - jsonlite_token_bucket *b = pool->buckets[index]; - jsonlite_token_bucket *extended = (jsonlite_token_bucket *)malloc(2 * size); - - if (b != NULL) { - memcpy(extended, b, size); // LCOV_EXCL_LINE - free(b); + jsonlite_token_bucket *buckets = pool->blocks[index].buckets; + jsonlite_token_bucket *extended = (jsonlite_token_bucket *)malloc(2 * size); + + if (buckets->start != NULL) { + memcpy(extended, buckets, size); // LCOV_EXCL_LINE + free(buckets); } - - pool->buckets[index] = extended; - pool->buckets_capacity[index] = 2 * capacity; -} -static int jsonlite_bucket_not_copied(jsonlite_token_pool pool, jsonlite_token_bucket *b) { - if (b == NULL) { - return 0; - } - - int res = b->start < pool->content_pool; - res |= b->start >= pool->content_pool + pool->content_pool_size; - return res; + pool->blocks[index].buckets = extended; + pool->blocks[index].capacity = 2 * capacity; } // Used MurmurHash2 function by Austin Appleby @@ -1628,39 +1884,39 @@ // 2. It will not produce the same results on little-endian and big-endian // machines. -static uint32_t MurmurHash2 ( const void * key, int len, uint32_t seed ) +static uint32_t MurmurHash2(const void * key, size_t len) { // 'm' and 'r' are mixing constants generated offline. // They're not really 'magic', they just happen to work well. - + const uint32_t m = 0x5bd1e995; const int r = 24; - + // Initialize the hash to a 'random' value - - uint32_t h = seed ^ len; - + + uint32_t h = (uint32_t)len; + // Mix 4 bytes at a time into the hash - + const unsigned char * data = (const unsigned char *)key; - + while(len >= 4) { uint32_t k = *(uint32_t*)data; - + k *= m; k ^= k >> r; k *= m; - + h *= m; h ^= k; - + data += 4; len -= 4; } - + // Handle the last few bytes of the input array - + switch(len) { case 3: h ^= data[2] << 16; @@ -1668,20 +1924,19 @@ case 1: h ^= data[0]; h *= m; }; - + // Do a few final mixes of the hash to ensure the last few // bytes are well-incorporated. - + h ^= h >> 13; h *= m; h ^= h >> 15; - + return h; } //----------------------------------------------------------------------------- static uint32_t jsonlite_hash(const uint8_t *data, size_t len) { - return MurmurHash2(data, (int)len, 0); -} - + return MurmurHash2(data, len); +} \ No newline at end of file
diff -r 01a2f8de46c8 -r 807034181e02 jsonlite.h --- a/jsonlite.h Thu Oct 24 12:20:56 2013 +0000 +++ b/jsonlite.h Fri Apr 25 02:12:53 2014 -0700 @@ -16,6 +16,356 @@ #ifndef JSONLITE_H #define JSONLITE_H +// #include "jsonlite_builder.h" +// +// Copyright 2012-2013, Andrii Mamchur +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License + +#ifndef JSONLITE_BUILDER_H +#define JSONLITE_BUILDER_H + +#include <stdio.h> +// #include "jsonlite_types.h" +// +// Copyright 2012-2013, Andrii Mamchur +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License + +#ifndef JSONLITE_TYPES_H +#define JSONLITE_TYPES_H + +typedef enum { + jsonlite_result_unknown = -1, + jsonlite_result_ok, + jsonlite_result_end_of_stream, + jsonlite_result_depth_limit, + jsonlite_result_invalid_argument, + jsonlite_result_expected_object_or_array, + jsonlite_result_expected_value, + jsonlite_result_expected_key_or_end, + jsonlite_result_expected_key, + jsonlite_result_expected_colon, + jsonlite_result_expected_comma_or_end, + jsonlite_result_invalid_escape, + jsonlite_result_invalid_number, + jsonlite_result_invalid_token, + jsonlite_result_invalid_utf8, + jsonlite_result_suspended, + + jsonlite_result_not_allowed +} jsonlite_result; + + +#endif + +// #include "jsonlite_stream.h" +// +// Copyright 2012-2013, Andrii Mamchur +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License + +#ifndef JSONLITE_STREAM_H +#define JSONLITE_STREAM_H + +#include <stdio.h> +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + + struct jsonlite_stream_struct; + typedef struct jsonlite_stream_struct const * jsonlite_stream; + + typedef int (*jsonlite_stream_write_fn)(jsonlite_stream stream, const void *data, size_t length); + typedef void (*jsonlite_stream_release_fn)(jsonlite_stream stream); + + int jsonlite_stream_write(jsonlite_stream stream, const void *data, size_t length); + void jsonlite_stream_release(jsonlite_stream stream); + + jsonlite_stream jsonlite_mem_stream_init(size_t block_size); + size_t jsonlite_mem_stream_data(jsonlite_stream stream, uint8_t **data, size_t extra_bytes); + + jsonlite_stream jsonlite_static_mem_stream_init(void *buffer, size_t size); + size_t jsonlite_static_mem_stream_written_bytes(jsonlite_stream stream); + + jsonlite_stream jsonlite_file_stream_init(FILE *file); + + extern jsonlite_stream jsonlite_null_stream; + extern jsonlite_stream jsonlite_stdout_stream; + +#ifdef __cplusplus +} +#endif + +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + + struct jsonlite_builder_struct; + typedef struct jsonlite_builder_struct* jsonlite_builder; + + /** @brief Creates and initializes new instance of builder object. + * + * You should release jsonlite_builder object using ::jsonlite_builder_release. + * @see jsonlite_builder + * @see jsonlite_builder_release + * @param depth the builder depth + * @return jsonlite_builder object + */ + jsonlite_builder jsonlite_builder_init(size_t depth, jsonlite_stream stream); + + /** \brief Releases builder object. + * + * If builder is NULL, jsonlite_builder_release does nothing. + * @see jsonlite_builder + * @see jsonlite_result + * @param builder the builder object + * @return jsonlite_result_invalid_argument when builder is NULL; otherwise jsonlite_result_ok. + */ + jsonlite_result jsonlite_builder_release(jsonlite_builder builder); + + /** \brief Sets beautify indentation. Default is 0. + * + * @see jsonlite_builder + * @see jsonlite_result + * @param builder the builder object + * @param indentation the beautify indentation; 0 - disabled + * @return jsonlite_result_invalid_argument when builder is NULL; otherwise jsonlite_result_ok. + */ + jsonlite_result jsonlite_builder_set_indentation(jsonlite_builder builder, size_t indentation); + + /** \brief Sets format for double values. Default is "%.16g". + * + * jsonlite_builder_set_double_format copies format parameter and you can safety release it. + * @see jsonlite_builder + * @see jsonlite_result + * @param builder the builder object + * @param format the double format; see sprintf function for details + * @return jsonlite_result_invalid_argument when builder or format are NULL; otherwise jsonlite_result_ok. + */ + jsonlite_result jsonlite_builder_set_double_format(jsonlite_builder builder, const char *format); + + /** \brief Begin JSON object. + * + * @see jsonlite_builder + * @see jsonlite_result + * @param builder the builder object + * @return jsonlite_result_invalid_argument when builder is NULL; + * jsonlite_result_not_allowed when operation is not allowed; + * otherwise jsonlite_result_ok. + */ + jsonlite_result jsonlite_builder_object_begin(jsonlite_builder builder); + + /** \brief End JSON object. + * + * @see jsonlite_builder + * @see jsonlite_result + * @param builder the builder object + * @return jsonlite_result_invalid_argument when builder is NULL; + * jsonlite_result_not_allowed when operation is not allowed; + * otherwise jsonlite_result_ok. + */ + jsonlite_result jsonlite_builder_object_end(jsonlite_builder builder); + + /** \brief Begin JSON array. + * + * @see jsonlite_builder + * @see jsonlite_result + * @param builder the builder object + * @return jsonlite_result_invalid_argument when builder is NULL; + * jsonlite_result_not_allowed when operation is not allowed; + * otherwise jsonlite_result_ok. + */ + jsonlite_result jsonlite_builder_array_begin(jsonlite_builder builder); + + /** \brief End JSON array. + * + * @see jsonlite_builder + * @see jsonlite_result + * @param builder the builder object + * @return jsonlite_result_invalid_argument when builder is NULL; + * jsonlite_result_not_allowed when operation is not allowed; + * otherwise jsonlite_result_ok. + */ + jsonlite_result jsonlite_builder_array_end(jsonlite_builder builder); + + /** \brief Write JSON key. + * + * jsonlite_builder_key performs two-character sequence escape for + * U+0022, U+005C, U+002F, U+0008, U+000C, U+000A, U+000D and U+0009 + * @see jsonlite_builder + * @see jsonlite_result + * @param builder the builder object + * @param data the UTF-8 encoded string + * @param length the string length + * @return jsonlite_result_invalid_argument when builder or data are NULL; + * jsonlite_result_not_allowed when operation is not allowed; + * otherwise jsonlite_result_ok. + */ + jsonlite_result jsonlite_builder_key(jsonlite_builder builder, const char *data, size_t length); + + /** \brief Write string value. + * + * jsonlite_builder_key performs two-character sequence escape for + * U+0022, U+005C, U+002F, U+0008, U+000C, U+000A, U+000D and U+0009 + * @see jsonlite_builder + * @see jsonlite_result + * @param builder the builder object + * @param data the UTF-8 encoded string + * @param length the string length + * @return jsonlite_result_invalid_argument when builder or data are NULL; + * jsonlite_result_not_allowed when operation is not allowed; + * otherwise jsonlite_result_ok. + */ + jsonlite_result jsonlite_builder_string(jsonlite_builder builder, const char *data, size_t length); + + /** \brief Write integer value. + * + * @see jsonlite_builder + * @see jsonlite_result + * @param builder the builder object + * @param value the integer value + * @return jsonlite_result_invalid_argument when builder is NULL; + * jsonlite_result_not_allowed when operation is not allowed; + * otherwise jsonlite_result_ok. + */ + jsonlite_result jsonlite_builder_int(jsonlite_builder builder, long long value); + + /** \brief Write double value. + * + * @see jsonlite_builder + * @see jsonlite_result + * @param builder the builder object + * @param value the double value + * @return jsonlite_result_invalid_argument when builder is NULL; + * jsonlite_result_not_allowed when operation is not allowed; + * otherwise jsonlite_result_ok. + */ + jsonlite_result jsonlite_builder_double(jsonlite_builder builder, double value); + + /** \brief Write true value. + * + * @see jsonlite_builder + * @see jsonlite_result + * @param builder the builder object + * @return jsonlite_result_invalid_argument when builder is NULL; + * jsonlite_result_not_allowed when operation is not allowed; + * otherwise jsonlite_result_ok. + */ + jsonlite_result jsonlite_builder_true(jsonlite_builder builder); + + /** \brief Write false value. + * + * @see jsonlite_builder + * @see jsonlite_result + * @param builder the builder object + * @return jsonlite_result_invalid_argument when builder is NULL; + * jsonlite_result_not_allowed when operation is not allowed; + * otherwise jsonlite_result_ok. + */ + jsonlite_result jsonlite_builder_false(jsonlite_builder builder); + + /** \brief Write null value. + * + * @see jsonlite_builder + * @see jsonlite_result + * @param builder the builder object + * @return jsonlite_result_invalid_argument when builder is NULL; + * jsonlite_result_not_allowed when operation is not allowed; + * otherwise jsonlite_result_ok. + */ + jsonlite_result jsonlite_builder_null(jsonlite_builder builder); + + /** \brief Write raw key. + * + * jsonlite_builder_raw_key does not perform any transformation. + * jsonlite_builder_raw_key wraps raw key with '"' (U+0022). + * If data already was wrapped with '"' use following practice jsonlite_builder_raw_key(d, data + 1, size - 2); + * @see jsonlite_builder + * @see jsonlite_result + * @param builder the builder object + * @param data the raw data + * @param length the data length + * @return jsonlite_result_invalid_argument when builder or data are NULL; + * jsonlite_result_not_allowed when operation is not allowed; + * otherwise jsonlite_result_ok. + */ + jsonlite_result jsonlite_builder_raw_key(jsonlite_builder builder, const void *data, size_t length); + + /** \brief Write raw string. + * + * jsonlite_builder_raw_string does not perform any transformation. + * jsonlite_builder_raw_string wraps raw string with '"' (U+0022). + * If data already was wrapped with '"' use following practice jsonlite_builder_raw_string(d, data + 1, size - 2); + * @see jsonlite_builder + * @see jsonlite_result + * @param builder the builder object + * @param data the raw data + * @param length the data length + * @return jsonlite_result_invalid_argument when builder or data are NULL; + * jsonlite_result_not_allowed when operation is not allowed; + * otherwise jsonlite_result_ok. + */ + jsonlite_result jsonlite_builder_raw_string(jsonlite_builder builder, const void *data, size_t length); + + /** \brief Write raw value. + * + * jsonlite_builder_raw_value does not perform any transformation. + * jsonlite_builder_raw_value does not wrap raw value with '"' (U+0022). + * @see jsonlite_builder + * @see jsonlite_result + * @param builder the builder object + * @param data the raw data + * @param length the data length + * @return jsonlite_result_invalid_argument when builder or data are NULL; + * jsonlite_result_not_allowed when operation is not allowed; + * otherwise jsonlite_result_ok. + */ + jsonlite_result jsonlite_builder_raw_value(jsonlite_builder builder, const void *data, size_t length); + + jsonlite_result jsonlite_builder_base64_value(jsonlite_builder builder, const void *data, size_t length); + +#ifdef __cplusplus +} +#endif + +#endif + // #include "jsonlite_parser.h" // // Copyright 2012-2013, Andrii Mamchur @@ -68,29 +418,29 @@ struct jsonlite_parser_struct; /** @brief Provides the hints for number token parsing. - * + * * This values is valid for jsonlite_parser_callbacks::number_found callback only. */ typedef enum { /** @brief Indicates that number token has integer part. - * + * * @note - * This flag is always set because of JSON number always has integer part (value .123 is not allowed). + * This flag is always set because of JSON number always has integer part (value .123 is not allowed). */ jsonlite_number_int = 0x01, - + /** @brief Indicates that number token has fraction part. * * This flag will set if token has an fraction part. For example: 123.987; * in current case fraction part is .987. */ jsonlite_number_frac = 0x02, - + /** @brief Indicates that number token has exponent part. * * This flag will set if token has an exponent part. * - * For example: + * For example: * For integer values: 123e5, 123E5, 123E+5, 123e+5; * all of this numbers are equal to each other and has exponent part. * @@ -101,13 +451,13 @@ * An other case 12301000 is also equals to previous numbers but has no exponent part. */ jsonlite_number_exp = 0x04, - + /** @brief Indicates that number token has negative value. * * This flag will set if token starts with '-' character. */ jsonlite_number_negative = 0x08, - + /** @brief Indicates that number token starts with zero character. */ jsonlite_number_zero_leading = 0x10, @@ -116,7 +466,7 @@ */ jsonlite_number_digit_leading = 0x20 } jsonlite_number_type; - + /** @brief Provides the hints for string token parsing. * * This values is valid for jsonlite_parser_callbacks::string_found @@ -129,14 +479,14 @@ * This flag is always set because of JSON string always has ASCII characters. */ jsonlite_string_ascii = 0x01, - + /** @brief Indicates that string token has the sequences of UTF-8 characters. * * @note * This flag will set if string token has 2, 3 or 4 subsequently. */ jsonlite_string_utf8 = 0x02, - + /** @brief Indicates that string token has an escaped character(s). * * This flag will be set if string token has one or more following escaped character: @@ -150,30 +500,37 @@ * - \\t */ jsonlite_string_escape = 0x04, - + /** @brief Indicates that string token has one or more unicode escaped character(s). * * This flag will be set if string token has \\uXXXX escape - where (XXXX is an unicode character code) */ - jsonlite_string_unicode_escape = 0x04 + jsonlite_string_unicode_escape = 0x08, + + + /** @brief Indicates that string token has one or more unicode noncharacter(s). + * + * This flag will be set if string token has \\uFDD0-\\uFDEF and \\uFFFE-\\uFFFF unicode character + */ + jsonlite_string_unicode_noncharacter = 0x10 } jsonlite_string_type; - + /** @brief Contains information about parsed token. */ typedef struct jsonlite_token { /** @brief This variable is reserved for high-level libraries. */ void *ext; - + /** @brief Contains the start position of token. */ const uint8_t *start; - + /** @brief Contains the end position of tokens. * * End position does not below to token, it should be interpreted as position of zero character. * @note - * To measure token length you can use following expression: token->end - token->start. + * To measure token length you can use following expression: token->end - token->start. */ const uint8_t *end; @@ -182,21 +539,21 @@ union { /** @brief Contains the hints for number token parsing. */ - jsonlite_number_type number_type; - + jsonlite_number_type number; + /** @brief Contains the hints for string token parsing. */ - jsonlite_string_type string_type; - }; + jsonlite_string_type string; + } type; } jsonlite_token; - + /** @brief Returns a size of memory that is required for token conversion to UTF-8 string. * @param ts jsonlite token * @return 0 if ts is NULL; otherwise required size of for token conversion. */ - size_t jsonlite_token_decode_size_for_uft8(jsonlite_token *ts); - + size_t jsonlite_token_size_of_uft8(jsonlite_token *ts); + /** @brief Converts specified token to UTF-8 string. * * Function converts specified token to UTF-8 string encoding and copy zero terminated string to buffer. @@ -206,14 +563,14 @@ * @param ts jsonlite token * @return length in bytes of converted string. */ - size_t jsonlite_token_decode_to_uft8(jsonlite_token *ts, uint8_t **buffer); - + size_t jsonlite_token_to_uft8(jsonlite_token *ts, uint8_t **buffer); + /** @brief Returns a size of memory that is required for token conversion to UTF-16 string. * @param ts jsonlite token * @return 0 if ts is NULL; otherwise required size of for token conversion. */ - size_t jsonlite_token_decode_size_for_uft16(jsonlite_token *ts); - + size_t jsonlite_token_size_of_uft16(jsonlite_token *ts); + /** @brief Converts specified token to UTF-16 string. * * Function converts specified token to UTF-16 string encoding and copy zero terminated string to buffer. @@ -223,16 +580,14 @@ * @param ts jsonlite token * @return length in bytes of converted string. */ - size_t jsonlite_token_decode_to_uft16(jsonlite_token *ts, uint16_t **buffer); + size_t jsonlite_token_to_uft16(jsonlite_token *ts, uint16_t **buffer); - /** @brief Converts hex digit to integer value. - * - * @param c a ASCII character. - * @return integer value of hex character, - * if character belongs to set [0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,a,b,c,d,e,f]; otherwise 0xFF. - */ - uint8_t jsonlite_hex_char_to_uint8(uint8_t c); - + size_t jsonlite_token_size_of_base64_binary(jsonlite_token *ts); + size_t jsonlite_token_base64_to_binary(jsonlite_token *ts, void **buffer); + + long jsonlite_token_to_long(jsonlite_token *token); + long long jsonlite_token_to_long_long(jsonlite_token *token); + #ifdef __cplusplus } #endif @@ -240,56 +595,15 @@ #endif // #include "jsonlite_types.h" -// -// Copyright 2012-2013, Andrii Mamchur -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License - -#ifndef JSONLITE_TYPES_H -#define JSONLITE_TYPES_H - -typedef enum { - jsonlite_result_unknown = -1, - jsonlite_result_ok, - jsonlite_result_end_of_stream, - jsonlite_result_depth_limit, - jsonlite_result_invalid_argument, - jsonlite_result_expected_object_or_array, - jsonlite_result_expected_value, - jsonlite_result_expected_key_or_end, - jsonlite_result_expected_key, - jsonlite_result_expected_colon, - jsonlite_result_expected_comma_or_end, - jsonlite_result_invalid_escape, - jsonlite_result_invalid_number, - jsonlite_result_invalid_token, - jsonlite_result_invalid_utf8, - jsonlite_result_suspended, - - jsonlite_result_not_allowed -} jsonlite_result; - - -#endif #ifdef __cplusplus extern "C" { #endif - + struct jsonlite_parser_struct; typedef struct jsonlite_parser_struct* jsonlite_parser; - + /** @brief Contains callback information. */ typedef struct { @@ -298,22 +612,22 @@ * You can use ::jsonlite_parser_suspend to stop tokenization. */ jsonlite_parser parser; - + /** @brief Reserved for client usage. */ void *client_state; } jsonlite_callback_context; - + /** @brief Type of value callback function. */ typedef void (*jsonlite_value_callback)(jsonlite_callback_context *, jsonlite_token *); - + /** @brief Type of state callback function. */ typedef void (*jsonlite_state_callback)(jsonlite_callback_context *); - + /** @brief Contains references to client callback functions. - * + * * You can use the global jsonlite_default_callbacks constant to initialize default values. */ typedef struct { @@ -321,47 +635,47 @@ * You can retrieve result of parsing using jsonlite_parser_get_result. */ jsonlite_state_callback parse_finished; - + /** @brief Called when parser found object start. */ jsonlite_state_callback object_start; - + /** @brief Called when parser found object end. */ jsonlite_state_callback object_end; - + /** @brief Called when parser found array start. */ jsonlite_state_callback array_start; - + /** @brief Called when parser found array end. */ jsonlite_state_callback array_end; - + /** @brief Called when parser found \a true token. */ jsonlite_state_callback true_found; - + /** @brief Called when parser found \a false token. */ jsonlite_state_callback false_found; - + /** @brief Called when parser found \a null token. */ jsonlite_state_callback null_found; - + /** @brief Called when parser found key token. */ jsonlite_value_callback key_found; - + /** @brief Called when parser found string token. */ jsonlite_value_callback string_found; - + /** @brief Called when parser found number token. */ jsonlite_value_callback number_found; - + /** @brief Callbacks' context, will be past as first parameter of callback function. */ jsonlite_callback_context context; @@ -384,7 +698,18 @@ * @return jsonlite_parser object. */ jsonlite_parser jsonlite_parser_init(size_t depth); - + + /** @brief Initializes memory for parser object. + * + * You should release internal resources using ::jsonlite_parser_cleanup + * @see jsonlite_parser + * @see jsonlite_parser_reset + * @param memory the memory for parser. + * @param size the memory size. + * @return jsonlite_parser object. + */ + jsonlite_parser jsonlite_parser_init_memory(void *memory, size_t size); + /** \brief Copies provided callbacks structure to parser object. * @see jsonlite_parser * @see jsonlite_parser_callbacks @@ -394,7 +719,7 @@ * @return jsonlite_result_invalid_argument when parser or cbs are NULL; otherwise jsonlite_result_ok. */ jsonlite_result jsonlite_parser_set_callback(jsonlite_parser parser, const jsonlite_parser_callbacks *cbs); - + /** \brief Returns result of last operation. * @see jsonlite_parser * @see jsonlite_result @@ -402,7 +727,7 @@ * @return jsonlite_result_invalid_argument when parser is NULL; otherwise s result of last operation. */ jsonlite_result jsonlite_parser_get_result(jsonlite_parser parser); - + /** \brief Performs JSON tokenization. * * jsonlite is a chunk parser and you can use this function to parser a fragment of JSON. @@ -412,7 +737,7 @@ * @param buffer the pointer to JSON payload buffer. * @param size the JSON payload buffer size. * @return JSON parsing result or jsonlite_result_invalid_argument when some parameter is invalid. - * + * * There is an example of JSON validation * @code{.c} * char json[] = "{\"key\" : 12345, \"obj\": {}, \"array\":[null, true, false, \"string\"]}"; @@ -439,7 +764,7 @@ * @endcode */ jsonlite_result jsonlite_parser_tokenize(jsonlite_parser parser, const void *buffer, size_t size); - + /** \brief Resumes JSON tokenization. * @see jsonlite_parser * @see jsonlite_result @@ -447,306 +772,58 @@ * @return JSON parsing result or jsonlite_result_invalid_argument when parser is NULL. */ jsonlite_result jsonlite_parser_resume(jsonlite_parser parser); - + /** \brief Suspends JSON tokenization. * * You can continue tokenization later by calling ::jsonlite_parser_resume. * @see jsonlite_parser * @see jsonlite_result * @param parser the parser object. - * @return jsonlite_result_invalid_argument when parser is NULL; + * @return jsonlite_result_invalid_argument when parser is NULL; * jsonlite_result_not_allowed when operation is not allowed; * otherwise jsonlite_result_ok. */ jsonlite_result jsonlite_parser_suspend(jsonlite_parser parser); - + + /** \brief Terminate JSON tokenization. + * + * @see jsonlite_parser + * @see jsonlite_result + * @param parser the parser object. + * @return jsonlite_result_invalid_argument when parser is NULL or result is jsonlite_result_unknown; + * otherwise jsonlite_result_ok. + */ + jsonlite_result jsonlite_parser_terminate(jsonlite_parser parser, jsonlite_result result); + /** \brief Releases parser object. * * If parser is NULL, jsonlite_parser_release does nothing. * @see jsonlite_parser - * @see jsonlite_result * @param parser the parser object. */ void jsonlite_parser_release(jsonlite_parser parser); + /** \brief Releases internal resources and states. + * + * If parser is NULL, jsonlite_parser_reset does nothing. + * @see jsonlite_parser + * @param parser the parser object. + */ + void jsonlite_parser_cleanup(jsonlite_parser parser); + /** \brief jsonlite_parser_callbacks structure initialized with callbacks that do nothing. */ extern const jsonlite_parser_callbacks jsonlite_default_callbacks; - + #ifdef __cplusplus } #endif #endif -// #include "jsonlite_builder.h" -// -// Copyright 2012-2013, Andrii Mamchur -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License - -#ifndef JSONLITE_BUILDER_H -#define JSONLITE_BUILDER_H - -#include <stdio.h> -// #include "jsonlite_types.h" - - -#ifdef __cplusplus -extern "C" { -#endif - - struct jsonlite_builder_struct; - typedef struct jsonlite_builder_struct* jsonlite_builder; +// #include "jsonlite_stream.h" - /** @brief Creates and initializes new instance of builder object. - * - * You should release jsonlite_builder object using ::jsonlite_builder_release. - * @see jsonlite_builder - * @see jsonlite_builder_release - * @param depth the builder depth - * @return jsonlite_builder object - */ - jsonlite_builder jsonlite_builder_init(size_t depth); - - /** \brief Releases builder object. - * - * If builder is NULL, jsonlite_builder_release does nothing. - * @see jsonlite_builder - * @see jsonlite_result - * @param builder the builder object - * @return jsonlite_result_invalid_argument when builder is NULL; otherwise jsonlite_result_ok. - */ - jsonlite_result jsonlite_builder_release(jsonlite_builder builder); - - /** \brief Sets beautify indentation. Default is 0. - * - * @see jsonlite_builder - * @see jsonlite_result - * @param builder the builder object - * @param indentation the beautify indentation; 0 - disabled - * @return jsonlite_result_invalid_argument when builder is NULL; otherwise jsonlite_result_ok. - */ - jsonlite_result jsonlite_builder_set_indentation(jsonlite_builder builder, size_t indentation); - - /** \brief Sets format for double values. Default is "%.16g". - * - * jsonlite_builder_set_double_format copies format parameter and you can safety release it. - * @see jsonlite_builder - * @see jsonlite_result - * @param builder the builder object - * @param format the double format; see sprintf function for details - * @return jsonlite_result_invalid_argument when builder or format are NULL; otherwise jsonlite_result_ok. - */ - jsonlite_result jsonlite_builder_set_double_format(jsonlite_builder builder, const char *format); - - /** \brief Begin JSON object. - * - * @see jsonlite_builder - * @see jsonlite_result - * @param builder the builder object - * @return jsonlite_result_invalid_argument when builder is NULL; - * jsonlite_result_not_allowed when operation is not allowed; - * otherwise jsonlite_result_ok. - */ - jsonlite_result jsonlite_builder_object_begin(jsonlite_builder builder); - - /** \brief End JSON object. - * - * @see jsonlite_builder - * @see jsonlite_result - * @param builder the builder object - * @return jsonlite_result_invalid_argument when builder is NULL; - * jsonlite_result_not_allowed when operation is not allowed; - * otherwise jsonlite_result_ok. - */ - jsonlite_result jsonlite_builder_object_end(jsonlite_builder builder); - - /** \brief Begin JSON array. - * - * @see jsonlite_builder - * @see jsonlite_result - * @param builder the builder object - * @return jsonlite_result_invalid_argument when builder is NULL; - * jsonlite_result_not_allowed when operation is not allowed; - * otherwise jsonlite_result_ok. - */ - jsonlite_result jsonlite_builder_array_begin(jsonlite_builder builder); - - /** \brief End JSON array. - * - * @see jsonlite_builder - * @see jsonlite_result - * @param builder the builder object - * @return jsonlite_result_invalid_argument when builder is NULL; - * jsonlite_result_not_allowed when operation is not allowed; - * otherwise jsonlite_result_ok. - */ - jsonlite_result jsonlite_builder_array_end(jsonlite_builder builder); - - /** \brief Write JSON key. - * - * jsonlite_builder_key performs two-character sequence escape for - * U+0022, U+005C, U+002F, U+0008, U+000C, U+000A, U+000D and U+0009 - * @see jsonlite_builder - * @see jsonlite_result - * @param builder the builder object - * @param data the UTF-8 encoded string - * @param length the string length - * @return jsonlite_result_invalid_argument when builder or data are NULL; - * jsonlite_result_not_allowed when operation is not allowed; - * otherwise jsonlite_result_ok. - */ - jsonlite_result jsonlite_builder_key(jsonlite_builder builder, const char *data, size_t length); - - /** \brief Write string value. - * - * jsonlite_builder_key performs two-character sequence escape for - * U+0022, U+005C, U+002F, U+0008, U+000C, U+000A, U+000D and U+0009 - * @see jsonlite_builder - * @see jsonlite_result - * @param builder the builder object - * @param data the UTF-8 encoded string - * @param length the string length - * @return jsonlite_result_invalid_argument when builder or data are NULL; - * jsonlite_result_not_allowed when operation is not allowed; - * otherwise jsonlite_result_ok. - */ - jsonlite_result jsonlite_builder_string(jsonlite_builder builder, const char *data, size_t length); - - /** \brief Write integer value. - * - * @see jsonlite_builder - * @see jsonlite_result - * @param builder the builder object - * @param value the integer value - * @return jsonlite_result_invalid_argument when builder is NULL; - * jsonlite_result_not_allowed when operation is not allowed; - * otherwise jsonlite_result_ok. - */ - jsonlite_result jsonlite_builder_int(jsonlite_builder builder, long long value); - - /** \brief Write double value. - * - * @see jsonlite_builder - * @see jsonlite_result - * @param builder the builder object - * @param value the double value - * @return jsonlite_result_invalid_argument when builder is NULL; - * jsonlite_result_not_allowed when operation is not allowed; - * otherwise jsonlite_result_ok. - */ - jsonlite_result jsonlite_builder_double(jsonlite_builder builder, double value); - - /** \brief Write true value. - * - * @see jsonlite_builder - * @see jsonlite_result - * @param builder the builder object - * @return jsonlite_result_invalid_argument when builder is NULL; - * jsonlite_result_not_allowed when operation is not allowed; - * otherwise jsonlite_result_ok. - */ - jsonlite_result jsonlite_builder_true(jsonlite_builder builder); - - /** \brief Write false value. - * - * @see jsonlite_builder - * @see jsonlite_result - * @param builder the builder object - * @return jsonlite_result_invalid_argument when builder is NULL; - * jsonlite_result_not_allowed when operation is not allowed; - * otherwise jsonlite_result_ok. - */ - jsonlite_result jsonlite_builder_false(jsonlite_builder builder); - - /** \brief Write null value. - * - * @see jsonlite_builder - * @see jsonlite_result - * @param builder the builder object - * @return jsonlite_result_invalid_argument when builder is NULL; - * jsonlite_result_not_allowed when operation is not allowed; - * otherwise jsonlite_result_ok. - */ - jsonlite_result jsonlite_builder_null(jsonlite_builder builder); - - /** \brief Write raw key. - * - * jsonlite_builder_raw_key does not perform any transformation. - * jsonlite_builder_raw_key wraps raw key with '"' (U+0022). - * If data already was wrapped with '"' use following practice jsonlite_builder_raw_key(d, data + 1, size - 2); - * @see jsonlite_builder - * @see jsonlite_result - * @param builder the builder object - * @param data the raw data - * @param length the data length - * @return jsonlite_result_invalid_argument when builder or data are NULL; - * jsonlite_result_not_allowed when operation is not allowed; - * otherwise jsonlite_result_ok. - */ - jsonlite_result jsonlite_builder_raw_key(jsonlite_builder builder, const void *data, size_t length); - - /** \brief Write raw string. - * - * jsonlite_builder_raw_string does not perform any transformation. - * jsonlite_builder_raw_string wraps raw string with '"' (U+0022). - * If data already was wrapped with '"' use following practice jsonlite_builder_raw_string(d, data + 1, size - 2); - * @see jsonlite_builder - * @see jsonlite_result - * @param builder the builder object - * @param data the raw data - * @param length the data length - * @return jsonlite_result_invalid_argument when builder or data are NULL; - * jsonlite_result_not_allowed when operation is not allowed; - * otherwise jsonlite_result_ok. - */ - jsonlite_result jsonlite_builder_raw_string(jsonlite_builder builder, const void *data, size_t length); - - /** \brief Write raw value. - * - * jsonlite_builder_raw_value does not perform any transformation. - * jsonlite_builder_raw_value does not wrap raw value with '"' (U+0022). - * @see jsonlite_builder - * @see jsonlite_result - * @param builder the builder object - * @param data the raw data - * @param length the data length - * @return jsonlite_result_invalid_argument when builder or data are NULL; - * jsonlite_result_not_allowed when operation is not allowed; - * otherwise jsonlite_result_ok. - */ - jsonlite_result jsonlite_builder_raw_value(jsonlite_builder builder, const void *data, size_t length); - - /** \brief Gets buffer data. - * - * You are responsible to free buffer using free function. - * @see jsonlite_builder - * @see jsonlite_result - * @param builder the builder object - * @param[out] buffer the output buffer - * @param[out] size the buffer size - * @return jsonlite_result_invalid_argument when builder, buffer or size are NULL; - * jsonlite_result_not_allowed when operation is not allowed; - * otherwise jsonlite_result_ok. - */ - jsonlite_result jsonlite_builder_data(jsonlite_builder builder, char **buffer, size_t *size); - -#ifdef __cplusplus -} -#endif - -#endif +// #include "jsonlite_token.h" // #include "jsonlite_token_pool.h" // @@ -773,18 +850,20 @@ #ifdef __cplusplus extern "C" { #endif - + typedef void (*jsonlite_token_pool_release_value_fn)(void *); -typedef struct content_pool_size* jsonlite_token_pool; - +typedef struct jsonlite_token_pool_struct* jsonlite_token_pool; + typedef struct jsonlite_token_bucket { - ptrdiff_t hash; const uint8_t *start; const uint8_t *end; - const void *value; + + ptrdiff_t hash; ptrdiff_t value_hash; + + const void *value; } jsonlite_token_bucket; - + jsonlite_token_pool jsonlite_token_pool_create(jsonlite_token_pool_release_value_fn release_fn); void jsonlite_token_pool_copy_tokens(jsonlite_token_pool pool); void jsonlite_token_pool_release(jsonlite_token_pool pool); @@ -797,18 +876,6 @@ #endif -#endif +extern const char *jsonlite_version; -/** @mainpage jsonlite Index Page - * - * @section intro_sec Introduction - * - * This is the introduction. - * - * @section install_sec Installation - * - * @subsection step1 Step 1: Opening the box - * - * etc... - */ - +#endif \ No newline at end of file