]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/common/ucnv_io.cpp
ICU-64252.0.1.tar.gz
[apple/icu.git] / icuSources / common / ucnv_io.cpp
index 12d2b63f0d8cbbf551e7928305425335cfabccfa..7a95a3f1e61dd7c06d53384d71de29b9ad1f6d85 100644 (file)
@@ -1,7 +1,9 @@
+// © 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.
 *
 ******************************************************************************
@@ -36,6 +38,7 @@
 
 #include "umutex.h"
 #include "uarrsort.h"
+#include "uassert.h"
 #include "udataswp.h"
 #include "cstring.h"
 #include "cmemory.h"
@@ -172,6 +175,7 @@ static const char DATA_NAME[] = "cnvalias";
 static const char DATA_TYPE[] = "icu";
 
 static UDataMemory *gAliasData=NULL;
+static icu::UInitOnce gAliasDataInitOnce = U_INITONCE_INITIALIZER;
 
 enum {
     tocLengthIndex=0,
@@ -218,113 +222,97 @@ static UBool U_CALLCONV ucnv_io_cleanup(void)
         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
@@ -351,7 +339,7 @@ static uint32_t getTagNumber(const char *tagname) {
 
 /* character types relevant for ucnv_compareNames() */
 enum {
-    IGNORE,
+    UIGNORE,
     ZERO,
     NONZERO,
     MINLETTER /* any values from here on are lowercase letter mappings */
@@ -369,7 +357,7 @@ static const uint8_t asciiTypes[128] = {
     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] = {
@@ -383,7 +371,7 @@ 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)
@@ -393,8 +381,9 @@ static const uint8_t ebcdicTypes[128] = {
 #   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;
@@ -404,7 +393,7 @@ ucnv_io_stripASCIIForCompare(char *dst, const char *name) {
     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:
@@ -429,7 +418,7 @@ ucnv_io_stripASCIIForCompare(char *dst, const char *name) {
     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;
@@ -439,7 +428,7 @@ ucnv_io_stripEBCDICForCompare(char *dst, const char *name) {
     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:
@@ -496,7 +485,7 @@ ucnv_compareNames(const char *name1, const char *name2) {
         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:
@@ -520,7 +509,7 @@ ucnv_compareNames(const char *name1, const char *name2) {
         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:
@@ -745,9 +734,7 @@ findTaggedConverterNum(const char *alias, const char *standard, UErrorCode *pErr
     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;
@@ -758,7 +745,7 @@ ucnv_io_getConverterName(const char *alias, UBool *containsOption, UErrorCode *p
              * 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;
@@ -778,6 +765,9 @@ ucnv_io_getConverterName(const char *alias, UBool *containsOption, UErrorCode *p
     return NULL;
 }
 
+U_CDECL_BEGIN
+
+
 static int32_t U_CALLCONV
 ucnv_io_countStandardAliases(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
     int32_t value = 0;
@@ -790,7 +780,7 @@ ucnv_io_countStandardAliases(UEnumeration *enumerator, UErrorCode * /*pErrorCode
     return value;
 }
 
-static const char* U_CALLCONV
+static const char * U_CALLCONV
 ucnv_io_nextStandardAliases(UEnumeration *enumerator,
                             int32_t* resultLength,
                             UErrorCode * /*pErrorCode*/)
@@ -828,6 +818,8 @@ ucnv_io_closeUEnumeration(UEnumeration *enumerator) {
     uprv_free(enumerator);
 }
 
+U_CDECL_END
+
 /* Enumerate the aliases for the specified converter and standard tag */
 static const UEnumeration gEnumAliases = {
     NULL,
@@ -1024,12 +1016,15 @@ ucnv_getCanonicalName(const char *alias, const char *standard, UErrorCode *pErro
     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*/)
@@ -1054,7 +1049,7 @@ static void U_CALLCONV
 ucnv_io_resetAllConverters(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
     *((uint16_t *)(enumerator->context)) = 0;
 }
-
+U_CDECL_END
 static const UEnumeration gEnumAllConverters = {
     NULL,
     NULL,
@@ -1089,7 +1084,7 @@ ucnv_openAllNames(UErrorCode *pErrorCode) {
     return myEnum;
 }
 
-U_CFUNC uint16_t
+U_CAPI uint16_t
 ucnv_io_countKnownConverters(UErrorCode *pErrorCode) {
     if (haveAliasData(pErrorCode)) {
         return (uint16_t)gMainTable.converterListSize;
@@ -1099,7 +1094,11 @@ ucnv_io_countKnownConverters(UErrorCode *pErrorCode) {
 
 /* alias table swapping ----------------------------------------------------- */
 
+U_CDECL_BEGIN
+
 typedef char * U_CALLCONV StripForCompareFn(char *dst, const char *name);
+U_CDECL_END
+
 
 /*
  * row of a temporary array
@@ -1123,7 +1122,7 @@ enum {
     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];
@@ -1311,13 +1310,13 @@ ucnv_swapAliases(const UDataSwapper *ds,
                         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);
                 }
             }
 
@@ -1350,6 +1349,7 @@ ucnv_swapAliases(const UDataSwapper *ds,
 
 #endif
 
+
 /*
  * Hey, Emacs, please set the following:
  *