symbian-qemu-0.9.1-12/python-2.6.1/Modules/cjkcodecs/_codecs_iso2022.c
changeset 1 2fb8b9db1c86
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/symbian-qemu-0.9.1-12/python-2.6.1/Modules/cjkcodecs/_codecs_iso2022.c	Fri Jul 31 15:01:17 2009 +0100
@@ -0,0 +1,1131 @@
+/*
+ * _codecs_iso2022.c: Codecs collection for ISO-2022 encodings.
+ *
+ * Written by Hye-Shik Chang <perky@FreeBSD.org>
+ */
+
+#define USING_IMPORTED_MAPS
+#define USING_BINARY_PAIR_SEARCH
+#define EXTERN_JISX0213_PAIR
+#define EMULATE_JISX0213_2000_ENCODE_INVALID MAP_UNMAPPABLE
+#define EMULATE_JISX0213_2000_DECODE_INVALID MAP_UNMAPPABLE
+
+#include "cjkcodecs.h"
+#include "alg_jisx0201.h"
+#include "emu_jisx0213_2000.h"
+#include "mappings_jisx0213_pair.h"
+
+/* STATE
+
+   state->c[0-3]
+
+	00000000
+	||^^^^^|
+	|+-----+----  G0-3 Character Set
+	+-----------  Is G0-3 double byte?
+
+   state->c[4]
+
+	00000000
+	      ||
+	      |+----  Locked-Shift?
+	      +-----  ESC Throughout
+*/
+
+#define ESC			0x1B
+#define SO			0x0E
+#define SI			0x0F
+#define LF			0x0A
+
+#define MAX_ESCSEQLEN		16
+
+#define CHARSET_ISO8859_1	'A'
+#define CHARSET_ASCII		'B'
+#define CHARSET_ISO8859_7	'F'
+#define CHARSET_JISX0201_K	'I'
+#define CHARSET_JISX0201_R	'J'
+
+#define CHARSET_GB2312		('A'|CHARSET_DBCS)
+#define CHARSET_JISX0208	('B'|CHARSET_DBCS)
+#define CHARSET_KSX1001		('C'|CHARSET_DBCS)
+#define CHARSET_JISX0212	('D'|CHARSET_DBCS)
+#define CHARSET_GB2312_8565	('E'|CHARSET_DBCS)
+#define CHARSET_CNS11643_1	('G'|CHARSET_DBCS)
+#define CHARSET_CNS11643_2	('H'|CHARSET_DBCS)
+#define CHARSET_JISX0213_2000_1	('O'|CHARSET_DBCS)
+#define CHARSET_JISX0213_2	('P'|CHARSET_DBCS)
+#define CHARSET_JISX0213_2004_1	('Q'|CHARSET_DBCS)
+#define CHARSET_JISX0208_O	('@'|CHARSET_DBCS)
+
+#define CHARSET_DBCS		0x80
+#define ESCMARK(mark)		((mark) & 0x7f)
+
+#define IS_ESCEND(c)	(((c) >= 'A' && (c) <= 'Z') || (c) == '@')
+#define IS_ISO2022ESC(c2) \
+		((c2) == '(' || (c2) == ')' || (c2) == '$' || \
+		 (c2) == '.' || (c2) == '&')
+	/* this is not a complete list of ISO-2022 escape sequence headers.
+	 * but, it's enough to implement CJK instances of iso-2022. */
+
+#define MAP_UNMAPPABLE		0xFFFF
+#define MAP_MULTIPLE_AVAIL	0xFFFE /* for JIS X 0213 */
+
+#define F_SHIFTED		0x01
+#define F_ESCTHROUGHOUT		0x02
+
+#define STATE_SETG(dn, v)	((state)->c[dn]) = (v);
+#define STATE_GETG(dn)		((state)->c[dn])
+
+#define STATE_G0		STATE_GETG(0)
+#define STATE_G1		STATE_GETG(1)
+#define STATE_G2		STATE_GETG(2)
+#define STATE_G3		STATE_GETG(3)
+#define STATE_SETG0(v)		STATE_SETG(0, v)
+#define STATE_SETG1(v)		STATE_SETG(1, v)
+#define STATE_SETG2(v)		STATE_SETG(2, v)
+#define STATE_SETG3(v)		STATE_SETG(3, v)
+
+#define STATE_SETFLAG(f)	((state)->c[4]) |= (f);
+#define STATE_GETFLAG(f)	((state)->c[4] & (f))
+#define STATE_CLEARFLAG(f)	((state)->c[4]) &= ~(f);
+#define STATE_CLEARFLAGS()	((state)->c[4]) = 0;
+
+#define ISO2022_CONFIG		((const struct iso2022_config *)config)
+#define CONFIG_ISSET(flag)	(ISO2022_CONFIG->flags & (flag))
+#define CONFIG_DESIGNATIONS	(ISO2022_CONFIG->designations)
+
+/* iso2022_config.flags */
+#define NO_SHIFT		0x01
+#define USE_G2			0x02
+#define USE_JISX0208_EXT	0x04
+
+/*-*- internal data structures -*-*/
+
+typedef int (*iso2022_init_func)(void);
+typedef ucs4_t (*iso2022_decode_func)(const unsigned char *data);
+typedef DBCHAR (*iso2022_encode_func)(const ucs4_t *data, Py_ssize_t *length);
+
+struct iso2022_designation {
+	unsigned char mark;
+	unsigned char plane;
+	unsigned char width;
+	iso2022_init_func initializer;
+	iso2022_decode_func decoder;
+	iso2022_encode_func encoder;
+};
+
+struct iso2022_config {
+	int flags;
+	const struct iso2022_designation *designations; /* non-ascii desigs */
+};
+
+/*-*- iso-2022 codec implementation -*-*/
+
+CODEC_INIT(iso2022)
+{
+	const struct iso2022_designation *desig = CONFIG_DESIGNATIONS;
+	for (desig = CONFIG_DESIGNATIONS; desig->mark; desig++)
+		if (desig->initializer != NULL && desig->initializer() != 0)
+			return -1;
+	return 0;
+}
+
+ENCODER_INIT(iso2022)
+{
+	STATE_CLEARFLAGS()
+	STATE_SETG0(CHARSET_ASCII)
+	STATE_SETG1(CHARSET_ASCII)
+	return 0;
+}
+
+ENCODER_RESET(iso2022)
+{
+	if (STATE_GETFLAG(F_SHIFTED)) {
+		WRITE1(SI)
+		NEXT_OUT(1)
+		STATE_CLEARFLAG(F_SHIFTED)
+	}
+	if (STATE_G0 != CHARSET_ASCII) {
+		WRITE3(ESC, '(', 'B')
+		NEXT_OUT(3)
+		STATE_SETG0(CHARSET_ASCII)
+	}
+	return 0;
+}
+
+ENCODER(iso2022)
+{
+	while (inleft > 0) {
+		const struct iso2022_designation *dsg;
+		DBCHAR encoded;
+		ucs4_t c = **inbuf;
+		Py_ssize_t insize;
+
+		if (c < 0x80) {
+			if (STATE_G0 != CHARSET_ASCII) {
+				WRITE3(ESC, '(', 'B')
+				STATE_SETG0(CHARSET_ASCII)
+				NEXT_OUT(3)
+			}
+			if (STATE_GETFLAG(F_SHIFTED)) {
+				WRITE1(SI)
+				STATE_CLEARFLAG(F_SHIFTED)
+				NEXT_OUT(1)
+			}
+			WRITE1((unsigned char)c)
+			NEXT(1, 1)
+			continue;
+		}
+
+		DECODE_SURROGATE(c)
+		insize = GET_INSIZE(c);
+
+		encoded = MAP_UNMAPPABLE;
+		for (dsg = CONFIG_DESIGNATIONS; dsg->mark; dsg++) {
+			Py_ssize_t length = 1;
+			encoded = dsg->encoder(&c, &length);
+			if (encoded == MAP_MULTIPLE_AVAIL) {
+				/* this implementation won't work for pair
+				 * of non-bmp characters. */
+				if (inleft < 2) {
+					if (!(flags & MBENC_FLUSH))
+						return MBERR_TOOFEW;
+					length = -1;
+				}
+				else
+					length = 2;
+#if Py_UNICODE_SIZE == 2
+				if (length == 2) {
+					ucs4_t u4in[2];
+					u4in[0] = (ucs4_t)IN1;
+					u4in[1] = (ucs4_t)IN2;
+					encoded = dsg->encoder(u4in, &length);
+				} else
+					encoded = dsg->encoder(&c, &length);
+#else
+				encoded = dsg->encoder(&c, &length);
+#endif
+				if (encoded != MAP_UNMAPPABLE) {
+					insize = length;
+					break;
+				}
+			}
+			else if (encoded != MAP_UNMAPPABLE)
+				break;
+		}
+
+		if (!dsg->mark)
+			return 1;
+		assert(dsg->width == 1 || dsg->width == 2);
+
+		switch (dsg->plane) {
+		case 0: /* G0 */
+			if (STATE_GETFLAG(F_SHIFTED)) {
+				WRITE1(SI)
+				STATE_CLEARFLAG(F_SHIFTED)
+				NEXT_OUT(1)
+			}
+			if (STATE_G0 != dsg->mark) {
+				if (dsg->width == 1) {
+					WRITE3(ESC, '(', ESCMARK(dsg->mark))
+					STATE_SETG0(dsg->mark)
+					NEXT_OUT(3)
+				}
+				else if (dsg->mark == CHARSET_JISX0208) {
+					WRITE3(ESC, '$', ESCMARK(dsg->mark))
+					STATE_SETG0(dsg->mark)
+					NEXT_OUT(3)
+				}
+				else {
+					WRITE4(ESC, '$', '(',
+						ESCMARK(dsg->mark))
+					STATE_SETG0(dsg->mark)
+					NEXT_OUT(4)
+				}
+			}
+			break;
+		case 1: /* G1 */
+			if (STATE_G1 != dsg->mark) {
+				if (dsg->width == 1) {
+					WRITE3(ESC, ')', ESCMARK(dsg->mark))
+					STATE_SETG1(dsg->mark)
+					NEXT_OUT(3)
+				}
+				else {
+					WRITE4(ESC, '$', ')',
+						ESCMARK(dsg->mark))
+					STATE_SETG1(dsg->mark)
+					NEXT_OUT(4)
+				}
+			}
+			if (!STATE_GETFLAG(F_SHIFTED)) {
+				WRITE1(SO)
+				STATE_SETFLAG(F_SHIFTED)
+				NEXT_OUT(1)
+			}
+			break;
+		default: /* G2 and G3 is not supported: no encoding in
+			  * CJKCodecs are using them yet */
+			return MBERR_INTERNAL;
+		}
+
+		if (dsg->width == 1) {
+			WRITE1((unsigned char)encoded)
+			NEXT_OUT(1)
+		}
+		else {
+			WRITE2(encoded >> 8, encoded & 0xff)
+			NEXT_OUT(2)
+		}
+		NEXT_IN(insize)
+	}
+
+	return 0;
+}
+
+DECODER_INIT(iso2022)
+{
+	STATE_CLEARFLAGS()
+	STATE_SETG0(CHARSET_ASCII)
+	STATE_SETG1(CHARSET_ASCII)
+	STATE_SETG2(CHARSET_ASCII)
+	return 0;
+}
+
+DECODER_RESET(iso2022)
+{
+	STATE_SETG0(CHARSET_ASCII)
+	STATE_CLEARFLAG(F_SHIFTED)
+	return 0;
+}
+
+static Py_ssize_t
+iso2022processesc(const void *config, MultibyteCodec_State *state,
+		  const unsigned char **inbuf, Py_ssize_t *inleft)
+{
+	unsigned char charset, designation;
+	Py_ssize_t i, esclen;
+
+	for (i = 1;i < MAX_ESCSEQLEN;i++) {
+		if (i >= *inleft)
+			return MBERR_TOOFEW;
+		if (IS_ESCEND((*inbuf)[i])) {
+			esclen = i + 1;
+			break;
+		}
+		else if (CONFIG_ISSET(USE_JISX0208_EXT) && i+1 < *inleft &&
+			 (*inbuf)[i] == '&' && (*inbuf)[i+1] == '@')
+			i += 2;
+	}
+
+	if (i >= MAX_ESCSEQLEN)
+		return 1; /* unterminated escape sequence */
+
+	switch (esclen) {
+	case 3:
+		if (IN2 == '$') {
+			charset = IN3 | CHARSET_DBCS;
+			designation = 0;
+		}
+		else {
+			charset = IN3;
+			if (IN2 == '(') designation = 0;
+			else if (IN2 == ')') designation = 1;
+			else if (CONFIG_ISSET(USE_G2) && IN2 == '.')
+				designation = 2;
+			else return 3;
+		}
+		break;
+	case 4:
+		if (IN2 != '$')
+			return 4;
+
+		charset = IN4 | CHARSET_DBCS;
+		if (IN3 == '(') designation = 0;
+		else if (IN3 == ')') designation = 1;
+		else return 4;
+		break;
+	case 6: /* designation with prefix */
+		if (CONFIG_ISSET(USE_JISX0208_EXT) &&
+		    (*inbuf)[3] == ESC && (*inbuf)[4] == '$' &&
+		    (*inbuf)[5] == 'B') {
+			charset = 'B' | CHARSET_DBCS;
+			designation = 0;
+		}
+		else
+			return 6;
+		break;
+	default:
+		return esclen;
+	}
+
+	/* raise error when the charset is not designated for this encoding */
+	if (charset != CHARSET_ASCII) {
+		const struct iso2022_designation *dsg;
+
+		for (dsg = CONFIG_DESIGNATIONS; dsg->mark; dsg++)
+			if (dsg->mark == charset)
+				break;
+		if (!dsg->mark)
+			return esclen;
+	}
+
+	STATE_SETG(designation, charset)
+	*inleft -= esclen;
+	(*inbuf) += esclen;
+	return 0;
+}
+
+#define ISO8859_7_DECODE(c, assi)					\
+	if ((c) < 0xa0) (assi) = (c);					\
+	else if ((c) < 0xc0 && (0x288f3bc9L & (1L << ((c)-0xa0))))	\
+		(assi) = (c);						\
+	else if ((c) >= 0xb4 && (c) <= 0xfe && ((c) >= 0xd4 ||		\
+		 (0xbffffd77L & (1L << ((c)-0xb4)))))			\
+		(assi) = 0x02d0 + (c);					\
+	else if ((c) == 0xa1) (assi) = 0x2018;				\
+	else if ((c) == 0xa2) (assi) = 0x2019;				\
+	else if ((c) == 0xaf) (assi) = 0x2015;
+
+static Py_ssize_t
+iso2022processg2(const void *config, MultibyteCodec_State *state,
+		 const unsigned char **inbuf, Py_ssize_t *inleft,
+		 Py_UNICODE **outbuf, Py_ssize_t *outleft)
+{
+	/* not written to use encoder, decoder functions because only few
+	 * encodings use G2 designations in CJKCodecs */
+	if (STATE_G2 == CHARSET_ISO8859_1) {
+		if (IN3 < 0x80)
+			OUT1(IN3 + 0x80)
+		else
+			return 3;
+	}
+	else if (STATE_G2 == CHARSET_ISO8859_7) {
+		ISO8859_7_DECODE(IN3 ^ 0x80, **outbuf)
+		else return 3;
+	}
+	else if (STATE_G2 == CHARSET_ASCII) {
+		if (IN3 & 0x80) return 3;
+		else **outbuf = IN3;
+	}
+	else
+		return MBERR_INTERNAL;
+
+	(*inbuf) += 3;
+	*inleft -= 3;
+	(*outbuf) += 1;
+	*outleft -= 1;
+	return 0;
+}
+
+DECODER(iso2022)
+{
+	const struct iso2022_designation *dsgcache = NULL;
+
+	while (inleft > 0) {
+		unsigned char c = IN1;
+		Py_ssize_t err;
+
+		if (STATE_GETFLAG(F_ESCTHROUGHOUT)) {
+			/* ESC throughout mode:
+			 * for non-iso2022 escape sequences */
+			WRITE1(c) /* assume as ISO-8859-1 */
+			NEXT(1, 1)
+			if (IS_ESCEND(c)) {
+				STATE_CLEARFLAG(F_ESCTHROUGHOUT)
+			}
+			continue;
+		}
+
+		switch (c) {
+		case ESC:
+			REQUIRE_INBUF(2)
+			if (IS_ISO2022ESC(IN2)) {
+				err = iso2022processesc(config, state,
+							inbuf, &inleft);
+				if (err != 0)
+					return err;
+			}
+			else if (CONFIG_ISSET(USE_G2) && IN2 == 'N') {/* SS2 */
+				REQUIRE_INBUF(3)
+				err = iso2022processg2(config, state,
+					inbuf, &inleft, outbuf, &outleft);
+				if (err != 0)
+					return err;
+			}
+			else {
+				WRITE1(ESC)
+				STATE_SETFLAG(F_ESCTHROUGHOUT)
+				NEXT(1, 1)
+			}
+			break;
+		case SI:
+			if (CONFIG_ISSET(NO_SHIFT))
+				goto bypass;
+			STATE_CLEARFLAG(F_SHIFTED)
+			NEXT_IN(1)
+			break;
+		case SO:
+			if (CONFIG_ISSET(NO_SHIFT))
+				goto bypass;
+			STATE_SETFLAG(F_SHIFTED)
+			NEXT_IN(1)
+			break;
+		case LF:
+			STATE_CLEARFLAG(F_SHIFTED)
+			WRITE1(LF)
+			NEXT(1, 1)
+			break;
+		default:
+			if (c < 0x20) /* C0 */
+				goto bypass;
+			else if (c >= 0x80)
+				return 1;
+			else {
+				const struct iso2022_designation *dsg;
+				unsigned char charset;
+				ucs4_t decoded;
+
+				if (STATE_GETFLAG(F_SHIFTED))
+					charset = STATE_G1;
+				else
+					charset = STATE_G0;
+
+				if (charset == CHARSET_ASCII) {
+bypass:					WRITE1(c)
+					NEXT(1, 1)
+					break;
+				}
+
+				if (dsgcache != NULL &&
+				    dsgcache->mark == charset)
+					dsg = dsgcache;
+				else {
+					for (dsg = CONFIG_DESIGNATIONS;
+					     dsg->mark != charset
+#ifdef Py_DEBUG
+						&& dsg->mark != '\0'
+#endif
+					     ;dsg++)
+						/* noop */;
+					assert(dsg->mark != '\0');
+					dsgcache = dsg;
+				}
+
+				REQUIRE_INBUF(dsg->width)
+				decoded = dsg->decoder(*inbuf);
+				if (decoded == MAP_UNMAPPABLE)
+					return dsg->width;
+
+				if (decoded < 0x10000) {
+					WRITE1(decoded)
+					NEXT_OUT(1)
+				}
+				else if (decoded < 0x30000) {
+					WRITEUCS4(decoded)
+				}
+				else { /* JIS X 0213 pairs */
+					WRITE2(decoded >> 16, decoded & 0xffff)
+					NEXT_OUT(2)
+				}
+				NEXT_IN(dsg->width)
+			}
+			break;
+		}
+	}
+	return 0;
+}
+
+/*-*- mapping table holders -*-*/
+
+#define ENCMAP(enc) static const encode_map *enc##_encmap = NULL;
+#define DECMAP(enc) static const decode_map *enc##_decmap = NULL;
+
+/* kr */
+ENCMAP(cp949)
+DECMAP(ksx1001)
+
+/* jp */
+ENCMAP(jisxcommon)
+DECMAP(jisx0208)
+DECMAP(jisx0212)
+ENCMAP(jisx0213_bmp)
+DECMAP(jisx0213_1_bmp)
+DECMAP(jisx0213_2_bmp)
+ENCMAP(jisx0213_emp)
+DECMAP(jisx0213_1_emp)
+DECMAP(jisx0213_2_emp)
+
+/* cn */
+ENCMAP(gbcommon)
+DECMAP(gb2312)
+
+/* tw */
+
+/*-*- mapping access functions -*-*/
+
+static int
+ksx1001_init(void)
+{
+	static int initialized = 0;
+
+	if (!initialized && (
+			IMPORT_MAP(kr, cp949, &cp949_encmap, NULL) ||
+			IMPORT_MAP(kr, ksx1001, NULL, &ksx1001_decmap)))
+		return -1;
+	initialized = 1;
+	return 0;
+}
+
+static ucs4_t
+ksx1001_decoder(const unsigned char *data)
+{
+	ucs4_t u;
+	TRYMAP_DEC(ksx1001, u, data[0], data[1])
+		return u;
+	else
+		return MAP_UNMAPPABLE;
+}
+
+static DBCHAR
+ksx1001_encoder(const ucs4_t *data, Py_ssize_t *length)
+{
+	DBCHAR coded;
+	assert(*length == 1);
+	if (*data < 0x10000) {
+		TRYMAP_ENC(cp949, coded, *data)
+			if (!(coded & 0x8000))
+				return coded;
+	}
+	return MAP_UNMAPPABLE;
+}
+
+static int
+jisx0208_init(void)
+{
+	static int initialized = 0;
+
+	if (!initialized && (
+			IMPORT_MAP(jp, jisxcommon, &jisxcommon_encmap, NULL) ||
+			IMPORT_MAP(jp, jisx0208, NULL, &jisx0208_decmap)))
+		return -1;
+	initialized = 1;
+	return 0;
+}
+
+static ucs4_t
+jisx0208_decoder(const unsigned char *data)
+{
+	ucs4_t u;
+	if (data[0] == 0x21 && data[1] == 0x40) /* F/W REVERSE SOLIDUS */
+		return 0xff3c;
+	else TRYMAP_DEC(jisx0208, u, data[0], data[1])
+		return u;
+	else
+		return MAP_UNMAPPABLE;
+}
+
+static DBCHAR
+jisx0208_encoder(const ucs4_t *data, Py_ssize_t *length)
+{
+	DBCHAR coded;
+	assert(*length == 1);
+	if (*data < 0x10000) {
+		if (*data == 0xff3c) /* F/W REVERSE SOLIDUS */
+			return 0x2140;
+		else TRYMAP_ENC(jisxcommon, coded, *data) {
+			if (!(coded & 0x8000))
+				return coded;
+		}
+	}
+	return MAP_UNMAPPABLE;
+}
+
+static int
+jisx0212_init(void)
+{
+	static int initialized = 0;
+
+	if (!initialized && (
+			IMPORT_MAP(jp, jisxcommon, &jisxcommon_encmap, NULL) ||
+			IMPORT_MAP(jp, jisx0212, NULL, &jisx0212_decmap)))
+		return -1;
+	initialized = 1;
+	return 0;
+}
+
+static ucs4_t
+jisx0212_decoder(const unsigned char *data)
+{
+	ucs4_t u;
+	TRYMAP_DEC(jisx0212, u, data[0], data[1])
+		return u;
+	else
+		return MAP_UNMAPPABLE;
+}
+
+static DBCHAR
+jisx0212_encoder(const ucs4_t *data, Py_ssize_t *length)
+{
+	DBCHAR coded;
+	assert(*length == 1);
+	if (*data < 0x10000) {
+		TRYMAP_ENC(jisxcommon, coded, *data) {
+			if (coded & 0x8000)
+				return coded & 0x7fff;
+		}
+	}
+	return MAP_UNMAPPABLE;
+}
+
+static int
+jisx0213_init(void)
+{
+	static int initialized = 0;
+
+	if (!initialized && (
+			jisx0208_init() ||
+			IMPORT_MAP(jp, jisx0213_bmp,
+				   &jisx0213_bmp_encmap, NULL) ||
+			IMPORT_MAP(jp, jisx0213_1_bmp,
+				   NULL, &jisx0213_1_bmp_decmap) ||
+			IMPORT_MAP(jp, jisx0213_2_bmp,
+				   NULL, &jisx0213_2_bmp_decmap) ||
+			IMPORT_MAP(jp, jisx0213_emp,
+				   &jisx0213_emp_encmap, NULL) ||
+			IMPORT_MAP(jp, jisx0213_1_emp,
+				   NULL, &jisx0213_1_emp_decmap) ||
+			IMPORT_MAP(jp, jisx0213_2_emp,
+				   NULL, &jisx0213_2_emp_decmap) ||
+			IMPORT_MAP(jp, jisx0213_pair, &jisx0213_pair_encmap,
+				   &jisx0213_pair_decmap)))
+		return -1;
+	initialized = 1;
+	return 0;
+}
+
+#define config ((void *)2000)
+static ucs4_t
+jisx0213_2000_1_decoder(const unsigned char *data)
+{
+	ucs4_t u;
+	EMULATE_JISX0213_2000_DECODE_PLANE1(u, data[0], data[1])
+	else if (data[0] == 0x21 && data[1] == 0x40) /* F/W REVERSE SOLIDUS */
+		return 0xff3c;
+	else TRYMAP_DEC(jisx0208, u, data[0], data[1]);
+	else TRYMAP_DEC(jisx0213_1_bmp, u, data[0], data[1]);
+	else TRYMAP_DEC(jisx0213_1_emp, u, data[0], data[1])
+		u |= 0x20000;
+	else TRYMAP_DEC(jisx0213_pair, u, data[0], data[1]);
+	else
+		return MAP_UNMAPPABLE;
+	return u;
+}
+
+static ucs4_t
+jisx0213_2000_2_decoder(const unsigned char *data)
+{
+	ucs4_t u;
+	EMULATE_JISX0213_2000_DECODE_PLANE2(u, data[0], data[1])
+	TRYMAP_DEC(jisx0213_2_bmp, u, data[0], data[1]);
+	else TRYMAP_DEC(jisx0213_2_emp, u, data[0], data[1])
+		u |= 0x20000;
+	else
+		return MAP_UNMAPPABLE;
+	return u;
+}
+#undef config
+
+static ucs4_t
+jisx0213_2004_1_decoder(const unsigned char *data)
+{
+	ucs4_t u;
+	if (data[0] == 0x21 && data[1] == 0x40) /* F/W REVERSE SOLIDUS */
+		return 0xff3c;
+	else TRYMAP_DEC(jisx0208, u, data[0], data[1]);
+	else TRYMAP_DEC(jisx0213_1_bmp, u, data[0], data[1]);
+	else TRYMAP_DEC(jisx0213_1_emp, u, data[0], data[1])
+		u |= 0x20000;
+	else TRYMAP_DEC(jisx0213_pair, u, data[0], data[1]);
+	else
+		return MAP_UNMAPPABLE;
+	return u;
+}
+
+static ucs4_t
+jisx0213_2004_2_decoder(const unsigned char *data)
+{
+	ucs4_t u;
+	TRYMAP_DEC(jisx0213_2_bmp, u, data[0], data[1]);
+	else TRYMAP_DEC(jisx0213_2_emp, u, data[0], data[1])
+		u |= 0x20000;
+	else
+		return MAP_UNMAPPABLE;
+	return u;
+}
+
+static DBCHAR
+jisx0213_encoder(const ucs4_t *data, Py_ssize_t *length, void *config)
+{
+	DBCHAR coded;
+
+	switch (*length) {
+	case 1: /* first character */
+		if (*data >= 0x10000) {
+			if ((*data) >> 16 == 0x20000 >> 16) {
+				EMULATE_JISX0213_2000_ENCODE_EMP(coded, *data)
+				else TRYMAP_ENC(jisx0213_emp, coded,
+						(*data) & 0xffff)
+					return coded;
+			}
+			return MAP_UNMAPPABLE;
+		}
+
+		EMULATE_JISX0213_2000_ENCODE_BMP(coded, *data)
+		else TRYMAP_ENC(jisx0213_bmp, coded, *data) {
+			if (coded == MULTIC)
+				return MAP_MULTIPLE_AVAIL;
+		}
+		else TRYMAP_ENC(jisxcommon, coded, *data) {
+			if (coded & 0x8000)
+				return MAP_UNMAPPABLE;
+		}
+		else
+			return MAP_UNMAPPABLE;
+		return coded;
+	case 2: /* second character of unicode pair */
+		coded = find_pairencmap((ucs2_t)data[0], (ucs2_t)data[1],
+				jisx0213_pair_encmap, JISX0213_ENCPAIRS);
+		if (coded == DBCINV) {
+			*length = 1;
+			coded = find_pairencmap((ucs2_t)data[0], 0,
+				  jisx0213_pair_encmap, JISX0213_ENCPAIRS);
+			if (coded == DBCINV)
+				return MAP_UNMAPPABLE;
+		}
+		else
+			return coded;
+	case -1: /* flush unterminated */
+		*length = 1;
+		coded = find_pairencmap((ucs2_t)data[0], 0,
+				jisx0213_pair_encmap, JISX0213_ENCPAIRS);
+		if (coded == DBCINV)
+			return MAP_UNMAPPABLE;
+		else
+			return coded;
+	default:
+		return MAP_UNMAPPABLE;
+	}
+}
+
+static DBCHAR
+jisx0213_2000_1_encoder(const ucs4_t *data, Py_ssize_t *length)
+{
+	DBCHAR coded = jisx0213_encoder(data, length, (void *)2000);
+	if (coded == MAP_UNMAPPABLE || coded == MAP_MULTIPLE_AVAIL)
+		return coded;
+	else if (coded & 0x8000)
+		return MAP_UNMAPPABLE;
+	else
+		return coded;
+}
+
+static DBCHAR
+jisx0213_2000_1_encoder_paironly(const ucs4_t *data, Py_ssize_t *length)
+{
+	DBCHAR coded;
+	Py_ssize_t ilength = *length;
+
+	coded = jisx0213_encoder(data, length, (void *)2000);
+	switch (ilength) {
+	case 1:
+		if (coded == MAP_MULTIPLE_AVAIL)
+			return MAP_MULTIPLE_AVAIL;
+		else
+			return MAP_UNMAPPABLE;
+	case 2:
+		if (*length != 2)
+			return MAP_UNMAPPABLE;
+		else
+			return coded;
+	default:
+		return MAP_UNMAPPABLE;
+	}
+}
+
+static DBCHAR
+jisx0213_2000_2_encoder(const ucs4_t *data, Py_ssize_t *length)
+{
+	DBCHAR coded = jisx0213_encoder(data, length, (void *)2000);
+	if (coded == MAP_UNMAPPABLE || coded == MAP_MULTIPLE_AVAIL)
+		return coded;
+	else if (coded & 0x8000)
+		return coded & 0x7fff;
+	else
+		return MAP_UNMAPPABLE;
+}
+
+static DBCHAR
+jisx0213_2004_1_encoder(const ucs4_t *data, Py_ssize_t *length)
+{
+	DBCHAR coded = jisx0213_encoder(data, length, NULL);
+	if (coded == MAP_UNMAPPABLE || coded == MAP_MULTIPLE_AVAIL)
+		return coded;
+	else if (coded & 0x8000)
+		return MAP_UNMAPPABLE;
+	else
+		return coded;
+}
+
+static DBCHAR
+jisx0213_2004_1_encoder_paironly(const ucs4_t *data, Py_ssize_t *length)
+{
+	DBCHAR coded;
+	Py_ssize_t ilength = *length;
+
+	coded = jisx0213_encoder(data, length, NULL);
+	switch (ilength) {
+	case 1:
+		if (coded == MAP_MULTIPLE_AVAIL)
+			return MAP_MULTIPLE_AVAIL;
+		else
+			return MAP_UNMAPPABLE;
+	case 2:
+		if (*length != 2)
+			return MAP_UNMAPPABLE;
+		else
+			return coded;
+	default:
+		return MAP_UNMAPPABLE;
+	}
+}
+
+static DBCHAR
+jisx0213_2004_2_encoder(const ucs4_t *data, Py_ssize_t *length)
+{
+	DBCHAR coded = jisx0213_encoder(data, length, NULL);
+	if (coded == MAP_UNMAPPABLE || coded == MAP_MULTIPLE_AVAIL)
+		return coded;
+	else if (coded & 0x8000)
+		return coded & 0x7fff;
+	else
+		return MAP_UNMAPPABLE;
+}
+
+static ucs4_t
+jisx0201_r_decoder(const unsigned char *data)
+{
+	ucs4_t u;
+	JISX0201_R_DECODE(*data, u)
+	else return MAP_UNMAPPABLE;
+	return u;
+}
+
+static DBCHAR
+jisx0201_r_encoder(const ucs4_t *data, Py_ssize_t *length)
+{
+	DBCHAR coded;
+	JISX0201_R_ENCODE(*data, coded)
+	else return MAP_UNMAPPABLE;
+	return coded;
+}
+
+static ucs4_t
+jisx0201_k_decoder(const unsigned char *data)
+{
+	ucs4_t u;
+	JISX0201_K_DECODE(*data ^ 0x80, u)
+	else return MAP_UNMAPPABLE;
+	return u;
+}
+
+static DBCHAR
+jisx0201_k_encoder(const ucs4_t *data, Py_ssize_t *length)
+{
+	DBCHAR coded;
+	JISX0201_K_ENCODE(*data, coded)
+	else return MAP_UNMAPPABLE;
+	return coded - 0x80;
+}
+
+static int
+gb2312_init(void)
+{
+	static int initialized = 0;
+
+	if (!initialized && (
+			IMPORT_MAP(cn, gbcommon, &gbcommon_encmap, NULL) ||
+			IMPORT_MAP(cn, gb2312, NULL, &gb2312_decmap)))
+		return -1;
+	initialized = 1;
+	return 0;
+}
+
+static ucs4_t
+gb2312_decoder(const unsigned char *data)
+{
+	ucs4_t u;
+	TRYMAP_DEC(gb2312, u, data[0], data[1])
+		return u;
+	else
+		return MAP_UNMAPPABLE;
+}
+
+static DBCHAR
+gb2312_encoder(const ucs4_t *data, Py_ssize_t *length)
+{
+	DBCHAR coded;
+	assert(*length == 1);
+	if (*data < 0x10000) {
+		TRYMAP_ENC(gbcommon, coded, *data) {
+			if (!(coded & 0x8000))
+				return coded;
+		}
+	}
+	return MAP_UNMAPPABLE;
+}
+
+
+static ucs4_t
+dummy_decoder(const unsigned char *data)
+{
+	return MAP_UNMAPPABLE;
+}
+
+static DBCHAR
+dummy_encoder(const ucs4_t *data, Py_ssize_t *length)
+{
+	return MAP_UNMAPPABLE;
+}
+
+/*-*- registry tables -*-*/
+
+#define REGISTRY_KSX1001_G0	{ CHARSET_KSX1001, 0, 2,		\
+				  ksx1001_init,				\
+				  ksx1001_decoder, ksx1001_encoder }
+#define REGISTRY_KSX1001_G1	{ CHARSET_KSX1001, 1, 2,		\
+				  ksx1001_init,				\
+				  ksx1001_decoder, ksx1001_encoder }
+#define REGISTRY_JISX0201_R	{ CHARSET_JISX0201_R, 0, 1,		\
+				  NULL,					\
+				  jisx0201_r_decoder, jisx0201_r_encoder }
+#define REGISTRY_JISX0201_K	{ CHARSET_JISX0201_K, 0, 1,		\
+				  NULL,					\
+				  jisx0201_k_decoder, jisx0201_k_encoder }
+#define REGISTRY_JISX0208	{ CHARSET_JISX0208, 0, 2,		\
+				  jisx0208_init,			\
+				  jisx0208_decoder, jisx0208_encoder }
+#define REGISTRY_JISX0208_O	{ CHARSET_JISX0208_O, 0, 2,		\
+				  jisx0208_init,			\
+				  jisx0208_decoder, jisx0208_encoder }
+#define REGISTRY_JISX0212	{ CHARSET_JISX0212, 0, 2,		\
+				  jisx0212_init,			\
+				  jisx0212_decoder, jisx0212_encoder }
+#define REGISTRY_JISX0213_2000_1 { CHARSET_JISX0213_2000_1, 0, 2,	\
+				  jisx0213_init,			\
+				  jisx0213_2000_1_decoder,		\
+				  jisx0213_2000_1_encoder }
+#define REGISTRY_JISX0213_2000_1_PAIRONLY { CHARSET_JISX0213_2000_1, 0, 2, \
+				  jisx0213_init,			\
+				  jisx0213_2000_1_decoder,		\
+				  jisx0213_2000_1_encoder_paironly }
+#define REGISTRY_JISX0213_2000_2 { CHARSET_JISX0213_2, 0, 2,		\
+				  jisx0213_init,			\
+				  jisx0213_2000_2_decoder,		\
+				  jisx0213_2000_2_encoder }
+#define REGISTRY_JISX0213_2004_1 { CHARSET_JISX0213_2004_1, 0, 2,	\
+				  jisx0213_init,			\
+				  jisx0213_2004_1_decoder,		\
+				  jisx0213_2004_1_encoder }
+#define REGISTRY_JISX0213_2004_1_PAIRONLY { CHARSET_JISX0213_2004_1, 0, 2, \
+				  jisx0213_init,			\
+				  jisx0213_2004_1_decoder,		\
+				  jisx0213_2004_1_encoder_paironly }
+#define REGISTRY_JISX0213_2004_2 { CHARSET_JISX0213_2, 0, 2,		\
+				  jisx0213_init,			\
+				  jisx0213_2004_2_decoder,		\
+				  jisx0213_2004_2_encoder }
+#define REGISTRY_GB2312		{ CHARSET_GB2312, 0, 2,			\
+				  gb2312_init,				\
+				  gb2312_decoder, gb2312_encoder }
+#define REGISTRY_CNS11643_1	{ CHARSET_CNS11643_1, 1, 2,		\
+				  cns11643_init,			\
+				  cns11643_1_decoder, cns11643_1_encoder }
+#define REGISTRY_CNS11643_2	{ CHARSET_CNS11643_2, 2, 2,		\
+				  cns11643_init,			\
+				  cns11643_2_decoder, cns11643_2_encoder }
+#define REGISTRY_ISO8859_1	{ CHARSET_ISO8859_1, 2, 1,		\
+				  NULL, dummy_decoder, dummy_encoder }
+#define REGISTRY_ISO8859_7	{ CHARSET_ISO8859_7, 2, 1,		\
+				  NULL, dummy_decoder, dummy_encoder }
+#define REGISTRY_SENTINEL	{ 0, }
+#define CONFIGDEF(var, attrs)						\
+	static const struct iso2022_config iso2022_##var##_config = {	\
+		attrs, iso2022_##var##_designations			\
+	};
+
+static const struct iso2022_designation iso2022_kr_designations[] = {
+	REGISTRY_KSX1001_G1, REGISTRY_SENTINEL
+};
+CONFIGDEF(kr, 0)
+
+static const struct iso2022_designation iso2022_jp_designations[] = {
+	REGISTRY_JISX0208, REGISTRY_JISX0201_R, REGISTRY_JISX0208_O,
+	REGISTRY_SENTINEL
+};
+CONFIGDEF(jp, NO_SHIFT | USE_JISX0208_EXT)
+
+static const struct iso2022_designation iso2022_jp_1_designations[] = {
+	REGISTRY_JISX0208, REGISTRY_JISX0212, REGISTRY_JISX0201_R,
+	REGISTRY_JISX0208_O, REGISTRY_SENTINEL
+};
+CONFIGDEF(jp_1, NO_SHIFT | USE_JISX0208_EXT)
+
+static const struct iso2022_designation iso2022_jp_2_designations[] = {
+	REGISTRY_JISX0208, REGISTRY_JISX0212, REGISTRY_KSX1001_G0,
+	REGISTRY_GB2312, REGISTRY_JISX0201_R, REGISTRY_JISX0208_O,
+	REGISTRY_ISO8859_1, REGISTRY_ISO8859_7, REGISTRY_SENTINEL
+};
+CONFIGDEF(jp_2, NO_SHIFT | USE_G2 | USE_JISX0208_EXT)
+
+static const struct iso2022_designation iso2022_jp_2004_designations[] = {
+	REGISTRY_JISX0213_2004_1_PAIRONLY, REGISTRY_JISX0208,
+	REGISTRY_JISX0213_2004_1, REGISTRY_JISX0213_2004_2, REGISTRY_SENTINEL
+};
+CONFIGDEF(jp_2004, NO_SHIFT | USE_JISX0208_EXT)
+
+static const struct iso2022_designation iso2022_jp_3_designations[] = {
+	REGISTRY_JISX0213_2000_1_PAIRONLY, REGISTRY_JISX0208,
+	REGISTRY_JISX0213_2000_1, REGISTRY_JISX0213_2000_2, REGISTRY_SENTINEL
+};
+CONFIGDEF(jp_3, NO_SHIFT | USE_JISX0208_EXT)
+
+static const struct iso2022_designation iso2022_jp_ext_designations[] = {
+	REGISTRY_JISX0208, REGISTRY_JISX0212, REGISTRY_JISX0201_R,
+	REGISTRY_JISX0201_K, REGISTRY_JISX0208_O, REGISTRY_SENTINEL
+};
+CONFIGDEF(jp_ext, NO_SHIFT | USE_JISX0208_EXT)
+
+
+BEGIN_MAPPINGS_LIST
+  /* no mapping table here */
+END_MAPPINGS_LIST
+
+#define ISO2022_CODEC(variation) {		\
+	"iso2022_" #variation,			\
+	&iso2022_##variation##_config,		\
+	iso2022_codec_init,			\
+	_STATEFUL_METHODS(iso2022)		\
+},
+
+BEGIN_CODECS_LIST
+  ISO2022_CODEC(kr)
+  ISO2022_CODEC(jp)
+  ISO2022_CODEC(jp_1)
+  ISO2022_CODEC(jp_2)
+  ISO2022_CODEC(jp_2004)
+  ISO2022_CODEC(jp_3)
+  ISO2022_CODEC(jp_ext)
+END_CODECS_LIST
+
+I_AM_A_MODULE_FOR(iso2022)