Path: blob/master/libs/icucommon/loadednormalizer2impl.cpp
12343 views
// © 2016 and later: Unicode, Inc. and others.1// License & terms of use: http://www.unicode.org/copyright.html2/*3*******************************************************************************4* Copyright (C) 2014, International Business Machines5* Corporation and others. All Rights Reserved.6*******************************************************************************7* loadednormalizer2impl.cpp8*9* created on: 2014sep0310* created by: Markus W. Scherer11*/1213#include "unicode/utypes.h"1415#if !UCONFIG_NO_NORMALIZATION1617#include "unicode/udata.h"18#include "unicode/localpointer.h"19#include "unicode/normalizer2.h"20#include "unicode/ucptrie.h"21#include "unicode/unistr.h"22#include "unicode/unorm.h"23#include "cstring.h"24#include "mutex.h"25#include "norm2allmodes.h"26#include "normalizer2impl.h"27#include "uassert.h"28#include "ucln_cmn.h"29#include "uhash.h"3031U_NAMESPACE_BEGIN3233class LoadedNormalizer2Impl : public Normalizer2Impl {34public:35LoadedNormalizer2Impl() : memory(NULL), ownedTrie(NULL) {}36virtual ~LoadedNormalizer2Impl();3738void load(const char *packageName, const char *name, UErrorCode &errorCode);3940private:41static UBool U_CALLCONV42isAcceptable(void *context, const char *type, const char *name, const UDataInfo *pInfo);4344UDataMemory *memory;45UCPTrie *ownedTrie;46};4748LoadedNormalizer2Impl::~LoadedNormalizer2Impl() {49udata_close(memory);50ucptrie_close(ownedTrie);51}5253UBool U_CALLCONV54LoadedNormalizer2Impl::isAcceptable(void * /*context*/,55const char * /* type */, const char * /*name*/,56const UDataInfo *pInfo) {57if(58pInfo->size>=20 &&59pInfo->isBigEndian==U_IS_BIG_ENDIAN &&60pInfo->charsetFamily==U_CHARSET_FAMILY &&61pInfo->dataFormat[0]==0x4e && /* dataFormat="Nrm2" */62pInfo->dataFormat[1]==0x72 &&63pInfo->dataFormat[2]==0x6d &&64pInfo->dataFormat[3]==0x32 &&65pInfo->formatVersion[0]==466) {67// Normalizer2Impl *me=(Normalizer2Impl *)context;68// uprv_memcpy(me->dataVersion, pInfo->dataVersion, 4);69return true;70} else {71return false;72}73}7475void76LoadedNormalizer2Impl::load(const char *packageName, const char *name, UErrorCode &errorCode) {77if(U_FAILURE(errorCode)) {78return;79}80memory=udata_openChoice(packageName, "nrm", name, isAcceptable, this, &errorCode);81if(U_FAILURE(errorCode)) {82return;83}84const uint8_t *inBytes=(const uint8_t *)udata_getMemory(memory);85const int32_t *inIndexes=(const int32_t *)inBytes;86int32_t indexesLength=inIndexes[IX_NORM_TRIE_OFFSET]/4;87if(indexesLength<=IX_MIN_LCCC_CP) {88errorCode=U_INVALID_FORMAT_ERROR; // Not enough indexes.89return;90}9192int32_t offset=inIndexes[IX_NORM_TRIE_OFFSET];93int32_t nextOffset=inIndexes[IX_EXTRA_DATA_OFFSET];94ownedTrie=ucptrie_openFromBinary(UCPTRIE_TYPE_FAST, UCPTRIE_VALUE_BITS_16,95inBytes+offset, nextOffset-offset, NULL,96&errorCode);97if(U_FAILURE(errorCode)) {98return;99}100101offset=nextOffset;102nextOffset=inIndexes[IX_SMALL_FCD_OFFSET];103const uint16_t *inExtraData=(const uint16_t *)(inBytes+offset);104105// smallFCD: new in formatVersion 2106offset=nextOffset;107const uint8_t *inSmallFCD=inBytes+offset;108109init(inIndexes, ownedTrie, inExtraData, inSmallFCD);110}111112// instance cache ---------------------------------------------------------- ***113114Norm2AllModes *115Norm2AllModes::createInstance(const char *packageName,116const char *name,117UErrorCode &errorCode) {118if(U_FAILURE(errorCode)) {119return NULL;120}121LoadedNormalizer2Impl *impl=new LoadedNormalizer2Impl;122if(impl==NULL) {123errorCode=U_MEMORY_ALLOCATION_ERROR;124return NULL;125}126impl->load(packageName, name, errorCode);127return createInstance(impl, errorCode);128}129130U_CDECL_BEGIN131static UBool U_CALLCONV uprv_loaded_normalizer2_cleanup();132U_CDECL_END133134#if !NORM2_HARDCODE_NFC_DATA135static Norm2AllModes *nfcSingleton;136static icu::UInitOnce nfcInitOnce {};137#endif138139static Norm2AllModes *nfkcSingleton;140static icu::UInitOnce nfkcInitOnce {};141142static Norm2AllModes *nfkc_cfSingleton;143static icu::UInitOnce nfkc_cfInitOnce {};144145static UHashtable *cache=NULL;146147// UInitOnce singleton initialization function148static void U_CALLCONV initSingletons(const char *what, UErrorCode &errorCode) {149#if !NORM2_HARDCODE_NFC_DATA150if (uprv_strcmp(what, "nfc") == 0) {151nfcSingleton = Norm2AllModes::createInstance(NULL, "nfc", errorCode);152} else153#endif154if (uprv_strcmp(what, "nfkc") == 0) {155nfkcSingleton = Norm2AllModes::createInstance(NULL, "nfkc", errorCode);156} else if (uprv_strcmp(what, "nfkc_cf") == 0) {157nfkc_cfSingleton = Norm2AllModes::createInstance(NULL, "nfkc_cf", errorCode);158} else {159UPRV_UNREACHABLE_EXIT; // Unknown singleton160}161ucln_common_registerCleanup(UCLN_COMMON_LOADED_NORMALIZER2, uprv_loaded_normalizer2_cleanup);162}163164U_CDECL_BEGIN165166static void U_CALLCONV deleteNorm2AllModes(void *allModes) {167delete (Norm2AllModes *)allModes;168}169170static UBool U_CALLCONV uprv_loaded_normalizer2_cleanup() {171#if !NORM2_HARDCODE_NFC_DATA172delete nfcSingleton;173nfcSingleton = NULL;174nfcInitOnce.reset();175#endif176177delete nfkcSingleton;178nfkcSingleton = NULL;179nfkcInitOnce.reset();180181delete nfkc_cfSingleton;182nfkc_cfSingleton = NULL;183nfkc_cfInitOnce.reset();184185uhash_close(cache);186cache=NULL;187return true;188}189190U_CDECL_END191192#if !NORM2_HARDCODE_NFC_DATA193const Norm2AllModes *194Norm2AllModes::getNFCInstance(UErrorCode &errorCode) {195if(U_FAILURE(errorCode)) { return NULL; }196umtx_initOnce(nfcInitOnce, &initSingletons, "nfc", errorCode);197return nfcSingleton;198}199#endif200201const Norm2AllModes *202Norm2AllModes::getNFKCInstance(UErrorCode &errorCode) {203if(U_FAILURE(errorCode)) { return NULL; }204umtx_initOnce(nfkcInitOnce, &initSingletons, "nfkc", errorCode);205return nfkcSingleton;206}207208const Norm2AllModes *209Norm2AllModes::getNFKC_CFInstance(UErrorCode &errorCode) {210if(U_FAILURE(errorCode)) { return NULL; }211umtx_initOnce(nfkc_cfInitOnce, &initSingletons, "nfkc_cf", errorCode);212return nfkc_cfSingleton;213}214215#if !NORM2_HARDCODE_NFC_DATA216const Normalizer2 *217Normalizer2::getNFCInstance(UErrorCode &errorCode) {218const Norm2AllModes *allModes=Norm2AllModes::getNFCInstance(errorCode);219return allModes!=NULL ? &allModes->comp : NULL;220}221222const Normalizer2 *223Normalizer2::getNFDInstance(UErrorCode &errorCode) {224const Norm2AllModes *allModes=Norm2AllModes::getNFCInstance(errorCode);225return allModes!=NULL ? &allModes->decomp : NULL;226}227228const Normalizer2 *Normalizer2Factory::getFCDInstance(UErrorCode &errorCode) {229const Norm2AllModes *allModes=Norm2AllModes::getNFCInstance(errorCode);230return allModes!=NULL ? &allModes->fcd : NULL;231}232233const Normalizer2 *Normalizer2Factory::getFCCInstance(UErrorCode &errorCode) {234const Norm2AllModes *allModes=Norm2AllModes::getNFCInstance(errorCode);235return allModes!=NULL ? &allModes->fcc : NULL;236}237238const Normalizer2Impl *239Normalizer2Factory::getNFCImpl(UErrorCode &errorCode) {240const Norm2AllModes *allModes=Norm2AllModes::getNFCInstance(errorCode);241return allModes!=NULL ? allModes->impl : NULL;242}243#endif244245const Normalizer2 *246Normalizer2::getNFKCInstance(UErrorCode &errorCode) {247const Norm2AllModes *allModes=Norm2AllModes::getNFKCInstance(errorCode);248return allModes!=NULL ? &allModes->comp : NULL;249}250251const Normalizer2 *252Normalizer2::getNFKDInstance(UErrorCode &errorCode) {253const Norm2AllModes *allModes=Norm2AllModes::getNFKCInstance(errorCode);254return allModes!=NULL ? &allModes->decomp : NULL;255}256257const Normalizer2 *258Normalizer2::getNFKCCasefoldInstance(UErrorCode &errorCode) {259const Norm2AllModes *allModes=Norm2AllModes::getNFKC_CFInstance(errorCode);260return allModes!=NULL ? &allModes->comp : NULL;261}262263const Normalizer2 *264Normalizer2::getInstance(const char *packageName,265const char *name,266UNormalization2Mode mode,267UErrorCode &errorCode) {268if(U_FAILURE(errorCode)) {269return NULL;270}271if(name==NULL || *name==0) {272errorCode=U_ILLEGAL_ARGUMENT_ERROR;273return NULL;274}275const Norm2AllModes *allModes=NULL;276if(packageName==NULL) {277if(0==uprv_strcmp(name, "nfc")) {278allModes=Norm2AllModes::getNFCInstance(errorCode);279} else if(0==uprv_strcmp(name, "nfkc")) {280allModes=Norm2AllModes::getNFKCInstance(errorCode);281} else if(0==uprv_strcmp(name, "nfkc_cf")) {282allModes=Norm2AllModes::getNFKC_CFInstance(errorCode);283}284}285if(allModes==NULL && U_SUCCESS(errorCode)) {286{287Mutex lock;288if(cache!=NULL) {289allModes=(Norm2AllModes *)uhash_get(cache, name);290}291}292if(allModes==NULL) {293ucln_common_registerCleanup(UCLN_COMMON_LOADED_NORMALIZER2, uprv_loaded_normalizer2_cleanup);294LocalPointer<Norm2AllModes> localAllModes(295Norm2AllModes::createInstance(packageName, name, errorCode));296if(U_SUCCESS(errorCode)) {297Mutex lock;298if(cache==NULL) {299cache=uhash_open(uhash_hashChars, uhash_compareChars, NULL, &errorCode);300if(U_FAILURE(errorCode)) {301return NULL;302}303uhash_setKeyDeleter(cache, uprv_free);304uhash_setValueDeleter(cache, deleteNorm2AllModes);305}306void *temp=uhash_get(cache, name);307if(temp==NULL) {308int32_t keyLength= static_cast<int32_t>(uprv_strlen(name)+1);309char *nameCopy=(char *)uprv_malloc(keyLength);310if(nameCopy==NULL) {311errorCode=U_MEMORY_ALLOCATION_ERROR;312return NULL;313}314uprv_memcpy(nameCopy, name, keyLength);315allModes=localAllModes.getAlias();316uhash_put(cache, nameCopy, localAllModes.orphan(), &errorCode);317} else {318// race condition319allModes=(Norm2AllModes *)temp;320}321}322}323}324if(allModes!=NULL && U_SUCCESS(errorCode)) {325switch(mode) {326case UNORM2_COMPOSE:327return &allModes->comp;328case UNORM2_DECOMPOSE:329return &allModes->decomp;330case UNORM2_FCD:331return &allModes->fcd;332case UNORM2_COMPOSE_CONTIGUOUS:333return &allModes->fcc;334default:335break; // do nothing336}337}338return NULL;339}340341const Normalizer2 *342Normalizer2Factory::getInstance(UNormalizationMode mode, UErrorCode &errorCode) {343if(U_FAILURE(errorCode)) {344return NULL;345}346switch(mode) {347case UNORM_NFD:348return Normalizer2::getNFDInstance(errorCode);349case UNORM_NFKD:350return Normalizer2::getNFKDInstance(errorCode);351case UNORM_NFC:352return Normalizer2::getNFCInstance(errorCode);353case UNORM_NFKC:354return Normalizer2::getNFKCInstance(errorCode);355case UNORM_FCD:356return getFCDInstance(errorCode);357default: // UNORM_NONE358return getNoopInstance(errorCode);359}360}361362const Normalizer2Impl *363Normalizer2Factory::getNFKCImpl(UErrorCode &errorCode) {364const Norm2AllModes *allModes=Norm2AllModes::getNFKCInstance(errorCode);365return allModes!=NULL ? allModes->impl : NULL;366}367368const Normalizer2Impl *369Normalizer2Factory::getNFKC_CFImpl(UErrorCode &errorCode) {370const Norm2AllModes *allModes=Norm2AllModes::getNFKC_CFInstance(errorCode);371return allModes!=NULL ? allModes->impl : NULL;372}373374U_NAMESPACE_END375376// C API ------------------------------------------------------------------- ***377378U_NAMESPACE_USE379380U_CAPI const UNormalizer2 * U_EXPORT2381unorm2_getNFKCInstance(UErrorCode *pErrorCode) {382return (const UNormalizer2 *)Normalizer2::getNFKCInstance(*pErrorCode);383}384385U_CAPI const UNormalizer2 * U_EXPORT2386unorm2_getNFKDInstance(UErrorCode *pErrorCode) {387return (const UNormalizer2 *)Normalizer2::getNFKDInstance(*pErrorCode);388}389390U_CAPI const UNormalizer2 * U_EXPORT2391unorm2_getNFKCCasefoldInstance(UErrorCode *pErrorCode) {392return (const UNormalizer2 *)Normalizer2::getNFKCCasefoldInstance(*pErrorCode);393}394395U_CAPI const UNormalizer2 * U_EXPORT2396unorm2_getInstance(const char *packageName,397const char *name,398UNormalization2Mode mode,399UErrorCode *pErrorCode) {400return (const UNormalizer2 *)Normalizer2::getInstance(packageName, name, mode, *pErrorCode);401}402403U_CFUNC UNormalizationCheckResult404unorm_getQuickCheck(UChar32 c, UNormalizationMode mode) {405if(mode<=UNORM_NONE || UNORM_FCD<=mode) {406return UNORM_YES;407}408UErrorCode errorCode=U_ZERO_ERROR;409const Normalizer2 *norm2=Normalizer2Factory::getInstance(mode, errorCode);410if(U_SUCCESS(errorCode)) {411return ((const Normalizer2WithImpl *)norm2)->getQuickCheck(c);412} else {413return UNORM_MAYBE;414}415}416417#endif // !UCONFIG_NO_NORMALIZATION418419420