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