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 }