Style and cruft
[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)
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         Ret->Value = NewStrBufDup(CopyMe);
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 }