From 5b546faa67544af395d6407553762b37e9711157 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Fri, 10 Nov 2017 15:06:42 -0500 Subject: add iconv framework for decoding stateful encodings assuming pointers obtained from malloc have some nonzero alignment, repurpose the low bit of iconv_t as an indicator that the descriptor is a stateless value representing the source and destination character encodings. --- src/locale/iconv.c | 25 ++++++++++++++++++++++--- src/locale/iconv_close.c | 2 ++ 2 files changed, 24 insertions(+), 3 deletions(-) (limited to 'src/locale') diff --git a/src/locale/iconv.c b/src/locale/iconv.c index fd51b73e..0696b555 100644 --- a/src/locale/iconv.c +++ b/src/locale/iconv.c @@ -100,9 +100,14 @@ static size_t find_charmap(const void *name) return -1; } +struct stateful_cd { + iconv_t base_cd; + unsigned state; +}; + static iconv_t combine_to_from(size_t t, size_t f) { - return (void *)(f<<16 | t); + return (void *)(f<<16 | t<<1 | 1); } static size_t extract_from(iconv_t cd) @@ -112,7 +117,7 @@ static size_t extract_from(iconv_t cd) static size_t extract_to(iconv_t cd) { - return (size_t)cd & 0xffff; + return (size_t)cd >> 1 & 0x7fff; } iconv_t iconv_open(const char *to, const char *from) @@ -125,8 +130,17 @@ iconv_t iconv_open(const char *to, const char *from) errno = EINVAL; return (iconv_t)-1; } + iconv_t cd = combine_to_from(t, f); - return combine_to_from(t, f); + if (0) { + struct stateful_cd *scd = malloc(sizeof *scd); + if (!scd) return (iconv_t)-1; + scd->base_cd = cd; + scd->state = 0; + cd = (iconv_t)scd; + } + + return cd; } static unsigned get_16(const unsigned char *s, int e) @@ -172,6 +186,11 @@ static unsigned legacy_map(const unsigned char *map, unsigned c) size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restrict out, size_t *restrict outb) { size_t x=0; + struct stateful_cd *scd=0; + if (!((size_t)cd & 1)) { + scd = (void *)cd; + cd = scd->base_cd; + } unsigned to = extract_to(cd); unsigned from = extract_from(cd); const unsigned char *map = charmaps+from+1; diff --git a/src/locale/iconv_close.c b/src/locale/iconv_close.c index fac681cc..28b29565 100644 --- a/src/locale/iconv_close.c +++ b/src/locale/iconv_close.c @@ -1,6 +1,8 @@ #include +#include int iconv_close(iconv_t cd) { + if (!((size_t)cd & 1)) free((void *)cd); return 0; } -- cgit v1.2.1