Beispiel #1
0
        private void Read(Stream input)
        {
            UInt32 magic = input.ReadValueU32();

            if (magic != 0x51890ACE && magic != 0xCE0A8951)
            {
                throw new FormatException("not a volition package");
            }

            this.LittleEndian = (magic == 0x51890ACE) ? true : false;
            this.Version      = input.ReadValueU32(this.LittleEndian);

            if (this.Version != 3 &&
                this.Version != 4 &&
                this.Version != 6)
            {
                throw new FormatException("unsupported volition package version");
            }

            input.Seek(-8, SeekOrigin.Current);

            IPackageFile packageFile = null;

            if (this.Version == 3)
            {
                packageFile = new Packages.PackageFile3();
            }
            else if (this.Version == 4)
            {
                packageFile = new Packages.PackageFile4();
            }
            else if (this.Version == 6)
            {
                packageFile = new Packages.PackageFile6();
            }
            else
            {
                throw new NotSupportedException();
            }

            packageFile.Deserialize(input, this.LittleEndian);

            this.Entries.Clear();
            this.OriginalEntries.Clear();

            if (packageFile.IsSolid == false)
            {
                foreach (Packages.PackageEntry packageEntry in packageFile.Entries)
                {
                    StreamEntry entry = new StreamEntry();
                    entry.Offset          = packageEntry.Offset;
                    entry.Size            = packageEntry.UncompressedSize;
                    entry.CompressedSize  = packageEntry.CompressedSize;
                    entry.CompressionType = packageEntry.CompressionType;

                    if (this.Entries.ContainsKey(packageEntry.Name) == false)
                    {
                        this.Entries.Add(packageEntry.Name, entry);
                    }
                    else
                    {
                        // Saints Row 1 seems to have bugged duplicate entries that point to
                        // different offsets with the same data.
                        this.Entries.Add(packageEntry.Name + "_DUPLICATE_" + packageEntry.Offset.ToString("X8"), entry);
                    }
                }
            }
            else
            {
                this.IsSolid = true;

                byte[] solid = new byte[packageFile.SolidUncompressedSize];

                input.Seek(packageFile.SolidOffset, SeekOrigin.Begin);

                // Decompress solid data
                var zlib = new InflaterInputStream(input);
                if (zlib.Read(solid, 0, solid.Length) != solid.Length)
                {
                    throw new InvalidOperationException("zlib error");
                }

                foreach (Packages.PackageEntry packageEntry in packageFile.Entries)
                {
                    var entry = new MemoryEntry();
                    entry.Data = new byte[packageEntry.UncompressedSize];
                    Array.Copy(solid, (int)packageEntry.Offset, entry.Data, 0, entry.Data.Length);
                    entry.Size = entry.Data.Length;
                    this.Entries.Add(packageEntry.Name, entry);
                }
            }
        }
Beispiel #2
0
        public void Commit(Packages.PackageCompressionType compressionType)
        {
            Stream clean;
            string tempFileName = Path.GetTempFileName();

            tempFileName = Path.GetTempFileName();
            clean        = File.Open(tempFileName, FileMode.Create, FileAccess.ReadWrite, FileShare.Read);

            IPackageFile packageFile = null;

            if (this.Version == 3)
            {
                packageFile = new Packages.PackageFile3();
            }
            else if (this.Version == 4)
            {
                packageFile = new Packages.PackageFile4();
            }
            else if (this.Version == 6)
            {
                packageFile = new Packages.PackageFile6();
            }
            else
            {
                throw new NotSupportedException();
            }

            foreach (KeyValuePair <string, Entry> kvp in this.Entries)
            {
                var packageEntry = new Packages.PackageEntry();
                packageEntry.Name             = kvp.Key;
                packageEntry.CompressedSize   = -1;
                packageEntry.UncompressedSize = kvp.Value.Size;
                packageEntry.Offset           = 0;
                packageFile.Entries.Add(packageEntry);
            }

            int headerSize = packageFile.EstimateHeaderSize();

            clean.Seek(headerSize, SeekOrigin.Begin);

            int uncompressedDataSize = 0;
            int compressedDataSize   = 0;

            if (compressionType == Packages.PackageCompressionType.None)
            {
                long offset = 0;
                foreach (Packages.PackageEntry packageEntry in packageFile.Entries)
                {
                    packageEntry.Offset = offset;

                    this.ExportEntry(packageEntry.Name, clean);

                    int align = packageEntry.UncompressedSize.Align(2048) - packageEntry.UncompressedSize;
                    if (align > 0)
                    {
                        byte[] block = new byte[align];
                        clean.Write(block, 0, (int)align);
                    }

                    offset += packageEntry.UncompressedSize + align;
                    uncompressedDataSize += packageEntry.UncompressedSize + align;
                }
            }
            else if (compressionType == Packages.PackageCompressionType.Zlib)
            {
                long offset = 0;
                foreach (Packages.PackageEntry packageEntry in packageFile.Entries)
                {
                    packageEntry.Offset = offset;

                    byte[] uncompressedData = this.GetEntry(packageEntry.Name);
                    using (var temp = new MemoryStream())
                    {
                        var zlib = new DeflaterOutputStream(temp);
                        zlib.Write(uncompressedData, 0, uncompressedData.Length);
                        zlib.Finish();

                        temp.Position = 0;
                        clean.WriteFromStream(temp, temp.Length);
                        packageEntry.CompressedSize = (int)temp.Length;

                        int align = packageEntry.CompressedSize.Align(2048) - packageEntry.CompressedSize;
                        if (align > 0)
                        {
                            byte[] block = new byte[align];
                            clean.Write(block, 0, (int)align);
                        }

                        offset += packageEntry.CompressedSize + align;
                        uncompressedDataSize += packageEntry.UncompressedSize;
                        compressedDataSize   += packageEntry.CompressedSize + align;
                    }
                }
            }
            else if (compressionType == Packages.PackageCompressionType.SolidZlib)
            {
                using (var compressed = new MemoryStream())
                {
                    var zlib = new DeflaterOutputStream(compressed, new Deflater(Deflater.DEFAULT_COMPRESSION));

                    long offset = 0;
                    foreach (Packages.PackageEntry packageEntry in packageFile.Entries)
                    {
                        packageEntry.Offset = offset;

                        this.ExportEntry(packageEntry.Name, zlib);

                        int align = packageEntry.UncompressedSize.Align(2048) - packageEntry.UncompressedSize;
                        if (align > 0)
                        {
                            byte[] block = new byte[align];
                            zlib.Write(block, 0, (int)align);
                        }

                        offset += packageEntry.UncompressedSize + align;
                        uncompressedDataSize += packageEntry.UncompressedSize + align;
                    }

                    zlib.Close();

                    compressed.Seek(0, SeekOrigin.Begin);
                    clean.WriteFromStream(compressed, compressed.Length);

                    compressedDataSize = (int)compressed.Length;
                }
            }
            else
            {
                throw new InvalidOperationException();
            }

            packageFile.PackageSize          = (int)clean.Length;
            packageFile.UncompressedDataSize = uncompressedDataSize;
            packageFile.CompressedDataSize   = compressedDataSize;

            clean.Seek(0, SeekOrigin.Begin);
            packageFile.Serialize(clean, this.LittleEndian, compressionType);

            // copy clean to real stream
            {
                this.Stream.Seek(0, SeekOrigin.Begin);
                clean.Seek(0, SeekOrigin.Begin);
                this.Stream.WriteFromStream(clean, clean.Length);
            }

            this.Stream.SetLength(clean.Length);
            clean.Close();

            if (tempFileName != null)
            {
                File.Delete(tempFileName);
            }

            this.Entries.Clear();
            this.OriginalEntries.Clear();

            foreach (Packages.PackageEntry entry in packageFile.Entries)
            {
                this.Entries.Add(entry.Name, new StreamEntry()
                {
                    Offset          = entry.Offset,
                    Size            = entry.UncompressedSize,
                    CompressedSize  = entry.CompressedSize,
                    CompressionType = entry.CompressionType,
                });
            }
        }