1*91e1e26aSAlexander Pyhalov /* 2*91e1e26aSAlexander Pyhalov * CDDL HEADER START 3*91e1e26aSAlexander Pyhalov * 4*91e1e26aSAlexander Pyhalov * The contents of this file are subject to the terms of the 5*91e1e26aSAlexander Pyhalov * Common Development and Distribution License (the "License"). 6*91e1e26aSAlexander Pyhalov * You may not use this file except in compliance with the License. 7*91e1e26aSAlexander Pyhalov * 8*91e1e26aSAlexander Pyhalov * You can obtain a copy of the license at src/OPENSOLARIS.LICENSE 9*91e1e26aSAlexander Pyhalov * or http://www.opensolaris.org/os/licensing. 10*91e1e26aSAlexander Pyhalov * See the License for the specific language governing permissions 11*91e1e26aSAlexander Pyhalov * and limitations under the License. 12*91e1e26aSAlexander Pyhalov * 13*91e1e26aSAlexander Pyhalov * When distributing Covered Code, include this CDDL HEADER in each 14*91e1e26aSAlexander Pyhalov * file and include the License file at src/OPENSOLARIS.LICENSE. 15*91e1e26aSAlexander Pyhalov * If applicable, add the following below this CDDL HEADER, with the 16*91e1e26aSAlexander Pyhalov * fields enclosed by brackets "[]" replaced with your own identifying 17*91e1e26aSAlexander Pyhalov * information: Portions Copyright [yyyy] [name of copyright owner] 18*91e1e26aSAlexander Pyhalov * 19*91e1e26aSAlexander Pyhalov * CDDL HEADER END 20*91e1e26aSAlexander Pyhalov */ 21*91e1e26aSAlexander Pyhalov /* 22*91e1e26aSAlexander Pyhalov * Copyright (c) 2008, by Sun Microsystems, Inc. 23*91e1e26aSAlexander Pyhalov * All rights reserved. 24*91e1e26aSAlexander Pyhalov */ 25*91e1e26aSAlexander Pyhalov 26*91e1e26aSAlexander Pyhalov #include <stdio.h> 27*91e1e26aSAlexander Pyhalov #include <errno.h> 28*91e1e26aSAlexander Pyhalov #include <stdlib.h> 29*91e1e26aSAlexander Pyhalov #include <sys/types.h> 30*91e1e26aSAlexander Pyhalov #define __NEED_TCVN_2_UNI__ 31*91e1e26aSAlexander Pyhalov #include <unicode_tcvn.h> /* Unicode to tcvn mapping table */ 32*91e1e26aSAlexander Pyhalov #include <vi_combine.h> 33*91e1e26aSAlexander Pyhalov #include "common_defs.h" 34*91e1e26aSAlexander Pyhalov 35*91e1e26aSAlexander Pyhalov 36*91e1e26aSAlexander Pyhalov typedef struct _icv_state { 37*91e1e26aSAlexander Pyhalov int _errno; /* internal errno */ 38*91e1e26aSAlexander Pyhalov unsigned long last; 39*91e1e26aSAlexander Pyhalov } _iconv_st; 40*91e1e26aSAlexander Pyhalov 41*91e1e26aSAlexander Pyhalov #if defined(UCS_2LE) 42*91e1e26aSAlexander Pyhalov #define SET_UCS(UNI) *(*outbuf)++ = (unsigned char)((UNI)&0xff); \ 43*91e1e26aSAlexander Pyhalov *(*outbuf)++ = (unsigned char)(((UNI)>>8)&0xff); 44*91e1e26aSAlexander Pyhalov #else 45*91e1e26aSAlexander Pyhalov #define SET_UCS(UNI) *(*outbuf)++ = (unsigned char)(((UNI)>>8)&0xff); \ 46*91e1e26aSAlexander Pyhalov *(*outbuf)++ = (unsigned char)((UNI)&0xff); 47*91e1e26aSAlexander Pyhalov #endif 48*91e1e26aSAlexander Pyhalov 49*91e1e26aSAlexander Pyhalov static int binsearch(unsigned long x, Combine_map v[], int n); 50*91e1e26aSAlexander Pyhalov 51*91e1e26aSAlexander Pyhalov /* 52*91e1e26aSAlexander Pyhalov * Open; called from iconv_open() 53*91e1e26aSAlexander Pyhalov */ 54*91e1e26aSAlexander Pyhalov void * 55*91e1e26aSAlexander Pyhalov _icv_open() 56*91e1e26aSAlexander Pyhalov { 57*91e1e26aSAlexander Pyhalov _iconv_st *st; 58*91e1e26aSAlexander Pyhalov 59*91e1e26aSAlexander Pyhalov if ((st = (_iconv_st *)malloc(sizeof(_iconv_st))) == NULL) { 60*91e1e26aSAlexander Pyhalov errno = ENOMEM; 61*91e1e26aSAlexander Pyhalov return ((void *) -1); 62*91e1e26aSAlexander Pyhalov } 63*91e1e26aSAlexander Pyhalov 64*91e1e26aSAlexander Pyhalov st->_errno = 0; 65*91e1e26aSAlexander Pyhalov st->last = 0; 66*91e1e26aSAlexander Pyhalov return ((void *) st); 67*91e1e26aSAlexander Pyhalov } 68*91e1e26aSAlexander Pyhalov 69*91e1e26aSAlexander Pyhalov 70*91e1e26aSAlexander Pyhalov /* 71*91e1e26aSAlexander Pyhalov * Close; called from iconv_close() 72*91e1e26aSAlexander Pyhalov */ 73*91e1e26aSAlexander Pyhalov void 74*91e1e26aSAlexander Pyhalov _icv_close(_iconv_st *st) 75*91e1e26aSAlexander Pyhalov { 76*91e1e26aSAlexander Pyhalov if (!st) 77*91e1e26aSAlexander Pyhalov errno = EBADF; 78*91e1e26aSAlexander Pyhalov else 79*91e1e26aSAlexander Pyhalov free(st); 80*91e1e26aSAlexander Pyhalov } 81*91e1e26aSAlexander Pyhalov 82*91e1e26aSAlexander Pyhalov 83*91e1e26aSAlexander Pyhalov /* 84*91e1e26aSAlexander Pyhalov * Actual conversion; called from iconv() 85*91e1e26aSAlexander Pyhalov */ 86*91e1e26aSAlexander Pyhalov size_t 87*91e1e26aSAlexander Pyhalov _icv_iconv(_iconv_st *st, char **inbuf, size_t *inbytesleft, 88*91e1e26aSAlexander Pyhalov char **outbuf, size_t *outbytesleft) 89*91e1e26aSAlexander Pyhalov { 90*91e1e26aSAlexander Pyhalov int unidx = -1; 91*91e1e26aSAlexander Pyhalov #ifdef DEBUG 92*91e1e26aSAlexander Pyhalov fprintf(stderr, "========== iconv(): TCVN5712 -->UCS-2 ==========\n"); 93*91e1e26aSAlexander Pyhalov #endif 94*91e1e26aSAlexander Pyhalov if (st == NULL) { 95*91e1e26aSAlexander Pyhalov errno = EBADF; 96*91e1e26aSAlexander Pyhalov return ((size_t) -1); 97*91e1e26aSAlexander Pyhalov } 98*91e1e26aSAlexander Pyhalov 99*91e1e26aSAlexander Pyhalov if (inbuf == NULL || *inbuf == NULL) { /* Reset request. */ 100*91e1e26aSAlexander Pyhalov st->_errno = 0; 101*91e1e26aSAlexander Pyhalov return ((size_t) 0); 102*91e1e26aSAlexander Pyhalov } 103*91e1e26aSAlexander Pyhalov 104*91e1e26aSAlexander Pyhalov st->_errno = 0; /* Reset internal errno */ 105*91e1e26aSAlexander Pyhalov errno = 0; /* Reset external errno */ 106*91e1e26aSAlexander Pyhalov 107*91e1e26aSAlexander Pyhalov /* Convert tcvn encoding to UCS-2 */ 108*91e1e26aSAlexander Pyhalov while (*inbytesleft > 0 && *outbytesleft > 1) { 109*91e1e26aSAlexander Pyhalov unsigned long uni = 0; 110*91e1e26aSAlexander Pyhalov 111*91e1e26aSAlexander Pyhalov tcvn_2_uni((unsigned char*)*inbuf, &uni); 112*91e1e26aSAlexander Pyhalov if (st->last != 0) { 113*91e1e26aSAlexander Pyhalov if (ISCOMB_UNI(uni)) { 114*91e1e26aSAlexander Pyhalov /* 115*91e1e26aSAlexander Pyhalov * Composed characters with combine character 116*91e1e26aSAlexander Pyhalov */ 117*91e1e26aSAlexander Pyhalov unsigned int k = 0; 118*91e1e26aSAlexander Pyhalov switch (uni) { 119*91e1e26aSAlexander Pyhalov case 0x0300: k = 0; break; 120*91e1e26aSAlexander Pyhalov case 0x0301: k = 1; break; 121*91e1e26aSAlexander Pyhalov case 0x0303: k = 2; break; 122*91e1e26aSAlexander Pyhalov case 0x0309: k = 3; break; 123*91e1e26aSAlexander Pyhalov case 0x0323: k = 4; break; 124*91e1e26aSAlexander Pyhalov default: 125*91e1e26aSAlexander Pyhalov break; 126*91e1e26aSAlexander Pyhalov } 127*91e1e26aSAlexander Pyhalov unidx = binsearch(st->last, vi_comb_data, VOWEL_NUM); 128*91e1e26aSAlexander Pyhalov if (unidx >= 0) { 129*91e1e26aSAlexander Pyhalov uni = vi_comb_data[unidx].composed[k]; 130*91e1e26aSAlexander Pyhalov } else { 131*91e1e26aSAlexander Pyhalov errno = EBADF; 132*91e1e26aSAlexander Pyhalov return ((size_t)-1); 133*91e1e26aSAlexander Pyhalov } 134*91e1e26aSAlexander Pyhalov st->last = 0; 135*91e1e26aSAlexander Pyhalov 136*91e1e26aSAlexander Pyhalov } else { 137*91e1e26aSAlexander Pyhalov SET_UCS(st->last); 138*91e1e26aSAlexander Pyhalov (*outbytesleft) -= 2; 139*91e1e26aSAlexander Pyhalov } 140*91e1e26aSAlexander Pyhalov st->last = 0; 141*91e1e26aSAlexander Pyhalov } else { 142*91e1e26aSAlexander Pyhalov if (uni >= 0x0041 && uni <= 0x01b0 143*91e1e26aSAlexander Pyhalov && ((tcvn_comp_bases_mask[(uni-0x0040) >> 5] >> (uni & 0x1f)) & 1)) { 144*91e1e26aSAlexander Pyhalov /* 145*91e1e26aSAlexander Pyhalov * uni is vowel, it's a possible match with combine character. 146*91e1e26aSAlexander Pyhalov * Buffer it. 147*91e1e26aSAlexander Pyhalov * */ 148*91e1e26aSAlexander Pyhalov st->last = uni; 149*91e1e26aSAlexander Pyhalov (*inbuf)++; 150*91e1e26aSAlexander Pyhalov (*inbytesleft)--; 151*91e1e26aSAlexander Pyhalov continue; 152*91e1e26aSAlexander Pyhalov } 153*91e1e26aSAlexander Pyhalov } 154*91e1e26aSAlexander Pyhalov SET_UCS(uni); 155*91e1e26aSAlexander Pyhalov (*outbytesleft) -= 2; 156*91e1e26aSAlexander Pyhalov (*inbuf)++; 157*91e1e26aSAlexander Pyhalov (*inbytesleft)--; 158*91e1e26aSAlexander Pyhalov 159*91e1e26aSAlexander Pyhalov } 160*91e1e26aSAlexander Pyhalov 161*91e1e26aSAlexander Pyhalov if ( *inbytesleft > 0 && *outbytesleft <= 1 ) { 162*91e1e26aSAlexander Pyhalov errno = E2BIG; 163*91e1e26aSAlexander Pyhalov st->last = 0; 164*91e1e26aSAlexander Pyhalov return ((size_t)-1); 165*91e1e26aSAlexander Pyhalov } 166*91e1e26aSAlexander Pyhalov if (st->last!=0 ) { 167*91e1e26aSAlexander Pyhalov SET_UCS(st->last); 168*91e1e26aSAlexander Pyhalov st->last = 0; 169*91e1e26aSAlexander Pyhalov (*outbytesleft) -= 2; 170*91e1e26aSAlexander Pyhalov } 171*91e1e26aSAlexander Pyhalov 172*91e1e26aSAlexander Pyhalov return ((size_t)(*inbytesleft)); 173*91e1e26aSAlexander Pyhalov } 174*91e1e26aSAlexander Pyhalov 175*91e1e26aSAlexander Pyhalov /* binsearch: find x in v[0] <= v[1] <= ... <= v[n-1] */ 176*91e1e26aSAlexander Pyhalov static int binsearch(unsigned long x, Combine_map v[], int n) 177*91e1e26aSAlexander Pyhalov { 178*91e1e26aSAlexander Pyhalov int low = 0; 179*91e1e26aSAlexander Pyhalov int mid = 0; 180*91e1e26aSAlexander Pyhalov int high = n - 1; 181*91e1e26aSAlexander Pyhalov 182*91e1e26aSAlexander Pyhalov low = 0; 183*91e1e26aSAlexander Pyhalov while (low <= high) { 184*91e1e26aSAlexander Pyhalov mid = ((high - low)>>1) + low; 185*91e1e26aSAlexander Pyhalov if (x < v[mid].base) 186*91e1e26aSAlexander Pyhalov high = mid - 1; 187*91e1e26aSAlexander Pyhalov else if (x > v[mid].base) 188*91e1e26aSAlexander Pyhalov low = mid + 1; 189*91e1e26aSAlexander Pyhalov else 190*91e1e26aSAlexander Pyhalov /* found match */ 191*91e1e26aSAlexander Pyhalov return mid; 192*91e1e26aSAlexander Pyhalov } 193*91e1e26aSAlexander Pyhalov 194*91e1e26aSAlexander Pyhalov /* no match */ 195*91e1e26aSAlexander Pyhalov return (-1); 196*91e1e26aSAlexander Pyhalov } 197