about summary refs log tree commit diff
path: root/src/locale/iconv.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/locale/iconv.c')
-rw-r--r--src/locale/iconv.c27
1 files changed, 16 insertions, 11 deletions
diff --git a/src/locale/iconv.c b/src/locale/iconv.c
index 2107b055..01f17521 100644
--- a/src/locale/iconv.c
+++ b/src/locale/iconv.c
@@ -27,8 +27,10 @@
 
 /* Definitions of charmaps. Each charmap consists of:
  * 1. Empty-string-terminated list of null-terminated aliases.
- * 2. Special type code or number of elided entries.
- * 3. Character table (size determined by field 2). */
+ * 2. Special type code or number of elided quads of entries.
+ * 3. Character table (size determined by field 2), consisting
+ *    of 5 bytes for every 4 characters, interpreted as 10-bit
+ *    indices into the legacy_chars table. */
 
 static const unsigned char charmaps[] =
 "utf8\0char\0\0\310"
@@ -51,6 +53,9 @@ static const unsigned char charmaps[] =
 #include "codepages.h"
 ;
 
+/* Table of characters that appear in legacy 8-bit codepages,
+ * limited to 1024 slots (10 bit indices). The first 256 entries
+ * are elided since those characters are obviously all included. */
 static const unsigned short legacy_chars[] = {
 #include "legacychars.h"
 };
@@ -96,7 +101,7 @@ static size_t find_charmap(const void *name)
 		s += strlen((void *)s)+1;
 		if (!*s) {
 			if (s[1] > 0200) s+=2;
-			else s+=2+(128U-s[1])/4*5;
+			else s+=2+(64U-s[1])*5;
 		}
 	}
 	return -1;
@@ -181,10 +186,10 @@ static void put_32(unsigned char *s, unsigned c, int e)
 
 static unsigned legacy_map(const unsigned char *map, unsigned c)
 {
-	unsigned x = c - 128 - map[-1];
-	x = legacy_chars[ map[x*5/4]>>2*x%8 |
-		map[x*5/4+1]<<8-2*x%8 & 1023 ];
-	return x ? x : c;
+	if (c < 4*map[-1]) return c;
+	unsigned x = c - 4*map[-1];
+	x = map[x*5/4]>>2*x%8 | map[x*5/4+1]<<8-2*x%8 & 1023;
+	return x < 256 ? x : legacy_chars[x-256];
 }
 
 size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restrict out, size_t *restrict outb)
@@ -449,9 +454,9 @@ size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restri
 			if (!c) goto ilseq;
 			break;
 		default:
-			if (c < 128+type) break;
+			if (!c) break;
 			c = legacy_map(map, c);
-			if (c==1) goto ilseq;
+			if (!c) goto ilseq;
 		}
 
 		switch (totype) {
@@ -475,14 +480,14 @@ size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restri
 			if (c > 0x7f) subst: x++, c='*';
 		default:
 			if (*outb < 1) goto toobig;
-			if (c < 128+totype || (c<256 && c==legacy_map(tomap, c))) {
+			if (c<256 && c==legacy_map(tomap, c)) {
 			revout:
 				*(*out)++ = c;
 				*outb -= 1;
 				break;
 			}
 			d = c;
-			for (c=128+totype; c<256; c++) {
+			for (c=4*totype; c<256; c++) {
 				if (d == legacy_map(tomap, c)) {
 					goto revout;
 				}