the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
1#include "stdafx.h"
2#include "compression.h"
3#if defined __ORBIS__ || defined __PS3__ || defined _DURANGO || defined _WIN64
4#include "..\Minecraft.Client\Common\zlib\zlib.h"
5#endif
6
7#if defined __PSVITA__
8#include "..\Minecraft.Client\PSVita\PSVitaExtras\zlib.h"
9#elif defined __PS3__
10#include "..\Minecraft.Client\PS3\PS3Extras\EdgeZLib.h"
11#endif //__PS3__
12
13
14DWORD Compression::tlsIdx = 0;
15Compression::ThreadStorage *Compression::tlsDefault = NULL;
16
17Compression::ThreadStorage::ThreadStorage()
18{
19 compression = new Compression();
20}
21
22Compression::ThreadStorage::~ThreadStorage()
23{
24 delete compression;
25}
26
27void Compression::CreateNewThreadStorage()
28{
29 ThreadStorage *tls = new ThreadStorage();
30 if(tlsDefault == NULL )
31 {
32 tlsIdx = TlsAlloc();
33 tlsDefault = tls;
34 }
35 TlsSetValue(tlsIdx, tls);
36}
37
38void Compression::UseDefaultThreadStorage()
39{
40 TlsSetValue(tlsIdx, tlsDefault);
41}
42
43void Compression::ReleaseThreadStorage()
44{
45 ThreadStorage *tls = (ThreadStorage *)TlsGetValue(tlsIdx);
46 if( tls == tlsDefault ) return;
47
48 delete tls;
49}
50
51Compression *Compression::getCompression()
52{
53 ThreadStorage *tls = (ThreadStorage *)TlsGetValue(tlsIdx);
54 return tls->compression;
55}
56
57HRESULT Compression::CompressLZXRLE(void *pDestination, unsigned int *pDestSize, void *pSource, unsigned int SrcSize)
58{
59 EnterCriticalSection(&rleCompressLock);
60 //static unsigned char rleBuf[1024*100];
61
62 unsigned char *pucIn = (unsigned char *)pSource;
63 unsigned char *pucEnd = pucIn + SrcSize;
64 unsigned char *pucOut = (unsigned char *)rleCompressBuf;
65
66 // Compress with RLE first:
67 // 0 - 254 - encodes a single byte
68 // 255 followed by 0, 1, 2 - encodes a 1, 2, or 3 255s
69 // 255 followed by 3-255, followed by a byte - encodes a run of n + 1 bytes
70 PIXBeginNamedEvent(0,"RLE compression");
71 do
72 {
73 unsigned char thisOne = *pucIn++;
74
75 unsigned int count = 1;
76 while( ( pucIn != pucEnd ) && ( *pucIn == thisOne ) && ( count < 256 ) )
77 {
78 pucIn++;
79 count++;
80 }
81
82 if( count <= 3 )
83 {
84 if( thisOne == 255 )
85 {
86 *pucOut++ = 255;
87 *pucOut++ = count - 1;
88 }
89 else
90 {
91 for( unsigned int i = 0; i < count ; i++ )
92 {
93 *pucOut++ = thisOne;
94 }
95 }
96 }
97 else
98 {
99 *pucOut++ = 255;
100 *pucOut++ = count - 1;
101 *pucOut++ = thisOne;
102 }
103 } while (pucIn != pucEnd);
104 unsigned int rleSize = (unsigned int)(pucOut - rleCompressBuf);
105 PIXEndNamedEvent();
106
107 PIXBeginNamedEvent(0,"Secondary compression");
108 Compress(pDestination, pDestSize, rleCompressBuf, rleSize);
109 PIXEndNamedEvent();
110 LeaveCriticalSection(&rleCompressLock);
111// printf("Compressed from %d to %d to %d\n",SrcSize,rleSize,*pDestSize);
112
113 return S_OK;
114}
115
116HRESULT Compression::CompressRLE(void *pDestination, unsigned int *pDestSize, void *pSource, unsigned int SrcSize)
117{
118 EnterCriticalSection(&rleCompressLock);
119 //static unsigned char rleBuf[1024*100];
120
121 unsigned char *pucIn = (unsigned char *)pSource;
122 unsigned char *pucEnd = pucIn + SrcSize;
123 unsigned char *pucOut = (unsigned char *)rleCompressBuf;
124
125 // Compress with RLE first:
126 // 0 - 254 - encodes a single byte
127 // 255 followed by 0, 1, 2 - encodes a 1, 2, or 3 255s
128 // 255 followed by 3-255, followed by a byte - encodes a run of n + 1 bytes
129 PIXBeginNamedEvent(0,"RLE compression");
130 do
131 {
132 unsigned char thisOne = *pucIn++;
133
134 unsigned int count = 1;
135 while( ( pucIn != pucEnd ) && ( *pucIn == thisOne ) && ( count < 256 ) )
136 {
137 pucIn++;
138 count++;
139 }
140
141 if( count <= 3 )
142 {
143 if( thisOne == 255 )
144 {
145 *pucOut++ = 255;
146 *pucOut++ = count - 1;
147 }
148 else
149 {
150 for( unsigned int i = 0; i < count ; i++ )
151 {
152 *pucOut++ = thisOne;
153 }
154 }
155 }
156 else
157 {
158 *pucOut++ = 255;
159 *pucOut++ = count - 1;
160 *pucOut++ = thisOne;
161 }
162 } while (pucIn != pucEnd);
163 unsigned int rleSize = (unsigned int)(pucOut - rleCompressBuf);
164 PIXEndNamedEvent();
165 LeaveCriticalSection(&rleCompressLock);
166
167 // Return
168 if (rleSize <= *pDestSize)
169 {
170 *pDestSize = rleSize;
171 memcpy(pDestination, rleCompressBuf, *pDestSize);
172 }
173 else
174 {
175#ifndef _CONTENT_PACKAGE
176 assert(false);
177#endif
178 }
179
180 return S_OK;
181}
182
183HRESULT Compression::DecompressLZXRLE(void *pDestination, unsigned int *pDestSize, void *pSource, unsigned int SrcSize)
184{
185 EnterCriticalSection(&rleDecompressLock);
186 // 4J Stu - Fix for #13676 - Crash: Crash while attempting to load a world after updating TU
187 // Some saves can have chunks that decompress into very large sizes, so I have doubled the size of this buffer
188 // Ideally we should be able to dynamically allocate the buffer if it's going to be too big, as most chunks
189 // only use 5% of this buffer
190
191 // 4J Stu - Changed this again to dynamically allocate a buffer if it's going to be too big
192 unsigned char *pucIn = NULL;
193
194 //const unsigned int staticRleSize = 1024*200;
195 //static unsigned char rleBuf[staticRleSize];
196 unsigned int rleSize = staticRleSize;
197 unsigned char *dynamicRleBuf = NULL;
198
199 if(*pDestSize > rleSize)
200 {
201 rleSize = *pDestSize;
202 dynamicRleBuf = new unsigned char[rleSize];
203 Decompress(dynamicRleBuf, &rleSize, pSource, SrcSize);
204 pucIn = (unsigned char *)dynamicRleBuf;
205 }
206 else
207 {
208 Decompress(rleDecompressBuf, &rleSize, pSource, SrcSize);
209 pucIn = (unsigned char *)rleDecompressBuf;
210 }
211
212 //unsigned char *pucIn = (unsigned char *)rleDecompressBuf;
213 unsigned char *pucEnd = pucIn + rleSize;
214 unsigned char *pucOut = (unsigned char *)pDestination;
215
216 while( pucIn != pucEnd )
217 {
218 unsigned char thisOne = *pucIn++;
219 if( thisOne == 255 )
220 {
221 unsigned int count = *pucIn++;
222 if( count < 3 )
223 {
224 count++;
225 for( unsigned int i = 0; i < count; i++ )
226 {
227 *pucOut++ = 255;
228 }
229 }
230 else
231 {
232 count++;
233 unsigned char data = *pucIn++;
234 for( unsigned int i = 0; i < count; i++ )
235 {
236 *pucOut++ = data;
237 }
238 }
239 }
240 else
241 {
242 *pucOut++ = thisOne;
243 }
244 }
245 *pDestSize = (unsigned int)(pucOut - (unsigned char *)pDestination);
246
247// printf("Decompressed from %d to %d to %d\n",SrcSize,rleSize,*pDestSize);
248
249 if(dynamicRleBuf != NULL) delete [] dynamicRleBuf;
250
251 LeaveCriticalSection(&rleDecompressLock);
252 return S_OK;
253}
254
255HRESULT Compression::DecompressRLE(void *pDestination, unsigned int *pDestSize, void *pSource, unsigned int SrcSize)
256{
257 EnterCriticalSection(&rleDecompressLock);
258
259 //unsigned char *pucIn = (unsigned char *)rleDecompressBuf;
260 unsigned char *pucIn = (unsigned char *)pSource;
261 unsigned char *pucEnd = pucIn + SrcSize;
262 unsigned char *pucOut = (unsigned char *)pDestination;
263
264 while( pucIn != pucEnd )
265 {
266 unsigned char thisOne = *pucIn++;
267 if( thisOne == 255 )
268 {
269 unsigned int count = *pucIn++;
270 if( count < 3 )
271 {
272 count++;
273 for( unsigned int i = 0; i < count; i++ )
274 {
275 *pucOut++ = 255;
276 }
277 }
278 else
279 {
280 count++;
281 unsigned char data = *pucIn++;
282 for( unsigned int i = 0; i < count; i++ )
283 {
284 *pucOut++ = data;
285 }
286 }
287 }
288 else
289 {
290 *pucOut++ = thisOne;
291 }
292 }
293 *pDestSize = (unsigned int)(pucOut - (unsigned char *)pDestination);
294
295 LeaveCriticalSection(&rleDecompressLock);
296 return S_OK;
297}
298
299
300HRESULT Compression::Compress(void *pDestination, unsigned int *pDestSize, void *pSource, unsigned int SrcSize)
301{
302 // Using zlib for x64 compression - 360 is using native 360 compression and PS3 a stubbed non-compressing version of this
303#if defined __ORBIS__ || defined _DURANGO || defined _WIN64 || defined __PSVITA__
304 SIZE_T destSize = (SIZE_T)(*pDestSize);
305 int res = ::compress((Bytef *)pDestination, (uLongf *)&destSize, (Bytef *)pSource, SrcSize);
306 *pDestSize = (unsigned int)destSize;
307 return ( ( res == Z_OK ) ? S_OK : -1 );
308#elif defined __PS3__
309 uint32_t destSize = (uint32_t)(*pDestSize);
310 bool res = EdgeZLib::Compress(pDestination, &destSize, pSource, SrcSize);
311 *pDestSize = (unsigned int)destSize;
312 return ( ( res ) ? S_OK : -1 );
313#else
314 SIZE_T destSize = (SIZE_T)(*pDestSize);
315 HRESULT res = XMemCompress(compressionContext, pDestination, &destSize, pSource, SrcSize);
316 *pDestSize = (unsigned int)destSize;
317 return res;
318#endif
319}
320
321HRESULT Compression::Decompress(void *pDestination, unsigned int *pDestSize, void *pSource, unsigned int SrcSize)
322{
323
324 if(m_decompressType != m_localDecompressType) // check if we're decompressing data from a different platform
325 {
326 // only used for loading a save from a different platform (Sony cloud storage cross play)
327 return DecompressWithType(pDestination, pDestSize, pSource, SrcSize);
328 }
329
330 // Using zlib for x64 compression - 360 is using native 360 compression and PS3 a stubbed non-compressing version of this
331#if defined __ORBIS__ || defined _DURANGO || defined _WIN64 || defined __PSVITA__
332 SIZE_T destSize = (SIZE_T)(*pDestSize);
333 int res = ::uncompress((Bytef *)pDestination, (uLongf *)&destSize, (Bytef *)pSource, SrcSize);
334 *pDestSize = (unsigned int)destSize;
335 return ( ( res == Z_OK ) ? S_OK : -1 );
336#elif defined __PS3__
337 uint32_t destSize = (uint32_t)(*pDestSize);
338 bool res = EdgeZLib::Decompress(pDestination, &destSize, pSource, SrcSize);
339 *pDestSize = (unsigned int)destSize;
340 return ( ( res ) ? S_OK : -1 );
341#else
342 SIZE_T destSize = (SIZE_T)(*pDestSize);
343 HRESULT res = XMemDecompress(decompressionContext, pDestination, (SIZE_T *)&destSize, pSource, SrcSize);
344 *pDestSize = (unsigned int)destSize;
345 return res;
346#endif
347}
348
349// MGH - same as VirtualDecompress in PSVitaStubs, but for use on other platforms (so no virtual mem stuff)
350#ifndef _XBOX
351VOID Compression::VitaVirtualDecompress(void *pDestination, unsigned int *pDestSize, void *pSource, unsigned int SrcSize) // (LPVOID buf, SIZE_T dwSize, LPVOID dst)
352{
353 uint8_t *pSrc = (uint8_t *)pSource;
354 int Offset = 0;
355 int Page = 0;
356 int Index = 0;
357 uint8_t* Data = (uint8_t*)pDestination;
358 while( Index != SrcSize )
359 {
360 // is this a normal value
361 if( pSrc[Index] )
362 {
363 // just copy it across
364 Data[Offset] = pSrc[Index];
365 Offset += 1;
366 }
367 else
368 {
369 // how many zeros do we have
370 Index += 1;
371 int Count = pSrc[Index];
372 // to do : this should really be a sequence of memsets
373 for( int i = 0;i < Count;i += 1 )
374 {
375 Data[Offset] = 0;
376 Offset += 1;
377 }
378 }
379 Index += 1;
380 }
381 *pDestSize = Offset;
382}
383#endif
384
385
386HRESULT Compression::DecompressWithType(void *pDestination, unsigned int *pDestSize, void *pSource, unsigned int SrcSize)
387{
388 switch(m_decompressType)
389 {
390 case eCompressionType_RLE: // 4J-JEV, RLE is just that; don't want to break here though.
391 case eCompressionType_None:
392 memcpy(pDestination,pSource,SrcSize);
393 *pDestSize = SrcSize;
394 return S_OK;
395 case eCompressionType_LZXRLE:
396 {
397#if (defined _XBOX || defined _DURANGO || defined _WIN64)
398 SIZE_T destSize = (SIZE_T)(*pDestSize);
399 HRESULT res = XMemDecompress(decompressionContext, pDestination, (SIZE_T *)&destSize, pSource, SrcSize);
400 *pDestSize = (unsigned int)destSize;
401 return res;
402#else
403 assert(0);
404#endif
405 }
406 break;
407 case eCompressionType_ZLIBRLE:
408#if (defined __ORBIS__ || defined __PS3__ || defined _DURANGO || defined _WIN64)
409 if (pDestination != NULL)
410 return ::uncompress((PBYTE)pDestination, (unsigned long *) pDestSize, (PBYTE) pSource, SrcSize); // Decompress
411 else break; // Cannot decompress when destination is NULL
412#else
413 assert(0);
414 break;
415#endif
416 case eCompressionType_PS3ZLIB:
417#if (defined __ORBIS__ || defined __PSVITA__ || defined _DURANGO || defined _WIN64)
418 // Note that we're missing the normal zlib header and footer so we'll use inflate to
419 // decompress the payload and skip all the CRC checking, etc
420 if (pDestination != NULL)
421 {
422 // Read big-endian srcize from array
423 PBYTE pbDestSize = (PBYTE) pDestSize;
424 PBYTE pbSource = (PBYTE) pSource;
425 for (int i = 3; i >= 0; i--) {
426 pbDestSize[3-i] = pbSource[i];
427 }
428
429 byteArray uncompr = byteArray(*pDestSize);
430
431 // Build decompression stream
432 z_stream strm;
433 strm.zalloc = Z_NULL;
434 strm.zfree = Z_NULL;
435 strm.opaque = Z_NULL;
436 strm.next_out = uncompr.data;
437 strm.avail_out = uncompr.length;
438 // Skip those first 4 bytes
439 strm.next_in = (PBYTE) pSource + 4;
440 strm.avail_in = SrcSize - 4;
441
442 int hr = inflateInit2(&strm, -15);
443
444 // Run inflate() on input until end of stream
445 do {
446 hr = inflate(&strm, Z_NO_FLUSH);
447
448 // Check
449 switch (hr) {
450 case Z_NEED_DICT:
451 case Z_DATA_ERROR:
452 case Z_MEM_ERROR:
453 case Z_STREAM_ERROR:
454 (void)inflateEnd(&strm);
455 assert(false);
456 }
457 } while (hr != Z_STREAM_END);
458
459 inflateEnd(&strm); // MGH - added, to clean up zlib, was causing a leak on Vita when dowloading a PS3 save
460
461 // Copy the uncompressed data to the destination
462 memcpy(pDestination, uncompr.data, uncompr.length);
463 *pDestSize = uncompr.length;
464
465 // Delete uncompressed data
466 delete uncompr.data;
467 return S_OK;
468 }
469 else break; // Cannot decompress when destination is NULL
470#else
471 assert(0);
472#endif
473 }
474
475 assert(false);
476 return -1;
477}
478
479
480
481Compression::Compression()
482{
483 // Using zlib for x64 compression - 360 is using native 360 compression and PS3 a stubbed non-compressing version of this
484#if !(defined __ORBIS__ || defined __PS3__)
485 // The default parameters for compression context allocated about 6.5MB, reducing the partition size here from the default 512KB to 128KB
486 // brings this down to about 3MB
487 XMEMCODEC_PARAMETERS_LZX params;
488 params.Flags = 0;
489 params.WindowSize = 128 * 1024;
490 params.CompressionPartitionSize = 128 * 1024;
491
492 XMemCreateCompressionContext(XMEMCODEC_LZX,¶ms,0,&compressionContext);
493 XMemCreateDecompressionContext(XMEMCODEC_LZX,¶ms,0,&decompressionContext);
494#endif
495
496#if defined _XBOX
497 m_localDecompressType = eCompressionType_LZXRLE;
498#elif defined __PS3__
499 m_localDecompressType = eCompressionType_PS3ZLIB;
500#else
501 m_localDecompressType = eCompressionType_ZLIBRLE;
502#endif
503 m_decompressType = m_localDecompressType;
504
505 InitializeCriticalSection(&rleCompressLock);
506 InitializeCriticalSection(&rleDecompressLock);
507}
508
509Compression::~Compression()
510{
511#if !(defined __ORBIS__ || defined __PS3__ || defined __PSVITA__)
512
513 XMemDestroyCompressionContext(compressionContext);
514 XMemDestroyDecompressionContext(decompressionContext);
515#endif
516 DeleteCriticalSection(&rleCompressLock);
517 DeleteCriticalSection(&rleDecompressLock);
518}
519
520
521
522void Compression::SetDecompressionType(ESavePlatform platform)
523{
524 switch(platform)
525 {
526 case SAVE_FILE_PLATFORM_X360:
527 Compression::getCompression()->SetDecompressionType(Compression::eCompressionType_LZXRLE);
528 break;
529 case SAVE_FILE_PLATFORM_PS3:
530 Compression::getCompression()->SetDecompressionType(Compression::eCompressionType_PS3ZLIB);
531 break;
532 case SAVE_FILE_PLATFORM_XBONE:
533 case SAVE_FILE_PLATFORM_PS4:
534 case SAVE_FILE_PLATFORM_PSVITA:
535 case SAVE_FILE_PLATFORM_WIN64:
536 Compression::getCompression()->SetDecompressionType(Compression::eCompressionType_ZLIBRLE);
537 break;
538 default:
539 assert(0);
540 break;
541 }
542}
543
544/*Compression gCompression;*/
545
546