2006-08-31 Anders Carlsson <acarlsson@apple.com>
[WebKit-https.git] / WebCore / platform / String.cpp
1 /**
2  * This file is part of the DOM implementation for KDE.
3  *
4  * (C) 1999 Lars Knoll (knoll@kde.org)
5  * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
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., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include "config.h"
24 #include "PlatformString.h"
25
26 #include "CString.h"
27 #include "DeprecatedString.h"
28 #include "TextEncoding.h"
29 #include <kjs/identifier.h>
30 #include <wtf/Vector.h>
31 #include <stdarg.h>
32
33 using KJS::Identifier;
34 using KJS::UString;
35
36 namespace WebCore {
37
38 String::String(const UChar* str, unsigned len)
39 {
40     if (!str)
41         return;
42     
43     if (len == 0)
44         m_impl = StringImpl::empty();
45     else
46         m_impl = new StringImpl(str, len);
47 }
48
49 String::String(const UChar* str)
50 {
51     if (!str)
52         return;
53         
54     int len = 0;
55     while (str[len] != UChar(0))
56         len++;
57     
58     if (len == 0)
59         m_impl = StringImpl::empty();
60     else
61         m_impl = new StringImpl(str, len);
62 }
63
64 String::String(const DeprecatedString& str)
65 {
66     if (str.isNull())
67         return;
68     
69     if (str.isEmpty())
70         m_impl = StringImpl::empty();
71     else 
72         m_impl = new StringImpl(reinterpret_cast<const UChar*>(str.unicode()), str.length());
73 }
74
75 String::String(const char* str)
76 {
77     if (!str)
78         return;
79
80     int l = strlen(str);
81     if (l == 0)
82         m_impl = StringImpl::empty();
83     else
84         m_impl = new StringImpl(str, l);
85 }
86
87 String::String(const char* str, unsigned length)
88 {
89     if (!str)
90         return;
91
92     if (length == 0)
93         m_impl = StringImpl::empty();
94     else
95         m_impl = new StringImpl(str, length);
96 }
97
98 void String::append(const String &str)
99 {
100     if (str.m_impl) {
101         if (!m_impl) {
102             // ### FIXME!!!
103             m_impl = str.m_impl;
104             return;
105         }
106         m_impl = m_impl->copy();
107         m_impl->append(str.m_impl.get());
108     }
109 }
110
111 void String::append(char c)
112 {
113     if (!m_impl)
114         m_impl = new StringImpl(&c, 1);
115     else {
116         m_impl = m_impl->copy();
117         m_impl->append(c);
118     }
119 }
120
121 void String::append(UChar c)
122 {
123     if (!m_impl)
124         m_impl = new StringImpl(&c, 1);
125     else {
126         m_impl = m_impl->copy();
127         m_impl->append(c);
128     }
129 }
130
131 String operator+(const String& a, const String& b)
132 {
133     if (a.isEmpty())
134         return b.copy();
135     if (b.isEmpty())
136         return a.copy();
137     String c = a.copy();
138     c += b;
139     return c;
140 }
141
142 String operator+(const String& s, const char* cs)
143 {
144     return s + String(cs);
145 }
146
147 String operator+(const char* cs, const String& s)
148 {
149     return String(cs) + s;
150 }
151
152 void String::insert(const String& str, unsigned pos)
153 {
154     if (!m_impl)
155         m_impl = str.m_impl->copy();
156     else
157         m_impl->insert(str.m_impl.get(), pos);
158 }
159
160 UChar String::operator[](unsigned i) const
161 {
162     if (!m_impl || i >= m_impl->length())
163         return 0;
164     return m_impl->characters()[i];
165 }
166
167 unsigned String::length() const
168 {
169     if (!m_impl)
170         return 0;
171     return m_impl->length();
172 }
173
174 void String::truncate(unsigned len)
175 {
176     if (m_impl)
177         m_impl->truncate(len);
178 }
179
180 void String::remove(unsigned pos, int len)
181 {
182     if (m_impl)
183         m_impl->remove(pos, len);
184 }
185
186 String String::substring(unsigned pos, unsigned len) const
187 {
188     if (!m_impl) 
189         return String();
190     return m_impl->substring(pos, len);
191 }
192
193 String String::split(unsigned pos)
194 {
195     if (!m_impl)
196         return String();
197     return m_impl->split(pos);
198 }
199
200 String String::lower() const
201 {
202     if (!m_impl)
203         return String();
204     return m_impl->lower();
205 }
206
207 String String::upper() const
208 {
209     if (!m_impl)
210         return String();
211     return m_impl->upper();
212 }
213
214 String String::foldCase() const
215 {
216     if (!m_impl)
217         return String();
218     return m_impl->foldCase();
219 }
220
221 bool String::percentage(int& result) const
222 {
223     if (!m_impl || !m_impl->length())
224         return false;
225
226     if ((*m_impl)[m_impl->length() - 1] != '%')
227        return false;
228
229     result = DeprecatedConstString(reinterpret_cast<const DeprecatedChar*>(m_impl->characters()), m_impl->length() - 1).string().toInt();
230     return true;
231 }
232
233 const UChar* String::characters() const
234 {
235     if (!m_impl)
236         return 0;
237     return m_impl->characters();
238 }
239
240 const UChar* String::charactersWithNullTermination()
241 {
242     if (!m_impl)
243         return 0;
244     return m_impl->charactersWithNullTermination();
245 }
246
247 DeprecatedString String::deprecatedString() const
248 {
249     if (!m_impl)
250         return DeprecatedString::null;
251     if (!m_impl->characters())
252         return DeprecatedString("", 0);
253     return DeprecatedString(reinterpret_cast<const DeprecatedChar*>(m_impl->characters()), m_impl->length());
254 }
255
256 String String::sprintf(const char *format, ...)
257 {
258     va_list args;
259     va_start(args, format);
260
261     Vector<char, 256> buffer;
262 #if PLATFORM(WIN_OS)
263     // Windows vsnprintf does not return the expected size on overflow
264     // So we just have to keep looping until our vsprintf call works!
265     int result = 0;
266     do {
267         if (result < 0)
268             buffer.resize(buffer.capacity() * 2);
269         result = vsnprintf(buffer.data(), buffer.capacity(), format, args);
270         // Windows vsnprintf returns -1 for both errors. Since there is no
271         // way to distinguish between "not enough room" and "invalid format"
272         // we just keep trying until we hit an arbitrary size and then stop.
273     } while (result < 0 && (buffer.capacity() * 2) < 2048);
274     if (result == 0)
275         return String("");
276     else if (result < 0)
277         return String();
278     unsigned len = result;
279 #else
280     // Do the format once to get the length.
281     char ch;
282     int result = vsnprintf(&ch, 1, format, args);
283     if (result == 0)
284         return String("");
285     else if (result < 0)
286         return String();
287     unsigned len = result;
288     buffer.resize(len + 1);
289     
290     // Now do the formatting again, guaranteed to fit.
291     vsnprintf(buffer.data(), buffer.size(), format, args);
292 #endif
293     va_end(args);
294     
295     return new StringImpl(buffer.data(), len);
296 }
297
298 String String::number(int n)
299 {
300     return String::sprintf("%d", n);
301 }
302
303 String String::number(unsigned n)
304 {
305     return String::sprintf("%u", n);
306 }
307
308 String String::number(long n)
309 {
310     return String::sprintf("%ld", n);
311 }
312
313 String String::number(unsigned long n)
314 {
315     return String::sprintf("%lu", n);
316 }
317
318 String String::number(long long n)
319 {
320 #if PLATFORM(WIN_OS)
321     return String::sprintf("%I64i", n);
322 #else
323     return String::sprintf("%lli", n);
324 #endif
325 }
326
327 String String::number(unsigned long long n)
328 {
329 #if PLATFORM(WIN_OS)
330     return String::sprintf("%I64u", n);
331 #else
332     return String::sprintf("%llu", n);
333 #endif
334 }
335     
336 String String::number(double n)
337 {
338     return String::sprintf("%.6lg", n);
339 }
340
341 int String::toInt(bool* ok) const
342 {
343     if (!m_impl) {
344         if (ok)
345             *ok = false;
346         return 0;
347     }
348     return m_impl->toInt(ok);
349 }
350
351 String String::copy() const
352 {
353     if (!m_impl)
354         return String();
355     return m_impl->copy();
356 }
357
358 bool String::isEmpty() const
359 {
360     return !m_impl || !m_impl->length();
361 }
362
363 Length* String::toCoordsArray(int& len) const 
364 {
365     return m_impl ? m_impl->toCoordsArray(len) : 0;
366 }
367
368 Length* String::toLengthArray(int& len) const 
369 {
370     return m_impl ? m_impl->toLengthArray(len) : 0;
371 }
372
373 #ifndef NDEBUG
374 Vector<char> String::ascii() const
375 {
376     if (m_impl) 
377         return m_impl->ascii();
378     
379     const char* nullMsg = "(null impl)";
380     Vector<char> buffer(strlen(nullMsg) + 1);
381     for (int i = 0; nullMsg[i]; ++i) {
382         buffer.append(nullMsg[i]);
383     }
384     buffer.append('\0');
385     return buffer;
386 }
387 #endif
388
389 CString String::latin1() const
390 {
391     return TextEncoding(Latin1Encoding).fromUnicode(deprecatedString());
392 }
393     
394 CString String::utf8() const
395 {
396     return TextEncoding(UTF8Encoding).fromUnicode(deprecatedString());
397 }
398
399 bool operator==(const String& a, const DeprecatedString& b)
400 {
401     unsigned l = a.length();
402     if (l != b.length())
403         return false;
404     if (!memcmp(a.characters(), b.unicode(), l * sizeof(UChar)))
405         return true;
406     return false;
407 }
408
409 String::String(const Identifier& str)
410 {
411     if (str.isNull())
412         return;
413     
414     if (str.isEmpty())
415         m_impl = StringImpl::empty();
416     else 
417         m_impl = new StringImpl(reinterpret_cast<const UChar*>(str.data()), str.size());
418 }
419
420 String::String(const UString& str)
421 {
422     if (str.isNull())
423         return;
424     
425     if (str.isEmpty())
426         m_impl = StringImpl::empty();
427     else 
428         m_impl = new StringImpl(reinterpret_cast<const UChar*>(str.data()), str.size());
429 }
430
431 String::operator Identifier() const
432 {
433     if (!m_impl)
434         return Identifier();
435     return Identifier(reinterpret_cast<const KJS::UChar*>(m_impl->characters()), m_impl->length());
436 }
437
438 String::operator UString() const
439 {
440     if (!m_impl)
441         return UString();
442     return UString(reinterpret_cast<const KJS::UChar*>(m_impl->characters()), m_impl->length());
443 }
444
445 } // namespace WebCore
446
447 #ifndef NDEBUG
448 // For debugging only -- leaks memory
449 WebCore::String* string(const char* s)
450 {
451     return new WebCore::String(s);
452 }
453 #endif