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 <darin@meer.net>
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 :
55 : /* ***** BEGIN RICKG BLOCK *****
56 : *
57 : * NOTE: This section of code was extracted from rickg's bufferRoutines.h file.
58 : * For the most part it remains unmodified. We want to eliminate (or at
59 : * least clean up) this code at some point. If you find the formatting
60 : * in this section somewhat inconsistent, don't blame me! ;-)
61 : */
62 :
63 : // avoid STDC's tolower since it may do weird things with non-ASCII bytes
64 : inline char
65 278 : ascii_tolower(char aChar)
66 : {
67 278 : if (aChar >= 'A' && aChar <= 'Z')
68 50 : return aChar + ('a' - 'A');
69 228 : return aChar;
70 : }
71 :
72 : //-----------------------------------------------------------------------------
73 : //
74 : // This set of methods is used to search a buffer looking for a char.
75 : //
76 :
77 :
78 : /**
79 : * This methods cans the given buffer for the given char
80 : *
81 : * @update gess 02/17/00
82 : * @param aDest is the buffer to be searched
83 : * @param aDestLength is the size (in char-units, not bytes) of the buffer
84 : * @param anOffset is the start pos to begin searching
85 : * @param aChar is the target character we're looking for
86 : * @param aCount tells us how many characters to iterate through (which may be different than aLength); -1 means use full length.
87 : * @return index of pos if found, else -1 (kNotFound)
88 : */
89 : static PRInt32
90 2170816 : FindChar1(const char* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRInt32 aCount) {
91 :
92 2170816 : if(anOffset < 0)
93 0 : anOffset=0;
94 :
95 2170816 : if(aCount < 0)
96 0 : aCount = (PRInt32)aDestLength;
97 :
98 2170816 : if((aChar < 256) && (0 < aDestLength) && ((PRUint32)anOffset < aDestLength)) {
99 :
100 : //We'll only search if the given aChar is within the normal ascii a range,
101 : //(Since this string is definitely within the ascii range).
102 :
103 2170679 : if(0<aCount) {
104 :
105 2170679 : const char* left= aDest+anOffset;
106 2170679 : const char* last= left+aCount;
107 2170679 : const char* max = aDest+aDestLength;
108 2170679 : const char* end = (last<max) ? last : max;
109 :
110 2170679 : PRInt32 theMax = end-left;
111 2170679 : if(0<theMax) {
112 :
113 2170679 : unsigned char theChar = (unsigned char) aChar;
114 2170679 : const char* result=(const char*)memchr(left, (int)theChar, theMax);
115 :
116 2170679 : if(result)
117 1276733 : return result-aDest;
118 :
119 : }
120 : }
121 : }
122 :
123 894083 : return kNotFound;
124 : }
125 :
126 :
127 : /**
128 : * This methods cans the given buffer for the given char
129 : *
130 : * @update gess 3/25/98
131 : * @param aDest is the buffer to be searched
132 : * @param aDestLength is the size (in char-units, not bytes) of the buffer
133 : * @param anOffset is the start pos to begin searching
134 : * @param aChar is the target character we're looking for
135 : * @param aCount tells us how many characters to iterate through (which may be different than aLength); -1 means use full length.
136 : * @return index of pos if found, else -1 (kNotFound)
137 : */
138 : static PRInt32
139 0 : FindChar2(const PRUnichar* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRInt32 aCount) {
140 :
141 0 : if(anOffset < 0)
142 0 : anOffset=0;
143 :
144 0 : if(aCount < 0)
145 0 : aCount = (PRInt32)aDestLength;
146 :
147 0 : if((0<aDestLength) && ((PRUint32)anOffset < aDestLength)) {
148 :
149 0 : if(0<aCount) {
150 :
151 0 : const PRUnichar* root = aDest;
152 0 : const PRUnichar* left = root+anOffset;
153 0 : const PRUnichar* last = left+aCount;
154 0 : const PRUnichar* max = root+aDestLength;
155 0 : const PRUnichar* end = (last<max) ? last : max;
156 :
157 0 : while(left<end){
158 :
159 0 : if(*left==aChar)
160 0 : return (left-root);
161 :
162 0 : ++left;
163 : }
164 : }
165 : }
166 :
167 0 : return kNotFound;
168 : }
169 :
170 :
171 : /**
172 : * This methods cans the given buffer (in reverse) for the given char
173 : *
174 : * @update gess 02/17/00
175 : * @param aDest is the buffer to be searched
176 : * @param aDestLength is the size (in char-units, not bytes) of the buffer
177 : * @param anOffset is the start pos to begin searching
178 : * @param aChar is the target character we're looking for
179 : * @param aCount tells us how many characters to iterate through (which may be different than aLength); -1 means use full length.
180 : * @return index of pos if found, else -1 (kNotFound)
181 : */
182 :
183 : static PRInt32
184 3036 : RFindChar1(const char* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRInt32 aCount) {
185 :
186 3036 : if(anOffset < 0)
187 3036 : anOffset=(PRInt32)aDestLength-1;
188 :
189 3036 : if(aCount < 0)
190 3036 : aCount = PRInt32(aDestLength);
191 :
192 3036 : if((aChar<256) && (0 < aDestLength) && ((PRUint32)anOffset < aDestLength)) {
193 :
194 : //We'll only search if the given aChar is within the normal ascii a range,
195 : //(Since this string is definitely within the ascii range).
196 :
197 3036 : if(0 < aCount) {
198 :
199 3036 : const char* rightmost = aDest + anOffset;
200 3036 : const char* min = rightmost - aCount + 1;
201 3036 : const char* leftmost = (min<aDest) ? aDest: min;
202 :
203 3036 : char theChar=(char)aChar;
204 14216 : while(leftmost <= rightmost){
205 :
206 11132 : if((*rightmost) == theChar)
207 2988 : return rightmost - aDest;
208 :
209 8144 : --rightmost;
210 : }
211 : }
212 : }
213 :
214 48 : return kNotFound;
215 : }
216 :
217 :
218 : /**
219 : * This methods cans the given buffer for the given char
220 : *
221 : * @update gess 3/25/98
222 : * @param aDest is the buffer to be searched
223 : * @param aDestLength is the size (in char-units, not bytes) of the buffer
224 : * @param anOffset is the start pos to begin searching
225 : * @param aChar is the target character we're looking for
226 : * @param aCount tells us how many characters to iterate through (which may be different than aLength); -1 means use full length.
227 : * @return index of pos if found, else -1 (kNotFound)
228 : */
229 : static PRInt32
230 43 : RFindChar2(const PRUnichar* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRInt32 aCount) {
231 :
232 43 : if(anOffset < 0)
233 43 : anOffset=(PRInt32)aDestLength-1;
234 :
235 43 : if(aCount < 0)
236 43 : aCount = PRInt32(aDestLength);
237 :
238 43 : if((0 < aDestLength) && ((PRUint32)anOffset < aDestLength)) {
239 :
240 43 : if(0 < aCount) {
241 :
242 43 : const PRUnichar* root = aDest;
243 43 : const PRUnichar* rightmost = root + anOffset;
244 43 : const PRUnichar* min = rightmost - aCount + 1;
245 43 : const PRUnichar* leftmost = (min<root) ? root: min;
246 :
247 140 : while(leftmost <= rightmost){
248 :
249 97 : if((*rightmost) == aChar)
250 43 : return rightmost - root;
251 :
252 54 : --rightmost;
253 : }
254 : }
255 : }
256 :
257 0 : return kNotFound;
258 : }
259 :
260 : //-----------------------------------------------------------------------------
261 : //
262 : // This set of methods is used to compare one buffer onto another. The
263 : // functions are differentiated by the size of source and dest character
264 : // sizes. WARNING: Your destination buffer MUST be big enough to hold all the
265 : // source bytes. We don't validate these ranges here (this should be done in
266 : // higher level routines).
267 : //
268 :
269 :
270 : /**
271 : * This method compares the data in one buffer with another
272 : * @update gess 01/04/99
273 : * @param aStr1 is the first buffer to be compared
274 : * @param aStr2 is the 2nd buffer to be compared
275 : * @param aCount is the number of chars to compare
276 : * @param aIgnoreCase tells us whether to use a case-sensitive comparison
277 : * @return -1,0,1 depending on <,==,>
278 : */
279 : static
280 : #ifdef __SUNPRO_CC
281 : inline
282 : #endif /* __SUNPRO_CC */
283 : PRInt32
284 19787002 : Compare1To1(const char* aStr1,const char* aStr2,PRUint32 aCount,bool aIgnoreCase){
285 19787002 : PRInt32 result=0;
286 19787002 : if(aIgnoreCase)
287 29884 : result=PRInt32(PL_strncasecmp(aStr1, aStr2, aCount));
288 : else
289 19757118 : result=nsCharTraits<char>::compare(aStr1,aStr2,aCount);
290 :
291 : // alien comparisons may return out-of-bound answers
292 : // instead of the -1, 0, 1 expected by most clients
293 19787002 : if ( result < -1 )
294 281 : result = -1;
295 19786721 : else if ( result > 1 )
296 283 : result = 1;
297 19787002 : return result;
298 : }
299 :
300 : /**
301 : * This method compares the data in one buffer with another
302 : * @update gess 01/04/99
303 : * @param aStr1 is the first buffer to be compared
304 : * @param aStr2 is the 2nd buffer to be compared
305 : * @param aCount is the number of chars to compare
306 : * @param aIgnoreCase tells us whether to use a case-sensitive comparison
307 : * @return -1,0,1 depending on <,==,>
308 : */
309 : static
310 : #ifdef __SUNPRO_CC
311 : inline
312 : #endif /* __SUNPRO_CC */
313 : PRInt32
314 0 : Compare2To2(const PRUnichar* aStr1,const PRUnichar* aStr2,PRUint32 aCount){
315 : PRInt32 result;
316 :
317 0 : if ( aStr1 && aStr2 )
318 0 : result = nsCharTraits<PRUnichar>::compare(aStr1, aStr2, aCount);
319 :
320 : // The following cases are rare and survivable caller errors.
321 : // Two null pointers are equal, but any string, even 0 length
322 : // is greater than a null pointer. It might not really matter,
323 : // but we pick something reasonable anyway.
324 0 : else if ( !aStr1 && !aStr2 )
325 0 : result = 0;
326 0 : else if ( aStr1 )
327 0 : result = 1;
328 : else
329 0 : result = -1;
330 :
331 : // alien comparisons may give answers outside the -1, 0, 1 expected by callers
332 0 : if ( result < -1 )
333 0 : result = -1;
334 0 : else if ( result > 1 )
335 0 : result = 1;
336 0 : return result;
337 : }
338 :
339 :
340 : /**
341 : * This method compares the data in one buffer with another
342 : * @update gess 01/04/99
343 : * @param aStr1 is the first buffer to be compared
344 : * @param aStr2 is the 2nd buffer to be compared
345 : * @param aCount is the number of chars to compare
346 : * @param aIgnoreCase tells us whether to use a case-sensitive comparison
347 : * @return -1,0,1 depending on <,==,>
348 : */
349 : static
350 : #ifdef __SUNPRO_CC
351 : inline
352 : #endif /* __SUNPRO_CC */
353 : PRInt32
354 189 : Compare2To1(const PRUnichar* aStr1,const char* aStr2,PRUint32 aCount,bool aIgnoreCase){
355 189 : const PRUnichar* s1 = aStr1;
356 189 : const char *s2 = aStr2;
357 :
358 189 : if (aStr1 && aStr2) {
359 189 : if (aCount != 0) {
360 350 : do {
361 :
362 489 : PRUnichar c1 = *s1++;
363 489 : PRUnichar c2 = PRUnichar((unsigned char)*s2++);
364 :
365 489 : if (c1 != c2) {
366 : #ifdef NS_DEBUG
367 : // we won't warn on c1>=128 (the 2-byte value) because often
368 : // it is just fine to compare an constant, ascii value (i.e. "body")
369 : // against some non-ascii value (i.e. a unicode string that
370 : // was downloaded from a web page)
371 139 : if (aIgnoreCase && c2>=128)
372 0 : NS_WARNING("got a non-ASCII string, but we can't do an accurate case conversion!");
373 : #endif
374 :
375 : // can't do case conversion on characters out of our range
376 139 : if (aIgnoreCase && c1<128 && c2<128) {
377 :
378 139 : c1 = ascii_tolower(char(c1));
379 139 : c2 = ascii_tolower(char(c2));
380 :
381 139 : if (c1 == c2) continue;
382 : }
383 :
384 139 : if (c1 < c2) return -1;
385 139 : return 1;
386 : }
387 : } while (--aCount);
388 : }
389 : }
390 50 : return 0;
391 : }
392 :
393 :
394 : /**
395 : * This method compares the data in one buffer with another
396 : * @update gess 01/04/99
397 : * @param aStr1 is the first buffer to be compared
398 : * @param aStr2 is the 2nd buffer to be compared
399 : * @param aCount is the number of chars to compare
400 : * @param aIgnoreCase tells us whether to use a case-sensitive comparison
401 : * @return -1,0,1 depending on <,==,>
402 : */
403 : inline PRInt32
404 : Compare1To2(const char* aStr1,const PRUnichar* aStr2,PRUint32 aCount,bool aIgnoreCase){
405 : return Compare2To1(aStr2, aStr1, aCount, aIgnoreCase) * -1;
406 : }
407 :
408 :
409 : //-----------------------------------------------------------------------------
410 : //
411 : // This set of methods is used compress char sequences in a buffer...
412 : //
413 :
414 :
415 : /**
416 : * This method compresses duplicate runs of a given char from the given buffer
417 : *
418 : * @update rickg 03.23.2000
419 : * @param aString is the buffer to be manipulated
420 : * @param aLength is the length of the buffer
421 : * @param aSet tells us which chars to compress from given buffer
422 : * @param aEliminateLeading tells us whether to strip chars from the start of the buffer
423 : * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer
424 : * @return the new length of the given buffer
425 : */
426 : static PRInt32
427 28 : CompressChars1(char* aString,PRUint32 aLength,const char* aSet){
428 :
429 28 : char* from = aString;
430 28 : char* end = aString + aLength;
431 28 : char* to = from;
432 :
433 : //this code converts /n, /t, /r into normal space ' ';
434 : //it also compresses runs of whitespace down to a single char...
435 28 : if(aSet && aString && (0 < aLength)){
436 28 : PRUint32 aSetLen=strlen(aSet);
437 :
438 262 : while (from < end) {
439 206 : char theChar = *from++;
440 :
441 206 : *to++=theChar; //always copy this char...
442 :
443 206 : if((kNotFound!=FindChar1(aSet,aSetLen,0,theChar,aSetLen))){
444 0 : while (from < end) {
445 0 : theChar = *from++;
446 0 : if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){
447 0 : *to++ = theChar;
448 0 : break;
449 : }
450 : } //while
451 : } //if
452 : } //if
453 28 : *to = 0;
454 : }
455 28 : return to - aString;
456 : }
457 :
458 :
459 :
460 : /**
461 : * This method compresses duplicate runs of a given char from the given buffer
462 : *
463 : * @update rickg 03.23.2000
464 : * @param aString is the buffer to be manipulated
465 : * @param aLength is the length of the buffer
466 : * @param aSet tells us which chars to compress from given buffer
467 : * @param aEliminateLeading tells us whether to strip chars from the start of the buffer
468 : * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer
469 : * @return the new length of the given buffer
470 : */
471 : static PRInt32
472 1038 : CompressChars2(PRUnichar* aString,PRUint32 aLength,const char* aSet){
473 :
474 1038 : PRUnichar* from = aString;
475 1038 : PRUnichar* end = from + aLength;
476 1038 : PRUnichar* to = from;
477 :
478 : //this code converts /n, /t, /r into normal space ' ';
479 : //it also compresses runs of whitespace down to a single char...
480 1038 : if(aSet && aString && (0 < aLength)){
481 0 : PRUint32 aSetLen=strlen(aSet);
482 :
483 0 : while (from < end) {
484 0 : PRUnichar theChar = *from++;
485 :
486 0 : *to++=theChar; //always copy this char...
487 :
488 0 : if((theChar<256) && (kNotFound!=FindChar1(aSet,aSetLen,0,theChar,aSetLen))){
489 0 : while (from < end) {
490 0 : theChar = *from++;
491 0 : if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){
492 0 : *to++ = theChar;
493 0 : break;
494 : }
495 : } //while
496 : } //if
497 : } //if
498 0 : *to = 0;
499 : }
500 1038 : return to - (PRUnichar*)aString;
501 : }
502 :
503 : /**
504 : * This method strips chars in a given set from the given buffer
505 : *
506 : * @update gess 01/04/99
507 : * @param aString is the buffer to be manipulated
508 : * @param aLength is the length of the buffer
509 : * @param aSet tells us which chars to compress from given buffer
510 : * @param aEliminateLeading tells us whether to strip chars from the start of the buffer
511 : * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer
512 : * @return the new length of the given buffer
513 : */
514 : static PRInt32
515 5252 : StripChars1(char* aString,PRUint32 aLength,const char* aSet){
516 :
517 : // XXX(darin): this code should defer writing until necessary.
518 :
519 5252 : char* to = aString;
520 5252 : char* from = aString-1;
521 5252 : char* end = aString + aLength;
522 :
523 5252 : if(aSet && aString && (0 < aLength)){
524 3633 : PRUint32 aSetLen=strlen(aSet);
525 236143 : while (++from < end) {
526 228877 : char theChar = *from;
527 228877 : if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){
528 226349 : *to++ = theChar;
529 : }
530 : }
531 3633 : *to = 0;
532 : }
533 5252 : return to - (char*)aString;
534 : }
535 :
536 :
537 : /**
538 : * This method strips chars in a given set from the given buffer
539 : *
540 : * @update gess 01/04/99
541 : * @param aString is the buffer to be manipulated
542 : * @param aLength is the length of the buffer
543 : * @param aSet tells us which chars to compress from given buffer
544 : * @param aEliminateLeading tells us whether to strip chars from the start of the buffer
545 : * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer
546 : * @return the new length of the given buffer
547 : */
548 : static PRInt32
549 0 : StripChars2(PRUnichar* aString,PRUint32 aLength,const char* aSet){
550 :
551 : // XXX(darin): this code should defer writing until necessary.
552 :
553 0 : PRUnichar* to = aString;
554 0 : PRUnichar* from = aString-1;
555 0 : PRUnichar* end = to + aLength;
556 :
557 0 : if(aSet && aString && (0 < aLength)){
558 0 : PRUint32 aSetLen=strlen(aSet);
559 0 : while (++from < end) {
560 0 : PRUnichar theChar = *from;
561 : //Note the test for ascii range below. If you have a real unicode char,
562 : //and you're searching for chars in the (given) ascii string, there's no
563 : //point in doing the real search since it's out of the ascii range.
564 0 : if((255<theChar) || (kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen))){
565 0 : *to++ = theChar;
566 : }
567 : }
568 0 : *to = 0;
569 : }
570 0 : return to - (PRUnichar*)aString;
571 : }
572 :
573 : /* ***** END RICKG BLOCK ***** */
574 :
575 : static const char* kWhitespace="\b\t\r\n ";
576 :
577 : // This function is used to implement FindCharInSet and friends
578 : template <class CharT>
579 : #ifndef __SUNPRO_CC
580 : static
581 : #endif /* !__SUNPRO_CC */
582 : CharT
583 18604 : GetFindInSetFilter( const CharT* set)
584 : {
585 18604 : CharT filter = ~CharT(0); // All bits set
586 80767 : while (*set) {
587 43559 : filter &= ~(*set);
588 43559 : ++set;
589 : }
590 18604 : return filter;
591 : }
592 :
593 : // This template class is used by our code to access rickg's buffer routines.
594 : template <class CharT> struct nsBufferRoutines {};
595 :
596 : template <>
597 : struct nsBufferRoutines<char>
598 : {
599 : static
600 19787002 : PRInt32 compare( const char* a, const char* b, PRUint32 max, bool ic )
601 : {
602 19787002 : return Compare1To1(a, b, max, ic);
603 : }
604 :
605 : static
606 : PRInt32 compare( const char* a, const PRUnichar* b, PRUint32 max, bool ic )
607 : {
608 : return Compare1To2(a, b, max, ic);
609 : }
610 :
611 : static
612 : PRInt32 find_char( const char* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count )
613 : {
614 : return FindChar1(s, max, offset, c, count);
615 : }
616 :
617 : static
618 3036 : PRInt32 rfind_char( const char* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count )
619 : {
620 3036 : return RFindChar1(s, max, offset, c, count);
621 : }
622 :
623 : static
624 16297 : char get_find_in_set_filter( const char* set )
625 : {
626 16297 : return GetFindInSetFilter(set);
627 : }
628 :
629 : static
630 5252 : PRInt32 strip_chars( char* s, PRUint32 len, const char* set )
631 : {
632 5252 : return StripChars1(s, len, set);
633 : }
634 :
635 : static
636 28 : PRInt32 compress_chars( char* s, PRUint32 len, const char* set )
637 : {
638 28 : return CompressChars1(s, len, set);
639 : }
640 : };
641 :
642 : template <>
643 : struct nsBufferRoutines<PRUnichar>
644 : {
645 : static
646 0 : PRInt32 compare( const PRUnichar* a, const PRUnichar* b, PRUint32 max, bool ic )
647 : {
648 0 : NS_ASSERTION(!ic, "no case-insensitive compare here");
649 0 : return Compare2To2(a, b, max);
650 : }
651 :
652 : static
653 189 : PRInt32 compare( const PRUnichar* a, const char* b, PRUint32 max, bool ic )
654 : {
655 189 : return Compare2To1(a, b, max, ic);
656 : }
657 :
658 : static
659 : PRInt32 find_char( const PRUnichar* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count )
660 : {
661 : return FindChar2(s, max, offset, c, count);
662 : }
663 :
664 : static
665 43 : PRInt32 rfind_char( const PRUnichar* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count )
666 : {
667 43 : return RFindChar2(s, max, offset, c, count);
668 : }
669 :
670 : static
671 17 : PRUnichar get_find_in_set_filter( const PRUnichar* set )
672 : {
673 17 : return GetFindInSetFilter(set);
674 : }
675 :
676 : static
677 2290 : PRUnichar get_find_in_set_filter( const char* set )
678 : {
679 2290 : return (~PRUnichar(0)^~char(0)) | GetFindInSetFilter(set);
680 : }
681 :
682 : static
683 0 : PRInt32 strip_chars( PRUnichar* s, PRUint32 max, const char* set )
684 : {
685 0 : return StripChars2(s, max, set);
686 : }
687 :
688 : static
689 1038 : PRInt32 compress_chars( PRUnichar* s, PRUint32 len, const char* set )
690 : {
691 1038 : return CompressChars2(s, len, set);
692 : }
693 : };
694 :
695 : //-----------------------------------------------------------------------------
696 :
697 : template <class L, class R>
698 : #ifndef __SUNPRO_CC
699 : static
700 : #endif /* !__SUNPRO_CC */
701 : PRInt32
702 196463 : FindSubstring( const L* big, PRUint32 bigLen,
703 : const R* little, PRUint32 littleLen,
704 : bool ignoreCase )
705 : {
706 196463 : if (littleLen > bigLen)
707 480 : return kNotFound;
708 :
709 195983 : PRInt32 i, max = PRInt32(bigLen - littleLen);
710 19902406 : for (i=0; i<=max; ++i, ++big)
711 : {
712 19712276 : if (nsBufferRoutines<L>::compare(big, little, littleLen, ignoreCase) == 0)
713 5853 : return i;
714 : }
715 :
716 190130 : return kNotFound;
717 : }
718 :
719 : template <class L, class R>
720 : #ifndef __SUNPRO_CC
721 : static
722 : #endif /* !__SUNPRO_CC */
723 : PRInt32
724 2939 : RFindSubstring( const L* big, PRUint32 bigLen,
725 : const R* little, PRUint32 littleLen,
726 : bool ignoreCase )
727 : {
728 2939 : if (littleLen > bigLen)
729 372 : return kNotFound;
730 :
731 2567 : PRInt32 i, max = PRInt32(bigLen - littleLen);
732 :
733 2567 : const L* iter = big + max;
734 32824 : for (i=max; iter >= big; --i, --iter)
735 : {
736 32099 : if (nsBufferRoutines<L>::compare(iter, little, littleLen, ignoreCase) == 0)
737 1842 : return i;
738 : }
739 :
740 725 : return kNotFound;
741 : }
742 :
743 : template <class CharT, class SetCharT>
744 : #ifndef __SUNPRO_CC
745 : static
746 : #endif /* !__SUNPRO_CC */
747 : PRInt32
748 18604 : FindCharInSet( const CharT* data, PRUint32 dataLen, const SetCharT* set )
749 : {
750 18604 : CharT filter = nsBufferRoutines<CharT>::get_find_in_set_filter(set);
751 :
752 18604 : const CharT* end = data + dataLen;
753 310785 : for (const CharT* iter = data; iter < end; ++iter)
754 : {
755 294046 : CharT currentChar = *iter;
756 294046 : if (currentChar & filter)
757 290771 : continue; // char is not in filter set; go on with next char.
758 :
759 : // test all chars
760 3275 : const SetCharT* charInSet = set;
761 3275 : CharT setChar = CharT(*charInSet);
762 27008 : while (setChar)
763 : {
764 22323 : if (setChar == currentChar)
765 1865 : return iter - data; // found it! return index of the found char.
766 :
767 20458 : setChar = CharT(*(++charInSet));
768 : }
769 : }
770 16739 : return kNotFound;
771 : }
772 :
773 : template <class CharT, class SetCharT>
774 : #ifndef __SUNPRO_CC
775 : static
776 : #endif /* !__SUNPRO_CC */
777 : PRInt32
778 0 : RFindCharInSet( const CharT* data, PRUint32 dataLen, const SetCharT* set )
779 : {
780 0 : CharT filter = nsBufferRoutines<CharT>::get_find_in_set_filter(set);
781 :
782 0 : for (const CharT* iter = data + dataLen - 1; iter >= data; --iter)
783 : {
784 0 : CharT currentChar = *iter;
785 0 : if (currentChar & filter)
786 0 : continue; // char is not in filter set; go on with next char.
787 :
788 : // test all chars
789 0 : const CharT* charInSet = set;
790 0 : CharT setChar = *charInSet;
791 0 : while (setChar)
792 : {
793 0 : if (setChar == currentChar)
794 0 : return iter - data; // found it! return index of the found char.
795 :
796 0 : setChar = *(++charInSet);
797 : }
798 : }
799 0 : return kNotFound;
800 : }
801 :
802 : /**
803 : * this method changes the meaning of |offset| and |count|:
804 : *
805 : * upon return,
806 : * |offset| specifies start of search range
807 : * |count| specifies length of search range
808 : */
809 : static void
810 5306 : Find_ComputeSearchRange( PRUint32 bigLen, PRUint32 littleLen, PRInt32& offset, PRInt32& count )
811 : {
812 : // |count| specifies how many iterations to make from |offset|
813 :
814 5306 : if (offset < 0)
815 : {
816 0 : offset = 0;
817 : }
818 5306 : else if (PRUint32(offset) > bigLen)
819 : {
820 0 : count = 0;
821 0 : return;
822 : }
823 :
824 5306 : PRInt32 maxCount = bigLen - offset;
825 5306 : if (count < 0 || count > maxCount)
826 : {
827 5231 : count = maxCount;
828 : }
829 : else
830 : {
831 75 : count += littleLen;
832 75 : if (count > maxCount)
833 0 : count = maxCount;
834 : }
835 : }
836 :
837 : /**
838 : * this method changes the meaning of |offset| and |count|:
839 : *
840 : * upon entry,
841 : * |offset| specifies the end point from which to search backwards
842 : * |count| specifies the number of iterations from |offset|
843 : *
844 : * upon return,
845 : * |offset| specifies start of search range
846 : * |count| specifies length of search range
847 : *
848 : *
849 : * EXAMPLE
850 : *
851 : * + -- littleLen=4 -- +
852 : * : :
853 : * |____|____|____|____|____|____|____|____|____|____|____|____|
854 : * : :
855 : * offset=5 bigLen=12
856 : *
857 : * if count = 4, then we expect this function to return offset = 2 and
858 : * count = 7.
859 : *
860 : */
861 : static void
862 2939 : RFind_ComputeSearchRange( PRUint32 bigLen, PRUint32 littleLen, PRInt32& offset, PRInt32& count )
863 : {
864 2939 : if (littleLen > bigLen)
865 : {
866 372 : offset = 0;
867 372 : count = 0;
868 372 : return;
869 : }
870 :
871 2567 : if (offset < 0)
872 2567 : offset = bigLen - littleLen;
873 2567 : if (count < 0)
874 2566 : count = offset + 1;
875 :
876 2567 : PRInt32 start = offset - count + 1;
877 2567 : if (start < 0)
878 0 : start = 0;
879 :
880 2567 : count = offset + littleLen - start;
881 2567 : offset = start;
882 : }
883 :
884 : //-----------------------------------------------------------------------------
885 :
886 : // define nsString obsolete methods
887 : #include "string-template-def-unichar.h"
888 : #include "nsTStringObsolete.cpp"
889 : #include "string-template-undef.h"
890 :
891 : // define nsCString obsolete methods
892 : #include "string-template-def-char.h"
893 : #include "nsTStringObsolete.cpp"
894 : #include "string-template-undef.h"
895 :
896 : //-----------------------------------------------------------------------------
897 :
898 : // specialized methods:
899 :
900 : PRInt32
901 0 : nsString::Find( const nsAFlatString& aString, PRInt32 aOffset, PRInt32 aCount ) const
902 : {
903 : // this method changes the meaning of aOffset and aCount:
904 0 : Find_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount);
905 :
906 0 : PRInt32 result = FindSubstring(mData + aOffset, aCount, aString.get(), aString.Length(), false);
907 0 : if (result != kNotFound)
908 0 : result += aOffset;
909 0 : return result;
910 : }
911 :
912 : PRInt32
913 0 : nsString::Find( const PRUnichar* aString, PRInt32 aOffset, PRInt32 aCount ) const
914 : {
915 0 : return Find(nsDependentString(aString), aOffset, aCount);
916 : }
917 :
918 : PRInt32
919 0 : nsString::RFind( const nsAFlatString& aString, PRInt32 aOffset, PRInt32 aCount ) const
920 : {
921 : // this method changes the meaning of aOffset and aCount:
922 0 : RFind_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount);
923 :
924 0 : PRInt32 result = RFindSubstring(mData + aOffset, aCount, aString.get(), aString.Length(), false);
925 0 : if (result != kNotFound)
926 0 : result += aOffset;
927 0 : return result;
928 : }
929 :
930 : PRInt32
931 0 : nsString::RFind( const PRUnichar* aString, PRInt32 aOffset, PRInt32 aCount ) const
932 : {
933 0 : return RFind(nsDependentString(aString), aOffset, aCount);
934 : }
935 :
936 : PRInt32
937 17 : nsString::FindCharInSet( const PRUnichar* aSet, PRInt32 aOffset ) const
938 : {
939 17 : if (aOffset < 0)
940 0 : aOffset = 0;
941 17 : else if (aOffset >= PRInt32(mLength))
942 0 : return kNotFound;
943 :
944 17 : PRInt32 result = ::FindCharInSet(mData + aOffset, mLength - aOffset, aSet);
945 17 : if (result != kNotFound)
946 0 : result += aOffset;
947 17 : return result;
948 : }
949 :
950 :
951 : /**
952 : * nsTString::Compare,CompareWithConversion,etc.
953 : */
954 :
955 : PRInt32
956 42816 : nsCString::Compare( const char* aString, bool aIgnoreCase, PRInt32 aCount ) const
957 : {
958 42816 : PRUint32 strLen = char_traits::length(aString);
959 :
960 42816 : PRInt32 maxCount = PRInt32(NS_MIN(mLength, strLen));
961 :
962 : PRInt32 compareCount;
963 42816 : if (aCount < 0 || aCount > maxCount)
964 30270 : compareCount = maxCount;
965 : else
966 12546 : compareCount = aCount;
967 :
968 : PRInt32 result =
969 42816 : nsBufferRoutines<char>::compare(mData, aString, compareCount, aIgnoreCase);
970 :
971 42816 : if (result == 0 &&
972 : (aCount < 0 || strLen < PRUint32(aCount) || mLength < PRUint32(aCount)))
973 : {
974 : // Since the caller didn't give us a length to test, or strings shorter
975 : // than aCount, and compareCount characters matched, we have to assume
976 : // that the longer string is greater.
977 :
978 29336 : if (mLength != strLen)
979 8 : result = (mLength < strLen) ? -1 : 1;
980 : }
981 42816 : return result;
982 : }
983 :
984 : bool
985 0 : nsString::EqualsIgnoreCase( const char* aString, PRInt32 aCount ) const
986 : {
987 0 : PRUint32 strLen = nsCharTraits<char>::length(aString);
988 :
989 0 : PRInt32 maxCount = PRInt32(NS_MIN(mLength, strLen));
990 :
991 : PRInt32 compareCount;
992 0 : if (aCount < 0 || aCount > maxCount)
993 0 : compareCount = maxCount;
994 : else
995 0 : compareCount = aCount;
996 :
997 : PRInt32 result =
998 0 : nsBufferRoutines<PRUnichar>::compare(mData, aString, compareCount, true);
999 :
1000 0 : if (result == 0 &&
1001 : (aCount < 0 || strLen < PRUint32(aCount) || mLength < PRUint32(aCount)))
1002 : {
1003 : // Since the caller didn't give us a length to test, or strings shorter
1004 : // than aCount, and compareCount characters matched, we have to assume
1005 : // that the longer string is greater.
1006 :
1007 0 : if (mLength != strLen)
1008 0 : result = 1; // Arbitrarily using any number != 0
1009 : }
1010 0 : return result == 0;
1011 : }
1012 :
1013 :
1014 : /**
1015 : * nsTString::ToDouble
1016 : */
1017 :
1018 : double
1019 0 : nsCString::ToDouble(PRInt32* aErrorCode) const
1020 : {
1021 0 : double res = 0.0;
1022 0 : if (mLength > 0)
1023 : {
1024 : char *conv_stopped;
1025 0 : const char *str = mData;
1026 : // Use PR_strtod, not strtod, since we don't want locale involved.
1027 0 : res = PR_strtod(str, &conv_stopped);
1028 0 : if (conv_stopped == str+mLength)
1029 0 : *aErrorCode = (PRInt32) NS_OK;
1030 : else // Not all the string was scanned
1031 0 : *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE;
1032 : }
1033 : else
1034 : {
1035 : // The string was too short (0 characters)
1036 0 : *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE;
1037 : }
1038 0 : return res;
1039 : }
1040 :
1041 : double
1042 0 : nsString::ToDouble(PRInt32* aErrorCode) const
1043 : {
1044 0 : return NS_LossyConvertUTF16toASCII(*this).ToDouble(aErrorCode);
1045 : }
1046 :
1047 :
1048 : /**
1049 : * nsTString::AssignWithConversion
1050 : */
1051 :
1052 : void
1053 11 : nsCString::AssignWithConversion( const nsAString& aData )
1054 : {
1055 11 : LossyCopyUTF16toASCII(aData, *this);
1056 11 : }
1057 :
1058 : void
1059 15875 : nsString::AssignWithConversion( const nsACString& aData )
1060 : {
1061 15875 : CopyASCIItoUTF16(aData, *this);
1062 15875 : }
1063 :
1064 :
1065 : /**
1066 : * nsTString::AppendWithConversion
1067 : */
1068 :
1069 : void
1070 0 : nsCString::AppendWithConversion( const nsAString& aData )
1071 : {
1072 0 : LossyAppendUTF16toASCII(aData, *this);
1073 0 : }
1074 :
1075 : void
1076 0 : nsString::AppendWithConversion( const nsACString& aData )
1077 : {
1078 0 : AppendASCIItoUTF16(aData, *this);
1079 0 : }
1080 :
1081 : #endif // !MOZ_STRING_WITH_OBSOLETE_API
|