blob: e165edefce7b50f1b9b2eb009795e00f02b0710e [file] [log] [blame]
/*
**********************************************************************
* Copyright (C) 2000, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* file name: ucnv2022.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.
* 08/08/2000 Ram Included support for ISO-2022-JP-2
* Changed implementation of toUnicode
* function
*/
#include "unicode/utypes.h"
#include "cmemory.h"
#include "ucmp16.h"
#include "ucmp8.h"
#include "unicode/ucnv_err.h"
#include "ucnv_bld.h"
#include "unicode/ucnv.h"
#include "ucnv_cnv.h"
#include "unicode/ustring.h"
#include "cstring.h"
/* Added by ram for ISO-2022JP implementation*/
typedef enum {
ASCII = 0,
ISO8859_1 ,
ISO8859_7 ,
JISX201 ,
JISX208 ,
JISX212 ,
GB2312 ,
KSC5601
} StateEnum;
typedef enum {
SBCS = 0,
DBCS,
MBCS,
LATIN1
}Cnv2022Type;
typedef struct
{
UConverter *currentConverter;
UConverter *previousConverter;
UConverter *fromUnicodeConverter;
UBool isFirstBuffer;
StateEnum currentState;
uint8_t escSeq2022[10];
int8_t escSeq2022Length;
UConverter* myConverterArray[8];
int32_t targetIndex;
int32_t sourceIndex;
UBool isEscapeAppended;
UBool soAppended;
char *currentLocale;
}
UConverterDataISO2022;
/* ISO-2022 ----------------------------------------------------------------- */
U_CFUNC void T_UConverter_fromUnicode_UTF8 (UConverterFromUnicodeArgs * args,
UErrorCode * err);
U_CFUNC void T_UConverter_fromUnicode_UTF8_OFFSETS_LOGIC (UConverterFromUnicodeArgs * converter,
UErrorCode * err);
U_CFUNC void T_UConverter_fromUnicode_ISO_2022_JP(UConverterFromUnicodeArgs* args,
UErrorCode* err);
#define ESC_2022 0x1B /*ESC*/
typedef enum
{
INVALID_2022 = -1, /*Doesn't correspond to a valid iso 2022 escape sequence*/
VALID_NON_TERMINAL_2022 = 0, /*so far corresponds to a valid iso 2022 escape sequence*/
VALID_TERMINAL_2022 = 1, /*corresponds to a valid iso 2022 escape sequence*/
VALID_MAYBE_TERMINAL_2022 = 2 /*so far matches one iso 2022 escape sequence, but by adding more characters might match another escape sequence*/
/* VALID_TERMINAL_2022_DONOT_CHANGE_STATE =3 /* for ISO-2022 JP support*/
} UCNV_TableStates_2022;
/*
* The way these state transition arrays work is:
* ex : ESC$B is the sequence for JISX208
* a) First Iteration: char is ESC
* i) Get the value of ESC from normalize_esq_chars_2022[] with int value of ESC as index
* int x = normalize_esq_chars_2022[27] which is equal to 1
* ii) Search for this value in escSeqStateTable_Key_2022[]
* value of x is stored at escSeqStateTable_Key_2022[0]
* iii) Save this index as offset
* iv) Get state of this sequence from escSeqStateTable_Value_2022[]
* escSeqStateTable_Value_2022[offset], which is VALID_NON_TERMINAL_2022
* b) Switch on this state and continue to next char
* i) Get the value of $ from normalize_esq_chars_2022[] with int value of $ as index
* which is normalize_esq_chars_2022[36] == 4
* ii) x is currently 1(from above)
* x<<=5 -- x is now 32
* x+=normalize_esq_chars_2022[36]
* now x is 36
* iii) Search for this value in escSeqStateTable_Key_2022[]
* value of x is stored at escSeqStateTable_Key_2022[2], so offset is 2
* iv) Get state of this sequence from escSeqStateTable_Value_2022[]
* escSeqStateTable_Value_2022[offset], which is VALID_NON_TERMINAL_2022
* c) Switch on this state and continue to next char
* i) Get the value of B from normalize_esq_chars_2022[] with int value of B as index
* ii) x is currently 36 (from above)
* x<<=5 -- x is now 1152
* x+=normalize_esq_chars_2022[66]
* now x is 1161
* iii) Search for this value in escSeqStateTable_Key_2022[]
* value of x is stored at escSeqStateTable_Key_2022[21], so offset is 21
* iv) Get state of this sequence from escSeqStateTable_Value_2022[21]
* escSeqStateTable_Value_2022[offset], which is VALID_TERMINAL_2022
* v) Get the converter name form escSeqStateTable_Result_2022[21] which is JISX208
*/
/*Below are the 3 arrays depicting a state transition table*/
int8_t normalize_esq_chars_2022[256] = {
/* 0 1 2 3 4 5 6 7 8 9 */
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 ,1 ,0 ,0
,0 ,0 ,0 ,0 ,0 ,0 ,4 ,7 ,0 ,0
,2 ,0 ,0 ,0 ,0 ,3 ,23 ,6 ,0 ,0
,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0
,0 ,0 ,0 ,0 ,5 ,8 ,9 ,10 ,11 ,12
,13 ,14 ,15 ,16 ,17 ,18 ,19 ,20 ,0 ,0
,0 ,0 ,21 ,0 ,0 ,0 ,0 ,0 ,0 ,0
,22 ,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 ,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 ,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
};
#define MAX_STATES_2022 58
int32_t escSeqStateTable_Key_2022[MAX_STATES_2022] = {
/* 0 1 2 3 4 5 6 7 8 9 */
1 ,34 ,36 ,39 ,55 ,1093 ,1096 ,1097 ,1098 ,1099
,1100 ,1101 ,1102 ,1103 ,1104 ,1105 ,1106 ,1109 ,1154 ,1157
,1160 ,1161 ,1254 ,1257 ,1768 ,1773 ,35105 ,36933 ,36936 ,36937
,36938 ,36939 ,36940 ,36942 ,36943 ,36944 ,36945 ,36946 ,36947 ,36948
,40133 ,40136 ,40138 ,40139 ,40140 ,40141 ,1123363 ,35947624 ,35947625 ,35947626
,35947627 ,35947629 ,35947630 ,35947631 ,35947635 ,35947636 ,35947638};
const char* escSeqStateTable_Result_2022[MAX_STATES_2022] = {
/* 0 1 2 3 4 5 6 7 8 9 */
NULL ,NULL ,NULL ,NULL ,NULL ,"latin1" ,"latin1" ,"latin1" ,"ibm-865" ,"ibm-865"
,"ibm-865" ,"ibm-865" ,"ibm-865" ,"ibm-865" ,"ibm-895" ,"jisx-201" ,"latin1" ,"latin1" ,NULL ,"ibm-955"
,"GB2312" ,"jisx-208" ,NULL ,"UTF8" ,"ISO-8859-1" ,"ISO-8859-7" ,NULL ,"ibm-955" ,"bm-367" ,"ibm-952"
,"ibm-949" ,"jisx-212" ,"ibm-1383" ,"ibm-952" ,"ibm-964" ,"ibm-964" ,"ibm-964" ,"ibm-964" ,"ibm-964" ,"ibm-964"
,"UTF16_PlatformEndian" ,"UTF16_PlatformEndian" ,"UTF16_PlatformEndian" ,"UTF16_PlatformEndian" ,"UTF16_PlatformEndian" ,"UTF16_PlatformEndian" ,NULL ,"latin1" ,"ibm-912" ,"ibm-913"
,"ibm-914" ,"ibm-813" ,"ibm-1089","ibm-920" ,"ibm-915" ,"ibm-915" ,"latin1"};
UCNV_TableStates_2022 escSeqStateTable_Value_2022[MAX_STATES_2022] = {
/* 0 1 2 3 4 5 6 7 8 9 */
VALID_NON_TERMINAL_2022 ,VALID_NON_TERMINAL_2022 ,VALID_NON_TERMINAL_2022 ,VALID_NON_TERMINAL_2022 ,VALID_NON_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_MAYBE_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022
,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_NON_TERMINAL_2022 ,VALID_TERMINAL_2022
,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_NON_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_NON_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022
,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022
,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_NON_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022
,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022 ,VALID_TERMINAL_2022};
/*for 2022 looks ahead in the stream
*to determine the longest possible convertible
*data stream*/
static const char* getEndOfBuffer_2022(const char* source,
const char* sourceLimit,
UBool flush);
/*runs through a state machine to determine the escape sequence - codepage correspondance
*changes the pointer pointed to be _this->extraInfo*/
static void changeState_2022(UConverter* _this,
const char** source,
const char* sourceLimit,
UBool flush,
UErrorCode* err);
UCNV_TableStates_2022 getKey_2022(char source,
int32_t* key,
int32_t* offset);
static void
_ISO2022Open(UConverter *cnv, const char *name, const char *locale, UErrorCode *errorCode) {
void *oldContext, *newContext=NULL;
UConverterFromUCallback *oldAction=malloc(sizeof(UConverterFromUCallback));
/* cnv->charErrorBufferLength = 3;
cnv->charErrorBuffer[0] = 0x1b;
cnv->charErrorBuffer[1] = 0x25;
cnv->charErrorBuffer[2] = 0x42;*/
cnv->extraInfo = uprv_malloc (sizeof (UConverterDataISO2022));
if(cnv->extraInfo != NULL) {
UConverterDataISO2022 *myConverterData=(UConverterDataISO2022 *) cnv->extraInfo;
UConverter **array= myConverterData->myConverterArray;
if( (locale != NULL) && (uprv_strlen(locale) > 0) ) {
myConverterData->currentLocale = (char*) uprv_malloc((sizeof(char) * uprv_strlen(locale)) + 1);
uprv_strcpy(myConverterData->currentLocale,locale);
}
else {
myConverterData->currentLocale = NULL;
}
myConverterData->myConverterArray[0] =NULL;
if(locale && uprv_stricmp(locale,"jp")==0){
myConverterData->myConverterArray[0]= ucnv_open("ASCII", errorCode );
myConverterData->myConverterArray[1]= ucnv_open("ISO8859_1", errorCode);
myConverterData->myConverterArray[2]= ucnv_open("ISO8859_7", errorCode);
myConverterData->myConverterArray[3]= ucnv_open("jisx-201", errorCode);
myConverterData->myConverterArray[4]= ucnv_open("jisx-208", errorCode);
myConverterData->myConverterArray[5]= ucnv_open("jisx-212", errorCode);
myConverterData->myConverterArray[6]= ucnv_open("GB2312", errorCode);
myConverterData->myConverterArray[7]= ucnv_open("KSC5601", errorCode);
myConverterData->myConverterArray[8]= NULL;
myConverterData->currentState =0;
myConverterData->targetIndex = 0;
myConverterData->sourceIndex =0;
myConverterData->isEscapeAppended=FALSE;
myConverterData->soAppended=FALSE;
while(*array!=NULL){
ucnv_setFromUCallBack(*array,UCNV_FROM_U_CALLBACK_STOP,
newContext, oldAction,&oldContext, errorCode);
*array++;
}
myConverterData->isFirstBuffer = TRUE;
}
else{
cnv->charErrorBufferLength = 3;
cnv->charErrorBuffer[0] = 0x1b;
cnv->charErrorBuffer[1] = 0x25;
cnv->charErrorBuffer[2] = 0x42;
myConverterData->currentLocale=NULL;
}
((UConverterDataISO2022 *) cnv->extraInfo)->currentConverter = NULL;
((UConverterDataISO2022 *) cnv->extraInfo)->previousConverter = NULL;
((UConverterDataISO2022 *) cnv->extraInfo)->fromUnicodeConverter = NULL;
((UConverterDataISO2022 *) cnv->extraInfo)->escSeq2022Length = 0;
cnv->fromUnicodeStatus =FALSE;
free(oldAction);
} else {
*errorCode = U_MEMORY_ALLOCATION_ERROR;
}
}
static void
_ISO2022Close(UConverter *converter) {
UConverter **array = ((UConverterDataISO2022 *) (converter->extraInfo))->myConverterArray;
if (converter->extraInfo != NULL) {
ucnv_close (((UConverterDataISO2022 *) (converter->extraInfo))->currentConverter);
/*close the array of converter pointers and free the memory*/
while(*array!=NULL){
ucnv_close(*array++);
}
uprv_free(((UConverterDataISO2022 *) (converter->extraInfo))->currentLocale);
uprv_free (converter->extraInfo);
}
}
/*** ??? why are we going to UTF-8??*/
static void
_ISO2022Reset(UConverter *converter) {
if(!((UConverterDataISO2022 *) (converter->extraInfo))->currentLocale){
converter->charErrorBufferLength = 3;
converter->charErrorBuffer[0] = 0x1b;
converter->charErrorBuffer[1] = 0x28;
converter->charErrorBuffer[2] = 0x42;
}
if (converter->mode == UCNV_SO)
{
/* converter->charErrorBufferLength = 3;
converter->charErrorBuffer[0] = 0x1b;
converter->charErrorBuffer[1] = 0x25;
converter->charErrorBuffer[2] = 0x42;*/
ucnv_close (((UConverterDataISO2022 *) (converter->extraInfo))->currentConverter);
((UConverterDataISO2022 *) (converter->extraInfo))->currentConverter = NULL;
((UConverterDataISO2022 *) (converter->extraInfo))->escSeq2022Length = 0;
converter->mode = UCNV_SI;
}
}
U_CFUNC void T_UConverter_fromUnicode_ISO_2022(UConverterFromUnicodeArgs *args,
UErrorCode* err)
{
UConverterDataISO2022 *myConverterData=(UConverterDataISO2022*)args->converter->extraInfo;
const char *locale =myConverterData->currentLocale;
if(locale && uprv_stricmp(locale,"jp")==0){
T_UConverter_fromUnicode_ISO_2022_JP(args,err);
}else{
T_UConverter_fromUnicode_UTF8(args, err);
}
}
U_CFUNC void T_UConverter_fromUnicode_ISO_2022_OFFSETS_LOGIC(UConverterFromUnicodeArgs* args,
UErrorCode* err)
{
char const* targetStart = args->target;
UConverterDataISO2022 *myConverterData=(UConverterDataISO2022*)args->converter->extraInfo;
const char *locale =myConverterData->currentLocale;
if(locale && uprv_stricmp(locale,"jp")==0){
T_UConverter_fromUnicode_ISO_2022_JP(args,err);
}
else{
T_UConverter_fromUnicode_UTF8_OFFSETS_LOGIC(args, err);
{
int32_t len = args->target - targetStart;
int32_t i;
/* uprv_memmove(offsets+3, offsets, len); MEMMOVE SEEMS BROKEN --srl*/
for(i=len-1;i>=0;i--) args->offsets[i] = args->offsets[i];
}
}
}
/*************************** BEGIN ****************************/
/************************************** IMPORTANT **************************************************
* The T_fromUnicode_ISO2022_JP converter doesnot use ucnv_fromUnicode() functions for SBCS and DBCS,
* instead the values are obtained directly by accessing the sharedData structs through ucmp8_getU()
* and ucmp16_getU() macros to increase speed, reduce the overhead of function call and make it
* efficient.The converter iterates over each Unicode codepoint to obtain the equivalent codepoints
* from the codepages supported. Since the source buffer is processed one char at a time it would
* make sense to reduce the extra processing a canned converter would do as far as possible.
*
* If the implementation of these macros or structure of sharedData struct change in the future, make
* sure that ISO-2022-JP is also changed.
***************************************************************************************************
*/
/***************************************************************************************************
* Rules for ISO-2022-jp encoding
* (i) Escape sequences must be fully contained within a line they should not
* span new lines or CRs
* (ii) If the last character on a line is represented by two bytes then an ASCII or
* JIS-Roman character escape sequence should follow before the line terminates
* (iii) If the first character on the line is represented by two bytes then a two
* byte character escape sequence should precede it
* (iv) If no escape sequence is encountered then the characters are ASCII
* (v) Latin(ISO-8859-1) and Greek(ISO-8859-7) characters must be designated to G2,
* and invoked with SS2 (ESC N).
* (vi) If there is any G0 designation in text, there must be a switch to
* ASCII or to JIS X 0201-Roman before a space character (but not
* necessarily before "ESC 4/14 2/0" or "ESC N ' '") or control
* characters such as tab or CRLF.
* (vi) Supported encodings:
* ASCII, JISX201, JISX208, JISX212, GB2312, KSC5601, ISO-8859-1,ISO-8859-7
*
* source : RFC-1554
*
* JISX201, JISX208,JISX212 : new .cnv data files created
* KSC5601 : alias to ibm-949 mapping table
* GB2312 : alias to ibm-1386 mapping table
* ISO-8859-1 : Algorithmic implemented as LATIN1 case
* ISO-8859-7 : alisas to ibm-9409 mapping table
*/
static Cnv2022Type myConverterType[8]={
SBCS,
LATIN1,
SBCS,
SBCS,
DBCS,
DBCS,
MBCS,
MBCS,
};
#define UCNV_SS2 "\x0BN"
#define ESC 0x0B
static const char* escSeqChars[8] ={
"\x1B\x28\x42",
"\x1B\x2E\x41",
"\x1B\x2E\x46",
"\x1B\x28\x4A",
"\x1B\x24\x42",
"\x1B\x24\x28\x44",
"\x1B\x24\x41",
"\x1B\x24\x28\x43",
};
static void concatChar(UConverterFromUnicodeArgs* args, int32_t *targetIndex, int32_t *targetLength,
int8_t charToAppend,UErrorCode* err);
static void concatEscape(UConverterFromUnicodeArgs* args, int32_t *targetIndex, int32_t *targetLength,
const char* strToAppend,UErrorCode* err,int len);
static void concatString(UConverterFromUnicodeArgs* args, int32_t *targetIndex, int32_t *targetLength,
const UChar* strToAppend,UErrorCode* err,int32_t *sourceIndex);
/*
* The iteration over various code pages works this way:
* i) Get the currentState from myConverterData->currentState
* ii) Check if the character is mapped to a valid character in the currentState
* Yes -> a) set the initIterState to currentState
* b) remain in this state until an invalid character is found
* No -> a) go to the next code page and find the character
* iii) Before changing the state increment the current state check if the current state
* is equal to the intitIteration state
* Yes -> A character that cannot be represented in any of the supported encodings
* break and return a U_INVALID_CHARACTER error
* No -> Continue and find the character in next code page
*
* Offsets Logic is handled by utility functions concatChar(), concatEscape() and concatString()
*
*/
U_CFUNC void T_UConverter_fromUnicode_ISO_2022_JP(UConverterFromUnicodeArgs* args, UErrorCode* err){
UChar* mySource =(UChar*)args->source;
UConverterDataISO2022 *myConverterData=(UConverterDataISO2022*)args->converter->extraInfo;
UConverterCallbackReason reason;
UBool isEscapeAppended = FALSE;
StateEnum initIterState;
unsigned char *myTarget = (unsigned char *) args->target;
char *uBuf =(char*) malloc(sizeof(char) * 4);
char *targetChar;
char *targetLimit;
const UChar *saveSource;
char *saveTarget;
int32_t *saveOffsets ;
const UChar* mySourceLimit;
int32_t myTargetLength = args->targetLimit - args->target;
int32_t mySourceLength = args->sourceLimit - args->source;
int32_t mySourceIndex = 0;
int32_t myTargetIndex = 0;
CompactShortArray *myFromUnicodeDBCS = NULL;
CompactShortArray *myFromUnicodeDBCSFallback = NULL;
CompactByteArray *myFromUnicodeSBCS = NULL;
CompactByteArray *myFromUnicodeSBCSFallback = NULL;
UChar targetUniChar = missingCharMarker;
StateEnum currentState=0;
Cnv2022Type myType;
UChar mySourceChar = 0x0000;
UChar *sourceCharPtr=NULL;
int iterCount = 0;
const char *escSeq = NULL;
UBool soAppended = FALSE;
UBool isTargetUCharDBCS=FALSE,oldIsTargetUCharDBCS=FALSE;
mySourceIndex = myConverterData->sourceIndex;
myTargetIndex = myConverterData->targetIndex;
isEscapeAppended =(UBool) myConverterData->isEscapeAppended;
soAppended =(UBool) myConverterData->soAppended;
initIterState =0;
/* arguments check*/
if ((args->converter == NULL) || (args->targetLimit < args->target) || (args->sourceLimit < args->source)){
*err = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
while(mySourceIndex < mySourceLength){
currentState = myConverterData->currentState;
myConverterData->fromUnicodeConverter = (myConverterData->fromUnicodeConverter == NULL) ?
myConverterData->myConverterArray[0] :
myConverterData->myConverterArray[(int)myConverterData->currentState];
isTargetUCharDBCS = (UBool) args->converter->fromUnicodeStatus;
if(myTargetIndex < myTargetLength){
mySourceChar = (UChar) args->source[mySourceIndex++];
myType= (Cnv2022Type) myConverterType[currentState];
/* I am handling surrogates in the begining itself so that I donot have to go through 8
* iterations on codepages that we support.
*/
if(UTF_IS_LEAD(mySourceChar)){
args->converter->invalidUCharBuffer[0] = (UChar)mySource[mySourceIndex - 1];
args->converter->invalidUCharLength = 1;
/*mySourceIndex has already been incremented*/
if(mySourceIndex < mySourceLength){
if(UTF_IS_TRAIL(mySource[mySourceIndex])){
args->converter->invalidUCharBuffer[1] = (UChar)mySource[mySourceIndex];
args->converter->invalidUCharLength++;
mySourceIndex++;
continue;
}
else if (args->flush == TRUE){
reason = UCNV_ILLEGAL;
*err = U_TRUNCATED_CHAR_FOUND;
goto CALLBACK;
}
else{
reason=UCNV_ILLEGAL;
goto CALLBACK;
}
}
else{
args->converter->invalidUCharBuffer[1] = (UChar)mySource[mySourceIndex];
continue;
}
}
else if(UTF_IS_TRAIL(mySourceChar)){
if(args->converter->fromUSurrogateLead == 0){
reason = UCNV_ILLEGAL;
goto CALLBACK;
}
else{
/* the only way we can arrive here is if UTF lead surrogate was found
* at the end of previous buffer. So we need to check if the current
* current source index is 0 or not
*/
if(mySourceIndex-1 ==0){
args->converter->invalidUCharBuffer[1] = (UChar)mySource[mySourceIndex];
args->converter->invalidUCharLength++;
mySourceIndex++;
continue;
}
else{
reason=UCNV_ILLEGAL;
goto CALLBACK;
}
}
}
/*Do the conversion*/
else if(mySourceChar == 0x0020){
targetUniChar = mySourceChar;
if(currentState > 2){
concatEscape(args, &myTargetIndex, &myTargetLength, escSeqChars[0],err,strlen(escSeqChars[0]));
if(*err ==U_BUFFER_OVERFLOW_ERROR){
/*save the state and return */
args->target += myTargetIndex;
args->source += mySourceIndex;
myConverterData->sourceIndex = 0;
myConverterData->targetIndex = 0;
args->converter->fromUnicodeStatus = isTargetUCharDBCS;
return;
}
}
}
/* if the source character is CR or LF then append the ASCII escape sequence*/
else if(mySourceChar== 0x000A || mySourceChar== 0x000D){
if(isTargetUCharDBCS && mySource[mySourceIndex-2]!=0x000A){
concatEscape(args, &myTargetIndex, &myTargetLength, escSeqChars[0],err,strlen(escSeqChars[0]));
isTargetUCharDBCS=FALSE;
soAppended =FALSE;
myConverterData->soAppended=FALSE;
if(*err ==U_BUFFER_OVERFLOW_ERROR){
/*save the state and return */
args->target += myTargetIndex;
args->source += mySourceIndex;
myConverterData->sourceIndex = 0;
myConverterData->targetIndex = 0;
args->converter->fromUnicodeStatus = isTargetUCharDBCS;
return;
}
}
targetUniChar = mySourceChar;
concatString(args, &myTargetIndex, &myTargetLength,&targetUniChar,err,&mySourceIndex);
if(currentState==ISO8859_1 || currentState ==ISO8859_7)
isEscapeAppended =FALSE;
if(*err ==U_BUFFER_OVERFLOW_ERROR)
break;
continue;
}
else{
switch (myType){
case SBCS:
myFromUnicodeSBCS = &myConverterData->fromUnicodeConverter->sharedData->table->sbcs.fromUnicode;
myFromUnicodeSBCSFallback = &myConverterData->fromUnicodeConverter->sharedData->table->sbcs.fromUnicodeFallback;
targetUniChar = (UChar) ucmp8_getu (myFromUnicodeSBCS, mySourceChar);
if ((targetUniChar==0)&&(myConverterData->fromUnicodeConverter->useFallback == TRUE) &&
(myConverterData->fromUnicodeConverter->sharedData->staticData->hasFromUnicodeFallback == TRUE)){
targetUniChar = (UChar) ucmp8_getu (myFromUnicodeSBCSFallback, mySourceChar);
}
/* ucmp8_getU returns 0 for missing char so explicitly set it missingCharMarker*/
targetUniChar=(UChar)((targetUniChar==0) ? (UChar) missingCharMarker : targetUniChar);
break;
case DBCS:
myFromUnicodeDBCS = &myConverterData->fromUnicodeConverter->sharedData->table->dbcs.fromUnicode;
myFromUnicodeDBCSFallback = &myConverterData->fromUnicodeConverter->sharedData->table->dbcs.fromUnicodeFallback;
targetUniChar = (UChar) ucmp16_getu (myFromUnicodeDBCS, mySourceChar);
if ((targetUniChar==missingCharMarker)&&(myConverterData->fromUnicodeConverter->useFallback == TRUE) &&
(myConverterData->fromUnicodeConverter->sharedData->staticData->hasFromUnicodeFallback == TRUE)){
targetUniChar = (UChar) ucmp16_getu (myFromUnicodeDBCSFallback, mySourceChar);
}
break;
case MBCS:
sourceCharPtr =&mySourceChar;
mySourceLimit= sourceCharPtr+1;
targetChar =uBuf;
targetLimit = uBuf+4;
ucnv_fromUnicode(myConverterData->fromUnicodeConverter,
&targetChar,targetLimit,
&sourceCharPtr,
mySourceLimit,args->offsets,args->flush,err);
if(U_FAILURE(*err)){
targetUniChar = missingCharMarker;
*err =U_ZERO_ERROR;
}else{
/*convert to targetUniChar*/
uint8_t len=(uint8_t)(targetChar-uBuf);
targetChar=uBuf;
targetUniChar=0;
/* the below switch structure is not required since IS2022-JP-2
* supports only DBCS char sets. Reverse engineered from DBCS code.
* the cases fall through without break
*/
switch(len){
case 4:
targetUniChar+=(uint32_t)((uint8_t)(*targetChar++))<<24;
case 3:
targetUniChar+=(uint32_t)((uint8_t)(*targetChar++))<<16;
case 2:
targetUniChar+=(uint32_t)((uint8_t)(*targetChar++))<<8;
case 1:
targetUniChar+=(uint8_t)(*targetChar);
default:
break;
}
}
break;
case LATIN1:
if(mySourceChar < 0x0100){
targetUniChar = mySourceChar;
} else targetUniChar = missingCharMarker;
break;
default:
/*not expected */
break;
}
}
if(targetUniChar!= missingCharMarker){
oldIsTargetUCharDBCS = isTargetUCharDBCS;
isTargetUCharDBCS =(UBool) (targetUniChar >0x00FF);
args->converter->fromUnicodeStatus= isTargetUCharDBCS;
/* set the iteration state and iteration count */
initIterState = currentState;
iterCount =0;
/* Append the escpace sequence */
if(!isEscapeAppended){
escSeq = escSeqChars[(int)currentState];
concatEscape(args, &myTargetIndex, &myTargetLength,
escSeqChars[(int)currentState],
err,strlen(escSeqChars[(int)currentState]));
isEscapeAppended =TRUE;
myConverterData->isEscapeAppended=TRUE;
if(*err ==U_BUFFER_OVERFLOW_ERROR){
/*save the state and return */
args->target += myTargetIndex;
args->source += mySourceIndex;
myConverterData->sourceIndex = 0;
myConverterData->targetIndex = 0;
args->converter->fromUnicodeStatus = isTargetUCharDBCS;
return;
}
/* Append SSN for shifting to G2 */
if(currentState==ISO8859_1 || currentState==ISO8859_7){
concatEscape(args, &myTargetIndex, &myTargetLength,
UCNV_SS2,err,strlen(UCNV_SS2));
if(*err ==U_BUFFER_OVERFLOW_ERROR){
/*save the state and return */
args->target += myTargetIndex;
args->source += mySourceIndex;
myConverterData->sourceIndex = 0;
myConverterData->targetIndex = 0;
args->converter->fromUnicodeStatus = isTargetUCharDBCS;
return;
}
}
}
else{
if(oldIsTargetUCharDBCS != isTargetUCharDBCS ){
/*Shifting from a double byte to single byte mode*/
if(!isTargetUCharDBCS){
concatChar(args, &myTargetIndex,
&myTargetLength, UCNV_SI,err);
soAppended =FALSE;
if(*err ==U_BUFFER_OVERFLOW_ERROR){
/*save the state and return */
args->target += myTargetIndex;
args->source += mySourceIndex;
myConverterData->sourceIndex = 0;
myConverterData->targetIndex = 0;
args->converter->fromUnicodeStatus = isTargetUCharDBCS;
return;
}
}
else{ /* Shifting from a single byte to double byte mode*/
concatChar(args, &myTargetIndex,
&myTargetLength, UCNV_SO,err);
soAppended =TRUE;
myConverterData->soAppended =soAppended;
if(*err ==U_BUFFER_OVERFLOW_ERROR){
/*save the state and return */
args->target += myTargetIndex;
args->source += mySourceIndex;
myConverterData->sourceIndex = 0;
myConverterData->targetIndex = 0;
args->converter->fromUnicodeStatus = isTargetUCharDBCS;
return;
}
}
}
}
concatString(args, &myTargetIndex, &myTargetLength,
&targetUniChar,err, &mySourceIndex);
if(*err ==U_BUFFER_OVERFLOW_ERROR){
/*save the state and return */
args->target += myTargetIndex;
args->source += mySourceIndex;
myConverterData->sourceIndex = 0;
myConverterData->targetIndex = 0;
args->converter->fromUnicodeStatus = isTargetUCharDBCS;
return;
}
}/* end of end if(targetUniChar==missingCharMarker)*/
else{
myConverterData->currentState=currentState=(currentState<7)? currentState+1:0;
iterCount = (iterCount<8)? iterCount+1 : 0;
if((currentState!= initIterState) ){
/* explicitly decrement source since it has already been incremented */
mySourceIndex--;
targetUniChar =missingCharMarker;
isEscapeAppended = FALSE;
/* save the state */
myConverterData->isEscapeAppended = isEscapeAppended;
myConverterData->soAppended =soAppended;
args->converter->fromUnicodeStatus = isTargetUCharDBCS;
myConverterData->sourceIndex = mySourceIndex;
myConverterData->targetIndex = myTargetIndex;
continue;
}
else{
/* if we cannot find the character after checking all codepages
* then this is an error
*/
reason = UCNV_UNASSIGNED;
*err = U_INVALID_CHAR_FOUND;
CALLBACK:
saveSource = args->source;
saveTarget = args->target;
saveOffsets = args->offsets;
args->target = (char*)myTarget + myTargetIndex;
args->source = mySource + mySourceIndex;
myConverterData->isEscapeAppended = isEscapeAppended;
myConverterData->soAppended =soAppended;
args->converter->fromUnicodeStatus = isTargetUCharDBCS;
myConverterData->sourceIndex = mySourceIndex;
myConverterData->targetIndex = myTargetIndex;
FromU_CALLBACK_MACRO(args->converter->fromUContext,
args,
args->converter->invalidUCharBuffer,
args->converter->invalidUCharLength,
(UChar32) (args->converter->invalidUCharLength == 2 ?
UTF16_GET_PAIR_VALUE(args->converter->invalidUCharBuffer[0],
args->converter->invalidUCharBuffer[1])
: args->converter->invalidUCharBuffer[0]),
reason,
err);
args->source = saveSource;
args->target = saveTarget;
args->offsets = saveOffsets;
if (U_FAILURE (*err)){
break;
}
args->converter->invalidUCharLength = 0;
}
}
} /* end if(myTargetIndex<myTargetLength) */
else{
*err =U_BUFFER_OVERFLOW_ERROR;
break;
}
}/* end while(mySourceIndex<mySourceLength) */
free(uBuf); /* free the malloced memory */
/*save the state and return */
args->target += myTargetIndex;
args->source += mySourceIndex;
myConverterData->sourceIndex = 0;
myConverterData->targetIndex = 0;
args->converter->fromUnicodeStatus = isTargetUCharDBCS;
}
static void concatString(UConverterFromUnicodeArgs* args, int32_t *targetIndex, int32_t *targetLength,
const UChar* strToAppend,UErrorCode* err, int32_t *sourceIndex){
if(*strToAppend < 0x00FF){
if( (*targetIndex)+1 >= *targetLength){
args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] = (unsigned char) *strToAppend;
*err = U_BUFFER_OVERFLOW_ERROR;
}else{
args->target[*targetIndex] = (unsigned char) *strToAppend;
if(args->offsets!=NULL){
args->offsets[*targetIndex] = *sourceIndex-1;
}
(*targetIndex)++;
}
}
else{
if(*targetIndex < *targetLength){
args->target[*targetIndex] =(unsigned char) (*strToAppend>>8);
if(args->offsets!=NULL){
args->offsets[*targetIndex] = *sourceIndex-1;
}
(*targetIndex)++;
if(*targetIndex < *targetLength){
args->target[(*targetIndex)] =(unsigned char) (*strToAppend & 0x00FF);
if(args->offsets!=NULL){
args->offsets[*targetIndex] = *sourceIndex-1;
}
(*targetIndex)++;
}
else{
args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] = (unsigned char) (*strToAppend & 0x00FF);
*err = U_BUFFER_OVERFLOW_ERROR;
}
}
else{
args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] = (unsigned char) (*strToAppend>>8);
args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] = (unsigned char) (*strToAppend & 0x00FF);
*err = U_BUFFER_OVERFLOW_ERROR;
if(args->offsets!=NULL){
args->offsets[*targetIndex] = *sourceIndex-1;
}
}
}
}
static void concatEscape(UConverterFromUnicodeArgs* args, int32_t *targetIndex, int32_t *targetLength,
const char* strToAppend,UErrorCode* err,int len){
while(len-->0){
if(*targetIndex < *targetLength){
args->target[(*targetIndex)++] = (unsigned char) *strToAppend;
}
else{
args->converter->charErrorBuffer[(int)args->converter->charErrorBufferLength++] = (unsigned char) *strToAppend;
*err =U_BUFFER_OVERFLOW_ERROR;
}
strToAppend++;
}
}
static void concatChar(UConverterFromUnicodeArgs* args, int32_t *targetIndex, int32_t *targetLength,
int8_t charToAppend,UErrorCode* err){
if( *targetIndex < *targetLength){
args->target[(*targetIndex)++] = (unsigned char) charToAppend;
}else{
args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] = (unsigned char) charToAppend;
*err = U_BUFFER_OVERFLOW_ERROR;
}
}
/*************** to unicode *******************/
UCNV_TableStates_2022 getKey_2022(char c,
int32_t* key,
int32_t* offset){
int32_t togo = *key;
int32_t low = 0;
int32_t hi = MAX_STATES_2022;
int32_t oldmid=0;
if (*key == 0){
togo = (int8_t)normalize_esq_chars_2022[c];
}
else{
togo <<= 5;
togo += (int8_t)normalize_esq_chars_2022[c];
}
while (hi != low) /*binary search*/{
register int32_t mid = (hi+low) >> 1; /*Finds median*/
if (mid == oldmid)
break;
if (escSeqStateTable_Key_2022[mid] > togo){
hi = mid;
}
else if (escSeqStateTable_Key_2022[mid] < togo){
low = mid;
}
else /*we found it*/{
*key = togo;
*offset = mid;
return escSeqStateTable_Value_2022[mid];
}
oldmid = mid;
}
*key = 0;
*offset = 0;
return INVALID_2022;
}
void changeState_2022(UConverter* _this,
const char** source,
const char* sourceLimit,
UBool flush,
UErrorCode* err){
UConverter* myUConverter;
uint32_t key = _this->toUnicodeStatus;
UCNV_TableStates_2022 value;
UConverterDataISO2022* myData2022 = ((UConverterDataISO2022*)_this->extraInfo);
const char* chosenConverterName = NULL;
int32_t offset;
/*In case we were in the process of consuming an escape sequence
we need to reprocess it */
do{
/* Needed explicit cast for key on MVS to make compiler happy - JJD */
value = getKey_2022(**source,(int32_t *) &key, &offset);
switch (value){
case VALID_NON_TERMINAL_2022 :
break;
case VALID_TERMINAL_2022:
{
(*source)++;
chosenConverterName = escSeqStateTable_Result_2022[offset];
key = 0;
goto DONE;
};
break;
case INVALID_2022:
{
_this->toUnicodeStatus = 0;
*err = U_ILLEGAL_CHAR_FOUND;
return;
}
case VALID_MAYBE_TERMINAL_2022:
{
const char* mySource = (*source+1);
int32_t myKey = key;
UCNV_TableStates_2022 myValue = value;
int32_t myOffset=0;
if(*mySource==ESC_2022){
while ((mySource < sourceLimit) &&
((myValue == VALID_MAYBE_TERMINAL_2022)||(myValue == VALID_NON_TERMINAL_2022))){
myValue = getKey_2022(*(mySource++), &myKey, &myOffset);
}
}
else{
(*source)++;
myValue=1;
myOffset = 5;
}
switch (myValue){
case INVALID_2022:
{
/*Backs off*/
chosenConverterName = escSeqStateTable_Result_2022[offset];
value = VALID_TERMINAL_2022;
goto DONE;
};
break;
case VALID_TERMINAL_2022:
{
/*uses longer escape sequence*/
chosenConverterName = escSeqStateTable_Result_2022[myOffset];
key = 0;
value = VALID_TERMINAL_2022;
goto DONE;
};
break;
case VALID_NON_TERMINAL_2022:
case VALID_MAYBE_TERMINAL_2022:
{
if (flush){
/*Backs off*/
chosenConverterName = escSeqStateTable_Result_2022[offset];
value = VALID_TERMINAL_2022;
key = 0;
goto DONE;
}
else{
key = myKey;
value = VALID_NON_TERMINAL_2022;
}
};
break;
};
break;
};
break;
}
}while (++(*source) < sourceLimit);
DONE:
_this->toUnicodeStatus = key;
if ((value == VALID_NON_TERMINAL_2022) || (value == VALID_MAYBE_TERMINAL_2022)) {
return;
}
if (value > 0) {
if(uprv_strcmp(chosenConverterName,"latin1")==0 && uprv_strcmp(myData2022->currentLocale,"jp")==0){
_this->mode = UCNV_SI;
myUConverter =myData2022->currentConverter;
}
else{
_this->mode = UCNV_SI;
ucnv_close(myData2022->currentConverter);
myData2022->currentConverter = myUConverter = ucnv_open(chosenConverterName, err);
}
if (U_SUCCESS(*err)){
/*Customize the converter with the attributes set on the 2022 converter*/
myUConverter->fromUCharErrorBehaviour = _this->fromUCharErrorBehaviour;
myUConverter->fromUContext = _this->fromUContext;
myUConverter->fromCharErrorBehaviour = _this->fromCharErrorBehaviour;
myUConverter->toUContext = _this->toUContext;
uprv_memcpy(myUConverter->subChar,
_this->subChar,
myUConverter->subCharLen = _this->subCharLen);
_this->mode = UCNV_SO;
}
}
return;
}
/*Checks the characters of the buffer against valid 2022 escape sequences
*if the match we return a pointer to the initial start of the sequence otherwise
*we return sourceLimit
*/
const char* getEndOfBuffer_2022(const char* source,
const char* sourceLimit,
UBool flush){
const char* mySource = source;
if (source >= sourceLimit)
return sourceLimit;
do{
if (*mySource == ESC_2022){
int8_t i;
int32_t key = 0;
int32_t offset;
UCNV_TableStates_2022 value = VALID_NON_TERMINAL_2022;
/* check for SS2*/
if(*mySource+1 == 0x4E){
if(mySource == source){
source++;
source++;
return getEndOfBuffer_2022(source,sourceLimit,flush);
}
else{
return mySource;
}
}
for (i=0;
(mySource+i < sourceLimit)&&(value == VALID_NON_TERMINAL_2022);
i++) {
value = getKey_2022(*(mySource+i), &key, &offset);
}
if (value > 0)
return mySource;
if ((value == VALID_NON_TERMINAL_2022)&&(!flush) )
return sourceLimit;
}
else if(*mySource == (char)UCNV_SI || *mySource==(char)UCNV_SO){
if(mySource == source){
source++;
return getEndOfBuffer_2022(source,sourceLimit,flush);
}
else{
return mySource;
}
}
}while (mySource++ < sourceLimit);
return sourceLimit;
}
U_CFUNC void T_UConverter_toUnicode_ISO_2022(UConverterToUnicodeArgs *args,
UErrorCode* err){
const char *mySourceLimit;
char const* sourceStart;
UConverter *saveThis;
/*Arguments Check*/
if (U_FAILURE(*err))
return;
if ((args->converter == NULL) || (args->targetLimit < args->target) || (args->sourceLimit < args->source)){
*err = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
do{
/*Find the end of the buffer e.g : Next Escape Seq | end of Buffer*/
mySourceLimit = getEndOfBuffer_2022(args->source, args->sourceLimit, args->flush);
if (args->converter->mode == UCNV_SO) /*Already doing some conversion*/{
saveThis = args->converter;
args->offsets = NULL;
args->converter = ((UConverterDataISO2022*)(args->converter->extraInfo))->currentConverter;
ucnv_toUnicode(args->converter,
&args->target,
args->targetLimit,
&args->source,
mySourceLimit,
args->offsets,
args->flush,
err);
args->converter = saveThis;
}
/* in ISO-2022-jp the characters preceeding any escape sequence are assumed
* to be ASCII so we need to explicitly check for it
*/
if((((UConverterDataISO2022 *)args->converter->extraInfo)->isFirstBuffer) && (args->source[0]!=(char)ESC_2022)
&& (((UConverterDataISO2022*)(args->converter->extraInfo))->currentConverter==NULL)){
saveThis = args->converter;
args->offsets = NULL;
((UConverterDataISO2022*)(args->converter->extraInfo))->currentConverter = ucnv_open("ASCII",err);
if(U_FAILURE(*err)){
break;
}
args->converter = ((UConverterDataISO2022*)(args->converter->extraInfo))->currentConverter;
ucnv_toUnicode(args->converter,
&args->target,
args->targetLimit,
&args->source,
mySourceLimit,
args->offsets,
args->flush,
err);
args->converter = saveThis;
args->converter->mode = UCNV_SO;
((UConverterDataISO2022*)(args->converter->extraInfo))->isFirstBuffer=FALSE;
}
/*-Done with buffer with entire buffer
-Error while converting
*/
if (U_FAILURE(*err) || (args->source == args->sourceLimit))
return;
sourceStart = args->source;
changeState_2022(args->converter,
&(args->source),
args->sourceLimit,
args->flush,
err);
/* args->source = sourceStart; */
}while(args->source < args->sourceLimit);
((UConverterDataISO2022*)(args->converter->extraInfo))->isFirstBuffer=FALSE;
return;
}
U_CFUNC void T_UConverter_toUnicode_ISO_2022_OFFSETS_LOGIC(UConverterToUnicodeArgs* args,
UErrorCode* err){
int32_t myOffset=0;
int32_t base = 0;
const char* mySourceLimit;
char const* sourceStart;
UConverter* _this = NULL;
/*Arguments Check*/
if (U_FAILURE(*err))
return;
if ((args->converter == NULL) || (args->targetLimit < args->target) || (args->sourceLimit < args->source)){
*err = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
do{
mySourceLimit = getEndOfBuffer_2022(args->source, args->sourceLimit, args->flush);
/*Find the end of the buffer e.g : Next Escape Seq | end of Buffer*/
if (args->converter->mode == UCNV_SO) /*Already doing some conversion*/{
const UChar* myTargetStart = args->target;
_this = args->converter;
args->converter = ((UConverterDataISO2022*)(_this->extraInfo))->currentConverter;
ucnv_toUnicode(args->converter,
&(args->target),
args->targetLimit,
&(args->source),
mySourceLimit,
args->offsets,
args->flush,
err);
args->converter = _this;
{
int32_t lim = args->target - myTargetStart;
int32_t i = 0;
for (i=base; i < lim;i++){
args->offsets[i] += myOffset;
}
base += lim;
}
}
if(((UConverterDataISO2022 *)args->converter->extraInfo)->isFirstBuffer && args->source[0]!=ESC_2022
&& ((UConverterDataISO2022*)(args->converter->extraInfo))->currentConverter==NULL){
const UChar* myTargetStart = args->target;
UConverter* saveThis = args->converter;
args->offsets = NULL;
((UConverterDataISO2022*)(args->converter->extraInfo))->currentConverter = ucnv_open("ASCII",err);
if(U_FAILURE(*err)){
break;
}
args->converter = ((UConverterDataISO2022*)(args->converter->extraInfo))->currentConverter;
ucnv_toUnicode(args->converter,
&args->target,
args->targetLimit,
&args->source,
mySourceLimit,
args->offsets,
args->flush,
err);
args->converter = saveThis;
args->converter->mode = UCNV_SO;
((UConverterDataISO2022*)(args->converter->extraInfo))->isFirstBuffer=FALSE;
args->converter = _this;
{
int32_t lim = args->target - myTargetStart;
int32_t i = 0;
for (i=base; i < lim;i++){
args->offsets[i] += myOffset;
}
base += lim;
}
}
/*-Done with buffer with entire buffer
-Error while converting
*/
if (U_FAILURE(*err) || (args->source == args->sourceLimit))
return;
sourceStart = args->source;
changeState_2022(args->converter,
&(args->source),
args->sourceLimit,
args->flush,
err);
myOffset += args->source - sourceStart;
}while(mySourceLimit != args->sourceLimit);
return;
}
/******************************* END *****************************/
U_CFUNC UChar32 T_UConverter_getNextUChar_ISO_2022(UConverterToUnicodeArgs* args,
UErrorCode* err)
{
const char* mySourceLimit;
/*Arguments Check*/
if (args->sourceLimit < args->source){
*err = U_ILLEGAL_ARGUMENT_ERROR;
return 0xffff;
}
do{
mySourceLimit = getEndOfBuffer_2022(args->source, args->sourceLimit, TRUE);
/*Find the end of the buffer e.g : Next Escape Seq | end of Buffer*/
if (args->converter->mode == UCNV_SO) /*Already doing some conversion*/{
return ucnv_getNextUChar(((UConverterDataISO2022*)(args->converter->extraInfo))->currentConverter,
&(args->source),
mySourceLimit,
err);
}
/*-Done with buffer with entire buffer
*-Error while converting
*/
changeState_2022(args->converter,
&(args->source),
args->sourceLimit,
TRUE,
err);
}while(args->source < args->sourceLimit);
return 0xffff;
}
static const UConverterImpl _ISO2022Impl={
UCNV_ISO_2022,
NULL,
NULL,
_ISO2022Open,
_ISO2022Close,
_ISO2022Reset,
T_UConverter_toUnicode_ISO_2022,
T_UConverter_toUnicode_ISO_2022_OFFSETS_LOGIC,
T_UConverter_fromUnicode_ISO_2022,
T_UConverter_fromUnicode_ISO_2022_OFFSETS_LOGIC,
T_UConverter_getNextUChar_ISO_2022,
NULL
};
const UConverterStaticData _ISO2022StaticData={
sizeof(UConverterStaticData),
"ISO_2022",
2022, UCNV_IBM, UCNV_ISO_2022, 1, 4,
1, { 0x1a, 0, 0, 0 }, FALSE, FALSE,
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} /* reserved */
};
const UConverterSharedData _ISO2022Data={
sizeof(UConverterSharedData), ~((uint32_t) 0),
NULL, NULL, &_ISO2022StaticData, FALSE, &_ISO2022Impl,
0
};
/* EBCDICStateful ----------------------------------------------------------- */
U_CFUNC void
_DBCSLoad(UConverterSharedData *sharedData, const uint8_t *raw, UErrorCode *pErrorCode);
U_CFUNC void
_DBCSUnload(UConverterSharedData *sharedData);
U_CFUNC void T_UConverter_toUnicode_EBCDIC_STATEFUL (UConverterToUnicodeArgs *args,
UErrorCode * err)
{
char *mySource = (char *) args->source;
UChar *myTarget = args->target;
int32_t mySourceIndex = 0;
int32_t myTargetIndex = 0;
int32_t targetLength = args->targetLimit - args->target;
int32_t sourceLength = args->sourceLimit - args->source;
CompactShortArray *myToUnicode = NULL;
UChar targetUniChar = 0x0000;
UChar mySourceChar = 0x0000;
int32_t myMode = args->converter->mode;
myToUnicode = &(args->converter->sharedData->table->dbcs.toUnicode);
while (mySourceIndex < sourceLength)
{
if (myTargetIndex < targetLength)
{
/*gets the corresponding UniChar */
mySourceChar = (unsigned char) (args->source[mySourceIndex++]);
if (mySourceChar == UCNV_SI) myMode = UCNV_SI;
else if (mySourceChar == UCNV_SO) myMode = UCNV_SO;
else if ((myMode == UCNV_SO) &&
(args->converter->toUnicodeStatus == 0x00))
{
args->converter->toUnicodeStatus = (unsigned char) mySourceChar;
}
else
{
/*In case there is a state, we update the source char
*by concatenating the previous char with the current
*one
*/
if (args->converter->toUnicodeStatus != 0x00)
{
mySourceChar |= (UChar) (args->converter->toUnicodeStatus << 8);
args->converter->toUnicodeStatus = 0x00;
}
else mySourceChar &= 0x00FF;
/*gets the corresponding Unicode codepoint */
targetUniChar = (UChar) ucmp16_getu (myToUnicode, mySourceChar);
/*writing the UniChar to the output stream */
if (targetUniChar < 0xfffe)
{
/*writes the UniChar to the output stream */
args->target[myTargetIndex++] = targetUniChar;
}
else
{
const char* saveSource = args->source;
UChar* saveTarget = args->target;
int32_t *saveOffsets = args->offsets;
UConverterCallbackReason reason;
if (targetUniChar == 0xfffe)
{
reason = UCNV_UNASSIGNED;
*err = U_INVALID_CHAR_FOUND;
}
else
{
reason = UCNV_ILLEGAL;
*err = U_ILLEGAL_CHAR_FOUND;
}
if (mySourceChar > 0xff)
{
args->converter->invalidCharLength = 2;
args->converter->invalidCharBuffer[0] = (char) (mySourceChar >> 8);
args->converter->invalidCharBuffer[1] = (char) mySourceChar;
}
else
{
args->converter->invalidCharLength = 1;
args->converter->invalidCharBuffer[0] = (char) mySourceChar;
}
args->converter->mode = myMode;
args->target += myTargetIndex;
args->source += mySourceIndex;
ToU_CALLBACK_MACRO(args->converter->toUContext,
args,
args->converter->invalidCharBuffer,
args->converter->invalidCharLength,
reason,
err);
myMode = args->converter->mode;
args->source = saveSource;
args->target = saveTarget;
args->offsets = saveOffsets;
myMode = args->converter->mode;
if (U_FAILURE (*err)) break;
args->converter->invalidCharLength = 0;
}
}
}
else
{
*err = U_BUFFER_OVERFLOW_ERROR;
break;
}
}
/*If at the end of conversion we are still carrying state information
*flush is TRUE, we can deduce that the input stream is truncated
*/
if (args->converter->toUnicodeStatus
&& (mySourceIndex == sourceLength)
&& (args->flush == TRUE))
{
if (U_SUCCESS(*err))
{
*err = U_TRUNCATED_CHAR_FOUND;
args->converter->toUnicodeStatus = 0x00;
}
}
args->target += myTargetIndex;
args->source += mySourceIndex;
args->converter->mode = myMode;
return;
}
U_CFUNC void T_UConverter_toUnicode_EBCDIC_STATEFUL_OFFSETS_LOGIC (UConverterToUnicodeArgs * args,
UErrorCode * err)
{
char *mySource = (char *) args->source;
UChar *myTarget = args->target;
int32_t mySourceIndex = 0;
int32_t myTargetIndex = 0;
int32_t targetLength = args->targetLimit - args->target;
int32_t sourceLength = args->sourceLimit - args->source;
CompactShortArray *myToUnicode = NULL;
UChar targetUniChar = 0x0000;
UChar mySourceChar = 0x0000;
int32_t myMode = args->converter->mode;
myToUnicode = &args->converter->sharedData->table->dbcs.toUnicode;
while (mySourceIndex < sourceLength)
{
if (myTargetIndex < targetLength)
{
/*gets the corresponding UniChar */
mySourceChar = (unsigned char) (args->source[mySourceIndex++]);
if (mySourceChar == UCNV_SI) myMode = UCNV_SI;
else if (mySourceChar == UCNV_SO) myMode = UCNV_SO;
else if ((myMode == UCNV_SO) &&
(args->converter->toUnicodeStatus == 0x00))
{
args->converter->toUnicodeStatus = (unsigned char) mySourceChar;
}
else
{
/*In case there is a state, we update the source char
*by concatenating the previous char with the current
*one
*/
if (args->converter->toUnicodeStatus != 0x00)
{
mySourceChar |= (UChar) (args->converter->toUnicodeStatus << 8);
args->converter->toUnicodeStatus = 0x00;
}
else mySourceChar &= 0x00FF;
/*gets the corresponding Unicode codepoint */
targetUniChar = (UChar) ucmp16_getu (myToUnicode, mySourceChar);
/*writing the UniChar to the output stream */
if (targetUniChar < 0xfffe)
{
/*writes the UniChar to the output stream */
{
if(myMode == UCNV_SO)
args->offsets[myTargetIndex] = mySourceIndex-2; /* double byte */
else
args->offsets[myTargetIndex] = mySourceIndex-1; /* single byte */
}
args->target[myTargetIndex++] = targetUniChar;
}
else
{
int32_t currentOffset = args->offsets[myTargetIndex-1] + 2;/* Because mySourceIndex was already incremented */
int32_t My_i = myTargetIndex;
const char* saveSource = args->source;
UChar* saveTarget = args->target;
int32_t *saveOffsets = args->offsets;
UConverterCallbackReason reason;
if (targetUniChar == 0xfffe)
{
reason = UCNV_UNASSIGNED;
*err = U_INVALID_CHAR_FOUND;
}
else
{
reason = UCNV_ILLEGAL;
*err = U_ILLEGAL_CHAR_FOUND;
}
if (mySourceChar > 0xFF)
{
args->converter->invalidCharLength = 2;
args->converter->invalidCharBuffer[0] = (char) (mySourceChar >> 8);
args->converter->invalidCharBuffer[1] = (char) mySourceChar;
}
else
{
args->converter->invalidCharLength = 1;
args->converter->invalidCharBuffer[0] = (char) mySourceChar;
}
args->converter->mode = myMode;
args->target = args->target + myTargetIndex;
args->source = args->source + mySourceIndex;
args->offsets = args->offsets?args->offsets+myTargetIndex:0;
/* call back handles the offset array */
ToU_CALLBACK_OFFSETS_LOGIC_MACRO(args->converter->toUContext,
args,
args->source,
1,
reason,
err);
args->source = saveSource;
args->target = saveTarget;
myMode = args->converter->mode;
if (U_FAILURE (*err)) break;
args->converter->invalidCharLength = 0;
myMode = args->converter->mode;
}
}
}
else
{
*err = U_BUFFER_OVERFLOW_ERROR;
break;
}
}
/*If at the end of conversion we are still carrying state information
*flush is TRUE, we can deduce that the input stream is truncated
*/
if (args->converter->toUnicodeStatus
&& (mySourceIndex == sourceLength)
&& (args->flush == TRUE))
{
if (U_SUCCESS(*err))
{
*err = U_TRUNCATED_CHAR_FOUND;
args->converter->toUnicodeStatus = 0x00;
}
}
args->target += myTargetIndex;
args->source += mySourceIndex;
args->converter->mode = myMode;
return;
}
U_CFUNC void T_UConverter_fromUnicode_EBCDIC_STATEFUL (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 - args->target;
int32_t sourceLength = args->sourceLimit - args->source;
CompactShortArray *myFromUnicode = NULL;
UChar targetUniChar = 0x0000;
UChar mySourceChar = 0x0000;
UBool isTargetUCharDBCS = (UBool)args->converter->fromUnicodeStatus;
UBool oldIsTargetUCharDBCS = isTargetUCharDBCS;
myFromUnicode = &args->converter->sharedData->table->dbcs.fromUnicode;
/*writing the char to the output stream */
while (mySourceIndex < sourceLength)
{
if (myTargetIndex < targetLength)
{
mySourceChar = (UChar) args->source[mySourceIndex++];
targetUniChar = (UChar) ucmp16_getu (myFromUnicode, mySourceChar);
oldIsTargetUCharDBCS = isTargetUCharDBCS;
isTargetUCharDBCS = (UBool)(targetUniChar>0x00FF);
if (targetUniChar != missingCharMarker)
{
if (oldIsTargetUCharDBCS != isTargetUCharDBCS)
{
if (isTargetUCharDBCS) args->target[myTargetIndex++] = UCNV_SO;
else args->target[myTargetIndex++] = UCNV_SI;
if ((!isTargetUCharDBCS)&&(myTargetIndex+1 >= targetLength))
{
args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] = (char) targetUniChar;
*err = U_BUFFER_OVERFLOW_ERROR;
break;
}
else if (myTargetIndex+1 >= targetLength)
{
args->converter->charErrorBuffer[0] = (char) (targetUniChar >> 8);
args->converter->charErrorBuffer[1] = (char)(targetUniChar & 0x00FF);
args->converter->charErrorBufferLength = 2;
*err = U_BUFFER_OVERFLOW_ERROR;
break;
}
}
if (!isTargetUCharDBCS)
{
args->target[myTargetIndex++] = (char) targetUniChar;
}
else
{
args->target[myTargetIndex++] = (char) (targetUniChar >> 8);
if (myTargetIndex < targetLength)
{
args->target[myTargetIndex++] = (char) targetUniChar;
}
else
{
args->converter->charErrorBuffer[0] = (char) targetUniChar;
args->converter->charErrorBufferLength = 1;
*err = U_BUFFER_OVERFLOW_ERROR;
break;
}
}
}
else
{
const UChar* saveSource = args->source;
char* saveTarget = args->target;
int32_t *saveOffsets = args->offsets;
isTargetUCharDBCS = oldIsTargetUCharDBCS;
*err = U_INVALID_CHAR_FOUND;
args->converter->invalidUCharBuffer[0] = (UChar) mySourceChar;
args->converter->invalidUCharLength = 1;
args->converter->fromUnicodeStatus = (int32_t)isTargetUCharDBCS;
args->target += myTargetIndex;
args->source += mySourceIndex;
FromU_CALLBACK_MACRO(args->converter->fromUContext,
args,
args->converter->invalidUCharBuffer,
1,
(UChar32) mySourceChar,
UCNV_UNASSIGNED,
err);
args->source = saveSource;
args->target = saveTarget;
args->offsets = saveOffsets;
isTargetUCharDBCS = (UBool) args->converter->fromUnicodeStatus;
if (U_FAILURE (*err)) break;
args->converter->invalidUCharLength = 0;
}
}
else
{
*err = U_BUFFER_OVERFLOW_ERROR;
break;
}
}
args->target += myTargetIndex;
args->source += mySourceIndex;
args->converter->fromUnicodeStatus = (int32_t)isTargetUCharDBCS;
return;
}
U_CFUNC void T_UConverter_fromUnicode_EBCDIC_STATEFUL_OFFSETS_LOGIC (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 - args->target;
int32_t sourceLength = args->sourceLimit - args->source;
CompactShortArray *myFromUnicode = NULL;
UChar targetUniChar = 0x0000;
UChar mySourceChar = 0x0000;
UBool isTargetUCharDBCS = (UBool)args->converter->fromUnicodeStatus;
UBool oldIsTargetUCharDBCS = isTargetUCharDBCS;
myFromUnicode = &args->converter->sharedData->table->dbcs.fromUnicode;
/*writing the char to the output stream */
while (mySourceIndex < sourceLength)
{
if (myTargetIndex < targetLength)
{
mySourceChar = (UChar) args->source[mySourceIndex++];
targetUniChar = (UChar) ucmp16_getu (myFromUnicode, mySourceChar);
oldIsTargetUCharDBCS = isTargetUCharDBCS;
isTargetUCharDBCS =(UBool) (targetUniChar>0x00FF);
if (targetUniChar != missingCharMarker)
{
if (oldIsTargetUCharDBCS != isTargetUCharDBCS)
{
args->offsets[myTargetIndex] = mySourceIndex-1;
if (isTargetUCharDBCS) args->target[myTargetIndex++] = UCNV_SO;
else args->target[myTargetIndex++] = UCNV_SI;
if ((!isTargetUCharDBCS)&&(myTargetIndex+1 >= targetLength))
{
args->converter->charErrorBuffer[0] = (char) targetUniChar;
args->converter->charErrorBufferLength = 1;
*err = U_BUFFER_OVERFLOW_ERROR;
break;
}
else if (myTargetIndex+1 >= targetLength)
{
args->converter->charErrorBuffer[0] = (char) (targetUniChar >> 8);
args->converter->charErrorBuffer[1] = (char) (targetUniChar & 0x00FF);
args->converter->charErrorBufferLength = 2;
*err = U_BUFFER_OVERFLOW_ERROR;
break;
}
}
if (!isTargetUCharDBCS)
{
args->offsets[myTargetIndex] = mySourceIndex-1;
args->target[myTargetIndex++] = (char) targetUniChar;
}
else
{
args->offsets[myTargetIndex] = mySourceIndex-1;
args->target[myTargetIndex++] = (char) (targetUniChar >> 8);
if (myTargetIndex < targetLength)
{
args->offsets[myTargetIndex] = mySourceIndex-1;
args->target[myTargetIndex++] = (char) targetUniChar;
}
else
{
args->converter->charErrorBuffer[0] = (char) targetUniChar;
args->converter->charErrorBufferLength = 1;
*err = U_BUFFER_OVERFLOW_ERROR;
break;
}
}
}
else
{
int32_t currentOffset = args->offsets[myTargetIndex-1]+1;
char * saveTarget = args->target;
const UChar* saveSource = args->source;
int32_t *saveOffsets = args->offsets;
*err = U_INVALID_CHAR_FOUND;
args->converter->invalidUCharBuffer[0] = (UChar) mySourceChar;
args->converter->invalidUCharLength = 1;
/* Breaks out of the loop since behaviour was set to stop */
args->converter->fromUnicodeStatus = (int32_t)isTargetUCharDBCS;
args->target += myTargetIndex;
args->source += mySourceIndex;
args->offsets = args->offsets?args->offsets+myTargetIndex:0;
FromU_CALLBACK_OFFSETS_LOGIC_MACRO(args->converter->fromUContext,
args,
args->converter->invalidUCharBuffer,
1,
(UChar32)mySourceChar,
UCNV_UNASSIGNED,
err);
isTargetUCharDBCS = (UBool)(args->converter->fromUnicodeStatus);
args->source = saveSource;
args->target = saveTarget;
args->offsets = saveOffsets;
isTargetUCharDBCS = (UBool)(args->converter->fromUnicodeStatus);
if (U_FAILURE (*err)) break;
args->converter->invalidUCharLength = 0;
}
}
else
{
*err = U_BUFFER_OVERFLOW_ERROR;
break;
}
}
args->target += myTargetIndex;
args->source += mySourceIndex;
args->converter->fromUnicodeStatus = (int32_t)isTargetUCharDBCS;
return;
}
U_CFUNC UChar32 T_UConverter_getNextUChar_EBCDIC_STATEFUL(UConverterToUnicodeArgs* args,
UErrorCode* err)
{
UChar myUChar;
char const *sourceInitial = args->source;
/*safe keeps a ptr to the beginning in case we need to step back*/
/*Input boundary check*/
if (args->source >= args->sourceLimit)
{
*err = U_INDEX_OUTOFBOUNDS_ERROR;
return 0xffff;
}
/*Checks to see if with have SI/SO shifters
if we do we change the mode appropriately and we consume the byte*/
while ((*(args->source) == UCNV_SI) || (*(args->source) == UCNV_SO))
{
args->converter->mode = *(args->source);
args->source++;
sourceInitial = args->source;
/*Rechecks boundary after consuming the shift sequence*/
if (args->source >= args->sourceLimit)
{
*err = U_INDEX_OUTOFBOUNDS_ERROR;
return 0xffff;
}
}
if (args->converter->mode == UCNV_SI)
{
myUChar = ucmp16_getu( (&(args->converter->sharedData->table->dbcs.toUnicode)),
((UChar)(uint8_t)(*(args->source))));
args->source++;
}
else
{
/*Lead byte: we Build the codepoint and get the corresponding character
* and update the source ptr*/
if ((args->source + 2) > args->sourceLimit)
{
*err = U_TRUNCATED_CHAR_FOUND;
return 0xffff;
}
myUChar = ucmp16_getu( (&(args->converter->sharedData->table->dbcs.toUnicode)),
(((UChar)(uint8_t)((*(args->source))) << 8) |((uint8_t)*(args->source+1))) );
args->source += 2;
}
if (myUChar < 0xfffe) return myUChar;
else
{
/* HSYS: Check logic here */
UChar* myUCharPtr = &myUChar;
UConverterCallbackReason reason;
if (myUChar == 0xfffe)
{
reason = UCNV_UNASSIGNED;
*err = U_INVALID_CHAR_FOUND;
}
else
{
reason = UCNV_ILLEGAL;
*err = U_ILLEGAL_CHAR_FOUND;
}
/*It's 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,
reason,
err);
/*makes the internal caching transparent to the user*/
if (*err == U_BUFFER_OVERFLOW_ERROR) *err = U_ZERO_ERROR;
return myUChar;
}
}
static const UConverterImpl _EBCDICStatefulImpl={
UCNV_EBCDIC_STATEFUL,
_DBCSLoad,
_DBCSUnload,
NULL,
NULL,
NULL,
T_UConverter_toUnicode_EBCDIC_STATEFUL,
T_UConverter_toUnicode_EBCDIC_STATEFUL_OFFSETS_LOGIC,
T_UConverter_fromUnicode_EBCDIC_STATEFUL,
T_UConverter_fromUnicode_EBCDIC_STATEFUL_OFFSETS_LOGIC,
T_UConverter_getNextUChar_EBCDIC_STATEFUL,
NULL
};
/* Static data is in tools/makeconv/ucnvstat.c for data-based
* converters. Be sure to update it as well.
*/
const UConverterSharedData _EBCDICStatefulData={
sizeof(UConverterSharedData), 1,
NULL, NULL, NULL, FALSE, &_EBCDICStatefulImpl,
0
};