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/bytestring.h"
8
9 #include <stddef.h>
10
11 #include <algorithm>
12 #include <cctype>
13 #include <string>
14 #include <utility>
15
16 #include "core/fxcrt/cfx_utf8decoder.h"
17 #include "core/fxcrt/fx_codepage.h"
18 #include "core/fxcrt/fx_extension.h"
19 #include "core/fxcrt/fx_safe_types.h"
20 #include "core/fxcrt/string_pool_template.h"
21 #include "third_party/base/numerics/safe_math.h"
22 #include "third_party/base/span.h"
23 #include "third_party/base/stl_util.h"
24
25 template class fxcrt::StringDataTemplate<char>;
26 template class fxcrt::StringViewTemplate<char>;
27 template class fxcrt::StringPoolTemplate<ByteString>;
28 template struct std::hash<ByteString>;
29
30 namespace {
31
32 constexpr char kTrimChars[] = "\x09\x0a\x0b\x0c\x0d\x20";
33
FX_strstr(const char * haystack,int haystack_len,const char * needle,int needle_len)34 const char* FX_strstr(const char* haystack,
35 int haystack_len,
36 const char* needle,
37 int needle_len) {
38 if (needle_len > haystack_len || needle_len == 0) {
39 return nullptr;
40 }
41 const char* end_ptr = haystack + haystack_len - needle_len;
42 while (haystack <= end_ptr) {
43 int i = 0;
44 while (1) {
45 if (haystack[i] != needle[i]) {
46 break;
47 }
48 i++;
49 if (i == needle_len) {
50 return haystack;
51 }
52 }
53 haystack++;
54 }
55 return nullptr;
56 }
57
58 } // namespace
59
60 namespace fxcrt {
61
62 static_assert(sizeof(ByteString) <= sizeof(char*),
63 "Strings must not require more space than pointers");
64
65 #define FORCE_ANSI 0x10000
66 #define FORCE_UNICODE 0x20000
67 #define FORCE_INT64 0x40000
68
69 // static
FormatInteger(int i)70 ByteString ByteString::FormatInteger(int i) {
71 char buf[32];
72 FXSYS_snprintf(buf, sizeof(buf), "%d", i);
73 return ByteString(buf);
74 }
75
76 // static
FormatFloat(float f)77 ByteString ByteString::FormatFloat(float f) {
78 char buf[32];
79 return ByteString(buf, FloatToString(f, buf));
80 }
81
82 // static
FormatV(const char * pFormat,va_list argList)83 ByteString ByteString::FormatV(const char* pFormat, va_list argList) {
84 va_list argListCopy;
85 va_copy(argListCopy, argList);
86 int nMaxLen = vsnprintf(nullptr, 0, pFormat, argListCopy);
87 va_end(argListCopy);
88
89 if (nMaxLen <= 0)
90 return ByteString();
91
92 ByteString ret;
93 {
94 // Span's lifetime must end before ReleaseBuffer() below.
95 pdfium::span<char> buf = ret.GetBuffer(nMaxLen);
96
97 // In the following two calls, there's always space in the buffer for
98 // a terminating NUL that's not included in nMaxLen.
99 memset(buf.data(), 0, nMaxLen + 1);
100 va_copy(argListCopy, argList);
101 vsnprintf(buf.data(), nMaxLen + 1, pFormat, argListCopy);
102 va_end(argListCopy);
103 }
104 ret.ReleaseBuffer(ret.GetStringLength());
105 return ret;
106 }
107
108 // static
Format(const char * pFormat,...)109 ByteString ByteString::Format(const char* pFormat, ...) {
110 va_list argList;
111 va_start(argList, pFormat);
112 ByteString ret = FormatV(pFormat, argList);
113 va_end(argList);
114
115 return ret;
116 }
117
ByteString(const char * pStr,size_t nLen)118 ByteString::ByteString(const char* pStr, size_t nLen) {
119 if (nLen)
120 m_pData.Reset(StringData::Create(pStr, nLen));
121 }
122
ByteString(const uint8_t * pStr,size_t nLen)123 ByteString::ByteString(const uint8_t* pStr, size_t nLen) {
124 if (nLen)
125 m_pData.Reset(
126 StringData::Create(reinterpret_cast<const char*>(pStr), nLen));
127 }
128
129 ByteString::ByteString() = default;
130
ByteString(const ByteString & other)131 ByteString::ByteString(const ByteString& other) : m_pData(other.m_pData) {}
132
ByteString(ByteString && other)133 ByteString::ByteString(ByteString&& other) noexcept {
134 m_pData.Swap(other.m_pData);
135 }
136
ByteString(char ch)137 ByteString::ByteString(char ch) {
138 m_pData.Reset(StringData::Create(1));
139 m_pData->m_String[0] = ch;
140 }
141
ByteString(const char * ptr)142 ByteString::ByteString(const char* ptr)
143 : ByteString(ptr, ptr ? strlen(ptr) : 0) {}
144
ByteString(ByteStringView bstrc)145 ByteString::ByteString(ByteStringView bstrc) {
146 if (!bstrc.IsEmpty()) {
147 m_pData.Reset(
148 StringData::Create(bstrc.unterminated_c_str(), bstrc.GetLength()));
149 }
150 }
151
ByteString(ByteStringView str1,ByteStringView str2)152 ByteString::ByteString(ByteStringView str1, ByteStringView str2) {
153 FX_SAFE_SIZE_T nSafeLen = str1.GetLength();
154 nSafeLen += str2.GetLength();
155
156 size_t nNewLen = nSafeLen.ValueOrDie();
157 if (nNewLen == 0)
158 return;
159
160 m_pData.Reset(StringData::Create(nNewLen));
161 m_pData->CopyContents(str1.unterminated_c_str(), str1.GetLength());
162 m_pData->CopyContentsAt(str1.GetLength(), str2.unterminated_c_str(),
163 str2.GetLength());
164 }
165
ByteString(const std::initializer_list<ByteStringView> & list)166 ByteString::ByteString(const std::initializer_list<ByteStringView>& list) {
167 FX_SAFE_SIZE_T nSafeLen = 0;
168 for (const auto& item : list)
169 nSafeLen += item.GetLength();
170
171 size_t nNewLen = nSafeLen.ValueOrDie();
172 if (nNewLen == 0)
173 return;
174
175 m_pData.Reset(StringData::Create(nNewLen));
176
177 size_t nOffset = 0;
178 for (const auto& item : list) {
179 m_pData->CopyContentsAt(nOffset, item.unterminated_c_str(),
180 item.GetLength());
181 nOffset += item.GetLength();
182 }
183 }
184
ByteString(const std::ostringstream & outStream)185 ByteString::ByteString(const std::ostringstream& outStream) {
186 std::string str = outStream.str();
187 if (str.length() > 0)
188 m_pData.Reset(StringData::Create(str.c_str(), str.length()));
189 }
190
~ByteString()191 ByteString::~ByteString() {}
192
operator =(const char * str)193 ByteString& ByteString::operator=(const char* str) {
194 if (!str || !str[0])
195 clear();
196 else
197 AssignCopy(str, strlen(str));
198
199 return *this;
200 }
201
operator =(ByteStringView str)202 ByteString& ByteString::operator=(ByteStringView str) {
203 if (str.IsEmpty())
204 clear();
205 else
206 AssignCopy(str.unterminated_c_str(), str.GetLength());
207
208 return *this;
209 }
210
operator =(const ByteString & that)211 ByteString& ByteString::operator=(const ByteString& that) {
212 if (m_pData != that.m_pData)
213 m_pData = that.m_pData;
214
215 return *this;
216 }
217
operator =(ByteString && that)218 ByteString& ByteString::operator=(ByteString&& that) {
219 if (m_pData != that.m_pData)
220 m_pData = std::move(that.m_pData);
221
222 return *this;
223 }
224
operator +=(const char * str)225 ByteString& ByteString::operator+=(const char* str) {
226 if (str)
227 Concat(str, strlen(str));
228
229 return *this;
230 }
231
operator +=(char ch)232 ByteString& ByteString::operator+=(char ch) {
233 Concat(&ch, 1);
234 return *this;
235 }
236
operator +=(const ByteString & str)237 ByteString& ByteString::operator+=(const ByteString& str) {
238 if (str.m_pData)
239 Concat(str.m_pData->m_String, str.m_pData->m_nDataLength);
240
241 return *this;
242 }
243
operator +=(ByteStringView str)244 ByteString& ByteString::operator+=(ByteStringView str) {
245 if (!str.IsEmpty())
246 Concat(str.unterminated_c_str(), str.GetLength());
247
248 return *this;
249 }
250
operator ==(const char * ptr) const251 bool ByteString::operator==(const char* ptr) const {
252 if (!m_pData)
253 return !ptr || !ptr[0];
254
255 if (!ptr)
256 return m_pData->m_nDataLength == 0;
257
258 return strlen(ptr) == m_pData->m_nDataLength &&
259 memcmp(ptr, m_pData->m_String, m_pData->m_nDataLength) == 0;
260 }
261
operator ==(ByteStringView str) const262 bool ByteString::operator==(ByteStringView str) const {
263 if (!m_pData)
264 return str.IsEmpty();
265
266 return m_pData->m_nDataLength == str.GetLength() &&
267 memcmp(m_pData->m_String, str.unterminated_c_str(), str.GetLength()) ==
268 0;
269 }
270
operator ==(const ByteString & other) const271 bool ByteString::operator==(const ByteString& other) const {
272 if (m_pData == other.m_pData)
273 return true;
274
275 if (IsEmpty())
276 return other.IsEmpty();
277
278 if (other.IsEmpty())
279 return false;
280
281 return other.m_pData->m_nDataLength == m_pData->m_nDataLength &&
282 memcmp(other.m_pData->m_String, m_pData->m_String,
283 m_pData->m_nDataLength) == 0;
284 }
285
operator <(const char * ptr) const286 bool ByteString::operator<(const char* ptr) const {
287 if (!m_pData && !ptr)
288 return false;
289 if (c_str() == ptr)
290 return false;
291
292 size_t len = GetLength();
293 size_t other_len = ptr ? strlen(ptr) : 0;
294 int result = memcmp(c_str(), ptr, std::min(len, other_len));
295 return result < 0 || (result == 0 && len < other_len);
296 }
297
operator <(ByteStringView str) const298 bool ByteString::operator<(ByteStringView str) const {
299 return Compare(str) < 0;
300 }
301
operator <(const ByteString & other) const302 bool ByteString::operator<(const ByteString& other) const {
303 if (m_pData == other.m_pData)
304 return false;
305
306 size_t len = GetLength();
307 size_t other_len = other.GetLength();
308 int result = memcmp(c_str(), other.c_str(), std::min(len, other_len));
309 return result < 0 || (result == 0 && len < other_len);
310 }
311
EqualNoCase(ByteStringView str) const312 bool ByteString::EqualNoCase(ByteStringView str) const {
313 if (!m_pData)
314 return str.IsEmpty();
315
316 size_t len = str.GetLength();
317 if (m_pData->m_nDataLength != len)
318 return false;
319
320 const uint8_t* pThis = (const uint8_t*)m_pData->m_String;
321 const uint8_t* pThat = str.raw_str();
322 for (size_t i = 0; i < len; i++) {
323 if ((*pThis) != (*pThat)) {
324 uint8_t bThis = tolower(*pThis);
325 uint8_t bThat = tolower(*pThat);
326 if (bThis != bThat)
327 return false;
328 }
329 pThis++;
330 pThat++;
331 }
332 return true;
333 }
334
AssignCopy(const char * pSrcData,size_t nSrcLen)335 void ByteString::AssignCopy(const char* pSrcData, size_t nSrcLen) {
336 AllocBeforeWrite(nSrcLen);
337 m_pData->CopyContents(pSrcData, nSrcLen);
338 m_pData->m_nDataLength = nSrcLen;
339 }
340
ReallocBeforeWrite(size_t nNewLength)341 void ByteString::ReallocBeforeWrite(size_t nNewLength) {
342 if (m_pData && m_pData->CanOperateInPlace(nNewLength))
343 return;
344
345 if (nNewLength == 0) {
346 clear();
347 return;
348 }
349
350 RetainPtr<StringData> pNewData(StringData::Create(nNewLength));
351 if (m_pData) {
352 size_t nCopyLength = std::min(m_pData->m_nDataLength, nNewLength);
353 pNewData->CopyContents(m_pData->m_String, nCopyLength);
354 pNewData->m_nDataLength = nCopyLength;
355 } else {
356 pNewData->m_nDataLength = 0;
357 }
358 pNewData->m_String[pNewData->m_nDataLength] = 0;
359 m_pData.Swap(pNewData);
360 }
361
AllocBeforeWrite(size_t nNewLength)362 void ByteString::AllocBeforeWrite(size_t nNewLength) {
363 if (m_pData && m_pData->CanOperateInPlace(nNewLength))
364 return;
365
366 if (nNewLength == 0) {
367 clear();
368 return;
369 }
370
371 m_pData.Reset(StringData::Create(nNewLength));
372 }
373
ReleaseBuffer(size_t nNewLength)374 void ByteString::ReleaseBuffer(size_t nNewLength) {
375 if (!m_pData)
376 return;
377
378 nNewLength = std::min(nNewLength, m_pData->m_nAllocLength);
379 if (nNewLength == 0) {
380 clear();
381 return;
382 }
383
384 ASSERT(m_pData->m_nRefs == 1);
385 m_pData->m_nDataLength = nNewLength;
386 m_pData->m_String[nNewLength] = 0;
387 if (m_pData->m_nAllocLength - nNewLength >= 32) {
388 // Over arbitrary threshold, so pay the price to relocate. Force copy to
389 // always occur by holding a second reference to the string.
390 ByteString preserve(*this);
391 ReallocBeforeWrite(nNewLength);
392 }
393 }
394
Reserve(size_t len)395 void ByteString::Reserve(size_t len) {
396 GetBuffer(len);
397 }
398
GetBuffer(size_t nMinBufLength)399 pdfium::span<char> ByteString::GetBuffer(size_t nMinBufLength) {
400 if (!m_pData) {
401 if (nMinBufLength == 0)
402 return pdfium::span<char>();
403
404 m_pData.Reset(StringData::Create(nMinBufLength));
405 m_pData->m_nDataLength = 0;
406 m_pData->m_String[0] = 0;
407 return pdfium::span<char>(m_pData->m_String, m_pData->m_nAllocLength);
408 }
409
410 if (m_pData->CanOperateInPlace(nMinBufLength))
411 return pdfium::span<char>(m_pData->m_String, m_pData->m_nAllocLength);
412
413 nMinBufLength = std::max(nMinBufLength, m_pData->m_nDataLength);
414 if (nMinBufLength == 0)
415 return pdfium::span<char>();
416
417 RetainPtr<StringData> pNewData(StringData::Create(nMinBufLength));
418 pNewData->CopyContents(*m_pData);
419 pNewData->m_nDataLength = m_pData->m_nDataLength;
420 m_pData.Swap(pNewData);
421 return pdfium::span<char>(m_pData->m_String, m_pData->m_nAllocLength);
422 }
423
Delete(size_t index,size_t count)424 size_t ByteString::Delete(size_t index, size_t count) {
425 if (!m_pData)
426 return 0;
427
428 size_t old_length = m_pData->m_nDataLength;
429 if (count == 0 || index != pdfium::clamp<size_t>(index, 0, old_length))
430 return old_length;
431
432 size_t removal_length = index + count;
433 if (removal_length > old_length)
434 return old_length;
435
436 ReallocBeforeWrite(old_length);
437 size_t chars_to_copy = old_length - removal_length + 1;
438 memmove(m_pData->m_String + index, m_pData->m_String + removal_length,
439 chars_to_copy);
440 m_pData->m_nDataLength = old_length - count;
441 return m_pData->m_nDataLength;
442 }
443
Concat(const char * pSrcData,size_t nSrcLen)444 void ByteString::Concat(const char* pSrcData, size_t nSrcLen) {
445 if (!pSrcData || nSrcLen == 0)
446 return;
447
448 if (!m_pData) {
449 m_pData.Reset(StringData::Create(pSrcData, nSrcLen));
450 return;
451 }
452
453 if (m_pData->CanOperateInPlace(m_pData->m_nDataLength + nSrcLen)) {
454 m_pData->CopyContentsAt(m_pData->m_nDataLength, pSrcData, nSrcLen);
455 m_pData->m_nDataLength += nSrcLen;
456 return;
457 }
458
459 size_t nConcatLen = std::max(m_pData->m_nDataLength / 2, nSrcLen);
460 RetainPtr<StringData> pNewData(
461 StringData::Create(m_pData->m_nDataLength + nConcatLen));
462 pNewData->CopyContents(*m_pData);
463 pNewData->CopyContentsAt(m_pData->m_nDataLength, pSrcData, nSrcLen);
464 pNewData->m_nDataLength = m_pData->m_nDataLength + nSrcLen;
465 m_pData.Swap(pNewData);
466 }
467
ReferenceCountForTesting() const468 intptr_t ByteString::ReferenceCountForTesting() const {
469 return m_pData ? m_pData->m_nRefs : 0;
470 }
471
Substr(size_t first,size_t count) const472 ByteString ByteString::Substr(size_t first, size_t count) const {
473 if (!m_pData)
474 return ByteString();
475
476 if (!IsValidIndex(first))
477 return ByteString();
478
479 if (count == 0 || !IsValidLength(count))
480 return ByteString();
481
482 if (!IsValidIndex(first + count - 1))
483 return ByteString();
484
485 if (first == 0 && count == m_pData->m_nDataLength)
486 return *this;
487
488 ByteString dest;
489 AllocCopy(dest, count, first);
490 return dest;
491 }
492
First(size_t count) const493 ByteString ByteString::First(size_t count) const {
494 if (count == 0 || !IsValidLength(count))
495 return ByteString();
496 return Substr(0, count);
497 }
498
Last(size_t count) const499 ByteString ByteString::Last(size_t count) const {
500 if (count == 0 || !IsValidLength(count))
501 return ByteString();
502 return Substr(GetLength() - count, count);
503 }
504
AllocCopy(ByteString & dest,size_t nCopyLen,size_t nCopyIndex) const505 void ByteString::AllocCopy(ByteString& dest,
506 size_t nCopyLen,
507 size_t nCopyIndex) const {
508 if (nCopyLen == 0)
509 return;
510
511 RetainPtr<StringData> pNewData(
512 StringData::Create(m_pData->m_String + nCopyIndex, nCopyLen));
513 dest.m_pData.Swap(pNewData);
514 }
515
SetAt(size_t index,char c)516 void ByteString::SetAt(size_t index, char c) {
517 ASSERT(IsValidIndex(index));
518 ReallocBeforeWrite(m_pData->m_nDataLength);
519 m_pData->m_String[index] = c;
520 }
521
Insert(size_t index,char ch)522 size_t ByteString::Insert(size_t index, char ch) {
523 const size_t cur_length = GetLength();
524 if (!IsValidLength(index))
525 return cur_length;
526
527 const size_t new_length = cur_length + 1;
528 ReallocBeforeWrite(new_length);
529 memmove(m_pData->m_String + index + 1, m_pData->m_String + index,
530 new_length - index);
531 m_pData->m_String[index] = ch;
532 m_pData->m_nDataLength = new_length;
533 return new_length;
534 }
535
Find(char ch,size_t start) const536 Optional<size_t> ByteString::Find(char ch, size_t start) const {
537 if (!m_pData)
538 return pdfium::nullopt;
539
540 if (!IsValidIndex(start))
541 return pdfium::nullopt;
542
543 const char* pStr = static_cast<const char*>(
544 memchr(m_pData->m_String + start, ch, m_pData->m_nDataLength - start));
545 return pStr ? Optional<size_t>(static_cast<size_t>(pStr - m_pData->m_String))
546 : pdfium::nullopt;
547 }
548
Find(ByteStringView subStr,size_t start) const549 Optional<size_t> ByteString::Find(ByteStringView subStr, size_t start) const {
550 if (!m_pData)
551 return pdfium::nullopt;
552
553 if (!IsValidIndex(start))
554 return pdfium::nullopt;
555
556 const char* pStr =
557 FX_strstr(m_pData->m_String + start, m_pData->m_nDataLength - start,
558 subStr.unterminated_c_str(), subStr.GetLength());
559 return pStr ? Optional<size_t>(static_cast<size_t>(pStr - m_pData->m_String))
560 : pdfium::nullopt;
561 }
562
ReverseFind(char ch) const563 Optional<size_t> ByteString::ReverseFind(char ch) const {
564 if (!m_pData)
565 return pdfium::nullopt;
566
567 size_t nLength = m_pData->m_nDataLength;
568 while (nLength--) {
569 if (m_pData->m_String[nLength] == ch)
570 return nLength;
571 }
572 return pdfium::nullopt;
573 }
574
MakeLower()575 void ByteString::MakeLower() {
576 if (!m_pData)
577 return;
578
579 ReallocBeforeWrite(m_pData->m_nDataLength);
580 FXSYS_strlwr(m_pData->m_String);
581 }
582
MakeUpper()583 void ByteString::MakeUpper() {
584 if (!m_pData)
585 return;
586
587 ReallocBeforeWrite(m_pData->m_nDataLength);
588 FXSYS_strupr(m_pData->m_String);
589 }
590
Remove(char chRemove)591 size_t ByteString::Remove(char chRemove) {
592 if (!m_pData || m_pData->m_nDataLength == 0)
593 return 0;
594
595 char* pstrSource = m_pData->m_String;
596 char* pstrEnd = m_pData->m_String + m_pData->m_nDataLength;
597 while (pstrSource < pstrEnd) {
598 if (*pstrSource == chRemove)
599 break;
600 pstrSource++;
601 }
602 if (pstrSource == pstrEnd)
603 return 0;
604
605 ptrdiff_t copied = pstrSource - m_pData->m_String;
606 ReallocBeforeWrite(m_pData->m_nDataLength);
607 pstrSource = m_pData->m_String + copied;
608 pstrEnd = m_pData->m_String + m_pData->m_nDataLength;
609
610 char* pstrDest = pstrSource;
611 while (pstrSource < pstrEnd) {
612 if (*pstrSource != chRemove) {
613 *pstrDest = *pstrSource;
614 pstrDest++;
615 }
616 pstrSource++;
617 }
618
619 *pstrDest = 0;
620 size_t nCount = static_cast<size_t>(pstrSource - pstrDest);
621 m_pData->m_nDataLength -= nCount;
622 return nCount;
623 }
624
Replace(ByteStringView pOld,ByteStringView pNew)625 size_t ByteString::Replace(ByteStringView pOld, ByteStringView pNew) {
626 if (!m_pData || pOld.IsEmpty())
627 return 0;
628
629 size_t nSourceLen = pOld.GetLength();
630 size_t nReplacementLen = pNew.GetLength();
631 size_t nCount = 0;
632 const char* pStart = m_pData->m_String;
633 char* pEnd = m_pData->m_String + m_pData->m_nDataLength;
634 while (1) {
635 const char* pTarget = FX_strstr(pStart, static_cast<int>(pEnd - pStart),
636 pOld.unterminated_c_str(), nSourceLen);
637 if (!pTarget)
638 break;
639
640 nCount++;
641 pStart = pTarget + nSourceLen;
642 }
643 if (nCount == 0)
644 return 0;
645
646 size_t nNewLength =
647 m_pData->m_nDataLength + (nReplacementLen - nSourceLen) * nCount;
648
649 if (nNewLength == 0) {
650 clear();
651 return nCount;
652 }
653
654 RetainPtr<StringData> pNewData(StringData::Create(nNewLength));
655 pStart = m_pData->m_String;
656 char* pDest = pNewData->m_String;
657 for (size_t i = 0; i < nCount; i++) {
658 const char* pTarget = FX_strstr(pStart, static_cast<int>(pEnd - pStart),
659 pOld.unterminated_c_str(), nSourceLen);
660 memcpy(pDest, pStart, pTarget - pStart);
661 pDest += pTarget - pStart;
662 memcpy(pDest, pNew.unterminated_c_str(), pNew.GetLength());
663 pDest += pNew.GetLength();
664 pStart = pTarget + nSourceLen;
665 }
666 memcpy(pDest, pStart, pEnd - pStart);
667 m_pData.Swap(pNewData);
668 return nCount;
669 }
670
Compare(ByteStringView str) const671 int ByteString::Compare(ByteStringView str) const {
672 if (!m_pData)
673 return str.IsEmpty() ? 0 : -1;
674
675 size_t this_len = m_pData->m_nDataLength;
676 size_t that_len = str.GetLength();
677 size_t min_len = std::min(this_len, that_len);
678 int result = memcmp(m_pData->m_String, str.unterminated_c_str(), min_len);
679 if (result != 0)
680 return result;
681 if (this_len == that_len)
682 return 0;
683 return this_len < that_len ? -1 : 1;
684 }
685
Trim()686 void ByteString::Trim() {
687 TrimRight(kTrimChars);
688 TrimLeft(kTrimChars);
689 }
690
Trim(char target)691 void ByteString::Trim(char target) {
692 ByteStringView targets(target);
693 TrimRight(targets);
694 TrimLeft(targets);
695 }
696
Trim(ByteStringView targets)697 void ByteString::Trim(ByteStringView targets) {
698 TrimRight(targets);
699 TrimLeft(targets);
700 }
701
TrimLeft()702 void ByteString::TrimLeft() {
703 TrimLeft(kTrimChars);
704 }
705
TrimLeft(char target)706 void ByteString::TrimLeft(char target) {
707 TrimLeft(ByteStringView(target));
708 }
709
TrimLeft(ByteStringView targets)710 void ByteString::TrimLeft(ByteStringView targets) {
711 if (!m_pData || targets.IsEmpty())
712 return;
713
714 size_t len = GetLength();
715 if (len == 0)
716 return;
717
718 size_t pos = 0;
719 while (pos < len) {
720 size_t i = 0;
721 while (i < targets.GetLength() && targets[i] != m_pData->m_String[pos])
722 i++;
723 if (i == targets.GetLength())
724 break;
725 pos++;
726 }
727 if (pos) {
728 ReallocBeforeWrite(len);
729 size_t nDataLength = len - pos;
730 memmove(m_pData->m_String, m_pData->m_String + pos,
731 (nDataLength + 1) * sizeof(char));
732 m_pData->m_nDataLength = nDataLength;
733 }
734 }
735
TrimRight()736 void ByteString::TrimRight() {
737 TrimRight(kTrimChars);
738 }
739
TrimRight(char target)740 void ByteString::TrimRight(char target) {
741 TrimRight(ByteStringView(target));
742 }
743
TrimRight(ByteStringView targets)744 void ByteString::TrimRight(ByteStringView targets) {
745 if (!m_pData || targets.IsEmpty())
746 return;
747
748 size_t pos = GetLength();
749 if (pos == 0)
750 return;
751
752 while (pos) {
753 size_t i = 0;
754 while (i < targets.GetLength() && targets[i] != m_pData->m_String[pos - 1])
755 i++;
756 if (i == targets.GetLength())
757 break;
758 pos--;
759 }
760 if (pos < m_pData->m_nDataLength) {
761 ReallocBeforeWrite(m_pData->m_nDataLength);
762 m_pData->m_String[pos] = 0;
763 m_pData->m_nDataLength = pos;
764 }
765 }
766
operator <<(std::ostream & os,const ByteString & str)767 std::ostream& operator<<(std::ostream& os, const ByteString& str) {
768 return os.write(str.c_str(), str.GetLength());
769 }
770
operator <<(std::ostream & os,ByteStringView str)771 std::ostream& operator<<(std::ostream& os, ByteStringView str) {
772 return os.write(str.unterminated_c_str(), str.GetLength());
773 }
774
775 } // namespace fxcrt
776
FX_HashCode_GetA(ByteStringView str,bool bIgnoreCase)777 uint32_t FX_HashCode_GetA(ByteStringView str, bool bIgnoreCase) {
778 uint32_t dwHashCode = 0;
779 if (bIgnoreCase) {
780 for (ByteStringView::UnsignedType c : str)
781 dwHashCode = 31 * dwHashCode + tolower(c);
782 } else {
783 for (ByteStringView::UnsignedType c : str)
784 dwHashCode = 31 * dwHashCode + c;
785 }
786 return dwHashCode;
787 }
788
FX_HashCode_GetAsIfW(ByteStringView str,bool bIgnoreCase)789 uint32_t FX_HashCode_GetAsIfW(ByteStringView str, bool bIgnoreCase) {
790 uint32_t dwHashCode = 0;
791 if (bIgnoreCase) {
792 for (ByteStringView::UnsignedType c : str)
793 dwHashCode = 1313 * dwHashCode + FXSYS_towlower(c);
794 } else {
795 for (ByteStringView::UnsignedType c : str)
796 dwHashCode = 1313 * dwHashCode + c;
797 }
798 return dwHashCode;
799 }
800