Fix for UMR in CXML_Parser::GetCharRef.
[pdfium.git] / core / src / fxcrt / fx_basic_memmgr_mini.cpp
index f8385e2..8d48bab 100644 (file)
-// Copyright 2014 PDFium Authors. All rights reserved.\r
-// Use of this source code is governed by a BSD-style license that can be\r
-// found in the LICENSE file.\r
\r
-// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
-\r
-#include "../../include/fxcrt/fx_ext.h"\r
-#include "mem_int.h"\r
-#ifdef _FPDFAPI_MINI_\r
-static FX_MEMCONFIG g_MemConfig = {\r
-    1,\r
-    5,\r
-    8,\r
-    4,\r
-    12,\r
-    8,\r
-    2,\r
-    4,\r
-    32,\r
-    64,\r
-};\r
-#else\r
-static FX_MEMCONFIG g_MemConfig = {\r
-    1,\r
-    8,\r
-    24,\r
-    8,\r
-    32,\r
-    16,\r
-    4,\r
-    8,\r
-    128,\r
-    64,\r
-};\r
-#endif\r
-void FXMEM_SetConfig(const FX_MEMCONFIG* memConfig)\r
-{\r
-    g_MemConfig = *memConfig;\r
-}\r
-#ifdef __cplusplus\r
-extern "C" {\r
-#endif\r
-static void* FixedAlloc(FXMEM_SystemMgr* pMgr, size_t size, int flags)\r
-{\r
-    return ((CFXMEM_FixedMgr*)pMgr->user)->Alloc(size);\r
-}\r
-static void* FixedAllocDebug(FXMEM_SystemMgr* pMgr, size_t size, int flags, FX_LPCSTR file, int line)\r
-{\r
-    return ((CFXMEM_FixedMgr*)pMgr->user)->Alloc(size);\r
-}\r
-static void* FixedRealloc(FXMEM_SystemMgr* pMgr, void* pointer, size_t size, int flags)\r
-{\r
-    return ((CFXMEM_FixedMgr*)pMgr->user)->Realloc(pointer, size);\r
-}\r
-static void* FixedReallocDebug(FXMEM_SystemMgr* pMgr, void* pointer, size_t size, int flags, FX_LPCSTR file, int line)\r
-{\r
-    return ((CFXMEM_FixedMgr*)pMgr->user)->Realloc(pointer, size);\r
-}\r
-static void  FixedFree(FXMEM_SystemMgr* pMgr, void* pointer, int flags)\r
-{\r
-    ((CFXMEM_FixedMgr*)pMgr->user)->Free(pointer);\r
-}\r
-static void  FixedPurge(FXMEM_SystemMgr* pMgr)\r
-{\r
-    ((CFXMEM_FixedMgr*)pMgr->user)->Purge();\r
-}\r
-static void FixedCollectAll(FXMEM_SystemMgr* pMgr)\r
-{\r
-    ((CFXMEM_FixedMgr*)pMgr->user)->FreeAll();\r
-}\r
-#define FIXEDMEM_MINIMUMSIZE   (1024 * 1024 * 8)\r
-FXMEM_FoxitMgr* FXMEM_CreateMemoryMgr(size_t size, FX_BOOL extensible)\r
-{\r
-    if (size < FIXEDMEM_MINIMUMSIZE) {\r
-        size = FIXEDMEM_MINIMUMSIZE;\r
-    }\r
-    FX_LPVOID pMemory = malloc(size);\r
-    if (!pMemory) {\r
-        return NULL;\r
-    }\r
-    CFixedMgr_Proxy* pProxy = (CFixedMgr_Proxy*)pMemory;\r
-    size_t offsetSize = (sizeof(CFixedMgr_Proxy) + 15) / 16 * 16;\r
-    FXMEM_FoxitMgr* pFoxitMgr = pProxy->Initialize((FX_LPBYTE)pProxy + offsetSize, size - offsetSize, extensible);\r
-    if (!pFoxitMgr) {\r
-        free(pMemory);\r
-        return NULL;\r
-    }\r
-    g_pDefFoxitMgr = (CFX_MemoryMgr*)pFoxitMgr;\r
-    g_pDefFoxitMgr->m_pExternalMemory = pMemory;\r
-    return pFoxitMgr;\r
-}\r
-FXMEM_FoxitMgr* FXMEM_CreateFixedMgr(void* pMemory, size_t size, FXMEM_SystemMgr2* pSystemMgr)\r
-{\r
-    if (pMemory == NULL || size < FX_FIXEDMEM_PAGESIZE) {\r
-        return NULL;\r
-    }\r
-    if (!pSystemMgr && size >= FIXEDMEM_PROXYSIZE_1) {\r
-        CFixedMgr_Proxy* pProxy = (CFixedMgr_Proxy*)pMemory;\r
-        size_t offsetSize = (sizeof(CFixedMgr_Proxy) + 15) / 16 * 16;\r
-        return pProxy->Initialize((FX_LPBYTE)pProxy + offsetSize, size - offsetSize, FALSE);\r
-    }\r
-    CFXMEM_FixedMgr* pHeader = (CFXMEM_FixedMgr*)pMemory;\r
-    pHeader->Initialize(size);\r
-    pHeader->m_pExtender = pSystemMgr;\r
-    CFX_MemoryMgr* p = (CFX_MemoryMgr*)pHeader->Alloc(sizeof(CFX_MemoryMgr));\r
-    if (p == NULL) {\r
-        return NULL;\r
-    }\r
-    p->Init(&pHeader->m_SystemMgr);\r
-    return (FXMEM_FoxitMgr*)p;\r
-}\r
-size_t FXMEM_GetBlockSizeInFixedMgr(FXMEM_FoxitMgr* pFoxitMgr, void* ptr)\r
-{\r
-    return pFoxitMgr ? ((CFXMEM_FixedMgr*)((CFX_MemoryMgr*)pFoxitMgr)->m_pSystemMgr->user)->GetSize(ptr) : 0;\r
-}\r
-#ifdef __cplusplus\r
-}\r
-#endif\r
-const FX_MEMCONFIG g_ProxyMgr_MemConfigs[6] = {\r
-    {1,      2,      4,      0,      2,      2,   2,       0,       0,     0},\r
-    {1,      4,      8,      0,      2,      2,   2,       0,       0,     0},\r
-    {1,      4,      16,     4,      8,      8,   2,       1,       16,    16},\r
-    {1,      8,      24,     4,      12,     12,  4,       2,       32,    16},\r
-    {1,      8,      24,     8,      16,     16,  4,       2,       64,    32},\r
-    {1,      8,      24,     8,      24,     32,  4,       2,       128,   64},\r
-};\r
-const FX_MEMCONFIG*    FixedMgr_GetConfig(size_t nSize)\r
-{\r
-    int index = 5;\r
-    if (nSize <= FIXEDMEM_PROXYSIZE_0) {\r
-        index = 0;\r
-    } else if (nSize <= FIXEDMEM_PROXYSIZE_1) {\r
-        index = 1;\r
-    } else if (nSize <= FIXEDMEM_PROXYSIZE_2) {\r
-        index = 2;\r
-    } else if (nSize <= FIXEDMEM_PROXYSIZE_3) {\r
-        index = 3;\r
-    } else if (nSize <= FIXEDMEM_PROXYSIZE_4) {\r
-        index = 4;\r
-    }\r
-    return &g_ProxyMgr_MemConfigs[index];\r
-}\r
-FXMEM_FoxitMgr* CFixedMgr_Proxy::Initialize(FX_LPVOID pBuffer, size_t nSize, FX_BOOL bExtensible)\r
-{\r
-    FXSYS_assert(pBuffer != NULL && nSize >= FIXEDMEM_PROXYSIZE_1 - sizeof(CFixedMgr_Proxy));\r
-    FXMEM_SetConfig(FixedMgr_GetConfig(nSize));\r
-    m_SystemMgr.More = &CFixedMgr_Proxy::Common_More;\r
-    m_SystemMgr.Free = &CFixedMgr_Proxy::Common_Free;\r
-    m_pFixedPage = (CFXMEM_Page*)((FX_LPBYTE)pBuffer + FIXEDMEM_PROXYSIZE_0);\r
-    m_pFixedPage->Initialize(nSize - FIXEDMEM_PROXYSIZE_0);\r
-    m_pBuffer = pBuffer;\r
-    m_nSize = nSize;\r
-    m_bExtensible = bExtensible;\r
-    return FXMEM_CreateFixedMgr(pBuffer, FIXEDMEM_PROXYSIZE_0, &m_SystemMgr);\r
-}\r
-FX_BOOL CFixedMgr_Proxy::Common_More(FXMEM_SystemMgr2* pMgr, size_t alloc_size, void** new_memory, size_t* new_size)\r
-{\r
-    CFixedMgr_Proxy* pProxyMgr = (CFixedMgr_Proxy*)pMgr;\r
-    FXSYS_assert(pProxyMgr != NULL && pProxyMgr->m_pFixedPage != NULL);\r
-    *new_size = alloc_size;\r
-    *new_memory = pProxyMgr->m_pFixedPage->Alloc(alloc_size);\r
-    if (*new_memory == NULL && pProxyMgr->m_bExtensible) {\r
-        *new_memory = malloc(alloc_size);\r
-    }\r
-    return *new_memory != NULL;\r
-}\r
-void CFixedMgr_Proxy::Common_Free(FXMEM_SystemMgr2* pMgr, void* memory)\r
-{\r
-    CFixedMgr_Proxy* pProxyMgr = (CFixedMgr_Proxy*)pMgr;\r
-    FXSYS_assert(pProxyMgr != NULL && pProxyMgr->m_pFixedPage != NULL);\r
-    if (memory > pProxyMgr->m_pBuffer && memory < (FX_LPBYTE)pProxyMgr->m_pBuffer + pProxyMgr->m_nSize) {\r
-        pProxyMgr->m_pFixedPage->Free(memory);\r
-    } else if (pProxyMgr->m_bExtensible) {\r
-        free(memory);\r
-    }\r
-}\r
-void CFXMEM_Page::Initialize(size_t size)\r
-{\r
-    CFXMEM_Block *pFirstBlock = (CFXMEM_Block*)(this + 1);\r
-    m_nAvailSize = size - sizeof(CFXMEM_Page) - sizeof(CFXMEM_Block);\r
-    pFirstBlock->m_nBlockSize = m_nAvailSize;\r
-    pFirstBlock->m_pNextBlock = NULL;\r
-    m_AvailHead.m_nBlockSize = m_nAvailSize;\r
-    m_AvailHead.m_pNextBlock = pFirstBlock;\r
-    m_pLimitPos = (CFXMEM_Block*)((FX_LPBYTE)this + size);\r
-}\r
-FX_LPVOID CFXMEM_Page::Alloc(CFXMEM_Block* pPrevBlock, CFXMEM_Block* pNextBlock, size_t size, size_t oldsize)\r
-{\r
-    size_t gap = pNextBlock->m_nBlockSize - size;\r
-    if (gap <= 64 + sizeof(CFXMEM_Block)) {\r
-        pPrevBlock->m_pNextBlock = pNextBlock->m_pNextBlock;\r
-        m_nAvailSize -= pNextBlock->m_nBlockSize;\r
-    } else {\r
-        m_nAvailSize -= size + sizeof(CFXMEM_Block);\r
-        pNextBlock->m_nBlockSize = size;\r
-        CFXMEM_Block *pNewBlock = (CFXMEM_Block*)((FX_LPBYTE)(pNextBlock + 1) + size);\r
-        pNewBlock->m_nBlockSize = gap - sizeof(CFXMEM_Block);\r
-        pNewBlock->m_pNextBlock = pNextBlock->m_pNextBlock;\r
-        pPrevBlock->m_pNextBlock = pNewBlock;\r
-    }\r
-    return (FX_LPVOID)(pNextBlock + 1);\r
-}\r
-FX_LPVOID CFXMEM_Page::Alloc(size_t size)\r
-{\r
-    size_t oldsize = size;\r
-#if _FX_WORDSIZE_ == _FX_W64_\r
-    size = (size + 31) / 32 * 32;\r
-#else\r
-    size = (size + 7) / 8 * 8;\r
-#endif\r
-    if (m_nAvailSize < size) {\r
-        return NULL;\r
-    }\r
-    CFXMEM_Block *pNextBlock;\r
-    CFXMEM_Block *pPrevBlock = &m_AvailHead;\r
-    while (TRUE) {\r
-        pNextBlock = pPrevBlock->m_pNextBlock;\r
-        if (!pNextBlock) {\r
-            return NULL;\r
-        }\r
-        if (pNextBlock->m_nBlockSize >= size) {\r
-            break;\r
-        }\r
-        pPrevBlock = pNextBlock;\r
-    }\r
-    return Alloc(pPrevBlock, pNextBlock, size, oldsize);\r
-}\r
-FX_LPVOID CFXMEM_Page::Realloc(FX_LPVOID p, size_t oldSize, size_t newSize)\r
-{\r
-    FXSYS_assert(p > (FX_LPVOID)this && p < (FX_LPVOID)m_pLimitPos);\r
-    size_t oldnewSize = newSize;\r
-#if _FX_WORDSIZE_ == _FX_W64_\r
-    newSize = (newSize + 31) / 32 * 32;\r
-#else\r
-    newSize = (newSize + 7) / 8 * 8;\r
-#endif\r
-    CFXMEM_Block *pPrevBlock = &m_AvailHead;\r
-    CFXMEM_Block *pNextBlock, *pPrevPrev;\r
-    CFXMEM_Block *pBlock = (CFXMEM_Block*)p - 1;\r
-    pPrevPrev = NULL;\r
-    while (TRUE) {\r
-        pNextBlock = pPrevBlock->m_pNextBlock;\r
-        if (pNextBlock == NULL || pNextBlock > pBlock) {\r
-            break;\r
-        }\r
-        if (pPrevBlock != &m_AvailHead && (FX_LPBYTE)pNextBlock == (FX_LPBYTE)(pPrevBlock + 1) + pPrevBlock->m_nBlockSize) {\r
-            m_nAvailSize += sizeof(CFXMEM_Block);\r
-            pPrevBlock->m_nBlockSize += pNextBlock->m_nBlockSize + sizeof(CFXMEM_Block);\r
-            pPrevBlock->m_pNextBlock = pNextBlock->m_pNextBlock;\r
-        } else {\r
-            pPrevPrev = pPrevBlock;\r
-            pPrevBlock = pNextBlock;\r
-        }\r
-    }\r
-    if (pNextBlock) {\r
-        CFXMEM_Block* pCurBlock = pNextBlock->m_pNextBlock;\r
-        while ((FX_LPBYTE)pCurBlock == (FX_LPBYTE)(pNextBlock + 1) + pNextBlock->m_nBlockSize) {\r
-            m_nAvailSize += sizeof(CFXMEM_Block);\r
-            pNextBlock->m_nBlockSize += pCurBlock->m_nBlockSize + sizeof(CFXMEM_Block);\r
-            pCurBlock = pCurBlock->m_pNextBlock;\r
-            pNextBlock->m_pNextBlock = pCurBlock;\r
-        }\r
-    }\r
-    size_t size = 0;\r
-    FX_DWORD dwFlags = 0;\r
-    if (pPrevBlock != &m_AvailHead && (FX_LPBYTE)pBlock == (FX_LPBYTE)(pPrevBlock + 1) + pPrevBlock->m_nBlockSize) {\r
-        size += pPrevBlock->m_nBlockSize + oldSize + sizeof(CFXMEM_Block);\r
-        dwFlags |= 0x10;\r
-    }\r
-    if (pNextBlock && (FX_LPBYTE)pNextBlock == (FX_LPBYTE)p + oldSize) {\r
-        size += pNextBlock->m_nBlockSize + sizeof(CFXMEM_Block);\r
-        dwFlags |= 0x01;\r
-    }\r
-    if (size >= newSize) {\r
-        m_nAvailSize += pBlock->m_nBlockSize;\r
-        CFXMEM_Block* pCurBlock = pBlock;\r
-        if (dwFlags & 0x10) {\r
-            pCurBlock = pPrevBlock;\r
-            m_nAvailSize += sizeof(CFXMEM_Block);\r
-            pCurBlock->m_nBlockSize += pBlock->m_nBlockSize + sizeof(CFXMEM_Block);\r
-            pPrevBlock = pPrevPrev;\r
-        }\r
-        if (dwFlags & 0x01) {\r
-            m_nAvailSize += sizeof(CFXMEM_Block);\r
-            pCurBlock->m_nBlockSize += pNextBlock->m_nBlockSize + sizeof(CFXMEM_Block);\r
-            pCurBlock->m_pNextBlock = pNextBlock->m_pNextBlock;\r
-        }\r
-        if (pCurBlock != pBlock) {\r
-            FXSYS_memmove32((FX_LPVOID)(pCurBlock + 1), p, oldSize);\r
-        }\r
-        return Alloc(pPrevBlock, pCurBlock, newSize, oldnewSize);\r
-    }\r
-    return NULL;\r
-}\r
-void CFXMEM_Page::Free(FX_LPVOID p)\r
-{\r
-    FXSYS_assert(p > (FX_LPVOID)this && p < (FX_LPVOID)m_pLimitPos);\r
-    CFXMEM_Block *pPrevBlock = &m_AvailHead;\r
-    CFXMEM_Block *pNextBlock;\r
-    CFXMEM_Block *pBlock = (CFXMEM_Block*)p - 1;\r
-    m_nAvailSize += pBlock->m_nBlockSize;\r
-    while (TRUE) {\r
-        pNextBlock = pPrevBlock->m_pNextBlock;\r
-        if (pNextBlock == NULL || pNextBlock > pBlock) {\r
-            break;\r
-        }\r
-        if (pPrevBlock != &m_AvailHead && (FX_LPBYTE)pNextBlock == (FX_LPBYTE)(pPrevBlock + 1) + pPrevBlock->m_nBlockSize) {\r
-            m_nAvailSize += sizeof(CFXMEM_Block);\r
-            pPrevBlock->m_nBlockSize += pNextBlock->m_nBlockSize + sizeof(CFXMEM_Block);\r
-            pPrevBlock->m_pNextBlock = pNextBlock->m_pNextBlock;\r
-        } else {\r
-            pPrevBlock = pNextBlock;\r
-        }\r
-    }\r
-    while ((FX_LPBYTE)pNextBlock == (FX_LPBYTE)(pBlock + 1) + pBlock->m_nBlockSize) {\r
-        m_nAvailSize += sizeof(CFXMEM_Block);\r
-        pBlock->m_nBlockSize += pNextBlock->m_nBlockSize + sizeof(CFXMEM_Block);\r
-        pNextBlock = pNextBlock->m_pNextBlock;\r
-    }\r
-    pBlock->m_pNextBlock = pNextBlock;\r
-    if (pPrevBlock != &m_AvailHead && (FX_LPBYTE)pBlock == (FX_LPBYTE)(pPrevBlock + 1) + pPrevBlock->m_nBlockSize) {\r
-        m_nAvailSize += sizeof(CFXMEM_Block);\r
-        pPrevBlock->m_nBlockSize += pBlock->m_nBlockSize + sizeof(CFXMEM_Block);\r
-        pPrevBlock->m_pNextBlock = pBlock->m_pNextBlock;\r
-    } else {\r
-        FXSYS_assert(pPrevBlock != pBlock);\r
-        pPrevBlock->m_pNextBlock = pBlock;\r
-    }\r
-}\r
-void CFXMEM_Pages::Initialize(FX_LPBYTE pStart, size_t pageSize, size_t pages)\r
-{\r
-    m_pStartPage = m_pCurPage = (CFXMEM_Page*)pStart;\r
-    m_nPageSize = pageSize;\r
-    for (size_t n = 0; n < pages; n++) {\r
-        ((CFXMEM_Page*)pStart)->Initialize(pageSize);\r
-        pStart += pageSize;\r
-    }\r
-    m_pLimitPos = (CFXMEM_Page*)pStart;\r
-}\r
-FX_BOOL CFXMEM_Pages::IsEmpty() const\r
-{\r
-    if (m_pStartPage >= m_pLimitPos) {\r
-        return TRUE;\r
-    }\r
-    FX_LPBYTE pPage = (FX_LPBYTE)m_pStartPage;\r
-    while (pPage < (FX_LPBYTE)m_pLimitPos) {\r
-        if (!((CFXMEM_Page*)pPage)->IsEmpty()) {\r
-            return FALSE;\r
-        }\r
-        pPage += m_nPageSize;\r
-    }\r
-    return TRUE;\r
-}\r
-FX_LPVOID CFXMEM_Pages::Alloc(size_t size)\r
-{\r
-    CFXMEM_Page *pCurPage = m_pCurPage;\r
-    do {\r
-        FX_LPVOID p = m_pCurPage->Alloc(size);\r
-        if (p) {\r
-            return p;\r
-        }\r
-        m_pCurPage = (CFXMEM_Page*)((FX_LPBYTE)m_pCurPage + m_nPageSize);\r
-        if (m_pCurPage == m_pLimitPos) {\r
-            m_pCurPage = m_pStartPage;\r
-        }\r
-    } while (m_pCurPage != pCurPage);\r
-    return NULL;\r
-}\r
-FX_LPVOID CFXMEM_Pages::Realloc(FX_LPVOID p, size_t oldSize, size_t newSize)\r
-{\r
-    FXSYS_assert (p > (FX_LPVOID)m_pStartPage && p < (FX_LPVOID)m_pLimitPos);\r
-    CFXMEM_Page* pPage = (CFXMEM_Page*)((FX_LPBYTE)m_pStartPage + ((FX_LPBYTE)p - (FX_LPBYTE)m_pStartPage) / m_nPageSize * m_nPageSize);\r
-    return pPage->Realloc(p, oldSize, newSize);\r
-}\r
-void CFXMEM_Pages::Free(FX_LPVOID p)\r
-{\r
-    FXSYS_assert (p > (FX_LPVOID)m_pStartPage && p < (FX_LPVOID)m_pLimitPos);\r
-    CFXMEM_Page* pPage = (CFXMEM_Page*)((FX_LPBYTE)m_pStartPage + ((FX_LPBYTE)p - (FX_LPBYTE)m_pStartPage) / m_nPageSize * m_nPageSize);\r
-    pPage->Free(p);\r
-}\r
-void CFXMEM_Pool::Initialize(const FX_MEMCONFIG* pMemConfig, size_t size, size_t pageNum8Bytes, size_t pageNum16Bytes, size_t pageNum32Bytes, size_t pageNumMid)\r
-{\r
-    m_pPrevPool = NULL;\r
-    m_pNextPool = NULL;\r
-    m_bAlone = FALSE;\r
-    FX_LPBYTE pPage = (FX_LPBYTE)this + sizeof(CFXMEM_Pool);\r
-    size -= sizeof(CFXMEM_Pool);\r
-    m_8BytesPages.Initialize(pPage, pageNum8Bytes);\r
-    pPage += pageNum8Bytes * FX_FIXEDMEM_PAGESIZE;\r
-    size -= pageNum8Bytes * FX_FIXEDMEM_PAGESIZE;\r
-    m_16BytesPages.Initialize(pPage, pageNum16Bytes);\r
-    pPage += pageNum16Bytes * FX_FIXEDMEM_PAGESIZE;\r
-    size -= pageNum16Bytes * FX_FIXEDMEM_PAGESIZE;\r
-    m_32BytesPages.Initialize(pPage, pageNum32Bytes);\r
-    pPage += pageNum32Bytes * FX_FIXEDMEM_PAGESIZE;\r
-    size -= pageNum32Bytes * FX_FIXEDMEM_PAGESIZE;\r
-    m_MidPages.Initialize(pPage, pMemConfig->nPageSize_Mid * FX_FIXEDMEM_PAGESIZE, pageNumMid);\r
-    pPage += pageNumMid * pMemConfig->nPageSize_Mid * FX_FIXEDMEM_PAGESIZE;\r
-    size -= pageNumMid * pMemConfig->nPageSize_Mid * FX_FIXEDMEM_PAGESIZE;\r
-    if (size < FX_FIXEDMEM_MIDBLOCKSIZE) {\r
-        m_pLargePage = NULL;\r
-    } else {\r
-        m_pLargePage = (CFXMEM_Page*)pPage;\r
-        m_pLargePage->Initialize(size);\r
-    }\r
-    m_pLimitPos = pPage + size;\r
-}\r
-FX_BOOL CFXMEM_Pool::IsEmpty() const\r
-{\r
-    if (!m_8BytesPages.IsEmpty()) {\r
-        return FALSE;\r
-    }\r
-    if (!m_16BytesPages.IsEmpty()) {\r
-        return FALSE;\r
-    }\r
-    if (!m_32BytesPages.IsEmpty()) {\r
-        return FALSE;\r
-    }\r
-    if (!m_MidPages.IsEmpty()) {\r
-        return FALSE;\r
-    }\r
-    return !m_pLargePage || m_pLargePage->IsEmpty();\r
-}\r
-size_t CFXMEM_Pool::GetSize(FX_LPVOID p) const\r
-{\r
-    FXSYS_assert(p > (FX_LPVOID)this && p < (FX_LPVOID)m_pLimitPos);\r
-    if (p < (FX_LPVOID)m_8BytesPages.m_pLimitPos) {\r
-        return 8;\r
-    }\r
-    if (p < (FX_LPVOID)m_16BytesPages.m_pLimitPos) {\r
-        return 16;\r
-    }\r
-    if (p < (FX_LPVOID)m_32BytesPages.m_pLimitPos) {\r
-        return 32;\r
-    }\r
-    return ((CFXMEM_Block*)p - 1)->m_nBlockSize;\r
-}\r
-FX_LPVOID CFXMEM_Pool::Realloc(FX_LPVOID p, size_t oldSize, size_t newSize)\r
-{\r
-    FXSYS_assert(p > (FX_LPVOID)this && p < (FX_LPVOID)m_pLimitPos);\r
-    if (p > (FX_LPVOID)m_32BytesPages.m_pLimitPos) {\r
-        if (p < (FX_LPVOID)m_MidPages.m_pLimitPos) {\r
-            return m_MidPages.Realloc(p, oldSize, newSize);\r
-        } else if (m_pLargePage) {\r
-            return m_pLargePage->Realloc(p, oldSize, newSize);\r
-        }\r
-    }\r
-    return NULL;\r
-}\r
-void CFXMEM_Pool::Free(FX_LPVOID p)\r
-{\r
-    FXSYS_assert(p > (FX_LPVOID)this && p < (FX_LPVOID)m_pLimitPos);\r
-    if (p < (FX_LPVOID)m_32BytesPages.m_pLimitPos) {\r
-        if (p < (FX_LPVOID)m_8BytesPages.m_pLimitPos) {\r
-            m_8BytesPages.Free(p);\r
-        } else if (p < (FX_LPVOID)m_16BytesPages.m_pLimitPos) {\r
-            m_16BytesPages.Free(p);\r
-        } else {\r
-            m_32BytesPages.Free(p);\r
-        }\r
-        return;\r
-    } else if (p < (FX_LPVOID)m_MidPages.m_pLimitPos) {\r
-        m_MidPages.Free(p);\r
-    } else {\r
-        m_pLargePage->Free(p);\r
-    }\r
-}\r
-void CFXMEM_FixedMgr::Initialize(size_t size)\r
-{\r
-    m_MemConfig = g_MemConfig;\r
-    FXSYS_memset32(&m_SystemMgr, 0, sizeof m_SystemMgr);\r
-    m_SystemMgr.Alloc = FixedAlloc;\r
-    m_SystemMgr.AllocDebug = FixedAllocDebug;\r
-    m_SystemMgr.Free = FixedFree;\r
-    m_SystemMgr.Realloc = FixedRealloc;\r
-    m_SystemMgr.ReallocDebug = FixedReallocDebug;\r
-    m_SystemMgr.CollectAll = FixedCollectAll;\r
-    m_SystemMgr.Purge = FixedPurge;\r
-    m_SystemMgr.user = this;\r
-    size -= sizeof(CFXMEM_FixedMgr);\r
-    size_t nMidPages = 0;\r
-    if (m_MemConfig.nPageSize_Mid) {\r
-        nMidPages = (size - (m_MemConfig.nPageNum_Init8 + m_MemConfig.nPageNum_Init16 + m_MemConfig.nPageNum_Init32) * FX_FIXEDMEM_PAGESIZE) / (m_MemConfig.nPageSize_Mid * FX_FIXEDMEM_PAGESIZE);\r
-        if (nMidPages > m_MemConfig.nPageNum_InitMid) {\r
-            nMidPages = m_MemConfig.nPageNum_InitMid;\r
-        }\r
-    }\r
-    m_FirstPool.Initialize(&m_MemConfig, size, m_MemConfig.nPageNum_Init8, m_MemConfig.nPageNum_Init16, m_MemConfig.nPageNum_Init32, nMidPages);\r
-}\r
-FX_LPVOID CFXMEM_FixedMgr::Alloc16(CFXMEM_Pool **pp32Pool, size_t size)\r
-{\r
-    CFXMEM_Pool *pPool = &m_FirstPool;\r
-    do {\r
-        CFXMEM_16BytesPages &pages = pPool->m_16BytesPages;\r
-        if (pages.HasFreeBlock()) {\r
-            return pages.Alloc(size);\r
-        }\r
-        if (pp32Pool && pPool->m_32BytesPages.HasFreeBlock()) {\r
-            *pp32Pool = pPool;\r
-        }\r
-        pPool = pPool->m_pNextPool;\r
-    } while(pPool);\r
-    return NULL;\r
-}\r
-FX_LPVOID CFXMEM_FixedMgr::Alloc32(size_t size)\r
-{\r
-    if (size <= 8) {\r
-        CFXMEM_8BytesPages &pages = m_FirstPool.m_8BytesPages;\r
-        if (pages.HasFreeBlock()) {\r
-            return pages.Alloc(size);\r
-        }\r
-    }\r
-    CFXMEM_Pool *p32BytesPool;\r
-    if (size <= 16) {\r
-        p32BytesPool = NULL;\r
-        FX_LPVOID p = Alloc16(&p32BytesPool, size);\r
-        if (p) {\r
-            return p;\r
-        }\r
-    } else {\r
-        p32BytesPool = &m_FirstPool;\r
-    }\r
-    while (p32BytesPool) {\r
-        CFXMEM_32BytesPages &pages = p32BytesPool->m_32BytesPages;\r
-        if (pages.HasFreeBlock()) {\r
-            return pages.Alloc(size);\r
-        }\r
-        p32BytesPool = p32BytesPool->m_pNextPool;\r
-    }\r
-    return NULL;\r
-}\r
-FX_LPVOID CFXMEM_FixedMgr::AllocSmall(size_t size)\r
-{\r
-    FX_LPVOID p = Alloc32(size);\r
-    if (p) {\r
-        return p;\r
-    }\r
-    if (!m_pExtender) {\r
-        return NULL;\r
-    }\r
-    size_t requiredSize = (m_MemConfig.nPageNum_More16 + m_MemConfig.nPageNum_More32) * FX_FIXEDMEM_PAGESIZE;\r
-    if (!requiredSize) {\r
-        return NULL;\r
-    }\r
-    CFXMEM_Pool *pNewPool = NULL;\r
-    requiredSize += sizeof(CFXMEM_Pool);\r
-    size_t newSize = requiredSize;\r
-    if (!m_pExtender->More(m_pExtender, newSize, (void**)&pNewPool, &newSize)) {\r
-        return NULL;\r
-    }\r
-    size_t nMidPages = 0;\r
-    if (m_MemConfig.nPageSize_Mid) {\r
-        nMidPages = (newSize - requiredSize) / (m_MemConfig.nPageSize_Mid * FX_FIXEDMEM_PAGESIZE);\r
-        if (nMidPages > m_MemConfig.nPageNum_MoreMid) {\r
-            nMidPages = m_MemConfig.nPageNum_MoreMid;\r
-        }\r
-    }\r
-    pNewPool->Initialize(&m_MemConfig, newSize, 0, m_MemConfig.nPageNum_More16, m_MemConfig.nPageNum_More32, nMidPages);\r
-    pNewPool->m_pPrevPool = &m_FirstPool;\r
-    CFXMEM_Pool *pPool = m_FirstPool.m_pNextPool;\r
-    pNewPool->m_pNextPool = pPool;\r
-    if (pPool) {\r
-        pPool->m_pPrevPool = pNewPool;\r
-    }\r
-    m_FirstPool.m_pNextPool = pNewPool;\r
-    return Alloc32(size);\r
-}\r
-FX_LPVOID CFXMEM_FixedMgr::AllocMid(size_t size)\r
-{\r
-    CFXMEM_Pool *pPool = &m_FirstPool;\r
-    do {\r
-        CFXMEM_Pages &pages = pPool->m_MidPages;\r
-        if (pages.m_pLimitPos > pages.m_pStartPage) {\r
-            FX_LPVOID p = pages.Alloc(size);\r
-            if (p) {\r
-                return p;\r
-            }\r
-        }\r
-        pPool = pPool->m_pNextPool;\r
-    } while(pPool);\r
-    if (!m_pExtender) {\r
-        return NULL;\r
-    }\r
-    size_t newSize = m_MemConfig.nPageSize_Mid * FX_FIXEDMEM_PAGESIZE * m_MemConfig.nPageNum_MoreMid;\r
-    if (!newSize) {\r
-        return NULL;\r
-    }\r
-    CFXMEM_Pool *pNewPool = NULL;\r
-    newSize += sizeof(CFXMEM_Pool);\r
-    if (!m_pExtender->More(m_pExtender, newSize, (void**)&pNewPool, &newSize)) {\r
-        return NULL;\r
-    }\r
-    size_t nMidPages = (newSize - sizeof(CFXMEM_Pool)) / (m_MemConfig.nPageSize_Mid * FX_FIXEDMEM_PAGESIZE);\r
-    if (nMidPages > m_MemConfig.nPageNum_MoreMid) {\r
-        nMidPages = m_MemConfig.nPageNum_MoreMid;\r
-    }\r
-    pNewPool->Initialize(&m_MemConfig, newSize, 0, 0, 0, nMidPages);\r
-    pNewPool->m_pPrevPool = &m_FirstPool;\r
-    pPool = m_FirstPool.m_pNextPool;\r
-    pNewPool->m_pNextPool = pPool;\r
-    if (pPool) {\r
-        pPool->m_pPrevPool = pNewPool;\r
-    }\r
-    m_FirstPool.m_pNextPool = pNewPool;\r
-    return pNewPool->m_MidPages.Alloc(size);\r
-}\r
-FX_LPVOID CFXMEM_FixedMgr::AllocLarge(size_t size)\r
-{\r
-    CFXMEM_Pool *pPool = &m_FirstPool;\r
-    do {\r
-        if (!pPool->m_bAlone && pPool->m_pLargePage) {\r
-            FX_LPVOID p = pPool->m_pLargePage->Alloc(size);\r
-            if (p) {\r
-                return p;\r
-            }\r
-        }\r
-        pPool = pPool->m_pNextPool;\r
-    } while(pPool);\r
-    if (!m_pExtender || !m_MemConfig.nPageSize_Large) {\r
-        return NULL;\r
-    }\r
-    CFXMEM_Pool *pNewPool = NULL;\r
-#if _FX_WORDSIZE_ == _FX_W64_\r
-    size_t newSize = ((size + 31) / 32 * 32 + sizeof(CFXMEM_Pool) + sizeof(CFXMEM_Page) + sizeof(CFXMEM_Block) + 4095) / 4096 * 4096;\r
-#else\r
-    size_t newSize = (size + 7) / 8 * 8 + sizeof(CFXMEM_Pool) + sizeof(CFXMEM_Page) + sizeof(CFXMEM_Block);\r
-#endif\r
-    if (newSize < m_MemConfig.nPageSize_Large * FX_FIXEDMEM_PAGESIZE) {\r
-        newSize = m_MemConfig.nPageSize_Large * FX_FIXEDMEM_PAGESIZE;\r
-    }\r
-    if (!m_pExtender->More(m_pExtender, newSize, (void**)&pNewPool, &newSize)) {\r
-        return NULL;\r
-    }\r
-    pNewPool->Initialize(&m_MemConfig, newSize, 0, 0, 0, 0);\r
-    pNewPool->m_bAlone = size >= m_MemConfig.nPageSize_Alone * FX_FIXEDMEM_PAGESIZE;\r
-    pNewPool->m_pPrevPool = &m_FirstPool;\r
-    pPool = m_FirstPool.m_pNextPool;\r
-    pNewPool->m_pNextPool = pPool;\r
-    if (pPool) {\r
-        pPool->m_pPrevPool = pNewPool;\r
-    }\r
-    m_FirstPool.m_pNextPool = pNewPool;\r
-    return pNewPool->m_pLargePage->Alloc(size);\r
-}\r
-size_t CFXMEM_FixedMgr::GetSize(FX_LPVOID p) const\r
-{\r
-    const CFXMEM_Pool *pFind = &m_FirstPool;\r
-    do {\r
-        if (p > (FX_LPVOID)pFind && p < pFind->m_pLimitPos) {\r
-            return pFind->GetSize(p);\r
-        }\r
-        pFind = pFind->m_pNextPool;\r
-    } while (pFind);\r
-    return 0;\r
-}\r
-FX_LPVOID CFXMEM_FixedMgr::Alloc(size_t size)\r
-{\r
-    FX_LPVOID p;\r
-    if (size <= 32) {\r
-        p = AllocSmall(size);\r
-        if (p) {\r
-            return p;\r
-        }\r
-    }\r
-    if (size <= FX_FIXEDMEM_MIDBLOCKSIZE) {\r
-        p = AllocMid(size);\r
-        if (p) {\r
-            return p;\r
-        }\r
-    }\r
-    p = AllocLarge(size);\r
-    return p;\r
-}\r
-FX_LPVOID CFXMEM_FixedMgr::ReallocSmall(CFXMEM_Pool* pPool, FX_LPVOID p, size_t oldSize, size_t newSize)\r
-{\r
-    FX_LPVOID np = AllocSmall(newSize);\r
-    if (!np) {\r
-        return NULL;\r
-    }\r
-    FXSYS_memcpy32(np, p, oldSize);\r
-    pPool->Free(p);\r
-    return np;\r
-}\r
-FX_LPVOID CFXMEM_FixedMgr::Realloc(FX_LPVOID p, size_t newSize)\r
-{\r
-    if (!p) {\r
-        return Alloc(newSize);\r
-    }\r
-    size_t oldSize = 0;\r
-    CFXMEM_Pool *pFind = &m_FirstPool;\r
-    do {\r
-        if (p > (FX_LPVOID)pFind && p < pFind->m_pLimitPos) {\r
-            oldSize = pFind->GetSize(p);\r
-            if (oldSize >= newSize) {\r
-                return p;\r
-            }\r
-            break;\r
-        }\r
-        pFind = pFind->m_pNextPool;\r
-    } while (pFind);\r
-    if (!oldSize || !pFind) {\r
-        return Alloc(newSize);\r
-    }\r
-    FX_LPVOID np = NULL;\r
-    if (newSize <= 32) {\r
-        np = ReallocSmall(pFind, p, oldSize, newSize);\r
-        if (np) {\r
-            return np;\r
-        }\r
-    }\r
-    if (newSize <= FX_FIXEDMEM_MIDBLOCKSIZE) {\r
-        np = pFind->Realloc(p, oldSize, newSize);\r
-        if (np) {\r
-            return np;\r
-        }\r
-    }\r
-    np = Alloc(newSize);\r
-    if (np) {\r
-        FXSYS_memcpy32(np, p, oldSize);\r
-        pFind->Free(p);\r
-    }\r
-    if (pFind->m_bAlone && pFind->IsEmpty()) {\r
-        FreePool(pFind);\r
-    }\r
-    return np;\r
-}\r
-void CFXMEM_FixedMgr::Free(FX_LPVOID p)\r
-{\r
-    CFXMEM_Pool *pFind = &m_FirstPool;\r
-    do {\r
-        if (p > (FX_LPVOID)pFind && p < pFind->m_pLimitPos) {\r
-            pFind->Free(p);\r
-            if (pFind->m_bAlone && pFind->IsEmpty()) {\r
-                FreePool(pFind);\r
-            }\r
-            return;\r
-        }\r
-        pFind = pFind->m_pNextPool;\r
-    } while (pFind);\r
-}\r
-void CFXMEM_FixedMgr::FreePool(CFXMEM_Pool* pPool)\r
-{\r
-    FXSYS_assert(pPool->m_bAlone && pPool->IsEmpty());\r
-    FXSYS_assert(m_pExtender != NULL);\r
-    CFXMEM_Pool* pPrevPool = pPool->m_pPrevPool;\r
-    CFXMEM_Pool* pNextPool = pPool->m_pNextPool;\r
-    if (pPrevPool) {\r
-        pPrevPool->m_pNextPool = pNextPool;\r
-    }\r
-    if (pNextPool) {\r
-        pNextPool->m_pPrevPool = pPrevPool;\r
-    }\r
-    m_pExtender->Free(m_pExtender, pPool);\r
-}\r
-void CFXMEM_FixedMgr::FreeAll()\r
-{\r
-    if (!m_pExtender) {\r
-        return;\r
-    }\r
-    CFXMEM_Pool* pPool = m_FirstPool.m_pNextPool;\r
-    while (pPool) {\r
-        CFXMEM_Pool* pPrevPool = pPool;\r
-        pPool = pPool->m_pNextPool;\r
-        m_pExtender->Free(m_pExtender, pPrevPool);\r
-    }\r
-    m_FirstPool.m_pNextPool = NULL;\r
-}\r
-void CFXMEM_FixedMgr::Purge()\r
-{\r
-    if (!m_pExtender) {\r
-        return;\r
-    }\r
-    CFXMEM_Pool* pPool = m_FirstPool.m_pNextPool;\r
-    while (pPool) {\r
-        CFXMEM_Pool* pNextPool = pPool->m_pNextPool;\r
-        if (pPool->IsEmpty()) {\r
-            CFXMEM_Pool* pPrevPool = pPool->m_pPrevPool;\r
-            pPrevPool->m_pNextPool = pNextPool;\r
-            if (pNextPool) {\r
-                pNextPool->m_pPrevPool = pPrevPool;\r
-            }\r
-            m_pExtender->Free(m_pExtender, pPool);\r
-        }\r
-        pPool = pNextPool;\r
-    }\r
-}\r
-extern const FX_BYTE OneLeadPos[256] = {\r
-    8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,\r
-    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\r
-    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\r
-    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\r
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-};\r
-extern const FX_BYTE ZeroLeadPos[256] = {\r
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
-    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\r
-    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\r
-    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\r
-    4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8,\r
-};\r
+// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "../../include/fxcrt/fx_ext.h"
+#include "mem_int.h"
+#ifdef _FPDFAPI_MINI_
+static FX_MEMCONFIG g_MemConfig = {
+    1,
+    5,
+    8,
+    4,
+    12,
+    8,
+    2,
+    4,
+    32,
+    64,
+};
+#else
+static FX_MEMCONFIG g_MemConfig = {
+    1,
+    8,
+    24,
+    8,
+    32,
+    16,
+    4,
+    8,
+    128,
+    64,
+};
+#endif
+void FXMEM_SetConfig(const FX_MEMCONFIG* memConfig)
+{
+    g_MemConfig = *memConfig;
+}
+#ifdef __cplusplus
+extern "C" {
+#endif
+static void* FixedAlloc(FXMEM_SystemMgr* pMgr, size_t size, int flags)
+{
+    return ((CFXMEM_FixedMgr*)pMgr->user)->Alloc(size);
+}
+static void* FixedAllocDebug(FXMEM_SystemMgr* pMgr, size_t size, int flags, FX_LPCSTR file, int line)
+{
+    return ((CFXMEM_FixedMgr*)pMgr->user)->Alloc(size);
+}
+static void* FixedRealloc(FXMEM_SystemMgr* pMgr, void* pointer, size_t size, int flags)
+{
+    return ((CFXMEM_FixedMgr*)pMgr->user)->Realloc(pointer, size);
+}
+static void* FixedReallocDebug(FXMEM_SystemMgr* pMgr, void* pointer, size_t size, int flags, FX_LPCSTR file, int line)
+{
+    return ((CFXMEM_FixedMgr*)pMgr->user)->Realloc(pointer, size);
+}
+static void  FixedFree(FXMEM_SystemMgr* pMgr, void* pointer, int flags)
+{
+    ((CFXMEM_FixedMgr*)pMgr->user)->Free(pointer);
+}
+static void  FixedPurge(FXMEM_SystemMgr* pMgr)
+{
+    ((CFXMEM_FixedMgr*)pMgr->user)->Purge();
+}
+static void FixedCollectAll(FXMEM_SystemMgr* pMgr)
+{
+    ((CFXMEM_FixedMgr*)pMgr->user)->FreeAll();
+}
+#define FIXEDMEM_MINIMUMSIZE   (1024 * 1024 * 8)
+FXMEM_FoxitMgr* FXMEM_CreateMemoryMgr(size_t size, FX_BOOL extensible)
+{
+    if (size < FIXEDMEM_MINIMUMSIZE) {
+        size = FIXEDMEM_MINIMUMSIZE;
+    }
+    FX_LPVOID pMemory = malloc(size);
+    if (!pMemory) {
+        return NULL;
+    }
+    CFixedMgr_Proxy* pProxy = (CFixedMgr_Proxy*)pMemory;
+    size_t offsetSize = (sizeof(CFixedMgr_Proxy) + 15) / 16 * 16;
+    FXMEM_FoxitMgr* pFoxitMgr = pProxy->Initialize((FX_LPBYTE)pProxy + offsetSize, size - offsetSize, extensible);
+    if (!pFoxitMgr) {
+        free(pMemory);
+        return NULL;
+    }
+    g_pDefFoxitMgr = (CFX_MemoryMgr*)pFoxitMgr;
+    g_pDefFoxitMgr->m_pExternalMemory = pMemory;
+    return pFoxitMgr;
+}
+FXMEM_FoxitMgr* FXMEM_CreateFixedMgr(void* pMemory, size_t size, FXMEM_SystemMgr2* pSystemMgr)
+{
+    if (pMemory == NULL || size < FX_FIXEDMEM_PAGESIZE) {
+        return NULL;
+    }
+    if (!pSystemMgr && size >= FIXEDMEM_PROXYSIZE_1) {
+        CFixedMgr_Proxy* pProxy = (CFixedMgr_Proxy*)pMemory;
+        size_t offsetSize = (sizeof(CFixedMgr_Proxy) + 15) / 16 * 16;
+        return pProxy->Initialize((FX_LPBYTE)pProxy + offsetSize, size - offsetSize, FALSE);
+    }
+    CFXMEM_FixedMgr* pHeader = (CFXMEM_FixedMgr*)pMemory;
+    pHeader->Initialize(size);
+    pHeader->m_pExtender = pSystemMgr;
+    CFX_MemoryMgr* p = (CFX_MemoryMgr*)pHeader->Alloc(sizeof(CFX_MemoryMgr));
+    if (p == NULL) {
+        return NULL;
+    }
+    p->Init(&pHeader->m_SystemMgr);
+    return (FXMEM_FoxitMgr*)p;
+}
+size_t FXMEM_GetBlockSizeInFixedMgr(FXMEM_FoxitMgr* pFoxitMgr, void* ptr)
+{
+    return pFoxitMgr ? ((CFXMEM_FixedMgr*)((CFX_MemoryMgr*)pFoxitMgr)->m_pSystemMgr->user)->GetSize(ptr) : 0;
+}
+#ifdef __cplusplus
+}
+#endif
+const FX_MEMCONFIG g_ProxyMgr_MemConfigs[6] = {
+    {1,      2,      4,      0,      2,      2,   2,       0,       0,     0},
+    {1,      4,      8,      0,      2,      2,   2,       0,       0,     0},
+    {1,      4,      16,     4,      8,      8,   2,       1,       16,    16},
+    {1,      8,      24,     4,      12,     12,  4,       2,       32,    16},
+    {1,      8,      24,     8,      16,     16,  4,       2,       64,    32},
+    {1,      8,      24,     8,      24,     32,  4,       2,       128,   64},
+};
+const FX_MEMCONFIG*    FixedMgr_GetConfig(size_t nSize)
+{
+    int index = 5;
+    if (nSize <= FIXEDMEM_PROXYSIZE_0) {
+        index = 0;
+    } else if (nSize <= FIXEDMEM_PROXYSIZE_1) {
+        index = 1;
+    } else if (nSize <= FIXEDMEM_PROXYSIZE_2) {
+        index = 2;
+    } else if (nSize <= FIXEDMEM_PROXYSIZE_3) {
+        index = 3;
+    } else if (nSize <= FIXEDMEM_PROXYSIZE_4) {
+        index = 4;
+    }
+    return &g_ProxyMgr_MemConfigs[index];
+}
+FXMEM_FoxitMgr* CFixedMgr_Proxy::Initialize(FX_LPVOID pBuffer, size_t nSize, FX_BOOL bExtensible)
+{
+    FXSYS_assert(pBuffer != NULL && nSize >= FIXEDMEM_PROXYSIZE_1 - sizeof(CFixedMgr_Proxy));
+    FXMEM_SetConfig(FixedMgr_GetConfig(nSize));
+    m_SystemMgr.More = &CFixedMgr_Proxy::Common_More;
+    m_SystemMgr.Free = &CFixedMgr_Proxy::Common_Free;
+    m_pFixedPage = (CFXMEM_Page*)((FX_LPBYTE)pBuffer + FIXEDMEM_PROXYSIZE_0);
+    m_pFixedPage->Initialize(nSize - FIXEDMEM_PROXYSIZE_0);
+    m_pBuffer = pBuffer;
+    m_nSize = nSize;
+    m_bExtensible = bExtensible;
+    return FXMEM_CreateFixedMgr(pBuffer, FIXEDMEM_PROXYSIZE_0, &m_SystemMgr);
+}
+FX_BOOL CFixedMgr_Proxy::Common_More(FXMEM_SystemMgr2* pMgr, size_t alloc_size, void** new_memory, size_t* new_size)
+{
+    CFixedMgr_Proxy* pProxyMgr = (CFixedMgr_Proxy*)pMgr;
+    FXSYS_assert(pProxyMgr != NULL && pProxyMgr->m_pFixedPage != NULL);
+    *new_size = alloc_size;
+    *new_memory = pProxyMgr->m_pFixedPage->Alloc(alloc_size);
+    if (*new_memory == NULL && pProxyMgr->m_bExtensible) {
+        *new_memory = malloc(alloc_size);
+    }
+    return *new_memory != NULL;
+}
+void CFixedMgr_Proxy::Common_Free(FXMEM_SystemMgr2* pMgr, void* memory)
+{
+    CFixedMgr_Proxy* pProxyMgr = (CFixedMgr_Proxy*)pMgr;
+    FXSYS_assert(pProxyMgr != NULL && pProxyMgr->m_pFixedPage != NULL);
+    if (memory > pProxyMgr->m_pBuffer && memory < (FX_LPBYTE)pProxyMgr->m_pBuffer + pProxyMgr->m_nSize) {
+        pProxyMgr->m_pFixedPage->Free(memory);
+    } else if (pProxyMgr->m_bExtensible) {
+        free(memory);
+    }
+}
+void CFXMEM_Page::Initialize(size_t size)
+{
+    CFXMEM_Block *pFirstBlock = (CFXMEM_Block*)(this + 1);
+    m_nAvailSize = size - sizeof(CFXMEM_Page) - sizeof(CFXMEM_Block);
+    pFirstBlock->m_nBlockSize = m_nAvailSize;
+    pFirstBlock->m_pNextBlock = NULL;
+    m_AvailHead.m_nBlockSize = m_nAvailSize;
+    m_AvailHead.m_pNextBlock = pFirstBlock;
+    m_pLimitPos = (CFXMEM_Block*)((FX_LPBYTE)this + size);
+}
+FX_LPVOID CFXMEM_Page::Alloc(CFXMEM_Block* pPrevBlock, CFXMEM_Block* pNextBlock, size_t size, size_t oldsize)
+{
+    size_t gap = pNextBlock->m_nBlockSize - size;
+    if (gap <= 64 + sizeof(CFXMEM_Block)) {
+        pPrevBlock->m_pNextBlock = pNextBlock->m_pNextBlock;
+        m_nAvailSize -= pNextBlock->m_nBlockSize;
+    } else {
+        m_nAvailSize -= size + sizeof(CFXMEM_Block);
+        pNextBlock->m_nBlockSize = size;
+        CFXMEM_Block *pNewBlock = (CFXMEM_Block*)((FX_LPBYTE)(pNextBlock + 1) + size);
+        pNewBlock->m_nBlockSize = gap - sizeof(CFXMEM_Block);
+        pNewBlock->m_pNextBlock = pNextBlock->m_pNextBlock;
+        pPrevBlock->m_pNextBlock = pNewBlock;
+    }
+    return (FX_LPVOID)(pNextBlock + 1);
+}
+FX_LPVOID CFXMEM_Page::Alloc(size_t size)
+{
+    size_t oldsize = size;
+#if _FX_WORDSIZE_ == _FX_W64_
+    size = (size + 31) / 32 * 32;
+#else
+    size = (size + 7) / 8 * 8;
+#endif
+    if (m_nAvailSize < size) {
+        return NULL;
+    }
+    CFXMEM_Block *pNextBlock;
+    CFXMEM_Block *pPrevBlock = &m_AvailHead;
+    while (TRUE) {
+        pNextBlock = pPrevBlock->m_pNextBlock;
+        if (!pNextBlock) {
+            return NULL;
+        }
+        if (pNextBlock->m_nBlockSize >= size) {
+            break;
+        }
+        pPrevBlock = pNextBlock;
+    }
+    return Alloc(pPrevBlock, pNextBlock, size, oldsize);
+}
+FX_LPVOID CFXMEM_Page::Realloc(FX_LPVOID p, size_t oldSize, size_t newSize)
+{
+    FXSYS_assert(p > (FX_LPVOID)this && p < (FX_LPVOID)m_pLimitPos);
+    size_t oldnewSize = newSize;
+#if _FX_WORDSIZE_ == _FX_W64_
+    newSize = (newSize + 31) / 32 * 32;
+#else
+    newSize = (newSize + 7) / 8 * 8;
+#endif
+    CFXMEM_Block *pPrevBlock = &m_AvailHead;
+    CFXMEM_Block *pNextBlock, *pPrevPrev;
+    CFXMEM_Block *pBlock = (CFXMEM_Block*)p - 1;
+    pPrevPrev = NULL;
+    while (TRUE) {
+        pNextBlock = pPrevBlock->m_pNextBlock;
+        if (pNextBlock == NULL || pNextBlock > pBlock) {
+            break;
+        }
+        if (pPrevBlock != &m_AvailHead && (FX_LPBYTE)pNextBlock == (FX_LPBYTE)(pPrevBlock + 1) + pPrevBlock->m_nBlockSize) {
+            m_nAvailSize += sizeof(CFXMEM_Block);
+            pPrevBlock->m_nBlockSize += pNextBlock->m_nBlockSize + sizeof(CFXMEM_Block);
+            pPrevBlock->m_pNextBlock = pNextBlock->m_pNextBlock;
+        } else {
+            pPrevPrev = pPrevBlock;
+            pPrevBlock = pNextBlock;
+        }
+    }
+    if (pNextBlock) {
+        CFXMEM_Block* pCurBlock = pNextBlock->m_pNextBlock;
+        while ((FX_LPBYTE)pCurBlock == (FX_LPBYTE)(pNextBlock + 1) + pNextBlock->m_nBlockSize) {
+            m_nAvailSize += sizeof(CFXMEM_Block);
+            pNextBlock->m_nBlockSize += pCurBlock->m_nBlockSize + sizeof(CFXMEM_Block);
+            pCurBlock = pCurBlock->m_pNextBlock;
+            pNextBlock->m_pNextBlock = pCurBlock;
+        }
+    }
+    size_t size = 0;
+    FX_DWORD dwFlags = 0;
+    if (pPrevBlock != &m_AvailHead && (FX_LPBYTE)pBlock == (FX_LPBYTE)(pPrevBlock + 1) + pPrevBlock->m_nBlockSize) {
+        size += pPrevBlock->m_nBlockSize + oldSize + sizeof(CFXMEM_Block);
+        dwFlags |= 0x10;
+    }
+    if (pNextBlock && (FX_LPBYTE)pNextBlock == (FX_LPBYTE)p + oldSize) {
+        size += pNextBlock->m_nBlockSize + sizeof(CFXMEM_Block);
+        dwFlags |= 0x01;
+    }
+    if (size >= newSize) {
+        m_nAvailSize += pBlock->m_nBlockSize;
+        CFXMEM_Block* pCurBlock = pBlock;
+        if (dwFlags & 0x10) {
+            pCurBlock = pPrevBlock;
+            m_nAvailSize += sizeof(CFXMEM_Block);
+            pCurBlock->m_nBlockSize += pBlock->m_nBlockSize + sizeof(CFXMEM_Block);
+            pPrevBlock = pPrevPrev;
+        }
+        if (dwFlags & 0x01) {
+            m_nAvailSize += sizeof(CFXMEM_Block);
+            pCurBlock->m_nBlockSize += pNextBlock->m_nBlockSize + sizeof(CFXMEM_Block);
+            pCurBlock->m_pNextBlock = pNextBlock->m_pNextBlock;
+        }
+        if (pCurBlock != pBlock) {
+            FXSYS_memmove32((FX_LPVOID)(pCurBlock + 1), p, oldSize);
+        }
+        return Alloc(pPrevBlock, pCurBlock, newSize, oldnewSize);
+    }
+    return NULL;
+}
+void CFXMEM_Page::Free(FX_LPVOID p)
+{
+    FXSYS_assert(p > (FX_LPVOID)this && p < (FX_LPVOID)m_pLimitPos);
+    CFXMEM_Block *pPrevBlock = &m_AvailHead;
+    CFXMEM_Block *pNextBlock;
+    CFXMEM_Block *pBlock = (CFXMEM_Block*)p - 1;
+    m_nAvailSize += pBlock->m_nBlockSize;
+    while (TRUE) {
+        pNextBlock = pPrevBlock->m_pNextBlock;
+        if (pNextBlock == NULL || pNextBlock > pBlock) {
+            break;
+        }
+        if (pPrevBlock != &m_AvailHead && (FX_LPBYTE)pNextBlock == (FX_LPBYTE)(pPrevBlock + 1) + pPrevBlock->m_nBlockSize) {
+            m_nAvailSize += sizeof(CFXMEM_Block);
+            pPrevBlock->m_nBlockSize += pNextBlock->m_nBlockSize + sizeof(CFXMEM_Block);
+            pPrevBlock->m_pNextBlock = pNextBlock->m_pNextBlock;
+        } else {
+            pPrevBlock = pNextBlock;
+        }
+    }
+    while ((FX_LPBYTE)pNextBlock == (FX_LPBYTE)(pBlock + 1) + pBlock->m_nBlockSize) {
+        m_nAvailSize += sizeof(CFXMEM_Block);
+        pBlock->m_nBlockSize += pNextBlock->m_nBlockSize + sizeof(CFXMEM_Block);
+        pNextBlock = pNextBlock->m_pNextBlock;
+    }
+    pBlock->m_pNextBlock = pNextBlock;
+    if (pPrevBlock != &m_AvailHead && (FX_LPBYTE)pBlock == (FX_LPBYTE)(pPrevBlock + 1) + pPrevBlock->m_nBlockSize) {
+        m_nAvailSize += sizeof(CFXMEM_Block);
+        pPrevBlock->m_nBlockSize += pBlock->m_nBlockSize + sizeof(CFXMEM_Block);
+        pPrevBlock->m_pNextBlock = pBlock->m_pNextBlock;
+    } else {
+        FXSYS_assert(pPrevBlock != pBlock);
+        pPrevBlock->m_pNextBlock = pBlock;
+    }
+}
+void CFXMEM_Pages::Initialize(FX_LPBYTE pStart, size_t pageSize, size_t pages)
+{
+    m_pStartPage = m_pCurPage = (CFXMEM_Page*)pStart;
+    m_nPageSize = pageSize;
+    for (size_t n = 0; n < pages; n++) {
+        ((CFXMEM_Page*)pStart)->Initialize(pageSize);
+        pStart += pageSize;
+    }
+    m_pLimitPos = (CFXMEM_Page*)pStart;
+}
+FX_BOOL CFXMEM_Pages::IsEmpty() const
+{
+    if (m_pStartPage >= m_pLimitPos) {
+        return TRUE;
+    }
+    FX_LPBYTE pPage = (FX_LPBYTE)m_pStartPage;
+    while (pPage < (FX_LPBYTE)m_pLimitPos) {
+        if (!((CFXMEM_Page*)pPage)->IsEmpty()) {
+            return FALSE;
+        }
+        pPage += m_nPageSize;
+    }
+    return TRUE;
+}
+FX_LPVOID CFXMEM_Pages::Alloc(size_t size)
+{
+    CFXMEM_Page *pCurPage = m_pCurPage;
+    do {
+        FX_LPVOID p = m_pCurPage->Alloc(size);
+        if (p) {
+            return p;
+        }
+        m_pCurPage = (CFXMEM_Page*)((FX_LPBYTE)m_pCurPage + m_nPageSize);
+        if (m_pCurPage == m_pLimitPos) {
+            m_pCurPage = m_pStartPage;
+        }
+    } while (m_pCurPage != pCurPage);
+    return NULL;
+}
+FX_LPVOID CFXMEM_Pages::Realloc(FX_LPVOID p, size_t oldSize, size_t newSize)
+{
+    FXSYS_assert (p > (FX_LPVOID)m_pStartPage && p < (FX_LPVOID)m_pLimitPos);
+    CFXMEM_Page* pPage = (CFXMEM_Page*)((FX_LPBYTE)m_pStartPage + ((FX_LPBYTE)p - (FX_LPBYTE)m_pStartPage) / m_nPageSize * m_nPageSize);
+    return pPage->Realloc(p, oldSize, newSize);
+}
+void CFXMEM_Pages::Free(FX_LPVOID p)
+{
+    FXSYS_assert (p > (FX_LPVOID)m_pStartPage && p < (FX_LPVOID)m_pLimitPos);
+    CFXMEM_Page* pPage = (CFXMEM_Page*)((FX_LPBYTE)m_pStartPage + ((FX_LPBYTE)p - (FX_LPBYTE)m_pStartPage) / m_nPageSize * m_nPageSize);
+    pPage->Free(p);
+}
+void CFXMEM_Pool::Initialize(const FX_MEMCONFIG* pMemConfig, size_t size, size_t pageNum8Bytes, size_t pageNum16Bytes, size_t pageNum32Bytes, size_t pageNumMid)
+{
+    m_pPrevPool = NULL;
+    m_pNextPool = NULL;
+    m_bAlone = FALSE;
+    FX_LPBYTE pPage = (FX_LPBYTE)this + sizeof(CFXMEM_Pool);
+    size -= sizeof(CFXMEM_Pool);
+    m_8BytesPages.Initialize(pPage, pageNum8Bytes);
+    pPage += pageNum8Bytes * FX_FIXEDMEM_PAGESIZE;
+    size -= pageNum8Bytes * FX_FIXEDMEM_PAGESIZE;
+    m_16BytesPages.Initialize(pPage, pageNum16Bytes);
+    pPage += pageNum16Bytes * FX_FIXEDMEM_PAGESIZE;
+    size -= pageNum16Bytes * FX_FIXEDMEM_PAGESIZE;
+    m_32BytesPages.Initialize(pPage, pageNum32Bytes);
+    pPage += pageNum32Bytes * FX_FIXEDMEM_PAGESIZE;
+    size -= pageNum32Bytes * FX_FIXEDMEM_PAGESIZE;
+    m_MidPages.Initialize(pPage, pMemConfig->nPageSize_Mid * FX_FIXEDMEM_PAGESIZE, pageNumMid);
+    pPage += pageNumMid * pMemConfig->nPageSize_Mid * FX_FIXEDMEM_PAGESIZE;
+    size -= pageNumMid * pMemConfig->nPageSize_Mid * FX_FIXEDMEM_PAGESIZE;
+    if (size < FX_FIXEDMEM_MIDBLOCKSIZE) {
+        m_pLargePage = NULL;
+    } else {
+        m_pLargePage = (CFXMEM_Page*)pPage;
+        m_pLargePage->Initialize(size);
+    }
+    m_pLimitPos = pPage + size;
+}
+FX_BOOL CFXMEM_Pool::IsEmpty() const
+{
+    if (!m_8BytesPages.IsEmpty()) {
+        return FALSE;
+    }
+    if (!m_16BytesPages.IsEmpty()) {
+        return FALSE;
+    }
+    if (!m_32BytesPages.IsEmpty()) {
+        return FALSE;
+    }
+    if (!m_MidPages.IsEmpty()) {
+        return FALSE;
+    }
+    return !m_pLargePage || m_pLargePage->IsEmpty();
+}
+size_t CFXMEM_Pool::GetSize(FX_LPVOID p) const
+{
+    FXSYS_assert(p > (FX_LPVOID)this && p < (FX_LPVOID)m_pLimitPos);
+    if (p < (FX_LPVOID)m_8BytesPages.m_pLimitPos) {
+        return 8;
+    }
+    if (p < (FX_LPVOID)m_16BytesPages.m_pLimitPos) {
+        return 16;
+    }
+    if (p < (FX_LPVOID)m_32BytesPages.m_pLimitPos) {
+        return 32;
+    }
+    return ((CFXMEM_Block*)p - 1)->m_nBlockSize;
+}
+FX_LPVOID CFXMEM_Pool::Realloc(FX_LPVOID p, size_t oldSize, size_t newSize)
+{
+    FXSYS_assert(p > (FX_LPVOID)this && p < (FX_LPVOID)m_pLimitPos);
+    if (p > (FX_LPVOID)m_32BytesPages.m_pLimitPos) {
+        if (p < (FX_LPVOID)m_MidPages.m_pLimitPos) {
+            return m_MidPages.Realloc(p, oldSize, newSize);
+        } else if (m_pLargePage) {
+            return m_pLargePage->Realloc(p, oldSize, newSize);
+        }
+    }
+    return NULL;
+}
+void CFXMEM_Pool::Free(FX_LPVOID p)
+{
+    FXSYS_assert(p > (FX_LPVOID)this && p < (FX_LPVOID)m_pLimitPos);
+    if (p < (FX_LPVOID)m_32BytesPages.m_pLimitPos) {
+        if (p < (FX_LPVOID)m_8BytesPages.m_pLimitPos) {
+            m_8BytesPages.Free(p);
+        } else if (p < (FX_LPVOID)m_16BytesPages.m_pLimitPos) {
+            m_16BytesPages.Free(p);
+        } else {
+            m_32BytesPages.Free(p);
+        }
+        return;
+    } else if (p < (FX_LPVOID)m_MidPages.m_pLimitPos) {
+        m_MidPages.Free(p);
+    } else {
+        m_pLargePage->Free(p);
+    }
+}
+void CFXMEM_FixedMgr::Initialize(size_t size)
+{
+    m_MemConfig = g_MemConfig;
+    FXSYS_memset32(&m_SystemMgr, 0, sizeof m_SystemMgr);
+    m_SystemMgr.Alloc = FixedAlloc;
+    m_SystemMgr.AllocDebug = FixedAllocDebug;
+    m_SystemMgr.Free = FixedFree;
+    m_SystemMgr.Realloc = FixedRealloc;
+    m_SystemMgr.ReallocDebug = FixedReallocDebug;
+    m_SystemMgr.CollectAll = FixedCollectAll;
+    m_SystemMgr.Purge = FixedPurge;
+    m_SystemMgr.user = this;
+    size -= sizeof(CFXMEM_FixedMgr);
+    size_t nMidPages = 0;
+    if (m_MemConfig.nPageSize_Mid) {
+        nMidPages = (size - (m_MemConfig.nPageNum_Init8 + m_MemConfig.nPageNum_Init16 + m_MemConfig.nPageNum_Init32) * FX_FIXEDMEM_PAGESIZE) / (m_MemConfig.nPageSize_Mid * FX_FIXEDMEM_PAGESIZE);
+        if (nMidPages > m_MemConfig.nPageNum_InitMid) {
+            nMidPages = m_MemConfig.nPageNum_InitMid;
+        }
+    }
+    m_FirstPool.Initialize(&m_MemConfig, size, m_MemConfig.nPageNum_Init8, m_MemConfig.nPageNum_Init16, m_MemConfig.nPageNum_Init32, nMidPages);
+}
+FX_LPVOID CFXMEM_FixedMgr::Alloc16(CFXMEM_Pool **pp32Pool, size_t size)
+{
+    CFXMEM_Pool *pPool = &m_FirstPool;
+    do {
+        CFXMEM_16BytesPages &pages = pPool->m_16BytesPages;
+        if (pages.HasFreeBlock()) {
+            return pages.Alloc(size);
+        }
+        if (pp32Pool && pPool->m_32BytesPages.HasFreeBlock()) {
+            *pp32Pool = pPool;
+        }
+        pPool = pPool->m_pNextPool;
+    } while(pPool);
+    return NULL;
+}
+FX_LPVOID CFXMEM_FixedMgr::Alloc32(size_t size)
+{
+    if (size <= 8) {
+        CFXMEM_8BytesPages &pages = m_FirstPool.m_8BytesPages;
+        if (pages.HasFreeBlock()) {
+            return pages.Alloc(size);
+        }
+    }
+    CFXMEM_Pool *p32BytesPool;
+    if (size <= 16) {
+        p32BytesPool = NULL;
+        FX_LPVOID p = Alloc16(&p32BytesPool, size);
+        if (p) {
+            return p;
+        }
+    } else {
+        p32BytesPool = &m_FirstPool;
+    }
+    while (p32BytesPool) {
+        CFXMEM_32BytesPages &pages = p32BytesPool->m_32BytesPages;
+        if (pages.HasFreeBlock()) {
+            return pages.Alloc(size);
+        }
+        p32BytesPool = p32BytesPool->m_pNextPool;
+    }
+    return NULL;
+}
+FX_LPVOID CFXMEM_FixedMgr::AllocSmall(size_t size)
+{
+    FX_LPVOID p = Alloc32(size);
+    if (p) {
+        return p;
+    }
+    if (!m_pExtender) {
+        return NULL;
+    }
+    size_t requiredSize = (m_MemConfig.nPageNum_More16 + m_MemConfig.nPageNum_More32) * FX_FIXEDMEM_PAGESIZE;
+    if (!requiredSize) {
+        return NULL;
+    }
+    CFXMEM_Pool *pNewPool = NULL;
+    requiredSize += sizeof(CFXMEM_Pool);
+    size_t newSize = requiredSize;
+    if (!m_pExtender->More(m_pExtender, newSize, (void**)&pNewPool, &newSize)) {
+        return NULL;
+    }
+    size_t nMidPages = 0;
+    if (m_MemConfig.nPageSize_Mid) {
+        nMidPages = (newSize - requiredSize) / (m_MemConfig.nPageSize_Mid * FX_FIXEDMEM_PAGESIZE);
+        if (nMidPages > m_MemConfig.nPageNum_MoreMid) {
+            nMidPages = m_MemConfig.nPageNum_MoreMid;
+        }
+    }
+    pNewPool->Initialize(&m_MemConfig, newSize, 0, m_MemConfig.nPageNum_More16, m_MemConfig.nPageNum_More32, nMidPages);
+    pNewPool->m_pPrevPool = &m_FirstPool;
+    CFXMEM_Pool *pPool = m_FirstPool.m_pNextPool;
+    pNewPool->m_pNextPool = pPool;
+    if (pPool) {
+        pPool->m_pPrevPool = pNewPool;
+    }
+    m_FirstPool.m_pNextPool = pNewPool;
+    return Alloc32(size);
+}
+FX_LPVOID CFXMEM_FixedMgr::AllocMid(size_t size)
+{
+    CFXMEM_Pool *pPool = &m_FirstPool;
+    do {
+        CFXMEM_Pages &pages = pPool->m_MidPages;
+        if (pages.m_pLimitPos > pages.m_pStartPage) {
+            FX_LPVOID p = pages.Alloc(size);
+            if (p) {
+                return p;
+            }
+        }
+        pPool = pPool->m_pNextPool;
+    } while(pPool);
+    if (!m_pExtender) {
+        return NULL;
+    }
+    size_t newSize = m_MemConfig.nPageSize_Mid * FX_FIXEDMEM_PAGESIZE * m_MemConfig.nPageNum_MoreMid;
+    if (!newSize) {
+        return NULL;
+    }
+    CFXMEM_Pool *pNewPool = NULL;
+    newSize += sizeof(CFXMEM_Pool);
+    if (!m_pExtender->More(m_pExtender, newSize, (void**)&pNewPool, &newSize)) {
+        return NULL;
+    }
+    size_t nMidPages = (newSize - sizeof(CFXMEM_Pool)) / (m_MemConfig.nPageSize_Mid * FX_FIXEDMEM_PAGESIZE);
+    if (nMidPages > m_MemConfig.nPageNum_MoreMid) {
+        nMidPages = m_MemConfig.nPageNum_MoreMid;
+    }
+    pNewPool->Initialize(&m_MemConfig, newSize, 0, 0, 0, nMidPages);
+    pNewPool->m_pPrevPool = &m_FirstPool;
+    pPool = m_FirstPool.m_pNextPool;
+    pNewPool->m_pNextPool = pPool;
+    if (pPool) {
+        pPool->m_pPrevPool = pNewPool;
+    }
+    m_FirstPool.m_pNextPool = pNewPool;
+    return pNewPool->m_MidPages.Alloc(size);
+}
+FX_LPVOID CFXMEM_FixedMgr::AllocLarge(size_t size)
+{
+    CFXMEM_Pool *pPool = &m_FirstPool;
+    do {
+        if (!pPool->m_bAlone && pPool->m_pLargePage) {
+            FX_LPVOID p = pPool->m_pLargePage->Alloc(size);
+            if (p) {
+                return p;
+            }
+        }
+        pPool = pPool->m_pNextPool;
+    } while(pPool);
+    if (!m_pExtender || !m_MemConfig.nPageSize_Large) {
+        return NULL;
+    }
+    CFXMEM_Pool *pNewPool = NULL;
+#if _FX_WORDSIZE_ == _FX_W64_
+    size_t newSize = ((size + 31) / 32 * 32 + sizeof(CFXMEM_Pool) + sizeof(CFXMEM_Page) + sizeof(CFXMEM_Block) + 4095) / 4096 * 4096;
+#else
+    size_t newSize = (size + 7) / 8 * 8 + sizeof(CFXMEM_Pool) + sizeof(CFXMEM_Page) + sizeof(CFXMEM_Block);
+#endif
+    if (newSize < m_MemConfig.nPageSize_Large * FX_FIXEDMEM_PAGESIZE) {
+        newSize = m_MemConfig.nPageSize_Large * FX_FIXEDMEM_PAGESIZE;
+    }
+    if (!m_pExtender->More(m_pExtender, newSize, (void**)&pNewPool, &newSize)) {
+        return NULL;
+    }
+    pNewPool->Initialize(&m_MemConfig, newSize, 0, 0, 0, 0);
+    pNewPool->m_bAlone = size >= m_MemConfig.nPageSize_Alone * FX_FIXEDMEM_PAGESIZE;
+    pNewPool->m_pPrevPool = &m_FirstPool;
+    pPool = m_FirstPool.m_pNextPool;
+    pNewPool->m_pNextPool = pPool;
+    if (pPool) {
+        pPool->m_pPrevPool = pNewPool;
+    }
+    m_FirstPool.m_pNextPool = pNewPool;
+    return pNewPool->m_pLargePage->Alloc(size);
+}
+size_t CFXMEM_FixedMgr::GetSize(FX_LPVOID p) const
+{
+    const CFXMEM_Pool *pFind = &m_FirstPool;
+    do {
+        if (p > (FX_LPVOID)pFind && p < pFind->m_pLimitPos) {
+            return pFind->GetSize(p);
+        }
+        pFind = pFind->m_pNextPool;
+    } while (pFind);
+    return 0;
+}
+FX_LPVOID CFXMEM_FixedMgr::Alloc(size_t size)
+{
+    FX_LPVOID p;
+    if (size <= 32) {
+        p = AllocSmall(size);
+        if (p) {
+            return p;
+        }
+    }
+    if (size <= FX_FIXEDMEM_MIDBLOCKSIZE) {
+        p = AllocMid(size);
+        if (p) {
+            return p;
+        }
+    }
+    p = AllocLarge(size);
+    return p;
+}
+FX_LPVOID CFXMEM_FixedMgr::ReallocSmall(CFXMEM_Pool* pPool, FX_LPVOID p, size_t oldSize, size_t newSize)
+{
+    FX_LPVOID np = AllocSmall(newSize);
+    if (!np) {
+        return NULL;
+    }
+    FXSYS_memcpy32(np, p, oldSize);
+    pPool->Free(p);
+    return np;
+}
+FX_LPVOID CFXMEM_FixedMgr::Realloc(FX_LPVOID p, size_t newSize)
+{
+    if (!p) {
+        return Alloc(newSize);
+    }
+    size_t oldSize = 0;
+    CFXMEM_Pool *pFind = &m_FirstPool;
+    do {
+        if (p > (FX_LPVOID)pFind && p < pFind->m_pLimitPos) {
+            oldSize = pFind->GetSize(p);
+            if (oldSize >= newSize) {
+                return p;
+            }
+            break;
+        }
+        pFind = pFind->m_pNextPool;
+    } while (pFind);
+    if (!oldSize || !pFind) {
+        return Alloc(newSize);
+    }
+    FX_LPVOID np = NULL;
+    if (newSize <= 32) {
+        np = ReallocSmall(pFind, p, oldSize, newSize);
+        if (np) {
+            return np;
+        }
+    }
+    if (newSize <= FX_FIXEDMEM_MIDBLOCKSIZE) {
+        np = pFind->Realloc(p, oldSize, newSize);
+        if (np) {
+            return np;
+        }
+    }
+    np = Alloc(newSize);
+    if (np) {
+        FXSYS_memcpy32(np, p, oldSize);
+        pFind->Free(p);
+    }
+    if (pFind->m_bAlone && pFind->IsEmpty()) {
+        FreePool(pFind);
+    }
+    return np;
+}
+void CFXMEM_FixedMgr::Free(FX_LPVOID p)
+{
+    CFXMEM_Pool *pFind = &m_FirstPool;
+    do {
+        if (p > (FX_LPVOID)pFind && p < pFind->m_pLimitPos) {
+            pFind->Free(p);
+            if (pFind->m_bAlone && pFind->IsEmpty()) {
+                FreePool(pFind);
+            }
+            return;
+        }
+        pFind = pFind->m_pNextPool;
+    } while (pFind);
+}
+void CFXMEM_FixedMgr::FreePool(CFXMEM_Pool* pPool)
+{
+    FXSYS_assert(pPool->m_bAlone && pPool->IsEmpty());
+    FXSYS_assert(m_pExtender != NULL);
+    CFXMEM_Pool* pPrevPool = pPool->m_pPrevPool;
+    CFXMEM_Pool* pNextPool = pPool->m_pNextPool;
+    if (pPrevPool) {
+        pPrevPool->m_pNextPool = pNextPool;
+    }
+    if (pNextPool) {
+        pNextPool->m_pPrevPool = pPrevPool;
+    }
+    m_pExtender->Free(m_pExtender, pPool);
+}
+void CFXMEM_FixedMgr::FreeAll()
+{
+    if (!m_pExtender) {
+        return;
+    }
+    CFXMEM_Pool* pPool = m_FirstPool.m_pNextPool;
+    while (pPool) {
+        CFXMEM_Pool* pPrevPool = pPool;
+        pPool = pPool->m_pNextPool;
+        m_pExtender->Free(m_pExtender, pPrevPool);
+    }
+    m_FirstPool.m_pNextPool = NULL;
+}
+void CFXMEM_FixedMgr::Purge()
+{
+    if (!m_pExtender) {
+        return;
+    }
+    CFXMEM_Pool* pPool = m_FirstPool.m_pNextPool;
+    while (pPool) {
+        CFXMEM_Pool* pNextPool = pPool->m_pNextPool;
+        if (pPool->IsEmpty()) {
+            CFXMEM_Pool* pPrevPool = pPool->m_pPrevPool;
+            pPrevPool->m_pNextPool = pNextPool;
+            if (pNextPool) {
+                pNextPool->m_pPrevPool = pPrevPool;
+            }
+            m_pExtender->Free(m_pExtender, pPool);
+        }
+        pPool = pNextPool;
+    }
+}
+extern const FX_BYTE OneLeadPos[256] = {
+    8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    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, 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, 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,
+};
+extern const FX_BYTE ZeroLeadPos[256] = {
+    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, 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, 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,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8,
+};