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