// 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 <utility> #include "core/fxcrt/extension.h" #include "core/fxcrt/include/fx_basic.h" #include "core/fxcrt/include/fx_ext.h" #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ #include <wincrypt.h> #else #include <ctime> #endif #ifdef PDF_ENABLE_XFA CFX_CRTFileAccess::CFX_CRTFileAccess() : m_RefCount(0) {} CFX_CRTFileAccess::~CFX_CRTFileAccess() {} void CFX_CRTFileAccess::Release() { if (--m_RefCount == 0) delete this; } IFX_FileAccess* CFX_CRTFileAccess::Retain() { m_RefCount++; return (IFX_FileAccess*)this; } void CFX_CRTFileAccess::GetPath(CFX_WideString& wsPath) { wsPath = m_path; } IFX_FileStream* CFX_CRTFileAccess::CreateFileStream(uint32_t dwModes) { return FX_CreateFileStream(m_path.c_str(), dwModes); } FX_BOOL CFX_CRTFileAccess::Init(const CFX_WideStringC& wsPath) { m_path = wsPath; m_RefCount = 1; return TRUE; } #endif // PDF_ENABLE_XFA CFX_CRTFileStream::CFX_CRTFileStream(std::unique_ptr<IFXCRT_FileAccess> pFA) : m_pFile(std::move(pFA)), m_dwCount(1) {} CFX_CRTFileStream::~CFX_CRTFileStream() {} CFX_MemoryStream::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::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::~CFX_MemoryStream() { if (m_dwFlags & FX_MEMSTREAM_TakeOver) { for (int32_t i = 0; i < m_Blocks.GetSize(); i++) { FX_Free(m_Blocks[i]); } } m_Blocks.RemoveAll(); } IFX_FileStream* CFX_MemoryStream::Retain() { m_dwCount++; return this; } void CFX_MemoryStream::Release() { uint32_t nCount = --m_dwCount; if (nCount) { return; } delete this; } FX_FILESIZE CFX_MemoryStream::GetSize() { return (FX_FILESIZE)m_nCurSize; } FX_BOOL CFX_MemoryStream::IsEOF() { return m_nCurPos >= (size_t)GetSize(); } FX_FILESIZE CFX_MemoryStream::GetPosition() { return (FX_FILESIZE)m_nCurPos; } FX_BOOL CFX_MemoryStream::ReadBlock(void* buffer, FX_FILESIZE offset, size_t size) { 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, 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, m_Blocks[(int)nStartBlock] + (size_t)offset, nRead); buffer = ((uint8_t*)buffer) + nRead; size -= nRead; nStartBlock++; offset = 0; } return TRUE; } size_t CFX_MemoryStream::ReadBlock(void* buffer, size_t size) { if (m_nCurPos >= m_nCurSize) { return 0; } size_t nRead = std::min(size, m_nCurSize - m_nCurPos); if (!ReadBlock(buffer, (int32_t)m_nCurPos, nRead)) { return 0; } return nRead; } FX_BOOL CFX_MemoryStream::WriteBlock(const void* buffer, FX_FILESIZE offset, size_t size) { 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) { uint8_t* 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(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(m_Blocks[(int)nStartBlock] + (size_t)offset, buffer, nWrite); buffer = ((uint8_t*)buffer) + nWrite; size -= nWrite; nStartBlock++; offset = 0; } return TRUE; } FX_BOOL CFX_MemoryStream::Flush() { return TRUE; } FX_BOOL CFX_MemoryStream::IsConsecutive() const { return !!(m_dwFlags & FX_MEMSTREAM_Consecutive); } void CFX_MemoryStream::EstimateSize(size_t nInitSize, size_t nGrowSize) { if (m_dwFlags & FX_MEMSTREAM_Consecutive) { if (m_Blocks.GetSize() < 1) { uint8_t* pBlock = FX_Alloc(uint8_t, std::max(nInitSize, static_cast<size_t>(4096))); m_Blocks.Add(pBlock); } m_nGrowSize = std::max(nGrowSize, static_cast<size_t>(4096)); } else if (m_Blocks.GetSize() < 1) { m_nGrowSize = std::max(nGrowSize, static_cast<size_t>(4096)); } } uint8_t* CFX_MemoryStream::GetBuffer() const { return m_Blocks.GetSize() ? m_Blocks[0] : nullptr; } void CFX_MemoryStream::AttachBuffer(uint8_t* pBuffer, size_t nSize, FX_BOOL bTakeOver) { 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); } void CFX_MemoryStream::DetachBuffer() { if (!(m_dwFlags & FX_MEMSTREAM_Consecutive)) { return; } m_Blocks.RemoveAll(); m_nTotalSize = m_nCurSize = m_nCurPos = 0; m_dwFlags = FX_MEMSTREAM_TakeOver; } FX_BOOL CFX_MemoryStream::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; } IFX_FileStream* CFX_CRTFileStream::Retain() { m_dwCount++; return this; } void CFX_CRTFileStream::Release() { uint32_t nCount = --m_dwCount; if (!nCount) { delete this; } } FX_FILESIZE CFX_CRTFileStream::GetSize() { return m_pFile->GetSize(); } FX_BOOL CFX_CRTFileStream::IsEOF() { return GetPosition() >= GetSize(); } FX_FILESIZE CFX_CRTFileStream::GetPosition() { return m_pFile->GetPosition(); } FX_BOOL CFX_CRTFileStream::ReadBlock(void* buffer, FX_FILESIZE offset, size_t size) { return (FX_BOOL)m_pFile->ReadPos(buffer, size, offset); } size_t CFX_CRTFileStream::ReadBlock(void* buffer, size_t size) { return m_pFile->Read(buffer, size); } FX_BOOL CFX_CRTFileStream::WriteBlock(const void* buffer, FX_FILESIZE offset, size_t size) { return (FX_BOOL)m_pFile->WritePos(buffer, size, offset); } FX_BOOL CFX_CRTFileStream::Flush() { return m_pFile->Flush(); } #ifdef PDF_ENABLE_XFA IFX_FileAccess* FX_CreateDefaultFileAccess(const CFX_WideStringC& wsPath) { if (wsPath.GetLength() == 0) return nullptr; CFX_CRTFileAccess* pFA = new CFX_CRTFileAccess; pFA->Init(wsPath); return pFA; } #endif // PDF_ENABLE_XFA IFX_FileStream* FX_CreateFileStream(const FX_CHAR* filename, uint32_t dwModes) { std::unique_ptr<IFXCRT_FileAccess> pFA(IFXCRT_FileAccess::Create()); if (!pFA->Open(filename, dwModes)) return nullptr; return new CFX_CRTFileStream(std::move(pFA)); } IFX_FileStream* FX_CreateFileStream(const FX_WCHAR* filename, uint32_t dwModes) { std::unique_ptr<IFXCRT_FileAccess> pFA(IFXCRT_FileAccess::Create()); if (!pFA->Open(filename, dwModes)) return nullptr; return new CFX_CRTFileStream(std::move(pFA)); } IFX_FileRead* FX_CreateFileRead(const FX_CHAR* filename) { return FX_CreateFileStream(filename, FX_FILEMODE_ReadOnly); } IFX_FileRead* FX_CreateFileRead(const FX_WCHAR* filename) { return FX_CreateFileStream(filename, FX_FILEMODE_ReadOnly); } IFX_MemoryStream* FX_CreateMemoryStream(uint8_t* pBuffer, size_t dwSize, FX_BOOL bTakeOver) { return new CFX_MemoryStream(pBuffer, dwSize, bTakeOver); } IFX_MemoryStream* FX_CreateMemoryStream(FX_BOOL bConsecutive) { return new CFX_MemoryStream(bConsecutive); } FX_FLOAT FXSYS_tan(FX_FLOAT a) { return (FX_FLOAT)tan(a); } FX_FLOAT FXSYS_logb(FX_FLOAT b, FX_FLOAT x) { return FXSYS_log(x) / FXSYS_log(b); } FX_FLOAT FXSYS_strtof(const FX_CHAR* pcsStr, int32_t iLength, int32_t* pUsedLen) { ASSERT(pcsStr); if (iLength < 0) { iLength = (int32_t)FXSYS_strlen(pcsStr); } CFX_WideString ws = CFX_WideString::FromLocal(CFX_ByteStringC(pcsStr, iLength)); return FXSYS_wcstof(ws.c_str(), iLength, pUsedLen); } FX_FLOAT FXSYS_wcstof(const FX_WCHAR* pwsStr, int32_t iLength, int32_t* pUsedLen) { ASSERT(pwsStr); if (iLength < 0) { iLength = (int32_t)FXSYS_wcslen(pwsStr); } if (iLength == 0) { return 0.0f; } int32_t iUsedLen = 0; FX_BOOL bNegtive = FALSE; switch (pwsStr[iUsedLen]) { case '-': bNegtive = TRUE; case '+': iUsedLen++; break; } FX_FLOAT fValue = 0.0f; while (iUsedLen < iLength) { FX_WCHAR wch = pwsStr[iUsedLen]; if (wch >= L'0' && wch <= L'9') { fValue = fValue * 10.0f + (wch - L'0'); } else { break; } iUsedLen++; } if (iUsedLen < iLength && pwsStr[iUsedLen] == L'.') { FX_FLOAT fPrecise = 0.1f; while (++iUsedLen < iLength) { FX_WCHAR wch = pwsStr[iUsedLen]; if (wch >= L'0' && wch <= L'9') { fValue += (wch - L'0') * fPrecise; fPrecise *= 0.1f; } else { break; } } } if (pUsedLen) { *pUsedLen = iUsedLen; } return bNegtive ? -fValue : fValue; } FX_WCHAR* FXSYS_wcsncpy(FX_WCHAR* dstStr, const FX_WCHAR* srcStr, size_t count) { ASSERT(dstStr && srcStr && count > 0); for (size_t i = 0; i < count; ++i) if ((dstStr[i] = srcStr[i]) == L'\0') { break; } return dstStr; } int32_t FXSYS_wcsnicmp(const FX_WCHAR* s1, const FX_WCHAR* s2, size_t count) { ASSERT(s1 && s2 && count > 0); FX_WCHAR wch1 = 0, wch2 = 0; while (count-- > 0) { wch1 = (FX_WCHAR)FXSYS_tolower(*s1++); wch2 = (FX_WCHAR)FXSYS_tolower(*s2++); if (wch1 != wch2) { break; } } return wch1 - wch2; } int32_t FXSYS_strnicmp(const FX_CHAR* s1, const FX_CHAR* s2, size_t count) { ASSERT(s1 && s2 && count > 0); FX_CHAR ch1 = 0, ch2 = 0; while (count-- > 0) { ch1 = (FX_CHAR)FXSYS_tolower(*s1++); ch2 = (FX_CHAR)FXSYS_tolower(*s2++); if (ch1 != ch2) { break; } } return ch1 - ch2; } uint32_t FX_HashCode_GetA(const CFX_ByteStringC& str, bool bIgnoreCase) { uint32_t dwHashCode = 0; if (bIgnoreCase) { for (FX_STRSIZE i = 0; i < str.GetLength(); ++i) dwHashCode = 31 * dwHashCode + FXSYS_tolower(str.CharAt(i)); } else { for (FX_STRSIZE i = 0; i < str.GetLength(); ++i) dwHashCode = 31 * dwHashCode + str.CharAt(i); } return dwHashCode; } uint32_t FX_HashCode_GetW(const CFX_WideStringC& str, bool bIgnoreCase) { uint32_t dwHashCode = 0; if (bIgnoreCase) { for (FX_STRSIZE i = 0; i < str.GetLength(); ++i) dwHashCode = 1313 * dwHashCode + FXSYS_tolower(str.CharAt(i)); } else { for (FX_STRSIZE i = 0; i < str.GetLength(); ++i) dwHashCode = 1313 * dwHashCode + str.CharAt(i); } return dwHashCode; } void* FX_Random_MT_Start(uint32_t dwSeed) { FX_MTRANDOMCONTEXT* pContext = FX_Alloc(FX_MTRANDOMCONTEXT, 1); pContext->mt[0] = dwSeed; uint32_t& i = pContext->mti; uint32_t* pBuf = pContext->mt; for (i = 1; i < MT_N; i++) { pBuf[i] = (1812433253UL * (pBuf[i - 1] ^ (pBuf[i - 1] >> 30)) + i); } pContext->bHaveSeed = TRUE; return pContext; } uint32_t FX_Random_MT_Generate(void* pContext) { ASSERT(pContext); FX_MTRANDOMCONTEXT* pMTC = static_cast<FX_MTRANDOMCONTEXT*>(pContext); uint32_t v; static uint32_t mag[2] = {0, MT_Matrix_A}; uint32_t& mti = pMTC->mti; uint32_t* pBuf = pMTC->mt; if ((int)mti < 0 || mti >= MT_N) { if (mti > MT_N && !pMTC->bHaveSeed) { return 0; } uint32_t kk; for (kk = 0; kk < MT_N - MT_M; kk++) { v = (pBuf[kk] & MT_Upper_Mask) | (pBuf[kk + 1] & MT_Lower_Mask); pBuf[kk] = pBuf[kk + MT_M] ^ (v >> 1) ^ mag[v & 1]; } for (; kk < MT_N - 1; kk++) { v = (pBuf[kk] & MT_Upper_Mask) | (pBuf[kk + 1] & MT_Lower_Mask); pBuf[kk] = pBuf[kk + (MT_M - MT_N)] ^ (v >> 1) ^ mag[v & 1]; } v = (pBuf[MT_N - 1] & MT_Upper_Mask) | (pBuf[0] & MT_Lower_Mask); pBuf[MT_N - 1] = pBuf[MT_M - 1] ^ (v >> 1) ^ mag[v & 1]; mti = 0; } v = pBuf[mti++]; v ^= (v >> 11); v ^= (v << 7) & 0x9d2c5680UL; v ^= (v << 15) & 0xefc60000UL; v ^= (v >> 18); return v; } void FX_Random_MT_Close(void* pContext) { ASSERT(pContext); FX_Free(pContext); } void FX_Random_GenerateMT(uint32_t* pBuffer, int32_t iCount) { uint32_t dwSeed; #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ if (!FX_GenerateCryptoRandom(&dwSeed, 1)) { FX_Random_GenerateBase(&dwSeed, 1); } #else FX_Random_GenerateBase(&dwSeed, 1); #endif void* pContext = FX_Random_MT_Start(dwSeed); while (iCount-- > 0) { *pBuffer++ = FX_Random_MT_Generate(pContext); } FX_Random_MT_Close(pContext); } void FX_Random_GenerateBase(uint32_t* pBuffer, int32_t iCount) { #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ SYSTEMTIME st1, st2; ::GetSystemTime(&st1); do { ::GetSystemTime(&st2); } while (FXSYS_memcmp(&st1, &st2, sizeof(SYSTEMTIME)) == 0); uint32_t dwHash1 = FX_HashCode_GetA(CFX_ByteStringC((uint8_t*)&st1, sizeof(st1)), true); uint32_t dwHash2 = FX_HashCode_GetA(CFX_ByteStringC((uint8_t*)&st2, sizeof(st2)), true); ::srand((dwHash1 << 16) | (uint32_t)dwHash2); #else time_t tmLast = time(nullptr); time_t tmCur; while ((tmCur = time(nullptr)) == tmLast) { continue; } ::srand((tmCur << 16) | (tmLast & 0xFFFF)); #endif while (iCount-- > 0) { *pBuffer++ = (uint32_t)((::rand() << 16) | (::rand() & 0xFFFF)); } } #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ FX_BOOL FX_GenerateCryptoRandom(uint32_t* pBuffer, int32_t iCount) { HCRYPTPROV hCP = 0; if (!::CryptAcquireContext(&hCP, nullptr, nullptr, PROV_RSA_FULL, 0) || !hCP) { return FALSE; } ::CryptGenRandom(hCP, iCount * sizeof(uint32_t), (uint8_t*)pBuffer); ::CryptReleaseContext(hCP, 0); return TRUE; } #endif void FX_Random_GenerateCrypto(uint32_t* pBuffer, int32_t iCount) { #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ FX_GenerateCryptoRandom(pBuffer, iCount); #else FX_Random_GenerateBase(pBuffer, iCount); #endif } #ifdef PDF_ENABLE_XFA void FX_GUID_CreateV4(FX_LPGUID pGUID) { FX_Random_GenerateMT((uint32_t*)pGUID, 4); uint8_t& b = ((uint8_t*)pGUID)[6]; b = (b & 0x0F) | 0x40; } const FX_CHAR* gs_FX_pHexChars = "0123456789ABCDEF"; void FX_GUID_ToString(FX_LPCGUID pGUID, CFX_ByteString& bsStr, FX_BOOL bSeparator) { FX_CHAR* pBuf = bsStr.GetBuffer(40); uint8_t b; for (int32_t i = 0; i < 16; i++) { b = ((const uint8_t*)pGUID)[i]; *pBuf++ = gs_FX_pHexChars[b >> 4]; *pBuf++ = gs_FX_pHexChars[b & 0x0F]; if (bSeparator && (i == 3 || i == 5 || i == 7 || i == 9)) { *pBuf++ = L'-'; } } bsStr.ReleaseBuffer(bSeparator ? 36 : 32); } #endif // PDF_ENABLE_XFA