|
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 /* 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 ascii_tolower(char aChar) |
|
34 { |
|
35 if (aChar >= 'A' && aChar <= 'Z') |
|
36 return aChar + ('a' - 'A'); |
|
37 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 FindChar1(const char* aDest,uint32_t aDestLength,int32_t anOffset,const char16_t aChar,int32_t aCount) { |
|
59 |
|
60 if(anOffset < 0) |
|
61 anOffset=0; |
|
62 |
|
63 if(aCount < 0) |
|
64 aCount = (int32_t)aDestLength; |
|
65 |
|
66 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 if(0<aCount) { |
|
72 |
|
73 const char* left= aDest+anOffset; |
|
74 const char* last= left+aCount; |
|
75 const char* max = aDest+aDestLength; |
|
76 const char* end = (last<max) ? last : max; |
|
77 |
|
78 int32_t theMax = end-left; |
|
79 if(0<theMax) { |
|
80 |
|
81 unsigned char theChar = (unsigned char) aChar; |
|
82 const char* result=(const char*)memchr(left, (int)theChar, theMax); |
|
83 |
|
84 if(result) |
|
85 return result-aDest; |
|
86 |
|
87 } |
|
88 } |
|
89 } |
|
90 |
|
91 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 FindChar2(const char16_t* aDest,uint32_t aDestLength,int32_t anOffset,const char16_t aChar,int32_t aCount) { |
|
108 |
|
109 if(anOffset < 0) |
|
110 anOffset=0; |
|
111 |
|
112 if(aCount < 0) |
|
113 aCount = (int32_t)aDestLength; |
|
114 |
|
115 if((0<aDestLength) && ((uint32_t)anOffset < aDestLength)) { |
|
116 |
|
117 if(0<aCount) { |
|
118 |
|
119 const char16_t* root = aDest; |
|
120 const char16_t* left = root+anOffset; |
|
121 const char16_t* last = left+aCount; |
|
122 const char16_t* max = root+aDestLength; |
|
123 const char16_t* end = (last<max) ? last : max; |
|
124 |
|
125 while(left<end){ |
|
126 |
|
127 if(*left==aChar) |
|
128 return (left-root); |
|
129 |
|
130 ++left; |
|
131 } |
|
132 } |
|
133 } |
|
134 |
|
135 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 RFindChar1(const char* aDest,uint32_t aDestLength,int32_t anOffset,const char16_t aChar,int32_t aCount) { |
|
153 |
|
154 if(anOffset < 0) |
|
155 anOffset=(int32_t)aDestLength-1; |
|
156 |
|
157 if(aCount < 0) |
|
158 aCount = int32_t(aDestLength); |
|
159 |
|
160 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 if(0 < aCount) { |
|
166 |
|
167 const char* rightmost = aDest + anOffset; |
|
168 const char* min = rightmost - aCount + 1; |
|
169 const char* leftmost = (min<aDest) ? aDest: min; |
|
170 |
|
171 char theChar=(char)aChar; |
|
172 while(leftmost <= rightmost){ |
|
173 |
|
174 if((*rightmost) == theChar) |
|
175 return rightmost - aDest; |
|
176 |
|
177 --rightmost; |
|
178 } |
|
179 } |
|
180 } |
|
181 |
|
182 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 RFindChar2(const char16_t* aDest,uint32_t aDestLength,int32_t anOffset,const char16_t aChar,int32_t aCount) { |
|
199 |
|
200 if(anOffset < 0) |
|
201 anOffset=(int32_t)aDestLength-1; |
|
202 |
|
203 if(aCount < 0) |
|
204 aCount = int32_t(aDestLength); |
|
205 |
|
206 if((0 < aDestLength) && ((uint32_t)anOffset < aDestLength)) { |
|
207 |
|
208 if(0 < aCount) { |
|
209 |
|
210 const char16_t* root = aDest; |
|
211 const char16_t* rightmost = root + anOffset; |
|
212 const char16_t* min = rightmost - aCount + 1; |
|
213 const char16_t* leftmost = (min<root) ? root: min; |
|
214 |
|
215 while(leftmost <= rightmost){ |
|
216 |
|
217 if((*rightmost) == aChar) |
|
218 return rightmost - root; |
|
219 |
|
220 --rightmost; |
|
221 } |
|
222 } |
|
223 } |
|
224 |
|
225 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 Compare1To1(const char* aStr1,const char* aStr2,uint32_t aCount,bool aIgnoreCase){ |
|
253 int32_t result=0; |
|
254 if(aIgnoreCase) |
|
255 result=int32_t(PL_strncasecmp(aStr1, aStr2, aCount)); |
|
256 else |
|
257 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 if ( result < -1 ) |
|
262 result = -1; |
|
263 else if ( result > 1 ) |
|
264 result = 1; |
|
265 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 Compare2To2(const char16_t* aStr1,const char16_t* aStr2,uint32_t aCount){ |
|
283 int32_t result; |
|
284 |
|
285 if ( aStr1 && aStr2 ) |
|
286 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 else if ( !aStr1 && !aStr2 ) |
|
293 result = 0; |
|
294 else if ( aStr1 ) |
|
295 result = 1; |
|
296 else |
|
297 result = -1; |
|
298 |
|
299 // alien comparisons may give answers outside the -1, 0, 1 expected by callers |
|
300 if ( result < -1 ) |
|
301 result = -1; |
|
302 else if ( result > 1 ) |
|
303 result = 1; |
|
304 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 Compare2To1(const char16_t* aStr1,const char* aStr2,uint32_t aCount,bool aIgnoreCase){ |
|
323 const char16_t* s1 = aStr1; |
|
324 const char *s2 = aStr2; |
|
325 |
|
326 if (aStr1 && aStr2) { |
|
327 if (aCount != 0) { |
|
328 do { |
|
329 |
|
330 char16_t c1 = *s1++; |
|
331 char16_t c2 = char16_t((unsigned char)*s2++); |
|
332 |
|
333 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 if (aIgnoreCase && c2>=128) |
|
340 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 if (aIgnoreCase && c1<128 && c2<128) { |
|
345 |
|
346 c1 = ascii_tolower(char(c1)); |
|
347 c2 = ascii_tolower(char(c2)); |
|
348 |
|
349 if (c1 == c2) continue; |
|
350 } |
|
351 |
|
352 if (c1 < c2) return -1; |
|
353 return 1; |
|
354 } |
|
355 } while (--aCount); |
|
356 } |
|
357 } |
|
358 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 CompressChars1(char* aString,uint32_t aLength,const char* aSet){ |
|
396 |
|
397 char* from = aString; |
|
398 char* end = aString + aLength; |
|
399 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 if(aSet && aString && (0 < aLength)){ |
|
404 uint32_t aSetLen=strlen(aSet); |
|
405 |
|
406 while (from < end) { |
|
407 char theChar = *from++; |
|
408 |
|
409 *to++=theChar; //always copy this char... |
|
410 |
|
411 if((kNotFound!=FindChar1(aSet,aSetLen,0,theChar,aSetLen))){ |
|
412 while (from < end) { |
|
413 theChar = *from++; |
|
414 if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){ |
|
415 *to++ = theChar; |
|
416 break; |
|
417 } |
|
418 } //while |
|
419 } //if |
|
420 } //if |
|
421 *to = 0; |
|
422 } |
|
423 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 CompressChars2(char16_t* aString,uint32_t aLength,const char* aSet){ |
|
441 |
|
442 char16_t* from = aString; |
|
443 char16_t* end = from + aLength; |
|
444 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 if(aSet && aString && (0 < aLength)){ |
|
449 uint32_t aSetLen=strlen(aSet); |
|
450 |
|
451 while (from < end) { |
|
452 char16_t theChar = *from++; |
|
453 |
|
454 *to++=theChar; //always copy this char... |
|
455 |
|
456 if((theChar<256) && (kNotFound!=FindChar1(aSet,aSetLen,0,theChar,aSetLen))){ |
|
457 while (from < end) { |
|
458 theChar = *from++; |
|
459 if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){ |
|
460 *to++ = theChar; |
|
461 break; |
|
462 } |
|
463 } //while |
|
464 } //if |
|
465 } //if |
|
466 *to = 0; |
|
467 } |
|
468 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 StripChars1(char* aString,uint32_t aLength,const char* aSet){ |
|
484 |
|
485 // XXX(darin): this code should defer writing until necessary. |
|
486 |
|
487 char* to = aString; |
|
488 char* from = aString-1; |
|
489 char* end = aString + aLength; |
|
490 |
|
491 if(aSet && aString && (0 < aLength)){ |
|
492 uint32_t aSetLen=strlen(aSet); |
|
493 while (++from < end) { |
|
494 char theChar = *from; |
|
495 if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){ |
|
496 *to++ = theChar; |
|
497 } |
|
498 } |
|
499 *to = 0; |
|
500 } |
|
501 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 StripChars2(char16_t* aString,uint32_t aLength,const char* aSet){ |
|
518 |
|
519 // XXX(darin): this code should defer writing until necessary. |
|
520 |
|
521 char16_t* to = aString; |
|
522 char16_t* from = aString-1; |
|
523 char16_t* end = to + aLength; |
|
524 |
|
525 if(aSet && aString && (0 < aLength)){ |
|
526 uint32_t aSetLen=strlen(aSet); |
|
527 while (++from < end) { |
|
528 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 if((255<theChar) || (kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen))){ |
|
533 *to++ = theChar; |
|
534 } |
|
535 } |
|
536 *to = 0; |
|
537 } |
|
538 return to - (char16_t*)aString; |
|
539 } |
|
540 |
|
541 /* ***** END RICKG BLOCK ***** */ |
|
542 |
|
543 static const char* kWhitespace="\b\t\r\n "; |
|
544 |
|
545 // This function is used to implement FindCharInSet and friends |
|
546 template <class CharT> |
|
547 #ifndef __SUNPRO_CC |
|
548 static |
|
549 #endif /* !__SUNPRO_CC */ |
|
550 CharT |
|
551 GetFindInSetFilter( const CharT* set) |
|
552 { |
|
553 CharT filter = ~CharT(0); // All bits set |
|
554 while (*set) { |
|
555 filter &= ~(*set); |
|
556 ++set; |
|
557 } |
|
558 return filter; |
|
559 } |
|
560 |
|
561 // This template class is used by our code to access rickg's buffer routines. |
|
562 template <class CharT> struct nsBufferRoutines {}; |
|
563 |
|
564 template <> |
|
565 struct nsBufferRoutines<char> |
|
566 { |
|
567 static |
|
568 int32_t compare( const char* a, const char* b, uint32_t max, bool ic ) |
|
569 { |
|
570 return Compare1To1(a, b, max, ic); |
|
571 } |
|
572 |
|
573 static |
|
574 int32_t compare( const char* a, const char16_t* b, uint32_t max, bool ic ) |
|
575 { |
|
576 return Compare1To2(a, b, max, ic); |
|
577 } |
|
578 |
|
579 static |
|
580 int32_t find_char( const char* s, uint32_t max, int32_t offset, const char16_t c, int32_t count ) |
|
581 { |
|
582 return FindChar1(s, max, offset, c, count); |
|
583 } |
|
584 |
|
585 static |
|
586 int32_t rfind_char( const char* s, uint32_t max, int32_t offset, const char16_t c, int32_t count ) |
|
587 { |
|
588 return RFindChar1(s, max, offset, c, count); |
|
589 } |
|
590 |
|
591 static |
|
592 char get_find_in_set_filter( const char* set ) |
|
593 { |
|
594 return GetFindInSetFilter(set); |
|
595 } |
|
596 |
|
597 static |
|
598 int32_t strip_chars( char* s, uint32_t len, const char* set ) |
|
599 { |
|
600 return StripChars1(s, len, set); |
|
601 } |
|
602 |
|
603 static |
|
604 int32_t compress_chars( char* s, uint32_t len, const char* set ) |
|
605 { |
|
606 return CompressChars1(s, len, set); |
|
607 } |
|
608 }; |
|
609 |
|
610 template <> |
|
611 struct nsBufferRoutines<char16_t> |
|
612 { |
|
613 static |
|
614 int32_t compare( const char16_t* a, const char16_t* b, uint32_t max, bool ic ) |
|
615 { |
|
616 NS_ASSERTION(!ic, "no case-insensitive compare here"); |
|
617 return Compare2To2(a, b, max); |
|
618 } |
|
619 |
|
620 static |
|
621 int32_t compare( const char16_t* a, const char* b, uint32_t max, bool ic ) |
|
622 { |
|
623 return Compare2To1(a, b, max, ic); |
|
624 } |
|
625 |
|
626 static |
|
627 int32_t find_char( const char16_t* s, uint32_t max, int32_t offset, const char16_t c, int32_t count ) |
|
628 { |
|
629 return FindChar2(s, max, offset, c, count); |
|
630 } |
|
631 |
|
632 static |
|
633 int32_t rfind_char( const char16_t* s, uint32_t max, int32_t offset, const char16_t c, int32_t count ) |
|
634 { |
|
635 return RFindChar2(s, max, offset, c, count); |
|
636 } |
|
637 |
|
638 static |
|
639 char16_t get_find_in_set_filter( const char16_t* set ) |
|
640 { |
|
641 return GetFindInSetFilter(set); |
|
642 } |
|
643 |
|
644 static |
|
645 char16_t get_find_in_set_filter( const char* set ) |
|
646 { |
|
647 return (~char16_t(0)^~char(0)) | GetFindInSetFilter(set); |
|
648 } |
|
649 |
|
650 static |
|
651 int32_t strip_chars( char16_t* s, uint32_t max, const char* set ) |
|
652 { |
|
653 return StripChars2(s, max, set); |
|
654 } |
|
655 |
|
656 static |
|
657 int32_t compress_chars( char16_t* s, uint32_t len, const char* set ) |
|
658 { |
|
659 return CompressChars2(s, len, set); |
|
660 } |
|
661 }; |
|
662 |
|
663 //----------------------------------------------------------------------------- |
|
664 |
|
665 template <class L, class R> |
|
666 #ifndef __SUNPRO_CC |
|
667 static |
|
668 #endif /* !__SUNPRO_CC */ |
|
669 int32_t |
|
670 FindSubstring( const L* big, uint32_t bigLen, |
|
671 const R* little, uint32_t littleLen, |
|
672 bool ignoreCase ) |
|
673 { |
|
674 if (littleLen > bigLen) |
|
675 return kNotFound; |
|
676 |
|
677 int32_t i, max = int32_t(bigLen - littleLen); |
|
678 for (i=0; i<=max; ++i, ++big) |
|
679 { |
|
680 if (nsBufferRoutines<L>::compare(big, little, littleLen, ignoreCase) == 0) |
|
681 return i; |
|
682 } |
|
683 |
|
684 return kNotFound; |
|
685 } |
|
686 |
|
687 template <class L, class R> |
|
688 #ifndef __SUNPRO_CC |
|
689 static |
|
690 #endif /* !__SUNPRO_CC */ |
|
691 int32_t |
|
692 RFindSubstring( const L* big, uint32_t bigLen, |
|
693 const R* little, uint32_t littleLen, |
|
694 bool ignoreCase ) |
|
695 { |
|
696 if (littleLen > bigLen) |
|
697 return kNotFound; |
|
698 |
|
699 int32_t i, max = int32_t(bigLen - littleLen); |
|
700 |
|
701 const L* iter = big + max; |
|
702 for (i=max; iter >= big; --i, --iter) |
|
703 { |
|
704 if (nsBufferRoutines<L>::compare(iter, little, littleLen, ignoreCase) == 0) |
|
705 return i; |
|
706 } |
|
707 |
|
708 return kNotFound; |
|
709 } |
|
710 |
|
711 template <class CharT, class SetCharT> |
|
712 #ifndef __SUNPRO_CC |
|
713 static |
|
714 #endif /* !__SUNPRO_CC */ |
|
715 int32_t |
|
716 FindCharInSet( const CharT* data, uint32_t dataLen, const SetCharT* set ) |
|
717 { |
|
718 CharT filter = nsBufferRoutines<CharT>::get_find_in_set_filter(set); |
|
719 |
|
720 const CharT* end = data + dataLen; |
|
721 for (const CharT* iter = data; iter < end; ++iter) |
|
722 { |
|
723 CharT currentChar = *iter; |
|
724 if (currentChar & filter) |
|
725 continue; // char is not in filter set; go on with next char. |
|
726 |
|
727 // test all chars |
|
728 const SetCharT* charInSet = set; |
|
729 CharT setChar = CharT(*charInSet); |
|
730 while (setChar) |
|
731 { |
|
732 if (setChar == currentChar) |
|
733 return iter - data; // found it! return index of the found char. |
|
734 |
|
735 setChar = CharT(*(++charInSet)); |
|
736 } |
|
737 } |
|
738 return kNotFound; |
|
739 } |
|
740 |
|
741 template <class CharT, class SetCharT> |
|
742 #ifndef __SUNPRO_CC |
|
743 static |
|
744 #endif /* !__SUNPRO_CC */ |
|
745 int32_t |
|
746 RFindCharInSet( const CharT* data, uint32_t dataLen, const SetCharT* set ) |
|
747 { |
|
748 CharT filter = nsBufferRoutines<CharT>::get_find_in_set_filter(set); |
|
749 |
|
750 for (const CharT* iter = data + dataLen - 1; iter >= data; --iter) |
|
751 { |
|
752 CharT currentChar = *iter; |
|
753 if (currentChar & filter) |
|
754 continue; // char is not in filter set; go on with next char. |
|
755 |
|
756 // test all chars |
|
757 const CharT* charInSet = set; |
|
758 CharT setChar = *charInSet; |
|
759 while (setChar) |
|
760 { |
|
761 if (setChar == currentChar) |
|
762 return iter - data; // found it! return index of the found char. |
|
763 |
|
764 setChar = *(++charInSet); |
|
765 } |
|
766 } |
|
767 return kNotFound; |
|
768 } |
|
769 |
|
770 /** |
|
771 * this method changes the meaning of |offset| and |count|: |
|
772 * |
|
773 * upon return, |
|
774 * |offset| specifies start of search range |
|
775 * |count| specifies length of search range |
|
776 */ |
|
777 static void |
|
778 Find_ComputeSearchRange( uint32_t bigLen, uint32_t littleLen, int32_t& offset, int32_t& count ) |
|
779 { |
|
780 // |count| specifies how many iterations to make from |offset| |
|
781 |
|
782 if (offset < 0) |
|
783 { |
|
784 offset = 0; |
|
785 } |
|
786 else if (uint32_t(offset) > bigLen) |
|
787 { |
|
788 count = 0; |
|
789 return; |
|
790 } |
|
791 |
|
792 int32_t maxCount = bigLen - offset; |
|
793 if (count < 0 || count > maxCount) |
|
794 { |
|
795 count = maxCount; |
|
796 } |
|
797 else |
|
798 { |
|
799 count += littleLen; |
|
800 if (count > maxCount) |
|
801 count = maxCount; |
|
802 } |
|
803 } |
|
804 |
|
805 /** |
|
806 * this method changes the meaning of |offset| and |count|: |
|
807 * |
|
808 * upon entry, |
|
809 * |offset| specifies the end point from which to search backwards |
|
810 * |count| specifies the number of iterations from |offset| |
|
811 * |
|
812 * upon return, |
|
813 * |offset| specifies start of search range |
|
814 * |count| specifies length of search range |
|
815 * |
|
816 * |
|
817 * EXAMPLE |
|
818 * |
|
819 * + -- littleLen=4 -- + |
|
820 * : : |
|
821 * |____|____|____|____|____|____|____|____|____|____|____|____| |
|
822 * : : |
|
823 * offset=5 bigLen=12 |
|
824 * |
|
825 * if count = 4, then we expect this function to return offset = 2 and |
|
826 * count = 7. |
|
827 * |
|
828 */ |
|
829 static void |
|
830 RFind_ComputeSearchRange( uint32_t bigLen, uint32_t littleLen, int32_t& offset, int32_t& count ) |
|
831 { |
|
832 if (littleLen > bigLen) |
|
833 { |
|
834 offset = 0; |
|
835 count = 0; |
|
836 return; |
|
837 } |
|
838 |
|
839 if (offset < 0) |
|
840 offset = bigLen - littleLen; |
|
841 if (count < 0) |
|
842 count = offset + 1; |
|
843 |
|
844 int32_t start = offset - count + 1; |
|
845 if (start < 0) |
|
846 start = 0; |
|
847 |
|
848 count = offset + littleLen - start; |
|
849 offset = start; |
|
850 } |
|
851 |
|
852 //----------------------------------------------------------------------------- |
|
853 |
|
854 // define nsString obsolete methods |
|
855 #include "string-template-def-unichar.h" |
|
856 #include "nsTStringObsolete.cpp" |
|
857 #include "string-template-undef.h" |
|
858 |
|
859 // define nsCString obsolete methods |
|
860 #include "string-template-def-char.h" |
|
861 #include "nsTStringObsolete.cpp" |
|
862 #include "string-template-undef.h" |
|
863 |
|
864 //----------------------------------------------------------------------------- |
|
865 |
|
866 // specialized methods: |
|
867 |
|
868 int32_t |
|
869 nsString::Find( const nsAFlatString& aString, int32_t aOffset, int32_t aCount ) const |
|
870 { |
|
871 // this method changes the meaning of aOffset and aCount: |
|
872 Find_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount); |
|
873 |
|
874 int32_t result = FindSubstring(mData + aOffset, aCount, static_cast<const char16_t*>(aString.get()), aString.Length(), false); |
|
875 if (result != kNotFound) |
|
876 result += aOffset; |
|
877 return result; |
|
878 } |
|
879 |
|
880 int32_t |
|
881 nsString::Find( const char16_t* aString, int32_t aOffset, int32_t aCount ) const |
|
882 { |
|
883 return Find(nsDependentString(aString), aOffset, aCount); |
|
884 } |
|
885 |
|
886 int32_t |
|
887 nsString::RFind( const nsAFlatString& aString, int32_t aOffset, int32_t aCount ) const |
|
888 { |
|
889 // this method changes the meaning of aOffset and aCount: |
|
890 RFind_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount); |
|
891 |
|
892 int32_t result = RFindSubstring(mData + aOffset, aCount, static_cast<const char16_t*>(aString.get()), aString.Length(), false); |
|
893 if (result != kNotFound) |
|
894 result += aOffset; |
|
895 return result; |
|
896 } |
|
897 |
|
898 int32_t |
|
899 nsString::RFind( const char16_t* aString, int32_t aOffset, int32_t aCount ) const |
|
900 { |
|
901 return RFind(nsDependentString(aString), aOffset, aCount); |
|
902 } |
|
903 |
|
904 int32_t |
|
905 nsString::FindCharInSet( const char16_t* aSet, int32_t aOffset ) const |
|
906 { |
|
907 if (aOffset < 0) |
|
908 aOffset = 0; |
|
909 else if (aOffset >= int32_t(mLength)) |
|
910 return kNotFound; |
|
911 |
|
912 int32_t result = ::FindCharInSet(mData + aOffset, mLength - aOffset, aSet); |
|
913 if (result != kNotFound) |
|
914 result += aOffset; |
|
915 return result; |
|
916 } |
|
917 |
|
918 void |
|
919 nsString::ReplaceChar( const char16_t* aSet, char16_t aNewChar ) |
|
920 { |
|
921 if (!EnsureMutable()) // XXX do this lazily? |
|
922 NS_ABORT_OOM(mLength); |
|
923 |
|
924 char16_t* data = mData; |
|
925 uint32_t lenRemaining = mLength; |
|
926 |
|
927 while (lenRemaining) |
|
928 { |
|
929 int32_t i = ::FindCharInSet(data, lenRemaining, aSet); |
|
930 if (i == kNotFound) |
|
931 break; |
|
932 |
|
933 data[i++] = aNewChar; |
|
934 data += i; |
|
935 lenRemaining -= i; |
|
936 } |
|
937 } |
|
938 |
|
939 |
|
940 /** |
|
941 * nsTString::Compare,CompareWithConversion,etc. |
|
942 */ |
|
943 |
|
944 int32_t |
|
945 nsCString::Compare( const char* aString, bool aIgnoreCase, int32_t aCount ) const |
|
946 { |
|
947 uint32_t strLen = char_traits::length(aString); |
|
948 |
|
949 int32_t maxCount = int32_t(XPCOM_MIN(mLength, strLen)); |
|
950 |
|
951 int32_t compareCount; |
|
952 if (aCount < 0 || aCount > maxCount) |
|
953 compareCount = maxCount; |
|
954 else |
|
955 compareCount = aCount; |
|
956 |
|
957 int32_t result = |
|
958 nsBufferRoutines<char>::compare(mData, aString, compareCount, aIgnoreCase); |
|
959 |
|
960 if (result == 0 && |
|
961 (aCount < 0 || strLen < uint32_t(aCount) || mLength < uint32_t(aCount))) |
|
962 { |
|
963 // Since the caller didn't give us a length to test, or strings shorter |
|
964 // than aCount, and compareCount characters matched, we have to assume |
|
965 // that the longer string is greater. |
|
966 |
|
967 if (mLength != strLen) |
|
968 result = (mLength < strLen) ? -1 : 1; |
|
969 } |
|
970 return result; |
|
971 } |
|
972 |
|
973 bool |
|
974 nsString::EqualsIgnoreCase( const char* aString, int32_t aCount ) const |
|
975 { |
|
976 uint32_t strLen = nsCharTraits<char>::length(aString); |
|
977 |
|
978 int32_t maxCount = int32_t(XPCOM_MIN(mLength, strLen)); |
|
979 |
|
980 int32_t compareCount; |
|
981 if (aCount < 0 || aCount > maxCount) |
|
982 compareCount = maxCount; |
|
983 else |
|
984 compareCount = aCount; |
|
985 |
|
986 int32_t result = |
|
987 nsBufferRoutines<char16_t>::compare(mData, aString, compareCount, true); |
|
988 |
|
989 if (result == 0 && |
|
990 (aCount < 0 || strLen < uint32_t(aCount) || mLength < uint32_t(aCount))) |
|
991 { |
|
992 // Since the caller didn't give us a length to test, or strings shorter |
|
993 // than aCount, and compareCount characters matched, we have to assume |
|
994 // that the longer string is greater. |
|
995 |
|
996 if (mLength != strLen) |
|
997 result = 1; // Arbitrarily using any number != 0 |
|
998 } |
|
999 return result == 0; |
|
1000 } |
|
1001 |
|
1002 |
|
1003 /** |
|
1004 * nsTString::ToDouble |
|
1005 */ |
|
1006 |
|
1007 double |
|
1008 nsCString::ToDouble(nsresult* aErrorCode) const |
|
1009 { |
|
1010 double res = 0.0; |
|
1011 if (mLength > 0) |
|
1012 { |
|
1013 char *conv_stopped; |
|
1014 const char *str = mData; |
|
1015 // Use PR_strtod, not strtod, since we don't want locale involved. |
|
1016 res = PR_strtod(str, &conv_stopped); |
|
1017 if (conv_stopped == str+mLength) |
|
1018 *aErrorCode = NS_OK; |
|
1019 else // Not all the string was scanned |
|
1020 *aErrorCode = NS_ERROR_ILLEGAL_VALUE; |
|
1021 } |
|
1022 else |
|
1023 { |
|
1024 // The string was too short (0 characters) |
|
1025 *aErrorCode = NS_ERROR_ILLEGAL_VALUE; |
|
1026 } |
|
1027 return res; |
|
1028 } |
|
1029 |
|
1030 double |
|
1031 nsString::ToDouble(nsresult* aErrorCode) const |
|
1032 { |
|
1033 return NS_LossyConvertUTF16toASCII(*this).ToDouble(aErrorCode); |
|
1034 } |
|
1035 |
|
1036 |
|
1037 /** |
|
1038 * nsTString::AssignWithConversion |
|
1039 */ |
|
1040 |
|
1041 void |
|
1042 nsCString::AssignWithConversion( const nsAString& aData ) |
|
1043 { |
|
1044 LossyCopyUTF16toASCII(aData, *this); |
|
1045 } |
|
1046 |
|
1047 void |
|
1048 nsString::AssignWithConversion( const nsACString& aData ) |
|
1049 { |
|
1050 CopyASCIItoUTF16(aData, *this); |
|
1051 } |
|
1052 |
|
1053 #endif // !MOZ_STRING_WITH_OBSOLETE_API |