diff --git a/openrct2.vcxproj b/openrct2.vcxproj
index 253ff35e50..db9aaeffe6 100644
--- a/openrct2.vcxproj
+++ b/openrct2.vcxproj
@@ -110,6 +110,7 @@
+
@@ -449,6 +450,7 @@
+
diff --git a/src/core/Zip.cpp b/src/core/Zip.cpp
new file mode 100644
index 0000000000..d6ddec99ed
--- /dev/null
+++ b/src/core/Zip.cpp
@@ -0,0 +1,113 @@
+#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
+/*****************************************************************************
+ * OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
+ *
+ * OpenRCT2 is the work of many authors, a full list can be found in contributors.md
+ * For more information, visit https://github.com/OpenRCT2/OpenRCT2
+ *
+ * OpenRCT2 is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * A full copy of the GNU General Public License can be found in licence.txt
+ *****************************************************************************/
+#pragma endregion
+
+#include
+#include "IStream.hpp"
+#include "Zip.h"
+
+class ZipArchive : public IZipArchive
+{
+private:
+ zip_t * _zip;
+
+public:
+ ZipArchive(const utf8 * path)
+ {
+ int error;
+ _zip = zip_open(path, ZIP_RDONLY, &error);
+ if (_zip == nullptr)
+ {
+ throw IOException("Unable to open zip file.");
+ }
+ }
+
+ ~ZipArchive() override
+ {
+ zip_close(_zip);
+ }
+
+ size_t GetNumFiles() const override
+ {
+ return zip_get_num_files(_zip);
+ }
+
+ const utf8 * GetFileName(size_t index) const override
+ {
+ const utf8 * name = zip_get_name(_zip, index, ZIP_FL_ENC_GUESS);
+ return name;
+ }
+
+ const uint64 GetFileSize(size_t index) const override
+ {
+ zip_stat_t zipFileStat;
+ if (zip_stat_index(_zip, index, 0, &zipFileStat) == ZIP_ER_OK)
+ {
+ return zipFileStat.size;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ void * GetFileData(const utf8 * path, size_t * outSize) const override
+ {
+ void * data = nullptr;
+
+ size_t index = (size_t)zip_name_locate(_zip, path, 0);
+ uint64 dataSize = GetFileSize(index);
+ if (dataSize > 0 && dataSize < SIZE_MAX)
+ {
+ zip_file_t * zipFile = zip_fopen(_zip, path, 0);
+ if (zipFile != nullptr)
+ {
+ data = malloc(dataSize);
+ size_t readBytes = zip_fread(zipFile, data, dataSize);
+ if (readBytes != dataSize)
+ {
+ free(data);
+ data = nullptr;
+ dataSize = 0;
+ }
+ zip_fclose(zipFile);
+ }
+ }
+
+ if (outSize != nullptr) *outSize = dataSize;
+ return data;
+ }
+};
+
+namespace Zip
+{
+ IZipArchive * Open(const utf8 * path)
+ {
+ return new ZipArchive(path);
+ }
+
+ IZipArchive * TryOpen(const utf8 * path)
+ {
+ IZipArchive * result = nullptr;
+ try
+ {
+ result = new ZipArchive(path);
+ }
+ catch (Exception)
+ {
+ }
+ return result;
+ }
+}
diff --git a/src/core/Zip.h b/src/core/Zip.h
new file mode 100644
index 0000000000..3bec4f6f88
--- /dev/null
+++ b/src/core/Zip.h
@@ -0,0 +1,38 @@
+#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
+/*****************************************************************************
+ * OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
+ *
+ * OpenRCT2 is the work of many authors, a full list can be found in contributors.md
+ * For more information, visit https://github.com/OpenRCT2/OpenRCT2
+ *
+ * OpenRCT2 is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * A full copy of the GNU General Public License can be found in licence.txt
+ *****************************************************************************/
+#pragma endregion
+
+#pragma once
+
+#include "../common.h"
+
+/**
+ * Represents a zip file.
+ */
+interface IZipArchive
+{
+ virtual ~IZipArchive() { }
+
+ virtual size_t GetNumFiles() const abstract;
+ virtual const utf8 * GetFileName(size_t index) const abstract;
+ virtual const uint64 GetFileSize(size_t index) const abstract;
+ virtual void * GetFileData(const utf8 * path, size_t * outSize) const abstract;
+};
+
+namespace Zip
+{
+ IZipArchive * Open(const utf8 * path);
+ IZipArchive * TryOpen(const utf8 * path);
+}
diff --git a/src/title/TitleSequence.cpp b/src/title/TitleSequence.cpp
index b097794015..00c4c4b7c3 100644
--- a/src/title/TitleSequence.cpp
+++ b/src/title/TitleSequence.cpp
@@ -16,7 +16,6 @@
#include "../common.h"
#include
-#include
#include
#include "../core/Collections.hpp"
#include "../core/Console.hpp"
@@ -27,14 +26,14 @@
#include "../core/Memory.hpp"
#include "../core/Path.hpp"
#include "../core/String.hpp"
+#include "../core/Zip.h"
#include "TitleSequence.h"
static std::vector GetSaves(const utf8 * path);
-static std::vector GetSaves(zip_t * zip);
+static std::vector GetSaves(IZipArchive * zip);
static std::vector LegacyScriptRead(utf8 * script, size_t scriptLength, std::vector saves);
static void LegacyScriptGetLine(SDL_RWops * file, char * parts);
static void * ReadScriptFile(const utf8 * path, size_t * outSize);
-static void * GetZipFileData(zip_t * zip, const char * name, size_t * outSize);
extern "C"
{
@@ -48,25 +47,25 @@ extern "C"
const utf8 * ext = Path::GetExtension(path);
if (String::Equals(ext, TITLE_SEQUENCE_EXTENSION))
{
- int error;
- zip_t * zip = zip_open(path, ZIP_RDONLY, &error);
+ IZipArchive * zip = Zip::TryOpen(path);
if (zip == nullptr)
{
Console::Error::WriteLine("Unable to open '%s'", path);
return nullptr;
}
- script = (char *)GetZipFileData(zip, "script.txt", &scriptLength);
+ script = (char *)zip->GetFileData("script.txt", &scriptLength);
if (script == nullptr)
{
Console::Error::WriteLine("Unable to open script.txt in '%s'", path);
-
- zip_close(zip);
+ delete zip;
return nullptr;
}
saves = GetSaves(zip);
isZip = true;
+
+ delete zip;
}
else
{
@@ -120,14 +119,14 @@ extern "C"
const utf8 * filename = seq->Saves[index];
if (seq->IsZip)
{
- int error;
- zip_t * zip = zip_open(seq->Path, ZIP_RDONLY, &error);
+ IZipArchive * zip = Zip::TryOpen(seq->Path);
if (zip != nullptr)
{
handle = Memory::Allocate();
- handle->Data = GetZipFileData(zip, filename, &handle->DataSize);
+ handle->Data = zip->GetFileData(filename, &handle->DataSize);
handle->RWOps = SDL_RWFromMem(handle->Data, (int)handle->DataSize);
handle->IsScenario = String::Equals(Path::GetExtension(filename), ".sc6", true);
+ delete zip;
}
}
else
@@ -173,13 +172,13 @@ static std::vector GetSaves(const utf8 * directory)
return saves;
}
-static std::vector GetSaves(zip_t * zip)
+static std::vector GetSaves(IZipArchive * zip)
{
std::vector saves;
- int numFiles = zip_get_num_files(zip);
- for (int i = 0; i < numFiles; i++)
+ size_t numFiles = zip->GetNumFiles();
+ for (size_t i = 0; i < numFiles; i++)
{
- const utf8 * name = zip_get_name(zip, i, ZIP_FL_ENC_GUESS);
+ const utf8 * name = zip->GetFileName(i);
const utf8 * ext = Path::GetExtension(name);
if (String::Equals(ext, ".sv6", true) ||
String::Equals(ext, ".sc6", true))
@@ -354,37 +353,6 @@ static void * ReadScriptFile(const utf8 * path, size_t * outSize)
return buffer;
}
-static void * GetZipFileData(zip_t * zip, const char * name, size_t * outSize)
-{
- void * data = nullptr;
- size_t dataSize = 0;
-
- zip_stat_t zipFileStat;
- if (zip_stat(zip, name, 0, &zipFileStat) == ZIP_ER_OK)
- {
- zip_file_t * zipFile = zip_fopen(zip, name, 0);
- if (zipFile != nullptr)
- {
- if (zipFileStat.size < SIZE_MAX)
- {
- dataSize = zipFileStat.size;
- data = malloc(dataSize);
- size_t readBytes = zip_fread(zipFile, data, dataSize);
- if (readBytes != dataSize)
- {
- free(data);
- data = NULL;
- dataSize = 0;
- }
- zip_fclose(zipFile);
- }
- }
- }
-
- if (outSize != NULL) *outSize = dataSize;
- return data;
-}
-
/*
void title_sequence_save_preset_script(int preset)
{