| #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; |
| } |