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 uint64_t uint64;
typedef uintptr_t int32_ptr; typedef uintptr_t int32_ptr;
typedef char CHAR;
#endif // _MSC_VER #endif // _MSC_VER

View File

@ -2,11 +2,13 @@
SET( SOURCES SET( SOURCES
"src/ImageFile.cpp" "src/ImageFile.cpp"
"src/ImageLoader.cpp" "src/ImageLoader.cpp"
"src/FileStream.cpp"
) )
SET( HEADERS SET( HEADERS
"config/ImageLoader.h.in" "config/ImageLoader.h.in"
"include/ImageFile.h" "include/ImageFile.h"
"include/FileStream.h"
) )
FIND_PACKAGE( PNG ) 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_ #ifndef _IMAGE_FILE_H_
#define _IMAGE_FILE_H_ #define _IMAGE_FILE_H_
#include "TexCompTypes.h"
#include "ImageFileFormat.h" #include "ImageFileFormat.h"
// Forward declare // Forward declare
class Image; class Image;
class CompressedImage; class CompressedImage;
struct SCompressionSettings;
// Class definition // Class definition
class ImageFile { class ImageFile {
@ -30,8 +32,8 @@ public:
const EImageFileFormat m_FileFormat; const EImageFileFormat m_FileFormat;
static unsigned char *ReadFileData(const char *filename); static unsigned char *ReadFileData(const CHAR *filename);
static EImageFileFormat DetectFileFormat(const char *filename); static EImageFileFormat DetectFileFormat(const CHAR *filename);
Image *LoadImage(const unsigned char *rawImageData) const; 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 <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <limits.h> #include <limits.h>
#include <assert.h> #include <assert.h>
#include "TexComp.h"
#include "ImageFile.h"
#include "ImageLoader.h" #include "ImageLoader.h"
#include "CompressedImage.h" #include "CompressedImage.h"
#include "Image.h" #include "Image.h"
#include "FileStream.h"
#ifdef PNG_FOUND #ifdef PNG_FOUND
# include "ImageLoaderPNG.h" # 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); 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_FileFormat( DetectFileFormat(filename) )
, m_Image(NULL) , 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_FileFormat(format)
, m_Image(NULL) , m_Image(NULL)
{ {
@ -102,7 +103,7 @@ Image *ImageFile::LoadImage(const unsigned char *rawImageData) const {
return i; return i;
} }
EImageFileFormat ImageFile::DetectFileFormat(const char *filename) { EImageFileFormat ImageFile::DetectFileFormat(const CHAR *filename) {
int len = strlen(filename); int len = strlen(filename);
if(len >= 256) { if(len >= 256) {
@ -122,7 +123,7 @@ EImageFileFormat ImageFile::DetectFileFormat(const char *filename) {
// consume the last character... // consume the last character...
dotPos++; dotPos++;
const char *ext = &filename[dotPos]; const CHAR *ext = &filename[dotPos];
if(strcmp(ext, ".png") == 0) { if(strcmp(ext, ".png") == 0) {
return eFileFormat_PNG; return eFileFormat_PNG;
@ -130,43 +131,33 @@ EImageFileFormat ImageFile::DetectFileFormat(const char *filename) {
return kNumImageFileFormats; return kNumImageFileFormats;
} }
#ifdef _MSC_VER unsigned char *ImageFile::ReadFileData(const CHAR *filename) {
unsigned char *ImageFile::ReadFileData(const char *filename) { FileStream fstr (filename, eFileMode_ReadBinary);
//!FIXME! - Actually, implement me if(fstr.Tell() < 0) {
assert(!"Not implemented!");
}
#else
unsigned char *ImageFile::ReadFileData(const char *filename) {
FILE *fp = fopen(filename, "rb");
if(!fp) {
fprintf(stderr, "Error opening file for reading: %s\n", filename); fprintf(stderr, "Error opening file for reading: %s\n", filename);
return 0; return 0;
} }
// Check filesize // Figure out the filesize.
long fileSize = 0; fstr.Seek(0, FileStream::eSeekPosition_End);
fseek(fp, 0, SEEK_END); uint64 fileSize = fstr.Tell();
fileSize = ftell(fp);
// Allocate data for file contents // Allocate data for file contents
unsigned char *rawData = new unsigned char[fileSize]; unsigned char *rawData = new unsigned char[fileSize];
// Return stream to beginning of file // Return stream to beginning of file
fseek(fp, 0, SEEK_SET); fstr.Seek(0, FileStream::eSeekPosition_Beginning);
assert(ftell(fp) == 0); assert(fstr.Tell() == 0);
// Read all of the data // Read all of the data
size_t bytesRead = fread(rawData, 1, fileSize, fp); int32 bytesRead = fstr.Read(rawData, fileSize);
if(bytesRead != fileSize) { if(bytesRead != fileSize) {
assert(!"We didn't read as much data as we thought we had!"); assert(!"We didn't read as much data as we thought we had!");
fprintf(stderr, "Internal error: Incorrect file size assumption\n"); fprintf(stderr, "Internal error: Incorrect file size assumption\n");
return 0; return 0;
} }
// Close the file pointer
fclose(fp);
// Return the data.. // Return the data..
return rawData; return rawData;
} }
#endif