diff --git a/ClassicalSharp/2D/Widgets/Chat/TextGroupWidget.cs b/ClassicalSharp/2D/Widgets/Chat/TextGroupWidget.cs
index 78d1e11f0..21512aaf9 100644
--- a/ClassicalSharp/2D/Widgets/Chat/TextGroupWidget.cs
+++ b/ClassicalSharp/2D/Widgets/Chat/TextGroupWidget.cs
@@ -92,12 +92,14 @@ namespace ClassicalSharp.Gui.Widgets {
}
public int GetUsedHeight() {
- int sum = 0;
- for (int i = 0; i < Textures.Length; i++) {
- if (!Textures[i].IsValid) continue;
- sum += Textures[i].Height;
+ int height = 0, i = 0;
+ for (i = 0; i < Textures.Length; i++) {
+ if (Textures[i].IsValid) break;
}
- return sum;
+ for (; i < Textures.Length; i++) {
+ height += Textures[i].Height;
+ }
+ return height;
}
void UpdateDimensions() {
diff --git a/src/Client/Client.vcxproj b/src/Client/Client.vcxproj
index fd78e792a..c5dead715 100644
--- a/src/Client/Client.vcxproj
+++ b/src/Client/Client.vcxproj
@@ -194,7 +194,7 @@
-
+
@@ -262,7 +262,7 @@
-
+
diff --git a/src/Client/Client.vcxproj.filters b/src/Client/Client.vcxproj.filters
index ee096e954..f58dff85f 100644
--- a/src/Client/Client.vcxproj.filters
+++ b/src/Client/Client.vcxproj.filters
@@ -273,9 +273,6 @@
Header Files\Defines
-
- Header Files\IO
-
Header Files\Math
@@ -351,6 +348,9 @@
Header Files\Math
+
+ Header Files\IO
+
@@ -437,9 +437,6 @@
Source Files\Entities
-
- Source Files\IO
-
Source Files\Math
@@ -530,5 +527,8 @@
Source Files\Utils
+
+ Source Files\IO
+
\ No newline at end of file
diff --git a/src/Client/Deflate.c b/src/Client/Deflate.c
new file mode 100644
index 000000000..a2c7ef221
--- /dev/null
+++ b/src/Client/Deflate.c
@@ -0,0 +1,142 @@
+#include "Deflate.h"
+#include "ErrorHandler.h"
+
+#define GZipState_Header1 0
+#define GZipState_Header2 1
+#define GZipState_CompressionMethod 2
+#define GZipState_Flags 3
+#define GZipState_LastModifiedTime 4
+#define GZipState_CompressionFlags 5
+#define GZipState_OperatingSystem 6
+#define GZipState_HeaderChecksum 7
+#define GZipState_Filename 8
+#define GZipState_Comment 9
+#define GZipState_Done 10
+
+#define ZLibState_CompressionMethod 0
+#define ZLibState_Flags 1
+#define ZLibState_Done 2
+
+bool Header_ReadByte(Stream* s, UInt8* state, Int32* value) {
+ *value = s->TryReadByte();
+ if (*value == -1) return false;
+
+ (*state)++;
+ return true;
+}
+
+
+void GZipHeader_Init(GZipHeader* header) {
+ header->State = GZipState_Header1;
+ header->Done = false;
+ header->Flags = 0;
+ header->PartsRead = 0;
+}
+
+void GZipHeader_Read(Stream* s, GZipHeader* header) {
+ Int32 temp;
+ switch (header->State) {
+
+ case GZipState_Header1:
+ if (!Header_ReadByte(s, &header->State, &temp)) return;
+ if (temp != 0x1F) {
+ ErrorHandler_Fail("Byte 1 of GZIP header must be 1F");
+ }
+
+ case GZipState_Header2:
+ if (!Header_ReadByte(s, &header->State, &temp)) return;
+ if (temp != 0x8B) {
+ ErrorHandler_Fail("Byte 2 of GZIP header must be 8B");
+ }
+
+ case GZipState_CompressionMethod:
+ if (!Header_ReadByte(s, &header->State, &temp)) return;
+ if (temp != 0x08) {
+ ErrorHandler_Fail("Only DEFLATE compression supported");
+ }
+
+ case GZipState_Flags:
+ if (!Header_ReadByte(s, &header->State, &header->Flags)) return;
+ if ((header->Flags & 0x04) != 0) {
+ ErrorHandler_Fail("Unsupported GZIP header flags");
+ }
+
+ case GZipState_LastModifiedTime:
+ for (; header->PartsRead < 4; header->PartsRead++) {
+ temp = s->TryReadByte();
+ if (temp == -1) return;
+ }
+ header->State++;
+ header->PartsRead = 0;
+
+ case GZipState_CompressionFlags:
+ if (!Header_ReadByte(s, &header->State, &temp)) return;
+
+ case GZipState_OperatingSystem:
+ if (!Header_ReadByte(s, &header->State, &temp)) return;
+
+ case GZipState_Filename:
+ if ((header->Flags & 0x08) != 0) {
+ for (; ;) {
+ temp = s->TryReadByte();
+ if (temp == -1) return;
+ if (temp == 0) break;
+ }
+ }
+ header->State++;
+
+ case GZipState_Comment:
+ if ((header->Flags & 0x10) != 0) {
+ for (; ;) {
+ temp = s->TryReadByte();
+ if (temp == -1) return;
+ if (temp == 0) break;
+ }
+ }
+ header->State++;
+
+ case GZipState_HeaderChecksum:
+ if ((header->Flags & 0x02) != 0) {
+ for (; header->PartsRead < 2; header->PartsRead++) {
+ temp = s->TryReadByte();
+ if (temp == -1) return;
+ }
+ }
+
+ header->State++;
+ header->PartsRead = 0;
+ header->Done = true;
+ }
+}
+
+
+void ZLibHeader_Init(ZLibHeader* header) {
+ header->State = ZLibState_CompressionMethod;
+ header->Done = false;
+ header->LZ77WindowSize = 0;
+}
+
+void ZLibHeader_Read(Stream* s, ZLibHeader* header) {
+ Int32 temp;
+ switch (header->State) {
+
+ case ZLibState_CompressionMethod:
+ if (!Header_ReadByte(s, &header->State, &temp)) return;
+ if ((temp & 0x0F) != 0x08) {
+ ErrorHandler_Fail("Only DEFLATE compression supported");
+ }
+
+ Int32 log2Size = (temp >> 4) + 8;
+ header->LZ77WindowSize = 1L << log2Size;
+ if (header->LZ77WindowSize > 32768) {
+ ErrorHandler_Fail("LZ77 window size must be 32KB or less");
+ }
+
+ case ZLibState_Flags:
+ if (!Header_ReadByte(s, &header->State, &temp)) return;
+ if ((temp & 0x20) != 0) {
+ ErrorHandler_Fail("Unsupported ZLIB header flags");
+ }
+ header->Done = true;
+ }
+}
\ No newline at end of file
diff --git a/src/Client/Deflate.h b/src/Client/Deflate.h
new file mode 100644
index 000000000..56585fd56
--- /dev/null
+++ b/src/Client/Deflate.h
@@ -0,0 +1,32 @@
+#ifndef CS_DEFLATE_H
+#define CS_DEFLATE_H
+#include "Typedefs.h"
+#include "Stream.h"
+/* Decodes data compressed using DEFLATE.
+ Copyright 2017 ClassicalSharp | Licensed under BSD-3
+*/
+
+typedef struct GZipHeader_ {
+ UInt8 State;
+ bool Done;
+ UInt8 PartsRead;
+ Int32 Flags;
+} GZipHeader;
+
+/* Initalises state of GZIP header. */
+void GZipHeader_Init(GZipHeader* header);
+/* Reads part of the GZIP header. header.Done is set to true on completion of reading the header. */
+void GZipHeader_Read(Stream* s, GZipHeader* header);
+
+
+typedef struct ZLibHeader_ {
+ UInt8 State;
+ bool Done;
+ Int32 LZ77WindowSize;
+} ZLibHeader;
+
+/* Initalises state of ZLIB header. */
+void ZLibHeader_Init(ZLibHeader* header);
+/* Reads part of the ZLIB header. header.Done is set to true on completion of reading the header. */
+void ZLibHeader_Read(Stream* s, ZLibHeader* header);
+#endif
\ No newline at end of file
diff --git a/src/Client/GZipHeader.c b/src/Client/GZipHeader.c
deleted file mode 100644
index d574b9728..000000000
--- a/src/Client/GZipHeader.c
+++ /dev/null
@@ -1,94 +0,0 @@
-#include "GZipHeader.h"
-#include "ErrorHandler.h"
-
-void GZipHeader_Init(GZipHeader* header) {
- header->State = GZipState_Header1;
- header->Done = false;
- header->Flags = 0;
- header->PartsRead = 0;
-}
-
-bool GZipHeader_ReadByte(Stream* s, GZipHeader* header, Int32* value) {
- *value = s->TryReadByte();
- if (*value == -1) return false;
-
- header->State++;
- return true;
-}
-
-bool GZipHeader_ReadAndCheckByte(Stream* s, GZipHeader* header, UInt8 expected) {
- Int32 value;
- if (!GZipHeader_ReadByte(s, header, &value)) return false;
-
- if (value != expected) {
- ErrorHandler_Fail("Unexpected constant in GZIP header");
- }
- return true;
-}
-
-void GZipHeader_Read(Stream* s, GZipHeader* header) {
- Int32 temp;
- switch (header->State) {
-
- case GZipState_Header1:
- if (!GZipHeader_ReadAndCheckByte(s, header, 0x1F)) return;
-
- case GZipState_Header2:
- if (!GZipHeader_ReadAndCheckByte(s, header, 0x8B)) return;
-
- case GZipState_CompressionMethod:
- if (!GZipHeader_ReadAndCheckByte(s, header, 0x08)) return;
-
- case GZipState_Flags:
- if (!GZipHeader_ReadByte(s, header, &header->Flags)) return;
- if ((header->Flags & 0x04) != 0) {
- ErrorHandler_Fail("Unsupported GZIP header flags");
- }
-
- case GZipState_LastModifiedTime:
- for (; header->PartsRead < 4; header->PartsRead++) {
- temp = s->TryReadByte();
- if (temp == -1) return;
- }
- header->PartsRead = 0;
- header->State++;
-
- case GZipState_CompressionFlags:
- if (!GZipHeader_ReadByte(s, header, &temp)) return;
-
- case GZipState_OperatingSystem:
- if (!GZipHeader_ReadByte(s, header, &temp)) return;
-
- case GZipState_Filename:
- if ((header->Flags & 0x08) != 0) {
- for (; ;) {
- temp = s->TryReadByte();
- if (temp == -1) return;
- if (temp == 0) break;
- }
- }
- header->State++;
-
- case GZipState_Comment:
- if ((header->Flags & 0x10) != 0) {
- for (; ;) {
- temp = s->TryReadByte();
- if (temp == -1) return;
- if (temp == 0) break;
- }
- }
- header->State++;
-
- case GZipState_HeaderChecksum:
- if ((header->Flags & 0x02) != 0) {
- for (; header->PartsRead < 2; header->PartsRead++) {
- temp = s->TryReadByte();
- if (temp == -1) return;
- }
- }
- header->PartsRead = 0;
- header->State++;
-
- header->Done = true;
- }
-}
\ No newline at end of file
diff --git a/src/Client/GZipHeader.h b/src/Client/GZipHeader.h
deleted file mode 100644
index 3eb739eb9..000000000
--- a/src/Client/GZipHeader.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef CS_GZIPHEADERREADER_H
-#define CS_GZIPHEADERREADER_H
-#include "Typedefs.h"
-#include "Stream.h"
-/* Skips the GZip header in a stream.
- Copyright 2017 ClassicalSharp | Licensed under BSD-3
-*/
-
-typedef Int32 GZipState;
-#define GZipState_Header1 0
-#define GZipState_Header2 1
-#define GZipState_CompressionMethod 2
-#define GZipState_Flags 3
-#define GZipState_LastModifiedTime 4
-#define GZipState_CompressionFlags 5
-#define GZipState_OperatingSystem 6
-#define GZipState_HeaderChecksum 7
-#define GZipState_Filename 8
-#define GZipState_Comment 9
-#define GZipState_Done 10
-
-typedef struct GZipHeader_ {
- /* State header reader is up to.*/
- GZipState State;
- /* Whether header has finished being read. */
- bool Done;
- Int32 Flags;
- Int32 PartsRead;
-} GZipHeader;
-
-/* Initalises state of GZIP header. */
-void GZipHeader_Init(GZipHeader* header);
-/* Reads part of the GZIP header. header.Done is set to true on completion. */
-void GZipHeader_Read(Stream* s, GZipHeader* header);
-#endif
\ No newline at end of file