#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <strings.h>
#include <stdlib.h>
#include "ea-iscii.h"
#define MSB 0x80
#define REPLACE_CHAR '?'
typedef enum { SPACE, ASCII, ISCII } CONTEXT;
typedef struct _icv_state {
CONTEXT context;
} _iconv_st;
static uchar
traverse_table(Entry *entry , int num, uchar iscii, uchar *type)
{
int i = 0;
uchar ea_iscii=0;
*type = 0;
for ( ; i < num; ++i) {
Entry en = entry[i];
if ( iscii < en.iscii ) break;
if ( en.count == NUKTA || en.count == MATRA || en.count ==
COMBINED_MATRA_NUKTA ) {
if ( iscii == en.iscii ) {
*type = en.count;
ea_iscii = en.ea_iscii;
break;
}
} else {
if ( iscii >= en.iscii && iscii < en.iscii + en.count ) {
ea_iscii = (iscii - en.iscii) + en.ea_iscii;
break;
}
}
}
return ea_iscii;
}
void *
_icv_open()
{
_iconv_st *st;
if ((st = (_iconv_st*)malloc(sizeof(_iconv_st))) == NULL) {
errno = ENOMEM;
return ((void*)-1);
}
bzero(st, sizeof(_iconv_st));
return ((void*)st);
}
void
_icv_close(_iconv_st *st)
{
if (!st)
errno = EBADF;
else
free(st);
}
size_t
_icv_iconv(_iconv_st *st, char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
if (st == NULL) {
errno = EBADF;
return ((size_t) -1);
}
if (inbuf == NULL || *inbuf == NULL) {
return ((size_t)0);
}
while (*inbytesleft > 0 && *outbytesleft > 0) {
uchar c = (uchar)**inbuf;
if ( c & MSB ) {
uchar type, ea_iscii;
if ( st->context != ISCII ) {
if ( st->context != SPACE ) {
**outbuf = 0x20;
(*outbuf)++;
(*outbytesleft)--;
st->context = SPACE;
}
if ( *outbytesleft < 1 ) {
errno = E2BIG;
return (size_t)-1;
}
st->context = ISCII;
**outbuf = LEADING_BYTE;
(*outbuf)++;
(*outbytesleft)--;
}
if ((ea_iscii = traverse_table(isc_eaiscii_tbl,
sizeof(isc_eaiscii_tbl)/sizeof(Entry), c, &type ))) {
switch ( type ) {
case MATRA:
if ( *outbytesleft < 2 ) {
errno = E2BIG;
return (size_t)-1;
}
**outbuf = FIRST_VOWEL;
*(*outbuf+1) = ea_iscii;
(*outbuf) += 2;
(*outbytesleft) -= 2;
break;
case NUKTA:
if ( *outbytesleft < 2 ) {
errno = E2BIG;
return (size_t)-1;
}
**outbuf = ea_iscii;
*(*outbuf+1) = NUKTA_VALUE;
(*outbuf) += 2;
(*outbytesleft) -= 2;
break;
case COMBINED_MATRA_NUKTA:
if ( *outbytesleft < 3 ) {
errno = E2BIG;
return (size_t)-1;
}
**outbuf = FIRST_VOWEL;
*(*outbuf+1) = ea_iscii;
*(*outbuf+2) = NUKTA_VALUE;
(*outbuf) += 3;
(*outbytesleft) -= 3;
break;
case 0:
if ( *outbytesleft < 1 ) {
errno = E2BIG;
return (size_t)-1;
}
**outbuf = ea_iscii;
(*outbuf)++;
(*outbytesleft)--;
break;
}
} else {
if ( *outbytesleft < 1 ) {
errno = E2BIG;
return (size_t)-1;
}
**outbuf = REPLACE_CHAR;
(*outbuf)++;
(*outbytesleft)--;
}
} else {
if ( st->context == ISCII && !isspace(c) ) {
**outbuf = 0x20;
(*outbuf)++;
(*outbytesleft)--;
st->context = SPACE;
}
if ( *outbytesleft < 1 ) {
errno = E2BIG;
return (size_t)-1;
}
**outbuf = c;
(*outbuf)++;
(*outbytesleft)--;
st->context = ASCII;
if ( isspace(c) )
st->context = SPACE;
}
(*inbuf)++;
(*inbytesleft)--;
}
if ( *inbytesleft > 0 && *outbytesleft == 0 ) {
errno = E2BIG;
return ((size_t)-1);
}
return ((size_t)(*inbytesleft));
}