summaryrefslogtreecommitdiff
path: root/imap/src/c-client/json.c
diff options
context:
space:
mode:
Diffstat (limited to 'imap/src/c-client/json.c')
-rw-r--r--imap/src/c-client/json.c497
1 files changed, 497 insertions, 0 deletions
diff --git a/imap/src/c-client/json.c b/imap/src/c-client/json.c
new file mode 100644
index 00000000..f6d05736
--- /dev/null
+++ b/imap/src/c-client/json.c
@@ -0,0 +1,497 @@
+/*
+ * Copyright 2018 Eduardo Chappa
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+#ifdef STANDALONE
+#include "headers.h"
+#include "mem.h"
+#include "readfile.h"
+#include "json.h"
+#else
+#include <ctype.h>
+#include <stdio.h>
+#include <time.h>
+#include "c-client.h"
+#include "json.h"
+#endif /* STANDALONE */
+
+#define NIL 0
+
+#define json_ws(X) (((X) == ' ' || (X) == '\t' || (X) == '\n' || (X) == '\r') ? 1 : 0)
+
+#define json_skipws(X) for(; json_ws(*(X)); (X)++)
+
+#define json_skipchar(X) { \
+ (X)++; \
+ json_skipws((X)); \
+}
+
+#define json_last_char(X) (((X) == ',' || (X) == ']' || (X) == '}') ? 1 : 0)
+
+JObjType json_number_type(unsigned char *);
+unsigned char *json_strchr(unsigned char *, unsigned char);
+JSON_S *json_parse_work(unsigned char **);
+JSON_S *json_parse_pairs(unsigned char **);
+
+JSON_X *json_value_parse(unsigned char **);
+void json_value_free(JSON_X **);
+
+/* An array is a JSON object where the name is null */
+JSON_S *json_array_parse_work(unsigned char **);
+JSON_S *json_array_parse(unsigned char **);
+void json_array_free(JSON_S **);
+
+#ifdef STANDALONE
+int compare_cstring (unsigned char *,unsigned char *);
+int compare_uchar (unsigned char,unsigned char);
+int compare_ulong (unsigned long,unsigned long);
+
+int compare_ulong (unsigned long l1,unsigned long l2)
+{
+ if (l1 < l2) return -1;
+ if (l1 > l2) return 1;
+ return 0;
+}
+
+int compare_uchar (unsigned char c1,unsigned char c2)
+{
+ return compare_ulong (((c1 >= 'a') && (c1 <= 'z')) ? c1 - ('a' - 'A') : c1,
+ ((c2 >= 'a') && (c2 <= 'z')) ? c2 - ('a' - 'A') : c2);
+}
+
+int compare_cstring (unsigned char *s1,unsigned char *s2)
+{
+ int i;
+ if (!s1) return s2 ? -1 : 0; /* empty string cases */
+ else if (!s2) return 1;
+ for (; *s1 && *s2; s1++,s2++) if ((i = (compare_uchar (*s1,*s2))) != 0) return i;
+ if (*s1) return 1; /* first string is longer */
+ return *s2 ? -1 : 0; /* second string longer : strings identical */
+}
+#endif /* STANDALONE */
+
+/* we are parsing from the text of the json object, so it is
+ * never possible to have a null character, unless something
+ * is corrupt, in whose case we return JNumberError.
+ */
+JObjType json_number_type(unsigned char *s)
+{
+ unsigned char *w = s, *u;
+ int PossibleDecimal, PossibleExponential;
+
+ PossibleDecimal = PossibleExponential = 0;
+
+ if(*w == '+' || *w == '-')
+ w++;
+
+ if (*w == '0'){
+ u = w + 1;
+ if(json_ws(*u)) json_skipws(u);
+ if(json_last_char(*u)) return JLong;
+ else if(*(w+1) == '.'){
+ for(u = w+2; *u >= '0' && *u <= '9'; u++);
+ if(json_ws(*u)) json_skipws(u);
+ if(json_last_char(*u)) return JDecimal;
+ else return JNumberError;
+ }
+ else return JNumberError;
+ }
+
+ if(*w < '1' || *w > '9')
+ return JNumberError;
+
+ u = w + 1;
+ if(json_ws(*u)) json_skipws(u);
+ if(json_last_char(*u)) return JLong;
+ else if (*(w+1) == 'e' || *(w+1) == 'E'){
+ PossibleExponential++;
+ w += 2;
+ }
+ else if(*(w+1) == '.'){
+ PossibleDecimal++;
+ PossibleExponential++;
+ w += 2;
+ } else {
+ for(; *w >= '0' && *w <= '9'; w++);
+ if(*w == '.'){
+ PossibleDecimal++;
+ w++;
+ }
+ else {
+ if(json_ws(*w)) json_skipws(w);
+ if(json_last_char(*w)) return JLong;
+ else return JNumberError;
+ }
+ }
+
+ if(PossibleDecimal){
+ for(; *w >= '0' && *w <= '9'; w++);
+ u = w;
+ if(json_ws(*u)) json_skipws(u);
+ if(json_last_char(*u)) return JDecimal;
+ else if (*w == 'e' || *w == 'E'){
+ PossibleExponential++;
+ w++;
+ }
+ else return JNumberError;
+ }
+
+ if(PossibleExponential){
+ if(*w == '+' || *w == '-')
+ w++;
+ if(*w == '0'){
+ u = w + 1;
+ if(json_ws(*u)) json_skipws(u);
+ if(json_last_char(*u)) return JExponential;
+ else return JNumberError;
+ }
+ if(*w < '1' || *w > '9')
+ return JNumberError;
+ for(; *w >= '0' && *w <= '9'; w++);
+ if(json_ws(*w)) json_skipws(w);
+ if(json_last_char(*w)) return JExponential;
+ else return JNumberError;
+ }
+ return JNumberError; /* never reached */
+}
+
+
+JSON_X *
+json_body_value(JSON_S *j, unsigned char *s)
+{
+ JSON_S *js;
+
+ if(!j || !j->value|| j->value->jtype != JObject) return NIL;
+
+ for(js = (JSON_S *) j->value->value; js ; js = js->next)
+ if(js->name && !compare_cstring(js->name, s))
+ break;
+
+ return js ? js->value : NIL;
+}
+
+unsigned char *
+json_strchr(unsigned char *s, unsigned char c)
+{
+ unsigned char *t, d;
+ int escaped, extended;
+
+ if(c == '\0'){
+ t = s + strlen((char *) s);
+ return t;
+ }
+
+ escaped = extended = 0;
+ for(t = s; (d = *t) != '\0';){
+ if(escaped){
+ if (d == '\"' || d == '\\' || d == '/' || d == 'b'
+ || d == 'f' || d == 'n' || d == 'r' || d == 't'){
+ escaped = 0;
+ t++;
+ continue;
+ }
+ else{
+ if(d == 'u'){
+ escaped = 0;
+ extended = 1;
+ t++;
+ }
+ else
+ return NIL;
+ }
+ }
+ else {
+ if(d == '\\'){
+ escaped = 1;
+ t++;
+ continue;
+ }
+ else if(extended){
+ int i;
+ static char HEX[] = "abcdefABCDEF0123456789";
+
+ if(strlen((char *) t) < 4)
+ return NIL;
+
+ for(i = 0; i < 4; i++){
+ if(!strchr(HEX, *t))
+ return NIL;
+ else
+ t++;
+ }
+ extended = 0;
+ }
+ else if (d == c)
+ break;
+ else t++;
+ }
+ }
+ return (*t == '\0') ? NULL : t;
+}
+
+JSON_X *
+json_value_parse(unsigned char **s)
+{
+ JSON_X *jx;
+ unsigned char *u, *w;
+ unsigned long *l;
+
+ w = *s;
+ json_skipws(w);
+ jx = fs_get(sizeof(JSON_X));
+ memset((void **) jx, 0, sizeof(JSON_X));
+ jx->jtype = JEnd;
+ switch(*w){
+ case '\"': jx->jtype = JString; break;
+ case '{' : jx->jtype = JObject; break;
+ case '[' : jx->jtype = JArray; break;
+ case 'f' : if(strlen((char *) w) > 5
+ && !strncmp((char *) w, "false", 5)){
+ u = w+5;
+ json_skipws(u);
+ if(json_last_char(*u))
+ jx->jtype = JBoolean;
+ }
+ break;
+ case 'n' : if(strlen((char *) w) > 4
+ && !strncmp((char *) w, "null", 4)){
+ u = w+4;
+ json_skipws(u);
+ if(json_last_char(*u))
+ jx->jtype = JNull;
+ }
+ break;
+ case 't' : if(strlen((char *) w) > 4
+ && !strncmp((char *) w, "true", 4)){
+ u = w+4;
+ json_skipws(u);
+ if(json_last_char(*u))
+ jx->jtype = JBoolean;
+ }
+ break;
+ default: jx->jtype = json_number_type(w);
+ break;
+ }
+
+ switch(jx->jtype){
+ case JString: u = json_strchr(w+1, '\"');
+ if(u != NULL){
+ *u = '\0';
+ jx->value = (void *) cpystr((char *) w+1);
+ *u = '\"';
+ json_skipchar(u);
+ w = u;
+ }
+ break;
+
+ case JObject: jx->value = (void *) json_parse(&w);
+ break;
+
+ case JLong : l = fs_get(sizeof(unsigned long));
+ *l = strtoul((char *) w, (char **) &w, 10);
+ jx->value = (void *) l;
+ json_skipws(w);
+ break;
+
+ case JDecimal :
+ case JExponential: l = fs_get(sizeof(double));
+ *l = strtod((char *) w, (char **) &w);
+ jx->value = (void *) l;
+ json_skipws(w);
+ break;
+
+ case JBoolean: if(*w == 't'){
+ jx->value = (void *) cpystr("true");
+ w += 4;
+ }
+ else{
+ jx->value = (void *) cpystr("false");
+ w += 5;
+ }
+ json_skipws(w);
+ break;
+
+ case JNull: jx->value = (void *) cpystr("null");
+ w += 4;
+ json_skipws(w);
+ break;
+
+ case JArray: jx->value = json_array_parse(&w);
+ json_skipchar(w);
+ break;
+
+ default: break; /* let caller handle this */
+ }
+ *s = w;
+ return jx;
+}
+
+JSON_S *
+json_array_parse(unsigned char **s)
+{
+ JSON_S *j;
+ unsigned char *w = *s;
+
+ json_skipws(w);
+ if(*w == '['){
+ json_skipchar(w);
+ j = json_array_parse_work(&w);
+ }
+ *s = w;
+ return j;
+}
+
+JSON_S *
+json_array_parse_work(unsigned char **s)
+{
+ unsigned char *w = *s;
+ JSON_S *j;
+
+ json_skipws(w);
+ j = fs_get(sizeof(JSON_S));
+ memset((void *) j, 0, sizeof(JSON_S));
+ j->value = json_value_parse(&w);
+ json_skipws(w);
+ switch(*w){
+ case ',' : json_skipchar(w);
+ j->next = json_array_parse_work(&w);
+ break;
+
+ case ']' : break;
+ default : json_free(&j);
+ }
+ *s = w;
+ return j;
+}
+
+void
+json_array_free(JSON_S **j)
+{
+ json_free(j);
+}
+
+JSON_S *
+json_parse_pairs(unsigned char **s)
+{
+ JSON_S *j;
+ unsigned char *u, *w = *s;
+
+ json_skipws(w);
+ if(*w++ != '\"')
+ return NIL;
+
+ u = json_strchr(w, '\"');
+ if(!u)
+ return NIL;
+
+ *u = '\0';
+ j = fs_get(sizeof(JSON_S));
+ memset((void *) j, 0, sizeof(JSON_S));
+ j->name = (unsigned char *) cpystr((char *) w);
+
+ *u = '\"';
+ json_skipchar(u);
+ if(*u != ':')
+ return j;
+ json_skipchar(u);
+
+ j->value = json_value_parse(&u);
+ json_skipws(u);
+ if (*u == ','){
+ json_skipchar(u);
+ j->next = json_parse_pairs(&u);
+ }
+ *s = u;
+ return j;
+}
+
+void
+json_value_free(JSON_X **jxp)
+{
+ if(!jxp || !*jxp)
+ return;
+
+ switch((*jxp)->jtype){
+ case JString:
+ case JLong :
+ case JDecimal:
+ case JExponential:
+ case JBoolean:
+ case JNull: fs_give((void **) &(*jxp)->value);
+ break;
+
+ case JArray: json_array_free((JSON_S **) &(*jxp)->value);
+ break;
+
+ case JObject: json_free((JSON_S **) &(*jxp)->value);
+ break;
+
+ default: printf("Unhandled case in json_value_free");
+ exit(1);
+ }
+}
+
+void
+json_free(JSON_S **jp)
+{
+
+ if(jp == NULL || *jp == NULL) return;
+
+ if((*jp)->name) fs_give((void **) &(*jp)->name);
+ if((*jp)->value) json_value_free(&(*jp)->value);
+ if((*jp)->next) json_free(&(*jp)->next);
+ fs_give((void **) jp);
+}
+
+JSON_S *
+json_parse(unsigned char **s)
+{
+ JSON_S *j = NULL;
+ JSON_X *jx;
+ unsigned char *w = *s;
+
+ json_skipws(w);
+ if(*w == '{'){
+ json_skipchar(w);
+ jx = fs_get(sizeof(JSON_X));
+ memset((void *) jx, 0, sizeof(JSON_X));
+ jx->jtype = JObject;
+ jx->value = (void *) json_parse_pairs(&w);
+ j = fs_get(sizeof(JSON_S));
+ memset((void *) j, 0, sizeof(JSON_S));
+ j->value = jx;
+ json_skipws(w);
+ if(*w == '}'){
+ json_skipchar(w);
+ }
+ else
+ json_free(&j);
+ }
+ *s = w;
+ return j;
+}
+
+#ifdef STANDALONE
+int main (int argc, char *argv[])
+{
+ unsigned char *s, *t;
+ JSON_S *json;
+ JSON_X *jx;
+
+ t = NULL;
+ readfile(argv[1], (char **) &t, NULL);
+ s = t;
+ json = json_parse(&s);
+ if(!*s) printf("Success!\n");
+// jx = json_body_value(json, (unsigned char *) "subject");
+// if(jx) printf("subject = %s\n", (char *) jx->value);
+ if(t) fs_give((void **)&t);
+ exit(0);
+}
+#endif /* STANDALONE */