#include "alutInternal.h" #include #include #include #include #if HAVE_STAT #if HAVE_UNISTD_H #include #endif #define structStat struct stat #elif HAVE__STAT #define stat(p,b) _stat((p),(b)) #define structStat struct _stat #else #error No stat-like function on this platform #endif struct InputStream_struct { ALboolean isFileStream; char *fileName; size_t remainingLength; union { FILE *fileDescriptor; /* for file streams */ const ALvoid *data; /* for memory streams */ } u; }; /**************************************************************************** * The functions below know the internal InputStream representation. ****************************************************************************/ InputStream * _alutInputStreamConstructFromFile (const char *fileName) { InputStream *stream; structStat statBuf; FILE *fileDescriptor; char *fileNameBuffer; stream = (InputStream *) _alutMalloc (sizeof (InputStream)); if (stream == NULL) { return NULL; } if (stat (fileName, &statBuf)) { _alutSetError (ALUT_ERROR_IO_ERROR); free (stream); return NULL; } fileDescriptor = fopen (fileName, "rb"); if (fileDescriptor == NULL) { _alutSetError (ALUT_ERROR_IO_ERROR); free (stream); return NULL; } fileNameBuffer = (char *) _alutMalloc (strlen (fileName) + 1); if (fileNameBuffer == NULL) { free (stream); return NULL; } stream->isFileStream = AL_TRUE; stream->fileName = strcpy (fileNameBuffer, fileName); stream->remainingLength = statBuf.st_size; stream->u.fileDescriptor = fileDescriptor; return stream; } InputStream * _alutInputStreamConstructFromMemory (const ALvoid *data, size_t length) { InputStream *stream = (InputStream *) _alutMalloc (sizeof (InputStream)); if (stream == NULL) { return NULL; } stream->isFileStream = AL_FALSE; stream->fileName = NULL; stream->remainingLength = length; stream->u.data = data; return stream; } ALboolean _alutInputStreamDestroy (InputStream *stream) { ALboolean status = (stream->isFileStream && fclose (stream->u.fileDescriptor)) ? AL_FALSE : AL_TRUE; if (stream->fileName) { free (stream->fileName); } free (stream); return status; } const char * _alutInputStreamGetFileName (const InputStream *stream) { return stream->fileName; } size_t _alutInputStreamGetRemainingLength (const InputStream *stream) { return stream->remainingLength; } ALboolean _alutInputStreamEOF (InputStream *stream) { if (stream->isFileStream) { int c = fgetc (stream->u.fileDescriptor); if (c != EOF) { ungetc (c, stream->u.fileDescriptor); } return (c == EOF) ? AL_TRUE : AL_FALSE; } else { return (stream->remainingLength == 0) ? AL_TRUE : AL_FALSE; } } static ALboolean streamRead (InputStream *stream, void *ptr, size_t numBytesToRead) { if (stream->isFileStream) { size_t numBytesRead = fread (ptr, 1, numBytesToRead, stream->u.fileDescriptor); if (numBytesToRead != numBytesRead) { _alutSetError (ferror (stream->u.fileDescriptor) ? ALUT_ERROR_IO_ERROR : ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA); return AL_FALSE; } return AL_TRUE; } else { if (stream->remainingLength < numBytesToRead) { _alutSetError (ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA); return AL_FALSE; } memcpy (ptr, stream->u.data, numBytesToRead); stream->u.data = ((const char *) (stream->u.data) + numBytesToRead); return AL_TRUE; } } /**************************************************************************** * The utility functions below do not know the internal InputStream * representation. ****************************************************************************/ ALvoid * _alutInputStreamRead (InputStream *stream, size_t length) { ALvoid *data = _alutMalloc (length); if (data == NULL) { return NULL; } if (!streamRead (stream, data, length)) { free (data); return NULL; } return data; } ALboolean _alutInputStreamSkip (InputStream *stream, size_t numBytesToSkip) { ALboolean status; char *buf; if (numBytesToSkip == 0) { return AL_TRUE; } buf = (char *) _alutMalloc (numBytesToSkip); if (buf == NULL) { return AL_FALSE; } status = streamRead (stream, buf, numBytesToSkip); free (buf); return status; } ALboolean _alutInputStreamReadUInt16LE (InputStream *stream, UInt16LittleEndian *value) { unsigned char buf[2]; if (!streamRead (stream, buf, sizeof (buf))) { return AL_FALSE; } *value = ((UInt16LittleEndian) buf[1] << 8) | ((UInt16LittleEndian) buf[0]); return AL_TRUE; } ALboolean _alutInputStreamReadInt32BE (InputStream *stream, Int32BigEndian *value) { unsigned char buf[4]; if (!streamRead (stream, buf, sizeof (buf))) { return AL_FALSE; } *value = ((Int32BigEndian) buf[0] << 24) | ((Int32BigEndian) buf[1] << 16) | ((Int32BigEndian) buf[2] << 8) | ((Int32BigEndian) buf[3]); return AL_TRUE; } ALboolean _alutInputStreamReadUInt32LE (InputStream *stream, UInt32LittleEndian *value) { unsigned char buf[4]; if (!streamRead (stream, buf, sizeof (buf))) { return AL_FALSE; } *value = ((UInt32LittleEndian) buf[3] << 24) | ((UInt32LittleEndian) buf[2] << 16) | ((UInt32LittleEndian) buf[1] << 8) | ((UInt32LittleEndian) buf[0]); return AL_TRUE; }