This change is for fixing the potential integer overflow from "offset + size"
[pdfium.git] / core / src / fxcrt / extension.h
index bf5c5ec..b8dce7c 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
-#ifndef _FXCRT_EXTENSION_IMP_\r
-#define _FXCRT_EXTENSION_IMP_\r
-class IFXCRT_FileAccess\r
-{\r
-public:\r
-    virtual ~IFXCRT_FileAccess() {}\r
-    virtual FX_BOOL            Open(FX_BSTR fileName, FX_DWORD dwMode) = 0;\r
-    virtual FX_BOOL            Open(FX_WSTR fileName, FX_DWORD dwMode) = 0;\r
-    virtual void               Close() = 0;\r
-    virtual void               Release(IFX_Allocator* pAllocator = NULL) = 0;\r
-    virtual FX_FILESIZE        GetSize() const = 0;\r
-    virtual FX_FILESIZE        GetPosition() const = 0;\r
-    virtual FX_FILESIZE        SetPosition(FX_FILESIZE pos) = 0;\r
-    virtual size_t             Read(void* pBuffer, size_t szBuffer) = 0;\r
-    virtual size_t             Write(const void* pBuffer, size_t szBuffer) = 0;\r
-    virtual size_t             ReadPos(void* pBuffer, size_t szBuffer, FX_FILESIZE pos) = 0;\r
-    virtual size_t             WritePos(const void* pBuffer, size_t szBuffer, FX_FILESIZE pos) = 0;\r
-    virtual FX_BOOL            Flush() = 0;\r
-    virtual FX_BOOL            Truncate(FX_FILESIZE szFile) = 0;\r
-};\r
-IFXCRT_FileAccess*     FXCRT_FileAccess_Create(IFX_Allocator* pAllocator = NULL);\r
-class CFX_CRTFileStream : public IFX_FileStream, public CFX_Object\r
-{\r
-public:\r
-    CFX_CRTFileStream(IFXCRT_FileAccess* pFA, IFX_Allocator* pAllocator) : m_pAllocator(pAllocator), m_pFile(pFA), m_dwCount(1), m_bUseRange(FALSE), m_nOffset(0), m_nSize(0) {}\r
-    ~CFX_CRTFileStream()\r
-    {\r
-        if (m_pFile) {\r
-            m_pFile->Release(m_pAllocator);\r
-        }\r
-    }\r
-    virtual IFX_FileStream*            Retain()\r
-    {\r
-        m_dwCount ++;\r
-        return this;\r
-    }\r
-    virtual void                               Release()\r
-    {\r
-        FX_DWORD nCount = -- m_dwCount;\r
-        if (!nCount) {\r
-            if (m_pAllocator) {\r
-                FX_DeleteAtAllocator(this, m_pAllocator, CFX_CRTFileStream);\r
-            } else {\r
-                delete this;\r
-            }\r
-        }\r
-    }\r
-    virtual FX_FILESIZE                        GetSize()\r
-    {\r
-        return m_bUseRange ? m_nSize : m_pFile->GetSize();\r
-    }\r
-    virtual FX_BOOL                            IsEOF()\r
-    {\r
-        return GetPosition() >= GetSize();\r
-    }\r
-    virtual FX_FILESIZE                        GetPosition()\r
-    {\r
-        FX_FILESIZE pos = m_pFile->GetPosition();\r
-        if (m_bUseRange) {\r
-            pos -= m_nOffset;\r
-        }\r
-        return pos;\r
-    }\r
-    virtual FX_BOOL                            SetRange(FX_FILESIZE offset, FX_FILESIZE size)\r
-    {\r
-        if (offset < 0 || offset + size > m_pFile->GetSize()) {\r
-            return FALSE;\r
-        }\r
-        m_nOffset = offset, m_nSize = size;\r
-        m_bUseRange = TRUE;\r
-        m_pFile->SetPosition(m_nOffset);\r
-        return TRUE;\r
-    }\r
-    virtual void                               ClearRange()\r
-    {\r
-        m_bUseRange = FALSE;\r
-    }\r
-    virtual FX_BOOL                            ReadBlock(void* buffer, FX_FILESIZE offset, size_t size)\r
-    {\r
-        if (m_bUseRange) {\r
-            if (offset + size > (size_t)GetSize()) {\r
-                return FALSE;\r
-            }\r
-            offset += m_nOffset;\r
-        }\r
-        return (FX_BOOL)m_pFile->ReadPos(buffer, size, offset);\r
-    }\r
-    virtual size_t                             ReadBlock(void* buffer, size_t size)\r
-    {\r
-        if (m_bUseRange) {\r
-            FX_FILESIZE availSize = m_nOffset + m_nSize - m_pFile->GetPosition();\r
-            if ((size_t)availSize < size) {\r
-                size -= size - (size_t)availSize;\r
-            }\r
-        }\r
-        return m_pFile->Read(buffer, size);\r
-    }\r
-    virtual    FX_BOOL                         WriteBlock(const void* buffer, FX_FILESIZE offset, size_t size)\r
-    {\r
-        if (m_bUseRange) {\r
-            offset += m_nOffset;\r
-        }\r
-        return (FX_BOOL)m_pFile->WritePos(buffer, size, offset);\r
-    }\r
-    virtual FX_BOOL                            Flush()\r
-    {\r
-        return m_pFile->Flush();\r
-    }\r
-    IFX_Allocator*             m_pAllocator;\r
-    IFXCRT_FileAccess* m_pFile;\r
-    FX_DWORD                   m_dwCount;\r
-    FX_BOOL                            m_bUseRange;\r
-    FX_FILESIZE                        m_nOffset;\r
-    FX_FILESIZE                        m_nSize;\r
-};\r
-#define FX_MEMSTREAM_BlockSize         (64 * 1024)\r
-#define FX_MEMSTREAM_Consecutive       0x01\r
-#define FX_MEMSTREAM_TakeOver          0x02\r
-class CFX_MemoryStream : public IFX_MemoryStream, public CFX_Object\r
-{\r
-public:\r
-    CFX_MemoryStream(FX_BOOL bConsecutive, IFX_Allocator* pAllocator)\r
-        : m_Blocks(pAllocator)\r
-        , m_dwCount(1)\r
-        , m_nTotalSize(0)\r
-        , m_nCurSize(0)\r
-        , m_nCurPos(0)\r
-        , m_nGrowSize(FX_MEMSTREAM_BlockSize)\r
-        , m_bUseRange(FALSE)\r
-    {\r
-        m_dwFlags = FX_MEMSTREAM_TakeOver | (bConsecutive ? FX_MEMSTREAM_Consecutive : 0);\r
-    }\r
-    CFX_MemoryStream(FX_LPBYTE pBuffer, size_t nSize, FX_BOOL bTakeOver, IFX_Allocator* pAllocator)\r
-        : m_Blocks(pAllocator)\r
-        , m_dwCount(1)\r
-        , m_nTotalSize(nSize)\r
-        , m_nCurSize(nSize)\r
-        , m_nCurPos(0)\r
-        , m_nGrowSize(FX_MEMSTREAM_BlockSize)\r
-        , m_bUseRange(FALSE)\r
-    {\r
-        m_Blocks.Add(pBuffer);\r
-        m_dwFlags = FX_MEMSTREAM_Consecutive | (bTakeOver ? FX_MEMSTREAM_TakeOver : 0);\r
-    }\r
-    ~CFX_MemoryStream()\r
-    {\r
-        IFX_Allocator* pAllocator = m_Blocks.m_pAllocator;\r
-        if (m_dwFlags & FX_MEMSTREAM_TakeOver) {\r
-            for (FX_INT32 i = 0; i < m_Blocks.GetSize(); i ++) {\r
-                FX_Allocator_Free(pAllocator, (FX_LPBYTE)m_Blocks[i]);\r
-            }\r
-        }\r
-        m_Blocks.RemoveAll();\r
-    }\r
-    virtual IFX_FileStream*            Retain()\r
-    {\r
-        m_dwCount ++;\r
-        return this;\r
-    }\r
-    virtual void                               Release()\r
-    {\r
-        FX_DWORD nCount = -- m_dwCount;\r
-        if (nCount) {\r
-            return;\r
-        }\r
-        IFX_Allocator* pAllocator = m_Blocks.m_pAllocator;\r
-        if (pAllocator) {\r
-            FX_DeleteAtAllocator(this, pAllocator, CFX_MemoryStream);\r
-        } else {\r
-            delete this;\r
-        }\r
-    }\r
-    virtual FX_FILESIZE                        GetSize()\r
-    {\r
-        return m_bUseRange ? (FX_FILESIZE) m_nSize : (FX_FILESIZE)m_nCurSize;\r
-    }\r
-    virtual FX_BOOL                            IsEOF()\r
-    {\r
-        return m_nCurPos >= (size_t)GetSize();\r
-    }\r
-    virtual FX_FILESIZE                        GetPosition()\r
-    {\r
-        FX_FILESIZE pos = (FX_FILESIZE)m_nCurPos;\r
-        if (m_bUseRange) {\r
-            pos -= (FX_FILESIZE)m_nOffset;\r
-        }\r
-        return pos;\r
-    }\r
-    virtual FX_BOOL                            SetRange(FX_FILESIZE offset, FX_FILESIZE size)\r
-    {\r
-        if (offset < 0 || (size_t)(offset + size) > m_nCurSize) {\r
-            return FALSE;\r
-        }\r
-        m_nOffset = (size_t)offset, m_nSize = (size_t)size;\r
-        m_bUseRange = TRUE;\r
-        m_nCurPos = m_nOffset;\r
-        return TRUE;\r
-    }\r
-    virtual void                               ClearRange()\r
-    {\r
-        m_bUseRange = FALSE;\r
-    }\r
-    virtual FX_BOOL                            ReadBlock(void* buffer, FX_FILESIZE offset, size_t size)\r
-    {\r
-        if (!buffer || !size) {\r
-            return FALSE;\r
-        }\r
-        if (m_bUseRange) {\r
-            offset += (FX_FILESIZE)m_nOffset;\r
-        }\r
-        if ((size_t)offset + size > m_nCurSize) {\r
-            return FALSE;\r
-        }\r
-        m_nCurPos = (size_t)offset + size;\r
-        if (m_dwFlags & FX_MEMSTREAM_Consecutive) {\r
-            FXSYS_memcpy32(buffer, (FX_LPBYTE)m_Blocks[0] + (size_t)offset, size);\r
-            return TRUE;\r
-        }\r
-        size_t nStartBlock = (size_t)offset / m_nGrowSize;\r
-        offset -= (FX_FILESIZE)(nStartBlock * m_nGrowSize);\r
-        while (size) {\r
-            size_t nRead = m_nGrowSize - (size_t)offset;\r
-            if (nRead > size) {\r
-                nRead = size;\r
-            }\r
-            FXSYS_memcpy32(buffer, (FX_LPBYTE)m_Blocks[(int)nStartBlock] + (size_t)offset, nRead);\r
-            buffer = ((FX_LPBYTE)buffer) + nRead;\r
-            size -= nRead;\r
-            nStartBlock ++;\r
-            offset = 0;\r
-        }\r
-        return TRUE;\r
-    }\r
-    virtual size_t                             ReadBlock(void* buffer, size_t size)\r
-    {\r
-        if (m_nCurPos >= m_nCurSize) {\r
-            return 0;\r
-        }\r
-        if (m_bUseRange) {\r
-            size_t availSize = m_nOffset + m_nSize - m_nCurPos;\r
-            if (availSize < size) {\r
-                size -= size - (size_t)availSize;\r
-            }\r
-        }\r
-        size_t nRead = FX_MIN(size, m_nCurSize - m_nCurPos);\r
-        if (!ReadBlock(buffer, (FX_INT32)m_nCurPos, nRead)) {\r
-            return 0;\r
-        }\r
-        return nRead;\r
-    }\r
-    virtual    FX_BOOL                         WriteBlock(const void* buffer, FX_FILESIZE offset, size_t size)\r
-    {\r
-        if (!buffer || !size) {\r
-            return FALSE;\r
-        }\r
-        if (m_bUseRange) {\r
-            offset += (FX_FILESIZE)m_nOffset;\r
-        }\r
-        if (m_dwFlags & FX_MEMSTREAM_Consecutive) {\r
-            m_nCurPos = (size_t)offset + size;\r
-            if (m_nCurPos > m_nTotalSize) {\r
-                IFX_Allocator* pAllocator = m_Blocks.m_pAllocator;\r
-                m_nTotalSize = (m_nCurPos + m_nGrowSize - 1) / m_nGrowSize * m_nGrowSize;\r
-                if (m_Blocks.GetSize() < 1) {\r
-                    void* block = FX_Allocator_Alloc(pAllocator, FX_BYTE, m_nTotalSize);\r
-                    m_Blocks.Add(block);\r
-                } else {\r
-                    m_Blocks[0] = FX_Allocator_Realloc(pAllocator, FX_BYTE, m_Blocks[0], m_nTotalSize);\r
-                }\r
-                if (!m_Blocks[0]) {\r
-                    m_Blocks.RemoveAll();\r
-                    return FALSE;\r
-                }\r
-            }\r
-            FXSYS_memcpy32((FX_LPBYTE)m_Blocks[0] + (size_t)offset, buffer, size);\r
-            if (m_nCurSize < m_nCurPos) {\r
-                m_nCurSize = m_nCurPos;\r
-            }\r
-            return TRUE;\r
-        }\r
-        if (!ExpandBlocks((size_t)offset + size)) {\r
-            return FALSE;\r
-        }\r
-        m_nCurPos = (size_t)offset + size;\r
-        size_t nStartBlock = (size_t)offset / m_nGrowSize;\r
-        offset -= (FX_FILESIZE)(nStartBlock * m_nGrowSize);\r
-        while (size) {\r
-            size_t nWrite = m_nGrowSize - (size_t)offset;\r
-            if (nWrite > size) {\r
-                nWrite = size;\r
-            }\r
-            FXSYS_memcpy32((FX_LPBYTE)m_Blocks[(int)nStartBlock] + (size_t)offset, buffer, nWrite);\r
-            buffer = ((FX_LPBYTE)buffer) + nWrite;\r
-            size -= nWrite;\r
-            nStartBlock ++;\r
-            offset = 0;\r
-        }\r
-        return TRUE;\r
-    }\r
-    virtual FX_BOOL                            Flush()\r
-    {\r
-        return TRUE;\r
-    }\r
-    virtual FX_BOOL                            IsConsecutive() const\r
-    {\r
-        return m_dwFlags & FX_MEMSTREAM_Consecutive;\r
-    }\r
-    virtual void                               EstimateSize(size_t nInitSize, size_t nGrowSize)\r
-    {\r
-        if (m_dwFlags & FX_MEMSTREAM_Consecutive) {\r
-            if (m_Blocks.GetSize() < 1) {\r
-                FX_LPBYTE pBlock = FX_Allocator_Alloc(m_Blocks.m_pAllocator, FX_BYTE, FX_MAX(nInitSize, 4096));\r
-                if (pBlock) {\r
-                    m_Blocks.Add(pBlock);\r
-                }\r
-            }\r
-            m_nGrowSize = FX_MAX(nGrowSize, 4096);\r
-        } else if (m_Blocks.GetSize() < 1) {\r
-            m_nGrowSize = FX_MAX(nGrowSize, 4096);\r
-        }\r
-    }\r
-    virtual FX_LPBYTE                  GetBuffer() const\r
-    {\r
-        return m_Blocks.GetSize() ? (FX_LPBYTE)m_Blocks[0] : NULL;\r
-    }\r
-    virtual void                               AttachBuffer(FX_LPBYTE pBuffer, size_t nSize, FX_BOOL bTakeOver = FALSE)\r
-    {\r
-        if (!(m_dwFlags & FX_MEMSTREAM_Consecutive)) {\r
-            return;\r
-        }\r
-        m_Blocks.RemoveAll();\r
-        m_Blocks.Add(pBuffer);\r
-        m_nTotalSize = m_nCurSize = nSize;\r
-        m_nCurPos = 0;\r
-        m_dwFlags = FX_MEMSTREAM_Consecutive | (bTakeOver ? FX_MEMSTREAM_TakeOver : 0);\r
-        ClearRange();\r
-    }\r
-    virtual void                               DetachBuffer()\r
-    {\r
-        if (!(m_dwFlags & FX_MEMSTREAM_Consecutive)) {\r
-            return;\r
-        }\r
-        m_Blocks.RemoveAll();\r
-        m_nTotalSize = m_nCurSize = m_nCurPos = 0;\r
-        m_dwFlags = FX_MEMSTREAM_TakeOver;\r
-        ClearRange();\r
-    }\r
-protected:\r
-    CFX_PtrArray       m_Blocks;\r
-    FX_DWORD           m_dwCount;\r
-    size_t                     m_nTotalSize;\r
-    size_t                     m_nCurSize;\r
-    size_t                     m_nCurPos;\r
-    size_t                     m_nGrowSize;\r
-    FX_DWORD           m_dwFlags;\r
-    FX_BOOL                    m_bUseRange;\r
-    size_t                     m_nOffset;\r
-    size_t                     m_nSize;\r
-    FX_BOOL    ExpandBlocks(size_t size)\r
-    {\r
-        if (m_nCurSize < size) {\r
-            m_nCurSize = size;\r
-        }\r
-        if (size <= m_nTotalSize) {\r
-            return TRUE;\r
-        }\r
-        FX_INT32 iCount = m_Blocks.GetSize();\r
-        size = (size - m_nTotalSize + m_nGrowSize - 1) / m_nGrowSize;\r
-        m_Blocks.SetSize(m_Blocks.GetSize() + (FX_INT32)size, -1);\r
-        IFX_Allocator* pAllocator = m_Blocks.m_pAllocator;\r
-        while (size --) {\r
-            FX_LPBYTE pBlock = FX_Allocator_Alloc(pAllocator, FX_BYTE, m_nGrowSize);\r
-            if (!pBlock) {\r
-                return FALSE;\r
-            }\r
-            m_Blocks.SetAt(iCount ++, pBlock);\r
-            m_nTotalSize += m_nGrowSize;\r
-        }\r
-        return TRUE;\r
-    }\r
-};\r
-#ifdef __cplusplus\r
-extern "C" {\r
-#endif\r
-#define MT_N                   848\r
-#define MT_M                   456\r
-#define MT_Matrix_A            0x9908b0df\r
-#define MT_Upper_Mask  0x80000000\r
-#define MT_Lower_Mask  0x7fffffff\r
-typedef struct _FX_MTRANDOMCONTEXT {\r
-    _FX_MTRANDOMCONTEXT()\r
-    {\r
-        mti = MT_N + 1;\r
-        bHaveSeed = FALSE;\r
-    }\r
-    FX_DWORD mti;\r
-    FX_BOOL     bHaveSeed;\r
-    FX_DWORD mt[MT_N];\r
-} FX_MTRANDOMCONTEXT, * FX_LPMTRANDOMCONTEXT;\r
-typedef FX_MTRANDOMCONTEXT const * FX_LPCMTRANDOMCONTEXT;\r
-#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_\r
-FX_BOOL FX_GenerateCryptoRandom(FX_LPDWORD pBuffer, FX_INT32 iCount);\r
-#endif\r
-#ifdef __cplusplus\r
-}\r
-#endif\r
-#endif\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
+
+#ifndef _FXCRT_EXTENSION_IMP_
+#define _FXCRT_EXTENSION_IMP_
+
+#include "../../../third_party/numerics/safe_math.h"
+
+class IFXCRT_FileAccess
+{
+public:
+    virtual ~IFXCRT_FileAccess() {}
+    virtual FX_BOOL            Open(FX_BSTR fileName, FX_DWORD dwMode) = 0;
+    virtual FX_BOOL            Open(FX_WSTR fileName, FX_DWORD dwMode) = 0;
+    virtual void               Close() = 0;
+    virtual void               Release() = 0;
+    virtual FX_FILESIZE        GetSize() const = 0;
+    virtual FX_FILESIZE        GetPosition() const = 0;
+    virtual FX_FILESIZE        SetPosition(FX_FILESIZE pos) = 0;
+    virtual size_t             Read(void* pBuffer, size_t szBuffer) = 0;
+    virtual size_t             Write(const void* pBuffer, size_t szBuffer) = 0;
+    virtual size_t             ReadPos(void* pBuffer, size_t szBuffer, FX_FILESIZE pos) = 0;
+    virtual size_t             WritePos(const void* pBuffer, size_t szBuffer, FX_FILESIZE pos) = 0;
+    virtual FX_BOOL            Flush() = 0;
+    virtual FX_BOOL            Truncate(FX_FILESIZE szFile) = 0;
+};
+IFXCRT_FileAccess*     FXCRT_FileAccess_Create();
+class CFX_CRTFileStream FX_FINAL : public IFX_FileStream, public CFX_Object
+{
+public:
+    CFX_CRTFileStream(IFXCRT_FileAccess* pFA) : m_pFile(pFA), m_dwCount(1), m_bUseRange(FALSE), m_nOffset(0), m_nSize(0) {}
+    ~CFX_CRTFileStream()
+    {
+        if (m_pFile) {
+            m_pFile->Release();
+        }
+    }
+    virtual IFX_FileStream*            Retain()
+    {
+        m_dwCount ++;
+        return this;
+    }
+    virtual void                               Release()
+    {
+        FX_DWORD nCount = -- m_dwCount;
+        if (!nCount) {
+            delete this;
+        }
+    }
+    virtual FX_FILESIZE                        GetSize()
+    {
+        return m_bUseRange ? m_nSize : m_pFile->GetSize();
+    }
+    virtual FX_BOOL                            IsEOF()
+    {
+        return GetPosition() >= GetSize();
+    }
+    virtual FX_FILESIZE                        GetPosition()
+    {
+        FX_FILESIZE pos = m_pFile->GetPosition();
+        if (m_bUseRange) {
+            pos -= m_nOffset;
+        }
+        return pos;
+    }
+    virtual FX_BOOL                            SetRange(FX_FILESIZE offset, FX_FILESIZE size)
+    {
+        if (offset < 0 || offset + size > m_pFile->GetSize()) {
+            return FALSE;
+        }
+        m_nOffset = offset, m_nSize = size;
+        m_bUseRange = TRUE;
+        m_pFile->SetPosition(m_nOffset);
+        return TRUE;
+    }
+    virtual void                               ClearRange()
+    {
+        m_bUseRange = FALSE;
+    }
+    virtual FX_BOOL                            ReadBlock(void* buffer, FX_FILESIZE offset, size_t size)
+    {
+        if (m_bUseRange) {
+            if (offset + size > (size_t)GetSize()) {
+                return FALSE;
+            }
+            offset += m_nOffset;
+        }
+        return (FX_BOOL)m_pFile->ReadPos(buffer, size, offset);
+    }
+    virtual size_t                             ReadBlock(void* buffer, size_t size)
+    {
+        if (m_bUseRange) {
+            FX_FILESIZE availSize = m_nOffset + m_nSize - m_pFile->GetPosition();
+            if ((size_t)availSize < size) {
+                size -= size - (size_t)availSize;
+            }
+        }
+        return m_pFile->Read(buffer, size);
+    }
+    virtual    FX_BOOL                         WriteBlock(const void* buffer, FX_FILESIZE offset, size_t size)
+    {
+        if (m_bUseRange) {
+            offset += m_nOffset;
+        }
+        return (FX_BOOL)m_pFile->WritePos(buffer, size, offset);
+    }
+    virtual FX_BOOL                            Flush()
+    {
+        return m_pFile->Flush();
+    }
+    IFXCRT_FileAccess* m_pFile;
+    FX_DWORD                   m_dwCount;
+    FX_BOOL                            m_bUseRange;
+    FX_FILESIZE                        m_nOffset;
+    FX_FILESIZE                        m_nSize;
+};
+#define FX_MEMSTREAM_BlockSize         (64 * 1024)
+#define FX_MEMSTREAM_Consecutive       0x01
+#define FX_MEMSTREAM_TakeOver          0x02
+class CFX_MemoryStream FX_FINAL : public IFX_MemoryStream, public CFX_Object
+{
+public:
+    CFX_MemoryStream(FX_BOOL bConsecutive)
+        : m_dwCount(1)
+        , m_nTotalSize(0)
+        , m_nCurSize(0)
+        , m_nCurPos(0)
+        , m_nGrowSize(FX_MEMSTREAM_BlockSize)
+        , m_bUseRange(FALSE)
+    {
+        m_dwFlags = FX_MEMSTREAM_TakeOver | (bConsecutive ? FX_MEMSTREAM_Consecutive : 0);
+    }
+    CFX_MemoryStream(FX_LPBYTE pBuffer, size_t nSize, FX_BOOL bTakeOver)
+        : m_dwCount(1)
+        , m_nTotalSize(nSize)
+        , m_nCurSize(nSize)
+        , m_nCurPos(0)
+        , m_nGrowSize(FX_MEMSTREAM_BlockSize)
+        , m_bUseRange(FALSE)
+    {
+        m_Blocks.Add(pBuffer);
+        m_dwFlags = FX_MEMSTREAM_Consecutive | (bTakeOver ? FX_MEMSTREAM_TakeOver : 0);
+    }
+    ~CFX_MemoryStream()
+    {
+        if (m_dwFlags & FX_MEMSTREAM_TakeOver) {
+            for (FX_INT32 i = 0; i < m_Blocks.GetSize(); i++) {
+                FX_Free((FX_LPBYTE)m_Blocks[i]);
+            }
+        }
+        m_Blocks.RemoveAll();
+    }
+    virtual IFX_FileStream*            Retain()
+    {
+        m_dwCount ++;
+        return this;
+    }
+    virtual void                               Release()
+    {
+        FX_DWORD nCount = -- m_dwCount;
+        if (nCount) {
+            return;
+        }
+        delete this;
+    }
+    virtual FX_FILESIZE                        GetSize()
+    {
+        return m_bUseRange ? (FX_FILESIZE) m_nSize : (FX_FILESIZE)m_nCurSize;
+    }
+    virtual FX_BOOL                            IsEOF()
+    {
+        return m_nCurPos >= (size_t)GetSize();
+    }
+    virtual FX_FILESIZE                        GetPosition()
+    {
+        FX_FILESIZE pos = (FX_FILESIZE)m_nCurPos;
+        if (m_bUseRange) {
+            pos -= (FX_FILESIZE)m_nOffset;
+        }
+        return pos;
+    }
+    virtual FX_BOOL                            SetRange(FX_FILESIZE offset, FX_FILESIZE size)
+    {
+        base::CheckedNumeric<FX_FILESIZE> range = size;
+        range += size;
+        if (!range.IsValid() || offset <= 0 || size <= 0 || range.ValueOrDie() > m_nCurSize) {
+            return FALSE;
+        }
+        
+        m_nOffset = (size_t)offset, m_nSize = (size_t)size;
+        m_bUseRange = TRUE;
+        m_nCurPos = m_nOffset;
+        return TRUE;
+    }
+    virtual void                               ClearRange()
+    {
+        m_bUseRange = FALSE;
+    }
+    virtual FX_BOOL                            ReadBlock(void* buffer, FX_FILESIZE offset, size_t size)
+    {
+        if (!buffer || !size) {
+            return FALSE;
+        }
+
+        base::CheckedNumeric<FX_FILESIZE> safeOffset = offset;
+        if (m_bUseRange) {
+            safeOffset += m_nOffset;
+        }
+         
+        if (!safeOffset.IsValid()) {
+            return FALSE;
+        }
+
+        offset = safeOffset.ValueOrDie();
+
+        base::CheckedNumeric<size_t> newPos = size;
+        newPos += offset;
+        if (!newPos.IsValid() || newPos.ValueOrDefault(0) == 0 || newPos.ValueOrDie() > m_nCurSize) {
+            return FALSE;
+        }
+
+        m_nCurPos = newPos.ValueOrDie();
+        if (m_dwFlags & FX_MEMSTREAM_Consecutive) {
+            FXSYS_memcpy32(buffer, (FX_LPBYTE)m_Blocks[0] + (size_t)offset, size);
+            return TRUE;
+        }
+        size_t nStartBlock = (size_t)offset / m_nGrowSize;
+        offset -= (FX_FILESIZE)(nStartBlock * m_nGrowSize);
+        while (size) {
+            size_t nRead = m_nGrowSize - (size_t)offset;
+            if (nRead > size) {
+                nRead = size;
+            }
+            FXSYS_memcpy32(buffer, (FX_LPBYTE)m_Blocks[(int)nStartBlock] + (size_t)offset, nRead);
+            buffer = ((FX_LPBYTE)buffer) + nRead;
+            size -= nRead;
+            nStartBlock ++;
+            offset = 0;
+        }
+        return TRUE;
+    }
+    virtual size_t                             ReadBlock(void* buffer, size_t size)
+    {
+        if (m_nCurPos >= m_nCurSize) {
+            return 0;
+        }
+        if (m_bUseRange) {
+            size_t availSize = m_nOffset + m_nSize - m_nCurPos;
+            if (availSize < size) {
+                size -= size - (size_t)availSize;
+            }
+        }
+        size_t nRead = FX_MIN(size, m_nCurSize - m_nCurPos);
+        if (!ReadBlock(buffer, (FX_INT32)m_nCurPos, nRead)) {
+            return 0;
+        }
+        return nRead;
+    }
+    virtual    FX_BOOL                         WriteBlock(const void* buffer, FX_FILESIZE offset, size_t size)
+    {
+        if (!buffer || !size) {
+            return FALSE;
+        }
+        if (m_bUseRange) {
+            offset += (FX_FILESIZE)m_nOffset;
+        }
+        if (m_dwFlags & FX_MEMSTREAM_Consecutive) {
+            base::CheckedNumeric<size_t> newPos = size; 
+            newPos += offset;
+            if (!newPos.IsValid())
+                return FALSE;
+
+            m_nCurPos = newPos.ValueOrDie();
+            if (m_nCurPos > m_nTotalSize) {
+                m_nTotalSize = (m_nCurPos + m_nGrowSize - 1) / m_nGrowSize * m_nGrowSize;
+                if (m_Blocks.GetSize() < 1) {
+                    void* block = FX_Alloc(FX_BYTE, m_nTotalSize);
+                    m_Blocks.Add(block);
+                } else {
+                    m_Blocks[0] = FX_Realloc(FX_BYTE, m_Blocks[0], m_nTotalSize);
+                }
+                if (!m_Blocks[0]) {
+                    m_Blocks.RemoveAll();
+                    return FALSE;
+                }
+            }
+            FXSYS_memcpy32((FX_LPBYTE)m_Blocks[0] + (size_t)offset, buffer, size);
+            if (m_nCurSize < m_nCurPos) {
+                m_nCurSize = m_nCurPos;
+            }
+            return TRUE;
+        }
+
+        base::CheckedNumeric<size_t> newPos = size;
+        newPos += offset;
+        if (!newPos.IsValid())
+            return FALSE;
+
+        if (!ExpandBlocks(newPos.ValueOrDie())) {
+            return FALSE;
+        }
+        m_nCurPos = newPos.ValueOrDie();
+        size_t nStartBlock = (size_t)offset / m_nGrowSize;
+        offset -= (FX_FILESIZE)(nStartBlock * m_nGrowSize);
+        while (size) {
+            size_t nWrite = m_nGrowSize - (size_t)offset;
+            if (nWrite > size) {
+                nWrite = size;
+            }
+            FXSYS_memcpy32((FX_LPBYTE)m_Blocks[(int)nStartBlock] + (size_t)offset, buffer, nWrite);
+            buffer = ((FX_LPBYTE)buffer) + nWrite;
+            size -= nWrite;
+            nStartBlock ++;
+            offset = 0;
+        }
+        return TRUE;
+    }
+    virtual FX_BOOL                            Flush()
+    {
+        return TRUE;
+    }
+    virtual FX_BOOL                            IsConsecutive() const
+    {
+        return m_dwFlags & FX_MEMSTREAM_Consecutive;
+    }
+    virtual void                               EstimateSize(size_t nInitSize, size_t nGrowSize)
+    {
+        if (m_dwFlags & FX_MEMSTREAM_Consecutive) {
+            if (m_Blocks.GetSize() < 1) {
+                FX_LPBYTE pBlock = FX_Alloc(FX_BYTE, FX_MAX(nInitSize, 4096));
+                if (pBlock) {
+                    m_Blocks.Add(pBlock);
+                }
+            }
+            m_nGrowSize = FX_MAX(nGrowSize, 4096);
+        } else if (m_Blocks.GetSize() < 1) {
+            m_nGrowSize = FX_MAX(nGrowSize, 4096);
+        }
+    }
+    virtual FX_LPBYTE                  GetBuffer() const
+    {
+        return m_Blocks.GetSize() ? (FX_LPBYTE)m_Blocks[0] : NULL;
+    }
+    virtual void                               AttachBuffer(FX_LPBYTE pBuffer, size_t nSize, FX_BOOL bTakeOver = FALSE)
+    {
+        if (!(m_dwFlags & FX_MEMSTREAM_Consecutive)) {
+            return;
+        }
+        m_Blocks.RemoveAll();
+        m_Blocks.Add(pBuffer);
+        m_nTotalSize = m_nCurSize = nSize;
+        m_nCurPos = 0;
+        m_dwFlags = FX_MEMSTREAM_Consecutive | (bTakeOver ? FX_MEMSTREAM_TakeOver : 0);
+        ClearRange();
+    }
+    virtual void                               DetachBuffer()
+    {
+        if (!(m_dwFlags & FX_MEMSTREAM_Consecutive)) {
+            return;
+        }
+        m_Blocks.RemoveAll();
+        m_nTotalSize = m_nCurSize = m_nCurPos = 0;
+        m_dwFlags = FX_MEMSTREAM_TakeOver;
+        ClearRange();
+    }
+protected:
+    CFX_PtrArray       m_Blocks;
+    FX_DWORD           m_dwCount;
+    size_t                     m_nTotalSize;
+    size_t                     m_nCurSize;
+    size_t                     m_nCurPos;
+    size_t                     m_nGrowSize;
+    FX_DWORD           m_dwFlags;
+    FX_BOOL                    m_bUseRange;
+    size_t                     m_nOffset;
+    size_t                     m_nSize;
+    FX_BOOL    ExpandBlocks(size_t size)
+    {
+        if (m_nCurSize < size) {
+            m_nCurSize = size;
+        }
+        if (size <= m_nTotalSize) {
+            return TRUE;
+        }
+        FX_INT32 iCount = m_Blocks.GetSize();
+        size = (size - m_nTotalSize + m_nGrowSize - 1) / m_nGrowSize;
+        m_Blocks.SetSize(m_Blocks.GetSize() + (FX_INT32)size);
+        while (size --) {
+            FX_LPBYTE pBlock = FX_Alloc(FX_BYTE, m_nGrowSize);
+            if (!pBlock) {
+                return FALSE;
+            }
+            m_Blocks.SetAt(iCount ++, pBlock);
+            m_nTotalSize += m_nGrowSize;
+        }
+        return TRUE;
+    }
+};
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define MT_N                   848
+#define MT_M                   456
+#define MT_Matrix_A            0x9908b0df
+#define MT_Upper_Mask  0x80000000
+#define MT_Lower_Mask  0x7fffffff
+typedef struct _FX_MTRANDOMCONTEXT {
+    _FX_MTRANDOMCONTEXT()
+    {
+        mti = MT_N + 1;
+        bHaveSeed = FALSE;
+    }
+    FX_DWORD mti;
+    FX_BOOL     bHaveSeed;
+    FX_DWORD mt[MT_N];
+} FX_MTRANDOMCONTEXT, * FX_LPMTRANDOMCONTEXT;
+typedef FX_MTRANDOMCONTEXT const * FX_LPCMTRANDOMCONTEXT;
+#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
+FX_BOOL FX_GenerateCryptoRandom(FX_LPDWORD pBuffer, FX_INT32 iCount);
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif