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