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