summaryrefslogtreecommitdiffstats
path: root/src/json_plist.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/json_plist.c')
-rw-r--r--src/json_plist.c229
1 files changed, 229 insertions, 0 deletions
diff --git a/src/json_plist.c b/src/json_plist.c
new file mode 100644
index 0000000..e61e3cb
--- /dev/null
+++ b/src/json_plist.c
@@ -0,0 +1,229 @@
+/*
+ * json_plist.c
+ * JSON/property list functions
+ *
+ * Copyright (c) 2013 Nikias Bassen. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <jsmn.h>
+#include <plist/plist.h>
+
+#include "json_plist.h"
+
+static plist_t parse_primitive(const char* js, jsmntok_t* tokens, int* index);
+static plist_t parse_string(const char* js, jsmntok_t* tokens, int* index);
+static plist_t parse_array(const char* js, jsmntok_t* tokens, int* index);
+static plist_t parse_object(const char* js, jsmntok_t* tokens, int* index);
+
+static char* get_string_value(const char* js, jsmntok_t token)
+{
+ int len = (token.end - token.start);
+ char* str = malloc(len+1);
+ memcpy(str, js + token.start, len);
+ str[len] = 0;
+ return str;
+}
+
+static plist_t parse_primitive(const char* js, jsmntok_t* tokens, int* index)
+{
+ if (tokens[*index].type != JSMN_PRIMITIVE) {
+ fprintf(stderr, "%s: ERROR: token type != JSMN_PRIMITIVE?!\n", __func__);
+ return NULL;
+ }
+ plist_t val = NULL;
+ char* strval = get_string_value(js, tokens[*index]);
+ if (strval[0] == 'f') {
+ val = plist_new_bool(0);
+ } else if (strval[0] == 't') {
+ val = plist_new_bool(1);
+ } else if ((strval[0] == '-') || ((strval[0] >= '0') && (strval[0] <= '9'))) {
+ val = plist_new_uint(strtoll(strval, NULL, 10));
+ } else {
+ fprintf(stderr, "%s: WARNING: invalid primitive value '%s' encountered, will return as string\n", __func__, strval);
+ val = plist_new_string(strval);
+ }
+ free(strval);
+ (*index)++;
+ return val;
+}
+
+static plist_t parse_string(const char* js, jsmntok_t* tokens, int* index)
+{
+ if (tokens[*index].type != JSMN_STRING) {
+ fprintf(stderr, "%s: ERROR: token type != JSMN_STRING?!\n", __func__);
+ return NULL;
+ }
+ char* str = get_string_value(js, tokens[*index]);
+ plist_t val = plist_new_string(str);
+ free(str);
+ (*index)++;
+ return val;
+}
+
+static plist_t parse_array(const char* js, jsmntok_t* tokens, int* index)
+{
+ if (tokens[*index].type != JSMN_ARRAY) {
+ fprintf(stderr, "%s: ERROR: token type != JSMN_ARRAY?!\n", __func__);
+ return NULL;
+ }
+ plist_t arr = plist_new_array();
+ int num_tokens = tokens[*index].size;
+ int num;
+ int j = (*index)+1;
+ for (num = 0; num < num_tokens; num++) {
+ plist_t val = NULL;
+ switch (tokens[j].type) {
+ case JSMN_OBJECT:
+ val = parse_object(js, tokens, &j);
+ break;
+ case JSMN_ARRAY:
+ val = parse_array(js, tokens, &j);
+ break;
+ case JSMN_STRING:
+ val = parse_string(js, tokens, &j);
+ break;
+ case JSMN_PRIMITIVE:
+ val = parse_primitive(js, tokens, &j);
+ break;
+ default:
+ break;
+ }
+ if (val) {
+ plist_array_append_item(arr, val);
+ }
+ }
+ *(index) = j;
+ return arr;
+}
+
+static plist_t parse_object(const char* js, jsmntok_t* tokens, int* index)
+{
+ if (tokens[*index].type != JSMN_OBJECT) {
+ fprintf(stderr, "%s: ERROR: token type != JSMN_OBJECT?!\n", __func__);
+ return NULL;
+ }
+ plist_t obj = plist_new_dict();
+ int num_tokens = tokens[*index].size;
+ int num;
+ int j = (*index)+1;
+ for (num = 0; num < num_tokens; num++) {
+ if (tokens[j].type == JSMN_STRING) {
+ char* key = get_string_value(js, tokens[j]);
+ plist_t val = NULL;
+ j++;
+ num++;
+ switch (tokens[j].type) {
+ case JSMN_OBJECT:
+ val = parse_object(js, tokens, &j);
+ break;
+ case JSMN_ARRAY:
+ val = parse_array(js, tokens, &j);
+ break;
+ case JSMN_STRING:
+ val = parse_string(js, tokens, &j);
+ break;
+ case JSMN_PRIMITIVE:
+ val = parse_primitive(js, tokens, &j);
+ break;
+ default:
+ break;
+ }
+ if (val) {
+ plist_dict_set_item(obj, key, val);
+ }
+ free(key);
+ } else {
+ fprintf(stderr, "%s: keys must be of type STRING\n", __func__);
+ return NULL;
+ }
+ }
+ (*index) = j;
+ return obj;
+}
+
+plist_t json_to_plist(const char* json_string)
+{
+ jsmn_parser parser;
+ jsmn_init(&parser);
+ int maxtoks = 256;
+ jsmntok_t *tokens;
+
+ if (!json_string) {
+ fprintf(stderr, "%s: ERROR: no JSON string given.\n", __func__);
+ return NULL;
+ }
+
+ tokens = malloc(sizeof(jsmntok_t)*maxtoks);
+ if (!tokens) {
+ fprintf(stderr, "%s: Out of memory\n", __func__);
+ return NULL;
+ }
+
+ int r = 0;
+reparse:
+ r = jsmn_parse(&parser, json_string, tokens, maxtoks);
+ if (r == JSMN_ERROR_NOMEM) {
+ //printf("not enough tokens (%d), retrying...\n", maxtoks);
+ maxtoks+=256;
+ jsmntok_t* newtokens = realloc(tokens, sizeof(jsmntok_t)*maxtoks);
+ if (newtokens) {
+ tokens = newtokens;
+ goto reparse;
+ }
+ }
+
+ switch(r) {
+ case JSMN_ERROR_NOMEM:
+ fprintf(stderr, "%s: ERROR: Out of memory...\n", __func__);
+ return NULL;
+ case JSMN_ERROR_INVAL:
+ fprintf(stderr, "%s: ERROR: Invalid character inside JSON string\n", __func__);
+ return NULL;
+ case JSMN_ERROR_PART:
+ fprintf(stderr, "%s: ERROR: The string is not a full JSON packet, more bytes expected\n", __func__);
+ return NULL;
+ default:
+ break;
+ }
+
+ int startindex = 0;
+ plist_t plist = NULL;
+ switch (tokens[startindex].type) {
+ case JSMN_PRIMITIVE:
+ plist = parse_primitive(json_string, tokens, &startindex);
+ break;
+ case JSMN_STRING:
+ plist = parse_string(json_string, tokens, &startindex);
+ break;
+ case JSMN_ARRAY:
+ plist = parse_array(json_string, tokens, &startindex);
+ break;
+ case JSMN_OBJECT:
+ plist = parse_object(json_string, tokens, &startindex);
+ break;
+ default:
+ break;
+ }
+
+ free(tokens);
+
+ return plist;
+}
+