summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/mfluadir/otfcc/dep/extern/json-builder.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/web2c/mfluadir/otfcc/dep/extern/json-builder.c')
-rw-r--r--Build/source/texk/web2c/mfluadir/otfcc/dep/extern/json-builder.c889
1 files changed, 889 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/mfluadir/otfcc/dep/extern/json-builder.c b/Build/source/texk/web2c/mfluadir/otfcc/dep/extern/json-builder.c
new file mode 100644
index 00000000000..9e36667bafd
--- /dev/null
+++ b/Build/source/texk/web2c/mfluadir/otfcc/dep/extern/json-builder.c
@@ -0,0 +1,889 @@
+
+/* vim: set et ts=3 sw=3 sts=3 ft=c:
+ *
+ * Copyright (C) 2014 James McLaughlin. All rights reserved.
+ * https://github.com/udp/json-builder
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "json-builder.h"
+#include "emyg-dtoa/emyg-dtoa.h"
+
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+#include <math.h>
+
+#ifdef _MSC_VER
+#define snprintf _snprintf
+#endif
+
+const static json_serialize_opts default_opts = {
+ json_serialize_mode_single_line, 0, 3 /* indent_size */
+};
+
+typedef struct json_builder_value {
+ json_value value;
+
+ int is_builder_value;
+
+ size_t additional_length_allocated;
+ size_t length_iterated;
+
+} json_builder_value;
+
+static int builderize(json_value *value) {
+ if (((json_builder_value *)value)->is_builder_value) return 1;
+
+ if (value->type == json_object) {
+ unsigned int i;
+
+ /* Values straight out of the parser have the names of object entries
+ * allocated in the same allocation as the values array itself. This is
+ * not desirable when manipulating values because the names would be easy
+ * to clobber.
+ */
+ for (i = 0; i < value->u.object.length; ++i) {
+ json_char *name_copy;
+ json_object_entry *entry = &value->u.object.values[i];
+
+ if (!(name_copy = (json_char *)malloc((entry->name_length + 1) * sizeof(json_char)))) return 0;
+
+ memcpy(name_copy, entry->name, entry->name_length + 1);
+ entry->name = name_copy;
+ }
+ }
+
+ ((json_builder_value *)value)->is_builder_value = 1;
+
+ return 1;
+}
+
+const size_t json_builder_extra = sizeof(json_builder_value) - sizeof(json_value);
+
+/* These flags are set up from the opts before serializing to make the
+ * serializer conditions simpler.
+ */
+const int f_spaces_around_brackets = (1 << 0);
+const int f_spaces_after_commas = (1 << 1);
+const int f_spaces_after_colons = (1 << 2);
+const int f_tabs = (1 << 3);
+
+static int get_serialize_flags(json_serialize_opts opts) {
+ int flags = 0;
+
+ if (opts.mode == json_serialize_mode_packed) return 0;
+
+ if (opts.mode == json_serialize_mode_multiline) {
+ if (opts.opts & json_serialize_opt_use_tabs) flags |= f_tabs;
+ } else {
+ if (!(opts.opts & json_serialize_opt_pack_brackets)) flags |= f_spaces_around_brackets;
+
+ if (!(opts.opts & json_serialize_opt_no_space_after_comma)) flags |= f_spaces_after_commas;
+ }
+
+ if (!(opts.opts & json_serialize_opt_no_space_after_colon)) flags |= f_spaces_after_colons;
+
+ return flags;
+}
+
+json_value *json_array_new(size_t length) {
+ json_value *value = (json_value *)calloc(1, sizeof(json_builder_value));
+
+ if (!value) return NULL;
+
+ ((json_builder_value *)value)->is_builder_value = 1;
+
+ value->type = json_array;
+
+ if (!(value->u.array.values = (json_value **)malloc(length * sizeof(json_value *)))) {
+ free(value);
+ return NULL;
+ }
+
+ ((json_builder_value *)value)->additional_length_allocated = length;
+
+ return value;
+}
+
+json_value *json_array_push(json_value *array, json_value *value) {
+ assert(array->type == json_array);
+
+ if (!builderize(array) || !builderize(value)) return NULL;
+
+ if (((json_builder_value *)array)->additional_length_allocated > 0) {
+ --((json_builder_value *)array)->additional_length_allocated;
+ } else {
+ json_value **values_new =
+ (json_value **)realloc(array->u.array.values, sizeof(json_value *) * (array->u.array.length + 1));
+
+ if (!values_new) return NULL;
+
+ array->u.array.values = values_new;
+ }
+
+ array->u.array.values[array->u.array.length] = value;
+ ++array->u.array.length;
+
+ value->parent = array;
+
+ return value;
+}
+
+json_value *json_object_new(size_t length) {
+ json_value *value = (json_value *)calloc(1, sizeof(json_builder_value));
+
+ if (!value) return NULL;
+
+ ((json_builder_value *)value)->is_builder_value = 1;
+
+ value->type = json_object;
+
+ if (!(value->u.object.values = (json_object_entry *)calloc(length, sizeof(*value->u.object.values)))) {
+ free(value);
+ return NULL;
+ }
+
+ ((json_builder_value *)value)->additional_length_allocated = length;
+
+ return value;
+}
+
+json_value *json_object_push(json_value *object, const json_char *name, json_value *value) {
+ return json_object_push_length(object, strlen(name), name, value);
+}
+
+json_value *json_object_push_length(json_value *object, unsigned int name_length, const json_char *name,
+ json_value *value) {
+ json_char *name_copy;
+
+ assert(object->type == json_object);
+
+ if (!(name_copy = (json_char *)malloc((name_length + 1) * sizeof(json_char)))) return NULL;
+
+ memcpy(name_copy, name, name_length * sizeof(json_char));
+ name_copy[name_length] = 0;
+
+ if (!json_object_push_nocopy(object, name_length, name_copy, value)) {
+ free(name_copy);
+ return NULL;
+ }
+
+ return value;
+}
+
+json_value *json_object_push_nocopy(json_value *object, unsigned int name_length, json_char *name, json_value *value) {
+ json_object_entry *entry;
+
+ assert(object->type == json_object);
+
+ if (!builderize(object) || !builderize(value)) return NULL;
+
+ if (((json_builder_value *)object)->additional_length_allocated > 0) {
+ --((json_builder_value *)object)->additional_length_allocated;
+ } else {
+ json_object_entry *values_new = (json_object_entry *)realloc(
+ object->u.object.values, sizeof(*object->u.object.values) * (object->u.object.length + 1));
+
+ if (!values_new) return NULL;
+
+ object->u.object.values = values_new;
+ }
+
+ entry = object->u.object.values + object->u.object.length;
+
+ entry->name_length = name_length;
+ entry->name = name;
+ entry->value = value;
+
+ ++object->u.object.length;
+
+ value->parent = object;
+
+ return value;
+}
+
+json_value *json_string_new(const json_char *buf) {
+ return json_string_new_length(strlen(buf), buf);
+}
+
+json_value *json_string_new_length(unsigned int length, const json_char *buf) {
+ json_value *value;
+ json_char *copy = (json_char *)malloc((length + 1) * sizeof(json_char));
+
+ if (!copy) return NULL;
+
+ memcpy(copy, buf, length * sizeof(json_char));
+ copy[length] = 0;
+
+ if (!(value = json_string_new_nocopy(length, copy))) {
+ free(copy);
+ return NULL;
+ }
+
+ return value;
+}
+
+json_value *json_string_new_nocopy(unsigned int length, json_char *buf) {
+ json_value *value = (json_value *)calloc(1, sizeof(json_builder_value));
+
+ if (!value) return NULL;
+
+ ((json_builder_value *)value)->is_builder_value = 1;
+
+ value->type = json_string;
+ value->u.string.length = length;
+ value->u.string.ptr = buf;
+
+ return value;
+}
+
+json_value *json_integer_new(json_int_t integer) {
+ json_value *value = (json_value *)calloc(1, sizeof(json_builder_value));
+
+ if (!value) return NULL;
+
+ ((json_builder_value *)value)->is_builder_value = 1;
+
+ value->type = json_integer;
+ value->u.integer = integer;
+
+ return value;
+}
+
+json_value *json_double_new(double dbl) {
+ json_value *value = (json_value *)calloc(1, sizeof(json_builder_value));
+
+ if (!value) return NULL;
+
+ ((json_builder_value *)value)->is_builder_value = 1;
+
+ value->type = json_double;
+ value->u.dbl = dbl;
+
+ return value;
+}
+
+json_value *json_boolean_new(int b) {
+ json_value *value = (json_value *)calloc(1, sizeof(json_builder_value));
+
+ if (!value) return NULL;
+
+ ((json_builder_value *)value)->is_builder_value = 1;
+
+ value->type = json_boolean;
+ value->u.boolean = b;
+
+ return value;
+}
+
+json_value *json_null_new(void) {
+ json_value *value = (json_value *)calloc(1, sizeof(json_builder_value));
+
+ if (!value) return NULL;
+
+ ((json_builder_value *)value)->is_builder_value = 1;
+
+ value->type = json_null;
+
+ return value;
+}
+
+void json_object_sort(json_value *object, json_value *proto) {
+ unsigned int i, out_index = 0;
+
+ if (!builderize(object)) return; /* TODO error */
+
+ assert(object->type == json_object);
+ assert(proto->type == json_object);
+
+ for (i = 0; i < proto->u.object.length; ++i) {
+ unsigned int j;
+ json_object_entry proto_entry = proto->u.object.values[i];
+
+ for (j = 0; j < object->u.object.length; ++j) {
+ json_object_entry entry = object->u.object.values[j];
+
+ if (entry.name_length != proto_entry.name_length) continue;
+
+ if (memcmp(entry.name, proto_entry.name, entry.name_length) != 0) continue;
+
+ object->u.object.values[j] = object->u.object.values[out_index];
+ object->u.object.values[out_index] = entry;
+
+ ++out_index;
+ }
+ }
+}
+
+json_value *json_object_merge(json_value *objectA, json_value *objectB) {
+ unsigned int i;
+
+ assert(objectA->type == json_object);
+ assert(objectB->type == json_object);
+ assert(objectA != objectB);
+
+ if (!builderize(objectA) || !builderize(objectB)) return NULL;
+
+ if (objectB->u.object.length <= ((json_builder_value *)objectA)->additional_length_allocated) {
+ ((json_builder_value *)objectA)->additional_length_allocated -= objectB->u.object.length;
+ } else {
+ json_object_entry *values_new;
+
+ unsigned int alloc = objectA->u.object.length + ((json_builder_value *)objectA)->additional_length_allocated +
+ objectB->u.object.length;
+
+ if (!(values_new = (json_object_entry *)realloc(objectA->u.object.values, sizeof(json_object_entry) * alloc))) {
+ return NULL;
+ }
+
+ objectA->u.object.values = values_new;
+ }
+
+ for (i = 0; i < objectB->u.object.length; ++i) {
+ json_object_entry *entry = &objectA->u.object.values[objectA->u.object.length + i];
+
+ *entry = objectB->u.object.values[i];
+ entry->value->parent = objectA;
+ }
+
+ objectA->u.object.length += objectB->u.object.length;
+
+ free(objectB->u.object.values);
+ free(objectB);
+
+ return objectA;
+}
+
+static size_t measure_string(unsigned int length, const json_char *str) {
+ unsigned int i;
+ size_t measured_length = 0;
+
+ for (i = 0; i < length; ++i) {
+ json_char c = str[i];
+
+ switch (c) {
+ case 0:
+ case 0xb:
+ measured_length += 6;
+ break;
+ case '"':
+ case '\\':
+ case '\b':
+ case '\f':
+ case '\n':
+ case '\r':
+ case '\t':
+
+ measured_length += 2;
+ break;
+
+ default:
+
+ ++measured_length;
+ break;
+ };
+ };
+
+ return measured_length;
+}
+
+#define PRINT_ESCAPED(c) \
+ do { \
+ *buf++ = '\\'; \
+ *buf++ = (c); \
+ } while (0);
+
+static size_t serialize_string(json_char *buf, unsigned int length, const json_char *str) {
+ json_char *orig_buf = buf;
+ unsigned int i;
+
+ for (i = 0; i < length; ++i) {
+ json_char c = str[i];
+
+ switch (c) {
+ case 0:
+ *buf++ = '\\';
+ *buf++ = 'u';
+ *buf++ = '0';
+ *buf++ = '0';
+ *buf++ = '0';
+ *buf++ = '0';
+ continue;
+ case '"':
+ PRINT_ESCAPED('\"');
+ continue;
+ case '\\':
+ PRINT_ESCAPED('\\');
+ continue;
+ case '\b':
+ PRINT_ESCAPED('b');
+ continue;
+ case '\f':
+ PRINT_ESCAPED('f');
+ continue;
+ case '\n':
+ PRINT_ESCAPED('n');
+ continue;
+ case '\r':
+ PRINT_ESCAPED('r');
+ continue;
+ case '\t':
+ PRINT_ESCAPED('t');
+ continue;
+ case 0xb:
+ *buf++ = '\\';
+ *buf++ = 'u';
+ *buf++ = '0';
+ *buf++ = '0';
+ *buf++ = '0';
+ *buf++ = 'b';
+ continue;
+
+ default:
+
+ *buf++ = c;
+ break;
+ };
+ };
+
+ return buf - orig_buf;
+}
+
+size_t json_measure(json_value *value) {
+ return json_measure_ex(value, default_opts);
+}
+
+#define MEASURE_NEWLINE() \
+ do { \
+ ++newlines; \
+ indents += depth; \
+ } while (0);
+
+size_t json_measure_ex(json_value *value, json_serialize_opts opts) {
+ size_t total = 1; /* null terminator */
+ size_t newlines = 0;
+ size_t depth = 0;
+ size_t indents = 0;
+ int flags;
+ int bracket_size, comma_size, colon_size;
+
+ flags = get_serialize_flags(opts);
+
+ /* to reduce branching
+ */
+ bracket_size = flags & f_spaces_around_brackets ? 2 : 1;
+ comma_size = flags & f_spaces_after_commas ? 2 : 1;
+ colon_size = flags & f_spaces_after_colons ? 2 : 1;
+
+ while (value) {
+ json_int_t integer;
+ json_object_entry *entry;
+
+ switch (value->type) {
+ case json_array:
+
+ if (((json_builder_value *)value)->length_iterated == 0) {
+ if (value->u.array.length == 0) {
+ total += 2; /* `[]` */
+ break;
+ }
+
+ total += bracket_size; /* `[` */
+
+ ++depth;
+ MEASURE_NEWLINE(); /* \n after [ */
+ }
+
+ if (((json_builder_value *)value)->length_iterated == value->u.array.length) {
+ --depth;
+ MEASURE_NEWLINE();
+ total += bracket_size; /* `]` */
+
+ ((json_builder_value *)value)->length_iterated = 0;
+ break;
+ }
+
+ if (((json_builder_value *)value)->length_iterated > 0) {
+ total += comma_size; /* `, ` */
+
+ MEASURE_NEWLINE();
+ }
+
+ ((json_builder_value *)value)->length_iterated++;
+ value = value->u.array.values[((json_builder_value *)value)->length_iterated - 1];
+ continue;
+
+ case json_object:
+
+ if (((json_builder_value *)value)->length_iterated == 0) {
+ if (value->u.object.length == 0) {
+ total += 2; /* `{}` */
+ break;
+ }
+
+ total += bracket_size; /* `{` */
+
+ ++depth;
+ MEASURE_NEWLINE(); /* \n after { */
+ }
+
+ if (((json_builder_value *)value)->length_iterated == value->u.object.length) {
+ --depth;
+ MEASURE_NEWLINE();
+ total += bracket_size; /* `}` */
+
+ ((json_builder_value *)value)->length_iterated = 0;
+ break;
+ }
+
+ if (((json_builder_value *)value)->length_iterated > 0) {
+ total += comma_size; /* `, ` */
+ MEASURE_NEWLINE();
+ }
+
+ entry = value->u.object.values + (((json_builder_value *)value)->length_iterated++);
+
+ total += 2 + colon_size; /* `"": ` */
+ total += measure_string(entry->name_length, entry->name);
+
+ value = entry->value;
+ continue;
+#ifdef CARYLL_USE_PRE_SERIALIZED
+ case json_pre_serialized:
+
+ total += value->u.string.length;
+ break;
+#endif
+ case json_string:
+ total += 2; /* `""` */
+ total += measure_string(value->u.string.length, value->u.string.ptr);
+ break;
+
+ case json_integer:
+
+ integer = value->u.integer;
+
+ if (integer < 0) {
+ total += 1; /* `-` */
+ integer = -integer;
+ }
+
+ ++total; /* first digit */
+
+ while (integer >= 10) {
+ ++total; /* another digit */
+ integer /= 10;
+ }
+
+ break;
+
+ case json_double: {
+ char buffer[256];
+ emyg_dtoa(value->u.dbl, buffer);
+ total += strlen(buffer);
+ break;
+ }
+
+ case json_boolean:
+
+ total += value->u.boolean ? 4 : /* `true` */
+ 5; /* `false` */
+
+ break;
+
+ case json_null:
+
+ total += 4; /* `null` */
+ break;
+
+ default:
+ break;
+ };
+
+ value = value->parent;
+ }
+
+ if (opts.mode == json_serialize_mode_multiline) {
+ total += newlines * (((opts.opts & json_serialize_opt_CRLF) ? 2 : 1) + opts.indent_size);
+ total += indents * opts.indent_size;
+ }
+
+ return total;
+}
+
+void json_serialize(json_char *buf, json_value *value) {
+ json_serialize_ex(buf, value, default_opts);
+}
+
+#define PRINT_NEWLINE() \
+ do { \
+ if (opts.mode == json_serialize_mode_multiline) { \
+ if (opts.opts & json_serialize_opt_CRLF) *buf++ = '\r'; \
+ *buf++ = '\n'; \
+ for (i = 0; i < indent; ++i) \
+ *buf++ = indent_char; \
+ } \
+ } while (0);
+
+#define PRINT_OPENING_BRACKET(c) \
+ do { \
+ *buf++ = (c); \
+ if (flags & f_spaces_around_brackets) *buf++ = ' '; \
+ } while (0);
+
+#define PRINT_CLOSING_BRACKET(c) \
+ do { \
+ if (flags & f_spaces_around_brackets) *buf++ = ' '; \
+ *buf++ = (c); \
+ } while (0);
+
+void json_serialize_ex(json_char *buf, json_value *value, json_serialize_opts opts) {
+ json_int_t integer, orig_integer;
+ json_object_entry *entry;
+ json_char *ptr;
+ int indent = 0;
+ char indent_char;
+ int i;
+ int flags;
+
+ flags = get_serialize_flags(opts);
+
+ indent_char = flags & f_tabs ? '\t' : ' ';
+
+ while (value) {
+ switch (value->type) {
+ case json_array:
+
+ if (((json_builder_value *)value)->length_iterated == 0) {
+ if (value->u.array.length == 0) {
+ *buf++ = '[';
+ *buf++ = ']';
+
+ break;
+ }
+
+ PRINT_OPENING_BRACKET('[');
+
+ indent += opts.indent_size;
+ PRINT_NEWLINE();
+ }
+
+ if (((json_builder_value *)value)->length_iterated == value->u.array.length) {
+ indent -= opts.indent_size;
+ PRINT_NEWLINE();
+ PRINT_CLOSING_BRACKET(']');
+
+ ((json_builder_value *)value)->length_iterated = 0;
+ break;
+ }
+
+ if (((json_builder_value *)value)->length_iterated > 0) {
+ *buf++ = ',';
+
+ if (flags & f_spaces_after_commas) *buf++ = ' ';
+
+ PRINT_NEWLINE();
+ }
+
+ ((json_builder_value *)value)->length_iterated++;
+ value = value->u.array.values[((json_builder_value *)value)->length_iterated - 1];
+ continue;
+
+ case json_object:
+
+ if (((json_builder_value *)value)->length_iterated == 0) {
+ if (value->u.object.length == 0) {
+ *buf++ = '{';
+ *buf++ = '}';
+
+ break;
+ }
+
+ PRINT_OPENING_BRACKET('{');
+
+ indent += opts.indent_size;
+ PRINT_NEWLINE();
+ }
+
+ if (((json_builder_value *)value)->length_iterated == value->u.object.length) {
+ indent -= opts.indent_size;
+ PRINT_NEWLINE();
+ PRINT_CLOSING_BRACKET('}');
+
+ ((json_builder_value *)value)->length_iterated = 0;
+ break;
+ }
+
+ if (((json_builder_value *)value)->length_iterated > 0) {
+ *buf++ = ',';
+
+ if (flags & f_spaces_after_commas) *buf++ = ' ';
+
+ PRINT_NEWLINE();
+ }
+
+ entry = value->u.object.values + (((json_builder_value *)value)->length_iterated++);
+
+ *buf++ = '\"';
+ buf += serialize_string(buf, entry->name_length, entry->name);
+ *buf++ = '\"';
+ *buf++ = ':';
+
+ if (flags & f_spaces_after_colons) *buf++ = ' ';
+
+ value = entry->value;
+ continue;
+#ifdef CARYLL_USE_PRE_SERIALIZED
+ case json_pre_serialized:
+ memcpy(buf, value->u.string.ptr, value->u.string.length);
+ buf += value->u.string.length;
+ break;
+#endif
+ case json_string:
+
+ *buf++ = '\"';
+ buf += serialize_string(buf, value->u.string.length, value->u.string.ptr);
+ *buf++ = '\"';
+ break;
+
+ case json_integer:
+
+ integer = value->u.integer;
+
+ if (integer < 0) {
+ *buf++ = '-';
+ integer = -integer;
+ }
+
+ orig_integer = integer;
+
+ ++buf;
+
+ while (integer >= 10) {
+ ++buf;
+ integer /= 10;
+ }
+
+ integer = orig_integer;
+ ptr = buf;
+
+ do {
+ *--ptr = "0123456789"[integer % 10];
+ } while ((integer /= 10) > 0);
+
+ break;
+
+ case json_double: {
+ char tmp[256];
+ emyg_dtoa(value->u.dbl, tmp);
+ memcpy(buf, tmp, strlen(tmp));
+ buf += strlen(tmp);
+ break;
+ }
+
+ case json_boolean:
+
+ if (value->u.boolean) {
+ memcpy(buf, "true", 4);
+ buf += 4;
+ } else {
+ memcpy(buf, "false", 5);
+ buf += 5;
+ }
+
+ break;
+
+ case json_null:
+
+ memcpy(buf, "null", 4);
+ buf += 4;
+ break;
+
+ default:
+ break;
+ };
+
+ value = value->parent;
+ }
+
+ *buf = 0;
+}
+
+void json_builder_free(json_value *value) {
+ json_value *cur_value;
+
+ if (!value) return;
+
+ value->parent = 0;
+
+ while (value) {
+ switch (value->type) {
+ case json_array:
+
+ if (!value->u.array.length) {
+ free(value->u.array.values);
+ break;
+ }
+
+ value = value->u.array.values[--value->u.array.length];
+ continue;
+
+ case json_object:
+
+ if (!value->u.object.length) {
+ free(value->u.object.values);
+ break;
+ }
+
+ --value->u.object.length;
+
+ if (((json_builder_value *)value)->is_builder_value) {
+ /* Names are allocated separately for builder values. In parser
+ * values, they are part of the same allocation as the values array
+ * itself.
+ */
+ free(value->u.object.values[value->u.object.length].name);
+ }
+
+ value = value->u.object.values[value->u.object.length].value;
+ continue;
+
+ case json_string:
+#ifdef CARYLL_USE_PRE_SERIALIZED
+ case json_pre_serialized:
+#endif
+ free(value->u.string.ptr);
+ break;
+
+ default:
+ break;
+ };
+
+ cur_value = value;
+ value = value->parent;
+ free(cur_value);
+ }
+}