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 }