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