Home | History | Annotate | Download | only in fxcrt
      1 // Copyright 2014 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "core/fxcrt/extension.h"
      8 
      9 #include <algorithm>
     10 #include <memory>
     11 #include <utility>
     12 
     13 #include "core/fxcrt/fx_basic.h"
     14 #include "core/fxcrt/fx_ext.h"
     15 
     16 #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
     17 #include <wincrypt.h>
     18 #else
     19 #include <ctime>
     20 #endif
     21 
     22 namespace {
     23 
     24 #ifdef PDF_ENABLE_XFA
     25 
     26 class CFX_CRTFileAccess : public IFX_FileAccess {
     27  public:
     28   template <typename T, typename... Args>
     29   friend CFX_RetainPtr<T> pdfium::MakeRetain(Args&&... args);
     30 
     31   // IFX_FileAccess
     32   void GetPath(CFX_WideString& wsPath) override;
     33   CFX_RetainPtr<IFX_SeekableStream> CreateFileStream(uint32_t dwModes) override;
     34 
     35   bool Init(const CFX_WideStringC& wsPath);
     36 
     37  private:
     38   CFX_CRTFileAccess();
     39   ~CFX_CRTFileAccess() override;
     40 
     41   CFX_WideString m_path;
     42 };
     43 
     44 CFX_CRTFileAccess::CFX_CRTFileAccess() {}
     45 
     46 CFX_CRTFileAccess::~CFX_CRTFileAccess() {}
     47 
     48 void CFX_CRTFileAccess::GetPath(CFX_WideString& wsPath) {
     49   wsPath = m_path;
     50 }
     51 
     52 CFX_RetainPtr<IFX_SeekableStream> CFX_CRTFileAccess::CreateFileStream(
     53     uint32_t dwModes) {
     54   return IFX_SeekableStream::CreateFromFilename(m_path.c_str(), dwModes);
     55 }
     56 
     57 bool CFX_CRTFileAccess::Init(const CFX_WideStringC& wsPath) {
     58   m_path = wsPath;
     59   return true;
     60 }
     61 
     62 #endif  // PDF_ENABLE_XFA
     63 
     64 class CFX_CRTFileStream final : public IFX_SeekableStream {
     65  public:
     66   template <typename T, typename... Args>
     67   friend CFX_RetainPtr<T> pdfium::MakeRetain(Args&&... args);
     68 
     69   // IFX_SeekableStream:
     70   FX_FILESIZE GetSize() override;
     71   bool IsEOF() override;
     72   FX_FILESIZE GetPosition() override;
     73   bool ReadBlock(void* buffer, FX_FILESIZE offset, size_t size) override;
     74   size_t ReadBlock(void* buffer, size_t size) override;
     75   bool WriteBlock(const void* buffer, FX_FILESIZE offset, size_t size) override;
     76   bool Flush() override;
     77 
     78  private:
     79   explicit CFX_CRTFileStream(std::unique_ptr<IFXCRT_FileAccess> pFA);
     80   ~CFX_CRTFileStream() override;
     81 
     82   std::unique_ptr<IFXCRT_FileAccess> m_pFile;
     83 };
     84 
     85 CFX_CRTFileStream::CFX_CRTFileStream(std::unique_ptr<IFXCRT_FileAccess> pFA)
     86     : m_pFile(std::move(pFA)) {}
     87 
     88 CFX_CRTFileStream::~CFX_CRTFileStream() {}
     89 
     90 FX_FILESIZE CFX_CRTFileStream::GetSize() {
     91   return m_pFile->GetSize();
     92 }
     93 
     94 bool CFX_CRTFileStream::IsEOF() {
     95   return GetPosition() >= GetSize();
     96 }
     97 
     98 FX_FILESIZE CFX_CRTFileStream::GetPosition() {
     99   return m_pFile->GetPosition();
    100 }
    101 
    102 bool CFX_CRTFileStream::ReadBlock(void* buffer,
    103                                   FX_FILESIZE offset,
    104                                   size_t size) {
    105   return m_pFile->ReadPos(buffer, size, offset) > 0;
    106 }
    107 
    108 size_t CFX_CRTFileStream::ReadBlock(void* buffer, size_t size) {
    109   return m_pFile->Read(buffer, size);
    110 }
    111 
    112 bool CFX_CRTFileStream::WriteBlock(const void* buffer,
    113                                    FX_FILESIZE offset,
    114                                    size_t size) {
    115   return !!m_pFile->WritePos(buffer, size, offset);
    116 }
    117 
    118 bool CFX_CRTFileStream::Flush() {
    119   return m_pFile->Flush();
    120 }
    121 
    122 #define FX_MEMSTREAM_BlockSize (64 * 1024)
    123 #define FX_MEMSTREAM_Consecutive 0x01
    124 #define FX_MEMSTREAM_TakeOver 0x02
    125 
    126 class CFX_MemoryStream final : public IFX_MemoryStream {
    127  public:
    128   template <typename T, typename... Args>
    129   friend CFX_RetainPtr<T> pdfium::MakeRetain(Args&&... args);
    130 
    131   // IFX_MemoryStream
    132   FX_FILESIZE GetSize() override;
    133   bool IsEOF() override;
    134   FX_FILESIZE GetPosition() override;
    135   bool ReadBlock(void* buffer, FX_FILESIZE offset, size_t size) override;
    136   size_t ReadBlock(void* buffer, size_t size) override;
    137   bool WriteBlock(const void* buffer, FX_FILESIZE offset, size_t size) override;
    138   bool Flush() override;
    139   bool IsConsecutive() const override;
    140   void EstimateSize(size_t nInitSize, size_t nGrowSize) override;
    141   uint8_t* GetBuffer() const override;
    142   void AttachBuffer(uint8_t* pBuffer,
    143                     size_t nSize,
    144                     bool bTakeOver = false) override;
    145   void DetachBuffer() override;
    146 
    147  private:
    148   explicit CFX_MemoryStream(bool bConsecutive);
    149   CFX_MemoryStream(uint8_t* pBuffer, size_t nSize, bool bTakeOver);
    150   ~CFX_MemoryStream() override;
    151 
    152   bool ExpandBlocks(size_t size);
    153 
    154   CFX_ArrayTemplate<uint8_t*> m_Blocks;
    155   size_t m_nTotalSize;
    156   size_t m_nCurSize;
    157   size_t m_nCurPos;
    158   size_t m_nGrowSize;
    159   uint32_t m_dwFlags;
    160 };
    161 
    162 CFX_MemoryStream::CFX_MemoryStream(bool bConsecutive)
    163     : m_nTotalSize(0),
    164       m_nCurSize(0),
    165       m_nCurPos(0),
    166       m_nGrowSize(FX_MEMSTREAM_BlockSize) {
    167   m_dwFlags =
    168       FX_MEMSTREAM_TakeOver | (bConsecutive ? FX_MEMSTREAM_Consecutive : 0);
    169 }
    170 
    171 CFX_MemoryStream::CFX_MemoryStream(uint8_t* pBuffer,
    172                                    size_t nSize,
    173                                    bool bTakeOver)
    174     : m_nTotalSize(nSize),
    175       m_nCurSize(nSize),
    176       m_nCurPos(0),
    177       m_nGrowSize(FX_MEMSTREAM_BlockSize) {
    178   m_Blocks.Add(pBuffer);
    179   m_dwFlags =
    180       FX_MEMSTREAM_Consecutive | (bTakeOver ? FX_MEMSTREAM_TakeOver : 0);
    181 }
    182 
    183 CFX_MemoryStream::~CFX_MemoryStream() {
    184   if (m_dwFlags & FX_MEMSTREAM_TakeOver) {
    185     for (int32_t i = 0; i < m_Blocks.GetSize(); i++) {
    186       FX_Free(m_Blocks[i]);
    187     }
    188   }
    189   m_Blocks.RemoveAll();
    190 }
    191 
    192 FX_FILESIZE CFX_MemoryStream::GetSize() {
    193   return (FX_FILESIZE)m_nCurSize;
    194 }
    195 
    196 bool CFX_MemoryStream::IsEOF() {
    197   return m_nCurPos >= (size_t)GetSize();
    198 }
    199 
    200 FX_FILESIZE CFX_MemoryStream::GetPosition() {
    201   return (FX_FILESIZE)m_nCurPos;
    202 }
    203 
    204 bool CFX_MemoryStream::ReadBlock(void* buffer,
    205                                  FX_FILESIZE offset,
    206                                  size_t size) {
    207   if (!buffer || !size || offset < 0)
    208     return false;
    209 
    210   FX_SAFE_SIZE_T newPos = size;
    211   newPos += offset;
    212   if (!newPos.IsValid() || newPos.ValueOrDefault(0) == 0 ||
    213       newPos.ValueOrDie() > m_nCurSize) {
    214     return false;
    215   }
    216 
    217   m_nCurPos = newPos.ValueOrDie();
    218   if (m_dwFlags & FX_MEMSTREAM_Consecutive) {
    219     FXSYS_memcpy(buffer, m_Blocks[0] + (size_t)offset, size);
    220     return true;
    221   }
    222   size_t nStartBlock = (size_t)offset / m_nGrowSize;
    223   offset -= (FX_FILESIZE)(nStartBlock * m_nGrowSize);
    224   while (size) {
    225     size_t nRead = m_nGrowSize - (size_t)offset;
    226     if (nRead > size) {
    227       nRead = size;
    228     }
    229     FXSYS_memcpy(buffer, m_Blocks[(int)nStartBlock] + (size_t)offset, nRead);
    230     buffer = ((uint8_t*)buffer) + nRead;
    231     size -= nRead;
    232     nStartBlock++;
    233     offset = 0;
    234   }
    235   return true;
    236 }
    237 
    238 size_t CFX_MemoryStream::ReadBlock(void* buffer, size_t size) {
    239   if (m_nCurPos >= m_nCurSize) {
    240     return 0;
    241   }
    242   size_t nRead = std::min(size, m_nCurSize - m_nCurPos);
    243   if (!ReadBlock(buffer, (int32_t)m_nCurPos, nRead)) {
    244     return 0;
    245   }
    246   return nRead;
    247 }
    248 
    249 bool CFX_MemoryStream::WriteBlock(const void* buffer,
    250                                   FX_FILESIZE offset,
    251                                   size_t size) {
    252   if (!buffer || !size)
    253     return false;
    254 
    255   if (m_dwFlags & FX_MEMSTREAM_Consecutive) {
    256     FX_SAFE_SIZE_T newPos = size;
    257     newPos += offset;
    258     if (!newPos.IsValid())
    259       return false;
    260 
    261     m_nCurPos = newPos.ValueOrDie();
    262     if (m_nCurPos > m_nTotalSize) {
    263       m_nTotalSize = (m_nCurPos + m_nGrowSize - 1) / m_nGrowSize * m_nGrowSize;
    264       if (m_Blocks.GetSize() < 1) {
    265         uint8_t* block = FX_Alloc(uint8_t, m_nTotalSize);
    266         m_Blocks.Add(block);
    267       } else {
    268         m_Blocks[0] = FX_Realloc(uint8_t, m_Blocks[0], m_nTotalSize);
    269       }
    270       if (!m_Blocks[0]) {
    271         m_Blocks.RemoveAll();
    272         return false;
    273       }
    274     }
    275     FXSYS_memcpy(m_Blocks[0] + (size_t)offset, buffer, size);
    276     if (m_nCurSize < m_nCurPos) {
    277       m_nCurSize = m_nCurPos;
    278     }
    279     return true;
    280   }
    281 
    282   FX_SAFE_SIZE_T newPos = size;
    283   newPos += offset;
    284   if (!newPos.IsValid()) {
    285     return false;
    286   }
    287 
    288   if (!ExpandBlocks(newPos.ValueOrDie())) {
    289     return false;
    290   }
    291   m_nCurPos = newPos.ValueOrDie();
    292   size_t nStartBlock = (size_t)offset / m_nGrowSize;
    293   offset -= (FX_FILESIZE)(nStartBlock * m_nGrowSize);
    294   while (size) {
    295     size_t nWrite = m_nGrowSize - (size_t)offset;
    296     if (nWrite > size) {
    297       nWrite = size;
    298     }
    299     FXSYS_memcpy(m_Blocks[(int)nStartBlock] + (size_t)offset, buffer, nWrite);
    300     buffer = ((uint8_t*)buffer) + nWrite;
    301     size -= nWrite;
    302     nStartBlock++;
    303     offset = 0;
    304   }
    305   return true;
    306 }
    307 
    308 bool CFX_MemoryStream::Flush() {
    309   return true;
    310 }
    311 
    312 bool CFX_MemoryStream::IsConsecutive() const {
    313   return !!(m_dwFlags & FX_MEMSTREAM_Consecutive);
    314 }
    315 
    316 void CFX_MemoryStream::EstimateSize(size_t nInitSize, size_t nGrowSize) {
    317   if (m_dwFlags & FX_MEMSTREAM_Consecutive) {
    318     if (m_Blocks.GetSize() < 1) {
    319       uint8_t* pBlock =
    320           FX_Alloc(uint8_t, std::max(nInitSize, static_cast<size_t>(4096)));
    321       m_Blocks.Add(pBlock);
    322     }
    323     m_nGrowSize = std::max(nGrowSize, static_cast<size_t>(4096));
    324   } else if (m_Blocks.GetSize() < 1) {
    325     m_nGrowSize = std::max(nGrowSize, static_cast<size_t>(4096));
    326   }
    327 }
    328 
    329 uint8_t* CFX_MemoryStream::GetBuffer() const {
    330   return m_Blocks.GetSize() ? m_Blocks[0] : nullptr;
    331 }
    332 
    333 void CFX_MemoryStream::AttachBuffer(uint8_t* pBuffer,
    334                                     size_t nSize,
    335                                     bool bTakeOver) {
    336   if (!(m_dwFlags & FX_MEMSTREAM_Consecutive))
    337     return;
    338 
    339   m_Blocks.RemoveAll();
    340   m_Blocks.Add(pBuffer);
    341   m_nTotalSize = m_nCurSize = nSize;
    342   m_nCurPos = 0;
    343   m_dwFlags =
    344       FX_MEMSTREAM_Consecutive | (bTakeOver ? FX_MEMSTREAM_TakeOver : 0);
    345 }
    346 
    347 void CFX_MemoryStream::DetachBuffer() {
    348   if (!(m_dwFlags & FX_MEMSTREAM_Consecutive)) {
    349     return;
    350   }
    351   m_Blocks.RemoveAll();
    352   m_nTotalSize = m_nCurSize = m_nCurPos = 0;
    353   m_dwFlags = FX_MEMSTREAM_TakeOver;
    354 }
    355 
    356 bool CFX_MemoryStream::ExpandBlocks(size_t size) {
    357   if (m_nCurSize < size) {
    358     m_nCurSize = size;
    359   }
    360   if (size <= m_nTotalSize) {
    361     return true;
    362   }
    363   int32_t iCount = m_Blocks.GetSize();
    364   size = (size - m_nTotalSize + m_nGrowSize - 1) / m_nGrowSize;
    365   m_Blocks.SetSize(m_Blocks.GetSize() + (int32_t)size);
    366   while (size--) {
    367     uint8_t* pBlock = FX_Alloc(uint8_t, m_nGrowSize);
    368     m_Blocks.SetAt(iCount++, pBlock);
    369     m_nTotalSize += m_nGrowSize;
    370   }
    371   return true;
    372 }
    373 
    374 }  // namespace
    375 
    376 #ifdef PDF_ENABLE_XFA
    377 CFX_RetainPtr<IFX_FileAccess> IFX_FileAccess::CreateDefault(
    378     const CFX_WideStringC& wsPath) {
    379   if (wsPath.GetLength() == 0)
    380     return nullptr;
    381 
    382   auto pFA = pdfium::MakeRetain<CFX_CRTFileAccess>();
    383   pFA->Init(wsPath);
    384   return pFA;
    385 }
    386 #endif  // PDF_ENABLE_XFA
    387 
    388 // static
    389 CFX_RetainPtr<IFX_SeekableStream> IFX_SeekableStream::CreateFromFilename(
    390     const FX_CHAR* filename,
    391     uint32_t dwModes) {
    392   std::unique_ptr<IFXCRT_FileAccess> pFA(IFXCRT_FileAccess::Create());
    393   if (!pFA->Open(filename, dwModes))
    394     return nullptr;
    395   return pdfium::MakeRetain<CFX_CRTFileStream>(std::move(pFA));
    396 }
    397 
    398 // static
    399 CFX_RetainPtr<IFX_SeekableStream> IFX_SeekableStream::CreateFromFilename(
    400     const FX_WCHAR* filename,
    401     uint32_t dwModes) {
    402   std::unique_ptr<IFXCRT_FileAccess> pFA(IFXCRT_FileAccess::Create());
    403   if (!pFA->Open(filename, dwModes))
    404     return nullptr;
    405   return pdfium::MakeRetain<CFX_CRTFileStream>(std::move(pFA));
    406 }
    407 
    408 // static
    409 CFX_RetainPtr<IFX_SeekableReadStream>
    410 IFX_SeekableReadStream::CreateFromFilename(const FX_CHAR* filename) {
    411   return IFX_SeekableStream::CreateFromFilename(filename, FX_FILEMODE_ReadOnly);
    412 }
    413 
    414 // static
    415 CFX_RetainPtr<IFX_MemoryStream> IFX_MemoryStream::Create(uint8_t* pBuffer,
    416                                                          size_t dwSize,
    417                                                          bool bTakeOver) {
    418   return pdfium::MakeRetain<CFX_MemoryStream>(pBuffer, dwSize, bTakeOver);
    419 }
    420 
    421 // static
    422 CFX_RetainPtr<IFX_MemoryStream> IFX_MemoryStream::Create(bool bConsecutive) {
    423   return pdfium::MakeRetain<CFX_MemoryStream>(bConsecutive);
    424 }
    425 
    426 FX_FLOAT FXSYS_tan(FX_FLOAT a) {
    427   return (FX_FLOAT)tan(a);
    428 }
    429 FX_FLOAT FXSYS_logb(FX_FLOAT b, FX_FLOAT x) {
    430   return FXSYS_log(x) / FXSYS_log(b);
    431 }
    432 FX_FLOAT FXSYS_strtof(const FX_CHAR* pcsStr,
    433                       int32_t iLength,
    434                       int32_t* pUsedLen) {
    435   ASSERT(pcsStr);
    436   if (iLength < 0) {
    437     iLength = (int32_t)FXSYS_strlen(pcsStr);
    438   }
    439   CFX_WideString ws =
    440       CFX_WideString::FromLocal(CFX_ByteStringC(pcsStr, iLength));
    441   return FXSYS_wcstof(ws.c_str(), iLength, pUsedLen);
    442 }
    443 FX_FLOAT FXSYS_wcstof(const FX_WCHAR* pwsStr,
    444                       int32_t iLength,
    445                       int32_t* pUsedLen) {
    446   ASSERT(pwsStr);
    447   if (iLength < 0) {
    448     iLength = (int32_t)FXSYS_wcslen(pwsStr);
    449   }
    450   if (iLength == 0) {
    451     return 0.0f;
    452   }
    453   int32_t iUsedLen = 0;
    454   bool bNegtive = false;
    455   switch (pwsStr[iUsedLen]) {
    456     case '-':
    457       bNegtive = true;
    458     case '+':
    459       iUsedLen++;
    460       break;
    461   }
    462   FX_FLOAT fValue = 0.0f;
    463   while (iUsedLen < iLength) {
    464     FX_WCHAR wch = pwsStr[iUsedLen];
    465     if (wch >= L'0' && wch <= L'9') {
    466       fValue = fValue * 10.0f + (wch - L'0');
    467     } else {
    468       break;
    469     }
    470     iUsedLen++;
    471   }
    472   if (iUsedLen < iLength && pwsStr[iUsedLen] == L'.') {
    473     FX_FLOAT fPrecise = 0.1f;
    474     while (++iUsedLen < iLength) {
    475       FX_WCHAR wch = pwsStr[iUsedLen];
    476       if (wch >= L'0' && wch <= L'9') {
    477         fValue += (wch - L'0') * fPrecise;
    478         fPrecise *= 0.1f;
    479       } else {
    480         break;
    481       }
    482     }
    483   }
    484   if (pUsedLen) {
    485     *pUsedLen = iUsedLen;
    486   }
    487   return bNegtive ? -fValue : fValue;
    488 }
    489 FX_WCHAR* FXSYS_wcsncpy(FX_WCHAR* dstStr,
    490                         const FX_WCHAR* srcStr,
    491                         size_t count) {
    492   ASSERT(dstStr && srcStr && count > 0);
    493   for (size_t i = 0; i < count; ++i)
    494     if ((dstStr[i] = srcStr[i]) == L'\0') {
    495       break;
    496     }
    497   return dstStr;
    498 }
    499 int32_t FXSYS_wcsnicmp(const FX_WCHAR* s1, const FX_WCHAR* s2, size_t count) {
    500   ASSERT(s1 && s2 && count > 0);
    501   FX_WCHAR wch1 = 0, wch2 = 0;
    502   while (count-- > 0) {
    503     wch1 = (FX_WCHAR)FXSYS_tolower(*s1++);
    504     wch2 = (FX_WCHAR)FXSYS_tolower(*s2++);
    505     if (wch1 != wch2) {
    506       break;
    507     }
    508   }
    509   return wch1 - wch2;
    510 }
    511 int32_t FXSYS_strnicmp(const FX_CHAR* s1, const FX_CHAR* s2, size_t count) {
    512   ASSERT(s1 && s2 && count > 0);
    513   FX_CHAR ch1 = 0, ch2 = 0;
    514   while (count-- > 0) {
    515     ch1 = (FX_CHAR)FXSYS_tolower(*s1++);
    516     ch2 = (FX_CHAR)FXSYS_tolower(*s2++);
    517     if (ch1 != ch2) {
    518       break;
    519     }
    520   }
    521   return ch1 - ch2;
    522 }
    523 
    524 uint32_t FX_HashCode_GetA(const CFX_ByteStringC& str, bool bIgnoreCase) {
    525   uint32_t dwHashCode = 0;
    526   if (bIgnoreCase) {
    527     for (FX_STRSIZE i = 0; i < str.GetLength(); ++i)
    528       dwHashCode = 31 * dwHashCode + FXSYS_tolower(str.CharAt(i));
    529   } else {
    530     for (FX_STRSIZE i = 0; i < str.GetLength(); ++i)
    531       dwHashCode = 31 * dwHashCode + str.CharAt(i);
    532   }
    533   return dwHashCode;
    534 }
    535 
    536 uint32_t FX_HashCode_GetW(const CFX_WideStringC& str, bool bIgnoreCase) {
    537   uint32_t dwHashCode = 0;
    538   if (bIgnoreCase) {
    539     for (FX_STRSIZE i = 0; i < str.GetLength(); ++i)
    540       dwHashCode = 1313 * dwHashCode + FXSYS_tolower(str.CharAt(i));
    541   } else {
    542     for (FX_STRSIZE i = 0; i < str.GetLength(); ++i)
    543       dwHashCode = 1313 * dwHashCode + str.CharAt(i);
    544   }
    545   return dwHashCode;
    546 }
    547 
    548 void* FX_Random_MT_Start(uint32_t dwSeed) {
    549   FX_MTRANDOMCONTEXT* pContext = FX_Alloc(FX_MTRANDOMCONTEXT, 1);
    550   pContext->mt[0] = dwSeed;
    551   uint32_t& i = pContext->mti;
    552   uint32_t* pBuf = pContext->mt;
    553   for (i = 1; i < MT_N; i++) {
    554     pBuf[i] = (1812433253UL * (pBuf[i - 1] ^ (pBuf[i - 1] >> 30)) + i);
    555   }
    556   pContext->bHaveSeed = true;
    557   return pContext;
    558 }
    559 uint32_t FX_Random_MT_Generate(void* pContext) {
    560   ASSERT(pContext);
    561   FX_MTRANDOMCONTEXT* pMTC = static_cast<FX_MTRANDOMCONTEXT*>(pContext);
    562   uint32_t v;
    563   static uint32_t mag[2] = {0, MT_Matrix_A};
    564   uint32_t& mti = pMTC->mti;
    565   uint32_t* pBuf = pMTC->mt;
    566   if ((int)mti < 0 || mti >= MT_N) {
    567     if (mti > MT_N && !pMTC->bHaveSeed) {
    568       return 0;
    569     }
    570     uint32_t kk;
    571     for (kk = 0; kk < MT_N - MT_M; kk++) {
    572       v = (pBuf[kk] & MT_Upper_Mask) | (pBuf[kk + 1] & MT_Lower_Mask);
    573       pBuf[kk] = pBuf[kk + MT_M] ^ (v >> 1) ^ mag[v & 1];
    574     }
    575     for (; kk < MT_N - 1; kk++) {
    576       v = (pBuf[kk] & MT_Upper_Mask) | (pBuf[kk + 1] & MT_Lower_Mask);
    577       pBuf[kk] = pBuf[kk + (MT_M - MT_N)] ^ (v >> 1) ^ mag[v & 1];
    578     }
    579     v = (pBuf[MT_N - 1] & MT_Upper_Mask) | (pBuf[0] & MT_Lower_Mask);
    580     pBuf[MT_N - 1] = pBuf[MT_M - 1] ^ (v >> 1) ^ mag[v & 1];
    581     mti = 0;
    582   }
    583   v = pBuf[mti++];
    584   v ^= (v >> 11);
    585   v ^= (v << 7) & 0x9d2c5680UL;
    586   v ^= (v << 15) & 0xefc60000UL;
    587   v ^= (v >> 18);
    588   return v;
    589 }
    590 void FX_Random_MT_Close(void* pContext) {
    591   ASSERT(pContext);
    592   FX_Free(pContext);
    593 }
    594 void FX_Random_GenerateMT(uint32_t* pBuffer, int32_t iCount) {
    595   uint32_t dwSeed;
    596 #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
    597   if (!FX_GenerateCryptoRandom(&dwSeed, 1)) {
    598     FX_Random_GenerateBase(&dwSeed, 1);
    599   }
    600 #else
    601   FX_Random_GenerateBase(&dwSeed, 1);
    602 #endif
    603   void* pContext = FX_Random_MT_Start(dwSeed);
    604   while (iCount-- > 0) {
    605     *pBuffer++ = FX_Random_MT_Generate(pContext);
    606   }
    607   FX_Random_MT_Close(pContext);
    608 }
    609 void FX_Random_GenerateBase(uint32_t* pBuffer, int32_t iCount) {
    610 #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
    611   SYSTEMTIME st1, st2;
    612   ::GetSystemTime(&st1);
    613   do {
    614     ::GetSystemTime(&st2);
    615   } while (FXSYS_memcmp(&st1, &st2, sizeof(SYSTEMTIME)) == 0);
    616   uint32_t dwHash1 =
    617       FX_HashCode_GetA(CFX_ByteStringC((uint8_t*)&st1, sizeof(st1)), true);
    618   uint32_t dwHash2 =
    619       FX_HashCode_GetA(CFX_ByteStringC((uint8_t*)&st2, sizeof(st2)), true);
    620   ::srand((dwHash1 << 16) | (uint32_t)dwHash2);
    621 #else
    622   time_t tmLast = time(nullptr);
    623   time_t tmCur;
    624   while ((tmCur = time(nullptr)) == tmLast) {
    625     continue;
    626   }
    627 
    628   ::srand((tmCur << 16) | (tmLast & 0xFFFF));
    629 #endif
    630   while (iCount-- > 0) {
    631     *pBuffer++ = (uint32_t)((::rand() << 16) | (::rand() & 0xFFFF));
    632   }
    633 }
    634 #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
    635 bool FX_GenerateCryptoRandom(uint32_t* pBuffer, int32_t iCount) {
    636   HCRYPTPROV hCP = 0;
    637   if (!::CryptAcquireContext(&hCP, nullptr, nullptr, PROV_RSA_FULL, 0) ||
    638       !hCP) {
    639     return false;
    640   }
    641   ::CryptGenRandom(hCP, iCount * sizeof(uint32_t), (uint8_t*)pBuffer);
    642   ::CryptReleaseContext(hCP, 0);
    643   return true;
    644 }
    645 #endif
    646 void FX_Random_GenerateCrypto(uint32_t* pBuffer, int32_t iCount) {
    647 #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
    648   FX_GenerateCryptoRandom(pBuffer, iCount);
    649 #else
    650   FX_Random_GenerateBase(pBuffer, iCount);
    651 #endif
    652 }
    653 
    654 #ifdef PDF_ENABLE_XFA
    655 static const FX_CHAR gs_FX_pHexChars[] = "0123456789ABCDEF";
    656 void FX_GUID_CreateV4(FX_GUID* pGUID) {
    657   FX_Random_GenerateMT((uint32_t*)pGUID, 4);
    658   uint8_t& b = ((uint8_t*)pGUID)[6];
    659   b = (b & 0x0F) | 0x40;
    660 }
    661 void FX_GUID_ToString(const FX_GUID* pGUID,
    662                       CFX_ByteString& bsStr,
    663                       bool bSeparator) {
    664   FX_CHAR* pBuf = bsStr.GetBuffer(40);
    665   uint8_t b;
    666   for (int32_t i = 0; i < 16; i++) {
    667     b = ((const uint8_t*)pGUID)[i];
    668     *pBuf++ = gs_FX_pHexChars[b >> 4];
    669     *pBuf++ = gs_FX_pHexChars[b & 0x0F];
    670     if (bSeparator && (i == 3 || i == 5 || i == 7 || i == 9)) {
    671       *pBuf++ = L'-';
    672     }
    673   }
    674   bsStr.ReleaseBuffer(bSeparator ? 36 : 32);
    675 }
    676 #endif  // PDF_ENABLE_XFA
    677