blob: 4620a631de373a4ebd46876f7e56783d235a3585 [file] [log] [blame]
/*
**********************************************************************
* Copyright (C) 2000, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* file name: ucnv_utf.cpp
* encoding: US-ASCII
* tab size: 8 (not used)
* indentation:4
*
* created on: 2000feb03
* created by: Markus W. Scherer
*
* Change history:
*
* 06/29/2000 helena Major rewrite of the callback APIs.
* 07/20/2000 george Change the coding style to conform to the coding guidelines,
* and a few miscellaneous bug fixes.
*/
#include "cmemory.h"
#include "unicode/utypes.h"
#include "ucmp16.h"
#include "ucmp8.h"
#include "unicode/ucnv_err.h"
#include "ucnv_bld.h"
#include "unicode/ucnv.h"
#include "ucnv_cnv.h"
/* UTF-8 -------------------------------------------------------------------- */
/* UTF-8 Conversion DATA
* for more information see Unicode Strandard 2.0 , Transformation Formats Appendix A-9
*/
/*static const uint32_t REPLACEMENT_CHARACTER = 0x0000FFFD;*/
static const uint32_t MAXIMUM_UCS2 = 0x0000FFFF;
static const uint32_t MAXIMUM_UTF16 = 0x0010FFFF;
static const uint32_t MAXIMUM_UCS4 = 0x7FFFFFFF;
static const int8_t HALF_SHIFT = 10;
static const uint32_t HALF_BASE = 0x0010000;
static const uint32_t HALF_MASK = 0x3FF;
static const uint32_t SURROGATE_HIGH_START = 0xD800;
static const uint32_t SURROGATE_HIGH_END = 0xDBFF;
static const uint32_t SURROGATE_LOW_START = 0xDC00;
static const uint32_t SURROGATE_LOW_END = 0xDFFF;
static const uint32_t SURROGATE_LOW_BASE = 9216; /* -SURROGATE_LOW_START + HALF_BASE */
static const uint32_t offsetsFromUTF8[7] = {0,
(uint32_t) 0x00000000, (uint32_t) 0x00003080, (uint32_t) 0x000E2080,
(uint32_t) 0x03C82080, (uint32_t) 0xFA082080, (uint32_t) 0x82082080
};
/* END OF UTF-8 Conversion DATA */
static const int8_t bytesFromUTF8[256] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0
};
/* static const unsigned char firstByteMark[7] = {0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC};*/
#define INVALID_UTF8_TAIL(utf8) (((utf8) & 0xC0) != 0x80)
/**
* Calls invalid char callback when an invalid character sequence is encountered.
* It presumes that the converter has a callback to call.
*
* @returns true when callback fails
*/
UBool T_UConverter_toUnicode_InvalidChar_Callback(UConverterToUnicodeArgs * args,
UErrorCode *err)
{
UConverter *converter = args->converter;
if (U_SUCCESS(*err))
{
*err = U_ILLEGAL_CHAR_FOUND;
}
/* Make the toUBytes invalid */
uprv_memcpy(converter->invalidCharBuffer,
converter->toUBytes,
converter->invalidCharLength);
/* Call the ErrorFunction */
args->converter->fromCharErrorBehaviour(converter->toUContext,
args,
converter->invalidCharBuffer,
converter->invalidCharLength,
UCNV_ILLEGAL,
err);
return (UBool)U_FAILURE(*err);
}
UBool T_UConverter_toUnicode_InvalidChar_OffsetCallback(UConverterToUnicodeArgs * args,
int32_t currentOffset,
UErrorCode *err)
{
int32_t *saveOffsets = args->offsets;
UBool result;
result = T_UConverter_toUnicode_InvalidChar_Callback(args, err);
while (saveOffsets < args->offsets)
{
*(saveOffsets++) = currentOffset;
}
return result;
}
U_CFUNC void T_UConverter_toUnicode_UTF8 (UConverterToUnicodeArgs * args,
UErrorCode * err)
{
const unsigned char *mySource = (unsigned char *) args->source;
UChar *myTarget = args->target;
const unsigned char *sourceLimit = (unsigned char *) args->sourceLimit;
const UChar *targetLimit = args->targetLimit;
unsigned char *toUBytes = args->converter->toUBytes;
UBool invalidTailChar = FALSE;
uint32_t ch, ch2 = 0, i;
uint32_t inBytes; /* Total number of bytes in the current UTF8 sequence */
if (U_FAILURE(*err))
{
return;
}
/* Restore size of current sequence */
if (args->converter->toUnicodeStatus && myTarget < targetLimit)
{
inBytes = args->converter->toULength; /* restore # of bytes to consume */
i = args->converter->invalidCharLength; /* restore # of bytes consumed */
ch = args->converter->toUnicodeStatus;/*Stores the previously calculated ch from a previous call*/
args->converter->toUnicodeStatus = 0;
goto morebytes;
}
while (mySource < sourceLimit && myTarget < targetLimit)
{
ch = *(mySource++);
if (ch < 0x80) /* Simple case */
{
*(myTarget++) = (UChar) ch;
}
else
{
/* store the first char */
toUBytes[0] = (char)ch;
inBytes = bytesFromUTF8[ch]; /* lookup current sequence length */
i = 1;
morebytes:
while (i < inBytes)
{
if (mySource < sourceLimit)
{
toUBytes[i] = (char) (ch2 = *(mySource++));
if (INVALID_UTF8_TAIL(ch2))
{
*err = U_TRUNCATED_CHAR_FOUND;
invalidTailChar = TRUE;
break;
}
ch = (ch << 6) + ch2;
i++;
}
else
{
if (args->flush)
{
if (U_SUCCESS(*err))
{
*err = U_TRUNCATED_CHAR_FOUND;
}
}
else
{ /* stores a partially calculated target*/
args->converter->toUnicodeStatus = ch;
args->converter->toULength = (int8_t) inBytes;
args->converter->invalidCharLength = (int8_t) i;
}
goto donefornow;
}
}
/* Remove the acummulated high bits */
ch -= offsetsFromUTF8[inBytes];
if (i == inBytes && ch <= MAXIMUM_UTF16)
{
/* Normal valid byte when the loop has not prematurely terminated (i < inBytes) */
if (ch <= MAXIMUM_UCS2)
{
/* fits in 16 bits */
*(myTarget++) = (UChar) ch;
}
else
{
/* write out the surrogates */
ch -= HALF_BASE;
*(myTarget++) = (UChar) ((ch >> HALF_SHIFT) + SURROGATE_HIGH_START);
ch = (ch & HALF_MASK) + SURROGATE_LOW_START;
if (myTarget < targetLimit)
{
*(myTarget++) = (UChar)ch;
}
else
{
/* Put in overflow buffer (not handled here) */
args->converter->UCharErrorBuffer[0] = (UChar) ch;
args->converter->UCharErrorBufferLength = 1;
*err = U_INDEX_OUTOFBOUNDS_ERROR;
break;
}
}
}
else
{
args->source = (const char *) mySource;
args->target = myTarget;
args->converter->invalidCharLength = (int8_t)i;
if (T_UConverter_toUnicode_InvalidChar_Callback(args, err))
{
/* Stop if the error wasn't handled */
break;
}
args->converter->invalidCharLength = 0;
mySource = (unsigned char *) args->source;
myTarget = args->target;
if (invalidTailChar)
{
/* Treat the tail as ASCII*/
if (myTarget < targetLimit)
{
*(myTarget++) = (UChar) ch2;
invalidTailChar = FALSE;
}
else
{
/* Put in overflow buffer (not handled here) */
args->converter->UCharErrorBuffer[0] = (UChar) ch2;
args->converter->UCharErrorBufferLength = 1;
*err = U_INDEX_OUTOFBOUNDS_ERROR;
break;
}
}
}
}
}
donefornow:
if (mySource < sourceLimit && myTarget >= targetLimit && U_SUCCESS(*err))
{
/* End of target buffer */
*err = U_INDEX_OUTOFBOUNDS_ERROR;
}
args->target = myTarget;
args->source = (const char *) mySource;
}
U_CFUNC void T_UConverter_toUnicode_UTF8_OFFSETS_LOGIC (UConverterToUnicodeArgs * args,
UErrorCode * err)
{
const unsigned char *mySource = (unsigned char *) args->source;
UChar *myTarget = args->target;
int32_t *myOffsets = args->offsets;
int32_t offsetNum = 0;
const unsigned char *sourceLimit = (unsigned char *) args->sourceLimit;
const UChar *targetLimit = args->targetLimit;
unsigned char *toUBytes = args->converter->toUBytes;
UBool invalidTailChar = FALSE;
uint32_t ch, ch2 = 0, i;
uint32_t inBytes;
/* Restore size of current sequence */
if (args->converter->toUnicodeStatus && myTarget < targetLimit)
{
inBytes = args->converter->toULength; /* restore # of bytes to consume */
i = args->converter->invalidCharLength; /* restore # of bytes consumed */
ch = args->converter->toUnicodeStatus;/*Stores the previously calculated ch from a previous call*/
args->converter->toUnicodeStatus = 0;
goto morebytes;
}
while (mySource < sourceLimit && myTarget < targetLimit)
{
ch = *(mySource++);
if (ch < 0x80) /* Simple case */
{
*(myTarget++) = (UChar) ch;
*(myOffsets++) = offsetNum++;
}
else
{
toUBytes[0] = (char)ch;
inBytes = bytesFromUTF8[ch];
i = 1;
morebytes:
while (i < inBytes)
{
if (mySource < sourceLimit)
{
toUBytes[i] = (char) (ch2 = *(mySource++));
if (INVALID_UTF8_TAIL(ch2))
{
*err = U_TRUNCATED_CHAR_FOUND;
invalidTailChar = TRUE;
break;
}
ch = (ch << 6) + ch2;
i++;
}
else
{
if (args->flush)
{
if (U_SUCCESS(*err))
{
*err = U_TRUNCATED_CHAR_FOUND;
args->converter->toUnicodeStatus = 0;
}
}
else
{
args->converter->toUnicodeStatus = ch;
args->converter->toULength = (int8_t)inBytes;
args->converter->invalidCharLength = (int8_t)i;
}
goto donefornow;
}
}
/* Remove the acummulated high bits */
ch -= offsetsFromUTF8[inBytes];
if (i == inBytes && ch <= MAXIMUM_UTF16)
{
/* Normal valid byte when the loop has not prematurely terminated (i < inBytes) */
if (ch <= MAXIMUM_UCS2)
{
/* fits in 16 bits */
*(myTarget++) = (UChar) ch;
*(myOffsets++) = offsetNum;
}
else
{
/* write out the surrogates */
*(myOffsets++) = offsetNum;
ch -= HALF_BASE;
*(myTarget++) = (UChar) ((ch >> HALF_SHIFT) + SURROGATE_HIGH_START);
ch = (ch & HALF_MASK) + SURROGATE_LOW_START;
if (myTarget < targetLimit)
{
*(myTarget++) = (UChar)ch;
*(myOffsets++) = offsetNum;
}
else
{
args->converter->UCharErrorBuffer[0] = (UChar) ch;
args->converter->UCharErrorBufferLength = 1;
*err = U_INDEX_OUTOFBOUNDS_ERROR;
}
}
offsetNum += i;
}
else
{
UBool useOffset;
args->source = (const char *) mySource;
args->target = myTarget;
args->offsets = myOffsets;
args->converter->invalidCharLength = (int8_t)i;
if (T_UConverter_toUnicode_InvalidChar_OffsetCallback(args,
offsetNum, err))
{
/* Stop if the error wasn't handled */
break;
}
args->converter->invalidCharLength = 0;
mySource = (unsigned char *) args->source;
myTarget = args->target;
useOffset = (UBool)(myOffsets != args->offsets);
myOffsets = args->offsets;
offsetNum += i;
if (invalidTailChar)
{
/* Treat the tail as ASCII*/
if (myTarget < targetLimit)
{
*(myTarget++) = (UChar) ch2;
*myOffsets = offsetNum++;
if (useOffset)
{
/* Increment when the target was consumed */
myOffsets++;
}
invalidTailChar = FALSE;
}
else
{
/* Put in overflow buffer (not handled here) */
args->converter->UCharErrorBuffer[0] = (UChar) ch2;
args->converter->UCharErrorBufferLength = 1;
*err = U_INDEX_OUTOFBOUNDS_ERROR;
break;
}
}
}
}
}
donefornow:
if (mySource < sourceLimit && myTarget >= targetLimit && U_SUCCESS(*err))
{ /* End of target buffer */
*err = U_INDEX_OUTOFBOUNDS_ERROR;
}
args->target = myTarget;
args->source = (const char *) mySource;
args->offsets = myOffsets;
}
U_CFUNC void T_UConverter_fromUnicode_UTF8 (UConverterFromUnicodeArgs * args,
UErrorCode * err)
{
const UChar *mySource = args->source;
unsigned char *myTarget = (unsigned char *) args->target;
const UChar *sourceLimit = args->sourceLimit;
const unsigned char *targetLimit = (unsigned char *) args->targetLimit;
uint32_t ch, ch2;
int16_t indexToWrite;
char temp[4];
if (args->converter->fromUnicodeStatus && myTarget < targetLimit)
{
ch = args->converter->fromUnicodeStatus;
args->converter->fromUnicodeStatus = 0;
goto lowsurogate;
}
while (mySource < sourceLimit && myTarget < targetLimit)
{
ch = *(mySource++);
if (ch < 0x80) /* Single byte */
{
*(myTarget++) = (char) ch;
}
else if (ch < 0x800) /* Double byte */
{
*(myTarget++) = (char) ((ch >> 6) | 0xc0);
if (myTarget < targetLimit)
{
*(myTarget++) = (char) ((ch & 0x3f) | 0x80);
}
else
{
args->converter->charErrorBuffer[0] = (char) ((ch & 0x3f) | 0x80);
args->converter->charErrorBufferLength = 1;
*err = U_INDEX_OUTOFBOUNDS_ERROR;
}
}
else
/* Check for surogates */
{
if ((ch >= SURROGATE_HIGH_START) && (ch <= SURROGATE_HIGH_END))
{
lowsurogate:
if (mySource < sourceLimit)
{
ch2 = *mySource;
if ((ch2 >= SURROGATE_LOW_START) && (ch2 <= SURROGATE_LOW_END))
{
/* If there were two surrogates, combine them otherwise treat them normally */
ch = ((ch - SURROGATE_HIGH_START) << HALF_SHIFT) + ch2 + SURROGATE_LOW_BASE;
mySource++;
}
}
else if (!args->flush)
{
args->converter->fromUnicodeStatus = ch;
break;
}
}
if (ch < 0x10000)
{
indexToWrite = 2;
temp[2] = (char) ((ch >> 12) | 0xe0);
}
else
{
indexToWrite = 3;
temp[3] = (char) ((ch >> 18) | 0xf0);
temp[2] = (char) ((ch >> 12) & 0x3f | 0x80);
}
temp[1] = (char) ((ch >> 6) & 0x3f | 0x80);
temp[0] = (char) (ch & 0x3f | 0x80);
for (; indexToWrite >= 0; indexToWrite--)
{
if (myTarget < targetLimit)
{
*(myTarget++) = temp[indexToWrite];
}
else
{
args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] = temp[indexToWrite];
*err = U_INDEX_OUTOFBOUNDS_ERROR;
}
}
}
}
if (mySource < sourceLimit && myTarget >= targetLimit && U_SUCCESS(*err))
{
*err = U_INDEX_OUTOFBOUNDS_ERROR;
}
args->target = (char *) myTarget;
args->source = mySource;
}
U_CFUNC void T_UConverter_fromUnicode_UTF8_OFFSETS_LOGIC (UConverterFromUnicodeArgs * args,
UErrorCode * err)
{
const UChar *mySource = args->source;
unsigned char *myTarget = (unsigned char *) args->target;
int32_t *myOffsets = args->offsets;
const UChar *sourceLimit = args->sourceLimit;
const unsigned char *targetLimit = (unsigned char *) args->targetLimit;
uint32_t ch, ch2;
int32_t offsetNum = 0;
int16_t indexToWrite;
char temp[4];
if (args->converter->fromUnicodeStatus && myTarget < targetLimit)
{
ch = args->converter->fromUnicodeStatus;
args->converter->fromUnicodeStatus = 0;
goto lowsurogate;
}
while (mySource < sourceLimit && myTarget < targetLimit)
{
ch = *(mySource++);
if (ch < 0x80) /* Single byte */
{
*(myOffsets++) = offsetNum++;
*(myTarget++) = (char) ch;
}
else if (ch < 0x800) /* Double byte */
{
*(myOffsets++) = offsetNum;
*(myTarget++) = (char) ((ch >> 6) | 0xc0);
if (myTarget < targetLimit)
{
*(myOffsets++) = offsetNum++;
*(myTarget++) = (char) ((ch & 0x3f) | 0x80);
}
else
{
args->converter->charErrorBuffer[0] = (char) ((ch & 0x3f) | 0x80);
args->converter->charErrorBufferLength = 1;
*err = U_INDEX_OUTOFBOUNDS_ERROR;
}
}
else
/* Check for surogates */
{
if ((ch >= SURROGATE_HIGH_START) && (ch <= SURROGATE_HIGH_END))
{
lowsurogate:
if (mySource < sourceLimit)
{
ch2 = *mySource;
if ((ch2 >= SURROGATE_LOW_START) && (ch2 <= SURROGATE_LOW_END))
{
/* If there were two surrogates, combine them otherwise treat them normally */
ch = ((ch - SURROGATE_HIGH_START) << HALF_SHIFT) + ch2 + SURROGATE_LOW_BASE;
mySource++;
}
}
else if (!args->flush)
{
args->converter->fromUnicodeStatus = ch;
break;
}
}
if (ch < 0x10000)
{
indexToWrite = 2;
temp[2] = (char) ((ch >> 12) | 0xe0);
}
else
{
indexToWrite = 3;
temp[3] = (char) ((ch >> 18) | 0xf0);
temp[2] = (char) ((ch >> 12) & 0x3f | 0x80);
}
temp[1] = (char) ((ch >> 6) & 0x3f | 0x80);
temp[0] = (char) (ch & 0x3f | 0x80);
for (; indexToWrite >= 0; indexToWrite--)
{
if (myTarget < targetLimit)
{
*(myOffsets++) = offsetNum;
*(myTarget++) = temp[indexToWrite];
}
else
{
args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] = temp[indexToWrite];
*err = U_INDEX_OUTOFBOUNDS_ERROR;
}
}
offsetNum += (ch >= 0x10000) + 1;
}
}
if (mySource < sourceLimit && myTarget >= targetLimit && U_SUCCESS(*err))
{
*err = U_INDEX_OUTOFBOUNDS_ERROR;
}
args->target = (char *) myTarget;
args->source = mySource;
}
U_CFUNC UChar32 T_UConverter_getNextUChar_UTF8(UConverterToUnicodeArgs *args,
UErrorCode* err)
{
/*safe keeps a ptr to the beginning in case we need to step back*/
char const *sourceInitial = args->source;
uint16_t extraBytesToWrite;
uint8_t myByte;
UChar32 ch;
int8_t isLegalSequence = 1;
/*Input boundary check*/
if (args->source >= args->sourceLimit)
{
*err = U_INDEX_OUTOFBOUNDS_ERROR;
return 0xffff;
}
myByte = (uint8_t)*(args->source++);
if (myByte < 0x80)
{
return (UChar32)myByte;
}
extraBytesToWrite = (uint16_t)bytesFromUTF8[myByte];
if (extraBytesToWrite == 0) {
goto CALL_ERROR_FUNCTION;
}
/*The byte sequence is longer than the buffer area passed*/
if ((args->source + extraBytesToWrite - 1) > args->sourceLimit)
{
*err = U_TRUNCATED_CHAR_FOUND;
return 0xffff;
}
else
{
ch = myByte << 6;
switch(extraBytesToWrite)
{
/* note: code falls through cases! (sic)*/
case 6:
ch += (myByte = (uint8_t)*(args->source++));
ch <<= 6;
if ((myByte & 0xC0) != 0x80)
{
isLegalSequence = 0;
break;
}
case 5:
ch += (myByte = *(args->source++));
ch <<= 6;
if ((myByte & 0xC0) != 0x80)
{
isLegalSequence = 0;
break;
}
case 4:
ch += (myByte = *(args->source++));
ch <<= 6;
if ((myByte & 0xC0) != 0x80)
{
isLegalSequence = 0;
break;
}
case 3:
ch += (myByte = *(args->source++));
ch <<= 6;
if ((myByte & 0xC0) != 0x80)
{
isLegalSequence = 0;
break;
}
case 2:
ch += (myByte = *(args->source++));
if ((myByte & 0xC0) != 0x80)
{
isLegalSequence = 0;
}
};
}
ch -= offsetsFromUTF8[extraBytesToWrite];
if (isLegalSequence)
return ch; /* return the code point */
CALL_ERROR_FUNCTION:
{
UChar myUChar = (UChar)0xffff; /* ### TODO: this is a hack until we prepare the callbacks for code points */
UChar* myUCharPtr = &myUChar;
*err = U_ILLEGAL_CHAR_FOUND;
/*It is very likely that the ErrorFunctor will write to the
*internal buffers */
args->target = myUCharPtr;
args->targetLimit = myUCharPtr + 1;
args->converter->fromCharErrorBehaviour(args->converter->toUContext,
args,
sourceInitial,
args->source-sourceInitial,
UCNV_ILLEGAL,
err);
/*makes the internal caching transparent to the user*/
if (*err == U_INDEX_OUTOFBOUNDS_ERROR)
*err = U_ZERO_ERROR;
return (UChar32)myUChar;
}
}
static const UConverterImpl _UTF8Impl={
UCNV_UTF8,
NULL,
NULL,
NULL,
NULL,
NULL,
T_UConverter_toUnicode_UTF8,
T_UConverter_toUnicode_UTF8_OFFSETS_LOGIC,
T_UConverter_fromUnicode_UTF8,
T_UConverter_fromUnicode_UTF8_OFFSETS_LOGIC,
T_UConverter_getNextUChar_UTF8,
NULL
};
/* Todo: verify that UTF-8 == (ccsid (ibm-codepage) 1208) for unicode version 2.0 and 3.0 */
const UConverterStaticData _UTF8StaticData={
sizeof(UConverterStaticData),
"UTF8",
1208, UCNV_IBM, UCNV_UTF8, 1, 4,
3, { 0xef, 0xbf, 0xbd, 0 }
};
const UConverterSharedData _UTF8Data={
sizeof(UConverterSharedData), ~((uint32_t) 0),
NULL, NULL, &_UTF8StaticData, FALSE, &_UTF8Impl,
0
};
/* UTF-16BE ----------------------------------------------------------------- */
U_CFUNC void T_UConverter_toUnicode_UTF16_BE (UConverterToUnicodeArgs * args,
UErrorCode * err)
{
const unsigned char *mySource = (unsigned char *) args->source;
UChar *myTarget = args->target;
int32_t mySourceIndex = 0;
int32_t myTargetIndex = 0;
int32_t targetLength = args->targetLimit - myTarget;
int32_t sourceLength = args->sourceLimit - (char *) mySource;
UChar mySourceChar = 0x0000;
UChar oldmySourceChar = 0x0000;
while (mySourceIndex < sourceLength)
{
if (myTargetIndex < targetLength)
{
/*gets the corresponding UChar */
mySourceChar = (unsigned char) mySource[mySourceIndex++];
oldmySourceChar = mySourceChar;
if (args->converter->toUnicodeStatus == 0)
{
args->converter->toUnicodeStatus =
(unsigned char) mySourceChar == 0 ? 0xFFFF : mySourceChar;
}
else
{
if (args->converter->toUnicodeStatus != 0xFFFF)
mySourceChar = (UChar) ((args->converter->toUnicodeStatus << 8) | mySourceChar);
args->converter->toUnicodeStatus = 0;
myTarget[myTargetIndex++] = mySourceChar;
}
}
else
{
*err = U_INDEX_OUTOFBOUNDS_ERROR;
break;
}
}
if (U_SUCCESS(*err) && args->flush
&& (mySourceIndex == sourceLength)
&& (args->converter->toUnicodeStatus != 0x00))
{
if (U_SUCCESS(*err))
{
*err = U_TRUNCATED_CHAR_FOUND;
args->converter->toUnicodeStatus = 0x00;
}
}
args->target += myTargetIndex;
args->source += mySourceIndex;
}
U_CFUNC void T_UConverter_fromUnicode_UTF16_BE (UConverterFromUnicodeArgs * args,
UErrorCode * err)
{
const UChar *mySource = args->source;
unsigned char *myTarget = (unsigned char *) args->target;
int32_t mySourceIndex = 0;
int32_t myTargetIndex = 0;
int32_t targetLength = args->targetLimit - (char *) myTarget;
int32_t sourceLength = args->sourceLimit - mySource;
UChar mySourceChar;
/*writing the char to the output stream */
while (mySourceIndex < sourceLength)
{
if (myTargetIndex < targetLength)
{
mySourceChar = (UChar) mySource[mySourceIndex++];
myTarget[myTargetIndex++] = (char) (mySourceChar >> 8);
if (myTargetIndex < targetLength)
{
myTarget[myTargetIndex++] = (char) mySourceChar;
}
else
{
args->converter->charErrorBuffer[0] = (char) mySourceChar;
args->converter->charErrorBufferLength = 1;
*err = U_INDEX_OUTOFBOUNDS_ERROR;
}
}
else
{
*err = U_INDEX_OUTOFBOUNDS_ERROR;
break;
}
}
args->target += myTargetIndex;
args->source += mySourceIndex;
}
U_CFUNC UChar32 T_UConverter_getNextUChar_UTF16_BE(UConverterToUnicodeArgs* args,
UErrorCode* err)
{
UChar32 myUChar;
uint16_t first;
/*Checks boundaries and set appropriate error codes*/
if (args->source+2 > args->sourceLimit)
{
if (args->source >= args->sourceLimit)
{
/*Either caller has reached the end of the byte stream*/
*err = U_INDEX_OUTOFBOUNDS_ERROR;
}
else
{
/* a character was cut in half*/
*err = U_TRUNCATED_CHAR_FOUND;
}
return 0xffff;
}
/*Gets the corresponding codepoint*/
first = ((uint16_t)(*(args->source)) << 8) |((uint8_t)*((args->source)+1));
myUChar = first;
args->source += 2;
if(UTF_IS_FIRST_SURROGATE(first)) {
uint16_t second;
if (args->source+2 > args->sourceLimit) {
*err = U_TRUNCATED_CHAR_FOUND;
return 0xffff;
}
/* get the second surrogate and assemble the code point */
second = ((uint16_t)(*(args->source)) << 8) |((uint8_t)*(args->source+1));
/* ignore unmatched surrogates and just deliver the first one in such a case */
if(UTF_IS_SECOND_SURROGATE(second)) {
/* matched pair, get pair value */
myUChar = UTF16_GET_PAIR_VALUE(first, second);
args->source += 2;
}
}
return myUChar;
}
static const UConverterImpl _UTF16BEImpl={
UCNV_UTF16_BigEndian,
NULL,
NULL,
NULL,
NULL,
NULL,
T_UConverter_toUnicode_UTF16_BE,
NULL,
T_UConverter_fromUnicode_UTF16_BE,
NULL,
T_UConverter_getNextUChar_UTF16_BE,
NULL
};
/* Todo: verify that UTF-16BE == (ccsid (ibm-codepage) 1200) for unicode version 2.0 and 3.0 */
const UConverterStaticData _UTF16BEStaticData={
sizeof(UConverterStaticData),
"UTF16_BigEndian",
1200, UCNV_IBM, UCNV_UTF16_BigEndian, 2, 2,
2, { 0xff, 0xfd, 0, 0 }
};
const UConverterSharedData _UTF16BEData={
sizeof(UConverterSharedData), ~((uint32_t) 0),
NULL, NULL, &_UTF16BEStaticData, FALSE, &_UTF16BEImpl,
0
};
/* UTF-16LE ----------------------------------------------------------------- */
U_CFUNC void T_UConverter_toUnicode_UTF16_LE (UConverterToUnicodeArgs * args,
UErrorCode * err)
{
const unsigned char *mySource = (unsigned char *) args->source;
UChar *myTarget = args->target;
int32_t mySourceIndex = 0;
int32_t myTargetIndex = 0;
int32_t targetLength = args->targetLimit - myTarget;
int32_t sourceLength = args->sourceLimit - (char *) mySource;
UChar mySourceChar = 0x0000;
while (mySourceIndex < sourceLength)
{
if (myTargetIndex < targetLength)
{
/*gets the corresponding UniChar */
mySourceChar = (unsigned char) mySource[mySourceIndex++];
if (args->converter->toUnicodeStatus == 0x00)
{
args->converter->toUnicodeStatus = (unsigned char) mySourceChar == 0x00 ? 0xFFFF : mySourceChar;
}
else
{
if (args->converter->toUnicodeStatus == 0xFFFF) {
mySourceChar = (UChar) (mySourceChar << 8);
}
else
{
mySourceChar <<= 8;
mySourceChar |= (UChar) (args->converter->toUnicodeStatus);
}
args->converter->toUnicodeStatus = 0x00;
myTarget[myTargetIndex++] = mySourceChar;
}
}
else
{
*err = U_INDEX_OUTOFBOUNDS_ERROR;
break;
}
}
if (U_SUCCESS(*err) && args->flush
&& (mySourceIndex == sourceLength)
&& (args->converter->toUnicodeStatus != 0x00))
{
if (U_SUCCESS(*err))
{
*err = U_TRUNCATED_CHAR_FOUND;
args->converter->toUnicodeStatus = 0x00;
}
}
args->target += myTargetIndex;
args->source += mySourceIndex;
}
U_CFUNC void T_UConverter_fromUnicode_UTF16_LE (UConverterFromUnicodeArgs * args,
UErrorCode * err)
{
const UChar *mySource = args->source;
unsigned char *myTarget = (unsigned char *) args->target;
int32_t mySourceIndex = 0;
int32_t myTargetIndex = 0;
int32_t targetLength = args->targetLimit - (char *) myTarget;
int32_t sourceLength = args->sourceLimit - mySource;
UChar mySourceChar;
/*writing the char to the output stream */
while (mySourceIndex < sourceLength)
{
if (myTargetIndex < targetLength)
{
mySourceChar = (UChar) mySource[mySourceIndex++];
myTarget[myTargetIndex++] = (char) mySourceChar;
if (myTargetIndex < targetLength)
{
myTarget[myTargetIndex++] = (char) (mySourceChar >> 8);
}
else
{
args->converter->charErrorBuffer[0] = (char) (mySourceChar >> 8);
args->converter->charErrorBufferLength = 1;
*err = U_INDEX_OUTOFBOUNDS_ERROR;
}
}
else
{
*err = U_INDEX_OUTOFBOUNDS_ERROR;
break;
}
}
args->target += myTargetIndex;
args->source += mySourceIndex;
}
U_CFUNC UChar32 T_UConverter_getNextUChar_UTF16_LE(UConverterToUnicodeArgs* args,
UErrorCode* err)
{
UChar32 myUChar;
uint16_t first;
/*Checks boundaries and set appropriate error codes*/
if (args->source+2 > args->sourceLimit)
{
if (args->source >= args->sourceLimit)
{
/*Either caller has reached the end of the byte stream*/
*err = U_INDEX_OUTOFBOUNDS_ERROR;
}
else
{
/* a character was cut in half*/
*err = U_TRUNCATED_CHAR_FOUND;
}
return 0xffff;
}
/*Gets the corresponding codepoint*/
first = ((uint16_t)*((args->source)+1) << 8) | ((uint8_t)(*(args->source)));
myUChar=first;
/*updates the source*/
args->source += 2;
if (UTF_IS_FIRST_SURROGATE(first))
{
uint16_t second;
if (args->source+2 > args->sourceLimit)
{
*err = U_TRUNCATED_CHAR_FOUND;
return 0xffff;
}
/* get the second surrogate and assemble the code point */
second = ((uint16_t)*(args->source+1) << 8) |((uint8_t)(*(args->source)));
/* ignore unmatched surrogates and just deliver the first one in such a case */
if(UTF_IS_SECOND_SURROGATE(second))
{
/* matched pair, get pair value */
myUChar = UTF16_GET_PAIR_VALUE(first, second);
args->source += 2;
}
}
return myUChar;
}
static const UConverterImpl _UTF16LEImpl={
UCNV_UTF16_LittleEndian,
NULL,
NULL,
NULL,
NULL,
NULL,
T_UConverter_toUnicode_UTF16_LE,
NULL,
T_UConverter_fromUnicode_UTF16_LE,
NULL,
T_UConverter_getNextUChar_UTF16_LE,
NULL
};
/* Todo: verify that UTF-16LE == (ccsid (ibm-codepage) 1200) for unicode version 2.0 and 3.0 */
const UConverterStaticData _UTF16LEStaticData={
sizeof(UConverterStaticData),
"UTF16_LittleEndian",
1200, UCNV_IBM, UCNV_UTF16_LittleEndian, 2, 2,
2, { 0xfd, 0xff, 0, 0 }
};
const UConverterSharedData _UTF16LEData={
sizeof(UConverterSharedData), ~((uint32_t) 0),
NULL, NULL, &_UTF16LEStaticData, FALSE, &_UTF16LEImpl,
0
};