intl/icu/source/common/ucnv_bld.cpp

changeset 0
6474c204b198
     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

mercurial