Add platform independent file stream reading and writing in order to allow us to write out logs.

This commit is contained in:
Pavel Krajcevski 2012-10-03 19:58:33 -04:00
parent 6c723ca289
commit f82173f423
6 changed files with 304 additions and 29 deletions

View File

@ -39,6 +39,7 @@ typedef uint32_t uint32;
typedef uint64_t uint64;
typedef uintptr_t int32_ptr;
typedef char CHAR;
#endif // _MSC_VER

View File

@ -2,11 +2,13 @@
SET( SOURCES
"src/ImageFile.cpp"
"src/ImageLoader.cpp"
"src/FileStream.cpp"
)
SET( HEADERS
"config/ImageLoader.h.in"
"include/ImageFile.h"
"include/FileStream.h"
)
FIND_PACKAGE( PNG )

68
IO/include/FileStream.h Normal file
View File

@ -0,0 +1,68 @@
#ifndef __FILE_STREAM_H__
#define __FILE_STREAM_H__
#include "TexCompTypes.h"
enum EFileMode {
eFileMode_Read,
eFileMode_ReadBinary,
eFileMode_Write,
eFileMode_WriteBinary,
eFileMode_WriteAppend,
eFileMode_WriteBinaryAppend,
kNumFileModes
};
class FileStreamImpl;
class FileStream {
public:
FileStream(const CHAR *filename, EFileMode mode);
FileStream(const FileStream &);
FileStream &operator=(const FileStream &);
~FileStream();
// Read the contents of the file into the specified buffer. This
// function returns the number of bytes read on success. It returns
// -2 if the file was opened with an incompatible mode and -1 on
// platform specific error.
int32 Read(uint8 *buf, uint32 bufSz);
// Write the contents of buf to the filestream. This function returns
// the number of bytes written on success. It returns -2 if the file
// was opened with an incompatible mode and -1 on platform specific
// error.
int32 Write(const uint8 *buf, uint32 bufSz);
// Returns where in the filestream we are. Returns -1 on error.
int64 Tell();
enum ESeekPosition {
eSeekPosition_Beginning,
eSeekPosition_Current,
eSeekPosition_End
};
// Repositions the stream to the specified offset away from the
// position in the stream. This function will always fail if the
// file mode is append. Otherwise, it returns true on success.
bool Seek(uint32 offset, ESeekPosition pos);
// Flush the data of the stream. This function is platform specific.
void Flush();
const CHAR *GetFilename() const { return m_Filename; }
private:
EFileMode m_Mode;
// Platform specific implementation
FileStreamImpl *m_Impl;
static const uint32 kMaxFilenameSz = 256;
CHAR m_Filename[kMaxFilenameSz];
};
#endif // __FILE_STREAM_H__

View File

@ -1,11 +1,13 @@
#ifndef _IMAGE_FILE_H_
#define _IMAGE_FILE_H_
#include "TexCompTypes.h"
#include "ImageFileFormat.h"
// Forward declare
class Image;
class CompressedImage;
struct SCompressionSettings;
// Class definition
class ImageFile {
@ -30,8 +32,8 @@ public:
const EImageFileFormat m_FileFormat;
static unsigned char *ReadFileData(const char *filename);
static EImageFileFormat DetectFileFormat(const char *filename);
static unsigned char *ReadFileData(const CHAR *filename);
static EImageFileFormat DetectFileFormat(const CHAR *filename);
Image *LoadImage(const unsigned char *rawImageData) const;
};

211
IO/src/FileStream.cpp Normal file
View File

@ -0,0 +1,211 @@
#include "FileStream.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
class FileStreamImpl {
private:
// Track the number of references to this filestream so
// that we know whether or not we need to close it when
// the object gets destroyed.
uint32 m_ReferenceCount;
FILE *m_FilePtr;
public:
FileStreamImpl(const CHAR *filename, EFileMode mode)
: m_ReferenceCount(1)
{
const char *modeStr = "r";
switch(mode) {
default:
case eFileMode_Read:
// Do nothing.
break;
case eFileMode_ReadBinary:
modeStr = "rb";
break;
case eFileMode_Write:
modeStr = "w";
break;
case eFileMode_WriteBinary:
modeStr = "wb";
break;
case eFileMode_WriteAppend:
modeStr = "a";
break;
case eFileMode_WriteBinaryAppend:
modeStr = "ab";
break;
}
m_FilePtr = fopen(filename, modeStr);
}
~FileStreamImpl() {
fclose(m_FilePtr);
}
void IncreaseReferenceCount() { m_ReferenceCount++; }
void DecreaseReferenceCount() { m_ReferenceCount--; }
uint32 GetReferenceCount() { return m_ReferenceCount; }
FILE *GetFilePtr() const { return m_FilePtr; }
};
FileStream::FileStream(const CHAR *filename, EFileMode mode)
: m_Impl(new FileStreamImpl(filename, mode))
, m_Mode(mode)
{
strncpy(m_Filename, filename, kMaxFilenameSz);
m_Filename[kMaxFilenameSz - 1] = '\0';
}
FileStream::FileStream(const FileStream &other)
: m_Impl(other.m_Impl)
, m_Mode(other.m_Mode)
{
m_Impl->IncreaseReferenceCount();
strncpy(m_Filename, other.m_Filename, kMaxFilenameSz);
}
FileStream &FileStream::operator=(const FileStream &other) {
// We no longer reference this implementation.
m_Impl->DecreaseReferenceCount();
// If we're the last ones to reference it, then it should be destroyed.
if(m_Impl->GetReferenceCount() <= 0) {
assert(m_Impl->GetReferenceCount() == 0);
delete m_Impl;
m_Impl = 0;
}
m_Impl = other.m_Impl;
m_Impl->IncreaseReferenceCount();
m_Mode = other.m_Mode;
strncpy(m_Filename, other.m_Filename, kMaxFilenameSz);
}
FileStream::~FileStream() {
// We no longer reference this implementation.
m_Impl->DecreaseReferenceCount();
// If we're the last ones to reference it, then it should be destroyed.
if(m_Impl->GetReferenceCount() <= 0) {
assert(m_Impl->GetReferenceCount() == 0);
delete m_Impl;
m_Impl = 0;
}
}
int32 FileStream::Read(uint8 *buf, uint32 bufSz) {
if(
m_Mode == eFileMode_Write ||
m_Mode == eFileMode_WriteBinary ||
m_Mode == eFileMode_WriteAppend ||
m_Mode == eFileMode_WriteBinaryAppend
) {
fprintf(stderr, "Cannot read from file '%s': File opened for reading.", m_Filename);
return -2;
}
FILE *fp = m_Impl->GetFilePtr();
if(NULL == fp)
return -1;
uint32 amtRead = fread(buf, 1, bufSz, fp);
if(amtRead != bufSz && !feof(fp)) {
fprintf(stderr, "Error reading from file '%s'.", m_Filename);
return -1;
}
return amtRead;
}
int32 FileStream::Write(const uint8 *buf, uint32 bufSz) {
if(
m_Mode == eFileMode_Read ||
m_Mode == eFileMode_ReadBinary
) {
fprintf(stderr, "Cannot write to file '%s': File opened for writing.", m_Filename);
return -2;
}
FILE *fp = m_Impl->GetFilePtr();
if(NULL == fp)
return -1;
uint32 amtWritten = fwrite(buf, 1, bufSz, fp);
if(amtWritten != bufSz) {
fprintf(stderr, "Error writing to file '%s'.", m_Filename);
return -1;
}
return amtWritten;
}
int64 FileStream::Tell() {
FILE *fp = m_Impl->GetFilePtr();
if(NULL == fp) {
return -1;
}
long int ret = ftell(fp);
if(-1L == ret) {
perror("Error opening file");
return -1;
}
return ret;
}
bool FileStream::Seek(uint32 offset, ESeekPosition pos) {
// We cannot seek in append mode.
if(m_Mode == eFileMode_WriteAppend || m_Mode == eFileMode_WriteBinaryAppend)
return false;
FILE *fp = m_Impl->GetFilePtr();
if(NULL == fp) return false;
int origin = SEEK_SET;
switch(pos) {
default:
case eSeekPosition_Beginning:
// Do nothing
break;
case eSeekPosition_Current:
origin = SEEK_CUR;
break;
case eSeekPosition_End:
origin = SEEK_END;
break;
}
if(fseek(fp, offset, origin))
return false;
return true;
}
void FileStream::Flush() {
FILE *fp = m_Impl->GetFilePtr();
if(NULL != fp) {
fflush(fp);
}
}

View File

@ -1,14 +1,15 @@
#include "ImageFile.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <assert.h>
#include "TexComp.h"
#include "ImageFile.h"
#include "ImageLoader.h"
#include "CompressedImage.h"
#include "Image.h"
#include "FileStream.h"
#ifdef PNG_FOUND
# include "ImageLoaderPNG.h"
@ -20,7 +21,7 @@
//
//////////////////////////////////////////////////////////////////////////////////////////
static inline void ReportError(const char *msg) {
static inline void ReportError(const CHAR *msg) {
fprintf(stderr, "ImageFile -- %s\n", msg);
}
@ -40,7 +41,7 @@ static inline T min(const T &a, const T &b) {
//
//////////////////////////////////////////////////////////////////////////////////////////
ImageFile::ImageFile(const char *filename)
ImageFile::ImageFile(const CHAR *filename)
: m_FileFormat( DetectFileFormat(filename) )
, m_Image(NULL)
{
@ -51,7 +52,7 @@ ImageFile::ImageFile(const char *filename)
}
}
ImageFile::ImageFile(const char *filename, EImageFileFormat format)
ImageFile::ImageFile(const CHAR *filename, EImageFileFormat format)
: m_FileFormat(format)
, m_Image(NULL)
{
@ -102,7 +103,7 @@ Image *ImageFile::LoadImage(const unsigned char *rawImageData) const {
return i;
}
EImageFileFormat ImageFile::DetectFileFormat(const char *filename) {
EImageFileFormat ImageFile::DetectFileFormat(const CHAR *filename) {
int len = strlen(filename);
if(len >= 256) {
@ -122,7 +123,7 @@ EImageFileFormat ImageFile::DetectFileFormat(const char *filename) {
// consume the last character...
dotPos++;
const char *ext = &filename[dotPos];
const CHAR *ext = &filename[dotPos];
if(strcmp(ext, ".png") == 0) {
return eFileFormat_PNG;
@ -130,43 +131,33 @@ EImageFileFormat ImageFile::DetectFileFormat(const char *filename) {
return kNumImageFileFormats;
}
#ifdef _MSC_VER
unsigned char *ImageFile::ReadFileData(const char *filename) {
//!FIXME! - Actually, implement me
assert(!"Not implemented!");
}
#else
unsigned char *ImageFile::ReadFileData(const char *filename) {
FILE *fp = fopen(filename, "rb");
if(!fp) {
unsigned char *ImageFile::ReadFileData(const CHAR *filename) {
FileStream fstr (filename, eFileMode_ReadBinary);
if(fstr.Tell() < 0) {
fprintf(stderr, "Error opening file for reading: %s\n", filename);
return 0;
}
// Check filesize
long fileSize = 0;
fseek(fp, 0, SEEK_END);
fileSize = ftell(fp);
// Figure out the filesize.
fstr.Seek(0, FileStream::eSeekPosition_End);
uint64 fileSize = fstr.Tell();
// Allocate data for file contents
unsigned char *rawData = new unsigned char[fileSize];
// Return stream to beginning of file
fseek(fp, 0, SEEK_SET);
assert(ftell(fp) == 0);
fstr.Seek(0, FileStream::eSeekPosition_Beginning);
assert(fstr.Tell() == 0);
// Read all of the data
size_t bytesRead = fread(rawData, 1, fileSize, fp);
int32 bytesRead = fstr.Read(rawData, fileSize);
if(bytesRead != fileSize) {
assert(!"We didn't read as much data as we thought we had!");
fprintf(stderr, "Internal error: Incorrect file size assumption\n");
return 0;
}
// Close the file pointer
fclose(fp);
// Return the data..
return rawData;
}
#endif