/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1997, by Sun Microsystems, Inc. * All rights reserved. */ #include #include #include #include #include "tab_lookup.h" /* table lookup data types */ int bisearch(unsigned long val, _icv_state *st, int n); /* * Actual conversion; called from iconv(). * Peforms conversion as per the parameters specified in * structure st. */ size_t _icv_iconv_lu(_icv_state *st, unsigned char **ibuf, size_t *inbytesleft, unsigned char **obuf, size_t *outbytesleft) { int idx, data_size; unsigned long search_val = 0, match_val; unsigned char **inbuf, **outbuf; inbuf = (unsigned char **)ibuf; outbuf = (unsigned char **)obuf; if (st == NULL) { errno = EBADF; return ((size_t)-1); } if (inbuf == NULL || *inbuf == NULL) { /* Reset request */ return 0; } errno = 0; while (*inbytesleft > 0 && *outbytesleft > 0) { fprintf(stderr, "INBL: %d , OUBL: %d \n", *inbytesleft, *outbytesleft); search_val = 0; /* * form a search member * lookup character by character */ if ( st->left_to_right ) { /* * create search val from the left code */ data_size = st->left_code_size; while ( data_size > 0 ) { search_val = ( search_val << 8 ) | ( **inbuf ); data_size--; (*inbuf)++; (*inbytesleft)--; } idx = bisearch(search_val, st, st->table_size); #ifdef TEST fprintf(stderr, "Match idx: %d \n", idx); #endif if ( idx >= 0 ) { /* * create matched code from the right column */ match_val = st->table[idx].right_code; } else { match_val = NON_ID_CHAR; } /* * Check sufficient space in the outbuf */ if ( *outbytesleft >= st->right_code_size ) { data_size = st->right_code_size; while ( data_size > 0 ) { *(*outbuf + data_size-- - 1 ) = (unsigned char) (match_val & 0xff); #ifdef TEST fprintf(stderr, "outbyte: %x \n", (unsigned char) (match_val & 0xff)); #endif match_val >>= 8; } (*outbuf) += st->right_code_size; (*outbytesleft) -= st->right_code_size; } else { /* no space for outbytes */ errno = E2BIG; return ((size_t)-1); } } else { /* search from right to left */ /* * create search val from the left code */ data_size = st->right_code_size; while ( data_size > 0 ) { search_val = ( search_val << 8 ) | ( **inbuf ); data_size--; (*inbuf)++; (*inbytesleft)--; } idx = bisearch(search_val, st, st->table_size); #ifdef TEST fprintf(stderr, "Match idx: %d \n", idx); #endif if ( idx >= 0 ) { /* * create matched code from the right column */ match_val = st->table[idx].left_code; } else { match_val = UCS2_NON_ID_CHAR; } /* * Check sufficient space in the outbuf */ if ( *outbytesleft >= st->left_code_size ) { data_size = st->left_code_size; while ( data_size > 0 ) { *(*outbuf + data_size-- - 1 ) = (unsigned char) (match_val & 0xff); #ifdef TEST fprintf(stderr, "outbyte: %x \n", (unsigned char) (match_val & 0xff)); #endif match_val >>= 8; } (*outbuf) += st->left_code_size; (*outbytesleft) -= st->left_code_size; } else { /* no space for outbytes */ errno = E2BIG; return ((size_t)-1); } } #ifdef TEST fprintf(stderr, "Search: %x match: %x \n", search_val, match_val); #endif }/* (*inbytesleft) && (*outbytesleft) */ if ( *inbytesleft && (!(*outbytesleft)) ) { errno = E2BIG; return ((size_t)-1); } return (*inbytesleft); } /* * Performs the binary search in the lookup table of structure * st. Memebers (left_to_right, right_to_left) control * the lookup direction. */ int bisearch(unsigned long val, _icv_state *st, int n) { int low, high, mid; #ifdef TEST fprintf(stderr, "Search: %x limit: %d \n", val, n); #endif low = 0; high = n - 1; while ( low <= high ) { mid = (low + high) / 2; if ( st->left_to_right ) { if ( val < st->table[mid].left_code ) high = mid - 1; else if ( val > st->table[mid].left_code ) low = mid + 1; else /* found match */ return mid; } else { if ( val < st->table[mid].right_code ) high = mid - 1; else if ( val > st->table[mid].right_code ) low = mid + 1; else /* found match */ return mid; } } return (-1); }