root/usr/src/lib/iconv_modules/zh/common/zh_TW-iso2022-CN-EXT%zh_TW-euc.c
/*
 * 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.
 */


/*
   Converts From:       ISO2022-CN-EXT encoding.
   Converts To:         Taiwanese EUC encoding ( CNS11643 )
 */

#include "iso2022-cn.h"
#include "gb2312_cns11643.h"


/* Forward reference the functions constrained to the scope of this file */
static int chinese_to_euc( _iconv_st*, unsigned char**, size_t*, int);
static int gb_to_euc( _iconv_st *st, unsigned char **outbuf, size_t *outbytesleft);


extern int errno;


size_t
_icv_iconv(_iconv_st *st, char **inbuf, size_t *inbytesleft,
                                char **outbuf, size_t *outbytesleft)
{
        return iso2022_icv_iconv(st, inbuf, inbytesleft, (unsigned char**) outbuf, outbytesleft,
                        chinese_to_euc);
}


static int
chinese_to_euc( _iconv_st *st, unsigned char **outbuf, size_t *outbytesleft, int plane_no )
{

        if ( st->SSfunc == NONE && st->SOcharset == 'A') {      /* GB2312 */
            return gb_to_euc(st, outbuf, outbytesleft);
        }

        if ( plane_no < 0 )/* Not a CNS character */
            return (1);

        if ( plane_no >= 2) {
            if ( *outbytesleft < 4 ){
                    st->_errno = errno = E2BIG;
                    return (-1);
            }
            /* Output the multi-byte code and plane number */
            *(*outbuf)++ = (unsigned char) MBYTE;
            *(*outbuf)++ = (unsigned char) (PMASK + plane_no);
            (*outbytesleft) -= 2;
        }

        if ( *outbytesleft < 2 ){ /* Redundant test if SS2 or SS3 character */
            st->_errno = errno = E2BIG;
            return (-1);
        }

        *(*outbuf)++ = (unsigned char) (st->keepc[0] | MSB);
        *(*outbuf)++ = (unsigned char) (st->keepc[1] | MSB);
        (*outbytesleft) -= 2;

        return (0);
}

static int make_cns(_iconv_st *st, unsigned long cnscode, unsigned char **outbuf, size_t *outbytesleft)
{
        int plane_no, ret;      /* return buffer size */

        ret = (int) (cnscode >> 16);
        switch (ret) {
        case 0x21:      /* 0x8EA1 - G */
        case 0x22:      /* 0x8EA2 - H */
        case 0x23:      /* 0x8EA3 - I */
        case 0x24:      /* 0x8EA4 - J */
        case 0x25:      /* 0x8EA5 - K */
        case 0x26:      /* 0x8EA6 - L */
        case 0x27:      /* 0x8EA7 - M */
        case 0x28:      /* 0x8EA8 - N */
        case 0x29:      /* 0x8EA9 - O */
        case 0x2a:      /* 0x8EAA - P */
        case 0x2b:      /* 0x8EAB - Q */
        case 0x2c:      /* 0x8EAC - R */
        case 0x2d:      /* 0x8EAD - S */
        case 0x2f:      /* 0x8EAF - U */
        case 0x30:      /* 0x8EB0 - V */
            plane_no =  ret - 0x20;
            break;
        case 0x2e:      /* 0x8EAE - T */
            plane_no = 3;               /* CNS 11643-1992 */
            break;
        default:
            st->_errno = errno = EILSEQ;
            return (0);
        }

        if ( plane_no >= 2) {
            if ( *outbytesleft < 4 ){
                st->_errno = errno = E2BIG;
                return (-1);
            }
            /* Output the multi-byte code and plane number */
            *(*outbuf)++ = (unsigned char) MBYTE;
            *(*outbuf)++ = (unsigned char) (PMASK + plane_no);
            (*outbytesleft) -= 2;
        }

        if ( *outbytesleft < 2 ){ /* Redundant test if SS2 or SS3 character */
            st->_errno = errno = E2BIG;
            return (-1);
        }

        *(*outbuf)++ = (unsigned char) (((cnscode >> 8) & 0xff) | MSB);
        *(*outbuf)++ = (unsigned char) ((cnscode & 0xff) | MSB);
        (*outbytesleft) -= 2;

        return (0);
}

static int
gb_cns_comp(const void *p1, const void *p2)
{
    gb_cns *ptr1 = (gb_cns*) p1, *ptr2 = (gb_cns*) p2;
    long result = ptr1->gbcode - ptr2->gbcode;
    return result == 0 ? 0 : result > 0 ? 1 : -1;
}

static int
gb_to_euc( _iconv_st *st, unsigned char **outbuf, size_t *outbytesleft )
{
        gb_cns *ptr, key;

        key.gbcode = (unsigned long) ((st->keepc[0] | MSB) << 8) + (st->keepc[1] | MSB);
        ptr = (gb_cns*) bsearch(&key, gb_cns_tab, BIG5MAX, sizeof(gb_cns), gb_cns_comp);

        if ( ptr && ptr->cnscode > 0 )
            return make_cns(st, ptr->cnscode, outbuf, outbytesleft);
        else
            return (1);
}