explicit error codes for C client png/zip

This commit is contained in:
UnknownShadow200 2018-07-22 20:09:01 +10:00
parent effed1f351
commit c4d1f2a2fe
9 changed files with 125 additions and 100 deletions

View File

@ -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) {

View File

@ -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)

View File

@ -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")) {

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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, &centralDirectoryOffset);
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);
}

View File

@ -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);