summaryrefslogtreecommitdiffstats
path: root/common/unqlite/fastjson.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/unqlite/fastjson.c')
-rw-r--r--common/unqlite/fastjson.c393
1 files changed, 393 insertions, 0 deletions
diff --git a/common/unqlite/fastjson.c b/common/unqlite/fastjson.c
new file mode 100644
index 0000000..96f287f
--- /dev/null
+++ b/common/unqlite/fastjson.c
@@ -0,0 +1,393 @@
1/*
2 * Symisc unQLite: An Embeddable NoSQL (Post Modern) Database Engine.
3 * Copyright (C) 2012-2013, Symisc Systems http://unqlite.org/
4 * Version 1.1.6
5 * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES
6 * please contact Symisc Systems via:
7 * legal@symisc.net
8 * licensing@symisc.net
9 * contact@symisc.net
10 * or visit:
11 * http://unqlite.org/licensing.html
12 */
13 /* $SymiscID: fastjson.c v1.1 FreeBSD 2012-12-05 22:52 stable <chm@symisc.net> $ */
14#ifndef UNQLITE_AMALGAMATION
15#include "unqliteInt.h"
16#endif
17/* JSON binary encoding, decoding and stuff like that */
18#ifndef UNQLITE_FAST_JSON_NEST_LIMIT
19#if defined(__WINNT__) || defined(__UNIXES__)
20#define UNQLITE_FAST_JSON_NEST_LIMIT 64 /* Nesting limit */
21#else
22#define UNQLITE_FAST_JSON_NEST_LIMIT 32 /* Nesting limit */
23#endif
24#endif /* UNQLITE_FAST_JSON_NEST_LIMIT */
25/*
26 * JSON to Binary using the FastJSON implementation (BigEndian).
27 */
28/*
29 * FastJSON implemented binary token.
30 */
31#define FJSON_DOC_START 1 /* { */
32#define FJSON_DOC_END 2 /* } */
33#define FJSON_ARRAY_START 3 /* [ */
34#define FJSON_ARRAY_END 4 /* ] */
35#define FJSON_COLON 5 /* : */
36#define FJSON_COMMA 6 /* , */
37#define FJSON_ID 7 /* ID + 4 Bytes length */
38#define FJSON_STRING 8 /* String + 4 bytes length */
39#define FJSON_BYTE 9 /* Byte */
40#define FJSON_INT64 10 /* Integer 64 + 8 bytes */
41#define FJSON_REAL 18 /* Floating point value + 2 bytes */
42#define FJSON_NULL 23 /* NULL */
43#define FJSON_TRUE 24 /* TRUE */
44#define FJSON_FALSE 25 /* FALSE */
45/*
46 * Encode a Jx9 value to binary JSON.
47 */
48UNQLITE_PRIVATE sxi32 FastJsonEncode(
49 jx9_value *pValue, /* Value to encode */
50 SyBlob *pOut, /* Store encoded value here */
51 int iNest /* Nesting limit */
52 )
53{
54 sxi32 iType = pValue ? pValue->iFlags : MEMOBJ_NULL;
55 sxi32 rc = SXRET_OK;
56 int c;
57 if( iNest >= UNQLITE_FAST_JSON_NEST_LIMIT ){
58 /* Nesting limit reached */
59 return SXERR_LIMIT;
60 }
61 if( iType & (MEMOBJ_NULL|MEMOBJ_RES) ){
62 /*
63 * Resources are encoded as null also.
64 */
65 c = FJSON_NULL;
66 rc = SyBlobAppend(pOut,(const void *)&c,sizeof(char));
67 }else if( iType & MEMOBJ_BOOL ){
68 c = pValue->x.iVal ? FJSON_TRUE : FJSON_FALSE;
69 rc = SyBlobAppend(pOut,(const void *)&c,sizeof(char));
70 }else if( iType & MEMOBJ_STRING ){
71 unsigned char zBuf[sizeof(sxu32)]; /* String length */
72 c = FJSON_STRING;
73 SyBigEndianPack32(zBuf,SyBlobLength(&pValue->sBlob));
74 rc = SyBlobAppend(pOut,(const void *)&c,sizeof(char));
75 if( rc == SXRET_OK ){
76 rc = SyBlobAppend(pOut,(const void *)zBuf,sizeof(zBuf));
77 if( rc == SXRET_OK ){
78 rc = SyBlobAppend(pOut,SyBlobData(&pValue->sBlob),SyBlobLength(&pValue->sBlob));
79 }
80 }
81 }else if( iType & MEMOBJ_INT ){
82 unsigned char zBuf[8];
83 /* 64bit big endian integer */
84 c = FJSON_INT64;
85 rc = SyBlobAppend(pOut,(const void *)&c,sizeof(char));
86 if( rc == SXRET_OK ){
87 SyBigEndianPack64(zBuf,(sxu64)pValue->x.iVal);
88 rc = SyBlobAppend(pOut,(const void *)zBuf,sizeof(zBuf));
89 }
90 }else if( iType & MEMOBJ_REAL ){
91 /* Real number */
92 c = FJSON_REAL;
93 rc = SyBlobAppend(pOut,(const void *)&c,sizeof(char));
94 if( rc == SXRET_OK ){
95 sxu32 iOfft = SyBlobLength(pOut);
96 rc = SyBlobAppendBig16(pOut,0);
97 if( rc == SXRET_OK ){
98 unsigned char *zBlob;
99 SyBlobFormat(pOut,"%.15g",pValue->x.rVal);
100 zBlob = (unsigned char *)SyBlobDataAt(pOut,iOfft);
101 SyBigEndianPack16(zBlob,(sxu16)(SyBlobLength(pOut) - ( 2 + iOfft)));
102 }
103 }
104 }else if( iType & MEMOBJ_HASHMAP ){
105 /* A JSON object or array */
106 jx9_hashmap *pMap = (jx9_hashmap *)pValue->x.pOther;
107 jx9_hashmap_node *pNode;
108 jx9_value *pEntry;
109 /* Reset the hashmap loop cursor */
110 jx9HashmapResetLoopCursor(pMap);
111 if( pMap->iFlags & HASHMAP_JSON_OBJECT ){
112 jx9_value sKey;
113 /* A JSON object */
114 c = FJSON_DOC_START; /* { */
115 rc = SyBlobAppend(pOut,(const void *)&c,sizeof(char));
116 if( rc == SXRET_OK ){
117 jx9MemObjInit(pMap->pVm,&sKey);
118 /* Encode object entries */
119 while((pNode = jx9HashmapGetNextEntry(pMap)) != 0 ){
120 /* Extract the key */
121 jx9HashmapExtractNodeKey(pNode,&sKey);
122 /* Encode it */
123 rc = FastJsonEncode(&sKey,pOut,iNest+1);
124 if( rc != SXRET_OK ){
125 break;
126 }
127 c = FJSON_COLON;
128 rc = SyBlobAppend(pOut,(const void *)&c,sizeof(char));
129 if( rc != SXRET_OK ){
130 break;
131 }
132 /* Extract the value */
133 pEntry = jx9HashmapGetNodeValue(pNode);
134 /* Encode it */
135 rc = FastJsonEncode(pEntry,pOut,iNest+1);
136 if( rc != SXRET_OK ){
137 break;
138 }
139 /* Delimit the entry */
140 c = FJSON_COMMA;
141 rc = SyBlobAppend(pOut,(const void *)&c,sizeof(char));
142 if( rc != SXRET_OK ){
143 break;
144 }
145 }
146 jx9MemObjRelease(&sKey);
147 if( rc == SXRET_OK ){
148 c = FJSON_DOC_END; /* } */
149 rc = SyBlobAppend(pOut,(const void *)&c,sizeof(char));
150 }
151 }
152 }else{
153 /* A JSON array */
154 c = FJSON_ARRAY_START; /* [ */
155 rc = SyBlobAppend(pOut,(const void *)&c,sizeof(char));
156 if( rc == SXRET_OK ){
157 /* Encode array entries */
158 while( (pNode = jx9HashmapGetNextEntry(pMap)) != 0 ){
159 /* Extract the value */
160 pEntry = jx9HashmapGetNodeValue(pNode);
161 /* Encode it */
162 rc = FastJsonEncode(pEntry,pOut,iNest+1);
163 if( rc != SXRET_OK ){
164 break;
165 }
166 /* Delimit the entry */
167 c = FJSON_COMMA;
168 rc = SyBlobAppend(pOut,(const void *)&c,sizeof(char));
169 if( rc != SXRET_OK ){
170 break;
171 }
172 }
173 if( rc == SXRET_OK ){
174 c = FJSON_ARRAY_END; /* ] */
175 rc = SyBlobAppend(pOut,(const void *)&c,sizeof(char));
176 }
177 }
178 }
179 }
180 return rc;
181}
182/*
183 * Decode a FastJSON binary blob.
184 */
185UNQLITE_PRIVATE sxi32 FastJsonDecode(
186 const void *pIn, /* Binary JSON */
187 sxu32 nByte, /* Chunk delimiter */
188 jx9_value *pOut, /* Decoded value */
189 const unsigned char **pzPtr,
190 int iNest /* Nesting limit */
191 )
192{
193 const unsigned char *zIn = (const unsigned char *)pIn;
194 const unsigned char *zEnd = &zIn[nByte];
195 sxi32 rc = SXRET_OK;
196 int c;
197 if( iNest >= UNQLITE_FAST_JSON_NEST_LIMIT ){
198 /* Nesting limit reached */
199 return SXERR_LIMIT;
200 }
201 c = zIn[0];
202 /* Advance the stream cursor */
203 zIn++;
204 /* Process the binary token */
205 switch(c){
206 case FJSON_NULL:
207 /* null */
208 jx9_value_null(pOut);
209 break;
210 case FJSON_FALSE:
211 /* Boolean FALSE */
212 jx9_value_bool(pOut,0);
213 break;
214 case FJSON_TRUE:
215 /* Boolean TRUE */
216 jx9_value_bool(pOut,1);
217 break;
218 case FJSON_INT64: {
219 /* 64Bit integer */
220 sxu64 iVal;
221 /* Sanity check */
222 if( &zIn[8] >= zEnd ){
223 /* Corrupt chunk */
224 rc = SXERR_CORRUPT;
225 break;
226 }
227 SyBigEndianUnpack64(zIn,&iVal);
228 /* Advance the pointer */
229 zIn += 8;
230 jx9_value_int64(pOut,(jx9_int64)iVal);
231 break;
232 }
233 case FJSON_REAL: {
234 /* Real number */
235 double iVal = 0; /* cc warning */
236 sxu16 iLen;
237 /* Sanity check */
238 if( &zIn[2] >= zEnd ){
239 /* Corrupt chunk */
240 rc = SXERR_CORRUPT;
241 break;
242 }
243 SyBigEndianUnpack16(zIn,&iLen);
244 if( &zIn[iLen] >= zEnd ){
245 /* Corrupt chunk */
246 rc = SXERR_CORRUPT;
247 break;
248 }
249 zIn += 2;
250 SyStrToReal((const char *)zIn,(sxu32)iLen,&iVal,0);
251 /* Advance the pointer */
252 zIn += iLen;
253 jx9_value_double(pOut,iVal);
254 break;
255 }
256 case FJSON_STRING: {
257 /* UTF-8/Binary chunk */
258 sxu32 iLength;
259 /* Sanity check */
260 if( &zIn[4] >= zEnd ){
261 /* Corrupt chunk */
262 rc = SXERR_CORRUPT;
263 break;
264 }
265 SyBigEndianUnpack32(zIn,&iLength);
266 if( &zIn[iLength] >= zEnd ){
267 /* Corrupt chunk */
268 rc = SXERR_CORRUPT;
269 break;
270 }
271 zIn += 4;
272 /* Invalidate any prior representation */
273 if( pOut->iFlags & MEMOBJ_STRING ){
274 /* Reset the string cursor */
275 SyBlobReset(&pOut->sBlob);
276 }
277 rc = jx9MemObjStringAppend(pOut,(const char *)zIn,iLength);
278 /* Update pointer */
279 zIn += iLength;
280 break;
281 }
282 case FJSON_ARRAY_START: {
283 /* Binary JSON array */
284 jx9_hashmap *pMap;
285 jx9_value sVal;
286 /* Allocate a new hashmap */
287 pMap = (jx9_hashmap *)jx9NewHashmap(pOut->pVm,0,0);
288 if( pMap == 0 ){
289 rc = SXERR_MEM;
290 break;
291 }
292 jx9MemObjInit(pOut->pVm,&sVal);
293 jx9MemObjRelease(pOut);
294 MemObjSetType(pOut,MEMOBJ_HASHMAP);
295 pOut->x.pOther = pMap;
296 rc = SXRET_OK;
297 for(;;){
298 /* Jump leading binary commas */
299 while (zIn < zEnd && zIn[0] == FJSON_COMMA ){
300 zIn++;
301 }
302 if( zIn >= zEnd || zIn[0] == FJSON_ARRAY_END ){
303 if( zIn < zEnd ){
304 zIn++; /* Jump the trailing binary ] */
305 }
306 break;
307 }
308 /* Decode the value */
309 rc = FastJsonDecode((const void *)zIn,(sxu32)(zEnd-zIn),&sVal,&zIn,iNest+1);
310 if( rc != SXRET_OK ){
311 break;
312 }
313 /* Insert the decoded value */
314 rc = jx9HashmapInsert(pMap,0,&sVal);
315 if( rc != UNQLITE_OK ){
316 break;
317 }
318 }
319 if( rc != SXRET_OK ){
320 jx9MemObjRelease(pOut);
321 }
322 jx9MemObjRelease(&sVal);
323 break;
324 }
325 case FJSON_DOC_START: {
326 /* Binary JSON object */
327 jx9_value sVal,sKey;
328 jx9_hashmap *pMap;
329 /* Allocate a new hashmap */
330 pMap = (jx9_hashmap *)jx9NewHashmap(pOut->pVm,0,0);
331 if( pMap == 0 ){
332 rc = SXERR_MEM;
333 break;
334 }
335 jx9MemObjInit(pOut->pVm,&sVal);
336 jx9MemObjInit(pOut->pVm,&sKey);
337 jx9MemObjRelease(pOut);
338 MemObjSetType(pOut,MEMOBJ_HASHMAP);
339 pOut->x.pOther = pMap;
340 rc = SXRET_OK;
341 for(;;){
342 /* Jump leading binary commas */
343 while (zIn < zEnd && zIn[0] == FJSON_COMMA ){
344 zIn++;
345 }
346 if( zIn >= zEnd || zIn[0] == FJSON_DOC_END ){
347 if( zIn < zEnd ){
348 zIn++; /* Jump the trailing binary } */
349 }
350 break;
351 }
352 /* Extract the key */
353 rc = FastJsonDecode((const void *)zIn,(sxu32)(zEnd-zIn),&sKey,&zIn,iNest+1);
354 if( rc != UNQLITE_OK ){
355 break;
356 }
357 if( zIn >= zEnd || zIn[0] != FJSON_COLON ){
358 rc = UNQLITE_CORRUPT;
359 break;
360 }
361 zIn++; /* Jump the binary colon ':' */
362 if( zIn >= zEnd ){
363 rc = UNQLITE_CORRUPT;
364 break;
365 }
366 /* Decode the value */
367 rc = FastJsonDecode((const void *)zIn,(sxu32)(zEnd-zIn),&sVal,&zIn,iNest+1);
368 if( rc != SXRET_OK ){
369 break;
370 }
371 /* Insert the key and its associated value */
372 rc = jx9HashmapInsert(pMap,&sKey,&sVal);
373 if( rc != UNQLITE_OK ){
374 break;
375 }
376 }
377 if( rc != SXRET_OK ){
378 jx9MemObjRelease(pOut);
379 }
380 jx9MemObjRelease(&sVal);
381 jx9MemObjRelease(&sKey);
382 break;
383 }
384 default:
385 /* Corrupt data */
386 rc = SXERR_CORRUPT;
387 break;
388 }
389 if( pzPtr ){
390 *pzPtr = zIn;
391 }
392 return rc;
393}