comparison 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
comparison
equal deleted inserted replaced
131:5825d48b27d1 132:1700239cab2e
1 /*******************************************************************************
2
3 copyright: Copyright (c) 2007 Kris Bell. All rights reserved
4
5 license: BSD style: $(LICENSE)
6
7 version: Initial release: Nov 2007
8
9 author: Kris
10
11 UTF conversion streams, supporting cross-translation of char, wchar
12 and dchar variants. For supporting endian variations, configure the
13 appropriate EndianStream upstream of this one (closer to the source)
14
15 *******************************************************************************/
16
17 module tango.io.stream.UtfStream;
18
19 private import tango.io.Buffer,
20 tango.io.Conduit;
21
22 private import Utf = tango.text.convert.Utf;
23
24 /*******************************************************************************
25
26 Streaming UTF converter. Type T is the target or destination type,
27 while S is the source type. Both types are either char/wchar/dchar.
28
29 *******************************************************************************/
30
31 class UtfInput(T, S) : InputFilter
32 {
33 static if (!is (S == char) && !is (S == wchar) && !is (S == dchar))
34 pragma (msg, "Source type must be char, wchar, or dchar");
35
36 static if (!is (T == char) && !is (T == wchar) && !is (T == dchar))
37 pragma (msg, "Target type must be char, wchar, or dchar");
38
39 private IBuffer buffer;
40
41 /***********************************************************************
42
43 ***********************************************************************/
44
45 this (InputStream stream)
46 {
47 super (buffer = Buffer.share (stream));
48 }
49
50 /***********************************************************************
51
52 ***********************************************************************/
53
54 final override uint read (void[] dst)
55 {
56 static if (is (S == T))
57 return super.read (dst);
58 else
59 {
60 // must have some space available for converting
61 if (dst.length < T.sizeof)
62 conduit.error ("UtfStream.read :: target array is too small");
63
64 uint produced,
65 consumed;
66 auto output = Buffer.convert!(T)(dst);
67 auto input = Buffer.convert!(S)(buffer.slice);
68
69 static if (is (T == char))
70 produced = Utf.toString(input, output, &consumed).length;
71
72 static if (is (T == wchar))
73 produced = Utf.toString16(input, output, &consumed).length;
74
75 static if (is (T == dchar))
76 produced = Utf.toString32(input, output, &consumed).length;
77
78 // consume buffer content
79 buffer.skip (consumed * S.sizeof);
80
81 // fill buffer when nothing produced ...
82 if (produced is 0)
83 if (buffer.compress.fill(buffer.input) is Eof)
84 return Eof;
85
86 return produced * T.sizeof;
87 }
88 }
89 }
90
91
92 /*******************************************************************************
93
94 Streaming UTF converter. Type T is the target or destination type,
95 while S is the source type. Both types are either char/wchar/dchar.
96
97 Note that the arguments are reversed from those of UtfInput
98
99 *******************************************************************************/
100
101 class UtfOutput (S, T) : OutputFilter
102 {
103 static if (!is (S == char) && !is (S == wchar) && !is (S == dchar))
104 pragma (msg, "Source type must be char, wchar, or dchar");
105
106 static if (!is (T == char) && !is (T == wchar) && !is (T == dchar))
107 pragma (msg, "Target type must be char, wchar, or dchar");
108
109
110 private IBuffer buffer;
111
112 /***********************************************************************
113
114 ***********************************************************************/
115
116 this (OutputStream stream)
117 {
118 super (buffer = Buffer.share (stream));
119 assert (buffer.capacity > 3, "UtfOutput :: output buffer is too small");
120 }
121
122 /***********************************************************************
123
124 Write to the output stream from a source array. The provided
125 src content is converted as necessary. Note that an attached
126 output buffer must be at least four bytes wide to accommodate
127 a conversion.
128
129 Returns the number of bytes consumed from src, which may be
130 less than the quantity provided
131
132 ***********************************************************************/
133
134 final override uint write (void[] src)
135 {
136 static if (is (S == T))
137 return super.write (src);
138 else
139 {
140 uint consumed,
141 produced;
142
143 uint writer (void[] dst)
144 {
145 auto input = Buffer.convert!(S)(src);
146 auto output = Buffer.convert!(T)(dst);
147
148 static if (is (T == char))
149 produced = Utf.toString(input, output, &consumed).length;
150
151 static if (is (T == wchar))
152 produced = Utf.toString16(input, output, &consumed).length;
153
154 static if (is (T == dchar))
155 produced = Utf.toString32(input, output, &consumed).length;
156
157 return produced * T.sizeof;
158 }
159
160 // write directly into the buffered content. A tad
161 // tricky to flush the output in an optimal manner.
162 // We could do this trivially via an internal work
163 // space conversion, but that would incur an extra
164 // memory copy
165 if (buffer.write(&writer) is 0)
166 // empty a connected buffer
167 if (buffer.output)
168 buffer.drain (buffer.output);
169 else
170 // buffer must be at least 4 bytes wide
171 // to contain a generic conversion
172 if (buffer.writable < 4)
173 return Eof;
174
175 return consumed * S.sizeof;
176 }
177 }
178 }
179
180
181 /*******************************************************************************
182
183 *******************************************************************************/
184
185 debug (UtfStream)
186 {
187 void main()
188 {
189 auto inp = new UtfInput!(dchar, char)(new Buffer("hello world"));
190 auto oot = new UtfOutput!(dchar, char)(new Buffer(20));
191 oot.copy(inp);
192 assert (oot.buffer.slice == "hello world");
193 }
194 }