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