Cuberite
A lightweight, fast and extensible game server for Minecraft
StringCompression.cpp
Go to the documentation of this file.
1 
2 // StringCompression.cpp
3 
4 // Implements the wrapping functions for compression and decompression using AString as their data
5 
6 #include "Globals.h"
7 #include "StringCompression.h"
8 
9 
10 
11 
12 
13 int CompressString(const char * a_Data, size_t a_Length, AString & a_Compressed, int a_Factor)
14 {
15  uLongf CompressedSize = compressBound(static_cast<uLong>(a_Length));
16 
17  // HACK: We're assuming that AString returns its internal buffer in its data() call and we're overwriting that buffer!
18  // It saves us one allocation and one memcpy of the entire compressed data
19  // It may not work on some STL implementations! (Confirmed working on all currently used MSVC, GCC and Clang versions)
20  a_Compressed.resize(CompressedSize);
21  int errorcode = compress2(reinterpret_cast<Bytef *>(const_cast<char *>(a_Compressed.data())), &CompressedSize, reinterpret_cast<const Bytef *>(a_Data), static_cast<uLong>(a_Length), a_Factor);
22  if (errorcode != Z_OK)
23  {
24  return errorcode;
25  }
26  a_Compressed.resize(CompressedSize);
27  return Z_OK;
28 }
29 
30 
31 
32 
33 
34 int UncompressString(const char * a_Data, size_t a_Length, AString & a_Uncompressed, size_t a_UncompressedSize)
35 {
36  // HACK: We're assuming that AString returns its internal buffer in its data() call and we're overwriting that buffer!
37  // It saves us one allocation and one memcpy of the entire compressed data
38  // It may not work on some STL implementations! (Confirmed working on all currently used MSVC, GCC and Clang versions)
39  a_Uncompressed.resize(a_UncompressedSize);
40  uLongf UncompressedSize = static_cast<uLongf>(a_UncompressedSize); // On some architectures the uLongf is different in size to int, that may be the cause of the -5 error
41  int errorcode = uncompress(reinterpret_cast<Bytef *>(const_cast<char *>(a_Uncompressed.data())), &UncompressedSize, reinterpret_cast<const Bytef *>(a_Data), static_cast<uLong>(a_Length));
42  if (errorcode != Z_OK)
43  {
44  return errorcode;
45  }
46  a_Uncompressed.resize(UncompressedSize);
47  return Z_OK;
48 }
49 
50 
51 
52 
53 
54 int CompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Compressed)
55 {
56  // Compress a_Data into a_Compressed using GZIP; return Z_XXX error constants same as zlib's compress2()
57 
58  a_Compressed.reserve(a_Length);
59 
60  char Buffer[64 KiB];
61  z_stream strm;
62  memset(&strm, 0, sizeof(strm));
63  strm.next_in = reinterpret_cast<Bytef *>(const_cast<char *>(a_Data));
64  strm.avail_in = static_cast<uInt>(a_Length);
65  strm.next_out = reinterpret_cast<Bytef *>(Buffer);
66  strm.avail_out = sizeof(Buffer);
67 
68  int res = deflateInit2(&strm, 9, Z_DEFLATED, 31, 9, Z_DEFAULT_STRATEGY);
69  if (res != Z_OK)
70  {
71  LOG("%s: compression initialization failed: %d (\"%s\").", __FUNCTION__, res, strm.msg);
72  return res;
73  }
74 
75  for (;;)
76  {
77  res = deflate(&strm, Z_FINISH);
78  switch (res)
79  {
80  case Z_OK:
81  {
82  // Some data has been compressed. Consume the buffer and continue compressing
83  a_Compressed.append(Buffer, sizeof(Buffer) - strm.avail_out);
84  strm.next_out = reinterpret_cast<Bytef *>(Buffer);
85  strm.avail_out = sizeof(Buffer);
86  if (strm.avail_in == 0)
87  {
88  // All data has been compressed
89  deflateEnd(&strm);
90  return Z_OK;
91  }
92  break;
93  }
94 
95  case Z_STREAM_END:
96  {
97  // Finished compressing. Consume the rest of the buffer and return
98  a_Compressed.append(Buffer, sizeof(Buffer) - strm.avail_out);
99  deflateEnd(&strm);
100  return Z_OK;
101  }
102 
103  default:
104  {
105  // An error has occurred, log it and return the error value
106  LOG("%s: compression failed: %d (\"%s\").", __FUNCTION__, res, strm.msg);
107  deflateEnd(&strm);
108  return res;
109  }
110  } // switch (res)
111  } // while (true)
112 }
113 
114 
115 
116 
117 
118 extern int UncompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Uncompressed)
119 {
120  // Uncompresses a_Data into a_Uncompressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib
121 
122  a_Uncompressed.reserve(a_Length);
123 
124  char Buffer[64 KiB];
125  z_stream strm;
126  memset(&strm, 0, sizeof(strm));
127  strm.next_in = reinterpret_cast<Bytef *>(const_cast<char *>(a_Data));
128  strm.avail_in = static_cast<uInt>(a_Length);
129  strm.next_out = reinterpret_cast<Bytef *>(Buffer);
130  strm.avail_out = sizeof(Buffer);
131 
132  int res = inflateInit2(&strm, 31); // Force GZIP decoding
133  if (res != Z_OK)
134  {
135  LOG("%s: uncompression initialization failed: %d (\"%s\").", __FUNCTION__, res, strm.msg);
136  return res;
137  }
138 
139  for (;;)
140  {
141  res = inflate(&strm, Z_NO_FLUSH);
142  switch (res)
143  {
144  case Z_OK:
145  {
146  // Some data has been uncompressed. Consume the buffer and continue uncompressing
147  a_Uncompressed.append(Buffer, sizeof(Buffer) - strm.avail_out);
148  strm.next_out = reinterpret_cast<Bytef *>(Buffer);
149  strm.avail_out = sizeof(Buffer);
150  if (strm.avail_in == 0)
151  {
152  // All data has been uncompressed
153  inflateEnd(&strm);
154  return Z_OK;
155  }
156  break;
157  }
158 
159  case Z_STREAM_END:
160  {
161  // Finished uncompressing. Consume the rest of the buffer and return
162  a_Uncompressed.append(Buffer, sizeof(Buffer) - strm.avail_out);
163  inflateEnd(&strm);
164  return Z_OK;
165  }
166 
167  default:
168  {
169  // An error has occurred, log it and return the error value
170  LOG("%s: uncompression failed: %d (\"%s\").", __FUNCTION__, res, strm.msg);
171  inflateEnd(&strm);
172  return res;
173  }
174  } // switch (res)
175  } // while (true)
176 }
177 
178 
179 
180 
181 
182 extern int InflateString(const char * a_Data, size_t a_Length, AString & a_Uncompressed)
183 {
184  a_Uncompressed.reserve(a_Length);
185 
186  char Buffer[64 KiB];
187  z_stream strm;
188  memset(&strm, 0, sizeof(strm));
189  strm.next_in = reinterpret_cast<Bytef *>(const_cast<char *>(a_Data));
190  strm.avail_in = static_cast<uInt>(a_Length);
191  strm.next_out = reinterpret_cast<Bytef *>(Buffer);
192  strm.avail_out = sizeof(Buffer);
193 
194  int res = inflateInit(&strm); // Force GZIP decoding
195  if (res != Z_OK)
196  {
197  LOG("%s: inflation initialization failed: %d (\"%s\").", __FUNCTION__, res, strm.msg);
198  return res;
199  }
200 
201  for (;;)
202  {
203  res = inflate(&strm, Z_NO_FLUSH);
204  switch (res)
205  {
206  case Z_OK:
207  {
208  // Some data has been uncompressed. Consume the buffer and continue uncompressing
209  a_Uncompressed.append(Buffer, sizeof(Buffer) - strm.avail_out);
210  strm.next_out = reinterpret_cast<Bytef *>(Buffer);
211  strm.avail_out = sizeof(Buffer);
212  if (strm.avail_in == 0)
213  {
214  // All data has been uncompressed
215  inflateEnd(&strm);
216  return Z_OK;
217  }
218  break;
219  }
220 
221  case Z_STREAM_END:
222  {
223  // Finished uncompressing. Consume the rest of the buffer and return
224  a_Uncompressed.append(Buffer, sizeof(Buffer) - strm.avail_out);
225  inflateEnd(&strm);
226  return Z_OK;
227  }
228 
229  default:
230  {
231  // An error has occurred, log it and return the error value
232  LOG("%s: inflation failed: %d (\"%s\").", __FUNCTION__, res, strm.msg);
233  inflateEnd(&strm);
234  return res;
235  }
236  } // switch (res)
237  } // while (true)
238 }
239 
240 
241 
242 
int InflateString(const char *a_Data, size_t a_Length, AString &a_Uncompressed)
Uncompresses a_Data into a_Uncompressed using Inflate; returns Z_OK for success or Z_XXX error consta...
int CompressString(const char *a_Data, size_t a_Length, AString &a_Compressed, int a_Factor)
Compresses a_Data into a_Compressed using ZLIB; returns Z_XXX error constants same as zlib&#39;s compress...
#define KiB
Allows arithmetic expressions like "32 KiB" (but consider using parenthesis around it...
Definition: Globals.h:293
int UncompressStringGZIP(const char *a_Data, size_t a_Length, AString &a_Uncompressed)
Uncompresses a_Data into a_Uncompressed using GZIP; returns Z_OK for success or Z_XXX error constants...
std::string AString
Definition: StringUtils.h:13
void LOG(const char *a_Format, fmt::ArgList a_ArgList)
Definition: Logger.cpp:156
int UncompressString(const char *a_Data, size_t a_Length, AString &a_Uncompressed, size_t a_UncompressedSize)
Uncompresses a_Data into a_Uncompressed; returns Z_XXX error constants same as zlib&#39;s decompress() ...
int CompressStringGZIP(const char *a_Data, size_t a_Length, AString &a_Compressed)
Compresses a_Data into a_Compressed using GZIP; returns Z_OK for success or Z_XXX error constants sam...