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 }