stringbuf.c: chipped away at style modernization
[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                 Ret->Name = NewStrBufPlain(Key, keylen);
146         }
147         Ret->Value = NewStrBufPlain(HKEY("nulll"));
148         return Ret;
149 }
150
151
152 JsonValue *NewJsonBool(const char *Key, long keylen, int value) {
153         JsonValue *Ret;
154
155         Ret = (JsonValue*) malloc(sizeof(JsonValue));
156         memset(Ret, 0, sizeof(JsonValue));
157         Ret->Type = JSON_BOOL;
158         if (Key != NULL) {
159                 Ret->Name = NewStrBufPlain(Key, keylen);
160         }
161         if (value) {
162                 Ret->Value = NewStrBufPlain(HKEY("true"));
163         }
164         else {
165                 Ret->Value = NewStrBufPlain(HKEY("false"));
166         }
167         return Ret;
168 }
169
170
171 void JsonArrayAppend(JsonValue *Array, JsonValue *Val) {
172         long n;
173         if (Array->Type != JSON_ARRAY) {
174                 return;
175         }
176
177         n = GetCount(Array->SubValues);
178         Put(Array->SubValues, LKEY(n), Val, DeleteJSONValue);
179 }
180
181
182 void JsonObjectAppend(JsonValue *Array, JsonValue *Val) {
183         if ((Array->Type != JSON_OBJECT) || (Val->Name == NULL)) {
184                 return;
185         }
186         Put(Array->SubValues, SKEY(Val->Name), Val, DeleteJSONValue);
187 }
188
189
190 void SerializeJson(StrBuf *Target, JsonValue *Val, int FreeVal) {
191         void *vValue, *vPrevious;
192         JsonValue *SubVal;
193         HashPos *It;
194         const char *Key;
195         long keylen;
196
197         switch (Val->Type) {
198         case JSON_STRING:
199                 StrBufAppendBufPlain(Target, HKEY("\""), 0);
200                 StrECMAEscAppend(Target, Val->Value, NULL);
201                 StrBufAppendBufPlain(Target, HKEY("\""), 0);
202                 break;
203         case JSON_NUM:
204                 StrBufAppendBuf(Target, Val->Value, 0);
205                 break;
206         case JSON_BOOL:
207                 StrBufAppendBuf(Target, Val->Value, 0);
208                 break;
209         case JSON_NULL:
210                 StrBufAppendBuf(Target, Val->Value, 0);
211                 break;
212         case JSON_ARRAY:
213                 vPrevious = NULL;
214                 StrBufAppendBufPlain(Target, HKEY("["), 0);
215                 It = GetNewHashPos(Val->SubValues, 0);
216                 while (GetNextHashPos(Val->SubValues, It, &keylen, &Key, &vValue)) {
217                         if (vPrevious != NULL) {
218                                 StrBufAppendBufPlain(Target, HKEY(","), 0);
219                         }
220                         SubVal = (JsonValue*) vValue;
221                         SerializeJson(Target, SubVal, 0);
222                         vPrevious = vValue;
223                 }
224                 StrBufAppendBufPlain(Target, HKEY("]"), 0);
225                 DeleteHashPos(&It);
226                 break;
227         case JSON_OBJECT:
228                 vPrevious = NULL;
229                 StrBufAppendBufPlain(Target, HKEY("{"), 0);
230                 It = GetNewHashPos(Val->SubValues, 0);
231                 while (GetNextHashPos(Val->SubValues, It, &keylen, &Key, &vValue)) {
232                         SubVal = (JsonValue*) vValue;
233
234                         if (vPrevious != NULL) {
235                                 StrBufAppendBufPlain(Target, HKEY(","), 0);
236                         }
237                         StrBufAppendBufPlain(Target, HKEY("\""), 0);
238                         StrBufAppendBuf(Target, SubVal->Name, 0);
239                         StrBufAppendBufPlain(Target, HKEY("\":"), 0);
240
241                         SerializeJson(Target, SubVal, 0);
242                         vPrevious = vValue;
243                 }
244                 StrBufAppendBufPlain(Target, HKEY("}"), 0);
245                 DeleteHashPos(&It);
246                 break;
247         }
248         if (FreeVal) {
249                 DeleteJSONValue(Val);
250         }
251 }