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