diff options
Diffstat (limited to 'deps/node/deps/icu-small/source/common/ucnv.cpp')
-rw-r--r-- | deps/node/deps/icu-small/source/common/ucnv.cpp | 2910 |
1 files changed, 0 insertions, 2910 deletions
diff --git a/deps/node/deps/icu-small/source/common/ucnv.cpp b/deps/node/deps/icu-small/source/common/ucnv.cpp deleted file mode 100644 index abf302ea..00000000 --- a/deps/node/deps/icu-small/source/common/ucnv.cpp +++ /dev/null @@ -1,2910 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* -****************************************************************************** -* -* Copyright (C) 1998-2016, International Business Machines -* Corporation and others. All Rights Reserved. -* -****************************************************************************** -* -* ucnv.c: -* Implements APIs for the ICU's codeset conversion library; -* mostly calls through internal functions; -* created by Bertrand A. Damiba -* -* Modification History: -* -* Date Name Description -* 04/04/99 helena Fixed internal header inclusion. -* 05/09/00 helena Added implementation to handle fallback mappings. -* 06/20/2000 helena OS/400 port changes; mostly typecast. -*/ - -#include "unicode/utypes.h" - -#if !UCONFIG_NO_CONVERSION - -#include "unicode/ustring.h" -#include "unicode/ucnv.h" -#include "unicode/ucnv_err.h" -#include "unicode/uset.h" -#include "unicode/utf.h" -#include "unicode/utf16.h" -#include "putilimp.h" -#include "cmemory.h" -#include "cstring.h" -#include "uassert.h" -#include "utracimp.h" -#include "ustr_imp.h" -#include "ucnv_imp.h" -#include "ucnv_cnv.h" -#include "ucnv_bld.h" - -/* size of intermediate and preflighting buffers in ucnv_convert() */ -#define CHUNK_SIZE 1024 - -typedef struct UAmbiguousConverter { - const char *name; - const UChar variant5c; -} UAmbiguousConverter; - -static const UAmbiguousConverter ambiguousConverters[]={ - { "ibm-897_P100-1995", 0xa5 }, - { "ibm-942_P120-1999", 0xa5 }, - { "ibm-943_P130-1999", 0xa5 }, - { "ibm-946_P100-1995", 0xa5 }, - { "ibm-33722_P120-1999", 0xa5 }, - { "ibm-1041_P100-1995", 0xa5 }, - /*{ "ibm-54191_P100-2006", 0xa5 },*/ - /*{ "ibm-62383_P100-2007", 0xa5 },*/ - /*{ "ibm-891_P100-1995", 0x20a9 },*/ - { "ibm-944_P100-1995", 0x20a9 }, - { "ibm-949_P110-1999", 0x20a9 }, - { "ibm-1363_P110-1997", 0x20a9 }, - { "ISO_2022,locale=ko,version=0", 0x20a9 }, - { "ibm-1088_P100-1995", 0x20a9 } -}; - -/*Calls through createConverter */ -U_CAPI UConverter* U_EXPORT2 -ucnv_open (const char *name, - UErrorCode * err) -{ - UConverter *r; - - if (err == NULL || U_FAILURE (*err)) { - return NULL; - } - - r = ucnv_createConverter(NULL, name, err); - return r; -} - -U_CAPI UConverter* U_EXPORT2 -ucnv_openPackage (const char *packageName, const char *converterName, UErrorCode * err) -{ - return ucnv_createConverterFromPackage(packageName, converterName, err); -} - -/*Extracts the UChar* to a char* and calls through createConverter */ -U_CAPI UConverter* U_EXPORT2 -ucnv_openU (const UChar * name, - UErrorCode * err) -{ - char asciiName[UCNV_MAX_CONVERTER_NAME_LENGTH]; - - if (err == NULL || U_FAILURE(*err)) - return NULL; - if (name == NULL) - return ucnv_open (NULL, err); - if (u_strlen(name) >= UCNV_MAX_CONVERTER_NAME_LENGTH) - { - *err = U_ILLEGAL_ARGUMENT_ERROR; - return NULL; - } - 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 -ucnv_openCCSID (int32_t codepage, - UConverterPlatform platform, - UErrorCode * err) -{ - char myName[UCNV_MAX_CONVERTER_NAME_LENGTH]; - int32_t myNameLen; - - if (err == NULL || U_FAILURE (*err)) - return NULL; - - /* ucnv_copyPlatformString could return "ibm-" or "cp" */ - myNameLen = ucnv_copyPlatformString(myName, platform); - T_CString_integerToString(myName + myNameLen, codepage, 10); - - return ucnv_createConverter(NULL, myName, err); -} - -/* Creating a temporary stack-based object that can be used in one thread, -and created from a converter that is shared across threads. -*/ - -U_CAPI UConverter* U_EXPORT2 -ucnv_safeClone(const UConverter* cnv, void *stackBuffer, int32_t *pBufferSize, UErrorCode *status) -{ - UConverter *localConverter, *allocatedConverter; - int32_t stackBufferSize; - int32_t bufferSizeNeeded; - char *stackBufferChars = (char *)stackBuffer; - UErrorCode cbErr; - UConverterToUnicodeArgs toUArgs = { - sizeof(UConverterToUnicodeArgs), - TRUE, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL - }; - UConverterFromUnicodeArgs fromUArgs = { - sizeof(UConverterFromUnicodeArgs), - TRUE, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL - }; - - UTRACE_ENTRY_OC(UTRACE_UCNV_CLONE); - - if (status == NULL || U_FAILURE(*status)){ - UTRACE_EXIT_STATUS(status? *status: U_ILLEGAL_ARGUMENT_ERROR); - return NULL; - } - - if (cnv == NULL) { - *status = U_ILLEGAL_ARGUMENT_ERROR; - UTRACE_EXIT_STATUS(*status); - return NULL; - } - - UTRACE_DATA3(UTRACE_OPEN_CLOSE, "clone converter %s at %p into stackBuffer %p", - ucnv_getName(cnv, status), cnv, stackBuffer); - - if (cnv->sharedData->impl->safeClone != NULL) { - /* call the custom safeClone function for sizing */ - bufferSizeNeeded = 0; - cnv->sharedData->impl->safeClone(cnv, NULL, &bufferSizeNeeded, status); - if (U_FAILURE(*status)) { - UTRACE_EXIT_STATUS(*status); - return NULL; - } - } - else - { - /* inherent sizing */ - bufferSizeNeeded = sizeof(UConverter); - } - - if (pBufferSize == NULL) { - stackBufferSize = 1; - pBufferSize = &stackBufferSize; - } else { - stackBufferSize = *pBufferSize; - if (stackBufferSize <= 0){ /* 'preflighting' request - set needed size into *pBufferSize */ - *pBufferSize = bufferSizeNeeded; - UTRACE_EXIT_VALUE(bufferSizeNeeded); - return NULL; - } - } - - - /* Pointers on 64-bit platforms need to be aligned - * on a 64-bit boundary in memory. - */ - if (U_ALIGNMENT_OFFSET(stackBuffer) != 0) { - int32_t offsetUp = (int32_t)U_ALIGNMENT_OFFSET_UP(stackBufferChars); - if(stackBufferSize > offsetUp) { - stackBufferSize -= offsetUp; - stackBufferChars += offsetUp; - } else { - /* prevent using the stack buffer but keep the size > 0 so that we do not just preflight */ - stackBufferSize = 1; - } - } - - stackBuffer = (void *)stackBufferChars; - - /* Now, see if we must allocate any memory */ - if (stackBufferSize < bufferSizeNeeded || stackBuffer == NULL) - { - /* allocate one here...*/ - localConverter = allocatedConverter = (UConverter *) uprv_malloc (bufferSizeNeeded); - - if(localConverter == NULL) { - *status = U_MEMORY_ALLOCATION_ERROR; - UTRACE_EXIT_STATUS(*status); - return NULL; - } - *status = U_SAFECLONE_ALLOCATED_WARNING; - - /* record the fact that memory was allocated */ - *pBufferSize = bufferSizeNeeded; - } else { - /* just use the stack buffer */ - localConverter = (UConverter*) stackBuffer; - allocatedConverter = NULL; - } - - uprv_memset(localConverter, 0, bufferSizeNeeded); - - /* Copy initial state */ - 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 */ - localConverter = cnv->sharedData->impl->safeClone(cnv, localConverter, pBufferSize, status); - } - - 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; - } - - /* increment refcount of shared data if needed */ - if (cnv->sharedData->isReferenceCounted) { - ucnv_incrementRefCount(cnv->sharedData); - } - - if(localConverter == (UConverter*)stackBuffer) { - /* we're using user provided data - set to not destroy */ - localConverter->isCopyLocal = TRUE; - } - - /* allow callback functions to handle any memory allocation */ - toUArgs.converter = fromUArgs.converter = localConverter; - cbErr = U_ZERO_ERROR; - cnv->fromCharErrorBehaviour(cnv->toUContext, &toUArgs, NULL, 0, UCNV_CLONE, &cbErr); - cbErr = U_ZERO_ERROR; - cnv->fromUCharErrorBehaviour(cnv->fromUContext, &fromUArgs, NULL, 0, 0, UCNV_CLONE, &cbErr); - - UTRACE_EXIT_PTR_STATUS(localConverter, *status); - return localConverter; -} - - - -/*Decreases the reference counter in the shared immutable section of the object - *and frees the mutable part*/ - -U_CAPI void U_EXPORT2 -ucnv_close (UConverter * converter) -{ - UErrorCode errorCode = U_ZERO_ERROR; - - UTRACE_ENTRY_OC(UTRACE_UCNV_CLOSE); - - if (converter == NULL) - { - UTRACE_EXIT(); - return; - } - - UTRACE_DATA3(UTRACE_OPEN_CLOSE, "close converter %s at %p, isCopyLocal=%b", - ucnv_getName(converter, &errorCode), converter, converter->isCopyLocal); - - /* 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 - }; - - 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); - } - - if (converter->sharedData->isReferenceCounted) { - ucnv_unloadSharedDataIfReady(converter->sharedData); - } - - if(!converter->isCopyLocal){ - uprv_free(converter); - } - - UTRACE_EXIT(); -} - -/*returns a single Name from the list, will return NULL if out of bounds - */ -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_bld_getAvailableConverter((uint16_t)n, &err); - if (U_SUCCESS(err)) { - return name; - } - } - return NULL; -} - -U_CAPI int32_t U_EXPORT2 -ucnv_countAvailable () -{ - UErrorCode err = U_ZERO_ERROR; - return ucnv_bld_countAvailableConverters(&err); -} - -U_CAPI void U_EXPORT2 -ucnv_getSubstChars (const UConverter * converter, - char *mySubChar, - int8_t * len, - UErrorCode * err) -{ - 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->subChars, converter->subCharLen); /*fills in the subchars */ - *len = converter->subCharLen; /*store # of bytes copied to buffer */ -} - -U_CAPI void U_EXPORT2 -ucnv_setSubstChars (UConverter * converter, - const char *mySubChar, - int8_t len, - UErrorCode * err) -{ - if (U_FAILURE (*err)) - return; - - /*Makes sure that the subChar is within the codepages char length boundaries */ - if ((len > converter->sharedData->staticData->maxBytesPerChar) - || (len < converter->sharedData->staticData->minBytesPerChar)) - { - *err = U_ILLEGAL_ARGUMENT_ERROR; - return; - } - - uprv_memcpy (converter->subChars, mySubChar, len); /*copies the subchars */ - converter->subCharLen = len; /*sets the new len */ - - /* - * There is currently (2001Feb) no separate API to set/get subChar1. - * In order to always have subChar written after it is explicitly set, - * we set subChar1 to 0. - */ - converter->subChar1 = 0; - - return; -} - -U_CAPI 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 - */ -static void _reset(UConverter *converter, UConverterResetChoice choice, - UBool callCallback) { - if(converter == NULL) { - return; - } - - if(callCallback) { - /* first, notify the callback functions that the converter is reset */ - UErrorCode errorCode; - - if(choice<=UCNV_RESET_TO_UNICODE && converter->fromCharErrorBehaviour != UCNV_TO_U_DEFAULT_CALLBACK) { - UConverterToUnicodeArgs toUArgs = { - sizeof(UConverterToUnicodeArgs), - TRUE, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL - }; - toUArgs.converter = converter; - errorCode = U_ZERO_ERROR; - converter->fromCharErrorBehaviour(converter->toUContext, &toUArgs, NULL, 0, UCNV_RESET, &errorCode); - } - if(choice!=UCNV_RESET_TO_UNICODE && 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_RESET, &errorCode); - } - } - - /* now reset the converter itself */ - if(choice<=UCNV_RESET_TO_UNICODE) { - converter->toUnicodeStatus = converter->sharedData->toUnicodeStatus; - converter->mode = 0; - converter->toULength = 0; - converter->invalidCharLength = converter->UCharErrorBufferLength = 0; - converter->preToULength = 0; - } - if(choice!=UCNV_RESET_TO_UNICODE) { - converter->fromUnicodeStatus = 0; - converter->fromUChar32 = 0; - converter->invalidUCharLength = converter->charErrorBufferLength = 0; - converter->preFromUFirstCP = U_SENTINEL; - converter->preFromULength = 0; - } - - if (converter->sharedData->impl->reset != NULL) { - /* call the custom reset function */ - converter->sharedData->impl->reset(converter, choice); - } -} - -U_CAPI void U_EXPORT2 -ucnv_reset(UConverter *converter) -{ - _reset(converter, UCNV_RESET_BOTH, TRUE); -} - -U_CAPI void U_EXPORT2 -ucnv_resetToUnicode(UConverter *converter) -{ - _reset(converter, UCNV_RESET_TO_UNICODE, TRUE); -} - -U_CAPI void U_EXPORT2 -ucnv_resetFromUnicode(UConverter *converter) -{ - _reset(converter, UCNV_RESET_FROM_UNICODE, TRUE); -} - -U_CAPI int8_t U_EXPORT2 -ucnv_getMaxCharSize (const UConverter * converter) -{ - return converter->maxBytesPerUChar; -} - - -U_CAPI int8_t U_EXPORT2 -ucnv_getMinCharSize (const UConverter * converter) -{ - return converter->sharedData->staticData->minBytesPerChar; -} - -U_CAPI const char* U_EXPORT2 -ucnv_getName (const UConverter * converter, UErrorCode * err) - -{ - if (U_FAILURE (*err)) - return NULL; - if(converter->sharedData->impl->getName){ - const char* temp= converter->sharedData->impl->getName(converter); - if(temp) - return temp; - } - return converter->sharedData->staticData->name; -} - -U_CAPI int32_t U_EXPORT2 -ucnv_getCCSID(const UConverter * converter, - UErrorCode * err) -{ - int32_t ccsid; - if (U_FAILURE (*err)) - return -1; - - ccsid = converter->sharedData->staticData->codepage; - if (ccsid == 0) { - /* Rare case. This is for cases like gb18030, - which doesn't have an IBM canonical name, but does have an IBM alias. */ - const char *standardName = ucnv_getStandardName(ucnv_getName(converter, err), "IBM", err); - if (U_SUCCESS(*err) && standardName) { - const char *ccsidStr = uprv_strchr(standardName, '-'); - if (ccsidStr) { - ccsid = (int32_t)atol(ccsidStr+1); /* +1 to skip '-' */ - } - } - } - return ccsid; -} - - -U_CAPI UConverterPlatform U_EXPORT2 -ucnv_getPlatform (const UConverter * converter, - UErrorCode * err) -{ - if (U_FAILURE (*err)) - return UCNV_UNKNOWN; - - return (UConverterPlatform)converter->sharedData->staticData->platform; -} - -U_CAPI void U_EXPORT2 - ucnv_getToUCallBack (const UConverter * converter, - UConverterToUCallback *action, - const void **context) -{ - *action = converter->fromCharErrorBehaviour; - *context = converter->toUContext; -} - -U_CAPI void U_EXPORT2 - ucnv_getFromUCallBack (const UConverter * converter, - UConverterFromUCallback *action, - const void **context) -{ - *action = converter->fromUCharErrorBehaviour; - *context = converter->fromUContext; -} - -U_CAPI void U_EXPORT2 -ucnv_setToUCallBack (UConverter * converter, - UConverterToUCallback newAction, - const void* newContext, - UConverterToUCallback *oldAction, - const void** oldContext, - UErrorCode * err) -{ - if (U_FAILURE (*err)) - return; - if (oldAction) *oldAction = converter->fromCharErrorBehaviour; - converter->fromCharErrorBehaviour = newAction; - if (oldContext) *oldContext = converter->toUContext; - converter->toUContext = newContext; -} - -U_CAPI void U_EXPORT2 -ucnv_setFromUCallBack (UConverter * converter, - UConverterFromUCallback newAction, - const void* newContext, - UConverterFromUCallback *oldAction, - const void** oldContext, - UErrorCode * err) -{ - if (U_FAILURE (*err)) - return; - if (oldAction) *oldAction = converter->fromUCharErrorBehaviour; - converter->fromUCharErrorBehaviour = newAction; - if (oldContext) *oldContext = converter->fromUContext; - converter->fromUContext = newContext; -} - -static void -_updateOffsets(int32_t *offsets, int32_t length, - int32_t sourceIndex, int32_t errorInputLength) { - int32_t *limit; - int32_t delta, offset; - - if(sourceIndex>=0) { - /* - * adjust each offset by adding the previous sourceIndex - * minus the length of the input sequence that caused an - * error, if any - */ - delta=sourceIndex-errorInputLength; - } else { - /* - * set each offset to -1 because this conversion function - * does not handle offsets - */ - delta=-1; - } - - limit=offsets+length; - if(delta==0) { - /* most common case, nothing to do */ - } else if(delta>0) { - /* add the delta to each offset (but not if the offset is <0) */ - while(offsets<limit) { - offset=*offsets; - if(offset>=0) { - *offsets=offset+delta; - } - ++offsets; - } - } else /* delta<0 */ { - /* - * set each offset to -1 because this conversion function - * does not handle offsets - * or the error input sequence started in a previous buffer - */ - while(offsets<limit) { - *offsets++=-1; - } - } -} - -/* ucnv_fromUnicode --------------------------------------------------------- */ - -/* - * Implementation note for m:n conversions - * - * While collecting source units to find the longest match for m:n conversion, - * some source units may need to be stored for a partial match. - * When a second buffer does not yield a match on all of the previously stored - * source units, then they must be "replayed", i.e., fed back into the converter. - * - * The code relies on the fact that replaying will not nest - - * converting a replay buffer will not result in a replay. - * This is because a replay is necessary only after the _continuation_ of a - * partial match failed, but a replay buffer is converted as a whole. - * It may result in some of its units being stored again for a partial match, - * but there will not be a continuation _during_ the replay which could fail. - * - * It is conceivable that a callback function could call the converter - * recursively in a way that causes another replay to be stored, but that - * would be an error in the callback function. - * Such violations will cause assertion failures in a debug build, - * and wrong output, but they will not cause a crash. - */ - -static void -_fromUnicodeWithCallback(UConverterFromUnicodeArgs *pArgs, UErrorCode *err) { - UConverterFromUnicode fromUnicode; - UConverter *cnv; - const UChar *s; - char *t; - int32_t *offsets; - int32_t sourceIndex; - int32_t errorInputLength; - UBool converterSawEndOfInput, calledCallback; - - /* variables for m:n conversion */ - UChar replay[UCNV_EXT_MAX_UCHARS]; - const UChar *realSource, *realSourceLimit; - int32_t realSourceIndex; - UBool realFlush; - - cnv=pArgs->converter; - s=pArgs->source; - t=pArgs->target; - offsets=pArgs->offsets; - - /* get the converter implementation function */ - sourceIndex=0; - if(offsets==NULL) { - fromUnicode=cnv->sharedData->impl->fromUnicode; - } else { - fromUnicode=cnv->sharedData->impl->fromUnicodeWithOffsets; - if(fromUnicode==NULL) { - /* there is no WithOffsets implementation */ - fromUnicode=cnv->sharedData->impl->fromUnicode; - /* we will write -1 for each offset */ - sourceIndex=-1; - } - } - - if(cnv->preFromULength>=0) { - /* normal mode */ - realSource=NULL; - - /* avoid compiler warnings - not otherwise necessary, and the values do not matter */ - realSourceLimit=NULL; - realFlush=FALSE; - realSourceIndex=0; - } else { - /* - * Previous m:n conversion stored source units from a partial match - * and failed to consume all of them. - * We need to "replay" them from a temporary buffer and convert them first. - */ - realSource=pArgs->source; - realSourceLimit=pArgs->sourceLimit; - realFlush=pArgs->flush; - realSourceIndex=sourceIndex; - - uprv_memcpy(replay, cnv->preFromU, -cnv->preFromULength*U_SIZEOF_UCHAR); - pArgs->source=replay; - pArgs->sourceLimit=replay-cnv->preFromULength; - pArgs->flush=FALSE; - sourceIndex=-1; - - cnv->preFromULength=0; - } - - /* - * loop for conversion and error handling - * - * loop { - * convert - * loop { - * update offsets - * handle end of input - * handle errors/call callback - * } - * } - */ - for(;;) { - if(U_SUCCESS(*err)) { - /* convert */ - fromUnicode(pArgs, err); - - /* - * set a flag for whether the converter - * successfully processed the end of the input - * - * need not check cnv->preFromULength==0 because a replay (<0) will cause - * s<sourceLimit before converterSawEndOfInput is checked - */ - converterSawEndOfInput= - (UBool)(U_SUCCESS(*err) && - pArgs->flush && pArgs->source==pArgs->sourceLimit && - cnv->fromUChar32==0); - } else { - /* handle error from ucnv_convertEx() */ - converterSawEndOfInput=FALSE; - } - - /* no callback called yet for this iteration */ - calledCallback=FALSE; - - /* no sourceIndex adjustment for conversion, only for callback output */ - errorInputLength=0; - - /* - * loop for offsets and error handling - * - * iterates at most 3 times: - * 1. to clean up after the conversion function - * 2. after the callback - * 3. after the callback again if there was truncated input - */ - for(;;) { - /* update offsets if we write any */ - if(offsets!=NULL) { - int32_t length=(int32_t)(pArgs->target-t); - if(length>0) { - _updateOffsets(offsets, length, sourceIndex, errorInputLength); - - /* - * if a converter handles offsets and updates the offsets - * pointer at the end, then pArgs->offset should not change - * here; - * however, some converters do not handle offsets at all - * (sourceIndex<0) or may not update the offsets pointer - */ - pArgs->offsets=offsets+=length; - } - - if(sourceIndex>=0) { - sourceIndex+=(int32_t)(pArgs->source-s); - } - } - - if(cnv->preFromULength<0) { - /* - * switch the source to new replay units (cannot occur while replaying) - * after offset handling and before end-of-input and callback handling - */ - if(realSource==NULL) { - realSource=pArgs->source; - realSourceLimit=pArgs->sourceLimit; - realFlush=pArgs->flush; - realSourceIndex=sourceIndex; - - uprv_memcpy(replay, cnv->preFromU, -cnv->preFromULength*U_SIZEOF_UCHAR); - pArgs->source=replay; - pArgs->sourceLimit=replay-cnv->preFromULength; - pArgs->flush=FALSE; - if((sourceIndex+=cnv->preFromULength)<0) { - sourceIndex=-1; - } - - cnv->preFromULength=0; - } else { - /* see implementation note before _fromUnicodeWithCallback() */ - U_ASSERT(realSource==NULL); - *err=U_INTERNAL_PROGRAM_ERROR; - } - } - - /* update pointers */ - s=pArgs->source; - t=pArgs->target; - - if(U_SUCCESS(*err)) { - if(s<pArgs->sourceLimit) { - /* - * continue with the conversion loop while there is still input left - * (continue converting by breaking out of only the inner loop) - */ - break; - } else if(realSource!=NULL) { - /* switch back from replaying to the real source and continue */ - pArgs->source=realSource; - pArgs->sourceLimit=realSourceLimit; - pArgs->flush=realFlush; - sourceIndex=realSourceIndex; - - realSource=NULL; - break; - } else if(pArgs->flush && cnv->fromUChar32!=0) { - /* - * the entire input stream is consumed - * and there is a partial, truncated input sequence left - */ - - /* inject an error and continue with callback handling */ - *err=U_TRUNCATED_CHAR_FOUND; - calledCallback=FALSE; /* new error condition */ - } else { - /* input consumed */ - if(pArgs->flush) { - /* - * return to the conversion loop once more if the flush - * flag is set and the conversion function has not - * successfully processed the end of the input yet - * - * (continue converting by breaking out of only the inner loop) - */ - if(!converterSawEndOfInput) { - break; - } - - /* reset the converter without calling the callback function */ - _reset(cnv, UCNV_RESET_FROM_UNICODE, FALSE); - } - - /* done successfully */ - return; - } - } - - /* U_FAILURE(*err) */ - { - UErrorCode e; - - if( calledCallback || - (e=*err)==U_BUFFER_OVERFLOW_ERROR || - (e!=U_INVALID_CHAR_FOUND && - e!=U_ILLEGAL_CHAR_FOUND && - e!=U_TRUNCATED_CHAR_FOUND) - ) { - /* - * the callback did not or cannot resolve the error: - * set output pointers and return - * - * the check for buffer overflow is redundant but it is - * a high-runner case and hopefully documents the intent - * well - * - * if we were replaying, then the replay buffer must be - * copied back into the UConverter - * and the real arguments must be restored - */ - if(realSource!=NULL) { - int32_t length; - - U_ASSERT(cnv->preFromULength==0); - - length=(int32_t)(pArgs->sourceLimit-pArgs->source); - if(length>0) { - u_memcpy(cnv->preFromU, pArgs->source, length); - cnv->preFromULength=(int8_t)-length; - } - - pArgs->source=realSource; - pArgs->sourceLimit=realSourceLimit; - pArgs->flush=realFlush; - } - - return; - } - } - - /* callback handling */ - { - UChar32 codePoint; - - /* get and write the code point */ - codePoint=cnv->fromUChar32; - errorInputLength=0; - U16_APPEND_UNSAFE(cnv->invalidUCharBuffer, errorInputLength, codePoint); - cnv->invalidUCharLength=(int8_t)errorInputLength; - - /* set the converter state to deal with the next character */ - cnv->fromUChar32=0; - - /* call the callback function */ - cnv->fromUCharErrorBehaviour(cnv->fromUContext, pArgs, - cnv->invalidUCharBuffer, errorInputLength, codePoint, - *err==U_INVALID_CHAR_FOUND ? UCNV_UNASSIGNED : UCNV_ILLEGAL, - err); - } - - /* - * loop back to the offset handling - * - * this flag will indicate after offset handling - * that a callback was called; - * if the callback did not resolve the error, then we return - */ - calledCallback=TRUE; - } - } -} - -/* - * Output the fromUnicode overflow buffer. - * Call this function if(cnv->charErrorBufferLength>0). - * @return TRUE if overflow - */ -static UBool -ucnv_outputOverflowFromUnicode(UConverter *cnv, - char **target, const char *targetLimit, - int32_t **pOffsets, - UErrorCode *err) { - int32_t *offsets; - char *overflow, *t; - int32_t i, length; - - t=*target; - if(pOffsets!=NULL) { - offsets=*pOffsets; - } else { - offsets=NULL; - } - - overflow=(char *)cnv->charErrorBuffer; - length=cnv->charErrorBufferLength; - i=0; - while(i<length) { - if(t==targetLimit) { - /* the overflow buffer contains too much, keep the rest */ - int32_t j=0; - - do { - overflow[j++]=overflow[i++]; - } while(i<length); - - cnv->charErrorBufferLength=(int8_t)j; - *target=t; - if(offsets!=NULL) { - *pOffsets=offsets; - } - *err=U_BUFFER_OVERFLOW_ERROR; - return TRUE; - } - - /* copy the overflow contents to the target */ - *t++=overflow[i++]; - if(offsets!=NULL) { - *offsets++=-1; /* no source index available for old output */ - } - } - - /* the overflow buffer is completely copied to the target */ - cnv->charErrorBufferLength=0; - *target=t; - if(offsets!=NULL) { - *pOffsets=offsets; - } - return FALSE; -} - -U_CAPI void U_EXPORT2 -ucnv_fromUnicode(UConverter *cnv, - char **target, const char *targetLimit, - const UChar **source, const UChar *sourceLimit, - int32_t *offsets, - UBool flush, - UErrorCode *err) { - UConverterFromUnicodeArgs args; - const UChar *s; - char *t; - - /* check parameters */ - if(err==NULL || U_FAILURE(*err)) { - return; - } - - if(cnv==NULL || target==NULL || source==NULL) { - *err=U_ILLEGAL_ARGUMENT_ERROR; - return; - } - - s=*source; - t=*target; - - if ((const void *)U_MAX_PTR(sourceLimit) == (const void *)sourceLimit) { - /* - Prevent code from going into an infinite loop in case we do hit this - limit. The limit pointer is expected to be on a UChar * boundary. - This also prevents the next argument check from failing. - */ - sourceLimit = (const UChar *)(((const char *)sourceLimit) - 1); - } - - /* - * All these conditions should never happen. - * - * 1) Make sure that the limits are >= to the address source or target - * - * 2) Make sure that the buffer sizes do not exceed the number range for - * int32_t because some functions use the size (in units or bytes) - * rather than comparing pointers, and because offsets are int32_t values. - * - * size_t is guaranteed to be unsigned and large enough for the job. - * - * Return with an error instead of adjusting the limits because we would - * not be able to maintain the semantics that either the source must be - * consumed or the target filled (unless an error occurs). - * An adjustment would be targetLimit=t+0x7fffffff; for example. - * - * 3) Make sure that the user didn't incorrectly cast a UChar * pointer - * to a char * pointer and provide an incomplete UChar code unit. - */ - if (sourceLimit<s || targetLimit<t || - ((size_t)(sourceLimit-s)>(size_t)0x3fffffff && sourceLimit>s) || - ((size_t)(targetLimit-t)>(size_t)0x7fffffff && targetLimit>t) || - (((const char *)sourceLimit-(const char *)s) & 1) != 0) - { - *err=U_ILLEGAL_ARGUMENT_ERROR; - return; - } - - /* output the target overflow buffer */ - if( cnv->charErrorBufferLength>0 && - ucnv_outputOverflowFromUnicode(cnv, target, targetLimit, &offsets, err) - ) { - /* U_BUFFER_OVERFLOW_ERROR */ - return; - } - /* *target may have moved, therefore stop using t */ - - if(!flush && s==sourceLimit && cnv->preFromULength>=0) { - /* the overflow buffer is emptied and there is no new input: we are done */ - return; - } - - /* - * Do not simply return with a buffer overflow error if - * !flush && t==targetLimit - * because it is possible that the source will not generate any output. - * For example, the skip callback may be called; - * it does not output anything. - */ - - /* prepare the converter arguments */ - args.converter=cnv; - args.flush=flush; - args.offsets=offsets; - args.source=s; - args.sourceLimit=sourceLimit; - args.target=*target; - args.targetLimit=targetLimit; - args.size=sizeof(args); - - _fromUnicodeWithCallback(&args, err); - - *source=args.source; - *target=args.target; -} - -/* ucnv_toUnicode() --------------------------------------------------------- */ - -static void -_toUnicodeWithCallback(UConverterToUnicodeArgs *pArgs, UErrorCode *err) { - UConverterToUnicode toUnicode; - UConverter *cnv; - const char *s; - UChar *t; - int32_t *offsets; - int32_t sourceIndex; - int32_t errorInputLength; - UBool converterSawEndOfInput, calledCallback; - - /* variables for m:n conversion */ - char replay[UCNV_EXT_MAX_BYTES]; - const char *realSource, *realSourceLimit; - int32_t realSourceIndex; - UBool realFlush; - - cnv=pArgs->converter; - s=pArgs->source; - t=pArgs->target; - offsets=pArgs->offsets; - - /* get the converter implementation function */ - sourceIndex=0; - if(offsets==NULL) { - toUnicode=cnv->sharedData->impl->toUnicode; - } else { - toUnicode=cnv->sharedData->impl->toUnicodeWithOffsets; - if(toUnicode==NULL) { - /* there is no WithOffsets implementation */ - toUnicode=cnv->sharedData->impl->toUnicode; - /* we will write -1 for each offset */ - sourceIndex=-1; - } - } - - if(cnv->preToULength>=0) { - /* normal mode */ - realSource=NULL; - - /* avoid compiler warnings - not otherwise necessary, and the values do not matter */ - realSourceLimit=NULL; - realFlush=FALSE; - realSourceIndex=0; - } else { - /* - * Previous m:n conversion stored source units from a partial match - * and failed to consume all of them. - * We need to "replay" them from a temporary buffer and convert them first. - */ - realSource=pArgs->source; - realSourceLimit=pArgs->sourceLimit; - realFlush=pArgs->flush; - realSourceIndex=sourceIndex; - - uprv_memcpy(replay, cnv->preToU, -cnv->preToULength); - pArgs->source=replay; - pArgs->sourceLimit=replay-cnv->preToULength; - pArgs->flush=FALSE; - sourceIndex=-1; - - cnv->preToULength=0; - } - - /* - * loop for conversion and error handling - * - * loop { - * convert - * loop { - * update offsets - * handle end of input - * handle errors/call callback - * } - * } - */ - for(;;) { - if(U_SUCCESS(*err)) { - /* convert */ - toUnicode(pArgs, err); - - /* - * set a flag for whether the converter - * successfully processed the end of the input - * - * need not check cnv->preToULength==0 because a replay (<0) will cause - * s<sourceLimit before converterSawEndOfInput is checked - */ - converterSawEndOfInput= - (UBool)(U_SUCCESS(*err) && - pArgs->flush && pArgs->source==pArgs->sourceLimit && - cnv->toULength==0); - } else { - /* handle error from getNextUChar() or ucnv_convertEx() */ - converterSawEndOfInput=FALSE; - } - - /* no callback called yet for this iteration */ - calledCallback=FALSE; - - /* no sourceIndex adjustment for conversion, only for callback output */ - errorInputLength=0; - - /* - * loop for offsets and error handling - * - * iterates at most 3 times: - * 1. to clean up after the conversion function - * 2. after the callback - * 3. after the callback again if there was truncated input - */ - for(;;) { - /* update offsets if we write any */ - if(offsets!=NULL) { - int32_t length=(int32_t)(pArgs->target-t); - if(length>0) { - _updateOffsets(offsets, length, sourceIndex, errorInputLength); - - /* - * if a converter handles offsets and updates the offsets - * pointer at the end, then pArgs->offset should not change - * here; - * however, some converters do not handle offsets at all - * (sourceIndex<0) or may not update the offsets pointer - */ - pArgs->offsets=offsets+=length; - } - - if(sourceIndex>=0) { - sourceIndex+=(int32_t)(pArgs->source-s); - } - } - - if(cnv->preToULength<0) { - /* - * switch the source to new replay units (cannot occur while replaying) - * after offset handling and before end-of-input and callback handling - */ - if(realSource==NULL) { - realSource=pArgs->source; - realSourceLimit=pArgs->sourceLimit; - realFlush=pArgs->flush; - realSourceIndex=sourceIndex; - - uprv_memcpy(replay, cnv->preToU, -cnv->preToULength); - pArgs->source=replay; - pArgs->sourceLimit=replay-cnv->preToULength; - pArgs->flush=FALSE; - if((sourceIndex+=cnv->preToULength)<0) { - sourceIndex=-1; - } - - cnv->preToULength=0; - } else { - /* see implementation note before _fromUnicodeWithCallback() */ - U_ASSERT(realSource==NULL); - *err=U_INTERNAL_PROGRAM_ERROR; - } - } - - /* update pointers */ - s=pArgs->source; - t=pArgs->target; - - if(U_SUCCESS(*err)) { - if(s<pArgs->sourceLimit) { - /* - * continue with the conversion loop while there is still input left - * (continue converting by breaking out of only the inner loop) - */ - break; - } else if(realSource!=NULL) { - /* switch back from replaying to the real source and continue */ - pArgs->source=realSource; - pArgs->sourceLimit=realSourceLimit; - pArgs->flush=realFlush; - sourceIndex=realSourceIndex; - - realSource=NULL; - break; - } else if(pArgs->flush && cnv->toULength>0) { - /* - * the entire input stream is consumed - * and there is a partial, truncated input sequence left - */ - - /* inject an error and continue with callback handling */ - *err=U_TRUNCATED_CHAR_FOUND; - calledCallback=FALSE; /* new error condition */ - } else { - /* input consumed */ - if(pArgs->flush) { - /* - * return to the conversion loop once more if the flush - * flag is set and the conversion function has not - * successfully processed the end of the input yet - * - * (continue converting by breaking out of only the inner loop) - */ - if(!converterSawEndOfInput) { - break; - } - - /* reset the converter without calling the callback function */ - _reset(cnv, UCNV_RESET_TO_UNICODE, FALSE); - } - - /* done successfully */ - return; - } - } - - /* U_FAILURE(*err) */ - { - UErrorCode e; - - if( calledCallback || - (e=*err)==U_BUFFER_OVERFLOW_ERROR || - (e!=U_INVALID_CHAR_FOUND && - e!=U_ILLEGAL_CHAR_FOUND && - e!=U_TRUNCATED_CHAR_FOUND && - e!=U_ILLEGAL_ESCAPE_SEQUENCE && - e!=U_UNSUPPORTED_ESCAPE_SEQUENCE) - ) { - /* - * the callback did not or cannot resolve the error: - * set output pointers and return - * - * the check for buffer overflow is redundant but it is - * a high-runner case and hopefully documents the intent - * well - * - * if we were replaying, then the replay buffer must be - * copied back into the UConverter - * and the real arguments must be restored - */ - if(realSource!=NULL) { - int32_t length; - - U_ASSERT(cnv->preToULength==0); - - length=(int32_t)(pArgs->sourceLimit-pArgs->source); - if(length>0) { - uprv_memcpy(cnv->preToU, pArgs->source, length); - cnv->preToULength=(int8_t)-length; - } - - pArgs->source=realSource; - pArgs->sourceLimit=realSourceLimit; - pArgs->flush=realFlush; - } - - return; - } - } - - /* copy toUBytes[] to invalidCharBuffer[] */ - errorInputLength=cnv->invalidCharLength=cnv->toULength; - if(errorInputLength>0) { - uprv_memcpy(cnv->invalidCharBuffer, cnv->toUBytes, errorInputLength); - } - - /* set the converter state to deal with the next character */ - cnv->toULength=0; - - /* call the callback function */ - if(cnv->toUCallbackReason==UCNV_ILLEGAL && *err==U_INVALID_CHAR_FOUND) { - cnv->toUCallbackReason = UCNV_UNASSIGNED; - } - cnv->fromCharErrorBehaviour(cnv->toUContext, pArgs, - cnv->invalidCharBuffer, errorInputLength, - cnv->toUCallbackReason, - err); - cnv->toUCallbackReason = UCNV_ILLEGAL; /* reset to default value */ - - /* - * loop back to the offset handling - * - * this flag will indicate after offset handling - * that a callback was called; - * if the callback did not resolve the error, then we return - */ - calledCallback=TRUE; - } - } -} - -/* - * Output the toUnicode overflow buffer. - * Call this function if(cnv->UCharErrorBufferLength>0). - * @return TRUE if overflow - */ -static UBool -ucnv_outputOverflowToUnicode(UConverter *cnv, - UChar **target, const UChar *targetLimit, - int32_t **pOffsets, - UErrorCode *err) { - int32_t *offsets; - UChar *overflow, *t; - int32_t i, length; - - t=*target; - if(pOffsets!=NULL) { - offsets=*pOffsets; - } else { - offsets=NULL; - } - - overflow=cnv->UCharErrorBuffer; - length=cnv->UCharErrorBufferLength; - i=0; - while(i<length) { - if(t==targetLimit) { - /* the overflow buffer contains too much, keep the rest */ - int32_t j=0; - - do { - overflow[j++]=overflow[i++]; - } while(i<length); - - cnv->UCharErrorBufferLength=(int8_t)j; - *target=t; - if(offsets!=NULL) { - *pOffsets=offsets; - } - *err=U_BUFFER_OVERFLOW_ERROR; - return TRUE; - } - - /* copy the overflow contents to the target */ - *t++=overflow[i++]; - if(offsets!=NULL) { - *offsets++=-1; /* no source index available for old output */ - } - } - - /* the overflow buffer is completely copied to the target */ - cnv->UCharErrorBufferLength=0; - *target=t; - if(offsets!=NULL) { - *pOffsets=offsets; - } - return FALSE; -} - -U_CAPI void U_EXPORT2 -ucnv_toUnicode(UConverter *cnv, - UChar **target, const UChar *targetLimit, - const char **source, const char *sourceLimit, - int32_t *offsets, - UBool flush, - UErrorCode *err) { - UConverterToUnicodeArgs args; - const char *s; - UChar *t; - - /* check parameters */ - if(err==NULL || U_FAILURE(*err)) { - return; - } - - if(cnv==NULL || target==NULL || source==NULL) { - *err=U_ILLEGAL_ARGUMENT_ERROR; - return; - } - - s=*source; - t=*target; - - if ((const void *)U_MAX_PTR(targetLimit) == (const void *)targetLimit) { - /* - Prevent code from going into an infinite loop in case we do hit this - limit. The limit pointer is expected to be on a UChar * boundary. - This also prevents the next argument check from failing. - */ - targetLimit = (const UChar *)(((const char *)targetLimit) - 1); - } - - /* - * All these conditions should never happen. - * - * 1) Make sure that the limits are >= to the address source or target - * - * 2) Make sure that the buffer sizes do not exceed the number range for - * int32_t because some functions use the size (in units or bytes) - * rather than comparing pointers, and because offsets are int32_t values. - * - * size_t is guaranteed to be unsigned and large enough for the job. - * - * Return with an error instead of adjusting the limits because we would - * not be able to maintain the semantics that either the source must be - * consumed or the target filled (unless an error occurs). - * An adjustment would be sourceLimit=t+0x7fffffff; for example. - * - * 3) Make sure that the user didn't incorrectly cast a UChar * pointer - * to a char * pointer and provide an incomplete UChar code unit. - */ - if (sourceLimit<s || targetLimit<t || - ((size_t)(sourceLimit-s)>(size_t)0x7fffffff && sourceLimit>s) || - ((size_t)(targetLimit-t)>(size_t)0x3fffffff && targetLimit>t) || - (((const char *)targetLimit-(const char *)t) & 1) != 0 - ) { - *err=U_ILLEGAL_ARGUMENT_ERROR; - return; - } - - /* output the target overflow buffer */ - if( cnv->UCharErrorBufferLength>0 && - ucnv_outputOverflowToUnicode(cnv, target, targetLimit, &offsets, err) - ) { - /* U_BUFFER_OVERFLOW_ERROR */ - return; - } - /* *target may have moved, therefore stop using t */ - - if(!flush && s==sourceLimit && cnv->preToULength>=0) { - /* the overflow buffer is emptied and there is no new input: we are done */ - return; - } - - /* - * Do not simply return with a buffer overflow error if - * !flush && t==targetLimit - * because it is possible that the source will not generate any output. - * For example, the skip callback may be called; - * it does not output anything. - */ - - /* prepare the converter arguments */ - args.converter=cnv; - args.flush=flush; - args.offsets=offsets; - args.source=s; - args.sourceLimit=sourceLimit; - args.target=*target; - args.targetLimit=targetLimit; - args.size=sizeof(args); - - _toUnicodeWithCallback(&args, err); - - *source=args.source; - *target=args.target; -} - -/* ucnv_to/fromUChars() ----------------------------------------------------- */ - -U_CAPI int32_t U_EXPORT2 -ucnv_fromUChars(UConverter *cnv, - char *dest, int32_t destCapacity, - const UChar *src, int32_t srcLength, - UErrorCode *pErrorCode) { - const UChar *srcLimit; - char *originalDest, *destLimit; - int32_t destLength; - - /* check arguments */ - if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { - return 0; - } - - if( cnv==NULL || - destCapacity<0 || (destCapacity>0 && dest==NULL) || - srcLength<-1 || (srcLength!=0 && src==NULL) - ) { - *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; - return 0; - } - - /* initialize */ - ucnv_resetFromUnicode(cnv); - originalDest=dest; - if(srcLength==-1) { - srcLength=u_strlen(src); - } - if(srcLength>0) { - srcLimit=src+srcLength; - destCapacity=pinCapacity(dest, destCapacity); - destLimit=dest+destCapacity; - - /* perform the conversion */ - ucnv_fromUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, TRUE, pErrorCode); - destLength=(int32_t)(dest-originalDest); - - /* if an overflow occurs, then get the preflighting length */ - if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) { - char buffer[1024]; - - destLimit=buffer+sizeof(buffer); - do { - dest=buffer; - *pErrorCode=U_ZERO_ERROR; - ucnv_fromUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, TRUE, pErrorCode); - destLength+=(int32_t)(dest-buffer); - } while(*pErrorCode==U_BUFFER_OVERFLOW_ERROR); - } - } else { - destLength=0; - } - - return u_terminateChars(originalDest, destCapacity, destLength, pErrorCode); -} - -U_CAPI int32_t U_EXPORT2 -ucnv_toUChars(UConverter *cnv, - UChar *dest, int32_t destCapacity, - const char *src, int32_t srcLength, - UErrorCode *pErrorCode) { - const char *srcLimit; - UChar *originalDest, *destLimit; - int32_t destLength; - - /* check arguments */ - if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { - return 0; - } - - if( cnv==NULL || - destCapacity<0 || (destCapacity>0 && dest==NULL) || - srcLength<-1 || (srcLength!=0 && src==NULL)) - { - *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; - return 0; - } - - /* initialize */ - ucnv_resetToUnicode(cnv); - originalDest=dest; - if(srcLength==-1) { - srcLength=(int32_t)uprv_strlen(src); - } - if(srcLength>0) { - srcLimit=src+srcLength; - destCapacity=pinCapacity(dest, destCapacity); - destLimit=dest+destCapacity; - - /* perform the conversion */ - ucnv_toUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, TRUE, pErrorCode); - destLength=(int32_t)(dest-originalDest); - - /* if an overflow occurs, then get the preflighting length */ - if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) - { - UChar buffer[1024]; - - destLimit=buffer+UPRV_LENGTHOF(buffer); - do { - dest=buffer; - *pErrorCode=U_ZERO_ERROR; - ucnv_toUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, TRUE, pErrorCode); - destLength+=(int32_t)(dest-buffer); - } - while(*pErrorCode==U_BUFFER_OVERFLOW_ERROR); - } - } else { - destLength=0; - } - - return u_terminateUChars(originalDest, destCapacity, destLength, pErrorCode); -} - -/* ucnv_getNextUChar() ------------------------------------------------------ */ - -U_CAPI UChar32 U_EXPORT2 -ucnv_getNextUChar(UConverter *cnv, - const char **source, const char *sourceLimit, - UErrorCode *err) { - UConverterToUnicodeArgs args; - UChar buffer[U16_MAX_LENGTH]; - const char *s; - UChar32 c; - int32_t i, length; - - /* check parameters */ - if(err==NULL || U_FAILURE(*err)) { - return 0xffff; - } - - if(cnv==NULL || source==NULL) { - *err=U_ILLEGAL_ARGUMENT_ERROR; - return 0xffff; - } - - s=*source; - if(sourceLimit<s) { - *err=U_ILLEGAL_ARGUMENT_ERROR; - return 0xffff; - } - - /* - * Make sure that the buffer sizes do not exceed the number range for - * int32_t because some functions use the size (in units or bytes) - * rather than comparing pointers, and because offsets are int32_t values. - * - * size_t is guaranteed to be unsigned and large enough for the job. - * - * Return with an error instead of adjusting the limits because we would - * not be able to maintain the semantics that either the source must be - * consumed or the target filled (unless an error occurs). - * An adjustment would be sourceLimit=t+0x7fffffff; for example. - */ - if(((size_t)(sourceLimit-s)>(size_t)0x7fffffff && sourceLimit>s)) { - *err=U_ILLEGAL_ARGUMENT_ERROR; - return 0xffff; - } - - c=U_SENTINEL; - - /* flush the target overflow buffer */ - if(cnv->UCharErrorBufferLength>0) { - UChar *overflow; - - overflow=cnv->UCharErrorBuffer; - i=0; - length=cnv->UCharErrorBufferLength; - U16_NEXT(overflow, i, length, c); - - /* move the remaining overflow contents up to the beginning */ - if((cnv->UCharErrorBufferLength=(int8_t)(length-i))>0) { - uprv_memmove(cnv->UCharErrorBuffer, cnv->UCharErrorBuffer+i, - cnv->UCharErrorBufferLength*U_SIZEOF_UCHAR); - } - - if(!U16_IS_LEAD(c) || i<length) { - return c; - } - /* - * Continue if the overflow buffer contained only a lead surrogate, - * in case the converter outputs single surrogates from complete - * input sequences. - */ - } - - /* - * flush==TRUE is implied for ucnv_getNextUChar() - * - * do not simply return even if s==sourceLimit because the converter may - * not have seen flush==TRUE before - */ - - /* prepare the converter arguments */ - args.converter=cnv; - args.flush=TRUE; - args.offsets=NULL; - args.source=s; - args.sourceLimit=sourceLimit; - args.target=buffer; - args.targetLimit=buffer+1; - args.size=sizeof(args); - - if(c<0) { - /* - * call the native getNextUChar() implementation if we are - * at a character boundary (toULength==0) - * - * unlike with _toUnicode(), getNextUChar() implementations must set - * U_TRUNCATED_CHAR_FOUND for truncated input, - * in addition to setting toULength/toUBytes[] - */ - if(cnv->toULength==0 && cnv->sharedData->impl->getNextUChar!=NULL) { - c=cnv->sharedData->impl->getNextUChar(&args, err); - *source=s=args.source; - if(*err==U_INDEX_OUTOFBOUNDS_ERROR) { - /* reset the converter without calling the callback function */ - _reset(cnv, UCNV_RESET_TO_UNICODE, FALSE); - return 0xffff; /* no output */ - } else if(U_SUCCESS(*err) && c>=0) { - return c; - /* - * else fall through to use _toUnicode() because - * UCNV_GET_NEXT_UCHAR_USE_TO_U: the native function did not want to handle it after all - * U_FAILURE: call _toUnicode() for callback handling (do not output c) - */ - } - } - - /* convert to one UChar in buffer[0], or handle getNextUChar() errors */ - _toUnicodeWithCallback(&args, err); - - if(*err==U_BUFFER_OVERFLOW_ERROR) { - *err=U_ZERO_ERROR; - } - - i=0; - length=(int32_t)(args.target-buffer); - } else { - /* write the lead surrogate from the overflow buffer */ - buffer[0]=(UChar)c; - args.target=buffer+1; - i=0; - length=1; - } - - /* buffer contents starts at i and ends before length */ - - if(U_FAILURE(*err)) { - c=0xffff; /* no output */ - } else if(length==0) { - /* no input or only state changes */ - *err=U_INDEX_OUTOFBOUNDS_ERROR; - /* no need to reset explicitly because _toUnicodeWithCallback() did it */ - c=0xffff; /* no output */ - } else { - c=buffer[0]; - i=1; - if(!U16_IS_LEAD(c)) { - /* consume c=buffer[0], done */ - } else { - /* got a lead surrogate, see if a trail surrogate follows */ - UChar c2; - - if(cnv->UCharErrorBufferLength>0) { - /* got overflow output from the conversion */ - if(U16_IS_TRAIL(c2=cnv->UCharErrorBuffer[0])) { - /* got a trail surrogate, too */ - c=U16_GET_SUPPLEMENTARY(c, c2); - - /* move the remaining overflow contents up to the beginning */ - if((--cnv->UCharErrorBufferLength)>0) { - uprv_memmove(cnv->UCharErrorBuffer, cnv->UCharErrorBuffer+1, - cnv->UCharErrorBufferLength*U_SIZEOF_UCHAR); - } - } else { - /* c is an unpaired lead surrogate, just return it */ - } - } else if(args.source<sourceLimit) { - /* convert once more, to buffer[1] */ - args.targetLimit=buffer+2; - _toUnicodeWithCallback(&args, err); - if(*err==U_BUFFER_OVERFLOW_ERROR) { - *err=U_ZERO_ERROR; - } - - length=(int32_t)(args.target-buffer); - if(U_SUCCESS(*err) && length==2 && U16_IS_TRAIL(c2=buffer[1])) { - /* got a trail surrogate, too */ - c=U16_GET_SUPPLEMENTARY(c, c2); - i=2; - } - } - } - } - - /* - * move leftover output from buffer[i..length[ - * into the beginning of the overflow buffer - */ - if(i<length) { - /* move further overflow back */ - int32_t delta=length-i; - if((length=cnv->UCharErrorBufferLength)>0) { - uprv_memmove(cnv->UCharErrorBuffer+delta, cnv->UCharErrorBuffer, - length*U_SIZEOF_UCHAR); - } - cnv->UCharErrorBufferLength=(int8_t)(length+delta); - - cnv->UCharErrorBuffer[0]=buffer[i++]; - if(delta>1) { - cnv->UCharErrorBuffer[1]=buffer[i]; - } - } - - *source=args.source; - return c; -} - -/* ucnv_convert() and siblings ---------------------------------------------- */ - -U_CAPI void U_EXPORT2 -ucnv_convertEx(UConverter *targetCnv, UConverter *sourceCnv, - char **target, const char *targetLimit, - const char **source, const char *sourceLimit, - UChar *pivotStart, UChar **pivotSource, - UChar **pivotTarget, const UChar *pivotLimit, - UBool reset, UBool flush, - UErrorCode *pErrorCode) { - UChar pivotBuffer[CHUNK_SIZE]; - const UChar *myPivotSource; - UChar *myPivotTarget; - const char *s; - char *t; - - UConverterToUnicodeArgs toUArgs; - UConverterFromUnicodeArgs fromUArgs; - UConverterConvert convert; - - /* error checking */ - if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { - return; - } - - if( targetCnv==NULL || sourceCnv==NULL || - source==NULL || *source==NULL || - target==NULL || *target==NULL || targetLimit==NULL - ) { - *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; - return; - } - - s=*source; - t=*target; - if((sourceLimit!=NULL && sourceLimit<s) || targetLimit<t) { - *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; - return; - } - - /* - * Make sure that the buffer sizes do not exceed the number range for - * int32_t. See ucnv_toUnicode() for a more detailed comment. - */ - if( - (sourceLimit!=NULL && ((size_t)(sourceLimit-s)>(size_t)0x7fffffff && sourceLimit>s)) || - ((size_t)(targetLimit-t)>(size_t)0x7fffffff && targetLimit>t) - ) { - *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; - return; - } - - if(pivotStart==NULL) { - if(!flush) { - /* streaming conversion requires an explicit pivot buffer */ - *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; - return; - } - - /* use the stack pivot buffer */ - myPivotSource=myPivotTarget=pivotStart=pivotBuffer; - pivotSource=(UChar **)&myPivotSource; - pivotTarget=&myPivotTarget; - pivotLimit=pivotBuffer+CHUNK_SIZE; - } else if( pivotStart>=pivotLimit || - pivotSource==NULL || *pivotSource==NULL || - pivotTarget==NULL || *pivotTarget==NULL || - pivotLimit==NULL - ) { - *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; - return; - } - - if(sourceLimit==NULL) { - /* get limit of single-byte-NUL-terminated source string */ - sourceLimit=uprv_strchr(*source, 0); - } - - if(reset) { - ucnv_resetToUnicode(sourceCnv); - ucnv_resetFromUnicode(targetCnv); - *pivotSource=*pivotTarget=pivotStart; - } else if(targetCnv->charErrorBufferLength>0) { - /* output the targetCnv overflow buffer */ - if(ucnv_outputOverflowFromUnicode(targetCnv, target, targetLimit, NULL, pErrorCode)) { - /* U_BUFFER_OVERFLOW_ERROR */ - return; - } - /* *target has moved, therefore stop using t */ - - if( !flush && - targetCnv->preFromULength>=0 && *pivotSource==*pivotTarget && - sourceCnv->UCharErrorBufferLength==0 && sourceCnv->preToULength>=0 && s==sourceLimit - ) { - /* the fromUnicode overflow buffer is emptied and there is no new input: we are done */ - return; - } - } - - /* Is direct-UTF-8 conversion available? */ - if( sourceCnv->sharedData->staticData->conversionType==UCNV_UTF8 && - targetCnv->sharedData->impl->fromUTF8!=NULL - ) { - convert=targetCnv->sharedData->impl->fromUTF8; - } else if( targetCnv->sharedData->staticData->conversionType==UCNV_UTF8 && - sourceCnv->sharedData->impl->toUTF8!=NULL - ) { - convert=sourceCnv->sharedData->impl->toUTF8; - } else { - convert=NULL; - } - - /* - * If direct-UTF-8 conversion is available, then we use a smaller - * pivot buffer for error handling and partial matches - * so that we quickly return to direct conversion. - * - * 32 is large enough for UCNV_EXT_MAX_UCHARS and UCNV_ERROR_BUFFER_LENGTH. - * - * We could reduce the pivot buffer size further, at the cost of - * buffer overflows from callbacks. - * The pivot buffer should not be smaller than the maximum number of - * fromUnicode extension table input UChars - * (for m:n conversion, see - * targetCnv->sharedData->mbcs.extIndexes[UCNV_EXT_COUNT_UCHARS]) - * or 2 for surrogate pairs. - * - * Too small a buffer can cause thrashing between pivoting and direct - * conversion, with function call overhead outweighing the benefits - * of direct conversion. - */ - if(convert!=NULL && (pivotLimit-pivotStart)>32) { - pivotLimit=pivotStart+32; - } - - /* prepare the converter arguments */ - fromUArgs.converter=targetCnv; - fromUArgs.flush=FALSE; - fromUArgs.offsets=NULL; - fromUArgs.target=*target; - fromUArgs.targetLimit=targetLimit; - fromUArgs.size=sizeof(fromUArgs); - - toUArgs.converter=sourceCnv; - toUArgs.flush=flush; - toUArgs.offsets=NULL; - toUArgs.source=s; - toUArgs.sourceLimit=sourceLimit; - toUArgs.targetLimit=pivotLimit; - toUArgs.size=sizeof(toUArgs); - - /* - * TODO: Consider separating this function into two functions, - * extracting exactly the conversion loop, - * for readability and to reduce the set of visible variables. - * - * Otherwise stop using s and t from here on. - */ - s=t=NULL; - - /* - * conversion loop - * - * The sequence of steps in the loop may appear backward, - * but the principle is simple: - * In the chain of - * source - sourceCnv overflow - pivot - targetCnv overflow - target - * empty out later buffers before refilling them from earlier ones. - * - * The targetCnv overflow buffer is flushed out only once before the loop. - */ - for(;;) { - /* - * if(pivot not empty or error or replay or flush fromUnicode) { - * fromUnicode(pivot -> target); - * } - * - * For pivoting conversion; and for direct conversion for - * error callback handling and flushing the replay buffer. - */ - if( *pivotSource<*pivotTarget || - U_FAILURE(*pErrorCode) || - targetCnv->preFromULength<0 || - fromUArgs.flush - ) { - fromUArgs.source=*pivotSource; - fromUArgs.sourceLimit=*pivotTarget; - _fromUnicodeWithCallback(&fromUArgs, pErrorCode); - if(U_FAILURE(*pErrorCode)) { - /* target overflow, or conversion error */ - *pivotSource=(UChar *)fromUArgs.source; - break; - } - - /* - * _fromUnicodeWithCallback() must have consumed the pivot contents - * (*pivotSource==*pivotTarget) since it returned with U_SUCCESS() - */ - } - - /* The pivot buffer is empty; reset it so we start at pivotStart. */ - *pivotSource=*pivotTarget=pivotStart; - - /* - * if(sourceCnv overflow buffer not empty) { - * move(sourceCnv overflow buffer -> pivot); - * continue; - * } - */ - /* output the sourceCnv overflow buffer */ - if(sourceCnv->UCharErrorBufferLength>0) { - if(ucnv_outputOverflowToUnicode(sourceCnv, pivotTarget, pivotLimit, NULL, pErrorCode)) { - /* U_BUFFER_OVERFLOW_ERROR */ - *pErrorCode=U_ZERO_ERROR; - } - continue; - } - - /* - * check for end of input and break if done - * - * Checking both flush and fromUArgs.flush ensures that the converters - * have been called with the flush flag set if the ucnv_convertEx() - * caller set it. - */ - if( toUArgs.source==sourceLimit && - sourceCnv->preToULength>=0 && sourceCnv->toULength==0 && - (!flush || fromUArgs.flush) - ) { - /* done successfully */ - break; - } - - /* - * use direct conversion if available - * but not if continuing a partial match - * or flushing the toUnicode replay buffer - */ - if(convert!=NULL && targetCnv->preFromUFirstCP<0 && sourceCnv->preToULength==0) { - if(*pErrorCode==U_USING_DEFAULT_WARNING) { - /* remove a warning that may be set by this function */ - *pErrorCode=U_ZERO_ERROR; - } - convert(&fromUArgs, &toUArgs, pErrorCode); - if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) { - break; - } else if(U_FAILURE(*pErrorCode)) { - if(sourceCnv->toULength>0) { - /* - * Fall through to calling _toUnicodeWithCallback() - * for callback handling. - * - * The pivot buffer will be reset with - * *pivotSource=*pivotTarget=pivotStart; - * which indicates a toUnicode error to the caller - * (*pivotSource==pivotStart shows no pivot UChars consumed). - */ - } else { - /* - * Indicate a fromUnicode error to the caller - * (*pivotSource>pivotStart shows some pivot UChars consumed). - */ - *pivotSource=*pivotTarget=pivotStart+1; - /* - * Loop around to calling _fromUnicodeWithCallbacks() - * for callback handling. - */ - continue; - } - } else if(*pErrorCode==U_USING_DEFAULT_WARNING) { - /* - * No error, but the implementation requested to temporarily - * fall back to pivoting. - */ - *pErrorCode=U_ZERO_ERROR; - /* - * The following else branches are almost identical to the end-of-input - * handling in _toUnicodeWithCallback(). - * Avoid calling it just for the end of input. - */ - } else if(flush && sourceCnv->toULength>0) { /* flush==toUArgs.flush */ - /* - * the entire input stream is consumed - * and there is a partial, truncated input sequence left - */ - - /* inject an error and continue with callback handling */ - *pErrorCode=U_TRUNCATED_CHAR_FOUND; - } else { - /* input consumed */ - if(flush) { - /* reset the converters without calling the callback functions */ - _reset(sourceCnv, UCNV_RESET_TO_UNICODE, FALSE); - _reset(targetCnv, UCNV_RESET_FROM_UNICODE, FALSE); - } - - /* done successfully */ - break; - } - } - - /* - * toUnicode(source -> pivot); - * - * For pivoting conversion; and for direct conversion for - * error callback handling, continuing partial matches - * and flushing the replay buffer. - * - * The pivot buffer is empty and reset. - */ - toUArgs.target=pivotStart; /* ==*pivotTarget */ - /* toUArgs.targetLimit=pivotLimit; already set before the loop */ - _toUnicodeWithCallback(&toUArgs, pErrorCode); - *pivotTarget=toUArgs.target; - if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) { - /* pivot overflow: continue with the conversion loop */ - *pErrorCode=U_ZERO_ERROR; - } else if(U_FAILURE(*pErrorCode) || (!flush && *pivotTarget==pivotStart)) { - /* conversion error, or there was nothing left to convert */ - break; - } - /* - * else: - * _toUnicodeWithCallback() wrote into the pivot buffer, - * continue with fromUnicode conversion. - * - * Set the fromUnicode flush flag if we flush and if toUnicode has - * processed the end of the input. - */ - if( flush && toUArgs.source==sourceLimit && - sourceCnv->preToULength>=0 && - sourceCnv->UCharErrorBufferLength==0 - ) { - fromUArgs.flush=TRUE; - } - } - - /* - * The conversion loop is exited when one of the following is true: - * - the entire source text has been converted successfully to the target buffer - * - a target buffer overflow occurred - * - a conversion error occurred - */ - - *source=toUArgs.source; - *target=fromUArgs.target; - - /* terminate the target buffer if possible */ - if(flush && U_SUCCESS(*pErrorCode)) { - if(*target!=targetLimit) { - **target=0; - if(*pErrorCode==U_STRING_NOT_TERMINATED_WARNING) { - *pErrorCode=U_ZERO_ERROR; - } - } else { - *pErrorCode=U_STRING_NOT_TERMINATED_WARNING; - } - } -} - -/* internal implementation of ucnv_convert() etc. with preflighting */ -static int32_t -ucnv_internalConvert(UConverter *outConverter, UConverter *inConverter, - char *target, int32_t targetCapacity, - const char *source, int32_t sourceLength, - UErrorCode *pErrorCode) { - UChar pivotBuffer[CHUNK_SIZE]; - UChar *pivot, *pivot2; - - char *myTarget; - const char *sourceLimit; - const char *targetLimit; - int32_t targetLength=0; - - /* set up */ - if(sourceLength<0) { - sourceLimit=uprv_strchr(source, 0); - } else { - sourceLimit=source+sourceLength; - } - - /* if there is no input data, we're done */ - if(source==sourceLimit) { - return u_terminateChars(target, targetCapacity, 0, pErrorCode); - } - - pivot=pivot2=pivotBuffer; - myTarget=target; - targetLength=0; - - if(targetCapacity>0) { - /* perform real conversion */ - targetLimit=target+targetCapacity; - ucnv_convertEx(outConverter, inConverter, - &myTarget, targetLimit, - &source, sourceLimit, - pivotBuffer, &pivot, &pivot2, pivotBuffer+CHUNK_SIZE, - FALSE, - TRUE, - pErrorCode); - targetLength=(int32_t)(myTarget-target); - } - - /* - * If the output buffer is exhausted (or we are only "preflighting"), we need to stop writing - * to it but continue the conversion in order to store in targetCapacity - * the number of bytes that was required. - */ - if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR || targetCapacity==0) - { - char targetBuffer[CHUNK_SIZE]; - - targetLimit=targetBuffer+CHUNK_SIZE; - do { - *pErrorCode=U_ZERO_ERROR; - myTarget=targetBuffer; - ucnv_convertEx(outConverter, inConverter, - &myTarget, targetLimit, - &source, sourceLimit, - pivotBuffer, &pivot, &pivot2, pivotBuffer+CHUNK_SIZE, - FALSE, - TRUE, - pErrorCode); - targetLength+=(int32_t)(myTarget-targetBuffer); - } while(*pErrorCode==U_BUFFER_OVERFLOW_ERROR); - - /* done with preflighting, set warnings and errors as appropriate */ - return u_terminateChars(target, targetCapacity, targetLength, pErrorCode); - } - - /* no need to call u_terminateChars() because ucnv_convertEx() took care of that */ - return targetLength; -} - -U_CAPI int32_t U_EXPORT2 -ucnv_convert(const char *toConverterName, const char *fromConverterName, - char *target, int32_t targetCapacity, - const char *source, int32_t sourceLength, - UErrorCode *pErrorCode) { - UConverter in, out; /* stack-allocated */ - UConverter *inConverter, *outConverter; - int32_t targetLength; - - if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { - return 0; - } - - if( source==NULL || sourceLength<-1 || - targetCapacity<0 || (targetCapacity>0 && target==NULL) - ) { - *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; - return 0; - } - - /* if there is no input data, we're done */ - if(sourceLength==0 || (sourceLength<0 && *source==0)) { - return u_terminateChars(target, targetCapacity, 0, pErrorCode); - } - - /* create the converters */ - inConverter=ucnv_createConverter(&in, fromConverterName, pErrorCode); - if(U_FAILURE(*pErrorCode)) { - return 0; - } - - outConverter=ucnv_createConverter(&out, toConverterName, pErrorCode); - if(U_FAILURE(*pErrorCode)) { - ucnv_close(inConverter); - return 0; - } - - targetLength=ucnv_internalConvert(outConverter, inConverter, - target, targetCapacity, - source, sourceLength, - pErrorCode); - - ucnv_close(inConverter); - ucnv_close(outConverter); - - return targetLength; -} - -/* @internal */ -static int32_t -ucnv_convertAlgorithmic(UBool convertToAlgorithmic, - UConverterType algorithmicType, - UConverter *cnv, - char *target, int32_t targetCapacity, - const char *source, int32_t sourceLength, - UErrorCode *pErrorCode) { - UConverter algoConverterStatic; /* stack-allocated */ - UConverter *algoConverter, *to, *from; - int32_t targetLength; - - if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { - return 0; - } - - if( cnv==NULL || source==NULL || sourceLength<-1 || - targetCapacity<0 || (targetCapacity>0 && target==NULL) - ) { - *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; - return 0; - } - - /* if there is no input data, we're done */ - if(sourceLength==0 || (sourceLength<0 && *source==0)) { - return u_terminateChars(target, targetCapacity, 0, pErrorCode); - } - - /* create the algorithmic converter */ - algoConverter=ucnv_createAlgorithmicConverter(&algoConverterStatic, algorithmicType, - "", 0, pErrorCode); - if(U_FAILURE(*pErrorCode)) { - return 0; - } - - /* reset the other converter */ - if(convertToAlgorithmic) { - /* cnv->Unicode->algo */ - ucnv_resetToUnicode(cnv); - to=algoConverter; - from=cnv; - } else { - /* algo->Unicode->cnv */ - ucnv_resetFromUnicode(cnv); - from=algoConverter; - to=cnv; - } - - targetLength=ucnv_internalConvert(to, from, - target, targetCapacity, - source, sourceLength, - pErrorCode); - - ucnv_close(algoConverter); - - return targetLength; -} - -U_CAPI int32_t U_EXPORT2 -ucnv_toAlgorithmic(UConverterType algorithmicType, - UConverter *cnv, - char *target, int32_t targetCapacity, - const char *source, int32_t sourceLength, - UErrorCode *pErrorCode) { - return ucnv_convertAlgorithmic(TRUE, algorithmicType, cnv, - target, targetCapacity, - source, sourceLength, - pErrorCode); -} - -U_CAPI int32_t U_EXPORT2 -ucnv_fromAlgorithmic(UConverter *cnv, - UConverterType algorithmicType, - char *target, int32_t targetCapacity, - const char *source, int32_t sourceLength, - UErrorCode *pErrorCode) { - return ucnv_convertAlgorithmic(FALSE, algorithmicType, cnv, - target, targetCapacity, - source, sourceLength, - pErrorCode); -} - -U_CAPI UConverterType U_EXPORT2 -ucnv_getType(const UConverter* converter) -{ - int8_t type = converter->sharedData->staticData->conversionType; -#if !UCONFIG_NO_LEGACY_CONVERSION - if(type == UCNV_MBCS) { - return ucnv_MBCSGetType(converter); - } -#endif - return (UConverterType)type; -} - -U_CAPI void U_EXPORT2 -ucnv_getStarters(const UConverter* converter, - UBool starters[256], - UErrorCode* err) -{ - if (err == NULL || U_FAILURE(*err)) { - return; - } - - if(converter->sharedData->impl->getStarters != NULL) { - converter->sharedData->impl->getStarters(converter, starters, err); - } else { - *err = U_ILLEGAL_ARGUMENT_ERROR; - } -} - -static const UAmbiguousConverter *ucnv_getAmbiguous(const UConverter *cnv) -{ - UErrorCode errorCode; - const char *name; - int32_t i; - - if(cnv==NULL) { - return NULL; - } - - errorCode=U_ZERO_ERROR; - name=ucnv_getName(cnv, &errorCode); - if(U_FAILURE(errorCode)) { - return NULL; - } - - for(i=0; i<UPRV_LENGTHOF(ambiguousConverters); ++i) - { - if(0==uprv_strcmp(name, ambiguousConverters[i].name)) - { - return ambiguousConverters+i; - } - } - - return NULL; -} - -U_CAPI void U_EXPORT2 -ucnv_fixFileSeparator(const UConverter *cnv, - UChar* source, - int32_t sourceLength) { - const UAmbiguousConverter *a; - int32_t i; - UChar variant5c; - - if(cnv==NULL || source==NULL || sourceLength<=0 || (a=ucnv_getAmbiguous(cnv))==NULL) - { - return; - } - - variant5c=a->variant5c; - for(i=0; i<sourceLength; ++i) { - if(source[i]==variant5c) { - source[i]=0x5c; - } - } -} - -U_CAPI UBool U_EXPORT2 -ucnv_isAmbiguous(const UConverter *cnv) { - return (UBool)(ucnv_getAmbiguous(cnv)!=NULL); -} - -U_CAPI void U_EXPORT2 -ucnv_setFallback(UConverter *cnv, UBool usesFallback) -{ - cnv->useFallback = usesFallback; -} - -U_CAPI UBool U_EXPORT2 -ucnv_usesFallback(const UConverter *cnv) -{ - return cnv->useFallback; -} - -U_CAPI void U_EXPORT2 -ucnv_getInvalidChars (const UConverter * converter, - char *errBytes, - int8_t * len, - UErrorCode * err) -{ - if (err == NULL || U_FAILURE(*err)) - { - return; - } - if (len == NULL || errBytes == NULL || converter == NULL) - { - *err = U_ILLEGAL_ARGUMENT_ERROR; - return; - } - if (*len < converter->invalidCharLength) - { - *err = U_INDEX_OUTOFBOUNDS_ERROR; - return; - } - if ((*len = converter->invalidCharLength) > 0) - { - uprv_memcpy (errBytes, converter->invalidCharBuffer, *len); - } -} - -U_CAPI void U_EXPORT2 -ucnv_getInvalidUChars (const UConverter * converter, - UChar *errChars, - int8_t * len, - UErrorCode * err) -{ - if (err == NULL || U_FAILURE(*err)) - { - return; - } - if (len == NULL || errChars == NULL || converter == NULL) - { - *err = U_ILLEGAL_ARGUMENT_ERROR; - return; - } - if (*len < converter->invalidUCharLength) - { - *err = U_INDEX_OUTOFBOUNDS_ERROR; - return; - } - if ((*len = converter->invalidUCharLength) > 0) - { - u_memcpy (errChars, converter->invalidUCharBuffer, *len); - } -} - -#define SIG_MAX_LEN 5 - -U_CAPI const char* U_EXPORT2 -ucnv_detectUnicodeSignature( const char* source, - int32_t sourceLength, - int32_t* signatureLength, - UErrorCode* pErrorCode) { - int32_t dummy; - - /* initial 0xa5 bytes: make sure that if we read <SIG_MAX_LEN - * bytes we don't misdetect something - */ - char start[SIG_MAX_LEN]={ '\xa5', '\xa5', '\xa5', '\xa5', '\xa5' }; - int i = 0; - - if((pErrorCode==NULL) || U_FAILURE(*pErrorCode)){ - return NULL; - } - - if(source == NULL || sourceLength < -1){ - *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR; - return NULL; - } - - if(signatureLength == NULL) { - signatureLength = &dummy; - } - - if(sourceLength==-1){ - sourceLength=(int32_t)uprv_strlen(source); - } - - - while(i<sourceLength&& i<SIG_MAX_LEN){ - start[i]=source[i]; - i++; - } - - if(start[0] == '\xFE' && start[1] == '\xFF') { - *signatureLength=2; - return "UTF-16BE"; - } else if(start[0] == '\xFF' && start[1] == '\xFE') { - if(start[2] == '\x00' && start[3] =='\x00') { - *signatureLength=4; - return "UTF-32LE"; - } else { - *signatureLength=2; - return "UTF-16LE"; - } - } else if(start[0] == '\xEF' && start[1] == '\xBB' && start[2] == '\xBF') { - *signatureLength=3; - return "UTF-8"; - } else if(start[0] == '\x00' && start[1] == '\x00' && - start[2] == '\xFE' && start[3]=='\xFF') { - *signatureLength=4; - return "UTF-32BE"; - } else if(start[0] == '\x0E' && start[1] == '\xFE' && start[2] == '\xFF') { - *signatureLength=3; - return "SCSU"; - } else if(start[0] == '\xFB' && start[1] == '\xEE' && start[2] == '\x28') { - *signatureLength=3; - return "BOCU-1"; - } else if(start[0] == '\x2B' && start[1] == '\x2F' && start[2] == '\x76') { - /* - * UTF-7: Initial U+FEFF is encoded as +/v8 or +/v9 or +/v+ or +/v/ - * depending on the second UTF-16 code unit. - * Detect the entire, closed Unicode mode sequence +/v8- for only U+FEFF - * if it occurs. - * - * So far we have +/v - */ - if(start[3] == '\x38' && start[4] == '\x2D') { - /* 5 bytes +/v8- */ - *signatureLength=5; - return "UTF-7"; - } else if(start[3] == '\x38' || start[3] == '\x39' || start[3] == '\x2B' || start[3] == '\x2F') { - /* 4 bytes +/v8 or +/v9 or +/v+ or +/v/ */ - *signatureLength=4; - return "UTF-7"; - } - }else if(start[0]=='\xDD' && start[1]== '\x73'&& start[2]=='\x66' && start[3]=='\x73'){ - *signatureLength=4; - return "UTF-EBCDIC"; - } - - - /* no known Unicode signature byte sequence recognized */ - *signatureLength=0; - return NULL; -} - -U_CAPI 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->preFromUFirstCP >= 0){ - return U16_LENGTH(cnv->preFromUFirstCP)+cnv->preFromULength ; - }else if(cnv->preFromULength < 0){ - return -cnv->preFromULength ; - }else if(cnv->fromUChar32 > 0){ - return 1; - } - return 0; - -} - -U_CAPI 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; -} - -U_CAPI UBool U_EXPORT2 -ucnv_isFixedWidth(UConverter *cnv, UErrorCode *status){ - if (U_FAILURE(*status)) { - return FALSE; - } - - if (cnv == NULL) { - *status = U_ILLEGAL_ARGUMENT_ERROR; - return FALSE; - } - - switch (ucnv_getType(cnv)) { - case UCNV_SBCS: - case UCNV_DBCS: - case UCNV_UTF32_BigEndian: - case UCNV_UTF32_LittleEndian: - case UCNV_UTF32: - case UCNV_US_ASCII: - return TRUE; - default: - return FALSE; - } -} -#endif - -/* - * Hey, Emacs, please set the following: - * - * Local Variables: - * indent-tabs-mode: nil - * End: - * - */ |