Skip to content

Commit 93df776

Browse files
committed
Add zlib compression support
1 parent a744cd1 commit 93df776

File tree

5 files changed

+256
-3
lines changed

5 files changed

+256
-3
lines changed

Shared/mods/deathmatch/logic/Enums.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ ADD_ENUM(StringEncodeFunction::AES128, "aes128")
6969
ADD_ENUM(StringEncodeFunction::RSA, "rsa")
7070
ADD_ENUM(StringEncodeFunction::BASE64, "base64")
7171
ADD_ENUM(StringEncodeFunction::BASE32, "base32")
72+
ADD_ENUM(StringEncodeFunction::ZLIB, "zlib")
7273
IMPLEMENT_ENUM_CLASS_END("string-encode-function")
7374

7475
IMPLEMENT_ENUM_CLASS_BEGIN(KeyPairAlgorithm)
@@ -84,6 +85,20 @@ ADD_ENUM(HmacAlgorithm::SHA384, "sha384")
8485
ADD_ENUM(HmacAlgorithm::SHA512, "sha512")
8586
IMPLEMENT_ENUM_CLASS_END("hmac-algorithm")
8687

88+
IMPLEMENT_ENUM_CLASS_BEGIN(ZLibFormat)
89+
ADD_ENUM(ZLibFormat::ZRAW, "raw")
90+
ADD_ENUM(ZLibFormat::ZLIB, "zlib")
91+
ADD_ENUM(ZLibFormat::GZIP, "gzip")
92+
IMPLEMENT_ENUM_CLASS_END("zlib-format")
93+
94+
IMPLEMENT_ENUM_CLASS_BEGIN(ZLibStrategy)
95+
ADD_ENUM(ZLibStrategy::DEFAULT, "default")
96+
ADD_ENUM(ZLibStrategy::FILTERED, "filtered")
97+
ADD_ENUM(ZLibStrategy::HUFFMAN_ONLY, "huffman")
98+
ADD_ENUM(ZLibStrategy::RLE, "rle")
99+
ADD_ENUM(ZLibStrategy::FIXED, "fixed")
100+
IMPLEMENT_ENUM_CLASS_END("zlib-strategy")
101+
87102
IMPLEMENT_ENUM_CLASS_BEGIN(WorldSpecialProperty)
88103
ADD_ENUM(WorldSpecialProperty::HOVERCARS, "hovercars")
89104
ADD_ENUM(WorldSpecialProperty::AIRCARS, "aircars")

Shared/mods/deathmatch/logic/Enums.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ DECLARE_ENUM_CLASS(PasswordHashFunction);
7272
DECLARE_ENUM_CLASS(StringEncodeFunction);
7373
DECLARE_ENUM_CLASS(KeyPairAlgorithm);
7474
DECLARE_ENUM_CLASS(HmacAlgorithm);
75+
DECLARE_ENUM_CLASS(ZLibFormat);
76+
DECLARE_ENUM_CLASS(ZLibStrategy);
7577

7678
enum class WorldSpecialProperty
7779
{

Shared/mods/deathmatch/logic/luadefs/CLuaCryptDefs.cpp

Lines changed: 150 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,8 @@ int CLuaCryptDefs::EncodeString(lua_State* luaVM)
403403
argStream.ReadEnumString(algorithm);
404404
argStream.ReadString(data);
405405

406-
if ((algorithm != StringEncodeFunction::BASE64 && algorithm != StringEncodeFunction::BASE32) || argStream.NextIsTable())
406+
if ((algorithm != StringEncodeFunction::BASE64 && algorithm != StringEncodeFunction::BASE32 && algorithm != StringEncodeFunction::ZLIB) ||
407+
argStream.NextIsTable())
407408
{
408409
argStream.ReadStringMap(options);
409410
}
@@ -727,6 +728,88 @@ int CLuaCryptDefs::EncodeString(lua_State* luaVM)
727728
}
728729
return 1;
729730
}
731+
case StringEncodeFunction::ZLIB:
732+
{
733+
int compression = 9;
734+
ZLibFormat format = ZLibFormat::GZIP;
735+
ZLibStrategy strategy = ZLibStrategy::DEFAULT;
736+
if (!options["format"].empty() && !StringToEnum(options["format"], format))
737+
{
738+
m_pScriptDebugging->LogCustom(luaVM, "Invalid value for field 'format'");
739+
lua::Push(luaVM, false);
740+
return 1;
741+
}
742+
if (!options["strategy"].empty() && !StringToEnum(options["strategy"], strategy))
743+
{
744+
m_pScriptDebugging->LogCustom(luaVM, "Invalid value for field 'strategy'");
745+
lua::Push(luaVM, false);
746+
return 1;
747+
}
748+
if (!options["compression"].empty())
749+
{
750+
compression = atoi(options["compression"].c_str());
751+
if (compression < 0 || compression > 9)
752+
{
753+
m_pScriptDebugging->LogCustom(luaVM, "Value for field 'compression' is out of range (0-9)");
754+
lua::Push(luaVM, false);
755+
return 1;
756+
}
757+
}
758+
759+
// Async
760+
if (VERIFY_FUNCTION(luaFunctionRef))
761+
{
762+
CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine(luaVM);
763+
if (pLuaMain)
764+
{
765+
CLuaShared::GetAsyncTaskScheduler()->PushTask(
766+
[data, format, compression, strategy]
767+
{
768+
// Execute time-consuming task
769+
SString output;
770+
int result = SharedUtil::ZLibCompress(data, &output, format, compression, strategy);
771+
if (result == Z_STREAM_END)
772+
return std::make_pair(output, true);
773+
else
774+
return std::make_pair(SString("zlib error: %i", result), false);
775+
},
776+
[luaFunctionRef](const std::pair<SString, bool>& result)
777+
{
778+
CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine(luaFunctionRef.GetLuaVM());
779+
if (pLuaMain)
780+
{
781+
CLuaArguments arguments;
782+
if (result.second)
783+
{
784+
arguments.PushString(result.first);
785+
arguments.Call(pLuaMain, luaFunctionRef);
786+
}
787+
else
788+
{
789+
m_pScriptDebugging->LogWarning(luaFunctionRef.GetLuaVM(), result.first.c_str());
790+
arguments.PushBoolean(false);
791+
arguments.Call(pLuaMain, luaFunctionRef);
792+
}
793+
}
794+
});
795+
796+
lua_pushboolean(luaVM, true);
797+
}
798+
}
799+
else // Sync
800+
{
801+
SString output;
802+
int result = SharedUtil::ZLibCompress(data, &output, format, compression, strategy);
803+
if (result == Z_STREAM_END)
804+
lua::Push(luaVM, output);
805+
else
806+
{
807+
m_pScriptDebugging->LogWarning(luaVM, "zlib error: %i", result);
808+
lua::Push(luaVM, false);
809+
}
810+
}
811+
return 1;
812+
}
730813
default:
731814
{
732815
m_pScriptDebugging->LogCustom(luaVM, "Unknown encryption algorithm");
@@ -753,7 +836,8 @@ int CLuaCryptDefs::DecodeString(lua_State* luaVM)
753836
argStream.ReadEnumString(algorithm);
754837
argStream.ReadString(data);
755838

756-
if ((algorithm != StringEncodeFunction::BASE64 && algorithm != StringEncodeFunction::BASE32) || argStream.NextIsTable())
839+
if ((algorithm != StringEncodeFunction::BASE64 && algorithm != StringEncodeFunction::BASE32 && algorithm != StringEncodeFunction::ZLIB) ||
840+
argStream.NextIsTable())
757841
{
758842
argStream.ReadStringMap(options);
759843
}
@@ -1084,6 +1168,70 @@ int CLuaCryptDefs::DecodeString(lua_State* luaVM)
10841168
}
10851169
return 1;
10861170
}
1171+
case StringEncodeFunction::ZLIB:
1172+
{
1173+
ZLibFormat format = ZLibFormat::AUTO;
1174+
if (!options["format"].empty() && !StringToEnum(options["format"], format))
1175+
{
1176+
m_pScriptDebugging->LogCustom(luaVM, "Not supported value for field 'format'");
1177+
lua::Push(luaVM, false);
1178+
return 1;
1179+
}
1180+
1181+
// Async
1182+
if (VERIFY_FUNCTION(luaFunctionRef))
1183+
{
1184+
CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine(luaVM);
1185+
if (pLuaMain)
1186+
{
1187+
CLuaShared::GetAsyncTaskScheduler()->PushTask(
1188+
[data, format]
1189+
{
1190+
// Execute time-consuming task
1191+
SString output;
1192+
int result = SharedUtil::ZLibUncompress(data, &output, format);
1193+
if (result == Z_STREAM_END)
1194+
return std::make_pair(output, true);
1195+
else
1196+
return std::make_pair(SString("zlib error: %i", result), false);
1197+
},
1198+
[luaFunctionRef](const std::pair<SString, bool>& result)
1199+
{
1200+
CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine(luaFunctionRef.GetLuaVM());
1201+
if (pLuaMain)
1202+
{
1203+
CLuaArguments arguments;
1204+
if (result.second)
1205+
{
1206+
arguments.PushString(result.first);
1207+
arguments.Call(pLuaMain, luaFunctionRef);
1208+
}
1209+
else
1210+
{
1211+
m_pScriptDebugging->LogWarning(luaFunctionRef.GetLuaVM(), result.first.c_str());
1212+
arguments.PushBoolean(false);
1213+
arguments.Call(pLuaMain, luaFunctionRef);
1214+
}
1215+
}
1216+
});
1217+
1218+
lua_pushboolean(luaVM, true);
1219+
}
1220+
}
1221+
else // Sync
1222+
{
1223+
SString output;
1224+
int result = SharedUtil::ZLibUncompress(data, &output, format);
1225+
if (result == Z_STREAM_END)
1226+
lua::Push(luaVM, output);
1227+
else
1228+
{
1229+
m_pScriptDebugging->LogWarning(luaVM, "zlib error: %i", result);
1230+
lua::Push(luaVM, false);
1231+
}
1232+
}
1233+
return 1;
1234+
}
10871235
default:
10881236
{
10891237
m_pScriptDebugging->LogCustom(luaVM, "Unknown encryption algorithm");

Shared/sdk/SharedUtil.Crypto.h

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <cryptopp/hmac.h>
1818
#include <cryptopp/hex.h>
1919
#include <cryptopp/md5.h>
20+
#include <zlib/zlib.h>
2021
#include "SString.h"
2122

2223
namespace SharedUtil
@@ -202,4 +203,73 @@ namespace SharedUtil
202203

203204
return result;
204205
}
206+
207+
inline int ZLibCompress(const std::string input, std::string* output, const ZLibFormat format = ZLibFormat::GZIP, const int compression = 9,
208+
const ZLibStrategy strategy = ZLibStrategy::DEFAULT)
209+
{
210+
z_stream stream{};
211+
212+
int result = deflateInit2(&stream, compression, Z_DEFLATED, (int)format, MAX_MEM_LEVEL, (int)strategy);
213+
if (result != Z_OK)
214+
return result;
215+
216+
output->resize(deflateBound(&stream, input.size())); // resize to the upper bound of what the compressed size might be
217+
218+
stream.next_out = (Bytef*)output->data();
219+
stream.avail_out = output->size();
220+
221+
stream.next_in = (z_const Bytef*)input.data();
222+
stream.avail_in = input.size();
223+
224+
result = deflate(&stream, Z_FINISH);
225+
result |= deflateEnd(&stream);
226+
227+
if (result == Z_STREAM_END)
228+
output->resize(stream.total_out); // resize to the actual size
229+
230+
return result;
231+
}
232+
233+
inline int ZLibUncompress(const std::string& input, std::string* output, const ZLibFormat format = ZLibFormat::AUTO)
234+
{
235+
int windowBits = (int)format;
236+
if (format == ZLibFormat::AUTO)
237+
{
238+
if (input[0] == 0x78)
239+
windowBits = (int)ZLibFormat::ZLIB;
240+
else if (input[0] == 0x1F)
241+
windowBits = (int)ZLibFormat::GZIP;
242+
else
243+
windowBits = (int)ZLibFormat::ZRAW;
244+
}
245+
z_stream stream{};
246+
247+
int result = inflateInit2(&stream, windowBits);
248+
if (result != Z_OK)
249+
return result;
250+
251+
stream.next_in = (z_const Bytef*)input.data();
252+
stream.avail_in = input.size();
253+
254+
// Uncompress in chunks
255+
std::string buffer;
256+
buffer.resize(std::min(stream.avail_in, 128000U)); // use input length for chunk size (capped to 128k bytes which should be efficient enough)
257+
while (true)
258+
{
259+
stream.next_out = (Bytef*)buffer.data();
260+
stream.avail_out = buffer.size();
261+
262+
result = inflate(&stream, Z_NO_FLUSH);
263+
if (result != Z_OK && result != Z_STREAM_END)
264+
break;
265+
266+
output->append(buffer, 0, stream.total_out - output->size()); // append only what was written to buffer
267+
268+
if (result == Z_STREAM_END)
269+
break;
270+
}
271+
result |= inflateEnd(&stream);
272+
return result;
273+
}
274+
205275
} // namespace SharedUtil

Shared/sdk/SharedUtil.Hash.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ enum class StringEncodeFunction
4949
AES128,
5050
RSA,
5151
BASE64,
52-
BASE32
52+
BASE32,
53+
ZLIB,
5354
};
5455

5556
enum class KeyPairAlgorithm
@@ -67,6 +68,23 @@ enum class HmacAlgorithm
6768
SHA512,
6869
};
6970

71+
enum class ZLibFormat
72+
{
73+
AUTO = 0,
74+
ZRAW = -15,
75+
ZLIB = 15,
76+
GZIP = 31,
77+
};
78+
79+
enum class ZLibStrategy
80+
{
81+
DEFAULT,
82+
FILTERED,
83+
HUFFMAN_ONLY,
84+
RLE,
85+
FIXED,
86+
};
87+
7088
namespace SharedUtil
7189
{
7290
struct MD5

0 commit comments

Comments
 (0)