Coverage Report

Created: 2025-06-24 06:43

/src/icu/source/common/charstr.cpp
Line
Count
Source (jump to first uncovered line)
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) U_NOEXCEPT
30
0
        : buffer(std::move(src.buffer)), len(src.len) {
31
0
    src.len = 0;  // not strictly necessary because we make no guarantees on the source string
32
0
}
33
34
0
CharString& CharString::operator=(CharString&& src) U_NOEXCEPT {
35
0
    buffer = std::move(src.buffer);
36
0
    len = src.len;
37
0
    src.len = 0;  // not strictly necessary because we make no guarantees on the source string
38
0
    return *this;
39
0
}
40
41
0
char *CharString::cloneData(UErrorCode &errorCode) const {
42
0
    if (U_FAILURE(errorCode)) { return nullptr; }
43
0
    char *p = static_cast<char *>(uprv_malloc(len + 1));
44
0
    if (p == nullptr) {
45
0
        errorCode = U_MEMORY_ALLOCATION_ERROR;
46
0
        return nullptr;
47
0
    }
48
0
    uprv_memcpy(p, buffer.getAlias(), len + 1);
49
0
    return p;
50
0
}
51
52
0
int32_t CharString::extract(char *dest, int32_t capacity, UErrorCode &errorCode) const {
53
0
    if (U_FAILURE(errorCode)) { return len; }
54
0
    if (capacity < 0 || (capacity > 0 && dest == nullptr)) {
55
0
        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
56
0
        return len;
57
0
    }
58
0
    const char *src = buffer.getAlias();
59
0
    if (0 < len && len <= capacity && src != dest) {
60
0
        uprv_memcpy(dest, src, len);
61
0
    }
62
0
    return u_terminateChars(dest, capacity, len, &errorCode);
63
0
}
64
65
0
CharString &CharString::copyFrom(const CharString &s, UErrorCode &errorCode) {
66
0
    if(U_SUCCESS(errorCode) && this!=&s && ensureCapacity(s.len+1, 0, errorCode)) {
67
0
        len=s.len;
68
0
        uprv_memcpy(buffer.getAlias(), s.buffer.getAlias(), len+1);
69
0
    }
70
0
    return *this;
71
0
}
72
73
0
int32_t CharString::lastIndexOf(char c) const {
74
0
    for(int32_t i=len; i>0;) {
75
0
        if(buffer[--i]==c) {
76
0
            return i;
77
0
        }
78
0
    }
79
0
    return -1;
80
0
}
81
82
0
bool CharString::contains(StringPiece s) const {
83
0
    if (s.empty()) { return false; }
84
0
    const char *p = buffer.getAlias();
85
0
    int32_t lastStart = len - s.length();
86
0
    for (int32_t i = 0; i <= lastStart; ++i) {
87
0
        if (uprv_memcmp(p + i, s.data(), s.length()) == 0) {
88
0
            return true;
89
0
        }
90
0
    }
91
0
    return false;
92
0
}
93
94
0
CharString &CharString::truncate(int32_t newLength) {
95
0
    if(newLength<0) {
96
0
        newLength=0;
97
0
    }
98
0
    if(newLength<len) {
99
0
        buffer[len=newLength]=0;
100
0
    }
101
0
    return *this;
102
0
}
103
104
0
CharString &CharString::append(char c, UErrorCode &errorCode) {
105
0
    if(ensureCapacity(len+2, 0, errorCode)) {
106
0
        buffer[len++]=c;
107
0
        buffer[len]=0;
108
0
    }
109
0
    return *this;
110
0
}
111
112
0
CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &errorCode) {
113
0
    if(U_FAILURE(errorCode)) {
114
0
        return *this;
115
0
    }
116
0
    if(sLength<-1 || (s==NULL && sLength!=0)) {
117
0
        errorCode=U_ILLEGAL_ARGUMENT_ERROR;
118
0
        return *this;
119
0
    }
120
0
    if(sLength<0) {
121
0
        sLength= static_cast<int32_t>(uprv_strlen(s));
122
0
    }
123
0
    if(sLength>0) {
124
0
        if(s==(buffer.getAlias()+len)) {
125
            // The caller wrote into the getAppendBuffer().
126
0
            if(sLength>=(buffer.getCapacity()-len)) {
127
                // The caller wrote too much.
128
0
                errorCode=U_INTERNAL_PROGRAM_ERROR;
129
0
            } else {
130
0
                buffer[len+=sLength]=0;
131
0
            }
132
0
        } else if(buffer.getAlias()<=s && s<(buffer.getAlias()+len) &&
133
0
                  sLength>=(buffer.getCapacity()-len)
134
0
        ) {
135
            // (Part of) this string is appended to itself which requires reallocation,
136
            // so we have to make a copy of the substring and append that.
137
0
            return append(CharString(s, sLength, errorCode), errorCode);
138
0
        } else if(ensureCapacity(len+sLength+1, 0, errorCode)) {
139
0
            uprv_memcpy(buffer.getAlias()+len, s, sLength);
140
0
            buffer[len+=sLength]=0;
141
0
        }
142
0
    }
143
0
    return *this;
144
0
}
145
146
0
CharString &CharString::appendNumber(int32_t number, UErrorCode &status) {
147
0
    if (number < 0) {
148
0
        this->append('-', status);
149
0
        if (U_FAILURE(status)) {
150
0
            return *this;
151
0
        }
152
0
    }
153
154
0
    if (number == 0) {
155
0
        this->append('0', status);
156
0
        return *this;
157
0
    }
158
159
0
    int32_t numLen = 0;
160
0
    while (number != 0) {
161
0
        int32_t residue = number % 10;
162
0
        number /= 10;
163
0
        this->append(std::abs(residue) + '0', status);
164
0
        numLen++;
165
0
        if (U_FAILURE(status)) {
166
0
            return *this;
167
0
        }
168
0
    }
169
170
0
    int32_t start = this->length() - numLen, end = this->length() - 1;
171
0
    while(start < end) {
172
0
        std::swap(this->data()[start++], this->data()[end--]);
173
0
    }
174
175
0
    return *this;
176
0
}
177
178
char *CharString::getAppendBuffer(int32_t minCapacity,
179
                                  int32_t desiredCapacityHint,
180
                                  int32_t &resultCapacity,
181
0
                                  UErrorCode &errorCode) {
182
0
    if(U_FAILURE(errorCode)) {
183
0
        resultCapacity=0;
184
0
        return NULL;
185
0
    }
186
0
    int32_t appendCapacity=buffer.getCapacity()-len-1;  // -1 for NUL
187
0
    if(appendCapacity>=minCapacity) {
188
0
        resultCapacity=appendCapacity;
189
0
        return buffer.getAlias()+len;
190
0
    }
191
0
    if(ensureCapacity(len+minCapacity+1, len+desiredCapacityHint+1, errorCode)) {
192
0
        resultCapacity=buffer.getCapacity()-len-1;
193
0
        return buffer.getAlias()+len;
194
0
    }
195
0
    resultCapacity=0;
196
0
    return NULL;
197
0
}
198
199
0
CharString &CharString::appendInvariantChars(const UnicodeString &s, UErrorCode &errorCode) {
200
0
    return appendInvariantChars(s.getBuffer(), s.length(), errorCode);
201
0
}
202
203
0
CharString &CharString::appendInvariantChars(const UChar* uchars, int32_t ucharsLen, UErrorCode &errorCode) {
204
0
    if(U_FAILURE(errorCode)) {
205
0
        return *this;
206
0
    }
207
0
    if (!uprv_isInvariantUString(uchars, ucharsLen)) {
208
0
        errorCode = U_INVARIANT_CONVERSION_ERROR;
209
0
        return *this;
210
0
    }
211
0
    if(ensureCapacity(len+ucharsLen+1, 0, errorCode)) {
212
0
        u_UCharsToChars(uchars, buffer.getAlias()+len, ucharsLen);
213
0
        len += ucharsLen;
214
0
        buffer[len] = 0;
215
0
    }
216
0
    return *this;
217
0
}
218
219
UBool CharString::ensureCapacity(int32_t capacity,
220
                                 int32_t desiredCapacityHint,
221
0
                                 UErrorCode &errorCode) {
222
0
    if(U_FAILURE(errorCode)) {
223
0
        return FALSE;
224
0
    }
225
0
    if(capacity>buffer.getCapacity()) {
226
0
        if(desiredCapacityHint==0) {
227
0
            desiredCapacityHint=capacity+buffer.getCapacity();
228
0
        }
229
0
        if( (desiredCapacityHint<=capacity || buffer.resize(desiredCapacityHint, len+1)==NULL) &&
230
0
            buffer.resize(capacity, len+1)==NULL
231
0
        ) {
232
0
            errorCode=U_MEMORY_ALLOCATION_ERROR;
233
0
            return FALSE;
234
0
        }
235
0
    }
236
0
    return TRUE;
237
0
}
238
239
0
CharString &CharString::appendPathPart(StringPiece s, UErrorCode &errorCode) {
240
0
    if(U_FAILURE(errorCode)) {
241
0
        return *this;
242
0
    }
243
0
    if(s.length()==0) {
244
0
        return *this;
245
0
    }
246
0
    char c;
247
0
    if(len>0 && (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
248
0
        append(getDirSepChar(), errorCode);
249
0
    }
250
0
    append(s, errorCode);
251
0
    return *this;
252
0
}
253
254
0
CharString &CharString::ensureEndsWithFileSeparator(UErrorCode &errorCode) {
255
0
    char c;
256
0
    if(U_SUCCESS(errorCode) && len>0 &&
257
0
            (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
258
0
        append(getDirSepChar(), errorCode);
259
0
    }
260
0
    return *this;
261
0
}
262
263
0
char CharString::getDirSepChar() const {
264
0
    char dirSepChar = U_FILE_SEP_CHAR;
265
#if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
266
    // We may need to return a different directory separator when building for Cygwin or MSYS2.
267
    if(len>0 && !uprv_strchr(data(), U_FILE_SEP_CHAR) && uprv_strchr(data(), U_FILE_ALT_SEP_CHAR))
268
        dirSepChar = U_FILE_ALT_SEP_CHAR;
269
#endif
270
0
    return dirSepChar;
271
0
}
272
273
U_NAMESPACE_END