Coverage Report

Created: 2025-06-13 06:34

/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
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) 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
CharString &CharString::copyFrom(StringPiece s, UErrorCode &errorCode) {
74
0
    if (U_FAILURE(errorCode)) {
75
0
        return *this;
76
0
    }
77
0
    len = 0;
78
0
    append(s, errorCode);
79
0
    return *this;
80
0
}
81
82
0
int32_t CharString::lastIndexOf(char c) const {
83
0
    for(int32_t i=len; i>0;) {
84
0
        if(buffer[--i]==c) {
85
0
            return i;
86
0
        }
87
0
    }
88
0
    return -1;
89
0
}
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
0
CharString &CharString::truncate(int32_t newLength) {
104
0
    if(newLength<0) {
105
0
        newLength=0;
106
0
    }
107
0
    if(newLength<len) {
108
0
        buffer[len=newLength]=0;
109
0
    }
110
0
    return *this;
111
0
}
112
113
8
CharString &CharString::append(char c, UErrorCode &errorCode) {
114
8
    if(ensureCapacity(len+2, 0, errorCode)) {
115
8
        buffer[len++]=c;
116
8
        buffer[len]=0;
117
8
    }
118
8
    return *this;
119
8
}
120
121
36
CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &errorCode) {
122
36
    if(U_FAILURE(errorCode)) {
123
0
        return *this;
124
0
    }
125
36
    if(sLength<-1 || (s==nullptr && sLength!=0)) {
126
0
        errorCode=U_ILLEGAL_ARGUMENT_ERROR;
127
0
        return *this;
128
0
    }
129
36
    if(sLength<0) {
130
0
        sLength= static_cast<int32_t>(uprv_strlen(s));
131
0
    }
132
36
    if(sLength>0) {
133
36
        if(s==(buffer.getAlias()+len)) {
134
            // The caller wrote into the getAppendBuffer().
135
0
            if(sLength>=(buffer.getCapacity()-len)) {
136
                // The caller wrote too much.
137
0
                errorCode=U_INTERNAL_PROGRAM_ERROR;
138
0
            } else {
139
0
                buffer[len+=sLength]=0;
140
0
            }
141
36
        } else if(buffer.getAlias()<=s && s<(buffer.getAlias()+len) &&
142
36
                  sLength>=(buffer.getCapacity()-len)
143
36
        ) {
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
36
        } else if(ensureCapacity(len+sLength+1, 0, errorCode)) {
148
36
            uprv_memcpy(buffer.getAlias()+len, s, sLength);
149
36
            buffer[len+=sLength]=0;
150
36
        }
151
36
    }
152
36
    return *this;
153
36
}
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
0
                                  UErrorCode &errorCode) {
191
0
    if(U_FAILURE(errorCode)) {
192
0
        resultCapacity=0;
193
0
        return nullptr;
194
0
    }
195
0
    int32_t appendCapacity=buffer.getCapacity()-len-1;  // -1 for NUL
196
0
    if(appendCapacity>=minCapacity) {
197
0
        resultCapacity=appendCapacity;
198
0
        return buffer.getAlias()+len;
199
0
    }
200
0
    if(ensureCapacity(len+minCapacity+1, len+desiredCapacityHint+1, errorCode)) {
201
0
        resultCapacity=buffer.getCapacity()-len-1;
202
0
        return buffer.getAlias()+len;
203
0
    }
204
0
    resultCapacity=0;
205
0
    return nullptr;
206
0
}
207
208
0
CharString &CharString::appendInvariantChars(const UnicodeString &s, UErrorCode &errorCode) {
209
0
    return appendInvariantChars(s.getBuffer(), s.length(), errorCode);
210
0
}
211
212
0
CharString &CharString::appendInvariantChars(const char16_t* uchars, int32_t ucharsLen, UErrorCode &errorCode) {
213
0
    if(U_FAILURE(errorCode)) {
214
0
        return *this;
215
0
    }
216
0
    if (!uprv_isInvariantUString(uchars, ucharsLen)) {
217
0
        errorCode = U_INVARIANT_CONVERSION_ERROR;
218
0
        return *this;
219
0
    }
220
0
    if(ensureCapacity(len+ucharsLen+1, 0, errorCode)) {
221
0
        u_UCharsToChars(uchars, buffer.getAlias()+len, ucharsLen);
222
0
        len += ucharsLen;
223
0
        buffer[len] = 0;
224
0
    }
225
0
    return *this;
226
0
}
227
228
UBool CharString::ensureCapacity(int32_t capacity,
229
                                 int32_t desiredCapacityHint,
230
44
                                 UErrorCode &errorCode) {
231
44
    if(U_FAILURE(errorCode)) {
232
0
        return false;
233
0
    }
234
44
    if(capacity>buffer.getCapacity()) {
235
0
        if(desiredCapacityHint==0) {
236
0
            desiredCapacityHint=capacity+buffer.getCapacity();
237
0
        }
238
0
        if( (desiredCapacityHint<=capacity || buffer.resize(desiredCapacityHint, len+1)==nullptr) &&
239
0
            buffer.resize(capacity, len+1)==nullptr
240
0
        ) {
241
0
            errorCode=U_MEMORY_ALLOCATION_ERROR;
242
0
            return false;
243
0
        }
244
0
    }
245
44
    return true;
246
44
}
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