Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F20320900
cJSON.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
32 KB
Subscribers
None
cJSON.c
View Options
/* cJSON.c - JSON parser in C.
* Copyright (c) 2009 Dave Gamble
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* SPDX-License-Identifier: MIT
*
* Note that this code has been modified from the original code taken
* from cjson-code-58.zip before 2014 (my first local commit was in
* 2014 but I may used the code even earlier). Since 2016 the project
* was revived and moved to https://github.com/DaveGamble/cJSON.git.
* It is now a lot more complex and has substantial changes so that it
* is not possible to merge them directly. In any case we only need a
* simple parser and not a complete library. I have looked through
* the commits and fixed a few things which should apply; I also added
* a few references to the upstream code. Regression test are missing!
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include
<string.h>
#include
<stdio.h>
#include
<math.h>
#include
<stdlib.h>
#include
<stdint.h>
#include
<float.h>
#include
<limits.h>
#include
<ctype.h>
#include
<errno.h>
#include
<gpg-error.h>
#include
"cJSON.h"
/* Only use calloc. */
#define CALLOC_ONLY 1
/* Maximum recursion depth */
#define MAX_DEPTH 512
/* We use malloc function wrappers from gpgrt (aka libgpg-error). */
#include
<gpgrt.h>
#define xtrycalloc(a,b) gpgrt_calloc ((a), (b))
#define xtrystrdup(a) gpgrt_strdup ((a))
#define xfree(a) gpgrt_free ((a))
#if CALLOC_ONLY
# define xtrymalloc(a) gpgrt_calloc (1, (a))
#else
# define xtrymalloc(a) gpgrt_malloc ((a))
#endif
static
void
wipememory
(
void
*
ptr
,
size_t
len
)
{
/* Prevent compiler from optimizing away the call to memset by accessing
* memset through volatile pointer. */
static
void
*
(
*
volatile
memset_ptr
)(
void
*
,
int
,
size_t
)
=
(
void
*
)
memset
;
memset_ptr
(
ptr
,
0
,
len
);
}
static
int
cJSON_strcasecmp
(
const
char
*
s1
,
const
char
*
s2
)
{
if
(
!
s1
)
return
(
s1
==
s2
)
?
0
:
1
;
if
(
!
s2
)
return
1
;
for
(;
tolower
(
*
(
const
unsigned
char
*
)
s1
)
==
tolower
(
*
(
const
unsigned
char
*
)
s2
);
++
s1
,
++
s2
)
if
(
*
s1
==
0
)
return
0
;
return
tolower
(
*
(
const
unsigned
char
*
)
s1
)
-
tolower
(
*
(
const
unsigned
char
*
)
s2
);
}
/* Internal constructor. */
static
cJSON
*
cJSON_New_Item
(
void
)
{
return
xtrycalloc
(
1
,
sizeof
(
cJSON
));
}
/* Delete a cJSON structure. (Does not clobber ERRNO). */
void
cJSON_Delete
(
cJSON
*
c
)
{
cJSON
*
next
;
int
save_errno
;
if
(
!
c
)
return
;
save_errno
=
errno
;
while
(
c
)
{
next
=
c
->
next
;
if
(
!
(
c
->
type
&
cJSON_IsReference
)
&&
c
->
child
)
cJSON_Delete
(
c
->
child
);
if
(
!
(
c
->
type
&
cJSON_IsReference
)
&&
c
->
valuestring
)
{
wipememory
(
c
->
valuestring
,
strlen
(
c
->
valuestring
));
xfree
(
c
->
valuestring
);
}
if
(
c
->
string
)
{
wipememory
(
c
->
string
,
strlen
(
c
->
string
));
xfree
(
c
->
string
);
}
xfree
(
c
);
c
=
next
;
}
errno
=
save_errno
;
}
/* Parse the input text to generate a number, and populate the result
* into item. */
static
const
char
*
parse_number
(
cJSON
*
item
,
const
char
*
num
)
{
int
subscale
=
0
;
int
signsubscale
=
1
;
double
n
=
0
;
double
sign
=
1
;
double
scale
=
0
;
double
dblmin
=
INT32_MIN
;
double
dblmax
=
INT32_MAX
;
if
(
*
num
==
'-'
)
sign
=
-1
,
num
++
;
/* Has sign? */
if
(
*
num
==
'0'
)
num
++
;
/* is zero */
if
(
*
num
>=
'1'
&&
*
num
<=
'9'
)
do
n
=
(
n
*
10.0
)
+
(
*
num
++
-
'0'
);
while
(
*
num
>=
'0'
&&
*
num
<=
'9'
);
/* Number? */
if
(
*
num
==
'.'
&&
num
[
1
]
>=
'0'
&&
num
[
1
]
<=
'9'
)
{
num
++
;
do
n
=
(
n
*
10.0
)
+
(
*
num
++
-
'0'
),
scale
--
;
while
(
*
num
>=
'0'
&&
*
num
<=
'9'
);
}
/* Fractional part? */
if
(
*
num
==
'e'
||
*
num
==
'E'
)
/* Exponent? */
{
num
++
;
if
(
*
num
==
'+'
)
num
++
;
else
if
(
*
num
==
'-'
)
/* With sign? */
signsubscale
=
-1
,
num
++
;
while
(
*
num
>=
'0'
&&
*
num
<=
'9'
)
{
if
((
10
*
(
double
)
subscale
)
>
dblmax
)
break
;
subscale
=
(
subscale
*
10
)
+
(
*
num
++
-
'0'
);
}
}
/* number = +/- number.fraction * 10^+/- exponent */
n
=
sign
*
n
*
pow
(
10.0
,
(
scale
+
subscale
*
signsubscale
));
/* For NAN set both parts to 0. For out of range values let the
* integer part be 0. */
if
(
isnan
(
n
)
||
isinf
(
n
))
{
item
->
valuedouble
=
0
;
item
->
valueint
=
0
;
}
else
if
(
n
>
dblmax
||
n
<
dblmin
)
{
item
->
valuedouble
=
n
;
item
->
valueint
=
0
;
}
else
{
item
->
valuedouble
=
n
;
item
->
valueint
=
(
int
)
n
;
}
item
->
type
=
cJSON_Number
;
return
num
;
}
/* Render the number nicely from the given item into a string. */
static
char
*
print_number
(
cJSON
*
item
)
{
char
*
str
;
double
d
=
item
->
valuedouble
;
int
i
;
if
(
fabs
(((
double
)
item
->
valueint
)
-
d
)
<=
DBL_EPSILON
&&
d
<=
INT_MAX
&&
d
>=
INT_MIN
)
{
/* 2^64+1 can be represented in 21 chars. */
str
=
xtrymalloc
(
21
);
if
(
str
)
sprintf
(
str
,
"%d"
,
item
->
valueint
);
}
else
{
str
=
xtrymalloc
(
64
);
/* This is a nice tradeoff. */
if
(
str
)
{
if
(
isnan
(
d
))
strcpy
(
str
,
"nan"
);
else
if
((
i
=
isinf
(
d
)))
strcpy
(
str
,
i
>
0
?
"inf"
:
":-inf"
);
else
if
(
fabs
(
floor
(
d
)
-
d
)
<=
DBL_EPSILON
&&
fabs
(
d
)
<
1.0e60
)
sprintf
(
str
,
"%.0f"
,
d
);
else
if
(
fabs
(
d
)
<
1.0e-6
||
fabs
(
d
)
>
1.0e9
)
sprintf
(
str
,
"%e"
,
d
);
else
sprintf
(
str
,
"%f"
,
d
);
}
}
return
str
;
}
static
unsigned
parse_hex4
(
const
char
*
str
)
{
unsigned
h
=
0
;
if
(
*
str
>=
'0'
&&
*
str
<=
'9'
)
h
+=
(
*
str
)
-
'0'
;
else
if
(
*
str
>=
'A'
&&
*
str
<=
'F'
)
h
+=
10
+
(
*
str
)
-
'A'
;
else
if
(
*
str
>=
'a'
&&
*
str
<=
'f'
)
h
+=
10
+
(
*
str
)
-
'a'
;
else
return
0
;
h
=
h
<<
4
;
str
++
;
if
(
*
str
>=
'0'
&&
*
str
<=
'9'
)
h
+=
(
*
str
)
-
'0'
;
else
if
(
*
str
>=
'A'
&&
*
str
<=
'F'
)
h
+=
10
+
(
*
str
)
-
'A'
;
else
if
(
*
str
>=
'a'
&&
*
str
<=
'f'
)
h
+=
10
+
(
*
str
)
-
'a'
;
else
return
0
;
h
=
h
<<
4
;
str
++
;
if
(
*
str
>=
'0'
&&
*
str
<=
'9'
)
h
+=
(
*
str
)
-
'0'
;
else
if
(
*
str
>=
'A'
&&
*
str
<=
'F'
)
h
+=
10
+
(
*
str
)
-
'A'
;
else
if
(
*
str
>=
'a'
&&
*
str
<=
'f'
)
h
+=
10
+
(
*
str
)
-
'a'
;
else
return
0
;
h
=
h
<<
4
;
str
++
;
if
(
*
str
>=
'0'
&&
*
str
<=
'9'
)
h
+=
(
*
str
)
-
'0'
;
else
if
(
*
str
>=
'A'
&&
*
str
<=
'F'
)
h
+=
10
+
(
*
str
)
-
'A'
;
else
if
(
*
str
>=
'a'
&&
*
str
<=
'f'
)
h
+=
10
+
(
*
str
)
-
'a'
;
else
return
0
;
return
h
;
}
/* Parse the input text into an unescaped cstring, and populate item. */
static
const
unsigned
char
firstByteMark
[
7
]
=
{
0x00
,
0x00
,
0xC0
,
0xE0
,
0xF0
,
0xF8
,
0xFC
};
static
const
char
*
parse_string
(
cJSON
*
item
,
const
char
*
str
,
const
char
**
ep
)
{
const
char
*
ptr
=
str
+
1
;
char
*
ptr2
;
char
*
out
;
int
len
=
0
;
unsigned
uc
,
uc2
;
/* FIXME: We should consider eary failure like it is done with
* commit 8656386c4f4a12f1cf3d6b26158407fd05e65029 in upstream. */
if
(
*
str
!=
'\"'
)
{
*
ep
=
str
;
return
0
;
}
/* not a string! */
while
(
*
ptr
!=
'\"'
&&
*
ptr
&&
++
len
)
if
(
*
ptr
++
==
'\\'
&&
*
ptr
)
ptr
++
;
/* Skip escaped quotes. */
out
=
xtrymalloc
(
len
+
2
);
/* This is how long we need for the
* string, roughly. We add one extra
* byte in case the last input
* character is a backslash. */
if
(
!
out
)
return
0
;
ptr
=
str
+
1
;
ptr2
=
out
;
while
(
*
ptr
!=
'\"'
&&
*
ptr
)
{
if
(
*
ptr
!=
'\\'
)
*
ptr2
++
=
*
ptr
++
;
else
{
ptr
++
;
if
(
!*
ptr
)
break
;
switch
(
*
ptr
)
{
case
'b'
:
*
ptr2
++
=
'\b'
;
break
;
case
'f'
:
*
ptr2
++
=
'\f'
;
break
;
case
'n'
:
*
ptr2
++
=
'\n'
;
break
;
case
'r'
:
*
ptr2
++
=
'\r'
;
break
;
case
't'
:
*
ptr2
++
=
'\t'
;
break
;
case
'u'
:
/* transcode utf16 to utf8. */
uc
=
parse_hex4
(
ptr
+
1
);
if
(
!
uc
)
break
;
/* Bad hex; continue right after the 'u'. */
ptr
+=
4
;
/* get the unicode char. */
if
((
uc
>=
0xDC00
&&
uc
<=
0xDFFF
))
break
;
/* check for invalid. */
if
(
uc
>=
0xD800
&&
uc
<=
0xDBFF
)
/* UTF16 surrogate pairs. */
{
if
(
ptr
[
1
]
!=
'\\'
||
ptr
[
2
]
!=
'u'
)
break
;
/* missing second-half of surrogate. */
ptr
+=
2
;
uc2
=
parse_hex4
(
ptr
+
1
);
if
(
!
uc2
)
break
;
/* Bad hex; continue right after the 'u'. */
ptr
+=
4
;
if
(
uc2
<
0xDC00
||
uc2
>
0xDFFF
)
break
;
/* invalid second-half of surrogate. */
uc
=
0x10000
+
(((
uc
&
0x3FF
)
<<
10
)
|
(
uc2
&
0x3FF
));
}
len
=
4
;
if
(
uc
<
0x80
)
len
=
1
;
else
if
(
uc
<
0x800
)
len
=
2
;
else
if
(
uc
<
0x10000
)
len
=
3
;
ptr2
+=
len
;
switch
(
len
)
{
case
4
:
*--
ptr2
=
((
uc
|
0x80
)
&
0xBF
);
uc
>>=
6
;
/*FALLTHRU*/
case
3
:
*--
ptr2
=
((
uc
|
0x80
)
&
0xBF
);
uc
>>=
6
;
/*FALLTHRU*/
case
2
:
*--
ptr2
=
((
uc
|
0x80
)
&
0xBF
);
uc
>>=
6
;
/*FALLTHRU*/
case
1
:
*--
ptr2
=
(
uc
|
firstByteMark
[
len
]);
}
ptr2
+=
len
;
break
;
default
:
/* Fixme: Should we fail here: See
* https://github.com/DaveGamble/cJSON/issues/10 */
*
ptr2
++
=
*
ptr
;
break
;
}
ptr
++
;
}
}
*
ptr2
=
0
;
if
(
*
ptr
==
'\"'
)
ptr
++
;
item
->
valuestring
=
out
;
item
->
type
=
cJSON_String
;
return
ptr
;
}
/* Render the cstring provided to an escaped version that can be printed. */
static
char
*
print_string_ptr
(
const
char
*
str
)
{
const
char
*
ptr
;
char
*
ptr2
,
*
out
;
int
len
=
0
;
unsigned
char
token
;
if
(
!
str
)
return
xtrystrdup
(
""
);
ptr
=
str
;
while
((
token
=
*
ptr
)
&&
++
len
)
{
if
(
strchr
(
"
\"\\\b\f\n\r\t
"
,
token
))
len
++
;
else
if
(
token
<
32
)
len
+=
5
;
ptr
++
;
}
out
=
xtrymalloc
(
len
+
3
);
if
(
!
out
)
return
0
;
ptr2
=
out
;
ptr
=
str
;
*
ptr2
++
=
'\"'
;
while
(
*
ptr
)
{
if
((
unsigned
char
)
*
ptr
>
31
&&
*
ptr
!=
'\"'
&&
*
ptr
!=
'\\'
)
*
ptr2
++
=
*
ptr
++
;
else
{
*
ptr2
++
=
'\\'
;
switch
(
token
=
*
ptr
++
)
{
case
'\\'
:
*
ptr2
++
=
'\\'
;
break
;
case
'\"'
:
*
ptr2
++
=
'\"'
;
break
;
case
'\b'
:
*
ptr2
++
=
'b'
;
break
;
case
'\f'
:
*
ptr2
++
=
'f'
;
break
;
case
'\n'
:
*
ptr2
++
=
'n'
;
break
;
case
'\r'
:
*
ptr2
++
=
'r'
;
break
;
case
'\t'
:
*
ptr2
++
=
't'
;
break
;
default
:
sprintf
(
ptr2
,
"u%04x"
,
token
);
ptr2
+=
5
;
break
;
/* escape and print */
}
}
}
*
ptr2
++
=
'\"'
;
*
ptr2
++
=
0
;
return
out
;
}
/* Invote print_string_ptr (which is useful) on an item. */
static
char
*
print_string
(
cJSON
*
item
)
{
return
print_string_ptr
(
item
->
valuestring
);
}
/* Predeclare these prototypes. */
static
const
char
*
parse_value
(
cJSON
*
item
,
const
char
*
value
,
const
char
**
ep
,
size_t
depth
);
static
char
*
print_value
(
cJSON
*
item
,
int
depth
,
int
fmt
);
static
const
char
*
parse_array
(
cJSON
*
item
,
const
char
*
value
,
const
char
**
ep
,
size_t
depth
);
static
char
*
print_array
(
cJSON
*
item
,
int
depth
,
int
fmt
);
static
const
char
*
parse_object
(
cJSON
*
item
,
const
char
*
value
,
const
char
**
ep
,
size_t
depth
);
static
char
*
print_object
(
cJSON
*
item
,
int
depth
,
int
fmt
);
/* Utility to jump whitespace and cr/lf */
static
const
char
*
skip
(
const
char
*
in
)
{
while
(
in
&&
*
in
&&
(
unsigned
char
)
*
in
<=
32
)
in
++
;
return
in
;
}
/* Parse an object - create a new root, and populate. */
cJSON
*
cJSON_ParseWithOpts
(
const
char
*
value
,
const
char
**
return_parse_end
,
int
require_null_terminated
,
size_t
*
r_erroff
)
{
const
char
*
end
=
0
;
const
char
*
ep
=
0
;
cJSON
*
c
;
if
(
r_erroff
)
*
r_erroff
=
0
;
c
=
cJSON_New_Item
();
if
(
!
c
)
return
NULL
;
/* memory fail */
end
=
parse_value
(
c
,
skip
(
value
),
&
ep
,
0
);
if
(
!
end
)
{
cJSON_Delete
(
c
);
errno
=
EINVAL
;
if
(
r_erroff
)
*
r_erroff
=
ep
-
value
;
return
0
;
}
/* parse failure. ep is set. */
/* if we require null-terminated JSON without appended garbage, skip
and then check for a null terminator */
if
(
require_null_terminated
)
{
end
=
skip
(
end
);
if
(
*
end
)
{
cJSON_Delete
(
c
);
ep
=
end
;
errno
=
EINVAL
;
if
(
r_erroff
)
*
r_erroff
=
ep
-
value
;
return
0
;
}
}
if
(
return_parse_end
)
*
return_parse_end
=
end
;
return
c
;
}
/* Default options for cJSON_Parse */
cJSON
*
cJSON_Parse
(
const
char
*
value
,
size_t
*
r_erroff
)
{
return
cJSON_ParseWithOpts
(
value
,
0
,
0
,
r_erroff
);
}
/* Render a cJSON item/entity/structure to text. */
char
*
cJSON_Print
(
cJSON
*
item
)
{
return
print_value
(
item
,
0
,
1
);
}
char
*
cJSON_PrintUnformatted
(
cJSON
*
item
)
{
return
print_value
(
item
,
0
,
0
);
}
/* Parser core - when encountering text, process appropriately. */
static
const
char
*
parse_value
(
cJSON
*
item
,
const
char
*
value
,
const
char
**
ep
,
size_t
depth
)
{
if
(
depth
>
MAX_DEPTH
)
{
*
ep
=
value
;
return
0
;
}
if
(
!
value
)
return
0
;
/* Fail on null. */
if
(
!
strncmp
(
value
,
"null"
,
4
))
{
item
->
type
=
cJSON_NULL
;
return
value
+
4
;
}
if
(
!
strncmp
(
value
,
"false"
,
5
))
{
item
->
type
=
cJSON_False
;
return
value
+
5
;
}
if
(
!
strncmp
(
value
,
"true"
,
4
))
{
item
->
type
=
cJSON_True
;
item
->
valueint
=
1
;
return
value
+
4
;
}
if
(
*
value
==
'\"'
)
{
return
parse_string
(
item
,
value
,
ep
);
}
if
(
*
value
==
'-'
||
(
*
value
>=
'0'
&&
*
value
<=
'9'
))
{
return
parse_number
(
item
,
value
);
}
if
(
*
value
==
'['
)
{
return
parse_array
(
item
,
value
,
ep
,
depth
+
1
);
}
if
(
*
value
==
'{'
)
{
return
parse_object
(
item
,
value
,
ep
,
depth
+
1
);
}
*
ep
=
value
;
return
0
;
/* failure. */
}
/* Render a value to text. */
static
char
*
print_value
(
cJSON
*
item
,
int
depth
,
int
fmt
)
{
char
*
out
=
0
;
if
(
!
item
)
return
0
;
switch
((
item
->
type
)
&
255
)
{
case
cJSON_NULL
:
out
=
xtrystrdup
(
"null"
);
break
;
case
cJSON_False
:
out
=
xtrystrdup
(
"false"
);
break
;
case
cJSON_True
:
out
=
xtrystrdup
(
"true"
);
break
;
case
cJSON_Number
:
out
=
print_number
(
item
);
break
;
case
cJSON_String
:
out
=
print_string
(
item
);
break
;
case
cJSON_Array
:
out
=
print_array
(
item
,
depth
,
fmt
);
break
;
case
cJSON_Object
:
out
=
print_object
(
item
,
depth
,
fmt
);
break
;
}
return
out
;
}
/* Build an array from input text. */
static
const
char
*
parse_array
(
cJSON
*
item
,
const
char
*
value
,
const
char
**
ep
,
size_t
depth
)
{
cJSON
*
child
;
if
(
depth
>
MAX_DEPTH
)
{
*
ep
=
value
;
return
0
;
}
if
(
*
value
!=
'['
)
{
*
ep
=
value
;
return
0
;
}
/* not an array! */
item
->
type
=
cJSON_Array
;
value
=
skip
(
value
+
1
);
if
(
*
value
==
']'
)
return
value
+
1
;
/* empty array. */
item
->
child
=
child
=
cJSON_New_Item
();
if
(
!
item
->
child
)
return
0
;
/* memory fail */
/* skip any spacing, get the value. */
value
=
skip
(
parse_value
(
child
,
skip
(
value
),
ep
,
depth
+
1
));
if
(
!
value
)
return
0
;
while
(
*
value
==
','
)
{
cJSON
*
new_item
;
if
(
!
(
new_item
=
cJSON_New_Item
()))
return
0
;
/* memory fail */
child
->
next
=
new_item
;
new_item
->
prev
=
child
;
child
=
new_item
;
value
=
skip
(
parse_value
(
child
,
skip
(
value
+
1
),
ep
,
depth
+
1
));
if
(
!
value
)
return
0
;
/* memory fail */
}
if
(
*
value
==
']'
)
return
value
+
1
;
/* end of array */
*
ep
=
value
;
return
0
;
/* malformed. */
}
/* Render an array to text */
static
char
*
print_array
(
cJSON
*
item
,
int
depth
,
int
fmt
)
{
char
**
entries
;
char
*
out
=
0
,
*
ptr
,
*
ret
;
int
len
=
5
;
cJSON
*
child
=
item
->
child
;
int
numentries
=
0
,
i
=
0
,
fail
=
0
;
/* How many entries in the array? */
while
(
child
)
numentries
++
,
child
=
child
->
next
;
/* Explicitly handle numentries==0 */
if
(
!
numentries
)
{
out
=
xtrymalloc
(
3
);
if
(
out
)
strcpy
(
out
,
"[]"
);
return
out
;
}
/* Allocate an array to hold the values for each */
entries
=
xtrymalloc
(
numentries
*
sizeof
(
char
*
));
if
(
!
entries
)
return
0
;
memset
(
entries
,
0
,
numentries
*
sizeof
(
char
*
));
/* Retrieve all the results: */
child
=
item
->
child
;
while
(
child
&&
!
fail
)
{
ret
=
print_value
(
child
,
depth
+
1
,
fmt
);
entries
[
i
++
]
=
ret
;
if
(
ret
)
len
+=
strlen
(
ret
)
+
2
+
(
fmt
?
1
:
0
);
else
fail
=
1
;
child
=
child
->
next
;
}
/* If we didn't fail, try to xtrymalloc the output string */
if
(
!
fail
)
out
=
xtrymalloc
(
len
);
/* If that fails, we fail. */
if
(
!
out
)
fail
=
1
;
/* Handle failure. */
if
(
fail
)
{
for
(
i
=
0
;
i
<
numentries
;
i
++
)
if
(
entries
[
i
])
xfree
(
entries
[
i
]);
xfree
(
entries
);
return
0
;
}
/* Compose the output array. */
*
out
=
'['
;
ptr
=
out
+
1
;
*
ptr
=
0
;
for
(
i
=
0
;
i
<
numentries
;
i
++
)
{
strcpy
(
ptr
,
entries
[
i
]);
ptr
+=
strlen
(
entries
[
i
]);
if
(
i
!=
numentries
-
1
)
{
*
ptr
++
=
','
;
if
(
fmt
)
*
ptr
++
=
' '
;
*
ptr
=
0
;
}
xfree
(
entries
[
i
]);
}
xfree
(
entries
);
*
ptr
++
=
']'
;
*
ptr
++
=
0
;
return
out
;
}
/* Build an object from the text. */
static
const
char
*
parse_object
(
cJSON
*
item
,
const
char
*
value
,
const
char
**
ep
,
size_t
depth
)
{
cJSON
*
child
;
if
(
depth
>
MAX_DEPTH
)
{
*
ep
=
value
;
return
0
;
}
if
(
*
value
!=
'{'
)
{
*
ep
=
value
;
return
0
;
}
/* not an object! */
item
->
type
=
cJSON_Object
;
value
=
skip
(
value
+
1
);
if
(
*
value
==
'}'
)
return
value
+
1
;
/* empty array. */
item
->
child
=
child
=
cJSON_New_Item
();
if
(
!
item
->
child
)
return
0
;
value
=
skip
(
parse_string
(
child
,
skip
(
value
),
ep
));
if
(
!
value
)
return
0
;
child
->
string
=
child
->
valuestring
;
child
->
valuestring
=
0
;
if
(
*
value
!=
':'
)
{
*
ep
=
value
;
return
0
;
}
/* fail! */
/* skip any spacing, get the value. */
value
=
skip
(
parse_value
(
child
,
skip
(
value
+
1
),
ep
,
depth
+
1
));
if
(
!
value
)
return
0
;
while
(
*
value
==
','
)
{
cJSON
*
new_item
;
if
(
!
(
new_item
=
cJSON_New_Item
()))
return
0
;
/* memory fail */
child
->
next
=
new_item
;
new_item
->
prev
=
child
;
child
=
new_item
;
value
=
skip
(
parse_string
(
child
,
skip
(
value
+
1
),
ep
));
if
(
!
value
)
return
0
;
child
->
string
=
child
->
valuestring
;
child
->
valuestring
=
0
;
if
(
*
value
!=
':'
)
{
*
ep
=
value
;
return
0
;
}
/* fail! */
/* skip any spacing, get the value. */
value
=
skip
(
parse_value
(
child
,
skip
(
value
+
1
),
ep
,
depth
+
1
));
if
(
!
value
)
return
0
;
}
if
(
*
value
==
'}'
)
return
value
+
1
;
/* end of array */
*
ep
=
value
;
return
0
;
/* malformed. */
}
/* Render an object to text. */
static
char
*
print_object
(
cJSON
*
item
,
int
depth
,
int
fmt
)
{
char
**
entries
=
0
,
**
names
=
0
;
char
*
out
=
0
,
*
ptr
,
*
ret
,
*
str
;
int
len
=
7
,
i
=
0
,
j
;
cJSON
*
child
=
item
->
child
;
int
numentries
=
0
,
fail
=
0
;
/* Count the number of entries. */
while
(
child
)
numentries
++
,
child
=
child
->
next
;
/* Explicitly handle empty object case */
if
(
!
numentries
)
{
out
=
xtrymalloc
(
fmt
?
depth
+
4
:
3
);
if
(
!
out
)
return
0
;
ptr
=
out
;
*
ptr
++
=
'{'
;
if
(
fmt
)
{
*
ptr
++
=
'\n'
;
for
(
i
=
0
;
i
<
depth
-
1
;
i
++
)
*
ptr
++
=
'\t'
;
}
*
ptr
++
=
'}'
;
*
ptr
++
=
0
;
return
out
;
}
/* Allocate space for the names and the objects */
entries
=
xtrymalloc
(
numentries
*
sizeof
(
char
*
));
if
(
!
entries
)
return
0
;
names
=
xtrymalloc
(
numentries
*
sizeof
(
char
*
));
if
(
!
names
)
{
xfree
(
entries
);
return
0
;
}
memset
(
entries
,
0
,
sizeof
(
char
*
)
*
numentries
);
memset
(
names
,
0
,
sizeof
(
char
*
)
*
numentries
);
/* Collect all the results into our arrays: */
child
=
item
->
child
;
depth
++
;
if
(
fmt
)
len
+=
depth
;
while
(
child
)
{
names
[
i
]
=
str
=
print_string_ptr
(
child
->
string
);
entries
[
i
++
]
=
ret
=
print_value
(
child
,
depth
,
fmt
);
if
(
str
&&
ret
)
len
+=
strlen
(
ret
)
+
strlen
(
str
)
+
2
+
(
fmt
?
2
+
depth
:
0
);
else
fail
=
1
;
child
=
child
->
next
;
}
/* Try to allocate the output string */
if
(
!
fail
)
out
=
xtrymalloc
(
len
);
if
(
!
out
)
fail
=
1
;
/* Handle failure */
if
(
fail
)
{
for
(
i
=
0
;
i
<
numentries
;
i
++
)
{
if
(
names
[
i
])
xfree
(
names
[
i
]);
if
(
entries
[
i
])
xfree
(
entries
[
i
]);
}
xfree
(
names
);
xfree
(
entries
);
return
0
;
}
/* Compose the output: */
*
out
=
'{'
;
ptr
=
out
+
1
;
if
(
fmt
)
*
ptr
++
=
'\n'
;
*
ptr
=
0
;
for
(
i
=
0
;
i
<
numentries
;
i
++
)
{
if
(
fmt
)
for
(
j
=
0
;
j
<
depth
;
j
++
)
*
ptr
++
=
'\t'
;
strcpy
(
ptr
,
names
[
i
]);
ptr
+=
strlen
(
names
[
i
]);
*
ptr
++
=
':'
;
if
(
fmt
)
*
ptr
++
=
'\t'
;
strcpy
(
ptr
,
entries
[
i
]);
ptr
+=
strlen
(
entries
[
i
]);
if
(
i
!=
numentries
-
1
)
*
ptr
++
=
','
;
if
(
fmt
)
*
ptr
++
=
'\n'
;
*
ptr
=
0
;
xfree
(
names
[
i
]);
xfree
(
entries
[
i
]);
}
xfree
(
names
);
xfree
(
entries
);
if
(
fmt
)
for
(
i
=
0
;
i
<
depth
-
1
;
i
++
)
*
ptr
++
=
'\t'
;
*
ptr
++
=
'}'
;
*
ptr
++
=
0
;
return
out
;
}
/* Get Array size/item / object item. */
int
cJSON_GetArraySize
(
cJSON
*
array
)
{
cJSON
*
c
=
array
->
child
;
int
i
=
0
;
while
(
c
)
i
++
,
c
=
c
->
next
;
return
i
;
}
cJSON
*
cJSON_GetArrayItem
(
cJSON
*
array
,
int
item
)
{
cJSON
*
c
=
array
->
child
;
while
(
c
&&
item
>
0
)
item
--
,
c
=
c
->
next
;
return
c
;
}
cJSON
*
cJSON_GetObjectItem
(
cJSON
*
object
,
const
char
*
string
)
{
cJSON
*
c
=
object
->
child
;
while
(
c
&&
cJSON_strcasecmp
(
c
->
string
,
string
))
c
=
c
->
next
;
return
c
;
}
/* Utility for array list handling. */
static
void
suffix_object
(
cJSON
*
prev
,
cJSON
*
item
)
{
prev
->
next
=
item
;
item
->
prev
=
prev
;
}
/* Utility for handling references. */
static
cJSON
*
create_reference
(
cJSON
*
item
)
{
cJSON
*
ref
=
cJSON_New_Item
();
if
(
!
ref
)
return
0
;
memcpy
(
ref
,
item
,
sizeof
(
cJSON
));
ref
->
string
=
0
;
ref
->
type
|=
cJSON_IsReference
;
ref
->
next
=
ref
->
prev
=
0
;
return
ref
;
}
/* Add item to array/object. */
void
cJSON_AddItemToArray
(
cJSON
*
array
,
cJSON
*
item
)
{
cJSON
*
c
;
if
(
!
item
||
!
array
)
return
;
c
=
array
->
child
;
if
(
!
c
)
{
array
->
child
=
item
;
}
else
{
while
(
c
&&
c
->
next
)
c
=
c
->
next
;
suffix_object
(
c
,
item
);
}
}
cJSON
*
cJSON_AddItemToObject
(
cJSON
*
object
,
const
char
*
string
,
cJSON
*
item
)
{
char
*
tmp
;
if
(
!
item
)
return
0
;
tmp
=
xtrystrdup
(
string
);
if
(
!
tmp
)
return
NULL
;
if
(
item
->
string
)
xfree
(
item
->
string
);
item
->
string
=
tmp
;
cJSON_AddItemToArray
(
object
,
item
);
return
object
;
}
cJSON
*
cJSON_AddNullToObject
(
cJSON
*
object
,
const
char
*
name
)
{
cJSON
*
obj
,
*
tmp
;
tmp
=
cJSON_CreateNull
();
if
(
!
tmp
)
return
NULL
;
obj
=
cJSON_AddItemToObject
(
object
,
name
,
tmp
);
if
(
!
obj
)
cJSON_Delete
(
tmp
);
return
obj
;
}
cJSON
*
cJSON_AddTrueToObject
(
cJSON
*
object
,
const
char
*
name
)
{
cJSON
*
obj
,
*
tmp
;
tmp
=
cJSON_CreateTrue
();
if
(
!
tmp
)
return
NULL
;
obj
=
cJSON_AddItemToObject
(
object
,
name
,
tmp
);
if
(
!
obj
)
cJSON_Delete
(
tmp
);
return
obj
;
}
cJSON
*
cJSON_AddFalseToObject
(
cJSON
*
object
,
const
char
*
name
)
{
cJSON
*
obj
,
*
tmp
;
tmp
=
cJSON_CreateFalse
();
if
(
!
tmp
)
return
NULL
;
obj
=
cJSON_AddItemToObject
(
object
,
name
,
tmp
);
if
(
!
obj
)
cJSON_Delete
(
tmp
);
return
obj
;
}
cJSON
*
cJSON_AddBoolToObject
(
cJSON
*
object
,
const
char
*
name
,
int
b
)
{
cJSON
*
obj
,
*
tmp
;
tmp
=
cJSON_CreateBool
(
b
);
if
(
!
tmp
)
return
NULL
;
obj
=
cJSON_AddItemToObject
(
object
,
name
,
tmp
);
if
(
!
obj
)
cJSON_Delete
(
tmp
);
return
obj
;
}
cJSON
*
cJSON_AddNumberToObject
(
cJSON
*
object
,
const
char
*
name
,
double
num
)
{
cJSON
*
obj
,
*
tmp
;
tmp
=
cJSON_CreateNumber
(
num
);
if
(
!
tmp
)
return
NULL
;
obj
=
cJSON_AddItemToObject
(
object
,
name
,
tmp
);
if
(
!
obj
)
cJSON_Delete
(
tmp
);
return
obj
;
}
cJSON
*
cJSON_AddStringToObject
(
cJSON
*
object
,
const
char
*
name
,
const
char
*
string
)
{
cJSON
*
obj
,
*
tmp
;
tmp
=
cJSON_CreateString
(
string
);
if
(
!
tmp
)
return
NULL
;
obj
=
cJSON_AddItemToObject
(
object
,
name
,
tmp
);
if
(
!
obj
)
cJSON_Delete
(
tmp
);
return
obj
;
}
void
cJSON_AddItemReferenceToArray
(
cJSON
*
array
,
cJSON
*
item
)
{
cJSON_AddItemToArray
(
array
,
create_reference
(
item
));
}
void
cJSON_AddItemReferenceToObject
(
cJSON
*
object
,
const
char
*
string
,
cJSON
*
item
)
{
cJSON_AddItemToObject
(
object
,
string
,
create_reference
(
item
));
}
cJSON
*
cJSON_DetachItemFromArray
(
cJSON
*
array
,
int
which
)
{
cJSON
*
c
=
array
->
child
;
while
(
c
&&
which
>
0
)
c
=
c
->
next
,
which
--
;
if
(
!
c
)
return
0
;
if
(
c
->
prev
)
c
->
prev
->
next
=
c
->
next
;
if
(
c
->
next
)
c
->
next
->
prev
=
c
->
prev
;
if
(
c
==
array
->
child
)
array
->
child
=
c
->
next
;
c
->
prev
=
c
->
next
=
0
;
return
c
;
}
void
cJSON_DeleteItemFromArray
(
cJSON
*
array
,
int
which
)
{
cJSON_Delete
(
cJSON_DetachItemFromArray
(
array
,
which
));
}
cJSON
*
cJSON_DetachItemFromObject
(
cJSON
*
object
,
const
char
*
string
)
{
int
i
=
0
;
cJSON
*
c
=
object
->
child
;
while
(
c
&&
cJSON_strcasecmp
(
c
->
string
,
string
))
i
++
,
c
=
c
->
next
;
if
(
c
)
return
cJSON_DetachItemFromArray
(
object
,
i
);
return
0
;
}
void
cJSON_DeleteItemFromObject
(
cJSON
*
object
,
const
char
*
string
)
{
cJSON_Delete
(
cJSON_DetachItemFromObject
(
object
,
string
));
}
/* Replace array/object items with new ones. */
void
cJSON_ReplaceItemInArray
(
cJSON
*
array
,
int
which
,
cJSON
*
newitem
)
{
cJSON
*
c
=
array
->
child
;
while
(
c
&&
which
>
0
)
c
=
c
->
next
,
which
--
;
if
(
!
c
)
return
;
newitem
->
next
=
c
->
next
;
newitem
->
prev
=
c
->
prev
;
if
(
newitem
->
next
)
newitem
->
next
->
prev
=
newitem
;
if
(
c
==
array
->
child
)
array
->
child
=
newitem
;
else
newitem
->
prev
->
next
=
newitem
;
c
->
next
=
c
->
prev
=
0
;
cJSON_Delete
(
c
);
}
void
cJSON_ReplaceItemInObject
(
cJSON
*
object
,
const
char
*
string
,
cJSON
*
newitem
)
{
int
i
=
0
;
cJSON
*
c
=
object
->
child
;
while
(
c
&&
cJSON_strcasecmp
(
c
->
string
,
string
))
i
++
,
c
=
c
->
next
;
if
(
c
)
{
/* FIXME: I guess we should free newitem->string here. See
* upstream commit 0d10e279c8b604f71829b5d49d092719f4ae96b6. */
newitem
->
string
=
xtrystrdup
(
string
);
cJSON_ReplaceItemInArray
(
object
,
i
,
newitem
);
}
}
/* Create basic types: */
cJSON
*
cJSON_CreateNull
(
void
)
{
cJSON
*
item
=
cJSON_New_Item
();
if
(
item
)
item
->
type
=
cJSON_NULL
;
return
item
;
}
cJSON
*
cJSON_CreateTrue
(
void
)
{
cJSON
*
item
=
cJSON_New_Item
();
if
(
item
)
item
->
type
=
cJSON_True
;
return
item
;
}
cJSON
*
cJSON_CreateFalse
(
void
)
{
cJSON
*
item
=
cJSON_New_Item
();
if
(
item
)
item
->
type
=
cJSON_False
;
return
item
;
}
cJSON
*
cJSON_CreateBool
(
int
b
)
{
cJSON
*
item
=
cJSON_New_Item
();
if
(
item
)
item
->
type
=
b
?
cJSON_True
:
cJSON_False
;
return
item
;
}
cJSON
*
cJSON_CreateNumber
(
double
num
)
{
cJSON
*
item
=
cJSON_New_Item
();
if
(
item
)
{
item
->
type
=
cJSON_Number
;
item
->
valuedouble
=
num
;
item
->
valueint
=
(
int
)
num
;
}
return
item
;
}
cJSON
*
cJSON_CreateString
(
const
char
*
string
)
{
cJSON
*
item
=
cJSON_New_Item
();
if
(
item
)
{
item
->
type
=
cJSON_String
;
item
->
valuestring
=
xtrystrdup
(
string
);
}
return
item
;
}
cJSON
*
cJSON_CreateStringConvey
(
char
*
string
)
{
cJSON
*
item
=
cJSON_New_Item
();
if
(
item
)
{
item
->
type
=
cJSON_String
;
item
->
valuestring
=
string
;
}
return
item
;
}
cJSON
*
cJSON_CreateArray
(
void
)
{
cJSON
*
item
=
cJSON_New_Item
();
if
(
item
)
item
->
type
=
cJSON_Array
;
return
item
;
}
cJSON
*
cJSON_CreateObject
(
void
)
{
cJSON
*
item
=
cJSON_New_Item
();
if
(
item
)
item
->
type
=
cJSON_Object
;
return
item
;
}
/* Create Arrays: */
cJSON
*
cJSON_CreateIntArray
(
const
int
*
numbers
,
int
count
)
{
int
i
;
cJSON
*
n
=
0
,
*
p
=
0
,
*
a
=
cJSON_CreateArray
();
for
(
i
=
0
;
a
&&
i
<
count
;
i
++
)
{
n
=
cJSON_CreateNumber
(
numbers
[
i
]);
if
(
!
i
)
a
->
child
=
n
;
else
suffix_object
(
p
,
n
);
p
=
n
;
}
return
a
;
}
cJSON
*
cJSON_CreateFloatArray
(
const
float
*
numbers
,
int
count
)
{
int
i
;
cJSON
*
n
=
0
,
*
p
=
0
,
*
a
=
cJSON_CreateArray
();
for
(
i
=
0
;
a
&&
i
<
count
;
i
++
)
{
n
=
cJSON_CreateNumber
(
numbers
[
i
]);
if
(
!
i
)
a
->
child
=
n
;
else
suffix_object
(
p
,
n
);
p
=
n
;
}
return
a
;
}
cJSON
*
cJSON_CreateDoubleArray
(
const
double
*
numbers
,
int
count
)
{
int
i
;
cJSON
*
n
=
0
,
*
p
=
0
,
*
a
=
cJSON_CreateArray
();
for
(
i
=
0
;
a
&&
i
<
count
;
i
++
)
{
n
=
cJSON_CreateNumber
(
numbers
[
i
]);
if
(
!
i
)
a
->
child
=
n
;
else
suffix_object
(
p
,
n
);
p
=
n
;
}
return
a
;
}
cJSON
*
cJSON_CreateStringArray
(
const
char
**
strings
,
int
count
)
{
int
i
;
cJSON
*
n
=
0
,
*
p
=
0
,
*
a
=
cJSON_CreateArray
();
for
(
i
=
0
;
a
&&
i
<
count
;
i
++
)
{
n
=
cJSON_CreateString
(
strings
[
i
]);
if
(
!
i
)
a
->
child
=
n
;
else
suffix_object
(
p
,
n
);
p
=
n
;
}
return
a
;
}
/* Duplication */
cJSON
*
cJSON_Duplicate
(
cJSON
*
item
,
int
recurse
)
{
cJSON
*
newitem
,
*
cptr
,
*
nptr
=
0
,
*
newchild
;
/* Bail on bad ptr */
if
(
!
item
)
return
0
;
/* Create new item */
newitem
=
cJSON_New_Item
();
if
(
!
newitem
)
return
0
;
/* Copy over all vars */
newitem
->
type
=
item
->
type
&
(
~
cJSON_IsReference
),
newitem
->
valueint
=
item
->
valueint
,
newitem
->
valuedouble
=
item
->
valuedouble
;
if
(
item
->
valuestring
)
{
newitem
->
valuestring
=
xtrystrdup
(
item
->
valuestring
);
if
(
!
newitem
->
valuestring
)
{
cJSON_Delete
(
newitem
);
return
0
;
}
}
if
(
item
->
string
)
{
newitem
->
string
=
xtrystrdup
(
item
->
string
);
if
(
!
newitem
->
string
)
{
cJSON_Delete
(
newitem
);
return
0
;
}
}
/* If non-recursive, then we're done! */
if
(
!
recurse
)
return
newitem
;
/* Walk the ->next chain for the child. */
cptr
=
item
->
child
;
while
(
cptr
)
{
/* Duplicate (with recurse) each item in the ->next chain */
newchild
=
cJSON_Duplicate
(
cptr
,
1
);
if
(
!
newchild
)
{
cJSON_Delete
(
newitem
);
return
0
;
}
if
(
nptr
)
{
/* If newitem->child already set,
* then crosswire ->prev and ->next and move on. */
nptr
->
next
=
newchild
,
newchild
->
prev
=
nptr
;
nptr
=
newchild
;
}
else
{
/* Set newitem->child and move to it. */
newitem
->
child
=
newchild
;
nptr
=
newchild
;
}
cptr
=
cptr
->
next
;
}
return
newitem
;
}
void
cJSON_Minify
(
char
*
json
)
{
char
*
into
=
json
;
while
(
*
json
)
{
if
(
*
json
==
' '
)
json
++
;
else
if
(
*
json
==
'\t'
)
json
++
;
/* Whitespace characters. */
else
if
(
*
json
==
'\r'
)
json
++
;
else
if
(
*
json
==
'\n'
)
json
++
;
else
if
(
*
json
==
'/'
&&
json
[
1
]
==
'/'
)
while
(
*
json
&&
*
json
!=
'\n'
)
json
++
;
/* Double-slash comments, to end of line. */
else
if
(
*
json
==
'/'
&&
json
[
1
]
==
'*'
)
{
while
(
*
json
&&
!
(
*
json
==
'*'
&&
json
[
1
]
==
'/'
))
json
++
;
json
+=
2
;
}
/* Multiline comments. */
else
if
(
*
json
==
'\"'
)
{
*
into
++
=
*
json
++
;
while
(
*
json
&&
*
json
!=
'\"'
)
{
if
(
*
json
==
'\\'
)
*
into
++
=
*
json
++
;
if
(
*
json
)
*
into
++
=
*
json
++
;
}
if
(
*
json
)
*
into
++
=
*
json
++
;
}
/* String literals, which are \" sensitive. */
else
*
into
++
=
*
json
++
;
/* All other characters. */
}
*
into
=
0
;
/* and null-terminate. */
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Fri, Mar 14, 4:43 AM (1 d, 15 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
1d/e7/04884f5bc00adb2ff65a34786880
Attached To
rM GPGME
Event Timeline
Log In to Comment