aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/irrlicht-1.8/source/Irrlicht/CZipReader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/irrlicht-1.8/source/Irrlicht/CZipReader.cpp')
-rw-r--r--libraries/irrlicht-1.8/source/Irrlicht/CZipReader.cpp839
1 files changed, 839 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CZipReader.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CZipReader.cpp
new file mode 100644
index 0000000..be29f98
--- /dev/null
+++ b/libraries/irrlicht-1.8/source/Irrlicht/CZipReader.cpp
@@ -0,0 +1,839 @@
1// Copyright (C) 2002-2012 Nikolaus Gebhardt
2// This file is part of the "Irrlicht Engine".
3// For conditions of distribution and use, see copyright notice in irrlicht.h
4
5#include "CZipReader.h"
6
7#include "os.h"
8
9// This method is used for error output from bzip2.
10extern "C" void bz_internal_error(int errorCode)
11{
12 irr::os::Printer::log("Error in bzip2 handling", irr::core::stringc(errorCode), irr::ELL_ERROR);
13}
14
15#ifdef __IRR_COMPILE_WITH_ZIP_ARCHIVE_LOADER_
16
17#include "CFileList.h"
18#include "CReadFile.h"
19#include "coreutil.h"
20
21#include "IrrCompileConfig.h"
22#ifdef _IRR_COMPILE_WITH_ZLIB_
23 #ifndef _IRR_USE_NON_SYSTEM_ZLIB_
24 #include <zlib.h> // use system lib
25 #else
26 #include "zlib/zlib.h"
27 #endif
28
29 #ifdef _IRR_COMPILE_WITH_ZIP_ENCRYPTION_
30 #include "aesGladman/fileenc.h"
31 #endif
32 #ifdef _IRR_COMPILE_WITH_BZIP2_
33 #ifndef _IRR_USE_NON_SYSTEM_BZLIB_
34 #include <bzlib.h>
35 #else
36 #include "bzip2/bzlib.h"
37 #endif
38 #endif
39 #ifdef _IRR_COMPILE_WITH_LZMA_
40 #include "lzma/LzmaDec.h"
41 #endif
42#endif
43
44namespace irr
45{
46namespace io
47{
48
49
50// -----------------------------------------------------------------------------
51// zip loader
52// -----------------------------------------------------------------------------
53
54//! Constructor
55CArchiveLoaderZIP::CArchiveLoaderZIP(io::IFileSystem* fs)
56: FileSystem(fs)
57{
58 #ifdef _DEBUG
59 setDebugName("CArchiveLoaderZIP");
60 #endif
61}
62
63//! returns true if the file maybe is able to be loaded by this class
64bool CArchiveLoaderZIP::isALoadableFileFormat(const io::path& filename) const
65{
66 return core::hasFileExtension(filename, "zip", "pk3") ||
67 core::hasFileExtension(filename, "gz", "tgz");
68}
69
70//! Check to see if the loader can create archives of this type.
71bool CArchiveLoaderZIP::isALoadableFileFormat(E_FILE_ARCHIVE_TYPE fileType) const
72{
73 return (fileType == EFAT_ZIP || fileType == EFAT_GZIP);
74}
75
76
77//! Creates an archive from the filename
78/** \param file File handle to check.
79\return Pointer to newly created archive, or 0 upon error. */
80IFileArchive* CArchiveLoaderZIP::createArchive(const io::path& filename, bool ignoreCase, bool ignorePaths) const
81{
82 IFileArchive *archive = 0;
83 io::IReadFile* file = FileSystem->createAndOpenFile(filename);
84
85 if (file)
86 {
87 archive = createArchive(file, ignoreCase, ignorePaths);
88 file->drop();
89 }
90
91 return archive;
92}
93
94//! creates/loads an archive from the file.
95//! \return Pointer to the created archive. Returns 0 if loading failed.
96IFileArchive* CArchiveLoaderZIP::createArchive(io::IReadFile* file, bool ignoreCase, bool ignorePaths) const
97{
98 IFileArchive *archive = 0;
99 if (file)
100 {
101 file->seek(0);
102
103 u16 sig;
104 file->read(&sig, 2);
105
106#ifdef __BIG_ENDIAN__
107 sig = os::Byteswap::byteswap(sig);
108#endif
109
110 file->seek(0);
111
112 bool isGZip = (sig == 0x8b1f);
113
114 archive = new CZipReader(file, ignoreCase, ignorePaths, isGZip);
115 }
116 return archive;
117}
118
119//! Check if the file might be loaded by this class
120/** Check might look into the file.
121\param file File handle to check.
122\return True if file seems to be loadable. */
123bool CArchiveLoaderZIP::isALoadableFileFormat(io::IReadFile* file) const
124{
125 SZIPFileHeader header;
126
127 file->read( &header.Sig, 4 );
128#ifdef __BIG_ENDIAN__
129 header.Sig = os::Byteswap::byteswap(header.Sig);
130#endif
131
132 return header.Sig == 0x04034b50 || // ZIP
133 (header.Sig&0xffff) == 0x8b1f; // gzip
134}
135
136// -----------------------------------------------------------------------------
137// zip archive
138// -----------------------------------------------------------------------------
139
140CZipReader::CZipReader(IReadFile* file, bool ignoreCase, bool ignorePaths, bool isGZip)
141 : CFileList((file ? file->getFileName() : io::path("")), ignoreCase, ignorePaths), File(file), IsGZip(isGZip)
142{
143 #ifdef _DEBUG
144 setDebugName("CZipReader");
145 #endif
146
147 if (File)
148 {
149 File->grab();
150
151 // load file entries
152 if (IsGZip)
153 while (scanGZipHeader()) { }
154 else
155 while (scanZipHeader()) { }
156
157 sort();
158 }
159}
160
161CZipReader::~CZipReader()
162{
163 if (File)
164 File->drop();
165}
166
167
168//! get the archive type
169E_FILE_ARCHIVE_TYPE CZipReader::getType() const
170{
171 return IsGZip ? EFAT_GZIP : EFAT_ZIP;
172}
173
174const IFileList* CZipReader::getFileList() const
175{
176 return this;
177}
178
179
180//! scans for a local header, returns false if there is no more local file header.
181//! The gzip file format seems to think that there can be multiple files in a gzip file
182//! but none
183bool CZipReader::scanGZipHeader()
184{
185 SZipFileEntry entry;
186 entry.Offset = 0;
187 memset(&entry.header, 0, sizeof(SZIPFileHeader));
188
189 // read header
190 SGZIPMemberHeader header;
191 if (File->read(&header, sizeof(SGZIPMemberHeader)) == sizeof(SGZIPMemberHeader))
192 {
193
194#ifdef __BIG_ENDIAN__
195 header.sig = os::Byteswap::byteswap(header.sig);
196 header.time = os::Byteswap::byteswap(header.time);
197#endif
198
199 // check header value
200 if (header.sig != 0x8b1f)
201 return false;
202
203 // now get the file info
204 if (header.flags & EGZF_EXTRA_FIELDS)
205 {
206 // read lenth of extra data
207 u16 dataLen;
208
209 File->read(&dataLen, 2);
210
211#ifdef __BIG_ENDIAN__
212 dataLen = os::Byteswap::byteswap(dataLen);
213#endif
214
215 // skip it
216 File->seek(dataLen, true);
217 }
218
219 io::path ZipFileName = "";
220
221 if (header.flags & EGZF_FILE_NAME)
222 {
223 c8 c;
224 File->read(&c, 1);
225 while (c)
226 {
227 ZipFileName.append(c);
228 File->read(&c, 1);
229 }
230 }
231 else
232 {
233 // no file name?
234 ZipFileName = Path;
235 core::deletePathFromFilename(ZipFileName);
236
237 // rename tgz to tar or remove gz extension
238 if (core::hasFileExtension(ZipFileName, "tgz"))
239 {
240 ZipFileName[ ZipFileName.size() - 2] = 'a';
241 ZipFileName[ ZipFileName.size() - 1] = 'r';
242 }
243 else if (core::hasFileExtension(ZipFileName, "gz"))
244 {
245 ZipFileName[ ZipFileName.size() - 3] = 0;
246 ZipFileName.validate();
247 }
248 }
249
250 if (header.flags & EGZF_COMMENT)
251 {
252 c8 c='a';
253 while (c)
254 File->read(&c, 1);
255 }
256
257 if (header.flags & EGZF_CRC16)
258 File->seek(2, true);
259
260 // we are now at the start of the data blocks
261 entry.Offset = File->getPos();
262
263 entry.header.FilenameLength = ZipFileName.size();
264
265 entry.header.CompressionMethod = header.compressionMethod;
266 entry.header.DataDescriptor.CompressedSize = (File->getSize() - 8) - File->getPos();
267
268 // seek to file end
269 File->seek(entry.header.DataDescriptor.CompressedSize, true);
270
271 // read CRC
272 File->read(&entry.header.DataDescriptor.CRC32, 4);
273 // read uncompressed size
274 File->read(&entry.header.DataDescriptor.UncompressedSize, 4);
275
276#ifdef __BIG_ENDIAN__
277 entry.header.DataDescriptor.CRC32 = os::Byteswap::byteswap(entry.header.DataDescriptor.CRC32);
278 entry.header.DataDescriptor.UncompressedSize = os::Byteswap::byteswap(entry.header.DataDescriptor.UncompressedSize);
279#endif
280
281 // now we've filled all the fields, this is just a standard deflate block
282 addItem(ZipFileName, entry.Offset, entry.header.DataDescriptor.UncompressedSize, false, 0);
283 FileInfo.push_back(entry);
284 }
285
286 // there's only one block of data in a gzip file
287 return false;
288}
289
290//! scans for a local header, returns false if there is no more local file header.
291bool CZipReader::scanZipHeader(bool ignoreGPBits)
292{
293 io::path ZipFileName = "";
294 SZipFileEntry entry;
295 entry.Offset = 0;
296 memset(&entry.header, 0, sizeof(SZIPFileHeader));
297
298 File->read(&entry.header, sizeof(SZIPFileHeader));
299
300#ifdef __BIG_ENDIAN__
301 entry.header.Sig = os::Byteswap::byteswap(entry.header.Sig);
302 entry.header.VersionToExtract = os::Byteswap::byteswap(entry.header.VersionToExtract);
303 entry.header.GeneralBitFlag = os::Byteswap::byteswap(entry.header.GeneralBitFlag);
304 entry.header.CompressionMethod = os::Byteswap::byteswap(entry.header.CompressionMethod);
305 entry.header.LastModFileTime = os::Byteswap::byteswap(entry.header.LastModFileTime);
306 entry.header.LastModFileDate = os::Byteswap::byteswap(entry.header.LastModFileDate);
307 entry.header.DataDescriptor.CRC32 = os::Byteswap::byteswap(entry.header.DataDescriptor.CRC32);
308 entry.header.DataDescriptor.CompressedSize = os::Byteswap::byteswap(entry.header.DataDescriptor.CompressedSize);
309 entry.header.DataDescriptor.UncompressedSize = os::Byteswap::byteswap(entry.header.DataDescriptor.UncompressedSize);
310 entry.header.FilenameLength = os::Byteswap::byteswap(entry.header.FilenameLength);
311 entry.header.ExtraFieldLength = os::Byteswap::byteswap(entry.header.ExtraFieldLength);
312#endif
313
314 if (entry.header.Sig != 0x04034b50)
315 return false; // local file headers end here.
316
317 // read filename
318 {
319 c8 *tmp = new c8 [ entry.header.FilenameLength + 2 ];
320 File->read(tmp, entry.header.FilenameLength);
321 tmp[entry.header.FilenameLength] = 0;
322 ZipFileName = tmp;
323 delete [] tmp;
324 }
325
326#ifdef _IRR_COMPILE_WITH_ZIP_ENCRYPTION_
327 // AES encryption
328 if ((entry.header.GeneralBitFlag & ZIP_FILE_ENCRYPTED) && (entry.header.CompressionMethod == 99))
329 {
330 s16 restSize = entry.header.ExtraFieldLength;
331 SZipFileExtraHeader extraHeader;
332 while (restSize)
333 {
334 File->read(&extraHeader, sizeof(extraHeader));
335#ifdef __BIG_ENDIAN__
336 extraHeader.ID = os::Byteswap::byteswap(extraHeader.ID);
337 extraHeader.Size = os::Byteswap::byteswap(extraHeader.Size);
338#endif
339 restSize -= sizeof(extraHeader);
340 if (extraHeader.ID==(s16)0x9901)
341 {
342 SZipFileAESExtraData data;
343 File->read(&data, sizeof(data));
344#ifdef __BIG_ENDIAN__
345 data.Version = os::Byteswap::byteswap(data.Version);
346 data.CompressionMode = os::Byteswap::byteswap(data.CompressionMode);
347#endif
348 restSize -= sizeof(data);
349 if (data.Vendor[0]=='A' && data.Vendor[1]=='E')
350 {
351 // encode values into Sig
352 // AE-Version | Strength | ActualMode
353 entry.header.Sig =
354 ((data.Version & 0xff) << 24) |
355 (data.EncryptionStrength << 16) |
356 (data.CompressionMode);
357 File->seek(restSize, true);
358 break;
359 }
360 }
361 }
362 }
363 // move forward length of extra field.
364 else
365#endif
366 if (entry.header.ExtraFieldLength)
367 File->seek(entry.header.ExtraFieldLength, true);
368
369 // if bit 3 was set, use CentralDirectory for setup
370 if (!ignoreGPBits && entry.header.GeneralBitFlag & ZIP_INFO_IN_DATA_DESCRIPTOR)
371 {
372 SZIPFileCentralDirEnd dirEnd;
373 FileInfo.clear();
374 Files.clear();
375 // First place where the end record could be stored
376 File->seek(File->getSize()-22);
377 const char endID[] = {0x50, 0x4b, 0x05, 0x06, 0x0};
378 char tmp[5]={'\0'};
379 bool found=false;
380 // search for the end record ID
381 while (!found && File->getPos()>0)
382 {
383 int seek=8;
384 File->read(tmp, 4);
385 switch (tmp[0])
386 {
387 case 0x50:
388 if (!strcmp(endID, tmp))
389 {
390 seek=4;
391 found=true;
392 }
393 break;
394 case 0x4b:
395 seek=5;
396 break;
397 case 0x05:
398 seek=6;
399 break;
400 case 0x06:
401 seek=7;
402 break;
403 }
404 File->seek(-seek, true);
405 }
406 File->read(&dirEnd, sizeof(dirEnd));
407#ifdef __BIG_ENDIAN__
408 dirEnd.NumberDisk = os::Byteswap::byteswap(dirEnd.NumberDisk);
409 dirEnd.NumberStart = os::Byteswap::byteswap(dirEnd.NumberStart);
410 dirEnd.TotalDisk = os::Byteswap::byteswap(dirEnd.TotalDisk);
411 dirEnd.TotalEntries = os::Byteswap::byteswap(dirEnd.TotalEntries);
412 dirEnd.Size = os::Byteswap::byteswap(dirEnd.Size);
413 dirEnd.Offset = os::Byteswap::byteswap(dirEnd.Offset);
414 dirEnd.CommentLength = os::Byteswap::byteswap(dirEnd.CommentLength);
415#endif
416 FileInfo.reallocate(dirEnd.TotalEntries);
417 File->seek(dirEnd.Offset);
418 while (scanCentralDirectoryHeader()) { }
419 return false;
420 }
421
422 // store position in file
423 entry.Offset = File->getPos();
424 // move forward length of data
425 File->seek(entry.header.DataDescriptor.CompressedSize, true);
426
427 #ifdef _DEBUG
428 //os::Debuginfo::print("added file from archive", ZipFileName.c_str());
429 #endif
430
431 addItem(ZipFileName, entry.Offset, entry.header.DataDescriptor.UncompressedSize, ZipFileName.lastChar()=='/', FileInfo.size());
432 FileInfo.push_back(entry);
433
434 return true;
435}
436
437
438//! scans for a local header, returns false if there is no more local file header.
439bool CZipReader::scanCentralDirectoryHeader()
440{
441 io::path ZipFileName = "";
442 SZIPFileCentralDirFileHeader entry;
443 File->read(&entry, sizeof(SZIPFileCentralDirFileHeader));
444
445#ifdef __BIG_ENDIAN__
446 entry.Sig = os::Byteswap::byteswap(entry.Sig);
447 entry.VersionMadeBy = os::Byteswap::byteswap(entry.VersionMadeBy);
448 entry.VersionToExtract = os::Byteswap::byteswap(entry.VersionToExtract);
449 entry.GeneralBitFlag = os::Byteswap::byteswap(entry.GeneralBitFlag);
450 entry.CompressionMethod = os::Byteswap::byteswap(entry.CompressionMethod);
451 entry.LastModFileTime = os::Byteswap::byteswap(entry.LastModFileTime);
452 entry.LastModFileDate = os::Byteswap::byteswap(entry.LastModFileDate);
453 entry.CRC32 = os::Byteswap::byteswap(entry.CRC32);
454 entry.CompressedSize = os::Byteswap::byteswap(entry.CompressedSize);
455 entry.UncompressedSize = os::Byteswap::byteswap(entry.UncompressedSize);
456 entry.FilenameLength = os::Byteswap::byteswap(entry.FilenameLength);
457 entry.ExtraFieldLength = os::Byteswap::byteswap(entry.ExtraFieldLength);
458 entry.FileCommentLength = os::Byteswap::byteswap(entry.FileCommentLength);
459 entry.DiskNumberStart = os::Byteswap::byteswap(entry.DiskNumberStart);
460 entry.InternalFileAttributes = os::Byteswap::byteswap(entry.InternalFileAttributes);
461 entry.ExternalFileAttributes = os::Byteswap::byteswap(entry.ExternalFileAttributes);
462 entry.RelativeOffsetOfLocalHeader = os::Byteswap::byteswap(entry.RelativeOffsetOfLocalHeader);
463#endif
464
465 if (entry.Sig != 0x02014b50)
466 return false; // central dir headers end here.
467
468 const long pos = File->getPos();
469 File->seek(entry.RelativeOffsetOfLocalHeader);
470 scanZipHeader(true);
471 File->seek(pos+entry.FilenameLength+entry.ExtraFieldLength+entry.FileCommentLength);
472 FileInfo.getLast().header.DataDescriptor.CompressedSize=entry.CompressedSize;
473 FileInfo.getLast().header.DataDescriptor.UncompressedSize=entry.UncompressedSize;
474 FileInfo.getLast().header.DataDescriptor.CRC32=entry.CRC32;
475 Files.getLast().Size=entry.UncompressedSize;
476 return true;
477}
478
479
480//! opens a file by file name
481IReadFile* CZipReader::createAndOpenFile(const io::path& filename)
482{
483 s32 index = findFile(filename, false);
484
485 if (index != -1)
486 return createAndOpenFile(index);
487
488 return 0;
489}
490
491#ifdef _IRR_COMPILE_WITH_LZMA_
492//! Used for LZMA decompression. The lib has no default memory management
493namespace
494{
495 void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); }
496 void SzFree(void *p, void *address) { p = p; free(address); }
497 ISzAlloc lzmaAlloc = { SzAlloc, SzFree };
498}
499#endif
500
501//! opens a file by index
502IReadFile* CZipReader::createAndOpenFile(u32 index)
503{
504 // Irrlicht supports 0, 8, 12, 14, 99
505 //0 - The file is stored (no compression)
506 //1 - The file is Shrunk
507 //2 - The file is Reduced with compression factor 1
508 //3 - The file is Reduced with compression factor 2
509 //4 - The file is Reduced with compression factor 3
510 //5 - The file is Reduced with compression factor 4
511 //6 - The file is Imploded
512 //7 - Reserved for Tokenizing compression algorithm
513 //8 - The file is Deflated
514 //9 - Reserved for enhanced Deflating
515 //10 - PKWARE Date Compression Library Imploding
516 //12 - bzip2 - Compression Method from libbz2, WinZip 10
517 //14 - LZMA - Compression Method, WinZip 12
518 //96 - Jpeg compression - Compression Method, WinZip 12
519 //97 - WavPack - Compression Method, WinZip 11
520 //98 - PPMd - Compression Method, WinZip 10
521 //99 - AES encryption, WinZip 9
522
523 const SZipFileEntry &e = FileInfo[Files[index].ID];
524 wchar_t buf[64];
525 s16 actualCompressionMethod=e.header.CompressionMethod;
526 IReadFile* decrypted=0;
527 u8* decryptedBuf=0;
528 u32 decryptedSize=e.header.DataDescriptor.CompressedSize;
529#ifdef _IRR_COMPILE_WITH_ZIP_ENCRYPTION_
530 if ((e.header.GeneralBitFlag & ZIP_FILE_ENCRYPTED) && (e.header.CompressionMethod == 99))
531 {
532 os::Printer::log("Reading encrypted file.");
533 u8 salt[16]={0};
534 const u16 saltSize = (((e.header.Sig & 0x00ff0000) >>16)+1)*4;
535 File->seek(e.Offset);
536 File->read(salt, saltSize);
537 char pwVerification[2];
538 char pwVerificationFile[2];
539 File->read(pwVerification, 2);
540 fcrypt_ctx zctx; // the encryption context
541 int rc = fcrypt_init(
542 (e.header.Sig & 0x00ff0000) >>16,
543 (const unsigned char*)Password.c_str(), // the password
544 Password.size(), // number of bytes in password
545 salt, // the salt
546 (unsigned char*)pwVerificationFile, // on return contains password verifier
547 &zctx); // encryption context
548 if (strncmp(pwVerificationFile, pwVerification, 2))
549 {
550 os::Printer::log("Wrong password");
551 return 0;
552 }
553 decryptedSize= e.header.DataDescriptor.CompressedSize-saltSize-12;
554 decryptedBuf= new u8[decryptedSize];
555 u32 c = 0;
556 while ((c+32768)<=decryptedSize)
557 {
558 File->read(decryptedBuf+c, 32768);
559 fcrypt_decrypt(
560 decryptedBuf+c, // pointer to the data to decrypt
561 32768, // how many bytes to decrypt
562 &zctx); // decryption context
563 c+=32768;
564 }
565 File->read(decryptedBuf+c, decryptedSize-c);
566 fcrypt_decrypt(
567 decryptedBuf+c, // pointer to the data to decrypt
568 decryptedSize-c, // how many bytes to decrypt
569 &zctx); // decryption context
570
571 char fileMAC[10];
572 char resMAC[10];
573 rc = fcrypt_end(
574 (unsigned char*)resMAC, // on return contains the authentication code
575 &zctx); // encryption context
576 if (rc != 10)
577 {
578 os::Printer::log("Error on encryption closing");
579 delete [] decryptedBuf;
580 return 0;
581 }
582 File->read(fileMAC, 10);
583 if (strncmp(fileMAC, resMAC, 10))
584 {
585 os::Printer::log("Error on encryption check");
586 delete [] decryptedBuf;
587 return 0;
588 }
589 decrypted = io::createMemoryReadFile(decryptedBuf, decryptedSize, Files[index].FullName, true);
590 actualCompressionMethod = (e.header.Sig & 0xffff);
591#if 0
592 if ((e.header.Sig & 0xff000000)==0x01000000)
593 {
594 }
595 else if ((e.header.Sig & 0xff000000)==0x02000000)
596 {
597 }
598 else
599 {
600 os::Printer::log("Unknown encryption method");
601 return 0;
602 }
603#endif
604 }
605#endif
606 switch(actualCompressionMethod)
607 {
608 case 0: // no compression
609 {
610 if (decrypted)
611 return decrypted;
612 else
613 return createLimitReadFile(Files[index].FullName, File, e.Offset, decryptedSize);
614 }
615 case 8:
616 {
617 #ifdef _IRR_COMPILE_WITH_ZLIB_
618
619 const u32 uncompressedSize = e.header.DataDescriptor.UncompressedSize;
620 c8* pBuf = new c8[ uncompressedSize ];
621 if (!pBuf)
622 {
623 swprintf ( buf, 64, L"Not enough memory for decompressing %s", Files[index].FullName.c_str() );
624 os::Printer::log( buf, ELL_ERROR);
625 if (decrypted)
626 decrypted->drop();
627 return 0;
628 }
629
630 u8 *pcData = decryptedBuf;
631 if (!pcData)
632 {
633 pcData = new u8[decryptedSize];
634 if (!pcData)
635 {
636 swprintf ( buf, 64, L"Not enough memory for decompressing %s", Files[index].FullName.c_str() );
637 os::Printer::log( buf, ELL_ERROR);
638 delete [] pBuf;
639 return 0;
640 }
641
642 //memset(pcData, 0, decryptedSize);
643 File->seek(e.Offset);
644 File->read(pcData, decryptedSize);
645 }
646
647 // Setup the inflate stream.
648 z_stream stream;
649 s32 err;
650
651 stream.next_in = (Bytef*)pcData;
652 stream.avail_in = (uInt)decryptedSize;
653 stream.next_out = (Bytef*)pBuf;
654 stream.avail_out = uncompressedSize;
655 stream.zalloc = (alloc_func)0;
656 stream.zfree = (free_func)0;
657
658 // Perform inflation. wbits < 0 indicates no zlib header inside the data.
659 err = inflateInit2(&stream, -MAX_WBITS);
660 if (err == Z_OK)
661 {
662 err = inflate(&stream, Z_FINISH);
663 inflateEnd(&stream);
664 if (err == Z_STREAM_END)
665 err = Z_OK;
666 err = Z_OK;
667 inflateEnd(&stream);
668 }
669
670 if (decrypted)
671 decrypted->drop();
672 else
673 delete[] pcData;
674
675 if (err != Z_OK)
676 {
677 swprintf ( buf, 64, L"Error decompressing %s", Files[index].FullName.c_str() );
678 os::Printer::log( buf, ELL_ERROR);
679 delete [] pBuf;
680 return 0;
681 }
682 else
683 return io::createMemoryReadFile(pBuf, uncompressedSize, Files[index].FullName, true);
684
685 #else
686 return 0; // zlib not compiled, we cannot decompress the data.
687 #endif
688 }
689 case 12:
690 {
691 #ifdef _IRR_COMPILE_WITH_BZIP2_
692
693 const u32 uncompressedSize = e.header.DataDescriptor.UncompressedSize;
694 c8* pBuf = new c8[ uncompressedSize ];
695 if (!pBuf)
696 {
697 swprintf ( buf, 64, L"Not enough memory for decompressing %s", Files[index].FullName.c_str() );
698 os::Printer::log( buf, ELL_ERROR);
699 if (decrypted)
700 decrypted->drop();
701 return 0;
702 }
703
704 u8 *pcData = decryptedBuf;
705 if (!pcData)
706 {
707 pcData = new u8[decryptedSize];
708 if (!pcData)
709 {
710 swprintf ( buf, 64, L"Not enough memory for decompressing %s", Files[index].FullName.c_str() );
711 os::Printer::log( buf, ELL_ERROR);
712 delete [] pBuf;
713 return 0;
714 }
715
716 //memset(pcData, 0, decryptedSize);
717 File->seek(e.Offset);
718 File->read(pcData, decryptedSize);
719 }
720
721 bz_stream bz_ctx={0};
722 /* use BZIP2's default memory allocation
723 bz_ctx->bzalloc = NULL;
724 bz_ctx->bzfree = NULL;
725 bz_ctx->opaque = NULL;
726 */
727 int err = BZ2_bzDecompressInit(&bz_ctx, 0, 0); /* decompression */
728 if(err != BZ_OK)
729 {
730 os::Printer::log("bzip2 decompression failed. File cannot be read.", ELL_ERROR);
731 return 0;
732 }
733 bz_ctx.next_in = (char*)pcData;
734 bz_ctx.avail_in = decryptedSize;
735 /* pass all input to decompressor */
736 bz_ctx.next_out = pBuf;
737 bz_ctx.avail_out = uncompressedSize;
738 err = BZ2_bzDecompress(&bz_ctx);
739 err = BZ2_bzDecompressEnd(&bz_ctx);
740
741 if (decrypted)
742 decrypted->drop();
743 else
744 delete[] pcData;
745
746 if (err != BZ_OK)
747 {
748 swprintf ( buf, 64, L"Error decompressing %s", Files[index].FullName.c_str() );
749 os::Printer::log( buf, ELL_ERROR);
750 delete [] pBuf;
751 return 0;
752 }
753 else
754 return io::createMemoryReadFile(pBuf, uncompressedSize, Files[index].FullName, true);
755
756 #else
757 os::Printer::log("bzip2 decompression not supported. File cannot be read.", ELL_ERROR);
758 return 0;
759 #endif
760 }
761 case 14:
762 {
763 #ifdef _IRR_COMPILE_WITH_LZMA_
764
765 u32 uncompressedSize = e.header.DataDescriptor.UncompressedSize;
766 c8* pBuf = new c8[ uncompressedSize ];
767 if (!pBuf)
768 {
769 swprintf ( buf, 64, L"Not enough memory for decompressing %s", Files[index].FullName.c_str() );
770 os::Printer::log( buf, ELL_ERROR);
771 if (decrypted)
772 decrypted->drop();
773 return 0;
774 }
775
776 u8 *pcData = decryptedBuf;
777 if (!pcData)
778 {
779 pcData = new u8[decryptedSize];
780 if (!pcData)
781 {
782 swprintf ( buf, 64, L"Not enough memory for decompressing %s", Files[index].FullName.c_str() );
783 os::Printer::log( buf, ELL_ERROR);
784 delete [] pBuf;
785 return 0;
786 }
787
788 //memset(pcData, 0, decryptedSize);
789 File->seek(e.Offset);
790 File->read(pcData, decryptedSize);
791 }
792
793 ELzmaStatus status;
794 SizeT tmpDstSize = uncompressedSize;
795 SizeT tmpSrcSize = decryptedSize;
796
797 unsigned int propSize = (pcData[3]<<8)+pcData[2];
798 int err = LzmaDecode((Byte*)pBuf, &tmpDstSize,
799 pcData+4+propSize, &tmpSrcSize,
800 pcData+4, propSize,
801 e.header.GeneralBitFlag&0x1?LZMA_FINISH_END:LZMA_FINISH_ANY, &status,
802 &lzmaAlloc);
803 uncompressedSize = tmpDstSize; // may be different to expected value
804
805 if (decrypted)
806 decrypted->drop();
807 else
808 delete[] pcData;
809
810 if (err != SZ_OK)
811 {
812 os::Printer::log( "Error decompressing", Files[index].FullName, ELL_ERROR);
813 delete [] pBuf;
814 return 0;
815 }
816 else
817 return io::createMemoryReadFile(pBuf, uncompressedSize, Files[index].FullName, true);
818
819 #else
820 os::Printer::log("lzma decompression not supported. File cannot be read.", ELL_ERROR);
821 return 0;
822 #endif
823 }
824 case 99:
825 // If we come here with an encrypted file, decryption support is missing
826 os::Printer::log("Decryption support not enabled. File cannot be read.", ELL_ERROR);
827 return 0;
828 default:
829 swprintf ( buf, 64, L"file has unsupported compression method. %s", Files[index].FullName.c_str() );
830 os::Printer::log( buf, ELL_ERROR);
831 return 0;
832 };
833
834}
835
836} // end namespace io
837} // end namespace irr
838
839#endif // __IRR_COMPILE_WITH_ZIP_ARCHIVE_LOADER_