mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-18 12:05:14 -04:00
Fix .zip with too many entries not getting loaded
This commit is contained in:
parent
5de42ad3d3
commit
7813b5719e
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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];
|
||||
};
|
||||
|
48
src/Game.c
48
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<string> 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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
|
@ -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 */
|
||||
@ -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[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);
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user