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 <stddef.h> 8 9 #include <algorithm> 10 #include <cctype> 11 12 #include "core/fxcrt/cfx_string_pool_template.h" 13 #include "core/fxcrt/fx_basic.h" 14 #include "third_party/base/numerics/safe_math.h" 15 16 template class CFX_StringDataTemplate<FX_CHAR>; 17 template class CFX_StringCTemplate<FX_CHAR>; 18 template class CFX_StringPoolTemplate<CFX_ByteString>; 19 template struct std::hash<CFX_ByteString>; 20 21 namespace { 22 23 int Buffer_itoa(char* buf, int i, uint32_t flags) { 24 if (i == 0) { 25 buf[0] = '0'; 26 return 1; 27 } 28 char buf1[32]; 29 int buf_pos = 31; 30 uint32_t u = i; 31 if ((flags & FXFORMAT_SIGNED) && i < 0) { 32 u = -i; 33 } 34 int base = 10; 35 const FX_CHAR* str = "0123456789abcdef"; 36 if (flags & FXFORMAT_HEX) { 37 base = 16; 38 if (flags & FXFORMAT_CAPITAL) { 39 str = "0123456789ABCDEF"; 40 } 41 } 42 while (u != 0) { 43 buf1[buf_pos--] = str[u % base]; 44 u = u / base; 45 } 46 if ((flags & FXFORMAT_SIGNED) && i < 0) { 47 buf1[buf_pos--] = '-'; 48 } 49 int len = 31 - buf_pos; 50 for (int ii = 0; ii < len; ii++) { 51 buf[ii] = buf1[ii + buf_pos + 1]; 52 } 53 return len; 54 } 55 56 const FX_CHAR* FX_strstr(const FX_CHAR* haystack, 57 int haystack_len, 58 const FX_CHAR* needle, 59 int needle_len) { 60 if (needle_len > haystack_len || needle_len == 0) { 61 return nullptr; 62 } 63 const FX_CHAR* end_ptr = haystack + haystack_len - needle_len; 64 while (haystack <= end_ptr) { 65 int i = 0; 66 while (1) { 67 if (haystack[i] != needle[i]) { 68 break; 69 } 70 i++; 71 if (i == needle_len) { 72 return haystack; 73 } 74 } 75 haystack++; 76 } 77 return nullptr; 78 } 79 80 } // namespace 81 82 static_assert(sizeof(CFX_ByteString) <= sizeof(FX_CHAR*), 83 "Strings must not require more space than pointers"); 84 85 CFX_ByteString::CFX_ByteString(const FX_CHAR* pStr, FX_STRSIZE nLen) { 86 if (nLen < 0) 87 nLen = pStr ? FXSYS_strlen(pStr) : 0; 88 89 if (nLen) 90 m_pData.Reset(StringData::Create(pStr, nLen)); 91 } 92 93 CFX_ByteString::CFX_ByteString(const uint8_t* pStr, FX_STRSIZE nLen) { 94 if (nLen > 0) { 95 m_pData.Reset( 96 StringData::Create(reinterpret_cast<const FX_CHAR*>(pStr), nLen)); 97 } 98 } 99 100 CFX_ByteString::CFX_ByteString() {} 101 102 CFX_ByteString::CFX_ByteString(const CFX_ByteString& other) 103 : m_pData(other.m_pData) {} 104 105 CFX_ByteString::CFX_ByteString(CFX_ByteString&& other) { 106 m_pData.Swap(other.m_pData); 107 } 108 109 CFX_ByteString::CFX_ByteString(char ch) { 110 m_pData.Reset(StringData::Create(1)); 111 m_pData->m_String[0] = ch; 112 } 113 114 CFX_ByteString::CFX_ByteString(const FX_CHAR* ptr) 115 : CFX_ByteString(ptr, ptr ? FXSYS_strlen(ptr) : 0) {} 116 117 CFX_ByteString::CFX_ByteString(const CFX_ByteStringC& stringSrc) { 118 if (!stringSrc.IsEmpty()) 119 m_pData.Reset(StringData::Create(stringSrc.c_str(), stringSrc.GetLength())); 120 } 121 122 CFX_ByteString::CFX_ByteString(const CFX_ByteStringC& str1, 123 const CFX_ByteStringC& str2) { 124 int nNewLen = str1.GetLength() + str2.GetLength(); 125 if (nNewLen == 0) 126 return; 127 128 m_pData.Reset(StringData::Create(nNewLen)); 129 m_pData->CopyContents(str1.c_str(), str1.GetLength()); 130 m_pData->CopyContentsAt(str1.GetLength(), str2.c_str(), str2.GetLength()); 131 } 132 133 CFX_ByteString::~CFX_ByteString() {} 134 135 const CFX_ByteString& CFX_ByteString::operator=(const FX_CHAR* pStr) { 136 if (!pStr || !pStr[0]) 137 clear(); 138 else 139 AssignCopy(pStr, FXSYS_strlen(pStr)); 140 141 return *this; 142 } 143 144 const CFX_ByteString& CFX_ByteString::operator=( 145 const CFX_ByteStringC& stringSrc) { 146 if (stringSrc.IsEmpty()) 147 clear(); 148 else 149 AssignCopy(stringSrc.c_str(), stringSrc.GetLength()); 150 151 return *this; 152 } 153 154 const CFX_ByteString& CFX_ByteString::operator=( 155 const CFX_ByteString& stringSrc) { 156 if (m_pData != stringSrc.m_pData) 157 m_pData = stringSrc.m_pData; 158 159 return *this; 160 } 161 162 const CFX_ByteString& CFX_ByteString::operator+=(const FX_CHAR* pStr) { 163 if (pStr) 164 Concat(pStr, FXSYS_strlen(pStr)); 165 166 return *this; 167 } 168 169 const CFX_ByteString& CFX_ByteString::operator+=(char ch) { 170 Concat(&ch, 1); 171 return *this; 172 } 173 174 const CFX_ByteString& CFX_ByteString::operator+=(const CFX_ByteString& str) { 175 if (str.m_pData) 176 Concat(str.m_pData->m_String, str.m_pData->m_nDataLength); 177 178 return *this; 179 } 180 181 const CFX_ByteString& CFX_ByteString::operator+=(const CFX_ByteStringC& str) { 182 if (!str.IsEmpty()) 183 Concat(str.c_str(), str.GetLength()); 184 185 return *this; 186 } 187 188 bool CFX_ByteString::operator==(const char* ptr) const { 189 if (!m_pData) 190 return !ptr || !ptr[0]; 191 192 if (!ptr) 193 return m_pData->m_nDataLength == 0; 194 195 return FXSYS_strlen(ptr) == m_pData->m_nDataLength && 196 FXSYS_memcmp(ptr, m_pData->m_String, m_pData->m_nDataLength) == 0; 197 } 198 199 bool CFX_ByteString::operator==(const CFX_ByteStringC& str) const { 200 if (!m_pData) 201 return str.IsEmpty(); 202 203 return m_pData->m_nDataLength == str.GetLength() && 204 FXSYS_memcmp(m_pData->m_String, str.c_str(), str.GetLength()) == 0; 205 } 206 207 bool CFX_ByteString::operator==(const CFX_ByteString& other) const { 208 if (m_pData == other.m_pData) 209 return true; 210 211 if (IsEmpty()) 212 return other.IsEmpty(); 213 214 if (other.IsEmpty()) 215 return false; 216 217 return other.m_pData->m_nDataLength == m_pData->m_nDataLength && 218 FXSYS_memcmp(other.m_pData->m_String, m_pData->m_String, 219 m_pData->m_nDataLength) == 0; 220 } 221 222 bool CFX_ByteString::operator<(const CFX_ByteString& str) const { 223 if (m_pData == str.m_pData) 224 return false; 225 226 int result = FXSYS_memcmp(c_str(), str.c_str(), 227 std::min(GetLength(), str.GetLength())); 228 return result < 0 || (result == 0 && GetLength() < str.GetLength()); 229 } 230 231 bool CFX_ByteString::EqualNoCase(const CFX_ByteStringC& str) const { 232 if (!m_pData) 233 return str.IsEmpty(); 234 235 FX_STRSIZE len = str.GetLength(); 236 if (m_pData->m_nDataLength != len) 237 return false; 238 239 const uint8_t* pThis = (const uint8_t*)m_pData->m_String; 240 const uint8_t* pThat = str.raw_str(); 241 for (FX_STRSIZE i = 0; i < len; i++) { 242 if ((*pThis) != (*pThat)) { 243 uint8_t bThis = *pThis; 244 if (bThis >= 'A' && bThis <= 'Z') 245 bThis += 'a' - 'A'; 246 247 uint8_t bThat = *pThat; 248 if (bThat >= 'A' && bThat <= 'Z') 249 bThat += 'a' - 'A'; 250 251 if (bThis != bThat) 252 return false; 253 } 254 pThis++; 255 pThat++; 256 } 257 return true; 258 } 259 260 void CFX_ByteString::AssignCopy(const FX_CHAR* pSrcData, FX_STRSIZE nSrcLen) { 261 AllocBeforeWrite(nSrcLen); 262 m_pData->CopyContents(pSrcData, nSrcLen); 263 m_pData->m_nDataLength = nSrcLen; 264 } 265 266 void CFX_ByteString::ReallocBeforeWrite(FX_STRSIZE nNewLength) { 267 if (m_pData && m_pData->CanOperateInPlace(nNewLength)) 268 return; 269 270 if (nNewLength <= 0) { 271 clear(); 272 return; 273 } 274 275 CFX_RetainPtr<StringData> pNewData(StringData::Create(nNewLength)); 276 if (m_pData) { 277 FX_STRSIZE nCopyLength = std::min(m_pData->m_nDataLength, nNewLength); 278 pNewData->CopyContents(m_pData->m_String, nCopyLength); 279 pNewData->m_nDataLength = nCopyLength; 280 } else { 281 pNewData->m_nDataLength = 0; 282 } 283 pNewData->m_String[pNewData->m_nDataLength] = 0; 284 m_pData.Swap(pNewData); 285 } 286 287 void CFX_ByteString::AllocBeforeWrite(FX_STRSIZE nNewLength) { 288 if (m_pData && m_pData->CanOperateInPlace(nNewLength)) 289 return; 290 291 if (nNewLength <= 0) { 292 clear(); 293 return; 294 } 295 296 m_pData.Reset(StringData::Create(nNewLength)); 297 } 298 299 void CFX_ByteString::ReleaseBuffer(FX_STRSIZE nNewLength) { 300 if (!m_pData) 301 return; 302 303 if (nNewLength == -1) 304 nNewLength = FXSYS_strlen(m_pData->m_String); 305 306 nNewLength = std::min(nNewLength, m_pData->m_nAllocLength); 307 if (nNewLength == 0) { 308 clear(); 309 return; 310 } 311 312 ASSERT(m_pData->m_nRefs == 1); 313 m_pData->m_nDataLength = nNewLength; 314 m_pData->m_String[nNewLength] = 0; 315 if (m_pData->m_nAllocLength - nNewLength >= 32) { 316 // Over arbitrary threshold, so pay the price to relocate. Force copy to 317 // always occur by holding a second reference to the string. 318 CFX_ByteString preserve(*this); 319 ReallocBeforeWrite(nNewLength); 320 } 321 } 322 323 void CFX_ByteString::Reserve(FX_STRSIZE len) { 324 GetBuffer(len); 325 } 326 327 FX_CHAR* CFX_ByteString::GetBuffer(FX_STRSIZE nMinBufLength) { 328 if (!m_pData) { 329 if (nMinBufLength == 0) 330 return nullptr; 331 332 m_pData.Reset(StringData::Create(nMinBufLength)); 333 m_pData->m_nDataLength = 0; 334 m_pData->m_String[0] = 0; 335 return m_pData->m_String; 336 } 337 338 if (m_pData->CanOperateInPlace(nMinBufLength)) 339 return m_pData->m_String; 340 341 nMinBufLength = std::max(nMinBufLength, m_pData->m_nDataLength); 342 if (nMinBufLength == 0) 343 return nullptr; 344 345 CFX_RetainPtr<StringData> pNewData(StringData::Create(nMinBufLength)); 346 pNewData->CopyContents(*m_pData); 347 pNewData->m_nDataLength = m_pData->m_nDataLength; 348 m_pData.Swap(pNewData); 349 return m_pData->m_String; 350 } 351 352 FX_STRSIZE CFX_ByteString::Delete(FX_STRSIZE nIndex, FX_STRSIZE nCount) { 353 if (!m_pData) 354 return 0; 355 356 if (nIndex < 0) 357 nIndex = 0; 358 359 FX_STRSIZE nOldLength = m_pData->m_nDataLength; 360 if (nCount > 0 && nIndex < nOldLength) { 361 FX_STRSIZE mLength = nIndex + nCount; 362 if (mLength >= nOldLength) { 363 m_pData->m_nDataLength = nIndex; 364 return m_pData->m_nDataLength; 365 } 366 ReallocBeforeWrite(nOldLength); 367 int nCharsToCopy = nOldLength - mLength + 1; 368 FXSYS_memmove(m_pData->m_String + nIndex, m_pData->m_String + mLength, 369 nCharsToCopy); 370 m_pData->m_nDataLength = nOldLength - nCount; 371 } 372 return m_pData->m_nDataLength; 373 } 374 375 void CFX_ByteString::Concat(const FX_CHAR* pSrcData, FX_STRSIZE nSrcLen) { 376 if (!pSrcData || nSrcLen <= 0) 377 return; 378 379 if (!m_pData) { 380 m_pData.Reset(StringData::Create(pSrcData, nSrcLen)); 381 return; 382 } 383 384 if (m_pData->CanOperateInPlace(m_pData->m_nDataLength + nSrcLen)) { 385 m_pData->CopyContentsAt(m_pData->m_nDataLength, pSrcData, nSrcLen); 386 m_pData->m_nDataLength += nSrcLen; 387 return; 388 } 389 390 CFX_RetainPtr<StringData> pNewData( 391 StringData::Create(m_pData->m_nDataLength + nSrcLen)); 392 pNewData->CopyContents(*m_pData); 393 pNewData->CopyContentsAt(m_pData->m_nDataLength, pSrcData, nSrcLen); 394 m_pData.Swap(pNewData); 395 } 396 397 CFX_ByteString CFX_ByteString::Mid(FX_STRSIZE nFirst) const { 398 if (!m_pData) 399 return CFX_ByteString(); 400 401 return Mid(nFirst, m_pData->m_nDataLength - nFirst); 402 } 403 404 CFX_ByteString CFX_ByteString::Mid(FX_STRSIZE nFirst, FX_STRSIZE nCount) const { 405 if (!m_pData) 406 return CFX_ByteString(); 407 408 nFirst = std::min(std::max(nFirst, 0), m_pData->m_nDataLength); 409 nCount = std::min(std::max(nCount, 0), m_pData->m_nDataLength - nFirst); 410 if (nCount == 0) 411 return CFX_ByteString(); 412 413 if (nFirst == 0 && nCount == m_pData->m_nDataLength) 414 return *this; 415 416 CFX_ByteString dest; 417 AllocCopy(dest, nCount, nFirst); 418 return dest; 419 } 420 421 void CFX_ByteString::AllocCopy(CFX_ByteString& dest, 422 FX_STRSIZE nCopyLen, 423 FX_STRSIZE nCopyIndex) const { 424 if (nCopyLen <= 0) 425 return; 426 427 CFX_RetainPtr<StringData> pNewData( 428 StringData::Create(m_pData->m_String + nCopyIndex, nCopyLen)); 429 dest.m_pData.Swap(pNewData); 430 } 431 432 #define FORCE_ANSI 0x10000 433 #define FORCE_UNICODE 0x20000 434 #define FORCE_INT64 0x40000 435 436 CFX_ByteString CFX_ByteString::FormatInteger(int i, uint32_t flags) { 437 char buf[32]; 438 return CFX_ByteString(buf, Buffer_itoa(buf, i, flags)); 439 } 440 441 void CFX_ByteString::FormatV(const FX_CHAR* pFormat, va_list argList) { 442 va_list argListSave; 443 #if defined(__ARMCC_VERSION) || \ 444 (!defined(_MSC_VER) && (_FX_CPU_ == _FX_X64_ || _FX_CPU_ == _FX_IA64_ || \ 445 _FX_CPU_ == _FX_ARM64_)) || \ 446 defined(__native_client__) 447 va_copy(argListSave, argList); 448 #else 449 argListSave = argList; 450 #endif 451 int nMaxLen = 0; 452 for (const FX_CHAR* pStr = pFormat; *pStr != 0; pStr++) { 453 if (*pStr != '%' || *(pStr = pStr + 1) == '%') { 454 nMaxLen += FXSYS_strlen(pStr); 455 continue; 456 } 457 int nItemLen = 0; 458 int nWidth = 0; 459 for (; *pStr != 0; pStr++) { 460 if (*pStr == '#') { 461 nMaxLen += 2; 462 } else if (*pStr == '*') { 463 nWidth = va_arg(argList, int); 464 } else if (*pStr != '-' && *pStr != '+' && *pStr != '0' && *pStr != ' ') { 465 break; 466 } 467 } 468 if (nWidth == 0) { 469 nWidth = FXSYS_atoi(pStr); 470 while (std::isdigit(*pStr)) 471 pStr++; 472 } 473 if (nWidth < 0 || nWidth > 128 * 1024) { 474 pFormat = "Bad width"; 475 nMaxLen = 10; 476 break; 477 } 478 int nPrecision = 0; 479 if (*pStr == '.') { 480 pStr++; 481 if (*pStr == '*') { 482 nPrecision = va_arg(argList, int); 483 pStr++; 484 } else { 485 nPrecision = FXSYS_atoi(pStr); 486 while (std::isdigit(*pStr)) 487 pStr++; 488 } 489 } 490 if (nPrecision < 0 || nPrecision > 128 * 1024) { 491 pFormat = "Bad precision"; 492 nMaxLen = 14; 493 break; 494 } 495 int nModifier = 0; 496 if (FXSYS_strncmp(pStr, "I64", 3) == 0) { 497 pStr += 3; 498 nModifier = FORCE_INT64; 499 } else { 500 switch (*pStr) { 501 case 'h': 502 nModifier = FORCE_ANSI; 503 pStr++; 504 break; 505 case 'l': 506 nModifier = FORCE_UNICODE; 507 pStr++; 508 break; 509 case 'F': 510 case 'N': 511 case 'L': 512 pStr++; 513 break; 514 } 515 } 516 switch (*pStr | nModifier) { 517 case 'c': 518 case 'C': 519 nItemLen = 2; 520 va_arg(argList, int); 521 break; 522 case 'c' | FORCE_ANSI: 523 case 'C' | FORCE_ANSI: 524 nItemLen = 2; 525 va_arg(argList, int); 526 break; 527 case 'c' | FORCE_UNICODE: 528 case 'C' | FORCE_UNICODE: 529 nItemLen = 2; 530 va_arg(argList, int); 531 break; 532 case 's': { 533 const FX_CHAR* pstrNextArg = va_arg(argList, const FX_CHAR*); 534 if (pstrNextArg) { 535 nItemLen = FXSYS_strlen(pstrNextArg); 536 if (nItemLen < 1) { 537 nItemLen = 1; 538 } 539 } else { 540 nItemLen = 6; 541 } 542 } break; 543 case 'S': { 544 FX_WCHAR* pstrNextArg = va_arg(argList, FX_WCHAR*); 545 if (pstrNextArg) { 546 nItemLen = FXSYS_wcslen(pstrNextArg); 547 if (nItemLen < 1) { 548 nItemLen = 1; 549 } 550 } else { 551 nItemLen = 6; 552 } 553 } break; 554 case 's' | FORCE_ANSI: 555 case 'S' | FORCE_ANSI: { 556 const FX_CHAR* pstrNextArg = va_arg(argList, const FX_CHAR*); 557 if (pstrNextArg) { 558 nItemLen = FXSYS_strlen(pstrNextArg); 559 if (nItemLen < 1) { 560 nItemLen = 1; 561 } 562 } else { 563 nItemLen = 6; 564 } 565 } break; 566 case 's' | FORCE_UNICODE: 567 case 'S' | FORCE_UNICODE: { 568 FX_WCHAR* pstrNextArg = va_arg(argList, FX_WCHAR*); 569 if (pstrNextArg) { 570 nItemLen = FXSYS_wcslen(pstrNextArg); 571 if (nItemLen < 1) { 572 nItemLen = 1; 573 } 574 } else { 575 nItemLen = 6; 576 } 577 } break; 578 } 579 if (nItemLen != 0) { 580 if (nPrecision != 0 && nItemLen > nPrecision) { 581 nItemLen = nPrecision; 582 } 583 if (nItemLen < nWidth) { 584 nItemLen = nWidth; 585 } 586 } else { 587 switch (*pStr) { 588 case 'd': 589 case 'i': 590 case 'u': 591 case 'x': 592 case 'X': 593 case 'o': 594 if (nModifier & FORCE_INT64) { 595 va_arg(argList, int64_t); 596 } else { 597 va_arg(argList, int); 598 } 599 nItemLen = 32; 600 if (nItemLen < nWidth + nPrecision) { 601 nItemLen = nWidth + nPrecision; 602 } 603 break; 604 case 'a': 605 case 'A': 606 case 'e': 607 case 'E': 608 case 'g': 609 case 'G': 610 va_arg(argList, double); 611 nItemLen = 128; 612 if (nItemLen < nWidth + nPrecision) { 613 nItemLen = nWidth + nPrecision; 614 } 615 break; 616 case 'f': 617 if (nWidth + nPrecision > 100) { 618 nItemLen = nPrecision + nWidth + 128; 619 } else { 620 char pszTemp[256]; 621 double f = va_arg(argList, double); 622 memset(pszTemp, 0, sizeof(pszTemp)); 623 FXSYS_snprintf(pszTemp, sizeof(pszTemp) - 1, "%*.*f", nWidth, 624 nPrecision + 6, f); 625 nItemLen = FXSYS_strlen(pszTemp); 626 } 627 break; 628 case 'p': 629 va_arg(argList, void*); 630 nItemLen = 32; 631 if (nItemLen < nWidth + nPrecision) { 632 nItemLen = nWidth + nPrecision; 633 } 634 break; 635 case 'n': 636 va_arg(argList, int*); 637 break; 638 } 639 } 640 nMaxLen += nItemLen; 641 } 642 nMaxLen += 32; // Fudge factor. 643 GetBuffer(nMaxLen); 644 if (m_pData) { 645 memset(m_pData->m_String, 0, nMaxLen); 646 FXSYS_vsnprintf(m_pData->m_String, nMaxLen - 1, pFormat, argListSave); 647 ReleaseBuffer(); 648 } 649 va_end(argListSave); 650 } 651 652 void CFX_ByteString::Format(const FX_CHAR* pFormat, ...) { 653 va_list argList; 654 va_start(argList, pFormat); 655 FormatV(pFormat, argList); 656 va_end(argList); 657 } 658 659 FX_STRSIZE CFX_ByteString::Insert(FX_STRSIZE nIndex, FX_CHAR ch) { 660 FX_STRSIZE nNewLength = m_pData ? m_pData->m_nDataLength : 0; 661 nIndex = std::max(nIndex, 0); 662 nIndex = std::min(nIndex, nNewLength); 663 nNewLength++; 664 665 ReallocBeforeWrite(nNewLength); 666 FXSYS_memmove(m_pData->m_String + nIndex + 1, m_pData->m_String + nIndex, 667 nNewLength - nIndex); 668 m_pData->m_String[nIndex] = ch; 669 m_pData->m_nDataLength = nNewLength; 670 return nNewLength; 671 } 672 673 CFX_ByteString CFX_ByteString::Right(FX_STRSIZE nCount) const { 674 if (!m_pData) 675 return CFX_ByteString(); 676 677 nCount = std::max(nCount, 0); 678 if (nCount >= m_pData->m_nDataLength) 679 return *this; 680 681 CFX_ByteString dest; 682 AllocCopy(dest, nCount, m_pData->m_nDataLength - nCount); 683 return dest; 684 } 685 686 CFX_ByteString CFX_ByteString::Left(FX_STRSIZE nCount) const { 687 if (!m_pData) 688 return CFX_ByteString(); 689 690 nCount = std::max(nCount, 0); 691 if (nCount >= m_pData->m_nDataLength) 692 return *this; 693 694 CFX_ByteString dest; 695 AllocCopy(dest, nCount, 0); 696 return dest; 697 } 698 699 FX_STRSIZE CFX_ByteString::Find(FX_CHAR ch, FX_STRSIZE nStart) const { 700 if (!m_pData) 701 return -1; 702 703 if (nStart < 0 || nStart >= m_pData->m_nDataLength) 704 return -1; 705 706 const FX_CHAR* pStr = static_cast<const FX_CHAR*>( 707 memchr(m_pData->m_String + nStart, ch, m_pData->m_nDataLength - nStart)); 708 return pStr ? pStr - m_pData->m_String : -1; 709 } 710 711 FX_STRSIZE CFX_ByteString::ReverseFind(FX_CHAR ch) const { 712 if (!m_pData) 713 return -1; 714 715 FX_STRSIZE nLength = m_pData->m_nDataLength; 716 while (nLength--) { 717 if (m_pData->m_String[nLength] == ch) 718 return nLength; 719 } 720 return -1; 721 } 722 723 FX_STRSIZE CFX_ByteString::Find(const CFX_ByteStringC& pSub, 724 FX_STRSIZE nStart) const { 725 if (!m_pData) 726 return -1; 727 728 FX_STRSIZE nLength = m_pData->m_nDataLength; 729 if (nStart > nLength) 730 return -1; 731 732 const FX_CHAR* pStr = 733 FX_strstr(m_pData->m_String + nStart, m_pData->m_nDataLength - nStart, 734 pSub.c_str(), pSub.GetLength()); 735 return pStr ? (int)(pStr - m_pData->m_String) : -1; 736 } 737 738 void CFX_ByteString::MakeLower() { 739 if (!m_pData) 740 return; 741 742 ReallocBeforeWrite(m_pData->m_nDataLength); 743 FXSYS_strlwr(m_pData->m_String); 744 } 745 746 void CFX_ByteString::MakeUpper() { 747 if (!m_pData) 748 return; 749 750 ReallocBeforeWrite(m_pData->m_nDataLength); 751 FXSYS_strupr(m_pData->m_String); 752 } 753 754 FX_STRSIZE CFX_ByteString::Remove(FX_CHAR chRemove) { 755 if (!m_pData || m_pData->m_nDataLength < 1) 756 return 0; 757 758 FX_CHAR* pstrSource = m_pData->m_String; 759 FX_CHAR* pstrEnd = m_pData->m_String + m_pData->m_nDataLength; 760 while (pstrSource < pstrEnd) { 761 if (*pstrSource == chRemove) 762 break; 763 pstrSource++; 764 } 765 if (pstrSource == pstrEnd) 766 return 0; 767 768 ptrdiff_t copied = pstrSource - m_pData->m_String; 769 ReallocBeforeWrite(m_pData->m_nDataLength); 770 pstrSource = m_pData->m_String + copied; 771 pstrEnd = m_pData->m_String + m_pData->m_nDataLength; 772 773 FX_CHAR* pstrDest = pstrSource; 774 while (pstrSource < pstrEnd) { 775 if (*pstrSource != chRemove) { 776 *pstrDest = *pstrSource; 777 pstrDest++; 778 } 779 pstrSource++; 780 } 781 782 *pstrDest = 0; 783 FX_STRSIZE nCount = (FX_STRSIZE)(pstrSource - pstrDest); 784 m_pData->m_nDataLength -= nCount; 785 return nCount; 786 } 787 788 FX_STRSIZE CFX_ByteString::Replace(const CFX_ByteStringC& pOld, 789 const CFX_ByteStringC& pNew) { 790 if (!m_pData || pOld.IsEmpty()) 791 return 0; 792 793 FX_STRSIZE nSourceLen = pOld.GetLength(); 794 FX_STRSIZE nReplacementLen = pNew.GetLength(); 795 FX_STRSIZE nCount = 0; 796 const FX_CHAR* pStart = m_pData->m_String; 797 FX_CHAR* pEnd = m_pData->m_String + m_pData->m_nDataLength; 798 while (1) { 799 const FX_CHAR* pTarget = FX_strstr(pStart, (FX_STRSIZE)(pEnd - pStart), 800 pOld.c_str(), nSourceLen); 801 if (!pTarget) 802 break; 803 804 nCount++; 805 pStart = pTarget + nSourceLen; 806 } 807 if (nCount == 0) 808 return 0; 809 810 FX_STRSIZE nNewLength = 811 m_pData->m_nDataLength + (nReplacementLen - nSourceLen) * nCount; 812 813 if (nNewLength == 0) { 814 clear(); 815 return nCount; 816 } 817 818 CFX_RetainPtr<StringData> pNewData(StringData::Create(nNewLength)); 819 pStart = m_pData->m_String; 820 FX_CHAR* pDest = pNewData->m_String; 821 for (FX_STRSIZE i = 0; i < nCount; i++) { 822 const FX_CHAR* pTarget = FX_strstr(pStart, (FX_STRSIZE)(pEnd - pStart), 823 pOld.c_str(), nSourceLen); 824 FXSYS_memcpy(pDest, pStart, pTarget - pStart); 825 pDest += pTarget - pStart; 826 FXSYS_memcpy(pDest, pNew.c_str(), pNew.GetLength()); 827 pDest += pNew.GetLength(); 828 pStart = pTarget + nSourceLen; 829 } 830 FXSYS_memcpy(pDest, pStart, pEnd - pStart); 831 m_pData.Swap(pNewData); 832 return nCount; 833 } 834 835 void CFX_ByteString::SetAt(FX_STRSIZE nIndex, FX_CHAR ch) { 836 if (!m_pData) { 837 return; 838 } 839 ASSERT(nIndex >= 0); 840 ASSERT(nIndex < m_pData->m_nDataLength); 841 ReallocBeforeWrite(m_pData->m_nDataLength); 842 m_pData->m_String[nIndex] = ch; 843 } 844 845 CFX_WideString CFX_ByteString::UTF8Decode() const { 846 CFX_UTF8Decoder decoder; 847 for (FX_STRSIZE i = 0; i < GetLength(); i++) { 848 decoder.Input((uint8_t)m_pData->m_String[i]); 849 } 850 return CFX_WideString(decoder.GetResult()); 851 } 852 853 // static 854 CFX_ByteString CFX_ByteString::FromUnicode(const FX_WCHAR* str, 855 FX_STRSIZE len) { 856 FX_STRSIZE str_len = len >= 0 ? len : FXSYS_wcslen(str); 857 return FromUnicode(CFX_WideString(str, str_len)); 858 } 859 860 // static 861 CFX_ByteString CFX_ByteString::FromUnicode(const CFX_WideString& str) { 862 return CFX_CharMap::GetByteString(0, str.AsStringC()); 863 } 864 865 int CFX_ByteString::Compare(const CFX_ByteStringC& str) const { 866 if (!m_pData) { 867 return str.IsEmpty() ? 0 : -1; 868 } 869 int this_len = m_pData->m_nDataLength; 870 int that_len = str.GetLength(); 871 int min_len = this_len < that_len ? this_len : that_len; 872 for (int i = 0; i < min_len; i++) { 873 if ((uint8_t)m_pData->m_String[i] < str.GetAt(i)) { 874 return -1; 875 } 876 if ((uint8_t)m_pData->m_String[i] > str.GetAt(i)) { 877 return 1; 878 } 879 } 880 if (this_len < that_len) { 881 return -1; 882 } 883 if (this_len > that_len) { 884 return 1; 885 } 886 return 0; 887 } 888 889 void CFX_ByteString::TrimRight(const CFX_ByteStringC& pTargets) { 890 if (!m_pData || pTargets.IsEmpty()) { 891 return; 892 } 893 FX_STRSIZE pos = GetLength(); 894 if (pos < 1) { 895 return; 896 } 897 while (pos) { 898 FX_STRSIZE i = 0; 899 while (i < pTargets.GetLength() && 900 pTargets[i] != m_pData->m_String[pos - 1]) { 901 i++; 902 } 903 if (i == pTargets.GetLength()) { 904 break; 905 } 906 pos--; 907 } 908 if (pos < m_pData->m_nDataLength) { 909 ReallocBeforeWrite(m_pData->m_nDataLength); 910 m_pData->m_String[pos] = 0; 911 m_pData->m_nDataLength = pos; 912 } 913 } 914 915 void CFX_ByteString::TrimRight(FX_CHAR chTarget) { 916 TrimRight(CFX_ByteStringC(chTarget)); 917 } 918 919 void CFX_ByteString::TrimRight() { 920 TrimRight("\x09\x0a\x0b\x0c\x0d\x20"); 921 } 922 923 void CFX_ByteString::TrimLeft(const CFX_ByteStringC& pTargets) { 924 if (!m_pData || pTargets.IsEmpty()) 925 return; 926 927 FX_STRSIZE len = GetLength(); 928 if (len < 1) 929 return; 930 931 FX_STRSIZE pos = 0; 932 while (pos < len) { 933 FX_STRSIZE i = 0; 934 while (i < pTargets.GetLength() && pTargets[i] != m_pData->m_String[pos]) { 935 i++; 936 } 937 if (i == pTargets.GetLength()) { 938 break; 939 } 940 pos++; 941 } 942 if (pos) { 943 ReallocBeforeWrite(len); 944 FX_STRSIZE nDataLength = len - pos; 945 FXSYS_memmove(m_pData->m_String, m_pData->m_String + pos, 946 (nDataLength + 1) * sizeof(FX_CHAR)); 947 m_pData->m_nDataLength = nDataLength; 948 } 949 } 950 951 void CFX_ByteString::TrimLeft(FX_CHAR chTarget) { 952 TrimLeft(CFX_ByteStringC(chTarget)); 953 } 954 955 void CFX_ByteString::TrimLeft() { 956 TrimLeft("\x09\x0a\x0b\x0c\x0d\x20"); 957 } 958 959 uint32_t CFX_ByteString::GetID(FX_STRSIZE start_pos) const { 960 return AsStringC().GetID(start_pos); 961 } 962 FX_STRSIZE FX_ftoa(FX_FLOAT d, FX_CHAR* buf) { 963 buf[0] = '0'; 964 buf[1] = '\0'; 965 if (d == 0.0f) { 966 return 1; 967 } 968 bool bNegative = false; 969 if (d < 0) { 970 bNegative = true; 971 d = -d; 972 } 973 int scale = 1; 974 int scaled = FXSYS_round(d); 975 while (scaled < 100000) { 976 if (scale == 1000000) { 977 break; 978 } 979 scale *= 10; 980 scaled = FXSYS_round(d * scale); 981 } 982 if (scaled == 0) { 983 return 1; 984 } 985 char buf2[32]; 986 int buf_size = 0; 987 if (bNegative) { 988 buf[buf_size++] = '-'; 989 } 990 int i = scaled / scale; 991 FXSYS_itoa(i, buf2, 10); 992 FX_STRSIZE len = FXSYS_strlen(buf2); 993 FXSYS_memcpy(buf + buf_size, buf2, len); 994 buf_size += len; 995 int fraction = scaled % scale; 996 if (fraction == 0) { 997 return buf_size; 998 } 999 buf[buf_size++] = '.'; 1000 scale /= 10; 1001 while (fraction) { 1002 buf[buf_size++] = '0' + fraction / scale; 1003 fraction %= scale; 1004 scale /= 10; 1005 } 1006 return buf_size; 1007 } 1008 CFX_ByteString CFX_ByteString::FormatFloat(FX_FLOAT d, int precision) { 1009 FX_CHAR buf[32]; 1010 FX_STRSIZE len = FX_ftoa(d, buf); 1011 return CFX_ByteString(buf, len); 1012 } 1013