diff options
author | Dan Sinclair <dsinclair@chromium.org> | 2017-04-20 13:13:04 -0400 |
---|---|---|
committer | Chromium commit bot <commit-bot@chromium.org> | 2017-04-20 17:49:41 +0000 |
commit | cfb1944e245e20fe2ce0e94feebc06526db34fa1 (patch) | |
tree | 6728e3ebca9e53dc97a18e1f5f37c3d53d9bb404 /core/fxcrt/fx_extension.cpp | |
parent | 6864bf8c4fbcac0833a77d044f17f4100d504f2a (diff) | |
download | pdfium-cfb1944e245e20fe2ce0e94feebc06526db34fa1.tar.xz |
Cleanup the fx_extension code.
This CL cleans up the fx_extension file. The stream code was moved to
fx_stream. IFX_FileAccess was removed and CFX_CRTFileAccess split to its
own file. Code shuffled from header to cpp file.
Change-Id: I700fdfcc9797cf4e8050cd9ba010ad8854feefbf
Reviewed-on: https://pdfium-review.googlesource.com/4371
Reviewed-by: Nicolás Peña <npm@chromium.org>
Commit-Queue: dsinclair <dsinclair@chromium.org>
Diffstat (limited to 'core/fxcrt/fx_extension.cpp')
-rw-r--r-- | core/fxcrt/fx_extension.cpp | 523 |
1 files changed, 56 insertions, 467 deletions
diff --git a/core/fxcrt/fx_extension.cpp b/core/fxcrt/fx_extension.cpp index f3e72fd6df..47bd937ff8 100644 --- a/core/fxcrt/fx_extension.cpp +++ b/core/fxcrt/fx_extension.cpp @@ -4,16 +4,7 @@ // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com -#include "core/fxcrt/extension.h" - -#include <algorithm> -#include <memory> -#include <utility> -#include <vector> - -#include "core/fxcrt/fx_basic.h" -#include "core/fxcrt/fx_ext.h" -#include "third_party/base/stl_util.h" +#include "core/fxcrt/fx_extension.h" #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ #include <wincrypt.h> @@ -21,422 +12,48 @@ #include <ctime> #endif -namespace { - -#ifdef PDF_ENABLE_XFA - -class CFX_CRTFileAccess : public IFX_FileAccess { - public: - template <typename T, typename... Args> - friend CFX_RetainPtr<T> pdfium::MakeRetain(Args&&... args); - - // IFX_FileAccess - void GetPath(CFX_WideString& wsPath) override; - CFX_RetainPtr<IFX_SeekableStream> CreateFileStream(uint32_t dwModes) override; - - bool Init(const CFX_WideStringC& wsPath); - - private: - CFX_CRTFileAccess(); - ~CFX_CRTFileAccess() override; - - CFX_WideString m_path; -}; - -CFX_CRTFileAccess::CFX_CRTFileAccess() {} - -CFX_CRTFileAccess::~CFX_CRTFileAccess() {} - -void CFX_CRTFileAccess::GetPath(CFX_WideString& wsPath) { - wsPath = m_path; -} - -CFX_RetainPtr<IFX_SeekableStream> CFX_CRTFileAccess::CreateFileStream( - uint32_t dwModes) { - return IFX_SeekableStream::CreateFromFilename(m_path.c_str(), dwModes); -} - -bool CFX_CRTFileAccess::Init(const CFX_WideStringC& wsPath) { - m_path = wsPath; - return true; -} - -#endif // PDF_ENABLE_XFA - -class CFX_CRTFileStream final : public IFX_SeekableStream { - public: - template <typename T, typename... Args> - friend CFX_RetainPtr<T> pdfium::MakeRetain(Args&&... args); - - // IFX_SeekableStream: - FX_FILESIZE GetSize() override; - bool IsEOF() override; - FX_FILESIZE GetPosition() override; - bool ReadBlock(void* buffer, FX_FILESIZE offset, size_t size) override; - size_t ReadBlock(void* buffer, size_t size) override; - bool WriteBlock(const void* buffer, FX_FILESIZE offset, size_t size) override; - bool Flush() override; - - private: - explicit CFX_CRTFileStream(std::unique_ptr<IFXCRT_FileAccess> pFA); - ~CFX_CRTFileStream() override; - - std::unique_ptr<IFXCRT_FileAccess> m_pFile; -}; - -CFX_CRTFileStream::CFX_CRTFileStream(std::unique_ptr<IFXCRT_FileAccess> pFA) - : m_pFile(std::move(pFA)) {} - -CFX_CRTFileStream::~CFX_CRTFileStream() {} - -FX_FILESIZE CFX_CRTFileStream::GetSize() { - return m_pFile->GetSize(); -} - -bool CFX_CRTFileStream::IsEOF() { - return GetPosition() >= GetSize(); -} - -FX_FILESIZE CFX_CRTFileStream::GetPosition() { - return m_pFile->GetPosition(); -} - -bool CFX_CRTFileStream::ReadBlock(void* buffer, - FX_FILESIZE offset, - size_t size) { - return m_pFile->ReadPos(buffer, size, offset) > 0; -} - -size_t CFX_CRTFileStream::ReadBlock(void* buffer, size_t size) { - return m_pFile->Read(buffer, size); -} - -bool CFX_CRTFileStream::WriteBlock(const void* buffer, - FX_FILESIZE offset, - size_t size) { - return !!m_pFile->WritePos(buffer, size, offset); -} - -bool CFX_CRTFileStream::Flush() { - return m_pFile->Flush(); -} - -#define FX_MEMSTREAM_BlockSize (64 * 1024) -#define FX_MEMSTREAM_Consecutive 0x01 -#define FX_MEMSTREAM_TakeOver 0x02 - -class CFX_MemoryStream final : public IFX_MemoryStream { - public: - template <typename T, typename... Args> - friend CFX_RetainPtr<T> pdfium::MakeRetain(Args&&... args); - - // IFX_MemoryStream - FX_FILESIZE GetSize() override; - bool IsEOF() override; - FX_FILESIZE GetPosition() override; - bool ReadBlock(void* buffer, FX_FILESIZE offset, size_t size) override; - size_t ReadBlock(void* buffer, size_t size) override; - bool WriteBlock(const void* buffer, FX_FILESIZE offset, size_t size) override; - bool Flush() override; - bool IsConsecutive() const override; - void EstimateSize(size_t nInitSize, size_t nGrowSize) override; - uint8_t* GetBuffer() const override; - void AttachBuffer(uint8_t* pBuffer, - size_t nSize, - bool bTakeOver = false) override; - void DetachBuffer() override; - - private: - explicit CFX_MemoryStream(bool bConsecutive); - CFX_MemoryStream(uint8_t* pBuffer, size_t nSize, bool bTakeOver); - ~CFX_MemoryStream() override; +#define MT_N 848 +#define MT_M 456 +#define MT_Matrix_A 0x9908b0df +#define MT_Upper_Mask 0x80000000 +#define MT_Lower_Mask 0x7fffffff - bool ExpandBlocks(size_t size); - - std::vector<uint8_t*> m_Blocks; - size_t m_nTotalSize; - size_t m_nCurSize; - size_t m_nCurPos; - size_t m_nGrowSize; - uint32_t m_dwFlags; -}; - -CFX_MemoryStream::CFX_MemoryStream(bool bConsecutive) - : 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, - bool bTakeOver) - : m_nTotalSize(nSize), - m_nCurSize(nSize), - m_nCurPos(0), - m_nGrowSize(FX_MEMSTREAM_BlockSize) { - m_Blocks.push_back(pBuffer); - m_dwFlags = - FX_MEMSTREAM_Consecutive | (bTakeOver ? FX_MEMSTREAM_TakeOver : 0); -} - -CFX_MemoryStream::~CFX_MemoryStream() { - if (m_dwFlags & FX_MEMSTREAM_TakeOver) { - for (uint8_t* pBlock : m_Blocks) - FX_Free(pBlock); - } -} - -FX_FILESIZE CFX_MemoryStream::GetSize() { - return (FX_FILESIZE)m_nCurSize; -} - -bool CFX_MemoryStream::IsEOF() { - return m_nCurPos >= (size_t)GetSize(); -} - -FX_FILESIZE CFX_MemoryStream::GetPosition() { - return (FX_FILESIZE)m_nCurPos; -} - -bool CFX_MemoryStream::ReadBlock(void* buffer, - FX_FILESIZE offset, - size_t size) { - if (!buffer || !size || offset < 0) - 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) { - 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; - } - memcpy(buffer, m_Blocks[(int)nStartBlock] + (size_t)offset, nRead); - buffer = ((uint8_t*)buffer) + nRead; - size -= nRead; - nStartBlock++; - offset = 0; - } - return true; -} +namespace { -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; +struct FX_MTRANDOMCONTEXT { + FX_MTRANDOMCONTEXT() { + mti = MT_N + 1; + bHaveSeed = false; } - return nRead; -} -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.empty()) { - m_Blocks.push_back(FX_Alloc(uint8_t, m_nTotalSize)); - } else { - m_Blocks[0] = FX_Realloc(uint8_t, m_Blocks[0], m_nTotalSize); - } - } - 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; - } + uint32_t mti; + bool bHaveSeed; + uint32_t mt[MT_N]; +}; - if (!ExpandBlocks(newPos.ValueOrDie())) { +#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ +bool GenerateCryptoRandom(uint32_t* pBuffer, int32_t iCount) { + HCRYPTPROV hCP = 0; + if (!::CryptAcquireContext(&hCP, nullptr, nullptr, PROV_RSA_FULL, 0) || + !hCP) { 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; - } - memcpy(m_Blocks[(int)nStartBlock] + (size_t)offset, buffer, nWrite); - buffer = ((uint8_t*)buffer) + nWrite; - size -= nWrite; - nStartBlock++; - offset = 0; - } - return true; -} - -bool CFX_MemoryStream::Flush() { - return true; -} - -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.empty()) { - m_Blocks.push_back( - FX_Alloc(uint8_t, std::max(nInitSize, static_cast<size_t>(4096)))); - } - m_nGrowSize = std::max(nGrowSize, static_cast<size_t>(4096)); - } else if (m_Blocks.empty()) { - m_nGrowSize = std::max(nGrowSize, static_cast<size_t>(4096)); - } -} - -uint8_t* CFX_MemoryStream::GetBuffer() const { - return !m_Blocks.empty() ? m_Blocks.front() : nullptr; -} - -void CFX_MemoryStream::AttachBuffer(uint8_t* pBuffer, - size_t nSize, - bool bTakeOver) { - if (!(m_dwFlags & FX_MEMSTREAM_Consecutive)) - return; - - m_Blocks.clear(); - m_Blocks.push_back(pBuffer); - m_nTotalSize = nSize; - 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.clear(); - m_nTotalSize = 0; - m_nCurSize = 0; - m_nCurPos = 0; - m_dwFlags = FX_MEMSTREAM_TakeOver; -} - -bool CFX_MemoryStream::ExpandBlocks(size_t size) { - if (m_nCurSize < size) - m_nCurSize = size; - - if (size <= m_nTotalSize) - return true; - - size = (size - m_nTotalSize + m_nGrowSize - 1) / m_nGrowSize; - size_t iCount = m_Blocks.size(); - m_Blocks.resize(iCount + size); - while (size--) { - m_Blocks[iCount++] = FX_Alloc(uint8_t, m_nGrowSize); - m_nTotalSize += m_nGrowSize; - } + ::CryptGenRandom(hCP, iCount * sizeof(uint32_t), + reinterpret_cast<uint8_t*>(pBuffer)); + ::CryptReleaseContext(hCP, 0); return true; } +#endif } // namespace -#ifdef PDF_ENABLE_XFA -CFX_RetainPtr<IFX_FileAccess> IFX_FileAccess::CreateDefault( - const CFX_WideStringC& wsPath) { - if (wsPath.GetLength() == 0) - return nullptr; - - auto pFA = pdfium::MakeRetain<CFX_CRTFileAccess>(); - pFA->Init(wsPath); - return pFA; -} -#endif // PDF_ENABLE_XFA - -// static -CFX_RetainPtr<IFX_SeekableStream> IFX_SeekableStream::CreateFromFilename( - const char* filename, - uint32_t dwModes) { - std::unique_ptr<IFXCRT_FileAccess> pFA(IFXCRT_FileAccess::Create()); - if (!pFA->Open(filename, dwModes)) - return nullptr; - return pdfium::MakeRetain<CFX_CRTFileStream>(std::move(pFA)); -} - -// static -CFX_RetainPtr<IFX_SeekableStream> IFX_SeekableStream::CreateFromFilename( - const wchar_t* filename, - uint32_t dwModes) { - std::unique_ptr<IFXCRT_FileAccess> pFA(IFXCRT_FileAccess::Create()); - if (!pFA->Open(filename, dwModes)) - return nullptr; - return pdfium::MakeRetain<CFX_CRTFileStream>(std::move(pFA)); -} - -// static -CFX_RetainPtr<IFX_SeekableReadStream> -IFX_SeekableReadStream::CreateFromFilename(const char* filename) { - return IFX_SeekableStream::CreateFromFilename(filename, FX_FILEMODE_ReadOnly); -} - -// static -CFX_RetainPtr<IFX_MemoryStream> IFX_MemoryStream::Create(uint8_t* pBuffer, - size_t dwSize, - bool bTakeOver) { - return pdfium::MakeRetain<CFX_MemoryStream>(pBuffer, dwSize, bTakeOver); -} - -// static -CFX_RetainPtr<IFX_MemoryStream> IFX_MemoryStream::Create(bool bConsecutive) { - return pdfium::MakeRetain<CFX_MemoryStream>(bConsecutive); -} - -float FXSYS_strtof(const 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); -} - float FXSYS_wcstof(const wchar_t* pwsStr, int32_t iLength, int32_t* pUsedLen) { ASSERT(pwsStr); - if (iLength < 0) { - iLength = (int32_t)FXSYS_wcslen(pwsStr); - } - if (iLength == 0) { + if (iLength < 0) + iLength = static_cast<int32_t>(FXSYS_wcslen(pwsStr)); + if (iLength == 0) return 0.0f; - } + int32_t iUsedLen = 0; bool bNegtive = false; switch (pwsStr[iUsedLen]) { @@ -446,16 +63,18 @@ float FXSYS_wcstof(const wchar_t* pwsStr, int32_t iLength, int32_t* pUsedLen) { iUsedLen++; break; } + float fValue = 0.0f; while (iUsedLen < iLength) { wchar_t wch = pwsStr[iUsedLen]; - if (wch >= L'0' && wch <= L'9') { + if (wch >= L'0' && wch <= L'9') fValue = fValue * 10.0f + (wch - L'0'); - } else { + else break; - } + iUsedLen++; } + if (iUsedLen < iLength && pwsStr[iUsedLen] == L'.') { float fPrecise = 0.1f; while (++iUsedLen < iLength) { @@ -468,43 +87,31 @@ float FXSYS_wcstof(const wchar_t* pwsStr, int32_t iLength, int32_t* pUsedLen) { } } } - if (pUsedLen) { + if (pUsedLen) *pUsedLen = iUsedLen; - } + return bNegtive ? -fValue : fValue; } + wchar_t* FXSYS_wcsncpy(wchar_t* dstStr, const wchar_t* srcStr, size_t count) { ASSERT(dstStr && srcStr && count > 0); for (size_t i = 0; i < count; ++i) - if ((dstStr[i] = srcStr[i]) == L'\0') { + if ((dstStr[i] = srcStr[i]) == L'\0') break; - } return dstStr; } + int32_t FXSYS_wcsnicmp(const wchar_t* s1, const wchar_t* s2, size_t count) { ASSERT(s1 && s2 && count > 0); wchar_t wch1 = 0, wch2 = 0; while (count-- > 0) { - wch1 = (wchar_t)FXSYS_tolower(*s1++); - wch2 = (wchar_t)FXSYS_tolower(*s2++); - if (wch1 != wch2) { + wch1 = static_cast<wchar_t>(FXSYS_tolower(*s1++)); + wch2 = static_cast<wchar_t>(FXSYS_tolower(*s2++)); + if (wch1 != wch2) break; - } } return wch1 - wch2; } -int32_t FXSYS_strnicmp(const char* s1, const char* s2, size_t count) { - ASSERT(s1 && s2 && count > 0); - char ch1 = 0, ch2 = 0; - while (count-- > 0) { - ch1 = (char)FXSYS_tolower(*s1++); - ch2 = (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; @@ -535,12 +142,13 @@ void* FX_Random_MT_Start(uint32_t dwSeed) { pContext->mt[0] = dwSeed; uint32_t& i = pContext->mti; uint32_t* pBuf = pContext->mt; - for (i = 1; i < MT_N; i++) { + 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); @@ -549,9 +157,9 @@ uint32_t FX_Random_MT_Generate(void* pContext) { uint32_t& mti = pMTC->mti; uint32_t* pBuf = pMTC->mt; if ((int)mti < 0 || mti >= MT_N) { - if (mti > MT_N && !pMTC->bHaveSeed) { + 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); @@ -572,25 +180,27 @@ uint32_t FX_Random_MT_Generate(void* pContext) { 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)) { + if (!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) { + 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; @@ -606,34 +216,13 @@ void FX_Random_GenerateBase(uint32_t* pBuffer, int32_t iCount) { #else time_t tmLast = time(nullptr); time_t tmCur; - while ((tmCur = time(nullptr)) == tmLast) { + 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_ -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 + while (iCount-- > 0) + *pBuffer++ = static_cast<uint32_t>((::rand() << 16) | (::rand() & 0xFFFF)); } #ifdef PDF_ENABLE_XFA @@ -654,7 +243,7 @@ CFX_ByteString FX_GUID_ToString(const FX_GUID* pGUID, bool bSeparator) { *pBuf++ = gs_FX_pHexChars[b & 0x0F]; if (bSeparator && (i == 3 || i == 5 || i == 7 || i == 9)) *pBuf++ = L'-'; - } + } bsStr.ReleaseBuffer(bSeparator ? 36 : 32); return bsStr; } |