diff options
Diffstat (limited to 'deps/node/deps/icu-small/source/common/ucnv_bld.cpp')
-rw-r--r-- | deps/node/deps/icu-small/source/common/ucnv_bld.cpp | 1689 |
1 files changed, 0 insertions, 1689 deletions
diff --git a/deps/node/deps/icu-small/source/common/ucnv_bld.cpp b/deps/node/deps/icu-small/source/common/ucnv_bld.cpp deleted file mode 100644 index 1a1625d6..00000000 --- a/deps/node/deps/icu-small/source/common/ucnv_bld.cpp +++ /dev/null @@ -1,1689 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* - ******************************************************************** - * COPYRIGHT: - * Copyright (c) 1996-2016, International Business Machines Corporation and - * others. All Rights Reserved. - ******************************************************************** - * - * ucnv_bld.cpp: - * - * Defines functions that are used in the creation/initialization/deletion - * of converters and related structures. - * uses uconv_io.h routines to access disk information - * is used by ucnv.h to implement public API create/delete/flushCache routines - * Modification History: - * - * Date Name Description - * - * 06/20/2000 helena OS/400 port changes; mostly typecast. - * 06/29/2000 helena Major rewrite of the callback interface. -*/ - -#include "unicode/utypes.h" - -#if !UCONFIG_NO_CONVERSION - -#include "unicode/putil.h" -#include "unicode/udata.h" -#include "unicode/ucnv.h" -#include "unicode/uloc.h" -#include "mutex.h" -#include "putilimp.h" -#include "uassert.h" -#include "utracimp.h" -#include "ucnv_io.h" -#include "ucnv_bld.h" -#include "ucnvmbcs.h" -#include "ucnv_ext.h" -#include "ucnv_cnv.h" -#include "ucnv_imp.h" -#include "uhash.h" -#include "umutex.h" -#include "cstring.h" -#include "cmemory.h" -#include "ucln_cmn.h" -#include "ustr_cnv.h" - - -#if 0 -#include <stdio.h> -extern void UCNV_DEBUG_LOG(char *what, char *who, void *p, int l); -#define UCNV_DEBUG_LOG(x,y,z) UCNV_DEBUG_LOG(x,y,z,__LINE__) -#else -# define UCNV_DEBUG_LOG(x,y,z) -#endif - -static const UConverterSharedData * const -converterData[UCNV_NUMBER_OF_SUPPORTED_CONVERTER_TYPES]={ - NULL, NULL, - -#if UCONFIG_NO_LEGACY_CONVERSION - NULL, -#else - &_MBCSData, -#endif - - &_Latin1Data, - &_UTF8Data, &_UTF16BEData, &_UTF16LEData, -#if UCONFIG_ONLY_HTML_CONVERSION - NULL, NULL, -#else - &_UTF32BEData, &_UTF32LEData, -#endif - NULL, - -#if UCONFIG_NO_LEGACY_CONVERSION - NULL, -#else - &_ISO2022Data, -#endif - -#if UCONFIG_NO_LEGACY_CONVERSION || UCONFIG_ONLY_HTML_CONVERSION - NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, - NULL, -#else - &_LMBCSData1,&_LMBCSData2, &_LMBCSData3, &_LMBCSData4, &_LMBCSData5, &_LMBCSData6, - &_LMBCSData8,&_LMBCSData11,&_LMBCSData16,&_LMBCSData17,&_LMBCSData18,&_LMBCSData19, - &_HZData, -#endif - -#if UCONFIG_ONLY_HTML_CONVERSION - NULL, -#else - &_SCSUData, -#endif - - -#if UCONFIG_NO_LEGACY_CONVERSION || UCONFIG_ONLY_HTML_CONVERSION - NULL, -#else - &_ISCIIData, -#endif - - &_ASCIIData, -#if UCONFIG_ONLY_HTML_CONVERSION - NULL, NULL, &_UTF16Data, NULL, NULL, NULL, -#else - &_UTF7Data, &_Bocu1Data, &_UTF16Data, &_UTF32Data, &_CESU8Data, &_IMAPData, -#endif - -#if UCONFIG_NO_LEGACY_CONVERSION || UCONFIG_ONLY_HTML_CONVERSION - NULL, -#else - &_CompoundTextData -#endif -}; - -/* Please keep this in binary sorted order for getAlgorithmicTypeFromName. - Also the name should be in lower case and all spaces, dashes and underscores - removed -*/ -static struct { - const char *name; - const UConverterType type; -} const cnvNameType[] = { -#if !UCONFIG_ONLY_HTML_CONVERSION - { "bocu1", UCNV_BOCU1 }, - { "cesu8", UCNV_CESU8 }, -#endif -#if !UCONFIG_NO_LEGACY_CONVERSION && !UCONFIG_ONLY_HTML_CONVERSION - { "hz",UCNV_HZ }, -#endif -#if !UCONFIG_ONLY_HTML_CONVERSION - { "imapmailboxname", UCNV_IMAP_MAILBOX }, -#endif -#if !UCONFIG_NO_LEGACY_CONVERSION && !UCONFIG_ONLY_HTML_CONVERSION - { "iscii", UCNV_ISCII }, -#endif -#if !UCONFIG_NO_LEGACY_CONVERSION - { "iso2022", UCNV_ISO_2022 }, -#endif - { "iso88591", UCNV_LATIN_1 }, -#if !UCONFIG_NO_LEGACY_CONVERSION && !UCONFIG_ONLY_HTML_CONVERSION - { "lmbcs1", UCNV_LMBCS_1 }, - { "lmbcs11",UCNV_LMBCS_11 }, - { "lmbcs16",UCNV_LMBCS_16 }, - { "lmbcs17",UCNV_LMBCS_17 }, - { "lmbcs18",UCNV_LMBCS_18 }, - { "lmbcs19",UCNV_LMBCS_19 }, - { "lmbcs2", UCNV_LMBCS_2 }, - { "lmbcs3", UCNV_LMBCS_3 }, - { "lmbcs4", UCNV_LMBCS_4 }, - { "lmbcs5", UCNV_LMBCS_5 }, - { "lmbcs6", UCNV_LMBCS_6 }, - { "lmbcs8", UCNV_LMBCS_8 }, -#endif -#if !UCONFIG_ONLY_HTML_CONVERSION - { "scsu", UCNV_SCSU }, -#endif - { "usascii", UCNV_US_ASCII }, - { "utf16", UCNV_UTF16 }, - { "utf16be", UCNV_UTF16_BigEndian }, - { "utf16le", UCNV_UTF16_LittleEndian }, -#if U_IS_BIG_ENDIAN - { "utf16oppositeendian", UCNV_UTF16_LittleEndian }, - { "utf16platformendian", UCNV_UTF16_BigEndian }, -#else - { "utf16oppositeendian", UCNV_UTF16_BigEndian}, - { "utf16platformendian", UCNV_UTF16_LittleEndian }, -#endif -#if !UCONFIG_ONLY_HTML_CONVERSION - { "utf32", UCNV_UTF32 }, - { "utf32be", UCNV_UTF32_BigEndian }, - { "utf32le", UCNV_UTF32_LittleEndian }, -#if U_IS_BIG_ENDIAN - { "utf32oppositeendian", UCNV_UTF32_LittleEndian }, - { "utf32platformendian", UCNV_UTF32_BigEndian }, -#else - { "utf32oppositeendian", UCNV_UTF32_BigEndian }, - { "utf32platformendian", UCNV_UTF32_LittleEndian }, -#endif -#endif -#if !UCONFIG_ONLY_HTML_CONVERSION - { "utf7", UCNV_UTF7 }, -#endif - { "utf8", UCNV_UTF8 }, -#if !UCONFIG_ONLY_HTML_CONVERSION - { "x11compoundtext", UCNV_COMPOUND_TEXT} -#endif -}; - - -/*initializes some global variables */ -static UHashtable *SHARED_DATA_HASHTABLE = NULL; -static UMutex cnvCacheMutex = U_MUTEX_INITIALIZER; /* Mutex for synchronizing cnv cache access. */ - /* Note: the global mutex is used for */ - /* reference count updates. */ - -static const char **gAvailableConverters = NULL; -static uint16_t gAvailableConverterCount = 0; -static icu::UInitOnce gAvailableConvertersInitOnce = U_INITONCE_INITIALIZER; - -#if !U_CHARSET_IS_UTF8 - -/* This contains the resolved converter name. So no further alias lookup is needed again. */ -static char gDefaultConverterNameBuffer[UCNV_MAX_CONVERTER_NAME_LENGTH + 1]; /* +1 for NULL */ -static const char *gDefaultConverterName = NULL; - -/* -If the default converter is an algorithmic converter, this is the cached value. -We don't cache a full UConverter and clone it because ucnv_clone doesn't have -less overhead than an algorithmic open. We don't cache non-algorithmic converters -because ucnv_flushCache must be able to unload the default converter and its table. -*/ -static const UConverterSharedData *gDefaultAlgorithmicSharedData = NULL; - -/* Does gDefaultConverterName have a converter option and require extra parsing? */ -static UBool gDefaultConverterContainsOption; - -#endif /* !U_CHARSET_IS_UTF8 */ - -static const char DATA_TYPE[] = "cnv"; - -/* ucnv_flushAvailableConverterCache. This is only called from ucnv_cleanup(). - * If it is ever to be called from elsewhere, synchronization - * will need to be considered. - */ -static void -ucnv_flushAvailableConverterCache() { - gAvailableConverterCount = 0; - if (gAvailableConverters) { - uprv_free((char **)gAvailableConverters); - gAvailableConverters = NULL; - } - gAvailableConvertersInitOnce.reset(); -} - -/* ucnv_cleanup - delete all storage held by the converter cache, except any */ -/* in use by open converters. */ -/* Not thread safe. */ -/* Not supported API. */ -static UBool U_CALLCONV ucnv_cleanup(void) { - ucnv_flushCache(); - if (SHARED_DATA_HASHTABLE != NULL && uhash_count(SHARED_DATA_HASHTABLE) == 0) { - uhash_close(SHARED_DATA_HASHTABLE); - SHARED_DATA_HASHTABLE = NULL; - } - - /* Isn't called from flushCache because other threads may have preexisting references to the table. */ - ucnv_flushAvailableConverterCache(); - -#if !U_CHARSET_IS_UTF8 - gDefaultConverterName = NULL; - gDefaultConverterNameBuffer[0] = 0; - gDefaultConverterContainsOption = FALSE; - gDefaultAlgorithmicSharedData = NULL; -#endif - - return (SHARED_DATA_HASHTABLE == NULL); -} - -U_CAPI void U_EXPORT2 -ucnv_enableCleanup() { - ucln_common_registerCleanup(UCLN_COMMON_UCNV, ucnv_cleanup); -} - -static UBool U_CALLCONV -isCnvAcceptable(void * /*context*/, - const char * /*type*/, const char * /*name*/, - const UDataInfo *pInfo) { - return (UBool)( - pInfo->size>=20 && - pInfo->isBigEndian==U_IS_BIG_ENDIAN && - pInfo->charsetFamily==U_CHARSET_FAMILY && - pInfo->sizeofUChar==U_SIZEOF_UCHAR && - pInfo->dataFormat[0]==0x63 && /* dataFormat="cnvt" */ - pInfo->dataFormat[1]==0x6e && - pInfo->dataFormat[2]==0x76 && - pInfo->dataFormat[3]==0x74 && - pInfo->formatVersion[0]==6); /* Everything will be version 6 */ -} - -/** - * Un flatten shared data from a UDATA.. - */ -static UConverterSharedData* -ucnv_data_unFlattenClone(UConverterLoadArgs *pArgs, UDataMemory *pData, UErrorCode *status) -{ - /* UDataInfo info; -- necessary only if some converters have different formatVersion */ - const uint8_t *raw = (const uint8_t *)udata_getMemory(pData); - const UConverterStaticData *source = (const UConverterStaticData *) raw; - UConverterSharedData *data; - UConverterType type = (UConverterType)source->conversionType; - - if(U_FAILURE(*status)) - return NULL; - - if( (uint16_t)type >= UCNV_NUMBER_OF_SUPPORTED_CONVERTER_TYPES || - converterData[type] == NULL || - !converterData[type]->isReferenceCounted || - converterData[type]->referenceCounter != 1 || - source->structSize != sizeof(UConverterStaticData)) - { - *status = U_INVALID_TABLE_FORMAT; - return NULL; - } - - data = (UConverterSharedData *)uprv_malloc(sizeof(UConverterSharedData)); - if(data == NULL) { - *status = U_MEMORY_ALLOCATION_ERROR; - return NULL; - } - - /* copy initial values from the static structure for this type */ - uprv_memcpy(data, converterData[type], sizeof(UConverterSharedData)); - - data->staticData = source; - - data->sharedDataCached = FALSE; - - /* fill in fields from the loaded data */ - data->dataMemory = (void*)pData; /* for future use */ - - if(data->impl->load != NULL) { - data->impl->load(data, pArgs, raw + source->structSize, status); - if(U_FAILURE(*status)) { - uprv_free(data); - return NULL; - } - } - return data; -} - -/*Takes an alias name gets an actual converter file name - *goes to disk and opens it. - *allocates the memory and returns a new UConverter object - */ -static UConverterSharedData *createConverterFromFile(UConverterLoadArgs *pArgs, UErrorCode * err) -{ - UDataMemory *data; - UConverterSharedData *sharedData; - - UTRACE_ENTRY_OC(UTRACE_UCNV_LOAD); - - if (U_FAILURE (*err)) { - UTRACE_EXIT_STATUS(*err); - return NULL; - } - - UTRACE_DATA2(UTRACE_OPEN_CLOSE, "load converter %s from package %s", pArgs->name, pArgs->pkg); - - data = udata_openChoice(pArgs->pkg, DATA_TYPE, pArgs->name, isCnvAcceptable, NULL, err); - if(U_FAILURE(*err)) - { - UTRACE_EXIT_STATUS(*err); - return NULL; - } - - sharedData = ucnv_data_unFlattenClone(pArgs, data, err); - if(U_FAILURE(*err)) - { - udata_close(data); - UTRACE_EXIT_STATUS(*err); - return NULL; - } - - /* - * TODO Store pkg in a field in the shared data so that delta-only converters - * can load base converters from the same package. - * If the pkg name is longer than the field, then either do not load the converter - * in the first place, or just set the pkg field to "". - */ - - UTRACE_EXIT_PTR_STATUS(sharedData, *err); - return sharedData; -} - -/*returns a converter type from a string - */ -static const UConverterSharedData * -getAlgorithmicTypeFromName(const char *realName) -{ - uint32_t mid, start, limit; - uint32_t lastMid; - int result; - char strippedName[UCNV_MAX_CONVERTER_NAME_LENGTH]; - - /* Lower case and remove ignoreable characters. */ - ucnv_io_stripForCompare(strippedName, realName); - - /* do a binary search for the alias */ - start = 0; - limit = UPRV_LENGTHOF(cnvNameType); - mid = limit; - lastMid = UINT32_MAX; - - for (;;) { - mid = (uint32_t)((start + limit) / 2); - if (lastMid == mid) { /* Have we moved? */ - break; /* We haven't moved, and it wasn't found. */ - } - lastMid = mid; - result = uprv_strcmp(strippedName, cnvNameType[mid].name); - - if (result < 0) { - limit = mid; - } else if (result > 0) { - start = mid; - } else { - return converterData[cnvNameType[mid].type]; - } - } - - return NULL; -} - -/* -* Based on the number of known converters, this determines how many times larger -* the shared data hash table should be. When on small platforms, or just a couple -* of converters are used, this number should be 2. When memory is plentiful, or -* when ucnv_countAvailable is ever used with a lot of available converters, -* this should be 4. -* Larger numbers reduce the number of hash collisions, but use more memory. -*/ -#define UCNV_CACHE_LOAD_FACTOR 2 - -/* Puts the shared data in the static hashtable SHARED_DATA_HASHTABLE */ -/* Will always be called with the cnvCacheMutex alrady being held */ -/* by the calling function. */ -/* Stores the shared data in the SHARED_DATA_HASHTABLE - * @param data The shared data - */ -static void -ucnv_shareConverterData(UConverterSharedData * data) -{ - UErrorCode err = U_ZERO_ERROR; - /*Lazy evaluates the Hashtable itself */ - /*void *sanity = NULL;*/ - - if (SHARED_DATA_HASHTABLE == NULL) - { - SHARED_DATA_HASHTABLE = uhash_openSize(uhash_hashChars, uhash_compareChars, NULL, - ucnv_io_countKnownConverters(&err)*UCNV_CACHE_LOAD_FACTOR, - &err); - ucnv_enableCleanup(); - - if (U_FAILURE(err)) - return; - } - - /* ### check to see if the element is not already there! */ - - /* - sanity = ucnv_getSharedConverterData (data->staticData->name); - if(sanity != NULL) - { - UCNV_DEBUG_LOG("put:overwrite!",data->staticData->name,sanity); - } - UCNV_DEBUG_LOG("put:chk",data->staticData->name,sanity); - */ - - /* Mark it shared */ - data->sharedDataCached = TRUE; - - uhash_put(SHARED_DATA_HASHTABLE, - (void*) data->staticData->name, /* Okay to cast away const as long as - keyDeleter == NULL */ - data, - &err); - UCNV_DEBUG_LOG("put", data->staticData->name,data); - -} - -/* Look up a converter name in the shared data cache. */ -/* cnvCacheMutex must be held by the caller to protect the hash table. */ -/* gets the shared data from the SHARED_DATA_HASHTABLE (might return NULL if it isn't there) - * @param name The name of the shared data - * @return the shared data from the SHARED_DATA_HASHTABLE - */ -static UConverterSharedData * -ucnv_getSharedConverterData(const char *name) -{ - /*special case when no Table has yet been created we return NULL */ - if (SHARED_DATA_HASHTABLE == NULL) - { - return NULL; - } - else - { - UConverterSharedData *rc; - - rc = (UConverterSharedData*)uhash_get(SHARED_DATA_HASHTABLE, name); - UCNV_DEBUG_LOG("get",name,rc); - return rc; - } -} - -/*frees the string of memory blocks associates with a sharedConverter - *if and only if the referenceCounter == 0 - */ -/* Deletes (frees) the Shared data it's passed. first it checks the referenceCounter to - * see if anyone is using it, if not it frees all the memory stemming from sharedConverterData and - * returns TRUE, - * otherwise returns FALSE - * @param sharedConverterData The shared data - * @return if not it frees all the memory stemming from sharedConverterData and - * returns TRUE, otherwise returns FALSE - */ -static UBool -ucnv_deleteSharedConverterData(UConverterSharedData * deadSharedData) -{ - UTRACE_ENTRY_OC(UTRACE_UCNV_UNLOAD); - UTRACE_DATA2(UTRACE_OPEN_CLOSE, "unload converter %s shared data %p", deadSharedData->staticData->name, deadSharedData); - - if (deadSharedData->referenceCounter > 0) { - UTRACE_EXIT_VALUE((int32_t)FALSE); - return FALSE; - } - - if (deadSharedData->impl->unload != NULL) { - deadSharedData->impl->unload(deadSharedData); - } - - if(deadSharedData->dataMemory != NULL) - { - UDataMemory *data = (UDataMemory*)deadSharedData->dataMemory; - udata_close(data); - } - - uprv_free(deadSharedData); - - UTRACE_EXIT_VALUE((int32_t)TRUE); - return TRUE; -} - -/** - * Load a non-algorithmic converter. - * If pkg==NULL, then this function must be called inside umtx_lock(&cnvCacheMutex). - */ -UConverterSharedData * -ucnv_load(UConverterLoadArgs *pArgs, UErrorCode *err) { - UConverterSharedData *mySharedConverterData; - - if(err == NULL || U_FAILURE(*err)) { - return NULL; - } - - if(pArgs->pkg != NULL && *pArgs->pkg != 0) { - /* application-provided converters are not currently cached */ - return createConverterFromFile(pArgs, err); - } - - mySharedConverterData = ucnv_getSharedConverterData(pArgs->name); - if (mySharedConverterData == NULL) - { - /*Not cached, we need to stream it in from file */ - mySharedConverterData = createConverterFromFile(pArgs, err); - if (U_FAILURE (*err) || (mySharedConverterData == NULL)) - { - return NULL; - } - else if (!pArgs->onlyTestIsLoadable) - { - /* share it with other library clients */ - ucnv_shareConverterData(mySharedConverterData); - } - } - else - { - /* The data for this converter was already in the cache. */ - /* Update the reference counter on the shared data: one more client */ - mySharedConverterData->referenceCounter++; - } - - return mySharedConverterData; -} - -/** - * Unload a non-algorithmic converter. - * It must be sharedData->isReferenceCounted - * and this function must be called inside umtx_lock(&cnvCacheMutex). - */ -U_CAPI void -ucnv_unload(UConverterSharedData *sharedData) { - if(sharedData != NULL) { - if (sharedData->referenceCounter > 0) { - sharedData->referenceCounter--; - } - - if((sharedData->referenceCounter <= 0)&&(sharedData->sharedDataCached == FALSE)) { - ucnv_deleteSharedConverterData(sharedData); - } - } -} - -U_CFUNC void -ucnv_unloadSharedDataIfReady(UConverterSharedData *sharedData) -{ - if(sharedData != NULL && sharedData->isReferenceCounted) { - umtx_lock(&cnvCacheMutex); - ucnv_unload(sharedData); - umtx_unlock(&cnvCacheMutex); - } -} - -U_CFUNC void -ucnv_incrementRefCount(UConverterSharedData *sharedData) -{ - if(sharedData != NULL && sharedData->isReferenceCounted) { - umtx_lock(&cnvCacheMutex); - sharedData->referenceCounter++; - umtx_unlock(&cnvCacheMutex); - } -} - -/* - * *pPieces must be initialized. - * The name without options will be copied to pPieces->cnvName. - * The locale and options will be copied to pPieces only if present in inName, - * otherwise the existing values in pPieces remain. - * *pArgs will be set to the pPieces values. - */ -static void -parseConverterOptions(const char *inName, - UConverterNamePieces *pPieces, - UConverterLoadArgs *pArgs, - UErrorCode *err) -{ - char *cnvName = pPieces->cnvName; - char c; - int32_t len = 0; - - pArgs->name=inName; - pArgs->locale=pPieces->locale; - pArgs->options=pPieces->options; - - /* copy the converter name itself to cnvName */ - while((c=*inName)!=0 && c!=UCNV_OPTION_SEP_CHAR) { - if (++len>=UCNV_MAX_CONVERTER_NAME_LENGTH) { - *err = U_ILLEGAL_ARGUMENT_ERROR; /* bad name */ - pPieces->cnvName[0]=0; - return; - } - *cnvName++=c; - inName++; - } - *cnvName=0; - pArgs->name=pPieces->cnvName; - - /* parse options. No more name copying should occur. */ - while((c=*inName)!=0) { - if(c==UCNV_OPTION_SEP_CHAR) { - ++inName; - } - - /* inName is behind an option separator */ - if(uprv_strncmp(inName, "locale=", 7)==0) { - /* do not modify locale itself in case we have multiple locale options */ - char *dest=pPieces->locale; - - /* copy the locale option value */ - inName+=7; - len=0; - while((c=*inName)!=0 && c!=UCNV_OPTION_SEP_CHAR) { - ++inName; - - if(++len>=ULOC_FULLNAME_CAPACITY) { - *err=U_ILLEGAL_ARGUMENT_ERROR; /* bad name */ - pPieces->locale[0]=0; - return; - } - - *dest++=c; - } - *dest=0; - } else if(uprv_strncmp(inName, "version=", 8)==0) { - /* copy the version option value into bits 3..0 of pPieces->options */ - inName+=8; - c=*inName; - if(c==0) { - pArgs->options=(pPieces->options&=~UCNV_OPTION_VERSION); - return; - } else if((uint8_t)(c-'0')<10) { - pArgs->options=pPieces->options=(pPieces->options&~UCNV_OPTION_VERSION)|(uint32_t)(c-'0'); - ++inName; - } - } else if(uprv_strncmp(inName, "swaplfnl", 8)==0) { - inName+=8; - pArgs->options=(pPieces->options|=UCNV_OPTION_SWAP_LFNL); - /* add processing for new options here with another } else if(uprv_strncmp(inName, "option-name=", XX)==0) { */ - } else { - /* ignore any other options until we define some */ - while(((c = *inName++) != 0) && (c != UCNV_OPTION_SEP_CHAR)) { - } - if(c==0) { - return; - } - } - } -} - -/*Logic determines if the converter is Algorithmic AND/OR cached - *depending on that: - * -we either go to get data from disk and cache it (Data=TRUE, Cached=False) - * -Get it from a Hashtable (Data=X, Cached=TRUE) - * -Call dataConverter initializer (Data=TRUE, Cached=TRUE) - * -Call AlgorithmicConverter initializer (Data=FALSE, Cached=TRUE) - */ -U_CFUNC UConverterSharedData * -ucnv_loadSharedData(const char *converterName, - UConverterNamePieces *pPieces, - UConverterLoadArgs *pArgs, - UErrorCode * err) { - UConverterNamePieces stackPieces; - UConverterLoadArgs stackArgs; - UConverterSharedData *mySharedConverterData = NULL; - UErrorCode internalErrorCode = U_ZERO_ERROR; - UBool mayContainOption = TRUE; - UBool checkForAlgorithmic = TRUE; - - if (U_FAILURE (*err)) { - return NULL; - } - - if(pPieces == NULL) { - if(pArgs != NULL) { - /* - * Bad: We may set pArgs pointers to stackPieces fields - * which will be invalid after this function returns. - */ - *err = U_INTERNAL_PROGRAM_ERROR; - return NULL; - } - pPieces = &stackPieces; - } - if(pArgs == NULL) { - uprv_memset(&stackArgs, 0, sizeof(stackArgs)); - stackArgs.size = (int32_t)sizeof(stackArgs); - pArgs = &stackArgs; - } - - pPieces->cnvName[0] = 0; - pPieces->locale[0] = 0; - pPieces->options = 0; - - pArgs->name = converterName; - pArgs->locale = pPieces->locale; - pArgs->options = pPieces->options; - - /* In case "name" is NULL we want to open the default converter. */ - if (converterName == NULL) { -#if U_CHARSET_IS_UTF8 - pArgs->name = "UTF-8"; - return (UConverterSharedData *)converterData[UCNV_UTF8]; -#else - /* Call ucnv_getDefaultName first to query the name from the OS. */ - pArgs->name = ucnv_getDefaultName(); - if (pArgs->name == NULL) { - *err = U_MISSING_RESOURCE_ERROR; - return NULL; - } - mySharedConverterData = (UConverterSharedData *)gDefaultAlgorithmicSharedData; - checkForAlgorithmic = FALSE; - mayContainOption = gDefaultConverterContainsOption; - /* the default converter name is already canonical */ -#endif - } - else if(UCNV_FAST_IS_UTF8(converterName)) { - /* fastpath for UTF-8 */ - pArgs->name = "UTF-8"; - return (UConverterSharedData *)converterData[UCNV_UTF8]; - } - else { - /* separate the converter name from the options */ - parseConverterOptions(converterName, pPieces, pArgs, err); - if (U_FAILURE(*err)) { - /* Very bad name used. */ - return NULL; - } - - /* get the canonical converter name */ - pArgs->name = ucnv_io_getConverterName(pArgs->name, &mayContainOption, &internalErrorCode); - if (U_FAILURE(internalErrorCode) || pArgs->name == NULL) { - /* - * set the input name in case the converter was added - * without updating the alias table, or when there is no alias table - */ - pArgs->name = pPieces->cnvName; - } else if (internalErrorCode == U_AMBIGUOUS_ALIAS_WARNING) { - *err = U_AMBIGUOUS_ALIAS_WARNING; - } - } - - /* separate the converter name from the options */ - if(mayContainOption && pArgs->name != pPieces->cnvName) { - parseConverterOptions(pArgs->name, pPieces, pArgs, err); - } - - /* get the shared data for an algorithmic converter, if it is one */ - if (checkForAlgorithmic) { - mySharedConverterData = (UConverterSharedData *)getAlgorithmicTypeFromName(pArgs->name); - } - if (mySharedConverterData == NULL) - { - /* it is a data-based converter, get its shared data. */ - /* Hold the cnvCacheMutex through the whole process of checking the */ - /* converter data cache, and adding new entries to the cache */ - /* to prevent other threads from modifying the cache during the */ - /* process. */ - pArgs->nestedLoads=1; - pArgs->pkg=NULL; - - umtx_lock(&cnvCacheMutex); - mySharedConverterData = ucnv_load(pArgs, err); - umtx_unlock(&cnvCacheMutex); - if (U_FAILURE (*err) || (mySharedConverterData == NULL)) - { - return NULL; - } - } - - return mySharedConverterData; -} - -U_CAPI UConverter * -ucnv_createConverter(UConverter *myUConverter, const char *converterName, UErrorCode * err) -{ - UConverterNamePieces stackPieces; - UConverterLoadArgs stackArgs=UCNV_LOAD_ARGS_INITIALIZER; - UConverterSharedData *mySharedConverterData; - - UTRACE_ENTRY_OC(UTRACE_UCNV_OPEN); - - if(U_SUCCESS(*err)) { - UTRACE_DATA1(UTRACE_OPEN_CLOSE, "open converter %s", converterName); - - mySharedConverterData = ucnv_loadSharedData(converterName, &stackPieces, &stackArgs, err); - - myUConverter = ucnv_createConverterFromSharedData( - myUConverter, mySharedConverterData, - &stackArgs, - err); - - if(U_SUCCESS(*err)) { - UTRACE_EXIT_PTR_STATUS(myUConverter, *err); - return myUConverter; - } - } - - /* exit with error */ - UTRACE_EXIT_STATUS(*err); - return NULL; -} - -U_CFUNC UBool -ucnv_canCreateConverter(const char *converterName, UErrorCode *err) { - UConverter myUConverter; - UConverterNamePieces stackPieces; - UConverterLoadArgs stackArgs=UCNV_LOAD_ARGS_INITIALIZER; - UConverterSharedData *mySharedConverterData; - - UTRACE_ENTRY_OC(UTRACE_UCNV_OPEN); - - if(U_SUCCESS(*err)) { - UTRACE_DATA1(UTRACE_OPEN_CLOSE, "test if can open converter %s", converterName); - - stackArgs.onlyTestIsLoadable=TRUE; - mySharedConverterData = ucnv_loadSharedData(converterName, &stackPieces, &stackArgs, err); - ucnv_createConverterFromSharedData( - &myUConverter, mySharedConverterData, - &stackArgs, - err); - ucnv_unloadSharedDataIfReady(mySharedConverterData); - } - - UTRACE_EXIT_STATUS(*err); - return U_SUCCESS(*err); -} - -UConverter * -ucnv_createAlgorithmicConverter(UConverter *myUConverter, - UConverterType type, - const char *locale, uint32_t options, - UErrorCode *err) { - UConverter *cnv; - const UConverterSharedData *sharedData; - UConverterLoadArgs stackArgs=UCNV_LOAD_ARGS_INITIALIZER; - - UTRACE_ENTRY_OC(UTRACE_UCNV_OPEN_ALGORITHMIC); - UTRACE_DATA1(UTRACE_OPEN_CLOSE, "open algorithmic converter type %d", (int32_t)type); - - if(type<0 || UCNV_NUMBER_OF_SUPPORTED_CONVERTER_TYPES<=type) { - *err = U_ILLEGAL_ARGUMENT_ERROR; - UTRACE_EXIT_STATUS(U_ILLEGAL_ARGUMENT_ERROR); - return NULL; - } - - sharedData = converterData[type]; - if(sharedData == NULL || sharedData->isReferenceCounted) { - /* not a valid type, or not an algorithmic converter */ - *err = U_ILLEGAL_ARGUMENT_ERROR; - UTRACE_EXIT_STATUS(U_ILLEGAL_ARGUMENT_ERROR); - return NULL; - } - - stackArgs.name = ""; - stackArgs.options = options; - stackArgs.locale=locale; - cnv = ucnv_createConverterFromSharedData( - myUConverter, (UConverterSharedData *)sharedData, - &stackArgs, err); - - UTRACE_EXIT_PTR_STATUS(cnv, *err); - return cnv; -} - -U_CFUNC UConverter* -ucnv_createConverterFromPackage(const char *packageName, const char *converterName, UErrorCode * err) -{ - UConverter *myUConverter; - UConverterSharedData *mySharedConverterData; - UConverterNamePieces stackPieces; - UConverterLoadArgs stackArgs=UCNV_LOAD_ARGS_INITIALIZER; - - UTRACE_ENTRY_OC(UTRACE_UCNV_OPEN_PACKAGE); - - if(U_FAILURE(*err)) { - UTRACE_EXIT_STATUS(*err); - return NULL; - } - - UTRACE_DATA2(UTRACE_OPEN_CLOSE, "open converter %s from package %s", converterName, packageName); - - /* first, get the options out of the converterName string */ - stackPieces.cnvName[0] = 0; - stackPieces.locale[0] = 0; - stackPieces.options = 0; - parseConverterOptions(converterName, &stackPieces, &stackArgs, err); - if (U_FAILURE(*err)) { - /* Very bad name used. */ - UTRACE_EXIT_STATUS(*err); - return NULL; - } - stackArgs.nestedLoads=1; - stackArgs.pkg=packageName; - - /* open the data, unflatten the shared structure */ - mySharedConverterData = createConverterFromFile(&stackArgs, err); - - if (U_FAILURE(*err)) { - UTRACE_EXIT_STATUS(*err); - return NULL; - } - - /* create the actual converter */ - myUConverter = ucnv_createConverterFromSharedData(NULL, mySharedConverterData, &stackArgs, err); - - if (U_FAILURE(*err)) { - ucnv_close(myUConverter); - UTRACE_EXIT_STATUS(*err); - return NULL; - } - - UTRACE_EXIT_PTR_STATUS(myUConverter, *err); - return myUConverter; -} - - -U_CFUNC UConverter* -ucnv_createConverterFromSharedData(UConverter *myUConverter, - UConverterSharedData *mySharedConverterData, - UConverterLoadArgs *pArgs, - UErrorCode *err) -{ - UBool isCopyLocal; - - if(U_FAILURE(*err)) { - ucnv_unloadSharedDataIfReady(mySharedConverterData); - return myUConverter; - } - if(myUConverter == NULL) - { - myUConverter = (UConverter *) uprv_malloc (sizeof (UConverter)); - if(myUConverter == NULL) - { - *err = U_MEMORY_ALLOCATION_ERROR; - ucnv_unloadSharedDataIfReady(mySharedConverterData); - return NULL; - } - isCopyLocal = FALSE; - } else { - isCopyLocal = TRUE; - } - - /* initialize the converter */ - uprv_memset(myUConverter, 0, sizeof(UConverter)); - myUConverter->isCopyLocal = isCopyLocal; - /*myUConverter->isExtraLocal = FALSE;*/ /* Set by the memset call */ - myUConverter->sharedData = mySharedConverterData; - myUConverter->options = pArgs->options; - if(!pArgs->onlyTestIsLoadable) { - myUConverter->preFromUFirstCP = U_SENTINEL; - myUConverter->fromCharErrorBehaviour = UCNV_TO_U_DEFAULT_CALLBACK; - myUConverter->fromUCharErrorBehaviour = UCNV_FROM_U_DEFAULT_CALLBACK; - myUConverter->toUnicodeStatus = mySharedConverterData->toUnicodeStatus; - myUConverter->maxBytesPerUChar = mySharedConverterData->staticData->maxBytesPerChar; - myUConverter->subChar1 = mySharedConverterData->staticData->subChar1; - myUConverter->subCharLen = mySharedConverterData->staticData->subCharLen; - myUConverter->subChars = (uint8_t *)myUConverter->subUChars; - uprv_memcpy(myUConverter->subChars, mySharedConverterData->staticData->subChar, myUConverter->subCharLen); - myUConverter->toUCallbackReason = UCNV_ILLEGAL; /* default reason to invoke (*fromCharErrorBehaviour) */ - } - - if(mySharedConverterData->impl->open != NULL) { - mySharedConverterData->impl->open(myUConverter, pArgs, err); - if(U_FAILURE(*err) && !pArgs->onlyTestIsLoadable) { - /* don't ucnv_close() if onlyTestIsLoadable because not fully initialized */ - ucnv_close(myUConverter); - return NULL; - } - } - - return myUConverter; -} - -/*Frees all shared immutable objects that aren't referred to (reference count = 0) - */ -U_CAPI int32_t U_EXPORT2 -ucnv_flushCache () -{ - UConverterSharedData *mySharedData = NULL; - int32_t pos; - int32_t tableDeletedNum = 0; - const UHashElement *e; - /*UErrorCode status = U_ILLEGAL_ARGUMENT_ERROR;*/ - int32_t i, remaining; - - UTRACE_ENTRY_OC(UTRACE_UCNV_FLUSH_CACHE); - - /* Close the default converter without creating a new one so that everything will be flushed. */ - u_flushDefaultConverter(); - - /*if shared data hasn't even been lazy evaluated yet - * return 0 - */ - if (SHARED_DATA_HASHTABLE == NULL) { - UTRACE_EXIT_VALUE((int32_t)0); - return 0; - } - - /*creates an enumeration to iterate through every element in the - * table - * - * Synchronization: holding cnvCacheMutex will prevent any other thread from - * accessing or modifying the hash table during the iteration. - * The reference count of an entry may be decremented by - * ucnv_close while the iteration is in process, but this is - * benign. It can't be incremented (in ucnv_createConverter()) - * because the sequence of looking up in the cache + incrementing - * is protected by cnvCacheMutex. - */ - umtx_lock(&cnvCacheMutex); - /* - * double loop: A delta/extension-only converter has a pointer to its base table's - * shared data; the first iteration of the outer loop may see the delta converter - * before the base converter, and unloading the delta converter may get the base - * converter's reference counter down to 0. - */ - i = 0; - do { - remaining = 0; - pos = UHASH_FIRST; - while ((e = uhash_nextElement (SHARED_DATA_HASHTABLE, &pos)) != NULL) - { - mySharedData = (UConverterSharedData *) e->value.pointer; - /*deletes only if reference counter == 0 */ - if (mySharedData->referenceCounter == 0) - { - tableDeletedNum++; - - UCNV_DEBUG_LOG("del",mySharedData->staticData->name,mySharedData); - - uhash_removeElement(SHARED_DATA_HASHTABLE, e); - mySharedData->sharedDataCached = FALSE; - ucnv_deleteSharedConverterData (mySharedData); - } else { - ++remaining; - } - } - } while(++i == 1 && remaining > 0); - umtx_unlock(&cnvCacheMutex); - - UTRACE_DATA1(UTRACE_INFO, "ucnv_flushCache() exits with %d converters remaining", remaining); - - UTRACE_EXIT_VALUE(tableDeletedNum); - return tableDeletedNum; -} - -/* available converters list --------------------------------------------------- */ - -static void U_CALLCONV initAvailableConvertersList(UErrorCode &errCode) { - U_ASSERT(gAvailableConverterCount == 0); - U_ASSERT(gAvailableConverters == NULL); - - ucnv_enableCleanup(); - UEnumeration *allConvEnum = ucnv_openAllNames(&errCode); - int32_t allConverterCount = uenum_count(allConvEnum, &errCode); - if (U_FAILURE(errCode)) { - return; - } - - /* We can't have more than "*converterTable" converters to open */ - gAvailableConverters = (const char **) uprv_malloc(allConverterCount * sizeof(char*)); - if (!gAvailableConverters) { - errCode = U_MEMORY_ALLOCATION_ERROR; - return; - } - - /* Open the default converter to make sure that it has first dibs in the hash table. */ - UErrorCode localStatus = U_ZERO_ERROR; - UConverter tempConverter; - ucnv_close(ucnv_createConverter(&tempConverter, NULL, &localStatus)); - - gAvailableConverterCount = 0; - - for (int32_t idx = 0; idx < allConverterCount; idx++) { - localStatus = U_ZERO_ERROR; - const char *converterName = uenum_next(allConvEnum, NULL, &localStatus); - if (ucnv_canCreateConverter(converterName, &localStatus)) { - gAvailableConverters[gAvailableConverterCount++] = converterName; - } - } - - uenum_close(allConvEnum); -} - - -static UBool haveAvailableConverterList(UErrorCode *pErrorCode) { - umtx_initOnce(gAvailableConvertersInitOnce, &initAvailableConvertersList, *pErrorCode); - return U_SUCCESS(*pErrorCode); -} - -U_CFUNC uint16_t -ucnv_bld_countAvailableConverters(UErrorCode *pErrorCode) { - if (haveAvailableConverterList(pErrorCode)) { - return gAvailableConverterCount; - } - return 0; -} - -U_CFUNC const char * -ucnv_bld_getAvailableConverter(uint16_t n, UErrorCode *pErrorCode) { - if (haveAvailableConverterList(pErrorCode)) { - if (n < gAvailableConverterCount) { - return gAvailableConverters[n]; - } - *pErrorCode = U_INDEX_OUTOFBOUNDS_ERROR; - } - return NULL; -} - -/* default converter name --------------------------------------------------- */ - -#if !U_CHARSET_IS_UTF8 -/* -Copy the canonical converter name. -ucnv_getDefaultName must be thread safe, which can call this function. - -ucnv_setDefaultName calls this function and it doesn't have to be -thread safe because there is no reliable/safe way to reset the -converter in use in all threads. If you did reset the converter, you -would not be sure that retrieving a default converter for one string -would be the same type of default converter for a successive string. -Since the name is a returned via ucnv_getDefaultName without copying, -you shouldn't be modifying or deleting the string from a separate thread. -*/ -static inline void -internalSetName(const char *name, UErrorCode *status) { - UConverterNamePieces stackPieces; - UConverterLoadArgs stackArgs=UCNV_LOAD_ARGS_INITIALIZER; - int32_t length=(int32_t)(uprv_strlen(name)); - UBool containsOption = (UBool)(uprv_strchr(name, UCNV_OPTION_SEP_CHAR) != NULL); - const UConverterSharedData *algorithmicSharedData; - - stackArgs.name = name; - if(containsOption) { - stackPieces.cnvName[0] = 0; - stackPieces.locale[0] = 0; - stackPieces.options = 0; - parseConverterOptions(name, &stackPieces, &stackArgs, status); - if(U_FAILURE(*status)) { - return; - } - } - algorithmicSharedData = getAlgorithmicTypeFromName(stackArgs.name); - - umtx_lock(&cnvCacheMutex); - - gDefaultAlgorithmicSharedData = algorithmicSharedData; - gDefaultConverterContainsOption = containsOption; - uprv_memcpy(gDefaultConverterNameBuffer, name, length); - gDefaultConverterNameBuffer[length]=0; - - /* gDefaultConverterName MUST be the last global var set by this function. */ - /* It is the variable checked in ucnv_getDefaultName() to see if initialization is required. */ - // But there is nothing here preventing that from being reordered, either by the compiler - // or hardware. I'm adding the mutex to ucnv_getDefaultName for now. UMTX_CHECK is not enough. - // -- Andy - gDefaultConverterName = gDefaultConverterNameBuffer; - - ucnv_enableCleanup(); - - umtx_unlock(&cnvCacheMutex); -} -#endif - -/* - * In order to be really thread-safe, the get function would have to take - * a buffer parameter and copy the current string inside a mutex block. - * This implementation only tries to be really thread-safe while - * setting the name. - * It assumes that setting a pointer is atomic. - */ - -U_CAPI const char* U_EXPORT2 -ucnv_getDefaultName() { -#if U_CHARSET_IS_UTF8 - return "UTF-8"; -#else - /* local variable to be thread-safe */ - const char *name; - - /* - Concurrent calls to ucnv_getDefaultName must be thread safe, - but ucnv_setDefaultName is not thread safe. - */ - { - icu::Mutex lock(&cnvCacheMutex); - name = gDefaultConverterName; - } - if(name==NULL) { - UErrorCode errorCode = U_ZERO_ERROR; - UConverter *cnv = NULL; - - name = uprv_getDefaultCodepage(); - - /* if the name is there, test it out and get the canonical name with options */ - if(name != NULL) { - cnv = ucnv_open(name, &errorCode); - if(U_SUCCESS(errorCode) && cnv != NULL) { - name = ucnv_getName(cnv, &errorCode); - } - } - - if(name == NULL || name[0] == 0 - || U_FAILURE(errorCode) || cnv == NULL - || uprv_strlen(name)>=sizeof(gDefaultConverterNameBuffer)) - { - /* Panic time, let's use a fallback. */ -#if (U_CHARSET_FAMILY == U_ASCII_FAMILY) - name = "US-ASCII"; - /* there is no 'algorithmic' converter for EBCDIC */ -#elif U_PLATFORM == U_PF_OS390 - name = "ibm-1047_P100-1995" UCNV_SWAP_LFNL_OPTION_STRING; -#else - name = "ibm-37_P100-1995"; -#endif - } - - internalSetName(name, &errorCode); - - /* The close may make the current name go away. */ - ucnv_close(cnv); - } - - return name; -#endif -} - -#if U_CHARSET_IS_UTF8 -U_CAPI void U_EXPORT2 ucnv_setDefaultName(const char *) {} -#else -/* -This function is not thread safe, and it can't be thread safe. -See internalSetName or the API reference for details. -*/ -U_CAPI void U_EXPORT2 -ucnv_setDefaultName(const char *converterName) { - if(converterName==NULL) { - /* reset to the default codepage */ - gDefaultConverterName=NULL; - } else { - UErrorCode errorCode = U_ZERO_ERROR; - UConverter *cnv = NULL; - const char *name = NULL; - - /* if the name is there, test it out and get the canonical name with options */ - cnv = ucnv_open(converterName, &errorCode); - if(U_SUCCESS(errorCode) && cnv != NULL) { - name = ucnv_getName(cnv, &errorCode); - } - - if(U_SUCCESS(errorCode) && name!=NULL) { - internalSetName(name, &errorCode); - } - /* else this converter is bad to use. Don't change it to a bad value. */ - - /* The close may make the current name go away. */ - ucnv_close(cnv); - - /* reset the converter cache */ - u_flushDefaultConverter(); - } -} -#endif - -/* data swapping ------------------------------------------------------------ */ - -/* most of this might belong more properly into ucnvmbcs.c, but that is so large */ - -#if !UCONFIG_NO_LEGACY_CONVERSION - -U_CAPI int32_t U_EXPORT2 -ucnv_swap(const UDataSwapper *ds, - const void *inData, int32_t length, void *outData, - UErrorCode *pErrorCode) { - const UDataInfo *pInfo; - int32_t headerSize; - - const uint8_t *inBytes; - uint8_t *outBytes; - - uint32_t offset, count, staticDataSize; - int32_t size; - - const UConverterStaticData *inStaticData; - UConverterStaticData *outStaticData; - - const _MBCSHeader *inMBCSHeader; - _MBCSHeader *outMBCSHeader; - _MBCSHeader mbcsHeader; - uint32_t mbcsHeaderLength; - UBool noFromU=FALSE; - - uint8_t outputType; - - int32_t maxFastUChar, mbcsIndexLength; - - const int32_t *inExtIndexes; - int32_t extOffset; - - /* udata_swapDataHeader checks the arguments */ - headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode); - if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { - return 0; - } - - /* check data format and format version */ - pInfo=(const UDataInfo *)((const char *)inData+4); - if(!( - pInfo->dataFormat[0]==0x63 && /* dataFormat="cnvt" */ - pInfo->dataFormat[1]==0x6e && - pInfo->dataFormat[2]==0x76 && - pInfo->dataFormat[3]==0x74 && - pInfo->formatVersion[0]==6 && - pInfo->formatVersion[1]>=2 - )) { - udata_printError(ds, "ucnv_swap(): data format %02x.%02x.%02x.%02x (format version %02x.%02x) is not recognized as an ICU .cnv conversion table\n", - pInfo->dataFormat[0], pInfo->dataFormat[1], - pInfo->dataFormat[2], pInfo->dataFormat[3], - pInfo->formatVersion[0], pInfo->formatVersion[1]); - *pErrorCode=U_UNSUPPORTED_ERROR; - return 0; - } - - inBytes=(const uint8_t *)inData+headerSize; - outBytes=(uint8_t *)outData+headerSize; - - /* read the initial UConverterStaticData structure after the UDataInfo header */ - inStaticData=(const UConverterStaticData *)inBytes; - outStaticData=(UConverterStaticData *)outBytes; - - if(length<0) { - staticDataSize=ds->readUInt32(inStaticData->structSize); - } else { - length-=headerSize; - if( length<(int32_t)sizeof(UConverterStaticData) || - (uint32_t)length<(staticDataSize=ds->readUInt32(inStaticData->structSize)) - ) { - udata_printError(ds, "ucnv_swap(): too few bytes (%d after header) for an ICU .cnv conversion table\n", - length); - *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; - return 0; - } - } - - if(length>=0) { - /* swap the static data */ - if(inStaticData!=outStaticData) { - uprv_memcpy(outStaticData, inStaticData, staticDataSize); - } - - ds->swapArray32(ds, &inStaticData->structSize, 4, - &outStaticData->structSize, pErrorCode); - ds->swapArray32(ds, &inStaticData->codepage, 4, - &outStaticData->codepage, pErrorCode); - - ds->swapInvChars(ds, inStaticData->name, (int32_t)uprv_strlen(inStaticData->name), - outStaticData->name, pErrorCode); - if(U_FAILURE(*pErrorCode)) { - udata_printError(ds, "ucnv_swap(): error swapping converter name\n"); - return 0; - } - } - - inBytes+=staticDataSize; - outBytes+=staticDataSize; - if(length>=0) { - length-=(int32_t)staticDataSize; - } - - /* check for supported conversionType values */ - if(inStaticData->conversionType==UCNV_MBCS) { - /* swap MBCS data */ - inMBCSHeader=(const _MBCSHeader *)inBytes; - outMBCSHeader=(_MBCSHeader *)outBytes; - - if(0<=length && length<(int32_t)sizeof(_MBCSHeader)) { - udata_printError(ds, "ucnv_swap(): too few bytes (%d after headers) for an ICU MBCS .cnv conversion table\n", - length); - *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; - return 0; - } - if(inMBCSHeader->version[0]==4 && inMBCSHeader->version[1]>=1) { - mbcsHeaderLength=MBCS_HEADER_V4_LENGTH; - } else if(inMBCSHeader->version[0]==5 && inMBCSHeader->version[1]>=3 && - ((mbcsHeader.options=ds->readUInt32(inMBCSHeader->options))& - MBCS_OPT_UNKNOWN_INCOMPATIBLE_MASK)==0 - ) { - mbcsHeaderLength=mbcsHeader.options&MBCS_OPT_LENGTH_MASK; - noFromU=(UBool)((mbcsHeader.options&MBCS_OPT_NO_FROM_U)!=0); - } else { - udata_printError(ds, "ucnv_swap(): unsupported _MBCSHeader.version %d.%d\n", - inMBCSHeader->version[0], inMBCSHeader->version[1]); - *pErrorCode=U_UNSUPPORTED_ERROR; - return 0; - } - - uprv_memcpy(mbcsHeader.version, inMBCSHeader->version, 4); - mbcsHeader.countStates= ds->readUInt32(inMBCSHeader->countStates); - mbcsHeader.countToUFallbacks= ds->readUInt32(inMBCSHeader->countToUFallbacks); - mbcsHeader.offsetToUCodeUnits= ds->readUInt32(inMBCSHeader->offsetToUCodeUnits); - mbcsHeader.offsetFromUTable= ds->readUInt32(inMBCSHeader->offsetFromUTable); - mbcsHeader.offsetFromUBytes= ds->readUInt32(inMBCSHeader->offsetFromUBytes); - mbcsHeader.flags= ds->readUInt32(inMBCSHeader->flags); - mbcsHeader.fromUBytesLength= ds->readUInt32(inMBCSHeader->fromUBytesLength); - /* mbcsHeader.options have been read above */ - - extOffset=(int32_t)(mbcsHeader.flags>>8); - outputType=(uint8_t)mbcsHeader.flags; - if(noFromU && outputType==MBCS_OUTPUT_1) { - udata_printError(ds, "ucnv_swap(): unsupported combination of makeconv --small with SBCS\n"); - *pErrorCode=U_UNSUPPORTED_ERROR; - return 0; - } - - /* make sure that the output type is known */ - switch(outputType) { - case MBCS_OUTPUT_1: - case MBCS_OUTPUT_2: - case MBCS_OUTPUT_3: - case MBCS_OUTPUT_4: - case MBCS_OUTPUT_3_EUC: - case MBCS_OUTPUT_4_EUC: - case MBCS_OUTPUT_2_SISO: - case MBCS_OUTPUT_EXT_ONLY: - /* OK */ - break; - default: - udata_printError(ds, "ucnv_swap(): unsupported MBCS output type 0x%x\n", - outputType); - *pErrorCode=U_UNSUPPORTED_ERROR; - return 0; - } - - /* calculate the length of the MBCS data */ - - /* - * utf8Friendly MBCS files (mbcsHeader.version 4.3) - * contain an additional mbcsIndex table: - * uint16_t[(maxFastUChar+1)>>6]; - * where maxFastUChar=((mbcsHeader.version[2]<<8)|0xff). - */ - maxFastUChar=0; - mbcsIndexLength=0; - if( outputType!=MBCS_OUTPUT_EXT_ONLY && outputType!=MBCS_OUTPUT_1 && - mbcsHeader.version[1]>=3 && (maxFastUChar=mbcsHeader.version[2])!=0 - ) { - maxFastUChar=(maxFastUChar<<8)|0xff; - mbcsIndexLength=((maxFastUChar+1)>>6)*2; /* number of bytes */ - } - - if(extOffset==0) { - size=(int32_t)(mbcsHeader.offsetFromUBytes+mbcsIndexLength); - if(!noFromU) { - size+=(int32_t)mbcsHeader.fromUBytesLength; - } - - /* avoid compiler warnings - not otherwise necessary, and the value does not matter */ - inExtIndexes=NULL; - } else { - /* there is extension data after the base data, see ucnv_ext.h */ - if(length>=0 && length<(extOffset+UCNV_EXT_INDEXES_MIN_LENGTH*4)) { - udata_printError(ds, "ucnv_swap(): too few bytes (%d after headers) for an ICU MBCS .cnv conversion table with extension data\n", - length); - *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; - return 0; - } - - inExtIndexes=(const int32_t *)(inBytes+extOffset); - size=extOffset+udata_readInt32(ds, inExtIndexes[UCNV_EXT_SIZE]); - } - - if(length>=0) { - if(length<size) { - udata_printError(ds, "ucnv_swap(): too few bytes (%d after headers) for an ICU MBCS .cnv conversion table\n", - length); - *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; - return 0; - } - - /* copy the data for inaccessible bytes */ - if(inBytes!=outBytes) { - uprv_memcpy(outBytes, inBytes, size); - } - - /* swap the MBCSHeader, except for the version field */ - count=mbcsHeaderLength*4; - ds->swapArray32(ds, &inMBCSHeader->countStates, count-4, - &outMBCSHeader->countStates, pErrorCode); - - if(outputType==MBCS_OUTPUT_EXT_ONLY) { - /* - * extension-only file, - * contains a base name instead of normal base table data - */ - - /* swap the base name, between the header and the extension data */ - const char *inBaseName=(const char *)inBytes+count; - char *outBaseName=(char *)outBytes+count; - ds->swapInvChars(ds, inBaseName, (int32_t)uprv_strlen(inBaseName), - outBaseName, pErrorCode); - } else { - /* normal file with base table data */ - - /* swap the state table, 1kB per state */ - offset=count; - count=mbcsHeader.countStates*1024; - ds->swapArray32(ds, inBytes+offset, (int32_t)count, - outBytes+offset, pErrorCode); - - /* swap the toUFallbacks[] */ - offset+=count; - count=mbcsHeader.countToUFallbacks*8; - ds->swapArray32(ds, inBytes+offset, (int32_t)count, - outBytes+offset, pErrorCode); - - /* swap the unicodeCodeUnits[] */ - offset=mbcsHeader.offsetToUCodeUnits; - count=mbcsHeader.offsetFromUTable-offset; - ds->swapArray16(ds, inBytes+offset, (int32_t)count, - outBytes+offset, pErrorCode); - - /* offset to the stage 1 table, independent of the outputType */ - offset=mbcsHeader.offsetFromUTable; - - if(outputType==MBCS_OUTPUT_1) { - /* SBCS: swap the fromU tables, all 16 bits wide */ - count=(mbcsHeader.offsetFromUBytes-offset)+mbcsHeader.fromUBytesLength; - ds->swapArray16(ds, inBytes+offset, (int32_t)count, - outBytes+offset, pErrorCode); - } else { - /* otherwise: swap the stage tables separately */ - - /* stage 1 table: uint16_t[0x440 or 0x40] */ - if(inStaticData->unicodeMask&UCNV_HAS_SUPPLEMENTARY) { - count=0x440*2; /* for all of Unicode */ - } else { - count=0x40*2; /* only BMP */ - } - ds->swapArray16(ds, inBytes+offset, (int32_t)count, - outBytes+offset, pErrorCode); - - /* stage 2 table: uint32_t[] */ - offset+=count; - count=mbcsHeader.offsetFromUBytes-offset; - ds->swapArray32(ds, inBytes+offset, (int32_t)count, - outBytes+offset, pErrorCode); - - /* stage 3/result bytes: sometimes uint16_t[] or uint32_t[] */ - offset=mbcsHeader.offsetFromUBytes; - count= noFromU ? 0 : mbcsHeader.fromUBytesLength; - switch(outputType) { - case MBCS_OUTPUT_2: - case MBCS_OUTPUT_3_EUC: - case MBCS_OUTPUT_2_SISO: - ds->swapArray16(ds, inBytes+offset, (int32_t)count, - outBytes+offset, pErrorCode); - break; - case MBCS_OUTPUT_4: - ds->swapArray32(ds, inBytes+offset, (int32_t)count, - outBytes+offset, pErrorCode); - break; - default: - /* just uint8_t[], nothing to swap */ - break; - } - - if(mbcsIndexLength!=0) { - offset+=count; - count=mbcsIndexLength; - ds->swapArray16(ds, inBytes+offset, (int32_t)count, - outBytes+offset, pErrorCode); - } - } - } - - if(extOffset!=0) { - /* swap the extension data */ - inBytes+=extOffset; - outBytes+=extOffset; - - /* swap toUTable[] */ - offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_TO_U_INDEX]); - length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_TO_U_LENGTH]); - ds->swapArray32(ds, inBytes+offset, length*4, outBytes+offset, pErrorCode); - - /* swap toUUChars[] */ - offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_TO_U_UCHARS_INDEX]); - length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_TO_U_UCHARS_LENGTH]); - ds->swapArray16(ds, inBytes+offset, length*2, outBytes+offset, pErrorCode); - - /* swap fromUTableUChars[] */ - offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_UCHARS_INDEX]); - length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_LENGTH]); - ds->swapArray16(ds, inBytes+offset, length*2, outBytes+offset, pErrorCode); - - /* swap fromUTableValues[] */ - offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_VALUES_INDEX]); - /* same length as for fromUTableUChars[] */ - ds->swapArray32(ds, inBytes+offset, length*4, outBytes+offset, pErrorCode); - - /* no need to swap fromUBytes[] */ - - /* swap fromUStage12[] */ - offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_STAGE_12_INDEX]); - length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_STAGE_12_LENGTH]); - ds->swapArray16(ds, inBytes+offset, length*2, outBytes+offset, pErrorCode); - - /* swap fromUStage3[] */ - offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_STAGE_3_INDEX]); - length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_STAGE_3_LENGTH]); - ds->swapArray16(ds, inBytes+offset, length*2, outBytes+offset, pErrorCode); - - /* swap fromUStage3b[] */ - offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_STAGE_3B_INDEX]); - length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_STAGE_3B_LENGTH]); - ds->swapArray32(ds, inBytes+offset, length*4, outBytes+offset, pErrorCode); - - /* swap indexes[] */ - length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_INDEXES_LENGTH]); - ds->swapArray32(ds, inBytes, length*4, outBytes, pErrorCode); - } - } - } else { - udata_printError(ds, "ucnv_swap(): unknown conversionType=%d!=UCNV_MBCS\n", - inStaticData->conversionType); - *pErrorCode=U_UNSUPPORTED_ERROR; - return 0; - } - - return headerSize+(int32_t)staticDataSize+size; -} - -#endif /* #if !UCONFIG_NO_LEGACY_CONVERSION */ - -#endif |