Compression.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. /* Copyright (c) 2002-2012 Croteam Ltd.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of version 2 of the GNU General Public License as published by
  4. the Free Software Foundation
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License along
  10. with this program; if not, write to the Free Software Foundation, Inc.,
  11. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
  12. #include "stdh.h"
  13. #include <Engine/Base/Stream.h>
  14. #include <Engine/Network/Compression.h>
  15. #include <Engine/Base/Synchronization.h>
  16. #include <Engine/zlib/zlib.h>
  17. extern CTCriticalSection zip_csLock; // critical section for access to zlib functions
  18. /* Unpack from stream to stream. */
  19. void CCompressor::UnpackStream_t(CTMemoryStream &strmSrc, CTStream &strmDst) // throw char *
  20. {
  21. // read the header
  22. SLONG slSizeDst, slSizeSrc;
  23. strmSrc>>slSizeDst;
  24. strmSrc>>slSizeSrc;
  25. // get the buffer of source stream
  26. UBYTE *pubSrc = strmSrc.mstrm_pubBuffer + strmSrc.mstrm_slLocation;
  27. // allocate buffer for decompression
  28. UBYTE *pubDst = (UBYTE*)AllocMemory(slSizeDst);
  29. // compress there
  30. BOOL bOk = Unpack(pubSrc, slSizeSrc, pubDst, slSizeDst);
  31. // if failed
  32. if (!bOk) {
  33. // report error
  34. FreeMemory(pubDst);
  35. ThrowF_t(TRANS("Error while unpacking a stream."));
  36. }
  37. // write the uncompressed data to destination
  38. strmDst.Write_t(pubDst, slSizeDst);
  39. strmDst.SetPos_t(0);
  40. FreeMemory(pubDst);
  41. }
  42. void CCompressor::PackStream_t(CTMemoryStream &strmSrc, CTStream &strmDst) // throw char *
  43. {
  44. // get the buffer of source stream
  45. UBYTE *pubSrc = strmSrc.mstrm_pubBuffer + strmSrc.mstrm_slLocation;
  46. SLONG slSizeSrc = strmSrc.GetStreamSize();
  47. // allocate buffer for compression
  48. SLONG slSizeDst = NeededDestinationSize(slSizeSrc);
  49. UBYTE *pubDst = (UBYTE*)AllocMemory(slSizeDst);
  50. // compress there
  51. BOOL bOk = Pack(pubSrc, slSizeSrc, pubDst, slSizeDst);
  52. // if failed
  53. if (!bOk) {
  54. // report error
  55. FreeMemory(pubDst);
  56. ThrowF_t(TRANS("Error while packing a stream."));
  57. }
  58. // write the header to destination
  59. strmDst<<slSizeSrc;
  60. strmDst<<slSizeDst;
  61. // write the compressed data to destination
  62. strmDst.Write_t(pubDst, slSizeDst);
  63. FreeMemory(pubDst);
  64. }
  65. /////////////////////////////////////////////////////////////////////
  66. // RLE compressor
  67. /*
  68. RLE packed format(s):
  69. NOTE:
  70. In order to decompress packed data, size of original data must be known, it is not
  71. written in the packed data by the algorithms. Depending on the usage, data size may be
  72. included in the header by the called function. This generally saves even more space
  73. if smaller chunks of known size are compressed (e.g. small networks packets).
  74. Basic implemented packing format here is BYTE-BYTE. It packes data by bytes and uses bytes
  75. for packing codes. Other sized RLE formats can be implemented as needed (WORD-WORD,
  76. LONG-LONG, BYTE-WORD, WORD-BYTE etc.).
  77. Packed data is divided in sections, each section has a leading byte as code and compressed
  78. data following it. The data is interpreted differently, depending on the code.
  79. 1) CODE<0 => REPLICATION
  80. If the code is negative, following data is one byte that is replicated given number of
  81. times:
  82. CODE DATA -> DATA DATA DATA ... DATA ((-CODE)+1 times)
  83. (note that it is not possible to encode just one byte this way, since one byte can be coded
  84. well with copying)
  85. (count = -code+1 => code = -count+1)
  86. 2) CODE>=0 => COPYING
  87. If the code is positive, following data is given number of bytes that are just copied:
  88. CODE DAT0 DAT1 ... DATn -> DAT0 DAT1 ... DATn (n=CODE)
  89. (note that CODE=0 means copy next one byte)
  90. (count = code+1 => code = count-1)
  91. Packing algorithm used here relies on the destination buffer being big enough to
  92. hold packed data. Generally, for BYTE-BYTE packing, maximum buffer is 129/128 of
  93. original size (degenerate case with no data replication).
  94. */
  95. /*
  96. * Calculate needed size for destination buffer when packing memory.
  97. */
  98. SLONG CRLEBBCompressor::NeededDestinationSize(SLONG slSourceSize)
  99. {
  100. // calculate worst case possible for size of RLEBB packed data
  101. // *129/128+1 would be enough, but we add some more to ensure that we don't
  102. // overwrite the temporary buffer
  103. return slSourceSize*129/128 + 5;
  104. }
  105. // on entry, slDstSize holds maximum size of output buffer,
  106. // on exit, it is filled with resulting size
  107. /* Pack a chunk of data using given compression. */
  108. BOOL CRLEBBCompressor::Pack(const void *pvSrc, SLONG slSrcSize, void *pvDst, SLONG &slDstSize)
  109. {
  110. // cannot pack zero bytes
  111. ASSERT(slSrcSize>=1);
  112. // calculate limits for source and destination buffers
  113. const SBYTE *pbSourceFirst = (const SBYTE *)pvSrc; // start marker
  114. const SBYTE *pbSourceLimit = (const SBYTE *)pvSrc+slSrcSize; // end marker
  115. // SLONG slDestinationSize=NeededDestinationSize(slSrcSize);
  116. SBYTE *pbDestinationFirst = (SBYTE *)pvDst; // start marker
  117. SBYTE *pbDestinationLimit = (SBYTE *)pvDst+slDstSize; // end marker
  118. UBYTE *pbCountFirst = (UBYTE *)pbDestinationLimit-slSrcSize; // start marker
  119. UBYTE *pbCountLimit = (UBYTE *)pbDestinationLimit; // end marker
  120. {
  121. /* PASS 1: Use destination buffer to cache number of forward-same bytes. */
  122. // set the count of the last byte to one
  123. UBYTE *pbCount = pbCountLimit-1;
  124. *pbCount-- = 1;
  125. // for all bytes from one before last to the first one
  126. for(const SBYTE *pbSource = pbSourceLimit-2;
  127. pbSource>=pbSourceFirst;
  128. pbSource--, pbCount--) {
  129. // if the byte is same as its successor, and the count will fit in code
  130. if (pbSource[0]==pbSource[1] && (SLONG)pbCount[1]+1<=-(SLONG)MIN_SBYTE) {
  131. // set its count to the count of its successor plus one
  132. pbCount[0] = pbCount[1]+1;
  133. // if the byte is different than its successor
  134. } else {
  135. // set its count to one
  136. pbCount[0] = 1;
  137. }
  138. }
  139. }
  140. /* PASS 2: Pack bytes from source to the destination buffer. */
  141. // start at the beginning of the buffers
  142. const SBYTE *pbSource = pbSourceFirst;
  143. const UBYTE *pbCount = pbCountFirst;
  144. SBYTE *pbDestination = pbDestinationFirst;
  145. // while there is some data to pack
  146. while(pbSource<pbSourceLimit) {
  147. ASSERT(pbCount<pbCountLimit);
  148. // if current byte is replicated
  149. if (*pbCount>1) {
  150. // write the replicate-packed data
  151. INDEX ctSameBytes = (INDEX)*pbCount;
  152. SLONG slCode = -ctSameBytes+1;
  153. ASSERT((SLONG)MIN_SBYTE<=slCode && slCode<0);
  154. *pbDestination++ = (SBYTE)slCode;
  155. *pbDestination++ = pbSource[0];
  156. pbSource+=ctSameBytes;
  157. pbCount +=ctSameBytes;
  158. // if current byte is not replicated
  159. } else {
  160. // count bytes to copy before encountering byte replicated more than 3 times
  161. INDEX ctDiffBytes=1;
  162. while( (ctDiffBytes < (SLONG)MAX_SBYTE + 1)
  163. && (&pbSource[ctDiffBytes]<pbSourceLimit) ) {
  164. if ((SLONG)pbCount[ctDiffBytes-1]<=3) {
  165. ctDiffBytes++;
  166. } else {
  167. break;
  168. }
  169. }
  170. // write the copy-packed data
  171. SLONG slCode = ctDiffBytes-1;
  172. ASSERT(0<=slCode && slCode<=(SLONG)MAX_SBYTE);
  173. *pbDestination++ = (SBYTE)slCode;
  174. memcpy(pbDestination, pbSource, ctDiffBytes);
  175. pbSource += ctDiffBytes;
  176. pbCount += ctDiffBytes;
  177. pbDestination += ctDiffBytes;
  178. }
  179. }
  180. // packing must exactly be finished now
  181. ASSERT(pbSource==pbSourceLimit);
  182. ASSERT(pbCount ==pbCountLimit);
  183. // calculate size of packed data
  184. slDstSize = pbDestination-pbDestinationFirst;
  185. return TRUE;
  186. }
  187. // on entry, slDstSize holds maximum size of output buffer,
  188. // on exit, it is filled with resulting size
  189. /* Unpack a chunk of data using given compression. */
  190. BOOL CRLEBBCompressor::Unpack(const void *pvSrc, SLONG slSrcSize, void *pvDst, SLONG &slDstSize)
  191. {
  192. const SBYTE *pbSource = (const SBYTE *)pvSrc; // current pointer
  193. const SBYTE *pbSourceLimit = (const SBYTE *)pvSrc+slSrcSize; // end marker
  194. SBYTE *pbDestination = (SBYTE *)pvDst; // current pointer
  195. SBYTE *pbDestinationFirst = (SBYTE *)pvDst; // start marker
  196. // repeat
  197. do {
  198. // get code
  199. SLONG slCode = *pbSource++;
  200. // if it is replication
  201. if (slCode<0) {
  202. // get next byte and replicate it given number of times
  203. INDEX ctSameBytes = -slCode+1;
  204. memset(pbDestination, *pbSource++, ctSameBytes);
  205. pbDestination += ctSameBytes;
  206. // if it is copying
  207. } else {
  208. // copy given number of next bytes
  209. INDEX ctCopyBytes = slCode+1;
  210. memcpy(pbDestination, pbSource, ctCopyBytes);
  211. pbSource += ctCopyBytes;
  212. pbDestination += ctCopyBytes;
  213. }
  214. // until all data is unpacked
  215. } while (pbSource<pbSourceLimit);
  216. // data must be unpacked correctly
  217. ASSERT(pbSource==pbSourceLimit);
  218. // calculate size of data that was unpacked
  219. slDstSize = pbDestination-pbDestinationFirst;
  220. return TRUE;
  221. }
  222. /////////////////////////////////////////////////////////////////////
  223. // LZRW1 compressor
  224. // uses algorithm by Ross Williams
  225. //#define TRUE 1
  226. //#define UBYTE unsigned char /* Unsigned byte (1 byte ) */
  227. //#define UWORD unsigned int /* Unsigned word (2 bytes) */
  228. //#define ULONG unsigned long /* Unsigned longword (4 bytes) */
  229. #define FLAG_BYTES 1 /* Number of bytes used by copy flag. */
  230. #define FLAG_COMPRESS 0 /* Signals that compression occurred. */
  231. #define FLAG_COPY 1 /* Signals that a copyover occurred. */
  232. //void fast_copy(p_src,p_dst,len) /* Fast copy routine. */
  233. //UBYTE *p_src,*p_dst; {while (len--) *p_dst++=*p_src++;}
  234. inline void fast_copy(const UBYTE *p_src, UBYTE *p_dst, SLONG len)
  235. {
  236. memcpy(p_dst, p_src, len);
  237. }
  238. /******************************************************************************/
  239. void lzrw1_compress(const UBYTE *p_src_first, ULONG src_len,UBYTE *p_dst_first, ULONG *p_dst_len)
  240. /* Input : Specify input block using p_src_first and src_len. */
  241. /* Input : Point p_dst_first to the start of the output zone (OZ). */
  242. /* Input : Point p_dst_len to a ULONG to receive the output length. */
  243. /* Input : Input block and output zone must not overlap. */
  244. /* Output : Length of output block written to *p_dst_len. */
  245. /* Output : Output block in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. */
  246. /* Output : May write in OZ=Mem[p_dst_first..p_dst_first+src_len+256-1].*/
  247. /* Output : Upon completion guaranteed *p_dst_len<=src_len+FLAG_BYTES. */
  248. #define PS *p++!=*s++ /* Body of inner unrolled matching loop. */
  249. #define ITEMMAX 16 /* Maximum number of bytes in an expanded item. */
  250. {const UBYTE *p_src=p_src_first;
  251. UBYTE *p_dst=p_dst_first;
  252. const UBYTE *p_src_post=p_src_first+src_len;
  253. UBYTE *p_dst_post=p_dst_first+src_len;
  254. const UBYTE *p_src_max1=p_src_post-ITEMMAX,*p_src_max16=p_src_post-16*ITEMMAX;
  255. const UBYTE *hash[4096];
  256. UBYTE *p_control; UWORD control=0,control_bits=0;
  257. *p_dst=FLAG_COMPRESS; p_dst+=FLAG_BYTES; p_control=p_dst; p_dst+=2;
  258. while (TRUE)
  259. {const UBYTE *p,*s; UWORD unroll=16,len,index; ULONG offset;
  260. if (p_dst>p_dst_post) goto overrun;
  261. if (p_src>p_src_max16)
  262. {unroll=1;
  263. if (p_src>p_src_max1)
  264. {if (p_src==p_src_post) break; goto literal;}}
  265. begin_unrolled_loop:
  266. index=((40543*((((p_src[0]<<4)^p_src[1])<<4)^p_src[2]))>>4) & 0xFFF;
  267. p=hash[index];
  268. hash[index]=s=p_src;
  269. offset=s-p;
  270. if (offset>4095 || p<p_src_first || offset==0 || PS || PS || PS)
  271. {literal: *p_dst++=*p_src++; control>>=1; control_bits++;}
  272. else
  273. {PS || PS || PS || PS || PS || PS || PS ||
  274. PS || PS || PS || PS || PS || PS || s++; len=s-p_src-1;
  275. *p_dst++=(UBYTE)(((offset&0xF00)>>4)+(len-1)); *p_dst++=(UBYTE)(offset&0xFF);
  276. p_src+=len; control=(control>>1)|0x8000; control_bits++;}
  277. /*end_unrolled_loop:*/ if (--unroll) goto begin_unrolled_loop;
  278. if (control_bits==16)
  279. {*p_control=control&0xFF; *(p_control+1)=control>>8;
  280. p_control=p_dst; p_dst+=2; control=control_bits=0;}
  281. }
  282. control>>=16-control_bits;
  283. *p_control++=control&0xFF; *p_control++=control>>8;
  284. if (p_control==p_dst) p_dst-=2;
  285. *p_dst_len=(p_dst-p_dst_first);
  286. return;
  287. overrun: fast_copy(p_src_first,p_dst_first+FLAG_BYTES,src_len);
  288. *p_dst_first=FLAG_COPY; *p_dst_len=src_len+FLAG_BYTES;
  289. }
  290. /******************************************************************************/
  291. void lzrw1_decompress(const UBYTE *p_src_first, ULONG src_len, UBYTE *p_dst_first, ULONG *p_dst_len)
  292. /* Input : Specify input block using p_src_first and src_len. */
  293. /* Input : Point p_dst_first to the start of the output zone. */
  294. /* Input : Point p_dst_len to a ULONG to receive the output length. */
  295. /* Input : Input block and output zone must not overlap. User knows */
  296. /* Input : upperbound on output block length from earlier compression. */
  297. /* Input : In any case, maximum expansion possible is eight times. */
  298. /* Output : Length of output block written to *p_dst_len. */
  299. /* Output : Output block in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. */
  300. /* Output : Writes only in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. */
  301. {UWORD controlbits=0, control;
  302. const UBYTE *p_src=p_src_first+FLAG_BYTES;
  303. UBYTE *p_dst=p_dst_first;
  304. const UBYTE *p_src_post=p_src_first+src_len;
  305. if (*p_src_first==FLAG_COPY)
  306. {fast_copy(p_src_first+FLAG_BYTES,p_dst_first,src_len-FLAG_BYTES);
  307. *p_dst_len=src_len-FLAG_BYTES; return;}
  308. while (p_src!=p_src_post)
  309. {if (controlbits==0)
  310. {control=*p_src++; control|=(*p_src++)<<8; controlbits=16;}
  311. if (control&1)
  312. {UWORD offset,len; UBYTE *p;
  313. offset=(*p_src&0xF0)<<4; len=1+(*p_src++&0xF);
  314. offset+=*p_src++&0xFF; p=p_dst-offset;
  315. while (len--) *p_dst++=*p++;}
  316. else
  317. *p_dst++=*p_src++;
  318. control>>=1; controlbits--;
  319. }
  320. *p_dst_len=p_dst-p_dst_first;
  321. }
  322. /*
  323. * Calculate needed size for destination buffer when packing memory.
  324. */
  325. SLONG CLZCompressor::NeededDestinationSize(SLONG slSourceSize)
  326. {
  327. // calculate worst case possible for size of LZ packed data
  328. return slSourceSize+256;
  329. }
  330. // on entry, slDstSize holds maximum size of output buffer,
  331. // on exit, it is filled with resulting size
  332. /* Pack a chunk of data using given compression. */
  333. BOOL CLZCompressor::Pack(const void *pvSrc, SLONG slSrcSize, void *pvDst, SLONG &slDstSize)
  334. {
  335. // this is just wrapper for original function by Ross Williams
  336. SLONG slDestinationSizeResult = slDstSize;
  337. lzrw1_compress(
  338. (const UBYTE *)pvSrc, (ULONG)slSrcSize,
  339. (UBYTE *)pvDst, (ULONG *)&slDestinationSizeResult);
  340. slDstSize = slDestinationSizeResult;
  341. return TRUE;
  342. }
  343. // on entry, slDstSize holds maximum size of output buffer,
  344. // on exit, it is filled with resulting size
  345. /* Unpack a chunk of data using given compression. */
  346. BOOL CLZCompressor::Unpack(const void *pvSrc, SLONG slSrcSize, void *pvDst, SLONG &slDstSize)
  347. {
  348. // this is just wrapper for original function by Ross Williams
  349. SLONG slDestinationSizeResult = slDstSize;
  350. lzrw1_decompress(
  351. (const UBYTE *)pvSrc, (ULONG)slSrcSize,
  352. (UBYTE *)pvDst, (ULONG *)&slDestinationSizeResult);
  353. slDstSize = slDestinationSizeResult;
  354. return TRUE;
  355. }
  356. /* Calculate needed size for destination buffer when packing memory. */
  357. SLONG CzlibCompressor::NeededDestinationSize(SLONG slSourceSize)
  358. {
  359. // calculate worst case possible for size of zlib packed data
  360. // NOTE: zlib docs state 0.1% of uncompressed size + 12 bytes,
  361. // we just want to be on the safe side
  362. return SLONG(slSourceSize*1.1f)+32;
  363. }
  364. // on entry, slDstSize holds maximum size of output buffer,
  365. // on exit, it is filled with resulting size
  366. /* Pack a chunk of data using given compression. */
  367. BOOL CzlibCompressor::Pack(const void *pvSrc, SLONG slSrcSize, void *pvDst, SLONG &slDstSize)
  368. {
  369. /*
  370. int ZEXPORT compress (dest, destLen, source, sourceLen)
  371. Bytef *dest;
  372. uLongf *destLen;
  373. const Bytef *source;
  374. uLong sourceLen;
  375. */
  376. CTSingleLock slZip(&zip_csLock, TRUE);
  377. int iResult = compress(
  378. (UBYTE *)pvDst, (ULONG *)&slDstSize,
  379. (const UBYTE *)pvSrc, (ULONG)slSrcSize);
  380. if (iResult==Z_OK) {
  381. return TRUE;
  382. } else {
  383. return FALSE;
  384. }
  385. }
  386. // on entry, slDstSize holds maximum size of output buffer,
  387. // on exit, it is filled with resulting size
  388. /* Unpack a chunk of data using given compression. */
  389. BOOL CzlibCompressor::Unpack(const void *pvSrc, SLONG slSrcSize, void *pvDst, SLONG &slDstSize)
  390. {
  391. /*
  392. int ZEXPORT uncompress (dest, destLen, source, sourceLen)
  393. Bytef *dest;
  394. uLongf *destLen;
  395. const Bytef *source;
  396. uLong sourceLen;
  397. */
  398. CTSingleLock slZip(&zip_csLock, TRUE);
  399. int iResult = uncompress(
  400. (UBYTE *)pvDst, (ULONG *)&slDstSize,
  401. (const UBYTE *)pvSrc, (ULONG)slSrcSize);
  402. if (iResult==Z_OK) {
  403. return TRUE;
  404. } else {
  405. return FALSE;
  406. }
  407. }