From 1a8faeb0b91d45e5937cccf352a890f16edbe3c3 Mon Sep 17 00:00:00 2001 From: AlexVinS Date: Tue, 11 Aug 2015 21:20:13 +0300 Subject: [PATCH] Start implementing map saver --- lib/VCMI_lib.cbp | 2 + lib/filesystem/CMemoryBuffer.h | 1 - lib/filesystem/CStream.h | 4 +- lib/filesystem/CZipLoader.cpp | 3 +- lib/filesystem/CZipLoader.h | 1 - lib/filesystem/CZipSaver.cpp | 79 ++++++++++++++++++++++++++++ lib/filesystem/CZipSaver.h | 53 +++++++++++++++++++ lib/filesystem/MinizipExtensions.cpp | 34 ++++++++++-- lib/filesystem/MinizipExtensions.h | 22 +++++--- lib/mapping/MapFormatJson.cpp | 31 ++++++++++- lib/mapping/MapFormatJson.h | 18 +++++-- test/Test.cbp | 1 + 12 files changed, 226 insertions(+), 23 deletions(-) create mode 100644 lib/filesystem/CZipSaver.cpp create mode 100644 lib/filesystem/CZipSaver.h diff --git a/lib/VCMI_lib.cbp b/lib/VCMI_lib.cbp index d3409c191..d966248a1 100644 --- a/lib/VCMI_lib.cbp +++ b/lib/VCMI_lib.cbp @@ -232,6 +232,8 @@ + + diff --git a/lib/filesystem/CMemoryBuffer.h b/lib/filesystem/CMemoryBuffer.h index 74f8f2c58..10e43fa6a 100644 --- a/lib/filesystem/CMemoryBuffer.h +++ b/lib/filesystem/CMemoryBuffer.h @@ -13,7 +13,6 @@ #include "CInputOutputStream.h" - /** * A class which provides IO memory buffer. */ diff --git a/lib/filesystem/CStream.h b/lib/filesystem/CStream.h index d085eec72..21026b72b 100644 --- a/lib/filesystem/CStream.h +++ b/lib/filesystem/CStream.h @@ -42,9 +42,9 @@ public: virtual si64 skip(si64 delta) = 0; /** - * Gets the length in bytes of the stream. + * Gets the length of the stream. * - * @return the length in bytes of the stream. + * @return the length in bytes */ virtual si64 getSize() = 0; }; diff --git a/lib/filesystem/CZipLoader.cpp b/lib/filesystem/CZipLoader.cpp index 0a98672da..47dc621d0 100644 --- a/lib/filesystem/CZipLoader.cpp +++ b/lib/filesystem/CZipLoader.cpp @@ -1,5 +1,4 @@ #include "StdInc.h" -#include "../../Global.h" #include "CZipLoader.h" #include "../ScopeGuard.h" @@ -14,6 +13,7 @@ * */ +///CZipStream CZipStream::CZipStream(std::shared_ptr api, const std::string & archive, unz_file_pos filepos) { zlib_filefunc64_def zlibApi; @@ -50,6 +50,7 @@ ui32 CZipStream::calculateCRC32() return info.crc; } +///CZipLoader CZipLoader::CZipLoader(const std::string & mountPoint, const std::string & archive, std::shared_ptr api): ioApi(api), zlibApi(ioApi->getApiStructure()), diff --git a/lib/filesystem/CZipLoader.h b/lib/filesystem/CZipLoader.h index ee0077aa6..d5393ea2b 100644 --- a/lib/filesystem/CZipLoader.h +++ b/lib/filesystem/CZipLoader.h @@ -61,7 +61,6 @@ public: std::unordered_set getFilteredFiles(std::function filter) const override; }; - namespace ZipArchive { /// List all files present in archive diff --git a/lib/filesystem/CZipSaver.cpp b/lib/filesystem/CZipSaver.cpp new file mode 100644 index 000000000..f3c3c2076 --- /dev/null +++ b/lib/filesystem/CZipSaver.cpp @@ -0,0 +1,79 @@ +/* + * CZipSaver.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 + * + */ + +#include "StdInc.h" +#include "CZipSaver.h" + +///CZipOutputStream +CZipOutputStream::CZipOutputStream(zipFile archive, const std::string & archiveFilename): + handle(archive) +{ + //zip_fileinfo fileInfo; + + zipOpenNewFileInZip(handle, + archiveFilename.c_str(), + nullptr,//todo: use fileInfo, + nullptr, + 0, + nullptr, + 0, + "", + Z_DEFLATED, + Z_DEFAULT_COMPRESSION); +} + +CZipOutputStream::~CZipOutputStream() +{ + zipCloseFileInZip(handle); +} + + +si64 CZipOutputStream::write(const ui8 * data, si64 size) +{ + int ret = zipWriteInFileInZip(handle, (const void*)data, (unsigned)size); + + if (ret == ZIP_OK) + return size; + else + return 0; +} + +///CZipSaver +CZipSaver::CZipSaver(std::shared_ptr api, const std::string & path): + ioApi(api), + zipApi(ioApi->getApiStructure()), + handle(nullptr) +{ + + + handle = zipOpen2_64(path.c_str(), APPEND_STATUS_CREATE, nullptr, &zipApi); + + if (handle == nullptr) + throw new std::runtime_error("Failed to create archive"); +} + +CZipSaver::~CZipSaver() +{ + if(handle != nullptr) + zipClose(handle, nullptr); +} + +std::unique_ptr CZipSaver::addFile(const std::string & archiveFilename) +{ + if(activeStream != nullptr) + throw new std::runtime_error("CZipSaver::addFile: stream already opened"); + + std::unique_ptr stream(new CZipOutputStream(handle, archiveFilename)); + + activeStream = stream.get(); + + return stream; +} + diff --git a/lib/filesystem/CZipSaver.h b/lib/filesystem/CZipSaver.h new file mode 100644 index 000000000..3a0cb9752 --- /dev/null +++ b/lib/filesystem/CZipSaver.h @@ -0,0 +1,53 @@ +#pragma once + +/* + * CZipSaver.h, 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 + * + */ + +#include "COutputStream.h" + +#include "MinizipExtensions.h" + +class DLL_LINKAGE CZipOutputStream: public COutputStream +{ +public: + /** + * @brief constructs zip stream from already opened file + * @param archive archive handle, must be opened + * @param archiveFilename name of file to write + */ + explicit CZipOutputStream(zipFile archive, const std::string & archiveFilename); + ~CZipOutputStream(); + + si64 write(const ui8 * data, si64 size) override; + + si64 seek(si64 position) override {return -1;}; + si64 tell() override {return 0;}; + si64 skip(si64 delta) override {return 0;}; + si64 getSize() override {return 0;}; +private: + zipFile handle; +}; + +class DLL_LINKAGE CZipSaver +{ +public: + explicit CZipSaver(std::shared_ptr api, const std::string & path); + virtual ~CZipSaver(); + + std::unique_ptr addFile(const std::string & archiveFilename); +private: + std::shared_ptr ioApi; + zlib_filefunc64_def zipApi; + + zipFile handle; + + ///due to minizip design only one file stream may opened at a time + COutputStream * activeStream; +}; diff --git a/lib/filesystem/MinizipExtensions.cpp b/lib/filesystem/MinizipExtensions.cpp index 9c29c5998..d07098957 100644 --- a/lib/filesystem/MinizipExtensions.cpp +++ b/lib/filesystem/MinizipExtensions.cpp @@ -8,9 +8,12 @@ * */ #include "StdInc.h" - #include "MinizipExtensions.h" +#include "CMemoryBuffer.h" + + +///CIOApi voidpf ZCALLBACK CIOApi::openFileProxy(voidpf opaque, const void * filename, int mode) { assert(opaque != nullptr); @@ -82,7 +85,7 @@ int ZCALLBACK CIOApi::closeFileProxy(voidpf opaque, voidpf stream) CInputOutputStream * actualStream = static_cast(stream); - delete actualStream; + ((CIOApi *)opaque)->closeFile(actualStream); return 0; } @@ -92,7 +95,6 @@ int ZCALLBACK CIOApi::errorFileProxy(voidpf opaque, voidpf stream) return 0; } -///CIOApi zlib_filefunc64_def CIOApi::getApiStructure() const { zlib_filefunc64_def api; @@ -108,6 +110,12 @@ zlib_filefunc64_def CIOApi::getApiStructure() const return api; } +void CIOApi::closeFile(CInputOutputStream * stream) const +{ + delete stream; +} + +///CDefaultIOApi CDefaultIOApi::CDefaultIOApi() { @@ -132,12 +140,28 @@ CInputOutputStream * CDefaultIOApi::openFile(const std::string& filename, int mo throw new std::runtime_error("CDefaultIOApi::openFile call not expected."); } -CZipArchive::CZipArchive(const CIOApi* api) +///CProxyIOApi +CProxyIOApi::CProxyIOApi(CInputOutputStream * buffer): + data(buffer) { } -CZipArchive::~CZipArchive() +CProxyIOApi::~CProxyIOApi() { } + +CInputOutputStream * CProxyIOApi::openFile(const std::string& filename, int mode) const +{ + logGlobal->traceStream() << "CProxyIOApi: stream opened for" <seek(0); + return data;//todo: check that only one "copy" is opened +} + +void CProxyIOApi::closeFile(CInputOutputStream * stream) const +{ + logGlobal->traceStream() << "CProxyIOApi: stream closed"; + stream->seek(0);//stream is local singleton and even not owned, just seek +} diff --git a/lib/filesystem/MinizipExtensions.h b/lib/filesystem/MinizipExtensions.h index 0f6d99280..a88e3db7e 100644 --- a/lib/filesystem/MinizipExtensions.h +++ b/lib/filesystem/MinizipExtensions.h @@ -20,7 +20,8 @@ #include "../minizip/ioapi.h" #endif -#include "CInputOutputStream.h" +class CInputOutputStream; +class CMemoryBuffer; class DLL_LINKAGE CIOApi { @@ -32,6 +33,9 @@ public: protected: virtual CInputOutputStream * openFile(const std::string & filename, int mode) const = 0; + ///default implementation deletes stream object + virtual void closeFile(CInputOutputStream * stream) const; + private: static voidpf ZCALLBACK openFileProxy(voidpf opaque, const void * filename, int mode); static uLong ZCALLBACK readFileProxy(voidpf opaque, voidpf stream, void * buf, uLong size); @@ -42,7 +46,8 @@ private: static int ZCALLBACK errorFileProxy(voidpf opaque, voidpf stream); }; - +///redirects back to minizip ioapi +//todo: replace with Virtual FileSystem interface class DLL_LINKAGE CDefaultIOApi: public CIOApi { public: @@ -55,12 +60,15 @@ protected: CInputOutputStream * openFile(const std::string & filename, int mode) const override; }; -class CZipArchive +///redirects all file IO to single stream +class DLL_LINKAGE CProxyIOApi: public CIOApi { public: - explicit CZipArchive(const CIOApi * api); - virtual ~CZipArchive(); - + CProxyIOApi(CInputOutputStream * buffer); + ~CProxyIOApi(); +protected: + CInputOutputStream * openFile(const std::string & filename, int mode) const override; + void closeFile(CInputOutputStream * stream) const override; private: - + CInputOutputStream * data; }; diff --git a/lib/mapping/MapFormatJson.cpp b/lib/mapping/MapFormatJson.cpp index 11151d9e8..09c5ebf94 100644 --- a/lib/mapping/MapFormatJson.cpp +++ b/lib/mapping/MapFormatJson.cpp @@ -51,6 +51,8 @@ static EventCondition JsonToCondition(const JsonNode & node) } ///CMapFormatJson +const std::string CMapFormatJson::HEADER_FILE_NAME = "header.json"; + void CMapFormatJson::readTriggeredEvents(const JsonNode & input) { mapHeader->victoryMessage = input["victoryString"].String(); @@ -183,15 +185,40 @@ void CMapLoaderJson::readPlayerInfo() } ///CMapSaverJson -CMapSaverJson::CMapSaverJson(COutputStream * stream): - output(stream) +CMapSaverJson::CMapSaverJson(CInputOutputStream * stream): + output(stream), + ioApi(new CProxyIOApi(output)), + saver(ioApi, "_") { } +CMapSaverJson::~CMapSaverJson() +{ + +} void CMapSaverJson::saveMap(const std::unique_ptr& map) { //TODO: saveMap + this->map = map.get(); } +void CMapSaverJson::saveHeader() +{ + JsonNode header; + //TODO: save header + + header["name"].String() = map->name; + + std::ostringstream out; + out << header; + out.flush(); + + { + auto s = out.str(); + auto stream = saver.addFile(HEADER_FILE_NAME); + + stream->write((const ui8*)s.c_str(), s.size()); + } +} diff --git a/lib/mapping/MapFormatJson.h b/lib/mapping/MapFormatJson.h index 9ac1bcfa0..114c6c51a 100644 --- a/lib/mapping/MapFormatJson.h +++ b/lib/mapping/MapFormatJson.h @@ -13,12 +13,16 @@ #include "CMapService.h" #include "../JsonNode.h" +#include "../filesystem/CZipSaver.h" +#include "../filesystem/CZipLoader.h" + class TriggeredEvent; -class CInputStream; -class COutputStream; + class DLL_LINKAGE CMapFormatJson { +public: + static const std::string HEADER_FILE_NAME; protected: @@ -121,7 +125,9 @@ public: * * @param stream a stream to save the map to */ - CMapSaverJson(COutputStream * stream); + CMapSaverJson(CInputOutputStream * stream); + + ~CMapSaverJson(); /** * Actually saves the VCMI/Json map into stream. @@ -129,5 +135,9 @@ public: */ void saveMap(const std::unique_ptr & map) override; private: - COutputStream * output; + void saveHeader(); + + CInputOutputStream * output; + std::shared_ptr ioApi; + CZipSaver saver; }; diff --git a/test/Test.cbp b/test/Test.cbp index a6a485353..6665380f5 100644 --- a/test/Test.cbp +++ b/test/Test.cbp @@ -47,6 +47,7 @@ +