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