/*-
 * Copyright (c) 1999,2000
 *	Konstantin Chuguev.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by Konstantin Chuguev
 *	and its contributors.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	iconv (Charset Conversion Library) v2.0
 */

#ifndef _ICONV_H_
#define _ICONV_H_

#include <sys/types.h>	/* size_t */

/*
 * iconv_t:	charset conversion descriptor type
 */
typedef void *iconv_t;

__BEGIN_DECLS

iconv_t	iconv_open(const char *, const char *);
size_t	iconv(iconv_t, const char **, size_t *, char **, size_t *);
int	iconv_close(iconv_t);

__END_DECLS


#ifdef ICONV_INTERNAL
/*
 * Internal declarations for charset conversion library and modules.
 */

#include <stddef.h>		/* NULL */
/* #include <sys/types.h>	   size_t
 * (already included in ICONV_H public section) */


/*
 * Unicode character data types and constants.
 */

#define UCS_CHAR_ZERO_WIDTH_NBSP 0xFEFF
#define UCS_CHAR_INVALID	 0xFFFE
#define UCS_CHAR_NONE		 0xFFFF

typedef u_int16_t ucs2_t;	/* Unicode character [D5] */
typedef u_int32_t ucs4_t;	/* Unicode scalar character [D28] */
#define ucs_t     ucs4_t

#define iconv_char32bit(ch)	((ch) & 0xFFFF0000)


/*
 * Builtin CCS and CES data.
 */

typedef struct {
	const char *key;
	const void *value;
} iconv_builtin_table;

extern const iconv_builtin_table iconv_builtin_ccs[];
extern const iconv_builtin_table iconv_builtin_ces[];


/*
 * Table-driven coded character set (CCS) definitions
 */
struct iconv_ccs;

/* Basic CCS functions */
typedef ucs2_t iconv_ccs_convert_t(const void *table, ucs2_t ch);
typedef int iconv_ccs_close_t(struct iconv_ccs *desc);

/* CCS structure */
struct iconv_ccs {
	const void *		from_ucs;	/* FROM table pointer */
	const void *		to_ucs;		/* TO table pointer */
	iconv_ccs_convert_t *	convert_from_ucs;	/* converter  */
	iconv_ccs_convert_t *	convert_to_ucs;		/*  functions */
	iconv_ccs_close_t *	close;		/* close function */
	void *			extra;		/* optional extra data */
	unsigned int		nbits;		/* number of bits */
};

/* CCS initialisation function */
int iconv_ccs_init(struct iconv_ccs *ccs, const char *name);

/* CCS conversion macros */
#define ICONV_CCS_CONVERT_FROM_UCS(ccs, ch) \
        ((ccs)->convert_from_ucs((ccs)->from_ucs, (ch)))
#define ICONV_CCS_CONVERT_TO_UCS(ccs, ch) \
        ((ccs)->convert_to_ucs((ccs)->to_ucs, (ch)))
#define ICONV_CCS_NBITS

/*
 * Module-driven character encoding scheme (CES) definitions
 */
struct iconv_ces;

/* Basic CES function types */
typedef int  iconv_ces_init_t(void **, const char *, const void *);
typedef	int iconv_ces_close_t(void *);
typedef	void iconv_ces_reset_t(void *);
typedef ssize_t iconv_ces_convert_from_ucs_t(
	struct iconv_ces *data, ucs_t in, unsigned char **outbuf,
	size_t *outbytesleft);
typedef ucs_t iconv_ces_convert_to_ucs_t(
	struct iconv_ces *data, const unsigned char **inbuf,
	size_t *inbytesleft);

/* CES descriptor structure - CES class data */
struct iconv_ces_desc {
	iconv_ces_init_t *	init;
	iconv_ces_close_t *	close;	/* class-specific close function */
	iconv_ces_reset_t *	reset;
	iconv_ces_convert_from_ucs_t * convert_from_ucs;
	iconv_ces_convert_to_ucs_t * convert_to_ucs;
	const void *data;	/* optional specific CES class data */
};

/* explicit CES class for table (CCS) driven charsets */
extern const struct iconv_ces_desc iconv_ces_table_driven;

/* CES structure - CES instance data */
struct iconv_ces {
	const struct iconv_ces_desc *desc;  /* descriptor/class pointer */
	iconv_ces_close_t *close;	/* instance-specific close function */
	void		  *data;	/* optional extra data */
	void		  *handle;	/* optional handle */
};

/* Basic CES functions and macros */
int iconv_ces_init(struct iconv_ces *ces, const char *name);

#define ICONV_CES_CLOSE(ces)	((ces)->close((ces)))
#define ICONV_CES_RESET(ces)	((ces)->desc->reset((ces)->data))
#define ICONV_CES_CONVERT_FROM_UCS(cesd, in, outbuf, outbytes) \
	    ((cesd)->desc->convert_from_ucs((cesd), (in), (outbuf), (outbytes)))
#define ICONV_CES_CONVERT_TO_UCS(cesd, inbuf, inbytes) \
	    ((cesd)->desc->convert_to_ucs((cesd), (inbuf), (inbytes)))


/* Virtual CES initialisation function type */
typedef int iconv_ces_init_int_t(void **, const void *, size_t);

/* CES subclass macros (for EUC and ISO-2022) */
#define ICONV_CES_DRIVER_DECL(name) \
	iconv_ces_init_int_t iconv_##name##_init; \
	iconv_ces_close_t iconv_##name##_close; \
	iconv_ces_reset_t iconv_##name##_reset; \
	iconv_ces_convert_from_ucs_t iconv_##name##_convert_from_ucs; \
	iconv_ces_convert_to_ucs_t iconv_##name##_convert_to_ucs

/* CES functions and macros for stateless encodings */
iconv_ces_init_t  iconv_ces_init_null;
iconv_ces_close_t iconv_ces_close_null;
iconv_ces_reset_t iconv_ces_reset_null;

#define ICONV_CES_STATELESS_MODULE_DECL(name) \
	const struct iconv_ces_desc iconv_ces_##name = { \
		iconv_ces_init_null, \
		iconv_ces_close_null, \
		iconv_ces_reset_null, \
		convert_from_ucs, \
		convert_to_ucs, \
		NULL \
	}

/* CES functions and macros for stateful (integer state) encodings */
iconv_ces_init_t  iconv_ces_init_state;
iconv_ces_close_t iconv_ces_close_state;
iconv_ces_reset_t iconv_ces_reset_state;

#define ICONV_CES_STATEFUL_MODULE_DECL(name) \
	const struct iconv_ces_desc iconv_ces_##name = { \
		iconv_ces_init_state, \
		iconv_ces_close_state, \
		iconv_ces_reset_state, \
		convert_from_ucs, \
		convert_to_ucs, \
		NULL \
	}

/* CES functions and macros for other encodings */
#define ICONV_CES_MODULE_DECL(type, name) \
	static int \
	module_init(void **data, const char *cs_name, const void *desc_data) \
	{ \
		return iconv_##type##_init(data, desc_data, \
		                           sizeof(ccsattr) / \
		                           sizeof(iconv_ces_##type##_ccs)); \
	} \
	\
	const struct iconv_ces_desc iconv_ces_##name = { \
		module_init, \
		iconv_##type##_close, \
		iconv_##type##_reset, \
		iconv_##type##_convert_from_ucs, \
		iconv_##type##_convert_to_ucs, \
		&ccsattr \
	}


/*
 * EUC character encoding schemes and functions
 */

typedef struct {
	const char	*name;
	const char	*prefix;
	size_t		prefixlen;
} iconv_ces_euc_ccs;

ICONV_CES_DRIVER_DECL(euc);
#define iconv_euc_reset	iconv_ces_reset_null


/*
 * ISO-2022 character encoding schemes and functions
 */

enum { ICONV_SHIFT_SI = 0, ICONV_SHIFT_SO, ICONV_SHIFT_SS2, ICONV_SHIFT_SS3 };

typedef struct {
	const char *	name;
	const char *	designator;
	size_t		designatorlen;
	int		shift;
} iconv_ces_iso2022_ccs;

ICONV_CES_DRIVER_DECL(iso2022);


/*
 * Converter structure and functions
 */

typedef size_t iconv_conv_t(void *, const unsigned char **, size_t *,
                            unsigned char **, size_t *);
typedef int iconv_close_t(void *);

/* Generic converter structure */
typedef struct {
	iconv_conv_t *convert;
	iconv_close_t *close;
} iconv_converter;


/* Converter initialisers */
iconv_converter *iconv_unicode_conv_init(const char *to, const char *from);
iconv_converter *iconv_null_conv_init(const char *to, const char *from);


/*
 * iconv auxiliary functions
 */

int iconv_malloc(size_t size, void **pp);
off_t iconv_filesize(const char *pathlist, const char *filename, char *result);
const void *iconv_mmap(const char *filename, size_t size);
int iconv_munmap(const void *addr, size_t size);
int iconv_get_aliases(char **name1, char **name2);


/*
 * iconv debug functions
 */

#ifdef ICONV_DEBUG
void iconv_debug(const char *file, int line, const char *function,
	const char *format, ...);
#define idebug(format, args...) \
		iconv_debug(__FILE__, __LINE__, __FUNCTION__, format , ## args)
#include <err.h>
#define iconv_warnx(format, args...) \
		warnx(__FUNCTION__ ": " format , ## args)
#else
#define idebug(format, args...)
#define iconv_warnx(format, args...)
#endif

#endif /* ICONV_INTERNAL */

#endif /* _ICONV_H_ */
