diff --git a/icu4c/source/common/ucnv.c b/icu4c/source/common/ucnv.c index 6cb1f744f64..8cfa0d16c95 100644 --- a/icu4c/source/common/ucnv.c +++ b/icu4c/source/common/ucnv.c @@ -93,6 +93,12 @@ ucnv_open (const char *name, return ucnv_createConverter(name, err); } +U_CAPI UConverter* U_EXPORT2 +ucnv_openPackage (const char *packageName, const char *converterName, UErrorCode * err) +{ + return ucnv_createConverterFromPackage(packageName, converterName, err); +} + /*Extracts the UChar* to a char* and calls through createConverter */ U_CAPI UConverter* U_EXPORT2 ucnv_openU (const UChar * name, @@ -243,14 +249,23 @@ ucnv_close (UConverter * converter) if (converter->sharedData->impl->close != NULL) { converter->sharedData->impl->close(converter); } - if(!converter->isCopyLocal){ - if (converter->sharedData->referenceCounter != ~0) { - umtx_lock (NULL); - if (converter->sharedData->referenceCounter != 0) { - converter->sharedData->referenceCounter--; - } - umtx_unlock (NULL); + +#if 1 + if(!converter->isCopyLocal) +#endif + if (converter->sharedData->referenceCounter != ~0) { + umtx_lock (NULL); + if (converter->sharedData->referenceCounter != 0) { + converter->sharedData->referenceCounter--; } + umtx_unlock (NULL); + + if((converter->sharedData->referenceCounter == 0)&&(converter->sharedData->sharedDataCached == FALSE)) { + ucnv_deleteSharedConverterData(converter->sharedData); + } + } + + if(!converter->isCopyLocal){ uprv_free (converter); } return; diff --git a/icu4c/source/common/ucnv_bld.c b/icu4c/source/common/ucnv_bld.c index ab7f748f31e..741df2d579d 100644 --- a/icu4c/source/common/ucnv_bld.c +++ b/icu4c/source/common/ucnv_bld.c @@ -107,7 +107,7 @@ static struct { *goes to disk and opens it. *allocates the memory and returns a new UConverter object */ -static UConverterSharedData *createConverterFromFile (const char *converterName, UErrorCode * err); +static UConverterSharedData *createConverterFromFile (const char *pkg, const char *converterName, UErrorCode * err); static const UConverterSharedData *getAlgorithmicTypeFromName (const char *realName); @@ -155,12 +155,12 @@ isCnvAcceptable(void *context, pInfo->dataFormat[1]==0x6e && pInfo->dataFormat[2]==0x76 && pInfo->dataFormat[3]==0x74 && - pInfo->formatVersion[0]==6); + pInfo->formatVersion[0]==6); /* Everything will be version 6 */ } #define DATA_TYPE "cnv" -static UConverterSharedData *createConverterFromFile (const char *fileName, UErrorCode * err) +static UConverterSharedData *createConverterFromFile (const char* pkg, const char *fileName, UErrorCode * err) { UDataMemory *data; UConverterSharedData *sharedData; @@ -169,7 +169,7 @@ static UConverterSharedData *createConverterFromFile (const char *fileName, UErr return NULL; } - data = udata_openChoice(NULL, DATA_TYPE, fileName, isCnvAcceptable, NULL, err); + data = udata_openChoice(pkg, DATA_TYPE, fileName, isCnvAcceptable, NULL, err); if(U_FAILURE(*err)) { return NULL; @@ -245,6 +245,9 @@ ucnv_shareConverterData(UConverterSharedData * data) } UCNV_DEBUG_LOG("put:chk",data->staticData->name,sanity); */ + + /* Mark it shared */ + data->sharedDataCached = TRUE; uhash_put(SHARED_DATA_HASHTABLE, (void*) data->staticData->name, /* Okay to cast away const as long as @@ -283,11 +286,11 @@ ucnv_deleteSharedConverterData(UConverterSharedData * deadSharedData) { if (deadSharedData->referenceCounter > 0) return FALSE; - + if (deadSharedData->impl->unload != NULL) { deadSharedData->impl->unload(deadSharedData); } - + if(deadSharedData->dataMemory != NULL) { UDataMemory *data = (UDataMemory*)deadSharedData->dataMemory; @@ -299,6 +302,20 @@ ucnv_deleteSharedConverterData(UConverterSharedData * deadSharedData) uprv_free(deadSharedData->table); } +#if 0 + /* if the static data is actually owned by the shared data */ + /* enable if we ever have this situation. */ + if(deadSharedData->staticDataOwned == TRUE) /* see ucnv_bld.h */ + { + uprv_free((void*)deadSharedData->staticData); + } +#endif + +#if 0 + /* Zap it ! */ + uprv_memset(deadSharedData->0, sizeof(*deadSharedData)); +#endif + uprv_free(deadSharedData); return TRUE; @@ -452,7 +469,7 @@ ucnv_createConverter (const char *converterName, UErrorCode * err) if (mySharedConverterData == NULL) { /*Not cached, we need to stream it in from file */ - mySharedConverterData = createConverterFromFile (realName, err); + mySharedConverterData = createConverterFromFile (NULL, realName, err); if (U_FAILURE (*err) || (mySharedConverterData == NULL)) { umtx_unlock(&cnvCacheMutex); @@ -475,8 +492,9 @@ ucnv_createConverter (const char *converterName, UErrorCode * err) umtx_unlock(&cnvCacheMutex); } + myUConverter = ucnv_createConverterFromSharedData(mySharedConverterData, realName, locale, options, err); + /* allocate the converter */ - myUConverter = (UConverter *) uprv_malloc (sizeof (UConverter)); if (myUConverter == NULL) { if (mySharedConverterData->referenceCounter != ~0) { @@ -488,6 +506,60 @@ ucnv_createConverter (const char *converterName, UErrorCode * err) return NULL; } + return myUConverter; +} + + +UConverter* +ucnv_createConverterFromPackage(const char *packageName, const char *converterName, UErrorCode * err) +{ + char cnvName[UCNV_MAX_CONVERTER_NAME_LENGTH], locale[ULOC_FULLNAME_CAPACITY]; + uint32_t options=0; + UConverter *myUConverter; + UConverterSharedData *mySharedConverterData = NULL; + + if(U_FAILURE(*err)) { + return NULL; + } + + /* first, get the options out of the convertername string */ + parseConverterOptions(converterName, cnvName, locale, &options, err); + if (U_FAILURE(*err)) { + /* Very bad name used. */ + return NULL; + } + + /* open the data, unflatten the shared structure */ + mySharedConverterData = createConverterFromFile(packageName, cnvName, err); + + if (U_FAILURE(*err)) { + return NULL; + } + + /* create the actual converter */ + myUConverter = ucnv_createConverterFromSharedData( mySharedConverterData, cnvName, locale, options, err); + + if (U_FAILURE(*err)) { + ucnv_close(myUConverter); + return NULL; + } + + return myUConverter; +} + + +UConverter* +ucnv_createConverterFromSharedData(UConverterSharedData *mySharedConverterData, const char *realName, const char *locale, uint32_t options, UErrorCode *err) +{ + UConverter *myUConverter; + + myUConverter = (UConverter *) uprv_malloc (sizeof (UConverter)); + if(myUConverter == NULL) + { + *err = U_MEMORY_ALLOCATION_ERROR; + return NULL; + } + /* initialize the converter */ uprv_memset(myUConverter, 0, sizeof(UConverter)); myUConverter->sharedData = mySharedConverterData; @@ -531,17 +603,6 @@ ucnv_data_unFlattenClone(UDataMemory *pData, UErrorCode *status) return NULL; } -#if 0 - /* necessary only if some converters have different formatVersion; now everything is at version 5 */ - /* test for the format version: MBCS is at version 5, the rest still at 4 */ - info.size=sizeof(UDataInfo); - udata_getInfo(pData, &info); - if(type == UCNV_MBCS ? info.formatVersion[0] != 5 : info.formatVersion[0] != 4) { - *status = U_INVALID_TABLE_FORMAT; - return NULL; - } -#endif - data = (UConverterSharedData *)uprv_malloc(sizeof(UConverterSharedData)); if(data == NULL) { *status = U_MEMORY_ALLOCATION_ERROR; @@ -560,6 +621,8 @@ ucnv_data_unFlattenClone(UDataMemory *pData, UErrorCode *status) } data->staticData = source; + + data->sharedDataCached = FALSE; /* fill in fields from the loaded data */ data->dataMemory = (void*)pData; /* for future use */ @@ -614,6 +677,7 @@ ucnv_flushCache () UCNV_DEBUG_LOG("del",mySharedData->staticData->name,mySharedData); uhash_removeElement(SHARED_DATA_HASHTABLE, e); + mySharedData->sharedDataCached = FALSE; ucnv_deleteSharedConverterData (mySharedData); } } diff --git a/icu4c/source/common/ucnv_bld.h b/icu4c/source/common/ucnv_bld.h index df7f90526e0..ad8f45c2665 100644 --- a/icu4c/source/common/ucnv_bld.h +++ b/icu4c/source/common/ucnv_bld.h @@ -75,11 +75,14 @@ struct UConverterSharedData { uint32_t structSize; /* Size of this structure */ uint32_t referenceCounter; /* used to count number of clients, 0xffffffff for static SharedData */ - const void *dataMemory; /* from udata_openChoice() */ + const void *dataMemory; /* from udata_openChoice() - for cleanup */ UConverterTable *table; /* Pointer to conversion data */ const UConverterStaticData *staticData; /* pointer to the static (non changing) data. */ - UBool staticDataOwned; /* T if we own the staticData */ + + UBool sharedDataCached; /* TRUE: shared data is in cache, don't destroy on ucnv_close() if 0 ref. FALSE: shared data isn't in the cache, do attempt to clean it up if the ref is 0 */ + /*UBool staticDataOwned; TRUE if static data owned by shared data & should be freed with it, NEVER true for udata() loaded statics. This ignored variable was removed to make space for sharedDataCached. */ + const UConverterImpl *impl; /* vtable-style struct of mostly function pointers */ /*initial values of some members of the mutable part of object */ @@ -137,8 +140,9 @@ struct UConverter { const void *fromUContext; const void *toUContext; - UBool isCopyLocal; /* TRUE if created by safeClone with no allocation or ref count */ + UBool isCopyLocal; /* TRUE if created by safeClone with no allocation - Don't free cnv memory on ucnv_close. */ UConverterSharedData *sharedData; /* Pointer to the shared immutable part of the converter object */ + UBool sharedDataIsCached; /* TRUE: shared data is in cache, don't destroy on ucnv_close() if 0 ref. FALSE: shared data isn't in the cache, do attempt to clean it up if the ref is 0 */ /* * currently only used to point to a struct containing UConverter used by iso 2022; diff --git a/icu4c/source/common/ucnv_imp.h b/icu4c/source/common/ucnv_imp.h index 44a53ee9148..ebfe97f3717 100644 --- a/icu4c/source/common/ucnv_imp.h +++ b/icu4c/source/common/ucnv_imp.h @@ -30,6 +30,14 @@ */ UConverter *ucnv_createConverter (const char *converterName, UErrorCode * err); +/* Creates a converter from shared data + */ +UConverter* +ucnv_createConverterFromSharedData(UConverterSharedData *mySharedConverterData, const char *realName, const char *locale, uint32_t options, UErrorCode *err); + +UConverter* ucnv_createConverterFromPackage(const char *packageName, const char *converterName, + UErrorCode *err); + /* Stores the shared data in the SHARED_DATA_HASHTABLE * @param data The shared data */ diff --git a/icu4c/source/common/unicode/ucnv.h b/icu4c/source/common/unicode/ucnv.h index 08b36ea9d34..51e4bdeb494 100644 --- a/icu4c/source/common/unicode/ucnv.h +++ b/icu4c/source/common/unicode/ucnv.h @@ -324,6 +324,36 @@ ucnv_openCCSID (int32_t codepage, UConverterPlatform platform, UErrorCode * err); +/** + *
Creates a UConverter object specified from a packageName and a converterName.
+ * + *The packageName and converterName must point to an ICU udata object, as defined by
+ * udata_open( packageName, "cnv", converterName, err)
or equivalent.
+ * Typically, packageName will refer to a (.dat) file, or to a package registered with
+ * udata_setAppData().
The name will NOT be looked up in the alias mechanism, nor will the converter be + * stored in the converter cache or the alias table. The only way to open further converters + * is call this function multiple times, or use the ucnv_safeClone() function to clone a + * 'master' converter.
+ * + *Example Use:
+ * cnv = ucnv_openPackage("myapp", "myconverter", &err);
+ *