tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

charstr.cpp (8479B)


      1 // © 2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 *******************************************************************************
      5 *   Copyright (C) 2010-2015, International Business Machines
      6 *   Corporation and others.  All Rights Reserved.
      7 *******************************************************************************
      8 *   file name:  charstr.cpp
      9 *   encoding:   UTF-8
     10 *   tab size:   8 (not used)
     11 *   indentation:4
     12 *
     13 *   created on: 2010may19
     14 *   created by: Markus W. Scherer
     15 */
     16 
     17 #include <cstdlib>
     18 
     19 #include "unicode/utypes.h"
     20 #include "unicode/putil.h"
     21 #include "charstr.h"
     22 #include "cmemory.h"
     23 #include "cstring.h"
     24 #include "uinvchar.h"
     25 #include "ustr_imp.h"
     26 
     27 U_NAMESPACE_BEGIN
     28 
     29 CharString::CharString(CharString&& src) noexcept
     30        : buffer(std::move(src.buffer)), len(src.len) {
     31    src.len = 0;  // not strictly necessary because we make no guarantees on the source string
     32 }
     33 
     34 CharString& CharString::operator=(CharString&& src) noexcept {
     35    buffer = std::move(src.buffer);
     36    len = src.len;
     37    src.len = 0;  // not strictly necessary because we make no guarantees on the source string
     38    return *this;
     39 }
     40 
     41 char *CharString::cloneData(UErrorCode &errorCode) const {
     42    if (U_FAILURE(errorCode)) { return nullptr; }
     43    char *p = static_cast<char *>(uprv_malloc(len + 1));
     44    if (p == nullptr) {
     45        errorCode = U_MEMORY_ALLOCATION_ERROR;
     46        return nullptr;
     47    }
     48    uprv_memcpy(p, buffer.getAlias(), len + 1);
     49    return p;
     50 }
     51 
     52 int32_t CharString::extract(char *dest, int32_t capacity, UErrorCode &errorCode) const {
     53    if (U_FAILURE(errorCode)) { return len; }
     54    if (capacity < 0 || (capacity > 0 && dest == nullptr)) {
     55        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
     56        return len;
     57    }
     58    const char *src = buffer.getAlias();
     59    if (0 < len && len <= capacity && src != dest) {
     60        uprv_memcpy(dest, src, len);
     61    }
     62    return u_terminateChars(dest, capacity, len, &errorCode);
     63 }
     64 
     65 CharString &CharString::copyFrom(const CharString &s, UErrorCode &errorCode) {
     66    if(U_SUCCESS(errorCode) && this!=&s && ensureCapacity(s.len+1, 0, errorCode)) {
     67        len=s.len;
     68        uprv_memcpy(buffer.getAlias(), s.buffer.getAlias(), len+1);
     69    }
     70    return *this;
     71 }
     72 
     73 CharString &CharString::copyFrom(StringPiece s, UErrorCode &errorCode) {
     74    if (U_FAILURE(errorCode)) {
     75        return *this;
     76    }
     77    len = 0;
     78    append(s, errorCode);
     79    return *this;
     80 }
     81 
     82 int32_t CharString::lastIndexOf(char c) const {
     83    for(int32_t i=len; i>0;) {
     84        if(buffer[--i]==c) {
     85            return i;
     86        }
     87    }
     88    return -1;
     89 }
     90 
     91 bool CharString::contains(StringPiece s) const {
     92    if (s.empty()) { return false; }
     93    const char *p = buffer.getAlias();
     94    int32_t lastStart = len - s.length();
     95    for (int32_t i = 0; i <= lastStart; ++i) {
     96        if (uprv_memcmp(p + i, s.data(), s.length()) == 0) {
     97            return true;
     98        }
     99    }
    100    return false;
    101 }
    102 
    103 CharString &CharString::truncate(int32_t newLength) {
    104    if(newLength<0) {
    105        newLength=0;
    106    }
    107    if(newLength<len) {
    108        buffer[len=newLength]=0;
    109    }
    110    return *this;
    111 }
    112 
    113 CharString &CharString::append(char c, UErrorCode &errorCode) {
    114    if(ensureCapacity(len+2, 0, errorCode)) {
    115        buffer[len++]=c;
    116        buffer[len]=0;
    117    }
    118    return *this;
    119 }
    120 
    121 CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &errorCode) {
    122    if(U_FAILURE(errorCode)) {
    123        return *this;
    124    }
    125    if(sLength<-1 || (s==nullptr && sLength!=0)) {
    126        errorCode=U_ILLEGAL_ARGUMENT_ERROR;
    127        return *this;
    128    }
    129    if(sLength<0) {
    130        sLength= static_cast<int32_t>(uprv_strlen(s));
    131    }
    132    if(sLength>0) {
    133        if(s==(buffer.getAlias()+len)) {
    134            // The caller wrote into the getAppendBuffer().
    135            if(sLength>=(buffer.getCapacity()-len)) {
    136                // The caller wrote too much.
    137                errorCode=U_INTERNAL_PROGRAM_ERROR;
    138            } else {
    139                buffer[len+=sLength]=0;
    140            }
    141        } else if(buffer.getAlias()<=s && s<(buffer.getAlias()+len) &&
    142                  sLength>=(buffer.getCapacity()-len)
    143        ) {
    144            // (Part of) this string is appended to itself which requires reallocation,
    145            // so we have to make a copy of the substring and append that.
    146            return append(CharString(s, sLength, errorCode), errorCode);
    147        } else if(ensureCapacity(len+sLength+1, 0, errorCode)) {
    148            uprv_memcpy(buffer.getAlias()+len, s, sLength);
    149            buffer[len+=sLength]=0;
    150        }
    151    }
    152    return *this;
    153 }
    154 
    155 CharString &CharString::appendNumber(int64_t number, UErrorCode &status) {
    156    if (number < 0) {
    157        this->append('-', status);
    158        if (U_FAILURE(status)) {
    159            return *this;
    160        }
    161    }
    162 
    163    if (number == 0) {
    164        this->append('0', status);
    165        return *this;
    166    }
    167 
    168    int32_t numLen = 0;
    169    while (number != 0) {
    170        int32_t residue = number % 10;
    171        number /= 10;
    172        this->append(std::abs(residue) + '0', status);
    173        numLen++;
    174        if (U_FAILURE(status)) {
    175            return *this;
    176        }
    177    }
    178 
    179    int32_t start = this->length() - numLen, end = this->length() - 1;
    180    while(start < end) {
    181        std::swap(this->data()[start++], this->data()[end--]);
    182    }
    183 
    184    return *this;
    185 }
    186 
    187 char *CharString::getAppendBuffer(int32_t minCapacity,
    188                                  int32_t desiredCapacityHint,
    189                                  int32_t &resultCapacity,
    190                                  UErrorCode &errorCode) {
    191    if(U_FAILURE(errorCode)) {
    192        resultCapacity=0;
    193        return nullptr;
    194    }
    195    int32_t appendCapacity=buffer.getCapacity()-len-1;  // -1 for NUL
    196    if(appendCapacity>=minCapacity) {
    197        resultCapacity=appendCapacity;
    198        return buffer.getAlias()+len;
    199    }
    200    if(ensureCapacity(len+minCapacity+1, len+desiredCapacityHint+1, errorCode)) {
    201        resultCapacity=buffer.getCapacity()-len-1;
    202        return buffer.getAlias()+len;
    203    }
    204    resultCapacity=0;
    205    return nullptr;
    206 }
    207 
    208 CharString &CharString::appendInvariantChars(const UnicodeString &s, UErrorCode &errorCode) {
    209    return appendInvariantChars(s.getBuffer(), s.length(), errorCode);
    210 }
    211 
    212 CharString &CharString::appendInvariantChars(const char16_t* uchars, int32_t ucharsLen, UErrorCode &errorCode) {
    213    if(U_FAILURE(errorCode)) {
    214        return *this;
    215    }
    216    if (!uprv_isInvariantUString(uchars, ucharsLen)) {
    217        errorCode = U_INVARIANT_CONVERSION_ERROR;
    218        return *this;
    219    }
    220    if(ensureCapacity(len+ucharsLen+1, 0, errorCode)) {
    221        u_UCharsToChars(uchars, buffer.getAlias()+len, ucharsLen);
    222        len += ucharsLen;
    223        buffer[len] = 0;
    224    }
    225    return *this;
    226 }
    227 
    228 UBool CharString::ensureCapacity(int32_t capacity,
    229                                 int32_t desiredCapacityHint,
    230                                 UErrorCode &errorCode) {
    231    if(U_FAILURE(errorCode)) {
    232        return false;
    233    }
    234    if(capacity>buffer.getCapacity()) {
    235        if(desiredCapacityHint==0) {
    236            desiredCapacityHint=capacity+buffer.getCapacity();
    237        }
    238        if( (desiredCapacityHint<=capacity || buffer.resize(desiredCapacityHint, len+1)==nullptr) &&
    239            buffer.resize(capacity, len+1)==nullptr
    240        ) {
    241            errorCode=U_MEMORY_ALLOCATION_ERROR;
    242            return false;
    243        }
    244    }
    245    return true;
    246 }
    247 
    248 CharString &CharString::appendPathPart(StringPiece s, UErrorCode &errorCode) {
    249    if(U_FAILURE(errorCode)) {
    250        return *this;
    251    }
    252    if(s.length()==0) {
    253        return *this;
    254    }
    255    char c;
    256    if(len>0 && (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
    257        append(getDirSepChar(), errorCode);
    258    }
    259    append(s, errorCode);
    260    return *this;
    261 }
    262 
    263 CharString &CharString::ensureEndsWithFileSeparator(UErrorCode &errorCode) {
    264    char c;
    265    if(U_SUCCESS(errorCode) && len>0 &&
    266            (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
    267        append(getDirSepChar(), errorCode);
    268    }
    269    return *this;
    270 }
    271 
    272 char CharString::getDirSepChar() const {
    273    char dirSepChar = U_FILE_SEP_CHAR;
    274 #if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
    275    // We may need to return a different directory separator when building for Cygwin or MSYS2.
    276    if(len>0 && !uprv_strchr(data(), U_FILE_SEP_CHAR) && uprv_strchr(data(), U_FILE_ALT_SEP_CHAR))
    277        dirSepChar = U_FILE_ALT_SEP_CHAR;
    278 #endif
    279    return dirSepChar;
    280 }
    281 
    282 U_NAMESPACE_END