Line data Source code
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/String8.h>
18 :
19 : #include <utils/Log.h>
20 : #include <utils/Unicode.h>
21 : #include <utils/SharedBuffer.h>
22 : #include <utils/String16.h>
23 : #include <utils/threads.h>
24 :
25 : #include <ctype.h>
26 :
27 : /*
28 : * Functions outside android is below the namespace stagefright, since they use
29 : * functions and constants in android namespace.
30 : */
31 :
32 : // ---------------------------------------------------------------------------
33 :
34 : namespace stagefright {
35 :
36 : // Separator used by resource paths. This is not platform dependent contrary
37 : // to OS_PATH_SEPARATOR.
38 : #define RES_PATH_SEPARATOR '/'
39 :
40 : static SharedBuffer* gEmptyStringBuf = NULL;
41 : static char* gEmptyString = NULL;
42 :
43 : extern int gDarwinCantLoadAllObjects;
44 : int gDarwinIsReallyAnnoying;
45 :
46 : void initialize_string8();
47 :
48 0 : static inline char* getEmptyString()
49 : {
50 0 : gEmptyStringBuf->acquire();
51 0 : return gEmptyString;
52 : }
53 :
54 3 : void initialize_string8()
55 : {
56 : // HACK: This dummy dependency forces linking libutils Static.cpp,
57 : // which is needed to initialize String8/String16 classes.
58 : // These variables are named for Darwin, but are needed elsewhere too,
59 : // including static linking on any platform.
60 3 : gDarwinIsReallyAnnoying = gDarwinCantLoadAllObjects;
61 :
62 3 : SharedBuffer* buf = SharedBuffer::alloc(1);
63 3 : char* str = (char*)buf->data();
64 3 : *str = 0;
65 3 : gEmptyStringBuf = buf;
66 3 : gEmptyString = str;
67 3 : }
68 :
69 0 : void terminate_string8()
70 : {
71 0 : SharedBuffer::bufferFromData(gEmptyString)->release();
72 0 : gEmptyStringBuf = NULL;
73 0 : gEmptyString = NULL;
74 0 : }
75 :
76 : // ---------------------------------------------------------------------------
77 :
78 0 : static char* allocFromUTF8(const char* in, size_t len)
79 : {
80 0 : if (len > 0) {
81 0 : SharedBuffer* buf = SharedBuffer::alloc(len+1);
82 : ALOG_ASSERT(buf, "Unable to allocate shared buffer");
83 0 : if (buf) {
84 0 : char* str = (char*)buf->data();
85 0 : memcpy(str, in, len);
86 0 : str[len] = 0;
87 0 : return str;
88 : }
89 0 : return NULL;
90 : }
91 :
92 0 : return getEmptyString();
93 : }
94 :
95 0 : static char* allocFromUTF16(const char16_t* in, size_t len)
96 : {
97 0 : if (len == 0) return getEmptyString();
98 :
99 0 : const ssize_t bytes = utf16_to_utf8_length(in, len);
100 0 : if (bytes < 0) {
101 0 : return getEmptyString();
102 : }
103 :
104 0 : SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
105 : ALOG_ASSERT(buf, "Unable to allocate shared buffer");
106 0 : if (!buf) {
107 0 : return getEmptyString();
108 : }
109 :
110 0 : char* str = (char*)buf->data();
111 0 : utf16_to_utf8(in, len, str);
112 0 : return str;
113 : }
114 :
115 0 : static char* allocFromUTF32(const char32_t* in, size_t len)
116 : {
117 0 : if (len == 0) {
118 0 : return getEmptyString();
119 : }
120 :
121 0 : const ssize_t bytes = utf32_to_utf8_length(in, len);
122 0 : if (bytes < 0) {
123 0 : return getEmptyString();
124 : }
125 :
126 0 : SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
127 : ALOG_ASSERT(buf, "Unable to allocate shared buffer");
128 0 : if (!buf) {
129 0 : return getEmptyString();
130 : }
131 :
132 0 : char* str = (char*) buf->data();
133 0 : utf32_to_utf8(in, len, str);
134 :
135 0 : return str;
136 : }
137 :
138 : // ---------------------------------------------------------------------------
139 :
140 0 : String8::String8()
141 0 : : mString(0)
142 : {
143 : char* data = static_cast<char*>(
144 0 : SharedBuffer::alloc(sizeof(char))->data());
145 0 : data[0] = 0;
146 0 : mString = data;
147 0 : }
148 :
149 0 : String8::String8(const String8& o)
150 0 : : mString(o.mString)
151 : {
152 0 : SharedBuffer::bufferFromData(mString)->acquire();
153 0 : }
154 :
155 0 : String8::String8(const char* o)
156 0 : : mString(allocFromUTF8(o, strlen(o)))
157 : {
158 0 : if (mString == NULL) {
159 0 : mString = getEmptyString();
160 : }
161 0 : }
162 :
163 0 : String8::String8(const char* o, size_t len)
164 0 : : mString(allocFromUTF8(o, len))
165 : {
166 0 : if (mString == NULL) {
167 0 : mString = getEmptyString();
168 : }
169 0 : }
170 :
171 0 : String8::String8(const String16& o)
172 0 : : mString(allocFromUTF16(o.string(), o.size()))
173 : {
174 0 : }
175 :
176 0 : String8::String8(const char16_t* o)
177 0 : : mString(allocFromUTF16(o, strlen16(o)))
178 : {
179 0 : }
180 :
181 0 : String8::String8(const char16_t* o, size_t len)
182 0 : : mString(allocFromUTF16(o, len))
183 : {
184 0 : }
185 :
186 0 : String8::String8(const char32_t* o)
187 0 : : mString(allocFromUTF32(o, strlen32(o)))
188 : {
189 0 : }
190 :
191 0 : String8::String8(const char32_t* o, size_t len)
192 0 : : mString(allocFromUTF32(o, len))
193 : {
194 0 : }
195 :
196 0 : String8::~String8()
197 : {
198 0 : SharedBuffer::bufferFromData(mString)->release();
199 0 : }
200 :
201 0 : String8 String8::format(const char* fmt, ...)
202 : {
203 : va_list args;
204 0 : va_start(args, fmt);
205 :
206 0 : String8 result(formatV(fmt, args));
207 :
208 0 : va_end(args);
209 0 : return result;
210 : }
211 :
212 0 : String8 String8::formatV(const char* fmt, va_list args)
213 : {
214 0 : String8 result;
215 0 : result.appendFormatV(fmt, args);
216 0 : return result;
217 : }
218 :
219 0 : void String8::clear() {
220 0 : SharedBuffer::bufferFromData(mString)->release();
221 0 : mString = getEmptyString();
222 0 : }
223 :
224 0 : void String8::setTo(const String8& other)
225 : {
226 0 : SharedBuffer::bufferFromData(other.mString)->acquire();
227 0 : SharedBuffer::bufferFromData(mString)->release();
228 0 : mString = other.mString;
229 0 : }
230 :
231 0 : status_t String8::setTo(const char* other)
232 : {
233 0 : const char *newString = allocFromUTF8(other, strlen(other));
234 0 : SharedBuffer::bufferFromData(mString)->release();
235 0 : mString = newString;
236 0 : if (mString) return NO_ERROR;
237 :
238 0 : mString = getEmptyString();
239 0 : return NO_MEMORY;
240 : }
241 :
242 0 : status_t String8::setTo(const char* other, size_t len)
243 : {
244 0 : const char *newString = allocFromUTF8(other, len);
245 0 : SharedBuffer::bufferFromData(mString)->release();
246 0 : mString = newString;
247 0 : if (mString) return NO_ERROR;
248 :
249 0 : mString = getEmptyString();
250 0 : return NO_MEMORY;
251 : }
252 :
253 0 : status_t String8::setTo(const char16_t* other, size_t len)
254 : {
255 0 : const char *newString = allocFromUTF16(other, len);
256 0 : SharedBuffer::bufferFromData(mString)->release();
257 0 : mString = newString;
258 0 : if (mString) return NO_ERROR;
259 :
260 0 : mString = getEmptyString();
261 0 : return NO_MEMORY;
262 : }
263 :
264 0 : status_t String8::setTo(const char32_t* other, size_t len)
265 : {
266 0 : const char *newString = allocFromUTF32(other, len);
267 0 : SharedBuffer::bufferFromData(mString)->release();
268 0 : mString = newString;
269 0 : if (mString) return NO_ERROR;
270 :
271 0 : mString = getEmptyString();
272 0 : return NO_MEMORY;
273 : }
274 :
275 0 : status_t String8::append(const String8& other)
276 : {
277 0 : const size_t otherLen = other.bytes();
278 0 : if (bytes() == 0) {
279 0 : setTo(other);
280 0 : return NO_ERROR;
281 0 : } else if (otherLen == 0) {
282 0 : return NO_ERROR;
283 : }
284 :
285 0 : return real_append(other.string(), otherLen);
286 : }
287 :
288 0 : status_t String8::append(const char* other)
289 : {
290 0 : return append(other, strlen(other));
291 : }
292 :
293 0 : status_t String8::append(const char* other, size_t otherLen)
294 : {
295 0 : if (bytes() == 0) {
296 0 : return setTo(other, otherLen);
297 0 : } else if (otherLen == 0) {
298 0 : return NO_ERROR;
299 : }
300 :
301 0 : return real_append(other, otherLen);
302 : }
303 :
304 0 : status_t String8::appendFormat(const char* fmt, ...)
305 : {
306 : va_list args;
307 0 : va_start(args, fmt);
308 :
309 0 : status_t result = appendFormatV(fmt, args);
310 :
311 0 : va_end(args);
312 0 : return result;
313 : }
314 :
315 0 : status_t String8::appendFormatV(const char* fmt, va_list args)
316 : {
317 0 : int result = NO_ERROR;
318 : #ifndef _MSC_VER
319 : va_list o;
320 0 : va_copy(o, args);
321 : #endif
322 0 : int n = vsnprintf(NULL, 0, fmt, args);
323 0 : if (n != 0) {
324 0 : size_t oldLength = length();
325 0 : char* buf = lockBuffer(oldLength + n);
326 0 : if (buf) {
327 : #ifdef _MSC_VER
328 : vsnprintf(buf + oldLength, n + 1, fmt, args);
329 : #else
330 0 : vsnprintf(buf + oldLength, n + 1, fmt, o);
331 : #endif
332 : } else {
333 0 : result = NO_MEMORY;
334 : }
335 : }
336 : #ifndef _MSC_VER
337 0 : va_end(o);
338 : #endif
339 0 : return result;
340 : }
341 :
342 0 : status_t String8::real_append(const char* other, size_t otherLen)
343 : {
344 0 : const size_t myLen = bytes();
345 :
346 0 : SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
347 0 : ->editResize(myLen+otherLen+1);
348 0 : if (buf) {
349 0 : char* str = (char*)buf->data();
350 0 : mString = str;
351 0 : str += myLen;
352 0 : memcpy(str, other, otherLen);
353 0 : str[otherLen] = '\0';
354 0 : return NO_ERROR;
355 : }
356 0 : return NO_MEMORY;
357 : }
358 :
359 0 : char* String8::lockBuffer(size_t size)
360 : {
361 0 : SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
362 0 : ->editResize(size+1);
363 0 : if (buf) {
364 0 : char* str = (char*)buf->data();
365 0 : mString = str;
366 0 : return str;
367 : }
368 0 : return NULL;
369 : }
370 :
371 0 : void String8::unlockBuffer()
372 : {
373 0 : unlockBuffer(strlen(mString));
374 0 : }
375 :
376 0 : status_t String8::unlockBuffer(size_t size)
377 : {
378 0 : if (size != this->size()) {
379 0 : SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
380 0 : ->editResize(size+1);
381 0 : if (! buf) {
382 0 : return NO_MEMORY;
383 : }
384 :
385 0 : char* str = (char*)buf->data();
386 0 : str[size] = 0;
387 0 : mString = str;
388 : }
389 :
390 0 : return NO_ERROR;
391 : }
392 :
393 0 : ssize_t String8::find(const char* other, size_t start) const
394 : {
395 0 : size_t len = size();
396 0 : if (start >= len) {
397 0 : return -1;
398 : }
399 0 : const char* s = mString+start;
400 0 : const char* p = strstr(s, other);
401 0 : return p ? p-mString : -1;
402 : }
403 :
404 0 : void String8::toLower()
405 : {
406 0 : toLower(0, size());
407 0 : }
408 :
409 0 : void String8::toLower(size_t start, size_t length)
410 : {
411 0 : const size_t len = size();
412 0 : if (start >= len) {
413 0 : return;
414 : }
415 0 : if (start+length > len) {
416 0 : length = len-start;
417 : }
418 0 : char* buf = lockBuffer(len);
419 0 : buf += start;
420 0 : while (length > 0) {
421 0 : *buf = tolower(*buf);
422 0 : buf++;
423 0 : length--;
424 : }
425 0 : unlockBuffer(len);
426 : }
427 :
428 0 : void String8::toUpper()
429 : {
430 0 : toUpper(0, size());
431 0 : }
432 :
433 0 : void String8::toUpper(size_t start, size_t length)
434 : {
435 0 : const size_t len = size();
436 0 : if (start >= len) {
437 0 : return;
438 : }
439 0 : if (start+length > len) {
440 0 : length = len-start;
441 : }
442 0 : char* buf = lockBuffer(len);
443 0 : buf += start;
444 0 : while (length > 0) {
445 0 : *buf = toupper(*buf);
446 0 : buf++;
447 0 : length--;
448 : }
449 0 : unlockBuffer(len);
450 : }
451 :
452 0 : size_t String8::getUtf32Length() const
453 : {
454 0 : return utf8_to_utf32_length(mString, length());
455 : }
456 :
457 0 : int32_t String8::getUtf32At(size_t index, size_t *next_index) const
458 : {
459 0 : return utf32_from_utf8_at(mString, length(), index, next_index);
460 : }
461 :
462 0 : void String8::getUtf32(char32_t* dst) const
463 : {
464 0 : utf8_to_utf32(mString, length(), dst);
465 0 : }
466 :
467 : // ---------------------------------------------------------------------------
468 : // Path functions
469 :
470 : #if 0
471 :
472 : void String8::setPathName(const char* name)
473 : {
474 : setPathName(name, strlen(name));
475 : }
476 :
477 : void String8::setPathName(const char* name, size_t len)
478 : {
479 : char* buf = lockBuffer(len);
480 :
481 : memcpy(buf, name, len);
482 :
483 : // remove trailing path separator, if present
484 : if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
485 : len--;
486 :
487 : buf[len] = '\0';
488 :
489 : unlockBuffer(len);
490 : }
491 :
492 : String8 String8::getPathLeaf(void) const
493 : {
494 : const char* cp;
495 : const char*const buf = mString;
496 :
497 : cp = strrchr(buf, OS_PATH_SEPARATOR);
498 : if (cp == NULL)
499 : return String8(*this);
500 : else
501 : return String8(cp+1);
502 : }
503 :
504 : String8 String8::getPathDir(void) const
505 : {
506 : const char* cp;
507 : const char*const str = mString;
508 :
509 : cp = strrchr(str, OS_PATH_SEPARATOR);
510 : if (cp == NULL)
511 : return String8("");
512 : else
513 : return String8(str, cp - str);
514 : }
515 :
516 : String8 String8::walkPath(String8* outRemains) const
517 : {
518 : const char* cp;
519 : const char*const str = mString;
520 : const char* buf = str;
521 :
522 : cp = strchr(buf, OS_PATH_SEPARATOR);
523 : if (cp == buf) {
524 : // don't include a leading '/'.
525 : buf = buf+1;
526 : cp = strchr(buf, OS_PATH_SEPARATOR);
527 : }
528 :
529 : if (cp == NULL) {
530 : String8 res = buf != str ? String8(buf) : *this;
531 : if (outRemains) *outRemains = String8("");
532 : return res;
533 : }
534 :
535 : String8 res(buf, cp-buf);
536 : if (outRemains) *outRemains = String8(cp+1);
537 : return res;
538 : }
539 :
540 : /*
541 : * Helper function for finding the start of an extension in a pathname.
542 : *
543 : * Returns a pointer inside mString, or NULL if no extension was found.
544 : */
545 : char* String8::find_extension(void) const
546 : {
547 : const char* lastSlash;
548 : const char* lastDot;
549 : int extLen;
550 : const char* const str = mString;
551 :
552 : // only look at the filename
553 : lastSlash = strrchr(str, OS_PATH_SEPARATOR);
554 : if (lastSlash == NULL)
555 : lastSlash = str;
556 : else
557 : lastSlash++;
558 :
559 : // find the last dot
560 : lastDot = strrchr(lastSlash, '.');
561 : if (lastDot == NULL)
562 : return NULL;
563 :
564 : // looks good, ship it
565 : return const_cast<char*>(lastDot);
566 : }
567 :
568 : String8 String8::getPathExtension(void) const
569 : {
570 : char* ext;
571 :
572 : ext = find_extension();
573 : if (ext != NULL)
574 : return String8(ext);
575 : else
576 : return String8("");
577 : }
578 :
579 : String8 String8::getBasePath(void) const
580 : {
581 : char* ext;
582 : const char* const str = mString;
583 :
584 : ext = find_extension();
585 : if (ext == NULL)
586 : return String8(*this);
587 : else
588 : return String8(str, ext - str);
589 : }
590 :
591 : String8& String8::appendPath(const char* name)
592 : {
593 : // TODO: The test below will fail for Win32 paths. Fix later or ignore.
594 : if (name[0] != OS_PATH_SEPARATOR) {
595 : if (*name == '\0') {
596 : // nothing to do
597 : return *this;
598 : }
599 :
600 : size_t len = length();
601 : if (len == 0) {
602 : // no existing filename, just use the new one
603 : setPathName(name);
604 : return *this;
605 : }
606 :
607 : // make room for oldPath + '/' + newPath
608 : int newlen = strlen(name);
609 :
610 : char* buf = lockBuffer(len+1+newlen);
611 :
612 : // insert a '/' if needed
613 : if (buf[len-1] != OS_PATH_SEPARATOR)
614 : buf[len++] = OS_PATH_SEPARATOR;
615 :
616 : memcpy(buf+len, name, newlen+1);
617 : len += newlen;
618 :
619 : unlockBuffer(len);
620 :
621 : return *this;
622 : } else {
623 : setPathName(name);
624 : return *this;
625 : }
626 : }
627 :
628 : String8& String8::convertToResPath()
629 : {
630 : #if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
631 : size_t len = length();
632 : if (len > 0) {
633 : char * buf = lockBuffer(len);
634 : for (char * end = buf + len; buf < end; ++buf) {
635 : if (*buf == OS_PATH_SEPARATOR)
636 : *buf = RES_PATH_SEPARATOR;
637 : }
638 : unlockBuffer(len);
639 : }
640 : #endif
641 : return *this;
642 : }
643 :
644 : #endif
645 :
646 : }; // namespace stagefright
|