1/*
2 ********************************************************************
3 * COPYRIGHT:
4 * Copyright (c) 1996-2013, International Business Machines Corporation and
5 * others. All Rights Reserved.
6 ********************************************************************
7 *
8 *  uconv_bld.cpp:
9 *
10 *  Defines functions that are used in the creation/initialization/deletion
11 *  of converters and related structures.
12 *  uses uconv_io.h routines to access disk information
13 *  is used by ucnv.h to implement public API create/delete/flushCache routines
14 * Modification History:
15 *
16 *   Date        Name        Description
17 *
18 *   06/20/2000  helena      OS/400 port changes; mostly typecast.
19 *   06/29/2000  helena      Major rewrite of the callback interface.
20*/
21
22#include "unicode/utypes.h"
23
24#if !UCONFIG_NO_CONVERSION
25
26#include "unicode/putil.h"
27#include "unicode/udata.h"
28#include "unicode/ucnv.h"
29#include "unicode/uloc.h"
30#include "mutex.h"
31#include "putilimp.h"
32#include "uassert.h"
33#include "utracimp.h"
34#include "ucnv_io.h"
35#include "ucnv_bld.h"
36#include "ucnvmbcs.h"
37#include "ucnv_ext.h"
38#include "ucnv_cnv.h"
39#include "ucnv_imp.h"
40#include "uhash.h"
41#include "umutex.h"
42#include "cstring.h"
43#include "cmemory.h"
44#include "ucln_cmn.h"
45#include "ustr_cnv.h"
46
47
48#if 0
49#include <stdio.h>
50extern void UCNV_DEBUG_LOG(char *what, char *who, void *p, int l);
51#define UCNV_DEBUG_LOG(x,y,z) UCNV_DEBUG_LOG(x,y,z,__LINE__)
52#else
53# define UCNV_DEBUG_LOG(x,y,z)
54#endif
55
56static const UConverterSharedData * const
57converterData[UCNV_NUMBER_OF_SUPPORTED_CONVERTER_TYPES]={
58    NULL, NULL,
59
60#if UCONFIG_NO_LEGACY_CONVERSION
61    NULL,
62#else
63    &_MBCSData,
64#endif
65
66    &_Latin1Data,
67    &_UTF8Data, &_UTF16BEData, &_UTF16LEData, &_UTF32BEData, &_UTF32LEData,
68    NULL,
69
70#if UCONFIG_NO_LEGACY_CONVERSION
71    NULL,
72    NULL, NULL, NULL, NULL, NULL, NULL,
73    NULL, NULL, NULL, NULL, NULL, NULL,
74    NULL,
75#else
76    &_ISO2022Data,
77    &_LMBCSData1,&_LMBCSData2, &_LMBCSData3, &_LMBCSData4, &_LMBCSData5, &_LMBCSData6,
78    &_LMBCSData8,&_LMBCSData11,&_LMBCSData16,&_LMBCSData17,&_LMBCSData18,&_LMBCSData19,
79    &_HZData,
80#endif
81
82    &_SCSUData,
83
84#if UCONFIG_NO_LEGACY_CONVERSION
85    NULL,
86#else
87    &_ISCIIData,
88#endif
89
90    &_ASCIIData,
91    &_UTF7Data, &_Bocu1Data, &_UTF16Data, &_UTF32Data, &_CESU8Data, &_IMAPData,
92
93#if UCONFIG_NO_LEGACY_CONVERSION
94    NULL,
95#else
96    &_CompoundTextData
97#endif
98};
99
100/* Please keep this in binary sorted order for getAlgorithmicTypeFromName.
101   Also the name should be in lower case and all spaces, dashes and underscores
102   removed
103*/
104static struct {
105  const char *name;
106  const UConverterType type;
107} const cnvNameType[] = {
108  { "bocu1", UCNV_BOCU1 },
109  { "cesu8", UCNV_CESU8 },
110#if !UCONFIG_NO_LEGACY_CONVERSION
111  { "hz",UCNV_HZ },
112#endif
113  { "imapmailboxname", UCNV_IMAP_MAILBOX },
114#if !UCONFIG_NO_LEGACY_CONVERSION
115  { "iscii", UCNV_ISCII },
116  { "iso2022", UCNV_ISO_2022 },
117#endif
118  { "iso88591", UCNV_LATIN_1 },
119#if !UCONFIG_NO_LEGACY_CONVERSION
120  { "lmbcs1", UCNV_LMBCS_1 },
121  { "lmbcs11",UCNV_LMBCS_11 },
122  { "lmbcs16",UCNV_LMBCS_16 },
123  { "lmbcs17",UCNV_LMBCS_17 },
124  { "lmbcs18",UCNV_LMBCS_18 },
125  { "lmbcs19",UCNV_LMBCS_19 },
126  { "lmbcs2", UCNV_LMBCS_2 },
127  { "lmbcs3", UCNV_LMBCS_3 },
128  { "lmbcs4", UCNV_LMBCS_4 },
129  { "lmbcs5", UCNV_LMBCS_5 },
130  { "lmbcs6", UCNV_LMBCS_6 },
131  { "lmbcs8", UCNV_LMBCS_8 },
132#endif
133  { "scsu", UCNV_SCSU },
134  { "usascii", UCNV_US_ASCII },
135  { "utf16", UCNV_UTF16 },
136  { "utf16be", UCNV_UTF16_BigEndian },
137  { "utf16le", UCNV_UTF16_LittleEndian },
138#if U_IS_BIG_ENDIAN
139  { "utf16oppositeendian", UCNV_UTF16_LittleEndian },
140  { "utf16platformendian", UCNV_UTF16_BigEndian },
141#else
142  { "utf16oppositeendian", UCNV_UTF16_BigEndian},
143  { "utf16platformendian", UCNV_UTF16_LittleEndian },
144#endif
145  { "utf32", UCNV_UTF32 },
146  { "utf32be", UCNV_UTF32_BigEndian },
147  { "utf32le", UCNV_UTF32_LittleEndian },
148#if U_IS_BIG_ENDIAN
149  { "utf32oppositeendian", UCNV_UTF32_LittleEndian },
150  { "utf32platformendian", UCNV_UTF32_BigEndian },
151#else
152  { "utf32oppositeendian", UCNV_UTF32_BigEndian },
153  { "utf32platformendian", UCNV_UTF32_LittleEndian },
154#endif
155  { "utf7", UCNV_UTF7 },
156  { "utf8", UCNV_UTF8 },
157  { "x11compoundtext", UCNV_COMPOUND_TEXT}
158};
159
160
161/*initializes some global variables */
162static UHashtable *SHARED_DATA_HASHTABLE = NULL;
163static UMutex cnvCacheMutex = U_MUTEX_INITIALIZER;  /* Mutex for synchronizing cnv cache access. */
164                                                    /*  Note:  the global mutex is used for      */
165                                                    /*         reference count updates.          */
166
167static const char **gAvailableConverters = NULL;
168static uint16_t gAvailableConverterCount = 0;
169static icu::UInitOnce gAvailableConvertersInitOnce = U_INITONCE_INITIALIZER;
170
171#if !U_CHARSET_IS_UTF8
172
173/* This contains the resolved converter name. So no further alias lookup is needed again. */
174static char gDefaultConverterNameBuffer[UCNV_MAX_CONVERTER_NAME_LENGTH + 1]; /* +1 for NULL */
175static const char *gDefaultConverterName = NULL;
176
177/*
178If the default converter is an algorithmic converter, this is the cached value.
179We don't cache a full UConverter and clone it because ucnv_clone doesn't have
180less overhead than an algorithmic open. We don't cache non-algorithmic converters
181because ucnv_flushCache must be able to unload the default converter and its table.
182*/
183static const UConverterSharedData *gDefaultAlgorithmicSharedData = NULL;
184
185/* Does gDefaultConverterName have a converter option and require extra parsing? */
186static UBool gDefaultConverterContainsOption;
187
188#endif  /* !U_CHARSET_IS_UTF8 */
189
190static const char DATA_TYPE[] = "cnv";
191
192/* ucnv_flushAvailableConverterCache. This is only called from ucnv_cleanup().
193 *                       If it is ever to be called from elsewhere, synchronization
194 *                       will need to be considered.
195 */
196static void
197ucnv_flushAvailableConverterCache() {
198    gAvailableConverterCount = 0;
199    if (gAvailableConverters) {
200        uprv_free((char **)gAvailableConverters);
201        gAvailableConverters = NULL;
202    }
203    gAvailableConvertersInitOnce.reset();
204}
205
206/* ucnv_cleanup - delete all storage held by the converter cache, except any  */
207/*                in use by open converters.                                  */
208/*                Not thread safe.                                            */
209/*                Not supported API.                                          */
210static UBool U_CALLCONV ucnv_cleanup(void) {
211    ucnv_flushCache();
212    if (SHARED_DATA_HASHTABLE != NULL && uhash_count(SHARED_DATA_HASHTABLE) == 0) {
213        uhash_close(SHARED_DATA_HASHTABLE);
214        SHARED_DATA_HASHTABLE = NULL;
215    }
216
217    /* Isn't called from flushCache because other threads may have preexisting references to the table. */
218    ucnv_flushAvailableConverterCache();
219
220#if !U_CHARSET_IS_UTF8
221    gDefaultConverterName = NULL;
222    gDefaultConverterNameBuffer[0] = 0;
223    gDefaultConverterContainsOption = FALSE;
224    gDefaultAlgorithmicSharedData = NULL;
225#endif
226
227    return (SHARED_DATA_HASHTABLE == NULL);
228}
229
230static UBool U_CALLCONV
231isCnvAcceptable(void * /*context*/,
232                const char * /*type*/, const char * /*name*/,
233                const UDataInfo *pInfo) {
234    return (UBool)(
235        pInfo->size>=20 &&
236        pInfo->isBigEndian==U_IS_BIG_ENDIAN &&
237        pInfo->charsetFamily==U_CHARSET_FAMILY &&
238        pInfo->sizeofUChar==U_SIZEOF_UCHAR &&
239        pInfo->dataFormat[0]==0x63 &&   /* dataFormat="cnvt" */
240        pInfo->dataFormat[1]==0x6e &&
241        pInfo->dataFormat[2]==0x76 &&
242        pInfo->dataFormat[3]==0x74 &&
243        pInfo->formatVersion[0]==6);  /* Everything will be version 6 */
244}
245
246/**
247 * Un flatten shared data from a UDATA..
248 */
249static UConverterSharedData*
250ucnv_data_unFlattenClone(UConverterLoadArgs *pArgs, UDataMemory *pData, UErrorCode *status)
251{
252    /* UDataInfo info; -- necessary only if some converters have different formatVersion */
253    const uint8_t *raw = (const uint8_t *)udata_getMemory(pData);
254    const UConverterStaticData *source = (const UConverterStaticData *) raw;
255    UConverterSharedData *data;
256    UConverterType type = (UConverterType)source->conversionType;
257
258    if(U_FAILURE(*status))
259        return NULL;
260
261    if( (uint16_t)type >= UCNV_NUMBER_OF_SUPPORTED_CONVERTER_TYPES ||
262        converterData[type] == NULL ||
263        converterData[type]->referenceCounter != 1 ||
264        source->structSize != sizeof(UConverterStaticData))
265    {
266        *status = U_INVALID_TABLE_FORMAT;
267        return NULL;
268    }
269
270    data = (UConverterSharedData *)uprv_malloc(sizeof(UConverterSharedData));
271    if(data == NULL) {
272        *status = U_MEMORY_ALLOCATION_ERROR;
273        return NULL;
274    }
275
276    /* copy initial values from the static structure for this type */
277    uprv_memcpy(data, converterData[type], sizeof(UConverterSharedData));
278
279#if 0 /* made UConverterMBCSTable part of UConverterSharedData -- markus 20031107 */
280    /*
281     * It would be much more efficient if the table were a direct member, not a pointer.
282     * However, that would add to the size of all UConverterSharedData objects
283     * even if they do not use this table (especially algorithmic ones).
284     * If this changes, then the static templates from converterData[type]
285     * need more entries.
286     *
287     * In principle, it would be cleaner if the load() function below
288     * allocated the table.
289     */
290    data->table = (UConverterTable *)uprv_malloc(sizeof(UConverterTable));
291    if(data->table == NULL) {
292        uprv_free(data);
293        *status = U_MEMORY_ALLOCATION_ERROR;
294        return NULL;
295    }
296    uprv_memset(data->table, 0, sizeof(UConverterTable));
297#endif
298
299    data->staticData = source;
300
301    data->sharedDataCached = FALSE;
302
303    /* fill in fields from the loaded data */
304    data->dataMemory = (void*)pData; /* for future use */
305
306    if(data->impl->load != NULL) {
307        data->impl->load(data, pArgs, raw + source->structSize, status);
308        if(U_FAILURE(*status)) {
309            uprv_free(data->table);
310            uprv_free(data);
311            return NULL;
312        }
313    }
314    return data;
315}
316
317/*Takes an alias name gets an actual converter file name
318 *goes to disk and opens it.
319 *allocates the memory and returns a new UConverter object
320 */
321static UConverterSharedData *createConverterFromFile(UConverterLoadArgs *pArgs, UErrorCode * err)
322{
323    UDataMemory *data;
324    UConverterSharedData *sharedData;
325
326    UTRACE_ENTRY_OC(UTRACE_UCNV_LOAD);
327
328    if (U_FAILURE (*err)) {
329        UTRACE_EXIT_STATUS(*err);
330        return NULL;
331    }
332
333    UTRACE_DATA2(UTRACE_OPEN_CLOSE, "load converter %s from package %s", pArgs->name, pArgs->pkg);
334
335    data = udata_openChoice(pArgs->pkg, DATA_TYPE, pArgs->name, isCnvAcceptable, NULL, err);
336    if(U_FAILURE(*err))
337    {
338        UTRACE_EXIT_STATUS(*err);
339        return NULL;
340    }
341
342    sharedData = ucnv_data_unFlattenClone(pArgs, data, err);
343    if(U_FAILURE(*err))
344    {
345        udata_close(data);
346        UTRACE_EXIT_STATUS(*err);
347        return NULL;
348    }
349
350    /*
351     * TODO Store pkg in a field in the shared data so that delta-only converters
352     * can load base converters from the same package.
353     * If the pkg name is longer than the field, then either do not load the converter
354     * in the first place, or just set the pkg field to "".
355     */
356
357    UTRACE_EXIT_PTR_STATUS(sharedData, *err);
358    return sharedData;
359}
360
361/*returns a converter type from a string
362 */
363static const UConverterSharedData *
364getAlgorithmicTypeFromName(const char *realName)
365{
366    uint32_t mid, start, limit;
367    uint32_t lastMid;
368    int result;
369    char strippedName[UCNV_MAX_CONVERTER_NAME_LENGTH];
370
371    /* Lower case and remove ignoreable characters. */
372    ucnv_io_stripForCompare(strippedName, realName);
373
374    /* do a binary search for the alias */
375    start = 0;
376    limit = sizeof(cnvNameType)/sizeof(cnvNameType[0]);
377    mid = limit;
378    lastMid = UINT32_MAX;
379
380    for (;;) {
381        mid = (uint32_t)((start + limit) / 2);
382        if (lastMid == mid) {   /* Have we moved? */
383            break;  /* We haven't moved, and it wasn't found. */
384        }
385        lastMid = mid;
386        result = uprv_strcmp(strippedName, cnvNameType[mid].name);
387
388        if (result < 0) {
389            limit = mid;
390        } else if (result > 0) {
391            start = mid;
392        } else {
393            return converterData[cnvNameType[mid].type];
394        }
395    }
396
397    return NULL;
398}
399
400/*
401* Based on the number of known converters, this determines how many times larger
402* the shared data hash table should be. When on small platforms, or just a couple
403* of converters are used, this number should be 2. When memory is plentiful, or
404* when ucnv_countAvailable is ever used with a lot of available converters,
405* this should be 4.
406* Larger numbers reduce the number of hash collisions, but use more memory.
407*/
408#define UCNV_CACHE_LOAD_FACTOR 2
409
410/* Puts the shared data in the static hashtable SHARED_DATA_HASHTABLE */
411/*   Will always be called with the cnvCacheMutex alrady being held   */
412/*     by the calling function.                                       */
413/* Stores the shared data in the SHARED_DATA_HASHTABLE
414 * @param data The shared data
415 */
416static void
417ucnv_shareConverterData(UConverterSharedData * data)
418{
419    UErrorCode err = U_ZERO_ERROR;
420    /*Lazy evaluates the Hashtable itself */
421    /*void *sanity = NULL;*/
422
423    if (SHARED_DATA_HASHTABLE == NULL)
424    {
425        SHARED_DATA_HASHTABLE = uhash_openSize(uhash_hashChars, uhash_compareChars, NULL,
426                            ucnv_io_countKnownConverters(&err)*UCNV_CACHE_LOAD_FACTOR,
427                            &err);
428        ucln_common_registerCleanup(UCLN_COMMON_UCNV, ucnv_cleanup);
429
430        if (U_FAILURE(err))
431            return;
432    }
433
434    /* ### check to see if the element is not already there! */
435
436    /*
437    sanity =   ucnv_getSharedConverterData (data->staticData->name);
438    if(sanity != NULL)
439    {
440    UCNV_DEBUG_LOG("put:overwrite!",data->staticData->name,sanity);
441    }
442    UCNV_DEBUG_LOG("put:chk",data->staticData->name,sanity);
443    */
444
445    /* Mark it shared */
446    data->sharedDataCached = TRUE;
447
448    uhash_put(SHARED_DATA_HASHTABLE,
449            (void*) data->staticData->name, /* Okay to cast away const as long as
450            keyDeleter == NULL */
451            data,
452            &err);
453    UCNV_DEBUG_LOG("put", data->staticData->name,data);
454
455}
456
457/*  Look up a converter name in the shared data cache.                    */
458/*    cnvCacheMutex must be held by the caller to protect the hash table. */
459/* gets the shared data from the SHARED_DATA_HASHTABLE (might return NULL if it isn't there)
460 * @param name The name of the shared data
461 * @return the shared data from the SHARED_DATA_HASHTABLE
462 */
463static UConverterSharedData *
464ucnv_getSharedConverterData(const char *name)
465{
466    /*special case when no Table has yet been created we return NULL */
467    if (SHARED_DATA_HASHTABLE == NULL)
468    {
469        return NULL;
470    }
471    else
472    {
473        UConverterSharedData *rc;
474
475        rc = (UConverterSharedData*)uhash_get(SHARED_DATA_HASHTABLE, name);
476        UCNV_DEBUG_LOG("get",name,rc);
477        return rc;
478    }
479}
480
481/*frees the string of memory blocks associates with a sharedConverter
482 *if and only if the referenceCounter == 0
483 */
484/* Deletes (frees) the Shared data it's passed. first it checks the referenceCounter to
485 * see if anyone is using it, if not it frees all the memory stemming from sharedConverterData and
486 * returns TRUE,
487 * otherwise returns FALSE
488 * @param sharedConverterData The shared data
489 * @return if not it frees all the memory stemming from sharedConverterData and
490 * returns TRUE, otherwise returns FALSE
491 */
492static UBool
493ucnv_deleteSharedConverterData(UConverterSharedData * deadSharedData)
494{
495    UTRACE_ENTRY_OC(UTRACE_UCNV_UNLOAD);
496    UTRACE_DATA2(UTRACE_OPEN_CLOSE, "unload converter %s shared data %p", deadSharedData->staticData->name, deadSharedData);
497
498    if (deadSharedData->referenceCounter > 0) {
499        UTRACE_EXIT_VALUE((int32_t)FALSE);
500        return FALSE;
501    }
502
503    if (deadSharedData->impl->unload != NULL) {
504        deadSharedData->impl->unload(deadSharedData);
505    }
506
507    if(deadSharedData->dataMemory != NULL)
508    {
509        UDataMemory *data = (UDataMemory*)deadSharedData->dataMemory;
510        udata_close(data);
511    }
512
513    if(deadSharedData->table != NULL)
514    {
515        uprv_free(deadSharedData->table);
516    }
517
518#if 0
519    /* if the static data is actually owned by the shared data */
520    /* enable if we ever have this situation. */
521    if(deadSharedData->staticDataOwned == TRUE) /* see ucnv_bld.h */
522    {
523        uprv_free((void*)deadSharedData->staticData);
524    }
525#endif
526
527#if 0
528    /* Zap it ! */
529    uprv_memset(deadSharedData->0, sizeof(*deadSharedData));
530#endif
531
532    uprv_free(deadSharedData);
533
534    UTRACE_EXIT_VALUE((int32_t)TRUE);
535    return TRUE;
536}
537
538/**
539 * Load a non-algorithmic converter.
540 * If pkg==NULL, then this function must be called inside umtx_lock(&cnvCacheMutex).
541 */
542UConverterSharedData *
543ucnv_load(UConverterLoadArgs *pArgs, UErrorCode *err) {
544    UConverterSharedData *mySharedConverterData;
545
546    if(err == NULL || U_FAILURE(*err)) {
547        return NULL;
548    }
549
550    if(pArgs->pkg != NULL && *pArgs->pkg != 0) {
551        /* application-provided converters are not currently cached */
552        return createConverterFromFile(pArgs, err);
553    }
554
555    mySharedConverterData = ucnv_getSharedConverterData(pArgs->name);
556    if (mySharedConverterData == NULL)
557    {
558        /*Not cached, we need to stream it in from file */
559        mySharedConverterData = createConverterFromFile(pArgs, err);
560        if (U_FAILURE (*err) || (mySharedConverterData == NULL))
561        {
562            return NULL;
563        }
564        else if (!pArgs->onlyTestIsLoadable)
565        {
566            /* share it with other library clients */
567            ucnv_shareConverterData(mySharedConverterData);
568        }
569    }
570    else
571    {
572        /* The data for this converter was already in the cache.            */
573        /* Update the reference counter on the shared data: one more client */
574        mySharedConverterData->referenceCounter++;
575    }
576
577    return mySharedConverterData;
578}
579
580/**
581 * Unload a non-algorithmic converter.
582 * It must be sharedData->referenceCounter != ~0
583 * and this function must be called inside umtx_lock(&cnvCacheMutex).
584 */
585U_CAPI void
586ucnv_unload(UConverterSharedData *sharedData) {
587    if(sharedData != NULL) {
588        if (sharedData->referenceCounter > 0) {
589            sharedData->referenceCounter--;
590        }
591
592        if((sharedData->referenceCounter <= 0)&&(sharedData->sharedDataCached == FALSE)) {
593            ucnv_deleteSharedConverterData(sharedData);
594        }
595    }
596}
597
598U_CFUNC void
599ucnv_unloadSharedDataIfReady(UConverterSharedData *sharedData)
600{
601    /*
602    Checking whether it's an algorithic converter is okay
603    in multithreaded applications because the value never changes.
604    Don't check referenceCounter for any other value.
605    */
606    if(sharedData != NULL && sharedData->referenceCounter != (uint32_t)~0) {
607        umtx_lock(&cnvCacheMutex);
608        ucnv_unload(sharedData);
609        umtx_unlock(&cnvCacheMutex);
610    }
611}
612
613U_CFUNC void
614ucnv_incrementRefCount(UConverterSharedData *sharedData)
615{
616    /*
617    Checking whether it's an algorithic converter is okay
618    in multithreaded applications because the value never changes.
619    Don't check referenceCounter for any other value.
620    */
621    if(sharedData != NULL && sharedData->referenceCounter != (uint32_t)~0) {
622        umtx_lock(&cnvCacheMutex);
623        sharedData->referenceCounter++;
624        umtx_unlock(&cnvCacheMutex);
625    }
626}
627
628/*
629 * *pPieces must be initialized.
630 * The name without options will be copied to pPieces->cnvName.
631 * The locale and options will be copied to pPieces only if present in inName,
632 * otherwise the existing values in pPieces remain.
633 * *pArgs will be set to the pPieces values.
634 */
635static void
636parseConverterOptions(const char *inName,
637                      UConverterNamePieces *pPieces,
638                      UConverterLoadArgs *pArgs,
639                      UErrorCode *err)
640{
641    char *cnvName = pPieces->cnvName;
642    char c;
643    int32_t len = 0;
644
645    pArgs->name=inName;
646    pArgs->locale=pPieces->locale;
647    pArgs->options=pPieces->options;
648
649    /* copy the converter name itself to cnvName */
650    while((c=*inName)!=0 && c!=UCNV_OPTION_SEP_CHAR) {
651        if (++len>=UCNV_MAX_CONVERTER_NAME_LENGTH) {
652            *err = U_ILLEGAL_ARGUMENT_ERROR;    /* bad name */
653            pPieces->cnvName[0]=0;
654            return;
655        }
656        *cnvName++=c;
657        inName++;
658    }
659    *cnvName=0;
660    pArgs->name=pPieces->cnvName;
661
662    /* parse options. No more name copying should occur. */
663    while((c=*inName)!=0) {
664        if(c==UCNV_OPTION_SEP_CHAR) {
665            ++inName;
666        }
667
668        /* inName is behind an option separator */
669        if(uprv_strncmp(inName, "locale=", 7)==0) {
670            /* do not modify locale itself in case we have multiple locale options */
671            char *dest=pPieces->locale;
672
673            /* copy the locale option value */
674            inName+=7;
675            len=0;
676            while((c=*inName)!=0 && c!=UCNV_OPTION_SEP_CHAR) {
677                ++inName;
678
679                if(++len>=ULOC_FULLNAME_CAPACITY) {
680                    *err=U_ILLEGAL_ARGUMENT_ERROR;    /* bad name */
681                    pPieces->locale[0]=0;
682                    return;
683                }
684
685                *dest++=c;
686            }
687            *dest=0;
688        } else if(uprv_strncmp(inName, "version=", 8)==0) {
689            /* copy the version option value into bits 3..0 of pPieces->options */
690            inName+=8;
691            c=*inName;
692            if(c==0) {
693                pArgs->options=(pPieces->options&=~UCNV_OPTION_VERSION);
694                return;
695            } else if((uint8_t)(c-'0')<10) {
696                pArgs->options=pPieces->options=(pPieces->options&~UCNV_OPTION_VERSION)|(uint32_t)(c-'0');
697                ++inName;
698            }
699        } else if(uprv_strncmp(inName, "swaplfnl", 8)==0) {
700            inName+=8;
701            pArgs->options=(pPieces->options|=UCNV_OPTION_SWAP_LFNL);
702        /* add processing for new options here with another } else if(uprv_strncmp(inName, "option-name=", XX)==0) { */
703        } else {
704            /* ignore any other options until we define some */
705            while(((c = *inName++) != 0) && (c != UCNV_OPTION_SEP_CHAR)) {
706            }
707            if(c==0) {
708                return;
709            }
710        }
711    }
712}
713
714/*Logic determines if the converter is Algorithmic AND/OR cached
715 *depending on that:
716 * -we either go to get data from disk and cache it (Data=TRUE, Cached=False)
717 * -Get it from a Hashtable (Data=X, Cached=TRUE)
718 * -Call dataConverter initializer (Data=TRUE, Cached=TRUE)
719 * -Call AlgorithmicConverter initializer (Data=FALSE, Cached=TRUE)
720 */
721U_CFUNC UConverterSharedData *
722ucnv_loadSharedData(const char *converterName,
723                    UConverterNamePieces *pPieces,
724                    UConverterLoadArgs *pArgs,
725                    UErrorCode * err) {
726    UConverterNamePieces stackPieces;
727    UConverterLoadArgs stackArgs;
728    UConverterSharedData *mySharedConverterData = NULL;
729    UErrorCode internalErrorCode = U_ZERO_ERROR;
730    UBool mayContainOption = TRUE;
731    UBool checkForAlgorithmic = TRUE;
732
733    if (U_FAILURE (*err)) {
734        return NULL;
735    }
736
737    if(pPieces == NULL) {
738        if(pArgs != NULL) {
739            /*
740             * Bad: We may set pArgs pointers to stackPieces fields
741             * which will be invalid after this function returns.
742             */
743            *err = U_INTERNAL_PROGRAM_ERROR;
744            return NULL;
745        }
746        pPieces = &stackPieces;
747    }
748    if(pArgs == NULL) {
749        uprv_memset(&stackArgs, 0, sizeof(stackArgs));
750        stackArgs.size = (int32_t)sizeof(stackArgs);
751        pArgs = &stackArgs;
752    }
753
754    pPieces->cnvName[0] = 0;
755    pPieces->locale[0] = 0;
756    pPieces->options = 0;
757
758    pArgs->name = converterName;
759    pArgs->locale = pPieces->locale;
760    pArgs->options = pPieces->options;
761
762    /* In case "name" is NULL we want to open the default converter. */
763    if (converterName == NULL) {
764#if U_CHARSET_IS_UTF8
765        pArgs->name = "UTF-8";
766        return (UConverterSharedData *)converterData[UCNV_UTF8];
767#else
768        /* Call ucnv_getDefaultName first to query the name from the OS. */
769        pArgs->name = ucnv_getDefaultName();
770        if (pArgs->name == NULL) {
771            *err = U_MISSING_RESOURCE_ERROR;
772            return NULL;
773        }
774        mySharedConverterData = (UConverterSharedData *)gDefaultAlgorithmicSharedData;
775        checkForAlgorithmic = FALSE;
776        mayContainOption = gDefaultConverterContainsOption;
777        /* the default converter name is already canonical */
778#endif
779    }
780    else if(UCNV_FAST_IS_UTF8(converterName)) {
781        /* fastpath for UTF-8 */
782        pArgs->name = "UTF-8";
783        return (UConverterSharedData *)converterData[UCNV_UTF8];
784    }
785    else {
786        /* separate the converter name from the options */
787        parseConverterOptions(converterName, pPieces, pArgs, err);
788        if (U_FAILURE(*err)) {
789            /* Very bad name used. */
790            return NULL;
791        }
792
793        /* get the canonical converter name */
794        pArgs->name = ucnv_io_getConverterName(pArgs->name, &mayContainOption, &internalErrorCode);
795        if (U_FAILURE(internalErrorCode) || pArgs->name == NULL) {
796            /*
797            * set the input name in case the converter was added
798            * without updating the alias table, or when there is no alias table
799            */
800            pArgs->name = pPieces->cnvName;
801        } else if (internalErrorCode == U_AMBIGUOUS_ALIAS_WARNING) {
802            *err = U_AMBIGUOUS_ALIAS_WARNING;
803        }
804    }
805
806    /* separate the converter name from the options */
807    if(mayContainOption && pArgs->name != pPieces->cnvName) {
808        parseConverterOptions(pArgs->name, pPieces, pArgs, err);
809    }
810
811    /* get the shared data for an algorithmic converter, if it is one */
812    if (checkForAlgorithmic) {
813        mySharedConverterData = (UConverterSharedData *)getAlgorithmicTypeFromName(pArgs->name);
814    }
815    if (mySharedConverterData == NULL)
816    {
817        /* it is a data-based converter, get its shared data.               */
818        /* Hold the cnvCacheMutex through the whole process of checking the */
819        /*   converter data cache, and adding new entries to the cache      */
820        /*   to prevent other threads from modifying the cache during the   */
821        /*   process.                                                       */
822        pArgs->nestedLoads=1;
823        pArgs->pkg=NULL;
824
825        umtx_lock(&cnvCacheMutex);
826        mySharedConverterData = ucnv_load(pArgs, err);
827        umtx_unlock(&cnvCacheMutex);
828        if (U_FAILURE (*err) || (mySharedConverterData == NULL))
829        {
830            return NULL;
831        }
832    }
833
834    return mySharedConverterData;
835}
836
837U_CAPI UConverter *
838ucnv_createConverter(UConverter *myUConverter, const char *converterName, UErrorCode * err)
839{
840    UConverterNamePieces stackPieces;
841    UConverterLoadArgs stackArgs=UCNV_LOAD_ARGS_INITIALIZER;
842    UConverterSharedData *mySharedConverterData;
843
844    UTRACE_ENTRY_OC(UTRACE_UCNV_OPEN);
845
846    if(U_SUCCESS(*err)) {
847        UTRACE_DATA1(UTRACE_OPEN_CLOSE, "open converter %s", converterName);
848
849        mySharedConverterData = ucnv_loadSharedData(converterName, &stackPieces, &stackArgs, err);
850
851        myUConverter = ucnv_createConverterFromSharedData(
852            myUConverter, mySharedConverterData,
853            &stackArgs,
854            err);
855
856        if(U_SUCCESS(*err)) {
857            UTRACE_EXIT_PTR_STATUS(myUConverter, *err);
858            return myUConverter;
859        }
860    }
861
862    /* exit with error */
863    UTRACE_EXIT_STATUS(*err);
864    return NULL;
865}
866
867U_CFUNC UBool
868ucnv_canCreateConverter(const char *converterName, UErrorCode *err) {
869    UConverter myUConverter;
870    UConverterNamePieces stackPieces;
871    UConverterLoadArgs stackArgs=UCNV_LOAD_ARGS_INITIALIZER;
872    UConverterSharedData *mySharedConverterData;
873
874    UTRACE_ENTRY_OC(UTRACE_UCNV_OPEN);
875
876    if(U_SUCCESS(*err)) {
877        UTRACE_DATA1(UTRACE_OPEN_CLOSE, "test if can open converter %s", converterName);
878
879        stackArgs.onlyTestIsLoadable=TRUE;
880        mySharedConverterData = ucnv_loadSharedData(converterName, &stackPieces, &stackArgs, err);
881        ucnv_createConverterFromSharedData(
882            &myUConverter, mySharedConverterData,
883            &stackArgs,
884            err);
885        ucnv_unloadSharedDataIfReady(mySharedConverterData);
886    }
887
888    UTRACE_EXIT_STATUS(*err);
889    return U_SUCCESS(*err);
890}
891
892UConverter *
893ucnv_createAlgorithmicConverter(UConverter *myUConverter,
894                                UConverterType type,
895                                const char *locale, uint32_t options,
896                                UErrorCode *err) {
897    UConverter *cnv;
898    const UConverterSharedData *sharedData;
899    UConverterLoadArgs stackArgs=UCNV_LOAD_ARGS_INITIALIZER;
900
901    UTRACE_ENTRY_OC(UTRACE_UCNV_OPEN_ALGORITHMIC);
902    UTRACE_DATA1(UTRACE_OPEN_CLOSE, "open algorithmic converter type %d", (int32_t)type);
903
904    if(type<0 || UCNV_NUMBER_OF_SUPPORTED_CONVERTER_TYPES<=type) {
905        *err = U_ILLEGAL_ARGUMENT_ERROR;
906        UTRACE_EXIT_STATUS(U_ILLEGAL_ARGUMENT_ERROR);
907        return NULL;
908    }
909
910    sharedData = converterData[type];
911    /*
912    Checking whether it's an algorithic converter is okay
913    in multithreaded applications because the value never changes.
914    Don't check referenceCounter for any other value.
915    */
916    if(sharedData == NULL || sharedData->referenceCounter != (uint32_t)~0) {
917        /* not a valid type, or not an algorithmic converter */
918        *err = U_ILLEGAL_ARGUMENT_ERROR;
919        UTRACE_EXIT_STATUS(U_ILLEGAL_ARGUMENT_ERROR);
920        return NULL;
921    }
922
923    stackArgs.name = "";
924    stackArgs.options = options;
925    stackArgs.locale=locale;
926    cnv = ucnv_createConverterFromSharedData(
927            myUConverter, (UConverterSharedData *)sharedData,
928            &stackArgs, err);
929
930    UTRACE_EXIT_PTR_STATUS(cnv, *err);
931    return cnv;
932}
933
934U_CFUNC UConverter*
935ucnv_createConverterFromPackage(const char *packageName, const char *converterName, UErrorCode * err)
936{
937    UConverter *myUConverter;
938    UConverterSharedData *mySharedConverterData;
939    UConverterNamePieces stackPieces;
940    UConverterLoadArgs stackArgs=UCNV_LOAD_ARGS_INITIALIZER;
941
942    UTRACE_ENTRY_OC(UTRACE_UCNV_OPEN_PACKAGE);
943
944    if(U_FAILURE(*err)) {
945        UTRACE_EXIT_STATUS(*err);
946        return NULL;
947    }
948
949    UTRACE_DATA2(UTRACE_OPEN_CLOSE, "open converter %s from package %s", converterName, packageName);
950
951    /* first, get the options out of the converterName string */
952    stackPieces.cnvName[0] = 0;
953    stackPieces.locale[0] = 0;
954    stackPieces.options = 0;
955    parseConverterOptions(converterName, &stackPieces, &stackArgs, err);
956    if (U_FAILURE(*err)) {
957        /* Very bad name used. */
958        UTRACE_EXIT_STATUS(*err);
959        return NULL;
960    }
961    stackArgs.nestedLoads=1;
962    stackArgs.pkg=packageName;
963
964    /* open the data, unflatten the shared structure */
965    mySharedConverterData = createConverterFromFile(&stackArgs, err);
966
967    if (U_FAILURE(*err)) {
968        UTRACE_EXIT_STATUS(*err);
969        return NULL;
970    }
971
972    /* create the actual converter */
973    myUConverter = ucnv_createConverterFromSharedData(NULL, mySharedConverterData, &stackArgs, err);
974
975    if (U_FAILURE(*err)) {
976        ucnv_close(myUConverter);
977        UTRACE_EXIT_STATUS(*err);
978        return NULL;
979    }
980
981    UTRACE_EXIT_PTR_STATUS(myUConverter, *err);
982    return myUConverter;
983}
984
985
986U_CFUNC UConverter*
987ucnv_createConverterFromSharedData(UConverter *myUConverter,
988                                   UConverterSharedData *mySharedConverterData,
989                                   UConverterLoadArgs *pArgs,
990                                   UErrorCode *err)
991{
992    UBool isCopyLocal;
993
994    if(U_FAILURE(*err)) {
995        ucnv_unloadSharedDataIfReady(mySharedConverterData);
996        return myUConverter;
997    }
998    if(myUConverter == NULL)
999    {
1000        myUConverter = (UConverter *) uprv_malloc (sizeof (UConverter));
1001        if(myUConverter == NULL)
1002        {
1003            *err = U_MEMORY_ALLOCATION_ERROR;
1004            ucnv_unloadSharedDataIfReady(mySharedConverterData);
1005            return NULL;
1006        }
1007        isCopyLocal = FALSE;
1008    } else {
1009        isCopyLocal = TRUE;
1010    }
1011
1012    /* initialize the converter */
1013    uprv_memset(myUConverter, 0, sizeof(UConverter));
1014    myUConverter->isCopyLocal = isCopyLocal;
1015    /*myUConverter->isExtraLocal = FALSE;*/ /* Set by the memset call */
1016    myUConverter->sharedData = mySharedConverterData;
1017    myUConverter->options = pArgs->options;
1018    if(!pArgs->onlyTestIsLoadable) {
1019        myUConverter->preFromUFirstCP = U_SENTINEL;
1020        myUConverter->fromCharErrorBehaviour = UCNV_TO_U_DEFAULT_CALLBACK;
1021        myUConverter->fromUCharErrorBehaviour = UCNV_FROM_U_DEFAULT_CALLBACK;
1022        myUConverter->toUnicodeStatus = mySharedConverterData->toUnicodeStatus;
1023        myUConverter->maxBytesPerUChar = mySharedConverterData->staticData->maxBytesPerChar;
1024        myUConverter->subChar1 = mySharedConverterData->staticData->subChar1;
1025        myUConverter->subCharLen = mySharedConverterData->staticData->subCharLen;
1026        myUConverter->subChars = (uint8_t *)myUConverter->subUChars;
1027        uprv_memcpy(myUConverter->subChars, mySharedConverterData->staticData->subChar, myUConverter->subCharLen);
1028        myUConverter->toUCallbackReason = UCNV_ILLEGAL; /* default reason to invoke (*fromCharErrorBehaviour) */
1029    }
1030
1031    if(mySharedConverterData->impl->open != NULL) {
1032        mySharedConverterData->impl->open(myUConverter, pArgs, err);
1033        if(U_FAILURE(*err) && !pArgs->onlyTestIsLoadable) {
1034            /* don't ucnv_close() if onlyTestIsLoadable because not fully initialized */
1035            ucnv_close(myUConverter);
1036            return NULL;
1037        }
1038    }
1039
1040    return myUConverter;
1041}
1042
1043/*Frees all shared immutable objects that aren't referred to (reference count = 0)
1044 */
1045U_CAPI int32_t U_EXPORT2
1046ucnv_flushCache ()
1047{
1048    UConverterSharedData *mySharedData = NULL;
1049    int32_t pos;
1050    int32_t tableDeletedNum = 0;
1051    const UHashElement *e;
1052    /*UErrorCode status = U_ILLEGAL_ARGUMENT_ERROR;*/
1053    int32_t i, remaining;
1054
1055    UTRACE_ENTRY_OC(UTRACE_UCNV_FLUSH_CACHE);
1056
1057    /* Close the default converter without creating a new one so that everything will be flushed. */
1058    u_flushDefaultConverter();
1059
1060    /*if shared data hasn't even been lazy evaluated yet
1061    * return 0
1062    */
1063    if (SHARED_DATA_HASHTABLE == NULL) {
1064        UTRACE_EXIT_VALUE((int32_t)0);
1065        return 0;
1066    }
1067
1068    /*creates an enumeration to iterate through every element in the
1069    * table
1070    *
1071    * Synchronization:  holding cnvCacheMutex will prevent any other thread from
1072    *                   accessing or modifying the hash table during the iteration.
1073    *                   The reference count of an entry may be decremented by
1074    *                   ucnv_close while the iteration is in process, but this is
1075    *                   benign.  It can't be incremented (in ucnv_createConverter())
1076    *                   because the sequence of looking up in the cache + incrementing
1077    *                   is protected by cnvCacheMutex.
1078    */
1079    umtx_lock(&cnvCacheMutex);
1080    /*
1081     * double loop: A delta/extension-only converter has a pointer to its base table's
1082     * shared data; the first iteration of the outer loop may see the delta converter
1083     * before the base converter, and unloading the delta converter may get the base
1084     * converter's reference counter down to 0.
1085     */
1086    i = 0;
1087    do {
1088        remaining = 0;
1089        pos = -1;
1090        while ((e = uhash_nextElement (SHARED_DATA_HASHTABLE, &pos)) != NULL)
1091        {
1092            mySharedData = (UConverterSharedData *) e->value.pointer;
1093            /*deletes only if reference counter == 0 */
1094            if (mySharedData->referenceCounter == 0)
1095            {
1096                tableDeletedNum++;
1097
1098                UCNV_DEBUG_LOG("del",mySharedData->staticData->name,mySharedData);
1099
1100                uhash_removeElement(SHARED_DATA_HASHTABLE, e);
1101                mySharedData->sharedDataCached = FALSE;
1102                ucnv_deleteSharedConverterData (mySharedData);
1103            } else {
1104                ++remaining;
1105            }
1106        }
1107    } while(++i == 1 && remaining > 0);
1108    umtx_unlock(&cnvCacheMutex);
1109
1110    UTRACE_DATA1(UTRACE_INFO, "ucnv_flushCache() exits with %d converters remaining", remaining);
1111
1112    UTRACE_EXIT_VALUE(tableDeletedNum);
1113    return tableDeletedNum;
1114}
1115
1116/* available converters list --------------------------------------------------- */
1117
1118static void U_CALLCONV initAvailableConvertersList(UErrorCode &errCode) {
1119    U_ASSERT(gAvailableConverterCount == 0);
1120    U_ASSERT(gAvailableConverters == NULL);
1121
1122    ucln_common_registerCleanup(UCLN_COMMON_UCNV, ucnv_cleanup);
1123    UEnumeration *allConvEnum = ucnv_openAllNames(&errCode);
1124    int32_t allConverterCount = uenum_count(allConvEnum, &errCode);
1125    if (U_FAILURE(errCode)) {
1126        return;
1127    }
1128
1129    /* We can't have more than "*converterTable" converters to open */
1130    gAvailableConverters = (const char **) uprv_malloc(allConverterCount * sizeof(char*));
1131    if (!gAvailableConverters) {
1132        errCode = U_MEMORY_ALLOCATION_ERROR;
1133        return;
1134    }
1135
1136    /* Open the default converter to make sure that it has first dibs in the hash table. */
1137    UErrorCode localStatus = U_ZERO_ERROR;
1138    UConverter tempConverter;
1139    ucnv_close(ucnv_createConverter(&tempConverter, NULL, &localStatus));
1140
1141    gAvailableConverterCount = 0;
1142
1143    for (int32_t idx = 0; idx < allConverterCount; idx++) {
1144        localStatus = U_ZERO_ERROR;
1145        const char *converterName = uenum_next(allConvEnum, NULL, &localStatus);
1146        if (ucnv_canCreateConverter(converterName, &localStatus)) {
1147            gAvailableConverters[gAvailableConverterCount++] = converterName;
1148        }
1149    }
1150
1151    uenum_close(allConvEnum);
1152}
1153
1154
1155static UBool haveAvailableConverterList(UErrorCode *pErrorCode) {
1156    umtx_initOnce(gAvailableConvertersInitOnce, &initAvailableConvertersList, *pErrorCode);
1157    return U_SUCCESS(*pErrorCode);
1158}
1159
1160U_CFUNC uint16_t
1161ucnv_bld_countAvailableConverters(UErrorCode *pErrorCode) {
1162    if (haveAvailableConverterList(pErrorCode)) {
1163        return gAvailableConverterCount;
1164    }
1165    return 0;
1166}
1167
1168U_CFUNC const char *
1169ucnv_bld_getAvailableConverter(uint16_t n, UErrorCode *pErrorCode) {
1170    if (haveAvailableConverterList(pErrorCode)) {
1171        if (n < gAvailableConverterCount) {
1172            return gAvailableConverters[n];
1173        }
1174        *pErrorCode = U_INDEX_OUTOFBOUNDS_ERROR;
1175    }
1176    return NULL;
1177}
1178
1179/* default converter name --------------------------------------------------- */
1180
1181#if !U_CHARSET_IS_UTF8
1182/*
1183Copy the canonical converter name.
1184ucnv_getDefaultName must be thread safe, which can call this function.
1185
1186ucnv_setDefaultName calls this function and it doesn't have to be
1187thread safe because there is no reliable/safe way to reset the
1188converter in use in all threads. If you did reset the converter, you
1189would not be sure that retrieving a default converter for one string
1190would be the same type of default converter for a successive string.
1191Since the name is a returned via ucnv_getDefaultName without copying,
1192you shouldn't be modifying or deleting the string from a separate thread.
1193*/
1194static inline void
1195internalSetName(const char *name, UErrorCode *status) {
1196    UConverterNamePieces stackPieces;
1197    UConverterLoadArgs stackArgs=UCNV_LOAD_ARGS_INITIALIZER;
1198    int32_t length=(int32_t)(uprv_strlen(name));
1199    UBool containsOption = (UBool)(uprv_strchr(name, UCNV_OPTION_SEP_CHAR) != NULL);
1200    const UConverterSharedData *algorithmicSharedData;
1201
1202    stackArgs.name = name;
1203    if(containsOption) {
1204        stackPieces.cnvName[0] = 0;
1205        stackPieces.locale[0] = 0;
1206        stackPieces.options = 0;
1207        parseConverterOptions(name, &stackPieces, &stackArgs, status);
1208        if(U_FAILURE(*status)) {
1209            return;
1210        }
1211    }
1212    algorithmicSharedData = getAlgorithmicTypeFromName(stackArgs.name);
1213
1214    umtx_lock(&cnvCacheMutex);
1215
1216    gDefaultAlgorithmicSharedData = algorithmicSharedData;
1217    gDefaultConverterContainsOption = containsOption;
1218    uprv_memcpy(gDefaultConverterNameBuffer, name, length);
1219    gDefaultConverterNameBuffer[length]=0;
1220
1221    /* gDefaultConverterName MUST be the last global var set by this function.  */
1222    /*    It is the variable checked in ucnv_getDefaultName() to see if initialization is required. */
1223    //    But there is nothing here preventing that from being reordered, either by the compiler
1224    //             or hardware. I'm adding the mutex to ucnv_getDefaultName for now. UMTX_CHECK is not enough.
1225    //             -- Andy
1226    gDefaultConverterName = gDefaultConverterNameBuffer;
1227
1228    ucln_common_registerCleanup(UCLN_COMMON_UCNV, ucnv_cleanup);
1229
1230    umtx_unlock(&cnvCacheMutex);
1231}
1232#endif
1233
1234/*
1235 * In order to be really thread-safe, the get function would have to take
1236 * a buffer parameter and copy the current string inside a mutex block.
1237 * This implementation only tries to be really thread-safe while
1238 * setting the name.
1239 * It assumes that setting a pointer is atomic.
1240 */
1241
1242U_CAPI const char*  U_EXPORT2
1243ucnv_getDefaultName() {
1244#if U_CHARSET_IS_UTF8
1245    return "UTF-8";
1246#else
1247    /* local variable to be thread-safe */
1248    const char *name;
1249
1250    /*
1251    Concurrent calls to ucnv_getDefaultName must be thread safe,
1252    but ucnv_setDefaultName is not thread safe.
1253    */
1254    {
1255        icu::Mutex lock(&cnvCacheMutex);
1256        name = gDefaultConverterName;
1257    }
1258    if(name==NULL) {
1259        UErrorCode errorCode = U_ZERO_ERROR;
1260        UConverter *cnv = NULL;
1261
1262        name = uprv_getDefaultCodepage();
1263
1264        /* if the name is there, test it out and get the canonical name with options */
1265        if(name != NULL) {
1266            cnv = ucnv_open(name, &errorCode);
1267            if(U_SUCCESS(errorCode) && cnv != NULL) {
1268                name = ucnv_getName(cnv, &errorCode);
1269            }
1270        }
1271
1272        if(name == NULL || name[0] == 0
1273            || U_FAILURE(errorCode) || cnv == NULL
1274            || uprv_strlen(name)>=sizeof(gDefaultConverterNameBuffer))
1275        {
1276            /* Panic time, let's use a fallback. */
1277#if (U_CHARSET_FAMILY == U_ASCII_FAMILY)
1278            name = "US-ASCII";
1279            /* there is no 'algorithmic' converter for EBCDIC */
1280#elif U_PLATFORM == U_PF_OS390
1281            name = "ibm-1047_P100-1995" UCNV_SWAP_LFNL_OPTION_STRING;
1282#else
1283            name = "ibm-37_P100-1995";
1284#endif
1285        }
1286
1287        internalSetName(name, &errorCode);
1288
1289        /* The close may make the current name go away. */
1290        ucnv_close(cnv);
1291    }
1292
1293    return name;
1294#endif
1295}
1296
1297#if U_CHARSET_IS_UTF8
1298U_CAPI void U_EXPORT2 ucnv_setDefaultName(const char *) {}
1299#else
1300/*
1301This function is not thread safe, and it can't be thread safe.
1302See internalSetName or the API reference for details.
1303*/
1304U_CAPI void U_EXPORT2
1305ucnv_setDefaultName(const char *converterName) {
1306    if(converterName==NULL) {
1307        /* reset to the default codepage */
1308        gDefaultConverterName=NULL;
1309    } else {
1310        UErrorCode errorCode = U_ZERO_ERROR;
1311        UConverter *cnv = NULL;
1312        const char *name = NULL;
1313
1314        /* if the name is there, test it out and get the canonical name with options */
1315        cnv = ucnv_open(converterName, &errorCode);
1316        if(U_SUCCESS(errorCode) && cnv != NULL) {
1317            name = ucnv_getName(cnv, &errorCode);
1318        }
1319
1320        if(U_SUCCESS(errorCode) && name!=NULL) {
1321            internalSetName(name, &errorCode);
1322        }
1323        /* else this converter is bad to use. Don't change it to a bad value. */
1324
1325        /* The close may make the current name go away. */
1326        ucnv_close(cnv);
1327
1328        /* reset the converter cache */
1329        u_flushDefaultConverter();
1330    }
1331}
1332#endif
1333
1334/* data swapping ------------------------------------------------------------ */
1335
1336/* most of this might belong more properly into ucnvmbcs.c, but that is so large */
1337
1338#if !UCONFIG_NO_LEGACY_CONVERSION
1339
1340U_CAPI int32_t U_EXPORT2
1341ucnv_swap(const UDataSwapper *ds,
1342          const void *inData, int32_t length, void *outData,
1343          UErrorCode *pErrorCode) {
1344    const UDataInfo *pInfo;
1345    int32_t headerSize;
1346
1347    const uint8_t *inBytes;
1348    uint8_t *outBytes;
1349
1350    uint32_t offset, count, staticDataSize;
1351    int32_t size;
1352
1353    const UConverterStaticData *inStaticData;
1354    UConverterStaticData *outStaticData;
1355
1356    const _MBCSHeader *inMBCSHeader;
1357    _MBCSHeader *outMBCSHeader;
1358    _MBCSHeader mbcsHeader;
1359    uint32_t mbcsHeaderLength;
1360    UBool noFromU=FALSE;
1361
1362    uint8_t outputType;
1363
1364    int32_t maxFastUChar, mbcsIndexLength;
1365
1366    const int32_t *inExtIndexes;
1367    int32_t extOffset;
1368
1369    /* udata_swapDataHeader checks the arguments */
1370    headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
1371    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
1372        return 0;
1373    }
1374
1375    /* check data format and format version */
1376    pInfo=(const UDataInfo *)((const char *)inData+4);
1377    if(!(
1378        pInfo->dataFormat[0]==0x63 &&   /* dataFormat="cnvt" */
1379        pInfo->dataFormat[1]==0x6e &&
1380        pInfo->dataFormat[2]==0x76 &&
1381        pInfo->dataFormat[3]==0x74 &&
1382        pInfo->formatVersion[0]==6 &&
1383        pInfo->formatVersion[1]>=2
1384    )) {
1385        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",
1386                         pInfo->dataFormat[0], pInfo->dataFormat[1],
1387                         pInfo->dataFormat[2], pInfo->dataFormat[3],
1388                         pInfo->formatVersion[0], pInfo->formatVersion[1]);
1389        *pErrorCode=U_UNSUPPORTED_ERROR;
1390        return 0;
1391    }
1392
1393    inBytes=(const uint8_t *)inData+headerSize;
1394    outBytes=(uint8_t *)outData+headerSize;
1395
1396    /* read the initial UConverterStaticData structure after the UDataInfo header */
1397    inStaticData=(const UConverterStaticData *)inBytes;
1398    outStaticData=(UConverterStaticData *)outBytes;
1399
1400    if(length<0) {
1401        staticDataSize=ds->readUInt32(inStaticData->structSize);
1402    } else {
1403        length-=headerSize;
1404        if( length<(int32_t)sizeof(UConverterStaticData) ||
1405            (uint32_t)length<(staticDataSize=ds->readUInt32(inStaticData->structSize))
1406        ) {
1407            udata_printError(ds, "ucnv_swap(): too few bytes (%d after header) for an ICU .cnv conversion table\n",
1408                             length);
1409            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
1410            return 0;
1411        }
1412    }
1413
1414    if(length>=0) {
1415        /* swap the static data */
1416        if(inStaticData!=outStaticData) {
1417            uprv_memcpy(outStaticData, inStaticData, staticDataSize);
1418        }
1419
1420        ds->swapArray32(ds, &inStaticData->structSize, 4,
1421                           &outStaticData->structSize, pErrorCode);
1422        ds->swapArray32(ds, &inStaticData->codepage, 4,
1423                           &outStaticData->codepage, pErrorCode);
1424
1425        ds->swapInvChars(ds, inStaticData->name, (int32_t)uprv_strlen(inStaticData->name),
1426                            outStaticData->name, pErrorCode);
1427        if(U_FAILURE(*pErrorCode)) {
1428            udata_printError(ds, "ucnv_swap(): error swapping converter name\n");
1429            return 0;
1430        }
1431    }
1432
1433    inBytes+=staticDataSize;
1434    outBytes+=staticDataSize;
1435    if(length>=0) {
1436        length-=(int32_t)staticDataSize;
1437    }
1438
1439    /* check for supported conversionType values */
1440    if(inStaticData->conversionType==UCNV_MBCS) {
1441        /* swap MBCS data */
1442        inMBCSHeader=(const _MBCSHeader *)inBytes;
1443        outMBCSHeader=(_MBCSHeader *)outBytes;
1444
1445        if(0<=length && length<(int32_t)sizeof(_MBCSHeader)) {
1446            udata_printError(ds, "ucnv_swap(): too few bytes (%d after headers) for an ICU MBCS .cnv conversion table\n",
1447                                length);
1448            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
1449            return 0;
1450        }
1451        if(inMBCSHeader->version[0]==4 && inMBCSHeader->version[1]>=1) {
1452            mbcsHeaderLength=MBCS_HEADER_V4_LENGTH;
1453        } else if(inMBCSHeader->version[0]==5 && inMBCSHeader->version[1]>=3 &&
1454                  ((mbcsHeader.options=ds->readUInt32(inMBCSHeader->options))&
1455                   MBCS_OPT_UNKNOWN_INCOMPATIBLE_MASK)==0
1456        ) {
1457            mbcsHeaderLength=mbcsHeader.options&MBCS_OPT_LENGTH_MASK;
1458            noFromU=(UBool)((mbcsHeader.options&MBCS_OPT_NO_FROM_U)!=0);
1459        } else {
1460            udata_printError(ds, "ucnv_swap(): unsupported _MBCSHeader.version %d.%d\n",
1461                             inMBCSHeader->version[0], inMBCSHeader->version[1]);
1462            *pErrorCode=U_UNSUPPORTED_ERROR;
1463            return 0;
1464        }
1465
1466        uprv_memcpy(mbcsHeader.version, inMBCSHeader->version, 4);
1467        mbcsHeader.countStates=         ds->readUInt32(inMBCSHeader->countStates);
1468        mbcsHeader.countToUFallbacks=   ds->readUInt32(inMBCSHeader->countToUFallbacks);
1469        mbcsHeader.offsetToUCodeUnits=  ds->readUInt32(inMBCSHeader->offsetToUCodeUnits);
1470        mbcsHeader.offsetFromUTable=    ds->readUInt32(inMBCSHeader->offsetFromUTable);
1471        mbcsHeader.offsetFromUBytes=    ds->readUInt32(inMBCSHeader->offsetFromUBytes);
1472        mbcsHeader.flags=               ds->readUInt32(inMBCSHeader->flags);
1473        mbcsHeader.fromUBytesLength=    ds->readUInt32(inMBCSHeader->fromUBytesLength);
1474        /* mbcsHeader.options have been read above */
1475
1476        extOffset=(int32_t)(mbcsHeader.flags>>8);
1477        outputType=(uint8_t)mbcsHeader.flags;
1478        if(noFromU && outputType==MBCS_OUTPUT_1) {
1479            udata_printError(ds, "ucnv_swap(): unsupported combination of makeconv --small with SBCS\n");
1480            *pErrorCode=U_UNSUPPORTED_ERROR;
1481            return 0;
1482        }
1483
1484        /* make sure that the output type is known */
1485        switch(outputType) {
1486        case MBCS_OUTPUT_1:
1487        case MBCS_OUTPUT_2:
1488        case MBCS_OUTPUT_3:
1489        case MBCS_OUTPUT_4:
1490        case MBCS_OUTPUT_3_EUC:
1491        case MBCS_OUTPUT_4_EUC:
1492        case MBCS_OUTPUT_2_SISO:
1493        case MBCS_OUTPUT_EXT_ONLY:
1494            /* OK */
1495            break;
1496        default:
1497            udata_printError(ds, "ucnv_swap(): unsupported MBCS output type 0x%x\n",
1498                             outputType);
1499            *pErrorCode=U_UNSUPPORTED_ERROR;
1500            return 0;
1501        }
1502
1503        /* calculate the length of the MBCS data */
1504
1505        /*
1506         * utf8Friendly MBCS files (mbcsHeader.version 4.3)
1507         * contain an additional mbcsIndex table:
1508         *   uint16_t[(maxFastUChar+1)>>6];
1509         * where maxFastUChar=((mbcsHeader.version[2]<<8)|0xff).
1510         */
1511        maxFastUChar=0;
1512        mbcsIndexLength=0;
1513        if( outputType!=MBCS_OUTPUT_EXT_ONLY && outputType!=MBCS_OUTPUT_1 &&
1514            mbcsHeader.version[1]>=3 && (maxFastUChar=mbcsHeader.version[2])!=0
1515        ) {
1516            maxFastUChar=(maxFastUChar<<8)|0xff;
1517            mbcsIndexLength=((maxFastUChar+1)>>6)*2;  /* number of bytes */
1518        }
1519
1520        if(extOffset==0) {
1521            size=(int32_t)(mbcsHeader.offsetFromUBytes+mbcsIndexLength);
1522            if(!noFromU) {
1523                size+=(int32_t)mbcsHeader.fromUBytesLength;
1524            }
1525
1526            /* avoid compiler warnings - not otherwise necessary, and the value does not matter */
1527            inExtIndexes=NULL;
1528        } else {
1529            /* there is extension data after the base data, see ucnv_ext.h */
1530            if(length>=0 && length<(extOffset+UCNV_EXT_INDEXES_MIN_LENGTH*4)) {
1531                udata_printError(ds, "ucnv_swap(): too few bytes (%d after headers) for an ICU MBCS .cnv conversion table with extension data\n",
1532                                 length);
1533                *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
1534                return 0;
1535            }
1536
1537            inExtIndexes=(const int32_t *)(inBytes+extOffset);
1538            size=extOffset+udata_readInt32(ds, inExtIndexes[UCNV_EXT_SIZE]);
1539        }
1540
1541        if(length>=0) {
1542            if(length<size) {
1543                udata_printError(ds, "ucnv_swap(): too few bytes (%d after headers) for an ICU MBCS .cnv conversion table\n",
1544                                 length);
1545                *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
1546                return 0;
1547            }
1548
1549            /* copy the data for inaccessible bytes */
1550            if(inBytes!=outBytes) {
1551                uprv_memcpy(outBytes, inBytes, size);
1552            }
1553
1554            /* swap the MBCSHeader, except for the version field */
1555            count=mbcsHeaderLength*4;
1556            ds->swapArray32(ds, &inMBCSHeader->countStates, count-4,
1557                               &outMBCSHeader->countStates, pErrorCode);
1558
1559            if(outputType==MBCS_OUTPUT_EXT_ONLY) {
1560                /*
1561                 * extension-only file,
1562                 * contains a base name instead of normal base table data
1563                 */
1564
1565                /* swap the base name, between the header and the extension data */
1566                const char *inBaseName=(const char *)inBytes+count;
1567                char *outBaseName=(char *)outBytes+count;
1568                ds->swapInvChars(ds, inBaseName, (int32_t)uprv_strlen(inBaseName),
1569                                    outBaseName, pErrorCode);
1570            } else {
1571                /* normal file with base table data */
1572
1573                /* swap the state table, 1kB per state */
1574                offset=count;
1575                count=mbcsHeader.countStates*1024;
1576                ds->swapArray32(ds, inBytes+offset, (int32_t)count,
1577                                   outBytes+offset, pErrorCode);
1578
1579                /* swap the toUFallbacks[] */
1580                offset+=count;
1581                count=mbcsHeader.countToUFallbacks*8;
1582                ds->swapArray32(ds, inBytes+offset, (int32_t)count,
1583                                   outBytes+offset, pErrorCode);
1584
1585                /* swap the unicodeCodeUnits[] */
1586                offset=mbcsHeader.offsetToUCodeUnits;
1587                count=mbcsHeader.offsetFromUTable-offset;
1588                ds->swapArray16(ds, inBytes+offset, (int32_t)count,
1589                                   outBytes+offset, pErrorCode);
1590
1591                /* offset to the stage 1 table, independent of the outputType */
1592                offset=mbcsHeader.offsetFromUTable;
1593
1594                if(outputType==MBCS_OUTPUT_1) {
1595                    /* SBCS: swap the fromU tables, all 16 bits wide */
1596                    count=(mbcsHeader.offsetFromUBytes-offset)+mbcsHeader.fromUBytesLength;
1597                    ds->swapArray16(ds, inBytes+offset, (int32_t)count,
1598                                       outBytes+offset, pErrorCode);
1599                } else {
1600                    /* otherwise: swap the stage tables separately */
1601
1602                    /* stage 1 table: uint16_t[0x440 or 0x40] */
1603                    if(inStaticData->unicodeMask&UCNV_HAS_SUPPLEMENTARY) {
1604                        count=0x440*2; /* for all of Unicode */
1605                    } else {
1606                        count=0x40*2; /* only BMP */
1607                    }
1608                    ds->swapArray16(ds, inBytes+offset, (int32_t)count,
1609                                       outBytes+offset, pErrorCode);
1610
1611                    /* stage 2 table: uint32_t[] */
1612                    offset+=count;
1613                    count=mbcsHeader.offsetFromUBytes-offset;
1614                    ds->swapArray32(ds, inBytes+offset, (int32_t)count,
1615                                       outBytes+offset, pErrorCode);
1616
1617                    /* stage 3/result bytes: sometimes uint16_t[] or uint32_t[] */
1618                    offset=mbcsHeader.offsetFromUBytes;
1619                    count= noFromU ? 0 : mbcsHeader.fromUBytesLength;
1620                    switch(outputType) {
1621                    case MBCS_OUTPUT_2:
1622                    case MBCS_OUTPUT_3_EUC:
1623                    case MBCS_OUTPUT_2_SISO:
1624                        ds->swapArray16(ds, inBytes+offset, (int32_t)count,
1625                                           outBytes+offset, pErrorCode);
1626                        break;
1627                    case MBCS_OUTPUT_4:
1628                        ds->swapArray32(ds, inBytes+offset, (int32_t)count,
1629                                           outBytes+offset, pErrorCode);
1630                        break;
1631                    default:
1632                        /* just uint8_t[], nothing to swap */
1633                        break;
1634                    }
1635
1636                    if(mbcsIndexLength!=0) {
1637                        offset+=count;
1638                        count=mbcsIndexLength;
1639                        ds->swapArray16(ds, inBytes+offset, (int32_t)count,
1640                                           outBytes+offset, pErrorCode);
1641                    }
1642                }
1643            }
1644
1645            if(extOffset!=0) {
1646                /* swap the extension data */
1647                inBytes+=extOffset;
1648                outBytes+=extOffset;
1649
1650                /* swap toUTable[] */
1651                offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_TO_U_INDEX]);
1652                length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_TO_U_LENGTH]);
1653                ds->swapArray32(ds, inBytes+offset, length*4, outBytes+offset, pErrorCode);
1654
1655                /* swap toUUChars[] */
1656                offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_TO_U_UCHARS_INDEX]);
1657                length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_TO_U_UCHARS_LENGTH]);
1658                ds->swapArray16(ds, inBytes+offset, length*2, outBytes+offset, pErrorCode);
1659
1660                /* swap fromUTableUChars[] */
1661                offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_UCHARS_INDEX]);
1662                length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_LENGTH]);
1663                ds->swapArray16(ds, inBytes+offset, length*2, outBytes+offset, pErrorCode);
1664
1665                /* swap fromUTableValues[] */
1666                offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_VALUES_INDEX]);
1667                /* same length as for fromUTableUChars[] */
1668                ds->swapArray32(ds, inBytes+offset, length*4, outBytes+offset, pErrorCode);
1669
1670                /* no need to swap fromUBytes[] */
1671
1672                /* swap fromUStage12[] */
1673                offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_STAGE_12_INDEX]);
1674                length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_STAGE_12_LENGTH]);
1675                ds->swapArray16(ds, inBytes+offset, length*2, outBytes+offset, pErrorCode);
1676
1677                /* swap fromUStage3[] */
1678                offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_STAGE_3_INDEX]);
1679                length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_STAGE_3_LENGTH]);
1680                ds->swapArray16(ds, inBytes+offset, length*2, outBytes+offset, pErrorCode);
1681
1682                /* swap fromUStage3b[] */
1683                offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_STAGE_3B_INDEX]);
1684                length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_STAGE_3B_LENGTH]);
1685                ds->swapArray32(ds, inBytes+offset, length*4, outBytes+offset, pErrorCode);
1686
1687                /* swap indexes[] */
1688                length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_INDEXES_LENGTH]);
1689                ds->swapArray32(ds, inBytes, length*4, outBytes, pErrorCode);
1690            }
1691        }
1692    } else {
1693        udata_printError(ds, "ucnv_swap(): unknown conversionType=%d!=UCNV_MBCS\n",
1694                         inStaticData->conversionType);
1695        *pErrorCode=U_UNSUPPORTED_ERROR;
1696        return 0;
1697    }
1698
1699    return headerSize+(int32_t)staticDataSize+size;
1700}
1701
1702#endif /* #if !UCONFIG_NO_LEGACY_CONVERSION */
1703
1704#endif
1705