aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external
diff options
context:
space:
mode:
authornalpp <nalpp@yandex-team.ru>2022-02-10 16:46:46 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:46:46 +0300
commit30d1ef3941e0dc835be7609de5ebee66958f215a (patch)
tree49e222ea1c5804306084bb3ae065bb702625360f /contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external
parent87f3eb38999df2d3c1cb77f8ffb9c52ec9c516fb (diff)
downloadydb-30d1ef3941e0dc835be7609de5ebee66958f215a.tar.gz
Restoring authorship annotation for <nalpp@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external')
-rw-r--r--contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external/cjson/cJSON.cpp5858
-rw-r--r--contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external/tinyxml2/tinyxml2.cpp5574
2 files changed, 5716 insertions, 5716 deletions
diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external/cjson/cJSON.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external/cjson/cJSON.cpp
index f7b1357d37..2525976334 100644
--- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external/cjson/cJSON.cpp
+++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external/cjson/cJSON.cpp
@@ -1,2334 +1,2334 @@
-/*
- Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
-*/
-
-/* cJSON */
-/* JSON parser in C. */
-
-/* disable warnings about old C89 functions in MSVC */
-#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER)
-#define _CRT_SECURE_NO_DEPRECATE
-#endif
-
-#ifdef __GNUC__
-#pragma GCC visibility push(default)
-#endif
-#if defined(_MSC_VER)
-#pragma warning (push)
-/* disable warning about single line comments in system headers */
-#pragma warning (disable : 4001)
-#endif
-
-#include <string.h>
-#include <stdio.h>
-#include <math.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <ctype.h>
-
-#ifdef ENABLE_LOCALES
-#include <locale.h>
-#endif
-
-#if defined(_MSC_VER)
-#pragma warning (pop)
-#endif
-#ifdef __GNUC__
-#pragma GCC visibility pop
-#endif
-
-#include <aws/core/external/cjson/cJSON.h>
-
-/* define our own boolean type */
-// #define true ((cJSON_bool)1)
-// #define false ((cJSON_bool)0)
-
-typedef struct {
- const unsigned char *json;
- size_t position;
-} error;
-static error global_error = { NULL, 0 };
-
-CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void)
-{
- return (const char*) (global_error.json + global_error.position);
-}
-
-CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) {
- if (!cJSON_IsString(item)) {
- return NULL;
- }
-
- return item->valuestring;
-}
-
-/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
-#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 7)
- #error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
-#endif
-
-CJSON_PUBLIC(const char*) cJSON_Version(void)
-{
- static char version[15];
- sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH);
-
- return version;
-}
-
-/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */
-static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2)
-{
- if ((string1 == NULL) || (string2 == NULL))
- {
- return 1;
- }
-
- if (string1 == string2)
- {
- return 0;
- }
-
- for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++)
- {
- if (*string1 == '\0')
- {
- return 0;
- }
- }
-
- return tolower(*string1) - tolower(*string2);
-}
-
-typedef struct internal_hooks
-{
- void *(*allocate)(size_t size);
- void (*deallocate)(void *pointer);
- void *(*reallocate)(void *pointer, size_t size);
-} internal_hooks;
-
-#if defined(_MSC_VER)
-/* work around MSVC error C2322: '...' address of dillimport '...' is not static */
-static void *internal_malloc(size_t size)
-{
- return malloc(size);
-}
-static void internal_free(void *pointer)
-{
- free(pointer);
-}
-static void *internal_realloc(void *pointer, size_t size)
-{
- return realloc(pointer, size);
-}
-#else
-#define internal_malloc malloc
-#define internal_free free
-#define internal_realloc realloc
-#endif
-
-static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc };
-
-static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks)
-{
- size_t length = 0;
- unsigned char *copy = NULL;
-
- if (string == NULL)
- {
- return NULL;
- }
-
- length = strlen((const char*)string) + sizeof("");
- copy = (unsigned char*)hooks->allocate(length);
- if (copy == NULL)
- {
- return NULL;
- }
- memcpy(copy, string, length);
-
- return copy;
-}
-
-CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks)
-{
- if (hooks == NULL)
- {
- /* Reset hooks */
- global_hooks.allocate = malloc;
- global_hooks.deallocate = free;
- global_hooks.reallocate = realloc;
- return;
- }
-
- global_hooks.allocate = malloc;
- if (hooks->malloc_fn != NULL)
- {
- global_hooks.allocate = hooks->malloc_fn;
- }
-
- global_hooks.deallocate = free;
- if (hooks->free_fn != NULL)
- {
- global_hooks.deallocate = hooks->free_fn;
- }
-
- /* use realloc only if both free and malloc are used */
- global_hooks.reallocate = NULL;
- if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free))
- {
- global_hooks.reallocate = realloc;
- }
-}
-
-/* Internal constructor. */
-static cJSON *cJSON_New_Item(const internal_hooks * const hooks)
-{
- cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON));
- if (node)
- {
- memset(node, '\0', sizeof(cJSON));
- }
-
- return node;
-}
-
-/* Delete a cJSON structure. */
-CJSON_PUBLIC(void) cJSON_Delete(cJSON *item)
-{
- cJSON *next = NULL;
- while (item != NULL)
- {
- next = item->next;
- if (!(item->type & cJSON_IsReference) && (item->child != NULL))
- {
- cJSON_Delete(item->child);
- }
- if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
- {
- global_hooks.deallocate(item->valuestring);
- }
- if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
- {
- global_hooks.deallocate(item->string);
- }
- global_hooks.deallocate(item);
- item = next;
- }
-}
-
-/* get the decimal point character of the current locale */
-static unsigned char get_decimal_point(void)
-{
-#ifdef ENABLE_LOCALES
- struct lconv *lconv = localeconv();
- return (unsigned char) lconv->decimal_point[0];
-#else
- return '.';
-#endif
-}
-
-typedef struct
-{
- const unsigned char *content;
- size_t length;
- size_t offset;
- size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */
- internal_hooks hooks;
-} parse_buffer;
-
-/* check if the given size is left to read in a given parse buffer (starting with 1) */
-#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))
-/* check if the buffer can be accessed at the given index (starting with 0) */
-#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
-#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
-/* get a pointer to the buffer at the position */
-#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
-
-/* Parse the input text to generate a number, and populate the result into item. */
-static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer)
-{
- double number = 0;
- unsigned char *after_end = NULL;
- unsigned char number_c_string[64];
- unsigned char decimal_point = get_decimal_point();
+/*
+ Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+/* cJSON */
+/* JSON parser in C. */
+
+/* disable warnings about old C89 functions in MSVC */
+#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER)
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+#ifdef __GNUC__
+#pragma GCC visibility push(default)
+#endif
+#if defined(_MSC_VER)
+#pragma warning (push)
+/* disable warning about single line comments in system headers */
+#pragma warning (disable : 4001)
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <ctype.h>
+
+#ifdef ENABLE_LOCALES
+#include <locale.h>
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning (pop)
+#endif
+#ifdef __GNUC__
+#pragma GCC visibility pop
+#endif
+
+#include <aws/core/external/cjson/cJSON.h>
+
+/* define our own boolean type */
+// #define true ((cJSON_bool)1)
+// #define false ((cJSON_bool)0)
+
+typedef struct {
+ const unsigned char *json;
+ size_t position;
+} error;
+static error global_error = { NULL, 0 };
+
+CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void)
+{
+ return (const char*) (global_error.json + global_error.position);
+}
+
+CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) {
+ if (!cJSON_IsString(item)) {
+ return NULL;
+ }
+
+ return item->valuestring;
+}
+
+/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
+#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 7)
+ #error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
+#endif
+
+CJSON_PUBLIC(const char*) cJSON_Version(void)
+{
+ static char version[15];
+ sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH);
+
+ return version;
+}
+
+/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */
+static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2)
+{
+ if ((string1 == NULL) || (string2 == NULL))
+ {
+ return 1;
+ }
+
+ if (string1 == string2)
+ {
+ return 0;
+ }
+
+ for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++)
+ {
+ if (*string1 == '\0')
+ {
+ return 0;
+ }
+ }
+
+ return tolower(*string1) - tolower(*string2);
+}
+
+typedef struct internal_hooks
+{
+ void *(*allocate)(size_t size);
+ void (*deallocate)(void *pointer);
+ void *(*reallocate)(void *pointer, size_t size);
+} internal_hooks;
+
+#if defined(_MSC_VER)
+/* work around MSVC error C2322: '...' address of dillimport '...' is not static */
+static void *internal_malloc(size_t size)
+{
+ return malloc(size);
+}
+static void internal_free(void *pointer)
+{
+ free(pointer);
+}
+static void *internal_realloc(void *pointer, size_t size)
+{
+ return realloc(pointer, size);
+}
+#else
+#define internal_malloc malloc
+#define internal_free free
+#define internal_realloc realloc
+#endif
+
+static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc };
+
+static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks)
+{
+ size_t length = 0;
+ unsigned char *copy = NULL;
+
+ if (string == NULL)
+ {
+ return NULL;
+ }
+
+ length = strlen((const char*)string) + sizeof("");
+ copy = (unsigned char*)hooks->allocate(length);
+ if (copy == NULL)
+ {
+ return NULL;
+ }
+ memcpy(copy, string, length);
+
+ return copy;
+}
+
+CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks)
+{
+ if (hooks == NULL)
+ {
+ /* Reset hooks */
+ global_hooks.allocate = malloc;
+ global_hooks.deallocate = free;
+ global_hooks.reallocate = realloc;
+ return;
+ }
+
+ global_hooks.allocate = malloc;
+ if (hooks->malloc_fn != NULL)
+ {
+ global_hooks.allocate = hooks->malloc_fn;
+ }
+
+ global_hooks.deallocate = free;
+ if (hooks->free_fn != NULL)
+ {
+ global_hooks.deallocate = hooks->free_fn;
+ }
+
+ /* use realloc only if both free and malloc are used */
+ global_hooks.reallocate = NULL;
+ if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free))
+ {
+ global_hooks.reallocate = realloc;
+ }
+}
+
+/* Internal constructor. */
+static cJSON *cJSON_New_Item(const internal_hooks * const hooks)
+{
+ cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON));
+ if (node)
+ {
+ memset(node, '\0', sizeof(cJSON));
+ }
+
+ return node;
+}
+
+/* Delete a cJSON structure. */
+CJSON_PUBLIC(void) cJSON_Delete(cJSON *item)
+{
+ cJSON *next = NULL;
+ while (item != NULL)
+ {
+ next = item->next;
+ if (!(item->type & cJSON_IsReference) && (item->child != NULL))
+ {
+ cJSON_Delete(item->child);
+ }
+ if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
+ {
+ global_hooks.deallocate(item->valuestring);
+ }
+ if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
+ {
+ global_hooks.deallocate(item->string);
+ }
+ global_hooks.deallocate(item);
+ item = next;
+ }
+}
+
+/* get the decimal point character of the current locale */
+static unsigned char get_decimal_point(void)
+{
+#ifdef ENABLE_LOCALES
+ struct lconv *lconv = localeconv();
+ return (unsigned char) lconv->decimal_point[0];
+#else
+ return '.';
+#endif
+}
+
+typedef struct
+{
+ const unsigned char *content;
+ size_t length;
+ size_t offset;
+ size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */
+ internal_hooks hooks;
+} parse_buffer;
+
+/* check if the given size is left to read in a given parse buffer (starting with 1) */
+#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))
+/* check if the buffer can be accessed at the given index (starting with 0) */
+#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
+#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
+/* get a pointer to the buffer at the position */
+#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
+
+/* Parse the input text to generate a number, and populate the result into item. */
+static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer)
+{
+ double number = 0;
+ unsigned char *after_end = NULL;
+ unsigned char number_c_string[64];
+ unsigned char decimal_point = get_decimal_point();
bool isInteger = true;
- size_t i = 0;
-
- if ((input_buffer == NULL) || (input_buffer->content == NULL))
- {
- return false;
- }
-
- /* copy the number into a temporary buffer and replace '.' with the decimal point
- * of the current locale (for strtod)
- * This also takes care of '\0' not necessarily being available for marking the end of the input */
- for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++)
- {
- switch (buffer_at_offset(input_buffer)[i])
- {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- case '+':
- case '-':
+ size_t i = 0;
+
+ if ((input_buffer == NULL) || (input_buffer->content == NULL))
+ {
+ return false;
+ }
+
+ /* copy the number into a temporary buffer and replace '.' with the decimal point
+ * of the current locale (for strtod)
+ * This also takes care of '\0' not necessarily being available for marking the end of the input */
+ for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++)
+ {
+ switch (buffer_at_offset(input_buffer)[i])
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '+':
+ case '-':
number_c_string[i] = buffer_at_offset(input_buffer)[i];
break;
- case 'e':
- case 'E':
- number_c_string[i] = buffer_at_offset(input_buffer)[i];
+ case 'e':
+ case 'E':
+ number_c_string[i] = buffer_at_offset(input_buffer)[i];
isInteger = false;
- break;
-
- case '.':
- number_c_string[i] = decimal_point;
+ break;
+
+ case '.':
+ number_c_string[i] = decimal_point;
isInteger = false;
- break;
-
- default:
- goto loop_end;
- }
- }
-loop_end:
- number_c_string[i] = '\0';
-
- number = strtod((const char*)number_c_string, (char**)&after_end);
- if (number_c_string == after_end)
- {
- return false; /* parse_error */
- }
-
- item->valuedouble = number;
+ break;
+
+ default:
+ goto loop_end;
+ }
+ }
+loop_end:
+ number_c_string[i] = '\0';
+
+ number = strtod((const char*)number_c_string, (char**)&after_end);
+ if (number_c_string == after_end)
+ {
+ return false; /* parse_error */
+ }
+
+ item->valuedouble = number;
// For integer which is out of the range of [INT_MIN, INT_MAX], it may lose precision if we cast it to double.
// Instead, we keep the integer literal as a string.
if (isInteger && (number > INT_MAX || number < INT_MIN))
{
item->valuestring = (char*)cJSON_strdup(number_c_string, &global_hooks);
}
-
- /* use saturation in case of overflow */
- if (number >= INT_MAX)
- {
- item->valueint = INT_MAX;
- }
- else if (number <= INT_MIN)
- {
- item->valueint = INT_MIN;
- }
- else
- {
- item->valueint = (int)number;
- }
-
- item->type = cJSON_Number;
-
- input_buffer->offset += (size_t)(after_end - number_c_string);
- return true;
-}
-
-/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
-CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
-{
- if (number >= INT_MAX)
- {
- object->valueint = INT_MAX;
- }
- else if (number <= INT_MIN)
- {
- object->valueint = INT_MIN;
- }
- else
- {
- object->valueint = (int)number;
- }
-
- return object->valuedouble = number;
-}
-
-typedef struct
-{
- unsigned char *buffer;
- size_t length;
- size_t offset;
- size_t depth; /* current nesting depth (for formatted printing) */
- cJSON_bool noalloc;
- cJSON_bool format; /* is this print a formatted print */
- internal_hooks hooks;
-} printbuffer;
-
-/* realloc printbuffer if necessary to have at least "needed" bytes more */
-static unsigned char* ensure(printbuffer * const p, size_t needed)
-{
- unsigned char *newbuffer = NULL;
- size_t newsize = 0;
-
- if ((p == NULL) || (p->buffer == NULL))
- {
- return NULL;
- }
-
- if ((p->length > 0) && (p->offset >= p->length))
- {
- /* make sure that offset is valid */
- return NULL;
- }
-
- if (needed > INT_MAX)
- {
- /* sizes bigger than INT_MAX are currently not supported */
- return NULL;
- }
-
- needed += p->offset + 1;
- if (needed <= p->length)
- {
- return p->buffer + p->offset;
- }
-
- if (p->noalloc) {
- return NULL;
- }
-
- /* calculate new buffer size */
- if (needed > (INT_MAX / 2))
- {
- /* overflow of int, use INT_MAX if possible */
- if (needed <= INT_MAX)
- {
- newsize = INT_MAX;
- }
- else
- {
- return NULL;
- }
- }
- else
- {
- newsize = needed * 2;
- }
-
- if (p->hooks.reallocate != NULL)
- {
- /* reallocate with realloc if available */
- newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize);
- if (newbuffer == NULL)
- {
- p->hooks.deallocate(p->buffer);
- p->length = 0;
- p->buffer = NULL;
-
- return NULL;
- }
- }
- else
- {
- /* otherwise reallocate manually */
- newbuffer = (unsigned char*)p->hooks.allocate(newsize);
- if (!newbuffer)
- {
- p->hooks.deallocate(p->buffer);
- p->length = 0;
- p->buffer = NULL;
-
- return NULL;
- }
- if (newbuffer)
- {
- memcpy(newbuffer, p->buffer, p->offset + 1);
- }
- p->hooks.deallocate(p->buffer);
- }
- p->length = newsize;
- p->buffer = newbuffer;
-
- return newbuffer + p->offset;
-}
-
-/* calculate the new length of the string in a printbuffer and update the offset */
-static void update_offset(printbuffer * const buffer)
-{
- const unsigned char *buffer_pointer = NULL;
- if ((buffer == NULL) || (buffer->buffer == NULL))
- {
- return;
- }
- buffer_pointer = buffer->buffer + buffer->offset;
-
- buffer->offset += strlen((const char*)buffer_pointer);
-}
-
-/* Render the number nicely from the given item into a string. */
-static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
-{
- unsigned char *output_pointer = NULL;
- double d = item->valuedouble;
- int length = 0;
- size_t i = 0;
- unsigned char number_buffer[26]; /* temporary buffer to print the number into */
- unsigned char decimal_point = get_decimal_point();
- double test;
-
- if (output_buffer == NULL)
- {
- return false;
- }
-
+
+ /* use saturation in case of overflow */
+ if (number >= INT_MAX)
+ {
+ item->valueint = INT_MAX;
+ }
+ else if (number <= INT_MIN)
+ {
+ item->valueint = INT_MIN;
+ }
+ else
+ {
+ item->valueint = (int)number;
+ }
+
+ item->type = cJSON_Number;
+
+ input_buffer->offset += (size_t)(after_end - number_c_string);
+ return true;
+}
+
+/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
+CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
+{
+ if (number >= INT_MAX)
+ {
+ object->valueint = INT_MAX;
+ }
+ else if (number <= INT_MIN)
+ {
+ object->valueint = INT_MIN;
+ }
+ else
+ {
+ object->valueint = (int)number;
+ }
+
+ return object->valuedouble = number;
+}
+
+typedef struct
+{
+ unsigned char *buffer;
+ size_t length;
+ size_t offset;
+ size_t depth; /* current nesting depth (for formatted printing) */
+ cJSON_bool noalloc;
+ cJSON_bool format; /* is this print a formatted print */
+ internal_hooks hooks;
+} printbuffer;
+
+/* realloc printbuffer if necessary to have at least "needed" bytes more */
+static unsigned char* ensure(printbuffer * const p, size_t needed)
+{
+ unsigned char *newbuffer = NULL;
+ size_t newsize = 0;
+
+ if ((p == NULL) || (p->buffer == NULL))
+ {
+ return NULL;
+ }
+
+ if ((p->length > 0) && (p->offset >= p->length))
+ {
+ /* make sure that offset is valid */
+ return NULL;
+ }
+
+ if (needed > INT_MAX)
+ {
+ /* sizes bigger than INT_MAX are currently not supported */
+ return NULL;
+ }
+
+ needed += p->offset + 1;
+ if (needed <= p->length)
+ {
+ return p->buffer + p->offset;
+ }
+
+ if (p->noalloc) {
+ return NULL;
+ }
+
+ /* calculate new buffer size */
+ if (needed > (INT_MAX / 2))
+ {
+ /* overflow of int, use INT_MAX if possible */
+ if (needed <= INT_MAX)
+ {
+ newsize = INT_MAX;
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+ else
+ {
+ newsize = needed * 2;
+ }
+
+ if (p->hooks.reallocate != NULL)
+ {
+ /* reallocate with realloc if available */
+ newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize);
+ if (newbuffer == NULL)
+ {
+ p->hooks.deallocate(p->buffer);
+ p->length = 0;
+ p->buffer = NULL;
+
+ return NULL;
+ }
+ }
+ else
+ {
+ /* otherwise reallocate manually */
+ newbuffer = (unsigned char*)p->hooks.allocate(newsize);
+ if (!newbuffer)
+ {
+ p->hooks.deallocate(p->buffer);
+ p->length = 0;
+ p->buffer = NULL;
+
+ return NULL;
+ }
+ if (newbuffer)
+ {
+ memcpy(newbuffer, p->buffer, p->offset + 1);
+ }
+ p->hooks.deallocate(p->buffer);
+ }
+ p->length = newsize;
+ p->buffer = newbuffer;
+
+ return newbuffer + p->offset;
+}
+
+/* calculate the new length of the string in a printbuffer and update the offset */
+static void update_offset(printbuffer * const buffer)
+{
+ const unsigned char *buffer_pointer = NULL;
+ if ((buffer == NULL) || (buffer->buffer == NULL))
+ {
+ return;
+ }
+ buffer_pointer = buffer->buffer + buffer->offset;
+
+ buffer->offset += strlen((const char*)buffer_pointer);
+}
+
+/* Render the number nicely from the given item into a string. */
+static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
+{
+ unsigned char *output_pointer = NULL;
+ double d = item->valuedouble;
+ int length = 0;
+ size_t i = 0;
+ unsigned char number_buffer[26]; /* temporary buffer to print the number into */
+ unsigned char decimal_point = get_decimal_point();
+ double test;
+
+ if (output_buffer == NULL)
+ {
+ return false;
+ }
+
/* For integer which is out of the range of [INT_MIN, INT_MAX], valuestring is an integer literal. */
if (item->valuestring)
{
length = sprintf((char*)number_buffer, "%s", item->valuestring);
}
- /* This checks for NaN and Infinity */
+ /* This checks for NaN and Infinity */
else if ((d * 0) != 0)
- {
- length = sprintf((char*)number_buffer, "null");
- }
- else
- {
- /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
- length = sprintf((char*)number_buffer, "%1.15g", d);
-
- /* Check whether the original double can be recovered */
- if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != d))
- {
- /* If not, print with 17 decimal places of precision */
- length = sprintf((char*)number_buffer, "%1.17g", d);
- }
- }
-
+ {
+ length = sprintf((char*)number_buffer, "null");
+ }
+ else
+ {
+ /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
+ length = sprintf((char*)number_buffer, "%1.15g", d);
+
+ /* Check whether the original double can be recovered */
+ if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != d))
+ {
+ /* If not, print with 17 decimal places of precision */
+ length = sprintf((char*)number_buffer, "%1.17g", d);
+ }
+ }
+
/* sprintf failed or buffer overrun occurred */
- if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1)))
- {
- return false;
- }
-
- /* reserve appropriate space in the output */
- output_pointer = ensure(output_buffer, (size_t)length + sizeof(""));
- if (output_pointer == NULL)
- {
- return false;
- }
-
- /* copy the printed number to the output and replace locale
- * dependent decimal point with '.' */
- for (i = 0; i < ((size_t)length); i++)
- {
- if (number_buffer[i] == decimal_point)
- {
- output_pointer[i] = '.';
- continue;
- }
-
- output_pointer[i] = number_buffer[i];
- }
- output_pointer[i] = '\0';
-
- output_buffer->offset += (size_t)length;
-
- return true;
-}
-
-/* parse 4 digit hexadecimal number */
-static unsigned parse_hex4(const unsigned char * const input)
-{
- unsigned int h = 0;
- size_t i = 0;
-
- for (i = 0; i < 4; i++)
- {
- /* parse digit */
- if ((input[i] >= '0') && (input[i] <= '9'))
- {
- h += (unsigned int) input[i] - '0';
- }
- else if ((input[i] >= 'A') && (input[i] <= 'F'))
- {
- h += (unsigned int) 10 + input[i] - 'A';
- }
- else if ((input[i] >= 'a') && (input[i] <= 'f'))
- {
- h += (unsigned int) 10 + input[i] - 'a';
- }
- else /* invalid */
- {
- return 0;
- }
-
- if (i < 3)
- {
- /* shift left to make place for the next nibble */
- h = h << 4;
- }
- }
-
- return h;
-}
-
-/* converts a UTF-16 literal to UTF-8
- * A literal can be one or two sequences of the form \uXXXX */
-static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer)
-{
- long unsigned int codepoint = 0;
- unsigned int first_code = 0;
- const unsigned char *first_sequence = input_pointer;
- unsigned char utf8_length = 0;
- unsigned char utf8_position = 0;
- unsigned char sequence_length = 0;
- unsigned char first_byte_mark = 0;
-
- if ((input_end - first_sequence) < 6)
- {
- /* input ends unexpectedly */
- goto fail;
- }
-
- /* get the first utf16 sequence */
- first_code = parse_hex4(first_sequence + 2);
-
- /* check that the code is valid */
- if (((first_code >= 0xDC00) && (first_code <= 0xDFFF)))
- {
- goto fail;
- }
-
- /* UTF16 surrogate pair */
- if ((first_code >= 0xD800) && (first_code <= 0xDBFF))
- {
- const unsigned char *second_sequence = first_sequence + 6;
- unsigned int second_code = 0;
- sequence_length = 12; /* \uXXXX\uXXXX */
-
- if ((input_end - second_sequence) < 6)
- {
- /* input ends unexpectedly */
- goto fail;
- }
-
- if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u'))
- {
- /* missing second half of the surrogate pair */
- goto fail;
- }
-
- /* get the second utf16 sequence */
- second_code = parse_hex4(second_sequence + 2);
- /* check that the code is valid */
- if ((second_code < 0xDC00) || (second_code > 0xDFFF))
- {
- /* invalid second half of the surrogate pair */
- goto fail;
- }
-
-
- /* calculate the unicode codepoint from the surrogate pair */
- codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
- }
- else
- {
- sequence_length = 6; /* \uXXXX */
- codepoint = first_code;
- }
-
- /* encode as UTF-8
- * takes at maximum 4 bytes to encode:
- * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
- if (codepoint < 0x80)
- {
- /* normal ascii, encoding 0xxxxxxx */
- utf8_length = 1;
- }
- else if (codepoint < 0x800)
- {
- /* two bytes, encoding 110xxxxx 10xxxxxx */
- utf8_length = 2;
- first_byte_mark = 0xC0; /* 11000000 */
- }
- else if (codepoint < 0x10000)
- {
- /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
- utf8_length = 3;
- first_byte_mark = 0xE0; /* 11100000 */
- }
- else if (codepoint <= 0x10FFFF)
- {
- /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
- utf8_length = 4;
- first_byte_mark = 0xF0; /* 11110000 */
- }
- else
- {
- /* invalid unicode codepoint */
- goto fail;
- }
-
- /* encode as utf8 */
- for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--)
- {
- /* 10xxxxxx */
- (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
- codepoint >>= 6;
- }
- /* encode first byte */
- if (utf8_length > 1)
- {
- (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
- }
- else
- {
- (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
- }
-
- *output_pointer += utf8_length;
-
- return sequence_length;
-
-fail:
- return 0;
-}
-
-/* Parse the input text into an unescaped cinput, and populate item. */
-static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer)
-{
- const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
- const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
- unsigned char *output_pointer = NULL;
- unsigned char *output = NULL;
-
- /* not a string */
- if (buffer_at_offset(input_buffer)[0] != '\"')
- {
- goto fail;
- }
-
- {
- /* calculate approximate size of the output (overestimate) */
- size_t allocation_length = 0;
- size_t skipped_bytes = 0;
- while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"'))
- {
- /* is escape sequence */
- if (input_end[0] == '\\')
- {
- if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length)
- {
- /* prevent buffer overflow when last input character is a backslash */
- goto fail;
- }
- skipped_bytes++;
- input_end++;
- }
- input_end++;
- }
- if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"'))
- {
- goto fail; /* string ended unexpectedly */
- }
-
- /* This is at most how much we need for the output */
- allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
- output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof(""));
- if (output == NULL)
- {
- goto fail; /* allocation failure */
- }
- }
-
- output_pointer = output;
- /* loop through the string literal */
- while (input_pointer < input_end)
- {
- if (*input_pointer != '\\')
- {
- *output_pointer++ = *input_pointer++;
- }
- /* escape sequence */
- else
- {
- unsigned char sequence_length = 2;
- if ((input_end - input_pointer) < 1)
- {
- goto fail;
- }
-
- switch (input_pointer[1])
- {
- case 'b':
- *output_pointer++ = '\b';
- break;
- case 'f':
- *output_pointer++ = '\f';
- break;
- case 'n':
- *output_pointer++ = '\n';
- break;
- case 'r':
- *output_pointer++ = '\r';
- break;
- case 't':
- *output_pointer++ = '\t';
- break;
- case '\"':
- case '\\':
- case '/':
- *output_pointer++ = input_pointer[1];
- break;
-
- /* UTF-16 literal */
- case 'u':
- sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
- if (sequence_length == 0)
- {
- /* failed to convert UTF16-literal to UTF-8 */
- goto fail;
- }
- break;
-
- default:
- goto fail;
- }
- input_pointer += sequence_length;
- }
- }
-
- /* zero terminate the output */
- *output_pointer = '\0';
-
- item->type = cJSON_String;
- item->valuestring = (char*)output;
-
- input_buffer->offset = (size_t) (input_end - input_buffer->content);
- input_buffer->offset++;
-
- return true;
-
-fail:
- if (output != NULL)
- {
- input_buffer->hooks.deallocate(output);
- }
-
- if (input_pointer != NULL)
- {
- input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
- }
-
- return false;
-}
-
-/* Render the cstring provided to an escaped version that can be printed. */
-static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer)
-{
- const unsigned char *input_pointer = NULL;
- unsigned char *output = NULL;
- unsigned char *output_pointer = NULL;
- size_t output_length = 0;
- /* numbers of additional characters needed for escaping */
- size_t escape_characters = 0;
-
- if (output_buffer == NULL)
- {
- return false;
- }
-
- /* empty string */
- if (input == NULL)
- {
- output = ensure(output_buffer, sizeof("\"\""));
- if (output == NULL)
- {
- return false;
- }
- strcpy((char*)output, "\"\"");
-
- return true;
- }
-
- /* set "flag" to 1 if something needs to be escaped */
- for (input_pointer = input; *input_pointer; input_pointer++)
- {
- switch (*input_pointer)
- {
- case '\"':
- case '\\':
- case '\b':
- case '\f':
- case '\n':
- case '\r':
- case '\t':
- /* one character escape sequence */
- escape_characters++;
- break;
- default:
- if (*input_pointer < 32)
- {
- /* UTF-16 escape sequence uXXXX */
- escape_characters += 5;
- }
- break;
- }
- }
- output_length = (size_t)(input_pointer - input) + escape_characters;
-
- output = ensure(output_buffer, output_length + sizeof("\"\""));
- if (output == NULL)
- {
- return false;
- }
-
- /* no characters have to be escaped */
- if (escape_characters == 0)
- {
- output[0] = '\"';
- memcpy(output + 1, input, output_length);
- output[output_length + 1] = '\"';
- output[output_length + 2] = '\0';
-
- return true;
- }
-
- output[0] = '\"';
- output_pointer = output + 1;
- /* copy the string */
- for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++)
- {
- if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\'))
- {
- /* normal character, copy */
- *output_pointer = *input_pointer;
- }
- else
- {
- /* character needs to be escaped */
- *output_pointer++ = '\\';
- switch (*input_pointer)
- {
- case '\\':
- *output_pointer = '\\';
- break;
- case '\"':
- *output_pointer = '\"';
- break;
- case '\b':
- *output_pointer = 'b';
- break;
- case '\f':
- *output_pointer = 'f';
- break;
- case '\n':
- *output_pointer = 'n';
- break;
- case '\r':
- *output_pointer = 'r';
- break;
- case '\t':
- *output_pointer = 't';
- break;
- default:
- /* escape and print as unicode codepoint */
- sprintf((char*)output_pointer, "u%04x", *input_pointer);
- output_pointer += 4;
- break;
- }
- }
- }
- output[output_length + 1] = '\"';
- output[output_length + 2] = '\0';
-
- return true;
-}
-
-/* Invoke print_string_ptr (which is useful) on an item. */
-static cJSON_bool print_string(const cJSON * const item, printbuffer * const p)
-{
- return print_string_ptr((unsigned char*)item->valuestring, p);
-}
-
-/* Predeclare these prototypes. */
-static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer);
-static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer);
-static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer);
-static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer);
-static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer);
-static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer);
-
-/* Utility to jump whitespace and cr/lf */
-static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)
-{
- if ((buffer == NULL) || (buffer->content == NULL))
- {
- return NULL;
- }
-
- while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32))
- {
- buffer->offset++;
- }
-
- if (buffer->offset == buffer->length)
- {
- buffer->offset--;
- }
-
- return buffer;
-}
-
-/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
-static parse_buffer *skip_utf8_bom(parse_buffer * const buffer)
-{
- if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0))
- {
- return NULL;
- }
-
- if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0))
- {
- buffer->offset += 3;
- }
-
- return buffer;
-}
-
-/* Parse an object - create a new root, and populate. */
-CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)
-{
- parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
- cJSON *item = NULL;
-
- /* reset error position */
- global_error.json = NULL;
- global_error.position = 0;
-
- if (value == NULL)
- {
- goto fail;
- }
-
- buffer.content = (const unsigned char*)value;
- buffer.length = strlen((const char*)value) + sizeof("");
- buffer.offset = 0;
- buffer.hooks = global_hooks;
-
- item = cJSON_New_Item(&global_hooks);
- if (item == NULL) /* memory fail */
- {
- goto fail;
- }
-
- if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer))))
- {
- /* parse failure. ep is set. */
- goto fail;
- }
-
- /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
- if (require_null_terminated)
- {
- buffer_skip_whitespace(&buffer);
- if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0')
- {
- goto fail;
- }
- }
- if (return_parse_end)
- {
- *return_parse_end = (const char*)buffer_at_offset(&buffer);
- }
-
- return item;
-
-fail:
- if (item != NULL)
- {
- cJSON_Delete(item);
- }
-
- if (value != NULL)
- {
- error local_error;
- local_error.json = (const unsigned char*)value;
- local_error.position = 0;
-
- if (buffer.offset < buffer.length)
- {
- local_error.position = buffer.offset;
- }
- else if (buffer.length > 0)
- {
- local_error.position = buffer.length - 1;
- }
-
- if (return_parse_end != NULL)
- {
- *return_parse_end = (const char*)local_error.json + local_error.position;
- }
-
- global_error = local_error;
- }
-
- return NULL;
-}
-
-/* Default options for cJSON_Parse */
-CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
-{
- return cJSON_ParseWithOpts(value, 0, 0);
-}
-
-#define cjson_min(a, b) ((a < b) ? a : b)
-
-static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks)
-{
- static const size_t default_buffer_size = 256;
- printbuffer buffer[1];
- unsigned char *printed = NULL;
-
- memset(buffer, 0, sizeof(buffer));
-
- /* create buffer */
- buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size);
- buffer->length = default_buffer_size;
- buffer->format = format;
- buffer->hooks = *hooks;
- if (buffer->buffer == NULL)
- {
- goto fail;
- }
-
- /* print the value */
- if (!print_value(item, buffer))
- {
- goto fail;
- }
- update_offset(buffer);
-
- /* check if reallocate is available */
- if (hooks->reallocate != NULL)
- {
- printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1);
- if (printed == NULL) {
- goto fail;
- }
- buffer->buffer = NULL;
- }
- else /* otherwise copy the JSON over to a new buffer */
- {
- printed = (unsigned char*) hooks->allocate(buffer->offset + 1);
- if (printed == NULL)
- {
- goto fail;
- }
- memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1));
- printed[buffer->offset] = '\0'; /* just to be sure */
-
- /* free the buffer */
- hooks->deallocate(buffer->buffer);
- }
-
- return printed;
-
-fail:
- if (buffer->buffer != NULL)
- {
- hooks->deallocate(buffer->buffer);
- }
-
- if (printed != NULL)
- {
- hooks->deallocate(printed);
- }
-
- return NULL;
-}
-
-/* Render a cJSON item/entity/structure to text. */
-CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item)
-{
- return (char*)print(item, true, &global_hooks);
-}
-
-CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item)
-{
- return (char*)print(item, false, &global_hooks);
-}
-
-CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)
-{
- printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
-
- if (prebuffer < 0)
- {
- return NULL;
- }
-
- p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer);
- if (!p.buffer)
- {
- return NULL;
- }
-
- p.length = (size_t)prebuffer;
- p.offset = 0;
- p.noalloc = false;
- p.format = fmt;
- p.hooks = global_hooks;
-
- if (!print_value(item, &p))
- {
- global_hooks.deallocate(p.buffer);
- return NULL;
- }
-
- return (char*)p.buffer;
-}
-
-CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt)
-{
- printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
-
- if ((len < 0) || (buf == NULL))
- {
- return false;
- }
-
- p.buffer = (unsigned char*)buf;
- p.length = (size_t)len;
- p.offset = 0;
- p.noalloc = true;
- p.format = fmt;
- p.hooks = global_hooks;
-
- return print_value(item, &p);
-}
-
-/* Parser core - when encountering text, process appropriately. */
-static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer)
-{
- if ((input_buffer == NULL) || (input_buffer->content == NULL))
- {
- return false; /* no input */
- }
-
- /* parse the different types of values */
- /* null */
- if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0))
- {
- item->type = cJSON_NULL;
- input_buffer->offset += 4;
- return true;
- }
- /* false */
- if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0))
- {
- item->type = cJSON_False;
- input_buffer->offset += 5;
- return true;
- }
- /* true */
- if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0))
- {
- item->type = cJSON_True;
- item->valueint = 1;
- input_buffer->offset += 4;
- return true;
- }
- /* string */
- if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"'))
- {
- return parse_string(item, input_buffer);
- }
- /* number */
- if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9'))))
- {
- return parse_number(item, input_buffer);
- }
- /* array */
- if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '['))
- {
- return parse_array(item, input_buffer);
- }
- /* object */
- if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{'))
- {
- return parse_object(item, input_buffer);
- }
-
- return false;
-}
-
-/* Render a value to text. */
-static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer)
-{
- unsigned char *output = NULL;
-
- if ((item == NULL) || (output_buffer == NULL))
- {
- return false;
- }
-
- switch ((item->type) & 0xFF)
- {
- case cJSON_NULL:
- output = ensure(output_buffer, 5);
- if (output == NULL)
- {
- return false;
- }
- strcpy((char*)output, "null");
- return true;
-
- case cJSON_False:
- output = ensure(output_buffer, 6);
- if (output == NULL)
- {
- return false;
- }
- strcpy((char*)output, "false");
- return true;
-
- case cJSON_True:
- output = ensure(output_buffer, 5);
- if (output == NULL)
- {
- return false;
- }
- strcpy((char*)output, "true");
- return true;
-
- case cJSON_Number:
- return print_number(item, output_buffer);
-
- case cJSON_Raw:
- {
- size_t raw_length = 0;
- if (item->valuestring == NULL)
- {
- return false;
- }
-
- raw_length = strlen(item->valuestring) + sizeof("");
- output = ensure(output_buffer, raw_length);
- if (output == NULL)
- {
- return false;
- }
- memcpy(output, item->valuestring, raw_length);
- return true;
- }
-
- case cJSON_String:
- return print_string(item, output_buffer);
-
- case cJSON_Array:
- return print_array(item, output_buffer);
-
- case cJSON_Object:
- return print_object(item, output_buffer);
-
- default:
- return false;
- }
-}
-
-/* Build an array from input text. */
-static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer)
-{
- cJSON *head = NULL; /* head of the linked list */
- cJSON *current_item = NULL;
-
- if (input_buffer->depth >= CJSON_NESTING_LIMIT)
- {
- return false; /* to deeply nested */
- }
- input_buffer->depth++;
-
- if (buffer_at_offset(input_buffer)[0] != '[')
- {
- /* not an array */
- goto fail;
- }
-
- input_buffer->offset++;
- buffer_skip_whitespace(input_buffer);
- if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']'))
- {
- /* empty array */
- goto success;
- }
-
- /* check if we skipped to the end of the buffer */
- if (cannot_access_at_index(input_buffer, 0))
- {
- input_buffer->offset--;
- goto fail;
- }
-
- /* step back to character in front of the first element */
- input_buffer->offset--;
- /* loop through the comma separated array elements */
- do
- {
- /* allocate next item */
- cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
- if (new_item == NULL)
- {
- goto fail; /* allocation failure */
- }
-
- /* attach next item to list */
- if (head == NULL)
- {
- /* start the linked list */
- current_item = head = new_item;
- }
- else
- {
- /* add to the end and advance */
- current_item->next = new_item;
- new_item->prev = current_item;
- current_item = new_item;
- }
-
- /* parse next value */
- input_buffer->offset++;
- buffer_skip_whitespace(input_buffer);
- if (!parse_value(current_item, input_buffer))
- {
- goto fail; /* failed to parse value */
- }
- buffer_skip_whitespace(input_buffer);
- }
- while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
-
- if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']')
- {
- goto fail; /* expected end of array */
- }
-
-success:
- input_buffer->depth--;
-
- item->type = cJSON_Array;
- item->child = head;
-
- input_buffer->offset++;
-
- return true;
-
-fail:
- if (head != NULL)
- {
- cJSON_Delete(head);
- }
-
- return false;
-}
-
-/* Render an array to text */
-static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer)
-{
- unsigned char *output_pointer = NULL;
- size_t length = 0;
- cJSON *current_element = item->child;
-
- if (output_buffer == NULL)
- {
- return false;
- }
-
- /* Compose the output array. */
- /* opening square bracket */
- output_pointer = ensure(output_buffer, 1);
- if (output_pointer == NULL)
- {
- return false;
- }
-
- *output_pointer = '[';
- output_buffer->offset++;
- output_buffer->depth++;
-
- while (current_element != NULL)
- {
- if (!print_value(current_element, output_buffer))
- {
- return false;
- }
- update_offset(output_buffer);
- if (current_element->next)
- {
- length = (size_t) (output_buffer->format ? 2 : 1);
- output_pointer = ensure(output_buffer, length + 1);
- if (output_pointer == NULL)
- {
- return false;
- }
- *output_pointer++ = ',';
- if(output_buffer->format)
- {
- *output_pointer++ = ' ';
- }
- *output_pointer = '\0';
- output_buffer->offset += length;
- }
- current_element = current_element->next;
- }
-
- output_pointer = ensure(output_buffer, 2);
- if (output_pointer == NULL)
- {
- return false;
- }
- *output_pointer++ = ']';
- *output_pointer = '\0';
- output_buffer->depth--;
-
- return true;
-}
-
-/* Build an object from the text. */
-static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer)
-{
- cJSON *head = NULL; /* linked list head */
- cJSON *current_item = NULL;
-
- if (input_buffer->depth >= CJSON_NESTING_LIMIT)
- {
- return false; /* to deeply nested */
- }
- input_buffer->depth++;
-
- if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{'))
- {
- goto fail; /* not an object */
- }
-
- input_buffer->offset++;
- buffer_skip_whitespace(input_buffer);
- if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}'))
- {
- goto success; /* empty object */
- }
-
- /* check if we skipped to the end of the buffer */
- if (cannot_access_at_index(input_buffer, 0))
- {
- input_buffer->offset--;
- goto fail;
- }
-
- /* step back to character in front of the first element */
- input_buffer->offset--;
- /* loop through the comma separated array elements */
- do
- {
- /* allocate next item */
- cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
- if (new_item == NULL)
- {
- goto fail; /* allocation failure */
- }
-
- /* attach next item to list */
- if (head == NULL)
- {
- /* start the linked list */
- current_item = head = new_item;
- }
- else
- {
- /* add to the end and advance */
- current_item->next = new_item;
- new_item->prev = current_item;
- current_item = new_item;
- }
-
- /* parse the name of the child */
- input_buffer->offset++;
- buffer_skip_whitespace(input_buffer);
- if (!parse_string(current_item, input_buffer))
- {
+ if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1)))
+ {
+ return false;
+ }
+
+ /* reserve appropriate space in the output */
+ output_pointer = ensure(output_buffer, (size_t)length + sizeof(""));
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+
+ /* copy the printed number to the output and replace locale
+ * dependent decimal point with '.' */
+ for (i = 0; i < ((size_t)length); i++)
+ {
+ if (number_buffer[i] == decimal_point)
+ {
+ output_pointer[i] = '.';
+ continue;
+ }
+
+ output_pointer[i] = number_buffer[i];
+ }
+ output_pointer[i] = '\0';
+
+ output_buffer->offset += (size_t)length;
+
+ return true;
+}
+
+/* parse 4 digit hexadecimal number */
+static unsigned parse_hex4(const unsigned char * const input)
+{
+ unsigned int h = 0;
+ size_t i = 0;
+
+ for (i = 0; i < 4; i++)
+ {
+ /* parse digit */
+ if ((input[i] >= '0') && (input[i] <= '9'))
+ {
+ h += (unsigned int) input[i] - '0';
+ }
+ else if ((input[i] >= 'A') && (input[i] <= 'F'))
+ {
+ h += (unsigned int) 10 + input[i] - 'A';
+ }
+ else if ((input[i] >= 'a') && (input[i] <= 'f'))
+ {
+ h += (unsigned int) 10 + input[i] - 'a';
+ }
+ else /* invalid */
+ {
+ return 0;
+ }
+
+ if (i < 3)
+ {
+ /* shift left to make place for the next nibble */
+ h = h << 4;
+ }
+ }
+
+ return h;
+}
+
+/* converts a UTF-16 literal to UTF-8
+ * A literal can be one or two sequences of the form \uXXXX */
+static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer)
+{
+ long unsigned int codepoint = 0;
+ unsigned int first_code = 0;
+ const unsigned char *first_sequence = input_pointer;
+ unsigned char utf8_length = 0;
+ unsigned char utf8_position = 0;
+ unsigned char sequence_length = 0;
+ unsigned char first_byte_mark = 0;
+
+ if ((input_end - first_sequence) < 6)
+ {
+ /* input ends unexpectedly */
+ goto fail;
+ }
+
+ /* get the first utf16 sequence */
+ first_code = parse_hex4(first_sequence + 2);
+
+ /* check that the code is valid */
+ if (((first_code >= 0xDC00) && (first_code <= 0xDFFF)))
+ {
+ goto fail;
+ }
+
+ /* UTF16 surrogate pair */
+ if ((first_code >= 0xD800) && (first_code <= 0xDBFF))
+ {
+ const unsigned char *second_sequence = first_sequence + 6;
+ unsigned int second_code = 0;
+ sequence_length = 12; /* \uXXXX\uXXXX */
+
+ if ((input_end - second_sequence) < 6)
+ {
+ /* input ends unexpectedly */
+ goto fail;
+ }
+
+ if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u'))
+ {
+ /* missing second half of the surrogate pair */
+ goto fail;
+ }
+
+ /* get the second utf16 sequence */
+ second_code = parse_hex4(second_sequence + 2);
+ /* check that the code is valid */
+ if ((second_code < 0xDC00) || (second_code > 0xDFFF))
+ {
+ /* invalid second half of the surrogate pair */
+ goto fail;
+ }
+
+
+ /* calculate the unicode codepoint from the surrogate pair */
+ codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
+ }
+ else
+ {
+ sequence_length = 6; /* \uXXXX */
+ codepoint = first_code;
+ }
+
+ /* encode as UTF-8
+ * takes at maximum 4 bytes to encode:
+ * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
+ if (codepoint < 0x80)
+ {
+ /* normal ascii, encoding 0xxxxxxx */
+ utf8_length = 1;
+ }
+ else if (codepoint < 0x800)
+ {
+ /* two bytes, encoding 110xxxxx 10xxxxxx */
+ utf8_length = 2;
+ first_byte_mark = 0xC0; /* 11000000 */
+ }
+ else if (codepoint < 0x10000)
+ {
+ /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
+ utf8_length = 3;
+ first_byte_mark = 0xE0; /* 11100000 */
+ }
+ else if (codepoint <= 0x10FFFF)
+ {
+ /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
+ utf8_length = 4;
+ first_byte_mark = 0xF0; /* 11110000 */
+ }
+ else
+ {
+ /* invalid unicode codepoint */
+ goto fail;
+ }
+
+ /* encode as utf8 */
+ for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--)
+ {
+ /* 10xxxxxx */
+ (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
+ codepoint >>= 6;
+ }
+ /* encode first byte */
+ if (utf8_length > 1)
+ {
+ (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
+ }
+ else
+ {
+ (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
+ }
+
+ *output_pointer += utf8_length;
+
+ return sequence_length;
+
+fail:
+ return 0;
+}
+
+/* Parse the input text into an unescaped cinput, and populate item. */
+static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer)
+{
+ const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
+ const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
+ unsigned char *output_pointer = NULL;
+ unsigned char *output = NULL;
+
+ /* not a string */
+ if (buffer_at_offset(input_buffer)[0] != '\"')
+ {
+ goto fail;
+ }
+
+ {
+ /* calculate approximate size of the output (overestimate) */
+ size_t allocation_length = 0;
+ size_t skipped_bytes = 0;
+ while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"'))
+ {
+ /* is escape sequence */
+ if (input_end[0] == '\\')
+ {
+ if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length)
+ {
+ /* prevent buffer overflow when last input character is a backslash */
+ goto fail;
+ }
+ skipped_bytes++;
+ input_end++;
+ }
+ input_end++;
+ }
+ if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"'))
+ {
+ goto fail; /* string ended unexpectedly */
+ }
+
+ /* This is at most how much we need for the output */
+ allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
+ output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof(""));
+ if (output == NULL)
+ {
+ goto fail; /* allocation failure */
+ }
+ }
+
+ output_pointer = output;
+ /* loop through the string literal */
+ while (input_pointer < input_end)
+ {
+ if (*input_pointer != '\\')
+ {
+ *output_pointer++ = *input_pointer++;
+ }
+ /* escape sequence */
+ else
+ {
+ unsigned char sequence_length = 2;
+ if ((input_end - input_pointer) < 1)
+ {
+ goto fail;
+ }
+
+ switch (input_pointer[1])
+ {
+ case 'b':
+ *output_pointer++ = '\b';
+ break;
+ case 'f':
+ *output_pointer++ = '\f';
+ break;
+ case 'n':
+ *output_pointer++ = '\n';
+ break;
+ case 'r':
+ *output_pointer++ = '\r';
+ break;
+ case 't':
+ *output_pointer++ = '\t';
+ break;
+ case '\"':
+ case '\\':
+ case '/':
+ *output_pointer++ = input_pointer[1];
+ break;
+
+ /* UTF-16 literal */
+ case 'u':
+ sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
+ if (sequence_length == 0)
+ {
+ /* failed to convert UTF16-literal to UTF-8 */
+ goto fail;
+ }
+ break;
+
+ default:
+ goto fail;
+ }
+ input_pointer += sequence_length;
+ }
+ }
+
+ /* zero terminate the output */
+ *output_pointer = '\0';
+
+ item->type = cJSON_String;
+ item->valuestring = (char*)output;
+
+ input_buffer->offset = (size_t) (input_end - input_buffer->content);
+ input_buffer->offset++;
+
+ return true;
+
+fail:
+ if (output != NULL)
+ {
+ input_buffer->hooks.deallocate(output);
+ }
+
+ if (input_pointer != NULL)
+ {
+ input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
+ }
+
+ return false;
+}
+
+/* Render the cstring provided to an escaped version that can be printed. */
+static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer)
+{
+ const unsigned char *input_pointer = NULL;
+ unsigned char *output = NULL;
+ unsigned char *output_pointer = NULL;
+ size_t output_length = 0;
+ /* numbers of additional characters needed for escaping */
+ size_t escape_characters = 0;
+
+ if (output_buffer == NULL)
+ {
+ return false;
+ }
+
+ /* empty string */
+ if (input == NULL)
+ {
+ output = ensure(output_buffer, sizeof("\"\""));
+ if (output == NULL)
+ {
+ return false;
+ }
+ strcpy((char*)output, "\"\"");
+
+ return true;
+ }
+
+ /* set "flag" to 1 if something needs to be escaped */
+ for (input_pointer = input; *input_pointer; input_pointer++)
+ {
+ switch (*input_pointer)
+ {
+ case '\"':
+ case '\\':
+ case '\b':
+ case '\f':
+ case '\n':
+ case '\r':
+ case '\t':
+ /* one character escape sequence */
+ escape_characters++;
+ break;
+ default:
+ if (*input_pointer < 32)
+ {
+ /* UTF-16 escape sequence uXXXX */
+ escape_characters += 5;
+ }
+ break;
+ }
+ }
+ output_length = (size_t)(input_pointer - input) + escape_characters;
+
+ output = ensure(output_buffer, output_length + sizeof("\"\""));
+ if (output == NULL)
+ {
+ return false;
+ }
+
+ /* no characters have to be escaped */
+ if (escape_characters == 0)
+ {
+ output[0] = '\"';
+ memcpy(output + 1, input, output_length);
+ output[output_length + 1] = '\"';
+ output[output_length + 2] = '\0';
+
+ return true;
+ }
+
+ output[0] = '\"';
+ output_pointer = output + 1;
+ /* copy the string */
+ for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++)
+ {
+ if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\'))
+ {
+ /* normal character, copy */
+ *output_pointer = *input_pointer;
+ }
+ else
+ {
+ /* character needs to be escaped */
+ *output_pointer++ = '\\';
+ switch (*input_pointer)
+ {
+ case '\\':
+ *output_pointer = '\\';
+ break;
+ case '\"':
+ *output_pointer = '\"';
+ break;
+ case '\b':
+ *output_pointer = 'b';
+ break;
+ case '\f':
+ *output_pointer = 'f';
+ break;
+ case '\n':
+ *output_pointer = 'n';
+ break;
+ case '\r':
+ *output_pointer = 'r';
+ break;
+ case '\t':
+ *output_pointer = 't';
+ break;
+ default:
+ /* escape and print as unicode codepoint */
+ sprintf((char*)output_pointer, "u%04x", *input_pointer);
+ output_pointer += 4;
+ break;
+ }
+ }
+ }
+ output[output_length + 1] = '\"';
+ output[output_length + 2] = '\0';
+
+ return true;
+}
+
+/* Invoke print_string_ptr (which is useful) on an item. */
+static cJSON_bool print_string(const cJSON * const item, printbuffer * const p)
+{
+ return print_string_ptr((unsigned char*)item->valuestring, p);
+}
+
+/* Predeclare these prototypes. */
+static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer);
+static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer);
+static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer);
+static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer);
+static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer);
+static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer);
+
+/* Utility to jump whitespace and cr/lf */
+static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)
+{
+ if ((buffer == NULL) || (buffer->content == NULL))
+ {
+ return NULL;
+ }
+
+ while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32))
+ {
+ buffer->offset++;
+ }
+
+ if (buffer->offset == buffer->length)
+ {
+ buffer->offset--;
+ }
+
+ return buffer;
+}
+
+/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
+static parse_buffer *skip_utf8_bom(parse_buffer * const buffer)
+{
+ if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0))
+ {
+ return NULL;
+ }
+
+ if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0))
+ {
+ buffer->offset += 3;
+ }
+
+ return buffer;
+}
+
+/* Parse an object - create a new root, and populate. */
+CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)
+{
+ parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
+ cJSON *item = NULL;
+
+ /* reset error position */
+ global_error.json = NULL;
+ global_error.position = 0;
+
+ if (value == NULL)
+ {
+ goto fail;
+ }
+
+ buffer.content = (const unsigned char*)value;
+ buffer.length = strlen((const char*)value) + sizeof("");
+ buffer.offset = 0;
+ buffer.hooks = global_hooks;
+
+ item = cJSON_New_Item(&global_hooks);
+ if (item == NULL) /* memory fail */
+ {
+ goto fail;
+ }
+
+ if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer))))
+ {
+ /* parse failure. ep is set. */
+ goto fail;
+ }
+
+ /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
+ if (require_null_terminated)
+ {
+ buffer_skip_whitespace(&buffer);
+ if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0')
+ {
+ goto fail;
+ }
+ }
+ if (return_parse_end)
+ {
+ *return_parse_end = (const char*)buffer_at_offset(&buffer);
+ }
+
+ return item;
+
+fail:
+ if (item != NULL)
+ {
+ cJSON_Delete(item);
+ }
+
+ if (value != NULL)
+ {
+ error local_error;
+ local_error.json = (const unsigned char*)value;
+ local_error.position = 0;
+
+ if (buffer.offset < buffer.length)
+ {
+ local_error.position = buffer.offset;
+ }
+ else if (buffer.length > 0)
+ {
+ local_error.position = buffer.length - 1;
+ }
+
+ if (return_parse_end != NULL)
+ {
+ *return_parse_end = (const char*)local_error.json + local_error.position;
+ }
+
+ global_error = local_error;
+ }
+
+ return NULL;
+}
+
+/* Default options for cJSON_Parse */
+CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
+{
+ return cJSON_ParseWithOpts(value, 0, 0);
+}
+
+#define cjson_min(a, b) ((a < b) ? a : b)
+
+static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks)
+{
+ static const size_t default_buffer_size = 256;
+ printbuffer buffer[1];
+ unsigned char *printed = NULL;
+
+ memset(buffer, 0, sizeof(buffer));
+
+ /* create buffer */
+ buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size);
+ buffer->length = default_buffer_size;
+ buffer->format = format;
+ buffer->hooks = *hooks;
+ if (buffer->buffer == NULL)
+ {
+ goto fail;
+ }
+
+ /* print the value */
+ if (!print_value(item, buffer))
+ {
+ goto fail;
+ }
+ update_offset(buffer);
+
+ /* check if reallocate is available */
+ if (hooks->reallocate != NULL)
+ {
+ printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1);
+ if (printed == NULL) {
+ goto fail;
+ }
+ buffer->buffer = NULL;
+ }
+ else /* otherwise copy the JSON over to a new buffer */
+ {
+ printed = (unsigned char*) hooks->allocate(buffer->offset + 1);
+ if (printed == NULL)
+ {
+ goto fail;
+ }
+ memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1));
+ printed[buffer->offset] = '\0'; /* just to be sure */
+
+ /* free the buffer */
+ hooks->deallocate(buffer->buffer);
+ }
+
+ return printed;
+
+fail:
+ if (buffer->buffer != NULL)
+ {
+ hooks->deallocate(buffer->buffer);
+ }
+
+ if (printed != NULL)
+ {
+ hooks->deallocate(printed);
+ }
+
+ return NULL;
+}
+
+/* Render a cJSON item/entity/structure to text. */
+CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item)
+{
+ return (char*)print(item, true, &global_hooks);
+}
+
+CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item)
+{
+ return (char*)print(item, false, &global_hooks);
+}
+
+CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)
+{
+ printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
+
+ if (prebuffer < 0)
+ {
+ return NULL;
+ }
+
+ p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer);
+ if (!p.buffer)
+ {
+ return NULL;
+ }
+
+ p.length = (size_t)prebuffer;
+ p.offset = 0;
+ p.noalloc = false;
+ p.format = fmt;
+ p.hooks = global_hooks;
+
+ if (!print_value(item, &p))
+ {
+ global_hooks.deallocate(p.buffer);
+ return NULL;
+ }
+
+ return (char*)p.buffer;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt)
+{
+ printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
+
+ if ((len < 0) || (buf == NULL))
+ {
+ return false;
+ }
+
+ p.buffer = (unsigned char*)buf;
+ p.length = (size_t)len;
+ p.offset = 0;
+ p.noalloc = true;
+ p.format = fmt;
+ p.hooks = global_hooks;
+
+ return print_value(item, &p);
+}
+
+/* Parser core - when encountering text, process appropriately. */
+static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer)
+{
+ if ((input_buffer == NULL) || (input_buffer->content == NULL))
+ {
+ return false; /* no input */
+ }
+
+ /* parse the different types of values */
+ /* null */
+ if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0))
+ {
+ item->type = cJSON_NULL;
+ input_buffer->offset += 4;
+ return true;
+ }
+ /* false */
+ if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0))
+ {
+ item->type = cJSON_False;
+ input_buffer->offset += 5;
+ return true;
+ }
+ /* true */
+ if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0))
+ {
+ item->type = cJSON_True;
+ item->valueint = 1;
+ input_buffer->offset += 4;
+ return true;
+ }
+ /* string */
+ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"'))
+ {
+ return parse_string(item, input_buffer);
+ }
+ /* number */
+ if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9'))))
+ {
+ return parse_number(item, input_buffer);
+ }
+ /* array */
+ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '['))
+ {
+ return parse_array(item, input_buffer);
+ }
+ /* object */
+ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{'))
+ {
+ return parse_object(item, input_buffer);
+ }
+
+ return false;
+}
+
+/* Render a value to text. */
+static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer)
+{
+ unsigned char *output = NULL;
+
+ if ((item == NULL) || (output_buffer == NULL))
+ {
+ return false;
+ }
+
+ switch ((item->type) & 0xFF)
+ {
+ case cJSON_NULL:
+ output = ensure(output_buffer, 5);
+ if (output == NULL)
+ {
+ return false;
+ }
+ strcpy((char*)output, "null");
+ return true;
+
+ case cJSON_False:
+ output = ensure(output_buffer, 6);
+ if (output == NULL)
+ {
+ return false;
+ }
+ strcpy((char*)output, "false");
+ return true;
+
+ case cJSON_True:
+ output = ensure(output_buffer, 5);
+ if (output == NULL)
+ {
+ return false;
+ }
+ strcpy((char*)output, "true");
+ return true;
+
+ case cJSON_Number:
+ return print_number(item, output_buffer);
+
+ case cJSON_Raw:
+ {
+ size_t raw_length = 0;
+ if (item->valuestring == NULL)
+ {
+ return false;
+ }
+
+ raw_length = strlen(item->valuestring) + sizeof("");
+ output = ensure(output_buffer, raw_length);
+ if (output == NULL)
+ {
+ return false;
+ }
+ memcpy(output, item->valuestring, raw_length);
+ return true;
+ }
+
+ case cJSON_String:
+ return print_string(item, output_buffer);
+
+ case cJSON_Array:
+ return print_array(item, output_buffer);
+
+ case cJSON_Object:
+ return print_object(item, output_buffer);
+
+ default:
+ return false;
+ }
+}
+
+/* Build an array from input text. */
+static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer)
+{
+ cJSON *head = NULL; /* head of the linked list */
+ cJSON *current_item = NULL;
+
+ if (input_buffer->depth >= CJSON_NESTING_LIMIT)
+ {
+ return false; /* to deeply nested */
+ }
+ input_buffer->depth++;
+
+ if (buffer_at_offset(input_buffer)[0] != '[')
+ {
+ /* not an array */
+ goto fail;
+ }
+
+ input_buffer->offset++;
+ buffer_skip_whitespace(input_buffer);
+ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']'))
+ {
+ /* empty array */
+ goto success;
+ }
+
+ /* check if we skipped to the end of the buffer */
+ if (cannot_access_at_index(input_buffer, 0))
+ {
+ input_buffer->offset--;
+ goto fail;
+ }
+
+ /* step back to character in front of the first element */
+ input_buffer->offset--;
+ /* loop through the comma separated array elements */
+ do
+ {
+ /* allocate next item */
+ cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
+ if (new_item == NULL)
+ {
+ goto fail; /* allocation failure */
+ }
+
+ /* attach next item to list */
+ if (head == NULL)
+ {
+ /* start the linked list */
+ current_item = head = new_item;
+ }
+ else
+ {
+ /* add to the end and advance */
+ current_item->next = new_item;
+ new_item->prev = current_item;
+ current_item = new_item;
+ }
+
+ /* parse next value */
+ input_buffer->offset++;
+ buffer_skip_whitespace(input_buffer);
+ if (!parse_value(current_item, input_buffer))
+ {
+ goto fail; /* failed to parse value */
+ }
+ buffer_skip_whitespace(input_buffer);
+ }
+ while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
+
+ if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']')
+ {
+ goto fail; /* expected end of array */
+ }
+
+success:
+ input_buffer->depth--;
+
+ item->type = cJSON_Array;
+ item->child = head;
+
+ input_buffer->offset++;
+
+ return true;
+
+fail:
+ if (head != NULL)
+ {
+ cJSON_Delete(head);
+ }
+
+ return false;
+}
+
+/* Render an array to text */
+static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer)
+{
+ unsigned char *output_pointer = NULL;
+ size_t length = 0;
+ cJSON *current_element = item->child;
+
+ if (output_buffer == NULL)
+ {
+ return false;
+ }
+
+ /* Compose the output array. */
+ /* opening square bracket */
+ output_pointer = ensure(output_buffer, 1);
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+
+ *output_pointer = '[';
+ output_buffer->offset++;
+ output_buffer->depth++;
+
+ while (current_element != NULL)
+ {
+ if (!print_value(current_element, output_buffer))
+ {
+ return false;
+ }
+ update_offset(output_buffer);
+ if (current_element->next)
+ {
+ length = (size_t) (output_buffer->format ? 2 : 1);
+ output_pointer = ensure(output_buffer, length + 1);
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+ *output_pointer++ = ',';
+ if(output_buffer->format)
+ {
+ *output_pointer++ = ' ';
+ }
+ *output_pointer = '\0';
+ output_buffer->offset += length;
+ }
+ current_element = current_element->next;
+ }
+
+ output_pointer = ensure(output_buffer, 2);
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+ *output_pointer++ = ']';
+ *output_pointer = '\0';
+ output_buffer->depth--;
+
+ return true;
+}
+
+/* Build an object from the text. */
+static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer)
+{
+ cJSON *head = NULL; /* linked list head */
+ cJSON *current_item = NULL;
+
+ if (input_buffer->depth >= CJSON_NESTING_LIMIT)
+ {
+ return false; /* to deeply nested */
+ }
+ input_buffer->depth++;
+
+ if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{'))
+ {
+ goto fail; /* not an object */
+ }
+
+ input_buffer->offset++;
+ buffer_skip_whitespace(input_buffer);
+ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}'))
+ {
+ goto success; /* empty object */
+ }
+
+ /* check if we skipped to the end of the buffer */
+ if (cannot_access_at_index(input_buffer, 0))
+ {
+ input_buffer->offset--;
+ goto fail;
+ }
+
+ /* step back to character in front of the first element */
+ input_buffer->offset--;
+ /* loop through the comma separated array elements */
+ do
+ {
+ /* allocate next item */
+ cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
+ if (new_item == NULL)
+ {
+ goto fail; /* allocation failure */
+ }
+
+ /* attach next item to list */
+ if (head == NULL)
+ {
+ /* start the linked list */
+ current_item = head = new_item;
+ }
+ else
+ {
+ /* add to the end and advance */
+ current_item->next = new_item;
+ new_item->prev = current_item;
+ current_item = new_item;
+ }
+
+ /* parse the name of the child */
+ input_buffer->offset++;
+ buffer_skip_whitespace(input_buffer);
+ if (!parse_string(current_item, input_buffer))
+ {
goto fail; /* failed to parse name */
- }
- buffer_skip_whitespace(input_buffer);
-
- /* swap valuestring and string, because we parsed the name */
- current_item->string = current_item->valuestring;
- current_item->valuestring = NULL;
-
- if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':'))
- {
- goto fail; /* invalid object */
- }
-
- /* parse the value */
- input_buffer->offset++;
- buffer_skip_whitespace(input_buffer);
- if (!parse_value(current_item, input_buffer))
- {
- goto fail; /* failed to parse value */
- }
- buffer_skip_whitespace(input_buffer);
- }
- while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
-
- if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}'))
- {
- goto fail; /* expected end of object */
- }
-
-success:
- input_buffer->depth--;
-
- item->type = cJSON_Object;
- item->child = head;
-
- input_buffer->offset++;
- return true;
-
-fail:
- if (head != NULL)
- {
- cJSON_Delete(head);
- }
-
- return false;
-}
-
-/* Render an object to text. */
-static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer)
-{
- unsigned char *output_pointer = NULL;
- size_t length = 0;
- cJSON *current_item = item->child;
-
- if (output_buffer == NULL)
- {
- return false;
- }
-
- /* Compose the output: */
- length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */
- output_pointer = ensure(output_buffer, length + 1);
- if (output_pointer == NULL)
- {
- return false;
- }
-
- *output_pointer++ = '{';
- output_buffer->depth++;
- if (output_buffer->format)
- {
- *output_pointer++ = '\n';
- }
- output_buffer->offset += length;
-
- while (current_item)
- {
- if (output_buffer->format)
- {
- size_t i;
- output_pointer = ensure(output_buffer, output_buffer->depth);
- if (output_pointer == NULL)
- {
- return false;
- }
- for (i = 0; i < output_buffer->depth; i++)
- {
- *output_pointer++ = '\t';
- }
- output_buffer->offset += output_buffer->depth;
- }
-
- /* print key */
- if (!print_string_ptr((unsigned char*)current_item->string, output_buffer))
- {
- return false;
- }
- update_offset(output_buffer);
-
- length = (size_t) (output_buffer->format ? 2 : 1);
- output_pointer = ensure(output_buffer, length);
- if (output_pointer == NULL)
- {
- return false;
- }
- *output_pointer++ = ':';
- if (output_buffer->format)
- {
- *output_pointer++ = '\t';
- }
- output_buffer->offset += length;
-
- /* print value */
- if (!print_value(current_item, output_buffer))
- {
- return false;
- }
- update_offset(output_buffer);
-
- /* print comma if not last */
- length = (size_t) ((output_buffer->format ? 1 : 0) + (current_item->next ? 1 : 0));
- output_pointer = ensure(output_buffer, length + 1);
- if (output_pointer == NULL)
- {
- return false;
- }
- if (current_item->next)
- {
- *output_pointer++ = ',';
- }
-
- if (output_buffer->format)
- {
- *output_pointer++ = '\n';
- }
- *output_pointer = '\0';
- output_buffer->offset += length;
-
- current_item = current_item->next;
- }
-
- output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2);
- if (output_pointer == NULL)
- {
- return false;
- }
- if (output_buffer->format)
- {
- size_t i;
- for (i = 0; i < (output_buffer->depth - 1); i++)
- {
- *output_pointer++ = '\t';
- }
- }
- *output_pointer++ = '}';
- *output_pointer = '\0';
- output_buffer->depth--;
-
- return true;
-}
-
-/* Get Array size/item / object item. */
-CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array)
-{
- cJSON *child = NULL;
- size_t size = 0;
-
- if (array == NULL)
- {
- return 0;
- }
-
- child = array->child;
-
- while(child != NULL)
- {
- size++;
- child = child->next;
- }
-
- /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
-
- return (int)size;
-}
-
-static cJSON* get_array_item(const cJSON *array, size_t index)
-{
- cJSON *current_child = NULL;
-
- if (array == NULL)
- {
- return NULL;
- }
-
- current_child = array->child;
- while ((current_child != NULL) && (index > 0))
- {
- index--;
- current_child = current_child->next;
- }
-
- return current_child;
-}
-
-CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index)
-{
- if (index < 0)
- {
- return NULL;
- }
-
- return get_array_item(array, (size_t)index);
-}
-
-static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive)
-{
- cJSON *current_element = NULL;
-
- if ((object == NULL) || (name == NULL))
- {
- return NULL;
- }
-
- current_element = object->child;
- if (case_sensitive)
- {
- while ((current_element != NULL) && (strcmp(name, current_element->string) != 0))
- {
- current_element = current_element->next;
- }
- }
- else
- {
- while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0))
- {
- current_element = current_element->next;
- }
- }
-
- return current_element;
-}
-
-CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string)
-{
- return get_object_item(object, string, false);
-}
-
-CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string)
-{
- return get_object_item(object, string, true);
-}
-
-CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string)
-{
- return cJSON_GetObjectItem(object, string) ? 1 : 0;
-}
-
-/* Utility for array list handling. */
-static void suffix_object(cJSON *prev, cJSON *item)
-{
- prev->next = item;
- item->prev = prev;
-}
-
-/* Utility for handling references. */
-static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks)
-{
- cJSON *reference = NULL;
- if (item == NULL)
- {
- return NULL;
- }
-
- reference = cJSON_New_Item(hooks);
- if (reference == NULL)
- {
- return NULL;
- }
-
- memcpy(reference, item, sizeof(cJSON));
- reference->string = NULL;
- reference->type |= cJSON_IsReference;
- reference->next = reference->prev = NULL;
- return reference;
-}
-
-static cJSON_bool add_item_to_array(cJSON *array, cJSON *item)
-{
- cJSON *child = NULL;
-
- if ((item == NULL) || (array == NULL))
- {
- return false;
- }
-
- child = array->child;
-
- if (child == NULL)
- {
- /* list is empty, start new one */
- array->child = item;
- }
- else
- {
- /* append to the end */
- while (child->next)
- {
- child = child->next;
- }
- suffix_object(child, item);
- }
-
- return true;
-}
-
-/* Add item to array/object. */
-CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item)
-{
- add_item_to_array(array, item);
-}
-
-#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
- #pragma GCC diagnostic push
-#endif
-#ifdef __GNUC__
-#pragma GCC diagnostic ignored "-Wcast-qual"
-#endif
-/* helper function to cast away const */
-static void* cast_away_const(const void* string)
-{
- return (void*)string;
-}
-#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
- #pragma GCC diagnostic pop
-#endif
-
-
-static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key)
-{
- char *new_key = NULL;
- int new_type = cJSON_Invalid;
-
- if ((object == NULL) || (string == NULL) || (item == NULL))
- {
- return false;
- }
-
- if (constant_key)
- {
- new_key = (char*)cast_away_const(string);
- new_type = item->type | cJSON_StringIsConst;
- }
- else
- {
- new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks);
- if (new_key == NULL)
- {
- return false;
- }
-
- new_type = item->type & ~cJSON_StringIsConst;
- }
-
- if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
- {
- hooks->deallocate(item->string);
- }
-
- item->string = new_key;
- item->type = new_type;
-
- return add_item_to_array(object, item);
-}
-
-CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
-{
- add_item_to_object(object, string, item, &global_hooks, false);
-}
-
-/* Add an item to an object with constant string as key */
-CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
-{
- add_item_to_object(object, string, item, &global_hooks, true);
-}
-
-CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
-{
- if (array == NULL)
- {
- return;
- }
-
- add_item_to_array(array, create_reference(item, &global_hooks));
-}
-
-CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)
-{
- if ((object == NULL) || (string == NULL))
- {
- return;
- }
-
- add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false);
-}
-
-CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name)
-{
- cJSON *null = cJSON_CreateNull();
- if (add_item_to_object(object, name, null, &global_hooks, false))
- {
- return null;
- }
-
- cJSON_Delete(null);
- return NULL;
-}
-
-CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name)
-{
- cJSON *true_item = cJSON_CreateTrue();
- if (add_item_to_object(object, name, true_item, &global_hooks, false))
- {
- return true_item;
- }
-
- cJSON_Delete(true_item);
- return NULL;
-}
-
-CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name)
-{
- cJSON *false_item = cJSON_CreateFalse();
- if (add_item_to_object(object, name, false_item, &global_hooks, false))
- {
- return false_item;
- }
-
- cJSON_Delete(false_item);
- return NULL;
-}
-
-CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean)
-{
- cJSON *bool_item = cJSON_CreateBool(boolean);
- if (add_item_to_object(object, name, bool_item, &global_hooks, false))
- {
- return bool_item;
- }
-
- cJSON_Delete(bool_item);
- return NULL;
-}
-
-CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number)
-{
- cJSON *number_item = cJSON_CreateNumber(number);
- if (add_item_to_object(object, name, number_item, &global_hooks, false))
- {
- return number_item;
- }
-
- cJSON_Delete(number_item);
- return NULL;
-}
-
-CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string)
-{
- cJSON *string_item = cJSON_CreateString(string);
- if (add_item_to_object(object, name, string_item, &global_hooks, false))
- {
- return string_item;
- }
-
- cJSON_Delete(string_item);
- return NULL;
-}
-
-CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw)
-{
- cJSON *raw_item = cJSON_CreateRaw(raw);
- if (add_item_to_object(object, name, raw_item, &global_hooks, false))
- {
- return raw_item;
- }
-
- cJSON_Delete(raw_item);
- return NULL;
-}
-
-CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name)
-{
- cJSON *object_item = cJSON_CreateObject();
- if (add_item_to_object(object, name, object_item, &global_hooks, false))
- {
- return object_item;
- }
-
- cJSON_Delete(object_item);
- return NULL;
-}
-
-CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name)
-{
- cJSON *array = cJSON_CreateArray();
- if (add_item_to_object(object, name, array, &global_hooks, false))
- {
- return array;
- }
-
- cJSON_Delete(array);
- return NULL;
-}
-
-CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item)
-{
- if ((parent == NULL) || (item == NULL))
- {
- return NULL;
- }
-
- if (item->prev != NULL)
- {
- /* not the first element */
- item->prev->next = item->next;
- }
- if (item->next != NULL)
- {
- /* not the last element */
- item->next->prev = item->prev;
- }
-
- if (item == parent->child)
- {
- /* first element */
- parent->child = item->next;
- }
- /* make sure the detached item doesn't point anywhere anymore */
- item->prev = NULL;
- item->next = NULL;
-
- return item;
-}
-
-CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which)
-{
- if (which < 0)
- {
- return NULL;
- }
-
- return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which));
-}
-
-CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which)
-{
- cJSON_Delete(cJSON_DetachItemFromArray(array, which));
-}
-
-CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string)
-{
- cJSON *to_detach = cJSON_GetObjectItem(object, string);
-
- return cJSON_DetachItemViaPointer(object, to_detach);
-}
-
-CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string)
-{
- cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string);
-
- return cJSON_DetachItemViaPointer(object, to_detach);
-}
-
-CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string)
-{
- cJSON_Delete(cJSON_DetachItemFromObject(object, string));
-}
-
-CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string)
-{
- cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string));
-}
-
-/* Replace array/object items with new ones. */
-CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
-{
- cJSON *after_inserted = NULL;
-
- if (which < 0)
- {
- return;
- }
-
- after_inserted = get_array_item(array, (size_t)which);
- if (after_inserted == NULL)
- {
- add_item_to_array(array, newitem);
- return;
- }
-
- newitem->next = after_inserted;
- newitem->prev = after_inserted->prev;
- after_inserted->prev = newitem;
- if (after_inserted == array->child)
- {
- array->child = newitem;
- }
- else
- {
- newitem->prev->next = newitem;
- }
-}
-
-CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement)
-{
- if ((parent == NULL) || (replacement == NULL) || (item == NULL))
- {
- return false;
- }
-
- if (replacement == item)
- {
- return true;
- }
-
- replacement->next = item->next;
- replacement->prev = item->prev;
-
- if (replacement->next != NULL)
- {
- replacement->next->prev = replacement;
- }
- if (replacement->prev != NULL)
- {
- replacement->prev->next = replacement;
- }
- if (parent->child == item)
- {
- parent->child = replacement;
- }
-
- item->next = NULL;
- item->prev = NULL;
- cJSON_Delete(item);
-
- return true;
-}
-
-CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
-{
- if (which < 0)
- {
- return;
- }
-
- cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem);
-}
-
-static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive)
-{
- if ((replacement == NULL) || (string == NULL))
- {
- return false;
- }
-
- /* replace the name in the replacement */
- if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL))
- {
- cJSON_free(replacement->string);
- }
- replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
- replacement->type &= ~cJSON_StringIsConst;
-
- cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement);
-
- return true;
-}
-
-CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
-{
- replace_item_in_object(object, string, newitem, false);
-}
-
-CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem)
-{
- replace_item_in_object(object, string, newitem, true);
-}
-
-/* Create basic types: */
-CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void)
-{
- cJSON *item = cJSON_New_Item(&global_hooks);
- if(item)
- {
- item->type = cJSON_NULL;
- }
-
- return item;
-}
-
-CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void)
-{
- cJSON *item = cJSON_New_Item(&global_hooks);
- if(item)
- {
- item->type = cJSON_True;
- }
-
- return item;
-}
-
-CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void)
-{
- cJSON *item = cJSON_New_Item(&global_hooks);
- if(item)
- {
- item->type = cJSON_False;
- }
-
- return item;
-}
-
-CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b)
-{
- cJSON *item = cJSON_New_Item(&global_hooks);
- if(item)
- {
- item->type = b ? cJSON_True : cJSON_False;
- }
-
- return item;
-}
-
-CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
-{
- cJSON *item = cJSON_New_Item(&global_hooks);
- if(item)
- {
- item->type = cJSON_Number;
- item->valuedouble = num;
-
- /* use saturation in case of overflow */
- if (num >= INT_MAX)
- {
- item->valueint = INT_MAX;
- }
- else if (num <= INT_MIN)
- {
- item->valueint = INT_MIN;
- }
- else
- {
- item->valueint = (int)num;
- }
- }
-
- return item;
-}
-
+ }
+ buffer_skip_whitespace(input_buffer);
+
+ /* swap valuestring and string, because we parsed the name */
+ current_item->string = current_item->valuestring;
+ current_item->valuestring = NULL;
+
+ if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':'))
+ {
+ goto fail; /* invalid object */
+ }
+
+ /* parse the value */
+ input_buffer->offset++;
+ buffer_skip_whitespace(input_buffer);
+ if (!parse_value(current_item, input_buffer))
+ {
+ goto fail; /* failed to parse value */
+ }
+ buffer_skip_whitespace(input_buffer);
+ }
+ while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
+
+ if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}'))
+ {
+ goto fail; /* expected end of object */
+ }
+
+success:
+ input_buffer->depth--;
+
+ item->type = cJSON_Object;
+ item->child = head;
+
+ input_buffer->offset++;
+ return true;
+
+fail:
+ if (head != NULL)
+ {
+ cJSON_Delete(head);
+ }
+
+ return false;
+}
+
+/* Render an object to text. */
+static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer)
+{
+ unsigned char *output_pointer = NULL;
+ size_t length = 0;
+ cJSON *current_item = item->child;
+
+ if (output_buffer == NULL)
+ {
+ return false;
+ }
+
+ /* Compose the output: */
+ length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */
+ output_pointer = ensure(output_buffer, length + 1);
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+
+ *output_pointer++ = '{';
+ output_buffer->depth++;
+ if (output_buffer->format)
+ {
+ *output_pointer++ = '\n';
+ }
+ output_buffer->offset += length;
+
+ while (current_item)
+ {
+ if (output_buffer->format)
+ {
+ size_t i;
+ output_pointer = ensure(output_buffer, output_buffer->depth);
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+ for (i = 0; i < output_buffer->depth; i++)
+ {
+ *output_pointer++ = '\t';
+ }
+ output_buffer->offset += output_buffer->depth;
+ }
+
+ /* print key */
+ if (!print_string_ptr((unsigned char*)current_item->string, output_buffer))
+ {
+ return false;
+ }
+ update_offset(output_buffer);
+
+ length = (size_t) (output_buffer->format ? 2 : 1);
+ output_pointer = ensure(output_buffer, length);
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+ *output_pointer++ = ':';
+ if (output_buffer->format)
+ {
+ *output_pointer++ = '\t';
+ }
+ output_buffer->offset += length;
+
+ /* print value */
+ if (!print_value(current_item, output_buffer))
+ {
+ return false;
+ }
+ update_offset(output_buffer);
+
+ /* print comma if not last */
+ length = (size_t) ((output_buffer->format ? 1 : 0) + (current_item->next ? 1 : 0));
+ output_pointer = ensure(output_buffer, length + 1);
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+ if (current_item->next)
+ {
+ *output_pointer++ = ',';
+ }
+
+ if (output_buffer->format)
+ {
+ *output_pointer++ = '\n';
+ }
+ *output_pointer = '\0';
+ output_buffer->offset += length;
+
+ current_item = current_item->next;
+ }
+
+ output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2);
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+ if (output_buffer->format)
+ {
+ size_t i;
+ for (i = 0; i < (output_buffer->depth - 1); i++)
+ {
+ *output_pointer++ = '\t';
+ }
+ }
+ *output_pointer++ = '}';
+ *output_pointer = '\0';
+ output_buffer->depth--;
+
+ return true;
+}
+
+/* Get Array size/item / object item. */
+CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array)
+{
+ cJSON *child = NULL;
+ size_t size = 0;
+
+ if (array == NULL)
+ {
+ return 0;
+ }
+
+ child = array->child;
+
+ while(child != NULL)
+ {
+ size++;
+ child = child->next;
+ }
+
+ /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
+
+ return (int)size;
+}
+
+static cJSON* get_array_item(const cJSON *array, size_t index)
+{
+ cJSON *current_child = NULL;
+
+ if (array == NULL)
+ {
+ return NULL;
+ }
+
+ current_child = array->child;
+ while ((current_child != NULL) && (index > 0))
+ {
+ index--;
+ current_child = current_child->next;
+ }
+
+ return current_child;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index)
+{
+ if (index < 0)
+ {
+ return NULL;
+ }
+
+ return get_array_item(array, (size_t)index);
+}
+
+static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive)
+{
+ cJSON *current_element = NULL;
+
+ if ((object == NULL) || (name == NULL))
+ {
+ return NULL;
+ }
+
+ current_element = object->child;
+ if (case_sensitive)
+ {
+ while ((current_element != NULL) && (strcmp(name, current_element->string) != 0))
+ {
+ current_element = current_element->next;
+ }
+ }
+ else
+ {
+ while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0))
+ {
+ current_element = current_element->next;
+ }
+ }
+
+ return current_element;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string)
+{
+ return get_object_item(object, string, false);
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string)
+{
+ return get_object_item(object, string, true);
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string)
+{
+ return cJSON_GetObjectItem(object, string) ? 1 : 0;
+}
+
+/* Utility for array list handling. */
+static void suffix_object(cJSON *prev, cJSON *item)
+{
+ prev->next = item;
+ item->prev = prev;
+}
+
+/* Utility for handling references. */
+static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks)
+{
+ cJSON *reference = NULL;
+ if (item == NULL)
+ {
+ return NULL;
+ }
+
+ reference = cJSON_New_Item(hooks);
+ if (reference == NULL)
+ {
+ return NULL;
+ }
+
+ memcpy(reference, item, sizeof(cJSON));
+ reference->string = NULL;
+ reference->type |= cJSON_IsReference;
+ reference->next = reference->prev = NULL;
+ return reference;
+}
+
+static cJSON_bool add_item_to_array(cJSON *array, cJSON *item)
+{
+ cJSON *child = NULL;
+
+ if ((item == NULL) || (array == NULL))
+ {
+ return false;
+ }
+
+ child = array->child;
+
+ if (child == NULL)
+ {
+ /* list is empty, start new one */
+ array->child = item;
+ }
+ else
+ {
+ /* append to the end */
+ while (child->next)
+ {
+ child = child->next;
+ }
+ suffix_object(child, item);
+ }
+
+ return true;
+}
+
+/* Add item to array/object. */
+CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item)
+{
+ add_item_to_array(array, item);
+}
+
+#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
+ #pragma GCC diagnostic push
+#endif
+#ifdef __GNUC__
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#endif
+/* helper function to cast away const */
+static void* cast_away_const(const void* string)
+{
+ return (void*)string;
+}
+#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
+ #pragma GCC diagnostic pop
+#endif
+
+
+static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key)
+{
+ char *new_key = NULL;
+ int new_type = cJSON_Invalid;
+
+ if ((object == NULL) || (string == NULL) || (item == NULL))
+ {
+ return false;
+ }
+
+ if (constant_key)
+ {
+ new_key = (char*)cast_away_const(string);
+ new_type = item->type | cJSON_StringIsConst;
+ }
+ else
+ {
+ new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks);
+ if (new_key == NULL)
+ {
+ return false;
+ }
+
+ new_type = item->type & ~cJSON_StringIsConst;
+ }
+
+ if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
+ {
+ hooks->deallocate(item->string);
+ }
+
+ item->string = new_key;
+ item->type = new_type;
+
+ return add_item_to_array(object, item);
+}
+
+CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
+{
+ add_item_to_object(object, string, item, &global_hooks, false);
+}
+
+/* Add an item to an object with constant string as key */
+CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
+{
+ add_item_to_object(object, string, item, &global_hooks, true);
+}
+
+CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
+{
+ if (array == NULL)
+ {
+ return;
+ }
+
+ add_item_to_array(array, create_reference(item, &global_hooks));
+}
+
+CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)
+{
+ if ((object == NULL) || (string == NULL))
+ {
+ return;
+ }
+
+ add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false);
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name)
+{
+ cJSON *null = cJSON_CreateNull();
+ if (add_item_to_object(object, name, null, &global_hooks, false))
+ {
+ return null;
+ }
+
+ cJSON_Delete(null);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name)
+{
+ cJSON *true_item = cJSON_CreateTrue();
+ if (add_item_to_object(object, name, true_item, &global_hooks, false))
+ {
+ return true_item;
+ }
+
+ cJSON_Delete(true_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name)
+{
+ cJSON *false_item = cJSON_CreateFalse();
+ if (add_item_to_object(object, name, false_item, &global_hooks, false))
+ {
+ return false_item;
+ }
+
+ cJSON_Delete(false_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean)
+{
+ cJSON *bool_item = cJSON_CreateBool(boolean);
+ if (add_item_to_object(object, name, bool_item, &global_hooks, false))
+ {
+ return bool_item;
+ }
+
+ cJSON_Delete(bool_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number)
+{
+ cJSON *number_item = cJSON_CreateNumber(number);
+ if (add_item_to_object(object, name, number_item, &global_hooks, false))
+ {
+ return number_item;
+ }
+
+ cJSON_Delete(number_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string)
+{
+ cJSON *string_item = cJSON_CreateString(string);
+ if (add_item_to_object(object, name, string_item, &global_hooks, false))
+ {
+ return string_item;
+ }
+
+ cJSON_Delete(string_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw)
+{
+ cJSON *raw_item = cJSON_CreateRaw(raw);
+ if (add_item_to_object(object, name, raw_item, &global_hooks, false))
+ {
+ return raw_item;
+ }
+
+ cJSON_Delete(raw_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name)
+{
+ cJSON *object_item = cJSON_CreateObject();
+ if (add_item_to_object(object, name, object_item, &global_hooks, false))
+ {
+ return object_item;
+ }
+
+ cJSON_Delete(object_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name)
+{
+ cJSON *array = cJSON_CreateArray();
+ if (add_item_to_object(object, name, array, &global_hooks, false))
+ {
+ return array;
+ }
+
+ cJSON_Delete(array);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item)
+{
+ if ((parent == NULL) || (item == NULL))
+ {
+ return NULL;
+ }
+
+ if (item->prev != NULL)
+ {
+ /* not the first element */
+ item->prev->next = item->next;
+ }
+ if (item->next != NULL)
+ {
+ /* not the last element */
+ item->next->prev = item->prev;
+ }
+
+ if (item == parent->child)
+ {
+ /* first element */
+ parent->child = item->next;
+ }
+ /* make sure the detached item doesn't point anywhere anymore */
+ item->prev = NULL;
+ item->next = NULL;
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which)
+{
+ if (which < 0)
+ {
+ return NULL;
+ }
+
+ return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which));
+}
+
+CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which)
+{
+ cJSON_Delete(cJSON_DetachItemFromArray(array, which));
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string)
+{
+ cJSON *to_detach = cJSON_GetObjectItem(object, string);
+
+ return cJSON_DetachItemViaPointer(object, to_detach);
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string)
+{
+ cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string);
+
+ return cJSON_DetachItemViaPointer(object, to_detach);
+}
+
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string)
+{
+ cJSON_Delete(cJSON_DetachItemFromObject(object, string));
+}
+
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string)
+{
+ cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string));
+}
+
+/* Replace array/object items with new ones. */
+CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
+{
+ cJSON *after_inserted = NULL;
+
+ if (which < 0)
+ {
+ return;
+ }
+
+ after_inserted = get_array_item(array, (size_t)which);
+ if (after_inserted == NULL)
+ {
+ add_item_to_array(array, newitem);
+ return;
+ }
+
+ newitem->next = after_inserted;
+ newitem->prev = after_inserted->prev;
+ after_inserted->prev = newitem;
+ if (after_inserted == array->child)
+ {
+ array->child = newitem;
+ }
+ else
+ {
+ newitem->prev->next = newitem;
+ }
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement)
+{
+ if ((parent == NULL) || (replacement == NULL) || (item == NULL))
+ {
+ return false;
+ }
+
+ if (replacement == item)
+ {
+ return true;
+ }
+
+ replacement->next = item->next;
+ replacement->prev = item->prev;
+
+ if (replacement->next != NULL)
+ {
+ replacement->next->prev = replacement;
+ }
+ if (replacement->prev != NULL)
+ {
+ replacement->prev->next = replacement;
+ }
+ if (parent->child == item)
+ {
+ parent->child = replacement;
+ }
+
+ item->next = NULL;
+ item->prev = NULL;
+ cJSON_Delete(item);
+
+ return true;
+}
+
+CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
+{
+ if (which < 0)
+ {
+ return;
+ }
+
+ cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem);
+}
+
+static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive)
+{
+ if ((replacement == NULL) || (string == NULL))
+ {
+ return false;
+ }
+
+ /* replace the name in the replacement */
+ if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL))
+ {
+ cJSON_free(replacement->string);
+ }
+ replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
+ replacement->type &= ~cJSON_StringIsConst;
+
+ cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement);
+
+ return true;
+}
+
+CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
+{
+ replace_item_in_object(object, string, newitem, false);
+}
+
+CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem)
+{
+ replace_item_in_object(object, string, newitem, true);
+}
+
+/* Create basic types: */
+CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if(item)
+ {
+ item->type = cJSON_NULL;
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if(item)
+ {
+ item->type = cJSON_True;
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if(item)
+ {
+ item->type = cJSON_False;
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if(item)
+ {
+ item->type = b ? cJSON_True : cJSON_False;
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if(item)
+ {
+ item->type = cJSON_Number;
+ item->valuedouble = num;
+
+ /* use saturation in case of overflow */
+ if (num >= INT_MAX)
+ {
+ item->valueint = INT_MAX;
+ }
+ else if (num <= INT_MIN)
+ {
+ item->valueint = INT_MIN;
+ }
+ else
+ {
+ item->valueint = (int)num;
+ }
+ }
+
+ return item;
+}
+
CJSON_PUBLIC(cJSON *) cJSON_CreateInt64(long long num)
{
cJSON *item = cJSON_New_Item(&global_hooks);
@@ -2364,620 +2364,620 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateInt64(long long num)
return item;
}
-CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string)
-{
- cJSON *item = cJSON_New_Item(&global_hooks);
- if(item)
- {
- item->type = cJSON_String;
- item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
- if(!item->valuestring)
- {
- cJSON_Delete(item);
- return NULL;
- }
- }
-
- return item;
-}
-
-CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string)
-{
- cJSON *item = cJSON_New_Item(&global_hooks);
- if (item != NULL)
- {
- item->type = cJSON_String | cJSON_IsReference;
- item->valuestring = (char*)cast_away_const(string);
- }
-
- return item;
-}
-
-CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child)
-{
- cJSON *item = cJSON_New_Item(&global_hooks);
- if (item != NULL) {
- item->type = cJSON_Object | cJSON_IsReference;
- item->child = (cJSON*)cast_away_const(child);
- }
-
- return item;
-}
-
-CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) {
- cJSON *item = cJSON_New_Item(&global_hooks);
- if (item != NULL) {
- item->type = cJSON_Array | cJSON_IsReference;
- item->child = (cJSON*)cast_away_const(child);
- }
-
- return item;
-}
-
-CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw)
-{
- cJSON *item = cJSON_New_Item(&global_hooks);
- if(item)
- {
- item->type = cJSON_Raw;
- item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks);
- if(!item->valuestring)
- {
- cJSON_Delete(item);
- return NULL;
- }
- }
-
- return item;
-}
-
-CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void)
-{
- cJSON *item = cJSON_New_Item(&global_hooks);
- if(item)
- {
- item->type=cJSON_Array;
- }
-
- return item;
-}
-
-CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void)
-{
- cJSON *item = cJSON_New_Item(&global_hooks);
- if (item)
- {
- item->type = cJSON_Object;
- }
-
- return item;
-}
-
-/* Create Arrays: */
-CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)
-{
- size_t i = 0;
- cJSON *n = NULL;
- cJSON *p = NULL;
- cJSON *a = NULL;
-
- if ((count < 0) || (numbers == NULL))
- {
- return NULL;
- }
-
- a = cJSON_CreateArray();
- for(i = 0; a && (i < (size_t)count); i++)
- {
- n = cJSON_CreateNumber(numbers[i]);
- if (!n)
- {
- cJSON_Delete(a);
- return NULL;
- }
- if(!i)
- {
- a->child = n;
- }
- else
- {
- suffix_object(p, n);
- }
- p = n;
- }
-
- return a;
-}
-
-CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count)
-{
- size_t i = 0;
- cJSON *n = NULL;
- cJSON *p = NULL;
- cJSON *a = NULL;
-
- if ((count < 0) || (numbers == NULL))
- {
- return NULL;
- }
-
- a = cJSON_CreateArray();
-
- for(i = 0; a && (i < (size_t)count); i++)
- {
- n = cJSON_CreateNumber((double)numbers[i]);
- if(!n)
- {
- cJSON_Delete(a);
- return NULL;
- }
- if(!i)
- {
- a->child = n;
- }
- else
- {
- suffix_object(p, n);
- }
- p = n;
- }
-
- return a;
-}
-
-CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count)
-{
- size_t i = 0;
- cJSON *n = NULL;
- cJSON *p = NULL;
- cJSON *a = NULL;
-
- if ((count < 0) || (numbers == NULL))
- {
- return NULL;
- }
-
- a = cJSON_CreateArray();
-
- for(i = 0;a && (i < (size_t)count); i++)
- {
- n = cJSON_CreateNumber(numbers[i]);
- if(!n)
- {
- cJSON_Delete(a);
- return NULL;
- }
- if(!i)
- {
- a->child = n;
- }
- else
- {
- suffix_object(p, n);
- }
- p = n;
- }
-
- return a;
-}
-
-CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count)
-{
- size_t i = 0;
- cJSON *n = NULL;
- cJSON *p = NULL;
- cJSON *a = NULL;
-
- if ((count < 0) || (strings == NULL))
- {
- return NULL;
- }
-
- a = cJSON_CreateArray();
-
- for (i = 0; a && (i < (size_t)count); i++)
- {
- n = cJSON_CreateString(strings[i]);
- if(!n)
- {
- cJSON_Delete(a);
- return NULL;
- }
- if(!i)
- {
- a->child = n;
- }
- else
- {
- suffix_object(p,n);
- }
- p = n;
- }
-
- return a;
-}
-
-/* Duplication */
-CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
-{
- cJSON *newitem = NULL;
- cJSON *child = NULL;
- cJSON *next = NULL;
- cJSON *newchild = NULL;
-
- /* Bail on bad ptr */
- if (!item)
- {
- goto fail;
- }
- /* Create new item */
- newitem = cJSON_New_Item(&global_hooks);
- if (!newitem)
- {
- goto fail;
- }
- /* Copy over all vars */
- newitem->type = item->type & (~cJSON_IsReference);
- newitem->valueint = item->valueint;
- newitem->valuedouble = item->valuedouble;
- if (item->valuestring)
- {
- newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks);
- if (!newitem->valuestring)
- {
- goto fail;
- }
- }
- if (item->string)
- {
- newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks);
- if (!newitem->string)
- {
- goto fail;
- }
- }
- /* If non-recursive, then we're done! */
- if (!recurse)
- {
- return newitem;
- }
- /* Walk the ->next chain for the child. */
- child = item->child;
- while (child != NULL)
- {
- newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */
- if (!newchild)
- {
- goto fail;
- }
- if (next != NULL)
- {
- /* If newitem->child already set, then crosswire ->prev and ->next and move on */
- next->next = newchild;
- newchild->prev = next;
- next = newchild;
- }
- else
- {
- /* Set newitem->child and move to it */
- newitem->child = newchild;
- next = newchild;
- }
- child = child->next;
- }
-
- return newitem;
-
-fail:
- if (newitem != NULL)
- {
- cJSON_Delete(newitem);
- }
-
- return NULL;
-}
-
-CJSON_PUBLIC(void) cJSON_Minify(char *json)
-{
- unsigned char *into = (unsigned char*)json;
-
- if (json == NULL)
- {
- return;
- }
-
- while (*json)
- {
- if (*json == ' ')
- {
- json++;
- }
- else if (*json == '\t')
- {
- /* Whitespace characters. */
- json++;
- }
- else if (*json == '\r')
- {
- json++;
- }
- else if (*json=='\n')
- {
- json++;
- }
- else if ((*json == '/') && (json[1] == '/'))
- {
- /* double-slash comments, to end of line. */
- while (*json && (*json != '\n'))
- {
- json++;
- }
- }
- else if ((*json == '/') && (json[1] == '*'))
- {
- /* multiline comments. */
- while (*json && !((*json == '*') && (json[1] == '/')))
- {
- json++;
- }
- json += 2;
- }
- else if (*json == '\"')
- {
- /* string literals, which are \" sensitive. */
- *into++ = (unsigned char)*json++;
- while (*json && (*json != '\"'))
- {
- if (*json == '\\')
- {
- *into++ = (unsigned char)*json++;
- }
- *into++ = (unsigned char)*json++;
- }
- *into++ = (unsigned char)*json++;
- }
- else
- {
- /* All other characters. */
- *into++ = (unsigned char)*json++;
- }
- }
-
- /* and null-terminate. */
- *into = '\0';
-}
-
-CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item)
-{
- if (item == NULL)
- {
- return false;
- }
-
- return (item->type & 0xFF) == cJSON_Invalid;
-}
-
-CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item)
-{
- if (item == NULL)
- {
- return false;
- }
-
- return (item->type & 0xFF) == cJSON_False;
-}
-
-CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item)
-{
- if (item == NULL)
- {
- return false;
- }
-
- return (item->type & 0xff) == cJSON_True;
-}
-
-
-CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item)
-{
- if (item == NULL)
- {
- return false;
- }
-
- return (item->type & (cJSON_True | cJSON_False)) != 0;
-}
-CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item)
-{
- if (item == NULL)
- {
- return false;
- }
-
- return (item->type & 0xFF) == cJSON_NULL;
-}
-
-CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item)
-{
- if (item == NULL)
- {
- return false;
- }
-
- return (item->type & 0xFF) == cJSON_Number;
-}
-
-CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item)
-{
- if (item == NULL)
- {
- return false;
- }
-
- return (item->type & 0xFF) == cJSON_String;
-}
-
-CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item)
-{
- if (item == NULL)
- {
- return false;
- }
-
- return (item->type & 0xFF) == cJSON_Array;
-}
-
-CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item)
-{
- if (item == NULL)
- {
- return false;
- }
-
- return (item->type & 0xFF) == cJSON_Object;
-}
-
-CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item)
-{
- if (item == NULL)
- {
- return false;
- }
-
- return (item->type & 0xFF) == cJSON_Raw;
-}
-
-CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive)
-{
- if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a))
- {
- return false;
- }
-
- /* check if type is valid */
- switch (a->type & 0xFF)
- {
- case cJSON_False:
- case cJSON_True:
- case cJSON_NULL:
- case cJSON_Number:
- case cJSON_String:
- case cJSON_Raw:
- case cJSON_Array:
- case cJSON_Object:
- break;
-
- default:
- return false;
- }
-
- /* identical objects are equal */
- if (a == b)
- {
- return true;
- }
-
- switch (a->type & 0xFF)
- {
- /* in these cases and equal type is enough */
- case cJSON_False:
- case cJSON_True:
- case cJSON_NULL:
- return true;
-
- case cJSON_Number:
- if (a->valuedouble == b->valuedouble)
- {
- return true;
- }
- return false;
-
- case cJSON_String:
- case cJSON_Raw:
- if ((a->valuestring == NULL) || (b->valuestring == NULL))
- {
- return false;
- }
- if (strcmp(a->valuestring, b->valuestring) == 0)
- {
- return true;
- }
-
- return false;
-
- case cJSON_Array:
- {
- cJSON *a_element = a->child;
- cJSON *b_element = b->child;
-
- for (; (a_element != NULL) && (b_element != NULL);)
- {
- if (!cJSON_Compare(a_element, b_element, case_sensitive))
- {
- return false;
- }
-
- a_element = a_element->next;
- b_element = b_element->next;
- }
-
- /* one of the arrays is longer than the other */
- if (a_element != b_element) {
- return false;
- }
-
- return true;
- }
-
- case cJSON_Object:
- {
- cJSON *a_element = NULL;
- cJSON *b_element = NULL;
- cJSON_ArrayForEach(a_element, a)
- {
- /* TODO This has O(n^2) runtime, which is horrible! */
- b_element = get_object_item(b, a_element->string, case_sensitive);
- if (b_element == NULL)
- {
- return false;
- }
-
- if (!cJSON_Compare(a_element, b_element, case_sensitive))
- {
- return false;
- }
- }
-
- /* doing this twice, once on a and b to prevent true comparison if a subset of b
- * TODO: Do this the proper way, this is just a fix for now */
- cJSON_ArrayForEach(b_element, b)
- {
- a_element = get_object_item(a, b_element->string, case_sensitive);
- if (a_element == NULL)
- {
- return false;
- }
-
- if (!cJSON_Compare(b_element, a_element, case_sensitive))
- {
- return false;
- }
- }
-
- return true;
- }
-
- default:
- return false;
- }
-}
-
-CJSON_PUBLIC(void *) cJSON_malloc(size_t size)
-{
- return global_hooks.allocate(size);
-}
-
-CJSON_PUBLIC(void) cJSON_free(void *object)
-{
- global_hooks.deallocate(object);
-}
+CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if(item)
+ {
+ item->type = cJSON_String;
+ item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
+ if(!item->valuestring)
+ {
+ cJSON_Delete(item);
+ return NULL;
+ }
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if (item != NULL)
+ {
+ item->type = cJSON_String | cJSON_IsReference;
+ item->valuestring = (char*)cast_away_const(string);
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if (item != NULL) {
+ item->type = cJSON_Object | cJSON_IsReference;
+ item->child = (cJSON*)cast_away_const(child);
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) {
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if (item != NULL) {
+ item->type = cJSON_Array | cJSON_IsReference;
+ item->child = (cJSON*)cast_away_const(child);
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if(item)
+ {
+ item->type = cJSON_Raw;
+ item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks);
+ if(!item->valuestring)
+ {
+ cJSON_Delete(item);
+ return NULL;
+ }
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if(item)
+ {
+ item->type=cJSON_Array;
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if (item)
+ {
+ item->type = cJSON_Object;
+ }
+
+ return item;
+}
+
+/* Create Arrays: */
+CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)
+{
+ size_t i = 0;
+ cJSON *n = NULL;
+ cJSON *p = NULL;
+ cJSON *a = NULL;
+
+ if ((count < 0) || (numbers == NULL))
+ {
+ return NULL;
+ }
+
+ a = cJSON_CreateArray();
+ for(i = 0; a && (i < (size_t)count); i++)
+ {
+ n = cJSON_CreateNumber(numbers[i]);
+ if (!n)
+ {
+ cJSON_Delete(a);
+ return NULL;
+ }
+ if(!i)
+ {
+ a->child = n;
+ }
+ else
+ {
+ suffix_object(p, n);
+ }
+ p = n;
+ }
+
+ return a;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count)
+{
+ size_t i = 0;
+ cJSON *n = NULL;
+ cJSON *p = NULL;
+ cJSON *a = NULL;
+
+ if ((count < 0) || (numbers == NULL))
+ {
+ return NULL;
+ }
+
+ a = cJSON_CreateArray();
+
+ for(i = 0; a && (i < (size_t)count); i++)
+ {
+ n = cJSON_CreateNumber((double)numbers[i]);
+ if(!n)
+ {
+ cJSON_Delete(a);
+ return NULL;
+ }
+ if(!i)
+ {
+ a->child = n;
+ }
+ else
+ {
+ suffix_object(p, n);
+ }
+ p = n;
+ }
+
+ return a;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count)
+{
+ size_t i = 0;
+ cJSON *n = NULL;
+ cJSON *p = NULL;
+ cJSON *a = NULL;
+
+ if ((count < 0) || (numbers == NULL))
+ {
+ return NULL;
+ }
+
+ a = cJSON_CreateArray();
+
+ for(i = 0;a && (i < (size_t)count); i++)
+ {
+ n = cJSON_CreateNumber(numbers[i]);
+ if(!n)
+ {
+ cJSON_Delete(a);
+ return NULL;
+ }
+ if(!i)
+ {
+ a->child = n;
+ }
+ else
+ {
+ suffix_object(p, n);
+ }
+ p = n;
+ }
+
+ return a;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count)
+{
+ size_t i = 0;
+ cJSON *n = NULL;
+ cJSON *p = NULL;
+ cJSON *a = NULL;
+
+ if ((count < 0) || (strings == NULL))
+ {
+ return NULL;
+ }
+
+ a = cJSON_CreateArray();
+
+ for (i = 0; a && (i < (size_t)count); i++)
+ {
+ n = cJSON_CreateString(strings[i]);
+ if(!n)
+ {
+ cJSON_Delete(a);
+ return NULL;
+ }
+ if(!i)
+ {
+ a->child = n;
+ }
+ else
+ {
+ suffix_object(p,n);
+ }
+ p = n;
+ }
+
+ return a;
+}
+
+/* Duplication */
+CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
+{
+ cJSON *newitem = NULL;
+ cJSON *child = NULL;
+ cJSON *next = NULL;
+ cJSON *newchild = NULL;
+
+ /* Bail on bad ptr */
+ if (!item)
+ {
+ goto fail;
+ }
+ /* Create new item */
+ newitem = cJSON_New_Item(&global_hooks);
+ if (!newitem)
+ {
+ goto fail;
+ }
+ /* Copy over all vars */
+ newitem->type = item->type & (~cJSON_IsReference);
+ newitem->valueint = item->valueint;
+ newitem->valuedouble = item->valuedouble;
+ if (item->valuestring)
+ {
+ newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks);
+ if (!newitem->valuestring)
+ {
+ goto fail;
+ }
+ }
+ if (item->string)
+ {
+ newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks);
+ if (!newitem->string)
+ {
+ goto fail;
+ }
+ }
+ /* If non-recursive, then we're done! */
+ if (!recurse)
+ {
+ return newitem;
+ }
+ /* Walk the ->next chain for the child. */
+ child = item->child;
+ while (child != NULL)
+ {
+ newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */
+ if (!newchild)
+ {
+ goto fail;
+ }
+ if (next != NULL)
+ {
+ /* If newitem->child already set, then crosswire ->prev and ->next and move on */
+ next->next = newchild;
+ newchild->prev = next;
+ next = newchild;
+ }
+ else
+ {
+ /* Set newitem->child and move to it */
+ newitem->child = newchild;
+ next = newchild;
+ }
+ child = child->next;
+ }
+
+ return newitem;
+
+fail:
+ if (newitem != NULL)
+ {
+ cJSON_Delete(newitem);
+ }
+
+ return NULL;
+}
+
+CJSON_PUBLIC(void) cJSON_Minify(char *json)
+{
+ unsigned char *into = (unsigned char*)json;
+
+ if (json == NULL)
+ {
+ return;
+ }
+
+ while (*json)
+ {
+ if (*json == ' ')
+ {
+ json++;
+ }
+ else if (*json == '\t')
+ {
+ /* Whitespace characters. */
+ json++;
+ }
+ else if (*json == '\r')
+ {
+ json++;
+ }
+ else if (*json=='\n')
+ {
+ json++;
+ }
+ else if ((*json == '/') && (json[1] == '/'))
+ {
+ /* double-slash comments, to end of line. */
+ while (*json && (*json != '\n'))
+ {
+ json++;
+ }
+ }
+ else if ((*json == '/') && (json[1] == '*'))
+ {
+ /* multiline comments. */
+ while (*json && !((*json == '*') && (json[1] == '/')))
+ {
+ json++;
+ }
+ json += 2;
+ }
+ else if (*json == '\"')
+ {
+ /* string literals, which are \" sensitive. */
+ *into++ = (unsigned char)*json++;
+ while (*json && (*json != '\"'))
+ {
+ if (*json == '\\')
+ {
+ *into++ = (unsigned char)*json++;
+ }
+ *into++ = (unsigned char)*json++;
+ }
+ *into++ = (unsigned char)*json++;
+ }
+ else
+ {
+ /* All other characters. */
+ *into++ = (unsigned char)*json++;
+ }
+ }
+
+ /* and null-terminate. */
+ *into = '\0';
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xFF) == cJSON_Invalid;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xFF) == cJSON_False;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xff) == cJSON_True;
+}
+
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & (cJSON_True | cJSON_False)) != 0;
+}
+CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xFF) == cJSON_NULL;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xFF) == cJSON_Number;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xFF) == cJSON_String;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xFF) == cJSON_Array;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xFF) == cJSON_Object;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xFF) == cJSON_Raw;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive)
+{
+ if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a))
+ {
+ return false;
+ }
+
+ /* check if type is valid */
+ switch (a->type & 0xFF)
+ {
+ case cJSON_False:
+ case cJSON_True:
+ case cJSON_NULL:
+ case cJSON_Number:
+ case cJSON_String:
+ case cJSON_Raw:
+ case cJSON_Array:
+ case cJSON_Object:
+ break;
+
+ default:
+ return false;
+ }
+
+ /* identical objects are equal */
+ if (a == b)
+ {
+ return true;
+ }
+
+ switch (a->type & 0xFF)
+ {
+ /* in these cases and equal type is enough */
+ case cJSON_False:
+ case cJSON_True:
+ case cJSON_NULL:
+ return true;
+
+ case cJSON_Number:
+ if (a->valuedouble == b->valuedouble)
+ {
+ return true;
+ }
+ return false;
+
+ case cJSON_String:
+ case cJSON_Raw:
+ if ((a->valuestring == NULL) || (b->valuestring == NULL))
+ {
+ return false;
+ }
+ if (strcmp(a->valuestring, b->valuestring) == 0)
+ {
+ return true;
+ }
+
+ return false;
+
+ case cJSON_Array:
+ {
+ cJSON *a_element = a->child;
+ cJSON *b_element = b->child;
+
+ for (; (a_element != NULL) && (b_element != NULL);)
+ {
+ if (!cJSON_Compare(a_element, b_element, case_sensitive))
+ {
+ return false;
+ }
+
+ a_element = a_element->next;
+ b_element = b_element->next;
+ }
+
+ /* one of the arrays is longer than the other */
+ if (a_element != b_element) {
+ return false;
+ }
+
+ return true;
+ }
+
+ case cJSON_Object:
+ {
+ cJSON *a_element = NULL;
+ cJSON *b_element = NULL;
+ cJSON_ArrayForEach(a_element, a)
+ {
+ /* TODO This has O(n^2) runtime, which is horrible! */
+ b_element = get_object_item(b, a_element->string, case_sensitive);
+ if (b_element == NULL)
+ {
+ return false;
+ }
+
+ if (!cJSON_Compare(a_element, b_element, case_sensitive))
+ {
+ return false;
+ }
+ }
+
+ /* doing this twice, once on a and b to prevent true comparison if a subset of b
+ * TODO: Do this the proper way, this is just a fix for now */
+ cJSON_ArrayForEach(b_element, b)
+ {
+ a_element = get_object_item(a, b_element->string, case_sensitive);
+ if (a_element == NULL)
+ {
+ return false;
+ }
+
+ if (!cJSON_Compare(b_element, a_element, case_sensitive))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ default:
+ return false;
+ }
+}
+
+CJSON_PUBLIC(void *) cJSON_malloc(size_t size)
+{
+ return global_hooks.allocate(size);
+}
+
+CJSON_PUBLIC(void) cJSON_free(void *object)
+{
+ global_hooks.deallocate(object);
+}
diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external/tinyxml2/tinyxml2.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external/tinyxml2/tinyxml2.cpp
index b880ff007d..ebe0fd9eec 100644
--- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external/tinyxml2/tinyxml2.cpp
+++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external/tinyxml2/tinyxml2.cpp
@@ -1,2802 +1,2802 @@
-/*
-Original code by Lee Thomason (www.grinninglizard.com)
-
-This software is provided 'as-is', without any express or implied
-warranty. In no event will the authors be held liable for any
-damages arising from the use of this software.
-
-Permission is granted to anyone to use this software for any
-purpose, including commercial applications, and to alter it and
-redistribute it freely, subject to the following restrictions:
-
-1. The origin of this software must not be misrepresented; you must
-not claim that you wrote the original software. If you use this
-software in a product, an acknowledgment in the product documentation
-would be appreciated but is not required.
-
-2. Altered source versions must be plainly marked as such, and
-must not be misrepresented as being the original software.
-
-3. This notice may not be removed or altered from any source
-distribution.
-*/
-
-/*
-This file has been modified from its original version by Amazon:
- (1) Memory management operations use aws memory management api
- (2) #includes all use <>
-*/
-
-#include <aws/core/external/tinyxml2/tinyxml2.h>
-
-#include <new> // yes, this one new style header, is in the Android SDK.
-#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
-# include <stddef.h>
-# include <stdarg.h>
-#else
-# include <cstddef>
-# include <cstdarg>
-#endif
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
- // Microsoft Visual Studio, version 2005 and higher. Not WinCE.
- /*int _snprintf_s(
- char *buffer,
- size_t sizeOfBuffer,
- size_t count,
- const char *format [,
- argument] ...
- );*/
- static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
- {
- va_list va;
- va_start( va, format );
- int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
- va_end( va );
- return result;
- }
-
- static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
- {
- int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
- return result;
- }
-
- #define TIXML_VSCPRINTF _vscprintf
- #define TIXML_SSCANF sscanf_s
-#elif defined _MSC_VER
- // Microsoft Visual Studio 2003 and earlier or WinCE
- #define TIXML_SNPRINTF _snprintf
- #define TIXML_VSNPRINTF _vsnprintf
- #define TIXML_SSCANF sscanf
- #if (_MSC_VER < 1400 ) && (!defined WINCE)
- // Microsoft Visual Studio 2003 and not WinCE.
- #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
- #else
- // Microsoft Visual Studio 2003 and earlier or WinCE.
- static inline int TIXML_VSCPRINTF( const char* format, va_list va )
- {
- int len = 512;
- for (;;) {
- len = len*2;
- char* str = Aws::NewArray<char>(len, ALLOCATION_TAG);
- const int required = _vsnprintf(str, len, format, va);
- Aws::DeleteArray(str);
- if ( required != -1 ) {
- TIXMLASSERT( required >= 0 );
- len = required;
- break;
- }
- }
- TIXMLASSERT( len >= 0 );
- return len;
- }
- #endif
-#else
- // GCC version 3 and higher
- //#warning( "Using sn* functions." )
- #define TIXML_SNPRINTF snprintf
- #define TIXML_VSNPRINTF vsnprintf
- static inline int TIXML_VSCPRINTF( const char* format, va_list va )
- {
- int len = vsnprintf( 0, 0, format, va );
- TIXMLASSERT( len >= 0 );
- return len;
- }
- #define TIXML_SSCANF sscanf
-#endif
-
-
-static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
-static const char LF = LINE_FEED;
-static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
-static const char CR = CARRIAGE_RETURN;
-static const char SINGLE_QUOTE = '\'';
-static const char DOUBLE_QUOTE = '\"';
-
-// Bunch of unicode info at:
-// http://www.unicode.org/faq/utf_bom.html
-// ef bb bf (Microsoft "lead bytes") - designates UTF-8
-
-static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
-static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
-static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
-
-namespace Aws
-{
-namespace External
-{
-namespace tinyxml2
-{
-
-struct Entity {
- const char* pattern;
- int length;
- char value;
-};
-
-static const int NUM_ENTITIES = 5;
-static const Entity entities[NUM_ENTITIES] = {
- { "quot", 4, DOUBLE_QUOTE },
- { "amp", 3, '&' },
- { "apos", 4, SINGLE_QUOTE },
- { "lt", 2, '<' },
- { "gt", 2, '>' }
-};
-
-
-StrPair::~StrPair()
-{
- Reset();
-}
-
-
-void StrPair::TransferTo( StrPair* other )
-{
- if ( this == other ) {
- return;
- }
- // This in effect implements the assignment operator by "moving"
- // ownership (as in auto_ptr).
-
- TIXMLASSERT( other != 0 );
- TIXMLASSERT( other->_flags == 0 );
- TIXMLASSERT( other->_start == 0 );
- TIXMLASSERT( other->_end == 0 );
-
- other->Reset();
-
- other->_flags = _flags;
- other->_start = _start;
- other->_end = _end;
-
- _flags = 0;
- _start = 0;
- _end = 0;
-}
-
-
-void StrPair::Reset()
-{
- if ( _flags & NEEDS_DELETE ) {
- Aws::DeleteArray(_start);
- }
- _flags = 0;
- _start = 0;
- _end = 0;
-}
-
-
-void StrPair::SetStr( const char* str, int flags )
-{
- TIXMLASSERT( str );
- Reset();
- size_t len = strlen( str );
- TIXMLASSERT( _start == 0 );
- _start = Aws::NewArray<char>(len+1, ALLOCATION_TAG);
- memcpy( _start, str, len+1 );
- _end = _start + len;
- _flags = flags | NEEDS_DELETE;
-}
-
-
-char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )
-{
- TIXMLASSERT( p );
- TIXMLASSERT( endTag && *endTag );
- TIXMLASSERT(curLineNumPtr);
-
- char* start = p;
- char endChar = *endTag;
- size_t length = strlen( endTag );
-
- // Inner loop of text parsing.
- while ( *p ) {
- if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
- Set( start, p, strFlags );
- return p + length;
- } else if (*p == '\n') {
- ++(*curLineNumPtr);
- }
- ++p;
- TIXMLASSERT( p );
- }
- return 0;
-}
-
-
-char* StrPair::ParseName( char* p )
-{
- if ( !p || !(*p) ) {
- return 0;
- }
- if ( !XMLUtil::IsNameStartChar( *p ) ) {
- return 0;
- }
-
- char* const start = p;
- ++p;
- while ( *p && XMLUtil::IsNameChar( *p ) ) {
- ++p;
- }
-
- Set( start, p, 0 );
- return p;
-}
-
-
-void StrPair::CollapseWhitespace()
-{
- // Adjusting _start would cause undefined behavior on delete[]
- TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
- // Trim leading space.
- _start = XMLUtil::SkipWhiteSpace( _start, 0 );
-
- if ( *_start ) {
- const char* p = _start; // the read pointer
- char* q = _start; // the write pointer
-
- while( *p ) {
- if ( XMLUtil::IsWhiteSpace( *p )) {
- p = XMLUtil::SkipWhiteSpace( p, 0 );
- if ( *p == 0 ) {
- break; // don't write to q; this trims the trailing space.
- }
- *q = ' ';
- ++q;
- }
- *q = *p;
- ++q;
- ++p;
- }
- *q = 0;
- }
-}
-
-
-const char* StrPair::GetStr()
-{
- TIXMLASSERT( _start );
- TIXMLASSERT( _end );
- if ( _flags & NEEDS_FLUSH ) {
- *_end = 0;
- _flags ^= NEEDS_FLUSH;
-
- if ( _flags ) {
- const char* p = _start; // the read pointer
- char* q = _start; // the write pointer
-
- while( p < _end ) {
- if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
- // CR-LF pair becomes LF
- // CR alone becomes LF
- // LF-CR becomes LF
- if ( *(p+1) == LF ) {
- p += 2;
- }
- else {
- ++p;
- }
- *q = LF;
- ++q;
- }
- else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
- if ( *(p+1) == CR ) {
- p += 2;
- }
- else {
- ++p;
- }
- *q = LF;
- ++q;
- }
- else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
- // Entities handled by tinyXML2:
- // - special entities in the entity table [in/out]
- // - numeric character reference [in]
- // &#20013; or &#x4e2d;
-
- if ( *(p+1) == '#' ) {
- const int buflen = 10;
- char buf[buflen] = { 0 };
- int len = 0;
- char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
- if ( adjusted == 0 ) {
- *q = *p;
- ++p;
- ++q;
- }
- else {
- TIXMLASSERT( 0 <= len && len <= buflen );
- TIXMLASSERT( q + len <= adjusted );
- p = adjusted;
- memcpy( q, buf, len );
- q += len;
- }
- }
- else {
- bool entityFound = false;
- for( int i = 0; i < NUM_ENTITIES; ++i ) {
- const Entity& entity = entities[i];
- if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
- && *( p + entity.length + 1 ) == ';' ) {
- // Found an entity - convert.
- *q = entity.value;
- ++q;
- p += entity.length + 2;
- entityFound = true;
- break;
- }
- }
- if ( !entityFound ) {
- // fixme: treat as error?
- ++p;
- ++q;
- }
- }
- }
- else {
- *q = *p;
- ++p;
- ++q;
- }
- }
- *q = 0;
- }
- // The loop below has plenty going on, and this
- // is a less useful mode. Break it out.
- if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
- CollapseWhitespace();
- }
- _flags = (_flags & NEEDS_DELETE);
- }
- TIXMLASSERT( _start );
- return _start;
-}
-
-
-
-
-// --------- XMLUtil ----------- //
-
-const char* XMLUtil::writeBoolTrue = "true";
-const char* XMLUtil::writeBoolFalse = "false";
-
-void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)
-{
- static const char* defTrue = "true";
- static const char* defFalse = "false";
-
- writeBoolTrue = (writeTrue) ? writeTrue : defTrue;
- writeBoolFalse = (writeFalse) ? writeFalse : defFalse;
-}
-
-
-const char* XMLUtil::ReadBOM( const char* p, bool* bom )
-{
- TIXMLASSERT( p );
- TIXMLASSERT( bom );
- *bom = false;
- const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
- // Check for BOM:
- if ( *(pu+0) == TIXML_UTF_LEAD_0
- && *(pu+1) == TIXML_UTF_LEAD_1
- && *(pu+2) == TIXML_UTF_LEAD_2 ) {
- *bom = true;
- p += 3;
- }
- TIXMLASSERT( p );
- return p;
-}
-
-
-void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
-{
- const unsigned long BYTE_MASK = 0xBF;
- const unsigned long BYTE_MARK = 0x80;
- const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
-
- if (input < 0x80) {
- *length = 1;
- }
- else if ( input < 0x800 ) {
- *length = 2;
- }
- else if ( input < 0x10000 ) {
- *length = 3;
- }
- else if ( input < 0x200000 ) {
- *length = 4;
- }
- else {
- *length = 0; // This code won't convert this correctly anyway.
- return;
- }
-
- output += *length;
-
- // Scary scary fall throughs are annotated with carefully designed comments
- // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc
- switch (*length) {
- case 4:
- --output;
- *output = (char)((input | BYTE_MARK) & BYTE_MASK);
- input >>= 6;
- //fall through
- case 3:
- --output;
- *output = (char)((input | BYTE_MARK) & BYTE_MASK);
- input >>= 6;
- //fall through
- case 2:
- --output;
- *output = (char)((input | BYTE_MARK) & BYTE_MASK);
- input >>= 6;
- //fall through
- case 1:
- --output;
- *output = (char)(input | FIRST_BYTE_MARK[*length]);
- break;
- default:
- TIXMLASSERT( false );
- }
-}
-
-
-const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
-{
- // Presume an entity, and pull it out.
- *length = 0;
-
- if ( *(p+1) == '#' && *(p+2) ) {
- unsigned long ucs = 0;
- TIXMLASSERT( sizeof( ucs ) >= 4 );
- ptrdiff_t delta = 0;
- unsigned mult = 1;
- static const char SEMICOLON = ';';
-
- if ( *(p+2) == 'x' ) {
- // Hexadecimal.
- const char* q = p+3;
- if ( !(*q) ) {
- return 0;
- }
-
- q = strchr( q, SEMICOLON );
-
- if ( !q ) {
- return 0;
- }
- TIXMLASSERT( *q == SEMICOLON );
-
- delta = q-p;
- --q;
-
- while ( *q != 'x' ) {
- unsigned int digit = 0;
-
- if ( *q >= '0' && *q <= '9' ) {
- digit = *q - '0';
- }
- else if ( *q >= 'a' && *q <= 'f' ) {
- digit = *q - 'a' + 10;
- }
- else if ( *q >= 'A' && *q <= 'F' ) {
- digit = *q - 'A' + 10;
- }
- else {
- return 0;
- }
- TIXMLASSERT( digit < 16 );
- TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
- const unsigned int digitScaled = mult * digit;
- TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
- ucs += digitScaled;
- TIXMLASSERT( mult <= UINT_MAX / 16 );
- mult *= 16;
- --q;
- }
- }
- else {
- // Decimal.
- const char* q = p+2;
- if ( !(*q) ) {
- return 0;
- }
-
- q = strchr( q, SEMICOLON );
-
- if ( !q ) {
- return 0;
- }
- TIXMLASSERT( *q == SEMICOLON );
-
- delta = q-p;
- --q;
-
- while ( *q != '#' ) {
- if ( *q >= '0' && *q <= '9' ) {
- const unsigned int digit = *q - '0';
- TIXMLASSERT( digit < 10 );
- TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
- const unsigned int digitScaled = mult * digit;
- TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
- ucs += digitScaled;
- }
- else {
- return 0;
- }
- TIXMLASSERT( mult <= UINT_MAX / 10 );
- mult *= 10;
- --q;
- }
- }
- // convert the UCS to UTF-8
- ConvertUTF32ToUTF8( ucs, value, length );
- return p + delta + 1;
- }
- return p+1;
-}
-
-
-void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
-{
- TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
-}
-
-
-void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
-{
- TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
-}
-
-
-void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
-{
- TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);
-}
-
-/*
- ToStr() of a number is a very tricky topic.
- https://github.com/leethomason/tinyxml2/issues/106
-*/
-void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
-{
- TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
-}
-
-
-void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
-{
- TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
-}
-
-
-void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
-{
- // horrible syntax trick to make the compiler happy about %lld
- TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
-}
-
-
-bool XMLUtil::ToInt( const char* str, int* value )
-{
- if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
- return true;
- }
- return false;
-}
-
-bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
-{
- if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
- return true;
- }
- return false;
-}
-
-bool XMLUtil::ToBool( const char* str, bool* value )
-{
- int ival = 0;
- if ( ToInt( str, &ival )) {
- *value = (ival==0) ? false : true;
- return true;
- }
- if ( StringEqual( str, "true" ) ) {
- *value = true;
- return true;
- }
- else if ( StringEqual( str, "false" ) ) {
- *value = false;
- return true;
- }
- return false;
-}
-
-
-bool XMLUtil::ToFloat( const char* str, float* value )
-{
- if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
- return true;
- }
- return false;
-}
-
-
-bool XMLUtil::ToDouble( const char* str, double* value )
-{
- if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
- return true;
- }
- return false;
-}
-
-
-bool XMLUtil::ToInt64(const char* str, int64_t* value)
-{
- long long v = 0; // horrible syntax trick to make the compiler happy about %lld
- if (TIXML_SSCANF(str, "%lld", &v) == 1) {
- *value = (int64_t)v;
- return true;
- }
- return false;
-}
-
-
-char* XMLDocument::Identify( char* p, XMLNode** node )
-{
- TIXMLASSERT( node );
- TIXMLASSERT( p );
- char* const start = p;
- int const startLine = _parseCurLineNum;
- p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
- if( !*p ) {
- *node = 0;
- TIXMLASSERT( p );
- return p;
- }
-
- // These strings define the matching patterns:
- static const char* xmlHeader = { "<?" };
- static const char* commentHeader = { "<!--" };
- static const char* cdataHeader = { "<![CDATA[" };
- static const char* dtdHeader = { "<!" };
- static const char* elementHeader = { "<" }; // and a header for everything else; check last.
-
- static const int xmlHeaderLen = 2;
- static const int commentHeaderLen = 4;
- static const int cdataHeaderLen = 9;
- static const int dtdHeaderLen = 2;
- static const int elementHeaderLen = 1;
-
- TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
- TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
- XMLNode* returnNode = 0;
- if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
- returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
- returnNode->_parseLineNum = _parseCurLineNum;
- p += xmlHeaderLen;
- }
- else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
- returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
- returnNode->_parseLineNum = _parseCurLineNum;
- p += commentHeaderLen;
- }
- else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
- XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
- returnNode = text;
- returnNode->_parseLineNum = _parseCurLineNum;
- p += cdataHeaderLen;
- text->SetCData( true );
- }
- else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
- returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
- returnNode->_parseLineNum = _parseCurLineNum;
- p += dtdHeaderLen;
- }
- else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
- returnNode = CreateUnlinkedNode<XMLElement>( _elementPool );
- returnNode->_parseLineNum = _parseCurLineNum;
- p += elementHeaderLen;
- }
- else {
- returnNode = CreateUnlinkedNode<XMLText>( _textPool );
- returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
- p = start; // Back it up, all the text counts.
- _parseCurLineNum = startLine;
- }
-
- TIXMLASSERT( returnNode );
- TIXMLASSERT( p );
- *node = returnNode;
- return p;
-}
-
-
-bool XMLDocument::Accept( XMLVisitor* visitor ) const
-{
- TIXMLASSERT( visitor );
- if ( visitor->VisitEnter( *this ) ) {
- for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
- if ( !node->Accept( visitor ) ) {
- break;
- }
- }
- }
- return visitor->VisitExit( *this );
-}
-
-
-// --------- XMLNode ----------- //
-
-XMLNode::XMLNode( XMLDocument* doc ) :
- _document( doc ),
- _parent( 0 ),
- _value(),
- _parseLineNum( 0 ),
- _firstChild( 0 ), _lastChild( 0 ),
- _prev( 0 ), _next( 0 ),
- _userData( 0 ),
- _memPool( 0 )
-{
-}
-
-
-XMLNode::~XMLNode()
-{
- DeleteChildren();
- if ( _parent ) {
- _parent->Unlink( this );
- }
-}
-
+/*
+Original code by Lee Thomason (www.grinninglizard.com)
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must
+not claim that you wrote the original software. If you use this
+software in a product, an acknowledgment in the product documentation
+would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+*/
+
+/*
+This file has been modified from its original version by Amazon:
+ (1) Memory management operations use aws memory management api
+ (2) #includes all use <>
+*/
+
+#include <aws/core/external/tinyxml2/tinyxml2.h>
+
+#include <new> // yes, this one new style header, is in the Android SDK.
+#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
+# include <stddef.h>
+# include <stdarg.h>
+#else
+# include <cstddef>
+# include <cstdarg>
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
+ // Microsoft Visual Studio, version 2005 and higher. Not WinCE.
+ /*int _snprintf_s(
+ char *buffer,
+ size_t sizeOfBuffer,
+ size_t count,
+ const char *format [,
+ argument] ...
+ );*/
+ static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
+ {
+ va_list va;
+ va_start( va, format );
+ int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
+ va_end( va );
+ return result;
+ }
+
+ static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
+ {
+ int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
+ return result;
+ }
+
+ #define TIXML_VSCPRINTF _vscprintf
+ #define TIXML_SSCANF sscanf_s
+#elif defined _MSC_VER
+ // Microsoft Visual Studio 2003 and earlier or WinCE
+ #define TIXML_SNPRINTF _snprintf
+ #define TIXML_VSNPRINTF _vsnprintf
+ #define TIXML_SSCANF sscanf
+ #if (_MSC_VER < 1400 ) && (!defined WINCE)
+ // Microsoft Visual Studio 2003 and not WinCE.
+ #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
+ #else
+ // Microsoft Visual Studio 2003 and earlier or WinCE.
+ static inline int TIXML_VSCPRINTF( const char* format, va_list va )
+ {
+ int len = 512;
+ for (;;) {
+ len = len*2;
+ char* str = Aws::NewArray<char>(len, ALLOCATION_TAG);
+ const int required = _vsnprintf(str, len, format, va);
+ Aws::DeleteArray(str);
+ if ( required != -1 ) {
+ TIXMLASSERT( required >= 0 );
+ len = required;
+ break;
+ }
+ }
+ TIXMLASSERT( len >= 0 );
+ return len;
+ }
+ #endif
+#else
+ // GCC version 3 and higher
+ //#warning( "Using sn* functions." )
+ #define TIXML_SNPRINTF snprintf
+ #define TIXML_VSNPRINTF vsnprintf
+ static inline int TIXML_VSCPRINTF( const char* format, va_list va )
+ {
+ int len = vsnprintf( 0, 0, format, va );
+ TIXMLASSERT( len >= 0 );
+ return len;
+ }
+ #define TIXML_SSCANF sscanf
+#endif
+
+
+static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
+static const char LF = LINE_FEED;
+static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
+static const char CR = CARRIAGE_RETURN;
+static const char SINGLE_QUOTE = '\'';
+static const char DOUBLE_QUOTE = '\"';
+
+// Bunch of unicode info at:
+// http://www.unicode.org/faq/utf_bom.html
+// ef bb bf (Microsoft "lead bytes") - designates UTF-8
+
+static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
+static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
+static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
+
+namespace Aws
+{
+namespace External
+{
+namespace tinyxml2
+{
+
+struct Entity {
+ const char* pattern;
+ int length;
+ char value;
+};
+
+static const int NUM_ENTITIES = 5;
+static const Entity entities[NUM_ENTITIES] = {
+ { "quot", 4, DOUBLE_QUOTE },
+ { "amp", 3, '&' },
+ { "apos", 4, SINGLE_QUOTE },
+ { "lt", 2, '<' },
+ { "gt", 2, '>' }
+};
+
+
+StrPair::~StrPair()
+{
+ Reset();
+}
+
+
+void StrPair::TransferTo( StrPair* other )
+{
+ if ( this == other ) {
+ return;
+ }
+ // This in effect implements the assignment operator by "moving"
+ // ownership (as in auto_ptr).
+
+ TIXMLASSERT( other != 0 );
+ TIXMLASSERT( other->_flags == 0 );
+ TIXMLASSERT( other->_start == 0 );
+ TIXMLASSERT( other->_end == 0 );
+
+ other->Reset();
+
+ other->_flags = _flags;
+ other->_start = _start;
+ other->_end = _end;
+
+ _flags = 0;
+ _start = 0;
+ _end = 0;
+}
+
+
+void StrPair::Reset()
+{
+ if ( _flags & NEEDS_DELETE ) {
+ Aws::DeleteArray(_start);
+ }
+ _flags = 0;
+ _start = 0;
+ _end = 0;
+}
+
+
+void StrPair::SetStr( const char* str, int flags )
+{
+ TIXMLASSERT( str );
+ Reset();
+ size_t len = strlen( str );
+ TIXMLASSERT( _start == 0 );
+ _start = Aws::NewArray<char>(len+1, ALLOCATION_TAG);
+ memcpy( _start, str, len+1 );
+ _end = _start + len;
+ _flags = flags | NEEDS_DELETE;
+}
+
+
+char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )
+{
+ TIXMLASSERT( p );
+ TIXMLASSERT( endTag && *endTag );
+ TIXMLASSERT(curLineNumPtr);
+
+ char* start = p;
+ char endChar = *endTag;
+ size_t length = strlen( endTag );
+
+ // Inner loop of text parsing.
+ while ( *p ) {
+ if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
+ Set( start, p, strFlags );
+ return p + length;
+ } else if (*p == '\n') {
+ ++(*curLineNumPtr);
+ }
+ ++p;
+ TIXMLASSERT( p );
+ }
+ return 0;
+}
+
+
+char* StrPair::ParseName( char* p )
+{
+ if ( !p || !(*p) ) {
+ return 0;
+ }
+ if ( !XMLUtil::IsNameStartChar( *p ) ) {
+ return 0;
+ }
+
+ char* const start = p;
+ ++p;
+ while ( *p && XMLUtil::IsNameChar( *p ) ) {
+ ++p;
+ }
+
+ Set( start, p, 0 );
+ return p;
+}
+
+
+void StrPair::CollapseWhitespace()
+{
+ // Adjusting _start would cause undefined behavior on delete[]
+ TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
+ // Trim leading space.
+ _start = XMLUtil::SkipWhiteSpace( _start, 0 );
+
+ if ( *_start ) {
+ const char* p = _start; // the read pointer
+ char* q = _start; // the write pointer
+
+ while( *p ) {
+ if ( XMLUtil::IsWhiteSpace( *p )) {
+ p = XMLUtil::SkipWhiteSpace( p, 0 );
+ if ( *p == 0 ) {
+ break; // don't write to q; this trims the trailing space.
+ }
+ *q = ' ';
+ ++q;
+ }
+ *q = *p;
+ ++q;
+ ++p;
+ }
+ *q = 0;
+ }
+}
+
+
+const char* StrPair::GetStr()
+{
+ TIXMLASSERT( _start );
+ TIXMLASSERT( _end );
+ if ( _flags & NEEDS_FLUSH ) {
+ *_end = 0;
+ _flags ^= NEEDS_FLUSH;
+
+ if ( _flags ) {
+ const char* p = _start; // the read pointer
+ char* q = _start; // the write pointer
+
+ while( p < _end ) {
+ if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
+ // CR-LF pair becomes LF
+ // CR alone becomes LF
+ // LF-CR becomes LF
+ if ( *(p+1) == LF ) {
+ p += 2;
+ }
+ else {
+ ++p;
+ }
+ *q = LF;
+ ++q;
+ }
+ else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
+ if ( *(p+1) == CR ) {
+ p += 2;
+ }
+ else {
+ ++p;
+ }
+ *q = LF;
+ ++q;
+ }
+ else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
+ // Entities handled by tinyXML2:
+ // - special entities in the entity table [in/out]
+ // - numeric character reference [in]
+ // &#20013; or &#x4e2d;
+
+ if ( *(p+1) == '#' ) {
+ const int buflen = 10;
+ char buf[buflen] = { 0 };
+ int len = 0;
+ char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
+ if ( adjusted == 0 ) {
+ *q = *p;
+ ++p;
+ ++q;
+ }
+ else {
+ TIXMLASSERT( 0 <= len && len <= buflen );
+ TIXMLASSERT( q + len <= adjusted );
+ p = adjusted;
+ memcpy( q, buf, len );
+ q += len;
+ }
+ }
+ else {
+ bool entityFound = false;
+ for( int i = 0; i < NUM_ENTITIES; ++i ) {
+ const Entity& entity = entities[i];
+ if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
+ && *( p + entity.length + 1 ) == ';' ) {
+ // Found an entity - convert.
+ *q = entity.value;
+ ++q;
+ p += entity.length + 2;
+ entityFound = true;
+ break;
+ }
+ }
+ if ( !entityFound ) {
+ // fixme: treat as error?
+ ++p;
+ ++q;
+ }
+ }
+ }
+ else {
+ *q = *p;
+ ++p;
+ ++q;
+ }
+ }
+ *q = 0;
+ }
+ // The loop below has plenty going on, and this
+ // is a less useful mode. Break it out.
+ if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
+ CollapseWhitespace();
+ }
+ _flags = (_flags & NEEDS_DELETE);
+ }
+ TIXMLASSERT( _start );
+ return _start;
+}
+
+
+
+
+// --------- XMLUtil ----------- //
+
+const char* XMLUtil::writeBoolTrue = "true";
+const char* XMLUtil::writeBoolFalse = "false";
+
+void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)
+{
+ static const char* defTrue = "true";
+ static const char* defFalse = "false";
+
+ writeBoolTrue = (writeTrue) ? writeTrue : defTrue;
+ writeBoolFalse = (writeFalse) ? writeFalse : defFalse;
+}
+
+
+const char* XMLUtil::ReadBOM( const char* p, bool* bom )
+{
+ TIXMLASSERT( p );
+ TIXMLASSERT( bom );
+ *bom = false;
+ const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
+ // Check for BOM:
+ if ( *(pu+0) == TIXML_UTF_LEAD_0
+ && *(pu+1) == TIXML_UTF_LEAD_1
+ && *(pu+2) == TIXML_UTF_LEAD_2 ) {
+ *bom = true;
+ p += 3;
+ }
+ TIXMLASSERT( p );
+ return p;
+}
+
+
+void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
+{
+ const unsigned long BYTE_MASK = 0xBF;
+ const unsigned long BYTE_MARK = 0x80;
+ const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+ if (input < 0x80) {
+ *length = 1;
+ }
+ else if ( input < 0x800 ) {
+ *length = 2;
+ }
+ else if ( input < 0x10000 ) {
+ *length = 3;
+ }
+ else if ( input < 0x200000 ) {
+ *length = 4;
+ }
+ else {
+ *length = 0; // This code won't convert this correctly anyway.
+ return;
+ }
+
+ output += *length;
+
+ // Scary scary fall throughs are annotated with carefully designed comments
+ // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc
+ switch (*length) {
+ case 4:
+ --output;
+ *output = (char)((input | BYTE_MARK) & BYTE_MASK);
+ input >>= 6;
+ //fall through
+ case 3:
+ --output;
+ *output = (char)((input | BYTE_MARK) & BYTE_MASK);
+ input >>= 6;
+ //fall through
+ case 2:
+ --output;
+ *output = (char)((input | BYTE_MARK) & BYTE_MASK);
+ input >>= 6;
+ //fall through
+ case 1:
+ --output;
+ *output = (char)(input | FIRST_BYTE_MARK[*length]);
+ break;
+ default:
+ TIXMLASSERT( false );
+ }
+}
+
+
+const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
+{
+ // Presume an entity, and pull it out.
+ *length = 0;
+
+ if ( *(p+1) == '#' && *(p+2) ) {
+ unsigned long ucs = 0;
+ TIXMLASSERT( sizeof( ucs ) >= 4 );
+ ptrdiff_t delta = 0;
+ unsigned mult = 1;
+ static const char SEMICOLON = ';';
+
+ if ( *(p+2) == 'x' ) {
+ // Hexadecimal.
+ const char* q = p+3;
+ if ( !(*q) ) {
+ return 0;
+ }
+
+ q = strchr( q, SEMICOLON );
+
+ if ( !q ) {
+ return 0;
+ }
+ TIXMLASSERT( *q == SEMICOLON );
+
+ delta = q-p;
+ --q;
+
+ while ( *q != 'x' ) {
+ unsigned int digit = 0;
+
+ if ( *q >= '0' && *q <= '9' ) {
+ digit = *q - '0';
+ }
+ else if ( *q >= 'a' && *q <= 'f' ) {
+ digit = *q - 'a' + 10;
+ }
+ else if ( *q >= 'A' && *q <= 'F' ) {
+ digit = *q - 'A' + 10;
+ }
+ else {
+ return 0;
+ }
+ TIXMLASSERT( digit < 16 );
+ TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
+ const unsigned int digitScaled = mult * digit;
+ TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
+ ucs += digitScaled;
+ TIXMLASSERT( mult <= UINT_MAX / 16 );
+ mult *= 16;
+ --q;
+ }
+ }
+ else {
+ // Decimal.
+ const char* q = p+2;
+ if ( !(*q) ) {
+ return 0;
+ }
+
+ q = strchr( q, SEMICOLON );
+
+ if ( !q ) {
+ return 0;
+ }
+ TIXMLASSERT( *q == SEMICOLON );
+
+ delta = q-p;
+ --q;
+
+ while ( *q != '#' ) {
+ if ( *q >= '0' && *q <= '9' ) {
+ const unsigned int digit = *q - '0';
+ TIXMLASSERT( digit < 10 );
+ TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
+ const unsigned int digitScaled = mult * digit;
+ TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
+ ucs += digitScaled;
+ }
+ else {
+ return 0;
+ }
+ TIXMLASSERT( mult <= UINT_MAX / 10 );
+ mult *= 10;
+ --q;
+ }
+ }
+ // convert the UCS to UTF-8
+ ConvertUTF32ToUTF8( ucs, value, length );
+ return p + delta + 1;
+ }
+ return p+1;
+}
+
+
+void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
+{
+ TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
+}
+
+
+void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
+{
+ TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
+}
+
+
+void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
+{
+ TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);
+}
+
+/*
+ ToStr() of a number is a very tricky topic.
+ https://github.com/leethomason/tinyxml2/issues/106
+*/
+void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
+{
+ TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
+}
+
+
+void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
+{
+ TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
+}
+
+
+void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
+{
+ // horrible syntax trick to make the compiler happy about %lld
+ TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
+}
+
+
+bool XMLUtil::ToInt( const char* str, int* value )
+{
+ if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
+ return true;
+ }
+ return false;
+}
+
+bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
+{
+ if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
+ return true;
+ }
+ return false;
+}
+
+bool XMLUtil::ToBool( const char* str, bool* value )
+{
+ int ival = 0;
+ if ( ToInt( str, &ival )) {
+ *value = (ival==0) ? false : true;
+ return true;
+ }
+ if ( StringEqual( str, "true" ) ) {
+ *value = true;
+ return true;
+ }
+ else if ( StringEqual( str, "false" ) ) {
+ *value = false;
+ return true;
+ }
+ return false;
+}
+
+
+bool XMLUtil::ToFloat( const char* str, float* value )
+{
+ if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
+ return true;
+ }
+ return false;
+}
+
+
+bool XMLUtil::ToDouble( const char* str, double* value )
+{
+ if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
+ return true;
+ }
+ return false;
+}
+
+
+bool XMLUtil::ToInt64(const char* str, int64_t* value)
+{
+ long long v = 0; // horrible syntax trick to make the compiler happy about %lld
+ if (TIXML_SSCANF(str, "%lld", &v) == 1) {
+ *value = (int64_t)v;
+ return true;
+ }
+ return false;
+}
+
+
+char* XMLDocument::Identify( char* p, XMLNode** node )
+{
+ TIXMLASSERT( node );
+ TIXMLASSERT( p );
+ char* const start = p;
+ int const startLine = _parseCurLineNum;
+ p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
+ if( !*p ) {
+ *node = 0;
+ TIXMLASSERT( p );
+ return p;
+ }
+
+ // These strings define the matching patterns:
+ static const char* xmlHeader = { "<?" };
+ static const char* commentHeader = { "<!--" };
+ static const char* cdataHeader = { "<![CDATA[" };
+ static const char* dtdHeader = { "<!" };
+ static const char* elementHeader = { "<" }; // and a header for everything else; check last.
+
+ static const int xmlHeaderLen = 2;
+ static const int commentHeaderLen = 4;
+ static const int cdataHeaderLen = 9;
+ static const int dtdHeaderLen = 2;
+ static const int elementHeaderLen = 1;
+
+ TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
+ TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
+ XMLNode* returnNode = 0;
+ if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
+ returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
+ returnNode->_parseLineNum = _parseCurLineNum;
+ p += xmlHeaderLen;
+ }
+ else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
+ returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
+ returnNode->_parseLineNum = _parseCurLineNum;
+ p += commentHeaderLen;
+ }
+ else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
+ XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
+ returnNode = text;
+ returnNode->_parseLineNum = _parseCurLineNum;
+ p += cdataHeaderLen;
+ text->SetCData( true );
+ }
+ else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
+ returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
+ returnNode->_parseLineNum = _parseCurLineNum;
+ p += dtdHeaderLen;
+ }
+ else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
+ returnNode = CreateUnlinkedNode<XMLElement>( _elementPool );
+ returnNode->_parseLineNum = _parseCurLineNum;
+ p += elementHeaderLen;
+ }
+ else {
+ returnNode = CreateUnlinkedNode<XMLText>( _textPool );
+ returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
+ p = start; // Back it up, all the text counts.
+ _parseCurLineNum = startLine;
+ }
+
+ TIXMLASSERT( returnNode );
+ TIXMLASSERT( p );
+ *node = returnNode;
+ return p;
+}
+
+
+bool XMLDocument::Accept( XMLVisitor* visitor ) const
+{
+ TIXMLASSERT( visitor );
+ if ( visitor->VisitEnter( *this ) ) {
+ for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
+ if ( !node->Accept( visitor ) ) {
+ break;
+ }
+ }
+ }
+ return visitor->VisitExit( *this );
+}
+
+
+// --------- XMLNode ----------- //
+
+XMLNode::XMLNode( XMLDocument* doc ) :
+ _document( doc ),
+ _parent( 0 ),
+ _value(),
+ _parseLineNum( 0 ),
+ _firstChild( 0 ), _lastChild( 0 ),
+ _prev( 0 ), _next( 0 ),
+ _userData( 0 ),
+ _memPool( 0 )
+{
+}
+
+
+XMLNode::~XMLNode()
+{
+ DeleteChildren();
+ if ( _parent ) {
+ _parent->Unlink( this );
+ }
+}
+
const char* XMLNode::Value() const
-{
- // Edge case: XMLDocuments don't have a Value. Return null.
- if ( this->ToDocument() )
- return 0;
- return _value.GetStr();
-}
-
-void XMLNode::SetValue( const char* str, bool staticMem )
-{
- if ( staticMem ) {
- _value.SetInternedStr( str );
- }
- else {
- _value.SetStr( str );
- }
-}
-
-XMLNode* XMLNode::DeepClone(XMLDocument* target) const
-{
- XMLNode* clone = this->ShallowClone(target);
- if (!clone) return 0;
-
- for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
- XMLNode* childClone = child->DeepClone(target);
- TIXMLASSERT(childClone);
- clone->InsertEndChild(childClone);
- }
- return clone;
-}
-
-void XMLNode::DeleteChildren()
-{
- while( _firstChild ) {
- TIXMLASSERT( _lastChild );
- DeleteChild( _firstChild );
- }
- _firstChild = _lastChild = 0;
-}
-
-
-void XMLNode::Unlink( XMLNode* child )
-{
- TIXMLASSERT( child );
- TIXMLASSERT( child->_document == _document );
- TIXMLASSERT( child->_parent == this );
- if ( child == _firstChild ) {
- _firstChild = _firstChild->_next;
- }
- if ( child == _lastChild ) {
- _lastChild = _lastChild->_prev;
- }
-
- if ( child->_prev ) {
- child->_prev->_next = child->_next;
- }
- if ( child->_next ) {
- child->_next->_prev = child->_prev;
- }
- child->_next = 0;
- child->_prev = 0;
- child->_parent = 0;
-}
-
-
-void XMLNode::DeleteChild( XMLNode* node )
-{
- TIXMLASSERT( node );
- TIXMLASSERT( node->_document == _document );
- TIXMLASSERT( node->_parent == this );
- Unlink( node );
- TIXMLASSERT(node->_prev == 0);
- TIXMLASSERT(node->_next == 0);
- TIXMLASSERT(node->_parent == 0);
- DeleteNode( node );
-}
-
-
-XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
-{
- TIXMLASSERT( addThis );
- if ( addThis->_document != _document ) {
- TIXMLASSERT( false );
- return 0;
- }
- InsertChildPreamble( addThis );
-
- if ( _lastChild ) {
- TIXMLASSERT( _firstChild );
- TIXMLASSERT( _lastChild->_next == 0 );
- _lastChild->_next = addThis;
- addThis->_prev = _lastChild;
- _lastChild = addThis;
-
- addThis->_next = 0;
- }
- else {
- TIXMLASSERT( _firstChild == 0 );
- _firstChild = _lastChild = addThis;
-
- addThis->_prev = 0;
- addThis->_next = 0;
- }
- addThis->_parent = this;
- return addThis;
-}
-
-
-XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
-{
- TIXMLASSERT( addThis );
- if ( addThis->_document != _document ) {
- TIXMLASSERT( false );
- return 0;
- }
- InsertChildPreamble( addThis );
-
- if ( _firstChild ) {
- TIXMLASSERT( _lastChild );
- TIXMLASSERT( _firstChild->_prev == 0 );
-
- _firstChild->_prev = addThis;
- addThis->_next = _firstChild;
- _firstChild = addThis;
-
- addThis->_prev = 0;
- }
- else {
- TIXMLASSERT( _lastChild == 0 );
- _firstChild = _lastChild = addThis;
-
- addThis->_prev = 0;
- addThis->_next = 0;
- }
- addThis->_parent = this;
- return addThis;
-}
-
-
-XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
-{
- TIXMLASSERT( addThis );
- if ( addThis->_document != _document ) {
- TIXMLASSERT( false );
- return 0;
- }
-
- TIXMLASSERT( afterThis );
-
- if ( afterThis->_parent != this ) {
- TIXMLASSERT( false );
- return 0;
- }
- if ( afterThis == addThis ) {
- // Current state: BeforeThis -> AddThis -> OneAfterAddThis
- // Now AddThis must disappear from it's location and then
- // reappear between BeforeThis and OneAfterAddThis.
- // So just leave it where it is.
- return addThis;
- }
-
- if ( afterThis->_next == 0 ) {
- // The last node or the only node.
- return InsertEndChild( addThis );
- }
- InsertChildPreamble( addThis );
- addThis->_prev = afterThis;
- addThis->_next = afterThis->_next;
- afterThis->_next->_prev = addThis;
- afterThis->_next = addThis;
- addThis->_parent = this;
- return addThis;
-}
-
-
-
-
-const XMLElement* XMLNode::FirstChildElement( const char* name ) const
-{
- for( const XMLNode* node = _firstChild; node; node = node->_next ) {
- const XMLElement* element = node->ToElementWithName( name );
- if ( element ) {
- return element;
- }
- }
- return 0;
-}
-
-
-const XMLElement* XMLNode::LastChildElement( const char* name ) const
-{
- for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
- const XMLElement* element = node->ToElementWithName( name );
- if ( element ) {
- return element;
- }
- }
- return 0;
-}
-
-
-const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
-{
- for( const XMLNode* node = _next; node; node = node->_next ) {
- const XMLElement* element = node->ToElementWithName( name );
- if ( element ) {
- return element;
- }
- }
- return 0;
-}
-
-
-const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
-{
- for( const XMLNode* node = _prev; node; node = node->_prev ) {
- const XMLElement* element = node->ToElementWithName( name );
- if ( element ) {
- return element;
- }
- }
- return 0;
-}
-
-
-char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
-{
- // This is a recursive method, but thinking about it "at the current level"
- // it is a pretty simple flat list:
- // <foo/>
- // <!-- comment -->
- //
- // With a special case:
- // <foo>
- // </foo>
- // <!-- comment -->
- //
- // Where the closing element (/foo) *must* be the next thing after the opening
- // element, and the names must match. BUT the tricky bit is that the closing
- // element will be read by the child.
- //
- // 'endTag' is the end tag for this node, it is returned by a call to a child.
- // 'parentEnd' is the end tag for the parent, which is filled in and returned.
-
- while( p && *p ) {
- XMLNode* node = 0;
-
- p = _document->Identify( p, &node );
- TIXMLASSERT( p );
- if ( node == 0 ) {
- break;
- }
-
- int initialLineNum = node->_parseLineNum;
-
- StrPair endTag;
- p = node->ParseDeep( p, &endTag, curLineNumPtr );
- if ( !p ) {
- DeleteNode( node );
- if ( !_document->Error() ) {
- _document->SetError( XML_ERROR_PARSING, initialLineNum, 0);
- }
- break;
- }
-
- XMLDeclaration* decl = node->ToDeclaration();
- if ( decl ) {
- // Declarations are only allowed at document level
- bool wellLocated = ( ToDocument() != 0 );
- if ( wellLocated ) {
- // Multiple declarations are allowed but all declarations
- // must occur before anything else
- for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
- if ( !existingNode->ToDeclaration() ) {
- wellLocated = false;
- break;
- }
- }
- }
- if ( !wellLocated ) {
- _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value());
- DeleteNode( node );
- break;
- }
- }
-
- XMLElement* ele = node->ToElement();
- if ( ele ) {
- // We read the end tag. Return it to the parent.
- if ( ele->ClosingType() == XMLElement::CLOSING ) {
- if ( parentEndTag ) {
- ele->_value.TransferTo( parentEndTag );
- }
- node->_memPool->SetTracked(); // created and then immediately deleted.
- DeleteNode( node );
- return p;
- }
-
- // Handle an end tag returned to this level.
- // And handle a bunch of annoying errors.
- bool mismatch = false;
- if ( endTag.Empty() ) {
- if ( ele->ClosingType() == XMLElement::OPEN ) {
- mismatch = true;
- }
- }
- else {
- if ( ele->ClosingType() != XMLElement::OPEN ) {
- mismatch = true;
- }
- else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
- mismatch = true;
- }
- }
- if ( mismatch ) {
- _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name());
- DeleteNode( node );
- break;
- }
- }
- InsertEndChild( node );
- }
- return 0;
-}
-
-/*static*/ void XMLNode::DeleteNode( XMLNode* node )
-{
- if ( node == 0 ) {
- return;
- }
- TIXMLASSERT(node->_document);
- if (!node->ToDocument()) {
- node->_document->MarkInUse(node);
- }
-
- MemPool* pool = node->_memPool;
- node->~XMLNode();
- pool->Free( node );
-}
-
-void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
-{
- TIXMLASSERT( insertThis );
- TIXMLASSERT( insertThis->_document == _document );
-
- if (insertThis->_parent) {
- insertThis->_parent->Unlink( insertThis );
- }
- else {
- insertThis->_document->MarkInUse(insertThis);
- insertThis->_memPool->SetTracked();
- }
-}
-
-const XMLElement* XMLNode::ToElementWithName( const char* name ) const
-{
- const XMLElement* element = this->ToElement();
- if ( element == 0 ) {
- return 0;
- }
- if ( name == 0 ) {
- return element;
- }
- if ( XMLUtil::StringEqual( element->Name(), name ) ) {
- return element;
- }
- return 0;
-}
-
-// --------- XMLText ---------- //
-char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
-{
- if ( this->CData() ) {
- p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
- if ( !p ) {
- _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );
- }
- return p;
- }
- else {
- int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
- if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
- flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
- }
-
- p = _value.ParseText( p, "<", flags, curLineNumPtr );
- if ( p && *p ) {
- return p-1;
- }
- if ( !p ) {
- _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );
- }
- }
- return 0;
-}
-
-
-XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
-{
- if ( !doc ) {
- doc = _document;
- }
- XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
- text->SetCData( this->CData() );
- return text;
-}
-
-
-bool XMLText::ShallowEqual( const XMLNode* compare ) const
-{
- TIXMLASSERT( compare );
- const XMLText* text = compare->ToText();
- return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
-}
-
-
-bool XMLText::Accept( XMLVisitor* visitor ) const
-{
- TIXMLASSERT( visitor );
- return visitor->Visit( *this );
-}
-
-
-// --------- XMLComment ---------- //
-
-XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
-{
-}
-
-
-XMLComment::~XMLComment()
-{
-}
-
-
-char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
-{
- // Comment parses as text.
- p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
- if ( p == 0 ) {
- _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );
- }
- return p;
-}
-
-
-XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
-{
- if ( !doc ) {
- doc = _document;
- }
- XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
- return comment;
-}
-
-
-bool XMLComment::ShallowEqual( const XMLNode* compare ) const
-{
- TIXMLASSERT( compare );
- const XMLComment* comment = compare->ToComment();
- return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
-}
-
-
-bool XMLComment::Accept( XMLVisitor* visitor ) const
-{
- TIXMLASSERT( visitor );
- return visitor->Visit( *this );
-}
-
-
-// --------- XMLDeclaration ---------- //
-
-XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
-{
-}
-
-
-XMLDeclaration::~XMLDeclaration()
-{
- //printf( "~XMLDeclaration\n" );
-}
-
-
-char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
-{
- // Declaration parses as text.
- p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
- if ( p == 0 ) {
- _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );
- }
- return p;
-}
-
-
-XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
-{
- if ( !doc ) {
- doc = _document;
- }
- XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
- return dec;
-}
-
-
-bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
-{
- TIXMLASSERT( compare );
- const XMLDeclaration* declaration = compare->ToDeclaration();
- return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
-}
-
-
-
-bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
-{
- TIXMLASSERT( visitor );
- return visitor->Visit( *this );
-}
-
-// --------- XMLUnknown ---------- //
-
-XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
-{
-}
-
-
-XMLUnknown::~XMLUnknown()
-{
-}
-
-
-char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
-{
- // Unknown parses as text.
- p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
- if ( !p ) {
- _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );
- }
- return p;
-}
-
-
-XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
-{
- if ( !doc ) {
- doc = _document;
- }
- XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
- return text;
-}
-
-
-bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
-{
- TIXMLASSERT( compare );
- const XMLUnknown* unknown = compare->ToUnknown();
- return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
-}
-
-
-bool XMLUnknown::Accept( XMLVisitor* visitor ) const
-{
- TIXMLASSERT( visitor );
- return visitor->Visit( *this );
-}
-
-// --------- XMLAttribute ---------- //
-
+{
+ // Edge case: XMLDocuments don't have a Value. Return null.
+ if ( this->ToDocument() )
+ return 0;
+ return _value.GetStr();
+}
+
+void XMLNode::SetValue( const char* str, bool staticMem )
+{
+ if ( staticMem ) {
+ _value.SetInternedStr( str );
+ }
+ else {
+ _value.SetStr( str );
+ }
+}
+
+XMLNode* XMLNode::DeepClone(XMLDocument* target) const
+{
+ XMLNode* clone = this->ShallowClone(target);
+ if (!clone) return 0;
+
+ for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
+ XMLNode* childClone = child->DeepClone(target);
+ TIXMLASSERT(childClone);
+ clone->InsertEndChild(childClone);
+ }
+ return clone;
+}
+
+void XMLNode::DeleteChildren()
+{
+ while( _firstChild ) {
+ TIXMLASSERT( _lastChild );
+ DeleteChild( _firstChild );
+ }
+ _firstChild = _lastChild = 0;
+}
+
+
+void XMLNode::Unlink( XMLNode* child )
+{
+ TIXMLASSERT( child );
+ TIXMLASSERT( child->_document == _document );
+ TIXMLASSERT( child->_parent == this );
+ if ( child == _firstChild ) {
+ _firstChild = _firstChild->_next;
+ }
+ if ( child == _lastChild ) {
+ _lastChild = _lastChild->_prev;
+ }
+
+ if ( child->_prev ) {
+ child->_prev->_next = child->_next;
+ }
+ if ( child->_next ) {
+ child->_next->_prev = child->_prev;
+ }
+ child->_next = 0;
+ child->_prev = 0;
+ child->_parent = 0;
+}
+
+
+void XMLNode::DeleteChild( XMLNode* node )
+{
+ TIXMLASSERT( node );
+ TIXMLASSERT( node->_document == _document );
+ TIXMLASSERT( node->_parent == this );
+ Unlink( node );
+ TIXMLASSERT(node->_prev == 0);
+ TIXMLASSERT(node->_next == 0);
+ TIXMLASSERT(node->_parent == 0);
+ DeleteNode( node );
+}
+
+
+XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
+{
+ TIXMLASSERT( addThis );
+ if ( addThis->_document != _document ) {
+ TIXMLASSERT( false );
+ return 0;
+ }
+ InsertChildPreamble( addThis );
+
+ if ( _lastChild ) {
+ TIXMLASSERT( _firstChild );
+ TIXMLASSERT( _lastChild->_next == 0 );
+ _lastChild->_next = addThis;
+ addThis->_prev = _lastChild;
+ _lastChild = addThis;
+
+ addThis->_next = 0;
+ }
+ else {
+ TIXMLASSERT( _firstChild == 0 );
+ _firstChild = _lastChild = addThis;
+
+ addThis->_prev = 0;
+ addThis->_next = 0;
+ }
+ addThis->_parent = this;
+ return addThis;
+}
+
+
+XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
+{
+ TIXMLASSERT( addThis );
+ if ( addThis->_document != _document ) {
+ TIXMLASSERT( false );
+ return 0;
+ }
+ InsertChildPreamble( addThis );
+
+ if ( _firstChild ) {
+ TIXMLASSERT( _lastChild );
+ TIXMLASSERT( _firstChild->_prev == 0 );
+
+ _firstChild->_prev = addThis;
+ addThis->_next = _firstChild;
+ _firstChild = addThis;
+
+ addThis->_prev = 0;
+ }
+ else {
+ TIXMLASSERT( _lastChild == 0 );
+ _firstChild = _lastChild = addThis;
+
+ addThis->_prev = 0;
+ addThis->_next = 0;
+ }
+ addThis->_parent = this;
+ return addThis;
+}
+
+
+XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
+{
+ TIXMLASSERT( addThis );
+ if ( addThis->_document != _document ) {
+ TIXMLASSERT( false );
+ return 0;
+ }
+
+ TIXMLASSERT( afterThis );
+
+ if ( afterThis->_parent != this ) {
+ TIXMLASSERT( false );
+ return 0;
+ }
+ if ( afterThis == addThis ) {
+ // Current state: BeforeThis -> AddThis -> OneAfterAddThis
+ // Now AddThis must disappear from it's location and then
+ // reappear between BeforeThis and OneAfterAddThis.
+ // So just leave it where it is.
+ return addThis;
+ }
+
+ if ( afterThis->_next == 0 ) {
+ // The last node or the only node.
+ return InsertEndChild( addThis );
+ }
+ InsertChildPreamble( addThis );
+ addThis->_prev = afterThis;
+ addThis->_next = afterThis->_next;
+ afterThis->_next->_prev = addThis;
+ afterThis->_next = addThis;
+ addThis->_parent = this;
+ return addThis;
+}
+
+
+
+
+const XMLElement* XMLNode::FirstChildElement( const char* name ) const
+{
+ for( const XMLNode* node = _firstChild; node; node = node->_next ) {
+ const XMLElement* element = node->ToElementWithName( name );
+ if ( element ) {
+ return element;
+ }
+ }
+ return 0;
+}
+
+
+const XMLElement* XMLNode::LastChildElement( const char* name ) const
+{
+ for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
+ const XMLElement* element = node->ToElementWithName( name );
+ if ( element ) {
+ return element;
+ }
+ }
+ return 0;
+}
+
+
+const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
+{
+ for( const XMLNode* node = _next; node; node = node->_next ) {
+ const XMLElement* element = node->ToElementWithName( name );
+ if ( element ) {
+ return element;
+ }
+ }
+ return 0;
+}
+
+
+const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
+{
+ for( const XMLNode* node = _prev; node; node = node->_prev ) {
+ const XMLElement* element = node->ToElementWithName( name );
+ if ( element ) {
+ return element;
+ }
+ }
+ return 0;
+}
+
+
+char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
+{
+ // This is a recursive method, but thinking about it "at the current level"
+ // it is a pretty simple flat list:
+ // <foo/>
+ // <!-- comment -->
+ //
+ // With a special case:
+ // <foo>
+ // </foo>
+ // <!-- comment -->
+ //
+ // Where the closing element (/foo) *must* be the next thing after the opening
+ // element, and the names must match. BUT the tricky bit is that the closing
+ // element will be read by the child.
+ //
+ // 'endTag' is the end tag for this node, it is returned by a call to a child.
+ // 'parentEnd' is the end tag for the parent, which is filled in and returned.
+
+ while( p && *p ) {
+ XMLNode* node = 0;
+
+ p = _document->Identify( p, &node );
+ TIXMLASSERT( p );
+ if ( node == 0 ) {
+ break;
+ }
+
+ int initialLineNum = node->_parseLineNum;
+
+ StrPair endTag;
+ p = node->ParseDeep( p, &endTag, curLineNumPtr );
+ if ( !p ) {
+ DeleteNode( node );
+ if ( !_document->Error() ) {
+ _document->SetError( XML_ERROR_PARSING, initialLineNum, 0);
+ }
+ break;
+ }
+
+ XMLDeclaration* decl = node->ToDeclaration();
+ if ( decl ) {
+ // Declarations are only allowed at document level
+ bool wellLocated = ( ToDocument() != 0 );
+ if ( wellLocated ) {
+ // Multiple declarations are allowed but all declarations
+ // must occur before anything else
+ for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
+ if ( !existingNode->ToDeclaration() ) {
+ wellLocated = false;
+ break;
+ }
+ }
+ }
+ if ( !wellLocated ) {
+ _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value());
+ DeleteNode( node );
+ break;
+ }
+ }
+
+ XMLElement* ele = node->ToElement();
+ if ( ele ) {
+ // We read the end tag. Return it to the parent.
+ if ( ele->ClosingType() == XMLElement::CLOSING ) {
+ if ( parentEndTag ) {
+ ele->_value.TransferTo( parentEndTag );
+ }
+ node->_memPool->SetTracked(); // created and then immediately deleted.
+ DeleteNode( node );
+ return p;
+ }
+
+ // Handle an end tag returned to this level.
+ // And handle a bunch of annoying errors.
+ bool mismatch = false;
+ if ( endTag.Empty() ) {
+ if ( ele->ClosingType() == XMLElement::OPEN ) {
+ mismatch = true;
+ }
+ }
+ else {
+ if ( ele->ClosingType() != XMLElement::OPEN ) {
+ mismatch = true;
+ }
+ else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
+ mismatch = true;
+ }
+ }
+ if ( mismatch ) {
+ _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name());
+ DeleteNode( node );
+ break;
+ }
+ }
+ InsertEndChild( node );
+ }
+ return 0;
+}
+
+/*static*/ void XMLNode::DeleteNode( XMLNode* node )
+{
+ if ( node == 0 ) {
+ return;
+ }
+ TIXMLASSERT(node->_document);
+ if (!node->ToDocument()) {
+ node->_document->MarkInUse(node);
+ }
+
+ MemPool* pool = node->_memPool;
+ node->~XMLNode();
+ pool->Free( node );
+}
+
+void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
+{
+ TIXMLASSERT( insertThis );
+ TIXMLASSERT( insertThis->_document == _document );
+
+ if (insertThis->_parent) {
+ insertThis->_parent->Unlink( insertThis );
+ }
+ else {
+ insertThis->_document->MarkInUse(insertThis);
+ insertThis->_memPool->SetTracked();
+ }
+}
+
+const XMLElement* XMLNode::ToElementWithName( const char* name ) const
+{
+ const XMLElement* element = this->ToElement();
+ if ( element == 0 ) {
+ return 0;
+ }
+ if ( name == 0 ) {
+ return element;
+ }
+ if ( XMLUtil::StringEqual( element->Name(), name ) ) {
+ return element;
+ }
+ return 0;
+}
+
+// --------- XMLText ---------- //
+char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
+{
+ if ( this->CData() ) {
+ p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
+ if ( !p ) {
+ _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );
+ }
+ return p;
+ }
+ else {
+ int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
+ if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
+ flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
+ }
+
+ p = _value.ParseText( p, "<", flags, curLineNumPtr );
+ if ( p && *p ) {
+ return p-1;
+ }
+ if ( !p ) {
+ _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );
+ }
+ }
+ return 0;
+}
+
+
+XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
+{
+ if ( !doc ) {
+ doc = _document;
+ }
+ XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
+ text->SetCData( this->CData() );
+ return text;
+}
+
+
+bool XMLText::ShallowEqual( const XMLNode* compare ) const
+{
+ TIXMLASSERT( compare );
+ const XMLText* text = compare->ToText();
+ return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
+}
+
+
+bool XMLText::Accept( XMLVisitor* visitor ) const
+{
+ TIXMLASSERT( visitor );
+ return visitor->Visit( *this );
+}
+
+
+// --------- XMLComment ---------- //
+
+XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
+{
+}
+
+
+XMLComment::~XMLComment()
+{
+}
+
+
+char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
+{
+ // Comment parses as text.
+ p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
+ if ( p == 0 ) {
+ _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );
+ }
+ return p;
+}
+
+
+XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
+{
+ if ( !doc ) {
+ doc = _document;
+ }
+ XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
+ return comment;
+}
+
+
+bool XMLComment::ShallowEqual( const XMLNode* compare ) const
+{
+ TIXMLASSERT( compare );
+ const XMLComment* comment = compare->ToComment();
+ return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
+}
+
+
+bool XMLComment::Accept( XMLVisitor* visitor ) const
+{
+ TIXMLASSERT( visitor );
+ return visitor->Visit( *this );
+}
+
+
+// --------- XMLDeclaration ---------- //
+
+XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
+{
+}
+
+
+XMLDeclaration::~XMLDeclaration()
+{
+ //printf( "~XMLDeclaration\n" );
+}
+
+
+char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
+{
+ // Declaration parses as text.
+ p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
+ if ( p == 0 ) {
+ _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );
+ }
+ return p;
+}
+
+
+XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
+{
+ if ( !doc ) {
+ doc = _document;
+ }
+ XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
+ return dec;
+}
+
+
+bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
+{
+ TIXMLASSERT( compare );
+ const XMLDeclaration* declaration = compare->ToDeclaration();
+ return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
+}
+
+
+
+bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
+{
+ TIXMLASSERT( visitor );
+ return visitor->Visit( *this );
+}
+
+// --------- XMLUnknown ---------- //
+
+XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
+{
+}
+
+
+XMLUnknown::~XMLUnknown()
+{
+}
+
+
+char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
+{
+ // Unknown parses as text.
+ p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
+ if ( !p ) {
+ _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );
+ }
+ return p;
+}
+
+
+XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
+{
+ if ( !doc ) {
+ doc = _document;
+ }
+ XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
+ return text;
+}
+
+
+bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
+{
+ TIXMLASSERT( compare );
+ const XMLUnknown* unknown = compare->ToUnknown();
+ return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
+}
+
+
+bool XMLUnknown::Accept( XMLVisitor* visitor ) const
+{
+ TIXMLASSERT( visitor );
+ return visitor->Visit( *this );
+}
+
+// --------- XMLAttribute ---------- //
+
const char* XMLAttribute::Name() const
-{
- return _name.GetStr();
-}
-
+{
+ return _name.GetStr();
+}
+
const char* XMLAttribute::Value() const
-{
- return _value.GetStr();
-}
-
-char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
-{
- // Parse using the name rules: bug fix, was using ParseText before
- p = _name.ParseName( p );
- if ( !p || !*p ) {
- return 0;
- }
-
- // Skip white space before =
- p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
- if ( *p != '=' ) {
- return 0;
- }
-
- ++p; // move up to opening quote
- p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
- if ( *p != '\"' && *p != '\'' ) {
- return 0;
- }
-
- char endTag[2] = { *p, 0 };
- ++p; // move past opening quote
-
- p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
- return p;
-}
-
-
-void XMLAttribute::SetName( const char* n )
-{
- _name.SetStr( n );
-}
-
-
-XMLError XMLAttribute::QueryIntValue( int* value ) const
-{
- if ( XMLUtil::ToInt( Value(), value )) {
- return XML_SUCCESS;
- }
- return XML_WRONG_ATTRIBUTE_TYPE;
-}
-
-
-XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
-{
- if ( XMLUtil::ToUnsigned( Value(), value )) {
- return XML_SUCCESS;
- }
- return XML_WRONG_ATTRIBUTE_TYPE;
-}
-
-
-XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
-{
- if (XMLUtil::ToInt64(Value(), value)) {
- return XML_SUCCESS;
- }
- return XML_WRONG_ATTRIBUTE_TYPE;
-}
-
-
-XMLError XMLAttribute::QueryBoolValue( bool* value ) const
-{
- if ( XMLUtil::ToBool( Value(), value )) {
- return XML_SUCCESS;
- }
- return XML_WRONG_ATTRIBUTE_TYPE;
-}
-
-
-XMLError XMLAttribute::QueryFloatValue( float* value ) const
-{
- if ( XMLUtil::ToFloat( Value(), value )) {
- return XML_SUCCESS;
- }
- return XML_WRONG_ATTRIBUTE_TYPE;
-}
-
-
-XMLError XMLAttribute::QueryDoubleValue( double* value ) const
-{
- if ( XMLUtil::ToDouble( Value(), value )) {
- return XML_SUCCESS;
- }
- return XML_WRONG_ATTRIBUTE_TYPE;
-}
-
-
-void XMLAttribute::SetAttribute( const char* v )
-{
- _value.SetStr( v );
-}
-
-
-void XMLAttribute::SetAttribute( int v )
-{
- char buf[BUF_SIZE];
- XMLUtil::ToStr( v, buf, BUF_SIZE );
- _value.SetStr( buf );
-}
-
-
-void XMLAttribute::SetAttribute( unsigned v )
-{
- char buf[BUF_SIZE];
- XMLUtil::ToStr( v, buf, BUF_SIZE );
- _value.SetStr( buf );
-}
-
-
-void XMLAttribute::SetAttribute(int64_t v)
-{
- char buf[BUF_SIZE];
- XMLUtil::ToStr(v, buf, BUF_SIZE);
- _value.SetStr(buf);
-}
-
-
-
-void XMLAttribute::SetAttribute( bool v )
-{
- char buf[BUF_SIZE];
- XMLUtil::ToStr( v, buf, BUF_SIZE );
- _value.SetStr( buf );
-}
-
-void XMLAttribute::SetAttribute( double v )
-{
- char buf[BUF_SIZE];
- XMLUtil::ToStr( v, buf, BUF_SIZE );
- _value.SetStr( buf );
-}
-
-void XMLAttribute::SetAttribute( float v )
-{
- char buf[BUF_SIZE];
- XMLUtil::ToStr( v, buf, BUF_SIZE );
- _value.SetStr( buf );
-}
-
-
-// --------- XMLElement ---------- //
-XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
- _closingType( OPEN ),
- _rootAttribute( 0 )
-{
-}
-
-
-XMLElement::~XMLElement()
-{
- while( _rootAttribute ) {
- XMLAttribute* next = _rootAttribute->_next;
- DeleteAttribute( _rootAttribute );
- _rootAttribute = next;
- }
-}
-
-
-const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
-{
- for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
- if ( XMLUtil::StringEqual( a->Name(), name ) ) {
- return a;
- }
- }
- return 0;
-}
-
-
-const char* XMLElement::Attribute( const char* name, const char* value ) const
-{
- const XMLAttribute* a = FindAttribute( name );
- if ( !a ) {
- return 0;
- }
- if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
- return a->Value();
- }
- return 0;
-}
-
+{
+ return _value.GetStr();
+}
+
+char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
+{
+ // Parse using the name rules: bug fix, was using ParseText before
+ p = _name.ParseName( p );
+ if ( !p || !*p ) {
+ return 0;
+ }
+
+ // Skip white space before =
+ p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
+ if ( *p != '=' ) {
+ return 0;
+ }
+
+ ++p; // move up to opening quote
+ p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
+ if ( *p != '\"' && *p != '\'' ) {
+ return 0;
+ }
+
+ char endTag[2] = { *p, 0 };
+ ++p; // move past opening quote
+
+ p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
+ return p;
+}
+
+
+void XMLAttribute::SetName( const char* n )
+{
+ _name.SetStr( n );
+}
+
+
+XMLError XMLAttribute::QueryIntValue( int* value ) const
+{
+ if ( XMLUtil::ToInt( Value(), value )) {
+ return XML_SUCCESS;
+ }
+ return XML_WRONG_ATTRIBUTE_TYPE;
+}
+
+
+XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
+{
+ if ( XMLUtil::ToUnsigned( Value(), value )) {
+ return XML_SUCCESS;
+ }
+ return XML_WRONG_ATTRIBUTE_TYPE;
+}
+
+
+XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
+{
+ if (XMLUtil::ToInt64(Value(), value)) {
+ return XML_SUCCESS;
+ }
+ return XML_WRONG_ATTRIBUTE_TYPE;
+}
+
+
+XMLError XMLAttribute::QueryBoolValue( bool* value ) const
+{
+ if ( XMLUtil::ToBool( Value(), value )) {
+ return XML_SUCCESS;
+ }
+ return XML_WRONG_ATTRIBUTE_TYPE;
+}
+
+
+XMLError XMLAttribute::QueryFloatValue( float* value ) const
+{
+ if ( XMLUtil::ToFloat( Value(), value )) {
+ return XML_SUCCESS;
+ }
+ return XML_WRONG_ATTRIBUTE_TYPE;
+}
+
+
+XMLError XMLAttribute::QueryDoubleValue( double* value ) const
+{
+ if ( XMLUtil::ToDouble( Value(), value )) {
+ return XML_SUCCESS;
+ }
+ return XML_WRONG_ATTRIBUTE_TYPE;
+}
+
+
+void XMLAttribute::SetAttribute( const char* v )
+{
+ _value.SetStr( v );
+}
+
+
+void XMLAttribute::SetAttribute( int v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ _value.SetStr( buf );
+}
+
+
+void XMLAttribute::SetAttribute( unsigned v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ _value.SetStr( buf );
+}
+
+
+void XMLAttribute::SetAttribute(int64_t v)
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr(v, buf, BUF_SIZE);
+ _value.SetStr(buf);
+}
+
+
+
+void XMLAttribute::SetAttribute( bool v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ _value.SetStr( buf );
+}
+
+void XMLAttribute::SetAttribute( double v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ _value.SetStr( buf );
+}
+
+void XMLAttribute::SetAttribute( float v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ _value.SetStr( buf );
+}
+
+
+// --------- XMLElement ---------- //
+XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
+ _closingType( OPEN ),
+ _rootAttribute( 0 )
+{
+}
+
+
+XMLElement::~XMLElement()
+{
+ while( _rootAttribute ) {
+ XMLAttribute* next = _rootAttribute->_next;
+ DeleteAttribute( _rootAttribute );
+ _rootAttribute = next;
+ }
+}
+
+
+const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
+{
+ for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
+ if ( XMLUtil::StringEqual( a->Name(), name ) ) {
+ return a;
+ }
+ }
+ return 0;
+}
+
+
+const char* XMLElement::Attribute( const char* name, const char* value ) const
+{
+ const XMLAttribute* a = FindAttribute( name );
+ if ( !a ) {
+ return 0;
+ }
+ if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
+ return a->Value();
+ }
+ return 0;
+}
+
int XMLElement::IntAttribute(const char* name, int defaultValue) const
-{
- int i = defaultValue;
- QueryIntAttribute(name, &i);
- return i;
-}
-
+{
+ int i = defaultValue;
+ QueryIntAttribute(name, &i);
+ return i;
+}
+
unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
-{
- unsigned i = defaultValue;
- QueryUnsignedAttribute(name, &i);
- return i;
-}
-
+{
+ unsigned i = defaultValue;
+ QueryUnsignedAttribute(name, &i);
+ return i;
+}
+
int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
-{
- int64_t i = defaultValue;
- QueryInt64Attribute(name, &i);
- return i;
-}
-
+{
+ int64_t i = defaultValue;
+ QueryInt64Attribute(name, &i);
+ return i;
+}
+
bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
-{
- bool b = defaultValue;
- QueryBoolAttribute(name, &b);
- return b;
-}
-
+{
+ bool b = defaultValue;
+ QueryBoolAttribute(name, &b);
+ return b;
+}
+
double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
-{
- double d = defaultValue;
- QueryDoubleAttribute(name, &d);
- return d;
-}
-
+{
+ double d = defaultValue;
+ QueryDoubleAttribute(name, &d);
+ return d;
+}
+
float XMLElement::FloatAttribute(const char* name, float defaultValue) const
-{
- float f = defaultValue;
- QueryFloatAttribute(name, &f);
- return f;
-}
-
-const char* XMLElement::GetText() const
-{
- if ( FirstChild() && FirstChild()->ToText() ) {
- return FirstChild()->Value();
- }
- return 0;
-}
-
-
-void XMLElement::SetText( const char* inText )
-{
- if ( FirstChild() && FirstChild()->ToText() )
- FirstChild()->SetValue( inText );
- else {
- XMLText* theText = GetDocument()->NewText( inText );
- InsertFirstChild( theText );
- }
-}
-
-
+{
+ float f = defaultValue;
+ QueryFloatAttribute(name, &f);
+ return f;
+}
+
+const char* XMLElement::GetText() const
+{
+ if ( FirstChild() && FirstChild()->ToText() ) {
+ return FirstChild()->Value();
+ }
+ return 0;
+}
+
+
+void XMLElement::SetText( const char* inText )
+{
+ if ( FirstChild() && FirstChild()->ToText() )
+ FirstChild()->SetValue( inText );
+ else {
+ XMLText* theText = GetDocument()->NewText( inText );
+ InsertFirstChild( theText );
+ }
+}
+
+
void XMLElement::SetText( int v )
-{
- char buf[BUF_SIZE];
- XMLUtil::ToStr( v, buf, BUF_SIZE );
- SetText( buf );
-}
-
-
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ SetText( buf );
+}
+
+
void XMLElement::SetText( unsigned v )
-{
- char buf[BUF_SIZE];
- XMLUtil::ToStr( v, buf, BUF_SIZE );
- SetText( buf );
-}
-
-
-void XMLElement::SetText(int64_t v)
-{
- char buf[BUF_SIZE];
- XMLUtil::ToStr(v, buf, BUF_SIZE);
- SetText(buf);
-}
-
-
-void XMLElement::SetText( bool v )
-{
- char buf[BUF_SIZE];
- XMLUtil::ToStr( v, buf, BUF_SIZE );
- SetText( buf );
-}
-
-
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ SetText( buf );
+}
+
+
+void XMLElement::SetText(int64_t v)
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr(v, buf, BUF_SIZE);
+ SetText(buf);
+}
+
+
+void XMLElement::SetText( bool v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ SetText( buf );
+}
+
+
void XMLElement::SetText( float v )
-{
- char buf[BUF_SIZE];
- XMLUtil::ToStr( v, buf, BUF_SIZE );
- SetText( buf );
-}
-
-
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ SetText( buf );
+}
+
+
void XMLElement::SetText( double v )
-{
- char buf[BUF_SIZE];
- XMLUtil::ToStr( v, buf, BUF_SIZE );
- SetText( buf );
-}
-
-
-XMLError XMLElement::QueryIntText( int* ival ) const
-{
- if ( FirstChild() && FirstChild()->ToText() ) {
- const char* t = FirstChild()->Value();
- if ( XMLUtil::ToInt( t, ival ) ) {
- return XML_SUCCESS;
- }
- return XML_CAN_NOT_CONVERT_TEXT;
- }
- return XML_NO_TEXT_NODE;
-}
-
-
-XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
-{
- if ( FirstChild() && FirstChild()->ToText() ) {
- const char* t = FirstChild()->Value();
- if ( XMLUtil::ToUnsigned( t, uval ) ) {
- return XML_SUCCESS;
- }
- return XML_CAN_NOT_CONVERT_TEXT;
- }
- return XML_NO_TEXT_NODE;
-}
-
-
-XMLError XMLElement::QueryInt64Text(int64_t* ival) const
-{
- if (FirstChild() && FirstChild()->ToText()) {
- const char* t = FirstChild()->Value();
- if (XMLUtil::ToInt64(t, ival)) {
- return XML_SUCCESS;
- }
- return XML_CAN_NOT_CONVERT_TEXT;
- }
- return XML_NO_TEXT_NODE;
-}
-
-
-XMLError XMLElement::QueryBoolText( bool* bval ) const
-{
- if ( FirstChild() && FirstChild()->ToText() ) {
- const char* t = FirstChild()->Value();
- if ( XMLUtil::ToBool( t, bval ) ) {
- return XML_SUCCESS;
- }
- return XML_CAN_NOT_CONVERT_TEXT;
- }
- return XML_NO_TEXT_NODE;
-}
-
-
-XMLError XMLElement::QueryDoubleText( double* dval ) const
-{
- if ( FirstChild() && FirstChild()->ToText() ) {
- const char* t = FirstChild()->Value();
- if ( XMLUtil::ToDouble( t, dval ) ) {
- return XML_SUCCESS;
- }
- return XML_CAN_NOT_CONVERT_TEXT;
- }
- return XML_NO_TEXT_NODE;
-}
-
-
-XMLError XMLElement::QueryFloatText( float* fval ) const
-{
- if ( FirstChild() && FirstChild()->ToText() ) {
- const char* t = FirstChild()->Value();
- if ( XMLUtil::ToFloat( t, fval ) ) {
- return XML_SUCCESS;
- }
- return XML_CAN_NOT_CONVERT_TEXT;
- }
- return XML_NO_TEXT_NODE;
-}
-
-int XMLElement::IntText(int defaultValue) const
-{
- int i = defaultValue;
- QueryIntText(&i);
- return i;
-}
-
-unsigned XMLElement::UnsignedText(unsigned defaultValue) const
-{
- unsigned i = defaultValue;
- QueryUnsignedText(&i);
- return i;
-}
-
-int64_t XMLElement::Int64Text(int64_t defaultValue) const
-{
- int64_t i = defaultValue;
- QueryInt64Text(&i);
- return i;
-}
-
-bool XMLElement::BoolText(bool defaultValue) const
-{
- bool b = defaultValue;
- QueryBoolText(&b);
- return b;
-}
-
-double XMLElement::DoubleText(double defaultValue) const
-{
- double d = defaultValue;
- QueryDoubleText(&d);
- return d;
-}
-
-float XMLElement::FloatText(float defaultValue) const
-{
- float f = defaultValue;
- QueryFloatText(&f);
- return f;
-}
-
-
-XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
-{
- XMLAttribute* last = 0;
- XMLAttribute* attrib = 0;
- for( attrib = _rootAttribute;
- attrib;
- last = attrib, attrib = attrib->_next ) {
- if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
- break;
- }
- }
- if ( !attrib ) {
- attrib = CreateAttribute();
- TIXMLASSERT( attrib );
- if ( last ) {
- TIXMLASSERT( last->_next == 0 );
- last->_next = attrib;
- }
- else {
- TIXMLASSERT( _rootAttribute == 0 );
- _rootAttribute = attrib;
- }
- attrib->SetName( name );
- }
- return attrib;
-}
-
-
-void XMLElement::DeleteAttribute( const char* name )
-{
- XMLAttribute* prev = 0;
- for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
- if ( XMLUtil::StringEqual( name, a->Name() ) ) {
- if ( prev ) {
- prev->_next = a->_next;
- }
- else {
- _rootAttribute = a->_next;
- }
- DeleteAttribute( a );
- break;
- }
- prev = a;
- }
-}
-
-
-char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
-{
- XMLAttribute* prevAttribute = 0;
-
- // Read the attributes.
- while( p ) {
- p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
- if ( !(*p) ) {
- _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() );
- return 0;
- }
-
- // attribute.
- if (XMLUtil::IsNameStartChar( *p ) ) {
- XMLAttribute* attrib = CreateAttribute();
- TIXMLASSERT( attrib );
- attrib->_parseLineNum = _document->_parseCurLineNum;
-
- int attrLineNum = attrib->_parseLineNum;
-
- p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
- if ( !p || Attribute( attrib->Name() ) ) {
- DeleteAttribute( attrib );
- _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() );
- return 0;
- }
- // There is a minor bug here: if the attribute in the source xml
- // document is duplicated, it will not be detected and the
- // attribute will be doubly added. However, tracking the 'prevAttribute'
- // avoids re-scanning the attribute list. Preferring performance for
- // now, may reconsider in the future.
- if ( prevAttribute ) {
- TIXMLASSERT( prevAttribute->_next == 0 );
- prevAttribute->_next = attrib;
- }
- else {
- TIXMLASSERT( _rootAttribute == 0 );
- _rootAttribute = attrib;
- }
- prevAttribute = attrib;
- }
- // end of the tag
- else if ( *p == '>' ) {
- ++p;
- break;
- }
- // end of the tag
- else if ( *p == '/' && *(p+1) == '>' ) {
- _closingType = CLOSED;
- return p+2; // done; sealed element.
- }
- else {
- _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );
- return 0;
- }
- }
- return p;
-}
-
-void XMLElement::DeleteAttribute( XMLAttribute* attribute )
-{
- if ( attribute == 0 ) {
- return;
- }
- MemPool* pool = attribute->_memPool;
- attribute->~XMLAttribute();
- pool->Free( attribute );
-}
-
-XMLAttribute* XMLElement::CreateAttribute()
-{
- TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
- XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
- TIXMLASSERT( attrib );
- attrib->_memPool = &_document->_attributePool;
- attrib->_memPool->SetTracked();
- return attrib;
-}
-
-//
-// <ele></ele>
-// <ele>foo<b>bar</b></ele>
-//
-char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
-{
- // Read the element name.
- p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
-
- // The closing element is the </element> form. It is
- // parsed just like a regular element then deleted from
- // the DOM.
- if ( *p == '/' ) {
- _closingType = CLOSING;
- ++p;
- }
-
- p = _value.ParseName( p );
- if ( _value.Empty() ) {
- return 0;
- }
-
- p = ParseAttributes( p, curLineNumPtr );
- if ( !p || !*p || _closingType != OPEN ) {
- return p;
- }
-
- p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
- return p;
-}
-
-
-
-XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
-{
- if ( !doc ) {
- doc = _document;
- }
- XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
- for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
- element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
- }
- return element;
-}
-
-
-bool XMLElement::ShallowEqual( const XMLNode* compare ) const
-{
- TIXMLASSERT( compare );
- const XMLElement* other = compare->ToElement();
- if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
-
- const XMLAttribute* a=FirstAttribute();
- const XMLAttribute* b=other->FirstAttribute();
-
- while ( a && b ) {
- if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
- return false;
- }
- a = a->Next();
- b = b->Next();
- }
- if ( a || b ) {
- // different count
- return false;
- }
- return true;
- }
- return false;
-}
-
-
-bool XMLElement::Accept( XMLVisitor* visitor ) const
-{
- TIXMLASSERT( visitor );
- if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
- for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
- if ( !node->Accept( visitor ) ) {
- break;
- }
- }
- }
- return visitor->VisitExit( *this );
-}
-
-
-// --------- XMLDocument ----------- //
-
-// Warning: List must match 'enum XMLError'
-const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
- "XML_SUCCESS",
- "XML_NO_ATTRIBUTE",
- "XML_WRONG_ATTRIBUTE_TYPE",
- "XML_ERROR_FILE_NOT_FOUND",
- "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
- "XML_ERROR_FILE_READ_ERROR",
- "UNUSED_XML_ERROR_ELEMENT_MISMATCH",
- "XML_ERROR_PARSING_ELEMENT",
- "XML_ERROR_PARSING_ATTRIBUTE",
- "UNUSED_XML_ERROR_IDENTIFYING_TAG",
- "XML_ERROR_PARSING_TEXT",
- "XML_ERROR_PARSING_CDATA",
- "XML_ERROR_PARSING_COMMENT",
- "XML_ERROR_PARSING_DECLARATION",
- "XML_ERROR_PARSING_UNKNOWN",
- "XML_ERROR_EMPTY_DOCUMENT",
- "XML_ERROR_MISMATCHED_ELEMENT",
- "XML_ERROR_PARSING",
- "XML_CAN_NOT_CONVERT_TEXT",
- "XML_NO_TEXT_NODE"
-};
-
-
-XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
- XMLNode( 0 ),
- _writeBOM( false ),
- _processEntities( processEntities ),
- _errorID(XML_SUCCESS),
- _whitespaceMode( whitespaceMode ),
- _errorStr(),
- _errorLineNum( 0 ),
- _charBuffer( 0 ),
- _parseCurLineNum( 0 ),
- _unlinked(),
- _elementPool(),
- _attributePool(),
- _textPool(),
- _commentPool()
-{
- // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
- _document = this;
-}
-
-
-XMLDocument::~XMLDocument()
-{
- Clear();
-}
-
-
-void XMLDocument::MarkInUse(XMLNode* node)
-{
- TIXMLASSERT(node);
- TIXMLASSERT(node->_parent == 0);
-
- for (int i = 0; i < _unlinked.Size(); ++i) {
- if (node == _unlinked[i]) {
- _unlinked.SwapRemove(i);
- break;
- }
- }
-}
-
-void XMLDocument::Clear()
-{
- DeleteChildren();
- while( _unlinked.Size()) {
- DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete.
- }
-
-#ifdef DEBUG
- const bool hadError = Error();
-#endif
- ClearError();
-
- Aws::DeleteArray(_charBuffer);
- _charBuffer = 0;
-
-#if 0
- _textPool.Trace( "text" );
- _elementPool.Trace( "element" );
- _commentPool.Trace( "comment" );
- _attributePool.Trace( "attribute" );
-#endif
-
-#ifdef DEBUG
- if ( !hadError ) {
- TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
- TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
- TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
- TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
- }
-#endif
-}
-
-
-void XMLDocument::DeepCopy(XMLDocument* target) const
-{
- TIXMLASSERT(target);
- if (target == this) {
- return; // technically success - a no-op.
- }
-
- target->Clear();
- for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
- target->InsertEndChild(node->DeepClone(target));
- }
-}
-
-XMLElement* XMLDocument::NewElement( const char* name )
-{
- XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
- ele->SetName( name );
- return ele;
-}
-
-
-XMLComment* XMLDocument::NewComment( const char* str )
-{
- XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
- comment->SetValue( str );
- return comment;
-}
-
-
-XMLText* XMLDocument::NewText( const char* str )
-{
- XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
- text->SetValue( str );
- return text;
-}
-
-
-XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
-{
- XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
- dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
- return dec;
-}
-
-
-XMLUnknown* XMLDocument::NewUnknown( const char* str )
-{
- XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
- unk->SetValue( str );
- return unk;
-}
-
-static FILE* callfopen( const char* filepath, const char* mode )
-{
- TIXMLASSERT( filepath );
- TIXMLASSERT( mode );
-#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
- FILE* fp = 0;
- errno_t err = fopen_s( &fp, filepath, mode );
- if ( err ) {
- return 0;
- }
-#else
- FILE* fp = fopen( filepath, mode );
-#endif
- return fp;
-}
-
-void XMLDocument::DeleteNode( XMLNode* node ) {
- TIXMLASSERT( node );
- TIXMLASSERT(node->_document == this );
- if (node->_parent) {
- node->_parent->DeleteChild( node );
- }
- else {
- // Isn't in the tree.
- // Use the parent delete.
- // Also, we need to mark it tracked: we 'know'
- // it was never used.
- node->_memPool->SetTracked();
- // Call the static XMLNode version:
- XMLNode::DeleteNode(node);
- }
-}
-
-
-XMLError XMLDocument::LoadFile( const char* filename )
-{
- Clear();
- FILE* fp = callfopen( filename, "rb" );
- if ( !fp ) {
- SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename ? filename : "<null>");
- return _errorID;
- }
- LoadFile( fp );
- fclose( fp );
- return _errorID;
-}
-
-// This is likely overengineered template art to have a check that unsigned long value incremented
-// by one still fits into size_t. If size_t type is larger than unsigned long type
-// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
-// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
-// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
-// types sizes relate to each other.
-template
-<bool = (sizeof(unsigned long) >= sizeof(size_t))>
-struct LongFitsIntoSizeTMinusOne {
- static bool Fits( unsigned long value )
- {
- return value < (size_t)-1;
- }
-};
-
-template <>
-struct LongFitsIntoSizeTMinusOne<false> {
- static bool Fits( unsigned long )
- {
- return true;
- }
-};
-
-XMLError XMLDocument::LoadFile( FILE* fp )
-{
- Clear();
-
- fseek( fp, 0, SEEK_SET );
- if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
- SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
- return _errorID;
- }
-
- fseek( fp, 0, SEEK_END );
- const long filelength = ftell( fp );
- fseek( fp, 0, SEEK_SET );
- if ( filelength == -1L ) {
- SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
- return _errorID;
- }
- TIXMLASSERT( filelength >= 0 );
-
- if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
- // Cannot handle files which won't fit in buffer together with null terminator
- SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
- return _errorID;
- }
-
- if ( filelength == 0 ) {
- SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
- return _errorID;
- }
-
- const size_t size = filelength;
- TIXMLASSERT( _charBuffer == 0 );
- _charBuffer = Aws::NewArray <char>(size+1, ALLOCATION_TAG);
- size_t read = fread( _charBuffer, 1, size, fp );
- if ( read != size ) {
- SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
- return _errorID;
- }
-
- _charBuffer[size] = 0;
-
- Parse();
- return _errorID;
-}
-
-
-XMLError XMLDocument::SaveFile( const char* filename, bool compact )
-{
- FILE* fp = callfopen( filename, "w" );
- if ( !fp ) {
- SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename ? filename : "<null>");
- return _errorID;
- }
- SaveFile(fp, compact);
- fclose( fp );
- return _errorID;
-}
-
-
-XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
-{
- // Clear any error from the last save, otherwise it will get reported
- // for *this* call.
- ClearError();
- XMLPrinter stream( fp, compact );
- Print( &stream );
- return _errorID;
-}
-
-
-XMLError XMLDocument::Parse( const char* p, size_t len )
-{
- Clear();
-
- if ( len == 0 || !p || !*p ) {
- SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
- return _errorID;
- }
- if ( len == (size_t)(-1) ) {
- len = strlen( p );
- }
- TIXMLASSERT( _charBuffer == 0 );
- _charBuffer = Aws::NewArray<char>(len+1, ALLOCATION_TAG);
- memcpy( _charBuffer, p, len );
- _charBuffer[len] = 0;
-
- Parse();
- if ( Error() ) {
- // clean up now essentially dangling memory.
- // and the parse fail can put objects in the
- // pools that are dead and inaccessible.
- DeleteChildren();
- _elementPool.Clear();
- _attributePool.Clear();
- _textPool.Clear();
- _commentPool.Clear();
- }
- return _errorID;
-}
-
-
-void XMLDocument::Print( XMLPrinter* streamer ) const
-{
- if ( streamer ) {
- Accept( streamer );
- }
- else {
- XMLPrinter stdoutStreamer( stdout );
- Accept( &stdoutStreamer );
- }
-}
-
-
-void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
-{
- TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
- _errorID = error;
- _errorLineNum = lineNum;
- _errorStr.Reset();
-
- if (format) {
- size_t BUFFER_SIZE = 1000;
- char* buffer = Aws::NewArray<char>(BUFFER_SIZE, ALLOCATION_TAG);
- TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d: ", ErrorIDToName(error), int(error), int(error), lineNum);
- size_t len = strlen(buffer);
-
- va_list va;
- va_start( va, format );
- TIXML_VSNPRINTF( buffer + len, BUFFER_SIZE - len, format, va );
- va_end( va );
-
- _errorStr.SetStr(buffer);
- Aws::DeleteArray(buffer);
- }
-}
-
-
-/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
-{
- TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
- const char* errorName = _errorNames[errorID];
- TIXMLASSERT( errorName && errorName[0] );
- return errorName;
-}
-
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ SetText( buf );
+}
+
+
+XMLError XMLElement::QueryIntText( int* ival ) const
+{
+ if ( FirstChild() && FirstChild()->ToText() ) {
+ const char* t = FirstChild()->Value();
+ if ( XMLUtil::ToInt( t, ival ) ) {
+ return XML_SUCCESS;
+ }
+ return XML_CAN_NOT_CONVERT_TEXT;
+ }
+ return XML_NO_TEXT_NODE;
+}
+
+
+XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
+{
+ if ( FirstChild() && FirstChild()->ToText() ) {
+ const char* t = FirstChild()->Value();
+ if ( XMLUtil::ToUnsigned( t, uval ) ) {
+ return XML_SUCCESS;
+ }
+ return XML_CAN_NOT_CONVERT_TEXT;
+ }
+ return XML_NO_TEXT_NODE;
+}
+
+
+XMLError XMLElement::QueryInt64Text(int64_t* ival) const
+{
+ if (FirstChild() && FirstChild()->ToText()) {
+ const char* t = FirstChild()->Value();
+ if (XMLUtil::ToInt64(t, ival)) {
+ return XML_SUCCESS;
+ }
+ return XML_CAN_NOT_CONVERT_TEXT;
+ }
+ return XML_NO_TEXT_NODE;
+}
+
+
+XMLError XMLElement::QueryBoolText( bool* bval ) const
+{
+ if ( FirstChild() && FirstChild()->ToText() ) {
+ const char* t = FirstChild()->Value();
+ if ( XMLUtil::ToBool( t, bval ) ) {
+ return XML_SUCCESS;
+ }
+ return XML_CAN_NOT_CONVERT_TEXT;
+ }
+ return XML_NO_TEXT_NODE;
+}
+
+
+XMLError XMLElement::QueryDoubleText( double* dval ) const
+{
+ if ( FirstChild() && FirstChild()->ToText() ) {
+ const char* t = FirstChild()->Value();
+ if ( XMLUtil::ToDouble( t, dval ) ) {
+ return XML_SUCCESS;
+ }
+ return XML_CAN_NOT_CONVERT_TEXT;
+ }
+ return XML_NO_TEXT_NODE;
+}
+
+
+XMLError XMLElement::QueryFloatText( float* fval ) const
+{
+ if ( FirstChild() && FirstChild()->ToText() ) {
+ const char* t = FirstChild()->Value();
+ if ( XMLUtil::ToFloat( t, fval ) ) {
+ return XML_SUCCESS;
+ }
+ return XML_CAN_NOT_CONVERT_TEXT;
+ }
+ return XML_NO_TEXT_NODE;
+}
+
+int XMLElement::IntText(int defaultValue) const
+{
+ int i = defaultValue;
+ QueryIntText(&i);
+ return i;
+}
+
+unsigned XMLElement::UnsignedText(unsigned defaultValue) const
+{
+ unsigned i = defaultValue;
+ QueryUnsignedText(&i);
+ return i;
+}
+
+int64_t XMLElement::Int64Text(int64_t defaultValue) const
+{
+ int64_t i = defaultValue;
+ QueryInt64Text(&i);
+ return i;
+}
+
+bool XMLElement::BoolText(bool defaultValue) const
+{
+ bool b = defaultValue;
+ QueryBoolText(&b);
+ return b;
+}
+
+double XMLElement::DoubleText(double defaultValue) const
+{
+ double d = defaultValue;
+ QueryDoubleText(&d);
+ return d;
+}
+
+float XMLElement::FloatText(float defaultValue) const
+{
+ float f = defaultValue;
+ QueryFloatText(&f);
+ return f;
+}
+
+
+XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
+{
+ XMLAttribute* last = 0;
+ XMLAttribute* attrib = 0;
+ for( attrib = _rootAttribute;
+ attrib;
+ last = attrib, attrib = attrib->_next ) {
+ if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
+ break;
+ }
+ }
+ if ( !attrib ) {
+ attrib = CreateAttribute();
+ TIXMLASSERT( attrib );
+ if ( last ) {
+ TIXMLASSERT( last->_next == 0 );
+ last->_next = attrib;
+ }
+ else {
+ TIXMLASSERT( _rootAttribute == 0 );
+ _rootAttribute = attrib;
+ }
+ attrib->SetName( name );
+ }
+ return attrib;
+}
+
+
+void XMLElement::DeleteAttribute( const char* name )
+{
+ XMLAttribute* prev = 0;
+ for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
+ if ( XMLUtil::StringEqual( name, a->Name() ) ) {
+ if ( prev ) {
+ prev->_next = a->_next;
+ }
+ else {
+ _rootAttribute = a->_next;
+ }
+ DeleteAttribute( a );
+ break;
+ }
+ prev = a;
+ }
+}
+
+
+char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
+{
+ XMLAttribute* prevAttribute = 0;
+
+ // Read the attributes.
+ while( p ) {
+ p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
+ if ( !(*p) ) {
+ _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() );
+ return 0;
+ }
+
+ // attribute.
+ if (XMLUtil::IsNameStartChar( *p ) ) {
+ XMLAttribute* attrib = CreateAttribute();
+ TIXMLASSERT( attrib );
+ attrib->_parseLineNum = _document->_parseCurLineNum;
+
+ int attrLineNum = attrib->_parseLineNum;
+
+ p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
+ if ( !p || Attribute( attrib->Name() ) ) {
+ DeleteAttribute( attrib );
+ _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() );
+ return 0;
+ }
+ // There is a minor bug here: if the attribute in the source xml
+ // document is duplicated, it will not be detected and the
+ // attribute will be doubly added. However, tracking the 'prevAttribute'
+ // avoids re-scanning the attribute list. Preferring performance for
+ // now, may reconsider in the future.
+ if ( prevAttribute ) {
+ TIXMLASSERT( prevAttribute->_next == 0 );
+ prevAttribute->_next = attrib;
+ }
+ else {
+ TIXMLASSERT( _rootAttribute == 0 );
+ _rootAttribute = attrib;
+ }
+ prevAttribute = attrib;
+ }
+ // end of the tag
+ else if ( *p == '>' ) {
+ ++p;
+ break;
+ }
+ // end of the tag
+ else if ( *p == '/' && *(p+1) == '>' ) {
+ _closingType = CLOSED;
+ return p+2; // done; sealed element.
+ }
+ else {
+ _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );
+ return 0;
+ }
+ }
+ return p;
+}
+
+void XMLElement::DeleteAttribute( XMLAttribute* attribute )
+{
+ if ( attribute == 0 ) {
+ return;
+ }
+ MemPool* pool = attribute->_memPool;
+ attribute->~XMLAttribute();
+ pool->Free( attribute );
+}
+
+XMLAttribute* XMLElement::CreateAttribute()
+{
+ TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
+ XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
+ TIXMLASSERT( attrib );
+ attrib->_memPool = &_document->_attributePool;
+ attrib->_memPool->SetTracked();
+ return attrib;
+}
+
+//
+// <ele></ele>
+// <ele>foo<b>bar</b></ele>
+//
+char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
+{
+ // Read the element name.
+ p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
+
+ // The closing element is the </element> form. It is
+ // parsed just like a regular element then deleted from
+ // the DOM.
+ if ( *p == '/' ) {
+ _closingType = CLOSING;
+ ++p;
+ }
+
+ p = _value.ParseName( p );
+ if ( _value.Empty() ) {
+ return 0;
+ }
+
+ p = ParseAttributes( p, curLineNumPtr );
+ if ( !p || !*p || _closingType != OPEN ) {
+ return p;
+ }
+
+ p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
+ return p;
+}
+
+
+
+XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
+{
+ if ( !doc ) {
+ doc = _document;
+ }
+ XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
+ for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
+ element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
+ }
+ return element;
+}
+
+
+bool XMLElement::ShallowEqual( const XMLNode* compare ) const
+{
+ TIXMLASSERT( compare );
+ const XMLElement* other = compare->ToElement();
+ if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
+
+ const XMLAttribute* a=FirstAttribute();
+ const XMLAttribute* b=other->FirstAttribute();
+
+ while ( a && b ) {
+ if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
+ return false;
+ }
+ a = a->Next();
+ b = b->Next();
+ }
+ if ( a || b ) {
+ // different count
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+
+bool XMLElement::Accept( XMLVisitor* visitor ) const
+{
+ TIXMLASSERT( visitor );
+ if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
+ for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
+ if ( !node->Accept( visitor ) ) {
+ break;
+ }
+ }
+ }
+ return visitor->VisitExit( *this );
+}
+
+
+// --------- XMLDocument ----------- //
+
+// Warning: List must match 'enum XMLError'
+const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
+ "XML_SUCCESS",
+ "XML_NO_ATTRIBUTE",
+ "XML_WRONG_ATTRIBUTE_TYPE",
+ "XML_ERROR_FILE_NOT_FOUND",
+ "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
+ "XML_ERROR_FILE_READ_ERROR",
+ "UNUSED_XML_ERROR_ELEMENT_MISMATCH",
+ "XML_ERROR_PARSING_ELEMENT",
+ "XML_ERROR_PARSING_ATTRIBUTE",
+ "UNUSED_XML_ERROR_IDENTIFYING_TAG",
+ "XML_ERROR_PARSING_TEXT",
+ "XML_ERROR_PARSING_CDATA",
+ "XML_ERROR_PARSING_COMMENT",
+ "XML_ERROR_PARSING_DECLARATION",
+ "XML_ERROR_PARSING_UNKNOWN",
+ "XML_ERROR_EMPTY_DOCUMENT",
+ "XML_ERROR_MISMATCHED_ELEMENT",
+ "XML_ERROR_PARSING",
+ "XML_CAN_NOT_CONVERT_TEXT",
+ "XML_NO_TEXT_NODE"
+};
+
+
+XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
+ XMLNode( 0 ),
+ _writeBOM( false ),
+ _processEntities( processEntities ),
+ _errorID(XML_SUCCESS),
+ _whitespaceMode( whitespaceMode ),
+ _errorStr(),
+ _errorLineNum( 0 ),
+ _charBuffer( 0 ),
+ _parseCurLineNum( 0 ),
+ _unlinked(),
+ _elementPool(),
+ _attributePool(),
+ _textPool(),
+ _commentPool()
+{
+ // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
+ _document = this;
+}
+
+
+XMLDocument::~XMLDocument()
+{
+ Clear();
+}
+
+
+void XMLDocument::MarkInUse(XMLNode* node)
+{
+ TIXMLASSERT(node);
+ TIXMLASSERT(node->_parent == 0);
+
+ for (int i = 0; i < _unlinked.Size(); ++i) {
+ if (node == _unlinked[i]) {
+ _unlinked.SwapRemove(i);
+ break;
+ }
+ }
+}
+
+void XMLDocument::Clear()
+{
+ DeleteChildren();
+ while( _unlinked.Size()) {
+ DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete.
+ }
+
+#ifdef DEBUG
+ const bool hadError = Error();
+#endif
+ ClearError();
+
+ Aws::DeleteArray(_charBuffer);
+ _charBuffer = 0;
+
+#if 0
+ _textPool.Trace( "text" );
+ _elementPool.Trace( "element" );
+ _commentPool.Trace( "comment" );
+ _attributePool.Trace( "attribute" );
+#endif
+
+#ifdef DEBUG
+ if ( !hadError ) {
+ TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
+ TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
+ TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
+ TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
+ }
+#endif
+}
+
+
+void XMLDocument::DeepCopy(XMLDocument* target) const
+{
+ TIXMLASSERT(target);
+ if (target == this) {
+ return; // technically success - a no-op.
+ }
+
+ target->Clear();
+ for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
+ target->InsertEndChild(node->DeepClone(target));
+ }
+}
+
+XMLElement* XMLDocument::NewElement( const char* name )
+{
+ XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
+ ele->SetName( name );
+ return ele;
+}
+
+
+XMLComment* XMLDocument::NewComment( const char* str )
+{
+ XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
+ comment->SetValue( str );
+ return comment;
+}
+
+
+XMLText* XMLDocument::NewText( const char* str )
+{
+ XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
+ text->SetValue( str );
+ return text;
+}
+
+
+XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
+{
+ XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
+ dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
+ return dec;
+}
+
+
+XMLUnknown* XMLDocument::NewUnknown( const char* str )
+{
+ XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
+ unk->SetValue( str );
+ return unk;
+}
+
+static FILE* callfopen( const char* filepath, const char* mode )
+{
+ TIXMLASSERT( filepath );
+ TIXMLASSERT( mode );
+#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
+ FILE* fp = 0;
+ errno_t err = fopen_s( &fp, filepath, mode );
+ if ( err ) {
+ return 0;
+ }
+#else
+ FILE* fp = fopen( filepath, mode );
+#endif
+ return fp;
+}
+
+void XMLDocument::DeleteNode( XMLNode* node ) {
+ TIXMLASSERT( node );
+ TIXMLASSERT(node->_document == this );
+ if (node->_parent) {
+ node->_parent->DeleteChild( node );
+ }
+ else {
+ // Isn't in the tree.
+ // Use the parent delete.
+ // Also, we need to mark it tracked: we 'know'
+ // it was never used.
+ node->_memPool->SetTracked();
+ // Call the static XMLNode version:
+ XMLNode::DeleteNode(node);
+ }
+}
+
+
+XMLError XMLDocument::LoadFile( const char* filename )
+{
+ Clear();
+ FILE* fp = callfopen( filename, "rb" );
+ if ( !fp ) {
+ SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename ? filename : "<null>");
+ return _errorID;
+ }
+ LoadFile( fp );
+ fclose( fp );
+ return _errorID;
+}
+
+// This is likely overengineered template art to have a check that unsigned long value incremented
+// by one still fits into size_t. If size_t type is larger than unsigned long type
+// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
+// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
+// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
+// types sizes relate to each other.
+template
+<bool = (sizeof(unsigned long) >= sizeof(size_t))>
+struct LongFitsIntoSizeTMinusOne {
+ static bool Fits( unsigned long value )
+ {
+ return value < (size_t)-1;
+ }
+};
+
+template <>
+struct LongFitsIntoSizeTMinusOne<false> {
+ static bool Fits( unsigned long )
+ {
+ return true;
+ }
+};
+
+XMLError XMLDocument::LoadFile( FILE* fp )
+{
+ Clear();
+
+ fseek( fp, 0, SEEK_SET );
+ if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
+ SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
+ return _errorID;
+ }
+
+ fseek( fp, 0, SEEK_END );
+ const long filelength = ftell( fp );
+ fseek( fp, 0, SEEK_SET );
+ if ( filelength == -1L ) {
+ SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
+ return _errorID;
+ }
+ TIXMLASSERT( filelength >= 0 );
+
+ if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
+ // Cannot handle files which won't fit in buffer together with null terminator
+ SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
+ return _errorID;
+ }
+
+ if ( filelength == 0 ) {
+ SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
+ return _errorID;
+ }
+
+ const size_t size = filelength;
+ TIXMLASSERT( _charBuffer == 0 );
+ _charBuffer = Aws::NewArray <char>(size+1, ALLOCATION_TAG);
+ size_t read = fread( _charBuffer, 1, size, fp );
+ if ( read != size ) {
+ SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
+ return _errorID;
+ }
+
+ _charBuffer[size] = 0;
+
+ Parse();
+ return _errorID;
+}
+
+
+XMLError XMLDocument::SaveFile( const char* filename, bool compact )
+{
+ FILE* fp = callfopen( filename, "w" );
+ if ( !fp ) {
+ SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename ? filename : "<null>");
+ return _errorID;
+ }
+ SaveFile(fp, compact);
+ fclose( fp );
+ return _errorID;
+}
+
+
+XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
+{
+ // Clear any error from the last save, otherwise it will get reported
+ // for *this* call.
+ ClearError();
+ XMLPrinter stream( fp, compact );
+ Print( &stream );
+ return _errorID;
+}
+
+
+XMLError XMLDocument::Parse( const char* p, size_t len )
+{
+ Clear();
+
+ if ( len == 0 || !p || !*p ) {
+ SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
+ return _errorID;
+ }
+ if ( len == (size_t)(-1) ) {
+ len = strlen( p );
+ }
+ TIXMLASSERT( _charBuffer == 0 );
+ _charBuffer = Aws::NewArray<char>(len+1, ALLOCATION_TAG);
+ memcpy( _charBuffer, p, len );
+ _charBuffer[len] = 0;
+
+ Parse();
+ if ( Error() ) {
+ // clean up now essentially dangling memory.
+ // and the parse fail can put objects in the
+ // pools that are dead and inaccessible.
+ DeleteChildren();
+ _elementPool.Clear();
+ _attributePool.Clear();
+ _textPool.Clear();
+ _commentPool.Clear();
+ }
+ return _errorID;
+}
+
+
+void XMLDocument::Print( XMLPrinter* streamer ) const
+{
+ if ( streamer ) {
+ Accept( streamer );
+ }
+ else {
+ XMLPrinter stdoutStreamer( stdout );
+ Accept( &stdoutStreamer );
+ }
+}
+
+
+void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
+{
+ TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
+ _errorID = error;
+ _errorLineNum = lineNum;
+ _errorStr.Reset();
+
+ if (format) {
+ size_t BUFFER_SIZE = 1000;
+ char* buffer = Aws::NewArray<char>(BUFFER_SIZE, ALLOCATION_TAG);
+ TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d: ", ErrorIDToName(error), int(error), int(error), lineNum);
+ size_t len = strlen(buffer);
+
+ va_list va;
+ va_start( va, format );
+ TIXML_VSNPRINTF( buffer + len, BUFFER_SIZE - len, format, va );
+ va_end( va );
+
+ _errorStr.SetStr(buffer);
+ Aws::DeleteArray(buffer);
+ }
+}
+
+
+/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
+{
+ TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
+ const char* errorName = _errorNames[errorID];
+ TIXMLASSERT( errorName && errorName[0] );
+ return errorName;
+}
+
const char* XMLDocument::ErrorStr() const
-{
- return _errorStr.Empty() ? "" : _errorStr.GetStr();
-}
-
-
-void XMLDocument::PrintError() const
-{
- printf("%s\n", ErrorStr());
-}
-
-const char* XMLDocument::ErrorName() const
-{
- return ErrorIDToName(_errorID);
-}
-
-void XMLDocument::Parse()
-{
- TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
- TIXMLASSERT( _charBuffer );
- _parseCurLineNum = 1;
- _parseLineNum = 1;
- char* p = _charBuffer;
- p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
- p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
- if ( !*p ) {
- SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
- return;
- }
- ParseDeep(p, 0, &_parseCurLineNum );
-}
-
-XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
- _elementJustOpened( false ),
- _stack(),
- _firstElement( true ),
- _fp( file ),
- _depth( depth ),
- _textDepth( -1 ),
- _processEntities( true ),
- _compactMode( compact ),
- _buffer()
-{
- for( int i=0; i<ENTITY_RANGE; ++i ) {
- _entityFlag[i] = false;
- _restrictedEntityFlag[i] = false;
- }
- for( int i=0; i<NUM_ENTITIES; ++i ) {
- const char entityValue = entities[i].value;
- const unsigned char flagIndex = (unsigned char)entityValue;
- TIXMLASSERT( flagIndex < ENTITY_RANGE );
- _entityFlag[flagIndex] = true;
- }
- _restrictedEntityFlag[(unsigned char)'&'] = true;
- _restrictedEntityFlag[(unsigned char)'<'] = true;
- _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
- _buffer.Push( 0 );
-}
-
-
-void XMLPrinter::Print( const char* format, ... )
-{
- va_list va;
- va_start( va, format );
-
- if ( _fp ) {
- vfprintf( _fp, format, va );
- }
- else {
- const int len = TIXML_VSCPRINTF( format, va );
- // Close out and re-start the va-args
- va_end( va );
- TIXMLASSERT( len >= 0 );
- va_start( va, format );
- TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
- char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
- TIXML_VSNPRINTF( p, len+1, format, va );
- }
- va_end( va );
-}
-
-
-void XMLPrinter::Write( const char* data, size_t size )
-{
- if ( _fp ) {
- fwrite ( data , sizeof(char), size, _fp);
- }
- else {
- char* p = _buffer.PushArr( static_cast<int>(size) ) - 1; // back up over the null terminator.
- memcpy( p, data, size );
- p[size] = 0;
- }
-}
-
-
-void XMLPrinter::Putc( char ch )
-{
- if ( _fp ) {
- fputc ( ch, _fp);
- }
- else {
- char* p = _buffer.PushArr( sizeof(char) ) - 1; // back up over the null terminator.
- p[0] = ch;
- p[1] = 0;
- }
-}
-
-
-void XMLPrinter::PrintSpace( int depth )
-{
- for( int i=0; i<depth; ++i ) {
- Write( " " );
- }
-}
-
-
-void XMLPrinter::PrintString( const char* p, bool restricted )
-{
- // Look for runs of bytes between entities to print.
- const char* q = p;
-
- if ( _processEntities ) {
- const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
- while ( *q ) {
- TIXMLASSERT( p <= q );
- // Remember, char is sometimes signed. (How many times has that bitten me?)
- if ( *q > 0 && *q < ENTITY_RANGE ) {
- // Check for entities. If one is found, flush
- // the stream up until the entity, write the
- // entity, and keep looking.
- if ( flag[(unsigned char)(*q)] ) {
- while ( p < q ) {
- const size_t delta = q - p;
- const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
- Write( p, toPrint );
- p += toPrint;
- }
- bool entityPatternPrinted = false;
- for( int i=0; i<NUM_ENTITIES; ++i ) {
- if ( entities[i].value == *q ) {
- Putc( '&' );
- Write( entities[i].pattern, entities[i].length );
- Putc( ';' );
- entityPatternPrinted = true;
- break;
- }
- }
- if ( !entityPatternPrinted ) {
- // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
- TIXMLASSERT( false );
- }
- ++p;
- }
- }
- ++q;
- TIXMLASSERT( p <= q );
- }
- }
- // Flush the remaining string. This will be the entire
- // string if an entity wasn't found.
- TIXMLASSERT( p <= q );
- if ( !_processEntities || ( p < q ) ) {
- const size_t delta = q - p;
- const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
- Write( p, toPrint );
- }
-}
-
-
-void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
-{
- if ( writeBOM ) {
- static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
- Write( reinterpret_cast< const char* >( bom ) );
- }
- if ( writeDec ) {
- PushDeclaration( "xml version=\"1.0\"" );
- }
-}
-
-
-void XMLPrinter::OpenElement( const char* name, bool compactMode )
-{
- SealElementIfJustOpened();
- _stack.Push( name );
-
- if ( _textDepth < 0 && !_firstElement && !compactMode ) {
- Putc( '\n' );
- }
- if ( !compactMode ) {
- PrintSpace( _depth );
- }
-
- Write ( "<" );
- Write ( name );
-
- _elementJustOpened = true;
- _firstElement = false;
- ++_depth;
-}
-
-
-void XMLPrinter::PushAttribute( const char* name, const char* value )
-{
- TIXMLASSERT( _elementJustOpened );
- Putc ( ' ' );
- Write( name );
- Write( "=\"" );
- PrintString( value, false );
- Putc ( '\"' );
-}
-
-
-void XMLPrinter::PushAttribute( const char* name, int v )
-{
- char buf[BUF_SIZE];
- XMLUtil::ToStr( v, buf, BUF_SIZE );
- PushAttribute( name, buf );
-}
-
-
-void XMLPrinter::PushAttribute( const char* name, unsigned v )
-{
- char buf[BUF_SIZE];
- XMLUtil::ToStr( v, buf, BUF_SIZE );
- PushAttribute( name, buf );
-}
-
-
-void XMLPrinter::PushAttribute(const char* name, int64_t v)
-{
- char buf[BUF_SIZE];
- XMLUtil::ToStr(v, buf, BUF_SIZE);
- PushAttribute(name, buf);
-}
-
-
-void XMLPrinter::PushAttribute( const char* name, bool v )
-{
- char buf[BUF_SIZE];
- XMLUtil::ToStr( v, buf, BUF_SIZE );
- PushAttribute( name, buf );
-}
-
-
-void XMLPrinter::PushAttribute( const char* name, double v )
-{
- char buf[BUF_SIZE];
- XMLUtil::ToStr( v, buf, BUF_SIZE );
- PushAttribute( name, buf );
-}
-
-
-void XMLPrinter::CloseElement( bool compactMode )
-{
- --_depth;
- const char* name = _stack.Pop();
-
- if ( _elementJustOpened ) {
- Write( "/>" );
- }
- else {
- if ( _textDepth < 0 && !compactMode) {
- Putc( '\n' );
- PrintSpace( _depth );
- }
- Write ( "</" );
- Write ( name );
- Write ( ">" );
- }
-
- if ( _textDepth == _depth ) {
- _textDepth = -1;
- }
- if ( _depth == 0 && !compactMode) {
- Putc( '\n' );
- }
- _elementJustOpened = false;
-}
-
-
-void XMLPrinter::SealElementIfJustOpened()
-{
- if ( !_elementJustOpened ) {
- return;
- }
- _elementJustOpened = false;
- Putc( '>' );
-}
-
-
-void XMLPrinter::PushText( const char* text, bool cdata )
-{
- _textDepth = _depth-1;
-
- SealElementIfJustOpened();
- if ( cdata ) {
- Write( "<![CDATA[" );
- Write( text );
- Write( "]]>" );
- }
- else {
- PrintString( text, true );
- }
-}
-
-void XMLPrinter::PushText( int64_t value )
-{
- char buf[BUF_SIZE];
- XMLUtil::ToStr( value, buf, BUF_SIZE );
- PushText( buf, false );
-}
-
-void XMLPrinter::PushText( int value )
-{
- char buf[BUF_SIZE];
- XMLUtil::ToStr( value, buf, BUF_SIZE );
- PushText( buf, false );
-}
-
-
-void XMLPrinter::PushText( unsigned value )
-{
- char buf[BUF_SIZE];
- XMLUtil::ToStr( value, buf, BUF_SIZE );
- PushText( buf, false );
-}
-
-
-void XMLPrinter::PushText( bool value )
-{
- char buf[BUF_SIZE];
- XMLUtil::ToStr( value, buf, BUF_SIZE );
- PushText( buf, false );
-}
-
-
-void XMLPrinter::PushText( float value )
-{
- char buf[BUF_SIZE];
- XMLUtil::ToStr( value, buf, BUF_SIZE );
- PushText( buf, false );
-}
-
-
-void XMLPrinter::PushText( double value )
-{
- char buf[BUF_SIZE];
- XMLUtil::ToStr( value, buf, BUF_SIZE );
- PushText( buf, false );
-}
-
-
-void XMLPrinter::PushComment( const char* comment )
-{
- SealElementIfJustOpened();
- if ( _textDepth < 0 && !_firstElement && !_compactMode) {
- Putc( '\n' );
- PrintSpace( _depth );
- }
- _firstElement = false;
-
- Write( "<!--" );
- Write( comment );
- Write( "-->" );
-}
-
-
-void XMLPrinter::PushDeclaration( const char* value )
-{
- SealElementIfJustOpened();
- if ( _textDepth < 0 && !_firstElement && !_compactMode) {
- Putc( '\n' );
- PrintSpace( _depth );
- }
- _firstElement = false;
-
- Write( "<?" );
- Write( value );
- Write( "?>" );
-}
-
-
-void XMLPrinter::PushUnknown( const char* value )
-{
- SealElementIfJustOpened();
- if ( _textDepth < 0 && !_firstElement && !_compactMode) {
- Putc( '\n' );
- PrintSpace( _depth );
- }
- _firstElement = false;
-
- Write( "<!" );
- Write( value );
- Putc( '>' );
-}
-
-
-bool XMLPrinter::VisitEnter( const XMLDocument& doc )
-{
- _processEntities = doc.ProcessEntities();
- if ( doc.HasBOM() ) {
- PushHeader( true, false );
- }
- return true;
-}
-
-
-bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
-{
- const XMLElement* parentElem = 0;
- if ( element.Parent() ) {
- parentElem = element.Parent()->ToElement();
- }
- const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
- OpenElement( element.Name(), compactMode );
- while ( attribute ) {
- PushAttribute( attribute->Name(), attribute->Value() );
- attribute = attribute->Next();
- }
- return true;
-}
-
-
-bool XMLPrinter::VisitExit( const XMLElement& element )
-{
- CloseElement( CompactMode(element) );
- return true;
-}
-
-
-bool XMLPrinter::Visit( const XMLText& text )
-{
- PushText( text.Value(), text.CData() );
- return true;
-}
-
-
-bool XMLPrinter::Visit( const XMLComment& comment )
-{
- PushComment( comment.Value() );
- return true;
-}
-
-bool XMLPrinter::Visit( const XMLDeclaration& declaration )
-{
- PushDeclaration( declaration.Value() );
- return true;
-}
-
-
-bool XMLPrinter::Visit( const XMLUnknown& unknown )
-{
- PushUnknown( unknown.Value() );
- return true;
-}
-
-} // namespace tinyxml2
+{
+ return _errorStr.Empty() ? "" : _errorStr.GetStr();
+}
+
+
+void XMLDocument::PrintError() const
+{
+ printf("%s\n", ErrorStr());
+}
+
+const char* XMLDocument::ErrorName() const
+{
+ return ErrorIDToName(_errorID);
+}
+
+void XMLDocument::Parse()
+{
+ TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
+ TIXMLASSERT( _charBuffer );
+ _parseCurLineNum = 1;
+ _parseLineNum = 1;
+ char* p = _charBuffer;
+ p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
+ p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
+ if ( !*p ) {
+ SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
+ return;
+ }
+ ParseDeep(p, 0, &_parseCurLineNum );
+}
+
+XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
+ _elementJustOpened( false ),
+ _stack(),
+ _firstElement( true ),
+ _fp( file ),
+ _depth( depth ),
+ _textDepth( -1 ),
+ _processEntities( true ),
+ _compactMode( compact ),
+ _buffer()
+{
+ for( int i=0; i<ENTITY_RANGE; ++i ) {
+ _entityFlag[i] = false;
+ _restrictedEntityFlag[i] = false;
+ }
+ for( int i=0; i<NUM_ENTITIES; ++i ) {
+ const char entityValue = entities[i].value;
+ const unsigned char flagIndex = (unsigned char)entityValue;
+ TIXMLASSERT( flagIndex < ENTITY_RANGE );
+ _entityFlag[flagIndex] = true;
+ }
+ _restrictedEntityFlag[(unsigned char)'&'] = true;
+ _restrictedEntityFlag[(unsigned char)'<'] = true;
+ _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
+ _buffer.Push( 0 );
+}
+
+
+void XMLPrinter::Print( const char* format, ... )
+{
+ va_list va;
+ va_start( va, format );
+
+ if ( _fp ) {
+ vfprintf( _fp, format, va );
+ }
+ else {
+ const int len = TIXML_VSCPRINTF( format, va );
+ // Close out and re-start the va-args
+ va_end( va );
+ TIXMLASSERT( len >= 0 );
+ va_start( va, format );
+ TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
+ char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
+ TIXML_VSNPRINTF( p, len+1, format, va );
+ }
+ va_end( va );
+}
+
+
+void XMLPrinter::Write( const char* data, size_t size )
+{
+ if ( _fp ) {
+ fwrite ( data , sizeof(char), size, _fp);
+ }
+ else {
+ char* p = _buffer.PushArr( static_cast<int>(size) ) - 1; // back up over the null terminator.
+ memcpy( p, data, size );
+ p[size] = 0;
+ }
+}
+
+
+void XMLPrinter::Putc( char ch )
+{
+ if ( _fp ) {
+ fputc ( ch, _fp);
+ }
+ else {
+ char* p = _buffer.PushArr( sizeof(char) ) - 1; // back up over the null terminator.
+ p[0] = ch;
+ p[1] = 0;
+ }
+}
+
+
+void XMLPrinter::PrintSpace( int depth )
+{
+ for( int i=0; i<depth; ++i ) {
+ Write( " " );
+ }
+}
+
+
+void XMLPrinter::PrintString( const char* p, bool restricted )
+{
+ // Look for runs of bytes between entities to print.
+ const char* q = p;
+
+ if ( _processEntities ) {
+ const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
+ while ( *q ) {
+ TIXMLASSERT( p <= q );
+ // Remember, char is sometimes signed. (How many times has that bitten me?)
+ if ( *q > 0 && *q < ENTITY_RANGE ) {
+ // Check for entities. If one is found, flush
+ // the stream up until the entity, write the
+ // entity, and keep looking.
+ if ( flag[(unsigned char)(*q)] ) {
+ while ( p < q ) {
+ const size_t delta = q - p;
+ const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
+ Write( p, toPrint );
+ p += toPrint;
+ }
+ bool entityPatternPrinted = false;
+ for( int i=0; i<NUM_ENTITIES; ++i ) {
+ if ( entities[i].value == *q ) {
+ Putc( '&' );
+ Write( entities[i].pattern, entities[i].length );
+ Putc( ';' );
+ entityPatternPrinted = true;
+ break;
+ }
+ }
+ if ( !entityPatternPrinted ) {
+ // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
+ TIXMLASSERT( false );
+ }
+ ++p;
+ }
+ }
+ ++q;
+ TIXMLASSERT( p <= q );
+ }
+ }
+ // Flush the remaining string. This will be the entire
+ // string if an entity wasn't found.
+ TIXMLASSERT( p <= q );
+ if ( !_processEntities || ( p < q ) ) {
+ const size_t delta = q - p;
+ const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
+ Write( p, toPrint );
+ }
+}
+
+
+void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
+{
+ if ( writeBOM ) {
+ static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
+ Write( reinterpret_cast< const char* >( bom ) );
+ }
+ if ( writeDec ) {
+ PushDeclaration( "xml version=\"1.0\"" );
+ }
+}
+
+
+void XMLPrinter::OpenElement( const char* name, bool compactMode )
+{
+ SealElementIfJustOpened();
+ _stack.Push( name );
+
+ if ( _textDepth < 0 && !_firstElement && !compactMode ) {
+ Putc( '\n' );
+ }
+ if ( !compactMode ) {
+ PrintSpace( _depth );
+ }
+
+ Write ( "<" );
+ Write ( name );
+
+ _elementJustOpened = true;
+ _firstElement = false;
+ ++_depth;
+}
+
+
+void XMLPrinter::PushAttribute( const char* name, const char* value )
+{
+ TIXMLASSERT( _elementJustOpened );
+ Putc ( ' ' );
+ Write( name );
+ Write( "=\"" );
+ PrintString( value, false );
+ Putc ( '\"' );
+}
+
+
+void XMLPrinter::PushAttribute( const char* name, int v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ PushAttribute( name, buf );
+}
+
+
+void XMLPrinter::PushAttribute( const char* name, unsigned v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ PushAttribute( name, buf );
+}
+
+
+void XMLPrinter::PushAttribute(const char* name, int64_t v)
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr(v, buf, BUF_SIZE);
+ PushAttribute(name, buf);
+}
+
+
+void XMLPrinter::PushAttribute( const char* name, bool v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ PushAttribute( name, buf );
+}
+
+
+void XMLPrinter::PushAttribute( const char* name, double v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ PushAttribute( name, buf );
+}
+
+
+void XMLPrinter::CloseElement( bool compactMode )
+{
+ --_depth;
+ const char* name = _stack.Pop();
+
+ if ( _elementJustOpened ) {
+ Write( "/>" );
+ }
+ else {
+ if ( _textDepth < 0 && !compactMode) {
+ Putc( '\n' );
+ PrintSpace( _depth );
+ }
+ Write ( "</" );
+ Write ( name );
+ Write ( ">" );
+ }
+
+ if ( _textDepth == _depth ) {
+ _textDepth = -1;
+ }
+ if ( _depth == 0 && !compactMode) {
+ Putc( '\n' );
+ }
+ _elementJustOpened = false;
+}
+
+
+void XMLPrinter::SealElementIfJustOpened()
+{
+ if ( !_elementJustOpened ) {
+ return;
+ }
+ _elementJustOpened = false;
+ Putc( '>' );
+}
+
+
+void XMLPrinter::PushText( const char* text, bool cdata )
+{
+ _textDepth = _depth-1;
+
+ SealElementIfJustOpened();
+ if ( cdata ) {
+ Write( "<![CDATA[" );
+ Write( text );
+ Write( "]]>" );
+ }
+ else {
+ PrintString( text, true );
+ }
+}
+
+void XMLPrinter::PushText( int64_t value )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( value, buf, BUF_SIZE );
+ PushText( buf, false );
+}
+
+void XMLPrinter::PushText( int value )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( value, buf, BUF_SIZE );
+ PushText( buf, false );
+}
+
+
+void XMLPrinter::PushText( unsigned value )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( value, buf, BUF_SIZE );
+ PushText( buf, false );
+}
+
+
+void XMLPrinter::PushText( bool value )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( value, buf, BUF_SIZE );
+ PushText( buf, false );
+}
+
+
+void XMLPrinter::PushText( float value )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( value, buf, BUF_SIZE );
+ PushText( buf, false );
+}
+
+
+void XMLPrinter::PushText( double value )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( value, buf, BUF_SIZE );
+ PushText( buf, false );
+}
+
+
+void XMLPrinter::PushComment( const char* comment )
+{
+ SealElementIfJustOpened();
+ if ( _textDepth < 0 && !_firstElement && !_compactMode) {
+ Putc( '\n' );
+ PrintSpace( _depth );
+ }
+ _firstElement = false;
+
+ Write( "<!--" );
+ Write( comment );
+ Write( "-->" );
+}
+
+
+void XMLPrinter::PushDeclaration( const char* value )
+{
+ SealElementIfJustOpened();
+ if ( _textDepth < 0 && !_firstElement && !_compactMode) {
+ Putc( '\n' );
+ PrintSpace( _depth );
+ }
+ _firstElement = false;
+
+ Write( "<?" );
+ Write( value );
+ Write( "?>" );
+}
+
+
+void XMLPrinter::PushUnknown( const char* value )
+{
+ SealElementIfJustOpened();
+ if ( _textDepth < 0 && !_firstElement && !_compactMode) {
+ Putc( '\n' );
+ PrintSpace( _depth );
+ }
+ _firstElement = false;
+
+ Write( "<!" );
+ Write( value );
+ Putc( '>' );
+}
+
+
+bool XMLPrinter::VisitEnter( const XMLDocument& doc )
+{
+ _processEntities = doc.ProcessEntities();
+ if ( doc.HasBOM() ) {
+ PushHeader( true, false );
+ }
+ return true;
+}
+
+
+bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
+{
+ const XMLElement* parentElem = 0;
+ if ( element.Parent() ) {
+ parentElem = element.Parent()->ToElement();
+ }
+ const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
+ OpenElement( element.Name(), compactMode );
+ while ( attribute ) {
+ PushAttribute( attribute->Name(), attribute->Value() );
+ attribute = attribute->Next();
+ }
+ return true;
+}
+
+
+bool XMLPrinter::VisitExit( const XMLElement& element )
+{
+ CloseElement( CompactMode(element) );
+ return true;
+}
+
+
+bool XMLPrinter::Visit( const XMLText& text )
+{
+ PushText( text.Value(), text.CData() );
+ return true;
+}
+
+
+bool XMLPrinter::Visit( const XMLComment& comment )
+{
+ PushComment( comment.Value() );
+ return true;
+}
+
+bool XMLPrinter::Visit( const XMLDeclaration& declaration )
+{
+ PushDeclaration( declaration.Value() );
+ return true;
+}
+
+
+bool XMLPrinter::Visit( const XMLUnknown& unknown )
+{
+ PushUnknown( unknown.Value() );
+ return true;
+}
+
+} // namespace tinyxml2
} // namespace External
-} // namespace Aws \ No newline at end of file
+} // namespace Aws \ No newline at end of file