| 1 | /* | 
| 2 |  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org) | 
| 3 |  *  Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. | 
| 4 |  *  Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) | 
| 5 |  *  Copyright (C) 2009 Google Inc. All rights reserved. | 
| 6 |  * | 
| 7 |  *  This library is free software; you can redistribute it and/or | 
| 8 |  *  modify it under the terms of the GNU Library General Public | 
| 9 |  *  License as published by the Free Software Foundation; either | 
| 10 |  *  version 2 of the License, or (at your option) any later version. | 
| 11 |  * | 
| 12 |  *  This library is distributed in the hope that it will be useful, | 
| 13 |  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| 14 |  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
| 15 |  *  Library General Public License for more details. | 
| 16 |  * | 
| 17 |  *  You should have received a copy of the GNU Library General Public License | 
| 18 |  *  along with this library; see the file COPYING.LIB.  If not, write to | 
| 19 |  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 
| 20 |  *  Boston, MA 02110-1301, USA. | 
| 21 |  * | 
| 22 |  */ | 
| 23 |  | 
| 24 | #include "config.h" | 
| 25 | #include "UString.h" | 
| 26 |  | 
| 27 | #include "JSGlobalObjectFunctions.h" | 
| 28 | #include "Collector.h" | 
| 29 | #include "dtoa.h" | 
| 30 | #include "Identifier.h" | 
| 31 | #include "Operations.h" | 
| 32 | #include <ctype.h> | 
| 33 | #include <limits.h> | 
| 34 | #include <limits> | 
| 35 | #include <math.h> | 
| 36 | #include <stdio.h> | 
| 37 | #include <stdlib.h> | 
| 38 | #include <string.h> | 
| 39 | #include <wtf/ASCIICType.h> | 
| 40 | #include <wtf/Assertions.h> | 
| 41 | #include <wtf/MathExtras.h> | 
| 42 | #include <wtf/StringExtras.h> | 
| 43 | #include <wtf/Vector.h> | 
| 44 | #include <wtf/unicode/UTF8.h> | 
| 45 | #include <wtf/StringExtras.h> | 
| 46 |  | 
| 47 | #if HAVE(STRINGS_H) | 
| 48 | #include <strings.h> | 
| 49 | #endif | 
| 50 |  | 
| 51 | using namespace WTF; | 
| 52 | using namespace WTF::Unicode; | 
| 53 | using namespace std; | 
| 54 |  | 
| 55 | namespace JSC { | 
| 56 |   | 
| 57 | extern const double NaN; | 
| 58 | extern const double Inf; | 
| 59 |  | 
| 60 | CString::CString(const char* c) | 
| 61 |     : m_length(strlen(s: c)) | 
| 62 |     , m_data(new char[m_length + 1]) | 
| 63 | { | 
| 64 |     memcpy(dest: m_data, src: c, n: m_length + 1); | 
| 65 | } | 
| 66 |  | 
| 67 | CString::CString(const char* c, size_t length) | 
| 68 |     : m_length(length) | 
| 69 |     , m_data(new char[length + 1]) | 
| 70 | { | 
| 71 |     memcpy(dest: m_data, src: c, n: m_length); | 
| 72 |     m_data[m_length] = 0; | 
| 73 | } | 
| 74 |  | 
| 75 | CString::CString(const CString& b) | 
| 76 | { | 
| 77 |     m_length = b.m_length; | 
| 78 |     if (b.m_data) { | 
| 79 |         m_data = new char[m_length + 1]; | 
| 80 |         memcpy(dest: m_data, src: b.m_data, n: m_length + 1); | 
| 81 |     } else | 
| 82 |         m_data = 0; | 
| 83 | } | 
| 84 |  | 
| 85 | CString::~CString() | 
| 86 | { | 
| 87 |     delete [] m_data; | 
| 88 | } | 
| 89 |  | 
| 90 | CString CString::adopt(char* c, size_t length) | 
| 91 | { | 
| 92 |     CString s; | 
| 93 |     s.m_data = c; | 
| 94 |     s.m_length = length; | 
| 95 |     return s; | 
| 96 | } | 
| 97 |  | 
| 98 | CString& CString::append(const CString& t) | 
| 99 | { | 
| 100 |     char* n; | 
| 101 |     n = new char[m_length + t.m_length + 1]; | 
| 102 |     if (m_length) | 
| 103 |         memcpy(dest: n, src: m_data, n: m_length); | 
| 104 |     if (t.m_length) | 
| 105 |         memcpy(dest: n + m_length, src: t.m_data, n: t.m_length); | 
| 106 |     m_length += t.m_length; | 
| 107 |     n[m_length] = 0; | 
| 108 |  | 
| 109 |     delete [] m_data; | 
| 110 |     m_data = n; | 
| 111 |  | 
| 112 |     return *this; | 
| 113 | } | 
| 114 |  | 
| 115 | CString& CString::operator=(const char* c) | 
| 116 | { | 
| 117 |     if (m_data) | 
| 118 |         delete [] m_data; | 
| 119 |     m_length = strlen(s: c); | 
| 120 |     m_data = new char[m_length + 1]; | 
| 121 |     memcpy(dest: m_data, src: c, n: m_length + 1); | 
| 122 |  | 
| 123 |     return *this; | 
| 124 | } | 
| 125 |  | 
| 126 | CString& CString::operator=(const CString& str) | 
| 127 | { | 
| 128 |     if (this == &str) | 
| 129 |         return *this; | 
| 130 |  | 
| 131 |     if (m_data) | 
| 132 |         delete [] m_data; | 
| 133 |     m_length = str.m_length; | 
| 134 |     if (str.m_data) { | 
| 135 |         m_data = new char[m_length + 1]; | 
| 136 |         memcpy(dest: m_data, src: str.m_data, n: m_length + 1); | 
| 137 |     } else | 
| 138 |         m_data = 0; | 
| 139 |  | 
| 140 |     return *this; | 
| 141 | } | 
| 142 |  | 
| 143 | bool operator==(const CString& c1, const CString& c2) | 
| 144 | { | 
| 145 |     size_t len = c1.size(); | 
| 146 |     return len == c2.size() && (len == 0 || memcmp(s1: c1.c_str(), s2: c2.c_str(), n: len) == 0); | 
| 147 | } | 
| 148 |  | 
| 149 | // These static strings are immutable, except for rc, whose initial value is chosen to  | 
| 150 | // reduce the possibility of it becoming zero due to ref/deref not being thread-safe. | 
| 151 | static UChar sharedEmptyChar; | 
| 152 | UStringImpl* UStringImpl::s_null; | 
| 153 | UStringImpl* UStringImpl::s_empty; | 
| 154 | UString* UString::nullUString; | 
| 155 |  | 
| 156 | void initializeUString() | 
| 157 | { | 
| 158 |     UStringImpl::s_null = new UStringImpl(0, 0, UStringImpl::ConstructStaticString); | 
| 159 |     UStringImpl::s_empty = new UStringImpl(&sharedEmptyChar, 0, UStringImpl::ConstructStaticString); | 
| 160 |     UString::nullUString = new UString; | 
| 161 | } | 
| 162 |  | 
| 163 | static PassRefPtr<UString::Rep> createRep(const char* c) | 
| 164 | { | 
| 165 |     if (!c) | 
| 166 |         return &UString::Rep::null(); | 
| 167 |  | 
| 168 |     if (!c[0]) | 
| 169 |         return &UString::Rep::empty(); | 
| 170 |  | 
| 171 |     size_t length = strlen(s: c); | 
| 172 |     UChar* d; | 
| 173 |     PassRefPtr<UStringImpl> result = UStringImpl::tryCreateUninitialized(length, output&: d); | 
| 174 |     if (!result) | 
| 175 |         return &UString::Rep::null(); | 
| 176 |  | 
| 177 |     for (size_t i = 0; i < length; i++) | 
| 178 |         d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend | 
| 179 |     return result; | 
| 180 | } | 
| 181 |  | 
| 182 | static inline PassRefPtr<UString::Rep> createRep(const char* c, int length) | 
| 183 | { | 
| 184 |     if (!c) | 
| 185 |         return &UString::Rep::null(); | 
| 186 |  | 
| 187 |     if (!length) | 
| 188 |         return &UString::Rep::empty(); | 
| 189 |  | 
| 190 |     UChar* d; | 
| 191 |     PassRefPtr<UStringImpl> result = UStringImpl::tryCreateUninitialized(length, output&: d); | 
| 192 |     if (!result) | 
| 193 |         return &UString::Rep::null(); | 
| 194 |  | 
| 195 |     for (int i = 0; i < length; i++) | 
| 196 |         d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend | 
| 197 |     return result; | 
| 198 | } | 
| 199 |  | 
| 200 | UString::UString(const char* c) | 
| 201 |     : m_rep(createRep(c)) | 
| 202 | { | 
| 203 | } | 
| 204 |  | 
| 205 | UString::UString(const char* c, int length) | 
| 206 |     : m_rep(createRep(c, length)) | 
| 207 | { | 
| 208 | } | 
| 209 |  | 
| 210 | UString::UString(const UChar* c, int length) | 
| 211 | { | 
| 212 |     if (length == 0)  | 
| 213 |         m_rep = &Rep::empty(); | 
| 214 |     else | 
| 215 |         m_rep = Rep::create(buffer: c, length); | 
| 216 | } | 
| 217 |  | 
| 218 | UString UString::createFromUTF8(const char* string) | 
| 219 | { | 
| 220 |     if (!string) | 
| 221 |         return null(); | 
| 222 |  | 
| 223 |     size_t length = strlen(s: string); | 
| 224 |     Vector<UChar, 1024> buffer(length); | 
| 225 |     UChar* p = buffer.data(); | 
| 226 |     if (conversionOK != convertUTF8ToUTF16(sourceStart: &string, sourceEnd: string + length, targetStart: &p, targetEnd: p + length)) | 
| 227 |         return null(); | 
| 228 |  | 
| 229 |     return UString(buffer.data(), p - buffer.data()); | 
| 230 | } | 
| 231 |  | 
| 232 | UString UString::from(int i) | 
| 233 | { | 
| 234 |     UChar buf[1 + sizeof(i) * 3]; | 
| 235 |     UChar* end = buf + sizeof(buf) / sizeof(UChar); | 
| 236 |     UChar* p = end; | 
| 237 |    | 
| 238 |     if (i == 0) | 
| 239 |         *--p = '0'; | 
| 240 |     else if (i == INT_MIN) { | 
| 241 |         char minBuf[1 + sizeof(i) * 3]; | 
| 242 |         sprintf(s: minBuf, format: "%d" , INT_MIN); | 
| 243 |         return UString(minBuf); | 
| 244 |     } else { | 
| 245 |         bool negative = false; | 
| 246 |         if (i < 0) { | 
| 247 |             negative = true; | 
| 248 |             i = -i; | 
| 249 |         } | 
| 250 |         while (i) { | 
| 251 |             *--p = static_cast<unsigned short>((i % 10) + '0'); | 
| 252 |             i /= 10; | 
| 253 |         } | 
| 254 |         if (negative) | 
| 255 |             *--p = '-'; | 
| 256 |     } | 
| 257 |  | 
| 258 |     return UString(p, static_cast<int>(end - p)); | 
| 259 | } | 
| 260 |  | 
| 261 | UString UString::from(long long i) | 
| 262 | { | 
| 263 |     UChar buf[1 + sizeof(i) * 3]; | 
| 264 |     UChar* end = buf + sizeof(buf) / sizeof(UChar); | 
| 265 |     UChar* p = end; | 
| 266 |  | 
| 267 |     if (i == 0) | 
| 268 |         *--p = '0'; | 
| 269 |     else if (i == std::numeric_limits<long long>::min()) { | 
| 270 |         char minBuf[1 + sizeof(i) * 3]; | 
| 271 | #if OS(WINDOWS) | 
| 272 |         snprintf(minBuf, sizeof(minBuf) - 1, "%I64d" , std::numeric_limits<long long>::min()); | 
| 273 | #else | 
| 274 |         snprintf(s: minBuf, maxlen: sizeof(minBuf) - 1, format: "%lld" , std::numeric_limits<long long>::min()); | 
| 275 | #endif | 
| 276 |         return UString(minBuf); | 
| 277 |     } else { | 
| 278 |         bool negative = false; | 
| 279 |         if (i < 0) { | 
| 280 |             negative = true; | 
| 281 |             i = -i; | 
| 282 |         } | 
| 283 |         while (i) { | 
| 284 |             *--p = static_cast<unsigned short>((i % 10) + '0'); | 
| 285 |             i /= 10; | 
| 286 |         } | 
| 287 |         if (negative) | 
| 288 |             *--p = '-'; | 
| 289 |     } | 
| 290 |  | 
| 291 |     return UString(p, static_cast<int>(end - p)); | 
| 292 | } | 
| 293 |  | 
| 294 | UString UString::from(unsigned int u) | 
| 295 | { | 
| 296 |     UChar buf[sizeof(u) * 3]; | 
| 297 |     UChar* end = buf + sizeof(buf) / sizeof(UChar); | 
| 298 |     UChar* p = end; | 
| 299 |      | 
| 300 |     if (u == 0) | 
| 301 |         *--p = '0'; | 
| 302 |     else { | 
| 303 |         while (u) { | 
| 304 |             *--p = static_cast<unsigned short>((u % 10) + '0'); | 
| 305 |             u /= 10; | 
| 306 |         } | 
| 307 |     } | 
| 308 |      | 
| 309 |     return UString(p, static_cast<int>(end - p)); | 
| 310 | } | 
| 311 |  | 
| 312 | UString UString::from(long l) | 
| 313 | { | 
| 314 |     UChar buf[1 + sizeof(l) * 3]; | 
| 315 |     UChar* end = buf + sizeof(buf) / sizeof(UChar); | 
| 316 |     UChar* p = end; | 
| 317 |  | 
| 318 |     if (l == 0) | 
| 319 |         *--p = '0'; | 
| 320 |     else if (l == LONG_MIN) { | 
| 321 |         char minBuf[1 + sizeof(l) * 3]; | 
| 322 |         sprintf(s: minBuf, format: "%ld" , LONG_MIN); | 
| 323 |         return UString(minBuf); | 
| 324 |     } else { | 
| 325 |         bool negative = false; | 
| 326 |         if (l < 0) { | 
| 327 |             negative = true; | 
| 328 |             l = -l; | 
| 329 |         } | 
| 330 |         while (l) { | 
| 331 |             *--p = static_cast<unsigned short>((l % 10) + '0'); | 
| 332 |             l /= 10; | 
| 333 |         } | 
| 334 |         if (negative) | 
| 335 |             *--p = '-'; | 
| 336 |     } | 
| 337 |  | 
| 338 |     return UString(p, static_cast<int>(end - p)); | 
| 339 | } | 
| 340 |  | 
| 341 | UString UString::from(double d) | 
| 342 | { | 
| 343 |     DtoaBuffer buffer; | 
| 344 |     unsigned length; | 
| 345 |     doubleToStringInJavaScriptFormat(d, buffer, resultLength: &length); | 
| 346 |     return UString(buffer, length); | 
| 347 | } | 
| 348 |  | 
| 349 | UString UString::spliceSubstringsWithSeparators(const Range* substringRanges, int rangeCount, const UString* separators, int separatorCount) const | 
| 350 | { | 
| 351 |     m_rep->checkConsistency(); | 
| 352 |  | 
| 353 |     if (rangeCount == 1 && separatorCount == 0) { | 
| 354 |         int thisSize = size(); | 
| 355 |         int position = substringRanges[0].position; | 
| 356 |         int length = substringRanges[0].length; | 
| 357 |         if (position <= 0 && length >= thisSize) | 
| 358 |             return *this; | 
| 359 |         return UString::Rep::create(rep: m_rep, offset: max(a: 0, b: position), length: min(a: thisSize, b: length)); | 
| 360 |     } | 
| 361 |  | 
| 362 |     int totalLength = 0; | 
| 363 |     for (int i = 0; i < rangeCount; i++) | 
| 364 |         totalLength += substringRanges[i].length; | 
| 365 |     for (int i = 0; i < separatorCount; i++) | 
| 366 |         totalLength += separators[i].size(); | 
| 367 |  | 
| 368 |     if (totalLength == 0) | 
| 369 |         return "" ; | 
| 370 |  | 
| 371 |     UChar* buffer; | 
| 372 |     PassRefPtr<Rep> rep = Rep::tryCreateUninitialized(length: totalLength, output&: buffer); | 
| 373 |     if (!rep) | 
| 374 |         return null(); | 
| 375 |  | 
| 376 |     int maxCount = max(a: rangeCount, b: separatorCount); | 
| 377 |     int bufferPos = 0; | 
| 378 |     for (int i = 0; i < maxCount; i++) { | 
| 379 |         if (i < rangeCount) { | 
| 380 |             UStringImpl::copyChars(destination: buffer + bufferPos, source: data() + substringRanges[i].position, numCharacters: substringRanges[i].length); | 
| 381 |             bufferPos += substringRanges[i].length; | 
| 382 |         } | 
| 383 |         if (i < separatorCount) { | 
| 384 |             UStringImpl::copyChars(destination: buffer + bufferPos, source: separators[i].data(), numCharacters: separators[i].size()); | 
| 385 |             bufferPos += separators[i].size(); | 
| 386 |         } | 
| 387 |     } | 
| 388 |  | 
| 389 |     return rep; | 
| 390 | } | 
| 391 |  | 
| 392 | UString UString::replaceRange(int rangeStart, int rangeLength, const UString& replacement) const | 
| 393 | { | 
| 394 |     m_rep->checkConsistency(); | 
| 395 |  | 
| 396 |     int replacementLength = replacement.size(); | 
| 397 |     int totalLength = size() - rangeLength + replacementLength; | 
| 398 |     if (totalLength == 0) | 
| 399 |         return "" ; | 
| 400 |  | 
| 401 |     UChar* buffer; | 
| 402 |     PassRefPtr<Rep> rep = Rep::tryCreateUninitialized(length: totalLength, output&: buffer); | 
| 403 |     if (!rep) | 
| 404 |         return null(); | 
| 405 |  | 
| 406 |     UStringImpl::copyChars(destination: buffer, source: data(), numCharacters: rangeStart); | 
| 407 |     UStringImpl::copyChars(destination: buffer + rangeStart, source: replacement.data(), numCharacters: replacementLength); | 
| 408 |     int rangeEnd = rangeStart + rangeLength; | 
| 409 |     UStringImpl::copyChars(destination: buffer + rangeStart + replacementLength, source: data() + rangeEnd, numCharacters: size() - rangeEnd); | 
| 410 |  | 
| 411 |     return rep; | 
| 412 | } | 
| 413 |  | 
| 414 | bool UString::getCString(CStringBuffer& buffer) const | 
| 415 | { | 
| 416 |     int length = size(); | 
| 417 |     int neededSize = length + 1; | 
| 418 |     buffer.resize(size: neededSize); | 
| 419 |     char* buf = buffer.data(); | 
| 420 |  | 
| 421 |     UChar ored = 0; | 
| 422 |     const UChar* p = data(); | 
| 423 |     char* q = buf; | 
| 424 |     const UChar* limit = p + length; | 
| 425 |     while (p != limit) { | 
| 426 |         UChar c = p[0]; | 
| 427 |         ored |= c; | 
| 428 |         *q = static_cast<char>(c); | 
| 429 |         ++p; | 
| 430 |         ++q; | 
| 431 |     } | 
| 432 |     *q = '\0'; | 
| 433 |  | 
| 434 |     return !(ored & 0xFF00); | 
| 435 | } | 
| 436 |  | 
| 437 | char* UString::ascii() const | 
| 438 | { | 
| 439 |     static char* asciiBuffer = 0; | 
| 440 |  | 
| 441 |     int length = size(); | 
| 442 |     int neededSize = length + 1; | 
| 443 |     delete[] asciiBuffer; | 
| 444 |     asciiBuffer = new char[neededSize]; | 
| 445 |  | 
| 446 |     const UChar* p = data(); | 
| 447 |     char* q = asciiBuffer; | 
| 448 |     const UChar* limit = p + length; | 
| 449 |     while (p != limit) { | 
| 450 |         *q = static_cast<char>(p[0]); | 
| 451 |         ++p; | 
| 452 |         ++q; | 
| 453 |     } | 
| 454 |     *q = '\0'; | 
| 455 |  | 
| 456 |     return asciiBuffer; | 
| 457 | } | 
| 458 |  | 
| 459 | UString& UString::operator=(const char* c) | 
| 460 | { | 
| 461 |     if (!c) { | 
| 462 |         m_rep = &Rep::null(); | 
| 463 |         return *this; | 
| 464 |     } | 
| 465 |  | 
| 466 |     if (!c[0]) { | 
| 467 |         m_rep = &Rep::empty(); | 
| 468 |         return *this; | 
| 469 |     } | 
| 470 |  | 
| 471 |     int l = static_cast<int>(strlen(s: c)); | 
| 472 |     UChar* d = 0; | 
| 473 |     m_rep = Rep::tryCreateUninitialized(length: l, output&: d); | 
| 474 |     if (m_rep) { | 
| 475 |         for (int i = 0; i < l; i++) | 
| 476 |             d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend | 
| 477 |     } else | 
| 478 |         makeNull(); | 
| 479 |  | 
| 480 |     return *this; | 
| 481 | } | 
| 482 |  | 
| 483 | bool UString::is8Bit() const | 
| 484 | { | 
| 485 |     const UChar* u = data(); | 
| 486 |     const UChar* limit = u + size(); | 
| 487 |     while (u < limit) { | 
| 488 |         if (u[0] > 0xFF) | 
| 489 |             return false; | 
| 490 |         ++u; | 
| 491 |     } | 
| 492 |  | 
| 493 |     return true; | 
| 494 | } | 
| 495 |  | 
| 496 | UChar UString::operator[](int pos) const | 
| 497 | { | 
| 498 |     if (pos >= size()) | 
| 499 |         return '\0'; | 
| 500 |     return data()[pos]; | 
| 501 | } | 
| 502 |  | 
| 503 | double UString::toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const | 
| 504 | { | 
| 505 |     if (size() == 1) { | 
| 506 |         UChar c = data()[0]; | 
| 507 |         if (isASCIIDigit(c)) | 
| 508 |             return c - '0'; | 
| 509 |         if (isASCIISpace(c) && tolerateEmptyString) | 
| 510 |             return 0; | 
| 511 |         return NaN; | 
| 512 |     } | 
| 513 |  | 
| 514 |     // FIXME: If tolerateTrailingJunk is true, then we want to tolerate non-8-bit junk | 
| 515 |     // after the number, so this is too strict a check. | 
| 516 |     CStringBuffer s; | 
| 517 |     if (!getCString(buffer&: s)) | 
| 518 |         return NaN; | 
| 519 |     const char* c = s.data(); | 
| 520 |  | 
| 521 |     // skip leading white space | 
| 522 |     while (isASCIISpace(c: *c)) | 
| 523 |         c++; | 
| 524 |  | 
| 525 |     // empty string ? | 
| 526 |     if (*c == '\0') | 
| 527 |         return tolerateEmptyString ? 0.0 : NaN; | 
| 528 |  | 
| 529 |     double d; | 
| 530 |  | 
| 531 |     // hex number ? | 
| 532 |     if (*c == '0' && (*(c + 1) == 'x' || *(c + 1) == 'X')) { | 
| 533 |         const char* firstDigitPosition = c + 2; | 
| 534 |         c++; | 
| 535 |         d = 0.0; | 
| 536 |         while (*(++c)) { | 
| 537 |             if (*c >= '0' && *c <= '9') | 
| 538 |                 d = d * 16.0 + *c - '0'; | 
| 539 |             else if ((*c >= 'A' && *c <= 'F') || (*c >= 'a' && *c <= 'f')) | 
| 540 |                 d = d * 16.0 + (*c & 0xdf) - 'A' + 10.0; | 
| 541 |             else | 
| 542 |                 break; | 
| 543 |         } | 
| 544 |  | 
| 545 |         if (d >= mantissaOverflowLowerBound) | 
| 546 |             d = parseIntOverflow(firstDigitPosition, length: c - firstDigitPosition, radix: 16); | 
| 547 |     } else { | 
| 548 |         // regular number ? | 
| 549 |         char* end; | 
| 550 |         d = WTF::strtod(s00: c, se: &end); | 
| 551 |         if ((d != 0.0 || end != c) && d != Inf && d != -Inf) { | 
| 552 |             c = end; | 
| 553 |         } else { | 
| 554 |             double sign = 1.0; | 
| 555 |  | 
| 556 |             if (*c == '+') | 
| 557 |                 c++; | 
| 558 |             else if (*c == '-') { | 
| 559 |                 sign = -1.0; | 
| 560 |                 c++; | 
| 561 |             } | 
| 562 |  | 
| 563 |             // We used strtod() to do the conversion. However, strtod() handles | 
| 564 |             // infinite values slightly differently than JavaScript in that it | 
| 565 |             // converts the string "inf" with any capitalization to infinity, | 
| 566 |             // whereas the ECMA spec requires that it be converted to NaN. | 
| 567 |  | 
| 568 |             if (c[0] == 'I' && c[1] == 'n' && c[2] == 'f' && c[3] == 'i' && c[4] == 'n' && c[5] == 'i' && c[6] == 't' && c[7] == 'y') { | 
| 569 |                 d = sign * Inf; | 
| 570 |                 c += 8; | 
| 571 |             } else if ((d == Inf || d == -Inf) && *c != 'I' && *c != 'i') | 
| 572 |                 c = end; | 
| 573 |             else | 
| 574 |                 return NaN; | 
| 575 |         } | 
| 576 |     } | 
| 577 |  | 
| 578 |     // allow trailing white space | 
| 579 |     while (isASCIISpace(c: *c)) | 
| 580 |         c++; | 
| 581 |     // don't allow anything after - unless tolerant=true | 
| 582 |     if (!tolerateTrailingJunk && *c != '\0') | 
| 583 |         d = NaN; | 
| 584 |  | 
| 585 |     return d; | 
| 586 | } | 
| 587 |  | 
| 588 | double UString::toDouble(bool tolerateTrailingJunk) const | 
| 589 | { | 
| 590 |     return toDouble(tolerateTrailingJunk, tolerateEmptyString: true); | 
| 591 | } | 
| 592 |  | 
| 593 | double UString::toDouble() const | 
| 594 | { | 
| 595 |     return toDouble(tolerateTrailingJunk: false, tolerateEmptyString: true); | 
| 596 | } | 
| 597 |  | 
| 598 | uint32_t UString::toUInt32(bool* ok) const | 
| 599 | { | 
| 600 |     double d = toDouble(); | 
| 601 |     bool b = true; | 
| 602 |  | 
| 603 |     if (d != static_cast<uint32_t>(d)) { | 
| 604 |         b = false; | 
| 605 |         d = 0; | 
| 606 |     } | 
| 607 |  | 
| 608 |     if (ok) | 
| 609 |         *ok = b; | 
| 610 |  | 
| 611 |     return static_cast<uint32_t>(d); | 
| 612 | } | 
| 613 |  | 
| 614 | uint32_t UString::toUInt32(bool* ok, bool tolerateEmptyString) const | 
| 615 | { | 
| 616 |     double d = toDouble(tolerateTrailingJunk: false, tolerateEmptyString); | 
| 617 |     bool b = true; | 
| 618 |  | 
| 619 |     if (d != static_cast<uint32_t>(d)) { | 
| 620 |         b = false; | 
| 621 |         d = 0; | 
| 622 |     } | 
| 623 |  | 
| 624 |     if (ok) | 
| 625 |         *ok = b; | 
| 626 |  | 
| 627 |     return static_cast<uint32_t>(d); | 
| 628 | } | 
| 629 |  | 
| 630 | uint32_t UString::toStrictUInt32(bool* ok) const | 
| 631 | { | 
| 632 |     if (ok) | 
| 633 |         *ok = false; | 
| 634 |  | 
| 635 |     // Empty string is not OK. | 
| 636 |     int len = m_rep->size(); | 
| 637 |     if (len == 0) | 
| 638 |         return 0; | 
| 639 |     const UChar* p = m_rep->data(); | 
| 640 |     unsigned short c = p[0]; | 
| 641 |  | 
| 642 |     // If the first digit is 0, only 0 itself is OK. | 
| 643 |     if (c == '0') { | 
| 644 |         if (len == 1 && ok) | 
| 645 |             *ok = true; | 
| 646 |         return 0; | 
| 647 |     } | 
| 648 |  | 
| 649 |     // Convert to UInt32, checking for overflow. | 
| 650 |     uint32_t i = 0; | 
| 651 |     while (1) { | 
| 652 |         // Process character, turning it into a digit. | 
| 653 |         if (c < '0' || c > '9') | 
| 654 |             return 0; | 
| 655 |         const unsigned d = c - '0'; | 
| 656 |  | 
| 657 |         // Multiply by 10, checking for overflow out of 32 bits. | 
| 658 |         if (i > 0xFFFFFFFFU / 10) | 
| 659 |             return 0; | 
| 660 |         i *= 10; | 
| 661 |  | 
| 662 |         // Add in the digit, checking for overflow out of 32 bits. | 
| 663 |         const unsigned max = 0xFFFFFFFFU - d; | 
| 664 |         if (i > max) | 
| 665 |             return 0; | 
| 666 |         i += d; | 
| 667 |  | 
| 668 |         // Handle end of string. | 
| 669 |         if (--len == 0) { | 
| 670 |             if (ok) | 
| 671 |                 *ok = true; | 
| 672 |             return i; | 
| 673 |         } | 
| 674 |  | 
| 675 |         // Get next character. | 
| 676 |         c = *(++p); | 
| 677 |     } | 
| 678 | } | 
| 679 |  | 
| 680 | int UString::find(const UString& f, int pos) const | 
| 681 | { | 
| 682 |     int fsz = f.size(); | 
| 683 |  | 
| 684 |     if (pos < 0) | 
| 685 |         pos = 0; | 
| 686 |  | 
| 687 |     if (fsz == 1) { | 
| 688 |         UChar ch = f[0]; | 
| 689 |         const UChar* end = data() + size(); | 
| 690 |         for (const UChar* c = data() + pos; c < end; c++) { | 
| 691 |             if (*c == ch) | 
| 692 |                 return static_cast<int>(c - data()); | 
| 693 |         } | 
| 694 |         return -1; | 
| 695 |     } | 
| 696 |  | 
| 697 |     int sz = size(); | 
| 698 |     if (sz < fsz) | 
| 699 |         return -1; | 
| 700 |     if (fsz == 0) | 
| 701 |         return pos; | 
| 702 |     const UChar* end = data() + sz - fsz; | 
| 703 |     int fsizeminusone = (fsz - 1) * sizeof(UChar); | 
| 704 |     const UChar* fdata = f.data(); | 
| 705 |     unsigned short fchar = fdata[0]; | 
| 706 |     ++fdata; | 
| 707 |     for (const UChar* c = data() + pos; c <= end; c++) { | 
| 708 |         if (c[0] == fchar && !memcmp(s1: c + 1, s2: fdata, n: fsizeminusone)) | 
| 709 |             return static_cast<int>(c - data()); | 
| 710 |     } | 
| 711 |  | 
| 712 |     return -1; | 
| 713 | } | 
| 714 |  | 
| 715 | int UString::find(UChar ch, int pos) const | 
| 716 | { | 
| 717 |     if (pos < 0) | 
| 718 |         pos = 0; | 
| 719 |     const UChar* end = data() + size(); | 
| 720 |     for (const UChar* c = data() + pos; c < end; c++) { | 
| 721 |         if (*c == ch) | 
| 722 |             return static_cast<int>(c - data()); | 
| 723 |     } | 
| 724 |      | 
| 725 |     return -1; | 
| 726 | } | 
| 727 |  | 
| 728 | int UString::rfind(const UString& f, int pos) const | 
| 729 | { | 
| 730 |     int sz = size(); | 
| 731 |     int fsz = f.size(); | 
| 732 |     if (sz < fsz) | 
| 733 |         return -1; | 
| 734 |     if (pos < 0) | 
| 735 |         pos = 0; | 
| 736 |     if (pos > sz - fsz) | 
| 737 |         pos = sz - fsz; | 
| 738 |     if (fsz == 0) | 
| 739 |         return pos; | 
| 740 |     int fsizeminusone = (fsz - 1) * sizeof(UChar); | 
| 741 |     const UChar* fdata = f.data(); | 
| 742 |     for (const UChar* c = data() + pos; c >= data(); c--) { | 
| 743 |         if (*c == *fdata && !memcmp(s1: c + 1, s2: fdata + 1, n: fsizeminusone)) | 
| 744 |             return static_cast<int>(c - data()); | 
| 745 |     } | 
| 746 |  | 
| 747 |     return -1; | 
| 748 | } | 
| 749 |  | 
| 750 | int UString::rfind(UChar ch, int pos) const | 
| 751 | { | 
| 752 |     if (isEmpty()) | 
| 753 |         return -1; | 
| 754 |     if (pos + 1 >= size()) | 
| 755 |         pos = size() - 1; | 
| 756 |     for (const UChar* c = data() + pos; c >= data(); c--) { | 
| 757 |         if (*c == ch) | 
| 758 |             return static_cast<int>(c - data()); | 
| 759 |     } | 
| 760 |  | 
| 761 |     return -1; | 
| 762 | } | 
| 763 |  | 
| 764 | UString UString::substr(int pos, int len) const | 
| 765 | { | 
| 766 |     int s = size(); | 
| 767 |  | 
| 768 |     if (pos < 0) | 
| 769 |         pos = 0; | 
| 770 |     else if (pos >= s) | 
| 771 |         pos = s; | 
| 772 |     if (len < 0) | 
| 773 |         len = s; | 
| 774 |     if (pos + len >= s) | 
| 775 |         len = s - pos; | 
| 776 |  | 
| 777 |     if (pos == 0 && len == s) | 
| 778 |         return *this; | 
| 779 |  | 
| 780 |     return UString(Rep::create(rep: m_rep, offset: pos, length: len)); | 
| 781 | } | 
| 782 |  | 
| 783 | bool operator==(const UString& s1, const char *s2) | 
| 784 | { | 
| 785 |     if (s2 == 0) | 
| 786 |         return s1.isEmpty(); | 
| 787 |  | 
| 788 |     const UChar* u = s1.data(); | 
| 789 |     const UChar* uend = u + s1.size(); | 
| 790 |     while (u != uend && *s2) { | 
| 791 |         if (u[0] != (unsigned char)*s2) | 
| 792 |             return false; | 
| 793 |         s2++; | 
| 794 |         u++; | 
| 795 |     } | 
| 796 |  | 
| 797 |     return u == uend && *s2 == 0; | 
| 798 | } | 
| 799 |  | 
| 800 | bool operator<(const UString& s1, const UString& s2) | 
| 801 | { | 
| 802 |     const int l1 = s1.size(); | 
| 803 |     const int l2 = s2.size(); | 
| 804 |     const int lmin = l1 < l2 ? l1 : l2; | 
| 805 |     const UChar* c1 = s1.data(); | 
| 806 |     const UChar* c2 = s2.data(); | 
| 807 |     int l = 0; | 
| 808 |     while (l < lmin && *c1 == *c2) { | 
| 809 |         c1++; | 
| 810 |         c2++; | 
| 811 |         l++; | 
| 812 |     } | 
| 813 |     if (l < lmin) | 
| 814 |         return (c1[0] < c2[0]); | 
| 815 |  | 
| 816 |     return (l1 < l2); | 
| 817 | } | 
| 818 |  | 
| 819 | bool operator>(const UString& s1, const UString& s2) | 
| 820 | { | 
| 821 |     const int l1 = s1.size(); | 
| 822 |     const int l2 = s2.size(); | 
| 823 |     const int lmin = l1 < l2 ? l1 : l2; | 
| 824 |     const UChar* c1 = s1.data(); | 
| 825 |     const UChar* c2 = s2.data(); | 
| 826 |     int l = 0; | 
| 827 |     while (l < lmin && *c1 == *c2) { | 
| 828 |         c1++; | 
| 829 |         c2++; | 
| 830 |         l++; | 
| 831 |     } | 
| 832 |     if (l < lmin) | 
| 833 |         return (c1[0] > c2[0]); | 
| 834 |  | 
| 835 |     return (l1 > l2); | 
| 836 | } | 
| 837 |  | 
| 838 | int compare(const UString& s1, const UString& s2) | 
| 839 | { | 
| 840 |     const int l1 = s1.size(); | 
| 841 |     const int l2 = s2.size(); | 
| 842 |     const int lmin = l1 < l2 ? l1 : l2; | 
| 843 |     const UChar* c1 = s1.data(); | 
| 844 |     const UChar* c2 = s2.data(); | 
| 845 |     int l = 0; | 
| 846 |     while (l < lmin && *c1 == *c2) { | 
| 847 |         c1++; | 
| 848 |         c2++; | 
| 849 |         l++; | 
| 850 |     } | 
| 851 |  | 
| 852 |     if (l < lmin) | 
| 853 |         return (c1[0] > c2[0]) ? 1 : -1; | 
| 854 |  | 
| 855 |     if (l1 == l2) | 
| 856 |         return 0; | 
| 857 |  | 
| 858 |     return (l1 > l2) ? 1 : -1; | 
| 859 | } | 
| 860 |  | 
| 861 | #if OS(SOLARIS) && COMPILER(SUNCC) | 
| 862 | // Signature must match that of UStringImpl.h, otherwise the linker complains about undefined symbol. | 
| 863 | bool equal(const UStringImpl* r, const UStringImpl* b) | 
| 864 | #else | 
| 865 | bool equal(const UString::Rep* r, const UString::Rep* b) | 
| 866 | #endif | 
| 867 | { | 
| 868 |     int length = r->size(); | 
| 869 |     if (length != b->size()) | 
| 870 |         return false; | 
| 871 |     const UChar* d = r->data(); | 
| 872 |     const UChar* s = b->data(); | 
| 873 |     for (int i = 0; i != length; ++i) { | 
| 874 |         if (d[i] != s[i]) | 
| 875 |             return false; | 
| 876 |     } | 
| 877 |     return true; | 
| 878 | } | 
| 879 |  | 
| 880 | CString UString::UTF8String(bool strict) const | 
| 881 | { | 
| 882 |     // Allocate a buffer big enough to hold all the characters. | 
| 883 |     const int length = size(); | 
| 884 |     Vector<char, 1024> buffer(length * 3); | 
| 885 |  | 
| 886 |     // Convert to runs of 8-bit characters. | 
| 887 |     char* p = buffer.data(); | 
| 888 |     const UChar* d = reinterpret_cast<const UChar*>(&data()[0]); | 
| 889 |     ConversionResult result = convertUTF16ToUTF8(sourceStart: &d, sourceEnd: d + length, targetStart: &p, targetEnd: p + buffer.size(), strict); | 
| 890 |     if (result != conversionOK) | 
| 891 |         return CString(); | 
| 892 |  | 
| 893 |     return CString(buffer.data(), p - buffer.data()); | 
| 894 | } | 
| 895 |  | 
| 896 | // For use in error handling code paths -- having this not be inlined helps avoid PIC branches to fetch the global on Mac OS X. | 
| 897 | NEVER_INLINE void UString::makeNull() | 
| 898 | { | 
| 899 |     m_rep = &Rep::null(); | 
| 900 | } | 
| 901 |  | 
| 902 | // For use in error handling code paths -- having this not be inlined helps avoid PIC branches to fetch the global on Mac OS X. | 
| 903 | NEVER_INLINE UString::Rep* UString::nullRep() | 
| 904 | { | 
| 905 |     return &Rep::null(); | 
| 906 | } | 
| 907 |  | 
| 908 | } // namespace JSC | 
| 909 |  |