The OpenD Programming Language

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 }