Mercurial > projects > hoofbaby
diff deps/Platinum/ThirdParty/Neptune/Source/System/StdC/NptStdcFile.cpp @ 0:3425707ddbf6
Initial import (hopefully this mercurial stuff works...)
author | fraserofthenight |
---|---|
date | Mon, 06 Jul 2009 08:06:28 -0700 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/deps/Platinum/ThirdParty/Neptune/Source/System/StdC/NptStdcFile.cpp Mon Jul 06 08:06:28 2009 -0700 @@ -0,0 +1,560 @@ +/***************************************************************** +| +| Neptune - Files :: Standard C Implementation +| +| (c) 2001-2008 Gilles Boccon-Gibod +| Author: Gilles Boccon-Gibod (bok@bok.net) +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#define _LARGEFILE_SOURCE +#define _LARGEFILE_SOURCE64 +#define _FILE_OFFSET_BITS 64 + +#include <stdio.h> +#if !defined(_WIN32_WCE) +#include <string.h> +#include <sys/stat.h> +#include <errno.h> +#else +#include <stdio.h> +#define errno GetLastError() +#endif + +#include "NptConfig.h" +#include "NptUtils.h" +#include "NptFile.h" +#include "NptThreads.h" +#include "NptInterfaces.h" +#include "NptStrings.h" +#include "NptLogging.h" + +#if defined(NPT_CONFIG_HAVE_SHARE_H) +#include <share.h> +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1500 +extern "C" { + __int64 __cdecl _ftelli64(FILE *); + int __cdecl _fseeki64(FILE *, __int64, int); +} +#endif + +#if defined(_WIN32) +extern FILE *NPT_fsopen_utf8(const char* path, const char* mode, int sh_flags); +extern FILE *NPT_fopen_utf8(const char* path, const char* mode); +#define fopen NPT_fopen_utf8 +#define fopen_s NPT_fopen_s_utf8 +#define _fsopen NPT_fsopen_utf8 +#endif + + +/*---------------------------------------------------------------------- +| logging ++---------------------------------------------------------------------*/ +NPT_SET_LOCAL_LOGGER("neptune.stdc.file") + +/*---------------------------------------------------------------------- +| compatibility wrappers ++---------------------------------------------------------------------*/ +#if !defined(NPT_CONFIG_HAVE_FOPEN_S) +static int fopen_s(FILE** file, + const char* filename, + const char* mode) +{ + *file = fopen(filename, mode); + +#if defined(_WIN32_WCE) + if (*file == NULL) return ENOENT; +#else + if (*file == NULL) return errno; +#endif + return 0; +} +#endif // defined(NPT_CONFIG_HAVE_FOPEN_S + +/*---------------------------------------------------------------------- +| MapErrno ++---------------------------------------------------------------------*/ +static NPT_Result +MapErrno(int err) { + switch (err) { + case EACCES: return NPT_ERROR_PERMISSION_DENIED; + case EPERM: return NPT_ERROR_PERMISSION_DENIED; + case ENOENT: return NPT_ERROR_NO_SUCH_FILE; +#if defined(ENAMETOOLONG) + case ENAMETOOLONG: return NPT_ERROR_INVALID_PARAMETERS; +#endif + case EBUSY: return NPT_ERROR_FILE_BUSY; + case EROFS: return NPT_ERROR_FILE_NOT_WRITABLE; + case ENOTDIR: return NPT_ERROR_FILE_NOT_DIRECTORY; + default: return NPT_ERROR_ERRNO(err); + } +} + +/*---------------------------------------------------------------------- +| NPT_StdcFileWrapper ++---------------------------------------------------------------------*/ +class NPT_StdcFileWrapper +{ +public: + // constructors and destructor + NPT_StdcFileWrapper(FILE* file) : m_File(file) {} + ~NPT_StdcFileWrapper() { + if (m_File != NULL && + m_File != stdin && + m_File != stdout && + m_File != stderr) { + fclose(m_File); + } + } + + // methods + FILE* GetFile() { return m_File; } + +private: + // members + FILE* m_File; +}; + +typedef NPT_Reference<NPT_StdcFileWrapper> NPT_StdcFileReference; + +/*---------------------------------------------------------------------- +| NPT_StdcFileStream ++---------------------------------------------------------------------*/ +class NPT_StdcFileStream +{ +public: + // constructors and destructor + NPT_StdcFileStream(NPT_StdcFileReference file) : + m_FileReference(file) {} + + // NPT_FileInterface methods + NPT_Result Seek(NPT_Position offset); + NPT_Result Tell(NPT_Position& offset); + NPT_Result Flush(); + +protected: + // constructors and destructors + virtual ~NPT_StdcFileStream() {} + + // members + NPT_StdcFileReference m_FileReference; +}; + +/*---------------------------------------------------------------------- +| NPT_StdcFileStream::Seek ++---------------------------------------------------------------------*/ +NPT_Result +NPT_StdcFileStream::Seek(NPT_Position offset) +{ + size_t result; + + result = NPT_fseek(m_FileReference->GetFile(), offset, SEEK_SET); + if (result == 0) { + return NPT_SUCCESS; + } else { + return NPT_FAILURE; + } +} + +/*---------------------------------------------------------------------- +| NPT_StdcFileStream::Tell ++---------------------------------------------------------------------*/ +NPT_Result +NPT_StdcFileStream::Tell(NPT_Position& offset) +{ + offset = 0; + + NPT_Int64 pos = NPT_ftell(m_FileReference->GetFile()); + if (pos <=0) return NPT_FAILURE; + + offset = pos; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_StdcFileStream::Flush ++---------------------------------------------------------------------*/ +NPT_Result +NPT_StdcFileStream::Flush() +{ + fflush(m_FileReference->GetFile()); + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_StdcFileInputStream ++---------------------------------------------------------------------*/ +class NPT_StdcFileInputStream : public NPT_InputStream, + private NPT_StdcFileStream + +{ +public: + // constructors and destructor + NPT_StdcFileInputStream(NPT_StdcFileReference& file, NPT_LargeSize size) : + NPT_StdcFileStream(file), m_Size(size) {} + + // NPT_InputStream methods + NPT_Result Read(void* buffer, + NPT_Size bytes_to_read, + NPT_Size* bytes_read); + NPT_Result Seek(NPT_Position offset) { + return NPT_StdcFileStream::Seek(offset); + } + NPT_Result Tell(NPT_Position& offset) { + return NPT_StdcFileStream::Tell(offset); + } + NPT_Result GetSize(NPT_LargeSize& size); + NPT_Result GetAvailable(NPT_LargeSize& available); + +private: + // members + NPT_LargeSize m_Size; +}; + +/*---------------------------------------------------------------------- +| NPT_StdcFileInputStream::Read ++---------------------------------------------------------------------*/ +NPT_Result +NPT_StdcFileInputStream::Read(void* buffer, + NPT_Size bytes_to_read, + NPT_Size* bytes_read) +{ + size_t nb_read; + + // check the parameters + if (buffer == NULL) { + return NPT_ERROR_INVALID_PARAMETERS; + } + + // read from the file + nb_read = fread(buffer, 1, bytes_to_read, m_FileReference->GetFile()); + if (nb_read > 0) { + if (bytes_read) *bytes_read = (NPT_Size)nb_read; + return NPT_SUCCESS; + } else if (feof(m_FileReference->GetFile())) { + if (bytes_read) *bytes_read = 0; + return NPT_ERROR_EOS; + } else { + if (bytes_read) *bytes_read = 0; + return NPT_ERROR_READ_FAILED; + } +} + +/*---------------------------------------------------------------------- +| NPT_StdcFileInputStream::GetSize ++---------------------------------------------------------------------*/ +NPT_Result +NPT_StdcFileInputStream::GetSize(NPT_LargeSize& size) +{ + // keep track of where we are + NPT_Position offset = NPT_ftell(m_FileReference->GetFile()); + + // seek to the end to get the size + NPT_fseek(m_FileReference->GetFile(), 0, SEEK_END); + size = NPT_ftell(m_FileReference->GetFile()); + + // seek back to where we were + NPT_fseek(m_FileReference->GetFile(), offset, SEEK_SET); + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_StdcFileInputStream::GetAvailable ++---------------------------------------------------------------------*/ +NPT_Result +NPT_StdcFileInputStream::GetAvailable(NPT_LargeSize& available) +{ + NPT_LargeSize size; + GetSize(size); + + NPT_Int64 offset = NPT_ftell(m_FileReference->GetFile()); + if (offset >= 0 && (NPT_LargeSize)offset <= size) { + available = size - offset; + return NPT_SUCCESS; + } else { + available = 0; + return NPT_FAILURE; + } +} + +/*---------------------------------------------------------------------- +| NPT_StdcFileOutputStream ++---------------------------------------------------------------------*/ +class NPT_StdcFileOutputStream : public NPT_OutputStream, + private NPT_StdcFileStream +{ +public: + // constructors and destructor + NPT_StdcFileOutputStream(NPT_StdcFileReference& file) : + NPT_StdcFileStream(file) {} + + // NPT_InputStream methods + NPT_Result Write(const void* buffer, + NPT_Size bytes_to_write, + NPT_Size* bytes_written); + NPT_Result Seek(NPT_Position offset) { + return NPT_StdcFileStream::Seek(offset); + } + NPT_Result Tell(NPT_Position& offset) { + return NPT_StdcFileStream::Tell(offset); + } + NPT_Result Flush() { + return NPT_StdcFileStream::Flush(); + } +}; + +/*---------------------------------------------------------------------- +| NPT_StdcFileOutputStream::Write ++---------------------------------------------------------------------*/ +NPT_Result +NPT_StdcFileOutputStream::Write(const void* buffer, + NPT_Size bytes_to_write, + NPT_Size* bytes_written) +{ + size_t nb_written; + + nb_written = fwrite(buffer, 1, bytes_to_write, m_FileReference->GetFile()); + + if (nb_written > 0) { + if (bytes_written) *bytes_written = (NPT_Size)nb_written; + return NPT_SUCCESS; + } else { + if (bytes_written) *bytes_written = 0; + return NPT_ERROR_WRITE_FAILED; + } +} + +/*---------------------------------------------------------------------- +| NPT_StdcFile ++---------------------------------------------------------------------*/ +class NPT_StdcFile: public NPT_FileInterface +{ +public: + // constructors and destructor + NPT_StdcFile(NPT_File& delegator); + ~NPT_StdcFile(); + + // NPT_FileInterface methods + NPT_Result Open(OpenMode mode); + NPT_Result Close(); + NPT_Result GetSize(NPT_LargeSize& size); + NPT_Result GetInputStream(NPT_InputStreamReference& stream); + NPT_Result GetOutputStream(NPT_OutputStreamReference& stream); + +private: + // members + NPT_File& m_Delegator; + OpenMode m_Mode; + NPT_StdcFileReference m_FileReference; +}; + +/*---------------------------------------------------------------------- +| NPT_StdcFile::NPT_StdcFile ++---------------------------------------------------------------------*/ +NPT_StdcFile::NPT_StdcFile(NPT_File& delegator) : + m_Delegator(delegator), + m_Mode(0) +{ +} + +/*---------------------------------------------------------------------- +| NPT_StdcFile::~NPT_StdcFile ++---------------------------------------------------------------------*/ +NPT_StdcFile::~NPT_StdcFile() +{ + Close(); +} + +/*---------------------------------------------------------------------- +| NPT_StdcFile::Open ++---------------------------------------------------------------------*/ +NPT_Result +NPT_StdcFile::Open(NPT_File::OpenMode mode) +{ + FILE* file = NULL; + + // check if we're already open + if (!m_FileReference.IsNull()) { + return NPT_ERROR_FILE_ALREADY_OPEN; + } + + // store the mode + m_Mode = mode; + + // check for special names + const char* name = (const char*)m_Delegator.GetPath(); + if (NPT_StringsEqual(name, NPT_FILE_STANDARD_INPUT)) { + file = stdin; + } else if (NPT_StringsEqual(name, NPT_FILE_STANDARD_OUTPUT)) { + file = stdout; + } else if (NPT_StringsEqual(name, NPT_FILE_STANDARD_ERROR)) { + file = stderr; + } else { + // compute mode + const char* fmode = ""; + if (mode & NPT_FILE_OPEN_MODE_WRITE) { + if (mode & NPT_FILE_OPEN_MODE_CREATE) { + if (mode & NPT_FILE_OPEN_MODE_TRUNCATE) { + /* write, read, create, truncate */ + fmode = "w+b"; + } else { + /* write, read, create */ + fmode = "a+b"; + } + } else { + if (mode & NPT_FILE_OPEN_MODE_TRUNCATE) { + /* write, read, truncate */ + fmode = "w+b"; + } else { + /* write, read */ + fmode = "r+b"; + } + } + } else { + /* read only */ + fmode = "rb"; + } + + // open the file +#if defined(NPT_CONFIG_HAVE_FSOPEN) + file = _fsopen(name, fmode, _SH_DENYWR); + int open_result = file == NULL ? ENOENT : 0; +#else + int open_result = fopen_s(&file, name, fmode); +#endif + + // test the result of the open + if (open_result != 0) return MapErrno(errno); + } + + // unbuffer the file if needed + if ((mode & NPT_FILE_OPEN_MODE_UNBUFFERED) && file != NULL) { +#if !defined(_WIN32_WCE) + setvbuf(file, NULL, _IONBF, 0); +#endif + } + + // create a reference to the FILE object + m_FileReference = new NPT_StdcFileWrapper(file); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_StdcFile::Close ++---------------------------------------------------------------------*/ +NPT_Result +NPT_StdcFile::Close() +{ + // release the file reference + m_FileReference = NULL; + + // reset the mode + m_Mode = 0; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_StdcFile::GetSize ++---------------------------------------------------------------------*/ +NPT_Result +NPT_StdcFile::GetSize(NPT_LargeSize& size) +{ + // default value + size = 0; + + // check that the file is open + if (m_FileReference.IsNull()) return NPT_ERROR_FILE_NOT_OPEN; + + // get the size from the info (call GetInfo() in case it has not + // yet been called) + NPT_FileInfo info; + NPT_CHECK_FATAL(m_Delegator.GetInfo(info)); + size = info.m_Size; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_StdcFile::GetInputStream ++---------------------------------------------------------------------*/ +NPT_Result +NPT_StdcFile::GetInputStream(NPT_InputStreamReference& stream) +{ + // default value + stream = NULL; + + // check that the file is open + if (m_FileReference.IsNull()) return NPT_ERROR_FILE_NOT_OPEN; + + // check that the mode is compatible + if (!(m_Mode & NPT_FILE_OPEN_MODE_READ)) { + return NPT_ERROR_FILE_NOT_READABLE; + } + + // create a stream + NPT_LargeSize size = 0; + GetSize(size); + stream = new NPT_StdcFileInputStream(m_FileReference, size); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_StdcFile::GetOutputStream ++---------------------------------------------------------------------*/ +NPT_Result +NPT_StdcFile::GetOutputStream(NPT_OutputStreamReference& stream) +{ + // default value + stream = NULL; + + // check that the file is open + if (m_FileReference.IsNull()) return NPT_ERROR_FILE_NOT_OPEN; + + // check that the mode is compatible + if (!(m_Mode & NPT_FILE_OPEN_MODE_WRITE)) { + return NPT_ERROR_FILE_NOT_WRITABLE; + } + + // create a stream + stream = new NPT_StdcFileOutputStream(m_FileReference); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_File::NPT_File ++---------------------------------------------------------------------*/ +NPT_File::NPT_File(const char* path) : + m_Path(path) +{ + m_Delegate = new NPT_StdcFile(*this); + + if (NPT_StringsEqual(path, NPT_FILE_STANDARD_INPUT) || + NPT_StringsEqual(path, NPT_FILE_STANDARD_OUTPUT) || + NPT_StringsEqual(path, NPT_FILE_STANDARD_ERROR)) { + m_Info.m_Type = NPT_FileInfo::FILE_TYPE_SPECIAL; + } +} + +/*---------------------------------------------------------------------- +| NPT_File::operator= ++---------------------------------------------------------------------*/ +NPT_File& +NPT_File::operator=(const NPT_File& file) +{ + if (this != &file) { + delete m_Delegate; + m_Path = file.m_Path; + m_Info = file.m_Info; + m_Delegate = new NPT_StdcFile(*this); + } + return *this; +} +