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