Compressor.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /**
  2. * Copyright (c) 2006-2015 LOVE Development Team
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. *
  8. * Permission is granted to anyone to use this software for any purpose,
  9. * including commercial applications, and to alter it and redistribute it
  10. * freely, subject to the following restrictions:
  11. *
  12. * 1. The origin of this software must not be misrepresented; you must not
  13. * claim that you wrote the original software. If you use this software
  14. * in a product, an acknowledgment in the product documentation would be
  15. * appreciated but is not required.
  16. * 2. Altered source versions must be plainly marked as such, and must not be
  17. * misrepresented as being the original software.
  18. * 3. This notice may not be removed or altered from any source distribution.
  19. **/
  20. // LOVE
  21. #include "Compressor.h"
  22. #include "common/config.h"
  23. #include "common/int.h"
  24. // LZ4
  25. #include "libraries/lz4/lz4.h"
  26. #include "libraries/lz4/lz4hc.h"
  27. // zlib
  28. #include <zlib.h>
  29. namespace love
  30. {
  31. namespace math
  32. {
  33. class LZ4Compressor : public Compressor
  34. {
  35. public:
  36. char *compress(const char *data, size_t dataSize, int level, size_t &compressedSize) override
  37. {
  38. if (dataSize > LZ4_MAX_INPUT_SIZE)
  39. throw love::Exception("Data is too large for LZ4 compressor.");
  40. // We use a custom header to store some info with the compressed data.
  41. const size_t headersize = sizeof(uint32);
  42. int maxdestsize = LZ4_compressBound((int) dataSize);
  43. size_t maxsize = headersize + (size_t) maxdestsize;
  44. char *compressedbytes = nullptr;
  45. try
  46. {
  47. compressedbytes = new char[maxsize];
  48. }
  49. catch (std::bad_alloc &)
  50. {
  51. throw love::Exception("Out of memory.");
  52. }
  53. // Store the size of the uncompressed data as a header.
  54. #ifdef LOVE_BIG_ENDIAN
  55. // Make sure it's little-endian for storage.
  56. *(uint32 *) compressedbytes = swap32((uint32) dataSize);
  57. #else
  58. *(uint32 *) compressedbytes = (uint32) dataSize;
  59. #endif
  60. // Use LZ4-HC for compression level 9 and higher.
  61. int csize = 0;
  62. if (level > 8)
  63. csize = LZ4_compress_HC(data, compressedbytes + headersize, (int) dataSize, maxdestsize, 0);
  64. else
  65. csize = LZ4_compress_default(data, compressedbytes + headersize, (int) dataSize, maxdestsize);
  66. if (csize <= 0)
  67. {
  68. delete[] compressedbytes;
  69. throw love::Exception("Could not LZ4-compress data.");
  70. }
  71. // We allocated space for the maximum possible amount of data, but the
  72. // actual compressed size might be much smaller, so we should shrink the
  73. // data buffer if so.
  74. if ((double) maxsize / (double) (csize + headersize) >= 1.2)
  75. {
  76. char *cbytes = new (std::nothrow) char[csize + headersize];
  77. if (cbytes)
  78. {
  79. memcpy(cbytes, compressedbytes, csize + headersize);
  80. delete[] compressedbytes;
  81. compressedbytes = cbytes;
  82. }
  83. }
  84. compressedSize = (size_t) csize + headersize;
  85. return compressedbytes;
  86. }
  87. char *decompress(const char *data, size_t dataSize, size_t &decompressedSize) override
  88. {
  89. const size_t headersize = sizeof(uint32);
  90. char *rawbytes = nullptr;
  91. if (dataSize < headersize)
  92. throw love::Exception("Invalid LZ4-compressed data size.");
  93. // Extract the original uncompressed size (stored in our custom header.)
  94. #ifdef LOVE_BIG_ENDIAN
  95. // Convert from stored little-endian to big-endian.
  96. uint32 rawsize = swap32(*(uint32 *) data);
  97. #else
  98. uint32 rawsize = *(uint32 *) data;
  99. #endif
  100. try
  101. {
  102. rawbytes = new char[rawsize];
  103. }
  104. catch (std::bad_alloc &)
  105. {
  106. throw love::Exception("Out of memory.");
  107. }
  108. // If the uncompressed size is passed in as an argument (non-zero) and
  109. // it matches the header's stored size, then we assume it's 100% accurate
  110. // and we use a more efficient decompression function.
  111. if (decompressedSize > 0 && decompressedSize == (size_t) rawsize)
  112. {
  113. // We don't use the header here, but we need to account for its size.
  114. if (LZ4_decompress_fast(data + headersize, rawbytes, (int) decompressedSize) < 0)
  115. {
  116. delete[] rawbytes;
  117. throw love::Exception("Could not decompress LZ4-compressed data.");
  118. }
  119. }
  120. else
  121. {
  122. // Account for our custom header's size in the decompress arguments.
  123. int result = LZ4_decompress_safe(data + headersize, rawbytes,
  124. dataSize - headersize, rawsize);
  125. if (result < 0)
  126. {
  127. delete[] rawbytes;
  128. throw love::Exception("Could not decompress LZ4-compressed data.");
  129. }
  130. decompressedSize = (size_t) result;
  131. }
  132. return rawbytes;
  133. }
  134. Compressor::Format getFormat() const override { return FORMAT_LZ4; }
  135. }; // LZ4Compressor
  136. class zlibCompressor : public Compressor
  137. {
  138. public:
  139. char *compress(const char *data, size_t dataSize, int level, size_t &compressedSize) override
  140. {
  141. if (level < 0)
  142. level = Z_DEFAULT_COMPRESSION;
  143. else if (level > 9)
  144. level = 9;
  145. uLong maxsize = compressBound((uLong) dataSize);
  146. char *compressedbytes = nullptr;
  147. try
  148. {
  149. compressedbytes = new char[maxsize];
  150. }
  151. catch (std::bad_alloc &)
  152. {
  153. throw love::Exception("Out of memory.");
  154. }
  155. uLongf destlen = maxsize;
  156. int status = compress2((Bytef *) compressedbytes, &destlen, (const Bytef *) data, (uLong) dataSize, level);
  157. if (status != Z_OK)
  158. {
  159. delete[] compressedbytes;
  160. throw love::Exception("Could not zlib-compress data.");
  161. }
  162. // We allocated space for the maximum possible amount of data, but the
  163. // actual compressed size might be much smaller, so we should shrink the
  164. // data buffer if so.
  165. if ((double) maxsize / (double) destlen >= 1.2)
  166. {
  167. char *cbytes = new (std::nothrow) char[destlen];
  168. if (cbytes)
  169. {
  170. memcpy(cbytes, compressedbytes, destlen);
  171. delete[] compressedbytes;
  172. compressedbytes = cbytes;
  173. }
  174. }
  175. compressedSize = (size_t) destlen;
  176. return compressedbytes;
  177. }
  178. char *decompress(const char *data, size_t dataSize, size_t &decompressedSize) override
  179. {
  180. char *rawbytes = nullptr;
  181. // We might know the output size before decompression. If not, we guess.
  182. size_t rawsize = decompressedSize > 0 ? decompressedSize : dataSize * 2;
  183. // Repeatedly try to decompress with an increasingly large output buffer.
  184. while (true)
  185. {
  186. try
  187. {
  188. rawbytes = new char[rawsize];
  189. }
  190. catch (std::bad_alloc &)
  191. {
  192. throw love::Exception("Out of memory.");
  193. }
  194. uLongf destLen = (uLongf) rawsize;
  195. int status = uncompress((Bytef *) rawbytes, &destLen, (const Bytef *) data, (uLong) dataSize);
  196. if (status == Z_OK)
  197. {
  198. decompressedSize = (size_t) destLen;
  199. break;
  200. }
  201. else if (status != Z_BUF_ERROR)
  202. {
  203. // For any error other than "not enough room", throw an exception.
  204. delete[] rawbytes;
  205. throw love::Exception("Could not decompress zlib-compressed data.");
  206. }
  207. // Not enough room in the output buffer: try again with a larger size.
  208. delete[] rawbytes;
  209. rawsize *= 2;
  210. }
  211. return rawbytes;
  212. }
  213. Compressor::Format getFormat() const override { return FORMAT_ZLIB; }
  214. }; // zlibCompressor
  215. Compressor *Compressor::Create(Format format)
  216. {
  217. switch (format)
  218. {
  219. case FORMAT_LZ4:
  220. return new LZ4Compressor;
  221. case FORMAT_ZLIB:
  222. return new zlibCompressor;
  223. default:
  224. throw love::Exception("Invalid compressor format.");
  225. return nullptr;
  226. }
  227. }
  228. bool Compressor::getConstant(const char *in, Format &out)
  229. {
  230. return formatNames.find(in, out);
  231. }
  232. bool Compressor::getConstant(Format in, const char *&out)
  233. {
  234. return formatNames.find(in, out);
  235. }
  236. StringMap<Compressor::Format, Compressor::FORMAT_MAX_ENUM>::Entry Compressor::formatEntries[] =
  237. {
  238. {"lz4", Compressor::FORMAT_LZ4},
  239. {"zlib", Compressor::FORMAT_ZLIB},
  240. };
  241. StringMap<Compressor::Format, Compressor::FORMAT_MAX_ENUM> Compressor::formatNames(Compressor::formatEntries, sizeof(Compressor::formatEntries));
  242. } // math
  243. } // love