aboutsummaryrefslogtreecommitdiff
path: root/tests/freealut/src/alutLoader.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/freealut/src/alutLoader.c')
-rw-r--r--tests/freealut/src/alutLoader.c493
1 files changed, 493 insertions, 0 deletions
diff --git a/tests/freealut/src/alutLoader.c b/tests/freealut/src/alutLoader.c
new file mode 100644
index 00000000..c21ed483
--- /dev/null
+++ b/tests/freealut/src/alutLoader.c
@@ -0,0 +1,493 @@
+#include "alutInternal.h"
+#include <ctype.h>
+
+/****************************************************************************/
+
+typedef enum
+{
+ LittleEndian,
+ BigEndian,
+ UnknwonEndian /* has anybody still a PDP11? :-) */
+} Endianess;
+
+/* test from Harbison & Steele, "C - A Reference Manual", section 6.1.2 */
+static Endianess endianess(void)
+{
+ union
+ {
+ long l;
+ char c[sizeof(long)];
+ } u;
+
+ u.l = 1;
+ return (u.c[0] == 1) ? LittleEndian : ((u.c[sizeof(long) - 1] == 1) ? BigEndian : UnknwonEndian);
+}
+
+/****************************************************************************/
+
+static int safeToLower(int c)
+{
+ return isupper(c) ? tolower(c) : c;
+}
+
+static int hasSuffixIgnoringCase(const char *string, const char *suffix)
+{
+ const char *stringPointer = string;
+ const char *suffixPointer = suffix;
+
+ if (suffix[0] == '\0')
+ {
+ return 1;
+ }
+
+ while (*stringPointer != '\0')
+ {
+ stringPointer++;
+ }
+
+ while (*suffixPointer != '\0')
+ {
+ suffixPointer++;
+ }
+
+ if (stringPointer - string < suffixPointer - suffix)
+ {
+ return 0;
+ }
+
+ while (safeToLower(*--suffixPointer) == safeToLower(*--stringPointer))
+ {
+ if (suffixPointer == suffix)
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static BufferData *loadWavFile(InputStream * stream)
+{
+ ALboolean found_header = AL_FALSE;
+ UInt32LittleEndian chunkLength;
+ Int32BigEndian magic;
+ UInt16LittleEndian audioFormat;
+ UInt16LittleEndian numChannels;
+ UInt32LittleEndian sampleFrequency;
+ UInt32LittleEndian byteRate;
+ UInt16LittleEndian blockAlign;
+ UInt16LittleEndian bitsPerSample;
+ Codec *codec = _alutCodecLinear;
+
+ if (!_alutInputStreamReadUInt32LE(stream, &chunkLength) || !_alutInputStreamReadInt32BE(stream, &magic))
+ {
+ return NULL;
+ }
+
+ if (magic != 0x57415645) /* "WAVE" */
+ {
+ _alutSetError(ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE);
+ return NULL;
+ }
+
+ while (1)
+ {
+ if (!_alutInputStreamReadInt32BE(stream, &magic) || !_alutInputStreamReadUInt32LE(stream, &chunkLength))
+ {
+ return NULL;
+ }
+
+ if (magic == 0x666d7420) /* "fmt " */
+ {
+ found_header = AL_TRUE;
+
+ if (chunkLength < 16)
+ {
+ _alutSetError(ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA);
+ return NULL;
+ }
+
+ if (!_alutInputStreamReadUInt16LE(stream, &audioFormat) ||
+ !_alutInputStreamReadUInt16LE(stream, &numChannels) ||
+ !_alutInputStreamReadUInt32LE(stream, &sampleFrequency) ||
+ !_alutInputStreamReadUInt32LE(stream, &byteRate) ||
+ !_alutInputStreamReadUInt16LE(stream, &blockAlign) || !_alutInputStreamReadUInt16LE(stream, &bitsPerSample))
+ {
+ return NULL;
+ }
+
+ if (!_alutInputStreamSkip(stream, chunkLength - 16))
+ {
+ return NULL;
+ }
+
+ switch (audioFormat)
+ {
+ case 1: /* PCM */
+ codec = (bitsPerSample == 8 || endianess() == LittleEndian) ? _alutCodecLinear : _alutCodecPCM16;
+ break;
+ case 7: /* uLaw */
+ bitsPerSample *= 2; /* ToDo: ??? */
+ codec = _alutCodecULaw;
+ break;
+ default:
+ _alutSetError(ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE);
+ return NULL;
+ }
+ }
+ else if (magic == 0x64617461) /* "data" */
+ {
+ ALvoid *data;
+
+ if (!found_header)
+ {
+ /* ToDo: A bit wrong to check here, fmt chunk could come later... */
+ _alutSetError(ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA);
+ return NULL;
+ }
+ data = _alutInputStreamRead(stream, chunkLength);
+ if (data == NULL)
+ {
+ return NULL;
+ }
+ return codec(data, chunkLength, numChannels, bitsPerSample, (ALfloat) sampleFrequency);
+ }
+ else
+ {
+ if (!_alutInputStreamSkip(stream, chunkLength))
+ {
+ return NULL;
+ }
+ }
+
+ if ((chunkLength & 1) && !_alutInputStreamEOF(stream) && !_alutInputStreamSkip(stream, 1))
+ {
+ return NULL;
+ }
+ }
+}
+
+static BufferData *loadAUFile(InputStream * stream)
+{
+ Int32BigEndian dataOffset; /* byte offset to data part, minimum 24 */
+ Int32BigEndian len; /* number of bytes in the data part, -1 = not known */
+ Int32BigEndian encoding; /* encoding of the data part, see AUEncoding */
+ Int32BigEndian sampleFrequency; /* number of samples per second */
+ Int32BigEndian numChannels; /* number of interleaved channels */
+ size_t length;
+ Codec *codec;
+ char *data;
+ ALint bitsPerSample;
+
+ if (!_alutInputStreamReadInt32BE(stream, &dataOffset) ||
+ !_alutInputStreamReadInt32BE(stream, &len) ||
+ !_alutInputStreamReadInt32BE(stream, &encoding) ||
+ !_alutInputStreamReadInt32BE(stream, &sampleFrequency) || !_alutInputStreamReadInt32BE(stream, &numChannels))
+ {
+ return AL_FALSE;
+ }
+
+ length = (len == -1) ? (_alutInputStreamGetRemainingLength(stream) - AU_HEADER_SIZE - dataOffset) : (size_t) len;
+
+ if (!(dataOffset >= AU_HEADER_SIZE && length > 0 && sampleFrequency >= 1 && numChannels >= 1))
+ {
+ _alutSetError(ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA);
+ return AL_FALSE;
+ }
+
+ if (!_alutInputStreamSkip(stream, dataOffset - AU_HEADER_SIZE))
+ {
+ return AL_FALSE;
+ }
+
+ switch (encoding)
+ {
+ case AU_ULAW_8:
+ bitsPerSample = 16;
+ codec = _alutCodecULaw;
+ break;
+ case AU_PCM_8:
+ bitsPerSample = 8;
+ codec = _alutCodecPCM8s;
+ break;
+ case AU_PCM_16:
+ bitsPerSample = 16;
+ codec = (endianess() == BigEndian) ? _alutCodecLinear : _alutCodecPCM16;
+ break;
+ case AU_ALAW_8:
+ bitsPerSample = 16;
+ codec = _alutCodecALaw;
+ break;
+ default:
+ _alutSetError(ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE);
+ return AL_FALSE;
+ }
+
+ data = _alutInputStreamRead(stream, length);
+ if (data == NULL)
+ {
+ return NULL;
+ }
+ return codec(data, length, numChannels, bitsPerSample, (ALfloat) sampleFrequency);
+}
+
+static BufferData *loadRawFile(InputStream * stream)
+{
+ size_t length = _alutInputStreamGetRemainingLength(stream);
+ ALvoid *data = _alutInputStreamRead(stream, length);
+
+ if (data == NULL)
+ {
+ return NULL;
+ }
+ /* Guesses */
+ return _alutCodecLinear(data, length, 1, 8, 8000);
+}
+
+static BufferData *loadFile(InputStream * stream)
+{
+ const char *fileName;
+ Int32BigEndian magic;
+
+ /* Raw files have no magic number - so use the fileName extension */
+
+ fileName = _alutInputStreamGetFileName(stream);
+ if (fileName != NULL && hasSuffixIgnoringCase(fileName, ".raw"))
+ {
+ return loadRawFile(stream);
+ }
+
+ /* For other file formats, read the quasi-standard four byte magic number */
+ if (!_alutInputStreamReadInt32BE(stream, &magic))
+ {
+ return AL_FALSE;
+ }
+
+ /* Magic number 'RIFF' == Microsoft '.wav' format */
+ if (magic == 0x52494646)
+ {
+ return loadWavFile(stream);
+ }
+
+ /* Magic number '.snd' == Sun & Next's '.au' format */
+ if (magic == 0x2E736E64)
+ {
+ return loadAUFile(stream);
+ }
+
+ _alutSetError(ALUT_ERROR_UNSUPPORTED_FILE_TYPE);
+ return AL_FALSE;
+}
+
+ALuint _alutCreateBufferFromInputStream(InputStream * stream)
+{
+ BufferData *bufferData;
+ ALuint buffer;
+
+ if (stream == NULL)
+ {
+ return AL_NONE;
+ }
+
+ bufferData = loadFile(stream);
+ _alutInputStreamDestroy(stream);
+ if (bufferData == NULL)
+ {
+ return AL_NONE;
+ }
+
+ buffer = _alutPassBufferData(bufferData);
+ _alutBufferDataDestroy(bufferData);
+
+ return buffer;
+}
+
+ALuint alutCreateBufferFromFile(const char *fileName)
+{
+ InputStream *stream;
+
+ if (!_alutSanityCheck())
+ {
+ return AL_NONE;
+ }
+ stream = _alutInputStreamConstructFromFile(fileName);
+ return _alutCreateBufferFromInputStream(stream);
+}
+
+ALuint alutCreateBufferFromFileImage(const ALvoid * data, ALsizei length)
+{
+ InputStream *stream;
+
+ if (!_alutSanityCheck())
+ {
+ return AL_NONE;
+ }
+ stream = _alutInputStreamConstructFromMemory(data, length);
+ return _alutCreateBufferFromInputStream(stream);
+}
+
+void *_alutLoadMemoryFromInputStream(InputStream * stream, ALenum * format, ALsizei * size, ALfloat * frequency)
+{
+ BufferData *bufferData;
+ ALenum fmt;
+ void *data;
+
+ if (stream == NULL)
+ {
+ return NULL;
+ }
+
+ bufferData = loadFile(stream);
+ if (bufferData == NULL)
+ {
+ _alutInputStreamDestroy(stream);
+ return NULL;
+ }
+ _alutInputStreamDestroy(stream);
+
+ if (!_alutGetFormat(bufferData, &fmt))
+ {
+ _alutBufferDataDestroy(bufferData);
+ return NULL;
+ }
+
+ if (size != NULL)
+ {
+ *size = (ALsizei) _alutBufferDataGetLength(bufferData);
+ }
+
+ if (format != NULL)
+ {
+ *format = fmt;
+ }
+
+ if (frequency != NULL)
+ {
+ *frequency = _alutBufferDataGetSampleFrequency(bufferData);
+ }
+
+ data = _alutBufferDataGetData(bufferData);
+ _alutBufferDataDetachData(bufferData);
+ _alutBufferDataDestroy(bufferData);
+ return data;
+}
+
+ALvoid *alutLoadMemoryFromFile(const char *fileName, ALenum * format, ALsizei * size, ALfloat * frequency)
+{
+ InputStream *stream;
+
+ if (!_alutSanityCheck())
+ {
+ return NULL;
+ }
+ stream = _alutInputStreamConstructFromFile(fileName);
+ return _alutLoadMemoryFromInputStream(stream, format, size, frequency);
+}
+
+ALvoid *alutLoadMemoryFromFileImage(const ALvoid * data, ALsizei length, ALenum * format, ALsizei * size, ALfloat * frequency)
+{
+ InputStream *stream;
+
+ if (!_alutSanityCheck())
+ {
+ return NULL;
+ }
+ stream = _alutInputStreamConstructFromMemory(data, length);
+ return _alutLoadMemoryFromInputStream(stream, format, size, frequency);
+}
+
+/*
+ Yukky backwards compatibility crap.
+*/
+
+void alutLoadWAVFile(ALbyte * fileName, ALenum * format, void **data, ALsizei * size, ALsizei * frequency
+#if !defined(__APPLE__)
+ , ALboolean * loop
+#endif
+ )
+{
+ InputStream *stream;
+ ALfloat freq;
+
+ /* Don't do an _alutSanityCheck () because it's not required in ALUT 0.x.x */
+
+ stream = _alutInputStreamConstructFromFile(fileName);
+ *data = _alutLoadMemoryFromInputStream(stream, format, size, &freq);
+ if (*data == NULL)
+ {
+ return;
+ }
+
+ if (frequency)
+ {
+ *frequency = (ALsizei) freq;
+ }
+
+#if !defined(__APPLE__)
+ if (loop)
+ {
+ *loop = AL_FALSE;
+ }
+#endif
+}
+
+void alutLoadWAVMemory(ALbyte * buffer, ALenum * format, void **data, ALsizei * size, ALsizei * frequency
+#if !defined(__APPLE__)
+ , ALboolean * loop
+#endif
+ )
+{
+ InputStream *stream;
+ ALfloat freq;
+
+ /* Don't do an _alutSanityCheck () because it's not required in ALUT 0.x.x */
+
+ /* ToDo: Can we do something less insane than passing 0x7FFFFFFF? */
+ stream = _alutInputStreamConstructFromMemory(buffer, 0x7FFFFFFF);
+ _alutLoadMemoryFromInputStream(stream, format, size, &freq);
+ if (*data == NULL)
+ {
+ return;
+ }
+
+ if (frequency)
+ {
+ *frequency = (ALsizei) freq;
+ }
+
+#if !defined(__APPLE__)
+ if (loop)
+ {
+ *loop = AL_FALSE;
+ }
+#endif
+}
+
+void alutUnloadWAV(ALenum UNUSED(format), ALvoid * data, ALsizei UNUSED(size), ALsizei UNUSED(frequency))
+{
+ /* Don't do an _alutSanityCheck () because it's not required in ALUT 0.x.x */
+
+ free(data);
+}
+
+const char *alutGetMIMETypes(ALenum loader)
+{
+ if (!_alutSanityCheck())
+ {
+ return NULL;
+ }
+
+ /* We do not distinguish the loaders yet... */
+ switch (loader)
+ {
+ case ALUT_LOADER_BUFFER:
+ return "audio/basic,audio/x-raw,audio/x-wav";
+
+ case ALUT_LOADER_MEMORY:
+ return "audio/basic,audio/x-raw,audio/x-wav";
+
+ default:
+ _alutSetError(ALUT_ERROR_INVALID_ENUM);
+ return NULL;
+ }
+}