cJSON.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 23 Jun 2017 17:28:03 -0400
changeset 58 1390348facc7
permissions -rw-r--r--
Command line tool that decrypts an OPVault keychain and dumps it to stdout.

To compile: gcc -o opvault opvault.c cJSON.c -lcrypto

Usage: ./opvault </path/to/mykeychain.opvault> <password>

This is just a proof of concept; I'll be recycling this into proper OPVault
support in 1pass later and deleting this tool.

This uses OpenSSL's libcrypto for the math instead of all the homegrown
crypto this project is otherwise using. I'll probably migrate the rest in
this direction, too, since this wasn't as bad as I expected to use and
gets you all the package-manager mojo of automatic bug fixes and security
patches and shared code, etc.

cJSON parses JSON in C. That is from https://github.com/DaveGamble/cJSON

An example OPVault keychain from AgileBits is available here:

https://cache.agilebits.com/security-kb/
icculus@58
     1
/*
icculus@58
     2
  Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
icculus@58
     3
icculus@58
     4
  Permission is hereby granted, free of charge, to any person obtaining a copy
icculus@58
     5
  of this software and associated documentation files (the "Software"), to deal
icculus@58
     6
  in the Software without restriction, including without limitation the rights
icculus@58
     7
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
icculus@58
     8
  copies of the Software, and to permit persons to whom the Software is
icculus@58
     9
  furnished to do so, subject to the following conditions:
icculus@58
    10
icculus@58
    11
  The above copyright notice and this permission notice shall be included in
icculus@58
    12
  all copies or substantial portions of the Software.
icculus@58
    13
icculus@58
    14
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
icculus@58
    15
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
icculus@58
    16
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
icculus@58
    17
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
icculus@58
    18
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
icculus@58
    19
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
icculus@58
    20
  THE SOFTWARE.
icculus@58
    21
*/
icculus@58
    22
icculus@58
    23
/* cJSON */
icculus@58
    24
/* JSON parser in C. */
icculus@58
    25
icculus@58
    26
#ifdef __GNUC__
icculus@58
    27
#pragma GCC visibility push(default)
icculus@58
    28
#endif
icculus@58
    29
icculus@58
    30
#include <string.h>
icculus@58
    31
#include <stdio.h>
icculus@58
    32
#include <math.h>
icculus@58
    33
#include <stdlib.h>
icculus@58
    34
#include <float.h>
icculus@58
    35
#include <limits.h>
icculus@58
    36
#include <ctype.h>
icculus@58
    37
#include <locale.h>
icculus@58
    38
icculus@58
    39
#ifdef __GNUC__
icculus@58
    40
#pragma GCC visibility pop
icculus@58
    41
#endif
icculus@58
    42
icculus@58
    43
#include "cJSON.h"
icculus@58
    44
icculus@58
    45
/* define our own boolean type */
icculus@58
    46
#define true ((cJSON_bool)1)
icculus@58
    47
#define false ((cJSON_bool)0)
icculus@58
    48
icculus@58
    49
typedef struct {
icculus@58
    50
    const unsigned char *json;
icculus@58
    51
    size_t position;
icculus@58
    52
} error;
icculus@58
    53
static error global_error = { NULL, 0 };
icculus@58
    54
icculus@58
    55
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void)
icculus@58
    56
{
icculus@58
    57
    return (const char*) (global_error.json + global_error.position);
icculus@58
    58
}
icculus@58
    59
icculus@58
    60
/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
icculus@58
    61
#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 5) || (CJSON_VERSION_PATCH != 5)
icculus@58
    62
    #error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
icculus@58
    63
#endif
icculus@58
    64
icculus@58
    65
CJSON_PUBLIC(const char*) cJSON_Version(void)
icculus@58
    66
{
icculus@58
    67
    static char version[15];
icculus@58
    68
    sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH);
icculus@58
    69
icculus@58
    70
    return version;
icculus@58
    71
}
icculus@58
    72
icculus@58
    73
/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */
icculus@58
    74
static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2)
icculus@58
    75
{
icculus@58
    76
    if ((string1 == NULL) || (string2 == NULL))
icculus@58
    77
    {
icculus@58
    78
        return 1;
icculus@58
    79
    }
icculus@58
    80
icculus@58
    81
    if (string1 == string2)
icculus@58
    82
    {
icculus@58
    83
        return 0;
icculus@58
    84
    }
icculus@58
    85
icculus@58
    86
    for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++)
icculus@58
    87
    {
icculus@58
    88
        if (*string1 == '\0')
icculus@58
    89
        {
icculus@58
    90
            return 0;
icculus@58
    91
        }
icculus@58
    92
    }
icculus@58
    93
icculus@58
    94
    return tolower(*string1) - tolower(*string2);
icculus@58
    95
}
icculus@58
    96
icculus@58
    97
typedef struct internal_hooks
icculus@58
    98
{
icculus@58
    99
    void *(*allocate)(size_t size);
icculus@58
   100
    void (*deallocate)(void *pointer);
icculus@58
   101
    void *(*reallocate)(void *pointer, size_t size);
icculus@58
   102
} internal_hooks;
icculus@58
   103
icculus@58
   104
static internal_hooks global_hooks = { malloc, free, realloc };
icculus@58
   105
icculus@58
   106
static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks)
icculus@58
   107
{
icculus@58
   108
    size_t length = 0;
icculus@58
   109
    unsigned char *copy = NULL;
icculus@58
   110
icculus@58
   111
    if (string == NULL)
icculus@58
   112
    {
icculus@58
   113
        return NULL;
icculus@58
   114
    }
icculus@58
   115
icculus@58
   116
    length = strlen((const char*)string) + sizeof("");
icculus@58
   117
    if (!(copy = (unsigned char*)hooks->allocate(length)))
icculus@58
   118
    {
icculus@58
   119
        return NULL;
icculus@58
   120
    }
icculus@58
   121
    memcpy(copy, string, length);
icculus@58
   122
icculus@58
   123
    return copy;
icculus@58
   124
}
icculus@58
   125
icculus@58
   126
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks)
icculus@58
   127
{
icculus@58
   128
    if (hooks == NULL)
icculus@58
   129
    {
icculus@58
   130
        /* Reset hooks */
icculus@58
   131
        global_hooks.allocate = malloc;
icculus@58
   132
        global_hooks.deallocate = free;
icculus@58
   133
        global_hooks.reallocate = realloc;
icculus@58
   134
        return;
icculus@58
   135
    }
icculus@58
   136
icculus@58
   137
    global_hooks.allocate = malloc;
icculus@58
   138
    if (hooks->malloc_fn != NULL)
icculus@58
   139
    {
icculus@58
   140
        global_hooks.allocate = hooks->malloc_fn;
icculus@58
   141
    }
icculus@58
   142
icculus@58
   143
    global_hooks.deallocate = free;
icculus@58
   144
    if (hooks->free_fn != NULL)
icculus@58
   145
    {
icculus@58
   146
        global_hooks.deallocate = hooks->free_fn;
icculus@58
   147
    }
icculus@58
   148
icculus@58
   149
    /* use realloc only if both free and malloc are used */
icculus@58
   150
    global_hooks.reallocate = NULL;
icculus@58
   151
    if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free))
icculus@58
   152
    {
icculus@58
   153
        global_hooks.reallocate = realloc;
icculus@58
   154
    }
icculus@58
   155
}
icculus@58
   156
icculus@58
   157
/* Internal constructor. */
icculus@58
   158
static cJSON *cJSON_New_Item(const internal_hooks * const hooks)
icculus@58
   159
{
icculus@58
   160
    cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON));
icculus@58
   161
    if (node)
icculus@58
   162
    {
icculus@58
   163
        memset(node, '\0', sizeof(cJSON));
icculus@58
   164
    }
icculus@58
   165
icculus@58
   166
    return node;
icculus@58
   167
}
icculus@58
   168
icculus@58
   169
/* Delete a cJSON structure. */
icculus@58
   170
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item)
icculus@58
   171
{
icculus@58
   172
    cJSON *next = NULL;
icculus@58
   173
    while (item != NULL)
icculus@58
   174
    {
icculus@58
   175
        next = item->next;
icculus@58
   176
        if (!(item->type & cJSON_IsReference) && (item->child != NULL))
icculus@58
   177
        {
icculus@58
   178
            cJSON_Delete(item->child);
icculus@58
   179
        }
icculus@58
   180
        if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
icculus@58
   181
        {
icculus@58
   182
            global_hooks.deallocate(item->valuestring);
icculus@58
   183
        }
icculus@58
   184
        if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
icculus@58
   185
        {
icculus@58
   186
            global_hooks.deallocate(item->string);
icculus@58
   187
        }
icculus@58
   188
        global_hooks.deallocate(item);
icculus@58
   189
        item = next;
icculus@58
   190
    }
icculus@58
   191
}
icculus@58
   192
icculus@58
   193
/* get the decimal point character of the current locale */
icculus@58
   194
static unsigned char get_decimal_point(void)
icculus@58
   195
{
icculus@58
   196
    struct lconv *lconv = localeconv();
icculus@58
   197
    return (unsigned char) lconv->decimal_point[0];
icculus@58
   198
}
icculus@58
   199
icculus@58
   200
typedef struct
icculus@58
   201
{
icculus@58
   202
    const unsigned char *content;
icculus@58
   203
    size_t length;
icculus@58
   204
    size_t offset;
icculus@58
   205
    size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */
icculus@58
   206
    internal_hooks hooks;
icculus@58
   207
} parse_buffer;
icculus@58
   208
icculus@58
   209
/* check if the given size is left to read in a given parse buffer (starting with 1) */
icculus@58
   210
#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))
icculus@58
   211
#define cannot_read(buffer, size) (!can_read(buffer, size))
icculus@58
   212
/* check if the buffer can be accessed at the given index (starting with 0) */
icculus@58
   213
#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
icculus@58
   214
#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
icculus@58
   215
/* get a pointer to the buffer at the position */
icculus@58
   216
#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
icculus@58
   217
icculus@58
   218
/* Parse the input text to generate a number, and populate the result into item. */
icculus@58
   219
static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer)
icculus@58
   220
{
icculus@58
   221
    double number = 0;
icculus@58
   222
    unsigned char *after_end = NULL;
icculus@58
   223
    unsigned char number_c_string[64];
icculus@58
   224
    unsigned char decimal_point = get_decimal_point();
icculus@58
   225
    size_t i = 0;
icculus@58
   226
icculus@58
   227
    if ((input_buffer == NULL) || (input_buffer->content == NULL))
icculus@58
   228
    {
icculus@58
   229
        return false;
icculus@58
   230
    }
icculus@58
   231
icculus@58
   232
    /* copy the number into a temporary buffer and replace '.' with the decimal point
icculus@58
   233
     * of the current locale (for strtod)
icculus@58
   234
     * This also takes care of '\0' not necessarily being available for marking the end of the input */
icculus@58
   235
    for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++)
icculus@58
   236
    {
icculus@58
   237
        switch (buffer_at_offset(input_buffer)[i])
icculus@58
   238
        {
icculus@58
   239
            case '0':
icculus@58
   240
            case '1':
icculus@58
   241
            case '2':
icculus@58
   242
            case '3':
icculus@58
   243
            case '4':
icculus@58
   244
            case '5':
icculus@58
   245
            case '6':
icculus@58
   246
            case '7':
icculus@58
   247
            case '8':
icculus@58
   248
            case '9':
icculus@58
   249
            case '+':
icculus@58
   250
            case '-':
icculus@58
   251
            case 'e':
icculus@58
   252
            case 'E':
icculus@58
   253
                number_c_string[i] = buffer_at_offset(input_buffer)[i];
icculus@58
   254
                break;
icculus@58
   255
icculus@58
   256
            case '.':
icculus@58
   257
                number_c_string[i] = decimal_point;
icculus@58
   258
                break;
icculus@58
   259
icculus@58
   260
            default:
icculus@58
   261
                goto loop_end;
icculus@58
   262
        }
icculus@58
   263
    }
icculus@58
   264
loop_end:
icculus@58
   265
    number_c_string[i] = '\0';
icculus@58
   266
icculus@58
   267
    number = strtod((const char*)number_c_string, (char**)&after_end);
icculus@58
   268
    if (number_c_string == after_end)
icculus@58
   269
    {
icculus@58
   270
        return false; /* parse_error */
icculus@58
   271
    }
icculus@58
   272
icculus@58
   273
    item->valuedouble = number;
icculus@58
   274
icculus@58
   275
    /* use saturation in case of overflow */
icculus@58
   276
    if (number >= INT_MAX)
icculus@58
   277
    {
icculus@58
   278
        item->valueint = INT_MAX;
icculus@58
   279
    }
icculus@58
   280
    else if (number <= INT_MIN)
icculus@58
   281
    {
icculus@58
   282
        item->valueint = INT_MIN;
icculus@58
   283
    }
icculus@58
   284
    else
icculus@58
   285
    {
icculus@58
   286
        item->valueint = (int)number;
icculus@58
   287
    }
icculus@58
   288
icculus@58
   289
    item->type = cJSON_Number;
icculus@58
   290
icculus@58
   291
    input_buffer->offset += (size_t)(after_end - number_c_string);
icculus@58
   292
    return true;
icculus@58
   293
}
icculus@58
   294
icculus@58
   295
/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
icculus@58
   296
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
icculus@58
   297
{
icculus@58
   298
    if (number >= INT_MAX)
icculus@58
   299
    {
icculus@58
   300
        object->valueint = INT_MAX;
icculus@58
   301
    }
icculus@58
   302
    else if (number <= INT_MIN)
icculus@58
   303
    {
icculus@58
   304
        object->valueint = INT_MIN;
icculus@58
   305
    }
icculus@58
   306
    else
icculus@58
   307
    {
icculus@58
   308
        object->valueint = (int)number;
icculus@58
   309
    }
icculus@58
   310
icculus@58
   311
    return object->valuedouble = number;
icculus@58
   312
}
icculus@58
   313
icculus@58
   314
typedef struct
icculus@58
   315
{
icculus@58
   316
    unsigned char *buffer;
icculus@58
   317
    size_t length;
icculus@58
   318
    size_t offset;
icculus@58
   319
    size_t depth; /* current nesting depth (for formatted printing) */
icculus@58
   320
    cJSON_bool noalloc;
icculus@58
   321
    cJSON_bool format; /* is this print a formatted print */
icculus@58
   322
    internal_hooks hooks;
icculus@58
   323
} printbuffer;
icculus@58
   324
icculus@58
   325
/* realloc printbuffer if necessary to have at least "needed" bytes more */
icculus@58
   326
static unsigned char* ensure(printbuffer * const p, size_t needed)
icculus@58
   327
{
icculus@58
   328
    unsigned char *newbuffer = NULL;
icculus@58
   329
    size_t newsize = 0;
icculus@58
   330
icculus@58
   331
    if ((p == NULL) || (p->buffer == NULL))
icculus@58
   332
    {
icculus@58
   333
        return NULL;
icculus@58
   334
    }
icculus@58
   335
icculus@58
   336
    if ((p->length > 0) && (p->offset >= p->length))
icculus@58
   337
    {
icculus@58
   338
        /* make sure that offset is valid */
icculus@58
   339
        return NULL;
icculus@58
   340
    }
icculus@58
   341
icculus@58
   342
    if (needed > INT_MAX)
icculus@58
   343
    {
icculus@58
   344
        /* sizes bigger than INT_MAX are currently not supported */
icculus@58
   345
        return NULL;
icculus@58
   346
    }
icculus@58
   347
icculus@58
   348
    needed += p->offset + 1;
icculus@58
   349
    if (needed <= p->length)
icculus@58
   350
    {
icculus@58
   351
        return p->buffer + p->offset;
icculus@58
   352
    }
icculus@58
   353
icculus@58
   354
    if (p->noalloc) {
icculus@58
   355
        return NULL;
icculus@58
   356
    }
icculus@58
   357
icculus@58
   358
    /* calculate new buffer size */
icculus@58
   359
    if (needed > (INT_MAX / 2))
icculus@58
   360
    {
icculus@58
   361
        /* overflow of int, use INT_MAX if possible */
icculus@58
   362
        if (needed <= INT_MAX)
icculus@58
   363
        {
icculus@58
   364
            newsize = INT_MAX;
icculus@58
   365
        }
icculus@58
   366
        else
icculus@58
   367
        {
icculus@58
   368
            return NULL;
icculus@58
   369
        }
icculus@58
   370
    }
icculus@58
   371
    else
icculus@58
   372
    {
icculus@58
   373
        newsize = needed * 2;
icculus@58
   374
    }
icculus@58
   375
icculus@58
   376
    if (p->hooks.reallocate != NULL)
icculus@58
   377
    {
icculus@58
   378
        /* reallocate with realloc if available */
icculus@58
   379
        newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize);
icculus@58
   380
    }
icculus@58
   381
    else
icculus@58
   382
    {
icculus@58
   383
        /* otherwise reallocate manually */
icculus@58
   384
        newbuffer = (unsigned char*)p->hooks.allocate(newsize);
icculus@58
   385
        if (!newbuffer)
icculus@58
   386
        {
icculus@58
   387
            p->hooks.deallocate(p->buffer);
icculus@58
   388
            p->length = 0;
icculus@58
   389
            p->buffer = NULL;
icculus@58
   390
icculus@58
   391
            return NULL;
icculus@58
   392
        }
icculus@58
   393
        if (newbuffer)
icculus@58
   394
        {
icculus@58
   395
            memcpy(newbuffer, p->buffer, p->offset + 1);
icculus@58
   396
        }
icculus@58
   397
        p->hooks.deallocate(p->buffer);
icculus@58
   398
    }
icculus@58
   399
    p->length = newsize;
icculus@58
   400
    p->buffer = newbuffer;
icculus@58
   401
icculus@58
   402
    return newbuffer + p->offset;
icculus@58
   403
}
icculus@58
   404
icculus@58
   405
/* calculate the new length of the string in a printbuffer and update the offset */
icculus@58
   406
static void update_offset(printbuffer * const buffer)
icculus@58
   407
{
icculus@58
   408
    const unsigned char *buffer_pointer = NULL;
icculus@58
   409
    if ((buffer == NULL) || (buffer->buffer == NULL))
icculus@58
   410
    {
icculus@58
   411
        return;
icculus@58
   412
    }
icculus@58
   413
    buffer_pointer = buffer->buffer + buffer->offset;
icculus@58
   414
icculus@58
   415
    buffer->offset += strlen((const char*)buffer_pointer);
icculus@58
   416
}
icculus@58
   417
icculus@58
   418
/* Render the number nicely from the given item into a string. */
icculus@58
   419
static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
icculus@58
   420
{
icculus@58
   421
    unsigned char *output_pointer = NULL;
icculus@58
   422
    double d = item->valuedouble;
icculus@58
   423
    int length = 0;
icculus@58
   424
    size_t i = 0;
icculus@58
   425
    unsigned char number_buffer[26]; /* temporary buffer to print the number into */
icculus@58
   426
    unsigned char decimal_point = get_decimal_point();
icculus@58
   427
    double test;
icculus@58
   428
icculus@58
   429
    if (output_buffer == NULL)
icculus@58
   430
    {
icculus@58
   431
        return false;
icculus@58
   432
    }
icculus@58
   433
icculus@58
   434
    /* This checks for NaN and Infinity */
icculus@58
   435
    if ((d * 0) != 0)
icculus@58
   436
    {
icculus@58
   437
        length = sprintf((char*)number_buffer, "null");
icculus@58
   438
    }
icculus@58
   439
    else
icculus@58
   440
    {
icculus@58
   441
        /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
icculus@58
   442
        length = sprintf((char*)number_buffer, "%1.15g", d);
icculus@58
   443
icculus@58
   444
        /* Check whether the original double can be recovered */
icculus@58
   445
        if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != d))
icculus@58
   446
        {
icculus@58
   447
            /* If not, print with 17 decimal places of precision */
icculus@58
   448
            length = sprintf((char*)number_buffer, "%1.17g", d);
icculus@58
   449
        }
icculus@58
   450
    }
icculus@58
   451
icculus@58
   452
    /* sprintf failed or buffer overrun occured */
icculus@58
   453
    if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1)))
icculus@58
   454
    {
icculus@58
   455
        return false;
icculus@58
   456
    }
icculus@58
   457
icculus@58
   458
    /* reserve appropriate space in the output */
icculus@58
   459
    output_pointer = ensure(output_buffer, (size_t)length);
icculus@58
   460
    if (output_pointer == NULL)
icculus@58
   461
    {
icculus@58
   462
        return false;
icculus@58
   463
    }
icculus@58
   464
icculus@58
   465
    /* copy the printed number to the output and replace locale
icculus@58
   466
     * dependent decimal point with '.' */
icculus@58
   467
    for (i = 0; i < ((size_t)length); i++)
icculus@58
   468
    {
icculus@58
   469
        if (number_buffer[i] == decimal_point)
icculus@58
   470
        {
icculus@58
   471
            output_pointer[i] = '.';
icculus@58
   472
            continue;
icculus@58
   473
        }
icculus@58
   474
icculus@58
   475
        output_pointer[i] = number_buffer[i];
icculus@58
   476
    }
icculus@58
   477
    output_pointer[i] = '\0';
icculus@58
   478
icculus@58
   479
    output_buffer->offset += (size_t)length;
icculus@58
   480
icculus@58
   481
    return true;
icculus@58
   482
}
icculus@58
   483
icculus@58
   484
/* parse 4 digit hexadecimal number */
icculus@58
   485
static unsigned parse_hex4(const unsigned char * const input)
icculus@58
   486
{
icculus@58
   487
    unsigned int h = 0;
icculus@58
   488
    size_t i = 0;
icculus@58
   489
icculus@58
   490
    for (i = 0; i < 4; i++)
icculus@58
   491
    {
icculus@58
   492
        /* parse digit */
icculus@58
   493
        if ((input[i] >= '0') && (input[i] <= '9'))
icculus@58
   494
        {
icculus@58
   495
            h += (unsigned int) input[i] - '0';
icculus@58
   496
        }
icculus@58
   497
        else if ((input[i] >= 'A') && (input[i] <= 'F'))
icculus@58
   498
        {
icculus@58
   499
            h += (unsigned int) 10 + input[i] - 'A';
icculus@58
   500
        }
icculus@58
   501
        else if ((input[i] >= 'a') && (input[i] <= 'f'))
icculus@58
   502
        {
icculus@58
   503
            h += (unsigned int) 10 + input[i] - 'a';
icculus@58
   504
        }
icculus@58
   505
        else /* invalid */
icculus@58
   506
        {
icculus@58
   507
            return 0;
icculus@58
   508
        }
icculus@58
   509
icculus@58
   510
        if (i < 3)
icculus@58
   511
        {
icculus@58
   512
            /* shift left to make place for the next nibble */
icculus@58
   513
            h = h << 4;
icculus@58
   514
        }
icculus@58
   515
    }
icculus@58
   516
icculus@58
   517
    return h;
icculus@58
   518
}
icculus@58
   519
icculus@58
   520
/* converts a UTF-16 literal to UTF-8
icculus@58
   521
 * A literal can be one or two sequences of the form \uXXXX */
icculus@58
   522
static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer)
icculus@58
   523
{
icculus@58
   524
    long unsigned int codepoint = 0;
icculus@58
   525
    unsigned int first_code = 0;
icculus@58
   526
    const unsigned char *first_sequence = input_pointer;
icculus@58
   527
    unsigned char utf8_length = 0;
icculus@58
   528
    unsigned char utf8_position = 0;
icculus@58
   529
    unsigned char sequence_length = 0;
icculus@58
   530
    unsigned char first_byte_mark = 0;
icculus@58
   531
icculus@58
   532
    if ((input_end - first_sequence) < 6)
icculus@58
   533
    {
icculus@58
   534
        /* input ends unexpectedly */
icculus@58
   535
        goto fail;
icculus@58
   536
    }
icculus@58
   537
icculus@58
   538
    /* get the first utf16 sequence */
icculus@58
   539
    first_code = parse_hex4(first_sequence + 2);
icculus@58
   540
icculus@58
   541
    /* check that the code is valid */
icculus@58
   542
    if (((first_code >= 0xDC00) && (first_code <= 0xDFFF)))
icculus@58
   543
    {
icculus@58
   544
        goto fail;
icculus@58
   545
    }
icculus@58
   546
icculus@58
   547
    /* UTF16 surrogate pair */
icculus@58
   548
    if ((first_code >= 0xD800) && (first_code <= 0xDBFF))
icculus@58
   549
    {
icculus@58
   550
        const unsigned char *second_sequence = first_sequence + 6;
icculus@58
   551
        unsigned int second_code = 0;
icculus@58
   552
        sequence_length = 12; /* \uXXXX\uXXXX */
icculus@58
   553
icculus@58
   554
        if ((input_end - second_sequence) < 6)
icculus@58
   555
        {
icculus@58
   556
            /* input ends unexpectedly */
icculus@58
   557
            goto fail;
icculus@58
   558
        }
icculus@58
   559
icculus@58
   560
        if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u'))
icculus@58
   561
        {
icculus@58
   562
            /* missing second half of the surrogate pair */
icculus@58
   563
            goto fail;
icculus@58
   564
        }
icculus@58
   565
icculus@58
   566
        /* get the second utf16 sequence */
icculus@58
   567
        second_code = parse_hex4(second_sequence + 2);
icculus@58
   568
        /* check that the code is valid */
icculus@58
   569
        if ((second_code < 0xDC00) || (second_code > 0xDFFF))
icculus@58
   570
        {
icculus@58
   571
            /* invalid second half of the surrogate pair */
icculus@58
   572
            goto fail;
icculus@58
   573
        }
icculus@58
   574
icculus@58
   575
icculus@58
   576
        /* calculate the unicode codepoint from the surrogate pair */
icculus@58
   577
        codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
icculus@58
   578
    }
icculus@58
   579
    else
icculus@58
   580
    {
icculus@58
   581
        sequence_length = 6; /* \uXXXX */
icculus@58
   582
        codepoint = first_code;
icculus@58
   583
    }
icculus@58
   584
icculus@58
   585
    /* encode as UTF-8
icculus@58
   586
     * takes at maximum 4 bytes to encode:
icculus@58
   587
     * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
icculus@58
   588
    if (codepoint < 0x80)
icculus@58
   589
    {
icculus@58
   590
        /* normal ascii, encoding 0xxxxxxx */
icculus@58
   591
        utf8_length = 1;
icculus@58
   592
    }
icculus@58
   593
    else if (codepoint < 0x800)
icculus@58
   594
    {
icculus@58
   595
        /* two bytes, encoding 110xxxxx 10xxxxxx */
icculus@58
   596
        utf8_length = 2;
icculus@58
   597
        first_byte_mark = 0xC0; /* 11000000 */
icculus@58
   598
    }
icculus@58
   599
    else if (codepoint < 0x10000)
icculus@58
   600
    {
icculus@58
   601
        /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
icculus@58
   602
        utf8_length = 3;
icculus@58
   603
        first_byte_mark = 0xE0; /* 11100000 */
icculus@58
   604
    }
icculus@58
   605
    else if (codepoint <= 0x10FFFF)
icculus@58
   606
    {
icculus@58
   607
        /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
icculus@58
   608
        utf8_length = 4;
icculus@58
   609
        first_byte_mark = 0xF0; /* 11110000 */
icculus@58
   610
    }
icculus@58
   611
    else
icculus@58
   612
    {
icculus@58
   613
        /* invalid unicode codepoint */
icculus@58
   614
        goto fail;
icculus@58
   615
    }
icculus@58
   616
icculus@58
   617
    /* encode as utf8 */
icculus@58
   618
    for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--)
icculus@58
   619
    {
icculus@58
   620
        /* 10xxxxxx */
icculus@58
   621
        (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
icculus@58
   622
        codepoint >>= 6;
icculus@58
   623
    }
icculus@58
   624
    /* encode first byte */
icculus@58
   625
    if (utf8_length > 1)
icculus@58
   626
    {
icculus@58
   627
        (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
icculus@58
   628
    }
icculus@58
   629
    else
icculus@58
   630
    {
icculus@58
   631
        (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
icculus@58
   632
    }
icculus@58
   633
icculus@58
   634
    *output_pointer += utf8_length;
icculus@58
   635
icculus@58
   636
    return sequence_length;
icculus@58
   637
icculus@58
   638
fail:
icculus@58
   639
    return 0;
icculus@58
   640
}
icculus@58
   641
icculus@58
   642
/* Parse the input text into an unescaped cinput, and populate item. */
icculus@58
   643
static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer)
icculus@58
   644
{
icculus@58
   645
    const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
icculus@58
   646
    const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
icculus@58
   647
    unsigned char *output_pointer = NULL;
icculus@58
   648
    unsigned char *output = NULL;
icculus@58
   649
icculus@58
   650
    /* not a string */
icculus@58
   651
    if (buffer_at_offset(input_buffer)[0] != '\"')
icculus@58
   652
    {
icculus@58
   653
        goto fail;
icculus@58
   654
    }
icculus@58
   655
icculus@58
   656
    {
icculus@58
   657
        /* calculate approximate size of the output (overestimate) */
icculus@58
   658
        size_t allocation_length = 0;
icculus@58
   659
        size_t skipped_bytes = 0;
icculus@58
   660
        while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"'))
icculus@58
   661
        {
icculus@58
   662
            /* is escape sequence */
icculus@58
   663
            if (input_end[0] == '\\')
icculus@58
   664
            {
icculus@58
   665
                if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length)
icculus@58
   666
                {
icculus@58
   667
                    /* prevent buffer overflow when last input character is a backslash */
icculus@58
   668
                    goto fail;
icculus@58
   669
                }
icculus@58
   670
                skipped_bytes++;
icculus@58
   671
                input_end++;
icculus@58
   672
            }
icculus@58
   673
            input_end++;
icculus@58
   674
        }
icculus@58
   675
        if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"'))
icculus@58
   676
        {
icculus@58
   677
            goto fail; /* string ended unexpectedly */
icculus@58
   678
        }
icculus@58
   679
icculus@58
   680
        /* This is at most how much we need for the output */
icculus@58
   681
        allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
icculus@58
   682
        output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof(""));
icculus@58
   683
        if (output == NULL)
icculus@58
   684
        {
icculus@58
   685
            goto fail; /* allocation failure */
icculus@58
   686
        }
icculus@58
   687
    }
icculus@58
   688
icculus@58
   689
    output_pointer = output;
icculus@58
   690
    /* loop through the string literal */
icculus@58
   691
    while (input_pointer < input_end)
icculus@58
   692
    {
icculus@58
   693
        if (*input_pointer != '\\')
icculus@58
   694
        {
icculus@58
   695
            *output_pointer++ = *input_pointer++;
icculus@58
   696
        }
icculus@58
   697
        /* escape sequence */
icculus@58
   698
        else
icculus@58
   699
        {
icculus@58
   700
            unsigned char sequence_length = 2;
icculus@58
   701
            if ((input_end - input_pointer) < 1)
icculus@58
   702
            {
icculus@58
   703
                goto fail;
icculus@58
   704
            }
icculus@58
   705
icculus@58
   706
            switch (input_pointer[1])
icculus@58
   707
            {
icculus@58
   708
                case 'b':
icculus@58
   709
                    *output_pointer++ = '\b';
icculus@58
   710
                    break;
icculus@58
   711
                case 'f':
icculus@58
   712
                    *output_pointer++ = '\f';
icculus@58
   713
                    break;
icculus@58
   714
                case 'n':
icculus@58
   715
                    *output_pointer++ = '\n';
icculus@58
   716
                    break;
icculus@58
   717
                case 'r':
icculus@58
   718
                    *output_pointer++ = '\r';
icculus@58
   719
                    break;
icculus@58
   720
                case 't':
icculus@58
   721
                    *output_pointer++ = '\t';
icculus@58
   722
                    break;
icculus@58
   723
                case '\"':
icculus@58
   724
                case '\\':
icculus@58
   725
                case '/':
icculus@58
   726
                    *output_pointer++ = input_pointer[1];
icculus@58
   727
                    break;
icculus@58
   728
icculus@58
   729
                /* UTF-16 literal */
icculus@58
   730
                case 'u':
icculus@58
   731
                    sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
icculus@58
   732
                    if (sequence_length == 0)
icculus@58
   733
                    {
icculus@58
   734
                        /* failed to convert UTF16-literal to UTF-8 */
icculus@58
   735
                        goto fail;
icculus@58
   736
                    }
icculus@58
   737
                    break;
icculus@58
   738
icculus@58
   739
                default:
icculus@58
   740
                    goto fail;
icculus@58
   741
            }
icculus@58
   742
            input_pointer += sequence_length;
icculus@58
   743
        }
icculus@58
   744
    }
icculus@58
   745
icculus@58
   746
    /* zero terminate the output */
icculus@58
   747
    *output_pointer = '\0';
icculus@58
   748
icculus@58
   749
    item->type = cJSON_String;
icculus@58
   750
    item->valuestring = (char*)output;
icculus@58
   751
icculus@58
   752
    input_buffer->offset = (size_t) (input_end - input_buffer->content);
icculus@58
   753
    input_buffer->offset++;
icculus@58
   754
icculus@58
   755
    return true;
icculus@58
   756
icculus@58
   757
fail:
icculus@58
   758
    if (output != NULL)
icculus@58
   759
    {
icculus@58
   760
        input_buffer->hooks.deallocate(output);
icculus@58
   761
    }
icculus@58
   762
icculus@58
   763
    if (input_pointer != NULL)
icculus@58
   764
    {
icculus@58
   765
        input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
icculus@58
   766
    }
icculus@58
   767
icculus@58
   768
    return false;
icculus@58
   769
}
icculus@58
   770
icculus@58
   771
/* Render the cstring provided to an escaped version that can be printed. */
icculus@58
   772
static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer)
icculus@58
   773
{
icculus@58
   774
    const unsigned char *input_pointer = NULL;
icculus@58
   775
    unsigned char *output = NULL;
icculus@58
   776
    unsigned char *output_pointer = NULL;
icculus@58
   777
    size_t output_length = 0;
icculus@58
   778
    /* numbers of additional characters needed for escaping */
icculus@58
   779
    size_t escape_characters = 0;
icculus@58
   780
icculus@58
   781
    if (output_buffer == NULL)
icculus@58
   782
    {
icculus@58
   783
        return false;
icculus@58
   784
    }
icculus@58
   785
icculus@58
   786
    /* empty string */
icculus@58
   787
    if (input == NULL)
icculus@58
   788
    {
icculus@58
   789
        output = ensure(output_buffer, sizeof("\"\""));
icculus@58
   790
        if (output == NULL)
icculus@58
   791
        {
icculus@58
   792
            return false;
icculus@58
   793
        }
icculus@58
   794
        strcpy((char*)output, "\"\"");
icculus@58
   795
icculus@58
   796
        return true;
icculus@58
   797
    }
icculus@58
   798
icculus@58
   799
    /* set "flag" to 1 if something needs to be escaped */
icculus@58
   800
    for (input_pointer = input; *input_pointer; input_pointer++)
icculus@58
   801
    {
icculus@58
   802
        switch (*input_pointer)
icculus@58
   803
        {
icculus@58
   804
            case '\"':
icculus@58
   805
            case '\\':
icculus@58
   806
            case '\b':
icculus@58
   807
            case '\f':
icculus@58
   808
            case '\n':
icculus@58
   809
            case '\r':
icculus@58
   810
            case '\t':
icculus@58
   811
                /* one character escape sequence */
icculus@58
   812
                escape_characters++;
icculus@58
   813
                break;
icculus@58
   814
            default:
icculus@58
   815
                if (*input_pointer < 32)
icculus@58
   816
                {
icculus@58
   817
                    /* UTF-16 escape sequence uXXXX */
icculus@58
   818
                    escape_characters += 5;
icculus@58
   819
                }
icculus@58
   820
                break;
icculus@58
   821
        }
icculus@58
   822
    }
icculus@58
   823
    output_length = (size_t)(input_pointer - input) + escape_characters;
icculus@58
   824
icculus@58
   825
    output = ensure(output_buffer, output_length + sizeof("\"\""));
icculus@58
   826
    if (output == NULL)
icculus@58
   827
    {
icculus@58
   828
        return false;
icculus@58
   829
    }
icculus@58
   830
icculus@58
   831
    /* no characters have to be escaped */
icculus@58
   832
    if (escape_characters == 0)
icculus@58
   833
    {
icculus@58
   834
        output[0] = '\"';
icculus@58
   835
        memcpy(output + 1, input, output_length);
icculus@58
   836
        output[output_length + 1] = '\"';
icculus@58
   837
        output[output_length + 2] = '\0';
icculus@58
   838
icculus@58
   839
        return true;
icculus@58
   840
    }
icculus@58
   841
icculus@58
   842
    output[0] = '\"';
icculus@58
   843
    output_pointer = output + 1;
icculus@58
   844
    /* copy the string */
icculus@58
   845
    for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++)
icculus@58
   846
    {
icculus@58
   847
        if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\'))
icculus@58
   848
        {
icculus@58
   849
            /* normal character, copy */
icculus@58
   850
            *output_pointer = *input_pointer;
icculus@58
   851
        }
icculus@58
   852
        else
icculus@58
   853
        {
icculus@58
   854
            /* character needs to be escaped */
icculus@58
   855
            *output_pointer++ = '\\';
icculus@58
   856
            switch (*input_pointer)
icculus@58
   857
            {
icculus@58
   858
                case '\\':
icculus@58
   859
                    *output_pointer = '\\';
icculus@58
   860
                    break;
icculus@58
   861
                case '\"':
icculus@58
   862
                    *output_pointer = '\"';
icculus@58
   863
                    break;
icculus@58
   864
                case '\b':
icculus@58
   865
                    *output_pointer = 'b';
icculus@58
   866
                    break;
icculus@58
   867
                case '\f':
icculus@58
   868
                    *output_pointer = 'f';
icculus@58
   869
                    break;
icculus@58
   870
                case '\n':
icculus@58
   871
                    *output_pointer = 'n';
icculus@58
   872
                    break;
icculus@58
   873
                case '\r':
icculus@58
   874
                    *output_pointer = 'r';
icculus@58
   875
                    break;
icculus@58
   876
                case '\t':
icculus@58
   877
                    *output_pointer = 't';
icculus@58
   878
                    break;
icculus@58
   879
                default:
icculus@58
   880
                    /* escape and print as unicode codepoint */
icculus@58
   881
                    sprintf((char*)output_pointer, "u%04x", *input_pointer);
icculus@58
   882
                    output_pointer += 4;
icculus@58
   883
                    break;
icculus@58
   884
            }
icculus@58
   885
        }
icculus@58
   886
    }
icculus@58
   887
    output[output_length + 1] = '\"';
icculus@58
   888
    output[output_length + 2] = '\0';
icculus@58
   889
icculus@58
   890
    return true;
icculus@58
   891
}
icculus@58
   892
icculus@58
   893
/* Invoke print_string_ptr (which is useful) on an item. */
icculus@58
   894
static cJSON_bool print_string(const cJSON * const item, printbuffer * const p)
icculus@58
   895
{
icculus@58
   896
    return print_string_ptr((unsigned char*)item->valuestring, p);
icculus@58
   897
}
icculus@58
   898
icculus@58
   899
/* Predeclare these prototypes. */
icculus@58
   900
static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer);
icculus@58
   901
static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer);
icculus@58
   902
static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer);
icculus@58
   903
static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer);
icculus@58
   904
static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer);
icculus@58
   905
static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer);
icculus@58
   906
icculus@58
   907
/* Utility to jump whitespace and cr/lf */
icculus@58
   908
static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)
icculus@58
   909
{
icculus@58
   910
    if ((buffer == NULL) || (buffer->content == NULL))
icculus@58
   911
    {
icculus@58
   912
        return NULL;
icculus@58
   913
    }
icculus@58
   914
icculus@58
   915
    while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32))
icculus@58
   916
    {
icculus@58
   917
       buffer->offset++;
icculus@58
   918
    }
icculus@58
   919
icculus@58
   920
    if (buffer->offset == buffer->length)
icculus@58
   921
    {
icculus@58
   922
        buffer->offset--;
icculus@58
   923
    }
icculus@58
   924
icculus@58
   925
    return buffer;
icculus@58
   926
}
icculus@58
   927
icculus@58
   928
/* Parse an object - create a new root, and populate. */
icculus@58
   929
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)
icculus@58
   930
{
icculus@58
   931
    parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
icculus@58
   932
    cJSON *item = NULL;
icculus@58
   933
icculus@58
   934
    /* reset error position */
icculus@58
   935
    global_error.json = NULL;
icculus@58
   936
    global_error.position = 0;
icculus@58
   937
icculus@58
   938
    if (value == NULL)
icculus@58
   939
    {
icculus@58
   940
        goto fail;
icculus@58
   941
    }
icculus@58
   942
icculus@58
   943
    buffer.content = (const unsigned char*)value;
icculus@58
   944
    buffer.length = strlen((const char*)value) + sizeof("");
icculus@58
   945
    buffer.offset = 0;
icculus@58
   946
    buffer.hooks = global_hooks;
icculus@58
   947
icculus@58
   948
    item = cJSON_New_Item(&global_hooks);
icculus@58
   949
    if (item == NULL) /* memory fail */
icculus@58
   950
    {
icculus@58
   951
        goto fail;
icculus@58
   952
    }
icculus@58
   953
icculus@58
   954
    if (!parse_value(item, buffer_skip_whitespace(&buffer)))
icculus@58
   955
    {
icculus@58
   956
        /* parse failure. ep is set. */
icculus@58
   957
        goto fail;
icculus@58
   958
    }
icculus@58
   959
icculus@58
   960
    /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
icculus@58
   961
    if (require_null_terminated)
icculus@58
   962
    {
icculus@58
   963
        buffer_skip_whitespace(&buffer);
icculus@58
   964
        if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0')
icculus@58
   965
        {
icculus@58
   966
            goto fail;
icculus@58
   967
        }
icculus@58
   968
    }
icculus@58
   969
    if (return_parse_end)
icculus@58
   970
    {
icculus@58
   971
        *return_parse_end = (const char*)buffer_at_offset(&buffer);
icculus@58
   972
    }
icculus@58
   973
icculus@58
   974
    return item;
icculus@58
   975
icculus@58
   976
fail:
icculus@58
   977
    if (item != NULL)
icculus@58
   978
    {
icculus@58
   979
        cJSON_Delete(item);
icculus@58
   980
    }
icculus@58
   981
icculus@58
   982
    if (value != NULL)
icculus@58
   983
    {
icculus@58
   984
        error local_error;
icculus@58
   985
        local_error.json = (const unsigned char*)value;
icculus@58
   986
        local_error.position = 0;
icculus@58
   987
icculus@58
   988
        if (buffer.offset < buffer.length)
icculus@58
   989
        {
icculus@58
   990
            local_error.position = buffer.offset;
icculus@58
   991
        }
icculus@58
   992
        else if (buffer.length > 0)
icculus@58
   993
        {
icculus@58
   994
            local_error.position = buffer.length - 1;
icculus@58
   995
        }
icculus@58
   996
icculus@58
   997
        if (return_parse_end != NULL)
icculus@58
   998
        {
icculus@58
   999
            *return_parse_end = (const char*)local_error.json + local_error.position;
icculus@58
  1000
        }
icculus@58
  1001
        else
icculus@58
  1002
        {
icculus@58
  1003
            global_error = local_error;
icculus@58
  1004
        }
icculus@58
  1005
    }
icculus@58
  1006
icculus@58
  1007
    return NULL;
icculus@58
  1008
}
icculus@58
  1009
icculus@58
  1010
/* Default options for cJSON_Parse */
icculus@58
  1011
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
icculus@58
  1012
{
icculus@58
  1013
    return cJSON_ParseWithOpts(value, 0, 0);
icculus@58
  1014
}
icculus@58
  1015
icculus@58
  1016
#define cjson_min(a, b) ((a < b) ? a : b)
icculus@58
  1017
icculus@58
  1018
static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks)
icculus@58
  1019
{
icculus@58
  1020
    printbuffer buffer[1];
icculus@58
  1021
    unsigned char *printed = NULL;
icculus@58
  1022
icculus@58
  1023
    memset(buffer, 0, sizeof(buffer));
icculus@58
  1024
icculus@58
  1025
    /* create buffer */
icculus@58
  1026
    buffer->buffer = (unsigned char*) hooks->allocate(256);
icculus@58
  1027
    buffer->format = format;
icculus@58
  1028
    buffer->hooks = *hooks;
icculus@58
  1029
    if (buffer->buffer == NULL)
icculus@58
  1030
    {
icculus@58
  1031
        goto fail;
icculus@58
  1032
    }
icculus@58
  1033
icculus@58
  1034
    /* print the value */
icculus@58
  1035
    if (!print_value(item, buffer))
icculus@58
  1036
    {
icculus@58
  1037
        goto fail;
icculus@58
  1038
    }
icculus@58
  1039
    update_offset(buffer);
icculus@58
  1040
icculus@58
  1041
    /* check if reallocate is available */
icculus@58
  1042
    if (hooks->reallocate != NULL)
icculus@58
  1043
    {
icculus@58
  1044
        printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->length);
icculus@58
  1045
        buffer->buffer = NULL;
icculus@58
  1046
        if (printed == NULL) {
icculus@58
  1047
            goto fail;
icculus@58
  1048
        }
icculus@58
  1049
    }
icculus@58
  1050
    else /* otherwise copy the JSON over to a new buffer */
icculus@58
  1051
    {
icculus@58
  1052
        printed = (unsigned char*) hooks->allocate(buffer->offset + 1);
icculus@58
  1053
        if (printed == NULL)
icculus@58
  1054
        {
icculus@58
  1055
            goto fail;
icculus@58
  1056
        }
icculus@58
  1057
        memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1));
icculus@58
  1058
        printed[buffer->offset] = '\0'; /* just to be sure */
icculus@58
  1059
icculus@58
  1060
        /* free the buffer */
icculus@58
  1061
        hooks->deallocate(buffer->buffer);
icculus@58
  1062
    }
icculus@58
  1063
icculus@58
  1064
    return printed;
icculus@58
  1065
icculus@58
  1066
fail:
icculus@58
  1067
    if (buffer->buffer != NULL)
icculus@58
  1068
    {
icculus@58
  1069
        hooks->deallocate(buffer->buffer);
icculus@58
  1070
    }
icculus@58
  1071
icculus@58
  1072
    if (printed != NULL)
icculus@58
  1073
    {
icculus@58
  1074
        hooks->deallocate(printed);
icculus@58
  1075
    }
icculus@58
  1076
icculus@58
  1077
    return NULL;
icculus@58
  1078
}
icculus@58
  1079
icculus@58
  1080
/* Render a cJSON item/entity/structure to text. */
icculus@58
  1081
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item)
icculus@58
  1082
{
icculus@58
  1083
    return (char*)print(item, true, &global_hooks);
icculus@58
  1084
}
icculus@58
  1085
icculus@58
  1086
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item)
icculus@58
  1087
{
icculus@58
  1088
    return (char*)print(item, false, &global_hooks);
icculus@58
  1089
}
icculus@58
  1090
icculus@58
  1091
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)
icculus@58
  1092
{
icculus@58
  1093
    printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
icculus@58
  1094
icculus@58
  1095
    if (prebuffer < 0)
icculus@58
  1096
    {
icculus@58
  1097
        return NULL;
icculus@58
  1098
    }
icculus@58
  1099
icculus@58
  1100
    p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer);
icculus@58
  1101
    if (!p.buffer)
icculus@58
  1102
    {
icculus@58
  1103
        return NULL;
icculus@58
  1104
    }
icculus@58
  1105
icculus@58
  1106
    p.length = (size_t)prebuffer;
icculus@58
  1107
    p.offset = 0;
icculus@58
  1108
    p.noalloc = false;
icculus@58
  1109
    p.format = fmt;
icculus@58
  1110
    p.hooks = global_hooks;
icculus@58
  1111
icculus@58
  1112
    if (!print_value(item, &p))
icculus@58
  1113
    {
icculus@58
  1114
        return NULL;
icculus@58
  1115
    }
icculus@58
  1116
icculus@58
  1117
    return (char*)p.buffer;
icculus@58
  1118
}
icculus@58
  1119
icculus@58
  1120
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt)
icculus@58
  1121
{
icculus@58
  1122
    printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
icculus@58
  1123
icculus@58
  1124
    if (len < 0)
icculus@58
  1125
    {
icculus@58
  1126
        return false;
icculus@58
  1127
    }
icculus@58
  1128
icculus@58
  1129
    p.buffer = (unsigned char*)buf;
icculus@58
  1130
    p.length = (size_t)len;
icculus@58
  1131
    p.offset = 0;
icculus@58
  1132
    p.noalloc = true;
icculus@58
  1133
    p.format = fmt;
icculus@58
  1134
    p.hooks = global_hooks;
icculus@58
  1135
icculus@58
  1136
    return print_value(item, &p);
icculus@58
  1137
}
icculus@58
  1138
icculus@58
  1139
/* Parser core - when encountering text, process appropriately. */
icculus@58
  1140
static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer)
icculus@58
  1141
{
icculus@58
  1142
    if ((input_buffer == NULL) || (input_buffer->content == NULL))
icculus@58
  1143
    {
icculus@58
  1144
        return false; /* no input */
icculus@58
  1145
    }
icculus@58
  1146
icculus@58
  1147
    /* parse the different types of values */
icculus@58
  1148
    /* null */
icculus@58
  1149
    if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0))
icculus@58
  1150
    {
icculus@58
  1151
        item->type = cJSON_NULL;
icculus@58
  1152
        input_buffer->offset += 4;
icculus@58
  1153
        return true;
icculus@58
  1154
    }
icculus@58
  1155
    /* false */
icculus@58
  1156
    if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0))
icculus@58
  1157
    {
icculus@58
  1158
        item->type = cJSON_False;
icculus@58
  1159
        input_buffer->offset += 5;
icculus@58
  1160
        return true;
icculus@58
  1161
    }
icculus@58
  1162
    /* true */
icculus@58
  1163
    if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0))
icculus@58
  1164
    {
icculus@58
  1165
        item->type = cJSON_True;
icculus@58
  1166
        item->valueint = 1;
icculus@58
  1167
        input_buffer->offset += 4;
icculus@58
  1168
        return true;
icculus@58
  1169
    }
icculus@58
  1170
    /* string */
icculus@58
  1171
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"'))
icculus@58
  1172
    {
icculus@58
  1173
        return parse_string(item, input_buffer);
icculus@58
  1174
    }
icculus@58
  1175
    /* number */
icculus@58
  1176
    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'))))
icculus@58
  1177
    {
icculus@58
  1178
        return parse_number(item, input_buffer);
icculus@58
  1179
    }
icculus@58
  1180
    /* array */
icculus@58
  1181
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '['))
icculus@58
  1182
    {
icculus@58
  1183
        return parse_array(item, input_buffer);
icculus@58
  1184
    }
icculus@58
  1185
    /* object */
icculus@58
  1186
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{'))
icculus@58
  1187
    {
icculus@58
  1188
        return parse_object(item, input_buffer);
icculus@58
  1189
    }
icculus@58
  1190
icculus@58
  1191
icculus@58
  1192
    return false;
icculus@58
  1193
}
icculus@58
  1194
icculus@58
  1195
/* Render a value to text. */
icculus@58
  1196
static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer)
icculus@58
  1197
{
icculus@58
  1198
    unsigned char *output = NULL;
icculus@58
  1199
icculus@58
  1200
    if ((item == NULL) || (output_buffer == NULL))
icculus@58
  1201
    {
icculus@58
  1202
        return false;
icculus@58
  1203
    }
icculus@58
  1204
icculus@58
  1205
    switch ((item->type) & 0xFF)
icculus@58
  1206
    {
icculus@58
  1207
        case cJSON_NULL:
icculus@58
  1208
            output = ensure(output_buffer, 5);
icculus@58
  1209
            if (output == NULL)
icculus@58
  1210
            {
icculus@58
  1211
                return false;
icculus@58
  1212
            }
icculus@58
  1213
            strcpy((char*)output, "null");
icculus@58
  1214
            return true;
icculus@58
  1215
icculus@58
  1216
        case cJSON_False:
icculus@58
  1217
            output = ensure(output_buffer, 6);
icculus@58
  1218
            if (output == NULL)
icculus@58
  1219
            {
icculus@58
  1220
                return false;
icculus@58
  1221
            }
icculus@58
  1222
            strcpy((char*)output, "false");
icculus@58
  1223
            return true;
icculus@58
  1224
icculus@58
  1225
        case cJSON_True:
icculus@58
  1226
            output = ensure(output_buffer, 5);
icculus@58
  1227
            if (output == NULL)
icculus@58
  1228
            {
icculus@58
  1229
                return false;
icculus@58
  1230
            }
icculus@58
  1231
            strcpy((char*)output, "true");
icculus@58
  1232
            return true;
icculus@58
  1233
icculus@58
  1234
        case cJSON_Number:
icculus@58
  1235
            return print_number(item, output_buffer);
icculus@58
  1236
icculus@58
  1237
        case cJSON_Raw:
icculus@58
  1238
        {
icculus@58
  1239
            size_t raw_length = 0;
icculus@58
  1240
            if (item->valuestring == NULL)
icculus@58
  1241
            {
icculus@58
  1242
                if (!output_buffer->noalloc)
icculus@58
  1243
                {
icculus@58
  1244
                    output_buffer->hooks.deallocate(output_buffer->buffer);
icculus@58
  1245
                }
icculus@58
  1246
                return false;
icculus@58
  1247
            }
icculus@58
  1248
icculus@58
  1249
            raw_length = strlen(item->valuestring) + sizeof("");
icculus@58
  1250
            output = ensure(output_buffer, raw_length);
icculus@58
  1251
            if (output == NULL)
icculus@58
  1252
            {
icculus@58
  1253
                return false;
icculus@58
  1254
            }
icculus@58
  1255
            memcpy(output, item->valuestring, raw_length);
icculus@58
  1256
            return true;
icculus@58
  1257
        }
icculus@58
  1258
icculus@58
  1259
        case cJSON_String:
icculus@58
  1260
            return print_string(item, output_buffer);
icculus@58
  1261
icculus@58
  1262
        case cJSON_Array:
icculus@58
  1263
            return print_array(item, output_buffer);
icculus@58
  1264
icculus@58
  1265
        case cJSON_Object:
icculus@58
  1266
            return print_object(item, output_buffer);
icculus@58
  1267
icculus@58
  1268
        default:
icculus@58
  1269
            return false;
icculus@58
  1270
    }
icculus@58
  1271
}
icculus@58
  1272
icculus@58
  1273
/* Build an array from input text. */
icculus@58
  1274
static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer)
icculus@58
  1275
{
icculus@58
  1276
    cJSON *head = NULL; /* head of the linked list */
icculus@58
  1277
    cJSON *current_item = NULL;
icculus@58
  1278
icculus@58
  1279
    if (input_buffer->depth >= CJSON_NESTING_LIMIT)
icculus@58
  1280
    {
icculus@58
  1281
        return false; /* to deeply nested */
icculus@58
  1282
    }
icculus@58
  1283
    input_buffer->depth++;
icculus@58
  1284
icculus@58
  1285
    if (buffer_at_offset(input_buffer)[0] != '[')
icculus@58
  1286
    {
icculus@58
  1287
        /* not an array */
icculus@58
  1288
        goto fail;
icculus@58
  1289
    }
icculus@58
  1290
icculus@58
  1291
    input_buffer->offset++;
icculus@58
  1292
    buffer_skip_whitespace(input_buffer);
icculus@58
  1293
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']'))
icculus@58
  1294
    {
icculus@58
  1295
        /* empty array */
icculus@58
  1296
        goto success;
icculus@58
  1297
    }
icculus@58
  1298
icculus@58
  1299
    /* check if we skipped to the end of the buffer */
icculus@58
  1300
    if (cannot_access_at_index(input_buffer, 0))
icculus@58
  1301
    {
icculus@58
  1302
        input_buffer->offset--;
icculus@58
  1303
        goto fail;
icculus@58
  1304
    }
icculus@58
  1305
icculus@58
  1306
    /* step back to character in front of the first element */
icculus@58
  1307
    input_buffer->offset--;
icculus@58
  1308
    /* loop through the comma separated array elements */
icculus@58
  1309
    do
icculus@58
  1310
    {
icculus@58
  1311
        /* allocate next item */
icculus@58
  1312
        cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
icculus@58
  1313
        if (new_item == NULL)
icculus@58
  1314
        {
icculus@58
  1315
            goto fail; /* allocation failure */
icculus@58
  1316
        }
icculus@58
  1317
icculus@58
  1318
        /* attach next item to list */
icculus@58
  1319
        if (head == NULL)
icculus@58
  1320
        {
icculus@58
  1321
            /* start the linked list */
icculus@58
  1322
            current_item = head = new_item;
icculus@58
  1323
        }
icculus@58
  1324
        else
icculus@58
  1325
        {
icculus@58
  1326
            /* add to the end and advance */
icculus@58
  1327
            current_item->next = new_item;
icculus@58
  1328
            new_item->prev = current_item;
icculus@58
  1329
            current_item = new_item;
icculus@58
  1330
        }
icculus@58
  1331
icculus@58
  1332
        /* parse next value */
icculus@58
  1333
        input_buffer->offset++;
icculus@58
  1334
        buffer_skip_whitespace(input_buffer);
icculus@58
  1335
        if (!parse_value(current_item, input_buffer))
icculus@58
  1336
        {
icculus@58
  1337
            goto fail; /* failed to parse value */
icculus@58
  1338
        }
icculus@58
  1339
        buffer_skip_whitespace(input_buffer);
icculus@58
  1340
    }
icculus@58
  1341
    while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
icculus@58
  1342
icculus@58
  1343
    if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']')
icculus@58
  1344
    {
icculus@58
  1345
        goto fail; /* expected end of array */
icculus@58
  1346
    }
icculus@58
  1347
icculus@58
  1348
success:
icculus@58
  1349
    input_buffer->depth--;
icculus@58
  1350
icculus@58
  1351
    item->type = cJSON_Array;
icculus@58
  1352
    item->child = head;
icculus@58
  1353
icculus@58
  1354
    input_buffer->offset++;
icculus@58
  1355
icculus@58
  1356
    return true;
icculus@58
  1357
icculus@58
  1358
fail:
icculus@58
  1359
    if (head != NULL)
icculus@58
  1360
    {
icculus@58
  1361
        cJSON_Delete(head);
icculus@58
  1362
    }
icculus@58
  1363
icculus@58
  1364
    return false;
icculus@58
  1365
}
icculus@58
  1366
icculus@58
  1367
/* Render an array to text */
icculus@58
  1368
static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer)
icculus@58
  1369
{
icculus@58
  1370
    unsigned char *output_pointer = NULL;
icculus@58
  1371
    size_t length = 0;
icculus@58
  1372
    cJSON *current_element = item->child;
icculus@58
  1373
icculus@58
  1374
    if (output_buffer == NULL)
icculus@58
  1375
    {
icculus@58
  1376
        return false;
icculus@58
  1377
    }
icculus@58
  1378
icculus@58
  1379
    /* Compose the output array. */
icculus@58
  1380
    /* opening square bracket */
icculus@58
  1381
    output_pointer = ensure(output_buffer, 1);
icculus@58
  1382
    if (output_pointer == NULL)
icculus@58
  1383
    {
icculus@58
  1384
        return false;
icculus@58
  1385
    }
icculus@58
  1386
icculus@58
  1387
    *output_pointer = '[';
icculus@58
  1388
    output_buffer->offset++;
icculus@58
  1389
    output_buffer->depth++;
icculus@58
  1390
icculus@58
  1391
    while (current_element != NULL)
icculus@58
  1392
    {
icculus@58
  1393
        if (!print_value(current_element, output_buffer))
icculus@58
  1394
        {
icculus@58
  1395
            return false;
icculus@58
  1396
        }
icculus@58
  1397
        update_offset(output_buffer);
icculus@58
  1398
        if (current_element->next)
icculus@58
  1399
        {
icculus@58
  1400
            length = (size_t) (output_buffer->format ? 2 : 1);
icculus@58
  1401
            output_pointer = ensure(output_buffer, length + 1);
icculus@58
  1402
            if (output_pointer == NULL)
icculus@58
  1403
            {
icculus@58
  1404
                return false;
icculus@58
  1405
            }
icculus@58
  1406
            *output_pointer++ = ',';
icculus@58
  1407
            if(output_buffer->format)
icculus@58
  1408
            {
icculus@58
  1409
                *output_pointer++ = ' ';
icculus@58
  1410
            }
icculus@58
  1411
            *output_pointer = '\0';
icculus@58
  1412
            output_buffer->offset += length;
icculus@58
  1413
        }
icculus@58
  1414
        current_element = current_element->next;
icculus@58
  1415
    }
icculus@58
  1416
icculus@58
  1417
    output_pointer = ensure(output_buffer, 2);
icculus@58
  1418
    if (output_pointer == NULL)
icculus@58
  1419
    {
icculus@58
  1420
        return false;
icculus@58
  1421
    }
icculus@58
  1422
    *output_pointer++ = ']';
icculus@58
  1423
    *output_pointer = '\0';
icculus@58
  1424
    output_buffer->depth--;
icculus@58
  1425
icculus@58
  1426
    return true;
icculus@58
  1427
}
icculus@58
  1428
icculus@58
  1429
/* Build an object from the text. */
icculus@58
  1430
static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer)
icculus@58
  1431
{
icculus@58
  1432
    cJSON *head = NULL; /* linked list head */
icculus@58
  1433
    cJSON *current_item = NULL;
icculus@58
  1434
icculus@58
  1435
    if (input_buffer->depth >= CJSON_NESTING_LIMIT)
icculus@58
  1436
    {
icculus@58
  1437
        return false; /* to deeply nested */
icculus@58
  1438
    }
icculus@58
  1439
    input_buffer->depth++;
icculus@58
  1440
icculus@58
  1441
    if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{'))
icculus@58
  1442
    {
icculus@58
  1443
        goto fail; /* not an object */
icculus@58
  1444
    }
icculus@58
  1445
icculus@58
  1446
    input_buffer->offset++;
icculus@58
  1447
    buffer_skip_whitespace(input_buffer);
icculus@58
  1448
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}'))
icculus@58
  1449
    {
icculus@58
  1450
        goto success; /* empty object */
icculus@58
  1451
    }
icculus@58
  1452
icculus@58
  1453
    /* check if we skipped to the end of the buffer */
icculus@58
  1454
    if (cannot_access_at_index(input_buffer, 0))
icculus@58
  1455
    {
icculus@58
  1456
        input_buffer->offset--;
icculus@58
  1457
        goto fail;
icculus@58
  1458
    }
icculus@58
  1459
icculus@58
  1460
    /* step back to character in front of the first element */
icculus@58
  1461
    input_buffer->offset--;
icculus@58
  1462
    /* loop through the comma separated array elements */
icculus@58
  1463
    do
icculus@58
  1464
    {
icculus@58
  1465
        /* allocate next item */
icculus@58
  1466
        cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
icculus@58
  1467
        if (new_item == NULL)
icculus@58
  1468
        {
icculus@58
  1469
            goto fail; /* allocation failure */
icculus@58
  1470
        }
icculus@58
  1471
icculus@58
  1472
        /* attach next item to list */
icculus@58
  1473
        if (head == NULL)
icculus@58
  1474
        {
icculus@58
  1475
            /* start the linked list */
icculus@58
  1476
            current_item = head = new_item;
icculus@58
  1477
        }
icculus@58
  1478
        else
icculus@58
  1479
        {
icculus@58
  1480
            /* add to the end and advance */
icculus@58
  1481
            current_item->next = new_item;
icculus@58
  1482
            new_item->prev = current_item;
icculus@58
  1483
            current_item = new_item;
icculus@58
  1484
        }
icculus@58
  1485
icculus@58
  1486
        /* parse the name of the child */
icculus@58
  1487
        input_buffer->offset++;
icculus@58
  1488
        buffer_skip_whitespace(input_buffer);
icculus@58
  1489
        if (!parse_string(current_item, input_buffer))
icculus@58
  1490
        {
icculus@58
  1491
            goto fail; /* faile to parse name */
icculus@58
  1492
        }
icculus@58
  1493
        buffer_skip_whitespace(input_buffer);
icculus@58
  1494
icculus@58
  1495
        /* swap valuestring and string, because we parsed the name */
icculus@58
  1496
        current_item->string = current_item->valuestring;
icculus@58
  1497
        current_item->valuestring = NULL;
icculus@58
  1498
icculus@58
  1499
        if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':'))
icculus@58
  1500
        {
icculus@58
  1501
            goto fail; /* invalid object */
icculus@58
  1502
        }
icculus@58
  1503
icculus@58
  1504
        /* parse the value */
icculus@58
  1505
        input_buffer->offset++;
icculus@58
  1506
        buffer_skip_whitespace(input_buffer);
icculus@58
  1507
        if (!parse_value(current_item, input_buffer))
icculus@58
  1508
        {
icculus@58
  1509
            goto fail; /* failed to parse value */
icculus@58
  1510
        }
icculus@58
  1511
        buffer_skip_whitespace(input_buffer);
icculus@58
  1512
    }
icculus@58
  1513
    while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
icculus@58
  1514
icculus@58
  1515
    if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}'))
icculus@58
  1516
    {
icculus@58
  1517
        goto fail; /* expected end of object */
icculus@58
  1518
    }
icculus@58
  1519
icculus@58
  1520
success:
icculus@58
  1521
    input_buffer->depth--;
icculus@58
  1522
icculus@58
  1523
    item->type = cJSON_Object;
icculus@58
  1524
    item->child = head;
icculus@58
  1525
icculus@58
  1526
    input_buffer->offset++;
icculus@58
  1527
    return true;
icculus@58
  1528
icculus@58
  1529
fail:
icculus@58
  1530
    if (head != NULL)
icculus@58
  1531
    {
icculus@58
  1532
        cJSON_Delete(head);
icculus@58
  1533
    }
icculus@58
  1534
icculus@58
  1535
    return false;
icculus@58
  1536
}
icculus@58
  1537
icculus@58
  1538
/* Render an object to text. */
icculus@58
  1539
static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer)
icculus@58
  1540
{
icculus@58
  1541
    unsigned char *output_pointer = NULL;
icculus@58
  1542
    size_t length = 0;
icculus@58
  1543
    cJSON *current_item = item->child;
icculus@58
  1544
icculus@58
  1545
    if (output_buffer == NULL)
icculus@58
  1546
    {
icculus@58
  1547
        return false;
icculus@58
  1548
    }
icculus@58
  1549
icculus@58
  1550
    /* Compose the output: */
icculus@58
  1551
    length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */
icculus@58
  1552
    output_pointer = ensure(output_buffer, length + 1);
icculus@58
  1553
    if (output_pointer == NULL)
icculus@58
  1554
    {
icculus@58
  1555
        return false;
icculus@58
  1556
    }
icculus@58
  1557
icculus@58
  1558
    *output_pointer++ = '{';
icculus@58
  1559
    output_buffer->depth++;
icculus@58
  1560
    if (output_buffer->format)
icculus@58
  1561
    {
icculus@58
  1562
        *output_pointer++ = '\n';
icculus@58
  1563
    }
icculus@58
  1564
    output_buffer->offset += length;
icculus@58
  1565
icculus@58
  1566
    while (current_item)
icculus@58
  1567
    {
icculus@58
  1568
        if (output_buffer->format)
icculus@58
  1569
        {
icculus@58
  1570
            size_t i;
icculus@58
  1571
            output_pointer = ensure(output_buffer, output_buffer->depth);
icculus@58
  1572
            if (output_pointer == NULL)
icculus@58
  1573
            {
icculus@58
  1574
                return false;
icculus@58
  1575
            }
icculus@58
  1576
            for (i = 0; i < output_buffer->depth; i++)
icculus@58
  1577
            {
icculus@58
  1578
                *output_pointer++ = '\t';
icculus@58
  1579
            }
icculus@58
  1580
            output_buffer->offset += output_buffer->depth;
icculus@58
  1581
        }
icculus@58
  1582
icculus@58
  1583
        /* print key */
icculus@58
  1584
        if (!print_string_ptr((unsigned char*)current_item->string, output_buffer))
icculus@58
  1585
        {
icculus@58
  1586
            return false;
icculus@58
  1587
        }
icculus@58
  1588
        update_offset(output_buffer);
icculus@58
  1589
icculus@58
  1590
        length = (size_t) (output_buffer->format ? 2 : 1);
icculus@58
  1591
        output_pointer = ensure(output_buffer, length);
icculus@58
  1592
        if (output_pointer == NULL)
icculus@58
  1593
        {
icculus@58
  1594
            return false;
icculus@58
  1595
        }
icculus@58
  1596
        *output_pointer++ = ':';
icculus@58
  1597
        if (output_buffer->format)
icculus@58
  1598
        {
icculus@58
  1599
            *output_pointer++ = '\t';
icculus@58
  1600
        }
icculus@58
  1601
        output_buffer->offset += length;
icculus@58
  1602
icculus@58
  1603
        /* print value */
icculus@58
  1604
        if (!print_value(current_item, output_buffer))
icculus@58
  1605
        {
icculus@58
  1606
            return false;
icculus@58
  1607
        }
icculus@58
  1608
        update_offset(output_buffer);
icculus@58
  1609
icculus@58
  1610
        /* print comma if not last */
icculus@58
  1611
        length = (size_t) ((output_buffer->format ? 1 : 0) + (current_item->next ? 1 : 0));
icculus@58
  1612
        output_pointer = ensure(output_buffer, length + 1);
icculus@58
  1613
        if (output_pointer == NULL)
icculus@58
  1614
        {
icculus@58
  1615
            return false;
icculus@58
  1616
        }
icculus@58
  1617
        if (current_item->next)
icculus@58
  1618
        {
icculus@58
  1619
            *output_pointer++ = ',';
icculus@58
  1620
        }
icculus@58
  1621
icculus@58
  1622
        if (output_buffer->format)
icculus@58
  1623
        {
icculus@58
  1624
            *output_pointer++ = '\n';
icculus@58
  1625
        }
icculus@58
  1626
        *output_pointer = '\0';
icculus@58
  1627
        output_buffer->offset += length;
icculus@58
  1628
icculus@58
  1629
        current_item = current_item->next;
icculus@58
  1630
    }
icculus@58
  1631
icculus@58
  1632
    output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2);
icculus@58
  1633
    if (output_pointer == NULL)
icculus@58
  1634
    {
icculus@58
  1635
        return false;
icculus@58
  1636
    }
icculus@58
  1637
    if (output_buffer->format)
icculus@58
  1638
    {
icculus@58
  1639
        size_t i;
icculus@58
  1640
        for (i = 0; i < (output_buffer->depth - 1); i++)
icculus@58
  1641
        {
icculus@58
  1642
            *output_pointer++ = '\t';
icculus@58
  1643
        }
icculus@58
  1644
    }
icculus@58
  1645
    *output_pointer++ = '}';
icculus@58
  1646
    *output_pointer = '\0';
icculus@58
  1647
    output_buffer->depth--;
icculus@58
  1648
icculus@58
  1649
    return true;
icculus@58
  1650
}
icculus@58
  1651
icculus@58
  1652
/* Get Array size/item / object item. */
icculus@58
  1653
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array)
icculus@58
  1654
{
icculus@58
  1655
    cJSON *c = array->child;
icculus@58
  1656
    size_t i = 0;
icculus@58
  1657
    while(c)
icculus@58
  1658
    {
icculus@58
  1659
        i++;
icculus@58
  1660
        c = c->next;
icculus@58
  1661
    }
icculus@58
  1662
icculus@58
  1663
    /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
icculus@58
  1664
icculus@58
  1665
    return (int)i;
icculus@58
  1666
}
icculus@58
  1667
icculus@58
  1668
static cJSON* get_array_item(const cJSON *array, size_t index)
icculus@58
  1669
{
icculus@58
  1670
    cJSON *current_child = NULL;
icculus@58
  1671
icculus@58
  1672
    if (array == NULL)
icculus@58
  1673
    {
icculus@58
  1674
        return NULL;
icculus@58
  1675
    }
icculus@58
  1676
icculus@58
  1677
    current_child = array->child;
icculus@58
  1678
    while ((current_child != NULL) && (index > 0))
icculus@58
  1679
    {
icculus@58
  1680
        index--;
icculus@58
  1681
        current_child = current_child->next;
icculus@58
  1682
    }
icculus@58
  1683
icculus@58
  1684
    return current_child;
icculus@58
  1685
}
icculus@58
  1686
icculus@58
  1687
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index)
icculus@58
  1688
{
icculus@58
  1689
    if (index < 0)
icculus@58
  1690
    {
icculus@58
  1691
        return NULL;
icculus@58
  1692
    }
icculus@58
  1693
icculus@58
  1694
    return get_array_item(array, (size_t)index);
icculus@58
  1695
}
icculus@58
  1696
icculus@58
  1697
static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive)
icculus@58
  1698
{
icculus@58
  1699
    cJSON *current_element = NULL;
icculus@58
  1700
icculus@58
  1701
    if ((object == NULL) || (name == NULL))
icculus@58
  1702
    {
icculus@58
  1703
        return NULL;
icculus@58
  1704
    }
icculus@58
  1705
icculus@58
  1706
    current_element = object->child;
icculus@58
  1707
    if (case_sensitive)
icculus@58
  1708
    {
icculus@58
  1709
        while ((current_element != NULL) && (strcmp(name, current_element->string) != 0))
icculus@58
  1710
        {
icculus@58
  1711
            current_element = current_element->next;
icculus@58
  1712
        }
icculus@58
  1713
    }
icculus@58
  1714
    else
icculus@58
  1715
    {
icculus@58
  1716
        while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0))
icculus@58
  1717
        {
icculus@58
  1718
            current_element = current_element->next;
icculus@58
  1719
        }
icculus@58
  1720
    }
icculus@58
  1721
icculus@58
  1722
    return current_element;
icculus@58
  1723
}
icculus@58
  1724
icculus@58
  1725
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string)
icculus@58
  1726
{
icculus@58
  1727
    return get_object_item(object, string, false);
icculus@58
  1728
}
icculus@58
  1729
icculus@58
  1730
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string)
icculus@58
  1731
{
icculus@58
  1732
    return get_object_item(object, string, true);
icculus@58
  1733
}
icculus@58
  1734
icculus@58
  1735
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string)
icculus@58
  1736
{
icculus@58
  1737
    return cJSON_GetObjectItem(object, string) ? 1 : 0;
icculus@58
  1738
}
icculus@58
  1739
icculus@58
  1740
/* Utility for array list handling. */
icculus@58
  1741
static void suffix_object(cJSON *prev, cJSON *item)
icculus@58
  1742
{
icculus@58
  1743
    prev->next = item;
icculus@58
  1744
    item->prev = prev;
icculus@58
  1745
}
icculus@58
  1746
icculus@58
  1747
/* Utility for handling references. */
icculus@58
  1748
static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks)
icculus@58
  1749
{
icculus@58
  1750
    cJSON *ref = cJSON_New_Item(hooks);
icculus@58
  1751
    if (!ref)
icculus@58
  1752
    {
icculus@58
  1753
        return NULL;
icculus@58
  1754
    }
icculus@58
  1755
    memcpy(ref, item, sizeof(cJSON));
icculus@58
  1756
    ref->string = NULL;
icculus@58
  1757
    ref->type |= cJSON_IsReference;
icculus@58
  1758
    ref->next = ref->prev = NULL;
icculus@58
  1759
    return ref;
icculus@58
  1760
}
icculus@58
  1761
icculus@58
  1762
/* Add item to array/object. */
icculus@58
  1763
CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item)
icculus@58
  1764
{
icculus@58
  1765
    cJSON *child = NULL;
icculus@58
  1766
icculus@58
  1767
    if ((item == NULL) || (array == NULL))
icculus@58
  1768
    {
icculus@58
  1769
        return;
icculus@58
  1770
    }
icculus@58
  1771
icculus@58
  1772
    child = array->child;
icculus@58
  1773
icculus@58
  1774
    if (child == NULL)
icculus@58
  1775
    {
icculus@58
  1776
        /* list is empty, start new one */
icculus@58
  1777
        array->child = item;
icculus@58
  1778
    }
icculus@58
  1779
    else
icculus@58
  1780
    {
icculus@58
  1781
        /* append to the end */
icculus@58
  1782
        while (child->next)
icculus@58
  1783
        {
icculus@58
  1784
            child = child->next;
icculus@58
  1785
        }
icculus@58
  1786
        suffix_object(child, item);
icculus@58
  1787
    }
icculus@58
  1788
}
icculus@58
  1789
icculus@58
  1790
CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
icculus@58
  1791
{
icculus@58
  1792
    /* call cJSON_AddItemToObjectCS for code reuse */
icculus@58
  1793
    cJSON_AddItemToObjectCS(object, (char*)cJSON_strdup((const unsigned char*)string, &global_hooks), item);
icculus@58
  1794
    /* remove cJSON_StringIsConst flag */
icculus@58
  1795
    item->type &= ~cJSON_StringIsConst;
icculus@58
  1796
}
icculus@58
  1797
icculus@58
  1798
#if defined (__clang__) || ((__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
icculus@58
  1799
    #pragma GCC diagnostic push
icculus@58
  1800
#endif
icculus@58
  1801
#ifdef __GNUC__
icculus@58
  1802
#pragma GCC diagnostic ignored "-Wcast-qual"
icculus@58
  1803
#endif
icculus@58
  1804
icculus@58
  1805
/* Add an item to an object with constant string as key */
icculus@58
  1806
CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
icculus@58
  1807
{
icculus@58
  1808
    if (!item)
icculus@58
  1809
    {
icculus@58
  1810
        return;
icculus@58
  1811
    }
icculus@58
  1812
    if (!(item->type & cJSON_StringIsConst) && item->string)
icculus@58
  1813
    {
icculus@58
  1814
        global_hooks.deallocate(item->string);
icculus@58
  1815
    }
icculus@58
  1816
    item->string = (char*)string;
icculus@58
  1817
    item->type |= cJSON_StringIsConst;
icculus@58
  1818
    cJSON_AddItemToArray(object, item);
icculus@58
  1819
}
icculus@58
  1820
#if defined (__clang__) || ((__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
icculus@58
  1821
    #pragma GCC diagnostic pop
icculus@58
  1822
#endif
icculus@58
  1823
icculus@58
  1824
CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
icculus@58
  1825
{
icculus@58
  1826
    cJSON_AddItemToArray(array, create_reference(item, &global_hooks));
icculus@58
  1827
}
icculus@58
  1828
icculus@58
  1829
CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)
icculus@58
  1830
{
icculus@58
  1831
    cJSON_AddItemToObject(object, string, create_reference(item, &global_hooks));
icculus@58
  1832
}
icculus@58
  1833
icculus@58
  1834
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item)
icculus@58
  1835
{
icculus@58
  1836
    if ((parent == NULL) || (item == NULL))
icculus@58
  1837
    {
icculus@58
  1838
        return NULL;
icculus@58
  1839
    }
icculus@58
  1840
icculus@58
  1841
    if (item->prev != NULL)
icculus@58
  1842
    {
icculus@58
  1843
        /* not the first element */
icculus@58
  1844
        item->prev->next = item->next;
icculus@58
  1845
    }
icculus@58
  1846
    if (item->next != NULL)
icculus@58
  1847
    {
icculus@58
  1848
        /* not the last element */
icculus@58
  1849
        item->next->prev = item->prev;
icculus@58
  1850
    }
icculus@58
  1851
icculus@58
  1852
    if (item == parent->child)
icculus@58
  1853
    {
icculus@58
  1854
        /* first element */
icculus@58
  1855
        parent->child = item->next;
icculus@58
  1856
    }
icculus@58
  1857
    /* make sure the detached item doesn't point anywhere anymore */
icculus@58
  1858
    item->prev = NULL;
icculus@58
  1859
    item->next = NULL;
icculus@58
  1860
icculus@58
  1861
    return item;
icculus@58
  1862
}
icculus@58
  1863
icculus@58
  1864
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which)
icculus@58
  1865
{
icculus@58
  1866
    if (which < 0)
icculus@58
  1867
    {
icculus@58
  1868
        return NULL;
icculus@58
  1869
    }
icculus@58
  1870
icculus@58
  1871
    return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which));
icculus@58
  1872
}
icculus@58
  1873
icculus@58
  1874
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which)
icculus@58
  1875
{
icculus@58
  1876
    cJSON_Delete(cJSON_DetachItemFromArray(array, which));
icculus@58
  1877
}
icculus@58
  1878
icculus@58
  1879
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string)
icculus@58
  1880
{
icculus@58
  1881
    cJSON *to_detach = cJSON_GetObjectItem(object, string);
icculus@58
  1882
icculus@58
  1883
    return cJSON_DetachItemViaPointer(object, to_detach);
icculus@58
  1884
}
icculus@58
  1885
icculus@58
  1886
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string)
icculus@58
  1887
{
icculus@58
  1888
    cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string);
icculus@58
  1889
icculus@58
  1890
    return cJSON_DetachItemViaPointer(object, to_detach);
icculus@58
  1891
}
icculus@58
  1892
icculus@58
  1893
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string)
icculus@58
  1894
{
icculus@58
  1895
    cJSON_Delete(cJSON_DetachItemFromObject(object, string));
icculus@58
  1896
}
icculus@58
  1897
icculus@58
  1898
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string)
icculus@58
  1899
{
icculus@58
  1900
    cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string));
icculus@58
  1901
}
icculus@58
  1902
icculus@58
  1903
/* Replace array/object items with new ones. */
icculus@58
  1904
CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
icculus@58
  1905
{
icculus@58
  1906
    cJSON *after_inserted = NULL;
icculus@58
  1907
icculus@58
  1908
    if (which < 0)
icculus@58
  1909
    {
icculus@58
  1910
        return;
icculus@58
  1911
    }
icculus@58
  1912
icculus@58
  1913
    after_inserted = get_array_item(array, (size_t)which);
icculus@58
  1914
    if (after_inserted == NULL)
icculus@58
  1915
    {
icculus@58
  1916
        cJSON_AddItemToArray(array, newitem);
icculus@58
  1917
        return;
icculus@58
  1918
    }
icculus@58
  1919
icculus@58
  1920
    newitem->next = after_inserted;
icculus@58
  1921
    newitem->prev = after_inserted->prev;
icculus@58
  1922
    after_inserted->prev = newitem;
icculus@58
  1923
    if (after_inserted == array->child)
icculus@58
  1924
    {
icculus@58
  1925
        array->child = newitem;
icculus@58
  1926
    }
icculus@58
  1927
    else
icculus@58
  1928
    {
icculus@58
  1929
        newitem->prev->next = newitem;
icculus@58
  1930
    }
icculus@58
  1931
}
icculus@58
  1932
icculus@58
  1933
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement)
icculus@58
  1934
{
icculus@58
  1935
    if ((parent == NULL) || (replacement == NULL))
icculus@58
  1936
    {
icculus@58
  1937
        return false;
icculus@58
  1938
    }
icculus@58
  1939
icculus@58
  1940
    if (replacement == item)
icculus@58
  1941
    {
icculus@58
  1942
        return true;
icculus@58
  1943
    }
icculus@58
  1944
icculus@58
  1945
    replacement->next = item->next;
icculus@58
  1946
    replacement->prev = item->prev;
icculus@58
  1947
icculus@58
  1948
    if (replacement->next != NULL)
icculus@58
  1949
    {
icculus@58
  1950
        replacement->next->prev = replacement;
icculus@58
  1951
    }
icculus@58
  1952
    if (replacement->prev != NULL)
icculus@58
  1953
    {
icculus@58
  1954
        replacement->prev->next = replacement;
icculus@58
  1955
    }
icculus@58
  1956
    if (parent->child == item)
icculus@58
  1957
    {
icculus@58
  1958
        parent->child = replacement;
icculus@58
  1959
    }
icculus@58
  1960
icculus@58
  1961
    item->next = NULL;
icculus@58
  1962
    item->prev = NULL;
icculus@58
  1963
    cJSON_Delete(item);
icculus@58
  1964
icculus@58
  1965
    return true;
icculus@58
  1966
}
icculus@58
  1967
icculus@58
  1968
CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
icculus@58
  1969
{
icculus@58
  1970
    if (which < 0)
icculus@58
  1971
    {
icculus@58
  1972
        return;
icculus@58
  1973
    }
icculus@58
  1974
icculus@58
  1975
    cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem);
icculus@58
  1976
}
icculus@58
  1977
icculus@58
  1978
static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive)
icculus@58
  1979
{
icculus@58
  1980
    if (replacement == NULL)
icculus@58
  1981
    {
icculus@58
  1982
        return false;
icculus@58
  1983
    }
icculus@58
  1984
icculus@58
  1985
    /* replace the name in the replacement */
icculus@58
  1986
    if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL))
icculus@58
  1987
    {
icculus@58
  1988
        cJSON_free(replacement->string);
icculus@58
  1989
    }
icculus@58
  1990
    replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
icculus@58
  1991
    replacement->type &= ~cJSON_StringIsConst;
icculus@58
  1992
icculus@58
  1993
    cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement);
icculus@58
  1994
icculus@58
  1995
    return true;
icculus@58
  1996
}
icculus@58
  1997
icculus@58
  1998
CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
icculus@58
  1999
{
icculus@58
  2000
    replace_item_in_object(object, string, newitem, false);
icculus@58
  2001
}
icculus@58
  2002
icculus@58
  2003
CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem)
icculus@58
  2004
{
icculus@58
  2005
    replace_item_in_object(object, string, newitem, true);
icculus@58
  2006
}
icculus@58
  2007
icculus@58
  2008
/* Create basic types: */
icculus@58
  2009
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void)
icculus@58
  2010
{
icculus@58
  2011
    cJSON *item = cJSON_New_Item(&global_hooks);
icculus@58
  2012
    if(item)
icculus@58
  2013
    {
icculus@58
  2014
        item->type = cJSON_NULL;
icculus@58
  2015
    }
icculus@58
  2016
icculus@58
  2017
    return item;
icculus@58
  2018
}
icculus@58
  2019
icculus@58
  2020
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void)
icculus@58
  2021
{
icculus@58
  2022
    cJSON *item = cJSON_New_Item(&global_hooks);
icculus@58
  2023
    if(item)
icculus@58
  2024
    {
icculus@58
  2025
        item->type = cJSON_True;
icculus@58
  2026
    }
icculus@58
  2027
icculus@58
  2028
    return item;
icculus@58
  2029
}
icculus@58
  2030
icculus@58
  2031
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void)
icculus@58
  2032
{
icculus@58
  2033
    cJSON *item = cJSON_New_Item(&global_hooks);
icculus@58
  2034
    if(item)
icculus@58
  2035
    {
icculus@58
  2036
        item->type = cJSON_False;
icculus@58
  2037
    }
icculus@58
  2038
icculus@58
  2039
    return item;
icculus@58
  2040
}
icculus@58
  2041
icculus@58
  2042
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b)
icculus@58
  2043
{
icculus@58
  2044
    cJSON *item = cJSON_New_Item(&global_hooks);
icculus@58
  2045
    if(item)
icculus@58
  2046
    {
icculus@58
  2047
        item->type = b ? cJSON_True : cJSON_False;
icculus@58
  2048
    }
icculus@58
  2049
icculus@58
  2050
    return item;
icculus@58
  2051
}
icculus@58
  2052
icculus@58
  2053
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
icculus@58
  2054
{
icculus@58
  2055
    cJSON *item = cJSON_New_Item(&global_hooks);
icculus@58
  2056
    if(item)
icculus@58
  2057
    {
icculus@58
  2058
        item->type = cJSON_Number;
icculus@58
  2059
        item->valuedouble = num;
icculus@58
  2060
icculus@58
  2061
        /* use saturation in case of overflow */
icculus@58
  2062
        if (num >= INT_MAX)
icculus@58
  2063
        {
icculus@58
  2064
            item->valueint = INT_MAX;
icculus@58
  2065
        }
icculus@58
  2066
        else if (num <= INT_MIN)
icculus@58
  2067
        {
icculus@58
  2068
            item->valueint = INT_MIN;
icculus@58
  2069
        }
icculus@58
  2070
        else
icculus@58
  2071
        {
icculus@58
  2072
            item->valueint = (int)num;
icculus@58
  2073
        }
icculus@58
  2074
    }
icculus@58
  2075
icculus@58
  2076
    return item;
icculus@58
  2077
}
icculus@58
  2078
icculus@58
  2079
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string)
icculus@58
  2080
{
icculus@58
  2081
    cJSON *item = cJSON_New_Item(&global_hooks);
icculus@58
  2082
    if(item)
icculus@58
  2083
    {
icculus@58
  2084
        item->type = cJSON_String;
icculus@58
  2085
        item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
icculus@58
  2086
        if(!item->valuestring)
icculus@58
  2087
        {
icculus@58
  2088
            cJSON_Delete(item);
icculus@58
  2089
            return NULL;
icculus@58
  2090
        }
icculus@58
  2091
    }
icculus@58
  2092
icculus@58
  2093
    return item;
icculus@58
  2094
}
icculus@58
  2095
icculus@58
  2096
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw)
icculus@58
  2097
{
icculus@58
  2098
    cJSON *item = cJSON_New_Item(&global_hooks);
icculus@58
  2099
    if(item)
icculus@58
  2100
    {
icculus@58
  2101
        item->type = cJSON_Raw;
icculus@58
  2102
        item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks);
icculus@58
  2103
        if(!item->valuestring)
icculus@58
  2104
        {
icculus@58
  2105
            cJSON_Delete(item);
icculus@58
  2106
            return NULL;
icculus@58
  2107
        }
icculus@58
  2108
    }
icculus@58
  2109
icculus@58
  2110
    return item;
icculus@58
  2111
}
icculus@58
  2112
icculus@58
  2113
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void)
icculus@58
  2114
{
icculus@58
  2115
    cJSON *item = cJSON_New_Item(&global_hooks);
icculus@58
  2116
    if(item)
icculus@58
  2117
    {
icculus@58
  2118
        item->type=cJSON_Array;
icculus@58
  2119
    }
icculus@58
  2120
icculus@58
  2121
    return item;
icculus@58
  2122
}
icculus@58
  2123
icculus@58
  2124
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void)
icculus@58
  2125
{
icculus@58
  2126
    cJSON *item = cJSON_New_Item(&global_hooks);
icculus@58
  2127
    if (item)
icculus@58
  2128
    {
icculus@58
  2129
        item->type = cJSON_Object;
icculus@58
  2130
    }
icculus@58
  2131
icculus@58
  2132
    return item;
icculus@58
  2133
}
icculus@58
  2134
icculus@58
  2135
/* Create Arrays: */
icculus@58
  2136
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)
icculus@58
  2137
{
icculus@58
  2138
    size_t i = 0;
icculus@58
  2139
    cJSON *n = NULL;
icculus@58
  2140
    cJSON *p = NULL;
icculus@58
  2141
    cJSON *a = NULL;
icculus@58
  2142
icculus@58
  2143
    if (count < 0)
icculus@58
  2144
    {
icculus@58
  2145
        return NULL;
icculus@58
  2146
    }
icculus@58
  2147
icculus@58
  2148
    a = cJSON_CreateArray();
icculus@58
  2149
    for(i = 0; a && (i < (size_t)count); i++)
icculus@58
  2150
    {
icculus@58
  2151
        n = cJSON_CreateNumber(numbers[i]);
icculus@58
  2152
        if (!n)
icculus@58
  2153
        {
icculus@58
  2154
            cJSON_Delete(a);
icculus@58
  2155
            return NULL;
icculus@58
  2156
        }
icculus@58
  2157
        if(!i)
icculus@58
  2158
        {
icculus@58
  2159
            a->child = n;
icculus@58
  2160
        }
icculus@58
  2161
        else
icculus@58
  2162
        {
icculus@58
  2163
            suffix_object(p, n);
icculus@58
  2164
        }
icculus@58
  2165
        p = n;
icculus@58
  2166
    }
icculus@58
  2167
icculus@58
  2168
    return a;
icculus@58
  2169
}
icculus@58
  2170
icculus@58
  2171
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count)
icculus@58
  2172
{
icculus@58
  2173
    size_t i = 0;
icculus@58
  2174
    cJSON *n = NULL;
icculus@58
  2175
    cJSON *p = NULL;
icculus@58
  2176
    cJSON *a = NULL;
icculus@58
  2177
icculus@58
  2178
    if (count < 0)
icculus@58
  2179
    {
icculus@58
  2180
        return NULL;
icculus@58
  2181
    }
icculus@58
  2182
icculus@58
  2183
    a = cJSON_CreateArray();
icculus@58
  2184
icculus@58
  2185
    for(i = 0; a && (i < (size_t)count); i++)
icculus@58
  2186
    {
icculus@58
  2187
        n = cJSON_CreateNumber((double)numbers[i]);
icculus@58
  2188
        if(!n)
icculus@58
  2189
        {
icculus@58
  2190
            cJSON_Delete(a);
icculus@58
  2191
            return NULL;
icculus@58
  2192
        }
icculus@58
  2193
        if(!i)
icculus@58
  2194
        {
icculus@58
  2195
            a->child = n;
icculus@58
  2196
        }
icculus@58
  2197
        else
icculus@58
  2198
        {
icculus@58
  2199
            suffix_object(p, n);
icculus@58
  2200
        }
icculus@58
  2201
        p = n;
icculus@58
  2202
    }
icculus@58
  2203
icculus@58
  2204
    return a;
icculus@58
  2205
}
icculus@58
  2206
icculus@58
  2207
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count)
icculus@58
  2208
{
icculus@58
  2209
    size_t i = 0;
icculus@58
  2210
    cJSON *n = NULL;
icculus@58
  2211
    cJSON *p = NULL;
icculus@58
  2212
    cJSON *a = NULL;
icculus@58
  2213
icculus@58
  2214
    if (count < 0)
icculus@58
  2215
    {
icculus@58
  2216
        return NULL;
icculus@58
  2217
    }
icculus@58
  2218
icculus@58
  2219
    a = cJSON_CreateArray();
icculus@58
  2220
icculus@58
  2221
    for(i = 0;a && (i < (size_t)count); i++)
icculus@58
  2222
    {
icculus@58
  2223
        n = cJSON_CreateNumber(numbers[i]);
icculus@58
  2224
        if(!n)
icculus@58
  2225
        {
icculus@58
  2226
            cJSON_Delete(a);
icculus@58
  2227
            return NULL;
icculus@58
  2228
        }
icculus@58
  2229
        if(!i)
icculus@58
  2230
        {
icculus@58
  2231
            a->child = n;
icculus@58
  2232
        }
icculus@58
  2233
        else
icculus@58
  2234
        {
icculus@58
  2235
            suffix_object(p, n);
icculus@58
  2236
        }
icculus@58
  2237
        p = n;
icculus@58
  2238
    }
icculus@58
  2239
icculus@58
  2240
    return a;
icculus@58
  2241
}
icculus@58
  2242
icculus@58
  2243
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count)
icculus@58
  2244
{
icculus@58
  2245
    size_t i = 0;
icculus@58
  2246
    cJSON *n = NULL;
icculus@58
  2247
    cJSON *p = NULL;
icculus@58
  2248
    cJSON *a = NULL;
icculus@58
  2249
icculus@58
  2250
    if (count < 0)
icculus@58
  2251
    {
icculus@58
  2252
        return NULL;
icculus@58
  2253
    }
icculus@58
  2254
icculus@58
  2255
    a = cJSON_CreateArray();
icculus@58
  2256
icculus@58
  2257
    for (i = 0; a && (i < (size_t)count); i++)
icculus@58
  2258
    {
icculus@58
  2259
        n = cJSON_CreateString(strings[i]);
icculus@58
  2260
        if(!n)
icculus@58
  2261
        {
icculus@58
  2262
            cJSON_Delete(a);
icculus@58
  2263
            return NULL;
icculus@58
  2264
        }
icculus@58
  2265
        if(!i)
icculus@58
  2266
        {
icculus@58
  2267
            a->child = n;
icculus@58
  2268
        }
icculus@58
  2269
        else
icculus@58
  2270
        {
icculus@58
  2271
            suffix_object(p,n);
icculus@58
  2272
        }
icculus@58
  2273
        p = n;
icculus@58
  2274
    }
icculus@58
  2275
icculus@58
  2276
    return a;
icculus@58
  2277
}
icculus@58
  2278
icculus@58
  2279
/* Duplication */
icculus@58
  2280
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
icculus@58
  2281
{
icculus@58
  2282
    cJSON *newitem = NULL;
icculus@58
  2283
    cJSON *child = NULL;
icculus@58
  2284
    cJSON *next = NULL;
icculus@58
  2285
    cJSON *newchild = NULL;
icculus@58
  2286
icculus@58
  2287
    /* Bail on bad ptr */
icculus@58
  2288
    if (!item)
icculus@58
  2289
    {
icculus@58
  2290
        goto fail;
icculus@58
  2291
    }
icculus@58
  2292
    /* Create new item */
icculus@58
  2293
    newitem = cJSON_New_Item(&global_hooks);
icculus@58
  2294
    if (!newitem)
icculus@58
  2295
    {
icculus@58
  2296
        goto fail;
icculus@58
  2297
    }
icculus@58
  2298
    /* Copy over all vars */
icculus@58
  2299
    newitem->type = item->type & (~cJSON_IsReference);
icculus@58
  2300
    newitem->valueint = item->valueint;
icculus@58
  2301
    newitem->valuedouble = item->valuedouble;
icculus@58
  2302
    if (item->valuestring)
icculus@58
  2303
    {
icculus@58
  2304
        newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks);
icculus@58
  2305
        if (!newitem->valuestring)
icculus@58
  2306
        {
icculus@58
  2307
            goto fail;
icculus@58
  2308
        }
icculus@58
  2309
    }
icculus@58
  2310
    if (item->string)
icculus@58
  2311
    {
icculus@58
  2312
        newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks);
icculus@58
  2313
        if (!newitem->string)
icculus@58
  2314
        {
icculus@58
  2315
            goto fail;
icculus@58
  2316
        }
icculus@58
  2317
    }
icculus@58
  2318
    /* If non-recursive, then we're done! */
icculus@58
  2319
    if (!recurse)
icculus@58
  2320
    {
icculus@58
  2321
        return newitem;
icculus@58
  2322
    }
icculus@58
  2323
    /* Walk the ->next chain for the child. */
icculus@58
  2324
    child = item->child;
icculus@58
  2325
    while (child != NULL)
icculus@58
  2326
    {
icculus@58
  2327
        newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */
icculus@58
  2328
        if (!newchild)
icculus@58
  2329
        {
icculus@58
  2330
            goto fail;
icculus@58
  2331
        }
icculus@58
  2332
        if (next != NULL)
icculus@58
  2333
        {
icculus@58
  2334
            /* If newitem->child already set, then crosswire ->prev and ->next and move on */
icculus@58
  2335
            next->next = newchild;
icculus@58
  2336
            newchild->prev = next;
icculus@58
  2337
            next = newchild;
icculus@58
  2338
        }
icculus@58
  2339
        else
icculus@58
  2340
        {
icculus@58
  2341
            /* Set newitem->child and move to it */
icculus@58
  2342
            newitem->child = newchild;
icculus@58
  2343
            next = newchild;
icculus@58
  2344
        }
icculus@58
  2345
        child = child->next;
icculus@58
  2346
    }
icculus@58
  2347
icculus@58
  2348
    return newitem;
icculus@58
  2349
icculus@58
  2350
fail:
icculus@58
  2351
    if (newitem != NULL)
icculus@58
  2352
    {
icculus@58
  2353
        cJSON_Delete(newitem);
icculus@58
  2354
    }
icculus@58
  2355
icculus@58
  2356
    return NULL;
icculus@58
  2357
}
icculus@58
  2358
icculus@58
  2359
CJSON_PUBLIC(void) cJSON_Minify(char *json)
icculus@58
  2360
{
icculus@58
  2361
    unsigned char *into = (unsigned char*)json;
icculus@58
  2362
    while (*json)
icculus@58
  2363
    {
icculus@58
  2364
        if (*json == ' ')
icculus@58
  2365
        {
icculus@58
  2366
            json++;
icculus@58
  2367
        }
icculus@58
  2368
        else if (*json == '\t')
icculus@58
  2369
        {
icculus@58
  2370
            /* Whitespace characters. */
icculus@58
  2371
            json++;
icculus@58
  2372
        }
icculus@58
  2373
        else if (*json == '\r')
icculus@58
  2374
        {
icculus@58
  2375
            json++;
icculus@58
  2376
        }
icculus@58
  2377
        else if (*json=='\n')
icculus@58
  2378
        {
icculus@58
  2379
            json++;
icculus@58
  2380
        }
icculus@58
  2381
        else if ((*json == '/') && (json[1] == '/'))
icculus@58
  2382
        {
icculus@58
  2383
            /* double-slash comments, to end of line. */
icculus@58
  2384
            while (*json && (*json != '\n'))
icculus@58
  2385
            {
icculus@58
  2386
                json++;
icculus@58
  2387
            }
icculus@58
  2388
        }
icculus@58
  2389
        else if ((*json == '/') && (json[1] == '*'))
icculus@58
  2390
        {
icculus@58
  2391
            /* multiline comments. */
icculus@58
  2392
            while (*json && !((*json == '*') && (json[1] == '/')))
icculus@58
  2393
            {
icculus@58
  2394
                json++;
icculus@58
  2395
            }
icculus@58
  2396
            json += 2;
icculus@58
  2397
        }
icculus@58
  2398
        else if (*json == '\"')
icculus@58
  2399
        {
icculus@58
  2400
            /* string literals, which are \" sensitive. */
icculus@58
  2401
            *into++ = (unsigned char)*json++;
icculus@58
  2402
            while (*json && (*json != '\"'))
icculus@58
  2403
            {
icculus@58
  2404
                if (*json == '\\')
icculus@58
  2405
                {
icculus@58
  2406
                    *into++ = (unsigned char)*json++;
icculus@58
  2407
                }
icculus@58
  2408
                *into++ = (unsigned char)*json++;
icculus@58
  2409
            }
icculus@58
  2410
            *into++ = (unsigned char)*json++;
icculus@58
  2411
        }
icculus@58
  2412
        else
icculus@58
  2413
        {
icculus@58
  2414
            /* All other characters. */
icculus@58
  2415
            *into++ = (unsigned char)*json++;
icculus@58
  2416
        }
icculus@58
  2417
    }
icculus@58
  2418
icculus@58
  2419
    /* and null-terminate. */
icculus@58
  2420
    *into = '\0';
icculus@58
  2421
}
icculus@58
  2422
icculus@58
  2423
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item)
icculus@58
  2424
{
icculus@58
  2425
    if (item == NULL)
icculus@58
  2426
    {
icculus@58
  2427
        return false;
icculus@58
  2428
    }
icculus@58
  2429
icculus@58
  2430
    return (item->type & 0xFF) == cJSON_Invalid;
icculus@58
  2431
}
icculus@58
  2432
icculus@58
  2433
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item)
icculus@58
  2434
{
icculus@58
  2435
    if (item == NULL)
icculus@58
  2436
    {
icculus@58
  2437
        return false;
icculus@58
  2438
    }
icculus@58
  2439
icculus@58
  2440
    return (item->type & 0xFF) == cJSON_False;
icculus@58
  2441
}
icculus@58
  2442
icculus@58
  2443
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item)
icculus@58
  2444
{
icculus@58
  2445
    if (item == NULL)
icculus@58
  2446
    {
icculus@58
  2447
        return false;
icculus@58
  2448
    }
icculus@58
  2449
icculus@58
  2450
    return (item->type & 0xff) == cJSON_True;
icculus@58
  2451
}
icculus@58
  2452
icculus@58
  2453
icculus@58
  2454
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item)
icculus@58
  2455
{
icculus@58
  2456
    if (item == NULL)
icculus@58
  2457
    {
icculus@58
  2458
        return false;
icculus@58
  2459
    }
icculus@58
  2460
icculus@58
  2461
    return (item->type & (cJSON_True | cJSON_False)) != 0;
icculus@58
  2462
}
icculus@58
  2463
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item)
icculus@58
  2464
{
icculus@58
  2465
    if (item == NULL)
icculus@58
  2466
    {
icculus@58
  2467
        return false;
icculus@58
  2468
    }
icculus@58
  2469
icculus@58
  2470
    return (item->type & 0xFF) == cJSON_NULL;
icculus@58
  2471
}
icculus@58
  2472
icculus@58
  2473
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item)
icculus@58
  2474
{
icculus@58
  2475
    if (item == NULL)
icculus@58
  2476
    {
icculus@58
  2477
        return false;
icculus@58
  2478
    }
icculus@58
  2479
icculus@58
  2480
    return (item->type & 0xFF) == cJSON_Number;
icculus@58
  2481
}
icculus@58
  2482
icculus@58
  2483
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item)
icculus@58
  2484
{
icculus@58
  2485
    if (item == NULL)
icculus@58
  2486
    {
icculus@58
  2487
        return false;
icculus@58
  2488
    }
icculus@58
  2489
icculus@58
  2490
    return (item->type & 0xFF) == cJSON_String;
icculus@58
  2491
}
icculus@58
  2492
icculus@58
  2493
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item)
icculus@58
  2494
{
icculus@58
  2495
    if (item == NULL)
icculus@58
  2496
    {
icculus@58
  2497
        return false;
icculus@58
  2498
    }
icculus@58
  2499
icculus@58
  2500
    return (item->type & 0xFF) == cJSON_Array;
icculus@58
  2501
}
icculus@58
  2502
icculus@58
  2503
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item)
icculus@58
  2504
{
icculus@58
  2505
    if (item == NULL)
icculus@58
  2506
    {
icculus@58
  2507
        return false;
icculus@58
  2508
    }
icculus@58
  2509
icculus@58
  2510
    return (item->type & 0xFF) == cJSON_Object;
icculus@58
  2511
}
icculus@58
  2512
icculus@58
  2513
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item)
icculus@58
  2514
{
icculus@58
  2515
    if (item == NULL)
icculus@58
  2516
    {
icculus@58
  2517
        return false;
icculus@58
  2518
    }
icculus@58
  2519
icculus@58
  2520
    return (item->type & 0xFF) == cJSON_Raw;
icculus@58
  2521
}
icculus@58
  2522
icculus@58
  2523
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive)
icculus@58
  2524
{
icculus@58
  2525
    if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a))
icculus@58
  2526
    {
icculus@58
  2527
        return false;
icculus@58
  2528
    }
icculus@58
  2529
icculus@58
  2530
    /* check if type is valid */
icculus@58
  2531
    switch (a->type & 0xFF)
icculus@58
  2532
    {
icculus@58
  2533
        case cJSON_False:
icculus@58
  2534
        case cJSON_True:
icculus@58
  2535
        case cJSON_NULL:
icculus@58
  2536
        case cJSON_Number:
icculus@58
  2537
        case cJSON_String:
icculus@58
  2538
        case cJSON_Raw:
icculus@58
  2539
        case cJSON_Array:
icculus@58
  2540
        case cJSON_Object:
icculus@58
  2541
            break;
icculus@58
  2542
icculus@58
  2543
        default:
icculus@58
  2544
            return false;
icculus@58
  2545
    }
icculus@58
  2546
icculus@58
  2547
    /* identical objects are equal */
icculus@58
  2548
    if (a == b)
icculus@58
  2549
    {
icculus@58
  2550
        return true;
icculus@58
  2551
    }
icculus@58
  2552
icculus@58
  2553
    switch (a->type & 0xFF)
icculus@58
  2554
    {
icculus@58
  2555
        /* in these cases and equal type is enough */
icculus@58
  2556
        case cJSON_False:
icculus@58
  2557
        case cJSON_True:
icculus@58
  2558
        case cJSON_NULL:
icculus@58
  2559
            return true;
icculus@58
  2560
icculus@58
  2561
        case cJSON_Number:
icculus@58
  2562
            if (a->valuedouble == b->valuedouble)
icculus@58
  2563
            {
icculus@58
  2564
                return true;
icculus@58
  2565
            }
icculus@58
  2566
            return false;
icculus@58
  2567
icculus@58
  2568
        case cJSON_String:
icculus@58
  2569
        case cJSON_Raw:
icculus@58
  2570
            if ((a->valuestring == NULL) || (b->valuestring == NULL))
icculus@58
  2571
            {
icculus@58
  2572
                return false;
icculus@58
  2573
            }
icculus@58
  2574
            if (strcmp(a->valuestring, b->valuestring) == 0)
icculus@58
  2575
            {
icculus@58
  2576
                return true;
icculus@58
  2577
            }
icculus@58
  2578
icculus@58
  2579
            return false;
icculus@58
  2580
icculus@58
  2581
        case cJSON_Array:
icculus@58
  2582
        {
icculus@58
  2583
            cJSON *a_element = a->child;
icculus@58
  2584
            cJSON *b_element = b->child;
icculus@58
  2585
icculus@58
  2586
            for (; (a_element != NULL) && (b_element != NULL);)
icculus@58
  2587
            {
icculus@58
  2588
                if (!cJSON_Compare(a_element, b_element, case_sensitive))
icculus@58
  2589
                {