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/widestring.h"
8
9 #include <stddef.h>
10
11 #include <algorithm>
12 #include <cctype>
13 #include <cwctype>
14
15 #include "core/fxcrt/cfx_utf8decoder.h"
16 #include "core/fxcrt/fx_codepage.h"
17 #include "core/fxcrt/fx_extension.h"
18 #include "core/fxcrt/fx_safe_types.h"
19 #include "core/fxcrt/string_pool_template.h"
20 #include "third_party/base/numerics/safe_math.h"
21 #include "third_party/base/stl_util.h"
22
23 template class fxcrt::StringDataTemplate<wchar_t>;
24 template class fxcrt::StringViewTemplate<wchar_t>;
25 template class fxcrt::StringPoolTemplate<WideString>;
26 template struct std::hash<WideString>;
27
28 #define FORCE_ANSI 0x10000
29 #define FORCE_UNICODE 0x20000
30 #define FORCE_INT64 0x40000
31
32 namespace {
33
34 constexpr wchar_t kWideTrimChars[] = L"\x09\x0a\x0b\x0c\x0d\x20";
35
FX_wcsstr(const wchar_t * haystack,int haystack_len,const wchar_t * needle,int needle_len)36 const wchar_t* FX_wcsstr(const wchar_t* haystack,
37 int haystack_len,
38 const wchar_t* needle,
39 int needle_len) {
40 if (needle_len > haystack_len || needle_len == 0) {
41 return nullptr;
42 }
43 const wchar_t* end_ptr = haystack + haystack_len - needle_len;
44 while (haystack <= end_ptr) {
45 int i = 0;
46 while (1) {
47 if (haystack[i] != needle[i]) {
48 break;
49 }
50 i++;
51 if (i == needle_len) {
52 return haystack;
53 }
54 }
55 haystack++;
56 }
57 return nullptr;
58 }
59
GuessSizeForVSWPrintf(const wchar_t * pFormat,va_list argList)60 Optional<size_t> GuessSizeForVSWPrintf(const wchar_t* pFormat,
61 va_list argList) {
62 size_t nMaxLen = 0;
63 for (const wchar_t* pStr = pFormat; *pStr != 0; pStr++) {
64 if (*pStr != '%' || *(pStr = pStr + 1) == '%') {
65 ++nMaxLen;
66 continue;
67 }
68 int nItemLen = 0;
69 int nWidth = 0;
70 for (; *pStr != 0; pStr++) {
71 if (*pStr == '#') {
72 nMaxLen += 2;
73 } else if (*pStr == '*') {
74 nWidth = va_arg(argList, int);
75 } else if (*pStr != '-' && *pStr != '+' && *pStr != '0' && *pStr != ' ') {
76 break;
77 }
78 }
79 if (nWidth == 0) {
80 nWidth = FXSYS_wtoi(pStr);
81 while (std::iswdigit(*pStr))
82 ++pStr;
83 }
84 if (nWidth < 0 || nWidth > 128 * 1024)
85 return Optional<size_t>();
86 int nPrecision = 0;
87 if (*pStr == '.') {
88 pStr++;
89 if (*pStr == '*') {
90 nPrecision = va_arg(argList, int);
91 pStr++;
92 } else {
93 nPrecision = FXSYS_wtoi(pStr);
94 while (std::iswdigit(*pStr))
95 ++pStr;
96 }
97 }
98 if (nPrecision < 0 || nPrecision > 128 * 1024)
99 return Optional<size_t>();
100 int nModifier = 0;
101 if (*pStr == L'I' && *(pStr + 1) == L'6' && *(pStr + 2) == L'4') {
102 pStr += 3;
103 nModifier = FORCE_INT64;
104 } else {
105 switch (*pStr) {
106 case 'h':
107 nModifier = FORCE_ANSI;
108 pStr++;
109 break;
110 case 'l':
111 nModifier = FORCE_UNICODE;
112 pStr++;
113 break;
114 case 'F':
115 case 'N':
116 case 'L':
117 pStr++;
118 break;
119 }
120 }
121 switch (*pStr | nModifier) {
122 case 'c':
123 case 'C':
124 nItemLen = 2;
125 va_arg(argList, int);
126 break;
127 case 'c' | FORCE_ANSI:
128 case 'C' | FORCE_ANSI:
129 nItemLen = 2;
130 va_arg(argList, int);
131 break;
132 case 'c' | FORCE_UNICODE:
133 case 'C' | FORCE_UNICODE:
134 nItemLen = 2;
135 va_arg(argList, int);
136 break;
137 case 's': {
138 const wchar_t* pstrNextArg = va_arg(argList, const wchar_t*);
139 if (pstrNextArg) {
140 nItemLen = wcslen(pstrNextArg);
141 if (nItemLen < 1) {
142 nItemLen = 1;
143 }
144 } else {
145 nItemLen = 6;
146 }
147 } break;
148 case 'S': {
149 const char* pstrNextArg = va_arg(argList, const char*);
150 if (pstrNextArg) {
151 nItemLen = strlen(pstrNextArg);
152 if (nItemLen < 1) {
153 nItemLen = 1;
154 }
155 } else {
156 nItemLen = 6;
157 }
158 } break;
159 case 's' | FORCE_ANSI:
160 case 'S' | FORCE_ANSI: {
161 const char* pstrNextArg = va_arg(argList, const char*);
162 if (pstrNextArg) {
163 nItemLen = strlen(pstrNextArg);
164 if (nItemLen < 1) {
165 nItemLen = 1;
166 }
167 } else {
168 nItemLen = 6;
169 }
170 } break;
171 case 's' | FORCE_UNICODE:
172 case 'S' | FORCE_UNICODE: {
173 const wchar_t* pstrNextArg = va_arg(argList, wchar_t*);
174 if (pstrNextArg) {
175 nItemLen = wcslen(pstrNextArg);
176 if (nItemLen < 1) {
177 nItemLen = 1;
178 }
179 } else {
180 nItemLen = 6;
181 }
182 } break;
183 }
184 if (nItemLen != 0) {
185 if (nPrecision != 0 && nItemLen > nPrecision) {
186 nItemLen = nPrecision;
187 }
188 if (nItemLen < nWidth) {
189 nItemLen = nWidth;
190 }
191 } else {
192 switch (*pStr) {
193 case 'd':
194 case 'i':
195 case 'u':
196 case 'x':
197 case 'X':
198 case 'o':
199 if (nModifier & FORCE_INT64) {
200 va_arg(argList, int64_t);
201 } else {
202 va_arg(argList, int);
203 }
204 nItemLen = 32;
205 if (nItemLen < nWidth + nPrecision) {
206 nItemLen = nWidth + nPrecision;
207 }
208 break;
209 case 'a':
210 case 'A':
211 case 'e':
212 case 'E':
213 case 'g':
214 case 'G':
215 va_arg(argList, double);
216 nItemLen = 128;
217 if (nItemLen < nWidth + nPrecision) {
218 nItemLen = nWidth + nPrecision;
219 }
220 break;
221 case 'f':
222 if (nWidth + nPrecision > 100) {
223 nItemLen = nPrecision + nWidth + 128;
224 } else {
225 double f;
226 char pszTemp[256];
227 f = va_arg(argList, double);
228 FXSYS_snprintf(pszTemp, sizeof(pszTemp), "%*.*f", nWidth,
229 nPrecision + 6, f);
230 nItemLen = strlen(pszTemp);
231 }
232 break;
233 case 'p':
234 va_arg(argList, void*);
235 nItemLen = 32;
236 if (nItemLen < nWidth + nPrecision) {
237 nItemLen = nWidth + nPrecision;
238 }
239 break;
240 case 'n':
241 va_arg(argList, int*);
242 break;
243 }
244 }
245 nMaxLen += nItemLen;
246 }
247 nMaxLen += 32; // Fudge factor.
248 return Optional<size_t>(nMaxLen);
249 }
250
251 // Returns string unless we ran out of space.
TryVSWPrintf(size_t size,const wchar_t * pFormat,va_list argList)252 Optional<WideString> TryVSWPrintf(size_t size,
253 const wchar_t* pFormat,
254 va_list argList) {
255 WideString str;
256 wchar_t* buffer = str.GetBuffer(size);
257
258 // In the following two calls, there's always space in the buffer for
259 // a terminating NUL that's not included in nMaxLen.
260 // For vswprintf(), MSAN won't untaint the buffer on a truncated write's
261 // -1 return code even though the buffer is written. Probably just as well
262 // not to trust the vendor's implementation to write anything anyways.
263 // See https://crbug.com/705912.
264 memset(buffer, 0, (size + 1) * sizeof(wchar_t));
265 int ret = vswprintf(buffer, size + 1, pFormat, argList);
266
267 bool bSufficientBuffer = ret >= 0 || buffer[size - 1] == 0;
268 if (!bSufficientBuffer)
269 return {};
270
271 str.ReleaseBuffer(str.GetStringLength());
272 return {str};
273 }
274
275 #ifndef NDEBUG
IsValidWideCodePage(uint16_t codepage)276 bool IsValidWideCodePage(uint16_t codepage) {
277 switch (codepage) {
278 case FX_CODEPAGE_DefANSI:
279 case FX_CODEPAGE_ShiftJIS:
280 case FX_CODEPAGE_ChineseSimplified:
281 case FX_CODEPAGE_Hangul:
282 case FX_CODEPAGE_ChineseTraditional:
283 return true;
284 default:
285 return false;
286 }
287 }
288 #endif
289
GetWideString(uint16_t codepage,const ByteStringView & bstr)290 WideString GetWideString(uint16_t codepage, const ByteStringView& bstr) {
291 #ifndef NDEBUG
292 ASSERT(IsValidWideCodePage(codepage));
293 #endif
294
295 int src_len = bstr.GetLength();
296 int dest_len = FXSYS_MultiByteToWideChar(
297 codepage, 0, bstr.unterminated_c_str(), src_len, nullptr, 0);
298 if (!dest_len)
299 return WideString();
300
301 WideString wstr;
302 wchar_t* dest_buf = wstr.GetBuffer(dest_len);
303 FXSYS_MultiByteToWideChar(codepage, 0, bstr.unterminated_c_str(), src_len,
304 dest_buf, dest_len);
305 wstr.ReleaseBuffer(dest_len);
306 return wstr;
307 }
308
309 } // namespace
310
311 namespace fxcrt {
312
313 static_assert(sizeof(WideString) <= sizeof(wchar_t*),
314 "Strings must not require more space than pointers");
315
316 // static
FormatV(const wchar_t * format,va_list argList)317 WideString WideString::FormatV(const wchar_t* format, va_list argList) {
318 va_list argListCopy;
319 va_copy(argListCopy, argList);
320 int maxLen = vswprintf(nullptr, 0, format, argListCopy);
321 va_end(argListCopy);
322
323 if (maxLen <= 0) {
324 va_copy(argListCopy, argList);
325 auto guess = GuessSizeForVSWPrintf(format, argListCopy);
326 va_end(argListCopy);
327
328 if (!guess.has_value())
329 return L"";
330 maxLen = pdfium::base::checked_cast<int>(guess.value());
331 }
332
333 while (maxLen < 32 * 1024) {
334 va_copy(argListCopy, argList);
335 Optional<WideString> ret =
336 TryVSWPrintf(static_cast<size_t>(maxLen), format, argListCopy);
337 va_end(argListCopy);
338
339 if (ret)
340 return *ret;
341 maxLen *= 2;
342 }
343 return L"";
344 }
345
346 // static
Format(const wchar_t * pFormat,...)347 WideString WideString::Format(const wchar_t* pFormat, ...) {
348 va_list argList;
349 va_start(argList, pFormat);
350 WideString ret = FormatV(pFormat, argList);
351 va_end(argList);
352 return ret;
353 }
354
WideString()355 WideString::WideString() {}
356
WideString(const WideString & other)357 WideString::WideString(const WideString& other) : m_pData(other.m_pData) {}
358
WideString(WideString && other)359 WideString::WideString(WideString&& other) noexcept {
360 m_pData.Swap(other.m_pData);
361 }
362
WideString(const wchar_t * pStr,size_t nLen)363 WideString::WideString(const wchar_t* pStr, size_t nLen) {
364 if (nLen)
365 m_pData.Reset(StringData::Create(pStr, nLen));
366 }
367
WideString(wchar_t ch)368 WideString::WideString(wchar_t ch) {
369 m_pData.Reset(StringData::Create(1));
370 m_pData->m_String[0] = ch;
371 }
372
WideString(const wchar_t * ptr)373 WideString::WideString(const wchar_t* ptr)
374 : WideString(ptr, ptr ? wcslen(ptr) : 0) {}
375
WideString(const WideStringView & stringSrc)376 WideString::WideString(const WideStringView& stringSrc) {
377 if (!stringSrc.IsEmpty()) {
378 m_pData.Reset(StringData::Create(stringSrc.unterminated_c_str(),
379 stringSrc.GetLength()));
380 }
381 }
382
WideString(const WideStringView & str1,const WideStringView & str2)383 WideString::WideString(const WideStringView& str1, const WideStringView& str2) {
384 FX_SAFE_SIZE_T nSafeLen = str1.GetLength();
385 nSafeLen += str2.GetLength();
386
387 size_t nNewLen = nSafeLen.ValueOrDie();
388 if (nNewLen == 0)
389 return;
390
391 m_pData.Reset(StringData::Create(nNewLen));
392 m_pData->CopyContents(str1.unterminated_c_str(), str1.GetLength());
393 m_pData->CopyContentsAt(str1.GetLength(), str2.unterminated_c_str(),
394 str2.GetLength());
395 }
396
WideString(const std::initializer_list<WideStringView> & list)397 WideString::WideString(const std::initializer_list<WideStringView>& list) {
398 FX_SAFE_SIZE_T nSafeLen = 0;
399 for (const auto& item : list)
400 nSafeLen += item.GetLength();
401
402 size_t nNewLen = nSafeLen.ValueOrDie();
403 if (nNewLen == 0)
404 return;
405
406 m_pData.Reset(StringData::Create(nNewLen));
407
408 size_t nOffset = 0;
409 for (const auto& item : list) {
410 m_pData->CopyContentsAt(nOffset, item.unterminated_c_str(),
411 item.GetLength());
412 nOffset += item.GetLength();
413 }
414 }
415
~WideString()416 WideString::~WideString() {}
417
operator =(const wchar_t * pStr)418 const WideString& WideString::operator=(const wchar_t* pStr) {
419 if (!pStr || !pStr[0])
420 clear();
421 else
422 AssignCopy(pStr, wcslen(pStr));
423
424 return *this;
425 }
426
operator =(const WideStringView & stringSrc)427 const WideString& WideString::operator=(const WideStringView& stringSrc) {
428 if (stringSrc.IsEmpty())
429 clear();
430 else
431 AssignCopy(stringSrc.unterminated_c_str(), stringSrc.GetLength());
432
433 return *this;
434 }
435
operator =(const WideString & stringSrc)436 const WideString& WideString::operator=(const WideString& stringSrc) {
437 if (m_pData != stringSrc.m_pData)
438 m_pData = stringSrc.m_pData;
439
440 return *this;
441 }
442
operator +=(const wchar_t * pStr)443 const WideString& WideString::operator+=(const wchar_t* pStr) {
444 if (pStr)
445 Concat(pStr, wcslen(pStr));
446
447 return *this;
448 }
449
operator +=(wchar_t ch)450 const WideString& WideString::operator+=(wchar_t ch) {
451 Concat(&ch, 1);
452 return *this;
453 }
454
operator +=(const WideString & str)455 const WideString& WideString::operator+=(const WideString& str) {
456 if (str.m_pData)
457 Concat(str.m_pData->m_String, str.m_pData->m_nDataLength);
458
459 return *this;
460 }
461
operator +=(const WideStringView & str)462 const WideString& WideString::operator+=(const WideStringView& str) {
463 if (!str.IsEmpty())
464 Concat(str.unterminated_c_str(), str.GetLength());
465
466 return *this;
467 }
468
operator ==(const wchar_t * ptr) const469 bool WideString::operator==(const wchar_t* ptr) const {
470 if (!m_pData)
471 return !ptr || !ptr[0];
472
473 if (!ptr)
474 return m_pData->m_nDataLength == 0;
475
476 return wcslen(ptr) == m_pData->m_nDataLength &&
477 wmemcmp(ptr, m_pData->m_String, m_pData->m_nDataLength) == 0;
478 }
479
operator ==(const WideStringView & str) const480 bool WideString::operator==(const WideStringView& str) const {
481 if (!m_pData)
482 return str.IsEmpty();
483
484 return m_pData->m_nDataLength == str.GetLength() &&
485 wmemcmp(m_pData->m_String, str.unterminated_c_str(),
486 str.GetLength()) == 0;
487 }
488
operator ==(const WideString & other) const489 bool WideString::operator==(const WideString& other) const {
490 if (m_pData == other.m_pData)
491 return true;
492
493 if (IsEmpty())
494 return other.IsEmpty();
495
496 if (other.IsEmpty())
497 return false;
498
499 return other.m_pData->m_nDataLength == m_pData->m_nDataLength &&
500 wmemcmp(other.m_pData->m_String, m_pData->m_String,
501 m_pData->m_nDataLength) == 0;
502 }
503
operator <(const wchar_t * ptr) const504 bool WideString::operator<(const wchar_t* ptr) const {
505 return Compare(ptr) < 0;
506 }
507
operator <(const WideStringView & str) const508 bool WideString::operator<(const WideStringView& str) const {
509 if (!m_pData && !str.unterminated_c_str())
510 return false;
511 if (c_str() == str.unterminated_c_str())
512 return false;
513
514 size_t len = GetLength();
515 size_t other_len = str.GetLength();
516 int result =
517 wmemcmp(c_str(), str.unterminated_c_str(), std::min(len, other_len));
518 return result < 0 || (result == 0 && len < other_len);
519 }
520
operator <(const WideString & other) const521 bool WideString::operator<(const WideString& other) const {
522 return Compare(other) < 0;
523 }
524
AssignCopy(const wchar_t * pSrcData,size_t nSrcLen)525 void WideString::AssignCopy(const wchar_t* pSrcData, size_t nSrcLen) {
526 AllocBeforeWrite(nSrcLen);
527 m_pData->CopyContents(pSrcData, nSrcLen);
528 m_pData->m_nDataLength = nSrcLen;
529 }
530
ReallocBeforeWrite(size_t nNewLength)531 void WideString::ReallocBeforeWrite(size_t nNewLength) {
532 if (m_pData && m_pData->CanOperateInPlace(nNewLength))
533 return;
534
535 if (nNewLength == 0) {
536 clear();
537 return;
538 }
539
540 RetainPtr<StringData> pNewData(StringData::Create(nNewLength));
541 if (m_pData) {
542 size_t nCopyLength = std::min(m_pData->m_nDataLength, nNewLength);
543 pNewData->CopyContents(m_pData->m_String, nCopyLength);
544 pNewData->m_nDataLength = nCopyLength;
545 } else {
546 pNewData->m_nDataLength = 0;
547 }
548 pNewData->m_String[pNewData->m_nDataLength] = 0;
549 m_pData.Swap(pNewData);
550 }
551
AllocBeforeWrite(size_t nNewLength)552 void WideString::AllocBeforeWrite(size_t nNewLength) {
553 if (m_pData && m_pData->CanOperateInPlace(nNewLength))
554 return;
555
556 if (nNewLength == 0) {
557 clear();
558 return;
559 }
560
561 m_pData.Reset(StringData::Create(nNewLength));
562 }
563
ReleaseBuffer(size_t nNewLength)564 void WideString::ReleaseBuffer(size_t nNewLength) {
565 if (!m_pData)
566 return;
567
568 nNewLength = std::min(nNewLength, m_pData->m_nAllocLength);
569 if (nNewLength == 0) {
570 clear();
571 return;
572 }
573
574 ASSERT(m_pData->m_nRefs == 1);
575 m_pData->m_nDataLength = nNewLength;
576 m_pData->m_String[nNewLength] = 0;
577 if (m_pData->m_nAllocLength - nNewLength >= 32) {
578 // Over arbitrary threshold, so pay the price to relocate. Force copy to
579 // always occur by holding a second reference to the string.
580 WideString preserve(*this);
581 ReallocBeforeWrite(nNewLength);
582 }
583 }
584
Reserve(size_t len)585 void WideString::Reserve(size_t len) {
586 GetBuffer(len);
587 }
588
GetBuffer(size_t nMinBufLength)589 wchar_t* WideString::GetBuffer(size_t nMinBufLength) {
590 if (!m_pData) {
591 if (nMinBufLength == 0)
592 return nullptr;
593
594 m_pData.Reset(StringData::Create(nMinBufLength));
595 m_pData->m_nDataLength = 0;
596 m_pData->m_String[0] = 0;
597 return m_pData->m_String;
598 }
599
600 if (m_pData->CanOperateInPlace(nMinBufLength))
601 return m_pData->m_String;
602
603 nMinBufLength = std::max(nMinBufLength, m_pData->m_nDataLength);
604 if (nMinBufLength == 0)
605 return nullptr;
606
607 RetainPtr<StringData> pNewData(StringData::Create(nMinBufLength));
608 pNewData->CopyContents(*m_pData);
609 pNewData->m_nDataLength = m_pData->m_nDataLength;
610 m_pData.Swap(pNewData);
611 return m_pData->m_String;
612 }
613
Delete(size_t index,size_t count)614 size_t WideString::Delete(size_t index, size_t count) {
615 if (!m_pData)
616 return 0;
617
618 size_t old_length = m_pData->m_nDataLength;
619 if (count == 0 ||
620 index != pdfium::clamp(index, static_cast<size_t>(0), old_length))
621 return old_length;
622
623 size_t removal_length = index + count;
624 if (removal_length > old_length)
625 return old_length;
626
627 ReallocBeforeWrite(old_length);
628 size_t chars_to_copy = old_length - removal_length + 1;
629 wmemmove(m_pData->m_String + index, m_pData->m_String + removal_length,
630 chars_to_copy);
631 m_pData->m_nDataLength = old_length - count;
632 return m_pData->m_nDataLength;
633 }
634
Concat(const wchar_t * pSrcData,size_t nSrcLen)635 void WideString::Concat(const wchar_t* pSrcData, size_t nSrcLen) {
636 if (!pSrcData || nSrcLen == 0)
637 return;
638
639 if (!m_pData) {
640 m_pData.Reset(StringData::Create(pSrcData, nSrcLen));
641 return;
642 }
643
644 if (m_pData->CanOperateInPlace(m_pData->m_nDataLength + nSrcLen)) {
645 m_pData->CopyContentsAt(m_pData->m_nDataLength, pSrcData, nSrcLen);
646 m_pData->m_nDataLength += nSrcLen;
647 return;
648 }
649
650 RetainPtr<StringData> pNewData(
651 StringData::Create(m_pData->m_nDataLength + nSrcLen));
652 pNewData->CopyContents(*m_pData);
653 pNewData->CopyContentsAt(m_pData->m_nDataLength, pSrcData, nSrcLen);
654 m_pData.Swap(pNewData);
655 }
656
UTF8Encode() const657 ByteString WideString::UTF8Encode() const {
658 return FX_UTF8Encode(AsStringView());
659 }
660
UTF16LE_Encode() const661 ByteString WideString::UTF16LE_Encode() const {
662 if (!m_pData) {
663 return ByteString("\0\0", 2);
664 }
665 int len = m_pData->m_nDataLength;
666 ByteString result;
667 char* buffer = result.GetBuffer(len * 2 + 2);
668 for (int i = 0; i < len; i++) {
669 buffer[i * 2] = m_pData->m_String[i] & 0xff;
670 buffer[i * 2 + 1] = m_pData->m_String[i] >> 8;
671 }
672 buffer[len * 2] = 0;
673 buffer[len * 2 + 1] = 0;
674 result.ReleaseBuffer(len * 2 + 2);
675 return result;
676 }
677
Mid(size_t first,size_t count) const678 WideString WideString::Mid(size_t first, size_t count) const {
679 if (!m_pData)
680 return WideString();
681
682 if (!IsValidIndex(first))
683 return WideString();
684
685 if (count == 0 || !IsValidLength(count))
686 return WideString();
687
688 if (!IsValidIndex(first + count - 1))
689 return WideString();
690
691 if (first == 0 && count == GetLength())
692 return *this;
693
694 WideString dest;
695 AllocCopy(dest, count, first);
696 return dest;
697 }
698
Left(size_t count) const699 WideString WideString::Left(size_t count) const {
700 if (count == 0 || !IsValidLength(count))
701 return WideString();
702 return Mid(0, count);
703 }
704
Right(size_t count) const705 WideString WideString::Right(size_t count) const {
706 if (count == 0 || !IsValidLength(count))
707 return WideString();
708 return Mid(GetLength() - count, count);
709 }
710
AllocCopy(WideString & dest,size_t nCopyLen,size_t nCopyIndex) const711 void WideString::AllocCopy(WideString& dest,
712 size_t nCopyLen,
713 size_t nCopyIndex) const {
714 if (nCopyLen == 0)
715 return;
716
717 RetainPtr<StringData> pNewData(
718 StringData::Create(m_pData->m_String + nCopyIndex, nCopyLen));
719 dest.m_pData.Swap(pNewData);
720 }
721
Insert(size_t location,wchar_t ch)722 size_t WideString::Insert(size_t location, wchar_t ch) {
723 const size_t cur_length = m_pData ? m_pData->m_nDataLength : 0;
724 if (!IsValidLength(location))
725 return cur_length;
726
727 const size_t new_length = cur_length + 1;
728 ReallocBeforeWrite(new_length);
729 wmemmove(m_pData->m_String + location + 1, m_pData->m_String + location,
730 new_length - location);
731 m_pData->m_String[location] = ch;
732 m_pData->m_nDataLength = new_length;
733 return new_length;
734 }
735
Find(wchar_t ch,size_t start) const736 Optional<size_t> WideString::Find(wchar_t ch, size_t start) const {
737 if (!m_pData)
738 return Optional<size_t>();
739
740 if (!IsValidIndex(start))
741 return Optional<size_t>();
742
743 const wchar_t* pStr =
744 wmemchr(m_pData->m_String + start, ch, m_pData->m_nDataLength - start);
745 return pStr ? Optional<size_t>(static_cast<size_t>(pStr - m_pData->m_String))
746 : Optional<size_t>();
747 }
748
Find(const WideStringView & subStr,size_t start) const749 Optional<size_t> WideString::Find(const WideStringView& subStr,
750 size_t start) const {
751 if (!m_pData)
752 return Optional<size_t>();
753
754 if (!IsValidIndex(start))
755 return Optional<size_t>();
756
757 const wchar_t* pStr =
758 FX_wcsstr(m_pData->m_String + start, m_pData->m_nDataLength - start,
759 subStr.unterminated_c_str(), subStr.GetLength());
760 return pStr ? Optional<size_t>(static_cast<size_t>(pStr - m_pData->m_String))
761 : Optional<size_t>();
762 }
763
MakeLower()764 void WideString::MakeLower() {
765 if (!m_pData)
766 return;
767
768 ReallocBeforeWrite(m_pData->m_nDataLength);
769 FXSYS_wcslwr(m_pData->m_String);
770 }
771
MakeUpper()772 void WideString::MakeUpper() {
773 if (!m_pData)
774 return;
775
776 ReallocBeforeWrite(m_pData->m_nDataLength);
777 FXSYS_wcsupr(m_pData->m_String);
778 }
779
Remove(wchar_t chRemove)780 size_t WideString::Remove(wchar_t chRemove) {
781 if (!m_pData || m_pData->m_nDataLength < 1)
782 return 0;
783
784 wchar_t* pstrSource = m_pData->m_String;
785 wchar_t* pstrEnd = m_pData->m_String + m_pData->m_nDataLength;
786 while (pstrSource < pstrEnd) {
787 if (*pstrSource == chRemove)
788 break;
789 pstrSource++;
790 }
791 if (pstrSource == pstrEnd)
792 return 0;
793
794 ptrdiff_t copied = pstrSource - m_pData->m_String;
795 ReallocBeforeWrite(m_pData->m_nDataLength);
796 pstrSource = m_pData->m_String + copied;
797 pstrEnd = m_pData->m_String + m_pData->m_nDataLength;
798
799 wchar_t* pstrDest = pstrSource;
800 while (pstrSource < pstrEnd) {
801 if (*pstrSource != chRemove) {
802 *pstrDest = *pstrSource;
803 pstrDest++;
804 }
805 pstrSource++;
806 }
807
808 *pstrDest = 0;
809 size_t count = static_cast<size_t>(pstrSource - pstrDest);
810 m_pData->m_nDataLength -= count;
811 return count;
812 }
813
Replace(const WideStringView & pOld,const WideStringView & pNew)814 size_t WideString::Replace(const WideStringView& pOld,
815 const WideStringView& pNew) {
816 if (!m_pData || pOld.IsEmpty())
817 return 0;
818
819 size_t nSourceLen = pOld.GetLength();
820 size_t nReplacementLen = pNew.GetLength();
821 size_t count = 0;
822 const wchar_t* pStart = m_pData->m_String;
823 wchar_t* pEnd = m_pData->m_String + m_pData->m_nDataLength;
824 while (1) {
825 const wchar_t* pTarget =
826 FX_wcsstr(pStart, static_cast<size_t>(pEnd - pStart),
827 pOld.unterminated_c_str(), nSourceLen);
828 if (!pTarget)
829 break;
830
831 count++;
832 pStart = pTarget + nSourceLen;
833 }
834 if (count == 0)
835 return 0;
836
837 size_t nNewLength =
838 m_pData->m_nDataLength + (nReplacementLen - nSourceLen) * count;
839
840 if (nNewLength == 0) {
841 clear();
842 return count;
843 }
844
845 RetainPtr<StringData> pNewData(StringData::Create(nNewLength));
846 pStart = m_pData->m_String;
847 wchar_t* pDest = pNewData->m_String;
848 for (size_t i = 0; i < count; i++) {
849 const wchar_t* pTarget =
850 FX_wcsstr(pStart, static_cast<size_t>(pEnd - pStart),
851 pOld.unterminated_c_str(), nSourceLen);
852 wmemcpy(pDest, pStart, pTarget - pStart);
853 pDest += pTarget - pStart;
854 wmemcpy(pDest, pNew.unterminated_c_str(), pNew.GetLength());
855 pDest += pNew.GetLength();
856 pStart = pTarget + nSourceLen;
857 }
858 wmemcpy(pDest, pStart, pEnd - pStart);
859 m_pData.Swap(pNewData);
860 return count;
861 }
862
863 // static
FromLocal(const ByteStringView & str)864 WideString WideString::FromLocal(const ByteStringView& str) {
865 return FromCodePage(str, 0);
866 }
867
868 // static
FromCodePage(const ByteStringView & str,uint16_t codepage)869 WideString WideString::FromCodePage(const ByteStringView& str,
870 uint16_t codepage) {
871 return GetWideString(codepage, str);
872 }
873
874 // static
FromUTF8(const ByteStringView & str)875 WideString WideString::FromUTF8(const ByteStringView& str) {
876 if (str.IsEmpty())
877 return WideString();
878
879 CFX_UTF8Decoder decoder;
880 for (size_t i = 0; i < str.GetLength(); i++)
881 decoder.Input(str[i]);
882
883 return WideString(decoder.GetResult());
884 }
885
886 // static
FromUTF16LE(const unsigned short * wstr,size_t wlen)887 WideString WideString::FromUTF16LE(const unsigned short* wstr, size_t wlen) {
888 if (!wstr || wlen == 0) {
889 return WideString();
890 }
891
892 WideString result;
893 wchar_t* buf = result.GetBuffer(wlen);
894 for (size_t i = 0; i < wlen; i++) {
895 buf[i] = wstr[i];
896 }
897 result.ReleaseBuffer(wlen);
898 return result;
899 }
900
SetAt(size_t index,wchar_t c)901 void WideString::SetAt(size_t index, wchar_t c) {
902 ASSERT(IsValidIndex(index));
903 ReallocBeforeWrite(m_pData->m_nDataLength);
904 m_pData->m_String[index] = c;
905 }
906
Compare(const wchar_t * lpsz) const907 int WideString::Compare(const wchar_t* lpsz) const {
908 if (m_pData)
909 return lpsz ? wcscmp(m_pData->m_String, lpsz) : 1;
910 return (!lpsz || lpsz[0] == 0) ? 0 : -1;
911 }
912
Compare(const WideString & str) const913 int WideString::Compare(const WideString& str) const {
914 if (!m_pData)
915 return str.m_pData ? -1 : 0;
916 if (!str.m_pData)
917 return 1;
918
919 size_t this_len = m_pData->m_nDataLength;
920 size_t that_len = str.m_pData->m_nDataLength;
921 size_t min_len = std::min(this_len, that_len);
922 int result = wmemcmp(m_pData->m_String, str.m_pData->m_String, min_len);
923 if (result != 0)
924 return result;
925 if (this_len == that_len)
926 return 0;
927 return this_len < that_len;
928 }
929
CompareNoCase(const wchar_t * lpsz) const930 int WideString::CompareNoCase(const wchar_t* lpsz) const {
931 if (m_pData)
932 return lpsz ? FXSYS_wcsicmp(m_pData->m_String, lpsz) : 1;
933 return (!lpsz || lpsz[0] == 0) ? 0 : -1;
934 }
935
WStringLength(const unsigned short * str)936 size_t WideString::WStringLength(const unsigned short* str) {
937 size_t len = 0;
938 if (str)
939 while (str[len])
940 len++;
941 return len;
942 }
943
Trim()944 void WideString::Trim() {
945 TrimRight(kWideTrimChars);
946 TrimLeft(kWideTrimChars);
947 }
948
Trim(wchar_t target)949 void WideString::Trim(wchar_t target) {
950 wchar_t str[2] = {target, 0};
951 TrimRight(str);
952 TrimLeft(str);
953 }
954
Trim(const WideStringView & targets)955 void WideString::Trim(const WideStringView& targets) {
956 TrimRight(targets);
957 TrimLeft(targets);
958 }
959
TrimLeft()960 void WideString::TrimLeft() {
961 TrimLeft(kWideTrimChars);
962 }
963
TrimLeft(wchar_t target)964 void WideString::TrimLeft(wchar_t target) {
965 wchar_t str[2] = {target, 0};
966 TrimLeft(str);
967 }
968
TrimLeft(const WideStringView & targets)969 void WideString::TrimLeft(const WideStringView& targets) {
970 if (!m_pData || targets.IsEmpty())
971 return;
972
973 size_t len = GetLength();
974 if (len == 0)
975 return;
976
977 size_t pos = 0;
978 while (pos < len) {
979 size_t i = 0;
980 while (i < targets.GetLength() &&
981 targets.CharAt(i) != m_pData->m_String[pos]) {
982 i++;
983 }
984 if (i == targets.GetLength())
985 break;
986 pos++;
987 }
988 if (!pos)
989 return;
990
991 ReallocBeforeWrite(len);
992 size_t nDataLength = len - pos;
993 memmove(m_pData->m_String, m_pData->m_String + pos,
994 (nDataLength + 1) * sizeof(wchar_t));
995 m_pData->m_nDataLength = nDataLength;
996 }
997
TrimRight()998 void WideString::TrimRight() {
999 TrimRight(kWideTrimChars);
1000 }
1001
TrimRight(wchar_t target)1002 void WideString::TrimRight(wchar_t target) {
1003 wchar_t str[2] = {target, 0};
1004 TrimRight(str);
1005 }
1006
TrimRight(const WideStringView & targets)1007 void WideString::TrimRight(const WideStringView& targets) {
1008 if (IsEmpty() || targets.IsEmpty())
1009 return;
1010
1011 size_t pos = GetLength();
1012 while (pos && targets.Contains(m_pData->m_String[pos - 1]))
1013 pos--;
1014
1015 if (pos < m_pData->m_nDataLength) {
1016 ReallocBeforeWrite(m_pData->m_nDataLength);
1017 m_pData->m_String[pos] = 0;
1018 m_pData->m_nDataLength = pos;
1019 }
1020 }
1021
FX_wtof(const wchar_t * str,int len)1022 float FX_wtof(const wchar_t* str, int len) {
1023 if (len == 0) {
1024 return 0.0;
1025 }
1026 int cc = 0;
1027 bool bNegative = false;
1028 if (str[0] == '+') {
1029 cc++;
1030 } else if (str[0] == '-') {
1031 bNegative = true;
1032 cc++;
1033 }
1034 int integer = 0;
1035 while (cc < len) {
1036 if (str[cc] == '.') {
1037 break;
1038 }
1039 integer = integer * 10 + FXSYS_DecimalCharToInt(str[cc]);
1040 cc++;
1041 }
1042 float fraction = 0;
1043 if (str[cc] == '.') {
1044 cc++;
1045 float scale = 0.1f;
1046 while (cc < len) {
1047 fraction += scale * FXSYS_DecimalCharToInt(str[cc]);
1048 scale *= 0.1f;
1049 cc++;
1050 }
1051 }
1052 fraction += static_cast<float>(integer);
1053 return bNegative ? -fraction : fraction;
1054 }
1055
GetInteger() const1056 int WideString::GetInteger() const {
1057 return m_pData ? FXSYS_wtoi(m_pData->m_String) : 0;
1058 }
1059
GetFloat() const1060 float WideString::GetFloat() const {
1061 return m_pData ? FX_wtof(m_pData->m_String, m_pData->m_nDataLength) : 0.0f;
1062 }
1063
operator <<(std::wostream & os,const WideString & str)1064 std::wostream& operator<<(std::wostream& os, const WideString& str) {
1065 return os.write(str.c_str(), str.GetLength());
1066 }
1067
operator <<(std::ostream & os,const WideString & str)1068 std::ostream& operator<<(std::ostream& os, const WideString& str) {
1069 os << str.UTF8Encode();
1070 return os;
1071 }
1072
operator <<(std::wostream & os,const WideStringView & str)1073 std::wostream& operator<<(std::wostream& os, const WideStringView& str) {
1074 return os.write(str.unterminated_c_str(), str.GetLength());
1075 }
1076
operator <<(std::ostream & os,const WideStringView & str)1077 std::ostream& operator<<(std::ostream& os, const WideStringView& str) {
1078 os << FX_UTF8Encode(str);
1079 return os;
1080 }
1081
1082 } // namespace fxcrt
1083