/* * Symisc PH7: An embeddable bytecode compiler and a virtual machine for the PHP(5) programming language. * Copyright (C) 2011-2012, Symisc Systems http://ph7.symisc.net/ * Version 2.1.4 * For information on licensing,redistribution of this file,and for a DISCLAIMER OF ALL WARRANTIES * please contact Symisc Systems via: * legal@symisc.net * licensing@symisc.net * contact@symisc.net * or visit: * http://ph7.symisc.net/ */ /* $SymiscID: lib.c v5.1 Win7 2012-08-08 04:19 stable $ */ /* * Symisc Run-Time API: A modern thread safe replacement of the standard libc * Copyright (C) Symisc Systems 2007-2012, http://www.symisc.net/ * * The Symisc Run-Time API is an independent project developed by symisc systems * internally as a secure replacement of the standard libc. * The library is re-entrant,thread-safe and platform independent. */ #include "ph7int.h" #if defined(__WINNT__) #include #else #include #endif #if defined(PH7_ENABLE_THREADS) /* SyRunTimeApi: sxmutex.c */ #if defined(__WINNT__) struct SyMutex { CRITICAL_SECTION sMutex; sxu32 nType; /* Mutex type,one of SXMUTEX_TYPE_* */ }; /* Preallocated static mutex */ static SyMutex aStaticMutexes[] = { {{0},SXMUTEX_TYPE_STATIC_1}, {{0},SXMUTEX_TYPE_STATIC_2}, {{0},SXMUTEX_TYPE_STATIC_3}, {{0},SXMUTEX_TYPE_STATIC_4}, {{0},SXMUTEX_TYPE_STATIC_5}, {{0},SXMUTEX_TYPE_STATIC_6} }; static BOOL winMutexInit = FALSE; static LONG winMutexLock = 0; static sxi32 WinMutexGlobaInit(void) { LONG rc; rc = InterlockedCompareExchange(&winMutexLock,1,0); if ( rc == 0 ){ sxu32 n; for( n = 0 ; n < SX_ARRAYSIZE(aStaticMutexes) ; ++n ){ InitializeCriticalSection(&aStaticMutexes[n].sMutex); } winMutexInit = TRUE; }else{ /* Someone else is doing this for us */ while( winMutexInit == FALSE ){ Sleep(1); } } return SXRET_OK; } static void WinMutexGlobalRelease(void) { LONG rc; rc = InterlockedCompareExchange(&winMutexLock,0,1); if( rc == 1 ){ /* The first to decrement to zero does the actual global release */ if( winMutexInit == TRUE ){ sxu32 n; for( n = 0 ; n < SX_ARRAYSIZE(aStaticMutexes) ; ++n ){ DeleteCriticalSection(&aStaticMutexes[n].sMutex); } winMutexInit = FALSE; } } } static SyMutex * WinMutexNew(int nType) { SyMutex *pMutex = 0; if( nType == SXMUTEX_TYPE_FAST || nType == SXMUTEX_TYPE_RECURSIVE ){ /* Allocate a new mutex */ pMutex = (SyMutex *)HeapAlloc(GetProcessHeap(),0,sizeof(SyMutex)); if( pMutex == 0 ){ return 0; } InitializeCriticalSection(&pMutex->sMutex); }else{ /* Use a pre-allocated static mutex */ if( nType > SXMUTEX_TYPE_STATIC_6 ){ nType = SXMUTEX_TYPE_STATIC_6; } pMutex = &aStaticMutexes[nType - 3]; } pMutex->nType = nType; return pMutex; } static void WinMutexRelease(SyMutex *pMutex) { if( pMutex->nType == SXMUTEX_TYPE_FAST || pMutex->nType == SXMUTEX_TYPE_RECURSIVE ){ DeleteCriticalSection(&pMutex->sMutex); HeapFree(GetProcessHeap(),0,pMutex); } } static void WinMutexEnter(SyMutex *pMutex) { EnterCriticalSection(&pMutex->sMutex); } static sxi32 WinMutexTryEnter(SyMutex *pMutex) { #ifdef _WIN32_WINNT BOOL rc; /* Only WindowsNT platforms */ rc = TryEnterCriticalSection(&pMutex->sMutex); if( rc ){ return SXRET_OK; }else{ return SXERR_BUSY; } #else return SXERR_NOTIMPLEMENTED; #endif } static void WinMutexLeave(SyMutex *pMutex) { LeaveCriticalSection(&pMutex->sMutex); } /* Export Windows mutex interfaces */ static const SyMutexMethods sWinMutexMethods = { WinMutexGlobaInit, /* xGlobalInit() */ WinMutexGlobalRelease, /* xGlobalRelease() */ WinMutexNew, /* xNew() */ WinMutexRelease, /* xRelease() */ WinMutexEnter, /* xEnter() */ WinMutexTryEnter, /* xTryEnter() */ WinMutexLeave /* xLeave() */ }; PH7_PRIVATE const SyMutexMethods * SyMutexExportMethods(void) { return &sWinMutexMethods; } #elif defined(__UNIXES__) #include struct SyMutex { pthread_mutex_t sMutex; sxu32 nType; }; static SyMutex * UnixMutexNew(int nType) { static SyMutex aStaticMutexes[] = { {PTHREAD_MUTEX_INITIALIZER,SXMUTEX_TYPE_STATIC_1}, {PTHREAD_MUTEX_INITIALIZER,SXMUTEX_TYPE_STATIC_2}, {PTHREAD_MUTEX_INITIALIZER,SXMUTEX_TYPE_STATIC_3}, {PTHREAD_MUTEX_INITIALIZER,SXMUTEX_TYPE_STATIC_4}, {PTHREAD_MUTEX_INITIALIZER,SXMUTEX_TYPE_STATIC_5}, {PTHREAD_MUTEX_INITIALIZER,SXMUTEX_TYPE_STATIC_6} }; SyMutex *pMutex; if( nType == SXMUTEX_TYPE_FAST || nType == SXMUTEX_TYPE_RECURSIVE ){ pthread_mutexattr_t sRecursiveAttr; /* Allocate a new mutex */ pMutex = (SyMutex *)malloc(sizeof(SyMutex)); if( pMutex == 0 ){ return 0; } if( nType == SXMUTEX_TYPE_RECURSIVE ){ pthread_mutexattr_init(&sRecursiveAttr); pthread_mutexattr_settype(&sRecursiveAttr,PTHREAD_MUTEX_RECURSIVE); } pthread_mutex_init(&pMutex->sMutex,nType == SXMUTEX_TYPE_RECURSIVE ? &sRecursiveAttr : 0 ); if( nType == SXMUTEX_TYPE_RECURSIVE ){ pthread_mutexattr_destroy(&sRecursiveAttr); } }else{ /* Use a pre-allocated static mutex */ if( nType > SXMUTEX_TYPE_STATIC_6 ){ nType = SXMUTEX_TYPE_STATIC_6; } pMutex = &aStaticMutexes[nType - 3]; } pMutex->nType = nType; return pMutex; } static void UnixMutexRelease(SyMutex *pMutex) { if( pMutex->nType == SXMUTEX_TYPE_FAST || pMutex->nType == SXMUTEX_TYPE_RECURSIVE ){ pthread_mutex_destroy(&pMutex->sMutex); free(pMutex); } } static void UnixMutexEnter(SyMutex *pMutex) { pthread_mutex_lock(&pMutex->sMutex); } static void UnixMutexLeave(SyMutex *pMutex) { pthread_mutex_unlock(&pMutex->sMutex); } /* Export pthread mutex interfaces */ static const SyMutexMethods sPthreadMutexMethods = { 0, /* xGlobalInit() */ 0, /* xGlobalRelease() */ UnixMutexNew, /* xNew() */ UnixMutexRelease, /* xRelease() */ UnixMutexEnter, /* xEnter() */ 0, /* xTryEnter() */ UnixMutexLeave /* xLeave() */ }; PH7_PRIVATE const SyMutexMethods * SyMutexExportMethods(void) { return &sPthreadMutexMethods; } #else /* Host application must register their own mutex subsystem if the target * platform is not an UNIX-like or windows systems. */ struct SyMutex { sxu32 nType; }; static SyMutex * DummyMutexNew(int nType) { static SyMutex sMutex; SXUNUSED(nType); return &sMutex; } static void DummyMutexRelease(SyMutex *pMutex) { SXUNUSED(pMutex); } static void DummyMutexEnter(SyMutex *pMutex) { SXUNUSED(pMutex); } static void DummyMutexLeave(SyMutex *pMutex) { SXUNUSED(pMutex); } /* Export the dummy mutex interfaces */ static const SyMutexMethods sDummyMutexMethods = { 0, /* xGlobalInit() */ 0, /* xGlobalRelease() */ DummyMutexNew, /* xNew() */ DummyMutexRelease, /* xRelease() */ DummyMutexEnter, /* xEnter() */ 0, /* xTryEnter() */ DummyMutexLeave /* xLeave() */ }; PH7_PRIVATE const SyMutexMethods * SyMutexExportMethods(void) { return &sDummyMutexMethods; } #endif /* __WINNT__ */ #endif /* PH7_ENABLE_THREADS */ static void * SyOSHeapAlloc(sxu32 nByte) { void *pNew; #if defined(__WINNT__) pNew = HeapAlloc(GetProcessHeap(),0,nByte); #else pNew = malloc((size_t)nByte); #endif return pNew; } static void * SyOSHeapRealloc(void *pOld,sxu32 nByte) { void *pNew; #if defined(__WINNT__) pNew = HeapReAlloc(GetProcessHeap(),0,pOld,nByte); #else pNew = realloc(pOld,(size_t)nByte); #endif return pNew; } static void SyOSHeapFree(void *pPtr) { #if defined(__WINNT__) HeapFree(GetProcessHeap(),0,pPtr); #else free(pPtr); #endif } /* SyRunTimeApi:sxstr.c */ PH7_PRIVATE sxu32 SyStrlen(const char *zSrc) { register const char *zIn = zSrc; #if defined(UNTRUST) if( zIn == 0 ){ return 0; } #endif for(;;){ if( !zIn[0] ){ break; } zIn++; if( !zIn[0] ){ break; } zIn++; if( !zIn[0] ){ break; } zIn++; if( !zIn[0] ){ break; } zIn++; } return (sxu32)(zIn - zSrc); } PH7_PRIVATE sxi32 SyByteFind(const char *zStr,sxu32 nLen,sxi32 c,sxu32 *pPos) { const char *zIn = zStr; const char *zEnd; zEnd = &zIn[nLen]; for(;;){ if( zIn >= zEnd ){ break; }if( zIn[0] == c ){ if( pPos ){ *pPos = (sxu32)(zIn - zStr); } return SXRET_OK; } zIn++; if( zIn >= zEnd ){ break; }if( zIn[0] == c ){ if( pPos ){ *pPos = (sxu32)(zIn - zStr); } return SXRET_OK; } zIn++; if( zIn >= zEnd ){ break; }if( zIn[0] == c ){ if( pPos ){ *pPos = (sxu32)(zIn - zStr); } return SXRET_OK; } zIn++; if( zIn >= zEnd ){ break; }if( zIn[0] == c ){ if( pPos ){ *pPos = (sxu32)(zIn - zStr); } return SXRET_OK; } zIn++; } return SXERR_NOTFOUND; } #ifndef PH7_DISABLE_BUILTIN_FUNC PH7_PRIVATE sxi32 SyByteFind2(const char *zStr,sxu32 nLen,sxi32 c,sxu32 *pPos) { const char *zIn = zStr; const char *zEnd; zEnd = &zIn[nLen - 1]; for( ;; ){ if( zEnd < zIn ){ break; } if( zEnd[0] == c ){ if( pPos ){ *pPos = (sxu32)(zEnd - zIn);} return SXRET_OK; } zEnd--; if( zEnd < zIn ){ break; } if( zEnd[0] == c ){ if( pPos ){ *pPos = (sxu32)(zEnd - zIn);} return SXRET_OK; } zEnd--; if( zEnd < zIn ){ break; } if( zEnd[0] == c ){ if( pPos ){ *pPos = (sxu32)(zEnd - zIn);} return SXRET_OK; } zEnd--; if( zEnd < zIn ){ break; } if( zEnd[0] == c ){ if( pPos ){ *pPos = (sxu32)(zEnd - zIn);} return SXRET_OK; } zEnd--; } return SXERR_NOTFOUND; } #endif /* PH7_DISABLE_BUILTIN_FUNC */ PH7_PRIVATE sxi32 SyByteListFind(const char *zSrc,sxu32 nLen,const char *zList,sxu32 *pFirstPos) { const char *zIn = zSrc; const char *zPtr; const char *zEnd; sxi32 c; zEnd = &zSrc[nLen]; for(;;){ 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++; 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++; 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++; 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++; } return SXERR_NOTFOUND; } #ifndef PH7_DISABLE_BUILTIN_FUNC PH7_PRIVATE sxi32 SyStrncmp(const char *zLeft,const char *zRight,sxu32 nLen) { const unsigned char *zP = (const unsigned char *)zLeft; const unsigned char *zQ = (const unsigned char *)zRight; if( SX_EMPTY_STR(zP) || SX_EMPTY_STR(zQ) ){ return SX_EMPTY_STR(zP) ? (SX_EMPTY_STR(zQ) ? 0 : -1) :1; } if( nLen <= 0 ){ return 0; } for(;;){ if( nLen <= 0 ){ return 0; } if( zP[0] == 0 || zQ[0] == 0 || zP[0] != zQ[0] ){ break; } zP++; zQ++; nLen--; if( nLen <= 0 ){ return 0; } if( zP[0] == 0 || zQ[0] == 0 || zP[0] != zQ[0] ){ break; } zP++; zQ++; nLen--; if( nLen <= 0 ){ return 0; } if( zP[0] == 0 || zQ[0] == 0 || zP[0] != zQ[0] ){ break; } zP++; zQ++; nLen--; if( nLen <= 0 ){ return 0; } if( zP[0] == 0 || zQ[0] == 0 || zP[0] != zQ[0] ){ break; } zP++; zQ++; nLen--; } return (sxi32)(zP[0] - zQ[0]); } #endif PH7_PRIVATE sxi32 SyStrnicmp(const char *zLeft, const char *zRight,sxu32 SLen) { register unsigned char *p = (unsigned char *)zLeft; register unsigned char *q = (unsigned char *)zRight; if( SX_EMPTY_STR(p) || SX_EMPTY_STR(q) ){ return SX_EMPTY_STR(p)? SX_EMPTY_STR(q) ? 0 : -1 :1; } for(;;){ if( !SLen ){ return 0; }if( !*p || !*q || SyCharToLower(*p) != SyCharToLower(*q) ){ break; }p++;q++;--SLen; if( !SLen ){ return 0; }if( !*p || !*q || SyCharToLower(*p) != SyCharToLower(*q) ){ break; }p++;q++;--SLen; if( !SLen ){ return 0; }if( !*p || !*q || SyCharToLower(*p) != SyCharToLower(*q) ){ break; }p++;q++;--SLen; if( !SLen ){ return 0; }if( !*p || !*q || SyCharToLower(*p) != SyCharToLower(*q) ){ break; }p++;q++;--SLen; } return (sxi32)(SyCharToLower(p[0]) - SyCharToLower(q[0])); } PH7_PRIVATE sxi32 SyStrnmicmp(const void *pLeft, const void *pRight,sxu32 SLen) { return SyStrnicmp((const char *)pLeft,(const char *)pRight,SLen); } static sxu32 Systrcpy(char *zDest,sxu32 nDestLen,const char *zSrc,sxu32 nLen) { unsigned char *zBuf = (unsigned char *)zDest; unsigned char *zIn = (unsigned char *)zSrc; unsigned char *zEnd; #if defined(UNTRUST) if( zSrc == (const char *)zDest ){ return 0; } #endif if( nLen <= 0 ){ nLen = SyStrlen(zSrc); } zEnd = &zBuf[nDestLen - 1]; /* reserve a room for the null terminator */ for(;;){ if( zBuf >= zEnd || nLen == 0 ){ break;} zBuf[0] = zIn[0]; zIn++; zBuf++; nLen--; if( zBuf >= zEnd || nLen == 0 ){ break;} zBuf[0] = zIn[0]; zIn++; zBuf++; nLen--; if( zBuf >= zEnd || nLen == 0 ){ break;} zBuf[0] = zIn[0]; zIn++; zBuf++; nLen--; if( zBuf >= zEnd || nLen == 0 ){ break;} zBuf[0] = zIn[0]; zIn++; zBuf++; nLen--; } zBuf[0] = 0; return (sxu32)(zBuf-(unsigned char *)zDest); } /* SyRunTimeApi:sxmem.c */ PH7_PRIVATE void SyZero(void *pSrc,sxu32 nSize) { register unsigned char *zSrc = (unsigned char *)pSrc; unsigned char *zEnd; #if defined(UNTRUST) if( zSrc == 0 || nSize <= 0 ){ return ; } #endif zEnd = &zSrc[nSize]; for(;;){ if( zSrc >= zEnd ){break;} zSrc[0] = 0; zSrc++; if( zSrc >= zEnd ){break;} zSrc[0] = 0; zSrc++; if( zSrc >= zEnd ){break;} zSrc[0] = 0; zSrc++; if( zSrc >= zEnd ){break;} zSrc[0] = 0; zSrc++; } } PH7_PRIVATE sxi32 SyMemcmp(const void *pB1,const void *pB2,sxu32 nSize) { sxi32 rc; if( nSize <= 0 ){ return 0; } if( pB1 == 0 || pB2 == 0 ){ return pB1 != 0 ? 1 : (pB2 == 0 ? 0 : -1); } SX_MACRO_FAST_CMP(pB1,pB2,nSize,rc); return rc; } PH7_PRIVATE sxu32 SyMemcpy(const void *pSrc,void *pDest,sxu32 nLen) { #if defined(UNTRUST) if( pSrc == 0 || pDest == 0 ){ return 0; } #endif if( pSrc == (const void *)pDest ){ return nLen; } SX_MACRO_FAST_MEMCPY(pSrc,pDest,nLen); return nLen; } static void * MemOSAlloc(sxu32 nBytes) { sxu32 *pChunk; pChunk = (sxu32 *)SyOSHeapAlloc(nBytes + sizeof(sxu32)); if( pChunk == 0 ){ return 0; } pChunk[0] = nBytes; return (void *)&pChunk[1]; } static void * MemOSRealloc(void *pOld,sxu32 nBytes) { sxu32 *pOldChunk; sxu32 *pChunk; pOldChunk = (sxu32 *)(((char *)pOld)-sizeof(sxu32)); if( pOldChunk[0] >= nBytes ){ return pOld; } pChunk = (sxu32 *)SyOSHeapRealloc(pOldChunk,nBytes + sizeof(sxu32)); if( pChunk == 0 ){ return 0; } pChunk[0] = nBytes; return (void *)&pChunk[1]; } static void MemOSFree(void *pBlock) { void *pChunk; pChunk = (void *)(((char *)pBlock)-sizeof(sxu32)); SyOSHeapFree(pChunk); } static sxu32 MemOSChunkSize(void *pBlock) { sxu32 *pChunk; pChunk = (sxu32 *)(((char *)pBlock)-sizeof(sxu32)); return pChunk[0]; } /* Export OS allocation methods */ static const SyMemMethods sOSAllocMethods = { MemOSAlloc, MemOSRealloc, MemOSFree, MemOSChunkSize, 0, 0, 0 }; static void * MemBackendAlloc(SyMemBackend *pBackend,sxu32 nByte) { SyMemBlock *pBlock; sxi32 nRetry = 0; /* Append an extra block so we can tracks allocated chunks and avoid memory * leaks. */ nByte += sizeof(SyMemBlock); for(;;){ pBlock = (SyMemBlock *)pBackend->pMethods->xAlloc(nByte); if( pBlock != 0 || pBackend->xMemError == 0 || nRetry > SXMEM_BACKEND_RETRY || SXERR_RETRY != pBackend->xMemError(pBackend->pUserData) ){ break; } nRetry++; } if( pBlock == 0 ){ return 0; } pBlock->pNext = pBlock->pPrev = 0; /* Link to the list of already tracked blocks */ MACRO_LD_PUSH(pBackend->pBlocks,pBlock); #if defined(UNTRUST) pBlock->nGuard = SXMEM_BACKEND_MAGIC; #endif pBackend->nBlock++; return (void *)&pBlock[1]; } PH7_PRIVATE void * SyMemBackendAlloc(SyMemBackend *pBackend,sxu32 nByte) { void *pChunk; #if defined(UNTRUST) if( SXMEM_BACKEND_CORRUPT(pBackend) ){ return 0; } #endif if( pBackend->pMutexMethods ){ SyMutexEnter(pBackend->pMutexMethods,pBackend->pMutex); } pChunk = MemBackendAlloc(&(*pBackend),nByte); if( pBackend->pMutexMethods ){ SyMutexLeave(pBackend->pMutexMethods,pBackend->pMutex); } return pChunk; } static void * MemBackendRealloc(SyMemBackend *pBackend,void * pOld,sxu32 nByte) { SyMemBlock *pBlock,*pNew,*pPrev,*pNext; sxu32 nRetry = 0; if( pOld == 0 ){ return MemBackendAlloc(&(*pBackend),nByte); } pBlock = (SyMemBlock *)(((char *)pOld) - sizeof(SyMemBlock)); #if defined(UNTRUST) if( pBlock->nGuard != SXMEM_BACKEND_MAGIC ){ return 0; } #endif nByte += sizeof(SyMemBlock); pPrev = pBlock->pPrev; pNext = pBlock->pNext; for(;;){ pNew = (SyMemBlock *)pBackend->pMethods->xRealloc(pBlock,nByte); if( pNew != 0 || pBackend->xMemError == 0 || nRetry > SXMEM_BACKEND_RETRY || SXERR_RETRY != pBackend->xMemError(pBackend->pUserData) ){ break; } nRetry++; } if( pNew == 0 ){ return 0; } if( pNew != pBlock ){ if( pPrev == 0 ){ pBackend->pBlocks = pNew; }else{ pPrev->pNext = pNew; } if( pNext ){ pNext->pPrev = pNew; } #if defined(UNTRUST) pNew->nGuard = SXMEM_BACKEND_MAGIC; #endif } return (void *)&pNew[1]; } PH7_PRIVATE void * SyMemBackendRealloc(SyMemBackend *pBackend,void * pOld,sxu32 nByte) { void *pChunk; #if defined(UNTRUST) if( SXMEM_BACKEND_CORRUPT(pBackend) ){ return 0; } #endif if( pBackend->pMutexMethods ){ SyMutexEnter(pBackend->pMutexMethods,pBackend->pMutex); } pChunk = MemBackendRealloc(&(*pBackend),pOld,nByte); if( pBackend->pMutexMethods ){ SyMutexLeave(pBackend->pMutexMethods,pBackend->pMutex); } return pChunk; } static sxi32 MemBackendFree(SyMemBackend *pBackend,void * pChunk) { SyMemBlock *pBlock; pBlock = (SyMemBlock *)(((char *)pChunk) - sizeof(SyMemBlock)); #if defined(UNTRUST) if( pBlock->nGuard != SXMEM_BACKEND_MAGIC ){ return SXERR_CORRUPT; } #endif /* Unlink from the list of active blocks */ if( pBackend->nBlock > 0 ){ /* Release the block */ #if defined(UNTRUST) /* Mark as stale block */ pBlock->nGuard = 0x635B; #endif MACRO_LD_REMOVE(pBackend->pBlocks,pBlock); pBackend->nBlock--; pBackend->pMethods->xFree(pBlock); } return SXRET_OK; } PH7_PRIVATE sxi32 SyMemBackendFree(SyMemBackend *pBackend,void * pChunk) { sxi32 rc; #if defined(UNTRUST) if( SXMEM_BACKEND_CORRUPT(pBackend) ){ return SXERR_CORRUPT; } #endif if( pChunk == 0 ){ return SXRET_OK; } if( pBackend->pMutexMethods ){ SyMutexEnter(pBackend->pMutexMethods,pBackend->pMutex); } rc = MemBackendFree(&(*pBackend),pChunk); if( pBackend->pMutexMethods ){ SyMutexLeave(pBackend->pMutexMethods,pBackend->pMutex); } return rc; } #if defined(PH7_ENABLE_THREADS) PH7_PRIVATE sxi32 SyMemBackendMakeThreadSafe(SyMemBackend *pBackend,const SyMutexMethods *pMethods) { SyMutex *pMutex; #if defined(UNTRUST) if( SXMEM_BACKEND_CORRUPT(pBackend) || pMethods == 0 || pMethods->xNew == 0){ return SXERR_CORRUPT; } #endif pMutex = pMethods->xNew(SXMUTEX_TYPE_FAST); if( pMutex == 0 ){ return SXERR_OS; } /* Attach the mutex to the memory backend */ pBackend->pMutex = pMutex; pBackend->pMutexMethods = pMethods; return SXRET_OK; } PH7_PRIVATE sxi32 SyMemBackendDisbaleMutexing(SyMemBackend *pBackend) { #if defined(UNTRUST) if( SXMEM_BACKEND_CORRUPT(pBackend) ){ return SXERR_CORRUPT; } #endif if( pBackend->pMutex == 0 ){ /* There is no mutex subsystem at all */ return SXRET_OK; } SyMutexRelease(pBackend->pMutexMethods,pBackend->pMutex); pBackend->pMutexMethods = 0; pBackend->pMutex = 0; return SXRET_OK; } #endif /* * Memory pool allocator */ #define SXMEM_POOL_MAGIC 0xDEAD #define SXMEM_POOL_MAXALLOC (1<<(SXMEM_POOL_NBUCKETS+SXMEM_POOL_INCR)) #define SXMEM_POOL_MINALLOC (1<<(SXMEM_POOL_INCR)) static sxi32 MemPoolBucketAlloc(SyMemBackend *pBackend,sxu32 nBucket) { char *zBucket,*zBucketEnd; SyMemHeader *pHeader; sxu32 nBucketSize; /* Allocate one big block first */ zBucket = (char *)MemBackendAlloc(&(*pBackend),SXMEM_POOL_MAXALLOC); if( zBucket == 0 ){ return SXERR_MEM; } zBucketEnd = &zBucket[SXMEM_POOL_MAXALLOC]; /* Divide the big block into mini bucket pool */ nBucketSize = 1 << (nBucket + SXMEM_POOL_INCR); pBackend->apPool[nBucket] = pHeader = (SyMemHeader *)zBucket; for(;;){ if( &zBucket[nBucketSize] >= zBucketEnd ){ break; } pHeader->pNext = (SyMemHeader *)&zBucket[nBucketSize]; /* Advance the cursor to the next available chunk */ pHeader = pHeader->pNext; zBucket += nBucketSize; } pHeader->pNext = 0; return SXRET_OK; } static void * MemBackendPoolAlloc(SyMemBackend *pBackend,sxu32 nByte) { SyMemHeader *pBucket,*pNext; sxu32 nBucketSize; sxu32 nBucket; if( nByte + sizeof(SyMemHeader) >= SXMEM_POOL_MAXALLOC ){ /* Allocate a big chunk directly */ pBucket = (SyMemHeader *)MemBackendAlloc(&(*pBackend),nByte+sizeof(SyMemHeader)); if( pBucket == 0 ){ return 0; } /* Record as big block */ pBucket->nBucket = (sxu32)(SXMEM_POOL_MAGIC << 16) | SXU16_HIGH; return (void *)(pBucket+1); } /* Locate the appropriate bucket */ nBucket = 0; nBucketSize = SXMEM_POOL_MINALLOC; while( nByte + sizeof(SyMemHeader) > nBucketSize ){ nBucketSize <<= 1; nBucket++; } pBucket = pBackend->apPool[nBucket]; if( pBucket == 0 ){ sxi32 rc; rc = MemPoolBucketAlloc(&(*pBackend),nBucket); if( rc != SXRET_OK ){ return 0; } pBucket = pBackend->apPool[nBucket]; } /* Remove from the free list */ pNext = pBucket->pNext; pBackend->apPool[nBucket] = pNext; /* Record bucket&magic number */ pBucket->nBucket = (SXMEM_POOL_MAGIC << 16) | nBucket; return (void *)&pBucket[1]; } PH7_PRIVATE void * SyMemBackendPoolAlloc(SyMemBackend *pBackend,sxu32 nByte) { void *pChunk; #if defined(UNTRUST) if( SXMEM_BACKEND_CORRUPT(pBackend) ){ return 0; } #endif if( pBackend->pMutexMethods ){ SyMutexEnter(pBackend->pMutexMethods,pBackend->pMutex); } pChunk = MemBackendPoolAlloc(&(*pBackend),nByte); if( pBackend->pMutexMethods ){ SyMutexLeave(pBackend->pMutexMethods,pBackend->pMutex); } return pChunk; } static sxi32 MemBackendPoolFree(SyMemBackend *pBackend,void * pChunk) { SyMemHeader *pHeader; sxu32 nBucket; /* Get the corresponding bucket */ pHeader = (SyMemHeader *)(((char *)pChunk) - sizeof(SyMemHeader)); /* Sanity check to avoid misuse */ if( (pHeader->nBucket >> 16) != SXMEM_POOL_MAGIC ){ return SXERR_CORRUPT; } nBucket = pHeader->nBucket & 0xFFFF; if( nBucket == SXU16_HIGH ){ /* Free the big block */ MemBackendFree(&(*pBackend),pHeader); }else{ /* Return to the free list */ pHeader->pNext = pBackend->apPool[nBucket & 0x0f]; pBackend->apPool[nBucket & 0x0f] = pHeader; } return SXRET_OK; } PH7_PRIVATE sxi32 SyMemBackendPoolFree(SyMemBackend *pBackend,void * pChunk) { sxi32 rc; #if defined(UNTRUST) if( SXMEM_BACKEND_CORRUPT(pBackend) || pChunk == 0 ){ return SXERR_CORRUPT; } #endif if( pBackend->pMutexMethods ){ SyMutexEnter(pBackend->pMutexMethods,pBackend->pMutex); } rc = MemBackendPoolFree(&(*pBackend),pChunk); if( pBackend->pMutexMethods ){ SyMutexLeave(pBackend->pMutexMethods,pBackend->pMutex); } return rc; } #if 0 static void * MemBackendPoolRealloc(SyMemBackend *pBackend,void * pOld,sxu32 nByte) { sxu32 nBucket,nBucketSize; SyMemHeader *pHeader; void * pNew; if( pOld == 0 ){ /* Allocate a new pool */ pNew = MemBackendPoolAlloc(&(*pBackend),nByte); return pNew; } /* Get the corresponding bucket */ pHeader = (SyMemHeader *)(((char *)pOld) - sizeof(SyMemHeader)); /* Sanity check to avoid misuse */ if( (pHeader->nBucket >> 16) != SXMEM_POOL_MAGIC ){ return 0; } nBucket = pHeader->nBucket & 0xFFFF; if( nBucket == SXU16_HIGH ){ /* Big block */ return MemBackendRealloc(&(*pBackend),pHeader,nByte); } nBucketSize = 1 << (nBucket + SXMEM_POOL_INCR); if( nBucketSize >= nByte + sizeof(SyMemHeader) ){ /* The old bucket can honor the requested size */ return pOld; } /* Allocate a new pool */ pNew = MemBackendPoolAlloc(&(*pBackend),nByte); if( pNew == 0 ){ return 0; } /* Copy the old data into the new block */ SyMemcpy(pOld,pNew,nBucketSize); /* Free the stale block */ MemBackendPoolFree(&(*pBackend),pOld); return pNew; } PH7_PRIVATE void * SyMemBackendPoolRealloc(SyMemBackend *pBackend,void * pOld,sxu32 nByte) { void *pChunk; #if defined(UNTRUST) if( SXMEM_BACKEND_CORRUPT(pBackend) ){ return 0; } #endif if( pBackend->pMutexMethods ){ SyMutexEnter(pBackend->pMutexMethods,pBackend->pMutex); } pChunk = MemBackendPoolRealloc(&(*pBackend),pOld,nByte); if( pBackend->pMutexMethods ){ SyMutexLeave(pBackend->pMutexMethods,pBackend->pMutex); } return pChunk; } #endif PH7_PRIVATE sxi32 SyMemBackendInit(SyMemBackend *pBackend,ProcMemError xMemErr,void * pUserData) { #if defined(UNTRUST) if( pBackend == 0 ){ return SXERR_EMPTY; } #endif /* Zero the allocator first */ SyZero(&(*pBackend),sizeof(SyMemBackend)); pBackend->xMemError = xMemErr; pBackend->pUserData = pUserData; /* Switch to the OS memory allocator */ pBackend->pMethods = &sOSAllocMethods; if( pBackend->pMethods->xInit ){ /* Initialize the backend */ if( SXRET_OK != pBackend->pMethods->xInit(pBackend->pMethods->pUserData) ){ return SXERR_ABORT; } } #if defined(UNTRUST) pBackend->nMagic = SXMEM_BACKEND_MAGIC; #endif return SXRET_OK; } PH7_PRIVATE sxi32 SyMemBackendInitFromOthers(SyMemBackend *pBackend,const SyMemMethods *pMethods,ProcMemError xMemErr,void * pUserData) { #if defined(UNTRUST) if( pBackend == 0 || pMethods == 0){ return SXERR_EMPTY; } #endif if( pMethods->xAlloc == 0 || pMethods->xRealloc == 0 || pMethods->xFree == 0 || pMethods->xChunkSize == 0 ){ /* mandatory methods are missing */ return SXERR_INVALID; } /* Zero the allocator first */ SyZero(&(*pBackend),sizeof(SyMemBackend)); pBackend->xMemError = xMemErr; pBackend->pUserData = pUserData; /* Switch to the host application memory allocator */ pBackend->pMethods = pMethods; if( pBackend->pMethods->xInit ){ /* Initialize the backend */ if( SXRET_OK != pBackend->pMethods->xInit(pBackend->pMethods->pUserData) ){ return SXERR_ABORT; } } #if defined(UNTRUST) pBackend->nMagic = SXMEM_BACKEND_MAGIC; #endif return SXRET_OK; } PH7_PRIVATE sxi32 SyMemBackendInitFromParent(SyMemBackend *pBackend,SyMemBackend *pParent) { sxu8 bInheritMutex; #if defined(UNTRUST) if( pBackend == 0 || SXMEM_BACKEND_CORRUPT(pParent) ){ return SXERR_CORRUPT; } #endif /* Zero the allocator first */ SyZero(&(*pBackend),sizeof(SyMemBackend)); pBackend->pMethods = pParent->pMethods; pBackend->xMemError = pParent->xMemError; pBackend->pUserData = pParent->pUserData; bInheritMutex = pParent->pMutexMethods ? TRUE : FALSE; if( bInheritMutex ){ pBackend->pMutexMethods = pParent->pMutexMethods; /* Create a private mutex */ pBackend->pMutex = pBackend->pMutexMethods->xNew(SXMUTEX_TYPE_FAST); if( pBackend->pMutex == 0){ return SXERR_OS; } } #if defined(UNTRUST) pBackend->nMagic = SXMEM_BACKEND_MAGIC; #endif return SXRET_OK; } static sxi32 MemBackendRelease(SyMemBackend *pBackend) { SyMemBlock *pBlock,*pNext; pBlock = pBackend->pBlocks; for(;;){ if( pBackend->nBlock == 0 ){ break; } pNext = pBlock->pNext; pBackend->pMethods->xFree(pBlock); pBlock = pNext; pBackend->nBlock--; /* LOOP ONE */ if( pBackend->nBlock == 0 ){ break; } pNext = pBlock->pNext; pBackend->pMethods->xFree(pBlock); pBlock = pNext; pBackend->nBlock--; /* LOOP TWO */ if( pBackend->nBlock == 0 ){ break; } pNext = pBlock->pNext; pBackend->pMethods->xFree(pBlock); pBlock = pNext; pBackend->nBlock--; /* LOOP THREE */ if( pBackend->nBlock == 0 ){ break; } pNext = pBlock->pNext; pBackend->pMethods->xFree(pBlock); pBlock = pNext; pBackend->nBlock--; /* LOOP FOUR */ } if( pBackend->pMethods->xRelease ){ pBackend->pMethods->xRelease(pBackend->pMethods->pUserData); } pBackend->pMethods = 0; pBackend->pBlocks = 0; #if defined(UNTRUST) pBackend->nMagic = 0x2626; #endif return SXRET_OK; } PH7_PRIVATE sxi32 SyMemBackendRelease(SyMemBackend *pBackend) { sxi32 rc; #if defined(UNTRUST) if( SXMEM_BACKEND_CORRUPT(pBackend) ){ return SXERR_INVALID; } #endif if( pBackend->pMutexMethods ){ SyMutexEnter(pBackend->pMutexMethods,pBackend->pMutex); } rc = MemBackendRelease(&(*pBackend)); if( pBackend->pMutexMethods ){ SyMutexLeave(pBackend->pMutexMethods,pBackend->pMutex); SyMutexRelease(pBackend->pMutexMethods,pBackend->pMutex); } return SXRET_OK; } PH7_PRIVATE void * SyMemBackendDup(SyMemBackend *pBackend,const void *pSrc,sxu32 nSize) { void *pNew; #if defined(UNTRUST) if( pSrc == 0 || nSize <= 0 ){ return 0; } #endif pNew = SyMemBackendAlloc(&(*pBackend),nSize); if( pNew ){ SyMemcpy(pSrc,pNew,nSize); } return pNew; } PH7_PRIVATE char * SyMemBackendStrDup(SyMemBackend *pBackend,const char *zSrc,sxu32 nSize) { char *zDest; zDest = (char *)SyMemBackendAlloc(&(*pBackend),nSize + 1); if( zDest ){ Systrcpy(zDest,nSize+1,zSrc,nSize); } return zDest; } PH7_PRIVATE sxi32 SyBlobInitFromBuf(SyBlob *pBlob,void *pBuffer,sxu32 nSize) { #if defined(UNTRUST) if( pBlob == 0 || pBuffer == 0 || nSize < 1 ){ return SXERR_EMPTY; } #endif pBlob->pBlob = pBuffer; pBlob->mByte = nSize; pBlob->nByte = 0; pBlob->pAllocator = 0; pBlob->nFlags = SXBLOB_LOCKED|SXBLOB_STATIC; return SXRET_OK; } PH7_PRIVATE sxi32 SyBlobInit(SyBlob *pBlob,SyMemBackend *pAllocator) { #if defined(UNTRUST) if( pBlob == 0 ){ return SXERR_EMPTY; } #endif pBlob->pBlob = 0; pBlob->mByte = pBlob->nByte = 0; pBlob->pAllocator = &(*pAllocator); pBlob->nFlags = 0; return SXRET_OK; } PH7_PRIVATE sxi32 SyBlobReadOnly(SyBlob *pBlob,const void *pData,sxu32 nByte) { #if defined(UNTRUST) if( pBlob == 0 ){ return SXERR_EMPTY; } #endif pBlob->pBlob = (void *)pData; pBlob->nByte = nByte; pBlob->mByte = 0; pBlob->nFlags |= SXBLOB_RDONLY; return SXRET_OK; } #ifndef SXBLOB_MIN_GROWTH #define SXBLOB_MIN_GROWTH 16 #endif static sxi32 BlobPrepareGrow(SyBlob *pBlob,sxu32 *pByte) { sxu32 nByte; void *pNew; nByte = *pByte; if( pBlob->nFlags & (SXBLOB_LOCKED|SXBLOB_STATIC) ){ if ( SyBlobFreeSpace(pBlob) < nByte ){ *pByte = SyBlobFreeSpace(pBlob); if( (*pByte) == 0 ){ return SXERR_SHORT; } } return SXRET_OK; } if( pBlob->nFlags & SXBLOB_RDONLY ){ /* Make a copy of the read-only item */ if( pBlob->nByte > 0 ){ pNew = SyMemBackendDup(pBlob->pAllocator,pBlob->pBlob,pBlob->nByte); if( pNew == 0 ){ return SXERR_MEM; } pBlob->pBlob = pNew; pBlob->mByte = pBlob->nByte; }else{ pBlob->pBlob = 0; pBlob->mByte = 0; } /* Remove the read-only flag */ pBlob->nFlags &= ~SXBLOB_RDONLY; } if( SyBlobFreeSpace(pBlob) >= nByte ){ return SXRET_OK; } if( pBlob->mByte > 0 ){ nByte = nByte + pBlob->mByte * 2 + SXBLOB_MIN_GROWTH; }else if ( nByte < SXBLOB_MIN_GROWTH ){ nByte = SXBLOB_MIN_GROWTH; } pNew = SyMemBackendRealloc(pBlob->pAllocator,pBlob->pBlob,nByte); if( pNew == 0 ){ return SXERR_MEM; } pBlob->pBlob = pNew; pBlob->mByte = nByte; return SXRET_OK; } PH7_PRIVATE sxi32 SyBlobAppend(SyBlob *pBlob,const void *pData,sxu32 nSize) { sxu8 *zBlob; sxi32 rc; if( nSize < 1 ){ return SXRET_OK; } rc = BlobPrepareGrow(&(*pBlob),&nSize); if( SXRET_OK != rc ){ return rc; } if( pData ){ zBlob = (sxu8 *)pBlob->pBlob ; zBlob = &zBlob[pBlob->nByte]; pBlob->nByte += nSize; SX_MACRO_FAST_MEMCPY(pData,zBlob,nSize); } return SXRET_OK; } PH7_PRIVATE sxi32 SyBlobNullAppend(SyBlob *pBlob) { sxi32 rc; sxu32 n; n = pBlob->nByte; rc = SyBlobAppend(&(*pBlob),(const void *)"\0",sizeof(char)); if (rc == SXRET_OK ){ pBlob->nByte = n; } return rc; } PH7_PRIVATE sxi32 SyBlobDup(SyBlob *pSrc,SyBlob *pDest) { sxi32 rc = SXRET_OK; #ifdef UNTRUST if( pSrc == 0 || pDest == 0 ){ return SXERR_EMPTY; } #endif if( pSrc->nByte > 0 ){ rc = SyBlobAppend(&(*pDest),pSrc->pBlob,pSrc->nByte); } return rc; } PH7_PRIVATE sxi32 SyBlobCmp(SyBlob *pLeft,SyBlob *pRight) { sxi32 rc; #ifdef UNTRUST if( pLeft == 0 || pRight == 0 ){ return pLeft ? 1 : -1; } #endif if( pLeft->nByte != pRight->nByte ){ /* Length differ */ return pLeft->nByte - pRight->nByte; } if( pLeft->nByte == 0 ){ return 0; } /* Perform a standard memcmp() operation */ rc = SyMemcmp(pLeft->pBlob,pRight->pBlob,pLeft->nByte); return rc; } PH7_PRIVATE sxi32 SyBlobReset(SyBlob *pBlob) { pBlob->nByte = 0; if( pBlob->nFlags & SXBLOB_RDONLY ){ pBlob->pBlob = 0; pBlob->mByte = 0; pBlob->nFlags &= ~SXBLOB_RDONLY; } return SXRET_OK; } PH7_PRIVATE sxi32 SyBlobRelease(SyBlob *pBlob) { if( (pBlob->nFlags & (SXBLOB_STATIC|SXBLOB_RDONLY)) == 0 && pBlob->mByte > 0 ){ SyMemBackendFree(pBlob->pAllocator,pBlob->pBlob); } pBlob->pBlob = 0; pBlob->nByte = pBlob->mByte = 0; pBlob->nFlags = 0; return SXRET_OK; } #ifndef PH7_DISABLE_BUILTIN_FUNC PH7_PRIVATE sxi32 SyBlobSearch(const void *pBlob,sxu32 nLen,const void *pPattern,sxu32 pLen,sxu32 *pOfft) { const char *zIn = (const char *)pBlob; const char *zEnd; sxi32 rc; if( pLen > nLen ){ return SXERR_NOTFOUND; } zEnd = &zIn[nLen-pLen]; for(;;){ 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++; 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++; 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++; 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++; } return SXERR_NOTFOUND; } #endif /* PH7_DISABLE_BUILTIN_FUNC */ /* SyRunTimeApi:sxds.c */ PH7_PRIVATE sxi32 SySetInit(SySet *pSet,SyMemBackend *pAllocator,sxu32 ElemSize) { pSet->nSize = 0 ; pSet->nUsed = 0; pSet->nCursor = 0; pSet->eSize = ElemSize; pSet->pAllocator = pAllocator; pSet->pBase = 0; pSet->pUserData = 0; return SXRET_OK; } PH7_PRIVATE sxi32 SySetPut(SySet *pSet,const void *pItem) { unsigned char *zbase; if( pSet->nUsed >= pSet->nSize ){ void *pNew; if( pSet->pAllocator == 0 ){ return SXERR_LOCKED; } if( pSet->nSize <= 0 ){ pSet->nSize = 4; } pNew = SyMemBackendRealloc(pSet->pAllocator,pSet->pBase,pSet->eSize * pSet->nSize * 2); if( pNew == 0 ){ return SXERR_MEM; } pSet->pBase = pNew; pSet->nSize <<= 1; } zbase = (unsigned char *)pSet->pBase; SX_MACRO_FAST_MEMCPY(pItem,&zbase[pSet->nUsed * pSet->eSize],pSet->eSize); pSet->nUsed++; return SXRET_OK; } PH7_PRIVATE sxi32 SySetAlloc(SySet *pSet,sxi32 nItem) { if( pSet->nSize > 0 ){ return SXERR_LOCKED; } if( nItem < 8 ){ nItem = 8; } pSet->pBase = SyMemBackendAlloc(pSet->pAllocator,pSet->eSize * nItem); if( pSet->pBase == 0 ){ return SXERR_MEM; } pSet->nSize = nItem; return SXRET_OK; } PH7_PRIVATE sxi32 SySetReset(SySet *pSet) { pSet->nUsed = 0; pSet->nCursor = 0; return SXRET_OK; } PH7_PRIVATE sxi32 SySetResetCursor(SySet *pSet) { pSet->nCursor = 0; return SXRET_OK; } PH7_PRIVATE sxi32 SySetGetNextEntry(SySet *pSet,void **ppEntry) { register unsigned char *zSrc; if( pSet->nCursor >= pSet->nUsed ){ /* Reset cursor */ pSet->nCursor = 0; return SXERR_EOF; } zSrc = (unsigned char *)SySetBasePtr(pSet); if( ppEntry ){ *ppEntry = (void *)&zSrc[pSet->nCursor * pSet->eSize]; } pSet->nCursor++; return SXRET_OK; } #ifndef PH7_DISABLE_BUILTIN_FUNC PH7_PRIVATE void * SySetPeekCurrentEntry(SySet *pSet) { register unsigned char *zSrc; if( pSet->nCursor >= pSet->nUsed ){ return 0; } zSrc = (unsigned char *)SySetBasePtr(pSet); return (void *)&zSrc[pSet->nCursor * pSet->eSize]; } #endif /* PH7_DISABLE_BUILTIN_FUNC */ PH7_PRIVATE sxi32 SySetTruncate(SySet *pSet,sxu32 nNewSize) { if( nNewSize < pSet->nUsed ){ pSet->nUsed = nNewSize; } return SXRET_OK; } PH7_PRIVATE sxi32 SySetRelease(SySet *pSet) { sxi32 rc = SXRET_OK; if( pSet->pAllocator && pSet->pBase ){ rc = SyMemBackendFree(pSet->pAllocator,pSet->pBase); } pSet->pBase = 0; pSet->nUsed = 0; pSet->nCursor = 0; return rc; } PH7_PRIVATE void * SySetPeek(SySet *pSet) { const char *zBase; if( pSet->nUsed <= 0 ){ return 0; } zBase = (const char *)pSet->pBase; return (void *)&zBase[(pSet->nUsed - 1) * pSet->eSize]; } PH7_PRIVATE void * SySetPop(SySet *pSet) { const char *zBase; void *pData; if( pSet->nUsed <= 0 ){ return 0; } zBase = (const char *)pSet->pBase; pSet->nUsed--; pData = (void *)&zBase[pSet->nUsed * pSet->eSize]; return pData; } PH7_PRIVATE void * SySetAt(SySet *pSet,sxu32 nIdx) { const char *zBase; if( nIdx >= pSet->nUsed ){ /* Out of range */ return 0; } zBase = (const char *)pSet->pBase; return (void *)&zBase[nIdx * pSet->eSize]; } /* Private hash entry */ struct SyHashEntry_Pr { const void *pKey; /* Hash key */ sxu32 nKeyLen; /* Key length */ void *pUserData; /* User private data */ /* Private fields */ sxu32 nHash; SyHash *pHash; SyHashEntry_Pr *pNext,*pPrev; /* Next and previous entry in the list */ SyHashEntry_Pr *pNextCollide,*pPrevCollide; /* Collision list */ }; #define INVALID_HASH(H) ((H)->apBucket == 0) /* Forward declarartion */ static sxu32 SyBinHash(const void *pSrc,sxu32 nLen); PH7_PRIVATE sxi32 SyHashInit(SyHash *pHash,SyMemBackend *pAllocator,ProcHash xHash,ProcCmp xCmp) { SyHashEntry_Pr **apNew; #if defined(UNTRUST) if( pHash == 0 ){ return SXERR_EMPTY; } #endif /* Allocate a new table */ apNew = (SyHashEntry_Pr **)SyMemBackendAlloc(&(*pAllocator),sizeof(SyHashEntry_Pr *) * SXHASH_BUCKET_SIZE); if( apNew == 0 ){ return SXERR_MEM; } SyZero((void *)apNew,sizeof(SyHashEntry_Pr *) * SXHASH_BUCKET_SIZE); pHash->pAllocator = &(*pAllocator); pHash->xHash = xHash ? xHash : SyBinHash; pHash->xCmp = xCmp ? xCmp : SyMemcmp; pHash->pCurrent = pHash->pList = 0; pHash->nEntry = 0; pHash->apBucket = apNew; pHash->nBucketSize = SXHASH_BUCKET_SIZE; return SXRET_OK; } PH7_PRIVATE sxi32 SyHashRelease(SyHash *pHash) { SyHashEntry_Pr *pEntry,*pNext; #if defined(UNTRUST) if( INVALID_HASH(pHash) ){ return SXERR_EMPTY; } #endif pEntry = pHash->pList; for(;;){ if( pHash->nEntry == 0 ){ break; } pNext = pEntry->pNext; SyMemBackendPoolFree(pHash->pAllocator,pEntry); pEntry = pNext; pHash->nEntry--; } if( pHash->apBucket ){ SyMemBackendFree(pHash->pAllocator,(void *)pHash->apBucket); } pHash->apBucket = 0; pHash->nBucketSize = 0; pHash->pAllocator = 0; return SXRET_OK; } static SyHashEntry_Pr * HashGetEntry(SyHash *pHash,const void *pKey,sxu32 nKeyLen) { SyHashEntry_Pr *pEntry; sxu32 nHash; nHash = pHash->xHash(pKey,nKeyLen); pEntry = pHash->apBucket[nHash & (pHash->nBucketSize - 1)]; for(;;){ if( pEntry == 0 ){ break; } if( pEntry->nHash == nHash && pEntry->nKeyLen == nKeyLen && pHash->xCmp(pEntry->pKey,pKey,nKeyLen) == 0 ){ return pEntry; } pEntry = pEntry->pNextCollide; } /* Entry not found */ return 0; } PH7_PRIVATE SyHashEntry * SyHashGet(SyHash *pHash,const void *pKey,sxu32 nKeyLen) { SyHashEntry_Pr *pEntry; #if defined(UNTRUST) if( INVALID_HASH(pHash) ){ return 0; } #endif if( pHash->nEntry < 1 || nKeyLen < 1 ){ /* Don't bother hashing,return immediately */ return 0; } pEntry = HashGetEntry(&(*pHash),pKey,nKeyLen); if( pEntry == 0 ){ return 0; } return (SyHashEntry *)pEntry; } static sxi32 HashDeleteEntry(SyHash *pHash,SyHashEntry_Pr *pEntry,void **ppUserData) { sxi32 rc; if( pEntry->pPrevCollide == 0 ){ pHash->apBucket[pEntry->nHash & (pHash->nBucketSize - 1)] = pEntry->pNextCollide; }else{ pEntry->pPrevCollide->pNextCollide = pEntry->pNextCollide; } if( pEntry->pNextCollide ){ pEntry->pNextCollide->pPrevCollide = pEntry->pPrevCollide; } MACRO_LD_REMOVE(pHash->pList,pEntry); pHash->nEntry--; if( ppUserData ){ /* Write a pointer to the user data */ *ppUserData = pEntry->pUserData; } /* Release the entry */ rc = SyMemBackendPoolFree(pHash->pAllocator,pEntry); return rc; } PH7_PRIVATE sxi32 SyHashDeleteEntry(SyHash *pHash,const void *pKey,sxu32 nKeyLen,void **ppUserData) { SyHashEntry_Pr *pEntry; sxi32 rc; #if defined(UNTRUST) if( INVALID_HASH(pHash) ){ return SXERR_CORRUPT; } #endif pEntry = HashGetEntry(&(*pHash),pKey,nKeyLen); if( pEntry == 0 ){ return SXERR_NOTFOUND; } rc = HashDeleteEntry(&(*pHash),pEntry,ppUserData); return rc; } PH7_PRIVATE sxi32 SyHashDeleteEntry2(SyHashEntry *pEntry) { SyHashEntry_Pr *pPtr = (SyHashEntry_Pr *)pEntry; sxi32 rc; #if defined(UNTRUST) if( pPtr == 0 || INVALID_HASH(pPtr->pHash) ){ return SXERR_CORRUPT; } #endif rc = HashDeleteEntry(pPtr->pHash,pPtr,0); return rc; } PH7_PRIVATE sxi32 SyHashResetLoopCursor(SyHash *pHash) { #if defined(UNTRUST) if( INVALID_HASH(pHash) ){ return SXERR_CORRUPT; } #endif pHash->pCurrent = pHash->pList; return SXRET_OK; } PH7_PRIVATE SyHashEntry * SyHashGetNextEntry(SyHash *pHash) { SyHashEntry_Pr *pEntry; #if defined(UNTRUST) if( INVALID_HASH(pHash) ){ return 0; } #endif if( pHash->pCurrent == 0 || pHash->nEntry <= 0 ){ pHash->pCurrent = pHash->pList; return 0; } pEntry = pHash->pCurrent; /* Advance the cursor */ pHash->pCurrent = pEntry->pNext; /* Return the current entry */ return (SyHashEntry *)pEntry; } PH7_PRIVATE sxi32 SyHashForEach(SyHash *pHash,sxi32 (*xStep)(SyHashEntry *,void *),void *pUserData) { SyHashEntry_Pr *pEntry; sxi32 rc; sxu32 n; #if defined(UNTRUST) if( INVALID_HASH(pHash) || xStep == 0){ return 0; } #endif pEntry = pHash->pList; for( n = 0 ; n < pHash->nEntry ; n++ ){ /* Invoke the callback */ rc = xStep((SyHashEntry *)pEntry,pUserData); if( rc != SXRET_OK ){ return rc; } /* Point to the next entry */ pEntry = pEntry->pNext; } return SXRET_OK; } static sxi32 HashGrowTable(SyHash *pHash) { sxu32 nNewSize = pHash->nBucketSize * 2; SyHashEntry_Pr *pEntry; SyHashEntry_Pr **apNew; sxu32 n,iBucket; /* Allocate a new larger table */ apNew = (SyHashEntry_Pr **)SyMemBackendAlloc(pHash->pAllocator,nNewSize * sizeof(SyHashEntry_Pr *)); if( apNew == 0 ){ /* Not so fatal,simply a performance hit */ return SXRET_OK; } /* Zero the new table */ SyZero((void *)apNew,nNewSize * sizeof(SyHashEntry_Pr *)); /* Rehash all entries */ for( n = 0,pEntry = pHash->pList; n < pHash->nEntry ; n++ ){ pEntry->pNextCollide = pEntry->pPrevCollide = 0; /* Install in the new bucket */ iBucket = pEntry->nHash & (nNewSize - 1); pEntry->pNextCollide = apNew[iBucket]; if( apNew[iBucket] != 0 ){ apNew[iBucket]->pPrevCollide = pEntry; } apNew[iBucket] = pEntry; /* Point to the next entry */ pEntry = pEntry->pNext; } /* Release the old table and reflect the change */ SyMemBackendFree(pHash->pAllocator,(void *)pHash->apBucket); pHash->apBucket = apNew; pHash->nBucketSize = nNewSize; return SXRET_OK; } static sxi32 HashInsert(SyHash *pHash,SyHashEntry_Pr *pEntry) { sxu32 iBucket = pEntry->nHash & (pHash->nBucketSize - 1); /* Insert the entry in its corresponding bcuket */ pEntry->pNextCollide = pHash->apBucket[iBucket]; if( pHash->apBucket[iBucket] != 0 ){ pHash->apBucket[iBucket]->pPrevCollide = pEntry; } pHash->apBucket[iBucket] = pEntry; /* Link to the entry list */ MACRO_LD_PUSH(pHash->pList,pEntry); if( pHash->nEntry == 0 ){ pHash->pCurrent = pHash->pList; } pHash->nEntry++; return SXRET_OK; } PH7_PRIVATE sxi32 SyHashInsert(SyHash *pHash,const void *pKey,sxu32 nKeyLen,void *pUserData) { SyHashEntry_Pr *pEntry; sxi32 rc; #if defined(UNTRUST) if( INVALID_HASH(pHash) || pKey == 0 ){ return SXERR_CORRUPT; } #endif if( pHash->nEntry >= pHash->nBucketSize * SXHASH_FILL_FACTOR ){ rc = HashGrowTable(&(*pHash)); if( rc != SXRET_OK ){ return rc; } } /* Allocate a new hash entry */ pEntry = (SyHashEntry_Pr *)SyMemBackendPoolAlloc(pHash->pAllocator,sizeof(SyHashEntry_Pr)); if( pEntry == 0 ){ return SXERR_MEM; } /* Zero the entry */ SyZero(pEntry,sizeof(SyHashEntry_Pr)); pEntry->pHash = pHash; pEntry->pKey = pKey; pEntry->nKeyLen = nKeyLen; pEntry->pUserData = pUserData; pEntry->nHash = pHash->xHash(pEntry->pKey,pEntry->nKeyLen); /* Finally insert the entry in its corresponding bucket */ rc = HashInsert(&(*pHash),pEntry); return rc; } PH7_PRIVATE SyHashEntry * SyHashLastEntry(SyHash *pHash) { #if defined(UNTRUST) if( INVALID_HASH(pHash) ){ return 0; } #endif /* Last inserted entry */ return (SyHashEntry *)pHash->pList; } /* SyRunTimeApi:sxutils.c */ PH7_PRIVATE sxi32 SyStrIsNumeric(const char *zSrc,sxu32 nLen,sxu8 *pReal,const char **pzTail) { const char *zCur,*zEnd; #ifdef UNTRUST if( SX_EMPTY_STR(zSrc) ){ return SXERR_EMPTY; } #endif zEnd = &zSrc[nLen]; /* Jump leading white spaces */ while( zSrc < zEnd && (unsigned char)zSrc[0] < 0xc0 && SyisSpace(zSrc[0]) ){ zSrc++; } if( zSrc < zEnd && (zSrc[0] == '+' || zSrc[0] == '-') ){ zSrc++; } zCur = zSrc; if( pReal ){ *pReal = FALSE; } for(;;){ if( zSrc >= zEnd || (unsigned char)zSrc[0] >= 0xc0 || !SyisDigit(zSrc[0]) ){ break; } zSrc++; if( zSrc >= zEnd || (unsigned char)zSrc[0] >= 0xc0 || !SyisDigit(zSrc[0]) ){ break; } zSrc++; if( zSrc >= zEnd || (unsigned char)zSrc[0] >= 0xc0 || !SyisDigit(zSrc[0]) ){ break; } zSrc++; if( zSrc >= zEnd || (unsigned char)zSrc[0] >= 0xc0 || !SyisDigit(zSrc[0]) ){ break; } zSrc++; }; if( zSrc < zEnd && zSrc > zCur ){ int c = zSrc[0]; if( c == '.' ){ zSrc++; if( pReal ){ *pReal = TRUE; } if( pzTail ){ while( zSrc < zEnd && (unsigned char)zSrc[0] < 0xc0 && SyisDigit(zSrc[0]) ){ zSrc++; } if( zSrc < zEnd && (zSrc[0] == 'e' || zSrc[0] == 'E') ){ zSrc++; if( zSrc < zEnd && (zSrc[0] == '+' || zSrc[0] == '-') ){ zSrc++; } while( zSrc < zEnd && (unsigned char)zSrc[0] < 0xc0 && SyisDigit(zSrc[0]) ){ zSrc++; } } } }else if( c == 'e' || c == 'E' ){ zSrc++; if( pReal ){ *pReal = TRUE; } if( pzTail ){ if( zSrc < zEnd && (zSrc[0] == '+' || zSrc[0] == '-') ){ zSrc++; } while( zSrc < zEnd && (unsigned char)zSrc[0] < 0xc0 && SyisDigit(zSrc[0]) ){ zSrc++; } } } } if( pzTail ){ /* Point to the non numeric part */ *pzTail = zSrc; } return zSrc > zCur ? SXRET_OK /* String prefix is numeric */ : SXERR_INVALID /* Not a digit stream */; } #define SXINT32_MIN_STR "2147483648" #define SXINT32_MAX_STR "2147483647" #define SXINT64_MIN_STR "9223372036854775808" #define SXINT64_MAX_STR "9223372036854775807" PH7_PRIVATE sxi32 SyStrToInt32(const char *zSrc,sxu32 nLen,void * pOutVal,const char **zRest) { int isNeg = FALSE; const char *zEnd; sxi32 nVal = 0; sxi16 i; #if defined(UNTRUST) if( SX_EMPTY_STR(zSrc) ){ if( pOutVal ){ *(sxi32 *)pOutVal = 0; } return SXERR_EMPTY; } #endif zEnd = &zSrc[nLen]; while(zSrc < zEnd && SyisSpace(zSrc[0]) ){ zSrc++; } if( zSrc < zEnd && ( zSrc[0] == '-' || zSrc[0] == '+' ) ){ isNeg = (zSrc[0] == '-') ? TRUE :FALSE; zSrc++; } /* Skip leading zero */ while(zSrc < zEnd && zSrc[0] == '0' ){ zSrc++; } i = 10; if( (sxu32)(zEnd-zSrc) >= 10 ){ /* Handle overflow */ i = SyMemcmp(zSrc,(isNeg == TRUE) ? SXINT32_MIN_STR : SXINT32_MAX_STR,nLen) <= 0 ? 10 : 9; } for(;;){ if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++; if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++; if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++; if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++; } /* Skip trailing spaces */ while(zSrc < zEnd && SyisSpace(zSrc[0])){ zSrc++; } if( zRest ){ *zRest = (char *)zSrc; } if( pOutVal ){ if( isNeg == TRUE && nVal != 0 ){ nVal = -nVal; } *(sxi32 *)pOutVal = nVal; } return (zSrc >= zEnd) ? SXRET_OK : SXERR_SYNTAX; } PH7_PRIVATE sxi32 SyStrToInt64(const char *zSrc,sxu32 nLen,void * pOutVal,const char **zRest) { int isNeg = FALSE; const char *zEnd; sxi64 nVal; sxi16 i; #if defined(UNTRUST) if( SX_EMPTY_STR(zSrc) ){ if( pOutVal ){ *(sxi32 *)pOutVal = 0; } return SXERR_EMPTY; } #endif zEnd = &zSrc[nLen]; while(zSrc < zEnd && SyisSpace(zSrc[0]) ){ zSrc++; } if( zSrc < zEnd && ( zSrc[0] == '-' || zSrc[0] == '+' ) ){ isNeg = (zSrc[0] == '-') ? TRUE :FALSE; zSrc++; } /* Skip leading zero */ while(zSrc < zEnd && zSrc[0] == '0' ){ zSrc++; } i = 19; if( (sxu32)(zEnd-zSrc) >= 19 ){ i = SyMemcmp(zSrc,isNeg ? SXINT64_MIN_STR : SXINT64_MAX_STR,19) <= 0 ? 19 : 18 ; } nVal = 0; for(;;){ if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++; if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++; if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++; if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++; } /* Skip trailing spaces */ while(zSrc < zEnd && SyisSpace(zSrc[0])){ zSrc++; } if( zRest ){ *zRest = (char *)zSrc; } if( pOutVal ){ if( isNeg == TRUE && nVal != 0 ){ nVal = -nVal; } *(sxi64 *)pOutVal = nVal; } return (zSrc >= zEnd) ? SXRET_OK : SXERR_SYNTAX; } PH7_PRIVATE sxi32 SyHexToint(sxi32 c) { switch(c){ case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case 'A': case 'a': return 10; case 'B': case 'b': return 11; case 'C': case 'c': return 12; case 'D': case 'd': return 13; case 'E': case 'e': return 14; case 'F': case 'f': return 15; } return -1; } PH7_PRIVATE sxi32 SyHexStrToInt64(const char *zSrc,sxu32 nLen,void * pOutVal,const char **zRest) { const char *zIn,*zEnd; int isNeg = FALSE; sxi64 nVal = 0; #if defined(UNTRUST) if( SX_EMPTY_STR(zSrc) ){ if( pOutVal ){ *(sxi32 *)pOutVal = 0; } return SXERR_EMPTY; } #endif zEnd = &zSrc[nLen]; while( zSrc < zEnd && SyisSpace(zSrc[0]) ){ zSrc++; } if( zSrc < zEnd && ( *zSrc == '-' || *zSrc == '+' ) ){ isNeg = (zSrc[0] == '-') ? TRUE :FALSE; zSrc++; } if( zSrc < &zEnd[-2] && zSrc[0] == '0' && (zSrc[1] == 'x' || zSrc[1] == 'X') ){ /* Bypass hex prefix */ zSrc += sizeof(char) * 2; } /* Skip leading zero */ while(zSrc < zEnd && zSrc[0] == '0' ){ zSrc++; } zIn = zSrc; for(;;){ if(zSrc >= zEnd || !SyisHex(zSrc[0]) || (int)(zSrc-zIn) > 15) break; nVal = nVal * 16 + SyHexToint(zSrc[0]); zSrc++ ; if(zSrc >= zEnd || !SyisHex(zSrc[0]) || (int)(zSrc-zIn) > 15) break; nVal = nVal * 16 + SyHexToint(zSrc[0]); zSrc++ ; if(zSrc >= zEnd || !SyisHex(zSrc[0]) || (int)(zSrc-zIn) > 15) break; nVal = nVal * 16 + SyHexToint(zSrc[0]); zSrc++ ; if(zSrc >= zEnd || !SyisHex(zSrc[0]) || (int)(zSrc-zIn) > 15) break; nVal = nVal * 16 + SyHexToint(zSrc[0]); zSrc++ ; } while( zSrc < zEnd && SyisSpace(zSrc[0]) ){ zSrc++; } if( zRest ){ *zRest = zSrc; } if( pOutVal ){ if( isNeg == TRUE && nVal != 0 ){ nVal = -nVal; } *(sxi64 *)pOutVal = nVal; } return zSrc >= zEnd ? SXRET_OK : SXERR_SYNTAX; } PH7_PRIVATE sxi32 SyOctalStrToInt64(const char *zSrc,sxu32 nLen,void * pOutVal,const char **zRest) { const char *zIn,*zEnd; int isNeg = FALSE; sxi64 nVal = 0; int c; #if defined(UNTRUST) if( SX_EMPTY_STR(zSrc) ){ if( pOutVal ){ *(sxi32 *)pOutVal = 0; } return SXERR_EMPTY; } #endif zEnd = &zSrc[nLen]; while(zSrc < zEnd && SyisSpace(zSrc[0]) ){ zSrc++; } if( zSrc < zEnd && ( zSrc[0] == '-' || zSrc[0] == '+' ) ){ isNeg = (zSrc[0] == '-') ? TRUE :FALSE; zSrc++; } /* Skip leading zero */ while(zSrc < zEnd && zSrc[0] == '0' ){ zSrc++; } zIn = zSrc; for(;;){ if(zSrc >= zEnd || !SyisDigit(zSrc[0])){ break; } if( (c=zSrc[0]-'0') > 7 || (int)(zSrc-zIn) > 20){ break;} nVal = nVal * 8 + c; zSrc++; if(zSrc >= zEnd || !SyisDigit(zSrc[0])){ break; } if( (c=zSrc[0]-'0') > 7 || (int)(zSrc-zIn) > 20){ break;} nVal = nVal * 8 + c; zSrc++; if(zSrc >= zEnd || !SyisDigit(zSrc[0])){ break; } if( (c=zSrc[0]-'0') > 7 || (int)(zSrc-zIn) > 20){ break;} nVal = nVal * 8 + c; zSrc++; if(zSrc >= zEnd || !SyisDigit(zSrc[0])){ break; } if( (c=zSrc[0]-'0') > 7 || (int)(zSrc-zIn) > 20){ break;} nVal = nVal * 8 + c; zSrc++; } /* Skip trailing spaces */ while(zSrc < zEnd && SyisSpace(zSrc[0])){ zSrc++; } if( zRest ){ *zRest = zSrc; } if( pOutVal ){ if( isNeg == TRUE && nVal != 0 ){ nVal = -nVal; } *(sxi64 *)pOutVal = nVal; } return (zSrc >= zEnd) ? SXRET_OK : SXERR_SYNTAX; } PH7_PRIVATE sxi32 SyBinaryStrToInt64(const char *zSrc,sxu32 nLen,void * pOutVal,const char **zRest) { const char *zIn,*zEnd; int isNeg = FALSE; sxi64 nVal = 0; int c; #if defined(UNTRUST) if( SX_EMPTY_STR(zSrc) ){ if( pOutVal ){ *(sxi32 *)pOutVal = 0; } return SXERR_EMPTY; } #endif zEnd = &zSrc[nLen]; while(zSrc < zEnd && SyisSpace(zSrc[0]) ){ zSrc++; } if( zSrc < zEnd && ( zSrc[0] == '-' || zSrc[0] == '+' ) ){ isNeg = (zSrc[0] == '-') ? TRUE :FALSE; zSrc++; } if( zSrc < &zEnd[-2] && zSrc[0] == '0' && (zSrc[1] == 'b' || zSrc[1] == 'B') ){ /* Bypass binary prefix */ zSrc += sizeof(char) * 2; } /* Skip leading zero */ while(zSrc < zEnd && zSrc[0] == '0' ){ zSrc++; } zIn = zSrc; for(;;){ if(zSrc >= zEnd || (zSrc[0] != '1' && zSrc[0] != '0') || (int)(zSrc-zIn) > 62){ break; } c = zSrc[0] - '0'; nVal = (nVal << 1) + c; zSrc++; if(zSrc >= zEnd || (zSrc[0] != '1' && zSrc[0] != '0') || (int)(zSrc-zIn) > 62){ break; } c = zSrc[0] - '0'; nVal = (nVal << 1) + c; zSrc++; if(zSrc >= zEnd || (zSrc[0] != '1' && zSrc[0] != '0') || (int)(zSrc-zIn) > 62){ break; } c = zSrc[0] - '0'; nVal = (nVal << 1) + c; zSrc++; if(zSrc >= zEnd || (zSrc[0] != '1' && zSrc[0] != '0') || (int)(zSrc-zIn) > 62){ break; } c = zSrc[0] - '0'; nVal = (nVal << 1) + c; zSrc++; } /* Skip trailing spaces */ while(zSrc < zEnd && SyisSpace(zSrc[0])){ zSrc++; } if( zRest ){ *zRest = zSrc; } if( pOutVal ){ if( isNeg == TRUE && nVal != 0 ){ nVal = -nVal; } *(sxi64 *)pOutVal = nVal; } return (zSrc >= zEnd) ? SXRET_OK : SXERR_SYNTAX; } PH7_PRIVATE sxi32 SyStrToReal(const char *zSrc,sxu32 nLen,void * pOutVal,const char **zRest) { #define SXDBL_DIG 15 #define SXDBL_MAX_EXP 308 #define SXDBL_MIN_EXP_PLUS 307 static const sxreal aTab[] = { 10, 1.0e2, 1.0e4, 1.0e8, 1.0e16, 1.0e32, 1.0e64, 1.0e128, 1.0e256 }; sxu8 neg = FALSE; sxreal Val = 0.0; const char *zEnd; sxi32 Lim,exp; sxreal *p = 0; #ifdef UNTRUST if( SX_EMPTY_STR(zSrc) ){ if( pOutVal ){ *(sxreal *)pOutVal = 0.0; } return SXERR_EMPTY; } #endif zEnd = &zSrc[nLen]; while( zSrc < zEnd && SyisSpace(zSrc[0]) ){ zSrc++; } if( zSrc < zEnd && (zSrc[0] == '-' || zSrc[0] == '+' ) ){ neg = zSrc[0] == '-' ? TRUE : FALSE ; zSrc++; } Lim = SXDBL_DIG ; for(;;){ if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; zSrc++ ; --Lim; if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; zSrc++ ; --Lim; if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; zSrc++ ; --Lim; if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; zSrc++ ; --Lim; } if( zSrc < zEnd && ( zSrc[0] == '.' || zSrc[0] == ',' ) ){ sxreal dec = 1.0; zSrc++; for(;;){ if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; dec *= 10.0; zSrc++ ;--Lim; if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; dec *= 10.0; zSrc++ ;--Lim; if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; dec *= 10.0; zSrc++ ;--Lim; if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; dec *= 10.0; zSrc++ ;--Lim; } Val /= dec; } if( neg == TRUE && Val != 0.0 ) { Val = -Val ; } if( Lim <= 0 ){ /* jump overflow digit */ while( zSrc < zEnd ){ if( zSrc[0] == 'e' || zSrc[0] == 'E' ){ break; } zSrc++; } } neg = FALSE; if( zSrc < zEnd && ( zSrc[0] == 'e' || zSrc[0] == 'E' ) ){ zSrc++; if( zSrc < zEnd && ( zSrc[0] == '-' || zSrc[0] == '+') ){ neg = zSrc[0] == '-' ? TRUE : FALSE ; zSrc++; } exp = 0; while( zSrc < zEnd && SyisDigit(zSrc[0]) && exp < SXDBL_MAX_EXP ){ exp = exp * 10 + (zSrc[0] - '0'); zSrc++; } if( neg ){ if( exp > SXDBL_MIN_EXP_PLUS ) exp = SXDBL_MIN_EXP_PLUS ; }else if ( exp > SXDBL_MAX_EXP ){ exp = SXDBL_MAX_EXP; } for( p = (sxreal *)aTab ; exp ; exp >>= 1 , p++ ){ if( exp & 01 ){ if( neg ){ Val /= *p ; }else{ Val *= *p; } } } } while( zSrc < zEnd && SyisSpace(zSrc[0]) ){ zSrc++; } if( zRest ){ *zRest = zSrc; } if( pOutVal ){ *(sxreal *)pOutVal = Val; } return zSrc >= zEnd ? SXRET_OK : SXERR_SYNTAX; } /* SyRunTimeApi:sxlib.c */ static sxu32 SyBinHash(const void *pSrc,sxu32 nLen) { register unsigned char *zIn = (unsigned char *)pSrc; unsigned char *zEnd; sxu32 nH = 5381; zEnd = &zIn[nLen]; for(;;){ if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++; if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++; if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++; if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++; } return nH; } PH7_PRIVATE sxu32 SyStrHash(const void *pSrc,sxu32 nLen) { register unsigned char *zIn = (unsigned char *)pSrc; unsigned char *zEnd; sxu32 nH = 5381; zEnd = &zIn[nLen]; for(;;){ if( zIn >= zEnd ){ break; } nH = nH * 33 + SyToLower(zIn[0]); zIn++; if( zIn >= zEnd ){ break; } nH = nH * 33 + SyToLower(zIn[0]); zIn++; if( zIn >= zEnd ){ break; } nH = nH * 33 + SyToLower(zIn[0]); zIn++; if( zIn >= zEnd ){ break; } nH = nH * 33 + SyToLower(zIn[0]); zIn++; } return nH; } #ifndef PH7_DISABLE_BUILTIN_FUNC PH7_PRIVATE sxi32 SyBase64Encode(const char *zSrc,sxu32 nLen,ProcConsumer xConsumer,void *pUserData) { static const unsigned char zBase64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; unsigned char *zIn = (unsigned char *)zSrc; unsigned char z64[4]; sxu32 i; sxi32 rc; #if defined(UNTRUST) if( SX_EMPTY_STR(zSrc) || xConsumer == 0){ return SXERR_EMPTY; } #endif for(i = 0; i + 2 < nLen; i += 3){ z64[0] = zBase64[(zIn[i] >> 2) & 0x3F]; z64[1] = zBase64[( ((zIn[i] & 0x03) << 4) | (zIn[i+1] >> 4)) & 0x3F]; z64[2] = zBase64[( ((zIn[i+1] & 0x0F) << 2) | (zIn[i + 2] >> 6) ) & 0x3F]; z64[3] = zBase64[ zIn[i + 2] & 0x3F]; rc = xConsumer((const void *)z64,sizeof(z64),pUserData); if( rc != SXRET_OK ){return SXERR_ABORT;} } if ( i+1 < nLen ){ z64[0] = zBase64[(zIn[i] >> 2) & 0x3F]; z64[1] = zBase64[( ((zIn[i] & 0x03) << 4) | (zIn[i+1] >> 4)) & 0x3F]; z64[2] = zBase64[(zIn[i+1] & 0x0F) << 2 ]; z64[3] = '='; rc = xConsumer((const void *)z64,sizeof(z64),pUserData); if( rc != SXRET_OK ){return SXERR_ABORT;} }else if( i < nLen ){ z64[0] = zBase64[(zIn[i] >> 2) & 0x3F]; z64[1] = zBase64[(zIn[i] & 0x03) << 4]; z64[2] = '='; z64[3] = '='; rc = xConsumer((const void *)z64,sizeof(z64),pUserData); if( rc != SXRET_OK ){return SXERR_ABORT;} } return SXRET_OK; } PH7_PRIVATE sxi32 SyBase64Decode(const char *zB64,sxu32 nLen,ProcConsumer xConsumer,void *pUserData) { static const sxu32 aBase64Trans[] = { 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, 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, 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, 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, 0,0,0 }; sxu32 n,w,x,y,z; sxi32 rc; unsigned char zOut[10]; #if defined(UNTRUST) if( SX_EMPTY_STR(zB64) || xConsumer == 0 ){ return SXERR_EMPTY; } #endif while(nLen > 0 && zB64[nLen - 1] == '=' ){ nLen--; } for( n = 0 ; n+3>4) & 0x03); zOut[1] = ((x<<4) & 0xF0) | ((y>>2) & 0x0F); zOut[2] = ((y<<6) & 0xC0) | (z & 0x3F); rc = xConsumer((const void *)zOut,sizeof(unsigned char)*3,pUserData); if( rc != SXRET_OK ){ return SXERR_ABORT;} } if( n+2 < nLen ){ w = aBase64Trans[zB64[n] & 0x7F]; x = aBase64Trans[zB64[n+1] & 0x7F]; y = aBase64Trans[zB64[n+2] & 0x7F]; zOut[0] = ((w<<2) & 0xFC) | ((x>>4) & 0x03); zOut[1] = ((x<<4) & 0xF0) | ((y>>2) & 0x0F); rc = xConsumer((const void *)zOut,sizeof(unsigned char)*2,pUserData); if( rc != SXRET_OK ){ return SXERR_ABORT;} }else if( n+1 < nLen ){ w = aBase64Trans[zB64[n] & 0x7F]; x = aBase64Trans[zB64[n+1] & 0x7F]; zOut[0] = ((w<<2) & 0xFC) | ((x>>4) & 0x03); rc = xConsumer((const void *)zOut,sizeof(unsigned char)*1,pUserData); if( rc != SXRET_OK ){ return SXERR_ABORT;} } return SXRET_OK; } #endif /* PH7_DISABLE_BUILTIN_FUNC */ #define INVALID_LEXER(LEX) ( LEX == 0 || LEX->xTokenizer == 0 ) PH7_PRIVATE sxi32 SyLexInit(SyLex *pLex,SySet *pSet,ProcTokenizer xTokenizer,void *pUserData) { SyStream *pStream; #if defined (UNTRUST) if ( pLex == 0 || xTokenizer == 0 ){ return SXERR_CORRUPT; } #endif pLex->pTokenSet = 0; /* Initialize lexer fields */ if( pSet ){ if ( SySetElemSize(pSet) != sizeof(SyToken) ){ return SXERR_INVALID; } pLex->pTokenSet = pSet; } pStream = &pLex->sStream; pLex->xTokenizer = xTokenizer; pLex->pUserData = pUserData; pStream->nLine = 1; pStream->nIgn = 0; pStream->zText = pStream->zEnd = 0; pStream->pSet = pSet; return SXRET_OK; } PH7_PRIVATE sxi32 SyLexTokenizeInput(SyLex *pLex,const char *zInput,sxu32 nLen,void *pCtxData,ProcSort xSort,ProcCmp xCmp) { const unsigned char *zCur; SyStream *pStream; SyToken sToken; sxi32 rc; #if defined (UNTRUST) if ( INVALID_LEXER(pLex) || zInput == 0 ){ return SXERR_CORRUPT; } #endif pStream = &pLex->sStream; /* Point to the head of the input */ pStream->zText = pStream->zInput = (const unsigned char *)zInput; /* Point to the end of the input */ pStream->zEnd = &pStream->zInput[nLen]; for(;;){ if( pStream->zText >= pStream->zEnd ){ /* End of the input reached */ break; } zCur = pStream->zText; /* Call the tokenizer callback */ rc = pLex->xTokenizer(pStream,&sToken,pLex->pUserData,pCtxData); if( rc != SXRET_OK && rc != SXERR_CONTINUE ){ /* Tokenizer callback request an operation abort */ if( rc == SXERR_ABORT ){ return SXERR_ABORT; } break; } if( rc == SXERR_CONTINUE ){ /* Request to ignore this token */ pStream->nIgn++; }else if( pLex->pTokenSet ){ /* Put the token in the set */ rc = SySetPut(pLex->pTokenSet,(const void *)&sToken); if( rc != SXRET_OK ){ break; } } if( zCur >= pStream->zText ){ /* Automatic advance of the stream cursor */ pStream->zText = &zCur[1]; } } if( xSort && pLex->pTokenSet ){ SyToken *aToken = (SyToken *)SySetBasePtr(pLex->pTokenSet); /* Sort the extrated tokens */ if( xCmp == 0 ){ /* Use a default comparison function */ xCmp = SyMemcmp; } xSort(aToken,SySetUsed(pLex->pTokenSet),sizeof(SyToken),xCmp); } return SXRET_OK; } PH7_PRIVATE sxi32 SyLexRelease(SyLex *pLex) { sxi32 rc = SXRET_OK; #if defined (UNTRUST) if ( INVALID_LEXER(pLex) ){ return SXERR_CORRUPT; } #else SXUNUSED(pLex); /* Prevent compiler warning */ #endif return rc; } #ifndef PH7_DISABLE_BUILTIN_FUNC #define SAFE_HTTP(C) (SyisAlphaNum(c) || c == '_' || c == '-' || c == '$' || c == '.' ) PH7_PRIVATE sxi32 SyUriEncode(const char *zSrc,sxu32 nLen,ProcConsumer xConsumer,void *pUserData) { unsigned char *zIn = (unsigned char *)zSrc; unsigned char zHex[3] = { '%',0,0 }; unsigned char zOut[2]; unsigned char *zCur,*zEnd; sxi32 c; sxi32 rc; #ifdef UNTRUST if( SX_EMPTY_STR(zSrc) || xConsumer == 0 ){ return SXERR_EMPTY; } #endif rc = SXRET_OK; zEnd = &zIn[nLen]; zCur = zIn; for(;;){ if( zCur >= zEnd ){ if( zCur != zIn ){ rc = xConsumer(zIn,(sxu32)(zCur-zIn),pUserData); } break; } c = zCur[0]; if( SAFE_HTTP(c) ){ zCur++; continue; } if( zCur != zIn && SXRET_OK != (rc = xConsumer(zIn,(sxu32)(zCur-zIn),pUserData))){ break; } if( c == ' ' ){ zOut[0] = '+'; rc = xConsumer((const void *)zOut,sizeof(unsigned char),pUserData); }else{ zHex[1] = "0123456789ABCDEF"[(c >> 4) & 0x0F]; zHex[2] = "0123456789ABCDEF"[c & 0x0F]; rc = xConsumer(zHex,sizeof(zHex),pUserData); } if( SXRET_OK != rc ){ break; } zIn = &zCur[1]; zCur = zIn ; } return rc == SXRET_OK ? SXRET_OK : SXERR_ABORT; } #endif /* PH7_DISABLE_BUILTIN_FUNC */ static sxi32 SyAsciiToHex(sxi32 c) { if( c >= 'a' && c <= 'f' ){ c += 10 - 'a'; return c; } if( c >= '0' && c <= '9' ){ c -= '0'; return c; } if( c >= 'A' && c <= 'F') { c += 10 - 'A'; return c; } return 0; } PH7_PRIVATE sxi32 SyUriDecode(const char *zSrc,sxu32 nLen,ProcConsumer xConsumer,void *pUserData,int bUTF8) { static const sxu8 Utf8Trans[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00 }; const char *zIn = zSrc; const char *zEnd; const char *zCur; sxu8 *zOutPtr; sxu8 zOut[10]; sxi32 c,d; sxi32 rc; #if defined(UNTRUST) if( SX_EMPTY_STR(zSrc) || xConsumer == 0 ){ return SXERR_EMPTY; } #endif rc = SXRET_OK; zEnd = &zSrc[nLen]; zCur = zIn; for(;;){ while(zCur < zEnd && zCur[0] != '%' && zCur[0] != '+' ){ zCur++; } if( zCur != zIn ){ /* Consume input */ rc = xConsumer(zIn,(unsigned int)(zCur-zIn),pUserData); if( rc != SXRET_OK ){ /* User consumer routine request an operation abort */ break; } } if( zCur >= zEnd ){ rc = SXRET_OK; break; } /* Decode unsafe HTTP characters */ zOutPtr = zOut; if( zCur[0] == '+' ){ *zOutPtr++ = ' '; zCur++; }else{ if( &zCur[2] >= zEnd ){ rc = SXERR_OVERFLOW; break; } c = (SyAsciiToHex(zCur[1]) <<4) | SyAsciiToHex(zCur[2]); zCur += 3; if( c < 0x000C0 ){ *zOutPtr++ = (sxu8)c; }else{ c = Utf8Trans[c-0xC0]; while( zCur[0] == '%' ){ d = (SyAsciiToHex(zCur[1]) <<4) | SyAsciiToHex(zCur[2]); if( (d&0xC0) != 0x80 ){ break; } c = (c<<6) + (0x3f & d); zCur += 3; } if( bUTF8 == FALSE ){ *zOutPtr++ = (sxu8)c; }else{ SX_WRITE_UTF8(zOutPtr,c); } } } /* Consume the decoded characters */ rc = xConsumer((const void *)zOut,(unsigned int)(zOutPtr-zOut),pUserData); if( rc != SXRET_OK ){ break; } /* Synchronize pointers */ zIn = zCur; } return rc; } #ifndef PH7_DISABLE_BUILTIN_FUNC static const char *zEngDay[] = { "Sunday","Monday","Tuesday","Wednesday", "Thursday","Friday","Saturday" }; static const char *zEngMonth[] = { "January","February","March","April", "May","June","July","August", "September","October","November","December" }; static const char * GetDay(sxi32 i) { return zEngDay[ i % 7 ]; } static const char * GetMonth(sxi32 i) { return zEngMonth[ i % 12 ]; } PH7_PRIVATE const char * SyTimeGetDay(sxi32 iDay) { return GetDay(iDay); } PH7_PRIVATE const char * SyTimeGetMonth(sxi32 iMonth) { return GetMonth(iMonth); } #endif /* PH7_DISABLE_BUILTIN_FUNC */ /* SyRunTimeApi: sxfmt.c */ #define SXFMT_BUFSIZ 1024 /* Conversion buffer size */ /* ** Conversion types fall into various categories as defined by the ** following enumeration. */ #define SXFMT_RADIX 1 /* Integer types.%d, %x, %o, and so forth */ #define SXFMT_FLOAT 2 /* Floating point.%f */ #define SXFMT_EXP 3 /* Exponentional notation.%e and %E */ #define SXFMT_GENERIC 4 /* Floating or exponential, depending on exponent.%g */ #define SXFMT_SIZE 5 /* Total number of characters processed so far.%n */ #define SXFMT_STRING 6 /* Strings.%s */ #define SXFMT_PERCENT 7 /* Percent symbol.%% */ #define SXFMT_CHARX 8 /* Characters.%c */ #define SXFMT_ERROR 9 /* Used to indicate no such conversion type */ /* Extension by Symisc Systems */ #define SXFMT_RAWSTR 13 /* %z Pointer to raw string (SyString *) */ #define SXFMT_UNUSED 15 /* ** Allowed values for SyFmtInfo.flags */ #define SXFLAG_SIGNED 0x01 #define SXFLAG_UNSIGNED 0x02 /* Allowed values for SyFmtConsumer.nType */ #define SXFMT_CONS_PROC 1 /* Consumer is a procedure */ #define SXFMT_CONS_STR 2 /* Consumer is a managed string */ #define SXFMT_CONS_FILE 5 /* Consumer is an open File */ #define SXFMT_CONS_BLOB 6 /* Consumer is a BLOB */ /* ** Each builtin conversion character (ex: the 'd' in "%d") is described ** by an instance of the following structure */ typedef struct SyFmtInfo SyFmtInfo; struct SyFmtInfo { char fmttype; /* The format field code letter [i.e: 'd','s','x'] */ sxu8 base; /* The base for radix conversion */ int flags; /* One or more of SXFLAG_ constants below */ sxu8 type; /* Conversion paradigm */ const char *charset; /* The character set for conversion */ const char *prefix; /* Prefix on non-zero values in alt format */ }; typedef struct SyFmtConsumer SyFmtConsumer; struct SyFmtConsumer { sxu32 nLen; /* Total output length */ sxi32 nType; /* Type of the consumer see below */ sxi32 rc; /* Consumer return value;Abort processing if rc != SXRET_OK */ union{ struct{ ProcConsumer xUserConsumer; void *pUserData; }sFunc; SyBlob *pBlob; }uConsumer; }; #ifndef SX_OMIT_FLOATINGPOINT static int getdigit(sxlongreal *val,int *cnt) { sxlongreal d; int digit; if( (*cnt)++ >= 16 ){ return '0'; } digit = (int)*val; d = digit; *val = (*val - d)*10.0; return digit + '0' ; } #endif /* SX_OMIT_FLOATINGPOINT */ /* * The following routine was taken from the SQLITE2 source tree and was * extended by Symisc Systems to fit its need. * Status: Public Domain */ static sxi32 InternFormat(ProcConsumer xConsumer,void *pUserData,const char *zFormat,va_list ap) { /* * The following table is searched linearly, so it is good to put the most frequently * used conversion types first. */ static const SyFmtInfo aFmt[] = { { 'd', 10, SXFLAG_SIGNED, SXFMT_RADIX, "0123456789",0 }, { 's', 0, 0, SXFMT_STRING, 0, 0 }, { 'c', 0, 0, SXFMT_CHARX, 0, 0 }, { 'x', 16, 0, SXFMT_RADIX, "0123456789abcdef", "x0" }, { 'X', 16, 0, SXFMT_RADIX, "0123456789ABCDEF", "X0" }, /* -- Extensions by Symisc Systems -- */ { 'z', 0, 0, SXFMT_RAWSTR, 0, 0 }, /* Pointer to a raw string (SyString *) */ { 'B', 2, 0, SXFMT_RADIX, "01", "b0"}, /* -- End of Extensions -- */ { 'o', 8, 0, SXFMT_RADIX, "01234567", "0" }, { 'u', 10, 0, SXFMT_RADIX, "0123456789", 0 }, #ifndef SX_OMIT_FLOATINGPOINT { 'f', 0, SXFLAG_SIGNED, SXFMT_FLOAT, 0, 0 }, { 'e', 0, SXFLAG_SIGNED, SXFMT_EXP, "e", 0 }, { 'E', 0, SXFLAG_SIGNED, SXFMT_EXP, "E", 0 }, { 'g', 0, SXFLAG_SIGNED, SXFMT_GENERIC, "e", 0 }, { 'G', 0, SXFLAG_SIGNED, SXFMT_GENERIC, "E", 0 }, #endif { 'i', 10, SXFLAG_SIGNED, SXFMT_RADIX,"0123456789", 0 }, { 'n', 0, 0, SXFMT_SIZE, 0, 0 }, { '%', 0, 0, SXFMT_PERCENT, 0, 0 }, { 'p', 10, 0, SXFMT_RADIX, "0123456789", 0 } }; int c; /* Next character in the format string */ char *bufpt; /* Pointer to the conversion buffer */ int precision; /* Precision of the current field */ int length; /* Length of the field */ int idx; /* A general purpose loop counter */ int width; /* Width of the current field */ sxu8 flag_leftjustify; /* True if "-" flag is present */ sxu8 flag_plussign; /* True if "+" flag is present */ sxu8 flag_blanksign; /* True if " " flag is present */ sxu8 flag_alternateform; /* True if "#" flag is present */ sxu8 flag_zeropad; /* True if field width constant starts with zero */ sxu8 flag_long; /* True if "l" flag is present */ sxi64 longvalue; /* Value for integer types */ const SyFmtInfo *infop; /* Pointer to the appropriate info structure */ char buf[SXFMT_BUFSIZ]; /* Conversion buffer */ char prefix; /* Prefix character."+" or "-" or " " or '\0'.*/ sxu8 errorflag = 0; /* True if an error is encountered */ sxu8 xtype; /* Conversion paradigm */ char *zExtra; static char spaces[] = " "; #define etSPACESIZE ((int)sizeof(spaces)-1) #ifndef SX_OMIT_FLOATINGPOINT sxlongreal realvalue; /* Value for real types */ int exp; /* exponent of real numbers */ double rounder; /* Used for rounding floating point values */ sxu8 flag_dp; /* True if decimal point should be shown */ sxu8 flag_rtz; /* True if trailing zeros should be removed */ sxu8 flag_exp; /* True to force display of the exponent */ int nsd; /* Number of significant digits returned */ #endif int rc; length = 0; bufpt = 0; for(; (c=(*zFormat))!=0; ++zFormat){ if( c!='%' ){ unsigned int amt; bufpt = (char *)zFormat; amt = 1; while( (c=(*++zFormat))!='%' && c!=0 ) amt++; rc = xConsumer((const void *)bufpt,amt,pUserData); if( rc != SXRET_OK ){ return SXERR_ABORT; /* Consumer routine request an operation abort */ } if( c==0 ){ return errorflag > 0 ? SXERR_FORMAT : SXRET_OK; } } if( (c=(*++zFormat))==0 ){ errorflag = 1; rc = xConsumer("%",sizeof("%")-1,pUserData); if( rc != SXRET_OK ){ return SXERR_ABORT; /* Consumer routine request an operation abort */ } return errorflag > 0 ? SXERR_FORMAT : SXRET_OK; } /* Find out what flags are present */ flag_leftjustify = flag_plussign = flag_blanksign = flag_alternateform = flag_zeropad = 0; do{ switch( c ){ case '-': flag_leftjustify = 1; c = 0; break; case '+': flag_plussign = 1; c = 0; break; case ' ': flag_blanksign = 1; c = 0; break; case '#': flag_alternateform = 1; c = 0; break; case '0': flag_zeropad = 1; c = 0; break; default: break; } }while( c==0 && (c=(*++zFormat))!=0 ); /* Get the field width */ width = 0; if( c=='*' ){ width = va_arg(ap,int); if( width<0 ){ flag_leftjustify = 1; width = -width; } c = *++zFormat; }else{ while( c>='0' && c<='9' ){ width = width*10 + c - '0'; c = *++zFormat; } } if( width > SXFMT_BUFSIZ-10 ){ width = SXFMT_BUFSIZ-10; } /* Get the precision */ precision = -1; if( c=='.' ){ precision = 0; c = *++zFormat; if( c=='*' ){ precision = va_arg(ap,int); if( precision<0 ) precision = -precision; c = *++zFormat; }else{ while( c>='0' && c<='9' ){ precision = precision*10 + c - '0'; c = *++zFormat; } } } /* Get the conversion type modifier */ flag_long = 0; if( c=='l' || c == 'q' /* BSD quad (expect a 64-bit integer) */ ){ flag_long = (c == 'q') ? 2 : 1; c = *++zFormat; if( c == 'l' ){ /* Standard printf emulation 'lld' (expect a 64bit integer) */ flag_long = 2; } } /* Fetch the info entry for the field */ infop = 0; xtype = SXFMT_ERROR; for(idx=0; idx< (int)SX_ARRAYSIZE(aFmt); idx++){ if( c==aFmt[idx].fmttype ){ infop = &aFmt[idx]; xtype = infop->type; break; } } zExtra = 0; /* ** At this point, variables are initialized as follows: ** ** flag_alternateform TRUE if a '#' is present. ** flag_plussign TRUE if a '+' is present. ** flag_leftjustify TRUE if a '-' is present or if the ** field width was negative. ** flag_zeropad TRUE if the width began with 0. ** flag_long TRUE if the letter 'l' (ell) or 'q'(BSD quad) prefixed ** the conversion character. ** flag_blanksign TRUE if a ' ' is present. ** width The specified field width.This is ** always non-negative.Zero is the default. ** precision The specified precision.The default ** is -1. ** xtype The class of the conversion. ** infop Pointer to the appropriate info struct. */ switch( xtype ){ case SXFMT_RADIX: if( flag_long > 0 ){ if( flag_long > 1 ){ /* BSD quad: expect a 64-bit integer */ longvalue = va_arg(ap,sxi64); }else{ longvalue = va_arg(ap,sxlong); } }else{ if( infop->flags & SXFLAG_SIGNED ){ longvalue = va_arg(ap,sxi32); }else{ longvalue = va_arg(ap,sxu32); } } /* Limit the precision to prevent overflowing buf[] during conversion */ if( precision>SXFMT_BUFSIZ-40 ) precision = SXFMT_BUFSIZ-40; #if 1 /* For the format %#x, the value zero is printed "0" not "0x0". ** I think this is stupid.*/ if( longvalue==0 ) flag_alternateform = 0; #else /* More sensible: turn off the prefix for octal (to prevent "00"), ** but leave the prefix for hex.*/ if( longvalue==0 && infop->base==8 ) flag_alternateform = 0; #endif if( infop->flags & SXFLAG_SIGNED ){ if( longvalue<0 ){ longvalue = -longvalue; /* Ticket 1433-003 */ if( longvalue < 0 ){ /* Overflow */ longvalue= SXI64_HIGH; } prefix = '-'; }else if( flag_plussign ) prefix = '+'; else if( flag_blanksign ) prefix = ' '; else prefix = 0; }else{ if( longvalue<0 ){ longvalue = -longvalue; /* Ticket 1433-003 */ if( longvalue < 0 ){ /* Overflow */ longvalue= SXI64_HIGH; } } prefix = 0; } if( flag_zeropad && precisioncharset; base = infop->base; do{ /* Convert to ascii */ *(--bufpt) = cset[longvalue%base]; longvalue = longvalue/base; }while( longvalue>0 ); } length = &buf[SXFMT_BUFSIZ-1]-bufpt; for(idx=precision-length; idx>0; idx--){ *(--bufpt) = '0'; /* Zero pad */ } if( prefix ) *(--bufpt) = prefix; /* Add sign */ if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */ const char *pre; char x; pre = infop->prefix; if( *bufpt!=pre[0] ){ for(pre=infop->prefix; (x=(*pre))!=0; pre++) *(--bufpt) = x; } } length = &buf[SXFMT_BUFSIZ-1]-bufpt; break; case SXFMT_FLOAT: case SXFMT_EXP: case SXFMT_GENERIC: #ifndef SX_OMIT_FLOATINGPOINT realvalue = va_arg(ap,double); if( precision<0 ) precision = 6; /* Set default precision */ if( precision>SXFMT_BUFSIZ-40) precision = SXFMT_BUFSIZ-40; if( realvalue<0.0 ){ realvalue = -realvalue; prefix = '-'; }else{ if( flag_plussign ) prefix = '+'; else if( flag_blanksign ) prefix = ' '; else prefix = 0; } if( infop->type==SXFMT_GENERIC && precision>0 ) precision--; rounder = 0.0; #if 0 /* Rounding works like BSD when the constant 0.4999 is used.Wierd! */ for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1); #else /* It makes more sense to use 0.5 */ for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1); #endif if( infop->type==SXFMT_FLOAT ) realvalue += rounder; /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ exp = 0; if( realvalue>0.0 ){ while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; } while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; } while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; } while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; } if( exp>350 || exp<-350 ){ bufpt = "NaN"; length = 3; break; } } bufpt = buf; /* ** If the field type is etGENERIC, then convert to either etEXP ** or etFLOAT, as appropriate. */ flag_exp = xtype==SXFMT_EXP; if( xtype!=SXFMT_FLOAT ){ realvalue += rounder; if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; } } if( xtype==SXFMT_GENERIC ){ flag_rtz = !flag_alternateform; if( exp<-4 || exp>precision ){ xtype = SXFMT_EXP; }else{ precision = precision - exp; xtype = SXFMT_FLOAT; } }else{ flag_rtz = 0; } /* ** The "exp+precision" test causes output to be of type etEXP if ** the precision is too large to fit in buf[]. */ nsd = 0; if( xtype==SXFMT_FLOAT && exp+precision0 || flag_alternateform); if( prefix ) *(bufpt++) = prefix; /* Sign */ if( exp<0 ) *(bufpt++) = '0'; /* Digits before "." */ else for(; exp>=0; exp--) *(bufpt++) = (char)getdigit(&realvalue,&nsd); if( flag_dp ) *(bufpt++) = '.'; /* The decimal point */ for(exp++; exp<0 && precision>0; precision--, exp++){ *(bufpt++) = '0'; } while( (precision--)>0 ) *(bufpt++) = (char)getdigit(&realvalue,&nsd); *(bufpt--) = 0; /* Null terminate */ if( flag_rtz && flag_dp ){ /* Remove trailing zeros and "." */ while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0; if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0; } bufpt++; /* point to next free slot */ }else{ /* etEXP or etGENERIC */ flag_dp = (precision>0 || flag_alternateform); if( prefix ) *(bufpt++) = prefix; /* Sign */ *(bufpt++) = (char)getdigit(&realvalue,&nsd); /* First digit */ if( flag_dp ) *(bufpt++) = '.'; /* Decimal point */ while( (precision--)>0 ) *(bufpt++) = (char)getdigit(&realvalue,&nsd); bufpt--; /* point to last digit */ if( flag_rtz && flag_dp ){ /* Remove tail zeros */ while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0; if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0; } bufpt++; /* point to next free slot */ if( exp || flag_exp ){ *(bufpt++) = infop->charset[0]; if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; } /* sign of exp */ else { *(bufpt++) = '+'; } if( exp>=100 ){ *(bufpt++) = (char)((exp/100)+'0'); /* 100's digit */ exp %= 100; } *(bufpt++) = (char)(exp/10+'0'); /* 10's digit */ *(bufpt++) = (char)(exp%10+'0'); /* 1's digit */ } } /* The converted number is in buf[] and zero terminated.Output it. ** Note that the number is in the usual order, not reversed as with ** integer conversions.*/ length = bufpt-buf; bufpt = buf; /* Special case: Add leading zeros if the flag_zeropad flag is ** set and we are not left justified */ if( flag_zeropad && !flag_leftjustify && length < width){ int i; int nPad = width - length; for(i=width; i>=nPad; i--){ bufpt[i] = bufpt[i-nPad]; } i = prefix!=0; while( nPad-- ) bufpt[i++] = '0'; length = width; } #else bufpt = " "; length = (int)sizeof(" ") - 1; #endif /* SX_OMIT_FLOATINGPOINT */ break; case SXFMT_SIZE:{ int *pSize = va_arg(ap,int *); *pSize = ((SyFmtConsumer *)pUserData)->nLen; length = width = 0; } break; case SXFMT_PERCENT: buf[0] = '%'; bufpt = buf; length = 1; break; case SXFMT_CHARX: c = va_arg(ap,int); buf[0] = (char)c; /* Limit the precision to prevent overflowing buf[] during conversion */ if( precision>SXFMT_BUFSIZ-40 ) precision = SXFMT_BUFSIZ-40; if( precision>=0 ){ for(idx=1; idx=0 && precisionzString == 0 ){ bufpt = " "; length = (int)sizeof(char); break; } bufpt = (char *)pStr->zString; length = (int)pStr->nByte; break; } case SXFMT_ERROR: buf[0] = '?'; bufpt = buf; length = (int)sizeof(char); if( c==0 ) zFormat--; break; }/* End switch over the format type */ /* ** The text of the conversion is pointed to by "bufpt" and is ** "length" characters long.The field width is "width".Do ** the output. */ if( !flag_leftjustify ){ register int nspace; nspace = width-length; if( nspace>0 ){ while( nspace>=etSPACESIZE ){ rc = xConsumer(spaces,etSPACESIZE,pUserData); if( rc != SXRET_OK ){ return SXERR_ABORT; /* Consumer routine request an operation abort */ } nspace -= etSPACESIZE; } if( nspace>0 ){ rc = xConsumer(spaces,(unsigned int)nspace,pUserData); if( rc != SXRET_OK ){ return SXERR_ABORT; /* Consumer routine request an operation abort */ } } } } if( length>0 ){ rc = xConsumer(bufpt,(unsigned int)length,pUserData); if( rc != SXRET_OK ){ return SXERR_ABORT; /* Consumer routine request an operation abort */ } } if( flag_leftjustify ){ register int nspace; nspace = width-length; if( nspace>0 ){ while( nspace>=etSPACESIZE ){ rc = xConsumer(spaces,etSPACESIZE,pUserData); if( rc != SXRET_OK ){ return SXERR_ABORT; /* Consumer routine request an operation abort */ } nspace -= etSPACESIZE; } if( nspace>0 ){ rc = xConsumer(spaces,(unsigned int)nspace,pUserData); if( rc != SXRET_OK ){ return SXERR_ABORT; /* Consumer routine request an operation abort */ } } } } }/* End for loop over the format string */ return errorflag ? SXERR_FORMAT : SXRET_OK; } static sxi32 FormatConsumer(const void *pSrc,unsigned int nLen,void *pData) { SyFmtConsumer *pConsumer = (SyFmtConsumer *)pData; sxi32 rc = SXERR_ABORT; switch(pConsumer->nType){ case SXFMT_CONS_PROC: /* User callback */ rc = pConsumer->uConsumer.sFunc.xUserConsumer(pSrc,nLen,pConsumer->uConsumer.sFunc.pUserData); break; case SXFMT_CONS_BLOB: /* Blob consumer */ rc = SyBlobAppend(pConsumer->uConsumer.pBlob,pSrc,(sxu32)nLen); break; default: /* Unknown consumer */ break; } /* Update total number of bytes consumed so far */ pConsumer->nLen += nLen; pConsumer->rc = rc; return rc; } static sxi32 FormatMount(sxi32 nType,void *pConsumer,ProcConsumer xUserCons,void *pUserData,sxu32 *pOutLen,const char *zFormat,va_list ap) { SyFmtConsumer sCons; sCons.nType = nType; sCons.rc = SXRET_OK; sCons.nLen = 0; if( pOutLen ){ *pOutLen = 0; } switch(nType){ case SXFMT_CONS_PROC: #if defined(UNTRUST) if( xUserCons == 0 ){ return SXERR_EMPTY; } #endif sCons.uConsumer.sFunc.xUserConsumer = xUserCons; sCons.uConsumer.sFunc.pUserData = pUserData; break; case SXFMT_CONS_BLOB: sCons.uConsumer.pBlob = (SyBlob *)pConsumer; break; default: return SXERR_UNKNOWN; } InternFormat(FormatConsumer,&sCons,zFormat,ap); if( pOutLen ){ *pOutLen = sCons.nLen; } return sCons.rc; } PH7_PRIVATE sxi32 SyProcFormat(ProcConsumer xConsumer,void *pData,const char *zFormat,...) { va_list ap; sxi32 rc; #if defined(UNTRUST) if( SX_EMPTY_STR(zFormat) ){ return SXERR_EMPTY; } #endif va_start(ap,zFormat); rc = FormatMount(SXFMT_CONS_PROC,0,xConsumer,pData,0,zFormat,ap); va_end(ap); return rc; } PH7_PRIVATE sxu32 SyBlobFormat(SyBlob *pBlob,const char *zFormat,...) { va_list ap; sxu32 n; #if defined(UNTRUST) if( SX_EMPTY_STR(zFormat) ){ return 0; } #endif va_start(ap,zFormat); FormatMount(SXFMT_CONS_BLOB,&(*pBlob),0,0,&n,zFormat,ap); va_end(ap); return n; } PH7_PRIVATE sxu32 SyBlobFormatAp(SyBlob *pBlob,const char *zFormat,va_list ap) { sxu32 n = 0; /* cc warning */ #if defined(UNTRUST) if( SX_EMPTY_STR(zFormat) ){ return 0; } #endif FormatMount(SXFMT_CONS_BLOB,&(*pBlob),0,0,&n,zFormat,ap); return n; } PH7_PRIVATE sxu32 SyBufferFormat(char *zBuf,sxu32 nLen,const char *zFormat,...) { SyBlob sBlob; va_list ap; sxu32 n; #if defined(UNTRUST) if( SX_EMPTY_STR(zFormat) ){ return 0; } #endif if( SXRET_OK != SyBlobInitFromBuf(&sBlob,zBuf,nLen - 1) ){ return 0; } va_start(ap,zFormat); FormatMount(SXFMT_CONS_BLOB,&sBlob,0,0,0,zFormat,ap); va_end(ap); n = SyBlobLength(&sBlob); /* Append the null terminator */ sBlob.mByte++; SyBlobAppend(&sBlob,"\0",sizeof(char)); return n; } #ifndef PH7_DISABLE_BUILTIN_FUNC /* * Symisc XML Parser Engine (UTF-8) SAX(Event Driven) API * @author Mrad Chems Eddine * @started 08/03/2010 21:32 FreeBSD * @finished 07/04/2010 23:24 Win32[VS8] */ /* * An XML raw text,CDATA,tag name is parsed out and stored * in an instance of the following structure. */ typedef struct SyXMLRawStrNS SyXMLRawStrNS; struct SyXMLRawStrNS { /* Public field [Must match the SyXMLRawStr fields ] */ const char *zString; /* Raw text [UTF-8 ENCODED EXCEPT CDATA] [NOT NULL TERMINATED] */ sxu32 nByte; /* Text length */ sxu32 nLine; /* Line number this text occurs */ /* Private fields */ SySet sNSset; /* Namespace entries */ }; /* * Lexer token codes * The following set of constants are the token value recognized * by the lexer when processing XML input. */ #define SXML_TOK_INVALID 0xFFFF /* Invalid Token */ #define SXML_TOK_COMMENT 0x01 /* Comment */ #define SXML_TOK_PI 0x02 /* Processing instruction */ #define SXML_TOK_DOCTYPE 0x04 /* Doctype directive */ #define SXML_TOK_RAW 0x08 /* Raw text */ #define SXML_TOK_START_TAG 0x10 /* Starting tag */ #define SXML_TOK_CDATA 0x20 /* CDATA */ #define SXML_TOK_END_TAG 0x40 /* Ending tag */ #define SXML_TOK_START_END 0x80 /* Tag */ #define SXML_TOK_SPACE 0x100 /* Spaces (including new lines) */ #define IS_XML_DIRTY(c) \ ( c == '<' || c == '$'|| c == '"' || c == '\''|| c == '&'|| c == '(' || c == ')' || c == '*' ||\ c == '%' || c == '#' || c == '|' || c == '/'|| c == '~' || c == '{' || c == '}' ||\ c == '[' || c == ']' || c == '\\'|| c == ';'||c == '^' || c == '`' ) /* Tokenize an entire XML input */ static sxi32 XML_Tokenize(SyStream *pStream,SyToken *pToken,void *pUserData,void *pUnused2) { SyXMLParser *pParse = (SyXMLParser *)pUserData; SyString *pStr; sxi32 rc; int c; /* Jump leading white spaces */ while( pStream->zText < pStream->zEnd && pStream->zText[0] < 0xc0 && SyisSpace(pStream->zText[0]) ){ /* Advance the stream cursor */ if( pStream->zText[0] == '\n' ){ /* Increment line counter */ pStream->nLine++; } pStream->zText++; } if( pStream->zText >= pStream->zEnd ){ SXUNUSED(pUnused2); /* End of input reached */ return SXERR_EOF; } /* Record token starting position and line */ pToken->nLine = pStream->nLine; pToken->pUserData = 0; pStr = &pToken->sData; SyStringInitFromBuf(pStr,pStream->zText,0); /* Extract the current token */ c = pStream->zText[0]; if( c == '<' ){ pStream->zText++; pStr->zString++; if( pStream->zText >= pStream->zEnd ){ if( pParse->xError ){ rc = pParse->xError("Illegal syntax,expecting valid start name character",SXML_ERROR_SYNTAX,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } /* End of input reached */ return SXERR_EOF; } c = pStream->zText[0]; if( c == '?' ){ /* Processing instruction */ pStream->zText++; pStr->zString++; pToken->nType = SXML_TOK_PI; while( XLEX_IN_LEN(pStream) >= sizeof("?>")-1 && SyMemcmp((const void *)pStream->zText,"?>",sizeof("?>")-1) != 0 ){ if( pStream->zText[0] == '\n' ){ /* Increment line counter */ pStream->nLine++; } pStream->zText++; } /* Record token length */ pStr->nByte = (sxu32)((const char *)pStream->zText-pStr->zString); if( XLEX_IN_LEN(pStream) < sizeof("?>")-1 ){ if( pParse->xError ){ rc = pParse->xError("End of input found,but processing instruction was not found",SXML_ERROR_UNCLOSED_TOKEN,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } return SXERR_EOF; } pStream->zText += sizeof("?>")-1; }else if( c == '!' ){ pStream->zText++; if( XLEX_IN_LEN(pStream) >= sizeof("--")-1 && pStream->zText[0] == '-' && pStream->zText[1] == '-' ){ /* Comment */ pStream->zText += sizeof("--") - 1; while( XLEX_IN_LEN(pStream) >= sizeof("-->")-1 && SyMemcmp((const void *)pStream->zText,"-->",sizeof("-->")-1) != 0 ){ if( pStream->zText[0] == '\n' ){ /* Increment line counter */ pStream->nLine++; } pStream->zText++; } pStream->zText += sizeof("-->")-1; /* Tell the lexer to ignore this token */ return SXERR_CONTINUE; } if( XLEX_IN_LEN(pStream) >= sizeof("[CDATA[") - 1 && SyMemcmp((const void *)pStream->zText,"[CDATA[",sizeof("[CDATA[")-1) == 0 ){ /* CDATA */ pStream->zText += sizeof("[CDATA[") - 1; pStr->zString = (const char *)pStream->zText; while( XLEX_IN_LEN(pStream) >= sizeof("]]>")-1 && SyMemcmp((const void *)pStream->zText,"]]>",sizeof("]]>")-1) != 0 ){ if( pStream->zText[0] == '\n' ){ /* Increment line counter */ pStream->nLine++; } pStream->zText++; } /* Record token type and length */ pStr->nByte = (sxu32)((const char *)pStream->zText-pStr->zString); pToken->nType = SXML_TOK_CDATA; if( XLEX_IN_LEN(pStream) < sizeof("]]>")-1 ){ if( pParse->xError ){ rc = pParse->xError("End of input found,but ]]> was not found",SXML_ERROR_UNCLOSED_TOKEN,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } return SXERR_EOF; } pStream->zText += sizeof("]]>")-1; return SXRET_OK; } if( XLEX_IN_LEN(pStream) >= sizeof("DOCTYPE") - 1 && SyMemcmp((const void *)pStream->zText,"DOCTYPE",sizeof("DOCTYPE")-1) == 0 ){ SyString sDelim = { ">" , sizeof(char) }; /* Default delimiter */ int c = 0; /* DOCTYPE */ pStream->zText += sizeof("DOCTYPE") - 1; pStr->zString = (const char *)pStream->zText; /* Check for element declaration */ while( pStream->zText < pStream->zEnd && pStream->zText[0] != '\n' ){ if( pStream->zText[0] >= 0xc0 || !SyisSpace(pStream->zText[0]) ){ c = pStream->zText[0]; if( c == '>' ){ break; } } pStream->zText++; } if( c == '[' ){ /* Change the delimiter */ SyStringInitFromBuf(&sDelim,"]>",sizeof("]>")-1); } if( c != '>' ){ while( XLEX_IN_LEN(pStream) >= sDelim.nByte && SyMemcmp((const void *)pStream->zText,sDelim.zString,sDelim.nByte) != 0 ){ if( pStream->zText[0] == '\n' ){ /* Increment line counter */ pStream->nLine++; } pStream->zText++; } } /* Record token type and length */ pStr->nByte = (sxu32)((const char *)pStream->zText-pStr->zString); pToken->nType = SXML_TOK_DOCTYPE; if( XLEX_IN_LEN(pStream) < sDelim.nByte ){ if( pParse->xError ){ rc = pParse->xError("End of input found,but ]> or > was not found",SXML_ERROR_UNCLOSED_TOKEN,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } return SXERR_EOF; } pStream->zText += sDelim.nByte; return SXRET_OK; } }else{ int c; c = pStream->zText[0]; rc = SXRET_OK; pToken->nType = SXML_TOK_START_TAG; if( c == '/' ){ /* End tag */ pToken->nType = SXML_TOK_END_TAG; pStream->zText++; pStr->zString++; if( pStream->zText >= pStream->zEnd ){ if( pParse->xError ){ rc = pParse->xError("Illegal syntax,expecting valid start name character",SXML_ERROR_SYNTAX,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } return SXERR_EOF; } c = pStream->zText[0]; } if( c == '>' ){ /*<>*/ if( pParse->xError ){ rc = pParse->xError("Illegal syntax,expecting valid start name character",SXML_ERROR_SYNTAX,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } /* Ignore the token */ return SXERR_CONTINUE; } if( c < 0xc0 && (SyisSpace(c) || SyisDigit(c) || c == '.' || c == '-' ||IS_XML_DIRTY(c) ) ){ if( pParse->xError ){ rc = pParse->xError("Illegal syntax,expecting valid start name character",SXML_ERROR_SYNTAX,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } rc = SXERR_INVALID; } pStream->zText++; /* Delimit the tag */ while( pStream->zText < pStream->zEnd && pStream->zText[0] != '>' ){ c = pStream->zText[0]; if( c >= 0xc0 ){ /* UTF-8 stream */ pStream->zText++; SX_JMP_UTF8(pStream->zText,pStream->zEnd); }else{ if( c == '/' && &pStream->zText[1] < pStream->zEnd && pStream->zText[1] == '>' ){ pStream->zText++; if( pToken->nType != SXML_TOK_START_TAG ){ if( pParse->xError ){ rc = pParse->xError("Unexpected closing tag,expecting '>'", SXML_ERROR_SYNTAX,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } /* Ignore the token */ rc = SXERR_INVALID; }else{ pToken->nType = SXML_TOK_START_END; } break; } if( pStream->zText[0] == '\n' ){ /* Increment line counter */ pStream->nLine++; } /* Advance the stream cursor */ pStream->zText++; } } if( rc != SXRET_OK ){ /* Tell the lexer to ignore this token */ return SXERR_CONTINUE; } /* Record token length */ pStr->nByte = (sxu32)((const char *)pStream->zText-pStr->zString); if( pToken->nType == SXML_TOK_START_END && pStr->nByte > 0){ pStr->nByte -= sizeof(char); } if ( pStream->zText < pStream->zEnd ){ pStream->zText++; }else{ if( pParse->xError ){ rc = pParse->xError("End of input found,but closing tag '>' was not found",SXML_ERROR_UNCLOSED_TOKEN,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } } } }else{ /* Raw input */ while( pStream->zText < pStream->zEnd ){ c = pStream->zText[0]; if( c < 0xc0 ){ if( c == '<' ){ break; }else if( c == '\n' ){ /* Increment line counter */ pStream->nLine++; } /* Advance the stream cursor */ pStream->zText++; }else{ /* UTF-8 stream */ pStream->zText++; SX_JMP_UTF8(pStream->zText,pStream->zEnd); } } /* Record token type,length */ pToken->nType = SXML_TOK_RAW; pStr->nByte = (sxu32)((const char *)pStream->zText-pStr->zString); } /* Return to the lexer */ return SXRET_OK; } static int XMLCheckDuplicateAttr(SyXMLRawStr *aSet,sxu32 nEntry,SyXMLRawStr *pEntry) { sxu32 n; for( n = 0 ; n < nEntry ; n += 2 ){ SyXMLRawStr *pAttr = &aSet[n]; if( pAttr->nByte == pEntry->nByte && SyMemcmp(pAttr->zString,pEntry->zString,pEntry->nByte) == 0 ){ /* Attribute found */ return 1; } } /* No duplicates */ return 0; } static sxi32 XMLProcessNamesSpace(SyXMLParser *pParse,SyXMLRawStrNS *pTag,SyToken *pToken,SySet *pAttr) { SyXMLRawStr *pPrefix,*pUri; /* Namespace prefix/URI */ SyHashEntry *pEntry; SyXMLRawStr *pDup; sxi32 rc; /* Extract the URI first */ pUri = (SyXMLRawStr *)SySetPeek(pAttr); /* Extract the prefix */ pPrefix = (SyXMLRawStr *)SySetAt(pAttr,SySetUsed(pAttr) - 2); /* Prefix name */ if( pPrefix->nByte == sizeof("xmlns")-1 ){ /* Default namespace */ pPrefix->nByte = 0; pPrefix->zString = ""; /* Empty string */ }else{ pPrefix->nByte -= sizeof("xmlns")-1; pPrefix->zString += sizeof("xmlns")-1; if( pPrefix->zString[0] != ':' ){ return SXRET_OK; } pPrefix->nByte--; pPrefix->zString++; if( pPrefix->nByte < 1 ){ if( pParse->xError ){ rc = pParse->xError("Invalid namespace name",SXML_ERROR_SYNTAX,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } /* POP the last insertred two entries */ (void)SySetPop(pAttr); (void)SySetPop(pAttr); return SXERR_SYNTAX; } } /* Invoke the namespace callback if available */ if( pParse->xNameSpace ){ rc = pParse->xNameSpace(pPrefix,pUri,pParse->pUserData); if( rc == SXERR_ABORT ){ /* User callback request an operation abort */ return SXERR_ABORT; } } /* Duplicate structure */ pDup = (SyXMLRawStr *)SyMemBackendAlloc(pParse->pAllocator,sizeof(SyXMLRawStr)); if( pDup == 0 ){ if( pParse->xError ){ pParse->xError("Out of memory",SXML_ERROR_NO_MEMORY,pToken,pParse->pUserData); } /* Abort processing immediately */ return SXERR_ABORT; } *pDup = *pUri; /* Structure assignement */ /* Save the namespace */ if( pPrefix->nByte == 0 ){ pPrefix->zString = "Default"; pPrefix->nByte = sizeof("Default")-1; } SyHashInsert(&pParse->hns,(const void *)pPrefix->zString,pPrefix->nByte,pDup); /* Peek the last inserted entry */ pEntry = SyHashLastEntry(&pParse->hns); /* Store in the corresponding tag container*/ SySetPut(&pTag->sNSset,(const void *)&pEntry); /* POP the last insertred two entries */ (void)SySetPop(pAttr); (void)SySetPop(pAttr); return SXRET_OK; } static sxi32 XMLProcessStartTag(SyXMLParser *pParse,SyToken *pToken,SyXMLRawStrNS *pTag,SySet *pAttrSet,SySet *pTagStack) { SyString *pIn = &pToken->sData; const char *zIn,*zCur,*zEnd; SyXMLRawStr sEntry; sxi32 rc; int c; /* Reset the working set */ SySetReset(pAttrSet); /* Delimit the raw tag */ zIn = pIn->zString; zEnd = &zIn[pIn->nByte]; while( zIn < zEnd && (unsigned char)zIn[0] < 0xc0 && SyisSpace(zIn[0]) ){ zIn++; } /* Isolate tag name */ sEntry.nLine = pTag->nLine = pToken->nLine; zCur = zIn; while( zIn < zEnd ){ if( (unsigned char)zIn[0] >= 0xc0 ){ /* UTF-8 stream */ zIn++; SX_JMP_UTF8(zIn,zEnd); }else if( SyisSpace(zIn[0])){ break; }else{ if( IS_XML_DIRTY(zIn[0]) ){ if( pParse->xError ){ rc = pParse->xError("Illegal character in XML name",SXML_ERROR_SYNTAX,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } } zIn++; } } if( zCur >= zIn ){ if( pParse->xError ){ rc = pParse->xError("Invalid XML name",SXML_ERROR_SYNTAX,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } return SXERR_SYNTAX; } pTag->zString = zCur; pTag->nByte = (sxu32)(zIn-zCur); /* Process tag attribute */ for(;;){ int is_ns = 0; while( zIn < zEnd && (unsigned char)zIn[0] < 0xc0 && SyisSpace(zIn[0]) ){ zIn++; } if( zIn >= zEnd ){ break; } zCur = zIn; while( zIn < zEnd && zIn[0] != '=' ){ if( (unsigned char)zIn[0] >= 0xc0 ){ /* UTF-8 stream */ zIn++; SX_JMP_UTF8(zIn,zEnd); }else if( SyisSpace(zIn[0]) ){ break; }else{ zIn++; } } if( zCur >= zIn ){ if( pParse->xError ){ rc = pParse->xError("Missing attribute name",SXML_ERROR_SYNTAX,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } return SXERR_SYNTAX; } /* Store attribute name */ sEntry.zString = zCur; sEntry.nByte = (sxu32)(zIn-zCur); if( (pParse->nFlags & SXML_ENABLE_NAMESPACE) && sEntry.nByte >= sizeof("xmlns") - 1 && SyMemcmp(sEntry.zString,"xmlns",sizeof("xmlns") - 1) == 0 ){ is_ns = 1; } while( zIn < zEnd && (unsigned char)zIn[0] < 0xc0 && SyisSpace(zIn[0]) ){ zIn++; } if( zIn >= zEnd || zIn[0] != '=' ){ if( pParse->xError ){ rc = pParse->xError("Missing attribute value",SXML_ERROR_SYNTAX,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } return SXERR_SYNTAX; } while( sEntry.nByte > 0 && (unsigned char)zCur[sEntry.nByte - 1] < 0xc0 && SyisSpace(zCur[sEntry.nByte - 1])){ sEntry.nByte--; } /* Check for duplicates first */ if( XMLCheckDuplicateAttr((SyXMLRawStr *)SySetBasePtr(pAttrSet),SySetUsed(pAttrSet),&sEntry) ){ if( pParse->xError ){ rc = pParse->xError("Duplicate attribute",SXML_ERROR_DUPLICATE_ATTRIBUTE,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } return SXERR_SYNTAX; } if( SXRET_OK != SySetPut(pAttrSet,(const void *)&sEntry) ){ return SXERR_ABORT; } /* Extract attribute value */ zIn++; /* Jump the trailing '=' */ while( zIn < zEnd && (unsigned char)zIn[0] < 0xc0 && SyisSpace(zIn[0]) ){ zIn++; } if( zIn >= zEnd ){ if( pParse->xError ){ rc = pParse->xError("Missing attribute value",SXML_ERROR_SYNTAX,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } (void)SySetPop(pAttrSet); return SXERR_SYNTAX; } if( zIn[0] != '\'' && zIn[0] != '"' ){ if( pParse->xError ){ rc = pParse->xError("Missing quotes on attribute value",SXML_ERROR_SYNTAX,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } (void)SySetPop(pAttrSet); return SXERR_SYNTAX; } c = zIn[0]; zIn++; zCur = zIn; while( zIn < zEnd && zIn[0] != c ){ zIn++; } if( zIn >= zEnd ){ if( pParse->xError ){ rc = pParse->xError("Missing quotes on attribute value",SXML_ERROR_SYNTAX,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } (void)SySetPop(pAttrSet); return SXERR_SYNTAX; } /* Store attribute value */ sEntry.zString = zCur; sEntry.nByte = (sxu32)(zIn-zCur); if( SXRET_OK != SySetPut(pAttrSet,(const void *)&sEntry) ){ return SXERR_ABORT; } zIn++; if( is_ns ){ /* Process namespace declaration */ XMLProcessNamesSpace(pParse,pTag,pToken,pAttrSet); } } /* Store in the tag stack */ if( pToken->nType == SXML_TOK_START_TAG ){ rc = SySetPut(pTagStack,(const void *)pTag); } return SXRET_OK; } static void XMLExtactPI(SyToken *pToken,SyXMLRawStr *pTarget,SyXMLRawStr *pData,int *pXML) { SyString *pIn = &pToken->sData; const char *zIn,*zCur,*zEnd; pTarget->nLine = pData->nLine = pToken->nLine; /* Nullify the entries first */ pTarget->zString = pData->zString = 0; /* Ignore leading and traing white spaces */ SyStringFullTrim(pIn); /* Delimit the raw PI */ zIn = pIn->zString; zEnd = &zIn[pIn->nByte]; if( pXML ){ *pXML = 0; } /* Extract the target */ zCur = zIn; while( zIn < zEnd ){ if( (unsigned char)zIn[0] >= 0xc0 ){ /* UTF-8 stream */ zIn++; SX_JMP_UTF8(zIn,zEnd); }else if( SyisSpace(zIn[0])){ break; }else{ zIn++; } } if( zIn > zCur ){ pTarget->zString = zCur; pTarget->nByte = (sxu32)(zIn-zCur); if( pXML && pTarget->nByte == sizeof("xml")-1 && SyStrnicmp(pTarget->zString,"xml",sizeof("xml")-1) == 0 ){ *pXML = 1; } } /* Extract the PI data */ while( zIn < zEnd && (unsigned char)zIn[0] < 0xc0 && SyisSpace(zIn[0]) ){ zIn++; } if( zIn < zEnd ){ pData->zString = zIn; pData->nByte = (sxu32)(zEnd-zIn); } } static sxi32 XMLExtractEndTag(SyXMLParser *pParse,SyToken *pToken,SyXMLRawStrNS *pOut) { SyString *pIn = &pToken->sData; const char *zEnd = &pIn->zString[pIn->nByte]; const char *zIn = pIn->zString; /* Ignore leading white spaces */ while( zIn < zEnd && (unsigned char)zIn[0] < 0xc0 && SyisSpace(zIn[0]) ){ zIn++; } pOut->nLine = pToken->nLine; pOut->zString = zIn; pOut->nByte = (sxu32)(zEnd-zIn); /* Ignore trailing white spaces */ while( pOut->nByte > 0 && (unsigned char)pOut->zString[pOut->nByte - 1] < 0xc0 && SyisSpace(pOut->zString[pOut->nByte - 1]) ){ pOut->nByte--; } if( pOut->nByte < 1 ){ if( pParse->xError ){ sxi32 rc; rc = pParse->xError("Invalid end tag name",SXML_ERROR_INVALID_TOKEN,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } return SXERR_SYNTAX; } return SXRET_OK; } static void TokenToXMLString(SyToken *pTok,SyXMLRawStrNS *pOut) { /* Remove leading and trailing white spaces first */ SyStringFullTrim(&pTok->sData); pOut->zString = SyStringData(&pTok->sData); pOut->nByte = SyStringLength(&pTok->sData); } static sxi32 XMLExtractNS(SyXMLParser *pParse,SyToken *pToken,SyXMLRawStrNS *pTag,SyXMLRawStr *pnsUri) { SyXMLRawStr *pUri,sPrefix; SyHashEntry *pEntry; sxu32 nOfft; sxi32 rc; /* Extract a prefix if available */ rc = SyByteFind(pTag->zString,pTag->nByte,':',&nOfft); if( rc != SXRET_OK ){ /* Check if there is a default namespace */ pEntry = SyHashGet(&pParse->hns,"Default",sizeof("Default")-1); if( pEntry ){ /* Extract the ns URI */ pUri = (SyXMLRawStr *)pEntry->pUserData; /* Save the ns URI */ pnsUri->zString = pUri->zString; pnsUri->nByte = pUri->nByte; } return SXRET_OK; } if( nOfft < 1 ){ if( pParse->xError ){ rc = pParse->xError("Empty prefix is not allowed according to XML namespace specification", SXML_ERROR_SYNTAX,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } return SXERR_SYNTAX; } sPrefix.zString = pTag->zString; sPrefix.nByte = nOfft; sPrefix.nLine = pTag->nLine; pTag->zString += nOfft + 1; pTag->nByte -= nOfft; if( pTag->nByte < 1 ){ if( pParse->xError ){ rc = pParse->xError("Missing tag name",SXML_ERROR_SYNTAX,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } return SXERR_SYNTAX; } /* Check if the prefix is already registered */ pEntry = SyHashGet(&pParse->hns,sPrefix.zString,sPrefix.nByte); if( pEntry == 0 ){ if( pParse->xError ){ rc = pParse->xError("Namespace prefix is not defined",SXML_ERROR_SYNTAX, pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } return SXERR_SYNTAX; } /* Extract the ns URI */ pUri = (SyXMLRawStr *)pEntry->pUserData; /* Save the ns URI */ pnsUri->zString = pUri->zString; pnsUri->nByte = pUri->nByte; /* All done */ return SXRET_OK; } static sxi32 XMLnsUnlink(SyXMLParser *pParse,SyXMLRawStrNS *pLast,SyToken *pToken) { SyHashEntry **apEntry,*pEntry; void *pUserData; sxu32 n; /* Release namespace entries */ apEntry = (SyHashEntry **)SySetBasePtr(&pLast->sNSset); for( n = 0 ; n < SySetUsed(&pLast->sNSset) ; ++n ){ pEntry = apEntry[n]; /* Invoke the end namespace declaration callback */ if( pParse->xNameSpaceEnd && (pParse->nFlags & SXML_ENABLE_NAMESPACE) && pToken ){ SyXMLRawStr sPrefix; sxi32 rc; sPrefix.zString = (const char *)pEntry->pKey; sPrefix.nByte = pEntry->nKeyLen; sPrefix.nLine = pToken->nLine; rc = pParse->xNameSpaceEnd(&sPrefix,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } pUserData = pEntry->pUserData; /* Remove from the namespace hashtable */ SyHashDeleteEntry2(pEntry); SyMemBackendFree(pParse->pAllocator,pUserData); } SySetRelease(&pLast->sNSset); return SXRET_OK; } /* Process XML tokens */ static sxi32 ProcessXML(SyXMLParser *pParse,SySet *pTagStack,SySet *pWorker) { SySet *pTokenSet = &pParse->sToken; SyXMLRawStrNS sEntry; SyXMLRawStr sNs; SyToken *pToken; int bGotTag; sxi32 rc; /* Initialize fields */ bGotTag = 0; /* Start processing */ if( pParse->xStartDoc && (SXERR_ABORT == pParse->xStartDoc(pParse->pUserData)) ){ /* User callback request an operation abort */ return SXERR_ABORT; } /* Reset the loop cursor */ SySetResetCursor(pTokenSet); /* Extract the current token */ while( SXRET_OK == (SySetGetNextEntry(&(*pTokenSet),(void **)&pToken)) ){ SyZero(&sEntry,sizeof(SyXMLRawStrNS)); SyZero(&sNs,sizeof(SyXMLRawStr)); SySetInit(&sEntry.sNSset,pParse->pAllocator,sizeof(SyHashEntry *)); sEntry.nLine = sNs.nLine = pToken->nLine; switch(pToken->nType){ case SXML_TOK_DOCTYPE: if( SySetUsed(pTagStack) > 1 || bGotTag ){ if( pParse->xError ){ rc = pParse->xError("DOCTYPE must be declared first",SXML_ERROR_MISPLACED_XML_PI,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } break; } /* Invoke the supplied callback if any */ if( pParse->xDoctype ){ TokenToXMLString(pToken,&sEntry); rc = pParse->xDoctype((SyXMLRawStr *)&sEntry,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } break; case SXML_TOK_CDATA: if( SySetUsed(pTagStack) < 1 ){ if( pParse->xError ){ rc = pParse->xError("CDATA without matching tag",SXML_ERROR_TAG_MISMATCH,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } } /* Invoke the supplied callback if any */ if( pParse->xRaw ){ TokenToXMLString(pToken,&sEntry); rc = pParse->xRaw((SyXMLRawStr *)&sEntry,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } break; case SXML_TOK_PI:{ SyXMLRawStr sTarget,sData; int isXML = 0; /* Extract the target and data */ XMLExtactPI(pToken,&sTarget,&sData,&isXML); if( isXML && SySetCursor(pTokenSet) - 1 > 0 ){ if( pParse->xError ){ rc = pParse->xError("Unexpected XML declaration. The XML declaration must be the first node in the document", SXML_ERROR_MISPLACED_XML_PI,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } }else if( pParse->xPi ){ /* Invoke the supplied callback*/ rc = pParse->xPi(&sTarget,&sData,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } break; } case SXML_TOK_RAW: if( SySetUsed(pTagStack) < 1 ){ if( pParse->xError ){ rc = pParse->xError("Text (Raw data) without matching tag",SXML_ERROR_TAG_MISMATCH,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } break; } /* Invoke the supplied callback if any */ if( pParse->xRaw ){ TokenToXMLString(pToken,&sEntry); rc = pParse->xRaw((SyXMLRawStr *)&sEntry,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } break; case SXML_TOK_END_TAG:{ SyXMLRawStrNS *pLast = 0; /* cc warning */ if( SySetUsed(pTagStack) < 1 ){ if( pParse->xError ){ rc = pParse->xError("Unexpected closing tag",SXML_ERROR_TAG_MISMATCH,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } break; } rc = XMLExtractEndTag(pParse,pToken,&sEntry); if( rc == SXRET_OK ){ /* Extract the last inserted entry */ pLast = (SyXMLRawStrNS *)SySetPeek(pTagStack); if( pLast == 0 || pLast->nByte != sEntry.nByte || SyMemcmp(pLast->zString,sEntry.zString,sEntry.nByte) != 0 ){ if( pParse->xError ){ rc = pParse->xError("Unexpected closing tag",SXML_ERROR_TAG_MISMATCH,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } }else{ /* Invoke the supllied callback if any */ if( pParse->xEndTag ){ rc = SXRET_OK; if( pParse->nFlags & SXML_ENABLE_NAMESPACE ){ /* Extract namespace URI */ rc = XMLExtractNS(pParse,pToken,&sEntry,&sNs); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } if( rc == SXRET_OK ){ rc = pParse->xEndTag((SyXMLRawStr *)&sEntry,&sNs,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } } } }else if( rc == SXERR_ABORT ){ return SXERR_ABORT; } if( pLast ){ rc = XMLnsUnlink(pParse,pLast,pToken); (void)SySetPop(pTagStack); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } break; } case SXML_TOK_START_TAG: case SXML_TOK_START_END: if( SySetUsed(pTagStack) < 1 && bGotTag ){ if( pParse->xError ){ rc = pParse->xError("XML document cannot contain multiple root level elements documents", SXML_ERROR_SYNTAX,pToken,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } break; } bGotTag = 1; /* Extract the tag and it's supplied attribute */ rc = XMLProcessStartTag(pParse,pToken,&sEntry,pWorker,pTagStack); if( rc == SXRET_OK ){ if( pParse->nFlags & SXML_ENABLE_NAMESPACE ){ /* Extract namespace URI */ rc = XMLExtractNS(pParse,pToken,&sEntry,&sNs); } } if( rc == SXRET_OK ){ /* Invoke the supplied callback */ if( pParse->xStartTag ){ rc = pParse->xStartTag((SyXMLRawStr *)&sEntry,&sNs,SySetUsed(pWorker), (SyXMLRawStr *)SySetBasePtr(pWorker),pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } if( pToken->nType == SXML_TOK_START_END ){ if ( pParse->xEndTag ){ rc = pParse->xEndTag((SyXMLRawStr *)&sEntry,&sNs,pParse->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } rc = XMLnsUnlink(pParse,&sEntry,pToken); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } } }else if( rc == SXERR_ABORT ){ /* Abort processing immediately */ return SXERR_ABORT; } break; default: /* Can't happen */ break; } } if( SySetUsed(pTagStack) > 0 && pParse->xError){ pParse->xError("Missing closing tag",SXML_ERROR_SYNTAX, (SyToken *)SySetPeek(&pParse->sToken),pParse->pUserData); } if( pParse->xEndDoc ){ pParse->xEndDoc(pParse->pUserData); } return SXRET_OK; } PH7_PRIVATE sxi32 SyXMLParserInit(SyXMLParser *pParser,SyMemBackend *pAllocator,sxi32 iFlags) { /* Zero the structure first */ SyZero(pParser,sizeof(SyXMLParser)); /* Initilaize fields */ SySetInit(&pParser->sToken,pAllocator,sizeof(SyToken)); SyLexInit(&pParser->sLex,&pParser->sToken,XML_Tokenize,pParser); SyHashInit(&pParser->hns,pAllocator,0,0); pParser->pAllocator = pAllocator; pParser->nFlags = iFlags; return SXRET_OK; } PH7_PRIVATE sxi32 SyXMLParserSetEventHandler(SyXMLParser *pParser, void *pUserData, ProcXMLStartTagHandler xStartTag, ProcXMLTextHandler xRaw, ProcXMLSyntaxErrorHandler xErr, ProcXMLStartDocument xStartDoc, ProcXMLEndTagHandler xEndTag, ProcXMLPIHandler xPi, ProcXMLEndDocument xEndDoc, ProcXMLDoctypeHandler xDoctype, ProcXMLNameSpaceStart xNameSpace, ProcXMLNameSpaceEnd xNameSpaceEnd ){ /* Install user callbacks */ if( xErr ){ pParser->xError = xErr; } if( xStartDoc ){ pParser->xStartDoc = xStartDoc; } if( xStartTag ){ pParser->xStartTag = xStartTag; } if( xRaw ){ pParser->xRaw = xRaw; } if( xEndTag ){ pParser->xEndTag = xEndTag; } if( xPi ){ pParser->xPi = xPi; } if( xEndDoc ){ pParser->xEndDoc = xEndDoc; } if( xDoctype ){ pParser->xDoctype = xDoctype; } if( xNameSpace ){ pParser->xNameSpace = xNameSpace; } if( xNameSpaceEnd ){ pParser->xNameSpaceEnd = xNameSpaceEnd; } pParser->pUserData = pUserData; return SXRET_OK; } /* Process an XML chunk */ PH7_PRIVATE sxi32 SyXMLProcess(SyXMLParser *pParser,const char *zInput,sxu32 nByte) { SySet sTagStack; SySet sWorker; sxi32 rc; /* Initialize working sets */ SySetInit(&sWorker,pParser->pAllocator,sizeof(SyXMLRawStr)); /* Tag container */ SySetInit(&sTagStack,pParser->pAllocator,sizeof(SyXMLRawStrNS)); /* Tag stack */ /* Tokenize the entire input */ rc = SyLexTokenizeInput(&pParser->sLex,zInput,nByte,0,0,0); if( rc == SXERR_ABORT ){ /* Tokenize callback request an operation abort */ return SXERR_ABORT; } if( SySetUsed(&pParser->sToken) < 1 ){ /* Nothing to process [i.e: white spaces] */ rc = SXRET_OK; }else{ /* Process XML Tokens */ rc = ProcessXML(&(*pParser),&sTagStack,&sWorker); if( pParser->nFlags & SXML_ENABLE_NAMESPACE ){ if( SySetUsed(&sTagStack) > 0 ){ SyXMLRawStrNS *pEntry; SyHashEntry **apEntry; sxu32 n; SySetResetCursor(&sTagStack); while( SySetGetNextEntry(&sTagStack,(void **)&pEntry) == SXRET_OK ){ /* Release namespace entries */ apEntry = (SyHashEntry **)SySetBasePtr(&pEntry->sNSset); for( n = 0 ; n < SySetUsed(&pEntry->sNSset) ; ++n ){ SyMemBackendFree(pParser->pAllocator,apEntry[n]->pUserData); } SySetRelease(&pEntry->sNSset); } } } } /* Clean-up the mess left behind */ SySetRelease(&sWorker); SySetRelease(&sTagStack); /* Processing result */ return rc; } PH7_PRIVATE sxi32 SyXMLParserRelease(SyXMLParser *pParser) { SyLexRelease(&pParser->sLex); SySetRelease(&pParser->sToken); SyHashRelease(&pParser->hns); return SXRET_OK; } /* * Zip File Format: * * Byte order: Little-endian * * [Local file header + Compressed data [+ Extended local header]?]* * [Central directory]* * [End of central directory record] * * Local file header:* * Offset Length Contents * 0 4 bytes Local file header signature (0x04034b50) * 4 2 bytes Version needed to extract * 6 2 bytes General purpose bit flag * 8 2 bytes Compression method * 10 2 bytes Last mod file time * 12 2 bytes Last mod file date * 14 4 bytes CRC-32 * 18 4 bytes Compressed size (n) * 22 4 bytes Uncompressed size * 26 2 bytes Filename length (f) * 28 2 bytes Extra field length (e) * 30 (f)bytes Filename * (e)bytes Extra field * (n)bytes Compressed data * * Extended local header:* * Offset Length Contents * 0 4 bytes Extended Local file header signature (0x08074b50) * 4 4 bytes CRC-32 * 8 4 bytes Compressed size * 12 4 bytes Uncompressed size * * Extra field:?(if any) * Offset Length Contents * 0 2 bytes Header ID (0x001 until 0xfb4a) see extended appnote from Info-zip * 2 2 bytes Data size (g) * (g) bytes (g) bytes of extra field * * Central directory:* * Offset Length Contents * 0 4 bytes Central file header signature (0x02014b50) * 4 2 bytes Version made by * 6 2 bytes Version needed to extract * 8 2 bytes General purpose bit flag * 10 2 bytes Compression method * 12 2 bytes Last mod file time * 14 2 bytes Last mod file date * 16 4 bytes CRC-32 * 20 4 bytes Compressed size * 24 4 bytes Uncompressed size * 28 2 bytes Filename length (f) * 30 2 bytes Extra field length (e) * 32 2 bytes File comment length (c) * 34 2 bytes Disk number start * 36 2 bytes Internal file attributes * 38 4 bytes External file attributes * 42 4 bytes Relative offset of local header * 46 (f)bytes Filename * (e)bytes Extra field * (c)bytes File comment * * End of central directory record: * Offset Length Contents * 0 4 bytes End of central dir signature (0x06054b50) * 4 2 bytes Number of this disk * 6 2 bytes Number of the disk with the start of the central directory * 8 2 bytes Total number of entries in the central dir on this disk * 10 2 bytes Total number of entries in the central dir * 12 4 bytes Size of the central directory * 16 4 bytes Offset of start of central directory with respect to the starting disk number * 20 2 bytes zipfile comment length (c) * 22 (c)bytes zipfile comment * * compression method: (2 bytes) * 0 - The file is stored (no compression) * 1 - The file is Shrunk * 2 - The file is Reduced with compression factor 1 * 3 - The file is Reduced with compression factor 2 * 4 - The file is Reduced with compression factor 3 * 5 - The file is Reduced with compression factor 4 * 6 - The file is Imploded * 7 - Reserved for Tokenizing compression algorithm * 8 - The file is Deflated */ #define SXMAKE_ZIP_WORKBUF (SXU16_HIGH/2) /* 32KB Initial working buffer size */ #define SXMAKE_ZIP_EXTRACT_VER 0x000a /* Version needed to extract */ #define SXMAKE_ZIP_VER 0x003 /* Version made by */ #define SXZIP_CENTRAL_MAGIC 0x02014b50 #define SXZIP_END_CENTRAL_MAGIC 0x06054b50 #define SXZIP_LOCAL_MAGIC 0x04034b50 /*#define SXZIP_CRC32_START 0xdebb20e3*/ #define SXZIP_LOCAL_HDRSZ 30 /* Local header size */ #define SXZIP_LOCAL_EXT_HDRZ 16 /* Extended local header(footer) size */ #define SXZIP_CENTRAL_HDRSZ 46 /* Central directory header size */ #define SXZIP_END_CENTRAL_HDRSZ 22 /* End of central directory header size */ #define SXARCHIVE_HASH_SIZE 64 /* Starting hash table size(MUST BE POWER OF 2)*/ static sxi32 SyLittleEndianUnpack32(sxu32 *uNB,const unsigned char *buf,sxu32 Len) { if( Len < sizeof(sxu32) ){ return SXERR_SHORT; } *uNB = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24); return SXRET_OK; } static sxi32 SyLittleEndianUnpack16(sxu16 *pOut,const unsigned char *zBuf,sxu32 nLen) { if( nLen < sizeof(sxu16) ){ return SXERR_SHORT; } *pOut = zBuf[0] + (zBuf[1] <<8); return SXRET_OK; } static sxi32 SyDosTimeFormat(sxu32 nDosDate,Sytm *pOut) { sxu16 nDate; sxu16 nTime; nDate = nDosDate >> 16; nTime = nDosDate & 0xFFFF; pOut->tm_isdst = 0; pOut->tm_year = 1980 + (nDate >> 9); pOut->tm_mon = (nDate % (1<<9))>>5; pOut->tm_mday = (nDate % (1<<9))&0x1F; pOut->tm_hour = nTime >> 11; pOut->tm_min = (nTime % (1<<11)) >> 5; pOut->tm_sec = ((nTime % (1<<11))& 0x1F )<<1; return SXRET_OK; } /* * Archive hashtable manager */ static sxi32 ArchiveHashGetEntry(SyArchive *pArch,const char *zName,sxu32 nLen,SyArchiveEntry **ppEntry) { SyArchiveEntry *pBucketEntry; SyString sEntry; sxu32 nHash; nHash = pArch->xHash(zName,nLen); pBucketEntry = pArch->apHash[nHash & (pArch->nSize - 1)]; SyStringInitFromBuf(&sEntry,zName,nLen); for(;;){ if( pBucketEntry == 0 ){ break; } if( nHash == pBucketEntry->nHash && pArch->xCmp(&sEntry,&pBucketEntry->sFileName) == 0 ){ if( ppEntry ){ *ppEntry = pBucketEntry; } return SXRET_OK; } pBucketEntry = pBucketEntry->pNextHash; } return SXERR_NOTFOUND; } static void ArchiveHashBucketInstall(SyArchiveEntry **apTable,sxu32 nBucket,SyArchiveEntry *pEntry) { pEntry->pNextHash = apTable[nBucket]; if( apTable[nBucket] != 0 ){ apTable[nBucket]->pPrevHash = pEntry; } apTable[nBucket] = pEntry; } static sxi32 ArchiveHashGrowTable(SyArchive *pArch) { sxu32 nNewSize = pArch->nSize * 2; SyArchiveEntry **apNew; SyArchiveEntry *pEntry; sxu32 n; /* Allocate a new table */ apNew = (SyArchiveEntry **)SyMemBackendAlloc(pArch->pAllocator,nNewSize * sizeof(SyArchiveEntry *)); if( apNew == 0 ){ return SXRET_OK; /* Not so fatal,simply a performance hit */ } SyZero(apNew,nNewSize * sizeof(SyArchiveEntry *)); /* Rehash old entries */ for( n = 0 , pEntry = pArch->pList ; n < pArch->nLoaded ; n++ , pEntry = pEntry->pNext ){ pEntry->pNextHash = pEntry->pPrevHash = 0; ArchiveHashBucketInstall(apNew,pEntry->nHash & (nNewSize - 1),pEntry); } /* Release the old table */ SyMemBackendFree(pArch->pAllocator,pArch->apHash); pArch->apHash = apNew; pArch->nSize = nNewSize; return SXRET_OK; } static sxi32 ArchiveHashInstallEntry(SyArchive *pArch,SyArchiveEntry *pEntry) { if( pArch->nLoaded > pArch->nSize * 3 ){ ArchiveHashGrowTable(&(*pArch)); } pEntry->nHash = pArch->xHash(SyStringData(&pEntry->sFileName),SyStringLength(&pEntry->sFileName)); /* Install the entry in its bucket */ ArchiveHashBucketInstall(pArch->apHash,pEntry->nHash & (pArch->nSize - 1),pEntry); MACRO_LD_PUSH(pArch->pList,pEntry); pArch->nLoaded++; return SXRET_OK; } /* * Parse the End of central directory and report status */ static sxi32 ParseEndOfCentralDirectory(SyArchive *pArch,const unsigned char *zBuf) { sxu32 nMagic = 0; /* cc -O6 warning */ sxi32 rc; /* Sanity check */ rc = SyLittleEndianUnpack32(&nMagic,zBuf,sizeof(sxu32)); if( /* rc != SXRET_OK || */nMagic != SXZIP_END_CENTRAL_MAGIC ){ return SXERR_CORRUPT; } /* # of entries */ rc = SyLittleEndianUnpack16((sxu16 *)&pArch->nEntry,&zBuf[8],sizeof(sxu16)); if( /* rc != SXRET_OK || */ pArch->nEntry > SXI16_HIGH /* SXU16_HIGH */ ){ return SXERR_CORRUPT; } /* Size of central directory */ rc = SyLittleEndianUnpack32(&pArch->nCentralSize,&zBuf[12],sizeof(sxu32)); if( /*rc != SXRET_OK ||*/ pArch->nCentralSize > SXI32_HIGH ){ return SXERR_CORRUPT; } /* Starting offset of central directory */ rc = SyLittleEndianUnpack32(&pArch->nCentralOfft,&zBuf[16],sizeof(sxu32)); if( /*rc != SXRET_OK ||*/ pArch->nCentralSize > SXI32_HIGH ){ return SXERR_CORRUPT; } return SXRET_OK; } /* * Fill the zip entry with the appropriate information from the central directory */ static sxi32 GetCentralDirectoryEntry(SyArchive *pArch,SyArchiveEntry *pEntry,const unsigned char *zCentral,sxu32 *pNextOffset) { SyString *pName = &pEntry->sFileName; /* File name */ sxu16 nDosDate,nDosTime; sxu16 nComment = 0 ; sxu32 nMagic = 0; /* cc -O6 warning */ sxi32 rc; nDosDate = nDosTime = 0; /* cc -O6 warning */ SXUNUSED(pArch); /* Sanity check */ rc = SyLittleEndianUnpack32(&nMagic,zCentral,sizeof(sxu32)); if( /* rc != SXRET_OK || */ nMagic != SXZIP_CENTRAL_MAGIC ){ rc = SXERR_CORRUPT; /* * Try to recover by examing the next central directory record. * Dont worry here,there is no risk of an infinite loop since * the buffer size is delimited. */ /* pName->nByte = 0; nComment = 0; pName->nExtra = 0 */ goto update; } /* * entry name length */ SyLittleEndianUnpack16((sxu16 *)&pName->nByte,&zCentral[28],sizeof(sxu16)); if( pName->nByte > SXI16_HIGH /* SXU16_HIGH */){ rc = SXERR_BIG; goto update; } /* Extra information */ SyLittleEndianUnpack16(&pEntry->nExtra,&zCentral[30],sizeof(sxu16)); /* Comment length */ SyLittleEndianUnpack16(&nComment,&zCentral[32],sizeof(sxu16)); /* Compression method 0 == stored / 8 == deflated */ rc = SyLittleEndianUnpack16(&pEntry->nComprMeth,&zCentral[10],sizeof(sxu16)); /* DOS Timestamp */ SyLittleEndianUnpack16(&nDosTime,&zCentral[12],sizeof(sxu16)); SyLittleEndianUnpack16(&nDosDate,&zCentral[14],sizeof(sxu16)); SyDosTimeFormat((nDosDate << 16 | nDosTime),&pEntry->sFmt); /* Little hack to fix month index */ pEntry->sFmt.tm_mon--; /* CRC32 */ rc = SyLittleEndianUnpack32(&pEntry->nCrc,&zCentral[16],sizeof(sxu32)); /* Content size before compression */ rc = SyLittleEndianUnpack32(&pEntry->nByte,&zCentral[24],sizeof(sxu32)); if( pEntry->nByte > SXI32_HIGH ){ rc = SXERR_BIG; goto update; } /* * Content size after compression. * Note that if the file is stored pEntry->nByte should be equal to pEntry->nByteCompr */ rc = SyLittleEndianUnpack32(&pEntry->nByteCompr,&zCentral[20],sizeof(sxu32)); if( pEntry->nByteCompr > SXI32_HIGH ){ rc = SXERR_BIG; goto update; } /* Finally grab the contents offset */ SyLittleEndianUnpack32(&pEntry->nOfft,&zCentral[42],sizeof(sxu32)); if( pEntry->nOfft > SXI32_HIGH ){ rc = SXERR_BIG; goto update; } rc = SXRET_OK; update: /* Update the offset to point to the next central directory record */ *pNextOffset = SXZIP_CENTRAL_HDRSZ + pName->nByte + pEntry->nExtra + nComment; return rc; /* Report failure or success */ } static sxi32 ZipFixOffset(SyArchiveEntry *pEntry,void *pSrc) { sxu16 nExtra,nNameLen; unsigned char *zHdr; nExtra = nNameLen = 0; zHdr = (unsigned char *)pSrc; zHdr = &zHdr[pEntry->nOfft]; if( SyMemcmp(zHdr,"PK\003\004",sizeof(sxu32)) != 0 ){ return SXERR_CORRUPT; } SyLittleEndianUnpack16(&nNameLen,&zHdr[26],sizeof(sxu16)); SyLittleEndianUnpack16(&nExtra,&zHdr[28],sizeof(sxu16)); /* Fix contents offset */ pEntry->nOfft += SXZIP_LOCAL_HDRSZ + nExtra + nNameLen; return SXRET_OK; } /* * Extract all valid entries from the central directory */ static sxi32 ZipExtract(SyArchive *pArch,const unsigned char *zCentral,sxu32 nLen,void *pSrc) { SyArchiveEntry *pEntry,*pDup; const unsigned char *zEnd ; /* End of central directory */ sxu32 nIncr,nOfft; /* Central Offset */ SyString *pName; /* Entry name */ char *zName; sxi32 rc; nOfft = nIncr = 0; zEnd = &zCentral[nLen]; for(;;){ if( &zCentral[nOfft] >= zEnd ){ break; } /* Add a new entry */ pEntry = (SyArchiveEntry *)SyMemBackendPoolAlloc(pArch->pAllocator,sizeof(SyArchiveEntry)); if( pEntry == 0 ){ break; } SyZero(pEntry,sizeof(SyArchiveEntry)); pEntry->nMagic = SXARCH_MAGIC; nIncr = 0; rc = GetCentralDirectoryEntry(&(*pArch),pEntry,&zCentral[nOfft],&nIncr); if( rc == SXRET_OK ){ /* Fix the starting record offset so we can access entry contents correctly */ rc = ZipFixOffset(pEntry,pSrc); } if(rc != SXRET_OK ){ sxu32 nJmp = 0; SyMemBackendPoolFree(pArch->pAllocator,pEntry); /* Try to recover by brute-forcing for a valid central directory record */ if( SXRET_OK == SyBlobSearch((const void *)&zCentral[nOfft + nIncr],(sxu32)(zEnd - &zCentral[nOfft + nIncr]), (const void *)"PK\001\002",sizeof(sxu32),&nJmp)){ nOfft += nIncr + nJmp; /* Check next entry */ continue; } break; /* Giving up,archive is hopelessly corrupted */ } pName = &pEntry->sFileName; pName->zString = (const char *)&zCentral[nOfft + SXZIP_CENTRAL_HDRSZ]; if( pName->nByte <= 0 || ( pEntry->nByte <= 0 && pName->zString[pName->nByte - 1] != '/') ){ /* Ignore zero length records (except folders) and records without names */ SyMemBackendPoolFree(pArch->pAllocator,pEntry); nOfft += nIncr; /* Check next entry */ continue; } zName = SyMemBackendStrDup(pArch->pAllocator,pName->zString,pName->nByte); if( zName == 0 ){ SyMemBackendPoolFree(pArch->pAllocator,pEntry); nOfft += nIncr; /* Check next entry */ continue; } pName->zString = (const char *)zName; /* Check for duplicates */ rc = ArchiveHashGetEntry(&(*pArch),pName->zString,pName->nByte,&pDup); if( rc == SXRET_OK ){ /* Another entry with the same name exists ; link them together */ pEntry->pNextName = pDup->pNextName; pDup->pNextName = pEntry; pDup->nDup++; }else{ /* Insert in hashtable */ ArchiveHashInstallEntry(pArch,pEntry); } nOfft += nIncr; /* Check next record */ } pArch->pCursor = pArch->pList; return pArch->nLoaded > 0 ? SXRET_OK : SXERR_EMPTY; } PH7_PRIVATE sxi32 SyZipExtractFromBuf(SyArchive *pArch,const char *zBuf,sxu32 nLen) { const unsigned char *zCentral,*zEnd; sxi32 rc; #if defined(UNTRUST) if( SXARCH_INVALID(pArch) || zBuf == 0 ){ return SXERR_INVALID; } #endif /* The miminal size of a zip archive: * LOCAL_HDR_SZ + CENTRAL_HDR_SZ + END_OF_CENTRAL_HDR_SZ * 30 46 22 */ if( nLen < SXZIP_LOCAL_HDRSZ + SXZIP_CENTRAL_HDRSZ + SXZIP_END_CENTRAL_HDRSZ ){ return SXERR_CORRUPT; /* Don't bother processing return immediately */ } zEnd = (unsigned char *)&zBuf[nLen - SXZIP_END_CENTRAL_HDRSZ]; /* Find the end of central directory */ while( ((sxu32)((unsigned char *)&zBuf[nLen] - zEnd) < (SXZIP_END_CENTRAL_HDRSZ + SXI16_HIGH)) && zEnd > (unsigned char *)zBuf && SyMemcmp(zEnd,"PK\005\006",sizeof(sxu32)) != 0 ){ zEnd--; } /* Parse the end of central directory */ rc = ParseEndOfCentralDirectory(&(*pArch),zEnd); if( rc != SXRET_OK ){ return rc; } /* Find the starting offset of the central directory */ zCentral = &zEnd[-(sxi32)pArch->nCentralSize]; if( zCentral <= (unsigned char *)zBuf || SyMemcmp(zCentral,"PK\001\002",sizeof(sxu32)) != 0 ){ if( pArch->nCentralOfft >= nLen ){ /* Corrupted central directory offset */ return SXERR_CORRUPT; } zCentral = (unsigned char *)&zBuf[pArch->nCentralOfft]; if( SyMemcmp(zCentral,"PK\001\002",sizeof(sxu32)) != 0 ){ /* Corrupted zip archive */ return SXERR_CORRUPT; } /* Fall thru and extract all valid entries from the central directory */ } rc = ZipExtract(&(*pArch),zCentral,(sxu32)(zEnd - zCentral),(void *)zBuf); return rc; } /* * Default comparison function. */ static sxi32 ArchiveHashCmp(const SyString *pStr1,const SyString *pStr2) { sxi32 rc; rc = SyStringCmp(pStr1,pStr2,SyMemcmp); return rc; } PH7_PRIVATE sxi32 SyArchiveInit(SyArchive *pArch,SyMemBackend *pAllocator,ProcHash xHash,ProcRawStrCmp xCmp) { SyArchiveEntry **apHash; #if defined(UNTRUST) if( pArch == 0 ){ return SXERR_EMPTY; } #endif SyZero(pArch,sizeof(SyArchive)); /* Allocate a new hashtable */ apHash = (SyArchiveEntry **)SyMemBackendAlloc(&(*pAllocator),SXARCHIVE_HASH_SIZE * sizeof(SyArchiveEntry *)); if( apHash == 0){ return SXERR_MEM; } SyZero(apHash,SXARCHIVE_HASH_SIZE * sizeof(SyArchiveEntry *)); pArch->apHash = apHash; pArch->xHash = xHash ? xHash : SyBinHash; pArch->xCmp = xCmp ? xCmp : ArchiveHashCmp; pArch->nSize = SXARCHIVE_HASH_SIZE; pArch->pAllocator = &(*pAllocator); pArch->nMagic = SXARCH_MAGIC; return SXRET_OK; } static sxi32 ArchiveReleaseEntry(SyMemBackend *pAllocator,SyArchiveEntry *pEntry) { SyArchiveEntry *pDup = pEntry->pNextName; SyArchiveEntry *pNextDup; /* Release duplicates first since there are not stored in the hashtable */ for(;;){ if( pEntry->nDup == 0 ){ break; } pNextDup = pDup->pNextName; pDup->nMagic = 0x2661; SyMemBackendFree(pAllocator,(void *)SyStringData(&pDup->sFileName)); SyMemBackendPoolFree(pAllocator,pDup); pDup = pNextDup; pEntry->nDup--; } pEntry->nMagic = 0x2661; SyMemBackendFree(pAllocator,(void *)SyStringData(&pEntry->sFileName)); SyMemBackendPoolFree(pAllocator,pEntry); return SXRET_OK; } PH7_PRIVATE sxi32 SyArchiveRelease(SyArchive *pArch) { SyArchiveEntry *pEntry,*pNext; pEntry = pArch->pList; for(;;){ if( pArch->nLoaded < 1 ){ break; } pNext = pEntry->pNext; MACRO_LD_REMOVE(pArch->pList,pEntry); ArchiveReleaseEntry(pArch->pAllocator,pEntry); pEntry = pNext; pArch->nLoaded--; } SyMemBackendFree(pArch->pAllocator,pArch->apHash); pArch->pCursor = 0; pArch->nMagic = 0x2626; return SXRET_OK; } PH7_PRIVATE sxi32 SyArchiveResetLoopCursor(SyArchive *pArch) { pArch->pCursor = pArch->pList; return SXRET_OK; } PH7_PRIVATE sxi32 SyArchiveGetNextEntry(SyArchive *pArch,SyArchiveEntry **ppEntry) { SyArchiveEntry *pNext; if( pArch->pCursor == 0 ){ /* Rewind the cursor */ pArch->pCursor = pArch->pList; return SXERR_EOF; } *ppEntry = pArch->pCursor; pNext = pArch->pCursor->pNext; /* Advance the cursor to the next entry */ pArch->pCursor = pNext; return SXRET_OK; } #endif /* PH7_DISABLE_BUILTIN_FUNC */ /* * Psuedo Random Number Generator (PRNG) * @authors: SQLite authors * @status: Public Domain * NOTE: * Nothing in this file or anywhere else in the library does any kind of * encryption.The RC4 algorithm is being used as a PRNG (pseudo-random * number generator) not as an encryption device. */ #define SXPRNG_MAGIC 0x13C4 #ifdef __UNIXES__ #include #include #include #include #include #include #include #endif static sxi32 SyOSUtilRandomSeed(void *pBuf,sxu32 nLen,void *pUnused) { char *zBuf = (char *)pBuf; #ifdef __WINNT__ DWORD nProcessID; /* Yes,keep it uninitialized when compiling using the MinGW32 builds tools */ #elif defined(__UNIXES__) pid_t pid; int fd; #else char zGarbage[128]; /* Yes,keep this buffer uninitialized */ #endif SXUNUSED(pUnused); #ifdef __WINNT__ #ifndef __MINGW32__ nProcessID = GetProcessId(GetCurrentProcess()); #endif SyMemcpy((const void *)&nProcessID,zBuf,SXMIN(nLen,sizeof(DWORD))); if( (sxu32)(&zBuf[nLen] - &zBuf[sizeof(DWORD)]) >= sizeof(SYSTEMTIME) ){ GetSystemTime((LPSYSTEMTIME)&zBuf[sizeof(DWORD)]); } #elif defined(__UNIXES__) fd = open("/dev/urandom",O_RDONLY); if (fd >= 0 ){ if( read(fd,zBuf,nLen) > 0 ){ close(fd); return SXRET_OK; } /* FALL THRU */ } close(fd); pid = getpid(); SyMemcpy((const void *)&pid,zBuf,SXMIN(nLen,sizeof(pid_t))); if( &zBuf[nLen] - &zBuf[sizeof(pid_t)] >= (int)sizeof(struct timeval) ){ gettimeofday((struct timeval *)&zBuf[sizeof(pid_t)],0); } #else /* Fill with uninitialized data */ SyMemcpy(zGarbage,zBuf,SXMIN(nLen,sizeof(zGarbage))); #endif return SXRET_OK; } PH7_PRIVATE sxi32 SyRandomnessInit(SyPRNGCtx *pCtx,ProcRandomSeed xSeed,void * pUserData) { char zSeed[256]; sxu8 t; sxi32 rc; sxu32 i; if( pCtx->nMagic == SXPRNG_MAGIC ){ return SXRET_OK; /* Already initialized */ } /* Initialize the state of the random number generator once, ** the first time this routine is called.The seed value does ** not need to contain a lot of randomness since we are not ** trying to do secure encryption or anything like that... */ if( xSeed == 0 ){ xSeed = SyOSUtilRandomSeed; } rc = xSeed(zSeed,sizeof(zSeed),pUserData); if( rc != SXRET_OK ){ return rc; } pCtx->i = pCtx->j = 0; for(i=0; i < SX_ARRAYSIZE(pCtx->s) ; i++){ pCtx->s[i] = (unsigned char)i; } for(i=0; i < sizeof(zSeed) ; i++){ pCtx->j += pCtx->s[i] + zSeed[i]; t = pCtx->s[pCtx->j]; pCtx->s[pCtx->j] = pCtx->s[i]; pCtx->s[i] = t; } pCtx->nMagic = SXPRNG_MAGIC; return SXRET_OK; } /* * Get a single 8-bit random value using the RC4 PRNG. */ static sxu8 randomByte(SyPRNGCtx *pCtx) { sxu8 t; /* Generate and return single random byte */ pCtx->i++; t = pCtx->s[pCtx->i]; pCtx->j += t; pCtx->s[pCtx->i] = pCtx->s[pCtx->j]; pCtx->s[pCtx->j] = t; t += pCtx->s[pCtx->i]; return pCtx->s[t]; } PH7_PRIVATE sxi32 SyRandomness(SyPRNGCtx *pCtx,void *pBuf,sxu32 nLen) { unsigned char *zBuf = (unsigned char *)pBuf; unsigned char *zEnd = &zBuf[nLen]; #if defined(UNTRUST) if( pCtx == 0 || pBuf == 0 || nLen <= 0 ){ return SXERR_EMPTY; } #endif if(pCtx->nMagic != SXPRNG_MAGIC ){ return SXERR_CORRUPT; } for(;;){ if( zBuf >= zEnd ){break;} zBuf[0] = randomByte(pCtx); zBuf++; if( zBuf >= zEnd ){break;} zBuf[0] = randomByte(pCtx); zBuf++; if( zBuf >= zEnd ){break;} zBuf[0] = randomByte(pCtx); zBuf++; if( zBuf >= zEnd ){break;} zBuf[0] = randomByte(pCtx); zBuf++; } return SXRET_OK; } #ifndef PH7_DISABLE_BUILTIN_FUNC #ifndef PH7_DISABLE_HASH_FUNC /* SyRunTimeApi: sxhash.c */ /* * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest.This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. * * To compute the message digest of a chunk of bytes, declare an * MD5Context structure, pass it to MD5Init, call MD5Update as * needed on buffers full of bytes, and then call MD5Final, which * will fill a supplied 16-byte array with the digest. */ #define SX_MD5_BINSZ 16 #define SX_MD5_HEXSZ 32 /* * Note: this code is harmless on little-endian machines. */ static void byteReverse (unsigned char *buf, unsigned longs) { sxu32 t; do { t = (sxu32)((unsigned)buf[3]<<8 | buf[2]) << 16 | ((unsigned)buf[1]<<8 | buf[0]); *(sxu32*)buf = t; buf += 4; } while (--longs); } /* The four core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ #ifdef F1 #undef F1 #endif #ifdef F2 #undef F2 #endif #ifdef F3 #undef F3 #endif #ifdef F4 #undef F4 #endif #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm.*/ #define SX_MD5STEP(f, w, x, y, z, data, s) \ ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data.MD5Update blocks * the data and converts bytes into longwords for this routine. */ static void MD5Transform(sxu32 buf[4], const sxu32 in[16]) { register sxu32 a, b, c, d; a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; SX_MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7); SX_MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); SX_MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); SX_MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); SX_MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7); SX_MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); SX_MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); SX_MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); SX_MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7); SX_MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); SX_MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); SX_MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); SX_MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7); SX_MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); SX_MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); SX_MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); SX_MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5); SX_MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9); SX_MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); SX_MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); SX_MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5); SX_MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9); SX_MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); SX_MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); SX_MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5); SX_MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9); SX_MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); SX_MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); SX_MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5); SX_MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9); SX_MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); SX_MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); SX_MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4); SX_MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); SX_MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); SX_MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); SX_MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4); SX_MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); SX_MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); SX_MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); SX_MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4); SX_MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); SX_MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); SX_MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); SX_MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4); SX_MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); SX_MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); SX_MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); SX_MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6); SX_MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); SX_MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); SX_MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); SX_MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6); SX_MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); SX_MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); SX_MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); SX_MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6); SX_MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); SX_MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); SX_MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); SX_MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6); SX_MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); SX_MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); SX_MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ PH7_PRIVATE void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len) { sxu32 t; /* Update bitcount */ t = ctx->bits[0]; if ((ctx->bits[0] = t + ((sxu32)len << 3)) < t) ctx->bits[1]++; /* Carry from low to high */ ctx->bits[1] += len >> 29; t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ /* Handle any leading odd-sized chunks */ if ( t ) { unsigned char *p = (unsigned char *)ctx->in + t; t = 64-t; if (len < t) { SyMemcpy(buf,p,len); return; } SyMemcpy(buf,p,t); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (sxu32*)ctx->in); buf += t; len -= t; } /* Process data in 64-byte chunks */ while (len >= 64) { SyMemcpy(buf,ctx->in,64); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (sxu32*)ctx->in); buf += 64; len -= 64; } /* Handle any remaining bytes of data.*/ SyMemcpy(buf,ctx->in,len); } /* * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ PH7_PRIVATE void MD5Final(unsigned char digest[16], MD5Context *ctx){ unsigned count; unsigned char *p; /* Compute number of bytes mod 64 */ count = (ctx->bits[0] >> 3) & 0x3F; /* Set the first char of padding to 0x80.This is safe since there is always at least one byte free */ p = ctx->in + count; *p++ = 0x80; /* Bytes of padding needed to make 64 bytes */ count = 64 - 1 - count; /* Pad out to 56 mod 64 */ if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */ SyZero(p,count); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (sxu32*)ctx->in); /* Now fill the next block with 56 bytes */ SyZero(ctx->in,56); } else { /* Pad block to 56 bytes */ SyZero(p,count-8); } byteReverse(ctx->in, 14); /* Append length in bits and transform */ ((sxu32*)ctx->in)[ 14 ] = ctx->bits[0]; ((sxu32*)ctx->in)[ 15 ] = ctx->bits[1]; MD5Transform(ctx->buf, (sxu32*)ctx->in); byteReverse((unsigned char *)ctx->buf, 4); SyMemcpy(ctx->buf,digest,0x10); SyZero(ctx,sizeof(ctx)); /* In case it's sensitive */ } #undef F1 #undef F2 #undef F3 #undef F4 PH7_PRIVATE sxi32 MD5Init(MD5Context *pCtx) { pCtx->buf[0] = 0x67452301; pCtx->buf[1] = 0xefcdab89; pCtx->buf[2] = 0x98badcfe; pCtx->buf[3] = 0x10325476; pCtx->bits[0] = 0; pCtx->bits[1] = 0; return SXRET_OK; } PH7_PRIVATE sxi32 SyMD5Compute(const void *pIn,sxu32 nLen,unsigned char zDigest[16]) { MD5Context sCtx; MD5Init(&sCtx); MD5Update(&sCtx,(const unsigned char *)pIn,nLen); MD5Final(zDigest,&sCtx); return SXRET_OK; } /* * SHA-1 in C * By Steve Reid * Status: Public Domain */ /* * blk0() and blk() perform the initial expand. * I got the idea of expanding during the round function from SSLeay * * blk0le() for little-endian and blk0be() for big-endian. */ #if __GNUC__ && (defined(__i386__) || defined(__x86_64__)) /* * GCC by itself only generates left rotates. Use right rotates if * possible to be kinder to dinky implementations with iterative rotate * instructions. */ #define SHA_ROT(op, x, k) \ ({ unsigned int y; asm(op " %1,%0" : "=r" (y) : "I" (k), "0" (x)); y; }) #define rol(x,k) SHA_ROT("roll", x, k) #define ror(x,k) SHA_ROT("rorl", x, k) #else /* Generic C equivalent */ #define SHA_ROT(x,l,r) ((x) << (l) | (x) >> (r)) #define rol(x,k) SHA_ROT(x,k,32-(k)) #define ror(x,k) SHA_ROT(x,32-(k),k) #endif #define blk0le(i) (block[i] = (ror(block[i],8)&0xFF00FF00) \ |(rol(block[i],8)&0x00FF00FF)) #define blk0be(i) block[i] #define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \ ^block[(i+2)&15]^block[i&15],1)) /* * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1 * * Rl0() for little-endian and Rb0() for big-endian. Endianness is * determined at run-time. */ #define Rl0(v,w,x,y,z,i) \ z+=((w&(x^y))^y)+blk0le(i)+0x5A827999+rol(v,5);w=ror(w,2); #define Rb0(v,w,x,y,z,i) \ z+=((w&(x^y))^y)+blk0be(i)+0x5A827999+rol(v,5);w=ror(w,2); #define R1(v,w,x,y,z,i) \ z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=ror(w,2); #define R2(v,w,x,y,z,i) \ z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=ror(w,2); #define R3(v,w,x,y,z,i) \ z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=ror(w,2); #define R4(v,w,x,y,z,i) \ z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=ror(w,2); /* * Hash a single 512-bit block. This is the core of the algorithm. */ #define a qq[0] #define b qq[1] #define c qq[2] #define d qq[3] #define e qq[4] static void SHA1Transform(unsigned int state[5], const unsigned char buffer[64]) { unsigned int qq[5]; /* a, b, c, d, e; */ static int one = 1; unsigned int block[16]; SyMemcpy(buffer,(void *)block,64); SyMemcpy(state,qq,5*sizeof(unsigned int)); /* Copy context->state[] to working vars */ /* a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; */ /* 4 rounds of 20 operations each. Loop unrolled. */ if( 1 == *(unsigned char*)&one ){ 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); 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); 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); 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); }else{ 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); 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); 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); 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); } 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); /* Add the working vars back into context.state[] */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; } #undef a #undef b #undef c #undef d #undef e /* * SHA1Init - Initialize new context */ PH7_PRIVATE void SHA1Init(SHA1Context *context){ /* SHA1 initialization constants */ context->state[0] = 0x67452301; context->state[1] = 0xEFCDAB89; context->state[2] = 0x98BADCFE; context->state[3] = 0x10325476; context->state[4] = 0xC3D2E1F0; context->count[0] = context->count[1] = 0; } /* * Run your data through this. */ PH7_PRIVATE void SHA1Update(SHA1Context *context,const unsigned char *data,unsigned int len){ unsigned int i, j; j = context->count[0]; if ((context->count[0] += len << 3) < j) context->count[1] += (len>>29)+1; j = (j >> 3) & 63; if ((j + len) > 63) { (void)SyMemcpy(data,&context->buffer[j], (i = 64-j)); SHA1Transform(context->state, context->buffer); for ( ; i + 63 < len; i += 64) SHA1Transform(context->state, &data[i]); j = 0; } else { i = 0; } (void)SyMemcpy(&data[i],&context->buffer[j],len - i); } /* * Add padding and return the message digest. */ PH7_PRIVATE void SHA1Final(SHA1Context *context, unsigned char digest[20]){ unsigned int i; unsigned char finalcount[8]; for (i = 0; i < 8; i++) { finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ } SHA1Update(context, (const unsigned char *)"\200", 1); while ((context->count[0] & 504) != 448) SHA1Update(context, (const unsigned char *)"\0", 1); SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ if (digest) { for (i = 0; i < 20; i++) digest[i] = (unsigned char) ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); } } #undef Rl0 #undef Rb0 #undef R1 #undef R2 #undef R3 #undef R4 PH7_PRIVATE sxi32 SySha1Compute(const void *pIn,sxu32 nLen,unsigned char zDigest[20]) { SHA1Context sCtx; SHA1Init(&sCtx); SHA1Update(&sCtx,(const unsigned char *)pIn,nLen); SHA1Final(&sCtx,zDigest); return SXRET_OK; } static const sxu32 crc32_table[] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, }; #define CRC32C(c,d) (c = ( crc32_table[(c ^ (d)) & 0xFF] ^ (c>>8) ) ) static sxu32 SyCrc32Update(sxu32 crc32,const void *pSrc,sxu32 nLen) { register unsigned char *zIn = (unsigned char *)pSrc; unsigned char *zEnd; if( zIn == 0 ){ return crc32; } zEnd = &zIn[nLen]; for(;;){ if(zIn >= zEnd ){ break; } CRC32C(crc32,zIn[0]); zIn++; if(zIn >= zEnd ){ break; } CRC32C(crc32,zIn[0]); zIn++; if(zIn >= zEnd ){ break; } CRC32C(crc32,zIn[0]); zIn++; if(zIn >= zEnd ){ break; } CRC32C(crc32,zIn[0]); zIn++; } return crc32; } PH7_PRIVATE sxu32 SyCrc32(const void *pSrc,sxu32 nLen) { return SyCrc32Update(SXU32_HIGH,pSrc,nLen); } #endif /* PH7_DISABLE_HASH_FUNC */ #endif /* PH7_DISABLE_BUILTIN_FUNC */ #ifndef PH7_DISABLE_BUILTIN_FUNC PH7_PRIVATE sxi32 SyBinToHexConsumer(const void *pIn,sxu32 nLen,ProcConsumer xConsumer,void *pConsumerData) { static const unsigned char zHexTab[] = "0123456789abcdef"; const unsigned char *zIn,*zEnd; unsigned char zOut[3]; sxi32 rc; #if defined(UNTRUST) if( pIn == 0 || xConsumer == 0 ){ return SXERR_EMPTY; } #endif zIn = (const unsigned char *)pIn; zEnd = &zIn[nLen]; for(;;){ if( zIn >= zEnd ){ break; } zOut[0] = zHexTab[zIn[0] >> 4]; zOut[1] = zHexTab[zIn[0] & 0x0F]; rc = xConsumer((const void *)zOut,sizeof(char)*2,pConsumerData); if( rc != SXRET_OK ){ return rc; } zIn++; } return SXRET_OK; } #endif /* PH7_DISABLE_BUILTIN_FUNC */