/*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;
/* If the default converter is an algorithmic converter, this is the cached value. We don't cache a full UConverter and clone it because ucnv_clone doesn't have less overhead than an algorithmic open. We don't cache non-algorithmic converters because ucnv_flushCache must be able to unload the default converter and its table.
*/ staticconst UConverterSharedData *gDefaultAlgorithmicSharedData = 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(). * If it is ever to be called from elsewhere, synchronization * will need to be considered.
*/ 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();
/** * Un flatten shared data from a UDATA..
*/ static UConverterSharedData*
ucnv_data_unFlattenClone(UConverterLoadArgs *pArgs, UDataMemory *pData, UErrorCode *status)
{ /* UDataInfo info; -- necessary only if some converters have different formatVersion */ const uint8_t* raw = static_cast<const uint8_t*>(udata_getMemory(pData)); const UConverterStaticData* source = reinterpret_cast<const UConverterStaticData*>(raw);
UConverterSharedData *data;
UConverterType type = static_cast<UConverterType>(source->conversionType);
/*Takes an alias name gets an actual converter file name *goes to disk and opens it. *allocates the memory and returns a new UConverter object
*/ 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);
/* * TODO Store pkg in a field in the shared data so that delta-only converters * can load base converters from the same package. * If the pkg name is longer than the field, then either do not load the converter * in the first place, or just set the pkg field to "".
*/
/*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);
/* * Based on the number of known converters, this determines how many times larger * the shared data hash table should be. When on small platforms, or just a couple * of converters are used, this number should be 2. When memory is plentiful, or * when ucnv_countAvailable is ever used with a lot of available converters, * this should be 4. * Larger numbers reduce the number of hash collisions, but use more memory.
*/ #define UCNV_CACHE_LOAD_FACTOR 2
/* 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 * @param data The shared data
*/ 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) * @param name The name of the shared data * @return the shared data from the SHARED_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 *if and only if the referenceCounter == 0
*/ /* Deletes (frees) the Shared data it's passed. first it checks the referenceCounter to * see if anyone is using it, if not it frees all the memory stemming from sharedConverterData and * returns true, * otherwise returns false * @param sharedConverterData The shared data * @return if not it frees all the memory stemming from sharedConverterData and * returns true, otherwise returns false
*/ 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);
}
/** * Load a non-algorithmic converter. * If pkg==nullptr, then this function must be called inside umtx_lock(&cnvCacheMutex).
*/
UConverterSharedData *
ucnv_load(UConverterLoadArgs *pArgs, UErrorCode *err) {
UConverterSharedData *mySharedConverterData;
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++;
}
return mySharedConverterData;
}
/** * Unload a non-algorithmic converter. * It must be sharedData->isReferenceCounted * and this function must be called inside umtx_lock(&cnvCacheMutex).
*/
U_CAPI void
ucnv_unload(UConverterSharedData *sharedData) { if(sharedData != nullptr) { if (sharedData->referenceCounter > 0) {
sharedData->referenceCounter--;
}
/* * *pPieces must be initialized. * The name without options will be copied to pPieces->cnvName. * The locale and options will be copied to pPieces only if present in inName, * otherwise the existing values in pPieces remain. * *pArgs will be set to the pPieces values.
*/ staticvoid
parseConverterOptions(constchar *inName,
UConverterNamePieces *pPieces,
UConverterLoadArgs *pArgs,
UErrorCode *err)
{ char *cnvName = pPieces->cnvName; char c;
int32_t len = 0;
/* 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;
}
}
}
}
/*Logic determines if the converter is Algorithmic AND/OR cached *depending on that: * -we either go to get data from disk and cache it (Data=true, Cached=false) * -Get it from a Hashtable (Data=X, Cached=true) * -Call dataConverter initializer (Data=true, Cached=true) * -Call AlgorithmicConverter initializer (Data=false, Cached=true)
*/
U_CFUNC UConverterSharedData *
ucnv_loadSharedData(constchar *converterName,
UConverterNamePieces *pPieces,
UConverterLoadArgs *pArgs,
UErrorCode * err) {
UConverterNamePieces stackPieces;
UConverterLoadArgs stackArgs;
UConverterSharedData *mySharedConverterData = nullptr;
UErrorCode internalErrorCode = U_ZERO_ERROR;
UBool mayContainOption = true;
UBool checkForAlgorithmic = true;
if (U_FAILURE (*err)) { return nullptr;
}
if(pPieces == nullptr) { if(pArgs != nullptr) { /* * Bad: We may set pArgs pointers to stackPieces fields * which will be invalid after this function returns.
*/
*err = U_INTERNAL_PROGRAM_ERROR; return nullptr;
}
pPieces = &stackPieces;
} if(pArgs == nullptr) {
uprv_memset(&stackArgs, 0, sizeof(stackArgs));
stackArgs.size = (int32_t)sizeof(stackArgs);
pArgs = &stackArgs;
}
/* 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) { /* * set the input name in case the converter was added * without updating the alias table, or when there is no alias table
*/
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;
}
if(mySharedConverterData->impl->open != nullptr) {
mySharedConverterData->impl->open(myUConverter, pArgs, err); if(U_FAILURE(*err) && !pArgs->onlyTestIsLoadable) { /* don't ucnv_close() if onlyTestIsLoadable because not fully initialized */
ucnv_close(myUConverter); return nullptr;
}
}
return myUConverter;
}
/*Frees all shared immutable objects that aren't referred to (reference count = 0)
*/
U_CAPI int32_t U_EXPORT2
ucnv_flushCache ()
{
UConverterSharedData *mySharedData = nullptr;
int32_t pos;
int32_t tableDeletedNum = 0; const UHashElement *e; /*UErrorCode status = U_ILLEGAL_ARGUMENT_ERROR;*/
int32_t i, remaining;
UTRACE_ENTRY_OC(UTRACE_UCNV_FLUSH_CACHE);
/* Close the default converter without creating a new one so that everything will be flushed. */
u_flushDefaultConverter();
/*if shared data hasn't even been lazy evaluated yet * return 0
*/ if (SHARED_DATA_HASHTABLE == nullptr) {
UTRACE_EXIT_VALUE((int32_t)0); return 0;
}
/*creates an enumeration to iterate through every element in the * table * * Synchronization: holding cnvCacheMutex will prevent any other thread from * accessing or modifying the hash table during the iteration. * The reference count of an entry may be decremented by * ucnv_close while the iteration is in process, but this is * benign. It can't be incremented (in ucnv_createConverter()) * because the sequence of looking up in the cache + incrementing * is protected by cnvCacheMutex.
*/
umtx_lock(&cnvCacheMutex); /* * double loop: A delta/extension-only converter has a pointer to its base table's * shared data; the first iteration of the outer loop may see the delta converter * before the base converter, and unloading the delta converter may get the base * converter's reference counter down to 0.
*/
i = 0; do {
remaining = 0;
pos = UHASH_FIRST; while ((e = uhash_nextElement (SHARED_DATA_HASHTABLE, &pos)) != nullptr)
{
mySharedData = (UConverterSharedData *) e->value.pointer; /*deletes only if reference counter == 0 */ if (mySharedData->referenceCounter == 0)
{
tableDeletedNum++;
/* 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));
U_CFUNC constchar *
ucnv_bld_getAvailableConverter(uint16_t n, UErrorCode *pErrorCode) { if (haveAvailableConverterList(pErrorCode)) { if (n < gAvailableConverterCount) { return gAvailableConverters[n];
}
*pErrorCode = U_INDEX_OUTOFBOUNDS_ERROR;
} return nullptr;
}
/* default converter name --------------------------------------------------- */
#if !U_CHARSET_IS_UTF8 /* Copy the canonical converter name. ucnv_getDefaultName must be thread safe, which can call this function.
ucnv_setDefaultName calls this function and it doesn't have to be thread safe because there is no reliable/safe way to reset the converter in use in all threads. If you did reset the converter, you would not be sure that retrieving a default converter for one string would be the same type of default converter for a successive string. Since the name is a returned via ucnv_getDefaultName without copying, you shouldn't be modifying or deleting the string from a separate thread.
*/ staticinlinevoid
internalSetName(constchar *name, UErrorCode *status) {
UConverterNamePieces stackPieces;
UConverterLoadArgs stackArgs=UCNV_LOAD_ARGS_INITIALIZER;
int32_t length=(int32_t)(uprv_strlen(name));
UBool containsOption = (UBool)(uprv_strchr(name, UCNV_OPTION_SEP_CHAR) != nullptr); const UConverterSharedData *algorithmicSharedData;
/* 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;
ucnv_enableCleanup();
umtx_unlock(&cnvCacheMutex);
} #endif
/* * In order to be really thread-safe, the get function would have to take * a buffer parameter and copy the current string inside a mutex block. * This implementation only tries to be really thread-safe while * setting the name. * It assumes that setting a pointer is atomic.
*/
U_CAPI constchar* U_EXPORT2
ucnv_getDefaultName() { #if U_CHARSET_IS_UTF8 return"UTF-8"; #else /* local variable to be thread-safe */ constchar *name;
/* Concurrent calls to ucnv_getDefaultName must be thread safe, but ucnv_setDefaultName is not thread safe.
*/
{
icu::Mutex lock(&cnvCacheMutex);
name = gDefaultConverterName;
} if(name==nullptr) {
UErrorCode errorCode = U_ZERO_ERROR;
UConverter *cnv = nullptr;
name = uprv_getDefaultCodepage();
/* 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);
}
return name; #endif
}
#if U_CHARSET_IS_UTF8
U_CAPI void U_EXPORT2 ucnv_setDefaultName(constchar *) {} #else /* This function is not thread safe, and it can't be thread safe. See internalSetName or the API reference for details.
*/
U_CAPI void U_EXPORT2
ucnv_setDefaultName(constchar *converterName) { if(converterName==nullptr) { /* reset to the default codepage */
gDefaultConverterName=nullptr;
} else {
UErrorCode errorCode = U_ZERO_ERROR;
UConverter *cnv = nullptr; constchar *name = nullptr;
/* 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; return 0;
}
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; return 0;
}
/* 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; return 0;
}
/* calculate the length of the MBCS data */
/* * utf8Friendly MBCS files (mbcsHeader.version 4.3) * contain an additional mbcsIndex table: * uint16_t[(maxFastUChar+1)>>6]; * where maxFastUChar=((mbcsHeader.version[2]<<8)|0xff).
*/
maxFastUChar=0;
mbcsIndexLength=0; if( outputType!=MBCS_OUTPUT_EXT_ONLY && outputType!=MBCS_OUTPUT_1 &&
mbcsHeader.version[1]>=3 && (maxFastUChar=mbcsHeader.version[2])!=0
) {
maxFastUChar=(maxFastUChar<<8)|0xff;
mbcsIndexLength=((maxFastUChar+1)>>6)*2; /* number of bytes */
}
/* 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; return 0;
}
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; return 0;
}
/* 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);
if(outputType==MBCS_OUTPUT_EXT_ONLY) { /* * extension-only file, * contains a base name instead of normal base table data
*/
/* 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.