blob: 699ef79d8a90e3126e98cc7f7976e80bf974c858 [file] [log] [blame]
mjs6f821c82002-03-22 00:31:57 +00001// -*- c-basic-offset: 2 -*-
kocienda66a6d362001-08-24 14:24:45 +00002/*
kocienda66a6d362001-08-24 14:24:45 +00003 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
darin@apple.com3beb3002008-04-28 05:59:07 +00004 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
darin5769f312007-07-18 02:25:38 +00005 * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
kocienda66a6d362001-08-24 14:24:45 +00006 *
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
mjscdff33b2006-01-23 21:41:36 +000019 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
ggaren07d4ce62005-07-14 18:27:04 +000020 * Boston, MA 02110-1301, USA.
mjs6f821c82002-03-22 00:31:57 +000021 *
kocienda66a6d362001-08-24 14:24:45 +000022 */
23
darin6e70e6a2006-01-12 15:25:58 +000024#include "config.h"
25#include "ustring.h"
kocienda66a6d362001-08-24 14:24:45 +000026
ggarenff599582007-03-07 04:25:49 +000027#include "JSLock.h"
mjs06ed4662007-07-25 21:50:00 +000028#include "collector.h"
ggarenff599582007-03-07 04:25:49 +000029#include "dtoa.h"
darin@apple.com3dcb6362008-06-16 04:00:19 +000030#include "JSFunction.h"
ggarenff599582007-03-07 04:25:49 +000031#include "identifier.h"
32#include "operations.h"
kocienda66a6d362001-08-24 14:24:45 +000033#include <ctype.h>
ggarenff599582007-03-07 04:25:49 +000034#include <float.h>
hausmann04373112007-10-10 11:12:20 +000035#include <limits.h>
ggarenff599582007-03-07 04:25:49 +000036#include <math.h>
37#include <stdio.h>
38#include <stdlib.h>
ggaren7213ee02007-10-16 23:25:33 +000039#include <wtf/Assertions.h>
darin185ca852007-10-16 20:53:21 +000040#include <wtf/ASCIICType.h>
mrowe@apple.com915de552007-10-29 02:52:04 +000041#include <wtf/MathExtras.h>
ggarenff599582007-03-07 04:25:49 +000042#include <wtf/Vector.h>
alp@webkit.orgf4917c62007-11-13 09:49:50 +000043#include <wtf/unicode/UTF8.h>
ggarenff599582007-03-07 04:25:49 +000044
mjs3bfb61b2006-03-02 09:12:06 +000045#if HAVE(STRING_H)
kocienda66a6d362001-08-24 14:24:45 +000046#include <string.h>
47#endif
mjs3bfb61b2006-03-02 09:12:06 +000048#if HAVE(STRINGS_H)
kocienda66a6d362001-08-24 14:24:45 +000049#include <strings.h>
50#endif
51
darineb0d86d2007-10-16 20:13:24 +000052using namespace WTF;
alp@webkit.orgf4917c62007-11-13 09:49:50 +000053using namespace WTF::Unicode;
darineb0d86d2007-10-16 20:13:24 +000054using namespace std;
darine3385e92004-08-10 18:43:51 +000055
kocienda66a6d362001-08-24 14:24:45 +000056namespace KJS {
kocienda66a6d362001-08-24 14:24:45 +000057
darin6c9bbfd2003-08-18 18:51:25 +000058extern const double NaN;
59extern const double Inf;
kocienda66a6d362001-08-24 14:24:45 +000060
darin6238e2a2007-08-14 22:19:04 +000061static inline const size_t overflowIndicator() { return std::numeric_limits<size_t>::max(); }
62static inline const size_t maxUChars() { return std::numeric_limits<size_t>::max() / sizeof(UChar); }
darin0d66de72007-08-08 00:45:39 +000063
bdash41705de2007-08-02 09:33:22 +000064static inline UChar* allocChars(size_t length)
65{
darin0d66de72007-08-08 00:45:39 +000066 ASSERT(length);
darin6238e2a2007-08-14 22:19:04 +000067 if (length > maxUChars())
bdash41705de2007-08-02 09:33:22 +000068 return 0;
69 return static_cast<UChar*>(fastMalloc(sizeof(UChar) * length));
70}
71
darin0d66de72007-08-08 00:45:39 +000072static inline UChar* reallocChars(UChar* buffer, size_t length)
bdash41705de2007-08-02 09:33:22 +000073{
darin0d66de72007-08-08 00:45:39 +000074 ASSERT(length);
darin6238e2a2007-08-14 22:19:04 +000075 if (length > maxUChars())
bdash41705de2007-08-02 09:33:22 +000076 return 0;
77 return static_cast<UChar*>(fastRealloc(buffer, sizeof(UChar) * length));
78}
79
kjk67f5d5a2007-02-17 09:07:39 +000080COMPILE_ASSERT(sizeof(UChar) == 2, uchar_is_2_bytes)
81
kocienda66a6d362001-08-24 14:24:45 +000082CString::CString(const char *c)
83{
darin6c9bbfd2003-08-18 18:51:25 +000084 length = strlen(c);
85 data = new char[length+1];
darin43d061b2003-10-27 04:21:15 +000086 memcpy(data, c, length + 1);
kocienda66a6d362001-08-24 14:24:45 +000087}
88
ggarendf6e53c2006-06-05 16:37:59 +000089CString::CString(const char *c, size_t len)
darin6c9bbfd2003-08-18 18:51:25 +000090{
91 length = len;
92 data = new char[len+1];
93 memcpy(data, c, len);
94 data[len] = 0;
95}
96
kocienda66a6d362001-08-24 14:24:45 +000097CString::CString(const CString &b)
98{
darin6c9bbfd2003-08-18 18:51:25 +000099 length = b.length;
eseidelb3ff6072006-03-15 22:26:37 +0000100 if (b.data) {
rjwc8b0fe82004-01-23 00:42:34 +0000101 data = new char[length+1];
102 memcpy(data, b.data, length + 1);
103 }
eseidelb3ff6072006-03-15 22:26:37 +0000104 else
rjwc8b0fe82004-01-23 00:42:34 +0000105 data = 0;
kocienda66a6d362001-08-24 14:24:45 +0000106}
107
108CString::~CString()
109{
110 delete [] data;
111}
112
ap@webkit.org11f38712008-04-07 06:33:20 +0000113CString CString::adopt(char* c, size_t len)
114{
115 CString s;
116 s.data = c;
117 s.length = len;
118
119 return s;
120}
121
kocienda66a6d362001-08-24 14:24:45 +0000122CString &CString::append(const CString &t)
123{
124 char *n;
darin6c9bbfd2003-08-18 18:51:25 +0000125 n = new char[length+t.length+1];
126 if (length)
127 memcpy(n, data, length);
128 if (t.length)
129 memcpy(n+length, t.data, t.length);
130 length += t.length;
131 n[length] = 0;
kocienda66a6d362001-08-24 14:24:45 +0000132
133 delete [] data;
134 data = n;
135
136 return *this;
137}
138
139CString &CString::operator=(const char *c)
140{
141 if (data)
142 delete [] data;
darin6c9bbfd2003-08-18 18:51:25 +0000143 length = strlen(c);
144 data = new char[length+1];
darin43d061b2003-10-27 04:21:15 +0000145 memcpy(data, c, length + 1);
kocienda66a6d362001-08-24 14:24:45 +0000146
147 return *this;
148}
149
150CString &CString::operator=(const CString &str)
151{
152 if (this == &str)
153 return *this;
154
155 if (data)
156 delete [] data;
darin6c9bbfd2003-08-18 18:51:25 +0000157 length = str.length;
eseidelb3ff6072006-03-15 22:26:37 +0000158 if (str.data) {
rjwc8b0fe82004-01-23 00:42:34 +0000159 data = new char[length + 1];
160 memcpy(data, str.data, length + 1);
161 }
eseidelb3ff6072006-03-15 22:26:37 +0000162 else
rjwc8b0fe82004-01-23 00:42:34 +0000163 data = 0;
kocienda66a6d362001-08-24 14:24:45 +0000164
165 return *this;
166}
167
darin04b93fa2005-05-16 18:57:29 +0000168bool operator==(const CString& c1, const CString& c2)
kocienda66a6d362001-08-24 14:24:45 +0000169{
ggarendf6e53c2006-06-05 16:37:59 +0000170 size_t len = c1.size();
darin6c9bbfd2003-08-18 18:51:25 +0000171 return len == c2.size() && (len == 0 || memcmp(c1.c_str(), c2.c_str(), len) == 0);
kocienda66a6d362001-08-24 14:24:45 +0000172}
173
ap@webkit.org11f38712008-04-07 06:33:20 +0000174// These static strings are immutable, except for rc, whose initial value is chosen to reduce the possibility of it becoming zero due to ref/deref not being thread-safe.
eric@webkit.org87d855b2008-03-10 22:06:44 +0000175static UChar sharedEmptyChar;
ap@webkit.org0ea9a692008-04-18 19:46:13 +0000176UString::Rep UString::Rep::null = { 0, 0, INT_MAX / 2, 0, 0, &UString::Rep::null, true, 0, 0, 0, 0, 0, 0 };
177UString::Rep UString::Rep::empty = { 0, 0, INT_MAX / 2, 0, 0, &UString::Rep::empty, true, 0, &sharedEmptyChar, 0, 0, 0, 0 };
ap@webkit.org11f38712008-04-07 06:33:20 +0000178
179static char* statBuffer = 0; // Only used for debugging via UString::ascii().
kocienda66a6d362001-08-24 14:24:45 +0000180
mjs97e2b182005-12-06 09:21:15 +0000181PassRefPtr<UString::Rep> UString::Rep::createCopying(const UChar *d, int l)
mjs80a4d8e2005-04-15 01:26:26 +0000182{
183 int sizeInBytes = l * sizeof(UChar);
mjscff5e5e2005-09-27 22:37:33 +0000184 UChar *copyD = static_cast<UChar *>(fastMalloc(sizeInBytes));
mjs80a4d8e2005-04-15 01:26:26 +0000185 memcpy(copyD, d, sizeInBytes);
186
187 return create(copyD, l);
188}
189
mjs97e2b182005-12-06 09:21:15 +0000190PassRefPtr<UString::Rep> UString::Rep::create(UChar *d, int l)
kocienda66a6d362001-08-24 14:24:45 +0000191{
mjs06ed4662007-07-25 21:50:00 +0000192 Rep* r = new Rep;
mjs7a882e82004-04-16 18:54:21 +0000193 r->offset = 0;
kocienda66a6d362001-08-24 14:24:45 +0000194 r->len = l;
mjs0ee0df72005-12-08 18:19:28 +0000195 r->rc = 1;
darin5721aa92002-11-20 01:23:02 +0000196 r->_hash = 0;
ap@webkit.org0ea9a692008-04-18 19:46:13 +0000197 r->identifierTable = 0;
mjs06ed4662007-07-25 21:50:00 +0000198 r->baseString = r;
ap@webkit.org0ea9a692008-04-18 19:46:13 +0000199 r->isStatic = false;
kmccullough@apple.com9f7c99e2008-01-18 21:05:16 +0000200 r->reportedCost = 0;
mjsf9c37952004-04-14 02:33:59 +0000201 r->buf = d;
202 r->usedCapacity = l;
203 r->capacity = l;
mjs37521172004-04-19 21:26:40 +0000204 r->usedPreCapacity = 0;
205 r->preCapacity = 0;
mjs03a10872005-12-20 20:12:50 +0000206
mjs0ee0df72005-12-08 18:19:28 +0000207 // steal the single reference this Rep was created with
mjs1aec3582005-12-25 09:22:35 +0000208 return adoptRef(r);
mjsf9c37952004-04-14 02:33:59 +0000209}
210
mjs97e2b182005-12-06 09:21:15 +0000211PassRefPtr<UString::Rep> UString::Rep::create(PassRefPtr<Rep> base, int offset, int length)
mjsf9c37952004-04-14 02:33:59 +0000212{
ggarenff599582007-03-07 04:25:49 +0000213 ASSERT(base);
mjs7a882e82004-04-16 18:54:21 +0000214
215 int baseOffset = base->offset;
216
mjs06ed4662007-07-25 21:50:00 +0000217 base = base->baseString;
mjsf9c37952004-04-14 02:33:59 +0000218
ggaren7213ee02007-10-16 23:25:33 +0000219 ASSERT(-(offset + baseOffset) <= base->usedPreCapacity);
220 ASSERT(offset + baseOffset + length <= base->usedCapacity);
mjsf9c37952004-04-14 02:33:59 +0000221
222 Rep *r = new Rep;
mjs7a882e82004-04-16 18:54:21 +0000223 r->offset = baseOffset + offset;
224 r->len = length;
mjsf9c37952004-04-14 02:33:59 +0000225 r->rc = 1;
226 r->_hash = 0;
ap@webkit.org0ea9a692008-04-18 19:46:13 +0000227 r->identifierTable = 0;
darine4d34c62006-10-29 06:48:02 +0000228 r->baseString = base.releaseRef();
ap@webkit.org0ea9a692008-04-18 19:46:13 +0000229 r->isStatic = false;
kmccullough@apple.com9f7c99e2008-01-18 21:05:16 +0000230 r->reportedCost = 0;
mjsf9c37952004-04-14 02:33:59 +0000231 r->buf = 0;
232 r->usedCapacity = 0;
233 r->capacity = 0;
mjs37521172004-04-19 21:26:40 +0000234 r->usedPreCapacity = 0;
235 r->preCapacity = 0;
mjs03a10872005-12-20 20:12:50 +0000236
mjs0ee0df72005-12-08 18:19:28 +0000237 // steal the single reference this Rep was created with
mjs1aec3582005-12-25 09:22:35 +0000238 return adoptRef(r);
kocienda66a6d362001-08-24 14:24:45 +0000239}
240
ap@webkit.orga1251b32008-05-13 09:46:47 +0000241PassRefPtr<UString::Rep> UString::Rep::createFromUTF8(const char* string)
242{
243 if (!string)
244 return &UString::Rep::null;
245
246 size_t length = strlen(string);
247 Vector<UChar, 1024> buffer(length);
248 UChar* p = buffer.data();
249 if (conversionOK != convertUTF8ToUTF16(&string, string + length, &p, p + length))
250 return &UString::Rep::null;
251
252 return UString::Rep::createCopying(buffer.data(), p - buffer.data());
253}
254
darin5721aa92002-11-20 01:23:02 +0000255void UString::Rep::destroy()
256{
ap@webkit.org11f38712008-04-07 06:33:20 +0000257 // Static null and empty strings can never be destroyed, but we cannot rely on reference counting, because ref/deref are not thread-safe.
258 if (!isStatic) {
ap@webkit.org0ea9a692008-04-18 19:46:13 +0000259 if (identifierTable)
ap@webkit.org11f38712008-04-07 06:33:20 +0000260 Identifier::remove(this);
261 if (baseString == this)
262 fastFree(buf);
263 else
264 baseString->deref();
ggarenff599582007-03-07 04:25:49 +0000265
ap@webkit.org11f38712008-04-07 06:33:20 +0000266 delete this;
mjsf9c37952004-04-14 02:33:59 +0000267 }
darin5721aa92002-11-20 01:23:02 +0000268}
269
mjsa5183842003-03-04 01:13:26 +0000270// Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's
271// or anything like that.
272const unsigned PHI = 0x9e3779b9U;
273
mjsbcd9d062005-06-28 00:02:08 +0000274// Paul Hsieh's SuperFastHash
275// http://www.azillionmonkeys.com/qed/hash.html
276unsigned UString::Rep::computeHash(const UChar *s, int len)
darin5721aa92002-11-20 01:23:02 +0000277{
mjsbcd9d062005-06-28 00:02:08 +0000278 unsigned l = len;
279 uint32_t hash = PHI;
280 uint32_t tmp;
darin5721aa92002-11-20 01:23:02 +0000281
mjsbcd9d062005-06-28 00:02:08 +0000282 int rem = l & 1;
283 l >>= 1;
mjsa5183842003-03-04 01:13:26 +0000284
mjsbcd9d062005-06-28 00:02:08 +0000285 // Main loop
286 for (; l > 0; l--) {
eric@webkit.org87d855b2008-03-10 22:06:44 +0000287 hash += s[0];
288 tmp = (s[1] << 11) ^ hash;
mjsbcd9d062005-06-28 00:02:08 +0000289 hash = (hash << 16) ^ tmp;
290 s += 2;
291 hash += hash >> 11;
292 }
mjsa5183842003-03-04 01:13:26 +0000293
mjsbcd9d062005-06-28 00:02:08 +0000294 // Handle end case
295 if (rem) {
eric@webkit.org87d855b2008-03-10 22:06:44 +0000296 hash += s[0];
mjsbcd9d062005-06-28 00:02:08 +0000297 hash ^= hash << 11;
298 hash += hash >> 17;
299 }
mjsa5183842003-03-04 01:13:26 +0000300
mjsbcd9d062005-06-28 00:02:08 +0000301 // Force "avalanching" of final 127 bits
302 hash ^= hash << 3;
303 hash += hash >> 5;
304 hash ^= hash << 2;
305 hash += hash >> 15;
306 hash ^= hash << 10;
307
308 // this avoids ever returning a hash code of 0, since that is used to
309 // signal "hash not computed yet", using a value that is likely to be
310 // effectively the same as 0 when the low bits are masked
311 if (hash == 0)
312 hash = 0x80000000;
313
314 return hash;
darin55be9892002-11-20 02:35:01 +0000315}
316
mjsbcd9d062005-06-28 00:02:08 +0000317// Paul Hsieh's SuperFastHash
318// http://www.azillionmonkeys.com/qed/hash.html
darin55be9892002-11-20 02:35:01 +0000319unsigned UString::Rep::computeHash(const char *s)
320{
mjsbcd9d062005-06-28 00:02:08 +0000321 // This hash is designed to work on 16-bit chunks at a time. But since the normal case
322 // (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they
323 // were 16-bit chunks, which should give matching results
darin55be9892002-11-20 02:35:01 +0000324
mjsbcd9d062005-06-28 00:02:08 +0000325 uint32_t hash = PHI;
326 uint32_t tmp;
darinb847b442006-10-27 16:48:28 +0000327 size_t l = strlen(s);
mjsbcd9d062005-06-28 00:02:08 +0000328
darinb847b442006-10-27 16:48:28 +0000329 size_t rem = l & 1;
mjsbcd9d062005-06-28 00:02:08 +0000330 l >>= 1;
mjsa5183842003-03-04 01:13:26 +0000331
mjsbcd9d062005-06-28 00:02:08 +0000332 // Main loop
333 for (; l > 0; l--) {
334 hash += (unsigned char)s[0];
335 tmp = ((unsigned char)s[1] << 11) ^ hash;
336 hash = (hash << 16) ^ tmp;
337 s += 2;
338 hash += hash >> 11;
339 }
mjsa5183842003-03-04 01:13:26 +0000340
mjsbcd9d062005-06-28 00:02:08 +0000341 // Handle end case
342 if (rem) {
343 hash += (unsigned char)s[0];
344 hash ^= hash << 11;
345 hash += hash >> 17;
346 }
mjsa5183842003-03-04 01:13:26 +0000347
mjsbcd9d062005-06-28 00:02:08 +0000348 // Force "avalanching" of final 127 bits
349 hash ^= hash << 3;
350 hash += hash >> 5;
351 hash ^= hash << 2;
352 hash += hash >> 15;
353 hash ^= hash << 10;
354
355 // this avoids ever returning a hash code of 0, since that is used to
356 // signal "hash not computed yet", using a value that is likely to be
357 // effectively the same as 0 when the low bits are masked
358 if (hash == 0)
359 hash = 0x80000000;
mjsa5183842003-03-04 01:13:26 +0000360
mjsbcd9d062005-06-28 00:02:08 +0000361 return hash;
darin5721aa92002-11-20 01:23:02 +0000362}
363
mjsf9c37952004-04-14 02:33:59 +0000364// put these early so they can be inlined
bdash41705de2007-08-02 09:33:22 +0000365inline size_t UString::expandedSize(size_t size, size_t otherSize) const
mjsf9c37952004-04-14 02:33:59 +0000366{
darin0d66de72007-08-08 00:45:39 +0000367 // Do the size calculation in two parts, returning overflowIndicator if
368 // we overflow the maximum value that we can handle.
369
darin6238e2a2007-08-14 22:19:04 +0000370 if (size > maxUChars())
371 return overflowIndicator();
bdash41705de2007-08-02 09:33:22 +0000372
373 size_t expandedSize = ((size + 10) / 10 * 11) + 1;
darin6238e2a2007-08-14 22:19:04 +0000374 if (maxUChars() - expandedSize < otherSize)
375 return overflowIndicator();
bdash41705de2007-08-02 09:33:22 +0000376
377 return expandedSize + otherSize;
mjsf9c37952004-04-14 02:33:59 +0000378}
379
380inline int UString::usedCapacity() const
381{
mjs06ed4662007-07-25 21:50:00 +0000382 return m_rep->baseString->usedCapacity;
mjsf9c37952004-04-14 02:33:59 +0000383}
384
mjs37521172004-04-19 21:26:40 +0000385inline int UString::usedPreCapacity() const
386{
mjs06ed4662007-07-25 21:50:00 +0000387 return m_rep->baseString->usedPreCapacity;
mjs37521172004-04-19 21:26:40 +0000388}
389
mjsf9c37952004-04-14 02:33:59 +0000390void UString::expandCapacity(int requiredLength)
391{
mjs06ed4662007-07-25 21:50:00 +0000392 Rep* r = m_rep->baseString;
mjsf9c37952004-04-14 02:33:59 +0000393
394 if (requiredLength > r->capacity) {
bdash41705de2007-08-02 09:33:22 +0000395 size_t newCapacity = expandedSize(requiredLength, r->preCapacity);
396 UChar* oldBuf = r->buf;
397 r->buf = reallocChars(r->buf, newCapacity);
398 if (!r->buf) {
399 r->buf = oldBuf;
400 m_rep = &Rep::null;
401 return;
402 }
mjs37521172004-04-19 21:26:40 +0000403 r->capacity = newCapacity - r->preCapacity;
mjsf9c37952004-04-14 02:33:59 +0000404 }
405 if (requiredLength > r->usedCapacity) {
406 r->usedCapacity = requiredLength;
407 }
408}
409
mjs37521172004-04-19 21:26:40 +0000410void UString::expandPreCapacity(int requiredPreCap)
411{
mjs06ed4662007-07-25 21:50:00 +0000412 Rep* r = m_rep->baseString;
mjs37521172004-04-19 21:26:40 +0000413
414 if (requiredPreCap > r->preCapacity) {
bdash41705de2007-08-02 09:33:22 +0000415 size_t newCapacity = expandedSize(requiredPreCap, r->capacity);
mjs37521172004-04-19 21:26:40 +0000416 int delta = newCapacity - r->capacity - r->preCapacity;
417
bdash41705de2007-08-02 09:33:22 +0000418 UChar* newBuf = allocChars(newCapacity);
419 if (!newBuf) {
420 m_rep = &Rep::null;
421 return;
422 }
mjs37521172004-04-19 21:26:40 +0000423 memcpy(newBuf + delta, r->buf, (r->capacity + r->preCapacity) * sizeof(UChar));
mjscff5e5e2005-09-27 22:37:33 +0000424 fastFree(r->buf);
mjs37521172004-04-19 21:26:40 +0000425 r->buf = newBuf;
426
427 r->preCapacity = newCapacity - r->capacity;
428 }
429 if (requiredPreCap > r->usedPreCapacity) {
430 r->usedPreCapacity = requiredPreCap;
431 }
432}
433
kocienda66a6d362001-08-24 14:24:45 +0000434UString::UString(const char *c)
435{
darin2dbbd422002-08-10 04:31:50 +0000436 if (!c) {
mjs97e2b182005-12-06 09:21:15 +0000437 m_rep = &Rep::null;
darin2dbbd422002-08-10 04:31:50 +0000438 return;
439 }
ggaren699f4d42007-10-27 19:20:25 +0000440
441 if (!c[0]) {
mjs97e2b182005-12-06 09:21:15 +0000442 m_rep = &Rep::empty;
darin07f7cce2002-08-12 20:14:02 +0000443 return;
444 }
ggaren699f4d42007-10-27 19:20:25 +0000445
446 size_t length = strlen(c);
bdash41705de2007-08-02 09:33:22 +0000447 UChar *d = allocChars(length);
448 if (!d)
449 m_rep = &Rep::null;
450 else {
451 for (size_t i = 0; i < length; i++)
eric@webkit.org87d855b2008-03-10 22:06:44 +0000452 d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend
bdash41705de2007-08-02 09:33:22 +0000453 m_rep = Rep::create(d, static_cast<int>(length));
454 }
kocienda66a6d362001-08-24 14:24:45 +0000455}
456
457UString::UString(const UChar *c, int length)
458{
mjs97e2b182005-12-06 09:21:15 +0000459 if (length == 0)
460 m_rep = &Rep::empty;
461 else
462 m_rep = Rep::createCopying(c, length);
kocienda66a6d362001-08-24 14:24:45 +0000463}
464
465UString::UString(UChar *c, int length, bool copy)
466{
mjs97e2b182005-12-06 09:21:15 +0000467 if (length == 0)
468 m_rep = &Rep::empty;
469 else if (copy)
470 m_rep = Rep::createCopying(c, length);
471 else
472 m_rep = Rep::create(c, length);
kocienda66a6d362001-08-24 14:24:45 +0000473}
474
mrowe@apple.comf458fb72007-11-16 22:43:36 +0000475UString::UString(const Vector<UChar>& buffer)
476{
477 if (!buffer.size())
478 m_rep = &Rep::empty;
479 else
480 m_rep = Rep::createCopying(buffer.data(), buffer.size());
481}
482
483
darin2dbbd422002-08-10 04:31:50 +0000484UString::UString(const UString &a, const UString &b)
kocienda66a6d362001-08-24 14:24:45 +0000485{
darin2dbbd422002-08-10 04:31:50 +0000486 int aSize = a.size();
mjs97e2b182005-12-06 09:21:15 +0000487 int aOffset = a.m_rep->offset;
darin2dbbd422002-08-10 04:31:50 +0000488 int bSize = b.size();
mjs97e2b182005-12-06 09:21:15 +0000489 int bOffset = b.m_rep->offset;
darin07f7cce2002-08-12 20:14:02 +0000490 int length = aSize + bSize;
mjsf9c37952004-04-14 02:33:59 +0000491
492 // possible cases:
493
494 if (aSize == 0) {
495 // a is empty
mjs97e2b182005-12-06 09:21:15 +0000496 m_rep = b.m_rep;
mjsf9c37952004-04-14 02:33:59 +0000497 } else if (bSize == 0) {
498 // b is empty
mjs97e2b182005-12-06 09:21:15 +0000499 m_rep = a.m_rep;
mjs06ed4662007-07-25 21:50:00 +0000500 } else if (aOffset + aSize == a.usedCapacity() && aSize >= minShareSize && 4 * aSize >= bSize &&
darinae58eff2006-07-30 00:04:22 +0000501 (-bOffset != b.usedPreCapacity() || aSize >= bSize)) {
mjs37521172004-04-19 21:26:40 +0000502 // - a reaches the end of its buffer so it qualifies for shared append
503 // - also, it's at least a quarter the length of b - appending to a much shorter
504 // string does more harm than good
505 // - however, if b qualifies for prepend and is longer than a, we'd rather prepend
mjsf9c37952004-04-14 02:33:59 +0000506 UString x(a);
mjs7a882e82004-04-16 18:54:21 +0000507 x.expandCapacity(aOffset + length);
bdash41705de2007-08-02 09:33:22 +0000508 if (a.data() && x.data()) {
aliceli196d1c4d2007-01-27 02:31:28 +0000509 memcpy(const_cast<UChar *>(a.data() + aSize), b.data(), bSize * sizeof(UChar));
510 m_rep = Rep::create(a.m_rep, 0, length);
511 } else
512 m_rep = &Rep::null;
kmccullough@apple.com9f7c99e2008-01-18 21:05:16 +0000513 } else if (-bOffset == b.usedPreCapacity() && bSize >= minShareSize && 4 * bSize >= aSize) {
mjs37521172004-04-19 21:26:40 +0000514 // - b reaches the beginning of its buffer so it qualifies for shared prepend
515 // - also, it's at least a quarter the length of a - prepending to a much shorter
516 // string does more harm than good
517 UString y(b);
518 y.expandPreCapacity(-bOffset + aSize);
bdash41705de2007-08-02 09:33:22 +0000519 if (b.data() && y.data()) {
aliceli196d1c4d2007-01-27 02:31:28 +0000520 memcpy(const_cast<UChar *>(b.data() - aSize), a.data(), aSize * sizeof(UChar));
521 m_rep = Rep::create(b.m_rep, -aSize, length);
522 } else
523 m_rep = &Rep::null;
mjsf9c37952004-04-14 02:33:59 +0000524 } else {
mjs37521172004-04-19 21:26:40 +0000525 // a does not qualify for append, and b does not qualify for prepend, gotta make a whole new string
bdash41705de2007-08-02 09:33:22 +0000526 size_t newCapacity = expandedSize(length, 0);
527 UChar* d = allocChars(newCapacity);
528 if (!d)
529 m_rep = &Rep::null;
530 else {
aliceli196d1c4d2007-01-27 02:31:28 +0000531 memcpy(d, a.data(), aSize * sizeof(UChar));
532 memcpy(d + aSize, b.data(), bSize * sizeof(UChar));
533 m_rep = Rep::create(d, length);
534 m_rep->capacity = newCapacity;
bdash41705de2007-08-02 09:33:22 +0000535 }
darin07f7cce2002-08-12 20:14:02 +0000536 }
kocienda66a6d362001-08-24 14:24:45 +0000537}
538
ggarenff599582007-03-07 04:25:49 +0000539const UString& UString::null()
darin8aede132003-04-29 18:26:29 +0000540{
ap@webkit.org11f38712008-04-07 06:33:20 +0000541 static UString* n = new UString; // Should be called from main thread at least once to be safely initialized.
ggarenff599582007-03-07 04:25:49 +0000542 return *n;
darin8aede132003-04-29 18:26:29 +0000543}
544
kocienda66a6d362001-08-24 14:24:45 +0000545UString UString::from(int i)
546{
adele704e8bb2005-09-16 22:42:30 +0000547 UChar buf[1 + sizeof(i) * 3];
548 UChar *end = buf + sizeof(buf) / sizeof(UChar);
549 UChar *p = end;
550
551 if (i == 0) {
552 *--p = '0';
553 } else if (i == INT_MIN) {
554 char minBuf[1 + sizeof(i) * 3];
555 sprintf(minBuf, "%d", INT_MIN);
556 return UString(minBuf);
557 } else {
558 bool negative = false;
559 if (i < 0) {
560 negative = true;
561 i = -i;
562 }
563 while (i) {
564 *--p = (unsigned short)((i % 10) + '0');
565 i /= 10;
566 }
567 if (negative) {
568 *--p = '-';
569 }
570 }
571
darinb847b442006-10-27 16:48:28 +0000572 return UString(p, static_cast<int>(end - p));
kocienda66a6d362001-08-24 14:24:45 +0000573}
574
575UString UString::from(unsigned int u)
576{
adele704e8bb2005-09-16 22:42:30 +0000577 UChar buf[sizeof(u) * 3];
578 UChar *end = buf + sizeof(buf) / sizeof(UChar);
darinff56afa02002-11-19 22:25:11 +0000579 UChar *p = end;
darin451d4352002-11-19 08:10:03 +0000580
581 if (u == 0) {
582 *--p = '0';
583 } else {
584 while (u) {
585 *--p = (unsigned short)((u % 10) + '0');
586 u /= 10;
587 }
588 }
589
darinb847b442006-10-27 16:48:28 +0000590 return UString(p, static_cast<int>(end - p));
kocienda66a6d362001-08-24 14:24:45 +0000591}
592
mjsda18fd02002-08-15 12:02:07 +0000593UString UString::from(long l)
594{
adele704e8bb2005-09-16 22:42:30 +0000595 UChar buf[1 + sizeof(l) * 3];
596 UChar *end = buf + sizeof(buf) / sizeof(UChar);
darinff56afa02002-11-19 22:25:11 +0000597 UChar *p = end;
darin451d4352002-11-19 08:10:03 +0000598
599 if (l == 0) {
600 *--p = '0';
601 } else if (l == LONG_MIN) {
adele704e8bb2005-09-16 22:42:30 +0000602 char minBuf[1 + sizeof(l) * 3];
darin451d4352002-11-19 08:10:03 +0000603 sprintf(minBuf, "%ld", LONG_MIN);
604 return UString(minBuf);
605 } else {
606 bool negative = false;
607 if (l < 0) {
608 negative = true;
609 l = -l;
610 }
611 while (l) {
612 *--p = (unsigned short)((l % 10) + '0');
613 l /= 10;
614 }
615 if (negative) {
616 *--p = '-';
617 }
618 }
619
darinb847b442006-10-27 16:48:28 +0000620 return UString(p, static_cast<int>(end - p));
mjsda18fd02002-08-15 12:02:07 +0000621}
622
kocienda66a6d362001-08-24 14:24:45 +0000623UString UString::from(double d)
624{
mjsf8fa72e2006-03-17 22:03:39 +0000625 // avoid ever printing -NaN, in JS conceptually there is only one NaN value
mrowe@apple.com915de552007-10-29 02:52:04 +0000626 if (isnan(d))
mjsf8fa72e2006-03-17 22:03:39 +0000627 return "NaN";
628
mjs7c33c6f2002-12-03 22:51:39 +0000629 char buf[80];
630 int decimalPoint;
631 int sign;
mjsf273a9f2002-12-15 03:33:10 +0000632
weinig@apple.com843df6f32008-04-16 18:41:54 +0000633 char *result = dtoa(d, 0, &decimalPoint, &sign, NULL);
darinb847b442006-10-27 16:48:28 +0000634 int length = static_cast<int>(strlen(result));
mjs7c33c6f2002-12-03 22:51:39 +0000635
636 int i = 0;
637 if (sign) {
638 buf[i++] = '-';
mjs6f821c82002-03-22 00:31:57 +0000639 }
mjs7c33c6f2002-12-03 22:51:39 +0000640
mjsf273a9f2002-12-15 03:33:10 +0000641 if (decimalPoint <= 0 && decimalPoint > -6) {
mjs957a1b32002-12-15 00:37:56 +0000642 buf[i++] = '0';
mjs7c33c6f2002-12-03 22:51:39 +0000643 buf[i++] = '.';
mjs957a1b32002-12-15 00:37:56 +0000644 for (int j = decimalPoint; j < 0; j++) {
645 buf[i++] = '0';
646 }
mjs7c33c6f2002-12-03 22:51:39 +0000647 strcpy(buf + i, result);
mjsf273a9f2002-12-15 03:33:10 +0000648 } else if (decimalPoint <= 21 && decimalPoint > 0) {
649 if (length <= decimalPoint) {
650 strcpy(buf + i, result);
651 i += length;
652 for (int j = 0; j < decimalPoint - length; j++) {
darinae58eff2006-07-30 00:04:22 +0000653 buf[i++] = '0';
mjsf273a9f2002-12-15 03:33:10 +0000654 }
655 buf[i] = '\0';
656 } else {
657 strncpy(buf + i, result, decimalPoint);
658 i += decimalPoint;
659 buf[i++] = '.';
660 strcpy(buf + i, result + decimalPoint);
661 }
662 } else if (result[0] < '0' || result[0] > '9') {
mjs7c33c6f2002-12-03 22:51:39 +0000663 strcpy(buf + i, result);
664 } else {
mjsf273a9f2002-12-15 03:33:10 +0000665 buf[i++] = result[0];
666 if (length > 1) {
667 buf[i++] = '.';
668 strcpy(buf + i, result + 1);
669 i += length - 1;
670 }
671
672 buf[i++] = 'e';
673 buf[i++] = (decimalPoint >= 0) ? '+' : '-';
674 // decimalPoint can't be more than 3 digits decimal given the
675 // nature of float representation
676 int exponential = decimalPoint - 1;
darinb847b442006-10-27 16:48:28 +0000677 if (exponential < 0)
678 exponential = -exponential;
679 if (exponential >= 100)
680 buf[i++] = static_cast<char>('0' + exponential / 100);
681 if (exponential >= 10)
682 buf[i++] = static_cast<char>('0' + (exponential % 100) / 10);
683 buf[i++] = static_cast<char>('0' + exponential % 10);
mjsf273a9f2002-12-15 03:33:10 +0000684 buf[i++] = '\0';
mjs7c33c6f2002-12-03 22:51:39 +0000685 }
weinig@apple.com843df6f32008-04-16 18:41:54 +0000686
687 freedtoa(result);
688
kocienda66a6d362001-08-24 14:24:45 +0000689 return UString(buf);
690}
691
darince72b7a2007-02-06 19:42:35 +0000692UString UString::spliceSubstringsWithSeparators(const Range* substringRanges, int rangeCount, const UString* separators, int separatorCount) const
mjs5d90e062004-09-15 00:16:34 +0000693{
darince72b7a2007-02-06 19:42:35 +0000694 if (rangeCount == 1 && separatorCount == 0) {
695 int thisSize = size();
696 int position = substringRanges[0].position;
697 int length = substringRanges[0].length;
698 if (position <= 0 && length >= thisSize)
699 return *this;
700 return UString::Rep::create(m_rep, max(0, position), min(thisSize, length));
701 }
702
mjs5d90e062004-09-15 00:16:34 +0000703 int totalLength = 0;
darince72b7a2007-02-06 19:42:35 +0000704 for (int i = 0; i < rangeCount; i++)
mjs5d90e062004-09-15 00:16:34 +0000705 totalLength += substringRanges[i].length;
darince72b7a2007-02-06 19:42:35 +0000706 for (int i = 0; i < separatorCount; i++)
mjs5d90e062004-09-15 00:16:34 +0000707 totalLength += separators[i].size();
mjs5d90e062004-09-15 00:16:34 +0000708
darin0d66de72007-08-08 00:45:39 +0000709 if (totalLength == 0)
710 return "";
711
bdash41705de2007-08-02 09:33:22 +0000712 UChar* buffer = allocChars(totalLength);
713 if (!buffer)
714 return null();
mjs5d90e062004-09-15 00:16:34 +0000715
darind5893602005-08-01 05:02:13 +0000716 int maxCount = max(rangeCount, separatorCount);
mjs5d90e062004-09-15 00:16:34 +0000717 int bufferPos = 0;
718 for (int i = 0; i < maxCount; i++) {
719 if (i < rangeCount) {
720 memcpy(buffer + bufferPos, data() + substringRanges[i].position, substringRanges[i].length * sizeof(UChar));
721 bufferPos += substringRanges[i].length;
722 }
723 if (i < separatorCount) {
724 memcpy(buffer + bufferPos, separators[i].data(), separators[i].size() * sizeof(UChar));
725 bufferPos += separators[i].size();
726 }
727 }
728
darince72b7a2007-02-06 19:42:35 +0000729 return UString::Rep::create(buffer, totalLength);
mjs5d90e062004-09-15 00:16:34 +0000730}
731
eric@webkit.org87d855b2008-03-10 22:06:44 +0000732UString& UString::append(const UString &t)
kocienda66a6d362001-08-24 14:24:45 +0000733{
mjs7a882e82004-04-16 18:54:21 +0000734 int thisSize = size();
mjs97e2b182005-12-06 09:21:15 +0000735 int thisOffset = m_rep->offset;
mjsf9c37952004-04-14 02:33:59 +0000736 int tSize = t.size();
737 int length = thisSize + tSize;
738
739 // possible cases:
740 if (thisSize == 0) {
741 // this is empty
742 *this = t;
743 } else if (tSize == 0) {
744 // t is empty
mjs06ed4662007-07-25 21:50:00 +0000745 } else if (m_rep->baseIsSelf() && m_rep->rc == 1) {
mjsf9c37952004-04-14 02:33:59 +0000746 // this is direct and has refcount of 1 (so we can just alter it directly)
mjs7a882e82004-04-16 18:54:21 +0000747 expandCapacity(thisOffset + length);
bdash41705de2007-08-02 09:33:22 +0000748 if (data()) {
749 memcpy(const_cast<UChar*>(data() + thisSize), t.data(), tSize * sizeof(UChar));
750 m_rep->len = length;
751 m_rep->_hash = 0;
752 }
mjs06ed4662007-07-25 21:50:00 +0000753 } else if (thisOffset + thisSize == usedCapacity() && thisSize >= minShareSize) {
754 // this reaches the end of the buffer - extend it if it's long enough to append to
darin08f6b3a2004-08-10 03:05:37 +0000755 expandCapacity(thisOffset + length);
bdash41705de2007-08-02 09:33:22 +0000756 if (data()) {
757 memcpy(const_cast<UChar*>(data() + thisSize), t.data(), tSize * sizeof(UChar));
758 m_rep = Rep::create(m_rep, 0, length);
759 }
mjsf9c37952004-04-14 02:33:59 +0000760 } else {
761 // this is shared with someone using more capacity, gotta make a whole new string
bdash41705de2007-08-02 09:33:22 +0000762 size_t newCapacity = expandedSize(length, 0);
763 UChar* d = allocChars(newCapacity);
764 if (!d)
765 m_rep = &Rep::null;
766 else {
767 memcpy(d, data(), thisSize * sizeof(UChar));
768 memcpy(const_cast<UChar*>(d + thisSize), t.data(), tSize * sizeof(UChar));
769 m_rep = Rep::create(d, length);
770 m_rep->capacity = newCapacity;
771 }
darin0c2dc3f2002-06-04 22:33:26 +0000772 }
kocienda66a6d362001-08-24 14:24:45 +0000773
774 return *this;
775}
776
darin@apple.com59c4d4e2008-06-27 02:53:42 +0000777UString& UString::append(const UChar* tData, int tSize)
778{
779 int thisSize = size();
780 int thisOffset = m_rep->offset;
781 int length = thisSize + tSize;
782
783 // possible cases:
784 if (tSize == 0) {
785 // t is empty
786 } else if (thisSize == 0) {
787 // this is empty
788 m_rep = Rep::createCopying(tData, tSize);
789 } else if (m_rep->baseIsSelf() && m_rep->rc == 1) {
790 // this is direct and has refcount of 1 (so we can just alter it directly)
791 expandCapacity(thisOffset + length);
792 if (data()) {
793 memcpy(const_cast<UChar*>(data() + thisSize), tData, tSize * sizeof(UChar));
794 m_rep->len = length;
795 m_rep->_hash = 0;
796 }
797 } else if (thisOffset + thisSize == usedCapacity() && thisSize >= minShareSize) {
798 // this reaches the end of the buffer - extend it if it's long enough to append to
799 expandCapacity(thisOffset + length);
800 if (data()) {
801 memcpy(const_cast<UChar*>(data() + thisSize), tData, tSize * sizeof(UChar));
802 m_rep = Rep::create(m_rep, 0, length);
803 }
804 } else {
805 // this is shared with someone using more capacity, gotta make a whole new string
806 size_t newCapacity = expandedSize(length, 0);
807 UChar* d = allocChars(newCapacity);
808 if (!d)
809 m_rep = &Rep::null;
810 else {
811 memcpy(d, data(), thisSize * sizeof(UChar));
812 memcpy(const_cast<UChar*>(d + thisSize), tData, tSize * sizeof(UChar));
813 m_rep = Rep::create(d, length);
814 m_rep->capacity = newCapacity;
815 }
816 }
817
818 return *this;
819}
820
eric@webkit.org87d855b2008-03-10 22:06:44 +0000821UString& UString::append(const char *t)
darin6c9bbfd2003-08-18 18:51:25 +0000822{
mjs7a882e82004-04-16 18:54:21 +0000823 int thisSize = size();
mjs97e2b182005-12-06 09:21:15 +0000824 int thisOffset = m_rep->offset;
darinb847b442006-10-27 16:48:28 +0000825 int tSize = static_cast<int>(strlen(t));
mjsf9c37952004-04-14 02:33:59 +0000826 int length = thisSize + tSize;
827
828 // possible cases:
829 if (thisSize == 0) {
830 // this is empty
831 *this = t;
832 } else if (tSize == 0) {
833 // t is empty, we'll just return *this below.
mjs06ed4662007-07-25 21:50:00 +0000834 } else if (m_rep->baseIsSelf() && m_rep->rc == 1) {
mjsf9c37952004-04-14 02:33:59 +0000835 // this is direct and has refcount of 1 (so we can just alter it directly)
mjs7a882e82004-04-16 18:54:21 +0000836 expandCapacity(thisOffset + length);
mjsf9c37952004-04-14 02:33:59 +0000837 UChar *d = const_cast<UChar *>(data());
bdash41705de2007-08-02 09:33:22 +0000838 if (d) {
839 for (int i = 0; i < tSize; ++i)
eric@webkit.org87d855b2008-03-10 22:06:44 +0000840 d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend
bdash41705de2007-08-02 09:33:22 +0000841 m_rep->len = length;
842 m_rep->_hash = 0;
843 }
mjs06ed4662007-07-25 21:50:00 +0000844 } else if (thisOffset + thisSize == usedCapacity() && thisSize >= minShareSize) {
mjs7a882e82004-04-16 18:54:21 +0000845 // this string reaches the end of the buffer - extend it
846 expandCapacity(thisOffset + length);
mjsf9c37952004-04-14 02:33:59 +0000847 UChar *d = const_cast<UChar *>(data());
bdash41705de2007-08-02 09:33:22 +0000848 if (d) {
849 for (int i = 0; i < tSize; ++i)
eric@webkit.org87d855b2008-03-10 22:06:44 +0000850 d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend
bdash41705de2007-08-02 09:33:22 +0000851 m_rep = Rep::create(m_rep, 0, length);
852 }
mjsf9c37952004-04-14 02:33:59 +0000853 } else {
854 // this is shared with someone using more capacity, gotta make a whole new string
bdash41705de2007-08-02 09:33:22 +0000855 size_t newCapacity = expandedSize(length, 0);
856 UChar* d = allocChars(newCapacity);
857 if (!d)
858 m_rep = &Rep::null;
859 else {
860 memcpy(d, data(), thisSize * sizeof(UChar));
861 for (int i = 0; i < tSize; ++i)
eric@webkit.org87d855b2008-03-10 22:06:44 +0000862 d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend
bdash41705de2007-08-02 09:33:22 +0000863 m_rep = Rep::create(d, length);
864 m_rep->capacity = newCapacity;
865 }
darin6c9bbfd2003-08-18 18:51:25 +0000866 }
darin6c9bbfd2003-08-18 18:51:25 +0000867
868 return *this;
869}
870
eric@webkit.org87d855b2008-03-10 22:06:44 +0000871UString& UString::append(UChar c)
darin6c9bbfd2003-08-18 18:51:25 +0000872{
mjs97e2b182005-12-06 09:21:15 +0000873 int thisOffset = m_rep->offset;
mjsf9c37952004-04-14 02:33:59 +0000874 int length = size();
875
876 // possible cases:
877 if (length == 0) {
mjs97e2b182005-12-06 09:21:15 +0000878 // this is empty - must make a new m_rep because we don't want to pollute the shared empty one
bdash41705de2007-08-02 09:33:22 +0000879 size_t newCapacity = expandedSize(1, 0);
880 UChar* d = allocChars(newCapacity);
881 if (!d)
882 m_rep = &Rep::null;
883 else {
884 d[0] = c;
885 m_rep = Rep::create(d, 1);
886 m_rep->capacity = newCapacity;
887 }
mjs06ed4662007-07-25 21:50:00 +0000888 } else if (m_rep->baseIsSelf() && m_rep->rc == 1) {
mjsf9c37952004-04-14 02:33:59 +0000889 // this is direct and has refcount of 1 (so we can just alter it directly)
mjs7a882e82004-04-16 18:54:21 +0000890 expandCapacity(thisOffset + length + 1);
mjsf9c37952004-04-14 02:33:59 +0000891 UChar *d = const_cast<UChar *>(data());
bdash41705de2007-08-02 09:33:22 +0000892 if (d) {
893 d[length] = c;
894 m_rep->len = length + 1;
895 m_rep->_hash = 0;
896 }
mjs06ed4662007-07-25 21:50:00 +0000897 } else if (thisOffset + length == usedCapacity() && length >= minShareSize) {
mjs7a882e82004-04-16 18:54:21 +0000898 // this reaches the end of the string - extend it and share
899 expandCapacity(thisOffset + length + 1);
mjsf9c37952004-04-14 02:33:59 +0000900 UChar *d = const_cast<UChar *>(data());
bdash41705de2007-08-02 09:33:22 +0000901 if (d) {
902 d[length] = c;
903 m_rep = Rep::create(m_rep, 0, length + 1);
904 }
mjsf9c37952004-04-14 02:33:59 +0000905 } else {
906 // this is shared with someone using more capacity, gotta make a whole new string
bdash41705de2007-08-02 09:33:22 +0000907 size_t newCapacity = expandedSize(length + 1, 0);
908 UChar* d = allocChars(newCapacity);
909 if (!d)
910 m_rep = &Rep::null;
911 else {
912 memcpy(d, data(), length * sizeof(UChar));
913 d[length] = c;
914 m_rep = Rep::create(d, length + 1);
915 m_rep->capacity = newCapacity;
916 }
darin6c9bbfd2003-08-18 18:51:25 +0000917 }
darin6c9bbfd2003-08-18 18:51:25 +0000918
919 return *this;
920}
921
darin@apple.com3beb3002008-04-28 05:59:07 +0000922bool UString::getCString(CStringBuffer& buffer) const
kocienda66a6d362001-08-24 14:24:45 +0000923{
darin@apple.com3beb3002008-04-28 05:59:07 +0000924 int length = size();
925 int neededSize = length + 1;
926 buffer.resize(neededSize);
927 char* buf = buffer.data();
ap@webkit.org11f38712008-04-07 06:33:20 +0000928
darin@apple.com3beb3002008-04-28 05:59:07 +0000929 UChar ored = 0;
930 const UChar* p = data();
931 char* q = buf;
932 const UChar* limit = p + length;
933 while (p != limit) {
934 UChar c = p[0];
935 ored |= c;
936 *q = static_cast<char>(c);
937 ++p;
938 ++q;
939 }
940 *q = '\0';
ap@webkit.org11f38712008-04-07 06:33:20 +0000941
darin@apple.com3beb3002008-04-28 05:59:07 +0000942 return !(ored & 0xFF00);
kocienda66a6d362001-08-24 14:24:45 +0000943}
944
945char *UString::ascii() const
946{
darin2dbbd422002-08-10 04:31:50 +0000947 int length = size();
948 int neededSize = length + 1;
ap@webkit.org11f38712008-04-07 06:33:20 +0000949 delete[] statBuffer;
950 statBuffer = new char[neededSize];
darin2dbbd422002-08-10 04:31:50 +0000951
952 const UChar *p = data();
953 char *q = statBuffer;
954 const UChar *limit = p + length;
955 while (p != limit) {
eric@webkit.org87d855b2008-03-10 22:06:44 +0000956 *q = static_cast<char>(p[0]);
darin2dbbd422002-08-10 04:31:50 +0000957 ++p;
958 ++q;
959 }
960 *q = '\0';
kocienda66a6d362001-08-24 14:24:45 +0000961
kocienda66a6d362001-08-24 14:24:45 +0000962 return statBuffer;
963}
964
eric@webkit.org87d855b2008-03-10 22:06:44 +0000965UString& UString::operator=(const char *c)
kocienda66a6d362001-08-24 14:24:45 +0000966{
darin0d66de72007-08-08 00:45:39 +0000967 if (!c) {
968 m_rep = &Rep::null;
969 return *this;
970 }
971
ggaren699f4d42007-10-27 19:20:25 +0000972 if (!c[0]) {
darin0d66de72007-08-08 00:45:39 +0000973 m_rep = &Rep::empty;
974 return *this;
975 }
976
ggaren699f4d42007-10-27 19:20:25 +0000977 int l = static_cast<int>(strlen(c));
darin0c2dc3f2002-06-04 22:33:26 +0000978 UChar *d;
mjs06ed4662007-07-25 21:50:00 +0000979 if (m_rep->rc == 1 && l <= m_rep->capacity && m_rep->baseIsSelf() && m_rep->offset == 0 && m_rep->preCapacity == 0) {
mjs97e2b182005-12-06 09:21:15 +0000980 d = m_rep->buf;
981 m_rep->_hash = 0;
mjs07533762007-07-26 01:50:54 +0000982 m_rep->len = l;
darin0c2dc3f2002-06-04 22:33:26 +0000983 } else {
bdash41705de2007-08-02 09:33:22 +0000984 d = allocChars(l);
985 if (!d) {
986 m_rep = &Rep::null;
987 return *this;
988 }
mjs97e2b182005-12-06 09:21:15 +0000989 m_rep = Rep::create(d, l);
darin0c2dc3f2002-06-04 22:33:26 +0000990 }
991 for (int i = 0; i < l; i++)
eric@webkit.org87d855b2008-03-10 22:06:44 +0000992 d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend
kocienda66a6d362001-08-24 14:24:45 +0000993
994 return *this;
995}
996
kocienda66a6d362001-08-24 14:24:45 +0000997bool UString::is8Bit() const
998{
999 const UChar *u = data();
darin2dbbd422002-08-10 04:31:50 +00001000 const UChar *limit = u + size();
1001 while (u < limit) {
eric@webkit.org87d855b2008-03-10 22:06:44 +00001002 if (u[0] > 0xFF)
kocienda66a6d362001-08-24 14:24:45 +00001003 return false;
darin2dbbd422002-08-10 04:31:50 +00001004 ++u;
1005 }
kocienda66a6d362001-08-24 14:24:45 +00001006
1007 return true;
1008}
1009
mrowe@apple.com59de0d02008-04-19 01:31:29 +00001010UChar UString::operator[](int pos) const
kocienda66a6d362001-08-24 14:24:45 +00001011{
1012 if (pos >= size())
darin8aede132003-04-29 18:26:29 +00001013 return '\0';
1014 return data()[pos];
kocienda66a6d362001-08-24 14:24:45 +00001015}
1016
darin0a2c7b82003-12-11 04:55:12 +00001017double UString::toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const
kocienda66a6d362001-08-24 14:24:45 +00001018{
1019 double d;
1020
darin0a2c7b82003-12-11 04:55:12 +00001021 // FIXME: If tolerateTrailingJunk is true, then we want to tolerate non-8-bit junk
darin@apple.com3beb3002008-04-28 05:59:07 +00001022 // after the number, so this is too strict a check.
1023 CStringBuffer s;
1024 if (!getCString(s))
kocienda66a6d362001-08-24 14:24:45 +00001025 return NaN;
darin@apple.com3beb3002008-04-28 05:59:07 +00001026 const char* c = s.data();
kocienda66a6d362001-08-24 14:24:45 +00001027
1028 // skip leading white space
darineb0d86d2007-10-16 20:13:24 +00001029 while (isASCIISpace(*c))
kocienda66a6d362001-08-24 14:24:45 +00001030 c++;
1031
1032 // empty string ?
1033 if (*c == '\0')
darin0a2c7b82003-12-11 04:55:12 +00001034 return tolerateEmptyString ? 0.0 : NaN;
kocienda66a6d362001-08-24 14:24:45 +00001035
1036 // hex number ?
1037 if (*c == '0' && (*(c+1) == 'x' || *(c+1) == 'X')) {
darin5769f312007-07-18 02:25:38 +00001038 const char* firstDigitPosition = c + 2;
kocienda66a6d362001-08-24 14:24:45 +00001039 c++;
1040 d = 0.0;
1041 while (*(++c)) {
1042 if (*c >= '0' && *c <= '9')
darinae58eff2006-07-30 00:04:22 +00001043 d = d * 16.0 + *c - '0';
kocienda66a6d362001-08-24 14:24:45 +00001044 else if ((*c >= 'A' && *c <= 'F') || (*c >= 'a' && *c <= 'f'))
darinae58eff2006-07-30 00:04:22 +00001045 d = d * 16.0 + (*c & 0xdf) - 'A' + 10.0;
kocienda66a6d362001-08-24 14:24:45 +00001046 else
darinae58eff2006-07-30 00:04:22 +00001047 break;
kocienda66a6d362001-08-24 14:24:45 +00001048 }
darin5769f312007-07-18 02:25:38 +00001049
1050 if (d >= mantissaOverflowLowerBound)
1051 d = parseIntOverflow(firstDigitPosition, c - firstDigitPosition, 16);
kocienda66a6d362001-08-24 14:24:45 +00001052 } else {
1053 // regular number ?
1054 char *end;
weinig@apple.com843df6f32008-04-16 18:41:54 +00001055 d = strtod(c, &end);
darin5769f312007-07-18 02:25:38 +00001056 if ((d != 0.0 || end != c) && d != Inf && d != -Inf) {
kocienda66a6d362001-08-24 14:24:45 +00001057 c = end;
1058 } else {
darin5769f312007-07-18 02:25:38 +00001059 double sign = 1.0;
1060
kocienda66a6d362001-08-24 14:24:45 +00001061 if (*c == '+')
darinae58eff2006-07-30 00:04:22 +00001062 c++;
kocienda66a6d362001-08-24 14:24:45 +00001063 else if (*c == '-') {
darin5769f312007-07-18 02:25:38 +00001064 sign = -1.0;
darinae58eff2006-07-30 00:04:22 +00001065 c++;
kocienda66a6d362001-08-24 14:24:45 +00001066 }
darin5769f312007-07-18 02:25:38 +00001067
1068 // We used strtod() to do the conversion. However, strtod() handles
1069 // infinite values slightly differently than JavaScript in that it
1070 // converts the string "inf" with any capitalization to infinity,
1071 // whereas the ECMA spec requires that it be converted to NaN.
1072
ggaren@apple.com2cffc2c2007-11-13 08:05:03 +00001073 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') {
darin5769f312007-07-18 02:25:38 +00001074 d = sign * Inf;
1075 c += 8;
1076 } else if ((d == Inf || d == -Inf) && *c != 'I' && *c != 'i')
1077 c = end;
1078 else
darinae58eff2006-07-30 00:04:22 +00001079 return NaN;
kocienda66a6d362001-08-24 14:24:45 +00001080 }
1081 }
1082
1083 // allow trailing white space
darineb0d86d2007-10-16 20:13:24 +00001084 while (isASCIISpace(*c))
kocienda66a6d362001-08-24 14:24:45 +00001085 c++;
mjs6f821c82002-03-22 00:31:57 +00001086 // don't allow anything after - unless tolerant=true
darin0a2c7b82003-12-11 04:55:12 +00001087 if (!tolerateTrailingJunk && *c != '\0')
kocienda66a6d362001-08-24 14:24:45 +00001088 d = NaN;
1089
1090 return d;
1091}
1092
darin0a2c7b82003-12-11 04:55:12 +00001093double UString::toDouble(bool tolerateTrailingJunk) const
kocienda66a6d362001-08-24 14:24:45 +00001094{
darin0a2c7b82003-12-11 04:55:12 +00001095 return toDouble(tolerateTrailingJunk, true);
1096}
1097
1098double UString::toDouble() const
1099{
1100 return toDouble(false, true);
1101}
1102
adele704e8bb2005-09-16 22:42:30 +00001103uint32_t UString::toUInt32(bool *ok) const
darin0a2c7b82003-12-11 04:55:12 +00001104{
adele704e8bb2005-09-16 22:42:30 +00001105 double d = toDouble();
kocienda66a6d362001-08-24 14:24:45 +00001106 bool b = true;
1107
ggarenf52a5ed2005-10-06 01:13:18 +00001108 if (d != static_cast<uint32_t>(d)) {
kocienda66a6d362001-08-24 14:24:45 +00001109 b = false;
1110 d = 0;
1111 }
1112
1113 if (ok)
1114 *ok = b;
1115
adele704e8bb2005-09-16 22:42:30 +00001116 return static_cast<uint32_t>(d);
kocienda66a6d362001-08-24 14:24:45 +00001117}
1118
adele704e8bb2005-09-16 22:42:30 +00001119uint32_t UString::toUInt32(bool *ok, bool tolerateEmptyString) const
darin0a2c7b82003-12-11 04:55:12 +00001120{
adele704e8bb2005-09-16 22:42:30 +00001121 double d = toDouble(false, tolerateEmptyString);
mjs1a9f1132002-11-24 07:49:26 +00001122 bool b = true;
1123
ggarenf52a5ed2005-10-06 01:13:18 +00001124 if (d != static_cast<uint32_t>(d)) {
mjs1a9f1132002-11-24 07:49:26 +00001125 b = false;
1126 d = 0;
1127 }
1128
1129 if (ok)
1130 *ok = b;
1131
1132 return static_cast<uint32_t>(d);
1133}
1134
darin7fdc25c2003-07-12 16:01:36 +00001135uint32_t UString::toStrictUInt32(bool *ok) const
1136{
1137 if (ok)
1138 *ok = false;
1139
1140 // Empty string is not OK.
mjs97e2b182005-12-06 09:21:15 +00001141 int len = m_rep->len;
darin7fdc25c2003-07-12 16:01:36 +00001142 if (len == 0)
1143 return 0;
mjs97e2b182005-12-06 09:21:15 +00001144 const UChar *p = m_rep->data();
eric@webkit.org87d855b2008-03-10 22:06:44 +00001145 unsigned short c = p[0];
darin7fdc25c2003-07-12 16:01:36 +00001146
1147 // If the first digit is 0, only 0 itself is OK.
1148 if (c == '0') {
1149 if (len == 1 && ok)
1150 *ok = true;
1151 return 0;
1152 }
1153
1154 // Convert to UInt32, checking for overflow.
1155 uint32_t i = 0;
1156 while (1) {
1157 // Process character, turning it into a digit.
1158 if (c < '0' || c > '9')
1159 return 0;
1160 const unsigned d = c - '0';
1161
darin08e4b212003-07-13 21:40:45 +00001162 // Multiply by 10, checking for overflow out of 32 bits.
1163 if (i > 0xFFFFFFFFU / 10)
darin7fdc25c2003-07-12 16:01:36 +00001164 return 0;
darin7fdc25c2003-07-12 16:01:36 +00001165 i *= 10;
darin08e4b212003-07-13 21:40:45 +00001166
1167 // Add in the digit, checking for overflow out of 32 bits.
1168 const unsigned max = 0xFFFFFFFFU - d;
1169 if (i > max)
1170 return 0;
darin7fdc25c2003-07-12 16:01:36 +00001171 i += d;
1172
1173 // Handle end of string.
1174 if (--len == 0) {
1175 if (ok)
1176 *ok = true;
1177 return i;
1178 }
1179
1180 // Get next character.
eric@webkit.org87d855b2008-03-10 22:06:44 +00001181 c = *(++p);
darin7fdc25c2003-07-12 16:01:36 +00001182 }
1183}
1184
kocienda66a6d362001-08-24 14:24:45 +00001185int UString::find(const UString &f, int pos) const
1186{
darinfe985882002-08-21 05:23:31 +00001187 int sz = size();
1188 int fsz = f.size();
1189 if (sz < fsz)
kocienda66a6d362001-08-24 14:24:45 +00001190 return -1;
kocienda66a6d362001-08-24 14:24:45 +00001191 if (pos < 0)
1192 pos = 0;
darinc2ded482002-10-11 04:07:07 +00001193 if (fsz == 0)
1194 return pos;
darinfe985882002-08-21 05:23:31 +00001195 const UChar *end = data() + sz - fsz;
adele704e8bb2005-09-16 22:42:30 +00001196 int fsizeminusone = (fsz - 1) * sizeof(UChar);
darinfe985882002-08-21 05:23:31 +00001197 const UChar *fdata = f.data();
eric@webkit.org87d855b2008-03-10 22:06:44 +00001198 unsigned short fchar = fdata[0];
darin140be372005-04-20 10:14:35 +00001199 ++fdata;
kocienda66a6d362001-08-24 14:24:45 +00001200 for (const UChar *c = data() + pos; c <= end; c++)
eric@webkit.org87d855b2008-03-10 22:06:44 +00001201 if (c[0] == fchar && !memcmp(c + 1, fdata, fsizeminusone))
darinb847b442006-10-27 16:48:28 +00001202 return static_cast<int>(c - data());
darin07f7cce2002-08-12 20:14:02 +00001203
1204 return -1;
1205}
1206
1207int UString::find(UChar ch, int pos) const
1208{
1209 if (pos < 0)
1210 pos = 0;
1211 const UChar *end = data() + size();
1212 for (const UChar *c = data() + pos; c < end; c++)
1213 if (*c == ch)
darinb847b442006-10-27 16:48:28 +00001214 return static_cast<int>(c - data());
kocienda66a6d362001-08-24 14:24:45 +00001215
1216 return -1;
1217}
1218
1219int UString::rfind(const UString &f, int pos) const
1220{
darinfe985882002-08-21 05:23:31 +00001221 int sz = size();
1222 int fsz = f.size();
1223 if (sz < fsz)
kocienda66a6d362001-08-24 14:24:45 +00001224 return -1;
darinfe985882002-08-21 05:23:31 +00001225 if (pos < 0)
1226 pos = 0;
darinc2ded482002-10-11 04:07:07 +00001227 if (pos > sz - fsz)
1228 pos = sz - fsz;
1229 if (fsz == 0)
1230 return pos;
adele704e8bb2005-09-16 22:42:30 +00001231 int fsizeminusone = (fsz - 1) * sizeof(UChar);
darinfe985882002-08-21 05:23:31 +00001232 const UChar *fdata = f.data();
kocienda66a6d362001-08-24 14:24:45 +00001233 for (const UChar *c = data() + pos; c >= data(); c--) {
darinfe985882002-08-21 05:23:31 +00001234 if (*c == *fdata && !memcmp(c + 1, fdata + 1, fsizeminusone))
darinb847b442006-10-27 16:48:28 +00001235 return static_cast<int>(c - data());
darin07f7cce2002-08-12 20:14:02 +00001236 }
1237
1238 return -1;
1239}
1240
1241int UString::rfind(UChar ch, int pos) const
1242{
1243 if (isEmpty())
1244 return -1;
1245 if (pos + 1 >= size())
1246 pos = size() - 1;
1247 for (const UChar *c = data() + pos; c >= data(); c--) {
1248 if (*c == ch)
darinb847b442006-10-27 16:48:28 +00001249 return static_cast<int>(c-data());
kocienda66a6d362001-08-24 14:24:45 +00001250 }
1251
1252 return -1;
1253}
1254
1255UString UString::substr(int pos, int len) const
1256{
darinbceb27f2004-08-12 17:21:29 +00001257 int s = size();
1258
kocienda66a6d362001-08-24 14:24:45 +00001259 if (pos < 0)
1260 pos = 0;
darinbceb27f2004-08-12 17:21:29 +00001261 else if (pos >= s)
1262 pos = s;
kocienda66a6d362001-08-24 14:24:45 +00001263 if (len < 0)
darinbceb27f2004-08-12 17:21:29 +00001264 len = s;
1265 if (pos + len >= s)
1266 len = s - pos;
1267
1268 if (pos == 0 && len == s)
1269 return *this;
kocienda66a6d362001-08-24 14:24:45 +00001270
mjs1aec3582005-12-25 09:22:35 +00001271 return UString(Rep::create(m_rep, pos, len));
kocienda66a6d362001-08-24 14:24:45 +00001272}
1273
darin04b93fa2005-05-16 18:57:29 +00001274bool operator==(const UString& s1, const UString& s2)
kocienda66a6d362001-08-24 14:24:45 +00001275{
mjs97e2b182005-12-06 09:21:15 +00001276 if (s1.m_rep->len != s2.m_rep->len)
kocienda66a6d362001-08-24 14:24:45 +00001277 return false;
1278
mjs97e2b182005-12-06 09:21:15 +00001279 return (memcmp(s1.m_rep->data(), s2.m_rep->data(),
darinae58eff2006-07-30 00:04:22 +00001280 s1.m_rep->len * sizeof(UChar)) == 0);
kocienda66a6d362001-08-24 14:24:45 +00001281}
1282
darin04b93fa2005-05-16 18:57:29 +00001283bool operator==(const UString& s1, const char *s2)
kocienda66a6d362001-08-24 14:24:45 +00001284{
darin07f7cce2002-08-12 20:14:02 +00001285 if (s2 == 0) {
1286 return s1.isEmpty();
1287 }
kocienda66a6d362001-08-24 14:24:45 +00001288
kocienda66a6d362001-08-24 14:24:45 +00001289 const UChar *u = s1.data();
darinfe985882002-08-21 05:23:31 +00001290 const UChar *uend = u + s1.size();
1291 while (u != uend && *s2) {
eric@webkit.org87d855b2008-03-10 22:06:44 +00001292 if (u[0] != (unsigned char)*s2)
kocienda66a6d362001-08-24 14:24:45 +00001293 return false;
1294 s2++;
1295 u++;
1296 }
1297
darinfe985882002-08-21 05:23:31 +00001298 return u == uend && *s2 == 0;
kocienda66a6d362001-08-24 14:24:45 +00001299}
1300
darin04b93fa2005-05-16 18:57:29 +00001301bool operator<(const UString& s1, const UString& s2)
kocienda66a6d362001-08-24 14:24:45 +00001302{
darinb70665a2002-04-15 23:43:21 +00001303 const int l1 = s1.size();
1304 const int l2 = s2.size();
1305 const int lmin = l1 < l2 ? l1 : l2;
kocienda66a6d362001-08-24 14:24:45 +00001306 const UChar *c1 = s1.data();
1307 const UChar *c2 = s2.data();
1308 int l = 0;
darinb70665a2002-04-15 23:43:21 +00001309 while (l < lmin && *c1 == *c2) {
kocienda66a6d362001-08-24 14:24:45 +00001310 c1++;
1311 c2++;
1312 l++;
1313 }
darinb70665a2002-04-15 23:43:21 +00001314 if (l < lmin)
eric@webkit.org87d855b2008-03-10 22:06:44 +00001315 return (c1[0] < c2[0]);
kocienda66a6d362001-08-24 14:24:45 +00001316
darinb70665a2002-04-15 23:43:21 +00001317 return (l1 < l2);
kocienda66a6d362001-08-24 14:24:45 +00001318}
darin401641e2002-11-18 21:55:23 +00001319
kmccullough@apple.comc74bed12008-05-20 20:59:16 +00001320bool operator>(const UString& s1, const UString& s2)
1321{
1322 const int l1 = s1.size();
1323 const int l2 = s2.size();
1324 const int lmin = l1 < l2 ? l1 : l2;
1325 const UChar *c1 = s1.data();
1326 const UChar *c2 = s2.data();
1327 int l = 0;
1328 while (l < lmin && *c1 == *c2) {
1329 c1++;
1330 c2++;
1331 l++;
1332 }
1333 if (l < lmin)
1334 return (c1[0] > c2[0]);
1335
1336 return (l1 > l2);
1337}
1338
darin04b93fa2005-05-16 18:57:29 +00001339int compare(const UString& s1, const UString& s2)
darin401641e2002-11-18 21:55:23 +00001340{
1341 const int l1 = s1.size();
1342 const int l2 = s2.size();
1343 const int lmin = l1 < l2 ? l1 : l2;
1344 const UChar *c1 = s1.data();
1345 const UChar *c2 = s2.data();
1346 int l = 0;
1347 while (l < lmin && *c1 == *c2) {
1348 c1++;
1349 c2++;
1350 l++;
1351 }
ggaren39a1c9a2006-03-15 01:09:15 +00001352
darin401641e2002-11-18 21:55:23 +00001353 if (l < lmin)
eric@webkit.org87d855b2008-03-10 22:06:44 +00001354 return (c1[0] > c2[0]) ? 1 : -1;
darin401641e2002-11-18 21:55:23 +00001355
ggaren39a1c9a2006-03-15 01:09:15 +00001356 if (l1 == l2)
darin401641e2002-11-18 21:55:23 +00001357 return 0;
ggaren39a1c9a2006-03-15 01:09:15 +00001358
1359 return (l1 > l2) ? 1 : -1;
darin401641e2002-11-18 21:55:23 +00001360}
darin6c9bbfd2003-08-18 18:51:25 +00001361
ap@webkit.orgfaaccdb2008-06-04 18:10:15 +00001362bool equal(const UString::Rep* r, const UString::Rep* b)
1363{
1364 int length = r->len;
1365 if (length != b->len)
1366 return false;
1367 const UChar* d = r->data();
1368 const UChar* s = b->data();
1369 for (int i = 0; i != length; ++i)
1370 if (d[i] != s[i])
1371 return false;
1372 return true;
1373}
1374
ap@webkit.orgf263e7d2007-11-13 07:12:55 +00001375CString UString::UTF8String(bool strict) const
darin6c9bbfd2003-08-18 18:51:25 +00001376{
darin6c9bbfd2003-08-18 18:51:25 +00001377 // Allocate a buffer big enough to hold all the characters.
1378 const int length = size();
mjsa09640f2006-01-29 04:12:59 +00001379 Vector<char, 1024> buffer(length * 3);
darin6c9bbfd2003-08-18 18:51:25 +00001380
1381 // Convert to runs of 8-bit characters.
ap@webkit.orgf263e7d2007-11-13 07:12:55 +00001382 char* p = buffer.data();
eric@webkit.org87d855b2008-03-10 22:06:44 +00001383 const UChar* d = reinterpret_cast<const UChar*>(&data()[0]);
ap@webkit.orgd3895dc2007-11-15 05:59:40 +00001384 ConversionResult result = convertUTF16ToUTF8(&d, d + length, &p, p + buffer.size(), strict);
ap@webkit.orgf263e7d2007-11-13 07:12:55 +00001385 if (result != conversionOK)
1386 return CString();
darin6c9bbfd2003-08-18 18:51:25 +00001387
ap@webkit.orgf263e7d2007-11-13 07:12:55 +00001388 return CString(buffer.data(), p - buffer.data());
darin@apple.com11f3b272007-11-03 16:40:32 +00001389}
1390
darin6c9bbfd2003-08-18 18:51:25 +00001391} // namespace KJS