mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-16 19:15:14 -04:00
explicit error codes for C client png/zip
This commit is contained in:
parent
effed1f351
commit
c4d1f2a2fe
@ -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) {
|
||||
|
@ -26,7 +26,7 @@ namespace Launcher.Patcher {
|
||||
public const string assetsUri = "http://resources.download.minecraft.net/";
|
||||
|
||||
public void DownloadItems(AsyncDownloader downloader, Action<string> setStatus) {
|
||||
this.downloader = downloader;
|
||||
this.downloader = downloader;
|
||||
byte fetchFlags = ResourceList.GetFetchFlags();
|
||||
|
||||
if ((fetchFlags & ResourceList.mask_classic) != 0)
|
||||
|
@ -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")) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user