mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-17 11:35:08 -04:00
Port TexturePack to C
This commit is contained in:
parent
8a25708f6f
commit
7c674c4e82
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -229,6 +229,7 @@
|
||||
<ClInclude Include="Stream.h" />
|
||||
<ClInclude Include="GameStructs.h" />
|
||||
<ClInclude Include="TerrainAtlas.h" />
|
||||
<ClInclude Include="TexturePack.h" />
|
||||
<ClInclude Include="TreeGen.h" />
|
||||
<ClInclude Include="Utils.h" />
|
||||
<ClInclude Include="WeatherRenderer.h" />
|
||||
@ -250,7 +251,6 @@
|
||||
<ClInclude Include="Window.h" />
|
||||
<ClInclude Include="WordWrap.h" />
|
||||
<ClInclude Include="World.h" />
|
||||
<ClInclude Include="ZipArchive.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="2DStructs.c" />
|
||||
@ -320,7 +320,6 @@
|
||||
<ClCompile Include="WinWindow.c" />
|
||||
<ClCompile Include="WordWrap.c" />
|
||||
<ClCompile Include="World.c" />
|
||||
<ClCompile Include="ZipArchive.c" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
@ -300,9 +300,6 @@
|
||||
<ClInclude Include="Formats.h">
|
||||
<Filter>Header Files\Map</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ZipArchive.h">
|
||||
<Filter>Header Files\TexturePack</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Gui.h">
|
||||
<Filter>Header Files\2D</Filter>
|
||||
</ClInclude>
|
||||
@ -366,6 +363,9 @@
|
||||
<ClInclude Include="Menus.h">
|
||||
<Filter>Header Files\2D</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TexturePack.h">
|
||||
<Filter>Header Files\TexturePack</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Noise.c">
|
||||
@ -503,9 +503,6 @@
|
||||
<ClCompile Include="Formats.c">
|
||||
<Filter>Source Files\Map</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZipArchive.c">
|
||||
<Filter>Source Files\TexturePack</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Gui.c">
|
||||
<Filter>Source Files\2D</Filter>
|
||||
</ClCompile>
|
||||
|
@ -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)
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "GraphicsAPI.h"
|
||||
#include "Deflate.h"
|
||||
#include "Formats.h"
|
||||
#include "ZipArchive.h"
|
||||
#include "TexturePack.h"
|
||||
#include "Bitmap.h"
|
||||
#include <Windows.h>
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
49
src/Client/TexturePack.h
Normal file
49
src/Client/TexturePack.h
Normal file
@ -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
|
@ -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);
|
||||
}
|
||||
}
|
@ -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
|
Loading…
x
Reference in New Issue
Block a user