|
@@ -12,6 +12,7 @@ Ultralightweight JSON parser in ANSI C.
|
|
* [Working with the data structure](#working-with-the-data-structure)
|
|
* [Working with the data structure](#working-with-the-data-structure)
|
|
* [Parsing JSON](#parsing-json)
|
|
* [Parsing JSON](#parsing-json)
|
|
* [Printing JSON](#printing-json)
|
|
* [Printing JSON](#printing-json)
|
|
|
|
+ * [Example](#example)
|
|
* [Some JSON](#some-json)
|
|
* [Some JSON](#some-json)
|
|
* [Here's the structure](#heres-the-structure)
|
|
* [Here's the structure](#heres-the-structure)
|
|
* [Caveats](#caveats)
|
|
* [Caveats](#caveats)
|
|
@@ -252,6 +253,216 @@ If you have a rough idea of how big your resulting string will be, you can use `
|
|
|
|
|
|
These dynamic buffer allocations can be completely avoided by using `cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)`. It takes a buffer to a pointer to print to and it's length. If the length is reached, printing will fail and it returns `0`. In case of success, `1` is returned. Note that you should provide 5 bytes more than is actually needed, because cJSON is not 100% accurate in estimating if the provided memory is enough.
|
|
These dynamic buffer allocations can be completely avoided by using `cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)`. It takes a buffer to a pointer to print to and it's length. If the length is reached, printing will fail and it returns `0`. In case of success, `1` is returned. Note that you should provide 5 bytes more than is actually needed, because cJSON is not 100% accurate in estimating if the provided memory is enough.
|
|
|
|
|
|
|
|
+### Example
|
|
|
|
+In this example we want to build and parse the following JSON:
|
|
|
|
+
|
|
|
|
+```json
|
|
|
|
+{
|
|
|
|
+ "name": "Awesome 4K",
|
|
|
|
+ "resolutions": [
|
|
|
|
+ {
|
|
|
|
+ "width": 1280,
|
|
|
|
+ "height": 720
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ "width": 1920,
|
|
|
|
+ "height": 1080
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ "width": 3840,
|
|
|
|
+ "height": 2160
|
|
|
|
+ }
|
|
|
|
+ ]
|
|
|
|
+}
|
|
|
|
+```
|
|
|
|
+
|
|
|
|
+#### Printing
|
|
|
|
+Let's build the above JSON and print it to a string:
|
|
|
|
+```c
|
|
|
|
+//create a monitor with a list of supported resolutions
|
|
|
|
+char* create_monitor(void)
|
|
|
|
+{
|
|
|
|
+ const unsigned int resolution_numbers[3][2] = {
|
|
|
|
+ {1280, 720},
|
|
|
|
+ {1920, 1080},
|
|
|
|
+ {3840, 2160}
|
|
|
|
+ };
|
|
|
|
+ char *string = NULL;
|
|
|
|
+ cJSON *name = NULL;
|
|
|
|
+ cJSON *resolutions = NULL;
|
|
|
|
+ cJSON *resolution = NULL;
|
|
|
|
+ cJSON *width = NULL;
|
|
|
|
+ cJSON *height = NULL;
|
|
|
|
+ size_t index = 0;
|
|
|
|
+
|
|
|
|
+ cJSON *monitor = cJSON_CreateObject();
|
|
|
|
+ if (monitor == NULL)
|
|
|
|
+ {
|
|
|
|
+ goto end;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ name = cJSON_CreateString("Awesome 4K");
|
|
|
|
+ if (name == NULL)
|
|
|
|
+ {
|
|
|
|
+ goto end;
|
|
|
|
+ }
|
|
|
|
+ /* after creation was successful, immediately add it to the monitor,
|
|
|
|
+ * thereby transfering ownership of the pointer to it */
|
|
|
|
+ cJSON_AddItemToObject(monitor, "name", name);
|
|
|
|
+
|
|
|
|
+ resolutions = cJSON_CreateArray();
|
|
|
|
+ if (resolutions == NULL)
|
|
|
|
+ {
|
|
|
|
+ goto end;
|
|
|
|
+ }
|
|
|
|
+ cJSON_AddItemToObject(monitor, "resolutions", resolutions);
|
|
|
|
+
|
|
|
|
+ for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index)
|
|
|
|
+ {
|
|
|
|
+ resolution = cJSON_CreateObject();
|
|
|
|
+ if (resolution == NULL)
|
|
|
|
+ {
|
|
|
|
+ goto end;
|
|
|
|
+ }
|
|
|
|
+ cJSON_AddItemToArray(resolutions, resolution);
|
|
|
|
+
|
|
|
|
+ width = cJSON_CreateNumber(resolution_numbers[index][0]);
|
|
|
|
+ if (width == NULL)
|
|
|
|
+ {
|
|
|
|
+ goto end;
|
|
|
|
+ }
|
|
|
|
+ cJSON_AddItemToObject(resolution, "width", width);
|
|
|
|
+
|
|
|
|
+ height = cJSON_CreateNumber(resolution_numbers[index][1]);
|
|
|
|
+ if (height == NULL)
|
|
|
|
+ {
|
|
|
|
+ goto end;
|
|
|
|
+ }
|
|
|
|
+ cJSON_AddItemToObject(resolution, "height", height);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ string = cJSON_Print(monitor);
|
|
|
|
+ if (string == NULL)
|
|
|
|
+ {
|
|
|
|
+ fprintf(stderr, "Failed to print monitor.\n");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+end:
|
|
|
|
+ cJSON_Delete(monitor);
|
|
|
|
+ return string;
|
|
|
|
+}
|
|
|
|
+```
|
|
|
|
+
|
|
|
|
+Alternatively we can use the `cJSON_Add...ToObject` helper functions to make our lifes a little easier:
|
|
|
|
+```c
|
|
|
|
+char *create_monitor_with_helpers(void)
|
|
|
|
+{
|
|
|
|
+ const unsigned int resolution_numbers[3][2] = {
|
|
|
|
+ {1280, 720},
|
|
|
|
+ {1920, 1080},
|
|
|
|
+ {3840, 2160}
|
|
|
|
+ };
|
|
|
|
+ char *string = NULL;
|
|
|
|
+ cJSON *resolutions = NULL;
|
|
|
|
+ size_t index = 0;
|
|
|
|
+
|
|
|
|
+ cJSON *monitor = cJSON_CreateObject();
|
|
|
|
+
|
|
|
|
+ if (cJSON_AddStringToObject(monitor, "name", "Awesome 4K") == NULL)
|
|
|
|
+ {
|
|
|
|
+ goto end;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ resolutions = cJSON_AddArrayToObject(monitor, "resolutions");
|
|
|
|
+ if (resolutions == NULL)
|
|
|
|
+ {
|
|
|
|
+ goto end;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index)
|
|
|
|
+ {
|
|
|
|
+ cJSON *resolution = cJSON_CreateObject();
|
|
|
|
+
|
|
|
|
+ if (cJSON_AddNumberToObject(resolution, "width", resolution_numbers[index][0]) == NULL)
|
|
|
|
+ {
|
|
|
|
+ goto end;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if(cJSON_AddNumberToObject(resolution, "height", resolution_numbers[index][1]) == NULL)
|
|
|
|
+ {
|
|
|
|
+ goto end;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ cJSON_AddItemToArray(resolutions, resolution);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ string = cJSON_Print(monitor);
|
|
|
|
+ if (string == NULL) {
|
|
|
|
+ fprintf(stderr, "Failed to print monitor.\n");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+end:
|
|
|
|
+ cJSON_Delete(monitor);
|
|
|
|
+ return string;
|
|
|
|
+}
|
|
|
|
+```
|
|
|
|
+
|
|
|
|
+#### Parsing
|
|
|
|
+In this example we will parse a JSON in the above format and check if the monitor supports a Full HD resolution while printing some diagnostic output:
|
|
|
|
+
|
|
|
|
+```c
|
|
|
|
+/* return 1 if the monitor supports full hd, 0 otherwise */
|
|
|
|
+int supports_full_hd(const char * const monitor)
|
|
|
|
+{
|
|
|
|
+ const cJSON *resolution = NULL;
|
|
|
|
+ const cJSON *resolutions = NULL;
|
|
|
|
+ const cJSON *name = NULL;
|
|
|
|
+ int status = 0;
|
|
|
|
+ cJSON *monitor_json = cJSON_Parse(monitor);
|
|
|
|
+ if (monitor_json == NULL)
|
|
|
|
+ {
|
|
|
|
+ const char *error_ptr = cJSON_GetErrorPtr();
|
|
|
|
+ if (error_ptr != NULL)
|
|
|
|
+ {
|
|
|
|
+ fprintf(stderr, "Error before: %s\n", error_ptr);
|
|
|
|
+ }
|
|
|
|
+ status = 0;
|
|
|
|
+ goto end;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ name = cJSON_GetObjectItemCaseSensitive(monitor_json, "name");
|
|
|
|
+ if (cJSON_IsString(name) && (name->valuestring != NULL))
|
|
|
|
+ {
|
|
|
|
+ printf("Checking monitor \"%s\"\n", name->valuestring);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ resolutions = cJSON_GetObjectItemCaseSensitive(monitor_json, "resolutions");
|
|
|
|
+ cJSON_ArrayForEach(resolution, resolutions)
|
|
|
|
+ {
|
|
|
|
+ cJSON *width = cJSON_GetObjectItemCaseSensitive(resolution, "width");
|
|
|
|
+ cJSON *height = cJSON_GetObjectItemCaseSensitive(resolution, "height");
|
|
|
|
+
|
|
|
|
+ if (!cJSON_IsNumber(width) || !cJSON_IsNumber(height))
|
|
|
|
+ {
|
|
|
|
+ status = 0;
|
|
|
|
+ goto end;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if ((width->valuedouble == 1920) && (height->valuedouble == 1080))
|
|
|
|
+ {
|
|
|
|
+ status = 1;
|
|
|
|
+ goto end;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+end:
|
|
|
|
+ cJSON_Delete(monitor_json);
|
|
|
|
+ return status;
|
|
|
|
+}
|
|
|
|
+```
|
|
|
|
+
|
|
|
|
+Note that there are no NULL checks except for the result of `cJSON_Parse` because `cJSON_GetObjectItemCaseSensitive` checks for `NULL` inputs already, so a `NULL` value is just propagated and `cJSON_IsNumber` and `cJSON_IsString` return `0` if the input is `NULL`.
|
|
|
|
+
|
|
### Some JSON:
|
|
### Some JSON:
|
|
|
|
|
|
```json
|
|
```json
|