Zyx-2000 10 лет назад
Родитель
Сommit
99cf8069d7
2 измененных файлов с 192 добавлено и 0 удалено
  1. 149 0
      lib/filesystem/FileStream.cpp
  2. 43 0
      lib/filesystem/FileStream.h

+ 149 - 0
lib/filesystem/FileStream.cpp

@@ -0,0 +1,149 @@
+#include "StdInc.h"
+#define INC_FROM_FILESTREAM_CPP
+#include "FileStream.h"
+#include "../minizip/unzip.h"
+
+#include <cstdio>
+
+
+#ifdef _WIN32
+	#ifndef _CRT_SECURE_NO_WARNINGS
+		#define _CRT_SECURE_NO_WARNINGS
+	#endif
+	#include <cwchar>
+	#define CHAR_LITERAL(s) L##s
+	#define DO_OPEN(name, mode) _wfopen(name, mode)
+	using CharType = wchar_t;
+#else
+	#define CHAR_LITERAL(s) s
+	#define DO_OPEN(name, mode) fopen(name, mode)
+	using CharType = char;
+#endif
+
+#define GETFILE static_cast<std::FILE*>(filePtr)
+
+voidpf ZCALLBACK MinizipOpenFunc(voidpf opaque, const void* filename, int mode)
+{
+    const CharType* mode_fopen = [mode]() -> const CharType*
+    {
+		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;
+    }();
+
+    if (filename != nullptr && mode_fopen != nullptr)
+        return DO_OPEN(static_cast<const CharType*>(filename), mode_fopen);
+	else
+		return nullptr;
+}
+
+zlib_filefunc64_def* FileStream::GetMinizipFilefunc()
+{
+	static zlib_filefunc64_def MinizipFilefunc;
+	static bool initialized = false;
+	if (!initialized) {
+		fill_fopen64_filefunc((&MinizipFilefunc));
+		MinizipFilefunc.zopen64_file = &MinizipOpenFunc;
+		initialized = true;
+	}
+	return &MinizipFilefunc;
+}
+
+template class DLL_LINKAGE boost::iostreams::stream<FileBuf>;
+
+/*static*/
+bool FileStream::CreateFile(const boost::filesystem::path& filename)
+{
+	FILE* f = DO_OPEN(filename.c_str(), CHAR_LITERAL("wb"));
+	bool result = (f != nullptr);
+	fclose(f);
+	return result;
+}
+
+FileBuf::FileBuf(const boost::filesystem::path& filename, std::ios_base::openmode mode)
+{
+	std::string openmode = [mode]() -> std::string
+	{
+		using namespace std;
+		switch (mode & (~ios_base::ate & ~ios_base::binary))
+		{
+		case (ios_base::in):
+			return "r";
+		case (ios_base::out):
+		case (ios_base::out | ios_base::trunc):
+			return "w";
+		case (ios_base::app):
+		case (ios_base::out | ios_base::app):
+			return "a";
+		case (ios_base::out | ios_base::in):
+			return "r+";
+		case (ios_base::out | ios_base::in | ios_base::trunc):
+			return "w+";
+		case (ios_base::out | ios_base::in | ios_base::app):
+		case (ios_base::in | ios_base::app):
+			return "a+";
+		default:
+			throw std::ios_base::failure("invalid open mode");
+		}
+	}();
+
+	if (mode & std::ios_base::binary)
+		openmode += 'b';
+
+	#if defined(_WIN32)
+	filePtr = _wfopen(filename.c_str(), std::wstring(openmode.begin(), openmode.end()).c_str());
+	#else
+	filePtr = std::open(filename.c_str(), openmode);
+	#endif
+
+	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)
+{
+	auto src = [way]() -> int
+	{
+		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");
+		}
+	}();
+	if(std::fseek(GETFILE, off, src))
+		throw std::ios_base::failure("bad seek offset");
+
+	return static_cast<std::streamsize>(std::ftell(GETFILE));
+}

+ 43 - 0
lib/filesystem/FileStream.h

@@ -0,0 +1,43 @@
+#pragma once
+
+#include <iosfwd>
+#include <boost/iostreams/categories.hpp>
+#include <boost/iostreams/stream.hpp>
+
+class DLL_LINKAGE FileBuf {
+public:
+	typedef char                 					char_type;
+    typedef struct category_ :
+    	boost::iostreams::seekable_device_tag,
+    	boost::iostreams::closable_tag
+    	{} category;
+
+	FileBuf(const boost::filesystem::path& filename, std::ios_base::openmode mode = (std::ios_base::in | std::ios_base::out));
+
+    std::streamsize read(char* s, std::streamsize n);
+    std::streamsize write(const char* s, std::streamsize n);
+    std::streamoff  seek(std::streamoff off, std::ios_base::seekdir way);
+
+    void close();
+private:
+	void* filePtr;
+};
+
+struct zlib_filefunc64_def_s;
+typedef zlib_filefunc64_def_s zlib_filefunc64_def;
+
+#ifdef VCMI_DLL
+extern template class DLL_LINKAGE boost::iostreams::stream<FileBuf>;
+#else
+template class DLL_LINKAGE boost::iostreams::stream<FileBuf>;
+#endif
+
+class DLL_LINKAGE FileStream : public boost::iostreams::stream<FileBuf>
+{
+public:
+	using boost::iostreams::stream<FileBuf>::stream;
+
+	static bool CreateFile(const boost::filesystem::path& filename);
+
+	static zlib_filefunc64_def* GetMinizipFilefunc();
+};