• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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