1*91e1e26aSAlexander Pyhalov /* 2*91e1e26aSAlexander Pyhalov * CDDL HEADER START 3*91e1e26aSAlexander Pyhalov * 4*91e1e26aSAlexander Pyhalov * The contents of this file are subject to the terms of the 5*91e1e26aSAlexander Pyhalov * Common Development and Distribution License (the "License"). 6*91e1e26aSAlexander Pyhalov * You may not use this file except in compliance with the License. 7*91e1e26aSAlexander Pyhalov * 8*91e1e26aSAlexander Pyhalov * You can obtain a copy of the license at src/OPENSOLARIS.LICENSE 9*91e1e26aSAlexander Pyhalov * or http://www.opensolaris.org/os/licensing. 10*91e1e26aSAlexander Pyhalov * See the License for the specific language governing permissions 11*91e1e26aSAlexander Pyhalov * and limitations under the License. 12*91e1e26aSAlexander Pyhalov * 13*91e1e26aSAlexander Pyhalov * When distributing Covered Code, include this CDDL HEADER in each 14*91e1e26aSAlexander Pyhalov * file and include the License file at src/OPENSOLARIS.LICENSE. 15*91e1e26aSAlexander Pyhalov * If applicable, add the following below this CDDL HEADER, with the 16*91e1e26aSAlexander Pyhalov * fields enclosed by brackets "[]" replaced with your own identifying 17*91e1e26aSAlexander Pyhalov * information: Portions Copyright [yyyy] [name of copyright owner] 18*91e1e26aSAlexander Pyhalov * 19*91e1e26aSAlexander Pyhalov * CDDL HEADER END 20*91e1e26aSAlexander Pyhalov */ 21*91e1e26aSAlexander Pyhalov /* 22*91e1e26aSAlexander Pyhalov * Copyright(c) 2001 Sun Microsystems, Inc. 23*91e1e26aSAlexander Pyhalov * All rights reserved. 24*91e1e26aSAlexander Pyhalov */ 25*91e1e26aSAlexander Pyhalov #include <stdio.h> 26*91e1e26aSAlexander Pyhalov #include <ctype.h> 27*91e1e26aSAlexander Pyhalov #include <errno.h> 28*91e1e26aSAlexander Pyhalov #include <strings.h> 29*91e1e26aSAlexander Pyhalov #include <stdlib.h> 30*91e1e26aSAlexander Pyhalov #include "ea-iscii.h" 31*91e1e26aSAlexander Pyhalov 32*91e1e26aSAlexander Pyhalov #define MSB 0x80 33*91e1e26aSAlexander Pyhalov #define REPLACE_CHAR '?' 34*91e1e26aSAlexander Pyhalov #define EA_START 0x40 35*91e1e26aSAlexander Pyhalov 36*91e1e26aSAlexander Pyhalov #define get_vowel(a) EAISCII_vowel_type[(a) - EA_START] 37*91e1e26aSAlexander Pyhalov #define get_nukta_value(a) EAISCII_nukta_type[(a) - EA_START] 38*91e1e26aSAlexander Pyhalov #define is_first_vowel(a) ((a) == FIRST_VOWEL) 39*91e1e26aSAlexander Pyhalov #define is_nukta(a) ((a) == NUKTA_VALUE) 40*91e1e26aSAlexander Pyhalov 41*91e1e26aSAlexander Pyhalov typedef enum { SPACE, ASCII, POSSIBLE_ISCII, ISCII } CONTEXT; 42*91e1e26aSAlexander Pyhalov typedef struct _icv_state { 43*91e1e26aSAlexander Pyhalov uchar keepc; /* if is_vowel is true, store the char following the FIRST_VOWEL */ 44*91e1e26aSAlexander Pyhalov CONTEXT context; 45*91e1e26aSAlexander Pyhalov int is_vowel; 46*91e1e26aSAlexander Pyhalov } _iconv_st; 47*91e1e26aSAlexander Pyhalov 48*91e1e26aSAlexander Pyhalov static uchar 49*91e1e26aSAlexander Pyhalov traverse_table(Entry *entry , int num, uchar ea_iscii) 50*91e1e26aSAlexander Pyhalov { 51*91e1e26aSAlexander Pyhalov int i=0; 52*91e1e26aSAlexander Pyhalov uchar iscii=0; 53*91e1e26aSAlexander Pyhalov 54*91e1e26aSAlexander Pyhalov for ( ; i < num; ++i) { 55*91e1e26aSAlexander Pyhalov Entry en = entry[i]; 56*91e1e26aSAlexander Pyhalov 57*91e1e26aSAlexander Pyhalov if ( ea_iscii < en.ea_iscii ) break; 58*91e1e26aSAlexander Pyhalov if ( ea_iscii >= en.ea_iscii && ea_iscii < en.ea_iscii + en.count ) { 59*91e1e26aSAlexander Pyhalov iscii = (ea_iscii - en.ea_iscii) + en.iscii; 60*91e1e26aSAlexander Pyhalov break; 61*91e1e26aSAlexander Pyhalov } 62*91e1e26aSAlexander Pyhalov } 63*91e1e26aSAlexander Pyhalov 64*91e1e26aSAlexander Pyhalov return iscii; 65*91e1e26aSAlexander Pyhalov } 66*91e1e26aSAlexander Pyhalov 67*91e1e26aSAlexander Pyhalov /* 68*91e1e26aSAlexander Pyhalov * run in ISCII context. 69*91e1e26aSAlexander Pyhalov * ea_iscii being 0: flush the keepc 70*91e1e26aSAlexander Pyhalov * flag return 0: don't decide iscii yet, need to advance the next char in outbuf 71*91e1e26aSAlexander Pyhalov */ 72*91e1e26aSAlexander Pyhalov static uchar 73*91e1e26aSAlexander Pyhalov get_iscii(_iconv_st *st, uchar ea_iscii, int *flag) 74*91e1e26aSAlexander Pyhalov { 75*91e1e26aSAlexander Pyhalov uchar iscii = 0; 76*91e1e26aSAlexander Pyhalov 77*91e1e26aSAlexander Pyhalov if ( st->keepc == 0 ) { 78*91e1e26aSAlexander Pyhalov if ( ea_iscii == 0 ) { *flag = 0; return 0; } 79*91e1e26aSAlexander Pyhalov if ( ea_iscii < EA_START ) return 0; /* invalid iscii */ 80*91e1e26aSAlexander Pyhalov 81*91e1e26aSAlexander Pyhalov if ( get_nukta_value(ea_iscii) || is_first_vowel(ea_iscii) ) { 82*91e1e26aSAlexander Pyhalov /* do nothing except store ea_iscii into st->keepc */ 83*91e1e26aSAlexander Pyhalov *flag = 0; 84*91e1e26aSAlexander Pyhalov st->keepc = ea_iscii; 85*91e1e26aSAlexander Pyhalov } else { 86*91e1e26aSAlexander Pyhalov iscii = traverse_table( eaiscii_isc_tbl, 87*91e1e26aSAlexander Pyhalov sizeof(eaiscii_isc_tbl)/sizeof(Entry), ea_iscii); 88*91e1e26aSAlexander Pyhalov } 89*91e1e26aSAlexander Pyhalov } else { 90*91e1e26aSAlexander Pyhalov uchar vowel, nukta_value; 91*91e1e26aSAlexander Pyhalov 92*91e1e26aSAlexander Pyhalov if ( st->is_vowel ) { 93*91e1e26aSAlexander Pyhalov /* need decide whether it is 0xAE or 0xB2 case */ 94*91e1e26aSAlexander Pyhalov if ( ea_iscii >= EA_START && is_nukta(ea_iscii) ) { 95*91e1e26aSAlexander Pyhalov if ( st->keepc == 0x73 ) iscii = 0xAE; 96*91e1e26aSAlexander Pyhalov if ( st->keepc == 0x76 ) iscii = 0xB2; 97*91e1e26aSAlexander Pyhalov st->keepc = 0; 98*91e1e26aSAlexander Pyhalov } else { 99*91e1e26aSAlexander Pyhalov iscii = get_vowel(st->keepc); 100*91e1e26aSAlexander Pyhalov st->keepc = ea_iscii; 101*91e1e26aSAlexander Pyhalov } 102*91e1e26aSAlexander Pyhalov st->is_vowel = 0; 103*91e1e26aSAlexander Pyhalov goto end; 104*91e1e26aSAlexander Pyhalov } 105*91e1e26aSAlexander Pyhalov 106*91e1e26aSAlexander Pyhalov if ( is_first_vowel(st->keepc) ) { 107*91e1e26aSAlexander Pyhalov if ( (ea_iscii >= EA_START) && (vowel = get_vowel(ea_iscii)) ) { 108*91e1e26aSAlexander Pyhalov if ( ea_iscii == 0x73 || ea_iscii == 0x76 ) { 109*91e1e26aSAlexander Pyhalov st->keepc = ea_iscii; 110*91e1e26aSAlexander Pyhalov *flag = 0; 111*91e1e26aSAlexander Pyhalov st->is_vowel = 1; 112*91e1e26aSAlexander Pyhalov } else { 113*91e1e26aSAlexander Pyhalov st->keepc = 0; 114*91e1e26aSAlexander Pyhalov iscii = vowel; 115*91e1e26aSAlexander Pyhalov } 116*91e1e26aSAlexander Pyhalov } else { 117*91e1e26aSAlexander Pyhalov iscii = traverse_table( eaiscii_isc_tbl, 118*91e1e26aSAlexander Pyhalov sizeof(eaiscii_isc_tbl)/sizeof(Entry), st->keepc); 119*91e1e26aSAlexander Pyhalov st->keepc = ea_iscii; 120*91e1e26aSAlexander Pyhalov } 121*91e1e26aSAlexander Pyhalov } else if ( (st->keepc >= EA_START) && (nukta_value = get_nukta_value(st->keepc))) { 122*91e1e26aSAlexander Pyhalov if ( ea_iscii >= EA_START && is_nukta(ea_iscii) ) { 123*91e1e26aSAlexander Pyhalov st->keepc = 0; 124*91e1e26aSAlexander Pyhalov iscii = nukta_value; 125*91e1e26aSAlexander Pyhalov } else { 126*91e1e26aSAlexander Pyhalov iscii = traverse_table( eaiscii_isc_tbl, 127*91e1e26aSAlexander Pyhalov sizeof(eaiscii_isc_tbl)/sizeof(Entry), st->keepc); 128*91e1e26aSAlexander Pyhalov st->keepc = ea_iscii; 129*91e1e26aSAlexander Pyhalov } 130*91e1e26aSAlexander Pyhalov } else { 131*91e1e26aSAlexander Pyhalov iscii = traverse_table( eaiscii_isc_tbl, 132*91e1e26aSAlexander Pyhalov sizeof(eaiscii_isc_tbl)/sizeof(Entry), st->keepc); 133*91e1e26aSAlexander Pyhalov st->keepc = ea_iscii; 134*91e1e26aSAlexander Pyhalov } 135*91e1e26aSAlexander Pyhalov } 136*91e1e26aSAlexander Pyhalov 137*91e1e26aSAlexander Pyhalov end: 138*91e1e26aSAlexander Pyhalov return iscii; 139*91e1e26aSAlexander Pyhalov } 140*91e1e26aSAlexander Pyhalov 141*91e1e26aSAlexander Pyhalov void * 142*91e1e26aSAlexander Pyhalov _icv_open() 143*91e1e26aSAlexander Pyhalov { 144*91e1e26aSAlexander Pyhalov _iconv_st *st; 145*91e1e26aSAlexander Pyhalov 146*91e1e26aSAlexander Pyhalov if ((st = (_iconv_st*)malloc(sizeof(_iconv_st))) == NULL) { 147*91e1e26aSAlexander Pyhalov errno = ENOMEM; 148*91e1e26aSAlexander Pyhalov return ((void*)-1); 149*91e1e26aSAlexander Pyhalov } 150*91e1e26aSAlexander Pyhalov 151*91e1e26aSAlexander Pyhalov bzero(st, sizeof(_iconv_st)); 152*91e1e26aSAlexander Pyhalov 153*91e1e26aSAlexander Pyhalov return ((void*)st); 154*91e1e26aSAlexander Pyhalov } 155*91e1e26aSAlexander Pyhalov 156*91e1e26aSAlexander Pyhalov /* 157*91e1e26aSAlexander Pyhalov * Close; called from iconv_close() 158*91e1e26aSAlexander Pyhalov */ 159*91e1e26aSAlexander Pyhalov void 160*91e1e26aSAlexander Pyhalov _icv_close(_iconv_st *st) 161*91e1e26aSAlexander Pyhalov { 162*91e1e26aSAlexander Pyhalov if (!st) 163*91e1e26aSAlexander Pyhalov errno = EBADF; 164*91e1e26aSAlexander Pyhalov else 165*91e1e26aSAlexander Pyhalov free(st); 166*91e1e26aSAlexander Pyhalov } 167*91e1e26aSAlexander Pyhalov 168*91e1e26aSAlexander Pyhalov size_t 169*91e1e26aSAlexander Pyhalov _icv_iconv(_iconv_st *st, char **inbuf, size_t *inbytesleft, 170*91e1e26aSAlexander Pyhalov char **outbuf, size_t *outbytesleft) 171*91e1e26aSAlexander Pyhalov { 172*91e1e26aSAlexander Pyhalov if (st == NULL) { 173*91e1e26aSAlexander Pyhalov errno = EBADF; 174*91e1e26aSAlexander Pyhalov return ((size_t) -1); 175*91e1e26aSAlexander Pyhalov } 176*91e1e26aSAlexander Pyhalov 177*91e1e26aSAlexander Pyhalov if (inbuf == NULL || *inbuf == NULL) { /* Reset request. */ 178*91e1e26aSAlexander Pyhalov return ((size_t)0); 179*91e1e26aSAlexander Pyhalov } 180*91e1e26aSAlexander Pyhalov 181*91e1e26aSAlexander Pyhalov /* a state machine for interpreting ISCII code */ 182*91e1e26aSAlexander Pyhalov while (*inbytesleft > 0 && *outbytesleft > 0) { 183*91e1e26aSAlexander Pyhalov uchar c = (uchar)**inbuf; 184*91e1e26aSAlexander Pyhalov 185*91e1e26aSAlexander Pyhalov if ( c & MSB ) { errno = EILSEQ; return (size_t)-1; } 186*91e1e26aSAlexander Pyhalov 187*91e1e26aSAlexander Pyhalov switch (st->context) { 188*91e1e26aSAlexander Pyhalov case SPACE: 189*91e1e26aSAlexander Pyhalov if ( c == LEADING_BYTE ) st->context = POSSIBLE_ISCII; 190*91e1e26aSAlexander Pyhalov else { 191*91e1e26aSAlexander Pyhalov if ( !isspace(c) ) st->context = ASCII; 192*91e1e26aSAlexander Pyhalov **outbuf = c; 193*91e1e26aSAlexander Pyhalov (*outbuf)++; 194*91e1e26aSAlexander Pyhalov (*outbytesleft)--; 195*91e1e26aSAlexander Pyhalov } 196*91e1e26aSAlexander Pyhalov break; 197*91e1e26aSAlexander Pyhalov case ASCII: 198*91e1e26aSAlexander Pyhalov if ( isspace(c) ) st->context = SPACE; 199*91e1e26aSAlexander Pyhalov **outbuf = c; 200*91e1e26aSAlexander Pyhalov (*outbuf)++; 201*91e1e26aSAlexander Pyhalov (*outbytesleft)--; 202*91e1e26aSAlexander Pyhalov break; 203*91e1e26aSAlexander Pyhalov case POSSIBLE_ISCII: 204*91e1e26aSAlexander Pyhalov /* it is impossible to represent with 'xx' one ASCII word that starts with 'x' */ 205*91e1e26aSAlexander Pyhalov if ( !isspace(c) ) { st->context = ISCII; continue; } /* don't advance */ 206*91e1e26aSAlexander Pyhalov 207*91e1e26aSAlexander Pyhalov **outbuf = LEADING_BYTE; /* the previous 'x' */ 208*91e1e26aSAlexander Pyhalov (*outbuf)++; 209*91e1e26aSAlexander Pyhalov (*outbytesleft)--; 210*91e1e26aSAlexander Pyhalov st->context = ASCII; 211*91e1e26aSAlexander Pyhalov 212*91e1e26aSAlexander Pyhalov if (*outbytesleft < 1) { 213*91e1e26aSAlexander Pyhalov errno = E2BIG; 214*91e1e26aSAlexander Pyhalov return (size_t)-1; 215*91e1e26aSAlexander Pyhalov } 216*91e1e26aSAlexander Pyhalov 217*91e1e26aSAlexander Pyhalov **outbuf = c; 218*91e1e26aSAlexander Pyhalov (*outbuf)++; 219*91e1e26aSAlexander Pyhalov (*outbytesleft)--; 220*91e1e26aSAlexander Pyhalov st->context = SPACE; 221*91e1e26aSAlexander Pyhalov 222*91e1e26aSAlexander Pyhalov break; 223*91e1e26aSAlexander Pyhalov case ISCII: 224*91e1e26aSAlexander Pyhalov if ( isspace(c) ) { 225*91e1e26aSAlexander Pyhalov uchar iscii; 226*91e1e26aSAlexander Pyhalov int flag = 1; 227*91e1e26aSAlexander Pyhalov 228*91e1e26aSAlexander Pyhalov /* flush keepc */ 229*91e1e26aSAlexander Pyhalov iscii = get_iscii(st, 0, &flag); 230*91e1e26aSAlexander Pyhalov if (flag) { 231*91e1e26aSAlexander Pyhalov if ( iscii ) **outbuf = iscii; 232*91e1e26aSAlexander Pyhalov else **outbuf = REPLACE_CHAR; 233*91e1e26aSAlexander Pyhalov 234*91e1e26aSAlexander Pyhalov (*outbuf)++; 235*91e1e26aSAlexander Pyhalov (*outbytesleft)--; 236*91e1e26aSAlexander Pyhalov } 237*91e1e26aSAlexander Pyhalov 238*91e1e26aSAlexander Pyhalov if ( *outbytesleft < 1 ) { 239*91e1e26aSAlexander Pyhalov errno = E2BIG; 240*91e1e26aSAlexander Pyhalov return (size_t)-1; 241*91e1e26aSAlexander Pyhalov } 242*91e1e26aSAlexander Pyhalov 243*91e1e26aSAlexander Pyhalov **outbuf = c; 244*91e1e26aSAlexander Pyhalov (*outbuf)++; 245*91e1e26aSAlexander Pyhalov (*outbytesleft)--; 246*91e1e26aSAlexander Pyhalov st->context = SPACE; 247*91e1e26aSAlexander Pyhalov } else { 248*91e1e26aSAlexander Pyhalov uchar iscii; 249*91e1e26aSAlexander Pyhalov int flag = 1; 250*91e1e26aSAlexander Pyhalov 251*91e1e26aSAlexander Pyhalov iscii = get_iscii(st, c, &flag); 252*91e1e26aSAlexander Pyhalov if (flag) { 253*91e1e26aSAlexander Pyhalov if ( iscii ) **outbuf = iscii; 254*91e1e26aSAlexander Pyhalov else **outbuf = REPLACE_CHAR; 255*91e1e26aSAlexander Pyhalov 256*91e1e26aSAlexander Pyhalov (*outbuf)++; 257*91e1e26aSAlexander Pyhalov (*outbytesleft)--; 258*91e1e26aSAlexander Pyhalov } 259*91e1e26aSAlexander Pyhalov } 260*91e1e26aSAlexander Pyhalov break; 261*91e1e26aSAlexander Pyhalov } 262*91e1e26aSAlexander Pyhalov 263*91e1e26aSAlexander Pyhalov (*inbuf)++; 264*91e1e26aSAlexander Pyhalov (*inbytesleft)--; 265*91e1e26aSAlexander Pyhalov } 266*91e1e26aSAlexander Pyhalov 267*91e1e26aSAlexander Pyhalov if ( *inbytesleft > 0 && *outbytesleft == 0 ) { 268*91e1e26aSAlexander Pyhalov errno = E2BIG; 269*91e1e26aSAlexander Pyhalov return ((size_t)-1); 270*91e1e26aSAlexander Pyhalov } 271*91e1e26aSAlexander Pyhalov 272*91e1e26aSAlexander Pyhalov return ((size_t)(*inbytesleft)); 273*91e1e26aSAlexander Pyhalov } 274