From 7813b5719e81a8ce30782f469a21e6dac7ff06a7 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Fri, 21 Dec 2018 10:05:09 +1100 Subject: [PATCH] Fix .zip with too many entries not getting loaded --- src/Constants.h | 7 +++--- src/Deflate.c | 45 +++++++++++++++++++++++---------------- src/Deflate.h | 13 ++++++++---- src/Game.c | 48 ++++++++++++++++++++++++++++++++---------- src/LScreens.c | 2 +- src/Launcher.c | 2 +- src/Platform.c | 4 ++-- src/Program.c | 6 +++--- src/Resources.c | 42 ++++++++++++++++++------------------ src/ServerConnection.c | 2 +- 10 files changed, 106 insertions(+), 65 deletions(-) diff --git a/src/Constants.h b/src/Constants.h index b1a9b05a4..26d53ae33 100644 --- a/src/Constants.h +++ b/src/Constants.h @@ -4,9 +4,10 @@ Copyright 2017 ClassicalSharp | Licensed under BSD-3 */ -#define PROGRAM_MAX_CMDARGS 5 -#define PROGRAM_APP_NAME "ClassiCube 0.99.9.2" -#define PROGRAM_APP_VER "0.99.9.2" +#define GAME_MAX_CMDARGS 5 +#define GAME_APP_NAME "ClassiCube 0.99.9.2" +#define GAME_APP_VER "0.99.9.2" +#define GAME_API_VER 1 /* Max number of characters strings can have. */ #define STRING_SIZE 64 diff --git a/src/Deflate.c b/src/Deflate.c index cae284911..df2d678b3 100644 --- a/src/Deflate.c +++ b/src/Deflate.c @@ -1107,34 +1107,45 @@ static ReturnCode Zip_ReadLocalFileHeader(struct ZipState* state, struct ZipEntr return 0; } -static ReturnCode Zip_ReadCentralDirectory(struct ZipState* state, struct ZipEntry* entry) { +static ReturnCode Zip_ReadCentralDirectory(struct ZipState* state) { struct Stream* stream = state->Input; + struct ZipEntry* entry; uint8_t header[42]; + + String path; char pathBuffer[ZIP_MAXNAMELEN]; int pathLen, extraLen, commentLen; ReturnCode res; if ((res = Stream_Read(stream, header, sizeof(header)))) return res; - entry->CompressedSize = Stream_GetU32_LE(&header[16]); - entry->UncompressedSize = Stream_GetU32_LE(&header[20]); + pathLen = Stream_GetU16_LE(&header[24]); + path = String_Init(pathBuffer, pathLen, pathLen); + if (pathLen > ZIP_MAXNAMELEN) return ZIP_ERR_FILENAME_LEN; + if ((res = Stream_Read(stream, pathBuffer, pathLen))) return res; - pathLen = Stream_GetU16_LE(&header[24]); + /* skip data following central directory entry header */ extraLen = Stream_GetU16_LE(&header[26]); commentLen = Stream_GetU16_LE(&header[28]); + if ((res = stream->Skip(stream, extraLen + commentLen))) return res; + if (!state->SelectEntry(&path)) return 0; + if (state->_usedEntries >= ZIP_MAX_ENTRIES) return ZIP_ERR_TOO_MANY_ENTRIES; + entry = &state->Entries[state->_usedEntries++]; + + entry->CompressedSize = Stream_GetU32_LE(&header[16]); + entry->UncompressedSize = Stream_GetU32_LE(&header[20]); entry->LocalHeaderOffset = Stream_GetU32_LE(&header[38]); - /* skip data following central directory entry header */ - return stream->Skip(stream, pathLen + extraLen + commentLen); + return 0; } -static ReturnCode Zip_ReadEndOfCentralDirectory(struct ZipState* state, uint32_t* centralDirectoryOffset) { +static ReturnCode Zip_ReadEndOfCentralDirectory(struct ZipState* state) { struct Stream* stream = state->Input; uint8_t header[18]; ReturnCode res; if ((res = Stream_Read(stream, header, sizeof(header)))) return res; - state->EntriesCount = Stream_GetU16_LE(&header[6]); - *centralDirectoryOffset = Stream_GetU32_LE(&header[12]); + state->_totalEntries = Stream_GetU16_LE(&header[6]); + state->_centralDirBeg = Stream_GetU32_LE(&header[12]); return 0; } @@ -1149,19 +1160,17 @@ static bool Zip_DefaultSelector(const String* path) { return true; } void Zip_Init(struct ZipState* state, struct Stream* input) { state->Input = input; state->Obj = NULL; - state->EntriesCount = 0; state->ProcessEntry = Zip_DefaultProcessor; state->SelectEntry = Zip_DefaultSelector; } ReturnCode Zip_Extract(struct ZipState* state) { struct Stream* stream = state->Input; - uint32_t stream_len, centralDirOffset; + uint32_t stream_len; uint32_t sig = 0; int i, count; ReturnCode res; - state->EntriesCount = 0; if ((res = stream->Length(stream, &stream_len))) return res; /* At -22 for nearly all zips, but try a bit further back in case of comment */ @@ -1175,19 +1184,19 @@ ReturnCode Zip_Extract(struct ZipState* state) { } if (sig != ZIP_SIG_ENDOFCENTRALDIR) return ZIP_ERR_NO_END_OF_CENTRAL_DIR; - res = Zip_ReadEndOfCentralDirectory(state, ¢ralDirOffset); + res = Zip_ReadEndOfCentralDirectory(state); if (res) return res; - res = stream->Seek(stream, centralDirOffset); + res = stream->Seek(stream, state->_centralDirBeg); if (res) return ZIP_ERR_SEEK_CENTRAL_DIR; - if (state->EntriesCount > ZIP_MAX_ENTRIES) return ZIP_ERR_TOO_MANY_ENTRIES; + state->_usedEntries = 0; /* Read all the central directory entries */ - for (count = 0; count < state->EntriesCount; count++) { + for (i = 0; i < state->_totalEntries; i++) { if ((res = Stream_ReadU32_LE(stream, &sig))) return res; if (sig == ZIP_SIG_CENTRALDIR) { - res = Zip_ReadCentralDirectory(state, &state->Entries[count]); + res = Zip_ReadCentralDirectory(state); if (res) return res; } else if (sig == ZIP_SIG_ENDOFCENTRALDIR) { break; @@ -1197,7 +1206,7 @@ ReturnCode Zip_Extract(struct ZipState* state) { } /* Now read the local file header entries */ - for (i = 0; i < count; i++) { + for (i = 0; i < state->_usedEntries; i++) { struct ZipEntry* entry = &state->Entries[i]; res = stream->Seek(stream, entry->LocalHeaderOffset); if (res) return ZIP_ERR_SEEK_LOCAL_DIR; diff --git a/src/Deflate.h b/src/Deflate.h index 7455703c7..aa266277e 100644 --- a/src/Deflate.h +++ b/src/Deflate.h @@ -67,7 +67,7 @@ struct InflateState { /* Initialises DEFLATE decompressor state to defaults. */ CC_API void Inflate_Init(struct InflateState* state, struct Stream* source); -/* Attempts to decompress all currently pending data. */ +/* Attempts to decompress as much of the currently pending data as possible. */ /* NOTE: This is a low level call - usually you should use Inflate_MakeStream. */ void Inflate_Process(struct InflateState* state); /* Deompresses input data read from another stream using DEFLATE. Read only stream. */ @@ -122,13 +122,18 @@ struct ZipState { /* Return non-zero to indicate an error and stop further processing. */ /* NOTE: data stream MAY NOT be seekable. (i.e. entry data might be compressed) */ ReturnCode (*ProcessEntry)(const String* path, struct Stream* data, void* obj); - /* Predicate used to select which entries in a .zip archive get proessed. */ + /* Predicate used to select which entries in a .zip archive get processed. */ /* NOTE: returning false entirely skips the entry. (avoids pointless seek to entry) */ bool (*SelectEntry)(const String* path); /* Generic object/pointer passed to ProcessEntry callback. */ void* Obj; - /* Number of entries in the .zip archive. */ - int EntriesCount; + + /* (internal) Number of entries selected by SelectEntry. */ + int _usedEntries; + /* (internal) Total number of entries in the archive. */ + int _totalEntries; + /* (internal) Offset to central directory entries. */ + uint32_t _centralDirBeg; /* Data for each entry in the .zip archive. */ struct ZipEntry Entries[ZIP_MAX_ENTRIES]; }; diff --git a/src/Game.c b/src/Game.c index 40499b1f2..f8b090f11 100644 --- a/src/Game.c +++ b/src/Game.c @@ -372,6 +372,41 @@ static void Game_LoadOptions(void) { }*/ } +static void Game_LoadPlugin(const String* filename, void* obj) { + void* lib; + void* verSymbol; /* EXPORT int Plugin_ApiVersion = GAME_API_VER; */ + void* compSymbol; /* EXPORT struct IGameComponent Plugin_Component = { (whatever) } */ + int ver; + ReturnCode res; + + res = Platform_LoadLibrary(filename, &lib); + if (res) { Chat_LogError2(res, "loading plugin", filename); return; } + + res = Platform_GetSymbol(lib, "Plugin_ApiVersion", &verSymbol); + if (res) { Chat_LogError2(res, "getting plugin version", filename); return; } + res = Platform_GetSymbol(lib, "Plugin_Component", &compSymbol); + if (res) { Chat_LogError2(res, "initing plugin", filename); return; } + + ver = *((int*)verSymbol); + if (ver < GAME_API_VER) { + Chat_Add1("&c%s plugin is outdated! Try getting a more recent version.", filename); + return; + } else if (ver > GAME_API_VER) { + Chat_Add1("&cYour game is too outdated to use %s plugin! Try updating it.", filename); + return; + } + + Game_AddComponent((struct IGameComponent*)compSymbol); +} + +static void Game_LoadPlugins(void) { + const static String dir = String_FromConst("plugins"); + ReturnCode res; + + res = Directory_Enum(&dir, NULL, Game_LoadPlugin); + if (res) Chat_LogError(res, "enumerating plugins directory"); +} + void Game_Free(void* obj); static void Game_Load(void) { String title; char titleBuffer[STRING_SIZE]; @@ -438,22 +473,13 @@ static void Game_Load(void) { Game_AddComponent(&Audio_Component); Game_AddComponent(&AxisLinesRenderer_Component); - /* TODO: plugin dll support */ - /* List nonLoaded = PluginLoader.LoadAll(); */ - + //Game_LoadPlugins(); for (comp = comps_head; comp; comp = comp->Next) { if (comp->Init) comp->Init(); } - Game_ExtractInitialTexturePack(); + Game_ExtractInitialTexturePack(); entTaskI = ScheduledTask_Add(GAME_DEF_TICKS, Entities_Tick); - /* TODO: plugin dll support */ - /* if (nonLoaded != null) { - for (int i = 0; i < nonLoaded.Count; i++) { - Overlay warning = new PluginOverlay(this, nonLoaded[i]); - Gui_ShowOverlay(warning, false); - } - }*/ if (Gfx_WarnIfNecessary()) EnvRenderer_SetMode(EnvRenderer_Minimal | ENV_LEGACY); String_InitArray(title, titleBuffer); diff --git a/src/LScreens.c b/src/LScreens.c index 820d81a64..9f289ec03 100644 --- a/src/LScreens.c +++ b/src/LScreens.c @@ -828,7 +828,7 @@ static void MainScreen_TickCheckUpdates(struct MainScreen* s) { const static String needUpdate = String_FromConst("&aNew release"); const static String upToDate = String_FromConst("&eUp to date"); const static String failed = String_FromConst("&cCheck failed"); - const static String currentStr = String_FromConst(PROGRAM_APP_VER); + const static String currentStr = String_FromConst(GAME_APP_VER); uint32_t latest, current; if (!CheckUpdateTask.Base.Working) return; diff --git a/src/Launcher.c b/src/Launcher.c index 869c0ca09..341de14d3 100644 --- a/src/Launcher.c +++ b/src/Launcher.c @@ -235,7 +235,7 @@ static void Launcher_Free(void) { } void Launcher_Run(void) { - const static String title = String_FromConst(PROGRAM_APP_NAME); + const static String title = String_FromConst(GAME_APP_NAME); Window_CreateSimple(640, 400); Window_SetTitle(&title); Window_SetVisible(true); diff --git a/src/Platform.c b/src/Platform.c index a77bb27fc..049f19296 100644 --- a/src/Platform.c +++ b/src/Platform.c @@ -1333,7 +1333,7 @@ static HINTERNET hInternet; void Http_Init(void) { /* TODO: Should we use INTERNET_OPEN_TYPE_PRECONFIG instead? */ - hInternet = InternetOpenA(PROGRAM_APP_NAME, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); + hInternet = InternetOpenA(GAME_APP_NAME, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); if (!hInternet) ErrorHandler_Fail2(GetLastError(), "Failed to init WinINet"); } @@ -2031,7 +2031,7 @@ int Platform_GetCommandLineArgs(int argc, STRING_REF const char** argv, String* int i; Platform_NextArg(&cmdArgs); /* skip exe path */ - for (i = 0; i < PROGRAM_MAX_CMDARGS; i++) { + for (i = 0; i < GAME_MAX_CMDARGS; i++) { args[i] = Platform_NextArg(&cmdArgs); if (!args[i].length) break; diff --git a/src/Program.c b/src/Program.c index 8fc0f98d4..6c1f459b7 100644 --- a/src/Program.c +++ b/src/Program.c @@ -61,12 +61,12 @@ static void Program_RunGame(void) { } String_InitArray(title, titleBuffer); - String_Format2(&title, "%c (%s)", PROGRAM_APP_NAME, &Game_Username); + String_Format2(&title, "%c (%s)", GAME_APP_NAME, &Game_Username); Game_Run(width, height, &title); } int main(int argc, char** argv) { - String args[PROGRAM_MAX_CMDARGS]; + String args[GAME_MAX_CMDARGS]; int argsCount; uint8_t ip[4]; uint16_t port; @@ -82,7 +82,7 @@ int main(int argc, char** argv) { #ifdef CC_TEST_VORBIS main_imdct(); #endif - Platform_LogConst("Starting " PROGRAM_APP_NAME " .."); + Platform_LogConst("Starting " GAME_APP_NAME " .."); Utils_EnsureDirectory("maps"); Utils_EnsureDirectory("texpacks"); diff --git a/src/Resources.c b/src/Resources.c index e2fcb0b75..1a05d9e43 100644 --- a/src/Resources.c +++ b/src/Resources.c @@ -172,11 +172,11 @@ struct ResourceMusic Resources_Music[7] = { /*########################################################################################################################* *---------------------------------------------------------Zip writer------------------------------------------------------* *#########################################################################################################################*/ -static ReturnCode ZipPatcher_LocalFile(struct Stream* s, struct ResourceTexture* entry) { - String name = String_FromReadonly(entry->Filename); +static ReturnCode ZipPatcher_LocalFile(struct Stream* s, struct ResourceTexture* e) { + String name = String_FromReadonly(e->Filename); uint8_t header[30 + STRING_SIZE]; ReturnCode res; - if ((res = s->Position(s, &entry->Offset))) return res; + if ((res = s->Position(s, &e->Offset))) return res; Stream_SetU32_LE(&header[0], 0x04034b50); /* signature */ Stream_SetU16_LE(&header[4], 20); /* version needed */ @@ -184,11 +184,11 @@ static ReturnCode ZipPatcher_LocalFile(struct Stream* s, struct ResourceTexture* Stream_SetU16_LE(&header[8] , 0); /* compression method */ Stream_SetU16_LE(&header[10], 0); /* last modified */ Stream_SetU16_LE(&header[12], 0); /* last modified */ - - Stream_SetU32_LE(&header[14], 0); /* CRC32 */ - Stream_SetU32_LE(&header[18], 0); /* Compressed size */ - Stream_SetU32_LE(&header[22], 0); /* Uncompressed size */ - + + Stream_SetU32_LE(&header[14], e->Crc32); /* CRC32 */ + Stream_SetU32_LE(&header[18], e->Size); /* Compressed size */ + Stream_SetU32_LE(&header[22], e->Size); /* Uncompressed size */ + Stream_SetU16_LE(&header[26], name.length); /* name length */ Stream_SetU16_LE(&header[28], 0); /* extra field length */ @@ -196,8 +196,8 @@ static ReturnCode ZipPatcher_LocalFile(struct Stream* s, struct ResourceTexture* return Stream_Write(s, header, 30 + name.length); } -static ReturnCode ZipPatcher_CentralDir(struct Stream* s, struct ResourceTexture* res) { - String name = String_FromReadonly(res->Filename); +static ReturnCode ZipPatcher_CentralDir(struct Stream* s, struct ResourceTexture* e) { + String name = String_FromReadonly(e->Filename); uint8_t header[46 + STRING_SIZE]; struct DateTime now; int modTime, modDate; @@ -206,17 +206,17 @@ static ReturnCode ZipPatcher_CentralDir(struct Stream* s, struct ResourceTexture modTime = (now.Second / 2) | (now.Minute << 5) | (now.Hour << 11); modDate = (now.Day) | (now.Month << 5) | ((now.Year - 1980) << 9); - Stream_SetU32_LE(&header[0], 0x02014b50); /* signature */ - Stream_SetU16_LE(&header[4], 20); /* version */ - Stream_SetU16_LE(&header[6], 20); /* version needed */ - Stream_SetU16_LE(&header[8], 0); /* bitflags */ - Stream_SetU16_LE(&header[10], 0); /* compression method */ - Stream_SetU16_LE(&header[12], modTime); /* last modified */ - Stream_SetU16_LE(&header[14], modDate); /* last modified */ + Stream_SetU32_LE(&header[0], 0x02014b50); /* signature */ + Stream_SetU16_LE(&header[4], 20); /* version */ + Stream_SetU16_LE(&header[6], 20); /* version needed */ + Stream_SetU16_LE(&header[8], 0); /* bitflags */ + Stream_SetU16_LE(&header[10], 0); /* compression method */ + Stream_SetU16_LE(&header[12], modTime); /* last modified */ + Stream_SetU16_LE(&header[14], modDate); /* last modified */ - Stream_SetU32_LE(&header[16], res->Crc32); /* CRC32 */ - Stream_SetU32_LE(&header[20], res->Size); /* compressed size */ - Stream_SetU32_LE(&header[24], res->Size); /* uncompressed size */ + Stream_SetU32_LE(&header[16], e->Crc32); /* CRC32 */ + Stream_SetU32_LE(&header[20], e->Size); /* compressed size */ + Stream_SetU32_LE(&header[24], e->Size); /* uncompressed size */ Stream_SetU16_LE(&header[28], name.length); /* name length */ Stream_SetU16_LE(&header[30], 0); /* extra field length */ @@ -224,7 +224,7 @@ static ReturnCode ZipPatcher_CentralDir(struct Stream* s, struct ResourceTexture Stream_SetU16_LE(&header[34], 0); /* disk number */ Stream_SetU16_LE(&header[36], 0); /* internal attributes */ Stream_SetU32_LE(&header[38], 0); /* external attributes */ - Stream_SetU32_LE(&header[42], res->Offset); /* local header offset */ + Stream_SetU32_LE(&header[42], e->Offset); /* local header offset */ Mem_Copy(&header[46], name.buffer, name.length); return Stream_Write(s, header, 46 + name.length); diff --git a/src/ServerConnection.c b/src/ServerConnection.c index 3e498891e..08f5c8d04 100644 --- a/src/ServerConnection.c +++ b/src/ServerConnection.c @@ -561,7 +561,7 @@ static void ServerConnection_Init(void) { Gfx_LostContextFunction = ServerConnection.Tick; ScheduledTask_Add(GAME_NET_TICKS, ServerConnection.Tick); - String_AppendConst(&ServerConnection_AppName, PROGRAM_APP_NAME); + String_AppendConst(&ServerConnection_AppName, GAME_APP_NAME); } static void ServerConnection_Free(void) {