/*initializes some global variables */ static UHashtable *SHARED_DATA_HASHTABLE = nullptr; static icu::UMutex cnvCacheMutex; /* Note: the global mutex is used for */ /* reference count updates. */
/* This contains the resolved converter name. So no further alias lookup is needed again. */ staticchar gDefaultConverterNameBuffer[UCNV_MAX_CONVERTER_NAME_LENGTH + 1]; /* +1 for nullptr */ staticconstchar *gDefaultConverterName = nullptr;
/* Does gDefaultConverterName have a converter option and require extra parsing? */ static UBool gDefaultConverterContainsOption;
#endif/* !U_CHARSET_IS_UTF8 */
staticconstchar DATA_TYPE[] = "cnv";
/* ucnv_flushAvailableConverterCache. This is only called from ucnv_cleanup(). *Ifitisevertobecalledfromelsewhere,synchronization *willneedtobeconsidered.
*/ staticvoid
ucnv_flushAvailableConverterCache() {
gAvailableConverterCount = 0; if (gAvailableConverters) {
uprv_free(const_cast<char**>(gAvailableConverters));
gAvailableConverters = nullptr;
}
gAvailableConvertersInitOnce.reset();
}
/* ucnv_cleanup - delete all storage held by the converter cache, except any */ /* in use by open converters. */ /* Not thread safe. */ /* Not supported API. */ static UBool U_CALLCONV ucnv_cleanup() {
ucnv_flushCache(); if (SHARED_DATA_HASHTABLE != nullptr && uhash_count(SHARED_DATA_HASHTABLE) == 0) {
uhash_close(SHARED_DATA_HASHTABLE);
SHARED_DATA_HASHTABLE = nullptr;
}
/* Isn't called from flushCache because other threads may have preexisting references to the table. */
ucnv_flushAvailableConverterCache();
/*Takes an alias name gets an actual converter file name *goestodiskandopensit. *allocatesthememoryandreturnsanewUConverterobject
*/ static UConverterSharedData *createConverterFromFile(UConverterLoadArgs *pArgs, UErrorCode * err)
{
UDataMemory *data;
UConverterSharedData *sharedData;
UTRACE_ENTRY_OC(UTRACE_UCNV_LOAD);
if (U_FAILURE (*err)) {
UTRACE_EXIT_STATUS(*err); return nullptr;
}
UTRACE_DATA2(UTRACE_OPEN_CLOSE, "load converter %s from package %s", pArgs->name, pArgs->pkg);
/*returns a converter type from a string
*/ staticconst UConverterSharedData *
getAlgorithmicTypeFromName(constchar *realName)
{
uint32_t mid, start, limit;
uint32_t lastMid; int result; char strippedName[UCNV_MAX_CONVERTER_NAME_LENGTH];
/* Lower case and remove ignoreable characters. */
ucnv_io_stripForCompare(strippedName, realName);
/* do a binary search for the alias */
start = 0;
limit = UPRV_LENGTHOF(cnvNameType);
mid = limit;
lastMid = UINT32_MAX;
for (;;) {
mid = (start + limit) / 2; if (lastMid == mid) { /* Have we moved? */ break; /* We haven't moved, and it wasn't found. */
}
lastMid = mid;
result = uprv_strcmp(strippedName, cnvNameType[mid].name);
/* Puts the shared data in the static hashtable SHARED_DATA_HASHTABLE */ /* Will always be called with the cnvCacheMutex already being held */ /* by the calling function. */ /* Stores the shared data in the SHARED_DATA_HASHTABLE *@paramdataTheshareddata
*/ staticvoid
ucnv_shareConverterData(UConverterSharedData * data)
{
UErrorCode err = U_ZERO_ERROR; /*Lazy evaluates the Hashtable itself */ /*void *sanity = nullptr;*/
/* Mark it shared */
data->sharedDataCached = true;
uhash_put(SHARED_DATA_HASHTABLE,
(void*) data->staticData->name, /* Okay to cast away const as long as
keyDeleter == nullptr */
data,
&err);
UCNV_DEBUG_LOG("put", data->staticData->name,data);
}
/* Look up a converter name in the shared data cache. */ /* cnvCacheMutex must be held by the caller to protect the hash table. */ /* gets the shared data from the SHARED_DATA_HASHTABLE (might return nullptr if it isn't there) *@paramnameThenameoftheshareddata *@returntheshareddatafromtheSHARED_DATA_HASHTABLE
*/ static UConverterSharedData *
ucnv_getSharedConverterData(constchar *name)
{ /*special case when no Table has yet been created we return nullptr */ if (SHARED_DATA_HASHTABLE == nullptr)
{ return nullptr;
} else
{
UConverterSharedData *rc;
/*frees the string of memory blocks associates with a sharedConverter *ifandonlyifthereferenceCounter==0
*/ /* Deletes (frees) the Shared data it's passed. first it checks the referenceCounter to *seeifanyoneisusingit,ifnotitfreesallthememorystemmingfromsharedConverterDataand *returnstrue, *otherwisereturnsfalse *@paramsharedConverterDataTheshareddata *@returnifnotitfreesallthememorystemmingfromsharedConverterDataand *returnstrue,otherwisereturnsfalse
*/ static UBool
ucnv_deleteSharedConverterData(UConverterSharedData * deadSharedData)
{
UTRACE_ENTRY_OC(UTRACE_UCNV_UNLOAD);
UTRACE_DATA2(UTRACE_OPEN_CLOSE, "unload converter %s shared data %p", deadSharedData->staticData->name, deadSharedData);
if (deadSharedData->referenceCounter > 0) {
UTRACE_EXIT_VALUE((int32_t)false); returnfalse;
}
if (deadSharedData->impl->unload != nullptr) {
deadSharedData->impl->unload(deadSharedData);
}
if(pArgs->pkg != nullptr && *pArgs->pkg != 0) { /* application-provided converters are not currently cached */ return createConverterFromFile(pArgs, err);
}
mySharedConverterData = ucnv_getSharedConverterData(pArgs->name); if (mySharedConverterData == nullptr)
{ /*Not cached, we need to stream it in from file */
mySharedConverterData = createConverterFromFile(pArgs, err); if (U_FAILURE (*err) || (mySharedConverterData == nullptr))
{ return nullptr;
} elseif (!pArgs->onlyTestIsLoadable)
{ /* share it with other library clients */
ucnv_shareConverterData(mySharedConverterData);
}
} else
{ /* The data for this converter was already in the cache. */ /* Update the reference counter on the shared data: one more client */
mySharedConverterData->referenceCounter++;
}
/* copy the converter name itself to cnvName */ while((c=*inName)!=0 && c!=UCNV_OPTION_SEP_CHAR) { if (++len>=UCNV_MAX_CONVERTER_NAME_LENGTH) {
*err = U_ILLEGAL_ARGUMENT_ERROR; /* bad name */
pPieces->cnvName[0]=0; return;
}
*cnvName++=c;
inName++;
}
*cnvName=0;
pArgs->name=pPieces->cnvName;
/* parse options. No more name copying should occur. */ while((c=*inName)!=0) { if(c==UCNV_OPTION_SEP_CHAR) {
++inName;
}
/* inName is behind an option separator */ if(uprv_strncmp(inName, "locale=", 7)==0) { /* do not modify locale itself in case we have multiple locale options */ char *dest=pPieces->locale;
/* copy the locale option value */
inName+=7;
len=0; while((c=*inName)!=0 && c!=UCNV_OPTION_SEP_CHAR) {
++inName;
if(++len>=ULOC_FULLNAME_CAPACITY) {
*err=U_ILLEGAL_ARGUMENT_ERROR; /* bad name */
pPieces->locale[0]=0; return;
}
*dest++=c;
}
*dest=0;
} elseif(uprv_strncmp(inName, "version=", 8)==0) { /* copy the version option value into bits 3..0 of pPieces->options */
inName+=8;
c=*inName; if(c==0) {
pArgs->options=(pPieces->options&=~UCNV_OPTION_VERSION); return;
} elseif (static_cast<uint8_t>(c - '0') < 10) {
pArgs->options = pPieces->options = (pPieces->options & ~UCNV_OPTION_VERSION) | static_cast<uint32_t>(c - '0');
++inName;
}
} elseif(uprv_strncmp(inName, "swaplfnl", 8)==0) {
inName+=8;
pArgs->options=(pPieces->options|=UCNV_OPTION_SWAP_LFNL); /* add processing for new options here with another } else if(uprv_strncmp(inName, "option-name=", XX)==0) { */
} else { /* ignore any other options until we define some */ while(((c = *inName++) != 0) && (c != UCNV_OPTION_SEP_CHAR)) {
} if(c==0) { return;
}
}
}
}
/* In case "name" is nullptr we want to open the default converter. */ if (converterName == nullptr) { #if U_CHARSET_IS_UTF8
pArgs->name = "UTF-8"; return (UConverterSharedData *)converterData[UCNV_UTF8]; #else /* Call ucnv_getDefaultName first to query the name from the OS. */
pArgs->name = ucnv_getDefaultName(); if (pArgs->name == nullptr) {
*err = U_MISSING_RESOURCE_ERROR; return nullptr;
}
mySharedConverterData = (UConverterSharedData *)gDefaultAlgorithmicSharedData;
checkForAlgorithmic = false;
mayContainOption = gDefaultConverterContainsOption; /* the default converter name is already canonical */ #endif
} elseif(UCNV_FAST_IS_UTF8(converterName)) { /* fastpath for UTF-8 */
pArgs->name = "UTF-8"; return (UConverterSharedData *)converterData[UCNV_UTF8];
} else { /* separate the converter name from the options */
parseConverterOptions(converterName, pPieces, pArgs, err); if (U_FAILURE(*err)) { /* Very bad name used. */ return nullptr;
}
/* get the canonical converter name */
pArgs->name = ucnv_io_getConverterName(pArgs->name, &mayContainOption, &internalErrorCode); if (U_FAILURE(internalErrorCode) || pArgs->name == nullptr) { /* *settheinputnameincasetheconverterwasadded *withoutupdatingthealiastable,orwhenthereisnoaliastable
*/
pArgs->name = pPieces->cnvName;
} elseif (internalErrorCode == U_AMBIGUOUS_ALIAS_WARNING) {
*err = U_AMBIGUOUS_ALIAS_WARNING;
}
}
/* separate the converter name from the options */ if(mayContainOption && pArgs->name != pPieces->cnvName) {
parseConverterOptions(pArgs->name, pPieces, pArgs, err);
}
/* get the shared data for an algorithmic converter, if it is one */ if (checkForAlgorithmic) {
mySharedConverterData = (UConverterSharedData *)getAlgorithmicTypeFromName(pArgs->name);
} if (mySharedConverterData == nullptr)
{ /* it is a data-based converter, get its shared data. */ /* Hold the cnvCacheMutex through the whole process of checking the */ /* converter data cache, and adding new entries to the cache */ /* to prevent other threads from modifying the cache during the */ /* process. */
pArgs->nestedLoads=1;
pArgs->pkg=nullptr;
UTRACE_DATA2(UTRACE_OPEN_CLOSE, "open converter %s from package %s", converterName, packageName);
/* first, get the options out of the converterName string */
stackPieces.cnvName[0] = 0;
stackPieces.locale[0] = 0;
stackPieces.options = 0;
parseConverterOptions(converterName, &stackPieces, &stackArgs, err); if (U_FAILURE(*err)) { /* Very bad name used. */
UTRACE_EXIT_STATUS(*err); return nullptr;
}
stackArgs.nestedLoads=1;
stackArgs.pkg=packageName;
/* open the data, unflatten the shared structure */
mySharedConverterData = createConverterFromFile(&stackArgs, err);
if (U_FAILURE(*err)) {
UTRACE_EXIT_STATUS(*err); return nullptr;
}
/* create the actual converter */
myUConverter = ucnv_createConverterFromSharedData(nullptr, mySharedConverterData, &stackArgs, err);
if (U_FAILURE(*err)) {
ucnv_close(myUConverter);
UTRACE_EXIT_STATUS(*err); return nullptr;
}
/* We can't have more than "*converterTable" converters to open */
gAvailableConverters = static_cast<constchar**>(uprv_malloc(allConverterCount * sizeof(char*))); if (!gAvailableConverters) {
errCode = U_MEMORY_ALLOCATION_ERROR; return;
}
/* Open the default converter to make sure that it has first dibs in the hash table. */
UErrorCode localStatus = U_ZERO_ERROR;
UConverter tempConverter;
ucnv_close(ucnv_createConverter(&tempConverter, nullptr, &localStatus));
/* gDefaultConverterName MUST be the last global var set by this function. */ /* It is the variable checked in ucnv_getDefaultName() to see if initialization is required. */ // But there is nothing here preventing that from being reordered, either by the compiler // or hardware. I'm adding the mutex to ucnv_getDefaultName for now. UMTX_CHECK is not enough. // -- Andy
gDefaultConverterName = gDefaultConverterNameBuffer;
/* if the name is there, test it out and get the canonical name with options */ if(name != nullptr) {
cnv = ucnv_open(name, &errorCode); if(U_SUCCESS(errorCode) && cnv != nullptr) {
name = ucnv_getName(cnv, &errorCode);
}
}
if(name == nullptr || name[0] == 0
|| U_FAILURE(errorCode) || cnv == nullptr
|| uprv_strlen(name)>=sizeof(gDefaultConverterNameBuffer))
{ /* Panic time, let's use a fallback. */ #if (U_CHARSET_FAMILY == U_ASCII_FAMILY)
name = "US-ASCII"; /* there is no 'algorithmic' converter for EBCDIC */ #elif U_PLATFORM == U_PF_OS390
name = "ibm-1047_P100-1995" UCNV_SWAP_LFNL_OPTION_STRING; #else
name = "ibm-37_P100-1995"; #endif
}
internalSetName(name, &errorCode);
/* The close may make the current name go away. */
ucnv_close(cnv);
}
/* if the name is there, test it out and get the canonical name with options */
cnv = ucnv_open(converterName, &errorCode); if(U_SUCCESS(errorCode) && cnv != nullptr) {
name = ucnv_getName(cnv, &errorCode);
}
if(U_SUCCESS(errorCode) && name!=nullptr) {
internalSetName(name, &errorCode);
} /* else this converter is bad to use. Don't change it to a bad value. */
/* The close may make the current name go away. */
ucnv_close(cnv);
/* reset the converter cache */
u_flushDefaultConverter();
}
} #endif
/* data swapping ------------------------------------------------------------ */
/* most of this might belong more properly into ucnvmbcs.c, but that is so large */
/* check data format and format version */
pInfo=(const UDataInfo *)((constchar *)inData+4); if(!(
pInfo->dataFormat[0]==0x63 && /* dataFormat="cnvt" */
pInfo->dataFormat[1]==0x6e &&
pInfo->dataFormat[2]==0x76 &&
pInfo->dataFormat[3]==0x74 &&
pInfo->formatVersion[0]==6 &&
pInfo->formatVersion[1]>=2
)) {
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",
pInfo->dataFormat[0], pInfo->dataFormat[1],
pInfo->dataFormat[2], pInfo->dataFormat[3],
pInfo->formatVersion[0], pInfo->formatVersion[1]);
*pErrorCode=U_UNSUPPORTED_ERROR; return0;
}
extOffset=(int32_t)(mbcsHeader.flags>>8);
outputType=(uint8_t)mbcsHeader.flags; if(noFromU && outputType==MBCS_OUTPUT_1) {
udata_printError(ds, "ucnv_swap(): unsupported combination of makeconv --small with SBCS\n");
*pErrorCode=U_UNSUPPORTED_ERROR; return0;
}
/* make sure that the output type is known */ switch(outputType) { case MBCS_OUTPUT_1: case MBCS_OUTPUT_2: case MBCS_OUTPUT_3: case MBCS_OUTPUT_4: case MBCS_OUTPUT_3_EUC: case MBCS_OUTPUT_4_EUC: case MBCS_OUTPUT_2_SISO: case MBCS_OUTPUT_EXT_ONLY: /* OK */ break; default:
udata_printError(ds, "ucnv_swap(): unsupported MBCS output type 0x%x\n",
outputType);
*pErrorCode=U_UNSUPPORTED_ERROR; return0;
}
/* avoid compiler warnings - not otherwise necessary, and the value does not matter */
inExtIndexes=nullptr;
} else { /* there is extension data after the base data, see ucnv_ext.h */ if(length>=0 && length<(extOffset+UCNV_EXT_INDEXES_MIN_LENGTH*4)) {
udata_printError(ds, "ucnv_swap(): too few bytes (%d after headers) for an ICU MBCS .cnv conversion table with extension data\n",
length);
*pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; return0;
}
if(length>=0) { if(length<size) {
udata_printError(ds, "ucnv_swap(): too few bytes (%d after headers) for an ICU MBCS .cnv conversion table\n",
length);
*pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; return0;
}
/* copy the data for inaccessible bytes */ if(inBytes!=outBytes) {
uprv_memcpy(outBytes, inBytes, size);
}
/* swap the MBCSHeader, except for the version field */
count=mbcsHeaderLength*4;
ds->swapArray32(ds, &inMBCSHeader->countStates, count-4,
&outMBCSHeader->countStates, pErrorCode);
/* swap the base name, between the header and the extension data */ constchar *inBaseName=(constchar *)inBytes+count; char *outBaseName=(char *)outBytes+count;
ds->swapInvChars(ds, inBaseName, (int32_t)uprv_strlen(inBaseName),
outBaseName, pErrorCode);
} else { /* normal file with base table data */
/* swap the state table, 1kB per state */
offset=count;
count=mbcsHeader.countStates*1024;
ds->swapArray32(ds, inBytes+offset, (int32_t)count,
outBytes+offset, pErrorCode);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.