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