Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 |
--- 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
--- 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