1 // Written in the D programming language.
2 
3 /**
4 Module for manipulating bytes in constructing and deconstructing various byte orders. 
5 
6 Copyright: LightHouse Software, 2021
7 License:   $(HTTP https://github.com/aquaratixc/ESL-License, Experimental Software License 1.0).
8 Authors:   Oleg Bakharev,
9 		   Ilya Pertsev
10 */
11 module styx2000.lowlevel.endianness;
12 
13 /// Endianess (i.e byte-order)
14 enum BYTE_ORDER
15 {
16 	/// Little-endian byte-order
17 	LITTLE_ENDIAN,
18 	/// Big-endian byte-order
19 	BIG_ENDIAN
20 }
21 
22 
23 /**
24 	A class that provides functionality for construct and deconstruct values. All methods is static.
25 */
26 class EndianSequence
27 {	
28 	/**
29 	Constructs (restores) a value from the passed in byte array.
30     Params:
31 	byteOrder = Byte order for value (little or big endian).
32     bytes = Array of unsigned bytes for reconstructing value.
33     
34     Typical usage:
35     ----
36     uint tmp = EndianSequence.unpack!uint([0xab, 0xcd, 0xef, 0x00]);
37     ----
38     */
39 	static T unpack(T)(BYTE_ORDER byteOrder, ubyte[] bytes...)
40     {
41         T mask;
42         size_t shift;
43 
44         foreach (i, e; bytes)
45         {
46             final switch (byteOrder) with (BYTE_ORDER)
47             {
48 	            case LITTLE_ENDIAN:
49 	                shift = (i << 3);
50 	                break;
51 	            case BIG_ENDIAN:
52 	                shift = ((bytes.length - i - 1) << 3);
53 	                break;
54             }
55             mask |= (e << shift);
56         }
57 
58         return mask;
59     }
60 
61 	/**
62 	Deconstructs (saves) a passed value to unsigned byte array.
63     Params:
64 	byteOrder = Byte order for value (little or big endian).
65     value = Value for deconstructing.
66     
67     Typical usage:
68     ----
69     ubyte[] tmp = EndianSequence.pack!uint(150_000);
70     ----
71     */
72     static ubyte[] pack(T)(BYTE_ORDER byteOrder, T value)
73     {
74         ubyte[] data;
75         T mask = cast(T) 0xff;
76         size_t shift;
77 
78         foreach (i; 0 .. T.sizeof)
79         {
80             final switch (byteOrder) with (BYTE_ORDER)
81             {
82 	            case LITTLE_ENDIAN:
83 	                shift = (i << 3);
84 	                break;
85 	            case BIG_ENDIAN:
86 	                shift = ((T.sizeof - i - 1) << 3);
87 	                break;
88             }
89 
90             data ~= cast(ubyte)((value & (mask << shift)) >> shift);
91         }
92 
93         return data;
94     }
95 }
96 
97 
98 
99 /**
100 Parse a value into bytes in little-endian order. Helper for EndianSequence.pack with preset Little Endian byte order (LE).
101 Params:
102 value = Value for parsing.
103 Returns: An array of unsigned bytes representing the value passed as a parameter in little-endian order
104 
105 
106 Typical usage:
107 ----
108 ubyte[] tmp = toLEBytes!uint(150_000);
109 ----
110 */
111 auto toLEBytes(T)(T value)
112 {
113 	return EndianSequence.pack!T(BYTE_ORDER.LITTLE_ENDIAN, value);
114 }
115 
116 /**
117 Construct a value from bytes fed in little-endian order. Helper for EndianSequence.unpack with preset Little Endian byte order (LE).
118 Params:
119 bytes = An array of unsigned bytes (little-endian-order).
120 Returns: The value retrieved from the array
121 
122 
123 Typical usage:
124 ----
125 // value is 0x00efcdab in hex or 15715755 in dec  
126 uint tmp = fromLEBytes!uint([0xab, 0xcd, 0xef, 0x00]);
127 ----
128 */
129 auto fromLEBytes(T)(ubyte[] bytes...)
130 {
131 	return EndianSequence.unpack!T(BYTE_ORDER.LITTLE_ENDIAN, bytes);
132 }
133 
134 /**
135 Parse a value into bytes in big-endian order. Helper for EndianSequence.pack with preset Big Endian byte order (BE).
136 Params:
137 value = Value for parsing.
138 Returns: An array of unsigned bytes representing the value passed as a parameter in little-endian order
139 
140 
141 Typical usage:
142 ----
143 ubyte[] tmp = toBEBytes!uint(150_000);
144 ----
145 */
146 auto toBEBytes(T)(T value)
147 {
148 	return EndianSequence.pack!T(BYTE_ORDER.BIG_ENDIAN, value);
149 }
150 
151 /**
152 Construct a value from bytes fed in big-endian order. Helper for EndianSequence.unpack with preset Big Endian byte order (BE).
153 Params:
154 bytes = An array of unsigned bytes (big-endian-order).
155 Returns: The value retrieved from the array
156 
157 
158 Typical usage:
159 ----
160 // value is 0xabcdef00 in hex or 2882400000 in dec
161 uint tmp = fromBEBytes!uint([0xab, 0xcd, 0xef, 0x00]);
162 ----
163 */
164 auto fromBEBytes(T)(ubyte[] bytes...)
165 {
166 	return EndianSequence.unpack!T(BYTE_ORDER.BIG_ENDIAN, bytes);
167 }