From c4d1f2a2fea1a77b2ae6b32da81702289bc0baba Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 22 Jul 2018 20:09:01 +1000 Subject: [PATCH] explicit error codes for C client png/zip --- ClassicalSharp/TexturePack/ZipReader.cs | 24 +++--- Launcher2/Patcher/ResourceFetcher.cs | 2 +- src/Client/Animations.c | 3 +- src/Client/Bitmap.c | 52 ++++++------ src/Client/Bitmap.h | 10 ++- src/Client/Entity.c | 3 +- src/Client/Game.c | 15 +++- src/Client/TexturePack.c | 103 +++++++++++++----------- src/Client/TexturePack.h | 13 ++- 9 files changed, 125 insertions(+), 100 deletions(-) diff --git a/ClassicalSharp/TexturePack/ZipReader.cs b/ClassicalSharp/TexturePack/ZipReader.cs index d02bb2ebd..3d7391417 100644 --- a/ClassicalSharp/TexturePack/ZipReader.cs +++ b/ClassicalSharp/TexturePack/ZipReader.cs @@ -83,7 +83,7 @@ namespace ClassicalSharp.Textures { ushort flags = reader.ReadUInt16(); ushort compressionMethod = reader.ReadUInt16(); reader.ReadUInt32(); // last modified - reader.ReadUInt32(); // CRC 32 + reader.ReadUInt32(); // CRC32 int compressedSize = reader.ReadInt32(); if (compressedSize == 0) compressedSize = entry.CompressedDataSize; @@ -107,9 +107,9 @@ namespace ClassicalSharp.Textures { void ReadCentralDirectory(BinaryReader reader, ZipEntry[] entries) { ZipEntry entry; reader.ReadUInt16(); // OS - ushort versionNeeded = reader.ReadUInt16(); - ushort flags = reader.ReadUInt16(); - ushort compressionMethod = reader.ReadUInt16(); + reader.ReadUInt16(); // version neede + reader.ReadUInt16(); // flags + reader.ReadUInt16(); // compression method reader.ReadUInt32(); // last modified uint crc32 = reader.ReadUInt32(); int compressedSize = reader.ReadInt32(); @@ -118,9 +118,9 @@ namespace ClassicalSharp.Textures { ushort extraFieldLen = reader.ReadUInt16(); ushort fileCommentLen = reader.ReadUInt16(); - ushort diskNum = reader.ReadUInt16(); - ushort internalAttributes = reader.ReadUInt16(); - uint externalAttributes = reader.ReadUInt32(); + reader.ReadUInt16(); // disk number + reader.ReadUInt16(); // internal attributes + reader.ReadUInt32(); // external attributes int localHeaderOffset = reader.ReadInt32(); string fileName = enc.GetString(reader.ReadBytes(fileNameLen)); reader.ReadBytes(extraFieldLen); @@ -135,13 +135,13 @@ namespace ClassicalSharp.Textures { } void ReadEndOfCentralDirectory(BinaryReader reader, out int entriesCount, out int centralDirectoryOffset) { - ushort diskNum = reader.ReadUInt16(); - ushort diskNumStart = reader.ReadUInt16(); - ushort diskEntries = reader.ReadUInt16(); + reader.ReadUInt16(); // disk number + reader.ReadUInt16(); // disk number start + reader.ReadUInt16(); // disk entries entriesCount = reader.ReadUInt16(); - int centralDirectorySize = reader.ReadInt32(); + reader.ReadInt32(); // central directory size centralDirectoryOffset = reader.ReadInt32(); - ushort commentLength = reader.ReadUInt16(); + reader.ReadUInt16(); // comment length } byte[] DecompressEntry(BinaryReader reader, ushort compressionMethod, int compressedSize, int uncompressedSize) { diff --git a/Launcher2/Patcher/ResourceFetcher.cs b/Launcher2/Patcher/ResourceFetcher.cs index 3ec519eb4..dfbcdd580 100644 --- a/Launcher2/Patcher/ResourceFetcher.cs +++ b/Launcher2/Patcher/ResourceFetcher.cs @@ -26,7 +26,7 @@ namespace Launcher.Patcher { public const string assetsUri = "http://resources.download.minecraft.net/"; public void DownloadItems(AsyncDownloader downloader, Action setStatus) { - this.downloader = downloader; + this.downloader = downloader; byte fetchFlags = ResourceList.GetFetchFlags(); if ((fetchFlags & ResourceList.mask_classic) != 0) diff --git a/src/Client/Animations.c b/src/Client/Animations.c index d305fba75..c8ef875ef 100644 --- a/src/Client/Animations.c +++ b/src/Client/Animations.c @@ -321,7 +321,8 @@ static void Animations_PackChanged(void* obj) { static void Animations_FileChanged(void* obj, struct Stream* stream) { String* name = &stream->Name; if (String_CaselessEqualsConst(name, "animation.png") || String_CaselessEqualsConst(name, "animations.png")) { - Bitmap_DecodePng(&anims_bmp, stream); + ReturnCode result = Bitmap_DecodePng(&anims_bmp, stream); + ErrorHandler_CheckOrFail(result, "Decoding animations bitmap"); } else if (String_CaselessEqualsConst(name, "animation.txt") || String_CaselessEqualsConst(name, "animations.txt")) { Animations_ReadDescription(stream); } else if (String_CaselessEqualsConst(name, "uselavaanim")) { diff --git a/src/Client/Bitmap.c b/src/Client/Bitmap.c index ea24bfb89..950b8a6f7 100644 --- a/src/Client/Bitmap.c +++ b/src/Client/Bitmap.c @@ -73,12 +73,6 @@ bool Bitmap_DetectPng(UInt8* data, UInt32 len) { return true; } -static void Png_CheckHeader(struct Stream* stream) { - UInt8 header[PNG_SIG_SIZE]; - Stream_Read(stream, header, PNG_SIG_SIZE); - if (!Bitmap_DetectPng(header, PNG_SIG_SIZE)) ErrorHandler_Fail("Invalid PNG header"); -} - static void Png_Reconstruct(UInt8 type, UInt8 bytesPerPixel, UInt8* line, UInt8* prior, UInt32 lineLen) { UInt32 i, j; switch (type) { @@ -299,9 +293,13 @@ static void Png_ComputeTransparency(struct Bitmap* bmp, UInt32 transparentCol) { /* Most bits per sample is 16. Most samples per pixel is 4. Add 1 for filter byte. */ #define PNG_BUFFER_SIZE ((PNG_MAX_DIMS * 2 * 4 + 1) * 2) /* TODO: Test a lot of .png files and ensure output is right */ -void Bitmap_DecodePng(struct Bitmap* bmp, struct Stream* stream) { - Png_CheckHeader(stream); +ReturnCode Bitmap_DecodePng(struct Bitmap* bmp, struct Stream* stream) { Bitmap_Create(bmp, 0, 0, NULL); + + UInt8 header[PNG_SIG_SIZE]; + Stream_Read(stream, header, PNG_SIG_SIZE); + if (!Bitmap_DetectPng(header, PNG_SIG_SIZE)) return PNG_ERR_INVALID_SIG; + UInt32 transparentCol = PackedCol_ARGB(0, 0, 0, 255); UInt8 col, bitsPerSample, bytesPerPixel; Png_RowExpander rowExpander; @@ -329,28 +327,28 @@ void Bitmap_DecodePng(struct Bitmap* bmp, struct Stream* stream) { switch (fourCC) { case PNG_FourCC('I', 'H', 'D', 'R'): { - if (dataSize != PNG_IHDR_SIZE) ErrorHandler_Fail("PNG header chunk has invalid size"); + if (dataSize != PNG_IHDR_SIZE) return PNG_ERR_INVALID_HEADER_SIZE; gotHeader = true; bmp->Width = Stream_ReadI32_BE(stream); bmp->Height = Stream_ReadI32_BE(stream); - if (bmp->Width < 0 || bmp->Width > PNG_MAX_DIMS) ErrorHandler_Fail("PNG image too wide"); - if (bmp->Height < 0 || bmp->Height > PNG_MAX_DIMS) ErrorHandler_Fail("PNG image too tall"); + if (bmp->Width < 0 || bmp->Width > PNG_MAX_DIMS) return PNG_ERR_TOO_WIDE; + if (bmp->Height < 0 || bmp->Height > PNG_MAX_DIMS) return PNG_ERR_TOO_TALL; bmp->Stride = bmp->Width * BITMAP_SIZEOF_PIXEL; bmp->Scan0 = Platform_MemAlloc(bmp->Width * bmp->Height, BITMAP_SIZEOF_PIXEL); if (bmp->Scan0 == NULL) ErrorHandler_Fail("Failed to allocate memory for PNG bitmap"); bitsPerSample = Stream_ReadU8(stream); - if (bitsPerSample > 16 || !Math_IsPowOf2(bitsPerSample)) ErrorHandler_Fail("PNG has invalid bits per pixel"); + if (bitsPerSample > 16 || !Math_IsPowOf2(bitsPerSample)) return PNG_ERR_INVALID_BPP; col = Stream_ReadU8(stream); - if (col == 1 || col == 5 || col > 6) ErrorHandler_Fail("PNG has invalid colour type"); - if (bitsPerSample < 8 && (col >= PNG_COL_RGB && col != PNG_COL_INDEXED)) ErrorHandler_Fail("PNG has invalid bpp for this colour type"); - if (bitsPerSample == 16 && col == PNG_COL_INDEXED) ErrorHandler_Fail("PNG has invalid bpp for this colour type"); + if (col == 1 || col == 5 || col > 6) return PNG_ERR_INVALID_COL; + if (bitsPerSample < 8 && (col >= PNG_COL_RGB && col != PNG_COL_INDEXED)) return PNG_ERR_INVALID_COL_BPP; + if (bitsPerSample == 16 && col == PNG_COL_INDEXED) return PNG_ERR_INVALID_COL_BPP; - if (Stream_ReadU8(stream) != 0) ErrorHandler_Fail("PNG compression method must be DEFLATE"); - if (Stream_ReadU8(stream) != 0) ErrorHandler_Fail("PNG filter method must be ADAPTIVE"); - if (Stream_ReadU8(stream) != 0) ErrorHandler_Fail("PNG interlacing not supported"); + if (Stream_ReadU8(stream) != 0) return PNG_ERR_COMP_METHOD; + if (Stream_ReadU8(stream) != 0) return PNG_ERR_FILTER; + if (Stream_ReadU8(stream) != 0) return PNG_ERR_INTERLACED; static UInt32 samplesPerPixel[7] = { 1, 0, 3, 1, 2, 0, 4 }; bytesPerPixel = ((samplesPerPixel[col] * bitsPerSample) + 7) >> 3; @@ -371,8 +369,8 @@ void Bitmap_DecodePng(struct Bitmap* bmp, struct Stream* stream) { } break; case PNG_FourCC('P', 'L', 'T', 'E'): { - if (dataSize > PNG_PALETTE * 3) ErrorHandler_Fail("PNG palette has too many entries"); - if ((dataSize % 3) != 0) ErrorHandler_Fail("PNG palette chunk has invalid size"); + if (dataSize > PNG_PALETTE * 3) return PNG_ERR_PAL_ENTRIES; + if ((dataSize % 3) != 0) return PNG_ERR_PAL_SIZE; UInt8 palRGB[PNG_PALETTE * 3]; Stream_Read(stream, palRGB, dataSize); @@ -383,11 +381,11 @@ void Bitmap_DecodePng(struct Bitmap* bmp, struct Stream* stream) { case PNG_FourCC('t', 'R', 'N', 'S'): { if (col == PNG_COL_GRAYSCALE) { - if (dataSize != 2) ErrorHandler_Fail("PNG only allows one explicit transparency colour"); + if (dataSize != 2) return PNG_ERR_TRANS_COUNT; UInt8 palRGB = (UInt8)Stream_ReadU16_BE(stream); transparentCol = PackedCol_ARGB(palRGB, palRGB, palRGB, 0); } else if (col == PNG_COL_INDEXED) { - if (dataSize > PNG_PALETTE) ErrorHandler_Fail("PNG transparency palette has too many entries"); + if (dataSize > PNG_PALETTE) return PNG_ERR_TRANS_COUNT; UInt8 palA[PNG_PALETTE * 3]; Stream_Read(stream, palA, dataSize); @@ -396,13 +394,13 @@ void Bitmap_DecodePng(struct Bitmap* bmp, struct Stream* stream) { palette[i] |= (UInt32)palA[i] << 24; } } else if (col == PNG_COL_RGB) { - if (dataSize != 6) ErrorHandler_Fail("PNG only allows one explicit transparency colour"); + if (dataSize != 6) return PNG_ERR_TRANS_COUNT; UInt8 palR = (UInt8)Stream_ReadU16_BE(stream); UInt8 palG = (UInt8)Stream_ReadU16_BE(stream); UInt8 palB = (UInt8)Stream_ReadU16_BE(stream); transparentCol = PackedCol_ARGB(palR, palG, palB, 0); } else { - ErrorHandler_Fail("PNG cannot have explicit transparency colour for this colour type"); + return PNG_ERR_TRANS_INVALID; } } break; @@ -450,12 +448,12 @@ void Bitmap_DecodePng(struct Bitmap* bmp, struct Stream* stream) { case PNG_FourCC('I', 'E', 'N', 'D'): { readingChunks = false; - if (dataSize != 0) ErrorHandler_Fail("PNG end chunk must be empty"); + if (dataSize != 0) return PNG_ERR_INVALID_END_SIZE; } break; default: { - ReturnCode code = Stream_Skip(stream, dataSize); - ErrorHandler_CheckOrFail(code, "PNG - skipping chunk"); + ReturnCode result = Stream_Skip(stream, dataSize); + if (result != 0) return PNG_ERR_SKIPPING_CHUNK; } break; } diff --git a/src/Client/Bitmap.h b/src/Client/Bitmap.h index e1b4d1db5..22e9c2fdb 100644 --- a/src/Client/Bitmap.h +++ b/src/Client/Bitmap.h @@ -26,11 +26,19 @@ void Bitmap_Allocate(struct Bitmap* bmp, Int32 width, Int32 height); void Bitmap_AllocateClearedPow2(struct Bitmap* bmp, Int32 width, Int32 height); bool Bitmap_DetectPng(UInt8* data, UInt32 len); +enum PNG_ERR { + PNG_ERR_INVALID_SIG = 307001, + PNG_ERR_INVALID_HEADER_SIZE, PNG_ERR_TOO_WIDE, PNG_ERR_TOO_TALL, + PNG_ERR_INVALID_BPP, PNG_ERR_INVALID_COL, PNG_ERR_INVALID_COL_BPP, + PNG_ERR_COMP_METHOD, PNG_ERR_FILTER, PNG_ERR_INTERLACED, + PNG_ERR_PAL_ENTRIES, PNG_ERR_PAL_SIZE, PNG_ERR_TRANS_COUNT, PNG_ERR_TRANS_INVALID, + PNG_ERR_INVALID_END_SIZE, PNG_ERR_SKIPPING_CHUNK, +}; /* Partially based off information from https://handmade.network/forums/wip/t/2363-implementing_a_basic_png_reader_the_handmade_way https://github.com/nothings/stb/blob/master/stb_image.h */ -void Bitmap_DecodePng(struct Bitmap* bmp, struct Stream* stream); +ReturnCode Bitmap_DecodePng(struct Bitmap* bmp, struct Stream* stream); void Bitmap_EncodePng(struct Bitmap* bmp, struct Stream* stream); #endif diff --git a/src/Client/Entity.c b/src/Client/Entity.c index 9c90c2da6..c47db5ba5 100644 --- a/src/Client/Entity.c +++ b/src/Client/Entity.c @@ -702,7 +702,8 @@ static void Player_CheckSkin(struct Player* player) { String url = String_FromRawArray(item.URL); struct Stream mem; struct Bitmap bmp; Stream_ReadonlyMemory(&mem, item.ResultData, item.ResultSize, &url); - Bitmap_DecodePng(&bmp, &mem); + ReturnCode result = Bitmap_DecodePng(&bmp, &mem); + ErrorHandler_CheckOrFail(result, "Decoding player skin"); Gfx_DeleteTexture(&entity->TextureId); Player_SetSkinAll(player, true); diff --git a/src/Client/Game.c b/src/Client/Game.c index e5ca6b11f..e80de62fa 100644 --- a/src/Client/Game.c +++ b/src/Client/Game.c @@ -235,9 +235,11 @@ void Game_SetDefaultSkinType(struct Bitmap* bmp) { } bool Game_UpdateTexture(GfxResourceID* texId, struct Stream* src, bool setSkinType) { - struct Bitmap bmp; Bitmap_DecodePng(&bmp, src); - bool success = Game_ValidateBitmap(&src->Name, &bmp); + struct Bitmap bmp; + ReturnCode result = Bitmap_DecodePng(&bmp, src); + ErrorHandler_CheckOrFail(result, "Decoding texture"); + bool success = Game_ValidateBitmap(&src->Name, &bmp); if (success) { Gfx_DeleteTexture(texId); if (setSkinType) Game_SetDefaultSkinType(&bmp); @@ -320,11 +322,16 @@ static void Game_OnNewMapLoadedCore(void* obj) { static void Game_TextureChangedCore(void* obj, struct Stream* src) { if (String_CaselessEqualsConst(&src->Name, "terrain.png")) { - struct Bitmap atlas; Bitmap_DecodePng(&atlas, src); + struct Bitmap atlas; + ReturnCode result = Bitmap_DecodePng(&atlas, src); + ErrorHandler_CheckOrFail(result, "Decoding terrain bitmap"); + if (Game_ChangeTerrainAtlas(&atlas)) return; Platform_MemFree(&atlas.Scan0); } else if (String_CaselessEqualsConst(&src->Name, "default.png")) { - struct Bitmap bmp; Bitmap_DecodePng(&bmp, src); + struct Bitmap bmp; + ReturnCode result = Bitmap_DecodePng(&bmp, src); + ErrorHandler_CheckOrFail(result, "Decoding font bitmap"); Drawer2D_SetFontBitmap(&bmp); Event_RaiseVoid(&ChatEvents_FontChanged); } diff --git a/src/Client/TexturePack.c b/src/Client/TexturePack.c index ae5bfba6a..e08b1b33b 100644 --- a/src/Client/TexturePack.c +++ b/src/Client/TexturePack.c @@ -71,9 +71,9 @@ static void Zip_ReadLocalFileHeader(struct ZipState* state, struct ZipEntry* ent static void Zip_ReadCentralDirectory(struct ZipState* state, struct ZipEntry* entry) { struct Stream* stream = state->Input; Stream_ReadU16_LE(stream); /* OS */ - UInt16 versionNeeded = Stream_ReadU16_LE(stream); - UInt16 flags = Stream_ReadU16_LE(stream); - UInt16 compressionMethod = Stream_ReadU16_LE(stream); + Stream_ReadU16_LE(stream); /* version needed*/ + Stream_ReadU16_LE(stream); /* flags */ + Stream_ReadU16_LE(stream); /* compresssion method*/ Stream_ReadU32_LE(stream); /* last modified */ entry->Crc32 = Stream_ReadU32_LE(stream); entry->CompressedDataSize = Stream_ReadI32_LE(stream); @@ -82,9 +82,9 @@ static void Zip_ReadCentralDirectory(struct ZipState* state, struct ZipEntry* en UInt16 fileNameLen = Stream_ReadU16_LE(stream); UInt16 extraFieldLen = Stream_ReadU16_LE(stream); UInt16 fileCommentLen = Stream_ReadU16_LE(stream); - UInt16 diskNum = Stream_ReadU16_LE(stream); - UInt16 internalAttributes = Stream_ReadU16_LE(stream); - UInt32 externalAttributes = Stream_ReadU32_LE(stream); + Stream_ReadU16_LE(stream); /* disk number */ + Stream_ReadU16_LE(stream); /* internal attributes */ + Stream_ReadU32_LE(stream); /* external attributes */ entry->LocalHeaderOffset = Stream_ReadI32_LE(stream); UInt32 extraDataLen = fileNameLen + extraFieldLen + fileCommentLen; @@ -94,18 +94,20 @@ static void Zip_ReadCentralDirectory(struct ZipState* state, struct ZipEntry* en static void Zip_ReadEndOfCentralDirectory(struct ZipState* state, Int32* centralDirectoryOffset) { struct Stream* stream = state->Input; - UInt16 diskNum = Stream_ReadU16_LE(stream); - UInt16 diskNumStart = Stream_ReadU16_LE(stream); - UInt16 diskEntries = Stream_ReadU16_LE(stream); + Stream_ReadU16_LE(stream); /* disk number */ + Stream_ReadU16_LE(stream); /* disk number start */ + Stream_ReadU16_LE(stream); /* disk entries */ state->EntriesCount = Stream_ReadU16_LE(stream); - Int32 centralDirectorySize = Stream_ReadI32_LE(stream); + Stream_ReadU32_LE(stream); /* central directory size */ *centralDirectoryOffset = Stream_ReadI32_LE(stream); - UInt16 commentLength = Stream_ReadU16_LE(stream); + Stream_ReadU16_LE(stream); /* comment length */ } -#define ZIP_ENDOFCENTRALDIR 0x06054b50UL -#define ZIP_CENTRALDIR 0x02014b50UL -#define ZIP_LOCALFILEHEADER 0x04034b50UL +enum ZIP_SIG { + ZIP_SIG_ENDOFCENTRALDIR = 0x06054b50, + ZIP_SIG_CENTRALDIR = 0x02014b50, + ZIP_SIG_LOCALFILEHEADER = 0x04034b50, +}; static void Zip_DefaultProcessor(STRING_TRANSIENT String* path, struct Stream* data, struct ZipEntry* entry) { } static bool Zip_DefaultSelector(STRING_TRANSIENT String* path) { return true; } @@ -116,7 +118,7 @@ void Zip_Init(struct ZipState* state, struct Stream* input) { state->SelectEntry = Zip_DefaultSelector; } -void Zip_Extract(struct ZipState* state) { +ReturnCode Zip_Extract(struct ZipState* state) { state->EntriesCount = 0; struct Stream* stream = state->Input; UInt32 sig = 0, stream_len = 0; @@ -126,36 +128,31 @@ void Zip_Extract(struct ZipState* state) { Int32 i, len = min(257, stream_len); for (i = 22; i < len; i++) { result = stream->Seek(stream, -i, STREAM_SEEKFROM_END); - ErrorHandler_CheckOrFail(result, "ZIP - Seek to end of central directory"); + if (result != 0) return ZIP_ERR_SEEK_END_OF_CENTRAL_DIR; + sig = Stream_ReadU32_LE(stream); - if (sig == ZIP_ENDOFCENTRALDIR) break; - } - if (sig != ZIP_ENDOFCENTRALDIR) { - ErrorHandler_Fail("ZIP - Failed to find end of central directory"); - return; + if (sig == ZIP_SIG_ENDOFCENTRALDIR) break; } + if (sig != ZIP_SIG_ENDOFCENTRALDIR) return ZIP_ERR_NO_END_OF_CENTRAL_DIR; 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"); - } + if (result != 0) return ZIP_ERR_SEEK_CENTRAL_DIR; + + if (state->EntriesCount > ZIP_MAX_ENTRIES) return ZIP_ERR_TOO_MANY_ENTRIES; /* Read all the central directory entries */ Int32 count = 0; while (count < state->EntriesCount) { sig = Stream_ReadU32_LE(stream); - if (sig == ZIP_CENTRALDIR) { + if (sig == ZIP_SIG_CENTRALDIR) { Zip_ReadCentralDirectory(state, &state->Entries[count]); count++; - } else if (sig == ZIP_ENDOFCENTRALDIR) { + } else if (sig == ZIP_SIG_ENDOFCENTRALDIR) { break; } else { - String sigMsg = String_FromConst("ZIP - Unsupported signature found, aborting"); - ErrorHandler_Log(&sigMsg); - return; + return ZIP_ERR_INVALID_CENTRAL_DIR; } } @@ -163,14 +160,10 @@ void Zip_Extract(struct ZipState* state) { for (i = 0; i < count; i++) { struct ZipEntry* entry = &state->Entries[i]; result = stream->Seek(stream, entry->LocalHeaderOffset, STREAM_SEEKFROM_BEGIN); - ErrorHandler_CheckOrFail(result, "ZIP - Seek to local file header"); + if (result != 0) return ZIP_ERR_SEEK_LOCAL_DIR; sig = Stream_ReadU32_LE(stream); - if (sig != ZIP_LOCALFILEHEADER) { - String sigMsg = String_FromConst("ZIP - Invalid entry found, skipping"); - ErrorHandler_Log(&sigMsg); - continue; - } + if (sig != ZIP_SIG_LOCALFILEHEADER) return ZIP_ERR_INVALID_LOCAL_DIR; Zip_ReadLocalFileHeader(state, entry); } } @@ -418,14 +411,14 @@ static void TexturePack_ProcessZipEntry(STRING_TRANSIENT String* path, struct St Event_RaiseStream(&TextureEvents_FileChanged, stream); } -static void TexturePack_ExtractZip(struct Stream* stream) { +static ReturnCode TexturePack_ExtractZip(struct Stream* stream) { Event_RaiseVoid(&TextureEvents_PackChanged); - if (Gfx_LostContext) return; + if (Gfx_LostContext) return 0; struct ZipState state; Zip_Init(&state, stream); state.ProcessEntry = TexturePack_ProcessZipEntry; - Zip_Extract(&state); + return Zip_Extract(&state); } void TexturePack_ExtractZip_File(STRING_PURE String* filename) { @@ -438,18 +431,24 @@ void TexturePack_ExtractZip_File(STRING_PURE String* filename) { ErrorHandler_CheckOrFail(result, "TexturePack_Extract - opening file"); struct Stream stream; Stream_FromFile(&stream, file, &path); { - TexturePack_ExtractZip(&stream); + result = TexturePack_ExtractZip(&stream); + ErrorHandler_CheckOrFail(result, "TexturePack_Extract - extract content"); } result = stream.Close(&stream); ErrorHandler_CheckOrFail(result, "TexturePack_Extract - closing file"); } -void TexturePack_ExtractTerrainPng(struct Stream* stream) { - struct Bitmap bmp; Bitmap_DecodePng(&bmp, stream); - Event_RaiseVoid(&TextureEvents_PackChanged); +ReturnCode TexturePack_ExtractTerrainPng(struct Stream* stream) { + struct Bitmap bmp; + ReturnCode result = Bitmap_DecodePng(&bmp, stream); + + if (result == 0) { + Event_RaiseVoid(&TextureEvents_PackChanged); + if (Game_ChangeTerrainAtlas(&bmp)) return 0; + } - if (Game_ChangeTerrainAtlas(&bmp)) return; Platform_MemFree(&bmp.Scan0); + return result; } void TexturePack_ExtractDefault(void) { @@ -470,16 +469,19 @@ void TexturePack_ExtractCurrent(STRING_PURE String* url) { if (World_TextureUrl.length > 0) TexturePack_ExtractDefault(); } else { String zip = String_FromConst(".zip"); + ReturnCode result = 0; + if (String_Equals(url, &World_TextureUrl)) { } else if (String_ContainsString(url, &zip)) { String_Set(&World_TextureUrl, url); - TexturePack_ExtractZip(&stream); + result = TexturePack_ExtractZip(&stream); } else { String_Set(&World_TextureUrl, url); - TexturePack_ExtractTerrainPng(&stream); + result = TexturePack_ExtractTerrainPng(&stream); } + ErrorHandler_CheckOrFail(result, "TexturePack_ExtractCurrent - extract content"); - ReturnCode result = stream.Close(&stream); + result = stream.Close(&stream); ErrorHandler_CheckOrFail(result, "TexturePack_ExtractCurrent - close stream"); } } @@ -498,10 +500,13 @@ void TexturePack_Extract_Req(struct AsyncRequest* item) { String id = String_FromRawArray(item->ID); struct Stream mem; Stream_ReadonlyMemory(&mem, data, len, &id); + ReturnCode result; if (Bitmap_DetectPng(data, len)) { - TexturePack_ExtractTerrainPng(&mem); + result = TexturePack_ExtractTerrainPng(&mem); } else { - TexturePack_ExtractZip(&mem); + result = TexturePack_ExtractZip(&mem); } + + ErrorHandler_CheckOrFail(result, "TexturePack_Extract_Req - extract content"); ASyncRequest_Free(item); } \ No newline at end of file diff --git a/src/Client/TexturePack.h b/src/Client/TexturePack.h index 51596d8b8..8e4f8f1d4 100644 --- a/src/Client/TexturePack.h +++ b/src/Client/TexturePack.h @@ -9,9 +9,7 @@ struct Stream; struct Bitmap; struct AsyncRequest; -struct ZipEntry { - Int32 CompressedDataSize, UncompressedDataSize, LocalHeaderOffset; UInt32 Crc32; -}; +struct ZipEntry { Int32 CompressedDataSize, UncompressedDataSize, LocalHeaderOffset; UInt32 Crc32; }; #define ZIP_MAX_ENTRIES 2048 struct ZipState { @@ -22,8 +20,15 @@ struct ZipState { struct ZipEntry Entries[ZIP_MAX_ENTRIES]; }; +enum ZIP_ERR { + ZIP_ERR_TOO_MANY_ENTRIES = 405001, + ZIP_ERR_SEEK_END_OF_CENTRAL_DIR, ZIP_ERR_NO_END_OF_CENTRAL_DIR, + ZIP_ERR_SEEK_CENTRAL_DIR, ZIP_ERR_INVALID_CENTRAL_DIR, + ZIP_ERR_SEEK_LOCAL_DIR, ZIP_ERR_INVALID_LOCAL_DIR, +}; + void Zip_Init(struct ZipState* state, struct Stream* input); -void Zip_Extract(struct ZipState* state); +ReturnCode Zip_Extract(struct ZipState* state); void TextureCache_Init(void); bool TextureCache_HasAccepted(STRING_PURE String* url);