module dinc.mime.iconv; typedef void* iconv_t; /// allocate a converter between charsets fromcode and tocode extern (C) iconv_t iconv_open (char *tocode, char *fromcode); /// convert inbuf to outbuf and set inbytesleft to unused input and /// outbuf to unused output and return number of non-reversable /// conversions or -1 on error. extern (C) size_t iconv (iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft); /// close converter extern (C) int iconv_close (iconv_t cd); import std.string; import std.stream; class Iconv { iconv_t cv; char[] fcode; char[] tcode; this(char[] toCode, char[] fromCode) { fcode = std.string.tolower(fromCode); tcode = std.string.tolower(toCode); cv = iconv_open (std.string.toStringz( toCode), std.string.toStringz(fromCode)); if (cv == cast(iconv_t)-1) { throw new Exception("Unknown charset"); } } void convStream(InputStream ifh, OutputStream ofh) { char[] l; //std.stdio.writefln("CONV STREAM:"); while (!ifh.eof()) { l = ifh.readLine(); //std.stdio.writefln("CONV<<: %s", l); l = conv(l); //std.stdio.writefln("CONV>>: %s", l); ofh.writeString(l); ofh.writeString("\n"); } } char[] conv(char[] inbuf) { if (!inbuf.length) { return ""; } return conv_iconv(inbuf); } char[] conv_iconv(char[] inbuf) { size_t in_len = inbuf.length; size_t out_size = in_len * int.sizeof + 15; size_t out_left = out_size; size_t result = 0; size_t in_size = in_len; //char* out_buf = NULL; size_t out_len = 0; size_t in_left = in_len; out_left = in_len + 32; /* Avoid realloc() most cases */ out_size = 0; size_t bsz = out_left; char* out_buf = cast(char *) new char[bsz+1]; char* out_p = out_buf; char* in_p = inbuf.ptr; while (in_left > 0) { result = iconv(cv, cast(char **) &in_p, &in_left, cast(char **) &out_p, &out_left); out_size = bsz - out_left; if (result == cast(size_t)(-1)) { break; /* if (errno == E2BIG && in_left > 0) { // converted string is longer than out buffer bsz += in_len; tmp_buf = (char*) erealloc(out_buf, bsz+1); out_p = out_buf = tmp_buf; out_p += out_size; out_left = bsz - out_size; continue; } */ } break; } if (result != cast(size_t)(-1)) { for (;;) { result = iconv(cv, null, null, cast(char **) &out_p, &out_left); out_size = bsz - out_left; if (result != cast(size_t)(-1)) { break; } /* if (errno == E2BIG) { bsz += 16; tmp_buf = (char *) erealloc(out_buf, bsz); out_p = out_buf = tmp_buf; out_p += out_size; out_left = bsz - out_size; } else { break; } */ } } return out_buf[0..out_size]; } ~this() { if (cv) iconv_close (cv); } }