Esempio n. 1
0
        /// <summary>
        /// Inflates selected entry.
        /// </summary>
        /// <param name="entry">Entry to unpack.</param>
        /// <param name = "destfilepath">Destination file used instead of the temp file.</param>
        public void InflateEntry(Entry entry, string destfilepath = "")
        {
            if (entry.Length == 0)
            {
                return;                   //skip empty files
            }
            // Decompress Entry
            const int zHeader   = 0x78DA;
            uint      zChunkID  = entry.zIndexBegin;
            int       blockSize = (int)_header.BlockSizeAlloc;

            //bool isZlib = _header.CompressionMethod == 2053925218;
            if (destfilepath.Length > 0)
            {
                entry.Data = new FileStream(destfilepath, FileMode.Create, FileAccess.Write, FileShare.Read);
            }
            else
            {
                if (UseMemory)
                {
                    entry.Data = new MemoryStreamExtension();
                }
                else
                {
                    entry.Data = new TempFileStream();
                }
            }

            _reader.BaseStream.Position = (long)entry.Offset;

            do
            {
                // check for corrupt CDLC content and catch exceptions
                try
                {
                    if (_zBlocksSizeList[zChunkID] == 0U) // raw. full cluster used.
                    {
                        entry.Data.Write(_reader.ReadBytes(blockSize), 0, blockSize);
                    }
                    else
                    {
                        var num = _reader.ReadUInt16();
                        _reader.BaseStream.Position -= 2L;

                        var array = _reader.ReadBytes((int)_zBlocksSizeList[zChunkID]);
                        if (num == zHeader)
                        {
                            // compressed
                            try
                            {
                                RijndaelEncryptor.Unzip(array, entry.Data, false);
                            }
                            catch (Exception ex) //IOException
                            {
                                // corrupt CDLC zlib.net exception ... try to unpack
                                if (String.IsNullOrEmpty(entry.Name))
                                {
                                    Console.WriteLine(String.Format(@"CDLC contains a zlib exception.{1}Warning: {0}", ex.Message, Environment.NewLine));
                                }
                                else
                                {
                                    Console.WriteLine(String.Format(@"CDLC contains a broken datachunk in file '{0}'.{2}Warning Type 1: {1}", entry.Name.Split('/').Last(), ex.Message, Environment.NewLine));
                                }
                            }
                        }
                        else // raw. used only for data(chunks) smaller than 64 kb
                        {
                            entry.Data.Write(array, 0, array.Length);
                        }
                    }

                    zChunkID += 1;
                }
                catch (Exception ex) // index is outside the bounds of the array
                {
                    // corrupt CDLC data length ... try to unpack
                    Console.WriteLine(String.Format(@"CDLC contains a broken datachunk in file '{0}'.{2}Warning Type 2: {1}", entry.Name.Split('/').Last(), ex.Message, Environment.NewLine));
                    break;
                }
            } while (entry.Data.Length < (long)entry.Length);

            entry.Data.Seek(0, SeekOrigin.Begin);
            entry.Data.Flush();
        }
Esempio n. 2
0
        public void Read(Stream psarc, bool lazy = false)
        {
            _toc.Clear();
            _reader             = new BigEndianBinaryReader(psarc);
            _header.MagicNumber = _reader.ReadUInt32();

            if (_header.MagicNumber == 1347633490U)//PSAR (BE)
            {
                //Parse Header
                _header.VersionNumber     = _reader.ReadUInt32();
                _header.CompressionMethod = _reader.ReadUInt32();
                _header.TotalTOCSize      = _reader.ReadUInt32();
                _header.TOCEntrySize      = _reader.ReadUInt32();
                _header.NumFiles          = _reader.ReadUInt32();
                _header.BlockSizeAlloc    = _reader.ReadUInt32();
                _header.ArchiveFlags      = _reader.ReadUInt32();
                //Read TOC
                int tocSize = (int)(_header.TotalTOCSize - 32U);

                if (_header.ArchiveFlags == 4)//TOC_ENCRYPTED
                {
                    // Decrypt TOC
                    var tocStream = new MemoryStream();
                    using (var decStream = new MemoryStream())
                    {
                        RijndaelEncryptor.DecryptPSARC(psarc, decStream, _header.TotalTOCSize);

                        int bytesRead;
                        int decSize = 0;
                        var buffer  = new byte[_header.BlockSizeAlloc];
                        while ((bytesRead = decStream.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            decSize += bytesRead;
                            if (decSize > tocSize)
                            {
                                bytesRead = tocSize - (decSize - bytesRead);
                            }
                            tocStream.Write(buffer, 0, bytesRead);
                        }
                    }

                    tocStream.Position = 0;
                    _reader            = new BigEndianBinaryReader(tocStream);
                }

                ParseTOC();
                //Parse zBlocksSizeList
                int tocChunkSize = (int)(_header.NumFiles * _header.TOCEntrySize);//(int)_reader.BaseStream.Position //don't alter this with. causes issues
                int zNum         = (tocSize - tocChunkSize) / bNum;
                var zLengths     = new uint[zNum];

                for (int i = 0; i < zNum; i++)
                {
                    switch (bNum)
                    {
                    case 2:    //64KB
                        zLengths[i] = _reader.ReadUInt16();
                        break;

                    case 3:    //16MB
                        zLengths[i] = _reader.ReadUInt24();
                        break;

                    case 4:    //4GB
                        zLengths[i] = _reader.ReadUInt32();
                        break;
                    }
                }

                _zBlocksSizeList = zLengths; //TODO: validate
                _reader.BaseStream.Flush();  //Free tocStream resources
                _reader = new BigEndianBinaryReader(psarc);

                // Validate psarc size
                // if (psarc.Length < RequiredPsarcSize())
                // throw new InvalidDataException("Truncated psarc.");
                // try to unpack corrupt CDLC for now

                switch (_header.CompressionMethod)
                {
                case 2053925218:     //zlib (BE)
                    ReadManifest();
                    psarc.Seek(_header.TotalTOCSize, SeekOrigin.Begin);
                    if (!lazy)
                    {    // Decompress Data
                        InflateEntries();
                    }
                    break;

                case 1819962721:     //lzma (BE)
                    throw new NotImplementedException("LZMA compression not supported.");

                default:
                    throw new InvalidDataException("Unknown compression.");
                }
            }

            psarc.Flush();
        }