Coverage Report

Created: 2025-06-13 06:38

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