blob: 9ddcb0590b1021ab1a41484e1b62f7e1ea3b037e [file] [log] [blame] [edit]
#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;
}