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
Buffer_itoa(char * buf,int i,uint32_t flags)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
FX_strstr(const FX_CHAR * haystack,int haystack_len,const FX_CHAR * needle,int needle_len)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
CFX_ByteString(const FX_CHAR * pStr,FX_STRSIZE nLen)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
CFX_ByteString(const uint8_t * pStr,FX_STRSIZE nLen)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
CFX_ByteString()100 CFX_ByteString::CFX_ByteString() {}
101
CFX_ByteString(const CFX_ByteString & other)102 CFX_ByteString::CFX_ByteString(const CFX_ByteString& other)
103 : m_pData(other.m_pData) {}
104
CFX_ByteString(CFX_ByteString && other)105 CFX_ByteString::CFX_ByteString(CFX_ByteString&& other) {
106 m_pData.Swap(other.m_pData);
107 }
108
CFX_ByteString(char ch)109 CFX_ByteString::CFX_ByteString(char ch) {
110 m_pData.Reset(StringData::Create(1));
111 m_pData->m_String[0] = ch;
112 }
113
CFX_ByteString(const FX_CHAR * ptr)114 CFX_ByteString::CFX_ByteString(const FX_CHAR* ptr)
115 : CFX_ByteString(ptr, ptr ? FXSYS_strlen(ptr) : 0) {}
116
CFX_ByteString(const CFX_ByteStringC & stringSrc)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
CFX_ByteString(const CFX_ByteStringC & str1,const CFX_ByteStringC & str2)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
~CFX_ByteString()133 CFX_ByteString::~CFX_ByteString() {}
134
operator =(const FX_CHAR * pStr)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
operator =(const CFX_ByteStringC & stringSrc)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
operator =(const CFX_ByteString & stringSrc)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
operator +=(const FX_CHAR * pStr)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
operator +=(char ch)169 const CFX_ByteString& CFX_ByteString::operator+=(char ch) {
170 Concat(&ch, 1);
171 return *this;
172 }
173
operator +=(const CFX_ByteString & str)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
operator +=(const CFX_ByteStringC & str)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
operator ==(const char * ptr) const188 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
operator ==(const CFX_ByteStringC & str) const199 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
operator ==(const CFX_ByteString & other) const207 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
operator <(const CFX_ByteString & str) const222 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
EqualNoCase(const CFX_ByteStringC & str) const231 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
AssignCopy(const FX_CHAR * pSrcData,FX_STRSIZE nSrcLen)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
ReallocBeforeWrite(FX_STRSIZE nNewLength)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
AllocBeforeWrite(FX_STRSIZE nNewLength)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
ReleaseBuffer(FX_STRSIZE nNewLength)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
Reserve(FX_STRSIZE len)323 void CFX_ByteString::Reserve(FX_STRSIZE len) {
324 GetBuffer(len);
325 }
326
GetBuffer(FX_STRSIZE nMinBufLength)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
Delete(FX_STRSIZE nIndex,FX_STRSIZE nCount)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
Concat(const FX_CHAR * pSrcData,FX_STRSIZE nSrcLen)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
Mid(FX_STRSIZE nFirst) const397 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
Mid(FX_STRSIZE nFirst,FX_STRSIZE nCount) const404 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
AllocCopy(CFX_ByteString & dest,FX_STRSIZE nCopyLen,FX_STRSIZE nCopyIndex) const421 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
FormatInteger(int i,uint32_t flags)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
FormatV(const FX_CHAR * pFormat,va_list argList)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
Format(const FX_CHAR * pFormat,...)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
Insert(FX_STRSIZE nIndex,FX_CHAR ch)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
Right(FX_STRSIZE nCount) const673 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
Left(FX_STRSIZE nCount) const686 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
Find(FX_CHAR ch,FX_STRSIZE nStart) const699 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
ReverseFind(FX_CHAR ch) const711 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
Find(const CFX_ByteStringC & pSub,FX_STRSIZE nStart) const723 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
MakeLower()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
MakeUpper()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
Remove(FX_CHAR chRemove)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
Replace(const CFX_ByteStringC & pOld,const CFX_ByteStringC & pNew)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
SetAt(FX_STRSIZE nIndex,FX_CHAR ch)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
UTF8Decode() const845 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
FromUnicode(const FX_WCHAR * str,FX_STRSIZE len)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
FromUnicode(const CFX_WideString & str)861 CFX_ByteString CFX_ByteString::FromUnicode(const CFX_WideString& str) {
862 return CFX_CharMap::GetByteString(0, str.AsStringC());
863 }
864
Compare(const CFX_ByteStringC & str) const865 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
TrimRight(const CFX_ByteStringC & pTargets)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
TrimRight(FX_CHAR chTarget)915 void CFX_ByteString::TrimRight(FX_CHAR chTarget) {
916 TrimRight(CFX_ByteStringC(chTarget));
917 }
918
TrimRight()919 void CFX_ByteString::TrimRight() {
920 TrimRight("\x09\x0a\x0b\x0c\x0d\x20");
921 }
922
TrimLeft(const CFX_ByteStringC & pTargets)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
TrimLeft(FX_CHAR chTarget)951 void CFX_ByteString::TrimLeft(FX_CHAR chTarget) {
952 TrimLeft(CFX_ByteStringC(chTarget));
953 }
954
TrimLeft()955 void CFX_ByteString::TrimLeft() {
956 TrimLeft("\x09\x0a\x0b\x0c\x0d\x20");
957 }
958
GetID(FX_STRSIZE start_pos) const959 uint32_t CFX_ByteString::GetID(FX_STRSIZE start_pos) const {
960 return AsStringC().GetID(start_pos);
961 }
FX_ftoa(FX_FLOAT d,FX_CHAR * buf)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 }
FormatFloat(FX_FLOAT d,int precision)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