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

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

jsonlite.c

Committer:
Josh Hollenbeck
Date:
2014-04-25
Revision:
1:807034181e02
Parent:
0:01a2f8de46c8

File content as of revision 1:807034181e02:

#define JSONLITE_AMALGAMATED
#include "jsonlite.h"
//
//  Copyright 2012-2013, Andrii Mamchur
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License

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

#include <stdlib.h>
#include <string.h>

#ifdef _MSC_VER

#include <intrin.h>

static uint32_t __inline jsonlite_clz(uint32_t x) {
   unsigned long r = 0;
   _BitScanForward(&r, x);
   return r;
}

#else

#define jsonlite_clz(x) __builtin_clz((x))

#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 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 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,
    state_object_key,
    state_object_key_end,
    state_colon,
    state_object_comma_end,
    state_array_value_end,
    state_array_comma_end,
    state_key,
    state_value,
    state_end,

    state_stop = 1 << 7
};

typedef uint8_t parse_state;
struct jsonlite_parser_struct {
    const uint8_t *cursor;
    const uint8_t *limit;
    const uint8_t *buffer;
    uint8_t *buffer_own;

    parse_state *current;
    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 empty_value_callback(jsonlite_callback_context *ctx, jsonlite_token *t) {}
static void empty_state_callback(jsonlite_callback_context *ctx) {}

const jsonlite_parser_callbacks jsonlite_default_callbacks = {
    &empty_state_callback,
    &empty_state_callback,
    &empty_state_callback,
    &empty_state_callback,
    &empty_state_callback,
    &empty_state_callback,
    &empty_state_callback,
    &empty_state_callback,
    &empty_value_callback,
    &empty_value_callback,
    &empty_value_callback,
    {NULL, NULL}
};

size_t jsonlite_parser_estimate_size(size_t depth) {
    depth = depth < MIN_DEPTH ? 32 : depth;
    return sizeof(jsonlite_parser_struct) + depth * sizeof(parse_state);
}

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->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;
    parser->current++;
    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;
    }

    parser->callbacks = *cbs;
    parser->callbacks.context.parser = parser;
    return jsonlite_result_ok;
}

jsonlite_result jsonlite_parser_get_result(jsonlite_parser parser) {
    if (parser == NULL) {
        return jsonlite_result_invalid_argument;
    }

    return parser->result;
}

jsonlite_result jsonlite_parser_tokenize(jsonlite_parser parser, const void *buffer, size_t size) {
    if (parser == NULL || buffer == NULL || size == 0) {
        return jsonlite_result_invalid_argument;
    }

    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->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);

        parser->buffer = b;
        parser->buffer_own = b;
        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);
    return parser->result;
}

jsonlite_result jsonlite_parser_resume(jsonlite_parser parser) {
    if (parser == NULL) {
        return jsonlite_result_invalid_argument;
    }

    if (parser->result != jsonlite_result_suspended) {
        return jsonlite_result_not_allowed;
    }

    jsonlite_do_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->control == NULL) {
        return jsonlite_result_not_allowed;
    }

    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);
}

static void jsonlite_do_parse(jsonlite_parser parser) {
    const uint8_t *c = parser->cursor;
    const uint8_t *l = parser->limit;
    const uint8_t *token_start = NULL;
    const parse_state *last = parser->last;
    parse_state *state = parser->current;
    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 end;
skip_char_and_whitespaces:
    c++;
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;

    switch (*state) {
        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 == 0x7B)             goto parse_object;
            if (*c == 0x5B)             goto parse_array_state;
            goto error_exp_ooa;
        case state_end:                 goto end;
        default:
            result = parser->result;
            goto end;
    }
parse_object:
    *state = state_object_key_end;
    CALL_STATE_CALLBACK(parser->callbacks, object_start);
    goto skip_char_and_whitespaces;
parse_array_state:
    *state = state_array_value_end;
    CALL_STATE_CALLBACK(parser->callbacks, array_start);
    goto skip_char_and_whitespaces;
parse_key:
    if (*c != 0x22) goto error_exp_key;
    *state = state_colon;
    *++state = state_key;
    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_whitespaces;
parse_key_end:
    switch (*c) {
        case 0x22:
            *state = state_colon;
            if (++state == last) goto error_depth;
            *state = state_key;
            goto parse_string_token;
        case 0x7D:
            state--;
            CALL_STATE_CALLBACK(parser->callbacks, object_end);
            goto structure_finished;
        default: goto error_exp_koe;
    }
parse_object_comma_end:
    switch (*c) {
        case 0x2C:
            *state = state_object_key;
            goto skip_char_and_whitespaces;
        case 0x7D:
            state--;
            CALL_STATE_CALLBACK(parser->callbacks, object_end);
            goto structure_finished;
        default: goto error_exp_coe;
    }
parse_array_value_end:
    switch (*c) {
        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 parse_value;
    }
parse_array_comma_end:
    switch (*c) {
        case 0x2C:
            *++state = state_value;
            goto skip_char_and_whitespaces;
        case 0x5D:
            state--;
            CALL_STATE_CALLBACK(parser->callbacks, array_end);
            goto structure_finished;
        default: goto error_exp_coe;
    }
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;

// 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;
    }
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)         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;
    }
    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++ != 0x72)   goto error_token;
    if (*c++ != 0x75)   goto error_token;
    if (*c++ != 0x65)   goto error_token;
    state--;
    CALL_STATE_CALLBACK(parser->callbacks, true_found);
    goto select_state;
parse_false_token:
    if (c++ + 4 >= l)   goto end_of_stream;
    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);
    goto select_state;
parse_null_token:
    if (c++ + 3 >= l)   goto end_of_stream;
    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);
    goto select_state;

// 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_whitespaces:
    token_start = l;
end_of_stream:
    result = jsonlite_result_end_of_stream;
end:
    parser->result = result;
    parser->current = state;
    parser->control = NULL;
    parser->cursor = c;
    parser->callbacks.parse_finished(&parser->callbacks.context);
    if (result != jsonlite_result_end_of_stream) {
        return;
    }

    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;
        }
    }
}
//
//  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_stream.h"
#endif

#include <stdlib.h>
#include <string.h>

struct jsonlite_stream_struct {
    jsonlite_stream_write_fn write;
    jsonlite_stream_release_fn release;
} jsonlite_stream_struct;

int jsonlite_stream_write(jsonlite_stream stream, const void *data, size_t length) {
    return stream->write(stream, data, length);
}

void jsonlite_stream_release(jsonlite_stream stream) {
    if (stream == NULL) {
        return;
    }

    if (stream->release != NULL) {
        stream->release(stream);
    }
}

static void jsonlite_stream_free_mem(jsonlite_stream stream) {
    free((void *)stream);
}

#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);
    }

    return (int)length;
}

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);
    }

    free((void *)stream);
}

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_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;

    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;
}

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;

    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;
        }
    }

    if (size == 0) {
        *data = NULL;
    } else {
        *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
            }
        }
    }

    return size;
}

#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 {
        mem_stream->enabled = 0;
        return 0;
    }

    return (int)length;
}

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;

    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;
}

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_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;

    jsonlite_file_stream *file_stream = CAST_TO_FILE_STREAM(stream);
    file_stream->file = file;
    return stream;
}

static int jsonlite_null_stream_write(jsonlite_stream stream, const void *data, size_t length) {
    return (int)length;
}

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
//
//  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_token.h"
#endif

#include <stdlib.h>

#ifdef _MSC_VER
#include <intrin.h>

static uint32_t __inline jsonlite_clz( uint32_t x ) {
   unsigned long r = 0;
   _BitScanForward(&r, x);
   return r;
}

#else

#define jsonlite_clz(x) __builtin_clz((x))

#endif

static uint8_t jsonlite_hex_char_to_uint8(uint8_t c) {
    if (c >= 'a') {
        return c - 'a' + 10;
    }

    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) {
        *utf16 = (uint16_t)ch;
        return 1;
    }

    *utf16++ = (uint16_t)(0xD800 + vh);
    *utf16 = (uint16_t)(0xDC00 + vl);
    return 2;
}

size_t jsonlite_token_size_of_uft8(jsonlite_token *ts) {
    return (size_t)(ts->end - ts->start + 1);
}

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);
    int res;
step:
    if (p == l)         goto done;
    if (*p == '\\')     goto escaped;
    if (*p >= 0x80)     goto utf8;
    *c++ = *p++;
    goto step;
escaped:
    switch (*++p) {
        case 34:    *c++ = '"';     p++; goto step;
        case 47:    *c++ = '/';     p++; goto step;
        case 92:    *c++ = '\\';    p++; goto step;
        case 98:    *c++ = '\b';    p++; goto step;
        case 102:   *c++ = '\f';    p++; goto step;
        case 110:   *c++ = '\n';    p++; goto step;
        case 114:   *c++ = '\r';    p++; goto step;
        case 116:   *c++ = '\t';    p++; goto step;
    }

    // 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;
    value = jsonlite_hex_char_to_uint8(*p++);
    value = (uint32_t)(value << 4) | jsonlite_hex_char_to_uint8(*p++);
    value = (uint32_t)(value << 4) | jsonlite_hex_char_to_uint8(*p++);
    value = (uint32_t)(value << 4) | jsonlite_hex_char_to_uint8(*p++);
    utf32 += value - 0xDC00 + 0x10000;
encode:
    if (utf32 < 0x80) {
        *c++ = (uint8_t)utf32;
    } else if (utf32 < 0x0800) {
        c[1] = (uint8_t)(utf32 & 0x3F) | 0x80;
        utf32 = utf32 >> 6;
        c[0] = (uint8_t)utf32 | 0xC0;
        c += 2;
    } else if (utf32 < 0x10000) {
        c[2] = (uint8_t)(utf32 & 0x3F) | 0x80;
        utf32 = utf32 >> 6;
        c[1] = (uint8_t)(utf32 & 0x3F) | 0x80;
        utf32 = utf32 >> 6;
        c[0] = (uint8_t)utf32 | 0xE0;
        c += 3;
    } else {
        c[3] = (uint8_t)(utf32 & 0x3F) | 0x80;
        utf32 = utf32 >> 6;
        c[2] = (uint8_t)(utf32 & 0x3F) | 0x80;
        utf32 = utf32 >> 6;
        c[1] = (uint8_t)(utf32 & 0x3F) | 0x80;
        utf32 = utf32 >> 6;
        c[0] = (uint8_t)utf32 | 0xF0;
        c += 4;
    }
    goto step;
utf8:
    res = jsonlite_clz(((*p) ^ 0xFF) << 0x19);
    *c++ = *p++;
    switch (res) {
        case 3: *c++ = *p++;
        case 2: *c++ = *p++;
        case 1: *c++ = *p++;
    }
    goto step;
done:
    *c = 0;
    return c - *buffer;
}

size_t jsonlite_token_size_of_uft16(jsonlite_token *ts) {
    return (ts->end - ts->start + 1) * sizeof(uint16_t);
}

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;
step:
    if (p == l)         goto done;
    if (*p == '\\')     goto escaped;
    if (*p >= 0x80)     goto utf8;
    *c++ = *p++;
    goto step;
escaped:
    switch (*++p) {
        case 34:    *c++ = '"';     p++; goto step;
        case 47:    *c++ = '/';     p++; goto step;
        case 92:    *c++ = '\\';    p++; goto step;
        case 98:    *c++ = '\b';    p++; goto step;
        case 102:   *c++ = '\f';    p++; goto step;
        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++);
    utf16 = (uint16_t)(utf16 << 4) | jsonlite_hex_char_to_uint8(*p++);
    utf16 = (uint16_t)(utf16 << 4) | jsonlite_hex_char_to_uint8(*p++);
    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++);
    utf16 = (uint16_t)(utf16 << 4) | jsonlite_hex_char_to_uint8(*p++);
    utf16 = (uint16_t)(utf16 << 4) | jsonlite_hex_char_to_uint8(*p++);
    utf16 = (uint16_t)(utf16 << 4) | jsonlite_hex_char_to_uint8(*p++);
    *c++ = utf16;
    goto step;
utf8:
    res = jsonlite_clz(((*p) ^ 0xFF) << 0x19);
    uint32_t code = (*p & (0xFF >> (res + 1)));
    switch (res) {
        case 3: code = (code << 6) | (*++p & 0x3F);
        case 2: code = (code << 6) | (*++p & 0x3F);
        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
//
//  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_token_pool.h"
#endif

#include <stdlib.h>
#include <string.h>

#define JSONLITE_TOKEN_POOL_FRONT 0x80
#define JSONLITE_TOKEN_POOL_FRONT_MASK (JSONLITE_TOKEN_POOL_FRONT - 1)

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, 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)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 *bucket;
    size_t size = 0;
    int i;
    for (i = 0; i < JSONLITE_TOKEN_POOL_FRONT; i++) {
        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);
    uint8_t *p = buffer;
    for (i = 0; i < JSONLITE_TOKEN_POOL_FRONT; i++) {
        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;
            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;
    for (i = 0; i < JSONLITE_TOKEN_POOL_FRONT; i++) {
        jsonlite_token_bucket *bucket = pool->blocks[i].buckets;
        if (bucket->start == NULL) {
            continue;
        }

        if (pool->release_fn != NULL) {
            for (; bucket->start != NULL; bucket++) {
                pool->release_fn((void *)bucket->value);
            }
        }

        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) {
    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 (memcmp(token->start, bucket->start, (size_t)length) == 0) {
            return bucket;
        }
    }

    size_t capacity = pool->blocks[index].capacity;
    if (count + 1 >= capacity) {
        jsonlite_extend_capacity(pool, 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 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 *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->blocks[index].buckets = extended;
    pool->blocks[index].capacity = 2 * capacity;
}

// Used MurmurHash2 function by Austin Appleby
// http://code.google.com/p/smhasher/ revision 147

//-----------------------------------------------------------------------------
// MurmurHash2 was written by Austin Appleby, and is placed in the public
// domain. The author hereby disclaims copyright to this source code.

// Note - This code makes a few assumptions about how your machine behaves -

// 1. We can read a 4-byte value from any address without crashing
// 2. sizeof(int) == 4

// And it has a few limitations -

// 1. It will not work incrementally.
// 2. It will not produce the same results on little-endian and big-endian
//    machines.

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 = (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;
        case 2: h ^= data[1] << 8;
        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, len);
}