1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "nscore.h"
8 #include "nsCRTGlue.h"
9 #include "prprf.h"
10 #include "nsStringAPI.h"
11 #include "nsXPCOMStrings.h"
12 #include "nsDebug.h"
13
14 #include "mozilla/Sprintf.h"
15
16 #include <stdio.h>
17
18 // nsAString
19
20 uint32_t
BeginReading(const char_type ** aBegin,const char_type ** aEnd) const21 nsAString::BeginReading(const char_type** aBegin, const char_type** aEnd) const
22 {
23 uint32_t len = NS_StringGetData(*this, aBegin);
24 if (aEnd) {
25 *aEnd = *aBegin + len;
26 }
27
28 return len;
29 }
30
31 const nsAString::char_type*
BeginReading() const32 nsAString::BeginReading() const
33 {
34 const char_type* data;
35 NS_StringGetData(*this, &data);
36 return data;
37 }
38
39 const nsAString::char_type*
EndReading() const40 nsAString::EndReading() const
41 {
42 const char_type* data;
43 uint32_t len = NS_StringGetData(*this, &data);
44 return data + len;
45 }
46
47 uint32_t
BeginWriting(char_type ** aBegin,char_type ** aEnd,uint32_t aNewSize)48 nsAString::BeginWriting(char_type** aBegin, char_type** aEnd, uint32_t aNewSize)
49 {
50 uint32_t len = NS_StringGetMutableData(*this, aNewSize, aBegin);
51 if (aEnd) {
52 *aEnd = *aBegin + len;
53 }
54
55 return len;
56 }
57
58 nsAString::char_type*
BeginWriting(uint32_t aLen)59 nsAString::BeginWriting(uint32_t aLen)
60 {
61 char_type* data;
62 NS_StringGetMutableData(*this, aLen, &data);
63 return data;
64 }
65
66 nsAString::char_type*
EndWriting()67 nsAString::EndWriting()
68 {
69 char_type* data;
70 uint32_t len = NS_StringGetMutableData(*this, UINT32_MAX, &data);
71 return data + len;
72 }
73
74 bool
SetLength(uint32_t aLen)75 nsAString::SetLength(uint32_t aLen)
76 {
77 char_type* data;
78 NS_StringGetMutableData(*this, aLen, &data);
79 return data != nullptr;
80 }
81
82 void
AssignLiteral(const char * aStr)83 nsAString::AssignLiteral(const char* aStr)
84 {
85 uint32_t len = strlen(aStr);
86 char16_t* buf = BeginWriting(len);
87 if (!buf) {
88 return;
89 }
90
91 for (; *aStr; ++aStr, ++buf) {
92 *buf = *aStr;
93 }
94 }
95
96 void
AppendLiteral(const char * aASCIIStr)97 nsAString::AppendLiteral(const char* aASCIIStr)
98 {
99 uint32_t appendLen = strlen(aASCIIStr);
100
101 uint32_t thisLen = Length();
102 char16_t* begin;
103 char16_t* end;
104 BeginWriting(&begin, &end, appendLen + thisLen);
105 if (!begin) {
106 return;
107 }
108
109 for (begin += thisLen; begin < end; ++begin, ++aASCIIStr) {
110 *begin = *aASCIIStr;
111 }
112 }
113
114 void
StripChars(const char * aSet)115 nsAString::StripChars(const char* aSet)
116 {
117 nsString copy(*this);
118
119 const char_type* source;
120 const char_type* sourceEnd;
121 copy.BeginReading(&source, &sourceEnd);
122
123 char_type* dest;
124 BeginWriting(&dest);
125 if (!dest) {
126 return;
127 }
128
129 char_type* curDest = dest;
130
131 for (; source < sourceEnd; ++source) {
132 const char* test;
133 for (test = aSet; *test; ++test) {
134 if (*source == char_type(*test)) {
135 break;
136 }
137 }
138
139 if (!*test) {
140 // not stripped, copy this char
141 *curDest = *source;
142 ++curDest;
143 }
144 }
145
146 SetLength(curDest - dest);
147 }
148
149 void
Trim(const char * aSet,bool aLeading,bool aTrailing)150 nsAString::Trim(const char* aSet, bool aLeading, bool aTrailing)
151 {
152 NS_ASSERTION(aLeading || aTrailing, "Ineffective Trim");
153
154 const char16_t* start;
155 const char16_t* end;
156 uint32_t cutLen;
157
158 if (aLeading) {
159 BeginReading(&start, &end);
160 for (cutLen = 0; start < end; ++start, ++cutLen) {
161 const char* test;
162 for (test = aSet; *test; ++test) {
163 if (*test == *start) {
164 break;
165 }
166 }
167 if (!*test) {
168 break;
169 }
170 }
171 if (cutLen) {
172 NS_StringCutData(*this, 0, cutLen);
173 }
174 }
175 if (aTrailing) {
176 uint32_t len = BeginReading(&start, &end);
177 --end;
178 for (cutLen = 0; end >= start; --end, ++cutLen) {
179 const char* test;
180 for (test = aSet; *test; ++test) {
181 if (*test == *end) {
182 break;
183 }
184 }
185 if (!*test) {
186 break;
187 }
188 }
189 if (cutLen) {
190 NS_StringCutData(*this, len - cutLen, cutLen);
191 }
192 }
193 }
194
195 int32_t
DefaultComparator(const char_type * aStrA,const char_type * aStrB,uint32_t aLen)196 nsAString::DefaultComparator(const char_type* aStrA, const char_type* aStrB,
197 uint32_t aLen)
198 {
199 for (const char_type* end = aStrA + aLen; aStrA < end; ++aStrA, ++aStrB) {
200 if (*aStrA == *aStrB) {
201 continue;
202 }
203
204 return *aStrA < *aStrB ? -1 : 1;
205 }
206
207 return 0;
208 }
209
210 int32_t
Compare(const char_type * aOther,ComparatorFunc aComparator) const211 nsAString::Compare(const char_type* aOther, ComparatorFunc aComparator) const
212 {
213 const char_type* cself;
214 uint32_t selflen = NS_StringGetData(*this, &cself);
215 uint32_t otherlen = NS_strlen(aOther);
216 uint32_t comparelen = selflen <= otherlen ? selflen : otherlen;
217
218 int32_t result = aComparator(cself, aOther, comparelen);
219 if (result == 0) {
220 if (selflen < otherlen) {
221 return -1;
222 } else if (selflen > otherlen) {
223 return 1;
224 }
225 }
226 return result;
227 }
228
229 int32_t
Compare(const self_type & aOther,ComparatorFunc aComparator) const230 nsAString::Compare(const self_type& aOther, ComparatorFunc aComparator) const
231 {
232 const char_type* cself;
233 const char_type* cother;
234 uint32_t selflen = NS_StringGetData(*this, &cself);
235 uint32_t otherlen = NS_StringGetData(aOther, &cother);
236 uint32_t comparelen = selflen <= otherlen ? selflen : otherlen;
237
238 int32_t result = aComparator(cself, cother, comparelen);
239 if (result == 0) {
240 if (selflen < otherlen) {
241 return -1;
242 } else if (selflen > otherlen) {
243 return 1;
244 }
245 }
246 return result;
247 }
248
249 bool
Equals(const char_type * aOther,ComparatorFunc aComparator) const250 nsAString::Equals(const char_type* aOther, ComparatorFunc aComparator) const
251 {
252 const char_type* cself;
253 uint32_t selflen = NS_StringGetData(*this, &cself);
254 uint32_t otherlen = NS_strlen(aOther);
255
256 if (selflen != otherlen) {
257 return false;
258 }
259
260 return aComparator(cself, aOther, selflen) == 0;
261 }
262
263 bool
Equals(const self_type & aOther,ComparatorFunc aComparator) const264 nsAString::Equals(const self_type& aOther, ComparatorFunc aComparator) const
265 {
266 const char_type* cself;
267 const char_type* cother;
268 uint32_t selflen = NS_StringGetData(*this, &cself);
269 uint32_t otherlen = NS_StringGetData(aOther, &cother);
270
271 if (selflen != otherlen) {
272 return false;
273 }
274
275 return aComparator(cself, cother, selflen) == 0;
276 }
277
278 bool
EqualsLiteral(const char * aASCIIString) const279 nsAString::EqualsLiteral(const char* aASCIIString) const
280 {
281 const char16_t* begin;
282 const char16_t* end;
283 BeginReading(&begin, &end);
284
285 for (; begin < end; ++begin, ++aASCIIString) {
286 if (!*aASCIIString || !NS_IsAscii(*begin) ||
287 (char)*begin != *aASCIIString) {
288 return false;
289 }
290 }
291
292 return *aASCIIString == '\0';
293 }
294
295 bool
LowerCaseEqualsLiteral(const char * aASCIIString) const296 nsAString::LowerCaseEqualsLiteral(const char* aASCIIString) const
297 {
298 const char16_t* begin;
299 const char16_t* end;
300 BeginReading(&begin, &end);
301
302 for (; begin < end; ++begin, ++aASCIIString) {
303 if (!*aASCIIString || !NS_IsAscii(*begin) ||
304 NS_ToLower((char)*begin) != *aASCIIString) {
305 return false;
306 }
307 }
308
309 return *aASCIIString == '\0';
310 }
311
312 int32_t
Find(const self_type & aStr,uint32_t aOffset,ComparatorFunc aComparator) const313 nsAString::Find(const self_type& aStr, uint32_t aOffset,
314 ComparatorFunc aComparator) const
315 {
316 const char_type* begin;
317 const char_type* end;
318 uint32_t selflen = BeginReading(&begin, &end);
319
320 if (aOffset > selflen) {
321 return -1;
322 }
323
324 const char_type* other;
325 uint32_t otherlen = aStr.BeginReading(&other);
326
327 if (otherlen > selflen - aOffset) {
328 return -1;
329 }
330
331 // We want to stop searching otherlen characters before the end of the string
332 end -= otherlen;
333
334 for (const char_type* cur = begin + aOffset; cur <= end; ++cur) {
335 if (!aComparator(cur, other, otherlen)) {
336 return cur - begin;
337 }
338 }
339 return -1;
340 }
341
342 static bool
ns_strnmatch(const char16_t * aStr,const char * aSubstring,uint32_t aLen)343 ns_strnmatch(const char16_t* aStr, const char* aSubstring, uint32_t aLen)
344 {
345 for (; aLen; ++aStr, ++aSubstring, --aLen) {
346 if (!NS_IsAscii(*aStr)) {
347 return false;
348 }
349
350 if ((char)*aStr != *aSubstring) {
351 return false;
352 }
353 }
354
355 return true;
356 }
357
358 static bool
ns_strnimatch(const char16_t * aStr,const char * aSubstring,uint32_t aLen)359 ns_strnimatch(const char16_t* aStr, const char* aSubstring, uint32_t aLen)
360 {
361 for (; aLen; ++aStr, ++aSubstring, --aLen) {
362 if (!NS_IsAscii(*aStr)) {
363 return false;
364 }
365
366 if (NS_ToLower((char)*aStr) != NS_ToLower(*aSubstring)) {
367 return false;
368 }
369 }
370
371 return true;
372 }
373
374 int32_t
Find(const char * aStr,uint32_t aOffset,bool aIgnoreCase) const375 nsAString::Find(const char* aStr, uint32_t aOffset, bool aIgnoreCase) const
376 {
377 bool (*match)(const char16_t*, const char*, uint32_t) =
378 aIgnoreCase ? ns_strnimatch : ns_strnmatch;
379
380 const char_type* begin;
381 const char_type* end;
382 uint32_t selflen = BeginReading(&begin, &end);
383
384 if (aOffset > selflen) {
385 return -1;
386 }
387
388 uint32_t otherlen = strlen(aStr);
389
390 if (otherlen > selflen - aOffset) {
391 return -1;
392 }
393
394 // We want to stop searching otherlen characters before the end of the string
395 end -= otherlen;
396
397 for (const char_type* cur = begin + aOffset; cur <= end; ++cur) {
398 if (match(cur, aStr, otherlen)) {
399 return cur - begin;
400 }
401 }
402 return -1;
403 }
404
405 int32_t
RFind(const self_type & aStr,int32_t aOffset,ComparatorFunc aComparator) const406 nsAString::RFind(const self_type& aStr, int32_t aOffset,
407 ComparatorFunc aComparator) const
408 {
409 const char_type* begin;
410 const char_type* end;
411 uint32_t selflen = BeginReading(&begin, &end);
412
413 const char_type* other;
414 uint32_t otherlen = aStr.BeginReading(&other);
415
416 if (selflen < otherlen) {
417 return -1;
418 }
419
420 if (aOffset < 0 || uint32_t(aOffset) > (selflen - otherlen)) {
421 end -= otherlen;
422 } else {
423 end = begin + aOffset;
424 }
425
426 for (const char_type* cur = end; cur >= begin; --cur) {
427 if (!aComparator(cur, other, otherlen)) {
428 return cur - begin;
429 }
430 }
431 return -1;
432 }
433
434 int32_t
RFind(const char * aStr,int32_t aOffset,bool aIgnoreCase) const435 nsAString::RFind(const char* aStr, int32_t aOffset, bool aIgnoreCase) const
436 {
437 bool (*match)(const char16_t*, const char*, uint32_t) =
438 aIgnoreCase ? ns_strnimatch : ns_strnmatch;
439
440 const char_type* begin;
441 const char_type* end;
442 uint32_t selflen = BeginReading(&begin, &end);
443 uint32_t otherlen = strlen(aStr);
444
445 if (selflen < otherlen) {
446 return -1;
447 }
448
449 if (aOffset < 0 || uint32_t(aOffset) > (selflen - otherlen)) {
450 end -= otherlen;
451 } else {
452 end = begin + aOffset;
453 }
454
455 for (const char_type* cur = end; cur >= begin; --cur) {
456 if (match(cur, aStr, otherlen)) {
457 return cur - begin;
458 }
459 }
460 return -1;
461 }
462
463 int32_t
FindChar(char_type aChar,uint32_t aOffset) const464 nsAString::FindChar(char_type aChar, uint32_t aOffset) const
465 {
466 const char_type* start;
467 const char_type* end;
468 uint32_t len = BeginReading(&start, &end);
469 if (aOffset > len) {
470 return -1;
471 }
472
473 const char_type* cur;
474
475 for (cur = start + aOffset; cur < end; ++cur) {
476 if (*cur == aChar) {
477 return cur - start;
478 }
479 }
480
481 return -1;
482 }
483
484 int32_t
RFindChar(char_type aChar) const485 nsAString::RFindChar(char_type aChar) const
486 {
487 const char16_t* start;
488 const char16_t* end;
489 BeginReading(&start, &end);
490
491 do {
492 --end;
493
494 if (*end == aChar) {
495 return end - start;
496 }
497
498 } while (end >= start);
499
500 return -1;
501 }
502
503 void
AppendInt(int aInt,int32_t aRadix)504 nsAString::AppendInt(int aInt, int32_t aRadix)
505 {
506 const char* fmt;
507 switch (aRadix) {
508 case 8:
509 fmt = "%o";
510 break;
511
512 case 10:
513 fmt = "%d";
514 break;
515
516 case 16:
517 fmt = "%x";
518 break;
519
520 default:
521 NS_ERROR("Unrecognized radix");
522 fmt = "";
523 }
524
525 char buf[20];
526 int len = SprintfLiteral(buf, fmt, aInt);
527 Append(NS_ConvertASCIItoUTF16(buf, len));
528 }
529
530 // Strings
531
532 #ifndef XPCOM_GLUE_AVOID_NSPR
533 int32_t
ToInteger(nsresult * aErrorCode,uint32_t aRadix) const534 nsAString::ToInteger(nsresult* aErrorCode, uint32_t aRadix) const
535 {
536 NS_ConvertUTF16toUTF8 narrow(*this);
537
538 const char* fmt;
539 switch (aRadix) {
540 case 10:
541 fmt = "%i";
542 break;
543
544 case 16:
545 fmt = "%x";
546 break;
547
548 default:
549 NS_ERROR("Unrecognized radix!");
550 *aErrorCode = NS_ERROR_INVALID_ARG;
551 return 0;
552 }
553
554 int32_t result = 0;
555 if (PR_sscanf(narrow.get(), fmt, &result) == 1) {
556 *aErrorCode = NS_OK;
557 } else {
558 *aErrorCode = NS_ERROR_FAILURE;
559 }
560
561 return result;
562 }
563
564 int64_t
ToInteger64(nsresult * aErrorCode,uint32_t aRadix) const565 nsAString::ToInteger64(nsresult* aErrorCode, uint32_t aRadix) const
566 {
567 NS_ConvertUTF16toUTF8 narrow(*this);
568
569 const char* fmt;
570 switch (aRadix) {
571 case 10:
572 fmt = "%lli";
573 break;
574
575 case 16:
576 fmt = "%llx";
577 break;
578
579 default:
580 NS_ERROR("Unrecognized radix!");
581 *aErrorCode = NS_ERROR_INVALID_ARG;
582 return 0;
583 }
584
585 int64_t result = 0;
586 if (PR_sscanf(narrow.get(), fmt, &result) == 1) {
587 *aErrorCode = NS_OK;
588 } else {
589 *aErrorCode = NS_ERROR_FAILURE;
590 }
591
592 return result;
593 }
594 #endif // XPCOM_GLUE_AVOID_NSPR
595
596 // nsACString
597
598 uint32_t
BeginReading(const char_type ** aBegin,const char_type ** aEnd) const599 nsACString::BeginReading(const char_type** aBegin, const char_type** aEnd) const
600 {
601 uint32_t len = NS_CStringGetData(*this, aBegin);
602 if (aEnd) {
603 *aEnd = *aBegin + len;
604 }
605
606 return len;
607 }
608
609 const nsACString::char_type*
BeginReading() const610 nsACString::BeginReading() const
611 {
612 const char_type* data;
613 NS_CStringGetData(*this, &data);
614 return data;
615 }
616
617 const nsACString::char_type*
EndReading() const618 nsACString::EndReading() const
619 {
620 const char_type* data;
621 uint32_t len = NS_CStringGetData(*this, &data);
622 return data + len;
623 }
624
625 uint32_t
BeginWriting(char_type ** aBegin,char_type ** aEnd,uint32_t aNewSize)626 nsACString::BeginWriting(char_type** aBegin, char_type** aEnd,
627 uint32_t aNewSize)
628 {
629 uint32_t len = NS_CStringGetMutableData(*this, aNewSize, aBegin);
630 if (aEnd) {
631 *aEnd = *aBegin + len;
632 }
633
634 return len;
635 }
636
637 nsACString::char_type*
BeginWriting(uint32_t aLen)638 nsACString::BeginWriting(uint32_t aLen)
639 {
640 char_type* data;
641 NS_CStringGetMutableData(*this, aLen, &data);
642 return data;
643 }
644
645 nsACString::char_type*
EndWriting()646 nsACString::EndWriting()
647 {
648 char_type* data;
649 uint32_t len = NS_CStringGetMutableData(*this, UINT32_MAX, &data);
650 return data + len;
651 }
652
653 bool
SetLength(uint32_t aLen)654 nsACString::SetLength(uint32_t aLen)
655 {
656 char_type* data;
657 NS_CStringGetMutableData(*this, aLen, &data);
658 return data != nullptr;
659 }
660
661 void
StripChars(const char * aSet)662 nsACString::StripChars(const char* aSet)
663 {
664 nsCString copy(*this);
665
666 const char_type* source;
667 const char_type* sourceEnd;
668 copy.BeginReading(&source, &sourceEnd);
669
670 char_type* dest;
671 BeginWriting(&dest);
672 if (!dest) {
673 return;
674 }
675
676 char_type* curDest = dest;
677
678 for (; source < sourceEnd; ++source) {
679 const char* test;
680 for (test = aSet; *test; ++test) {
681 if (*source == char_type(*test)) {
682 break;
683 }
684 }
685
686 if (!*test) {
687 // not stripped, copy this char
688 *curDest = *source;
689 ++curDest;
690 }
691 }
692
693 SetLength(curDest - dest);
694 }
695
696 void
Trim(const char * aSet,bool aLeading,bool aTrailing)697 nsACString::Trim(const char* aSet, bool aLeading, bool aTrailing)
698 {
699 NS_ASSERTION(aLeading || aTrailing, "Ineffective Trim");
700
701 const char* start;
702 const char* end;
703 uint32_t cutLen;
704
705 if (aLeading) {
706 BeginReading(&start, &end);
707 for (cutLen = 0; start < end; ++start, ++cutLen) {
708 const char* test;
709 for (test = aSet; *test; ++test) {
710 if (*test == *start) {
711 break;
712 }
713 }
714 if (!*test) {
715 break;
716 }
717 }
718 if (cutLen) {
719 NS_CStringCutData(*this, 0, cutLen);
720 }
721 }
722 if (aTrailing) {
723 uint32_t len = BeginReading(&start, &end);
724 --end;
725 for (cutLen = 0; end >= start; --end, ++cutLen) {
726 const char* test;
727 for (test = aSet; *test; ++test) {
728 if (*test == *end) {
729 break;
730 }
731 }
732 if (!*test) {
733 break;
734 }
735 }
736 if (cutLen) {
737 NS_CStringCutData(*this, len - cutLen, cutLen);
738 }
739 }
740 }
741
742 int32_t
DefaultComparator(const char_type * aStrA,const char_type * aStrB,uint32_t aLen)743 nsACString::DefaultComparator(const char_type* aStrA, const char_type* aStrB,
744 uint32_t aLen)
745 {
746 return memcmp(aStrA, aStrB, aLen);
747 }
748
749 int32_t
Compare(const char_type * aOther,ComparatorFunc aComparator) const750 nsACString::Compare(const char_type* aOther, ComparatorFunc aComparator) const
751 {
752 const char_type* cself;
753 uint32_t selflen = NS_CStringGetData(*this, &cself);
754 uint32_t otherlen = strlen(aOther);
755 uint32_t comparelen = selflen <= otherlen ? selflen : otherlen;
756
757 int32_t result = aComparator(cself, aOther, comparelen);
758 if (result == 0) {
759 if (selflen < otherlen) {
760 return -1;
761 } else if (selflen > otherlen) {
762 return 1;
763 }
764 }
765 return result;
766 }
767
768 int32_t
Compare(const self_type & aOther,ComparatorFunc aComparator) const769 nsACString::Compare(const self_type& aOther, ComparatorFunc aComparator) const
770 {
771 const char_type* cself;
772 const char_type* cother;
773 uint32_t selflen = NS_CStringGetData(*this, &cself);
774 uint32_t otherlen = NS_CStringGetData(aOther, &cother);
775 uint32_t comparelen = selflen <= otherlen ? selflen : otherlen;
776
777 int32_t result = aComparator(cself, cother, comparelen);
778 if (result == 0) {
779 if (selflen < otherlen) {
780 return -1;
781 } else if (selflen > otherlen) {
782 return 1;
783 }
784 }
785 return result;
786 }
787
788 bool
Equals(const char_type * aOther,ComparatorFunc aComparator) const789 nsACString::Equals(const char_type* aOther, ComparatorFunc aComparator) const
790 {
791 const char_type* cself;
792 uint32_t selflen = NS_CStringGetData(*this, &cself);
793 uint32_t otherlen = strlen(aOther);
794
795 if (selflen != otherlen) {
796 return false;
797 }
798
799 return aComparator(cself, aOther, selflen) == 0;
800 }
801
802 bool
Equals(const self_type & aOther,ComparatorFunc aComparator) const803 nsACString::Equals(const self_type& aOther, ComparatorFunc aComparator) const
804 {
805 const char_type* cself;
806 const char_type* cother;
807 uint32_t selflen = NS_CStringGetData(*this, &cself);
808 uint32_t otherlen = NS_CStringGetData(aOther, &cother);
809
810 if (selflen != otherlen) {
811 return false;
812 }
813
814 return aComparator(cself, cother, selflen) == 0;
815 }
816
817 int32_t
Find(const self_type & aStr,uint32_t aOffset,ComparatorFunc aComparator) const818 nsACString::Find(const self_type& aStr, uint32_t aOffset,
819 ComparatorFunc aComparator) const
820 {
821 const char_type* begin;
822 const char_type* end;
823 uint32_t selflen = BeginReading(&begin, &end);
824
825 if (aOffset > selflen) {
826 return -1;
827 }
828
829 const char_type* other;
830 uint32_t otherlen = aStr.BeginReading(&other);
831
832 if (otherlen > selflen - aOffset) {
833 return -1;
834 }
835
836 // We want to stop searching otherlen characters before the end of the string
837 end -= otherlen;
838
839 for (const char_type* cur = begin + aOffset; cur <= end; ++cur) {
840 if (!aComparator(cur, other, otherlen)) {
841 return cur - begin;
842 }
843 }
844 return -1;
845 }
846
847 int32_t
Find(const char_type * aStr,ComparatorFunc aComparator) const848 nsACString::Find(const char_type* aStr, ComparatorFunc aComparator) const
849 {
850 return Find(aStr, strlen(aStr), aComparator);
851 }
852
853 int32_t
Find(const char_type * aStr,uint32_t aLen,ComparatorFunc aComparator) const854 nsACString::Find(const char_type* aStr, uint32_t aLen,
855 ComparatorFunc aComparator) const
856 {
857 const char_type* begin;
858 const char_type* end;
859 uint32_t selflen = BeginReading(&begin, &end);
860
861 if (aLen == 0) {
862 NS_WARNING("Searching for zero-length string.");
863 return -1;
864 }
865
866 if (aLen > selflen) {
867 return -1;
868 }
869
870 // We want to stop searching otherlen characters before the end of the string
871 end -= aLen;
872
873 for (const char_type* cur = begin; cur <= end; ++cur) {
874 if (!aComparator(cur, aStr, aLen)) {
875 return cur - begin;
876 }
877 }
878 return -1;
879 }
880
881 int32_t
RFind(const self_type & aStr,int32_t aOffset,ComparatorFunc aComparator) const882 nsACString::RFind(const self_type& aStr, int32_t aOffset,
883 ComparatorFunc aComparator) const
884 {
885 const char_type* begin;
886 const char_type* end;
887 uint32_t selflen = BeginReading(&begin, &end);
888
889 const char_type* other;
890 uint32_t otherlen = aStr.BeginReading(&other);
891
892 if (selflen < otherlen) {
893 return -1;
894 }
895
896 if (aOffset < 0 || uint32_t(aOffset) > (selflen - otherlen)) {
897 end -= otherlen;
898 } else {
899 end = begin + aOffset;
900 }
901
902 for (const char_type* cur = end; cur >= begin; --cur) {
903 if (!aComparator(cur, other, otherlen)) {
904 return cur - begin;
905 }
906 }
907 return -1;
908 }
909
910 int32_t
RFind(const char_type * aStr,ComparatorFunc aComparator) const911 nsACString::RFind(const char_type* aStr, ComparatorFunc aComparator) const
912 {
913 return RFind(aStr, strlen(aStr), aComparator);
914 }
915
916 int32_t
RFind(const char_type * aStr,int32_t aLen,ComparatorFunc aComparator) const917 nsACString::RFind(const char_type* aStr, int32_t aLen,
918 ComparatorFunc aComparator) const
919 {
920 const char_type* begin;
921 const char_type* end;
922 uint32_t selflen = BeginReading(&begin, &end);
923
924 if (aLen <= 0) {
925 NS_WARNING("Searching for zero-length string.");
926 return -1;
927 }
928
929 if (uint32_t(aLen) > selflen) {
930 return -1;
931 }
932
933 // We want to start searching otherlen characters before the end of the string
934 end -= aLen;
935
936 for (const char_type* cur = end; cur >= begin; --cur) {
937 if (!aComparator(cur, aStr, aLen)) {
938 return cur - begin;
939 }
940 }
941 return -1;
942 }
943
944 int32_t
FindChar(char_type aChar,uint32_t aOffset) const945 nsACString::FindChar(char_type aChar, uint32_t aOffset) const
946 {
947 const char_type* start;
948 const char_type* end;
949 uint32_t len = BeginReading(&start, &end);
950 if (aOffset > len) {
951 return -1;
952 }
953
954 const char_type* cur;
955
956 for (cur = start + aOffset; cur < end; ++cur) {
957 if (*cur == aChar) {
958 return cur - start;
959 }
960 }
961
962 return -1;
963 }
964
965 int32_t
RFindChar(char_type aChar) const966 nsACString::RFindChar(char_type aChar) const
967 {
968 const char* start;
969 const char* end;
970 BeginReading(&start, &end);
971
972 for (; end >= start; --end) {
973 if (*end == aChar) {
974 return end - start;
975 }
976 }
977
978 return -1;
979 }
980
981 void
AppendInt(int aInt,int32_t aRadix)982 nsACString::AppendInt(int aInt, int32_t aRadix)
983 {
984 const char* fmt;
985 switch (aRadix) {
986 case 8:
987 fmt = "%o";
988 break;
989
990 case 10:
991 fmt = "%d";
992 break;
993
994 case 16:
995 fmt = "%x";
996 break;
997
998 default:
999 NS_ERROR("Unrecognized radix");
1000 fmt = "";
1001 }
1002
1003 char buf[20];
1004 int len = SprintfLiteral(buf, fmt, aInt);
1005 Append(buf, len);
1006 }
1007
1008 #ifndef XPCOM_GLUE_AVOID_NSPR
1009 int32_t
ToInteger(nsresult * aErrorCode,uint32_t aRadix) const1010 nsACString::ToInteger(nsresult* aErrorCode, uint32_t aRadix) const
1011 {
1012 const char* fmt;
1013 switch (aRadix) {
1014 case 10:
1015 fmt = "%i";
1016 break;
1017
1018 case 16:
1019 fmt = "%x";
1020 break;
1021
1022 default:
1023 NS_ERROR("Unrecognized radix!");
1024 *aErrorCode = NS_ERROR_INVALID_ARG;
1025 return 0;
1026 }
1027
1028 int32_t result = 0;
1029 if (PR_sscanf(nsCString(*this).get(), fmt, &result) == 1) {
1030 *aErrorCode = NS_OK;
1031 } else {
1032 *aErrorCode = NS_ERROR_FAILURE;
1033 }
1034
1035 return result;
1036 }
1037
1038 int64_t
ToInteger64(nsresult * aErrorCode,uint32_t aRadix) const1039 nsACString::ToInteger64(nsresult* aErrorCode, uint32_t aRadix) const
1040 {
1041 const char* fmt;
1042 switch (aRadix) {
1043 case 10:
1044 fmt = "%lli";
1045 break;
1046
1047 case 16:
1048 fmt = "%llx";
1049 break;
1050
1051 default:
1052 NS_ERROR("Unrecognized radix!");
1053 *aErrorCode = NS_ERROR_INVALID_ARG;
1054 return 0;
1055 }
1056
1057 int64_t result = 0;
1058 if (PR_sscanf(nsCString(*this).get(), fmt, &result) == 1) {
1059 *aErrorCode = NS_OK;
1060 } else {
1061 *aErrorCode = NS_ERROR_FAILURE;
1062 }
1063
1064 return result;
1065 }
1066 #endif // XPCOM_GLUE_AVOID_NSPR
1067
1068 // Substrings
1069
nsDependentSubstring(const abstract_string_type & aStr,uint32_t aStartPos)1070 nsDependentSubstring::nsDependentSubstring(const abstract_string_type& aStr,
1071 uint32_t aStartPos)
1072 {
1073 const char16_t* data;
1074 uint32_t len = NS_StringGetData(aStr, &data);
1075
1076 if (aStartPos > len) {
1077 aStartPos = len;
1078 }
1079
1080 NS_StringContainerInit2(*this, data + aStartPos, len - aStartPos,
1081 NS_STRING_CONTAINER_INIT_DEPEND |
1082 NS_STRING_CONTAINER_INIT_SUBSTRING);
1083 }
1084
nsDependentSubstring(const abstract_string_type & aStr,uint32_t aStartPos,uint32_t aLength)1085 nsDependentSubstring::nsDependentSubstring(const abstract_string_type& aStr,
1086 uint32_t aStartPos,
1087 uint32_t aLength)
1088 {
1089 const char16_t* data;
1090 uint32_t len = NS_StringGetData(aStr, &data);
1091
1092 if (aStartPos > len) {
1093 aStartPos = len;
1094 }
1095
1096 if (aStartPos + aLength > len) {
1097 aLength = len - aStartPos;
1098 }
1099
1100 NS_StringContainerInit2(*this, data + aStartPos, aLength,
1101 NS_STRING_CONTAINER_INIT_DEPEND |
1102 NS_STRING_CONTAINER_INIT_SUBSTRING);
1103 }
1104
nsDependentCSubstring(const abstract_string_type & aStr,uint32_t aStartPos)1105 nsDependentCSubstring::nsDependentCSubstring(const abstract_string_type& aStr,
1106 uint32_t aStartPos)
1107 {
1108 const char* data;
1109 uint32_t len = NS_CStringGetData(aStr, &data);
1110
1111 if (aStartPos > len) {
1112 aStartPos = len;
1113 }
1114
1115 NS_CStringContainerInit2(*this, data + aStartPos, len - aStartPos,
1116 NS_CSTRING_CONTAINER_INIT_DEPEND |
1117 NS_CSTRING_CONTAINER_INIT_SUBSTRING);
1118 }
1119
nsDependentCSubstring(const abstract_string_type & aStr,uint32_t aStartPos,uint32_t aLength)1120 nsDependentCSubstring::nsDependentCSubstring(const abstract_string_type& aStr,
1121 uint32_t aStartPos,
1122 uint32_t aLength)
1123 {
1124 const char* data;
1125 uint32_t len = NS_CStringGetData(aStr, &data);
1126
1127 if (aStartPos > len) {
1128 aStartPos = len;
1129 }
1130
1131 if (aStartPos + aLength > len) {
1132 aLength = len - aStartPos;
1133 }
1134
1135 NS_CStringContainerInit2(*this, data + aStartPos, aLength,
1136 NS_CSTRING_CONTAINER_INIT_DEPEND |
1137 NS_CSTRING_CONTAINER_INIT_SUBSTRING);
1138 }
1139
1140 // Utils
1141
1142 char*
ToNewUTF8String(const nsAString & aSource)1143 ToNewUTF8String(const nsAString& aSource)
1144 {
1145 nsCString temp;
1146 CopyUTF16toUTF8(aSource, temp);
1147 return NS_CStringCloneData(temp);
1148 }
1149
1150 void
CompressWhitespace(nsAString & aString)1151 CompressWhitespace(nsAString& aString)
1152 {
1153 char16_t* start;
1154 uint32_t len = NS_StringGetMutableData(aString, UINT32_MAX, &start);
1155 char16_t* end = start + len;
1156 char16_t* from = start;
1157 char16_t* to = start;
1158
1159 // Skip any leading whitespace
1160 while (from < end && NS_IsAsciiWhitespace(*from)) {
1161 from++;
1162 }
1163
1164 while (from < end) {
1165 char16_t theChar = *from++;
1166
1167 if (NS_IsAsciiWhitespace(theChar)) {
1168 // We found a whitespace char, so skip over any more
1169 while (from < end && NS_IsAsciiWhitespace(*from)) {
1170 from++;
1171 }
1172
1173 // Turn all whitespace into spaces
1174 theChar = ' ';
1175 }
1176
1177 *to++ = theChar;
1178 }
1179
1180 // Drop any trailing space
1181 if (to > start && to[-1] == ' ') {
1182 to--;
1183 }
1184
1185 // Re-terminate the string
1186 *to = '\0';
1187
1188 // Set the new length
1189 aString.SetLength(to - start);
1190 }
1191
1192 uint32_t
ToLowerCase(nsACString & aStr)1193 ToLowerCase(nsACString& aStr)
1194 {
1195 char* begin;
1196 char* end;
1197 uint32_t len = aStr.BeginWriting(&begin, &end);
1198
1199 for (; begin < end; ++begin) {
1200 *begin = NS_ToLower(*begin);
1201 }
1202
1203 return len;
1204 }
1205
1206 uint32_t
ToUpperCase(nsACString & aStr)1207 ToUpperCase(nsACString& aStr)
1208 {
1209 char* begin;
1210 char* end;
1211 uint32_t len = aStr.BeginWriting(&begin, &end);
1212
1213 for (; begin < end; ++begin) {
1214 *begin = NS_ToUpper(*begin);
1215 }
1216
1217 return len;
1218 }
1219
1220 uint32_t
ToLowerCase(const nsACString & aSrc,nsACString & aDest)1221 ToLowerCase(const nsACString& aSrc, nsACString& aDest)
1222 {
1223 const char* begin;
1224 const char* end;
1225 uint32_t len = aSrc.BeginReading(&begin, &end);
1226
1227 char* dest;
1228 NS_CStringGetMutableData(aDest, len, &dest);
1229
1230 for (; begin < end; ++begin, ++dest) {
1231 *dest = NS_ToLower(*begin);
1232 }
1233
1234 return len;
1235 }
1236
1237 uint32_t
ToUpperCase(const nsACString & aSrc,nsACString & aDest)1238 ToUpperCase(const nsACString& aSrc, nsACString& aDest)
1239 {
1240 const char* begin;
1241 const char* end;
1242 uint32_t len = aSrc.BeginReading(&begin, &end);
1243
1244 char* dest;
1245 NS_CStringGetMutableData(aDest, len, &dest);
1246
1247 for (; begin < end; ++begin, ++dest) {
1248 *dest = NS_ToUpper(*begin);
1249 }
1250
1251 return len;
1252 }
1253
1254 int32_t
CaseInsensitiveCompare(const char * aStrA,const char * aStrB,uint32_t aLen)1255 CaseInsensitiveCompare(const char* aStrA, const char* aStrB,
1256 uint32_t aLen)
1257 {
1258 for (const char* aend = aStrA + aLen; aStrA < aend; ++aStrA, ++aStrB) {
1259 char la = NS_ToLower(*aStrA);
1260 char lb = NS_ToLower(*aStrB);
1261
1262 if (la == lb) {
1263 continue;
1264 }
1265
1266 return la < lb ? -1 : 1;
1267 }
1268
1269 return 0;
1270 }
1271
1272 bool
ParseString(const nsACString & aSource,char aDelimiter,nsTArray<nsCString> & aArray)1273 ParseString(const nsACString& aSource, char aDelimiter,
1274 nsTArray<nsCString>& aArray)
1275 {
1276 int32_t start = 0;
1277 int32_t end = aSource.Length();
1278
1279 uint32_t oldLength = aArray.Length();
1280
1281 for (;;) {
1282 int32_t delimiter = aSource.FindChar(aDelimiter, start);
1283 if (delimiter < 0) {
1284 delimiter = end;
1285 }
1286
1287 if (delimiter != start) {
1288 if (!aArray.AppendElement(Substring(aSource, start, delimiter - start))) {
1289 aArray.RemoveElementsAt(oldLength, aArray.Length() - oldLength);
1290 return false;
1291 }
1292 }
1293
1294 if (delimiter == end) {
1295 break;
1296 }
1297 start = ++delimiter;
1298 if (start == end) {
1299 break;
1300 }
1301 }
1302
1303 return true;
1304 }
1305