Coverage Report

Created: 2026-10-31 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/icu/icu4c/source/common/ucasemap.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
*
6
*   Copyright (C) 2005-2016, International Business Machines
7
*   Corporation and others.  All Rights Reserved.
8
*
9
*******************************************************************************
10
*   file name:  ucasemap.cpp
11
*   encoding:   UTF-8
12
*   tab size:   8 (not used)
13
*   indentation:4
14
*
15
*   created on: 2005may06
16
*   created by: Markus W. Scherer
17
*
18
*   Case mapping service object and functions using it.
19
*/
20
21
#include "unicode/utypes.h"
22
#include "unicode/brkiter.h"
23
#include "unicode/bytestream.h"
24
#include "unicode/casemap.h"
25
#include "unicode/edits.h"
26
#include "unicode/stringoptions.h"
27
#include "unicode/stringpiece.h"
28
#include "unicode/ubrk.h"
29
#include "unicode/uloc.h"
30
#include "unicode/ustring.h"
31
#include "unicode/ucasemap.h"
32
#if !UCONFIG_NO_BREAK_ITERATION
33
#include "unicode/utext.h"
34
#endif
35
#include "unicode/utf.h"
36
#include "unicode/utf8.h"
37
#include "unicode/utf16.h"
38
#include "bytesinkutil.h"
39
#include "cmemory.h"
40
#include "cstring.h"
41
#include "uassert.h"
42
#include "ucase.h"
43
#include "ucasemap_imp.h"
44
45
U_NAMESPACE_USE
46
47
/* UCaseMap service object -------------------------------------------------- */
48
49
// The public type, unicode/ucasemap.h struct UCaseMap, is an opaque C type.
50
// We define a parallel C++ type in the ICU namespace for entry point renaming.
51
52
U_NAMESPACE_BEGIN
53
54
UCaseMapImpl::UCaseMapImpl(const char *localeID, uint32_t opts, UErrorCode *pErrorCode) :
55
#if !UCONFIG_NO_BREAK_ITERATION
56
7.29k
        iter(nullptr),
57
#endif
58
7.29k
        caseLocale(UCASE_LOC_UNKNOWN), options(opts) {
59
7.29k
    ucasemap_setLocale(reinterpret_cast<UCaseMap *>(this), localeID, pErrorCode);
60
7.29k
}
61
62
7.29k
UCaseMapImpl::~UCaseMapImpl() {
63
7.29k
#if !UCONFIG_NO_BREAK_ITERATION
64
7.29k
    delete iter;
65
7.29k
#endif
66
7.29k
}
67
68
U_NAMESPACE_END
69
70
U_CAPI UCaseMap * U_EXPORT2
71
7.29k
ucasemap_open(const char *locale, uint32_t options, UErrorCode *pErrorCode) {
72
7.29k
    if(U_FAILURE(*pErrorCode)) {
73
0
        return nullptr;
74
0
    }
75
7.29k
    UCaseMapImpl *csm = new UCaseMapImpl(locale, options, pErrorCode);
76
7.29k
    if(csm==nullptr) {
77
0
        *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
78
0
        return nullptr;
79
7.29k
    } else if (U_FAILURE(*pErrorCode)) {
80
0
        delete csm;
81
0
        return nullptr;
82
0
    }
83
7.29k
    return reinterpret_cast<UCaseMap *>(csm);
84
7.29k
}
85
86
U_CAPI void U_EXPORT2
87
7.29k
ucasemap_close(UCaseMap *csm) {
88
7.29k
    delete reinterpret_cast<UCaseMapImpl *>(csm);
89
7.29k
}
90
91
U_CAPI const char* U_EXPORT2
92
0
ucasemap_getLocale(const UCaseMap* csm U_LIFETIME_BOUND) {
93
0
    return reinterpret_cast<const UCaseMapImpl *>(csm)->locale;
94
0
}
95
96
U_CAPI uint32_t U_EXPORT2
97
0
ucasemap_getOptions(const UCaseMap *csm) {
98
0
    return reinterpret_cast<const UCaseMapImpl *>(csm)->options;
99
0
}
100
101
U_CAPI void U_EXPORT2
102
7.29k
ucasemap_setLocale(UCaseMap *csm, const char *locale, UErrorCode *pErrorCode) {
103
7.29k
    if(U_FAILURE(*pErrorCode)) {
104
0
        return;
105
0
    }
106
7.29k
    auto *impl = reinterpret_cast<UCaseMapImpl *>(csm);
107
7.29k
    if (locale != nullptr && *locale == 0) {
108
0
        impl->locale[0] = 0;
109
0
        impl->caseLocale = UCASE_LOC_ROOT;
110
0
        return;
111
0
    }
112
113
7.29k
    UErrorCode bufferStatus = U_ZERO_ERROR;
114
7.29k
    int32_t length=uloc_getName(locale, impl->locale, (int32_t)sizeof(impl->locale), &bufferStatus);
115
7.29k
    if(bufferStatus==U_BUFFER_OVERFLOW_ERROR || (U_SUCCESS(bufferStatus) && length==sizeof(impl->locale))) {
116
0
        bufferStatus = U_ZERO_ERROR;
117
        /* we only really need the language code for case mappings */
118
0
        length=uloc_getLanguage(locale, impl->locale, (int32_t)sizeof(impl->locale), &bufferStatus);
119
0
    }
120
7.29k
    if(U_FAILURE(bufferStatus)) {
121
0
        *pErrorCode=bufferStatus;
122
7.29k
    } else if(length==sizeof(impl->locale)) {
123
0
        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
124
0
    }
125
7.29k
    if(U_SUCCESS(*pErrorCode)) {     
126
7.29k
        impl->caseLocale = ucase_getCaseLocale(impl->locale);
127
7.29k
    } else {
128
0
        impl->locale[0]=0;
129
0
        impl->caseLocale = UCASE_LOC_ROOT;
130
0
    }
131
7.29k
}
132
133
U_CAPI void U_EXPORT2
134
0
ucasemap_setOptions(UCaseMap *csm, uint32_t options, UErrorCode *pErrorCode) {
135
0
    if(U_FAILURE(*pErrorCode)) {
136
0
        return;
137
0
    }
138
0
    reinterpret_cast<UCaseMapImpl *>(csm)->options=options;
139
0
}
140
141
/* UTF-8 string case mappings ----------------------------------------------- */
142
143
/* TODO(markus): Move to a new, separate utf8case.cpp file. */
144
145
namespace {
146
147
/* append a full case mapping result, see UCASE_MAX_STRING_LENGTH */
148
inline UBool
149
appendResult(int32_t cpLength, int32_t result, const char16_t *s,
150
35.9M
             ByteSink &sink, uint32_t options, icu::Edits *edits, UErrorCode &errorCode) {
151
35.9M
    U_ASSERT(U_SUCCESS(errorCode));
152
153
    /* decode the result */
154
35.9M
    if(result<0) {
155
        /* (not) original code point */
156
32.3M
        if(edits!=nullptr) {
157
0
            edits->addUnchanged(cpLength);
158
0
        }
159
32.3M
        if((options & U_OMIT_UNCHANGED_TEXT) == 0) {
160
10.2M
            ByteSinkUtil::appendCodePoint(cpLength, ~result, sink);
161
10.2M
        }
162
32.3M
    } else {
163
3.57M
        if(result<=UCASE_MAX_STRING_LENGTH) {
164
            // string: "result" is the UTF-16 length
165
59.4k
            return ByteSinkUtil::appendChange(cpLength, s, result, sink, edits, errorCode);
166
3.51M
        } else {
167
3.51M
            ByteSinkUtil::appendCodePoint(cpLength, result, sink, edits);
168
3.51M
        }
169
3.57M
    }
170
35.8M
    return true;
171
35.9M
}
172
173
// See unicode/utf8.h U8_APPEND_UNSAFE().
174
324k
inline uint8_t getTwoByteLead(UChar32 c) { return static_cast<uint8_t>((c >> 6) | 0xc0); }
175
288k
inline uint8_t getTwoByteTrail(UChar32 c) { return static_cast<uint8_t>((c & 0x3f) | 0x80); }
176
177
UChar32 U_CALLCONV
178
235k
utf8_caseContextIterator(void *context, int8_t dir) {
179
235k
    UCaseContext* csc = static_cast<UCaseContext*>(context);
180
235k
    UChar32 c;
181
182
235k
    if(dir<0) {
183
        /* reset for backward iteration */
184
86.1k
        csc->index=csc->cpStart;
185
86.1k
        csc->dir=dir;
186
149k
    } else if(dir>0) {
187
        /* reset for forward iteration */
188
109k
        csc->index=csc->cpLimit;
189
109k
        csc->dir=dir;
190
109k
    } else {
191
        /* continue current iteration direction */
192
39.4k
        dir=csc->dir;
193
39.4k
    }
194
195
235k
    if(dir<0) {
196
115k
        if(csc->start<csc->index) {
197
115k
            U8_PREV((const uint8_t *)csc->p, csc->start, csc->index, c);
198
115k
            return c;
199
115k
        }
200
120k
    } else {
201
120k
        if(csc->index<csc->limit) {
202
119k
            U8_NEXT((const uint8_t *)csc->p, csc->index, csc->limit, c);
203
119k
            return c;
204
119k
        }
205
120k
    }
206
491
    return U_SENTINEL;
207
235k
}
208
209
/**
210
 * caseLocale >= 0: Lowercases [srcStart..srcLimit[ but takes context [0..srcLength[ into account.
211
 * caseLocale < 0: Case-folds [srcStart..srcLimit[.
212
 */
213
void toLower(int32_t caseLocale, uint32_t options,
214
             const uint8_t *src, UCaseContext *csc, int32_t srcStart, int32_t srcLimit,
215
1.86M
             icu::ByteSink &sink, icu::Edits *edits, UErrorCode &errorCode) {
216
1.86M
    const int8_t *latinToLower;
217
1.86M
    if (caseLocale == UCASE_LOC_ROOT ||
218
481k
            (caseLocale >= 0 ?
219
480k
                !(caseLocale == UCASE_LOC_TURKISH || caseLocale == UCASE_LOC_LITHUANIAN) :
220
1.82M
                (options & _FOLD_CASE_OPTIONS_MASK) == U_FOLD_CASE_DEFAULT)) {
221
1.82M
        latinToLower = LatinCase::TO_LOWER_NORMAL;
222
1.82M
    } else {
223
42.2k
        latinToLower = LatinCase::TO_LOWER_TR_LT;
224
42.2k
    }
225
1.86M
    const UTrie2 *trie = ucase_getTrie();
226
1.86M
    int32_t prev = srcStart;
227
1.86M
    int32_t srcIndex = srcStart;
228
2.76M
    for (;;) {
229
        // fast path for simple cases
230
2.76M
        int32_t cpStart;
231
2.76M
        UChar32 c;
232
40.4M
        for (;;) {
233
40.4M
            if (U_FAILURE(errorCode) || srcIndex >= srcLimit) {
234
1.86M
                c = U_SENTINEL;
235
1.86M
                break;
236
1.86M
            }
237
38.5M
            uint8_t lead = src[srcIndex++];
238
38.5M
            if (lead <= 0x7f) {
239
22.3M
                int8_t d = latinToLower[lead];
240
22.3M
                if (d == LatinCase::EXC) {
241
655k
                    cpStart = srcIndex - 1;
242
655k
                    c = lead;
243
655k
                    break;
244
655k
                }
245
21.6M
                if (d == 0) { continue; }
246
2.13M
                ByteSinkUtil::appendUnchanged(src + prev, srcIndex - 1 - prev,
247
2.13M
                                              sink, options, edits, errorCode);
248
2.13M
                char ascii = static_cast<char>(lead + d);
249
2.13M
                sink.Append(&ascii, 1);
250
2.13M
                if (edits != nullptr) {
251
0
                    edits->addReplace(1, 1);
252
0
                }
253
2.13M
                prev = srcIndex;
254
2.13M
                continue;
255
21.6M
            } else if (lead < 0xe3) {
256
10.3M
                uint8_t t;
257
10.3M
                if (0xc2 <= lead && lead <= 0xc5 && srcIndex < srcLimit &&
258
1.12M
                        (t = src[srcIndex] - 0x80) <= 0x3f) {
259
                    // U+0080..U+017F
260
76.6k
                    ++srcIndex;
261
76.6k
                    c = ((lead - 0xc0) << 6) | t;
262
76.6k
                    int8_t d = latinToLower[c];
263
76.6k
                    if (d == LatinCase::EXC) {
264
13.0k
                        cpStart = srcIndex - 2;
265
13.0k
                        break;
266
13.0k
                    }
267
63.6k
                    if (d == 0) { continue; }
268
26.9k
                    ByteSinkUtil::appendUnchanged(src + prev, srcIndex - 2 - prev,
269
26.9k
                                                  sink, options, edits, errorCode);
270
26.9k
                    ByteSinkUtil::appendTwoBytes(c + d, sink);
271
26.9k
                    if (edits != nullptr) {
272
0
                        edits->addReplace(2, 2);
273
0
                    }
274
26.9k
                    prev = srcIndex;
275
26.9k
                    continue;
276
63.6k
                }
277
10.3M
            } else if ((lead <= 0xe9 || lead == 0xeb || lead == 0xec) &&
278
872k
                    (srcIndex + 2) <= srcLimit &&
279
871k
                    U8_IS_TRAIL(src[srcIndex]) && U8_IS_TRAIL(src[srcIndex + 1])) {
280
                // most of CJK: no case mappings
281
439k
                srcIndex += 2;
282
439k
                continue;
283
439k
            }
284
15.7M
            cpStart = --srcIndex;
285
15.7M
            U8_NEXT(src, srcIndex, srcLimit, c);
286
15.7M
            if (c < 0) {
287
                // ill-formed UTF-8
288
9.72M
                continue;
289
9.72M
            }
290
5.99M
            uint16_t props = UTRIE2_GET16(trie, c);
291
5.99M
            if (UCASE_HAS_EXCEPTION(props)) { break; }
292
5.76M
            int32_t delta;
293
5.76M
            if (!UCASE_IS_UPPER_OR_TITLE(props) || (delta = UCASE_GET_DELTA(props)) == 0) {
294
5.67M
                continue;
295
5.67M
            }
296
91.4k
            ByteSinkUtil::appendUnchanged(src + prev, cpStart - prev,
297
91.4k
                                          sink, options, edits, errorCode);
298
91.4k
            ByteSinkUtil::appendCodePoint(srcIndex - cpStart, c + delta, sink, edits);
299
91.4k
            prev = srcIndex;
300
91.4k
        }
301
2.76M
        if (c < 0) {
302
1.86M
            break;
303
1.86M
        }
304
        // slow path
305
899k
        const char16_t *s;
306
899k
        if (caseLocale >= 0) {
307
273k
            csc->cpStart = cpStart;
308
273k
            csc->cpLimit = srcIndex;
309
273k
            c = ucase_toFullLower(c, utf8_caseContextIterator, csc, &s, caseLocale);
310
626k
        } else {
311
626k
            c = ucase_toFullFolding(c, &s, options);
312
626k
        }
313
899k
        if (c >= 0) {
314
761k
            ByteSinkUtil::appendUnchanged(src + prev, cpStart - prev,
315
761k
                                          sink, options, edits, errorCode);
316
761k
            appendResult(srcIndex - cpStart, c, s, sink, options, edits, errorCode);
317
761k
            prev = srcIndex;
318
761k
        }
319
899k
    }
320
1.86M
    ByteSinkUtil::appendUnchanged(src + prev, srcIndex - prev,
321
1.86M
                                  sink, options, edits, errorCode);
322
1.86M
}
323
324
void toUpper(int32_t caseLocale, uint32_t options,
325
             const uint8_t *src, UCaseContext *csc, int32_t srcLength,
326
648
             icu::ByteSink &sink, icu::Edits *edits, UErrorCode &errorCode) {
327
648
    const int8_t *latinToUpper;
328
648
    if (caseLocale == UCASE_LOC_TURKISH) {
329
37
        latinToUpper = LatinCase::TO_UPPER_TR;
330
611
    } else {
331
611
        latinToUpper = LatinCase::TO_UPPER_NORMAL;
332
611
    }
333
648
    const UTrie2 *trie = ucase_getTrie();
334
648
    int32_t prev = 0;
335
648
    int32_t srcIndex = 0;
336
51.4k
    for (;;) {
337
        // fast path for simple cases
338
51.4k
        int32_t cpStart;
339
51.4k
        UChar32 c;
340
10.6M
        for (;;) {
341
10.6M
            if (U_FAILURE(errorCode) || srcIndex >= srcLength) {
342
648
                c = U_SENTINEL;
343
648
                break;
344
648
            }
345
10.6M
            uint8_t lead = src[srcIndex++];
346
10.6M
            if (lead <= 0x7f) {
347
6.29M
                int8_t d = latinToUpper[lead];
348
6.29M
                if (d == LatinCase::EXC) {
349
495
                    cpStart = srcIndex - 1;
350
495
                    c = lead;
351
495
                    break;
352
495
                }
353
6.29M
                if (d == 0) { continue; }
354
802k
                ByteSinkUtil::appendUnchanged(src + prev, srcIndex - 1 - prev,
355
802k
                                              sink, options, edits, errorCode);
356
802k
                char ascii = static_cast<char>(lead + d);
357
802k
                sink.Append(&ascii, 1);
358
802k
                if (edits != nullptr) {
359
0
                    edits->addReplace(1, 1);
360
0
                }
361
802k
                prev = srcIndex;
362
802k
                continue;
363
6.29M
            } else if (lead < 0xe3) {
364
2.83M
                uint8_t t;
365
2.83M
                if (0xc2 <= lead && lead <= 0xc5 && srcIndex < srcLength &&
366
100k
                        (t = src[srcIndex] - 0x80) <= 0x3f) {
367
                    // U+0080..U+017F
368
25.9k
                    ++srcIndex;
369
25.9k
                    c = ((lead - 0xc0) << 6) | t;
370
25.9k
                    int8_t d = latinToUpper[c];
371
25.9k
                    if (d == LatinCase::EXC) {
372
756
                        cpStart = srcIndex - 2;
373
756
                        break;
374
756
                    }
375
25.1k
                    if (d == 0) { continue; }
376
9.53k
                    ByteSinkUtil::appendUnchanged(src + prev, srcIndex - 2 - prev,
377
9.53k
                                                  sink, options, edits, errorCode);
378
9.53k
                    ByteSinkUtil::appendTwoBytes(c + d, sink);
379
9.53k
                    if (edits != nullptr) {
380
0
                        edits->addReplace(2, 2);
381
0
                    }
382
9.53k
                    prev = srcIndex;
383
9.53k
                    continue;
384
25.1k
                }
385
2.83M
            } else if ((lead <= 0xe9 || lead == 0xeb || lead == 0xec) &&
386
376k
                    (srcIndex + 2) <= srcLength &&
387
376k
                    U8_IS_TRAIL(src[srcIndex]) && U8_IS_TRAIL(src[srcIndex + 1])) {
388
                // most of CJK: no case mappings
389
145k
                srcIndex += 2;
390
145k
                continue;
391
145k
            }
392
4.21M
            cpStart = --srcIndex;
393
4.21M
            U8_NEXT(src, srcIndex, srcLength, c);
394
4.21M
            if (c < 0) {
395
                // ill-formed UTF-8
396
3.25M
                continue;
397
3.25M
            }
398
957k
            uint16_t props = UTRIE2_GET16(trie, c);
399
957k
            if (UCASE_HAS_EXCEPTION(props)) { break; }
400
908k
            int32_t delta;
401
908k
            if (UCASE_GET_TYPE(props) != UCASE_LOWER || (delta = UCASE_GET_DELTA(props)) == 0) {
402
869k
                continue;
403
869k
            }
404
38.9k
            ByteSinkUtil::appendUnchanged(src + prev, cpStart - prev,
405
38.9k
                                          sink, options, edits, errorCode);
406
38.9k
            ByteSinkUtil::appendCodePoint(srcIndex - cpStart, c + delta, sink, edits);
407
38.9k
            prev = srcIndex;
408
38.9k
        }
409
51.4k
        if (c < 0) {
410
648
            break;
411
648
        }
412
        // slow path
413
50.7k
        csc->cpStart = cpStart;
414
50.7k
        csc->cpLimit = srcIndex;
415
50.7k
        const char16_t *s;
416
50.7k
        c = ucase_toFullUpper(c, utf8_caseContextIterator, csc, &s, caseLocale);
417
50.7k
        if (c >= 0) {
418
35.2k
            ByteSinkUtil::appendUnchanged(src + prev, cpStart - prev,
419
35.2k
                                          sink, options, edits, errorCode);
420
35.2k
            appendResult(srcIndex - cpStart, c, s, sink, options, edits, errorCode);
421
35.2k
            prev = srcIndex;
422
35.2k
        }
423
50.7k
    }
424
648
    ByteSinkUtil::appendUnchanged(src + prev, srcIndex - prev,
425
648
                                  sink, options, edits, errorCode);
426
648
}
427
428
}  // namespace
429
430
#if !UCONFIG_NO_BREAK_ITERATION
431
432
namespace {
433
434
constexpr uint8_t ACUTE_BYTE0 = u8"\u0301"[0];
435
436
constexpr uint8_t ACUTE_BYTE1 = u8"\u0301"[1];
437
438
/**
439
 * Input: c is a letter I with or without acute accent.
440
 * start is the index in src after c, and is less than segmentLimit.
441
 * If a plain i/I is followed by a plain j/J,
442
 * or an i/I with acute (precomposed or decomposed) is followed by a j/J with acute,
443
 * then we output accordingly.
444
 *
445
 * @return the src index after the titlecased sequence, or the start index if no Dutch IJ
446
 */
447
int32_t maybeTitleDutchIJ(const uint8_t *src, UChar32 c, int32_t start, int32_t segmentLimit,
448
50.6k
                          ByteSink &sink, uint32_t options, icu::Edits *edits, UErrorCode &errorCode) {
449
50.6k
    U_ASSERT(start < segmentLimit);
450
451
50.6k
    int32_t index = start;
452
50.6k
    bool withAcute = false;
453
454
    // If the conditions are met, then the following variables tell us what to output.
455
50.6k
    int32_t unchanged1 = 0;  // code units before the j, or the whole sequence (0..3)
456
50.6k
    bool doTitleJ = false;  // true if the j needs to be titlecased
457
50.6k
    int32_t unchanged2 = 0;  // after the j (0 or 1)
458
459
    // next character after the first letter
460
50.6k
    UChar32 c2;
461
50.6k
    c2 = src[index++];
462
463
    // Is the first letter an i/I with accent?
464
50.6k
    if (c == u'I') {
465
49.7k
        if (c2 == ACUTE_BYTE0 && index < segmentLimit && src[index++] == ACUTE_BYTE1) {
466
6.91k
            withAcute = true;
467
6.91k
            unchanged1 = 2;  // ACUTE is 2 code units in UTF-8
468
6.91k
            if (index == segmentLimit) { return start; }
469
6.32k
            c2 = src[index++];
470
6.32k
        }
471
49.7k
    } else {  // Í
472
928
        withAcute = true;
473
928
    }
474
475
    // Is the next character a j/J?
476
50.0k
    if (c2 == u'j') {
477
22.2k
        doTitleJ = true;
478
27.7k
    } else if (c2 == u'J') {
479
10.8k
        ++unchanged1;
480
16.9k
    } else {
481
16.9k
        return start;
482
16.9k
    }
483
484
    // A plain i/I must be followed by a plain j/J.
485
    // An i/I with acute must be followed by a j/J with acute.
486
33.0k
    if (withAcute) {
487
6.72k
        if ((index + 1) >= segmentLimit || src[index++] != ACUTE_BYTE0 || src[index++] != ACUTE_BYTE1) {
488
2.69k
            return start;
489
2.69k
        }
490
4.03k
        if (doTitleJ) {
491
342
            unchanged2 = 2;  // ACUTE is 2 code units in UTF-8
492
3.68k
        } else {
493
3.68k
            unchanged1 = unchanged1 + 2;    // ACUTE is 2 code units in UTF-8
494
3.68k
        }
495
4.03k
    }
496
497
    // There must not be another combining mark.
498
30.3k
    if (index < segmentLimit) {
499
15.1k
        int32_t cp;
500
15.1k
        int32_t i = index;
501
15.1k
        U8_NEXT(src, i, segmentLimit, cp);
502
15.1k
        uint32_t typeMask = U_GET_GC_MASK(cp);
503
15.1k
        if ((typeMask & U_GC_M_MASK) != 0) {
504
318
            return start;
505
318
        }
506
15.1k
    }
507
508
    // Output the rest of the Dutch IJ.
509
30.0k
    ByteSinkUtil::appendUnchanged(src + start, unchanged1, sink, options, edits, errorCode);
510
30.0k
    start += unchanged1;
511
30.0k
    if (doTitleJ) {
512
21.9k
        ByteSinkUtil::appendCodePoint(1, u'J', sink, edits);
513
21.9k
        ++start;
514
21.9k
    }
515
30.0k
    ByteSinkUtil::appendUnchanged(src + start, unchanged2, sink, options, edits, errorCode);
516
517
30.0k
    U_ASSERT(start + unchanged2 == index);
518
30.0k
    return index;
519
30.3k
}
520
521
}  // namespace
522
523
U_CFUNC void U_CALLCONV
524
ucasemap_internalUTF8ToTitle(
525
        int32_t caseLocale, uint32_t options, BreakIterator *iter,
526
        const uint8_t *src, int32_t srcLength,
527
        ByteSink &sink, icu::Edits *edits,
528
4.42k
        UErrorCode &errorCode) {
529
4.42k
    if (!ustrcase_checkTitleAdjustmentOptions(options, errorCode)) {
530
11
        return;
531
11
    }
532
533
    /* set up local variables */
534
4.41k
    UCaseContext csc=UCASECONTEXT_INITIALIZER;
535
4.41k
    csc.p=(void *)src;
536
4.41k
    csc.limit=srcLength;
537
4.41k
    int32_t prev=0;
538
4.41k
    UBool isFirstIndex=true;
539
540
    /* titlecasing loop */
541
66.6M
    while(prev<srcLength) {
542
        /* find next index where to titlecase */
543
66.6M
        int32_t index;
544
66.6M
        if(isFirstIndex) {
545
4.35k
            isFirstIndex=false;
546
4.35k
            index=iter->first();
547
66.6M
        } else {
548
66.6M
            index=iter->next();
549
66.6M
        }
550
66.6M
        if(index==UBRK_DONE || index>srcLength) {
551
0
            index=srcLength;
552
0
        }
553
554
        /*
555
         * Segment [prev..index[ into 3 parts:
556
         * a) skipped characters (copy as-is) [prev..titleStart[
557
         * b) first letter (titlecase)              [titleStart..titleLimit[
558
         * c) subsequent characters (lowercase)                 [titleLimit..index[
559
         */
560
66.6M
        if(prev<index) {
561
            /* find and copy skipped characters [prev..titleStart[ */
562
66.6M
            int32_t titleStart=prev;
563
66.6M
            int32_t titleLimit=prev;
564
66.6M
            UChar32 c;
565
66.6M
            U8_NEXT(src, titleLimit, index, c);
566
66.6M
            if ((options&U_TITLECASE_NO_BREAK_ADJUSTMENT)==0) {
567
                // Adjust the titlecasing index to the next cased character,
568
                // or to the next letter/number/symbol/private use.
569
                // Stop with titleStart<titleLimit<=index
570
                // if there is a character to be titlecased,
571
                // or else stop with titleStart==titleLimit==index.
572
39.7M
                UBool toCased = (options&U_TITLECASE_ADJUST_TO_CASED) != 0;
573
42.6M
                while (toCased ? UCASE_NONE==ucase_getType(c) : !ustrcase_isLNS(c)) {
574
34.0M
                    titleStart=titleLimit;
575
34.0M
                    if(titleLimit==index) {
576
31.0M
                        break;
577
31.0M
                    }
578
2.98M
                    U8_NEXT(src, titleLimit, index, c);
579
2.98M
                }
580
39.7M
                if (prev < titleStart) {
581
31.1M
                    if (!ByteSinkUtil::appendUnchanged(src+prev, titleStart-prev,
582
31.1M
                                                       sink, options, edits, errorCode)) {
583
0
                        return;
584
0
                    }
585
31.1M
                }
586
39.7M
            }
587
588
66.6M
            if(titleStart<titleLimit) {
589
                /* titlecase c which is from [titleStart..titleLimit[ */
590
35.6M
                if(c>=0) {
591
30.0M
                    csc.cpStart=titleStart;
592
30.0M
                    csc.cpLimit=titleLimit;
593
30.0M
                    const char16_t *s;
594
30.0M
                    c=ucase_toFullTitle(c, utf8_caseContextIterator, &csc, &s, caseLocale);
595
30.0M
                    if (!appendResult(titleLimit-titleStart, c, s, sink, options, edits, errorCode)) {
596
0
                        return;
597
0
                    }
598
30.0M
                } else {
599
                    // Malformed UTF-8.
600
5.55M
                    if (!ByteSinkUtil::appendUnchanged(src+titleStart, titleLimit-titleStart,
601
5.55M
                                                       sink, options, edits, errorCode)) {
602
0
                        return;
603
0
                    }
604
5.55M
                }
605
606
                /* Special case Dutch IJ titlecasing */
607
35.6M
                if (titleLimit < index &&
608
2.41M
                    caseLocale == UCASE_LOC_DUTCH) {
609
521k
                    if (c < 0) {
610
312k
                        c = ~c;
611
312k
                    }
612
613
521k
                    if (c == u'I' || c == u'Í') {
614
50.6k
                        titleLimit = maybeTitleDutchIJ(src, c, titleLimit, index, sink, options, edits, errorCode);
615
50.6k
                    }
616
521k
                }
617
618
                /* lowercase [titleLimit..index[ */
619
35.6M
                if(titleLimit<index) {
620
2.40M
                    if((options&U_TITLECASE_NO_LOWERCASE)==0) {
621
                        /* Normal operation: Lowercase the rest of the word. */
622
1.86M
                        toLower(caseLocale, options,
623
1.86M
                                src, &csc, titleLimit, index,
624
1.86M
                                sink, edits, errorCode);
625
1.86M
                        if(U_FAILURE(errorCode)) {
626
0
                            return;
627
0
                        }
628
1.86M
                    } else {
629
                        /* Optionally just copy the rest of the word unchanged. */
630
538k
                        if (!ByteSinkUtil::appendUnchanged(src+titleLimit, index-titleLimit,
631
538k
                                                           sink, options, edits, errorCode)) {
632
0
                            return;
633
0
                        }
634
538k
                    }
635
2.40M
                }
636
35.6M
            }
637
66.6M
        }
638
639
66.6M
        prev=index;
640
66.6M
    }
641
4.41k
}
642
643
#endif
644
645
U_NAMESPACE_BEGIN
646
namespace GreekUpper {
647
648
206k
UBool isFollowedByCasedLetter(const uint8_t *s, int32_t i, int32_t length) {
649
210k
    while (i < length) {
650
210k
        UChar32 c;
651
210k
        U8_NEXT(s, i, length, c);
652
210k
        int32_t type = ucase_getTypeOrIgnorable(c);
653
210k
        if ((type & UCASE_IGNORABLE) != 0) {
654
            // Case-ignorable, continue with the loop.
655
206k
        } else if (type != UCASE_NONE) {
656
19.7k
            return true;  // Followed by cased letter.
657
186k
        } else {
658
186k
            return false;  // Uncased and not case-ignorable.
659
186k
        }
660
210k
    }
661
90
    return false;  // Not followed by cased letter.
662
206k
}
663
664
// Keep this consistent with the UTF-16 version in ustrcase.cpp and the Java version in CaseMap.java.
665
void toUpper(uint32_t options,
666
             const uint8_t *src, int32_t srcLength,
667
             ByteSink &sink, Edits *edits,
668
798
             UErrorCode &errorCode) {
669
798
    uint32_t state = 0;
670
8.30M
    for (int32_t i = 0; i < srcLength;) {
671
8.30M
        int32_t nextIndex = i;
672
8.30M
        UChar32 c;
673
8.30M
        U8_NEXT(src, nextIndex, srcLength, c);
674
8.30M
        uint32_t nextState = 0;
675
8.30M
        int32_t type = ucase_getTypeOrIgnorable(c);
676
8.30M
        if ((type & UCASE_IGNORABLE) != 0) {
677
            // c is case-ignorable
678
381k
            nextState |= (state & AFTER_CASED);
679
7.92M
        } else if (type != UCASE_NONE) {
680
            // c is cased
681
1.76M
            nextState |= AFTER_CASED;
682
1.76M
        }
683
8.30M
        uint32_t data = getLetterData(c);
684
8.30M
        if (data > 0) {
685
330k
            uint32_t upper = data & UPPER_MASK;
686
            // Add a dialytika to this iota or ypsilon vowel
687
            // if we removed a tonos from the previous vowel,
688
            // and that previous vowel did not also have (or gain) a dialytika.
689
            // Adding one only to the final vowel in a longer sequence
690
            // (which does not occur in normal writing) would require lookahead.
691
            // Set the same flag as for preserving an existing dialytika.
692
330k
            if ((data & HAS_VOWEL) != 0 &&
693
268k
                (state & (AFTER_VOWEL_WITH_PRECOMPOSED_ACCENT | AFTER_VOWEL_WITH_COMBINING_ACCENT)) !=
694
268k
                    0 &&
695
17.7k
                (upper == 0x399 || upper == 0x3A5)) {
696
2.34k
                data |= (state & AFTER_VOWEL_WITH_PRECOMPOSED_ACCENT) != 0 ? HAS_DIALYTIKA
697
2.34k
                                                                           : HAS_COMBINING_DIALYTIKA;
698
2.34k
            }
699
330k
            int32_t numYpogegrammeni = 0;  // Map each one to a trailing, spacing, capital iota.
700
330k
            if ((data & HAS_YPOGEGRAMMENI) != 0) {
701
15.0k
                numYpogegrammeni = 1;
702
15.0k
            }
703
330k
            const UBool hasPrecomposedAccent = (data & HAS_ACCENT) != 0;
704
            // Skip combining diacritics after this Greek letter.
705
330k
            int32_t nextNextIndex = nextIndex;
706
384k
            while (nextIndex < srcLength) {
707
384k
                UChar32 c2;
708
384k
                U8_NEXT(src, nextNextIndex, srcLength, c2);
709
384k
                uint32_t diacriticData = getDiacriticData(c2);
710
384k
                if (diacriticData != 0) {
711
54.1k
                    data |= diacriticData;
712
54.1k
                    if ((diacriticData & HAS_YPOGEGRAMMENI) != 0) {
713
440
                        ++numYpogegrammeni;
714
440
                    }
715
54.1k
                    nextIndex = nextNextIndex;
716
330k
                } else {
717
330k
                    break;  // not a Greek diacritic
718
330k
                }
719
384k
            }
720
330k
            if ((data & HAS_VOWEL_AND_ACCENT_AND_DIALYTIKA) == HAS_VOWEL_AND_ACCENT) {
721
249k
                nextState |= hasPrecomposedAccent ? AFTER_VOWEL_WITH_PRECOMPOSED_ACCENT
722
249k
                                                  : AFTER_VOWEL_WITH_COMBINING_ACCENT;
723
249k
            }
724
            // Map according to Greek rules.
725
330k
            UBool addTonos = false;
726
330k
            if (upper == 0x397 &&
727
231k
                    (data & HAS_ACCENT) != 0 &&
728
231k
                    numYpogegrammeni == 0 &&
729
230k
                    (state & AFTER_CASED) == 0 &&
730
206k
                    !isFollowedByCasedLetter(src, nextIndex, srcLength)) {
731
                // Keep disjunctive "or" with (only) a tonos.
732
                // We use the same "word boundary" conditions as for the Final_Sigma test.
733
186k
                if (hasPrecomposedAccent) {
734
184k
                    upper = 0x389;  // Preserve the precomposed form.
735
184k
                } else {
736
2.00k
                    addTonos = true;
737
2.00k
                }
738
186k
            } else if ((data & HAS_DIALYTIKA) != 0) {
739
                // Preserve a vowel with dialytika in precomposed form if it exists.
740
8.39k
                if (upper == 0x399) {
741
2.66k
                    upper = 0x3AA;
742
2.66k
                    data &= ~HAS_EITHER_DIALYTIKA;
743
5.73k
                } else if (upper == 0x3A5) {
744
5.38k
                    upper = 0x3AB;
745
5.38k
                    data &= ~HAS_EITHER_DIALYTIKA;
746
5.38k
                }
747
8.39k
            }
748
749
330k
            UBool change;
750
330k
            if (edits == nullptr && (options & U_OMIT_UNCHANGED_TEXT) == 0) {
751
6.37k
                change = true;  // common, simple usage
752
324k
            } else {
753
                // Find out first whether we are changing the text.
754
324k
                U_ASSERT(0x370 <= upper && upper <= 0x3ff);  // 2-byte UTF-8, main Greek block
755
324k
                change = (i + 2) > nextIndex ||
756
324k
                        src[i] != getTwoByteLead(upper) || src[i + 1] != getTwoByteTrail(upper) ||
757
80.4k
                        numYpogegrammeni > 0;
758
324k
                int32_t i2 = i + 2;
759
324k
                if ((data & HAS_EITHER_DIALYTIKA) != 0) {
760
6.23k
                    change |= (i2 + 2) > nextIndex ||
761
5.89k
                            src[i2] != static_cast<uint8_t>(u8"\u0308"[0]) ||
762
402
                            src[i2 + 1] != static_cast<uint8_t>(u8"\u0308"[1]);
763
6.23k
                    i2 += 2;
764
6.23k
                }
765
324k
                if (addTonos) {
766
1.99k
                    change |= (i2 + 2) > nextIndex ||
767
653
                            src[i2] != static_cast<uint8_t>(u8"\u0301"[0]) ||
768
384
                            src[i2 + 1] != static_cast<uint8_t>(u8"\u0301"[1]);
769
1.99k
                    i2 += 2;
770
1.99k
                }
771
324k
                int32_t oldLength = nextIndex - i;
772
324k
                int32_t newLength = (i2 - i) + numYpogegrammeni * 2;  // 2 bytes per U+0399
773
324k
                change |= oldLength != newLength;
774
324k
                if (change) {
775
254k
                    if (edits != nullptr) {
776
0
                        edits->addReplace(oldLength, newLength);
777
0
                    }
778
254k
                } else {
779
69.2k
                    if (edits != nullptr) {
780
0
                        edits->addUnchanged(oldLength);
781
0
                    }
782
                    // Write unchanged text?
783
69.2k
                    change = (options & U_OMIT_UNCHANGED_TEXT) == 0;
784
69.2k
                }
785
324k
            }
786
787
330k
            if (change) {
788
261k
                ByteSinkUtil::appendTwoBytes(upper, sink);
789
261k
                if ((data & HAS_EITHER_DIALYTIKA) != 0) {
790
6.24k
                    sink.AppendU8(u8"\u0308", 2);  // restore or add a dialytika
791
6.24k
                }
792
261k
                if (addTonos) {
793
1.97k
                    sink.AppendU8(u8"\u0301", 2);
794
1.97k
                }
795
276k
                while (numYpogegrammeni > 0) {
796
15.5k
                    sink.AppendU8(u8"\u0399", 2);
797
15.5k
                    --numYpogegrammeni;
798
15.5k
                }
799
261k
            }
800
7.97M
        } else if(c>=0) {
801
5.05M
            const char16_t *s;
802
5.05M
            c=ucase_toFullUpper(c, nullptr, nullptr, &s, UCASE_LOC_GREEK);
803
5.05M
            if (!appendResult(nextIndex - i, c, s, sink, options, edits, errorCode)) {
804
0
                return;
805
0
            }
806
5.05M
        } else {
807
            // Malformed UTF-8.
808
2.92M
            if (!ByteSinkUtil::appendUnchanged(src+i, nextIndex-i,
809
2.92M
                                               sink, options, edits, errorCode)) {
810
0
                return;
811
0
            }
812
2.92M
        }
813
8.30M
        i = nextIndex;
814
8.30M
        state = nextState;
815
8.30M
    }
816
798
}
817
818
}  // namespace GreekUpper
819
U_NAMESPACE_END
820
821
static void U_CALLCONV
822
ucasemap_internalUTF8ToLower(int32_t caseLocale, uint32_t options, UCASEMAP_BREAK_ITERATOR_UNUSED
823
                             const uint8_t *src, int32_t srcLength,
824
                             icu::ByteSink &sink, icu::Edits *edits,
825
1.18k
                             UErrorCode &errorCode) {
826
1.18k
    UCaseContext csc=UCASECONTEXT_INITIALIZER;
827
1.18k
    csc.p=(void *)src;
828
1.18k
    csc.limit=srcLength;
829
1.18k
    toLower(
830
1.18k
        caseLocale, options,
831
1.18k
        src, &csc, 0, srcLength,
832
1.18k
        sink, edits, errorCode);
833
1.18k
}
834
835
static void U_CALLCONV
836
ucasemap_internalUTF8ToUpper(int32_t caseLocale, uint32_t options, UCASEMAP_BREAK_ITERATOR_UNUSED
837
                             const uint8_t *src, int32_t srcLength,
838
                             icu::ByteSink &sink, icu::Edits *edits,
839
1.44k
                             UErrorCode &errorCode) {
840
1.44k
    if (caseLocale == UCASE_LOC_GREEK) {
841
798
        GreekUpper::toUpper(options, src, srcLength, sink, edits, errorCode);
842
798
    } else {
843
648
        UCaseContext csc=UCASECONTEXT_INITIALIZER;
844
648
        csc.p=(void *)src;
845
648
        csc.limit=srcLength;
846
648
        toUpper(
847
648
            caseLocale, options,
848
648
            src, &csc, srcLength,
849
648
            sink, edits, errorCode);
850
648
    }
851
1.44k
}
852
853
static void U_CALLCONV
854
ucasemap_internalUTF8Fold(int32_t /* caseLocale */, uint32_t options, UCASEMAP_BREAK_ITERATOR_UNUSED
855
                          const uint8_t *src, int32_t srcLength,
856
                          icu::ByteSink &sink, icu::Edits *edits,
857
237
                          UErrorCode &errorCode) {
858
237
    toLower(
859
237
        -1, options,
860
237
        src, nullptr, 0, srcLength,
861
237
        sink, edits, errorCode);
862
237
}
863
864
void
865
ucasemap_mapUTF8(int32_t caseLocale, uint32_t options, UCASEMAP_BREAK_ITERATOR_PARAM
866
                 const char *src, int32_t srcLength,
867
                 UTF8CaseMapper *stringCaseMapper,
868
                 icu::ByteSink &sink, icu::Edits *edits,
869
0
                 UErrorCode &errorCode) {
870
    /* check argument values */
871
0
    if (U_FAILURE(errorCode)) {
872
0
        return;
873
0
    }
874
0
    if ((src == nullptr && srcLength != 0) || srcLength < -1) {
875
0
        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
876
0
        return;
877
0
    }
878
879
    // Get the string length.
880
0
    if (srcLength == -1) {
881
0
        srcLength = static_cast<int32_t>(uprv_strlen(src));
882
0
    }
883
884
0
    if (edits != nullptr && (options & U_EDITS_NO_RESET) == 0) {
885
0
        edits->reset();
886
0
    }
887
0
    stringCaseMapper(caseLocale, options, UCASEMAP_BREAK_ITERATOR
888
0
                     reinterpret_cast<const uint8_t*>(src), srcLength, sink, edits, errorCode);
889
0
    sink.Flush();
890
0
    if (U_SUCCESS(errorCode)) {
891
0
        if (edits != nullptr) {
892
0
            edits->copyErrorTo(errorCode);
893
0
        }
894
0
    }
895
0
}
896
897
int32_t
898
ucasemap_mapUTF8(int32_t caseLocale, uint32_t options, UCASEMAP_BREAK_ITERATOR_PARAM
899
                 char *dest, int32_t destCapacity,
900
                 const char *src, int32_t srcLength,
901
                 UTF8CaseMapper *stringCaseMapper,
902
                 icu::Edits *edits,
903
7.28k
                 UErrorCode &errorCode) {
904
    /* check argument values */
905
7.28k
    if(U_FAILURE(errorCode)) {
906
0
        return 0;
907
0
    }
908
7.28k
    if( destCapacity<0 ||
909
7.28k
        (dest==nullptr && destCapacity>0) ||
910
7.28k
        (src==nullptr && srcLength!=0) || srcLength<-1
911
7.28k
    ) {
912
0
        errorCode=U_ILLEGAL_ARGUMENT_ERROR;
913
0
        return 0;
914
0
    }
915
916
    /* get the string length */
917
7.28k
    if(srcLength==-1) {
918
0
        srcLength = static_cast<int32_t>(uprv_strlen(src));
919
0
    }
920
921
    /* check for overlapping source and destination */
922
7.28k
    if( dest!=nullptr &&
923
7.28k
        ((src>=dest && src<(dest+destCapacity)) ||
924
7.28k
         (dest>=src && dest<(src+srcLength)))
925
7.28k
    ) {
926
0
        errorCode=U_ILLEGAL_ARGUMENT_ERROR;
927
0
        return 0;
928
0
    }
929
930
7.28k
    if (edits != nullptr && (options & U_EDITS_NO_RESET) == 0) {
931
0
        edits->reset();
932
0
    }
933
7.28k
    int32_t reslen = ByteSinkUtil::viaByteSinkToTerminatedChars(
934
7.28k
        dest, destCapacity,
935
7.28k
        [&](ByteSink& sink, UErrorCode& status) {
936
7.28k
            stringCaseMapper(caseLocale, options, UCASEMAP_BREAK_ITERATOR
937
7.28k
                             reinterpret_cast<const uint8_t*>(src), srcLength, sink, edits, status);
938
7.28k
        },
939
7.28k
        errorCode);
940
7.28k
    if (U_SUCCESS(errorCode) && edits != nullptr) {
941
0
        edits->copyErrorTo(errorCode);
942
0
    }
943
7.28k
    return reslen;
944
7.28k
}
945
946
/* public API functions */
947
948
U_CAPI int32_t U_EXPORT2
949
ucasemap_utf8ToLower(const UCaseMap *csm,
950
                     char *dest, int32_t destCapacity,
951
                     const char *src, int32_t srcLength,
952
1.18k
                     UErrorCode *pErrorCode) {
953
1.18k
    auto *impl = reinterpret_cast<const UCaseMapImpl *>(csm);
954
1.18k
    return ucasemap_mapUTF8(
955
1.18k
        impl->caseLocale, impl->options, UCASEMAP_BREAK_ITERATOR_NULL
956
1.18k
        dest, destCapacity,
957
1.18k
        src, srcLength,
958
1.18k
        ucasemap_internalUTF8ToLower, nullptr, *pErrorCode);
959
1.18k
}
960
961
U_CAPI int32_t U_EXPORT2
962
ucasemap_utf8ToUpper(const UCaseMap *csm,
963
                     char *dest, int32_t destCapacity,
964
                     const char *src, int32_t srcLength,
965
1.44k
                     UErrorCode *pErrorCode) {
966
1.44k
    auto *impl = reinterpret_cast<const UCaseMapImpl *>(csm);
967
1.44k
    return ucasemap_mapUTF8(
968
1.44k
        impl->caseLocale, impl->options, UCASEMAP_BREAK_ITERATOR_NULL
969
1.44k
        dest, destCapacity,
970
1.44k
        src, srcLength,
971
1.44k
        ucasemap_internalUTF8ToUpper, nullptr, *pErrorCode);
972
1.44k
}
973
974
U_CAPI int32_t U_EXPORT2
975
ucasemap_utf8FoldCase(const UCaseMap *csm,
976
                      char *dest, int32_t destCapacity,
977
                      const char *src, int32_t srcLength,
978
237
                      UErrorCode *pErrorCode) {
979
237
    auto *impl = reinterpret_cast<const UCaseMapImpl *>(csm);
980
237
    return ucasemap_mapUTF8(
981
237
        UCASE_LOC_ROOT, impl->options, UCASEMAP_BREAK_ITERATOR_NULL
982
237
        dest, destCapacity,
983
237
        src, srcLength,
984
237
        ucasemap_internalUTF8Fold, nullptr, *pErrorCode);
985
237
}
986
987
U_NAMESPACE_BEGIN
988
989
void CaseMap::utf8ToLower(
990
        const char *locale, uint32_t options,
991
        StringPiece src, ByteSink &sink, Edits *edits,
992
0
        UErrorCode &errorCode) {
993
0
    ucasemap_mapUTF8(
994
0
        ustrcase_getCaseLocale(locale), options, UCASEMAP_BREAK_ITERATOR_NULL
995
0
        src.data(), src.length(),
996
0
        ucasemap_internalUTF8ToLower, sink, edits, errorCode);
997
0
}
998
999
void CaseMap::utf8ToUpper(
1000
        const char *locale, uint32_t options,
1001
        StringPiece src, ByteSink &sink, Edits *edits,
1002
0
        UErrorCode &errorCode) {
1003
0
    ucasemap_mapUTF8(
1004
0
        ustrcase_getCaseLocale(locale), options, UCASEMAP_BREAK_ITERATOR_NULL
1005
0
        src.data(), src.length(),
1006
0
        ucasemap_internalUTF8ToUpper, sink, edits, errorCode);
1007
0
}
1008
1009
void CaseMap::utf8Fold(
1010
        uint32_t options,
1011
        StringPiece src, ByteSink &sink, Edits *edits,
1012
0
        UErrorCode &errorCode) {
1013
0
    ucasemap_mapUTF8(
1014
0
        UCASE_LOC_ROOT, options, UCASEMAP_BREAK_ITERATOR_NULL
1015
0
        src.data(), src.length(),
1016
0
        ucasemap_internalUTF8Fold, sink, edits, errorCode);
1017
0
}
1018
1019
int32_t CaseMap::utf8ToLower(
1020
        const char *locale, uint32_t options,
1021
        const char *src, int32_t srcLength,
1022
        char *dest, int32_t destCapacity, Edits *edits,
1023
0
        UErrorCode &errorCode) {
1024
0
    return ucasemap_mapUTF8(
1025
0
        ustrcase_getCaseLocale(locale), options, UCASEMAP_BREAK_ITERATOR_NULL
1026
0
        dest, destCapacity,
1027
0
        src, srcLength,
1028
0
        ucasemap_internalUTF8ToLower, edits, errorCode);
1029
0
}
1030
1031
int32_t CaseMap::utf8ToUpper(
1032
        const char *locale, uint32_t options,
1033
        const char *src, int32_t srcLength,
1034
        char *dest, int32_t destCapacity, Edits *edits,
1035
0
        UErrorCode &errorCode) {
1036
0
    return ucasemap_mapUTF8(
1037
0
        ustrcase_getCaseLocale(locale), options, UCASEMAP_BREAK_ITERATOR_NULL
1038
0
        dest, destCapacity,
1039
0
        src, srcLength,
1040
0
        ucasemap_internalUTF8ToUpper, edits, errorCode);
1041
0
}
1042
1043
int32_t CaseMap::utf8Fold(
1044
        uint32_t options,
1045
        const char *src, int32_t srcLength,
1046
        char *dest, int32_t destCapacity, Edits *edits,
1047
0
        UErrorCode &errorCode) {
1048
0
    return ucasemap_mapUTF8(
1049
        UCASE_LOC_ROOT, options, UCASEMAP_BREAK_ITERATOR_NULL
1050
0
        dest, destCapacity,
1051
0
        src, srcLength,
1052
0
        ucasemap_internalUTF8Fold, edits, errorCode);
1053
0
}
1054
1055
U_NAMESPACE_END