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