Coverage Report

Created: 2021-08-22 09:07

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