Home | History | Annotate | Download | only in utils
      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 
     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 static inline char* getEmptyString()
     50 {
     51     gEmptyStringBuf->acquire();
     52     return gEmptyString;
     53 }
     54 
     55 void 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 
     70 void terminate_string8()
     71 {
     72     SharedBuffer::bufferFromData(gEmptyString)->release();
     73     gEmptyStringBuf = NULL;
     74     gEmptyString = NULL;
     75 }
     76 
     77 // ---------------------------------------------------------------------------
     78 
     79 static char* allocFromUTF8(const char* in, size_t len)
     80 {
     81     if (len > 0) {
     82         SharedBuffer* buf = SharedBuffer::alloc(len+1);
     83         LOG_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 
     96 static 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     LOG_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 
    116 static 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     LOG_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 
    141 String8::String8()
    142     : mString(getEmptyString())
    143 {
    144 }
    145 
    146 String8::String8(const String8& o)
    147     : mString(o.mString)
    148 {
    149     SharedBuffer::bufferFromData(mString)->acquire();
    150 }
    151 
    152 String8::String8(const char* o)
    153     : mString(allocFromUTF8(o, strlen(o)))
    154 {
    155     if (mString == NULL) {
    156         mString = getEmptyString();
    157     }
    158 }
    159 
    160 String8::String8(const char* o, size_t len)
    161     : mString(allocFromUTF8(o, len))
    162 {
    163     if (mString == NULL) {
    164         mString = getEmptyString();
    165     }
    166 }
    167 
    168 String8::String8(const String16& o)
    169     : mString(allocFromUTF16(o.string(), o.size()))
    170 {
    171 }
    172 
    173 String8::String8(const char16_t* o)
    174     : mString(allocFromUTF16(o, strlen16(o)))
    175 {
    176 }
    177 
    178 String8::String8(const char16_t* o, size_t len)
    179     : mString(allocFromUTF16(o, len))
    180 {
    181 }
    182 
    183 String8::String8(const char32_t* o)
    184     : mString(allocFromUTF32(o, strlen32(o)))
    185 {
    186 }
    187 
    188 String8::String8(const char32_t* o, size_t len)
    189     : mString(allocFromUTF32(o, len))
    190 {
    191 }
    192 
    193 String8::~String8()
    194 {
    195     SharedBuffer::bufferFromData(mString)->release();
    196 }
    197 
    198 String8 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 
    209 String8 String8::formatV(const char* fmt, va_list args)
    210 {
    211     String8 result;
    212     result.appendFormatV(fmt, args);
    213     return result;
    214 }
    215 
    216 void String8::clear() {
    217     SharedBuffer::bufferFromData(mString)->release();
    218     mString = getEmptyString();
    219 }
    220 
    221 void String8::setTo(const String8& other)
    222 {
    223     SharedBuffer::bufferFromData(other.mString)->acquire();
    224     SharedBuffer::bufferFromData(mString)->release();
    225     mString = other.mString;
    226 }
    227 
    228 status_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 
    239 status_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 
    250 status_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 
    261 status_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 
    272 status_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 
    285 status_t String8::append(const char* other)
    286 {
    287     return append(other, strlen(other));
    288 }
    289 
    290 status_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 
    301 status_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 
    312 status_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 
    328 status_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 
    345 char* 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 
    357 void String8::unlockBuffer()
    358 {
    359     unlockBuffer(strlen(mString));
    360 }
    361 
    362 status_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 
    379 ssize_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 
    390 void String8::toLower()
    391 {
    392     toLower(0, size());
    393 }
    394 
    395 void 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 
    414 void String8::toUpper()
    415 {
    416     toUpper(0, size());
    417 }
    418 
    419 void 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 
    438 size_t String8::getUtf32Length() const
    439 {
    440     return utf8_to_utf32_length(mString, length());
    441 }
    442 
    443 int32_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 
    448 void String8::getUtf32(char32_t* dst) const
    449 {
    450     utf8_to_utf32(mString, length(), dst);
    451 }
    452 
    453 TextOutput& operator<<(TextOutput& to, const String8& val)
    454 {
    455     to << val.string();
    456     return to;
    457 }
    458 
    459 // ---------------------------------------------------------------------------
    460 // Path functions
    461 
    462 void String8::setPathName(const char* name)
    463 {
    464     setPathName(name, strlen(name));
    465 }
    466 
    467 void 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 
    482 String8 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 
    494 String8 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 
    506 String8 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  */
    535 char* 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 
    558 String8 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 
    569 String8 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 
    581 String8& 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 
    618 String8& 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