Mercurial > projects > ldc
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 } |