/*
 * 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 <chm@symisc.net> $ */
/*
 * 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 <Windows.h>
#else
	#include <stdlib.h>
#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 <pthread.h>
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 < nLen ; n += 4) {
		w = aBase64Trans[zB64[n] & 0x7F];
		x = aBase64Trans[zB64[n + 1] & 0x7F];
		y = aBase64Trans[zB64[n + 2] & 0x7F];
		z = aBase64Trans[zB64[n + 3] & 0x7F];
		zOut[0] = ((w << 2) & 0xFC) | ((x >> 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 && precision < width - (prefix != 0)) {
					precision = width - (prefix != 0);
				}
				bufpt = &buf[SXFMT_BUFSIZ - 1];
				{
					register const char *cset;      /* Use registers for speed */
					register int base;
					cset = infop->charset;
					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 + precision < SXFMT_BUFSIZ - 30) {
					flag_dp = (precision > 0 || 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++) = '-';    /* sign of exp */
							exp = -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 < precision; idx++) {
						buf[idx] = (char)c;
					}
					length = precision;
				} else {
					length = 1;
				}
				bufpt = buf;
				break;
			case SXFMT_STRING:
				bufpt = va_arg(ap, char *);
				if(bufpt == 0) {
					bufpt = " ";
					length = (int)sizeof(" ") - 1;
					break;
				}
				length = precision;
				if(precision < 0) {
					/* Symisc extension */
					length = (int)SyStrlen(bufpt);
				}
				if(precision >= 0 && precision < length) {
					length = precision;
				}
				break;
			case SXFMT_RAWSTR: {
					/* Symisc extension */
					SyString *pStr = va_arg(ap, SyString *);
					if(pStr == 0 || pStr->zString == 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 <chm@symisc.net>
* @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 <http://www.sqlite.org/>
 * @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 <sys/types.h>
	#include <sys/stat.h>
	#include <fcntl.h>
	#include <unistd.h>
	#include <errno.h>
	#include <time.h>
	#include <sys/time.h>
#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<<s | 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 <steve@edmweb.com>
 * 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 */