diff --git a/icu4c/source/common/ucnv_bld.c b/icu4c/source/common/ucnv_bld.c index 42db2467daa..062bd6d7c04 100644 --- a/icu4c/source/common/ucnv_bld.c +++ b/icu4c/source/common/ucnv_bld.c @@ -197,7 +197,7 @@ isCnvAcceptable(void *context, * Un flatten shared data from a UDATA.. */ static UConverterSharedData* -ucnv_data_unFlattenClone(UDataMemory *pData, UErrorCode *status) +ucnv_data_unFlattenClone(UConverterLoadArgs *pArgs, UDataMemory *pData, UErrorCode *status) { /* UDataInfo info; -- necessary only if some converters have different formatVersion */ const uint8_t *raw = (const uint8_t *)udata_getMemory(pData); @@ -254,7 +254,7 @@ ucnv_data_unFlattenClone(UDataMemory *pData, UErrorCode *status) data->dataMemory = (void*)pData; /* for future use */ if(data->impl->load != NULL) { - data->impl->load(data, raw + source->structSize, status); + data->impl->load(data, pArgs, raw + source->structSize, status); if(U_FAILURE(*status)) { uprv_free(data->table); uprv_free(data); @@ -268,7 +268,7 @@ ucnv_data_unFlattenClone(UDataMemory *pData, UErrorCode *status) *goes to disk and opens it. *allocates the memory and returns a new UConverter object */ -static UConverterSharedData *createConverterFromFile(const char* pkg, const char *fileName, UErrorCode * err) +static UConverterSharedData *createConverterFromFile(UConverterLoadArgs *pArgs, UErrorCode * err) { UDataMemory *data; UConverterSharedData *sharedData; @@ -277,13 +277,13 @@ static UConverterSharedData *createConverterFromFile(const char* pkg, const char return NULL; } - data = udata_openChoice(pkg, DATA_TYPE, fileName, isCnvAcceptable, NULL, err); + data = udata_openChoice(pArgs->pkg, DATA_TYPE, pArgs->name, isCnvAcceptable, NULL, err); if(U_FAILURE(*err)) { return NULL; } - sharedData = ucnv_data_unFlattenClone(data, err); + sharedData = ucnv_data_unFlattenClone(pArgs, data, err); if(U_FAILURE(*err)) { udata_close(data); @@ -481,23 +481,23 @@ ucnv_deleteSharedConverterData(UConverterSharedData * deadSharedData) * If pkg==NULL, then this function must be called inside umtx_lock(&cnvCacheMutex). */ UConverterSharedData * -ucnv_load(const char *pkg, const char *realName, UErrorCode *err) { +ucnv_load(UConverterLoadArgs *pArgs, UErrorCode *err) { UConverterSharedData *mySharedConverterData; if(err == NULL || U_FAILURE(*err)) { return NULL; } - if(pkg != NULL && *pkg != 0) { + if(pArgs->pkg != NULL && *pArgs->pkg != 0) { /* application-provided converters are not currently cached */ - return createConverterFromFile(pkg, realName, err); + return createConverterFromFile(pArgs, err); } - mySharedConverterData = ucnv_getSharedConverterData(realName); + mySharedConverterData = ucnv_getSharedConverterData(pArgs->name); if (mySharedConverterData == NULL) { /*Not cached, we need to stream it in from file */ - mySharedConverterData = createConverterFromFile(NULL, realName, err); + mySharedConverterData = createConverterFromFile(pArgs, err); if (U_FAILURE (*err) || (mySharedConverterData == NULL)) { return NULL; @@ -703,8 +703,16 @@ ucnv_createConverter(UConverter *myUConverter, const char *converterName, UError /* converter data cache, and adding new entries to the cache */ /* to prevent other threads from modifying the cache during the */ /* process. */ + UConverterLoadArgs args={ 0 }; + + args.size=sizeof(UConverterLoadArgs); + args.nestedLoads=1; + args.options=options; + args.pkg=NULL; + args.name=realName; + umtx_lock(&cnvCacheMutex); - mySharedConverterData = ucnv_load(NULL, realName, err); + mySharedConverterData = ucnv_load(&args, err); umtx_unlock(&cnvCacheMutex); if (U_FAILURE (*err) || (mySharedConverterData == NULL)) { @@ -763,30 +771,36 @@ 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; + UConverterSharedData *mySharedConverterData; + + UConverterLoadArgs args={ 0 }; if(U_FAILURE(*err)) { return NULL; } - /* first, get the options out of the convertername string */ - parseConverterOptions(converterName, cnvName, locale, &options, err); + args.size=sizeof(UConverterLoadArgs); + args.nestedLoads=1; + args.pkg=packageName; + + /* first, get the options out of the converterName string */ + parseConverterOptions(converterName, cnvName, locale, &args.options, err); if (U_FAILURE(*err)) { /* Very bad name used. */ return NULL; } + args.name=cnvName; /* open the data, unflatten the shared structure */ - mySharedConverterData = createConverterFromFile(packageName, cnvName, err); + mySharedConverterData = createConverterFromFile(&args, err); if (U_FAILURE(*err)) { return NULL; } /* create the actual converter */ - myUConverter = ucnv_createConverterFromSharedData(NULL, mySharedConverterData, cnvName, locale, options, err); + myUConverter = ucnv_createConverterFromSharedData(NULL, mySharedConverterData, cnvName, locale, args.options, err); if (U_FAILURE(*err)) { ucnv_close(myUConverter); diff --git a/icu4c/source/common/ucnv_bld.h b/icu4c/source/common/ucnv_bld.h index 3d2a4c66920..d53c2142884 100644 --- a/icu4c/source/common/ucnv_bld.h +++ b/icu4c/source/common/ucnv_bld.h @@ -232,7 +232,7 @@ UConverterDataLMBCS; * If pkg==NULL, then this function must be called inside umtx_lock(&cnvCacheMutex). */ UConverterSharedData * -ucnv_load(const char *pkg, const char *name, UErrorCode *err); +ucnv_load(UConverterLoadArgs *pArgs, UErrorCode *err); /** * Unload a non-algorithmic converter. diff --git a/icu4c/source/common/ucnv_cnv.h b/icu4c/source/common/ucnv_cnv.h index 17ba5b495d7..62856bbfd56 100644 --- a/icu4c/source/common/ucnv_cnv.h +++ b/icu4c/source/common/ucnv_cnv.h @@ -41,7 +41,18 @@ typedef struct UConverterSharedData UConverterSharedData; /* function types for UConverterImpl ---------------------------------------- */ -typedef void (*UConverterLoad) (UConverterSharedData *sharedData, const uint8_t *raw, UErrorCode *pErrorCode); +/* struct with arguments for UConverterLoad and ucnv_load() */ +typedef struct { + int32_t size; /* sizeof(UConverterLoadArgs) */ + int32_t nestedLoads; /* count nested ucnv_load() calls */ + int32_t reserved; /* reserved - for good alignment of the pointers */ + uint32_t options; + const char *pkg, *name; +} UConverterLoadArgs; + +typedef void (*UConverterLoad) (UConverterSharedData *sharedData, + UConverterLoadArgs *pArgs, + const uint8_t *raw, UErrorCode *pErrorCode); typedef void (*UConverterUnload) (UConverterSharedData *sharedData); typedef void (*UConverterOpen) (UConverter *cnv, const char *name, const char *locale,uint32_t options, UErrorCode *pErrorCode); diff --git a/icu4c/source/common/ucnvmbcs.c b/icu4c/source/common/ucnvmbcs.c index 8fa5e3a3d6e..70d02a10a8f 100644 --- a/icu4c/source/common/ucnvmbcs.c +++ b/icu4c/source/common/ucnvmbcs.c @@ -863,6 +863,7 @@ _EBCDICSwapLFNL(UConverterSharedData *sharedData, UErrorCode *pErrorCode) { static void _MBCSLoad(UConverterSharedData *sharedData, + UConverterLoadArgs *pArgs, const uint8_t *raw, UErrorCode *pErrorCode) { UDataInfo info; @@ -884,6 +885,7 @@ _MBCSLoad(UConverterSharedData *sharedData, } if(mbcsTable->outputType==MBCS_OUTPUT_EXT_ONLY) { + UConverterLoadArgs args={ 0 }; UConverterSharedData *baseSharedData; const int32_t *extIndexes; const char *baseName; @@ -895,17 +897,28 @@ _MBCSLoad(UConverterSharedData *sharedData, return; } + if(pArgs->nestedLoads!=1) { + /* an extension table must not be loaded as a base table */ + *pErrorCode=U_INVALID_TABLE_FILE; + return; + } + /* load the base table */ baseName=(const char *)(header+1); if(0==uprv_strcmp(baseName, sharedData->staticData->name)) { /* forbid loading this same extension-only file */ - /* TODO better prevention of loading another extension table */ *pErrorCode=U_INVALID_TABLE_FORMAT; return; } - /* TODO pass package name, same as current converter (see ucnv_bld.c) and/or parse out of prefix of base name */ - baseSharedData=ucnv_load(NULL, baseName, pErrorCode); + /* TODO parse package name out of the prefix of the base name in the extension .cnv file? */ + args.size=sizeof(UConverterLoadArgs); + args.nestedLoads=2; + args.reserved=pArgs->reserved; + args.options=pArgs->options; + args.pkg=pArgs->pkg; + args.name=baseName; + baseSharedData=ucnv_load(&args, pErrorCode); if(U_FAILURE(*pErrorCode)) { return; } diff --git a/icu4c/source/test/testdata/conversion.txt b/icu4c/source/test/testdata/conversion.txt index 2d105402e3c..33211ef5490 100644 --- a/icu4c/source/test/testdata/conversion.txt +++ b/icu4c/source/test/testdata/conversion.txt @@ -177,6 +177,15 @@ conversion { fromUnicode { Headers { "charset", "unicode", "bytes", "offsets", "flush", "fallbacks", "errorCode", "callback", "invalidUChars" } Cases { + // extension in testdata + { + "*test4x", + "\u20ac\x09", + :bin{ 0009 }, + :intvector{ 0, 1 }, + :int{1}, :int{1}, "", "?", "" + } + // DBCS-only extensions { "ibm-970", diff --git a/icu4c/source/test/testdata/test4x.ucm b/icu4c/source/test/testdata/test4x.ucm new file mode 100644 index 00000000000..c7692aaece8 --- /dev/null +++ b/icu4c/source/test/testdata/test4x.ucm @@ -0,0 +1,20 @@ +# ******************************************************************************* +# * Copyright (C) 2003, International Business Machines +# * Corporation and others. All Rights Reserved. +# ******************************************************************************* +# +# test4x.ucm +# +# Test file for MBCS conversion extension with four-byte codepage data. + + "test4x" + 4 + 1 + "MBCS" + +# test loading an extension table from the testdata package + "test4" + +CHARMAP + \x09 |0 +END CHARMAP diff --git a/icu4c/source/test/testdata/testdata.mk b/icu4c/source/test/testdata/testdata.mk index b28455a7894..ba35661aedd 100644 --- a/icu4c/source/test/testdata/testdata.mk +++ b/icu4c/source/test/testdata/testdata.mk @@ -14,7 +14,7 @@ TESTDT=$(TESTPKG)_ ALL : "$(TESTDATAOUT)\testdata.dat" @echo Test data is built. -"$(TESTDATAOUT)\testdata.dat" : "$(TESTDATABLD)\casing.res" "$(TESTDATABLD)\conversion.res" "$(TESTDATABLD)\mc.res" "$(TESTDATABLD)\root.res" "$(TESTDATABLD)\te.res" "$(TESTDATABLD)\te_IN.res" "$(TESTDATABLD)\testaliases.res" "$(TESTDATABLD)\testtypes.res" "$(TESTDATABLD)\testempty.res" "$(TESTDATABLD)\$(TESTDT)iscii.res" "$(TESTDATABLD)\$(TESTDT)idna_rules.res" "$(TESTDATABLD)\DataDrivenCollationTest.res" "$(TESTDATABLD)\$(TESTDT)test.icu" "$(TESTDATABLD)\$(TESTDT)testtable32.res" "$(TESTDATABLD)\$(TESTDT)test1.cnv" "$(TESTDATABLD)\$(TESTDT)test3.cnv" "$(TESTDATABLD)\$(TESTDT)test4.cnv" "$(TESTDATABLD)\$(TESTDT)ibm9027.cnv" "$(TESTDATABLD)\$(TESTDT)nfscsi.spp" "$(TESTDATABLD)\$(TESTDT)nfscss.spp" "$(TESTDATABLD)\$(TESTDT)nfscis.spp" "$(TESTDATABLD)\$(TESTDT)nfsmxs.spp" "$(TESTDATABLD)\$(TESTDT)nfsmxp.spp" +"$(TESTDATAOUT)\testdata.dat" : "$(TESTDATABLD)\casing.res" "$(TESTDATABLD)\conversion.res" "$(TESTDATABLD)\mc.res" "$(TESTDATABLD)\root.res" "$(TESTDATABLD)\te.res" "$(TESTDATABLD)\te_IN.res" "$(TESTDATABLD)\testaliases.res" "$(TESTDATABLD)\testtypes.res" "$(TESTDATABLD)\testempty.res" "$(TESTDATABLD)\$(TESTDT)iscii.res" "$(TESTDATABLD)\$(TESTDT)idna_rules.res" "$(TESTDATABLD)\DataDrivenCollationTest.res" "$(TESTDATABLD)\$(TESTDT)test.icu" "$(TESTDATABLD)\$(TESTDT)testtable32.res" "$(TESTDATABLD)\$(TESTDT)test1.cnv" "$(TESTDATABLD)\$(TESTDT)test3.cnv" "$(TESTDATABLD)\$(TESTDT)test4.cnv" "$(TESTDATABLD)\$(TESTDT)test4x.cnv" "$(TESTDATABLD)\$(TESTDT)ibm9027.cnv" "$(TESTDATABLD)\$(TESTDT)nfscsi.spp" "$(TESTDATABLD)\$(TESTDT)nfscss.spp" "$(TESTDATABLD)\$(TESTDT)nfscis.spp" "$(TESTDATABLD)\$(TESTDT)nfsmxs.spp" "$(TESTDATABLD)\$(TESTDT)nfsmxp.spp" @echo Building test data @copy "$(TESTDATABLD)\$(TESTDT)te.res" "$(TESTDATAOUT)\$(TESTDT)nam.typ" @"$(ICUP)\bin\pkgdata" -f -v -m common -c -p"$(TESTPKG)" -d "$(TESTDATAOUT)" -T "$(TESTDATABLD)" -s "$(TESTDATABLD)" << @@ -34,6 +34,7 @@ $(TESTDT)test.icu $(TESTDT)test1.cnv $(TESTDT)test3.cnv $(TESTDT)test4.cnv +$(TESTDT)test4x.cnv $(TESTDT)ibm9027.cnv $(TESTDT)idna_rules.res $(TESTDT)nfscsi.spp @@ -107,6 +108,9 @@ $(TESTDT)nfsmxp.spp "$(TESTDATABLD)\$(TESTDT)test4.cnv": "$(TESTDATA)\test4.ucm" @"$(ICUTOOLS)\makeconv\$(CFG)\makeconv" -d"$(TESTDATABLD)" -p $(TESTPKG) $** +"$(TESTDATABLD)\$(TESTDT)test4x.cnv": "$(TESTDATA)\test4x.ucm" + @"$(ICUTOOLS)\makeconv\$(CFG)\makeconv" -d"$(TESTDATABLD)" -p $(TESTPKG) $** + "$(TESTDATABLD)\$(TESTDT)ibm9027.cnv": "$(TESTDATA)\ibm9027.ucm" @"$(ICUTOOLS)\makeconv\$(CFG)\makeconv" -d"$(TESTDATABLD)" -p $(TESTPKG) $**