Mercurial > projects > ldc
view tango/tango/io/stream/UtfStream.d @ 132:1700239cab2e trunk
[svn r136] MAJOR UNSTABLE UPDATE!!!
Initial commit after moving to Tango instead of Phobos.
Lots of bugfixes...
This build is not suitable for most things.
author | lindquist |
---|---|
date | Fri, 11 Jan 2008 17:57:40 +0100 |
parents | |
children |
line wrap: on
line source
/******************************************************************************* copyright: Copyright (c) 2007 Kris Bell. All rights reserved license: BSD style: $(LICENSE) version: Initial release: Nov 2007 author: Kris UTF conversion streams, supporting cross-translation of char, wchar and dchar variants. For supporting endian variations, configure the appropriate EndianStream upstream of this one (closer to the source) *******************************************************************************/ module tango.io.stream.UtfStream; private import tango.io.Buffer, tango.io.Conduit; private import Utf = tango.text.convert.Utf; /******************************************************************************* Streaming UTF converter. Type T is the target or destination type, while S is the source type. Both types are either char/wchar/dchar. *******************************************************************************/ class UtfInput(T, S) : InputFilter { static if (!is (S == char) && !is (S == wchar) && !is (S == dchar)) pragma (msg, "Source type must be char, wchar, or dchar"); static if (!is (T == char) && !is (T == wchar) && !is (T == dchar)) pragma (msg, "Target type must be char, wchar, or dchar"); private IBuffer buffer; /*********************************************************************** ***********************************************************************/ this (InputStream stream) { super (buffer = Buffer.share (stream)); } /*********************************************************************** ***********************************************************************/ final override uint read (void[] dst) { static if (is (S == T)) return super.read (dst); else { // must have some space available for converting if (dst.length < T.sizeof) conduit.error ("UtfStream.read :: target array is too small"); uint produced, consumed; auto output = Buffer.convert!(T)(dst); auto input = Buffer.convert!(S)(buffer.slice); static if (is (T == char)) produced = Utf.toString(input, output, &consumed).length; static if (is (T == wchar)) produced = Utf.toString16(input, output, &consumed).length; static if (is (T == dchar)) produced = Utf.toString32(input, output, &consumed).length; // consume buffer content buffer.skip (consumed * S.sizeof); // fill buffer when nothing produced ... if (produced is 0) if (buffer.compress.fill(buffer.input) is Eof) return Eof; return produced * T.sizeof; } } } /******************************************************************************* Streaming UTF converter. Type T is the target or destination type, while S is the source type. Both types are either char/wchar/dchar. Note that the arguments are reversed from those of UtfInput *******************************************************************************/ class UtfOutput (S, T) : OutputFilter { static if (!is (S == char) && !is (S == wchar) && !is (S == dchar)) pragma (msg, "Source type must be char, wchar, or dchar"); static if (!is (T == char) && !is (T == wchar) && !is (T == dchar)) pragma (msg, "Target type must be char, wchar, or dchar"); private IBuffer buffer; /*********************************************************************** ***********************************************************************/ this (OutputStream stream) { super (buffer = Buffer.share (stream)); assert (buffer.capacity > 3, "UtfOutput :: output buffer is too small"); } /*********************************************************************** Write to the output stream from a source array. The provided src content is converted as necessary. Note that an attached output buffer must be at least four bytes wide to accommodate a conversion. Returns the number of bytes consumed from src, which may be less than the quantity provided ***********************************************************************/ final override uint write (void[] src) { static if (is (S == T)) return super.write (src); else { uint consumed, produced; uint writer (void[] dst) { auto input = Buffer.convert!(S)(src); auto output = Buffer.convert!(T)(dst); static if (is (T == char)) produced = Utf.toString(input, output, &consumed).length; static if (is (T == wchar)) produced = Utf.toString16(input, output, &consumed).length; static if (is (T == dchar)) produced = Utf.toString32(input, output, &consumed).length; return produced * T.sizeof; } // write directly into the buffered content. A tad // tricky to flush the output in an optimal manner. // We could do this trivially via an internal work // space conversion, but that would incur an extra // memory copy if (buffer.write(&writer) is 0) // empty a connected buffer if (buffer.output) buffer.drain (buffer.output); else // buffer must be at least 4 bytes wide // to contain a generic conversion if (buffer.writable < 4) return Eof; return consumed * S.sizeof; } } } /******************************************************************************* *******************************************************************************/ debug (UtfStream) { void main() { auto inp = new UtfInput!(dchar, char)(new Buffer("hello world")); auto oot = new UtfOutput!(dchar, char)(new Buffer(20)); oot.copy(inp); assert (oot.buffer.slice == "hello world"); } }