/src/icu/source/common/uprops.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) 2002-2016, International Business Machines  | 
7  |  | *   Corporation and others.  All Rights Reserved.  | 
8  |  | *  | 
9  |  | *******************************************************************************  | 
10  |  | *   file name:  uprops.cpp  | 
11  |  | *   encoding:   UTF-8  | 
12  |  | *   tab size:   8 (not used)  | 
13  |  | *   indentation:4  | 
14  |  | *  | 
15  |  | *   created on: 2002feb24  | 
16  |  | *   created by: Markus W. Scherer  | 
17  |  | *  | 
18  |  | *   Implementations for mostly non-core Unicode character properties  | 
19  |  | *   stored in uprops.icu.  | 
20  |  | *  | 
21  |  | *   With the APIs implemented here, almost all properties files and  | 
22  |  | *   their associated implementation files are used from this file,  | 
23  |  | *   including those for normalization and case mappings.  | 
24  |  | */  | 
25  |  |  | 
26  |  | #include "unicode/utypes.h"  | 
27  |  | #include "unicode/uchar.h"  | 
28  |  | #include "unicode/ucptrie.h"  | 
29  |  | #include "unicode/udata.h"  | 
30  |  | #include "unicode/unorm2.h"  | 
31  |  | #include "unicode/uscript.h"  | 
32  |  | #include "unicode/ustring.h"  | 
33  |  | #include "cstring.h"  | 
34  |  | #include "mutex.h"  | 
35  |  | #include "normalizer2impl.h"  | 
36  |  | #include "umutex.h"  | 
37  |  | #include "ubidi_props.h"  | 
38  |  | #include "uprops.h"  | 
39  |  | #include "ucase.h"  | 
40  |  | #include "ucln_cmn.h"  | 
41  |  | #include "ulayout_props.h"  | 
42  |  | #include "ustr_imp.h"  | 
43  |  |  | 
44  |  | U_NAMESPACE_USE  | 
45  |  |  | 
46  |  | // Unicode text layout properties data -----------------------------------------  | 
47  |  |  | 
48  |  | namespace { | 
49  |  |  | 
50  |  | icu::UInitOnce gLayoutInitOnce = U_INITONCE_INITIALIZER;  | 
51  |  | UDataMemory *gLayoutMemory = nullptr;  | 
52  |  |  | 
53  |  | UCPTrie *gInpcTrie = nullptr;  // Indic_Positional_Category  | 
54  |  | UCPTrie *gInscTrie = nullptr;  // Indic_Syllabic_Category  | 
55  |  | UCPTrie *gVoTrie = nullptr;  // Vertical_Orientation  | 
56  |  |  | 
57  |  | int32_t gMaxInpcValue = 0;  | 
58  |  | int32_t gMaxInscValue = 0;  | 
59  |  | int32_t gMaxVoValue = 0;  | 
60  |  |  | 
61  | 0  | UBool U_CALLCONV uprops_cleanup() { | 
62  | 0  |     udata_close(gLayoutMemory);  | 
63  | 0  |     gLayoutMemory = nullptr;  | 
64  |  | 
  | 
65  | 0  |     ucptrie_close(gInpcTrie);  | 
66  | 0  |     gInpcTrie = nullptr;  | 
67  | 0  |     ucptrie_close(gInscTrie);  | 
68  | 0  |     gInscTrie = nullptr;  | 
69  | 0  |     ucptrie_close(gVoTrie);  | 
70  | 0  |     gVoTrie = nullptr;  | 
71  |  | 
  | 
72  | 0  |     gMaxInpcValue = 0;  | 
73  | 0  |     gMaxInscValue = 0;  | 
74  | 0  |     gMaxVoValue = 0;  | 
75  |  | 
  | 
76  | 0  |     gLayoutInitOnce.reset();  | 
77  | 0  |     return TRUE;  | 
78  | 0  | }  | 
79  |  |  | 
80  |  | UBool U_CALLCONV  | 
81  |  | ulayout_isAcceptable(void * /*context*/,  | 
82  |  |                      const char * /* type */, const char * /*name*/,  | 
83  | 0  |                      const UDataInfo *pInfo) { | 
84  | 0  |     return pInfo->size >= 20 &&  | 
85  | 0  |         pInfo->isBigEndian == U_IS_BIG_ENDIAN &&  | 
86  | 0  |         pInfo->charsetFamily == U_CHARSET_FAMILY &&  | 
87  | 0  |         pInfo->dataFormat[0] == ULAYOUT_FMT_0 &&  | 
88  | 0  |         pInfo->dataFormat[1] == ULAYOUT_FMT_1 &&  | 
89  | 0  |         pInfo->dataFormat[2] == ULAYOUT_FMT_2 &&  | 
90  | 0  |         pInfo->dataFormat[3] == ULAYOUT_FMT_3 &&  | 
91  | 0  |         pInfo->formatVersion[0] == 1;  | 
92  | 0  | }  | 
93  |  |  | 
94  |  | // UInitOnce singleton initialization function  | 
95  | 0  | void U_CALLCONV ulayout_load(UErrorCode &errorCode) { | 
96  | 0  |     gLayoutMemory = udata_openChoice(  | 
97  | 0  |         nullptr, ULAYOUT_DATA_TYPE, ULAYOUT_DATA_NAME,  | 
98  | 0  |         ulayout_isAcceptable, nullptr, &errorCode);  | 
99  | 0  |     if (U_FAILURE(errorCode)) { return; } | 
100  |  |  | 
101  | 0  |     const uint8_t *inBytes = (const uint8_t *)udata_getMemory(gLayoutMemory);  | 
102  | 0  |     const int32_t *inIndexes = (const int32_t *)inBytes;  | 
103  | 0  |     int32_t indexesLength = inIndexes[ULAYOUT_IX_INDEXES_LENGTH];  | 
104  | 0  |     if (indexesLength < 12) { | 
105  | 0  |         errorCode = U_INVALID_FORMAT_ERROR;  // Not enough indexes.  | 
106  | 0  |         return;  | 
107  | 0  |     }  | 
108  | 0  |     int32_t offset = indexesLength * 4;  | 
109  | 0  |     int32_t top = inIndexes[ULAYOUT_IX_INPC_TRIE_TOP];  | 
110  | 0  |     int32_t trieSize = top - offset;  | 
111  | 0  |     if (trieSize >= 16) { | 
112  | 0  |         gInpcTrie = ucptrie_openFromBinary(  | 
113  | 0  |             UCPTRIE_TYPE_ANY, UCPTRIE_VALUE_BITS_ANY,  | 
114  | 0  |             inBytes + offset, trieSize, nullptr, &errorCode);  | 
115  | 0  |     }  | 
116  | 0  |     offset = top;  | 
117  | 0  |     top = inIndexes[ULAYOUT_IX_INSC_TRIE_TOP];  | 
118  | 0  |     trieSize = top - offset;  | 
119  | 0  |     if (trieSize >= 16) { | 
120  | 0  |         gInscTrie = ucptrie_openFromBinary(  | 
121  | 0  |             UCPTRIE_TYPE_ANY, UCPTRIE_VALUE_BITS_ANY,  | 
122  | 0  |             inBytes + offset, trieSize, nullptr, &errorCode);  | 
123  | 0  |     }  | 
124  | 0  |     offset = top;  | 
125  | 0  |     top = inIndexes[ULAYOUT_IX_VO_TRIE_TOP];  | 
126  | 0  |     trieSize = top - offset;  | 
127  | 0  |     if (trieSize >= 16) { | 
128  | 0  |         gVoTrie = ucptrie_openFromBinary(  | 
129  | 0  |             UCPTRIE_TYPE_ANY, UCPTRIE_VALUE_BITS_ANY,  | 
130  | 0  |             inBytes + offset, trieSize, nullptr, &errorCode);  | 
131  | 0  |     }  | 
132  |  | 
  | 
133  | 0  |     uint32_t maxValues = inIndexes[ULAYOUT_IX_MAX_VALUES];  | 
134  | 0  |     gMaxInpcValue = maxValues >> ULAYOUT_MAX_INPC_SHIFT;  | 
135  | 0  |     gMaxInscValue = (maxValues >> ULAYOUT_MAX_INSC_SHIFT) & 0xff;  | 
136  | 0  |     gMaxVoValue = (maxValues >> ULAYOUT_MAX_VO_SHIFT) & 0xff;  | 
137  |  | 
  | 
138  | 0  |     ucln_common_registerCleanup(UCLN_COMMON_UPROPS, uprops_cleanup);  | 
139  | 0  | }  | 
140  |  |  | 
141  | 0  | UBool ulayout_ensureData(UErrorCode &errorCode) { | 
142  | 0  |     if (U_FAILURE(errorCode)) { return FALSE; } | 
143  | 0  |     umtx_initOnce(gLayoutInitOnce, &ulayout_load, errorCode);  | 
144  | 0  |     return U_SUCCESS(errorCode);  | 
145  | 0  | }  | 
146  |  |  | 
147  | 0  | UBool ulayout_ensureData() { | 
148  | 0  |     UErrorCode errorCode = U_ZERO_ERROR;  | 
149  | 0  |     return ulayout_ensureData(errorCode);  | 
150  | 0  | }  | 
151  |  |  | 
152  |  | }  // namespace  | 
153  |  |  | 
154  |  | /* general properties API functions ----------------------------------------- */  | 
155  |  |  | 
156  |  | struct BinaryProperty;  | 
157  |  |  | 
158  |  | typedef UBool BinaryPropertyContains(const BinaryProperty &prop, UChar32 c, UProperty which);  | 
159  |  |  | 
160  |  | struct BinaryProperty { | 
161  |  |     int32_t column;  // SRC_PROPSVEC column, or "source" if mask==0  | 
162  |  |     uint32_t mask;  | 
163  |  |     BinaryPropertyContains *contains;  | 
164  |  | };  | 
165  |  |  | 
166  | 0  | static UBool defaultContains(const BinaryProperty &prop, UChar32 c, UProperty /*which*/) { | 
167  |  |     /* systematic, directly stored properties */  | 
168  | 0  |     return (u_getUnicodeProperties(c, prop.column)&prop.mask)!=0;  | 
169  | 0  | }  | 
170  |  |  | 
171  | 0  | static UBool caseBinaryPropertyContains(const BinaryProperty &/*prop*/, UChar32 c, UProperty which) { | 
172  | 0  |     return static_cast<UBool>(ucase_hasBinaryProperty(c, which));  | 
173  | 0  | }  | 
174  |  |  | 
175  | 0  | static UBool isBidiControl(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) { | 
176  | 0  |     return ubidi_isBidiControl(c);  | 
177  | 0  | }  | 
178  |  |  | 
179  | 0  | static UBool isMirrored(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) { | 
180  | 0  |     return ubidi_isMirrored(c);  | 
181  | 0  | }  | 
182  |  |  | 
183  | 0  | static UBool isJoinControl(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) { | 
184  | 0  |     return ubidi_isJoinControl(c);  | 
185  | 0  | }  | 
186  |  |  | 
187  |  | #if UCONFIG_NO_NORMALIZATION  | 
188  |  | static UBool hasFullCompositionExclusion(const BinaryProperty &, UChar32, UProperty) { | 
189  |  |     return FALSE;  | 
190  |  | }  | 
191  |  | #else  | 
192  | 0  | static UBool hasFullCompositionExclusion(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) { | 
193  |  |     // By definition, Full_Composition_Exclusion is the same as NFC_QC=No.  | 
194  | 0  |     UErrorCode errorCode=U_ZERO_ERROR;  | 
195  | 0  |     const Normalizer2Impl *impl=Normalizer2Factory::getNFCImpl(errorCode);  | 
196  | 0  |     return U_SUCCESS(errorCode) && impl->isCompNo(impl->getNorm16(c));  | 
197  | 0  | }  | 
198  |  | #endif  | 
199  |  |  | 
200  |  | // UCHAR_NF*_INERT properties  | 
201  |  | #if UCONFIG_NO_NORMALIZATION  | 
202  |  | static UBool isNormInert(const BinaryProperty &, UChar32, UProperty) { | 
203  |  |     return FALSE;  | 
204  |  | }  | 
205  |  | #else  | 
206  | 0  | static UBool isNormInert(const BinaryProperty &/*prop*/, UChar32 c, UProperty which) { | 
207  | 0  |     UErrorCode errorCode=U_ZERO_ERROR;  | 
208  | 0  |     const Normalizer2 *norm2=Normalizer2Factory::getInstance(  | 
209  | 0  |         (UNormalizationMode)(which-UCHAR_NFD_INERT+UNORM_NFD), errorCode);  | 
210  | 0  |     return U_SUCCESS(errorCode) && norm2->isInert(c);  | 
211  | 0  | }  | 
212  |  | #endif  | 
213  |  |  | 
214  |  | #if UCONFIG_NO_NORMALIZATION  | 
215  |  | static UBool changesWhenCasefolded(const BinaryProperty &, UChar32, UProperty) { | 
216  |  |     return FALSE;  | 
217  |  | }  | 
218  |  | #else  | 
219  | 0  | static UBool changesWhenCasefolded(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) { | 
220  | 0  |     UnicodeString nfd;  | 
221  | 0  |     UErrorCode errorCode=U_ZERO_ERROR;  | 
222  | 0  |     const Normalizer2 *nfcNorm2=Normalizer2::getNFCInstance(errorCode);  | 
223  | 0  |     if(U_FAILURE(errorCode)) { | 
224  | 0  |         return FALSE;  | 
225  | 0  |     }  | 
226  | 0  |     if(nfcNorm2->getDecomposition(c, nfd)) { | 
227  |  |         /* c has a decomposition */  | 
228  | 0  |         if(nfd.length()==1) { | 
229  | 0  |             c=nfd[0];  /* single BMP code point */  | 
230  | 0  |         } else if(nfd.length()<=U16_MAX_LENGTH &&  | 
231  | 0  |                   nfd.length()==U16_LENGTH(c=nfd.char32At(0))  | 
232  | 0  |         ) { | 
233  |  |             /* single supplementary code point */  | 
234  | 0  |         } else { | 
235  | 0  |             c=U_SENTINEL;  | 
236  | 0  |         }  | 
237  | 0  |     } else if(c<0) { | 
238  | 0  |         return FALSE;  /* protect against bad input */  | 
239  | 0  |     }  | 
240  | 0  |     if(c>=0) { | 
241  |  |         /* single code point */  | 
242  | 0  |         const UChar *resultString;  | 
243  | 0  |         return (UBool)(ucase_toFullFolding(c, &resultString, U_FOLD_CASE_DEFAULT)>=0);  | 
244  | 0  |     } else { | 
245  |  |         /* guess some large but stack-friendly capacity */  | 
246  | 0  |         UChar dest[2*UCASE_MAX_STRING_LENGTH];  | 
247  | 0  |         int32_t destLength;  | 
248  | 0  |         destLength=u_strFoldCase(dest, UPRV_LENGTHOF(dest),  | 
249  | 0  |                                   nfd.getBuffer(), nfd.length(),  | 
250  | 0  |                                   U_FOLD_CASE_DEFAULT, &errorCode);  | 
251  | 0  |         return (UBool)(U_SUCCESS(errorCode) &&  | 
252  | 0  |                        0!=u_strCompare(nfd.getBuffer(), nfd.length(),  | 
253  | 0  |                                        dest, destLength, FALSE));  | 
254  | 0  |     }  | 
255  | 0  | }  | 
256  |  | #endif  | 
257  |  |  | 
258  |  | #if UCONFIG_NO_NORMALIZATION  | 
259  |  | static UBool changesWhenNFKC_Casefolded(const BinaryProperty &, UChar32, UProperty) { | 
260  |  |     return FALSE;  | 
261  |  | }  | 
262  |  | #else  | 
263  | 0  | static UBool changesWhenNFKC_Casefolded(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) { | 
264  | 0  |     UErrorCode errorCode=U_ZERO_ERROR;  | 
265  | 0  |     const Normalizer2Impl *kcf=Normalizer2Factory::getNFKC_CFImpl(errorCode);  | 
266  | 0  |     if(U_FAILURE(errorCode)) { | 
267  | 0  |         return FALSE;  | 
268  | 0  |     }  | 
269  | 0  |     UnicodeString src(c);  | 
270  | 0  |     UnicodeString dest;  | 
271  | 0  |     { | 
272  |  |         // The ReorderingBuffer must be in a block because its destructor  | 
273  |  |         // needs to release dest's buffer before we look at its contents.  | 
274  | 0  |         ReorderingBuffer buffer(*kcf, dest);  | 
275  |  |         // Small destCapacity for NFKC_CF(c).  | 
276  | 0  |         if(buffer.init(5, errorCode)) { | 
277  | 0  |             const UChar *srcArray=src.getBuffer();  | 
278  | 0  |             kcf->compose(srcArray, srcArray+src.length(), FALSE,  | 
279  | 0  |                           TRUE, buffer, errorCode);  | 
280  | 0  |         }  | 
281  | 0  |     }  | 
282  | 0  |     return U_SUCCESS(errorCode) && dest!=src;  | 
283  | 0  | }  | 
284  |  | #endif  | 
285  |  |  | 
286  |  | #if UCONFIG_NO_NORMALIZATION  | 
287  |  | static UBool isCanonSegmentStarter(const BinaryProperty &, UChar32, UProperty) { | 
288  |  |     return FALSE;  | 
289  |  | }  | 
290  |  | #else  | 
291  | 0  | static UBool isCanonSegmentStarter(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) { | 
292  | 0  |     UErrorCode errorCode=U_ZERO_ERROR;  | 
293  | 0  |     const Normalizer2Impl *impl=Normalizer2Factory::getNFCImpl(errorCode);  | 
294  | 0  |     return  | 
295  | 0  |         U_SUCCESS(errorCode) && impl->ensureCanonIterData(errorCode) &&  | 
296  | 0  |         impl->isCanonSegmentStarter(c);  | 
297  | 0  | }  | 
298  |  | #endif  | 
299  |  |  | 
300  | 0  | static UBool isPOSIX_alnum(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) { | 
301  | 0  |     return u_isalnumPOSIX(c);  | 
302  | 0  | }  | 
303  |  |  | 
304  | 0  | static UBool isPOSIX_blank(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) { | 
305  | 0  |     return u_isblank(c);  | 
306  | 0  | }  | 
307  |  |  | 
308  | 0  | static UBool isPOSIX_graph(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) { | 
309  | 0  |     return u_isgraphPOSIX(c);  | 
310  | 0  | }  | 
311  |  |  | 
312  | 0  | static UBool isPOSIX_print(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) { | 
313  | 0  |     return u_isprintPOSIX(c);  | 
314  | 0  | }  | 
315  |  |  | 
316  | 0  | static UBool isPOSIX_xdigit(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) { | 
317  | 0  |     return u_isxdigit(c);  | 
318  | 0  | }  | 
319  |  |  | 
320  | 0  | static UBool isRegionalIndicator(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) { | 
321  |  |     // Property starts are a subset of lb=RI etc.  | 
322  | 0  |     return 0x1F1E6<=c && c<=0x1F1FF;  | 
323  | 0  | }  | 
324  |  |  | 
325  |  | static const BinaryProperty binProps[UCHAR_BINARY_LIMIT]={ | 
326  |  |     /*  | 
327  |  |      * column and mask values for binary properties from u_getUnicodeProperties().  | 
328  |  |      * Must be in order of corresponding UProperty,  | 
329  |  |      * and there must be exactly one entry per binary UProperty.  | 
330  |  |      *  | 
331  |  |      * Properties with mask==0 are handled in code.  | 
332  |  |      * For them, column is the UPropertySource value.  | 
333  |  |      */  | 
334  |  |     { 1,                U_MASK(UPROPS_ALPHABETIC), defaultContains }, | 
335  |  |     { 1,                U_MASK(UPROPS_ASCII_HEX_DIGIT), defaultContains }, | 
336  |  |     { UPROPS_SRC_BIDI,  0, isBidiControl }, | 
337  |  |     { UPROPS_SRC_BIDI,  0, isMirrored }, | 
338  |  |     { 1,                U_MASK(UPROPS_DASH), defaultContains }, | 
339  |  |     { 1,                U_MASK(UPROPS_DEFAULT_IGNORABLE_CODE_POINT), defaultContains }, | 
340  |  |     { 1,                U_MASK(UPROPS_DEPRECATED), defaultContains }, | 
341  |  |     { 1,                U_MASK(UPROPS_DIACRITIC), defaultContains }, | 
342  |  |     { 1,                U_MASK(UPROPS_EXTENDER), defaultContains }, | 
343  |  |     { UPROPS_SRC_NFC,   0, hasFullCompositionExclusion }, | 
344  |  |     { 1,                U_MASK(UPROPS_GRAPHEME_BASE), defaultContains }, | 
345  |  |     { 1,                U_MASK(UPROPS_GRAPHEME_EXTEND), defaultContains }, | 
346  |  |     { 1,                U_MASK(UPROPS_GRAPHEME_LINK), defaultContains }, | 
347  |  |     { 1,                U_MASK(UPROPS_HEX_DIGIT), defaultContains }, | 
348  |  |     { 1,                U_MASK(UPROPS_HYPHEN), defaultContains }, | 
349  |  |     { 1,                U_MASK(UPROPS_ID_CONTINUE), defaultContains }, | 
350  |  |     { 1,                U_MASK(UPROPS_ID_START), defaultContains }, | 
351  |  |     { 1,                U_MASK(UPROPS_IDEOGRAPHIC), defaultContains }, | 
352  |  |     { 1,                U_MASK(UPROPS_IDS_BINARY_OPERATOR), defaultContains }, | 
353  |  |     { 1,                U_MASK(UPROPS_IDS_TRINARY_OPERATOR), defaultContains }, | 
354  |  |     { UPROPS_SRC_BIDI,  0, isJoinControl }, | 
355  |  |     { 1,                U_MASK(UPROPS_LOGICAL_ORDER_EXCEPTION), defaultContains }, | 
356  |  |     { UPROPS_SRC_CASE,  0, caseBinaryPropertyContains },  // UCHAR_LOWERCASE | 
357  |  |     { 1,                U_MASK(UPROPS_MATH), defaultContains }, | 
358  |  |     { 1,                U_MASK(UPROPS_NONCHARACTER_CODE_POINT), defaultContains }, | 
359  |  |     { 1,                U_MASK(UPROPS_QUOTATION_MARK), defaultContains }, | 
360  |  |     { 1,                U_MASK(UPROPS_RADICAL), defaultContains }, | 
361  |  |     { UPROPS_SRC_CASE,  0, caseBinaryPropertyContains },  // UCHAR_SOFT_DOTTED | 
362  |  |     { 1,                U_MASK(UPROPS_TERMINAL_PUNCTUATION), defaultContains }, | 
363  |  |     { 1,                U_MASK(UPROPS_UNIFIED_IDEOGRAPH), defaultContains }, | 
364  |  |     { UPROPS_SRC_CASE,  0, caseBinaryPropertyContains },  // UCHAR_UPPERCASE | 
365  |  |     { 1,                U_MASK(UPROPS_WHITE_SPACE), defaultContains }, | 
366  |  |     { 1,                U_MASK(UPROPS_XID_CONTINUE), defaultContains }, | 
367  |  |     { 1,                U_MASK(UPROPS_XID_START), defaultContains }, | 
368  |  |     { UPROPS_SRC_CASE,  0, caseBinaryPropertyContains },  // UCHAR_CASE_SENSITIVE | 
369  |  |     { 1,                U_MASK(UPROPS_S_TERM), defaultContains }, | 
370  |  |     { 1,                U_MASK(UPROPS_VARIATION_SELECTOR), defaultContains }, | 
371  |  |     { UPROPS_SRC_NFC,   0, isNormInert },  // UCHAR_NFD_INERT | 
372  |  |     { UPROPS_SRC_NFKC,  0, isNormInert },  // UCHAR_NFKD_INERT | 
373  |  |     { UPROPS_SRC_NFC,   0, isNormInert },  // UCHAR_NFC_INERT | 
374  |  |     { UPROPS_SRC_NFKC,  0, isNormInert },  // UCHAR_NFKC_INERT | 
375  |  |     { UPROPS_SRC_NFC_CANON_ITER, 0, isCanonSegmentStarter }, | 
376  |  |     { 1,                U_MASK(UPROPS_PATTERN_SYNTAX), defaultContains }, | 
377  |  |     { 1,                U_MASK(UPROPS_PATTERN_WHITE_SPACE), defaultContains }, | 
378  |  |     { UPROPS_SRC_CHAR_AND_PROPSVEC,  0, isPOSIX_alnum }, | 
379  |  |     { UPROPS_SRC_CHAR,  0, isPOSIX_blank }, | 
380  |  |     { UPROPS_SRC_CHAR,  0, isPOSIX_graph }, | 
381  |  |     { UPROPS_SRC_CHAR,  0, isPOSIX_print }, | 
382  |  |     { UPROPS_SRC_CHAR,  0, isPOSIX_xdigit }, | 
383  |  |     { UPROPS_SRC_CASE,  0, caseBinaryPropertyContains },  // UCHAR_CASED | 
384  |  |     { UPROPS_SRC_CASE,  0, caseBinaryPropertyContains },  // UCHAR_CASE_IGNORABLE | 
385  |  |     { UPROPS_SRC_CASE,  0, caseBinaryPropertyContains },  // UCHAR_CHANGES_WHEN_LOWERCASED | 
386  |  |     { UPROPS_SRC_CASE,  0, caseBinaryPropertyContains },  // UCHAR_CHANGES_WHEN_UPPERCASED | 
387  |  |     { UPROPS_SRC_CASE,  0, caseBinaryPropertyContains },  // UCHAR_CHANGES_WHEN_TITLECASED | 
388  |  |     { UPROPS_SRC_CASE_AND_NORM,  0, changesWhenCasefolded }, | 
389  |  |     { UPROPS_SRC_CASE,  0, caseBinaryPropertyContains },  // UCHAR_CHANGES_WHEN_CASEMAPPED | 
390  |  |     { UPROPS_SRC_NFKC_CF, 0, changesWhenNFKC_Casefolded }, | 
391  |  |     { 2,                U_MASK(UPROPS_2_EMOJI), defaultContains }, | 
392  |  |     { 2,                U_MASK(UPROPS_2_EMOJI_PRESENTATION), defaultContains }, | 
393  |  |     { 2,                U_MASK(UPROPS_2_EMOJI_MODIFIER), defaultContains }, | 
394  |  |     { 2,                U_MASK(UPROPS_2_EMOJI_MODIFIER_BASE), defaultContains }, | 
395  |  |     { 2,                U_MASK(UPROPS_2_EMOJI_COMPONENT), defaultContains }, | 
396  |  |     { 2,                0, isRegionalIndicator }, | 
397  |  |     { 1,                U_MASK(UPROPS_PREPENDED_CONCATENATION_MARK), defaultContains }, | 
398  |  |     { 2,                U_MASK(UPROPS_2_EXTENDED_PICTOGRAPHIC), defaultContains }, | 
399  |  | };  | 
400  |  |  | 
401  |  | U_CAPI UBool U_EXPORT2  | 
402  | 0  | u_hasBinaryProperty(UChar32 c, UProperty which) { | 
403  |  |     /* c is range-checked in the functions that are called from here */  | 
404  | 0  |     if(which<UCHAR_BINARY_START || UCHAR_BINARY_LIMIT<=which) { | 
405  |  |         /* not a known binary property */  | 
406  | 0  |         return FALSE;  | 
407  | 0  |     } else { | 
408  | 0  |         const BinaryProperty &prop=binProps[which];  | 
409  | 0  |         return prop.contains(prop, c, which);  | 
410  | 0  |     }  | 
411  | 0  | }  | 
412  |  |  | 
413  |  | struct IntProperty;  | 
414  |  |  | 
415  |  | typedef int32_t IntPropertyGetValue(const IntProperty &prop, UChar32 c, UProperty which);  | 
416  |  | typedef int32_t IntPropertyGetMaxValue(const IntProperty &prop, UProperty which);  | 
417  |  |  | 
418  |  | struct IntProperty { | 
419  |  |     int32_t column;  // SRC_PROPSVEC column, or "source" if mask==0  | 
420  |  |     uint32_t mask;  | 
421  |  |     int32_t shift;  // =maxValue if getMaxValueFromShift() is used  | 
422  |  |     IntPropertyGetValue *getValue;  | 
423  |  |     IntPropertyGetMaxValue *getMaxValue;  | 
424  |  | };  | 
425  |  |  | 
426  | 0  | static int32_t defaultGetValue(const IntProperty &prop, UChar32 c, UProperty /*which*/) { | 
427  |  |     /* systematic, directly stored properties */  | 
428  | 0  |     return (int32_t)(u_getUnicodeProperties(c, prop.column)&prop.mask)>>prop.shift;  | 
429  | 0  | }  | 
430  |  |  | 
431  | 0  | static int32_t defaultGetMaxValue(const IntProperty &prop, UProperty /*which*/) { | 
432  | 0  |     return (uprv_getMaxValues(prop.column)&prop.mask)>>prop.shift;  | 
433  | 0  | }  | 
434  |  |  | 
435  | 0  | static int32_t getMaxValueFromShift(const IntProperty &prop, UProperty /*which*/) { | 
436  | 0  |     return prop.shift;  | 
437  | 0  | }  | 
438  |  |  | 
439  | 0  | static int32_t getBiDiClass(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) { | 
440  | 0  |     return (int32_t)u_charDirection(c);  | 
441  | 0  | }  | 
442  |  |  | 
443  | 0  | static int32_t getBiDiPairedBracketType(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) { | 
444  | 0  |     return (int32_t)ubidi_getPairedBracketType(c);  | 
445  | 0  | }  | 
446  |  |  | 
447  | 0  | static int32_t biDiGetMaxValue(const IntProperty &/*prop*/, UProperty which) { | 
448  | 0  |     return ubidi_getMaxValue(which);  | 
449  | 0  | }  | 
450  |  |  | 
451  |  | #if UCONFIG_NO_NORMALIZATION  | 
452  |  | static int32_t getCombiningClass(const IntProperty &, UChar32, UProperty) { | 
453  |  |     return 0;  | 
454  |  | }  | 
455  |  | #else  | 
456  | 0  | static int32_t getCombiningClass(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) { | 
457  | 0  |     return u_getCombiningClass(c);  | 
458  | 0  | }  | 
459  |  | #endif  | 
460  |  |  | 
461  | 0  | static int32_t getGeneralCategory(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) { | 
462  | 0  |     return (int32_t)u_charType(c);  | 
463  | 0  | }  | 
464  |  |  | 
465  | 0  | static int32_t getJoiningGroup(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) { | 
466  | 0  |     return ubidi_getJoiningGroup(c);  | 
467  | 0  | }  | 
468  |  |  | 
469  | 0  | static int32_t getJoiningType(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) { | 
470  | 0  |     return ubidi_getJoiningType(c);  | 
471  | 0  | }  | 
472  |  |  | 
473  | 0  | static int32_t getNumericType(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) { | 
474  | 0  |     int32_t ntv=(int32_t)GET_NUMERIC_TYPE_VALUE(u_getMainProperties(c));  | 
475  | 0  |     return UPROPS_NTV_GET_TYPE(ntv);  | 
476  | 0  | }  | 
477  |  |  | 
478  | 0  | static int32_t getScript(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) { | 
479  | 0  |     UErrorCode errorCode=U_ZERO_ERROR;  | 
480  | 0  |     return (int32_t)uscript_getScript(c, &errorCode);  | 
481  | 0  | }  | 
482  |  |  | 
483  | 0  | static int32_t scriptGetMaxValue(const IntProperty &/*prop*/, UProperty /*which*/) { | 
484  | 0  |     uint32_t scriptX=uprv_getMaxValues(0)&UPROPS_SCRIPT_X_MASK;  | 
485  | 0  |     return uprops_mergeScriptCodeOrIndex(scriptX);  | 
486  | 0  | }  | 
487  |  |  | 
488  |  | /*  | 
489  |  |  * Map some of the Grapheme Cluster Break values to Hangul Syllable Types.  | 
490  |  |  * Hangul_Syllable_Type is fully redundant with a subset of Grapheme_Cluster_Break.  | 
491  |  |  */  | 
492  |  | static const UHangulSyllableType gcbToHst[]={ | 
493  |  |     U_HST_NOT_APPLICABLE,   /* U_GCB_OTHER */  | 
494  |  |     U_HST_NOT_APPLICABLE,   /* U_GCB_CONTROL */  | 
495  |  |     U_HST_NOT_APPLICABLE,   /* U_GCB_CR */  | 
496  |  |     U_HST_NOT_APPLICABLE,   /* U_GCB_EXTEND */  | 
497  |  |     U_HST_LEADING_JAMO,     /* U_GCB_L */  | 
498  |  |     U_HST_NOT_APPLICABLE,   /* U_GCB_LF */  | 
499  |  |     U_HST_LV_SYLLABLE,      /* U_GCB_LV */  | 
500  |  |     U_HST_LVT_SYLLABLE,     /* U_GCB_LVT */  | 
501  |  |     U_HST_TRAILING_JAMO,    /* U_GCB_T */  | 
502  |  |     U_HST_VOWEL_JAMO        /* U_GCB_V */  | 
503  |  |     /*  | 
504  |  |      * Omit GCB values beyond what we need for hst.  | 
505  |  |      * The code below checks for the array length.  | 
506  |  |      */  | 
507  |  | };  | 
508  |  |  | 
509  | 0  | static int32_t getHangulSyllableType(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) { | 
510  |  |     /* see comments on gcbToHst[] above */  | 
511  | 0  |     int32_t gcb=(int32_t)(u_getUnicodeProperties(c, 2)&UPROPS_GCB_MASK)>>UPROPS_GCB_SHIFT;  | 
512  | 0  |     if(gcb<UPRV_LENGTHOF(gcbToHst)) { | 
513  | 0  |         return gcbToHst[gcb];  | 
514  | 0  |     } else { | 
515  | 0  |         return U_HST_NOT_APPLICABLE;  | 
516  | 0  |     }  | 
517  | 0  | }  | 
518  |  |  | 
519  |  | #if UCONFIG_NO_NORMALIZATION  | 
520  |  | static int32_t getNormQuickCheck(const IntProperty &, UChar32, UProperty) { | 
521  |  |     return 0;  | 
522  |  | }  | 
523  |  | #else  | 
524  | 0  | static int32_t getNormQuickCheck(const IntProperty &/*prop*/, UChar32 c, UProperty which) { | 
525  | 0  |     return (int32_t)unorm_getQuickCheck(c, (UNormalizationMode)(which-UCHAR_NFD_QUICK_CHECK+UNORM_NFD));  | 
526  | 0  | }  | 
527  |  | #endif  | 
528  |  |  | 
529  |  | #if UCONFIG_NO_NORMALIZATION  | 
530  |  | static int32_t getLeadCombiningClass(const IntProperty &, UChar32, UProperty) { | 
531  |  |     return 0;  | 
532  |  | }  | 
533  |  | #else  | 
534  | 0  | static int32_t getLeadCombiningClass(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) { | 
535  | 0  |     return unorm_getFCD16(c)>>8;  | 
536  | 0  | }  | 
537  |  | #endif  | 
538  |  |  | 
539  |  | #if UCONFIG_NO_NORMALIZATION  | 
540  |  | static int32_t getTrailCombiningClass(const IntProperty &, UChar32, UProperty) { | 
541  |  |     return 0;  | 
542  |  | }  | 
543  |  | #else  | 
544  | 0  | static int32_t getTrailCombiningClass(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) { | 
545  | 0  |     return unorm_getFCD16(c)&0xff;  | 
546  | 0  | }  | 
547  |  | #endif  | 
548  |  |  | 
549  | 0  | static int32_t getInPC(const IntProperty &, UChar32 c, UProperty) { | 
550  | 0  |     return ulayout_ensureData() && gInpcTrie != nullptr ? ucptrie_get(gInpcTrie, c) : 0;  | 
551  | 0  | }  | 
552  |  |  | 
553  | 0  | static int32_t getInSC(const IntProperty &, UChar32 c, UProperty) { | 
554  | 0  |     return ulayout_ensureData() && gInscTrie != nullptr ? ucptrie_get(gInscTrie, c) : 0;  | 
555  | 0  | }  | 
556  |  |  | 
557  | 0  | static int32_t getVo(const IntProperty &, UChar32 c, UProperty) { | 
558  | 0  |     return ulayout_ensureData() && gVoTrie != nullptr ? ucptrie_get(gVoTrie, c) : 0;  | 
559  | 0  | }  | 
560  |  |  | 
561  | 0  | static int32_t layoutGetMaxValue(const IntProperty &/*prop*/, UProperty which) { | 
562  | 0  |     if (!ulayout_ensureData()) { return 0; } | 
563  | 0  |     switch (which) { | 
564  | 0  |     case UCHAR_INDIC_POSITIONAL_CATEGORY:  | 
565  | 0  |         return gMaxInpcValue;  | 
566  | 0  |     case UCHAR_INDIC_SYLLABIC_CATEGORY:  | 
567  | 0  |         return gMaxInscValue;  | 
568  | 0  |     case UCHAR_VERTICAL_ORIENTATION:  | 
569  | 0  |         return gMaxVoValue;  | 
570  | 0  |     default:  | 
571  | 0  |         return 0;  | 
572  | 0  |     }  | 
573  | 0  | }  | 
574  |  |  | 
575  |  | static const IntProperty intProps[UCHAR_INT_LIMIT-UCHAR_INT_START]={ | 
576  |  |     /*  | 
577  |  |      * column, mask and shift values for int-value properties from u_getUnicodeProperties().  | 
578  |  |      * Must be in order of corresponding UProperty,  | 
579  |  |      * and there must be exactly one entry per int UProperty.  | 
580  |  |      *  | 
581  |  |      * Properties with mask==0 are handled in code.  | 
582  |  |      * For them, column is the UPropertySource value.  | 
583  |  |      */  | 
584  |  |     { UPROPS_SRC_BIDI,  0, 0,                               getBiDiClass, biDiGetMaxValue }, | 
585  |  |     { 0,                UPROPS_BLOCK_MASK, UPROPS_BLOCK_SHIFT, defaultGetValue, defaultGetMaxValue }, | 
586  |  |     { UPROPS_SRC_NFC,   0, 0xff,                            getCombiningClass, getMaxValueFromShift }, | 
587  |  |     { 2,                UPROPS_DT_MASK, 0,                  defaultGetValue, defaultGetMaxValue }, | 
588  |  |     { 0,                UPROPS_EA_MASK, UPROPS_EA_SHIFT,    defaultGetValue, defaultGetMaxValue }, | 
589  |  |     { UPROPS_SRC_CHAR,  0, (int32_t)U_CHAR_CATEGORY_COUNT-1,getGeneralCategory, getMaxValueFromShift }, | 
590  |  |     { UPROPS_SRC_BIDI,  0, 0,                               getJoiningGroup, biDiGetMaxValue }, | 
591  |  |     { UPROPS_SRC_BIDI,  0, 0,                               getJoiningType, biDiGetMaxValue }, | 
592  |  |     { 2,                UPROPS_LB_MASK, UPROPS_LB_SHIFT,    defaultGetValue, defaultGetMaxValue }, | 
593  |  |     { UPROPS_SRC_CHAR,  0, (int32_t)U_NT_COUNT-1,           getNumericType, getMaxValueFromShift }, | 
594  |  |     { UPROPS_SRC_PROPSVEC, 0, 0,                            getScript, scriptGetMaxValue }, | 
595  |  |     { UPROPS_SRC_PROPSVEC, 0, (int32_t)U_HST_COUNT-1,       getHangulSyllableType, getMaxValueFromShift }, | 
596  |  |     // UCHAR_NFD_QUICK_CHECK: max=1=YES -- never "maybe", only "no" or "yes"  | 
597  |  |     { UPROPS_SRC_NFC,   0, (int32_t)UNORM_YES,              getNormQuickCheck, getMaxValueFromShift }, | 
598  |  |     // UCHAR_NFKD_QUICK_CHECK: max=1=YES -- never "maybe", only "no" or "yes"  | 
599  |  |     { UPROPS_SRC_NFKC,  0, (int32_t)UNORM_YES,              getNormQuickCheck, getMaxValueFromShift }, | 
600  |  |     // UCHAR_NFC_QUICK_CHECK: max=2=MAYBE  | 
601  |  |     { UPROPS_SRC_NFC,   0, (int32_t)UNORM_MAYBE,            getNormQuickCheck, getMaxValueFromShift }, | 
602  |  |     // UCHAR_NFKC_QUICK_CHECK: max=2=MAYBE  | 
603  |  |     { UPROPS_SRC_NFKC,  0, (int32_t)UNORM_MAYBE,            getNormQuickCheck, getMaxValueFromShift }, | 
604  |  |     { UPROPS_SRC_NFC,   0, 0xff,                            getLeadCombiningClass, getMaxValueFromShift }, | 
605  |  |     { UPROPS_SRC_NFC,   0, 0xff,                            getTrailCombiningClass, getMaxValueFromShift }, | 
606  |  |     { 2,                UPROPS_GCB_MASK, UPROPS_GCB_SHIFT,  defaultGetValue, defaultGetMaxValue }, | 
607  |  |     { 2,                UPROPS_SB_MASK, UPROPS_SB_SHIFT,    defaultGetValue, defaultGetMaxValue }, | 
608  |  |     { 2,                UPROPS_WB_MASK, UPROPS_WB_SHIFT,    defaultGetValue, defaultGetMaxValue }, | 
609  |  |     { UPROPS_SRC_BIDI,  0, 0,                               getBiDiPairedBracketType, biDiGetMaxValue }, | 
610  |  |     { UPROPS_SRC_INPC,  0, 0,                               getInPC, layoutGetMaxValue }, | 
611  |  |     { UPROPS_SRC_INSC,  0, 0,                               getInSC, layoutGetMaxValue }, | 
612  |  |     { UPROPS_SRC_VO,    0, 0,                               getVo, layoutGetMaxValue }, | 
613  |  | };  | 
614  |  |  | 
615  |  | U_CAPI int32_t U_EXPORT2  | 
616  | 0  | u_getIntPropertyValue(UChar32 c, UProperty which) { | 
617  | 0  |     if(which<UCHAR_INT_START) { | 
618  | 0  |         if(UCHAR_BINARY_START<=which && which<UCHAR_BINARY_LIMIT) { | 
619  | 0  |             const BinaryProperty &prop=binProps[which];  | 
620  | 0  |             return prop.contains(prop, c, which);  | 
621  | 0  |         }  | 
622  | 0  |     } else if(which<UCHAR_INT_LIMIT) { | 
623  | 0  |         const IntProperty &prop=intProps[which-UCHAR_INT_START];  | 
624  | 0  |         return prop.getValue(prop, c, which);  | 
625  | 0  |     } else if(which==UCHAR_GENERAL_CATEGORY_MASK) { | 
626  | 0  |         return U_MASK(u_charType(c));  | 
627  | 0  |     }  | 
628  | 0  |     return 0;  // undefined  | 
629  | 0  | }  | 
630  |  |  | 
631  |  | U_CAPI int32_t U_EXPORT2  | 
632  | 0  | u_getIntPropertyMinValue(UProperty /*which*/) { | 
633  | 0  |     return 0; /* all binary/enum/int properties have a minimum value of 0 */  | 
634  | 0  | }  | 
635  |  |  | 
636  |  | U_CAPI int32_t U_EXPORT2  | 
637  | 0  | u_getIntPropertyMaxValue(UProperty which) { | 
638  | 0  |     if(which<UCHAR_INT_START) { | 
639  | 0  |         if(UCHAR_BINARY_START<=which && which<UCHAR_BINARY_LIMIT) { | 
640  | 0  |             return 1;  // maximum TRUE for all binary properties  | 
641  | 0  |         }  | 
642  | 0  |     } else if(which<UCHAR_INT_LIMIT) { | 
643  | 0  |         const IntProperty &prop=intProps[which-UCHAR_INT_START];  | 
644  | 0  |         return prop.getMaxValue(prop, which);  | 
645  | 0  |     }  | 
646  | 0  |     return -1;  // undefined  | 
647  | 0  | }  | 
648  |  |  | 
649  |  | U_CFUNC UPropertySource U_EXPORT2  | 
650  | 0  | uprops_getSource(UProperty which) { | 
651  | 0  |     if(which<UCHAR_BINARY_START) { | 
652  | 0  |         return UPROPS_SRC_NONE; /* undefined */  | 
653  | 0  |     } else if(which<UCHAR_BINARY_LIMIT) { | 
654  | 0  |         const BinaryProperty &prop=binProps[which];  | 
655  | 0  |         if(prop.mask!=0) { | 
656  | 0  |             return UPROPS_SRC_PROPSVEC;  | 
657  | 0  |         } else { | 
658  | 0  |             return (UPropertySource)prop.column;  | 
659  | 0  |         }  | 
660  | 0  |     } else if(which<UCHAR_INT_START) { | 
661  | 0  |         return UPROPS_SRC_NONE; /* undefined */  | 
662  | 0  |     } else if(which<UCHAR_INT_LIMIT) { | 
663  | 0  |         const IntProperty &prop=intProps[which-UCHAR_INT_START];  | 
664  | 0  |         if(prop.mask!=0) { | 
665  | 0  |             return UPROPS_SRC_PROPSVEC;  | 
666  | 0  |         } else { | 
667  | 0  |             return (UPropertySource)prop.column;  | 
668  | 0  |         }  | 
669  | 0  |     } else if(which<UCHAR_STRING_START) { | 
670  | 0  |         switch(which) { | 
671  | 0  |         case UCHAR_GENERAL_CATEGORY_MASK:  | 
672  | 0  |         case UCHAR_NUMERIC_VALUE:  | 
673  | 0  |             return UPROPS_SRC_CHAR;  | 
674  |  |  | 
675  | 0  |         default:  | 
676  | 0  |             return UPROPS_SRC_NONE;  | 
677  | 0  |         }  | 
678  | 0  |     } else if(which<UCHAR_STRING_LIMIT) { | 
679  | 0  |         switch(which) { | 
680  | 0  |         case UCHAR_AGE:  | 
681  | 0  |             return UPROPS_SRC_PROPSVEC;  | 
682  |  |  | 
683  | 0  |         case UCHAR_BIDI_MIRRORING_GLYPH:  | 
684  | 0  |             return UPROPS_SRC_BIDI;  | 
685  |  |  | 
686  | 0  |         case UCHAR_CASE_FOLDING:  | 
687  | 0  |         case UCHAR_LOWERCASE_MAPPING:  | 
688  | 0  |         case UCHAR_SIMPLE_CASE_FOLDING:  | 
689  | 0  |         case UCHAR_SIMPLE_LOWERCASE_MAPPING:  | 
690  | 0  |         case UCHAR_SIMPLE_TITLECASE_MAPPING:  | 
691  | 0  |         case UCHAR_SIMPLE_UPPERCASE_MAPPING:  | 
692  | 0  |         case UCHAR_TITLECASE_MAPPING:  | 
693  | 0  |         case UCHAR_UPPERCASE_MAPPING:  | 
694  | 0  |             return UPROPS_SRC_CASE;  | 
695  |  |  | 
696  | 0  |         case UCHAR_ISO_COMMENT:  | 
697  | 0  |         case UCHAR_NAME:  | 
698  | 0  |         case UCHAR_UNICODE_1_NAME:  | 
699  | 0  |             return UPROPS_SRC_NAMES;  | 
700  |  |  | 
701  | 0  |         default:  | 
702  | 0  |             return UPROPS_SRC_NONE;  | 
703  | 0  |         }  | 
704  | 0  |     } else { | 
705  | 0  |         switch(which) { | 
706  | 0  |         case UCHAR_SCRIPT_EXTENSIONS:  | 
707  | 0  |             return UPROPS_SRC_PROPSVEC;  | 
708  | 0  |         default:  | 
709  | 0  |             return UPROPS_SRC_NONE; /* undefined */  | 
710  | 0  |         }  | 
711  | 0  |     }  | 
712  | 0  | }  | 
713  |  |  | 
714  |  | U_CFUNC void U_EXPORT2  | 
715  | 0  | uprops_addPropertyStarts(UPropertySource src, const USetAdder *sa, UErrorCode *pErrorCode) { | 
716  | 0  |     if (!ulayout_ensureData(*pErrorCode)) { return; } | 
717  | 0  |     const UCPTrie *trie;  | 
718  | 0  |     switch (src) { | 
719  | 0  |     case UPROPS_SRC_INPC:  | 
720  | 0  |         trie = gInpcTrie;  | 
721  | 0  |         break;  | 
722  | 0  |     case UPROPS_SRC_INSC:  | 
723  | 0  |         trie = gInscTrie;  | 
724  | 0  |         break;  | 
725  | 0  |     case UPROPS_SRC_VO:  | 
726  | 0  |         trie = gVoTrie;  | 
727  | 0  |         break;  | 
728  | 0  |     default:  | 
729  | 0  |         *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;  | 
730  | 0  |         return;  | 
731  | 0  |     }  | 
732  |  |  | 
733  | 0  |     if (trie == nullptr) { | 
734  | 0  |         *pErrorCode = U_MISSING_RESOURCE_ERROR;  | 
735  | 0  |         return;  | 
736  | 0  |     }  | 
737  |  |  | 
738  |  |     // Add the start code point of each same-value range of the trie.  | 
739  | 0  |     UChar32 start = 0, end;  | 
740  | 0  |     while ((end = ucptrie_getRange(trie, start, UCPMAP_RANGE_NORMAL, 0,  | 
741  | 0  |                                    nullptr, nullptr, nullptr)) >= 0) { | 
742  | 0  |         sa->add(sa->set, start);  | 
743  | 0  |         start = end + 1;  | 
744  | 0  |     }  | 
745  | 0  | }  | 
746  |  |  | 
747  |  | #if !UCONFIG_NO_NORMALIZATION  | 
748  |  |  | 
749  |  | U_CAPI int32_t U_EXPORT2  | 
750  | 0  | u_getFC_NFKC_Closure(UChar32 c, UChar *dest, int32_t destCapacity, UErrorCode *pErrorCode) { | 
751  | 0  |     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { | 
752  | 0  |         return 0;  | 
753  | 0  |     }  | 
754  | 0  |     if(destCapacity<0 || (dest==NULL && destCapacity>0)) { | 
755  | 0  |         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;  | 
756  | 0  |         return 0;  | 
757  | 0  |     }  | 
758  |  |     // Compute the FC_NFKC_Closure on the fly:  | 
759  |  |     // We have the API for complete coverage of Unicode properties, although  | 
760  |  |     // this value by itself is not useful via API.  | 
761  |  |     // (What could be useful is a custom normalization table that combines  | 
762  |  |     // case folding and NFKC.)  | 
763  |  |     // For the derivation, see Unicode's DerivedNormalizationProps.txt.  | 
764  | 0  |     const Normalizer2 *nfkc=Normalizer2::getNFKCInstance(*pErrorCode);  | 
765  | 0  |     if(U_FAILURE(*pErrorCode)) { | 
766  | 0  |         return 0;  | 
767  | 0  |     }  | 
768  |  |     // first: b = NFKC(Fold(a))  | 
769  | 0  |     UnicodeString folded1String;  | 
770  | 0  |     const UChar *folded1;  | 
771  | 0  |     int32_t folded1Length=ucase_toFullFolding(c, &folded1, U_FOLD_CASE_DEFAULT);  | 
772  | 0  |     if(folded1Length<0) { | 
773  | 0  |         const Normalizer2Impl *nfkcImpl=Normalizer2Factory::getImpl(nfkc);  | 
774  | 0  |         if(nfkcImpl->getCompQuickCheck(nfkcImpl->getNorm16(c))!=UNORM_NO) { | 
775  | 0  |             return u_terminateUChars(dest, destCapacity, 0, pErrorCode);  // c does not change at all under CaseFolding+NFKC  | 
776  | 0  |         }  | 
777  | 0  |         folded1String.setTo(c);  | 
778  | 0  |     } else { | 
779  | 0  |         if(folded1Length>UCASE_MAX_STRING_LENGTH) { | 
780  | 0  |             folded1String.setTo(folded1Length);  | 
781  | 0  |         } else { | 
782  | 0  |             folded1String.setTo(FALSE, folded1, folded1Length);  | 
783  | 0  |         }  | 
784  | 0  |     }  | 
785  | 0  |     UnicodeString kc1=nfkc->normalize(folded1String, *pErrorCode);  | 
786  |  |     // second: c = NFKC(Fold(b))  | 
787  | 0  |     UnicodeString folded2String(kc1);  | 
788  | 0  |     UnicodeString kc2=nfkc->normalize(folded2String.foldCase(), *pErrorCode);  | 
789  |  |     // if (c != b) add the mapping from a to c  | 
790  | 0  |     if(U_FAILURE(*pErrorCode) || kc1==kc2) { | 
791  | 0  |         return u_terminateUChars(dest, destCapacity, 0, pErrorCode);  | 
792  | 0  |     } else { | 
793  | 0  |         return kc2.extract(dest, destCapacity, *pErrorCode);  | 
794  | 0  |     }  | 
795  | 0  | }  | 
796  |  |  | 
797  |  | #endif  |