diff options
Diffstat (limited to 'core/fxcrt/cfx_widestring.cpp')
-rw-r--r-- | core/fxcrt/cfx_widestring.cpp | 1044 |
1 files changed, 1044 insertions, 0 deletions
diff --git a/core/fxcrt/cfx_widestring.cpp b/core/fxcrt/cfx_widestring.cpp new file mode 100644 index 0000000000..49a62da9a7 --- /dev/null +++ b/core/fxcrt/cfx_widestring.cpp @@ -0,0 +1,1044 @@ +// 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 "core/fxcrt/cfx_widestring.h" + +#include <stddef.h> + +#include <algorithm> +#include <cctype> + +#include "core/fxcrt/cfx_string_pool_template.h" +#include "core/fxcrt/fx_basic.h" +#include "core/fxcrt/fx_ext.h" +#include "third_party/base/numerics/safe_math.h" +#include "third_party/base/stl_util.h" + +template class CFX_StringDataTemplate<wchar_t>; +template class CFX_StringCTemplate<wchar_t>; +template class CFX_StringPoolTemplate<CFX_WideString>; +template struct std::hash<CFX_WideString>; + +#define FORCE_ANSI 0x10000 +#define FORCE_UNICODE 0x20000 +#define FORCE_INT64 0x40000 + +namespace { + +#ifndef NDEBUG +bool IsValidCodePage(uint16_t codepage) { + switch (codepage) { + case 0: + case 932: + case 936: + case 949: + case 950: + return true; + + default: + return false; + } +} +#endif + +const wchar_t* FX_wcsstr(const wchar_t* haystack, + int haystack_len, + const wchar_t* needle, + int needle_len) { + if (needle_len > haystack_len || needle_len == 0) { + return nullptr; + } + const wchar_t* end_ptr = haystack + haystack_len - needle_len; + while (haystack <= end_ptr) { + int i = 0; + while (1) { + if (haystack[i] != needle[i]) { + break; + } + i++; + if (i == needle_len) { + return haystack; + } + } + haystack++; + } + return nullptr; +} + +FX_STRSIZE GuessSizeForVSWPrintf(const wchar_t* pFormat, va_list argList) { + FX_STRSIZE nMaxLen = 0; + for (const wchar_t* pStr = pFormat; *pStr != 0; pStr++) { + if (*pStr != '%' || *(pStr = pStr + 1) == '%') { + ++nMaxLen; + continue; + } + int nItemLen = 0; + int nWidth = 0; + for (; *pStr != 0; pStr++) { + if (*pStr == '#') { + nMaxLen += 2; + } else if (*pStr == '*') { + nWidth = va_arg(argList, int); + } else if (*pStr != '-' && *pStr != '+' && *pStr != '0' && *pStr != ' ') { + break; + } + } + if (nWidth == 0) { + nWidth = FXSYS_wtoi(pStr); + while (std::iswdigit(*pStr)) + ++pStr; + } + if (nWidth < 0 || nWidth > 128 * 1024) + return -1; + int nPrecision = 0; + if (*pStr == '.') { + pStr++; + if (*pStr == '*') { + nPrecision = va_arg(argList, int); + pStr++; + } else { + nPrecision = FXSYS_wtoi(pStr); + while (std::iswdigit(*pStr)) + ++pStr; + } + } + if (nPrecision < 0 || nPrecision > 128 * 1024) + return -1; + int nModifier = 0; + if (*pStr == L'I' && *(pStr + 1) == L'6' && *(pStr + 2) == L'4') { + pStr += 3; + nModifier = FORCE_INT64; + } else { + switch (*pStr) { + case 'h': + nModifier = FORCE_ANSI; + pStr++; + break; + case 'l': + nModifier = FORCE_UNICODE; + pStr++; + break; + case 'F': + case 'N': + case 'L': + pStr++; + break; + } + } + switch (*pStr | nModifier) { + case 'c': + case 'C': + nItemLen = 2; + va_arg(argList, int); + break; + case 'c' | FORCE_ANSI: + case 'C' | FORCE_ANSI: + nItemLen = 2; + va_arg(argList, int); + break; + case 'c' | FORCE_UNICODE: + case 'C' | FORCE_UNICODE: + nItemLen = 2; + va_arg(argList, int); + break; + case 's': { + const wchar_t* pstrNextArg = va_arg(argList, const wchar_t*); + if (pstrNextArg) { + nItemLen = FXSYS_wcslen(pstrNextArg); + if (nItemLen < 1) { + nItemLen = 1; + } + } else { + nItemLen = 6; + } + } break; + case 'S': { + const char* pstrNextArg = va_arg(argList, const char*); + if (pstrNextArg) { + nItemLen = FXSYS_strlen(pstrNextArg); + if (nItemLen < 1) { + nItemLen = 1; + } + } else { + nItemLen = 6; + } + } break; + case 's' | FORCE_ANSI: + case 'S' | FORCE_ANSI: { + const char* pstrNextArg = va_arg(argList, const char*); + if (pstrNextArg) { + nItemLen = FXSYS_strlen(pstrNextArg); + if (nItemLen < 1) { + nItemLen = 1; + } + } else { + nItemLen = 6; + } + } break; + case 's' | FORCE_UNICODE: + case 'S' | FORCE_UNICODE: { + const wchar_t* pstrNextArg = va_arg(argList, wchar_t*); + if (pstrNextArg) { + nItemLen = FXSYS_wcslen(pstrNextArg); + if (nItemLen < 1) { + nItemLen = 1; + } + } else { + nItemLen = 6; + } + } break; + } + if (nItemLen != 0) { + if (nPrecision != 0 && nItemLen > nPrecision) { + nItemLen = nPrecision; + } + if (nItemLen < nWidth) { + nItemLen = nWidth; + } + } else { + switch (*pStr) { + case 'd': + case 'i': + case 'u': + case 'x': + case 'X': + case 'o': + if (nModifier & FORCE_INT64) { + va_arg(argList, int64_t); + } else { + va_arg(argList, int); + } + nItemLen = 32; + if (nItemLen < nWidth + nPrecision) { + nItemLen = nWidth + nPrecision; + } + break; + case 'a': + case 'A': + case 'e': + case 'E': + case 'g': + case 'G': + va_arg(argList, double); + nItemLen = 128; + if (nItemLen < nWidth + nPrecision) { + nItemLen = nWidth + nPrecision; + } + break; + case 'f': + if (nWidth + nPrecision > 100) { + nItemLen = nPrecision + nWidth + 128; + } else { + double f; + char pszTemp[256]; + f = va_arg(argList, double); + FXSYS_snprintf(pszTemp, sizeof(pszTemp), "%*.*f", nWidth, + nPrecision + 6, f); + nItemLen = FXSYS_strlen(pszTemp); + } + break; + case 'p': + va_arg(argList, void*); + nItemLen = 32; + if (nItemLen < nWidth + nPrecision) { + nItemLen = nWidth + nPrecision; + } + break; + case 'n': + va_arg(argList, int*); + break; + } + } + nMaxLen += nItemLen; + } + nMaxLen += 32; // Fudge factor. + return nMaxLen; +} + +} // namespace + +static_assert(sizeof(CFX_WideString) <= sizeof(wchar_t*), + "Strings must not require more space than pointers"); + +CFX_WideString::CFX_WideString() {} + +CFX_WideString::CFX_WideString(const CFX_WideString& other) + : m_pData(other.m_pData) {} + +CFX_WideString::CFX_WideString(CFX_WideString&& other) noexcept { + m_pData.Swap(other.m_pData); +} + +CFX_WideString::CFX_WideString(const wchar_t* pStr, FX_STRSIZE nLen) { + if (nLen < 0) + nLen = pStr ? FXSYS_wcslen(pStr) : 0; + + if (nLen) + m_pData.Reset(StringData::Create(pStr, nLen)); +} + +CFX_WideString::CFX_WideString(wchar_t ch) { + m_pData.Reset(StringData::Create(1)); + m_pData->m_String[0] = ch; +} + +CFX_WideString::CFX_WideString(const wchar_t* ptr) + : CFX_WideString(ptr, ptr ? FXSYS_wcslen(ptr) : 0) {} + +CFX_WideString::CFX_WideString(const CFX_WideStringC& stringSrc) { + if (!stringSrc.IsEmpty()) { + m_pData.Reset(StringData::Create(stringSrc.c_str(), stringSrc.GetLength())); + } +} + +CFX_WideString::CFX_WideString(const CFX_WideStringC& str1, + const CFX_WideStringC& str2) { + int nNewLen = str1.GetLength() + str2.GetLength(); + if (nNewLen == 0) + return; + + m_pData.Reset(StringData::Create(nNewLen)); + m_pData->CopyContents(str1.c_str(), str1.GetLength()); + m_pData->CopyContentsAt(str1.GetLength(), str2.c_str(), str2.GetLength()); +} + +CFX_WideString::~CFX_WideString() {} + +const CFX_WideString& CFX_WideString::operator=(const wchar_t* pStr) { + if (!pStr || !pStr[0]) + clear(); + else + AssignCopy(pStr, FXSYS_wcslen(pStr)); + + return *this; +} + +const CFX_WideString& CFX_WideString::operator=( + const CFX_WideStringC& stringSrc) { + if (stringSrc.IsEmpty()) + clear(); + else + AssignCopy(stringSrc.c_str(), stringSrc.GetLength()); + + return *this; +} + +const CFX_WideString& CFX_WideString::operator=( + const CFX_WideString& stringSrc) { + if (m_pData != stringSrc.m_pData) + m_pData = stringSrc.m_pData; + + return *this; +} + +const CFX_WideString& CFX_WideString::operator+=(const wchar_t* pStr) { + if (pStr) + Concat(pStr, FXSYS_wcslen(pStr)); + + return *this; +} + +const CFX_WideString& CFX_WideString::operator+=(wchar_t ch) { + Concat(&ch, 1); + return *this; +} + +const CFX_WideString& CFX_WideString::operator+=(const CFX_WideString& str) { + if (str.m_pData) + Concat(str.m_pData->m_String, str.m_pData->m_nDataLength); + + return *this; +} + +const CFX_WideString& CFX_WideString::operator+=(const CFX_WideStringC& str) { + if (!str.IsEmpty()) + Concat(str.c_str(), str.GetLength()); + + return *this; +} + +bool CFX_WideString::operator==(const wchar_t* ptr) const { + if (!m_pData) + return !ptr || !ptr[0]; + + if (!ptr) + return m_pData->m_nDataLength == 0; + + return wcslen(ptr) == static_cast<size_t>(m_pData->m_nDataLength) && + wmemcmp(ptr, m_pData->m_String, m_pData->m_nDataLength) == 0; +} + +bool CFX_WideString::operator==(const CFX_WideStringC& str) const { + if (!m_pData) + return str.IsEmpty(); + + return m_pData->m_nDataLength == str.GetLength() && + wmemcmp(m_pData->m_String, str.c_str(), str.GetLength()) == 0; +} + +bool CFX_WideString::operator==(const CFX_WideString& other) const { + if (m_pData == other.m_pData) + return true; + + if (IsEmpty()) + return other.IsEmpty(); + + if (other.IsEmpty()) + return false; + + return other.m_pData->m_nDataLength == m_pData->m_nDataLength && + wmemcmp(other.m_pData->m_String, m_pData->m_String, + m_pData->m_nDataLength) == 0; +} + +bool CFX_WideString::operator<(const CFX_WideString& str) const { + if (m_pData == str.m_pData) + return false; + + int result = + wmemcmp(c_str(), str.c_str(), std::min(GetLength(), str.GetLength())); + return result < 0 || (result == 0 && GetLength() < str.GetLength()); +} + +void CFX_WideString::AssignCopy(const wchar_t* pSrcData, FX_STRSIZE nSrcLen) { + AllocBeforeWrite(nSrcLen); + m_pData->CopyContents(pSrcData, nSrcLen); + m_pData->m_nDataLength = nSrcLen; +} + +void CFX_WideString::ReallocBeforeWrite(FX_STRSIZE nNewLength) { + if (m_pData && m_pData->CanOperateInPlace(nNewLength)) + return; + + if (nNewLength <= 0) { + clear(); + return; + } + + CFX_RetainPtr<StringData> pNewData(StringData::Create(nNewLength)); + if (m_pData) { + FX_STRSIZE nCopyLength = std::min(m_pData->m_nDataLength, nNewLength); + pNewData->CopyContents(m_pData->m_String, nCopyLength); + pNewData->m_nDataLength = nCopyLength; + } else { + pNewData->m_nDataLength = 0; + } + pNewData->m_String[pNewData->m_nDataLength] = 0; + m_pData.Swap(pNewData); +} + +void CFX_WideString::AllocBeforeWrite(FX_STRSIZE nNewLength) { + if (m_pData && m_pData->CanOperateInPlace(nNewLength)) + return; + + if (nNewLength <= 0) { + clear(); + return; + } + + m_pData.Reset(StringData::Create(nNewLength)); +} + +void CFX_WideString::ReleaseBuffer(FX_STRSIZE nNewLength) { + if (!m_pData) + return; + + if (nNewLength == -1) + nNewLength = FXSYS_wcslen(m_pData->m_String); + + nNewLength = std::min(nNewLength, m_pData->m_nAllocLength); + if (nNewLength == 0) { + clear(); + return; + } + + ASSERT(m_pData->m_nRefs == 1); + m_pData->m_nDataLength = nNewLength; + m_pData->m_String[nNewLength] = 0; + if (m_pData->m_nAllocLength - nNewLength >= 32) { + // Over arbitrary threshold, so pay the price to relocate. Force copy to + // always occur by holding a second reference to the string. + CFX_WideString preserve(*this); + ReallocBeforeWrite(nNewLength); + } +} + +void CFX_WideString::Reserve(FX_STRSIZE len) { + GetBuffer(len); +} + +wchar_t* CFX_WideString::GetBuffer(FX_STRSIZE nMinBufLength) { + if (!m_pData) { + if (nMinBufLength == 0) + return nullptr; + + m_pData.Reset(StringData::Create(nMinBufLength)); + m_pData->m_nDataLength = 0; + m_pData->m_String[0] = 0; + return m_pData->m_String; + } + + if (m_pData->CanOperateInPlace(nMinBufLength)) + return m_pData->m_String; + + nMinBufLength = std::max(nMinBufLength, m_pData->m_nDataLength); + if (nMinBufLength == 0) + return nullptr; + + CFX_RetainPtr<StringData> pNewData(StringData::Create(nMinBufLength)); + pNewData->CopyContents(*m_pData); + pNewData->m_nDataLength = m_pData->m_nDataLength; + m_pData.Swap(pNewData); + return m_pData->m_String; +} + +FX_STRSIZE CFX_WideString::Delete(FX_STRSIZE nIndex, FX_STRSIZE nCount) { + if (!m_pData) + return 0; + + if (nIndex < 0) + nIndex = 0; + + FX_STRSIZE nOldLength = m_pData->m_nDataLength; + if (nCount > 0 && nIndex < nOldLength) { + FX_STRSIZE mLength = nIndex + nCount; + if (mLength >= nOldLength) { + m_pData->m_nDataLength = nIndex; + return m_pData->m_nDataLength; + } + ReallocBeforeWrite(nOldLength); + int nCharsToCopy = nOldLength - mLength + 1; + wmemmove(m_pData->m_String + nIndex, m_pData->m_String + mLength, + nCharsToCopy); + m_pData->m_nDataLength = nOldLength - nCount; + } + return m_pData->m_nDataLength; +} + +void CFX_WideString::Concat(const wchar_t* pSrcData, FX_STRSIZE nSrcLen) { + if (!pSrcData || nSrcLen <= 0) + return; + + if (!m_pData) { + m_pData.Reset(StringData::Create(pSrcData, nSrcLen)); + return; + } + + if (m_pData->CanOperateInPlace(m_pData->m_nDataLength + nSrcLen)) { + m_pData->CopyContentsAt(m_pData->m_nDataLength, pSrcData, nSrcLen); + m_pData->m_nDataLength += nSrcLen; + return; + } + + CFX_RetainPtr<StringData> pNewData( + StringData::Create(m_pData->m_nDataLength + nSrcLen)); + pNewData->CopyContents(*m_pData); + pNewData->CopyContentsAt(m_pData->m_nDataLength, pSrcData, nSrcLen); + m_pData.Swap(pNewData); +} + +CFX_ByteString CFX_WideString::UTF8Encode() const { + return FX_UTF8Encode(AsStringC()); +} + +CFX_ByteString CFX_WideString::UTF16LE_Encode() const { + if (!m_pData) { + return CFX_ByteString("\0\0", 2); + } + int len = m_pData->m_nDataLength; + CFX_ByteString result; + char* buffer = result.GetBuffer(len * 2 + 2); + for (int i = 0; i < len; i++) { + buffer[i * 2] = m_pData->m_String[i] & 0xff; + buffer[i * 2 + 1] = m_pData->m_String[i] >> 8; + } + buffer[len * 2] = 0; + buffer[len * 2 + 1] = 0; + result.ReleaseBuffer(len * 2 + 2); + return result; +} + +CFX_WideString CFX_WideString::Mid(FX_STRSIZE nFirst) const { + if (!m_pData) + return CFX_WideString(); + + return Mid(nFirst, m_pData->m_nDataLength - nFirst); +} + +CFX_WideString CFX_WideString::Mid(FX_STRSIZE nFirst, FX_STRSIZE nCount) const { + if (!m_pData) + return CFX_WideString(); + + nFirst = pdfium::clamp(nFirst, 0, m_pData->m_nDataLength); + nCount = pdfium::clamp(nCount, 0, m_pData->m_nDataLength - nFirst); + if (nCount == 0) + return CFX_WideString(); + + if (nFirst == 0 && nCount == m_pData->m_nDataLength) + return *this; + + CFX_WideString dest; + AllocCopy(dest, nCount, nFirst); + return dest; +} + +void CFX_WideString::AllocCopy(CFX_WideString& dest, + FX_STRSIZE nCopyLen, + FX_STRSIZE nCopyIndex) const { + if (nCopyLen <= 0) + return; + + CFX_RetainPtr<StringData> pNewData( + StringData::Create(m_pData->m_String + nCopyIndex, nCopyLen)); + dest.m_pData.Swap(pNewData); +} + +bool CFX_WideString::TryVSWPrintf(FX_STRSIZE size, + const wchar_t* pFormat, + va_list argList) { + GetBuffer(size); + if (!m_pData) + return true; + + // In the following two calls, there's always space in the buffer for + // a terminating NUL that's not included in nMaxLen. + // For vswprintf(), MSAN won't untaint the buffer on a truncated write's + // -1 return code even though the buffer is written. Probably just as well + // not to trust the vendor's implementation to write anything anyways. + // See https://crbug.com/705912. + memset(m_pData->m_String, 0, (size + 1) * sizeof(wchar_t)); + int ret = vswprintf(m_pData->m_String, size + 1, pFormat, argList); + ReleaseBuffer(); + return ret >= 0 || m_pData->m_String[size - 1] == 0; +} + +void CFX_WideString::FormatV(const wchar_t* pFormat, va_list argList) { + va_list argListCopy; + FX_VA_COPY(argListCopy, argList); + FX_STRSIZE nMaxLen = vswprintf(nullptr, 0, pFormat, argListCopy); + va_end(argListCopy); + if (nMaxLen <= 0) { + nMaxLen = GuessSizeForVSWPrintf(pFormat, argListCopy); + if (nMaxLen <= 0) + return; + } + while (nMaxLen < 32 * 1024) { + FX_VA_COPY(argListCopy, argList); + bool bRetryPointless = TryVSWPrintf(nMaxLen, pFormat, argListCopy); + va_end(argListCopy); + if (bRetryPointless) + break; + nMaxLen *= 2; + } +} + +void CFX_WideString::Format(const wchar_t* pFormat, ...) { + va_list argList; + va_start(argList, pFormat); + FormatV(pFormat, argList); + va_end(argList); +} + +FX_STRSIZE CFX_WideString::Insert(FX_STRSIZE nIndex, wchar_t ch) { + FX_STRSIZE nNewLength = m_pData ? m_pData->m_nDataLength : 0; + nIndex = std::max(nIndex, 0); + nIndex = std::min(nIndex, nNewLength); + nNewLength++; + + ReallocBeforeWrite(nNewLength); + wmemmove(m_pData->m_String + nIndex + 1, m_pData->m_String + nIndex, + nNewLength - nIndex); + m_pData->m_String[nIndex] = ch; + m_pData->m_nDataLength = nNewLength; + return nNewLength; +} + +CFX_WideString CFX_WideString::Right(FX_STRSIZE nCount) const { + if (!m_pData) + return CFX_WideString(); + + nCount = std::max(nCount, 0); + if (nCount >= m_pData->m_nDataLength) + return *this; + + CFX_WideString dest; + AllocCopy(dest, nCount, m_pData->m_nDataLength - nCount); + return dest; +} + +CFX_WideString CFX_WideString::Left(FX_STRSIZE nCount) const { + if (!m_pData) + return CFX_WideString(); + + nCount = std::max(nCount, 0); + if (nCount >= m_pData->m_nDataLength) + return *this; + + CFX_WideString dest; + AllocCopy(dest, nCount, 0); + return dest; +} + +FX_STRSIZE CFX_WideString::Find(wchar_t ch, FX_STRSIZE nStart) const { + if (!m_pData) + return -1; + + if (nStart < 0 || nStart >= m_pData->m_nDataLength) + return -1; + + const wchar_t* pStr = + wmemchr(m_pData->m_String + nStart, ch, m_pData->m_nDataLength - nStart); + return pStr ? pStr - m_pData->m_String : -1; +} + +FX_STRSIZE CFX_WideString::Find(const CFX_WideStringC& pSub, + FX_STRSIZE nStart) const { + if (!m_pData) + return -1; + + FX_STRSIZE nLength = m_pData->m_nDataLength; + if (nStart > nLength) + return -1; + + const wchar_t* pStr = + FX_wcsstr(m_pData->m_String + nStart, m_pData->m_nDataLength - nStart, + pSub.c_str(), pSub.GetLength()); + return pStr ? (int)(pStr - m_pData->m_String) : -1; +} + +void CFX_WideString::MakeLower() { + if (!m_pData) + return; + + ReallocBeforeWrite(m_pData->m_nDataLength); + FXSYS_wcslwr(m_pData->m_String); +} + +void CFX_WideString::MakeUpper() { + if (!m_pData) + return; + + ReallocBeforeWrite(m_pData->m_nDataLength); + FXSYS_wcsupr(m_pData->m_String); +} + +FX_STRSIZE CFX_WideString::Remove(wchar_t chRemove) { + if (!m_pData || m_pData->m_nDataLength < 1) + return 0; + + wchar_t* pstrSource = m_pData->m_String; + wchar_t* pstrEnd = m_pData->m_String + m_pData->m_nDataLength; + while (pstrSource < pstrEnd) { + if (*pstrSource == chRemove) + break; + pstrSource++; + } + if (pstrSource == pstrEnd) + return 0; + + ptrdiff_t copied = pstrSource - m_pData->m_String; + ReallocBeforeWrite(m_pData->m_nDataLength); + pstrSource = m_pData->m_String + copied; + pstrEnd = m_pData->m_String + m_pData->m_nDataLength; + + wchar_t* pstrDest = pstrSource; + while (pstrSource < pstrEnd) { + if (*pstrSource != chRemove) { + *pstrDest = *pstrSource; + pstrDest++; + } + pstrSource++; + } + + *pstrDest = 0; + FX_STRSIZE nCount = (FX_STRSIZE)(pstrSource - pstrDest); + m_pData->m_nDataLength -= nCount; + return nCount; +} + +FX_STRSIZE CFX_WideString::Replace(const CFX_WideStringC& pOld, + const CFX_WideStringC& pNew) { + if (!m_pData || pOld.IsEmpty()) + return 0; + + FX_STRSIZE nSourceLen = pOld.GetLength(); + FX_STRSIZE nReplacementLen = pNew.GetLength(); + FX_STRSIZE nCount = 0; + const wchar_t* pStart = m_pData->m_String; + wchar_t* pEnd = m_pData->m_String + m_pData->m_nDataLength; + while (1) { + const wchar_t* pTarget = FX_wcsstr(pStart, (FX_STRSIZE)(pEnd - pStart), + pOld.c_str(), nSourceLen); + if (!pTarget) + break; + + nCount++; + pStart = pTarget + nSourceLen; + } + if (nCount == 0) + return 0; + + FX_STRSIZE nNewLength = + m_pData->m_nDataLength + (nReplacementLen - nSourceLen) * nCount; + + if (nNewLength == 0) { + clear(); + return nCount; + } + + CFX_RetainPtr<StringData> pNewData(StringData::Create(nNewLength)); + pStart = m_pData->m_String; + wchar_t* pDest = pNewData->m_String; + for (FX_STRSIZE i = 0; i < nCount; i++) { + const wchar_t* pTarget = FX_wcsstr(pStart, (FX_STRSIZE)(pEnd - pStart), + pOld.c_str(), nSourceLen); + wmemcpy(pDest, pStart, pTarget - pStart); + pDest += pTarget - pStart; + wmemcpy(pDest, pNew.c_str(), pNew.GetLength()); + pDest += pNew.GetLength(); + pStart = pTarget + nSourceLen; + } + wmemcpy(pDest, pStart, pEnd - pStart); + m_pData.Swap(pNewData); + return nCount; +} + +void CFX_WideString::SetAt(FX_STRSIZE nIndex, wchar_t ch) { + if (!m_pData) { + return; + } + ASSERT(nIndex >= 0); + ASSERT(nIndex < m_pData->m_nDataLength); + ReallocBeforeWrite(m_pData->m_nDataLength); + m_pData->m_String[nIndex] = ch; +} + +// static +CFX_WideString CFX_WideString::FromLocal(const CFX_ByteStringC& str) { + return FromCodePage(str, 0); +} + +// static +CFX_WideString CFX_WideString::FromCodePage(const CFX_ByteStringC& str, + uint16_t codepage) { + return CFX_CharMap::GetWideString(codepage, str); +} + +// static +CFX_WideString CFX_WideString::FromUTF8(const CFX_ByteStringC& str) { + if (str.IsEmpty()) + return CFX_WideString(); + + CFX_UTF8Decoder decoder; + for (FX_STRSIZE i = 0; i < str.GetLength(); i++) + decoder.Input(str[i]); + + return CFX_WideString(decoder.GetResult()); +} + +// static +CFX_WideString CFX_WideString::FromUTF16LE(const unsigned short* wstr, + FX_STRSIZE wlen) { + if (!wstr || 0 == wlen) { + return CFX_WideString(); + } + + CFX_WideString result; + wchar_t* buf = result.GetBuffer(wlen); + for (int i = 0; i < wlen; i++) { + buf[i] = wstr[i]; + } + result.ReleaseBuffer(wlen); + return result; +} + +int CFX_WideString::Compare(const wchar_t* lpsz) const { + if (m_pData) + return FXSYS_wcscmp(m_pData->m_String, lpsz); + return (!lpsz || lpsz[0] == 0) ? 0 : -1; +} + +int CFX_WideString::Compare(const CFX_WideString& str) const { + if (!m_pData) { + if (!str.m_pData) { + return 0; + } + return -1; + } + if (!str.m_pData) { + return 1; + } + int this_len = m_pData->m_nDataLength; + int that_len = str.m_pData->m_nDataLength; + int min_len = this_len < that_len ? this_len : that_len; + for (int i = 0; i < min_len; i++) { + if (m_pData->m_String[i] < str.m_pData->m_String[i]) { + return -1; + } + if (m_pData->m_String[i] > str.m_pData->m_String[i]) { + return 1; + } + } + if (this_len < that_len) { + return -1; + } + if (this_len > that_len) { + return 1; + } + return 0; +} + +int CFX_WideString::CompareNoCase(const wchar_t* lpsz) const { + if (!m_pData) { + return (!lpsz || lpsz[0] == 0) ? 0 : -1; + } + return FXSYS_wcsicmp(m_pData->m_String, lpsz); +} + +FX_STRSIZE CFX_WideString::WStringLength(const unsigned short* str) { + FX_STRSIZE len = 0; + if (str) + while (str[len]) + len++; + return len; +} + +void CFX_WideString::TrimRight(const CFX_WideStringC& pTargets) { + if (IsEmpty() || pTargets.IsEmpty()) + return; + + FX_STRSIZE pos = GetLength(); + while (pos && pTargets.Find(m_pData->m_String[pos - 1]) != -1) + pos--; + + if (pos < m_pData->m_nDataLength) { + ReallocBeforeWrite(m_pData->m_nDataLength); + m_pData->m_String[pos] = 0; + m_pData->m_nDataLength = pos; + } +} + +void CFX_WideString::TrimRight(wchar_t chTarget) { + wchar_t str[2] = {chTarget, 0}; + TrimRight(str); +} + +void CFX_WideString::TrimRight() { + TrimRight(L"\x09\x0a\x0b\x0c\x0d\x20"); +} + +void CFX_WideString::TrimLeft(const CFX_WideStringC& pTargets) { + if (!m_pData || pTargets.IsEmpty()) + return; + + FX_STRSIZE len = GetLength(); + if (len < 1) + return; + + FX_STRSIZE pos = 0; + while (pos < len) { + FX_STRSIZE i = 0; + while (i < pTargets.GetLength() && + pTargets.CharAt(i) != m_pData->m_String[pos]) { + i++; + } + if (i == pTargets.GetLength()) { + break; + } + pos++; + } + if (pos) { + ReallocBeforeWrite(len); + FX_STRSIZE nDataLength = len - pos; + FXSYS_memmove(m_pData->m_String, m_pData->m_String + pos, + (nDataLength + 1) * sizeof(wchar_t)); + m_pData->m_nDataLength = nDataLength; + } +} + +void CFX_WideString::TrimLeft(wchar_t chTarget) { + wchar_t str[2] = {chTarget, 0}; + TrimLeft(str); +} + +void CFX_WideString::TrimLeft() { + TrimLeft(L"\x09\x0a\x0b\x0c\x0d\x20"); +} +float FX_wtof(const wchar_t* str, int len) { + if (len == 0) { + return 0.0; + } + int cc = 0; + bool bNegative = false; + if (str[0] == '+') { + cc++; + } else if (str[0] == '-') { + bNegative = true; + cc++; + } + int integer = 0; + while (cc < len) { + if (str[cc] == '.') { + break; + } + integer = integer * 10 + FXSYS_toDecimalDigit(str[cc]); + cc++; + } + float fraction = 0; + if (str[cc] == '.') { + cc++; + float scale = 0.1f; + while (cc < len) { + fraction += scale * FXSYS_toDecimalDigit(str[cc]); + scale *= 0.1f; + cc++; + } + } + fraction += (float)integer; + return bNegative ? -fraction : fraction; +} + +int CFX_WideString::GetInteger() const { + return m_pData ? FXSYS_wtoi(m_pData->m_String) : 0; +} + +float CFX_WideString::GetFloat() const { + return m_pData ? FX_wtof(m_pData->m_String, m_pData->m_nDataLength) : 0.0f; +} + +// static +CFX_ByteString CFX_CharMap::GetByteString(uint16_t codepage, + const CFX_WideStringC& wstr) { + ASSERT(IsValidCodePage(codepage)); + int src_len = wstr.GetLength(); + int dest_len = FXSYS_WideCharToMultiByte(codepage, 0, wstr.c_str(), src_len, + nullptr, 0, nullptr, nullptr); + CFX_ByteString bstr; + if (dest_len) { + char* dest_buf = bstr.GetBuffer(dest_len); + FXSYS_WideCharToMultiByte(codepage, 0, wstr.c_str(), src_len, dest_buf, + dest_len, nullptr, nullptr); + bstr.ReleaseBuffer(dest_len); + } + return bstr; +} + +// static +CFX_WideString CFX_CharMap::GetWideString(uint16_t codepage, + const CFX_ByteStringC& bstr) { + ASSERT(IsValidCodePage(codepage)); + int src_len = bstr.GetLength(); + int dest_len = + FXSYS_MultiByteToWideChar(codepage, 0, bstr.c_str(), src_len, nullptr, 0); + CFX_WideString wstr; + if (dest_len) { + wchar_t* dest_buf = wstr.GetBuffer(dest_len); + FXSYS_MultiByteToWideChar(codepage, 0, bstr.c_str(), src_len, dest_buf, + dest_len); + wstr.ReleaseBuffer(dest_len); + } + return wstr; +} |