1/*
2 * Copyright (C) 2005 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <utils/String16.h>
18
19#include <utils/Log.h>
20#include <utils/Unicode.h>
21#include <utils/String8.h>
22#include <utils/threads.h>
23
24#include <memory.h>
25#include <stdio.h>
26#include <ctype.h>
27
28
29namespace android {
30
31static SharedBuffer* gEmptyStringBuf = NULL;
32static char16_t* gEmptyString = NULL;
33
34static inline char16_t* getEmptyString()
35{
36    gEmptyStringBuf->acquire();
37   return gEmptyString;
38}
39
40void initialize_string16()
41{
42    SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t));
43    char16_t* str = (char16_t*)buf->data();
44    *str = 0;
45    gEmptyStringBuf = buf;
46    gEmptyString = str;
47}
48
49void terminate_string16()
50{
51    SharedBuffer::bufferFromData(gEmptyString)->release();
52    gEmptyStringBuf = NULL;
53    gEmptyString = NULL;
54}
55
56// ---------------------------------------------------------------------------
57
58static char16_t* allocFromUTF8(const char* u8str, size_t u8len)
59{
60    if (u8len == 0) return getEmptyString();
61
62    const uint8_t* u8cur = (const uint8_t*) u8str;
63
64    const ssize_t u16len = utf8_to_utf16_length(u8cur, u8len);
65    if (u16len < 0) {
66        return getEmptyString();
67    }
68
69    SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t)*(u16len+1));
70    if (buf) {
71        u8cur = (const uint8_t*) u8str;
72        char16_t* u16str = (char16_t*)buf->data();
73
74        utf8_to_utf16(u8cur, u8len, u16str);
75
76        //printf("Created UTF-16 string from UTF-8 \"%s\":", in);
77        //printHexData(1, str, buf->size(), 16, 1);
78        //printf("\n");
79
80        return u16str;
81    }
82
83    return getEmptyString();
84}
85
86// ---------------------------------------------------------------------------
87
88String16::String16()
89    : mString(getEmptyString())
90{
91}
92
93String16::String16(StaticLinkage)
94    : mString(0)
95{
96    // this constructor is used when we can't rely on the static-initializers
97    // having run. In this case we always allocate an empty string. It's less
98    // efficient than using getEmptyString(), but we assume it's uncommon.
99
100    char16_t* data = static_cast<char16_t*>(
101            SharedBuffer::alloc(sizeof(char16_t))->data());
102    data[0] = 0;
103    mString = data;
104}
105
106String16::String16(const String16& o)
107    : mString(o.mString)
108{
109    SharedBuffer::bufferFromData(mString)->acquire();
110}
111
112String16::String16(const String16& o, size_t len, size_t begin)
113    : mString(getEmptyString())
114{
115    setTo(o, len, begin);
116}
117
118String16::String16(const char16_t* o)
119{
120    size_t len = strlen16(o);
121    SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t));
122    ALOG_ASSERT(buf, "Unable to allocate shared buffer");
123    if (buf) {
124        char16_t* str = (char16_t*)buf->data();
125        strcpy16(str, o);
126        mString = str;
127        return;
128    }
129
130    mString = getEmptyString();
131}
132
133String16::String16(const char16_t* o, size_t len)
134{
135    SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t));
136    ALOG_ASSERT(buf, "Unable to allocate shared buffer");
137    if (buf) {
138        char16_t* str = (char16_t*)buf->data();
139        memcpy(str, o, len*sizeof(char16_t));
140        str[len] = 0;
141        mString = str;
142        return;
143    }
144
145    mString = getEmptyString();
146}
147
148String16::String16(const String8& o)
149    : mString(allocFromUTF8(o.string(), o.size()))
150{
151}
152
153String16::String16(const char* o)
154    : mString(allocFromUTF8(o, strlen(o)))
155{
156}
157
158String16::String16(const char* o, size_t len)
159    : mString(allocFromUTF8(o, len))
160{
161}
162
163String16::~String16()
164{
165    SharedBuffer::bufferFromData(mString)->release();
166}
167
168void String16::setTo(const String16& other)
169{
170    SharedBuffer::bufferFromData(other.mString)->acquire();
171    SharedBuffer::bufferFromData(mString)->release();
172    mString = other.mString;
173}
174
175status_t String16::setTo(const String16& other, size_t len, size_t begin)
176{
177    const size_t N = other.size();
178    if (begin >= N) {
179        SharedBuffer::bufferFromData(mString)->release();
180        mString = getEmptyString();
181        return NO_ERROR;
182    }
183    if ((begin+len) > N) len = N-begin;
184    if (begin == 0 && len == N) {
185        setTo(other);
186        return NO_ERROR;
187    }
188
189    if (&other == this) {
190        LOG_ALWAYS_FATAL("Not implemented");
191    }
192
193    return setTo(other.string()+begin, len);
194}
195
196status_t String16::setTo(const char16_t* other)
197{
198    return setTo(other, strlen16(other));
199}
200
201status_t String16::setTo(const char16_t* other, size_t len)
202{
203    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
204        ->editResize((len+1)*sizeof(char16_t));
205    if (buf) {
206        char16_t* str = (char16_t*)buf->data();
207        memmove(str, other, len*sizeof(char16_t));
208        str[len] = 0;
209        mString = str;
210        return NO_ERROR;
211    }
212    return NO_MEMORY;
213}
214
215status_t String16::append(const String16& other)
216{
217    const size_t myLen = size();
218    const size_t otherLen = other.size();
219    if (myLen == 0) {
220        setTo(other);
221        return NO_ERROR;
222    } else if (otherLen == 0) {
223        return NO_ERROR;
224    }
225
226    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
227        ->editResize((myLen+otherLen+1)*sizeof(char16_t));
228    if (buf) {
229        char16_t* str = (char16_t*)buf->data();
230        memcpy(str+myLen, other, (otherLen+1)*sizeof(char16_t));
231        mString = str;
232        return NO_ERROR;
233    }
234    return NO_MEMORY;
235}
236
237status_t String16::append(const char16_t* chrs, size_t otherLen)
238{
239    const size_t myLen = size();
240    if (myLen == 0) {
241        setTo(chrs, otherLen);
242        return NO_ERROR;
243    } else if (otherLen == 0) {
244        return NO_ERROR;
245    }
246
247    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
248        ->editResize((myLen+otherLen+1)*sizeof(char16_t));
249    if (buf) {
250        char16_t* str = (char16_t*)buf->data();
251        memcpy(str+myLen, chrs, otherLen*sizeof(char16_t));
252        str[myLen+otherLen] = 0;
253        mString = str;
254        return NO_ERROR;
255    }
256    return NO_MEMORY;
257}
258
259status_t String16::insert(size_t pos, const char16_t* chrs)
260{
261    return insert(pos, chrs, strlen16(chrs));
262}
263
264status_t String16::insert(size_t pos, const char16_t* chrs, size_t len)
265{
266    const size_t myLen = size();
267    if (myLen == 0) {
268        return setTo(chrs, len);
269        return NO_ERROR;
270    } else if (len == 0) {
271        return NO_ERROR;
272    }
273
274    if (pos > myLen) pos = myLen;
275
276    #if 0
277    printf("Insert in to %s: pos=%d, len=%d, myLen=%d, chrs=%s\n",
278           String8(*this).string(), pos,
279           len, myLen, String8(chrs, len).string());
280    #endif
281
282    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
283        ->editResize((myLen+len+1)*sizeof(char16_t));
284    if (buf) {
285        char16_t* str = (char16_t*)buf->data();
286        if (pos < myLen) {
287            memmove(str+pos+len, str+pos, (myLen-pos)*sizeof(char16_t));
288        }
289        memcpy(str+pos, chrs, len*sizeof(char16_t));
290        str[myLen+len] = 0;
291        mString = str;
292        #if 0
293        printf("Result (%d chrs): %s\n", size(), String8(*this).string());
294        #endif
295        return NO_ERROR;
296    }
297    return NO_MEMORY;
298}
299
300ssize_t String16::findFirst(char16_t c) const
301{
302    const char16_t* str = string();
303    const char16_t* p = str;
304    const char16_t* e = p + size();
305    while (p < e) {
306        if (*p == c) {
307            return p-str;
308        }
309        p++;
310    }
311    return -1;
312}
313
314ssize_t String16::findLast(char16_t c) const
315{
316    const char16_t* str = string();
317    const char16_t* p = str;
318    const char16_t* e = p + size();
319    while (p < e) {
320        e--;
321        if (*e == c) {
322            return e-str;
323        }
324    }
325    return -1;
326}
327
328bool String16::startsWith(const String16& prefix) const
329{
330    const size_t ps = prefix.size();
331    if (ps > size()) return false;
332    return strzcmp16(mString, ps, prefix.string(), ps) == 0;
333}
334
335bool String16::startsWith(const char16_t* prefix) const
336{
337    const size_t ps = strlen16(prefix);
338    if (ps > size()) return false;
339    return strncmp16(mString, prefix, ps) == 0;
340}
341
342status_t String16::makeLower()
343{
344    const size_t N = size();
345    const char16_t* str = string();
346    char16_t* edit = NULL;
347    for (size_t i=0; i<N; i++) {
348        const char16_t v = str[i];
349        if (v >= 'A' && v <= 'Z') {
350            if (!edit) {
351                SharedBuffer* buf = SharedBuffer::bufferFromData(mString)->edit();
352                if (!buf) {
353                    return NO_MEMORY;
354                }
355                edit = (char16_t*)buf->data();
356                mString = str = edit;
357            }
358            edit[i] = tolower((char)v);
359        }
360    }
361    return NO_ERROR;
362}
363
364status_t String16::replaceAll(char16_t replaceThis, char16_t withThis)
365{
366    const size_t N = size();
367    const char16_t* str = string();
368    char16_t* edit = NULL;
369    for (size_t i=0; i<N; i++) {
370        if (str[i] == replaceThis) {
371            if (!edit) {
372                SharedBuffer* buf = SharedBuffer::bufferFromData(mString)->edit();
373                if (!buf) {
374                    return NO_MEMORY;
375                }
376                edit = (char16_t*)buf->data();
377                mString = str = edit;
378            }
379            edit[i] = withThis;
380        }
381    }
382    return NO_ERROR;
383}
384
385status_t String16::remove(size_t len, size_t begin)
386{
387    const size_t N = size();
388    if (begin >= N) {
389        SharedBuffer::bufferFromData(mString)->release();
390        mString = getEmptyString();
391        return NO_ERROR;
392    }
393    if ((begin+len) > N) len = N-begin;
394    if (begin == 0 && len == N) {
395        return NO_ERROR;
396    }
397
398    if (begin > 0) {
399        SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
400            ->editResize((N+1)*sizeof(char16_t));
401        if (!buf) {
402            return NO_MEMORY;
403        }
404        char16_t* str = (char16_t*)buf->data();
405        memmove(str, str+begin, (N-begin+1)*sizeof(char16_t));
406        mString = str;
407    }
408    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
409        ->editResize((len+1)*sizeof(char16_t));
410    if (buf) {
411        char16_t* str = (char16_t*)buf->data();
412        str[len] = 0;
413        mString = str;
414        return NO_ERROR;
415    }
416    return NO_MEMORY;
417}
418
419}; // namespace android
420