VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/string/src/nsStringObsolete.cpp@ 31259

Last change on this file since 31259 was 31259, checked in by vboxsync, 15 years ago

xpcom: Use RTMem* for memory alloc so that we can more easily wrap direct it to the electric fence heap.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.5 KB
Line 
1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim:set ts=2 sw=2 sts=2 et cindent: */
3/* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 *
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
10 *
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
15 *
16 * The Original Code is Mozilla.
17 *
18 * The Initial Developer of the Original Code is IBM Corporation.
19 * Portions created by IBM Corporation are Copyright (C) 2003
20 * IBM Corporation. All Rights Reserved.
21 *
22 * Contributor(s):
23 * Darin Fisher <[email protected]>
24 *
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
36 *
37 * ***** END LICENSE BLOCK ***** */
38
39#include "nsString.h"
40
41
42 /**
43 * nsTString obsolete API support
44 */
45
46#if MOZ_STRING_WITH_OBSOLETE_API
47
48#include "nsDependentString.h"
49#include "nsDependentSubstring.h"
50#include "nsReadableUtils.h"
51#include "nsCRT.h"
52#include "nsUTF8Utils.h"
53#include "prdtoa.h"
54#include "prprf.h"
55#ifdef VBOX_USE_IPRT_IN_XPCOM
56# include <iprt/mem.h>
57#endif
58
59/* ***** BEGIN RICKG BLOCK *****
60 *
61 * NOTE: This section of code was extracted from rickg's bufferRoutines.h file.
62 * For the most part it remains unmodified. We want to eliminate (or at
63 * least clean up) this code at some point. If you find the formatting
64 * in this section somewhat inconsistent, don't blame me! ;-)
65 */
66
67// XXXdarin what is wrong with STDC's tolower?
68inline char
69ascii_tolower(char aChar)
70{
71 if (aChar >= 'A' && aChar <= 'Z')
72 return aChar + ('a' - 'A');
73 return aChar;
74}
75
76//-----------------------------------------------------------------------------
77//
78// This set of methods is used to search a buffer looking for a char.
79//
80
81
82/**
83 * This methods cans the given buffer for the given char
84 *
85 * @update gess 02/17/00
86 * @param aDest is the buffer to be searched
87 * @param aDestLength is the size (in char-units, not bytes) of the buffer
88 * @param anOffset is the start pos to begin searching
89 * @param aChar is the target character we're looking for
90 * @param aCount tells us how many characters to iterate through (which may be different than aLength); -1 means use full length.
91 * @return index of pos if found, else -1 (kNotFound)
92 */
93static PRInt32
94FindChar1(const char* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRInt32 aCount) {
95
96 if(anOffset < 0)
97 anOffset=0;
98
99 if(aCount < 0)
100 aCount = (PRInt32)aDestLength;
101
102 if((aChar < 256) && (0 < aDestLength) && ((PRUint32)anOffset < aDestLength)) {
103
104 //We'll only search if the given aChar is within the normal ascii a range,
105 //(Since this string is definitely within the ascii range).
106
107 if(0<aCount) {
108
109 const char* left= aDest+anOffset;
110 const char* last= left+aCount;
111 const char* max = aDest+aDestLength;
112 const char* end = (last<max) ? last : max;
113
114 PRInt32 theMax = end-left;
115 if(0<theMax) {
116
117 unsigned char theChar = (unsigned char) aChar;
118 const char* result=(const char*)memchr(left, (int)theChar, theMax);
119
120 if(result)
121 return result-aDest;
122
123 }
124 }
125 }
126
127 return kNotFound;
128}
129
130
131/**
132 * This methods cans the given buffer for the given char
133 *
134 * @update gess 3/25/98
135 * @param aDest is the buffer to be searched
136 * @param aDestLength is the size (in char-units, not bytes) of the buffer
137 * @param anOffset is the start pos to begin searching
138 * @param aChar is the target character we're looking for
139 * @param aCount tells us how many characters to iterate through (which may be different than aLength); -1 means use full length.
140 * @return index of pos if found, else -1 (kNotFound)
141 */
142static PRInt32
143FindChar2(const PRUnichar* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRInt32 aCount) {
144
145 if(anOffset < 0)
146 anOffset=0;
147
148 if(aCount < 0)
149 aCount = (PRInt32)aDestLength;
150
151 if((0<aDestLength) && ((PRUint32)anOffset < aDestLength)) {
152
153 if(0<aCount) {
154
155 const PRUnichar* root = aDest;
156 const PRUnichar* left = root+anOffset;
157 const PRUnichar* last = left+aCount;
158 const PRUnichar* max = root+aDestLength;
159 const PRUnichar* end = (last<max) ? last : max;
160
161 while(left<end){
162
163 if(*left==aChar)
164 return (left-root);
165
166 ++left;
167 }
168 }
169 }
170
171 return kNotFound;
172}
173
174
175/**
176 * This methods cans the given buffer (in reverse) for the given char
177 *
178 * @update gess 02/17/00
179 * @param aDest is the buffer to be searched
180 * @param aDestLength is the size (in char-units, not bytes) of the buffer
181 * @param anOffset is the start pos to begin searching
182 * @param aChar is the target character we're looking for
183 * @param aCount tells us how many characters to iterate through (which may be different than aLength); -1 means use full length.
184 * @return index of pos if found, else -1 (kNotFound)
185 */
186
187static PRInt32
188RFindChar1(const char* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRInt32 aCount) {
189
190 if(anOffset < 0)
191 anOffset=(PRInt32)aDestLength-1;
192
193 if(aCount < 0)
194 aCount = PRInt32(aDestLength);
195
196 if((aChar<256) && (0 < aDestLength) && ((PRUint32)anOffset < aDestLength)) {
197
198 //We'll only search if the given aChar is within the normal ascii a range,
199 //(Since this string is definitely within the ascii range).
200
201 if(0 < aCount) {
202
203 const char* rightmost = aDest + anOffset;
204 const char* min = rightmost - aCount + 1;
205 const char* leftmost = (min<aDest) ? aDest: min;
206
207 char theChar=(char)aChar;
208 while(leftmost <= rightmost){
209
210 if((*rightmost) == theChar)
211 return rightmost - aDest;
212
213 --rightmost;
214 }
215 }
216 }
217
218 return kNotFound;
219}
220
221
222/**
223 * This methods cans the given buffer for the given char
224 *
225 * @update gess 3/25/98
226 * @param aDest is the buffer to be searched
227 * @param aDestLength is the size (in char-units, not bytes) of the buffer
228 * @param anOffset is the start pos to begin searching
229 * @param aChar is the target character we're looking for
230 * @param aCount tells us how many characters to iterate through (which may be different than aLength); -1 means use full length.
231 * @return index of pos if found, else -1 (kNotFound)
232 */
233static PRInt32
234RFindChar2(const PRUnichar* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRInt32 aCount) {
235
236 if(anOffset < 0)
237 anOffset=(PRInt32)aDestLength-1;
238
239 if(aCount < 0)
240 aCount = PRInt32(aDestLength);
241
242 if((0 < aDestLength) && ((PRUint32)anOffset < aDestLength)) {
243
244 if(0 < aCount) {
245
246 const PRUnichar* root = aDest;
247 const PRUnichar* rightmost = root + anOffset;
248 const PRUnichar* min = rightmost - aCount + 1;
249 const PRUnichar* leftmost = (min<root) ? root: min;
250
251 while(leftmost <= rightmost){
252
253 if((*rightmost) == aChar)
254 return rightmost - root;
255
256 --rightmost;
257 }
258 }
259 }
260
261 return kNotFound;
262}
263
264//-----------------------------------------------------------------------------
265//
266// This set of methods is used to compare one buffer onto another. The
267// functions are differentiated by the size of source and dest character
268// sizes. WARNING: Your destination buffer MUST be big enough to hold all the
269// source bytes. We don't validate these ranges here (this should be done in
270// higher level routines).
271//
272
273
274/**
275 * This method compares the data in one buffer with another
276 * @update gess 01/04/99
277 * @param aStr1 is the first buffer to be compared
278 * @param aStr2 is the 2nd buffer to be compared
279 * @param aCount is the number of chars to compare
280 * @param aIgnoreCase tells us whether to use a case-sensitive comparison
281 * @return -1,0,1 depending on <,==,>
282 */
283static
284#ifdef __SUNPRO_CC
285inline
286#endif /* __SUNPRO_CC */
287PRInt32
288Compare1To1(const char* aStr1,const char* aStr2,PRUint32 aCount,PRBool aIgnoreCase){
289 PRInt32 result=0;
290 if(aIgnoreCase)
291 result=PRInt32(PL_strncasecmp(aStr1, aStr2, aCount));
292 else
293 result=nsCharTraits<char>::compare(aStr1,aStr2,aCount);
294
295 // alien comparisons may return out-of-bound answers
296 // instead of the -1, 0, 1 expected by most clients
297 if ( result < -1 )
298 result = -1;
299 else if ( result > 1 )
300 result = 1;
301 return result;
302}
303
304/**
305 * This method compares the data in one buffer with another
306 * @update gess 01/04/99
307 * @param aStr1 is the first buffer to be compared
308 * @param aStr2 is the 2nd buffer to be compared
309 * @param aCount is the number of chars to compare
310 * @param aIgnoreCase tells us whether to use a case-sensitive comparison
311 * @return -1,0,1 depending on <,==,>
312 */
313static
314#ifdef __SUNPRO_CC
315inline
316#endif /* __SUNPRO_CC */
317PRInt32
318Compare2To2(const PRUnichar* aStr1,const PRUnichar* aStr2,PRUint32 aCount){
319 PRInt32 result;
320
321 if ( aStr1 && aStr2 )
322 result = nsCharTraits<PRUnichar>::compare(aStr1, aStr2, aCount);
323
324 // The following cases are rare and survivable caller errors.
325 // Two null pointers are equal, but any string, even 0 length
326 // is greater than a null pointer. It might not really matter,
327 // but we pick something reasonable anyway.
328 else if ( !aStr1 && !aStr2 )
329 result = 0;
330 else if ( aStr1 )
331 result = 1;
332 else
333 result = -1;
334
335 // alien comparisons may give answers outside the -1, 0, 1 expected by callers
336 if ( result < -1 )
337 result = -1;
338 else if ( result > 1 )
339 result = 1;
340 return result;
341}
342
343
344/**
345 * This method compares the data in one buffer with another
346 * @update gess 01/04/99
347 * @param aStr1 is the first buffer to be compared
348 * @param aStr2 is the 2nd buffer to be compared
349 * @param aCount is the number of chars to compare
350 * @param aIgnoreCase tells us whether to use a case-sensitive comparison
351 * @return -1,0,1 depending on <,==,>
352 */
353static
354#ifdef __SUNPRO_CC
355inline
356#endif /* __SUNPRO_CC */
357PRInt32
358Compare2To1(const PRUnichar* aStr1,const char* aStr2,PRUint32 aCount,PRBool aIgnoreCase){
359 const PRUnichar* s1 = aStr1;
360 const char *s2 = aStr2;
361
362 if (aStr1 && aStr2) {
363 if (aCount != 0) {
364 do {
365
366 PRUnichar c1 = *s1++;
367 PRUnichar c2 = PRUnichar((unsigned char)*s2++);
368
369 if (c1 != c2) {
370#ifdef NS_DEBUG
371 // we won't warn on c1>=128 (the 2-byte value) because often
372 // it is just fine to compare an constant, ascii value (i.e. "body")
373 // against some non-ascii value (i.e. a unicode string that
374 // was downloaded from a web page)
375 if (aIgnoreCase && c2>=128)
376 NS_WARNING("got a non-ASCII string, but we can't do an accurate case conversion!");
377#endif
378
379 // can't do case conversion on characters out of our range
380 if (aIgnoreCase && c1<128 && c2<128) {
381
382 c1 = ascii_tolower(char(c1));
383 c2 = ascii_tolower(char(c2));
384
385 if (c1 == c2) continue;
386 }
387
388 if (c1 < c2) return -1;
389 return 1;
390 }
391 } while (--aCount);
392 }
393 }
394 return 0;
395}
396
397
398/**
399 * This method compares the data in one buffer with another
400 * @update gess 01/04/99
401 * @param aStr1 is the first buffer to be compared
402 * @param aStr2 is the 2nd buffer to be compared
403 * @param aCount is the number of chars to compare
404 * @param aIgnoreCase tells us whether to use a case-sensitive comparison
405 * @return -1,0,1 depending on <,==,>
406 */
407inline PRInt32
408Compare1To2(const char* aStr1,const PRUnichar* aStr2,PRUint32 aCount,PRBool aIgnoreCase){
409 return Compare2To1(aStr2, aStr1, aCount, aIgnoreCase) * -1;
410}
411
412
413//-----------------------------------------------------------------------------
414//
415// This set of methods is used compress char sequences in a buffer...
416//
417
418
419/**
420 * This method compresses duplicate runs of a given char from the given buffer
421 *
422 * @update rickg 03.23.2000
423 * @param aString is the buffer to be manipulated
424 * @param aLength is the length of the buffer
425 * @param aSet tells us which chars to compress from given buffer
426 * @param aEliminateLeading tells us whether to strip chars from the start of the buffer
427 * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer
428 * @return the new length of the given buffer
429 */
430static PRInt32
431CompressChars1(char* aString,PRUint32 aLength,const char* aSet){
432
433 char* from = aString;
434 char* end = aString + aLength;
435 char* to = from;
436
437 //this code converts /n, /t, /r into normal space ' ';
438 //it also compresses runs of whitespace down to a single char...
439 if(aSet && aString && (0 < aLength)){
440 PRUint32 aSetLen=strlen(aSet);
441
442 while (from < end) {
443 char theChar = *from++;
444
445 *to++=theChar; //always copy this char...
446
447 if((kNotFound!=FindChar1(aSet,aSetLen,0,theChar,aSetLen))){
448 while (from < end) {
449 theChar = *from++;
450 if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){
451 *to++ = theChar;
452 break;
453 }
454 } //while
455 } //if
456 } //if
457 *to = 0;
458 }
459 return to - aString;
460}
461
462
463
464/**
465 * This method compresses duplicate runs of a given char from the given buffer
466 *
467 * @update rickg 03.23.2000
468 * @param aString is the buffer to be manipulated
469 * @param aLength is the length of the buffer
470 * @param aSet tells us which chars to compress from given buffer
471 * @param aEliminateLeading tells us whether to strip chars from the start of the buffer
472 * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer
473 * @return the new length of the given buffer
474 */
475static PRInt32
476CompressChars2(PRUnichar* aString,PRUint32 aLength,const char* aSet){
477
478 PRUnichar* from = aString;
479 PRUnichar* end = from + aLength;
480 PRUnichar* to = from;
481
482 //this code converts /n, /t, /r into normal space ' ';
483 //it also compresses runs of whitespace down to a single char...
484 if(aSet && aString && (0 < aLength)){
485 PRUint32 aSetLen=strlen(aSet);
486
487 while (from < end) {
488 PRUnichar theChar = *from++;
489
490 *to++=theChar; //always copy this char...
491
492 if((theChar<256) && (kNotFound!=FindChar1(aSet,aSetLen,0,theChar,aSetLen))){
493 while (from < end) {
494 theChar = *from++;
495 if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){
496 *to++ = theChar;
497 break;
498 }
499 } //while
500 } //if
501 } //if
502 *to = 0;
503 }
504 return to - (PRUnichar*)aString;
505}
506
507/**
508 * This method strips chars in a given set from the given buffer
509 *
510 * @update gess 01/04/99
511 * @param aString is the buffer to be manipulated
512 * @param aLength is the length of the buffer
513 * @param aSet tells us which chars to compress from given buffer
514 * @param aEliminateLeading tells us whether to strip chars from the start of the buffer
515 * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer
516 * @return the new length of the given buffer
517 */
518static PRInt32
519StripChars1(char* aString,PRUint32 aLength,const char* aSet){
520
521 // XXXdarin this code should defer writing until necessary.
522
523 char* to = aString;
524 char* from = aString-1;
525 char* end = aString + aLength;
526
527 if(aSet && aString && (0 < aLength)){
528 PRUint32 aSetLen=strlen(aSet);
529 while (++from < end) {
530 char theChar = *from;
531 if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){
532 *to++ = theChar;
533 }
534 }
535 *to = 0;
536 }
537 return to - (char*)aString;
538}
539
540
541/**
542 * This method strips chars in a given set from the given buffer
543 *
544 * @update gess 01/04/99
545 * @param aString is the buffer to be manipulated
546 * @param aLength is the length of the buffer
547 * @param aSet tells us which chars to compress from given buffer
548 * @param aEliminateLeading tells us whether to strip chars from the start of the buffer
549 * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer
550 * @return the new length of the given buffer
551 */
552static PRInt32
553StripChars2(PRUnichar* aString,PRUint32 aLength,const char* aSet){
554
555 // XXXdarin this code should defer writing until necessary.
556
557 PRUnichar* to = aString;
558 PRUnichar* from = aString-1;
559 PRUnichar* end = to + aLength;
560
561 if(aSet && aString && (0 < aLength)){
562 PRUint32 aSetLen=strlen(aSet);
563 while (++from < end) {
564 PRUnichar theChar = *from;
565 //Note the test for ascii range below. If you have a real unicode char,
566 //and you're searching for chars in the (given) ascii string, there's no
567 //point in doing the real search since it's out of the ascii range.
568 if((255<theChar) || (kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen))){
569 *to++ = theChar;
570 }
571 }
572 *to = 0;
573 }
574 return to - (PRUnichar*)aString;
575}
576
577/* ***** END RICKG BLOCK ***** */
578
579static const char* kWhitespace="\b\t\r\n ";
580
581// This function is used to implement FindCharInSet and friends
582template <class CharT>
583#ifndef __SUNPRO_CC
584static
585#endif /* !__SUNPRO_CC */
586CharT
587GetFindInSetFilter( const CharT* set)
588 {
589 CharT filter = ~CharT(0); // All bits set
590 while (*set) {
591 filter &= ~(*set);
592 ++set;
593 }
594 return filter;
595 }
596
597// This template class is used by our code to access rickg's buffer routines.
598template <class CharT> struct nsBufferRoutines {};
599
600NS_SPECIALIZE_TEMPLATE
601struct nsBufferRoutines<char>
602 {
603 static
604 PRInt32 compare( const char* a, const char* b, PRUint32 max, PRBool ic )
605 {
606 return Compare1To1(a, b, max, ic);
607 }
608
609 static
610 PRInt32 compare( const char* a, const PRUnichar* b, PRUint32 max, PRBool ic )
611 {
612 return Compare1To2(a, b, max, ic);
613 }
614
615 static
616 PRInt32 find_char( const char* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count )
617 {
618 return FindChar1(s, max, offset, c, count);
619 }
620
621 static
622 PRInt32 rfind_char( const char* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count )
623 {
624 return RFindChar1(s, max, offset, c, count);
625 }
626
627 static
628 char get_find_in_set_filter( const char* set )
629 {
630 return GetFindInSetFilter(set);
631 }
632
633 static
634 PRInt32 strip_chars( char* s, PRUint32 len, const char* set )
635 {
636 return StripChars1(s, len, set);
637 }
638
639 static
640 PRInt32 compress_chars( char* s, PRUint32 len, const char* set )
641 {
642 return CompressChars1(s, len, set);
643 }
644 };
645
646NS_SPECIALIZE_TEMPLATE
647struct nsBufferRoutines<PRUnichar>
648 {
649 static
650 PRInt32 compare( const PRUnichar* a, const PRUnichar* b, PRUint32 max, PRBool ic )
651 {
652 NS_ASSERTION(!ic, "no case-insensitive compare here");
653 return Compare2To2(a, b, max);
654 }
655
656 static
657 PRInt32 compare( const PRUnichar* a, const char* b, PRUint32 max, PRBool ic )
658 {
659 return Compare2To1(a, b, max, ic);
660 }
661
662 static
663 PRInt32 find_char( const PRUnichar* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count )
664 {
665 return FindChar2(s, max, offset, c, count);
666 }
667
668 static
669 PRInt32 rfind_char( const PRUnichar* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count )
670 {
671 return RFindChar2(s, max, offset, c, count);
672 }
673
674 static
675 PRUnichar get_find_in_set_filter( const PRUnichar* set )
676 {
677 return GetFindInSetFilter(set);
678 }
679
680 static
681 PRUnichar get_find_in_set_filter( const char* set )
682 {
683 return (~PRUnichar(0)^~char(0)) | GetFindInSetFilter(set);
684 }
685
686 static
687 PRInt32 strip_chars( PRUnichar* s, PRUint32 max, const char* set )
688 {
689 return StripChars2(s, max, set);
690 }
691
692 static
693 PRInt32 compress_chars( PRUnichar* s, PRUint32 len, const char* set )
694 {
695 return CompressChars2(s, len, set);
696 }
697 };
698
699//-----------------------------------------------------------------------------
700
701template <class L, class R>
702#ifndef __SUNPRO_CC
703static
704#endif /* !__SUNPRO_CC */
705PRInt32
706FindSubstring( const L* big, PRUint32 bigLen,
707 const R* little, PRUint32 littleLen,
708 PRBool ignoreCase )
709 {
710 if (littleLen > bigLen)
711 return kNotFound;
712
713 PRInt32 i, max = PRInt32(bigLen - littleLen);
714 for (i=0; i<=max; ++i, ++big)
715 {
716 if (nsBufferRoutines<L>::compare(big, little, littleLen, ignoreCase) == 0)
717 return i;
718 }
719
720 return kNotFound;
721 }
722
723template <class L, class R>
724#ifndef __SUNPRO_CC
725static
726#endif /* !__SUNPRO_CC */
727PRInt32
728RFindSubstring( const L* big, PRUint32 bigLen,
729 const R* little, PRUint32 littleLen,
730 PRBool ignoreCase )
731 {
732 if (littleLen > bigLen)
733 return kNotFound;
734
735 PRInt32 i, max = PRInt32(bigLen - littleLen);
736
737 const L* iter = big + max;
738 for (i=max; iter >= big; --i, --iter)
739 {
740 if (nsBufferRoutines<L>::compare(iter, little, littleLen, ignoreCase) == 0)
741 return i;
742 }
743
744 return kNotFound;
745 }
746
747template <class CharT, class SetCharT>
748#ifndef __SUNPRO_CC
749static
750#endif /* !__SUNPRO_CC */
751PRInt32
752FindCharInSet( const CharT* data, PRUint32 dataLen, const SetCharT* set )
753 {
754 CharT filter = nsBufferRoutines<CharT>::get_find_in_set_filter(set);
755
756 const CharT* end = data + dataLen;
757 for (const CharT* iter = data; iter < end; ++iter)
758 {
759 CharT currentChar = *iter;
760 if (currentChar & filter)
761 continue; // char is not in filter set; go on with next char.
762
763 // test all chars
764 const SetCharT* charInSet = set;
765 CharT setChar = CharT(*charInSet);
766 while (setChar)
767 {
768 if (setChar == currentChar)
769 return iter - data; // found it! return index of the found char.
770
771 setChar = CharT(*(++charInSet));
772 }
773 }
774 return kNotFound;
775 }
776
777template <class CharT, class SetCharT>
778#ifndef __SUNPRO_CC
779static
780#endif /* !__SUNPRO_CC */
781PRInt32
782RFindCharInSet( const CharT* data, PRUint32 dataLen, const SetCharT* set )
783 {
784 CharT filter = nsBufferRoutines<CharT>::get_find_in_set_filter(set);
785
786 for (const CharT* iter = data + dataLen - 1; iter >= data; --iter)
787 {
788 CharT currentChar = *iter;
789 if (currentChar & filter)
790 continue; // char is not in filter set; go on with next char.
791
792 // test all chars
793 const CharT* charInSet = set;
794 CharT setChar = *charInSet;
795 while (setChar)
796 {
797 if (setChar == currentChar)
798 return iter - data; // found it! return index of the found char.
799
800 setChar = *(++charInSet);
801 }
802 }
803 return kNotFound;
804 }
805
806/**
807 * This is a copy of |PR_cnvtf| with a bug fixed. (The second argument
808 * of PR_dtoa is 2 rather than 1.)
809 *
810 * XXXdarin if this is the right thing, then why wasn't it fixed in NSPR?!?
811 */
812void
813Modified_cnvtf(char *buf, int bufsz, int prcsn, double fval)
814{
815 PRIntn decpt, sign, numdigits;
816 char *num, *nump;
817 char *bufp = buf;
818 char *endnum;
819
820 /* If anything fails, we store an empty string in 'buf' */
821#ifdef VBOX_USE_IPRT_IN_XPCOM
822 num = (char*)RTMemAlloc(bufsz);
823#else
824 num = (char*)malloc(bufsz);
825#endif
826 if (num == NULL) {
827 buf[0] = '\0';
828 return;
829 }
830 if (PR_dtoa(fval, 2, prcsn, &decpt, &sign, &endnum, num, bufsz)
831 == PR_FAILURE) {
832 buf[0] = '\0';
833 goto done;
834 }
835 numdigits = endnum - num;
836 nump = num;
837
838 /*
839 * The NSPR code had a fancy way of checking that we weren't dealing
840 * with -0.0 or -NaN, but I'll just use < instead.
841 * XXX Should we check !isnan(fval) as well? Is it portable? We
842 * probably don't need to bother since NAN isn't portable.
843 */
844 if (sign && fval < 0.0f) {
845 *bufp++ = '-';
846 }
847
848 if (decpt == 9999) {
849 while ((*bufp++ = *nump++) != 0) {} /* nothing to execute */
850 goto done;
851 }
852
853 if (decpt > (prcsn+1) || decpt < -(prcsn-1) || decpt < -5) {
854 *bufp++ = *nump++;
855 if (numdigits != 1) {
856 *bufp++ = '.';
857 }
858
859 while (*nump != '\0') {
860 *bufp++ = *nump++;
861 }
862 *bufp++ = 'e';
863 PR_snprintf(bufp, bufsz - (bufp - buf), "%+d", decpt-1);
864 }
865 else if (decpt >= 0) {
866 if (decpt == 0) {
867 *bufp++ = '0';
868 }
869 else {
870 while (decpt--) {
871 if (*nump != '\0') {
872 *bufp++ = *nump++;
873 }
874 else {
875 *bufp++ = '0';
876 }
877 }
878 }
879 if (*nump != '\0') {
880 *bufp++ = '.';
881 while (*nump != '\0') {
882 *bufp++ = *nump++;
883 }
884 }
885 *bufp++ = '\0';
886 }
887 else if (decpt < 0) {
888 *bufp++ = '0';
889 *bufp++ = '.';
890 while (decpt++) {
891 *bufp++ = '0';
892 }
893
894 while (*nump != '\0') {
895 *bufp++ = *nump++;
896 }
897 *bufp++ = '\0';
898 }
899done:
900#ifdef VBOX_USE_IPRT_IN_XPCOM
901 RTMemFree(num);
902#else
903 free(num);
904#endif
905}
906
907 /**
908 * this method changes the meaning of |offset| and |count|:
909 *
910 * upon return,
911 * |offset| specifies start of search range
912 * |count| specifies length of search range
913 */
914static void
915Find_ComputeSearchRange( PRUint32 bigLen, PRUint32 littleLen, PRInt32& offset, PRInt32& count )
916 {
917 // |count| specifies how many iterations to make from |offset|
918
919 if (offset < 0)
920 {
921 offset = 0;
922 }
923 else if (PRUint32(offset) > bigLen)
924 {
925 count = 0;
926 return;
927 }
928
929 PRInt32 maxCount = bigLen - offset;
930 if (count < 0 || count > maxCount)
931 {
932 count = maxCount;
933 }
934 else
935 {
936 count += littleLen;
937 if (count > maxCount)
938 count = maxCount;
939 }
940 }
941
942 /**
943 * this method changes the meaning of |offset| and |count|:
944 *
945 * upon entry,
946 * |offset| specifies the end point from which to search backwards
947 * |count| specifies the number of iterations from |offset|
948 *
949 * upon return,
950 * |offset| specifies start of search range
951 * |count| specifies length of search range
952 *
953 *
954 * EXAMPLE
955 *
956 * + -- littleLen=4 -- +
957 * : :
958 * |____|____|____|____|____|____|____|____|____|____|____|____|
959 * : :
960 * offset=5 bigLen=12
961 *
962 * if count = 4, then we expect this function to return offset = 2 and
963 * count = 7.
964 *
965 */
966static void
967RFind_ComputeSearchRange( PRUint32 bigLen, PRUint32 littleLen, PRInt32& offset, PRInt32& count )
968 {
969 if (littleLen > bigLen)
970 {
971 offset = 0;
972 count = 0;
973 return;
974 }
975
976 if (offset < 0)
977 offset = bigLen - littleLen;
978 if (count < 0)
979 count = offset + 1;
980
981 PRInt32 start = offset - count + 1;
982 if (start < 0)
983 start = 0;
984
985 count = offset + littleLen - start;
986 offset = start;
987 }
988
989//-----------------------------------------------------------------------------
990
991 // define nsString obsolete methods
992#include "string-template-def-unichar.h"
993#include "nsTStringObsolete.cpp"
994#include "string-template-undef.h"
995
996 // define nsCString obsolete methods
997#include "string-template-def-char.h"
998#include "nsTStringObsolete.cpp"
999#include "string-template-undef.h"
1000
1001//-----------------------------------------------------------------------------
1002
1003// specialized methods:
1004
1005PRInt32
1006nsString::Find( const nsAFlatString& aString, PRInt32 aOffset, PRInt32 aCount ) const
1007 {
1008 // this method changes the meaning of aOffset and aCount:
1009 Find_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount);
1010
1011 PRInt32 result = FindSubstring(mData + aOffset, aCount, aString.get(), aString.Length(), PR_FALSE);
1012 if (result != kNotFound)
1013 result += aOffset;
1014 return result;
1015 }
1016
1017PRInt32
1018nsString::Find( const PRUnichar* aString, PRInt32 aOffset, PRInt32 aCount ) const
1019 {
1020 return Find(nsDependentString(aString), aOffset, aCount);
1021 }
1022
1023PRInt32
1024nsString::RFind( const nsAFlatString& aString, PRInt32 aOffset, PRInt32 aCount ) const
1025 {
1026 // this method changes the meaning of aOffset and aCount:
1027 RFind_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount);
1028
1029 PRInt32 result = RFindSubstring(mData + aOffset, aCount, aString.get(), aString.Length(), PR_FALSE);
1030 if (result != kNotFound)
1031 result += aOffset;
1032 return result;
1033 }
1034
1035PRInt32
1036nsString::RFind( const PRUnichar* aString, PRInt32 aOffset, PRInt32 aCount ) const
1037 {
1038 return RFind(nsDependentString(aString), aOffset, aCount);
1039 }
1040
1041PRInt32
1042nsString::FindCharInSet( const PRUnichar* aSet, PRInt32 aOffset ) const
1043 {
1044 if (aOffset < 0)
1045 aOffset = 0;
1046 else if (aOffset >= PRInt32(mLength))
1047 return kNotFound;
1048
1049 PRInt32 result = ::FindCharInSet(mData + aOffset, mLength - aOffset, aSet);
1050 if (result != kNotFound)
1051 result += aOffset;
1052 return result;
1053 }
1054
1055
1056 /**
1057 * nsTString::Compare,CompareWithConversion,etc.
1058 */
1059
1060PRInt32
1061nsCString::Compare( const char* aString, PRBool aIgnoreCase, PRInt32 aCount ) const
1062 {
1063 PRUint32 strLen = char_traits::length(aString);
1064
1065 PRInt32 maxCount = PRInt32(NS_MIN(mLength, strLen));
1066
1067 PRInt32 compareCount;
1068 if (aCount < 0 || aCount > maxCount)
1069 compareCount = maxCount;
1070 else
1071 compareCount = aCount;
1072
1073 PRInt32 result =
1074 nsBufferRoutines<char>::compare(mData, aString, compareCount, aIgnoreCase);
1075
1076 if (result == 0 &&
1077 (aCount < 0 || strLen < PRUint32(aCount) || mLength < PRUint32(aCount)))
1078 {
1079 // Since the caller didn't give us a length to test, or strings shorter
1080 // than aCount, and compareCount characters matched, we have to assume
1081 // that the longer string is greater.
1082
1083 if (mLength != strLen)
1084 result = (mLength < strLen) ? -1 : 1;
1085 }
1086 return result;
1087 }
1088
1089PRBool
1090nsString::EqualsIgnoreCase( const char* aString, PRInt32 aCount ) const
1091 {
1092 PRUint32 strLen = nsCharTraits<char>::length(aString);
1093
1094 PRInt32 maxCount = PRInt32(NS_MIN(mLength, strLen));
1095
1096 PRInt32 compareCount;
1097 if (aCount < 0 || aCount > maxCount)
1098 compareCount = maxCount;
1099 else
1100 compareCount = aCount;
1101
1102 PRInt32 result =
1103 nsBufferRoutines<PRUnichar>::compare(mData, aString, compareCount, PR_TRUE);
1104
1105 if (result == 0 &&
1106 (aCount < 0 || strLen < PRUint32(aCount) || mLength < PRUint32(aCount)))
1107 {
1108 // Since the caller didn't give us a length to test, or strings shorter
1109 // than aCount, and compareCount characters matched, we have to assume
1110 // that the longer string is greater.
1111
1112 if (mLength != strLen)
1113 result = 1; // Arbitrarily using any number != 0
1114 }
1115 return result == 0;
1116 }
1117
1118 /**
1119 * ToCString, ToFloat, ToInteger
1120 */
1121
1122char*
1123nsString::ToCString( char* aBuf, PRUint32 aBufLength, PRUint32 aOffset ) const
1124 {
1125 // because the old implementation checked aBuf
1126 if (!(aBuf && aBufLength > 0 && aOffset <= mLength))
1127 return nsnull;
1128
1129 PRUint32 maxCount = NS_MIN(aBufLength-1, mLength - aOffset);
1130
1131 LossyConvertEncoding<PRUnichar, char> converter(aBuf);
1132 converter.write(mData + aOffset, maxCount);
1133 converter.write_terminator();
1134 return aBuf;
1135 }
1136
1137float
1138nsCString::ToFloat(PRInt32* aErrorCode) const
1139 {
1140 float res = 0.0f;
1141 if (mLength > 0)
1142 {
1143 char *conv_stopped;
1144 const char *str = mData;
1145 // Use PR_strtod, not strtod, since we don't want locale involved.
1146 res = (float)PR_strtod(str, &conv_stopped);
1147 if (conv_stopped == str+mLength)
1148 *aErrorCode = (PRInt32) NS_OK;
1149 else // Not all the string was scanned
1150 *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE;
1151 }
1152 else
1153 {
1154 // The string was too short (0 characters)
1155 *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE;
1156 }
1157 return res;
1158 }
1159
1160float
1161nsString::ToFloat(PRInt32* aErrorCode) const
1162 {
1163 float res = 0.0f;
1164 char buf[100];
1165 if (mLength > 0 && mLength < sizeof(buf))
1166 {
1167 char *conv_stopped;
1168 const char *str = ToCString(buf, sizeof(buf));
1169 // Use PR_strtod, not strtod, since we don't want locale involved.
1170 res = (float)PR_strtod(str, &conv_stopped);
1171 if (conv_stopped == str+mLength)
1172 *aErrorCode = (PRInt32) NS_OK;
1173 else // Not all the string was scanned
1174 *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE;
1175 }
1176 else
1177 {
1178 // The string was too short (0 characters) or too long (sizeof(buf))
1179 *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE;
1180 }
1181 return res;
1182 }
1183
1184
1185 /**
1186 * nsTString::AssignWithConversion
1187 */
1188
1189void
1190nsCString::AssignWithConversion( const nsAString& aData )
1191 {
1192 LossyCopyUTF16toASCII(aData, *this);
1193 }
1194
1195void
1196nsString::AssignWithConversion( const nsACString& aData )
1197 {
1198 CopyASCIItoUTF16(aData, *this);
1199 }
1200
1201
1202 /**
1203 * nsTString::AppendWithConversion
1204 */
1205
1206void
1207nsCString::AppendWithConversion( const nsAString& aData )
1208 {
1209 LossyAppendUTF16toASCII(aData, *this);
1210 }
1211
1212void
1213nsString::AppendWithConversion( const nsACString& aData )
1214 {
1215 AppendASCIItoUTF16(aData, *this);
1216 }
1217
1218
1219 /**
1220 * nsTString::AppendInt
1221 */
1222
1223void
1224nsCString::AppendInt( PRInt32 aInteger, PRInt32 aRadix )
1225 {
1226 char buf[20];
1227 const char* fmt;
1228 switch (aRadix) {
1229 case 8:
1230 fmt = "%o";
1231 break;
1232 case 10:
1233 fmt = "%d";
1234 break;
1235 default:
1236 NS_ASSERTION(aRadix == 16, "Invalid radix!");
1237 fmt = "%x";
1238 }
1239 PR_snprintf(buf, sizeof(buf), fmt, aInteger);
1240 Append(buf);
1241 }
1242
1243void
1244nsString::AppendInt( PRInt32 aInteger, PRInt32 aRadix )
1245 {
1246 char buf[20];
1247 const char* fmt;
1248 switch (aRadix) {
1249 case 8:
1250 fmt = "%o";
1251 break;
1252 case 10:
1253 fmt = "%d";
1254 break;
1255 default:
1256 NS_ASSERTION(aRadix == 16, "Invalid radix!");
1257 fmt = "%x";
1258 }
1259 PR_snprintf(buf, sizeof(buf), fmt, aInteger);
1260 AppendASCIItoUTF16(buf, *this);
1261 }
1262
1263void
1264nsCString::AppendInt( PRInt64 aInteger, PRInt32 aRadix )
1265 {
1266 char buf[30];
1267 const char* fmt;
1268 switch (aRadix) {
1269 case 8:
1270 fmt = "%llo";
1271 break;
1272 case 10:
1273 fmt = "%lld";
1274 break;
1275 default:
1276 NS_ASSERTION(aRadix == 16, "Invalid radix!");
1277 fmt = "%llx";
1278 }
1279 PR_snprintf(buf, sizeof(buf), fmt, aInteger);
1280 Append(buf);
1281 }
1282
1283void
1284nsString::AppendInt( PRInt64 aInteger, PRInt32 aRadix )
1285 {
1286 char buf[30];
1287 const char* fmt;
1288 switch (aRadix) {
1289 case 8:
1290 fmt = "%llo";
1291 break;
1292 case 10:
1293 fmt = "%lld";
1294 break;
1295 default:
1296 NS_ASSERTION(aRadix == 16, "Invalid radix!");
1297 fmt = "%llx";
1298 }
1299 PR_snprintf(buf, sizeof(buf), fmt, aInteger);
1300 AppendASCIItoUTF16(buf, *this);
1301 }
1302
1303 /**
1304 * nsTString::AppendFloat
1305 */
1306
1307void
1308nsCString::AppendFloat( double aFloat )
1309 {
1310 char buf[40];
1311 // Use Modified_cnvtf, which is locale-insensitive, instead of the
1312 // locale-sensitive PR_snprintf or sprintf(3)
1313 Modified_cnvtf(buf, sizeof(buf), 6, aFloat);
1314 Append(buf);
1315 }
1316
1317void
1318nsString::AppendFloat( double aFloat )
1319 {
1320 char buf[40];
1321 // Use Modified_cnvtf, which is locale-insensitive, instead of the
1322 // locale-sensitive PR_snprintf or sprintf(3)
1323 Modified_cnvtf(buf, sizeof(buf), 6, aFloat);
1324 AppendWithConversion(buf);
1325 }
1326
1327#endif // !MOZ_STRING_WITH_OBSOLETE_API
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette