1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
5 * Copyright (C) 2014, International Business Machines
6 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
8 * loadednormalizer2impl.cpp
10 * created on: 2014sep03
11 * created by: Markus W. Scherer
14 #include "unicode/utypes.h"
16 #if !UCONFIG_NO_NORMALIZATION
18 #include "unicode/udata.h"
19 #include "unicode/localpointer.h"
20 #include "unicode/normalizer2.h"
21 #include "unicode/ucptrie.h"
22 #include "unicode/unistr.h"
23 #include "unicode/unorm.h"
26 #include "norm2allmodes.h"
27 #include "normalizer2impl.h"
34 class LoadedNormalizer2Impl
: public Normalizer2Impl
{
36 LoadedNormalizer2Impl() : memory(NULL
), ownedTrie(NULL
) {}
37 virtual ~LoadedNormalizer2Impl();
39 void load(const char *packageName
, const char *name
, UErrorCode
&errorCode
);
42 static UBool U_CALLCONV
43 isAcceptable(void *context
, const char *type
, const char *name
, const UDataInfo
*pInfo
);
49 LoadedNormalizer2Impl::~LoadedNormalizer2Impl() {
51 ucptrie_close(ownedTrie
);
55 LoadedNormalizer2Impl::isAcceptable(void * /*context*/,
56 const char * /* type */, const char * /*name*/,
57 const UDataInfo
*pInfo
) {
60 pInfo
->isBigEndian
==U_IS_BIG_ENDIAN
&&
61 pInfo
->charsetFamily
==U_CHARSET_FAMILY
&&
62 pInfo
->dataFormat
[0]==0x4e && /* dataFormat="Nrm2" */
63 pInfo
->dataFormat
[1]==0x72 &&
64 pInfo
->dataFormat
[2]==0x6d &&
65 pInfo
->dataFormat
[3]==0x32 &&
66 pInfo
->formatVersion
[0]==4
68 // Normalizer2Impl *me=(Normalizer2Impl *)context;
69 // uprv_memcpy(me->dataVersion, pInfo->dataVersion, 4);
77 LoadedNormalizer2Impl::load(const char *packageName
, const char *name
, UErrorCode
&errorCode
) {
78 if(U_FAILURE(errorCode
)) {
81 memory
=udata_openChoice(packageName
, "nrm", name
, isAcceptable
, this, &errorCode
);
82 if(U_FAILURE(errorCode
)) {
85 const uint8_t *inBytes
=(const uint8_t *)udata_getMemory(memory
);
86 const int32_t *inIndexes
=(const int32_t *)inBytes
;
87 int32_t indexesLength
=inIndexes
[IX_NORM_TRIE_OFFSET
]/4;
88 if(indexesLength
<=IX_MIN_LCCC_CP
) {
89 errorCode
=U_INVALID_FORMAT_ERROR
; // Not enough indexes.
93 int32_t offset
=inIndexes
[IX_NORM_TRIE_OFFSET
];
94 int32_t nextOffset
=inIndexes
[IX_EXTRA_DATA_OFFSET
];
95 ownedTrie
=ucptrie_openFromBinary(UCPTRIE_TYPE_FAST
, UCPTRIE_VALUE_BITS_16
,
96 inBytes
+offset
, nextOffset
-offset
, NULL
,
98 if(U_FAILURE(errorCode
)) {
103 nextOffset
=inIndexes
[IX_SMALL_FCD_OFFSET
];
104 const uint16_t *inExtraData
=(const uint16_t *)(inBytes
+offset
);
106 // smallFCD: new in formatVersion 2
108 const uint8_t *inSmallFCD
=inBytes
+offset
;
110 init(inIndexes
, ownedTrie
, inExtraData
, inSmallFCD
);
113 // instance cache ---------------------------------------------------------- ***
116 Norm2AllModes::createInstance(const char *packageName
,
118 UErrorCode
&errorCode
) {
119 if(U_FAILURE(errorCode
)) {
122 LoadedNormalizer2Impl
*impl
=new LoadedNormalizer2Impl
;
124 errorCode
=U_MEMORY_ALLOCATION_ERROR
;
127 impl
->load(packageName
, name
, errorCode
);
128 return createInstance(impl
, errorCode
);
132 static UBool U_CALLCONV
uprv_loaded_normalizer2_cleanup();
135 #if !NORM2_HARDCODE_NFC_DATA
136 static Norm2AllModes
*nfcSingleton
;
137 static icu::UInitOnce nfcInitOnce
= U_INITONCE_INITIALIZER
;
140 static Norm2AllModes
*nfkcSingleton
;
141 static icu::UInitOnce nfkcInitOnce
= U_INITONCE_INITIALIZER
;
143 static Norm2AllModes
*nfkc_cfSingleton
;
144 static icu::UInitOnce nfkc_cfInitOnce
= U_INITONCE_INITIALIZER
;
146 static UHashtable
*cache
=NULL
;
148 // UInitOnce singleton initialization function
149 static void U_CALLCONV
initSingletons(const char *what
, UErrorCode
&errorCode
) {
150 #if !NORM2_HARDCODE_NFC_DATA
151 if (uprv_strcmp(what
, "nfc") == 0) {
152 nfcSingleton
= Norm2AllModes::createInstance(NULL
, "nfc", errorCode
);
155 if (uprv_strcmp(what
, "nfkc") == 0) {
156 nfkcSingleton
= Norm2AllModes::createInstance(NULL
, "nfkc", errorCode
);
157 } else if (uprv_strcmp(what
, "nfkc_cf") == 0) {
158 nfkc_cfSingleton
= Norm2AllModes::createInstance(NULL
, "nfkc_cf", errorCode
);
160 UPRV_UNREACHABLE
; // Unknown singleton
162 ucln_common_registerCleanup(UCLN_COMMON_LOADED_NORMALIZER2
, uprv_loaded_normalizer2_cleanup
);
167 static void U_CALLCONV
deleteNorm2AllModes(void *allModes
) {
168 delete (Norm2AllModes
*)allModes
;
171 static UBool U_CALLCONV
uprv_loaded_normalizer2_cleanup() {
172 #if !NORM2_HARDCODE_NFC_DATA
178 delete nfkcSingleton
;
179 nfkcSingleton
= NULL
;
180 nfkcInitOnce
.reset();
182 delete nfkc_cfSingleton
;
183 nfkc_cfSingleton
= NULL
;
184 nfkc_cfInitOnce
.reset();
193 #if !NORM2_HARDCODE_NFC_DATA
194 const Norm2AllModes
*
195 Norm2AllModes::getNFCInstance(UErrorCode
&errorCode
) {
196 if(U_FAILURE(errorCode
)) { return NULL
; }
197 umtx_initOnce(nfcInitOnce
, &initSingletons
, "nfc", errorCode
);
202 const Norm2AllModes
*
203 Norm2AllModes::getNFKCInstance(UErrorCode
&errorCode
) {
204 if(U_FAILURE(errorCode
)) { return NULL
; }
205 umtx_initOnce(nfkcInitOnce
, &initSingletons
, "nfkc", errorCode
);
206 return nfkcSingleton
;
209 const Norm2AllModes
*
210 Norm2AllModes::getNFKC_CFInstance(UErrorCode
&errorCode
) {
211 if(U_FAILURE(errorCode
)) { return NULL
; }
212 umtx_initOnce(nfkc_cfInitOnce
, &initSingletons
, "nfkc_cf", errorCode
);
213 return nfkc_cfSingleton
;
216 #if !NORM2_HARDCODE_NFC_DATA
218 Normalizer2::getNFCInstance(UErrorCode
&errorCode
) {
219 const Norm2AllModes
*allModes
=Norm2AllModes::getNFCInstance(errorCode
);
220 return allModes
!=NULL
? &allModes
->comp
: NULL
;
224 Normalizer2::getNFDInstance(UErrorCode
&errorCode
) {
225 const Norm2AllModes
*allModes
=Norm2AllModes::getNFCInstance(errorCode
);
226 return allModes
!=NULL
? &allModes
->decomp
: NULL
;
229 const Normalizer2
*Normalizer2Factory::getFCDInstance(UErrorCode
&errorCode
) {
230 const Norm2AllModes
*allModes
=Norm2AllModes::getNFCInstance(errorCode
);
231 return allModes
!=NULL
? &allModes
->fcd
: NULL
;
234 const Normalizer2
*Normalizer2Factory::getFCCInstance(UErrorCode
&errorCode
) {
235 const Norm2AllModes
*allModes
=Norm2AllModes::getNFCInstance(errorCode
);
236 return allModes
!=NULL
? &allModes
->fcc
: NULL
;
239 const Normalizer2Impl
*
240 Normalizer2Factory::getNFCImpl(UErrorCode
&errorCode
) {
241 const Norm2AllModes
*allModes
=Norm2AllModes::getNFCInstance(errorCode
);
242 return allModes
!=NULL
? allModes
->impl
: NULL
;
247 Normalizer2::getNFKCInstance(UErrorCode
&errorCode
) {
248 const Norm2AllModes
*allModes
=Norm2AllModes::getNFKCInstance(errorCode
);
249 return allModes
!=NULL
? &allModes
->comp
: NULL
;
253 Normalizer2::getNFKDInstance(UErrorCode
&errorCode
) {
254 const Norm2AllModes
*allModes
=Norm2AllModes::getNFKCInstance(errorCode
);
255 return allModes
!=NULL
? &allModes
->decomp
: NULL
;
259 Normalizer2::getNFKCCasefoldInstance(UErrorCode
&errorCode
) {
260 const Norm2AllModes
*allModes
=Norm2AllModes::getNFKC_CFInstance(errorCode
);
261 return allModes
!=NULL
? &allModes
->comp
: NULL
;
265 Normalizer2::getInstance(const char *packageName
,
267 UNormalization2Mode mode
,
268 UErrorCode
&errorCode
) {
269 if(U_FAILURE(errorCode
)) {
272 if(name
==NULL
|| *name
==0) {
273 errorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
276 const Norm2AllModes
*allModes
=NULL
;
277 if(packageName
==NULL
) {
278 if(0==uprv_strcmp(name
, "nfc")) {
279 allModes
=Norm2AllModes::getNFCInstance(errorCode
);
280 } else if(0==uprv_strcmp(name
, "nfkc")) {
281 allModes
=Norm2AllModes::getNFKCInstance(errorCode
);
282 } else if(0==uprv_strcmp(name
, "nfkc_cf")) {
283 allModes
=Norm2AllModes::getNFKC_CFInstance(errorCode
);
286 if(allModes
==NULL
&& U_SUCCESS(errorCode
)) {
290 allModes
=(Norm2AllModes
*)uhash_get(cache
, name
);
294 ucln_common_registerCleanup(UCLN_COMMON_LOADED_NORMALIZER2
, uprv_loaded_normalizer2_cleanup
);
295 LocalPointer
<Norm2AllModes
> localAllModes(
296 Norm2AllModes::createInstance(packageName
, name
, errorCode
));
297 if(U_SUCCESS(errorCode
)) {
300 cache
=uhash_open(uhash_hashChars
, uhash_compareChars
, NULL
, &errorCode
);
301 if(U_FAILURE(errorCode
)) {
304 uhash_setKeyDeleter(cache
, uprv_free
);
305 uhash_setValueDeleter(cache
, deleteNorm2AllModes
);
307 void *temp
=uhash_get(cache
, name
);
309 int32_t keyLength
= static_cast<int32_t>(uprv_strlen(name
)+1);
310 char *nameCopy
=(char *)uprv_malloc(keyLength
);
312 errorCode
=U_MEMORY_ALLOCATION_ERROR
;
315 uprv_memcpy(nameCopy
, name
, keyLength
);
316 allModes
=localAllModes
.getAlias();
317 uhash_put(cache
, nameCopy
, localAllModes
.orphan(), &errorCode
);
320 allModes
=(Norm2AllModes
*)temp
;
325 if(allModes
!=NULL
&& U_SUCCESS(errorCode
)) {
328 return &allModes
->comp
;
329 case UNORM2_DECOMPOSE
:
330 return &allModes
->decomp
;
332 return &allModes
->fcd
;
333 case UNORM2_COMPOSE_CONTIGUOUS
:
334 return &allModes
->fcc
;
343 Normalizer2Factory::getInstance(UNormalizationMode mode
, UErrorCode
&errorCode
) {
344 if(U_FAILURE(errorCode
)) {
349 return Normalizer2::getNFDInstance(errorCode
);
351 return Normalizer2::getNFKDInstance(errorCode
);
353 return Normalizer2::getNFCInstance(errorCode
);
355 return Normalizer2::getNFKCInstance(errorCode
);
357 return getFCDInstance(errorCode
);
358 default: // UNORM_NONE
359 return getNoopInstance(errorCode
);
363 const Normalizer2Impl
*
364 Normalizer2Factory::getNFKCImpl(UErrorCode
&errorCode
) {
365 const Norm2AllModes
*allModes
=Norm2AllModes::getNFKCInstance(errorCode
);
366 return allModes
!=NULL
? allModes
->impl
: NULL
;
369 const Normalizer2Impl
*
370 Normalizer2Factory::getNFKC_CFImpl(UErrorCode
&errorCode
) {
371 const Norm2AllModes
*allModes
=Norm2AllModes::getNFKC_CFInstance(errorCode
);
372 return allModes
!=NULL
? allModes
->impl
: NULL
;
377 // C API ------------------------------------------------------------------- ***
381 U_CAPI
const UNormalizer2
* U_EXPORT2
382 unorm2_getNFKCInstance(UErrorCode
*pErrorCode
) {
383 return (const UNormalizer2
*)Normalizer2::getNFKCInstance(*pErrorCode
);
386 U_CAPI
const UNormalizer2
* U_EXPORT2
387 unorm2_getNFKDInstance(UErrorCode
*pErrorCode
) {
388 return (const UNormalizer2
*)Normalizer2::getNFKDInstance(*pErrorCode
);
391 U_CAPI
const UNormalizer2
* U_EXPORT2
392 unorm2_getNFKCCasefoldInstance(UErrorCode
*pErrorCode
) {
393 return (const UNormalizer2
*)Normalizer2::getNFKCCasefoldInstance(*pErrorCode
);
396 U_CAPI
const UNormalizer2
* U_EXPORT2
397 unorm2_getInstance(const char *packageName
,
399 UNormalization2Mode mode
,
400 UErrorCode
*pErrorCode
) {
401 return (const UNormalizer2
*)Normalizer2::getInstance(packageName
, name
, mode
, *pErrorCode
);
404 U_CFUNC UNormalizationCheckResult
405 unorm_getQuickCheck(UChar32 c
, UNormalizationMode mode
) {
406 if(mode
<=UNORM_NONE
|| UNORM_FCD
<=mode
) {
409 UErrorCode errorCode
=U_ZERO_ERROR
;
410 const Normalizer2
*norm2
=Normalizer2Factory::getInstance(mode
, errorCode
);
411 if(U_SUCCESS(errorCode
)) {
412 return ((const Normalizer2WithImpl
*)norm2
)->getQuickCheck(c
);
418 #endif // !UCONFIG_NO_NORMALIZATION