https://bugs.webkit.org/show_bug.cgi?id=16777
[WebKit-https.git] / Source / JavaScriptCore / runtime / UString.cpp
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 "Heap.h"
29 #include "Identifier.h"
30 #include "Operations.h"
31 #include <ctype.h>
32 #include <limits.h>
33 #include <limits>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <wtf/ASCIICType.h>
37 #include <wtf/Assertions.h>
38 #include <wtf/DecimalNumber.h>
39 #include <wtf/MathExtras.h>
40 #include <wtf/StringExtras.h>
41 #include <wtf/Vector.h>
42 #include <wtf/unicode/UTF8.h>
43
44 #if HAVE(STRINGS_H)
45 #include <strings.h>
46 #endif
47
48 using namespace WTF;
49 using namespace WTF::Unicode;
50 using namespace std;
51
52 namespace JSC {
53
54 COMPILE_ASSERT(sizeof(UString) == sizeof(void*), UString_should_stay_small);
55
56 // Construct a string with UTF-16 data.
57 UString::UString(const UChar* characters, unsigned length)
58     : m_impl(characters ? StringImpl::create(characters, length) : 0)
59 {
60 }
61
62 // Construct a string with UTF-16 data, from a null-terminated source.
63 UString::UString(const UChar* characters)
64 {
65     if (!characters)
66         return;
67
68     int length = 0;
69     while (characters[length] != UChar(0))
70         ++length;
71
72     m_impl = StringImpl::create(characters, length);
73 }
74
75 // Construct a string with latin1 data.
76 UString::UString(const char* characters, unsigned length)
77     : m_impl(characters ? StringImpl::create(characters, length) : 0)
78 {
79 }
80
81 // Construct a string with latin1 data, from a null-terminated source.
82 UString::UString(const char* characters)
83     : m_impl(characters ? StringImpl::create(characters) : 0)
84 {
85 }
86
87 UString UString::number(int i)
88 {
89     UChar buf[1 + sizeof(i) * 3];
90     UChar* end = buf + WTF_ARRAY_LENGTH(buf);
91     UChar* p = end;
92
93     if (i == 0)
94         *--p = '0';
95     else if (i == INT_MIN) {
96         char minBuf[1 + sizeof(i) * 3];
97         snprintf(minBuf, sizeof(minBuf), "%d", INT_MIN);
98         return UString(minBuf);
99     } else {
100         bool negative = false;
101         if (i < 0) {
102             negative = true;
103             i = -i;
104         }
105         while (i) {
106             *--p = static_cast<unsigned short>((i % 10) + '0');
107             i /= 10;
108         }
109         if (negative)
110             *--p = '-';
111     }
112
113     return UString(p, static_cast<unsigned>(end - p));
114 }
115
116 UString UString::number(long long i)
117 {
118     UChar buf[1 + sizeof(i) * 3];
119     UChar* end = buf + WTF_ARRAY_LENGTH(buf);
120     UChar* p = end;
121
122     if (i == 0)
123         *--p = '0';
124     else if (i == std::numeric_limits<long long>::min()) {
125         char minBuf[1 + sizeof(i) * 3];
126 #if OS(WINDOWS)
127         snprintf(minBuf, sizeof(minBuf), "%I64d", std::numeric_limits<long long>::min());
128 #else
129         snprintf(minBuf, sizeof(minBuf), "%lld", std::numeric_limits<long long>::min());
130 #endif
131         return UString(minBuf);
132     } else {
133         bool negative = false;
134         if (i < 0) {
135             negative = true;
136             i = -i;
137         }
138         while (i) {
139             *--p = static_cast<unsigned short>((i % 10) + '0');
140             i /= 10;
141         }
142         if (negative)
143             *--p = '-';
144     }
145
146     return UString(p, static_cast<unsigned>(end - p));
147 }
148
149 UString UString::number(unsigned u)
150 {
151     UChar buf[sizeof(u) * 3];
152     UChar* end = buf + WTF_ARRAY_LENGTH(buf);
153     UChar* p = end;
154
155     if (u == 0)
156         *--p = '0';
157     else {
158         while (u) {
159             *--p = static_cast<unsigned short>((u % 10) + '0');
160             u /= 10;
161         }
162     }
163
164     return UString(p, static_cast<unsigned>(end - p));
165 }
166
167 UString UString::number(long l)
168 {
169     UChar buf[1 + sizeof(l) * 3];
170     UChar* end = buf + WTF_ARRAY_LENGTH(buf);
171     UChar* p = end;
172
173     if (l == 0)
174         *--p = '0';
175     else if (l == LONG_MIN) {
176         char minBuf[1 + sizeof(l) * 3];
177         snprintf(minBuf, sizeof(minBuf), "%ld", LONG_MIN);
178         return UString(minBuf);
179     } else {
180         bool negative = false;
181         if (l < 0) {
182             negative = true;
183             l = -l;
184         }
185         while (l) {
186             *--p = static_cast<unsigned short>((l % 10) + '0');
187             l /= 10;
188         }
189         if (negative)
190             *--p = '-';
191     }
192
193     return UString(p, end - p);
194 }
195
196 UString UString::number(double d)
197 {
198     NumberToStringBuffer buffer;
199     unsigned length = numberToString(d, buffer);
200     return UString(buffer, length);
201 }
202
203 UString UString::substringSharingImpl(unsigned offset, unsigned length) const
204 {
205     // FIXME: We used to check against a limit of Heap::minExtraCost / sizeof(UChar).
206
207     unsigned stringLength = this->length();
208     offset = min(offset, stringLength);
209     length = min(length, stringLength - offset);
210
211     if (!offset && length == stringLength)
212         return *this;
213     return UString(StringImpl::create(m_impl, offset, length));
214 }
215
216 bool operator==(const UString& s1, const char *s2)
217 {
218     if (s2 == 0)
219         return s1.isEmpty();
220
221     const UChar* u = s1.characters();
222     const UChar* uend = u + s1.length();
223     while (u != uend && *s2) {
224         if (u[0] != (unsigned char)*s2)
225             return false;
226         s2++;
227         u++;
228     }
229
230     return u == uend && *s2 == 0;
231 }
232
233 bool operator<(const UString& s1, const UString& s2)
234 {
235     const unsigned l1 = s1.length();
236     const unsigned l2 = s2.length();
237     const unsigned lmin = l1 < l2 ? l1 : l2;
238     const UChar* c1 = s1.characters();
239     const UChar* c2 = s2.characters();
240     unsigned l = 0;
241     while (l < lmin && *c1 == *c2) {
242         c1++;
243         c2++;
244         l++;
245     }
246     if (l < lmin)
247         return (c1[0] < c2[0]);
248
249     return (l1 < l2);
250 }
251
252 bool operator>(const UString& s1, const UString& s2)
253 {
254     const unsigned l1 = s1.length();
255     const unsigned l2 = s2.length();
256     const unsigned lmin = l1 < l2 ? l1 : l2;
257     const UChar* c1 = s1.characters();
258     const UChar* c2 = s2.characters();
259     unsigned l = 0;
260     while (l < lmin && *c1 == *c2) {
261         c1++;
262         c2++;
263         l++;
264     }
265     if (l < lmin)
266         return (c1[0] > c2[0]);
267
268     return (l1 > l2);
269 }
270
271 CString UString::ascii() const
272 {
273     // Basic Latin1 (ISO) encoding - Unicode characters 0..255 are
274     // preserved, characters outside of this range are converted to '?'.
275
276     unsigned length = this->length();
277     const UChar* characters = this->characters();
278
279     char* characterBuffer;
280     CString result = CString::newUninitialized(length, characterBuffer);
281
282     for (unsigned i = 0; i < length; ++i) {
283         UChar ch = characters[i];
284         characterBuffer[i] = ch && (ch < 0x20 || ch >= 0x7f) ? '?' : ch;
285     }
286
287     return result;
288 }
289
290 CString UString::latin1() const
291 {
292     // Basic Latin1 (ISO) encoding - Unicode characters 0..255 are
293     // preserved, characters outside of this range are converted to '?'.
294
295     unsigned length = this->length();
296     const UChar* characters = this->characters();
297
298     char* characterBuffer;
299     CString result = CString::newUninitialized(length, characterBuffer);
300
301     for (unsigned i = 0; i < length; ++i) {
302         UChar ch = characters[i];
303         characterBuffer[i] = ch > 0xff ? '?' : ch;
304     }
305
306     return result;
307 }
308
309 // Helper to write a three-byte UTF-8 code point to the buffer, caller must check room is available.
310 static inline void putUTF8Triple(char*& buffer, UChar ch)
311 {
312     ASSERT(ch >= 0x0800);
313     *buffer++ = static_cast<char>(((ch >> 12) & 0x0F) | 0xE0);
314     *buffer++ = static_cast<char>(((ch >> 6) & 0x3F) | 0x80);
315     *buffer++ = static_cast<char>((ch & 0x3F) | 0x80);
316 }
317
318 CString UString::utf8(bool strict) const
319 {
320     unsigned length = this->length();
321     const UChar* characters = this->characters();
322
323     // Allocate a buffer big enough to hold all the characters
324     // (an individual UTF-16 UChar can only expand to 3 UTF-8 bytes).
325     // Optimization ideas, if we find this function is hot:
326     //  * We could speculatively create a CStringBuffer to contain 'length' 
327     //    characters, and resize if necessary (i.e. if the buffer contains
328     //    non-ascii characters). (Alternatively, scan the buffer first for
329     //    ascii characters, so we know this will be sufficient).
330     //  * We could allocate a CStringBuffer with an appropriate size to
331     //    have a good chance of being able to write the string into the
332     //    buffer without reallocing (say, 1.5 x length).
333     if (length > numeric_limits<unsigned>::max() / 3)
334         return CString();
335     Vector<char, 1024> bufferVector(length * 3);
336
337     char* buffer = bufferVector.data();
338     ConversionResult result = convertUTF16ToUTF8(&characters, characters + length, &buffer, buffer + bufferVector.size(), strict);
339     ASSERT(result != targetExhausted); // (length * 3) should be sufficient for any conversion
340
341     // Only produced from strict conversion.
342     if (result == sourceIllegal)
343         return CString();
344
345     // Check for an unconverted high surrogate.
346     if (result == sourceExhausted) {
347         if (strict)
348             return CString();
349         // This should be one unpaired high surrogate. Treat it the same
350         // was as an unpaired high surrogate would have been handled in
351         // the middle of a string with non-strict conversion - which is
352         // to say, simply encode it to UTF-8.
353         ASSERT((characters + 1) == (this->characters() + length));
354         ASSERT((*characters >= 0xD800) && (*characters <= 0xDBFF));
355         // There should be room left, since one UChar hasn't been converted.
356         ASSERT((buffer + 3) <= (buffer + bufferVector.size()));
357         putUTF8Triple(buffer, *characters);
358     }
359
360     return CString(bufferVector.data(), buffer - bufferVector.data());
361 }
362
363 } // namespace JSC