11cb0ef41Sopenharmony_ci// © 2016 and later: Unicode, Inc. and others.
21cb0ef41Sopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html
31cb0ef41Sopenharmony_ci/*
41cb0ef41Sopenharmony_ci*******************************************************************************
51cb0ef41Sopenharmony_ci*   Copyright (C) 2010-2015, International Business Machines
61cb0ef41Sopenharmony_ci*   Corporation and others.  All Rights Reserved.
71cb0ef41Sopenharmony_ci*******************************************************************************
81cb0ef41Sopenharmony_ci*   file name:  charstr.cpp
91cb0ef41Sopenharmony_ci*   encoding:   UTF-8
101cb0ef41Sopenharmony_ci*   tab size:   8 (not used)
111cb0ef41Sopenharmony_ci*   indentation:4
121cb0ef41Sopenharmony_ci*
131cb0ef41Sopenharmony_ci*   created on: 2010may19
141cb0ef41Sopenharmony_ci*   created by: Markus W. Scherer
151cb0ef41Sopenharmony_ci*/
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_ci#include <cstdlib>
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_ci#include "unicode/utypes.h"
201cb0ef41Sopenharmony_ci#include "unicode/putil.h"
211cb0ef41Sopenharmony_ci#include "charstr.h"
221cb0ef41Sopenharmony_ci#include "cmemory.h"
231cb0ef41Sopenharmony_ci#include "cstring.h"
241cb0ef41Sopenharmony_ci#include "uinvchar.h"
251cb0ef41Sopenharmony_ci#include "ustr_imp.h"
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_ciU_NAMESPACE_BEGIN
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ciCharString::CharString(CharString&& src) noexcept
301cb0ef41Sopenharmony_ci        : buffer(std::move(src.buffer)), len(src.len) {
311cb0ef41Sopenharmony_ci    src.len = 0;  // not strictly necessary because we make no guarantees on the source string
321cb0ef41Sopenharmony_ci}
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ciCharString& CharString::operator=(CharString&& src) noexcept {
351cb0ef41Sopenharmony_ci    buffer = std::move(src.buffer);
361cb0ef41Sopenharmony_ci    len = src.len;
371cb0ef41Sopenharmony_ci    src.len = 0;  // not strictly necessary because we make no guarantees on the source string
381cb0ef41Sopenharmony_ci    return *this;
391cb0ef41Sopenharmony_ci}
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_cichar *CharString::cloneData(UErrorCode &errorCode) const {
421cb0ef41Sopenharmony_ci    if (U_FAILURE(errorCode)) { return nullptr; }
431cb0ef41Sopenharmony_ci    char *p = static_cast<char *>(uprv_malloc(len + 1));
441cb0ef41Sopenharmony_ci    if (p == nullptr) {
451cb0ef41Sopenharmony_ci        errorCode = U_MEMORY_ALLOCATION_ERROR;
461cb0ef41Sopenharmony_ci        return nullptr;
471cb0ef41Sopenharmony_ci    }
481cb0ef41Sopenharmony_ci    uprv_memcpy(p, buffer.getAlias(), len + 1);
491cb0ef41Sopenharmony_ci    return p;
501cb0ef41Sopenharmony_ci}
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ciint32_t CharString::extract(char *dest, int32_t capacity, UErrorCode &errorCode) const {
531cb0ef41Sopenharmony_ci    if (U_FAILURE(errorCode)) { return len; }
541cb0ef41Sopenharmony_ci    if (capacity < 0 || (capacity > 0 && dest == nullptr)) {
551cb0ef41Sopenharmony_ci        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
561cb0ef41Sopenharmony_ci        return len;
571cb0ef41Sopenharmony_ci    }
581cb0ef41Sopenharmony_ci    const char *src = buffer.getAlias();
591cb0ef41Sopenharmony_ci    if (0 < len && len <= capacity && src != dest) {
601cb0ef41Sopenharmony_ci        uprv_memcpy(dest, src, len);
611cb0ef41Sopenharmony_ci    }
621cb0ef41Sopenharmony_ci    return u_terminateChars(dest, capacity, len, &errorCode);
631cb0ef41Sopenharmony_ci}
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ciCharString &CharString::copyFrom(const CharString &s, UErrorCode &errorCode) {
661cb0ef41Sopenharmony_ci    if(U_SUCCESS(errorCode) && this!=&s && ensureCapacity(s.len+1, 0, errorCode)) {
671cb0ef41Sopenharmony_ci        len=s.len;
681cb0ef41Sopenharmony_ci        uprv_memcpy(buffer.getAlias(), s.buffer.getAlias(), len+1);
691cb0ef41Sopenharmony_ci    }
701cb0ef41Sopenharmony_ci    return *this;
711cb0ef41Sopenharmony_ci}
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ciint32_t CharString::lastIndexOf(char c) const {
741cb0ef41Sopenharmony_ci    for(int32_t i=len; i>0;) {
751cb0ef41Sopenharmony_ci        if(buffer[--i]==c) {
761cb0ef41Sopenharmony_ci            return i;
771cb0ef41Sopenharmony_ci        }
781cb0ef41Sopenharmony_ci    }
791cb0ef41Sopenharmony_ci    return -1;
801cb0ef41Sopenharmony_ci}
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_cibool CharString::contains(StringPiece s) const {
831cb0ef41Sopenharmony_ci    if (s.empty()) { return false; }
841cb0ef41Sopenharmony_ci    const char *p = buffer.getAlias();
851cb0ef41Sopenharmony_ci    int32_t lastStart = len - s.length();
861cb0ef41Sopenharmony_ci    for (int32_t i = 0; i <= lastStart; ++i) {
871cb0ef41Sopenharmony_ci        if (uprv_memcmp(p + i, s.data(), s.length()) == 0) {
881cb0ef41Sopenharmony_ci            return true;
891cb0ef41Sopenharmony_ci        }
901cb0ef41Sopenharmony_ci    }
911cb0ef41Sopenharmony_ci    return false;
921cb0ef41Sopenharmony_ci}
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_ciCharString &CharString::truncate(int32_t newLength) {
951cb0ef41Sopenharmony_ci    if(newLength<0) {
961cb0ef41Sopenharmony_ci        newLength=0;
971cb0ef41Sopenharmony_ci    }
981cb0ef41Sopenharmony_ci    if(newLength<len) {
991cb0ef41Sopenharmony_ci        buffer[len=newLength]=0;
1001cb0ef41Sopenharmony_ci    }
1011cb0ef41Sopenharmony_ci    return *this;
1021cb0ef41Sopenharmony_ci}
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ciCharString &CharString::append(char c, UErrorCode &errorCode) {
1051cb0ef41Sopenharmony_ci    if(ensureCapacity(len+2, 0, errorCode)) {
1061cb0ef41Sopenharmony_ci        buffer[len++]=c;
1071cb0ef41Sopenharmony_ci        buffer[len]=0;
1081cb0ef41Sopenharmony_ci    }
1091cb0ef41Sopenharmony_ci    return *this;
1101cb0ef41Sopenharmony_ci}
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ciCharString &CharString::append(const char *s, int32_t sLength, UErrorCode &errorCode) {
1131cb0ef41Sopenharmony_ci    if(U_FAILURE(errorCode)) {
1141cb0ef41Sopenharmony_ci        return *this;
1151cb0ef41Sopenharmony_ci    }
1161cb0ef41Sopenharmony_ci    if(sLength<-1 || (s==nullptr && sLength!=0)) {
1171cb0ef41Sopenharmony_ci        errorCode=U_ILLEGAL_ARGUMENT_ERROR;
1181cb0ef41Sopenharmony_ci        return *this;
1191cb0ef41Sopenharmony_ci    }
1201cb0ef41Sopenharmony_ci    if(sLength<0) {
1211cb0ef41Sopenharmony_ci        sLength= static_cast<int32_t>(uprv_strlen(s));
1221cb0ef41Sopenharmony_ci    }
1231cb0ef41Sopenharmony_ci    if(sLength>0) {
1241cb0ef41Sopenharmony_ci        if(s==(buffer.getAlias()+len)) {
1251cb0ef41Sopenharmony_ci            // The caller wrote into the getAppendBuffer().
1261cb0ef41Sopenharmony_ci            if(sLength>=(buffer.getCapacity()-len)) {
1271cb0ef41Sopenharmony_ci                // The caller wrote too much.
1281cb0ef41Sopenharmony_ci                errorCode=U_INTERNAL_PROGRAM_ERROR;
1291cb0ef41Sopenharmony_ci            } else {
1301cb0ef41Sopenharmony_ci                buffer[len+=sLength]=0;
1311cb0ef41Sopenharmony_ci            }
1321cb0ef41Sopenharmony_ci        } else if(buffer.getAlias()<=s && s<(buffer.getAlias()+len) &&
1331cb0ef41Sopenharmony_ci                  sLength>=(buffer.getCapacity()-len)
1341cb0ef41Sopenharmony_ci        ) {
1351cb0ef41Sopenharmony_ci            // (Part of) this string is appended to itself which requires reallocation,
1361cb0ef41Sopenharmony_ci            // so we have to make a copy of the substring and append that.
1371cb0ef41Sopenharmony_ci            return append(CharString(s, sLength, errorCode), errorCode);
1381cb0ef41Sopenharmony_ci        } else if(ensureCapacity(len+sLength+1, 0, errorCode)) {
1391cb0ef41Sopenharmony_ci            uprv_memcpy(buffer.getAlias()+len, s, sLength);
1401cb0ef41Sopenharmony_ci            buffer[len+=sLength]=0;
1411cb0ef41Sopenharmony_ci        }
1421cb0ef41Sopenharmony_ci    }
1431cb0ef41Sopenharmony_ci    return *this;
1441cb0ef41Sopenharmony_ci}
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_ciCharString &CharString::appendNumber(int32_t number, UErrorCode &status) {
1471cb0ef41Sopenharmony_ci    if (number < 0) {
1481cb0ef41Sopenharmony_ci        this->append('-', status);
1491cb0ef41Sopenharmony_ci        if (U_FAILURE(status)) {
1501cb0ef41Sopenharmony_ci            return *this;
1511cb0ef41Sopenharmony_ci        }
1521cb0ef41Sopenharmony_ci    }
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_ci    if (number == 0) {
1551cb0ef41Sopenharmony_ci        this->append('0', status);
1561cb0ef41Sopenharmony_ci        return *this;
1571cb0ef41Sopenharmony_ci    }
1581cb0ef41Sopenharmony_ci
1591cb0ef41Sopenharmony_ci    int32_t numLen = 0;
1601cb0ef41Sopenharmony_ci    while (number != 0) {
1611cb0ef41Sopenharmony_ci        int32_t residue = number % 10;
1621cb0ef41Sopenharmony_ci        number /= 10;
1631cb0ef41Sopenharmony_ci        this->append(std::abs(residue) + '0', status);
1641cb0ef41Sopenharmony_ci        numLen++;
1651cb0ef41Sopenharmony_ci        if (U_FAILURE(status)) {
1661cb0ef41Sopenharmony_ci            return *this;
1671cb0ef41Sopenharmony_ci        }
1681cb0ef41Sopenharmony_ci    }
1691cb0ef41Sopenharmony_ci
1701cb0ef41Sopenharmony_ci    int32_t start = this->length() - numLen, end = this->length() - 1;
1711cb0ef41Sopenharmony_ci    while(start < end) {
1721cb0ef41Sopenharmony_ci        std::swap(this->data()[start++], this->data()[end--]);
1731cb0ef41Sopenharmony_ci    }
1741cb0ef41Sopenharmony_ci
1751cb0ef41Sopenharmony_ci    return *this;
1761cb0ef41Sopenharmony_ci}
1771cb0ef41Sopenharmony_ci
1781cb0ef41Sopenharmony_cichar *CharString::getAppendBuffer(int32_t minCapacity,
1791cb0ef41Sopenharmony_ci                                  int32_t desiredCapacityHint,
1801cb0ef41Sopenharmony_ci                                  int32_t &resultCapacity,
1811cb0ef41Sopenharmony_ci                                  UErrorCode &errorCode) {
1821cb0ef41Sopenharmony_ci    if(U_FAILURE(errorCode)) {
1831cb0ef41Sopenharmony_ci        resultCapacity=0;
1841cb0ef41Sopenharmony_ci        return nullptr;
1851cb0ef41Sopenharmony_ci    }
1861cb0ef41Sopenharmony_ci    int32_t appendCapacity=buffer.getCapacity()-len-1;  // -1 for NUL
1871cb0ef41Sopenharmony_ci    if(appendCapacity>=minCapacity) {
1881cb0ef41Sopenharmony_ci        resultCapacity=appendCapacity;
1891cb0ef41Sopenharmony_ci        return buffer.getAlias()+len;
1901cb0ef41Sopenharmony_ci    }
1911cb0ef41Sopenharmony_ci    if(ensureCapacity(len+minCapacity+1, len+desiredCapacityHint+1, errorCode)) {
1921cb0ef41Sopenharmony_ci        resultCapacity=buffer.getCapacity()-len-1;
1931cb0ef41Sopenharmony_ci        return buffer.getAlias()+len;
1941cb0ef41Sopenharmony_ci    }
1951cb0ef41Sopenharmony_ci    resultCapacity=0;
1961cb0ef41Sopenharmony_ci    return nullptr;
1971cb0ef41Sopenharmony_ci}
1981cb0ef41Sopenharmony_ci
1991cb0ef41Sopenharmony_ciCharString &CharString::appendInvariantChars(const UnicodeString &s, UErrorCode &errorCode) {
2001cb0ef41Sopenharmony_ci    return appendInvariantChars(s.getBuffer(), s.length(), errorCode);
2011cb0ef41Sopenharmony_ci}
2021cb0ef41Sopenharmony_ci
2031cb0ef41Sopenharmony_ciCharString &CharString::appendInvariantChars(const char16_t* uchars, int32_t ucharsLen, UErrorCode &errorCode) {
2041cb0ef41Sopenharmony_ci    if(U_FAILURE(errorCode)) {
2051cb0ef41Sopenharmony_ci        return *this;
2061cb0ef41Sopenharmony_ci    }
2071cb0ef41Sopenharmony_ci    if (!uprv_isInvariantUString(uchars, ucharsLen)) {
2081cb0ef41Sopenharmony_ci        errorCode = U_INVARIANT_CONVERSION_ERROR;
2091cb0ef41Sopenharmony_ci        return *this;
2101cb0ef41Sopenharmony_ci    }
2111cb0ef41Sopenharmony_ci    if(ensureCapacity(len+ucharsLen+1, 0, errorCode)) {
2121cb0ef41Sopenharmony_ci        u_UCharsToChars(uchars, buffer.getAlias()+len, ucharsLen);
2131cb0ef41Sopenharmony_ci        len += ucharsLen;
2141cb0ef41Sopenharmony_ci        buffer[len] = 0;
2151cb0ef41Sopenharmony_ci    }
2161cb0ef41Sopenharmony_ci    return *this;
2171cb0ef41Sopenharmony_ci}
2181cb0ef41Sopenharmony_ci
2191cb0ef41Sopenharmony_ciUBool CharString::ensureCapacity(int32_t capacity,
2201cb0ef41Sopenharmony_ci                                 int32_t desiredCapacityHint,
2211cb0ef41Sopenharmony_ci                                 UErrorCode &errorCode) {
2221cb0ef41Sopenharmony_ci    if(U_FAILURE(errorCode)) {
2231cb0ef41Sopenharmony_ci        return false;
2241cb0ef41Sopenharmony_ci    }
2251cb0ef41Sopenharmony_ci    if(capacity>buffer.getCapacity()) {
2261cb0ef41Sopenharmony_ci        if(desiredCapacityHint==0) {
2271cb0ef41Sopenharmony_ci            desiredCapacityHint=capacity+buffer.getCapacity();
2281cb0ef41Sopenharmony_ci        }
2291cb0ef41Sopenharmony_ci        if( (desiredCapacityHint<=capacity || buffer.resize(desiredCapacityHint, len+1)==nullptr) &&
2301cb0ef41Sopenharmony_ci            buffer.resize(capacity, len+1)==nullptr
2311cb0ef41Sopenharmony_ci        ) {
2321cb0ef41Sopenharmony_ci            errorCode=U_MEMORY_ALLOCATION_ERROR;
2331cb0ef41Sopenharmony_ci            return false;
2341cb0ef41Sopenharmony_ci        }
2351cb0ef41Sopenharmony_ci    }
2361cb0ef41Sopenharmony_ci    return true;
2371cb0ef41Sopenharmony_ci}
2381cb0ef41Sopenharmony_ci
2391cb0ef41Sopenharmony_ciCharString &CharString::appendPathPart(StringPiece s, UErrorCode &errorCode) {
2401cb0ef41Sopenharmony_ci    if(U_FAILURE(errorCode)) {
2411cb0ef41Sopenharmony_ci        return *this;
2421cb0ef41Sopenharmony_ci    }
2431cb0ef41Sopenharmony_ci    if(s.length()==0) {
2441cb0ef41Sopenharmony_ci        return *this;
2451cb0ef41Sopenharmony_ci    }
2461cb0ef41Sopenharmony_ci    char c;
2471cb0ef41Sopenharmony_ci    if(len>0 && (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
2481cb0ef41Sopenharmony_ci        append(getDirSepChar(), errorCode);
2491cb0ef41Sopenharmony_ci    }
2501cb0ef41Sopenharmony_ci    append(s, errorCode);
2511cb0ef41Sopenharmony_ci    return *this;
2521cb0ef41Sopenharmony_ci}
2531cb0ef41Sopenharmony_ci
2541cb0ef41Sopenharmony_ciCharString &CharString::ensureEndsWithFileSeparator(UErrorCode &errorCode) {
2551cb0ef41Sopenharmony_ci    char c;
2561cb0ef41Sopenharmony_ci    if(U_SUCCESS(errorCode) && len>0 &&
2571cb0ef41Sopenharmony_ci            (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
2581cb0ef41Sopenharmony_ci        append(getDirSepChar(), errorCode);
2591cb0ef41Sopenharmony_ci    }
2601cb0ef41Sopenharmony_ci    return *this;
2611cb0ef41Sopenharmony_ci}
2621cb0ef41Sopenharmony_ci
2631cb0ef41Sopenharmony_cichar CharString::getDirSepChar() const {
2641cb0ef41Sopenharmony_ci    char dirSepChar = U_FILE_SEP_CHAR;
2651cb0ef41Sopenharmony_ci#if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
2661cb0ef41Sopenharmony_ci    // We may need to return a different directory separator when building for Cygwin or MSYS2.
2671cb0ef41Sopenharmony_ci    if(len>0 && !uprv_strchr(data(), U_FILE_SEP_CHAR) && uprv_strchr(data(), U_FILE_ALT_SEP_CHAR))
2681cb0ef41Sopenharmony_ci        dirSepChar = U_FILE_ALT_SEP_CHAR;
2691cb0ef41Sopenharmony_ci#endif
2701cb0ef41Sopenharmony_ci    return dirSepChar;
2711cb0ef41Sopenharmony_ci}
2721cb0ef41Sopenharmony_ci
2731cb0ef41Sopenharmony_ciU_NAMESPACE_END
274