1 // © 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