summaryrefslogtreecommitdiff
path: root/src/locale
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2017-11-10 15:06:42 -0500
committerRich Felker <dalias@aerifal.cx>2017-11-10 15:06:42 -0500
commit5b546faa67544af395d6407553762b37e9711157 (patch)
tree2dea3ba8d23b5cc6c088a364945985f7b046fa75 /src/locale
parent0df5b39a1e9c8aaf480e3f8667d7967e08bbef2b (diff)
downloadmusl-5b546faa67544af395d6407553762b37e9711157.tar.gz
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.
Diffstat (limited to 'src/locale')
-rw-r--r--src/locale/iconv.c25
-rw-r--r--src/locale/iconv_close.c2
2 files changed, 24 insertions, 3 deletions
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 <iconv.h>
+#include <stdlib.h>
int iconv_close(iconv_t cd)
{
+ if (!((size_t)cd & 1)) free((void *)cd);
return 0;
}