From f82173f42304a3f6b9db60279cafe059ce040e93 Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Wed, 3 Oct 2012 19:58:33 -0400 Subject: [PATCH] Add platform independent file stream reading and writing in order to allow us to write out logs. --- Core/include/TexCompTypes.h | 1 + IO/CMakeLists.txt | 2 + IO/include/FileStream.h | 68 ++++++++++++ IO/include/ImageFile.h | 6 +- IO/src/FileStream.cpp | 211 ++++++++++++++++++++++++++++++++++++ IO/src/ImageFile.cpp | 45 +++----- 6 files changed, 304 insertions(+), 29 deletions(-) create mode 100644 IO/include/FileStream.h create mode 100644 IO/src/FileStream.cpp diff --git a/Core/include/TexCompTypes.h b/Core/include/TexCompTypes.h index 7e9843b..9e26fa9 100644 --- a/Core/include/TexCompTypes.h +++ b/Core/include/TexCompTypes.h @@ -39,6 +39,7 @@ typedef uint32_t uint32; typedef uint64_t uint64; typedef uintptr_t int32_ptr; +typedef char CHAR; #endif // _MSC_VER diff --git a/IO/CMakeLists.txt b/IO/CMakeLists.txt index 17063af..7307945 100644 --- a/IO/CMakeLists.txt +++ b/IO/CMakeLists.txt @@ -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 ) diff --git a/IO/include/FileStream.h b/IO/include/FileStream.h new file mode 100644 index 0000000..0d66528 --- /dev/null +++ b/IO/include/FileStream.h @@ -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__ diff --git a/IO/include/ImageFile.h b/IO/include/ImageFile.h index 1aea2c1..485f93e 100644 --- a/IO/include/ImageFile.h +++ b/IO/include/ImageFile.h @@ -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; }; diff --git a/IO/src/FileStream.cpp b/IO/src/FileStream.cpp new file mode 100644 index 0000000..085e6ab --- /dev/null +++ b/IO/src/FileStream.cpp @@ -0,0 +1,211 @@ +#include "FileStream.h" + +#include +#include +#include +#include + +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); + } +} diff --git a/IO/src/ImageFile.cpp b/IO/src/ImageFile.cpp index 087a842..d286991 100644 --- a/IO/src/ImageFile.cpp +++ b/IO/src/ImageFile.cpp @@ -1,14 +1,15 @@ +#include "ImageFile.h" + #include #include #include #include #include -#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 +