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 | |