blob: 80018897e17176d84b907998bc3d0af553764918 [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>
Kenny Rootba0165b2010-11-09 14:37:23 -080020#include <utils/Unicode.h>
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080021#include <utils/String8.h>
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080022#include <utils/threads.h>
23
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080024#include <memory.h>
25#include <stdio.h>
26#include <ctype.h>
27
Sergio Girod2529f22015-09-23 16:22:59 +010028#include "SharedBuffer.h"
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080029
Kenny Root9a2d83e2009-12-04 09:38:48 -080030namespace android {
31
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080032static SharedBuffer* gEmptyStringBuf = NULL;
33static char16_t* gEmptyString = NULL;
34
35static inline char16_t* getEmptyString()
36{
37 gEmptyStringBuf->acquire();
38 return gEmptyString;
39}
40
41void 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
50void terminate_string16()
51{
52 SharedBuffer::bufferFromData(gEmptyString)->release();
53 gEmptyStringBuf = NULL;
54 gEmptyString = NULL;
55}
56
57// ---------------------------------------------------------------------------
58
Kenny Rootba0165b2010-11-09 14:37:23 -080059static char16_t* allocFromUTF8(const char* u8str, size_t u8len)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080060{
Kenny Rootba0165b2010-11-09 14:37:23 -080061 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();
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080068 }
Kenny Rootba0165b2010-11-09 14:37:23 -080069
Kenny Rootba0165b2010-11-09 14:37:23 -080070 SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t)*(u16len+1));
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080071 if (buf) {
Kenny Rootba0165b2010-11-09 14:37:23 -080072 u8cur = (const uint8_t*) u8str;
73 char16_t* u16str = (char16_t*)buf->data();
74
75 utf8_to_utf16(u8cur, u8len, u16str);
Kenny Root9a2d83e2009-12-04 09:38:48 -080076
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080077 //printf("Created UTF-16 string from UTF-8 \"%s\":", in);
78 //printHexData(1, str, buf->size(), 16, 1);
79 //printf("\n");
80
Kenny Rootba0165b2010-11-09 14:37:23 -080081 return u16str;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080082 }
Kenny Rootba0165b2010-11-09 14:37:23 -080083
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080084 return getEmptyString();
85}
86
Steven Morelandd0648d82018-03-01 11:03:04 -080087static char16_t* allocFromUTF16(const char16_t* u16str, size_t u16len) {
88 if (u16len >= SIZE_MAX / sizeof(char16_t)) {
89 android_errorWriteLog(0x534e4554, "73826242");
90 abort();
91 }
92
93 SharedBuffer* buf = SharedBuffer::alloc((u16len + 1) * sizeof(char16_t));
94 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
95 if (buf) {
96 char16_t* str = (char16_t*)buf->data();
97 memcpy(str, u16str, u16len * sizeof(char16_t));
98 str[u16len] = 0;
99 return str;
100 }
101 return getEmptyString();
102}
103
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800104// ---------------------------------------------------------------------------
105
106String16::String16()
107 : mString(getEmptyString())
108{
109}
110
Mathias Agopian4485d0d2013-05-08 16:04:13 -0700111String16::String16(StaticLinkage)
112 : mString(0)
113{
114 // this constructor is used when we can't rely on the static-initializers
115 // having run. In this case we always allocate an empty string. It's less
116 // efficient than using getEmptyString(), but we assume it's uncommon.
117
118 char16_t* data = static_cast<char16_t*>(
119 SharedBuffer::alloc(sizeof(char16_t))->data());
120 data[0] = 0;
121 mString = data;
122}
123
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800124String16::String16(const String16& o)
125 : mString(o.mString)
126{
127 SharedBuffer::bufferFromData(mString)->acquire();
128}
129
130String16::String16(const String16& o, size_t len, size_t begin)
131 : mString(getEmptyString())
132{
133 setTo(o, len, begin);
134}
135
Steven Morelandd0648d82018-03-01 11:03:04 -0800136String16::String16(const char16_t* o) : mString(allocFromUTF16(o, strlen16(o))) {}
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800137
Steven Morelandd0648d82018-03-01 11:03:04 -0800138String16::String16(const char16_t* o, size_t len) : mString(allocFromUTF16(o, len)) {}
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800139
140String16::String16(const String8& o)
141 : mString(allocFromUTF8(o.string(), o.size()))
142{
143}
144
145String16::String16(const char* o)
146 : mString(allocFromUTF8(o, strlen(o)))
147{
148}
149
150String16::String16(const char* o, size_t len)
151 : mString(allocFromUTF8(o, len))
152{
153}
154
155String16::~String16()
156{
157 SharedBuffer::bufferFromData(mString)->release();
158}
159
Sergio Girod2529f22015-09-23 16:22:59 +0100160size_t String16::size() const
161{
162 return SharedBuffer::sizeFromData(mString)/sizeof(char16_t)-1;
163}
164
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800165void String16::setTo(const String16& other)
166{
167 SharedBuffer::bufferFromData(other.mString)->acquire();
168 SharedBuffer::bufferFromData(mString)->release();
169 mString = other.mString;
170}
171
172status_t String16::setTo(const String16& other, size_t len, size_t begin)
173{
174 const size_t N = other.size();
175 if (begin >= N) {
176 SharedBuffer::bufferFromData(mString)->release();
177 mString = getEmptyString();
178 return NO_ERROR;
179 }
180 if ((begin+len) > N) len = N-begin;
181 if (begin == 0 && len == N) {
182 setTo(other);
183 return NO_ERROR;
184 }
185
186 if (&other == this) {
187 LOG_ALWAYS_FATAL("Not implemented");
188 }
189
190 return setTo(other.string()+begin, len);
191}
192
193status_t String16::setTo(const char16_t* other)
194{
195 return setTo(other, strlen16(other));
196}
197
198status_t String16::setTo(const char16_t* other, size_t len)
199{
Steven Morelandd0648d82018-03-01 11:03:04 -0800200 if (len >= SIZE_MAX / sizeof(char16_t)) {
201 android_errorWriteLog(0x534e4554, "73826242");
202 abort();
203 }
204
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800205 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
206 ->editResize((len+1)*sizeof(char16_t));
207 if (buf) {
208 char16_t* str = (char16_t*)buf->data();
The Android Open Source Project7a4c8392009-03-05 14:34:35 -0800209 memmove(str, other, len*sizeof(char16_t));
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800210 str[len] = 0;
211 mString = str;
212 return NO_ERROR;
213 }
214 return NO_MEMORY;
215}
216
217status_t String16::append(const String16& other)
218{
219 const size_t myLen = size();
220 const size_t otherLen = other.size();
221 if (myLen == 0) {
222 setTo(other);
223 return NO_ERROR;
224 } else if (otherLen == 0) {
225 return NO_ERROR;
226 }
Steven Morelandd0648d82018-03-01 11:03:04 -0800227
228 if (myLen >= SIZE_MAX / sizeof(char16_t) - otherLen) {
229 android_errorWriteLog(0x534e4554, "73826242");
230 abort();
231 }
232
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800233 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
234 ->editResize((myLen+otherLen+1)*sizeof(char16_t));
235 if (buf) {
236 char16_t* str = (char16_t*)buf->data();
237 memcpy(str+myLen, other, (otherLen+1)*sizeof(char16_t));
238 mString = str;
239 return NO_ERROR;
240 }
241 return NO_MEMORY;
242}
243
244status_t String16::append(const char16_t* chrs, size_t otherLen)
245{
246 const size_t myLen = size();
247 if (myLen == 0) {
248 setTo(chrs, otherLen);
249 return NO_ERROR;
250 } else if (otherLen == 0) {
251 return NO_ERROR;
252 }
Steven Morelandd0648d82018-03-01 11:03:04 -0800253
254 if (myLen >= SIZE_MAX / sizeof(char16_t) - otherLen) {
255 android_errorWriteLog(0x534e4554, "73826242");
256 abort();
257 }
258
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800259 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
260 ->editResize((myLen+otherLen+1)*sizeof(char16_t));
261 if (buf) {
262 char16_t* str = (char16_t*)buf->data();
263 memcpy(str+myLen, chrs, otherLen*sizeof(char16_t));
264 str[myLen+otherLen] = 0;
265 mString = str;
266 return NO_ERROR;
267 }
268 return NO_MEMORY;
269}
270
271status_t String16::insert(size_t pos, const char16_t* chrs)
272{
273 return insert(pos, chrs, strlen16(chrs));
274}
275
276status_t String16::insert(size_t pos, const char16_t* chrs, size_t len)
277{
278 const size_t myLen = size();
279 if (myLen == 0) {
280 return setTo(chrs, len);
281 return NO_ERROR;
282 } else if (len == 0) {
283 return NO_ERROR;
284 }
285
286 if (pos > myLen) pos = myLen;
287
288 #if 0
289 printf("Insert in to %s: pos=%d, len=%d, myLen=%d, chrs=%s\n",
290 String8(*this).string(), pos,
291 len, myLen, String8(chrs, len).string());
292 #endif
293
294 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
295 ->editResize((myLen+len+1)*sizeof(char16_t));
296 if (buf) {
297 char16_t* str = (char16_t*)buf->data();
298 if (pos < myLen) {
299 memmove(str+pos+len, str+pos, (myLen-pos)*sizeof(char16_t));
300 }
301 memcpy(str+pos, chrs, len*sizeof(char16_t));
302 str[myLen+len] = 0;
303 mString = str;
304 #if 0
305 printf("Result (%d chrs): %s\n", size(), String8(*this).string());
306 #endif
307 return NO_ERROR;
308 }
309 return NO_MEMORY;
310}
311
312ssize_t String16::findFirst(char16_t c) const
313{
314 const char16_t* str = string();
315 const char16_t* p = str;
316 const char16_t* e = p + size();
317 while (p < e) {
318 if (*p == c) {
319 return p-str;
320 }
321 p++;
322 }
323 return -1;
324}
325
326ssize_t String16::findLast(char16_t c) const
327{
328 const char16_t* str = string();
329 const char16_t* p = str;
330 const char16_t* e = p + size();
331 while (p < e) {
332 e--;
333 if (*e == c) {
334 return e-str;
335 }
336 }
337 return -1;
338}
339
340bool String16::startsWith(const String16& prefix) const
341{
342 const size_t ps = prefix.size();
343 if (ps > size()) return false;
344 return strzcmp16(mString, ps, prefix.string(), ps) == 0;
345}
346
347bool String16::startsWith(const char16_t* prefix) const
348{
349 const size_t ps = strlen16(prefix);
350 if (ps > size()) return false;
351 return strncmp16(mString, prefix, ps) == 0;
352}
353
Michael Wright5bacef32016-05-09 14:43:31 +0100354bool String16::contains(const char16_t* chrs) const
355{
356 return strstr16(mString, chrs) != nullptr;
357}
358
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800359status_t String16::makeLower()
360{
361 const size_t N = size();
362 const char16_t* str = string();
363 char16_t* edit = NULL;
364 for (size_t i=0; i<N; i++) {
365 const char16_t v = str[i];
366 if (v >= 'A' && v <= 'Z') {
367 if (!edit) {
368 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)->edit();
369 if (!buf) {
370 return NO_MEMORY;
371 }
372 edit = (char16_t*)buf->data();
373 mString = str = edit;
374 }
375 edit[i] = tolower((char)v);
376 }
377 }
378 return NO_ERROR;
379}
380
381status_t String16::replaceAll(char16_t replaceThis, char16_t withThis)
382{
383 const size_t N = size();
384 const char16_t* str = string();
385 char16_t* edit = NULL;
386 for (size_t i=0; i<N; i++) {
387 if (str[i] == replaceThis) {
388 if (!edit) {
389 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)->edit();
390 if (!buf) {
391 return NO_MEMORY;
392 }
393 edit = (char16_t*)buf->data();
394 mString = str = edit;
395 }
396 edit[i] = withThis;
397 }
398 }
399 return NO_ERROR;
400}
401
402status_t String16::remove(size_t len, size_t begin)
403{
404 const size_t N = size();
405 if (begin >= N) {
406 SharedBuffer::bufferFromData(mString)->release();
407 mString = getEmptyString();
408 return NO_ERROR;
409 }
410 if ((begin+len) > N) len = N-begin;
411 if (begin == 0 && len == N) {
412 return NO_ERROR;
413 }
414
415 if (begin > 0) {
416 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
417 ->editResize((N+1)*sizeof(char16_t));
418 if (!buf) {
419 return NO_MEMORY;
420 }
421 char16_t* str = (char16_t*)buf->data();
422 memmove(str, str+begin, (N-begin+1)*sizeof(char16_t));
423 mString = str;
424 }
425 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
426 ->editResize((len+1)*sizeof(char16_t));
427 if (buf) {
428 char16_t* str = (char16_t*)buf->data();
429 str[len] = 0;
430 mString = str;
431 return NO_ERROR;
432 }
433 return NO_MEMORY;
434}
435
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800436}; // namespace android