diff --git a/Minecraft.Client/stubs.h b/Minecraft.Client/stubs.h
index f4ae056f2..a953dd2e3 100644
--- a/Minecraft.Client/stubs.h
+++ b/Minecraft.Client/stubs.h
@@ -160,20 +160,11 @@ public:
void dispose() {}
};
-class ZipEntry
-{
-};
+class ZipEntry;
class InputStream;
class File;
-class ZipFile
-{
-public:
- ZipFile(File *file) {}
- InputStream *getInputStream(ZipEntry *entry) { return NULL; }
- ZipEntry *getEntry(const wstring& name) {return NULL;}
- void close() {}
-};
+class ZipFile;
class ImageIO
{
diff --git a/Minecraft.World/Minecraft.World.vcxproj b/Minecraft.World/Minecraft.World.vcxproj
index c9191573e..6e5f95bac 100644
--- a/Minecraft.World/Minecraft.World.vcxproj
+++ b/Minecraft.World/Minecraft.World.vcxproj
@@ -3441,6 +3441,8 @@
+
+
@@ -4793,6 +4795,8 @@
+
+
diff --git a/Minecraft.World/Minecraft.World.vcxproj.filters b/Minecraft.World/Minecraft.World.vcxproj.filters
index bf872596b..d228a70fd 100644
--- a/Minecraft.World/Minecraft.World.vcxproj.filters
+++ b/Minecraft.World/Minecraft.World.vcxproj.filters
@@ -3197,6 +3197,12 @@
net\minecraft\world\inventory
+
+ ConsoleJavaLibs
+
+
+ ConsoleJavaLibs
+
@@ -5626,5 +5632,11 @@
net\minecraft\world\item
+
+ ConsoleJavaLibs
+
+
+ ConsoleJavaLibs
+
\ No newline at end of file
diff --git a/Minecraft.World/ZipEntry.cpp b/Minecraft.World/ZipEntry.cpp
new file mode 100644
index 000000000..7765d45c8
--- /dev/null
+++ b/Minecraft.World/ZipEntry.cpp
@@ -0,0 +1,27 @@
+#include "stdafx.h"
+#include "ZipEntry.h"
+
+ZipEntry::ZipEntry(bit7z::BitArchiveItemOffset itemInfo) : _itemInfo(itemInfo) {
+ _name = itemInfo.name();
+ _path = itemInfo.path();
+}
+
+DWORD ZipEntry::getSize() {
+ return _itemInfo.size();
+}
+
+bool ZipEntry::isDir() {
+ return _itemInfo.isDir();
+}
+
+std::string ZipEntry::getName() {
+ return _name;
+}
+
+std::string ZipEntry::path() {
+ return _path;
+}
+
+unsigned int ZipEntry::getIndex() {
+ return (unsigned int)_itemInfo.index();
+}
\ No newline at end of file
diff --git a/Minecraft.World/ZipEntry.h b/Minecraft.World/ZipEntry.h
new file mode 100644
index 000000000..12eeb2023
--- /dev/null
+++ b/Minecraft.World/ZipEntry.h
@@ -0,0 +1,20 @@
+#pragma once
+#include "../Minecraft.Client/Common/libs/bit7z/include/bitarchivereader.hpp"
+
+class ZipEntry {
+private:
+ bit7z::BitArchiveItemOffset _itemInfo;
+
+ // caching for faster load times
+ std::string _name;
+ std::string _path;
+
+public:
+ ZipEntry(bit7z::BitArchiveItemOffset itemInfo);
+ DWORD getSize();
+ bool isDir();
+ bool isFile() { return !isDir(); }
+ std::string getName();
+ std::string path();
+ unsigned int getIndex();
+};
\ No newline at end of file
diff --git a/Minecraft.World/ZipFile.cpp b/Minecraft.World/ZipFile.cpp
new file mode 100644
index 000000000..8e82111cc
--- /dev/null
+++ b/Minecraft.World/ZipFile.cpp
@@ -0,0 +1,140 @@
+#include "stdafx.h"
+#include "ZipFile.h"
+
+// static library
+bit7z::Bit7zLibrary* ZipFile::_library;
+
+ZipFile::ZipFile(File* file) {
+ if (file != NULL && file->exists()) {
+ open(file);
+ }
+}
+
+ZipFile::ZipFile(std::string name) {
+ File file(convStringToWstring(name));
+ if (file.exists()) {
+ open(&file);
+ }
+}
+
+std::vector ZipFile::listFiles() {
+ std::vector files;
+ files.reserve(_fileCache.size());
+
+ for (auto item : _fileCache) {
+ files.emplace_back(item.first);
+ }
+ return files;
+}
+
+// returns -1 if not found
+std::unique_ptr ZipFile::getEntry(const std::wstring* name) {
+ bool path = name->find('/') != name->npos || name->find('\\') != name->npos;
+ std::wstring nameCopy = *name;
+#ifdef _WIN64
+ if (path) { //
+ for (int i = 0; i < nameCopy.length(); i++)
+ if (nameCopy[i] == L'/')
+ nameCopy[i] = L'\\';
+ }
+#endif
+
+ auto it = _fileCache.find(nameCopy);
+ if (it != _fileCache.end()) {
+ auto entryInfo = _reader->itemAt(it->second);
+ return std::make_unique(entryInfo);
+ }
+
+ return nullptr;
+}
+
+std::vector ZipFile::extract(const std::wstring* name) {
+ auto entry = getEntry(name);
+ if (!entry)
+ return {};
+
+ try {
+ auto size = entry->getSize();
+ std::vector buffer(size);
+ _reader->extractTo(buffer.data(), size, entry->getIndex());
+ return buffer;
+ }
+ catch (exception e) {
+ OutputDebugString(wstringtochararray(L"Error extracting file from zip: " + *name + L'\n'));
+ OutputDebugString(wstringtochararray(L"Exception: " + convStringToWstring(e.what()) + L'\n'));
+ __debugbreak();
+ return {};
+ }
+}
+
+bool ZipFile::hasFile(const std::wstring* name) {
+ bool path = name->find('/') != name->npos || name->find('\\') != name->npos;
+ std::wstring nameCopy = *name;
+#ifdef _WIN64
+ if (path) { //
+ for (int i = 0; i < nameCopy.length(); i++)
+ if (nameCopy[i] == L'/')
+ nameCopy[i] = L'\\';
+ }
+#endif
+
+ return _fileCache.find(nameCopy) != _fileCache.end();
+}
+
+bool ZipFile::hasFile(char* str) {
+ try {
+ std::wstring wstr = convStringToWstring(std::string(str));
+ return hasFile(&wstr);
+ }
+ catch (exception e) {
+ return false;
+ }
+}
+
+InputStream* ZipFile::getInputStream(ZipEntry* entry) {
+ std::vector data(entry->getSize());
+ _reader->extractTo(data.data(), data.size(), entry->getIndex());
+ byteArray* buf = new byteArray(data.data(), data.size());
+ ByteArrayInputStream* stream = new ByteArrayInputStream(*buf, 0, data.size());
+ return stream;
+}
+
+InputStream* ZipFile::getInputStream(int entryId) {
+ auto entry = _reader->itemAt(entryId);
+ std::vector data(entry.size());
+ _reader->extractTo(data.data(), data.size(), entry.index());
+ byteArray* buf = new byteArray(data.data(), data.size());
+ ByteArrayInputStream* stream = new ByteArrayInputStream(*buf, 0, data.size());
+ return stream;
+}
+
+bool ZipFile::open(File* file) {
+ try {
+ std::wstring wpath = file->getPath();
+ int charCount = WideCharToMultiByte(CP_UTF8, 0, wpath.c_str(), -1, NULL, 0, NULL, NULL);
+ std::string path(charCount - 1, 0);
+ WideCharToMultiByte(CP_UTF8, 0, wpath.c_str(), -1, &path[0], charCount, NULL, NULL);
+
+ if (_library == nullptr) {
+ OutputDebugString("Initializing bit7z library");
+ _library = new bit7z::Bit7zLibrary("Windows64Media\\7z.dll");
+ }
+
+ _reader = std::make_unique(*_library, path, bit7z::BitFormat::Zip);
+ auto _libentries = _reader->items();
+ _fileCache.clear();
+
+ for (auto &item : _libentries) {
+ if (!item.isDir()) { // We never unpack directories, this also saves time comparing against them
+ _fileCache[item.nativePath()] = item.index();
+ _fileCache[convStringToWstring(item.name())] = item.index();
+ }
+ }
+ }
+ catch (exception e) {
+ OutputDebugString(wstringtochararray(L"Error opening zip file: " + file->getPath()));
+ OutputDebugString(wstringtochararray(L"\nException: " + convStringToWstring(e.what())));
+ __debugbreak();
+ }
+ return false;
+}
\ No newline at end of file
diff --git a/Minecraft.World/ZipFile.h b/Minecraft.World/ZipFile.h
new file mode 100644
index 000000000..a359a472d
--- /dev/null
+++ b/Minecraft.World/ZipFile.h
@@ -0,0 +1,30 @@
+#pragma once
+#include
+#include
+#include "File.h"
+#include "ZipEntry.h"
+#include "../Minecraft.Client/Common/libs/bit7z/include/bitarchivereader.hpp"
+
+class ZipFile {
+public:
+ ZipFile(File* file);
+ ZipFile(std::string name);
+ std::vector listFiles();
+ bool hasFile(const std::wstring* name);
+ bool hasFile(char* str);
+ std::unique_ptr getEntry(const std::wstring* name);
+ std::vector extract(const std::wstring* name);
+ InputStream* getInputStream(ZipEntry* entry);
+ InputStream* getInputStream(int entryId);
+
+
+private:
+ static bit7z::Bit7zLibrary* _library;
+ std::unique_ptr _reader;
+ unordered_map _fileCache;
+
+
+ bool open(File* file);
+
+
+};
\ No newline at end of file