From 7028cbe09c688437910a25623098762bf0fa592d Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Mon, 28 Mar 2016 22:28:34 +1000 Subject: Move Irrlicht to src/others. --- .../irrlicht-1.8.1/source/Irrlicht/CZipReader.cpp | 839 +++++++++++++++++++++ 1 file changed, 839 insertions(+) create mode 100644 src/others/irrlicht-1.8.1/source/Irrlicht/CZipReader.cpp (limited to 'src/others/irrlicht-1.8.1/source/Irrlicht/CZipReader.cpp') diff --git a/src/others/irrlicht-1.8.1/source/Irrlicht/CZipReader.cpp b/src/others/irrlicht-1.8.1/source/Irrlicht/CZipReader.cpp new file mode 100644 index 0000000..be29f98 --- /dev/null +++ b/src/others/irrlicht-1.8.1/source/Irrlicht/CZipReader.cpp @@ -0,0 +1,839 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CZipReader.h" + +#include "os.h" + +// This method is used for error output from bzip2. +extern "C" void bz_internal_error(int errorCode) +{ + irr::os::Printer::log("Error in bzip2 handling", irr::core::stringc(errorCode), irr::ELL_ERROR); +} + +#ifdef __IRR_COMPILE_WITH_ZIP_ARCHIVE_LOADER_ + +#include "CFileList.h" +#include "CReadFile.h" +#include "coreutil.h" + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_ZLIB_ + #ifndef _IRR_USE_NON_SYSTEM_ZLIB_ + #include // use system lib + #else + #include "zlib/zlib.h" + #endif + + #ifdef _IRR_COMPILE_WITH_ZIP_ENCRYPTION_ + #include "aesGladman/fileenc.h" + #endif + #ifdef _IRR_COMPILE_WITH_BZIP2_ + #ifndef _IRR_USE_NON_SYSTEM_BZLIB_ + #include + #else + #include "bzip2/bzlib.h" + #endif + #endif + #ifdef _IRR_COMPILE_WITH_LZMA_ + #include "lzma/LzmaDec.h" + #endif +#endif + +namespace irr +{ +namespace io +{ + + +// ----------------------------------------------------------------------------- +// zip loader +// ----------------------------------------------------------------------------- + +//! Constructor +CArchiveLoaderZIP::CArchiveLoaderZIP(io::IFileSystem* fs) +: FileSystem(fs) +{ + #ifdef _DEBUG + setDebugName("CArchiveLoaderZIP"); + #endif +} + +//! returns true if the file maybe is able to be loaded by this class +bool CArchiveLoaderZIP::isALoadableFileFormat(const io::path& filename) const +{ + return core::hasFileExtension(filename, "zip", "pk3") || + core::hasFileExtension(filename, "gz", "tgz"); +} + +//! Check to see if the loader can create archives of this type. +bool CArchiveLoaderZIP::isALoadableFileFormat(E_FILE_ARCHIVE_TYPE fileType) const +{ + return (fileType == EFAT_ZIP || fileType == EFAT_GZIP); +} + + +//! Creates an archive from the filename +/** \param file File handle to check. +\return Pointer to newly created archive, or 0 upon error. */ +IFileArchive* CArchiveLoaderZIP::createArchive(const io::path& filename, bool ignoreCase, bool ignorePaths) const +{ + IFileArchive *archive = 0; + io::IReadFile* file = FileSystem->createAndOpenFile(filename); + + if (file) + { + archive = createArchive(file, ignoreCase, ignorePaths); + file->drop(); + } + + return archive; +} + +//! creates/loads an archive from the file. +//! \return Pointer to the created archive. Returns 0 if loading failed. +IFileArchive* CArchiveLoaderZIP::createArchive(io::IReadFile* file, bool ignoreCase, bool ignorePaths) const +{ + IFileArchive *archive = 0; + if (file) + { + file->seek(0); + + u16 sig; + file->read(&sig, 2); + +#ifdef __BIG_ENDIAN__ + sig = os::Byteswap::byteswap(sig); +#endif + + file->seek(0); + + bool isGZip = (sig == 0x8b1f); + + archive = new CZipReader(file, ignoreCase, ignorePaths, isGZip); + } + return archive; +} + +//! Check if the file might be loaded by this class +/** Check might look into the file. +\param file File handle to check. +\return True if file seems to be loadable. */ +bool CArchiveLoaderZIP::isALoadableFileFormat(io::IReadFile* file) const +{ + SZIPFileHeader header; + + file->read( &header.Sig, 4 ); +#ifdef __BIG_ENDIAN__ + header.Sig = os::Byteswap::byteswap(header.Sig); +#endif + + return header.Sig == 0x04034b50 || // ZIP + (header.Sig&0xffff) == 0x8b1f; // gzip +} + +// ----------------------------------------------------------------------------- +// zip archive +// ----------------------------------------------------------------------------- + +CZipReader::CZipReader(IReadFile* file, bool ignoreCase, bool ignorePaths, bool isGZip) + : CFileList((file ? file->getFileName() : io::path("")), ignoreCase, ignorePaths), File(file), IsGZip(isGZip) +{ + #ifdef _DEBUG + setDebugName("CZipReader"); + #endif + + if (File) + { + File->grab(); + + // load file entries + if (IsGZip) + while (scanGZipHeader()) { } + else + while (scanZipHeader()) { } + + sort(); + } +} + +CZipReader::~CZipReader() +{ + if (File) + File->drop(); +} + + +//! get the archive type +E_FILE_ARCHIVE_TYPE CZipReader::getType() const +{ + return IsGZip ? EFAT_GZIP : EFAT_ZIP; +} + +const IFileList* CZipReader::getFileList() const +{ + return this; +} + + +//! scans for a local header, returns false if there is no more local file header. +//! The gzip file format seems to think that there can be multiple files in a gzip file +//! but none +bool CZipReader::scanGZipHeader() +{ + SZipFileEntry entry; + entry.Offset = 0; + memset(&entry.header, 0, sizeof(SZIPFileHeader)); + + // read header + SGZIPMemberHeader header; + if (File->read(&header, sizeof(SGZIPMemberHeader)) == sizeof(SGZIPMemberHeader)) + { + +#ifdef __BIG_ENDIAN__ + header.sig = os::Byteswap::byteswap(header.sig); + header.time = os::Byteswap::byteswap(header.time); +#endif + + // check header value + if (header.sig != 0x8b1f) + return false; + + // now get the file info + if (header.flags & EGZF_EXTRA_FIELDS) + { + // read lenth of extra data + u16 dataLen; + + File->read(&dataLen, 2); + +#ifdef __BIG_ENDIAN__ + dataLen = os::Byteswap::byteswap(dataLen); +#endif + + // skip it + File->seek(dataLen, true); + } + + io::path ZipFileName = ""; + + if (header.flags & EGZF_FILE_NAME) + { + c8 c; + File->read(&c, 1); + while (c) + { + ZipFileName.append(c); + File->read(&c, 1); + } + } + else + { + // no file name? + ZipFileName = Path; + core::deletePathFromFilename(ZipFileName); + + // rename tgz to tar or remove gz extension + if (core::hasFileExtension(ZipFileName, "tgz")) + { + ZipFileName[ ZipFileName.size() - 2] = 'a'; + ZipFileName[ ZipFileName.size() - 1] = 'r'; + } + else if (core::hasFileExtension(ZipFileName, "gz")) + { + ZipFileName[ ZipFileName.size() - 3] = 0; + ZipFileName.validate(); + } + } + + if (header.flags & EGZF_COMMENT) + { + c8 c='a'; + while (c) + File->read(&c, 1); + } + + if (header.flags & EGZF_CRC16) + File->seek(2, true); + + // we are now at the start of the data blocks + entry.Offset = File->getPos(); + + entry.header.FilenameLength = ZipFileName.size(); + + entry.header.CompressionMethod = header.compressionMethod; + entry.header.DataDescriptor.CompressedSize = (File->getSize() - 8) - File->getPos(); + + // seek to file end + File->seek(entry.header.DataDescriptor.CompressedSize, true); + + // read CRC + File->read(&entry.header.DataDescriptor.CRC32, 4); + // read uncompressed size + File->read(&entry.header.DataDescriptor.UncompressedSize, 4); + +#ifdef __BIG_ENDIAN__ + entry.header.DataDescriptor.CRC32 = os::Byteswap::byteswap(entry.header.DataDescriptor.CRC32); + entry.header.DataDescriptor.UncompressedSize = os::Byteswap::byteswap(entry.header.DataDescriptor.UncompressedSize); +#endif + + // now we've filled all the fields, this is just a standard deflate block + addItem(ZipFileName, entry.Offset, entry.header.DataDescriptor.UncompressedSize, false, 0); + FileInfo.push_back(entry); + } + + // there's only one block of data in a gzip file + return false; +} + +//! scans for a local header, returns false if there is no more local file header. +bool CZipReader::scanZipHeader(bool ignoreGPBits) +{ + io::path ZipFileName = ""; + SZipFileEntry entry; + entry.Offset = 0; + memset(&entry.header, 0, sizeof(SZIPFileHeader)); + + File->read(&entry.header, sizeof(SZIPFileHeader)); + +#ifdef __BIG_ENDIAN__ + entry.header.Sig = os::Byteswap::byteswap(entry.header.Sig); + entry.header.VersionToExtract = os::Byteswap::byteswap(entry.header.VersionToExtract); + entry.header.GeneralBitFlag = os::Byteswap::byteswap(entry.header.GeneralBitFlag); + entry.header.CompressionMethod = os::Byteswap::byteswap(entry.header.CompressionMethod); + entry.header.LastModFileTime = os::Byteswap::byteswap(entry.header.LastModFileTime); + entry.header.LastModFileDate = os::Byteswap::byteswap(entry.header.LastModFileDate); + entry.header.DataDescriptor.CRC32 = os::Byteswap::byteswap(entry.header.DataDescriptor.CRC32); + entry.header.DataDescriptor.CompressedSize = os::Byteswap::byteswap(entry.header.DataDescriptor.CompressedSize); + entry.header.DataDescriptor.UncompressedSize = os::Byteswap::byteswap(entry.header.DataDescriptor.UncompressedSize); + entry.header.FilenameLength = os::Byteswap::byteswap(entry.header.FilenameLength); + entry.header.ExtraFieldLength = os::Byteswap::byteswap(entry.header.ExtraFieldLength); +#endif + + if (entry.header.Sig != 0x04034b50) + return false; // local file headers end here. + + // read filename + { + c8 *tmp = new c8 [ entry.header.FilenameLength + 2 ]; + File->read(tmp, entry.header.FilenameLength); + tmp[entry.header.FilenameLength] = 0; + ZipFileName = tmp; + delete [] tmp; + } + +#ifdef _IRR_COMPILE_WITH_ZIP_ENCRYPTION_ + // AES encryption + if ((entry.header.GeneralBitFlag & ZIP_FILE_ENCRYPTED) && (entry.header.CompressionMethod == 99)) + { + s16 restSize = entry.header.ExtraFieldLength; + SZipFileExtraHeader extraHeader; + while (restSize) + { + File->read(&extraHeader, sizeof(extraHeader)); +#ifdef __BIG_ENDIAN__ + extraHeader.ID = os::Byteswap::byteswap(extraHeader.ID); + extraHeader.Size = os::Byteswap::byteswap(extraHeader.Size); +#endif + restSize -= sizeof(extraHeader); + if (extraHeader.ID==(s16)0x9901) + { + SZipFileAESExtraData data; + File->read(&data, sizeof(data)); +#ifdef __BIG_ENDIAN__ + data.Version = os::Byteswap::byteswap(data.Version); + data.CompressionMode = os::Byteswap::byteswap(data.CompressionMode); +#endif + restSize -= sizeof(data); + if (data.Vendor[0]=='A' && data.Vendor[1]=='E') + { + // encode values into Sig + // AE-Version | Strength | ActualMode + entry.header.Sig = + ((data.Version & 0xff) << 24) | + (data.EncryptionStrength << 16) | + (data.CompressionMode); + File->seek(restSize, true); + break; + } + } + } + } + // move forward length of extra field. + else +#endif + if (entry.header.ExtraFieldLength) + File->seek(entry.header.ExtraFieldLength, true); + + // if bit 3 was set, use CentralDirectory for setup + if (!ignoreGPBits && entry.header.GeneralBitFlag & ZIP_INFO_IN_DATA_DESCRIPTOR) + { + SZIPFileCentralDirEnd dirEnd; + FileInfo.clear(); + Files.clear(); + // First place where the end record could be stored + File->seek(File->getSize()-22); + const char endID[] = {0x50, 0x4b, 0x05, 0x06, 0x0}; + char tmp[5]={'\0'}; + bool found=false; + // search for the end record ID + while (!found && File->getPos()>0) + { + int seek=8; + File->read(tmp, 4); + switch (tmp[0]) + { + case 0x50: + if (!strcmp(endID, tmp)) + { + seek=4; + found=true; + } + break; + case 0x4b: + seek=5; + break; + case 0x05: + seek=6; + break; + case 0x06: + seek=7; + break; + } + File->seek(-seek, true); + } + File->read(&dirEnd, sizeof(dirEnd)); +#ifdef __BIG_ENDIAN__ + dirEnd.NumberDisk = os::Byteswap::byteswap(dirEnd.NumberDisk); + dirEnd.NumberStart = os::Byteswap::byteswap(dirEnd.NumberStart); + dirEnd.TotalDisk = os::Byteswap::byteswap(dirEnd.TotalDisk); + dirEnd.TotalEntries = os::Byteswap::byteswap(dirEnd.TotalEntries); + dirEnd.Size = os::Byteswap::byteswap(dirEnd.Size); + dirEnd.Offset = os::Byteswap::byteswap(dirEnd.Offset); + dirEnd.CommentLength = os::Byteswap::byteswap(dirEnd.CommentLength); +#endif + FileInfo.reallocate(dirEnd.TotalEntries); + File->seek(dirEnd.Offset); + while (scanCentralDirectoryHeader()) { } + return false; + } + + // store position in file + entry.Offset = File->getPos(); + // move forward length of data + File->seek(entry.header.DataDescriptor.CompressedSize, true); + + #ifdef _DEBUG + //os::Debuginfo::print("added file from archive", ZipFileName.c_str()); + #endif + + addItem(ZipFileName, entry.Offset, entry.header.DataDescriptor.UncompressedSize, ZipFileName.lastChar()=='/', FileInfo.size()); + FileInfo.push_back(entry); + + return true; +} + + +//! scans for a local header, returns false if there is no more local file header. +bool CZipReader::scanCentralDirectoryHeader() +{ + io::path ZipFileName = ""; + SZIPFileCentralDirFileHeader entry; + File->read(&entry, sizeof(SZIPFileCentralDirFileHeader)); + +#ifdef __BIG_ENDIAN__ + entry.Sig = os::Byteswap::byteswap(entry.Sig); + entry.VersionMadeBy = os::Byteswap::byteswap(entry.VersionMadeBy); + entry.VersionToExtract = os::Byteswap::byteswap(entry.VersionToExtract); + entry.GeneralBitFlag = os::Byteswap::byteswap(entry.GeneralBitFlag); + entry.CompressionMethod = os::Byteswap::byteswap(entry.CompressionMethod); + entry.LastModFileTime = os::Byteswap::byteswap(entry.LastModFileTime); + entry.LastModFileDate = os::Byteswap::byteswap(entry.LastModFileDate); + entry.CRC32 = os::Byteswap::byteswap(entry.CRC32); + entry.CompressedSize = os::Byteswap::byteswap(entry.CompressedSize); + entry.UncompressedSize = os::Byteswap::byteswap(entry.UncompressedSize); + entry.FilenameLength = os::Byteswap::byteswap(entry.FilenameLength); + entry.ExtraFieldLength = os::Byteswap::byteswap(entry.ExtraFieldLength); + entry.FileCommentLength = os::Byteswap::byteswap(entry.FileCommentLength); + entry.DiskNumberStart = os::Byteswap::byteswap(entry.DiskNumberStart); + entry.InternalFileAttributes = os::Byteswap::byteswap(entry.InternalFileAttributes); + entry.ExternalFileAttributes = os::Byteswap::byteswap(entry.ExternalFileAttributes); + entry.RelativeOffsetOfLocalHeader = os::Byteswap::byteswap(entry.RelativeOffsetOfLocalHeader); +#endif + + if (entry.Sig != 0x02014b50) + return false; // central dir headers end here. + + const long pos = File->getPos(); + File->seek(entry.RelativeOffsetOfLocalHeader); + scanZipHeader(true); + File->seek(pos+entry.FilenameLength+entry.ExtraFieldLength+entry.FileCommentLength); + FileInfo.getLast().header.DataDescriptor.CompressedSize=entry.CompressedSize; + FileInfo.getLast().header.DataDescriptor.UncompressedSize=entry.UncompressedSize; + FileInfo.getLast().header.DataDescriptor.CRC32=entry.CRC32; + Files.getLast().Size=entry.UncompressedSize; + return true; +} + + +//! opens a file by file name +IReadFile* CZipReader::createAndOpenFile(const io::path& filename) +{ + s32 index = findFile(filename, false); + + if (index != -1) + return createAndOpenFile(index); + + return 0; +} + +#ifdef _IRR_COMPILE_WITH_LZMA_ +//! Used for LZMA decompression. The lib has no default memory management +namespace +{ + void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); } + void SzFree(void *p, void *address) { p = p; free(address); } + ISzAlloc lzmaAlloc = { SzAlloc, SzFree }; +} +#endif + +//! opens a file by index +IReadFile* CZipReader::createAndOpenFile(u32 index) +{ + // Irrlicht supports 0, 8, 12, 14, 99 + //0 - The file is stored (no compression) + //1 - The file is Shrunk + //2 - The file is Reduced with compression factor 1 + //3 - The file is Reduced with compression factor 2 + //4 - The file is Reduced with compression factor 3 + //5 - The file is Reduced with compression factor 4 + //6 - The file is Imploded + //7 - Reserved for Tokenizing compression algorithm + //8 - The file is Deflated + //9 - Reserved for enhanced Deflating + //10 - PKWARE Date Compression Library Imploding + //12 - bzip2 - Compression Method from libbz2, WinZip 10 + //14 - LZMA - Compression Method, WinZip 12 + //96 - Jpeg compression - Compression Method, WinZip 12 + //97 - WavPack - Compression Method, WinZip 11 + //98 - PPMd - Compression Method, WinZip 10 + //99 - AES encryption, WinZip 9 + + const SZipFileEntry &e = FileInfo[Files[index].ID]; + wchar_t buf[64]; + s16 actualCompressionMethod=e.header.CompressionMethod; + IReadFile* decrypted=0; + u8* decryptedBuf=0; + u32 decryptedSize=e.header.DataDescriptor.CompressedSize; +#ifdef _IRR_COMPILE_WITH_ZIP_ENCRYPTION_ + if ((e.header.GeneralBitFlag & ZIP_FILE_ENCRYPTED) && (e.header.CompressionMethod == 99)) + { + os::Printer::log("Reading encrypted file."); + u8 salt[16]={0}; + const u16 saltSize = (((e.header.Sig & 0x00ff0000) >>16)+1)*4; + File->seek(e.Offset); + File->read(salt, saltSize); + char pwVerification[2]; + char pwVerificationFile[2]; + File->read(pwVerification, 2); + fcrypt_ctx zctx; // the encryption context + int rc = fcrypt_init( + (e.header.Sig & 0x00ff0000) >>16, + (const unsigned char*)Password.c_str(), // the password + Password.size(), // number of bytes in password + salt, // the salt + (unsigned char*)pwVerificationFile, // on return contains password verifier + &zctx); // encryption context + if (strncmp(pwVerificationFile, pwVerification, 2)) + { + os::Printer::log("Wrong password"); + return 0; + } + decryptedSize= e.header.DataDescriptor.CompressedSize-saltSize-12; + decryptedBuf= new u8[decryptedSize]; + u32 c = 0; + while ((c+32768)<=decryptedSize) + { + File->read(decryptedBuf+c, 32768); + fcrypt_decrypt( + decryptedBuf+c, // pointer to the data to decrypt + 32768, // how many bytes to decrypt + &zctx); // decryption context + c+=32768; + } + File->read(decryptedBuf+c, decryptedSize-c); + fcrypt_decrypt( + decryptedBuf+c, // pointer to the data to decrypt + decryptedSize-c, // how many bytes to decrypt + &zctx); // decryption context + + char fileMAC[10]; + char resMAC[10]; + rc = fcrypt_end( + (unsigned char*)resMAC, // on return contains the authentication code + &zctx); // encryption context + if (rc != 10) + { + os::Printer::log("Error on encryption closing"); + delete [] decryptedBuf; + return 0; + } + File->read(fileMAC, 10); + if (strncmp(fileMAC, resMAC, 10)) + { + os::Printer::log("Error on encryption check"); + delete [] decryptedBuf; + return 0; + } + decrypted = io::createMemoryReadFile(decryptedBuf, decryptedSize, Files[index].FullName, true); + actualCompressionMethod = (e.header.Sig & 0xffff); +#if 0 + if ((e.header.Sig & 0xff000000)==0x01000000) + { + } + else if ((e.header.Sig & 0xff000000)==0x02000000) + { + } + else + { + os::Printer::log("Unknown encryption method"); + return 0; + } +#endif + } +#endif + switch(actualCompressionMethod) + { + case 0: // no compression + { + if (decrypted) + return decrypted; + else + return createLimitReadFile(Files[index].FullName, File, e.Offset, decryptedSize); + } + case 8: + { + #ifdef _IRR_COMPILE_WITH_ZLIB_ + + const u32 uncompressedSize = e.header.DataDescriptor.UncompressedSize; + c8* pBuf = new c8[ uncompressedSize ]; + if (!pBuf) + { + swprintf ( buf, 64, L"Not enough memory for decompressing %s", Files[index].FullName.c_str() ); + os::Printer::log( buf, ELL_ERROR); + if (decrypted) + decrypted->drop(); + return 0; + } + + u8 *pcData = decryptedBuf; + if (!pcData) + { + pcData = new u8[decryptedSize]; + if (!pcData) + { + swprintf ( buf, 64, L"Not enough memory for decompressing %s", Files[index].FullName.c_str() ); + os::Printer::log( buf, ELL_ERROR); + delete [] pBuf; + return 0; + } + + //memset(pcData, 0, decryptedSize); + File->seek(e.Offset); + File->read(pcData, decryptedSize); + } + + // Setup the inflate stream. + z_stream stream; + s32 err; + + stream.next_in = (Bytef*)pcData; + stream.avail_in = (uInt)decryptedSize; + stream.next_out = (Bytef*)pBuf; + stream.avail_out = uncompressedSize; + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + // Perform inflation. wbits < 0 indicates no zlib header inside the data. + err = inflateInit2(&stream, -MAX_WBITS); + if (err == Z_OK) + { + err = inflate(&stream, Z_FINISH); + inflateEnd(&stream); + if (err == Z_STREAM_END) + err = Z_OK; + err = Z_OK; + inflateEnd(&stream); + } + + if (decrypted) + decrypted->drop(); + else + delete[] pcData; + + if (err != Z_OK) + { + swprintf ( buf, 64, L"Error decompressing %s", Files[index].FullName.c_str() ); + os::Printer::log( buf, ELL_ERROR); + delete [] pBuf; + return 0; + } + else + return io::createMemoryReadFile(pBuf, uncompressedSize, Files[index].FullName, true); + + #else + return 0; // zlib not compiled, we cannot decompress the data. + #endif + } + case 12: + { + #ifdef _IRR_COMPILE_WITH_BZIP2_ + + const u32 uncompressedSize = e.header.DataDescriptor.UncompressedSize; + c8* pBuf = new c8[ uncompressedSize ]; + if (!pBuf) + { + swprintf ( buf, 64, L"Not enough memory for decompressing %s", Files[index].FullName.c_str() ); + os::Printer::log( buf, ELL_ERROR); + if (decrypted) + decrypted->drop(); + return 0; + } + + u8 *pcData = decryptedBuf; + if (!pcData) + { + pcData = new u8[decryptedSize]; + if (!pcData) + { + swprintf ( buf, 64, L"Not enough memory for decompressing %s", Files[index].FullName.c_str() ); + os::Printer::log( buf, ELL_ERROR); + delete [] pBuf; + return 0; + } + + //memset(pcData, 0, decryptedSize); + File->seek(e.Offset); + File->read(pcData, decryptedSize); + } + + bz_stream bz_ctx={0}; + /* use BZIP2's default memory allocation + bz_ctx->bzalloc = NULL; + bz_ctx->bzfree = NULL; + bz_ctx->opaque = NULL; + */ + int err = BZ2_bzDecompressInit(&bz_ctx, 0, 0); /* decompression */ + if(err != BZ_OK) + { + os::Printer::log("bzip2 decompression failed. File cannot be read.", ELL_ERROR); + return 0; + } + bz_ctx.next_in = (char*)pcData; + bz_ctx.avail_in = decryptedSize; + /* pass all input to decompressor */ + bz_ctx.next_out = pBuf; + bz_ctx.avail_out = uncompressedSize; + err = BZ2_bzDecompress(&bz_ctx); + err = BZ2_bzDecompressEnd(&bz_ctx); + + if (decrypted) + decrypted->drop(); + else + delete[] pcData; + + if (err != BZ_OK) + { + swprintf ( buf, 64, L"Error decompressing %s", Files[index].FullName.c_str() ); + os::Printer::log( buf, ELL_ERROR); + delete [] pBuf; + return 0; + } + else + return io::createMemoryReadFile(pBuf, uncompressedSize, Files[index].FullName, true); + + #else + os::Printer::log("bzip2 decompression not supported. File cannot be read.", ELL_ERROR); + return 0; + #endif + } + case 14: + { + #ifdef _IRR_COMPILE_WITH_LZMA_ + + u32 uncompressedSize = e.header.DataDescriptor.UncompressedSize; + c8* pBuf = new c8[ uncompressedSize ]; + if (!pBuf) + { + swprintf ( buf, 64, L"Not enough memory for decompressing %s", Files[index].FullName.c_str() ); + os::Printer::log( buf, ELL_ERROR); + if (decrypted) + decrypted->drop(); + return 0; + } + + u8 *pcData = decryptedBuf; + if (!pcData) + { + pcData = new u8[decryptedSize]; + if (!pcData) + { + swprintf ( buf, 64, L"Not enough memory for decompressing %s", Files[index].FullName.c_str() ); + os::Printer::log( buf, ELL_ERROR); + delete [] pBuf; + return 0; + } + + //memset(pcData, 0, decryptedSize); + File->seek(e.Offset); + File->read(pcData, decryptedSize); + } + + ELzmaStatus status; + SizeT tmpDstSize = uncompressedSize; + SizeT tmpSrcSize = decryptedSize; + + unsigned int propSize = (pcData[3]<<8)+pcData[2]; + int err = LzmaDecode((Byte*)pBuf, &tmpDstSize, + pcData+4+propSize, &tmpSrcSize, + pcData+4, propSize, + e.header.GeneralBitFlag&0x1?LZMA_FINISH_END:LZMA_FINISH_ANY, &status, + &lzmaAlloc); + uncompressedSize = tmpDstSize; // may be different to expected value + + if (decrypted) + decrypted->drop(); + else + delete[] pcData; + + if (err != SZ_OK) + { + os::Printer::log( "Error decompressing", Files[index].FullName, ELL_ERROR); + delete [] pBuf; + return 0; + } + else + return io::createMemoryReadFile(pBuf, uncompressedSize, Files[index].FullName, true); + + #else + os::Printer::log("lzma decompression not supported. File cannot be read.", ELL_ERROR); + return 0; + #endif + } + case 99: + // If we come here with an encrypted file, decryption support is missing + os::Printer::log("Decryption support not enabled. File cannot be read.", ELL_ERROR); + return 0; + default: + swprintf ( buf, 64, L"file has unsupported compression method. %s", Files[index].FullName.c_str() ); + os::Printer::log( buf, ELL_ERROR); + return 0; + }; + +} + +} // end namespace io +} // end namespace irr + +#endif // __IRR_COMPILE_WITH_ZIP_ARCHIVE_LOADER_ -- cgit v1.1