Coverage Report

Created: 2025-12-07 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/icu/icu4c/source/common/charstr.cpp
Line
Count
Source
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.87M
        : buffer(std::move(src.buffer)), len(src.len) {
31
1.87M
    src.len = 0;  // not strictly necessary because we make no guarantees on the source string
32
1.87M
}
33
34
1.62M
CharString& CharString::operator=(CharString&& src) noexcept {
35
1.62M
    buffer = std::move(src.buffer);
36
1.62M
    len = src.len;
37
1.62M
    src.len = 0;  // not strictly necessary because we make no guarantees on the source string
38
1.62M
    return *this;
39
1.62M
}
40
41
101k
char *CharString::cloneData(UErrorCode &errorCode) const {
42
101k
    if (U_FAILURE(errorCode)) { return nullptr; }
43
101k
    char *p = static_cast<char *>(uprv_malloc(len + 1));
44
101k
    if (p == nullptr) {
45
0
        errorCode = U_MEMORY_ALLOCATION_ERROR;
46
0
        return nullptr;
47
0
    }
48
101k
    uprv_memcpy(p, buffer.getAlias(), len + 1);
49
101k
    return p;
50
101k
}
51
52
49.4k
int32_t CharString::extract(char *dest, int32_t capacity, UErrorCode &errorCode) const {
53
49.4k
    if (U_FAILURE(errorCode)) { return len; }
54
49.4k
    if (capacity < 0 || (capacity > 0 && dest == nullptr)) {
55
0
        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
56
0
        return len;
57
0
    }
58
49.4k
    const char *src = buffer.getAlias();
59
49.4k
    if (0 < len && len <= capacity && src != dest) {
60
49.4k
        uprv_memcpy(dest, src, len);
61
49.4k
    }
62
49.4k
    return u_terminateChars(dest, capacity, len, &errorCode);
63
49.4k
}
64
65
2.15M
CharString &CharString::copyFrom(const CharString &s, UErrorCode &errorCode) {
66
2.15M
    if(U_SUCCESS(errorCode) && this!=&s && ensureCapacity(s.len+1, 0, errorCode)) {
67
2.15M
        len=s.len;
68
2.15M
        uprv_memcpy(buffer.getAlias(), s.buffer.getAlias(), len+1);
69
2.15M
    }
70
2.15M
    return *this;
71
2.15M
}
72
73
166
CharString &CharString::copyFrom(StringPiece s, UErrorCode &errorCode) {
74
166
    if (U_FAILURE(errorCode)) {
75
0
        return *this;
76
0
    }
77
166
    len = 0;
78
166
    append(s, errorCode);
79
166
    return *this;
80
166
}
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
4.44k
CharString &CharString::truncate(int32_t newLength) {
104
4.44k
    if(newLength<0) {
105
0
        newLength=0;
106
0
    }
107
4.44k
    if(newLength<len) {
108
4.44k
        buffer[len=newLength]=0;
109
4.44k
    }
110
4.44k
    return *this;
111
4.44k
}
112
113
87.6M
CharString &CharString::append(char c, UErrorCode &errorCode) {
114
87.6M
    if(ensureCapacity(len+2, 0, errorCode)) {
115
87.5M
        buffer[len++]=c;
116
87.5M
        buffer[len]=0;
117
87.5M
    }
118
87.6M
    return *this;
119
87.6M
}
120
121
272M
CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &errorCode) {
122
272M
    if(U_FAILURE(errorCode)) {
123
228k
        return *this;
124
228k
    }
125
272M
    if(sLength<-1 || (s==nullptr && sLength!=0)) {
126
0
        errorCode=U_ILLEGAL_ARGUMENT_ERROR;
127
0
        return *this;
128
0
    }
129
272M
    if(sLength<0) {
130
1.24M
        sLength= static_cast<int32_t>(uprv_strlen(s));
131
1.24M
    }
132
272M
    if(sLength>0) {
133
266M
        if(s==(buffer.getAlias()+len)) {
134
            // The caller wrote into the getAppendBuffer().
135
21.8M
            if(sLength>=(buffer.getCapacity()-len)) {
136
                // The caller wrote too much.
137
0
                errorCode=U_INTERNAL_PROGRAM_ERROR;
138
21.8M
            } else {
139
21.8M
                buffer[len+=sLength]=0;
140
21.8M
            }
141
244M
        } else if(buffer.getAlias()<=s && s<(buffer.getAlias()+len) &&
142
0
                  sLength>=(buffer.getCapacity()-len)
143
244M
        ) {
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
244M
        } else if(ensureCapacity(len+sLength+1, 0, errorCode)) {
148
244M
            uprv_memcpy(buffer.getAlias()+len, s, sLength);
149
244M
            buffer[len+=sLength]=0;
150
244M
        }
151
266M
    }
152
272M
    return *this;
153
272M
}
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
23.3M
                                  UErrorCode &errorCode) {
191
23.3M
    if(U_FAILURE(errorCode)) {
192
0
        resultCapacity=0;
193
0
        return nullptr;
194
0
    }
195
23.3M
    int32_t appendCapacity=buffer.getCapacity()-len-1;  // -1 for NUL
196
23.3M
    if(appendCapacity>=minCapacity) {
197
23.3M
        resultCapacity=appendCapacity;
198
23.3M
        return buffer.getAlias()+len;
199
23.3M
    }
200
22.4k
    if(ensureCapacity(len+minCapacity+1, len+desiredCapacityHint+1, errorCode)) {
201
22.4k
        resultCapacity=buffer.getCapacity()-len-1;
202
22.4k
        return buffer.getAlias()+len;
203
22.4k
    }
204
0
    resultCapacity=0;
205
0
    return nullptr;
206
22.4k
}
207
208
630k
CharString &CharString::appendInvariantChars(const UnicodeString &s, UErrorCode &errorCode) {
209
630k
    return appendInvariantChars(s.getBuffer(), s.length(), errorCode);
210
630k
}
211
212
2.66M
CharString &CharString::appendInvariantChars(const char16_t* uchars, int32_t ucharsLen, UErrorCode &errorCode) {
213
2.66M
    if(U_FAILURE(errorCode)) {
214
0
        return *this;
215
0
    }
216
2.66M
    if (!uprv_isInvariantUString(uchars, ucharsLen)) {
217
32
        errorCode = U_INVARIANT_CONVERSION_ERROR;
218
32
        return *this;
219
32
    }
220
2.66M
    if(ensureCapacity(len+ucharsLen+1, 0, errorCode)) {
221
2.66M
        u_UCharsToChars(uchars, buffer.getAlias()+len, ucharsLen);
222
2.66M
        len += ucharsLen;
223
2.66M
        buffer[len] = 0;
224
2.66M
    }
225
2.66M
    return *this;
226
2.66M
}
227
228
UBool CharString::ensureCapacity(int32_t capacity,
229
                                 int32_t desiredCapacityHint,
230
337M
                                 UErrorCode &errorCode) {
231
337M
    if(U_FAILURE(errorCode)) {
232
155k
        return false;
233
155k
    }
234
337M
    if(capacity>buffer.getCapacity()) {
235
862k
        if(desiredCapacityHint==0) {
236
840k
            desiredCapacityHint=capacity+buffer.getCapacity();
237
840k
        }
238
862k
        if( (desiredCapacityHint<=capacity || buffer.resize(desiredCapacityHint, len+1)==nullptr) &&
239
22.4k
            buffer.resize(capacity, len+1)==nullptr
240
862k
        ) {
241
0
            errorCode=U_MEMORY_ALLOCATION_ERROR;
242
0
            return false;
243
0
        }
244
862k
    }
245
337M
    return true;
246
337M
}
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