xref: /aosp_15_r20/external/pdfium/core/fxcrt/bytestring.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
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/fx_codepage.h"
18 #include "core/fxcrt/fx_extension.h"
19 #include "core/fxcrt/fx_memcpy_wrappers.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/containers/span.h"
26 #include "third_party/base/numerics/safe_math.h"
27 
28 template class fxcrt::StringDataTemplate<char>;
29 template class fxcrt::StringViewTemplate<char>;
30 template class fxcrt::StringPoolTemplate<ByteString>;
31 template struct std::hash<ByteString>;
32 
33 namespace {
34 
35 constexpr char kTrimChars[] = "\x09\x0a\x0b\x0c\x0d\x20";
36 
FX_strstr(const char * haystack,size_t haystack_len,const char * needle,size_t needle_len)37 const char* FX_strstr(const char* haystack,
38                       size_t haystack_len,
39                       const char* needle,
40                       size_t needle_len) {
41   if (needle_len > haystack_len || needle_len == 0)
42     return nullptr;
43 
44   const char* end_ptr = haystack + haystack_len - needle_len;
45   while (haystack <= end_ptr) {
46     size_t i = 0;
47     while (true) {
48       if (haystack[i] != needle[i])
49         break;
50 
51       i++;
52       if (i == needle_len)
53         return haystack;
54     }
55     haystack++;
56   }
57   return nullptr;
58 }
59 
60 }  // namespace
61 
62 namespace fxcrt {
63 
64 static_assert(sizeof(ByteString) <= sizeof(char*),
65               "Strings must not require more space than pointers");
66 
67 // static
FormatInteger(int i)68 ByteString ByteString::FormatInteger(int i) {
69   char buf[32];
70   FXSYS_snprintf(buf, sizeof(buf), "%d", i);
71   return ByteString(buf);
72 }
73 
74 // static
FormatFloat(float f)75 ByteString ByteString::FormatFloat(float f) {
76   char buf[32];
77   return ByteString(buf, FloatToString(f, buf));
78 }
79 
80 // static
FormatV(const char * pFormat,va_list argList)81 ByteString ByteString::FormatV(const char* pFormat, va_list argList) {
82   va_list argListCopy;
83   va_copy(argListCopy, argList);
84   int nMaxLen = vsnprintf(nullptr, 0, pFormat, argListCopy);
85   va_end(argListCopy);
86 
87   if (nMaxLen <= 0)
88     return ByteString();
89 
90   ByteString ret;
91   {
92     // Span's lifetime must end before ReleaseBuffer() below.
93     pdfium::span<char> buf = ret.GetBuffer(nMaxLen);
94 
95     // In the following two calls, there's always space in the buffer for
96     // a terminating NUL that's not included in nMaxLen.
97     memset(buf.data(), 0, nMaxLen + 1);
98     va_copy(argListCopy, argList);
99     vsnprintf(buf.data(), nMaxLen + 1, pFormat, argListCopy);
100     va_end(argListCopy);
101   }
102   ret.ReleaseBuffer(ret.GetStringLength());
103   return ret;
104 }
105 
106 // static
Format(const char * pFormat,...)107 ByteString ByteString::Format(const char* pFormat, ...) {
108   va_list argList;
109   va_start(argList, pFormat);
110   ByteString ret = FormatV(pFormat, argList);
111   va_end(argList);
112 
113   return ret;
114 }
115 
ByteString(const char * pStr,size_t nLen)116 ByteString::ByteString(const char* pStr, size_t nLen) {
117   if (nLen)
118     m_pData.Reset(StringData::Create(pStr, nLen));
119 }
120 
ByteString(const uint8_t * pStr,size_t nLen)121 ByteString::ByteString(const uint8_t* pStr, size_t nLen) {
122   if (nLen)
123     m_pData.Reset(
124         StringData::Create(reinterpret_cast<const char*>(pStr), nLen));
125 }
126 
127 ByteString::ByteString() = default;
128 
ByteString(const ByteString & other)129 ByteString::ByteString(const ByteString& other) : m_pData(other.m_pData) {}
130 
ByteString(ByteString && other)131 ByteString::ByteString(ByteString&& other) noexcept {
132   m_pData.Swap(other.m_pData);
133 }
134 
ByteString(char ch)135 ByteString::ByteString(char ch) {
136   m_pData.Reset(StringData::Create(1));
137   m_pData->m_String[0] = ch;
138 }
139 
ByteString(const char * ptr)140 ByteString::ByteString(const char* ptr)
141     : ByteString(ptr, ptr ? strlen(ptr) : 0) {}
142 
ByteString(ByteStringView bstrc)143 ByteString::ByteString(ByteStringView bstrc) {
144   if (!bstrc.IsEmpty()) {
145     m_pData.Reset(
146         StringData::Create(bstrc.unterminated_c_str(), bstrc.GetLength()));
147   }
148 }
149 
ByteString(ByteStringView str1,ByteStringView str2)150 ByteString::ByteString(ByteStringView str1, ByteStringView str2) {
151   FX_SAFE_SIZE_T nSafeLen = str1.GetLength();
152   nSafeLen += str2.GetLength();
153 
154   size_t nNewLen = nSafeLen.ValueOrDie();
155   if (nNewLen == 0)
156     return;
157 
158   m_pData.Reset(StringData::Create(nNewLen));
159   m_pData->CopyContents(str1.unterminated_c_str(), str1.GetLength());
160   m_pData->CopyContentsAt(str1.GetLength(), str2.unterminated_c_str(),
161                           str2.GetLength());
162 }
163 
ByteString(const std::initializer_list<ByteStringView> & list)164 ByteString::ByteString(const std::initializer_list<ByteStringView>& list) {
165   FX_SAFE_SIZE_T nSafeLen = 0;
166   for (const auto& item : list)
167     nSafeLen += item.GetLength();
168 
169   size_t nNewLen = nSafeLen.ValueOrDie();
170   if (nNewLen == 0)
171     return;
172 
173   m_pData.Reset(StringData::Create(nNewLen));
174 
175   size_t nOffset = 0;
176   for (const auto& item : list) {
177     m_pData->CopyContentsAt(nOffset, item.unterminated_c_str(),
178                             item.GetLength());
179     nOffset += item.GetLength();
180   }
181 }
182 
ByteString(const fxcrt::ostringstream & outStream)183 ByteString::ByteString(const fxcrt::ostringstream& outStream) {
184   auto str = outStream.str();
185   if (!str.empty())
186     m_pData.Reset(StringData::Create(str.c_str(), str.size()));
187 }
188 
189 ByteString::~ByteString() = default;
190 
clear()191 void ByteString::clear() {
192   if (m_pData && m_pData->CanOperateInPlace(0)) {
193     m_pData->m_nDataLength = 0;
194     return;
195   }
196   m_pData.Reset();
197 }
198 
operator =(const char * str)199 ByteString& ByteString::operator=(const char* str) {
200   if (!str || !str[0])
201     clear();
202   else
203     AssignCopy(str, strlen(str));
204 
205   return *this;
206 }
207 
operator =(ByteStringView str)208 ByteString& ByteString::operator=(ByteStringView str) {
209   if (str.IsEmpty())
210     clear();
211   else
212     AssignCopy(str.unterminated_c_str(), str.GetLength());
213 
214   return *this;
215 }
216 
operator =(const ByteString & that)217 ByteString& ByteString::operator=(const ByteString& that) {
218   if (m_pData != that.m_pData)
219     m_pData = that.m_pData;
220 
221   return *this;
222 }
223 
operator =(ByteString && that)224 ByteString& ByteString::operator=(ByteString&& that) noexcept {
225   if (m_pData != that.m_pData)
226     m_pData = std::move(that.m_pData);
227 
228   return *this;
229 }
230 
operator +=(const char * str)231 ByteString& ByteString::operator+=(const char* str) {
232   if (str)
233     Concat(str, strlen(str));
234 
235   return *this;
236 }
237 
operator +=(char ch)238 ByteString& ByteString::operator+=(char ch) {
239   Concat(&ch, 1);
240   return *this;
241 }
242 
operator +=(const ByteString & str)243 ByteString& ByteString::operator+=(const ByteString& str) {
244   if (str.m_pData)
245     Concat(str.m_pData->m_String, str.m_pData->m_nDataLength);
246 
247   return *this;
248 }
249 
operator +=(ByteStringView str)250 ByteString& ByteString::operator+=(ByteStringView str) {
251   if (!str.IsEmpty())
252     Concat(str.unterminated_c_str(), str.GetLength());
253 
254   return *this;
255 }
256 
operator ==(const char * ptr) const257 bool ByteString::operator==(const char* ptr) const {
258   if (!m_pData)
259     return !ptr || !ptr[0];
260 
261   if (!ptr)
262     return m_pData->m_nDataLength == 0;
263 
264   return strlen(ptr) == m_pData->m_nDataLength &&
265          FXSYS_memcmp(ptr, m_pData->m_String, m_pData->m_nDataLength) == 0;
266 }
267 
operator ==(ByteStringView str) const268 bool ByteString::operator==(ByteStringView str) const {
269   if (!m_pData)
270     return str.IsEmpty();
271 
272   return m_pData->m_nDataLength == str.GetLength() &&
273          FXSYS_memcmp(m_pData->m_String, str.unterminated_c_str(),
274                       str.GetLength()) == 0;
275 }
276 
operator ==(const ByteString & other) const277 bool ByteString::operator==(const ByteString& other) const {
278   if (m_pData == other.m_pData)
279     return true;
280 
281   if (IsEmpty())
282     return other.IsEmpty();
283 
284   if (other.IsEmpty())
285     return false;
286 
287   return other.m_pData->m_nDataLength == m_pData->m_nDataLength &&
288          memcmp(other.m_pData->m_String, m_pData->m_String,
289                 m_pData->m_nDataLength) == 0;
290 }
291 
operator <(const char * ptr) const292 bool ByteString::operator<(const char* ptr) const {
293   if (!m_pData && !ptr)
294     return false;
295   if (c_str() == ptr)
296     return false;
297 
298   size_t len = GetLength();
299   size_t other_len = ptr ? strlen(ptr) : 0;
300   int result = FXSYS_memcmp(c_str(), ptr, std::min(len, other_len));
301   return result < 0 || (result == 0 && len < other_len);
302 }
303 
operator <(ByteStringView str) const304 bool ByteString::operator<(ByteStringView str) const {
305   return Compare(str) < 0;
306 }
307 
operator <(const ByteString & other) const308 bool ByteString::operator<(const ByteString& other) const {
309   if (m_pData == other.m_pData)
310     return false;
311 
312   size_t len = GetLength();
313   size_t other_len = other.GetLength();
314   int result = FXSYS_memcmp(c_str(), other.c_str(), std::min(len, other_len));
315   return result < 0 || (result == 0 && len < other_len);
316 }
317 
EqualNoCase(ByteStringView str) const318 bool ByteString::EqualNoCase(ByteStringView str) const {
319   if (!m_pData)
320     return str.IsEmpty();
321 
322   size_t len = str.GetLength();
323   if (m_pData->m_nDataLength != len)
324     return false;
325 
326   const uint8_t* pThis = (const uint8_t*)m_pData->m_String;
327   const uint8_t* pThat = str.raw_str();
328   for (size_t i = 0; i < len; i++) {
329     if ((*pThis) != (*pThat)) {
330       uint8_t bThis = tolower(*pThis);
331       uint8_t bThat = tolower(*pThat);
332       if (bThis != bThat)
333         return false;
334     }
335     pThis++;
336     pThat++;
337   }
338   return true;
339 }
340 
AssignCopy(const char * pSrcData,size_t nSrcLen)341 void ByteString::AssignCopy(const char* pSrcData, size_t nSrcLen) {
342   AllocBeforeWrite(nSrcLen);
343   m_pData->CopyContents(pSrcData, nSrcLen);
344   m_pData->m_nDataLength = nSrcLen;
345 }
346 
ReallocBeforeWrite(size_t nNewLength)347 void ByteString::ReallocBeforeWrite(size_t nNewLength) {
348   if (m_pData && m_pData->CanOperateInPlace(nNewLength))
349     return;
350 
351   if (nNewLength == 0) {
352     clear();
353     return;
354   }
355 
356   RetainPtr<StringData> pNewData(StringData::Create(nNewLength));
357   if (m_pData) {
358     size_t nCopyLength = std::min(m_pData->m_nDataLength, nNewLength);
359     pNewData->CopyContents(m_pData->m_String, nCopyLength);
360     pNewData->m_nDataLength = nCopyLength;
361   } else {
362     pNewData->m_nDataLength = 0;
363   }
364   pNewData->m_String[pNewData->m_nDataLength] = 0;
365   m_pData.Swap(pNewData);
366 }
367 
AllocBeforeWrite(size_t nNewLength)368 void ByteString::AllocBeforeWrite(size_t nNewLength) {
369   if (m_pData && m_pData->CanOperateInPlace(nNewLength))
370     return;
371 
372   if (nNewLength == 0) {
373     clear();
374     return;
375   }
376 
377   m_pData.Reset(StringData::Create(nNewLength));
378 }
379 
ReleaseBuffer(size_t nNewLength)380 void ByteString::ReleaseBuffer(size_t nNewLength) {
381   if (!m_pData)
382     return;
383 
384   nNewLength = std::min(nNewLength, m_pData->m_nAllocLength);
385   if (nNewLength == 0) {
386     clear();
387     return;
388   }
389 
390   DCHECK_EQ(m_pData->m_nRefs, 1);
391   m_pData->m_nDataLength = nNewLength;
392   m_pData->m_String[nNewLength] = 0;
393   if (m_pData->m_nAllocLength - nNewLength >= 32) {
394     // Over arbitrary threshold, so pay the price to relocate.  Force copy to
395     // always occur by holding a second reference to the string.
396     ByteString preserve(*this);
397     ReallocBeforeWrite(nNewLength);
398   }
399 }
400 
Reserve(size_t len)401 void ByteString::Reserve(size_t len) {
402   GetBuffer(len);
403 }
404 
GetBuffer(size_t nMinBufLength)405 pdfium::span<char> ByteString::GetBuffer(size_t nMinBufLength) {
406   if (!m_pData) {
407     if (nMinBufLength == 0)
408       return pdfium::span<char>();
409 
410     m_pData.Reset(StringData::Create(nMinBufLength));
411     m_pData->m_nDataLength = 0;
412     m_pData->m_String[0] = 0;
413     return pdfium::span<char>(m_pData->m_String, m_pData->m_nAllocLength);
414   }
415 
416   if (m_pData->CanOperateInPlace(nMinBufLength))
417     return pdfium::span<char>(m_pData->m_String, m_pData->m_nAllocLength);
418 
419   nMinBufLength = std::max(nMinBufLength, m_pData->m_nDataLength);
420   if (nMinBufLength == 0)
421     return pdfium::span<char>();
422 
423   RetainPtr<StringData> pNewData(StringData::Create(nMinBufLength));
424   pNewData->CopyContents(*m_pData);
425   pNewData->m_nDataLength = m_pData->m_nDataLength;
426   m_pData.Swap(pNewData);
427   return pdfium::span<char>(m_pData->m_String, m_pData->m_nAllocLength);
428 }
429 
Delete(size_t index,size_t count)430 size_t ByteString::Delete(size_t index, size_t count) {
431   if (!m_pData)
432     return 0;
433 
434   size_t old_length = m_pData->m_nDataLength;
435   if (count == 0 || index != std::clamp<size_t>(index, 0, old_length)) {
436     return old_length;
437   }
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   FXSYS_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   FXSYS_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*>(FXSYS_memchr(
553       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     FXSYS_memcpy(pDest, pStart, pTarget - pStart);
673     pDest += pTarget - pStart;
674     FXSYS_memcpy(pDest, pNew.unterminated_c_str(), pNew.GetLength());
675     pDest += pNew.GetLength();
676     pStart = pTarget + nSourceLen;
677   }
678   FXSYS_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 =
691       FXSYS_memcmp(m_pData->m_String, str.unterminated_c_str(), min_len);
692   if (result != 0)
693     return result;
694   if (this_len == that_len)
695     return 0;
696   return this_len < that_len ? -1 : 1;
697 }
698 
Trim()699 void ByteString::Trim() {
700   TrimRight(kTrimChars);
701   TrimLeft(kTrimChars);
702 }
703 
Trim(char target)704 void ByteString::Trim(char target) {
705   ByteStringView targets(target);
706   TrimRight(targets);
707   TrimLeft(targets);
708 }
709 
Trim(ByteStringView targets)710 void ByteString::Trim(ByteStringView targets) {
711   TrimRight(targets);
712   TrimLeft(targets);
713 }
714 
TrimLeft()715 void ByteString::TrimLeft() {
716   TrimLeft(kTrimChars);
717 }
718 
TrimLeft(char target)719 void ByteString::TrimLeft(char target) {
720   TrimLeft(ByteStringView(target));
721 }
722 
TrimLeft(ByteStringView targets)723 void ByteString::TrimLeft(ByteStringView targets) {
724   if (!m_pData || targets.IsEmpty())
725     return;
726 
727   size_t len = GetLength();
728   if (len == 0)
729     return;
730 
731   size_t pos = 0;
732   while (pos < len) {
733     size_t i = 0;
734     while (i < targets.GetLength() && targets[i] != m_pData->m_String[pos])
735       i++;
736     if (i == targets.GetLength())
737       break;
738     pos++;
739   }
740   if (pos) {
741     ReallocBeforeWrite(len);
742     size_t nDataLength = len - pos;
743     FXSYS_memmove(m_pData->m_String, m_pData->m_String + pos,
744                   (nDataLength + 1) * sizeof(char));
745     m_pData->m_nDataLength = nDataLength;
746   }
747 }
748 
TrimRight()749 void ByteString::TrimRight() {
750   TrimRight(kTrimChars);
751 }
752 
TrimRight(char target)753 void ByteString::TrimRight(char target) {
754   TrimRight(ByteStringView(target));
755 }
756 
TrimRight(ByteStringView targets)757 void ByteString::TrimRight(ByteStringView targets) {
758   if (!m_pData || targets.IsEmpty())
759     return;
760 
761   size_t pos = GetLength();
762   if (pos == 0)
763     return;
764 
765   while (pos) {
766     size_t i = 0;
767     while (i < targets.GetLength() && targets[i] != m_pData->m_String[pos - 1])
768       i++;
769     if (i == targets.GetLength())
770       break;
771     pos--;
772   }
773   if (pos < m_pData->m_nDataLength) {
774     ReallocBeforeWrite(m_pData->m_nDataLength);
775     m_pData->m_String[pos] = 0;
776     m_pData->m_nDataLength = pos;
777   }
778 }
779 
operator <<(std::ostream & os,const ByteString & str)780 std::ostream& operator<<(std::ostream& os, const ByteString& str) {
781   return os.write(str.c_str(), str.GetLength());
782 }
783 
operator <<(std::ostream & os,ByteStringView str)784 std::ostream& operator<<(std::ostream& os, ByteStringView str) {
785   return os.write(str.unterminated_c_str(), str.GetLength());
786 }
787 
788 }  // namespace fxcrt
789 
FX_HashCode_GetA(ByteStringView str)790 uint32_t FX_HashCode_GetA(ByteStringView str) {
791   uint32_t dwHashCode = 0;
792   for (ByteStringView::UnsignedType c : str)
793     dwHashCode = 31 * dwHashCode + c;
794   return dwHashCode;
795 }
796 
FX_HashCode_GetLoweredA(ByteStringView str)797 uint32_t FX_HashCode_GetLoweredA(ByteStringView str) {
798   uint32_t dwHashCode = 0;
799   for (ByteStringView::UnsignedType c : str)
800     dwHashCode = 31 * dwHashCode + tolower(c);
801   return dwHashCode;
802 }
803 
FX_HashCode_GetAsIfW(ByteStringView str)804 uint32_t FX_HashCode_GetAsIfW(ByteStringView str) {
805   uint32_t dwHashCode = 0;
806   for (ByteStringView::UnsignedType c : str)
807     dwHashCode = 1313 * dwHashCode + c;
808   return dwHashCode;
809 }
810 
FX_HashCode_GetLoweredAsIfW(ByteStringView str)811 uint32_t FX_HashCode_GetLoweredAsIfW(ByteStringView str) {
812   uint32_t dwHashCode = 0;
813   for (ByteStringView::UnsignedType c : str)
814     dwHashCode = 1313 * dwHashCode + FXSYS_towlower(c);
815   return dwHashCode;
816 }
817