The OpenD Programming Language

1 module audioformats.io;
2 
3 import audioformats.internals;
4 
5 nothrow @nogc
6 {
7     alias ioSeekCallback          = bool function(long offset, bool relative, void* userData); // return true on success
8     alias ioTellCallback          = long function(                            void* userData);  
9     alias ioGetFileLengthCallback = long function(                            void* userData);
10     alias ioReadCallback          = int  function(void* outData, int bytes,   void* userData); // returns number of read bytes
11     alias ioWriteCallback         = int  function(void* inData, int bytes,    void* userData); // returns number of written bytes
12     alias ioSkipCallback          = bool function(int bytes,                  void* userData);
13     alias ioFlushCallback         = bool function(                            void* userData);
14 }
15 
16 struct IOCallbacks
17 {
18 nothrow @nogc:
19 
20     ioSeekCallback seek;
21     ioTellCallback tell;
22     ioGetFileLengthCallback getFileLength;
23     ioReadCallback read;
24     ioWriteCallback write;
25     ioSkipCallback skip;
26     ioFlushCallback flush;
27 
28 
29     // Now, some helpers for binary parsing based on these callbacks
30 
31     // <reading>
32 
33     bool nothingToReadAnymore(void* userData)
34     {
35         return remainingBytesToRead(userData) <= 0;
36     }
37 
38     long remainingBytesToRead(void* userData)
39     {
40         long cursor = tell(userData);
41         long fileLength = getFileLength(userData);
42         assert(cursor <= fileLength);
43         return fileLength - cursor;
44     }
45   
46     /// Read one ubyte from stream and do not advance the stream cursor.
47     /// On error, return an error, the stream then is considered invalid.
48     ubyte peek_ubyte(void* userData, bool* err)
49     {
50         ubyte b = read_ubyte(userData, err);
51         if (*err)
52             return 0;
53 
54         *err = !seek(tell(userData) - 1, false, userData);
55         return b;
56     }
57 
58     /// Read one ubyte from stream and advance the stream cursor.
59     /// On error, return 0 and an error, stream is then considered invalid.
60     ubyte read_ubyte(void* userData, bool* err)
61     {
62         ubyte b;
63         if (1 == read(&b, 1, userData))
64         {
65             *err = false;
66             return b;
67         }
68         *err = true;
69         return 0;
70     }
71 
72     /// Reads a 16-byte UUID from the stream and advance cursor.
73     /// On error, the stream is considered invalid, and the return value is undefined behaviour.
74     ubyte[16] read_guid(void* userData, bool* err)
75     {
76         ubyte[16] b;
77         if (16 == read(&b, 16, userData))
78         {
79             *err = false;
80             return b;
81         }
82         *err = true;
83         return b;
84     }
85 
86     /// Read one Little Endian ushort from stream and advance the stream cursor.
87     /// On error, return 0 and an error, stream is then considered invalid.
88     ushort read_ushort_LE(void* userData, bool* err)
89     {
90         ubyte[2] v;
91         if (2 == read(v.ptr, 2, userData))
92         {
93             version(BigEndian)
94             {
95                 ubyte v0 = v[0];
96                 v[0] = v[1];
97                 v[1] = v0;
98             }
99 
100             *err = false;
101             return *cast(ushort*)(v.ptr);
102         }
103         else
104         {
105             *err = true;
106             return 0;
107         }
108     }
109 
110     /// Read one Big Endian 32-bit unsigned int from stream and advance the stream cursor.
111     /// On error, return 0 and an error, stream is then considered invalid.
112     uint read_uint_BE(void* userData, bool* err)
113     {
114         ubyte[4] v;
115         if (4 == read(v.ptr, 4, userData))
116         {
117             version(LittleEndian)
118             {
119                 ubyte v0 = v[0];
120                 v[0] = v[3];
121                 v[3] = v0;
122                 ubyte v1 = v[1];
123                 v[1] = v[2];
124                 v[2] = v1;
125             }
126             *err = false;
127             return *cast(uint*)(v.ptr);
128         }
129         else
130         {
131             *err = true;
132             return 0;
133         }
134     }
135 
136     /// Read one Little Endian 32-bit unsigned int from stream and advance the stream cursor.
137     /// On error, return 0 and an error, stream is then considered invalid.
138     uint read_uint_LE(void* userData, bool* err)
139     {
140         ubyte[4] v;
141         if (4 == read(v.ptr, 4, userData))
142         {
143             version(BigEndian)
144             {
145                 ubyte v0 = v[0];
146                 v[0] = v[3];
147                 v[3] = v0;
148                 ubyte v1 = v[1];
149                 v[1] = v[2];
150                 v[2] = v1;
151             }
152             *err = false;
153             return *cast(uint*)(v.ptr);
154         }
155         else
156         {
157             *err = true;
158             return 0;
159         }
160     }
161 
162     /// Read one Big Endian 64-bit integer from stream and advance the stream cursor.
163     /// On error, return `0` and an error, stream is then considered invalid.
164     ulong read_ulong_BE(void* userData, bool* err)
165     {
166         ubyte[8] v;
167         if (8 == read(v.ptr, 8, userData))
168         {
169             version(LittleEndian)
170             {
171                 ubyte v0 = v[0];
172                 v[0] = v[7];
173                 v[7] = v0;
174                 ubyte v1 = v[1];
175                 v[1] = v[6];
176                 v[6] = v1;
177                 ubyte v2 = v[2];
178                 v[2] = v[5];
179                 v[5] = v2;
180                 ubyte v3 = v[3];
181                 v[3] = v[4];
182                 v[4] = v3;
183             }
184             *err = false;
185             return *cast(ulong*)(v.ptr);
186         }
187         else
188         {
189             *err = true;
190             return 0;
191         }
192     }
193 
194     /// Read one Little Endian 24-bit unsigned int from stream and advance the stream cursor.
195     /// On error, return 0 and an error, stream is then considered invalid.
196     uint read_24bits_LE(void* userData, bool *err)
197     {
198         ubyte[3] v;
199         if (3 == read(v.ptr, 3, userData))
200         {
201             *err = false;
202             return v[0] | (v[1] << 8) | (v[2] << 16);
203         }
204         else
205         {
206             *err = true;
207             return 0;
208         }
209     }
210 
211     /// Read one Little Endian 32-bit float from stream and advance the stream cursor.
212     /// On error, return `float.nan` and an error, stream is then considered invalid.
213     float read_float_LE(void* userData, bool* err)
214     {
215         uint u = read_uint_LE(userData, err);
216         if (*err)
217             return float.nan;
218         else
219             return *cast(float*)(&u);
220     }
221 
222     /// Read one Little Endian 64-bit float from stream and advance the stream cursor.
223     /// On error, return `double.nan` and an error, stream is then considered invalid.
224     double read_double_LE(void* userData, bool* err)
225     {
226         ubyte[8] v;
227         if (8 == read(v.ptr, 8, userData))
228         {
229             version(BigEndian)
230             {
231                 ubyte v0 = v[0];
232                 v[0] = v[7];
233                 v[7] = v0;
234                 ubyte v1 = v[1];
235                 v[1] = v[6];
236                 v[6] = v1;
237                 ubyte v2 = v[2];
238                 v[2] = v[5];
239                 v[5] = v2;
240                 ubyte v3 = v[3];
241                 v[3] = v[4];
242                 v[4] = v3;
243             }
244             *err = false;
245             return *cast(double*)(v.ptr);
246         }
247         else
248         {
249             *err = true;
250             return double.nan;
251         }
252     }
253 
254     /// Read one Lthe two fields of a RIFF header: chunk ID and chunk size.
255     /// On error, return values are undefined behaviour.
256     void readRIFFChunkHeader(void* userData, 
257                              ref uint chunkId, 
258                              ref uint chunkSize,
259                              bool* err)
260     {
261         // chunk ID is read as Big Endian uint
262         chunkId = read_uint_BE(userData, err);
263         if (*err)
264             return;
265 
266         // chunk size is read as Little Endian uint
267         chunkSize = read_uint_LE(userData, err);
268     }
269 
270     // </reading>
271 
272     // <writing>
273 
274     string writeFailureMessage = "write failure";
275 
276     /// Write a Big Endian 32-bit unsigned int to stream and advance cursor.
277     /// Returns: `true` on success, else stream is invalid.
278     bool write_uint_BE(void* userData, uint value)
279     {
280         ubyte[4] v;
281         *cast(uint*)(v.ptr) = value;
282         version(LittleEndian)
283         {
284             ubyte v0 = v[0];
285             v[0] = v[3];
286             v[3] = v0;
287             ubyte v1 = v[1];
288             v[1] = v[2];
289             v[2] = v1;
290         }
291         return (4 == write(v.ptr, 4, userData));
292     }
293 
294     /// Write a 8-bit signed int to stream and advance cursor.
295     /// Returns: `true` on success, else stream is invalid.
296     bool write_byte(void* userData, byte value)
297     {
298         return 1 == write(&value, 1, userData);
299     }
300 
301     /// Write a 8-bit signed int to stream and advance cursor.
302     /// Returns: `true` on success, else stream is invalid.
303     bool write_short_LE(void* userData, short value)
304     {
305         ubyte[2] v;
306         *cast(ushort*)(v.ptr) = value;
307         version(BigEndian)
308         {
309             ubyte v0 = v[0];
310             v[0] = v[1];
311             v[1] = v0;
312         }
313         return 2 == write(v.ptr, 2, userData);
314     }
315 
316     /// Write a Little Endian 24-bit signed int to stream and advance cursor.
317     /// Returns: `true` on success, else stream is invalid.
318     bool write_24bits_LE(void* userData, int value)
319     {
320         ubyte[4] v;
321         *cast(int*)(v.ptr) = value;
322         version(BigEndian)
323         {
324             ubyte v0 = v[0];
325             v[0] = v[3];
326             v[3] = v0;
327             ubyte v1 = v[1];
328             v[1] = v[2];
329             v[2] = v1;
330         }
331         return 3 == write(v.ptr, 3, userData);
332     }
333 
334     /// Write a Little Endian 32-bit float to stream and advance cursor.
335     /// Returns: `true` on success, else stream is invalid.
336     bool write_float_LE(void* userData, float value)
337     {
338         return write_uint_LE(userData, *cast(uint*)(&value));
339     }
340 
341     /// Write a Little Endian 64-bit double to stream and advance cursor.
342     /// Returns: `true` on success, else stream is invalid.
343     bool write_double_LE(void* userData, float value)
344     {
345         return write_ulong_LE(userData, *cast(ulong*)(&value));
346     }
347 
348     /// Write a Little Endian 64-bit unsigned integer to stream and advance cursor.
349     /// Returns: `true` on success, else stream is invalid.
350     bool write_ulong_LE(void* userData, ulong value)
351     {
352         ubyte[8] v;
353         *cast(ulong*)(v.ptr) = value;
354         version(BigEndian)
355         {
356             ubyte v0 = v[0];
357             v[0] = v[7];
358             v[7] = v0;
359             ubyte v1 = v[1];
360             v[1] = v[6];
361             v[6] = v1;
362             ubyte v2 = v[2];
363             v[2] = v[5];
364             v[5] = v2;
365             ubyte v3 = v[3];
366             v[3] = v[4];
367             v[4] = v3;
368         }
369 
370         return 8 == write(v.ptr, 8, userData);
371     }
372 
373     /// Write a Little Endian 64-bit unsigned integer to stream and advance cursor.
374     /// Returns: `true` on success, else stream is invalid.
375     bool write_ulong_BE(void* userData, ulong value)
376     {
377         ubyte[8] v;
378         *cast(ulong*)(v.ptr) = value;
379         version(LittleEndian)
380         {
381             ubyte v0 = v[0];
382             v[0] = v[7];
383             v[7] = v0;
384             ubyte v1 = v[1];
385             v[1] = v[6];
386             v[6] = v1;
387             ubyte v2 = v[2];
388             v[2] = v[5];
389             v[5] = v2;
390             ubyte v3 = v[3];
391             v[3] = v[4];
392             v[4] = v3;
393         }
394 
395         return 8 == write(v.ptr, 8, userData);
396     }
397 
398     /// Write a Little Endian 32-bit unsigned integer to stream and advance cursor.
399     /// Returns: `true` on success, else stream is invalid.
400     bool write_uint_LE(void* userData, uint value)
401     {
402         ubyte[4] v;
403         *cast(uint*)(v.ptr) = value;
404         version(BigEndian)
405         {
406             ubyte v0 = v[0];
407             v[0] = v[3];
408             v[3] = v0;
409             ubyte v1 = v[1];
410             v[1] = v[2];
411             v[2] = v1;
412         }
413 
414         return 4 == write(v.ptr, 4, userData);
415     }
416 
417     /// Write a Little Endian 16-bit unsigned integer to stream and advance cursor.
418     /// Returns: `true` on success, else stream is invalid.
419     bool write_ushort_LE(void* userData, ushort value)
420     {
421         ubyte[2] v;
422         *cast(ushort*)(v.ptr) = value;
423         version(BigEndian)
424         {
425             ubyte v0 = v[0];
426             v[0] = v[1];
427             v[1] = v0;
428         }
429         return 2 == write(v.ptr, 2, userData);
430     }
431 
432     /// Write a RIFF header to stream and advance cursor.
433     /// Returns: `true` on success, else stream is invalid.
434     bool writeRIFFChunkHeader(void* userData, uint chunkId, uint chunkSize)
435     {
436         if (!write_uint_BE(userData, chunkId))
437             return false;
438         return write_uint_LE(userData, chunkSize);
439     }
440 
441     // </writing>
442 }
443 
444 
445 template RIFFChunkId(string id)
446 {
447     static assert(id.length == 4);
448     __gshared uint RIFFChunkId = (cast(ubyte)(id[0]) << 24)
449         | (cast(ubyte)(id[1]) << 16)
450         | (cast(ubyte)(id[2]) << 8)
451         | (cast(ubyte)(id[3]));
452 }