2 *******************************************************************************
3 * Copyright (C) 2014, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 *******************************************************************************
6 * loadednormalizer2impl.cpp
8 * created on: 2014sep03
9 * created by: Markus W. Scherer
12 #include "unicode/utypes.h"
14 #if !UCONFIG_NO_NORMALIZATION
16 #include "unicode/udata.h"
17 #include "unicode/localpointer.h"
18 #include "unicode/normalizer2.h"
19 #include "unicode/unistr.h"
20 #include "unicode/unorm.h"
23 #include "norm2allmodes.h"
24 #include "normalizer2impl.h"
31 class LoadedNormalizer2Impl
: public Normalizer2Impl
{
33 LoadedNormalizer2Impl() : memory(NULL
), ownedTrie(NULL
) {}
34 virtual ~LoadedNormalizer2Impl();
36 void load(const char *packageName
, const char *name
, UErrorCode
&errorCode
);
39 static UBool U_CALLCONV
40 isAcceptable(void *context
, const char *type
, const char *name
, const UDataInfo
*pInfo
);
46 LoadedNormalizer2Impl::~LoadedNormalizer2Impl() {
48 utrie2_close(ownedTrie
);
52 LoadedNormalizer2Impl::isAcceptable(void * /*context*/,
53 const char * /* type */, const char * /*name*/,
54 const UDataInfo
*pInfo
) {
57 pInfo
->isBigEndian
==U_IS_BIG_ENDIAN
&&
58 pInfo
->charsetFamily
==U_CHARSET_FAMILY
&&
59 pInfo
->dataFormat
[0]==0x4e && /* dataFormat="Nrm2" */
60 pInfo
->dataFormat
[1]==0x72 &&
61 pInfo
->dataFormat
[2]==0x6d &&
62 pInfo
->dataFormat
[3]==0x32 &&
63 pInfo
->formatVersion
[0]==2
65 // Normalizer2Impl *me=(Normalizer2Impl *)context;
66 // uprv_memcpy(me->dataVersion, pInfo->dataVersion, 4);
74 LoadedNormalizer2Impl::load(const char *packageName
, const char *name
, UErrorCode
&errorCode
) {
75 if(U_FAILURE(errorCode
)) {
78 memory
=udata_openChoice(packageName
, "nrm", name
, isAcceptable
, this, &errorCode
);
79 if(U_FAILURE(errorCode
)) {
82 const uint8_t *inBytes
=(const uint8_t *)udata_getMemory(memory
);
83 const int32_t *inIndexes
=(const int32_t *)inBytes
;
84 int32_t indexesLength
=inIndexes
[IX_NORM_TRIE_OFFSET
]/4;
85 if(indexesLength
<=IX_MIN_MAYBE_YES
) {
86 errorCode
=U_INVALID_FORMAT_ERROR
; // Not enough indexes.
90 int32_t offset
=inIndexes
[IX_NORM_TRIE_OFFSET
];
91 int32_t nextOffset
=inIndexes
[IX_EXTRA_DATA_OFFSET
];
92 ownedTrie
=utrie2_openFromSerialized(UTRIE2_16_VALUE_BITS
,
93 inBytes
+offset
, nextOffset
-offset
, NULL
,
95 if(U_FAILURE(errorCode
)) {
100 nextOffset
=inIndexes
[IX_SMALL_FCD_OFFSET
];
101 const uint16_t *inExtraData
=(const uint16_t *)(inBytes
+offset
);
103 // smallFCD: new in formatVersion 2
105 const uint8_t *inSmallFCD
=inBytes
+offset
;
107 init(inIndexes
, ownedTrie
, inExtraData
, inSmallFCD
);
110 // instance cache ---------------------------------------------------------- ***
113 Norm2AllModes::createInstance(const char *packageName
,
115 UErrorCode
&errorCode
) {
116 if(U_FAILURE(errorCode
)) {
119 LoadedNormalizer2Impl
*impl
=new LoadedNormalizer2Impl
;
121 errorCode
=U_MEMORY_ALLOCATION_ERROR
;
124 impl
->load(packageName
, name
, errorCode
);
125 return createInstance(impl
, errorCode
);
129 static UBool U_CALLCONV
uprv_loaded_normalizer2_cleanup();
132 static Norm2AllModes
*nfkcSingleton
;
133 static Norm2AllModes
*nfkc_cfSingleton
;
134 static UHashtable
*cache
=NULL
;
136 static icu::UInitOnce nfkcInitOnce
= U_INITONCE_INITIALIZER
;
137 static icu::UInitOnce nfkc_cfInitOnce
= U_INITONCE_INITIALIZER
;
139 // UInitOnce singleton initialization function
140 static void U_CALLCONV
initSingletons(const char *what
, UErrorCode
&errorCode
) {
141 if (uprv_strcmp(what
, "nfkc") == 0) {
142 nfkcSingleton
= Norm2AllModes::createInstance(NULL
, "nfkc", errorCode
);
143 } else if (uprv_strcmp(what
, "nfkc_cf") == 0) {
144 nfkc_cfSingleton
= Norm2AllModes::createInstance(NULL
, "nfkc_cf", errorCode
);
146 U_ASSERT(FALSE
); // Unknown singleton
148 ucln_common_registerCleanup(UCLN_COMMON_LOADED_NORMALIZER2
, uprv_loaded_normalizer2_cleanup
);
153 static void U_CALLCONV
deleteNorm2AllModes(void *allModes
) {
154 delete (Norm2AllModes
*)allModes
;
157 static UBool U_CALLCONV
uprv_loaded_normalizer2_cleanup() {
158 delete nfkcSingleton
;
159 nfkcSingleton
= NULL
;
160 delete nfkc_cfSingleton
;
161 nfkc_cfSingleton
= NULL
;
164 nfkcInitOnce
.reset();
165 nfkc_cfInitOnce
.reset();
171 const Norm2AllModes
*
172 Norm2AllModes::getNFKCInstance(UErrorCode
&errorCode
) {
173 if(U_FAILURE(errorCode
)) { return NULL
; }
174 umtx_initOnce(nfkcInitOnce
, &initSingletons
, "nfkc", errorCode
);
175 return nfkcSingleton
;
178 const Norm2AllModes
*
179 Norm2AllModes::getNFKC_CFInstance(UErrorCode
&errorCode
) {
180 if(U_FAILURE(errorCode
)) { return NULL
; }
181 umtx_initOnce(nfkc_cfInitOnce
, &initSingletons
, "nfkc_cf", errorCode
);
182 return nfkc_cfSingleton
;
186 Normalizer2::getNFKCInstance(UErrorCode
&errorCode
) {
187 const Norm2AllModes
*allModes
=Norm2AllModes::getNFKCInstance(errorCode
);
188 return allModes
!=NULL
? &allModes
->comp
: NULL
;
192 Normalizer2::getNFKDInstance(UErrorCode
&errorCode
) {
193 const Norm2AllModes
*allModes
=Norm2AllModes::getNFKCInstance(errorCode
);
194 return allModes
!=NULL
? &allModes
->decomp
: NULL
;
198 Normalizer2::getNFKCCasefoldInstance(UErrorCode
&errorCode
) {
199 const Norm2AllModes
*allModes
=Norm2AllModes::getNFKC_CFInstance(errorCode
);
200 return allModes
!=NULL
? &allModes
->comp
: NULL
;
204 Normalizer2::getInstance(const char *packageName
,
206 UNormalization2Mode mode
,
207 UErrorCode
&errorCode
) {
208 if(U_FAILURE(errorCode
)) {
211 if(name
==NULL
|| *name
==0) {
212 errorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
215 const Norm2AllModes
*allModes
=NULL
;
216 if(packageName
==NULL
) {
217 if(0==uprv_strcmp(name
, "nfc")) {
218 allModes
=Norm2AllModes::getNFCInstance(errorCode
);
219 } else if(0==uprv_strcmp(name
, "nfkc")) {
220 allModes
=Norm2AllModes::getNFKCInstance(errorCode
);
221 } else if(0==uprv_strcmp(name
, "nfkc_cf")) {
222 allModes
=Norm2AllModes::getNFKC_CFInstance(errorCode
);
225 if(allModes
==NULL
&& U_SUCCESS(errorCode
)) {
229 allModes
=(Norm2AllModes
*)uhash_get(cache
, name
);
233 LocalPointer
<Norm2AllModes
> localAllModes(
234 Norm2AllModes::createInstance(packageName
, name
, errorCode
));
235 if(U_SUCCESS(errorCode
)) {
238 cache
=uhash_open(uhash_hashChars
, uhash_compareChars
, NULL
, &errorCode
);
239 if(U_FAILURE(errorCode
)) {
242 uhash_setKeyDeleter(cache
, uprv_free
);
243 uhash_setValueDeleter(cache
, deleteNorm2AllModes
);
245 void *temp
=uhash_get(cache
, name
);
247 int32_t keyLength
=uprv_strlen(name
)+1;
248 char *nameCopy
=(char *)uprv_malloc(keyLength
);
250 errorCode
=U_MEMORY_ALLOCATION_ERROR
;
253 uprv_memcpy(nameCopy
, name
, keyLength
);
254 allModes
=localAllModes
.getAlias();
255 uhash_put(cache
, nameCopy
, localAllModes
.orphan(), &errorCode
);
258 allModes
=(Norm2AllModes
*)temp
;
263 if(allModes
!=NULL
&& U_SUCCESS(errorCode
)) {
266 return &allModes
->comp
;
267 case UNORM2_DECOMPOSE
:
268 return &allModes
->decomp
;
270 return &allModes
->fcd
;
271 case UNORM2_COMPOSE_CONTIGUOUS
:
272 return &allModes
->fcc
;
281 Normalizer2Factory::getInstance(UNormalizationMode mode
, UErrorCode
&errorCode
) {
282 if(U_FAILURE(errorCode
)) {
287 return Normalizer2::getNFDInstance(errorCode
);
289 return Normalizer2::getNFKDInstance(errorCode
);
291 return Normalizer2::getNFCInstance(errorCode
);
293 return Normalizer2::getNFKCInstance(errorCode
);
295 return getFCDInstance(errorCode
);
296 default: // UNORM_NONE
297 return getNoopInstance(errorCode
);
301 const Normalizer2Impl
*
302 Normalizer2Factory::getNFKCImpl(UErrorCode
&errorCode
) {
303 const Norm2AllModes
*allModes
=Norm2AllModes::getNFKCInstance(errorCode
);
304 return allModes
!=NULL
? allModes
->impl
: NULL
;
307 const Normalizer2Impl
*
308 Normalizer2Factory::getNFKC_CFImpl(UErrorCode
&errorCode
) {
309 const Norm2AllModes
*allModes
=Norm2AllModes::getNFKC_CFInstance(errorCode
);
310 return allModes
!=NULL
? allModes
->impl
: NULL
;
315 // C API ------------------------------------------------------------------- ***
319 U_CAPI
const UNormalizer2
* U_EXPORT2
320 unorm2_getNFKCInstance(UErrorCode
*pErrorCode
) {
321 return (const UNormalizer2
*)Normalizer2::getNFKCInstance(*pErrorCode
);
324 U_CAPI
const UNormalizer2
* U_EXPORT2
325 unorm2_getNFKDInstance(UErrorCode
*pErrorCode
) {
326 return (const UNormalizer2
*)Normalizer2::getNFKDInstance(*pErrorCode
);
329 U_CAPI
const UNormalizer2
* U_EXPORT2
330 unorm2_getNFKCCasefoldInstance(UErrorCode
*pErrorCode
) {
331 return (const UNormalizer2
*)Normalizer2::getNFKCCasefoldInstance(*pErrorCode
);
334 U_CAPI
const UNormalizer2
* U_EXPORT2
335 unorm2_getInstance(const char *packageName
,
337 UNormalization2Mode mode
,
338 UErrorCode
*pErrorCode
) {
339 return (const UNormalizer2
*)Normalizer2::getInstance(packageName
, name
, mode
, *pErrorCode
);
342 U_CFUNC UNormalizationCheckResult
343 unorm_getQuickCheck(UChar32 c
, UNormalizationMode mode
) {
344 if(mode
<=UNORM_NONE
|| UNORM_FCD
<=mode
) {
347 UErrorCode errorCode
=U_ZERO_ERROR
;
348 const Normalizer2
*norm2
=Normalizer2Factory::getInstance(mode
, errorCode
);
349 if(U_SUCCESS(errorCode
)) {
350 return ((const Normalizer2WithImpl
*)norm2
)->getQuickCheck(c
);
356 #endif // !UCONFIG_NO_NORMALIZATION