1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/common/ucnv_bld.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1704 @@ 1.4 +/* 1.5 + ******************************************************************** 1.6 + * COPYRIGHT: 1.7 + * Copyright (c) 1996-2013, International Business Machines Corporation and 1.8 + * others. All Rights Reserved. 1.9 + ******************************************************************** 1.10 + * 1.11 + * uconv_bld.cpp: 1.12 + * 1.13 + * Defines functions that are used in the creation/initialization/deletion 1.14 + * of converters and related structures. 1.15 + * uses uconv_io.h routines to access disk information 1.16 + * is used by ucnv.h to implement public API create/delete/flushCache routines 1.17 + * Modification History: 1.18 + * 1.19 + * Date Name Description 1.20 + * 1.21 + * 06/20/2000 helena OS/400 port changes; mostly typecast. 1.22 + * 06/29/2000 helena Major rewrite of the callback interface. 1.23 +*/ 1.24 + 1.25 +#include "unicode/utypes.h" 1.26 + 1.27 +#if !UCONFIG_NO_CONVERSION 1.28 + 1.29 +#include "unicode/putil.h" 1.30 +#include "unicode/udata.h" 1.31 +#include "unicode/ucnv.h" 1.32 +#include "unicode/uloc.h" 1.33 +#include "mutex.h" 1.34 +#include "putilimp.h" 1.35 +#include "uassert.h" 1.36 +#include "utracimp.h" 1.37 +#include "ucnv_io.h" 1.38 +#include "ucnv_bld.h" 1.39 +#include "ucnvmbcs.h" 1.40 +#include "ucnv_ext.h" 1.41 +#include "ucnv_cnv.h" 1.42 +#include "ucnv_imp.h" 1.43 +#include "uhash.h" 1.44 +#include "umutex.h" 1.45 +#include "cstring.h" 1.46 +#include "cmemory.h" 1.47 +#include "ucln_cmn.h" 1.48 +#include "ustr_cnv.h" 1.49 + 1.50 + 1.51 +#if 0 1.52 +#include <stdio.h> 1.53 +extern void UCNV_DEBUG_LOG(char *what, char *who, void *p, int l); 1.54 +#define UCNV_DEBUG_LOG(x,y,z) UCNV_DEBUG_LOG(x,y,z,__LINE__) 1.55 +#else 1.56 +# define UCNV_DEBUG_LOG(x,y,z) 1.57 +#endif 1.58 + 1.59 +static const UConverterSharedData * const 1.60 +converterData[UCNV_NUMBER_OF_SUPPORTED_CONVERTER_TYPES]={ 1.61 + NULL, NULL, 1.62 + 1.63 +#if UCONFIG_NO_LEGACY_CONVERSION 1.64 + NULL, 1.65 +#else 1.66 + &_MBCSData, 1.67 +#endif 1.68 + 1.69 + &_Latin1Data, 1.70 + &_UTF8Data, &_UTF16BEData, &_UTF16LEData, &_UTF32BEData, &_UTF32LEData, 1.71 + NULL, 1.72 + 1.73 +#if UCONFIG_NO_LEGACY_CONVERSION 1.74 + NULL, 1.75 + NULL, NULL, NULL, NULL, NULL, NULL, 1.76 + NULL, NULL, NULL, NULL, NULL, NULL, 1.77 + NULL, 1.78 +#else 1.79 + &_ISO2022Data, 1.80 + &_LMBCSData1,&_LMBCSData2, &_LMBCSData3, &_LMBCSData4, &_LMBCSData5, &_LMBCSData6, 1.81 + &_LMBCSData8,&_LMBCSData11,&_LMBCSData16,&_LMBCSData17,&_LMBCSData18,&_LMBCSData19, 1.82 + &_HZData, 1.83 +#endif 1.84 + 1.85 + &_SCSUData, 1.86 + 1.87 +#if UCONFIG_NO_LEGACY_CONVERSION 1.88 + NULL, 1.89 +#else 1.90 + &_ISCIIData, 1.91 +#endif 1.92 + 1.93 + &_ASCIIData, 1.94 + &_UTF7Data, &_Bocu1Data, &_UTF16Data, &_UTF32Data, &_CESU8Data, &_IMAPData, 1.95 + 1.96 +#if UCONFIG_NO_LEGACY_CONVERSION 1.97 + NULL, 1.98 +#else 1.99 + &_CompoundTextData 1.100 +#endif 1.101 +}; 1.102 + 1.103 +/* Please keep this in binary sorted order for getAlgorithmicTypeFromName. 1.104 + Also the name should be in lower case and all spaces, dashes and underscores 1.105 + removed 1.106 +*/ 1.107 +static struct { 1.108 + const char *name; 1.109 + const UConverterType type; 1.110 +} const cnvNameType[] = { 1.111 + { "bocu1", UCNV_BOCU1 }, 1.112 + { "cesu8", UCNV_CESU8 }, 1.113 +#if !UCONFIG_NO_LEGACY_CONVERSION 1.114 + { "hz",UCNV_HZ }, 1.115 +#endif 1.116 + { "imapmailboxname", UCNV_IMAP_MAILBOX }, 1.117 +#if !UCONFIG_NO_LEGACY_CONVERSION 1.118 + { "iscii", UCNV_ISCII }, 1.119 + { "iso2022", UCNV_ISO_2022 }, 1.120 +#endif 1.121 + { "iso88591", UCNV_LATIN_1 }, 1.122 +#if !UCONFIG_NO_LEGACY_CONVERSION 1.123 + { "lmbcs1", UCNV_LMBCS_1 }, 1.124 + { "lmbcs11",UCNV_LMBCS_11 }, 1.125 + { "lmbcs16",UCNV_LMBCS_16 }, 1.126 + { "lmbcs17",UCNV_LMBCS_17 }, 1.127 + { "lmbcs18",UCNV_LMBCS_18 }, 1.128 + { "lmbcs19",UCNV_LMBCS_19 }, 1.129 + { "lmbcs2", UCNV_LMBCS_2 }, 1.130 + { "lmbcs3", UCNV_LMBCS_3 }, 1.131 + { "lmbcs4", UCNV_LMBCS_4 }, 1.132 + { "lmbcs5", UCNV_LMBCS_5 }, 1.133 + { "lmbcs6", UCNV_LMBCS_6 }, 1.134 + { "lmbcs8", UCNV_LMBCS_8 }, 1.135 +#endif 1.136 + { "scsu", UCNV_SCSU }, 1.137 + { "usascii", UCNV_US_ASCII }, 1.138 + { "utf16", UCNV_UTF16 }, 1.139 + { "utf16be", UCNV_UTF16_BigEndian }, 1.140 + { "utf16le", UCNV_UTF16_LittleEndian }, 1.141 +#if U_IS_BIG_ENDIAN 1.142 + { "utf16oppositeendian", UCNV_UTF16_LittleEndian }, 1.143 + { "utf16platformendian", UCNV_UTF16_BigEndian }, 1.144 +#else 1.145 + { "utf16oppositeendian", UCNV_UTF16_BigEndian}, 1.146 + { "utf16platformendian", UCNV_UTF16_LittleEndian }, 1.147 +#endif 1.148 + { "utf32", UCNV_UTF32 }, 1.149 + { "utf32be", UCNV_UTF32_BigEndian }, 1.150 + { "utf32le", UCNV_UTF32_LittleEndian }, 1.151 +#if U_IS_BIG_ENDIAN 1.152 + { "utf32oppositeendian", UCNV_UTF32_LittleEndian }, 1.153 + { "utf32platformendian", UCNV_UTF32_BigEndian }, 1.154 +#else 1.155 + { "utf32oppositeendian", UCNV_UTF32_BigEndian }, 1.156 + { "utf32platformendian", UCNV_UTF32_LittleEndian }, 1.157 +#endif 1.158 + { "utf7", UCNV_UTF7 }, 1.159 + { "utf8", UCNV_UTF8 }, 1.160 + { "x11compoundtext", UCNV_COMPOUND_TEXT} 1.161 +}; 1.162 + 1.163 + 1.164 +/*initializes some global variables */ 1.165 +static UHashtable *SHARED_DATA_HASHTABLE = NULL; 1.166 +static UMutex cnvCacheMutex = U_MUTEX_INITIALIZER; /* Mutex for synchronizing cnv cache access. */ 1.167 + /* Note: the global mutex is used for */ 1.168 + /* reference count updates. */ 1.169 + 1.170 +static const char **gAvailableConverters = NULL; 1.171 +static uint16_t gAvailableConverterCount = 0; 1.172 +static icu::UInitOnce gAvailableConvertersInitOnce = U_INITONCE_INITIALIZER; 1.173 + 1.174 +#if !U_CHARSET_IS_UTF8 1.175 + 1.176 +/* This contains the resolved converter name. So no further alias lookup is needed again. */ 1.177 +static char gDefaultConverterNameBuffer[UCNV_MAX_CONVERTER_NAME_LENGTH + 1]; /* +1 for NULL */ 1.178 +static const char *gDefaultConverterName = NULL; 1.179 + 1.180 +/* 1.181 +If the default converter is an algorithmic converter, this is the cached value. 1.182 +We don't cache a full UConverter and clone it because ucnv_clone doesn't have 1.183 +less overhead than an algorithmic open. We don't cache non-algorithmic converters 1.184 +because ucnv_flushCache must be able to unload the default converter and its table. 1.185 +*/ 1.186 +static const UConverterSharedData *gDefaultAlgorithmicSharedData = NULL; 1.187 + 1.188 +/* Does gDefaultConverterName have a converter option and require extra parsing? */ 1.189 +static UBool gDefaultConverterContainsOption; 1.190 + 1.191 +#endif /* !U_CHARSET_IS_UTF8 */ 1.192 + 1.193 +static const char DATA_TYPE[] = "cnv"; 1.194 + 1.195 +/* ucnv_flushAvailableConverterCache. This is only called from ucnv_cleanup(). 1.196 + * If it is ever to be called from elsewhere, synchronization 1.197 + * will need to be considered. 1.198 + */ 1.199 +static void 1.200 +ucnv_flushAvailableConverterCache() { 1.201 + gAvailableConverterCount = 0; 1.202 + if (gAvailableConverters) { 1.203 + uprv_free((char **)gAvailableConverters); 1.204 + gAvailableConverters = NULL; 1.205 + } 1.206 + gAvailableConvertersInitOnce.reset(); 1.207 +} 1.208 + 1.209 +/* ucnv_cleanup - delete all storage held by the converter cache, except any */ 1.210 +/* in use by open converters. */ 1.211 +/* Not thread safe. */ 1.212 +/* Not supported API. */ 1.213 +static UBool U_CALLCONV ucnv_cleanup(void) { 1.214 + ucnv_flushCache(); 1.215 + if (SHARED_DATA_HASHTABLE != NULL && uhash_count(SHARED_DATA_HASHTABLE) == 0) { 1.216 + uhash_close(SHARED_DATA_HASHTABLE); 1.217 + SHARED_DATA_HASHTABLE = NULL; 1.218 + } 1.219 + 1.220 + /* Isn't called from flushCache because other threads may have preexisting references to the table. */ 1.221 + ucnv_flushAvailableConverterCache(); 1.222 + 1.223 +#if !U_CHARSET_IS_UTF8 1.224 + gDefaultConverterName = NULL; 1.225 + gDefaultConverterNameBuffer[0] = 0; 1.226 + gDefaultConverterContainsOption = FALSE; 1.227 + gDefaultAlgorithmicSharedData = NULL; 1.228 +#endif 1.229 + 1.230 + return (SHARED_DATA_HASHTABLE == NULL); 1.231 +} 1.232 + 1.233 +static UBool U_CALLCONV 1.234 +isCnvAcceptable(void * /*context*/, 1.235 + const char * /*type*/, const char * /*name*/, 1.236 + const UDataInfo *pInfo) { 1.237 + return (UBool)( 1.238 + pInfo->size>=20 && 1.239 + pInfo->isBigEndian==U_IS_BIG_ENDIAN && 1.240 + pInfo->charsetFamily==U_CHARSET_FAMILY && 1.241 + pInfo->sizeofUChar==U_SIZEOF_UCHAR && 1.242 + pInfo->dataFormat[0]==0x63 && /* dataFormat="cnvt" */ 1.243 + pInfo->dataFormat[1]==0x6e && 1.244 + pInfo->dataFormat[2]==0x76 && 1.245 + pInfo->dataFormat[3]==0x74 && 1.246 + pInfo->formatVersion[0]==6); /* Everything will be version 6 */ 1.247 +} 1.248 + 1.249 +/** 1.250 + * Un flatten shared data from a UDATA.. 1.251 + */ 1.252 +static UConverterSharedData* 1.253 +ucnv_data_unFlattenClone(UConverterLoadArgs *pArgs, UDataMemory *pData, UErrorCode *status) 1.254 +{ 1.255 + /* UDataInfo info; -- necessary only if some converters have different formatVersion */ 1.256 + const uint8_t *raw = (const uint8_t *)udata_getMemory(pData); 1.257 + const UConverterStaticData *source = (const UConverterStaticData *) raw; 1.258 + UConverterSharedData *data; 1.259 + UConverterType type = (UConverterType)source->conversionType; 1.260 + 1.261 + if(U_FAILURE(*status)) 1.262 + return NULL; 1.263 + 1.264 + if( (uint16_t)type >= UCNV_NUMBER_OF_SUPPORTED_CONVERTER_TYPES || 1.265 + converterData[type] == NULL || 1.266 + converterData[type]->referenceCounter != 1 || 1.267 + source->structSize != sizeof(UConverterStaticData)) 1.268 + { 1.269 + *status = U_INVALID_TABLE_FORMAT; 1.270 + return NULL; 1.271 + } 1.272 + 1.273 + data = (UConverterSharedData *)uprv_malloc(sizeof(UConverterSharedData)); 1.274 + if(data == NULL) { 1.275 + *status = U_MEMORY_ALLOCATION_ERROR; 1.276 + return NULL; 1.277 + } 1.278 + 1.279 + /* copy initial values from the static structure for this type */ 1.280 + uprv_memcpy(data, converterData[type], sizeof(UConverterSharedData)); 1.281 + 1.282 +#if 0 /* made UConverterMBCSTable part of UConverterSharedData -- markus 20031107 */ 1.283 + /* 1.284 + * It would be much more efficient if the table were a direct member, not a pointer. 1.285 + * However, that would add to the size of all UConverterSharedData objects 1.286 + * even if they do not use this table (especially algorithmic ones). 1.287 + * If this changes, then the static templates from converterData[type] 1.288 + * need more entries. 1.289 + * 1.290 + * In principle, it would be cleaner if the load() function below 1.291 + * allocated the table. 1.292 + */ 1.293 + data->table = (UConverterTable *)uprv_malloc(sizeof(UConverterTable)); 1.294 + if(data->table == NULL) { 1.295 + uprv_free(data); 1.296 + *status = U_MEMORY_ALLOCATION_ERROR; 1.297 + return NULL; 1.298 + } 1.299 + uprv_memset(data->table, 0, sizeof(UConverterTable)); 1.300 +#endif 1.301 + 1.302 + data->staticData = source; 1.303 + 1.304 + data->sharedDataCached = FALSE; 1.305 + 1.306 + /* fill in fields from the loaded data */ 1.307 + data->dataMemory = (void*)pData; /* for future use */ 1.308 + 1.309 + if(data->impl->load != NULL) { 1.310 + data->impl->load(data, pArgs, raw + source->structSize, status); 1.311 + if(U_FAILURE(*status)) { 1.312 + uprv_free(data->table); 1.313 + uprv_free(data); 1.314 + return NULL; 1.315 + } 1.316 + } 1.317 + return data; 1.318 +} 1.319 + 1.320 +/*Takes an alias name gets an actual converter file name 1.321 + *goes to disk and opens it. 1.322 + *allocates the memory and returns a new UConverter object 1.323 + */ 1.324 +static UConverterSharedData *createConverterFromFile(UConverterLoadArgs *pArgs, UErrorCode * err) 1.325 +{ 1.326 + UDataMemory *data; 1.327 + UConverterSharedData *sharedData; 1.328 + 1.329 + UTRACE_ENTRY_OC(UTRACE_UCNV_LOAD); 1.330 + 1.331 + if (U_FAILURE (*err)) { 1.332 + UTRACE_EXIT_STATUS(*err); 1.333 + return NULL; 1.334 + } 1.335 + 1.336 + UTRACE_DATA2(UTRACE_OPEN_CLOSE, "load converter %s from package %s", pArgs->name, pArgs->pkg); 1.337 + 1.338 + data = udata_openChoice(pArgs->pkg, DATA_TYPE, pArgs->name, isCnvAcceptable, NULL, err); 1.339 + if(U_FAILURE(*err)) 1.340 + { 1.341 + UTRACE_EXIT_STATUS(*err); 1.342 + return NULL; 1.343 + } 1.344 + 1.345 + sharedData = ucnv_data_unFlattenClone(pArgs, data, err); 1.346 + if(U_FAILURE(*err)) 1.347 + { 1.348 + udata_close(data); 1.349 + UTRACE_EXIT_STATUS(*err); 1.350 + return NULL; 1.351 + } 1.352 + 1.353 + /* 1.354 + * TODO Store pkg in a field in the shared data so that delta-only converters 1.355 + * can load base converters from the same package. 1.356 + * If the pkg name is longer than the field, then either do not load the converter 1.357 + * in the first place, or just set the pkg field to "". 1.358 + */ 1.359 + 1.360 + UTRACE_EXIT_PTR_STATUS(sharedData, *err); 1.361 + return sharedData; 1.362 +} 1.363 + 1.364 +/*returns a converter type from a string 1.365 + */ 1.366 +static const UConverterSharedData * 1.367 +getAlgorithmicTypeFromName(const char *realName) 1.368 +{ 1.369 + uint32_t mid, start, limit; 1.370 + uint32_t lastMid; 1.371 + int result; 1.372 + char strippedName[UCNV_MAX_CONVERTER_NAME_LENGTH]; 1.373 + 1.374 + /* Lower case and remove ignoreable characters. */ 1.375 + ucnv_io_stripForCompare(strippedName, realName); 1.376 + 1.377 + /* do a binary search for the alias */ 1.378 + start = 0; 1.379 + limit = sizeof(cnvNameType)/sizeof(cnvNameType[0]); 1.380 + mid = limit; 1.381 + lastMid = UINT32_MAX; 1.382 + 1.383 + for (;;) { 1.384 + mid = (uint32_t)((start + limit) / 2); 1.385 + if (lastMid == mid) { /* Have we moved? */ 1.386 + break; /* We haven't moved, and it wasn't found. */ 1.387 + } 1.388 + lastMid = mid; 1.389 + result = uprv_strcmp(strippedName, cnvNameType[mid].name); 1.390 + 1.391 + if (result < 0) { 1.392 + limit = mid; 1.393 + } else if (result > 0) { 1.394 + start = mid; 1.395 + } else { 1.396 + return converterData[cnvNameType[mid].type]; 1.397 + } 1.398 + } 1.399 + 1.400 + return NULL; 1.401 +} 1.402 + 1.403 +/* 1.404 +* Based on the number of known converters, this determines how many times larger 1.405 +* the shared data hash table should be. When on small platforms, or just a couple 1.406 +* of converters are used, this number should be 2. When memory is plentiful, or 1.407 +* when ucnv_countAvailable is ever used with a lot of available converters, 1.408 +* this should be 4. 1.409 +* Larger numbers reduce the number of hash collisions, but use more memory. 1.410 +*/ 1.411 +#define UCNV_CACHE_LOAD_FACTOR 2 1.412 + 1.413 +/* Puts the shared data in the static hashtable SHARED_DATA_HASHTABLE */ 1.414 +/* Will always be called with the cnvCacheMutex alrady being held */ 1.415 +/* by the calling function. */ 1.416 +/* Stores the shared data in the SHARED_DATA_HASHTABLE 1.417 + * @param data The shared data 1.418 + */ 1.419 +static void 1.420 +ucnv_shareConverterData(UConverterSharedData * data) 1.421 +{ 1.422 + UErrorCode err = U_ZERO_ERROR; 1.423 + /*Lazy evaluates the Hashtable itself */ 1.424 + /*void *sanity = NULL;*/ 1.425 + 1.426 + if (SHARED_DATA_HASHTABLE == NULL) 1.427 + { 1.428 + SHARED_DATA_HASHTABLE = uhash_openSize(uhash_hashChars, uhash_compareChars, NULL, 1.429 + ucnv_io_countKnownConverters(&err)*UCNV_CACHE_LOAD_FACTOR, 1.430 + &err); 1.431 + ucln_common_registerCleanup(UCLN_COMMON_UCNV, ucnv_cleanup); 1.432 + 1.433 + if (U_FAILURE(err)) 1.434 + return; 1.435 + } 1.436 + 1.437 + /* ### check to see if the element is not already there! */ 1.438 + 1.439 + /* 1.440 + sanity = ucnv_getSharedConverterData (data->staticData->name); 1.441 + if(sanity != NULL) 1.442 + { 1.443 + UCNV_DEBUG_LOG("put:overwrite!",data->staticData->name,sanity); 1.444 + } 1.445 + UCNV_DEBUG_LOG("put:chk",data->staticData->name,sanity); 1.446 + */ 1.447 + 1.448 + /* Mark it shared */ 1.449 + data->sharedDataCached = TRUE; 1.450 + 1.451 + uhash_put(SHARED_DATA_HASHTABLE, 1.452 + (void*) data->staticData->name, /* Okay to cast away const as long as 1.453 + keyDeleter == NULL */ 1.454 + data, 1.455 + &err); 1.456 + UCNV_DEBUG_LOG("put", data->staticData->name,data); 1.457 + 1.458 +} 1.459 + 1.460 +/* Look up a converter name in the shared data cache. */ 1.461 +/* cnvCacheMutex must be held by the caller to protect the hash table. */ 1.462 +/* gets the shared data from the SHARED_DATA_HASHTABLE (might return NULL if it isn't there) 1.463 + * @param name The name of the shared data 1.464 + * @return the shared data from the SHARED_DATA_HASHTABLE 1.465 + */ 1.466 +static UConverterSharedData * 1.467 +ucnv_getSharedConverterData(const char *name) 1.468 +{ 1.469 + /*special case when no Table has yet been created we return NULL */ 1.470 + if (SHARED_DATA_HASHTABLE == NULL) 1.471 + { 1.472 + return NULL; 1.473 + } 1.474 + else 1.475 + { 1.476 + UConverterSharedData *rc; 1.477 + 1.478 + rc = (UConverterSharedData*)uhash_get(SHARED_DATA_HASHTABLE, name); 1.479 + UCNV_DEBUG_LOG("get",name,rc); 1.480 + return rc; 1.481 + } 1.482 +} 1.483 + 1.484 +/*frees the string of memory blocks associates with a sharedConverter 1.485 + *if and only if the referenceCounter == 0 1.486 + */ 1.487 +/* Deletes (frees) the Shared data it's passed. first it checks the referenceCounter to 1.488 + * see if anyone is using it, if not it frees all the memory stemming from sharedConverterData and 1.489 + * returns TRUE, 1.490 + * otherwise returns FALSE 1.491 + * @param sharedConverterData The shared data 1.492 + * @return if not it frees all the memory stemming from sharedConverterData and 1.493 + * returns TRUE, otherwise returns FALSE 1.494 + */ 1.495 +static UBool 1.496 +ucnv_deleteSharedConverterData(UConverterSharedData * deadSharedData) 1.497 +{ 1.498 + UTRACE_ENTRY_OC(UTRACE_UCNV_UNLOAD); 1.499 + UTRACE_DATA2(UTRACE_OPEN_CLOSE, "unload converter %s shared data %p", deadSharedData->staticData->name, deadSharedData); 1.500 + 1.501 + if (deadSharedData->referenceCounter > 0) { 1.502 + UTRACE_EXIT_VALUE((int32_t)FALSE); 1.503 + return FALSE; 1.504 + } 1.505 + 1.506 + if (deadSharedData->impl->unload != NULL) { 1.507 + deadSharedData->impl->unload(deadSharedData); 1.508 + } 1.509 + 1.510 + if(deadSharedData->dataMemory != NULL) 1.511 + { 1.512 + UDataMemory *data = (UDataMemory*)deadSharedData->dataMemory; 1.513 + udata_close(data); 1.514 + } 1.515 + 1.516 + if(deadSharedData->table != NULL) 1.517 + { 1.518 + uprv_free(deadSharedData->table); 1.519 + } 1.520 + 1.521 +#if 0 1.522 + /* if the static data is actually owned by the shared data */ 1.523 + /* enable if we ever have this situation. */ 1.524 + if(deadSharedData->staticDataOwned == TRUE) /* see ucnv_bld.h */ 1.525 + { 1.526 + uprv_free((void*)deadSharedData->staticData); 1.527 + } 1.528 +#endif 1.529 + 1.530 +#if 0 1.531 + /* Zap it ! */ 1.532 + uprv_memset(deadSharedData->0, sizeof(*deadSharedData)); 1.533 +#endif 1.534 + 1.535 + uprv_free(deadSharedData); 1.536 + 1.537 + UTRACE_EXIT_VALUE((int32_t)TRUE); 1.538 + return TRUE; 1.539 +} 1.540 + 1.541 +/** 1.542 + * Load a non-algorithmic converter. 1.543 + * If pkg==NULL, then this function must be called inside umtx_lock(&cnvCacheMutex). 1.544 + */ 1.545 +UConverterSharedData * 1.546 +ucnv_load(UConverterLoadArgs *pArgs, UErrorCode *err) { 1.547 + UConverterSharedData *mySharedConverterData; 1.548 + 1.549 + if(err == NULL || U_FAILURE(*err)) { 1.550 + return NULL; 1.551 + } 1.552 + 1.553 + if(pArgs->pkg != NULL && *pArgs->pkg != 0) { 1.554 + /* application-provided converters are not currently cached */ 1.555 + return createConverterFromFile(pArgs, err); 1.556 + } 1.557 + 1.558 + mySharedConverterData = ucnv_getSharedConverterData(pArgs->name); 1.559 + if (mySharedConverterData == NULL) 1.560 + { 1.561 + /*Not cached, we need to stream it in from file */ 1.562 + mySharedConverterData = createConverterFromFile(pArgs, err); 1.563 + if (U_FAILURE (*err) || (mySharedConverterData == NULL)) 1.564 + { 1.565 + return NULL; 1.566 + } 1.567 + else if (!pArgs->onlyTestIsLoadable) 1.568 + { 1.569 + /* share it with other library clients */ 1.570 + ucnv_shareConverterData(mySharedConverterData); 1.571 + } 1.572 + } 1.573 + else 1.574 + { 1.575 + /* The data for this converter was already in the cache. */ 1.576 + /* Update the reference counter on the shared data: one more client */ 1.577 + mySharedConverterData->referenceCounter++; 1.578 + } 1.579 + 1.580 + return mySharedConverterData; 1.581 +} 1.582 + 1.583 +/** 1.584 + * Unload a non-algorithmic converter. 1.585 + * It must be sharedData->referenceCounter != ~0 1.586 + * and this function must be called inside umtx_lock(&cnvCacheMutex). 1.587 + */ 1.588 +U_CAPI void 1.589 +ucnv_unload(UConverterSharedData *sharedData) { 1.590 + if(sharedData != NULL) { 1.591 + if (sharedData->referenceCounter > 0) { 1.592 + sharedData->referenceCounter--; 1.593 + } 1.594 + 1.595 + if((sharedData->referenceCounter <= 0)&&(sharedData->sharedDataCached == FALSE)) { 1.596 + ucnv_deleteSharedConverterData(sharedData); 1.597 + } 1.598 + } 1.599 +} 1.600 + 1.601 +U_CFUNC void 1.602 +ucnv_unloadSharedDataIfReady(UConverterSharedData *sharedData) 1.603 +{ 1.604 + /* 1.605 + Checking whether it's an algorithic converter is okay 1.606 + in multithreaded applications because the value never changes. 1.607 + Don't check referenceCounter for any other value. 1.608 + */ 1.609 + if(sharedData != NULL && sharedData->referenceCounter != (uint32_t)~0) { 1.610 + umtx_lock(&cnvCacheMutex); 1.611 + ucnv_unload(sharedData); 1.612 + umtx_unlock(&cnvCacheMutex); 1.613 + } 1.614 +} 1.615 + 1.616 +U_CFUNC void 1.617 +ucnv_incrementRefCount(UConverterSharedData *sharedData) 1.618 +{ 1.619 + /* 1.620 + Checking whether it's an algorithic converter is okay 1.621 + in multithreaded applications because the value never changes. 1.622 + Don't check referenceCounter for any other value. 1.623 + */ 1.624 + if(sharedData != NULL && sharedData->referenceCounter != (uint32_t)~0) { 1.625 + umtx_lock(&cnvCacheMutex); 1.626 + sharedData->referenceCounter++; 1.627 + umtx_unlock(&cnvCacheMutex); 1.628 + } 1.629 +} 1.630 + 1.631 +/* 1.632 + * *pPieces must be initialized. 1.633 + * The name without options will be copied to pPieces->cnvName. 1.634 + * The locale and options will be copied to pPieces only if present in inName, 1.635 + * otherwise the existing values in pPieces remain. 1.636 + * *pArgs will be set to the pPieces values. 1.637 + */ 1.638 +static void 1.639 +parseConverterOptions(const char *inName, 1.640 + UConverterNamePieces *pPieces, 1.641 + UConverterLoadArgs *pArgs, 1.642 + UErrorCode *err) 1.643 +{ 1.644 + char *cnvName = pPieces->cnvName; 1.645 + char c; 1.646 + int32_t len = 0; 1.647 + 1.648 + pArgs->name=inName; 1.649 + pArgs->locale=pPieces->locale; 1.650 + pArgs->options=pPieces->options; 1.651 + 1.652 + /* copy the converter name itself to cnvName */ 1.653 + while((c=*inName)!=0 && c!=UCNV_OPTION_SEP_CHAR) { 1.654 + if (++len>=UCNV_MAX_CONVERTER_NAME_LENGTH) { 1.655 + *err = U_ILLEGAL_ARGUMENT_ERROR; /* bad name */ 1.656 + pPieces->cnvName[0]=0; 1.657 + return; 1.658 + } 1.659 + *cnvName++=c; 1.660 + inName++; 1.661 + } 1.662 + *cnvName=0; 1.663 + pArgs->name=pPieces->cnvName; 1.664 + 1.665 + /* parse options. No more name copying should occur. */ 1.666 + while((c=*inName)!=0) { 1.667 + if(c==UCNV_OPTION_SEP_CHAR) { 1.668 + ++inName; 1.669 + } 1.670 + 1.671 + /* inName is behind an option separator */ 1.672 + if(uprv_strncmp(inName, "locale=", 7)==0) { 1.673 + /* do not modify locale itself in case we have multiple locale options */ 1.674 + char *dest=pPieces->locale; 1.675 + 1.676 + /* copy the locale option value */ 1.677 + inName+=7; 1.678 + len=0; 1.679 + while((c=*inName)!=0 && c!=UCNV_OPTION_SEP_CHAR) { 1.680 + ++inName; 1.681 + 1.682 + if(++len>=ULOC_FULLNAME_CAPACITY) { 1.683 + *err=U_ILLEGAL_ARGUMENT_ERROR; /* bad name */ 1.684 + pPieces->locale[0]=0; 1.685 + return; 1.686 + } 1.687 + 1.688 + *dest++=c; 1.689 + } 1.690 + *dest=0; 1.691 + } else if(uprv_strncmp(inName, "version=", 8)==0) { 1.692 + /* copy the version option value into bits 3..0 of pPieces->options */ 1.693 + inName+=8; 1.694 + c=*inName; 1.695 + if(c==0) { 1.696 + pArgs->options=(pPieces->options&=~UCNV_OPTION_VERSION); 1.697 + return; 1.698 + } else if((uint8_t)(c-'0')<10) { 1.699 + pArgs->options=pPieces->options=(pPieces->options&~UCNV_OPTION_VERSION)|(uint32_t)(c-'0'); 1.700 + ++inName; 1.701 + } 1.702 + } else if(uprv_strncmp(inName, "swaplfnl", 8)==0) { 1.703 + inName+=8; 1.704 + pArgs->options=(pPieces->options|=UCNV_OPTION_SWAP_LFNL); 1.705 + /* add processing for new options here with another } else if(uprv_strncmp(inName, "option-name=", XX)==0) { */ 1.706 + } else { 1.707 + /* ignore any other options until we define some */ 1.708 + while(((c = *inName++) != 0) && (c != UCNV_OPTION_SEP_CHAR)) { 1.709 + } 1.710 + if(c==0) { 1.711 + return; 1.712 + } 1.713 + } 1.714 + } 1.715 +} 1.716 + 1.717 +/*Logic determines if the converter is Algorithmic AND/OR cached 1.718 + *depending on that: 1.719 + * -we either go to get data from disk and cache it (Data=TRUE, Cached=False) 1.720 + * -Get it from a Hashtable (Data=X, Cached=TRUE) 1.721 + * -Call dataConverter initializer (Data=TRUE, Cached=TRUE) 1.722 + * -Call AlgorithmicConverter initializer (Data=FALSE, Cached=TRUE) 1.723 + */ 1.724 +U_CFUNC UConverterSharedData * 1.725 +ucnv_loadSharedData(const char *converterName, 1.726 + UConverterNamePieces *pPieces, 1.727 + UConverterLoadArgs *pArgs, 1.728 + UErrorCode * err) { 1.729 + UConverterNamePieces stackPieces; 1.730 + UConverterLoadArgs stackArgs; 1.731 + UConverterSharedData *mySharedConverterData = NULL; 1.732 + UErrorCode internalErrorCode = U_ZERO_ERROR; 1.733 + UBool mayContainOption = TRUE; 1.734 + UBool checkForAlgorithmic = TRUE; 1.735 + 1.736 + if (U_FAILURE (*err)) { 1.737 + return NULL; 1.738 + } 1.739 + 1.740 + if(pPieces == NULL) { 1.741 + if(pArgs != NULL) { 1.742 + /* 1.743 + * Bad: We may set pArgs pointers to stackPieces fields 1.744 + * which will be invalid after this function returns. 1.745 + */ 1.746 + *err = U_INTERNAL_PROGRAM_ERROR; 1.747 + return NULL; 1.748 + } 1.749 + pPieces = &stackPieces; 1.750 + } 1.751 + if(pArgs == NULL) { 1.752 + uprv_memset(&stackArgs, 0, sizeof(stackArgs)); 1.753 + stackArgs.size = (int32_t)sizeof(stackArgs); 1.754 + pArgs = &stackArgs; 1.755 + } 1.756 + 1.757 + pPieces->cnvName[0] = 0; 1.758 + pPieces->locale[0] = 0; 1.759 + pPieces->options = 0; 1.760 + 1.761 + pArgs->name = converterName; 1.762 + pArgs->locale = pPieces->locale; 1.763 + pArgs->options = pPieces->options; 1.764 + 1.765 + /* In case "name" is NULL we want to open the default converter. */ 1.766 + if (converterName == NULL) { 1.767 +#if U_CHARSET_IS_UTF8 1.768 + pArgs->name = "UTF-8"; 1.769 + return (UConverterSharedData *)converterData[UCNV_UTF8]; 1.770 +#else 1.771 + /* Call ucnv_getDefaultName first to query the name from the OS. */ 1.772 + pArgs->name = ucnv_getDefaultName(); 1.773 + if (pArgs->name == NULL) { 1.774 + *err = U_MISSING_RESOURCE_ERROR; 1.775 + return NULL; 1.776 + } 1.777 + mySharedConverterData = (UConverterSharedData *)gDefaultAlgorithmicSharedData; 1.778 + checkForAlgorithmic = FALSE; 1.779 + mayContainOption = gDefaultConverterContainsOption; 1.780 + /* the default converter name is already canonical */ 1.781 +#endif 1.782 + } 1.783 + else if(UCNV_FAST_IS_UTF8(converterName)) { 1.784 + /* fastpath for UTF-8 */ 1.785 + pArgs->name = "UTF-8"; 1.786 + return (UConverterSharedData *)converterData[UCNV_UTF8]; 1.787 + } 1.788 + else { 1.789 + /* separate the converter name from the options */ 1.790 + parseConverterOptions(converterName, pPieces, pArgs, err); 1.791 + if (U_FAILURE(*err)) { 1.792 + /* Very bad name used. */ 1.793 + return NULL; 1.794 + } 1.795 + 1.796 + /* get the canonical converter name */ 1.797 + pArgs->name = ucnv_io_getConverterName(pArgs->name, &mayContainOption, &internalErrorCode); 1.798 + if (U_FAILURE(internalErrorCode) || pArgs->name == NULL) { 1.799 + /* 1.800 + * set the input name in case the converter was added 1.801 + * without updating the alias table, or when there is no alias table 1.802 + */ 1.803 + pArgs->name = pPieces->cnvName; 1.804 + } else if (internalErrorCode == U_AMBIGUOUS_ALIAS_WARNING) { 1.805 + *err = U_AMBIGUOUS_ALIAS_WARNING; 1.806 + } 1.807 + } 1.808 + 1.809 + /* separate the converter name from the options */ 1.810 + if(mayContainOption && pArgs->name != pPieces->cnvName) { 1.811 + parseConverterOptions(pArgs->name, pPieces, pArgs, err); 1.812 + } 1.813 + 1.814 + /* get the shared data for an algorithmic converter, if it is one */ 1.815 + if (checkForAlgorithmic) { 1.816 + mySharedConverterData = (UConverterSharedData *)getAlgorithmicTypeFromName(pArgs->name); 1.817 + } 1.818 + if (mySharedConverterData == NULL) 1.819 + { 1.820 + /* it is a data-based converter, get its shared data. */ 1.821 + /* Hold the cnvCacheMutex through the whole process of checking the */ 1.822 + /* converter data cache, and adding new entries to the cache */ 1.823 + /* to prevent other threads from modifying the cache during the */ 1.824 + /* process. */ 1.825 + pArgs->nestedLoads=1; 1.826 + pArgs->pkg=NULL; 1.827 + 1.828 + umtx_lock(&cnvCacheMutex); 1.829 + mySharedConverterData = ucnv_load(pArgs, err); 1.830 + umtx_unlock(&cnvCacheMutex); 1.831 + if (U_FAILURE (*err) || (mySharedConverterData == NULL)) 1.832 + { 1.833 + return NULL; 1.834 + } 1.835 + } 1.836 + 1.837 + return mySharedConverterData; 1.838 +} 1.839 + 1.840 +U_CAPI UConverter * 1.841 +ucnv_createConverter(UConverter *myUConverter, const char *converterName, UErrorCode * err) 1.842 +{ 1.843 + UConverterNamePieces stackPieces; 1.844 + UConverterLoadArgs stackArgs=UCNV_LOAD_ARGS_INITIALIZER; 1.845 + UConverterSharedData *mySharedConverterData; 1.846 + 1.847 + UTRACE_ENTRY_OC(UTRACE_UCNV_OPEN); 1.848 + 1.849 + if(U_SUCCESS(*err)) { 1.850 + UTRACE_DATA1(UTRACE_OPEN_CLOSE, "open converter %s", converterName); 1.851 + 1.852 + mySharedConverterData = ucnv_loadSharedData(converterName, &stackPieces, &stackArgs, err); 1.853 + 1.854 + myUConverter = ucnv_createConverterFromSharedData( 1.855 + myUConverter, mySharedConverterData, 1.856 + &stackArgs, 1.857 + err); 1.858 + 1.859 + if(U_SUCCESS(*err)) { 1.860 + UTRACE_EXIT_PTR_STATUS(myUConverter, *err); 1.861 + return myUConverter; 1.862 + } 1.863 + } 1.864 + 1.865 + /* exit with error */ 1.866 + UTRACE_EXIT_STATUS(*err); 1.867 + return NULL; 1.868 +} 1.869 + 1.870 +U_CFUNC UBool 1.871 +ucnv_canCreateConverter(const char *converterName, UErrorCode *err) { 1.872 + UConverter myUConverter; 1.873 + UConverterNamePieces stackPieces; 1.874 + UConverterLoadArgs stackArgs=UCNV_LOAD_ARGS_INITIALIZER; 1.875 + UConverterSharedData *mySharedConverterData; 1.876 + 1.877 + UTRACE_ENTRY_OC(UTRACE_UCNV_OPEN); 1.878 + 1.879 + if(U_SUCCESS(*err)) { 1.880 + UTRACE_DATA1(UTRACE_OPEN_CLOSE, "test if can open converter %s", converterName); 1.881 + 1.882 + stackArgs.onlyTestIsLoadable=TRUE; 1.883 + mySharedConverterData = ucnv_loadSharedData(converterName, &stackPieces, &stackArgs, err); 1.884 + ucnv_createConverterFromSharedData( 1.885 + &myUConverter, mySharedConverterData, 1.886 + &stackArgs, 1.887 + err); 1.888 + ucnv_unloadSharedDataIfReady(mySharedConverterData); 1.889 + } 1.890 + 1.891 + UTRACE_EXIT_STATUS(*err); 1.892 + return U_SUCCESS(*err); 1.893 +} 1.894 + 1.895 +UConverter * 1.896 +ucnv_createAlgorithmicConverter(UConverter *myUConverter, 1.897 + UConverterType type, 1.898 + const char *locale, uint32_t options, 1.899 + UErrorCode *err) { 1.900 + UConverter *cnv; 1.901 + const UConverterSharedData *sharedData; 1.902 + UConverterLoadArgs stackArgs=UCNV_LOAD_ARGS_INITIALIZER; 1.903 + 1.904 + UTRACE_ENTRY_OC(UTRACE_UCNV_OPEN_ALGORITHMIC); 1.905 + UTRACE_DATA1(UTRACE_OPEN_CLOSE, "open algorithmic converter type %d", (int32_t)type); 1.906 + 1.907 + if(type<0 || UCNV_NUMBER_OF_SUPPORTED_CONVERTER_TYPES<=type) { 1.908 + *err = U_ILLEGAL_ARGUMENT_ERROR; 1.909 + UTRACE_EXIT_STATUS(U_ILLEGAL_ARGUMENT_ERROR); 1.910 + return NULL; 1.911 + } 1.912 + 1.913 + sharedData = converterData[type]; 1.914 + /* 1.915 + Checking whether it's an algorithic converter is okay 1.916 + in multithreaded applications because the value never changes. 1.917 + Don't check referenceCounter for any other value. 1.918 + */ 1.919 + if(sharedData == NULL || sharedData->referenceCounter != (uint32_t)~0) { 1.920 + /* not a valid type, or not an algorithmic converter */ 1.921 + *err = U_ILLEGAL_ARGUMENT_ERROR; 1.922 + UTRACE_EXIT_STATUS(U_ILLEGAL_ARGUMENT_ERROR); 1.923 + return NULL; 1.924 + } 1.925 + 1.926 + stackArgs.name = ""; 1.927 + stackArgs.options = options; 1.928 + stackArgs.locale=locale; 1.929 + cnv = ucnv_createConverterFromSharedData( 1.930 + myUConverter, (UConverterSharedData *)sharedData, 1.931 + &stackArgs, err); 1.932 + 1.933 + UTRACE_EXIT_PTR_STATUS(cnv, *err); 1.934 + return cnv; 1.935 +} 1.936 + 1.937 +U_CFUNC UConverter* 1.938 +ucnv_createConverterFromPackage(const char *packageName, const char *converterName, UErrorCode * err) 1.939 +{ 1.940 + UConverter *myUConverter; 1.941 + UConverterSharedData *mySharedConverterData; 1.942 + UConverterNamePieces stackPieces; 1.943 + UConverterLoadArgs stackArgs=UCNV_LOAD_ARGS_INITIALIZER; 1.944 + 1.945 + UTRACE_ENTRY_OC(UTRACE_UCNV_OPEN_PACKAGE); 1.946 + 1.947 + if(U_FAILURE(*err)) { 1.948 + UTRACE_EXIT_STATUS(*err); 1.949 + return NULL; 1.950 + } 1.951 + 1.952 + UTRACE_DATA2(UTRACE_OPEN_CLOSE, "open converter %s from package %s", converterName, packageName); 1.953 + 1.954 + /* first, get the options out of the converterName string */ 1.955 + stackPieces.cnvName[0] = 0; 1.956 + stackPieces.locale[0] = 0; 1.957 + stackPieces.options = 0; 1.958 + parseConverterOptions(converterName, &stackPieces, &stackArgs, err); 1.959 + if (U_FAILURE(*err)) { 1.960 + /* Very bad name used. */ 1.961 + UTRACE_EXIT_STATUS(*err); 1.962 + return NULL; 1.963 + } 1.964 + stackArgs.nestedLoads=1; 1.965 + stackArgs.pkg=packageName; 1.966 + 1.967 + /* open the data, unflatten the shared structure */ 1.968 + mySharedConverterData = createConverterFromFile(&stackArgs, err); 1.969 + 1.970 + if (U_FAILURE(*err)) { 1.971 + UTRACE_EXIT_STATUS(*err); 1.972 + return NULL; 1.973 + } 1.974 + 1.975 + /* create the actual converter */ 1.976 + myUConverter = ucnv_createConverterFromSharedData(NULL, mySharedConverterData, &stackArgs, err); 1.977 + 1.978 + if (U_FAILURE(*err)) { 1.979 + ucnv_close(myUConverter); 1.980 + UTRACE_EXIT_STATUS(*err); 1.981 + return NULL; 1.982 + } 1.983 + 1.984 + UTRACE_EXIT_PTR_STATUS(myUConverter, *err); 1.985 + return myUConverter; 1.986 +} 1.987 + 1.988 + 1.989 +U_CFUNC UConverter* 1.990 +ucnv_createConverterFromSharedData(UConverter *myUConverter, 1.991 + UConverterSharedData *mySharedConverterData, 1.992 + UConverterLoadArgs *pArgs, 1.993 + UErrorCode *err) 1.994 +{ 1.995 + UBool isCopyLocal; 1.996 + 1.997 + if(U_FAILURE(*err)) { 1.998 + ucnv_unloadSharedDataIfReady(mySharedConverterData); 1.999 + return myUConverter; 1.1000 + } 1.1001 + if(myUConverter == NULL) 1.1002 + { 1.1003 + myUConverter = (UConverter *) uprv_malloc (sizeof (UConverter)); 1.1004 + if(myUConverter == NULL) 1.1005 + { 1.1006 + *err = U_MEMORY_ALLOCATION_ERROR; 1.1007 + ucnv_unloadSharedDataIfReady(mySharedConverterData); 1.1008 + return NULL; 1.1009 + } 1.1010 + isCopyLocal = FALSE; 1.1011 + } else { 1.1012 + isCopyLocal = TRUE; 1.1013 + } 1.1014 + 1.1015 + /* initialize the converter */ 1.1016 + uprv_memset(myUConverter, 0, sizeof(UConverter)); 1.1017 + myUConverter->isCopyLocal = isCopyLocal; 1.1018 + /*myUConverter->isExtraLocal = FALSE;*/ /* Set by the memset call */ 1.1019 + myUConverter->sharedData = mySharedConverterData; 1.1020 + myUConverter->options = pArgs->options; 1.1021 + if(!pArgs->onlyTestIsLoadable) { 1.1022 + myUConverter->preFromUFirstCP = U_SENTINEL; 1.1023 + myUConverter->fromCharErrorBehaviour = UCNV_TO_U_DEFAULT_CALLBACK; 1.1024 + myUConverter->fromUCharErrorBehaviour = UCNV_FROM_U_DEFAULT_CALLBACK; 1.1025 + myUConverter->toUnicodeStatus = mySharedConverterData->toUnicodeStatus; 1.1026 + myUConverter->maxBytesPerUChar = mySharedConverterData->staticData->maxBytesPerChar; 1.1027 + myUConverter->subChar1 = mySharedConverterData->staticData->subChar1; 1.1028 + myUConverter->subCharLen = mySharedConverterData->staticData->subCharLen; 1.1029 + myUConverter->subChars = (uint8_t *)myUConverter->subUChars; 1.1030 + uprv_memcpy(myUConverter->subChars, mySharedConverterData->staticData->subChar, myUConverter->subCharLen); 1.1031 + myUConverter->toUCallbackReason = UCNV_ILLEGAL; /* default reason to invoke (*fromCharErrorBehaviour) */ 1.1032 + } 1.1033 + 1.1034 + if(mySharedConverterData->impl->open != NULL) { 1.1035 + mySharedConverterData->impl->open(myUConverter, pArgs, err); 1.1036 + if(U_FAILURE(*err) && !pArgs->onlyTestIsLoadable) { 1.1037 + /* don't ucnv_close() if onlyTestIsLoadable because not fully initialized */ 1.1038 + ucnv_close(myUConverter); 1.1039 + return NULL; 1.1040 + } 1.1041 + } 1.1042 + 1.1043 + return myUConverter; 1.1044 +} 1.1045 + 1.1046 +/*Frees all shared immutable objects that aren't referred to (reference count = 0) 1.1047 + */ 1.1048 +U_CAPI int32_t U_EXPORT2 1.1049 +ucnv_flushCache () 1.1050 +{ 1.1051 + UConverterSharedData *mySharedData = NULL; 1.1052 + int32_t pos; 1.1053 + int32_t tableDeletedNum = 0; 1.1054 + const UHashElement *e; 1.1055 + /*UErrorCode status = U_ILLEGAL_ARGUMENT_ERROR;*/ 1.1056 + int32_t i, remaining; 1.1057 + 1.1058 + UTRACE_ENTRY_OC(UTRACE_UCNV_FLUSH_CACHE); 1.1059 + 1.1060 + /* Close the default converter without creating a new one so that everything will be flushed. */ 1.1061 + u_flushDefaultConverter(); 1.1062 + 1.1063 + /*if shared data hasn't even been lazy evaluated yet 1.1064 + * return 0 1.1065 + */ 1.1066 + if (SHARED_DATA_HASHTABLE == NULL) { 1.1067 + UTRACE_EXIT_VALUE((int32_t)0); 1.1068 + return 0; 1.1069 + } 1.1070 + 1.1071 + /*creates an enumeration to iterate through every element in the 1.1072 + * table 1.1073 + * 1.1074 + * Synchronization: holding cnvCacheMutex will prevent any other thread from 1.1075 + * accessing or modifying the hash table during the iteration. 1.1076 + * The reference count of an entry may be decremented by 1.1077 + * ucnv_close while the iteration is in process, but this is 1.1078 + * benign. It can't be incremented (in ucnv_createConverter()) 1.1079 + * because the sequence of looking up in the cache + incrementing 1.1080 + * is protected by cnvCacheMutex. 1.1081 + */ 1.1082 + umtx_lock(&cnvCacheMutex); 1.1083 + /* 1.1084 + * double loop: A delta/extension-only converter has a pointer to its base table's 1.1085 + * shared data; the first iteration of the outer loop may see the delta converter 1.1086 + * before the base converter, and unloading the delta converter may get the base 1.1087 + * converter's reference counter down to 0. 1.1088 + */ 1.1089 + i = 0; 1.1090 + do { 1.1091 + remaining = 0; 1.1092 + pos = -1; 1.1093 + while ((e = uhash_nextElement (SHARED_DATA_HASHTABLE, &pos)) != NULL) 1.1094 + { 1.1095 + mySharedData = (UConverterSharedData *) e->value.pointer; 1.1096 + /*deletes only if reference counter == 0 */ 1.1097 + if (mySharedData->referenceCounter == 0) 1.1098 + { 1.1099 + tableDeletedNum++; 1.1100 + 1.1101 + UCNV_DEBUG_LOG("del",mySharedData->staticData->name,mySharedData); 1.1102 + 1.1103 + uhash_removeElement(SHARED_DATA_HASHTABLE, e); 1.1104 + mySharedData->sharedDataCached = FALSE; 1.1105 + ucnv_deleteSharedConverterData (mySharedData); 1.1106 + } else { 1.1107 + ++remaining; 1.1108 + } 1.1109 + } 1.1110 + } while(++i == 1 && remaining > 0); 1.1111 + umtx_unlock(&cnvCacheMutex); 1.1112 + 1.1113 + UTRACE_DATA1(UTRACE_INFO, "ucnv_flushCache() exits with %d converters remaining", remaining); 1.1114 + 1.1115 + UTRACE_EXIT_VALUE(tableDeletedNum); 1.1116 + return tableDeletedNum; 1.1117 +} 1.1118 + 1.1119 +/* available converters list --------------------------------------------------- */ 1.1120 + 1.1121 +static void U_CALLCONV initAvailableConvertersList(UErrorCode &errCode) { 1.1122 + U_ASSERT(gAvailableConverterCount == 0); 1.1123 + U_ASSERT(gAvailableConverters == NULL); 1.1124 + 1.1125 + ucln_common_registerCleanup(UCLN_COMMON_UCNV, ucnv_cleanup); 1.1126 + UEnumeration *allConvEnum = ucnv_openAllNames(&errCode); 1.1127 + int32_t allConverterCount = uenum_count(allConvEnum, &errCode); 1.1128 + if (U_FAILURE(errCode)) { 1.1129 + return; 1.1130 + } 1.1131 + 1.1132 + /* We can't have more than "*converterTable" converters to open */ 1.1133 + gAvailableConverters = (const char **) uprv_malloc(allConverterCount * sizeof(char*)); 1.1134 + if (!gAvailableConverters) { 1.1135 + errCode = U_MEMORY_ALLOCATION_ERROR; 1.1136 + return; 1.1137 + } 1.1138 + 1.1139 + /* Open the default converter to make sure that it has first dibs in the hash table. */ 1.1140 + UErrorCode localStatus = U_ZERO_ERROR; 1.1141 + UConverter tempConverter; 1.1142 + ucnv_close(ucnv_createConverter(&tempConverter, NULL, &localStatus)); 1.1143 + 1.1144 + gAvailableConverterCount = 0; 1.1145 + 1.1146 + for (int32_t idx = 0; idx < allConverterCount; idx++) { 1.1147 + localStatus = U_ZERO_ERROR; 1.1148 + const char *converterName = uenum_next(allConvEnum, NULL, &localStatus); 1.1149 + if (ucnv_canCreateConverter(converterName, &localStatus)) { 1.1150 + gAvailableConverters[gAvailableConverterCount++] = converterName; 1.1151 + } 1.1152 + } 1.1153 + 1.1154 + uenum_close(allConvEnum); 1.1155 +} 1.1156 + 1.1157 + 1.1158 +static UBool haveAvailableConverterList(UErrorCode *pErrorCode) { 1.1159 + umtx_initOnce(gAvailableConvertersInitOnce, &initAvailableConvertersList, *pErrorCode); 1.1160 + return U_SUCCESS(*pErrorCode); 1.1161 +} 1.1162 + 1.1163 +U_CFUNC uint16_t 1.1164 +ucnv_bld_countAvailableConverters(UErrorCode *pErrorCode) { 1.1165 + if (haveAvailableConverterList(pErrorCode)) { 1.1166 + return gAvailableConverterCount; 1.1167 + } 1.1168 + return 0; 1.1169 +} 1.1170 + 1.1171 +U_CFUNC const char * 1.1172 +ucnv_bld_getAvailableConverter(uint16_t n, UErrorCode *pErrorCode) { 1.1173 + if (haveAvailableConverterList(pErrorCode)) { 1.1174 + if (n < gAvailableConverterCount) { 1.1175 + return gAvailableConverters[n]; 1.1176 + } 1.1177 + *pErrorCode = U_INDEX_OUTOFBOUNDS_ERROR; 1.1178 + } 1.1179 + return NULL; 1.1180 +} 1.1181 + 1.1182 +/* default converter name --------------------------------------------------- */ 1.1183 + 1.1184 +#if !U_CHARSET_IS_UTF8 1.1185 +/* 1.1186 +Copy the canonical converter name. 1.1187 +ucnv_getDefaultName must be thread safe, which can call this function. 1.1188 + 1.1189 +ucnv_setDefaultName calls this function and it doesn't have to be 1.1190 +thread safe because there is no reliable/safe way to reset the 1.1191 +converter in use in all threads. If you did reset the converter, you 1.1192 +would not be sure that retrieving a default converter for one string 1.1193 +would be the same type of default converter for a successive string. 1.1194 +Since the name is a returned via ucnv_getDefaultName without copying, 1.1195 +you shouldn't be modifying or deleting the string from a separate thread. 1.1196 +*/ 1.1197 +static inline void 1.1198 +internalSetName(const char *name, UErrorCode *status) { 1.1199 + UConverterNamePieces stackPieces; 1.1200 + UConverterLoadArgs stackArgs=UCNV_LOAD_ARGS_INITIALIZER; 1.1201 + int32_t length=(int32_t)(uprv_strlen(name)); 1.1202 + UBool containsOption = (UBool)(uprv_strchr(name, UCNV_OPTION_SEP_CHAR) != NULL); 1.1203 + const UConverterSharedData *algorithmicSharedData; 1.1204 + 1.1205 + stackArgs.name = name; 1.1206 + if(containsOption) { 1.1207 + stackPieces.cnvName[0] = 0; 1.1208 + stackPieces.locale[0] = 0; 1.1209 + stackPieces.options = 0; 1.1210 + parseConverterOptions(name, &stackPieces, &stackArgs, status); 1.1211 + if(U_FAILURE(*status)) { 1.1212 + return; 1.1213 + } 1.1214 + } 1.1215 + algorithmicSharedData = getAlgorithmicTypeFromName(stackArgs.name); 1.1216 + 1.1217 + umtx_lock(&cnvCacheMutex); 1.1218 + 1.1219 + gDefaultAlgorithmicSharedData = algorithmicSharedData; 1.1220 + gDefaultConverterContainsOption = containsOption; 1.1221 + uprv_memcpy(gDefaultConverterNameBuffer, name, length); 1.1222 + gDefaultConverterNameBuffer[length]=0; 1.1223 + 1.1224 + /* gDefaultConverterName MUST be the last global var set by this function. */ 1.1225 + /* It is the variable checked in ucnv_getDefaultName() to see if initialization is required. */ 1.1226 + // But there is nothing here preventing that from being reordered, either by the compiler 1.1227 + // or hardware. I'm adding the mutex to ucnv_getDefaultName for now. UMTX_CHECK is not enough. 1.1228 + // -- Andy 1.1229 + gDefaultConverterName = gDefaultConverterNameBuffer; 1.1230 + 1.1231 + ucln_common_registerCleanup(UCLN_COMMON_UCNV, ucnv_cleanup); 1.1232 + 1.1233 + umtx_unlock(&cnvCacheMutex); 1.1234 +} 1.1235 +#endif 1.1236 + 1.1237 +/* 1.1238 + * In order to be really thread-safe, the get function would have to take 1.1239 + * a buffer parameter and copy the current string inside a mutex block. 1.1240 + * This implementation only tries to be really thread-safe while 1.1241 + * setting the name. 1.1242 + * It assumes that setting a pointer is atomic. 1.1243 + */ 1.1244 + 1.1245 +U_CAPI const char* U_EXPORT2 1.1246 +ucnv_getDefaultName() { 1.1247 +#if U_CHARSET_IS_UTF8 1.1248 + return "UTF-8"; 1.1249 +#else 1.1250 + /* local variable to be thread-safe */ 1.1251 + const char *name; 1.1252 + 1.1253 + /* 1.1254 + Concurrent calls to ucnv_getDefaultName must be thread safe, 1.1255 + but ucnv_setDefaultName is not thread safe. 1.1256 + */ 1.1257 + { 1.1258 + icu::Mutex lock(&cnvCacheMutex); 1.1259 + name = gDefaultConverterName; 1.1260 + } 1.1261 + if(name==NULL) { 1.1262 + UErrorCode errorCode = U_ZERO_ERROR; 1.1263 + UConverter *cnv = NULL; 1.1264 + 1.1265 + name = uprv_getDefaultCodepage(); 1.1266 + 1.1267 + /* if the name is there, test it out and get the canonical name with options */ 1.1268 + if(name != NULL) { 1.1269 + cnv = ucnv_open(name, &errorCode); 1.1270 + if(U_SUCCESS(errorCode) && cnv != NULL) { 1.1271 + name = ucnv_getName(cnv, &errorCode); 1.1272 + } 1.1273 + } 1.1274 + 1.1275 + if(name == NULL || name[0] == 0 1.1276 + || U_FAILURE(errorCode) || cnv == NULL 1.1277 + || uprv_strlen(name)>=sizeof(gDefaultConverterNameBuffer)) 1.1278 + { 1.1279 + /* Panic time, let's use a fallback. */ 1.1280 +#if (U_CHARSET_FAMILY == U_ASCII_FAMILY) 1.1281 + name = "US-ASCII"; 1.1282 + /* there is no 'algorithmic' converter for EBCDIC */ 1.1283 +#elif U_PLATFORM == U_PF_OS390 1.1284 + name = "ibm-1047_P100-1995" UCNV_SWAP_LFNL_OPTION_STRING; 1.1285 +#else 1.1286 + name = "ibm-37_P100-1995"; 1.1287 +#endif 1.1288 + } 1.1289 + 1.1290 + internalSetName(name, &errorCode); 1.1291 + 1.1292 + /* The close may make the current name go away. */ 1.1293 + ucnv_close(cnv); 1.1294 + } 1.1295 + 1.1296 + return name; 1.1297 +#endif 1.1298 +} 1.1299 + 1.1300 +#if U_CHARSET_IS_UTF8 1.1301 +U_CAPI void U_EXPORT2 ucnv_setDefaultName(const char *) {} 1.1302 +#else 1.1303 +/* 1.1304 +This function is not thread safe, and it can't be thread safe. 1.1305 +See internalSetName or the API reference for details. 1.1306 +*/ 1.1307 +U_CAPI void U_EXPORT2 1.1308 +ucnv_setDefaultName(const char *converterName) { 1.1309 + if(converterName==NULL) { 1.1310 + /* reset to the default codepage */ 1.1311 + gDefaultConverterName=NULL; 1.1312 + } else { 1.1313 + UErrorCode errorCode = U_ZERO_ERROR; 1.1314 + UConverter *cnv = NULL; 1.1315 + const char *name = NULL; 1.1316 + 1.1317 + /* if the name is there, test it out and get the canonical name with options */ 1.1318 + cnv = ucnv_open(converterName, &errorCode); 1.1319 + if(U_SUCCESS(errorCode) && cnv != NULL) { 1.1320 + name = ucnv_getName(cnv, &errorCode); 1.1321 + } 1.1322 + 1.1323 + if(U_SUCCESS(errorCode) && name!=NULL) { 1.1324 + internalSetName(name, &errorCode); 1.1325 + } 1.1326 + /* else this converter is bad to use. Don't change it to a bad value. */ 1.1327 + 1.1328 + /* The close may make the current name go away. */ 1.1329 + ucnv_close(cnv); 1.1330 + 1.1331 + /* reset the converter cache */ 1.1332 + u_flushDefaultConverter(); 1.1333 + } 1.1334 +} 1.1335 +#endif 1.1336 + 1.1337 +/* data swapping ------------------------------------------------------------ */ 1.1338 + 1.1339 +/* most of this might belong more properly into ucnvmbcs.c, but that is so large */ 1.1340 + 1.1341 +#if !UCONFIG_NO_LEGACY_CONVERSION 1.1342 + 1.1343 +U_CAPI int32_t U_EXPORT2 1.1344 +ucnv_swap(const UDataSwapper *ds, 1.1345 + const void *inData, int32_t length, void *outData, 1.1346 + UErrorCode *pErrorCode) { 1.1347 + const UDataInfo *pInfo; 1.1348 + int32_t headerSize; 1.1349 + 1.1350 + const uint8_t *inBytes; 1.1351 + uint8_t *outBytes; 1.1352 + 1.1353 + uint32_t offset, count, staticDataSize; 1.1354 + int32_t size; 1.1355 + 1.1356 + const UConverterStaticData *inStaticData; 1.1357 + UConverterStaticData *outStaticData; 1.1358 + 1.1359 + const _MBCSHeader *inMBCSHeader; 1.1360 + _MBCSHeader *outMBCSHeader; 1.1361 + _MBCSHeader mbcsHeader; 1.1362 + uint32_t mbcsHeaderLength; 1.1363 + UBool noFromU=FALSE; 1.1364 + 1.1365 + uint8_t outputType; 1.1366 + 1.1367 + int32_t maxFastUChar, mbcsIndexLength; 1.1368 + 1.1369 + const int32_t *inExtIndexes; 1.1370 + int32_t extOffset; 1.1371 + 1.1372 + /* udata_swapDataHeader checks the arguments */ 1.1373 + headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode); 1.1374 + if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 1.1375 + return 0; 1.1376 + } 1.1377 + 1.1378 + /* check data format and format version */ 1.1379 + pInfo=(const UDataInfo *)((const char *)inData+4); 1.1380 + if(!( 1.1381 + pInfo->dataFormat[0]==0x63 && /* dataFormat="cnvt" */ 1.1382 + pInfo->dataFormat[1]==0x6e && 1.1383 + pInfo->dataFormat[2]==0x76 && 1.1384 + pInfo->dataFormat[3]==0x74 && 1.1385 + pInfo->formatVersion[0]==6 && 1.1386 + pInfo->formatVersion[1]>=2 1.1387 + )) { 1.1388 + 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", 1.1389 + pInfo->dataFormat[0], pInfo->dataFormat[1], 1.1390 + pInfo->dataFormat[2], pInfo->dataFormat[3], 1.1391 + pInfo->formatVersion[0], pInfo->formatVersion[1]); 1.1392 + *pErrorCode=U_UNSUPPORTED_ERROR; 1.1393 + return 0; 1.1394 + } 1.1395 + 1.1396 + inBytes=(const uint8_t *)inData+headerSize; 1.1397 + outBytes=(uint8_t *)outData+headerSize; 1.1398 + 1.1399 + /* read the initial UConverterStaticData structure after the UDataInfo header */ 1.1400 + inStaticData=(const UConverterStaticData *)inBytes; 1.1401 + outStaticData=(UConverterStaticData *)outBytes; 1.1402 + 1.1403 + if(length<0) { 1.1404 + staticDataSize=ds->readUInt32(inStaticData->structSize); 1.1405 + } else { 1.1406 + length-=headerSize; 1.1407 + if( length<(int32_t)sizeof(UConverterStaticData) || 1.1408 + (uint32_t)length<(staticDataSize=ds->readUInt32(inStaticData->structSize)) 1.1409 + ) { 1.1410 + udata_printError(ds, "ucnv_swap(): too few bytes (%d after header) for an ICU .cnv conversion table\n", 1.1411 + length); 1.1412 + *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; 1.1413 + return 0; 1.1414 + } 1.1415 + } 1.1416 + 1.1417 + if(length>=0) { 1.1418 + /* swap the static data */ 1.1419 + if(inStaticData!=outStaticData) { 1.1420 + uprv_memcpy(outStaticData, inStaticData, staticDataSize); 1.1421 + } 1.1422 + 1.1423 + ds->swapArray32(ds, &inStaticData->structSize, 4, 1.1424 + &outStaticData->structSize, pErrorCode); 1.1425 + ds->swapArray32(ds, &inStaticData->codepage, 4, 1.1426 + &outStaticData->codepage, pErrorCode); 1.1427 + 1.1428 + ds->swapInvChars(ds, inStaticData->name, (int32_t)uprv_strlen(inStaticData->name), 1.1429 + outStaticData->name, pErrorCode); 1.1430 + if(U_FAILURE(*pErrorCode)) { 1.1431 + udata_printError(ds, "ucnv_swap(): error swapping converter name\n"); 1.1432 + return 0; 1.1433 + } 1.1434 + } 1.1435 + 1.1436 + inBytes+=staticDataSize; 1.1437 + outBytes+=staticDataSize; 1.1438 + if(length>=0) { 1.1439 + length-=(int32_t)staticDataSize; 1.1440 + } 1.1441 + 1.1442 + /* check for supported conversionType values */ 1.1443 + if(inStaticData->conversionType==UCNV_MBCS) { 1.1444 + /* swap MBCS data */ 1.1445 + inMBCSHeader=(const _MBCSHeader *)inBytes; 1.1446 + outMBCSHeader=(_MBCSHeader *)outBytes; 1.1447 + 1.1448 + if(0<=length && length<(int32_t)sizeof(_MBCSHeader)) { 1.1449 + udata_printError(ds, "ucnv_swap(): too few bytes (%d after headers) for an ICU MBCS .cnv conversion table\n", 1.1450 + length); 1.1451 + *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; 1.1452 + return 0; 1.1453 + } 1.1454 + if(inMBCSHeader->version[0]==4 && inMBCSHeader->version[1]>=1) { 1.1455 + mbcsHeaderLength=MBCS_HEADER_V4_LENGTH; 1.1456 + } else if(inMBCSHeader->version[0]==5 && inMBCSHeader->version[1]>=3 && 1.1457 + ((mbcsHeader.options=ds->readUInt32(inMBCSHeader->options))& 1.1458 + MBCS_OPT_UNKNOWN_INCOMPATIBLE_MASK)==0 1.1459 + ) { 1.1460 + mbcsHeaderLength=mbcsHeader.options&MBCS_OPT_LENGTH_MASK; 1.1461 + noFromU=(UBool)((mbcsHeader.options&MBCS_OPT_NO_FROM_U)!=0); 1.1462 + } else { 1.1463 + udata_printError(ds, "ucnv_swap(): unsupported _MBCSHeader.version %d.%d\n", 1.1464 + inMBCSHeader->version[0], inMBCSHeader->version[1]); 1.1465 + *pErrorCode=U_UNSUPPORTED_ERROR; 1.1466 + return 0; 1.1467 + } 1.1468 + 1.1469 + uprv_memcpy(mbcsHeader.version, inMBCSHeader->version, 4); 1.1470 + mbcsHeader.countStates= ds->readUInt32(inMBCSHeader->countStates); 1.1471 + mbcsHeader.countToUFallbacks= ds->readUInt32(inMBCSHeader->countToUFallbacks); 1.1472 + mbcsHeader.offsetToUCodeUnits= ds->readUInt32(inMBCSHeader->offsetToUCodeUnits); 1.1473 + mbcsHeader.offsetFromUTable= ds->readUInt32(inMBCSHeader->offsetFromUTable); 1.1474 + mbcsHeader.offsetFromUBytes= ds->readUInt32(inMBCSHeader->offsetFromUBytes); 1.1475 + mbcsHeader.flags= ds->readUInt32(inMBCSHeader->flags); 1.1476 + mbcsHeader.fromUBytesLength= ds->readUInt32(inMBCSHeader->fromUBytesLength); 1.1477 + /* mbcsHeader.options have been read above */ 1.1478 + 1.1479 + extOffset=(int32_t)(mbcsHeader.flags>>8); 1.1480 + outputType=(uint8_t)mbcsHeader.flags; 1.1481 + if(noFromU && outputType==MBCS_OUTPUT_1) { 1.1482 + udata_printError(ds, "ucnv_swap(): unsupported combination of makeconv --small with SBCS\n"); 1.1483 + *pErrorCode=U_UNSUPPORTED_ERROR; 1.1484 + return 0; 1.1485 + } 1.1486 + 1.1487 + /* make sure that the output type is known */ 1.1488 + switch(outputType) { 1.1489 + case MBCS_OUTPUT_1: 1.1490 + case MBCS_OUTPUT_2: 1.1491 + case MBCS_OUTPUT_3: 1.1492 + case MBCS_OUTPUT_4: 1.1493 + case MBCS_OUTPUT_3_EUC: 1.1494 + case MBCS_OUTPUT_4_EUC: 1.1495 + case MBCS_OUTPUT_2_SISO: 1.1496 + case MBCS_OUTPUT_EXT_ONLY: 1.1497 + /* OK */ 1.1498 + break; 1.1499 + default: 1.1500 + udata_printError(ds, "ucnv_swap(): unsupported MBCS output type 0x%x\n", 1.1501 + outputType); 1.1502 + *pErrorCode=U_UNSUPPORTED_ERROR; 1.1503 + return 0; 1.1504 + } 1.1505 + 1.1506 + /* calculate the length of the MBCS data */ 1.1507 + 1.1508 + /* 1.1509 + * utf8Friendly MBCS files (mbcsHeader.version 4.3) 1.1510 + * contain an additional mbcsIndex table: 1.1511 + * uint16_t[(maxFastUChar+1)>>6]; 1.1512 + * where maxFastUChar=((mbcsHeader.version[2]<<8)|0xff). 1.1513 + */ 1.1514 + maxFastUChar=0; 1.1515 + mbcsIndexLength=0; 1.1516 + if( outputType!=MBCS_OUTPUT_EXT_ONLY && outputType!=MBCS_OUTPUT_1 && 1.1517 + mbcsHeader.version[1]>=3 && (maxFastUChar=mbcsHeader.version[2])!=0 1.1518 + ) { 1.1519 + maxFastUChar=(maxFastUChar<<8)|0xff; 1.1520 + mbcsIndexLength=((maxFastUChar+1)>>6)*2; /* number of bytes */ 1.1521 + } 1.1522 + 1.1523 + if(extOffset==0) { 1.1524 + size=(int32_t)(mbcsHeader.offsetFromUBytes+mbcsIndexLength); 1.1525 + if(!noFromU) { 1.1526 + size+=(int32_t)mbcsHeader.fromUBytesLength; 1.1527 + } 1.1528 + 1.1529 + /* avoid compiler warnings - not otherwise necessary, and the value does not matter */ 1.1530 + inExtIndexes=NULL; 1.1531 + } else { 1.1532 + /* there is extension data after the base data, see ucnv_ext.h */ 1.1533 + if(length>=0 && length<(extOffset+UCNV_EXT_INDEXES_MIN_LENGTH*4)) { 1.1534 + udata_printError(ds, "ucnv_swap(): too few bytes (%d after headers) for an ICU MBCS .cnv conversion table with extension data\n", 1.1535 + length); 1.1536 + *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; 1.1537 + return 0; 1.1538 + } 1.1539 + 1.1540 + inExtIndexes=(const int32_t *)(inBytes+extOffset); 1.1541 + size=extOffset+udata_readInt32(ds, inExtIndexes[UCNV_EXT_SIZE]); 1.1542 + } 1.1543 + 1.1544 + if(length>=0) { 1.1545 + if(length<size) { 1.1546 + udata_printError(ds, "ucnv_swap(): too few bytes (%d after headers) for an ICU MBCS .cnv conversion table\n", 1.1547 + length); 1.1548 + *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; 1.1549 + return 0; 1.1550 + } 1.1551 + 1.1552 + /* copy the data for inaccessible bytes */ 1.1553 + if(inBytes!=outBytes) { 1.1554 + uprv_memcpy(outBytes, inBytes, size); 1.1555 + } 1.1556 + 1.1557 + /* swap the MBCSHeader, except for the version field */ 1.1558 + count=mbcsHeaderLength*4; 1.1559 + ds->swapArray32(ds, &inMBCSHeader->countStates, count-4, 1.1560 + &outMBCSHeader->countStates, pErrorCode); 1.1561 + 1.1562 + if(outputType==MBCS_OUTPUT_EXT_ONLY) { 1.1563 + /* 1.1564 + * extension-only file, 1.1565 + * contains a base name instead of normal base table data 1.1566 + */ 1.1567 + 1.1568 + /* swap the base name, between the header and the extension data */ 1.1569 + const char *inBaseName=(const char *)inBytes+count; 1.1570 + char *outBaseName=(char *)outBytes+count; 1.1571 + ds->swapInvChars(ds, inBaseName, (int32_t)uprv_strlen(inBaseName), 1.1572 + outBaseName, pErrorCode); 1.1573 + } else { 1.1574 + /* normal file with base table data */ 1.1575 + 1.1576 + /* swap the state table, 1kB per state */ 1.1577 + offset=count; 1.1578 + count=mbcsHeader.countStates*1024; 1.1579 + ds->swapArray32(ds, inBytes+offset, (int32_t)count, 1.1580 + outBytes+offset, pErrorCode); 1.1581 + 1.1582 + /* swap the toUFallbacks[] */ 1.1583 + offset+=count; 1.1584 + count=mbcsHeader.countToUFallbacks*8; 1.1585 + ds->swapArray32(ds, inBytes+offset, (int32_t)count, 1.1586 + outBytes+offset, pErrorCode); 1.1587 + 1.1588 + /* swap the unicodeCodeUnits[] */ 1.1589 + offset=mbcsHeader.offsetToUCodeUnits; 1.1590 + count=mbcsHeader.offsetFromUTable-offset; 1.1591 + ds->swapArray16(ds, inBytes+offset, (int32_t)count, 1.1592 + outBytes+offset, pErrorCode); 1.1593 + 1.1594 + /* offset to the stage 1 table, independent of the outputType */ 1.1595 + offset=mbcsHeader.offsetFromUTable; 1.1596 + 1.1597 + if(outputType==MBCS_OUTPUT_1) { 1.1598 + /* SBCS: swap the fromU tables, all 16 bits wide */ 1.1599 + count=(mbcsHeader.offsetFromUBytes-offset)+mbcsHeader.fromUBytesLength; 1.1600 + ds->swapArray16(ds, inBytes+offset, (int32_t)count, 1.1601 + outBytes+offset, pErrorCode); 1.1602 + } else { 1.1603 + /* otherwise: swap the stage tables separately */ 1.1604 + 1.1605 + /* stage 1 table: uint16_t[0x440 or 0x40] */ 1.1606 + if(inStaticData->unicodeMask&UCNV_HAS_SUPPLEMENTARY) { 1.1607 + count=0x440*2; /* for all of Unicode */ 1.1608 + } else { 1.1609 + count=0x40*2; /* only BMP */ 1.1610 + } 1.1611 + ds->swapArray16(ds, inBytes+offset, (int32_t)count, 1.1612 + outBytes+offset, pErrorCode); 1.1613 + 1.1614 + /* stage 2 table: uint32_t[] */ 1.1615 + offset+=count; 1.1616 + count=mbcsHeader.offsetFromUBytes-offset; 1.1617 + ds->swapArray32(ds, inBytes+offset, (int32_t)count, 1.1618 + outBytes+offset, pErrorCode); 1.1619 + 1.1620 + /* stage 3/result bytes: sometimes uint16_t[] or uint32_t[] */ 1.1621 + offset=mbcsHeader.offsetFromUBytes; 1.1622 + count= noFromU ? 0 : mbcsHeader.fromUBytesLength; 1.1623 + switch(outputType) { 1.1624 + case MBCS_OUTPUT_2: 1.1625 + case MBCS_OUTPUT_3_EUC: 1.1626 + case MBCS_OUTPUT_2_SISO: 1.1627 + ds->swapArray16(ds, inBytes+offset, (int32_t)count, 1.1628 + outBytes+offset, pErrorCode); 1.1629 + break; 1.1630 + case MBCS_OUTPUT_4: 1.1631 + ds->swapArray32(ds, inBytes+offset, (int32_t)count, 1.1632 + outBytes+offset, pErrorCode); 1.1633 + break; 1.1634 + default: 1.1635 + /* just uint8_t[], nothing to swap */ 1.1636 + break; 1.1637 + } 1.1638 + 1.1639 + if(mbcsIndexLength!=0) { 1.1640 + offset+=count; 1.1641 + count=mbcsIndexLength; 1.1642 + ds->swapArray16(ds, inBytes+offset, (int32_t)count, 1.1643 + outBytes+offset, pErrorCode); 1.1644 + } 1.1645 + } 1.1646 + } 1.1647 + 1.1648 + if(extOffset!=0) { 1.1649 + /* swap the extension data */ 1.1650 + inBytes+=extOffset; 1.1651 + outBytes+=extOffset; 1.1652 + 1.1653 + /* swap toUTable[] */ 1.1654 + offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_TO_U_INDEX]); 1.1655 + length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_TO_U_LENGTH]); 1.1656 + ds->swapArray32(ds, inBytes+offset, length*4, outBytes+offset, pErrorCode); 1.1657 + 1.1658 + /* swap toUUChars[] */ 1.1659 + offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_TO_U_UCHARS_INDEX]); 1.1660 + length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_TO_U_UCHARS_LENGTH]); 1.1661 + ds->swapArray16(ds, inBytes+offset, length*2, outBytes+offset, pErrorCode); 1.1662 + 1.1663 + /* swap fromUTableUChars[] */ 1.1664 + offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_UCHARS_INDEX]); 1.1665 + length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_LENGTH]); 1.1666 + ds->swapArray16(ds, inBytes+offset, length*2, outBytes+offset, pErrorCode); 1.1667 + 1.1668 + /* swap fromUTableValues[] */ 1.1669 + offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_VALUES_INDEX]); 1.1670 + /* same length as for fromUTableUChars[] */ 1.1671 + ds->swapArray32(ds, inBytes+offset, length*4, outBytes+offset, pErrorCode); 1.1672 + 1.1673 + /* no need to swap fromUBytes[] */ 1.1674 + 1.1675 + /* swap fromUStage12[] */ 1.1676 + offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_STAGE_12_INDEX]); 1.1677 + length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_STAGE_12_LENGTH]); 1.1678 + ds->swapArray16(ds, inBytes+offset, length*2, outBytes+offset, pErrorCode); 1.1679 + 1.1680 + /* swap fromUStage3[] */ 1.1681 + offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_STAGE_3_INDEX]); 1.1682 + length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_STAGE_3_LENGTH]); 1.1683 + ds->swapArray16(ds, inBytes+offset, length*2, outBytes+offset, pErrorCode); 1.1684 + 1.1685 + /* swap fromUStage3b[] */ 1.1686 + offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_STAGE_3B_INDEX]); 1.1687 + length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_STAGE_3B_LENGTH]); 1.1688 + ds->swapArray32(ds, inBytes+offset, length*4, outBytes+offset, pErrorCode); 1.1689 + 1.1690 + /* swap indexes[] */ 1.1691 + length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_INDEXES_LENGTH]); 1.1692 + ds->swapArray32(ds, inBytes, length*4, outBytes, pErrorCode); 1.1693 + } 1.1694 + } 1.1695 + } else { 1.1696 + udata_printError(ds, "ucnv_swap(): unknown conversionType=%d!=UCNV_MBCS\n", 1.1697 + inStaticData->conversionType); 1.1698 + *pErrorCode=U_UNSUPPORTED_ERROR; 1.1699 + return 0; 1.1700 + } 1.1701 + 1.1702 + return headerSize+(int32_t)staticDataSize+size; 1.1703 +} 1.1704 + 1.1705 +#endif /* #if !UCONFIG_NO_LEGACY_CONVERSION */ 1.1706 + 1.1707 +#endif