/* ******************************************************************************* * * Copyright (C) 1998-1999, 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 and maintained * 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 "umutex.h" #include "unicode/ures.h" #include "uhash.h" #include "ucmp16.h" #include "ucmp8.h" #include "ucnv_io.h" #include "unicode/ucnv_err.h" #include "ucnv_cnv.h" #include "ucnv_imp.h" #include "unicode/ucnv.h" #include "cmemory.h" #include "cstring.h" #include "unicode/ustring.h" #include "unicode/uloc.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 #define CHUNK_SIZE 5*1024 /* Internal function : begin */ static int32_t ucnv_getAmbiguousCCSID (const UConverter* cnv); /* Internal function : end */ static void T_UConverter_fromCodepageToCodepage (UConverter * outConverter, UConverter * inConverter, char **target, const char *targetLimit, const char **source, const char *sourceLimit, int32_t* offsets, UBool flush, UErrorCode * err); const char* ucnv_getDefaultName () { return ucnv_io_getDefaultConverterName(); } void ucnv_setDefaultName (const char *converterName) { ucnv_io_setDefaultConverterName(converterName); } /*Calls through createConverter */ UConverter* ucnv_open (const char *name, UErrorCode * err) { if (err == NULL || U_FAILURE (*err)) { return NULL; } return createConverter (name, err); } /*Extracts the UChar* to a char* and calls through createConverter */ UConverter* ucnv_openU (const UChar * name, UErrorCode * err) { char asciiName[UCNV_MAX_CONVERTER_NAME_LENGTH]; if (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*/ UConverter* ucnv_openCCSID (int32_t codepage, UConverterPlatform platform, UErrorCode * err) { char myName[UCNV_MAX_CONVERTER_NAME_LENGTH]; if (U_FAILURE (*err)) return NULL; copyPlatformString (myName, platform); uprv_strcat (myName, "-"); T_CString_integerToString (myName + uprv_strlen (myName), codepage, 10); return createConverter (myName, err); } /*Decreases the reference counter in the shared immutable section of the object *and frees the mutable part*/ void 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 (converter->sharedData->referenceCounter != ~0) { umtx_lock (NULL); if (converter->sharedData->referenceCounter != 0) { converter->sharedData->referenceCounter--; } umtx_unlock (NULL); } uprv_free (converter); return; } /*Frees all shared immutable objects that aren't referred to (reference count = 0) */ int32_t ucnv_flushCache () { UConverterSharedData *mySharedData = NULL; int32_t pos = -1; int32_t tableDeletedNum = 0; const UHashElement *e; /*if shared data hasn't even been lazy evaluated yet * return 0 */ if (SHARED_DATA_HASHTABLE == NULL) return 0; /*creates an enumeration to iterate through every element in the *table */ umtx_lock (NULL); while ((e = uhash_nextElement (SHARED_DATA_HASHTABLE, &pos)) != NULL) { mySharedData = (UConverterSharedData *) e->value; /*deletes only if reference counter == 0 */ if (mySharedData->referenceCounter == 0) { tableDeletedNum++; UCNV_DEBUG_LOG("del",mySharedData->staticData->name,mySharedData); uhash_removeElement(SHARED_DATA_HASHTABLE, e); deleteSharedConverterData (mySharedData); } } umtx_unlock (NULL); return tableDeletedNum; } /*returns a single Name from the list, will return NULL if out of bounds */ const char* 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; } int32_t ucnv_countAvailable () { UErrorCode err = U_ZERO_ERROR; return ucnv_io_countAvailableConverters(&err); } U_CAPI uint16_t ucnv_countAliases(const char *alias, UErrorCode *pErrorCode) { const char *p; return ucnv_io_getAliases(alias, &p, pErrorCode); } U_CAPI const char * ucnv_getAlias(const char *alias, uint16_t n, UErrorCode *pErrorCode) { return ucnv_io_getAlias(alias, n, pErrorCode); } U_CAPI void ucnv_getAliases(const char *alias, const char **aliases, UErrorCode *pErrorCode) { const char *p; uint16_t count=ucnv_io_getAliases(alias, &p, pErrorCode); while(count>0) { *aliases++=p; /* skip a name, first the canonical converter name */ p+=uprv_strlen(p)+1; --count; } } U_CAPI uint16_t ucnv_countStandards(void) { UErrorCode err = U_ZERO_ERROR; return ucnv_io_countStandards(&err); } void 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 */ return; } void 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 */ return; } int32_t ucnv_getDisplayName (const UConverter * converter, const char *displayLocale, UChar * displayName, int32_t displayNameCapacity, UErrorCode * err) { UChar stringToWriteBuffer[UCNV_MAX_CONVERTER_NAME_LENGTH]; UChar const *stringToWrite; int32_t stringToWriteLength; UResourceBundle *rb = NULL; if (U_FAILURE (*err)) return 0; /*create an RB, init the fill-in string, gets it from the RB */ rb = ures_open (NULL, displayLocale, err); stringToWrite = ures_getStringByKey(rb, converter->sharedData->staticData->name, &stringToWriteLength, err); if (rb) ures_close (rb); if(U_FAILURE(*err)) { /*Error While creating or getting resource from the resource bundle *use the internal name instead * *sets stringToWriteLength (which accounts for a NULL terminator) *and stringToWrite */ stringToWriteLength = uprv_strlen (converter->sharedData->staticData->name) + 1; stringToWrite = u_uastrcpy (stringToWriteBuffer, converter->sharedData->staticData->name); /*Hides the fallback to the internal name from the user */ if (*err == U_MISSING_RESOURCE_ERROR) *err = U_ZERO_ERROR; } /*At this point we have a displayName and its length *we want to see if it fits in the user provided params */ if (stringToWriteLength <= displayNameCapacity) { /*it fits */ u_strcpy (displayName, stringToWrite); } else { /*it doesn't fit */ *err = U_BUFFER_OVERFLOW_ERROR; u_strncpy (displayName, stringToWrite, displayNameCapacity); /*Zero terminates the string */ if (displayNameCapacity > 0) displayName[displayNameCapacity - 1] = 0x0000; } /*if the user provided us with a with an outputLength *buffer we'll store in it the theoretical size of the *displayString */ return stringToWriteLength; } /*resets the internal states of a converter *goal : have the same behaviour than a freshly created converter */ void ucnv_reset (UConverter * converter) { /* 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; errorCode = U_ZERO_ERROR; converter->fromCharErrorBehaviour(converter->toUContext, &toUArgs, NULL, 0, UCNV_RESET, &errorCode); errorCode = U_ZERO_ERROR; converter->fromUCharErrorBehaviour(converter->fromUContext, &fromUArgs, NULL, 0, 0, UCNV_RESET, &errorCode); /* now reset the converter itself */ converter->toUnicodeStatus = converter->sharedData->toUnicodeStatus; converter->fromUnicodeStatus = 0; converter->UCharErrorBufferLength = 0; converter->charErrorBufferLength = 0; if (converter->sharedData->impl->reset != NULL) { /* call the custom reset function */ converter->sharedData->impl->reset(converter); } else { converter->mode = UCNV_SI; } } void ucnv_resetToUnicode(UConverter *converter) { #if 0 UConverterToUnicodeArgs toUArgs = { sizeof(UConverterToUnicodeArgs), TRUE, NULL, NULL, NULL, NULL, NULL, NULL }; UErrorCode errorCode = U_ZERO_ERROR; if(converter == NULL) { return; } toUArgs.converter = converter; converter->fromCharErrorBehaviour(converter->toUContext, &toUArgs, NULL, 0, UCNV_RESET, &errorCode); /* now reset the converter itself */ converter->toUnicodeStatus = converter->sharedData->toUnicodeStatus; converter->fromUnicodeStatus = 0; converter->UCharErrorBufferLength = 0; converter->charErrorBufferLength = 0; /* Todo: Needs rest of implementation */ #endif } void ucnv_resetFromUnicode(UConverter *converter) { #if 0 UConverterFromUnicodeArgs fromUArgs = { sizeof(UConverterFromUnicodeArgs), TRUE, NULL, NULL, NULL, NULL, NULL, NULL }; UErrorCode errorCode = U_ZERO_ERROR; if(converter == NULL) { return; } fromUArgs.converter = converter; converter->fromUCharErrorBehaviour(converter->fromUContext, &fromUArgs, NULL, 0, 0, UCNV_RESET, &errorCode); /* now reset the converter itself */ converter->toUnicodeStatus = converter->sharedData->toUnicodeStatus; converter->fromUnicodeStatus = 0; converter->UCharErrorBufferLength = 0; converter->charErrorBufferLength = 0; /* Todo: Needs rest of implementation */ #endif } int8_t ucnv_getMaxCharSize (const UConverter * converter) { return converter->sharedData->staticData->maxBytesPerChar; } int8_t ucnv_getMinCharSize (const UConverter * converter) { return converter->sharedData->staticData->minBytesPerChar; } const char* 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; } int32_t ucnv_getCCSID (const UConverter * converter, UErrorCode * err) { if (U_FAILURE (*err)) return -1; return converter->sharedData->staticData->codepage; } UConverterPlatform 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, void **context) { *action = converter->fromCharErrorBehaviour; *context = converter->toUContext; } U_CAPI void U_EXPORT2 ucnv_getFromUCallBack (const UConverter * converter, UConverterFromUCallback *action, void **context) { *action = converter->fromUCharErrorBehaviour; *context = converter->fromUContext; } void ucnv_setToUCallBack (UConverter * converter, UConverterToUCallback newAction, void* newContext, UConverterToUCallback *oldAction, void** oldContext, UErrorCode * err) { if (U_FAILURE (*err)) return; *oldAction = converter->fromCharErrorBehaviour; converter->fromCharErrorBehaviour = newAction; *oldContext = converter->toUContext; converter->toUContext = newContext; } void ucnv_setFromUCallBack (UConverter * converter, UConverterFromUCallback newAction, void* newContext, UConverterFromUCallback *oldAction, void** oldContext, UErrorCode * err) { if (U_FAILURE (*err)) return; *oldAction = converter->fromUCharErrorBehaviour; converter->fromUCharErrorBehaviour = newAction; *oldContext = converter->fromUContext; converter->fromUContext = newContext; } void ucnv_fromUnicode (UConverter * _this, char **target, const char *targetLimit, const UChar ** source, const UChar * sourceLimit, int32_t* offsets, UBool flush, UErrorCode * err) { UConverterFromUnicodeArgs args; /* * Check parameters in for all conversions */ if (U_FAILURE (*err)) return; if ((_this == NULL) || ((char *) targetLimit < *target) || (sourceLimit < *source)) { *err = U_ILLEGAL_ARGUMENT_ERROR; return; } /* * 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; flushInternalCharBuffer (_this, (char *) *target, &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 { /* all code points are of the same length */ int32_t targetSize = targetLimit - *target; int32_t i, bytesPerChar = _this->sharedData->staticData->maxBytesPerChar; if(bytesPerChar == 1) { for (i=0; i>1; } } else { int32_t j = 0, k = bytesPerChar; for (i=0; isharedData->impl->fromUnicode(&args, err); *source = args.source; *target = args.target; return; } void ucnv_toUnicode (UConverter * _this, UChar ** target, const UChar * targetLimit, const char **source, const char *sourceLimit, int32_t* offsets, UBool flush, UErrorCode * err) { UConverterToUnicodeArgs args; /* * Check parameters in for all conversions */ if (U_FAILURE (*err)) return; if ((_this == NULL) || ((UChar *) targetLimit < *target) || (sourceLimit < *source)) { *err = U_ILLEGAL_ARGUMENT_ERROR; return; } /* * 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; flushInternalUnicodeBuffer (_this, *target, &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 { /* all code points are of the same length */ int32_t targetSize = targetLimit - *target; int32_t i, bytesPerChar = _this->sharedData->staticData->maxBytesPerChar; if(bytesPerChar == 1) { for (i=0; isharedData->impl->toUnicode(&args, err); *source = args.source; *target = args.target; return; } int32_t ucnv_fromUChars (const UConverter * converter, char *target, int32_t targetSize, const UChar * source, int32_t sourceSize, UErrorCode * err) { const UChar *mySource_limit; int32_t mySourceLength = sourceSize; UConverter myConverter; char *myTarget_limit; int32_t targetCapacity = 0; UConverterFromUnicodeArgs args; if (U_FAILURE (*err)) return 0; if ((converter == NULL) || (targetSize < 0)) { *err = U_ILLEGAL_ARGUMENT_ERROR; return 0; } /*makes a local copy of the UConverter */ myConverter = *converter; /*Removes all state info on the UConverter */ ucnv_reset (&myConverter); /*if the source is empty we return immediately */ if (sourceSize == -1) { mySourceLength = u_strlen (source); } if (mySourceLength == 0) { /*for consistency we still need to *store 0 in the targetCapacity *if the user requires it */ return 0; } mySource_limit = source + mySourceLength; myTarget_limit = target + targetSize; /* Pin the limit to U_MAX_PTR. NULL check is for AS/400. */ if((myTarget_limit < target) || ( (myTarget_limit == NULL) && (target != NULL))) { myTarget_limit = (char *)U_MAX_PTR; } args.converter = &myConverter; args.flush = TRUE; args.offsets = NULL; args.source = source; args.sourceLimit = mySource_limit; args.target = target; args.targetLimit = myTarget_limit; args.size = sizeof(args); if (targetSize > 0) { /*calls the specific conversion routines */ args.converter->sharedData->impl->fromUnicode(&args, err); targetCapacity = args.target - target; } /*Updates targetCapacity to contain the number of bytes written to target */ /* If the output buffer is exhausted, 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 (*err == U_BUFFER_OVERFLOW_ERROR || targetSize == 0) { char target2[CHUNK_SIZE]; const char *target2_limit = target2 + CHUNK_SIZE; /*We use a stack allocated buffer around which we loop *(in case the output is greater than CHUNK_SIZE) */ do { *err = U_ZERO_ERROR; args.target = target2; args.targetLimit = target2_limit; args.converter->sharedData->impl->fromUnicode(&args, err); /*updates the output parameter to contain the number of char required */ targetCapacity += (args.target - target2); } while (*err == U_BUFFER_OVERFLOW_ERROR); /*We will set the error code to U_BUFFER_OVERFLOW_ERROR only if *nothing graver happened in the previous loop*/ if (U_SUCCESS (*err)) *err = U_BUFFER_OVERFLOW_ERROR; } return targetCapacity; } int32_t ucnv_toUChars (const UConverter * converter, UChar * target, int32_t targetSize, const char *source, int32_t sourceSize, UErrorCode * err) { const char *mySource_limit = source + sourceSize; UConverter myConverter; UChar *myTarget_limit; int32_t targetCapacity; UConverterToUnicodeArgs args; if (U_FAILURE (*err)) return 0; if ((converter == NULL) || (targetSize < 0) || (sourceSize < 0)) { *err = U_ILLEGAL_ARGUMENT_ERROR; return 0; } /*Means there is no work to be done */ if (sourceSize == 0) { /*for consistency we still need to *store 0 in the targetCapacity *if the user requires it */ if (targetSize >= 1) { target[0] = 0x0000; return 1; } else return 0; } /*makes a local copy of the UConverter */ myConverter = *converter; /*Removes all state info on the UConverter */ ucnv_reset (&myConverter); args.converter = &myConverter; args.flush = TRUE; args.offsets = NULL; args.source = source; args.sourceLimit = mySource_limit; args.target = target; args.size = sizeof(args); if (targetSize > 0) { myTarget_limit = target + targetSize - 1; /* Pin the limit to U_MAX_PTR. NULL check is for AS/400. */ if ((myTarget_limit == NULL) || (myTarget_limit < target)) { myTarget_limit = ((UChar*)U_MAX_PTR) - 1; } /*Not in pure pre-flight mode */ args.targetLimit = myTarget_limit; args.converter->sharedData->impl->toUnicode(&args, err); /*Null terminates the string */ *(args.target) = 0x0000; } /*Rigs targetCapacity to have at least one cell for zero termination */ /*Updates targetCapacity to contain the number of bytes written to target */ targetCapacity = 1; targetCapacity += args.target - target; /* If the output buffer is exhausted, we need to stop writing * to it but if the input buffer is not exhausted, * we need to continue the conversion in order to store in targetSize * the number of bytes that was required */ if (*err == U_BUFFER_OVERFLOW_ERROR || targetSize == 0) { UChar target2[CHUNK_SIZE]; const UChar *target2_limit = target2 + CHUNK_SIZE; /*We use a stack allocated buffer around which we loop (in case the output is greater than CHUNK_SIZE) */ do { *err = U_ZERO_ERROR; args.target = target2; args.targetLimit = target2_limit; args.converter->sharedData->impl->toUnicode(&args, err); /*updates the output parameter to contain the number of char required */ targetCapacity += args.target - target2; } while (*err == U_BUFFER_OVERFLOW_ERROR); if (U_SUCCESS (*err)) *err = U_BUFFER_OVERFLOW_ERROR; } return targetCapacity; } UChar32 ucnv_getNextUChar(UConverter * converter, const char **source, const char *sourceLimit, UErrorCode * err) { UConverterToUnicodeArgs args; UChar32 ch; if(err == NULL || U_FAILURE(*err)) { return 0xffff; } /* In case internal data had been stored * we return the first UChar32 in the internal buffer, * and update the internal state accordingly */ if (converter->UCharErrorBufferLength > 0) { UTextOffset 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; } /************************** * Will convert a sequence of bytes from one codepage to another. * @param toConverterName: The name of the converter that will be used to encode the output buffer * @param fromConverterName: The name of the converter that will be used to decode the input buffer * @param target: Pointer to the output buffer* written * @param targetLength: on input contains the capacity of target, on output the number of bytes copied to target * @param source: Pointer to the input buffer * @param sourceLength: on input contains the capacity of source, on output the number of bytes processed in "source" * @param internal: used internally to store store state data across calls * @param err: fills in an error status */ static void T_UConverter_fromCodepageToCodepage (UConverter * outConverter, UConverter * inConverter, char **target, const char *targetLimit, const char **source, const char *sourceLimit, int32_t* offsets, UBool flush, UErrorCode * err) { UChar out_chunk[CHUNK_SIZE]; const UChar *out_chunk_limit = out_chunk + CHUNK_SIZE; UChar *out_chunk_alias; UChar const *out_chunk_alias2; if (U_FAILURE (*err)) return; /*loops until the input buffer is completely consumed *or if an error has be encountered *first we convert from inConverter codepage to Unicode *then from Unicode to outConverter codepage */ while ((*source != sourceLimit) && U_SUCCESS (*err)) { out_chunk_alias = out_chunk; ucnv_toUnicode (inConverter, &out_chunk_alias, out_chunk_limit, source, sourceLimit, NULL, flush, err); /*U_BUFFER_OVERFLOW_ERROR means that the output "CHUNK" is full *we will require at least another loop (it's a recoverable error) */ if (U_SUCCESS (*err) || (*err == U_BUFFER_OVERFLOW_ERROR)) { *err = U_ZERO_ERROR; out_chunk_alias2 = out_chunk; while ((out_chunk_alias2 != out_chunk_alias) && U_SUCCESS (*err)) { ucnv_fromUnicode (outConverter, target, targetLimit, &out_chunk_alias2, out_chunk_alias, NULL, TRUE, err); } } else break; } return; } int32_t ucnv_convert(const char *toConverterName, const char *fromConverterName, char *target, int32_t targetSize, const char *source, int32_t sourceSize, UErrorCode * err) { const char *mySource = source; const char *mySource_limit = source + sourceSize; UConverter *inConverter; UConverter *outConverter; char *myTarget = target; int32_t targetCapacity = 0; if (U_FAILURE (*err)) return 0; if ((targetSize < 0) || (sourceSize < 0)) { *err = U_ILLEGAL_ARGUMENT_ERROR; return 0; } /*if there is no input data, we're done */ if (sourceSize == 0) { /*in case the caller passed an output ptr *we update it */ return 0; } /*create the converters */ inConverter = ucnv_open (fromConverterName, err); if (U_FAILURE (*err)) return 0; outConverter = ucnv_open (toConverterName, err); if (U_FAILURE (*err)) { ucnv_close (inConverter); return 0; } if (targetSize > 0) { T_UConverter_fromCodepageToCodepage (outConverter, inConverter, &myTarget, target + targetSize, &mySource, mySource_limit, NULL, TRUE, err); /*Updates targetCapacity to contain the number of bytes written to target */ targetCapacity = myTarget - target; } /* If the output buffer is exhausted (or we are "pre-flighting"), 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 (*err == U_BUFFER_OVERFLOW_ERROR || targetSize == 0) { char target2[CHUNK_SIZE]; char *target2_alias = target2; const char *target2_limit = target2 + CHUNK_SIZE; /*We use a stack allocated buffer around which we loop *(in case the output is greater than CHUNK_SIZE) */ do { *err = U_ZERO_ERROR; target2_alias = target2; T_UConverter_fromCodepageToCodepage (outConverter, inConverter, &target2_alias, target2_limit, &mySource, mySource_limit, NULL, TRUE, err); /*updates the output parameter to contain the number of char required */ targetCapacity += (target2_alias - target2); } while (*err == U_BUFFER_OVERFLOW_ERROR); /*We will set the error code to U_BUFFER_OVERFLOW_ERROR only if *nothing graver happened in the previous loop*/ if (U_SUCCESS (*err)) *err = U_BUFFER_OVERFLOW_ERROR; } ucnv_close (inConverter); ucnv_close (outConverter); return targetCapacity; } UConverterType ucnv_getType(const UConverter* converter) { return (UConverterType)converter->sharedData->staticData->conversionType; } void 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 int32_t ucnv_getAmbiguousCCSID(const UConverter *cnv) { UErrorCode status = U_ZERO_ERROR; int32_t i = 0; int32_t ccsid = 0; if (cnv == NULL) { return -1; } ccsid = ucnv_getCCSID(cnv, &status); if (U_FAILURE(status)) { return -1; } for (i = 0; i < UCNV_MAX_AMBIGUOUSCCSIDS; i++) { if (ccsid == UCNV_AMBIGUOUSCONVERTERS[i].ccsid) { return i; } } return -1; } void ucnv_fixFileSeparator(const UConverter *cnv, UChar* source, int32_t sourceLength) { int32_t i = 0; int32_t offset = 0; if ((source == NULL) || (cnv == NULL)) { return; } if ((offset = ucnv_getAmbiguousCCSID(cnv)) != -1) { for (i = 0; i < sourceLength; i++) { if (source[i] == UCNV_AMBIGUOUSCONVERTERS[offset].mismapped) { source[i] = UCNV_AMBIGUOUSCONVERTERS[offset].replacement; } } } } UBool ucnv_isAmbiguous(const UConverter *cnv) { return (UBool)(ucnv_getAmbiguousCCSID(cnv) == -1 ? FALSE : TRUE); } void ucnv_setFallback(UConverter *cnv, UBool usesFallback) { cnv->useFallback = usesFallback; } UBool ucnv_usesFallback(const UConverter *cnv) { return cnv->useFallback; } void 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); } } void 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)); } } /* * Hey, Emacs, please set the following: * * Local Variables: * indent-tabs-mode: nil * End: * */