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