blob: 12bb7c454e52bffb421d9266df4fd217c1bb9a70 [file] [log] [blame]
The Android Open Source Projectcbb10112009-03-03 19:31:44 -08001/*
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
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080019#include <utils/Log.h>
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080020
Sergio Girod2529f22015-09-23 16:22:59 +010021#include "SharedBuffer.h"
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080022
Kenny Root9a2d83e2009-12-04 09:38:48 -080023namespace android {
24
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080025static SharedBuffer* gEmptyStringBuf = NULL;
26static char16_t* gEmptyString = NULL;
27
28static inline char16_t* getEmptyString()
29{
30 gEmptyStringBuf->acquire();
31 return gEmptyString;
32}
33
34void initialize_string16()
35{
36 SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t));
37 char16_t* str = (char16_t*)buf->data();
38 *str = 0;
39 gEmptyStringBuf = buf;
40 gEmptyString = str;
41}
42
43void terminate_string16()
44{
45 SharedBuffer::bufferFromData(gEmptyString)->release();
46 gEmptyStringBuf = NULL;
47 gEmptyString = NULL;
48}
49
50// ---------------------------------------------------------------------------
51
Kenny Rootba0165b2010-11-09 14:37:23 -080052static char16_t* allocFromUTF8(const char* u8str, size_t u8len)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080053{
Kenny Rootba0165b2010-11-09 14:37:23 -080054 if (u8len == 0) return getEmptyString();
55
56 const uint8_t* u8cur = (const uint8_t*) u8str;
57
58 const ssize_t u16len = utf8_to_utf16_length(u8cur, u8len);
59 if (u16len < 0) {
60 return getEmptyString();
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080061 }
Kenny Rootba0165b2010-11-09 14:37:23 -080062
Kenny Rootba0165b2010-11-09 14:37:23 -080063 SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t)*(u16len+1));
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080064 if (buf) {
Kenny Rootba0165b2010-11-09 14:37:23 -080065 u8cur = (const uint8_t*) u8str;
66 char16_t* u16str = (char16_t*)buf->data();
67
Sergio Giro1dcc0c82016-07-20 20:01:33 +010068 utf8_to_utf16(u8cur, u8len, u16str, ((size_t) u16len) + 1);
Kenny Root9a2d83e2009-12-04 09:38:48 -080069
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080070 //printf("Created UTF-16 string from UTF-8 \"%s\":", in);
71 //printHexData(1, str, buf->size(), 16, 1);
72 //printf("\n");
Samuel Tanf9d16ef2016-02-16 15:17:10 -080073
Kenny Rootba0165b2010-11-09 14:37:23 -080074 return u16str;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080075 }
Kenny Rootba0165b2010-11-09 14:37:23 -080076
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080077 return getEmptyString();
78}
79
80// ---------------------------------------------------------------------------
81
82String16::String16()
83 : mString(getEmptyString())
84{
85}
86
Mathias Agopian4485d0d2013-05-08 16:04:13 -070087String16::String16(StaticLinkage)
88 : mString(0)
89{
90 // this constructor is used when we can't rely on the static-initializers
91 // having run. In this case we always allocate an empty string. It's less
92 // efficient than using getEmptyString(), but we assume it's uncommon.
93
94 char16_t* data = static_cast<char16_t*>(
95 SharedBuffer::alloc(sizeof(char16_t))->data());
96 data[0] = 0;
97 mString = data;
98}
99
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800100String16::String16(const String16& o)
101 : mString(o.mString)
102{
103 SharedBuffer::bufferFromData(mString)->acquire();
104}
105
106String16::String16(const String16& o, size_t len, size_t begin)
107 : mString(getEmptyString())
108{
109 setTo(o, len, begin);
110}
111
112String16::String16(const char16_t* o)
113{
114 size_t len = strlen16(o);
115 SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t));
Steve Blockae074452012-01-09 18:35:44 +0000116 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800117 if (buf) {
118 char16_t* str = (char16_t*)buf->data();
119 strcpy16(str, o);
120 mString = str;
121 return;
122 }
Samuel Tanf9d16ef2016-02-16 15:17:10 -0800123
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800124 mString = getEmptyString();
125}
126
127String16::String16(const char16_t* o, size_t len)
128{
129 SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t));
Steve Blockae074452012-01-09 18:35:44 +0000130 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800131 if (buf) {
132 char16_t* str = (char16_t*)buf->data();
133 memcpy(str, o, len*sizeof(char16_t));
134 str[len] = 0;
135 mString = str;
136 return;
137 }
Samuel Tanf9d16ef2016-02-16 15:17:10 -0800138
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800139 mString = getEmptyString();
140}
141
142String16::String16(const String8& o)
143 : mString(allocFromUTF8(o.string(), o.size()))
144{
145}
146
147String16::String16(const char* o)
148 : mString(allocFromUTF8(o, strlen(o)))
149{
150}
151
152String16::String16(const char* o, size_t len)
153 : mString(allocFromUTF8(o, len))
154{
155}
156
157String16::~String16()
158{
159 SharedBuffer::bufferFromData(mString)->release();
160}
161
Sergio Girod2529f22015-09-23 16:22:59 +0100162size_t String16::size() const
163{
164 return SharedBuffer::sizeFromData(mString)/sizeof(char16_t)-1;
165}
166
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800167void String16::setTo(const String16& other)
168{
169 SharedBuffer::bufferFromData(other.mString)->acquire();
170 SharedBuffer::bufferFromData(mString)->release();
171 mString = other.mString;
172}
173
174status_t String16::setTo(const String16& other, size_t len, size_t begin)
175{
176 const size_t N = other.size();
177 if (begin >= N) {
178 SharedBuffer::bufferFromData(mString)->release();
179 mString = getEmptyString();
180 return NO_ERROR;
181 }
182 if ((begin+len) > N) len = N-begin;
183 if (begin == 0 && len == N) {
184 setTo(other);
185 return NO_ERROR;
186 }
187
188 if (&other == this) {
189 LOG_ALWAYS_FATAL("Not implemented");
190 }
191
192 return setTo(other.string()+begin, len);
193}
194
195status_t String16::setTo(const char16_t* other)
196{
197 return setTo(other, strlen16(other));
198}
199
200status_t String16::setTo(const char16_t* other, size_t len)
201{
202 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
203 ->editResize((len+1)*sizeof(char16_t));
204 if (buf) {
205 char16_t* str = (char16_t*)buf->data();
The Android Open Source Project7a4c8392009-03-05 14:34:35 -0800206 memmove(str, other, len*sizeof(char16_t));
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800207 str[len] = 0;
208 mString = str;
209 return NO_ERROR;
210 }
211 return NO_MEMORY;
212}
213
214status_t String16::append(const String16& other)
215{
216 const size_t myLen = size();
217 const size_t otherLen = other.size();
218 if (myLen == 0) {
219 setTo(other);
220 return NO_ERROR;
221 } else if (otherLen == 0) {
222 return NO_ERROR;
223 }
Samuel Tanf9d16ef2016-02-16 15:17:10 -0800224
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800225 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
226 ->editResize((myLen+otherLen+1)*sizeof(char16_t));
227 if (buf) {
228 char16_t* str = (char16_t*)buf->data();
229 memcpy(str+myLen, other, (otherLen+1)*sizeof(char16_t));
230 mString = str;
231 return NO_ERROR;
232 }
233 return NO_MEMORY;
234}
235
236status_t String16::append(const char16_t* chrs, size_t otherLen)
237{
238 const size_t myLen = size();
239 if (myLen == 0) {
240 setTo(chrs, otherLen);
241 return NO_ERROR;
242 } else if (otherLen == 0) {
243 return NO_ERROR;
244 }
Samuel Tanf9d16ef2016-02-16 15:17:10 -0800245
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800246 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
247 ->editResize((myLen+otherLen+1)*sizeof(char16_t));
248 if (buf) {
249 char16_t* str = (char16_t*)buf->data();
250 memcpy(str+myLen, chrs, otherLen*sizeof(char16_t));
251 str[myLen+otherLen] = 0;
252 mString = str;
253 return NO_ERROR;
254 }
255 return NO_MEMORY;
256}
257
258status_t String16::insert(size_t pos, const char16_t* chrs)
259{
260 return insert(pos, chrs, strlen16(chrs));
261}
262
263status_t String16::insert(size_t pos, const char16_t* chrs, size_t len)
264{
265 const size_t myLen = size();
266 if (myLen == 0) {
267 return setTo(chrs, len);
268 return NO_ERROR;
269 } else if (len == 0) {
270 return NO_ERROR;
271 }
272
273 if (pos > myLen) pos = myLen;
274
275 #if 0
276 printf("Insert in to %s: pos=%d, len=%d, myLen=%d, chrs=%s\n",
277 String8(*this).string(), pos,
278 len, myLen, String8(chrs, len).string());
279 #endif
280
281 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
282 ->editResize((myLen+len+1)*sizeof(char16_t));
283 if (buf) {
284 char16_t* str = (char16_t*)buf->data();
285 if (pos < myLen) {
286 memmove(str+pos+len, str+pos, (myLen-pos)*sizeof(char16_t));
287 }
288 memcpy(str+pos, chrs, len*sizeof(char16_t));
289 str[myLen+len] = 0;
290 mString = str;
291 #if 0
292 printf("Result (%d chrs): %s\n", size(), String8(*this).string());
293 #endif
294 return NO_ERROR;
295 }
296 return NO_MEMORY;
297}
298
299ssize_t String16::findFirst(char16_t c) const
300{
301 const char16_t* str = string();
302 const char16_t* p = str;
303 const char16_t* e = p + size();
304 while (p < e) {
305 if (*p == c) {
306 return p-str;
307 }
308 p++;
309 }
310 return -1;
311}
312
313ssize_t String16::findLast(char16_t c) const
314{
315 const char16_t* str = string();
316 const char16_t* p = str;
317 const char16_t* e = p + size();
318 while (p < e) {
319 e--;
320 if (*e == c) {
321 return e-str;
322 }
323 }
324 return -1;
325}
326
327bool String16::startsWith(const String16& prefix) const
328{
329 const size_t ps = prefix.size();
330 if (ps > size()) return false;
331 return strzcmp16(mString, ps, prefix.string(), ps) == 0;
332}
333
334bool String16::startsWith(const char16_t* prefix) const
335{
336 const size_t ps = strlen16(prefix);
337 if (ps > size()) return false;
338 return strncmp16(mString, prefix, ps) == 0;
339}
340
Michael Wright5bacef32016-05-09 14:43:31 +0100341bool String16::contains(const char16_t* chrs) const
342{
343 return strstr16(mString, chrs) != nullptr;
344}
345
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800346status_t String16::makeLower()
347{
348 const size_t N = size();
349 const char16_t* str = string();
350 char16_t* edit = NULL;
351 for (size_t i=0; i<N; i++) {
352 const char16_t v = str[i];
353 if (v >= 'A' && v <= 'Z') {
354 if (!edit) {
355 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)->edit();
356 if (!buf) {
357 return NO_MEMORY;
358 }
359 edit = (char16_t*)buf->data();
360 mString = str = edit;
361 }
362 edit[i] = tolower((char)v);
363 }
364 }
365 return NO_ERROR;
366}
367
368status_t String16::replaceAll(char16_t replaceThis, char16_t withThis)
369{
370 const size_t N = size();
371 const char16_t* str = string();
372 char16_t* edit = NULL;
373 for (size_t i=0; i<N; i++) {
374 if (str[i] == replaceThis) {
375 if (!edit) {
376 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)->edit();
377 if (!buf) {
378 return NO_MEMORY;
379 }
380 edit = (char16_t*)buf->data();
381 mString = str = edit;
382 }
383 edit[i] = withThis;
384 }
385 }
386 return NO_ERROR;
387}
388
389status_t String16::remove(size_t len, size_t begin)
390{
391 const size_t N = size();
392 if (begin >= N) {
393 SharedBuffer::bufferFromData(mString)->release();
394 mString = getEmptyString();
395 return NO_ERROR;
396 }
397 if ((begin+len) > N) len = N-begin;
398 if (begin == 0 && len == N) {
399 return NO_ERROR;
400 }
401
402 if (begin > 0) {
403 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
404 ->editResize((N+1)*sizeof(char16_t));
405 if (!buf) {
406 return NO_MEMORY;
407 }
408 char16_t* str = (char16_t*)buf->data();
409 memmove(str, str+begin, (N-begin+1)*sizeof(char16_t));
410 mString = str;
411 }
412 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
413 ->editResize((len+1)*sizeof(char16_t));
414 if (buf) {
415 char16_t* str = (char16_t*)buf->data();
416 str[len] = 0;
417 mString = str;
418 return NO_ERROR;
419 }
420 return NO_MEMORY;
421}
422
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800423}; // namespace android