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

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

Revision:
1:807034181e02
Parent:
0:01a2f8de46c8
--- 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