+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
*
-* Copyright (C) 1999-2012, International Business Machines
+* Copyright (C) 1999-2015, International Business Machines
* Corporation and others. All Rights Reserved.
*
******************************************************************************
#include "umutex.h"
#include "uarrsort.h"
+#include "uassert.h"
#include "udataswp.h"
#include "cstring.h"
#include "cmemory.h"
static const char DATA_TYPE[] = "icu";
static UDataMemory *gAliasData=NULL;
+static icu::UInitOnce gAliasDataInitOnce = U_INITONCE_INITIALIZER;
enum {
tocLengthIndex=0,
udata_close(gAliasData);
gAliasData = NULL;
}
+ gAliasDataInitOnce.reset();
uprv_memset(&gMainTable, 0, sizeof(gMainTable));
return TRUE; /* Everything was cleaned up */
}
-static UBool
-haveAliasData(UErrorCode *pErrorCode) {
- int needInit;
-
- if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
- return FALSE;
- }
-
- UMTX_CHECK(NULL, (gAliasData==NULL), needInit);
-
- /* load converter alias data from file if necessary */
- if (needInit) {
- UDataMemory *data;
- const uint16_t *table;
- const uint32_t *sectionSizes;
- uint32_t tableStart;
- uint32_t currOffset;
-
- data = udata_openChoice(NULL, DATA_TYPE, DATA_NAME, isAcceptable, NULL, pErrorCode);
- if(U_FAILURE(*pErrorCode)) {
- return FALSE;
- }
+static void U_CALLCONV initAliasData(UErrorCode &errCode) {
+ UDataMemory *data;
+ const uint16_t *table;
+ const uint32_t *sectionSizes;
+ uint32_t tableStart;
+ uint32_t currOffset;
- sectionSizes = (const uint32_t *)udata_getMemory(data);
- table = (const uint16_t *)sectionSizes;
+ ucln_common_registerCleanup(UCLN_COMMON_UCNV_IO, ucnv_io_cleanup);
- tableStart = sectionSizes[0];
- if (tableStart < minTocLength) {
- *pErrorCode = U_INVALID_FORMAT_ERROR;
- udata_close(data);
- return FALSE;
- }
-
- umtx_lock(NULL);
- if(gAliasData==NULL) {
- gMainTable.converterListSize = sectionSizes[1];
- gMainTable.tagListSize = sectionSizes[2];
- gMainTable.aliasListSize = sectionSizes[3];
- gMainTable.untaggedConvArraySize = sectionSizes[4];
- gMainTable.taggedAliasArraySize = sectionSizes[5];
- gMainTable.taggedAliasListsSize = sectionSizes[6];
- gMainTable.optionTableSize = sectionSizes[7];
- gMainTable.stringTableSize = sectionSizes[8];
-
- if (tableStart > 8) {
- gMainTable.normalizedStringTableSize = sectionSizes[9];
- }
+ U_ASSERT(gAliasData == NULL);
+ data = udata_openChoice(NULL, DATA_TYPE, DATA_NAME, isAcceptable, NULL, &errCode);
+ if(U_FAILURE(errCode)) {
+ return;
+ }
- currOffset = tableStart * (sizeof(uint32_t)/sizeof(uint16_t)) + (sizeof(uint32_t)/sizeof(uint16_t));
- gMainTable.converterList = table + currOffset;
+ sectionSizes = (const uint32_t *)udata_getMemory(data);
+ table = (const uint16_t *)sectionSizes;
- currOffset += gMainTable.converterListSize;
- gMainTable.tagList = table + currOffset;
+ tableStart = sectionSizes[0];
+ if (tableStart < minTocLength) {
+ errCode = U_INVALID_FORMAT_ERROR;
+ udata_close(data);
+ return;
+ }
+ gAliasData = data;
+
+ gMainTable.converterListSize = sectionSizes[1];
+ gMainTable.tagListSize = sectionSizes[2];
+ gMainTable.aliasListSize = sectionSizes[3];
+ gMainTable.untaggedConvArraySize = sectionSizes[4];
+ gMainTable.taggedAliasArraySize = sectionSizes[5];
+ gMainTable.taggedAliasListsSize = sectionSizes[6];
+ gMainTable.optionTableSize = sectionSizes[7];
+ gMainTable.stringTableSize = sectionSizes[8];
+
+ if (tableStart > 8) {
+ gMainTable.normalizedStringTableSize = sectionSizes[9];
+ }
- currOffset += gMainTable.tagListSize;
- gMainTable.aliasList = table + currOffset;
+ currOffset = tableStart * (sizeof(uint32_t)/sizeof(uint16_t)) + (sizeof(uint32_t)/sizeof(uint16_t));
+ gMainTable.converterList = table + currOffset;
- currOffset += gMainTable.aliasListSize;
- gMainTable.untaggedConvArray = table + currOffset;
+ currOffset += gMainTable.converterListSize;
+ gMainTable.tagList = table + currOffset;
- currOffset += gMainTable.untaggedConvArraySize;
- gMainTable.taggedAliasArray = table + currOffset;
+ currOffset += gMainTable.tagListSize;
+ gMainTable.aliasList = table + currOffset;
- /* aliasLists is a 1's based array, but it has a padding character */
- currOffset += gMainTable.taggedAliasArraySize;
- gMainTable.taggedAliasLists = table + currOffset;
+ currOffset += gMainTable.aliasListSize;
+ gMainTable.untaggedConvArray = table + currOffset;
- currOffset += gMainTable.taggedAliasListsSize;
- if (gMainTable.optionTableSize > 0
- && ((const UConverterAliasOptions *)(table + currOffset))->stringNormalizationType < UCNV_IO_NORM_TYPE_COUNT)
- {
- /* Faster table */
- gMainTable.optionTable = (const UConverterAliasOptions *)(table + currOffset);
- }
- else {
- /* Smaller table, or I can't handle this normalization mode!
- Use the original slower table lookup. */
- gMainTable.optionTable = &defaultTableOptions;
- }
+ currOffset += gMainTable.untaggedConvArraySize;
+ gMainTable.taggedAliasArray = table + currOffset;
- currOffset += gMainTable.optionTableSize;
- gMainTable.stringTable = table + currOffset;
+ /* aliasLists is a 1's based array, but it has a padding character */
+ currOffset += gMainTable.taggedAliasArraySize;
+ gMainTable.taggedAliasLists = table + currOffset;
- currOffset += gMainTable.stringTableSize;
- gMainTable.normalizedStringTable = ((gMainTable.optionTable->stringNormalizationType == UCNV_IO_UNNORMALIZED)
- ? gMainTable.stringTable : (table + currOffset));
+ currOffset += gMainTable.taggedAliasListsSize;
+ if (gMainTable.optionTableSize > 0
+ && ((const UConverterAliasOptions *)(table + currOffset))->stringNormalizationType < UCNV_IO_NORM_TYPE_COUNT)
+ {
+ /* Faster table */
+ gMainTable.optionTable = (const UConverterAliasOptions *)(table + currOffset);
+ }
+ else {
+ /* Smaller table, or I can't handle this normalization mode!
+ Use the original slower table lookup. */
+ gMainTable.optionTable = &defaultTableOptions;
+ }
- ucln_common_registerCleanup(UCLN_COMMON_UCNV_IO, ucnv_io_cleanup);
+ currOffset += gMainTable.optionTableSize;
+ gMainTable.stringTable = table + currOffset;
- gAliasData = data;
- data=NULL;
- }
- umtx_unlock(NULL);
+ currOffset += gMainTable.stringTableSize;
+ gMainTable.normalizedStringTable = ((gMainTable.optionTable->stringNormalizationType == UCNV_IO_UNNORMALIZED)
+ ? gMainTable.stringTable : (table + currOffset));
+}
- /* if a different thread set it first, then close the extra data */
- if(data!=NULL) {
- udata_close(data); /* NULL if it was set correctly */
- }
- }
- return TRUE;
+static UBool
+haveAliasData(UErrorCode *pErrorCode) {
+ umtx_initOnce(gAliasDataInitOnce, &initAliasData, *pErrorCode);
+ return U_SUCCESS(*pErrorCode);
}
static inline UBool
/* character types relevant for ucnv_compareNames() */
enum {
- IGNORE,
+ UIGNORE,
ZERO,
NONZERO,
MINLETTER /* any values from here on are lowercase letter mappings */
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0, 0, 0, 0, 0
};
-#define GET_ASCII_TYPE(c) ((int8_t)(c) >= 0 ? asciiTypes[(uint8_t)c] : (uint8_t)IGNORE)
+#define GET_ASCII_TYPE(c) ((int8_t)(c) >= 0 ? asciiTypes[(uint8_t)c] : (uint8_t)UIGNORE)
/* character types for EBCDIC 80..FF */
static const uint8_t ebcdicTypes[128] = {
ZERO, NONZERO, NONZERO, NONZERO, NONZERO, NONZERO, NONZERO, NONZERO, NONZERO, NONZERO, 0, 0, 0, 0, 0, 0
};
-#define GET_EBCDIC_TYPE(c) ((int8_t)(c) < 0 ? ebcdicTypes[(c)&0x7f] : (uint8_t)IGNORE)
+#define GET_EBCDIC_TYPE(c) ((int8_t)(c) < 0 ? ebcdicTypes[(c)&0x7f] : (uint8_t)UIGNORE)
#if U_CHARSET_FAMILY==U_ASCII_FAMILY
# define GET_CHAR_TYPE(c) GET_ASCII_TYPE(c)
# error U_CHARSET_FAMILY is not valid
#endif
+
/* @see ucnv_compareNames */
-U_CFUNC char * U_EXPORT2
+U_CAPI char * U_CALLCONV
ucnv_io_stripASCIIForCompare(char *dst, const char *name) {
char *dstItr = dst;
uint8_t type, nextType;
while ((c1 = *name++) != 0) {
type = GET_ASCII_TYPE(c1);
switch (type) {
- case IGNORE:
+ case UIGNORE:
afterDigit = FALSE;
continue; /* ignore all but letters and digits */
case ZERO:
return dst;
}
-U_CFUNC char * U_EXPORT2
+U_CAPI char * U_CALLCONV
ucnv_io_stripEBCDICForCompare(char *dst, const char *name) {
char *dstItr = dst;
uint8_t type, nextType;
while ((c1 = *name++) != 0) {
type = GET_EBCDIC_TYPE(c1);
switch (type) {
- case IGNORE:
+ case UIGNORE:
afterDigit = FALSE;
continue; /* ignore all but letters and digits */
case ZERO:
while ((c1 = *name1++) != 0) {
type = GET_CHAR_TYPE(c1);
switch (type) {
- case IGNORE:
+ case UIGNORE:
afterDigit1 = FALSE;
continue; /* ignore all but letters and digits */
case ZERO:
while ((c2 = *name2++) != 0) {
type = GET_CHAR_TYPE(c2);
switch (type) {
- case IGNORE:
+ case UIGNORE:
afterDigit2 = FALSE;
continue; /* ignore all but letters and digits */
case ZERO:
return UINT32_MAX;
}
-
-
-U_CFUNC const char *
+U_CAPI const char *
ucnv_io_getConverterName(const char *alias, UBool *containsOption, UErrorCode *pErrorCode) {
const char *aliasTmp = alias;
int32_t i = 0;
* the name begins with 'x-'. If it does, strip it off and try
* again. This behaviour is similar to how ICU4J does it.
*/
- if (aliasTmp[0] == 'x' || aliasTmp[1] == '-') {
+ if (aliasTmp[0] == 'x' && aliasTmp[1] == '-') {
aliasTmp = aliasTmp+2;
} else {
break;
return NULL;
}
+U_CDECL_BEGIN
+
+
static int32_t U_CALLCONV
ucnv_io_countStandardAliases(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
int32_t value = 0;
return value;
}
-static const char* U_CALLCONV
+static const char * U_CALLCONV
ucnv_io_nextStandardAliases(UEnumeration *enumerator,
int32_t* resultLength,
UErrorCode * /*pErrorCode*/)
uprv_free(enumerator);
}
+U_CDECL_END
+
/* Enumerate the aliases for the specified converter and standard tag */
static const UEnumeration gEnumAliases = {
NULL,
return NULL;
}
+U_CDECL_BEGIN
+
+
static int32_t U_CALLCONV
ucnv_io_countAllConverters(UEnumeration * /*enumerator*/, UErrorCode * /*pErrorCode*/) {
return gMainTable.converterListSize;
}
-static const char* U_CALLCONV
+static const char * U_CALLCONV
ucnv_io_nextAllConverters(UEnumeration *enumerator,
int32_t* resultLength,
UErrorCode * /*pErrorCode*/)
ucnv_io_resetAllConverters(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
*((uint16_t *)(enumerator->context)) = 0;
}
-
+U_CDECL_END
static const UEnumeration gEnumAllConverters = {
NULL,
NULL,
return myEnum;
}
-U_CFUNC uint16_t
+U_CAPI uint16_t
ucnv_io_countKnownConverters(UErrorCode *pErrorCode) {
if (haveAliasData(pErrorCode)) {
return (uint16_t)gMainTable.converterListSize;
/* alias table swapping ----------------------------------------------------- */
+U_CDECL_BEGIN
+
typedef char * U_CALLCONV StripForCompareFn(char *dst, const char *name);
+U_CDECL_END
+
/*
* row of a temporary array
STACK_ROW_CAPACITY=500
};
-static int32_t
+static int32_t U_CALLCONV
io_compareRows(const void *context, const void *left, const void *right) {
char strippedLeft[UCNV_MAX_CONVERTER_NAME_LENGTH],
strippedRight[UCNV_MAX_CONVERTER_NAME_LENGTH];
oldIndex=tempTable.rows[i].sortIndex;
ds->swapArray16(ds, p+oldIndex, 2, r+i, pErrorCode);
}
- uprv_memcpy(q, r, 2*count);
+ uprv_memcpy(q, r, 2*(size_t)count);
for(i=0; i<count; ++i) {
oldIndex=tempTable.rows[i].sortIndex;
ds->swapArray16(ds, p2+oldIndex, 2, r+i, pErrorCode);
}
- uprv_memcpy(q2, r, 2*count);
+ uprv_memcpy(q2, r, 2*(size_t)count);
}
}
#endif
+
/*
* Hey, Emacs, please set the following:
*