1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 ******************************************************************************
6 * Copyright (C) 1998-2016, International Business Machines
7 * Corporation and others. All Rights Reserved.
9 ******************************************************************************
12 * Implements APIs for the ICU's codeset conversion library;
13 * mostly calls through internal functions;
14 * created by Bertrand A. Damiba
16 * Modification History:
18 * Date Name Description
19 * 04/04/99 helena Fixed internal header inclusion.
20 * 05/09/00 helena Added implementation to handle fallback mappings.
21 * 06/20/2000 helena OS/400 port changes; mostly typecast.
24 #include "unicode/utypes.h"
26 #if !UCONFIG_NO_CONVERSION
28 #include "unicode/ustring.h"
29 #include "unicode/ucnv.h"
30 #include "unicode/ucnv_err.h"
31 #include "unicode/uset.h"
32 #include "unicode/utf.h"
33 #include "unicode/utf16.h"
44 /* size of intermediate and preflighting buffers in ucnv_convert() */
45 #define CHUNK_SIZE 1024
47 typedef struct UAmbiguousConverter {
49 const UChar variant5c;
50 } UAmbiguousConverter;
52 static const UAmbiguousConverter ambiguousConverters[]={
53 { "ibm-897_P100-1995", 0xa5 },
54 { "ibm-942_P120-1999", 0xa5 },
55 { "ibm-943_P130-1999", 0xa5 },
56 { "ibm-946_P100-1995", 0xa5 },
57 { "ibm-33722_P120-1999", 0xa5 },
58 { "ibm-1041_P100-1995", 0xa5 },
59 /*{ "ibm-54191_P100-2006", 0xa5 },*/
60 /*{ "ibm-62383_P100-2007", 0xa5 },*/
61 /*{ "ibm-891_P100-1995", 0x20a9 },*/
62 { "ibm-944_P100-1995", 0x20a9 },
63 { "ibm-949_P110-1999", 0x20a9 },
64 { "ibm-1363_P110-1997", 0x20a9 },
65 { "ISO_2022,locale=ko,version=0", 0x20a9 },
66 { "ibm-1088_P100-1995", 0x20a9 }
69 /*Calls through createConverter */
70 U_CAPI UConverter* U_EXPORT2
71 ucnv_open (const char *name,
76 if (err == NULL || U_FAILURE (*err)) {
80 r = ucnv_createConverter(NULL, name, err);
84 U_CAPI UConverter* U_EXPORT2
85 ucnv_openPackage (const char *packageName, const char *converterName, UErrorCode * err)
87 return ucnv_createConverterFromPackage(packageName, converterName, err);
90 /*Extracts the UChar* to a char* and calls through createConverter */
91 U_CAPI UConverter* U_EXPORT2
92 ucnv_openU (const UChar * name,
95 char asciiName[UCNV_MAX_CONVERTER_NAME_LENGTH];
97 if (err == NULL || U_FAILURE(*err))
100 return ucnv_open (NULL, err);
101 if (u_strlen(name) >= UCNV_MAX_CONVERTER_NAME_LENGTH)
103 *err = U_ILLEGAL_ARGUMENT_ERROR;
106 return ucnv_open(u_austrcpy(asciiName, name), err);
109 /* Copy the string that is represented by the UConverterPlatform enum
110 * @param platformString An output buffer
111 * @param platform An enum representing a platform
112 * @return the length of the copied string.
115 ucnv_copyPlatformString(char *platformString, UConverterPlatform pltfrm)
120 uprv_strcpy(platformString, "ibm-");
126 /* default to empty string */
131 /*Assumes a $platform-#codepage.$CONVERTER_FILE_EXTENSION scheme and calls
132 *through createConverter*/
133 U_CAPI UConverter* U_EXPORT2
134 ucnv_openCCSID (int32_t codepage,
135 UConverterPlatform platform,
138 char myName[UCNV_MAX_CONVERTER_NAME_LENGTH];
141 if (err == NULL || U_FAILURE (*err))
144 /* ucnv_copyPlatformString could return "ibm-" or "cp" */
145 myNameLen = ucnv_copyPlatformString(myName, platform);
146 T_CString_integerToString(myName + myNameLen, codepage, 10);
148 return ucnv_createConverter(NULL, myName, err);
151 /* Creating a temporary stack-based object that can be used in one thread,
152 and created from a converter that is shared across threads.
155 U_CAPI UConverter* U_EXPORT2
156 ucnv_safeClone(const UConverter* cnv, void *stackBuffer, int32_t *pBufferSize, UErrorCode *status)
158 UConverter *localConverter, *allocatedConverter;
159 int32_t stackBufferSize;
160 int32_t bufferSizeNeeded;
161 char *stackBufferChars = (char *)stackBuffer;
163 UConverterToUnicodeArgs toUArgs = {
164 sizeof(UConverterToUnicodeArgs),
173 UConverterFromUnicodeArgs fromUArgs = {
174 sizeof(UConverterFromUnicodeArgs),
184 UTRACE_ENTRY_OC(UTRACE_UCNV_CLONE);
186 if (status == NULL || U_FAILURE(*status)){
187 UTRACE_EXIT_STATUS(status? *status: U_ILLEGAL_ARGUMENT_ERROR);
192 *status = U_ILLEGAL_ARGUMENT_ERROR;
193 UTRACE_EXIT_STATUS(*status);
197 UTRACE_DATA3(UTRACE_OPEN_CLOSE, "clone converter %s at %p into stackBuffer %p",
198 ucnv_getName(cnv, status), cnv, stackBuffer);
200 if (cnv->sharedData->impl->safeClone != NULL) {
201 /* call the custom safeClone function for sizing */
202 bufferSizeNeeded = 0;
203 cnv->sharedData->impl->safeClone(cnv, NULL, &bufferSizeNeeded, status);
204 if (U_FAILURE(*status)) {
205 UTRACE_EXIT_STATUS(*status);
211 /* inherent sizing */
212 bufferSizeNeeded = sizeof(UConverter);
215 if (pBufferSize == NULL) {
217 pBufferSize = &stackBufferSize;
219 stackBufferSize = *pBufferSize;
220 if (stackBufferSize <= 0){ /* 'preflighting' request - set needed size into *pBufferSize */
221 *pBufferSize = bufferSizeNeeded;
222 UTRACE_EXIT_VALUE(bufferSizeNeeded);
228 /* Pointers on 64-bit platforms need to be aligned
229 * on a 64-bit boundary in memory.
231 if (U_ALIGNMENT_OFFSET(stackBuffer) != 0) {
232 int32_t offsetUp = (int32_t)U_ALIGNMENT_OFFSET_UP(stackBufferChars);
233 if(stackBufferSize > offsetUp) {
234 stackBufferSize -= offsetUp;
235 stackBufferChars += offsetUp;
237 /* prevent using the stack buffer but keep the size > 0 so that we do not just preflight */
242 stackBuffer = (void *)stackBufferChars;
244 /* Now, see if we must allocate any memory */
245 if (stackBufferSize < bufferSizeNeeded || stackBuffer == NULL)
247 /* allocate one here...*/
248 localConverter = allocatedConverter = (UConverter *) uprv_malloc (bufferSizeNeeded);
250 if(localConverter == NULL) {
251 *status = U_MEMORY_ALLOCATION_ERROR;
252 UTRACE_EXIT_STATUS(*status);
255 *status = U_SAFECLONE_ALLOCATED_WARNING;
257 /* record the fact that memory was allocated */
258 *pBufferSize = bufferSizeNeeded;
260 /* just use the stack buffer */
261 localConverter = (UConverter*) stackBuffer;
262 allocatedConverter = NULL;
265 uprv_memset(localConverter, 0, bufferSizeNeeded);
267 /* Copy initial state */
268 uprv_memcpy(localConverter, cnv, sizeof(UConverter));
269 localConverter->isCopyLocal = localConverter->isExtraLocal = FALSE;
271 /* copy the substitution string */
272 if (cnv->subChars == (uint8_t *)cnv->subUChars) {
273 localConverter->subChars = (uint8_t *)localConverter->subUChars;
275 localConverter->subChars = (uint8_t *)uprv_malloc(UCNV_ERROR_BUFFER_LENGTH * U_SIZEOF_UCHAR);
276 if (localConverter->subChars == NULL) {
277 uprv_free(allocatedConverter);
278 UTRACE_EXIT_STATUS(*status);
281 uprv_memcpy(localConverter->subChars, cnv->subChars, UCNV_ERROR_BUFFER_LENGTH * U_SIZEOF_UCHAR);
284 /* now either call the safeclone fcn or not */
285 if (cnv->sharedData->impl->safeClone != NULL) {
286 /* call the custom safeClone function */
287 localConverter = cnv->sharedData->impl->safeClone(cnv, localConverter, pBufferSize, status);
290 if(localConverter==NULL || U_FAILURE(*status)) {
291 if (allocatedConverter != NULL && allocatedConverter->subChars != (uint8_t *)allocatedConverter->subUChars) {
292 uprv_free(allocatedConverter->subChars);
294 uprv_free(allocatedConverter);
295 UTRACE_EXIT_STATUS(*status);
299 /* increment refcount of shared data if needed */
300 if (cnv->sharedData->isReferenceCounted) {
301 ucnv_incrementRefCount(cnv->sharedData);
304 if(localConverter == (UConverter*)stackBuffer) {
305 /* we're using user provided data - set to not destroy */
306 localConverter->isCopyLocal = TRUE;
309 /* allow callback functions to handle any memory allocation */
310 toUArgs.converter = fromUArgs.converter = localConverter;
311 cbErr = U_ZERO_ERROR;
312 cnv->fromCharErrorBehaviour(cnv->toUContext, &toUArgs, NULL, 0, UCNV_CLONE, &cbErr);
313 cbErr = U_ZERO_ERROR;
314 cnv->fromUCharErrorBehaviour(cnv->fromUContext, &fromUArgs, NULL, 0, 0, UCNV_CLONE, &cbErr);
316 UTRACE_EXIT_PTR_STATUS(localConverter, *status);
317 return localConverter;
322 /*Decreases the reference counter in the shared immutable section of the object
323 *and frees the mutable part*/
325 U_CAPI void U_EXPORT2
326 ucnv_close (UConverter * converter)
328 UErrorCode errorCode = U_ZERO_ERROR;
330 UTRACE_ENTRY_OC(UTRACE_UCNV_CLOSE);
332 if (converter == NULL)
338 UTRACE_DATA3(UTRACE_OPEN_CLOSE, "close converter %s at %p, isCopyLocal=%b",
339 ucnv_getName(converter, &errorCode), converter, converter->isCopyLocal);
341 /* In order to speed up the close, only call the callbacks when they have been changed.
342 This performance check will only work when the callbacks are set within a shared library
343 or from user code that statically links this code. */
344 /* first, notify the callback functions that the converter is closed */
345 if (converter->fromCharErrorBehaviour != UCNV_TO_U_DEFAULT_CALLBACK) {
346 UConverterToUnicodeArgs toUArgs = {
347 sizeof(UConverterToUnicodeArgs),
357 toUArgs.converter = converter;
358 errorCode = U_ZERO_ERROR;
359 converter->fromCharErrorBehaviour(converter->toUContext, &toUArgs, NULL, 0, UCNV_CLOSE, &errorCode);
361 if (converter->fromUCharErrorBehaviour != UCNV_FROM_U_DEFAULT_CALLBACK) {
362 UConverterFromUnicodeArgs fromUArgs = {
363 sizeof(UConverterFromUnicodeArgs),
372 fromUArgs.converter = converter;
373 errorCode = U_ZERO_ERROR;
374 converter->fromUCharErrorBehaviour(converter->fromUContext, &fromUArgs, NULL, 0, 0, UCNV_CLOSE, &errorCode);
377 if (converter->sharedData->impl->close != NULL) {
378 converter->sharedData->impl->close(converter);
381 if (converter->subChars != (uint8_t *)converter->subUChars) {
382 uprv_free(converter->subChars);
385 if (converter->sharedData->isReferenceCounted) {
386 ucnv_unloadSharedDataIfReady(converter->sharedData);
389 if(!converter->isCopyLocal){
390 uprv_free(converter);
396 /*returns a single Name from the list, will return NULL if out of bounds
398 U_CAPI const char* U_EXPORT2
399 ucnv_getAvailableName (int32_t n)
401 if (0 <= n && n <= 0xffff) {
402 UErrorCode err = U_ZERO_ERROR;
403 const char *name = ucnv_bld_getAvailableConverter((uint16_t)n, &err);
404 if (U_SUCCESS(err)) {
411 U_CAPI int32_t U_EXPORT2
412 ucnv_countAvailable ()
414 UErrorCode err = U_ZERO_ERROR;
415 return ucnv_bld_countAvailableConverters(&err);
418 U_CAPI void U_EXPORT2
419 ucnv_getSubstChars (const UConverter * converter,
424 if (U_FAILURE (*err))
427 if (converter->subCharLen <= 0) {
428 /* Unicode string or empty string from ucnv_setSubstString(). */
433 if (*len < converter->subCharLen) /*not enough space in subChars */
435 *err = U_INDEX_OUTOFBOUNDS_ERROR;
439 uprv_memcpy (mySubChar, converter->subChars, converter->subCharLen); /*fills in the subchars */
440 *len = converter->subCharLen; /*store # of bytes copied to buffer */
443 U_CAPI void U_EXPORT2
444 ucnv_setSubstChars (UConverter * converter,
445 const char *mySubChar,
449 if (U_FAILURE (*err))
452 /*Makes sure that the subChar is within the codepages char length boundaries */
453 if ((len > converter->sharedData->staticData->maxBytesPerChar)
454 || (len < converter->sharedData->staticData->minBytesPerChar))
456 *err = U_ILLEGAL_ARGUMENT_ERROR;
460 uprv_memcpy (converter->subChars, mySubChar, len); /*copies the subchars */
461 converter->subCharLen = len; /*sets the new len */
464 * There is currently (2001Feb) no separate API to set/get subChar1.
465 * In order to always have subChar written after it is explicitly set,
466 * we set subChar1 to 0.
468 converter->subChar1 = 0;
473 U_CAPI void U_EXPORT2
474 ucnv_setSubstString(UConverter *cnv,
478 UAlignedMemory cloneBuffer[U_CNV_SAFECLONE_BUFFERSIZE / sizeof(UAlignedMemory) + 1];
479 char chars[UCNV_ERROR_BUFFER_LENGTH];
483 int32_t cloneSize, length8;
485 /* Let the following functions check all arguments. */
486 cloneSize = sizeof(cloneBuffer);
487 clone = ucnv_safeClone(cnv, cloneBuffer, &cloneSize, err);
488 ucnv_setFromUCallBack(clone, UCNV_FROM_U_CALLBACK_STOP, NULL, NULL, NULL, err);
489 length8 = ucnv_fromUChars(clone, chars, (int32_t)sizeof(chars), s, length, err);
491 if (U_FAILURE(*err)) {
495 if (cnv->sharedData->impl->writeSub == NULL
496 #if !UCONFIG_NO_LEGACY_CONVERSION
497 || (cnv->sharedData->staticData->conversionType == UCNV_MBCS &&
498 ucnv_MBCSGetType(cnv) != UCNV_EBCDIC_STATEFUL)
501 /* The converter is not stateful. Store the charset bytes as a fixed string. */
502 subChars = (uint8_t *)chars;
505 * The converter has a non-default writeSub() function, indicating
506 * that it is stateful.
507 * Store the Unicode string for on-the-fly conversion for correct
510 if (length > UCNV_ERROR_BUFFER_LENGTH) {
512 * Should not occur. The converter should output at least one byte
513 * per UChar, which means that ucnv_fromUChars() should catch all
516 *err = U_BUFFER_OVERFLOW_ERROR;
519 subChars = (uint8_t *)s;
521 length = u_strlen(s);
523 length8 = length * U_SIZEOF_UCHAR;
527 * For storing the substitution string, select either the small buffer inside
528 * UConverter or allocate a subChars buffer.
530 if (length8 > UCNV_MAX_SUBCHAR_LEN) {
531 /* Use a separate buffer for the string. Outside UConverter to not make it too large. */
532 if (cnv->subChars == (uint8_t *)cnv->subUChars) {
533 /* Allocate a new buffer for the string. */
534 cnv->subChars = (uint8_t *)uprv_malloc(UCNV_ERROR_BUFFER_LENGTH * U_SIZEOF_UCHAR);
535 if (cnv->subChars == NULL) {
536 cnv->subChars = (uint8_t *)cnv->subUChars;
537 *err = U_MEMORY_ALLOCATION_ERROR;
540 uprv_memset(cnv->subChars, 0, UCNV_ERROR_BUFFER_LENGTH * U_SIZEOF_UCHAR);
544 /* Copy the substitution string into the UConverter or its subChars buffer. */
548 uprv_memcpy(cnv->subChars, subChars, length8);
549 if (subChars == (uint8_t *)chars) {
550 cnv->subCharLen = (int8_t)length8;
551 } else /* subChars == s */ {
552 cnv->subCharLen = (int8_t)-length;
556 /* See comment in ucnv_setSubstChars(). */
560 /*resets the internal states of a converter
561 *goal : have the same behaviour than a freshly created converter
563 static void _reset(UConverter *converter, UConverterResetChoice choice,
564 UBool callCallback) {
565 if(converter == NULL) {
570 /* first, notify the callback functions that the converter is reset */
571 UErrorCode errorCode;
573 if(choice<=UCNV_RESET_TO_UNICODE && converter->fromCharErrorBehaviour != UCNV_TO_U_DEFAULT_CALLBACK) {
574 UConverterToUnicodeArgs toUArgs = {
575 sizeof(UConverterToUnicodeArgs),
584 toUArgs.converter = converter;
585 errorCode = U_ZERO_ERROR;
586 converter->fromCharErrorBehaviour(converter->toUContext, &toUArgs, NULL, 0, UCNV_RESET, &errorCode);
588 if(choice!=UCNV_RESET_TO_UNICODE && converter->fromUCharErrorBehaviour != UCNV_FROM_U_DEFAULT_CALLBACK) {
589 UConverterFromUnicodeArgs fromUArgs = {
590 sizeof(UConverterFromUnicodeArgs),
599 fromUArgs.converter = converter;
600 errorCode = U_ZERO_ERROR;
601 converter->fromUCharErrorBehaviour(converter->fromUContext, &fromUArgs, NULL, 0, 0, UCNV_RESET, &errorCode);
605 /* now reset the converter itself */
606 if(choice<=UCNV_RESET_TO_UNICODE) {
607 converter->toUnicodeStatus = converter->sharedData->toUnicodeStatus;
609 converter->toULength = 0;
610 converter->invalidCharLength = converter->UCharErrorBufferLength = 0;
611 converter->preToULength = 0;
613 if(choice!=UCNV_RESET_TO_UNICODE) {
614 converter->fromUnicodeStatus = 0;
615 converter->fromUChar32 = 0;
616 converter->invalidUCharLength = converter->charErrorBufferLength = 0;
617 converter->preFromUFirstCP = U_SENTINEL;
618 converter->preFromULength = 0;
621 if (converter->sharedData->impl->reset != NULL) {
622 /* call the custom reset function */
623 converter->sharedData->impl->reset(converter, choice);
627 U_CAPI void U_EXPORT2
628 ucnv_reset(UConverter *converter)
630 _reset(converter, UCNV_RESET_BOTH, TRUE);
633 U_CAPI void U_EXPORT2
634 ucnv_resetToUnicode(UConverter *converter)
636 _reset(converter, UCNV_RESET_TO_UNICODE, TRUE);
639 U_CAPI void U_EXPORT2
640 ucnv_resetFromUnicode(UConverter *converter)
642 _reset(converter, UCNV_RESET_FROM_UNICODE, TRUE);
645 U_CAPI int8_t U_EXPORT2
646 ucnv_getMaxCharSize (const UConverter * converter)
648 return converter->maxBytesPerUChar;
652 U_CAPI int8_t U_EXPORT2
653 ucnv_getMinCharSize (const UConverter * converter)
655 return converter->sharedData->staticData->minBytesPerChar;
658 U_CAPI const char* U_EXPORT2
659 ucnv_getName (const UConverter * converter, UErrorCode * err)
662 if (U_FAILURE (*err))
664 if(converter->sharedData->impl->getName){
665 const char* temp= converter->sharedData->impl->getName(converter);
669 return converter->sharedData->staticData->name;
672 U_CAPI int32_t U_EXPORT2
673 ucnv_getCCSID(const UConverter * converter,
677 if (U_FAILURE (*err))
680 ccsid = converter->sharedData->staticData->codepage;
682 /* Rare case. This is for cases like gb18030,
683 which doesn't have an IBM canonical name, but does have an IBM alias. */
684 const char *standardName = ucnv_getStandardName(ucnv_getName(converter, err), "IBM", err);
685 if (U_SUCCESS(*err) && standardName) {
686 const char *ccsidStr = uprv_strchr(standardName, '-');
688 ccsid = (int32_t)atol(ccsidStr+1); /* +1 to skip '-' */
696 U_CAPI UConverterPlatform U_EXPORT2
697 ucnv_getPlatform (const UConverter * converter,
700 if (U_FAILURE (*err))
703 return (UConverterPlatform)converter->sharedData->staticData->platform;
706 U_CAPI void U_EXPORT2
707 ucnv_getToUCallBack (const UConverter * converter,
708 UConverterToUCallback *action,
709 const void **context)
711 *action = converter->fromCharErrorBehaviour;
712 *context = converter->toUContext;
715 U_CAPI void U_EXPORT2
716 ucnv_getFromUCallBack (const UConverter * converter,
717 UConverterFromUCallback *action,
718 const void **context)
720 *action = converter->fromUCharErrorBehaviour;
721 *context = converter->fromUContext;
724 U_CAPI void U_EXPORT2
725 ucnv_setToUCallBack (UConverter * converter,
726 UConverterToUCallback newAction,
727 const void* newContext,
728 UConverterToUCallback *oldAction,
729 const void** oldContext,
732 if (U_FAILURE (*err))
734 if (oldAction) *oldAction = converter->fromCharErrorBehaviour;
735 converter->fromCharErrorBehaviour = newAction;
736 if (oldContext) *oldContext = converter->toUContext;
737 converter->toUContext = newContext;
740 U_CAPI void U_EXPORT2
741 ucnv_setFromUCallBack (UConverter * converter,
742 UConverterFromUCallback newAction,
743 const void* newContext,
744 UConverterFromUCallback *oldAction,
745 const void** oldContext,
748 if (U_FAILURE (*err))
750 if (oldAction) *oldAction = converter->fromUCharErrorBehaviour;
751 converter->fromUCharErrorBehaviour = newAction;
752 if (oldContext) *oldContext = converter->fromUContext;
753 converter->fromUContext = newContext;
757 _updateOffsets(int32_t *offsets, int32_t length,
758 int32_t sourceIndex, int32_t errorInputLength) {
760 int32_t delta, offset;
764 * adjust each offset by adding the previous sourceIndex
765 * minus the length of the input sequence that caused an
768 delta=sourceIndex-errorInputLength;
771 * set each offset to -1 because this conversion function
772 * does not handle offsets
777 limit=offsets+length;
779 /* most common case, nothing to do */
781 /* add the delta to each offset (but not if the offset is <0) */
782 while(offsets<limit) {
785 *offsets=offset+delta;
789 } else /* delta<0 */ {
791 * set each offset to -1 because this conversion function
792 * does not handle offsets
793 * or the error input sequence started in a previous buffer
795 while(offsets<limit) {
801 /* ucnv_fromUnicode --------------------------------------------------------- */
804 * Implementation note for m:n conversions
806 * While collecting source units to find the longest match for m:n conversion,
807 * some source units may need to be stored for a partial match.
808 * When a second buffer does not yield a match on all of the previously stored
809 * source units, then they must be "replayed", i.e., fed back into the converter.
811 * The code relies on the fact that replaying will not nest -
812 * converting a replay buffer will not result in a replay.
813 * This is because a replay is necessary only after the _continuation_ of a
814 * partial match failed, but a replay buffer is converted as a whole.
815 * It may result in some of its units being stored again for a partial match,
816 * but there will not be a continuation _during_ the replay which could fail.
818 * It is conceivable that a callback function could call the converter
819 * recursively in a way that causes another replay to be stored, but that
820 * would be an error in the callback function.
821 * Such violations will cause assertion failures in a debug build,
822 * and wrong output, but they will not cause a crash.
826 _fromUnicodeWithCallback(UConverterFromUnicodeArgs *pArgs, UErrorCode *err) {
827 UConverterFromUnicode fromUnicode;
833 int32_t errorInputLength;
834 UBool converterSawEndOfInput, calledCallback;
836 /* variables for m:n conversion */
837 UChar replay[UCNV_EXT_MAX_UCHARS];
838 const UChar *realSource, *realSourceLimit;
839 int32_t realSourceIndex;
842 cnv=pArgs->converter;
845 offsets=pArgs->offsets;
847 /* get the converter implementation function */
850 fromUnicode=cnv->sharedData->impl->fromUnicode;
852 fromUnicode=cnv->sharedData->impl->fromUnicodeWithOffsets;
853 if(fromUnicode==NULL) {
854 /* there is no WithOffsets implementation */
855 fromUnicode=cnv->sharedData->impl->fromUnicode;
856 /* we will write -1 for each offset */
861 if(cnv->preFromULength>=0) {
865 /* avoid compiler warnings - not otherwise necessary, and the values do not matter */
866 realSourceLimit=NULL;
871 * Previous m:n conversion stored source units from a partial match
872 * and failed to consume all of them.
873 * We need to "replay" them from a temporary buffer and convert them first.
875 realSource=pArgs->source;
876 realSourceLimit=pArgs->sourceLimit;
877 realFlush=pArgs->flush;
878 realSourceIndex=sourceIndex;
880 uprv_memcpy(replay, cnv->preFromU, -cnv->preFromULength*U_SIZEOF_UCHAR);
881 pArgs->source=replay;
882 pArgs->sourceLimit=replay-cnv->preFromULength;
886 cnv->preFromULength=0;
890 * loop for conversion and error handling
896 * handle end of input
897 * handle errors/call callback
902 if(U_SUCCESS(*err)) {
904 fromUnicode(pArgs, err);
907 * set a flag for whether the converter
908 * successfully processed the end of the input
910 * need not check cnv->preFromULength==0 because a replay (<0) will cause
911 * s<sourceLimit before converterSawEndOfInput is checked
913 converterSawEndOfInput=
914 (UBool)(U_SUCCESS(*err) &&
915 pArgs->flush && pArgs->source==pArgs->sourceLimit &&
916 cnv->fromUChar32==0);
918 /* handle error from ucnv_convertEx() */
919 converterSawEndOfInput=FALSE;
922 /* no callback called yet for this iteration */
923 calledCallback=FALSE;
925 /* no sourceIndex adjustment for conversion, only for callback output */
929 * loop for offsets and error handling
931 * iterates at most 3 times:
932 * 1. to clean up after the conversion function
933 * 2. after the callback
934 * 3. after the callback again if there was truncated input
937 /* update offsets if we write any */
939 int32_t length=(int32_t)(pArgs->target-t);
941 _updateOffsets(offsets, length, sourceIndex, errorInputLength);
944 * if a converter handles offsets and updates the offsets
945 * pointer at the end, then pArgs->offset should not change
947 * however, some converters do not handle offsets at all
948 * (sourceIndex<0) or may not update the offsets pointer
950 pArgs->offsets=offsets+=length;
954 sourceIndex+=(int32_t)(pArgs->source-s);
958 if(cnv->preFromULength<0) {
960 * switch the source to new replay units (cannot occur while replaying)
961 * after offset handling and before end-of-input and callback handling
963 if(realSource==NULL) {
964 realSource=pArgs->source;
965 realSourceLimit=pArgs->sourceLimit;
966 realFlush=pArgs->flush;
967 realSourceIndex=sourceIndex;
969 uprv_memcpy(replay, cnv->preFromU, -cnv->preFromULength*U_SIZEOF_UCHAR);
970 pArgs->source=replay;
971 pArgs->sourceLimit=replay-cnv->preFromULength;
973 if((sourceIndex+=cnv->preFromULength)<0) {
977 cnv->preFromULength=0;
979 /* see implementation note before _fromUnicodeWithCallback() */
980 U_ASSERT(realSource==NULL);
981 *err=U_INTERNAL_PROGRAM_ERROR;
985 /* update pointers */
989 if(U_SUCCESS(*err)) {
990 if(s<pArgs->sourceLimit) {
992 * continue with the conversion loop while there is still input left
993 * (continue converting by breaking out of only the inner loop)
996 } else if(realSource!=NULL) {
997 /* switch back from replaying to the real source and continue */
998 pArgs->source=realSource;
999 pArgs->sourceLimit=realSourceLimit;
1000 pArgs->flush=realFlush;
1001 sourceIndex=realSourceIndex;
1005 } else if(pArgs->flush && cnv->fromUChar32!=0) {
1007 * the entire input stream is consumed
1008 * and there is a partial, truncated input sequence left
1011 /* inject an error and continue with callback handling */
1012 *err=U_TRUNCATED_CHAR_FOUND;
1013 calledCallback=FALSE; /* new error condition */
1015 /* input consumed */
1018 * return to the conversion loop once more if the flush
1019 * flag is set and the conversion function has not
1020 * successfully processed the end of the input yet
1022 * (continue converting by breaking out of only the inner loop)
1024 if(!converterSawEndOfInput) {
1028 /* reset the converter without calling the callback function */
1029 _reset(cnv, UCNV_RESET_FROM_UNICODE, FALSE);
1032 /* done successfully */
1037 /* U_FAILURE(*err) */
1041 if( calledCallback ||
1042 (e=*err)==U_BUFFER_OVERFLOW_ERROR ||
1043 (e!=U_INVALID_CHAR_FOUND &&
1044 e!=U_ILLEGAL_CHAR_FOUND &&
1045 e!=U_TRUNCATED_CHAR_FOUND)
1048 * the callback did not or cannot resolve the error:
1049 * set output pointers and return
1051 * the check for buffer overflow is redundant but it is
1052 * a high-runner case and hopefully documents the intent
1055 * if we were replaying, then the replay buffer must be
1056 * copied back into the UConverter
1057 * and the real arguments must be restored
1059 if(realSource!=NULL) {
1062 U_ASSERT(cnv->preFromULength==0);
1064 length=(int32_t)(pArgs->sourceLimit-pArgs->source);
1066 u_memcpy(cnv->preFromU, pArgs->source, length);
1067 cnv->preFromULength=(int8_t)-length;
1070 pArgs->source=realSource;
1071 pArgs->sourceLimit=realSourceLimit;
1072 pArgs->flush=realFlush;
1079 /* callback handling */
1083 /* get and write the code point */
1084 codePoint=cnv->fromUChar32;
1086 U16_APPEND_UNSAFE(cnv->invalidUCharBuffer, errorInputLength, codePoint);
1087 cnv->invalidUCharLength=(int8_t)errorInputLength;
1089 /* set the converter state to deal with the next character */
1092 /* call the callback function */
1093 cnv->fromUCharErrorBehaviour(cnv->fromUContext, pArgs,
1094 cnv->invalidUCharBuffer, errorInputLength, codePoint,
1095 *err==U_INVALID_CHAR_FOUND ? UCNV_UNASSIGNED : UCNV_ILLEGAL,
1100 * loop back to the offset handling
1102 * this flag will indicate after offset handling
1103 * that a callback was called;
1104 * if the callback did not resolve the error, then we return
1106 calledCallback=TRUE;
1112 * Output the fromUnicode overflow buffer.
1113 * Call this function if(cnv->charErrorBufferLength>0).
1114 * @return TRUE if overflow
1117 ucnv_outputOverflowFromUnicode(UConverter *cnv,
1118 char **target, const char *targetLimit,
1126 if(pOffsets!=NULL) {
1132 overflow=(char *)cnv->charErrorBuffer;
1133 length=cnv->charErrorBufferLength;
1136 if(t==targetLimit) {
1137 /* the overflow buffer contains too much, keep the rest */
1141 overflow[j++]=overflow[i++];
1144 cnv->charErrorBufferLength=(int8_t)j;
1149 *err=U_BUFFER_OVERFLOW_ERROR;
1153 /* copy the overflow contents to the target */
1156 *offsets++=-1; /* no source index available for old output */
1160 /* the overflow buffer is completely copied to the target */
1161 cnv->charErrorBufferLength=0;
1169 U_CAPI void U_EXPORT2
1170 ucnv_fromUnicode(UConverter *cnv,
1171 char **target, const char *targetLimit,
1172 const UChar **source, const UChar *sourceLimit,
1176 UConverterFromUnicodeArgs args;
1180 /* check parameters */
1181 if(err==NULL || U_FAILURE(*err)) {
1185 if(cnv==NULL || target==NULL || source==NULL) {
1186 *err=U_ILLEGAL_ARGUMENT_ERROR;
1193 if ((const void *)U_MAX_PTR(sourceLimit) == (const void *)sourceLimit) {
1195 Prevent code from going into an infinite loop in case we do hit this
1196 limit. The limit pointer is expected to be on a UChar * boundary.
1197 This also prevents the next argument check from failing.
1199 sourceLimit = (const UChar *)(((const char *)sourceLimit) - 1);
1203 * All these conditions should never happen.
1205 * 1) Make sure that the limits are >= to the address source or target
1207 * 2) Make sure that the buffer sizes do not exceed the number range for
1208 * int32_t because some functions use the size (in units or bytes)
1209 * rather than comparing pointers, and because offsets are int32_t values.
1211 * size_t is guaranteed to be unsigned and large enough for the job.
1213 * Return with an error instead of adjusting the limits because we would
1214 * not be able to maintain the semantics that either the source must be
1215 * consumed or the target filled (unless an error occurs).
1216 * An adjustment would be targetLimit=t+0x7fffffff; for example.
1218 * 3) Make sure that the user didn't incorrectly cast a UChar * pointer
1219 * to a char * pointer and provide an incomplete UChar code unit.
1221 if (sourceLimit<s || targetLimit<t ||
1222 ((size_t)(sourceLimit-s)>(size_t)0x3fffffff && sourceLimit>s) ||
1223 ((size_t)(targetLimit-t)>(size_t)0x7fffffff && targetLimit>t) ||
1224 (((const char *)sourceLimit-(const char *)s) & 1) != 0)
1226 *err=U_ILLEGAL_ARGUMENT_ERROR;
1230 /* output the target overflow buffer */
1231 if( cnv->charErrorBufferLength>0 &&
1232 ucnv_outputOverflowFromUnicode(cnv, target, targetLimit, &offsets, err)
1234 /* U_BUFFER_OVERFLOW_ERROR */
1237 /* *target may have moved, therefore stop using t */
1239 if(!flush && s==sourceLimit && cnv->preFromULength>=0) {
1240 /* the overflow buffer is emptied and there is no new input: we are done */
1245 * Do not simply return with a buffer overflow error if
1246 * !flush && t==targetLimit
1247 * because it is possible that the source will not generate any output.
1248 * For example, the skip callback may be called;
1249 * it does not output anything.
1252 /* prepare the converter arguments */
1255 args.offsets=offsets;
1257 args.sourceLimit=sourceLimit;
1258 args.target=*target;
1259 args.targetLimit=targetLimit;
1260 args.size=sizeof(args);
1262 _fromUnicodeWithCallback(&args, err);
1264 *source=args.source;
1265 *target=args.target;
1268 /* ucnv_toUnicode() --------------------------------------------------------- */
1271 _toUnicodeWithCallback(UConverterToUnicodeArgs *pArgs, UErrorCode *err) {
1272 UConverterToUnicode toUnicode;
1277 int32_t sourceIndex;
1278 int32_t errorInputLength;
1279 UBool converterSawEndOfInput, calledCallback;
1281 /* variables for m:n conversion */
1282 char replay[UCNV_EXT_MAX_BYTES];
1283 const char *realSource, *realSourceLimit;
1284 int32_t realSourceIndex;
1287 cnv=pArgs->converter;
1290 offsets=pArgs->offsets;
1292 /* get the converter implementation function */
1295 toUnicode=cnv->sharedData->impl->toUnicode;
1297 toUnicode=cnv->sharedData->impl->toUnicodeWithOffsets;
1298 if(toUnicode==NULL) {
1299 /* there is no WithOffsets implementation */
1300 toUnicode=cnv->sharedData->impl->toUnicode;
1301 /* we will write -1 for each offset */
1306 if(cnv->preToULength>=0) {
1310 /* avoid compiler warnings - not otherwise necessary, and the values do not matter */
1311 realSourceLimit=NULL;
1316 * Previous m:n conversion stored source units from a partial match
1317 * and failed to consume all of them.
1318 * We need to "replay" them from a temporary buffer and convert them first.
1320 realSource=pArgs->source;
1321 realSourceLimit=pArgs->sourceLimit;
1322 realFlush=pArgs->flush;
1323 realSourceIndex=sourceIndex;
1325 uprv_memcpy(replay, cnv->preToU, -cnv->preToULength);
1326 pArgs->source=replay;
1327 pArgs->sourceLimit=replay-cnv->preToULength;
1331 cnv->preToULength=0;
1335 * loop for conversion and error handling
1341 * handle end of input
1342 * handle errors/call callback
1347 if(U_SUCCESS(*err)) {
1349 toUnicode(pArgs, err);
1352 * set a flag for whether the converter
1353 * successfully processed the end of the input
1355 * need not check cnv->preToULength==0 because a replay (<0) will cause
1356 * s<sourceLimit before converterSawEndOfInput is checked
1358 converterSawEndOfInput=
1359 (UBool)(U_SUCCESS(*err) &&
1360 pArgs->flush && pArgs->source==pArgs->sourceLimit &&
1363 /* handle error from getNextUChar() or ucnv_convertEx() */
1364 converterSawEndOfInput=FALSE;
1367 /* no callback called yet for this iteration */
1368 calledCallback=FALSE;
1370 /* no sourceIndex adjustment for conversion, only for callback output */
1374 * loop for offsets and error handling
1376 * iterates at most 3 times:
1377 * 1. to clean up after the conversion function
1378 * 2. after the callback
1379 * 3. after the callback again if there was truncated input
1382 /* update offsets if we write any */
1384 int32_t length=(int32_t)(pArgs->target-t);
1386 _updateOffsets(offsets, length, sourceIndex, errorInputLength);
1389 * if a converter handles offsets and updates the offsets
1390 * pointer at the end, then pArgs->offset should not change
1392 * however, some converters do not handle offsets at all
1393 * (sourceIndex<0) or may not update the offsets pointer
1395 pArgs->offsets=offsets+=length;
1398 if(sourceIndex>=0) {
1399 sourceIndex+=(int32_t)(pArgs->source-s);
1403 if(cnv->preToULength<0) {
1405 * switch the source to new replay units (cannot occur while replaying)
1406 * after offset handling and before end-of-input and callback handling
1408 if(realSource==NULL) {
1409 realSource=pArgs->source;
1410 realSourceLimit=pArgs->sourceLimit;
1411 realFlush=pArgs->flush;
1412 realSourceIndex=sourceIndex;
1414 uprv_memcpy(replay, cnv->preToU, -cnv->preToULength);
1415 pArgs->source=replay;
1416 pArgs->sourceLimit=replay-cnv->preToULength;
1418 if((sourceIndex+=cnv->preToULength)<0) {
1422 cnv->preToULength=0;
1424 /* see implementation note before _fromUnicodeWithCallback() */
1425 U_ASSERT(realSource==NULL);
1426 *err=U_INTERNAL_PROGRAM_ERROR;
1430 /* update pointers */
1434 if(U_SUCCESS(*err)) {
1435 if(s<pArgs->sourceLimit) {
1437 * continue with the conversion loop while there is still input left
1438 * (continue converting by breaking out of only the inner loop)
1441 } else if(realSource!=NULL) {
1442 /* switch back from replaying to the real source and continue */
1443 pArgs->source=realSource;
1444 pArgs->sourceLimit=realSourceLimit;
1445 pArgs->flush=realFlush;
1446 sourceIndex=realSourceIndex;
1450 } else if(pArgs->flush && cnv->toULength>0) {
1452 * the entire input stream is consumed
1453 * and there is a partial, truncated input sequence left
1456 /* inject an error and continue with callback handling */
1457 *err=U_TRUNCATED_CHAR_FOUND;
1458 calledCallback=FALSE; /* new error condition */
1460 /* input consumed */
1463 * return to the conversion loop once more if the flush
1464 * flag is set and the conversion function has not
1465 * successfully processed the end of the input yet
1467 * (continue converting by breaking out of only the inner loop)
1469 if(!converterSawEndOfInput) {
1473 /* reset the converter without calling the callback function */
1474 _reset(cnv, UCNV_RESET_TO_UNICODE, FALSE);
1477 /* done successfully */
1482 /* U_FAILURE(*err) */
1486 if( calledCallback ||
1487 (e=*err)==U_BUFFER_OVERFLOW_ERROR ||
1488 (e!=U_INVALID_CHAR_FOUND &&
1489 e!=U_ILLEGAL_CHAR_FOUND &&
1490 e!=U_TRUNCATED_CHAR_FOUND &&
1491 e!=U_ILLEGAL_ESCAPE_SEQUENCE &&
1492 e!=U_UNSUPPORTED_ESCAPE_SEQUENCE)
1495 * the callback did not or cannot resolve the error:
1496 * set output pointers and return
1498 * the check for buffer overflow is redundant but it is
1499 * a high-runner case and hopefully documents the intent
1502 * if we were replaying, then the replay buffer must be
1503 * copied back into the UConverter
1504 * and the real arguments must be restored
1506 if(realSource!=NULL) {
1509 U_ASSERT(cnv->preToULength==0);
1511 length=(int32_t)(pArgs->sourceLimit-pArgs->source);
1513 uprv_memcpy(cnv->preToU, pArgs->source, length);
1514 cnv->preToULength=(int8_t)-length;
1517 pArgs->source=realSource;
1518 pArgs->sourceLimit=realSourceLimit;
1519 pArgs->flush=realFlush;
1526 /* copy toUBytes[] to invalidCharBuffer[] */
1527 errorInputLength=cnv->invalidCharLength=cnv->toULength;
1528 if(errorInputLength>0) {
1529 uprv_memcpy(cnv->invalidCharBuffer, cnv->toUBytes, errorInputLength);
1532 /* set the converter state to deal with the next character */
1535 /* call the callback function */
1536 if(cnv->toUCallbackReason==UCNV_ILLEGAL && *err==U_INVALID_CHAR_FOUND) {
1537 cnv->toUCallbackReason = UCNV_UNASSIGNED;
1539 cnv->fromCharErrorBehaviour(cnv->toUContext, pArgs,
1540 cnv->invalidCharBuffer, errorInputLength,
1541 cnv->toUCallbackReason,
1543 cnv->toUCallbackReason = UCNV_ILLEGAL; /* reset to default value */
1546 * loop back to the offset handling
1548 * this flag will indicate after offset handling
1549 * that a callback was called;
1550 * if the callback did not resolve the error, then we return
1552 calledCallback=TRUE;
1558 * Output the toUnicode overflow buffer.
1559 * Call this function if(cnv->UCharErrorBufferLength>0).
1560 * @return TRUE if overflow
1563 ucnv_outputOverflowToUnicode(UConverter *cnv,
1564 UChar **target, const UChar *targetLimit,
1568 UChar *overflow, *t;
1572 if(pOffsets!=NULL) {
1578 overflow=cnv->UCharErrorBuffer;
1579 length=cnv->UCharErrorBufferLength;
1582 if(t==targetLimit) {
1583 /* the overflow buffer contains too much, keep the rest */
1587 overflow[j++]=overflow[i++];
1590 cnv->UCharErrorBufferLength=(int8_t)j;
1595 *err=U_BUFFER_OVERFLOW_ERROR;
1599 /* copy the overflow contents to the target */
1602 *offsets++=-1; /* no source index available for old output */
1606 /* the overflow buffer is completely copied to the target */
1607 cnv->UCharErrorBufferLength=0;
1615 U_CAPI void U_EXPORT2
1616 ucnv_toUnicode(UConverter *cnv,
1617 UChar **target, const UChar *targetLimit,
1618 const char **source, const char *sourceLimit,
1622 UConverterToUnicodeArgs args;
1626 /* check parameters */
1627 if(err==NULL || U_FAILURE(*err)) {
1631 if(cnv==NULL || target==NULL || source==NULL) {
1632 *err=U_ILLEGAL_ARGUMENT_ERROR;
1639 if ((const void *)U_MAX_PTR(targetLimit) == (const void *)targetLimit) {
1641 Prevent code from going into an infinite loop in case we do hit this
1642 limit. The limit pointer is expected to be on a UChar * boundary.
1643 This also prevents the next argument check from failing.
1645 targetLimit = (const UChar *)(((const char *)targetLimit) - 1);
1649 * All these conditions should never happen.
1651 * 1) Make sure that the limits are >= to the address source or target
1653 * 2) Make sure that the buffer sizes do not exceed the number range for
1654 * int32_t because some functions use the size (in units or bytes)
1655 * rather than comparing pointers, and because offsets are int32_t values.
1657 * size_t is guaranteed to be unsigned and large enough for the job.
1659 * Return with an error instead of adjusting the limits because we would
1660 * not be able to maintain the semantics that either the source must be
1661 * consumed or the target filled (unless an error occurs).
1662 * An adjustment would be sourceLimit=t+0x7fffffff; for example.
1664 * 3) Make sure that the user didn't incorrectly cast a UChar * pointer
1665 * to a char * pointer and provide an incomplete UChar code unit.
1667 if (sourceLimit<s || targetLimit<t ||
1668 ((size_t)(sourceLimit-s)>(size_t)0x7fffffff && sourceLimit>s) ||
1669 ((size_t)(targetLimit-t)>(size_t)0x3fffffff && targetLimit>t) ||
1670 (((const char *)targetLimit-(const char *)t) & 1) != 0
1672 *err=U_ILLEGAL_ARGUMENT_ERROR;
1676 /* output the target overflow buffer */
1677 if( cnv->UCharErrorBufferLength>0 &&
1678 ucnv_outputOverflowToUnicode(cnv, target, targetLimit, &offsets, err)
1680 /* U_BUFFER_OVERFLOW_ERROR */
1683 /* *target may have moved, therefore stop using t */
1685 if(!flush && s==sourceLimit && cnv->preToULength>=0) {
1686 /* the overflow buffer is emptied and there is no new input: we are done */
1691 * Do not simply return with a buffer overflow error if
1692 * !flush && t==targetLimit
1693 * because it is possible that the source will not generate any output.
1694 * For example, the skip callback may be called;
1695 * it does not output anything.
1698 /* prepare the converter arguments */
1701 args.offsets=offsets;
1703 args.sourceLimit=sourceLimit;
1704 args.target=*target;
1705 args.targetLimit=targetLimit;
1706 args.size=sizeof(args);
1708 _toUnicodeWithCallback(&args, err);
1710 *source=args.source;
1711 *target=args.target;
1714 /* ucnv_to/fromUChars() ----------------------------------------------------- */
1716 U_CAPI int32_t U_EXPORT2
1717 ucnv_fromUChars(UConverter *cnv,
1718 char *dest, int32_t destCapacity,
1719 const UChar *src, int32_t srcLength,
1720 UErrorCode *pErrorCode) {
1721 const UChar *srcLimit;
1722 char *originalDest, *destLimit;
1725 /* check arguments */
1726 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
1731 destCapacity<0 || (destCapacity>0 && dest==NULL) ||
1732 srcLength<-1 || (srcLength!=0 && src==NULL)
1734 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
1739 ucnv_resetFromUnicode(cnv);
1742 srcLength=u_strlen(src);
1745 srcLimit=src+srcLength;
1746 destLimit=dest+destCapacity;
1748 /* pin the destination limit to U_MAX_PTR; NULL check is for OS/400 */
1749 if(destLimit<dest || (destLimit==NULL && dest!=NULL)) {
1750 destLimit=(char *)U_MAX_PTR(dest);
1753 /* perform the conversion */
1754 ucnv_fromUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, TRUE, pErrorCode);
1755 destLength=(int32_t)(dest-originalDest);
1757 /* if an overflow occurs, then get the preflighting length */
1758 if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
1761 destLimit=buffer+sizeof(buffer);
1764 *pErrorCode=U_ZERO_ERROR;
1765 ucnv_fromUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, TRUE, pErrorCode);
1766 destLength+=(int32_t)(dest-buffer);
1767 } while(*pErrorCode==U_BUFFER_OVERFLOW_ERROR);
1773 return u_terminateChars(originalDest, destCapacity, destLength, pErrorCode);
1776 U_CAPI int32_t U_EXPORT2
1777 ucnv_toUChars(UConverter *cnv,
1778 UChar *dest, int32_t destCapacity,
1779 const char *src, int32_t srcLength,
1780 UErrorCode *pErrorCode) {
1781 const char *srcLimit;
1782 UChar *originalDest, *destLimit;
1785 /* check arguments */
1786 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
1791 destCapacity<0 || (destCapacity>0 && dest==NULL) ||
1792 srcLength<-1 || (srcLength!=0 && src==NULL))
1794 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
1799 ucnv_resetToUnicode(cnv);
1802 srcLength=(int32_t)uprv_strlen(src);
1805 srcLimit=src+srcLength;
1806 destLimit=dest+destCapacity;
1808 /* pin the destination limit to U_MAX_PTR; NULL check is for OS/400 */
1809 if(destLimit<dest || (destLimit==NULL && dest!=NULL)) {
1810 destLimit=(UChar *)U_MAX_PTR(dest);
1813 /* perform the conversion */
1814 ucnv_toUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, TRUE, pErrorCode);
1815 destLength=(int32_t)(dest-originalDest);
1817 /* if an overflow occurs, then get the preflighting length */
1818 if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR)
1822 destLimit=buffer+UPRV_LENGTHOF(buffer);
1825 *pErrorCode=U_ZERO_ERROR;
1826 ucnv_toUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, TRUE, pErrorCode);
1827 destLength+=(int32_t)(dest-buffer);
1829 while(*pErrorCode==U_BUFFER_OVERFLOW_ERROR);
1835 return u_terminateUChars(originalDest, destCapacity, destLength, pErrorCode);
1838 /* ucnv_getNextUChar() ------------------------------------------------------ */
1840 U_CAPI UChar32 U_EXPORT2
1841 ucnv_getNextUChar(UConverter *cnv,
1842 const char **source, const char *sourceLimit,
1844 UConverterToUnicodeArgs args;
1845 UChar buffer[U16_MAX_LENGTH];
1850 /* check parameters */
1851 if(err==NULL || U_FAILURE(*err)) {
1855 if(cnv==NULL || source==NULL) {
1856 *err=U_ILLEGAL_ARGUMENT_ERROR;
1862 *err=U_ILLEGAL_ARGUMENT_ERROR;
1867 * Make sure that the buffer sizes do not exceed the number range for
1868 * int32_t because some functions use the size (in units or bytes)
1869 * rather than comparing pointers, and because offsets are int32_t values.
1871 * size_t is guaranteed to be unsigned and large enough for the job.
1873 * Return with an error instead of adjusting the limits because we would
1874 * not be able to maintain the semantics that either the source must be
1875 * consumed or the target filled (unless an error occurs).
1876 * An adjustment would be sourceLimit=t+0x7fffffff; for example.
1878 if(((size_t)(sourceLimit-s)>(size_t)0x7fffffff && sourceLimit>s)) {
1879 *err=U_ILLEGAL_ARGUMENT_ERROR;
1885 /* flush the target overflow buffer */
1886 if(cnv->UCharErrorBufferLength>0) {
1889 overflow=cnv->UCharErrorBuffer;
1891 length=cnv->UCharErrorBufferLength;
1892 U16_NEXT(overflow, i, length, c);
1894 /* move the remaining overflow contents up to the beginning */
1895 if((cnv->UCharErrorBufferLength=(int8_t)(length-i))>0) {
1896 uprv_memmove(cnv->UCharErrorBuffer, cnv->UCharErrorBuffer+i,
1897 cnv->UCharErrorBufferLength*U_SIZEOF_UCHAR);
1900 if(!U16_IS_LEAD(c) || i<length) {
1904 * Continue if the overflow buffer contained only a lead surrogate,
1905 * in case the converter outputs single surrogates from complete
1911 * flush==TRUE is implied for ucnv_getNextUChar()
1913 * do not simply return even if s==sourceLimit because the converter may
1914 * not have seen flush==TRUE before
1917 /* prepare the converter arguments */
1922 args.sourceLimit=sourceLimit;
1924 args.targetLimit=buffer+1;
1925 args.size=sizeof(args);
1929 * call the native getNextUChar() implementation if we are
1930 * at a character boundary (toULength==0)
1932 * unlike with _toUnicode(), getNextUChar() implementations must set
1933 * U_TRUNCATED_CHAR_FOUND for truncated input,
1934 * in addition to setting toULength/toUBytes[]
1936 if(cnv->toULength==0 && cnv->sharedData->impl->getNextUChar!=NULL) {
1937 c=cnv->sharedData->impl->getNextUChar(&args, err);
1938 *source=s=args.source;
1939 if(*err==U_INDEX_OUTOFBOUNDS_ERROR) {
1940 /* reset the converter without calling the callback function */
1941 _reset(cnv, UCNV_RESET_TO_UNICODE, FALSE);
1942 return 0xffff; /* no output */
1943 } else if(U_SUCCESS(*err) && c>=0) {
1946 * else fall through to use _toUnicode() because
1947 * UCNV_GET_NEXT_UCHAR_USE_TO_U: the native function did not want to handle it after all
1948 * U_FAILURE: call _toUnicode() for callback handling (do not output c)
1953 /* convert to one UChar in buffer[0], or handle getNextUChar() errors */
1954 _toUnicodeWithCallback(&args, err);
1956 if(*err==U_BUFFER_OVERFLOW_ERROR) {
1961 length=(int32_t)(args.target-buffer);
1963 /* write the lead surrogate from the overflow buffer */
1965 args.target=buffer+1;
1970 /* buffer contents starts at i and ends before length */
1972 if(U_FAILURE(*err)) {
1973 c=0xffff; /* no output */
1974 } else if(length==0) {
1975 /* no input or only state changes */
1976 *err=U_INDEX_OUTOFBOUNDS_ERROR;
1977 /* no need to reset explicitly because _toUnicodeWithCallback() did it */
1978 c=0xffff; /* no output */
1982 if(!U16_IS_LEAD(c)) {
1983 /* consume c=buffer[0], done */
1985 /* got a lead surrogate, see if a trail surrogate follows */
1988 if(cnv->UCharErrorBufferLength>0) {
1989 /* got overflow output from the conversion */
1990 if(U16_IS_TRAIL(c2=cnv->UCharErrorBuffer[0])) {
1991 /* got a trail surrogate, too */
1992 c=U16_GET_SUPPLEMENTARY(c, c2);
1994 /* move the remaining overflow contents up to the beginning */
1995 if((--cnv->UCharErrorBufferLength)>0) {
1996 uprv_memmove(cnv->UCharErrorBuffer, cnv->UCharErrorBuffer+1,
1997 cnv->UCharErrorBufferLength*U_SIZEOF_UCHAR);
2000 /* c is an unpaired lead surrogate, just return it */
2002 } else if(args.source<sourceLimit) {
2003 /* convert once more, to buffer[1] */
2004 args.targetLimit=buffer+2;
2005 _toUnicodeWithCallback(&args, err);
2006 if(*err==U_BUFFER_OVERFLOW_ERROR) {
2010 length=(int32_t)(args.target-buffer);
2011 if(U_SUCCESS(*err) && length==2 && U16_IS_TRAIL(c2=buffer[1])) {
2012 /* got a trail surrogate, too */
2013 c=U16_GET_SUPPLEMENTARY(c, c2);
2021 * move leftover output from buffer[i..length[
2022 * into the beginning of the overflow buffer
2025 /* move further overflow back */
2026 int32_t delta=length-i;
2027 if((length=cnv->UCharErrorBufferLength)>0) {
2028 uprv_memmove(cnv->UCharErrorBuffer+delta, cnv->UCharErrorBuffer,
2029 length*U_SIZEOF_UCHAR);
2031 cnv->UCharErrorBufferLength=(int8_t)(length+delta);
2033 cnv->UCharErrorBuffer[0]=buffer[i++];
2035 cnv->UCharErrorBuffer[1]=buffer[i];
2039 *source=args.source;
2043 /* ucnv_convert() and siblings ---------------------------------------------- */
2045 U_CAPI void U_EXPORT2
2046 ucnv_convertEx(UConverter *targetCnv, UConverter *sourceCnv,
2047 char **target, const char *targetLimit,
2048 const char **source, const char *sourceLimit,
2049 UChar *pivotStart, UChar **pivotSource,
2050 UChar **pivotTarget, const UChar *pivotLimit,
2051 UBool reset, UBool flush,
2052 UErrorCode *pErrorCode) {
2053 UChar pivotBuffer[CHUNK_SIZE];
2054 const UChar *myPivotSource;
2055 UChar *myPivotTarget;
2059 UConverterToUnicodeArgs toUArgs;
2060 UConverterFromUnicodeArgs fromUArgs;
2061 UConverterConvert convert;
2063 /* error checking */
2064 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
2068 if( targetCnv==NULL || sourceCnv==NULL ||
2069 source==NULL || *source==NULL ||
2070 target==NULL || *target==NULL || targetLimit==NULL
2072 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
2078 if((sourceLimit!=NULL && sourceLimit<s) || targetLimit<t) {
2079 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
2084 * Make sure that the buffer sizes do not exceed the number range for
2085 * int32_t. See ucnv_toUnicode() for a more detailed comment.
2088 (sourceLimit!=NULL && ((size_t)(sourceLimit-s)>(size_t)0x7fffffff && sourceLimit>s)) ||
2089 ((size_t)(targetLimit-t)>(size_t)0x7fffffff && targetLimit>t)
2091 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
2095 if(pivotStart==NULL) {
2097 /* streaming conversion requires an explicit pivot buffer */
2098 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
2102 /* use the stack pivot buffer */
2103 myPivotSource=myPivotTarget=pivotStart=pivotBuffer;
2104 pivotSource=(UChar **)&myPivotSource;
2105 pivotTarget=&myPivotTarget;
2106 pivotLimit=pivotBuffer+CHUNK_SIZE;
2107 } else if( pivotStart>=pivotLimit ||
2108 pivotSource==NULL || *pivotSource==NULL ||
2109 pivotTarget==NULL || *pivotTarget==NULL ||
2112 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
2116 if(sourceLimit==NULL) {
2117 /* get limit of single-byte-NUL-terminated source string */
2118 sourceLimit=uprv_strchr(*source, 0);
2122 ucnv_resetToUnicode(sourceCnv);
2123 ucnv_resetFromUnicode(targetCnv);
2124 *pivotSource=*pivotTarget=pivotStart;
2125 } else if(targetCnv->charErrorBufferLength>0) {
2126 /* output the targetCnv overflow buffer */
2127 if(ucnv_outputOverflowFromUnicode(targetCnv, target, targetLimit, NULL, pErrorCode)) {
2128 /* U_BUFFER_OVERFLOW_ERROR */
2131 /* *target has moved, therefore stop using t */
2134 targetCnv->preFromULength>=0 && *pivotSource==*pivotTarget &&
2135 sourceCnv->UCharErrorBufferLength==0 && sourceCnv->preToULength>=0 && s==sourceLimit
2137 /* the fromUnicode overflow buffer is emptied and there is no new input: we are done */
2142 /* Is direct-UTF-8 conversion available? */
2143 if( sourceCnv->sharedData->staticData->conversionType==UCNV_UTF8 &&
2144 targetCnv->sharedData->impl->fromUTF8!=NULL
2146 convert=targetCnv->sharedData->impl->fromUTF8;
2147 } else if( targetCnv->sharedData->staticData->conversionType==UCNV_UTF8 &&
2148 sourceCnv->sharedData->impl->toUTF8!=NULL
2150 convert=sourceCnv->sharedData->impl->toUTF8;
2156 * If direct-UTF-8 conversion is available, then we use a smaller
2157 * pivot buffer for error handling and partial matches
2158 * so that we quickly return to direct conversion.
2160 * 32 is large enough for UCNV_EXT_MAX_UCHARS and UCNV_ERROR_BUFFER_LENGTH.
2162 * We could reduce the pivot buffer size further, at the cost of
2163 * buffer overflows from callbacks.
2164 * The pivot buffer should not be smaller than the maximum number of
2165 * fromUnicode extension table input UChars
2166 * (for m:n conversion, see
2167 * targetCnv->sharedData->mbcs.extIndexes[UCNV_EXT_COUNT_UCHARS])
2168 * or 2 for surrogate pairs.
2170 * Too small a buffer can cause thrashing between pivoting and direct
2171 * conversion, with function call overhead outweighing the benefits
2172 * of direct conversion.
2174 if(convert!=NULL && (pivotLimit-pivotStart)>32) {
2175 pivotLimit=pivotStart+32;
2178 /* prepare the converter arguments */
2179 fromUArgs.converter=targetCnv;
2180 fromUArgs.flush=FALSE;
2181 fromUArgs.offsets=NULL;
2182 fromUArgs.target=*target;
2183 fromUArgs.targetLimit=targetLimit;
2184 fromUArgs.size=sizeof(fromUArgs);
2186 toUArgs.converter=sourceCnv;
2187 toUArgs.flush=flush;
2188 toUArgs.offsets=NULL;
2190 toUArgs.sourceLimit=sourceLimit;
2191 toUArgs.targetLimit=pivotLimit;
2192 toUArgs.size=sizeof(toUArgs);
2195 * TODO: Consider separating this function into two functions,
2196 * extracting exactly the conversion loop,
2197 * for readability and to reduce the set of visible variables.
2199 * Otherwise stop using s and t from here on.
2206 * The sequence of steps in the loop may appear backward,
2207 * but the principle is simple:
2209 * source - sourceCnv overflow - pivot - targetCnv overflow - target
2210 * empty out later buffers before refilling them from earlier ones.
2212 * The targetCnv overflow buffer is flushed out only once before the loop.
2216 * if(pivot not empty or error or replay or flush fromUnicode) {
2217 * fromUnicode(pivot -> target);
2220 * For pivoting conversion; and for direct conversion for
2221 * error callback handling and flushing the replay buffer.
2223 if( *pivotSource<*pivotTarget ||
2224 U_FAILURE(*pErrorCode) ||
2225 targetCnv->preFromULength<0 ||
2228 fromUArgs.source=*pivotSource;
2229 fromUArgs.sourceLimit=*pivotTarget;
2230 _fromUnicodeWithCallback(&fromUArgs, pErrorCode);
2231 if(U_FAILURE(*pErrorCode)) {
2232 /* target overflow, or conversion error */
2233 *pivotSource=(UChar *)fromUArgs.source;
2238 * _fromUnicodeWithCallback() must have consumed the pivot contents
2239 * (*pivotSource==*pivotTarget) since it returned with U_SUCCESS()
2243 /* The pivot buffer is empty; reset it so we start at pivotStart. */
2244 *pivotSource=*pivotTarget=pivotStart;
2247 * if(sourceCnv overflow buffer not empty) {
2248 * move(sourceCnv overflow buffer -> pivot);
2252 /* output the sourceCnv overflow buffer */
2253 if(sourceCnv->UCharErrorBufferLength>0) {
2254 if(ucnv_outputOverflowToUnicode(sourceCnv, pivotTarget, pivotLimit, NULL, pErrorCode)) {
2255 /* U_BUFFER_OVERFLOW_ERROR */
2256 *pErrorCode=U_ZERO_ERROR;
2262 * check for end of input and break if done
2264 * Checking both flush and fromUArgs.flush ensures that the converters
2265 * have been called with the flush flag set if the ucnv_convertEx()
2268 if( toUArgs.source==sourceLimit &&
2269 sourceCnv->preToULength>=0 && sourceCnv->toULength==0 &&
2270 (!flush || fromUArgs.flush)
2272 /* done successfully */
2277 * use direct conversion if available
2278 * but not if continuing a partial match
2279 * or flushing the toUnicode replay buffer
2281 if(convert!=NULL && targetCnv->preFromUFirstCP<0 && sourceCnv->preToULength==0) {
2282 if(*pErrorCode==U_USING_DEFAULT_WARNING) {
2283 /* remove a warning that may be set by this function */
2284 *pErrorCode=U_ZERO_ERROR;
2286 convert(&fromUArgs, &toUArgs, pErrorCode);
2287 if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
2289 } else if(U_FAILURE(*pErrorCode)) {
2290 if(sourceCnv->toULength>0) {
2292 * Fall through to calling _toUnicodeWithCallback()
2293 * for callback handling.
2295 * The pivot buffer will be reset with
2296 * *pivotSource=*pivotTarget=pivotStart;
2297 * which indicates a toUnicode error to the caller
2298 * (*pivotSource==pivotStart shows no pivot UChars consumed).
2302 * Indicate a fromUnicode error to the caller
2303 * (*pivotSource>pivotStart shows some pivot UChars consumed).
2305 *pivotSource=*pivotTarget=pivotStart+1;
2307 * Loop around to calling _fromUnicodeWithCallbacks()
2308 * for callback handling.
2312 } else if(*pErrorCode==U_USING_DEFAULT_WARNING) {
2314 * No error, but the implementation requested to temporarily
2315 * fall back to pivoting.
2317 *pErrorCode=U_ZERO_ERROR;
2319 * The following else branches are almost identical to the end-of-input
2320 * handling in _toUnicodeWithCallback().
2321 * Avoid calling it just for the end of input.
2323 } else if(flush && sourceCnv->toULength>0) { /* flush==toUArgs.flush */
2325 * the entire input stream is consumed
2326 * and there is a partial, truncated input sequence left
2329 /* inject an error and continue with callback handling */
2330 *pErrorCode=U_TRUNCATED_CHAR_FOUND;
2332 /* input consumed */
2334 /* reset the converters without calling the callback functions */
2335 _reset(sourceCnv, UCNV_RESET_TO_UNICODE, FALSE);
2336 _reset(targetCnv, UCNV_RESET_FROM_UNICODE, FALSE);
2339 /* done successfully */
2345 * toUnicode(source -> pivot);
2347 * For pivoting conversion; and for direct conversion for
2348 * error callback handling, continuing partial matches
2349 * and flushing the replay buffer.
2351 * The pivot buffer is empty and reset.
2353 toUArgs.target=pivotStart; /* ==*pivotTarget */
2354 /* toUArgs.targetLimit=pivotLimit; already set before the loop */
2355 _toUnicodeWithCallback(&toUArgs, pErrorCode);
2356 *pivotTarget=toUArgs.target;
2357 if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
2358 /* pivot overflow: continue with the conversion loop */
2359 *pErrorCode=U_ZERO_ERROR;
2360 } else if(U_FAILURE(*pErrorCode) || (!flush && *pivotTarget==pivotStart)) {
2361 /* conversion error, or there was nothing left to convert */
2366 * _toUnicodeWithCallback() wrote into the pivot buffer,
2367 * continue with fromUnicode conversion.
2369 * Set the fromUnicode flush flag if we flush and if toUnicode has
2370 * processed the end of the input.
2372 if( flush && toUArgs.source==sourceLimit &&
2373 sourceCnv->preToULength>=0 &&
2374 sourceCnv->UCharErrorBufferLength==0
2376 fromUArgs.flush=TRUE;
2381 * The conversion loop is exited when one of the following is true:
2382 * - the entire source text has been converted successfully to the target buffer
2383 * - a target buffer overflow occurred
2384 * - a conversion error occurred
2387 *source=toUArgs.source;
2388 *target=fromUArgs.target;
2390 /* terminate the target buffer if possible */
2391 if(flush && U_SUCCESS(*pErrorCode)) {
2392 if(*target!=targetLimit) {
2394 if(*pErrorCode==U_STRING_NOT_TERMINATED_WARNING) {
2395 *pErrorCode=U_ZERO_ERROR;
2398 *pErrorCode=U_STRING_NOT_TERMINATED_WARNING;
2403 /* internal implementation of ucnv_convert() etc. with preflighting */
2405 ucnv_internalConvert(UConverter *outConverter, UConverter *inConverter,
2406 char *target, int32_t targetCapacity,
2407 const char *source, int32_t sourceLength,
2408 UErrorCode *pErrorCode) {
2409 UChar pivotBuffer[CHUNK_SIZE];
2410 UChar *pivot, *pivot2;
2413 const char *sourceLimit;
2414 const char *targetLimit;
2415 int32_t targetLength=0;
2418 if(sourceLength<0) {
2419 sourceLimit=uprv_strchr(source, 0);
2421 sourceLimit=source+sourceLength;
2424 /* if there is no input data, we're done */
2425 if(source==sourceLimit) {
2426 return u_terminateChars(target, targetCapacity, 0, pErrorCode);
2429 pivot=pivot2=pivotBuffer;
2433 if(targetCapacity>0) {
2434 /* perform real conversion */
2435 targetLimit=target+targetCapacity;
2436 ucnv_convertEx(outConverter, inConverter,
2437 &myTarget, targetLimit,
2438 &source, sourceLimit,
2439 pivotBuffer, &pivot, &pivot2, pivotBuffer+CHUNK_SIZE,
2443 targetLength=(int32_t)(myTarget-target);
2447 * If the output buffer is exhausted (or we are only "preflighting"), we need to stop writing
2448 * to it but continue the conversion in order to store in targetCapacity
2449 * the number of bytes that was required.
2451 if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR || targetCapacity==0)
2453 char targetBuffer[CHUNK_SIZE];
2455 targetLimit=targetBuffer+CHUNK_SIZE;
2457 *pErrorCode=U_ZERO_ERROR;
2458 myTarget=targetBuffer;
2459 ucnv_convertEx(outConverter, inConverter,
2460 &myTarget, targetLimit,
2461 &source, sourceLimit,
2462 pivotBuffer, &pivot, &pivot2, pivotBuffer+CHUNK_SIZE,
2466 targetLength+=(int32_t)(myTarget-targetBuffer);
2467 } while(*pErrorCode==U_BUFFER_OVERFLOW_ERROR);
2469 /* done with preflighting, set warnings and errors as appropriate */
2470 return u_terminateChars(target, targetCapacity, targetLength, pErrorCode);
2473 /* no need to call u_terminateChars() because ucnv_convertEx() took care of that */
2474 return targetLength;
2477 U_CAPI int32_t U_EXPORT2
2478 ucnv_convert(const char *toConverterName, const char *fromConverterName,
2479 char *target, int32_t targetCapacity,
2480 const char *source, int32_t sourceLength,
2481 UErrorCode *pErrorCode) {
2482 UConverter in, out; /* stack-allocated */
2483 UConverter *inConverter, *outConverter;
2484 int32_t targetLength;
2486 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
2490 if( source==NULL || sourceLength<-1 ||
2491 targetCapacity<0 || (targetCapacity>0 && target==NULL)
2493 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
2497 /* if there is no input data, we're done */
2498 if(sourceLength==0 || (sourceLength<0 && *source==0)) {
2499 return u_terminateChars(target, targetCapacity, 0, pErrorCode);
2502 /* create the converters */
2503 inConverter=ucnv_createConverter(&in, fromConverterName, pErrorCode);
2504 if(U_FAILURE(*pErrorCode)) {
2508 outConverter=ucnv_createConverter(&out, toConverterName, pErrorCode);
2509 if(U_FAILURE(*pErrorCode)) {
2510 ucnv_close(inConverter);
2514 targetLength=ucnv_internalConvert(outConverter, inConverter,
2515 target, targetCapacity,
2516 source, sourceLength,
2519 ucnv_close(inConverter);
2520 ucnv_close(outConverter);
2522 return targetLength;
2527 ucnv_convertAlgorithmic(UBool convertToAlgorithmic,
2528 UConverterType algorithmicType,
2530 char *target, int32_t targetCapacity,
2531 const char *source, int32_t sourceLength,
2532 UErrorCode *pErrorCode) {
2533 UConverter algoConverterStatic; /* stack-allocated */
2534 UConverter *algoConverter, *to, *from;
2535 int32_t targetLength;
2537 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
2541 if( cnv==NULL || source==NULL || sourceLength<-1 ||
2542 targetCapacity<0 || (targetCapacity>0 && target==NULL)
2544 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
2548 /* if there is no input data, we're done */
2549 if(sourceLength==0 || (sourceLength<0 && *source==0)) {
2550 return u_terminateChars(target, targetCapacity, 0, pErrorCode);
2553 /* create the algorithmic converter */
2554 algoConverter=ucnv_createAlgorithmicConverter(&algoConverterStatic, algorithmicType,
2556 if(U_FAILURE(*pErrorCode)) {
2560 /* reset the other converter */
2561 if(convertToAlgorithmic) {
2562 /* cnv->Unicode->algo */
2563 ucnv_resetToUnicode(cnv);
2567 /* algo->Unicode->cnv */
2568 ucnv_resetFromUnicode(cnv);
2573 targetLength=ucnv_internalConvert(to, from,
2574 target, targetCapacity,
2575 source, sourceLength,
2578 ucnv_close(algoConverter);
2580 return targetLength;
2583 U_CAPI int32_t U_EXPORT2
2584 ucnv_toAlgorithmic(UConverterType algorithmicType,
2586 char *target, int32_t targetCapacity,
2587 const char *source, int32_t sourceLength,
2588 UErrorCode *pErrorCode) {
2589 return ucnv_convertAlgorithmic(TRUE, algorithmicType, cnv,
2590 target, targetCapacity,
2591 source, sourceLength,
2595 U_CAPI int32_t U_EXPORT2
2596 ucnv_fromAlgorithmic(UConverter *cnv,
2597 UConverterType algorithmicType,
2598 char *target, int32_t targetCapacity,
2599 const char *source, int32_t sourceLength,
2600 UErrorCode *pErrorCode) {
2601 return ucnv_convertAlgorithmic(FALSE, algorithmicType, cnv,
2602 target, targetCapacity,
2603 source, sourceLength,
2607 U_CAPI UConverterType U_EXPORT2
2608 ucnv_getType(const UConverter* converter)
2610 int8_t type = converter->sharedData->staticData->conversionType;
2611 #if !UCONFIG_NO_LEGACY_CONVERSION
2612 if(type == UCNV_MBCS) {
2613 return ucnv_MBCSGetType(converter);
2616 return (UConverterType)type;
2619 U_CAPI void U_EXPORT2
2620 ucnv_getStarters(const UConverter* converter,
2621 UBool starters[256],
2624 if (err == NULL || U_FAILURE(*err)) {
2628 if(converter->sharedData->impl->getStarters != NULL) {
2629 converter->sharedData->impl->getStarters(converter, starters, err);
2631 *err = U_ILLEGAL_ARGUMENT_ERROR;
2635 static const UAmbiguousConverter *ucnv_getAmbiguous(const UConverter *cnv)
2637 UErrorCode errorCode;
2645 errorCode=U_ZERO_ERROR;
2646 name=ucnv_getName(cnv, &errorCode);
2647 if(U_FAILURE(errorCode)) {
2651 for(i=0; i<UPRV_LENGTHOF(ambiguousConverters); ++i)
2653 if(0==uprv_strcmp(name, ambiguousConverters[i].name))
2655 return ambiguousConverters+i;
2662 U_CAPI void U_EXPORT2
2663 ucnv_fixFileSeparator(const UConverter *cnv,
2665 int32_t sourceLength) {
2666 const UAmbiguousConverter *a;
2670 if(cnv==NULL || source==NULL || sourceLength<=0 || (a=ucnv_getAmbiguous(cnv))==NULL)
2675 variant5c=a->variant5c;
2676 for(i=0; i<sourceLength; ++i) {
2677 if(source[i]==variant5c) {
2683 U_CAPI UBool U_EXPORT2
2684 ucnv_isAmbiguous(const UConverter *cnv) {
2685 return (UBool)(ucnv_getAmbiguous(cnv)!=NULL);
2688 U_CAPI void U_EXPORT2
2689 ucnv_setFallback(UConverter *cnv, UBool usesFallback)
2691 cnv->useFallback = usesFallback;
2694 U_CAPI UBool U_EXPORT2
2695 ucnv_usesFallback(const UConverter *cnv)
2697 return cnv->useFallback;
2700 U_CAPI void U_EXPORT2
2701 ucnv_getInvalidChars (const UConverter * converter,
2706 if (err == NULL || U_FAILURE(*err))
2710 if (len == NULL || errBytes == NULL || converter == NULL)
2712 *err = U_ILLEGAL_ARGUMENT_ERROR;
2715 if (*len < converter->invalidCharLength)
2717 *err = U_INDEX_OUTOFBOUNDS_ERROR;
2720 if ((*len = converter->invalidCharLength) > 0)
2722 uprv_memcpy (errBytes, converter->invalidCharBuffer, *len);
2726 U_CAPI void U_EXPORT2
2727 ucnv_getInvalidUChars (const UConverter * converter,
2732 if (err == NULL || U_FAILURE(*err))
2736 if (len == NULL || errChars == NULL || converter == NULL)
2738 *err = U_ILLEGAL_ARGUMENT_ERROR;
2741 if (*len < converter->invalidUCharLength)
2743 *err = U_INDEX_OUTOFBOUNDS_ERROR;
2746 if ((*len = converter->invalidUCharLength) > 0)
2748 u_memcpy (errChars, converter->invalidUCharBuffer, *len);
2752 #define SIG_MAX_LEN 5
2754 U_CAPI const char* U_EXPORT2
2755 ucnv_detectUnicodeSignature( const char* source,
2756 int32_t sourceLength,
2757 int32_t* signatureLength,
2758 UErrorCode* pErrorCode) {
2761 /* initial 0xa5 bytes: make sure that if we read <SIG_MAX_LEN
2762 * bytes we don't misdetect something
2764 char start[SIG_MAX_LEN]={ '\xa5', '\xa5', '\xa5', '\xa5', '\xa5' };
2767 if((pErrorCode==NULL) || U_FAILURE(*pErrorCode)){
2771 if(source == NULL || sourceLength < -1){
2772 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
2776 if(signatureLength == NULL) {
2777 signatureLength = &dummy;
2780 if(sourceLength==-1){
2781 sourceLength=(int32_t)uprv_strlen(source);
2785 while(i<sourceLength&& i<SIG_MAX_LEN){
2790 if(start[0] == '\xFE' && start[1] == '\xFF') {
2793 } else if(start[0] == '\xFF' && start[1] == '\xFE') {
2794 if(start[2] == '\x00' && start[3] =='\x00') {
2801 } else if(start[0] == '\xEF' && start[1] == '\xBB' && start[2] == '\xBF') {
2804 } else if(start[0] == '\x00' && start[1] == '\x00' &&
2805 start[2] == '\xFE' && start[3]=='\xFF') {
2808 } else if(start[0] == '\x0E' && start[1] == '\xFE' && start[2] == '\xFF') {
2811 } else if(start[0] == '\xFB' && start[1] == '\xEE' && start[2] == '\x28') {
2814 } else if(start[0] == '\x2B' && start[1] == '\x2F' && start[2] == '\x76') {
2816 * UTF-7: Initial U+FEFF is encoded as +/v8 or +/v9 or +/v+ or +/v/
2817 * depending on the second UTF-16 code unit.
2818 * Detect the entire, closed Unicode mode sequence +/v8- for only U+FEFF
2821 * So far we have +/v
2823 if(start[3] == '\x38' && start[4] == '\x2D') {
2827 } else if(start[3] == '\x38' || start[3] == '\x39' || start[3] == '\x2B' || start[3] == '\x2F') {
2828 /* 4 bytes +/v8 or +/v9 or +/v+ or +/v/ */
2832 }else if(start[0]=='\xDD' && start[1]== '\x73'&& start[2]=='\x66' && start[3]=='\x73'){
2834 return "UTF-EBCDIC";
2838 /* no known Unicode signature byte sequence recognized */
2843 U_CAPI int32_t U_EXPORT2
2844 ucnv_fromUCountPending(const UConverter* cnv, UErrorCode* status)
2846 if(status == NULL || U_FAILURE(*status)){
2850 *status = U_ILLEGAL_ARGUMENT_ERROR;
2854 if(cnv->preFromUFirstCP >= 0){
2855 return U16_LENGTH(cnv->preFromUFirstCP)+cnv->preFromULength ;
2856 }else if(cnv->preFromULength < 0){
2857 return -cnv->preFromULength ;
2858 }else if(cnv->fromUChar32 > 0){
2865 U_CAPI int32_t U_EXPORT2
2866 ucnv_toUCountPending(const UConverter* cnv, UErrorCode* status){
2868 if(status == NULL || U_FAILURE(*status)){
2872 *status = U_ILLEGAL_ARGUMENT_ERROR;
2876 if(cnv->preToULength > 0){
2877 return cnv->preToULength ;
2878 }else if(cnv->preToULength < 0){
2879 return -cnv->preToULength;
2880 }else if(cnv->toULength > 0){
2881 return cnv->toULength;
2886 U_CAPI UBool U_EXPORT2
2887 ucnv_isFixedWidth(UConverter *cnv, UErrorCode *status){
2888 if (U_FAILURE(*status)) {
2893 *status = U_ILLEGAL_ARGUMENT_ERROR;
2897 switch (ucnv_getType(cnv)) {
2900 case UCNV_UTF32_BigEndian:
2901 case UCNV_UTF32_LittleEndian:
2912 * Hey, Emacs, please set the following:
2915 * indent-tabs-mode: nil