Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/intl/icu/source/common/normalizer2.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
*
6
*   Copyright (C) 2009-2016, International Business Machines
7
*   Corporation and others.  All Rights Reserved.
8
*
9
*******************************************************************************
10
*   file name:  normalizer2.cpp
11
*   encoding:   UTF-8
12
*   tab size:   8 (not used)
13
*   indentation:4
14
*
15
*   created on: 2009nov22
16
*   created by: Markus W. Scherer
17
*/
18
19
#include "unicode/utypes.h"
20
21
#if !UCONFIG_NO_NORMALIZATION
22
23
#include "unicode/edits.h"
24
#include "unicode/normalizer2.h"
25
#include "unicode/stringoptions.h"
26
#include "unicode/unistr.h"
27
#include "unicode/unorm.h"
28
#include "cstring.h"
29
#include "mutex.h"
30
#include "norm2allmodes.h"
31
#include "normalizer2impl.h"
32
#include "uassert.h"
33
#include "ucln_cmn.h"
34
35
using icu::Normalizer2Impl;
36
37
// NFC/NFD data machine-generated by gennorm2 --csource
38
#define INCLUDED_FROM_NORMALIZER2_CPP
39
#include "norm2_nfc_data.h"
40
41
U_NAMESPACE_BEGIN
42
43
// Public API dispatch via Normalizer2 subclasses -------------------------- ***
44
45
0
Normalizer2::~Normalizer2() {}
46
47
void
48
Normalizer2::normalizeUTF8(uint32_t /*options*/, StringPiece src, ByteSink &sink,
49
0
                           Edits *edits, UErrorCode &errorCode) const {
50
0
    if (U_FAILURE(errorCode)) {
51
0
        return;
52
0
    }
53
0
    if (edits != nullptr) {
54
0
        errorCode = U_UNSUPPORTED_ERROR;
55
0
        return;
56
0
    }
57
0
    UnicodeString src16 = UnicodeString::fromUTF8(src);
58
0
    normalize(src16, errorCode).toUTF8(sink);
59
0
}
60
61
UBool
62
0
Normalizer2::getRawDecomposition(UChar32, UnicodeString &) const {
63
0
    return FALSE;
64
0
}
65
66
UChar32
67
0
Normalizer2::composePair(UChar32, UChar32) const {
68
0
    return U_SENTINEL;
69
0
}
70
71
uint8_t
72
0
Normalizer2::getCombiningClass(UChar32 /*c*/) const {
73
0
    return 0;
74
0
}
75
76
UBool
77
0
Normalizer2::isNormalizedUTF8(StringPiece s, UErrorCode &errorCode) const {
78
0
    return U_SUCCESS(errorCode) && isNormalized(UnicodeString::fromUTF8(s), errorCode);
79
0
}
80
81
// Normalizer2 implementation for the old UNORM_NONE.
82
class NoopNormalizer2 : public Normalizer2 {
83
    virtual ~NoopNormalizer2();
84
85
    virtual UnicodeString &
86
    normalize(const UnicodeString &src,
87
              UnicodeString &dest,
88
0
              UErrorCode &errorCode) const U_OVERRIDE {
89
0
        if(U_SUCCESS(errorCode)) {
90
0
            if(&dest!=&src) {
91
0
                dest=src;
92
0
            } else {
93
0
                errorCode=U_ILLEGAL_ARGUMENT_ERROR;
94
0
            }
95
0
        }
96
0
        return dest;
97
0
    }
98
    virtual void
99
    normalizeUTF8(uint32_t options, StringPiece src, ByteSink &sink,
100
0
                  Edits *edits, UErrorCode &errorCode) const U_OVERRIDE {
101
0
        if(U_SUCCESS(errorCode)) {
102
0
            if (edits != nullptr) {
103
0
                if ((options & U_EDITS_NO_RESET) == 0) {
104
0
                    edits->reset();
105
0
                }
106
0
                edits->addUnchanged(src.length());
107
0
            }
108
0
            if ((options & U_OMIT_UNCHANGED_TEXT) == 0) {
109
0
                sink.Append(src.data(), src.length());
110
0
            }
111
0
            sink.Flush();
112
0
        }
113
0
    }
114
115
    virtual UnicodeString &
116
    normalizeSecondAndAppend(UnicodeString &first,
117
                             const UnicodeString &second,
118
0
                             UErrorCode &errorCode) const U_OVERRIDE {
119
0
        if(U_SUCCESS(errorCode)) {
120
0
            if(&first!=&second) {
121
0
                first.append(second);
122
0
            } else {
123
0
                errorCode=U_ILLEGAL_ARGUMENT_ERROR;
124
0
            }
125
0
        }
126
0
        return first;
127
0
    }
128
    virtual UnicodeString &
129
    append(UnicodeString &first,
130
           const UnicodeString &second,
131
0
           UErrorCode &errorCode) const U_OVERRIDE {
132
0
        if(U_SUCCESS(errorCode)) {
133
0
            if(&first!=&second) {
134
0
                first.append(second);
135
0
            } else {
136
0
                errorCode=U_ILLEGAL_ARGUMENT_ERROR;
137
0
            }
138
0
        }
139
0
        return first;
140
0
    }
141
    virtual UBool
142
0
    getDecomposition(UChar32, UnicodeString &) const U_OVERRIDE {
143
0
        return FALSE;
144
0
    }
145
    // No need to U_OVERRIDE the default getRawDecomposition().
146
    virtual UBool
147
0
    isNormalized(const UnicodeString &, UErrorCode &errorCode) const U_OVERRIDE {
148
0
        return U_SUCCESS(errorCode);
149
0
    }
150
    virtual UBool
151
0
    isNormalizedUTF8(StringPiece, UErrorCode &errorCode) const U_OVERRIDE {
152
0
        return U_SUCCESS(errorCode);
153
0
    }
154
    virtual UNormalizationCheckResult
155
0
    quickCheck(const UnicodeString &, UErrorCode &) const U_OVERRIDE {
156
0
        return UNORM_YES;
157
0
    }
158
    virtual int32_t
159
0
    spanQuickCheckYes(const UnicodeString &s, UErrorCode &) const U_OVERRIDE {
160
0
        return s.length();
161
0
    }
162
0
    virtual UBool hasBoundaryBefore(UChar32) const U_OVERRIDE { return TRUE; }
163
0
    virtual UBool hasBoundaryAfter(UChar32) const U_OVERRIDE { return TRUE; }
164
0
    virtual UBool isInert(UChar32) const U_OVERRIDE { return TRUE; }
165
};
166
167
NoopNormalizer2::~NoopNormalizer2() {}
168
169
Normalizer2WithImpl::~Normalizer2WithImpl() {}
170
171
DecomposeNormalizer2::~DecomposeNormalizer2() {}
172
173
ComposeNormalizer2::~ComposeNormalizer2() {}
174
175
FCDNormalizer2::~FCDNormalizer2() {}
176
177
// instance cache ---------------------------------------------------------- ***
178
179
0
Norm2AllModes::~Norm2AllModes() {
180
0
    delete impl;
181
0
}
182
183
Norm2AllModes *
184
3
Norm2AllModes::createInstance(Normalizer2Impl *impl, UErrorCode &errorCode) {
185
3
    if(U_FAILURE(errorCode)) {
186
0
        delete impl;
187
0
        return NULL;
188
0
    }
189
3
    Norm2AllModes *allModes=new Norm2AllModes(impl);
190
3
    if(allModes==NULL) {
191
0
        errorCode=U_MEMORY_ALLOCATION_ERROR;
192
0
        delete impl;
193
0
        return NULL;
194
0
    }
195
3
    return allModes;
196
3
}
197
198
Norm2AllModes *
199
0
Norm2AllModes::createNFCInstance(UErrorCode &errorCode) {
200
0
    if(U_FAILURE(errorCode)) {
201
0
        return NULL;
202
0
    }
203
0
    Normalizer2Impl *impl=new Normalizer2Impl;
204
0
    if(impl==NULL) {
205
0
        errorCode=U_MEMORY_ALLOCATION_ERROR;
206
0
        return NULL;
207
0
    }
208
0
    impl->init(norm2_nfc_data_indexes, &norm2_nfc_data_trie,
209
0
               norm2_nfc_data_extraData, norm2_nfc_data_smallFCD);
210
0
    return createInstance(impl, errorCode);
211
0
}
212
213
U_CDECL_BEGIN
214
static UBool U_CALLCONV uprv_normalizer2_cleanup();
215
U_CDECL_END
216
217
static Norm2AllModes *nfcSingleton;
218
static Normalizer2   *noopSingleton;
219
220
static icu::UInitOnce nfcInitOnce = U_INITONCE_INITIALIZER;
221
static icu::UInitOnce noopInitOnce = U_INITONCE_INITIALIZER;
222
223
// UInitOnce singleton initialization functions
224
0
static void U_CALLCONV initNFCSingleton(UErrorCode &errorCode) {
225
0
    nfcSingleton=Norm2AllModes::createNFCInstance(errorCode);
226
0
    ucln_common_registerCleanup(UCLN_COMMON_NORMALIZER2, uprv_normalizer2_cleanup);
227
0
}
228
229
0
static void U_CALLCONV initNoopSingleton(UErrorCode &errorCode) {
230
0
    if(U_FAILURE(errorCode)) {
231
0
        return;
232
0
    }
233
0
    noopSingleton=new NoopNormalizer2;
234
0
    if(noopSingleton==NULL) {
235
0
        errorCode=U_MEMORY_ALLOCATION_ERROR;
236
0
        return;
237
0
    }
238
0
    ucln_common_registerCleanup(UCLN_COMMON_NORMALIZER2, uprv_normalizer2_cleanup);
239
0
}
240
241
U_CDECL_BEGIN
242
243
0
static UBool U_CALLCONV uprv_normalizer2_cleanup() {
244
0
    delete nfcSingleton;
245
0
    nfcSingleton = NULL;
246
0
    delete noopSingleton;
247
0
    noopSingleton = NULL;
248
0
    nfcInitOnce.reset(); 
249
0
    noopInitOnce.reset(); 
250
0
    return TRUE;
251
0
}
252
253
U_CDECL_END
254
255
const Norm2AllModes *
256
0
Norm2AllModes::getNFCInstance(UErrorCode &errorCode) {
257
0
    if(U_FAILURE(errorCode)) { return NULL; }
258
0
    umtx_initOnce(nfcInitOnce, &initNFCSingleton, errorCode);
259
0
    return nfcSingleton;
260
0
}
261
262
const Normalizer2 *
263
0
Normalizer2::getNFCInstance(UErrorCode &errorCode) {
264
0
    const Norm2AllModes *allModes=Norm2AllModes::getNFCInstance(errorCode);
265
0
    return allModes!=NULL ? &allModes->comp : NULL;
266
0
}
267
268
const Normalizer2 *
269
0
Normalizer2::getNFDInstance(UErrorCode &errorCode) {
270
0
    const Norm2AllModes *allModes=Norm2AllModes::getNFCInstance(errorCode);
271
0
    return allModes!=NULL ? &allModes->decomp : NULL;
272
0
}
273
274
0
const Normalizer2 *Normalizer2Factory::getFCDInstance(UErrorCode &errorCode) {
275
0
    const Norm2AllModes *allModes=Norm2AllModes::getNFCInstance(errorCode);
276
0
    return allModes!=NULL ? &allModes->fcd : NULL;
277
0
}
278
279
0
const Normalizer2 *Normalizer2Factory::getFCCInstance(UErrorCode &errorCode) {
280
0
    const Norm2AllModes *allModes=Norm2AllModes::getNFCInstance(errorCode);
281
0
    return allModes!=NULL ? &allModes->fcc : NULL;
282
0
}
283
284
0
const Normalizer2 *Normalizer2Factory::getNoopInstance(UErrorCode &errorCode) {
285
0
    if(U_FAILURE(errorCode)) { return NULL; }
286
0
    umtx_initOnce(noopInitOnce, &initNoopSingleton, errorCode);
287
0
    return noopSingleton;
288
0
}
289
290
const Normalizer2Impl *
291
0
Normalizer2Factory::getNFCImpl(UErrorCode &errorCode) {
292
0
    const Norm2AllModes *allModes=Norm2AllModes::getNFCInstance(errorCode);
293
0
    return allModes!=NULL ? allModes->impl : NULL;
294
0
}
295
296
const Normalizer2Impl *
297
0
Normalizer2Factory::getImpl(const Normalizer2 *norm2) {
298
0
    return &((Normalizer2WithImpl *)norm2)->impl;
299
0
}
300
301
U_NAMESPACE_END
302
303
// C API ------------------------------------------------------------------- ***
304
305
U_NAMESPACE_USE
306
307
U_CAPI const UNormalizer2 * U_EXPORT2
308
0
unorm2_getNFCInstance(UErrorCode *pErrorCode) {
309
0
    return (const UNormalizer2 *)Normalizer2::getNFCInstance(*pErrorCode);
310
0
}
311
312
U_CAPI const UNormalizer2 * U_EXPORT2
313
0
unorm2_getNFDInstance(UErrorCode *pErrorCode) {
314
0
    return (const UNormalizer2 *)Normalizer2::getNFDInstance(*pErrorCode);
315
0
}
316
317
U_CAPI void U_EXPORT2
318
0
unorm2_close(UNormalizer2 *norm2) {
319
0
    delete (Normalizer2 *)norm2;
320
0
}
321
322
U_CAPI int32_t U_EXPORT2
323
unorm2_normalize(const UNormalizer2 *norm2,
324
                 const UChar *src, int32_t length,
325
                 UChar *dest, int32_t capacity,
326
0
                 UErrorCode *pErrorCode) {
327
0
    if(U_FAILURE(*pErrorCode)) {
328
0
        return 0;
329
0
    }
330
0
    if( (src==NULL ? length!=0 : length<-1) ||
331
0
        (dest==NULL ? capacity!=0 : capacity<0) ||
332
0
        (src==dest && src!=NULL)
333
0
    ) {
334
0
        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
335
0
        return 0;
336
0
    }
337
0
    UnicodeString destString(dest, 0, capacity);
338
0
    // length==0: Nothing to do, and n2wi->normalize(NULL, NULL, buffer, ...) would crash.
339
0
    if(length!=0) {
340
0
        const Normalizer2 *n2=(const Normalizer2 *)norm2;
341
0
        const Normalizer2WithImpl *n2wi=dynamic_cast<const Normalizer2WithImpl *>(n2);
342
0
        if(n2wi!=NULL) {
343
0
            // Avoid duplicate argument checking and support NUL-terminated src.
344
0
            ReorderingBuffer buffer(n2wi->impl, destString);
345
0
            if(buffer.init(length, *pErrorCode)) {
346
0
                n2wi->normalize(src, length>=0 ? src+length : NULL, buffer, *pErrorCode);
347
0
            }
348
0
        } else {
349
0
            UnicodeString srcString(length<0, src, length);
350
0
            n2->normalize(srcString, destString, *pErrorCode);
351
0
        }
352
0
    }
353
0
    return destString.extract(dest, capacity, *pErrorCode);
354
0
}
355
356
static int32_t
357
normalizeSecondAndAppend(const UNormalizer2 *norm2,
358
                         UChar *first, int32_t firstLength, int32_t firstCapacity,
359
                         const UChar *second, int32_t secondLength,
360
                         UBool doNormalize,
361
0
                         UErrorCode *pErrorCode) {
362
0
    if(U_FAILURE(*pErrorCode)) {
363
0
        return 0;
364
0
    }
365
0
    if( (second==NULL ? secondLength!=0 : secondLength<-1) ||
366
0
        (first==NULL ? (firstCapacity!=0 || firstLength!=0) :
367
0
                       (firstCapacity<0 || firstLength<-1)) ||
368
0
        (first==second && first!=NULL)
369
0
    ) {
370
0
        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
371
0
        return 0;
372
0
    }
373
0
    UnicodeString firstString(first, firstLength, firstCapacity);
374
0
    firstLength=firstString.length();  // In case it was -1.
375
0
    // secondLength==0: Nothing to do, and n2wi->normalizeAndAppend(NULL, NULL, buffer, ...) would crash.
376
0
    if(secondLength!=0) {
377
0
        const Normalizer2 *n2=(const Normalizer2 *)norm2;
378
0
        const Normalizer2WithImpl *n2wi=dynamic_cast<const Normalizer2WithImpl *>(n2);
379
0
        if(n2wi!=NULL) {
380
0
            // Avoid duplicate argument checking and support NUL-terminated src.
381
0
            UnicodeString safeMiddle;
382
0
            {
383
0
                ReorderingBuffer buffer(n2wi->impl, firstString);
384
0
                if(buffer.init(firstLength+secondLength+1, *pErrorCode)) {  // destCapacity>=-1
385
0
                    n2wi->normalizeAndAppend(second, secondLength>=0 ? second+secondLength : NULL,
386
0
                                             doNormalize, safeMiddle, buffer, *pErrorCode);
387
0
                }
388
0
            }  // The ReorderingBuffer destructor finalizes firstString.
389
0
            if(U_FAILURE(*pErrorCode) || firstString.length()>firstCapacity) {
390
0
                // Restore the modified suffix of the first string.
391
0
                // This does not restore first[] array contents between firstLength and firstCapacity.
392
0
                // (That might be uninitialized memory, as far as we know.)
393
0
                if(first!=NULL) { /* don't dereference NULL */
394
0
                  safeMiddle.extract(0, 0x7fffffff, first+firstLength-safeMiddle.length());
395
0
                  if(firstLength<firstCapacity) {
396
0
                    first[firstLength]=0;  // NUL-terminate in case it was originally.
397
0
                  }
398
0
                }
399
0
            }
400
0
        } else {
401
0
            UnicodeString secondString(secondLength<0, second, secondLength);
402
0
            if(doNormalize) {
403
0
                n2->normalizeSecondAndAppend(firstString, secondString, *pErrorCode);
404
0
            } else {
405
0
                n2->append(firstString, secondString, *pErrorCode);
406
0
            }
407
0
        }
408
0
    }
409
0
    return firstString.extract(first, firstCapacity, *pErrorCode);
410
0
}
411
412
U_CAPI int32_t U_EXPORT2
413
unorm2_normalizeSecondAndAppend(const UNormalizer2 *norm2,
414
                                UChar *first, int32_t firstLength, int32_t firstCapacity,
415
                                const UChar *second, int32_t secondLength,
416
0
                                UErrorCode *pErrorCode) {
417
0
    return normalizeSecondAndAppend(norm2,
418
0
                                    first, firstLength, firstCapacity,
419
0
                                    second, secondLength,
420
0
                                    TRUE, pErrorCode);
421
0
}
422
423
U_CAPI int32_t U_EXPORT2
424
unorm2_append(const UNormalizer2 *norm2,
425
              UChar *first, int32_t firstLength, int32_t firstCapacity,
426
              const UChar *second, int32_t secondLength,
427
0
              UErrorCode *pErrorCode) {
428
0
    return normalizeSecondAndAppend(norm2,
429
0
                                    first, firstLength, firstCapacity,
430
0
                                    second, secondLength,
431
0
                                    FALSE, pErrorCode);
432
0
}
433
434
U_CAPI int32_t U_EXPORT2
435
unorm2_getDecomposition(const UNormalizer2 *norm2,
436
                        UChar32 c, UChar *decomposition, int32_t capacity,
437
0
                        UErrorCode *pErrorCode) {
438
0
    if(U_FAILURE(*pErrorCode)) {
439
0
        return 0;
440
0
    }
441
0
    if(decomposition==NULL ? capacity!=0 : capacity<0) {
442
0
        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
443
0
        return 0;
444
0
    }
445
0
    UnicodeString destString(decomposition, 0, capacity);
446
0
    if(reinterpret_cast<const Normalizer2 *>(norm2)->getDecomposition(c, destString)) {
447
0
        return destString.extract(decomposition, capacity, *pErrorCode);
448
0
    } else {
449
0
        return -1;
450
0
    }
451
0
}
452
453
U_CAPI int32_t U_EXPORT2
454
unorm2_getRawDecomposition(const UNormalizer2 *norm2,
455
                           UChar32 c, UChar *decomposition, int32_t capacity,
456
0
                           UErrorCode *pErrorCode) {
457
0
    if(U_FAILURE(*pErrorCode)) {
458
0
        return 0;
459
0
    }
460
0
    if(decomposition==NULL ? capacity!=0 : capacity<0) {
461
0
        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
462
0
        return 0;
463
0
    }
464
0
    UnicodeString destString(decomposition, 0, capacity);
465
0
    if(reinterpret_cast<const Normalizer2 *>(norm2)->getRawDecomposition(c, destString)) {
466
0
        return destString.extract(decomposition, capacity, *pErrorCode);
467
0
    } else {
468
0
        return -1;
469
0
    }
470
0
}
471
472
U_CAPI UChar32 U_EXPORT2
473
0
unorm2_composePair(const UNormalizer2 *norm2, UChar32 a, UChar32 b) {
474
0
    return reinterpret_cast<const Normalizer2 *>(norm2)->composePair(a, b);
475
0
}
476
477
U_CAPI uint8_t U_EXPORT2
478
0
unorm2_getCombiningClass(const UNormalizer2 *norm2, UChar32 c) {
479
0
    return reinterpret_cast<const Normalizer2 *>(norm2)->getCombiningClass(c);
480
0
}
481
482
U_CAPI UBool U_EXPORT2
483
unorm2_isNormalized(const UNormalizer2 *norm2,
484
                    const UChar *s, int32_t length,
485
0
                    UErrorCode *pErrorCode) {
486
0
    if(U_FAILURE(*pErrorCode)) {
487
0
        return 0;
488
0
    }
489
0
    if((s==NULL && length!=0) || length<-1) {
490
0
        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
491
0
        return 0;
492
0
    }
493
0
    UnicodeString sString(length<0, s, length);
494
0
    return ((const Normalizer2 *)norm2)->isNormalized(sString, *pErrorCode);
495
0
}
496
497
U_CAPI UNormalizationCheckResult U_EXPORT2
498
unorm2_quickCheck(const UNormalizer2 *norm2,
499
                  const UChar *s, int32_t length,
500
0
                  UErrorCode *pErrorCode) {
501
0
    if(U_FAILURE(*pErrorCode)) {
502
0
        return UNORM_NO;
503
0
    }
504
0
    if((s==NULL && length!=0) || length<-1) {
505
0
        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
506
0
        return UNORM_NO;
507
0
    }
508
0
    UnicodeString sString(length<0, s, length);
509
0
    return ((const Normalizer2 *)norm2)->quickCheck(sString, *pErrorCode);
510
0
}
511
512
U_CAPI int32_t U_EXPORT2
513
unorm2_spanQuickCheckYes(const UNormalizer2 *norm2,
514
                         const UChar *s, int32_t length,
515
0
                         UErrorCode *pErrorCode) {
516
0
    if(U_FAILURE(*pErrorCode)) {
517
0
        return 0;
518
0
    }
519
0
    if((s==NULL && length!=0) || length<-1) {
520
0
        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
521
0
        return 0;
522
0
    }
523
0
    UnicodeString sString(length<0, s, length);
524
0
    return ((const Normalizer2 *)norm2)->spanQuickCheckYes(sString, *pErrorCode);
525
0
}
526
527
U_CAPI UBool U_EXPORT2
528
0
unorm2_hasBoundaryBefore(const UNormalizer2 *norm2, UChar32 c) {
529
0
    return ((const Normalizer2 *)norm2)->hasBoundaryBefore(c);
530
0
}
531
532
U_CAPI UBool U_EXPORT2
533
0
unorm2_hasBoundaryAfter(const UNormalizer2 *norm2, UChar32 c) {
534
0
    return ((const Normalizer2 *)norm2)->hasBoundaryAfter(c);
535
0
}
536
537
U_CAPI UBool U_EXPORT2
538
0
unorm2_isInert(const UNormalizer2 *norm2, UChar32 c) {
539
0
    return ((const Normalizer2 *)norm2)->isInert(c);
540
0
}
541
542
// Some properties APIs ---------------------------------------------------- ***
543
544
U_CAPI uint8_t U_EXPORT2
545
0
u_getCombiningClass(UChar32 c) {
546
0
    UErrorCode errorCode=U_ZERO_ERROR;
547
0
    const Normalizer2 *nfd=Normalizer2::getNFDInstance(errorCode);
548
0
    if(U_SUCCESS(errorCode)) {
549
0
        return nfd->getCombiningClass(c);
550
0
    } else {
551
0
        return 0;
552
0
    }
553
0
}
554
555
U_CFUNC uint16_t
556
0
unorm_getFCD16(UChar32 c) {
557
0
    UErrorCode errorCode=U_ZERO_ERROR;
558
0
    const Normalizer2Impl *impl=Normalizer2Factory::getNFCImpl(errorCode);
559
0
    if(U_SUCCESS(errorCode)) {
560
0
        return impl->getFCD16(c);
561
0
    } else {
562
0
        return 0;
563
0
    }
564
0
}
565
566
#endif  // !UCONFIG_NO_NORMALIZATION