fx_extension.cpp revision 5ae9d0c6fd838a2967cca72aa5751b51dadc2769
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
22namespace {
23
24#ifdef PDF_ENABLE_XFA
25
26class 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
44CFX_CRTFileAccess::CFX_CRTFileAccess() {}
45
46CFX_CRTFileAccess::~CFX_CRTFileAccess() {}
47
48void CFX_CRTFileAccess::GetPath(CFX_WideString& wsPath) {
49  wsPath = m_path;
50}
51
52CFX_RetainPtr<IFX_SeekableStream> CFX_CRTFileAccess::CreateFileStream(
53    uint32_t dwModes) {
54  return IFX_SeekableStream::CreateFromFilename(m_path.c_str(), dwModes);
55}
56
57bool CFX_CRTFileAccess::Init(const CFX_WideStringC& wsPath) {
58  m_path = wsPath;
59  return true;
60}
61
62#endif  // PDF_ENABLE_XFA
63
64class 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
85CFX_CRTFileStream::CFX_CRTFileStream(std::unique_ptr<IFXCRT_FileAccess> pFA)
86    : m_pFile(std::move(pFA)) {}
87
88CFX_CRTFileStream::~CFX_CRTFileStream() {}
89
90FX_FILESIZE CFX_CRTFileStream::GetSize() {
91  return m_pFile->GetSize();
92}
93
94bool CFX_CRTFileStream::IsEOF() {
95  return GetPosition() >= GetSize();
96}
97
98FX_FILESIZE CFX_CRTFileStream::GetPosition() {
99  return m_pFile->GetPosition();
100}
101
102bool CFX_CRTFileStream::ReadBlock(void* buffer,
103                                  FX_FILESIZE offset,
104                                  size_t size) {
105  return m_pFile->ReadPos(buffer, size, offset) > 0;
106}
107
108size_t CFX_CRTFileStream::ReadBlock(void* buffer, size_t size) {
109  return m_pFile->Read(buffer, size);
110}
111
112bool CFX_CRTFileStream::WriteBlock(const void* buffer,
113                                   FX_FILESIZE offset,
114                                   size_t size) {
115  return !!m_pFile->WritePos(buffer, size, offset);
116}
117
118bool 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
126class 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
162CFX_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
171CFX_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
183CFX_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
192FX_FILESIZE CFX_MemoryStream::GetSize() {
193  return (FX_FILESIZE)m_nCurSize;
194}
195
196bool CFX_MemoryStream::IsEOF() {
197  return m_nCurPos >= (size_t)GetSize();
198}
199
200FX_FILESIZE CFX_MemoryStream::GetPosition() {
201  return (FX_FILESIZE)m_nCurPos;
202}
203
204bool 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
238size_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
249bool 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
308bool CFX_MemoryStream::Flush() {
309  return true;
310}
311
312bool CFX_MemoryStream::IsConsecutive() const {
313  return !!(m_dwFlags & FX_MEMSTREAM_Consecutive);
314}
315
316void 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
329uint8_t* CFX_MemoryStream::GetBuffer() const {
330  return m_Blocks.GetSize() ? m_Blocks[0] : nullptr;
331}
332
333void 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
347void 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
356bool 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
377CFX_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
389CFX_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
399CFX_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
409CFX_RetainPtr<IFX_SeekableReadStream>
410IFX_SeekableReadStream::CreateFromFilename(const FX_CHAR* filename) {
411  return IFX_SeekableStream::CreateFromFilename(filename, FX_FILEMODE_ReadOnly);
412}
413
414// static
415CFX_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
422CFX_RetainPtr<IFX_MemoryStream> IFX_MemoryStream::Create(bool bConsecutive) {
423  return pdfium::MakeRetain<CFX_MemoryStream>(bConsecutive);
424}
425
426FX_FLOAT FXSYS_tan(FX_FLOAT a) {
427  return (FX_FLOAT)tan(a);
428}
429FX_FLOAT FXSYS_logb(FX_FLOAT b, FX_FLOAT x) {
430  return FXSYS_log(x) / FXSYS_log(b);
431}
432FX_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}
443FX_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}
489FX_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}
499int32_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}
511int32_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
524uint32_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
536uint32_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
548void* 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}
559uint32_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}
590void FX_Random_MT_Close(void* pContext) {
591  ASSERT(pContext);
592  FX_Free(pContext);
593}
594void 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}
609void 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_
635bool 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
646void 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
655static const FX_CHAR gs_FX_pHexChars[] = "0123456789ABCDEF";
656void 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}
661void 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