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