xpcom/string/src/nsStringObsolete.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial