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 }