浏览代码

Start implementing map saver

AlexVinS 10 年之前
父节点
当前提交
1a8faeb0b9

+ 2 - 0
lib/VCMI_lib.cbp

@@ -232,6 +232,8 @@
 		<Unit filename="filesystem/CStream.h" />
 		<Unit filename="filesystem/CZipLoader.cpp" />
 		<Unit filename="filesystem/CZipLoader.h" />
+		<Unit filename="filesystem/CZipSaver.cpp" />
+		<Unit filename="filesystem/CZipSaver.h" />
 		<Unit filename="filesystem/Filesystem.cpp" />
 		<Unit filename="filesystem/Filesystem.h" />
 		<Unit filename="filesystem/ISimpleResourceLoader.h" />

+ 0 - 1
lib/filesystem/CMemoryBuffer.h

@@ -13,7 +13,6 @@
 
 #include "CInputOutputStream.h"
 
-
 /**
  * A class which provides IO memory buffer.
  */

+ 2 - 2
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;	
 };

+ 2 - 1
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<CIOApi> 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<CIOApi> api):
 	ioApi(api),
     zlibApi(ioApi->getApiStructure()),	

+ 0 - 1
lib/filesystem/CZipLoader.h

@@ -61,7 +61,6 @@ public:
 	std::unordered_set<ResourceID> getFilteredFiles(std::function<bool(const ResourceID &)> filter) const override;
 };
 
-
 namespace ZipArchive
 {
 	/// List all files present in archive

+ 79 - 0
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<CIOApi> 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<COutputStream> CZipSaver::addFile(const std::string & archiveFilename)
+{
+	if(activeStream != nullptr)
+		throw new std::runtime_error("CZipSaver::addFile: stream already opened");
+	
+	std::unique_ptr<COutputStream> stream(new CZipOutputStream(handle, archiveFilename));
+	
+	activeStream = stream.get();
+	
+	return stream;
+}
+

+ 53 - 0
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<CIOApi> api, const std::string & path);
+	virtual ~CZipSaver();
+	
+	std::unique_ptr<COutputStream> addFile(const std::string & archiveFilename);
+private:
+	std::shared_ptr<CIOApi> ioApi;
+	zlib_filefunc64_def zipApi;	
+	
+	zipFile handle;
+	
+	///due to minizip design only one file stream may opened at a time
+	COutputStream * activeStream;
+};

+ 29 - 5
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<CInputOutputStream *>(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" <<filename<<" with mode "<<mode; 
+	
+	data->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
+}

+ 15 - 7
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;
 };

+ 29 - 2
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<CMap>& 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());
+	}	
+}

+ 14 - 4
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<CMap> & map) override;	
 private:
-	COutputStream * output;		
+	void saveHeader();
+	
+	CInputOutputStream * output;
+	std::shared_ptr<CIOApi> ioApi;		
+	CZipSaver saver;	
 };

+ 1 - 0
test/Test.cbp

@@ -47,6 +47,7 @@
 			<Add option="-Wno-unused-parameter" />
 			<Add option="-Wno-overloaded-virtual" />
 			<Add option="-Wno-unused-local-typedefs" />
+			<Add directory="$(#zlib.include)" />
 			<Add directory="$(#boost.include)" />
 		</Compiler>
 		<Linker>