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) 2001 Sun Microsystems, Inc. 23 * All rights reserved. 24 */ 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <errno.h> 28 #include <big5hk_gb18030.h> 29 30 #define NON_ID_CHAR '_' /* non-identifier charactor */ 31 #define MSB 0x80 32 #define ONEBYTE 0xff 33 #define gbk_4th_byte(v) ( ((v) >= 0x30) && ((v) <= 0x39) ) 34 35 typedef struct _icv_state { 36 char keepc[2]; /* maximum # byte of HKSCS charactor */ 37 short cstate; 38 int _errno; /* internal errno */ 39 } _iconv_st; 40 41 enum _CSTATE { C0, C1 }; 42 43 int binsearch(unsigned long x, table_t table[], int n); 44 int hkscs_2nd_byte(char inbuf); 45 int hkscs_to_gbk2k(char keepc[], char *buf, size_t buflen); 46 47 /* 48 * Open; called from iconv_open() 49 */ 50 void * _icv_open() { 51 _iconv_st * st; 52 53 if ((st = (_iconv_st *) malloc(sizeof(_iconv_st))) == NULL) { 54 errno = ENOMEM; 55 return ((void *) -1); 56 } 57 58 st->cstate = C0; 59 st->_errno = 0; 60 61 return ((void *) st); 62 } 63 64 /* 65 * Close; called from iconv_close() 66 */ 67 void _icv_close(_iconv_st * st) { 68 if (!st) 69 errno = EBADF; 70 else 71 free(st); 72 } 73 74 /* 75 * Actual conversion; called from iconv() 76 */ 77 78 size_t _icv_iconv(_iconv_st * st, char **inbuf, size_t *inbytesleft, 79 char ** outbuf, size_t *outbytesleft) { 80 int n; 81 if (st == NULL) { 82 errno = EBADF; 83 return ((size_t) -1); 84 } 85 86 if (inbuf == NULL || *inbuf == NULL) { /* Reset request. */ 87 st->cstate = C0; 88 st->_errno = 0; 89 return ((size_t) 0); 90 } 91 92 errno = st->_errno = 0; 93 94 while (*inbytesleft > 0 && *outbytesleft > 0) { 95 switch (st->cstate) { 96 case C0: 97 if (**inbuf & MSB) { /* hkscs charactor */ 98 st->keepc[0] = (**inbuf); 99 st->cstate = C1; 100 } else { /* ASCII */ 101 **outbuf = **inbuf; 102 (*outbuf)++; 103 (*outbytesleft)--; 104 } 105 break; 106 case C1: /* hkscs charactor 2nd byte */ 107 if (hkscs_2nd_byte(**inbuf) == 0) { 108 st->keepc[1] = (**inbuf); 109 n = hkscs_to_gbk2k(st->keepc, *outbuf, *outbytesleft); 110 if (n > 0) { 111 (*outbuf) += n; 112 (*outbytesleft) -= n; 113 114 st->cstate = C0; 115 } else { 116 st->_errno = errno = E2BIG; 117 } 118 } else { /* illegal input */ 119 st->_errno = errno =EILSEQ; 120 } 121 break; 122 default: 123 st->_errno = errno = EILSEQ; 124 st->cstate = C0; 125 break; 126 } 127 128 if (st->_errno) break; 129 130 (*inbuf) ++; 131 (*inbytesleft)--; 132 133 } 134 135 if (errno) return ((size_t) -1); 136 137 if (*inbytesleft == 0 && st->cstate != C0) { 138 errno = EINVAL; 139 return ((size_t) -1); 140 } 141 142 if (*inbytesleft > 0 && *outbytesleft == 0) { 143 errno = E2BIG; 144 return (size_t)-1; 145 } 146 147 return (size_t)(*inbytesleft); 148 } 149 150 /* 151 * Test whether inbuf is a valid character for 152 * 2nd byte of HKSCS charactor: 153 * Return: 0 --- valid HKSCS 2nd byte 154 * 1 --- invalid HKSCS 2nd byte 155 */ 156 int hkscs_2nd_byte(inbuf) 157 char inbuf; 158 { 159 unsigned int buf = (unsigned int)(inbuf & ONEBYTE); 160 161 if ((buf >= 0x40) && (buf <= 0xfe)) 162 return 0; 163 return 1; 164 } 165 166 /* 167 * hkscs_to_gbk2k: Convert hkscs to gbk. 168 * Return: >0 --- converted with enough space in output buffer 169 * =0 --- no space in outbuf 170 */ 171 172 int hkscs_to_gbk2k(char keepc[], char *buf, size_t buflen) { 173 174 unsigned long gbk_val; 175 int index, len; 176 unsigned long hkscs_val; 177 178 if (buflen < 2) { 179 errno = E2BIG; 180 return 0; 181 } 182 183 hkscs_val = ((keepc[0] & ONEBYTE) << 8) + (keepc[1] & ONEBYTE); 184 index = binsearch(hkscs_val, hkscs_gbk2k_tab, MAX_HKSCS_NUM); 185 if (index >= 0) { 186 char c; 187 188 gbk_val = hkscs_gbk2k_tab[index].value; 189 c = gbk_val & ONEBYTE; 190 if ( gbk_4th_byte( (unsigned char)c ) ) { 191 192 if ( buflen < 4 ) { 193 errno = E2BIG; 194 return 0; 195 } 196 197 *buf = ( gbk_val >> 24) & ONEBYTE; 198 *(buf + 1) = (gbk_val >> 16) & ONEBYTE; 199 *(buf + 2) = (gbk_val >> 8) & ONEBYTE; 200 *(buf + 3) = c; 201 202 len = 4; 203 } else { 204 *buf = (gbk_val >> 8) & ONEBYTE; 205 *(buf + 1) = c; 206 207 len = 2; 208 } 209 } else { 210 *buf = *(buf + 1) = (char)NON_ID_CHAR; 211 len = 2; 212 } 213 return len; 214 } 215 216 /* 217 * binsearch() 218 */ 219 int binsearch(unsigned long x, table_t table[], int n) { 220 int low, high, mid; 221 222 low = 0; 223 high = n - 1; 224 while (low <= high) { 225 mid = (low + high) >> 1; 226 if (x < table[mid].key) 227 high = mid - 1; 228 else if (x > table[mid].key) 229 low = mid + 1; 230 else 231 return mid; 232 } 233 return -1; 234 } 235