7#include "core/fxcrt/bytestring.h"
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"
30template struct std::hash<ByteString>;
34constexpr char kTrimChars[] =
"\x09\x0a\x0b\x0c\x0d\x20";
36const char* FX_strstr(
const char* haystack,
40 if (needle_len > haystack_len || needle_len == 0)
43 const char* end_ptr = haystack + haystack_len - needle_len;
44 while (haystack <= end_ptr) {
47 if (haystack[i] != needle[i])
63static_assert(
sizeof(
ByteString) <=
sizeof(
char*),
64 "Strings must not require more space than pointers");
76 return ByteString(buf, FloatToString(f, buf));
82 va_copy(argListCopy, argList);
83 int nMaxLen = vsnprintf(
nullptr, 0, pFormat, argListCopy);
92 pdfium::span<
char> buf = ret.GetBuffer(nMaxLen);
96 memset(buf.data(), 0, nMaxLen + 1);
97 va_copy(argListCopy, argList);
98 vsnprintf(buf.data(), nMaxLen + 1, pFormat, argListCopy);
101 ret.ReleaseBuffer(ret.GetStringLength());
108 va_start(argList, pFormat);
117 m_pData.Reset(StringData::Create(pStr, nLen));
123 StringData::Create(
reinterpret_cast<
const char*>(pStr), nLen));
131 m_pData.Swap(other.m_pData);
135 m_pData.Reset(StringData::Create(1));
136 m_pData->m_String[0] = ch;
143 if (!bstrc.IsEmpty()) {
145 StringData::Create(bstrc.unterminated_c_str(), bstrc.GetLength()));
150 FX_SAFE_SIZE_T nSafeLen = str1.GetLength();
151 nSafeLen += str2.GetLength();
153 size_t nNewLen = nSafeLen.ValueOrDie();
157 m_pData.Reset(StringData::Create(nNewLen));
158 m_pData->CopyContents(str1.unterminated_c_str(), str1.GetLength());
159 m_pData->CopyContentsAt(str1.GetLength(), str2.unterminated_c_str(),
164 FX_SAFE_SIZE_T nSafeLen = 0;
165 for (
const auto& item : list)
166 nSafeLen += item.GetLength();
168 size_t nNewLen = nSafeLen.ValueOrDie();
172 m_pData.Reset(StringData::Create(nNewLen));
175 for (
const auto& item : list) {
176 m_pData->CopyContentsAt(nOffset, item.unterminated_c_str(),
178 nOffset += item.GetLength();
183 auto str = outStream.str();
185 m_pData.Reset(StringData::Create(str.c_str(), str.size()));
191 if (m_pData && m_pData->CanOperateInPlace(0)) {
192 m_pData->m_nDataLength = 0;
202 AssignCopy(str, strlen(str));
211 AssignCopy(str.unterminated_c_str(), str.GetLength());
217 if (m_pData != that.m_pData)
218 m_pData = that.m_pData;
224 if (m_pData != that.m_pData)
225 m_pData = std::move(that.m_pData);
232 Concat(str, strlen(str));
244 Concat(str.m_pData->m_String, str.m_pData->m_nDataLength);
251 Concat(str.unterminated_c_str(), str.GetLength());
258 return !ptr || !ptr[0];
261 return m_pData->m_nDataLength == 0;
263 return strlen(ptr) == m_pData->m_nDataLength &&
264 FXSYS_memcmp(ptr, m_pData->m_String, m_pData->m_nDataLength) == 0;
269 return str.IsEmpty();
271 return m_pData->m_nDataLength == str.GetLength() &&
272 FXSYS_memcmp(m_pData->m_String, str.unterminated_c_str(),
273 str.GetLength()) == 0;
277 if (m_pData == other.m_pData)
286 return other.m_pData->m_nDataLength == m_pData->m_nDataLength &&
287 memcmp(other.m_pData->m_String, m_pData->m_String,
288 m_pData->m_nDataLength) == 0;
292 if (!m_pData && !ptr)
297 size_t len = GetLength();
298 size_t other_len = ptr ? strlen(ptr) : 0;
299 int result = FXSYS_memcmp(c_str(), ptr, std::min(len, other_len));
300 return result < 0 || (result == 0 && len < other_len);
308 if (m_pData == other.m_pData)
311 size_t len = GetLength();
312 size_t other_len = other.GetLength();
313 int result = FXSYS_memcmp(c_str(), other.c_str(), std::min(len, other_len));
314 return result < 0 || (result == 0 && len < other_len);
319 return str.IsEmpty();
321 size_t len = str.GetLength();
322 if (m_pData->m_nDataLength != len)
325 const uint8_t* pThis = (
const uint8_t*)m_pData->m_String;
326 const uint8_t* pThat = str.raw_str();
327 for (size_t i = 0; i < len; i++) {
328 if ((*pThis) != (*pThat)) {
329 uint8_t this_char = tolower(*pThis);
330 uint8_t that_char = tolower(*pThat);
331 if (this_char != that_char) {
342 AllocBeforeWrite(nSrcLen);
343 m_pData->CopyContents(pSrcData, nSrcLen);
344 m_pData->m_nDataLength = nSrcLen;
348 if (m_pData && m_pData->CanOperateInPlace(nNewLength))
351 if (nNewLength == 0) {
356 RetainPtr<StringData> pNewData(StringData::Create(nNewLength));
358 size_t nCopyLength = std::min(m_pData->m_nDataLength, nNewLength);
359 pNewData->CopyContents(m_pData->m_String, nCopyLength);
360 pNewData->m_nDataLength = nCopyLength;
362 pNewData->m_nDataLength = 0;
364 pNewData->m_String[pNewData->m_nDataLength] = 0;
365 m_pData.Swap(pNewData);
369 if (m_pData && m_pData->CanOperateInPlace(nNewLength))
372 if (nNewLength == 0) {
377 m_pData.Reset(StringData::Create(nNewLength));
384 nNewLength = std::min(nNewLength, m_pData->m_nAllocLength);
385 if (nNewLength == 0) {
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) {
397 ReallocBeforeWrite(nNewLength);
407 if (nMinBufLength == 0)
408 return pdfium::span<
char>();
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);
416 if (m_pData->CanOperateInPlace(nMinBufLength))
417 return pdfium::span<
char>(m_pData->m_String, m_pData->m_nAllocLength);
419 nMinBufLength = std::max(nMinBufLength, m_pData->m_nDataLength);
420 if (nMinBufLength == 0)
421 return pdfium::span<
char>();
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);
434 size_t old_length = m_pData->m_nDataLength;
435 if (count == 0 || index != std::clamp<size_t>(index, 0, old_length)) {
439 size_t removal_length = index + count;
440 if (removal_length > old_length)
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,
447 m_pData->m_nDataLength = old_length - count;
448 return m_pData->m_nDataLength;
452 if (!pSrcData || nSrcLen == 0)
456 m_pData.Reset(StringData::Create(pSrcData, nSrcLen));
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;
466 size_t nConcatLen = std::max(m_pData->m_nDataLength / 2, nSrcLen);
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);
476 return m_pData ? m_pData->m_nRefs : 0;
481 return Substr(offset, GetLength() - offset);
488 if (!IsValidIndex(first))
491 if (count == 0 || !IsValidLength(count))
494 if (!IsValidIndex(first + count - 1))
497 if (first == 0 && count == m_pData->m_nDataLength)
501 AllocCopy(dest, count, first);
506 return Substr(0, count);
511 return Substr(GetLength() - count, count);
516 size_t nCopyIndex)
const {
521 StringData::Create(m_pData->m_String + nCopyIndex, nCopyLen));
522 dest.m_pData.Swap(pNewData);
526 DCHECK(IsValidIndex(index));
527 ReallocBeforeWrite(m_pData->m_nDataLength);
528 m_pData->m_String[index] = c;
532 const size_t cur_length = GetLength();
533 if (!IsValidLength(index))
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,
540 m_pData->m_String[index] = ch;
541 m_pData->m_nDataLength = new_length;
547 return absl::nullopt;
549 if (!IsValidIndex(start))
550 return absl::nullopt;
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))
560 size_t start)
const {
562 return absl::nullopt;
564 if (!IsValidIndex(start))
565 return absl::nullopt;
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))
577 return absl::nullopt;
579 size_t nLength = m_pData->m_nDataLength;
581 if (m_pData->m_String[nLength] == ch)
584 return absl::nullopt;
591 ReallocBeforeWrite(m_pData->m_nDataLength);
592 FXSYS_strlwr(m_pData->m_String);
599 ReallocBeforeWrite(m_pData->m_nDataLength);
600 FXSYS_strupr(m_pData->m_String);
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)
614 if (pstrSource == pstrEnd)
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;
622 char* pstrDest = pstrSource;
623 while (pstrSource < pstrEnd) {
624 if (*pstrSource != chRemove) {
625 *pstrDest = *pstrSource;
632 size_t nCount =
static_cast<size_t>(pstrSource - pstrDest);
633 m_pData->m_nDataLength -= nCount;
638 if (!m_pData || pOld.IsEmpty())
641 size_t nSourceLen = pOld.GetLength();
642 size_t nReplacementLen = pNew.GetLength();
644 const char* pStart = m_pData->m_String;
645 char* pEnd = m_pData->m_String + m_pData->m_nDataLength;
647 const char* pTarget = FX_strstr(pStart,
static_cast<
int>(pEnd - pStart),
648 pOld.unterminated_c_str(), nSourceLen);
653 pStart = pTarget + nSourceLen;
659 m_pData->m_nDataLength + (nReplacementLen - nSourceLen) * nCount;
661 if (nNewLength == 0) {
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);
673 pDest += pTarget - pStart;
674 FXSYS_memcpy(pDest, pNew.unterminated_c_str(), pNew.GetLength());
675 pDest += pNew.GetLength();
676 pStart = pTarget + nSourceLen;
679 m_pData.Swap(pNewData);
685 return str.IsEmpty() ? 0 : -1;
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);
691 FXSYS_memcmp(m_pData->m_String, str.unterminated_c_str(), min_len);
694 if (this_len == that_len)
696 return this_len < that_len ? -1 : 1;
700 TrimRight(kTrimChars);
701 TrimLeft(kTrimChars);
705 ByteStringView targets(target);
716 TrimLeft(kTrimChars);
724 if (!m_pData || targets.IsEmpty())
727 size_t len = GetLength();
734 while (i < targets.GetLength() && targets[i] != m_pData->m_String[pos])
736 if (i == targets.GetLength())
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;
750 TrimRight(kTrimChars);
758 if (!m_pData || targets.IsEmpty())
761 size_t pos = GetLength();
767 while (i < targets.GetLength() && targets[i] != m_pData->m_String[pos - 1])
769 if (i == targets.GetLength())
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;
781 return os.write(str
.c_str(), str.GetLength());
784std::ostream& operator<<(
std::ostream& os, ByteStringView str) {
785 return os.write(str.unterminated_c_str(), str.GetLength());
791 uint32_t dwHashCode = 0;
792 for (ByteStringView::UnsignedType c : str)
793 dwHashCode = 31 * dwHashCode + c;
798 uint32_t dwHashCode = 0;
799 for (ByteStringView::UnsignedType c : str)
800 dwHashCode = 31 * dwHashCode + tolower(c);
805 uint32_t dwHashCode = 0;
806 for (ByteStringView::UnsignedType c : str)
807 dwHashCode = 1313 * dwHashCode + c;
812 uint32_t dwHashCode = 0;
813 for (ByteStringView::UnsignedType c : str)
814 dwHashCode = 1313 * dwHashCode + FXSYS_towlower(c);
uint32_t FX_HashCode_GetLoweredAsIfW(ByteStringView str)
uint32_t FX_HashCode_GetLoweredA(ByteStringView str)
uint32_t FX_HashCode_GetAsIfW(ByteStringView str)
uint32_t FX_HashCode_GetA(ByteStringView str)
void TrimLeft(ByteStringView targets)
static ByteString FormatFloat(float f)
ByteString(const char *ptr)
bool EqualNoCase(ByteStringView str) const
static ByteString Format(const char *pFormat,...)
ByteString & operator+=(const ByteString &str)
ByteString Substr(size_t first, size_t count) const
bool operator==(ByteStringView str) const
void AllocCopy(ByteString &dest, size_t nCopyLen, size_t nCopyIndex) const
void AssignCopy(const char *pSrcData, size_t nSrcLen)
absl::optional< size_t > ReverseFind(char ch) const
intptr_t ReferenceCountForTesting() const
size_t Delete(size_t index, size_t count=1)
ByteString & operator+=(char ch)
void ReallocBeforeWrite(size_t nNewLen)
ByteString(ByteStringView bstrc)
static ByteString FormatInteger(int i)
pdfium::span< char > GetBuffer(size_t nMinBufLength)
bool operator==(const ByteString &other) const
bool operator==(const char *ptr) const
ByteString(const ByteString &other)
ByteString(const char *pStr, size_t len)
bool operator<(ByteStringView str) const
ByteString & operator+=(const char *str)
ByteString & operator+=(ByteStringView str)
ByteString(const uint8_t *pStr, size_t len)
size_t Replace(ByteStringView pOld, ByteStringView pNew)
absl::optional< size_t > Find(ByteStringView subStr, size_t start=0) const
void SetAt(size_t index, char c)
ByteString & operator=(ByteStringView str)
ByteString(ByteStringView str1, ByteStringView str2)
void Trim(ByteStringView targets)
ByteString & operator=(const char *str)
static ByteString FormatV(const char *pFormat, va_list argList)
void TrimRight(char target)
const char * c_str() const
ByteString Substr(size_t offset) const
ByteString & operator=(const ByteString &that)
ByteString & operator=(ByteString &&that) noexcept
void TrimRight(ByteStringView targets)
bool operator<(const ByteString &other) const
ByteString(const std::initializer_list< ByteStringView > &list)
int Compare(ByteStringView str) const
size_t Insert(size_t index, char ch)
void ReleaseBuffer(size_t nNewLength)
ByteString(const fxcrt::ostringstream &outStream)
void TrimLeft(char target)
ByteString First(size_t count) const
void AllocBeforeWrite(size_t nNewLen)
bool operator<(const char *ptr) const
void Concat(const char *pSrcData, size_t nSrcLen)
absl::optional< size_t > Find(char ch, size_t start=0) const
ByteString(ByteString &&other) noexcept
ByteString Last(size_t count) const
void * FXSYS_memcpy(void *ptr1, const void *ptr2, size_t len)