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