/* ****************************************************************************** * * Copyright (C) 1998-2001, 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" #include "unicode/ustring.h" #include "unicode/ures.h" #include "unicode/ucnv.h" #include "unicode/ucnv_err.h" #include "cmemory.h" #include "cstring.h" #include "umutex.h" #include "uhash.h" #include "ustr_imp.h" #include "ucnv_imp.h" #include "ucnv_io.h" #include "ucnv_cnv.h" #include "ucnv_bld.h" #if 0 /* debugging for converters */ # include void UCNV_DEBUG_LOG(char *what, char *who, void *p, int l) { static FILE *f = NULL; if(f==NULL) { f = fopen("c:\\UCNV_DEBUG_LOG.txt", "w"); } fprintf(f, "%-20s %-10s %p@%d\n", who,what,p,l); fflush(f); } # define UCNV_DEBUG_LOG(x,y,z) UCNV_DEBUG_LOG(x,y,z,__LINE__) #else # define UCNV_DEBUG_LOG(x,y,z) #endif /* size of intermediate and preflighting buffers in ucnv_convert() */ #define CHUNK_SIZE 5*1024 typedef struct UAmbiguousConverter { const char *name; const UChar variant5c; } UAmbiguousConverter; static const UAmbiguousConverter ambiguousConverters[]={ { "ibm-942_P120-2000", 0xa5 }, { "ibm-943_P130-2000", 0xa5 }, { "ibm-33722_P120-2000", 0xa5 }, { "ibm-949_P110-2000", 0x20a9 }, { "ibm-1363_P110-2000", 0x20a9 }, { "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, UErrorCode * err) { if (err == NULL || U_FAILURE (*err)) { return NULL; } return ucnv_createConverter(name, err); } 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); } /*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(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; 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 }; if (status == NULL || U_FAILURE(*status)){ return 0; } if (!pBufferSize || !cnv){ *status = U_ILLEGAL_ARGUMENT_ERROR; return 0; } /* Pointers on 64-bit platforms need to be aligned * on a 64-bit boundry in memory. */ if (U_ALIGNMENT_OFFSET(stackBuffer) != 0) { int32_t offsetUp = (int32_t)U_ALIGNMENT_OFFSET_UP(stackBufferChars); *pBufferSize -= offsetUp; stackBufferChars += offsetUp; } stackBuffer = (void *)stackBufferChars; if (cnv->sharedData->impl->safeClone != NULL) { /* call the custom safeClone function for sizing */ bufferSizeNeeded = 0; cnv->sharedData->impl->safeClone(cnv, stackBuffer, &bufferSizeNeeded, status); } else { /* inherent sizing */ bufferSizeNeeded = sizeof(UConverter); } if (*pBufferSize <= 0){ /* 'preflighting' request - set needed size into *pBufferSize */ *pBufferSize = bufferSizeNeeded; return 0; } /* Now, see if we must allocate any memory */ if (*pBufferSize < bufferSizeNeeded || stackBuffer == NULL) { /* allocate one here...*/ localConverter = (UConverter *) uprv_malloc (bufferSizeNeeded); if(localConverter == NULL) { *status = U_MEMORY_ALLOCATION_ERROR; return NULL; } if (U_SUCCESS(*status)) { *status = U_SAFECLONE_ALLOCATED_ERROR; } /* record the fact that memory was allocated */ *pBufferSize = bufferSizeNeeded; } else { /* just use the stack buffer */ localConverter = (UConverter*) stackBuffer; } /* increment refcount of shared data if needed */ if (cnv->sharedData->referenceCounter != ~0) { umtx_lock (NULL); if (cnv->sharedData->referenceCounter != ~0) { cnv->sharedData->referenceCounter++; } umtx_unlock (NULL); } /* Copy initial state */ uprv_memcpy(localConverter, cnv, sizeof(UConverter)); /* 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 == (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); 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) { /* 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; if (converter == NULL) { return; } toUArgs.converter = fromUArgs.converter = converter; errorCode = U_ZERO_ERROR; 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); if (converter->sharedData->impl->close != NULL) { converter->sharedData->impl->close(converter); } #if 1 if(!converter->isCopyLocal) #endif if (converter->sharedData->referenceCounter != ~0) { umtx_lock (NULL); if (converter->sharedData->referenceCounter != 0) { converter->sharedData->referenceCounter--; } umtx_unlock (NULL); if((converter->sharedData->referenceCounter == 0)&&(converter->sharedData->sharedDataCached == FALSE)) { ucnv_deleteSharedConverterData(converter->sharedData); } } if(!converter->isCopyLocal){ uprv_free (converter); } return; } /*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_io_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_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); } U_CAPI void U_EXPORT2 ucnv_getSubstChars (const UConverter * converter, char *mySubChar, int8_t * len, UErrorCode * err) { if (U_FAILURE (*err)) 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 */ *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->subChar, 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 int32_t U_EXPORT2 ucnv_getDisplayName(const UConverter *cnv, const char *displayLocale, UChar *displayName, int32_t displayNameCapacity, UErrorCode *pErrorCode) { UResourceBundle *rb; const UChar *name; int32_t length; /* check arguments */ if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { return 0; } if(cnv==NULL || displayNameCapacity<0 || (displayNameCapacity>0 && displayName==NULL)) { *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; return 0; } /* open the resource bundle and get the display name string */ rb=ures_open(NULL, displayLocale, pErrorCode); if(U_FAILURE(*pErrorCode)) { return 0; } /* use the internal name as the key */ name=ures_getStringByKey(rb, cnv->sharedData->staticData->name, &length, pErrorCode); ures_close(rb); if(U_SUCCESS(*pErrorCode)) { /* copy the string */ u_memcpy(displayName, name, uprv_min(length, displayNameCapacity)*U_SIZEOF_UCHAR); } else { /* convert the internal name into a Unicode string */ *pErrorCode=U_ZERO_ERROR; length=uprv_strlen(cnv->sharedData->staticData->name); u_charsToUChars(cnv->sharedData->staticData->name, displayName, uprv_min(length, displayNameCapacity)); } return u_terminateUChars(displayName, displayNameCapacity, length, pErrorCode); } /*resets the internal states of a converter *goal : have the same behaviour than a freshly created converter */ static void _reset(UConverter *converter, UConverterResetChoice choice) { /* first, notify the callback functions that the converter is reset */ UConverterToUnicodeArgs toUArgs = { sizeof(UConverterToUnicodeArgs), TRUE, NULL, NULL, NULL, NULL, NULL, NULL }; UConverterFromUnicodeArgs fromUArgs = { sizeof(UConverterFromUnicodeArgs), TRUE, NULL, NULL, NULL, NULL, NULL, NULL }; UErrorCode errorCode; if(converter == NULL) { return; } toUArgs.converter = fromUArgs.converter = converter; if(choice<=UCNV_RESET_TO_UNICODE) { errorCode = U_ZERO_ERROR; converter->fromCharErrorBehaviour(converter->toUContext, &toUArgs, NULL, 0, UCNV_RESET, &errorCode); } if(choice!=UCNV_RESET_TO_UNICODE) { 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->toULength = 0; converter->invalidCharLength = converter->UCharErrorBufferLength = 0; } if(choice!=UCNV_RESET_TO_UNICODE) { converter->fromUnicodeStatus = 0; converter->fromUSurrogateLead = 0; converter->invalidUCharLength = converter->charErrorBufferLength = 0; } if (converter->sharedData->impl->reset != NULL) { /* call the custom reset function */ converter->sharedData->impl->reset(converter, choice); } else if(choice<=UCNV_RESET_TO_UNICODE) { converter->mode = UCNV_SI; } } U_CAPI void U_EXPORT2 ucnv_reset(UConverter *converter) { _reset(converter, UCNV_RESET_BOTH); } U_CAPI void U_EXPORT2 ucnv_resetToUnicode(UConverter *converter) { _reset(converter, UCNV_RESET_TO_UNICODE); } U_CAPI void U_EXPORT2 ucnv_resetFromUnicode(UConverter *converter) { _reset(converter, UCNV_RESET_FROM_UNICODE); } U_CAPI int8_t U_EXPORT2 ucnv_getMaxCharSize (const UConverter * converter) { return converter->sharedData->staticData->maxBytesPerChar; } 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) { if (U_FAILURE (*err)) return -1; return converter->sharedData->staticData->codepage; } 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; } U_CAPI void U_EXPORT2 ucnv_fromUnicode (UConverter * _this, char **target, const char *targetLimit, const UChar ** source, const UChar * sourceLimit, int32_t* offsets, UBool flush, UErrorCode * err) { UConverterFromUnicodeArgs args; const char *t; /* * Check parameters in for all conversions */ if (err == NULL || U_FAILURE (*err)) { return; } if (_this == NULL || target == NULL || source == NULL) { *err = U_ILLEGAL_ARGUMENT_ERROR; return; } t = *target; if (targetLimit < t || sourceLimit < *source) { *err = U_ILLEGAL_ARGUMENT_ERROR; return; } /* * Make sure that the target buffer size does not exceed the number range for int32_t * because some functions use the size rather than comparing pointers. * size_t is guaranteed to be unsigned. */ if((size_t)(targetLimit - t) > (size_t)0x7fffffff && targetLimit > t) { targetLimit = t + 0x7fffffff; } /* * Deal with stored carry over data. This is done in the common location * to avoid doing it for each conversion. */ if (_this->charErrorBufferLength > 0) { int32_t myTargetIndex = 0; ucnv_flushInternalCharBuffer (_this, (char *)t, &myTargetIndex, targetLimit - *target, offsets?&offsets:NULL, err); *target += myTargetIndex; if (U_FAILURE (*err)) return; } args.converter = _this; args.flush = flush; args.offsets = offsets; args.source = *source; args.sourceLimit = sourceLimit; args.target = *target; args.targetLimit = targetLimit; args.size = sizeof(args); if (offsets) { if (_this->sharedData->impl->fromUnicodeWithOffsets != NULL) { _this->sharedData->impl->fromUnicodeWithOffsets(&args, err); *source = args.source; *target = args.target; return; } else { /* there is no implementation that sets offsets, set them all to -1 */ int32_t i, targetSize = targetLimit - *target; for (i=0; isharedData->impl->fromUnicode(&args, err); *source = args.source; *target = args.target; } U_CAPI void U_EXPORT2 ucnv_toUnicode (UConverter * _this, UChar ** target, const UChar * targetLimit, const char **source, const char *sourceLimit, int32_t* offsets, UBool flush, UErrorCode * err) { UConverterToUnicodeArgs args; const UChar *t; /* * Check parameters in for all conversions */ if (err == NULL || U_FAILURE (*err)) { return; } if (_this == NULL || target == NULL || source == NULL) { *err = U_ILLEGAL_ARGUMENT_ERROR; return; } t = *target; if (targetLimit < t || sourceLimit < *source) { *err = U_ILLEGAL_ARGUMENT_ERROR; return; } /* * Make sure that the target buffer size does not exceed the number range for int32_t * because some functions use the size rather than comparing pointers. * size_t is guaranteed to be unsigned. */ if((size_t)(targetLimit - t) > (size_t)0x3fffffff && targetLimit > t) { targetLimit = t + 0x3fffffff; } /* * Deal with stored carry over data. This is done in the common location * to avoid doing it for each conversion. */ if (_this->UCharErrorBufferLength > 0) { int32_t myTargetIndex = 0; ucnv_flushInternalUnicodeBuffer (_this, (UChar *)t, &myTargetIndex, targetLimit - *target, offsets?&offsets:NULL, err); *target += myTargetIndex; if (U_FAILURE (*err)) return; } args.converter = _this; args.flush = flush; args.offsets = offsets; args.source = (char *) *source; args.sourceLimit = sourceLimit; args.target = *target; args.targetLimit = targetLimit; args.size = sizeof(args); if (offsets) { if (_this->sharedData->impl->toUnicodeWithOffsets != NULL) { _this->sharedData->impl->toUnicodeWithOffsets(&args, err); *source = args.source; *target = args.target; return; } else { /* there is no implementation that sets offsets, set them all to -1 */ int32_t i, targetSize = targetLimit - *target; for (i=0; isharedData->impl->toUnicode(&args, err); *source = args.source; *target = args.target; return; } 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; destLimit=dest+destCapacity; /* pin the destination limit to U_MAX_PTR; NULL check is for OS/400 */ if(destLimit0 && 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=uprv_strlen(src); } if(srcLength>0) { srcLimit=src+srcLength; destLimit=dest+destCapacity; /* pin the destination limit to U_MAX_PTR; NULL check is for OS/400 */ if(destLimitUCharErrorBufferLength > 0) { int32_t i = 0; UChar32 myUChar; UTF_NEXT_CHAR(converter->UCharErrorBuffer, i, sizeof(converter->UCharErrorBuffer), myUChar); /*In this memmove we update the internal buffer by *popping the first character. *Note that in the call itself we decrement *UCharErrorBufferLength */ uprv_memmove (converter->UCharErrorBuffer, converter->UCharErrorBuffer + i, (converter->UCharErrorBufferLength - i) * sizeof (UChar)); converter->UCharErrorBufferLength -= (int8_t)i; return myUChar; } /*calls the specific conversion routines */ /*as dictated in a code review, avoids a switch statement */ args.converter = converter; args.flush = TRUE; args.offsets = NULL; args.source = *source; args.sourceLimit = sourceLimit; args.target = NULL; args.targetLimit = NULL; args.size = sizeof(args); if (converter->sharedData->impl->getNextUChar != NULL) { ch = converter->sharedData->impl->getNextUChar(&args, err); } else { /* default implementation */ ch = ucnv_getNextUCharFromToUImpl(&args, converter->sharedData->impl->toUnicode, FALSE, err); } *source = args.source; return ch; } U_CAPI int32_t U_EXPORT2 ucnv_convert(const char *toConverterName, const char *fromConverterName, char *target, int32_t targetSize, const char *source, int32_t sourceSize, UErrorCode *pErrorCode) { UChar pivotBuffer[CHUNK_SIZE]; UChar *pivot, *pivot2; UConverter *inConverter, *outConverter; char *myTarget; const char *sourceLimit; const char *targetLimit; int32_t targetCapacity=0; if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { return 0; } if(sourceSize<0 || targetSize<0 || source==NULL || (targetSize>0 && target==NULL)) { *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; return 0; } /* if there is no input data, we're done */ if(sourceSize==0) { return 0; } /* create the converters */ inConverter=ucnv_open(fromConverterName, pErrorCode); if(U_FAILURE(*pErrorCode)) { return 0; } outConverter=ucnv_open(toConverterName, pErrorCode); if(U_FAILURE(*pErrorCode)) { ucnv_close(inConverter); return 0; } /* set up the other variables */ sourceLimit=source+sourceSize; pivot=pivot2=pivotBuffer; myTarget=target; targetCapacity=0; if(targetSize>0) { /* perform real conversion */ /* * loops until the input buffer is completely consumed * or an error is encountered; * first we convert from inConverter codepage to Unicode * then from Unicode to outConverter codepage */ targetLimit=target+targetSize; do { pivot=pivotBuffer; ucnv_toUnicode(inConverter, &pivot, pivotBuffer+CHUNK_SIZE, &source, sourceLimit, NULL, TRUE, pErrorCode); /* U_BUFFER_OVERFLOW_ERROR only means that the pivot buffer is full */ if(U_SUCCESS(*pErrorCode) || *pErrorCode==U_BUFFER_OVERFLOW_ERROR) { *pErrorCode=U_ZERO_ERROR; pivot2=pivotBuffer; ucnv_fromUnicode(outConverter, &myTarget, targetLimit, (const UChar **)&pivot2, pivot, NULL, (UBool)(source==sourceLimit), pErrorCode); /* * If this overflows the real target, then we must stop * converting and preflight with the loop below. */ } } while(U_SUCCESS(*pErrorCode) && source!=sourceLimit); targetCapacity=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 targetSize * the number of bytes that was required. */ if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR || targetSize==0) { char targetBuffer[CHUNK_SIZE]; targetLimit=targetBuffer+CHUNK_SIZE; do { /* since the pivot buffer may still contain some characters, start with emptying it */ *pErrorCode=U_ZERO_ERROR; while(pivot2!=pivot && U_SUCCESS(*pErrorCode)) { myTarget=targetBuffer; ucnv_fromUnicode(outConverter, &myTarget, targetLimit, (const UChar **)&pivot2, pivot, NULL, (UBool)(source==sourceLimit), pErrorCode); targetCapacity+=(myTarget-targetBuffer); if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) { *pErrorCode=U_ZERO_ERROR; } } if(U_FAILURE(*pErrorCode)) { /* an error occurred: done */ break; } if(source==sourceLimit) { /* * source is consumed: * done, and set the buffer overflow error as * the result for the entire function */ *pErrorCode=U_BUFFER_OVERFLOW_ERROR; break; } /* now convert from the source into the pivot buffer again */ pivot=pivot2=pivotBuffer; ucnv_toUnicode(inConverter, &pivot, pivotBuffer+CHUNK_SIZE, &source, sourceLimit, NULL, TRUE, pErrorCode); } while(U_SUCCESS(*pErrorCode) || *pErrorCode==U_BUFFER_OVERFLOW_ERROR); } ucnv_close (inConverter); ucnv_close (outConverter); return u_terminateChars(target, targetSize, targetCapacity, pErrorCode); } U_CAPI UConverterType U_EXPORT2 ucnv_getType(const UConverter* converter) { int8_t type = converter->sharedData->staticData->conversionType; if(type == UCNV_MBCS) { return _MBCSGetType(converter); } 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<(int32_t)(sizeof(ambiguousConverters)/sizeof(UAmbiguousConverter)); ++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; iuseFallback = 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) { uprv_memcpy (errChars, converter->invalidUCharBuffer, sizeof(UChar) * (*len)); } } #define SIG_MAX_LEN 4 U_CAPI const char* U_EXPORT2 ucnv_detectUnicodeSignature( const char* source, int32_t sourceLength, int32_t* signatureLength, UErrorCode* pErrorCode){ /* initial 0xa5 bytes: make sure that if we read <4 * bytes we don't misdetect something */ char start[SIG_MAX_LEN]={ '\xa5', '\xa5', '\xa5', '\xa5' }; int i = 0; if((pErrorCode==NULL) || U_FAILURE(*pErrorCode)){ return NULL; } if(source == NULL || signatureLength == NULL || sourceLength < -1){ *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR; return NULL; } if(sourceLength==-1){ sourceLength=uprv_strlen(source); } while(i