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_UNI__ 31 #include <unicode_tcvn.h> /* Unicode to tcvn mapping table */ 32 #include <vi_combine.h> 33 #include "common_defs.h" 34 35 36 typedef struct _icv_state { 37 int _errno; /* internal errno */ 38 unsigned long last; 39 } _iconv_st; 40 41 #if defined(UCS_2LE) 42 #define SET_UCS(UNI) *(*outbuf)++ = (unsigned char)((UNI)&0xff); \ 43 *(*outbuf)++ = (unsigned char)(((UNI)>>8)&0xff); 44 #else 45 #define SET_UCS(UNI) *(*outbuf)++ = (unsigned char)(((UNI)>>8)&0xff); \ 46 *(*outbuf)++ = (unsigned char)((UNI)&0xff); 47 #endif 48 49 static int binsearch(unsigned long x, Combine_map v[], int n); 50 51 /* 52 * Open; called from iconv_open() 53 */ 54 void * 55 _icv_open() 56 { 57 _iconv_st *st; 58 59 if ((st = (_iconv_st *)malloc(sizeof(_iconv_st))) == NULL) { 60 errno = ENOMEM; 61 return ((void *) -1); 62 } 63 64 st->_errno = 0; 65 st->last = 0; 66 return ((void *) st); 67 } 68 69 70 /* 71 * Close; called from iconv_close() 72 */ 73 void 74 _icv_close(_iconv_st *st) 75 { 76 if (!st) 77 errno = EBADF; 78 else 79 free(st); 80 } 81 82 83 /* 84 * Actual conversion; called from iconv() 85 */ 86 size_t 87 _icv_iconv(_iconv_st *st, char **inbuf, size_t *inbytesleft, 88 char **outbuf, size_t *outbytesleft) 89 { 90 int unidx = -1; 91 #ifdef DEBUG 92 fprintf(stderr, "========== iconv(): TCVN5712 -->UCS-2 ==========\n"); 93 #endif 94 if (st == NULL) { 95 errno = EBADF; 96 return ((size_t) -1); 97 } 98 99 if (inbuf == NULL || *inbuf == NULL) { /* Reset request. */ 100 st->_errno = 0; 101 return ((size_t) 0); 102 } 103 104 st->_errno = 0; /* Reset internal errno */ 105 errno = 0; /* Reset external errno */ 106 107 /* Convert tcvn encoding to UCS-2 */ 108 while (*inbytesleft > 0 && *outbytesleft > 1) { 109 unsigned long uni = 0; 110 111 tcvn_2_uni((unsigned char*)*inbuf, &uni); 112 if (st->last != 0) { 113 if (ISCOMB_UNI(uni)) { 114 /* 115 * Composed characters with combine character 116 */ 117 unsigned int k = 0; 118 switch (uni) { 119 case 0x0300: k = 0; break; 120 case 0x0301: k = 1; break; 121 case 0x0303: k = 2; break; 122 case 0x0309: k = 3; break; 123 case 0x0323: k = 4; break; 124 default: 125 break; 126 } 127 unidx = binsearch(st->last, vi_comb_data, VOWEL_NUM); 128 if (unidx >= 0) { 129 uni = vi_comb_data[unidx].composed[k]; 130 } else { 131 errno = EBADF; 132 return ((size_t)-1); 133 } 134 st->last = 0; 135 136 } else { 137 SET_UCS(st->last); 138 (*outbytesleft) -= 2; 139 } 140 st->last = 0; 141 } else { 142 if (uni >= 0x0041 && uni <= 0x01b0 143 && ((tcvn_comp_bases_mask[(uni-0x0040) >> 5] >> (uni & 0x1f)) & 1)) { 144 /* 145 * uni is vowel, it's a possible match with combine character. 146 * Buffer it. 147 * */ 148 st->last = uni; 149 (*inbuf)++; 150 (*inbytesleft)--; 151 continue; 152 } 153 } 154 SET_UCS(uni); 155 (*outbytesleft) -= 2; 156 (*inbuf)++; 157 (*inbytesleft)--; 158 159 } 160 161 if ( *inbytesleft > 0 && *outbytesleft <= 1 ) { 162 errno = E2BIG; 163 st->last = 0; 164 return ((size_t)-1); 165 } 166 if (st->last!=0 ) { 167 SET_UCS(st->last); 168 st->last = 0; 169 (*outbytesleft) -= 2; 170 } 171 172 return ((size_t)(*inbytesleft)); 173 } 174 175 /* binsearch: find x in v[0] <= v[1] <= ... <= v[n-1] */ 176 static int binsearch(unsigned long x, Combine_map v[], int n) 177 { 178 int low = 0; 179 int mid = 0; 180 int high = n - 1; 181 182 low = 0; 183 while (low <= high) { 184 mid = ((high - low)>>1) + low; 185 if (x < v[mid].base) 186 high = mid - 1; 187 else if (x > v[mid].base) 188 low = mid + 1; 189 else 190 /* found match */ 191 return mid; 192 } 193 194 /* no match */ 195 return (-1); 196 } 197