#include "iso2022-cn.h"
static int process_esc_seq(char, _iconv_st *);
static int ascii_to_euc(char, _iconv_st *, unsigned char **, size_t *);
static int iscns( _iconv_st * );
extern int errno;
void *
_icv_open()
{
_iconv_st *st;
if (( st = (_iconv_st *) malloc( sizeof( _iconv_st ))) == NULL ){
errno = ENOMEM;
return ((void *) -1);
}
st->Sfunc = SI;
st->SSfunc = NONE;
st->ESCstate = OFF;
st->firstbyte = True;
st->numsav = 0;
st->SOcharset = 0;
st->SS2charset = 0;
st->SS3charset = 0;
st->nonidcount = 0;
st->_errno = 0;
return ((void *) st);
}
void
_icv_close(_iconv_st *st)
{
if (st == NULL )
errno = EBADF;
else
free(st);
}
size_t
iso2022_icv_iconv(_iconv_st *st, char **inbuf, size_t *inbytesleft,
unsigned char **outbuf, size_t *outbytesleft, int (*convert)() )
{
int ret, n;
if (st == NULL) {
errno = EBADF;
return ((size_t) -1);
}
if ( inbuf == NULL || *inbuf == NULL || inbytesleft == NULL ||
*inbytesleft <= 0 ) {
st->Sfunc = SI;
st->SSfunc = NONE;
st->ESCstate = OFF;
st->firstbyte = True;
st->numsav = 0;
st->SOcharset = 0;
st->SS2charset = 0;
st->SS3charset = 0;
st->nonidcount = 0;
st->_errno = 0;
return ((size_t) 0);
}
st->_errno = 0;
errno = 0;
if ( outbytesleft == NULL || *outbytesleft <= 0 ||
outbuf == NULL || *outbuf == NULL ) {
errno = E2BIG;
return((size_t)-1);
}
do {
if (st->firstbyte == False) {
st->keepc[1] = **inbuf;
n = (*convert)( st, outbuf, outbytesleft, iscns(st) );
if ( n < 0 )
return((size_t)-1);
else if ( n > 0 ){
n = ascii_to_euc(NON_ID_CHAR, st, outbuf, outbytesleft);
if ( n < 0 )
return((size_t)-1);
st->nonidcount += 1;
} else
st->nonidcount -= 1;
st->firstbyte = True;
st->SSfunc = NONE;
} else if ( st->SSfunc != NONE ) {
st->keepc[0] = **inbuf;
st->nonidcount += 1;
st->firstbyte = False;
} else if ( **inbuf == ESC && st->ESCstate == OFF ) {
st->nonidcount += 1;
st->ESCstate = E0;
} else if ( st->ESCstate != OFF ) {
ret = process_esc_seq( **inbuf, st );
if ( ret == DONE ) {
st->ESCstate = OFF;
} else if ( ret == INVALID ){
if (st->Sfunc == SI){
n = ascii_to_euc( **inbuf, st, outbuf, outbytesleft );
if ( n < 0 )
return((size_t)-1);
st->nonidcount -= st->numsav;
} else if (st->Sfunc == SO) {
st->_errno = errno = EILSEQ;
st->nonidcount += 1;
}
st->numsav = 0;
st->ESCstate = OFF;
}
} else if (st->Sfunc == SI) {
if ( **inbuf == SO && st->SOcharset != 0 ){
st->Sfunc = SO;
} else {
n = ascii_to_euc(**inbuf, st, outbuf, outbytesleft );
if ( n < 0 )
return((size_t)-1);
}
} else if (st->Sfunc == SO) {
if ( **inbuf == SI ){
st->Sfunc = SI;
}
else {
st->keepc[0] = **inbuf;
st->nonidcount += 1;
st->firstbyte = False;
}
}
else
fprintf(stderr,
"_icv_iconv():ISO-CN-EXT->CNS:Should never have come here\n");
(*inbuf)++;
(*inbytesleft)--;
if ( st->_errno)
break;
if (errno)
return((size_t)-1);
} while (*inbytesleft > 0 && *outbytesleft > 0);
if ( *inbytesleft > 0 && *outbytesleft == 0) {
errno = E2BIG;
return((size_t)-1);
}
return (*inbytesleft + st->nonidcount);
}
static int
process_esc_seq( char c, _iconv_st *st )
{
switch(st->ESCstate){
case E0:
switch (c){
case SS2LOW:
if ( st->SS2charset == 0 ){
st->savbuf[0] = ESC;
st->numsav = 1;
return(INVALID);
}
st->SSfunc = SS2;
st->nonidcount -= 1;
return(DONE);
case SS3LOW:
if ( st->SS3charset == 0 ){
st->savbuf[0] = ESC;
st->numsav = 1;
return(INVALID);
}
st->SSfunc = SS3;
st->nonidcount -= 1;
return(DONE);
case '$':
st->nonidcount += 1;
st->ESCstate = E1;
return(NEEDMORE);
default:
st->savbuf[0] = ESC;
st->numsav = 1;
return(INVALID);
}
case E1:
switch (c){
case ')':
st->nonidcount += 1;
st->ESCstate = E2;
return(NEEDMORE);
case '*':
st->nonidcount += 1;
st->ESCstate = E3;
return(NEEDMORE);
case '+':
st->nonidcount += 1;
st->ESCstate = E4;
return(NEEDMORE);
default:
st->savbuf[0] = ESC;
st->savbuf[1] = '$';
st->numsav = 2;
return(INVALID);
}
case E2:
st->SOcharset = c;
st->nonidcount -= 3;
return(DONE);
case E3:
st->SS2charset = c;
st->nonidcount -= 3;
return(DONE);
case E4:
st->SS3charset = c;
st->nonidcount -= 3;
return(DONE);
default:
fprintf(stderr,
"process_esc_seq():ISO-CN-EXT->CNS:Should never have come here\n");
st->_errno = errno = EILSEQ;
return(DONE);
}
}
static int
ascii_to_euc( char c, _iconv_st *st, unsigned char **outbuf, size_t *outbytesleft )
{
int i;
if ( *outbytesleft < (1 + st->numsav) ) {
st->_errno = errno = E2BIG;
return (-1);
}
for ( i=0; i < st->numsav; i++ ) {
*(*outbuf)++ = (unsigned char) st->savbuf[i];
(*outbytesleft)--;
}
*(*outbuf)++ = (unsigned char) c;
(*outbytesleft)--;
return(0);
}
static int
iscns( _iconv_st *st )
{
int plane_no = -1;
if ( st->SSfunc == NONE && st->SOcharset == 'G' )
plane_no = 1;
else if ( st->SSfunc == SS2 && st->SS2charset == 'H' )
plane_no = 2;
else if ( st->SSfunc == SS3 )
switch ( st->SS3charset ){
case 'I': plane_no = 3; break;
case 'J': plane_no = 4; break;
case 'K': plane_no = 5; break;
case 'L': plane_no = 6; break;
case 'M': plane_no = 7; break;
}
return (plane_no);
}