diff options
author | Aaron Seigo <aseigo@kde.org> | 2014-12-14 12:00:05 +0100 |
---|---|---|
committer | Aaron Seigo <aseigo@kde.org> | 2014-12-14 12:00:05 +0100 |
commit | 7cc25005b8c46d1fa783d33def2c6923e8ef8469 (patch) | |
tree | 64fa59d17af29838396cf37b912b3babd885e5dd /common/unqlite/fastjson.c | |
parent | bfc32f265e8ad72823db960fed371d72596003b7 (diff) | |
parent | a6ed70495f9f3ecb21c26860dda16aadcdc91c3a (diff) | |
download | sink-7cc25005b8c46d1fa783d33def2c6923e8ef8469.tar.gz sink-7cc25005b8c46d1fa783d33def2c6923e8ef8469.zip |
Merge branch 'unqlite'
Diffstat (limited to 'common/unqlite/fastjson.c')
-rw-r--r-- | common/unqlite/fastjson.c | 393 |
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 | */ | ||
48 | UNQLITE_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 | */ | ||
185 | UNQLITE_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 | } | ||