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