summaryrefslogtreecommitdiffstats
path: root/common/unqlite/jx9_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/unqlite/jx9_lib.c')
-rw-r--r--common/unqlite/jx9_lib.c4387
1 files changed, 4387 insertions, 0 deletions
diff --git a/common/unqlite/jx9_lib.c b/common/unqlite/jx9_lib.c
new file mode 100644
index 0000000..9f3bcb2
--- /dev/null
+++ b/common/unqlite/jx9_lib.c
@@ -0,0 +1,4387 @@
1/*
2 * Symisc JX9: A Highly Efficient Embeddable Scripting Engine Based on JSON.
3 * Copyright (C) 2012-2013, Symisc Systems http://jx9.symisc.net/
4 * Version 1.7.2
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://jx9.symisc.net/
12 */
13 /* $SymiscID: lib.c v5.1 Win7 2012-08-08 04:19 stable <chm@symisc.net> $ */
14/*
15 * Symisc Run-Time API: A modern thread safe replacement of the standard libc
16 * Copyright (C) Symisc Systems 2007-2012, http://www.symisc.net/
17 *
18 * The Symisc Run-Time API is an independent project developed by symisc systems
19 * internally as a secure replacement of the standard libc.
20 * The library is re-entrant, thread-safe and platform independent.
21 */
22#ifndef JX9_AMALGAMATION
23#include "jx9Int.h"
24#endif
25#if defined(__WINNT__)
26#include <Windows.h>
27#else
28#include <stdlib.h>
29#endif
30#if defined(JX9_ENABLE_THREADS)
31/* SyRunTimeApi: sxmutex.c */
32#if defined(__WINNT__)
33struct SyMutex
34{
35 CRITICAL_SECTION sMutex;
36 sxu32 nType; /* Mutex type, one of SXMUTEX_TYPE_* */
37};
38/* Preallocated static mutex */
39static SyMutex aStaticMutexes[] = {
40 {{0}, SXMUTEX_TYPE_STATIC_1},
41 {{0}, SXMUTEX_TYPE_STATIC_2},
42 {{0}, SXMUTEX_TYPE_STATIC_3},
43 {{0}, SXMUTEX_TYPE_STATIC_4},
44 {{0}, SXMUTEX_TYPE_STATIC_5},
45 {{0}, SXMUTEX_TYPE_STATIC_6}
46};
47static BOOL winMutexInit = FALSE;
48static LONG winMutexLock = 0;
49
50static sxi32 WinMutexGlobaInit(void)
51{
52 LONG rc;
53 rc = InterlockedCompareExchange(&winMutexLock, 1, 0);
54 if ( rc == 0 ){
55 sxu32 n;
56 for( n = 0 ; n < SX_ARRAYSIZE(aStaticMutexes) ; ++n ){
57 InitializeCriticalSection(&aStaticMutexes[n].sMutex);
58 }
59 winMutexInit = TRUE;
60 }else{
61 /* Someone else is doing this for us */
62 while( winMutexInit == FALSE ){
63 Sleep(1);
64 }
65 }
66 return SXRET_OK;
67}
68static void WinMutexGlobalRelease(void)
69{
70 LONG rc;
71 rc = InterlockedCompareExchange(&winMutexLock, 0, 1);
72 if( rc == 1 ){
73 /* The first to decrement to zero does the actual global release */
74 if( winMutexInit == TRUE ){
75 sxu32 n;
76 for( n = 0 ; n < SX_ARRAYSIZE(aStaticMutexes) ; ++n ){
77 DeleteCriticalSection(&aStaticMutexes[n].sMutex);
78 }
79 winMutexInit = FALSE;
80 }
81 }
82}
83static SyMutex * WinMutexNew(int nType)
84{
85 SyMutex *pMutex = 0;
86 if( nType == SXMUTEX_TYPE_FAST || nType == SXMUTEX_TYPE_RECURSIVE ){
87 /* Allocate a new mutex */
88 pMutex = (SyMutex *)HeapAlloc(GetProcessHeap(), 0, sizeof(SyMutex));
89 if( pMutex == 0 ){
90 return 0;
91 }
92 InitializeCriticalSection(&pMutex->sMutex);
93 }else{
94 /* Use a pre-allocated static mutex */
95 if( nType > SXMUTEX_TYPE_STATIC_6 ){
96 nType = SXMUTEX_TYPE_STATIC_6;
97 }
98 pMutex = &aStaticMutexes[nType - 3];
99 }
100 pMutex->nType = nType;
101 return pMutex;
102}
103static void WinMutexRelease(SyMutex *pMutex)
104{
105 if( pMutex->nType == SXMUTEX_TYPE_FAST || pMutex->nType == SXMUTEX_TYPE_RECURSIVE ){
106 DeleteCriticalSection(&pMutex->sMutex);
107 HeapFree(GetProcessHeap(), 0, pMutex);
108 }
109}
110static void WinMutexEnter(SyMutex *pMutex)
111{
112 EnterCriticalSection(&pMutex->sMutex);
113}
114static sxi32 WinMutexTryEnter(SyMutex *pMutex)
115{
116#ifdef _WIN32_WINNT
117 BOOL rc;
118 /* Only WindowsNT platforms */
119 rc = TryEnterCriticalSection(&pMutex->sMutex);
120 if( rc ){
121 return SXRET_OK;
122 }else{
123 return SXERR_BUSY;
124 }
125#else
126 return SXERR_NOTIMPLEMENTED;
127#endif
128}
129static void WinMutexLeave(SyMutex *pMutex)
130{
131 LeaveCriticalSection(&pMutex->sMutex);
132}
133/* Export Windows mutex interfaces */
134static const SyMutexMethods sWinMutexMethods = {
135 WinMutexGlobaInit, /* xGlobalInit() */
136 WinMutexGlobalRelease, /* xGlobalRelease() */
137 WinMutexNew, /* xNew() */
138 WinMutexRelease, /* xRelease() */
139 WinMutexEnter, /* xEnter() */
140 WinMutexTryEnter, /* xTryEnter() */
141 WinMutexLeave /* xLeave() */
142};
143JX9_PRIVATE const SyMutexMethods * SyMutexExportMethods(void)
144{
145 return &sWinMutexMethods;
146}
147#elif defined(__UNIXES__)
148#include <pthread.h>
149struct SyMutex
150{
151 pthread_mutex_t sMutex;
152 sxu32 nType;
153};
154static SyMutex * UnixMutexNew(int nType)
155{
156 static SyMutex aStaticMutexes[] = {
157 {PTHREAD_MUTEX_INITIALIZER, SXMUTEX_TYPE_STATIC_1},
158 {PTHREAD_MUTEX_INITIALIZER, SXMUTEX_TYPE_STATIC_2},
159 {PTHREAD_MUTEX_INITIALIZER, SXMUTEX_TYPE_STATIC_3},
160 {PTHREAD_MUTEX_INITIALIZER, SXMUTEX_TYPE_STATIC_4},
161 {PTHREAD_MUTEX_INITIALIZER, SXMUTEX_TYPE_STATIC_5},
162 {PTHREAD_MUTEX_INITIALIZER, SXMUTEX_TYPE_STATIC_6}
163 };
164 SyMutex *pMutex;
165
166 if( nType == SXMUTEX_TYPE_FAST || nType == SXMUTEX_TYPE_RECURSIVE ){
167 pthread_mutexattr_t sRecursiveAttr;
168 /* Allocate a new mutex */
169 pMutex = (SyMutex *)malloc(sizeof(SyMutex));
170 if( pMutex == 0 ){
171 return 0;
172 }
173 if( nType == SXMUTEX_TYPE_RECURSIVE ){
174 pthread_mutexattr_init(&sRecursiveAttr);
175 pthread_mutexattr_settype(&sRecursiveAttr, PTHREAD_MUTEX_RECURSIVE);
176 }
177 pthread_mutex_init(&pMutex->sMutex, nType == SXMUTEX_TYPE_RECURSIVE ? &sRecursiveAttr : 0 );
178 if( nType == SXMUTEX_TYPE_RECURSIVE ){
179 pthread_mutexattr_destroy(&sRecursiveAttr);
180 }
181 }else{
182 /* Use a pre-allocated static mutex */
183 if( nType > SXMUTEX_TYPE_STATIC_6 ){
184 nType = SXMUTEX_TYPE_STATIC_6;
185 }
186 pMutex = &aStaticMutexes[nType - 3];
187 }
188 pMutex->nType = nType;
189
190 return pMutex;
191}
192static void UnixMutexRelease(SyMutex *pMutex)
193{
194 if( pMutex->nType == SXMUTEX_TYPE_FAST || pMutex->nType == SXMUTEX_TYPE_RECURSIVE ){
195 pthread_mutex_destroy(&pMutex->sMutex);
196 free(pMutex);
197 }
198}
199static void UnixMutexEnter(SyMutex *pMutex)
200{
201 pthread_mutex_lock(&pMutex->sMutex);
202}
203static void UnixMutexLeave(SyMutex *pMutex)
204{
205 pthread_mutex_unlock(&pMutex->sMutex);
206}
207/* Export pthread mutex interfaces */
208static const SyMutexMethods sPthreadMutexMethods = {
209 0, /* xGlobalInit() */
210 0, /* xGlobalRelease() */
211 UnixMutexNew, /* xNew() */
212 UnixMutexRelease, /* xRelease() */
213 UnixMutexEnter, /* xEnter() */
214 0, /* xTryEnter() */
215 UnixMutexLeave /* xLeave() */
216};
217JX9_PRIVATE const SyMutexMethods * SyMutexExportMethods(void)
218{
219 return &sPthreadMutexMethods;
220}
221#else
222/* Host application must register their own mutex subsystem if the target
223 * platform is not an UNIX-like or windows systems.
224 */
225struct SyMutex
226{
227 sxu32 nType;
228};
229static SyMutex * DummyMutexNew(int nType)
230{
231 static SyMutex sMutex;
232 SXUNUSED(nType);
233 return &sMutex;
234}
235static void DummyMutexRelease(SyMutex *pMutex)
236{
237 SXUNUSED(pMutex);
238}
239static void DummyMutexEnter(SyMutex *pMutex)
240{
241 SXUNUSED(pMutex);
242}
243static void DummyMutexLeave(SyMutex *pMutex)
244{
245 SXUNUSED(pMutex);
246}
247/* Export the dummy mutex interfaces */
248static const SyMutexMethods sDummyMutexMethods = {
249 0, /* xGlobalInit() */
250 0, /* xGlobalRelease() */
251 DummyMutexNew, /* xNew() */
252 DummyMutexRelease, /* xRelease() */
253 DummyMutexEnter, /* xEnter() */
254 0, /* xTryEnter() */
255 DummyMutexLeave /* xLeave() */
256};
257JX9_PRIVATE const SyMutexMethods * SyMutexExportMethods(void)
258{
259 return &sDummyMutexMethods;
260}
261#endif /* __WINNT__ */
262#endif /* JX9_ENABLE_THREADS */
263static void * SyOSHeapAlloc(sxu32 nByte)
264{
265 void *pNew;
266#if defined(__WINNT__)
267 pNew = HeapAlloc(GetProcessHeap(), 0, nByte);
268#else
269 pNew = malloc((size_t)nByte);
270#endif
271 return pNew;
272}
273static void * SyOSHeapRealloc(void *pOld, sxu32 nByte)
274{
275 void *pNew;
276#if defined(__WINNT__)
277 pNew = HeapReAlloc(GetProcessHeap(), 0, pOld, nByte);
278#else
279 pNew = realloc(pOld, (size_t)nByte);
280#endif
281 return pNew;
282}
283static void SyOSHeapFree(void *pPtr)
284{
285#if defined(__WINNT__)
286 HeapFree(GetProcessHeap(), 0, pPtr);
287#else
288 free(pPtr);
289#endif
290}
291/* SyRunTimeApi:sxstr.c */
292JX9_PRIVATE sxu32 SyStrlen(const char *zSrc)
293{
294 register const char *zIn = zSrc;
295#if defined(UNTRUST)
296 if( zIn == 0 ){
297 return 0;
298 }
299#endif
300 for(;;){
301 if( !zIn[0] ){ break; } zIn++;
302 if( !zIn[0] ){ break; } zIn++;
303 if( !zIn[0] ){ break; } zIn++;
304 if( !zIn[0] ){ break; } zIn++;
305 }
306 return (sxu32)(zIn - zSrc);
307}
308JX9_PRIVATE sxi32 SyByteFind(const char *zStr, sxu32 nLen, sxi32 c, sxu32 *pPos)
309{
310 const char *zIn = zStr;
311 const char *zEnd;
312
313 zEnd = &zIn[nLen];
314 for(;;){
315 if( zIn >= zEnd ){ break; }if( zIn[0] == c ){ if( pPos ){ *pPos = (sxu32)(zIn - zStr); } return SXRET_OK; } zIn++;
316 if( zIn >= zEnd ){ break; }if( zIn[0] == c ){ if( pPos ){ *pPos = (sxu32)(zIn - zStr); } return SXRET_OK; } zIn++;
317 if( zIn >= zEnd ){ break; }if( zIn[0] == c ){ if( pPos ){ *pPos = (sxu32)(zIn - zStr); } return SXRET_OK; } zIn++;
318 if( zIn >= zEnd ){ break; }if( zIn[0] == c ){ if( pPos ){ *pPos = (sxu32)(zIn - zStr); } return SXRET_OK; } zIn++;
319 }
320 return SXERR_NOTFOUND;
321}
322#ifndef JX9_DISABLE_BUILTIN_FUNC
323JX9_PRIVATE sxi32 SyByteFind2(const char *zStr, sxu32 nLen, sxi32 c, sxu32 *pPos)
324{
325 const char *zIn = zStr;
326 const char *zEnd;
327
328 zEnd = &zIn[nLen - 1];
329 for( ;; ){
330 if( zEnd < zIn ){ break; } if( zEnd[0] == c ){ if( pPos ){ *pPos = (sxu32)(zEnd - zIn);} return SXRET_OK; } zEnd--;
331 if( zEnd < zIn ){ break; } if( zEnd[0] == c ){ if( pPos ){ *pPos = (sxu32)(zEnd - zIn);} return SXRET_OK; } zEnd--;
332 if( zEnd < zIn ){ break; } if( zEnd[0] == c ){ if( pPos ){ *pPos = (sxu32)(zEnd - zIn);} return SXRET_OK; } zEnd--;
333 if( zEnd < zIn ){ break; } if( zEnd[0] == c ){ if( pPos ){ *pPos = (sxu32)(zEnd - zIn);} return SXRET_OK; } zEnd--;
334 }
335 return SXERR_NOTFOUND;
336}
337#endif /* JX9_DISABLE_BUILTIN_FUNC */
338JX9_PRIVATE sxi32 SyByteListFind(const char *zSrc, sxu32 nLen, const char *zList, sxu32 *pFirstPos)
339{
340 const char *zIn = zSrc;
341 const char *zPtr;
342 const char *zEnd;
343 sxi32 c;
344 zEnd = &zSrc[nLen];
345 for(;;){
346 if( zIn >= zEnd ){ break; } for(zPtr = zList ; (c = zPtr[0]) != 0 ; zPtr++ ){ if( zIn[0] == c ){ if( pFirstPos ){ *pFirstPos = (sxu32)(zIn - zSrc); } return SXRET_OK; } } zIn++;
347 if( zIn >= zEnd ){ break; } for(zPtr = zList ; (c = zPtr[0]) != 0 ; zPtr++ ){ if( zIn[0] == c ){ if( pFirstPos ){ *pFirstPos = (sxu32)(zIn - zSrc); } return SXRET_OK; } } zIn++;
348 if( zIn >= zEnd ){ break; } for(zPtr = zList ; (c = zPtr[0]) != 0 ; zPtr++ ){ if( zIn[0] == c ){ if( pFirstPos ){ *pFirstPos = (sxu32)(zIn - zSrc); } return SXRET_OK; } } zIn++;
349 if( zIn >= zEnd ){ break; } for(zPtr = zList ; (c = zPtr[0]) != 0 ; zPtr++ ){ if( zIn[0] == c ){ if( pFirstPos ){ *pFirstPos = (sxu32)(zIn - zSrc); } return SXRET_OK; } } zIn++;
350 }
351 return SXERR_NOTFOUND;
352}
353#ifndef JX9_DISABLE_BUILTIN_FUNC
354JX9_PRIVATE sxi32 SyStrncmp(const char *zLeft, const char *zRight, sxu32 nLen)
355{
356 const unsigned char *zP = (const unsigned char *)zLeft;
357 const unsigned char *zQ = (const unsigned char *)zRight;
358
359 if( SX_EMPTY_STR(zP) || SX_EMPTY_STR(zQ) ){
360 return SX_EMPTY_STR(zP) ? (SX_EMPTY_STR(zQ) ? 0 : -1) :1;
361 }
362 if( nLen <= 0 ){
363 return 0;
364 }
365 for(;;){
366 if( nLen <= 0 ){ return 0; } if( zP[0] == 0 || zQ[0] == 0 || zP[0] != zQ[0] ){ break; } zP++; zQ++; nLen--;
367 if( nLen <= 0 ){ return 0; } if( zP[0] == 0 || zQ[0] == 0 || zP[0] != zQ[0] ){ break; } zP++; zQ++; nLen--;
368 if( nLen <= 0 ){ return 0; } if( zP[0] == 0 || zQ[0] == 0 || zP[0] != zQ[0] ){ break; } zP++; zQ++; nLen--;
369 if( nLen <= 0 ){ return 0; } if( zP[0] == 0 || zQ[0] == 0 || zP[0] != zQ[0] ){ break; } zP++; zQ++; nLen--;
370 }
371 return (sxi32)(zP[0] - zQ[0]);
372}
373#endif
374JX9_PRIVATE sxi32 SyStrnicmp(const char *zLeft, const char *zRight, sxu32 SLen)
375{
376 register unsigned char *p = (unsigned char *)zLeft;
377 register unsigned char *q = (unsigned char *)zRight;
378
379 if( SX_EMPTY_STR(p) || SX_EMPTY_STR(q) ){
380 return SX_EMPTY_STR(p)? SX_EMPTY_STR(q) ? 0 : -1 :1;
381 }
382 for(;;){
383 if( !SLen ){ return 0; }if( !*p || !*q || SyCharToLower(*p) != SyCharToLower(*q) ){ break; }p++;q++;--SLen;
384 if( !SLen ){ return 0; }if( !*p || !*q || SyCharToLower(*p) != SyCharToLower(*q) ){ break; }p++;q++;--SLen;
385 if( !SLen ){ return 0; }if( !*p || !*q || SyCharToLower(*p) != SyCharToLower(*q) ){ break; }p++;q++;--SLen;
386 if( !SLen ){ return 0; }if( !*p || !*q || SyCharToLower(*p) != SyCharToLower(*q) ){ break; }p++;q++;--SLen;
387
388 }
389 return (sxi32)(SyCharToLower(p[0]) - SyCharToLower(q[0]));
390}
391JX9_PRIVATE sxu32 Systrcpy(char *zDest, sxu32 nDestLen, const char *zSrc, sxu32 nLen)
392{
393 unsigned char *zBuf = (unsigned char *)zDest;
394 unsigned char *zIn = (unsigned char *)zSrc;
395 unsigned char *zEnd;
396#if defined(UNTRUST)
397 if( zSrc == (const char *)zDest ){
398 return 0;
399 }
400#endif
401 if( nLen <= 0 ){
402 nLen = SyStrlen(zSrc);
403 }
404 zEnd = &zBuf[nDestLen - 1]; /* reserve a room for the null terminator */
405 for(;;){
406 if( zBuf >= zEnd || nLen == 0 ){ break;} zBuf[0] = zIn[0]; zIn++; zBuf++; nLen--;
407 if( zBuf >= zEnd || nLen == 0 ){ break;} zBuf[0] = zIn[0]; zIn++; zBuf++; nLen--;
408 if( zBuf >= zEnd || nLen == 0 ){ break;} zBuf[0] = zIn[0]; zIn++; zBuf++; nLen--;
409 if( zBuf >= zEnd || nLen == 0 ){ break;} zBuf[0] = zIn[0]; zIn++; zBuf++; nLen--;
410 }
411 zBuf[0] = 0;
412 return (sxu32)(zBuf-(unsigned char *)zDest);
413}
414/* SyRunTimeApi:sxmem.c */
415JX9_PRIVATE void SyZero(void *pSrc, sxu32 nSize)
416{
417 register unsigned char *zSrc = (unsigned char *)pSrc;
418 unsigned char *zEnd;
419#if defined(UNTRUST)
420 if( zSrc == 0 || nSize <= 0 ){
421 return ;
422 }
423#endif
424 zEnd = &zSrc[nSize];
425 for(;;){
426 if( zSrc >= zEnd ){break;} zSrc[0] = 0; zSrc++;
427 if( zSrc >= zEnd ){break;} zSrc[0] = 0; zSrc++;
428 if( zSrc >= zEnd ){break;} zSrc[0] = 0; zSrc++;
429 if( zSrc >= zEnd ){break;} zSrc[0] = 0; zSrc++;
430 }
431}
432JX9_PRIVATE sxi32 SyMemcmp(const void *pB1, const void *pB2, sxu32 nSize)
433{
434 sxi32 rc;
435 if( nSize <= 0 ){
436 return 0;
437 }
438 if( pB1 == 0 || pB2 == 0 ){
439 return pB1 != 0 ? 1 : (pB2 == 0 ? 0 : -1);
440 }
441 SX_MACRO_FAST_CMP(pB1, pB2, nSize, rc);
442 return rc;
443}
444JX9_PRIVATE sxu32 SyMemcpy(const void *pSrc, void *pDest, sxu32 nLen)
445{
446 if( pSrc == 0 || pDest == 0 ){
447 return 0;
448 }
449 if( pSrc == (const void *)pDest ){
450 return nLen;
451 }
452 SX_MACRO_FAST_MEMCPY(pSrc, pDest, nLen);
453 return nLen;
454}
455static void * MemOSAlloc(sxu32 nBytes)
456{
457 sxu32 *pChunk;
458 pChunk = (sxu32 *)SyOSHeapAlloc(nBytes + sizeof(sxu32));
459 if( pChunk == 0 ){
460 return 0;
461 }
462 pChunk[0] = nBytes;
463 return (void *)&pChunk[1];
464}
465static void * MemOSRealloc(void *pOld, sxu32 nBytes)
466{
467 sxu32 *pOldChunk;
468 sxu32 *pChunk;
469 pOldChunk = (sxu32 *)(((char *)pOld)-sizeof(sxu32));
470 if( pOldChunk[0] >= nBytes ){
471 return pOld;
472 }
473 pChunk = (sxu32 *)SyOSHeapRealloc(pOldChunk, nBytes + sizeof(sxu32));
474 if( pChunk == 0 ){
475 return 0;
476 }
477 pChunk[0] = nBytes;
478 return (void *)&pChunk[1];
479}
480static void MemOSFree(void *pBlock)
481{
482 void *pChunk;
483 pChunk = (void *)(((char *)pBlock)-sizeof(sxu32));
484 SyOSHeapFree(pChunk);
485}
486static sxu32 MemOSChunkSize(void *pBlock)
487{
488 sxu32 *pChunk;
489 pChunk = (sxu32 *)(((char *)pBlock)-sizeof(sxu32));
490 return pChunk[0];
491}
492/* Export OS allocation methods */
493static const SyMemMethods sOSAllocMethods = {
494 MemOSAlloc,
495 MemOSRealloc,
496 MemOSFree,
497 MemOSChunkSize,
498 0,
499 0,
500 0
501};
502static void * MemBackendAlloc(SyMemBackend *pBackend, sxu32 nByte)
503{
504 SyMemBlock *pBlock;
505 sxi32 nRetry = 0;
506
507 /* Append an extra block so we can tracks allocated chunks and avoid memory
508 * leaks.
509 */
510 nByte += sizeof(SyMemBlock);
511 for(;;){
512 pBlock = (SyMemBlock *)pBackend->pMethods->xAlloc(nByte);
513 if( pBlock != 0 || pBackend->xMemError == 0 || nRetry > SXMEM_BACKEND_RETRY
514 || SXERR_RETRY != pBackend->xMemError(pBackend->pUserData) ){
515 break;
516 }
517 nRetry++;
518 }
519 if( pBlock == 0 ){
520 return 0;
521 }
522 pBlock->pNext = pBlock->pPrev = 0;
523 /* Link to the list of already tracked blocks */
524 MACRO_LD_PUSH(pBackend->pBlocks, pBlock);
525#if defined(UNTRUST)
526 pBlock->nGuard = SXMEM_BACKEND_MAGIC;
527#endif
528 pBackend->nBlock++;
529 return (void *)&pBlock[1];
530}
531JX9_PRIVATE void * SyMemBackendAlloc(SyMemBackend *pBackend, sxu32 nByte)
532{
533 void *pChunk;
534#if defined(UNTRUST)
535 if( SXMEM_BACKEND_CORRUPT(pBackend) ){
536 return 0;
537 }
538#endif
539 if( pBackend->pMutexMethods ){
540 SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex);
541 }
542 pChunk = MemBackendAlloc(&(*pBackend), nByte);
543 if( pBackend->pMutexMethods ){
544 SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex);
545 }
546 return pChunk;
547}
548static void * MemBackendRealloc(SyMemBackend *pBackend, void * pOld, sxu32 nByte)
549{
550 SyMemBlock *pBlock, *pNew, *pPrev, *pNext;
551 sxu32 nRetry = 0;
552
553 if( pOld == 0 ){
554 return MemBackendAlloc(&(*pBackend), nByte);
555 }
556 pBlock = (SyMemBlock *)(((char *)pOld) - sizeof(SyMemBlock));
557#if defined(UNTRUST)
558 if( pBlock->nGuard != SXMEM_BACKEND_MAGIC ){
559 return 0;
560 }
561#endif
562 nByte += sizeof(SyMemBlock);
563 pPrev = pBlock->pPrev;
564 pNext = pBlock->pNext;
565 for(;;){
566 pNew = (SyMemBlock *)pBackend->pMethods->xRealloc(pBlock, nByte);
567 if( pNew != 0 || pBackend->xMemError == 0 || nRetry > SXMEM_BACKEND_RETRY ||
568 SXERR_RETRY != pBackend->xMemError(pBackend->pUserData) ){
569 break;
570 }
571 nRetry++;
572 }
573 if( pNew == 0 ){
574 return 0;
575 }
576 if( pNew != pBlock ){
577 if( pPrev == 0 ){
578 pBackend->pBlocks = pNew;
579 }else{
580 pPrev->pNext = pNew;
581 }
582 if( pNext ){
583 pNext->pPrev = pNew;
584 }
585#if defined(UNTRUST)
586 pNew->nGuard = SXMEM_BACKEND_MAGIC;
587#endif
588 }
589 return (void *)&pNew[1];
590}
591JX9_PRIVATE void * SyMemBackendRealloc(SyMemBackend *pBackend, void * pOld, sxu32 nByte)
592{
593 void *pChunk;
594#if defined(UNTRUST)
595 if( SXMEM_BACKEND_CORRUPT(pBackend) ){
596 return 0;
597 }
598#endif
599 if( pBackend->pMutexMethods ){
600 SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex);
601 }
602 pChunk = MemBackendRealloc(&(*pBackend), pOld, nByte);
603 if( pBackend->pMutexMethods ){
604 SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex);
605 }
606 return pChunk;
607}
608static sxi32 MemBackendFree(SyMemBackend *pBackend, void * pChunk)
609{
610 SyMemBlock *pBlock;
611 pBlock = (SyMemBlock *)(((char *)pChunk) - sizeof(SyMemBlock));
612#if defined(UNTRUST)
613 if( pBlock->nGuard != SXMEM_BACKEND_MAGIC ){
614 return SXERR_CORRUPT;
615 }
616#endif
617 /* Unlink from the list of active blocks */
618 if( pBackend->nBlock > 0 ){
619 /* Release the block */
620#if defined(UNTRUST)
621 /* Mark as stale block */
622 pBlock->nGuard = 0x635B;
623#endif
624 MACRO_LD_REMOVE(pBackend->pBlocks, pBlock);
625 pBackend->nBlock--;
626 pBackend->pMethods->xFree(pBlock);
627 }
628 return SXRET_OK;
629}
630JX9_PRIVATE sxi32 SyMemBackendFree(SyMemBackend *pBackend, void * pChunk)
631{
632 sxi32 rc;
633#if defined(UNTRUST)
634 if( SXMEM_BACKEND_CORRUPT(pBackend) ){
635 return SXERR_CORRUPT;
636 }
637#endif
638 if( pChunk == 0 ){
639 return SXRET_OK;
640 }
641 if( pBackend->pMutexMethods ){
642 SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex);
643 }
644 rc = MemBackendFree(&(*pBackend), pChunk);
645 if( pBackend->pMutexMethods ){
646 SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex);
647 }
648 return rc;
649}
650#if defined(JX9_ENABLE_THREADS)
651JX9_PRIVATE sxi32 SyMemBackendMakeThreadSafe(SyMemBackend *pBackend, const SyMutexMethods *pMethods)
652{
653 SyMutex *pMutex;
654#if defined(UNTRUST)
655 if( SXMEM_BACKEND_CORRUPT(pBackend) || pMethods == 0 || pMethods->xNew == 0){
656 return SXERR_CORRUPT;
657 }
658#endif
659 pMutex = pMethods->xNew(SXMUTEX_TYPE_FAST);
660 if( pMutex == 0 ){
661 return SXERR_OS;
662 }
663 /* Attach the mutex to the memory backend */
664 pBackend->pMutex = pMutex;
665 pBackend->pMutexMethods = pMethods;
666 return SXRET_OK;
667}
668JX9_PRIVATE sxi32 SyMemBackendDisbaleMutexing(SyMemBackend *pBackend)
669{
670#if defined(UNTRUST)
671 if( SXMEM_BACKEND_CORRUPT(pBackend) ){
672 return SXERR_CORRUPT;
673 }
674#endif
675 if( pBackend->pMutex == 0 ){
676 /* There is no mutex subsystem at all */
677 return SXRET_OK;
678 }
679 SyMutexRelease(pBackend->pMutexMethods, pBackend->pMutex);
680 pBackend->pMutexMethods = 0;
681 pBackend->pMutex = 0;
682 return SXRET_OK;
683}
684#endif
685/*
686 * Memory pool allocator
687 */
688#define SXMEM_POOL_MAGIC 0xDEAD
689#define SXMEM_POOL_MAXALLOC (1<<(SXMEM_POOL_NBUCKETS+SXMEM_POOL_INCR))
690#define SXMEM_POOL_MINALLOC (1<<(SXMEM_POOL_INCR))
691static sxi32 MemPoolBucketAlloc(SyMemBackend *pBackend, sxu32 nBucket)
692{
693 char *zBucket, *zBucketEnd;
694 SyMemHeader *pHeader;
695 sxu32 nBucketSize;
696
697 /* Allocate one big block first */
698 zBucket = (char *)MemBackendAlloc(&(*pBackend), SXMEM_POOL_MAXALLOC);
699 if( zBucket == 0 ){
700 return SXERR_MEM;
701 }
702 zBucketEnd = &zBucket[SXMEM_POOL_MAXALLOC];
703 /* Divide the big block into mini bucket pool */
704 nBucketSize = 1 << (nBucket + SXMEM_POOL_INCR);
705 pBackend->apPool[nBucket] = pHeader = (SyMemHeader *)zBucket;
706 for(;;){
707 if( &zBucket[nBucketSize] >= zBucketEnd ){
708 break;
709 }
710 pHeader->pNext = (SyMemHeader *)&zBucket[nBucketSize];
711 /* Advance the cursor to the next available chunk */
712 pHeader = pHeader->pNext;
713 zBucket += nBucketSize;
714 }
715 pHeader->pNext = 0;
716
717 return SXRET_OK;
718}
719static void * MemBackendPoolAlloc(SyMemBackend *pBackend, sxu32 nByte)
720{
721 SyMemHeader *pBucket, *pNext;
722 sxu32 nBucketSize;
723 sxu32 nBucket;
724
725 if( nByte + sizeof(SyMemHeader) >= SXMEM_POOL_MAXALLOC ){
726 /* Allocate a big chunk directly */
727 pBucket = (SyMemHeader *)MemBackendAlloc(&(*pBackend), nByte+sizeof(SyMemHeader));
728 if( pBucket == 0 ){
729 return 0;
730 }
731 /* Record as big block */
732 pBucket->nBucket = (sxu32)(SXMEM_POOL_MAGIC << 16) | SXU16_HIGH;
733 return (void *)(pBucket+1);
734 }
735 /* Locate the appropriate bucket */
736 nBucket = 0;
737 nBucketSize = SXMEM_POOL_MINALLOC;
738 while( nByte + sizeof(SyMemHeader) > nBucketSize ){
739 nBucketSize <<= 1;
740 nBucket++;
741 }
742 pBucket = pBackend->apPool[nBucket];
743 if( pBucket == 0 ){
744 sxi32 rc;
745 rc = MemPoolBucketAlloc(&(*pBackend), nBucket);
746 if( rc != SXRET_OK ){
747 return 0;
748 }
749 pBucket = pBackend->apPool[nBucket];
750 }
751 /* Remove from the free list */
752 pNext = pBucket->pNext;
753 pBackend->apPool[nBucket] = pNext;
754 /* Record bucket&magic number */
755 pBucket->nBucket = (SXMEM_POOL_MAGIC << 16) | nBucket;
756 return (void *)&pBucket[1];
757}
758JX9_PRIVATE void * SyMemBackendPoolAlloc(SyMemBackend *pBackend, sxu32 nByte)
759{
760 void *pChunk;
761#if defined(UNTRUST)
762 if( SXMEM_BACKEND_CORRUPT(pBackend) ){
763 return 0;
764 }
765#endif
766 if( pBackend->pMutexMethods ){
767 SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex);
768 }
769 pChunk = MemBackendPoolAlloc(&(*pBackend), nByte);
770 if( pBackend->pMutexMethods ){
771 SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex);
772 }
773 return pChunk;
774}
775static sxi32 MemBackendPoolFree(SyMemBackend *pBackend, void * pChunk)
776{
777 SyMemHeader *pHeader;
778 sxu32 nBucket;
779 /* Get the corresponding bucket */
780 pHeader = (SyMemHeader *)(((char *)pChunk) - sizeof(SyMemHeader));
781 /* Sanity check to avoid misuse */
782 if( (pHeader->nBucket >> 16) != SXMEM_POOL_MAGIC ){
783 return SXERR_CORRUPT;
784 }
785 nBucket = pHeader->nBucket & 0xFFFF;
786 if( nBucket == SXU16_HIGH ){
787 /* Free the big block */
788 MemBackendFree(&(*pBackend), pHeader);
789 }else{
790 /* Return to the free list */
791 pHeader->pNext = pBackend->apPool[nBucket & 0x0f];
792 pBackend->apPool[nBucket & 0x0f] = pHeader;
793 }
794 return SXRET_OK;
795}
796JX9_PRIVATE sxi32 SyMemBackendPoolFree(SyMemBackend *pBackend, void * pChunk)
797{
798 sxi32 rc;
799#if defined(UNTRUST)
800 if( SXMEM_BACKEND_CORRUPT(pBackend) || pChunk == 0 ){
801 return SXERR_CORRUPT;
802 }
803#endif
804 if( pBackend->pMutexMethods ){
805 SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex);
806 }
807 rc = MemBackendPoolFree(&(*pBackend), pChunk);
808 if( pBackend->pMutexMethods ){
809 SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex);
810 }
811 return rc;
812}
813#if 0
814static void * MemBackendPoolRealloc(SyMemBackend *pBackend, void * pOld, sxu32 nByte)
815{
816 sxu32 nBucket, nBucketSize;
817 SyMemHeader *pHeader;
818 void * pNew;
819
820 if( pOld == 0 ){
821 /* Allocate a new pool */
822 pNew = MemBackendPoolAlloc(&(*pBackend), nByte);
823 return pNew;
824 }
825 /* Get the corresponding bucket */
826 pHeader = (SyMemHeader *)(((char *)pOld) - sizeof(SyMemHeader));
827 /* Sanity check to avoid misuse */
828 if( (pHeader->nBucket >> 16) != SXMEM_POOL_MAGIC ){
829 return 0;
830 }
831 nBucket = pHeader->nBucket & 0xFFFF;
832 if( nBucket == SXU16_HIGH ){
833 /* Big block */
834 return MemBackendRealloc(&(*pBackend), pHeader, nByte);
835 }
836 nBucketSize = 1 << (nBucket + SXMEM_POOL_INCR);
837 if( nBucketSize >= nByte + sizeof(SyMemHeader) ){
838 /* The old bucket can honor the requested size */
839 return pOld;
840 }
841 /* Allocate a new pool */
842 pNew = MemBackendPoolAlloc(&(*pBackend), nByte);
843 if( pNew == 0 ){
844 return 0;
845 }
846 /* Copy the old data into the new block */
847 SyMemcpy(pOld, pNew, nBucketSize);
848 /* Free the stale block */
849 MemBackendPoolFree(&(*pBackend), pOld);
850 return pNew;
851}
852JX9_PRIVATE void * SyMemBackendPoolRealloc(SyMemBackend *pBackend, void * pOld, sxu32 nByte)
853{
854 void *pChunk;
855#if defined(UNTRUST)
856 if( SXMEM_BACKEND_CORRUPT(pBackend) ){
857 return 0;
858 }
859#endif
860 if( pBackend->pMutexMethods ){
861 SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex);
862 }
863 pChunk = MemBackendPoolRealloc(&(*pBackend), pOld, nByte);
864 if( pBackend->pMutexMethods ){
865 SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex);
866 }
867 return pChunk;
868}
869#endif
870JX9_PRIVATE sxi32 SyMemBackendInit(SyMemBackend *pBackend, ProcMemError xMemErr, void * pUserData)
871{
872#if defined(UNTRUST)
873 if( pBackend == 0 ){
874 return SXERR_EMPTY;
875 }
876#endif
877 /* Zero the allocator first */
878 SyZero(&(*pBackend), sizeof(SyMemBackend));
879 pBackend->xMemError = xMemErr;
880 pBackend->pUserData = pUserData;
881 /* Switch to the OS memory allocator */
882 pBackend->pMethods = &sOSAllocMethods;
883 if( pBackend->pMethods->xInit ){
884 /* Initialize the backend */
885 if( SXRET_OK != pBackend->pMethods->xInit(pBackend->pMethods->pUserData) ){
886 return SXERR_ABORT;
887 }
888 }
889#if defined(UNTRUST)
890 pBackend->nMagic = SXMEM_BACKEND_MAGIC;
891#endif
892 return SXRET_OK;
893}
894JX9_PRIVATE sxi32 SyMemBackendInitFromOthers(SyMemBackend *pBackend, const SyMemMethods *pMethods, ProcMemError xMemErr, void * pUserData)
895{
896#if defined(UNTRUST)
897 if( pBackend == 0 || pMethods == 0){
898 return SXERR_EMPTY;
899 }
900#endif
901 if( pMethods->xAlloc == 0 || pMethods->xRealloc == 0 || pMethods->xFree == 0 || pMethods->xChunkSize == 0 ){
902 /* mandatory methods are missing */
903 return SXERR_INVALID;
904 }
905 /* Zero the allocator first */
906 SyZero(&(*pBackend), sizeof(SyMemBackend));
907 pBackend->xMemError = xMemErr;
908 pBackend->pUserData = pUserData;
909 /* Switch to the host application memory allocator */
910 pBackend->pMethods = pMethods;
911 if( pBackend->pMethods->xInit ){
912 /* Initialize the backend */
913 if( SXRET_OK != pBackend->pMethods->xInit(pBackend->pMethods->pUserData) ){
914 return SXERR_ABORT;
915 }
916 }
917#if defined(UNTRUST)
918 pBackend->nMagic = SXMEM_BACKEND_MAGIC;
919#endif
920 return SXRET_OK;
921}
922JX9_PRIVATE sxi32 SyMemBackendInitFromParent(SyMemBackend *pBackend,const SyMemBackend *pParent)
923{
924 sxu8 bInheritMutex;
925#if defined(UNTRUST)
926 if( pBackend == 0 || SXMEM_BACKEND_CORRUPT(pParent) ){
927 return SXERR_CORRUPT;
928 }
929#endif
930 /* Zero the allocator first */
931 SyZero(&(*pBackend), sizeof(SyMemBackend));
932 pBackend->pMethods = pParent->pMethods;
933 pBackend->xMemError = pParent->xMemError;
934 pBackend->pUserData = pParent->pUserData;
935 bInheritMutex = pParent->pMutexMethods ? TRUE : FALSE;
936 if( bInheritMutex ){
937 pBackend->pMutexMethods = pParent->pMutexMethods;
938 /* Create a private mutex */
939 pBackend->pMutex = pBackend->pMutexMethods->xNew(SXMUTEX_TYPE_FAST);
940 if( pBackend->pMutex == 0){
941 return SXERR_OS;
942 }
943 }
944#if defined(UNTRUST)
945 pBackend->nMagic = SXMEM_BACKEND_MAGIC;
946#endif
947 return SXRET_OK;
948}
949static sxi32 MemBackendRelease(SyMemBackend *pBackend)
950{
951 SyMemBlock *pBlock, *pNext;
952
953 pBlock = pBackend->pBlocks;
954 for(;;){
955 if( pBackend->nBlock == 0 ){
956 break;
957 }
958 pNext = pBlock->pNext;
959 pBackend->pMethods->xFree(pBlock);
960 pBlock = pNext;
961 pBackend->nBlock--;
962 /* LOOP ONE */
963 if( pBackend->nBlock == 0 ){
964 break;
965 }
966 pNext = pBlock->pNext;
967 pBackend->pMethods->xFree(pBlock);
968 pBlock = pNext;
969 pBackend->nBlock--;
970 /* LOOP TWO */
971 if( pBackend->nBlock == 0 ){
972 break;
973 }
974 pNext = pBlock->pNext;
975 pBackend->pMethods->xFree(pBlock);
976 pBlock = pNext;
977 pBackend->nBlock--;
978 /* LOOP THREE */
979 if( pBackend->nBlock == 0 ){
980 break;
981 }
982 pNext = pBlock->pNext;
983 pBackend->pMethods->xFree(pBlock);
984 pBlock = pNext;
985 pBackend->nBlock--;
986 /* LOOP FOUR */
987 }
988 if( pBackend->pMethods->xRelease ){
989 pBackend->pMethods->xRelease(pBackend->pMethods->pUserData);
990 }
991 pBackend->pMethods = 0;
992 pBackend->pBlocks = 0;
993#if defined(UNTRUST)
994 pBackend->nMagic = 0x2626;
995#endif
996 return SXRET_OK;
997}
998JX9_PRIVATE sxi32 SyMemBackendRelease(SyMemBackend *pBackend)
999{
1000 sxi32 rc;
1001#if defined(UNTRUST)
1002 if( SXMEM_BACKEND_CORRUPT(pBackend) ){
1003 return SXERR_INVALID;
1004 }
1005#endif
1006 if( pBackend->pMutexMethods ){
1007 SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex);
1008 }
1009 rc = MemBackendRelease(&(*pBackend));
1010 if( pBackend->pMutexMethods ){
1011 SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex);
1012 SyMutexRelease(pBackend->pMutexMethods, pBackend->pMutex);
1013 }
1014 return rc;
1015}
1016JX9_PRIVATE void * SyMemBackendDup(SyMemBackend *pBackend, const void *pSrc, sxu32 nSize)
1017{
1018 void *pNew;
1019#if defined(UNTRUST)
1020 if( pSrc == 0 || nSize <= 0 ){
1021 return 0;
1022 }
1023#endif
1024 pNew = SyMemBackendAlloc(&(*pBackend), nSize);
1025 if( pNew ){
1026 SyMemcpy(pSrc, pNew, nSize);
1027 }
1028 return pNew;
1029}
1030JX9_PRIVATE char * SyMemBackendStrDup(SyMemBackend *pBackend, const char *zSrc, sxu32 nSize)
1031{
1032 char *zDest;
1033 zDest = (char *)SyMemBackendAlloc(&(*pBackend), nSize + 1);
1034 if( zDest ){
1035 Systrcpy(zDest, nSize+1, zSrc, nSize);
1036 }
1037 return zDest;
1038}
1039JX9_PRIVATE sxi32 SyBlobInitFromBuf(SyBlob *pBlob, void *pBuffer, sxu32 nSize)
1040{
1041#if defined(UNTRUST)
1042 if( pBlob == 0 || pBuffer == 0 || nSize < 1 ){
1043 return SXERR_EMPTY;
1044 }
1045#endif
1046 pBlob->pBlob = pBuffer;
1047 pBlob->mByte = nSize;
1048 pBlob->nByte = 0;
1049 pBlob->pAllocator = 0;
1050 pBlob->nFlags = SXBLOB_LOCKED|SXBLOB_STATIC;
1051 return SXRET_OK;
1052}
1053JX9_PRIVATE sxi32 SyBlobInit(SyBlob *pBlob, SyMemBackend *pAllocator)
1054{
1055#if defined(UNTRUST)
1056 if( pBlob == 0 ){
1057 return SXERR_EMPTY;
1058 }
1059#endif
1060 pBlob->pBlob = 0;
1061 pBlob->mByte = pBlob->nByte = 0;
1062 pBlob->pAllocator = &(*pAllocator);
1063 pBlob->nFlags = 0;
1064 return SXRET_OK;
1065}
1066JX9_PRIVATE sxi32 SyBlobReadOnly(SyBlob *pBlob, const void *pData, sxu32 nByte)
1067{
1068#if defined(UNTRUST)
1069 if( pBlob == 0 ){
1070 return SXERR_EMPTY;
1071 }
1072#endif
1073 pBlob->pBlob = (void *)pData;
1074 pBlob->nByte = nByte;
1075 pBlob->mByte = 0;
1076 pBlob->nFlags |= SXBLOB_RDONLY;
1077 return SXRET_OK;
1078}
1079#ifndef SXBLOB_MIN_GROWTH
1080#define SXBLOB_MIN_GROWTH 16
1081#endif
1082static sxi32 BlobPrepareGrow(SyBlob *pBlob, sxu32 *pByte)
1083{
1084 sxu32 nByte;
1085 void *pNew;
1086 nByte = *pByte;
1087 if( pBlob->nFlags & (SXBLOB_LOCKED|SXBLOB_STATIC) ){
1088 if ( SyBlobFreeSpace(pBlob) < nByte ){
1089 *pByte = SyBlobFreeSpace(pBlob);
1090 if( (*pByte) == 0 ){
1091 return SXERR_SHORT;
1092 }
1093 }
1094 return SXRET_OK;
1095 }
1096 if( pBlob->nFlags & SXBLOB_RDONLY ){
1097 /* Make a copy of the read-only item */
1098 if( pBlob->nByte > 0 ){
1099 pNew = SyMemBackendDup(pBlob->pAllocator, pBlob->pBlob, pBlob->nByte);
1100 if( pNew == 0 ){
1101 return SXERR_MEM;
1102 }
1103 pBlob->pBlob = pNew;
1104 pBlob->mByte = pBlob->nByte;
1105 }else{
1106 pBlob->pBlob = 0;
1107 pBlob->mByte = 0;
1108 }
1109 /* Remove the read-only flag */
1110 pBlob->nFlags &= ~SXBLOB_RDONLY;
1111 }
1112 if( SyBlobFreeSpace(pBlob) >= nByte ){
1113 return SXRET_OK;
1114 }
1115 if( pBlob->mByte > 0 ){
1116 nByte = nByte + pBlob->mByte * 2 + SXBLOB_MIN_GROWTH;
1117 }else if ( nByte < SXBLOB_MIN_GROWTH ){
1118 nByte = SXBLOB_MIN_GROWTH;
1119 }
1120 pNew = SyMemBackendRealloc(pBlob->pAllocator, pBlob->pBlob, nByte);
1121 if( pNew == 0 ){
1122 return SXERR_MEM;
1123 }
1124 pBlob->pBlob = pNew;
1125 pBlob->mByte = nByte;
1126 return SXRET_OK;
1127}
1128JX9_PRIVATE sxi32 SyBlobAppend(SyBlob *pBlob, const void *pData, sxu32 nSize)
1129{
1130 sxu8 *zBlob;
1131 sxi32 rc;
1132 if( nSize < 1 ){
1133 return SXRET_OK;
1134 }
1135 rc = BlobPrepareGrow(&(*pBlob), &nSize);
1136 if( SXRET_OK != rc ){
1137 return rc;
1138 }
1139 if( pData ){
1140 zBlob = (sxu8 *)pBlob->pBlob ;
1141 zBlob = &zBlob[pBlob->nByte];
1142 pBlob->nByte += nSize;
1143 SX_MACRO_FAST_MEMCPY(pData, zBlob, nSize);
1144 }
1145 return SXRET_OK;
1146}
1147JX9_PRIVATE sxi32 SyBlobNullAppend(SyBlob *pBlob)
1148{
1149 sxi32 rc;
1150 sxu32 n;
1151 n = pBlob->nByte;
1152 rc = SyBlobAppend(&(*pBlob), (const void *)"\0", sizeof(char));
1153 if (rc == SXRET_OK ){
1154 pBlob->nByte = n;
1155 }
1156 return rc;
1157}
1158JX9_PRIVATE sxi32 SyBlobDup(SyBlob *pSrc, SyBlob *pDest)
1159{
1160 sxi32 rc = SXRET_OK;
1161 if( pSrc->nByte > 0 ){
1162 rc = SyBlobAppend(&(*pDest), pSrc->pBlob, pSrc->nByte);
1163 }
1164 return rc;
1165}
1166JX9_PRIVATE sxi32 SyBlobReset(SyBlob *pBlob)
1167{
1168 pBlob->nByte = 0;
1169 if( pBlob->nFlags & SXBLOB_RDONLY ){
1170 /* Read-only (Not malloced chunk) */
1171 pBlob->pBlob = 0;
1172 pBlob->mByte = 0;
1173 pBlob->nFlags &= ~SXBLOB_RDONLY;
1174 }
1175 return SXRET_OK;
1176}
1177JX9_PRIVATE sxi32 SyBlobTruncate(SyBlob *pBlob,sxu32 nNewLen)
1178{
1179 if( nNewLen < pBlob->nByte ){
1180 pBlob->nByte = nNewLen;
1181 }
1182 return SXRET_OK;
1183}
1184JX9_PRIVATE sxi32 SyBlobRelease(SyBlob *pBlob)
1185{
1186 if( (pBlob->nFlags & (SXBLOB_STATIC|SXBLOB_RDONLY)) == 0 && pBlob->mByte > 0 ){
1187 SyMemBackendFree(pBlob->pAllocator, pBlob->pBlob);
1188 }
1189 pBlob->pBlob = 0;
1190 pBlob->nByte = pBlob->mByte = 0;
1191 pBlob->nFlags = 0;
1192 return SXRET_OK;
1193}
1194#ifndef JX9_DISABLE_BUILTIN_FUNC
1195JX9_PRIVATE sxi32 SyBlobSearch(const void *pBlob, sxu32 nLen, const void *pPattern, sxu32 pLen, sxu32 *pOfft)
1196{
1197 const char *zIn = (const char *)pBlob;
1198 const char *zEnd;
1199 sxi32 rc;
1200 if( pLen > nLen ){
1201 return SXERR_NOTFOUND;
1202 }
1203 zEnd = &zIn[nLen-pLen];
1204 for(;;){
1205 if( zIn > zEnd ){break;} SX_MACRO_FAST_CMP(zIn, pPattern, pLen, rc); if( rc == 0 ){ if( pOfft ){ *pOfft = (sxu32)(zIn - (const char *)pBlob);} return SXRET_OK; } zIn++;
1206 if( zIn > zEnd ){break;} SX_MACRO_FAST_CMP(zIn, pPattern, pLen, rc); if( rc == 0 ){ if( pOfft ){ *pOfft = (sxu32)(zIn - (const char *)pBlob);} return SXRET_OK; } zIn++;
1207 if( zIn > zEnd ){break;} SX_MACRO_FAST_CMP(zIn, pPattern, pLen, rc); if( rc == 0 ){ if( pOfft ){ *pOfft = (sxu32)(zIn - (const char *)pBlob);} return SXRET_OK; } zIn++;
1208 if( zIn > zEnd ){break;} SX_MACRO_FAST_CMP(zIn, pPattern, pLen, rc); if( rc == 0 ){ if( pOfft ){ *pOfft = (sxu32)(zIn - (const char *)pBlob);} return SXRET_OK; } zIn++;
1209 }
1210 return SXERR_NOTFOUND;
1211}
1212#endif /* JX9_DISABLE_BUILTIN_FUNC */
1213/* SyRunTimeApi:sxds.c */
1214JX9_PRIVATE sxi32 SySetInit(SySet *pSet, SyMemBackend *pAllocator, sxu32 ElemSize)
1215{
1216 pSet->nSize = 0 ;
1217 pSet->nUsed = 0;
1218 pSet->nCursor = 0;
1219 pSet->eSize = ElemSize;
1220 pSet->pAllocator = pAllocator;
1221 pSet->pBase = 0;
1222 pSet->pUserData = 0;
1223 return SXRET_OK;
1224}
1225JX9_PRIVATE sxi32 SySetPut(SySet *pSet, const void *pItem)
1226{
1227 unsigned char *zbase;
1228 if( pSet->nUsed >= pSet->nSize ){
1229 void *pNew;
1230 if( pSet->pAllocator == 0 ){
1231 return SXERR_LOCKED;
1232 }
1233 if( pSet->nSize <= 0 ){
1234 pSet->nSize = 4;
1235 }
1236 pNew = SyMemBackendRealloc(pSet->pAllocator, pSet->pBase, pSet->eSize * pSet->nSize * 2);
1237 if( pNew == 0 ){
1238 return SXERR_MEM;
1239 }
1240 pSet->pBase = pNew;
1241 pSet->nSize <<= 1;
1242 }
1243 zbase = (unsigned char *)pSet->pBase;
1244 SX_MACRO_FAST_MEMCPY(pItem, &zbase[pSet->nUsed * pSet->eSize], pSet->eSize);
1245 pSet->nUsed++;
1246 return SXRET_OK;
1247}
1248JX9_PRIVATE sxi32 SySetAlloc(SySet *pSet, sxi32 nItem)
1249{
1250 if( pSet->nSize > 0 ){
1251 return SXERR_LOCKED;
1252 }
1253 if( nItem < 8 ){
1254 nItem = 8;
1255 }
1256 pSet->pBase = SyMemBackendAlloc(pSet->pAllocator, pSet->eSize * nItem);
1257 if( pSet->pBase == 0 ){
1258 return SXERR_MEM;
1259 }
1260 pSet->nSize = nItem;
1261 return SXRET_OK;
1262}
1263JX9_PRIVATE sxi32 SySetReset(SySet *pSet)
1264{
1265 pSet->nUsed = 0;
1266 pSet->nCursor = 0;
1267 return SXRET_OK;
1268}
1269JX9_PRIVATE sxi32 SySetResetCursor(SySet *pSet)
1270{
1271 pSet->nCursor = 0;
1272 return SXRET_OK;
1273}
1274JX9_PRIVATE sxi32 SySetGetNextEntry(SySet *pSet, void **ppEntry)
1275{
1276 register unsigned char *zSrc;
1277 if( pSet->nCursor >= pSet->nUsed ){
1278 /* Reset cursor */
1279 pSet->nCursor = 0;
1280 return SXERR_EOF;
1281 }
1282 zSrc = (unsigned char *)SySetBasePtr(pSet);
1283 if( ppEntry ){
1284 *ppEntry = (void *)&zSrc[pSet->nCursor * pSet->eSize];
1285 }
1286 pSet->nCursor++;
1287 return SXRET_OK;
1288}
1289JX9_PRIVATE sxi32 SySetRelease(SySet *pSet)
1290{
1291 sxi32 rc = SXRET_OK;
1292 if( pSet->pAllocator && pSet->pBase ){
1293 rc = SyMemBackendFree(pSet->pAllocator, pSet->pBase);
1294 }
1295 pSet->pBase = 0;
1296 pSet->nUsed = 0;
1297 pSet->nCursor = 0;
1298 return rc;
1299}
1300JX9_PRIVATE void * SySetPeek(SySet *pSet)
1301{
1302 const char *zBase;
1303 if( pSet->nUsed <= 0 ){
1304 return 0;
1305 }
1306 zBase = (const char *)pSet->pBase;
1307 return (void *)&zBase[(pSet->nUsed - 1) * pSet->eSize];
1308}
1309JX9_PRIVATE void * SySetPop(SySet *pSet)
1310{
1311 const char *zBase;
1312 void *pData;
1313 if( pSet->nUsed <= 0 ){
1314 return 0;
1315 }
1316 zBase = (const char *)pSet->pBase;
1317 pSet->nUsed--;
1318 pData = (void *)&zBase[pSet->nUsed * pSet->eSize];
1319 return pData;
1320}
1321JX9_PRIVATE void * SySetAt(SySet *pSet, sxu32 nIdx)
1322{
1323 const char *zBase;
1324 if( nIdx >= pSet->nUsed ){
1325 /* Out of range */
1326 return 0;
1327 }
1328 zBase = (const char *)pSet->pBase;
1329 return (void *)&zBase[nIdx * pSet->eSize];
1330}
1331/* Private hash entry */
1332struct SyHashEntry_Pr
1333{
1334 const void *pKey; /* Hash key */
1335 sxu32 nKeyLen; /* Key length */
1336 void *pUserData; /* User private data */
1337 /* Private fields */
1338 sxu32 nHash;
1339 SyHash *pHash;
1340 SyHashEntry_Pr *pNext, *pPrev; /* Next and previous entry in the list */
1341 SyHashEntry_Pr *pNextCollide, *pPrevCollide; /* Collision list */
1342};
1343#define INVALID_HASH(H) ((H)->apBucket == 0)
1344JX9_PRIVATE sxi32 SyHashInit(SyHash *pHash, SyMemBackend *pAllocator, ProcHash xHash, ProcCmp xCmp)
1345{
1346 SyHashEntry_Pr **apNew;
1347#if defined(UNTRUST)
1348 if( pHash == 0 ){
1349 return SXERR_EMPTY;
1350 }
1351#endif
1352 /* Allocate a new table */
1353 apNew = (SyHashEntry_Pr **)SyMemBackendAlloc(&(*pAllocator), sizeof(SyHashEntry_Pr *) * SXHASH_BUCKET_SIZE);
1354 if( apNew == 0 ){
1355 return SXERR_MEM;
1356 }
1357 SyZero((void *)apNew, sizeof(SyHashEntry_Pr *) * SXHASH_BUCKET_SIZE);
1358 pHash->pAllocator = &(*pAllocator);
1359 pHash->xHash = xHash ? xHash : SyBinHash;
1360 pHash->xCmp = xCmp ? xCmp : SyMemcmp;
1361 pHash->pCurrent = pHash->pList = 0;
1362 pHash->nEntry = 0;
1363 pHash->apBucket = apNew;
1364 pHash->nBucketSize = SXHASH_BUCKET_SIZE;
1365 return SXRET_OK;
1366}
1367JX9_PRIVATE sxi32 SyHashRelease(SyHash *pHash)
1368{
1369 SyHashEntry_Pr *pEntry, *pNext;
1370#if defined(UNTRUST)
1371 if( INVALID_HASH(pHash) ){
1372 return SXERR_EMPTY;
1373 }
1374#endif
1375 pEntry = pHash->pList;
1376 for(;;){
1377 if( pHash->nEntry == 0 ){
1378 break;
1379 }
1380 pNext = pEntry->pNext;
1381 SyMemBackendPoolFree(pHash->pAllocator, pEntry);
1382 pEntry = pNext;
1383 pHash->nEntry--;
1384 }
1385 if( pHash->apBucket ){
1386 SyMemBackendFree(pHash->pAllocator, (void *)pHash->apBucket);
1387 }
1388 pHash->apBucket = 0;
1389 pHash->nBucketSize = 0;
1390 pHash->pAllocator = 0;
1391 return SXRET_OK;
1392}
1393static SyHashEntry_Pr * HashGetEntry(SyHash *pHash, const void *pKey, sxu32 nKeyLen)
1394{
1395 SyHashEntry_Pr *pEntry;
1396 sxu32 nHash;
1397
1398 nHash = pHash->xHash(pKey, nKeyLen);
1399 pEntry = pHash->apBucket[nHash & (pHash->nBucketSize - 1)];
1400 for(;;){
1401 if( pEntry == 0 ){
1402 break;
1403 }
1404 if( pEntry->nHash == nHash && pEntry->nKeyLen == nKeyLen &&
1405 pHash->xCmp(pEntry->pKey, pKey, nKeyLen) == 0 ){
1406 return pEntry;
1407 }
1408 pEntry = pEntry->pNextCollide;
1409 }
1410 /* Entry not found */
1411 return 0;
1412}
1413JX9_PRIVATE SyHashEntry * SyHashGet(SyHash *pHash, const void *pKey, sxu32 nKeyLen)
1414{
1415 SyHashEntry_Pr *pEntry;
1416#if defined(UNTRUST)
1417 if( INVALID_HASH(pHash) ){
1418 return 0;
1419 }
1420#endif
1421 if( pHash->nEntry < 1 || nKeyLen < 1 ){
1422 /* Don't bother hashing, return immediately */
1423 return 0;
1424 }
1425 pEntry = HashGetEntry(&(*pHash), pKey, nKeyLen);
1426 if( pEntry == 0 ){
1427 return 0;
1428 }
1429 return (SyHashEntry *)pEntry;
1430}
1431static sxi32 HashDeleteEntry(SyHash *pHash, SyHashEntry_Pr *pEntry, void **ppUserData)
1432{
1433 sxi32 rc;
1434 if( pEntry->pPrevCollide == 0 ){
1435 pHash->apBucket[pEntry->nHash & (pHash->nBucketSize - 1)] = pEntry->pNextCollide;
1436 }else{
1437 pEntry->pPrevCollide->pNextCollide = pEntry->pNextCollide;
1438 }
1439 if( pEntry->pNextCollide ){
1440 pEntry->pNextCollide->pPrevCollide = pEntry->pPrevCollide;
1441 }
1442 MACRO_LD_REMOVE(pHash->pList, pEntry);
1443 pHash->nEntry--;
1444 if( ppUserData ){
1445 /* Write a pointer to the user data */
1446 *ppUserData = pEntry->pUserData;
1447 }
1448 /* Release the entry */
1449 rc = SyMemBackendPoolFree(pHash->pAllocator, pEntry);
1450 return rc;
1451}
1452JX9_PRIVATE sxi32 SyHashDeleteEntry(SyHash *pHash, const void *pKey, sxu32 nKeyLen, void **ppUserData)
1453{
1454 SyHashEntry_Pr *pEntry;
1455 sxi32 rc;
1456#if defined(UNTRUST)
1457 if( INVALID_HASH(pHash) ){
1458 return SXERR_CORRUPT;
1459 }
1460#endif
1461 pEntry = HashGetEntry(&(*pHash), pKey, nKeyLen);
1462 if( pEntry == 0 ){
1463 return SXERR_NOTFOUND;
1464 }
1465 rc = HashDeleteEntry(&(*pHash), pEntry, ppUserData);
1466 return rc;
1467}
1468JX9_PRIVATE sxi32 SyHashForEach(SyHash *pHash, sxi32 (*xStep)(SyHashEntry *, void *), void *pUserData)
1469{
1470 SyHashEntry_Pr *pEntry;
1471 sxi32 rc;
1472 sxu32 n;
1473#if defined(UNTRUST)
1474 if( INVALID_HASH(pHash) || xStep == 0){
1475 return 0;
1476 }
1477#endif
1478 pEntry = pHash->pList;
1479 for( n = 0 ; n < pHash->nEntry ; n++ ){
1480 /* Invoke the callback */
1481 rc = xStep((SyHashEntry *)pEntry, pUserData);
1482 if( rc != SXRET_OK ){
1483 return rc;
1484 }
1485 /* Point to the next entry */
1486 pEntry = pEntry->pNext;
1487 }
1488 return SXRET_OK;
1489}
1490static sxi32 HashGrowTable(SyHash *pHash)
1491{
1492 sxu32 nNewSize = pHash->nBucketSize * 2;
1493 SyHashEntry_Pr *pEntry;
1494 SyHashEntry_Pr **apNew;
1495 sxu32 n, iBucket;
1496
1497 /* Allocate a new larger table */
1498 apNew = (SyHashEntry_Pr **)SyMemBackendAlloc(pHash->pAllocator, nNewSize * sizeof(SyHashEntry_Pr *));
1499 if( apNew == 0 ){
1500 /* Not so fatal, simply a performance hit */
1501 return SXRET_OK;
1502 }
1503 /* Zero the new table */
1504 SyZero((void *)apNew, nNewSize * sizeof(SyHashEntry_Pr *));
1505 /* Rehash all entries */
1506 for( n = 0, pEntry = pHash->pList; n < pHash->nEntry ; n++ ){
1507 pEntry->pNextCollide = pEntry->pPrevCollide = 0;
1508 /* Install in the new bucket */
1509 iBucket = pEntry->nHash & (nNewSize - 1);
1510 pEntry->pNextCollide = apNew[iBucket];
1511 if( apNew[iBucket] != 0 ){
1512 apNew[iBucket]->pPrevCollide = pEntry;
1513 }
1514 apNew[iBucket] = pEntry;
1515 /* Point to the next entry */
1516 pEntry = pEntry->pNext;
1517 }
1518 /* Release the old table and reflect the change */
1519 SyMemBackendFree(pHash->pAllocator, (void *)pHash->apBucket);
1520 pHash->apBucket = apNew;
1521 pHash->nBucketSize = nNewSize;
1522 return SXRET_OK;
1523}
1524static sxi32 HashInsert(SyHash *pHash, SyHashEntry_Pr *pEntry)
1525{
1526 sxu32 iBucket = pEntry->nHash & (pHash->nBucketSize - 1);
1527 /* Insert the entry in its corresponding bcuket */
1528 pEntry->pNextCollide = pHash->apBucket[iBucket];
1529 if( pHash->apBucket[iBucket] != 0 ){
1530 pHash->apBucket[iBucket]->pPrevCollide = pEntry;
1531 }
1532 pHash->apBucket[iBucket] = pEntry;
1533 /* Link to the entry list */
1534 MACRO_LD_PUSH(pHash->pList, pEntry);
1535 if( pHash->nEntry == 0 ){
1536 pHash->pCurrent = pHash->pList;
1537 }
1538 pHash->nEntry++;
1539 return SXRET_OK;
1540}
1541JX9_PRIVATE sxi32 SyHashInsert(SyHash *pHash, const void *pKey, sxu32 nKeyLen, void *pUserData)
1542{
1543 SyHashEntry_Pr *pEntry;
1544 sxi32 rc;
1545#if defined(UNTRUST)
1546 if( INVALID_HASH(pHash) || pKey == 0 ){
1547 return SXERR_CORRUPT;
1548 }
1549#endif
1550 if( pHash->nEntry >= pHash->nBucketSize * SXHASH_FILL_FACTOR ){
1551 rc = HashGrowTable(&(*pHash));
1552 if( rc != SXRET_OK ){
1553 return rc;
1554 }
1555 }
1556 /* Allocate a new hash entry */
1557 pEntry = (SyHashEntry_Pr *)SyMemBackendPoolAlloc(pHash->pAllocator, sizeof(SyHashEntry_Pr));
1558 if( pEntry == 0 ){
1559 return SXERR_MEM;
1560 }
1561 /* Zero the entry */
1562 SyZero(pEntry, sizeof(SyHashEntry_Pr));
1563 pEntry->pHash = pHash;
1564 pEntry->pKey = pKey;
1565 pEntry->nKeyLen = nKeyLen;
1566 pEntry->pUserData = pUserData;
1567 pEntry->nHash = pHash->xHash(pEntry->pKey, pEntry->nKeyLen);
1568 /* Finally insert the entry in its corresponding bucket */
1569 rc = HashInsert(&(*pHash), pEntry);
1570 return rc;
1571}
1572/* SyRunTimeApi:sxutils.c */
1573JX9_PRIVATE sxi32 SyStrIsNumeric(const char *zSrc, sxu32 nLen, sxu8 *pReal, const char **pzTail)
1574{
1575 const char *zCur, *zEnd;
1576#ifdef UNTRUST
1577 if( SX_EMPTY_STR(zSrc) ){
1578 return SXERR_EMPTY;
1579 }
1580#endif
1581 zEnd = &zSrc[nLen];
1582 /* Jump leading white spaces */
1583 while( zSrc < zEnd && (unsigned char)zSrc[0] < 0xc0 && SyisSpace(zSrc[0]) ){
1584 zSrc++;
1585 }
1586 if( zSrc < zEnd && (zSrc[0] == '+' || zSrc[0] == '-') ){
1587 zSrc++;
1588 }
1589 zCur = zSrc;
1590 if( pReal ){
1591 *pReal = FALSE;
1592 }
1593 for(;;){
1594 if( zSrc >= zEnd || (unsigned char)zSrc[0] >= 0xc0 || !SyisDigit(zSrc[0]) ){ break; } zSrc++;
1595 if( zSrc >= zEnd || (unsigned char)zSrc[0] >= 0xc0 || !SyisDigit(zSrc[0]) ){ break; } zSrc++;
1596 if( zSrc >= zEnd || (unsigned char)zSrc[0] >= 0xc0 || !SyisDigit(zSrc[0]) ){ break; } zSrc++;
1597 if( zSrc >= zEnd || (unsigned char)zSrc[0] >= 0xc0 || !SyisDigit(zSrc[0]) ){ break; } zSrc++;
1598 };
1599 if( zSrc < zEnd && zSrc > zCur ){
1600 int c = zSrc[0];
1601 if( c == '.' ){
1602 zSrc++;
1603 if( pReal ){
1604 *pReal = TRUE;
1605 }
1606 if( pzTail ){
1607 while( zSrc < zEnd && (unsigned char)zSrc[0] < 0xc0 && SyisDigit(zSrc[0]) ){
1608 zSrc++;
1609 }
1610 if( zSrc < zEnd && (zSrc[0] == 'e' || zSrc[0] == 'E') ){
1611 zSrc++;
1612 if( zSrc < zEnd && (zSrc[0] == '+' || zSrc[0] == '-') ){
1613 zSrc++;
1614 }
1615 while( zSrc < zEnd && (unsigned char)zSrc[0] < 0xc0 && SyisDigit(zSrc[0]) ){
1616 zSrc++;
1617 }
1618 }
1619 }
1620 }else if( c == 'e' || c == 'E' ){
1621 zSrc++;
1622 if( pReal ){
1623 *pReal = TRUE;
1624 }
1625 if( pzTail ){
1626 if( zSrc < zEnd && (zSrc[0] == '+' || zSrc[0] == '-') ){
1627 zSrc++;
1628 }
1629 while( zSrc < zEnd && (unsigned char)zSrc[0] < 0xc0 && SyisDigit(zSrc[0]) ){
1630 zSrc++;
1631 }
1632 }
1633 }
1634 }
1635 if( pzTail ){
1636 /* Point to the non numeric part */
1637 *pzTail = zSrc;
1638 }
1639 return zSrc > zCur ? SXRET_OK /* String prefix is numeric */ : SXERR_INVALID /* Not a digit stream */;
1640}
1641#define SXINT32_MIN_STR "2147483648"
1642#define SXINT32_MAX_STR "2147483647"
1643#define SXINT64_MIN_STR "9223372036854775808"
1644#define SXINT64_MAX_STR "9223372036854775807"
1645JX9_PRIVATE sxi32 SyStrToInt32(const char *zSrc, sxu32 nLen, void * pOutVal, const char **zRest)
1646{
1647 int isNeg = FALSE;
1648 const char *zEnd;
1649 sxi32 nVal = 0;
1650 sxi16 i;
1651#if defined(UNTRUST)
1652 if( SX_EMPTY_STR(zSrc) ){
1653 if( pOutVal ){
1654 *(sxi32 *)pOutVal = 0;
1655 }
1656 return SXERR_EMPTY;
1657 }
1658#endif
1659 zEnd = &zSrc[nLen];
1660 while(zSrc < zEnd && SyisSpace(zSrc[0]) ){
1661 zSrc++;
1662 }
1663 if( zSrc < zEnd && ( zSrc[0] == '-' || zSrc[0] == '+' ) ){
1664 isNeg = (zSrc[0] == '-') ? TRUE :FALSE;
1665 zSrc++;
1666 }
1667 /* Skip leading zero */
1668 while(zSrc < zEnd && zSrc[0] == '0' ){
1669 zSrc++;
1670 }
1671 i = 10;
1672 if( (sxu32)(zEnd-zSrc) >= 10 ){
1673 /* Handle overflow */
1674 i = SyMemcmp(zSrc, (isNeg == TRUE) ? SXINT32_MIN_STR : SXINT32_MAX_STR, nLen) <= 0 ? 10 : 9;
1675 }
1676 for(;;){
1677 if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++;
1678 if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++;
1679 if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++;
1680 if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++;
1681 }
1682 /* Skip trailing spaces */
1683 while(zSrc < zEnd && SyisSpace(zSrc[0])){
1684 zSrc++;
1685 }
1686 if( zRest ){
1687 *zRest = (char *)zSrc;
1688 }
1689 if( pOutVal ){
1690 if( isNeg == TRUE && nVal != 0 ){
1691 nVal = -nVal;
1692 }
1693 *(sxi32 *)pOutVal = nVal;
1694 }
1695 return (zSrc >= zEnd) ? SXRET_OK : SXERR_SYNTAX;
1696}
1697JX9_PRIVATE sxi32 SyStrToInt64(const char *zSrc, sxu32 nLen, void * pOutVal, const char **zRest)
1698{
1699 int isNeg = FALSE;
1700 const char *zEnd;
1701 sxi64 nVal;
1702 sxi16 i;
1703#if defined(UNTRUST)
1704 if( SX_EMPTY_STR(zSrc) ){
1705 if( pOutVal ){
1706 *(sxi32 *)pOutVal = 0;
1707 }
1708 return SXERR_EMPTY;
1709 }
1710#endif
1711 zEnd = &zSrc[nLen];
1712 while(zSrc < zEnd && SyisSpace(zSrc[0]) ){
1713 zSrc++;
1714 }
1715 if( zSrc < zEnd && ( zSrc[0] == '-' || zSrc[0] == '+' ) ){
1716 isNeg = (zSrc[0] == '-') ? TRUE :FALSE;
1717 zSrc++;
1718 }
1719 /* Skip leading zero */
1720 while(zSrc < zEnd && zSrc[0] == '0' ){
1721 zSrc++;
1722 }
1723 i = 19;
1724 if( (sxu32)(zEnd-zSrc) >= 19 ){
1725 i = SyMemcmp(zSrc, isNeg ? SXINT64_MIN_STR : SXINT64_MAX_STR, 19) <= 0 ? 19 : 18 ;
1726 }
1727 nVal = 0;
1728 for(;;){
1729 if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++;
1730 if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++;
1731 if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++;
1732 if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++;
1733 }
1734 /* Skip trailing spaces */
1735 while(zSrc < zEnd && SyisSpace(zSrc[0])){
1736 zSrc++;
1737 }
1738 if( zRest ){
1739 *zRest = (char *)zSrc;
1740 }
1741 if( pOutVal ){
1742 if( isNeg == TRUE && nVal != 0 ){
1743 nVal = -nVal;
1744 }
1745 *(sxi64 *)pOutVal = nVal;
1746 }
1747 return (zSrc >= zEnd) ? SXRET_OK : SXERR_SYNTAX;
1748}
1749JX9_PRIVATE sxi32 SyHexToint(sxi32 c)
1750{
1751 switch(c){
1752 case '0': return 0;
1753 case '1': return 1;
1754 case '2': return 2;
1755 case '3': return 3;
1756 case '4': return 4;
1757 case '5': return 5;
1758 case '6': return 6;
1759 case '7': return 7;
1760 case '8': return 8;
1761 case '9': return 9;
1762 case 'A': case 'a': return 10;
1763 case 'B': case 'b': return 11;
1764 case 'C': case 'c': return 12;
1765 case 'D': case 'd': return 13;
1766 case 'E': case 'e': return 14;
1767 case 'F': case 'f': return 15;
1768 }
1769 return -1;
1770}
1771JX9_PRIVATE sxi32 SyHexStrToInt64(const char *zSrc, sxu32 nLen, void * pOutVal, const char **zRest)
1772{
1773 const char *zIn, *zEnd;
1774 int isNeg = FALSE;
1775 sxi64 nVal = 0;
1776#if defined(UNTRUST)
1777 if( SX_EMPTY_STR(zSrc) ){
1778 if( pOutVal ){
1779 *(sxi32 *)pOutVal = 0;
1780 }
1781 return SXERR_EMPTY;
1782 }
1783#endif
1784 zEnd = &zSrc[nLen];
1785 while( zSrc < zEnd && SyisSpace(zSrc[0]) ){
1786 zSrc++;
1787 }
1788 if( zSrc < zEnd && ( *zSrc == '-' || *zSrc == '+' ) ){
1789 isNeg = (zSrc[0] == '-') ? TRUE :FALSE;
1790 zSrc++;
1791 }
1792 if( zSrc < &zEnd[-2] && zSrc[0] == '0' && (zSrc[1] == 'x' || zSrc[1] == 'X') ){
1793 /* Bypass hex prefix */
1794 zSrc += sizeof(char) * 2;
1795 }
1796 /* Skip leading zero */
1797 while(zSrc < zEnd && zSrc[0] == '0' ){
1798 zSrc++;
1799 }
1800 zIn = zSrc;
1801 for(;;){
1802 if(zSrc >= zEnd || !SyisHex(zSrc[0]) || (int)(zSrc-zIn) > 15) break; nVal = nVal * 16 + SyHexToint(zSrc[0]); zSrc++ ;
1803 if(zSrc >= zEnd || !SyisHex(zSrc[0]) || (int)(zSrc-zIn) > 15) break; nVal = nVal * 16 + SyHexToint(zSrc[0]); zSrc++ ;
1804 if(zSrc >= zEnd || !SyisHex(zSrc[0]) || (int)(zSrc-zIn) > 15) break; nVal = nVal * 16 + SyHexToint(zSrc[0]); zSrc++ ;
1805 if(zSrc >= zEnd || !SyisHex(zSrc[0]) || (int)(zSrc-zIn) > 15) break; nVal = nVal * 16 + SyHexToint(zSrc[0]); zSrc++ ;
1806 }
1807 while( zSrc < zEnd && SyisSpace(zSrc[0]) ){
1808 zSrc++;
1809 }
1810 if( zRest ){
1811 *zRest = zSrc;
1812 }
1813 if( pOutVal ){
1814 if( isNeg == TRUE && nVal != 0 ){
1815 nVal = -nVal;
1816 }
1817 *(sxi64 *)pOutVal = nVal;
1818 }
1819 return zSrc >= zEnd ? SXRET_OK : SXERR_SYNTAX;
1820}
1821JX9_PRIVATE sxi32 SyOctalStrToInt64(const char *zSrc, sxu32 nLen, void * pOutVal, const char **zRest)
1822{
1823 const char *zIn, *zEnd;
1824 int isNeg = FALSE;
1825 sxi64 nVal = 0;
1826 int c;
1827#if defined(UNTRUST)
1828 if( SX_EMPTY_STR(zSrc) ){
1829 if( pOutVal ){
1830 *(sxi32 *)pOutVal = 0;
1831 }
1832 return SXERR_EMPTY;
1833 }
1834#endif
1835 zEnd = &zSrc[nLen];
1836 while(zSrc < zEnd && SyisSpace(zSrc[0]) ){
1837 zSrc++;
1838 }
1839 if( zSrc < zEnd && ( zSrc[0] == '-' || zSrc[0] == '+' ) ){
1840 isNeg = (zSrc[0] == '-') ? TRUE :FALSE;
1841 zSrc++;
1842 }
1843 /* Skip leading zero */
1844 while(zSrc < zEnd && zSrc[0] == '0' ){
1845 zSrc++;
1846 }
1847 zIn = zSrc;
1848 for(;;){
1849 if(zSrc >= zEnd || !SyisDigit(zSrc[0])){ break; } if( (c=zSrc[0]-'0') > 7 || (int)(zSrc-zIn) > 20){ break;} nVal = nVal * 8 + c; zSrc++;
1850 if(zSrc >= zEnd || !SyisDigit(zSrc[0])){ break; } if( (c=zSrc[0]-'0') > 7 || (int)(zSrc-zIn) > 20){ break;} nVal = nVal * 8 + c; zSrc++;
1851 if(zSrc >= zEnd || !SyisDigit(zSrc[0])){ break; } if( (c=zSrc[0]-'0') > 7 || (int)(zSrc-zIn) > 20){ break;} nVal = nVal * 8 + c; zSrc++;
1852 if(zSrc >= zEnd || !SyisDigit(zSrc[0])){ break; } if( (c=zSrc[0]-'0') > 7 || (int)(zSrc-zIn) > 20){ break;} nVal = nVal * 8 + c; zSrc++;
1853 }
1854 /* Skip trailing spaces */
1855 while(zSrc < zEnd && SyisSpace(zSrc[0])){
1856 zSrc++;
1857 }
1858 if( zRest ){
1859 *zRest = zSrc;
1860 }
1861 if( pOutVal ){
1862 if( isNeg == TRUE && nVal != 0 ){
1863 nVal = -nVal;
1864 }
1865 *(sxi64 *)pOutVal = nVal;
1866 }
1867 return (zSrc >= zEnd) ? SXRET_OK : SXERR_SYNTAX;
1868}
1869JX9_PRIVATE sxi32 SyBinaryStrToInt64(const char *zSrc, sxu32 nLen, void * pOutVal, const char **zRest)
1870{
1871 const char *zIn, *zEnd;
1872 int isNeg = FALSE;
1873 sxi64 nVal = 0;
1874 int c;
1875#if defined(UNTRUST)
1876 if( SX_EMPTY_STR(zSrc) ){
1877 if( pOutVal ){
1878 *(sxi32 *)pOutVal = 0;
1879 }
1880 return SXERR_EMPTY;
1881 }
1882#endif
1883 zEnd = &zSrc[nLen];
1884 while(zSrc < zEnd && SyisSpace(zSrc[0]) ){
1885 zSrc++;
1886 }
1887 if( zSrc < zEnd && ( zSrc[0] == '-' || zSrc[0] == '+' ) ){
1888 isNeg = (zSrc[0] == '-') ? TRUE :FALSE;
1889 zSrc++;
1890 }
1891 if( zSrc < &zEnd[-2] && zSrc[0] == '0' && (zSrc[1] == 'b' || zSrc[1] == 'B') ){
1892 /* Bypass binary prefix */
1893 zSrc += sizeof(char) * 2;
1894 }
1895 /* Skip leading zero */
1896 while(zSrc < zEnd && zSrc[0] == '0' ){
1897 zSrc++;
1898 }
1899 zIn = zSrc;
1900 for(;;){
1901 if(zSrc >= zEnd || (zSrc[0] != '1' && zSrc[0] != '0') || (int)(zSrc-zIn) > 62){ break; } c = zSrc[0] - '0'; nVal = (nVal << 1) + c; zSrc++;
1902 if(zSrc >= zEnd || (zSrc[0] != '1' && zSrc[0] != '0') || (int)(zSrc-zIn) > 62){ break; } c = zSrc[0] - '0'; nVal = (nVal << 1) + c; zSrc++;
1903 if(zSrc >= zEnd || (zSrc[0] != '1' && zSrc[0] != '0') || (int)(zSrc-zIn) > 62){ break; } c = zSrc[0] - '0'; nVal = (nVal << 1) + c; zSrc++;
1904 if(zSrc >= zEnd || (zSrc[0] != '1' && zSrc[0] != '0') || (int)(zSrc-zIn) > 62){ break; } c = zSrc[0] - '0'; nVal = (nVal << 1) + c; zSrc++;
1905 }
1906 /* Skip trailing spaces */
1907 while(zSrc < zEnd && SyisSpace(zSrc[0])){
1908 zSrc++;
1909 }
1910 if( zRest ){
1911 *zRest = zSrc;
1912 }
1913 if( pOutVal ){
1914 if( isNeg == TRUE && nVal != 0 ){
1915 nVal = -nVal;
1916 }
1917 *(sxi64 *)pOutVal = nVal;
1918 }
1919 return (zSrc >= zEnd) ? SXRET_OK : SXERR_SYNTAX;
1920}
1921JX9_PRIVATE sxi32 SyStrToReal(const char *zSrc, sxu32 nLen, void * pOutVal, const char **zRest)
1922{
1923#define SXDBL_DIG 15
1924#define SXDBL_MAX_EXP 308
1925#define SXDBL_MIN_EXP_PLUS 307
1926 static const sxreal aTab[] = {
1927 10,
1928 1.0e2,
1929 1.0e4,
1930 1.0e8,
1931 1.0e16,
1932 1.0e32,
1933 1.0e64,
1934 1.0e128,
1935 1.0e256
1936 };
1937 sxu8 neg = FALSE;
1938 sxreal Val = 0.0;
1939 const char *zEnd;
1940 sxi32 Lim, exp;
1941 sxreal *p = 0;
1942#ifdef UNTRUST
1943 if( SX_EMPTY_STR(zSrc) ){
1944 if( pOutVal ){
1945 *(sxreal *)pOutVal = 0.0;
1946 }
1947 return SXERR_EMPTY;
1948 }
1949#endif
1950 zEnd = &zSrc[nLen];
1951 while( zSrc < zEnd && SyisSpace(zSrc[0]) ){
1952 zSrc++;
1953 }
1954 if( zSrc < zEnd && (zSrc[0] == '-' || zSrc[0] == '+' ) ){
1955 neg = zSrc[0] == '-' ? TRUE : FALSE ;
1956 zSrc++;
1957 }
1958 Lim = SXDBL_DIG ;
1959 for(;;){
1960 if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; zSrc++ ; --Lim;
1961 if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; zSrc++ ; --Lim;
1962 if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; zSrc++ ; --Lim;
1963 if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; zSrc++ ; --Lim;
1964 }
1965 if( zSrc < zEnd && ( zSrc[0] == '.' || zSrc[0] == ',' ) ){
1966 sxreal dec = 1.0;
1967 zSrc++;
1968 for(;;){
1969 if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; dec *= 10.0; zSrc++ ;--Lim;
1970 if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; dec *= 10.0; zSrc++ ;--Lim;
1971 if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; dec *= 10.0; zSrc++ ;--Lim;
1972 if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; dec *= 10.0; zSrc++ ;--Lim;
1973 }
1974 Val /= dec;
1975 }
1976 if( neg == TRUE && Val != 0.0 ) {
1977 Val = -Val ;
1978 }
1979 if( Lim <= 0 ){
1980 /* jump overflow digit */
1981 while( zSrc < zEnd ){
1982 if( zSrc[0] == 'e' || zSrc[0] == 'E' ){
1983 break;
1984 }
1985 zSrc++;
1986 }
1987 }
1988 neg = FALSE;
1989 if( zSrc < zEnd && ( zSrc[0] == 'e' || zSrc[0] == 'E' ) ){
1990 zSrc++;
1991 if( zSrc < zEnd && ( zSrc[0] == '-' || zSrc[0] == '+') ){
1992 neg = zSrc[0] == '-' ? TRUE : FALSE ;
1993 zSrc++;
1994 }
1995 exp = 0;
1996 while( zSrc < zEnd && SyisDigit(zSrc[0]) && exp < SXDBL_MAX_EXP ){
1997 exp = exp * 10 + (zSrc[0] - '0');
1998 zSrc++;
1999 }
2000 if( neg ){
2001 if( exp > SXDBL_MIN_EXP_PLUS ) exp = SXDBL_MIN_EXP_PLUS ;
2002 }else if ( exp > SXDBL_MAX_EXP ){
2003 exp = SXDBL_MAX_EXP;
2004 }
2005 for( p = (sxreal *)aTab ; exp ; exp >>= 1 , p++ ){
2006 if( exp & 01 ){
2007 if( neg ){
2008 Val /= *p ;
2009 }else{
2010 Val *= *p;
2011 }
2012 }
2013 }
2014 }
2015 while( zSrc < zEnd && SyisSpace(zSrc[0]) ){
2016 zSrc++;
2017 }
2018 if( zRest ){
2019 *zRest = zSrc;
2020 }
2021 if( pOutVal ){
2022 *(sxreal *)pOutVal = Val;
2023 }
2024 return zSrc >= zEnd ? SXRET_OK : SXERR_SYNTAX;
2025}
2026/* SyRunTimeApi:sxlib.c */
2027JX9_PRIVATE sxu32 SyBinHash(const void *pSrc, sxu32 nLen)
2028{
2029 register unsigned char *zIn = (unsigned char *)pSrc;
2030 unsigned char *zEnd;
2031 sxu32 nH = 5381;
2032 zEnd = &zIn[nLen];
2033 for(;;){
2034 if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
2035 if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
2036 if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
2037 if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
2038 }
2039 return nH;
2040}
2041#ifndef JX9_DISABLE_BUILTIN_FUNC
2042JX9_PRIVATE sxi32 SyBase64Encode(const char *zSrc, sxu32 nLen, ProcConsumer xConsumer, void *pUserData)
2043{
2044 static const unsigned char zBase64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2045 unsigned char *zIn = (unsigned char *)zSrc;
2046 unsigned char z64[4];
2047 sxu32 i;
2048 sxi32 rc;
2049#if defined(UNTRUST)
2050 if( SX_EMPTY_STR(zSrc) || xConsumer == 0){
2051 return SXERR_EMPTY;
2052 }
2053#endif
2054 for(i = 0; i + 2 < nLen; i += 3){
2055 z64[0] = zBase64[(zIn[i] >> 2) & 0x3F];
2056 z64[1] = zBase64[( ((zIn[i] & 0x03) << 4) | (zIn[i+1] >> 4)) & 0x3F];
2057 z64[2] = zBase64[( ((zIn[i+1] & 0x0F) << 2) | (zIn[i + 2] >> 6) ) & 0x3F];
2058 z64[3] = zBase64[ zIn[i + 2] & 0x3F];
2059
2060 rc = xConsumer((const void *)z64, sizeof(z64), pUserData);
2061 if( rc != SXRET_OK ){return SXERR_ABORT;}
2062
2063 }
2064 if ( i+1 < nLen ){
2065 z64[0] = zBase64[(zIn[i] >> 2) & 0x3F];
2066 z64[1] = zBase64[( ((zIn[i] & 0x03) << 4) | (zIn[i+1] >> 4)) & 0x3F];
2067 z64[2] = zBase64[(zIn[i+1] & 0x0F) << 2 ];
2068 z64[3] = '=';
2069
2070 rc = xConsumer((const void *)z64, sizeof(z64), pUserData);
2071 if( rc != SXRET_OK ){return SXERR_ABORT;}
2072
2073 }else if( i < nLen ){
2074 z64[0] = zBase64[(zIn[i] >> 2) & 0x3F];
2075 z64[1] = zBase64[(zIn[i] & 0x03) << 4];
2076 z64[2] = '=';
2077 z64[3] = '=';
2078
2079 rc = xConsumer((const void *)z64, sizeof(z64), pUserData);
2080 if( rc != SXRET_OK ){return SXERR_ABORT;}
2081 }
2082
2083 return SXRET_OK;
2084}
2085JX9_PRIVATE sxi32 SyBase64Decode(const char *zB64, sxu32 nLen, ProcConsumer xConsumer, void *pUserData)
2086{
2087 static const sxu32 aBase64Trans[] = {
2088 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2089 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
2090 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27,
2091 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0,
2092 0, 0, 0
2093 };
2094 sxu32 n, w, x, y, z;
2095 sxi32 rc;
2096 unsigned char zOut[10];
2097#if defined(UNTRUST)
2098 if( SX_EMPTY_STR(zB64) || xConsumer == 0 ){
2099 return SXERR_EMPTY;
2100 }
2101#endif
2102 while(nLen > 0 && zB64[nLen - 1] == '=' ){
2103 nLen--;
2104 }
2105 for( n = 0 ; n+3<nLen ; n += 4){
2106 w = aBase64Trans[zB64[n] & 0x7F];
2107 x = aBase64Trans[zB64[n+1] & 0x7F];
2108 y = aBase64Trans[zB64[n+2] & 0x7F];
2109 z = aBase64Trans[zB64[n+3] & 0x7F];
2110 zOut[0] = ((w<<2) & 0xFC) | ((x>>4) & 0x03);
2111 zOut[1] = ((x<<4) & 0xF0) | ((y>>2) & 0x0F);
2112 zOut[2] = ((y<<6) & 0xC0) | (z & 0x3F);
2113
2114 rc = xConsumer((const void *)zOut, sizeof(unsigned char)*3, pUserData);
2115 if( rc != SXRET_OK ){ return SXERR_ABORT;}
2116 }
2117 if( n+2 < nLen ){
2118 w = aBase64Trans[zB64[n] & 0x7F];
2119 x = aBase64Trans[zB64[n+1] & 0x7F];
2120 y = aBase64Trans[zB64[n+2] & 0x7F];
2121
2122 zOut[0] = ((w<<2) & 0xFC) | ((x>>4) & 0x03);
2123 zOut[1] = ((x<<4) & 0xF0) | ((y>>2) & 0x0F);
2124
2125 rc = xConsumer((const void *)zOut, sizeof(unsigned char)*2, pUserData);
2126 if( rc != SXRET_OK ){ return SXERR_ABORT;}
2127 }else if( n+1 < nLen ){
2128 w = aBase64Trans[zB64[n] & 0x7F];
2129 x = aBase64Trans[zB64[n+1] & 0x7F];
2130
2131 zOut[0] = ((w<<2) & 0xFC) | ((x>>4) & 0x03);
2132
2133 rc = xConsumer((const void *)zOut, sizeof(unsigned char)*1, pUserData);
2134 if( rc != SXRET_OK ){ return SXERR_ABORT;}
2135 }
2136 return SXRET_OK;
2137}
2138#endif /* JX9_DISABLE_BUILTIN_FUNC */
2139#define INVALID_LEXER(LEX) ( LEX == 0 || LEX->xTokenizer == 0 )
2140JX9_PRIVATE sxi32 SyLexInit(SyLex *pLex, SySet *pSet, ProcTokenizer xTokenizer, void *pUserData)
2141{
2142 SyStream *pStream;
2143#if defined (UNTRUST)
2144 if ( pLex == 0 || xTokenizer == 0 ){
2145 return SXERR_CORRUPT;
2146 }
2147#endif
2148 pLex->pTokenSet = 0;
2149 /* Initialize lexer fields */
2150 if( pSet ){
2151 if ( SySetElemSize(pSet) != sizeof(SyToken) ){
2152 return SXERR_INVALID;
2153 }
2154 pLex->pTokenSet = pSet;
2155 }
2156 pStream = &pLex->sStream;
2157 pLex->xTokenizer = xTokenizer;
2158 pLex->pUserData = pUserData;
2159
2160 pStream->nLine = 1;
2161 pStream->nIgn = 0;
2162 pStream->zText = pStream->zEnd = 0;
2163 pStream->pSet = pSet;
2164 return SXRET_OK;
2165}
2166JX9_PRIVATE sxi32 SyLexTokenizeInput(SyLex *pLex, const char *zInput, sxu32 nLen, void *pCtxData, ProcSort xSort, ProcCmp xCmp)
2167{
2168 const unsigned char *zCur;
2169 SyStream *pStream;
2170 SyToken sToken;
2171 sxi32 rc;
2172#if defined (UNTRUST)
2173 if ( INVALID_LEXER(pLex) || zInput == 0 ){
2174 return SXERR_CORRUPT;
2175 }
2176#endif
2177 pStream = &pLex->sStream;
2178 /* Point to the head of the input */
2179 pStream->zText = pStream->zInput = (const unsigned char *)zInput;
2180 /* Point to the end of the input */
2181 pStream->zEnd = &pStream->zInput[nLen];
2182 for(;;){
2183 if( pStream->zText >= pStream->zEnd ){
2184 /* End of the input reached */
2185 break;
2186 }
2187 zCur = pStream->zText;
2188 /* Call the tokenizer callback */
2189 rc = pLex->xTokenizer(pStream, &sToken, pLex->pUserData, pCtxData);
2190 if( rc != SXRET_OK && rc != SXERR_CONTINUE ){
2191 /* Tokenizer callback request an operation abort */
2192 if( rc == SXERR_ABORT ){
2193 return SXERR_ABORT;
2194 }
2195 break;
2196 }
2197 if( rc == SXERR_CONTINUE ){
2198 /* Request to ignore this token */
2199 pStream->nIgn++;
2200 }else if( pLex->pTokenSet ){
2201 /* Put the token in the set */
2202 rc = SySetPut(pLex->pTokenSet, (const void *)&sToken);
2203 if( rc != SXRET_OK ){
2204 break;
2205 }
2206 }
2207 if( zCur >= pStream->zText ){
2208 /* Automatic advance of the stream cursor */
2209 pStream->zText = &zCur[1];
2210 }
2211 }
2212 if( xSort && pLex->pTokenSet ){
2213 SyToken *aToken = (SyToken *)SySetBasePtr(pLex->pTokenSet);
2214 /* Sort the extrated tokens */
2215 if( xCmp == 0 ){
2216 /* Use a default comparison function */
2217 xCmp = SyMemcmp;
2218 }
2219 xSort(aToken, SySetUsed(pLex->pTokenSet), sizeof(SyToken), xCmp);
2220 }
2221 return SXRET_OK;
2222}
2223JX9_PRIVATE sxi32 SyLexRelease(SyLex *pLex)
2224{
2225 sxi32 rc = SXRET_OK;
2226#if defined (UNTRUST)
2227 if ( INVALID_LEXER(pLex) ){
2228 return SXERR_CORRUPT;
2229 }
2230#else
2231 SXUNUSED(pLex); /* Prevent compiler warning */
2232#endif
2233 return rc;
2234}
2235#ifndef JX9_DISABLE_BUILTIN_FUNC
2236#define SAFE_HTTP(C) (SyisAlphaNum(c) || c == '_' || c == '-' || c == '$' || c == '.' )
2237JX9_PRIVATE sxi32 SyUriEncode(const char *zSrc, sxu32 nLen, ProcConsumer xConsumer, void *pUserData)
2238{
2239 unsigned char *zIn = (unsigned char *)zSrc;
2240 unsigned char zHex[3] = { '%', 0, 0 };
2241 unsigned char zOut[2];
2242 unsigned char *zCur, *zEnd;
2243 sxi32 c;
2244 sxi32 rc;
2245#ifdef UNTRUST
2246 if( SX_EMPTY_STR(zSrc) || xConsumer == 0 ){
2247 return SXERR_EMPTY;
2248 }
2249#endif
2250 rc = SXRET_OK;
2251 zEnd = &zIn[nLen]; zCur = zIn;
2252 for(;;){
2253 if( zCur >= zEnd ){
2254 if( zCur != zIn ){
2255 rc = xConsumer(zIn, (sxu32)(zCur-zIn), pUserData);
2256 }
2257 break;
2258 }
2259 c = zCur[0];
2260 if( SAFE_HTTP(c) ){
2261 zCur++; continue;
2262 }
2263 if( zCur != zIn && SXRET_OK != (rc = xConsumer(zIn, (sxu32)(zCur-zIn), pUserData))){
2264 break;
2265 }
2266 if( c == ' ' ){
2267 zOut[0] = '+';
2268 rc = xConsumer((const void *)zOut, sizeof(unsigned char), pUserData);
2269 }else{
2270 zHex[1] = "0123456789ABCDEF"[(c >> 4) & 0x0F];
2271 zHex[2] = "0123456789ABCDEF"[c & 0x0F];
2272 rc = xConsumer(zHex, sizeof(zHex), pUserData);
2273 }
2274 if( SXRET_OK != rc ){
2275 break;
2276 }
2277 zIn = &zCur[1]; zCur = zIn ;
2278 }
2279 return rc == SXRET_OK ? SXRET_OK : SXERR_ABORT;
2280}
2281#endif /* JX9_DISABLE_BUILTIN_FUNC */
2282static sxi32 SyAsciiToHex(sxi32 c)
2283{
2284 if( c >= 'a' && c <= 'f' ){
2285 c += 10 - 'a';
2286 return c;
2287 }
2288 if( c >= '0' && c <= '9' ){
2289 c -= '0';
2290 return c;
2291 }
2292 if( c >= 'A' && c <= 'F') {
2293 c += 10 - 'A';
2294 return c;
2295 }
2296 return 0;
2297}
2298JX9_PRIVATE sxi32 SyUriDecode(const char *zSrc, sxu32 nLen, ProcConsumer xConsumer, void *pUserData, int bUTF8)
2299{
2300 static const sxu8 Utf8Trans[] = {
2301 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
2302 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
2303 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
2304 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
2305 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
2306 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
2307 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
2308 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00
2309 };
2310 const char *zIn = zSrc;
2311 const char *zEnd;
2312 const char *zCur;
2313 sxu8 *zOutPtr;
2314 sxu8 zOut[10];
2315 sxi32 c, d;
2316 sxi32 rc;
2317#if defined(UNTRUST)
2318 if( SX_EMPTY_STR(zSrc) || xConsumer == 0 ){
2319 return SXERR_EMPTY;
2320 }
2321#endif
2322 rc = SXRET_OK;
2323 zEnd = &zSrc[nLen];
2324 zCur = zIn;
2325 for(;;){
2326 while(zCur < zEnd && zCur[0] != '%' && zCur[0] != '+' ){
2327 zCur++;
2328 }
2329 if( zCur != zIn ){
2330 /* Consume input */
2331 rc = xConsumer(zIn, (unsigned int)(zCur-zIn), pUserData);
2332 if( rc != SXRET_OK ){
2333 /* User consumer routine request an operation abort */
2334 break;
2335 }
2336 }
2337 if( zCur >= zEnd ){
2338 rc = SXRET_OK;
2339 break;
2340 }
2341 /* Decode unsafe HTTP characters */
2342 zOutPtr = zOut;
2343 if( zCur[0] == '+' ){
2344 *zOutPtr++ = ' ';
2345 zCur++;
2346 }else{
2347 if( &zCur[2] >= zEnd ){
2348 rc = SXERR_OVERFLOW;
2349 break;
2350 }
2351 c = (SyAsciiToHex(zCur[1]) <<4) | SyAsciiToHex(zCur[2]);
2352 zCur += 3;
2353 if( c < 0x000C0 ){
2354 *zOutPtr++ = (sxu8)c;
2355 }else{
2356 c = Utf8Trans[c-0xC0];
2357 while( zCur[0] == '%' ){
2358 d = (SyAsciiToHex(zCur[1]) <<4) | SyAsciiToHex(zCur[2]);
2359 if( (d&0xC0) != 0x80 ){
2360 break;
2361 }
2362 c = (c<<6) + (0x3f & d);
2363 zCur += 3;
2364 }
2365 if( bUTF8 == FALSE ){
2366 *zOutPtr++ = (sxu8)c;
2367 }else{
2368 SX_WRITE_UTF8(zOutPtr, c);
2369 }
2370 }
2371
2372 }
2373 /* Consume the decoded characters */
2374 rc = xConsumer((const void *)zOut, (unsigned int)(zOutPtr-zOut), pUserData);
2375 if( rc != SXRET_OK ){
2376 break;
2377 }
2378 /* Synchronize pointers */
2379 zIn = zCur;
2380 }
2381 return rc;
2382}
2383#ifndef JX9_DISABLE_BUILTIN_FUNC
2384static const char *zEngDay[] = {
2385 "Sunday", "Monday", "Tuesday", "Wednesday",
2386 "Thursday", "Friday", "Saturday"
2387};
2388static const char *zEngMonth[] = {
2389 "January", "February", "March", "April",
2390 "May", "June", "July", "August",
2391 "September", "October", "November", "December"
2392};
2393static const char * GetDay(sxi32 i)
2394{
2395 return zEngDay[ i % 7 ];
2396}
2397static const char * GetMonth(sxi32 i)
2398{
2399 return zEngMonth[ i % 12 ];
2400}
2401JX9_PRIVATE const char * SyTimeGetDay(sxi32 iDay)
2402{
2403 return GetDay(iDay);
2404}
2405JX9_PRIVATE const char * SyTimeGetMonth(sxi32 iMonth)
2406{
2407 return GetMonth(iMonth);
2408}
2409#endif /* JX9_DISABLE_BUILTIN_FUNC */
2410/* SyRunTimeApi: sxfmt.c */
2411#define SXFMT_BUFSIZ 1024 /* Conversion buffer size */
2412/*
2413** Conversion types fall into various categories as defined by the
2414** following enumeration.
2415*/
2416#define SXFMT_RADIX 1 /* Integer types.%d, %x, %o, and so forth */
2417#define SXFMT_FLOAT 2 /* Floating point.%f */
2418#define SXFMT_EXP 3 /* Exponentional notation.%e and %E */
2419#define SXFMT_GENERIC 4 /* Floating or exponential, depending on exponent.%g */
2420#define SXFMT_SIZE 5 /* Total number of characters processed so far.%n */
2421#define SXFMT_STRING 6 /* Strings.%s */
2422#define SXFMT_PERCENT 7 /* Percent symbol.%% */
2423#define SXFMT_CHARX 8 /* Characters.%c */
2424#define SXFMT_ERROR 9 /* Used to indicate no such conversion type */
2425/* Extension by Symisc Systems */
2426#define SXFMT_RAWSTR 13 /* %z Pointer to raw string (SyString *) */
2427#define SXFMT_UNUSED 15
2428/*
2429** Allowed values for SyFmtInfo.flags
2430*/
2431#define SXFLAG_SIGNED 0x01
2432#define SXFLAG_UNSIGNED 0x02
2433/* Allowed values for SyFmtConsumer.nType */
2434#define SXFMT_CONS_PROC 1 /* Consumer is a procedure */
2435#define SXFMT_CONS_STR 2 /* Consumer is a managed string */
2436#define SXFMT_CONS_FILE 5 /* Consumer is an open File */
2437#define SXFMT_CONS_BLOB 6 /* Consumer is a BLOB */
2438/*
2439** Each builtin conversion character (ex: the 'd' in "%d") is described
2440** by an instance of the following structure
2441*/
2442typedef struct SyFmtInfo SyFmtInfo;
2443struct SyFmtInfo
2444{
2445 char fmttype; /* The format field code letter [i.e: 'd', 's', 'x'] */
2446 sxu8 base; /* The base for radix conversion */
2447 int flags; /* One or more of SXFLAG_ constants below */
2448 sxu8 type; /* Conversion paradigm */
2449 char *charset; /* The character set for conversion */
2450 char *prefix; /* Prefix on non-zero values in alt format */
2451};
2452typedef struct SyFmtConsumer SyFmtConsumer;
2453struct SyFmtConsumer
2454{
2455 sxu32 nLen; /* Total output length */
2456 sxi32 nType; /* Type of the consumer see below */
2457 sxi32 rc; /* Consumer return value;Abort processing if rc != SXRET_OK */
2458 union{
2459 struct{
2460 ProcConsumer xUserConsumer;
2461 void *pUserData;
2462 }sFunc;
2463 SyBlob *pBlob;
2464 }uConsumer;
2465};
2466#ifndef SX_OMIT_FLOATINGPOINT
2467static int getdigit(sxlongreal *val, int *cnt)
2468{
2469 sxlongreal d;
2470 int digit;
2471
2472 if( (*cnt)++ >= 16 ){
2473 return '0';
2474 }
2475 digit = (int)*val;
2476 d = digit;
2477 *val = (*val - d)*10.0;
2478 return digit + '0' ;
2479}
2480#endif /* SX_OMIT_FLOATINGPOINT */
2481/*
2482 * The following routine was taken from the SQLITE2 source tree and was
2483 * extended by Symisc Systems to fit its need.
2484 * Status: Public Domain
2485 */
2486static sxi32 InternFormat(ProcConsumer xConsumer, void *pUserData, const char *zFormat, va_list ap)
2487{
2488 /*
2489 * The following table is searched linearly, so it is good to put the most frequently
2490 * used conversion types first.
2491 */
2492static const SyFmtInfo aFmt[] = {
2493 { 'd', 10, SXFLAG_SIGNED, SXFMT_RADIX, "0123456789", 0 },
2494 { 's', 0, 0, SXFMT_STRING, 0, 0 },
2495 { 'c', 0, 0, SXFMT_CHARX, 0, 0 },
2496 { 'x', 16, 0, SXFMT_RADIX, "0123456789abcdef", "x0" },
2497 { 'X', 16, 0, SXFMT_RADIX, "0123456789ABCDEF", "X0" },
2498 /* -- Extensions by Symisc Systems -- */
2499 { 'z', 0, 0, SXFMT_RAWSTR, 0, 0 }, /* Pointer to a raw string (SyString *) */
2500 { 'B', 2, 0, SXFMT_RADIX, "01", "b0"},
2501 /* -- End of Extensions -- */
2502 { 'o', 8, 0, SXFMT_RADIX, "01234567", "0" },
2503 { 'u', 10, 0, SXFMT_RADIX, "0123456789", 0 },
2504#ifndef SX_OMIT_FLOATINGPOINT
2505 { 'f', 0, SXFLAG_SIGNED, SXFMT_FLOAT, 0, 0 },
2506 { 'e', 0, SXFLAG_SIGNED, SXFMT_EXP, "e", 0 },
2507 { 'E', 0, SXFLAG_SIGNED, SXFMT_EXP, "E", 0 },
2508 { 'g', 0, SXFLAG_SIGNED, SXFMT_GENERIC, "e", 0 },
2509 { 'G', 0, SXFLAG_SIGNED, SXFMT_GENERIC, "E", 0 },
2510#endif
2511 { 'i', 10, SXFLAG_SIGNED, SXFMT_RADIX, "0123456789", 0 },
2512 { 'n', 0, 0, SXFMT_SIZE, 0, 0 },
2513 { '%', 0, 0, SXFMT_PERCENT, 0, 0 },
2514 { 'p', 10, 0, SXFMT_RADIX, "0123456789", 0 }
2515};
2516 int c; /* Next character in the format string */
2517 char *bufpt; /* Pointer to the conversion buffer */
2518 int precision; /* Precision of the current field */
2519 int length; /* Length of the field */
2520 int idx; /* A general purpose loop counter */
2521 int width; /* Width of the current field */
2522 sxu8 flag_leftjustify; /* True if "-" flag is present */
2523 sxu8 flag_plussign; /* True if "+" flag is present */
2524 sxu8 flag_blanksign; /* True if " " flag is present */
2525 sxu8 flag_alternateform; /* True if "#" flag is present */
2526 sxu8 flag_zeropad; /* True if field width constant starts with zero */
2527 sxu8 flag_long; /* True if "l" flag is present */
2528 sxi64 longvalue; /* Value for integer types */
2529 const SyFmtInfo *infop; /* Pointer to the appropriate info structure */
2530 char buf[SXFMT_BUFSIZ]; /* Conversion buffer */
2531 char prefix; /* Prefix character."+" or "-" or " " or '\0'.*/
2532 sxu8 errorflag = 0; /* True if an error is encountered */
2533 sxu8 xtype; /* Conversion paradigm */
2534 char *zExtra;
2535 static char spaces[] = " ";
2536#define etSPACESIZE ((int)sizeof(spaces)-1)
2537#ifndef SX_OMIT_FLOATINGPOINT
2538 sxlongreal realvalue; /* Value for real types */
2539 int exp; /* exponent of real numbers */
2540 double rounder; /* Used for rounding floating point values */
2541 sxu8 flag_dp; /* True if decimal point should be shown */
2542 sxu8 flag_rtz; /* True if trailing zeros should be removed */
2543 sxu8 flag_exp; /* True to force display of the exponent */
2544 int nsd; /* Number of significant digits returned */
2545#endif
2546 int rc;
2547
2548 length = 0;
2549 bufpt = 0;
2550 for(; (c=(*zFormat))!=0; ++zFormat){
2551 if( c!='%' ){
2552 unsigned int amt;
2553 bufpt = (char *)zFormat;
2554 amt = 1;
2555 while( (c=(*++zFormat))!='%' && c!=0 ) amt++;
2556 rc = xConsumer((const void *)bufpt, amt, pUserData);
2557 if( rc != SXRET_OK ){
2558 return SXERR_ABORT; /* Consumer routine request an operation abort */
2559 }
2560 if( c==0 ){
2561 return errorflag > 0 ? SXERR_FORMAT : SXRET_OK;
2562 }
2563 }
2564 if( (c=(*++zFormat))==0 ){
2565 errorflag = 1;
2566 rc = xConsumer("%", sizeof("%")-1, pUserData);
2567 if( rc != SXRET_OK ){
2568 return SXERR_ABORT; /* Consumer routine request an operation abort */
2569 }
2570 return errorflag > 0 ? SXERR_FORMAT : SXRET_OK;
2571 }
2572 /* Find out what flags are present */
2573 flag_leftjustify = flag_plussign = flag_blanksign =
2574 flag_alternateform = flag_zeropad = 0;
2575 do{
2576 switch( c ){
2577 case '-': flag_leftjustify = 1; c = 0; break;
2578 case '+': flag_plussign = 1; c = 0; break;
2579 case ' ': flag_blanksign = 1; c = 0; break;
2580 case '#': flag_alternateform = 1; c = 0; break;
2581 case '0': flag_zeropad = 1; c = 0; break;
2582 default: break;
2583 }
2584 }while( c==0 && (c=(*++zFormat))!=0 );
2585 /* Get the field width */
2586 width = 0;
2587 if( c=='*' ){
2588 width = va_arg(ap, int);
2589 if( width<0 ){
2590 flag_leftjustify = 1;
2591 width = -width;
2592 }
2593 c = *++zFormat;
2594 }else{
2595 while( c>='0' && c<='9' ){
2596 width = width*10 + c - '0';
2597 c = *++zFormat;
2598 }
2599 }
2600 if( width > SXFMT_BUFSIZ-10 ){
2601 width = SXFMT_BUFSIZ-10;
2602 }
2603 /* Get the precision */
2604 precision = -1;
2605 if( c=='.' ){
2606 precision = 0;
2607 c = *++zFormat;
2608 if( c=='*' ){
2609 precision = va_arg(ap, int);
2610 if( precision<0 ) precision = -precision;
2611 c = *++zFormat;
2612 }else{
2613 while( c>='0' && c<='9' ){
2614 precision = precision*10 + c - '0';
2615 c = *++zFormat;
2616 }
2617 }
2618 }
2619 /* Get the conversion type modifier */
2620 flag_long = 0;
2621 if( c=='l' || c == 'q' /* BSD quad (expect a 64-bit integer) */ ){
2622 flag_long = (c == 'q') ? 2 : 1;
2623 c = *++zFormat;
2624 if( c == 'l' ){
2625 /* Standard printf emulation 'lld' (expect a 64bit integer) */
2626 flag_long = 2;
2627 }
2628 }
2629 /* Fetch the info entry for the field */
2630 infop = 0;
2631 xtype = SXFMT_ERROR;
2632 for(idx=0; idx< (int)SX_ARRAYSIZE(aFmt); idx++){
2633 if( c==aFmt[idx].fmttype ){
2634 infop = &aFmt[idx];
2635 xtype = infop->type;
2636 break;
2637 }
2638 }
2639 zExtra = 0;
2640
2641 /*
2642 ** At this point, variables are initialized as follows:
2643 **
2644 ** flag_alternateform TRUE if a '#' is present.
2645 ** flag_plussign TRUE if a '+' is present.
2646 ** flag_leftjustify TRUE if a '-' is present or if the
2647 ** field width was negative.
2648 ** flag_zeropad TRUE if the width began with 0.
2649 ** flag_long TRUE if the letter 'l' (ell) or 'q'(BSD quad) prefixed
2650 ** the conversion character.
2651 ** flag_blanksign TRUE if a ' ' is present.
2652 ** width The specified field width.This is
2653 ** always non-negative.Zero is the default.
2654 ** precision The specified precision.The default
2655 ** is -1.
2656 ** xtype The object of the conversion.
2657 ** infop Pointer to the appropriate info struct.
2658 */
2659 switch( xtype ){
2660 case SXFMT_RADIX:
2661 if( flag_long > 0 ){
2662 if( flag_long > 1 ){
2663 /* BSD quad: expect a 64-bit integer */
2664 longvalue = va_arg(ap, sxi64);
2665 }else{
2666 longvalue = va_arg(ap, sxlong);
2667 }
2668 }else{
2669 if( infop->flags & SXFLAG_SIGNED ){
2670 longvalue = va_arg(ap, sxi32);
2671 }else{
2672 longvalue = va_arg(ap, sxu32);
2673 }
2674 }
2675 /* Limit the precision to prevent overflowing buf[] during conversion */
2676 if( precision>SXFMT_BUFSIZ-40 ) precision = SXFMT_BUFSIZ-40;
2677#if 1
2678 /* For the format %#x, the value zero is printed "0" not "0x0".
2679 ** I think this is stupid.*/
2680 if( longvalue==0 ) flag_alternateform = 0;
2681#else
2682 /* More sensible: turn off the prefix for octal (to prevent "00"),
2683 ** but leave the prefix for hex.*/
2684 if( longvalue==0 && infop->base==8 ) flag_alternateform = 0;
2685#endif
2686 if( infop->flags & SXFLAG_SIGNED ){
2687 if( longvalue<0 ){
2688 longvalue = -longvalue;
2689 /* Ticket 1433-003 */
2690 if( longvalue < 0 ){
2691 /* Overflow */
2692 longvalue= 0x7FFFFFFFFFFFFFFF;
2693 }
2694 prefix = '-';
2695 }else if( flag_plussign ) prefix = '+';
2696 else if( flag_blanksign ) prefix = ' ';
2697 else prefix = 0;
2698 }else{
2699 if( longvalue<0 ){
2700 longvalue = -longvalue;
2701 /* Ticket 1433-003 */
2702 if( longvalue < 0 ){
2703 /* Overflow */
2704 longvalue= 0x7FFFFFFFFFFFFFFF;
2705 }
2706 }
2707 prefix = 0;
2708 }
2709 if( flag_zeropad && precision<width-(prefix!=0) ){
2710 precision = width-(prefix!=0);
2711 }
2712 bufpt = &buf[SXFMT_BUFSIZ-1];
2713 {
2714 register char *cset; /* Use registers for speed */
2715 register int base;
2716 cset = infop->charset;
2717 base = infop->base;
2718 do{ /* Convert to ascii */
2719 *(--bufpt) = cset[longvalue%base];
2720 longvalue = longvalue/base;
2721 }while( longvalue>0 );
2722 }
2723 length = &buf[SXFMT_BUFSIZ-1]-bufpt;
2724 for(idx=precision-length; idx>0; idx--){
2725 *(--bufpt) = '0'; /* Zero pad */
2726 }
2727 if( prefix ) *(--bufpt) = prefix; /* Add sign */
2728 if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */
2729 char *pre, x;
2730 pre = infop->prefix;
2731 if( *bufpt!=pre[0] ){
2732 for(pre=infop->prefix; (x=(*pre))!=0; pre++) *(--bufpt) = x;
2733 }
2734 }
2735 length = &buf[SXFMT_BUFSIZ-1]-bufpt;
2736 break;
2737 case SXFMT_FLOAT:
2738 case SXFMT_EXP:
2739 case SXFMT_GENERIC:
2740#ifndef SX_OMIT_FLOATINGPOINT
2741 realvalue = va_arg(ap, double);
2742 if( precision<0 ) precision = 6; /* Set default precision */
2743 if( precision>SXFMT_BUFSIZ-40) precision = SXFMT_BUFSIZ-40;
2744 if( realvalue<0.0 ){
2745 realvalue = -realvalue;
2746 prefix = '-';
2747 }else{
2748 if( flag_plussign ) prefix = '+';
2749 else if( flag_blanksign ) prefix = ' ';
2750 else prefix = 0;
2751 }
2752 if( infop->type==SXFMT_GENERIC && precision>0 ) precision--;
2753 rounder = 0.0;
2754#if 0
2755 /* Rounding works like BSD when the constant 0.4999 is used.Wierd! */
2756 for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1);
2757#else
2758 /* It makes more sense to use 0.5 */
2759 for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1);
2760#endif
2761 if( infop->type==SXFMT_FLOAT ) realvalue += rounder;
2762 /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
2763 exp = 0;
2764 if( realvalue>0.0 ){
2765 while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; }
2766 while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; }
2767 while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; }
2768 while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; }
2769 if( exp>350 || exp<-350 ){
2770 bufpt = "NaN";
2771 length = 3;
2772 break;
2773 }
2774 }
2775 bufpt = buf;
2776 /*
2777 ** If the field type is etGENERIC, then convert to either etEXP
2778 ** or etFLOAT, as appropriate.
2779 */
2780 flag_exp = xtype==SXFMT_EXP;
2781 if( xtype!=SXFMT_FLOAT ){
2782 realvalue += rounder;
2783 if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }
2784 }
2785 if( xtype==SXFMT_GENERIC ){
2786 flag_rtz = !flag_alternateform;
2787 if( exp<-4 || exp>precision ){
2788 xtype = SXFMT_EXP;
2789 }else{
2790 precision = precision - exp;
2791 xtype = SXFMT_FLOAT;
2792 }
2793 }else{
2794 flag_rtz = 0;
2795 }
2796 /*
2797 ** The "exp+precision" test causes output to be of type etEXP if
2798 ** the precision is too large to fit in buf[].
2799 */
2800 nsd = 0;
2801 if( xtype==SXFMT_FLOAT && exp+precision<SXFMT_BUFSIZ-30 ){
2802 flag_dp = (precision>0 || flag_alternateform);
2803 if( prefix ) *(bufpt++) = prefix; /* Sign */
2804 if( exp<0 ) *(bufpt++) = '0'; /* Digits before "." */
2805 else for(; exp>=0; exp--) *(bufpt++) = (char)getdigit(&realvalue, &nsd);
2806 if( flag_dp ) *(bufpt++) = '.'; /* The decimal point */
2807 for(exp++; exp<0 && precision>0; precision--, exp++){
2808 *(bufpt++) = '0';
2809 }
2810 while( (precision--)>0 ) *(bufpt++) = (char)getdigit(&realvalue, &nsd);
2811 *(bufpt--) = 0; /* Null terminate */
2812 if( flag_rtz && flag_dp ){ /* Remove trailing zeros and "." */
2813 while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;
2814 if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;
2815 }
2816 bufpt++; /* point to next free slot */
2817 }else{ /* etEXP or etGENERIC */
2818 flag_dp = (precision>0 || flag_alternateform);
2819 if( prefix ) *(bufpt++) = prefix; /* Sign */
2820 *(bufpt++) = (char)getdigit(&realvalue, &nsd); /* First digit */
2821 if( flag_dp ) *(bufpt++) = '.'; /* Decimal point */
2822 while( (precision--)>0 ) *(bufpt++) = (char)getdigit(&realvalue, &nsd);
2823 bufpt--; /* point to last digit */
2824 if( flag_rtz && flag_dp ){ /* Remove tail zeros */
2825 while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;
2826 if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;
2827 }
2828 bufpt++; /* point to next free slot */
2829 if( exp || flag_exp ){
2830 *(bufpt++) = infop->charset[0];
2831 if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; } /* sign of exp */
2832 else { *(bufpt++) = '+'; }
2833 if( exp>=100 ){
2834 *(bufpt++) = (char)((exp/100)+'0'); /* 100's digit */
2835 exp %= 100;
2836 }
2837 *(bufpt++) = (char)(exp/10+'0'); /* 10's digit */
2838 *(bufpt++) = (char)(exp%10+'0'); /* 1's digit */
2839 }
2840 }
2841 /* The converted number is in buf[] and zero terminated.Output it.
2842 ** Note that the number is in the usual order, not reversed as with
2843 ** integer conversions.*/
2844 length = bufpt-buf;
2845 bufpt = buf;
2846
2847 /* Special case: Add leading zeros if the flag_zeropad flag is
2848 ** set and we are not left justified */
2849 if( flag_zeropad && !flag_leftjustify && length < width){
2850 int i;
2851 int nPad = width - length;
2852 for(i=width; i>=nPad; i--){
2853 bufpt[i] = bufpt[i-nPad];
2854 }
2855 i = prefix!=0;
2856 while( nPad-- ) bufpt[i++] = '0';
2857 length = width;
2858 }
2859#else
2860 bufpt = " ";
2861 length = (int)sizeof(" ") - 1;
2862#endif /* SX_OMIT_FLOATINGPOINT */
2863 break;
2864 case SXFMT_SIZE:{
2865 int *pSize = va_arg(ap, int *);
2866 *pSize = ((SyFmtConsumer *)pUserData)->nLen;
2867 length = width = 0;
2868 }
2869 break;
2870 case SXFMT_PERCENT:
2871 buf[0] = '%';
2872 bufpt = buf;
2873 length = 1;
2874 break;
2875 case SXFMT_CHARX:
2876 c = va_arg(ap, int);
2877 buf[0] = (char)c;
2878 /* Limit the precision to prevent overflowing buf[] during conversion */
2879 if( precision>SXFMT_BUFSIZ-40 ) precision = SXFMT_BUFSIZ-40;
2880 if( precision>=0 ){
2881 for(idx=1; idx<precision; idx++) buf[idx] = (char)c;
2882 length = precision;
2883 }else{
2884 length =1;
2885 }
2886 bufpt = buf;
2887 break;
2888 case SXFMT_STRING:
2889 bufpt = va_arg(ap, char*);
2890 if( bufpt==0 ){
2891 bufpt = " ";
2892 length = (int)sizeof(" ")-1;
2893 break;
2894 }
2895 length = precision;
2896 if( precision < 0 ){
2897 /* Symisc extension */
2898 length = (int)SyStrlen(bufpt);
2899 }
2900 if( precision>=0 && precision<length ) length = precision;
2901 break;
2902 case SXFMT_RAWSTR:{
2903 /* Symisc extension */
2904 SyString *pStr = va_arg(ap, SyString *);
2905 if( pStr == 0 || pStr->zString == 0 ){
2906 bufpt = " ";
2907 length = (int)sizeof(char);
2908 break;
2909 }
2910 bufpt = (char *)pStr->zString;
2911 length = (int)pStr->nByte;
2912 break;
2913 }
2914 case SXFMT_ERROR:
2915 buf[0] = '?';
2916 bufpt = buf;
2917 length = (int)sizeof(char);
2918 if( c==0 ) zFormat--;
2919 break;
2920 }/* End switch over the format type */
2921 /*
2922 ** The text of the conversion is pointed to by "bufpt" and is
2923 ** "length" characters long.The field width is "width".Do
2924 ** the output.
2925 */
2926 if( !flag_leftjustify ){
2927 register int nspace;
2928 nspace = width-length;
2929 if( nspace>0 ){
2930 while( nspace>=etSPACESIZE ){
2931 rc = xConsumer(spaces, etSPACESIZE, pUserData);
2932 if( rc != SXRET_OK ){
2933 return SXERR_ABORT; /* Consumer routine request an operation abort */
2934 }
2935 nspace -= etSPACESIZE;
2936 }
2937 if( nspace>0 ){
2938 rc = xConsumer(spaces, (unsigned int)nspace, pUserData);
2939 if( rc != SXRET_OK ){
2940 return SXERR_ABORT; /* Consumer routine request an operation abort */
2941 }
2942 }
2943 }
2944 }
2945 if( length>0 ){
2946 rc = xConsumer(bufpt, (unsigned int)length, pUserData);
2947 if( rc != SXRET_OK ){
2948 return SXERR_ABORT; /* Consumer routine request an operation abort */
2949 }
2950 }
2951 if( flag_leftjustify ){
2952 register int nspace;
2953 nspace = width-length;
2954 if( nspace>0 ){
2955 while( nspace>=etSPACESIZE ){
2956 rc = xConsumer(spaces, etSPACESIZE, pUserData);
2957 if( rc != SXRET_OK ){
2958 return SXERR_ABORT; /* Consumer routine request an operation abort */
2959 }
2960 nspace -= etSPACESIZE;
2961 }
2962 if( nspace>0 ){
2963 rc = xConsumer(spaces, (unsigned int)nspace, pUserData);
2964 if( rc != SXRET_OK ){
2965 return SXERR_ABORT; /* Consumer routine request an operation abort */
2966 }
2967 }
2968 }
2969 }
2970 }/* End for loop over the format string */
2971 return errorflag ? SXERR_FORMAT : SXRET_OK;
2972}
2973static sxi32 FormatConsumer(const void *pSrc, unsigned int nLen, void *pData)
2974{
2975 SyFmtConsumer *pConsumer = (SyFmtConsumer *)pData;
2976 sxi32 rc = SXERR_ABORT;
2977 switch(pConsumer->nType){
2978 case SXFMT_CONS_PROC:
2979 /* User callback */
2980 rc = pConsumer->uConsumer.sFunc.xUserConsumer(pSrc, nLen, pConsumer->uConsumer.sFunc.pUserData);
2981 break;
2982 case SXFMT_CONS_BLOB:
2983 /* Blob consumer */
2984 rc = SyBlobAppend(pConsumer->uConsumer.pBlob, pSrc, (sxu32)nLen);
2985 break;
2986 default:
2987 /* Unknown consumer */
2988 break;
2989 }
2990 /* Update total number of bytes consumed so far */
2991 pConsumer->nLen += nLen;
2992 pConsumer->rc = rc;
2993 return rc;
2994}
2995static sxi32 FormatMount(sxi32 nType, void *pConsumer, ProcConsumer xUserCons, void *pUserData, sxu32 *pOutLen, const char *zFormat, va_list ap)
2996{
2997 SyFmtConsumer sCons;
2998 sCons.nType = nType;
2999 sCons.rc = SXRET_OK;
3000 sCons.nLen = 0;
3001 if( pOutLen ){
3002 *pOutLen = 0;
3003 }
3004 switch(nType){
3005 case SXFMT_CONS_PROC:
3006#if defined(UNTRUST)
3007 if( xUserCons == 0 ){
3008 return SXERR_EMPTY;
3009 }
3010#endif
3011 sCons.uConsumer.sFunc.xUserConsumer = xUserCons;
3012 sCons.uConsumer.sFunc.pUserData = pUserData;
3013 break;
3014 case SXFMT_CONS_BLOB:
3015 sCons.uConsumer.pBlob = (SyBlob *)pConsumer;
3016 break;
3017 default:
3018 return SXERR_UNKNOWN;
3019 }
3020 InternFormat(FormatConsumer, &sCons, zFormat, ap);
3021 if( pOutLen ){
3022 *pOutLen = sCons.nLen;
3023 }
3024 return sCons.rc;
3025}
3026JX9_PRIVATE sxi32 SyProcFormat(ProcConsumer xConsumer, void *pData, const char *zFormat, ...)
3027{
3028 va_list ap;
3029 sxi32 rc;
3030#if defined(UNTRUST)
3031 if( SX_EMPTY_STR(zFormat) ){
3032 return SXERR_EMPTY;
3033 }
3034#endif
3035 va_start(ap, zFormat);
3036 rc = FormatMount(SXFMT_CONS_PROC, 0, xConsumer, pData, 0, zFormat, ap);
3037 va_end(ap);
3038 return rc;
3039}
3040JX9_PRIVATE sxu32 SyBlobFormat(SyBlob *pBlob, const char *zFormat, ...)
3041{
3042 va_list ap;
3043 sxu32 n;
3044#if defined(UNTRUST)
3045 if( SX_EMPTY_STR(zFormat) ){
3046 return 0;
3047 }
3048#endif
3049 va_start(ap, zFormat);
3050 FormatMount(SXFMT_CONS_BLOB, &(*pBlob), 0, 0, &n, zFormat, ap);
3051 va_end(ap);
3052 return n;
3053}
3054JX9_PRIVATE sxu32 SyBlobFormatAp(SyBlob *pBlob, const char *zFormat, va_list ap)
3055{
3056 sxu32 n = 0; /* cc warning */
3057#if defined(UNTRUST)
3058 if( SX_EMPTY_STR(zFormat) ){
3059 return 0;
3060 }
3061#endif
3062 FormatMount(SXFMT_CONS_BLOB, &(*pBlob), 0, 0, &n, zFormat, ap);
3063 return n;
3064}
3065JX9_PRIVATE sxu32 SyBufferFormat(char *zBuf, sxu32 nLen, const char *zFormat, ...)
3066{
3067 SyBlob sBlob;
3068 va_list ap;
3069 sxu32 n;
3070#if defined(UNTRUST)
3071 if( SX_EMPTY_STR(zFormat) ){
3072 return 0;
3073 }
3074#endif
3075 if( SXRET_OK != SyBlobInitFromBuf(&sBlob, zBuf, nLen - 1) ){
3076 return 0;
3077 }
3078 va_start(ap, zFormat);
3079 FormatMount(SXFMT_CONS_BLOB, &sBlob, 0, 0, 0, zFormat, ap);
3080 va_end(ap);
3081 n = SyBlobLength(&sBlob);
3082 /* Append the null terminator */
3083 sBlob.mByte++;
3084 SyBlobAppend(&sBlob, "\0", sizeof(char));
3085 return n;
3086}
3087#ifndef JX9_DISABLE_BUILTIN_FUNC
3088/*
3089 * Zip File Format:
3090 *
3091 * Byte order: Little-endian
3092 *
3093 * [Local file header + Compressed data [+ Extended local header]?]*
3094 * [Central directory]*
3095 * [End of central directory record]
3096 *
3097 * Local file header:*
3098 * Offset Length Contents
3099 * 0 4 bytes Local file header signature (0x04034b50)
3100 * 4 2 bytes Version needed to extract
3101 * 6 2 bytes General purpose bit flag
3102 * 8 2 bytes Compression method
3103 * 10 2 bytes Last mod file time
3104 * 12 2 bytes Last mod file date
3105 * 14 4 bytes CRC-32
3106 * 18 4 bytes Compressed size (n)
3107 * 22 4 bytes Uncompressed size
3108 * 26 2 bytes Filename length (f)
3109 * 28 2 bytes Extra field length (e)
3110 * 30 (f)bytes Filename
3111 * (e)bytes Extra field
3112 * (n)bytes Compressed data
3113 *
3114 * Extended local header:*
3115 * Offset Length Contents
3116 * 0 4 bytes Extended Local file header signature (0x08074b50)
3117 * 4 4 bytes CRC-32
3118 * 8 4 bytes Compressed size
3119 * 12 4 bytes Uncompressed size
3120 *
3121 * Extra field:?(if any)
3122 * Offset Length Contents
3123 * 0 2 bytes Header ID (0x001 until 0xfb4a) see extended appnote from Info-zip
3124 * 2 2 bytes Data size (g)
3125 * (g) bytes (g) bytes of extra field
3126 *
3127 * Central directory:*
3128 * Offset Length Contents
3129 * 0 4 bytes Central file header signature (0x02014b50)
3130 * 4 2 bytes Version made by
3131 * 6 2 bytes Version needed to extract
3132 * 8 2 bytes General purpose bit flag
3133 * 10 2 bytes Compression method
3134 * 12 2 bytes Last mod file time
3135 * 14 2 bytes Last mod file date
3136 * 16 4 bytes CRC-32
3137 * 20 4 bytes Compressed size
3138 * 24 4 bytes Uncompressed size
3139 * 28 2 bytes Filename length (f)
3140 * 30 2 bytes Extra field length (e)
3141 * 32 2 bytes File comment length (c)
3142 * 34 2 bytes Disk number start
3143 * 36 2 bytes Internal file attributes
3144 * 38 4 bytes External file attributes
3145 * 42 4 bytes Relative offset of local header
3146 * 46 (f)bytes Filename
3147 * (e)bytes Extra field
3148 * (c)bytes File comment
3149 *
3150 * End of central directory record:
3151 * Offset Length Contents
3152 * 0 4 bytes End of central dir signature (0x06054b50)
3153 * 4 2 bytes Number of this disk
3154 * 6 2 bytes Number of the disk with the start of the central directory
3155 * 8 2 bytes Total number of entries in the central dir on this disk
3156 * 10 2 bytes Total number of entries in the central dir
3157 * 12 4 bytes Size of the central directory
3158 * 16 4 bytes Offset of start of central directory with respect to the starting disk number
3159 * 20 2 bytes zipfile comment length (c)
3160 * 22 (c)bytes zipfile comment
3161 *
3162 * compression method: (2 bytes)
3163 * 0 - The file is stored (no compression)
3164 * 1 - The file is Shrunk
3165 * 2 - The file is Reduced with compression factor 1
3166 * 3 - The file is Reduced with compression factor 2
3167 * 4 - The file is Reduced with compression factor 3
3168 * 5 - The file is Reduced with compression factor 4
3169 * 6 - The file is Imploded
3170 * 7 - Reserved for Tokenizing compression algorithm
3171 * 8 - The file is Deflated
3172 */
3173
3174#define SXMAKE_ZIP_WORKBUF (SXU16_HIGH/2) /* 32KB Initial working buffer size */
3175#define SXMAKE_ZIP_EXTRACT_VER 0x000a /* Version needed to extract */
3176#define SXMAKE_ZIP_VER 0x003 /* Version made by */
3177
3178#define SXZIP_CENTRAL_MAGIC 0x02014b50
3179#define SXZIP_END_CENTRAL_MAGIC 0x06054b50
3180#define SXZIP_LOCAL_MAGIC 0x04034b50
3181/*#define SXZIP_CRC32_START 0xdebb20e3*/
3182
3183#define SXZIP_LOCAL_HDRSZ 30 /* Local header size */
3184#define SXZIP_LOCAL_EXT_HDRZ 16 /* Extended local header(footer) size */
3185#define SXZIP_CENTRAL_HDRSZ 46 /* Central directory header size */
3186#define SXZIP_END_CENTRAL_HDRSZ 22 /* End of central directory header size */
3187
3188#define SXARCHIVE_HASH_SIZE 64 /* Starting hash table size(MUST BE POWER OF 2)*/
3189static sxi32 SyLittleEndianUnpack32(sxu32 *uNB, const unsigned char *buf, sxu32 Len)
3190{
3191 if( Len < sizeof(sxu32) ){
3192 return SXERR_SHORT;
3193 }
3194 *uNB = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24);
3195 return SXRET_OK;
3196}
3197static sxi32 SyLittleEndianUnpack16(sxu16 *pOut, const unsigned char *zBuf, sxu32 nLen)
3198{
3199 if( nLen < sizeof(sxu16) ){
3200 return SXERR_SHORT;
3201 }
3202 *pOut = zBuf[0] + (zBuf[1] <<8);
3203
3204 return SXRET_OK;
3205}
3206/*
3207 * Archive hashtable manager
3208 */
3209static sxi32 ArchiveHashGetEntry(SyArchive *pArch, const char *zName, sxu32 nLen, SyArchiveEntry **ppEntry)
3210{
3211 SyArchiveEntry *pBucketEntry;
3212 SyString sEntry;
3213 sxu32 nHash;
3214
3215 nHash = pArch->xHash(zName, nLen);
3216 pBucketEntry = pArch->apHash[nHash & (pArch->nSize - 1)];
3217
3218 SyStringInitFromBuf(&sEntry, zName, nLen);
3219
3220 for(;;){
3221 if( pBucketEntry == 0 ){
3222 break;
3223 }
3224 if( nHash == pBucketEntry->nHash && pArch->xCmp(&sEntry, &pBucketEntry->sFileName) == 0 ){
3225 if( ppEntry ){
3226 *ppEntry = pBucketEntry;
3227 }
3228 return SXRET_OK;
3229 }
3230 pBucketEntry = pBucketEntry->pNextHash;
3231 }
3232 return SXERR_NOTFOUND;
3233}
3234static void ArchiveHashBucketInstall(SyArchiveEntry **apTable, sxu32 nBucket, SyArchiveEntry *pEntry)
3235{
3236 pEntry->pNextHash = apTable[nBucket];
3237 if( apTable[nBucket] != 0 ){
3238 apTable[nBucket]->pPrevHash = pEntry;
3239 }
3240 apTable[nBucket] = pEntry;
3241}
3242static sxi32 ArchiveHashGrowTable(SyArchive *pArch)
3243{
3244 sxu32 nNewSize = pArch->nSize * 2;
3245 SyArchiveEntry **apNew;
3246 SyArchiveEntry *pEntry;
3247 sxu32 n;
3248
3249 /* Allocate a new table */
3250 apNew = (SyArchiveEntry **)SyMemBackendAlloc(pArch->pAllocator, nNewSize * sizeof(SyArchiveEntry *));
3251 if( apNew == 0 ){
3252 return SXRET_OK; /* Not so fatal, simply a performance hit */
3253 }
3254 SyZero(apNew, nNewSize * sizeof(SyArchiveEntry *));
3255 /* Rehash old entries */
3256 for( n = 0 , pEntry = pArch->pList ; n < pArch->nLoaded ; n++ , pEntry = pEntry->pNext ){
3257 pEntry->pNextHash = pEntry->pPrevHash = 0;
3258 ArchiveHashBucketInstall(apNew, pEntry->nHash & (nNewSize - 1), pEntry);
3259 }
3260 /* Release the old table */
3261 SyMemBackendFree(pArch->pAllocator, pArch->apHash);
3262 pArch->apHash = apNew;
3263 pArch->nSize = nNewSize;
3264
3265 return SXRET_OK;
3266}
3267static sxi32 ArchiveHashInstallEntry(SyArchive *pArch, SyArchiveEntry *pEntry)
3268{
3269 if( pArch->nLoaded > pArch->nSize * 3 ){
3270 ArchiveHashGrowTable(&(*pArch));
3271 }
3272 pEntry->nHash = pArch->xHash(SyStringData(&pEntry->sFileName), SyStringLength(&pEntry->sFileName));
3273 /* Install the entry in its bucket */
3274 ArchiveHashBucketInstall(pArch->apHash, pEntry->nHash & (pArch->nSize - 1), pEntry);
3275 MACRO_LD_PUSH(pArch->pList, pEntry);
3276 pArch->nLoaded++;
3277
3278 return SXRET_OK;
3279}
3280 /*
3281 * Parse the End of central directory and report status
3282 */
3283 static sxi32 ParseEndOfCentralDirectory(SyArchive *pArch, const unsigned char *zBuf)
3284 {
3285 sxu32 nMagic = 0; /* cc -O6 warning */
3286 sxi32 rc;
3287
3288 /* Sanity check */
3289 rc = SyLittleEndianUnpack32(&nMagic, zBuf, sizeof(sxu32));
3290 if( /* rc != SXRET_OK || */nMagic != SXZIP_END_CENTRAL_MAGIC ){
3291 return SXERR_CORRUPT;
3292 }
3293 /* # of entries */
3294 rc = SyLittleEndianUnpack16((sxu16 *)&pArch->nEntry, &zBuf[8], sizeof(sxu16));
3295 if( /* rc != SXRET_OK || */ pArch->nEntry > SXI16_HIGH /* SXU16_HIGH */ ){
3296 return SXERR_CORRUPT;
3297 }
3298 /* Size of central directory */
3299 rc = SyLittleEndianUnpack32(&pArch->nCentralSize, &zBuf[12], sizeof(sxu32));
3300 if( /*rc != SXRET_OK ||*/ pArch->nCentralSize > SXI32_HIGH ){
3301 return SXERR_CORRUPT;
3302 }
3303 /* Starting offset of central directory */
3304 rc = SyLittleEndianUnpack32(&pArch->nCentralOfft, &zBuf[16], sizeof(sxu32));
3305 if( /*rc != SXRET_OK ||*/ pArch->nCentralSize > SXI32_HIGH ){
3306 return SXERR_CORRUPT;
3307 }
3308
3309 return SXRET_OK;
3310 }
3311 /*
3312 * Fill the zip entry with the appropriate information from the central directory
3313 */
3314static sxi32 GetCentralDirectoryEntry(SyArchive *pArch, SyArchiveEntry *pEntry, const unsigned char *zCentral, sxu32 *pNextOffset)
3315 {
3316 SyString *pName = &pEntry->sFileName; /* File name */
3317 sxu16 nDosDate, nDosTime;
3318 sxu16 nComment = 0 ;
3319 sxu32 nMagic = 0; /* cc -O6 warning */
3320 sxi32 rc;
3321 nDosDate = nDosTime = 0; /* cc -O6 warning */
3322 SXUNUSED(pArch);
3323 /* Sanity check */
3324 rc = SyLittleEndianUnpack32(&nMagic, zCentral, sizeof(sxu32));
3325 if( /* rc != SXRET_OK || */ nMagic != SXZIP_CENTRAL_MAGIC ){
3326 rc = SXERR_CORRUPT;
3327 /*
3328 * Try to recover by examing the next central directory record.
3329 * Dont worry here, there is no risk of an infinite loop since
3330 * the buffer size is delimited.
3331 */
3332
3333 /* pName->nByte = 0; nComment = 0; pName->nExtra = 0 */
3334 goto update;
3335 }
3336 /*
3337 * entry name length
3338 */
3339 SyLittleEndianUnpack16((sxu16 *)&pName->nByte, &zCentral[28], sizeof(sxu16));
3340 if( pName->nByte > SXI16_HIGH /* SXU16_HIGH */){
3341 rc = SXERR_BIG;
3342 goto update;
3343 }
3344 /* Extra information */
3345 SyLittleEndianUnpack16(&pEntry->nExtra, &zCentral[30], sizeof(sxu16));
3346 /* Comment length */
3347 SyLittleEndianUnpack16(&nComment, &zCentral[32], sizeof(sxu16));
3348 /* Compression method 0 == stored / 8 == deflated */
3349 rc = SyLittleEndianUnpack16(&pEntry->nComprMeth, &zCentral[10], sizeof(sxu16));
3350 /* DOS Timestamp */
3351 SyLittleEndianUnpack16(&nDosTime, &zCentral[12], sizeof(sxu16));
3352 SyLittleEndianUnpack16(&nDosDate, &zCentral[14], sizeof(sxu16));
3353 SyDosTimeFormat((nDosDate << 16 | nDosTime), &pEntry->sFmt);
3354 /* Little hack to fix month index */
3355 pEntry->sFmt.tm_mon--;
3356 /* CRC32 */
3357 rc = SyLittleEndianUnpack32(&pEntry->nCrc, &zCentral[16], sizeof(sxu32));
3358 /* Content size before compression */
3359 rc = SyLittleEndianUnpack32(&pEntry->nByte, &zCentral[24], sizeof(sxu32));
3360 if( pEntry->nByte > SXI32_HIGH ){
3361 rc = SXERR_BIG;
3362 goto update;
3363 }
3364 /*
3365 * Content size after compression.
3366 * Note that if the file is stored pEntry->nByte should be equal to pEntry->nByteCompr
3367 */
3368 rc = SyLittleEndianUnpack32(&pEntry->nByteCompr, &zCentral[20], sizeof(sxu32));
3369 if( pEntry->nByteCompr > SXI32_HIGH ){
3370 rc = SXERR_BIG;
3371 goto update;
3372 }
3373 /* Finally grab the contents offset */
3374 SyLittleEndianUnpack32(&pEntry->nOfft, &zCentral[42], sizeof(sxu32));
3375 if( pEntry->nOfft > SXI32_HIGH ){
3376 rc = SXERR_BIG;
3377 goto update;
3378 }
3379 rc = SXRET_OK;
3380update:
3381 /* Update the offset to point to the next central directory record */
3382 *pNextOffset = SXZIP_CENTRAL_HDRSZ + pName->nByte + pEntry->nExtra + nComment;
3383 return rc; /* Report failure or success */
3384}
3385static sxi32 ZipFixOffset(SyArchiveEntry *pEntry, void *pSrc)
3386{
3387 sxu16 nExtra, nNameLen;
3388 unsigned char *zHdr;
3389 nExtra = nNameLen = 0;
3390 zHdr = (unsigned char *)pSrc;
3391 zHdr = &zHdr[pEntry->nOfft];
3392 if( SyMemcmp(zHdr, "PK\003\004", sizeof(sxu32)) != 0 ){
3393 return SXERR_CORRUPT;
3394 }
3395 SyLittleEndianUnpack16(&nNameLen, &zHdr[26], sizeof(sxu16));
3396 SyLittleEndianUnpack16(&nExtra, &zHdr[28], sizeof(sxu16));
3397 /* Fix contents offset */
3398 pEntry->nOfft += SXZIP_LOCAL_HDRSZ + nExtra + nNameLen;
3399 return SXRET_OK;
3400}
3401/*
3402 * Extract all valid entries from the central directory
3403 */
3404static sxi32 ZipExtract(SyArchive *pArch, const unsigned char *zCentral, sxu32 nLen, void *pSrc)
3405{
3406 SyArchiveEntry *pEntry, *pDup;
3407 const unsigned char *zEnd ; /* End of central directory */
3408 sxu32 nIncr, nOfft; /* Central Offset */
3409 SyString *pName; /* Entry name */
3410 char *zName;
3411 sxi32 rc;
3412
3413 nOfft = nIncr = 0;
3414 zEnd = &zCentral[nLen];
3415
3416 for(;;){
3417 if( &zCentral[nOfft] >= zEnd ){
3418 break;
3419 }
3420 /* Add a new entry */
3421 pEntry = (SyArchiveEntry *)SyMemBackendPoolAlloc(pArch->pAllocator, sizeof(SyArchiveEntry));
3422 if( pEntry == 0 ){
3423 break;
3424 }
3425 SyZero(pEntry, sizeof(SyArchiveEntry));
3426 pEntry->nMagic = SXARCH_MAGIC;
3427 nIncr = 0;
3428 rc = GetCentralDirectoryEntry(&(*pArch), pEntry, &zCentral[nOfft], &nIncr);
3429 if( rc == SXRET_OK ){
3430 /* Fix the starting record offset so we can access entry contents correctly */
3431 rc = ZipFixOffset(pEntry, pSrc);
3432 }
3433 if(rc != SXRET_OK ){
3434 sxu32 nJmp = 0;
3435 SyMemBackendPoolFree(pArch->pAllocator, pEntry);
3436 /* Try to recover by brute-forcing for a valid central directory record */
3437 if( SXRET_OK == SyBlobSearch((const void *)&zCentral[nOfft + nIncr], (sxu32)(zEnd - &zCentral[nOfft + nIncr]),
3438 (const void *)"PK\001\002", sizeof(sxu32), &nJmp)){
3439 nOfft += nIncr + nJmp; /* Check next entry */
3440 continue;
3441 }
3442 break; /* Giving up, archive is hopelessly corrupted */
3443 }
3444 pName = &pEntry->sFileName;
3445 pName->zString = (const char *)&zCentral[nOfft + SXZIP_CENTRAL_HDRSZ];
3446 if( pName->nByte <= 0 || ( pEntry->nByte <= 0 && pName->zString[pName->nByte - 1] != '/') ){
3447 /* Ignore zero length records (except folders) and records without names */
3448 SyMemBackendPoolFree(pArch->pAllocator, pEntry);
3449 nOfft += nIncr; /* Check next entry */
3450 continue;
3451 }
3452 zName = SyMemBackendStrDup(pArch->pAllocator, pName->zString, pName->nByte);
3453 if( zName == 0 ){
3454 SyMemBackendPoolFree(pArch->pAllocator, pEntry);
3455 nOfft += nIncr; /* Check next entry */
3456 continue;
3457 }
3458 pName->zString = (const char *)zName;
3459 /* Check for duplicates */
3460 rc = ArchiveHashGetEntry(&(*pArch), pName->zString, pName->nByte, &pDup);
3461 if( rc == SXRET_OK ){
3462 /* Another entry with the same name exists ; link them together */
3463 pEntry->pNextName = pDup->pNextName;
3464 pDup->pNextName = pEntry;
3465 pDup->nDup++;
3466 }else{
3467 /* Insert in hashtable */
3468 ArchiveHashInstallEntry(pArch, pEntry);
3469 }
3470 nOfft += nIncr; /* Check next record */
3471 }
3472 pArch->pCursor = pArch->pList;
3473
3474 return pArch->nLoaded > 0 ? SXRET_OK : SXERR_EMPTY;
3475}
3476JX9_PRIVATE sxi32 SyZipExtractFromBuf(SyArchive *pArch, const char *zBuf, sxu32 nLen)
3477 {
3478 const unsigned char *zCentral, *zEnd;
3479 sxi32 rc;
3480#if defined(UNTRUST)
3481 if( SXARCH_INVALID(pArch) || zBuf == 0 ){
3482 return SXERR_INVALID;
3483 }
3484#endif
3485 /* The miminal size of a zip archive:
3486 * LOCAL_HDR_SZ + CENTRAL_HDR_SZ + END_OF_CENTRAL_HDR_SZ
3487 * 30 46 22
3488 */
3489 if( nLen < SXZIP_LOCAL_HDRSZ + SXZIP_CENTRAL_HDRSZ + SXZIP_END_CENTRAL_HDRSZ ){
3490 return SXERR_CORRUPT; /* Don't bother processing return immediately */
3491 }
3492
3493 zEnd = (unsigned char *)&zBuf[nLen - SXZIP_END_CENTRAL_HDRSZ];
3494 /* Find the end of central directory */
3495 while( ((sxu32)((unsigned char *)&zBuf[nLen] - zEnd) < (SXZIP_END_CENTRAL_HDRSZ + SXI16_HIGH)) &&
3496 zEnd > (unsigned char *)zBuf && SyMemcmp(zEnd, "PK\005\006", sizeof(sxu32)) != 0 ){
3497 zEnd--;
3498 }
3499 /* Parse the end of central directory */
3500 rc = ParseEndOfCentralDirectory(&(*pArch), zEnd);
3501 if( rc != SXRET_OK ){
3502 return rc;
3503 }
3504
3505 /* Find the starting offset of the central directory */
3506 zCentral = &zEnd[-(sxi32)pArch->nCentralSize];
3507 if( zCentral <= (unsigned char *)zBuf || SyMemcmp(zCentral, "PK\001\002", sizeof(sxu32)) != 0 ){
3508 if( pArch->nCentralOfft >= nLen ){
3509 /* Corrupted central directory offset */
3510 return SXERR_CORRUPT;
3511 }
3512 zCentral = (unsigned char *)&zBuf[pArch->nCentralOfft];
3513 if( SyMemcmp(zCentral, "PK\001\002", sizeof(sxu32)) != 0 ){
3514 /* Corrupted zip archive */
3515 return SXERR_CORRUPT;
3516 }
3517 /* Fall thru and extract all valid entries from the central directory */
3518 }
3519 rc = ZipExtract(&(*pArch), zCentral, (sxu32)(zEnd - zCentral), (void *)zBuf);
3520 return rc;
3521 }
3522/*
3523 * Default comparison function.
3524 */
3525 static sxi32 ArchiveHashCmp(const SyString *pStr1, const SyString *pStr2)
3526 {
3527 sxi32 rc;
3528 rc = SyStringCmp(pStr1, pStr2, SyMemcmp);
3529 return rc;
3530 }
3531JX9_PRIVATE sxi32 SyArchiveInit(SyArchive *pArch, SyMemBackend *pAllocator, ProcHash xHash, ProcRawStrCmp xCmp)
3532 {
3533 SyArchiveEntry **apHash;
3534#if defined(UNTRUST)
3535 if( pArch == 0 ){
3536 return SXERR_EMPTY;
3537 }
3538#endif
3539 SyZero(pArch, sizeof(SyArchive));
3540 /* Allocate a new hashtable */
3541 apHash = (SyArchiveEntry **)SyMemBackendAlloc(&(*pAllocator), SXARCHIVE_HASH_SIZE * sizeof(SyArchiveEntry *));
3542 if( apHash == 0){
3543 return SXERR_MEM;
3544 }
3545 SyZero(apHash, SXARCHIVE_HASH_SIZE * sizeof(SyArchiveEntry *));
3546 pArch->apHash = apHash;
3547 pArch->xHash = xHash ? xHash : SyBinHash;
3548 pArch->xCmp = xCmp ? xCmp : ArchiveHashCmp;
3549 pArch->nSize = SXARCHIVE_HASH_SIZE;
3550 pArch->pAllocator = &(*pAllocator);
3551 pArch->nMagic = SXARCH_MAGIC;
3552 return SXRET_OK;
3553 }
3554 static sxi32 ArchiveReleaseEntry(SyMemBackend *pAllocator, SyArchiveEntry *pEntry)
3555 {
3556 SyArchiveEntry *pDup = pEntry->pNextName;
3557 SyArchiveEntry *pNextDup;
3558
3559 /* Release duplicates first since there are not stored in the hashtable */
3560 for(;;){
3561 if( pEntry->nDup == 0 ){
3562 break;
3563 }
3564 pNextDup = pDup->pNextName;
3565 pDup->nMagic = 0x2661;
3566 SyMemBackendFree(pAllocator, (void *)SyStringData(&pDup->sFileName));
3567 SyMemBackendPoolFree(pAllocator, pDup);
3568 pDup = pNextDup;
3569 pEntry->nDup--;
3570 }
3571 pEntry->nMagic = 0x2661;
3572 SyMemBackendFree(pAllocator, (void *)SyStringData(&pEntry->sFileName));
3573 SyMemBackendPoolFree(pAllocator, pEntry);
3574 return SXRET_OK;
3575 }
3576JX9_PRIVATE sxi32 SyArchiveRelease(SyArchive *pArch)
3577 {
3578 SyArchiveEntry *pEntry, *pNext;
3579 pEntry = pArch->pList;
3580 for(;;){
3581 if( pArch->nLoaded < 1 ){
3582 break;
3583 }
3584 pNext = pEntry->pNext;
3585 MACRO_LD_REMOVE(pArch->pList, pEntry);
3586 ArchiveReleaseEntry(pArch->pAllocator, pEntry);
3587 pEntry = pNext;
3588 pArch->nLoaded--;
3589 }
3590 SyMemBackendFree(pArch->pAllocator, pArch->apHash);
3591 pArch->pCursor = 0;
3592 pArch->nMagic = 0x2626;
3593 return SXRET_OK;
3594 }
3595 JX9_PRIVATE sxi32 SyArchiveResetLoopCursor(SyArchive *pArch)
3596 {
3597 pArch->pCursor = pArch->pList;
3598 return SXRET_OK;
3599 }
3600 JX9_PRIVATE sxi32 SyArchiveGetNextEntry(SyArchive *pArch, SyArchiveEntry **ppEntry)
3601 {
3602 SyArchiveEntry *pNext;
3603 if( pArch->pCursor == 0 ){
3604 /* Rewind the cursor */
3605 pArch->pCursor = pArch->pList;
3606 return SXERR_EOF;
3607 }
3608 *ppEntry = pArch->pCursor;
3609 pNext = pArch->pCursor->pNext;
3610 /* Advance the cursor to the next entry */
3611 pArch->pCursor = pNext;
3612 return SXRET_OK;
3613 }
3614#endif /* JX9_DISABLE_BUILTIN_FUNC */
3615/*
3616 * Psuedo Random Number Generator (PRNG)
3617 * @authors: SQLite authors <http://www.sqlite.org/>
3618 * @status: Public Domain
3619 * NOTE:
3620 * Nothing in this file or anywhere else in the library does any kind of
3621 * encryption.The RC4 algorithm is being used as a PRNG (pseudo-random
3622 * number generator) not as an encryption device.
3623 */
3624#define SXPRNG_MAGIC 0x13C4
3625#ifdef __UNIXES__
3626#include <sys/types.h>
3627#include <sys/stat.h>
3628#include <fcntl.h>
3629#include <unistd.h>
3630#include <errno.h>
3631#include <time.h>
3632#include <sys/time.h>
3633#endif
3634static sxi32 SyOSUtilRandomSeed(void *pBuf, sxu32 nLen, void *pUnused)
3635{
3636 char *zBuf = (char *)pBuf;
3637#ifdef __WINNT__
3638 DWORD nProcessID; /* Yes, keep it uninitialized when compiling using the MinGW32 builds tools */
3639#elif defined(__UNIXES__)
3640 pid_t pid;
3641 int fd;
3642#else
3643 char zGarbage[128]; /* Yes, keep this buffer uninitialized */
3644#endif
3645 SXUNUSED(pUnused);
3646#ifdef __WINNT__
3647#ifndef __MINGW32__
3648 nProcessID = GetProcessId(GetCurrentProcess());
3649#endif
3650 SyMemcpy((const void *)&nProcessID, zBuf, SXMIN(nLen, sizeof(DWORD)));
3651 if( (sxu32)(&zBuf[nLen] - &zBuf[sizeof(DWORD)]) >= sizeof(SYSTEMTIME) ){
3652 GetSystemTime((LPSYSTEMTIME)&zBuf[sizeof(DWORD)]);
3653 }
3654#elif defined(__UNIXES__)
3655 fd = open("/dev/urandom", O_RDONLY);
3656 if (fd >= 0 ){
3657 if( read(fd, zBuf, nLen) > 0 ){
3658 return SXRET_OK;
3659 }
3660 /* FALL THRU */
3661 }
3662 pid = getpid();
3663 SyMemcpy((const void *)&pid, zBuf, SXMIN(nLen, sizeof(pid_t)));
3664 if( &zBuf[nLen] - &zBuf[sizeof(pid_t)] >= (int)sizeof(struct timeval) ){
3665 gettimeofday((struct timeval *)&zBuf[sizeof(pid_t)], 0);
3666 }
3667#else
3668 /* Fill with uninitialized data */
3669 SyMemcpy(zGarbage, zBuf, SXMIN(nLen, sizeof(zGarbage)));
3670#endif
3671 return SXRET_OK;
3672}
3673JX9_PRIVATE sxi32 SyRandomnessInit(SyPRNGCtx *pCtx, ProcRandomSeed xSeed, void * pUserData)
3674{
3675 char zSeed[256];
3676 sxu8 t;
3677 sxi32 rc;
3678 sxu32 i;
3679 if( pCtx->nMagic == SXPRNG_MAGIC ){
3680 return SXRET_OK; /* Already initialized */
3681 }
3682 /* Initialize the state of the random number generator once,
3683 ** the first time this routine is called.The seed value does
3684 ** not need to contain a lot of randomness since we are not
3685 ** trying to do secure encryption or anything like that...
3686 */
3687 if( xSeed == 0 ){
3688 xSeed = SyOSUtilRandomSeed;
3689 }
3690 rc = xSeed(zSeed, sizeof(zSeed), pUserData);
3691 if( rc != SXRET_OK ){
3692 return rc;
3693 }
3694 pCtx->i = pCtx->j = 0;
3695 for(i=0; i < SX_ARRAYSIZE(pCtx->s) ; i++){
3696 pCtx->s[i] = (unsigned char)i;
3697 }
3698 for(i=0; i < sizeof(zSeed) ; i++){
3699 pCtx->j += pCtx->s[i] + zSeed[i];
3700 t = pCtx->s[pCtx->j];
3701 pCtx->s[pCtx->j] = pCtx->s[i];
3702 pCtx->s[i] = t;
3703 }
3704 pCtx->nMagic = SXPRNG_MAGIC;
3705
3706 return SXRET_OK;
3707}
3708/*
3709 * Get a single 8-bit random value using the RC4 PRNG.
3710 */
3711static sxu8 randomByte(SyPRNGCtx *pCtx)
3712{
3713 sxu8 t;
3714
3715 /* Generate and return single random byte */
3716 pCtx->i++;
3717 t = pCtx->s[pCtx->i];
3718 pCtx->j += t;
3719 pCtx->s[pCtx->i] = pCtx->s[pCtx->j];
3720 pCtx->s[pCtx->j] = t;
3721 t += pCtx->s[pCtx->i];
3722 return pCtx->s[t];
3723}
3724JX9_PRIVATE sxi32 SyRandomness(SyPRNGCtx *pCtx, void *pBuf, sxu32 nLen)
3725{
3726 unsigned char *zBuf = (unsigned char *)pBuf;
3727 unsigned char *zEnd = &zBuf[nLen];
3728#if defined(UNTRUST)
3729 if( pCtx == 0 || pBuf == 0 || nLen <= 0 ){
3730 return SXERR_EMPTY;
3731 }
3732#endif
3733 if(pCtx->nMagic != SXPRNG_MAGIC ){
3734 return SXERR_CORRUPT;
3735 }
3736 for(;;){
3737 if( zBuf >= zEnd ){break;} zBuf[0] = randomByte(pCtx); zBuf++;
3738 if( zBuf >= zEnd ){break;} zBuf[0] = randomByte(pCtx); zBuf++;
3739 if( zBuf >= zEnd ){break;} zBuf[0] = randomByte(pCtx); zBuf++;
3740 if( zBuf >= zEnd ){break;} zBuf[0] = randomByte(pCtx); zBuf++;
3741 }
3742 return SXRET_OK;
3743}
3744#ifndef JX9_DISABLE_BUILTIN_FUNC
3745#ifndef JX9_DISABLE_HASH_FUNC
3746/* SyRunTimeApi: sxhash.c */
3747/*
3748 * This code implements the MD5 message-digest algorithm.
3749 * The algorithm is due to Ron Rivest.This code was
3750 * written by Colin Plumb in 1993, no copyright is claimed.
3751 * This code is in the public domain; do with it what you wish.
3752 *
3753 * Equivalent code is available from RSA Data Security, Inc.
3754 * This code has been tested against that, and is equivalent,
3755 * except that you don't need to include two pages of legalese
3756 * with every copy.
3757 *
3758 * To compute the message digest of a chunk of bytes, declare an
3759 * MD5Context structure, pass it to MD5Init, call MD5Update as
3760 * needed on buffers full of bytes, and then call MD5Final, which
3761 * will fill a supplied 16-byte array with the digest.
3762 */
3763#define SX_MD5_BINSZ 16
3764#define SX_MD5_HEXSZ 32
3765/*
3766 * Note: this code is harmless on little-endian machines.
3767 */
3768static void byteReverse (unsigned char *buf, unsigned longs)
3769{
3770 sxu32 t;
3771 do {
3772 t = (sxu32)((unsigned)buf[3]<<8 | buf[2]) << 16 |
3773 ((unsigned)buf[1]<<8 | buf[0]);
3774 *(sxu32*)buf = t;
3775 buf += 4;
3776 } while (--longs);
3777}
3778/* The four core functions - F1 is optimized somewhat */
3779
3780/* #define F1(x, y, z) (x & y | ~x & z) */
3781#ifdef F1
3782#undef F1
3783#endif
3784#ifdef F2
3785#undef F2
3786#endif
3787#ifdef F3
3788#undef F3
3789#endif
3790#ifdef F4
3791#undef F4
3792#endif
3793
3794#define F1(x, y, z) (z ^ (x & (y ^ z)))
3795#define F2(x, y, z) F1(z, x, y)
3796#define F3(x, y, z) (x ^ y ^ z)
3797#define F4(x, y, z) (y ^ (x | ~z))
3798
3799/* This is the central step in the MD5 algorithm.*/
3800#define SX_MD5STEP(f, w, x, y, z, data, s) \
3801 ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
3802
3803/*
3804 * The core of the MD5 algorithm, this alters an existing MD5 hash to
3805 * reflect the addition of 16 longwords of new data.MD5Update blocks
3806 * the data and converts bytes into longwords for this routine.
3807 */
3808static void MD5Transform(sxu32 buf[4], const sxu32 in[16])
3809{
3810 register sxu32 a, b, c, d;
3811
3812 a = buf[0];
3813 b = buf[1];
3814 c = buf[2];
3815 d = buf[3];
3816
3817 SX_MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
3818 SX_MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
3819 SX_MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
3820 SX_MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
3821 SX_MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
3822 SX_MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
3823 SX_MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
3824 SX_MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
3825 SX_MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
3826 SX_MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
3827 SX_MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
3828 SX_MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
3829 SX_MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
3830 SX_MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
3831 SX_MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
3832 SX_MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
3833
3834 SX_MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
3835 SX_MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
3836 SX_MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
3837 SX_MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
3838 SX_MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
3839 SX_MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
3840 SX_MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
3841 SX_MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
3842 SX_MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
3843 SX_MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
3844 SX_MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
3845 SX_MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
3846 SX_MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
3847 SX_MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
3848 SX_MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
3849 SX_MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
3850
3851 SX_MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
3852 SX_MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
3853 SX_MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
3854 SX_MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
3855 SX_MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
3856 SX_MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
3857 SX_MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
3858 SX_MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
3859 SX_MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
3860 SX_MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
3861 SX_MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
3862 SX_MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
3863 SX_MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
3864 SX_MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
3865 SX_MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
3866 SX_MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
3867
3868 SX_MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
3869 SX_MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
3870 SX_MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
3871 SX_MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
3872 SX_MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
3873 SX_MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
3874 SX_MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
3875 SX_MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
3876 SX_MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
3877 SX_MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
3878 SX_MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
3879 SX_MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
3880 SX_MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
3881 SX_MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
3882 SX_MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
3883 SX_MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
3884
3885 buf[0] += a;
3886 buf[1] += b;
3887 buf[2] += c;
3888 buf[3] += d;
3889}
3890/*
3891 * Update context to reflect the concatenation of another buffer full
3892 * of bytes.
3893 */
3894JX9_PRIVATE void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len)
3895{
3896 sxu32 t;
3897
3898 /* Update bitcount */
3899 t = ctx->bits[0];
3900 if ((ctx->bits[0] = t + ((sxu32)len << 3)) < t)
3901 ctx->bits[1]++; /* Carry from low to high */
3902 ctx->bits[1] += len >> 29;
3903 t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
3904 /* Handle any leading odd-sized chunks */
3905 if ( t ) {
3906 unsigned char *p = (unsigned char *)ctx->in + t;
3907
3908 t = 64-t;
3909 if (len < t) {
3910 SyMemcpy(buf, p, len);
3911 return;
3912 }
3913 SyMemcpy(buf, p, t);
3914 byteReverse(ctx->in, 16);
3915 MD5Transform(ctx->buf, (sxu32*)ctx->in);
3916 buf += t;
3917 len -= t;
3918 }
3919 /* Process data in 64-byte chunks */
3920 while (len >= 64) {
3921 SyMemcpy(buf, ctx->in, 64);
3922 byteReverse(ctx->in, 16);
3923 MD5Transform(ctx->buf, (sxu32*)ctx->in);
3924 buf += 64;
3925 len -= 64;
3926 }
3927 /* Handle any remaining bytes of data.*/
3928 SyMemcpy(buf, ctx->in, len);
3929}
3930/*
3931 * Final wrapup - pad to 64-byte boundary with the bit pattern
3932 * 1 0* (64-bit count of bits processed, MSB-first)
3933 */
3934JX9_PRIVATE void MD5Final(unsigned char digest[16], MD5Context *ctx){
3935 unsigned count;
3936 unsigned char *p;
3937
3938 /* Compute number of bytes mod 64 */
3939 count = (ctx->bits[0] >> 3) & 0x3F;
3940
3941 /* Set the first char of padding to 0x80.This is safe since there is
3942 always at least one byte free */
3943 p = ctx->in + count;
3944 *p++ = 0x80;
3945
3946 /* Bytes of padding needed to make 64 bytes */
3947 count = 64 - 1 - count;
3948
3949 /* Pad out to 56 mod 64 */
3950 if (count < 8) {
3951 /* Two lots of padding: Pad the first block to 64 bytes */
3952 SyZero(p, count);
3953 byteReverse(ctx->in, 16);
3954 MD5Transform(ctx->buf, (sxu32*)ctx->in);
3955
3956 /* Now fill the next block with 56 bytes */
3957 SyZero(ctx->in, 56);
3958 } else {
3959 /* Pad block to 56 bytes */
3960 SyZero(p, count-8);
3961 }
3962 byteReverse(ctx->in, 14);
3963
3964 /* Append length in bits and transform */
3965 ((sxu32*)ctx->in)[ 14 ] = ctx->bits[0];
3966 ((sxu32*)ctx->in)[ 15 ] = ctx->bits[1];
3967
3968 MD5Transform(ctx->buf, (sxu32*)ctx->in);
3969 byteReverse((unsigned char *)ctx->buf, 4);
3970 SyMemcpy(ctx->buf, digest, 0x10);
3971 SyZero(ctx, sizeof(ctx)); /* In case it's sensitive */
3972}
3973#undef F1
3974#undef F2
3975#undef F3
3976#undef F4
3977JX9_PRIVATE sxi32 MD5Init(MD5Context *pCtx)
3978{
3979 pCtx->buf[0] = 0x67452301;
3980 pCtx->buf[1] = 0xefcdab89;
3981 pCtx->buf[2] = 0x98badcfe;
3982 pCtx->buf[3] = 0x10325476;
3983 pCtx->bits[0] = 0;
3984 pCtx->bits[1] = 0;
3985
3986 return SXRET_OK;
3987}
3988JX9_PRIVATE sxi32 SyMD5Compute(const void *pIn, sxu32 nLen, unsigned char zDigest[16])
3989{
3990 MD5Context sCtx;
3991 MD5Init(&sCtx);
3992 MD5Update(&sCtx, (const unsigned char *)pIn, nLen);
3993 MD5Final(zDigest, &sCtx);
3994 return SXRET_OK;
3995}
3996/*
3997 * SHA-1 in C
3998 * By Steve Reid <steve@edmweb.com>
3999 * Status: Public Domain
4000 */
4001/*
4002 * blk0() and blk() perform the initial expand.
4003 * I got the idea of expanding during the round function from SSLeay
4004 *
4005 * blk0le() for little-endian and blk0be() for big-endian.
4006 */
4007#if __GNUC__ && (defined(__i386__) || defined(__x86_64__))
4008/*
4009 * GCC by itself only generates left rotates. Use right rotates if
4010 * possible to be kinder to dinky implementations with iterative rotate
4011 * instructions.
4012 */
4013#define SHA_ROT(op, x, k) \
4014 ({ unsigned int y; asm(op " %1, %0" : "=r" (y) : "I" (k), "0" (x)); y; })
4015#define rol(x, k) SHA_ROT("roll", x, k)
4016#define ror(x, k) SHA_ROT("rorl", x, k)
4017
4018#else
4019/* Generic C equivalent */
4020#define SHA_ROT(x, l, r) ((x) << (l) | (x) >> (r))
4021#define rol(x, k) SHA_ROT(x, k, 32-(k))
4022#define ror(x, k) SHA_ROT(x, 32-(k), k)
4023#endif
4024
4025#define blk0le(i) (block[i] = (ror(block[i], 8)&0xFF00FF00) \
4026 |(rol(block[i], 8)&0x00FF00FF))
4027#define blk0be(i) block[i]
4028#define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \
4029 ^block[(i+2)&15]^block[i&15], 1))
4030
4031/*
4032 * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
4033 *
4034 * Rl0() for little-endian and Rb0() for big-endian. Endianness is
4035 * determined at run-time.
4036 */
4037#define Rl0(v, w, x, y, z, i) \
4038 z+=((w&(x^y))^y)+blk0le(i)+0x5A827999+rol(v, 5);w=ror(w, 2);
4039#define Rb0(v, w, x, y, z, i) \
4040 z+=((w&(x^y))^y)+blk0be(i)+0x5A827999+rol(v, 5);w=ror(w, 2);
4041#define R1(v, w, x, y, z, i) \
4042 z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v, 5);w=ror(w, 2);
4043#define R2(v, w, x, y, z, i) \
4044 z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v, 5);w=ror(w, 2);
4045#define R3(v, w, x, y, z, i) \
4046 z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v, 5);w=ror(w, 2);
4047#define R4(v, w, x, y, z, i) \
4048 z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v, 5);w=ror(w, 2);
4049
4050/*
4051 * Hash a single 512-bit block. This is the core of the algorithm.
4052 */
4053#define a qq[0]
4054#define b qq[1]
4055#define c qq[2]
4056#define d qq[3]
4057#define e qq[4]
4058
4059static void SHA1Transform(unsigned int state[5], const unsigned char buffer[64])
4060{
4061 unsigned int qq[5]; /* a, b, c, d, e; */
4062 static int one = 1;
4063 unsigned int block[16];
4064 SyMemcpy(buffer, (void *)block, 64);
4065 SyMemcpy(state, qq, 5*sizeof(unsigned int));
4066
4067 /* Copy context->state[] to working vars */
4068 /*
4069 a = state[0];
4070 b = state[1];
4071 c = state[2];
4072 d = state[3];
4073 e = state[4];
4074 */
4075
4076 /* 4 rounds of 20 operations each. Loop unrolled. */
4077 if( 1 == *(unsigned char*)&one ){
4078 Rl0(a, b, c, d, e, 0); Rl0(e, a, b, c, d, 1); Rl0(d, e, a, b, c, 2); Rl0(c, d, e, a, b, 3);
4079 Rl0(b, c, d, e, a, 4); Rl0(a, b, c, d, e, 5); Rl0(e, a, b, c, d, 6); Rl0(d, e, a, b, c, 7);
4080 Rl0(c, d, e, a, b, 8); Rl0(b, c, d, e, a, 9); Rl0(a, b, c, d, e, 10); Rl0(e, a, b, c, d, 11);
4081 Rl0(d, e, a, b, c, 12); Rl0(c, d, e, a, b, 13); Rl0(b, c, d, e, a, 14); Rl0(a, b, c, d, e, 15);
4082 }else{
4083 Rb0(a, b, c, d, e, 0); Rb0(e, a, b, c, d, 1); Rb0(d, e, a, b, c, 2); Rb0(c, d, e, a, b, 3);
4084 Rb0(b, c, d, e, a, 4); Rb0(a, b, c, d, e, 5); Rb0(e, a, b, c, d, 6); Rb0(d, e, a, b, c, 7);
4085 Rb0(c, d, e, a, b, 8); Rb0(b, c, d, e, a, 9); Rb0(a, b, c, d, e, 10); Rb0(e, a, b, c, d, 11);
4086 Rb0(d, e, a, b, c, 12); Rb0(c, d, e, a, b, 13); Rb0(b, c, d, e, a, 14); Rb0(a, b, c, d, e, 15);
4087 }
4088 R1(e, a, b, c, d, 16); R1(d, e, a, b, c, 17); R1(c, d, e, a, b, 18); R1(b, c, d, e, a, 19);
4089 R2(a, b, c, d, e, 20); R2(e, a, b, c, d, 21); R2(d, e, a, b, c, 22); R2(c, d, e, a, b, 23);
4090 R2(b, c, d, e, a, 24); R2(a, b, c, d, e, 25); R2(e, a, b, c, d, 26); R2(d, e, a, b, c, 27);
4091 R2(c, d, e, a, b, 28); R2(b, c, d, e, a, 29); R2(a, b, c, d, e, 30); R2(e, a, b, c, d, 31);
4092 R2(d, e, a, b, c, 32); R2(c, d, e, a, b, 33); R2(b, c, d, e, a, 34); R2(a, b, c, d, e, 35);
4093 R2(e, a, b, c, d, 36); R2(d, e, a, b, c, 37); R2(c, d, e, a, b, 38); R2(b, c, d, e, a, 39);
4094 R3(a, b, c, d, e, 40); R3(e, a, b, c, d, 41); R3(d, e, a, b, c, 42); R3(c, d, e, a, b, 43);
4095 R3(b, c, d, e, a, 44); R3(a, b, c, d, e, 45); R3(e, a, b, c, d, 46); R3(d, e, a, b, c, 47);
4096 R3(c, d, e, a, b, 48); R3(b, c, d, e, a, 49); R3(a, b, c, d, e, 50); R3(e, a, b, c, d, 51);
4097 R3(d, e, a, b, c, 52); R3(c, d, e, a, b, 53); R3(b, c, d, e, a, 54); R3(a, b, c, d, e, 55);
4098 R3(e, a, b, c, d, 56); R3(d, e, a, b, c, 57); R3(c, d, e, a, b, 58); R3(b, c, d, e, a, 59);
4099 R4(a, b, c, d, e, 60); R4(e, a, b, c, d, 61); R4(d, e, a, b, c, 62); R4(c, d, e, a, b, 63);
4100 R4(b, c, d, e, a, 64); R4(a, b, c, d, e, 65); R4(e, a, b, c, d, 66); R4(d, e, a, b, c, 67);
4101 R4(c, d, e, a, b, 68); R4(b, c, d, e, a, 69); R4(a, b, c, d, e, 70); R4(e, a, b, c, d, 71);
4102 R4(d, e, a, b, c, 72); R4(c, d, e, a, b, 73); R4(b, c, d, e, a, 74); R4(a, b, c, d, e, 75);
4103 R4(e, a, b, c, d, 76); R4(d, e, a, b, c, 77); R4(c, d, e, a, b, 78); R4(b, c, d, e, a, 79);
4104
4105 /* Add the working vars back into context.state[] */
4106 state[0] += a;
4107 state[1] += b;
4108 state[2] += c;
4109 state[3] += d;
4110 state[4] += e;
4111}
4112#undef a
4113#undef b
4114#undef c
4115#undef d
4116#undef e
4117/*
4118 * SHA1Init - Initialize new context
4119 */
4120JX9_PRIVATE void SHA1Init(SHA1Context *context){
4121 /* SHA1 initialization constants */
4122 context->state[0] = 0x67452301;
4123 context->state[1] = 0xEFCDAB89;
4124 context->state[2] = 0x98BADCFE;
4125 context->state[3] = 0x10325476;
4126 context->state[4] = 0xC3D2E1F0;
4127 context->count[0] = context->count[1] = 0;
4128}
4129/*
4130 * Run your data through this.
4131 */
4132JX9_PRIVATE void SHA1Update(SHA1Context *context, const unsigned char *data, unsigned int len){
4133 unsigned int i, j;
4134
4135 j = context->count[0];
4136 if ((context->count[0] += len << 3) < j)
4137 context->count[1] += (len>>29)+1;
4138 j = (j >> 3) & 63;
4139 if ((j + len) > 63) {
4140 (void)SyMemcpy(data, &context->buffer[j], (i = 64-j));
4141 SHA1Transform(context->state, context->buffer);
4142 for ( ; i + 63 < len; i += 64)
4143 SHA1Transform(context->state, &data[i]);
4144 j = 0;
4145 } else {
4146 i = 0;
4147 }
4148 (void)SyMemcpy(&data[i], &context->buffer[j], len - i);
4149}
4150/*
4151 * Add padding and return the message digest.
4152 */
4153JX9_PRIVATE void SHA1Final(SHA1Context *context, unsigned char digest[20]){
4154 unsigned int i;
4155 unsigned char finalcount[8];
4156
4157 for (i = 0; i < 8; i++) {
4158 finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
4159 >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
4160 }
4161 SHA1Update(context, (const unsigned char *)"\200", 1);
4162 while ((context->count[0] & 504) != 448)
4163 SHA1Update(context, (const unsigned char *)"\0", 1);
4164 SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
4165
4166 if (digest) {
4167 for (i = 0; i < 20; i++)
4168 digest[i] = (unsigned char)
4169 ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
4170 }
4171}
4172#undef Rl0
4173#undef Rb0
4174#undef R1
4175#undef R2
4176#undef R3
4177#undef R4
4178
4179JX9_PRIVATE sxi32 SySha1Compute(const void *pIn, sxu32 nLen, unsigned char zDigest[20])
4180{
4181 SHA1Context sCtx;
4182 SHA1Init(&sCtx);
4183 SHA1Update(&sCtx, (const unsigned char *)pIn, nLen);
4184 SHA1Final(&sCtx, zDigest);
4185 return SXRET_OK;
4186}
4187static const sxu32 crc32_table[] = {
4188 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
4189 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
4190 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
4191 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
4192 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
4193 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
4194 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
4195 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
4196 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
4197 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
4198 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
4199 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
4200 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
4201 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
4202 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
4203 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
4204 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
4205 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
4206 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
4207 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
4208 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
4209 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
4210 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
4211 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
4212 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
4213 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
4214 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
4215 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
4216 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
4217 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
4218 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
4219 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
4220 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
4221 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
4222 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
4223 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
4224 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
4225 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
4226 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
4227 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
4228 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
4229 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
4230 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
4231 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
4232 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
4233 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
4234 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
4235 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
4236 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
4237 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
4238 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
4239 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
4240 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
4241 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
4242 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
4243 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
4244 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
4245 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
4246 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
4247 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
4248 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
4249 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
4250 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
4251 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
4252};
4253#define CRC32C(c, d) (c = ( crc32_table[(c ^ (d)) & 0xFF] ^ (c>>8) ) )
4254static sxu32 SyCrc32Update(sxu32 crc32, const void *pSrc, sxu32 nLen)
4255{
4256 register unsigned char *zIn = (unsigned char *)pSrc;
4257 unsigned char *zEnd;
4258 if( zIn == 0 ){
4259 return crc32;
4260 }
4261 zEnd = &zIn[nLen];
4262 for(;;){
4263 if(zIn >= zEnd ){ break; } CRC32C(crc32, zIn[0]); zIn++;
4264 if(zIn >= zEnd ){ break; } CRC32C(crc32, zIn[0]); zIn++;
4265 if(zIn >= zEnd ){ break; } CRC32C(crc32, zIn[0]); zIn++;
4266 if(zIn >= zEnd ){ break; } CRC32C(crc32, zIn[0]); zIn++;
4267 }
4268
4269 return crc32;
4270}
4271JX9_PRIVATE sxu32 SyCrc32(const void *pSrc, sxu32 nLen)
4272{
4273 return SyCrc32Update(SXU32_HIGH, pSrc, nLen);
4274}
4275#endif /* JX9_DISABLE_HASH_FUNC */
4276#endif /* JX9_DISABLE_BUILTIN_FUNC */
4277#ifndef JX9_DISABLE_BUILTIN_FUNC
4278JX9_PRIVATE sxi32 SyBinToHexConsumer(const void *pIn, sxu32 nLen, ProcConsumer xConsumer, void *pConsumerData)
4279{
4280 static const unsigned char zHexTab[] = "0123456789abcdef";
4281 const unsigned char *zIn, *zEnd;
4282 unsigned char zOut[3];
4283 sxi32 rc;
4284#if defined(UNTRUST)
4285 if( pIn == 0 || xConsumer == 0 ){
4286 return SXERR_EMPTY;
4287 }
4288#endif
4289 zIn = (const unsigned char *)pIn;
4290 zEnd = &zIn[nLen];
4291 for(;;){
4292 if( zIn >= zEnd ){
4293 break;
4294 }
4295 zOut[0] = zHexTab[zIn[0] >> 4]; zOut[1] = zHexTab[zIn[0] & 0x0F];
4296 rc = xConsumer((const void *)zOut, sizeof(char)*2, pConsumerData);
4297 if( rc != SXRET_OK ){
4298 return rc;
4299 }
4300 zIn++;
4301 }
4302 return SXRET_OK;
4303}
4304#endif /* JX9_DISABLE_BUILTIN_FUNC */
4305JX9_PRIVATE void SyBigEndianPack32(unsigned char *buf,sxu32 nb)
4306{
4307 buf[3] = nb & 0xFF ; nb >>=8;
4308 buf[2] = nb & 0xFF ; nb >>=8;
4309 buf[1] = nb & 0xFF ; nb >>=8;
4310 buf[0] = (unsigned char)nb ;
4311}
4312JX9_PRIVATE void SyBigEndianUnpack32(const unsigned char *buf,sxu32 *uNB)
4313{
4314 *uNB = buf[3] + (buf[2] << 8) + (buf[1] << 16) + (buf[0] << 24);
4315}
4316JX9_PRIVATE void SyBigEndianPack16(unsigned char *buf,sxu16 nb)
4317{
4318 buf[1] = nb & 0xFF ; nb >>=8;
4319 buf[0] = (unsigned char)nb ;
4320}
4321JX9_PRIVATE void SyBigEndianUnpack16(const unsigned char *buf,sxu16 *uNB)
4322{
4323 *uNB = buf[1] + (buf[0] << 8);
4324}
4325JX9_PRIVATE void SyBigEndianPack64(unsigned char *buf,sxu64 n64)
4326{
4327 buf[7] = n64 & 0xFF; n64 >>=8;
4328 buf[6] = n64 & 0xFF; n64 >>=8;
4329 buf[5] = n64 & 0xFF; n64 >>=8;
4330 buf[4] = n64 & 0xFF; n64 >>=8;
4331 buf[3] = n64 & 0xFF; n64 >>=8;
4332 buf[2] = n64 & 0xFF; n64 >>=8;
4333 buf[1] = n64 & 0xFF; n64 >>=8;
4334 buf[0] = (sxu8)n64 ;
4335}
4336JX9_PRIVATE void SyBigEndianUnpack64(const unsigned char *buf,sxu64 *n64)
4337{
4338 sxu32 u1,u2;
4339 u1 = buf[7] + (buf[6] << 8) + (buf[5] << 16) + (buf[4] << 24);
4340 u2 = buf[3] + (buf[2] << 8) + (buf[1] << 16) + (buf[0] << 24);
4341 *n64 = (((sxu64)u2) << 32) | u1;
4342}
4343JX9_PRIVATE sxi32 SyBlobAppendBig64(SyBlob *pBlob,sxu64 n64)
4344{
4345 unsigned char zBuf[8];
4346 sxi32 rc;
4347 SyBigEndianPack64(zBuf,n64);
4348 rc = SyBlobAppend(pBlob,(const void *)zBuf,sizeof(zBuf));
4349 return rc;
4350}
4351JX9_PRIVATE sxi32 SyBlobAppendBig32(SyBlob *pBlob,sxu32 n32)
4352{
4353 unsigned char zBuf[4];
4354 sxi32 rc;
4355 SyBigEndianPack32(zBuf,n32);
4356 rc = SyBlobAppend(pBlob,(const void *)zBuf,sizeof(zBuf));
4357 return rc;
4358}
4359JX9_PRIVATE sxi32 SyBlobAppendBig16(SyBlob *pBlob,sxu16 n16)
4360{
4361 unsigned char zBuf[2];
4362 sxi32 rc;
4363 SyBigEndianPack16(zBuf,n16);
4364 rc = SyBlobAppend(pBlob,(const void *)zBuf,sizeof(zBuf));
4365 return rc;
4366}
4367JX9_PRIVATE void SyTimeFormatToDos(Sytm *pFmt,sxu32 *pOut)
4368{
4369 sxi32 nDate,nTime;
4370 nDate = ((pFmt->tm_year - 1980) << 9) + (pFmt->tm_mon << 5) + pFmt->tm_mday;
4371 nTime = (pFmt->tm_hour << 11) + (pFmt->tm_min << 5)+ (pFmt->tm_sec >> 1);
4372 *pOut = (nDate << 16) | nTime;
4373}
4374JX9_PRIVATE void SyDosTimeFormat(sxu32 nDosDate, Sytm *pOut)
4375{
4376 sxu16 nDate;
4377 sxu16 nTime;
4378 nDate = nDosDate >> 16;
4379 nTime = nDosDate & 0xFFFF;
4380 pOut->tm_isdst = 0;
4381 pOut->tm_year = 1980 + (nDate >> 9);
4382 pOut->tm_mon = (nDate % (1<<9))>>5;
4383 pOut->tm_mday = (nDate % (1<<9))&0x1F;
4384 pOut->tm_hour = nTime >> 11;
4385 pOut->tm_min = (nTime % (1<<11)) >> 5;
4386 pOut->tm_sec = ((nTime % (1<<11))& 0x1F )<<1;
4387}