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