blob: ab843f6e798b82ebdc769d6b27f633f752a021d3 [file] [log] [blame]
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001/*
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/String8.h>
18
19#include <utils/Log.h>
20#include <utils/String16.h>
21#include <utils/TextOutput.h>
22#include <utils/threads.h>
23
24#include <private/utils/Static.h>
25
26#include <ctype.h>
27
28namespace android {
29
30// ---------------------------------------------------------------------------
31
32static const uint32_t kByteMask = 0x000000BF;
33static const uint32_t kByteMark = 0x00000080;
34
35// Surrogates aren't valid for UTF-32 characters, so define some
36// constants that will let us screen them out.
37static const uint32_t kUnicodeSurrogateHighStart = 0x0000D800;
38static const uint32_t kUnicodeSurrogateHighEnd = 0x0000DBFF;
39static const uint32_t kUnicodeSurrogateLowStart = 0x0000DC00;
40static const uint32_t kUnicodeSurrogateLowEnd = 0x0000DFFF;
41static const uint32_t kUnicodeSurrogateStart = kUnicodeSurrogateHighStart;
42static const uint32_t kUnicodeSurrogateEnd = kUnicodeSurrogateLowEnd;
43
44// Mask used to set appropriate bits in first byte of UTF-8 sequence,
45// indexed by number of bytes in the sequence.
46static const uint32_t kFirstByteMark[] = {
47 0x00000000, 0x00000000, 0x000000C0, 0x000000E0, 0x000000F0
48};
49
50// Separator used by resource paths. This is not platform dependent contrary
51// to OS_PATH_SEPARATOR.
52#define RES_PATH_SEPARATOR '/'
53
54// Return number of utf8 bytes required for the character.
55static size_t utf32_to_utf8_bytes(uint32_t srcChar)
56{
57 size_t bytesToWrite;
58
59 // Figure out how many bytes the result will require.
60 if (srcChar < 0x00000080)
61 {
62 bytesToWrite = 1;
63 }
64 else if (srcChar < 0x00000800)
65 {
66 bytesToWrite = 2;
67 }
68 else if (srcChar < 0x00010000)
69 {
70 if ((srcChar < kUnicodeSurrogateStart)
71 || (srcChar > kUnicodeSurrogateEnd))
72 {
73 bytesToWrite = 3;
74 }
75 else
76 {
77 // Surrogates are invalid UTF-32 characters.
78 return 0;
79 }
80 }
81 // Max code point for Unicode is 0x0010FFFF.
82 else if (srcChar < 0x00110000)
83 {
84 bytesToWrite = 4;
85 }
86 else
87 {
88 // Invalid UTF-32 character.
89 return 0;
90 }
91
92 return bytesToWrite;
93}
94
95// Write out the source character to <dstP>.
96
97static void utf32_to_utf8(uint8_t* dstP, uint32_t srcChar, size_t bytes)
98{
99 dstP += bytes;
100 switch (bytes)
101 { /* note: everything falls through. */
102 case 4: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
103 case 3: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
104 case 2: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
105 case 1: *--dstP = (uint8_t)(srcChar | kFirstByteMark[bytes]);
106 }
107}
108
109// ---------------------------------------------------------------------------
110
111static SharedBuffer* gEmptyStringBuf = NULL;
112static char* gEmptyString = NULL;
113
114extern int gDarwinCantLoadAllObjects;
115int gDarwinIsReallyAnnoying;
116
117static inline char* getEmptyString()
118{
119 gEmptyStringBuf->acquire();
120 return gEmptyString;
121}
122
123void initialize_string8()
124{
125#ifdef LIBUTILS_NATIVE
126 // Bite me, Darwin!
127 gDarwinIsReallyAnnoying = gDarwinCantLoadAllObjects;
128#endif
129
130 SharedBuffer* buf = SharedBuffer::alloc(1);
131 char* str = (char*)buf->data();
132 *str = 0;
133 gEmptyStringBuf = buf;
134 gEmptyString = str;
135}
136
137void terminate_string8()
138{
139 SharedBuffer::bufferFromData(gEmptyString)->release();
140 gEmptyStringBuf = NULL;
141 gEmptyString = NULL;
142}
143
144// ---------------------------------------------------------------------------
145
146static char* allocFromUTF8(const char* in, size_t len)
147{
148 if (len > 0) {
149 SharedBuffer* buf = SharedBuffer::alloc(len+1);
150 LOG_ASSERT(buf, "Unable to allocate shared buffer");
151 if (buf) {
152 char* str = (char*)buf->data();
153 memcpy(str, in, len);
154 str[len] = 0;
155 return str;
156 }
157 return NULL;
158 }
159
160 return getEmptyString();
161}
162
163// Note: not dealing with expanding surrogate pairs.
164static char* allocFromUTF16(const char16_t* in, size_t len)
165{
166 if (len == 0) return getEmptyString();
167
168 size_t bytes = 0;
169 const char16_t* end = in+len;
170 const char16_t* p = in;
171
172 while (p < end) {
173 bytes += utf32_to_utf8_bytes(*p);
174 p++;
175 }
176
177 SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
178 LOG_ASSERT(buf, "Unable to allocate shared buffer");
179 if (buf) {
180 p = in;
181 char* str = (char*)buf->data();
182 char* d = str;
183 while (p < end) {
184 uint32_t c = *p++;
185 size_t len = utf32_to_utf8_bytes(c);
186 utf32_to_utf8((uint8_t*)d, c, len);
187 d += len;
188 }
189 *d = 0;
190
191 return str;
192 }
193
194 return getEmptyString();
195}
196
197// ---------------------------------------------------------------------------
198
199String8::String8()
200 : mString(getEmptyString())
201{
202}
203
204String8::String8(const String8& o)
205 : mString(o.mString)
206{
207 SharedBuffer::bufferFromData(mString)->acquire();
208}
209
210String8::String8(const char* o)
211 : mString(allocFromUTF8(o, strlen(o)))
212{
213 if (mString == NULL) {
214 mString = getEmptyString();
215 }
216}
217
218String8::String8(const char* o, size_t len)
219 : mString(allocFromUTF8(o, len))
220{
221 if (mString == NULL) {
222 mString = getEmptyString();
223 }
224}
225
226String8::String8(const String16& o)
227 : mString(allocFromUTF16(o.string(), o.size()))
228{
229}
230
231String8::String8(const char16_t* o)
232 : mString(allocFromUTF16(o, strlen16(o)))
233{
234}
235
236String8::String8(const char16_t* o, size_t len)
237 : mString(allocFromUTF16(o, len))
238{
239}
240
241String8::~String8()
242{
243 SharedBuffer::bufferFromData(mString)->release();
244}
245
246void String8::setTo(const String8& other)
247{
248 SharedBuffer::bufferFromData(other.mString)->acquire();
249 SharedBuffer::bufferFromData(mString)->release();
250 mString = other.mString;
251}
252
253status_t String8::setTo(const char* other)
254{
255 SharedBuffer::bufferFromData(mString)->release();
256 mString = allocFromUTF8(other, strlen(other));
257 if (mString) return NO_ERROR;
258
259 mString = getEmptyString();
260 return NO_MEMORY;
261}
262
263status_t String8::setTo(const char* other, size_t len)
264{
265 SharedBuffer::bufferFromData(mString)->release();
266 mString = allocFromUTF8(other, len);
267 if (mString) return NO_ERROR;
268
269 mString = getEmptyString();
270 return NO_MEMORY;
271}
272
273status_t String8::setTo(const char16_t* other, size_t len)
274{
275 SharedBuffer::bufferFromData(mString)->release();
276 mString = allocFromUTF16(other, len);
277 if (mString) return NO_ERROR;
278
279 mString = getEmptyString();
280 return NO_MEMORY;
281}
282
283status_t String8::append(const String8& other)
284{
285 const size_t otherLen = other.bytes();
286 if (bytes() == 0) {
287 setTo(other);
288 return NO_ERROR;
289 } else if (otherLen == 0) {
290 return NO_ERROR;
291 }
292
293 return real_append(other.string(), otherLen);
294}
295
296status_t String8::append(const char* other)
297{
298 return append(other, strlen(other));
299}
300
301status_t String8::append(const char* other, size_t otherLen)
302{
303 if (bytes() == 0) {
304 return setTo(other, otherLen);
305 } else if (otherLen == 0) {
306 return NO_ERROR;
307 }
308
309 return real_append(other, otherLen);
310}
311
312status_t String8::real_append(const char* other, size_t otherLen)
313{
314 const size_t myLen = bytes();
315
316 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
317 ->editResize(myLen+otherLen+1);
318 if (buf) {
319 char* str = (char*)buf->data();
320 memcpy(str+myLen, other, otherLen+1);
321 mString = str;
322 return NO_ERROR;
323 }
324 return NO_MEMORY;
325}
326
327char* String8::lockBuffer(size_t size)
328{
329 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
330 ->editResize(size+1);
331 if (buf) {
332 char* str = (char*)buf->data();
333 mString = str;
334 return str;
335 }
336 return NULL;
337}
338
339void String8::unlockBuffer()
340{
341 unlockBuffer(strlen(mString));
342}
343
344status_t String8::unlockBuffer(size_t size)
345{
346 if (size != this->size()) {
347 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
348 ->editResize(size+1);
349 if (buf) {
350 char* str = (char*)buf->data();
351 str[size] = 0;
352 mString = str;
353 return NO_ERROR;
354 }
355 }
356
357 return NO_MEMORY;
358}
359
360ssize_t String8::find(const char* other, size_t start) const
361{
362 size_t len = size();
363 if (start >= len) {
364 return -1;
365 }
366 const char* s = mString+start;
367 const char* p = strstr(s, other);
368 return p ? p-mString : -1;
369}
370
371void String8::toLower()
372{
373 toLower(0, size());
374}
375
376void String8::toLower(size_t start, size_t length)
377{
378 const size_t len = size();
379 if (start >= len) {
380 return;
381 }
382 if (start+length > len) {
383 length = len-start;
384 }
385 char* buf = lockBuffer(len);
386 buf += start;
387 while (length > 0) {
388 *buf = tolower(*buf);
389 buf++;
390 length--;
391 }
392 unlockBuffer(len);
393}
394
395void String8::toUpper()
396{
397 toUpper(0, size());
398}
399
400void String8::toUpper(size_t start, size_t length)
401{
402 const size_t len = size();
403 if (start >= len) {
404 return;
405 }
406 if (start+length > len) {
407 length = len-start;
408 }
409 char* buf = lockBuffer(len);
410 buf += start;
411 while (length > 0) {
412 *buf = toupper(*buf);
413 buf++;
414 length--;
415 }
416 unlockBuffer(len);
417}
418
419TextOutput& operator<<(TextOutput& to, const String8& val)
420{
421 to << val.string();
422 return to;
423}
424
425// ---------------------------------------------------------------------------
426// Path functions
427
428
429void String8::setPathName(const char* name)
430{
431 setPathName(name, strlen(name));
432}
433
434void String8::setPathName(const char* name, size_t len)
435{
436 char* buf = lockBuffer(len);
437
438 memcpy(buf, name, len);
439
440 // remove trailing path separator, if present
441 if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
442 len--;
443
444 buf[len] = '\0';
445
446 unlockBuffer(len);
447}
448
449String8 String8::getPathLeaf(void) const
450{
451 const char* cp;
452 const char*const buf = mString;
453
454 cp = strrchr(buf, OS_PATH_SEPARATOR);
455 if (cp == NULL)
456 return String8(*this);
457 else
458 return String8(cp+1);
459}
460
461String8 String8::getPathDir(void) const
462{
463 const char* cp;
464 const char*const str = mString;
465
466 cp = strrchr(str, OS_PATH_SEPARATOR);
467 if (cp == NULL)
468 return String8("");
469 else
470 return String8(str, cp - str);
471}
472
473String8 String8::walkPath(String8* outRemains) const
474{
475 const char* cp;
476 const char*const str = mString;
477 const char* buf = str;
478
479 cp = strchr(buf, OS_PATH_SEPARATOR);
480 if (cp == buf) {
481 // don't include a leading '/'.
482 buf = buf+1;
483 cp = strchr(buf, OS_PATH_SEPARATOR);
484 }
485
486 if (cp == NULL) {
487 String8 res = buf != str ? String8(buf) : *this;
488 if (outRemains) *outRemains = String8("");
489 return res;
490 }
491
492 String8 res(buf, cp-buf);
493 if (outRemains) *outRemains = String8(cp+1);
494 return res;
495}
496
497/*
498 * Helper function for finding the start of an extension in a pathname.
499 *
500 * Returns a pointer inside mString, or NULL if no extension was found.
501 */
502char* String8::find_extension(void) const
503{
504 const char* lastSlash;
505 const char* lastDot;
506 int extLen;
507 const char* const str = mString;
508
509 // only look at the filename
510 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
511 if (lastSlash == NULL)
512 lastSlash = str;
513 else
514 lastSlash++;
515
516 // find the last dot
517 lastDot = strrchr(lastSlash, '.');
518 if (lastDot == NULL)
519 return NULL;
520
521 // looks good, ship it
522 return const_cast<char*>(lastDot);
523}
524
525String8 String8::getPathExtension(void) const
526{
527 char* ext;
528
529 ext = find_extension();
530 if (ext != NULL)
531 return String8(ext);
532 else
533 return String8("");
534}
535
536String8 String8::getBasePath(void) const
537{
538 char* ext;
539 const char* const str = mString;
540
541 ext = find_extension();
542 if (ext == NULL)
543 return String8(*this);
544 else
545 return String8(str, ext - str);
546}
547
548String8& String8::appendPath(const char* name)
549{
550 // TODO: The test below will fail for Win32 paths. Fix later or ignore.
551 if (name[0] != OS_PATH_SEPARATOR) {
552 if (*name == '\0') {
553 // nothing to do
554 return *this;
555 }
556
557 size_t len = length();
558 if (len == 0) {
559 // no existing filename, just use the new one
560 setPathName(name);
561 return *this;
562 }
563
564 // make room for oldPath + '/' + newPath
565 int newlen = strlen(name);
566
567 char* buf = lockBuffer(len+1+newlen);
568
569 // insert a '/' if needed
570 if (buf[len-1] != OS_PATH_SEPARATOR)
571 buf[len++] = OS_PATH_SEPARATOR;
572
573 memcpy(buf+len, name, newlen+1);
574 len += newlen;
575
576 unlockBuffer(len);
577
578 return *this;
579 } else {
580 setPathName(name);
581 return *this;
582 }
583}
584
585String8& String8::convertToResPath()
586{
587#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
588 size_t len = length();
589 if (len > 0) {
590 char * buf = lockBuffer(len);
591 for (char * end = buf + len; buf < end; ++buf) {
592 if (*buf == OS_PATH_SEPARATOR)
593 *buf = RES_PATH_SEPARATOR;
594 }
595 unlockBuffer(len);
596 }
597#endif
598 return *this;
599}
600
601
602}; // namespace android