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