1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00
vcmi/lib/filesystem/FileStream.cpp

176 lines
4.1 KiB
C++
Raw Normal View History

/*
* FileStream.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
2016-01-09 22:24:20 +02:00
#include "StdInc.h"
#include "FileStream.h"
2016-01-19 12:56:03 +02:00
#ifdef USE_SYSTEM_MINIZIP
#include <minizip/unzip.h>
#include <minizip/ioapi.h>
2016-01-19 12:56:03 +02:00
#else
2016-01-09 22:24:20 +02:00
#include "../minizip/unzip.h"
#include "../minizip/ioapi.h"
#endif
#include <cstdio>
2023-02-24 11:58:23 +02:00
#define GETFILE static_cast<std::FILE*>(filePtr)
2016-01-19 12:56:03 +02:00
#ifdef VCMI_WINDOWS
2016-01-09 22:24:20 +02:00
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <cwchar>
#define CHAR_LITERAL(s) L##s
using CharType = wchar_t;
#else
#define CHAR_LITERAL(s) s
using CharType = char;
#endif
namespace
{
2016-01-18 22:30:06 +02:00
inline FILE* do_open(const CharType* name, const CharType* mode)
{
2016-01-19 12:56:03 +02:00
#ifdef VCMI_WINDOWS
2016-01-18 22:30:06 +02:00
return _wfopen(name, mode);
#else
return std::fopen(name, mode);
#endif
}
2016-01-09 22:24:20 +02:00
voidpf ZCALLBACK MinizipOpenFunc(voidpf opaque, const void* filename, int mode)
{
2023-02-24 11:58:23 +02:00
const CharType* mode_fopen = [mode]() -> const CharType*
{
2016-01-09 22:24:20 +02:00
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ)
return CHAR_LITERAL("rb");
else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
return CHAR_LITERAL("r+b");
else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
return CHAR_LITERAL("wb");
return nullptr;
2023-02-24 11:58:23 +02:00
}();
2016-01-09 22:24:20 +02:00
2023-02-24 11:58:23 +02:00
if (filename != nullptr && mode_fopen != nullptr)
return do_open(static_cast<const CharType*>(filename), mode_fopen);
2016-01-09 22:24:20 +02:00
else
return nullptr;
}
} // namespace
2016-01-09 22:24:20 +02:00
template struct boost::iostreams::stream<VCMI_LIB_WRAP_NAMESPACE(FileBuf)>;
VCMI_LIB_NAMESPACE_BEGIN
2016-01-09 22:24:20 +02:00
zlib_filefunc64_def* FileStream::GetMinizipFilefunc()
{
static zlib_filefunc64_def MinizipFilefunc;
static bool initialized = false;
if (!initialized)
{
fill_fopen64_filefunc(&MinizipFilefunc);
2016-01-09 22:24:20 +02:00
MinizipFilefunc.zopen64_file = &MinizipOpenFunc;
initialized = true;
}
return &MinizipFilefunc;
}
/*static*/
bool FileStream::createFile(const boost::filesystem::path& filename)
2016-01-09 22:24:20 +02:00
{
2016-01-18 22:30:06 +02:00
FILE* f = do_open(filename.c_str(), CHAR_LITERAL("wb"));
2016-01-09 22:24:20 +02:00
bool result = (f != nullptr);
2016-11-26 20:45:58 +02:00
if(result)
fclose(f);
2016-01-09 22:24:20 +02:00
return result;
}
FileBuf::FileBuf(const boost::filesystem::path& filename, std::ios_base::openmode mode)
{
2016-01-18 22:30:06 +02:00
auto openmode = [mode]() -> std::basic_string<CharType>
2016-01-09 22:24:20 +02:00
{
using namespace std;
switch (mode & (~ios_base::ate & ~ios_base::binary))
{
case (ios_base::in):
2016-01-18 22:30:06 +02:00
return CHAR_LITERAL("r");
2016-01-09 22:24:20 +02:00
case (ios_base::out):
case (ios_base::out | ios_base::trunc):
2016-01-18 22:30:06 +02:00
return CHAR_LITERAL("w");
2016-01-09 22:24:20 +02:00
case (ios_base::app):
case (ios_base::out | ios_base::app):
2016-01-18 22:30:06 +02:00
return CHAR_LITERAL("a");
2016-01-09 22:24:20 +02:00
case (ios_base::out | ios_base::in):
2016-01-18 22:30:06 +02:00
return CHAR_LITERAL("r+");
2016-01-09 22:24:20 +02:00
case (ios_base::out | ios_base::in | ios_base::trunc):
2016-01-18 22:30:06 +02:00
return CHAR_LITERAL("w+");
2016-01-09 22:24:20 +02:00
case (ios_base::out | ios_base::in | ios_base::app):
case (ios_base::in | ios_base::app):
2016-01-18 22:30:06 +02:00
return CHAR_LITERAL("a+");
2016-01-09 22:24:20 +02:00
default:
throw std::ios_base::failure("invalid open mode");
}
}();
if (mode & std::ios_base::binary)
2016-01-18 22:30:06 +02:00
openmode += CHAR_LITERAL('b');
2016-01-09 22:24:20 +02:00
2016-01-18 22:30:06 +02:00
filePtr = do_open(filename.c_str(), openmode.c_str());
2016-01-09 22:24:20 +02:00
if (filePtr == nullptr)
throw std::ios_base::failure("could not open file");
if (mode & std::ios_base::ate) {
if (std::fseek(GETFILE, 0, SEEK_END)) {
fclose(GETFILE);
throw std::ios_base::failure("could not open file");
}
}
}
void FileBuf::close()
{
std::fclose(GETFILE);
}
std::streamsize FileBuf::read(char* s, std::streamsize n)
{
return static_cast<std::streamsize>(std::fread(s, 1, n, GETFILE));
}
std::streamsize FileBuf::write(const char* s, std::streamsize n)
{
return static_cast<std::streamsize>(std::fwrite(s, 1, n, GETFILE));
}
std::streamoff FileBuf::seek(std::streamoff off, std::ios_base::seekdir way)
{
2016-01-18 22:30:06 +02:00
const auto src = [way]() -> int
2016-01-09 22:24:20 +02:00
{
switch(way)
{
case std::ios_base::beg:
return SEEK_SET;
case std::ios_base::cur:
return SEEK_CUR;
case std::ios_base::end:
return SEEK_END;
default:
throw std::ios_base::failure("bad seek direction");
}
}();
2023-02-15 00:09:07 +02:00
if(std::fseek(GETFILE, static_cast<long>(off), src))
2016-01-09 22:24:20 +02:00
throw std::ios_base::failure("bad seek offset");
return static_cast<std::streamsize>(std::ftell(GETFILE));
}
VCMI_LIB_NAMESPACE_END