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

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

Committer:
Josh Hollenbeck
Date:
Fri Apr 25 02:12:53 2014 -0700
Revision:
1:807034181e02
Parent:
0:01a2f8de46c8
updated jsonlite to ver 1.1.2

Who changed what in which revision?

UserRevisionLine numberNew contents of line
citrusbyte 0:01a2f8de46c8 1 #define JSONLITE_AMALGAMATED
citrusbyte 0:01a2f8de46c8 2 #include "jsonlite.h"
citrusbyte 0:01a2f8de46c8 3 //
citrusbyte 0:01a2f8de46c8 4 // Copyright 2012-2013, Andrii Mamchur
citrusbyte 0:01a2f8de46c8 5 //
citrusbyte 0:01a2f8de46c8 6 // Licensed under the Apache License, Version 2.0 (the "License");
citrusbyte 0:01a2f8de46c8 7 // you may not use this file except in compliance with the License.
citrusbyte 0:01a2f8de46c8 8 // You may obtain a copy of the License at
citrusbyte 0:01a2f8de46c8 9 //
citrusbyte 0:01a2f8de46c8 10 // http://www.apache.org/licenses/LICENSE-2.0
citrusbyte 0:01a2f8de46c8 11 //
citrusbyte 0:01a2f8de46c8 12 // Unless required by applicable law or agreed to in writing, software
citrusbyte 0:01a2f8de46c8 13 // distributed under the License is distributed on an "AS IS" BASIS,
citrusbyte 0:01a2f8de46c8 14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
citrusbyte 0:01a2f8de46c8 15 // See the License for the specific language governing permissions and
citrusbyte 0:01a2f8de46c8 16 // limitations under the License
citrusbyte 0:01a2f8de46c8 17
Josh Hollenbeck 1:807034181e02 18 const char *jsonlite_version = "1.1.2";
Josh Hollenbeck 1:807034181e02 19 //
Josh Hollenbeck 1:807034181e02 20 // Copyright 2012-2013, Andrii Mamchur
Josh Hollenbeck 1:807034181e02 21 //
Josh Hollenbeck 1:807034181e02 22 // Licensed under the Apache License, Version 2.0 (the "License");
Josh Hollenbeck 1:807034181e02 23 // you may not use this file except in compliance with the License.
Josh Hollenbeck 1:807034181e02 24 // You may obtain a copy of the License at
Josh Hollenbeck 1:807034181e02 25 //
Josh Hollenbeck 1:807034181e02 26 // http://www.apache.org/licenses/LICENSE-2.0
Josh Hollenbeck 1:807034181e02 27 //
Josh Hollenbeck 1:807034181e02 28 // Unless required by applicable law or agreed to in writing, software
Josh Hollenbeck 1:807034181e02 29 // distributed under the License is distributed on an "AS IS" BASIS,
Josh Hollenbeck 1:807034181e02 30 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Josh Hollenbeck 1:807034181e02 31 // See the License for the specific language governing permissions and
Josh Hollenbeck 1:807034181e02 32 // limitations under the License
Josh Hollenbeck 1:807034181e02 33
Josh Hollenbeck 1:807034181e02 34 #ifndef JSONLITE_AMALGAMATED
Josh Hollenbeck 1:807034181e02 35 #include "../include/jsonlite_builder.h"
Josh Hollenbeck 1:807034181e02 36 #endif
Josh Hollenbeck 1:807034181e02 37
Josh Hollenbeck 1:807034181e02 38 #include <stdlib.h>
Josh Hollenbeck 1:807034181e02 39 #include <stddef.h>
Josh Hollenbeck 1:807034181e02 40 #include <string.h>
Josh Hollenbeck 1:807034181e02 41
Josh Hollenbeck 1:807034181e02 42 #define jsonlite_builder_check_depth() \
Josh Hollenbeck 1:807034181e02 43 do { \
Josh Hollenbeck 1:807034181e02 44 if (builder->state >= builder->limit) { \
Josh Hollenbeck 1:807034181e02 45 return jsonlite_result_depth_limit; \
Josh Hollenbeck 1:807034181e02 46 } \
Josh Hollenbeck 1:807034181e02 47 } while (0)
Josh Hollenbeck 1:807034181e02 48
Josh Hollenbeck 1:807034181e02 49 enum {
Josh Hollenbeck 1:807034181e02 50 jsonlite_accept_object_begin = 0x0001,
Josh Hollenbeck 1:807034181e02 51 jsonlite_accept_object_end = 0x0002,
Josh Hollenbeck 1:807034181e02 52 jsonlite_accept_array_begin = 0x0004,
Josh Hollenbeck 1:807034181e02 53 jsonlite_accept_array_end = 0x0008,
Josh Hollenbeck 1:807034181e02 54 jsonlite_accept_key = 0x0010,
Josh Hollenbeck 1:807034181e02 55 jsonlite_accept_string = 0x0020,
Josh Hollenbeck 1:807034181e02 56 jsonlite_accept_number = 0x0040,
Josh Hollenbeck 1:807034181e02 57 jsonlite_accept_boolean = 0x0080,
Josh Hollenbeck 1:807034181e02 58 jsonlite_accept_null = 0x0100,
Josh Hollenbeck 1:807034181e02 59 jsonlite_accept_values_only = 0x0200,
Josh Hollenbeck 1:807034181e02 60 jsonlite_accept_next = 0x0400,
Josh Hollenbeck 1:807034181e02 61
Josh Hollenbeck 1:807034181e02 62 jsonlite_accept_value = 0
Josh Hollenbeck 1:807034181e02 63 | jsonlite_accept_object_begin
Josh Hollenbeck 1:807034181e02 64 | jsonlite_accept_array_begin
Josh Hollenbeck 1:807034181e02 65 | jsonlite_accept_string
Josh Hollenbeck 1:807034181e02 66 | jsonlite_accept_number
Josh Hollenbeck 1:807034181e02 67 | jsonlite_accept_boolean
Josh Hollenbeck 1:807034181e02 68 | jsonlite_accept_null,
Josh Hollenbeck 1:807034181e02 69 jsonlite_accept_continue_object = 0
Josh Hollenbeck 1:807034181e02 70 | jsonlite_accept_next
Josh Hollenbeck 1:807034181e02 71 | jsonlite_accept_key
Josh Hollenbeck 1:807034181e02 72 | jsonlite_accept_object_end,
Josh Hollenbeck 1:807034181e02 73 jsonlite_accept_continue_array = 0
Josh Hollenbeck 1:807034181e02 74 | jsonlite_accept_next
Josh Hollenbeck 1:807034181e02 75 | jsonlite_accept_values_only
Josh Hollenbeck 1:807034181e02 76 | jsonlite_accept_value
Josh Hollenbeck 1:807034181e02 77 | jsonlite_accept_array_end
Josh Hollenbeck 1:807034181e02 78 };
Josh Hollenbeck 1:807034181e02 79
Josh Hollenbeck 1:807034181e02 80 typedef uint16_t jsonlite_write_state;
Josh Hollenbeck 1:807034181e02 81 typedef struct jsonlite_builder_struct {
Josh Hollenbeck 1:807034181e02 82 jsonlite_write_state *state;
Josh Hollenbeck 1:807034181e02 83 jsonlite_write_state *limit;
Josh Hollenbeck 1:807034181e02 84 jsonlite_write_state *stack;
Josh Hollenbeck 1:807034181e02 85 jsonlite_stream stream;
Josh Hollenbeck 1:807034181e02 86
Josh Hollenbeck 1:807034181e02 87 size_t indentation;
Josh Hollenbeck 1:807034181e02 88 char *doubleFormat;
Josh Hollenbeck 1:807034181e02 89 } jsonlite_builder_struct;
Josh Hollenbeck 1:807034181e02 90
Josh Hollenbeck 1:807034181e02 91 static int jsonlite_builder_accept(jsonlite_builder builder, jsonlite_write_state a);
Josh Hollenbeck 1:807034181e02 92 static void jsonlite_builder_pop_state(jsonlite_builder builder);
Josh Hollenbeck 1:807034181e02 93 static void jsonlite_builder_prepare_value_writing(jsonlite_builder builder);
Josh Hollenbeck 1:807034181e02 94 static void jsonlite_builder_raw_char(jsonlite_builder builder, char data);
Josh Hollenbeck 1:807034181e02 95 static void jsonlite_builder_write_uft8(jsonlite_builder builder, const char *data, size_t length);
Josh Hollenbeck 1:807034181e02 96 static void jsonlite_builder_raw(jsonlite_builder builder, const void *data, size_t length);
Josh Hollenbeck 1:807034181e02 97 static void jsonlite_builder_repeat(jsonlite_builder builder, const char ch, size_t count);
Josh Hollenbeck 1:807034181e02 98 static void jsonlite_builder_write_base64(jsonlite_builder builder, const void *data, size_t length);
Josh Hollenbeck 1:807034181e02 99
Josh Hollenbeck 1:807034181e02 100 jsonlite_builder jsonlite_builder_init(size_t depth, jsonlite_stream stream) {
Josh Hollenbeck 1:807034181e02 101 jsonlite_builder builder;
Josh Hollenbeck 1:807034181e02 102
Josh Hollenbeck 1:807034181e02 103 depth = depth < 2 ? 2 : depth;
Josh Hollenbeck 1:807034181e02 104
Josh Hollenbeck 1:807034181e02 105 builder = malloc(sizeof(jsonlite_builder_struct) + depth * sizeof(jsonlite_write_state));
Josh Hollenbeck 1:807034181e02 106 builder->state = (jsonlite_write_state *)((uint8_t *)builder + sizeof(jsonlite_builder_struct));
Josh Hollenbeck 1:807034181e02 107 builder->limit = builder->state + depth - 1;
Josh Hollenbeck 1:807034181e02 108 builder->stack = builder->state;
Josh Hollenbeck 1:807034181e02 109 builder->stream = stream;
Josh Hollenbeck 1:807034181e02 110 builder->indentation = 0;
Josh Hollenbeck 1:807034181e02 111 *builder->state = jsonlite_accept_object_begin | jsonlite_accept_array_begin;
Josh Hollenbeck 1:807034181e02 112 jsonlite_builder_set_double_format(builder, "%.16g");
Josh Hollenbeck 1:807034181e02 113 return builder;
Josh Hollenbeck 1:807034181e02 114 }
Josh Hollenbeck 1:807034181e02 115
Josh Hollenbeck 1:807034181e02 116 jsonlite_result jsonlite_builder_release(jsonlite_builder builder) {
Josh Hollenbeck 1:807034181e02 117 if (builder == NULL) {
Josh Hollenbeck 1:807034181e02 118 return jsonlite_result_invalid_argument;
Josh Hollenbeck 1:807034181e02 119 }
Josh Hollenbeck 1:807034181e02 120
Josh Hollenbeck 1:807034181e02 121 free(builder->doubleFormat);
Josh Hollenbeck 1:807034181e02 122 free(builder);
Josh Hollenbeck 1:807034181e02 123 return jsonlite_result_ok;
Josh Hollenbeck 1:807034181e02 124 }
Josh Hollenbeck 1:807034181e02 125
Josh Hollenbeck 1:807034181e02 126 jsonlite_result jsonlite_builder_set_indentation(jsonlite_builder builder, size_t indentation) {
Josh Hollenbeck 1:807034181e02 127 if (builder != NULL) {
Josh Hollenbeck 1:807034181e02 128 builder->indentation = indentation;
Josh Hollenbeck 1:807034181e02 129 return jsonlite_result_ok;
Josh Hollenbeck 1:807034181e02 130 }
Josh Hollenbeck 1:807034181e02 131 return jsonlite_result_invalid_argument;
Josh Hollenbeck 1:807034181e02 132 }
Josh Hollenbeck 1:807034181e02 133
Josh Hollenbeck 1:807034181e02 134 jsonlite_result jsonlite_builder_set_double_format(jsonlite_builder builder, const char *format) {
Josh Hollenbeck 1:807034181e02 135 if (builder != NULL && format != NULL) {
Josh Hollenbeck 1:807034181e02 136 builder->doubleFormat = strdup(format);
Josh Hollenbeck 1:807034181e02 137 return jsonlite_result_ok;
Josh Hollenbeck 1:807034181e02 138 }
Josh Hollenbeck 1:807034181e02 139 return jsonlite_result_invalid_argument;
Josh Hollenbeck 1:807034181e02 140 }
Josh Hollenbeck 1:807034181e02 141
Josh Hollenbeck 1:807034181e02 142 static int jsonlite_builder_accept(jsonlite_builder builder, jsonlite_write_state a) {
Josh Hollenbeck 1:807034181e02 143 return (*builder->state & a) == a;
Josh Hollenbeck 1:807034181e02 144 }
Josh Hollenbeck 1:807034181e02 145
Josh Hollenbeck 1:807034181e02 146 static void jsonlite_builder_pop_state(jsonlite_builder builder) {
Josh Hollenbeck 1:807034181e02 147 jsonlite_write_state *ws = --builder->state;
Josh Hollenbeck 1:807034181e02 148 if (jsonlite_builder_accept(builder, jsonlite_accept_values_only)) {
Josh Hollenbeck 1:807034181e02 149 *ws = jsonlite_accept_continue_array;
Josh Hollenbeck 1:807034181e02 150 } else {
Josh Hollenbeck 1:807034181e02 151 *ws = jsonlite_accept_continue_object;
Josh Hollenbeck 1:807034181e02 152 }
Josh Hollenbeck 1:807034181e02 153 }
Josh Hollenbeck 1:807034181e02 154
Josh Hollenbeck 1:807034181e02 155 static void jsonlite_builder_prepare_value_writing(jsonlite_builder builder) {
Josh Hollenbeck 1:807034181e02 156 jsonlite_write_state *ws = builder->state;
Josh Hollenbeck 1:807034181e02 157 if (jsonlite_builder_accept(builder, jsonlite_accept_values_only)) {
Josh Hollenbeck 1:807034181e02 158 if (jsonlite_builder_accept(builder, jsonlite_accept_next)) {
Josh Hollenbeck 1:807034181e02 159 jsonlite_builder_raw_char(builder, ',');
Josh Hollenbeck 1:807034181e02 160 }
Josh Hollenbeck 1:807034181e02 161
Josh Hollenbeck 1:807034181e02 162 if (builder->indentation != 0) {
Josh Hollenbeck 1:807034181e02 163 jsonlite_builder_raw_char(builder, '\r');
Josh Hollenbeck 1:807034181e02 164 jsonlite_builder_repeat(builder, ' ', (builder->state - builder->stack) * builder->indentation);
Josh Hollenbeck 1:807034181e02 165 }
Josh Hollenbeck 1:807034181e02 166 } else {
Josh Hollenbeck 1:807034181e02 167 *ws &= ~jsonlite_accept_value;
Josh Hollenbeck 1:807034181e02 168 *ws |= jsonlite_accept_key;
Josh Hollenbeck 1:807034181e02 169 }
Josh Hollenbeck 1:807034181e02 170 *ws |= jsonlite_accept_next;
Josh Hollenbeck 1:807034181e02 171 }
Josh Hollenbeck 1:807034181e02 172
Josh Hollenbeck 1:807034181e02 173 jsonlite_result jsonlite_builder_object_begin(jsonlite_builder builder) {
Josh Hollenbeck 1:807034181e02 174 if (builder == NULL) {
Josh Hollenbeck 1:807034181e02 175 return jsonlite_result_invalid_argument;
Josh Hollenbeck 1:807034181e02 176 }
Josh Hollenbeck 1:807034181e02 177
Josh Hollenbeck 1:807034181e02 178 jsonlite_builder_check_depth();
Josh Hollenbeck 1:807034181e02 179
Josh Hollenbeck 1:807034181e02 180 if (jsonlite_builder_accept(builder, jsonlite_accept_object_begin)) {
Josh Hollenbeck 1:807034181e02 181 jsonlite_builder_prepare_value_writing(builder);
Josh Hollenbeck 1:807034181e02 182 *++builder->state = jsonlite_accept_object_end | jsonlite_accept_key;
Josh Hollenbeck 1:807034181e02 183 jsonlite_builder_raw_char(builder, '{');
Josh Hollenbeck 1:807034181e02 184 return jsonlite_result_ok;
Josh Hollenbeck 1:807034181e02 185 }
Josh Hollenbeck 1:807034181e02 186
Josh Hollenbeck 1:807034181e02 187 return jsonlite_result_not_allowed;
Josh Hollenbeck 1:807034181e02 188 }
Josh Hollenbeck 1:807034181e02 189
Josh Hollenbeck 1:807034181e02 190 jsonlite_result jsonlite_builder_object_end(jsonlite_builder builder) {
Josh Hollenbeck 1:807034181e02 191 if (builder == NULL) {
Josh Hollenbeck 1:807034181e02 192 return jsonlite_result_invalid_argument;
Josh Hollenbeck 1:807034181e02 193 }
Josh Hollenbeck 1:807034181e02 194
Josh Hollenbeck 1:807034181e02 195 if (jsonlite_builder_accept(builder, jsonlite_accept_object_end)) {
Josh Hollenbeck 1:807034181e02 196 jsonlite_builder_pop_state(builder);
Josh Hollenbeck 1:807034181e02 197 if (builder->indentation != 0) {
Josh Hollenbeck 1:807034181e02 198 jsonlite_builder_raw_char(builder, '\r');
Josh Hollenbeck 1:807034181e02 199 jsonlite_builder_repeat(builder, ' ', (builder->state - builder->stack) * builder->indentation);
Josh Hollenbeck 1:807034181e02 200 }
Josh Hollenbeck 1:807034181e02 201 jsonlite_builder_raw_char(builder, '}');
Josh Hollenbeck 1:807034181e02 202 return jsonlite_result_ok;
Josh Hollenbeck 1:807034181e02 203 }
Josh Hollenbeck 1:807034181e02 204
Josh Hollenbeck 1:807034181e02 205 return jsonlite_result_not_allowed;
Josh Hollenbeck 1:807034181e02 206 }
Josh Hollenbeck 1:807034181e02 207
Josh Hollenbeck 1:807034181e02 208 jsonlite_result jsonlite_builder_array_begin(jsonlite_builder builder) {
Josh Hollenbeck 1:807034181e02 209 if (builder == NULL) {
Josh Hollenbeck 1:807034181e02 210 return jsonlite_result_invalid_argument;
Josh Hollenbeck 1:807034181e02 211 }
Josh Hollenbeck 1:807034181e02 212
Josh Hollenbeck 1:807034181e02 213 jsonlite_builder_check_depth();
Josh Hollenbeck 1:807034181e02 214
Josh Hollenbeck 1:807034181e02 215 if (jsonlite_builder_accept(builder, jsonlite_accept_array_begin)) {
Josh Hollenbeck 1:807034181e02 216 jsonlite_builder_prepare_value_writing(builder);
Josh Hollenbeck 1:807034181e02 217 *++builder->state = jsonlite_accept_array_end
Josh Hollenbeck 1:807034181e02 218 | jsonlite_accept_value
Josh Hollenbeck 1:807034181e02 219 | jsonlite_accept_values_only;
Josh Hollenbeck 1:807034181e02 220 jsonlite_builder_raw_char(builder, '[');
Josh Hollenbeck 1:807034181e02 221 return jsonlite_result_ok;
Josh Hollenbeck 1:807034181e02 222 }
Josh Hollenbeck 1:807034181e02 223
Josh Hollenbeck 1:807034181e02 224 return jsonlite_result_not_allowed;
Josh Hollenbeck 1:807034181e02 225 }
Josh Hollenbeck 1:807034181e02 226
Josh Hollenbeck 1:807034181e02 227 jsonlite_result jsonlite_builder_array_end(jsonlite_builder builder) {
Josh Hollenbeck 1:807034181e02 228 if (builder == NULL) {
Josh Hollenbeck 1:807034181e02 229 return jsonlite_result_invalid_argument;
Josh Hollenbeck 1:807034181e02 230 }
Josh Hollenbeck 1:807034181e02 231
Josh Hollenbeck 1:807034181e02 232 if (jsonlite_builder_accept(builder, jsonlite_accept_array_end)) {
Josh Hollenbeck 1:807034181e02 233 jsonlite_builder_pop_state(builder);
Josh Hollenbeck 1:807034181e02 234 if (builder->indentation != 0) {
Josh Hollenbeck 1:807034181e02 235 jsonlite_builder_raw_char(builder, '\r');
Josh Hollenbeck 1:807034181e02 236 jsonlite_builder_repeat(builder, ' ', (builder->state - builder->stack) * builder->indentation);
Josh Hollenbeck 1:807034181e02 237 }
Josh Hollenbeck 1:807034181e02 238 jsonlite_builder_raw_char(builder, ']');
Josh Hollenbeck 1:807034181e02 239 return jsonlite_result_ok;
Josh Hollenbeck 1:807034181e02 240 }
Josh Hollenbeck 1:807034181e02 241
Josh Hollenbeck 1:807034181e02 242 return jsonlite_result_not_allowed;
Josh Hollenbeck 1:807034181e02 243 }
Josh Hollenbeck 1:807034181e02 244
Josh Hollenbeck 1:807034181e02 245 static void jsonlite_builder_write_uft8(jsonlite_builder builder, const char *data, size_t length) {
Josh Hollenbeck 1:807034181e02 246 char b[2] = {'\\', '?'};
Josh Hollenbeck 1:807034181e02 247 const char *c = data;
Josh Hollenbeck 1:807034181e02 248 const char *p = data;
Josh Hollenbeck 1:807034181e02 249 const char *l = data + length;
Josh Hollenbeck 1:807034181e02 250
Josh Hollenbeck 1:807034181e02 251 jsonlite_builder_raw_char(builder, '\"');
Josh Hollenbeck 1:807034181e02 252 next:
Josh Hollenbeck 1:807034181e02 253 if (c == l) goto end;
Josh Hollenbeck 1:807034181e02 254 switch (*c) {
Josh Hollenbeck 1:807034181e02 255 case '"': b[1] = '"'; goto flush;
Josh Hollenbeck 1:807034181e02 256 case '\\': b[1] = '\\'; goto flush;
Josh Hollenbeck 1:807034181e02 257 case '\b': b[1] = 'b'; goto flush;
Josh Hollenbeck 1:807034181e02 258 case '\f': b[1] = 'f'; goto flush;
Josh Hollenbeck 1:807034181e02 259 case '\n': b[1] = 'n'; goto flush;
Josh Hollenbeck 1:807034181e02 260 case '\r': b[1] = 'r'; goto flush;
Josh Hollenbeck 1:807034181e02 261 case '\t': b[1] = 't'; goto flush;
Josh Hollenbeck 1:807034181e02 262 default: c++; goto next;
Josh Hollenbeck 1:807034181e02 263 }
Josh Hollenbeck 1:807034181e02 264 flush:
Josh Hollenbeck 1:807034181e02 265 jsonlite_stream_write(builder->stream, p, c - p);
Josh Hollenbeck 1:807034181e02 266 jsonlite_stream_write(builder->stream, b, 2);
Josh Hollenbeck 1:807034181e02 267 p = ++c;
Josh Hollenbeck 1:807034181e02 268 goto next;
Josh Hollenbeck 1:807034181e02 269 end:
Josh Hollenbeck 1:807034181e02 270 jsonlite_stream_write(builder->stream, p, c - p);
Josh Hollenbeck 1:807034181e02 271 jsonlite_builder_raw_char(builder, '\"');
Josh Hollenbeck 1:807034181e02 272 }
Josh Hollenbeck 1:807034181e02 273
Josh Hollenbeck 1:807034181e02 274 jsonlite_result jsonlite_builder_key(jsonlite_builder builder, const char *data, size_t length) {
Josh Hollenbeck 1:807034181e02 275 if (builder == NULL || data == NULL) {
Josh Hollenbeck 1:807034181e02 276 return jsonlite_result_invalid_argument;
Josh Hollenbeck 1:807034181e02 277 }
Josh Hollenbeck 1:807034181e02 278
Josh Hollenbeck 1:807034181e02 279 jsonlite_write_state *ws = builder->state;
Josh Hollenbeck 1:807034181e02 280 if (jsonlite_builder_accept(builder, jsonlite_accept_key)) {
Josh Hollenbeck 1:807034181e02 281 if (jsonlite_builder_accept(builder, jsonlite_accept_next)) {
Josh Hollenbeck 1:807034181e02 282 jsonlite_builder_raw_char(builder, ',');
Josh Hollenbeck 1:807034181e02 283 }
Josh Hollenbeck 1:807034181e02 284
Josh Hollenbeck 1:807034181e02 285 if (builder->indentation != 0) {
Josh Hollenbeck 1:807034181e02 286 jsonlite_builder_raw_char(builder, '\r');
Josh Hollenbeck 1:807034181e02 287 jsonlite_builder_repeat(builder, ' ', (builder->state - builder->stack) * builder->indentation);
Josh Hollenbeck 1:807034181e02 288 }
Josh Hollenbeck 1:807034181e02 289
Josh Hollenbeck 1:807034181e02 290 jsonlite_builder_write_uft8(builder, data, length);
Josh Hollenbeck 1:807034181e02 291 if (builder->indentation != 0) {
Josh Hollenbeck 1:807034181e02 292 jsonlite_builder_raw(builder, ": ", 2);
Josh Hollenbeck 1:807034181e02 293 } else {
Josh Hollenbeck 1:807034181e02 294 jsonlite_builder_raw_char(builder, ':');
Josh Hollenbeck 1:807034181e02 295 }
Josh Hollenbeck 1:807034181e02 296 *ws = jsonlite_accept_value;
Josh Hollenbeck 1:807034181e02 297 return jsonlite_result_ok;
Josh Hollenbeck 1:807034181e02 298 }
Josh Hollenbeck 1:807034181e02 299
Josh Hollenbeck 1:807034181e02 300 return jsonlite_result_not_allowed;
Josh Hollenbeck 1:807034181e02 301 }
Josh Hollenbeck 1:807034181e02 302
Josh Hollenbeck 1:807034181e02 303 jsonlite_result jsonlite_builder_string(jsonlite_builder builder, const char *data, size_t length) {
Josh Hollenbeck 1:807034181e02 304 if (builder == NULL || data == NULL) {
Josh Hollenbeck 1:807034181e02 305 return jsonlite_result_invalid_argument;
Josh Hollenbeck 1:807034181e02 306 }
Josh Hollenbeck 1:807034181e02 307
Josh Hollenbeck 1:807034181e02 308 jsonlite_write_state *ws = builder->state;
Josh Hollenbeck 1:807034181e02 309 if (jsonlite_builder_accept(builder, jsonlite_accept_value)) {
Josh Hollenbeck 1:807034181e02 310 jsonlite_builder_prepare_value_writing(builder);
Josh Hollenbeck 1:807034181e02 311 jsonlite_builder_write_uft8(builder, data, length);
Josh Hollenbeck 1:807034181e02 312 if (jsonlite_builder_accept(builder, jsonlite_accept_values_only)) {
Josh Hollenbeck 1:807034181e02 313 *ws = jsonlite_accept_continue_array;
Josh Hollenbeck 1:807034181e02 314 } else {
Josh Hollenbeck 1:807034181e02 315 *ws = jsonlite_accept_continue_object;
Josh Hollenbeck 1:807034181e02 316 }
Josh Hollenbeck 1:807034181e02 317 return jsonlite_result_ok;
Josh Hollenbeck 1:807034181e02 318 }
Josh Hollenbeck 1:807034181e02 319
Josh Hollenbeck 1:807034181e02 320 return jsonlite_result_not_allowed;
Josh Hollenbeck 1:807034181e02 321 }
Josh Hollenbeck 1:807034181e02 322
Josh Hollenbeck 1:807034181e02 323 jsonlite_result jsonlite_builder_int(jsonlite_builder builder, long long value) {
Josh Hollenbeck 1:807034181e02 324 if (builder == NULL) {
Josh Hollenbeck 1:807034181e02 325 return jsonlite_result_invalid_argument;
Josh Hollenbeck 1:807034181e02 326 }
Josh Hollenbeck 1:807034181e02 327
Josh Hollenbeck 1:807034181e02 328 char buff[64];
Josh Hollenbeck 1:807034181e02 329 size_t size = 0;
Josh Hollenbeck 1:807034181e02 330 jsonlite_write_state *ws = builder->state;
Josh Hollenbeck 1:807034181e02 331 if (jsonlite_builder_accept(builder, jsonlite_accept_value)) {
Josh Hollenbeck 1:807034181e02 332 jsonlite_builder_prepare_value_writing(builder);
Josh Hollenbeck 1:807034181e02 333 size = sprintf(buff, "%lld", value);
Josh Hollenbeck 1:807034181e02 334 jsonlite_builder_raw(builder, buff, size);
Josh Hollenbeck 1:807034181e02 335 if (jsonlite_builder_accept(builder, jsonlite_accept_values_only)) {
Josh Hollenbeck 1:807034181e02 336 *ws = jsonlite_accept_continue_array;
Josh Hollenbeck 1:807034181e02 337 } else {
Josh Hollenbeck 1:807034181e02 338 *ws = jsonlite_accept_continue_object;
Josh Hollenbeck 1:807034181e02 339 }
Josh Hollenbeck 1:807034181e02 340 return jsonlite_result_ok;
Josh Hollenbeck 1:807034181e02 341 }
Josh Hollenbeck 1:807034181e02 342
Josh Hollenbeck 1:807034181e02 343 return jsonlite_result_not_allowed;
Josh Hollenbeck 1:807034181e02 344 }
Josh Hollenbeck 1:807034181e02 345
Josh Hollenbeck 1:807034181e02 346 jsonlite_result jsonlite_builder_double(jsonlite_builder builder, double value) {
Josh Hollenbeck 1:807034181e02 347 if (builder == NULL) {
Josh Hollenbeck 1:807034181e02 348 return jsonlite_result_invalid_argument;
Josh Hollenbeck 1:807034181e02 349 }
Josh Hollenbeck 1:807034181e02 350
Josh Hollenbeck 1:807034181e02 351 char buff[64];
Josh Hollenbeck 1:807034181e02 352 size_t size = 0;
Josh Hollenbeck 1:807034181e02 353 jsonlite_write_state *ws = builder->state;
Josh Hollenbeck 1:807034181e02 354 if (jsonlite_builder_accept(builder, jsonlite_accept_value)) {
Josh Hollenbeck 1:807034181e02 355 jsonlite_builder_prepare_value_writing(builder);
Josh Hollenbeck 1:807034181e02 356 size = sprintf(buff, builder->doubleFormat, value);
Josh Hollenbeck 1:807034181e02 357 jsonlite_builder_raw(builder, buff, size);
Josh Hollenbeck 1:807034181e02 358 if (jsonlite_builder_accept(builder, jsonlite_accept_values_only)) {
Josh Hollenbeck 1:807034181e02 359 *ws = jsonlite_accept_continue_array;
Josh Hollenbeck 1:807034181e02 360 } else {
Josh Hollenbeck 1:807034181e02 361 *ws = jsonlite_accept_continue_object;
Josh Hollenbeck 1:807034181e02 362 }
Josh Hollenbeck 1:807034181e02 363 return jsonlite_result_ok;
Josh Hollenbeck 1:807034181e02 364 }
Josh Hollenbeck 1:807034181e02 365
Josh Hollenbeck 1:807034181e02 366 return jsonlite_result_not_allowed;
Josh Hollenbeck 1:807034181e02 367 }
Josh Hollenbeck 1:807034181e02 368
Josh Hollenbeck 1:807034181e02 369 jsonlite_result jsonlite_builder_true(jsonlite_builder builder) {
Josh Hollenbeck 1:807034181e02 370 if (builder == NULL) {
Josh Hollenbeck 1:807034181e02 371 return jsonlite_result_invalid_argument;
Josh Hollenbeck 1:807034181e02 372 }
Josh Hollenbeck 1:807034181e02 373
Josh Hollenbeck 1:807034181e02 374 static const char value[] = "true";
Josh Hollenbeck 1:807034181e02 375 jsonlite_write_state *ws = builder->state;
Josh Hollenbeck 1:807034181e02 376 if (!(jsonlite_builder_accept(builder, jsonlite_accept_value))) {
Josh Hollenbeck 1:807034181e02 377
Josh Hollenbeck 1:807034181e02 378 return jsonlite_result_not_allowed;
Josh Hollenbeck 1:807034181e02 379 }
Josh Hollenbeck 1:807034181e02 380
Josh Hollenbeck 1:807034181e02 381 jsonlite_builder_prepare_value_writing(builder);
Josh Hollenbeck 1:807034181e02 382 jsonlite_builder_raw(builder, (char *)value, sizeof(value) - 1);
Josh Hollenbeck 1:807034181e02 383 if (jsonlite_builder_accept(builder, jsonlite_accept_values_only)) {
Josh Hollenbeck 1:807034181e02 384 *ws = jsonlite_accept_continue_array;
Josh Hollenbeck 1:807034181e02 385 } else {
Josh Hollenbeck 1:807034181e02 386 *ws = jsonlite_accept_continue_object;
Josh Hollenbeck 1:807034181e02 387 }
Josh Hollenbeck 1:807034181e02 388 return jsonlite_result_ok;
Josh Hollenbeck 1:807034181e02 389 }
Josh Hollenbeck 1:807034181e02 390
Josh Hollenbeck 1:807034181e02 391 jsonlite_result jsonlite_builder_false(jsonlite_builder builder) {
Josh Hollenbeck 1:807034181e02 392 if (builder == NULL) {
Josh Hollenbeck 1:807034181e02 393 return jsonlite_result_invalid_argument;
Josh Hollenbeck 1:807034181e02 394 }
Josh Hollenbeck 1:807034181e02 395
Josh Hollenbeck 1:807034181e02 396 static const char value[] = "false";
Josh Hollenbeck 1:807034181e02 397 jsonlite_write_state *ws = builder->state;
Josh Hollenbeck 1:807034181e02 398 if (!(jsonlite_builder_accept(builder, jsonlite_accept_value))) {
Josh Hollenbeck 1:807034181e02 399 return jsonlite_result_not_allowed;
Josh Hollenbeck 1:807034181e02 400 }
Josh Hollenbeck 1:807034181e02 401
Josh Hollenbeck 1:807034181e02 402 jsonlite_builder_prepare_value_writing(builder);
Josh Hollenbeck 1:807034181e02 403 jsonlite_builder_raw(builder, (char *)value, sizeof(value) - 1);
Josh Hollenbeck 1:807034181e02 404 if (jsonlite_builder_accept(builder, jsonlite_accept_values_only)) {
Josh Hollenbeck 1:807034181e02 405 *ws = jsonlite_accept_continue_array;
Josh Hollenbeck 1:807034181e02 406 } else {
Josh Hollenbeck 1:807034181e02 407 *ws = jsonlite_accept_continue_object;
Josh Hollenbeck 1:807034181e02 408 }
Josh Hollenbeck 1:807034181e02 409 return jsonlite_result_ok;
Josh Hollenbeck 1:807034181e02 410 }
Josh Hollenbeck 1:807034181e02 411
Josh Hollenbeck 1:807034181e02 412 jsonlite_result jsonlite_builder_null(jsonlite_builder builder) {
Josh Hollenbeck 1:807034181e02 413 if (builder == NULL) {
Josh Hollenbeck 1:807034181e02 414 return jsonlite_result_invalid_argument;
Josh Hollenbeck 1:807034181e02 415 }
Josh Hollenbeck 1:807034181e02 416
Josh Hollenbeck 1:807034181e02 417 static const char value[] = "null";
Josh Hollenbeck 1:807034181e02 418 jsonlite_write_state *ws = builder->state;
Josh Hollenbeck 1:807034181e02 419 if (!(jsonlite_builder_accept(builder, jsonlite_accept_value))) {
Josh Hollenbeck 1:807034181e02 420
Josh Hollenbeck 1:807034181e02 421 return jsonlite_result_not_allowed;
Josh Hollenbeck 1:807034181e02 422 }
Josh Hollenbeck 1:807034181e02 423
Josh Hollenbeck 1:807034181e02 424 jsonlite_builder_prepare_value_writing(builder);
Josh Hollenbeck 1:807034181e02 425 jsonlite_builder_raw(builder, (char *)value, sizeof(value) - 1);
Josh Hollenbeck 1:807034181e02 426 if (jsonlite_builder_accept(builder, jsonlite_accept_values_only)) {
Josh Hollenbeck 1:807034181e02 427 *ws = jsonlite_accept_continue_array;
Josh Hollenbeck 1:807034181e02 428 } else {
Josh Hollenbeck 1:807034181e02 429 *ws = jsonlite_accept_continue_object;
Josh Hollenbeck 1:807034181e02 430 }
Josh Hollenbeck 1:807034181e02 431 return jsonlite_result_ok;
Josh Hollenbeck 1:807034181e02 432 }
Josh Hollenbeck 1:807034181e02 433
Josh Hollenbeck 1:807034181e02 434 static void jsonlite_builder_raw(jsonlite_builder builder, const void *data, size_t length) {
Josh Hollenbeck 1:807034181e02 435 jsonlite_stream_write(builder->stream, data, length);
Josh Hollenbeck 1:807034181e02 436 }
Josh Hollenbeck 1:807034181e02 437
Josh Hollenbeck 1:807034181e02 438 static void jsonlite_builder_repeat(jsonlite_builder builder, const char ch, size_t count) {
Josh Hollenbeck 1:807034181e02 439 ptrdiff_t i = 0;
Josh Hollenbeck 1:807034181e02 440 for (; i < count; i++) {
Josh Hollenbeck 1:807034181e02 441 jsonlite_stream_write(builder->stream, &ch, 1);
Josh Hollenbeck 1:807034181e02 442 }
Josh Hollenbeck 1:807034181e02 443 }
Josh Hollenbeck 1:807034181e02 444
Josh Hollenbeck 1:807034181e02 445 static void jsonlite_builder_raw_char(jsonlite_builder builder, char data) {
Josh Hollenbeck 1:807034181e02 446 jsonlite_stream_write(builder->stream, &data, 1);
Josh Hollenbeck 1:807034181e02 447 }
Josh Hollenbeck 1:807034181e02 448
Josh Hollenbeck 1:807034181e02 449 jsonlite_result jsonlite_builder_raw_key(jsonlite_builder builder, const void *data, size_t length) {
Josh Hollenbeck 1:807034181e02 450 if (builder == NULL || data == NULL || length == 0) {
Josh Hollenbeck 1:807034181e02 451 return jsonlite_result_invalid_argument;
Josh Hollenbeck 1:807034181e02 452 }
Josh Hollenbeck 1:807034181e02 453
Josh Hollenbeck 1:807034181e02 454 jsonlite_write_state *ws = builder->state;
Josh Hollenbeck 1:807034181e02 455 if (jsonlite_builder_accept(builder, jsonlite_accept_key)) {
Josh Hollenbeck 1:807034181e02 456 if (jsonlite_builder_accept(builder, jsonlite_accept_next)) {
Josh Hollenbeck 1:807034181e02 457 jsonlite_builder_raw(builder, ",", 1);
Josh Hollenbeck 1:807034181e02 458 }
Josh Hollenbeck 1:807034181e02 459
Josh Hollenbeck 1:807034181e02 460 if (builder->indentation != 0) {
Josh Hollenbeck 1:807034181e02 461 jsonlite_builder_raw_char(builder, '\r');
Josh Hollenbeck 1:807034181e02 462 jsonlite_builder_repeat(builder, ' ', (builder->state - builder->stack) * builder->indentation);
Josh Hollenbeck 1:807034181e02 463 }
Josh Hollenbeck 1:807034181e02 464
Josh Hollenbeck 1:807034181e02 465 jsonlite_builder_raw_char(builder, '\"');
Josh Hollenbeck 1:807034181e02 466 jsonlite_builder_raw(builder, data, length);
Josh Hollenbeck 1:807034181e02 467 jsonlite_builder_raw_char(builder, '\"');
Josh Hollenbeck 1:807034181e02 468 if (builder->indentation != 0) {
Josh Hollenbeck 1:807034181e02 469 jsonlite_builder_raw(builder, ": ", 2);
Josh Hollenbeck 1:807034181e02 470 } else {
Josh Hollenbeck 1:807034181e02 471 jsonlite_builder_raw_char(builder, ':');
Josh Hollenbeck 1:807034181e02 472 }
Josh Hollenbeck 1:807034181e02 473 *ws = jsonlite_accept_value;
Josh Hollenbeck 1:807034181e02 474 return jsonlite_result_ok;
Josh Hollenbeck 1:807034181e02 475 }
Josh Hollenbeck 1:807034181e02 476
Josh Hollenbeck 1:807034181e02 477 return jsonlite_result_not_allowed;
Josh Hollenbeck 1:807034181e02 478 }
Josh Hollenbeck 1:807034181e02 479
Josh Hollenbeck 1:807034181e02 480 jsonlite_result jsonlite_builder_raw_string(jsonlite_builder builder, const void *data, size_t length) {
Josh Hollenbeck 1:807034181e02 481 if (builder == NULL || data == NULL || length == 0) {
Josh Hollenbeck 1:807034181e02 482 return jsonlite_result_invalid_argument;
Josh Hollenbeck 1:807034181e02 483 }
Josh Hollenbeck 1:807034181e02 484
Josh Hollenbeck 1:807034181e02 485 jsonlite_write_state *ws = builder->state;
Josh Hollenbeck 1:807034181e02 486 if (jsonlite_builder_accept(builder, jsonlite_accept_value)) {
Josh Hollenbeck 1:807034181e02 487 jsonlite_builder_prepare_value_writing(builder);
Josh Hollenbeck 1:807034181e02 488 jsonlite_builder_raw_char(builder, '\"');
Josh Hollenbeck 1:807034181e02 489 jsonlite_builder_raw(builder, data, length);
Josh Hollenbeck 1:807034181e02 490 jsonlite_builder_raw_char(builder, '\"');
Josh Hollenbeck 1:807034181e02 491 if (jsonlite_builder_accept(builder, jsonlite_accept_values_only)) {
Josh Hollenbeck 1:807034181e02 492 *ws = jsonlite_accept_continue_array;
Josh Hollenbeck 1:807034181e02 493 } else {
Josh Hollenbeck 1:807034181e02 494 *ws = jsonlite_accept_continue_object;
Josh Hollenbeck 1:807034181e02 495 }
Josh Hollenbeck 1:807034181e02 496 return jsonlite_result_ok;
Josh Hollenbeck 1:807034181e02 497 }
Josh Hollenbeck 1:807034181e02 498
Josh Hollenbeck 1:807034181e02 499 return jsonlite_result_not_allowed;
Josh Hollenbeck 1:807034181e02 500 }
Josh Hollenbeck 1:807034181e02 501
Josh Hollenbeck 1:807034181e02 502 jsonlite_result jsonlite_builder_raw_value(jsonlite_builder builder, const void *data, size_t length) {
Josh Hollenbeck 1:807034181e02 503 if (builder == NULL || data == NULL || length == 0) {
Josh Hollenbeck 1:807034181e02 504 return jsonlite_result_invalid_argument;
Josh Hollenbeck 1:807034181e02 505 }
Josh Hollenbeck 1:807034181e02 506
Josh Hollenbeck 1:807034181e02 507 jsonlite_write_state *ws = builder->state;
Josh Hollenbeck 1:807034181e02 508 if (jsonlite_builder_accept(builder, jsonlite_accept_value)) {
Josh Hollenbeck 1:807034181e02 509 jsonlite_builder_prepare_value_writing(builder);
Josh Hollenbeck 1:807034181e02 510 jsonlite_builder_raw(builder, data, length);
Josh Hollenbeck 1:807034181e02 511 if (jsonlite_builder_accept(builder, jsonlite_accept_values_only)) {
Josh Hollenbeck 1:807034181e02 512 *ws = jsonlite_accept_continue_array;
Josh Hollenbeck 1:807034181e02 513 } else {
Josh Hollenbeck 1:807034181e02 514 *ws = jsonlite_accept_continue_object;
Josh Hollenbeck 1:807034181e02 515 }
Josh Hollenbeck 1:807034181e02 516 return jsonlite_result_ok;
Josh Hollenbeck 1:807034181e02 517 }
Josh Hollenbeck 1:807034181e02 518
Josh Hollenbeck 1:807034181e02 519 return jsonlite_result_not_allowed;
Josh Hollenbeck 1:807034181e02 520 }
Josh Hollenbeck 1:807034181e02 521
Josh Hollenbeck 1:807034181e02 522 static void jsonlite_builder_write_base64(jsonlite_builder builder, const void *data, size_t length) {
Josh Hollenbeck 1:807034181e02 523 static const char encode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
Josh Hollenbeck 1:807034181e02 524 char buffer[5] = {0};
Josh Hollenbeck 1:807034181e02 525 const uint8_t *c = data;
Josh Hollenbeck 1:807034181e02 526 const uint8_t *l = data + length;
Josh Hollenbeck 1:807034181e02 527 uint32_t bits;
Josh Hollenbeck 1:807034181e02 528 jsonlite_stream_write(builder->stream, "\"", 1);
Josh Hollenbeck 1:807034181e02 529 next:
Josh Hollenbeck 1:807034181e02 530 switch (l - c) {
Josh Hollenbeck 1:807034181e02 531 case 0:
Josh Hollenbeck 1:807034181e02 532 goto done;
Josh Hollenbeck 1:807034181e02 533 case 1:
Josh Hollenbeck 1:807034181e02 534 bits = *c++ << 16;
Josh Hollenbeck 1:807034181e02 535 buffer[0] = encode[(bits & 0x00FC0000) >> 18];
Josh Hollenbeck 1:807034181e02 536 buffer[1] = encode[(bits & 0x0003F000) >> 12];
Josh Hollenbeck 1:807034181e02 537 buffer[2] = '=';
Josh Hollenbeck 1:807034181e02 538 buffer[3] = '=';
Josh Hollenbeck 1:807034181e02 539 l = c;
Josh Hollenbeck 1:807034181e02 540 goto write;
Josh Hollenbeck 1:807034181e02 541 case 2:
Josh Hollenbeck 1:807034181e02 542 bits = *c++ << 16;
Josh Hollenbeck 1:807034181e02 543 bits |= *c++ << 8;
Josh Hollenbeck 1:807034181e02 544 buffer[0] = encode[(bits & 0x00FC0000) >> 18];
Josh Hollenbeck 1:807034181e02 545 buffer[1] = encode[(bits & 0x0003F000) >> 12];
Josh Hollenbeck 1:807034181e02 546 buffer[2] = encode[(bits & 0x00000FC0) >> 6];
Josh Hollenbeck 1:807034181e02 547 buffer[3] = '=';
Josh Hollenbeck 1:807034181e02 548 l = c;
Josh Hollenbeck 1:807034181e02 549 goto write;
Josh Hollenbeck 1:807034181e02 550 default:
Josh Hollenbeck 1:807034181e02 551 bits = *c++ << 16;
Josh Hollenbeck 1:807034181e02 552 bits |= *c++ << 8;
Josh Hollenbeck 1:807034181e02 553 bits |= *c++;
Josh Hollenbeck 1:807034181e02 554 buffer[0] = encode[(bits & 0x00FC0000) >> 18];
Josh Hollenbeck 1:807034181e02 555 buffer[1] = encode[(bits & 0x0003F000) >> 12];
Josh Hollenbeck 1:807034181e02 556 buffer[2] = encode[(bits & 0x00000FC0) >> 6];
Josh Hollenbeck 1:807034181e02 557 buffer[3] = encode[(bits & 0x0000003F)];
Josh Hollenbeck 1:807034181e02 558 goto write;
Josh Hollenbeck 1:807034181e02 559 }
Josh Hollenbeck 1:807034181e02 560 write:
Josh Hollenbeck 1:807034181e02 561 jsonlite_stream_write(builder->stream, buffer, 4);
Josh Hollenbeck 1:807034181e02 562 goto next;
Josh Hollenbeck 1:807034181e02 563 done:
Josh Hollenbeck 1:807034181e02 564 jsonlite_stream_write(builder->stream, "\"", 1);
Josh Hollenbeck 1:807034181e02 565 }
Josh Hollenbeck 1:807034181e02 566
Josh Hollenbeck 1:807034181e02 567 jsonlite_result jsonlite_builder_base64_value(jsonlite_builder builder, const void *data, size_t length) {
Josh Hollenbeck 1:807034181e02 568 if (builder == NULL || data == NULL || length == 0) {
Josh Hollenbeck 1:807034181e02 569 return jsonlite_result_invalid_argument;
Josh Hollenbeck 1:807034181e02 570 }
Josh Hollenbeck 1:807034181e02 571
Josh Hollenbeck 1:807034181e02 572 jsonlite_write_state *ws = builder->state;
Josh Hollenbeck 1:807034181e02 573 if (jsonlite_builder_accept(builder, jsonlite_accept_value)) {
Josh Hollenbeck 1:807034181e02 574 jsonlite_builder_prepare_value_writing(builder);
Josh Hollenbeck 1:807034181e02 575 jsonlite_builder_write_base64(builder, data, length);
Josh Hollenbeck 1:807034181e02 576 if (jsonlite_builder_accept(builder, jsonlite_accept_values_only)) {
Josh Hollenbeck 1:807034181e02 577 *ws = jsonlite_accept_continue_array;
Josh Hollenbeck 1:807034181e02 578 } else {
Josh Hollenbeck 1:807034181e02 579 *ws = jsonlite_accept_continue_object;
Josh Hollenbeck 1:807034181e02 580 }
Josh Hollenbeck 1:807034181e02 581 return jsonlite_result_ok;
Josh Hollenbeck 1:807034181e02 582 }
Josh Hollenbeck 1:807034181e02 583
Josh Hollenbeck 1:807034181e02 584 return jsonlite_result_not_allowed;
Josh Hollenbeck 1:807034181e02 585
Josh Hollenbeck 1:807034181e02 586 }
Josh Hollenbeck 1:807034181e02 587 //
Josh Hollenbeck 1:807034181e02 588 // Copyright 2012-2013, Andrii Mamchur
Josh Hollenbeck 1:807034181e02 589 //
Josh Hollenbeck 1:807034181e02 590 // Licensed under the Apache License, Version 2.0 (the "License");
Josh Hollenbeck 1:807034181e02 591 // you may not use this file except in compliance with the License.
Josh Hollenbeck 1:807034181e02 592 // You may obtain a copy of the License at
Josh Hollenbeck 1:807034181e02 593 //
Josh Hollenbeck 1:807034181e02 594 // http://www.apache.org/licenses/LICENSE-2.0
Josh Hollenbeck 1:807034181e02 595 //
Josh Hollenbeck 1:807034181e02 596 // Unless required by applicable law or agreed to in writing, software
Josh Hollenbeck 1:807034181e02 597 // distributed under the License is distributed on an "AS IS" BASIS,
Josh Hollenbeck 1:807034181e02 598 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Josh Hollenbeck 1:807034181e02 599 // See the License for the specific language governing permissions and
Josh Hollenbeck 1:807034181e02 600 // limitations under the License
Josh Hollenbeck 1:807034181e02 601
citrusbyte 0:01a2f8de46c8 602 #ifndef JSONLITE_AMALGAMATED
citrusbyte 0:01a2f8de46c8 603 #include "jsonlite_parser.h"
citrusbyte 0:01a2f8de46c8 604 #endif
citrusbyte 0:01a2f8de46c8 605
citrusbyte 0:01a2f8de46c8 606 #include <stdlib.h>
citrusbyte 0:01a2f8de46c8 607 #include <string.h>
citrusbyte 0:01a2f8de46c8 608
citrusbyte 0:01a2f8de46c8 609 #ifdef _MSC_VER
citrusbyte 0:01a2f8de46c8 610
citrusbyte 0:01a2f8de46c8 611 #include <intrin.h>
citrusbyte 0:01a2f8de46c8 612
citrusbyte 0:01a2f8de46c8 613 static uint32_t __inline jsonlite_clz(uint32_t x) {
citrusbyte 0:01a2f8de46c8 614 unsigned long r = 0;
citrusbyte 0:01a2f8de46c8 615 _BitScanForward(&r, x);
citrusbyte 0:01a2f8de46c8 616 return r;
citrusbyte 0:01a2f8de46c8 617 }
citrusbyte 0:01a2f8de46c8 618
citrusbyte 0:01a2f8de46c8 619 #else
citrusbyte 0:01a2f8de46c8 620
citrusbyte 0:01a2f8de46c8 621 #define jsonlite_clz(x) __builtin_clz((x))
citrusbyte 0:01a2f8de46c8 622
citrusbyte 0:01a2f8de46c8 623 #endif
citrusbyte 0:01a2f8de46c8 624
Josh Hollenbeck 1:807034181e02 625 #define MIN_DEPTH 2
citrusbyte 0:01a2f8de46c8 626 #define CALL_VALUE_CALLBACK(cbs, type, token) (cbs.type(&cbs.context, token))
citrusbyte 0:01a2f8de46c8 627 #define CALL_STATE_CALLBACK(cbs, type) (cbs.type(&cbs.context))
citrusbyte 0:01a2f8de46c8 628
Josh Hollenbeck 1:807034181e02 629 #define HEX_CHAR_TO_INT(c, step) \
Josh Hollenbeck 1:807034181e02 630 if (0x30 <= *c && *c <= 0x39) { \
Josh Hollenbeck 1:807034181e02 631 hex_value = *c - 0x30; \
Josh Hollenbeck 1:807034181e02 632 } else if (0x41 <= *c && *c <= 0x46) { \
Josh Hollenbeck 1:807034181e02 633 hex_value = *c - 0x37; \
Josh Hollenbeck 1:807034181e02 634 } else if (0x61 <= *c && *c <= 0x66) { \
Josh Hollenbeck 1:807034181e02 635 hex_value = *c - 0x57; \
Josh Hollenbeck 1:807034181e02 636 } else goto error_escape; \
Josh Hollenbeck 1:807034181e02 637 c += step
citrusbyte 0:01a2f8de46c8 638
Josh Hollenbeck 1:807034181e02 639 #define CASE_NUMBER_TOKEN_END \
Josh Hollenbeck 1:807034181e02 640 case 0x09: goto number_parsed; \
Josh Hollenbeck 1:807034181e02 641 case 0x0A: goto number_parsed; \
Josh Hollenbeck 1:807034181e02 642 case 0x0D: goto number_parsed; \
Josh Hollenbeck 1:807034181e02 643 case 0x20: goto number_parsed; \
Josh Hollenbeck 1:807034181e02 644 case 0x2C: goto number_parsed; \
Josh Hollenbeck 1:807034181e02 645 case 0x5D: goto number_parsed; \
Josh Hollenbeck 1:807034181e02 646 case 0x7D: goto number_parsed
citrusbyte 0:01a2f8de46c8 647
citrusbyte 0:01a2f8de46c8 648 enum {
citrusbyte 0:01a2f8de46c8 649 state_start,
citrusbyte 0:01a2f8de46c8 650 state_object_key,
citrusbyte 0:01a2f8de46c8 651 state_object_key_end,
citrusbyte 0:01a2f8de46c8 652 state_colon,
citrusbyte 0:01a2f8de46c8 653 state_object_comma_end,
citrusbyte 0:01a2f8de46c8 654 state_array_value_end,
citrusbyte 0:01a2f8de46c8 655 state_array_comma_end,
citrusbyte 0:01a2f8de46c8 656 state_key,
citrusbyte 0:01a2f8de46c8 657 state_value,
citrusbyte 0:01a2f8de46c8 658 state_end,
Josh Hollenbeck 1:807034181e02 659
Josh Hollenbeck 1:807034181e02 660 state_stop = 1 << 7
citrusbyte 0:01a2f8de46c8 661 };
citrusbyte 0:01a2f8de46c8 662
citrusbyte 0:01a2f8de46c8 663 typedef uint8_t parse_state;
citrusbyte 0:01a2f8de46c8 664 struct jsonlite_parser_struct {
citrusbyte 0:01a2f8de46c8 665 const uint8_t *cursor;
citrusbyte 0:01a2f8de46c8 666 const uint8_t *limit;
citrusbyte 0:01a2f8de46c8 667 const uint8_t *buffer;
citrusbyte 0:01a2f8de46c8 668 uint8_t *buffer_own;
Josh Hollenbeck 1:807034181e02 669
citrusbyte 0:01a2f8de46c8 670 parse_state *current;
Josh Hollenbeck 1:807034181e02 671 parse_state *last;
Josh Hollenbeck 1:807034181e02 672 parse_state **control;
Josh Hollenbeck 1:807034181e02 673
citrusbyte 0:01a2f8de46c8 674 jsonlite_result result;
citrusbyte 0:01a2f8de46c8 675 jsonlite_parser_callbacks callbacks;
citrusbyte 0:01a2f8de46c8 676 } jsonlite_parser_struct;
citrusbyte 0:01a2f8de46c8 677
citrusbyte 0:01a2f8de46c8 678 static void jsonlite_do_parse(jsonlite_parser parser);
citrusbyte 0:01a2f8de46c8 679 static void empty_value_callback(jsonlite_callback_context *ctx, jsonlite_token *t) {}
citrusbyte 0:01a2f8de46c8 680 static void empty_state_callback(jsonlite_callback_context *ctx) {}
citrusbyte 0:01a2f8de46c8 681
citrusbyte 0:01a2f8de46c8 682 const jsonlite_parser_callbacks jsonlite_default_callbacks = {
citrusbyte 0:01a2f8de46c8 683 &empty_state_callback,
citrusbyte 0:01a2f8de46c8 684 &empty_state_callback,
citrusbyte 0:01a2f8de46c8 685 &empty_state_callback,
citrusbyte 0:01a2f8de46c8 686 &empty_state_callback,
citrusbyte 0:01a2f8de46c8 687 &empty_state_callback,
citrusbyte 0:01a2f8de46c8 688 &empty_state_callback,
citrusbyte 0:01a2f8de46c8 689 &empty_state_callback,
citrusbyte 0:01a2f8de46c8 690 &empty_state_callback,
citrusbyte 0:01a2f8de46c8 691 &empty_value_callback,
citrusbyte 0:01a2f8de46c8 692 &empty_value_callback,
citrusbyte 0:01a2f8de46c8 693 &empty_value_callback,
citrusbyte 0:01a2f8de46c8 694 {NULL, NULL}
citrusbyte 0:01a2f8de46c8 695 };
citrusbyte 0:01a2f8de46c8 696
citrusbyte 0:01a2f8de46c8 697 size_t jsonlite_parser_estimate_size(size_t depth) {
Josh Hollenbeck 1:807034181e02 698 depth = depth < MIN_DEPTH ? 32 : depth;
citrusbyte 0:01a2f8de46c8 699 return sizeof(jsonlite_parser_struct) + depth * sizeof(parse_state);
citrusbyte 0:01a2f8de46c8 700 }
citrusbyte 0:01a2f8de46c8 701
Josh Hollenbeck 1:807034181e02 702 static jsonlite_parser jsonlite_parser_configure(void *memory, size_t size) {
Josh Hollenbeck 1:807034181e02 703 size_t depth = (size - sizeof(jsonlite_parser_struct)) / sizeof(parse_state);
Josh Hollenbeck 1:807034181e02 704 jsonlite_parser parser = (jsonlite_parser)memory;
citrusbyte 0:01a2f8de46c8 705 parser->result = jsonlite_result_unknown;
Josh Hollenbeck 1:807034181e02 706 parser->buffer_own = NULL;
citrusbyte 0:01a2f8de46c8 707 parser->callbacks = jsonlite_default_callbacks;
Josh Hollenbeck 1:807034181e02 708 parser->control = NULL;
Josh Hollenbeck 1:807034181e02 709 parser->current = ((uint8_t *)parser + sizeof(jsonlite_parser_struct));
citrusbyte 0:01a2f8de46c8 710 parser->current[0] = state_end;
citrusbyte 0:01a2f8de46c8 711 parser->current[1] = state_start;
citrusbyte 0:01a2f8de46c8 712 parser->last = parser->current + depth;
citrusbyte 0:01a2f8de46c8 713 parser->current++;
citrusbyte 0:01a2f8de46c8 714 return parser;
citrusbyte 0:01a2f8de46c8 715 }
citrusbyte 0:01a2f8de46c8 716
Josh Hollenbeck 1:807034181e02 717 jsonlite_parser jsonlite_parser_init(size_t depth) {
Josh Hollenbeck 1:807034181e02 718 size_t size = jsonlite_parser_estimate_size(depth);
Josh Hollenbeck 1:807034181e02 719 void *memory = malloc(size);
Josh Hollenbeck 1:807034181e02 720 return jsonlite_parser_configure(memory, size);
Josh Hollenbeck 1:807034181e02 721 }
Josh Hollenbeck 1:807034181e02 722
Josh Hollenbeck 1:807034181e02 723 jsonlite_parser jsonlite_parser_init_memory(void *memory, size_t size) {
Josh Hollenbeck 1:807034181e02 724 if (memory == NULL) {
Josh Hollenbeck 1:807034181e02 725 return NULL;
Josh Hollenbeck 1:807034181e02 726 }
Josh Hollenbeck 1:807034181e02 727
Josh Hollenbeck 1:807034181e02 728 if (size < jsonlite_parser_estimate_size(MIN_DEPTH)) {
Josh Hollenbeck 1:807034181e02 729 return NULL;
Josh Hollenbeck 1:807034181e02 730 }
Josh Hollenbeck 1:807034181e02 731
Josh Hollenbeck 1:807034181e02 732 return jsonlite_parser_configure(memory, size);
Josh Hollenbeck 1:807034181e02 733 }
Josh Hollenbeck 1:807034181e02 734
citrusbyte 0:01a2f8de46c8 735 jsonlite_result jsonlite_parser_set_callback(jsonlite_parser parser, const jsonlite_parser_callbacks *cbs) {
citrusbyte 0:01a2f8de46c8 736 if (parser == NULL || cbs == NULL) {
citrusbyte 0:01a2f8de46c8 737 return jsonlite_result_invalid_argument;
citrusbyte 0:01a2f8de46c8 738 }
citrusbyte 0:01a2f8de46c8 739
citrusbyte 0:01a2f8de46c8 740 parser->callbacks = *cbs;
citrusbyte 0:01a2f8de46c8 741 parser->callbacks.context.parser = parser;
citrusbyte 0:01a2f8de46c8 742 return jsonlite_result_ok;
citrusbyte 0:01a2f8de46c8 743 }
citrusbyte 0:01a2f8de46c8 744
citrusbyte 0:01a2f8de46c8 745 jsonlite_result jsonlite_parser_get_result(jsonlite_parser parser) {
citrusbyte 0:01a2f8de46c8 746 if (parser == NULL) {
citrusbyte 0:01a2f8de46c8 747 return jsonlite_result_invalid_argument;
citrusbyte 0:01a2f8de46c8 748 }
Josh Hollenbeck 1:807034181e02 749
citrusbyte 0:01a2f8de46c8 750 return parser->result;
citrusbyte 0:01a2f8de46c8 751 }
citrusbyte 0:01a2f8de46c8 752
citrusbyte 0:01a2f8de46c8 753 jsonlite_result jsonlite_parser_tokenize(jsonlite_parser parser, const void *buffer, size_t size) {
citrusbyte 0:01a2f8de46c8 754 if (parser == NULL || buffer == NULL || size == 0) {
citrusbyte 0:01a2f8de46c8 755 return jsonlite_result_invalid_argument;
citrusbyte 0:01a2f8de46c8 756 }
Josh Hollenbeck 1:807034181e02 757
Josh Hollenbeck 1:807034181e02 758 if (parser->buffer_own != NULL) {
Josh Hollenbeck 1:807034181e02 759 size_t total_size = size + parser->limit - parser->buffer_own;
citrusbyte 0:01a2f8de46c8 760 uint8_t *b = (uint8_t *)malloc(total_size);
Josh Hollenbeck 1:807034181e02 761 memcpy(b, parser->buffer_own, parser->limit - parser->buffer_own); // LCOV_EXCL_LINE
Josh Hollenbeck 1:807034181e02 762 memcpy(b + (parser->limit - parser->buffer_own), buffer, size); // LCOV_EXCL_LINE
Josh Hollenbeck 1:807034181e02 763
citrusbyte 0:01a2f8de46c8 764 free(parser->buffer_own);
Josh Hollenbeck 1:807034181e02 765
citrusbyte 0:01a2f8de46c8 766 parser->buffer = b;
citrusbyte 0:01a2f8de46c8 767 parser->buffer_own = b;
Josh Hollenbeck 1:807034181e02 768 parser->cursor = b;
Josh Hollenbeck 1:807034181e02 769 parser->limit = b + total_size;
citrusbyte 0:01a2f8de46c8 770 } else {
citrusbyte 0:01a2f8de46c8 771 parser->buffer = buffer;
citrusbyte 0:01a2f8de46c8 772 parser->cursor = parser->buffer;
citrusbyte 0:01a2f8de46c8 773 parser->limit = parser->buffer + size;
citrusbyte 0:01a2f8de46c8 774 }
Josh Hollenbeck 1:807034181e02 775
citrusbyte 0:01a2f8de46c8 776 jsonlite_do_parse(parser);
citrusbyte 0:01a2f8de46c8 777 return parser->result;
citrusbyte 0:01a2f8de46c8 778 }
citrusbyte 0:01a2f8de46c8 779
citrusbyte 0:01a2f8de46c8 780 jsonlite_result jsonlite_parser_resume(jsonlite_parser parser) {
citrusbyte 0:01a2f8de46c8 781 if (parser == NULL) {
citrusbyte 0:01a2f8de46c8 782 return jsonlite_result_invalid_argument;
citrusbyte 0:01a2f8de46c8 783 }
Josh Hollenbeck 1:807034181e02 784
citrusbyte 0:01a2f8de46c8 785 if (parser->result != jsonlite_result_suspended) {
citrusbyte 0:01a2f8de46c8 786 return jsonlite_result_not_allowed;
citrusbyte 0:01a2f8de46c8 787 }
Josh Hollenbeck 1:807034181e02 788
citrusbyte 0:01a2f8de46c8 789 jsonlite_do_parse(parser);
citrusbyte 0:01a2f8de46c8 790 return parser->result;
citrusbyte 0:01a2f8de46c8 791 }
citrusbyte 0:01a2f8de46c8 792
citrusbyte 0:01a2f8de46c8 793 jsonlite_result jsonlite_parser_suspend(jsonlite_parser parser) {
Josh Hollenbeck 1:807034181e02 794 return jsonlite_parser_terminate(parser, jsonlite_result_suspended);
Josh Hollenbeck 1:807034181e02 795 }
Josh Hollenbeck 1:807034181e02 796
Josh Hollenbeck 1:807034181e02 797 jsonlite_result jsonlite_parser_terminate(jsonlite_parser parser, jsonlite_result result) {
citrusbyte 0:01a2f8de46c8 798 if (parser == NULL) {
citrusbyte 0:01a2f8de46c8 799 return jsonlite_result_invalid_argument;
citrusbyte 0:01a2f8de46c8 800 }
Josh Hollenbeck 1:807034181e02 801
Josh Hollenbeck 1:807034181e02 802 if (parser->control == NULL) {
citrusbyte 0:01a2f8de46c8 803 return jsonlite_result_not_allowed;
citrusbyte 0:01a2f8de46c8 804 }
Josh Hollenbeck 1:807034181e02 805
Josh Hollenbeck 1:807034181e02 806 parser->result = result;
Josh Hollenbeck 1:807034181e02 807 **parser->control |= state_stop;
citrusbyte 0:01a2f8de46c8 808 return jsonlite_result_ok;
citrusbyte 0:01a2f8de46c8 809 }
citrusbyte 0:01a2f8de46c8 810
citrusbyte 0:01a2f8de46c8 811 void jsonlite_parser_release(jsonlite_parser parser) {
Josh Hollenbeck 1:807034181e02 812 jsonlite_parser_cleanup(parser);
Josh Hollenbeck 1:807034181e02 813 free(parser);
Josh Hollenbeck 1:807034181e02 814 }
Josh Hollenbeck 1:807034181e02 815
Josh Hollenbeck 1:807034181e02 816 void jsonlite_parser_cleanup(jsonlite_parser parser) {
citrusbyte 0:01a2f8de46c8 817 if (parser == NULL) {
citrusbyte 0:01a2f8de46c8 818 return;
citrusbyte 0:01a2f8de46c8 819 }
Josh Hollenbeck 1:807034181e02 820
citrusbyte 0:01a2f8de46c8 821 free(parser->buffer_own);
citrusbyte 0:01a2f8de46c8 822 }
citrusbyte 0:01a2f8de46c8 823
citrusbyte 0:01a2f8de46c8 824 static void jsonlite_do_parse(jsonlite_parser parser) {
citrusbyte 0:01a2f8de46c8 825 const uint8_t *c = parser->cursor;
citrusbyte 0:01a2f8de46c8 826 const uint8_t *l = parser->limit;
citrusbyte 0:01a2f8de46c8 827 const uint8_t *token_start = NULL;
citrusbyte 0:01a2f8de46c8 828 const parse_state *last = parser->last;
citrusbyte 0:01a2f8de46c8 829 parse_state *state = parser->current;
Josh Hollenbeck 1:807034181e02 830 jsonlite_token token = {NULL, NULL, NULL, 0};
Josh Hollenbeck 1:807034181e02 831 jsonlite_result result = jsonlite_result_ok;
Josh Hollenbeck 1:807034181e02 832 uint32_t value, utf32;
Josh Hollenbeck 1:807034181e02 833 uint8_t hex_value;
Josh Hollenbeck 1:807034181e02 834
Josh Hollenbeck 1:807034181e02 835 *state &= ~state_stop;
Josh Hollenbeck 1:807034181e02 836 parser->control = &state;
Josh Hollenbeck 1:807034181e02 837 goto select_state;
Josh Hollenbeck 1:807034181e02 838
citrusbyte 0:01a2f8de46c8 839 structure_finished:
Josh Hollenbeck 1:807034181e02 840 if (*state == state_end) goto end;
Josh Hollenbeck 1:807034181e02 841 skip_char_and_whitespaces:
citrusbyte 0:01a2f8de46c8 842 c++;
Josh Hollenbeck 1:807034181e02 843 select_state:
Josh Hollenbeck 1:807034181e02 844 if (c == l) goto end_of_stream_whitespaces;
Josh Hollenbeck 1:807034181e02 845 if (*c == 0x20) goto skip_char_and_whitespaces;
Josh Hollenbeck 1:807034181e02 846 if (*c == 0x0A) goto skip_char_and_whitespaces;
Josh Hollenbeck 1:807034181e02 847 if (*c == 0x0D) goto skip_char_and_whitespaces;
Josh Hollenbeck 1:807034181e02 848 if (*c == 0x09) goto skip_char_and_whitespaces;
citrusbyte 0:01a2f8de46c8 849 token_start = c;
Josh Hollenbeck 1:807034181e02 850
citrusbyte 0:01a2f8de46c8 851 switch (*state) {
Josh Hollenbeck 1:807034181e02 852 case state_value: goto parse_value;
Josh Hollenbeck 1:807034181e02 853 case state_colon: goto parse_colon;
Josh Hollenbeck 1:807034181e02 854 case state_object_comma_end: goto parse_object_comma_end;
Josh Hollenbeck 1:807034181e02 855 case state_object_key: goto parse_key;
Josh Hollenbeck 1:807034181e02 856 case state_object_key_end: goto parse_key_end;
Josh Hollenbeck 1:807034181e02 857 case state_array_comma_end: goto parse_array_comma_end;
Josh Hollenbeck 1:807034181e02 858 case state_array_value_end: goto parse_array_value_end;
Josh Hollenbeck 1:807034181e02 859 case state_key: goto parse_string_token;
citrusbyte 0:01a2f8de46c8 860 case state_start:
Josh Hollenbeck 1:807034181e02 861 if (*c == 0x7B) goto parse_object;
Josh Hollenbeck 1:807034181e02 862 if (*c == 0x5B) goto parse_array_state;
citrusbyte 0:01a2f8de46c8 863 goto error_exp_ooa;
Josh Hollenbeck 1:807034181e02 864 case state_end: goto end;
citrusbyte 0:01a2f8de46c8 865 default:
Josh Hollenbeck 1:807034181e02 866 result = parser->result;
Josh Hollenbeck 1:807034181e02 867 goto end;
citrusbyte 0:01a2f8de46c8 868 }
Josh Hollenbeck 1:807034181e02 869 parse_object:
citrusbyte 0:01a2f8de46c8 870 *state = state_object_key_end;
citrusbyte 0:01a2f8de46c8 871 CALL_STATE_CALLBACK(parser->callbacks, object_start);
Josh Hollenbeck 1:807034181e02 872 goto skip_char_and_whitespaces;
Josh Hollenbeck 1:807034181e02 873 parse_array_state:
citrusbyte 0:01a2f8de46c8 874 *state = state_array_value_end;
citrusbyte 0:01a2f8de46c8 875 CALL_STATE_CALLBACK(parser->callbacks, array_start);
Josh Hollenbeck 1:807034181e02 876 goto skip_char_and_whitespaces;
Josh Hollenbeck 1:807034181e02 877 parse_key:
Josh Hollenbeck 1:807034181e02 878 if (*c != 0x22) goto error_exp_key;
citrusbyte 0:01a2f8de46c8 879 *state = state_colon;
citrusbyte 0:01a2f8de46c8 880 *++state = state_key;
Josh Hollenbeck 1:807034181e02 881 goto parse_string_token;
Josh Hollenbeck 1:807034181e02 882 parse_colon:
Josh Hollenbeck 1:807034181e02 883 if (*c != 0x3A) goto error_exp_colon;
citrusbyte 0:01a2f8de46c8 884 *state = state_object_comma_end;
citrusbyte 0:01a2f8de46c8 885 *++state = state_value;
Josh Hollenbeck 1:807034181e02 886 goto skip_char_and_whitespaces;
Josh Hollenbeck 1:807034181e02 887 parse_key_end:
citrusbyte 0:01a2f8de46c8 888 switch (*c) {
Josh Hollenbeck 1:807034181e02 889 case 0x22:
citrusbyte 0:01a2f8de46c8 890 *state = state_colon;
citrusbyte 0:01a2f8de46c8 891 if (++state == last) goto error_depth;
citrusbyte 0:01a2f8de46c8 892 *state = state_key;
Josh Hollenbeck 1:807034181e02 893 goto parse_string_token;
Josh Hollenbeck 1:807034181e02 894 case 0x7D:
Josh Hollenbeck 1:807034181e02 895 state--;
citrusbyte 0:01a2f8de46c8 896 CALL_STATE_CALLBACK(parser->callbacks, object_end);
citrusbyte 0:01a2f8de46c8 897 goto structure_finished;
Josh Hollenbeck 1:807034181e02 898 default: goto error_exp_koe;
citrusbyte 0:01a2f8de46c8 899 }
Josh Hollenbeck 1:807034181e02 900 parse_object_comma_end:
citrusbyte 0:01a2f8de46c8 901 switch (*c) {
Josh Hollenbeck 1:807034181e02 902 case 0x2C:
citrusbyte 0:01a2f8de46c8 903 *state = state_object_key;
Josh Hollenbeck 1:807034181e02 904 goto skip_char_and_whitespaces;
Josh Hollenbeck 1:807034181e02 905 case 0x7D:
Josh Hollenbeck 1:807034181e02 906 state--;
citrusbyte 0:01a2f8de46c8 907 CALL_STATE_CALLBACK(parser->callbacks, object_end);
citrusbyte 0:01a2f8de46c8 908 goto structure_finished;
Josh Hollenbeck 1:807034181e02 909 default: goto error_exp_coe;
citrusbyte 0:01a2f8de46c8 910 }
Josh Hollenbeck 1:807034181e02 911 parse_array_value_end:
citrusbyte 0:01a2f8de46c8 912 switch (*c) {
Josh Hollenbeck 1:807034181e02 913 case 0x5D:
Josh Hollenbeck 1:807034181e02 914 state--;
citrusbyte 0:01a2f8de46c8 915 CALL_STATE_CALLBACK(parser->callbacks, array_end);
citrusbyte 0:01a2f8de46c8 916 goto structure_finished;
citrusbyte 0:01a2f8de46c8 917 default:
citrusbyte 0:01a2f8de46c8 918 *state = state_array_comma_end;
citrusbyte 0:01a2f8de46c8 919 if (++state == last) goto error_depth;
citrusbyte 0:01a2f8de46c8 920 *state = state_value;
Josh Hollenbeck 1:807034181e02 921 goto parse_value;
citrusbyte 0:01a2f8de46c8 922 }
Josh Hollenbeck 1:807034181e02 923 parse_array_comma_end:
citrusbyte 0:01a2f8de46c8 924 switch (*c) {
Josh Hollenbeck 1:807034181e02 925 case 0x2C:
citrusbyte 0:01a2f8de46c8 926 *++state = state_value;
Josh Hollenbeck 1:807034181e02 927 goto skip_char_and_whitespaces;
Josh Hollenbeck 1:807034181e02 928 case 0x5D:
Josh Hollenbeck 1:807034181e02 929 state--;
citrusbyte 0:01a2f8de46c8 930 CALL_STATE_CALLBACK(parser->callbacks, array_end);
citrusbyte 0:01a2f8de46c8 931 goto structure_finished;
Josh Hollenbeck 1:807034181e02 932 default: goto error_exp_coe;
citrusbyte 0:01a2f8de46c8 933 }
Josh Hollenbeck 1:807034181e02 934 parse_value:
Josh Hollenbeck 1:807034181e02 935 if (0x31 <= *c && *c <= 0x39) goto parse_digit_leading_number;
Josh Hollenbeck 1:807034181e02 936 if (*c == 0x30) goto parse_zero_leading_number;
Josh Hollenbeck 1:807034181e02 937 if (*c == 0x2D) goto parse_negative_number;
Josh Hollenbeck 1:807034181e02 938 if (*c == 0x22) goto parse_string_token;
Josh Hollenbeck 1:807034181e02 939 if (*c == 0x74) goto parse_true_token;
Josh Hollenbeck 1:807034181e02 940 if (*c == 0x66) goto parse_false_token;
Josh Hollenbeck 1:807034181e02 941 if (*c == 0x6E) goto parse_null_token;
Josh Hollenbeck 1:807034181e02 942 if (*c == 0x7B) goto parse_object;
Josh Hollenbeck 1:807034181e02 943 if (*c == 0x5B) goto parse_array_state;
citrusbyte 0:01a2f8de46c8 944 goto error_exp_value;
Josh Hollenbeck 1:807034181e02 945
Josh Hollenbeck 1:807034181e02 946 // Number parsing
Josh Hollenbeck 1:807034181e02 947 parse_negative_number:
Josh Hollenbeck 1:807034181e02 948 token.start = c;
Josh Hollenbeck 1:807034181e02 949 token.type.number = jsonlite_number_int | jsonlite_number_negative;
Josh Hollenbeck 1:807034181e02 950 if (++c == l) goto end_of_stream;
Josh Hollenbeck 1:807034181e02 951 if (0x31 <= *c && *c <= 0x39) goto parse_digits;
Josh Hollenbeck 1:807034181e02 952 if (*c == 0x30) goto parse_exponent_fraction;
Josh Hollenbeck 1:807034181e02 953 goto error_number;
Josh Hollenbeck 1:807034181e02 954 parse_zero_leading_number:
Josh Hollenbeck 1:807034181e02 955 token.start = c;
Josh Hollenbeck 1:807034181e02 956 token.type.number = jsonlite_number_int | jsonlite_number_zero_leading;
Josh Hollenbeck 1:807034181e02 957 parse_exponent_fraction:
Josh Hollenbeck 1:807034181e02 958 if (++c == l) goto end_of_stream;
Josh Hollenbeck 1:807034181e02 959 switch (*c) {
Josh Hollenbeck 1:807034181e02 960 CASE_NUMBER_TOKEN_END;
Josh Hollenbeck 1:807034181e02 961 case 0x2E: goto parse_fraction;
Josh Hollenbeck 1:807034181e02 962 case 0x45: goto parse_exponent;
Josh Hollenbeck 1:807034181e02 963 case 0x65: goto parse_exponent;
Josh Hollenbeck 1:807034181e02 964 default: goto error_number;
Josh Hollenbeck 1:807034181e02 965 }
Josh Hollenbeck 1:807034181e02 966 parse_fraction:
Josh Hollenbeck 1:807034181e02 967 token.type.number |= jsonlite_number_frac;
Josh Hollenbeck 1:807034181e02 968 if (++c == l) goto end_of_stream;
Josh Hollenbeck 1:807034181e02 969 if (0x30 <= *c && *c <= 0x39) goto parse_frac_number;
Josh Hollenbeck 1:807034181e02 970 goto error_number;
Josh Hollenbeck 1:807034181e02 971 parse_frac_number:
Josh Hollenbeck 1:807034181e02 972 if (++c == l) goto end_of_stream;
Josh Hollenbeck 1:807034181e02 973 if (0x30 <= *c && *c <= 0x39) goto parse_frac_number;
Josh Hollenbeck 1:807034181e02 974 switch (*c) {
Josh Hollenbeck 1:807034181e02 975 CASE_NUMBER_TOKEN_END;
Josh Hollenbeck 1:807034181e02 976 case 0x45: goto parse_exponent;
Josh Hollenbeck 1:807034181e02 977 case 0x65: goto parse_exponent;
Josh Hollenbeck 1:807034181e02 978 default: goto error_number;
Josh Hollenbeck 1:807034181e02 979 }
Josh Hollenbeck 1:807034181e02 980 parse_exponent:
Josh Hollenbeck 1:807034181e02 981 token.type.number |= jsonlite_number_exp;
Josh Hollenbeck 1:807034181e02 982 if (++c == l) goto end_of_stream;
Josh Hollenbeck 1:807034181e02 983 if (0x30 <= *c && *c <= 0x39) goto parse_exponent_number;
Josh Hollenbeck 1:807034181e02 984 switch(*c) {
Josh Hollenbeck 1:807034181e02 985 case 0x2B: goto parse_exponent_sign;
Josh Hollenbeck 1:807034181e02 986 case 0x2D: goto parse_exponent_sign;
Josh Hollenbeck 1:807034181e02 987 default: goto error_number;
Josh Hollenbeck 1:807034181e02 988 }
Josh Hollenbeck 1:807034181e02 989 parse_exponent_sign:
Josh Hollenbeck 1:807034181e02 990 if (++c == l) goto end_of_stream;
Josh Hollenbeck 1:807034181e02 991 if (0x30 <= *c && *c <= 0x39) goto parse_exponent_number;
Josh Hollenbeck 1:807034181e02 992 goto error_number;
Josh Hollenbeck 1:807034181e02 993 parse_exponent_number:
Josh Hollenbeck 1:807034181e02 994 if (++c == l) goto end_of_stream;
Josh Hollenbeck 1:807034181e02 995 if (0x30 <= *c && *c <= 0x39) goto parse_exponent_number;
Josh Hollenbeck 1:807034181e02 996 switch(*c) {
Josh Hollenbeck 1:807034181e02 997 CASE_NUMBER_TOKEN_END;
Josh Hollenbeck 1:807034181e02 998 default: goto error_number;
Josh Hollenbeck 1:807034181e02 999 }
Josh Hollenbeck 1:807034181e02 1000 parse_digit_leading_number:
Josh Hollenbeck 1:807034181e02 1001 token.start = c;
Josh Hollenbeck 1:807034181e02 1002 token.type.number = jsonlite_number_int | jsonlite_number_digit_leading;
Josh Hollenbeck 1:807034181e02 1003 parse_digits:
Josh Hollenbeck 1:807034181e02 1004 if (++c == l) goto end_of_stream;
Josh Hollenbeck 1:807034181e02 1005 if (0x30 <= *c && *c <= 0x39) goto parse_digits;
Josh Hollenbeck 1:807034181e02 1006 switch(*c) {
Josh Hollenbeck 1:807034181e02 1007 CASE_NUMBER_TOKEN_END;
Josh Hollenbeck 1:807034181e02 1008 case 0x2E: goto parse_fraction;
Josh Hollenbeck 1:807034181e02 1009 case 0x45: goto parse_exponent;
Josh Hollenbeck 1:807034181e02 1010 case 0x65: goto parse_exponent;
Josh Hollenbeck 1:807034181e02 1011 default: goto error_number;
citrusbyte 0:01a2f8de46c8 1012 }
Josh Hollenbeck 1:807034181e02 1013 number_parsed:
Josh Hollenbeck 1:807034181e02 1014 token.end = c;
Josh Hollenbeck 1:807034181e02 1015 state--;
Josh Hollenbeck 1:807034181e02 1016 CALL_VALUE_CALLBACK(parser->callbacks, number_found, &token);
Josh Hollenbeck 1:807034181e02 1017 goto select_state;
Josh Hollenbeck 1:807034181e02 1018
Josh Hollenbeck 1:807034181e02 1019 // String parsing
Josh Hollenbeck 1:807034181e02 1020 parse_string_token:
Josh Hollenbeck 1:807034181e02 1021 token.type.string = jsonlite_string_ascii;
Josh Hollenbeck 1:807034181e02 1022 token.start = c + 1;
Josh Hollenbeck 1:807034181e02 1023 next_char:
Josh Hollenbeck 1:807034181e02 1024 if (++c == l) goto end_of_stream;
Josh Hollenbeck 1:807034181e02 1025 if (*c == 0x22) goto string_parsed;
Josh Hollenbeck 1:807034181e02 1026 if (*c == 0x5C) goto escaped;
Josh Hollenbeck 1:807034181e02 1027 if (*c > 0x7F) goto utf8;
Josh Hollenbeck 1:807034181e02 1028 if (*c < 0x20) goto error_token;
Josh Hollenbeck 1:807034181e02 1029 goto next_char;
Josh Hollenbeck 1:807034181e02 1030 escaped:
Josh Hollenbeck 1:807034181e02 1031 token.type.string |= jsonlite_string_escape;
Josh Hollenbeck 1:807034181e02 1032 if (++c == l) goto end_of_stream;
Josh Hollenbeck 1:807034181e02 1033 switch (*c) {
Josh Hollenbeck 1:807034181e02 1034 case 0x22: goto next_char; // " quotation mark U+0022
Josh Hollenbeck 1:807034181e02 1035 case 0x2F: goto next_char; // / solidus U+002F
Josh Hollenbeck 1:807034181e02 1036 case 0x5C: goto next_char; // \ reverse solidus U+005C
Josh Hollenbeck 1:807034181e02 1037 case 0x62: goto next_char; // b backspace U+0008
Josh Hollenbeck 1:807034181e02 1038 case 0x66: goto next_char; // f form feed U+000C
Josh Hollenbeck 1:807034181e02 1039 case 0x6E: goto next_char; // n line feed U+000A
Josh Hollenbeck 1:807034181e02 1040 case 0x72: goto next_char; // r carriage return U+000D
Josh Hollenbeck 1:807034181e02 1041 case 0x74: goto next_char; // t tab U+0009
Josh Hollenbeck 1:807034181e02 1042 case 0x75: goto hex; // uXXXX U+XXXX
Josh Hollenbeck 1:807034181e02 1043 default: goto error_escape;
Josh Hollenbeck 1:807034181e02 1044 }
Josh Hollenbeck 1:807034181e02 1045 hex:
Josh Hollenbeck 1:807034181e02 1046 token.type.string |= jsonlite_string_unicode_escape;
Josh Hollenbeck 1:807034181e02 1047 if (c++ + 4 >= l) goto end_of_stream;
Josh Hollenbeck 1:807034181e02 1048 HEX_CHAR_TO_INT(c, 1); value = hex_value;
Josh Hollenbeck 1:807034181e02 1049 HEX_CHAR_TO_INT(c, 1); value = (uint32_t)(value << 4) | hex_value;
Josh Hollenbeck 1:807034181e02 1050 HEX_CHAR_TO_INT(c, 1); value = (uint32_t)(value << 4) | hex_value;
Josh Hollenbeck 1:807034181e02 1051 HEX_CHAR_TO_INT(c, 0); value = (uint32_t)(value << 4) | hex_value;
Josh Hollenbeck 1:807034181e02 1052
Josh Hollenbeck 1:807034181e02 1053 if ((value & 0xFFFFu) >= 0xFFFEu) token.type.string |= jsonlite_string_unicode_noncharacter;
Josh Hollenbeck 1:807034181e02 1054 if (value >= 0xFDD0u && value <= 0xFDEFu) token.type.string |= jsonlite_string_unicode_noncharacter;
Josh Hollenbeck 1:807034181e02 1055 if (0xD800 > value || value > 0xDBFF) goto next_char;
Josh Hollenbeck 1:807034181e02 1056
Josh Hollenbeck 1:807034181e02 1057 // UTF-16 Surrogate
Josh Hollenbeck 1:807034181e02 1058 utf32 = (value - 0xD800) << 10;
Josh Hollenbeck 1:807034181e02 1059 if (c++ + 6 >= l) goto end_of_stream;
Josh Hollenbeck 1:807034181e02 1060 if (*c++ != 0x5C) goto error_escape;
Josh Hollenbeck 1:807034181e02 1061 if (*c++ != 0x75) goto error_escape;
Josh Hollenbeck 1:807034181e02 1062 HEX_CHAR_TO_INT(c, 1); value = hex_value;
Josh Hollenbeck 1:807034181e02 1063 HEX_CHAR_TO_INT(c, 1); value = (uint32_t)(value << 4) | hex_value;
Josh Hollenbeck 1:807034181e02 1064 HEX_CHAR_TO_INT(c, 1); value = (uint32_t)(value << 4) | hex_value;
Josh Hollenbeck 1:807034181e02 1065 HEX_CHAR_TO_INT(c, 0); value = (uint32_t)(value << 4) | hex_value;
citrusbyte 0:01a2f8de46c8 1066
Josh Hollenbeck 1:807034181e02 1067 if (value < 0xDC00 || value > 0xDFFF) goto error_escape;
Josh Hollenbeck 1:807034181e02 1068 utf32 += value - 0xDC00 + 0x10000;
Josh Hollenbeck 1:807034181e02 1069 if ((utf32 & 0x0FFFFu) >= 0x0FFFEu) token.type.string |= jsonlite_string_unicode_noncharacter;
Josh Hollenbeck 1:807034181e02 1070 goto next_char;
Josh Hollenbeck 1:807034181e02 1071 utf8:
Josh Hollenbeck 1:807034181e02 1072 token.type.string |= jsonlite_string_utf8;
Josh Hollenbeck 1:807034181e02 1073 int res = jsonlite_clz((unsigned int)((*c) ^ 0xFF) << 0x19);
Josh Hollenbeck 1:807034181e02 1074 utf32 = (*c & (0xFF >> (res + 1)));
Josh Hollenbeck 1:807034181e02 1075 value = 0xAAAAAAAA; // == 1010...
Josh Hollenbeck 1:807034181e02 1076 if (c + res >= l) goto end_of_stream;
Josh Hollenbeck 1:807034181e02 1077 switch (res) {
Josh Hollenbeck 1:807034181e02 1078 case 3: value = (value << 2) | (*++c >> 6); utf32 = (utf32 << 6) | (*c & 0x3F);
Josh Hollenbeck 1:807034181e02 1079 case 2: value = (value << 2) | (*++c >> 6); utf32 = (utf32 << 6) | (*c & 0x3F);
Josh Hollenbeck 1:807034181e02 1080 case 1: value = (value << 2) | (*++c >> 6); utf32 = (utf32 << 6) | (*c & 0x3F);
Josh Hollenbeck 1:807034181e02 1081 if (value != 0xAAAAAAAA) goto error_utf8;
Josh Hollenbeck 1:807034181e02 1082 if ((utf32 & 0xFFFFu) >= 0xFFFEu) token.type.string |= jsonlite_string_unicode_noncharacter;
Josh Hollenbeck 1:807034181e02 1083 if (utf32 >= 0xFDD0u && utf32 <= 0xFDEFu) token.type.string |= jsonlite_string_unicode_noncharacter;
citrusbyte 0:01a2f8de46c8 1084 }
Josh Hollenbeck 1:807034181e02 1085 goto next_char;
Josh Hollenbeck 1:807034181e02 1086 string_parsed:
Josh Hollenbeck 1:807034181e02 1087 token.end = c;
Josh Hollenbeck 1:807034181e02 1088 parser->cursor = c + 1;
Josh Hollenbeck 1:807034181e02 1089 if (*state-- == state_value) {
Josh Hollenbeck 1:807034181e02 1090 CALL_VALUE_CALLBACK(parser->callbacks, string_found, &token);
Josh Hollenbeck 1:807034181e02 1091 } else {
Josh Hollenbeck 1:807034181e02 1092 CALL_VALUE_CALLBACK(parser->callbacks, key_found, &token);
Josh Hollenbeck 1:807034181e02 1093 }
Josh Hollenbeck 1:807034181e02 1094 goto skip_char_and_whitespaces;
Josh Hollenbeck 1:807034181e02 1095
Josh Hollenbeck 1:807034181e02 1096 // Primitive tokens
Josh Hollenbeck 1:807034181e02 1097 parse_true_token:
citrusbyte 0:01a2f8de46c8 1098 if (c++ + 3 >= l) goto end_of_stream;
Josh Hollenbeck 1:807034181e02 1099 if (*c++ != 0x72) goto error_token;
Josh Hollenbeck 1:807034181e02 1100 if (*c++ != 0x75) goto error_token;
Josh Hollenbeck 1:807034181e02 1101 if (*c++ != 0x65) goto error_token;
Josh Hollenbeck 1:807034181e02 1102 state--;
citrusbyte 0:01a2f8de46c8 1103 CALL_STATE_CALLBACK(parser->callbacks, true_found);
Josh Hollenbeck 1:807034181e02 1104 goto select_state;
Josh Hollenbeck 1:807034181e02 1105 parse_false_token:
citrusbyte 0:01a2f8de46c8 1106 if (c++ + 4 >= l) goto end_of_stream;
Josh Hollenbeck 1:807034181e02 1107 if (*c++ != 0x61) goto error_token;
Josh Hollenbeck 1:807034181e02 1108 if (*c++ != 0x6C) goto error_token;
Josh Hollenbeck 1:807034181e02 1109 if (*c++ != 0x73) goto error_token;
Josh Hollenbeck 1:807034181e02 1110 if (*c++ != 0x65) goto error_token;
Josh Hollenbeck 1:807034181e02 1111 state--;
citrusbyte 0:01a2f8de46c8 1112 CALL_STATE_CALLBACK(parser->callbacks, false_found);
Josh Hollenbeck 1:807034181e02 1113 goto select_state;
Josh Hollenbeck 1:807034181e02 1114 parse_null_token:
citrusbyte 0:01a2f8de46c8 1115 if (c++ + 3 >= l) goto end_of_stream;
Josh Hollenbeck 1:807034181e02 1116 if (*c++ != 0x75) goto error_token;
Josh Hollenbeck 1:807034181e02 1117 if (*c++ != 0x6C) goto error_token;
Josh Hollenbeck 1:807034181e02 1118 if (*c++ != 0x6C) goto error_token;
Josh Hollenbeck 1:807034181e02 1119 state--;
citrusbyte 0:01a2f8de46c8 1120 CALL_STATE_CALLBACK(parser->callbacks, null_found);
Josh Hollenbeck 1:807034181e02 1121 goto select_state;
citrusbyte 0:01a2f8de46c8 1122
Josh Hollenbeck 1:807034181e02 1123 // Error states.
Josh Hollenbeck 1:807034181e02 1124 error_depth: result = jsonlite_result_depth_limit; goto end;
Josh Hollenbeck 1:807034181e02 1125 error_exp_ooa: result = jsonlite_result_expected_object_or_array; goto end;
Josh Hollenbeck 1:807034181e02 1126 error_exp_value: result = jsonlite_result_expected_value; goto end;
Josh Hollenbeck 1:807034181e02 1127 error_exp_koe: result = jsonlite_result_expected_key_or_end; goto end;
Josh Hollenbeck 1:807034181e02 1128 error_exp_key: result = jsonlite_result_expected_key; goto end;
Josh Hollenbeck 1:807034181e02 1129 error_exp_colon: result = jsonlite_result_expected_colon; goto end;
Josh Hollenbeck 1:807034181e02 1130 error_exp_coe: result = jsonlite_result_expected_comma_or_end; goto end;
Josh Hollenbeck 1:807034181e02 1131 error_escape: result = jsonlite_result_invalid_escape; goto end;
Josh Hollenbeck 1:807034181e02 1132 error_number: result = jsonlite_result_invalid_number; goto end;
Josh Hollenbeck 1:807034181e02 1133 error_token: result = jsonlite_result_invalid_token; goto end;
Josh Hollenbeck 1:807034181e02 1134 error_utf8: result = jsonlite_result_invalid_utf8; goto end;
Josh Hollenbeck 1:807034181e02 1135
citrusbyte 0:01a2f8de46c8 1136 // End of stream states.
Josh Hollenbeck 1:807034181e02 1137 end_of_stream_whitespaces:
citrusbyte 0:01a2f8de46c8 1138 token_start = l;
citrusbyte 0:01a2f8de46c8 1139 end_of_stream:
Josh Hollenbeck 1:807034181e02 1140 result = jsonlite_result_end_of_stream;
citrusbyte 0:01a2f8de46c8 1141 end:
Josh Hollenbeck 1:807034181e02 1142 parser->result = result;
citrusbyte 0:01a2f8de46c8 1143 parser->current = state;
Josh Hollenbeck 1:807034181e02 1144 parser->control = NULL;
citrusbyte 0:01a2f8de46c8 1145 parser->cursor = c;
citrusbyte 0:01a2f8de46c8 1146 parser->callbacks.parse_finished(&parser->callbacks.context);
Josh Hollenbeck 1:807034181e02 1147 if (result != jsonlite_result_end_of_stream) {
citrusbyte 0:01a2f8de46c8 1148 return;
citrusbyte 0:01a2f8de46c8 1149 }
Josh Hollenbeck 1:807034181e02 1150
Josh Hollenbeck 1:807034181e02 1151 res = parser->buffer_own != NULL;
Josh Hollenbeck 1:807034181e02 1152 if ((parser->limit - token_start) > 0) {
Josh Hollenbeck 1:807034181e02 1153 parser->buffer_own = malloc(parser->limit - token_start); // LCOV_EXCL_LINE
Josh Hollenbeck 1:807034181e02 1154 parser->limit = parser->buffer_own + (parser->limit - token_start);
Josh Hollenbeck 1:807034181e02 1155 memcpy(parser->buffer_own, token_start, parser->limit - parser->buffer_own);
Josh Hollenbeck 1:807034181e02 1156 if (res) {
Josh Hollenbeck 1:807034181e02 1157 free((void *)parser->buffer);
Josh Hollenbeck 1:807034181e02 1158 parser->buffer = parser->buffer_own;
Josh Hollenbeck 1:807034181e02 1159 }
Josh Hollenbeck 1:807034181e02 1160 } else {
Josh Hollenbeck 1:807034181e02 1161 if (res) {
Josh Hollenbeck 1:807034181e02 1162 free((void *)parser->buffer_own);
Josh Hollenbeck 1:807034181e02 1163 parser->buffer = NULL;
Josh Hollenbeck 1:807034181e02 1164 parser->buffer_own = NULL;
Josh Hollenbeck 1:807034181e02 1165 }
citrusbyte 0:01a2f8de46c8 1166 }
citrusbyte 0:01a2f8de46c8 1167 }
citrusbyte 0:01a2f8de46c8 1168 //
citrusbyte 0:01a2f8de46c8 1169 // Copyright 2012-2013, Andrii Mamchur
citrusbyte 0:01a2f8de46c8 1170 //
citrusbyte 0:01a2f8de46c8 1171 // Licensed under the Apache License, Version 2.0 (the "License");
citrusbyte 0:01a2f8de46c8 1172 // you may not use this file except in compliance with the License.
citrusbyte 0:01a2f8de46c8 1173 // You may obtain a copy of the License at
citrusbyte 0:01a2f8de46c8 1174 //
citrusbyte 0:01a2f8de46c8 1175 // http://www.apache.org/licenses/LICENSE-2.0
citrusbyte 0:01a2f8de46c8 1176 //
citrusbyte 0:01a2f8de46c8 1177 // Unless required by applicable law or agreed to in writing, software
citrusbyte 0:01a2f8de46c8 1178 // distributed under the License is distributed on an "AS IS" BASIS,
citrusbyte 0:01a2f8de46c8 1179 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
citrusbyte 0:01a2f8de46c8 1180 // See the License for the specific language governing permissions and
citrusbyte 0:01a2f8de46c8 1181 // limitations under the License
citrusbyte 0:01a2f8de46c8 1182
citrusbyte 0:01a2f8de46c8 1183 #ifndef JSONLITE_AMALGAMATED
Josh Hollenbeck 1:807034181e02 1184 #include "../include/jsonlite_stream.h"
citrusbyte 0:01a2f8de46c8 1185 #endif
citrusbyte 0:01a2f8de46c8 1186
citrusbyte 0:01a2f8de46c8 1187 #include <stdlib.h>
citrusbyte 0:01a2f8de46c8 1188 #include <string.h>
citrusbyte 0:01a2f8de46c8 1189
Josh Hollenbeck 1:807034181e02 1190 struct jsonlite_stream_struct {
Josh Hollenbeck 1:807034181e02 1191 jsonlite_stream_write_fn write;
Josh Hollenbeck 1:807034181e02 1192 jsonlite_stream_release_fn release;
Josh Hollenbeck 1:807034181e02 1193 } jsonlite_stream_struct;
citrusbyte 0:01a2f8de46c8 1194
Josh Hollenbeck 1:807034181e02 1195 int jsonlite_stream_write(jsonlite_stream stream, const void *data, size_t length) {
Josh Hollenbeck 1:807034181e02 1196 return stream->write(stream, data, length);
citrusbyte 0:01a2f8de46c8 1197 }
citrusbyte 0:01a2f8de46c8 1198
Josh Hollenbeck 1:807034181e02 1199 void jsonlite_stream_release(jsonlite_stream stream) {
Josh Hollenbeck 1:807034181e02 1200 if (stream == NULL) {
Josh Hollenbeck 1:807034181e02 1201 return;
citrusbyte 0:01a2f8de46c8 1202 }
citrusbyte 0:01a2f8de46c8 1203
Josh Hollenbeck 1:807034181e02 1204 if (stream->release != NULL) {
Josh Hollenbeck 1:807034181e02 1205 stream->release(stream);
citrusbyte 0:01a2f8de46c8 1206 }
citrusbyte 0:01a2f8de46c8 1207 }
citrusbyte 0:01a2f8de46c8 1208
Josh Hollenbeck 1:807034181e02 1209 static void jsonlite_stream_free_mem(jsonlite_stream stream) {
Josh Hollenbeck 1:807034181e02 1210 free((void *)stream);
citrusbyte 0:01a2f8de46c8 1211 }
citrusbyte 0:01a2f8de46c8 1212
Josh Hollenbeck 1:807034181e02 1213 #define CAST_TO_MEM_STREAM(S) (jsonlite_mem_stream *)((uint8_t *)(S) + sizeof(jsonlite_stream_struct))
Josh Hollenbeck 1:807034181e02 1214 #define SIZE_OF_MEM_STREAM() (sizeof(jsonlite_stream_struct) + sizeof(jsonlite_mem_stream))
Josh Hollenbeck 1:807034181e02 1215
Josh Hollenbeck 1:807034181e02 1216 typedef struct jsonlite_mem_stream_block {
Josh Hollenbeck 1:807034181e02 1217 struct jsonlite_mem_stream_block *next;
Josh Hollenbeck 1:807034181e02 1218 uint8_t *data;
Josh Hollenbeck 1:807034181e02 1219 } jsonlite_mem_stream_block;
Josh Hollenbeck 1:807034181e02 1220
Josh Hollenbeck 1:807034181e02 1221 typedef struct jsonlite_mem_stream {
Josh Hollenbeck 1:807034181e02 1222 size_t block_size;
Josh Hollenbeck 1:807034181e02 1223 uint8_t *cursor;
Josh Hollenbeck 1:807034181e02 1224 uint8_t *limit;
Josh Hollenbeck 1:807034181e02 1225 struct jsonlite_mem_stream_block *current;
Josh Hollenbeck 1:807034181e02 1226 struct jsonlite_mem_stream_block *first;
Josh Hollenbeck 1:807034181e02 1227 } jsonlite_mem_stream;
Josh Hollenbeck 1:807034181e02 1228
Josh Hollenbeck 1:807034181e02 1229 static int jsonlite_mem_stream_write(jsonlite_stream stream, const void *data, size_t length) {
Josh Hollenbeck 1:807034181e02 1230 jsonlite_mem_stream *mem_stream = CAST_TO_MEM_STREAM(stream);
Josh Hollenbeck 1:807034181e02 1231 size_t write_limit = mem_stream->limit - mem_stream->cursor;
Josh Hollenbeck 1:807034181e02 1232 if (write_limit >= length) {
Josh Hollenbeck 1:807034181e02 1233 memcpy(mem_stream->cursor, data, length); // LCOV_EXCL_LINE
Josh Hollenbeck 1:807034181e02 1234 mem_stream->cursor += length;
Josh Hollenbeck 1:807034181e02 1235 } else {
Josh Hollenbeck 1:807034181e02 1236 memcpy(mem_stream->cursor, data, write_limit); // LCOV_EXCL_LINE
Josh Hollenbeck 1:807034181e02 1237 mem_stream->cursor += write_limit;
Josh Hollenbeck 1:807034181e02 1238
Josh Hollenbeck 1:807034181e02 1239 size_t size = sizeof(jsonlite_mem_stream_block) + mem_stream->block_size;
Josh Hollenbeck 1:807034181e02 1240 jsonlite_mem_stream_block *block = malloc(size);
Josh Hollenbeck 1:807034181e02 1241 block->data = (uint8_t *)block + sizeof(jsonlite_mem_stream_block);
Josh Hollenbeck 1:807034181e02 1242 block->next = NULL;
Josh Hollenbeck 1:807034181e02 1243
Josh Hollenbeck 1:807034181e02 1244 mem_stream->current->next = block;
Josh Hollenbeck 1:807034181e02 1245 mem_stream->current = block;
Josh Hollenbeck 1:807034181e02 1246 mem_stream->cursor = block->data;
Josh Hollenbeck 1:807034181e02 1247 mem_stream->limit = block->data + mem_stream->block_size;
Josh Hollenbeck 1:807034181e02 1248
Josh Hollenbeck 1:807034181e02 1249 jsonlite_mem_stream_write(stream, (char *)data + write_limit, length - write_limit);
citrusbyte 0:01a2f8de46c8 1250 }
Josh Hollenbeck 1:807034181e02 1251
Josh Hollenbeck 1:807034181e02 1252 return (int)length;
citrusbyte 0:01a2f8de46c8 1253 }
citrusbyte 0:01a2f8de46c8 1254
Josh Hollenbeck 1:807034181e02 1255 static void jsonlite_mem_stream_release(jsonlite_stream stream) {
Josh Hollenbeck 1:807034181e02 1256 jsonlite_mem_stream *mem_stream = CAST_TO_MEM_STREAM(stream);
Josh Hollenbeck 1:807034181e02 1257 jsonlite_mem_stream_block *block = mem_stream->first;
Josh Hollenbeck 1:807034181e02 1258 void *prev;
Josh Hollenbeck 1:807034181e02 1259 for (; block != NULL;) {
Josh Hollenbeck 1:807034181e02 1260 prev = block;
Josh Hollenbeck 1:807034181e02 1261 block = block->next;
Josh Hollenbeck 1:807034181e02 1262 free(prev);
citrusbyte 0:01a2f8de46c8 1263 }
citrusbyte 0:01a2f8de46c8 1264
Josh Hollenbeck 1:807034181e02 1265 free((void *)stream);
citrusbyte 0:01a2f8de46c8 1266 }
citrusbyte 0:01a2f8de46c8 1267
Josh Hollenbeck 1:807034181e02 1268 jsonlite_stream jsonlite_mem_stream_init(size_t block_size) {
Josh Hollenbeck 1:807034181e02 1269 size_t size = SIZE_OF_MEM_STREAM();
Josh Hollenbeck 1:807034181e02 1270 struct jsonlite_stream_struct *stream = malloc(size);
Josh Hollenbeck 1:807034181e02 1271 stream->write = jsonlite_mem_stream_write;
Josh Hollenbeck 1:807034181e02 1272 stream->release = jsonlite_mem_stream_release;
citrusbyte 0:01a2f8de46c8 1273
Josh Hollenbeck 1:807034181e02 1274 jsonlite_mem_stream_block *first = malloc(sizeof(jsonlite_mem_stream_block) + block_size);
Josh Hollenbeck 1:807034181e02 1275 first->data = (uint8_t *)first + sizeof(jsonlite_mem_stream_block);
Josh Hollenbeck 1:807034181e02 1276 first->next = NULL;
citrusbyte 0:01a2f8de46c8 1277
Josh Hollenbeck 1:807034181e02 1278 jsonlite_mem_stream *mem_stream = CAST_TO_MEM_STREAM(stream);
Josh Hollenbeck 1:807034181e02 1279 mem_stream->block_size = block_size;
Josh Hollenbeck 1:807034181e02 1280 mem_stream->cursor = first->data;
Josh Hollenbeck 1:807034181e02 1281 mem_stream->limit = first->data + block_size;
Josh Hollenbeck 1:807034181e02 1282 mem_stream->current = first;
Josh Hollenbeck 1:807034181e02 1283 mem_stream->first = first;
Josh Hollenbeck 1:807034181e02 1284 return stream;
citrusbyte 0:01a2f8de46c8 1285 }
citrusbyte 0:01a2f8de46c8 1286
Josh Hollenbeck 1:807034181e02 1287 size_t jsonlite_mem_stream_data(jsonlite_stream stream, uint8_t **data, size_t extra_bytes) {
Josh Hollenbeck 1:807034181e02 1288 jsonlite_mem_stream *mem_stream = CAST_TO_MEM_STREAM(stream);
Josh Hollenbeck 1:807034181e02 1289 jsonlite_mem_stream_block *block = NULL;
Josh Hollenbeck 1:807034181e02 1290 uint8_t *buff = NULL;
Josh Hollenbeck 1:807034181e02 1291 size_t size = 0;
citrusbyte 0:01a2f8de46c8 1292
Josh Hollenbeck 1:807034181e02 1293 for (block = mem_stream->first; block != NULL; block = block->next) {
Josh Hollenbeck 1:807034181e02 1294 if (block->next != NULL) {
Josh Hollenbeck 1:807034181e02 1295 size += mem_stream->block_size;
Josh Hollenbeck 1:807034181e02 1296 } else {
Josh Hollenbeck 1:807034181e02 1297 size += mem_stream->cursor - block->data;
Josh Hollenbeck 1:807034181e02 1298 }
citrusbyte 0:01a2f8de46c8 1299 }
citrusbyte 0:01a2f8de46c8 1300
Josh Hollenbeck 1:807034181e02 1301 if (size == 0) {
Josh Hollenbeck 1:807034181e02 1302 *data = NULL;
citrusbyte 0:01a2f8de46c8 1303 } else {
Josh Hollenbeck 1:807034181e02 1304 *data = (uint8_t *)malloc(size + extra_bytes);
Josh Hollenbeck 1:807034181e02 1305 buff = *data;
Josh Hollenbeck 1:807034181e02 1306 for (block = mem_stream->first; block != NULL; block = block->next) {
Josh Hollenbeck 1:807034181e02 1307 if (block->next != NULL) {
Josh Hollenbeck 1:807034181e02 1308 memcpy(buff, block->data, mem_stream->block_size); // LCOV_EXCL_LINE
Josh Hollenbeck 1:807034181e02 1309 buff += mem_stream->block_size;
Josh Hollenbeck 1:807034181e02 1310 } else {
Josh Hollenbeck 1:807034181e02 1311 memcpy(buff, block->data, mem_stream->cursor - block->data); // LCOV_EXCL_LINE
Josh Hollenbeck 1:807034181e02 1312 }
Josh Hollenbeck 1:807034181e02 1313 }
citrusbyte 0:01a2f8de46c8 1314 }
Josh Hollenbeck 1:807034181e02 1315
Josh Hollenbeck 1:807034181e02 1316 return size;
citrusbyte 0:01a2f8de46c8 1317 }
citrusbyte 0:01a2f8de46c8 1318
Josh Hollenbeck 1:807034181e02 1319 #define CAST_TO_STATIC_MEM_STREAM(S) (jsonlite_static_mem_stream *)((uint8_t *)(S) + sizeof(jsonlite_stream_struct))
Josh Hollenbeck 1:807034181e02 1320 #define SIZE_OF_STATIC_MEM_STREAM() (sizeof(jsonlite_stream_struct) + sizeof(jsonlite_static_mem_stream))
Josh Hollenbeck 1:807034181e02 1321
Josh Hollenbeck 1:807034181e02 1322 typedef struct jsonlite_static_mem_stream {
Josh Hollenbeck 1:807034181e02 1323 uint8_t *buffer;
Josh Hollenbeck 1:807034181e02 1324 size_t size;
Josh Hollenbeck 1:807034181e02 1325 size_t written;
Josh Hollenbeck 1:807034181e02 1326 uint8_t *limit;
Josh Hollenbeck 1:807034181e02 1327 int enabled;
Josh Hollenbeck 1:807034181e02 1328 } jsonlite_static_mem_stream;
Josh Hollenbeck 1:807034181e02 1329
Josh Hollenbeck 1:807034181e02 1330 static int jsonlite_static_mem_stream_write(jsonlite_stream stream, const void *data, size_t length) {
Josh Hollenbeck 1:807034181e02 1331 jsonlite_static_mem_stream *mem_stream = CAST_TO_STATIC_MEM_STREAM(stream);
Josh Hollenbeck 1:807034181e02 1332 size_t write_limit = mem_stream->size - mem_stream->written;
Josh Hollenbeck 1:807034181e02 1333 if (mem_stream->enabled && write_limit >= length) {
Josh Hollenbeck 1:807034181e02 1334 memcpy(mem_stream->buffer + mem_stream->written, data, length); // LCOV_EXCL_LINE
Josh Hollenbeck 1:807034181e02 1335 mem_stream->written += length;
citrusbyte 0:01a2f8de46c8 1336 } else {
Josh Hollenbeck 1:807034181e02 1337 mem_stream->enabled = 0;
Josh Hollenbeck 1:807034181e02 1338 return 0;
citrusbyte 0:01a2f8de46c8 1339 }
citrusbyte 0:01a2f8de46c8 1340
Josh Hollenbeck 1:807034181e02 1341 return (int)length;
citrusbyte 0:01a2f8de46c8 1342 }
citrusbyte 0:01a2f8de46c8 1343
Josh Hollenbeck 1:807034181e02 1344 jsonlite_stream jsonlite_static_mem_stream_init(void *buffer, size_t size) {
Josh Hollenbeck 1:807034181e02 1345 size_t s = SIZE_OF_STATIC_MEM_STREAM();
Josh Hollenbeck 1:807034181e02 1346 struct jsonlite_stream_struct *stream = malloc(s);
Josh Hollenbeck 1:807034181e02 1347 stream->write = jsonlite_static_mem_stream_write;
Josh Hollenbeck 1:807034181e02 1348 stream->release = jsonlite_stream_free_mem;
citrusbyte 0:01a2f8de46c8 1349
Josh Hollenbeck 1:807034181e02 1350 jsonlite_static_mem_stream *mem_stream = CAST_TO_STATIC_MEM_STREAM(stream);
Josh Hollenbeck 1:807034181e02 1351 mem_stream->buffer = buffer;
Josh Hollenbeck 1:807034181e02 1352 mem_stream->size = size;
Josh Hollenbeck 1:807034181e02 1353 mem_stream->written = 0;
Josh Hollenbeck 1:807034181e02 1354 mem_stream->enabled = 1;
Josh Hollenbeck 1:807034181e02 1355 return stream;
citrusbyte 0:01a2f8de46c8 1356 }
citrusbyte 0:01a2f8de46c8 1357
Josh Hollenbeck 1:807034181e02 1358 size_t jsonlite_static_mem_stream_written_bytes(jsonlite_stream stream) {
Josh Hollenbeck 1:807034181e02 1359 jsonlite_static_mem_stream *mem_stream = CAST_TO_STATIC_MEM_STREAM(stream);
Josh Hollenbeck 1:807034181e02 1360 return mem_stream->written;
Josh Hollenbeck 1:807034181e02 1361 }
Josh Hollenbeck 1:807034181e02 1362
Josh Hollenbeck 1:807034181e02 1363 #define CAST_TO_FILE_STREAM(S) (jsonlite_file_stream *)((uint8_t *)(S) + sizeof(jsonlite_stream_struct))
Josh Hollenbeck 1:807034181e02 1364 #define SIZE_OF_FILE_STREAM() (sizeof(jsonlite_stream_struct) + sizeof(jsonlite_file_stream))
Josh Hollenbeck 1:807034181e02 1365
Josh Hollenbeck 1:807034181e02 1366 typedef struct jsonlite_file_stream {
Josh Hollenbeck 1:807034181e02 1367 FILE *file;
Josh Hollenbeck 1:807034181e02 1368 } jsonlite_file_stream;
Josh Hollenbeck 1:807034181e02 1369
Josh Hollenbeck 1:807034181e02 1370 static int jsonlite_file_stream_write(jsonlite_stream stream, const void *data, size_t length) {
Josh Hollenbeck 1:807034181e02 1371 jsonlite_file_stream *file_stream = CAST_TO_FILE_STREAM(stream);
Josh Hollenbeck 1:807034181e02 1372 return (int)fwrite(data, 1, length, file_stream->file);
citrusbyte 0:01a2f8de46c8 1373 }
citrusbyte 0:01a2f8de46c8 1374
Josh Hollenbeck 1:807034181e02 1375 jsonlite_stream jsonlite_file_stream_init(FILE *file) {
Josh Hollenbeck 1:807034181e02 1376 size_t size = SIZE_OF_FILE_STREAM();
Josh Hollenbeck 1:807034181e02 1377 struct jsonlite_stream_struct *stream = malloc(size);
Josh Hollenbeck 1:807034181e02 1378 stream->write = jsonlite_file_stream_write;
Josh Hollenbeck 1:807034181e02 1379 stream->release = jsonlite_stream_free_mem;
citrusbyte 0:01a2f8de46c8 1380
Josh Hollenbeck 1:807034181e02 1381 jsonlite_file_stream *file_stream = CAST_TO_FILE_STREAM(stream);
Josh Hollenbeck 1:807034181e02 1382 file_stream->file = file;
Josh Hollenbeck 1:807034181e02 1383 return stream;
citrusbyte 0:01a2f8de46c8 1384 }
citrusbyte 0:01a2f8de46c8 1385
Josh Hollenbeck 1:807034181e02 1386 static int jsonlite_null_stream_write(jsonlite_stream stream, const void *data, size_t length) {
Josh Hollenbeck 1:807034181e02 1387 return (int)length;
Josh Hollenbeck 1:807034181e02 1388 }
citrusbyte 0:01a2f8de46c8 1389
Josh Hollenbeck 1:807034181e02 1390 static int jsonlite_stdout_stream_write(jsonlite_stream stream, const void *data, size_t length) {
Josh Hollenbeck 1:807034181e02 1391 return (int)fwrite(data, 1, length, stdout);
citrusbyte 0:01a2f8de46c8 1392 }
Josh Hollenbeck 1:807034181e02 1393
Josh Hollenbeck 1:807034181e02 1394 static struct jsonlite_stream_struct jsonlite_stdout_stream_struct = {jsonlite_stdout_stream_write, NULL};
Josh Hollenbeck 1:807034181e02 1395 static struct jsonlite_stream_struct jsonlite_null_stream_struct = {jsonlite_null_stream_write, NULL};
Josh Hollenbeck 1:807034181e02 1396
Josh Hollenbeck 1:807034181e02 1397 jsonlite_stream jsonlite_stdout_stream = &jsonlite_stdout_stream_struct;
Josh Hollenbeck 1:807034181e02 1398 jsonlite_stream jsonlite_null_stream = &jsonlite_null_stream_struct;
citrusbyte 0:01a2f8de46c8 1399 //
citrusbyte 0:01a2f8de46c8 1400 // Copyright 2012-2013, Andrii Mamchur
citrusbyte 0:01a2f8de46c8 1401 //
citrusbyte 0:01a2f8de46c8 1402 // Licensed under the Apache License, Version 2.0 (the "License");
citrusbyte 0:01a2f8de46c8 1403 // you may not use this file except in compliance with the License.
citrusbyte 0:01a2f8de46c8 1404 // You may obtain a copy of the License at
citrusbyte 0:01a2f8de46c8 1405 //
citrusbyte 0:01a2f8de46c8 1406 // http://www.apache.org/licenses/LICENSE-2.0
citrusbyte 0:01a2f8de46c8 1407 //
citrusbyte 0:01a2f8de46c8 1408 // Unless required by applicable law or agreed to in writing, software
citrusbyte 0:01a2f8de46c8 1409 // distributed under the License is distributed on an "AS IS" BASIS,
citrusbyte 0:01a2f8de46c8 1410 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
citrusbyte 0:01a2f8de46c8 1411 // See the License for the specific language governing permissions and
citrusbyte 0:01a2f8de46c8 1412 // limitations under the License
citrusbyte 0:01a2f8de46c8 1413
citrusbyte 0:01a2f8de46c8 1414 #ifndef JSONLITE_AMALGAMATED
citrusbyte 0:01a2f8de46c8 1415 #include "../include/jsonlite_token.h"
citrusbyte 0:01a2f8de46c8 1416 #endif
citrusbyte 0:01a2f8de46c8 1417
citrusbyte 0:01a2f8de46c8 1418 #include <stdlib.h>
citrusbyte 0:01a2f8de46c8 1419
citrusbyte 0:01a2f8de46c8 1420 #ifdef _MSC_VER
citrusbyte 0:01a2f8de46c8 1421 #include <intrin.h>
citrusbyte 0:01a2f8de46c8 1422
citrusbyte 0:01a2f8de46c8 1423 static uint32_t __inline jsonlite_clz( uint32_t x ) {
citrusbyte 0:01a2f8de46c8 1424 unsigned long r = 0;
citrusbyte 0:01a2f8de46c8 1425 _BitScanForward(&r, x);
citrusbyte 0:01a2f8de46c8 1426 return r;
citrusbyte 0:01a2f8de46c8 1427 }
citrusbyte 0:01a2f8de46c8 1428
citrusbyte 0:01a2f8de46c8 1429 #else
citrusbyte 0:01a2f8de46c8 1430
citrusbyte 0:01a2f8de46c8 1431 #define jsonlite_clz(x) __builtin_clz((x))
citrusbyte 0:01a2f8de46c8 1432
citrusbyte 0:01a2f8de46c8 1433 #endif
citrusbyte 0:01a2f8de46c8 1434
Josh Hollenbeck 1:807034181e02 1435 static uint8_t jsonlite_hex_char_to_uint8(uint8_t c) {
Josh Hollenbeck 1:807034181e02 1436 if (c >= 'a') {
Josh Hollenbeck 1:807034181e02 1437 return c - 'a' + 10;
citrusbyte 0:01a2f8de46c8 1438 }
Josh Hollenbeck 1:807034181e02 1439
Josh Hollenbeck 1:807034181e02 1440 if (c >= 'A') {
Josh Hollenbeck 1:807034181e02 1441 return c - 'A' + 10;
Josh Hollenbeck 1:807034181e02 1442 }
Josh Hollenbeck 1:807034181e02 1443
Josh Hollenbeck 1:807034181e02 1444 return c - '0';
citrusbyte 0:01a2f8de46c8 1445 }
citrusbyte 0:01a2f8de46c8 1446
citrusbyte 0:01a2f8de46c8 1447 static int unicode_char_to_utf16(uint32_t ch, uint16_t *utf16) {
citrusbyte 0:01a2f8de46c8 1448 uint32_t v = ch - 0x10000;
citrusbyte 0:01a2f8de46c8 1449 uint32_t vh = v >> 10;
citrusbyte 0:01a2f8de46c8 1450 uint32_t vl = v & 0x3FF;
Josh Hollenbeck 1:807034181e02 1451 if (ch <= 0xFFFF) {
citrusbyte 0:01a2f8de46c8 1452 *utf16 = (uint16_t)ch;
citrusbyte 0:01a2f8de46c8 1453 return 1;
citrusbyte 0:01a2f8de46c8 1454 }
Josh Hollenbeck 1:807034181e02 1455
citrusbyte 0:01a2f8de46c8 1456 *utf16++ = (uint16_t)(0xD800 + vh);
citrusbyte 0:01a2f8de46c8 1457 *utf16 = (uint16_t)(0xDC00 + vl);
citrusbyte 0:01a2f8de46c8 1458 return 2;
citrusbyte 0:01a2f8de46c8 1459 }
citrusbyte 0:01a2f8de46c8 1460
Josh Hollenbeck 1:807034181e02 1461 size_t jsonlite_token_size_of_uft8(jsonlite_token *ts) {
Josh Hollenbeck 1:807034181e02 1462 return (size_t)(ts->end - ts->start + 1);
citrusbyte 0:01a2f8de46c8 1463 }
citrusbyte 0:01a2f8de46c8 1464
Josh Hollenbeck 1:807034181e02 1465 size_t jsonlite_token_to_uft8(jsonlite_token *ts, uint8_t **buffer) {
Josh Hollenbeck 1:807034181e02 1466 size_t size = jsonlite_token_size_of_uft8(ts);
citrusbyte 0:01a2f8de46c8 1467 const uint8_t *p = ts->start;
citrusbyte 0:01a2f8de46c8 1468 const uint8_t *l = ts->end;
citrusbyte 0:01a2f8de46c8 1469 uint32_t value, utf32;
Josh Hollenbeck 1:807034181e02 1470 uint8_t *c = *buffer = (uint8_t *)malloc(size);
citrusbyte 0:01a2f8de46c8 1471 int res;
citrusbyte 0:01a2f8de46c8 1472 step:
citrusbyte 0:01a2f8de46c8 1473 if (p == l) goto done;
citrusbyte 0:01a2f8de46c8 1474 if (*p == '\\') goto escaped;
citrusbyte 0:01a2f8de46c8 1475 if (*p >= 0x80) goto utf8;
citrusbyte 0:01a2f8de46c8 1476 *c++ = *p++;
citrusbyte 0:01a2f8de46c8 1477 goto step;
citrusbyte 0:01a2f8de46c8 1478 escaped:
citrusbyte 0:01a2f8de46c8 1479 switch (*++p) {
citrusbyte 0:01a2f8de46c8 1480 case 34: *c++ = '"'; p++; goto step;
citrusbyte 0:01a2f8de46c8 1481 case 47: *c++ = '/'; p++; goto step;
citrusbyte 0:01a2f8de46c8 1482 case 92: *c++ = '\\'; p++; goto step;
citrusbyte 0:01a2f8de46c8 1483 case 98: *c++ = '\b'; p++; goto step;
citrusbyte 0:01a2f8de46c8 1484 case 102: *c++ = '\f'; p++; goto step;
citrusbyte 0:01a2f8de46c8 1485 case 110: *c++ = '\n'; p++; goto step;
citrusbyte 0:01a2f8de46c8 1486 case 114: *c++ = '\r'; p++; goto step;
citrusbyte 0:01a2f8de46c8 1487 case 116: *c++ = '\t'; p++; goto step;
Josh Hollenbeck 1:807034181e02 1488 }
citrusbyte 0:01a2f8de46c8 1489
Josh Hollenbeck 1:807034181e02 1490 // UTF-16
citrusbyte 0:01a2f8de46c8 1491 p++;
citrusbyte 0:01a2f8de46c8 1492 utf32 = jsonlite_hex_char_to_uint8(*p++);
citrusbyte 0:01a2f8de46c8 1493 utf32 = (uint32_t)(utf32 << 4) | jsonlite_hex_char_to_uint8(*p++);
citrusbyte 0:01a2f8de46c8 1494 utf32 = (uint32_t)(utf32 << 4) | jsonlite_hex_char_to_uint8(*p++);
citrusbyte 0:01a2f8de46c8 1495 utf32 = (uint32_t)(utf32 << 4) | jsonlite_hex_char_to_uint8(*p++);
citrusbyte 0:01a2f8de46c8 1496 if (0xD800 > utf32 || utf32 > 0xDBFF) goto encode;
Josh Hollenbeck 1:807034181e02 1497
citrusbyte 0:01a2f8de46c8 1498 // UTF-16 Surrogate
citrusbyte 0:01a2f8de46c8 1499 p += 2;
citrusbyte 0:01a2f8de46c8 1500 utf32 = (utf32 - 0xD800) << 10;
citrusbyte 0:01a2f8de46c8 1501 value = jsonlite_hex_char_to_uint8(*p++);
citrusbyte 0:01a2f8de46c8 1502 value = (uint32_t)(value << 4) | jsonlite_hex_char_to_uint8(*p++);
citrusbyte 0:01a2f8de46c8 1503 value = (uint32_t)(value << 4) | jsonlite_hex_char_to_uint8(*p++);
citrusbyte 0:01a2f8de46c8 1504 value = (uint32_t)(value << 4) | jsonlite_hex_char_to_uint8(*p++);
citrusbyte 0:01a2f8de46c8 1505 utf32 += value - 0xDC00 + 0x10000;
citrusbyte 0:01a2f8de46c8 1506 encode:
citrusbyte 0:01a2f8de46c8 1507 if (utf32 < 0x80) {
citrusbyte 0:01a2f8de46c8 1508 *c++ = (uint8_t)utf32;
citrusbyte 0:01a2f8de46c8 1509 } else if (utf32 < 0x0800) {
citrusbyte 0:01a2f8de46c8 1510 c[1] = (uint8_t)(utf32 & 0x3F) | 0x80;
citrusbyte 0:01a2f8de46c8 1511 utf32 = utf32 >> 6;
citrusbyte 0:01a2f8de46c8 1512 c[0] = (uint8_t)utf32 | 0xC0;
citrusbyte 0:01a2f8de46c8 1513 c += 2;
citrusbyte 0:01a2f8de46c8 1514 } else if (utf32 < 0x10000) {
citrusbyte 0:01a2f8de46c8 1515 c[2] = (uint8_t)(utf32 & 0x3F) | 0x80;
citrusbyte 0:01a2f8de46c8 1516 utf32 = utf32 >> 6;
citrusbyte 0:01a2f8de46c8 1517 c[1] = (uint8_t)(utf32 & 0x3F) | 0x80;
citrusbyte 0:01a2f8de46c8 1518 utf32 = utf32 >> 6;
citrusbyte 0:01a2f8de46c8 1519 c[0] = (uint8_t)utf32 | 0xE0;
citrusbyte 0:01a2f8de46c8 1520 c += 3;
citrusbyte 0:01a2f8de46c8 1521 } else {
citrusbyte 0:01a2f8de46c8 1522 c[3] = (uint8_t)(utf32 & 0x3F) | 0x80;
citrusbyte 0:01a2f8de46c8 1523 utf32 = utf32 >> 6;
citrusbyte 0:01a2f8de46c8 1524 c[2] = (uint8_t)(utf32 & 0x3F) | 0x80;
citrusbyte 0:01a2f8de46c8 1525 utf32 = utf32 >> 6;
citrusbyte 0:01a2f8de46c8 1526 c[1] = (uint8_t)(utf32 & 0x3F) | 0x80;
citrusbyte 0:01a2f8de46c8 1527 utf32 = utf32 >> 6;
citrusbyte 0:01a2f8de46c8 1528 c[0] = (uint8_t)utf32 | 0xF0;
citrusbyte 0:01a2f8de46c8 1529 c += 4;
citrusbyte 0:01a2f8de46c8 1530 }
citrusbyte 0:01a2f8de46c8 1531 goto step;
citrusbyte 0:01a2f8de46c8 1532 utf8:
citrusbyte 0:01a2f8de46c8 1533 res = jsonlite_clz(((*p) ^ 0xFF) << 0x19);
citrusbyte 0:01a2f8de46c8 1534 *c++ = *p++;
citrusbyte 0:01a2f8de46c8 1535 switch (res) {
citrusbyte 0:01a2f8de46c8 1536 case 3: *c++ = *p++;
citrusbyte 0:01a2f8de46c8 1537 case 2: *c++ = *p++;
citrusbyte 0:01a2f8de46c8 1538 case 1: *c++ = *p++;
citrusbyte 0:01a2f8de46c8 1539 }
citrusbyte 0:01a2f8de46c8 1540 goto step;
citrusbyte 0:01a2f8de46c8 1541 done:
citrusbyte 0:01a2f8de46c8 1542 *c = 0;
citrusbyte 0:01a2f8de46c8 1543 return c - *buffer;
citrusbyte 0:01a2f8de46c8 1544 }
citrusbyte 0:01a2f8de46c8 1545
Josh Hollenbeck 1:807034181e02 1546 size_t jsonlite_token_size_of_uft16(jsonlite_token *ts) {
citrusbyte 0:01a2f8de46c8 1547 return (ts->end - ts->start + 1) * sizeof(uint16_t);
citrusbyte 0:01a2f8de46c8 1548 }
citrusbyte 0:01a2f8de46c8 1549
Josh Hollenbeck 1:807034181e02 1550 size_t jsonlite_token_to_uft16(jsonlite_token *ts, uint16_t **buffer) {
Josh Hollenbeck 1:807034181e02 1551 size_t size = jsonlite_token_size_of_uft16(ts);
citrusbyte 0:01a2f8de46c8 1552 const uint8_t *p = ts->start;
citrusbyte 0:01a2f8de46c8 1553 const uint8_t *l = ts->end;
citrusbyte 0:01a2f8de46c8 1554 uint16_t utf16;
citrusbyte 0:01a2f8de46c8 1555 uint16_t *c = *buffer = (uint16_t *)malloc(size);
Josh Hollenbeck 1:807034181e02 1556 int res;
citrusbyte 0:01a2f8de46c8 1557 step:
citrusbyte 0:01a2f8de46c8 1558 if (p == l) goto done;
citrusbyte 0:01a2f8de46c8 1559 if (*p == '\\') goto escaped;
citrusbyte 0:01a2f8de46c8 1560 if (*p >= 0x80) goto utf8;
citrusbyte 0:01a2f8de46c8 1561 *c++ = *p++;
citrusbyte 0:01a2f8de46c8 1562 goto step;
citrusbyte 0:01a2f8de46c8 1563 escaped:
citrusbyte 0:01a2f8de46c8 1564 switch (*++p) {
citrusbyte 0:01a2f8de46c8 1565 case 34: *c++ = '"'; p++; goto step;
citrusbyte 0:01a2f8de46c8 1566 case 47: *c++ = '/'; p++; goto step;
citrusbyte 0:01a2f8de46c8 1567 case 92: *c++ = '\\'; p++; goto step;
citrusbyte 0:01a2f8de46c8 1568 case 98: *c++ = '\b'; p++; goto step;
citrusbyte 0:01a2f8de46c8 1569 case 102: *c++ = '\f'; p++; goto step;
citrusbyte 0:01a2f8de46c8 1570 case 110: *c++ = '\n'; p++; goto step;
citrusbyte 0:01a2f8de46c8 1571 case 114: *c++ = '\r'; p++; goto step;
citrusbyte 0:01a2f8de46c8 1572 case 116: *c++ = '\t'; p++; goto step;
Josh Hollenbeck 1:807034181e02 1573 }
Josh Hollenbeck 1:807034181e02 1574
citrusbyte 0:01a2f8de46c8 1575 // UTF-16
citrusbyte 0:01a2f8de46c8 1576 p++;
citrusbyte 0:01a2f8de46c8 1577 utf16 = jsonlite_hex_char_to_uint8(*p++);
citrusbyte 0:01a2f8de46c8 1578 utf16 = (uint16_t)(utf16 << 4) | jsonlite_hex_char_to_uint8(*p++);
citrusbyte 0:01a2f8de46c8 1579 utf16 = (uint16_t)(utf16 << 4) | jsonlite_hex_char_to_uint8(*p++);
citrusbyte 0:01a2f8de46c8 1580 utf16 = (uint16_t)(utf16 << 4) | jsonlite_hex_char_to_uint8(*p++);
citrusbyte 0:01a2f8de46c8 1581 *c++ = utf16;
citrusbyte 0:01a2f8de46c8 1582 if (0xD800 > utf16 || utf16 > 0xDBFF) goto step;
Josh Hollenbeck 1:807034181e02 1583
citrusbyte 0:01a2f8de46c8 1584 // UTF-16 Surrogate
citrusbyte 0:01a2f8de46c8 1585 p += 2;
citrusbyte 0:01a2f8de46c8 1586 utf16 = jsonlite_hex_char_to_uint8(*p++);
citrusbyte 0:01a2f8de46c8 1587 utf16 = (uint16_t)(utf16 << 4) | jsonlite_hex_char_to_uint8(*p++);
citrusbyte 0:01a2f8de46c8 1588 utf16 = (uint16_t)(utf16 << 4) | jsonlite_hex_char_to_uint8(*p++);
citrusbyte 0:01a2f8de46c8 1589 utf16 = (uint16_t)(utf16 << 4) | jsonlite_hex_char_to_uint8(*p++);
citrusbyte 0:01a2f8de46c8 1590 *c++ = utf16;
citrusbyte 0:01a2f8de46c8 1591 goto step;
citrusbyte 0:01a2f8de46c8 1592 utf8:
citrusbyte 0:01a2f8de46c8 1593 res = jsonlite_clz(((*p) ^ 0xFF) << 0x19);
citrusbyte 0:01a2f8de46c8 1594 uint32_t code = (*p & (0xFF >> (res + 1)));
citrusbyte 0:01a2f8de46c8 1595 switch (res) {
citrusbyte 0:01a2f8de46c8 1596 case 3: code = (code << 6) | (*++p & 0x3F);
citrusbyte 0:01a2f8de46c8 1597 case 2: code = (code << 6) | (*++p & 0x3F);
citrusbyte 0:01a2f8de46c8 1598 case 1: code = (code << 6) | (*++p & 0x3F);
citrusbyte 0:01a2f8de46c8 1599 case 0: ++p;
citrusbyte 0:01a2f8de46c8 1600 }
Josh Hollenbeck 1:807034181e02 1601
citrusbyte 0:01a2f8de46c8 1602 c += unicode_char_to_utf16(code, c);
citrusbyte 0:01a2f8de46c8 1603 goto step;
citrusbyte 0:01a2f8de46c8 1604 done:
citrusbyte 0:01a2f8de46c8 1605 *c = 0;
citrusbyte 0:01a2f8de46c8 1606 return (c - *buffer) * sizeof(uint16_t);
citrusbyte 0:01a2f8de46c8 1607 }
Josh Hollenbeck 1:807034181e02 1608
Josh Hollenbeck 1:807034181e02 1609 size_t jsonlite_token_size_of_base64_binary(jsonlite_token *ts) {
Josh Hollenbeck 1:807034181e02 1610 return (((ts->end - ts->start) * 3) / 4 + 3) & ~3;
Josh Hollenbeck 1:807034181e02 1611 }
Josh Hollenbeck 1:807034181e02 1612
Josh Hollenbeck 1:807034181e02 1613 size_t jsonlite_token_base64_to_binary(jsonlite_token *ts, void **buffer) {
Josh Hollenbeck 1:807034181e02 1614 size_t length = 0;
Josh Hollenbeck 1:807034181e02 1615 size_t size = jsonlite_token_size_of_base64_binary(ts);
Josh Hollenbeck 1:807034181e02 1616 const uint8_t *p = ts->start;
Josh Hollenbeck 1:807034181e02 1617 const uint8_t *l = ts->end;
Josh Hollenbeck 1:807034181e02 1618 uint8_t *c;
Josh Hollenbeck 1:807034181e02 1619 size_t bytes, i;
Josh Hollenbeck 1:807034181e02 1620 if (size > 0) {
Josh Hollenbeck 1:807034181e02 1621 c = *buffer = (uint16_t *)malloc(size);
Josh Hollenbeck 1:807034181e02 1622 } else {
Josh Hollenbeck 1:807034181e02 1623 *buffer = NULL;
Josh Hollenbeck 1:807034181e02 1624 goto error;
Josh Hollenbeck 1:807034181e02 1625 }
Josh Hollenbeck 1:807034181e02 1626 next:
Josh Hollenbeck 1:807034181e02 1627 bytes = 0;
Josh Hollenbeck 1:807034181e02 1628 i = 0;
Josh Hollenbeck 1:807034181e02 1629 do {
Josh Hollenbeck 1:807034181e02 1630 if (p == l) goto error;
Josh Hollenbeck 1:807034181e02 1631 i++;
Josh Hollenbeck 1:807034181e02 1632 bytes <<= 6;
Josh Hollenbeck 1:807034181e02 1633 if (0x41 <= *p && *p <= 0x5A) { bytes |= *p++ - 0x41; continue; }
Josh Hollenbeck 1:807034181e02 1634 if (0x61 <= *p && *p <= 0x7A) { bytes |= *p++ - 0x47; continue; }
Josh Hollenbeck 1:807034181e02 1635 if (0x30 <= *p && *p <= 0x39) { bytes |= *p++ + 0x04; continue; }
Josh Hollenbeck 1:807034181e02 1636 if (*p == 0x2B) { bytes |= 0x3E; p++; continue; }
Josh Hollenbeck 1:807034181e02 1637 if (*p == 0x2F) { bytes |= 0x3F; p++; continue; }
Josh Hollenbeck 1:807034181e02 1638 if (*p == '=') {
Josh Hollenbeck 1:807034181e02 1639 switch (l - p) {
Josh Hollenbeck 1:807034181e02 1640 case 1:
Josh Hollenbeck 1:807034181e02 1641 *c++ = (uint8_t)((bytes >> 16) & 0x000000FF);
Josh Hollenbeck 1:807034181e02 1642 *c = (uint8_t)((bytes >> 8) & 0x000000FF);
Josh Hollenbeck 1:807034181e02 1643 return length + 2;
Josh Hollenbeck 1:807034181e02 1644 case 2:
Josh Hollenbeck 1:807034181e02 1645 *c = (uint8_t)((bytes >> 10) & 0x000000FF);
Josh Hollenbeck 1:807034181e02 1646 return length + 1;
Josh Hollenbeck 1:807034181e02 1647 }
Josh Hollenbeck 1:807034181e02 1648 }
Josh Hollenbeck 1:807034181e02 1649 if (*p == 0x5C && *++p == 0x2F) { bytes |= 0x3F; p++; continue; }
Josh Hollenbeck 1:807034181e02 1650 goto error;
Josh Hollenbeck 1:807034181e02 1651 } while (i < 4);
Josh Hollenbeck 1:807034181e02 1652
Josh Hollenbeck 1:807034181e02 1653 *c++ = (uint8_t)((bytes >> 16) & 0x000000FF);
Josh Hollenbeck 1:807034181e02 1654 *c++ = (uint8_t)((bytes >> 8) & 0x000000FF);
Josh Hollenbeck 1:807034181e02 1655 *c++ = (uint8_t)((bytes) & 0x000000FF);
Josh Hollenbeck 1:807034181e02 1656 length += 3;
Josh Hollenbeck 1:807034181e02 1657
Josh Hollenbeck 1:807034181e02 1658 if (p == l) goto done;
Josh Hollenbeck 1:807034181e02 1659 goto next;
Josh Hollenbeck 1:807034181e02 1660 error:
Josh Hollenbeck 1:807034181e02 1661 free(*buffer);
Josh Hollenbeck 1:807034181e02 1662 *buffer = NULL;
Josh Hollenbeck 1:807034181e02 1663 length = 0;
Josh Hollenbeck 1:807034181e02 1664 done:
Josh Hollenbeck 1:807034181e02 1665 return length;
Josh Hollenbeck 1:807034181e02 1666 }
Josh Hollenbeck 1:807034181e02 1667
Josh Hollenbeck 1:807034181e02 1668 long jsonlite_token_to_long(jsonlite_token *token) {
Josh Hollenbeck 1:807034181e02 1669 long res = 0;
Josh Hollenbeck 1:807034181e02 1670 int negative = (token->type.number & jsonlite_number_negative) == jsonlite_number_negative;
Josh Hollenbeck 1:807034181e02 1671 ptrdiff_t length = token->end - token->start - negative;
Josh Hollenbeck 1:807034181e02 1672 const uint8_t *c = token->start + negative;
Josh Hollenbeck 1:807034181e02 1673 switch (length & 3) {
Josh Hollenbeck 1:807034181e02 1674 for (; length > 0; length -= 4) {
Josh Hollenbeck 1:807034181e02 1675 case 0: res = res * 10 + *c++ - '0';
Josh Hollenbeck 1:807034181e02 1676 case 3: res = res * 10 + *c++ - '0';
Josh Hollenbeck 1:807034181e02 1677 case 2: res = res * 10 + *c++ - '0';
Josh Hollenbeck 1:807034181e02 1678 case 1: res = res * 10 + *c++ - '0';
Josh Hollenbeck 1:807034181e02 1679 }
Josh Hollenbeck 1:807034181e02 1680 }
Josh Hollenbeck 1:807034181e02 1681
Josh Hollenbeck 1:807034181e02 1682 return negative ? -res : res;
Josh Hollenbeck 1:807034181e02 1683 }
Josh Hollenbeck 1:807034181e02 1684
Josh Hollenbeck 1:807034181e02 1685 long long jsonlite_token_to_long_long(jsonlite_token *token) {
Josh Hollenbeck 1:807034181e02 1686 long long res = 0;
Josh Hollenbeck 1:807034181e02 1687 int negative = (token->type.number & jsonlite_number_negative) == jsonlite_number_negative;
Josh Hollenbeck 1:807034181e02 1688 ptrdiff_t length = token->end - token->start - negative;
Josh Hollenbeck 1:807034181e02 1689 const uint8_t *c = token->start + negative;
Josh Hollenbeck 1:807034181e02 1690 switch (length & 7) {
Josh Hollenbeck 1:807034181e02 1691 for (; length > 0; length -= 8) {
Josh Hollenbeck 1:807034181e02 1692 case 0: res = res * 10 + *c++ - '0';
Josh Hollenbeck 1:807034181e02 1693 case 7: res = res * 10 + *c++ - '0';
Josh Hollenbeck 1:807034181e02 1694 case 6: res = res * 10 + *c++ - '0';
Josh Hollenbeck 1:807034181e02 1695 case 5: res = res * 10 + *c++ - '0';
Josh Hollenbeck 1:807034181e02 1696 case 4: res = res * 10 + *c++ - '0';
Josh Hollenbeck 1:807034181e02 1697 case 3: res = res * 10 + *c++ - '0';
Josh Hollenbeck 1:807034181e02 1698 case 2: res = res * 10 + *c++ - '0';
Josh Hollenbeck 1:807034181e02 1699 case 1: res = res * 10 + *c++ - '0';
Josh Hollenbeck 1:807034181e02 1700 }
Josh Hollenbeck 1:807034181e02 1701 }
Josh Hollenbeck 1:807034181e02 1702
Josh Hollenbeck 1:807034181e02 1703 return negative ? -res : res;
Josh Hollenbeck 1:807034181e02 1704 }
citrusbyte 0:01a2f8de46c8 1705 //
citrusbyte 0:01a2f8de46c8 1706 // Copyright 2012-2013, Andrii Mamchur
citrusbyte 0:01a2f8de46c8 1707 //
citrusbyte 0:01a2f8de46c8 1708 // Licensed under the Apache License, Version 2.0 (the "License");
citrusbyte 0:01a2f8de46c8 1709 // you may not use this file except in compliance with the License.
citrusbyte 0:01a2f8de46c8 1710 // You may obtain a copy of the License at
citrusbyte 0:01a2f8de46c8 1711 //
citrusbyte 0:01a2f8de46c8 1712 // http://www.apache.org/licenses/LICENSE-2.0
citrusbyte 0:01a2f8de46c8 1713 //
citrusbyte 0:01a2f8de46c8 1714 // Unless required by applicable law or agreed to in writing, software
citrusbyte 0:01a2f8de46c8 1715 // distributed under the License is distributed on an "AS IS" BASIS,
citrusbyte 0:01a2f8de46c8 1716 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
citrusbyte 0:01a2f8de46c8 1717 // See the License for the specific language governing permissions and
citrusbyte 0:01a2f8de46c8 1718 // limitations under the License
citrusbyte 0:01a2f8de46c8 1719
citrusbyte 0:01a2f8de46c8 1720 #ifndef JSONLITE_AMALGAMATED
citrusbyte 0:01a2f8de46c8 1721 #include "../include/jsonlite_token_pool.h"
citrusbyte 0:01a2f8de46c8 1722 #endif
citrusbyte 0:01a2f8de46c8 1723
citrusbyte 0:01a2f8de46c8 1724 #include <stdlib.h>
citrusbyte 0:01a2f8de46c8 1725 #include <string.h>
citrusbyte 0:01a2f8de46c8 1726
citrusbyte 0:01a2f8de46c8 1727 #define JSONLITE_TOKEN_POOL_FRONT 0x80
citrusbyte 0:01a2f8de46c8 1728 #define JSONLITE_TOKEN_POOL_FRONT_MASK (JSONLITE_TOKEN_POOL_FRONT - 1)
citrusbyte 0:01a2f8de46c8 1729
Josh Hollenbeck 1:807034181e02 1730 typedef struct jsonlite_token_block {
Josh Hollenbeck 1:807034181e02 1731 jsonlite_token_bucket *buckets;
Josh Hollenbeck 1:807034181e02 1732 size_t capacity;
Josh Hollenbeck 1:807034181e02 1733 } jsonlite_token_block;
Josh Hollenbeck 1:807034181e02 1734
Josh Hollenbeck 1:807034181e02 1735 typedef struct jsonlite_token_pool_struct {
Josh Hollenbeck 1:807034181e02 1736 jsonlite_token_block blocks[JSONLITE_TOKEN_POOL_FRONT];
citrusbyte 0:01a2f8de46c8 1737 uint8_t *content_pool;
citrusbyte 0:01a2f8de46c8 1738 size_t content_pool_size;
citrusbyte 0:01a2f8de46c8 1739 jsonlite_token_pool_release_value_fn release_fn;
Josh Hollenbeck 1:807034181e02 1740
citrusbyte 0:01a2f8de46c8 1741 } jsonlite_token_pool_struct;
citrusbyte 0:01a2f8de46c8 1742
Josh Hollenbeck 1:807034181e02 1743 static void jsonlite_extend_capacity(jsonlite_token_pool pool, ptrdiff_t index);
citrusbyte 0:01a2f8de46c8 1744 static uint32_t jsonlite_hash(const uint8_t *data, size_t len);
Josh Hollenbeck 1:807034181e02 1745 static jsonlite_token_bucket terminate_bucket = {NULL, NULL, 0, 0, NULL};
citrusbyte 0:01a2f8de46c8 1746
citrusbyte 0:01a2f8de46c8 1747 jsonlite_token_pool jsonlite_token_pool_create(jsonlite_token_pool_release_value_fn release_fn) {
Josh Hollenbeck 1:807034181e02 1748 jsonlite_token_pool pool = (jsonlite_token_pool)malloc(sizeof(jsonlite_token_pool_struct));
Josh Hollenbeck 1:807034181e02 1749 int i;
Josh Hollenbeck 1:807034181e02 1750 for (i = 0; i < JSONLITE_TOKEN_POOL_FRONT; i++) {
Josh Hollenbeck 1:807034181e02 1751 pool->blocks[i].buckets = &terminate_bucket;
Josh Hollenbeck 1:807034181e02 1752 pool->blocks[i].capacity = 0;
Josh Hollenbeck 1:807034181e02 1753 }
citrusbyte 0:01a2f8de46c8 1754 pool->release_fn = release_fn;
Josh Hollenbeck 1:807034181e02 1755 pool->content_pool = NULL;
Josh Hollenbeck 1:807034181e02 1756 pool->content_pool_size = 0;
citrusbyte 0:01a2f8de46c8 1757 return pool;
citrusbyte 0:01a2f8de46c8 1758 }
citrusbyte 0:01a2f8de46c8 1759
citrusbyte 0:01a2f8de46c8 1760 void jsonlite_token_pool_copy_tokens(jsonlite_token_pool pool) {
Josh Hollenbeck 1:807034181e02 1761 jsonlite_token_bucket *bucket;
Josh Hollenbeck 1:807034181e02 1762 size_t size = 0;
citrusbyte 0:01a2f8de46c8 1763 int i;
citrusbyte 0:01a2f8de46c8 1764 for (i = 0; i < JSONLITE_TOKEN_POOL_FRONT; i++) {
Josh Hollenbeck 1:807034181e02 1765 bucket = pool->blocks[i].buckets;
Josh Hollenbeck 1:807034181e02 1766 while (bucket->start != NULL) {
Josh Hollenbeck 1:807034181e02 1767 size += bucket->end - bucket->start;
Josh Hollenbeck 1:807034181e02 1768 bucket++;
citrusbyte 0:01a2f8de46c8 1769 }
citrusbyte 0:01a2f8de46c8 1770 }
Josh Hollenbeck 1:807034181e02 1771
citrusbyte 0:01a2f8de46c8 1772 if (size == pool->content_pool_size) {
citrusbyte 0:01a2f8de46c8 1773 return;
citrusbyte 0:01a2f8de46c8 1774 }
Josh Hollenbeck 1:807034181e02 1775
Josh Hollenbeck 1:807034181e02 1776 uint8_t *buffer = (uint8_t *)malloc(size);
Josh Hollenbeck 1:807034181e02 1777 uint8_t *p = buffer;
citrusbyte 0:01a2f8de46c8 1778 for (i = 0; i < JSONLITE_TOKEN_POOL_FRONT; i++) {
Josh Hollenbeck 1:807034181e02 1779 bucket = pool->blocks[i].buckets;
Josh Hollenbeck 1:807034181e02 1780 while (bucket->start != NULL) {
Josh Hollenbeck 1:807034181e02 1781 size_t length = bucket->end - bucket->start;
Josh Hollenbeck 1:807034181e02 1782 memcpy(p, bucket->start, length); // LCOV_EXCL_LINE
Josh Hollenbeck 1:807034181e02 1783 bucket->start = p;
Josh Hollenbeck 1:807034181e02 1784 bucket->end = p + length;
citrusbyte 0:01a2f8de46c8 1785 p += length;
Josh Hollenbeck 1:807034181e02 1786 bucket++;
citrusbyte 0:01a2f8de46c8 1787 }
citrusbyte 0:01a2f8de46c8 1788 }
Josh Hollenbeck 1:807034181e02 1789
citrusbyte 0:01a2f8de46c8 1790 free(pool->content_pool);
citrusbyte 0:01a2f8de46c8 1791 pool->content_pool = buffer;
citrusbyte 0:01a2f8de46c8 1792 pool->content_pool_size = size;
citrusbyte 0:01a2f8de46c8 1793 }
citrusbyte 0:01a2f8de46c8 1794
citrusbyte 0:01a2f8de46c8 1795 void jsonlite_token_pool_release(jsonlite_token_pool pool) {
Josh Hollenbeck 1:807034181e02 1796 int i;
citrusbyte 0:01a2f8de46c8 1797 for (i = 0; i < JSONLITE_TOKEN_POOL_FRONT; i++) {
Josh Hollenbeck 1:807034181e02 1798 jsonlite_token_bucket *bucket = pool->blocks[i].buckets;
Josh Hollenbeck 1:807034181e02 1799 if (bucket->start == NULL) {
citrusbyte 0:01a2f8de46c8 1800 continue;
citrusbyte 0:01a2f8de46c8 1801 }
Josh Hollenbeck 1:807034181e02 1802
citrusbyte 0:01a2f8de46c8 1803 if (pool->release_fn != NULL) {
Josh Hollenbeck 1:807034181e02 1804 for (; bucket->start != NULL; bucket++) {
Josh Hollenbeck 1:807034181e02 1805 pool->release_fn((void *)bucket->value);
citrusbyte 0:01a2f8de46c8 1806 }
citrusbyte 0:01a2f8de46c8 1807 }
citrusbyte 0:01a2f8de46c8 1808
Josh Hollenbeck 1:807034181e02 1809 free(pool->blocks[i].buckets);
citrusbyte 0:01a2f8de46c8 1810 }
Josh Hollenbeck 1:807034181e02 1811
citrusbyte 0:01a2f8de46c8 1812 free(pool->content_pool);
citrusbyte 0:01a2f8de46c8 1813 free(pool);
citrusbyte 0:01a2f8de46c8 1814 }
citrusbyte 0:01a2f8de46c8 1815
citrusbyte 0:01a2f8de46c8 1816 jsonlite_token_bucket* jsonlite_token_pool_get_bucket(jsonlite_token_pool pool, jsonlite_token *token) {
Josh Hollenbeck 1:807034181e02 1817 ptrdiff_t length = token->end - token->start;
Josh Hollenbeck 1:807034181e02 1818 ptrdiff_t hash = jsonlite_hash(token->start, (size_t)length);
Josh Hollenbeck 1:807034181e02 1819 ptrdiff_t index = hash & JSONLITE_TOKEN_POOL_FRONT_MASK;
Josh Hollenbeck 1:807034181e02 1820 size_t count = 0;
Josh Hollenbeck 1:807034181e02 1821 jsonlite_token_bucket *bucket = pool->blocks[index].buckets;
Josh Hollenbeck 1:807034181e02 1822 for (; bucket->start != NULL; count++, bucket++) {
citrusbyte 0:01a2f8de46c8 1823 if (bucket->hash != hash) {
citrusbyte 0:01a2f8de46c8 1824 continue;
citrusbyte 0:01a2f8de46c8 1825 }
Josh Hollenbeck 1:807034181e02 1826
citrusbyte 0:01a2f8de46c8 1827 if (length != bucket->end - bucket->start) {
citrusbyte 0:01a2f8de46c8 1828 continue;
citrusbyte 0:01a2f8de46c8 1829 }
Josh Hollenbeck 1:807034181e02 1830
Josh Hollenbeck 1:807034181e02 1831 if (memcmp(token->start, bucket->start, (size_t)length) == 0) {
citrusbyte 0:01a2f8de46c8 1832 return bucket;
citrusbyte 0:01a2f8de46c8 1833 }
citrusbyte 0:01a2f8de46c8 1834 }
citrusbyte 0:01a2f8de46c8 1835
Josh Hollenbeck 1:807034181e02 1836 size_t capacity = pool->blocks[index].capacity;
Josh Hollenbeck 1:807034181e02 1837 if (count + 1 >= capacity) {
citrusbyte 0:01a2f8de46c8 1838 jsonlite_extend_capacity(pool, index);
citrusbyte 0:01a2f8de46c8 1839 }
Josh Hollenbeck 1:807034181e02 1840
Josh Hollenbeck 1:807034181e02 1841 bucket = pool->blocks[index].buckets + count;
citrusbyte 0:01a2f8de46c8 1842 bucket->hash = hash;
citrusbyte 0:01a2f8de46c8 1843 bucket->start = token->start;
citrusbyte 0:01a2f8de46c8 1844 bucket->end = token->end;
citrusbyte 0:01a2f8de46c8 1845 bucket->value = NULL;
Josh Hollenbeck 1:807034181e02 1846 bucket[1].start = NULL;
citrusbyte 0:01a2f8de46c8 1847 return bucket;
citrusbyte 0:01a2f8de46c8 1848 }
citrusbyte 0:01a2f8de46c8 1849
Josh Hollenbeck 1:807034181e02 1850 static void jsonlite_extend_capacity(jsonlite_token_pool pool, ptrdiff_t index) {
Josh Hollenbeck 1:807034181e02 1851 size_t capacity = pool->blocks[index].capacity;
citrusbyte 0:01a2f8de46c8 1852 if (capacity == 0) {
citrusbyte 0:01a2f8de46c8 1853 capacity = 0x10;
citrusbyte 0:01a2f8de46c8 1854 }
Josh Hollenbeck 1:807034181e02 1855
citrusbyte 0:01a2f8de46c8 1856 size_t size = capacity * sizeof(jsonlite_token_bucket);
Josh Hollenbeck 1:807034181e02 1857 jsonlite_token_bucket *buckets = pool->blocks[index].buckets;
Josh Hollenbeck 1:807034181e02 1858 jsonlite_token_bucket *extended = (jsonlite_token_bucket *)malloc(2 * size);
Josh Hollenbeck 1:807034181e02 1859
Josh Hollenbeck 1:807034181e02 1860 if (buckets->start != NULL) {
Josh Hollenbeck 1:807034181e02 1861 memcpy(extended, buckets, size); // LCOV_EXCL_LINE
Josh Hollenbeck 1:807034181e02 1862 free(buckets);
citrusbyte 0:01a2f8de46c8 1863 }
citrusbyte 0:01a2f8de46c8 1864
Josh Hollenbeck 1:807034181e02 1865 pool->blocks[index].buckets = extended;
Josh Hollenbeck 1:807034181e02 1866 pool->blocks[index].capacity = 2 * capacity;
citrusbyte 0:01a2f8de46c8 1867 }
citrusbyte 0:01a2f8de46c8 1868
citrusbyte 0:01a2f8de46c8 1869 // Used MurmurHash2 function by Austin Appleby
citrusbyte 0:01a2f8de46c8 1870 // http://code.google.com/p/smhasher/ revision 147
citrusbyte 0:01a2f8de46c8 1871
citrusbyte 0:01a2f8de46c8 1872 //-----------------------------------------------------------------------------
citrusbyte 0:01a2f8de46c8 1873 // MurmurHash2 was written by Austin Appleby, and is placed in the public
citrusbyte 0:01a2f8de46c8 1874 // domain. The author hereby disclaims copyright to this source code.
citrusbyte 0:01a2f8de46c8 1875
citrusbyte 0:01a2f8de46c8 1876 // Note - This code makes a few assumptions about how your machine behaves -
citrusbyte 0:01a2f8de46c8 1877
citrusbyte 0:01a2f8de46c8 1878 // 1. We can read a 4-byte value from any address without crashing
citrusbyte 0:01a2f8de46c8 1879 // 2. sizeof(int) == 4
citrusbyte 0:01a2f8de46c8 1880
citrusbyte 0:01a2f8de46c8 1881 // And it has a few limitations -
citrusbyte 0:01a2f8de46c8 1882
citrusbyte 0:01a2f8de46c8 1883 // 1. It will not work incrementally.
citrusbyte 0:01a2f8de46c8 1884 // 2. It will not produce the same results on little-endian and big-endian
citrusbyte 0:01a2f8de46c8 1885 // machines.
citrusbyte 0:01a2f8de46c8 1886
Josh Hollenbeck 1:807034181e02 1887 static uint32_t MurmurHash2(const void * key, size_t len)
citrusbyte 0:01a2f8de46c8 1888 {
citrusbyte 0:01a2f8de46c8 1889 // 'm' and 'r' are mixing constants generated offline.
citrusbyte 0:01a2f8de46c8 1890 // They're not really 'magic', they just happen to work well.
Josh Hollenbeck 1:807034181e02 1891
citrusbyte 0:01a2f8de46c8 1892 const uint32_t m = 0x5bd1e995;
citrusbyte 0:01a2f8de46c8 1893 const int r = 24;
Josh Hollenbeck 1:807034181e02 1894
citrusbyte 0:01a2f8de46c8 1895 // Initialize the hash to a 'random' value
Josh Hollenbeck 1:807034181e02 1896
Josh Hollenbeck 1:807034181e02 1897 uint32_t h = (uint32_t)len;
Josh Hollenbeck 1:807034181e02 1898
citrusbyte 0:01a2f8de46c8 1899 // Mix 4 bytes at a time into the hash
Josh Hollenbeck 1:807034181e02 1900
citrusbyte 0:01a2f8de46c8 1901 const unsigned char * data = (const unsigned char *)key;
Josh Hollenbeck 1:807034181e02 1902
citrusbyte 0:01a2f8de46c8 1903 while(len >= 4)
citrusbyte 0:01a2f8de46c8 1904 {
citrusbyte 0:01a2f8de46c8 1905 uint32_t k = *(uint32_t*)data;
Josh Hollenbeck 1:807034181e02 1906
citrusbyte 0:01a2f8de46c8 1907 k *= m;
citrusbyte 0:01a2f8de46c8 1908 k ^= k >> r;
citrusbyte 0:01a2f8de46c8 1909 k *= m;
Josh Hollenbeck 1:807034181e02 1910
citrusbyte 0:01a2f8de46c8 1911 h *= m;
citrusbyte 0:01a2f8de46c8 1912 h ^= k;
Josh Hollenbeck 1:807034181e02 1913
citrusbyte 0:01a2f8de46c8 1914 data += 4;
citrusbyte 0:01a2f8de46c8 1915 len -= 4;
citrusbyte 0:01a2f8de46c8 1916 }
Josh Hollenbeck 1:807034181e02 1917
citrusbyte 0:01a2f8de46c8 1918 // Handle the last few bytes of the input array
Josh Hollenbeck 1:807034181e02 1919
citrusbyte 0:01a2f8de46c8 1920 switch(len)
citrusbyte 0:01a2f8de46c8 1921 {
citrusbyte 0:01a2f8de46c8 1922 case 3: h ^= data[2] << 16;
citrusbyte 0:01a2f8de46c8 1923 case 2: h ^= data[1] << 8;
citrusbyte 0:01a2f8de46c8 1924 case 1: h ^= data[0];
citrusbyte 0:01a2f8de46c8 1925 h *= m;
citrusbyte 0:01a2f8de46c8 1926 };
Josh Hollenbeck 1:807034181e02 1927
citrusbyte 0:01a2f8de46c8 1928 // Do a few final mixes of the hash to ensure the last few
citrusbyte 0:01a2f8de46c8 1929 // bytes are well-incorporated.
Josh Hollenbeck 1:807034181e02 1930
citrusbyte 0:01a2f8de46c8 1931 h ^= h >> 13;
citrusbyte 0:01a2f8de46c8 1932 h *= m;
citrusbyte 0:01a2f8de46c8 1933 h ^= h >> 15;
Josh Hollenbeck 1:807034181e02 1934
citrusbyte 0:01a2f8de46c8 1935 return h;
citrusbyte 0:01a2f8de46c8 1936 }
citrusbyte 0:01a2f8de46c8 1937
citrusbyte 0:01a2f8de46c8 1938 //-----------------------------------------------------------------------------
citrusbyte 0:01a2f8de46c8 1939
citrusbyte 0:01a2f8de46c8 1940 static uint32_t jsonlite_hash(const uint8_t *data, size_t len) {
Josh Hollenbeck 1:807034181e02 1941 return MurmurHash2(data, len);
Josh Hollenbeck 1:807034181e02 1942 }