/*
 * Copyright (c) 1999 Sun Microsystems, Inc.
 * Copyright (c) 1999 Nihon Sun Microsystems K.K.
 * All rights reserved.
 */

#ifndef _CSC_UTF_H
#define _CSC_UTF_H

/*
 * "$Id"
 */

#pragma ident	"@(#)csc_utf.h 1.1	99/05/24 SMI"

#ifdef	__cplusplus
extern "C" {
#endif


typedef	struct	{
	int	cmask;
	int	cval;
	int	bytes;
	int	shift;
	long	lmask;
	long	lval;
} utf16_utf8_conv_table_t;

static const utf16_utf8_conv_table_t	utf16_utf8_conv_table[] = {
	{0x80, 0x00, 1, 0*6, 0x0000007F, 0x00000000},	/* 1 byte sequence */
	{0xE0, 0xC0, 2, 1*6, 0x000007FF, 0x00000080},	/* 2 byte sequence */
	{0xF0, 0xE0, 3, 2*6, 0x0000FFFF, 0x00000800},	/* 3 byte sequence */
	{0xF8, 0xF0, 4, 3*6, 0x001FFFFF, 0x00010000},	/* 4 byte sequence */
	{0xFC, 0xF8, 5, 4*6, 0x03FFFFFF, 0x00200000},	/* 5 byte sequence */
	{0xFE, 0xFC, 6, 5*6, 0x7FFFFFFF, 0x04000000},	/* 6 byte sequence */
	{0x00, 0x00, 0, 0*0, 0x00000000, 0x00000000}	/* end of table */
};

#define UTF16_UTF8(uc, len, op, oleft)					\
{									\
	int				s;				\
	const utf16_utf8_conv_table_t *	tbl;				\
									\
	len = 0;							\
	for (tbl = utf16_utf8_conv_table; 0 != tbl->cmask; tbl++) {	\
		if (tbl->lmask < (uc)) {				\
			continue;					\
		}							\
		s = tbl->shift;						\
		*((op)++) = (tbl->cval | ((uc) >> s));			\
		(len)++;						\
		--(oleft);						\
		while (0 < s) {						\
			s -= 6;						\
			*((op)++) = (0x80 | (((uc) >> s) & 0x3f));	\
			(len)++;					\
			--(oleft);					\
		}							\
		break;							\
	}								\
}

#define UTF8_UTF16(ip, ileft, len, uc, ret_errno)			\
{									\
	int				c;				\
									\
	c = *(ip);							\
	if (0xf0 <= c) {						\
		ERROR_BREAK(EILSEQ);					\
	} else if (0xe0 <= c) {						\
		if ((ileft) < 3) {					\
			(len) = 0;					\
			ERROR_BREAK(EINVAL);				\
		}							\
		(len) = 3;						\
		(uc) = (((*(ip++)) & 0x0f) << 12);			\
		(uc) |= (((*(ip++)) & 0x3f) << 6);			\
		(uc) |= ((*(ip++)) & 0x3f);				\
		(ileft) -= 3;						\
	} else if (0xc0 <= c) {						\
		if ((ileft) < 2) {					\
			(len) = 0;					\
			ERROR_BREAK(EINVAL);				\
		}							\
		(len) = 2;						\
		(uc) = (((*(ip++)) & 0x1f) << 6);			\
		(uc) |= ((*(ip++)) & 0x3f);				\
		(ileft) -= 2;						\
	} else {							\
		if ((ileft) < 1) {					\
			(len) = 0;					\
			ERROR_BREAK(EINVAL);				\
		}							\
		(len) = 1;						\
		(uc) = (*(ip++));					\
		(ileft) -= 1;						\
	}								\
}

#define UTF8LEN(length, start, end)					\
{									\
	const unsigned char *		p0;				\
	const unsigned char *		p1;				\
	utf16_utf8_conv_table_t *	tbl;				\
									\
	p0 = (unsigned char *)start;					\
	p1 = (unsigned char *)end;					\
	while (p0 < p1) {						\
		tbl = utf16_utf8_conv_table;				\
		for (; 0 != tbl->cmask; tbl++) {			\
			if (tbl->cval & *p0) {				\
				p0 += tbl->bytes;			\
				(length) += 1;				\
				break;					\
			}						\
		}							\
	}								\
}


#ifdef	__cplusplus
}
#endif

#endif /* !_CSC_UTF_H */
