#include "alutInternal.h" #include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #if HAVE_STAT #if HAVE_UNISTD_H #include <unistd.h> #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; }