]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/common/ucnv.c
ICU-8.11.2.tar.gz
[apple/icu.git] / icuSources / common / ucnv.c
index 635c78faf3c2a7a2c8216789c493a1a64dc0c6ec..f764f361a1fc27fe53128504cc6b32a76a2eae7e 100644 (file)
@@ -1,7 +1,7 @@
 /*
 ******************************************************************************
 *
-*   Copyright (C) 1998-2004, International Business Machines
+*   Copyright (C) 1998-2006,2008 International Business Machines
 *   Corporation and others.  All Rights Reserved.
 *
 ******************************************************************************
@@ -34,7 +34,6 @@
 #include "utracimp.h"
 #include "ustr_imp.h"
 #include "ucnv_imp.h"
-#include "ucnv_io.h"
 #include "ucnv_cnv.h"
 #include "ucnv_bld.h"
 
@@ -56,17 +55,6 @@ static const UAmbiguousConverter ambiguousConverters[]={
     { "ISO_2022,locale=ko,version=0", 0x20a9 }
 };
 
-U_CAPI const char*  U_EXPORT2
-ucnv_getDefaultName ()
-{
-    return ucnv_io_getDefaultConverterName();
-}
-
-U_CAPI void U_EXPORT2
-ucnv_setDefaultName (const char *converterName)
-{
-  ucnv_io_setDefaultConverterName(converterName);
-}
 /*Calls through createConverter */
 U_CAPI UConverter* U_EXPORT2
 ucnv_open (const char *name,
@@ -107,6 +95,28 @@ ucnv_openU (const UChar * name,
     return ucnv_open(u_austrcpy(asciiName, name), err);
 }
 
+/* Copy the string that is represented by the UConverterPlatform enum
+ * @param platformString An output buffer
+ * @param platform An enum representing a platform
+ * @return the length of the copied string.
+ */
+static int32_t
+ucnv_copyPlatformString(char *platformString, UConverterPlatform pltfrm)
+{
+    switch (pltfrm)
+    {
+    case UCNV_IBM:
+        uprv_strcpy(platformString, "ibm-");
+        return 4;
+    case UCNV_UNKNOWN:
+        break;
+    }
+
+    /* default to empty string */
+    *platformString = 0;
+    return 0;
+}
+
 /*Assumes a $platform-#codepage.$CONVERTER_FILE_EXTENSION scheme and calls
  *through createConverter*/
 U_CAPI UConverter*   U_EXPORT2
@@ -239,6 +249,19 @@ ucnv_safeClone(const UConverter* cnv, void *stackBuffer, int32_t *pBufferSize, U
     uprv_memcpy(localConverter, cnv, sizeof(UConverter));
     localConverter->isCopyLocal = localConverter->isExtraLocal = FALSE;
 
+    /* copy the substitution string */
+    if (cnv->subChars == (uint8_t *)cnv->subUChars) {
+        localConverter->subChars = (uint8_t *)localConverter->subUChars;
+    } else {
+        localConverter->subChars = (uint8_t *)uprv_malloc(UCNV_ERROR_BUFFER_LENGTH * U_SIZEOF_UCHAR);
+        if (localConverter->subChars == NULL) {
+            uprv_free(allocatedConverter);
+            UTRACE_EXIT_STATUS(*status);
+            return NULL;
+        }
+        uprv_memcpy(localConverter->subChars, cnv->subChars, UCNV_ERROR_BUFFER_LENGTH * U_SIZEOF_UCHAR);
+    }
+
     /* now either call the safeclone fcn or not */
     if (cnv->sharedData->impl->safeClone != NULL) {
         /* call the custom safeClone function */
@@ -246,6 +269,9 @@ ucnv_safeClone(const UConverter* cnv, void *stackBuffer, int32_t *pBufferSize, U
     }
 
     if(localConverter==NULL || U_FAILURE(*status)) {
+        if (allocatedConverter != NULL && allocatedConverter->subChars != (uint8_t *)allocatedConverter->subUChars) {
+            uprv_free(allocatedConverter->subChars);
+        }
         uprv_free(allocatedConverter);
         UTRACE_EXIT_STATUS(*status);
         return NULL;
@@ -285,27 +311,6 @@ ucnv_safeClone(const UConverter* cnv, void *stackBuffer, int32_t *pBufferSize, U
 U_CAPI void  U_EXPORT2
 ucnv_close (UConverter * converter)
 {
-    /* first, notify the callback functions that the converter is closed */
-    UConverterToUnicodeArgs toUArgs = {
-        sizeof(UConverterToUnicodeArgs),
-            TRUE,
-            NULL,
-            NULL,
-            NULL,
-            NULL,
-            NULL,
-            NULL
-    };
-    UConverterFromUnicodeArgs fromUArgs = {
-        sizeof(UConverterFromUnicodeArgs),
-            TRUE,
-            NULL,
-            NULL,
-            NULL,
-            NULL,
-            NULL,
-            NULL
-    };
     UErrorCode errorCode = U_ZERO_ERROR;
 
     UTRACE_ENTRY_OC(UTRACE_UCNV_CLOSE);
@@ -319,16 +324,50 @@ ucnv_close (UConverter * converter)
     UTRACE_DATA3(UTRACE_OPEN_CLOSE, "close converter %s at %p, isCopyLocal=%b",
         ucnv_getName(converter, &errorCode), converter, converter->isCopyLocal);
 
-    toUArgs.converter = fromUArgs.converter = converter;
+    /* In order to speed up the close, only call the callbacks when they have been changed.
+    This performance check will only work when the callbacks are set within a shared library
+    or from user code that statically links this code. */
+    /* first, notify the callback functions that the converter is closed */
+    if (converter->fromCharErrorBehaviour != UCNV_TO_U_DEFAULT_CALLBACK) {
+        UConverterToUnicodeArgs toUArgs = {
+            sizeof(UConverterToUnicodeArgs),
+                TRUE,
+                NULL,
+                NULL,
+                NULL,
+                NULL,
+                NULL,
+                NULL
+        };
 
-    converter->fromCharErrorBehaviour(converter->toUContext, &toUArgs, NULL, 0, UCNV_CLOSE, &errorCode);
-    errorCode = U_ZERO_ERROR;
-    converter->fromUCharErrorBehaviour(converter->fromUContext, &fromUArgs, NULL, 0, 0, UCNV_CLOSE, &errorCode);
+        toUArgs.converter = converter;
+        errorCode = U_ZERO_ERROR;
+        converter->fromCharErrorBehaviour(converter->toUContext, &toUArgs, NULL, 0, UCNV_CLOSE, &errorCode);
+    }
+    if (converter->fromUCharErrorBehaviour != UCNV_FROM_U_DEFAULT_CALLBACK) {
+        UConverterFromUnicodeArgs fromUArgs = {
+            sizeof(UConverterFromUnicodeArgs),
+                TRUE,
+                NULL,
+                NULL,
+                NULL,
+                NULL,
+                NULL,
+                NULL
+        };
+        fromUArgs.converter = converter;
+        errorCode = U_ZERO_ERROR;
+        converter->fromUCharErrorBehaviour(converter->fromUContext, &fromUArgs, NULL, 0, 0, UCNV_CLOSE, &errorCode);
+    }
 
     if (converter->sharedData->impl->close != NULL) {
         converter->sharedData->impl->close(converter);
     }
 
+    if (converter->subChars != (uint8_t *)converter->subUChars) {
+        uprv_free(converter->subChars);
+    }
+
     /*
     Checking whether it's an algorithic converter is okay
     in multithreaded applications because the value never changes.
@@ -339,7 +378,7 @@ ucnv_close (UConverter * converter)
     }
 
     if(!converter->isCopyLocal){
-        uprv_free (converter);
+        uprv_free(converter);
     }
 
     UTRACE_EXIT();
@@ -350,47 +389,21 @@ ucnv_close (UConverter * converter)
 U_CAPI const char*   U_EXPORT2
 ucnv_getAvailableName (int32_t n)
 {
-  if (0 <= n && n <= 0xffff) {
-    UErrorCode err = U_ZERO_ERROR;
-    const char *name = ucnv_io_getAvailableConverter((uint16_t)n, &err);
-    if (U_SUCCESS(err)) {
-      return name;
+    if (0 <= n && n <= 0xffff) {
+        UErrorCode err = U_ZERO_ERROR;
+        const char *name = ucnv_bld_getAvailableConverter((uint16_t)n, &err);
+        if (U_SUCCESS(err)) {
+            return name;
+        }
     }
-  }
-  return NULL;
+    return NULL;
 }
 
 U_CAPI int32_t   U_EXPORT2
 ucnv_countAvailable ()
 {
     UErrorCode err = U_ZERO_ERROR;
-    return ucnv_io_countAvailableConverters(&err);
-}
-
-U_CAPI uint16_t U_EXPORT2
-ucnv_countAliases(const char *alias, UErrorCode *pErrorCode)
-{
-    return ucnv_io_countAliases(alias, pErrorCode);
-}
-
-
-U_CAPI const char* U_EXPORT2
-ucnv_getAlias(const char *alias, uint16_t n, UErrorCode *pErrorCode)
-{
-    return ucnv_io_getAlias(alias, n, pErrorCode);
-}
-
-U_CAPI void U_EXPORT2
-ucnv_getAliases(const char *alias, const char **aliases, UErrorCode *pErrorCode)
-{
-    ucnv_io_getAliases(alias, 0, aliases, pErrorCode);
-}
-
-U_CAPI uint16_t U_EXPORT2
-ucnv_countStandards(void)
-{
-    UErrorCode err = U_ZERO_ERROR;
-    return ucnv_io_countStandards(&err);
+    return ucnv_bld_countAvailableConverters(&err);
 }
 
 U_CAPI void    U_EXPORT2
@@ -402,15 +415,19 @@ ucnv_getSubstChars (const UConverter * converter,
     if (U_FAILURE (*err))
         return;
 
+    if (converter->subCharLen <= 0) {
+        /* Unicode string or empty string from ucnv_setSubstString(). */
+        *len = 0;
+        return;
+    }
+
     if (*len < converter->subCharLen) /*not enough space in subChars */
     {
         *err = U_INDEX_OUTOFBOUNDS_ERROR;
         return;
     }
 
-  uprv_memcpy (mySubChar, converter->subChar, converter->subCharLen);   /*fills in the subchars */
-  *len = converter->subCharLen; /*store # of bytes copied to buffer */
-    uprv_memcpy (mySubChar, converter->subChar, converter->subCharLen);   /*fills in the subchars */
+    uprv_memcpy (mySubChar, converter->subChars, converter->subCharLen);   /*fills in the subchars */
     *len = converter->subCharLen; /*store # of bytes copied to buffer */
 }
 
@@ -431,7 +448,7 @@ ucnv_setSubstChars (UConverter * converter,
         return;
     }
     
-    uprv_memcpy (converter->subChar, mySubChar, len); /*copies the subchars */
+    uprv_memcpy (converter->subChars, mySubChar, len); /*copies the subchars */
     converter->subCharLen = len;  /*sets the new len */
 
     /*
@@ -444,6 +461,93 @@ ucnv_setSubstChars (UConverter * converter,
     return;
 }
 
+U_DRAFT void U_EXPORT2
+ucnv_setSubstString(UConverter *cnv,
+                    const UChar *s,
+                    int32_t length,
+                    UErrorCode *err) {
+    UAlignedMemory cloneBuffer[U_CNV_SAFECLONE_BUFFERSIZE / sizeof(UAlignedMemory) + 1];
+    char chars[UCNV_ERROR_BUFFER_LENGTH];
+
+    UConverter *clone;
+    uint8_t *subChars;
+    int32_t cloneSize, length8;
+
+    /* Let the following functions check all arguments. */
+    cloneSize = sizeof(cloneBuffer);
+    clone = ucnv_safeClone(cnv, cloneBuffer, &cloneSize, err);
+    ucnv_setFromUCallBack(clone, UCNV_FROM_U_CALLBACK_STOP, NULL, NULL, NULL, err);
+    length8 = ucnv_fromUChars(clone, chars, (int32_t)sizeof(chars), s, length, err);
+    ucnv_close(clone);
+    if (U_FAILURE(*err)) {
+        return;
+    }
+
+    if (cnv->sharedData->impl->writeSub == NULL
+#if !UCONFIG_NO_LEGACY_CONVERSION
+        || (cnv->sharedData->staticData->conversionType == UCNV_MBCS &&
+         ucnv_MBCSGetType(cnv) != UCNV_EBCDIC_STATEFUL)
+#endif
+    ) {
+        /* The converter is not stateful. Store the charset bytes as a fixed string. */
+        subChars = (uint8_t *)chars;
+    } else {
+        /*
+         * The converter has a non-default writeSub() function, indicating
+         * that it is stateful.
+         * Store the Unicode string for on-the-fly conversion for correct
+         * state handling.
+         */
+        if (length > UCNV_ERROR_BUFFER_LENGTH) {
+            /*
+             * Should not occur. The converter should output at least one byte
+             * per UChar, which means that ucnv_fromUChars() should catch all
+             * overflows.
+             */
+            *err = U_BUFFER_OVERFLOW_ERROR;
+            return;
+        }
+        subChars = (uint8_t *)s;
+        if (length < 0) {
+            length = u_strlen(s);
+        }
+        length8 = length * U_SIZEOF_UCHAR;
+    }
+
+    /*
+     * For storing the substitution string, select either the small buffer inside
+     * UConverter or allocate a subChars buffer.
+     */
+    if (length8 > UCNV_MAX_SUBCHAR_LEN) {
+        /* Use a separate buffer for the string. Outside UConverter to not make it too large. */
+        if (cnv->subChars == (uint8_t *)cnv->subUChars) {
+            /* Allocate a new buffer for the string. */
+            cnv->subChars = (uint8_t *)uprv_malloc(UCNV_ERROR_BUFFER_LENGTH * U_SIZEOF_UCHAR);
+            if (cnv->subChars == NULL) {
+                cnv->subChars = (uint8_t *)cnv->subUChars;
+                *err = U_MEMORY_ALLOCATION_ERROR;
+                return;
+            }
+            uprv_memset(cnv->subChars, 0, UCNV_ERROR_BUFFER_LENGTH * U_SIZEOF_UCHAR);
+        }
+    }
+
+    /* Copy the substitution string into the UConverter or its subChars buffer. */
+    if (length8 == 0) {
+        cnv->subCharLen = 0;
+    } else {
+        uprv_memcpy(cnv->subChars, subChars, length8);
+        if (subChars == (uint8_t *)chars) {
+            cnv->subCharLen = (int8_t)length8;
+        } else /* subChars == s */ {
+            cnv->subCharLen = (int8_t)-length;
+        }
+    }
+
+    /* See comment in ucnv_setSubstChars(). */
+    cnv->subChar1 = 0;
+}
+
 /*resets the internal states of a converter
  *goal : have the same behaviour than a freshly created converter
  */
@@ -1325,7 +1429,8 @@ _toUnicodeWithCallback(UConverterToUnicodeArgs *pArgs, UErrorCode *err) {
                      e!=U_ILLEGAL_CHAR_FOUND &&
                      e!=U_TRUNCATED_CHAR_FOUND &&
                      e!=U_ILLEGAL_ESCAPE_SEQUENCE &&
-                     e!=U_UNSUPPORTED_ESCAPE_SEQUENCE)
+                     e!=U_UNSUPPORTED_ESCAPE_SEQUENCE &&
+                     e!=U_PARSE_ERROR) /* temporary err to flag empty segment, will be reset to U_ILLEGAL_ESCAPE_SEQUENCE below */
                 ) {
                     /*
                      * the callback did not or cannot resolve the error:
@@ -1369,11 +1474,18 @@ _toUnicodeWithCallback(UConverterToUnicodeArgs *pArgs, UErrorCode *err) {
             cnv->toULength=0;
 
             /* call the callback function */
-            cnv->fromCharErrorBehaviour(cnv->toUContext, pArgs,
-                cnv->invalidCharBuffer, errorInputLength,
-                (*err==U_INVALID_CHAR_FOUND || *err==U_UNSUPPORTED_ESCAPE_SEQUENCE) ?
-                    UCNV_UNASSIGNED : UCNV_ILLEGAL,
-                err);
+            {
+                UConverterCallbackReason reason;
+                if (*err == U_PARSE_ERROR) {   /* Here U_PARSE_ERROR indicates empty segment */
+                    *err = U_ILLEGAL_ESCAPE_SEQUENCE;
+                    reason = UCNV_IRREGULAR;
+                } else {
+                       reason = (*err==U_INVALID_CHAR_FOUND || *err==U_UNSUPPORTED_ESCAPE_SEQUENCE) ?
+                                 UCNV_UNASSIGNED : UCNV_ILLEGAL;
+                }
+                cnv->fromCharErrorBehaviour(cnv->toUContext, pArgs,
+                    cnv->invalidCharBuffer, errorInputLength, reason, err);
+            }
 
             /*
              * loop back to the offset handling
@@ -1587,7 +1699,7 @@ ucnv_toUChars(UConverter *cnv,
     ucnv_resetToUnicode(cnv);
     originalDest=dest;
     if(srcLength==-1) {
-        srcLength=uprv_strlen(src);
+        srcLength=(int32_t)uprv_strlen(src);
     }
     if(srcLength>0) {
         srcLimit=src+srcLength;
@@ -1855,6 +1967,12 @@ ucnv_convertEx(UConverter *targetCnv, UConverter *sourceCnv,
     }
 
     if(pivotStart==NULL) {
+        if(!flush) {
+            /* streaming conversion requires an explicit pivot buffer */
+            *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+            return;
+        }
+
         /* use the stack pivot buffer */
         pivotStart=myPivotSource=myPivotTarget=pivotBuffer;
         pivotSource=&myPivotSource;
@@ -1984,7 +2102,7 @@ ucnv_internalConvert(UConverter *outConverter, UConverter *inConverter,
                        FALSE,
                        TRUE,
                        pErrorCode);
-        targetLength=myTarget-target;
+        targetLength=(int32_t)(myTarget-target);
     }
 
     /*
@@ -2007,7 +2125,7 @@ ucnv_internalConvert(UConverter *outConverter, UConverter *inConverter,
                            FALSE,
                            TRUE,
                            pErrorCode);
-            targetLength+=(myTarget-targetBuffer);
+            targetLength+=(int32_t)(myTarget-targetBuffer);
         } while(*pErrorCode==U_BUFFER_OVERFLOW_ERROR);
 
         /* done with preflighting, set warnings and errors as appropriate */
@@ -2322,7 +2440,7 @@ ucnv_detectUnicodeSignature( const char* source,
     }
 
     if(sourceLength==-1){
-        sourceLength=uprv_strlen(source);
+        sourceLength=(int32_t)uprv_strlen(source);
     }
 
     
@@ -2384,6 +2502,50 @@ ucnv_detectUnicodeSignature( const char* source,
     return NULL;
 }
 
+ U_DRAFT int32_t U_EXPORT2
+ ucnv_fromUCountPending(const UConverter* cnv, UErrorCode* status){
+    
+    if(status == NULL || U_FAILURE(*status)){
+        return -1;
+    }
+    if(cnv == NULL){
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return -1;
+    }
+
+    if(cnv->preFromULength > 0){
+        return U16_LENGTH(cnv->preFromUFirstCP)+cnv->preFromULength ;
+    }else if(cnv->preFromULength < 0){
+        return -cnv->preFromULength ;
+    }else if(cnv->fromUChar32 > 0){
+        return 1;
+    }else if(cnv->preFromUFirstCP >0){
+        return U16_LENGTH(cnv->preFromUFirstCP);
+    }
+    return 0; 
+
+ }
+
+U_DRAFT int32_t U_EXPORT2
+ucnv_toUCountPending(const UConverter* cnv, UErrorCode* status){
+
+    if(status == NULL || U_FAILURE(*status)){
+        return -1;
+    }
+    if(cnv == NULL){
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return -1;
+    }
+
+    if(cnv->preToULength > 0){
+        return cnv->preToULength ;
+    }else if(cnv->preToULength < 0){
+        return -cnv->preToULength;
+    }else if(cnv->toULength > 0){
+        return cnv->toULength;
+    }
+    return 0;
+}
 #endif
 
 /*