1 /*****************************************************************************/
2 /* SCompression.cpp                       Copyright (c) Ladislav Zezula 2003 */
3 /*---------------------------------------------------------------------------*/
4 /* This module serves as a bridge between StormLib code and (de)compression  */
5 /* functions. All (de)compression calls go (and should only go) through this */
6 /* module. No system headers should be included in this module to prevent    */
7 /* compile-time problems.                                                    */
8 /*---------------------------------------------------------------------------*/
9 /*   Date    Ver   Who  Comment                                              */
10 /* --------  ----  ---  -------                                              */
11 /* 01.04.03  1.00  Lad  The first version of SCompression.cpp                */
12 /* 19.11.03  1.01  Dan  Big endian handling                                  */
13 /*****************************************************************************/
14 
15 #define __STORMLIB_SELF__
16 #include "StormLib.h"
17 #include "StormCommon.h"
18 
19 //-----------------------------------------------------------------------------
20 // Local structures
21 
22 // Information about the input and output buffers for pklib
23 typedef struct
24 {
25     unsigned char * pbInBuff;           // Pointer to input data buffer
26     unsigned char * pbInBuffEnd;        // End of the input buffer
27     unsigned char * pbOutBuff;          // Pointer to output data buffer
28     unsigned char * pbOutBuffEnd;       // Pointer to output data buffer
29 } TDataInfo;
30 
31 // Prototype of the compression function
32 // Function doesn't return an error. A success means that the size of compressed buffer
33 // is lower than size of uncompressed buffer.
34 typedef void (*COMPRESS)(
35     void * pvOutBuffer,                 // [out] Pointer to the buffer where the compressed data will be stored
36     int  * pcbOutBuffer,                // [in]  Pointer to length of the buffer pointed by pvOutBuffer
37     void * pvInBuffer,                  // [in]  Pointer to the buffer with data to compress
38     int cbInBuffer,                     // [in]  Length of the buffer pointer by pvInBuffer
39     int * pCmpType,                     // [in]  Compression-method specific value. ADPCM Setups this for the following Huffman compression
40     int nCmpLevel);                     // [in]  Compression specific value. ADPCM uses this. Should be set to zero.
41 
42 // Prototype of the decompression function
43 // Returns 1 if success, 0 if failure
44 typedef int (*DECOMPRESS)(
45     void * pvOutBuffer,                 // [out] Pointer to the buffer where to store decompressed data
46     int  * pcbOutBuffer,                // [in]  Pointer to total size of the buffer pointed by pvOutBuffer
47                                         // [out] Contains length of the decompressed data
48     void * pvInBuffer,                  // [in]  Pointer to data to be decompressed
49     int cbInBuffer);                    // [in]  Length of the data to be decompressed
50 
51 // Table of compression functions
52 typedef struct
53 {
54     unsigned long uMask;                // Compression mask
55     COMPRESS Compress;                  // Compression function
56 } TCompressTable;
57 
58 // Table of decompression functions
59 typedef struct
60 {
61     unsigned long uMask;                // Decompression bit
62     DECOMPRESS    Decompress;           // Decompression function
63 } TDecompressTable;
64 
65 
66 /*****************************************************************************/
67 /*                                                                           */
68 /*  Support for Huffman compression (0x01)                                   */
69 /*                                                                           */
70 /*****************************************************************************/
71 
Compress_huff(void * pvOutBuffer,int * pcbOutBuffer,void * pvInBuffer,int cbInBuffer,int * pCmpType,int nCmpLevel)72 void Compress_huff(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, int * pCmpType, int nCmpLevel)
73 {
74     THuffmannTree ht(true);
75     TOutputStream os(pvOutBuffer, *pcbOutBuffer);
76 
77     STORMLIB_UNUSED(nCmpLevel);
78     *pcbOutBuffer = ht.Compress(&os, pvInBuffer, cbInBuffer, *pCmpType);
79 }
80 
Decompress_huff(void * pvOutBuffer,int * pcbOutBuffer,void * pvInBuffer,int cbInBuffer)81 int Decompress_huff(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer)
82 {
83     THuffmannTree ht(false);
84     TInputStream is(pvInBuffer, cbInBuffer);
85 
86     *pcbOutBuffer = ht.Decompress(pvOutBuffer, *pcbOutBuffer, &is);
87     return (*pcbOutBuffer == 0) ? 0 : 1;
88 }
89 
90 /******************************************************************************/
91 /*                                                                            */
92 /*  Support for ZLIB compression (0x02)                                       */
93 /*                                                                            */
94 /******************************************************************************/
95 
Compress_ZLIB(void * pvOutBuffer,int * pcbOutBuffer,void * pvInBuffer,int cbInBuffer,int * pCmpType,int nCmpLevel)96 void Compress_ZLIB(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, int * pCmpType, int nCmpLevel)
97 {
98     z_stream z;                        // Stream information for zlib
99     int windowBits;
100     int nResult;
101 
102     // Keep compilers happy
103     STORMLIB_UNUSED(pCmpType);
104     STORMLIB_UNUSED(nCmpLevel);
105 
106     // Fill the stream structure for zlib
107     z.next_in   = (Bytef *)pvInBuffer;
108     z.avail_in  = (uInt)cbInBuffer;
109     z.total_in  = cbInBuffer;
110     z.next_out  = (Bytef *)pvOutBuffer;
111     z.avail_out = *pcbOutBuffer;
112     z.total_out = 0;
113     z.zalloc    = NULL;
114     z.zfree     = NULL;
115 
116     // Determine the proper window bits (WoW.exe build 12694)
117     if(cbInBuffer <= 0x100)
118         windowBits = 8;
119     else if(cbInBuffer <= 0x200)
120         windowBits = 9;
121     else if(cbInBuffer <= 0x400)
122         windowBits = 10;
123     else if(cbInBuffer <= 0x800)
124         windowBits = 11;
125     else if(cbInBuffer <= 0x1000)
126         windowBits = 12;
127     else if(cbInBuffer <= 0x2000)
128         windowBits = 13;
129     else if(cbInBuffer <= 0x4000)
130         windowBits = 14;
131     else
132         windowBits = 15;
133 
134     // Initialize the compression.
135     // Storm.dll uses zlib version 1.1.3
136     // Wow.exe uses zlib version 1.2.3
137     nResult = deflateInit2(&z,
138                             6,                  // Compression level used by WoW MPQs
139                             Z_DEFLATED,
140                             windowBits,
141                             8,
142                             Z_DEFAULT_STRATEGY);
143     if(nResult == Z_OK)
144     {
145         // Call zlib to compress the data
146         nResult = deflate(&z, Z_FINISH);
147 
148         if(nResult == Z_OK || nResult == Z_STREAM_END)
149             *pcbOutBuffer = z.total_out;
150 
151         deflateEnd(&z);
152     }
153 }
154 
Decompress_ZLIB(void * pvOutBuffer,int * pcbOutBuffer,void * pvInBuffer,int cbInBuffer)155 int Decompress_ZLIB(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer)
156 {
157     z_stream z;                        // Stream information for zlib
158     int nResult;
159 
160     // Fill the stream structure for zlib
161     z.next_in   = (Bytef *)pvInBuffer;
162     z.avail_in  = (uInt)cbInBuffer;
163     z.total_in  = cbInBuffer;
164     z.next_out  = (Bytef *)pvOutBuffer;
165     z.avail_out = *pcbOutBuffer;
166     z.total_out = 0;
167     z.zalloc    = NULL;
168     z.zfree     = NULL;
169 
170     // Initialize the decompression structure. Storm.dll uses zlib version 1.1.3
171     if((nResult = inflateInit(&z)) == Z_OK)
172     {
173         // Call zlib to decompress the data
174         nResult = inflate(&z, Z_FINISH);
175         *pcbOutBuffer = z.total_out;
176         inflateEnd(&z);
177     }
178 
179 	return (nResult >= Z_OK);
180 }
181 
182 /******************************************************************************/
183 /*                                                                            */
184 /*  Support functions for PKWARE Data Compression Library compression (0x08)  */
185 /*                                                                            */
186 /******************************************************************************/
187 
188 // Function loads data from the input buffer. Used by Pklib's "implode"
189 // and "explode" function as user-defined callback
190 // Returns number of bytes loaded
191 //
192 //   char * buf          - Pointer to a buffer where to store loaded data
193 //   unsigned int * size - Max. number of bytes to read
194 //   void * param        - Custom pointer, parameter of implode/explode
195 
ReadInputData(char * buf,unsigned int * size,void * param)196 static unsigned int ReadInputData(char * buf, unsigned int * size, void * param)
197 {
198     TDataInfo * pInfo = (TDataInfo *)param;
199     unsigned int nMaxAvail = (unsigned int)(pInfo->pbInBuffEnd - pInfo->pbInBuff);
200     unsigned int nToRead = *size;
201 
202     // Check the case when not enough data available
203     if(nToRead > nMaxAvail)
204         nToRead = nMaxAvail;
205 
206     // Load data and increment offsets
207     memcpy(buf, pInfo->pbInBuff, nToRead);
208     pInfo->pbInBuff += nToRead;
209     assert(pInfo->pbInBuff <= pInfo->pbInBuffEnd);
210     return nToRead;
211 }
212 
213 // Function for store output data. Used by Pklib's "implode" and "explode"
214 // as user-defined callback
215 //
216 //   char * buf          - Pointer to data to be written
217 //   unsigned int * size - Number of bytes to write
218 //   void * param        - Custom pointer, parameter of implode/explode
219 
WriteOutputData(char * buf,unsigned int * size,void * param)220 static void WriteOutputData(char * buf, unsigned int * size, void * param)
221 {
222     TDataInfo * pInfo = (TDataInfo *)param;
223     unsigned int nMaxWrite = (unsigned int)(pInfo->pbOutBuffEnd - pInfo->pbOutBuff);
224     unsigned int nToWrite = *size;
225 
226     // Check the case when not enough space in the output buffer
227     if(nToWrite > nMaxWrite)
228         nToWrite = nMaxWrite;
229 
230     // Write output data and increments offsets
231     memcpy(pInfo->pbOutBuff, buf, nToWrite);
232     pInfo->pbOutBuff += nToWrite;
233     assert(pInfo->pbOutBuff <= pInfo->pbOutBuffEnd);
234 }
235 
Compress_PKLIB(void * pvOutBuffer,int * pcbOutBuffer,void * pvInBuffer,int cbInBuffer,int * pCmpType,int nCmpLevel)236 static void Compress_PKLIB(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, int * pCmpType, int nCmpLevel)
237 {
238     TDataInfo Info;                                      // Data information
239     char * work_buf = STORM_ALLOC(char, CMP_BUFFER_SIZE);// Pklib's work buffer
240     unsigned int dict_size;                              // Dictionary size
241     unsigned int ctype = CMP_BINARY;                     // Compression type
242 
243     // Keep compilers happy
244     STORMLIB_UNUSED(pCmpType);
245     STORMLIB_UNUSED(nCmpLevel);
246 
247     // Handle no-memory condition
248     if(work_buf != NULL)
249     {
250         // Fill data information structure
251         memset(work_buf, 0, CMP_BUFFER_SIZE);
252         Info.pbInBuff     = (unsigned char *)pvInBuffer;
253         Info.pbInBuffEnd  = (unsigned char *)pvInBuffer + cbInBuffer;
254         Info.pbOutBuff    = (unsigned char *)pvOutBuffer;
255         Info.pbOutBuffEnd = (unsigned char *)pvOutBuffer + *pcbOutBuffer;
256 
257         //
258         // Set the dictionary size
259         //
260         // Diablo I uses fixed dictionary size of CMP_IMPLODE_DICT_SIZE3
261         // Starcraft I uses the variable dictionary size based on algorithm below
262         //
263 
264         if (cbInBuffer < 0x600)
265             dict_size = CMP_IMPLODE_DICT_SIZE1;
266         else if(0x600 <= cbInBuffer && cbInBuffer < 0xC00)
267             dict_size = CMP_IMPLODE_DICT_SIZE2;
268         else
269             dict_size = CMP_IMPLODE_DICT_SIZE3;
270 
271         // Do the compression
272         if(implode(ReadInputData, WriteOutputData, work_buf, &Info, &ctype, &dict_size) == CMP_NO_ERROR)
273             *pcbOutBuffer = (int)(Info.pbOutBuff - (unsigned char *)pvOutBuffer);
274 
275         STORM_FREE(work_buf);
276     }
277 }
278 
Decompress_PKLIB(void * pvOutBuffer,int * pcbOutBuffer,void * pvInBuffer,int cbInBuffer)279 static int Decompress_PKLIB(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer)
280 {
281     TDataInfo Info;                             // Data information
282 	char * work_buf;
283 	int nResult = 0;
284 
285     // Allocate Pklib's work buffer
286     if((work_buf = STORM_ALLOC(char, EXP_BUFFER_SIZE)) != NULL)
287 	{
288 		// Fill data information structure
289 		memset(work_buf, 0, EXP_BUFFER_SIZE);
290 		Info.pbInBuff     = (unsigned char *)pvInBuffer;
291 		Info.pbInBuffEnd  = (unsigned char *)pvInBuffer + cbInBuffer;
292 		Info.pbOutBuff    = (unsigned char *)pvOutBuffer;
293 		Info.pbOutBuffEnd = (unsigned char *)pvOutBuffer + *pcbOutBuffer;
294 
295 		// Do the decompression
296 		if(explode(ReadInputData, WriteOutputData, work_buf, &Info) == CMP_NO_ERROR)
297 			nResult = 1;
298 
299 		// Give away the number of decompressed bytes
300 		*pcbOutBuffer = (int)(Info.pbOutBuff - (unsigned char *)pvOutBuffer);
301         STORM_FREE(work_buf);
302 	}
303 
304     return nResult;
305 }
306 
307 /******************************************************************************/
308 /*                                                                            */
309 /*  Support for Bzip2 compression (0x10)                                      */
310 /*                                                                            */
311 /******************************************************************************/
312 
Compress_BZIP2(void * pvOutBuffer,int * pcbOutBuffer,void * pvInBuffer,int cbInBuffer,int * pCmpType,int nCmpLevel)313 static void Compress_BZIP2(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, int * pCmpType, int nCmpLevel)
314 {
315     bz_stream strm;
316     int blockSize100k = 9;
317     int workFactor = 30;
318     int bzError;
319 
320     // Keep compilers happy
321     STORMLIB_UNUSED(pCmpType);
322     STORMLIB_UNUSED(nCmpLevel);
323 
324     // Initialize the BZIP2 compression
325     strm.bzalloc = NULL;
326     strm.bzfree  = NULL;
327     strm.opaque  = NULL;
328 
329     // Blizzard uses 9 as blockSize100k, (0x30 as workFactor)
330     // Last checked on Starcraft II
331     if(BZ2_bzCompressInit(&strm, blockSize100k, 0, workFactor) == BZ_OK)
332     {
333         strm.next_in   = (char *)pvInBuffer;
334         strm.avail_in  = cbInBuffer;
335         strm.next_out  = (char *)pvOutBuffer;
336         strm.avail_out = *pcbOutBuffer;
337 
338         // Perform the compression
339         for(;;)
340         {
341             bzError = BZ2_bzCompress(&strm, (strm.avail_in != 0) ? BZ_RUN : BZ_FINISH);
342             if(bzError == BZ_STREAM_END || bzError < 0)
343                 break;
344         }
345 
346         // Put the stream into idle state
347         BZ2_bzCompressEnd(&strm);
348 
349         if(bzError > 0)
350             *pcbOutBuffer = strm.total_out_lo32;
351     }
352 }
353 
Decompress_BZIP2(void * pvOutBuffer,int * pcbOutBuffer,void * pvInBuffer,int cbInBuffer)354 static int Decompress_BZIP2(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer)
355 {
356     bz_stream strm;
357     int nResult;
358 
359     // Initialize the BZIP2 decompression
360     strm.next_in   = (char *)pvInBuffer;
361     strm.avail_in  = cbInBuffer;
362     strm.next_out  = (char *)pvOutBuffer;
363     strm.avail_out = *pcbOutBuffer;
364     strm.bzalloc   = NULL;
365     strm.bzfree    = NULL;
366     strm.opaque    = NULL;
367 
368     // Initialize decompression
369     if((nResult = BZ2_bzDecompressInit(&strm, 0, 0)) == BZ_OK)
370     {
371         // Perform the decompression
372         nResult = BZ2_bzDecompress(&strm);
373         *pcbOutBuffer = strm.total_out_lo32;
374         BZ2_bzDecompressEnd(&strm);
375     }
376 
377 	return (nResult >= BZ_OK);
378 }
379 
380 /******************************************************************************/
381 /*                                                                            */
382 /*  Support functions for LZMA compression (0x12)                             */
383 /*                                                                            */
384 /******************************************************************************/
385 
386 #define LZMA_HEADER_SIZE (1 + LZMA_PROPS_SIZE + 8)
387 
LZMA_Callback_Progress(void *,UInt64,UInt64)388 static SRes LZMA_Callback_Progress(void * /* p */, UInt64 /* inSize */, UInt64 /* outSize */)
389 {
390     return SZ_OK;
391 }
392 
LZMA_Callback_Alloc(void * p,size_t size)393 static void * LZMA_Callback_Alloc(void *p, size_t size)
394 {
395     p = p;
396     return STORM_ALLOC(BYTE, size);
397 }
398 
399 /* address can be 0 */
LZMA_Callback_Free(void * p,void * address)400 static void LZMA_Callback_Free(void *p, void *address)
401 {
402     p = p;
403     if(address != NULL)
404         STORM_FREE(address);
405 }
406 
407 //
408 // Note: So far, I haven't seen any files compressed by LZMA.
409 // This code haven't been verified against code ripped from Starcraft II Beta,
410 // but we know that Starcraft LZMA decompression code is able to decompress
411 // the data compressed by StormLib.
412 //
413 
Compress_LZMA(void * pvOutBuffer,int * pcbOutBuffer,void * pvInBuffer,int cbInBuffer,int * pCmpType,int nCmpLevel)414 static void Compress_LZMA(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, int * pCmpType, int nCmpLevel)
415 {
416     ICompressProgress Progress;
417     CLzmaEncProps props;
418     ISzAlloc SzAlloc;
419     Byte * pbOutBuffer = (Byte *)pvOutBuffer;
420     Byte * destBuffer;
421     SizeT destLen = *pcbOutBuffer;
422     SizeT srcLen = cbInBuffer;
423     Byte encodedProps[LZMA_PROPS_SIZE];
424     size_t encodedPropsSize = LZMA_PROPS_SIZE;
425     SRes nResult;
426 
427     // Keep compilers happy
428     STORMLIB_UNUSED(pCmpType);
429     STORMLIB_UNUSED(nCmpLevel);
430 
431     // Fill the callbacks in structures
432     Progress.Progress = LZMA_Callback_Progress;
433     SzAlloc.Alloc = LZMA_Callback_Alloc;
434     SzAlloc.Free = LZMA_Callback_Free;
435 
436     // Initialize properties
437     LzmaEncProps_Init(&props);
438 
439     // Perform compression
440     destBuffer = (Byte *)pvOutBuffer + LZMA_HEADER_SIZE;
441     destLen = *pcbOutBuffer - LZMA_HEADER_SIZE;
442     nResult = LzmaEncode(destBuffer,
443                         &destLen,
444                  (Byte *)pvInBuffer,
445                          srcLen,
446                         &props,
447                          encodedProps,
448                         &encodedPropsSize,
449                          0,
450                         &Progress,
451                         &SzAlloc,
452                         &SzAlloc);
453     if(nResult != SZ_OK)
454         return;
455 
456     // If we failed to compress the data
457     if(destLen >= (SizeT)(*pcbOutBuffer - LZMA_HEADER_SIZE))
458         return;
459 
460     // Write "useFilter" variable. Blizzard MPQ must not use filter.
461     *pbOutBuffer++ = 0;
462 
463     // Copy the encoded properties to the output buffer
464     memcpy(pvOutBuffer, encodedProps, encodedPropsSize);
465     pbOutBuffer += encodedPropsSize;
466 
467     // Copy the size of the data
468     *pbOutBuffer++ = (unsigned char)(srcLen >> 0x00);
469     *pbOutBuffer++ = (unsigned char)(srcLen >> 0x08);
470     *pbOutBuffer++ = (unsigned char)(srcLen >> 0x10);
471     *pbOutBuffer++ = (unsigned char)(srcLen >> 0x18);
472     *pbOutBuffer++ = 0;
473     *pbOutBuffer++ = 0;
474     *pbOutBuffer++ = 0;
475     *pbOutBuffer++ = 0;
476 
477     // Give the size of the data to the caller
478     *pcbOutBuffer = (unsigned int)(destLen + LZMA_HEADER_SIZE);
479 }
480 
Decompress_LZMA(void * pvOutBuffer,int * pcbOutBuffer,void * pvInBuffer,int cbInBuffer)481 static int Decompress_LZMA(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer)
482 {
483     ELzmaStatus LzmaStatus;
484     ISzAlloc SzAlloc;
485     Byte * destBuffer = (Byte *)pvOutBuffer;
486     Byte * srcBuffer = (Byte *)pvInBuffer;
487     SizeT destLen = *pcbOutBuffer;
488     SizeT srcLen = cbInBuffer;
489     SRes nResult;
490 
491     // There must be at least 0x0E bytes in the buffer
492     if(srcLen <= LZMA_HEADER_SIZE)
493         return 0;
494 
495     // We only accept blocks that have no filter used
496     if(*srcBuffer != 0)
497         return 0;
498 
499     // Fill the callbacks in structures
500     SzAlloc.Alloc = LZMA_Callback_Alloc;
501     SzAlloc.Free = LZMA_Callback_Free;
502 
503     // Perform compression
504     srcLen = cbInBuffer - LZMA_HEADER_SIZE;
505     nResult = LzmaDecode(destBuffer,
506                         &destLen,
507                          srcBuffer + LZMA_HEADER_SIZE,
508                         &srcLen,
509                          srcBuffer + 1,
510                          LZMA_PROPS_SIZE,
511                          LZMA_FINISH_END,
512                         &LzmaStatus,
513                         &SzAlloc);
514     if(nResult != SZ_OK)
515         return 0;
516 
517     *pcbOutBuffer = (unsigned int)destLen;
518     return 1;
519 }
520 
Decompress_LZMA_MPK(void * pvOutBuffer,int * pcbOutBuffer,void * pvInBuffer,int cbInBuffer)521 static int Decompress_LZMA_MPK(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer)
522 {
523     ELzmaStatus LzmaStatus;
524     ISzAlloc SzAlloc;
525     Byte * destBuffer = (Byte *)pvOutBuffer;
526     Byte * srcBuffer = (Byte *)pvInBuffer;
527     SizeT destLen = *pcbOutBuffer;
528     SizeT srcLen = cbInBuffer;
529     SRes nResult;
530     BYTE LZMA_Props[] = {0x5D, 0x00, 0x00, 0x00, 0x01};
531 
532     // There must be at least 0x0E bytes in the buffer
533     if(srcLen <= sizeof(LZMA_Props))
534         return 0;
535 
536     // Verify the props header
537     if(memcmp(pvInBuffer, LZMA_Props, sizeof(LZMA_Props)))
538         return 0;
539 
540     // Fill the callbacks in structures
541     SzAlloc.Alloc = LZMA_Callback_Alloc;
542     SzAlloc.Free = LZMA_Callback_Free;
543 
544     // Perform compression
545     srcLen = cbInBuffer - sizeof(LZMA_Props);
546     nResult = LzmaDecode(destBuffer,
547                         &destLen,
548                          srcBuffer + sizeof(LZMA_Props),
549                         &srcLen,
550                          srcBuffer,
551                          sizeof(LZMA_Props),
552                          LZMA_FINISH_END,
553                         &LzmaStatus,
554                         &SzAlloc);
555     if(nResult != SZ_OK)
556         return 0;
557 
558     *pcbOutBuffer = (unsigned int)destLen;
559     return 1;
560 }
561 
562 /******************************************************************************/
563 /*                                                                            */
564 /*  Support functions for SPARSE compression (0x20)                           */
565 /*                                                                            */
566 /******************************************************************************/
567 
Compress_SPARSE(void * pvOutBuffer,int * pcbOutBuffer,void * pvInBuffer,int cbInBuffer,int * pCmpType,int nCmpLevel)568 void Compress_SPARSE(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, int * pCmpType, int nCmpLevel)
569 {
570     // Keep compilers happy
571     STORMLIB_UNUSED(pCmpType);
572     STORMLIB_UNUSED(nCmpLevel);
573 
574     CompressSparse(pvOutBuffer, pcbOutBuffer, pvInBuffer, cbInBuffer);
575 }
576 
Decompress_SPARSE(void * pvOutBuffer,int * pcbOutBuffer,void * pvInBuffer,int cbInBuffer)577 int Decompress_SPARSE(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer)
578 {
579     return DecompressSparse(pvOutBuffer, pcbOutBuffer, pvInBuffer, cbInBuffer);
580 }
581 
582 /******************************************************************************/
583 /*                                                                            */
584 /*  Support for ADPCM mono compression (0x40)                                 */
585 /*                                                                            */
586 /******************************************************************************/
587 
Compress_ADPCM_mono(void * pvOutBuffer,int * pcbOutBuffer,void * pvInBuffer,int cbInBuffer,int * pCmpType,int nCmpLevel)588 static void Compress_ADPCM_mono(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, int * pCmpType, int nCmpLevel)
589 {
590     // Prepare the compression level for Huffmann compression,
591     // which will be called as next step
592     if(0 < nCmpLevel && nCmpLevel <= 2)
593     {
594         nCmpLevel = 4;
595         *pCmpType = 6;
596     }
597     else if(nCmpLevel == 3)
598     {
599         nCmpLevel = 6;
600         *pCmpType = 8;
601     }
602     else
603     {
604         nCmpLevel = 5;
605         *pCmpType = 7;
606     }
607     *pcbOutBuffer = CompressADPCM(pvOutBuffer, *pcbOutBuffer, pvInBuffer, cbInBuffer, 1, nCmpLevel);
608 }
609 
Decompress_ADPCM_mono(void * pvOutBuffer,int * pcbOutBuffer,void * pvInBuffer,int cbInBuffer)610 static int Decompress_ADPCM_mono(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer)
611 {
612     *pcbOutBuffer = DecompressADPCM(pvOutBuffer, *pcbOutBuffer, pvInBuffer, cbInBuffer, 1);
613     return 1;
614 }
615 
616 /******************************************************************************/
617 /*                                                                            */
618 /*  Support for ADPCM stereo compression (0x80)                               */
619 /*                                                                            */
620 /******************************************************************************/
621 
Compress_ADPCM_stereo(void * pvOutBuffer,int * pcbOutBuffer,void * pvInBuffer,int cbInBuffer,int * pCmpType,int nCmpLevel)622 static void Compress_ADPCM_stereo(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, int * pCmpType, int nCmpLevel)
623 {
624     // Prepare the compression level for Huffmann compression,
625     // which will be called as next step
626     if(0 < nCmpLevel && nCmpLevel <= 2)
627     {
628         nCmpLevel = 4;
629         *pCmpType = 6;
630     }
631     else if(nCmpLevel == 3)
632     {
633         nCmpLevel = 6;
634         *pCmpType = 8;
635     }
636     else
637     {
638         nCmpLevel = 5;
639         *pCmpType = 7;
640     }
641     *pcbOutBuffer = CompressADPCM(pvOutBuffer, *pcbOutBuffer, pvInBuffer, cbInBuffer, 2, nCmpLevel);
642 }
643 
Decompress_ADPCM_stereo(void * pvOutBuffer,int * pcbOutBuffer,void * pvInBuffer,int cbInBuffer)644 static int Decompress_ADPCM_stereo(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer)
645 {
646     *pcbOutBuffer = DecompressADPCM(pvOutBuffer, *pcbOutBuffer, pvInBuffer, cbInBuffer, 2);
647     return 1;
648 }
649 
650 /*****************************************************************************/
651 /*                                                                           */
652 /*   SCompImplode                                                            */
653 /*                                                                           */
654 /*****************************************************************************/
655 
SCompImplode(void * pvOutBuffer,int * pcbOutBuffer,void * pvInBuffer,int cbInBuffer)656 int WINAPI SCompImplode(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer)
657 {
658     int cbOutBuffer;
659 
660     // Check for valid parameters
661     if(!pcbOutBuffer || *pcbOutBuffer < cbInBuffer || !pvOutBuffer || !pvInBuffer)
662     {
663         SetLastError(ERROR_INVALID_PARAMETER);
664         return 0;
665     }
666 
667     // Perform the compression
668     cbOutBuffer = *pcbOutBuffer;
669     Compress_PKLIB(pvOutBuffer, &cbOutBuffer, pvInBuffer, cbInBuffer, NULL, 0);
670 
671     // If the compression was unsuccessful, copy the data as-is
672     if(cbOutBuffer >= *pcbOutBuffer)
673     {
674         memcpy(pvOutBuffer, pvInBuffer, cbInBuffer);
675         cbOutBuffer = *pcbOutBuffer;
676     }
677 
678     *pcbOutBuffer = cbOutBuffer;
679     return 1;
680 }
681 
682 /*****************************************************************************/
683 /*                                                                           */
684 /*   SCompExplode                                                            */
685 /*                                                                           */
686 /*****************************************************************************/
687 
SCompExplode(void * pvOutBuffer,int * pcbOutBuffer,void * pvInBuffer,int cbInBuffer)688 int WINAPI SCompExplode(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer)
689 {
690     int cbOutBuffer;
691 
692     // Check for valid parameters
693     if(!pcbOutBuffer || *pcbOutBuffer < cbInBuffer || !pvOutBuffer || !pvInBuffer)
694     {
695         SetLastError(ERROR_INVALID_PARAMETER);
696         return 0;
697     }
698 
699     // If the input length is the same as output length, do nothing.
700     cbOutBuffer = *pcbOutBuffer;
701     if(cbInBuffer == cbOutBuffer)
702     {
703         // If the buffers are equal, don't copy anything.
704         if(pvInBuffer == pvOutBuffer)
705             return 1;
706 
707         memcpy(pvOutBuffer, pvInBuffer, cbInBuffer);
708         return 1;
709     }
710 
711     // Perform decompression
712     if(!Decompress_PKLIB(pvOutBuffer, &cbOutBuffer, pvInBuffer, cbInBuffer))
713     {
714         SetLastError(ERROR_FILE_CORRUPT);
715         return 0;
716     }
717 
718     *pcbOutBuffer = cbOutBuffer;
719     return 1;
720 }
721 
722 /*****************************************************************************/
723 /*                                                                           */
724 /*   SCompCompress                                                           */
725 /*                                                                           */
726 /*****************************************************************************/
727 
728 // This table contains compress functions which can be applied to
729 // uncompressed data. Each bit means the corresponding
730 // compression method/function must be applied.
731 //
732 //   WAVes compression            Data compression
733 //   ------------------           -------------------
734 //   1st sector   - 0x08          0x08 (D, HF, W2, SC, D2)
735 //   Next sectors - 0x81          0x02 (W3)
736 
737 static TCompressTable cmp_table[] =
738 {
739     {MPQ_COMPRESSION_SPARSE,       Compress_SPARSE},        // Sparse compression
740     {MPQ_COMPRESSION_ADPCM_MONO,   Compress_ADPCM_mono},    // IMA ADPCM mono compression
741     {MPQ_COMPRESSION_ADPCM_STEREO, Compress_ADPCM_stereo},  // IMA ADPCM stereo compression
742     {MPQ_COMPRESSION_HUFFMANN,     Compress_huff},          // Huffmann compression
743     {MPQ_COMPRESSION_ZLIB,         Compress_ZLIB},          // Compression with the "zlib" library
744     {MPQ_COMPRESSION_PKWARE,       Compress_PKLIB},         // Compression with Pkware DCL
745     {MPQ_COMPRESSION_BZIP2,        Compress_BZIP2}          // Compression Bzip2 library
746 };
747 
SCompCompress(void * pvOutBuffer,int * pcbOutBuffer,void * pvInBuffer,int cbInBuffer,unsigned uCompressionMask,int nCmpType,int nCmpLevel)748 int WINAPI SCompCompress(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, unsigned uCompressionMask, int nCmpType, int nCmpLevel)
749 {
750     COMPRESS CompressFuncArray[0x10];                       // Array of compression functions, applied sequentially
751     unsigned char CompressByte[0x10];                       // CompressByte for each method in the CompressFuncArray array
752     unsigned char * pbWorkBuffer = NULL;                    // Temporary storage for decompressed data
753     unsigned char * pbOutBuffer = (unsigned char *)pvOutBuffer;
754     unsigned char * pbOutput = (unsigned char *)pvOutBuffer;// Current output buffer
755     unsigned char * pbInput = (unsigned char *)pvInBuffer;  // Current input buffer
756     int nCompressCount = 0;
757     int nCompressIndex = 0;
758     int nAtLeastOneCompressionDone = 0;
759     int cbOutBuffer = 0;
760     int cbInLength = cbInBuffer;
761     int nResult = 1;
762 
763     // Check for valid parameters
764     if(!pcbOutBuffer || *pcbOutBuffer < cbInBuffer || !pvOutBuffer || !pvInBuffer)
765     {
766         SetLastError(ERROR_INVALID_PARAMETER);
767         return 0;
768     }
769 
770     // Zero input length brings zero output length
771     if(cbInBuffer == 0)
772     {
773         *pcbOutBuffer = 0;
774         return true;
775     }
776 
777     // Setup the compression function array
778     if(uCompressionMask == MPQ_COMPRESSION_LZMA)
779     {
780         CompressFuncArray[0] = Compress_LZMA;
781         CompressByte[0] = (char)uCompressionMask;
782         nCompressCount = 1;
783     }
784     else
785     {
786         // Fill the compressions array
787         for(size_t i = 0; i < (sizeof(cmp_table) / sizeof(TCompressTable)); i++)
788         {
789             // If the mask agrees, insert the compression function to the array
790             if(uCompressionMask & cmp_table[i].uMask)
791             {
792                 CompressFuncArray[nCompressCount] = cmp_table[i].Compress;
793                 CompressByte[nCompressCount] = (unsigned char)cmp_table[i].uMask;
794                 uCompressionMask &= ~cmp_table[i].uMask;
795                 nCompressCount++;
796             }
797         }
798 
799         // If at least one of the compressions remaing unknown, return an error
800         if(uCompressionMask != 0)
801         {
802             SetLastError(ERROR_NOT_SUPPORTED);
803             return 0;
804         }
805     }
806 
807     // If there is at least one compression, do it
808     if(nCompressCount > 0)
809     {
810         // If we need to do more than 1 compression, allocate intermediate buffer
811         if(nCompressCount > 1)
812         {
813             pbWorkBuffer = STORM_ALLOC(unsigned char, *pcbOutBuffer);
814             if(pbWorkBuffer == NULL)
815             {
816                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
817                 return 0;
818             }
819         }
820 
821         // Get the current compression index
822         nCompressIndex = nCompressCount - 1;
823 
824         // Perform all compressions in the array
825         for(int i = 0; i < nCompressCount; i++)
826         {
827             // Choose the proper output buffer
828             pbOutput = (nCompressIndex & 1) ? pbWorkBuffer : pbOutBuffer;
829             nCompressIndex--;
830 
831             // Perform the (next) compression
832             // Note that if the compression method is unable to compress the input data block
833             // by at least 2 bytes, we consider it as failure and will use source data instead
834             cbOutBuffer = *pcbOutBuffer - 1;
835             CompressFuncArray[i](pbOutput + 1, &cbOutBuffer, pbInput, cbInLength, &nCmpType, nCmpLevel);
836 
837             // If the compression failed, we copy the input buffer as-is.
838             // Note that there is one extra byte at the end of the intermediate buffer, so it should be OK
839             if(cbOutBuffer > (cbInLength - 2))
840             {
841                 memcpy(pbOutput + nAtLeastOneCompressionDone, pbInput, cbInLength);
842                 cbOutBuffer = cbInLength;
843             }
844             else
845             {
846                 // Remember that we have done at least one compression
847                 nAtLeastOneCompressionDone = 1;
848                 uCompressionMask |= CompressByte[i];
849             }
850 
851             // Now point input buffer to the output buffer
852             pbInput = pbOutput + nAtLeastOneCompressionDone;
853             cbInLength = cbOutBuffer;
854         }
855 
856         // If at least one compression succeeded, put the compression
857         // mask to the begin of the output buffer
858         if(nAtLeastOneCompressionDone)
859             *pbOutBuffer  = (unsigned char)uCompressionMask;
860         *pcbOutBuffer = cbOutBuffer + nAtLeastOneCompressionDone;
861     }
862     else
863     {
864         memcpy(pvOutBuffer, pvInBuffer, cbInBuffer);
865         *pcbOutBuffer = cbInBuffer;
866     }
867 
868     // Cleanup and return
869     if(pbWorkBuffer != NULL)
870         STORM_FREE(pbWorkBuffer);
871     return nResult;
872 }
873 
874 /*****************************************************************************/
875 /*                                                                           */
876 /*   SCompDecompress                                                         */
877 /*                                                                           */
878 /*****************************************************************************/
879 
880 // This table contains decompress functions which can be applied to
881 // uncompressed data. The compression mask is stored in the first byte
882 // of compressed data
883 static TDecompressTable dcmp_table[] =
884 {
885     {MPQ_COMPRESSION_BZIP2,        Decompress_BZIP2},        // Decompression with Bzip2 library
886     {MPQ_COMPRESSION_PKWARE,       Decompress_PKLIB},        // Decompression with Pkware Data Compression Library
887     {MPQ_COMPRESSION_ZLIB,         Decompress_ZLIB},         // Decompression with the "zlib" library
888     {MPQ_COMPRESSION_HUFFMANN,     Decompress_huff},         // Huffmann decompression
889     {MPQ_COMPRESSION_ADPCM_STEREO, Decompress_ADPCM_stereo}, // IMA ADPCM stereo decompression
890     {MPQ_COMPRESSION_ADPCM_MONO,   Decompress_ADPCM_mono},   // IMA ADPCM mono decompression
891     {MPQ_COMPRESSION_SPARSE,       Decompress_SPARSE}        // Sparse decompression
892 };
893 
SCompDecompress(void * pvOutBuffer,int * pcbOutBuffer,void * pvInBuffer,int cbInBuffer)894 int WINAPI SCompDecompress(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer)
895 {
896     unsigned char * pbWorkBuffer = NULL;
897     unsigned char * pbOutBuffer = (unsigned char *)pvOutBuffer;
898     unsigned char * pbInBuffer = (unsigned char *)pvInBuffer;
899     unsigned char * pbOutput = (unsigned char *)pvOutBuffer;
900     unsigned char * pbInput;
901     unsigned uCompressionMask;              // Decompressions applied to the data
902     unsigned uCompressionCopy;              // Decompressions applied to the data
903     int      cbOutBuffer = *pcbOutBuffer;   // Current size of the output buffer
904     int      cbInLength;                    // Current size of the input buffer
905     int      nCompressCount = 0;            // Number of compressions to be applied
906     int      nCompressIndex = 0;
907     int      nResult = 1;
908 
909     // Verify buffer sizes
910     if(cbOutBuffer < cbInBuffer || cbInBuffer < 1)
911         return 0;
912 
913     // If the input length is the same as output length, do nothing.
914     if(cbOutBuffer == cbInBuffer)
915     {
916         // If the buffers are equal, don't copy anything.
917         if(pvInBuffer != pvOutBuffer)
918             memcpy(pvOutBuffer, pvInBuffer, cbInBuffer);
919         return 1;
920     }
921 
922     // Get applied compression types and decrement data length
923     uCompressionMask = uCompressionCopy = (unsigned char)*pbInBuffer++;
924     cbInBuffer--;
925 
926     // Get current compressed data and length of it
927     pbInput = pbInBuffer;
928     cbInLength = cbInBuffer;
929 
930     // This compression function doesn't support LZMA
931     assert(uCompressionMask != MPQ_COMPRESSION_LZMA);
932 
933     // Parse the compression mask
934     for(size_t i = 0; i < (sizeof(dcmp_table) / sizeof(TDecompressTable)); i++)
935     {
936         // If the mask agrees, insert the compression function to the array
937         if(uCompressionMask & dcmp_table[i].uMask)
938         {
939             uCompressionCopy &= ~dcmp_table[i].uMask;
940             nCompressCount++;
941         }
942     }
943 
944     // If at least one of the compressions remaing unknown, return an error
945     if(nCompressCount == 0 || uCompressionCopy != 0)
946     {
947         SetLastError(ERROR_NOT_SUPPORTED);
948         return 0;
949     }
950 
951     // If there is more than one compression, we have to allocate extra buffer
952     if(nCompressCount > 1)
953     {
954         pbWorkBuffer = STORM_ALLOC(unsigned char, cbOutBuffer);
955         if(pbWorkBuffer == NULL)
956         {
957             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
958             return 0;
959         }
960     }
961 
962     // Get the current compression index
963     nCompressIndex = nCompressCount - 1;
964 
965     // Apply all decompressions
966     for(size_t i = 0; i < (sizeof(dcmp_table) / sizeof(TDecompressTable)); i++)
967     {
968         // Perform the (next) decompression
969         if(uCompressionMask & dcmp_table[i].uMask)
970         {
971             // Get the correct output buffer
972             pbOutput = (nCompressIndex & 1) ? pbWorkBuffer : pbOutBuffer;
973             nCompressIndex--;
974 
975             // Perform the decompression
976             cbOutBuffer = *pcbOutBuffer;
977             nResult = dcmp_table[i].Decompress(pbOutput, &cbOutBuffer, pbInput, cbInLength);
978             if(nResult == 0 || cbOutBuffer == 0)
979             {
980                 SetLastError(ERROR_FILE_CORRUPT);
981                 nResult = 0;
982                 break;
983             }
984 
985             // Switch buffers
986             cbInLength = cbOutBuffer;
987             pbInput = pbOutput;
988         }
989     }
990 
991     // Put the length of the decompressed data to the output buffer
992     *pcbOutBuffer = cbOutBuffer;
993 
994     // Cleanup and return
995     if(pbWorkBuffer != NULL)
996         STORM_FREE(pbWorkBuffer);
997     return nResult;
998 }
999 
SCompDecompress2(void * pvOutBuffer,int * pcbOutBuffer,void * pvInBuffer,int cbInBuffer)1000 int WINAPI SCompDecompress2(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer)
1001 {
1002     DECOMPRESS pfnDecompress1 = NULL;
1003     DECOMPRESS pfnDecompress2 = NULL;
1004     unsigned char * pbWorkBuffer = (unsigned char *)pvOutBuffer;
1005     unsigned char * pbInBuffer = (unsigned char *)pvInBuffer;
1006     int cbWorkBuffer = *pcbOutBuffer;
1007     int nResult;
1008     char CompressionMethod;
1009 
1010     // Verify buffer sizes
1011     if(*pcbOutBuffer < cbInBuffer || cbInBuffer < 1)
1012         return 0;
1013 
1014     // If the outputbuffer is as big as input buffer, just copy the block
1015     if(*pcbOutBuffer == cbInBuffer)
1016     {
1017         if(pvOutBuffer != pvInBuffer)
1018             memcpy(pvOutBuffer, pvInBuffer, cbInBuffer);
1019         return 1;
1020     }
1021 
1022     // Get the compression methods
1023     CompressionMethod = *pbInBuffer++;
1024     cbInBuffer--;
1025 
1026     // We only recognize a fixed set of compression methods
1027     switch((unsigned char)CompressionMethod)
1028     {
1029         case MPQ_COMPRESSION_ZLIB:
1030             pfnDecompress1 = Decompress_ZLIB;
1031             break;
1032 
1033         case MPQ_COMPRESSION_PKWARE:
1034             pfnDecompress1 = Decompress_PKLIB;
1035             break;
1036 
1037         case MPQ_COMPRESSION_BZIP2:
1038             pfnDecompress1 = Decompress_BZIP2;
1039             break;
1040 
1041         case MPQ_COMPRESSION_LZMA:
1042             pfnDecompress1 = Decompress_LZMA;
1043             break;
1044 
1045         case MPQ_COMPRESSION_SPARSE:
1046             pfnDecompress1 = Decompress_SPARSE;
1047             break;
1048 
1049         case (MPQ_COMPRESSION_SPARSE | MPQ_COMPRESSION_ZLIB):
1050             pfnDecompress1 = Decompress_ZLIB;
1051             pfnDecompress2 = Decompress_SPARSE;
1052             break;
1053 
1054         case (MPQ_COMPRESSION_SPARSE | MPQ_COMPRESSION_BZIP2):
1055             pfnDecompress1 = Decompress_BZIP2;
1056             pfnDecompress2 = Decompress_SPARSE;
1057             break;
1058 
1059         //
1060         // Note: Any combination including MPQ_COMPRESSION_ADPCM_MONO,
1061         // MPQ_COMPRESSION_ADPCM_STEREO or MPQ_COMPRESSION_HUFFMANN
1062         // is not supported by newer MPQs.
1063         //
1064 
1065         case (MPQ_COMPRESSION_ADPCM_MONO | MPQ_COMPRESSION_HUFFMANN):
1066             pfnDecompress1 = Decompress_huff;
1067             pfnDecompress2 = Decompress_ADPCM_mono;
1068             break;
1069 
1070         case (MPQ_COMPRESSION_ADPCM_STEREO | MPQ_COMPRESSION_HUFFMANN):
1071             pfnDecompress1 = Decompress_huff;
1072             pfnDecompress2 = Decompress_ADPCM_stereo;
1073             break;
1074 
1075         default:
1076             SetLastError(ERROR_FILE_CORRUPT);
1077             return 0;
1078     }
1079 
1080     // If we have to use two decompressions, allocate temporary buffer
1081     if(pfnDecompress2 != NULL)
1082     {
1083         pbWorkBuffer = STORM_ALLOC(unsigned char, *pcbOutBuffer);
1084         if(pbWorkBuffer == NULL)
1085         {
1086             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1087             return 0;
1088         }
1089     }
1090 
1091     // Apply the first decompression method
1092     nResult = pfnDecompress1(pbWorkBuffer, &cbWorkBuffer, pbInBuffer, cbInBuffer);
1093 
1094     // Apply the second decompression method, if any
1095     if(pfnDecompress2 != NULL && nResult != 0)
1096     {
1097         cbInBuffer   = cbWorkBuffer;
1098         cbWorkBuffer = *pcbOutBuffer;
1099         nResult = pfnDecompress2(pvOutBuffer, &cbWorkBuffer, pbWorkBuffer, cbInBuffer);
1100     }
1101 
1102     // Supply the output buffer size
1103     *pcbOutBuffer = cbWorkBuffer;
1104 
1105     // Free temporary buffer
1106     if(pbWorkBuffer != pvOutBuffer)
1107         STORM_FREE(pbWorkBuffer);
1108 
1109     if(nResult == 0)
1110         SetLastError(ERROR_FILE_CORRUPT);
1111     return nResult;
1112 }
1113 
1114 /*****************************************************************************/
1115 /*                                                                           */
1116 /*   File decompression for MPK archives                                     */
1117 /*                                                                           */
1118 /*****************************************************************************/
1119 
SCompDecompressMpk(void * pvOutBuffer,int * pcbOutBuffer,void * pvInBuffer,int cbInBuffer)1120 int SCompDecompressMpk(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer)
1121 {
1122     return Decompress_LZMA_MPK(pvOutBuffer, pcbOutBuffer, pvInBuffer, cbInBuffer);
1123 }
1124 
1125