Coverage Report

Created: 2025-06-24 06:54

/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.67M
        : buffer(std::move(src.buffer)), len(src.len) {
31
1.67M
    src.len = 0;  // not strictly necessary because we make no guarantees on the source string
32
1.67M
}
33
34
1.64M
CharString& CharString::operator=(CharString&& src) noexcept {
35
1.64M
    buffer = std::move(src.buffer);
36
1.64M
    len = src.len;
37
1.64M
    src.len = 0;  // not strictly necessary because we make no guarantees on the source string
38
1.64M
    return *this;
39
1.64M
}
40
41
114k
char *CharString::cloneData(UErrorCode &errorCode) const {
42
114k
    if (U_FAILURE(errorCode)) { return nullptr; }
43
114k
    char *p = static_cast<char *>(uprv_malloc(len + 1));
44
114k
    if (p == nullptr) {
45
0
        errorCode = U_MEMORY_ALLOCATION_ERROR;
46
0
        return nullptr;
47
0
    }
48
114k
    uprv_memcpy(p, buffer.getAlias(), len + 1);
49
114k
    return p;
50
114k
}
51
52
56.5k
int32_t CharString::extract(char *dest, int32_t capacity, UErrorCode &errorCode) const {
53
56.5k
    if (U_FAILURE(errorCode)) { return len; }
54
56.5k
    if (capacity < 0 || (capacity > 0 && dest == nullptr)) {
55
0
        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
56
0
        return len;
57
0
    }
58
56.5k
    const char *src = buffer.getAlias();
59
56.5k
    if (0 < len && len <= capacity && src != dest) {
60
56.4k
        uprv_memcpy(dest, src, len);
61
56.4k
    }
62
56.5k
    return u_terminateChars(dest, capacity, len, &errorCode);
63
56.5k
}
64
65
2.71M
CharString &CharString::copyFrom(const CharString &s, UErrorCode &errorCode) {
66
2.71M
    if(U_SUCCESS(errorCode) && this!=&s && ensureCapacity(s.len+1, 0, errorCode)) {
67
2.70M
        len=s.len;
68
2.70M
        uprv_memcpy(buffer.getAlias(), s.buffer.getAlias(), len+1);
69
2.70M
    }
70
2.71M
    return *this;
71
2.71M
}
72
73
623
CharString &CharString::copyFrom(StringPiece s, UErrorCode &errorCode) {
74
623
    if (U_FAILURE(errorCode)) {
75
0
        return *this;
76
0
    }
77
623
    len = 0;
78
623
    append(s, errorCode);
79
623
    return *this;
80
623
}
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
130M
CharString &CharString::append(char c, UErrorCode &errorCode) {
114
130M
    if(ensureCapacity(len+2, 0, errorCode)) {
115
129M
        buffer[len++]=c;
116
129M
        buffer[len]=0;
117
129M
    }
118
130M
    return *this;
119
130M
}
120
121
268M
CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &errorCode) {
122
268M
    if(U_FAILURE(errorCode)) {
123
251k
        return *this;
124
251k
    }
125
268M
    if(sLength<-1 || (s==nullptr && sLength!=0)) {
126
0
        errorCode=U_ILLEGAL_ARGUMENT_ERROR;
127
0
        return *this;
128
0
    }
129
268M
    if(sLength<0) {
130
1.31M
        sLength= static_cast<int32_t>(uprv_strlen(s));
131
1.31M
    }
132
268M
    if(sLength>0) {
133
263M
        if(s==(buffer.getAlias()+len)) {
134
            // The caller wrote into the getAppendBuffer().
135
15.0M
            if(sLength>=(buffer.getCapacity()-len)) {
136
                // The caller wrote too much.
137
0
                errorCode=U_INTERNAL_PROGRAM_ERROR;
138
15.0M
            } else {
139
15.0M
                buffer[len+=sLength]=0;
140
15.0M
            }
141
248M
        } else if(buffer.getAlias()<=s && s<(buffer.getAlias()+len) &&
142
248M
                  sLength>=(buffer.getCapacity()-len)
143
248M
        ) {
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
248M
        } else if(ensureCapacity(len+sLength+1, 0, errorCode)) {
148
248M
            uprv_memcpy(buffer.getAlias()+len, s, sLength);
149
248M
            buffer[len+=sLength]=0;
150
248M
        }
151
263M
    }
152
268M
    return *this;
153
268M
}
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.4M
                                  UErrorCode &errorCode) {
191
16.4M
    if(U_FAILURE(errorCode)) {
192
0
        resultCapacity=0;
193
0
        return nullptr;
194
0
    }
195
16.4M
    int32_t appendCapacity=buffer.getCapacity()-len-1;  // -1 for NUL
196
16.4M
    if(appendCapacity>=minCapacity) {
197
16.3M
        resultCapacity=appendCapacity;
198
16.3M
        return buffer.getAlias()+len;
199
16.3M
    }
200
30.2k
    if(ensureCapacity(len+minCapacity+1, len+desiredCapacityHint+1, errorCode)) {
201
30.2k
        resultCapacity=buffer.getCapacity()-len-1;
202
30.2k
        return buffer.getAlias()+len;
203
30.2k
    }
204
0
    resultCapacity=0;
205
0
    return nullptr;
206
30.2k
}
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.91M
CharString &CharString::appendInvariantChars(const char16_t* uchars, int32_t ucharsLen, UErrorCode &errorCode) {
213
2.91M
    if(U_FAILURE(errorCode)) {
214
0
        return *this;
215
0
    }
216
2.91M
    if (!uprv_isInvariantUString(uchars, ucharsLen)) {
217
34
        errorCode = U_INVARIANT_CONVERSION_ERROR;
218
34
        return *this;
219
34
    }
220
2.91M
    if(ensureCapacity(len+ucharsLen+1, 0, errorCode)) {
221
2.91M
        u_UCharsToChars(uchars, buffer.getAlias()+len, ucharsLen);
222
2.91M
        len += ucharsLen;
223
2.91M
        buffer[len] = 0;
224
2.91M
    }
225
2.91M
    return *this;
226
2.91M
}
227
228
UBool CharString::ensureCapacity(int32_t capacity,
229
                                 int32_t desiredCapacityHint,
230
384M
                                 UErrorCode &errorCode) {
231
384M
    if(U_FAILURE(errorCode)) {
232
171k
        return false;
233
171k
    }
234
384M
    if(capacity>buffer.getCapacity()) {
235
968k
        if(desiredCapacityHint==0) {
236
938k
            desiredCapacityHint=capacity+buffer.getCapacity();
237
938k
        }
238
968k
        if( (desiredCapacityHint<=capacity || buffer.resize(desiredCapacityHint, len+1)==nullptr) &&
239
968k
            buffer.resize(capacity, len+1)==nullptr
240
968k
        ) {
241
0
            errorCode=U_MEMORY_ALLOCATION_ERROR;
242
0
            return false;
243
0
        }
244
968k
    }
245
384M
    return true;
246
384M
}
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