1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 1994 by Sun Microsystems, Inc. 23 */ 24 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <errno.h> 28 29 #define MSB 0x80 30 31 enum _GSTATE { G0, G1, G2}; 32 33 34 typedef struct _icv_state { 35 char _lastc; 36 short _gstate; 37 } _iconv_st; 38 39 /* 40 * Open; called from iconv_open() 41 */ 42 void * 43 _icv_open() 44 { 45 _iconv_st *st; 46 47 if ((st = (_iconv_st *)malloc(sizeof(_iconv_st))) == NULL) { 48 errno = ENOMEM; 49 return ((void *) -1); 50 } 51 52 st->_gstate = G0; 53 return ((void *)st); 54 } 55 56 57 /* 58 * Close; called from iconv_close() 59 */ 60 void 61 _icv_close(_iconv_st *st) 62 { 63 if (st == NULL) 64 errno = EBADF; 65 else 66 free(st); 67 } 68 69 70 /* 71 * Actual conversion; called from iconv() 72 */ 73 /*======================================================================= 74 * 75 * 76 * +-------------------------------------+ 77 * V MSB MSB ascii | 78 * +-> G0 ------------> G1 ------> G2 -------+ 79 * | ascii (~{) ^ MSB | (~}) 80 * +----+ +----------+ 81 *=======================================================================*/ 82 size_t 83 _icv_iconv(_iconv_st *st, char **inbuf, size_t*inbytesleft, 84 char **outbuf, size_t*outbytesleft) 85 { 86 if (st == NULL) { 87 errno = EBADF; 88 return -1; 89 } 90 if (inbuf == NULL || *inbuf == NULL) { /* Reset request. */ 91 st->_gstate = G0; 92 return 0; 93 } 94 95 errno = 0; 96 97 while (*inbytesleft > 0 && *outbytesleft > 0) { 98 switch (st->_gstate) { 99 case G0: 100 if ( **inbuf & MSB ) { 101 if(*outbytesleft >=2) { 102 **outbuf = '~'; 103 *(*outbuf+1) = '{'; 104 (*outbuf) += 2, (*outbytesleft) -= 2; 105 st->_lastc = **inbuf; 106 st->_gstate = G1; 107 } else { 108 errno = E2BIG; 109 return (size_t)-1; 110 } 111 112 } else { 113 **outbuf = **inbuf; 114 (*outbuf)++, (*outbytesleft)--; 115 if (**inbuf == '~') { 116 **outbuf = '~'; 117 (*outbuf)++, (*outbytesleft)--; 118 } 119 } 120 break; 121 case G1: 122 if ( **inbuf & MSB ) { 123 if(*outbytesleft >=2) { 124 **outbuf = st->_lastc - 0x80; 125 *(*outbuf+1) = **inbuf - 0x80; 126 (*outbuf) += 2, (*outbytesleft) -= 2; 127 st->_gstate = G2; 128 } else { 129 errno = E2BIG; 130 return (size_t)-1; 131 } 132 133 } else { 134 errno = E2BIG; 135 return (size_t)-1; 136 } 137 break; 138 case G2: 139 if ( **inbuf & MSB ) { 140 st->_lastc = **inbuf; 141 st->_gstate = G1; 142 } else { 143 if(*outbytesleft >=3) { 144 **outbuf = '~'; 145 *(*outbuf+1) = '}'; 146 *(*outbuf+2) = **inbuf; 147 (*outbuf) += 3, (*outbytesleft) -= 3; 148 st->_gstate = G0; 149 }else { 150 errno = E2BIG; 151 return (size_t)-1; 152 } 153 154 } 155 break; 156 } 157 158 (*inbuf)++, (*inbytesleft)--; 159 if (errno) 160 return -1; 161 } 162 if (*inbytesleft > 0 && *outbytesleft == 0) { 163 errno = E2BIG; 164 return -1; 165 } 166 return (*inbytesleft); 167 } 168