diff --git a/ClassicalSharp/TexturePack/TextureCache.cs b/ClassicalSharp/TexturePack/TextureCache.cs
index ad7c85304..820ef0def 100644
--- a/ClassicalSharp/TexturePack/TextureCache.cs
+++ b/ClassicalSharp/TexturePack/TextureCache.cs
@@ -130,7 +130,7 @@ namespace ClassicalSharp.Textures {
tags.Add(entry);
}
- public static string MakePath(string url) { return PathIO.Combine(folder, CRC32(url)); }
+ static string MakePath(string url) { return PathIO.Combine(folder, CRC32(url)); }
static string CRC32(string url) {
byte[] data = Encoding.UTF8.GetBytes(url);
diff --git a/ClassicalSharp/TexturePack/TexturePack.cs b/ClassicalSharp/TexturePack/TexturePack.cs
index 043c1f5c3..bcf8099b9 100644
--- a/ClassicalSharp/TexturePack/TexturePack.cs
+++ b/ClassicalSharp/TexturePack/TexturePack.cs
@@ -45,7 +45,7 @@ namespace ClassicalSharp.Textures {
}
}
- public static void ExtractZip(Stream stream, Game game) {
+ static void ExtractZip(Stream stream, Game game) {
TexturePack.game = game;
game.Events.RaiseTexturePackChanged();
if (game.Graphics.LostContext) return;
diff --git a/src/Client/Chat.c b/src/Client/Chat.c
index f53ea4ea1..4909bfc7f 100644
--- a/src/Client/Chat.c
+++ b/src/Client/Chat.c
@@ -16,7 +16,7 @@
#define CHAT_LOGTIMES_DEF_ELEMS 256
#define CHAT_LOGTIMES_EXPAND_ELEMS 512
Int64 Chat_DefaultLogTimes[CHAT_LOGTIMES_DEF_ELEMS];
-Int64* Chat_LogTimes = &Chat_DefaultLogTimes;
+Int64* Chat_LogTimes = Chat_DefaultLogTimes;
UInt32 Chat_LogTimesCount = CHAT_LOGTIMES_DEF_ELEMS, Chat_LogTimesUsed;
void Chat_GetLogTime(UInt32 index, Int64* timeMs) {
diff --git a/src/Client/Client.vcxproj b/src/Client/Client.vcxproj
index 097dbd0ec..abb5e53cb 100644
--- a/src/Client/Client.vcxproj
+++ b/src/Client/Client.vcxproj
@@ -229,6 +229,7 @@
+
@@ -250,7 +251,6 @@
-
@@ -320,7 +320,6 @@
-
diff --git a/src/Client/Client.vcxproj.filters b/src/Client/Client.vcxproj.filters
index f3d8a78f5..25ae35c53 100644
--- a/src/Client/Client.vcxproj.filters
+++ b/src/Client/Client.vcxproj.filters
@@ -300,9 +300,6 @@
Header Files\Map
-
- Header Files\TexturePack
-
Header Files\2D
@@ -366,6 +363,9 @@
Header Files\2D
+
+ Header Files\TexturePack
+
@@ -503,9 +503,6 @@
Source Files\Map
-
- Source Files\TexturePack
-
Source Files\2D
diff --git a/src/Client/Menus.c b/src/Client/Menus.c
index ceb053274..1fac436d2 100644
--- a/src/Client/Menus.c
+++ b/src/Client/Menus.c
@@ -24,6 +24,7 @@
#include "ErrorHandler.h"
#include "BlockPhysics.h"
#include "MapRenderer.h"
+#include "TexturePack.h"
#define LIST_SCREEN_ITEMS 5
#define LIST_SCREEN_BUTTONS (LIST_SCREEN_ITEMS + 3)
diff --git a/src/Client/Program.c b/src/Client/Program.c
index cfa99d793..2266312d6 100644
--- a/src/Client/Program.c
+++ b/src/Client/Program.c
@@ -5,7 +5,7 @@
#include "GraphicsAPI.h"
#include "Deflate.h"
#include "Formats.h"
-#include "ZipArchive.h"
+#include "TexturePack.h"
#include "Bitmap.h"
#include
diff --git a/src/Client/Screens.c b/src/Client/Screens.c
index 22c18d51f..37fe1b17e 100644
--- a/src/Client/Screens.c
+++ b/src/Client/Screens.c
@@ -1378,7 +1378,7 @@ void HUDScreen_AppendInput(Screen* hud, STRING_PURE String* text) {
Widget* HUDScreen_GetHotbar(Screen* hud) {
HUDScreen* screen = (HUDScreen*)hud;
- return &screen->Hotbar;
+ return (Widget*)(&screen->Hotbar);
}
diff --git a/src/Client/ServerConnection.c b/src/Client/ServerConnection.c
index 29670c327..aea686341 100644
--- a/src/Client/ServerConnection.c
+++ b/src/Client/ServerConnection.c
@@ -14,6 +14,7 @@
#include "MapGenerator.h"
#include "World.h"
#include "Camera.h"
+#include "TexturePack.h"
UInt8 ServerConnection_ServerNameBuffer[String_BufferSize(STRING_SIZE)];
String ServerConnection_ServerName = String_FromEmptyArray(ServerConnection_ServerNameBuffer);
diff --git a/src/Client/TexturePack.c b/src/Client/TexturePack.c
index a3af68524..7dd38acc7 100644
--- a/src/Client/TexturePack.c
+++ b/src/Client/TexturePack.c
@@ -1,11 +1,179 @@
-#include "Typedefs.h"
-#include "String.h"
+#include "TexturePack.h"
#include "Constants.h"
#include "Platform.h"
#include "ErrorHandler.h"
#include "Stream.h"
#include "Bitmap.h"
+#include "World.h"
+#include "GraphicsAPI.h"
+#include "Event.h"
+#include "Game.h"
+#include "AsyncDownloader.h"
+#include "ErrorHandler.h"
+#include "Platform.h"
+#include "Deflate.h"
+#include "Stream.h"
+/*########################################################################################################################*
+*--------------------------------------------------------ZipEntry---------------------------------------------------------*
+*#########################################################################################################################*/
+String Zip_ReadFixedString(Stream* stream, UInt8* buffer, UInt16 length) {
+ String fileName;
+ fileName.buffer = buffer;
+ fileName.length = length;
+ fileName.capacity = length;
+
+ Stream_Read(stream, buffer, length);
+ buffer[length] = NULL; /* Ensure null terminated */
+ return fileName;
+}
+
+void Zip_ReadLocalFileHeader(ZipState* state, ZipEntry* entry) {
+ Stream* stream = state->Input;
+ UInt16 versionNeeded = Stream_ReadUInt16_LE(stream);
+ UInt16 flags = Stream_ReadUInt16_LE(stream);
+ UInt16 compressionMethod = Stream_ReadUInt16_LE(stream);
+ Stream_ReadUInt32_LE(stream); /* last modified */
+ Stream_ReadUInt32_LE(stream); /* CRC32 */
+
+ Int32 compressedSize = Stream_ReadInt32_LE(stream);
+ if (compressedSize == 0) compressedSize = entry->CompressedDataSize;
+ Int32 uncompressedSize = Stream_ReadInt32_LE(stream);
+ if (uncompressedSize == 0) uncompressedSize = entry->UncompressedDataSize;
+
+ UInt16 fileNameLen = Stream_ReadUInt16_LE(stream);
+ UInt16 extraFieldLen = Stream_ReadUInt16_LE(stream);
+ UInt8 filenameBuffer[String_BufferSize(UInt16_MaxValue)];
+ String filename = Zip_ReadFixedString(stream, filenameBuffer, fileNameLen);
+ if (!state->SelectEntry(&filename)) return;
+
+ ReturnCode code = Stream_Skip(stream, extraFieldLen);
+ ErrorHandler_CheckOrFail(code, "Zip - skipping local header extra");
+ if (versionNeeded > 20) {
+ String warnMsg = String_FromConst("May not be able to properly extract a .zip enty with a version later than 2.0");
+ Platform_Log(&warnMsg);
+ }
+
+ Stream portion, compStream;
+ if (compressionMethod == 0) {
+ Stream_ReadonlyPortion(&portion, stream, uncompressedSize);
+ state->ProcessEntry(&filename, &portion, entry);
+ } else if (compressionMethod == 8) {
+ DeflateState deflate;
+ Stream_ReadonlyPortion(&portion, stream, compressedSize);
+ Deflate_MakeStream(&compStream, &deflate, &portion);
+ state->ProcessEntry(&filename, &compStream, entry);
+ } else {
+ String warnMsg = String_FromConst("Unsupported .zip entry compression method");
+ Platform_Log(&warnMsg);
+ }
+}
+
+void Zip_ReadCentralDirectory(ZipState* state, ZipEntry* entry) {
+ Stream* stream = state->Input;
+ Stream_ReadUInt16_LE(stream); /* OS */
+ UInt16 versionNeeded = Stream_ReadUInt16_LE(stream);
+ UInt16 flags = Stream_ReadUInt16_LE(stream);
+ UInt16 compressionMethod = Stream_ReadUInt16_LE(stream);
+ Stream_ReadUInt32_LE(stream); /* last modified */
+ entry->Crc32 = Stream_ReadUInt32_LE(stream);
+ entry->CompressedDataSize = Stream_ReadInt32_LE(stream);
+ entry->UncompressedDataSize = Stream_ReadInt32_LE(stream);
+
+ UInt16 fileNameLen = Stream_ReadUInt16_LE(stream);
+ UInt16 extraFieldLen = Stream_ReadUInt16_LE(stream);
+ UInt16 fileCommentLen = Stream_ReadUInt16_LE(stream);
+ UInt16 diskNum = Stream_ReadUInt16_LE(stream);
+ UInt16 internalAttributes = Stream_ReadUInt16_LE(stream);
+ UInt32 externalAttributes = Stream_ReadUInt32_LE(stream);
+ entry->LocalHeaderOffset = Stream_ReadInt32_LE(stream);
+
+ UInt32 extraDataLen = fileNameLen + extraFieldLen + fileCommentLen;
+ ReturnCode code = Stream_Skip(stream, extraDataLen);
+ ErrorHandler_CheckOrFail(code, "Zip - skipping central header extra");
+}
+
+void Zip_ReadEndOfCentralDirectory(ZipState* state, Int32* centralDirectoryOffset) {
+ Stream* stream = state->Input;
+ UInt16 diskNum = Stream_ReadUInt16_LE(stream);
+ UInt16 diskNumStart = Stream_ReadUInt16_LE(stream);
+ UInt16 diskEntries = Stream_ReadUInt16_LE(stream);
+ state->EntriesCount = Stream_ReadUInt16_LE(stream);
+ Int32 centralDirectorySize = Stream_ReadInt32_LE(stream);
+ *centralDirectoryOffset = Stream_ReadInt32_LE(stream);
+ UInt16 commentLength = Stream_ReadUInt16_LE(stream);
+}
+
+#define ZIP_ENDOFCENTRALDIR 0x06054b50UL
+#define ZIP_CENTRALDIR 0x02014b50UL
+#define ZIP_LOCALFILEHEADER 0x04034b50UL
+
+void Zip_DefaultProcessor(STRING_TRANSIENT String* path, Stream* data, ZipEntry* entry) { }
+bool Zip_DefaultSelector(STRING_TRANSIENT String* path) { return true; }
+void Zip_Init(ZipState* state, Stream* input) {
+ state->Input = input;
+ state->EntriesCount = 0;
+ state->ProcessEntry = Zip_DefaultProcessor;
+ state->SelectEntry = Zip_DefaultSelector;
+}
+
+void Zip_Extract(ZipState* state) {
+ state->EntriesCount = 0;
+ Stream* stream = state->Input;
+ ReturnCode result = stream->Seek(stream, -22, STREAM_SEEKFROM_END);
+ ErrorHandler_CheckOrFail(result, "ZIP - Seek to end of central directory");
+
+ UInt32 sig = Stream_ReadUInt32_LE(stream);
+ if (sig != ZIP_ENDOFCENTRALDIR) {
+ ErrorHandler_Fail("ZIP - Comment in .zip file not supported");
+ return;
+ }
+
+ Int32 centralDirectoryOffset;
+ Zip_ReadEndOfCentralDirectory(state, ¢ralDirectoryOffset);
+ result = stream->Seek(stream, centralDirectoryOffset, STREAM_SEEKFROM_BEGIN);
+ ErrorHandler_CheckOrFail(result, "ZIP - Seek to central directory");
+ if (state->EntriesCount > ZIP_MAX_ENTRIES) {
+ ErrorHandler_Fail("ZIP - Max of 2048 entries supported");
+ }
+
+ /* Read all the central directory entries */
+ Int32 count = 0;
+ while (count < state->EntriesCount) {
+ sig = Stream_ReadUInt32_LE(stream);
+ if (sig == ZIP_CENTRALDIR) {
+ Zip_ReadCentralDirectory(state, &state->Entries[count]);
+ count++;
+ } else if (sig == ZIP_ENDOFCENTRALDIR) {
+ break;
+ } else {
+ String sigMsg = String_FromConst("ZIP - Unsupported signature found, aborting");
+ ErrorHandler_Log(&sigMsg);
+ return;
+ }
+ }
+
+ /* Now read the local file header entries */
+ Int32 i;
+ for (i = 0; i < count; i++) {
+ ZipEntry* entry = &state->Entries[i];
+ result = stream->Seek(stream, entry->LocalHeaderOffset, STREAM_SEEKFROM_BEGIN);
+ ErrorHandler_CheckOrFail(result, "ZIP - Seek to local file header");
+
+ sig = Stream_ReadUInt32_LE(stream);
+ if (sig != ZIP_LOCALFILEHEADER) {
+ String sigMsg = String_FromConst("ZIP - Invalid entry found, skipping");
+ ErrorHandler_Log(&sigMsg);
+ continue;
+ }
+ Zip_ReadLocalFileHeader(state, entry);
+ }
+}
+
+
+/*########################################################################################################################*
+*--------------------------------------------------------EntryList--------------------------------------------------------*
+*#########################################################################################################################*/
typedef struct EntryList_ {
UInt8 FolderBuffer[String_BufferSize(STRING_SIZE)];
UInt8 FileBuffer[String_BufferSize(STRING_SIZE)];
@@ -90,6 +258,10 @@ void EntryList_Make(EntryList* list, STRING_PURE const UInt8* folder, STRING_PUR
EntryList_Load(list);
}
+
+/*########################################################################################################################*
+*------------------------------------------------------TextureCache-------------------------------------------------------*
+*#########################################################################################################################*/
#define TEXCACHE_FOLDER "texturecache"
/* Because I didn't store milliseconds in original C# client */
#define TEXCACHE_TICKS_PER_MS 10000LL
@@ -239,4 +411,125 @@ void TextureCache_AddLastModified(STRING_PURE String* url, DateTime* lastModifie
String data = String_InitAndClearArray(dataBuffer);
String_AppendInt64(&data, ticks);
TextureCache_AddToTags(url, &data, &cache_lastModified);
+}
+
+
+/*########################################################################################################################*
+*-------------------------------------------------------TexturePack-------------------------------------------------------*
+*#########################################################################################################################*/
+void TexturePack_ProcessZipEntry(STRING_TRANSIENT String* path, Stream* stream, ZipEntry* entry) {
+ /* Ignore directories: convert x/name to name and x\name to name. */
+ String_MakeLowercase(path);
+ String name = *path;
+ Int32 i;
+
+ i = String_LastIndexOf(&name, '\\');
+ if (i >= 0) { name = String_UNSAFE_SubstringAt(&name, i + 1); }
+ i = String_LastIndexOf(&name, '/');
+ if (i >= 0) { name = String_UNSAFE_SubstringAt(&name, i + 1); }
+
+ String_Set(&stream->Name, &name);
+ Event_RaiseStream(&TextureEvents_FileChanged, stream);
+}
+
+void TexturePack_ExtractZip(Stream* stream) {
+ Event_RaiseVoid(&TextureEvents_PackChanged);
+ if (Gfx_LostContext) return;
+
+ ZipState state;
+ Zip_Init(&state, stream);
+ state.ProcessEntry = TexturePack_ProcessZipEntry;
+ Zip_Extract(&state);
+}
+
+void TexturePack_ExtractZip_File(STRING_PURE String* filename) {
+ UInt8 pathBuffer[String_BufferSize(FILENAME_SIZE)];
+ String path = String_InitAndClearArray(pathBuffer);
+ String_Format2(&path, "texpacks%b%s", TEXCACHE_FOLDER, &Platform_DirectorySeparator, filename);
+
+ void* file;
+ ReturnCode result = Platform_FileOpen(&file, &path);
+ ErrorHandler_CheckOrFail(result, "TexturePack_Extract - opening file");
+
+ Stream stream;
+ Stream_FromFile(&stream, &file, &path);
+ TexturePack_ExtractZip(&stream);
+
+ result = stream.Close(&stream);
+ ErrorHandler_CheckOrFail(result, "TexturePack_Extract - closing file");
+}
+
+void TexturePack_ExtractTerrainPng(Stream* stream) {
+ Bitmap bmp; Bitmap_DecodePng(&bmp, stream);
+ Event_RaiseVoid(&TextureEvents_PackChanged);
+
+ if (Game_ChangeTerrainAtlas(&bmp)) return;
+ Platform_MemFree(&bmp.Scan0);
+}
+
+void TexturePack_ExtractDefault(void) {
+ UInt8 texPackBuffer[String_BufferSize(STRING_SIZE)];
+ String texPack = String_InitAndClearArray(texPackBuffer);
+ Game_GetDefaultTexturePack(&texPack);
+
+ TexturePack_ExtractZip_File(&texPack);
+ String_Clear(&World_TextureUrl);
+}
+
+void TexturePack_ExtractCurrent(STRING_PURE String* url) {
+ if (url->length == 0) { TexturePack_ExtractDefault(); return; }
+
+ Stream stream;
+ if (!TextureCache_GetStream(url, &stream)) {
+ /* e.g. 404 errors */
+ if (World_TextureUrl.length > 0) TexturePack_ExtractDefault();
+ } else {
+ String zip = String_FromConst(".zip");
+ if (String_Equals(url, &World_TextureUrl)) {
+ } else if (String_ContainsString(url, &zip)) {
+ String_Set(&World_TextureUrl, url);
+ TexturePack_ExtractZip(&stream);
+ } else {
+ String_Set(&World_TextureUrl, url);
+ TexturePack_ExtractTerrainPng(&stream);
+ }
+
+ ReturnCode result = stream.Close(&stream);
+ ErrorHandler_CheckOrFail(result, "TexturePack_ExtractCurrent - slow stream");
+ }
+}
+
+void TexturePack_ExtractTerrainPng_Req(AsyncRequest* item) {
+ if (item->ResultBitmap.Scan0 == NULL) return;
+ String url = String_FromRawArray(item->URL);
+ String_Set(&World_TextureUrl, &url);
+ Bitmap bmp = item->ResultBitmap;
+
+ String etag = String_FromRawArray(item->Etag);
+ TextureCache_AddImage(&url, &bmp);
+ TextureCache_AddETag(&url, &etag);
+ TextureCache_AddLastModified(&url, &item->LastModified);
+
+ Event_RaiseVoid(&TextureEvents_PackChanged);
+ if (!Game_ChangeTerrainAtlas(&bmp)) {
+ Platform_MemFree(&bmp.Scan0);
+ }
+}
+
+void TexturePack_ExtractTexturePack_Req(AsyncRequest* item) {
+ if (item->ResultData.Ptr == NULL) return;
+ String url = String_FromRawArray(item->URL);
+ String_Set(&World_TextureUrl, &url);
+ void* data = item->ResultData.Ptr;
+ UInt32 len = item->ResultData.Size;
+
+ String etag = String_FromRawArray(item->Etag);
+ TextureCache_AddData(&url, data, len);
+ TextureCache_AddETag(&url, &etag);
+ TextureCache_AddLastModified(&url, &item->LastModified);
+
+ String id = String_FromRawArray(item->ID);
+ Stream stream; Stream_ReadonlyMemory(&stream, data, len, &id);
+ TexturePack_ExtractZip(&stream);
+ stream.Close(&stream);
}
\ No newline at end of file
diff --git a/src/Client/TexturePack.h b/src/Client/TexturePack.h
new file mode 100644
index 000000000..32143b330
--- /dev/null
+++ b/src/Client/TexturePack.h
@@ -0,0 +1,49 @@
+#ifndef CC_TEXPACKS_H
+#define CC_TEXPACKS_H
+#include "String.h"
+/* Extracts entries from a .zip archive stream (mostly resources for .zip texture pack)
+ Caches terrain atlases and texture packs to avoid making redundant downloads.
+ Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
+*/
+typedef struct Stream_ Stream;
+typedef struct DateTime_ DateTime;
+typedef struct Bitmap_ Bitmap;
+typedef struct AsyncRequest_ AsyncRequest;
+
+typedef struct ZipEntry_ {
+ Int32 CompressedDataSize, UncompressedDataSize, LocalHeaderOffset; UInt32 Crc32;
+} ZipEntry;
+
+#define ZIP_MAX_ENTRIES 2048
+typedef struct ZipState_ {
+ Stream* Input;
+ void (*ProcessEntry)(STRING_TRANSIENT String* path, Stream* data, ZipEntry* entry);
+ bool (*SelectEntry)(STRING_PURE String* path);
+ Int32 EntriesCount;
+ ZipEntry Entries[ZIP_MAX_ENTRIES];
+} ZipState;
+
+void Zip_Init(ZipState* state, Stream* input);
+void Zip_Extract(ZipState* state);
+
+void TextureCache_Init(void);
+bool TextureCache_HasAccepted(STRING_PURE String* url);
+bool TextureCache_HasDenied(STRING_PURE String* url);
+void TextureCache_Accept(STRING_PURE String* url);
+void TextureCache_Deny(STRING_PURE String* url);
+
+bool TextureCache_HasUrl(STRING_PURE String* url);
+bool TextureCache_GetStream(STRING_PURE String* url, Stream* stream);
+void TextureCache_GetLastModified(STRING_PURE String* url, DateTime* time);
+void TextureCache_GetETag(STRING_PURE String* url, STRING_PURE String* etag);
+void TextureCache_AddImage(STRING_PURE String* url, Bitmap* bmp);
+void TextureCache_AddData(STRING_PURE String* url, UInt8* data, UInt32 length);
+void TextureCache_AddETag(STRING_PURE String* url, STRING_PURE String* etag);
+void TextureCache_AddLastModified(STRING_PURE String* url, DateTime* lastModified);
+
+void TexturePack_ExtractZip_File(STRING_PURE String* filename);
+void TexturePack_ExtractDefault(void);
+void TexturePack_ExtractCurrent(STRING_PURE String* url);
+void TexturePack_ExtractTerrainPng_Req(AsyncRequest* item);
+void TexturePack_ExtractTexturePack_Req(AsyncRequest* item);
+#endif
\ No newline at end of file
diff --git a/src/Client/ZipArchive.c b/src/Client/ZipArchive.c
deleted file mode 100644
index 46acb9a60..000000000
--- a/src/Client/ZipArchive.c
+++ /dev/null
@@ -1,159 +0,0 @@
-#include "ZipArchive.h"
-#include "ErrorHandler.h"
-#include "Platform.h"
-#include "Deflate.h"
-#include "Stream.h"
-
-String Zip_ReadFixedString(Stream* stream, UInt8* buffer, UInt16 length) {
- String fileName;
- fileName.buffer = buffer;
- fileName.length = length;
- fileName.capacity = length;
-
- Stream_Read(stream, buffer, length);
- buffer[length] = NULL; /* Ensure null terminated */
- return fileName;
-}
-
-void Zip_ReadLocalFileHeader(ZipState* state, ZipEntry* entry) {
- Stream* stream = state->Input;
- UInt16 versionNeeded = Stream_ReadUInt16_LE(stream);
- UInt16 flags = Stream_ReadUInt16_LE(stream);
- UInt16 compressionMethod = Stream_ReadUInt16_LE(stream);
- Stream_ReadUInt32_LE(stream); /* last modified */
- Stream_ReadUInt32_LE(stream); /* CRC32 */
-
- Int32 compressedSize = Stream_ReadInt32_LE(stream);
- if (compressedSize == 0) compressedSize = entry->CompressedDataSize;
- Int32 uncompressedSize = Stream_ReadInt32_LE(stream);
- if (uncompressedSize == 0) uncompressedSize = entry->UncompressedDataSize;
-
- UInt16 fileNameLen = Stream_ReadUInt16_LE(stream);
- UInt16 extraFieldLen = Stream_ReadUInt16_LE(stream);
- UInt8 filenameBuffer[String_BufferSize(UInt16_MaxValue)];
- String filename = Zip_ReadFixedString(stream, filenameBuffer, fileNameLen);
- if (!state->SelectEntry(&filename)) return;
-
- ReturnCode code = Stream_Skip(stream, extraFieldLen);
- ErrorHandler_CheckOrFail(code, "Zip - skipping local header extra");
- if (versionNeeded > 20) {
- String warnMsg = String_FromConst("May not be able to properly extract a .zip enty with a version later than 2.0");
- Platform_Log(&warnMsg);
- }
-
- Stream portion, compStream;
- if (compressionMethod == 0) {
- Stream_ReadonlyPortion(&portion, stream, uncompressedSize);
- state->ProcessEntry(&filename, &portion, entry);
- } else if (compressionMethod == 8) {
- DeflateState deflate;
- Stream_ReadonlyPortion(&portion, stream, compressedSize);
- Deflate_MakeStream(&compStream, &deflate, &portion);
- state->ProcessEntry(&filename, &compStream, entry);
- } else {
- String warnMsg = String_FromConst("Unsupported .zip entry compression method");
- Platform_Log(&warnMsg);
- }
-}
-
-void Zip_ReadCentralDirectory(ZipState* state, ZipEntry* entry) {
- Stream* stream = state->Input;
- Stream_ReadUInt16_LE(stream); /* OS */
- UInt16 versionNeeded = Stream_ReadUInt16_LE(stream);
- UInt16 flags = Stream_ReadUInt16_LE(stream);
- UInt16 compressionMethod = Stream_ReadUInt16_LE(stream);
- Stream_ReadUInt32_LE(stream); /* last modified */
- entry->Crc32 = Stream_ReadUInt32_LE(stream);
- entry->CompressedDataSize = Stream_ReadInt32_LE(stream);
- entry->UncompressedDataSize = Stream_ReadInt32_LE(stream);
-
- UInt16 fileNameLen = Stream_ReadUInt16_LE(stream);
- UInt16 extraFieldLen = Stream_ReadUInt16_LE(stream);
- UInt16 fileCommentLen = Stream_ReadUInt16_LE(stream);
- UInt16 diskNum = Stream_ReadUInt16_LE(stream);
- UInt16 internalAttributes = Stream_ReadUInt16_LE(stream);
- UInt32 externalAttributes = Stream_ReadUInt32_LE(stream);
- entry->LocalHeaderOffset = Stream_ReadInt32_LE(stream);
-
- UInt32 extraDataLen = fileNameLen + extraFieldLen + fileCommentLen;
- ReturnCode code = Stream_Skip(stream, extraDataLen);
- ErrorHandler_CheckOrFail(code, "Zip - skipping central header extra");
-}
-
-void Zip_ReadEndOfCentralDirectory(ZipState* state, Int32* centralDirectoryOffset) {
- Stream* stream = state->Input;
- UInt16 diskNum = Stream_ReadUInt16_LE(stream);
- UInt16 diskNumStart = Stream_ReadUInt16_LE(stream);
- UInt16 diskEntries = Stream_ReadUInt16_LE(stream);
- state->EntriesCount = Stream_ReadUInt16_LE(stream);
- Int32 centralDirectorySize = Stream_ReadInt32_LE(stream);
- *centralDirectoryOffset = Stream_ReadInt32_LE(stream);
- UInt16 commentLength = Stream_ReadUInt16_LE(stream);
-}
-
-
-#define ZIP_ENDOFCENTRALDIR 0x06054b50UL
-#define ZIP_CENTRALDIR 0x02014b50UL
-#define ZIP_LOCALFILEHEADER 0x04034b50UL
-
-void Zip_DefaultProcessor(STRING_TRANSIENT String* path, Stream* data, ZipEntry* entry) { }
-bool Zip_DefaultSelector(STRING_TRANSIENT String* path) { return true; }
-void Zip_Init(ZipState* state, Stream* input) {
- state->Input = input;
- state->EntriesCount = 0;
- state->ProcessEntry = Zip_DefaultProcessor;
- state->SelectEntry = Zip_DefaultSelector;
-}
-
-void Zip_Extract(ZipState* state) {
- state->EntriesCount = 0;
- Stream* stream = state->Input;
- ReturnCode result = stream->Seek(stream, -22, STREAM_SEEKFROM_END);
- ErrorHandler_CheckOrFail(result, "ZIP - Seek to end of central directory");
-
- UInt32 sig = Stream_ReadUInt32_LE(stream);
- if (sig != ZIP_ENDOFCENTRALDIR) {
- ErrorHandler_Fail("ZIP - Comment in .zip file not supported");
- return;
- }
-
- Int32 centralDirectoryOffset;
- Zip_ReadEndOfCentralDirectory(state, ¢ralDirectoryOffset);
- result = stream->Seek(stream, centralDirectoryOffset, STREAM_SEEKFROM_BEGIN);
- ErrorHandler_CheckOrFail(result, "ZIP - Seek to central directory");
- if (state->EntriesCount > ZIP_MAX_ENTRIES) {
- ErrorHandler_Fail("ZIP - Max of 2048 entries supported");
- }
-
- /* Read all the central directory entries */
- Int32 count = 0;
- while (count < state->EntriesCount) {
- sig = Stream_ReadUInt32_LE(stream);
- if (sig == ZIP_CENTRALDIR) {
- Zip_ReadCentralDirectory(state, &state->Entries[count]);
- count++;
- } else if (sig == ZIP_ENDOFCENTRALDIR) {
- break;
- } else {
- String sigMsg = String_FromConst("ZIP - Unsupported signature found, aborting");
- ErrorHandler_Log(&sigMsg);
- return;
- }
- }
-
- /* Now read the local file header entries */
- Int32 i;
- for (i = 0; i < count; i++) {
- ZipEntry* entry = &state->Entries[i];
- result = stream->Seek(stream, entry->LocalHeaderOffset, STREAM_SEEKFROM_BEGIN);
- ErrorHandler_CheckOrFail(result, "ZIP - Seek to local file header");
-
- sig = Stream_ReadUInt32_LE(stream);
- if (sig != ZIP_LOCALFILEHEADER) {
- String sigMsg = String_FromConst("ZIP - Invalid entry found, skipping");
- ErrorHandler_Log(&sigMsg);
- continue;
- }
- Zip_ReadLocalFileHeader(state, entry);
- }
-}
\ No newline at end of file
diff --git a/src/Client/ZipArchive.h b/src/Client/ZipArchive.h
deleted file mode 100644
index c8d3d59f0..000000000
--- a/src/Client/ZipArchive.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef CC_ZIPARCHIVE_H
-#define CC_ZIPARCHIVE_H
-#include "String.h"
-/* Extracts entries from a .zip archive stream.
- Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
-*/
-typedef struct Stream_ Stream;
-
-typedef struct ZipEntry_ {
- Int32 CompressedDataSize, UncompressedDataSize, LocalHeaderOffset;
- UInt32 Crc32;
-} ZipEntry;
-
-#define ZIP_MAX_ENTRIES 2048
-typedef struct ZipState_ {
- Stream* Input;
- void (*ProcessEntry)(STRING_TRANSIENT String* path, Stream* data, ZipEntry* entry);
- bool (*SelectEntry)(STRING_TRANSIENT String* path);
- Int32 EntriesCount;
- ZipEntry Entries[ZIP_MAX_ENTRIES];
-} ZipState;
-
-void Zip_Init(ZipState* state, Stream* input);
-void Zip_Extract(ZipState* state);
-#endif
\ No newline at end of file