about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2017-09-16 16:11:15 -0400
committerKelly Rauchenberger <fefferburbia@gmail.com>2017-09-16 16:11:15 -0400
commit4fe95cc1e7412e309d026e53cd44239bd3ef031d (patch)
treec1b711ed5a81976d9054da6205f5f9b2c3133248
parente2a76d1f0fd978f285edf1dbc0f6e87cf89c63ce (diff)
downloadgen3uploader-4fe95cc1e7412e309d026e53cd44239bd3ef031d.tar.gz
gen3uploader-4fe95cc1e7412e309d026e53cd44239bd3ef031d.tar.bz2
gen3uploader-4fe95cc1e7412e309d026e53cd44239bd3ef031d.zip
Wii can now send a POST request to a website
The extractor now uses libfat to read a config file off the root of the
SD card, a model for which is included in the repository. The extractor
is capable of negotiating an HTTPS connection, but it requires a
download of the target site's root CA certificate to be on the SD card
and pointed at by the config file. TLS/SSL functionality is provided by
wolfSSL. I had to make a couple of minor changes to wolfSSL for it to
work properly, and those changes are located in the devkitpro branch of
my fork, hatkirby/wolfssl.

The Wii program now arranges some of the information that the GBA sends
it into a JSON object, which is then sent off (along with some
authentication information from the config file) to the endpoint defined
in the config file. The code used to maintain the network connection is
from the WiiTweet project, which was licensed under the GPL. Some of the
code used to send the HTTP request also comes from said project.
-rw-r--r--.gitignore2
-rw-r--r--Makefile.wii6
-rw-r--r--README.md17
-rw-r--r--gen3uploader.cfg6
-rw-r--r--source/cJSON.c2701
-rw-r--r--source/cJSON.h263
-rw-r--r--source/http.c359
-rw-r--r--source/http.h37
-rw-r--r--source/main.c244
-rw-r--r--source/netinf.c161
-rw-r--r--source/netinf.h16
-rw-r--r--vendor/include/.gitkeep0
-rw-r--r--vendor/lib/.gitkeep0
13 files changed, 3793 insertions, 19 deletions
diff --git a/.gitignore b/.gitignore index 9f62bc6..cfb6808 100644 --- a/.gitignore +++ b/.gitignore
@@ -6,3 +6,5 @@ tags
6*.o 6*.o
7*.d 7*.d
8*.swp 8*.swp
9*.swo
10.DS_Store
diff --git a/Makefile.wii b/Makefile.wii index 8e2f2c8..60d072e 100644 --- a/Makefile.wii +++ b/Makefile.wii
@@ -19,7 +19,7 @@ TARGET := gen3uploader_wii
19BUILD := build 19BUILD := build
20SOURCES := source 20SOURCES := source
21DATA := data 21DATA := data
22INCLUDES := source include 22INCLUDES := source include vendor/include
23 23
24#--------------------------------------------------------------------------------- 24#---------------------------------------------------------------------------------
25# options for code generation 25# options for code generation
@@ -33,14 +33,14 @@ LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map
33#--------------------------------------------------------------------------------- 33#---------------------------------------------------------------------------------
34# any extra libraries we wish to link with the project 34# any extra libraries we wish to link with the project
35#--------------------------------------------------------------------------------- 35#---------------------------------------------------------------------------------
36LIBS := -logc 36LIBS := -lfat -logc -lwolfssl -lm
37 37
38 38
39#--------------------------------------------------------------------------------- 39#---------------------------------------------------------------------------------
40# list of directories containing libraries, this must be the top level containing 40# list of directories containing libraries, this must be the top level containing
41# include and lib 41# include and lib
42#--------------------------------------------------------------------------------- 42#---------------------------------------------------------------------------------
43LIBDIRS := $(DEVKITPPC)/lib $(CURDIR) 43LIBDIRS := $(DEVKITPPC)/lib $(CURDIR) $(CURDIR)/vendor
44 44
45#--------------------------------------------------------------------------------- 45#---------------------------------------------------------------------------------
46# no real need to edit anything past this point unless you need to add additional 46# no real need to edit anything past this point unless you need to add additional
diff --git a/README.md b/README.md index 2edfe2a..e263297 100644 --- a/README.md +++ b/README.md
@@ -7,7 +7,22 @@ The multiboot image that the Wii sends to the GBA is executed in the context of
7 7
8One of the main reasons that I chose to use this method to extract save data from my GBA games is that I'm very concerned about the "legitimacy" of my Pokémon experience. I don't want to be able to do anything with my saves that could be considered cheating. Thus, the multiboot image only sends to the Wii information that is publicly visible using the game's interface. For instance, the Wii never receives a Pokémon's IVs, EVs, or full personality value. The GBA multiboot image derives all the necessary information (stats, Nature, gender, shininess, Unown letter, etc) from those values, and then sends that over the connection. In this way, this private information never leaves the context of the GBA's code. 8One of the main reasons that I chose to use this method to extract save data from my GBA games is that I'm very concerned about the "legitimacy" of my Pokémon experience. I don't want to be able to do anything with my saves that could be considered cheating. Thus, the multiboot image only sends to the Wii information that is publicly visible using the game's interface. For instance, the Wii never receives a Pokémon's IVs, EVs, or full personality value. The GBA multiboot image derives all the necessary information (stats, Nature, gender, shininess, Unown letter, etc) from those values, and then sends that over the connection. In this way, this private information never leaves the context of the GBA's code.
9 9
10This project is still in active development, and currently only displays debug information on the Wii's screen. No data is sent to a website yet. 10This project is still in active development, and is not yet ready to be used.
11
12# Compiling
13`gen3uploader` depends on wolfSSL in order to negotiate HTTPS connections. The main branch has a couple of minor problems that prevent it from working with this project right out of the box, so for now you should use the [devkitpro branch in hatkirby/wolfssl](/hatkirby/wolfssl/tree/devkitpro).
14
15In order to compile wolfSSL, first ensure your $DEVKITPPC environment variable is set. Then, assuming that $GEN3UPLOADER points to your `gen3uploader` repository, you can run the following commands:
16
17```bash
18./autogen.sh
19./configure --disable-shared CC=$DEVKITPPC/bin/powerpc-eabi-gcc --host=ppc --enable-singlethreaded RANLIB=$DEVKITPPC/bin/powerpc-eabi-gcc-ranlib CFLAGS="-DDEVKITPRO -DNO_WRITEV" --disable-examples --disable-crypttests
20make
21cp src/.libs/libwolfssl.a $GEN3UPLOADER/vendor/lib/
22cp -r wolfssl $GEN3UPLOADER/vendor/include/
23```
24
25From there, you should be able to run the `build.sh` script in the `gen3uploader` project to compile everything.
11 26
12# Usage 27# Usage
13Have a GC Controller in Port 1 and a GBA with Gen3 game in Port 2. Run the Wii program, and follow the instructions. The connection is not very stable, and it can take several tries for the program to run successfully. 28Have a GC Controller in Port 1 and a GBA with Gen3 game in Port 2. Run the Wii program, and follow the instructions. The connection is not very stable, and it can take several tries for the program to run successfully.
diff --git a/gen3uploader.cfg b/gen3uploader.cfg new file mode 100644 index 0000000..2d987d0 --- /dev/null +++ b/gen3uploader.cfg
@@ -0,0 +1,6 @@
1{
2 "url": "",
3 "username": "",
4 "password": "",
5 "certificate": ""
6} \ No newline at end of file
diff --git a/source/cJSON.c b/source/cJSON.c new file mode 100644 index 0000000..6e3d42b --- /dev/null +++ b/source/cJSON.c
@@ -0,0 +1,2701 @@
1/*
2 Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21*/
22
23/* cJSON */
24/* JSON parser in C. */
25
26#ifdef __GNUC__
27#pragma GCC visibility push(default)
28#endif
29
30#include <string.h>
31#include <stdio.h>
32#include <math.h>
33#include <stdlib.h>
34#include <float.h>
35#include <limits.h>
36#include <ctype.h>
37#include <locale.h>
38
39#ifdef __GNUC__
40#pragma GCC visibility pop
41#endif
42
43#include "cJSON.h"
44
45/* define our own boolean type */
46#define true ((cJSON_bool)1)
47#define false ((cJSON_bool)0)
48
49typedef struct {
50 const unsigned char *json;
51 size_t position;
52} error;
53static error global_error = { NULL, 0 };
54
55CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void)
56{
57 return (const char*) (global_error.json + global_error.position);
58}
59
60/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
61#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 5) || (CJSON_VERSION_PATCH != 7)
62 #error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
63#endif
64
65CJSON_PUBLIC(const char*) cJSON_Version(void)
66{
67 static char version[15];
68 sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH);
69
70 return version;
71}
72
73/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */
74static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2)
75{
76 if ((string1 == NULL) || (string2 == NULL))
77 {
78 return 1;
79 }
80
81 if (string1 == string2)
82 {
83 return 0;
84 }
85
86 for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++)
87 {
88 if (*string1 == '\0')
89 {
90 return 0;
91 }
92 }
93
94 return tolower(*string1) - tolower(*string2);
95}
96
97typedef struct internal_hooks
98{
99 void *(*allocate)(size_t size);
100 void (*deallocate)(void *pointer);
101 void *(*reallocate)(void *pointer, size_t size);
102} internal_hooks;
103
104static internal_hooks global_hooks = { malloc, free, realloc };
105
106static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks)
107{
108 size_t length = 0;
109 unsigned char *copy = NULL;
110
111 if (string == NULL)
112 {
113 return NULL;
114 }
115
116 length = strlen((const char*)string) + sizeof("");
117 if (!(copy = (unsigned char*)hooks->allocate(length)))
118 {
119 return NULL;
120 }
121 memcpy(copy, string, length);
122
123 return copy;
124}
125
126CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks)
127{
128 if (hooks == NULL)
129 {
130 /* Reset hooks */
131 global_hooks.allocate = malloc;
132 global_hooks.deallocate = free;
133 global_hooks.reallocate = realloc;
134 return;
135 }
136
137 global_hooks.allocate = malloc;
138 if (hooks->malloc_fn != NULL)
139 {
140 global_hooks.allocate = hooks->malloc_fn;
141 }
142
143 global_hooks.deallocate = free;
144 if (hooks->free_fn != NULL)
145 {
146 global_hooks.deallocate = hooks->free_fn;
147 }
148
149 /* use realloc only if both free and malloc are used */
150 global_hooks.reallocate = NULL;
151 if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free))
152 {
153 global_hooks.reallocate = realloc;
154 }
155}
156
157/* Internal constructor. */
158static cJSON *cJSON_New_Item(const internal_hooks * const hooks)
159{
160 cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON));
161 if (node)
162 {
163 memset(node, '\0', sizeof(cJSON));
164 }
165
166 return node;
167}
168
169/* Delete a cJSON structure. */
170CJSON_PUBLIC(void) cJSON_Delete(cJSON *item)
171{
172 cJSON *next = NULL;
173 while (item != NULL)
174 {
175 next = item->next;
176 if (!(item->type & cJSON_IsReference) && (item->child != NULL))
177 {
178 cJSON_Delete(item->child);
179 }
180 if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
181 {
182 global_hooks.deallocate(item->valuestring);
183 }
184 if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
185 {
186 global_hooks.deallocate(item->string);
187 }
188 global_hooks.deallocate(item);
189 item = next;
190 }
191}
192
193/* get the decimal point character of the current locale */
194static unsigned char get_decimal_point(void)
195{
196 struct lconv *lconv = localeconv();
197 return (unsigned char) lconv->decimal_point[0];
198}
199
200typedef struct
201{
202 const unsigned char *content;
203 size_t length;
204 size_t offset;
205 size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */
206 internal_hooks hooks;
207} parse_buffer;
208
209/* check if the given size is left to read in a given parse buffer (starting with 1) */
210#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))
211#define cannot_read(buffer, size) (!can_read(buffer, size))
212/* check if the buffer can be accessed at the given index (starting with 0) */
213#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
214#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
215/* get a pointer to the buffer at the position */
216#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
217
218/* Parse the input text to generate a number, and populate the result into item. */
219static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer)
220{
221 double number = 0;
222 unsigned char *after_end = NULL;
223 unsigned char number_c_string[64];
224 unsigned char decimal_point = get_decimal_point();
225 size_t i = 0;
226
227 if ((input_buffer == NULL) || (input_buffer->content == NULL))
228 {
229 return false;
230 }
231
232 /* copy the number into a temporary buffer and replace '.' with the decimal point
233 * of the current locale (for strtod)
234 * This also takes care of '\0' not necessarily being available for marking the end of the input */
235 for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++)
236 {
237 switch (buffer_at_offset(input_buffer)[i])
238 {
239 case '0':
240 case '1':
241 case '2':
242 case '3':
243 case '4':
244 case '5':
245 case '6':
246 case '7':
247 case '8':
248 case '9':
249 case '+':
250 case '-':
251 case 'e':
252 case 'E':
253 number_c_string[i] = buffer_at_offset(input_buffer)[i];
254 break;
255
256 case '.':
257 number_c_string[i] = decimal_point;
258 break;
259
260 default:
261 goto loop_end;
262 }
263 }
264loop_end:
265 number_c_string[i] = '\0';
266
267 number = strtod((const char*)number_c_string, (char**)&after_end);
268 if (number_c_string == after_end)
269 {
270 return false; /* parse_error */
271 }
272
273 item->valuedouble = number;
274
275 /* use saturation in case of overflow */
276 if (number >= INT_MAX)
277 {
278 item->valueint = INT_MAX;
279 }
280 else if (number <= INT_MIN)
281 {
282 item->valueint = INT_MIN;
283 }
284 else
285 {
286 item->valueint = (int)number;
287 }
288
289 item->type = cJSON_Number;
290
291 input_buffer->offset += (size_t)(after_end - number_c_string);
292 return true;
293}
294
295/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
296CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
297{
298 if (number >= INT_MAX)
299 {
300 object->valueint = INT_MAX;
301 }
302 else if (number <= INT_MIN)
303 {
304 object->valueint = INT_MIN;
305 }
306 else
307 {
308 object->valueint = (int)number;
309 }
310
311 return object->valuedouble = number;
312}
313
314typedef struct
315{
316 unsigned char *buffer;
317 size_t length;
318 size_t offset;
319 size_t depth; /* current nesting depth (for formatted printing) */
320 cJSON_bool noalloc;
321 cJSON_bool format; /* is this print a formatted print */
322 internal_hooks hooks;
323} printbuffer;
324
325/* realloc printbuffer if necessary to have at least "needed" bytes more */
326static unsigned char* ensure(printbuffer * const p, size_t needed)
327{
328 unsigned char *newbuffer = NULL;
329 size_t newsize = 0;
330
331 if ((p == NULL) || (p->buffer == NULL))
332 {
333 return NULL;
334 }
335
336 if ((p->length > 0) && (p->offset >= p->length))
337 {
338 /* make sure that offset is valid */
339 return NULL;
340 }
341
342 if (needed > INT_MAX)
343 {
344 /* sizes bigger than INT_MAX are currently not supported */
345 return NULL;
346 }
347
348 needed += p->offset + 1;
349 if (needed <= p->length)
350 {
351 return p->buffer + p->offset;
352 }
353
354 if (p->noalloc) {
355 return NULL;
356 }
357
358 /* calculate new buffer size */
359 if (needed > (INT_MAX / 2))
360 {
361 /* overflow of int, use INT_MAX if possible */
362 if (needed <= INT_MAX)
363 {
364 newsize = INT_MAX;
365 }
366 else
367 {
368 return NULL;
369 }
370 }
371 else
372 {
373 newsize = needed * 2;
374 }
375
376 if (p->hooks.reallocate != NULL)
377 {
378 /* reallocate with realloc if available */
379 newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize);
380 if (newbuffer == NULL)
381 {
382 p->hooks.deallocate(p->buffer);
383 p->length = 0;
384 p->buffer = NULL;
385
386 return NULL;
387 }
388 }
389 else
390 {
391 /* otherwise reallocate manually */
392 newbuffer = (unsigned char*)p->hooks.allocate(newsize);
393 if (!newbuffer)
394 {
395 p->hooks.deallocate(p->buffer);
396 p->length = 0;
397 p->buffer = NULL;
398
399 return NULL;
400 }
401 if (newbuffer)
402 {
403 memcpy(newbuffer, p->buffer, p->offset + 1);
404 }
405 p->hooks.deallocate(p->buffer);
406 }
407 p->length = newsize;
408 p->buffer = newbuffer;
409
410 return newbuffer + p->offset;
411}
412
413/* calculate the new length of the string in a printbuffer and update the offset */
414static void update_offset(printbuffer * const buffer)
415{
416 const unsigned char *buffer_pointer = NULL;
417 if ((buffer == NULL) || (buffer->buffer == NULL))
418 {
419 return;
420 }
421 buffer_pointer = buffer->buffer + buffer->offset;
422
423 buffer->offset += strlen((const char*)buffer_pointer);
424}
425
426/* Render the number nicely from the given item into a string. */
427static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
428{
429 unsigned char *output_pointer = NULL;
430 double d = item->valuedouble;
431 int length = 0;
432 size_t i = 0;
433 unsigned char number_buffer[26]; /* temporary buffer to print the number into */
434 unsigned char decimal_point = get_decimal_point();
435 double test;
436
437 if (output_buffer == NULL)
438 {
439 return false;
440 }
441
442 /* This checks for NaN and Infinity */
443 if ((d * 0) != 0)
444 {
445 length = sprintf((char*)number_buffer, "null");
446 }
447 else
448 {
449 /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
450 length = sprintf((char*)number_buffer, "%1.15g", d);
451
452 /* Check whether the original double can be recovered */
453 if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != d))
454 {
455 /* If not, print with 17 decimal places of precision */
456 length = sprintf((char*)number_buffer, "%1.17g", d);
457 }
458 }
459
460 /* sprintf failed or buffer overrun occured */
461 if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1)))
462 {
463 return false;
464 }
465
466 /* reserve appropriate space in the output */
467 output_pointer = ensure(output_buffer, (size_t)length);
468 if (output_pointer == NULL)
469 {
470 return false;
471 }
472
473 /* copy the printed number to the output and replace locale
474 * dependent decimal point with '.' */
475 for (i = 0; i < ((size_t)length); i++)
476 {
477 if (number_buffer[i] == decimal_point)
478 {
479 output_pointer[i] = '.';
480 continue;
481 }
482
483 output_pointer[i] = number_buffer[i];
484 }
485 output_pointer[i] = '\0';
486
487 output_buffer->offset += (size_t)length;
488
489 return true;
490}
491
492/* parse 4 digit hexadecimal number */
493static unsigned parse_hex4(const unsigned char * const input)
494{
495 unsigned int h = 0;
496 size_t i = 0;
497
498 for (i = 0; i < 4; i++)
499 {
500 /* parse digit */
501 if ((input[i] >= '0') && (input[i] <= '9'))
502 {
503 h += (unsigned int) input[i] - '0';
504 }
505 else if ((input[i] >= 'A') && (input[i] <= 'F'))
506 {
507 h += (unsigned int) 10 + input[i] - 'A';
508 }
509 else if ((input[i] >= 'a') && (input[i] <= 'f'))
510 {
511 h += (unsigned int) 10 + input[i] - 'a';
512 }
513 else /* invalid */
514 {
515 return 0;
516 }
517
518 if (i < 3)
519 {
520 /* shift left to make place for the next nibble */
521 h = h << 4;
522 }
523 }
524
525 return h;
526}
527
528/* converts a UTF-16 literal to UTF-8
529 * A literal can be one or two sequences of the form \uXXXX */
530static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer)
531{
532 long unsigned int codepoint = 0;
533 unsigned int first_code = 0;
534 const unsigned char *first_sequence = input_pointer;
535 unsigned char utf8_length = 0;
536 unsigned char utf8_position = 0;
537 unsigned char sequence_length = 0;
538 unsigned char first_byte_mark = 0;
539
540 if ((input_end - first_sequence) < 6)
541 {
542 /* input ends unexpectedly */
543 goto fail;
544 }
545
546 /* get the first utf16 sequence */
547 first_code = parse_hex4(first_sequence + 2);
548
549 /* check that the code is valid */
550 if (((first_code >= 0xDC00) && (first_code <= 0xDFFF)))
551 {
552 goto fail;
553 }
554
555 /* UTF16 surrogate pair */
556 if ((first_code >= 0xD800) && (first_code <= 0xDBFF))
557 {
558 const unsigned char *second_sequence = first_sequence + 6;
559 unsigned int second_code = 0;
560 sequence_length = 12; /* \uXXXX\uXXXX */
561
562 if ((input_end - second_sequence) < 6)
563 {
564 /* input ends unexpectedly */
565 goto fail;
566 }
567
568 if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u'))
569 {
570 /* missing second half of the surrogate pair */
571 goto fail;
572 }
573
574 /* get the second utf16 sequence */
575 second_code = parse_hex4(second_sequence + 2);
576 /* check that the code is valid */
577 if ((second_code < 0xDC00) || (second_code > 0xDFFF))
578 {
579 /* invalid second half of the surrogate pair */
580 goto fail;
581 }
582
583
584 /* calculate the unicode codepoint from the surrogate pair */
585 codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
586 }
587 else
588 {
589 sequence_length = 6; /* \uXXXX */
590 codepoint = first_code;
591 }
592
593 /* encode as UTF-8
594 * takes at maximum 4 bytes to encode:
595 * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
596 if (codepoint < 0x80)
597 {
598 /* normal ascii, encoding 0xxxxxxx */
599 utf8_length = 1;
600 }
601 else if (codepoint < 0x800)
602 {
603 /* two bytes, encoding 110xxxxx 10xxxxxx */
604 utf8_length = 2;
605 first_byte_mark = 0xC0; /* 11000000 */
606 }
607 else if (codepoint < 0x10000)
608 {
609 /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
610 utf8_length = 3;
611 first_byte_mark = 0xE0; /* 11100000 */
612 }
613 else if (codepoint <= 0x10FFFF)
614 {
615 /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
616 utf8_length = 4;
617 first_byte_mark = 0xF0; /* 11110000 */
618 }
619 else
620 {
621 /* invalid unicode codepoint */
622 goto fail;
623 }
624
625 /* encode as utf8 */
626 for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--)
627 {
628 /* 10xxxxxx */
629 (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
630 codepoint >>= 6;
631 }
632 /* encode first byte */
633 if (utf8_length > 1)
634 {
635 (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
636 }
637 else
638 {
639 (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
640 }
641
642 *output_pointer += utf8_length;
643
644 return sequence_length;
645
646fail:
647 return 0;
648}
649
650/* Parse the input text into an unescaped cinput, and populate item. */
651static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer)
652{
653 const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
654 const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
655 unsigned char *output_pointer = NULL;
656 unsigned char *output = NULL;
657
658 /* not a string */
659 if (buffer_at_offset(input_buffer)[0] != '\"')
660 {
661 goto fail;
662 }
663
664 {
665 /* calculate approximate size of the output (overestimate) */
666 size_t allocation_length = 0;
667 size_t skipped_bytes = 0;
668 while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"'))
669 {
670 /* is escape sequence */
671 if (input_end[0] == '\\')
672 {
673 if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length)
674 {
675 /* prevent buffer overflow when last input character is a backslash */
676 goto fail;
677 }
678 skipped_bytes++;
679 input_end++;
680 }
681 input_end++;
682 }
683 if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"'))
684 {
685 goto fail; /* string ended unexpectedly */
686 }
687
688 /* This is at most how much we need for the output */
689 allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
690 output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof(""));
691 if (output == NULL)
692 {
693 goto fail; /* allocation failure */
694 }
695 }
696
697 output_pointer = output;
698 /* loop through the string literal */
699 while (input_pointer < input_end)
700 {
701 if (*input_pointer != '\\')
702 {
703 *output_pointer++ = *input_pointer++;
704 }
705 /* escape sequence */
706 else
707 {
708 unsigned char sequence_length = 2;
709 if ((input_end - input_pointer) < 1)
710 {
711 goto fail;
712 }
713
714 switch (input_pointer[1])
715 {
716 case 'b':
717 *output_pointer++ = '\b';
718 break;
719 case 'f':
720 *output_pointer++ = '\f';
721 break;
722 case 'n':
723 *output_pointer++ = '\n';
724 break;
725 case 'r':
726 *output_pointer++ = '\r';
727 break;
728 case 't':
729 *output_pointer++ = '\t';
730 break;
731 case '\"':
732 case '\\':
733 case '/':
734 *output_pointer++ = input_pointer[1];
735 break;
736
737 /* UTF-16 literal */
738 case 'u':
739 sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
740 if (sequence_length == 0)
741 {
742 /* failed to convert UTF16-literal to UTF-8 */
743 goto fail;
744 }
745 break;
746
747 default:
748 goto fail;
749 }
750 input_pointer += sequence_length;
751 }
752 }
753
754 /* zero terminate the output */
755 *output_pointer = '\0';
756
757 item->type = cJSON_String;
758 item->valuestring = (char*)output;
759
760 input_buffer->offset = (size_t) (input_end - input_buffer->content);
761 input_buffer->offset++;
762
763 return true;
764
765fail:
766 if (output != NULL)
767 {
768 input_buffer->hooks.deallocate(output);
769 }
770
771 if (input_pointer != NULL)
772 {
773 input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
774 }
775
776 return false;
777}
778
779/* Render the cstring provided to an escaped version that can be printed. */
780static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer)
781{
782 const unsigned char *input_pointer = NULL;
783 unsigned char *output = NULL;
784 unsigned char *output_pointer = NULL;
785 size_t output_length = 0;
786 /* numbers of additional characters needed for escaping */
787 size_t escape_characters = 0;
788
789 if (output_buffer == NULL)
790 {
791 return false;
792 }
793
794 /* empty string */
795 if (input == NULL)
796 {
797 output = ensure(output_buffer, sizeof("\"\""));
798 if (output == NULL)
799 {
800 return false;
801 }
802 strcpy((char*)output, "\"\"");
803
804 return true;
805 }
806
807 /* set "flag" to 1 if something needs to be escaped */
808 for (input_pointer = input; *input_pointer; input_pointer++)
809 {
810 switch (*input_pointer)
811 {
812 case '\"':
813 case '\\':
814 case '\b':
815 case '\f':
816 case '\n':
817 case '\r':
818 case '\t':
819 /* one character escape sequence */
820 escape_characters++;
821 break;
822 default:
823 if (*input_pointer < 32)
824 {
825 /* UTF-16 escape sequence uXXXX */
826 escape_characters += 5;
827 }
828 break;
829 }
830 }
831 output_length = (size_t)(input_pointer - input) + escape_characters;
832
833 output = ensure(output_buffer, output_length + sizeof("\"\""));
834 if (output == NULL)
835 {
836 return false;
837 }
838
839 /* no characters have to be escaped */
840 if (escape_characters == 0)
841 {
842 output[0] = '\"';
843 memcpy(output + 1, input, output_length);
844 output[output_length + 1] = '\"';
845 output[output_length + 2] = '\0';
846
847 return true;
848 }
849
850 output[0] = '\"';
851 output_pointer = output + 1;
852 /* copy the string */
853 for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++)
854 {
855 if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\'))
856 {
857 /* normal character, copy */
858 *output_pointer = *input_pointer;
859 }
860 else
861 {
862 /* character needs to be escaped */
863 *output_pointer++ = '\\';
864 switch (*input_pointer)
865 {
866 case '\\':
867 *output_pointer = '\\';
868 break;
869 case '\"':
870 *output_pointer = '\"';
871 break;
872 case '\b':
873 *output_pointer = 'b';
874 break;
875 case '\f':
876 *output_pointer = 'f';
877 break;
878 case '\n':
879 *output_pointer = 'n';
880 break;
881 case '\r':
882 *output_pointer = 'r';
883 break;
884 case '\t':
885 *output_pointer = 't';
886 break;
887 default:
888 /* escape and print as unicode codepoint */
889 sprintf((char*)output_pointer, "u%04x", *input_pointer);
890 output_pointer += 4;
891 break;
892 }
893 }
894 }
895 output[output_length + 1] = '\"';
896 output[output_length + 2] = '\0';
897
898 return true;
899}
900
901/* Invoke print_string_ptr (which is useful) on an item. */
902static cJSON_bool print_string(const cJSON * const item, printbuffer * const p)
903{
904 return print_string_ptr((unsigned char*)item->valuestring, p);
905}
906
907/* Predeclare these prototypes. */
908static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer);
909static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer);
910static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer);
911static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer);
912static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer);
913static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer);
914
915/* Utility to jump whitespace and cr/lf */
916static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)
917{
918 if ((buffer == NULL) || (buffer->content == NULL))
919 {
920 return NULL;
921 }
922
923 while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32))
924 {
925 buffer->offset++;
926 }
927
928 if (buffer->offset == buffer->length)
929 {
930 buffer->offset--;
931 }
932
933 return buffer;
934}
935
936/* Parse an object - create a new root, and populate. */
937CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)
938{
939 parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
940 cJSON *item = NULL;
941
942 /* reset error position */
943 global_error.json = NULL;
944 global_error.position = 0;
945
946 if (value == NULL)
947 {
948 goto fail;
949 }
950
951 buffer.content = (const unsigned char*)value;
952 buffer.length = strlen((const char*)value) + sizeof("");
953 buffer.offset = 0;
954 buffer.hooks = global_hooks;
955
956 item = cJSON_New_Item(&global_hooks);
957 if (item == NULL) /* memory fail */
958 {
959 goto fail;
960 }
961
962 if (!parse_value(item, buffer_skip_whitespace(&buffer)))
963 {
964 /* parse failure. ep is set. */
965 goto fail;
966 }
967
968 /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
969 if (require_null_terminated)
970 {
971 buffer_skip_whitespace(&buffer);
972 if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0')
973 {
974 goto fail;
975 }
976 }
977 if (return_parse_end)
978 {
979 *return_parse_end = (const char*)buffer_at_offset(&buffer);
980 }
981
982 return item;
983
984fail:
985 if (item != NULL)
986 {
987 cJSON_Delete(item);
988 }
989
990 if (value != NULL)
991 {
992 error local_error;
993 local_error.json = (const unsigned char*)value;
994 local_error.position = 0;
995
996 if (buffer.offset < buffer.length)
997 {
998 local_error.position = buffer.offset;
999 }
1000 else if (buffer.length > 0)
1001 {
1002 local_error.position = buffer.length - 1;
1003 }
1004
1005 if (return_parse_end != NULL)
1006 {
1007 *return_parse_end = (const char*)local_error.json + local_error.position;
1008 }
1009 else
1010 {
1011 global_error = local_error;
1012 }
1013 }
1014
1015 return NULL;
1016}
1017
1018/* Default options for cJSON_Parse */
1019CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
1020{
1021 return cJSON_ParseWithOpts(value, 0, 0);
1022}
1023
1024#define cjson_min(a, b) ((a < b) ? a : b)
1025
1026static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks)
1027{
1028 printbuffer buffer[1];
1029 unsigned char *printed = NULL;
1030
1031 memset(buffer, 0, sizeof(buffer));
1032
1033 /* create buffer */
1034 buffer->buffer = (unsigned char*) hooks->allocate(256);
1035 buffer->format = format;
1036 buffer->hooks = *hooks;
1037 if (buffer->buffer == NULL)
1038 {
1039 goto fail;
1040 }
1041
1042 /* print the value */
1043 if (!print_value(item, buffer))
1044 {
1045 goto fail;
1046 }
1047 update_offset(buffer);
1048
1049 /* check if reallocate is available */
1050 if (hooks->reallocate != NULL)
1051 {
1052 printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->length);
1053 buffer->buffer = NULL;
1054 if (printed == NULL) {
1055 goto fail;
1056 }
1057 }
1058 else /* otherwise copy the JSON over to a new buffer */
1059 {
1060 printed = (unsigned char*) hooks->allocate(buffer->offset + 1);
1061 if (printed == NULL)
1062 {
1063 goto fail;
1064 }
1065 memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1));
1066 printed[buffer->offset] = '\0'; /* just to be sure */
1067
1068 /* free the buffer */
1069 hooks->deallocate(buffer->buffer);
1070 }
1071
1072 return printed;
1073
1074fail:
1075 if (buffer->buffer != NULL)
1076 {
1077 hooks->deallocate(buffer->buffer);
1078 }
1079
1080 if (printed != NULL)
1081 {
1082 hooks->deallocate(printed);
1083 }
1084
1085 return NULL;
1086}
1087
1088/* Render a cJSON item/entity/structure to text. */
1089CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item)
1090{
1091 return (char*)print(item, true, &global_hooks);
1092}
1093
1094CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item)
1095{
1096 return (char*)print(item, false, &global_hooks);
1097}
1098
1099CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)
1100{
1101 printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
1102
1103 if (prebuffer < 0)
1104 {
1105 return NULL;
1106 }
1107
1108 p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer);
1109 if (!p.buffer)
1110 {
1111 return NULL;
1112 }
1113
1114 p.length = (size_t)prebuffer;
1115 p.offset = 0;
1116 p.noalloc = false;
1117 p.format = fmt;
1118 p.hooks = global_hooks;
1119
1120 if (!print_value(item, &p))
1121 {
1122 global_hooks.deallocate(p.buffer);
1123 return NULL;
1124 }
1125
1126 return (char*)p.buffer;
1127}
1128
1129CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt)
1130{
1131 printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
1132
1133 if ((len < 0) || (buf == NULL))
1134 {
1135 return false;
1136 }
1137
1138 p.buffer = (unsigned char*)buf;
1139 p.length = (size_t)len;
1140 p.offset = 0;
1141 p.noalloc = true;
1142 p.format = fmt;
1143 p.hooks = global_hooks;
1144
1145 return print_value(item, &p);
1146}
1147
1148/* Parser core - when encountering text, process appropriately. */
1149static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer)
1150{
1151 if ((input_buffer == NULL) || (input_buffer->content == NULL))
1152 {
1153 return false; /* no input */
1154 }
1155
1156 /* parse the different types of values */
1157 /* null */
1158 if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0))
1159 {
1160 item->type = cJSON_NULL;
1161 input_buffer->offset += 4;
1162 return true;
1163 }
1164 /* false */
1165 if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0))
1166 {
1167 item->type = cJSON_False;
1168 input_buffer->offset += 5;
1169 return true;
1170 }
1171 /* true */
1172 if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0))
1173 {
1174 item->type = cJSON_True;
1175 item->valueint = 1;
1176 input_buffer->offset += 4;
1177 return true;
1178 }
1179 /* string */
1180 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"'))
1181 {
1182 return parse_string(item, input_buffer);
1183 }
1184 /* number */
1185 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'))))
1186 {
1187 return parse_number(item, input_buffer);
1188 }
1189 /* array */
1190 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '['))
1191 {
1192 return parse_array(item, input_buffer);
1193 }
1194 /* object */
1195 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{'))
1196 {
1197 return parse_object(item, input_buffer);
1198 }
1199
1200
1201 return false;
1202}
1203
1204/* Render a value to text. */
1205static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer)
1206{
1207 unsigned char *output = NULL;
1208
1209 if ((item == NULL) || (output_buffer == NULL))
1210 {
1211 return false;
1212 }
1213
1214 switch ((item->type) & 0xFF)
1215 {
1216 case cJSON_NULL:
1217 output = ensure(output_buffer, 5);
1218 if (output == NULL)
1219 {
1220 return false;
1221 }
1222 strcpy((char*)output, "null");
1223 return true;
1224
1225 case cJSON_False:
1226 output = ensure(output_buffer, 6);
1227 if (output == NULL)
1228 {
1229 return false;
1230 }
1231 strcpy((char*)output, "false");
1232 return true;
1233
1234 case cJSON_True:
1235 output = ensure(output_buffer, 5);
1236 if (output == NULL)
1237 {
1238 return false;
1239 }
1240 strcpy((char*)output, "true");
1241 return true;
1242
1243 case cJSON_Number:
1244 return print_number(item, output_buffer);
1245
1246 case cJSON_Raw:
1247 {
1248 size_t raw_length = 0;
1249 if (item->valuestring == NULL)
1250 {
1251 if (!output_buffer->noalloc)
1252 {
1253 output_buffer->hooks.deallocate(output_buffer->buffer);
1254 }
1255 return false;
1256 }
1257
1258 raw_length = strlen(item->valuestring) + sizeof("");
1259 output = ensure(output_buffer, raw_length);
1260 if (output == NULL)
1261 {
1262 return false;
1263 }
1264 memcpy(output, item->valuestring, raw_length);
1265 return true;
1266 }
1267
1268 case cJSON_String:
1269 return print_string(item, output_buffer);
1270
1271 case cJSON_Array:
1272 return print_array(item, output_buffer);
1273
1274 case cJSON_Object:
1275 return print_object(item, output_buffer);
1276
1277 default:
1278 return false;
1279 }
1280}
1281
1282/* Build an array from input text. */
1283static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer)
1284{
1285 cJSON *head = NULL; /* head of the linked list */
1286 cJSON *current_item = NULL;
1287
1288 if (input_buffer->depth >= CJSON_NESTING_LIMIT)
1289 {
1290 return false; /* to deeply nested */
1291 }
1292 input_buffer->depth++;
1293
1294 if (buffer_at_offset(input_buffer)[0] != '[')
1295 {
1296 /* not an array */
1297 goto fail;
1298 }
1299
1300 input_buffer->offset++;
1301 buffer_skip_whitespace(input_buffer);
1302 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']'))
1303 {
1304 /* empty array */
1305 goto success;
1306 }
1307
1308 /* check if we skipped to the end of the buffer */
1309 if (cannot_access_at_index(input_buffer, 0))
1310 {
1311 input_buffer->offset--;
1312 goto fail;
1313 }
1314
1315 /* step back to character in front of the first element */
1316 input_buffer->offset--;
1317 /* loop through the comma separated array elements */
1318 do
1319 {
1320 /* allocate next item */
1321 cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
1322 if (new_item == NULL)
1323 {
1324 goto fail; /* allocation failure */
1325 }
1326
1327 /* attach next item to list */
1328 if (head == NULL)
1329 {
1330 /* start the linked list */
1331 current_item = head = new_item;
1332 }
1333 else
1334 {
1335 /* add to the end and advance */
1336 current_item->next = new_item;
1337 new_item->prev = current_item;
1338 current_item = new_item;
1339 }
1340
1341 /* parse next value */
1342 input_buffer->offset++;
1343 buffer_skip_whitespace(input_buffer);
1344 if (!parse_value(current_item, input_buffer))
1345 {
1346 goto fail; /* failed to parse value */
1347 }
1348 buffer_skip_whitespace(input_buffer);
1349 }
1350 while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1351
1352 if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']')
1353 {
1354 goto fail; /* expected end of array */
1355 }
1356
1357success:
1358 input_buffer->depth--;
1359
1360 item->type = cJSON_Array;
1361 item->child = head;
1362
1363 input_buffer->offset++;
1364
1365 return true;
1366
1367fail:
1368 if (head != NULL)
1369 {
1370 cJSON_Delete(head);
1371 }
1372
1373 return false;
1374}
1375
1376/* Render an array to text */
1377static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer)
1378{
1379 unsigned char *output_pointer = NULL;
1380 size_t length = 0;
1381 cJSON *current_element = item->child;
1382
1383 if (output_buffer == NULL)
1384 {
1385 return false;
1386 }
1387
1388 /* Compose the output array. */
1389 /* opening square bracket */
1390 output_pointer = ensure(output_buffer, 1);
1391 if (output_pointer == NULL)
1392 {
1393 return false;
1394 }
1395
1396 *output_pointer = '[';
1397 output_buffer->offset++;
1398 output_buffer->depth++;
1399
1400 while (current_element != NULL)
1401 {
1402 if (!print_value(current_element, output_buffer))
1403 {
1404 return false;
1405 }
1406 update_offset(output_buffer);
1407 if (current_element->next)
1408 {
1409 length = (size_t) (output_buffer->format ? 2 : 1);
1410 output_pointer = ensure(output_buffer, length + 1);
1411 if (output_pointer == NULL)
1412 {
1413 return false;
1414 }
1415 *output_pointer++ = ',';
1416 if(output_buffer->format)
1417 {
1418 *output_pointer++ = ' ';
1419 }
1420 *output_pointer = '\0';
1421 output_buffer->offset += length;
1422 }
1423 current_element = current_element->next;
1424 }
1425
1426 output_pointer = ensure(output_buffer, 2);
1427 if (output_pointer == NULL)
1428 {
1429 return false;
1430 }
1431 *output_pointer++ = ']';
1432 *output_pointer = '\0';
1433 output_buffer->depth--;
1434
1435 return true;
1436}
1437
1438/* Build an object from the text. */
1439static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer)
1440{
1441 cJSON *head = NULL; /* linked list head */
1442 cJSON *current_item = NULL;
1443
1444 if (input_buffer->depth >= CJSON_NESTING_LIMIT)
1445 {
1446 return false; /* to deeply nested */
1447 }
1448 input_buffer->depth++;
1449
1450 if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{'))
1451 {
1452 goto fail; /* not an object */
1453 }
1454
1455 input_buffer->offset++;
1456 buffer_skip_whitespace(input_buffer);
1457 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}'))
1458 {
1459 goto success; /* empty object */
1460 }
1461
1462 /* check if we skipped to the end of the buffer */
1463 if (cannot_access_at_index(input_buffer, 0))
1464 {
1465 input_buffer->offset--;
1466 goto fail;
1467 }
1468
1469 /* step back to character in front of the first element */
1470 input_buffer->offset--;
1471 /* loop through the comma separated array elements */
1472 do
1473 {
1474 /* allocate next item */
1475 cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
1476 if (new_item == NULL)
1477 {
1478 goto fail; /* allocation failure */
1479 }
1480
1481 /* attach next item to list */
1482 if (head == NULL)
1483 {
1484 /* start the linked list */
1485 current_item = head = new_item;
1486 }
1487 else
1488 {
1489 /* add to the end and advance */
1490 current_item->next = new_item;
1491 new_item->prev = current_item;
1492 current_item = new_item;
1493 }
1494
1495 /* parse the name of the child */
1496 input_buffer->offset++;
1497 buffer_skip_whitespace(input_buffer);
1498 if (!parse_string(current_item, input_buffer))
1499 {
1500 goto fail; /* faile to parse name */
1501 }
1502 buffer_skip_whitespace(input_buffer);
1503
1504 /* swap valuestring and string, because we parsed the name */
1505 current_item->string = current_item->valuestring;
1506 current_item->valuestring = NULL;
1507
1508 if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':'))
1509 {
1510 goto fail; /* invalid object */
1511 }
1512
1513 /* parse the value */
1514 input_buffer->offset++;
1515 buffer_skip_whitespace(input_buffer);
1516 if (!parse_value(current_item, input_buffer))
1517 {
1518 goto fail; /* failed to parse value */
1519 }
1520 buffer_skip_whitespace(input_buffer);
1521 }
1522 while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1523
1524 if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}'))
1525 {
1526 goto fail; /* expected end of object */
1527 }
1528
1529success:
1530 input_buffer->depth--;
1531
1532 item->type = cJSON_Object;
1533 item->child = head;
1534
1535 input_buffer->offset++;
1536 return true;
1537
1538fail:
1539 if (head != NULL)
1540 {
1541 cJSON_Delete(head);
1542 }
1543
1544 return false;
1545}
1546
1547/* Render an object to text. */
1548static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer)
1549{
1550 unsigned char *output_pointer = NULL;
1551 size_t length = 0;
1552 cJSON *current_item = item->child;
1553
1554 if (output_buffer == NULL)
1555 {
1556 return false;
1557 }
1558
1559 /* Compose the output: */
1560 length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */
1561 output_pointer = ensure(output_buffer, length + 1);
1562 if (output_pointer == NULL)
1563 {
1564 return false;
1565 }
1566
1567 *output_pointer++ = '{';
1568 output_buffer->depth++;
1569 if (output_buffer->format)
1570 {
1571 *output_pointer++ = '\n';
1572 }
1573 output_buffer->offset += length;
1574
1575 while (current_item)
1576 {
1577 if (output_buffer->format)
1578 {
1579 size_t i;
1580 output_pointer = ensure(output_buffer, output_buffer->depth);
1581 if (output_pointer == NULL)
1582 {
1583 return false;
1584 }
1585 for (i = 0; i < output_buffer->depth; i++)
1586 {
1587 *output_pointer++ = '\t';
1588 }
1589 output_buffer->offset += output_buffer->depth;
1590 }
1591
1592 /* print key */
1593 if (!print_string_ptr((unsigned char*)current_item->string, output_buffer))
1594 {
1595 return false;
1596 }
1597 update_offset(output_buffer);
1598
1599 length = (size_t) (output_buffer->format ? 2 : 1);
1600 output_pointer = ensure(output_buffer, length);
1601 if (output_pointer == NULL)
1602 {
1603 return false;
1604 }
1605 *output_pointer++ = ':';
1606 if (output_buffer->format)
1607 {
1608 *output_pointer++ = '\t';
1609 }
1610 output_buffer->offset += length;
1611
1612 /* print value */
1613 if (!print_value(current_item, output_buffer))
1614 {
1615 return false;
1616 }
1617 update_offset(output_buffer);
1618
1619 /* print comma if not last */
1620 length = (size_t) ((output_buffer->format ? 1 : 0) + (current_item->next ? 1 : 0));
1621 output_pointer = ensure(output_buffer, length + 1);
1622 if (output_pointer == NULL)
1623 {
1624 return false;
1625 }
1626 if (current_item->next)
1627 {
1628 *output_pointer++ = ',';
1629 }
1630
1631 if (output_buffer->format)
1632 {
1633 *output_pointer++ = '\n';
1634 }
1635 *output_pointer = '\0';
1636 output_buffer->offset += length;
1637
1638 current_item = current_item->next;
1639 }
1640
1641 output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2);
1642 if (output_pointer == NULL)
1643 {
1644 return false;
1645 }
1646 if (output_buffer->format)
1647 {
1648 size_t i;
1649 for (i = 0; i < (output_buffer->depth - 1); i++)
1650 {
1651 *output_pointer++ = '\t';
1652 }
1653 }
1654 *output_pointer++ = '}';
1655 *output_pointer = '\0';
1656 output_buffer->depth--;
1657
1658 return true;
1659}
1660
1661/* Get Array size/item / object item. */
1662CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array)
1663{
1664 cJSON *child = NULL;
1665 size_t size = 0;
1666
1667 if (array == NULL)
1668 {
1669 return 0;
1670 }
1671
1672 child = array->child;
1673
1674 while(child != NULL)
1675 {
1676 size++;
1677 child = child->next;
1678 }
1679
1680 /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
1681
1682 return (int)size;
1683}
1684
1685static cJSON* get_array_item(const cJSON *array, size_t index)
1686{
1687 cJSON *current_child = NULL;
1688
1689 if (array == NULL)
1690 {
1691 return NULL;
1692 }
1693
1694 current_child = array->child;
1695 while ((current_child != NULL) && (index > 0))
1696 {
1697 index--;
1698 current_child = current_child->next;
1699 }
1700
1701 return current_child;
1702}
1703
1704CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index)
1705{
1706 if (index < 0)
1707 {
1708 return NULL;
1709 }
1710
1711 return get_array_item(array, (size_t)index);
1712}
1713
1714static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive)
1715{
1716 cJSON *current_element = NULL;
1717
1718 if ((object == NULL) || (name == NULL))
1719 {
1720 return NULL;
1721 }
1722
1723 current_element = object->child;
1724 if (case_sensitive)
1725 {
1726 while ((current_element != NULL) && (strcmp(name, current_element->string) != 0))
1727 {
1728 current_element = current_element->next;
1729 }
1730 }
1731 else
1732 {
1733 while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0))
1734 {
1735 current_element = current_element->next;
1736 }
1737 }
1738
1739 return current_element;
1740}
1741
1742CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string)
1743{
1744 return get_object_item(object, string, false);
1745}
1746
1747CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string)
1748{
1749 return get_object_item(object, string, true);
1750}
1751
1752CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string)
1753{
1754 return cJSON_GetObjectItem(object, string) ? 1 : 0;
1755}
1756
1757/* Utility for array list handling. */
1758static void suffix_object(cJSON *prev, cJSON *item)
1759{
1760 prev->next = item;
1761 item->prev = prev;
1762}
1763
1764/* Utility for handling references. */
1765static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks)
1766{
1767 cJSON *reference = NULL;
1768 if (item == NULL)
1769 {
1770 return NULL;
1771 }
1772
1773 reference = cJSON_New_Item(hooks);
1774 if (reference == NULL)
1775 {
1776 return NULL;
1777 }
1778
1779 memcpy(reference, item, sizeof(cJSON));
1780 reference->string = NULL;
1781 reference->type |= cJSON_IsReference;
1782 reference->next = reference->prev = NULL;
1783 return reference;
1784}
1785
1786/* Add item to array/object. */
1787CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item)
1788{
1789 cJSON *child = NULL;
1790
1791 if ((item == NULL) || (array == NULL))
1792 {
1793 return;
1794 }
1795
1796 child = array->child;
1797
1798 if (child == NULL)
1799 {
1800 /* list is empty, start new one */
1801 array->child = item;
1802 }
1803 else
1804 {
1805 /* append to the end */
1806 while (child->next)
1807 {
1808 child = child->next;
1809 }
1810 suffix_object(child, item);
1811 }
1812}
1813
1814CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
1815{
1816 if (item == NULL)
1817 {
1818 return;
1819 }
1820
1821 /* call cJSON_AddItemToObjectCS for code reuse */
1822 cJSON_AddItemToObjectCS(object, (char*)cJSON_strdup((const unsigned char*)string, &global_hooks), item);
1823 /* remove cJSON_StringIsConst flag */
1824 item->type &= ~cJSON_StringIsConst;
1825}
1826
1827#if defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
1828 #pragma GCC diagnostic push
1829#endif
1830#ifdef __GNUC__
1831#pragma GCC diagnostic ignored "-Wcast-qual"
1832#endif
1833
1834/* Add an item to an object with constant string as key */
1835CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
1836{
1837 if ((item == NULL) || (string == NULL))
1838 {
1839 return;
1840 }
1841 if (!(item->type & cJSON_StringIsConst) && item->string)
1842 {
1843 global_hooks.deallocate(item->string);
1844 }
1845 item->string = (char*)string;
1846 item->type |= cJSON_StringIsConst;
1847 cJSON_AddItemToArray(object, item);
1848}
1849#if defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
1850 #pragma GCC diagnostic pop
1851#endif
1852
1853CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
1854{
1855 if (array == NULL)
1856 {
1857 return;
1858 }
1859
1860 cJSON_AddItemToArray(array, create_reference(item, &global_hooks));
1861}
1862
1863CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)
1864{
1865 if ((object == NULL) || (string == NULL))
1866 {
1867 return;
1868 }
1869
1870 cJSON_AddItemToObject(object, string, create_reference(item, &global_hooks));
1871}
1872
1873CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item)
1874{
1875 if ((parent == NULL) || (item == NULL))
1876 {
1877 return NULL;
1878 }
1879
1880 if (item->prev != NULL)
1881 {
1882 /* not the first element */
1883 item->prev->next = item->next;
1884 }
1885 if (item->next != NULL)
1886 {
1887 /* not the last element */
1888 item->next->prev = item->prev;
1889 }
1890
1891 if (item == parent->child)
1892 {
1893 /* first element */
1894 parent->child = item->next;
1895 }
1896 /* make sure the detached item doesn't point anywhere anymore */
1897 item->prev = NULL;
1898 item->next = NULL;
1899
1900 return item;
1901}
1902
1903CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which)
1904{
1905 if (which < 0)
1906 {
1907 return NULL;
1908 }
1909
1910 return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which));
1911}
1912
1913CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which)
1914{
1915 cJSON_Delete(cJSON_DetachItemFromArray(array, which));
1916}
1917
1918CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string)
1919{
1920 cJSON *to_detach = cJSON_GetObjectItem(object, string);
1921
1922 return cJSON_DetachItemViaPointer(object, to_detach);
1923}
1924
1925CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string)
1926{
1927 cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string);
1928
1929 return cJSON_DetachItemViaPointer(object, to_detach);
1930}
1931
1932CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string)
1933{
1934 cJSON_Delete(cJSON_DetachItemFromObject(object, string));
1935}
1936
1937CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string)
1938{
1939 cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string));
1940}
1941
1942/* Replace array/object items with new ones. */
1943CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
1944{
1945 cJSON *after_inserted = NULL;
1946
1947 if (which < 0)
1948 {
1949 return;
1950 }
1951
1952 after_inserted = get_array_item(array, (size_t)which);
1953 if (after_inserted == NULL)
1954 {
1955 cJSON_AddItemToArray(array, newitem);
1956 return;
1957 }
1958
1959 newitem->next = after_inserted;
1960 newitem->prev = after_inserted->prev;
1961 after_inserted->prev = newitem;
1962 if (after_inserted == array->child)
1963 {
1964 array->child = newitem;
1965 }
1966 else
1967 {
1968 newitem->prev->next = newitem;
1969 }
1970}
1971
1972CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement)
1973{
1974 if ((parent == NULL) || (replacement == NULL) || (item == NULL))
1975 {
1976 return false;
1977 }
1978
1979 if (replacement == item)
1980 {
1981 return true;
1982 }
1983
1984 replacement->next = item->next;
1985 replacement->prev = item->prev;
1986
1987 if (replacement->next != NULL)
1988 {
1989 replacement->next->prev = replacement;
1990 }
1991 if (replacement->prev != NULL)
1992 {
1993 replacement->prev->next = replacement;
1994 }
1995 if (parent->child == item)
1996 {
1997 parent->child = replacement;
1998 }
1999
2000 item->next = NULL;
2001 item->prev = NULL;
2002 cJSON_Delete(item);
2003
2004 return true;
2005}
2006
2007CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
2008{
2009 if (which < 0)
2010 {
2011 return;
2012 }
2013
2014 cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem);
2015}
2016
2017static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive)
2018{
2019 if ((replacement == NULL) || (string == NULL))
2020 {
2021 return false;
2022 }
2023
2024 /* replace the name in the replacement */
2025 if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL))
2026 {
2027 cJSON_free(replacement->string);
2028 }
2029 replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
2030 replacement->type &= ~cJSON_StringIsConst;
2031
2032 cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement);
2033
2034 return true;
2035}
2036
2037CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
2038{
2039 replace_item_in_object(object, string, newitem, false);
2040}
2041
2042CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem)
2043{
2044 replace_item_in_object(object, string, newitem, true);
2045}
2046
2047/* Create basic types: */
2048CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void)
2049{
2050 cJSON *item = cJSON_New_Item(&global_hooks);
2051 if(item)
2052 {
2053 item->type = cJSON_NULL;
2054 }
2055
2056 return item;
2057}
2058
2059CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void)
2060{
2061 cJSON *item = cJSON_New_Item(&global_hooks);
2062 if(item)
2063 {
2064 item->type = cJSON_True;
2065 }
2066
2067 return item;
2068}
2069
2070CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void)
2071{
2072 cJSON *item = cJSON_New_Item(&global_hooks);
2073 if(item)
2074 {
2075 item->type = cJSON_False;
2076 }
2077
2078 return item;
2079}
2080
2081CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b)
2082{
2083 cJSON *item = cJSON_New_Item(&global_hooks);
2084 if(item)
2085 {
2086 item->type = b ? cJSON_True : cJSON_False;
2087 }
2088
2089 return item;
2090}
2091
2092CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
2093{
2094 cJSON *item = cJSON_New_Item(&global_hooks);
2095 if(item)
2096 {
2097 item->type = cJSON_Number;
2098 item->valuedouble = num;
2099
2100 /* use saturation in case of overflow */
2101 if (num >= INT_MAX)
2102 {
2103 item->valueint = INT_MAX;
2104 }
2105 else if (num <= INT_MIN)
2106 {
2107 item->valueint = INT_MIN;
2108 }
2109 else
2110 {
2111 item->valueint = (int)num;
2112 }
2113 }
2114
2115 return item;
2116}
2117
2118CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string)
2119{
2120 cJSON *item = cJSON_New_Item(&global_hooks);
2121 if(item)
2122 {
2123 item->type = cJSON_String;
2124 item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
2125 if(!item->valuestring)
2126 {
2127 cJSON_Delete(item);
2128 return NULL;
2129 }
2130 }
2131
2132 return item;
2133}
2134
2135CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw)
2136{
2137 cJSON *item = cJSON_New_Item(&global_hooks);
2138 if(item)
2139 {
2140 item->type = cJSON_Raw;
2141 item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks);
2142 if(!item->valuestring)
2143 {
2144 cJSON_Delete(item);
2145 return NULL;
2146 }
2147 }
2148
2149 return item;
2150}
2151
2152CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void)
2153{
2154 cJSON *item = cJSON_New_Item(&global_hooks);
2155 if(item)
2156 {
2157 item->type=cJSON_Array;
2158 }
2159
2160 return item;
2161}
2162
2163CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void)
2164{
2165 cJSON *item = cJSON_New_Item(&global_hooks);
2166 if (item)
2167 {
2168 item->type = cJSON_Object;
2169 }
2170
2171 return item;
2172}
2173
2174/* Create Arrays: */
2175CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)
2176{
2177 size_t i = 0;
2178 cJSON *n = NULL;
2179 cJSON *p = NULL;
2180 cJSON *a = NULL;
2181
2182 if ((count < 0) || (numbers == NULL))
2183 {
2184 return NULL;
2185 }
2186
2187 a = cJSON_CreateArray();
2188 for(i = 0; a && (i < (size_t)count); i++)
2189 {
2190 n = cJSON_CreateNumber(numbers[i]);
2191 if (!n)
2192 {
2193 cJSON_Delete(a);
2194 return NULL;
2195 }
2196 if(!i)
2197 {
2198 a->child = n;
2199 }
2200 else
2201 {
2202 suffix_object(p, n);
2203 }
2204 p = n;
2205 }
2206
2207 return a;
2208}
2209
2210CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count)
2211{
2212 size_t i = 0;
2213 cJSON *n = NULL;
2214 cJSON *p = NULL;
2215 cJSON *a = NULL;
2216
2217 if ((count < 0) || (numbers == NULL))
2218 {
2219 return NULL;
2220 }
2221
2222 a = cJSON_CreateArray();
2223
2224 for(i = 0; a && (i < (size_t)count); i++)
2225 {
2226 n = cJSON_CreateNumber((double)numbers[i]);
2227 if(!n)
2228 {
2229 cJSON_Delete(a);
2230 return NULL;
2231 }
2232 if(!i)
2233 {
2234 a->child = n;
2235 }
2236 else
2237 {
2238 suffix_object(p, n);
2239 }
2240 p = n;
2241 }
2242
2243 return a;
2244}
2245
2246CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count)
2247{
2248 size_t i = 0;
2249 cJSON *n = NULL;
2250 cJSON *p = NULL;
2251 cJSON *a = NULL;
2252
2253 if ((count < 0) || (numbers == NULL))
2254 {
2255 return NULL;
2256 }
2257
2258 a = cJSON_CreateArray();
2259
2260 for(i = 0;a && (i < (size_t)count); i++)
2261 {
2262 n = cJSON_CreateNumber(numbers[i]);
2263 if(!n)
2264 {
2265 cJSON_Delete(a);
2266 return NULL;
2267 }
2268 if(!i)
2269 {
2270 a->child = n;
2271 }
2272 else
2273 {
2274 suffix_object(p, n);
2275 }
2276 p = n;
2277 }
2278
2279 return a;
2280}
2281
2282CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count)
2283{
2284 size_t i = 0;
2285 cJSON *n = NULL;
2286 cJSON *p = NULL;
2287 cJSON *a = NULL;
2288
2289 if ((count < 0) || (strings == NULL))
2290 {
2291 return NULL;
2292 }
2293
2294 a = cJSON_CreateArray();
2295
2296 for (i = 0; a && (i < (size_t)count); i++)
2297 {
2298 n = cJSON_CreateString(strings[i]);
2299 if(!n)
2300 {
2301 cJSON_Delete(a);
2302 return NULL;
2303 }
2304 if(!i)
2305 {
2306 a->child = n;
2307 }
2308 else
2309 {
2310 suffix_object(p,n);
2311 }
2312 p = n;
2313 }
2314
2315 return a;
2316}
2317
2318/* Duplication */
2319CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
2320{
2321 cJSON *newitem = NULL;
2322 cJSON *child = NULL;
2323 cJSON *next = NULL;
2324 cJSON *newchild = NULL;
2325
2326 /* Bail on bad ptr */
2327 if (!item)
2328 {
2329 goto fail;
2330 }
2331 /* Create new item */
2332 newitem = cJSON_New_Item(&global_hooks);
2333 if (!newitem)
2334 {
2335 goto fail;
2336 }
2337 /* Copy over all vars */
2338 newitem->type = item->type & (~cJSON_IsReference);
2339 newitem->valueint = item->valueint;
2340 newitem->valuedouble = item->valuedouble;
2341 if (item->valuestring)
2342 {
2343 newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks);
2344 if (!newitem->valuestring)
2345 {
2346 goto fail;
2347 }
2348 }
2349 if (item->string)
2350 {
2351 newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks);
2352 if (!newitem->string)
2353 {
2354 goto fail;
2355 }
2356 }
2357 /* If non-recursive, then we're done! */
2358 if (!recurse)
2359 {
2360 return newitem;
2361 }
2362 /* Walk the ->next chain for the child. */
2363 child = item->child;
2364 while (child != NULL)
2365 {
2366 newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */
2367 if (!newchild)
2368 {
2369 goto fail;
2370 }
2371 if (next != NULL)
2372 {
2373 /* If newitem->child already set, then crosswire ->prev and ->next and move on */
2374 next->next = newchild;
2375 newchild->prev = next;
2376 next = newchild;
2377 }
2378 else
2379 {
2380 /* Set newitem->child and move to it */
2381 newitem->child = newchild;
2382 next = newchild;
2383 }
2384 child = child->next;
2385 }
2386
2387 return newitem;
2388
2389fail:
2390 if (newitem != NULL)
2391 {
2392 cJSON_Delete(newitem);
2393 }
2394
2395 return NULL;
2396}
2397
2398CJSON_PUBLIC(void) cJSON_Minify(char *json)
2399{
2400 unsigned char *into = (unsigned char*)json;
2401
2402 if (json == NULL)
2403 {
2404 return;
2405 }
2406
2407 while (*json)
2408 {
2409 if (*json == ' ')
2410 {
2411 json++;
2412 }
2413 else if (*json == '\t')
2414 {
2415 /* Whitespace characters. */
2416 json++;
2417 }
2418 else if (*json == '\r')
2419 {
2420 json++;
2421 }
2422 else if (*json=='\n')
2423 {
2424 json++;
2425 }
2426 else if ((*json == '/') && (json[1] == '/'))
2427 {
2428 /* double-slash comments, to end of line. */
2429 while (*json && (*json != '\n'))
2430 {
2431 json++;
2432 }
2433 }
2434 else if ((*json == '/') && (json[1] == '*'))
2435 {
2436 /* multiline comments. */
2437 while (*json && !((*json == '*') && (json[1] == '/')))
2438 {
2439 json++;
2440 }
2441 json += 2;
2442 }
2443 else if (*json == '\"')
2444 {
2445 /* string literals, which are \" sensitive. */
2446 *into++ = (unsigned char)*json++;
2447 while (*json && (*json != '\"'))
2448 {
2449 if (*json == '\\')
2450 {
2451 *into++ = (unsigned char)*json++;
2452 }
2453 *into++ = (unsigned char)*json++;
2454 }
2455 *into++ = (unsigned char)*json++;
2456 }
2457 else
2458 {
2459 /* All other characters. */
2460 *into++ = (unsigned char)*json++;
2461 }
2462 }
2463
2464 /* and null-terminate. */
2465 *into = '\0';
2466}
2467
2468CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item)
2469{
2470 if (item == NULL)
2471 {
2472 return false;
2473 }
2474
2475 return (item->type & 0xFF) == cJSON_Invalid;
2476}
2477
2478CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item)
2479{
2480 if (item == NULL)
2481 {
2482 return false;
2483 }
2484
2485 return (item->type & 0xFF) == cJSON_False;
2486}
2487
2488CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item)
2489{
2490 if (item == NULL)
2491 {
2492 return false;
2493 }
2494
2495 return (item->type & 0xff) == cJSON_True;
2496}
2497
2498
2499CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item)
2500{
2501 if (item == NULL)
2502 {
2503 return false;
2504 }
2505
2506 return (item->type & (cJSON_True | cJSON_False)) != 0;
2507}
2508CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item)
2509{
2510 if (item == NULL)
2511 {
2512 return false;
2513 }
2514
2515 return (item->type & 0xFF) == cJSON_NULL;
2516}
2517
2518CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item)
2519{
2520 if (item == NULL)
2521 {
2522 return false;
2523 }
2524
2525 return (item->type & 0xFF) == cJSON_Number;
2526}
2527
2528CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item)
2529{
2530 if (item == NULL)
2531 {
2532 return false;
2533 }
2534
2535 return (item->type & 0xFF) == cJSON_String;
2536}
2537
2538CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item)
2539{
2540 if (item == NULL)
2541 {
2542 return false;
2543 }
2544
2545 return (item->type & 0xFF) == cJSON_Array;
2546}
2547
2548CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item)
2549{
2550 if (item == NULL)
2551 {
2552 return false;
2553 }
2554
2555 return (item->type & 0xFF) == cJSON_Object;
2556}
2557
2558CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item)
2559{
2560 if (item == NULL)
2561 {
2562 return false;
2563 }
2564
2565 return (item->type & 0xFF) == cJSON_Raw;
2566}
2567
2568CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive)
2569{
2570 if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a))
2571 {
2572 return false;
2573 }
2574
2575 /* check if type is valid */
2576 switch (a->type & 0xFF)
2577 {
2578 case cJSON_False:
2579 case cJSON_True:
2580 case cJSON_NULL:
2581 case cJSON_Number:
2582 case cJSON_String:
2583 case cJSON_Raw:
2584 case cJSON_Array:
2585 case cJSON_Object:
2586 break;
2587
2588 default:
2589 return false;
2590 }
2591
2592 /* identical objects are equal */
2593 if (a == b)
2594 {
2595 return true;
2596 }
2597
2598 switch (a->type & 0xFF)
2599 {
2600 /* in these cases and equal type is enough */
2601 case cJSON_False:
2602 case cJSON_True:
2603 case cJSON_NULL:
2604 return true;
2605
2606 case cJSON_Number:
2607 if (a->valuedouble == b->valuedouble)
2608 {
2609 return true;
2610 }
2611 return false;
2612
2613 case cJSON_String:
2614 case cJSON_Raw:
2615 if ((a->valuestring == NULL) || (b->valuestring == NULL))
2616 {
2617 return false;
2618 }
2619 if (strcmp(a->valuestring, b->valuestring) == 0)
2620 {
2621 return true;
2622 }
2623
2624 return false;
2625
2626 case cJSON_Array:
2627 {
2628 cJSON *a_element = a->child;
2629 cJSON *b_element = b->child;
2630
2631 for (; (a_element != NULL) && (b_element != NULL);)
2632 {
2633 if (!cJSON_Compare(a_element, b_element, case_sensitive))
2634 {
2635 return false;
2636 }
2637
2638 a_element = a_element->next;
2639 b_element = b_element->next;
2640 }
2641
2642 /* one of the arrays is longer than the other */
2643 if (a_element != b_element) {
2644 return false;
2645 }
2646
2647 return true;
2648 }
2649
2650 case cJSON_Object:
2651 {
2652 cJSON *a_element = NULL;
2653 cJSON *b_element = NULL;
2654 cJSON_ArrayForEach(a_element, a)
2655 {
2656 /* TODO This has O(n^2) runtime, which is horrible! */
2657 b_element = get_object_item(b, a_element->string, case_sensitive);
2658 if (b_element == NULL)
2659 {
2660 return false;
2661 }
2662
2663 if (!cJSON_Compare(a_element, b_element, case_sensitive))
2664 {
2665 return false;
2666 }
2667 }
2668
2669 /* doing this twice, once on a and b to prevent true comparison if a subset of b
2670 * TODO: Do this the proper way, this is just a fix for now */
2671 cJSON_ArrayForEach(b_element, b)
2672 {
2673 a_element = get_object_item(a, b_element->string, case_sensitive);
2674 if (a_element == NULL)
2675 {
2676 return false;
2677 }
2678
2679 if (!cJSON_Compare(b_element, a_element, case_sensitive))
2680 {
2681 return false;
2682 }
2683 }
2684
2685 return true;
2686 }
2687
2688 default:
2689 return false;
2690 }
2691}
2692
2693CJSON_PUBLIC(void *) cJSON_malloc(size_t size)
2694{
2695 return global_hooks.allocate(size);
2696}
2697
2698CJSON_PUBLIC(void) cJSON_free(void *object)
2699{
2700 global_hooks.deallocate(object);
2701} \ No newline at end of file
diff --git a/source/cJSON.h b/source/cJSON.h new file mode 100644 index 0000000..6d94e1f --- /dev/null +++ b/source/cJSON.h
@@ -0,0 +1,263 @@
1/*
2 Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21*/
22
23#ifndef cJSON__h
24#define cJSON__h
25
26#ifdef __cplusplus
27extern "C"
28{
29#endif
30
31/* project version */
32#define CJSON_VERSION_MAJOR 1
33#define CJSON_VERSION_MINOR 5
34#define CJSON_VERSION_PATCH 7
35
36#include <stddef.h>
37
38/* cJSON Types: */
39#define cJSON_Invalid (0)
40#define cJSON_False (1 << 0)
41#define cJSON_True (1 << 1)
42#define cJSON_NULL (1 << 2)
43#define cJSON_Number (1 << 3)
44#define cJSON_String (1 << 4)
45#define cJSON_Array (1 << 5)
46#define cJSON_Object (1 << 6)
47#define cJSON_Raw (1 << 7) /* raw json */
48
49#define cJSON_IsReference 256
50#define cJSON_StringIsConst 512
51
52/* The cJSON structure: */
53typedef struct cJSON
54{
55 /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
56 struct cJSON *next;
57 struct cJSON *prev;
58 /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
59 struct cJSON *child;
60
61 /* The type of the item, as above. */
62 int type;
63
64 /* The item's string, if type==cJSON_String and type == cJSON_Raw */
65 char *valuestring;
66 /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
67 int valueint;
68 /* The item's number, if type==cJSON_Number */
69 double valuedouble;
70
71 /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
72 char *string;
73} cJSON;
74
75typedef struct cJSON_Hooks
76{
77 void *(*malloc_fn)(size_t sz);
78 void (*free_fn)(void *ptr);
79} cJSON_Hooks;
80
81typedef int cJSON_bool;
82
83#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
84#define __WINDOWS__
85#endif
86#ifdef __WINDOWS__
87
88/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 2 define options:
89
90CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
91CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
92CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
93
94For *nix builds that support visibility attribute, you can define similar behavior by
95
96setting default visibility to hidden by adding
97-fvisibility=hidden (for gcc)
98or
99-xldscope=hidden (for sun cc)
100to CFLAGS
101
102then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
103
104*/
105
106/* export symbols by default, this is necessary for copy pasting the C and header file */
107#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
108#define CJSON_EXPORT_SYMBOLS
109#endif
110
111#if defined(CJSON_HIDE_SYMBOLS)
112#define CJSON_PUBLIC(type) type __stdcall
113#elif defined(CJSON_EXPORT_SYMBOLS)
114#define CJSON_PUBLIC(type) __declspec(dllexport) type __stdcall
115#elif defined(CJSON_IMPORT_SYMBOLS)
116#define CJSON_PUBLIC(type) __declspec(dllimport) type __stdcall
117#endif
118#else /* !WIN32 */
119#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
120#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
121#else
122#define CJSON_PUBLIC(type) type
123#endif
124#endif
125
126/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
127 * This is to prevent stack overflows. */
128#ifndef CJSON_NESTING_LIMIT
129#define CJSON_NESTING_LIMIT 1000
130#endif
131
132/* returns the version of cJSON as a string */
133CJSON_PUBLIC(const char*) cJSON_Version(void);
134
135/* Supply malloc, realloc and free functions to cJSON */
136CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
137
138/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
139/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
140CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
141/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
142/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error. If not, then cJSON_GetErrorPtr() does the job. */
143CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
144
145/* Render a cJSON entity to text for transfer/storage. */
146CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
147/* Render a cJSON entity to text for transfer/storage without any formatting. */
148CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
149/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
150CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
151/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
152/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
153CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
154/* Delete a cJSON entity and all subentities. */
155CJSON_PUBLIC(void) cJSON_Delete(cJSON *c);
156
157/* Returns the number of items in an array (or object). */
158CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
159/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
160CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
161/* Get item "string" from object. Case insensitive. */
162CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
163CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
164CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
165/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
166CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
167
168/* These functions check the type of an item */
169CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
170CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
171CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
172CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
173CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
174CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
175CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
176CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
177CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
178CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
179
180/* These calls create a cJSON item of the appropriate type. */
181CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
182CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
183CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
184CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
185CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
186CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
187/* raw json */
188CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
189CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
190CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
191
192/* These utilities create an Array of count items. */
193CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
194CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
195CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
196CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count);
197
198/* Append item to the specified array/object. */
199CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item);
200CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
201/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
202 * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
203 * writing to `item->string` */
204CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
205/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
206CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
207CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
208
209/* Remove/Detatch items from Arrays/Objects. */
210CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
211CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
212CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
213CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
214CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
215CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
216CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
217
218/* Update array items. */
219CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
220CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
221CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
222CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
223CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
224
225/* Duplicate a cJSON item */
226CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
227/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
228need to be released. With recurse!=0, it will duplicate any children connected to the item.
229The item->next and ->prev pointers are always zero on return from Duplicate. */
230/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
231 * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
232CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
233
234
235CJSON_PUBLIC(void) cJSON_Minify(char *json);
236
237/* Macros for creating things quickly. */
238#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
239#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
240#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
241#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
242#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
243#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
244#define cJSON_AddRawToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateRaw(s))
245
246/* When assigning an integer value, it needs to be propagated to valuedouble too. */
247#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
248/* helper for the cJSON_SetNumberValue macro */
249CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
250#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
251
252/* Macro for iterating over an array or object */
253#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
254
255/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
256CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
257CJSON_PUBLIC(void) cJSON_free(void *object);
258
259#ifdef __cplusplus
260}
261#endif
262
263#endif \ No newline at end of file
diff --git a/source/http.c b/source/http.c new file mode 100644 index 0000000..1979e22 --- /dev/null +++ b/source/http.c
@@ -0,0 +1,359 @@
1/*
2 * Copyright (C) 2008 Tantric
3 * Copyright (C) 2012 Pedro Aguiar
4 * Copyright (C) 2017 hatkirby
5 *
6 * Originally part of the WiiTweet project, which was distributed under the
7 * GPL.
8 */
9#include "http.h"
10#include <gccore.h>
11#include <network.h>
12#include <unistd.h>
13#include <fcntl.h>
14#include <ogcsys.h>
15#include <ogc/lwp_watchdog.h>
16#include <sys/errno.h>
17#include <string.h>
18#include <stdio.h>
19
20#define TCP_CONNECT_TIMEOUT 4000
21#define TCP_SEND_SIZE (32 * 1024)
22#define TCP_RECV_SIZE (32 * 1024)
23#define TCP_BLOCK_RECV_TIMEOUT 4000
24#define TCP_BLOCK_SEND_TIMEOUT 4000
25#define TCP_BLOCK_SIZE 1024
26#define HTTP_TIMEOUT 10000
27#define IOS_O_NONBLOCK 0x04
28
29static int tcpWrite(
30 bool secure,
31 void* firstParam,
32 const u8* buffer,
33 u32 length)
34{
35 int left = length;
36 int sent = 0;
37 int step = 0;
38
39 u64 t = gettime();
40 while (left)
41 {
42 if (ticks_to_millisecs(diff_ticks(t, gettime())) > TCP_BLOCK_SEND_TIMEOUT)
43 {
44 return HTTPR_ERR_TIMEOUT;
45 }
46
47 int block = left;
48 if (block > TCP_SEND_SIZE)
49 {
50 block = TCP_SEND_SIZE;
51 }
52
53 int result;
54 if (secure)
55 {
56 result = wolfSSL_write(*(WOLFSSL**)firstParam, buffer, block);
57 } else {
58 result = net_write(*(s32*)firstParam, buffer, block);
59 }
60
61 if ((result == 0) || (result == -56))
62 {
63 usleep(20 * 1000);
64
65 continue;
66 }
67
68 if (result < 0)
69 {
70 break;
71 }
72
73 sent += result;
74 left -= result;
75 buffer += result;
76 usleep(100);
77
78 if ((sent / TCP_BLOCK_SIZE) > step)
79 {
80 t = gettime();
81 step++;
82 }
83 }
84
85 if (left == 0)
86 {
87 return HTTPR_OK;
88 } else {
89 return HTTPR_ERR_WRITE;
90 }
91}
92
93static int tcpRead(
94 bool secure,
95 void* firstParam,
96 char* buffer,
97 u16 maxLength)
98{
99 u64 startTime = gettime();
100 u16 cur = 0;
101
102 while (cur < maxLength)
103 {
104 if (ticks_to_millisecs(diff_ticks(startTime, gettime())) > HTTP_TIMEOUT)
105 {
106 return HTTPR_ERR_TIMEOUT;
107 }
108
109 u32 result;
110 if (secure)
111 {
112 result = wolfSSL_read(*(WOLFSSL**)firstParam, &buffer[cur], 1);
113 } else {
114 result = net_read(*(s32*)firstParam, &buffer[cur], 1);
115 }
116
117 if (result == -EAGAIN)
118 {
119 usleep(20 * 1000);
120
121 continue;
122 }
123
124 if (result <= 0)
125 {
126 break;
127 }
128
129 if ((cur > 0) && (buffer[cur-1] == '\r') && (buffer[cur] == '\n'))
130 {
131 buffer[cur-1] = 0;
132
133 return HTTPR_OK;
134 }
135
136 cur++;
137 startTime = gettime();
138 usleep(100);
139 }
140
141 return HTTPR_ERR_RECEIVE;
142}
143
144int submitToApi(
145 const char* endpoint,
146 WOLFSSL_CTX* sslContext,
147 cJSON* data,
148 const char* username,
149 const char* password)
150{
151 // Form request body.
152 cJSON* jRequestBody = cJSON_CreateObject();
153
154 cJSON_AddItemToObject(jRequestBody, "game", data);
155
156 cJSON_AddItemToObject(
157 jRequestBody,
158 "username",
159 cJSON_CreateString(username));
160
161 cJSON_AddItemToObject(
162 jRequestBody,
163 "password",
164 cJSON_CreateString(password));
165
166 const char* requestBody = cJSON_PrintUnformatted(jRequestBody);
167
168 // Gather data from endpoint URL.
169 char httpHost[64];
170 char httpPath[256];
171 int httpPort = 80;
172 bool secure = false;
173
174 if (!strncasecmp(endpoint, "https://", 8))
175 {
176 endpoint += 8;
177 secure = true;
178 httpPort = 443;
179 } else if (!strncasecmp(endpoint, "http://", 7))
180 {
181 endpoint += 7;
182 } else {
183 return 10;
184 }
185
186 char* solidus = strchr(endpoint, '/');
187 if ((solidus == NULL) || (solidus[0] == 0))
188 {
189 return 11;
190 }
191
192 char* colon = strchr(endpoint, ':');
193 if (colon != NULL)
194 {
195 snprintf(httpHost, colon - endpoint + 1, "%s", endpoint);
196 sscanf(colon + 1, "%d", &httpPort);
197 } else {
198 snprintf(httpHost, solidus - endpoint + 1, "%s", endpoint);
199 }
200
201 strcpy(httpPath, solidus);
202
203 // Connect to endpoint.
204 printf("Connecting...\n");
205
206 s32 socket = net_socket(PF_INET, SOCK_STREAM, IPPROTO_IP);
207 if (socket < 0)
208 {
209 return HTTPR_ERR_CONNECT;
210 }
211
212 if (!secure)
213 {
214 int result = net_fcntl(socket, F_GETFL, 0);
215 if (result < 0)
216 {
217 net_close(socket);
218
219 return HTTPR_ERR_CONNECT;
220 }
221
222 if (net_fcntl(socket, F_SETFL, result | IOS_O_NONBLOCK))
223 {
224 net_close(socket);
225
226 return HTTPR_ERR_CONNECT;
227 }
228 }
229
230 struct sockaddr_in sa;
231 memset(&sa, 0, sizeof(struct sockaddr_in));
232 sa.sin_family = PF_INET;
233 sa.sin_len = sizeof(struct sockaddr_in);
234 sa.sin_port = htons(httpPort);
235
236 struct in_addr inAddr;
237 if ((strlen(httpHost) < 16) && (inet_aton(httpHost, &inAddr)))
238 {
239 sa.sin_addr.s_addr = inAddr.s_addr;
240 } else {
241 struct hostent* hp = net_gethostbyname(httpHost);
242 if (!hp || (hp->h_addrtype != PF_INET))
243 {
244 return HTTPR_ERR_CONNECT;
245 }
246
247 memcpy(
248 (char*) &sa.sin_addr,
249 hp->h_addr_list[0],
250 hp->h_length);
251 }
252
253 u64 time1 = ticks_to_secs(gettime());
254 s32 connectResult;
255 do
256 {
257 connectResult = net_connect(
258 socket,
259 (struct sockaddr*) &sa,
260 sizeof(sa));
261
262 if (ticks_to_secs(gettime()) - time1 > TCP_CONNECT_TIMEOUT*1000)
263 {
264 break;
265 }
266 } while (connectResult != -EISCONN);
267
268 if (connectResult != -EISCONN)
269 {
270 net_close(socket);
271
272 return HTTPR_ERR_CONNECT;
273 }
274
275 // Initialize SSL, if necessary.
276 WOLFSSL* sslHandle = 0;
277 if (secure)
278 {
279 sslHandle = wolfSSL_new(sslContext);
280 if (sslHandle == NULL)
281 {
282 net_close(socket);
283
284 return HTTPR_ERR_SSL;
285 }
286
287 wolfSSL_set_fd(sslHandle, socket);
288 }
289
290 // Send request.
291 printf("Sending...\n");
292
293 void* firstParam = 0;
294
295 if (secure)
296 {
297 firstParam = &sslHandle;
298 } else {
299 firstParam = &socket;
300 }
301
302 char requestHeader[1024];
303 char* r = requestHeader;
304 r += sprintf(r, "POST %s HTTP/1.1\r\n", httpPath);
305 r += sprintf(r, "Host: %s\r\n", httpHost);
306 r += sprintf(r, "Content-Type: application/json\r\n");
307 r += sprintf(r, "Content-Length: %d\r\n\r\n", strlen(requestBody));
308
309 int result = tcpWrite(
310 secure,
311 firstParam,
312 (u8*) requestHeader,
313 strlen(requestHeader));
314 if (result != HTTPR_OK)
315 {
316 return result;
317 }
318
319 result = tcpWrite(
320 secure,
321 firstParam,
322 (u8*) requestBody,
323 strlen(requestBody));
324
325 if (result != HTTPR_OK)
326 {
327 return result;
328 }
329
330 // Read response.
331 char line[1024];
332 int httpStatus = 404;
333 while (!tcpRead(secure, firstParam, line, 1024))
334 {
335 if (!line[0])
336 {
337 break;
338 }
339
340 sscanf(line, "HTTP/1.%*u %u", &httpStatus);
341 }
342
343 if (httpStatus != 200)
344 {
345 return HTTPR_ERR_STATUS;
346 }
347
348 // Clean up.
349 if (secure)
350 {
351 wolfSSL_free(sslHandle);
352 }
353
354 net_close(socket);
355
356 cJSON_Delete(jRequestBody);
357
358 return HTTPR_OK;
359}
diff --git a/source/http.h b/source/http.h new file mode 100644 index 0000000..9597a1d --- /dev/null +++ b/source/http.h
@@ -0,0 +1,37 @@
1/*
2 * Copyright (C) 2008 Tantric
3 * Copyright (C) 2012 Pedro Aguiar
4 * Copyright (C) 2017 hatkirby
5 *
6 * Originally part of the WiiTweet project, which was distributed under the
7 * GPL.
8 */
9#ifndef HTTP_H_A46C206E
10#define HTTP_H_A46C206E
11
12#include "cJSON.h"
13#include <wolfssl/options.h>
14#include <wolfssl/ssl.h>
15
16typedef enum {
17 HTTPR_OK,
18 HTTPR_ERR_CONNECT,
19 HTTPR_ERR_TIMEOUT,
20 HTTPR_ERR_WRITE,
21 HTTPR_ERR_RECEIVE,
22 HTTPR_ERR_SSL,
23 HTTPR_ERR_STATUS
24} http_res;
25
26/**
27 * Submits a JSON request to a web service. Takes ownership of the cJSON object,
28 * because it needs to embed authentication data in it.
29 */
30int submitToApi(
31 const char* endpoint,
32 WOLFSSL_CTX* sslContext,
33 cJSON* data,
34 const char* username,
35 const char* password);
36
37#endif /* end of include guard: HTTP_H_A46C206E */
diff --git a/source/main.c b/source/main.c index 3806106..eb5072e 100644 --- a/source/main.c +++ b/source/main.c
@@ -11,10 +11,14 @@
11#include <stdlib.h> 11#include <stdlib.h>
12#include <unistd.h> 12#include <unistd.h>
13#include <string.h> 13#include <string.h>
14#include <fat.h>
15#include "cJSON.h"
14#include "link.h" 16#include "link.h"
15#include "encoding.h" 17#include "encoding.h"
16#include "multiboot.h" 18#include "multiboot.h"
17#include "pokemon.h" 19#include "pokemon.h"
20#include "http.h"
21#include "netinf.h"
18 22
19void printmain() 23void printmain()
20{ 24{
@@ -65,8 +69,75 @@ void fatalError(char *msg)
65 exit(0); 69 exit(0);
66} 70}
67 71
72cJSON* getConfig()
73{
74 FILE* fp = fopen("/gen3uploader.cfg", "r");
75 if (!fp)
76 {
77 fatalError("ERROR: Could not find config file!\n");
78 }
79
80 fseek(fp, 0L, SEEK_END);
81 long lSize = ftell(fp);
82 rewind(fp);
83
84 char* buffer = calloc(1, lSize+1);
85 if (!buffer)
86 {
87 fclose(fp);
88 fatalError("ERROR: Could not allocate memory.\n");
89 }
90
91 if (fread(buffer, lSize, 1, fp) != 1)
92 {
93 fclose(fp);
94 free(buffer);
95 fatalError("ERROR: Could not read config file.\n");
96 }
97
98 cJSON* config = cJSON_Parse(buffer);
99
100 fclose(fp);
101 free(buffer);
102
103 return config;
104}
105
68void* extractor(void* userdata) 106void* extractor(void* userdata)
69{ 107{
108 cJSON* config = (cJSON*)userdata;
109
110 WOLFSSL_CTX* sslContext = 0;
111 if (cJSON_HasObjectItem(config, "certificate"))
112 {
113 wolfSSL_Init();
114
115 sslContext = wolfSSL_CTX_new(wolfTLSv1_client_method());
116 if (sslContext == NULL)
117 {
118 fatalError("wolfSSL_CTX_new error.\n");
119 }
120
121 if (wolfSSL_CTX_load_verify_locations(
122 sslContext,
123 cJSON_GetObjectItem(config, "certificate")->valuestring,
124 0) != SSL_SUCCESS)
125 {
126 fatalError("Error loading certificate file.\n");
127 }
128 }
129
130 while (!initializeNetwork())
131 {
132 printf("Could not initialize network.\n");
133 printf("Press A to try again, press B to exit.\n");
134
135 if (waitForButtons(PAD_BUTTON_A | PAD_BUTTON_B) == PAD_BUTTON_B)
136 {
137 endproc();
138 }
139 }
140
70 for (;;) 141 for (;;)
71 { 142 {
72 printmain(); 143 printmain();
@@ -174,6 +245,17 @@ void* extractor(void* userdata)
174 245
175 sendMsg(1); 246 sendMsg(1);
176 247
248 cJSON* root = cJSON_CreateObject();
249
250 cJSON_AddItemToObject(
251 root,
252 "playerName",
253 cJSON_CreateString(d_trainerName));
254
255 cJSON_AddNumberToObject(root, "playerId", trainerId);
256 cJSON_AddNumberToObject(root, "gameId", gameId);
257 cJSON_AddNumberToObject(root, "language", gameLanguage);
258
177 // Get Pokédex data 259 // Get Pokédex data
178 u32 pokedexSeen[13]; 260 u32 pokedexSeen[13];
179 u32 pokedexCaught[13]; 261 u32 pokedexCaught[13];
@@ -208,6 +290,8 @@ void* extractor(void* userdata)
208 290
209 u32 partyCount = getMsg(); 291 u32 partyCount = getMsg();
210 292
293 cJSON* jParty = cJSON_CreateArray();
294
211 for (u32 i = 0; i < partyCount; i++) 295 for (u32 i = 0; i < partyCount; i++)
212 { 296 {
213 usleep(5000); 297 usleep(5000);
@@ -235,22 +319,144 @@ void* extractor(void* userdata)
235 pki->key[5], 319 pki->key[5],
236 pki->key[6]); 320 pki->key[6]);
237 321
238 printf("Species: %d\n", __builtin_bswap16(pki->species)); 322 cJSON* jPoke = cJSON_CreateObject();
239 printf("Nickname: %s\n", d_pokename); 323
240 printf("OT: %s\n", d_otName); 324 cJSON_AddNumberToObject(
241 printf("Level: %d\n", pki->level); 325 jPoke,
242 printf("HP: %ld\n", __builtin_bswap32(pki->hp)); 326 "species",
243 printf("Attack: %ld\n", __builtin_bswap32(pki->attack)); 327 __builtin_bswap16(pki->species));
244 printf("Defense: %ld\n", __builtin_bswap32(pki->defense)); 328
245 printf("Special Attack: %ld\n", __builtin_bswap32(pki->spAttack)); 329 cJSON_AddItemToObject(
246 printf("Special Defense: %ld\n", __builtin_bswap32(pki->spDefense)); 330 jPoke,
247 printf("Speed: %ld\n", __builtin_bswap32(pki->speed)); 331 "nickname",
248 printf("Key: %s\n", d_key); 332 cJSON_CreateString(d_pokename));
249 333
250 printf("\n"); 334 cJSON_AddItemToObject(
335 jPoke,
336 "otName",
337 cJSON_CreateString(d_otName));
338
339 cJSON_AddNumberToObject(
340 jPoke,
341 "otId",
342 __builtin_bswap16(pki->otId));
343
344 cJSON_AddNumberToObject(
345 jPoke,
346 "level",
347 pki->level);
348
349 cJSON_AddNumberToObject(
350 jPoke,
351 "hp",
352 __builtin_bswap32(pki->hp));
353
354 cJSON_AddNumberToObject(
355 jPoke,
356 "attack",
357 __builtin_bswap32(pki->attack));
358
359 cJSON_AddNumberToObject(
360 jPoke,
361 "defense",
362 __builtin_bswap32(pki->defense));
363
364 cJSON_AddNumberToObject(
365 jPoke,
366 "speed",
367 __builtin_bswap32(pki->speed));
368
369 cJSON_AddNumberToObject(
370 jPoke,
371 "spAttack",
372 __builtin_bswap32(pki->spAttack));
373
374 cJSON_AddNumberToObject(
375 jPoke,
376 "spDefense",
377 __builtin_bswap32(pki->spDefense));
378
379 cJSON_AddItemToObject(
380 jPoke,
381 "key",
382 cJSON_CreateString(d_key));
383
384 cJSON_AddNumberToObject(
385 jPoke,
386 "experience",
387 __builtin_bswap32(pki->experience));
388
389 cJSON_AddNumberToObject(
390 jPoke,
391 "heldItem",
392 __builtin_bswap16(pki->heldItem));
393
394 cJSON* jMoves = cJSON_CreateArray();
395
396 for (int j=0; j<4; j++)
397 {
398 if (pki->moves[j] != 0)
399 {
400 cJSON* jMove = cJSON_CreateObject();
401
402 cJSON_AddNumberToObject(
403 jMove,
404 "id",
405 __builtin_bswap16(pki->moves[j]));
406
407 cJSON_AddNumberToObject(
408 jMove,
409 "ppBonuses",
410 (pki->ppBonuses >> (2*j)) & 3);
411
412 cJSON_AddItemToArray(jMoves, jMove);
413 } else {
414 break;
415 }
416 }
417
418 cJSON_AddItemToObject(
419 jPoke,
420 "moves",
421 jMoves);
422
423 if (pki->otGender)
424 {
425 cJSON_AddStringToObject(jPoke, "otGender", "female");
426 } else {
427 cJSON_AddStringToObject(jPoke, "otGender", "male");
428 }
429
430 cJSON_AddNumberToObject(
431 jPoke,
432 "metLevel",
433 pki->metLevel);
434
435 cJSON_AddNumberToObject(
436 jPoke,
437 "metLocation",
438 pki->metLocation);
439
440 cJSON_AddItemToArray(jParty, jPoke);
251 } 441 }
252 442
253 waitForButtons(PAD_BUTTON_START); 443 cJSON_AddItemToObject(root, "party", jParty);
444
445 char *rendered = cJSON_Print(root);
446 printf("%s\n", rendered);
447
448 waitForButtons(PAD_BUTTON_A);
449
450 int result = submitToApi(
451 cJSON_GetObjectItem(config, "url")->valuestring,
452 sslContext,
453 root,
454 cJSON_GetObjectItem(config, "username")->valuestring,
455 cJSON_GetObjectItem(config, "password")->valuestring);
456
457 printf("Result: %d\n", result);
458
459 waitForButtons(PAD_BUTTON_A);
254 } 460 }
255 461
256 return NULL; 462 return NULL;
@@ -276,6 +482,14 @@ int main(int argc, char *argv[])
276 VIDEO_ClearFrameBuffer(rmode, xfb, COLOR_BLACK); 482 VIDEO_ClearFrameBuffer(rmode, xfb, COLOR_BLACK);
277 PAD_Init(); 483 PAD_Init();
278 484
485 if (!fatInitDefault())
486 {
487 printmain();
488 fatalError("ERROR: Cannot find config file!\n");
489 }
490
491 cJSON* config = getConfig();
492
279 initLink(); 493 initLink();
280 494
281 lwp_t extractorHandle = (lwp_t)NULL; 495 lwp_t extractorHandle = (lwp_t)NULL;
@@ -283,7 +497,7 @@ int main(int argc, char *argv[])
283 LWP_CreateThread( 497 LWP_CreateThread(
284 &extractorHandle, // thread handle 498 &extractorHandle, // thread handle
285 extractor, // code 499 extractor, // code
286 NULL, // userdata 500 config, // userdata
287 NULL, // stack base 501 NULL, // stack base
288 16*1024, // stack size 502 16*1024, // stack size
289 LWP_PRIO_HIGHEST); // thread priority 503 LWP_PRIO_HIGHEST); // thread priority
diff --git a/source/netinf.c b/source/netinf.c new file mode 100644 index 0000000..4e4ec6f --- /dev/null +++ b/source/netinf.c
@@ -0,0 +1,161 @@
1/*
2 * Copyright (C) 2008 Tantric
3 * Copyright (C) 2012 Pedro Aguiar
4 * Copyright (C) 2017 hatkirby
5 *
6 * Originally part of the WiiTweet project, which was distributed under the
7 * GPL.
8 */
9#include "netinf.h"
10#include <gccore.h>
11#include <network.h>
12#include <ogc/lwp_watchdog.h>
13#include <sys/errno.h>
14#include <unistd.h>
15#include <string.h>
16#include <stdio.h>
17
18static bool networkInit = false;
19static lwp_t networkThread = LWP_THREAD_NULL;
20static u8 netStack[32768] ATTRIBUTE_ALIGN(32);
21static char wiiIP[16] = {0};
22static bool netHalt = false;
23
24static void* interface(void* arg)
25{
26 static bool prevInit = false;
27
28 while (!netHalt)
29 {
30 int retry = 5;
31 int result = -1;
32
33 while ((retry > 0) && (!netHalt))
34 {
35 if (prevInit)
36 {
37 net_deinit();
38
39 for (int i=0; (i<400) && !netHalt; i++)
40 {
41 if (net_get_status() != -EBUSY)
42 {
43 usleep(2000);
44 net_wc24cleanup();
45 prevInit = false;
46 usleep(20000);
47
48 break;
49 }
50
51 usleep(20000);
52 }
53 }
54
55 usleep(2000);
56
57 if (net_init_async(NULL, NULL))
58 {
59 sleep(1);
60
61 retry--;
62
63 continue;
64 }
65
66 result = net_get_status();
67 for (int wait = 400; (wait > 0) && (result == -EBUSY) && !netHalt; wait++)
68 {
69 usleep(20000);
70
71 result = net_get_status();
72 }
73
74 if (result == 0)
75 {
76 break;
77 }
78
79 retry--;
80
81 usleep(2000);
82 }
83
84 if (result == 0)
85 {
86 struct in_addr hostip;
87 hostip.s_addr = net_gethostip();
88
89 if (hostip.s_addr)
90 {
91 strcpy(wiiIP, inet_ntoa(hostip));
92 networkInit = true;
93 prevInit = true;
94 }
95 }
96
97 if (!netHalt)
98 {
99 LWP_SuspendThread(networkThread);
100 }
101 }
102
103 return NULL;
104}
105
106static void startNetworkThread()
107{
108 netHalt = false;
109
110 if (networkThread == LWP_THREAD_NULL)
111 {
112 LWP_CreateThread(&networkThread, interface, NULL, netStack, 8192, 40);
113 } else {
114 LWP_ResumeThread(networkThread);
115 }
116}
117
118static void stopNetworkThread()
119{
120 if ((networkThread == LWP_THREAD_NULL)
121 || (!LWP_ThreadIsSuspended(networkThread)))
122 {
123 return;
124 }
125
126 netHalt = true;
127
128 LWP_ResumeThread(networkThread);
129 LWP_JoinThread(networkThread, NULL);
130
131 networkThread = LWP_THREAD_NULL;
132}
133
134bool initializeNetwork()
135{
136 stopNetworkThread();
137
138 if (networkInit && (net_gethostip() > 0))
139 {
140 return true;
141 }
142
143 networkInit = false;
144
145 printf("Initializing network...\n");
146
147 u64 start = gettime();
148 startNetworkThread();
149
150 while (!LWP_ThreadIsSuspended(networkThread))
151 {
152 usleep(50 * 1000);
153
154 if (diff_sec(start, gettime()) > 10)
155 {
156 break;
157 }
158 }
159
160 return networkInit;
161}
diff --git a/source/netinf.h b/source/netinf.h new file mode 100644 index 0000000..dd280ad --- /dev/null +++ b/source/netinf.h
@@ -0,0 +1,16 @@
1/*
2 * Copyright (C) 2008 Tantric
3 * Copyright (C) 2012 Pedro Aguiar
4 * Copyright (C) 2017 hatkirby
5 *
6 * Originally part of the WiiTweet project, which was distributed under the
7 * GPL.
8 */
9#ifndef NETWORK_H_93BC9F7D
10#define NETWORK_H_93BC9F7D
11
12#include <stdbool.h>
13
14bool initializeNetwork();
15
16#endif /* end of include guard: NETWORK_H_93BC9F7D */
diff --git a/vendor/include/.gitkeep b/vendor/include/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/vendor/include/.gitkeep
diff --git a/vendor/lib/.gitkeep b/vendor/lib/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/vendor/lib/.gitkeep