ff649f75a07d6754c5a7c75830e7c8b6bebbff46
[citadel.git] / libcitadel / lib / json.c
1 //
2 // JSON data type and serializer for Citadel
3 //
4 // Copyright (c) 1987-2018 by the citadel.org team
5 //
6 // This program is open source software.  Use, duplication, or disclosure
7 // is subject to the terms of the GNU General Public License, version 3.
8
9 #include "sysdep.h"
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <unistd.h>
13 #include <dirent.h>
14 #include <errno.h>
15 #include <stdio.h>
16 #include <stdarg.h>
17 #include <string.h>
18 #include "libcitadel.h"
19
20 #define JSON_STRING 0
21 #define JSON_NUM 1
22 #define JSON_NULL 2
23 #define JSON_BOOL 3
24 #define JSON_ARRAY 4
25 #define JSON_OBJECT 7
26
27 struct JsonValue {
28         int Type;
29         StrBuf *Name;
30         StrBuf *Value;
31         HashList *SubValues;
32 };
33
34
35 void DeleteJSONValue(void *vJsonValue) {
36         JsonValue *Val = (JsonValue*) vJsonValue;
37         FreeStrBuf(&Val->Name);
38         FreeStrBuf(&Val->Value);
39         DeleteHash(&Val->SubValues);
40         free(Val);
41 }
42
43
44 JsonValue *NewJsonObject(const char *Key, long keylen) {
45         JsonValue *Ret;
46
47         Ret = (JsonValue*) malloc(sizeof(JsonValue));
48         memset(Ret, 0, sizeof(JsonValue));
49         Ret->Type = JSON_OBJECT;
50         if (Key != NULL) {
51                 Ret->Name = NewStrBufPlain(Key, keylen);
52         }
53         Ret->SubValues = NewHash(1, NULL);
54         return Ret;
55 }
56
57
58 JsonValue *NewJsonArray(const char *Key, long keylen) {
59         JsonValue *Ret;
60
61         Ret = (JsonValue*) malloc(sizeof(JsonValue));
62         memset(Ret, 0, sizeof(JsonValue));
63         Ret->Type = JSON_ARRAY;
64         if (Key != NULL) {
65                 Ret->Name = NewStrBufPlain(Key, keylen);
66         }
67         Ret->SubValues = NewHash(1, lFlathash);
68         return Ret;
69 }
70
71
72 JsonValue *NewJsonNumber(const char *Key, long keylen, long Number) {
73         JsonValue *Ret;
74
75         Ret = (JsonValue*) malloc(sizeof(JsonValue));
76         memset(Ret, 0, sizeof(JsonValue));
77         Ret->Type = JSON_NUM;
78         if (Key != NULL) {
79                 Ret->Name = NewStrBufPlain(Key, keylen);
80         }
81         Ret->Value = NewStrBufPlain(NULL, 64);
82         StrBufPrintf(Ret->Value, "%ld", Number);
83         return Ret;
84 }
85
86
87 JsonValue *NewJsonBigNumber(const char *Key, long keylen, double Number) {
88         JsonValue *Ret;
89
90         Ret = (JsonValue*) malloc(sizeof(JsonValue));
91         memset(Ret, 0, sizeof(JsonValue));
92         Ret->Type = JSON_NUM;
93         if (Key != NULL) {
94                 Ret->Name = NewStrBufPlain(Key, keylen);
95         }
96         Ret->Value = NewStrBufPlain(NULL, 128);
97         StrBufPrintf(Ret->Value, "%f", Number);
98         return Ret;
99 }
100
101
102 JsonValue *NewJsonString(const char *Key, long keylen, StrBuf *CopyMe, int copy_or_smash) {
103         JsonValue *Ret;
104
105         Ret = (JsonValue*) malloc(sizeof(JsonValue));
106         memset(Ret, 0, sizeof(JsonValue));
107         Ret->Type = JSON_STRING;
108         if (Key != NULL) {
109                 Ret->Name = NewStrBufPlain(Key, keylen);
110         }
111         if (copy_or_smash == NEWJSONSTRING_COPYBUF) {
112                 Ret->Value = NewStrBufDup(CopyMe);
113         }
114         else if (copy_or_smash == NEWJSONSTRING_SMASHBUF) {
115                 Ret->Value = CopyMe;
116         }
117         else {
118                 Ret->Value = NULL;              // error condition
119         }
120         return Ret;
121 }
122
123
124 JsonValue *NewJsonPlainString(const char *Key, long keylen, const char *CopyMe, long len) {
125         JsonValue *Ret;
126
127         Ret = (JsonValue*) malloc(sizeof(JsonValue));
128         memset(Ret, 0, sizeof(JsonValue));
129         Ret->Type = JSON_STRING;
130         if (Key != NULL) {
131                 Ret->Name = NewStrBufPlain(Key, keylen);
132         }
133         Ret->Value = NewStrBufPlain(CopyMe, len);
134         return Ret;
135 }
136
137
138 JsonValue *NewJsonNull(const char *Key, long keylen) {
139         JsonValue *Ret;
140
141         Ret = (JsonValue*) malloc(sizeof(JsonValue));
142         memset(Ret, 0, sizeof(JsonValue));
143         Ret->Type = JSON_NULL;
144         if (Key != NULL)
145         {
146                 Ret->Name = NewStrBufPlain(Key, keylen);
147         }
148         Ret->Value = NewStrBufPlain(HKEY("nulll"));
149         return Ret;
150 }
151
152
153 JsonValue *NewJsonBool(const char *Key, long keylen, int value) {
154         JsonValue *Ret;
155
156         Ret = (JsonValue*) malloc(sizeof(JsonValue));
157         memset(Ret, 0, sizeof(JsonValue));
158         Ret->Type = JSON_BOOL;
159         if (Key != NULL) {
160                 Ret->Name = NewStrBufPlain(Key, keylen);
161         }
162         if (value) {
163                 Ret->Value = NewStrBufPlain(HKEY("true"));
164         }
165         else {
166                 Ret->Value = NewStrBufPlain(HKEY("false"));
167         }
168         return Ret;
169 }
170
171
172 void JsonArrayAppend(JsonValue *Array, JsonValue *Val) {
173         long n;
174         if (Array->Type != JSON_ARRAY) {
175                 return;
176         }
177
178         n = GetCount(Array->SubValues);
179         Put(Array->SubValues, LKEY(n), Val, DeleteJSONValue);
180 }
181
182
183 void JsonObjectAppend(JsonValue *Array, JsonValue *Val) {
184         if ((Array->Type != JSON_OBJECT) || (Val->Name == NULL)) {
185                 return;
186         }
187         Put(Array->SubValues, SKEY(Val->Name), Val, DeleteJSONValue);
188 }
189
190
191 void SerializeJson(StrBuf *Target, JsonValue *Val, int FreeVal) {
192         void *vValue, *vPrevious;
193         JsonValue *SubVal;
194         HashPos *It;
195         const char *Key;
196         long keylen;
197
198
199         switch (Val->Type)
200         {
201         case JSON_STRING:
202                 StrBufAppendBufPlain(Target, HKEY("\""), 0);
203                 StrECMAEscAppend(Target, Val->Value, NULL);
204                 StrBufAppendBufPlain(Target, HKEY("\""), 0);
205                 break;
206         case JSON_NUM:
207                 StrBufAppendBuf(Target, Val->Value, 0);
208                 break;
209         case JSON_BOOL:
210                 StrBufAppendBuf(Target, Val->Value, 0);
211                 break;
212         case JSON_NULL:
213                 StrBufAppendBuf(Target, Val->Value, 0);
214                 break;
215         case JSON_ARRAY:
216                 vPrevious = NULL;
217                 StrBufAppendBufPlain(Target, HKEY("["), 0);
218                 It = GetNewHashPos(Val->SubValues, 0);
219                 while (GetNextHashPos(Val->SubValues, It, &keylen, &Key, &vValue)) {
220                         if (vPrevious != NULL) {
221                                 StrBufAppendBufPlain(Target, HKEY(","), 0);
222                         }
223                         SubVal = (JsonValue*) vValue;
224                         SerializeJson(Target, SubVal, 0);
225                         vPrevious = vValue;
226                 }
227                 StrBufAppendBufPlain(Target, HKEY("]"), 0);
228                 DeleteHashPos(&It);
229                 break;
230         case JSON_OBJECT:
231                 vPrevious = NULL;
232                 StrBufAppendBufPlain(Target, HKEY("{"), 0);
233                 It = GetNewHashPos(Val->SubValues, 0);
234                 while (GetNextHashPos(Val->SubValues, It, &keylen, &Key, &vValue)) {
235                         SubVal = (JsonValue*) vValue;
236
237                         if (vPrevious != NULL) {
238                                 StrBufAppendBufPlain(Target, HKEY(","), 0);
239                         }
240                         StrBufAppendBufPlain(Target, HKEY("\""), 0);
241                         StrBufAppendBuf(Target, SubVal->Name, 0);
242                         StrBufAppendBufPlain(Target, HKEY("\":"), 0);
243
244                         SerializeJson(Target, SubVal, 0);
245                         vPrevious = vValue;
246                 }
247                 StrBufAppendBufPlain(Target, HKEY("}"), 0);
248                 DeleteHashPos(&It);
249                 break;
250         }
251         if (FreeVal) {
252                 DeleteJSONValue(Val);
253         }
254 }