Mercurial > projects > ldc
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tango/tango/io/stream/UtfStream.d Fri Jan 11 17:57:40 2008 +0100 @@ -0,0 +1,194 @@ +/******************************************************************************* + + 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"); + } +}