1 /** 2 Just plain functions for reading and writing binary streams, without templates now. 3 4 Copyright: Copyright Guillaume Piolat 2015-2022 5 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 6 */ 7 module gamut.internals.binop; 8 9 pure nothrow @nogc @system: 10 11 // Those functions takes a pointer and update it. 12 // Image codecs are choke full of these sort of functions. 13 // No checks, you must check elsewhere that there is no overflow. 14 // 15 // All those functions take a ubyte* buffer. 16 17 version(LittleEndian) 18 {} 19 else 20 { 21 static assert(false); // adapt this file 22 } 23 24 /// Skip bytes, this is for semantic purpose. 25 void skip_bytes(ref inout(ubyte)* bytes, int toSkip) 26 { 27 bytes += toSkip; 28 } 29 30 // 31 // Bytes (8-bit read and writes) 32 // 33 34 /// Read a `byte`. 35 byte read_byte(ref inout(ubyte)* s) 36 { 37 return *s++; 38 } 39 40 /// Read a `ubyte`. 41 ubyte read_ubyte(ref inout(ubyte)* s) 42 { 43 return *s++; 44 } 45 46 /// Write a `byte`. 47 void write_byte(ref ubyte* s, byte v) 48 { 49 *s++ = v; 50 } 51 52 /// Write a `ubyte`. 53 void write_ubyte(ref ubyte* s, ubyte v) 54 { 55 *s++ = v; 56 } 57 58 // 59 // Shorts (16-bit read and writes) 60 // 61 62 /// Read a Little Endian `short`. 63 short read_short_LE(ref inout(ubyte)* s) 64 { 65 return cast(short) read_ushort_LE(s); 66 } 67 68 /// Read a Little Endian `ushort`. 69 ushort read_ushort_LE(ref inout(ubyte)* s) 70 { 71 ushort v = *cast(ushort*)s; 72 s += 2; 73 return v; 74 } 75 76 /// Write a Little Endian `short`. 77 void write_short_LE(ref ubyte* s, short v) 78 { 79 write_ushort_LE(s, v); 80 } 81 82 /// Write a Little Endian `ushort`. 83 void write_ushort_LE(ref ubyte* s, ushort v) 84 { 85 *cast(ushort*)s = v; 86 s += 2; 87 } 88 89 /// Read a Big Endian `short`. 90 short read_short_BE(ref inout(ubyte)* s) 91 { 92 return read_ushort_BE(s); 93 } 94 95 /// Read a Big Endian `ushort`. 96 ushort read_ushort_BE(ref inout(ubyte)* s) 97 { 98 ubyte a = *s++; 99 ubyte b = *s++; 100 return a << 8 | b; 101 } 102 103 /// Write a Big Endian `short`. 104 void write_short_BE(ref ubyte* s, short v) 105 { 106 write_ushort_BE(s, v); 107 } 108 109 /// Write a Big Endian `ushort`. 110 void write_ushort_BE(ref ubyte* s, ushort v) 111 { 112 *s++ = (0xff00 & v) >> 8; 113 *s++ = (0x00ff & v); 114 } 115 116 // 117 // Ints (32-bit read and writes) 118 // 119 120 /// Read a Little Endian `int`. 121 int read_int_LE(ref inout(ubyte)* s) 122 { 123 return read_uint_LE(s); 124 } 125 126 /// Read a Little Endian `uint`. 127 uint read_uint_LE(ref inout(ubyte)* s) 128 { 129 uint v = *cast(uint*)s; 130 s += uint.sizeof; 131 return v; 132 } 133 134 /// Write a Little Endian `int`. 135 void write_int_LE(ref ubyte* s, int v) 136 { 137 write_uint_LE(s, v); 138 } 139 140 /// Write a Little Endian `uint`. 141 void write_uint_LE(ref ubyte* s, uint v) 142 { 143 *cast(uint*)s = v; 144 s += uint.sizeof; 145 } 146 147 /// Read a Big Endian `int`. 148 int read_int_BE(ref inout(ubyte)* s) 149 { 150 return read_uint_BE(s); 151 } 152 153 /// Read a Big Endian `uint`. 154 uint read_uint_BE(ref inout(ubyte)* s) 155 { 156 ubyte a = *s++; 157 ubyte b = *s++; 158 ubyte c = *s++; 159 ubyte d = *s++; 160 return a << 24 | b << 16 | c << 8 | d; 161 } 162 163 /// Write a Big Endian `int`. 164 void write_int_BE(ref ubyte* s, int v) 165 { 166 write_uint_BE(s, v); 167 } 168 169 /// Write a Big Endian `uint`. 170 void write_uint_BE(ref ubyte* s, uint v) 171 { 172 *s++ = (0xff000000 & v) >> 24; 173 *s++ = (0x00ff0000 & v) >> 16; 174 *s++ = (0x0000ff00 & v) >> 8; 175 *s++ = (0x000000ff & v); 176 } 177 178 // 179 // Long (64-bit read and writes) 180 // 181 182 /// Read a Little Endian `long`. 183 long read_long_LE(ref inout(ubyte)* s) 184 { 185 return read_ulong_LE(s); 186 } 187 188 /// Read a Little Endian `ulong`. 189 ulong read_ulong_LE(ref inout(ubyte)* s) 190 { 191 ulong v = *cast(ulong*)s; 192 s += ulong.sizeof; 193 return v; 194 } 195 196 /// Write a Little Endian `long`. 197 void write_long_LE(ref ubyte* s, long v) 198 { 199 write_ulong_LE(s, v); 200 } 201 202 /// Write a Little Endian `ulong`. 203 void write_ulong_LE(ref ubyte* s, ulong v) 204 { 205 *cast(ulong*)s = v; 206 s += ulong.sizeof; 207 } 208 209 /// Read a Big Endian `long`. 210 long read_long_BE(ref inout(ubyte)* s) 211 { 212 return read_ulong_BE(s); 213 } 214 215 /// Read a Big Endian `ulong`. 216 ulong read_ulong_BE(ref inout(ubyte)* s) 217 { 218 ulong r = 0; 219 foreach(n; 0..8) 220 { 221 r = (r << 8) | *s++; 222 } 223 return r; 224 } 225 226 /// Write a Big Endian `long`. 227 void write_long_BE(ref ubyte* s, long v) 228 { 229 write_ulong_BE(s, v); 230 } 231 232 /// Write a Big Endian `uint`. 233 void write_ulong_BE(ref ubyte* s, ulong v) 234 { 235 *s++ = (0xff00000000000000 & v) >> 56; 236 *s++ = (0x00ff000000000000 & v) >> 48; 237 *s++ = (0x0000ff0000000000 & v) >> 40; 238 *s++ = (0x000000ff00000000 & v) >> 32; 239 *s++ = (0x00000000ff000000 & v) >> 24; 240 *s++ = (0x0000000000ff0000 & v) >> 16; 241 *s++ = (0x000000000000ff00 & v) >> 8; 242 *s++ = (0x00000000000000ff & v); 243 } 244 245 // 246 // Float (32-bit FP) read and write. 247 // 248 249 /// Read a Little Endian `float`. 250 float read_float_LE(ref inout(ubyte)* s) 251 { 252 uint u = read_uint_LE(s); 253 return *cast(float*)&u; 254 } 255 256 /// Write a Little Endian `float`. 257 void write_float_LE(ref ubyte* s, float v) 258 { 259 write_uint_LE(s, *cast(uint*)&v); 260 } 261 262 /// Read a Big Endian `float`. 263 float read_float_BE(ref inout(ubyte)* s) 264 { 265 uint u = read_uint_BE(s); 266 return *cast(float*)&u; 267 } 268 269 /// Write a Big Endian `float`. 270 void write_float_BE(ref ubyte* s, float v) 271 { 272 write_uint_BE(s, *cast(uint*)&v); 273 } 274 275 // 276 // Double (64-bit FP) read and write. 277 // 278 279 /// Read a Little Endian `double`. 280 double read_double_LE(ref inout(ubyte)* s) 281 { 282 ulong u = read_ulong_LE(s); 283 return *cast(double*)&u; 284 } 285 286 /// Write a Little Endian `float`. 287 void write_double_LE(ref ubyte* s, double v) 288 { 289 write_ulong_LE(s, *cast(ulong*)&v); 290 } 291 292 /// Read a Big Endian `float`. 293 double read_double_BE(ref inout(ubyte)* s) 294 { 295 ulong u = read_ulong_BE(s); 296 return *cast(double*)&u; 297 } 298 299 /// Write a Big Endian `float`. 300 void write_double_BE(ref ubyte* s, double v) 301 { 302 write_ulong_BE(s, *cast(ulong*)&v); 303 } 304 305 306 unittest 307 { 308 ubyte[10] arr = [ 0x00, 0x01, 0x02, 0x03 , 309 0x00, 0x01, 0x02, 0x03, 310 0x04, 0x05 ]; 311 ubyte* pRead = arr.ptr; 312 313 assert(read_uint_LE(pRead) == 0x03020100); 314 assert(read_int_BE(pRead) == 0x00010203); 315 assert(read_short_BE(pRead) == 0x0405); 316 317 import std.array; 318 ubyte[4 + 8 + 2] arr2; 319 ubyte* pWrite = arr2.ptr; 320 write_float_BE(pWrite, 1.0f); 321 write_double_LE(pWrite, 2.0); 322 write_short_LE(pWrite, 2); 323 } 324 325 unittest 326 { 327 ubyte[8] arr = [0, 0, 0, 0, 0, 0, 0xe0, 0x3f]; 328 329 ubyte* p = arr.ptr; 330 assert(read_double_LE(p) == 0.5); 331 332 arr = [0, 0, 0, 0, 0, 0, 0xe0, 0xbf]; 333 p = arr.ptr; 334 assert(read_double_LE(p) == -0.5); 335 }