diff --git a/src/Bitmap.c b/src/Bitmap.c index 1694cef3b..6a36880d0 100644 --- a/src/Bitmap.c +++ b/src/Bitmap.c @@ -377,7 +377,7 @@ cc_result Png_Decode(struct Bitmap* bmp, struct Stream* stream) { trnsCol = BITMAPCOL_BLACK; for (i = 0; i < PNG_PALETTE; i++) { palette[i] = BITMAPCOL_BLACK; } - Inflate_MakeStream(&compStream, &inflate, stream); + Inflate_MakeStream2(&compStream, &inflate, stream); ZLibHeader_Init(&zlibHeader); for (;;) { diff --git a/src/Deflate.c b/src/Deflate.c index ba17f0131..812b7d20b 100644 --- a/src/Deflate.c +++ b/src/Deflate.c @@ -154,6 +154,8 @@ enum INFLATE_STATE_ { #define Inflate_UNSAFE_EnsureBits(state, bitsCount) while (state->NumBits < bitsCount) { Inflate_GetByte(state); } /* Peeks then consumes given bits */ #define Inflate_ReadBits(state, bitsCount) Inflate_PeekBits(state, bitsCount); Inflate_ConsumeBits(state, bitsCount); +/* Sets to given result and sets state to DONE */ +#define Inflate_Fail(state, res) state->result = res; state->State = INFLATE_STATE_DONE; /* Goes to the next state, after having read data of a block */ #define Inflate_NextBlockState(state) (state->LastBlock ? INFLATE_STATE_DONE : INFLATE_STATE_HEADER) @@ -329,7 +331,7 @@ static int Huffman_Unsafe_Decode_Slow(struct InflateState* state, struct Huffman return -1; } -void Inflate_Init(struct InflateState* state, struct Stream* source) { +void Inflate_Init2(struct InflateState* state, struct Stream* source) { state->State = INFLATE_STATE_HEADER; state->LastBlock = false; state->Bits = 0; @@ -340,6 +342,7 @@ void Inflate_Init(struct InflateState* state, struct Stream* source) { state->AvailOut = 0; state->Source = source; state->WindowIndex = 0; + state->result = 0; } static const cc_uint8 fixed_lits[INFLATE_MAX_LITS] = { @@ -496,7 +499,7 @@ void Inflate_Process(struct InflateState* state) { } break; case 3: { - Logger_Abort("DEFLATE - Invalid block type"); + Inflate_Fail(state, INF_ERR_BLOCKTYPE); } break; } @@ -509,7 +512,8 @@ void Inflate_Process(struct InflateState* state) { nlen = Inflate_ReadBits(state, 16); if (len != (nlen ^ 0xFFFFUL)) { - Logger_Abort("DEFLATE - Uncompressed block LEN check failed"); + Inflate_Fail(state, INF_ERR_BLOCKTYPE); + return; } state->Index = len; /* Reuse for 'uncompressed length' */ state->State = INFLATE_STATE_UNCOMPRESSED_DATA; @@ -602,7 +606,7 @@ void Inflate_Process(struct InflateState* state) { case 16: Inflate_EnsureBits(state, 2); repeatCount = Inflate_ReadBits(state, 2); - if (!state->Index) Logger_Abort("DEFLATE - Tried to repeat invalid byte"); + if (!state->Index) { Inflate_Fail(state, INF_ERR_REPEAT_BEG); return; } repeatCount += 3; repeatValue = state->Buffer[state->Index - 1]; break; @@ -621,7 +625,8 @@ void Inflate_Process(struct InflateState* state) { count = state->NumLits + state->NumDists; if (state->Index + repeatCount > count) { - Logger_Abort("DEFLATE - Tried to repeat past end"); + Inflate_Fail(state, INF_ERR_REPEAT_END); + return; } Mem_Set(&state->Buffer[state->Index], repeatValue, repeatCount); @@ -723,7 +728,7 @@ static cc_result Inflate_StreamRead(struct Stream* stream, cc_uint8* data, cc_ui hasInput = true; while (state->AvailOut > 0 && hasInput) { - if (state->State == INFLATE_STATE_DONE) break; + if (state->State == INFLATE_STATE_DONE) return state->result; if (!state->AvailIn) { /* Fully used up input buffer. Cycle back to start. */ @@ -748,9 +753,9 @@ static cc_result Inflate_StreamRead(struct Stream* stream, cc_uint8* data, cc_ui return 0; } -void Inflate_MakeStream(struct Stream* stream, struct InflateState* state, struct Stream* underlying) { +void Inflate_MakeStream2(struct Stream* stream, struct InflateState* state, struct Stream* underlying) { Stream_Init(stream); - Inflate_Init(state, underlying); + Inflate_Init2(state, underlying); stream->Meta.Inflate = state; stream->Read = Inflate_StreamRead; } @@ -1151,7 +1156,7 @@ static cc_result Zip_ReadLocalFileHeader(struct ZipState* state, struct ZipEntry return state->ProcessEntry(&path, &portion, state); } else if (method == 8) { Stream_ReadonlyPortion(&portion, stream, compressedSize); - Inflate_MakeStream(&compStream, &inflate, &portion); + Inflate_MakeStream2(&compStream, &inflate, &portion); return state->ProcessEntry(&path, &compStream, state); } else { Platform_Log1("Unsupported.zip entry compression method: %i", &method); diff --git a/src/Deflate.h b/src/Deflate.h index cd879a831..833775490 100644 --- a/src/Deflate.h +++ b/src/Deflate.h @@ -64,17 +64,18 @@ struct InflateState { } Table; /* union to save on memory */ struct HuffmanTable TableDists; /* Values represent distances back */ cc_uint8 Window[INFLATE_WINDOW_SIZE]; /* Holds circular buffer of recent output data, used for LZ77 */ + cc_result result; }; /* Initialises DEFLATE decompressor state to defaults. */ -CC_API void Inflate_Init(struct InflateState* state, struct Stream* source); +CC_API void Inflate_Init2(struct InflateState* state, struct Stream* source); /* Attempts to decompress as much of the currently pending data as possible. */ /* NOTE: This is a low level call - usually you treat as a stream via Inflate_MakeStream. */ void Inflate_Process(struct InflateState* state); /* Deompresses input data read from another stream using DEFLATE. Read only stream. */ /* NOTE: This only uncompresses pure DEFLATE compressed data. */ /* If data starts with a GZIP or ZLIB header, use GZipHeader_Read or ZLibHeader_Read to first skip it. */ -CC_API void Inflate_MakeStream(struct Stream* stream, struct InflateState* state, struct Stream* underlying); +CC_API void Inflate_MakeStream2(struct Stream* stream, struct InflateState* state, struct Stream* underlying); #define DEFLATE_BLOCK_SIZE 16384 diff --git a/src/Errors.h b/src/Errors.h index 723bd0214..ea364b436 100644 --- a/src/Errors.h +++ b/src/Errors.h @@ -49,6 +49,8 @@ enum ERRORS_ALL { /* CW map decoding errors */ NBT_ERR_INT32S, NBT_ERR_UNKNOWN, CW_ERR_ROOT_TAG, CW_ERR_STRING_LEN, /* OpenAL initing errors */ - AL_ERR_INIT_DEVICE, AL_ERR_INIT_CONTEXT + AL_ERR_INIT_DEVICE, AL_ERR_INIT_CONTEXT, + /* Inflate errors */ + INF_ERR_BLOCKTYPE, INF_ERR_LEN_VERIFY, INF_ERR_REPEAT_BEG, INF_ERR_REPEAT_END }; #endif diff --git a/src/Formats.c b/src/Formats.c index ef25623b3..bccaec105 100644 --- a/src/Formats.c +++ b/src/Formats.c @@ -166,7 +166,7 @@ cc_result Lvl_Load(struct Stream* stream) { struct LocalPlayer* p = &LocalPlayer_Instance; struct Stream compStream; struct InflateState state; - Inflate_MakeStream(&compStream, &state, stream); + Inflate_MakeStream2(&compStream, &state, stream); if ((res = Map_SkipGZipHeader(stream))) return res; if ((res = Stream_Read(&compStream, header, sizeof(header)))) return res; @@ -241,7 +241,7 @@ cc_result Fcm_Load(struct Stream* stream) { struct LocalPlayer* p = &LocalPlayer_Instance; struct Stream compStream; struct InflateState state; - Inflate_MakeStream(&compStream, &state, stream); + Inflate_MakeStream2(&compStream, &state, stream); if ((res = Stream_Read(stream, header, sizeof(header)))) return res; if (Stream_GetU32_LE(&header[0]) != 0x0FC2AF40UL) return FCM_ERR_IDENTIFIER; @@ -690,7 +690,7 @@ cc_result Cw_Load(struct Stream* stream) { Vec3* spawn; IVec3 pos; cc_result res; - Inflate_MakeStream(&compStream, &state, stream); + Inflate_MakeStream2(&compStream, &state, stream); if ((res = Map_SkipGZipHeader(stream))) return res; if ((res = compStream.ReadU8(&compStream, &tag))) return res; @@ -899,7 +899,7 @@ cc_result Dat_Load(struct Stream* stream) { struct LocalPlayer* p = &LocalPlayer_Instance; struct Stream compStream; struct InflateState state; - Inflate_MakeStream(&compStream, &state, stream); + Inflate_MakeStream2(&compStream, &state, stream); if ((res = Map_SkipGZipHeader(stream))) return res; if ((res = Stream_Read(&compStream, header, sizeof(header)))) return res; diff --git a/src/Protocol.c b/src/Protocol.c index c1b9f3e2a..8efdb9394 100644 --- a/src/Protocol.c +++ b/src/Protocol.c @@ -409,8 +409,18 @@ static void Classic_Handshake(cc_uint8* data) { static void Classic_Ping(cc_uint8* data) { } +#define MAP_SIZE_LEN 4 +static void DisconnectInvalidMap(cc_result res) { + static const String title = String_FromConst("Disconnected"); + String tmp; char tmpBuffer[STRING_SIZE]; + String_InitArray(tmp, tmpBuffer); + + String_Format1(&tmp, "Server sent corrupted map data (error %h)", &res); + Game_Disconnect(&title, &tmp); return; +} + static void MapState_Init(struct MapState* m) { - Inflate_MakeStream(&m->stream, &m->inflateState, &map_part); + Inflate_MakeStream2(&m->stream, &m->inflateState, &map_part); m->index = 0; m->blocks = NULL; m->allocFailed = false; @@ -427,6 +437,7 @@ static void FreeMapStates(void) { static void MapState_Read(struct MapState* m) { cc_uint32 left, read; + cc_result res; if (m->allocFailed) return; if (!m->blocks) { @@ -440,7 +451,9 @@ static void MapState_Read(struct MapState* m) { } left = map_volume - m->index; - m->stream.Read(&m->stream, &m->blocks[m->index], left, &read); + res = m->stream.Read(&m->stream, &m->blocks[m->index], left, &read); + + if (res) DisconnectInvalidMap(res); m->index += read; } @@ -471,16 +484,7 @@ static void Classic_LevelInit(cc_uint8* data) { /* Fast map puts volume in header, and uses raw DEFLATE without GZIP header/footer */ map_volume = Stream_GetU32_BE(data); map_gzHeader.done = true; - map_sizeIndex = 4; -} - -static void DisconnectInvalidMap(cc_result res) { - static const String title = String_FromConst("Disconnected"); - String tmp; char tmpBuffer[STRING_SIZE]; - String_InitArray(tmp, tmpBuffer); - - String_Format1(&tmp, "Server sent corrupted map data (error %h)", &res); - Game_Disconnect(&title, &tmp); return; + map_sizeIndex = MAP_SIZE_LEN; } static void Classic_LevelDataChunk(cc_uint8* data) { @@ -508,13 +512,15 @@ static void Classic_LevelDataChunk(cc_uint8* data) { } if (map_gzHeader.done) { - if (map_sizeIndex < 4) { - left = 4 - map_sizeIndex; - map.stream.Read(&map.stream, &map_size[map_sizeIndex], left, &read); + if (map_sizeIndex < MAP_SIZE_LEN) { + left = MAP_SIZE_LEN - map_sizeIndex; + res = map.stream.Read(&map.stream, &map_size[map_sizeIndex], left, &read); + + if (res) { DisconnectInvalidMap(res); return; } map_sizeIndex += read; } - if (map_sizeIndex == 4) { + if (map_sizeIndex == MAP_SIZE_LEN) { if (!map_volume) map_volume = Stream_GetU32_BE(map_size); #ifndef EXTENDED_BLOCKS