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