Fix .zip with too many entries not getting loaded

This commit is contained in:
UnknownShadow200 2018-12-21 10:05:09 +11:00
parent 5de42ad3d3
commit 7813b5719e
10 changed files with 106 additions and 65 deletions

View File

@ -4,9 +4,10 @@
Copyright 2017 ClassicalSharp | Licensed under BSD-3 Copyright 2017 ClassicalSharp | Licensed under BSD-3
*/ */
#define PROGRAM_MAX_CMDARGS 5 #define GAME_MAX_CMDARGS 5
#define PROGRAM_APP_NAME "ClassiCube 0.99.9.2" #define GAME_APP_NAME "ClassiCube 0.99.9.2"
#define PROGRAM_APP_VER "0.99.9.2" #define GAME_APP_VER "0.99.9.2"
#define GAME_API_VER 1
/* Max number of characters strings can have. */ /* Max number of characters strings can have. */
#define STRING_SIZE 64 #define STRING_SIZE 64

View File

@ -1107,34 +1107,45 @@ static ReturnCode Zip_ReadLocalFileHeader(struct ZipState* state, struct ZipEntr
return 0; 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 Stream* stream = state->Input;
struct ZipEntry* entry;
uint8_t header[42]; uint8_t header[42];
String path; char pathBuffer[ZIP_MAXNAMELEN];
int pathLen, extraLen, commentLen; int pathLen, extraLen, commentLen;
ReturnCode res; ReturnCode res;
if ((res = Stream_Read(stream, header, sizeof(header)))) return 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]); 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;
/* skip data following central directory entry header */
extraLen = Stream_GetU16_LE(&header[26]); extraLen = Stream_GetU16_LE(&header[26]);
commentLen = Stream_GetU16_LE(&header[28]); 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]); entry->LocalHeaderOffset = Stream_GetU32_LE(&header[38]);
/* skip data following central directory entry header */ return 0;
return stream->Skip(stream, pathLen + extraLen + commentLen);
} }
static ReturnCode Zip_ReadEndOfCentralDirectory(struct ZipState* state, uint32_t* centralDirectoryOffset) { static ReturnCode Zip_ReadEndOfCentralDirectory(struct ZipState* state) {
struct Stream* stream = state->Input; struct Stream* stream = state->Input;
uint8_t header[18]; uint8_t header[18];
ReturnCode res; ReturnCode res;
if ((res = Stream_Read(stream, header, sizeof(header)))) return res; if ((res = Stream_Read(stream, header, sizeof(header)))) return res;
state->EntriesCount = Stream_GetU16_LE(&header[6]); state->_totalEntries = Stream_GetU16_LE(&header[6]);
*centralDirectoryOffset = Stream_GetU32_LE(&header[12]); state->_centralDirBeg = Stream_GetU32_LE(&header[12]);
return 0; return 0;
} }
@ -1149,19 +1160,17 @@ static bool Zip_DefaultSelector(const String* path) { return true; }
void Zip_Init(struct ZipState* state, struct Stream* input) { void Zip_Init(struct ZipState* state, struct Stream* input) {
state->Input = input; state->Input = input;
state->Obj = NULL; state->Obj = NULL;
state->EntriesCount = 0;
state->ProcessEntry = Zip_DefaultProcessor; state->ProcessEntry = Zip_DefaultProcessor;
state->SelectEntry = Zip_DefaultSelector; state->SelectEntry = Zip_DefaultSelector;
} }
ReturnCode Zip_Extract(struct ZipState* state) { ReturnCode Zip_Extract(struct ZipState* state) {
struct Stream* stream = state->Input; struct Stream* stream = state->Input;
uint32_t stream_len, centralDirOffset; uint32_t stream_len;
uint32_t sig = 0; uint32_t sig = 0;
int i, count; int i, count;
ReturnCode res; ReturnCode res;
state->EntriesCount = 0;
if ((res = stream->Length(stream, &stream_len))) return res; 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 */ /* 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; if (sig != ZIP_SIG_ENDOFCENTRALDIR) return ZIP_ERR_NO_END_OF_CENTRAL_DIR;
res = Zip_ReadEndOfCentralDirectory(state, &centralDirOffset); res = Zip_ReadEndOfCentralDirectory(state);
if (res) return res; if (res) return res;
res = stream->Seek(stream, centralDirOffset); res = stream->Seek(stream, state->_centralDirBeg);
if (res) return ZIP_ERR_SEEK_CENTRAL_DIR; 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 */ /* 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 ((res = Stream_ReadU32_LE(stream, &sig))) return res;
if (sig == ZIP_SIG_CENTRALDIR) { if (sig == ZIP_SIG_CENTRALDIR) {
res = Zip_ReadCentralDirectory(state, &state->Entries[count]); res = Zip_ReadCentralDirectory(state);
if (res) return res; if (res) return res;
} else if (sig == ZIP_SIG_ENDOFCENTRALDIR) { } else if (sig == ZIP_SIG_ENDOFCENTRALDIR) {
break; break;
@ -1197,7 +1206,7 @@ ReturnCode Zip_Extract(struct ZipState* state) {
} }
/* Now read the local file header entries */ /* 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]; struct ZipEntry* entry = &state->Entries[i];
res = stream->Seek(stream, entry->LocalHeaderOffset); res = stream->Seek(stream, entry->LocalHeaderOffset);
if (res) return ZIP_ERR_SEEK_LOCAL_DIR; if (res) return ZIP_ERR_SEEK_LOCAL_DIR;

View File

@ -67,7 +67,7 @@ struct InflateState {
/* Initialises DEFLATE decompressor state to defaults. */ /* Initialises DEFLATE decompressor state to defaults. */
CC_API void Inflate_Init(struct InflateState* state, struct Stream* source); 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. */ /* NOTE: This is a low level call - usually you should use Inflate_MakeStream. */
void Inflate_Process(struct InflateState* state); void Inflate_Process(struct InflateState* state);
/* Deompresses input data read from another stream using DEFLATE. Read only stream. */ /* 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. */ /* 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) */ /* NOTE: data stream MAY NOT be seekable. (i.e. entry data might be compressed) */
ReturnCode (*ProcessEntry)(const String* path, struct Stream* data, void* obj); 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) */ /* NOTE: returning false entirely skips the entry. (avoids pointless seek to entry) */
bool (*SelectEntry)(const String* path); bool (*SelectEntry)(const String* path);
/* Generic object/pointer passed to ProcessEntry callback. */ /* Generic object/pointer passed to ProcessEntry callback. */
void* Obj; 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. */ /* Data for each entry in the .zip archive. */
struct ZipEntry Entries[ZIP_MAX_ENTRIES]; struct ZipEntry Entries[ZIP_MAX_ENTRIES];
}; };

View File

@ -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); void Game_Free(void* obj);
static void Game_Load(void) { static void Game_Load(void) {
String title; char titleBuffer[STRING_SIZE]; String title; char titleBuffer[STRING_SIZE];
@ -438,22 +473,13 @@ static void Game_Load(void) {
Game_AddComponent(&Audio_Component); Game_AddComponent(&Audio_Component);
Game_AddComponent(&AxisLinesRenderer_Component); Game_AddComponent(&AxisLinesRenderer_Component);
/* TODO: plugin dll support */ //Game_LoadPlugins();
/* List<string> nonLoaded = PluginLoader.LoadAll(); */
for (comp = comps_head; comp; comp = comp->Next) { for (comp = comps_head; comp; comp = comp->Next) {
if (comp->Init) comp->Init(); if (comp->Init) comp->Init();
} }
Game_ExtractInitialTexturePack();
Game_ExtractInitialTexturePack();
entTaskI = ScheduledTask_Add(GAME_DEF_TICKS, Entities_Tick); 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); if (Gfx_WarnIfNecessary()) EnvRenderer_SetMode(EnvRenderer_Minimal | ENV_LEGACY);
String_InitArray(title, titleBuffer); String_InitArray(title, titleBuffer);

View File

@ -828,7 +828,7 @@ static void MainScreen_TickCheckUpdates(struct MainScreen* s) {
const static String needUpdate = String_FromConst("&aNew release"); const static String needUpdate = String_FromConst("&aNew release");
const static String upToDate = String_FromConst("&eUp to date"); const static String upToDate = String_FromConst("&eUp to date");
const static String failed = String_FromConst("&cCheck failed"); 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; uint32_t latest, current;
if (!CheckUpdateTask.Base.Working) return; if (!CheckUpdateTask.Base.Working) return;

View File

@ -235,7 +235,7 @@ static void Launcher_Free(void) {
} }
void Launcher_Run(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_CreateSimple(640, 400);
Window_SetTitle(&title); Window_SetTitle(&title);
Window_SetVisible(true); Window_SetVisible(true);

View File

@ -1333,7 +1333,7 @@ static HINTERNET hInternet;
void Http_Init(void) { void Http_Init(void) {
/* TODO: Should we use INTERNET_OPEN_TYPE_PRECONFIG instead? */ /* 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"); 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; int i;
Platform_NextArg(&cmdArgs); /* skip exe path */ 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); args[i] = Platform_NextArg(&cmdArgs);
if (!args[i].length) break; if (!args[i].length) break;

View File

@ -61,12 +61,12 @@ static void Program_RunGame(void) {
} }
String_InitArray(title, titleBuffer); 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); Game_Run(width, height, &title);
} }
int main(int argc, char** argv) { int main(int argc, char** argv) {
String args[PROGRAM_MAX_CMDARGS]; String args[GAME_MAX_CMDARGS];
int argsCount; int argsCount;
uint8_t ip[4]; uint8_t ip[4];
uint16_t port; uint16_t port;
@ -82,7 +82,7 @@ int main(int argc, char** argv) {
#ifdef CC_TEST_VORBIS #ifdef CC_TEST_VORBIS
main_imdct(); main_imdct();
#endif #endif
Platform_LogConst("Starting " PROGRAM_APP_NAME " .."); Platform_LogConst("Starting " GAME_APP_NAME " ..");
Utils_EnsureDirectory("maps"); Utils_EnsureDirectory("maps");
Utils_EnsureDirectory("texpacks"); Utils_EnsureDirectory("texpacks");

View File

@ -172,11 +172,11 @@ struct ResourceMusic Resources_Music[7] = {
/*########################################################################################################################* /*########################################################################################################################*
*---------------------------------------------------------Zip writer------------------------------------------------------* *---------------------------------------------------------Zip writer------------------------------------------------------*
*#########################################################################################################################*/ *#########################################################################################################################*/
static ReturnCode ZipPatcher_LocalFile(struct Stream* s, struct ResourceTexture* entry) { static ReturnCode ZipPatcher_LocalFile(struct Stream* s, struct ResourceTexture* e) {
String name = String_FromReadonly(entry->Filename); String name = String_FromReadonly(e->Filename);
uint8_t header[30 + STRING_SIZE]; uint8_t header[30 + STRING_SIZE];
ReturnCode res; 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_SetU32_LE(&header[0], 0x04034b50); /* signature */
Stream_SetU16_LE(&header[4], 20); /* version needed */ Stream_SetU16_LE(&header[4], 20); /* version needed */
@ -185,9 +185,9 @@ static ReturnCode ZipPatcher_LocalFile(struct Stream* s, struct ResourceTexture*
Stream_SetU16_LE(&header[10], 0); /* last modified */ Stream_SetU16_LE(&header[10], 0); /* last modified */
Stream_SetU16_LE(&header[12], 0); /* last modified */ Stream_SetU16_LE(&header[12], 0); /* last modified */
Stream_SetU32_LE(&header[14], 0); /* CRC32 */ Stream_SetU32_LE(&header[14], e->Crc32); /* CRC32 */
Stream_SetU32_LE(&header[18], 0); /* Compressed size */ Stream_SetU32_LE(&header[18], e->Size); /* Compressed size */
Stream_SetU32_LE(&header[22], 0); /* Uncompressed size */ Stream_SetU32_LE(&header[22], e->Size); /* Uncompressed size */
Stream_SetU16_LE(&header[26], name.length); /* name length */ Stream_SetU16_LE(&header[26], name.length); /* name length */
Stream_SetU16_LE(&header[28], 0); /* extra field 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); return Stream_Write(s, header, 30 + name.length);
} }
static ReturnCode ZipPatcher_CentralDir(struct Stream* s, struct ResourceTexture* res) { static ReturnCode ZipPatcher_CentralDir(struct Stream* s, struct ResourceTexture* e) {
String name = String_FromReadonly(res->Filename); String name = String_FromReadonly(e->Filename);
uint8_t header[46 + STRING_SIZE]; uint8_t header[46 + STRING_SIZE];
struct DateTime now; struct DateTime now;
int modTime, modDate; int modTime, modDate;
@ -214,9 +214,9 @@ static ReturnCode ZipPatcher_CentralDir(struct Stream* s, struct ResourceTexture
Stream_SetU16_LE(&header[12], modTime); /* last modified */ Stream_SetU16_LE(&header[12], modTime); /* last modified */
Stream_SetU16_LE(&header[14], modDate); /* last modified */ Stream_SetU16_LE(&header[14], modDate); /* last modified */
Stream_SetU32_LE(&header[16], res->Crc32); /* CRC32 */ Stream_SetU32_LE(&header[16], e->Crc32); /* CRC32 */
Stream_SetU32_LE(&header[20], res->Size); /* compressed size */ Stream_SetU32_LE(&header[20], e->Size); /* compressed size */
Stream_SetU32_LE(&header[24], res->Size); /* uncompressed size */ Stream_SetU32_LE(&header[24], e->Size); /* uncompressed size */
Stream_SetU16_LE(&header[28], name.length); /* name length */ Stream_SetU16_LE(&header[28], name.length); /* name length */
Stream_SetU16_LE(&header[30], 0); /* extra field 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[34], 0); /* disk number */
Stream_SetU16_LE(&header[36], 0); /* internal attributes */ Stream_SetU16_LE(&header[36], 0); /* internal attributes */
Stream_SetU32_LE(&header[38], 0); /* external 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); Mem_Copy(&header[46], name.buffer, name.length);
return Stream_Write(s, header, 46 + name.length); return Stream_Write(s, header, 46 + name.length);

View File

@ -561,7 +561,7 @@ static void ServerConnection_Init(void) {
Gfx_LostContextFunction = ServerConnection.Tick; Gfx_LostContextFunction = ServerConnection.Tick;
ScheduledTask_Add(GAME_NET_TICKS, 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) { static void ServerConnection_Free(void) {