Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
widestring.cpp
Go to the documentation of this file.
1// Copyright 2014 The PDFium Authors
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#include <string.h>
11#include <wchar.h>
12
13#include <algorithm>
14#include <sstream>
15
16#include "core/fxcrt/check.h"
17#include "core/fxcrt/check_op.h"
18#include "core/fxcrt/compiler_specific.h"
19#include "core/fxcrt/fx_codepage.h"
20#include "core/fxcrt/fx_extension.h"
21#include "core/fxcrt/fx_memcpy_wrappers.h"
22#include "core/fxcrt/fx_safe_types.h"
23#include "core/fxcrt/fx_system.h"
24#include "core/fxcrt/numerics/safe_math.h"
25#include "core/fxcrt/span_util.h"
26#include "core/fxcrt/string_pool_template.h"
27#include "core/fxcrt/utf16.h"
28
29// Instantiate.
30template class fxcrt::StringViewTemplate<wchar_t>;
31template class fxcrt::StringPoolTemplate<WideString>;
32template struct std::hash<WideString>;
33
34#define FORCE_ANSI 0x10000
35#define FORCE_UNICODE 0x20000
36#define FORCE_INT64 0x40000
37
38namespace {
39
40#if defined(WCHAR_T_IS_32_BIT)
41size_t FuseSurrogates(pdfium::span<wchar_t> s) {
42 size_t dest_pos = 0;
43 for (size_t i = 0; i < s.size(); ++i) {
44 // TODO(crbug.com/pdfium/2031): Always use UTF-16.
45 if (pdfium::IsHighSurrogate(s[i]) && i + 1 < s.size() &&
46 pdfium::IsLowSurrogate(s[i + 1])) {
47 s[dest_pos++] = pdfium::SurrogatePair(s[i], s[i + 1]).ToCodePoint();
48 ++i;
49 continue;
50 }
51 s[dest_pos++] = s[i];
52 }
53 return dest_pos;
54}
55#endif // defined(WCHAR_T_IS_32_BIT)
56
57constexpr wchar_t kWideTrimChars[] = L"\x09\x0a\x0b\x0c\x0d\x20";
58
59std::optional<size_t> GuessSizeForVSWPrintf(const wchar_t* pFormat,
60 va_list argList) {
61 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 iWidth = 0;
69 for (; *pStr != 0; pStr++) {
70 if (*pStr == '#') {
71 nMaxLen += 2;
72 } else if (*pStr == '*') {
73 iWidth = va_arg(argList, int);
74 } else if (*pStr != '-' && *pStr != '+' && *pStr != '0' &&
75 *pStr != ' ') {
76 break;
77 }
78 }
79 if (iWidth == 0) {
80 iWidth = FXSYS_wtoi(pStr);
81 while (FXSYS_IsDecimalDigit(*pStr))
82 ++pStr;
83 }
84 if (iWidth < 0 || iWidth > 128 * 1024) {
85 return std::nullopt;
86 }
87 uint32_t nWidth = static_cast<uint32_t>(iWidth);
88 int iPrecision = 0;
89 if (*pStr == '.') {
90 pStr++;
91 if (*pStr == '*') {
92 iPrecision = va_arg(argList, int);
93 pStr++;
94 } else {
95 iPrecision = FXSYS_wtoi(pStr);
96 while (FXSYS_IsDecimalDigit(*pStr)) {
97 ++pStr;
98 }
99 }
100 }
101 if (iPrecision < 0 || iPrecision > 128 * 1024) {
102 return std::nullopt;
103 }
104 uint32_t nPrecision = static_cast<uint32_t>(iPrecision);
105 int nModifier = 0;
106 if (*pStr == L'I' && *(pStr + 1) == L'6' && *(pStr + 2) == L'4') {
107 pStr += 3;
108 nModifier = FORCE_INT64;
109 } else {
110 switch (*pStr) {
111 case 'h':
112 nModifier = FORCE_ANSI;
113 pStr++;
114 break;
115 case 'l':
116 nModifier = FORCE_UNICODE;
117 pStr++;
118 break;
119 case 'F':
120 case 'N':
121 case 'L':
122 pStr++;
123 break;
124 }
125 }
126 size_t nItemLen = 0;
127 switch (*pStr | nModifier) {
128 case 'c':
129 case 'C':
130 nItemLen = 2;
131 va_arg(argList, int);
132 break;
133 case 'c' | FORCE_ANSI:
134 case 'C' | FORCE_ANSI:
135 nItemLen = 2;
136 va_arg(argList, int);
137 break;
138 case 'c' | FORCE_UNICODE:
139 case 'C' | FORCE_UNICODE:
140 nItemLen = 2;
141 va_arg(argList, int);
142 break;
143 case 's': {
144 const wchar_t* pstrNextArg = va_arg(argList, const wchar_t*);
145 if (pstrNextArg) {
146 nItemLen = wcslen(pstrNextArg);
147 if (nItemLen < 1) {
148 nItemLen = 1;
149 }
150 } else {
151 nItemLen = 6;
152 }
153 } break;
154 case 'S': {
155 const char* pstrNextArg = va_arg(argList, const char*);
156 if (pstrNextArg) {
157 nItemLen = strlen(pstrNextArg);
158 if (nItemLen < 1) {
159 nItemLen = 1;
160 }
161 } else {
162 nItemLen = 6;
163 }
164 } break;
165 case 's' | FORCE_ANSI:
166 case 'S' | FORCE_ANSI: {
167 const char* pstrNextArg = va_arg(argList, const char*);
168 if (pstrNextArg) {
169 nItemLen = strlen(pstrNextArg);
170 if (nItemLen < 1) {
171 nItemLen = 1;
172 }
173 } else {
174 nItemLen = 6;
175 }
176 } break;
177 case 's' | FORCE_UNICODE:
178 case 'S' | FORCE_UNICODE: {
179 const wchar_t* pstrNextArg = va_arg(argList, wchar_t*);
180 if (pstrNextArg) {
181 nItemLen = wcslen(pstrNextArg);
182 if (nItemLen < 1) {
183 nItemLen = 1;
184 }
185 } else {
186 nItemLen = 6;
187 }
188 } break;
189 }
190 if (nItemLen != 0) {
191 if (nPrecision != 0 && nItemLen > nPrecision) {
192 nItemLen = nPrecision;
193 }
194 if (nItemLen < nWidth) {
195 nItemLen = nWidth;
196 }
197 } else {
198 switch (*pStr) {
199 case 'd':
200 case 'i':
201 case 'u':
202 case 'x':
203 case 'X':
204 case 'o':
205 if (nModifier & FORCE_INT64) {
206 va_arg(argList, int64_t);
207 } else {
208 va_arg(argList, int);
209 }
210 nItemLen = 32;
211 if (nItemLen < nWidth + nPrecision) {
212 nItemLen = nWidth + nPrecision;
213 }
214 break;
215 case 'a':
216 case 'A':
217 case 'e':
218 case 'E':
219 case 'g':
220 case 'G':
221 va_arg(argList, double);
222 nItemLen = 128;
223 if (nItemLen < nWidth + nPrecision) {
224 nItemLen = nWidth + nPrecision;
225 }
226 break;
227 case 'f':
228 if (nWidth + nPrecision > 100) {
229 nItemLen = nPrecision + nWidth + 128;
230 } else {
231 double f;
232 char pszTemp[256];
233 f = va_arg(argList, double);
234 FXSYS_snprintf(pszTemp, sizeof(pszTemp), "%*.*f", nWidth,
235 nPrecision + 6, f);
236 nItemLen = strlen(pszTemp);
237 }
238 break;
239 case 'p':
240 va_arg(argList, void*);
241 nItemLen = 32;
242 if (nItemLen < nWidth + nPrecision) {
243 nItemLen = nWidth + nPrecision;
244 }
245 break;
246 case 'n':
247 va_arg(argList, int*);
248 break;
249 }
250 }
251 nMaxLen += nItemLen;
252 }
253 });
254 nMaxLen += 32; // Fudge factor.
255 return nMaxLen;
256}
257
258// Returns string unless we ran out of space.
259std::optional<WideString> TryVSWPrintf(size_t size,
260 const wchar_t* pFormat,
261 va_list argList) {
262 if (!size)
263 return std::nullopt;
264
265 WideString str;
266 {
267 // Span's lifetime must end before ReleaseBuffer() below.
268 pdfium::span<wchar_t> buffer = str.GetBuffer(size);
269
270 // SAFETY: In the following two calls, there's always space in the
271 // WideString for a terminating NUL that's not included in the span.
272 // For vswprintf(), MSAN won't untaint the buffer on a truncated write's
273 // -1 return code even though the buffer is written. Probably just as well
274 // not to trust the vendor's implementation to write anything anyways.
275 // See https://crbug.com/705912.
277 FXSYS_memset(buffer.data(), 0, (size + 1) * sizeof(wchar_t)));
278 int ret = vswprintf(buffer.data(), size + 1, pFormat, argList);
279 bool bSufficientBuffer = ret >= 0 || buffer[size - 1] == 0;
280 if (!bSufficientBuffer)
281 return std::nullopt;
282 }
283 str.ReleaseBuffer(str.GetStringLength());
284 return str;
285}
286
287// Appends a Unicode code point to a `WideString` using either UTF-16 or UTF-32,
288// depending on the platform's definition of `wchar_t`.
289//
290// TODO(crbug.com/pdfium/2031): Always use UTF-16.
291// TODO(crbug.com/pdfium/2041): Migrate to `WideString`.
292void AppendCodePointToWideString(char32_t code_point, WideString& buffer) {
294 // Invalid code point above U+10FFFF.
295 return;
296 }
297
298#if defined(WCHAR_T_IS_16_BIT)
299 if (code_point < pdfium::kMinimumSupplementaryCodePoint) {
300 buffer += static_cast<wchar_t>(code_point);
301 } else {
302 // Encode as UTF-16 surrogate pair.
303 pdfium::SurrogatePair surrogate_pair(code_point);
304 buffer += surrogate_pair.high();
305 buffer += surrogate_pair.low();
306 }
307#else
308 buffer += static_cast<wchar_t>(code_point);
309#endif // defined(WCHAR_T_IS_16_BIT)
310}
311
312WideString UTF8Decode(ByteStringView bsStr) {
313 WideString buffer;
314
315 int remaining = 0;
316 char32_t code_point = 0;
317 for (char byte : bsStr) {
318 uint8_t code_unit = static_cast<uint8_t>(byte);
319 if (code_unit < 0x80) {
320 remaining = 0;
321 AppendCodePointToWideString(code_unit, buffer);
322 } else if (code_unit < 0xc0) {
323 if (remaining > 0) {
324 --remaining;
325 code_point = (code_point << 6) | (code_unit & 0x3f);
326 if (remaining == 0) {
327 AppendCodePointToWideString(code_point, buffer);
328 }
329 }
330 } else if (code_unit < 0xe0) {
331 remaining = 1;
332 code_point = code_unit & 0x1f;
333 } else if (code_unit < 0xf0) {
334 remaining = 2;
335 code_point = code_unit & 0x0f;
336 } else if (code_unit < 0xf8) {
337 remaining = 3;
338 code_point = code_unit & 0x07;
339 } else {
340 remaining = 0;
341 }
342 }
343
344 return buffer;
345}
346
347} // namespace
348
349namespace fxcrt {
350
351static_assert(sizeof(WideString) <= sizeof(wchar_t*),
352 "Strings must not require more space than pointers");
353
354// static
356 wchar_t wbuf[32];
357 swprintf(wbuf, std::size(wbuf), L"%d", i);
358 return WideString(wbuf);
359}
360
361// static
362WideString WideString::FormatV(const wchar_t* format, va_list argList) {
363 va_list argListCopy;
364 va_copy(argListCopy, argList);
365 auto guess = GuessSizeForVSWPrintf(format, argListCopy);
366 va_end(argListCopy);
367
368 if (!guess.has_value()) {
369 return WideString();
370 }
371 int maxLen = pdfium::checked_cast<int>(guess.value());
372
373 while (maxLen < 32 * 1024) {
374 va_copy(argListCopy, argList);
375 std::optional<WideString> ret =
376 TryVSWPrintf(static_cast<size_t>(maxLen), format, argListCopy);
377 va_end(argListCopy);
378 if (ret.has_value())
379 return ret.value();
380
381 maxLen *= 2;
382 }
383 return WideString();
384}
385
386// static
387WideString WideString::Format(const wchar_t* pFormat, ...) {
388 va_list argList;
389 va_start(argList, pFormat);
390 WideString ret = FormatV(pFormat, argList);
391 va_end(argList);
392 return ret;
393}
394
395WideString::WideString(const wchar_t* pStr, size_t nLen) {
396 if (nLen) {
397 // SAFETY: caller ensures `pStr` points to al least `nLen` wchar_t.
398 m_pData = StringData::Create(UNSAFE_BUFFERS(pdfium::make_span(pStr, nLen)));
399 }
400}
401
402WideString::WideString(wchar_t ch) {
403 m_pData = StringData::Create(1);
404 m_pData->m_String[0] = ch;
405}
406
407WideString::WideString(const wchar_t* ptr)
408 : WideString(ptr, ptr ? wcslen(ptr) : 0) {}
409
411 if (!stringSrc.IsEmpty()) {
412 m_pData = StringData::Create(stringSrc.span());
413 }
414}
415
417 FX_SAFE_SIZE_T nSafeLen = str1.GetLength();
418 nSafeLen += str2.GetLength();
419
420 size_t nNewLen = nSafeLen.ValueOrDie();
421 if (nNewLen == 0)
422 return;
423
424 m_pData = StringData::Create(nNewLen);
425 m_pData->CopyContents(str1.span());
426 m_pData->CopyContentsAt(str1.GetLength(), str2.span());
427}
428
429WideString::WideString(const std::initializer_list<WideStringView>& list) {
430 FX_SAFE_SIZE_T nSafeLen = 0;
431 for (const auto& item : list)
432 nSafeLen += item.GetLength();
433
434 size_t nNewLen = nSafeLen.ValueOrDie();
435 if (nNewLen == 0)
436 return;
437
438 m_pData = StringData::Create(nNewLen);
439
440 size_t nOffset = 0;
441 for (const auto& item : list) {
442 m_pData->CopyContentsAt(nOffset, item.span());
443 nOffset += item.GetLength();
444 }
445}
446
447WideString& WideString::operator=(const wchar_t* str) {
448 if (!str || !str[0])
449 clear();
450 else
451 AssignCopy(str, wcslen(str));
452
453 return *this;
454}
455
457 if (str.IsEmpty())
458 clear();
459 else
460 AssignCopy(str.unterminated_c_str(), str.GetLength());
461
462 return *this;
463}
464
466 if (m_pData != that.m_pData)
467 m_pData = that.m_pData;
468
469 return *this;
470}
471
473 if (m_pData != that.m_pData)
474 m_pData = std::move(that.m_pData);
475
476 return *this;
477}
478
479WideString& WideString::operator+=(const wchar_t* str) {
480 if (str)
481 Concat(str, wcslen(str));
482
483 return *this;
484}
485
487 Concat(&ch, 1);
488 return *this;
489}
490
492 if (str.m_pData)
493 Concat(str.m_pData->m_String, str.m_pData->m_nDataLength);
494
495 return *this;
496}
497
499 if (!str.IsEmpty())
500 Concat(str.unterminated_c_str(), str.GetLength());
501
502 return *this;
503}
504
505bool WideString::operator==(const wchar_t* ptr) const {
506 if (!m_pData)
507 return !ptr || !ptr[0];
508
509 if (!ptr)
510 return m_pData->m_nDataLength == 0;
511
512 // SAFTEY: `wsclen()` comparison ensures there are `m_nDataLength` wchars at
513 // `ptr` before the terminator, and `m_nDataLength` is within `m_String`.
514 return wcslen(ptr) == m_pData->m_nDataLength &&
515 UNSAFE_BUFFERS(FXSYS_wmemcmp(ptr, m_pData->m_String,
516 m_pData->m_nDataLength)) == 0;
517}
518
520 if (!m_pData)
521 return str.IsEmpty();
522
523 // SAFTEY: Comparison ensure there are `m_nDataLength` wchars in `str`
524 // and `m_nDataLength is within `m_String`.
525 return m_pData->m_nDataLength == str.GetLength() &&
526 UNSAFE_BUFFERS(FXSYS_wmemcmp(
527 m_pData->m_String, str.unterminated_c_str(), str.GetLength())) ==
528 0;
529}
530
531bool WideString::operator==(const WideString& other) const {
532 if (m_pData == other.m_pData)
533 return true;
534
535 if (IsEmpty())
536 return other.IsEmpty();
537
538 if (other.IsEmpty())
539 return false;
540
541 return other.m_pData->m_nDataLength == m_pData->m_nDataLength &&
542 wmemcmp(other.m_pData->m_String, m_pData->m_String,
543 m_pData->m_nDataLength) == 0;
544}
545
546bool WideString::operator<(const wchar_t* ptr) const {
547 return Compare(ptr) < 0;
548}
549
551 if (!m_pData && !str.unterminated_c_str())
552 return false;
553 if (c_str() == str.unterminated_c_str())
554 return false;
555
556 size_t len = GetLength();
557 size_t other_len = str.GetLength();
558
559 // SAFETY: Comparison limited to minimum valid length of either argument.
560 int result = UNSAFE_BUFFERS(FXSYS_wmemcmp(c_str(), str.unterminated_c_str(),
561 std::min(len, other_len)));
562 return result < 0 || (result == 0 && len < other_len);
563}
564
565bool WideString::operator<(const WideString& other) const {
566 return Compare(other) < 0;
567}
568
570 return m_pData ? m_pData->m_nRefs : 0;
571}
572
574 ByteString result;
575 result.Reserve(GetLength());
576 for (wchar_t wc : *this)
577 result.InsertAtBack(static_cast<char>(wc & 0x7f));
578 return result;
579}
580
582 ByteString result;
583 result.Reserve(GetLength());
584 for (wchar_t wc : *this)
585 result.InsertAtBack(static_cast<char>(wc & 0xff));
586 return result;
587}
588
590 size_t dest_len =
591 FX_WideCharToMultiByte(FX_CodePage::kDefANSI, AsStringView(), {});
592 if (!dest_len)
593 return ByteString();
594
595 ByteString bstr;
596 {
597 // Span's lifetime must end before ReleaseBuffer() below.
598 pdfium::span<char> dest_buf = bstr.GetBuffer(dest_len);
599 FX_WideCharToMultiByte(FX_CodePage::kDefANSI, AsStringView(), dest_buf);
600 }
601 bstr.ReleaseBuffer(dest_len);
602 return bstr;
603}
604
606 return FX_UTF8Encode(AsStringView());
607}
608
610 std::u16string utf16 = FX_UTF16Encode(AsStringView());
611 ByteString result;
612 size_t output_length = 0;
613 {
614 // Span's lifetime must end before ReleaseBuffer() below.
615 // 2 bytes required per UTF-16 code unit.
616 pdfium::span<uint8_t> buffer =
617 pdfium::as_writable_bytes(result.GetBuffer(utf16.size() * 2 + 2));
618 for (char16_t c : utf16) {
619 buffer[output_length++] = c & 0xff;
620 buffer[output_length++] = c >> 8;
621 }
622 buffer[output_length++] = 0;
623 buffer[output_length++] = 0;
624 }
625 result.ReleaseBuffer(output_length);
626 return result;
627}
628
630 ByteString result;
631 size_t output_length = 0;
632 {
633 // Span's lifetime must end before ReleaseBuffer() below.
634 // 2 bytes required per UTF-16 code unit.
635 pdfium::span<uint8_t> buffer =
636 pdfium::as_writable_bytes(result.GetBuffer(GetLength() * 2 + 2));
637 for (wchar_t wc : AsStringView()) {
638#if defined(WCHAR_T_IS_32_BIT)
639 if (pdfium::IsSupplementary(wc)) {
640 continue;
641 }
642#endif
643 buffer[output_length++] = wc & 0xff;
644 buffer[output_length++] = wc >> 8;
645 }
646 buffer[output_length++] = 0;
647 buffer[output_length++] = 0;
648 }
649 result.ReleaseBuffer(output_length);
650 return result;
651}
652
654 WideString ret = *this;
655 ret.Replace(L"&", L"&amp;");
656 ret.Replace(L"<", L"&lt;");
657 ret.Replace(L">", L"&gt;");
658 ret.Replace(L"\'", L"&apos;");
659 ret.Replace(L"\"", L"&quot;");
660 return ret;
661}
662
663WideString WideString::Substr(size_t offset) const {
664 // Unsigned underflow is well-defined and out-of-range is handled by Substr().
665 return Substr(offset, GetLength() - offset);
666}
667
668WideString WideString::Substr(size_t first, size_t count) const {
669 if (!m_pData) {
670 return WideString();
671 }
672 if (first == 0 && count == GetLength()) {
673 return *this;
674 }
675 return WideString(AsStringView().Substr(first, count));
676}
677
678WideString WideString::First(size_t count) const {
679 return Substr(0, count);
680}
681
682WideString WideString::Last(size_t count) const {
683 // Unsigned underflow is well-defined and out-of-range is handled by Substr().
684 return Substr(GetLength() - count, count);
685}
686
688 if (IsEmpty())
689 return;
690
691 ReallocBeforeWrite(m_pData->m_nDataLength);
692 FXSYS_wcslwr(m_pData->m_String);
693}
694
696 if (IsEmpty())
697 return;
698
699 ReallocBeforeWrite(m_pData->m_nDataLength);
700 FXSYS_wcsupr(m_pData->m_String);
701}
702
703// static
705 WideString result;
706 result.Reserve(bstr.GetLength());
707 for (char c : bstr)
708 result.InsertAtBack(static_cast<wchar_t>(c & 0x7f));
709 return result;
710}
711
712// static
714 WideString result;
715 result.Reserve(bstr.GetLength());
716 for (char c : bstr)
717 result.InsertAtBack(static_cast<wchar_t>(c & 0xff));
718 return result;
719}
720
721// static
723 size_t dest_len = FX_MultiByteToWideChar(FX_CodePage::kDefANSI, bstr, {});
724 if (!dest_len)
725 return WideString();
726
727 WideString wstr;
728 {
729 // Span's lifetime must end before ReleaseBuffer() below.
730 pdfium::span<wchar_t> dest_buf = wstr.GetBuffer(dest_len);
731 FX_MultiByteToWideChar(FX_CodePage::kDefANSI, bstr, dest_buf);
732 }
733 wstr.ReleaseBuffer(dest_len);
734 return wstr;
735}
736
737// static
739 return UTF8Decode(str);
740}
741
742// static
743WideString WideString::FromUTF16LE(pdfium::span<const uint8_t> data) {
744 if (data.empty()) {
745 return WideString();
746 }
747
748 WideString result;
749 size_t length = 0;
750 {
751 // Span's lifetime must end before ReleaseBuffer() below.
752 pdfium::span<wchar_t> buf = result.GetBuffer(data.size() / 2);
753 for (size_t i = 0; i + 1 < data.size(); i += 2) {
754 buf[length++] = data[i] | data[i + 1] << 8;
755 }
756
757#if defined(WCHAR_T_IS_32_BIT)
758 length = FuseSurrogates(buf.first(length));
759#endif
760 }
761 result.ReleaseBuffer(length);
762 return result;
763}
764
765WideString WideString::FromUTF16BE(pdfium::span<const uint8_t> data) {
766 if (data.empty()) {
767 return WideString();
768 }
769
770 WideString result;
771 size_t length = 0;
772 {
773 // Span's lifetime must end before ReleaseBuffer() below.
774 pdfium::span<wchar_t> buf = result.GetBuffer(data.size() / 2);
775 for (size_t i = 0; i + 1 < data.size(); i += 2) {
776 buf[length++] = data[i] << 8 | data[i + 1];
777 }
778
779#if defined(WCHAR_T_IS_32_BIT)
780 length = FuseSurrogates(buf.first(length));
781#endif
782 }
783 result.ReleaseBuffer(length);
784 return result;
785}
786
787int WideString::Compare(const wchar_t* str) const {
788 if (m_pData)
789 return str ? wcscmp(m_pData->m_String, str) : 1;
790 return (!str || str[0] == 0) ? 0 : -1;
791}
792
793int WideString::Compare(const WideString& str) const {
794 if (!m_pData)
795 return str.m_pData ? -1 : 0;
796 if (!str.m_pData)
797 return 1;
798
799 size_t this_len = m_pData->m_nDataLength;
800 size_t that_len = str.m_pData->m_nDataLength;
801 size_t min_len = std::min(this_len, that_len);
802
803 // SAFTEY: Comparison limited to minimum length of either argument.
804 int result = UNSAFE_BUFFERS(
805 FXSYS_wmemcmp(m_pData->m_String, str.m_pData->m_String, min_len));
806 if (result != 0)
807 return result;
808 if (this_len == that_len)
809 return 0;
810 return this_len < that_len ? -1 : 1;
811}
812
813int WideString::CompareNoCase(const wchar_t* str) const {
814 if (m_pData)
815 return str ? FXSYS_wcsicmp(m_pData->m_String, str) : 1;
816 return (!str || str[0] == 0) ? 0 : -1;
817}
818
823
825 TrimFront(kWideTrimChars);
826}
827
829 TrimBack(kWideTrimChars);
830}
831int WideString::GetInteger() const {
832 return m_pData ? FXSYS_wtoi(m_pData->m_String) : 0;
833}
834
835std::wostream& operator<<(std::wostream& os, const WideString& str) {
836 return os.write(str.c_str(), str.GetLength());
837}
838
839std::ostream& operator<<(std::ostream& os, const WideString& str) {
840 os << str.ToUTF8();
841 return os;
842}
843
844std::wostream& operator<<(std::wostream& os, WideStringView str) {
845 return os.write(str.unterminated_c_str(), str.GetLength());
846}
847
848std::ostream& operator<<(std::ostream& os, WideStringView str) {
849 os << FX_UTF8Encode(str);
850 return os;
851}
852
853} // namespace fxcrt
854
856 uint32_t dwHashCode = 0;
857 for (WideStringView::UnsignedType c : str)
858 dwHashCode = 1313 * dwHashCode + c;
859 return dwHashCode;
860}
861
863 uint32_t dwHashCode = 0;
864 for (wchar_t c : str) // match FXSYS_towlower() arg type.
865 dwHashCode = 1313 * dwHashCode + FXSYS_towlower(c);
866 return dwHashCode;
867}
ByteString()=default
WideString(const std::initializer_list< WideStringView > &list)
WideString & operator+=(const WideString &str)
WideString(wchar_t ch)
bool operator==(const WideString &other) const
ByteString ToUTF8() const
static WideString Format(const wchar_t *pFormat,...)
UNSAFE_BUFFER_USAGE WideString(const wchar_t *pStr, size_t len)
WideString & operator=(WideString &&that) noexcept
WideString(WideStringView str1, WideStringView str2)
WideString()=default
WideString First(size_t count) const
static WideString FromUTF8(ByteStringView str)
WideString & operator+=(const wchar_t *str)
bool operator==(const wchar_t *ptr) const
WideString & operator+=(wchar_t ch)
bool operator<(WideStringView str) const
static WideString FromDefANSI(ByteStringView str)
int GetInteger() const
int CompareNoCase(const wchar_t *str) const
WideString(const wchar_t *ptr)
static WideString FromLatin1(ByteStringView str)
bool operator==(WideStringView str) const
ByteString ToLatin1() const
intptr_t ReferenceCountForTesting() const
bool operator<(const WideString &other) const
int Compare(const wchar_t *str) const
WideString & operator=(const WideString &that)
WideString EncodeEntities() const
ByteString ToASCII() const
static WideString FromASCII(ByteStringView str)
WideString & operator+=(WideStringView str)
ByteString ToUCS2LE() const
WideString Last(size_t count) const
int Compare(const WideString &str) const
WideString & operator=(const wchar_t *str)
WideString Substr(size_t offset) const
WideString(WideStringView str)
static WideString FormatV(const wchar_t *lpszFormat, va_list argList)
ByteString ToUTF16LE() const
static WideString FormatInteger(int i)
ByteString ToDefANSI() const
bool operator<(const wchar_t *ptr) const
WideString Substr(size_t first, size_t count) const
WideString & operator=(WideStringView str)
#define UNSAFE_BUFFERS(...)
#define UNSAFE_TODO(...)
FX_CodePage
Definition fx_codepage.h:19
bool FXSYS_IsDecimalDigit(wchar_t c)
int32_t FXSYS_wtoi(const wchar_t *str)
#define FXSYS_snprintf
Definition fx_system.h:49
StringViewTemplate< wchar_t > WideStringView
StringViewTemplate< char > ByteStringView
constexpr char32_t kMaximumSupplementaryCodePoint
Definition utf16.h:22
fxcrt::ByteStringView ByteStringView
fxcrt::WideStringView WideStringView
#define FORCE_INT64
#define FORCE_UNICODE
#define FORCE_ANSI
fxcrt::WideString WideString
Definition widestring.h:207
uint32_t FX_HashCode_GetLoweredW(WideStringView str)
uint32_t FX_HashCode_GetW(WideStringView str)