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 <wtf/text/WTFString.h>
30
31namespace WTF {
32
33template<typename StringType>
34class StringTypeAdapter {
35};
36
37template<>
38class StringTypeAdapter<char> {
39public:
40    StringTypeAdapter<char>(char buffer)
41        : m_buffer(buffer)
42    {
43    }
44
45    unsigned length() { return 1; }
46    void writeTo(UChar* destination) { *destination = m_buffer; }
47
48private:
49    unsigned char m_buffer;
50};
51
52template<>
53class StringTypeAdapter<UChar> {
54public:
55    StringTypeAdapter<UChar>(UChar buffer)
56        : m_buffer(buffer)
57    {
58    }
59
60    unsigned length() { return 1; }
61    void writeTo(UChar* destination) { *destination = m_buffer; }
62
63private:
64    UChar m_buffer;
65};
66
67template<>
68class StringTypeAdapter<char*> {
69public:
70    StringTypeAdapter<char*>(char* buffer)
71        : m_buffer(buffer)
72        , m_length(strlen(buffer))
73    {
74    }
75
76    unsigned length() { return m_length; }
77
78    void writeTo(UChar* destination)
79    {
80        for (unsigned i = 0; i < m_length; ++i) {
81            unsigned char c = m_buffer[i];
82            destination[i] = c;
83        }
84    }
85
86private:
87    const char* m_buffer;
88    unsigned m_length;
89};
90
91template<>
92class StringTypeAdapter<const UChar*> {
93public:
94    StringTypeAdapter<const UChar*>(const UChar* buffer)
95        : m_buffer(buffer)
96    {
97        size_t len = 0;
98        while (m_buffer[len] != UChar(0))
99            len++;
100
101        if (len > std::numeric_limits<unsigned>::max())
102            CRASH();
103
104        m_length = len;
105    }
106
107    unsigned length() { return m_length; }
108
109    void writeTo(UChar* destination)
110    {
111        memcpy(destination, m_buffer, static_cast<size_t>(m_length) * sizeof(UChar));
112    }
113
114private:
115    const UChar* m_buffer;
116    unsigned m_length;
117};
118
119template<>
120class StringTypeAdapter<const char*> {
121public:
122    StringTypeAdapter<const char*>(const char* buffer)
123        : m_buffer(buffer)
124        , m_length(strlen(buffer))
125    {
126    }
127
128    unsigned length() { return m_length; }
129
130    void writeTo(UChar* destination)
131    {
132        for (unsigned i = 0; i < m_length; ++i) {
133            unsigned char c = m_buffer[i];
134            destination[i] = c;
135        }
136    }
137
138private:
139    const char* m_buffer;
140    unsigned m_length;
141};
142
143template<>
144class StringTypeAdapter<Vector<char> > {
145public:
146    StringTypeAdapter<Vector<char> >(const Vector<char>& buffer)
147        : m_buffer(buffer)
148    {
149    }
150
151    size_t length() { return m_buffer.size(); }
152
153    void writeTo(UChar* destination)
154    {
155        for (size_t i = 0; i < m_buffer.size(); ++i) {
156            unsigned char c = m_buffer[i];
157            destination[i] = c;
158        }
159    }
160
161private:
162    const Vector<char>& m_buffer;
163};
164
165template<>
166class StringTypeAdapter<String> {
167public:
168    StringTypeAdapter<String>(const String& string)
169        : m_buffer(string)
170    {
171    }
172
173    unsigned length() { return m_buffer.length(); }
174
175    void writeTo(UChar* destination)
176    {
177        const UChar* data = m_buffer.characters();
178        unsigned length = m_buffer.length();
179        for (unsigned i = 0; i < length; ++i)
180            destination[i] = data[i];
181    }
182
183private:
184    const String& m_buffer;
185};
186
187inline void sumWithOverflow(unsigned& total, unsigned addend, bool& overflow)
188{
189    unsigned oldTotal = total;
190    total = oldTotal + addend;
191    if (total < oldTotal)
192        overflow = true;
193}
194
195template<typename StringType1, typename StringType2>
196PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2)
197{
198    StringTypeAdapter<StringType1> adapter1(string1);
199    StringTypeAdapter<StringType2> adapter2(string2);
200
201    UChar* buffer;
202    bool overflow = false;
203    unsigned length = adapter1.length();
204    sumWithOverflow(length, adapter2.length(), overflow);
205    if (overflow)
206        return 0;
207    RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
208    if (!resultImpl)
209        return 0;
210
211    UChar* result = buffer;
212    adapter1.writeTo(result);
213    result += adapter1.length();
214    adapter2.writeTo(result);
215
216    return resultImpl.release();
217}
218
219template<typename StringType1, typename StringType2, typename StringType3>
220PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3)
221{
222    StringTypeAdapter<StringType1> adapter1(string1);
223    StringTypeAdapter<StringType2> adapter2(string2);
224    StringTypeAdapter<StringType3> adapter3(string3);
225
226    UChar* buffer = 0;
227    bool overflow = false;
228    unsigned length = adapter1.length();
229    sumWithOverflow(length, adapter2.length(), overflow);
230    sumWithOverflow(length, adapter3.length(), overflow);
231    if (overflow)
232        return 0;
233    RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
234    if (!resultImpl)
235        return 0;
236
237    UChar* result = buffer;
238    adapter1.writeTo(result);
239    result += adapter1.length();
240    adapter2.writeTo(result);
241    result += adapter2.length();
242    adapter3.writeTo(result);
243
244    return resultImpl.release();
245}
246
247template<typename StringType1, typename StringType2, typename StringType3, typename StringType4>
248PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4)
249{
250    StringTypeAdapter<StringType1> adapter1(string1);
251    StringTypeAdapter<StringType2> adapter2(string2);
252    StringTypeAdapter<StringType3> adapter3(string3);
253    StringTypeAdapter<StringType4> adapter4(string4);
254
255    UChar* buffer;
256    bool overflow = false;
257    unsigned length = adapter1.length();
258    sumWithOverflow(length, adapter2.length(), overflow);
259    sumWithOverflow(length, adapter3.length(), overflow);
260    sumWithOverflow(length, adapter4.length(), overflow);
261    if (overflow)
262        return 0;
263    RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
264    if (!resultImpl)
265        return 0;
266
267    UChar* result = buffer;
268    adapter1.writeTo(result);
269    result += adapter1.length();
270    adapter2.writeTo(result);
271    result += adapter2.length();
272    adapter3.writeTo(result);
273    result += adapter3.length();
274    adapter4.writeTo(result);
275
276    return resultImpl.release();
277}
278
279template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5>
280PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5)
281{
282    StringTypeAdapter<StringType1> adapter1(string1);
283    StringTypeAdapter<StringType2> adapter2(string2);
284    StringTypeAdapter<StringType3> adapter3(string3);
285    StringTypeAdapter<StringType4> adapter4(string4);
286    StringTypeAdapter<StringType5> adapter5(string5);
287
288    UChar* buffer;
289    bool overflow = false;
290    unsigned length = adapter1.length();
291    sumWithOverflow(length, adapter2.length(), overflow);
292    sumWithOverflow(length, adapter3.length(), overflow);
293    sumWithOverflow(length, adapter4.length(), overflow);
294    sumWithOverflow(length, adapter5.length(), overflow);
295    if (overflow)
296        return 0;
297    RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
298    if (!resultImpl)
299        return 0;
300
301    UChar* result = buffer;
302    adapter1.writeTo(result);
303    result += adapter1.length();
304    adapter2.writeTo(result);
305    result += adapter2.length();
306    adapter3.writeTo(result);
307    result += adapter3.length();
308    adapter4.writeTo(result);
309    result += adapter4.length();
310    adapter5.writeTo(result);
311
312    return resultImpl.release();
313}
314
315template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6>
316PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6)
317{
318    StringTypeAdapter<StringType1> adapter1(string1);
319    StringTypeAdapter<StringType2> adapter2(string2);
320    StringTypeAdapter<StringType3> adapter3(string3);
321    StringTypeAdapter<StringType4> adapter4(string4);
322    StringTypeAdapter<StringType5> adapter5(string5);
323    StringTypeAdapter<StringType6> adapter6(string6);
324
325    UChar* buffer;
326    bool overflow = false;
327    unsigned length = adapter1.length();
328    sumWithOverflow(length, adapter2.length(), overflow);
329    sumWithOverflow(length, adapter3.length(), overflow);
330    sumWithOverflow(length, adapter4.length(), overflow);
331    sumWithOverflow(length, adapter5.length(), overflow);
332    sumWithOverflow(length, adapter6.length(), overflow);
333    if (overflow)
334        return 0;
335    RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
336    if (!resultImpl)
337        return 0;
338
339    UChar* result = buffer;
340    adapter1.writeTo(result);
341    result += adapter1.length();
342    adapter2.writeTo(result);
343    result += adapter2.length();
344    adapter3.writeTo(result);
345    result += adapter3.length();
346    adapter4.writeTo(result);
347    result += adapter4.length();
348    adapter5.writeTo(result);
349    result += adapter5.length();
350    adapter6.writeTo(result);
351
352    return resultImpl.release();
353}
354
355template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7>
356PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7)
357{
358    StringTypeAdapter<StringType1> adapter1(string1);
359    StringTypeAdapter<StringType2> adapter2(string2);
360    StringTypeAdapter<StringType3> adapter3(string3);
361    StringTypeAdapter<StringType4> adapter4(string4);
362    StringTypeAdapter<StringType5> adapter5(string5);
363    StringTypeAdapter<StringType6> adapter6(string6);
364    StringTypeAdapter<StringType7> adapter7(string7);
365
366    UChar* buffer;
367    bool overflow = false;
368    unsigned length = adapter1.length();
369    sumWithOverflow(length, adapter2.length(), overflow);
370    sumWithOverflow(length, adapter3.length(), overflow);
371    sumWithOverflow(length, adapter4.length(), overflow);
372    sumWithOverflow(length, adapter5.length(), overflow);
373    sumWithOverflow(length, adapter6.length(), overflow);
374    sumWithOverflow(length, adapter7.length(), overflow);
375    if (overflow)
376        return 0;
377    RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
378    if (!resultImpl)
379        return 0;
380
381    UChar* result = buffer;
382    adapter1.writeTo(result);
383    result += adapter1.length();
384    adapter2.writeTo(result);
385    result += adapter2.length();
386    adapter3.writeTo(result);
387    result += adapter3.length();
388    adapter4.writeTo(result);
389    result += adapter4.length();
390    adapter5.writeTo(result);
391    result += adapter5.length();
392    adapter6.writeTo(result);
393    result += adapter6.length();
394    adapter7.writeTo(result);
395
396    return resultImpl.release();
397}
398
399template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7, typename StringType8>
400PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8)
401{
402    StringTypeAdapter<StringType1> adapter1(string1);
403    StringTypeAdapter<StringType2> adapter2(string2);
404    StringTypeAdapter<StringType3> adapter3(string3);
405    StringTypeAdapter<StringType4> adapter4(string4);
406    StringTypeAdapter<StringType5> adapter5(string5);
407    StringTypeAdapter<StringType6> adapter6(string6);
408    StringTypeAdapter<StringType7> adapter7(string7);
409    StringTypeAdapter<StringType8> adapter8(string8);
410
411    UChar* buffer;
412    bool overflow = false;
413    unsigned length = adapter1.length();
414    sumWithOverflow(length, adapter2.length(), overflow);
415    sumWithOverflow(length, adapter3.length(), overflow);
416    sumWithOverflow(length, adapter4.length(), overflow);
417    sumWithOverflow(length, adapter5.length(), overflow);
418    sumWithOverflow(length, adapter6.length(), overflow);
419    sumWithOverflow(length, adapter7.length(), overflow);
420    sumWithOverflow(length, adapter8.length(), overflow);
421    if (overflow)
422        return 0;
423    RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
424    if (!resultImpl)
425        return 0;
426
427    UChar* result = buffer;
428    adapter1.writeTo(result);
429    result += adapter1.length();
430    adapter2.writeTo(result);
431    result += adapter2.length();
432    adapter3.writeTo(result);
433    result += adapter3.length();
434    adapter4.writeTo(result);
435    result += adapter4.length();
436    adapter5.writeTo(result);
437    result += adapter5.length();
438    adapter6.writeTo(result);
439    result += adapter6.length();
440    adapter7.writeTo(result);
441    result += adapter7.length();
442    adapter8.writeTo(result);
443
444    return resultImpl.release();
445}
446
447template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7, typename StringType8, typename StringType9>
448PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8, StringType9 string9)
449{
450    StringTypeAdapter<StringType1> adapter1(string1);
451    StringTypeAdapter<StringType2> adapter2(string2);
452    StringTypeAdapter<StringType3> adapter3(string3);
453    StringTypeAdapter<StringType4> adapter4(string4);
454    StringTypeAdapter<StringType5> adapter5(string5);
455    StringTypeAdapter<StringType6> adapter6(string6);
456    StringTypeAdapter<StringType7> adapter7(string7);
457    StringTypeAdapter<StringType8> adapter8(string8);
458    StringTypeAdapter<StringType9> adapter9(string9);
459
460    UChar* buffer;
461    bool overflow = false;
462    unsigned length = adapter1.length();
463    sumWithOverflow(length, adapter2.length(), overflow);
464    sumWithOverflow(length, adapter3.length(), overflow);
465    sumWithOverflow(length, adapter4.length(), overflow);
466    sumWithOverflow(length, adapter5.length(), overflow);
467    sumWithOverflow(length, adapter6.length(), overflow);
468    sumWithOverflow(length, adapter7.length(), overflow);
469    sumWithOverflow(length, adapter8.length(), overflow);
470    sumWithOverflow(length, adapter9.length(), overflow);
471    if (overflow)
472        return 0;
473    RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
474    if (!resultImpl)
475        return 0;
476
477    UChar* result = buffer;
478    adapter1.writeTo(result);
479    result += adapter1.length();
480    adapter2.writeTo(result);
481    result += adapter2.length();
482    adapter3.writeTo(result);
483    result += adapter3.length();
484    adapter4.writeTo(result);
485    result += adapter4.length();
486    adapter5.writeTo(result);
487    result += adapter5.length();
488    adapter6.writeTo(result);
489    result += adapter6.length();
490    adapter7.writeTo(result);
491    result += adapter7.length();
492    adapter8.writeTo(result);
493    result += adapter8.length();
494    adapter9.writeTo(result);
495
496    return resultImpl.release();
497}
498
499
500// Convenience only.
501template<typename StringType1>
502String makeString(StringType1 string1)
503{
504    return String(string1);
505}
506
507template<typename StringType1, typename StringType2>
508String makeString(StringType1 string1, StringType2 string2)
509{
510    RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2);
511    if (!resultImpl)
512        CRASH();
513    return resultImpl.release();
514}
515
516template<typename StringType1, typename StringType2, typename StringType3>
517String makeString(StringType1 string1, StringType2 string2, StringType3 string3)
518{
519    RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3);
520    if (!resultImpl)
521        CRASH();
522    return resultImpl.release();
523}
524
525template<typename StringType1, typename StringType2, typename StringType3, typename StringType4>
526String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4)
527{
528    RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4);
529    if (!resultImpl)
530        CRASH();
531    return resultImpl.release();
532}
533
534template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5>
535String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5)
536{
537    RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5);
538    if (!resultImpl)
539        CRASH();
540    return resultImpl.release();
541}
542
543template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6>
544String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6)
545{
546    RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5, string6);
547    if (!resultImpl)
548        CRASH();
549    return resultImpl.release();
550}
551
552template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7>
553String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7)
554{
555    RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5, string6, string7);
556    if (!resultImpl)
557        CRASH();
558    return resultImpl.release();
559}
560
561template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7, typename StringType8>
562String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8)
563{
564    RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5, string6, string7, string8);
565    if (!resultImpl)
566        CRASH();
567    return resultImpl.release();
568}
569
570template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7, typename StringType8, typename StringType9>
571String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8, StringType9 string9)
572{
573    RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5, string6, string7, string8, string9);
574    if (!resultImpl)
575        CRASH();
576    return resultImpl.release();
577}
578
579} // namespace WTF
580
581using WTF::makeString;
582
583#endif
584