blob: 391140d6c5e2b9d9703d4e023871429992314204 [file] [log] [blame]
Jungshik Shin87232d82017-05-13 21:10:13 -07001// © 2016 and later: Unicode, Inc. and others.
Jungshik Shin5feb9ad2016-10-21 12:52:48 -07002// License & terms of use: http://www.unicode.org/copyright.html
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003/*
4*******************************************************************************
5*
Jungshik Shin5feb9ad2016-10-21 12:52:48 -07006* Copyright (C) 2005-2016, International Business Machines
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00007* Corporation and others. All Rights Reserved.
8*
9*******************************************************************************
10* file name: ucasemap.cpp
Jungshik Shin87232d82017-05-13 21:10:13 -070011* encoding: UTF-8
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000012* 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"
Jungshik Shin87232d82017-05-13 21:10:13 -070023#include "unicode/casemap.h"
24#include "unicode/edits.h"
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000025#include "unicode/ubrk.h"
26#include "unicode/uloc.h"
27#include "unicode/ustring.h"
28#include "unicode/ucasemap.h"
29#if !UCONFIG_NO_BREAK_ITERATION
30#include "unicode/utext.h"
31#endif
32#include "unicode/utf.h"
33#include "unicode/utf8.h"
34#include "unicode/utf16.h"
35#include "cmemory.h"
36#include "cstring.h"
Jungshik Shin87232d82017-05-13 21:10:13 -070037#include "uassert.h"
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000038#include "ucase.h"
Jungshik Shin87232d82017-05-13 21:10:13 -070039#include "ucasemap_imp.h"
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000040#include "ustr_imp.h"
41
Jungshik Shin87232d82017-05-13 21:10:13 -070042U_NAMESPACE_BEGIN
43
44namespace {
45
46// TODO: share with UTF-16? inline in ucasemap_imp.h?
47int32_t checkOverflowAndEditsError(int32_t destIndex, int32_t destCapacity,
48 Edits *edits, UErrorCode &errorCode) {
49 if (U_SUCCESS(errorCode)) {
50 if (destIndex > destCapacity) {
51 errorCode = U_BUFFER_OVERFLOW_ERROR;
52 } else if (edits != NULL) {
53 edits->copyErrorTo(errorCode);
54 }
55 }
56 return destIndex;
57}
58
59} // namespace
60
61U_NAMESPACE_END
62
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000063U_NAMESPACE_USE
64
65/* UCaseMap service object -------------------------------------------------- */
66
Jungshik Shin87232d82017-05-13 21:10:13 -070067UCaseMap::UCaseMap(const char *localeID, uint32_t opts, UErrorCode *pErrorCode) :
68#if !UCONFIG_NO_BREAK_ITERATION
69 iter(NULL),
70#endif
71 caseLocale(UCASE_LOC_UNKNOWN), options(opts) {
72 ucasemap_setLocale(this, localeID, pErrorCode);
73}
74
75UCaseMap::~UCaseMap() {
76#if !UCONFIG_NO_BREAK_ITERATION
77 delete iter;
78#endif
79}
80
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000081U_CAPI UCaseMap * U_EXPORT2
82ucasemap_open(const char *locale, uint32_t options, UErrorCode *pErrorCode) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000083 if(U_FAILURE(*pErrorCode)) {
84 return NULL;
85 }
Jungshik Shin87232d82017-05-13 21:10:13 -070086 UCaseMap *csm = new UCaseMap(locale, options, pErrorCode);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000087 if(csm==NULL) {
Jungshik Shin87232d82017-05-13 21:10:13 -070088 *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
89 return NULL;
90 } else if (U_FAILURE(*pErrorCode)) {
91 delete csm;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000092 return NULL;
93 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000094 return csm;
95}
96
97U_CAPI void U_EXPORT2
98ucasemap_close(UCaseMap *csm) {
Jungshik Shin87232d82017-05-13 21:10:13 -070099 delete csm;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000100}
101
102U_CAPI const char * U_EXPORT2
103ucasemap_getLocale(const UCaseMap *csm) {
104 return csm->locale;
105}
106
107U_CAPI uint32_t U_EXPORT2
108ucasemap_getOptions(const UCaseMap *csm) {
109 return csm->options;
110}
111
112U_CAPI void U_EXPORT2
113ucasemap_setLocale(UCaseMap *csm, const char *locale, UErrorCode *pErrorCode) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000114 if(U_FAILURE(*pErrorCode)) {
115 return;
116 }
Jungshik Shin87232d82017-05-13 21:10:13 -0700117 if (locale != NULL && *locale == 0) {
118 csm->locale[0] = 0;
119 csm->caseLocale = UCASE_LOC_ROOT;
120 return;
121 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000122
Jungshik Shin87232d82017-05-13 21:10:13 -0700123 int32_t length=uloc_getName(locale, csm->locale, (int32_t)sizeof(csm->locale), pErrorCode);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000124 if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR || length==sizeof(csm->locale)) {
125 *pErrorCode=U_ZERO_ERROR;
126 /* we only really need the language code for case mappings */
127 length=uloc_getLanguage(locale, csm->locale, (int32_t)sizeof(csm->locale), pErrorCode);
128 }
129 if(length==sizeof(csm->locale)) {
130 *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
131 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000132 if(U_SUCCESS(*pErrorCode)) {
Jungshik Shin87232d82017-05-13 21:10:13 -0700133 csm->caseLocale=UCASE_LOC_UNKNOWN;
134 csm->caseLocale = ucase_getCaseLocale(csm->locale);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000135 } else {
136 csm->locale[0]=0;
Jungshik Shin87232d82017-05-13 21:10:13 -0700137 csm->caseLocale = UCASE_LOC_ROOT;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000138 }
139}
140
141U_CAPI void U_EXPORT2
Jungshik Shin87232d82017-05-13 21:10:13 -0700142ucasemap_setOptions(UCaseMap *csm, uint32_t options, UErrorCode *pErrorCode) {
143 if(U_FAILURE(*pErrorCode)) {
144 return;
145 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000146 csm->options=options;
147}
148
149/* UTF-8 string case mappings ----------------------------------------------- */
150
Jungshik Shin87232d82017-05-13 21:10:13 -0700151/* TODO(markus): Move to a new, separate utf8case.cpp file. */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000152
153/* append a full case mapping result, see UCASE_MAX_STRING_LENGTH */
154static inline int32_t
155appendResult(uint8_t *dest, int32_t destIndex, int32_t destCapacity,
Jungshik Shin87232d82017-05-13 21:10:13 -0700156 int32_t result, const UChar *s,
157 int32_t cpLength, uint32_t options, icu::Edits *edits) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000158 UChar32 c;
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700159 int32_t length;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000160 UErrorCode errorCode;
161
162 /* decode the result */
163 if(result<0) {
164 /* (not) original code point */
Jungshik Shin87232d82017-05-13 21:10:13 -0700165 if(edits!=NULL) {
166 edits->addUnchanged(cpLength);
167 if(options & UCASEMAP_OMIT_UNCHANGED_TEXT) {
168 return destIndex;
169 }
170 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000171 c=~result;
Jungshik Shin87232d82017-05-13 21:10:13 -0700172 if(destIndex<destCapacity && c<=0x7f) { // ASCII slightly-fastpath
173 dest[destIndex++]=(uint8_t)c;
174 return destIndex;
175 }
176 length=cpLength;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000177 } else {
Jungshik Shin87232d82017-05-13 21:10:13 -0700178 if(result<=UCASE_MAX_STRING_LENGTH) {
179 // string: "result" is the UTF-16 length
180 errorCode=U_ZERO_ERROR;
181 if(destIndex<destCapacity) {
182 u_strToUTF8((char *)(dest+destIndex), destCapacity-destIndex, &length,
183 s, result, &errorCode);
184 } else {
185 u_strToUTF8(NULL, 0, &length, s, result, &errorCode);
186 }
187 if(U_FAILURE(errorCode) && errorCode != U_BUFFER_OVERFLOW_ERROR) {
188 return -1;
189 }
190 if(length>(INT32_MAX-destIndex)) {
191 return -1; // integer overflow
192 }
193 if(edits!=NULL) {
194 edits->addReplace(cpLength, length);
195 }
196 // We might have an overflow, but we know the actual length.
197 return destIndex+length;
198 } else if(destIndex<destCapacity && result<=0x7f) { // ASCII slightly-fastpath
199 dest[destIndex++]=(uint8_t)result;
200 if(edits!=NULL) {
201 edits->addReplace(cpLength, 1);
202 }
203 return destIndex;
204 } else {
205 c=result;
206 length=U8_LENGTH(c);
207 if(edits!=NULL) {
208 edits->addReplace(cpLength, length);
209 }
210 }
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700211 }
Jungshik Shin87232d82017-05-13 21:10:13 -0700212 // c>=0 single code point
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700213 if(length>(INT32_MAX-destIndex)) {
214 return -1; // integer overflow
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000215 }
216
217 if(destIndex<destCapacity) {
218 /* append the result */
Jungshik Shin87232d82017-05-13 21:10:13 -0700219 UBool isError=FALSE;
220 U8_APPEND(dest, destIndex, destCapacity, c, isError);
221 if(isError) {
222 /* overflow, nothing written */
223 destIndex+=length;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000224 }
225 } else {
226 /* preflight */
Jungshik Shin87232d82017-05-13 21:10:13 -0700227 destIndex+=length;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000228 }
229 return destIndex;
230}
231
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700232static inline int32_t
Jungshik Shin87232d82017-05-13 21:10:13 -0700233appendASCII(uint8_t *dest, int32_t destIndex, int32_t destCapacity, uint8_t c) {
234 if(destIndex<destCapacity) {
235 dest[destIndex]=c;
236 } else if(destIndex==INT32_MAX) {
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700237 return -1; // integer overflow
238 }
Jungshik Shin87232d82017-05-13 21:10:13 -0700239 return destIndex+1;
240}
241
242// See unicode/utf8.h U8_APPEND_UNSAFE().
243static inline uint8_t getTwoByteLead(UChar32 c) { return (uint8_t)((c >> 6) | 0xc0); }
244static inline uint8_t getTwoByteTrail(UChar32 c) { return (uint8_t)((c & 0x3f) | 0x80); }
245
246static inline int32_t
247appendTwoBytes(uint8_t *dest, int32_t destIndex, int32_t destCapacity, UChar32 c) {
248 U_ASSERT(0x370 <= c && c <= 0x3ff); // 2-byte UTF-8, main Greek block
249 if(2>(INT32_MAX-destIndex)) {
250 return -1; // integer overflow
251 }
252 int32_t limit=destIndex+2;
Jungshik Shin7ddf5e92016-11-10 17:11:45 -0800253 if(limit<=destCapacity) {
Jungshik Shin87232d82017-05-13 21:10:13 -0700254 dest+=destIndex;
255 dest[0]=getTwoByteLead(c);
256 dest[1]=getTwoByteTrail(c);
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700257 }
258 return limit;
259}
260
261static inline int32_t
Jungshik Shin87232d82017-05-13 21:10:13 -0700262appendTwoBytes(uint8_t *dest, int32_t destIndex, int32_t destCapacity, const char *s) {
263 if(2>(INT32_MAX-destIndex)) {
264 return -1; // integer overflow
265 }
266 int32_t limit=destIndex+2;
267 if(limit<=destCapacity) {
268 dest+=destIndex;
269 dest[0]=(uint8_t)s[0];
270 dest[1]=(uint8_t)s[1];
271 }
272 return limit;
273}
274
275static inline int32_t
276appendUnchanged(uint8_t *dest, int32_t destIndex, int32_t destCapacity,
277 const uint8_t *s, int32_t length, uint32_t options, icu::Edits *edits) {
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700278 if(length>0) {
Jungshik Shin87232d82017-05-13 21:10:13 -0700279 if(edits!=NULL) {
280 edits->addUnchanged(length);
281 if(options & UCASEMAP_OMIT_UNCHANGED_TEXT) {
282 return destIndex;
283 }
284 }
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700285 if(length>(INT32_MAX-destIndex)) {
286 return -1; // integer overflow
287 }
288 if((destIndex+length)<=destCapacity) {
289 uprv_memcpy(dest+destIndex, s, length);
290 }
291 destIndex+=length;
292 }
293 return destIndex;
294}
295
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000296static UChar32 U_CALLCONV
297utf8_caseContextIterator(void *context, int8_t dir) {
298 UCaseContext *csc=(UCaseContext *)context;
299 UChar32 c;
300
301 if(dir<0) {
302 /* reset for backward iteration */
303 csc->index=csc->cpStart;
304 csc->dir=dir;
305 } else if(dir>0) {
306 /* reset for forward iteration */
307 csc->index=csc->cpLimit;
308 csc->dir=dir;
309 } else {
310 /* continue current iteration direction */
311 dir=csc->dir;
312 }
313
314 if(dir<0) {
315 if(csc->start<csc->index) {
316 U8_PREV((const uint8_t *)csc->p, csc->start, csc->index, c);
317 return c;
318 }
319 } else {
320 if(csc->index<csc->limit) {
321 U8_NEXT((const uint8_t *)csc->p, csc->index, csc->limit, c);
322 return c;
323 }
324 }
325 return U_SENTINEL;
326}
327
328/*
329 * Case-maps [srcStart..srcLimit[ but takes
330 * context [0..srcLength[ into account.
331 */
332static int32_t
Jungshik Shin87232d82017-05-13 21:10:13 -0700333_caseMap(int32_t caseLocale, uint32_t options, UCaseMapFull *map,
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000334 uint8_t *dest, int32_t destCapacity,
335 const uint8_t *src, UCaseContext *csc,
336 int32_t srcStart, int32_t srcLimit,
Jungshik Shin87232d82017-05-13 21:10:13 -0700337 icu::Edits *edits,
338 UErrorCode &errorCode) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000339 /* case mapping loop */
Jungshik Shin87232d82017-05-13 21:10:13 -0700340 int32_t srcIndex=srcStart;
341 int32_t destIndex=0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000342 while(srcIndex<srcLimit) {
Jungshik Shin87232d82017-05-13 21:10:13 -0700343 int32_t cpStart;
344 csc->cpStart=cpStart=srcIndex;
345 UChar32 c;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000346 U8_NEXT(src, srcIndex, srcLimit, c);
347 csc->cpLimit=srcIndex;
348 if(c<0) {
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700349 // Malformed UTF-8.
Jungshik Shin87232d82017-05-13 21:10:13 -0700350 destIndex=appendUnchanged(dest, destIndex, destCapacity,
351 src+cpStart, srcIndex-cpStart, options, edits);
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700352 if(destIndex<0) {
Jungshik Shin87232d82017-05-13 21:10:13 -0700353 errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700354 return 0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000355 }
356 continue;
357 }
Jungshik Shin87232d82017-05-13 21:10:13 -0700358 const UChar *s;
359 c=map(c, utf8_caseContextIterator, csc, &s, caseLocale);
360 destIndex = appendResult(dest, destIndex, destCapacity, c, s,
361 srcIndex - cpStart, options, edits);
362 if (destIndex < 0) {
363 errorCode = U_INDEX_OUTOFBOUNDS_ERROR;
364 return 0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000365 }
366 }
367
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000368 return destIndex;
369}
370
371#if !UCONFIG_NO_BREAK_ITERATION
372
373U_CFUNC int32_t U_CALLCONV
Jungshik Shin87232d82017-05-13 21:10:13 -0700374ucasemap_internalUTF8ToTitle(
375 int32_t caseLocale, uint32_t options, BreakIterator *iter,
376 uint8_t *dest, int32_t destCapacity,
377 const uint8_t *src, int32_t srcLength,
378 icu::Edits *edits,
379 UErrorCode &errorCode) {
380 if(U_FAILURE(errorCode)) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000381 return 0;
382 }
383
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000384 /* set up local variables */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000385 UCaseContext csc=UCASECONTEXT_INITIALIZER;
386 csc.p=(void *)src;
387 csc.limit=srcLength;
Jungshik Shin87232d82017-05-13 21:10:13 -0700388 int32_t destIndex=0;
389 int32_t prev=0;
390 UBool isFirstIndex=TRUE;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000391
392 /* titlecasing loop */
393 while(prev<srcLength) {
394 /* find next index where to titlecase */
Jungshik Shin87232d82017-05-13 21:10:13 -0700395 int32_t index;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000396 if(isFirstIndex) {
397 isFirstIndex=FALSE;
Jungshik Shin87232d82017-05-13 21:10:13 -0700398 index=iter->first();
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000399 } else {
Jungshik Shin87232d82017-05-13 21:10:13 -0700400 index=iter->next();
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000401 }
Jungshik Shin87232d82017-05-13 21:10:13 -0700402 if(index==UBRK_DONE || index>srcLength) {
403 index=srcLength;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000404 }
405
406 /*
407 * Unicode 4 & 5 section 3.13 Default Case Operations:
408 *
409 * R3 toTitlecase(X): Find the word boundaries based on Unicode Standard Annex
410 * #29, "Text Boundaries." Between each pair of word boundaries, find the first
411 * cased character F. If F exists, map F to default_title(F); then map each
412 * subsequent character C to default_lower(C).
413 *
414 * In this implementation, segment [prev..index[ into 3 parts:
415 * a) uncased characters (copy as-is) [prev..titleStart[
416 * b) first case letter (titlecase) [titleStart..titleLimit[
417 * c) subsequent characters (lowercase) [titleLimit..index[
418 */
Jungshik Shin87232d82017-05-13 21:10:13 -0700419 if(prev<index) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000420 /* find and copy uncased characters [prev..titleStart[ */
Jungshik Shin87232d82017-05-13 21:10:13 -0700421 int32_t titleStart=prev;
422 int32_t titleLimit=prev;
423 UChar32 c;
424 U8_NEXT(src, titleLimit, index, c);
425 if((options&U_TITLECASE_NO_BREAK_ADJUSTMENT)==0 && UCASE_NONE==ucase_getType(c)) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000426 /* Adjust the titlecasing index (titleStart) to the next cased character. */
427 for(;;) {
428 titleStart=titleLimit;
Jungshik Shin87232d82017-05-13 21:10:13 -0700429 if(titleLimit==index) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000430 /*
431 * only uncased characters in [prev..index[
432 * stop with titleStart==titleLimit==index
433 */
434 break;
435 }
Jungshik Shin87232d82017-05-13 21:10:13 -0700436 U8_NEXT(src, titleLimit, index, c);
437 if(UCASE_NONE!=ucase_getType(c)) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000438 break; /* cased letter at [titleStart..titleLimit[ */
439 }
440 }
Jungshik Shin87232d82017-05-13 21:10:13 -0700441 destIndex=appendUnchanged(dest, destIndex, destCapacity,
442 src+prev, titleStart-prev, options, edits);
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700443 if(destIndex<0) {
Jungshik Shin87232d82017-05-13 21:10:13 -0700444 errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700445 return 0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000446 }
447 }
448
449 if(titleStart<titleLimit) {
450 /* titlecase c which is from [titleStart..titleLimit[ */
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700451 if(c>=0) {
452 csc.cpStart=titleStart;
453 csc.cpLimit=titleLimit;
Jungshik Shin87232d82017-05-13 21:10:13 -0700454 const UChar *s;
455 c=ucase_toFullTitle(c, utf8_caseContextIterator, &csc, &s, caseLocale);
456 destIndex=appendResult(dest, destIndex, destCapacity, c, s,
457 titleLimit-titleStart, options, edits);
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700458 } else {
459 // Malformed UTF-8.
Jungshik Shin87232d82017-05-13 21:10:13 -0700460 destIndex=appendUnchanged(dest, destIndex, destCapacity,
461 src+titleStart, titleLimit-titleStart, options, edits);
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700462 }
463 if(destIndex<0) {
Jungshik Shin87232d82017-05-13 21:10:13 -0700464 errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700465 return 0;
466 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000467
468 /* Special case Dutch IJ titlecasing */
Jungshik Shin87232d82017-05-13 21:10:13 -0700469 if (titleStart+1 < index &&
470 caseLocale == UCASE_LOC_DUTCH &&
471 (src[titleStart] == 0x0049 || src[titleStart] == 0x0069)) {
472 if (src[titleStart+1] == 0x006A) {
473 destIndex=appendASCII(dest, destIndex, destCapacity, 0x004A);
474 if(destIndex<0) {
475 errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
476 return 0;
477 }
478 if(edits!=NULL) {
479 edits->addReplace(1, 1);
480 }
481 titleLimit++;
482 } else if (src[titleStart+1] == 0x004A) {
483 // Keep the capital J from getting lowercased.
484 destIndex=appendUnchanged(dest, destIndex, destCapacity,
485 src+titleStart+1, 1, options, edits);
486 if(destIndex<0) {
487 errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
488 return 0;
489 }
490 titleLimit++;
491 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000492 }
Jungshik Shin87232d82017-05-13 21:10:13 -0700493
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000494 /* lowercase [titleLimit..index[ */
Jungshik Shin87232d82017-05-13 21:10:13 -0700495 if(titleLimit<index) {
496 if((options&U_TITLECASE_NO_LOWERCASE)==0) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000497 /* Normal operation: Lowercase the rest of the word. */
498 destIndex+=
499 _caseMap(
Jungshik Shin87232d82017-05-13 21:10:13 -0700500 caseLocale, options, ucase_toFullLower,
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000501 dest+destIndex, destCapacity-destIndex,
502 src, &csc,
Jungshik Shin87232d82017-05-13 21:10:13 -0700503 titleLimit, index,
504 edits, errorCode);
505 if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
506 errorCode=U_ZERO_ERROR;
507 }
508 if(U_FAILURE(errorCode)) {
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700509 return destIndex;
510 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000511 } else {
512 /* Optionally just copy the rest of the word unchanged. */
Jungshik Shin87232d82017-05-13 21:10:13 -0700513 destIndex=appendUnchanged(dest, destIndex, destCapacity,
514 src+titleLimit, index-titleLimit, options, edits);
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700515 if(destIndex<0) {
Jungshik Shin87232d82017-05-13 21:10:13 -0700516 errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700517 return 0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000518 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000519 }
520 }
521 }
522 }
523
Jungshik Shin87232d82017-05-13 21:10:13 -0700524 prev=index;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000525 }
526
Jungshik Shin87232d82017-05-13 21:10:13 -0700527 return checkOverflowAndEditsError(destIndex, destCapacity, edits, errorCode);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000528}
529
530#endif
531
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700532U_NAMESPACE_BEGIN
533namespace GreekUpper {
534
Jungshik Shin87232d82017-05-13 21:10:13 -0700535UBool isFollowedByCasedLetter(const uint8_t *s, int32_t i, int32_t length) {
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700536 while (i < length) {
537 UChar32 c;
538 U8_NEXT(s, i, length, c);
Jungshik Shin87232d82017-05-13 21:10:13 -0700539 int32_t type = ucase_getTypeOrIgnorable(c);
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700540 if ((type & UCASE_IGNORABLE) != 0) {
541 // Case-ignorable, continue with the loop.
542 } else if (type != UCASE_NONE) {
543 return TRUE; // Followed by cased letter.
544 } else {
545 return FALSE; // Uncased and not case-ignorable.
546 }
547 }
548 return FALSE; // Not followed by cased letter.
549}
550
551// Keep this consistent with the UTF-16 version in ustrcase.cpp and the Java version in CaseMap.java.
Jungshik Shin87232d82017-05-13 21:10:13 -0700552int32_t toUpper(uint32_t options,
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700553 uint8_t *dest, int32_t destCapacity,
554 const uint8_t *src, int32_t srcLength,
Jungshik Shin87232d82017-05-13 21:10:13 -0700555 Edits *edits,
556 UErrorCode &errorCode) {
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700557 int32_t destIndex=0;
558 uint32_t state = 0;
559 for (int32_t i = 0; i < srcLength;) {
560 int32_t nextIndex = i;
561 UChar32 c;
562 U8_NEXT(src, nextIndex, srcLength, c);
563 uint32_t nextState = 0;
Jungshik Shin87232d82017-05-13 21:10:13 -0700564 int32_t type = ucase_getTypeOrIgnorable(c);
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700565 if ((type & UCASE_IGNORABLE) != 0) {
566 // c is case-ignorable
567 nextState |= (state & AFTER_CASED);
568 } else if (type != UCASE_NONE) {
569 // c is cased
570 nextState |= AFTER_CASED;
571 }
572 uint32_t data = getLetterData(c);
573 if (data > 0) {
574 uint32_t upper = data & UPPER_MASK;
575 // Add a dialytika to this iota or ypsilon vowel
576 // if we removed a tonos from the previous vowel,
577 // and that previous vowel did not also have (or gain) a dialytika.
578 // Adding one only to the final vowel in a longer sequence
579 // (which does not occur in normal writing) would require lookahead.
580 // Set the same flag as for preserving an existing dialytika.
581 if ((data & HAS_VOWEL) != 0 && (state & AFTER_VOWEL_WITH_ACCENT) != 0 &&
582 (upper == 0x399 || upper == 0x3A5)) {
583 data |= HAS_DIALYTIKA;
584 }
585 int32_t numYpogegrammeni = 0; // Map each one to a trailing, spacing, capital iota.
586 if ((data & HAS_YPOGEGRAMMENI) != 0) {
587 numYpogegrammeni = 1;
588 }
589 // Skip combining diacritics after this Greek letter.
590 int32_t nextNextIndex = nextIndex;
591 while (nextIndex < srcLength) {
592 UChar32 c2;
593 U8_NEXT(src, nextNextIndex, srcLength, c2);
594 uint32_t diacriticData = getDiacriticData(c2);
595 if (diacriticData != 0) {
596 data |= diacriticData;
597 if ((diacriticData & HAS_YPOGEGRAMMENI) != 0) {
598 ++numYpogegrammeni;
599 }
600 nextIndex = nextNextIndex;
601 } else {
602 break; // not a Greek diacritic
603 }
604 }
605 if ((data & HAS_VOWEL_AND_ACCENT_AND_DIALYTIKA) == HAS_VOWEL_AND_ACCENT) {
606 nextState |= AFTER_VOWEL_WITH_ACCENT;
607 }
608 // Map according to Greek rules.
609 UBool addTonos = FALSE;
610 if (upper == 0x397 &&
611 (data & HAS_ACCENT) != 0 &&
612 numYpogegrammeni == 0 &&
613 (state & AFTER_CASED) == 0 &&
Jungshik Shin87232d82017-05-13 21:10:13 -0700614 !isFollowedByCasedLetter(src, nextIndex, srcLength)) {
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700615 // Keep disjunctive "or" with (only) a tonos.
616 // We use the same "word boundary" conditions as for the Final_Sigma test.
617 if (i == nextIndex) {
618 upper = 0x389; // Preserve the precomposed form.
619 } else {
620 addTonos = TRUE;
621 }
622 } else if ((data & HAS_DIALYTIKA) != 0) {
623 // Preserve a vowel with dialytika in precomposed form if it exists.
624 if (upper == 0x399) {
625 upper = 0x3AA;
626 data &= ~HAS_EITHER_DIALYTIKA;
627 } else if (upper == 0x3A5) {
628 upper = 0x3AB;
629 data &= ~HAS_EITHER_DIALYTIKA;
630 }
631 }
Jungshik Shin87232d82017-05-13 21:10:13 -0700632
633 UBool change = TRUE;
634 if (edits != NULL) {
635 // Find out first whether we are changing the text.
636 U_ASSERT(0x370 <= upper && upper <= 0x3ff); // 2-byte UTF-8, main Greek block
637 change = (i + 2) > nextIndex ||
638 src[i] != getTwoByteLead(upper) || src[i + 1] != getTwoByteTrail(upper) ||
639 numYpogegrammeni > 0;
640 int32_t i2 = i + 2;
641 if ((data & HAS_EITHER_DIALYTIKA) != 0) {
642 change |= (i2 + 2) > nextIndex ||
643 src[i2] != (uint8_t)u8"\u0308"[0] ||
644 src[i2 + 1] != (uint8_t)u8"\u0308"[1];
645 i2 += 2;
646 }
647 if (addTonos) {
648 change |= (i2 + 2) > nextIndex ||
649 src[i2] != (uint8_t)u8"\u0301"[0] ||
650 src[i2 + 1] != (uint8_t)u8"\u0301"[1];
651 i2 += 2;
652 }
653 int32_t oldLength = nextIndex - i;
654 int32_t newLength = (i2 - i) + numYpogegrammeni * 2; // 2 bytes per U+0399
655 change |= oldLength != newLength;
656 if (change) {
657 if (edits != NULL) {
658 edits->addReplace(oldLength, newLength);
659 }
660 } else {
661 if (edits != NULL) {
662 edits->addUnchanged(oldLength);
663 }
664 // Write unchanged text?
665 change = (options & UCASEMAP_OMIT_UNCHANGED_TEXT) == 0;
666 }
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700667 }
Jungshik Shin87232d82017-05-13 21:10:13 -0700668
669 if (change) {
670 destIndex=appendTwoBytes(dest, destIndex, destCapacity, upper);
671 if (destIndex >= 0 && (data & HAS_EITHER_DIALYTIKA) != 0) {
672 destIndex=appendTwoBytes(dest, destIndex, destCapacity, u8"\u0308"); // restore or add a dialytika
673 }
674 if (destIndex >= 0 && addTonos) {
675 destIndex=appendTwoBytes(dest, destIndex, destCapacity, u8"\u0301");
676 }
677 while (destIndex >= 0 && numYpogegrammeni > 0) {
678 destIndex=appendTwoBytes(dest, destIndex, destCapacity, u8"\u0399");
679 --numYpogegrammeni;
680 }
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700681 if(destIndex<0) {
Jungshik Shin87232d82017-05-13 21:10:13 -0700682 errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700683 return 0;
684 }
685 }
Jungshik Shin87232d82017-05-13 21:10:13 -0700686 } else if(c>=0) {
687 const UChar *s;
688 c=ucase_toFullUpper(c, NULL, NULL, &s, UCASE_LOC_GREEK);
689 destIndex = appendResult(dest, destIndex, destCapacity, c, s,
690 nextIndex - i, options, edits);
691 if (destIndex < 0) {
692 errorCode = U_INDEX_OUTOFBOUNDS_ERROR;
693 return 0;
694 }
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700695 } else {
696 // Malformed UTF-8.
Jungshik Shin87232d82017-05-13 21:10:13 -0700697 destIndex=appendUnchanged(dest, destIndex, destCapacity,
698 src+i, nextIndex-i, options, edits);
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700699 if(destIndex<0) {
Jungshik Shin87232d82017-05-13 21:10:13 -0700700 errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700701 return 0;
702 }
703 }
704 i = nextIndex;
705 state = nextState;
706 }
707
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700708 return destIndex;
709}
710
711} // namespace GreekUpper
712U_NAMESPACE_END
713
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000714static int32_t U_CALLCONV
Jungshik Shin87232d82017-05-13 21:10:13 -0700715ucasemap_internalUTF8ToLower(int32_t caseLocale, uint32_t options, UCASEMAP_BREAK_ITERATOR_UNUSED
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000716 uint8_t *dest, int32_t destCapacity,
717 const uint8_t *src, int32_t srcLength,
Jungshik Shin87232d82017-05-13 21:10:13 -0700718 icu::Edits *edits,
719 UErrorCode &errorCode) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000720 UCaseContext csc=UCASECONTEXT_INITIALIZER;
721 csc.p=(void *)src;
722 csc.limit=srcLength;
Jungshik Shin87232d82017-05-13 21:10:13 -0700723 int32_t destIndex = _caseMap(
724 caseLocale, options, ucase_toFullLower,
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000725 dest, destCapacity,
726 src, &csc, 0, srcLength,
Jungshik Shin87232d82017-05-13 21:10:13 -0700727 edits, errorCode);
728 return checkOverflowAndEditsError(destIndex, destCapacity, edits, errorCode);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000729}
730
731static int32_t U_CALLCONV
Jungshik Shin87232d82017-05-13 21:10:13 -0700732ucasemap_internalUTF8ToUpper(int32_t caseLocale, uint32_t options, UCASEMAP_BREAK_ITERATOR_UNUSED
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000733 uint8_t *dest, int32_t destCapacity,
734 const uint8_t *src, int32_t srcLength,
Jungshik Shin87232d82017-05-13 21:10:13 -0700735 icu::Edits *edits,
736 UErrorCode &errorCode) {
737 int32_t destIndex;
738 if (caseLocale == UCASE_LOC_GREEK) {
739 destIndex = GreekUpper::toUpper(options, dest, destCapacity,
740 src, srcLength, edits, errorCode);
741 } else {
742 UCaseContext csc=UCASECONTEXT_INITIALIZER;
743 csc.p=(void *)src;
744 csc.limit=srcLength;
745 destIndex = _caseMap(
746 caseLocale, options, ucase_toFullUpper,
747 dest, destCapacity,
748 src, &csc, 0, srcLength,
749 edits, errorCode);
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700750 }
Jungshik Shin87232d82017-05-13 21:10:13 -0700751 return checkOverflowAndEditsError(destIndex, destCapacity, edits, errorCode);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000752}
753
Jungshik Shin87232d82017-05-13 21:10:13 -0700754static int32_t U_CALLCONV
755ucasemap_internalUTF8Fold(int32_t /* caseLocale */, uint32_t options, UCASEMAP_BREAK_ITERATOR_UNUSED
756 uint8_t *dest, int32_t destCapacity,
757 const uint8_t *src, int32_t srcLength,
758 icu::Edits *edits,
759 UErrorCode &errorCode) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000760 /* case mapping loop */
Jungshik Shin87232d82017-05-13 21:10:13 -0700761 int32_t srcIndex = 0;
762 int32_t destIndex = 0;
763 while (srcIndex < srcLength) {
764 int32_t cpStart = srcIndex;
765 UChar32 c;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000766 U8_NEXT(src, srcIndex, srcLength, c);
767 if(c<0) {
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700768 // Malformed UTF-8.
Jungshik Shin87232d82017-05-13 21:10:13 -0700769 destIndex=appendUnchanged(dest, destIndex, destCapacity,
770 src+cpStart, srcIndex-cpStart, options, edits);
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700771 if(destIndex<0) {
Jungshik Shin87232d82017-05-13 21:10:13 -0700772 errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700773 return 0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000774 }
775 continue;
776 }
Jungshik Shin87232d82017-05-13 21:10:13 -0700777 const UChar *s;
778 c = ucase_toFullFolding(c, &s, options);
779 destIndex = appendResult(dest, destIndex, destCapacity, c, s,
780 srcIndex - cpStart, options, edits);
781 if (destIndex < 0) {
782 errorCode = U_INDEX_OUTOFBOUNDS_ERROR;
783 return 0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000784 }
785 }
786
Jungshik Shin87232d82017-05-13 21:10:13 -0700787 return checkOverflowAndEditsError(destIndex, destCapacity, edits, errorCode);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000788}
789
790U_CFUNC int32_t
Jungshik Shin87232d82017-05-13 21:10:13 -0700791ucasemap_mapUTF8(int32_t caseLocale, uint32_t options, UCASEMAP_BREAK_ITERATOR_PARAM
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000792 uint8_t *dest, int32_t destCapacity,
793 const uint8_t *src, int32_t srcLength,
794 UTF8CaseMapper *stringCaseMapper,
Jungshik Shin87232d82017-05-13 21:10:13 -0700795 icu::Edits *edits,
796 UErrorCode &errorCode) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000797 int32_t destLength;
798
799 /* check argument values */
Jungshik Shin87232d82017-05-13 21:10:13 -0700800 if(U_FAILURE(errorCode)) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000801 return 0;
802 }
803 if( destCapacity<0 ||
804 (dest==NULL && destCapacity>0) ||
805 src==NULL ||
806 srcLength<-1
807 ) {
Jungshik Shin87232d82017-05-13 21:10:13 -0700808 errorCode=U_ILLEGAL_ARGUMENT_ERROR;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000809 return 0;
810 }
811
812 /* get the string length */
813 if(srcLength==-1) {
814 srcLength=(int32_t)uprv_strlen((const char *)src);
815 }
816
817 /* check for overlapping source and destination */
818 if( dest!=NULL &&
819 ((src>=dest && src<(dest+destCapacity)) ||
820 (dest>=src && dest<(src+srcLength)))
821 ) {
Jungshik Shin87232d82017-05-13 21:10:13 -0700822 errorCode=U_ILLEGAL_ARGUMENT_ERROR;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000823 return 0;
824 }
825
Jungshik Shin87232d82017-05-13 21:10:13 -0700826 if(edits!=NULL) {
827 edits->reset();
828 }
829 destLength=stringCaseMapper(caseLocale, options, UCASEMAP_BREAK_ITERATOR
830 dest, destCapacity, src, srcLength, edits, errorCode);
831 return u_terminateChars((char *)dest, destCapacity, destLength, &errorCode);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000832}
833
834/* public API functions */
835
836U_CAPI int32_t U_EXPORT2
837ucasemap_utf8ToLower(const UCaseMap *csm,
838 char *dest, int32_t destCapacity,
839 const char *src, int32_t srcLength,
840 UErrorCode *pErrorCode) {
Jungshik Shin87232d82017-05-13 21:10:13 -0700841 return ucasemap_mapUTF8(
842 csm->caseLocale, csm->options, UCASEMAP_BREAK_ITERATOR_NULL
843 (uint8_t *)dest, destCapacity,
844 (const uint8_t *)src, srcLength,
845 ucasemap_internalUTF8ToLower, NULL, *pErrorCode);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000846}
847
848U_CAPI int32_t U_EXPORT2
849ucasemap_utf8ToUpper(const UCaseMap *csm,
850 char *dest, int32_t destCapacity,
851 const char *src, int32_t srcLength,
852 UErrorCode *pErrorCode) {
Jungshik Shin87232d82017-05-13 21:10:13 -0700853 return ucasemap_mapUTF8(
854 csm->caseLocale, csm->options, UCASEMAP_BREAK_ITERATOR_NULL
855 (uint8_t *)dest, destCapacity,
856 (const uint8_t *)src, srcLength,
857 ucasemap_internalUTF8ToUpper, NULL, *pErrorCode);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000858}
859
860U_CAPI int32_t U_EXPORT2
861ucasemap_utf8FoldCase(const UCaseMap *csm,
862 char *dest, int32_t destCapacity,
863 const char *src, int32_t srcLength,
864 UErrorCode *pErrorCode) {
Jungshik Shin87232d82017-05-13 21:10:13 -0700865 return ucasemap_mapUTF8(
866 UCASE_LOC_ROOT, csm->options, UCASEMAP_BREAK_ITERATOR_NULL
867 (uint8_t *)dest, destCapacity,
868 (const uint8_t *)src, srcLength,
869 ucasemap_internalUTF8Fold, NULL, *pErrorCode);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000870}
Jungshik Shin87232d82017-05-13 21:10:13 -0700871
872U_NAMESPACE_BEGIN
873
874int32_t CaseMap::utf8ToLower(
875 const char *locale, uint32_t options,
876 const char *src, int32_t srcLength,
877 char *dest, int32_t destCapacity, Edits *edits,
878 UErrorCode &errorCode) {
879 return ucasemap_mapUTF8(
880 ustrcase_getCaseLocale(locale), options, UCASEMAP_BREAK_ITERATOR_NULL
881 (uint8_t *)dest, destCapacity,
882 (const uint8_t *)src, srcLength,
883 ucasemap_internalUTF8ToLower, edits, errorCode);
884}
885
886int32_t CaseMap::utf8ToUpper(
887 const char *locale, uint32_t options,
888 const char *src, int32_t srcLength,
889 char *dest, int32_t destCapacity, Edits *edits,
890 UErrorCode &errorCode) {
891 return ucasemap_mapUTF8(
892 ustrcase_getCaseLocale(locale), options, UCASEMAP_BREAK_ITERATOR_NULL
893 (uint8_t *)dest, destCapacity,
894 (const uint8_t *)src, srcLength,
895 ucasemap_internalUTF8ToUpper, edits, errorCode);
896}
897
898int32_t CaseMap::utf8Fold(
899 uint32_t options,
900 const char *src, int32_t srcLength,
901 char *dest, int32_t destCapacity, Edits *edits,
902 UErrorCode &errorCode) {
903 return ucasemap_mapUTF8(
904 UCASE_LOC_ROOT, options, UCASEMAP_BREAK_ITERATOR_NULL
905 (uint8_t *)dest, destCapacity,
906 (const uint8_t *)src, srcLength,
907 ucasemap_internalUTF8Fold, edits, errorCode);
908}
909
910U_NAMESPACE_END