JSON parsing library by Andrii Mamchur https://github.com/amamchur/jsonlite

Dependents:   M2X_dev MTS_M2x_Example1 MTS_M2x_Example m2x-demo-all ... more

Files at this revision

API Documentation at this revision

Comitter:
Josh Hollenbeck
Date:
Fri Apr 25 02:12:53 2014 -0700
Parent:
0:01a2f8de46c8
Commit message:
updated jsonlite to ver 1.1.2

Changed in this revision

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