Fix infinite loop for objects that reference themselves.
[pdfium.git] / core / src / fxcrt / extension.h
index bf5c5ec..a712fa3 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 CORE_SRC_FXCRT_EXTENSION_H_
+#define CORE_SRC_FXCRT_EXTENSION_H_
+
+#include "../../include/fxcrt/fx_basic.h"
+#include "../../include/fxcrt/fx_safe_types.h"
+
+class IFXCRT_FileAccess {
+ public:
+  virtual ~IFXCRT_FileAccess() {}
+  virtual FX_BOOL Open(const CFX_ByteStringC& fileName, FX_DWORD dwMode) = 0;
+  virtual FX_BOOL Open(const CFX_WideStringC& 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 final : public IFX_FileStream {
+ public:
+  CFX_CRTFileStream(IFXCRT_FileAccess* pFA) : m_pFile(pFA), m_dwCount(1) {}
+  ~CFX_CRTFileStream() override {
+    if (m_pFile) {
+      m_pFile->Release();
+    }
+  }
+  virtual IFX_FileStream* Retain() override {
+    m_dwCount++;
+    return this;
+  }
+  virtual void Release() override {
+    FX_DWORD nCount = --m_dwCount;
+    if (!nCount) {
+      delete this;
+    }
+  }
+  virtual FX_FILESIZE GetSize() override { return m_pFile->GetSize(); }
+  virtual FX_BOOL IsEOF() override { return GetPosition() >= GetSize(); }
+  virtual FX_FILESIZE GetPosition() override { return m_pFile->GetPosition(); }
+  virtual FX_BOOL ReadBlock(void* buffer,
+                            FX_FILESIZE offset,
+                            size_t size) override {
+    return (FX_BOOL)m_pFile->ReadPos(buffer, size, offset);
+  }
+  virtual size_t ReadBlock(void* buffer, size_t size) override {
+    return m_pFile->Read(buffer, size);
+  }
+  virtual FX_BOOL WriteBlock(const void* buffer,
+                             FX_FILESIZE offset,
+                             size_t size) override {
+    return (FX_BOOL)m_pFile->WritePos(buffer, size, offset);
+  }
+  virtual FX_BOOL Flush() override { return m_pFile->Flush(); }
+
+ protected:
+  IFXCRT_FileAccess* m_pFile;
+  FX_DWORD m_dwCount;
+};
+
+#define FX_MEMSTREAM_BlockSize (64 * 1024)
+#define FX_MEMSTREAM_Consecutive 0x01
+#define FX_MEMSTREAM_TakeOver 0x02
+class CFX_MemoryStream final : public IFX_MemoryStream {
+ public:
+  CFX_MemoryStream(FX_BOOL bConsecutive)
+      : m_dwCount(1),
+        m_nTotalSize(0),
+        m_nCurSize(0),
+        m_nCurPos(0),
+        m_nGrowSize(FX_MEMSTREAM_BlockSize) {
+    m_dwFlags =
+        FX_MEMSTREAM_TakeOver | (bConsecutive ? FX_MEMSTREAM_Consecutive : 0);
+  }
+  CFX_MemoryStream(uint8_t* 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_Blocks.Add(pBuffer);
+    m_dwFlags =
+        FX_MEMSTREAM_Consecutive | (bTakeOver ? FX_MEMSTREAM_TakeOver : 0);
+  }
+  ~CFX_MemoryStream() override {
+    if (m_dwFlags & FX_MEMSTREAM_TakeOver) {
+      for (int32_t i = 0; i < m_Blocks.GetSize(); i++) {
+        FX_Free((uint8_t*)m_Blocks[i]);
+      }
+    }
+    m_Blocks.RemoveAll();
+  }
+  virtual IFX_FileStream* Retain() override {
+    m_dwCount++;
+    return this;
+  }
+  virtual void Release() override {
+    FX_DWORD nCount = --m_dwCount;
+    if (nCount) {
+      return;
+    }
+    delete this;
+  }
+  virtual FX_FILESIZE GetSize() override { return (FX_FILESIZE)m_nCurSize; }
+  virtual FX_BOOL IsEOF() override { return m_nCurPos >= (size_t)GetSize(); }
+  virtual FX_FILESIZE GetPosition() override { return (FX_FILESIZE)m_nCurPos; }
+  virtual FX_BOOL ReadBlock(void* buffer,
+                            FX_FILESIZE offset,
+                            size_t size) override {
+    if (!buffer || !size) {
+      return FALSE;
+    }
+
+    FX_SAFE_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_memcpy(buffer, (uint8_t*)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_memcpy(
+          buffer, (uint8_t*)m_Blocks[(int)nStartBlock] + (size_t)offset, nRead);
+      buffer = ((uint8_t*)buffer) + nRead;
+      size -= nRead;
+      nStartBlock++;
+      offset = 0;
+    }
+    return TRUE;
+  }
+  virtual size_t ReadBlock(void* buffer, size_t size) override {
+    if (m_nCurPos >= m_nCurSize) {
+      return 0;
+    }
+    size_t nRead = FX_MIN(size, m_nCurSize - m_nCurPos);
+    if (!ReadBlock(buffer, (int32_t)m_nCurPos, nRead)) {
+      return 0;
+    }
+    return nRead;
+  }
+  virtual FX_BOOL WriteBlock(const void* buffer,
+                             FX_FILESIZE offset,
+                             size_t size) override {
+    if (!buffer || !size) {
+      return FALSE;
+    }
+    if (m_dwFlags & FX_MEMSTREAM_Consecutive) {
+      FX_SAFE_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(uint8_t, m_nTotalSize);
+          m_Blocks.Add(block);
+        } else {
+          m_Blocks[0] = FX_Realloc(uint8_t, m_Blocks[0], m_nTotalSize);
+        }
+        if (!m_Blocks[0]) {
+          m_Blocks.RemoveAll();
+          return FALSE;
+        }
+      }
+      FXSYS_memcpy((uint8_t*)m_Blocks[0] + (size_t)offset, buffer, size);
+      if (m_nCurSize < m_nCurPos) {
+        m_nCurSize = m_nCurPos;
+      }
+      return TRUE;
+    }
+
+    FX_SAFE_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_memcpy((uint8_t*)m_Blocks[(int)nStartBlock] + (size_t)offset,
+                   buffer, nWrite);
+      buffer = ((uint8_t*)buffer) + nWrite;
+      size -= nWrite;
+      nStartBlock++;
+      offset = 0;
+    }
+    return TRUE;
+  }
+  virtual FX_BOOL Flush() override { return TRUE; }
+  virtual FX_BOOL IsConsecutive() const override {
+    return m_dwFlags & FX_MEMSTREAM_Consecutive;
+  }
+  virtual void EstimateSize(size_t nInitSize, size_t nGrowSize) override {
+    if (m_dwFlags & FX_MEMSTREAM_Consecutive) {
+      if (m_Blocks.GetSize() < 1) {
+        uint8_t* pBlock = FX_Alloc(uint8_t, FX_MAX(nInitSize, 4096));
+        m_Blocks.Add(pBlock);
+      }
+      m_nGrowSize = FX_MAX(nGrowSize, 4096);
+    } else if (m_Blocks.GetSize() < 1) {
+      m_nGrowSize = FX_MAX(nGrowSize, 4096);
+    }
+  }
+  virtual uint8_t* GetBuffer() const override {
+    return m_Blocks.GetSize() ? (uint8_t*)m_Blocks[0] : NULL;
+  }
+  virtual void AttachBuffer(uint8_t* pBuffer,
+                            size_t nSize,
+                            FX_BOOL bTakeOver = FALSE) override {
+    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);
+  }
+  virtual void DetachBuffer() override {
+    if (!(m_dwFlags & FX_MEMSTREAM_Consecutive)) {
+      return;
+    }
+    m_Blocks.RemoveAll();
+    m_nTotalSize = m_nCurSize = m_nCurPos = 0;
+    m_dwFlags = FX_MEMSTREAM_TakeOver;
+  }
+
+ 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 ExpandBlocks(size_t size) {
+    if (m_nCurSize < size) {
+      m_nCurSize = size;
+    }
+    if (size <= m_nTotalSize) {
+      return TRUE;
+    }
+    int32_t iCount = m_Blocks.GetSize();
+    size = (size - m_nTotalSize + m_nGrowSize - 1) / m_nGrowSize;
+    m_Blocks.SetSize(m_Blocks.GetSize() + (int32_t)size);
+    while (size--) {
+      uint8_t* pBlock = FX_Alloc(uint8_t, m_nGrowSize);
+      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_DWORD* pBuffer, int32_t iCount);
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // CORE_SRC_FXCRT_EXTENSION_H_