132
|
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 Streams for swapping endian-order. The stream is treated as a set
|
|
12 of same-sized elements. Note that partial elements are not mutated
|
|
13
|
|
14 *******************************************************************************/
|
|
15
|
|
16 module tango.io.stream.EndianStream;
|
|
17
|
|
18 private import tango.io.Buffer,
|
|
19 tango.io.Conduit;
|
|
20
|
|
21 private import tango.core.ByteSwap;
|
|
22
|
|
23 /*******************************************************************************
|
|
24
|
|
25 Type T is the element type
|
|
26
|
|
27 *******************************************************************************/
|
|
28
|
|
29 class EndianInput(T) : InputFilter
|
|
30 {
|
|
31 static if ((T.sizeof != 2) && (T.sizeof != 4) && (T.sizeof != 8))
|
|
32 pragma (msg, "EndianInput :: type should be of length 2, 4, or 8 bytes");
|
|
33
|
|
34
|
|
35 private IBuffer input;
|
|
36
|
|
37 /***********************************************************************
|
|
38
|
|
39 ***********************************************************************/
|
|
40
|
|
41 this (InputStream stream)
|
|
42 {
|
|
43 super (input = Buffer.share (stream));
|
|
44 }
|
|
45
|
|
46 /***********************************************************************
|
|
47
|
|
48 Buffered interface
|
|
49
|
|
50 ***********************************************************************/
|
|
51
|
|
52 final IBuffer buffer ()
|
|
53 {
|
|
54 return input;
|
|
55 }
|
|
56
|
|
57 /***********************************************************************
|
|
58
|
|
59 Read from conduit into a target array. The provided dst
|
|
60 will be populated with content from the conduit.
|
|
61
|
|
62 Returns the number of bytes read, which may be less than
|
|
63 requested in dst (or IOStream.Eof for end-of-flow). Note
|
|
64 that a trailing partial element will be placed into dst,
|
|
65 but the returned length will effectively ignore it
|
|
66
|
|
67 ***********************************************************************/
|
|
68
|
|
69 final override uint read (void[] dst)
|
|
70 {
|
|
71 uint len = input.fill (dst[0 .. dst.length & ~(T.sizeof-1)]);
|
|
72 if (len != Eof)
|
|
73 {
|
|
74 // the final read may be misaligned ...
|
|
75 len &= ~(T.sizeof - 1);
|
|
76
|
|
77 static if (T.sizeof == 2)
|
|
78 ByteSwap.swap16 (dst.ptr, len);
|
|
79
|
|
80 static if (T.sizeof == 4)
|
|
81 ByteSwap.swap32 (dst.ptr, len);
|
|
82
|
|
83 static if (T.sizeof == 8)
|
|
84 ByteSwap.swap64 (dst.ptr, len);
|
|
85 }
|
|
86 return len;
|
|
87 }
|
|
88 }
|
|
89
|
|
90
|
|
91
|
|
92 /*******************************************************************************
|
|
93
|
|
94 Type T is the element type
|
|
95
|
|
96 *******************************************************************************/
|
|
97
|
|
98 class EndianOutput (T) : OutputFilter
|
|
99 {
|
|
100 static if ((T.sizeof != 2) && (T.sizeof != 4) && (T.sizeof != 8))
|
|
101 pragma (msg, "EndianOutput :: type should be of length 2, 4, or 8 bytes");
|
|
102
|
|
103 private IBuffer output;
|
|
104
|
|
105 /***********************************************************************
|
|
106
|
|
107 ***********************************************************************/
|
|
108
|
|
109 this (OutputStream stream)
|
|
110 {
|
|
111 super (output = Buffer.share (stream));
|
|
112 }
|
|
113
|
|
114 /***********************************************************************
|
|
115
|
|
116 Write to output stream from a source array. The provided
|
|
117 src content will be consumed and left intact.
|
|
118
|
|
119 Returns the number of bytes written from src, which may
|
|
120 be less than the quantity provided. Note that any partial
|
|
121 elements will not be consumed
|
|
122
|
|
123 ***********************************************************************/
|
|
124
|
|
125 final override uint write (void[] src)
|
|
126 {
|
|
127 uint writer (void[] dst)
|
|
128 {
|
|
129 auto len = dst.length;
|
|
130 if (len > src.length)
|
|
131 len = src.length;
|
|
132
|
|
133 len &= ~(T.sizeof - 1);
|
|
134 dst [0..len] = src [0..len];
|
|
135
|
|
136 static if (T.sizeof == 2)
|
|
137 ByteSwap.swap16 (dst.ptr, len);
|
|
138
|
|
139 static if (T.sizeof == 4)
|
|
140 ByteSwap.swap32 (dst.ptr, len);
|
|
141
|
|
142 static if (T.sizeof == 8)
|
|
143 ByteSwap.swap64 (dst.ptr, len);
|
|
144
|
|
145 return len;
|
|
146 }
|
|
147
|
|
148 uint bytes = src.length;
|
|
149
|
|
150 // flush if we used all buffer space
|
|
151 if ((bytes -= output.write (&writer)) >= T.sizeof)
|
|
152 if (output.output)
|
|
153 output.drain (output.output);
|
|
154 else
|
|
155 return Eof;
|
|
156 return src.length - bytes;
|
|
157 }
|
|
158 }
|
|
159
|
|
160
|
|
161 /*******************************************************************************
|
|
162
|
|
163 *******************************************************************************/
|
|
164
|
|
165 debug (UnitTest)
|
|
166 {
|
|
167 import tango.io.Stdout;
|
|
168
|
|
169 unittest
|
|
170 {
|
|
171 auto inp = new EndianInput!(dchar)(new Buffer("hello world"d));
|
|
172 auto oot = new EndianOutput!(dchar)(new Buffer(64));
|
|
173 oot.copy (inp);
|
|
174 assert (oot.output.slice == "hello world"d);
|
|
175 }
|
|
176 }
|