| // 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 "xfa/fgas/crt/fgas_stream.h" |
| |
| #if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN32_MOBILE_ || \ |
| _FX_OS_ == _FX_WIN64_ |
| #include <io.h> |
| #endif |
| |
| #include <algorithm> |
| #include <memory> |
| |
| #include "xfa/fgas/crt/fgas_codepage.h" |
| |
| namespace { |
| |
| class IFX_StreamImp { |
| public: |
| virtual ~IFX_StreamImp() {} |
| |
| virtual int32_t GetLength() const = 0; |
| virtual int32_t Seek(FX_STREAMSEEK eSeek, int32_t iOffset) = 0; |
| virtual int32_t GetPosition() = 0; |
| virtual bool IsEOF() const = 0; |
| virtual int32_t ReadData(uint8_t* pBuffer, int32_t iBufferSize) = 0; |
| virtual int32_t ReadString(FX_WCHAR* pStr, |
| int32_t iMaxLength, |
| bool& bEOS) = 0; |
| virtual int32_t WriteData(const uint8_t* pBuffer, int32_t iBufferSize) = 0; |
| virtual int32_t WriteString(const FX_WCHAR* pStr, int32_t iLength) = 0; |
| virtual void Flush() = 0; |
| virtual bool SetLength(int32_t iLength) = 0; |
| |
| protected: |
| IFX_StreamImp(); |
| |
| uint32_t GetAccessModes() const { return m_dwAccess; } |
| void SetAccessModes(uint32_t modes) { m_dwAccess = modes; } |
| |
| private: |
| uint32_t m_dwAccess; |
| }; |
| |
| class CFX_FileStreamImp : public IFX_StreamImp { |
| public: |
| CFX_FileStreamImp(); |
| ~CFX_FileStreamImp() override; |
| |
| bool LoadFile(const FX_WCHAR* pszSrcFileName, uint32_t dwAccess); |
| |
| // IFX_StreamImp: |
| int32_t GetLength() const override; |
| int32_t Seek(FX_STREAMSEEK eSeek, int32_t iOffset) override; |
| int32_t GetPosition() override; |
| bool IsEOF() const override; |
| int32_t ReadData(uint8_t* pBuffer, int32_t iBufferSize) override; |
| int32_t ReadString(FX_WCHAR* pStr, int32_t iMaxLength, bool& bEOS) override; |
| int32_t WriteData(const uint8_t* pBuffer, int32_t iBufferSize) override; |
| int32_t WriteString(const FX_WCHAR* pStr, int32_t iLength) override; |
| void Flush() override; |
| bool SetLength(int32_t iLength) override; |
| |
| protected: |
| FXSYS_FILE* m_hFile; |
| int32_t m_iLength; |
| }; |
| |
| class CFX_BufferStreamImp : public IFX_StreamImp { |
| public: |
| CFX_BufferStreamImp(); |
| ~CFX_BufferStreamImp() override {} |
| |
| bool LoadBuffer(uint8_t* pData, int32_t iTotalSize, uint32_t dwAccess); |
| |
| // IFX_StreamImp: |
| int32_t GetLength() const override; |
| int32_t Seek(FX_STREAMSEEK eSeek, int32_t iOffset) override; |
| int32_t GetPosition() override; |
| bool IsEOF() const override; |
| int32_t ReadData(uint8_t* pBuffer, int32_t iBufferSize) override; |
| int32_t ReadString(FX_WCHAR* pStr, int32_t iMaxLength, bool& bEOS) override; |
| int32_t WriteData(const uint8_t* pBuffer, int32_t iBufferSize) override; |
| int32_t WriteString(const FX_WCHAR* pStr, int32_t iLength) override; |
| void Flush() override {} |
| bool SetLength(int32_t iLength) override { return false; } |
| |
| protected: |
| uint8_t* m_pData; |
| int32_t m_iTotalSize; |
| int32_t m_iPosition; |
| int32_t m_iLength; |
| }; |
| |
| class CFX_FileReadStreamImp : public IFX_StreamImp { |
| public: |
| CFX_FileReadStreamImp(); |
| ~CFX_FileReadStreamImp() override {} |
| |
| bool LoadFileRead(IFX_SeekableReadStream* pFileRead, uint32_t dwAccess); |
| |
| // IFX_StreamImp: |
| int32_t GetLength() const override; |
| int32_t Seek(FX_STREAMSEEK eSeek, int32_t iOffset) override; |
| int32_t GetPosition() override { return m_iPosition; } |
| bool IsEOF() const override; |
| int32_t ReadData(uint8_t* pBuffer, int32_t iBufferSize) override; |
| int32_t ReadString(FX_WCHAR* pStr, int32_t iMaxLength, bool& bEOS) override; |
| int32_t WriteData(const uint8_t* pBuffer, int32_t iBufferSize) override { |
| return 0; |
| } |
| int32_t WriteString(const FX_WCHAR* pStr, int32_t iLength) override { |
| return 0; |
| } |
| void Flush() override {} |
| bool SetLength(int32_t iLength) override { return false; } |
| |
| protected: |
| IFX_SeekableReadStream* m_pFileRead; |
| int32_t m_iPosition; |
| int32_t m_iLength; |
| }; |
| |
| class CFX_BufferReadStreamImp : public IFX_StreamImp { |
| public: |
| CFX_BufferReadStreamImp(); |
| ~CFX_BufferReadStreamImp() override; |
| |
| bool LoadBufferRead(IFX_BufferRead* pBufferRead, |
| int32_t iFileSize, |
| uint32_t dwAccess, |
| bool bReleaseBufferRead); |
| |
| // IFX_StreamImp: |
| int32_t GetLength() const override; |
| int32_t Seek(FX_STREAMSEEK eSeek, int32_t iOffset) override; |
| int32_t GetPosition() override { return m_iPosition; } |
| bool IsEOF() const override; |
| int32_t ReadData(uint8_t* pBuffer, int32_t iBufferSize) override; |
| int32_t ReadString(FX_WCHAR* pStr, int32_t iMaxLength, bool& bEOS) override; |
| int32_t WriteData(const uint8_t* pBuffer, int32_t iBufferSize) override { |
| return 0; |
| } |
| int32_t WriteString(const FX_WCHAR* pStr, int32_t iLength) override { |
| return 0; |
| } |
| void Flush() override {} |
| bool SetLength(int32_t iLength) override { return false; } |
| |
| private: |
| IFX_BufferRead* m_pBufferRead; |
| bool m_bReleaseBufferRead; |
| int32_t m_iPosition; |
| int32_t m_iBufferSize; |
| }; |
| |
| class CFX_FileWriteStreamImp : public IFX_StreamImp { |
| public: |
| CFX_FileWriteStreamImp(); |
| ~CFX_FileWriteStreamImp() override {} |
| |
| bool LoadFileWrite(IFX_SeekableWriteStream* pFileWrite, uint32_t dwAccess); |
| |
| // IFX_StreamImp: |
| int32_t GetLength() const override; |
| int32_t Seek(FX_STREAMSEEK eSeek, int32_t iOffset) override; |
| int32_t GetPosition() override { return m_iPosition; } |
| bool IsEOF() const override; |
| int32_t ReadData(uint8_t* pBuffer, int32_t iBufferSize) override { return 0; } |
| int32_t ReadString(FX_WCHAR* pStr, int32_t iMaxLength, bool& bEOS) override { |
| return 0; |
| } |
| int32_t WriteData(const uint8_t* pBuffer, int32_t iBufferSize) override; |
| int32_t WriteString(const FX_WCHAR* pStr, int32_t iLength) override; |
| void Flush() override; |
| bool SetLength(int32_t iLength) override { return false; } |
| |
| protected: |
| IFX_SeekableWriteStream* m_pFileWrite; |
| int32_t m_iPosition; |
| }; |
| |
| enum FX_STREAMTYPE { |
| FX_SREAMTYPE_Unknown = 0, |
| FX_STREAMTYPE_File, |
| FX_STREAMTYPE_Buffer, |
| FX_STREAMTYPE_Stream, |
| FX_STREAMTYPE_BufferRead, |
| }; |
| |
| class CFX_Stream : public IFX_Stream { |
| public: |
| CFX_Stream(); |
| ~CFX_Stream() override; |
| |
| bool LoadFile(const FX_WCHAR* pszSrcFileName, uint32_t dwAccess); |
| bool LoadBuffer(uint8_t* pData, int32_t iTotalSize, uint32_t dwAccess); |
| bool LoadFileRead(IFX_SeekableReadStream* pFileRead, uint32_t dwAccess); |
| bool LoadFileWrite(IFX_SeekableWriteStream* pFileWrite, uint32_t dwAccess); |
| bool LoadBufferRead(IFX_BufferRead* pBufferRead, |
| int32_t iFileSize, |
| uint32_t dwAccess, |
| bool bReleaseBufferRead); |
| |
| // IFX_Stream |
| void Release() override; |
| IFX_Stream* Retain() override; |
| uint32_t GetAccessModes() const override; |
| int32_t GetLength() const override; |
| int32_t Seek(FX_STREAMSEEK eSeek, int32_t iOffset) override; |
| int32_t GetPosition() override; |
| bool IsEOF() const override; |
| int32_t ReadData(uint8_t* pBuffer, int32_t iBufferSize) override; |
| int32_t ReadString(FX_WCHAR* pStr, int32_t iMaxLength, bool& bEOS) override; |
| int32_t WriteData(const uint8_t* pBuffer, int32_t iBufferSize) override; |
| int32_t WriteString(const FX_WCHAR* pStr, int32_t iLength) override; |
| void Flush() override; |
| bool SetLength(int32_t iLength) override; |
| int32_t GetBOM(uint8_t bom[4]) const override; |
| uint16_t GetCodePage() const override; |
| uint16_t SetCodePage(uint16_t wCodePage) override; |
| IFX_Stream* CreateSharedStream(uint32_t dwAccess, |
| int32_t iOffset, |
| int32_t iLength) override; |
| |
| protected: |
| FX_STREAMTYPE m_eStreamType; |
| IFX_StreamImp* m_pStreamImp; |
| uint32_t m_dwAccess; |
| int32_t m_iTotalSize; |
| int32_t m_iPosition; |
| int32_t m_iStart; |
| int32_t m_iLength; |
| int32_t m_iRefCount; |
| }; |
| |
| class CFX_TextStream : public IFX_Stream { |
| public: |
| CFX_TextStream(IFX_Stream* pStream, bool bDelStream); |
| ~CFX_TextStream() override; |
| |
| // IFX_Stream |
| void Release() override; |
| IFX_Stream* Retain() override; |
| uint32_t GetAccessModes() const override; |
| int32_t GetLength() const override; |
| int32_t Seek(FX_STREAMSEEK eSeek, int32_t iOffset) override; |
| int32_t GetPosition() override; |
| bool IsEOF() const override; |
| int32_t ReadData(uint8_t* pBuffer, int32_t iBufferSize) override; |
| int32_t ReadString(FX_WCHAR* pStr, int32_t iMaxLength, bool& bEOS) override; |
| int32_t WriteData(const uint8_t* pBuffer, int32_t iBufferSize) override; |
| int32_t WriteString(const FX_WCHAR* pStr, int32_t iLength) override; |
| void Flush() override; |
| bool SetLength(int32_t iLength) override; |
| int32_t GetBOM(uint8_t bom[4]) const override; |
| uint16_t GetCodePage() const override; |
| uint16_t SetCodePage(uint16_t wCodePage) override; |
| IFX_Stream* CreateSharedStream(uint32_t dwAccess, |
| int32_t iOffset, |
| int32_t iLength) override; |
| |
| protected: |
| uint16_t m_wCodePage; |
| int32_t m_wBOMLength; |
| uint32_t m_dwBOM; |
| uint8_t* m_pBuf; |
| int32_t m_iBufSize; |
| bool m_bDelStream; |
| IFX_Stream* m_pStreamImp; |
| int32_t m_iRefCount; |
| void InitStream(); |
| }; |
| |
| class CFGAS_FileRead : public IFX_SeekableReadStream { |
| public: |
| CFGAS_FileRead(IFX_Stream* pStream, bool bReleaseStream); |
| ~CFGAS_FileRead() override; |
| |
| // IFX_SeekableReadStream |
| void Release() override; |
| FX_FILESIZE GetSize() override; |
| bool ReadBlock(void* buffer, FX_FILESIZE offset, size_t size) override; |
| |
| protected: |
| bool m_bReleaseStream; |
| IFX_Stream* m_pStream; |
| }; |
| |
| int32_t FileLength(FXSYS_FILE* file) { |
| ASSERT(file); |
| #if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_ |
| return _filelength(_fileno(file)); |
| #else |
| int32_t iPos = FXSYS_ftell(file); |
| FXSYS_fseek(file, 0, FXSYS_SEEK_END); |
| int32_t iLen = FXSYS_ftell(file); |
| FXSYS_fseek(file, iPos, FXSYS_SEEK_SET); |
| return iLen; |
| #endif |
| } |
| |
| bool FileSetSize(FXSYS_FILE* file, int32_t size) { |
| ASSERT(file); |
| #if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_ |
| return _chsize(_fileno(file), size) == 0; |
| #elif _FX_OS_ == _FX_WIN32_MOBILE_ |
| HANDLE hFile = _fileno(file); |
| uint32_t dwPos = ::SetFilePointer(hFile, 0, 0, FILE_CURRENT); |
| ::SetFilePointer(hFile, size, 0, FILE_BEGIN); |
| bool bRet = ::SetEndOfFile(hFile); |
| ::SetFilePointer(hFile, (int32_t)dwPos, 0, FILE_BEGIN); |
| return bRet; |
| #else |
| return false; |
| #endif |
| } |
| |
| } // namespace |
| |
| // static |
| IFX_Stream* IFX_Stream::CreateStream(IFX_SeekableReadStream* pFileRead, |
| uint32_t dwAccess) { |
| CFX_Stream* pSR = new CFX_Stream; |
| if (!pSR->LoadFileRead(pFileRead, dwAccess)) { |
| pSR->Release(); |
| return nullptr; |
| } |
| if (dwAccess & FX_STREAMACCESS_Text) { |
| return new CFX_TextStream(pSR, true); |
| } |
| return pSR; |
| } |
| |
| // static |
| IFX_Stream* IFX_Stream::CreateStream(IFX_SeekableWriteStream* pFileWrite, |
| uint32_t dwAccess) { |
| CFX_Stream* pSR = new CFX_Stream; |
| if (!pSR->LoadFileWrite(pFileWrite, dwAccess)) { |
| pSR->Release(); |
| return nullptr; |
| } |
| if (dwAccess & FX_STREAMACCESS_Text) { |
| return new CFX_TextStream(pSR, true); |
| } |
| return pSR; |
| } |
| |
| // static |
| IFX_Stream* IFX_Stream::CreateStream(uint8_t* pData, |
| int32_t length, |
| uint32_t dwAccess) { |
| CFX_Stream* pSR = new CFX_Stream; |
| if (!pSR->LoadBuffer(pData, length, dwAccess)) { |
| pSR->Release(); |
| return nullptr; |
| } |
| if (dwAccess & FX_STREAMACCESS_Text) { |
| return new CFX_TextStream(pSR, true); |
| } |
| return pSR; |
| } |
| |
| IFX_StreamImp::IFX_StreamImp() : m_dwAccess(0) {} |
| |
| CFX_FileStreamImp::CFX_FileStreamImp() : m_hFile(nullptr), m_iLength(0) {} |
| |
| CFX_FileStreamImp::~CFX_FileStreamImp() { |
| if (m_hFile) |
| FXSYS_fclose(m_hFile); |
| } |
| |
| bool CFX_FileStreamImp::LoadFile(const FX_WCHAR* pszSrcFileName, |
| uint32_t dwAccess) { |
| ASSERT(!m_hFile); |
| ASSERT(pszSrcFileName && FXSYS_wcslen(pszSrcFileName) > 0); |
| #if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN32_MOBILE_ || \ |
| _FX_OS_ == _FX_WIN64_ |
| const FX_WCHAR* wsMode; |
| if (dwAccess & FX_STREAMACCESS_Write) { |
| if (dwAccess & FX_STREAMACCESS_Append) { |
| wsMode = L"a+b"; |
| } else if (dwAccess & FX_STREAMACCESS_Truncate) { |
| wsMode = L"w+b"; |
| } else { |
| wsMode = L"r+b"; |
| } |
| } else { |
| wsMode = L"rb"; |
| } |
| m_hFile = FXSYS_wfopen(pszSrcFileName, wsMode); |
| |
| if (!m_hFile) { |
| if (dwAccess & FX_STREAMACCESS_Write) { |
| if (dwAccess & FX_STREAMACCESS_Create) |
| m_hFile = FXSYS_wfopen(pszSrcFileName, L"w+b"); |
| |
| if (!m_hFile) { |
| m_hFile = FXSYS_wfopen(pszSrcFileName, L"r+b"); |
| if (!m_hFile) |
| return false; |
| |
| if (dwAccess & FX_STREAMACCESS_Truncate) |
| FileSetSize(m_hFile, 0); |
| } |
| } else { |
| return false; |
| } |
| } |
| #else |
| const FX_CHAR* wsMode = "rb"; |
| if (dwAccess & FX_STREAMACCESS_Write) { |
| if (dwAccess & FX_STREAMACCESS_Append) { |
| wsMode = "a+b"; |
| } else if (dwAccess & FX_STREAMACCESS_Truncate) { |
| wsMode = "w+b"; |
| } else { |
| wsMode = "r+b"; |
| } |
| } |
| CFX_ByteString szFileName = CFX_ByteString::FromUnicode(pszSrcFileName); |
| m_hFile = FXSYS_fopen(szFileName.c_str(), wsMode); |
| if (!m_hFile) { |
| if (dwAccess & FX_STREAMACCESS_Write) { |
| if (dwAccess & FX_STREAMACCESS_Create) { |
| m_hFile = FXSYS_fopen(szFileName.c_str(), "w+b"); |
| } |
| if (!m_hFile) { |
| m_hFile = FXSYS_fopen(szFileName.c_str(), "r+b"); |
| if (!m_hFile) { |
| return false; |
| } |
| if (dwAccess & FX_STREAMACCESS_Truncate) { |
| FileSetSize(m_hFile, 0); |
| } |
| } |
| } else { |
| return false; |
| } |
| } |
| #endif |
| SetAccessModes(dwAccess); |
| if ((dwAccess & (FX_STREAMACCESS_Write | FX_STREAMACCESS_Truncate)) == |
| (FX_STREAMACCESS_Write | FX_STREAMACCESS_Truncate)) { |
| m_iLength = 0; |
| } else { |
| m_iLength = FileLength(m_hFile); |
| } |
| return true; |
| } |
| int32_t CFX_FileStreamImp::GetLength() const { |
| ASSERT(m_hFile); |
| return m_iLength; |
| } |
| int32_t CFX_FileStreamImp::Seek(FX_STREAMSEEK eSeek, int32_t iOffset) { |
| ASSERT(m_hFile); |
| FXSYS_fseek(m_hFile, iOffset, eSeek); |
| return FXSYS_ftell(m_hFile); |
| } |
| int32_t CFX_FileStreamImp::GetPosition() { |
| ASSERT(m_hFile); |
| return FXSYS_ftell(m_hFile); |
| } |
| bool CFX_FileStreamImp::IsEOF() const { |
| ASSERT(m_hFile); |
| return FXSYS_ftell(m_hFile) >= m_iLength; |
| } |
| int32_t CFX_FileStreamImp::ReadData(uint8_t* pBuffer, int32_t iBufferSize) { |
| ASSERT(m_hFile); |
| ASSERT(pBuffer && iBufferSize > 0); |
| return FXSYS_fread(pBuffer, 1, iBufferSize, m_hFile); |
| } |
| int32_t CFX_FileStreamImp::ReadString(FX_WCHAR* pStr, |
| int32_t iMaxLength, |
| bool& bEOS) { |
| ASSERT(m_hFile); |
| ASSERT(pStr && iMaxLength > 0); |
| if (m_iLength <= 0) { |
| return 0; |
| } |
| int32_t iPosition = FXSYS_ftell(m_hFile); |
| int32_t iLen = std::min((m_iLength - iPosition) / 2, iMaxLength); |
| if (iLen <= 0) { |
| return 0; |
| } |
| iLen = FXSYS_fread(pStr, 2, iLen, m_hFile); |
| int32_t iCount = 0; |
| while (*pStr != L'\0' && iCount < iLen) { |
| pStr++, iCount++; |
| } |
| iPosition += iCount * 2; |
| if (FXSYS_ftell(m_hFile) != iPosition) { |
| FXSYS_fseek(m_hFile, iPosition, 0); |
| } |
| bEOS = (iPosition >= m_iLength); |
| return iCount; |
| } |
| int32_t CFX_FileStreamImp::WriteData(const uint8_t* pBuffer, |
| int32_t iBufferSize) { |
| ASSERT(m_hFile && (GetAccessModes() & FX_STREAMACCESS_Write) != 0); |
| ASSERT(pBuffer && iBufferSize > 0); |
| int32_t iRet = FXSYS_fwrite(pBuffer, 1, iBufferSize, m_hFile); |
| if (iRet != 0) { |
| int32_t iPos = FXSYS_ftell(m_hFile); |
| if (iPos > m_iLength) { |
| m_iLength = iPos; |
| } |
| } |
| return iRet; |
| } |
| int32_t CFX_FileStreamImp::WriteString(const FX_WCHAR* pStr, int32_t iLength) { |
| ASSERT(m_hFile && (GetAccessModes() & FX_STREAMACCESS_Write) != 0); |
| ASSERT(pStr && iLength > 0); |
| int32_t iRet = FXSYS_fwrite(pStr, 2, iLength, m_hFile); |
| if (iRet != 0) { |
| int32_t iPos = FXSYS_ftell(m_hFile); |
| if (iPos > m_iLength) { |
| m_iLength = iPos; |
| } |
| } |
| return iRet; |
| } |
| void CFX_FileStreamImp::Flush() { |
| ASSERT(m_hFile && (GetAccessModes() & FX_STREAMACCESS_Write) != 0); |
| FXSYS_fflush(m_hFile); |
| } |
| bool CFX_FileStreamImp::SetLength(int32_t iLength) { |
| ASSERT(m_hFile && (GetAccessModes() & FX_STREAMACCESS_Write) != 0); |
| bool bRet = FileSetSize(m_hFile, iLength); |
| m_iLength = FileLength(m_hFile); |
| return bRet; |
| } |
| CFX_FileReadStreamImp::CFX_FileReadStreamImp() |
| : m_pFileRead(nullptr), m_iPosition(0), m_iLength(0) {} |
| bool CFX_FileReadStreamImp::LoadFileRead(IFX_SeekableReadStream* pFileRead, |
| uint32_t dwAccess) { |
| ASSERT(!m_pFileRead && pFileRead); |
| if (dwAccess & FX_STREAMACCESS_Write) { |
| return false; |
| } |
| m_pFileRead = pFileRead; |
| m_iLength = m_pFileRead->GetSize(); |
| return true; |
| } |
| int32_t CFX_FileReadStreamImp::GetLength() const { |
| return m_iLength; |
| } |
| int32_t CFX_FileReadStreamImp::Seek(FX_STREAMSEEK eSeek, int32_t iOffset) { |
| switch (eSeek) { |
| case FX_STREAMSEEK_Begin: |
| m_iPosition = iOffset; |
| break; |
| case FX_STREAMSEEK_Current: |
| m_iPosition += iOffset; |
| break; |
| case FX_STREAMSEEK_End: |
| m_iPosition = m_iLength + iOffset; |
| break; |
| } |
| if (m_iPosition < 0) { |
| m_iPosition = 0; |
| } else if (m_iPosition >= m_iLength) { |
| m_iPosition = m_iLength; |
| } |
| return m_iPosition; |
| } |
| bool CFX_FileReadStreamImp::IsEOF() const { |
| return m_iPosition >= m_iLength; |
| } |
| int32_t CFX_FileReadStreamImp::ReadData(uint8_t* pBuffer, int32_t iBufferSize) { |
| ASSERT(m_pFileRead); |
| ASSERT(pBuffer && iBufferSize > 0); |
| if (iBufferSize > m_iLength - m_iPosition) { |
| iBufferSize = m_iLength - m_iPosition; |
| } |
| if (m_pFileRead->ReadBlock(pBuffer, m_iPosition, iBufferSize)) { |
| m_iPosition += iBufferSize; |
| return iBufferSize; |
| } |
| return 0; |
| } |
| int32_t CFX_FileReadStreamImp::ReadString(FX_WCHAR* pStr, |
| int32_t iMaxLength, |
| bool& bEOS) { |
| ASSERT(m_pFileRead); |
| ASSERT(pStr && iMaxLength > 0); |
| iMaxLength = ReadData((uint8_t*)pStr, iMaxLength * 2) / 2; |
| if (iMaxLength <= 0) { |
| return 0; |
| } |
| int32_t i = 0; |
| while (i < iMaxLength && pStr[i] != L'\0') { |
| ++i; |
| } |
| bEOS = (m_iPosition >= m_iLength) || pStr[i] == L'\0'; |
| return i; |
| } |
| CFX_BufferReadStreamImp::CFX_BufferReadStreamImp() |
| : m_pBufferRead(nullptr), |
| m_bReleaseBufferRead(false), |
| m_iPosition(0), |
| m_iBufferSize(0) {} |
| CFX_BufferReadStreamImp::~CFX_BufferReadStreamImp() { |
| if (m_bReleaseBufferRead && m_pBufferRead) { |
| m_pBufferRead->Release(); |
| } |
| } |
| bool CFX_BufferReadStreamImp::LoadBufferRead(IFX_BufferRead* pBufferRead, |
| int32_t iFileSize, |
| uint32_t dwAccess, |
| bool bReleaseBufferRead) { |
| ASSERT(!m_pBufferRead && pBufferRead); |
| if (dwAccess & FX_STREAMACCESS_Write) { |
| return false; |
| } |
| m_bReleaseBufferRead = bReleaseBufferRead; |
| m_pBufferRead = pBufferRead; |
| m_iBufferSize = iFileSize; |
| if (m_iBufferSize >= 0) { |
| return true; |
| } |
| if (!m_pBufferRead->ReadNextBlock(true)) { |
| return false; |
| } |
| m_iBufferSize = m_pBufferRead->GetBlockSize(); |
| while (!m_pBufferRead->IsEOF()) { |
| m_pBufferRead->ReadNextBlock(false); |
| m_iBufferSize += m_pBufferRead->GetBlockSize(); |
| } |
| return true; |
| } |
| int32_t CFX_BufferReadStreamImp::GetLength() const { |
| return m_iBufferSize; |
| } |
| int32_t CFX_BufferReadStreamImp::Seek(FX_STREAMSEEK eSeek, int32_t iOffset) { |
| int32_t iLength = GetLength(); |
| switch (eSeek) { |
| case FX_STREAMSEEK_Begin: |
| m_iPosition = iOffset; |
| break; |
| case FX_STREAMSEEK_Current: |
| m_iPosition += iOffset; |
| break; |
| case FX_STREAMSEEK_End: |
| m_iPosition = iLength + iOffset; |
| break; |
| } |
| if (m_iPosition < 0) { |
| m_iPosition = 0; |
| } else if (m_iPosition >= iLength) { |
| m_iPosition = iLength; |
| } |
| return m_iPosition; |
| } |
| bool CFX_BufferReadStreamImp::IsEOF() const { |
| return m_pBufferRead ? m_pBufferRead->IsEOF() : true; |
| } |
| int32_t CFX_BufferReadStreamImp::ReadData(uint8_t* pBuffer, |
| int32_t iBufferSize) { |
| ASSERT(m_pBufferRead); |
| ASSERT(pBuffer && iBufferSize > 0); |
| int32_t iLength = GetLength(); |
| if (m_iPosition >= iLength) { |
| return 0; |
| } |
| if (iBufferSize > iLength - m_iPosition) { |
| iBufferSize = iLength - m_iPosition; |
| } |
| uint32_t dwBlockOffset = m_pBufferRead->GetBlockOffset(); |
| uint32_t dwBlockSize = m_pBufferRead->GetBlockSize(); |
| if (m_iPosition < (int32_t)dwBlockOffset) { |
| if (!m_pBufferRead->ReadNextBlock(true)) { |
| return 0; |
| } |
| dwBlockOffset = m_pBufferRead->GetBlockOffset(); |
| dwBlockSize = m_pBufferRead->GetBlockSize(); |
| } |
| while (m_iPosition < (int32_t)dwBlockOffset || |
| m_iPosition >= (int32_t)(dwBlockOffset + dwBlockSize)) { |
| if (m_pBufferRead->IsEOF() || !m_pBufferRead->ReadNextBlock(false)) { |
| break; |
| } |
| dwBlockOffset = m_pBufferRead->GetBlockOffset(); |
| dwBlockSize = m_pBufferRead->GetBlockSize(); |
| } |
| if (m_iPosition < (int32_t)dwBlockOffset || |
| m_iPosition >= (int32_t)(dwBlockOffset + dwBlockSize)) { |
| return 0; |
| } |
| const uint8_t* pBufferTmp = m_pBufferRead->GetBlockBuffer(); |
| uint32_t dwOffsetTmp = m_iPosition - dwBlockOffset; |
| uint32_t dwCopySize = |
| std::min(iBufferSize, (int32_t)(dwBlockSize - dwOffsetTmp)); |
| FXSYS_memcpy(pBuffer, pBufferTmp + dwOffsetTmp, dwCopySize); |
| dwOffsetTmp = dwCopySize; |
| iBufferSize -= dwCopySize; |
| while (iBufferSize > 0) { |
| if (!m_pBufferRead->ReadNextBlock(false)) { |
| break; |
| } |
| dwBlockOffset = m_pBufferRead->GetBlockOffset(); |
| dwBlockSize = m_pBufferRead->GetBlockSize(); |
| pBufferTmp = m_pBufferRead->GetBlockBuffer(); |
| dwCopySize = std::min((uint32_t)iBufferSize, dwBlockSize); |
| FXSYS_memcpy(pBuffer + dwOffsetTmp, pBufferTmp, dwCopySize); |
| dwOffsetTmp += dwCopySize; |
| iBufferSize -= dwCopySize; |
| } |
| m_iPosition += dwOffsetTmp; |
| return dwOffsetTmp; |
| } |
| int32_t CFX_BufferReadStreamImp::ReadString(FX_WCHAR* pStr, |
| int32_t iMaxLength, |
| bool& bEOS) { |
| ASSERT(m_pBufferRead); |
| ASSERT(pStr && iMaxLength > 0); |
| iMaxLength = ReadData((uint8_t*)pStr, iMaxLength * 2) / 2; |
| if (iMaxLength <= 0) { |
| return 0; |
| } |
| int32_t i = 0; |
| while (i < iMaxLength && pStr[i] != L'\0') { |
| ++i; |
| } |
| bEOS = (m_iPosition >= GetLength()) || pStr[i] == L'\0'; |
| return i; |
| } |
| CFX_FileWriteStreamImp::CFX_FileWriteStreamImp() |
| : m_pFileWrite(nullptr), m_iPosition(0) {} |
| bool CFX_FileWriteStreamImp::LoadFileWrite(IFX_SeekableWriteStream* pFileWrite, |
| uint32_t dwAccess) { |
| ASSERT(!m_pFileWrite && pFileWrite); |
| if (dwAccess & FX_STREAMACCESS_Read) { |
| return false; |
| } |
| if (dwAccess & FX_STREAMACCESS_Append) { |
| m_iPosition = pFileWrite->GetSize(); |
| } |
| m_pFileWrite = pFileWrite; |
| return true; |
| } |
| int32_t CFX_FileWriteStreamImp::GetLength() const { |
| if (!m_pFileWrite) { |
| return 0; |
| } |
| return (int32_t)m_pFileWrite->GetSize(); |
| } |
| int32_t CFX_FileWriteStreamImp::Seek(FX_STREAMSEEK eSeek, int32_t iOffset) { |
| int32_t iLength = GetLength(); |
| switch (eSeek) { |
| case FX_STREAMSEEK_Begin: |
| m_iPosition = iOffset; |
| break; |
| case FX_STREAMSEEK_Current: |
| m_iPosition += iOffset; |
| break; |
| case FX_STREAMSEEK_End: |
| m_iPosition = iLength + iOffset; |
| break; |
| } |
| if (m_iPosition < 0) { |
| m_iPosition = 0; |
| } else if (m_iPosition >= iLength) { |
| m_iPosition = iLength; |
| } |
| return m_iPosition; |
| } |
| bool CFX_FileWriteStreamImp::IsEOF() const { |
| return m_iPosition >= GetLength(); |
| } |
| int32_t CFX_FileWriteStreamImp::WriteData(const uint8_t* pBuffer, |
| int32_t iBufferSize) { |
| if (!m_pFileWrite) { |
| return 0; |
| } |
| if (m_pFileWrite->WriteBlock(pBuffer, m_iPosition, iBufferSize)) { |
| m_iPosition += iBufferSize; |
| } |
| return iBufferSize; |
| } |
| int32_t CFX_FileWriteStreamImp::WriteString(const FX_WCHAR* pStr, |
| int32_t iLength) { |
| return WriteData((const uint8_t*)pStr, iLength * sizeof(FX_WCHAR)); |
| } |
| void CFX_FileWriteStreamImp::Flush() { |
| if (m_pFileWrite) { |
| m_pFileWrite->Flush(); |
| } |
| } |
| CFX_BufferStreamImp::CFX_BufferStreamImp() |
| : m_pData(nullptr), m_iTotalSize(0), m_iPosition(0), m_iLength(0) {} |
| |
| bool CFX_BufferStreamImp::LoadBuffer(uint8_t* pData, |
| int32_t iTotalSize, |
| uint32_t dwAccess) { |
| ASSERT(!m_pData && pData && iTotalSize > 0); |
| SetAccessModes(dwAccess); |
| m_pData = pData; |
| m_iTotalSize = iTotalSize; |
| m_iPosition = 0; |
| m_iLength = (dwAccess & FX_STREAMACCESS_Write) != 0 ? 0 : iTotalSize; |
| return true; |
| } |
| int32_t CFX_BufferStreamImp::GetLength() const { |
| ASSERT(m_pData); |
| return m_iLength; |
| } |
| int32_t CFX_BufferStreamImp::Seek(FX_STREAMSEEK eSeek, int32_t iOffset) { |
| ASSERT(m_pData); |
| if (eSeek == FX_STREAMSEEK_Begin) { |
| m_iPosition = iOffset; |
| } else if (eSeek == FX_STREAMSEEK_Current) { |
| m_iPosition += iOffset; |
| } else if (eSeek == FX_STREAMSEEK_End) { |
| m_iPosition = m_iLength + iOffset; |
| } |
| if (m_iPosition > m_iLength) { |
| m_iPosition = m_iLength; |
| } |
| if (m_iPosition < 0) { |
| m_iPosition = 0; |
| } |
| return m_iPosition; |
| } |
| int32_t CFX_BufferStreamImp::GetPosition() { |
| ASSERT(m_pData); |
| return m_iPosition; |
| } |
| bool CFX_BufferStreamImp::IsEOF() const { |
| ASSERT(m_pData); |
| return m_iPosition >= m_iLength; |
| } |
| int32_t CFX_BufferStreamImp::ReadData(uint8_t* pBuffer, int32_t iBufferSize) { |
| ASSERT(m_pData); |
| ASSERT(pBuffer && iBufferSize > 0); |
| int32_t iLen = std::min(m_iLength - m_iPosition, iBufferSize); |
| if (iLen <= 0) { |
| return 0; |
| } |
| FXSYS_memcpy(pBuffer, m_pData + m_iPosition, iLen); |
| m_iPosition += iLen; |
| return iLen; |
| } |
| int32_t CFX_BufferStreamImp::ReadString(FX_WCHAR* pStr, |
| int32_t iMaxLength, |
| bool& bEOS) { |
| ASSERT(m_pData); |
| ASSERT(pStr && iMaxLength > 0); |
| int32_t iLen = std::min((m_iLength - m_iPosition) / 2, iMaxLength); |
| if (iLen <= 0) { |
| return 0; |
| } |
| const FX_WCHAR* pSrc = (const FX_WCHAR*)(FX_CHAR*)(m_pData + m_iPosition); |
| int32_t iCount = 0; |
| while (*pSrc && iCount < iLen) { |
| *pStr++ = *pSrc++; |
| iCount++; |
| } |
| m_iPosition += iCount * 2; |
| bEOS = (*pSrc == L'\0') || (m_iPosition >= m_iLength); |
| return iCount; |
| } |
| int32_t CFX_BufferStreamImp::WriteData(const uint8_t* pBuffer, |
| int32_t iBufferSize) { |
| ASSERT(m_pData && (GetAccessModes() & FX_STREAMACCESS_Write) != 0); |
| ASSERT(pBuffer && iBufferSize > 0); |
| int32_t iLen = std::min(m_iTotalSize - m_iPosition, iBufferSize); |
| if (iLen <= 0) { |
| return 0; |
| } |
| FXSYS_memcpy(m_pData + m_iPosition, pBuffer, iLen); |
| m_iPosition += iLen; |
| if (m_iPosition > m_iLength) { |
| m_iLength = m_iPosition; |
| } |
| return iLen; |
| } |
| int32_t CFX_BufferStreamImp::WriteString(const FX_WCHAR* pStr, |
| int32_t iLength) { |
| ASSERT(m_pData && (GetAccessModes() & FX_STREAMACCESS_Write) != 0); |
| ASSERT(pStr && iLength > 0); |
| int32_t iLen = std::min((m_iTotalSize - m_iPosition) / 2, iLength); |
| if (iLen <= 0) { |
| return 0; |
| } |
| FXSYS_memcpy(m_pData + m_iPosition, pStr, iLen * 2); |
| m_iPosition += iLen * 2; |
| if (m_iPosition > m_iLength) { |
| m_iLength = m_iPosition; |
| } |
| return iLen; |
| } |
| |
| // static |
| IFX_Stream* IFX_Stream::CreateTextStream(IFX_Stream* pBaseStream, |
| bool bDeleteOnRelease) { |
| ASSERT(pBaseStream); |
| return new CFX_TextStream(pBaseStream, bDeleteOnRelease); |
| } |
| |
| CFX_TextStream::CFX_TextStream(IFX_Stream* pStream, bool bDelStream) |
| : m_wCodePage(FX_CODEPAGE_DefANSI), |
| m_wBOMLength(0), |
| m_dwBOM(0), |
| m_pBuf(nullptr), |
| m_iBufSize(0), |
| m_bDelStream(bDelStream), |
| m_pStreamImp(pStream), |
| m_iRefCount(1) { |
| ASSERT(m_pStreamImp); |
| m_pStreamImp->Retain(); |
| InitStream(); |
| } |
| CFX_TextStream::~CFX_TextStream() { |
| m_pStreamImp->Release(); |
| if (m_bDelStream) { |
| m_pStreamImp->Release(); |
| } |
| if (m_pBuf) { |
| FX_Free(m_pBuf); |
| } |
| } |
| void CFX_TextStream::InitStream() { |
| int32_t iPosition = m_pStreamImp->GetPosition(); |
| m_pStreamImp->Seek(FX_STREAMSEEK_Begin, 0); |
| m_pStreamImp->ReadData((uint8_t*)&m_dwBOM, 3); |
| #if _FX_ENDIAN_ == _FX_LITTLE_ENDIAN_ |
| m_dwBOM &= 0x00FFFFFF; |
| if (m_dwBOM == 0x00BFBBEF) { |
| m_wBOMLength = 3; |
| m_wCodePage = FX_CODEPAGE_UTF8; |
| } else { |
| m_dwBOM &= 0x0000FFFF; |
| if (m_dwBOM == 0x0000FFFE) { |
| m_wBOMLength = 2; |
| m_wCodePage = FX_CODEPAGE_UTF16BE; |
| } else if (m_dwBOM == 0x0000FEFF) { |
| m_wBOMLength = 2; |
| m_wCodePage = FX_CODEPAGE_UTF16LE; |
| } else { |
| m_wBOMLength = 0; |
| m_dwBOM = 0; |
| m_wCodePage = FXSYS_GetACP(); |
| } |
| } |
| #else |
| m_dwBOM &= 0xFFFFFF00; |
| if (m_dwBOM == 0xEFBBBF00) { |
| m_wBOMLength = 3; |
| m_wCodePage = FX_CODEPAGE_UTF8; |
| } else { |
| m_dwBOM &= 0xFFFF0000; |
| if (m_dwBOM == 0xFEFF0000) { |
| m_wBOMLength = 2; |
| m_wCodePage = FX_CODEPAGE_UTF16BE; |
| } else if (m_dwBOM == 0xFFFE0000) { |
| m_wBOMLength = 2; |
| m_wCodePage = FX_CODEPAGE_UTF16LE; |
| } else { |
| m_wBOMLength = 0; |
| m_dwBOM = 0; |
| m_wCodePage = FXSYS_GetACP(); |
| } |
| } |
| #endif |
| m_pStreamImp->Seek(FX_STREAMSEEK_Begin, std::max(m_wBOMLength, iPosition)); |
| } |
| void CFX_TextStream::Release() { |
| if (--m_iRefCount < 1) { |
| delete this; |
| } |
| } |
| IFX_Stream* CFX_TextStream::Retain() { |
| m_iRefCount++; |
| return this; |
| } |
| uint32_t CFX_TextStream::GetAccessModes() const { |
| return m_pStreamImp->GetAccessModes() | FX_STREAMACCESS_Text; |
| } |
| int32_t CFX_TextStream::GetLength() const { |
| return m_pStreamImp->GetLength(); |
| } |
| int32_t CFX_TextStream::Seek(FX_STREAMSEEK eSeek, int32_t iOffset) { |
| return m_pStreamImp->Seek(eSeek, iOffset); |
| } |
| int32_t CFX_TextStream::GetPosition() { |
| return m_pStreamImp->GetPosition(); |
| } |
| bool CFX_TextStream::IsEOF() const { |
| return m_pStreamImp->IsEOF(); |
| } |
| int32_t CFX_TextStream::ReadData(uint8_t* pBuffer, int32_t iBufferSize) { |
| return m_pStreamImp->ReadData(pBuffer, iBufferSize); |
| } |
| int32_t CFX_TextStream::WriteData(const uint8_t* pBuffer, int32_t iBufferSize) { |
| return m_pStreamImp->WriteData(pBuffer, iBufferSize); |
| } |
| void CFX_TextStream::Flush() { |
| m_pStreamImp->Flush(); |
| } |
| bool CFX_TextStream::SetLength(int32_t iLength) { |
| return m_pStreamImp->SetLength(iLength); |
| } |
| uint16_t CFX_TextStream::GetCodePage() const { |
| return m_wCodePage; |
| } |
| IFX_Stream* CFX_TextStream::CreateSharedStream(uint32_t dwAccess, |
| int32_t iOffset, |
| int32_t iLength) { |
| IFX_Stream* pSR = |
| m_pStreamImp->CreateSharedStream(dwAccess, iOffset, iLength); |
| if (!pSR) { |
| return nullptr; |
| } |
| if (dwAccess & FX_STREAMACCESS_Text) { |
| return new CFX_TextStream(pSR, true); |
| } |
| return pSR; |
| } |
| int32_t CFX_TextStream::GetBOM(uint8_t bom[4]) const { |
| if (m_wBOMLength < 1) { |
| return 0; |
| } |
| *(uint32_t*)bom = m_dwBOM; |
| return m_wBOMLength; |
| } |
| uint16_t CFX_TextStream::SetCodePage(uint16_t wCodePage) { |
| if (m_wBOMLength > 0) { |
| return m_wCodePage; |
| } |
| uint16_t v = m_wCodePage; |
| m_wCodePage = wCodePage; |
| return v; |
| } |
| int32_t CFX_TextStream::ReadString(FX_WCHAR* pStr, |
| int32_t iMaxLength, |
| bool& bEOS) { |
| ASSERT(pStr && iMaxLength > 0); |
| if (!m_pStreamImp) { |
| return -1; |
| } |
| int32_t iLen; |
| if (m_wCodePage == FX_CODEPAGE_UTF16LE || |
| m_wCodePage == FX_CODEPAGE_UTF16BE) { |
| int32_t iBytes = iMaxLength * 2; |
| iLen = m_pStreamImp->ReadData((uint8_t*)pStr, iBytes); |
| iMaxLength = iLen / 2; |
| if (sizeof(FX_WCHAR) > 2) { |
| FX_UTF16ToWChar(pStr, iMaxLength); |
| } |
| #if _FX_ENDIAN_ == _FX_BIG_ENDIAN_ |
| if (m_wCodePage == FX_CODEPAGE_UTF16LE) { |
| FX_SwapByteOrder(pStr, iMaxLength); |
| } |
| #else |
| if (m_wCodePage == FX_CODEPAGE_UTF16BE) { |
| FX_SwapByteOrder(pStr, iMaxLength); |
| } |
| #endif |
| } else { |
| int32_t pos = m_pStreamImp->GetPosition(); |
| int32_t iBytes = iMaxLength; |
| iBytes = std::min(iBytes, m_pStreamImp->GetLength() - pos); |
| if (iBytes > 0) { |
| if (!m_pBuf) { |
| m_pBuf = FX_Alloc(uint8_t, iBytes); |
| m_iBufSize = iBytes; |
| } else if (iBytes > m_iBufSize) { |
| m_pBuf = FX_Realloc(uint8_t, m_pBuf, iBytes); |
| m_iBufSize = iBytes; |
| } |
| iLen = m_pStreamImp->ReadData(m_pBuf, iBytes); |
| int32_t iSrc = iLen; |
| int32_t iDecode = FX_DecodeString(m_wCodePage, (const FX_CHAR*)m_pBuf, |
| &iSrc, pStr, &iMaxLength, true); |
| m_pStreamImp->Seek(FX_STREAMSEEK_Current, iSrc - iLen); |
| if (iDecode < 1) { |
| return -1; |
| } |
| } else { |
| iMaxLength = 0; |
| } |
| } |
| bEOS = m_pStreamImp->IsEOF(); |
| return iMaxLength; |
| } |
| int32_t CFX_TextStream::WriteString(const FX_WCHAR* pStr, int32_t iLength) { |
| ASSERT(pStr && iLength > 0); |
| if ((m_pStreamImp->GetAccessModes() & FX_STREAMACCESS_Write) == 0) { |
| return -1; |
| } |
| if (m_wCodePage == FX_CODEPAGE_UTF8) { |
| int32_t len = iLength; |
| CFX_UTF8Encoder encoder; |
| while (len-- > 0) { |
| encoder.Input(*pStr++); |
| } |
| CFX_ByteStringC bsResult = encoder.GetResult(); |
| m_pStreamImp->WriteData((const uint8_t*)bsResult.c_str(), |
| bsResult.GetLength()); |
| } |
| return iLength; |
| } |
| CFX_Stream::CFX_Stream() |
| : m_eStreamType(FX_SREAMTYPE_Unknown), |
| m_pStreamImp(nullptr), |
| m_dwAccess(0), |
| m_iTotalSize(0), |
| m_iPosition(0), |
| m_iStart(0), |
| m_iLength(0), |
| m_iRefCount(1) {} |
| |
| CFX_Stream::~CFX_Stream() { |
| if (m_eStreamType != FX_STREAMTYPE_Stream) |
| delete m_pStreamImp; |
| } |
| |
| bool CFX_Stream::LoadFile(const FX_WCHAR* pszSrcFileName, uint32_t dwAccess) { |
| if (m_eStreamType != FX_SREAMTYPE_Unknown || m_pStreamImp) |
| return false; |
| |
| if (!pszSrcFileName || FXSYS_wcslen(pszSrcFileName) < 1) |
| return false; |
| |
| std::unique_ptr<CFX_FileStreamImp> pImp(new CFX_FileStreamImp()); |
| if (!pImp->LoadFile(pszSrcFileName, dwAccess)) |
| return false; |
| |
| m_pStreamImp = pImp.release(); |
| m_eStreamType = FX_STREAMTYPE_File; |
| m_dwAccess = dwAccess; |
| m_iLength = m_pStreamImp->GetLength(); |
| return true; |
| } |
| |
| bool CFX_Stream::LoadFileRead(IFX_SeekableReadStream* pFileRead, |
| uint32_t dwAccess) { |
| if (m_eStreamType != FX_SREAMTYPE_Unknown || m_pStreamImp) |
| return false; |
| |
| if (!pFileRead) |
| return false; |
| |
| std::unique_ptr<CFX_FileReadStreamImp> pImp(new CFX_FileReadStreamImp()); |
| if (!pImp->LoadFileRead(pFileRead, dwAccess)) |
| return false; |
| |
| m_pStreamImp = pImp.release(); |
| m_eStreamType = FX_STREAMTYPE_File; |
| m_dwAccess = dwAccess; |
| m_iLength = m_pStreamImp->GetLength(); |
| return true; |
| } |
| |
| bool CFX_Stream::LoadFileWrite(IFX_SeekableWriteStream* pFileWrite, |
| uint32_t dwAccess) { |
| if (m_eStreamType != FX_SREAMTYPE_Unknown || m_pStreamImp) |
| return false; |
| |
| if (!pFileWrite) |
| return false; |
| |
| std::unique_ptr<CFX_FileWriteStreamImp> pImp(new CFX_FileWriteStreamImp()); |
| if (!pImp->LoadFileWrite(pFileWrite, dwAccess)) |
| return false; |
| |
| m_pStreamImp = pImp.release(); |
| m_eStreamType = FX_STREAMTYPE_File; |
| m_dwAccess = dwAccess; |
| m_iLength = m_pStreamImp->GetLength(); |
| return true; |
| } |
| |
| bool CFX_Stream::LoadBuffer(uint8_t* pData, |
| int32_t iTotalSize, |
| uint32_t dwAccess) { |
| if (m_eStreamType != FX_SREAMTYPE_Unknown || m_pStreamImp) |
| return false; |
| |
| if (!pData || iTotalSize < 1) |
| return false; |
| |
| std::unique_ptr<CFX_BufferStreamImp> pImp(new CFX_BufferStreamImp()); |
| if (!pImp->LoadBuffer(pData, iTotalSize, dwAccess)) |
| return false; |
| |
| m_pStreamImp = pImp.release(); |
| m_eStreamType = FX_STREAMTYPE_Buffer; |
| m_dwAccess = dwAccess; |
| m_iLength = m_pStreamImp->GetLength(); |
| return true; |
| } |
| |
| bool CFX_Stream::LoadBufferRead(IFX_BufferRead* pBufferRead, |
| int32_t iFileSize, |
| uint32_t dwAccess, |
| bool bReleaseBufferRead) { |
| if (m_eStreamType != FX_SREAMTYPE_Unknown || m_pStreamImp) |
| return false; |
| |
| if (!pBufferRead) |
| return false; |
| |
| std::unique_ptr<CFX_BufferReadStreamImp> pImp(new CFX_BufferReadStreamImp); |
| if (!pImp->LoadBufferRead(pBufferRead, iFileSize, dwAccess, |
| bReleaseBufferRead)) |
| return false; |
| |
| m_pStreamImp = pImp.release(); |
| m_eStreamType = FX_STREAMTYPE_BufferRead; |
| m_dwAccess = dwAccess; |
| m_iLength = m_pStreamImp->GetLength(); |
| return true; |
| } |
| |
| void CFX_Stream::Release() { |
| if (--m_iRefCount < 1) { |
| delete this; |
| } |
| } |
| IFX_Stream* CFX_Stream::Retain() { |
| m_iRefCount++; |
| return this; |
| } |
| |
| uint32_t CFX_Stream::GetAccessModes() const { |
| return m_dwAccess; |
| } |
| |
| int32_t CFX_Stream::GetLength() const { |
| if (!m_pStreamImp) { |
| return -1; |
| } |
| if (m_eStreamType == FX_STREAMTYPE_File || |
| m_eStreamType == FX_STREAMTYPE_Buffer) { |
| return m_pStreamImp->GetLength(); |
| } |
| return m_iLength; |
| } |
| int32_t CFX_Stream::Seek(FX_STREAMSEEK eSeek, int32_t iOffset) { |
| if (!m_pStreamImp) { |
| return -1; |
| } |
| if (m_eStreamType == FX_STREAMTYPE_File || |
| m_eStreamType == FX_STREAMTYPE_Buffer) { |
| return m_iPosition = m_pStreamImp->Seek(eSeek, iOffset); |
| } |
| int32_t iEnd = m_iStart + m_iLength; |
| int32_t iPosition = m_iStart + iOffset; |
| if (eSeek == FX_STREAMSEEK_Begin) { |
| m_iPosition = iPosition; |
| } else if (eSeek == FX_STREAMSEEK_Current) { |
| m_iPosition += iOffset; |
| } else if (eSeek == FX_STREAMSEEK_End) { |
| m_iPosition = iEnd + iOffset; |
| } |
| if (m_iPosition > iEnd) { |
| m_iPosition = iEnd; |
| } |
| if (m_iPosition < m_iStart) { |
| m_iPosition = m_iStart; |
| } |
| return m_iPosition - m_iStart; |
| } |
| int32_t CFX_Stream::GetPosition() { |
| if (!m_pStreamImp) { |
| return -1; |
| } |
| if (m_eStreamType == FX_STREAMTYPE_File || |
| m_eStreamType == FX_STREAMTYPE_Buffer) { |
| return m_iPosition = m_pStreamImp->GetPosition(); |
| } |
| return m_iPosition - m_iStart; |
| } |
| bool CFX_Stream::IsEOF() const { |
| if (!m_pStreamImp) { |
| return true; |
| } |
| if (m_eStreamType == FX_STREAMTYPE_File || |
| m_eStreamType == FX_STREAMTYPE_Buffer) { |
| return m_pStreamImp->IsEOF(); |
| } |
| return m_iPosition >= m_iStart + m_iLength; |
| } |
| int32_t CFX_Stream::ReadData(uint8_t* pBuffer, int32_t iBufferSize) { |
| ASSERT(pBuffer && iBufferSize > 0); |
| if (!m_pStreamImp) { |
| return -1; |
| } |
| int32_t iLen = std::min(m_iStart + m_iLength - m_iPosition, iBufferSize); |
| if (iLen <= 0) { |
| return 0; |
| } |
| if (m_pStreamImp->GetPosition() != m_iPosition) { |
| m_pStreamImp->Seek(FX_STREAMSEEK_Begin, m_iPosition); |
| } |
| iLen = m_pStreamImp->ReadData(pBuffer, iLen); |
| m_iPosition = m_pStreamImp->GetPosition(); |
| return iLen; |
| } |
| int32_t CFX_Stream::ReadString(FX_WCHAR* pStr, int32_t iMaxLength, bool& bEOS) { |
| ASSERT(pStr && iMaxLength > 0); |
| if (!m_pStreamImp) { |
| return -1; |
| } |
| int32_t iEnd = m_iStart + m_iLength; |
| int32_t iLen = iEnd - m_iPosition; |
| iLen = std::min(iEnd / 2, iMaxLength); |
| if (iLen <= 0) { |
| return 0; |
| } |
| if (m_pStreamImp->GetPosition() != m_iPosition) { |
| m_pStreamImp->Seek(FX_STREAMSEEK_Begin, m_iPosition); |
| } |
| iLen = m_pStreamImp->ReadString(pStr, iLen, bEOS); |
| m_iPosition = m_pStreamImp->GetPosition(); |
| if (iLen > 0 && m_iPosition >= iEnd) { |
| bEOS = true; |
| } |
| return iLen; |
| } |
| |
| int32_t CFX_Stream::WriteData(const uint8_t* pBuffer, int32_t iBufferSize) { |
| ASSERT(pBuffer && iBufferSize > 0); |
| if (!m_pStreamImp) { |
| return -1; |
| } |
| if ((m_dwAccess & FX_STREAMACCESS_Write) == 0) { |
| return -1; |
| } |
| int32_t iLen = iBufferSize; |
| if (m_eStreamType == FX_STREAMTYPE_Stream) { |
| iLen = std::min(m_iStart + m_iTotalSize - m_iPosition, iBufferSize); |
| if (iLen <= 0) { |
| return 0; |
| } |
| } |
| int32_t iEnd = m_iStart + m_iLength; |
| if (m_pStreamImp->GetPosition() != m_iPosition) { |
| m_pStreamImp->Seek(FX_STREAMSEEK_Begin, m_iPosition); |
| } |
| iLen = m_pStreamImp->WriteData(pBuffer, iLen); |
| m_iPosition = m_pStreamImp->GetPosition(); |
| if (m_iPosition > iEnd) { |
| m_iLength = m_iPosition - m_iStart; |
| } |
| return iLen; |
| } |
| int32_t CFX_Stream::WriteString(const FX_WCHAR* pStr, int32_t iLength) { |
| ASSERT(pStr && iLength > 0); |
| if (!m_pStreamImp) { |
| return -1; |
| } |
| if ((m_dwAccess & FX_STREAMACCESS_Write) == 0) { |
| return -1; |
| } |
| int32_t iLen = iLength; |
| if (m_eStreamType == FX_STREAMTYPE_Stream) { |
| iLen = std::min((m_iStart + m_iTotalSize - m_iPosition) / 2, iLength); |
| if (iLen <= 0) { |
| return 0; |
| } |
| } |
| int32_t iEnd = m_iStart + m_iLength; |
| if (m_pStreamImp->GetPosition() != m_iPosition) { |
| m_pStreamImp->Seek(FX_STREAMSEEK_Begin, m_iPosition); |
| } |
| iLen = m_pStreamImp->WriteString(pStr, iLen); |
| m_iPosition = m_pStreamImp->GetPosition(); |
| if (m_iPosition > iEnd) { |
| m_iLength = m_iPosition - m_iStart; |
| } |
| return iLen; |
| } |
| void CFX_Stream::Flush() { |
| if (!m_pStreamImp) { |
| return; |
| } |
| if ((m_dwAccess & FX_STREAMACCESS_Write) == 0) { |
| return; |
| } |
| m_pStreamImp->Flush(); |
| } |
| bool CFX_Stream::SetLength(int32_t iLength) { |
| if (!m_pStreamImp) { |
| return false; |
| } |
| if ((m_dwAccess & FX_STREAMACCESS_Write) == 0) { |
| return false; |
| } |
| return m_pStreamImp->SetLength(iLength); |
| } |
| int32_t CFX_Stream::GetBOM(uint8_t bom[4]) const { |
| if (!m_pStreamImp) { |
| return -1; |
| } |
| return 0; |
| } |
| uint16_t CFX_Stream::GetCodePage() const { |
| #if _FX_ENDIAN_ == _FX_LITTLE_ENDIAN_ |
| return FX_CODEPAGE_UTF16LE; |
| #else |
| return FX_CODEPAGE_UTF16BE; |
| #endif |
| } |
| uint16_t CFX_Stream::SetCodePage(uint16_t wCodePage) { |
| #if _FX_ENDIAN_ == _FX_LITTLE_ENDIAN_ |
| return FX_CODEPAGE_UTF16LE; |
| #else |
| return FX_CODEPAGE_UTF16BE; |
| #endif |
| } |
| IFX_Stream* CFX_Stream::CreateSharedStream(uint32_t dwAccess, |
| int32_t iOffset, |
| int32_t iLength) { |
| ASSERT(iLength > 0); |
| if (!m_pStreamImp) { |
| return nullptr; |
| } |
| if ((m_dwAccess & FX_STREAMACCESS_Text) != 0 && |
| (dwAccess & FX_STREAMACCESS_Text) == 0) { |
| return nullptr; |
| } |
| if ((m_dwAccess & FX_STREAMACCESS_Write) == 0 && |
| (dwAccess & FX_STREAMACCESS_Write) != 0) { |
| return nullptr; |
| } |
| int32_t iStart = m_iStart + iOffset; |
| int32_t iTotal = m_iStart + m_iLength; |
| if (iStart < m_iStart || iStart >= iTotal) { |
| return nullptr; |
| } |
| int32_t iEnd = iStart + iLength; |
| if (iEnd < iStart || iEnd > iTotal) { |
| return nullptr; |
| } |
| CFX_Stream* pShared = new CFX_Stream; |
| pShared->m_eStreamType = FX_STREAMTYPE_Stream; |
| pShared->m_pStreamImp = m_pStreamImp; |
| pShared->m_dwAccess = dwAccess; |
| pShared->m_iTotalSize = iLength; |
| pShared->m_iPosition = iStart; |
| pShared->m_iStart = iStart; |
| pShared->m_iLength = (dwAccess & FX_STREAMACCESS_Write) != 0 ? 0 : iLength; |
| if (dwAccess & FX_STREAMACCESS_Text) { |
| return IFX_Stream::CreateTextStream(pShared, true); |
| } |
| return pShared; |
| } |
| |
| IFX_SeekableReadStream* FX_CreateFileRead(IFX_Stream* pBaseStream, |
| bool bReleaseStream) { |
| ASSERT(pBaseStream); |
| return new CFGAS_FileRead(pBaseStream, bReleaseStream); |
| } |
| |
| CFGAS_FileRead::CFGAS_FileRead(IFX_Stream* pStream, bool bReleaseStream) |
| : m_bReleaseStream(bReleaseStream), m_pStream(pStream) { |
| ASSERT(m_pStream); |
| } |
| CFGAS_FileRead::~CFGAS_FileRead() { |
| if (m_bReleaseStream) { |
| m_pStream->Release(); |
| } |
| } |
| FX_FILESIZE CFGAS_FileRead::GetSize() { |
| return (FX_FILESIZE)m_pStream->GetLength(); |
| } |
| |
| bool CFGAS_FileRead::ReadBlock(void* buffer, FX_FILESIZE offset, size_t size) { |
| m_pStream->Seek(FX_STREAMSEEK_Begin, (int32_t)offset); |
| int32_t iLen = m_pStream->ReadData((uint8_t*)buffer, (int32_t)size); |
| return iLen == (int32_t)size; |
| } |
| |
| void CFGAS_FileRead::Release() { |
| delete this; |
| } |