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
_Buffer_itoa(char * buf,int i,FX_DWORD flags)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 }
FormatInteger(int i,FX_DWORD flags)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
Create(int nLen)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 }
~CFX_ByteString()78 CFX_ByteString::~CFX_ByteString()
79 {
80 if (m_pData) {
81 m_pData->Release();
82 }
83 }
CFX_ByteString(FX_LPCSTR lpsz,FX_STRSIZE nLen)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 }
CFX_ByteString(FX_LPCBYTE lpsz,FX_STRSIZE nLen)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 }
CFX_ByteString(char ch)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 }
CFX_ByteString(const CFX_ByteString & stringSrc)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 }
CFX_ByteString(FX_BSTR stringSrc)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 }
CFX_ByteString(FX_BSTR str1,FX_BSTR str2)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 }
operator =(FX_LPCSTR lpsz)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 }
operator =(FX_BSTR str)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 }
operator =(const CFX_ByteString & stringSrc)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 }
operator =(const CFX_BinaryBuf & buf)190 const CFX_ByteString& CFX_ByteString::operator=(const CFX_BinaryBuf& buf)
191 {
192 Load(buf.GetBuffer(), buf.GetSize());
193 return *this;
194 }
Load(FX_LPCBYTE buf,FX_STRSIZE len)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 }
operator +=(FX_LPCSTR lpsz)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 }
operator +=(char ch)214 const CFX_ByteString& CFX_ByteString::operator+=(char ch)
215 {
216 ConcatInPlace(1, &ch);
217 return *this;
218 }
operator +=(const CFX_ByteString & string)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 }
operator +=(FX_BSTR string)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 }
Equal(const char * ptr) const235 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 }
Equal(const CFX_ByteStringC & str) const246 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 }
Equal(const CFX_ByteString & other) const254 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 }
Empty()267 void CFX_ByteString::Empty()
268 {
269 if (m_pData) {
270 m_pData->Release();
271 m_pData = NULL;
272 }
273 }
EqualNoCase(FX_BSTR str) const274 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 }
AssignCopy(FX_STRSIZE nSrcLen,FX_LPCSTR lpszSrcData)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 }
CopyBeforeWrite()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 }
AllocBeforeWrite(FX_STRSIZE nLen)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 }
ReleaseBuffer(FX_STRSIZE nNewLength)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 }
Reserve(FX_STRSIZE len)349 void CFX_ByteString::Reserve(FX_STRSIZE len)
350 {
351 GetBuffer(len);
352 ReleaseBuffer(GetLength());
353 }
GetBuffer(FX_STRSIZE nMinBufLength)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 }
Delete(FX_STRSIZE nIndex,FX_STRSIZE nCount)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 }
ConcatInPlace(FX_STRSIZE nSrcLen,FX_LPCSTR lpszSrcData)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 }
ConcatCopy(FX_STRSIZE nSrc1Len,FX_LPCSTR lpszSrc1Data,FX_STRSIZE nSrc2Len,FX_LPCSTR lpszSrc2Data)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 }
Mid(FX_STRSIZE nFirst) const445 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 }
Mid(FX_STRSIZE nFirst,FX_STRSIZE nCount) const452 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 }
AllocCopy(CFX_ByteString & dest,FX_STRSIZE nCopyLen,FX_STRSIZE nCopyIndex) const473 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
FormatV(FX_LPCSTR lpszFormat,va_list argList)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 }
Format(FX_LPCSTR lpszFormat,...)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 }
Insert(FX_STRSIZE nIndex,FX_CHAR ch)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 }
Right(FX_STRSIZE nCount) const741 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 }
Left(FX_STRSIZE nCount) const756 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 }
Find(FX_CHAR ch,FX_STRSIZE nStart) const771 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 }
ReverseFind(FX_CHAR ch) const783 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 }
FX_strstr(FX_LPCSTR str1,int len1,FX_LPCSTR str2,int len2)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 }
Find(FX_BSTR lpszSub,FX_STRSIZE nStart) const818 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 }
MakeLower()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 }
MakeUpper()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 }
Remove(FX_CHAR chRemove)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 }
Replace(FX_BSTR lpszOld,FX_BSTR lpszNew)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 }
SetAt(FX_STRSIZE nIndex,FX_CHAR ch)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 }
UTF8Decode() const935 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 }
FromUnicode(FX_LPCWSTR str,FX_STRSIZE len)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 }
FromUnicode(const CFX_WideString & str)952 CFX_ByteString CFX_ByteString::FromUnicode(const CFX_WideString& str)
953 {
954 return FromUnicode(str.c_str(), str.GetLength());
955 }
ConvertFrom(const CFX_WideString & str,CFX_CharMap * pCharMap)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 }
Compare(FX_BSTR str) const963 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 }
TrimRight(FX_BSTR lpszTargets)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 }
TrimRight(FX_CHAR chTarget)1010 void CFX_ByteString::TrimRight(FX_CHAR chTarget)
1011 {
1012 TrimRight(CFX_ByteStringC(chTarget));
1013 }
TrimRight()1014 void CFX_ByteString::TrimRight()
1015 {
1016 TrimRight(FX_BSTRC("\x09\x0a\x0b\x0c\x0d\x20"));
1017 }
TrimLeft(FX_BSTR lpszTargets)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 }
TrimLeft(FX_CHAR chTarget)1048 void CFX_ByteString::TrimLeft(FX_CHAR chTarget)
1049 {
1050 TrimLeft(CFX_ByteStringC(chTarget));
1051 }
TrimLeft()1052 void CFX_ByteString::TrimLeft()
1053 {
1054 TrimLeft(FX_BSTRC("\x09\x0a\x0b\x0c\x0d\x20"));
1055 }
GetID(FX_STRSIZE start_pos) const1056 FX_DWORD CFX_ByteString::GetID(FX_STRSIZE start_pos) const
1057 {
1058 return CFX_ByteStringC(*this).GetID(start_pos);
1059 }
GetID(FX_STRSIZE start_pos) const1060 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 }
FX_ftoa(FX_FLOAT d,FX_LPSTR buf)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 }
FormatFloat(FX_FLOAT d,int precision)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