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 *
_icv_open()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
_icv_close(_iconv_st * st)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
_icv_iconv(_iconv_st * st,char ** inbuf,size_t * inbytesleft,char ** outbuf,size_t * outbytesleft)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