1/*
2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef StringConcatenate_h
27#define StringConcatenate_h
28
29#include <string.h>
30
31#ifndef WTFString_h
32#include "wtf/text/AtomicString.h"
33#endif
34
35// This macro is helpful for testing how many intermediate Strings are created while evaluating an
36// expression containing operator+.
37#ifndef WTF_STRINGTYPEADAPTER_COPIED_WTF_STRING
38#define WTF_STRINGTYPEADAPTER_COPIED_WTF_STRING() ((void)0)
39#endif
40
41namespace WTF {
42
43template<typename StringType>
44class StringTypeAdapter {
45};
46
47template<>
48class StringTypeAdapter<char> {
49public:
50    StringTypeAdapter<char>(char buffer)
51        : m_buffer(buffer)
52    {
53    }
54
55    unsigned length() { return 1; }
56
57    bool is8Bit() { return true; }
58
59    void writeTo(LChar* destination)
60    {
61        *destination = m_buffer;
62    }
63
64    void writeTo(UChar* destination) { *destination = m_buffer; }
65
66private:
67    unsigned char m_buffer;
68};
69
70template<>
71class StringTypeAdapter<LChar> {
72public:
73    StringTypeAdapter<LChar>(LChar buffer)
74        : m_buffer(buffer)
75    {
76    }
77
78    unsigned length() { return 1; }
79
80    bool is8Bit() { return true; }
81
82    void writeTo(LChar* destination)
83    {
84        *destination = m_buffer;
85    }
86
87    void writeTo(UChar* destination) { *destination = m_buffer; }
88
89private:
90    LChar m_buffer;
91};
92
93template<>
94class StringTypeAdapter<UChar> {
95public:
96    StringTypeAdapter<UChar>(UChar buffer)
97        : m_buffer(buffer)
98    {
99    }
100
101    unsigned length() { return 1; }
102
103    bool is8Bit() { return m_buffer <= 0xff; }
104
105    void writeTo(LChar* destination)
106    {
107        ASSERT(is8Bit());
108        *destination = static_cast<LChar>(m_buffer);
109    }
110
111    void writeTo(UChar* destination) { *destination = m_buffer; }
112
113private:
114    UChar m_buffer;
115};
116
117template<>
118class StringTypeAdapter<char*> {
119public:
120    StringTypeAdapter<char*>(char* buffer)
121        : m_buffer(buffer)
122        , m_length(strlen(buffer))
123    {
124    }
125
126    unsigned length() { return m_length; }
127
128    bool is8Bit() { return true; }
129
130    void writeTo(LChar* destination)
131    {
132        for (unsigned i = 0; i < m_length; ++i)
133            destination[i] = static_cast<LChar>(m_buffer[i]);
134    }
135
136    void writeTo(UChar* destination)
137    {
138        for (unsigned i = 0; i < m_length; ++i) {
139            unsigned char c = m_buffer[i];
140            destination[i] = c;
141        }
142    }
143
144private:
145    const char* m_buffer;
146    unsigned m_length;
147};
148
149template<>
150class StringTypeAdapter<LChar*> {
151public:
152    StringTypeAdapter<LChar*>(LChar* buffer)
153    : m_buffer(buffer)
154    , m_length(strlen(reinterpret_cast<char*>(buffer)))
155    {
156    }
157
158    unsigned length() { return m_length; }
159
160    bool is8Bit() { return true; }
161
162    void writeTo(LChar* destination)
163    {
164        memcpy(destination, m_buffer, m_length * sizeof(LChar));
165    }
166
167    void writeTo(UChar* destination)
168    {
169        StringImpl::copyChars(destination, m_buffer, m_length);
170    }
171
172private:
173    const LChar* m_buffer;
174    unsigned m_length;
175};
176
177template<>
178class StringTypeAdapter<const UChar*> {
179public:
180    StringTypeAdapter<const UChar*>(const UChar* buffer)
181        : m_buffer(buffer)
182    {
183        size_t len = 0;
184        while (m_buffer[len] != UChar(0))
185            ++len;
186
187        RELEASE_ASSERT(len <= std::numeric_limits<unsigned>::max());
188
189        m_length = len;
190    }
191
192    unsigned length() { return m_length; }
193
194    bool is8Bit() { return false; }
195
196    NO_RETURN_DUE_TO_CRASH void writeTo(LChar*)
197    {
198        RELEASE_ASSERT(false);
199    }
200
201    void writeTo(UChar* destination)
202    {
203        memcpy(destination, m_buffer, m_length * sizeof(UChar));
204    }
205
206private:
207    const UChar* m_buffer;
208    unsigned m_length;
209};
210
211template<>
212class StringTypeAdapter<const char*> {
213public:
214    StringTypeAdapter<const char*>(const char* buffer)
215        : m_buffer(buffer)
216        , m_length(strlen(buffer))
217    {
218    }
219
220    unsigned length() { return m_length; }
221
222    bool is8Bit() { return true; }
223
224    void writeTo(LChar* destination)
225    {
226        memcpy(destination, m_buffer, static_cast<size_t>(m_length) * sizeof(LChar));
227    }
228
229    void writeTo(UChar* destination)
230    {
231        for (unsigned i = 0; i < m_length; ++i) {
232            unsigned char c = m_buffer[i];
233            destination[i] = c;
234        }
235    }
236
237private:
238    const char* m_buffer;
239    unsigned m_length;
240};
241
242template<>
243class StringTypeAdapter<const LChar*> {
244public:
245    StringTypeAdapter<const LChar*>(const LChar* buffer)
246        : m_buffer(buffer)
247        , m_length(strlen(reinterpret_cast<const char*>(buffer)))
248    {
249    }
250
251    unsigned length() { return m_length; }
252
253    bool is8Bit() { return true; }
254
255    void writeTo(LChar* destination)
256    {
257        memcpy(destination, m_buffer, static_cast<size_t>(m_length) * sizeof(LChar));
258    }
259
260    void writeTo(UChar* destination)
261    {
262        StringImpl::copyChars(destination, m_buffer, m_length);
263    }
264
265private:
266    const LChar* m_buffer;
267    unsigned m_length;
268};
269
270template<>
271class StringTypeAdapter<Vector<char> > {
272public:
273    StringTypeAdapter<Vector<char> >(const Vector<char>& buffer)
274        : m_buffer(buffer)
275    {
276    }
277
278    size_t length() { return m_buffer.size(); }
279
280    bool is8Bit() { return true; }
281
282    void writeTo(LChar* destination)
283    {
284        for (size_t i = 0; i < m_buffer.size(); ++i)
285            destination[i] = static_cast<unsigned char>(m_buffer[i]);
286    }
287
288    void writeTo(UChar* destination)
289    {
290        for (size_t i = 0; i < m_buffer.size(); ++i)
291            destination[i] = static_cast<unsigned char>(m_buffer[i]);
292    }
293
294private:
295    const Vector<char>& m_buffer;
296};
297
298template<>
299class StringTypeAdapter<Vector<LChar> > {
300public:
301    StringTypeAdapter<Vector<LChar> >(const Vector<LChar>& buffer)
302        : m_buffer(buffer)
303    {
304    }
305
306    size_t length() { return m_buffer.size(); }
307
308    bool is8Bit() { return true; }
309
310    void writeTo(LChar* destination)
311    {
312        for (size_t i = 0; i < m_buffer.size(); ++i)
313            destination[i] = m_buffer[i];
314    }
315
316    void writeTo(UChar* destination)
317    {
318        for (size_t i = 0; i < m_buffer.size(); ++i)
319            destination[i] = m_buffer[i];
320    }
321
322private:
323    const Vector<LChar>& m_buffer;
324};
325
326template<>
327class StringTypeAdapter<String> {
328public:
329    StringTypeAdapter<String>(const String& string)
330        : m_buffer(string)
331    {
332    }
333
334    unsigned length() { return m_buffer.length(); }
335
336    bool is8Bit() { return m_buffer.isNull() || m_buffer.is8Bit(); }
337
338    void writeTo(LChar* destination)
339    {
340        unsigned length = m_buffer.length();
341
342        ASSERT(is8Bit());
343        const LChar* data = m_buffer.characters8();
344        for (unsigned i = 0; i < length; ++i)
345            destination[i] = data[i];
346
347        WTF_STRINGTYPEADAPTER_COPIED_WTF_STRING();
348    }
349
350    void writeTo(UChar* destination)
351    {
352        unsigned length = m_buffer.length();
353
354        if (is8Bit()) {
355            const LChar* data = m_buffer.characters8();
356            for (unsigned i = 0; i < length; ++i)
357                destination[i] = data[i];
358        } else {
359            const UChar* data = m_buffer.characters16();
360            for (unsigned i = 0; i < length; ++i)
361                destination[i] = data[i];
362        }
363
364        WTF_STRINGTYPEADAPTER_COPIED_WTF_STRING();
365    }
366
367private:
368    const String& m_buffer;
369};
370
371template<>
372class StringTypeAdapter<AtomicString> {
373public:
374    StringTypeAdapter<AtomicString>(const AtomicString& string)
375        : m_adapter(string.string())
376    {
377    }
378
379    unsigned length() { return m_adapter.length(); }
380
381    bool is8Bit() { return m_adapter.is8Bit(); }
382
383    void writeTo(LChar* destination) { m_adapter.writeTo(destination); }
384    void writeTo(UChar* destination) { m_adapter.writeTo(destination); }
385
386private:
387    StringTypeAdapter<String> m_adapter;
388};
389
390inline void sumWithOverflow(unsigned& total, unsigned addend, bool& overflow)
391{
392    unsigned oldTotal = total;
393    total = oldTotal + addend;
394    if (total < oldTotal)
395        overflow = true;
396}
397
398template<typename StringType1, typename StringType2>
399PassRefPtr<StringImpl> makeString(StringType1 string1, StringType2 string2)
400{
401    StringTypeAdapter<StringType1> adapter1(string1);
402    StringTypeAdapter<StringType2> adapter2(string2);
403
404    bool overflow = false;
405    unsigned length = adapter1.length();
406    sumWithOverflow(length, adapter2.length(), overflow);
407    if (overflow)
408        return 0;
409
410    if (adapter1.is8Bit() && adapter2.is8Bit()) {
411        LChar* buffer;
412        RefPtr<StringImpl> resultImpl = StringImpl::createUninitialized(length, buffer);
413        if (!resultImpl)
414            return 0;
415
416        LChar* result = buffer;
417        adapter1.writeTo(result);
418        result += adapter1.length();
419        adapter2.writeTo(result);
420
421        return resultImpl.release();
422    }
423
424    UChar* buffer;
425    RefPtr<StringImpl> resultImpl = StringImpl::createUninitialized(length, buffer);
426    if (!resultImpl)
427        return 0;
428
429    UChar* result = buffer;
430    adapter1.writeTo(result);
431    result += adapter1.length();
432    adapter2.writeTo(result);
433
434    return resultImpl.release();
435}
436
437} // namespace WTF
438
439#include "wtf/text/StringOperators.h"
440#endif
441