xref: /illumos-gate/usr/src/lib/iconv_modules/common/tab_lookup.c (revision 16d8656330ae5622ec32e5007f62145ebafdc50f)
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 /*
23  * Copyright (c) 1997, by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <sys/types.h>
31 
32 #include "tab_lookup.h"   	/* table lookup data types */
33 
34 int bisearch(unsigned long val, _icv_state *st, int n);
35 
36 /*
37  * Actual conversion; called from iconv().
38  * Peforms conversion as per the parameters specified in
39  * structure st.
40  */
41 size_t
_icv_iconv_lu(_icv_state * st,unsigned char ** ibuf,size_t * inbytesleft,unsigned char ** obuf,size_t * outbytesleft)42 _icv_iconv_lu(_icv_state *st, unsigned char **ibuf, size_t *inbytesleft,
43                               unsigned char **obuf, size_t *outbytesleft)
44 {
45         int     	  idx, data_size;
46 	unsigned  long 	  search_val = 0, match_val;
47 	unsigned  char 	  **inbuf, **outbuf;
48 
49         inbuf  = (unsigned char **)ibuf;
50         outbuf = (unsigned char **)obuf;
51 
52         if (st == NULL) {
53                 errno = EBADF;
54                 return ((size_t)-1);
55         }
56 
57         if (inbuf == NULL || *inbuf == NULL) { /* Reset request */
58 
59 	    return 0;
60         }
61 
62         errno = 0;
63 
64 
65         while (*inbytesleft > 0 && *outbytesleft > 0) {
66 	    fprintf(stderr, "INBL: %d , OUBL: %d \n",
67 		    *inbytesleft, *outbytesleft);
68 	    search_val = 0;
69 
70 	    /*
71 	     * form a search member
72 	     * lookup character by character
73 	     */
74 
75 	    if ( st->left_to_right ) {
76 	        /*
77 	         * create search val from the left code
78 	         */
79 
80 	        data_size  = st->left_code_size;
81 	        while ( data_size > 0  ) {
82 		    search_val = ( search_val << 8 ) |  ( **inbuf );
83 		    data_size--;
84 	            (*inbuf)++;
85 	            (*inbytesleft)--;
86 	        }
87 
88 	        idx = bisearch(search_val, st, st->table_size);
89 #ifdef TEST
90 		fprintf(stderr, "Match idx: %d \n", idx);
91 #endif
92 
93 	        if ( idx >= 0 ) {
94 		    /*
95 		     * create matched code from the right column
96 		     */
97 		    match_val = st->table[idx].right_code;
98 
99 	        } else {
100 		    match_val = NON_ID_CHAR;
101 
102 	        }
103 
104 	        /*
105 	         * Check sufficient space in the outbuf
106 	         */
107 	        if ( *outbytesleft >= st->right_code_size ) {
108 
109                     data_size  = st->right_code_size;
110 	            while ( data_size > 0 ) {
111 		        *(*outbuf + data_size-- - 1 ) =
112 			    (unsigned char) (match_val & 0xff);
113 #ifdef TEST
114 		        fprintf(stderr, "outbyte: %x \n",
115 			       (unsigned char) (match_val & 0xff));
116 #endif
117 		        match_val >>= 8;
118 	            }
119 	            (*outbuf) += st->right_code_size;
120 	            (*outbytesleft) -= st->right_code_size;
121 
122 	        } else {
123 	            /* no space for outbytes */
124 	            errno = E2BIG;
125 		    return ((size_t)-1);
126 	        }
127 	    } else {
128 	        /* search from right to left */
129 	        /*
130 	         * create search val from the left code
131 	         */
132 
133 	        data_size  = st->right_code_size;
134 	        while ( data_size > 0  ) {
135 		    search_val = ( search_val << 8 ) |  ( **inbuf );
136 		    data_size--;
137 	            (*inbuf)++;
138 	            (*inbytesleft)--;
139 	        }
140 
141 	        idx = bisearch(search_val, st, st->table_size);
142 
143 #ifdef TEST
144 		fprintf(stderr, "Match idx: %d \n", idx);
145 #endif
146 
147 	        if ( idx >= 0 ) {
148 		    /*
149 		     * create matched code from the right column
150 		     */
151 		    match_val = st->table[idx].left_code;
152 
153 	        } else {
154 		    match_val = UCS2_NON_ID_CHAR;
155 
156 	        }
157 
158 	        /*
159 	         * Check sufficient space in the outbuf
160 	         */
161 	        if ( *outbytesleft >= st->left_code_size ) {
162 
163                     data_size  = st->left_code_size;
164 	            while ( data_size > 0 ) {
165 		        *(*outbuf + data_size-- - 1 ) =
166 			    (unsigned char) (match_val & 0xff);
167 #ifdef TEST
168 		        fprintf(stderr, "outbyte: %x \n",
169 			       (unsigned char) (match_val & 0xff));
170 #endif
171 		        match_val >>= 8;
172 	            }
173 	            (*outbuf) += st->left_code_size;
174 	            (*outbytesleft) -= st->left_code_size;
175 
176 	        } else {
177 	            /* no space for outbytes */
178 	            errno = E2BIG;
179 		    return ((size_t)-1);
180 	        }
181 
182 	    }
183 #ifdef TEST
184 	    fprintf(stderr, "Search: %x  match: %x \n", search_val, match_val);
185 #endif
186 
187     }/* (*inbytesleft) && (*outbytesleft) */
188 
189     if ( *inbytesleft && (!(*outbytesleft)) ) {
190 	errno = E2BIG;
191 	return ((size_t)-1);
192     }
193 
194     return (*inbytesleft);
195 }
196 
197 
198 /*
199  * Performs the binary search in the lookup table of structure
200  * st. Memebers (left_to_right, right_to_left)  control
201  * the lookup direction.
202  */
bisearch(unsigned long val,_icv_state * st,int n)203 int bisearch(unsigned long val, _icv_state *st, int n)
204 {
205     int low, high, mid;
206 
207 #ifdef TEST
208 	    fprintf(stderr, "Search: %x limit: %d  \n", val, n);
209 #endif
210 
211     low = 0;
212     high = n - 1;
213     while ( low <= high ) {
214 	mid = (low + high) / 2;
215 	if ( st->left_to_right ) {
216 	    if ( val < st->table[mid].left_code )
217 		high = mid - 1;
218 	     else if ( val > st->table[mid].left_code )
219 		      low = mid + 1;
220 	     else /* found match */
221 		return mid;
222 	} else {
223 	    if ( val < st->table[mid].right_code )
224 		high = mid - 1;
225 	     else if ( val > st->table[mid].right_code )
226 		      low = mid + 1;
227 	     else /* found match */
228 		return mid;
229         }
230 
231     }
232 
233     return (-1);
234 }
235