1 module binary.common; 2 3 import std.bitmanip; 4 import std..string; 5 6 7 /** 8 * Represents byte order (endianess) 9 */ 10 enum ByteOrder 11 { 12 /// Byte order used on local machine 13 Native, 14 15 /// Little endian 16 LittleEndian, 17 18 /// Big endian 19 BigEndian, 20 } 21 22 23 /** 24 * Binary encodes value. 25 * 26 * Params: 27 * value = Value to encode 28 * byteOrder = Byte order to use 29 * 30 * Returns: 31 * Encoded value 32 */ 33 ubyte[] encodeBinary(T)(T value, ByteOrder byteOrder = ByteOrder.Native) 34 { 35 switch(byteOrder) with (ByteOrder) 36 { 37 case BigEndian: 38 return nativeToBigEndian!T(value).dup; 39 40 case LittleEndian: 41 return nativeToLittleEndian!T(value).dup; 42 43 case Native: 44 ubyte[T.sizeof] buf; 45 ubyte* ptr = cast(ubyte*)&value; 46 for(int i=0; i < T.sizeof; i++) 47 buf[i] = ptr[i]; 48 return buf.dup; 49 50 default: 51 assert(0, "Invalid byte order"); 52 } 53 } 54 55 56 /** 57 * Reads T value from source. 58 * 59 * If data is to small to carry T, DecodeException is thrown. 60 * 61 * Throws: 62 * DecodeException 63 * 64 * Params: 65 * data = Array to read from 66 * byteOrder = Byte order to use 67 */ 68 T decodeBinary(T)(ubyte[] data, ByteOrder byteOrder = ByteOrder.Native, string file = __FILE__, uint line = __LINE__) 69 { 70 if (data.length < T.sizeof) { 71 throw new DecodeException(format("Unexpected end of input stream. Trying to read %d bytes (type %s), but got %d.", 72 T.sizeof, T.stringof, data.length), file, line); 73 } 74 75 switch (byteOrder) with (ByteOrder) 76 { 77 case BigEndian: 78 return bigEndianToNative!T( cast(ubyte[T.sizeof])data[0 .. T.sizeof] ); 79 80 case LittleEndian: 81 return littleEndianToNative!T( cast(ubyte[T.sizeof])data[0 .. T.sizeof] ); 82 83 case Native: 84 T value; 85 ubyte* ptr = cast(ubyte*)&value; 86 for (size_t i=0; i < T.sizeof; ++i) 87 ptr[i] = data[i]; 88 return value; 89 90 default: 91 assert(0, "Invalid byte order"); 92 } 93 } 94 95 96 /** 97 * Thrown when an error occured while decoding data. 98 */ 99 class DecodeException : Exception 100 { 101 this(string msg, string file = __FILE__, uint line = __LINE__) 102 { 103 super(msg, file, line); 104 } 105 }