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) 2008, by Sun Microsystems, Inc. 23 * All rights reserved. 24 */ 25 26 #include <stdio.h> 27 #include <errno.h> 28 #include <stdlib.h> 29 #include <sys/types.h> 30 #define __NEED_TCVN_2_VISCII__ 31 #include <viscii_tcvn.h> /* VISCII <-> TCVN mapping table */ 32 #include <vi_combine.h> 33 #include "common_defs.h" 34 35 36 #define NON_ID_CHAR '?' /* non-identified character */ 37 38 typedef struct _icv_state { 39 int _errno; /* internal errno */ 40 unsigned short last; 41 } _iconv_st; 42 43 44 static int binsearch(unsigned short x, Combine_map_tcvn v[], int n); 45 46 /* 47 * Open; called from iconv_open() 48 */ 49 void * 50 _icv_open() 51 { 52 _iconv_st *st; 53 54 if ((st = (_iconv_st *)malloc(sizeof(_iconv_st))) == NULL) { 55 errno = ENOMEM; 56 return ((void *) -1); 57 } 58 59 st->_errno = 0; 60 st->last = 0; 61 return ((void *) st); 62 } 63 64 65 /* 66 * Close; called from iconv_close() 67 */ 68 void 69 _icv_close(_iconv_st *st) 70 { 71 if (!st) 72 errno = EBADF; 73 else 74 free(st); 75 } 76 77 78 /* 79 * Actual conversion; called from iconv() 80 */ 81 size_t 82 _icv_iconv(_iconv_st *st, char **inbuf, size_t *inbytesleft, 83 char **outbuf, size_t *outbytesleft) 84 { 85 int unconv = 0; 86 int idx = -1; 87 unsigned char chout = 0; 88 #ifdef DEBUG 89 fprintf(stderr, "========== iconv(): TCVN5712 -->UCS-2 ==========\n"); 90 #endif 91 if (st == NULL) { 92 errno = EBADF; 93 return ((size_t) -1); 94 } 95 96 if (inbuf == NULL || *inbuf == NULL) { /* Reset request. */ 97 st->_errno = 0; 98 return ((size_t) 0); 99 } 100 101 st->_errno = 0; /* Reset internal errno */ 102 errno = 0; /* Reset external errno */ 103 104 /* Convert tcvn encoding to UCS-2 */ 105 while (*inbytesleft > 0 && *outbytesleft > 0) { 106 unsigned char ch = 0; 107 108 if (st->last != 0) { 109 if (ISCOMB_TCVN((unsigned char)**inbuf)) { 110 /* 111 * Composed characters with combine character 112 */ 113 idx = binsearch(st->last, tcvn_comb_data, VOWEL_NUM); 114 if (idx >= 0) { 115 ch = tcvn_comb_data[idx].composed[(unsigned char)**inbuf - 0xb0]; 116 } else { 117 errno = EBADF; 118 return ((size_t)-1); 119 } 120 st->last = 0; 121 } else { 122 tcvn_2_viscii(st->last, &chout); 123 if (st->last != 0x0 && chout == 0x0) { 124 unconv++; 125 chout = NON_ID_CHAR; 126 } 127 128 *(*outbuf)++ = chout; 129 (*outbytesleft) -= 1; 130 ch = (unsigned char)**inbuf; 131 } 132 st->last = 0; 133 } else { 134 ch = (unsigned char)**inbuf; 135 if (ch >= 0x41 && ch <= 0xad 136 && ((tcvn_comp_bases_mask0[(ch-0x40) >> 5] >> (ch & 0x1f)) & 1)) { 137 /* 138 * uni is vowel, it's a possible match with combine character. 139 * Buffer it. 140 * */ 141 st->last = ch; 142 (*inbuf)++; 143 (*inbytesleft)--; 144 continue; 145 } 146 } 147 148 149 tcvn_2_viscii(ch, &chout); 150 if (ch != 0x0 && chout == 0x0) { 151 unconv++; 152 chout = NON_ID_CHAR; 153 } 154 155 *(*outbuf)++ = chout; 156 (*outbytesleft) -= 1; 157 (*inbuf)++; 158 (*inbytesleft)--; 159 160 } 161 162 if ( *inbytesleft > 0 && *outbytesleft <= 0 ) { 163 errno = E2BIG; 164 st->last = 0; 165 return ((size_t)-1); 166 } 167 168 if (st->last != 0) { 169 tcvn_2_viscii(st->last, &chout); 170 if (**inbuf != 0x0 && chout == 0x0) { 171 unconv++; 172 chout = NON_ID_CHAR; 173 } 174 st->last = 0; 175 *(*outbuf)++ = chout; 176 (*outbytesleft) -= 1; 177 } 178 return ((size_t)unconv); 179 180 } 181 182 /* binsearch: find x in v[0] <= v[1] <= ... <= v[n-1] */ 183 static int binsearch(unsigned short x, Combine_map_tcvn v[], int n) 184 { 185 int low = 0; 186 int mid = 0; 187 int high = n - 1; 188 189 low = 0; 190 while (low <= high) { 191 mid = (low + high) / 2; 192 if (x < (unsigned short)v[mid].base) 193 high = mid - 1; 194 else if (x > (unsigned short)v[mid].base) 195 low = mid + 1; 196 else 197 /* found match */ 198 return mid; 199 } 200 201 /* no match */ 202 return (-1); 203 } 204