public void Deserialize(Stream input)
        {
            Endian endian;

            Package.HeaderV6 header;

            using (var data = input.ReadToMemoryStream(2048))
            {
                var magic = data.ReadValueU32(Endian.Little);
                if (magic != 0x51890ACE &&
                    magic.Swap() != 0x51890ACE)
                {
                    throw new FormatException("not a package file");
                }
                endian = magic == 0x51890ACE ? Endian.Little : Endian.Big;

                var version = data.ReadValueU32(endian);
                if (version != 6)
                {
                    throw new FormatException("unexpected package version (expected 6)");
                }

                header = new Package.HeaderV6();
                header.Deserialize(data, endian);
            }

            this.Entries.Clear();
            using (var directory = input.ReadToMemoryStream(header.DirectorySize.Align(2048)))
            {
                using (var names = input.ReadToMemoryStream(header.NamesSize.Align(2048)))
                {
                    for (int i = 0; i < header.DirectoryCount; i++)
                    {
                        var nameOffset = directory.ReadValueU32(endian);
                        directory.Seek(4, SeekOrigin.Current); // runtime offset
                        var offset           = directory.ReadValueU32(endian);
                        var uncompressedSize = directory.ReadValueU32(endian);
                        var compressedSize   = directory.ReadValueU32(endian);
                        directory.Seek(4, SeekOrigin.Current); // package pointer

                        names.Seek(nameOffset, SeekOrigin.Begin);
                        var name = names.ReadStringZ(Encoding.ASCII);

                        this.Entries.Add(new Package.Entry()
                        {
                            Name             = name,
                            Offset           = offset,
                            UncompressedSize = uncompressedSize,
                            CompressedSize   = compressedSize,
                        });
                    }
                }
            }

            this.Endian           = endian;
            this.Flags            = ConvertFlags(header.Flags);
            this.UncompressedSize = header.UncompressedSize;
            this.CompressedSize   = header.CompressedSize;
            this.DataOffset       = input.Position;
        }
Example #2
0
        public void Deserialize(Stream input, Endian endian)
        {
            var chunk = DataFormats.Chunk.Read(input, endian);

            if (chunk.Id != ChunkId || chunk.ChunkSize != chunk.DataSize)
            {
                throw new FormatException();
            }

            using (var data = input.ReadToMemoryStream(chunk.DataSize))
            {
                var basePosition = chunk.DataOffset;
                data.Position = basePosition;

                var index = new DataFormats.BigFileIndex();
                index.Deserialize(data, endian);

                if (index.TypeId != TypeId)
                {
                    throw new FormatException();
                }

                data.Position = index.EntriesOffset;
                var entries = DataFormats.BigFileIndex.ReadEntries(data, index.EntryCount, endian);

                this._Id        = index.TypeId;
                this._DebugName = index.DebugName;
                this._SortKey   = index.SortKey;
                this._Entries.Clear();
                this._Entries.AddRange(entries);
                this._BigFileName = index.BigFileName;
            }
        }
        public void Deserialize(Stream input)
        {
            var endian = this.Endian;

            this.Nodes.Clear();
            while (input.Position < input.Length)
            {
                if (CheckMagic(input) == false)
                {
                    throw new FormatException();
                }

                uint length = input.ReadValueU32(endian);
                if (input.Position + length > input.Length)
                {
                    throw new EndOfStreamException("object size greater than input size");
                }

                using (var memory = input.ReadToMemoryStream(length))
                {
                    this.Nodes.Add(this.DeserializeNode(memory));
                }
            }

            if (input.Position != input.Length)
            {
                throw new FormatException();
            }
        }
Example #4
0
        public static void Export(AdfFile adf, RuntimeTypeLibrary runtime, Stream input, XmlWriter writer)
        {
            writer.WriteStartDocument();
            writer.WriteStartElement("adf");

            if (adf.InstanceInfos.Count > 0)
            {
                writer.WriteStartElement("instances");

                foreach (var instanceInfo in adf.InstanceInfos)
                {
                    writer.WriteStartElement("instance");
                    writer.WriteAttributeString("root", instanceInfo.Name);

                    var typeDefinition = runtime.GetTypeDefinition(instanceInfo.TypeHash);
                    input.Position = instanceInfo.Offset;
                    using (var data = input.ReadToMemoryStream((int)instanceInfo.Size))
                    {
                        var exporter = new InstanceExporter(adf, runtime);
                        exporter.Write(typeDefinition, instanceInfo.Name, data, writer);
                    }

                    writer.WriteEndElement();
                }

                writer.WriteEndElement();
            }

            writer.WriteEndElement();
            writer.WriteEndDocument();
        }
Example #5
0
        public override void Deserialize(Stream input)
        {
            var dataType = input.ReadValueU32();
            var length   = input.ReadValueS32();

            this.GlobalVariableCount = input.ReadValueU32();

            var   codeStream = input.ReadToMemoryStream(length);
            ICode code;

            if (dataType == 1)
            {
                code = new SourceCode();
            }
            else if (dataType == 5)
            {
                code = new CompiledCode();
            }
            else
            {
                throw new InvalidOperationException();
            }

            code.Deserialize(codeStream);
            this.Code = code;
        }
        public void Deserialize(Stream input, Endian endian)
        {
            this._Items.Clear();

            while (input.Position < input.Length)
            {
                var chunk = DataFormats.Chunk.Read(input, endian);
                if (chunk.Id != this._ChunkId || chunk.ChunkSize != chunk.DataSize)
                {
                    throw new FormatException();
                }

                using (var data = input.ReadToMemoryStream(chunk.DataSize))
                {
                    data.Position = chunk.DataOffset;

                    var resource = new TResource();
                    resource.Deserialize(data, endian);

                    if (resource.TypeId != this._TypeId)
                    {
                        throw new FormatException();
                    }

                    var item = this.Export(resource, data, endian);
                    this._Items.Add(item);
                }
            }
        }
        public void Deserialize(Stream input)
        {
            var count1 = input.ReadValueU32(false);
            var unk1   = input.ReadValueU8();
            var data1  = input.ReadToMemoryStream(count1 * 4);

            var count2 = input.ReadValueU32(false);
            var unk2   = input.ReadValueU8();
            var data2  = input.ReadToMemoryStream(count2 * 4);

            var count3 = input.ReadValueU32(false);
            var count4 = input.ReadValueU32(false);

            var stringCount   = input.ReadValueU32(false);
            var stringOffsets = new uint[stringCount];

            for (uint i = 0; i < stringCount; i++)
            {
                stringOffsets[i] = input.ReadValueU32(false);
            }
            var stringSize = input.ReadValueU32(false);
            var stringData = input.ReadToMemoryStream(stringSize);

            var entryCount = input.ReadValueU32(false);

            this.Entries.Clear();
            for (uint i = 0; i < entryCount; i++)
            {
                var entry = new PackageMetadata.Entry();

                stringData.Seek(stringOffsets[input.ReadValueU32(false)], SeekOrigin.Begin);
                entry.DirectoryName = stringData.ReadStringZ(Encoding.ASCII);

                stringData.Seek(stringOffsets[input.ReadValueU32(false)], SeekOrigin.Begin);
                entry.FileName = stringData.ReadStringZ(Encoding.ASCII);

                entry.Unknown08 = input.ReadValueU32(false);
                entry.Unknown0C = input.ReadValueU32(false);
                entry.Unknown10 = input.ReadValueU32(false);

                this.Entries.Add(entry);
            }
        }
Example #8
0
        public void Deserialize(ushort version, Stream input, Endian endian)
        {
            this.NameHash = input.ReadValueU64(endian);
            this.Name     = input.ReadStringU16(endian);

            if (version >= 2)
            {
                input.ReadBytes(18);
            }

            var columnCount = input.ReadValueU16(endian);

            Unk1 = input.ReadValueU32(endian);
            Unk2 = input.ReadValueU32(endian);

            var rowSize  = input.ReadValueU32(endian);
            var rowCount = input.ReadValueU32(endian);
            var data     = input.ReadToMemoryStream((int)(rowSize * rowCount));

            Data = data.ReadBytes((int)data.Length);

            this.Columns = new List <Column>();
            for (uint i = 0; i < columnCount; i++)
            {
                this.Columns.Add(new Column()
                {
                    NameHash = input.ReadValueU32(endian),
                    Type     = (ColumnType)input.ReadValueU8(),
                    Unknown2 = input.ReadValueU8(),
                    Unknown3 = input.ReadValueU16(endian),
                });
            }

            this.Rows.Clear();
            for (uint i = 0; i < rowCount; i++)
            {
                var row = new Row();

                data.Seek(i * rowSize, SeekOrigin.Begin);
                foreach (var column in this.Columns)
                {
                    if ((byte)column.Type > 163)
                    {
                        throw new FormatException();
                    }

                    object DeserializedObject = column.DeserializeType(data, endian);
                    row.Values.Add(DeserializedObject);
                }

                this.Rows.Add(row);
            }
        }
Example #9
0
        public void Deserialize(Stream input)
        {
            var directoryCount = input.ReadValueS32();

            if (input.Position + (directoryCount * 8) > input.Length)
            {
                throw new EndOfStreamException();
            }

            // don't need to load this information for our uses :)

            /*
             * for (int i = 0; i < directoryCount; i++)
             * {
             *  var directoryId = input.ReadValueU32();
             *  var firstFileIndex = input.ReadValueU32();
             * }
             */
            input.Seek(directoryCount * 8, SeekOrigin.Current);

            var fileCount = input.ReadValueS32();

            if (input.Position + (fileCount * 12) > input.Length)
            {
                throw new EndOfStreamException();
            }

            byte[] fileData = new byte[fileCount * 12];
            input.Read(fileData, 0, fileData.Length);

            var directoryNameSize = input.ReadValueU32();
            var fileNameSize      = input.ReadValueU32();

            input.Seek(directoryNameSize, SeekOrigin.Current); // don't need to load directory names
            var fileNames = input.ReadToMemoryStream(fileNameSize);

            this.Entries.Clear();
            for (int i = 0; i < fileCount; i++)
            {
                if (fileNames.Position >= fileNames.Length)
                {
                    throw new EndOfStreamException();
                }

                this.Entries.Add(new Entry()
                {
                    Path   = fileNames.ReadStringZ().Replace('/', '\\'),
                    Offset = BitConverter.ToUInt32(fileData, (i * 12) + 0),
                    Size   = BitConverter.ToUInt32(fileData, (i * 12) + 4),
                });
            }
        }
Example #10
0
        private MemoryStream ReadAlignedBlock(Stream input)
        {
            uint tableLength   = input.ReadValueU32();
            uint alignedLength = tableLength.Align(16);

            var memory = input.ReadToMemoryStream(tableLength);

            if (alignedLength != tableLength)
            {
                input.Seek(alignedLength - tableLength, SeekOrigin.Current);
            }

            return(memory);
        }
Example #11
0
        public object ParseEntry(DataFormat.Entry entry, Stream input)
        {
            var definition = this.FindDefinition(entry.TypeHash);

            if (definition == null)
            {
                throw new InvalidOperationException("missing definition " + entry.TypeHash.ToString("X8"));
            }

            input.Seek(entry.Offset, SeekOrigin.Begin);
            using (MemoryStream data = input.ReadToMemoryStream(entry.Size))
            {
                return(this.ParseDefinition(0, definition, data));
            }
        }
Example #12
0
        public static void DeserializeTable(ParseSchema.Table table, Stream input, XmlWriter output)
        {
            //output.Flush();

            var dataSize = input.ReadValueU32();

            using (var data = input.ReadToMemoryStream((int)dataSize))
            {
                /*
                 * Counter++;
                 * using (var temp = File.Create(string.Format("{0}.struct", Counter)))
                 * {
                 *  temp.WriteFromStream(data, data.Length);
                 *  data.Position = 0;
                 * }
                 */

                output.WriteStartElement("table");

                foreach (var column in table.Columns)
                {
                    if (column.Flags.HasAny(
                            Parse.ColumnFlags.REDUNDANTNAME |
                            Parse.ColumnFlags.UNOWNED |
                            Parse.ColumnFlags.NO_WRITE) == true)
                    {
                        continue;
                    }

                    //output.WriteComment(string.Format(" offset = {0} ", data.Position));
                    output.WriteStartElement("column");
                    output.WriteAttributeString("name", column.Name);
                    DeserializeColumn(column, data, output);
                    output.WriteEndElement();
                    //output.Flush();
                }

                output.WriteEndElement();

                if (data.Position != data.Length)
                {
                    throw new InvalidOperationException();
                }
            }

            //output.Flush();
        }
Example #13
0
        private static void ReadFileData(
            HogFile hog,
            Hog.FileEntry entry,
            Stream input,
            Stream output)
        {
            if (hog.Files.Contains(entry) == false)
            {
                throw new ArgumentException("bad entry", "entry");
            }

            if (entry.Size == -1)
            {
                throw new ArgumentException("cannot read file with size of -1", "entry");
            }

            if (entry.Unknown5 != -2 || entry.AttributeId == -1)
            {
                throw new ArgumentException("strange entry");
            }

            if (entry.AttributeId < 0 || entry.AttributeId >= hog.Attributes.Count)
            {
                throw new ArgumentException("entry pointing to invalid metadata", "entry");
            }

            if ((hog.Attributes[entry.AttributeId].Flags & 1) == 1) // entry is unused
            {
                throw new ArgumentException("entry referencing unused attribute", "entry");
            }

            input.Seek(entry.Offset, SeekOrigin.Begin);
            var attribute = hog.Attributes[entry.AttributeId];

            if (attribute.UncompressedSize != 0)
            {
                using (var temp = input.ReadToMemoryStream(entry.Size))
                {
                    var zlib = new InflaterInputStream(temp);
                    output.WriteFromStream(zlib, attribute.UncompressedSize);
                }
            }
            else
            {
                output.WriteFromStream(input, entry.Size);
            }
        }
Example #14
0
        public void Deserialize(Stream input)
        {
            uint length = input.ReadValueU32();

            if (input.Position + length > input.Length)
            {
                throw new InvalidOperationException();
            }

            uint count  = input.ReadValueU32();
            var  memory = input.ReadToMemoryStream(length);

            this.Entries = new List <string>();
            for (uint i = 0; i < count; i++)
            {
                this.Entries.Add(memory.ReadStringGame(64, true));
            }
        }
        public void Deserialize(Stream input, int length)
        {
            if (input == null)
            {
                throw new ArgumentNullException("input");
            }

            if (length < 0 ||
                input.Position + length > input.Length)
            {
                throw new ArgumentOutOfRangeException("length");
            }

            var endian = this.Endian;

            var end = input.Position + length;

            this.Nodes.Clear();
            while (input.Position < end)
            {
                if (CheckMagic(input) == false)
                {
                    throw new FormatException();
                }

                uint objectLength = input.ReadValueU32(endian);
                if (input.Position + objectLength > input.Length)
                {
                    throw new EndOfStreamException("object size greater than input size");
                }

                using (var memory = input.ReadToMemoryStream(objectLength))
                {
                    this.Nodes.Add(this.DeserializeNode(memory));
                }
            }

            if (input.Position != end)
            {
                throw new FormatException();
            }
        }
Example #16
0
        public void Deserialize(Stream input)
        {
            var endian = this.Endian;

            var unknown = input.ReadValueU32(endian);
            var size1   = input.ReadValueU32(endian);
            var size2   = input.ReadValueU32(endian);

            if (unknown != 0 ||
                size1 != size2)
            {
                throw new FormatException();
            }

            this.Entries.Clear();
            using (var data = input.ReadToMemoryStream((int)size1))
            {
                while (data.Position < data.Length)
                {
                    // ReSharper disable UseObjectOrCollectionInitializer
                    var entry = new Journal.Entry();
                    // ReSharper restore UseObjectOrCollectionInitializer
                    entry.Action   = data.ReadValueEnum <Journal.Action>();
                    entry.TargetId = data.ReadValueS32(endian);

                    if (entry.Action == Journal.Action.Add)
                    {
                        var length = data.ReadValueU32(endian);
                        entry.Data = data.ReadBytes((int)length);
                    }
                    else if (entry.Action == Journal.Action.Remove)
                    {
                    }
                    else
                    {
                        throw new FormatException();
                    }

                    this.Entries.Add(entry);
                }
            }
        }
Example #17
0
        public void Deserialize(Stream input)
        {
            uint length = input.ReadValueU32();

            if (input.Position + length > input.Length)
            {
                throw new InvalidOperationException();
            }

            uint count  = input.ReadValueU32();
            var  memory = input.ReadToMemoryStream(length);

            this.Entries = new List <Entry>();
            for (uint i = 0; i < count; i++)
            {
                var entry = new Entry();
                entry.Deserialize(memory);
                this.Entries.Add(entry);
            }
        }
Example #18
0
        public void Deserialize(Stream input)
        {
            uint magic = input.ReadValueU32();

            if (magic != 4 && magic.Swap() != 4)
            {
                throw new FormatException("bad header size");
            }
            var endian = magic == 4 ? Endian.Little : Endian.Big;

            var tag = input.ReadString(4, Encoding.ASCII);

            if (tag != "SARC")
            {
                throw new FormatException("bad header magic");
            }

            var version = input.ReadValueU32(endian);

            if (version != 2)
            {
                throw new FormatException("bad header version");
            }

            var indexSize = input.ReadValueU32(endian);

            var entries = new List <Entry>();

            using (var index = input.ReadToMemoryStream((int)indexSize))
            {
                while (index.Length - index.Position > 15)
                {
                    entries.Add(Entry.Read(index, endian));
                }
            }

            this._Endian = endian;
            this._Entries.Clear();
            this._Entries.AddRange(entries);
        }
        public void Deserialize(Stream input)
        {
            uint magicSize = input.ReadValueU32();

            if (magicSize != 4 && magicSize.Swap() != 4)
            {
                throw new FormatException("bad header size");
            }

            var endian = magicSize == 4
                             ? Endian.Little
                             : Endian.Big;

            if (input.ReadString(4, Encoding.ASCII) != "SARC")
            {
                throw new FormatException("bad header magic");
            }

            uint version = input.ReadValueU32(endian);

            if (version != 1 && version != 2)
            {
                throw new FormatException("bad header version");
            }

            using (var index = input.ReadToMemoryStream(input.ReadValueU32(endian)))
            {
                this.Entries = new List <Entry>();
                while (index.Length - index.Position > 15)
                {
                    var entry = new Entry();
                    entry.Deserialize(index, endian);
                    this.Entries.Add(entry);
                }
            }

            this.Endian = endian;
        }
        public void Deserialize(Stream input, Endian endian)
        {
            var count = input.ReadValueU32(endian);
            var size  = input.ReadValueU32(endian);

            var offsets = new uint[count];

            for (uint i = 0; i < count; i++)
            {
                offsets[i] = input.ReadValueU32(endian);
            }

            var encoding = Encoding.GetEncoding(1252);

            this.Strings.Clear();
            using (var data = input.ReadToMemoryStream(size))
            {
                for (uint i = 0; i < count; i++)
                {
                    data.Seek(offsets[i], SeekOrigin.Begin);
                    this.Strings.Add(data.ReadStringZ(encoding));
                }
            }
        }
Example #21
0
        public static void Main(string[] args)
        {
            bool   showHelp        = false;
            bool?  extractUnknowns = null;
            bool   overwriteFiles  = false;
            bool   verbose         = true;
            string currentProject  = null;
            string filterPattern   = null;

            var options = new OptionSet()
            {
                { "o|overwrite", "overwrite existing files", v => overwriteFiles = v != null },
                {
                    "nu|no-unknowns", "don't extract unknown files",
                    v => extractUnknowns = v != null ? false : extractUnknowns
                },
                {
                    "ou|only-unknowns", "only extract unknown files",
                    v => extractUnknowns = v != null ? true : extractUnknowns
                },
                { "f|filter=", "filter files using pattern", v => filterPattern = v },
                { "v|verbose", "be verbose", v => verbose = v != null },
                { "h|help", "show this message and exit", v => showHelp = v != null },
                { "p|project=", "override current project", v => currentProject = v },
            };

            List <string> extras;

            try
            {
                extras = options.Parse(args);
            }
            catch (OptionException e)
            {
                Console.Write("{0}: ", GetExecutableName());
                Console.WriteLine(e.Message);
                Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName());
                return;
            }

            if (extras.Count < 1 ||
                extras.Count > 2 ||
                showHelp == true ||
                Is000(extras[0]) == false)
            {
                Console.WriteLine("Usage: {0} [OPTIONS]+ input_file.000 [output_dir]", GetExecutableName());
                Console.WriteLine();
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }

            var inputPath  = extras[0];
            var outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(inputPath, null) + "_unpack";

            Regex filter = null;

            if (string.IsNullOrEmpty(filterPattern) == false)
            {
                filter = new Regex(filterPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
            }

            string bigPathSuffix;
            var    bigPathBase = GetBasePath(inputPath, out bigPathSuffix);

            var manager = ProjectData.Manager.Load(currentProject);

            if (manager.ActiveProject == null)
            {
                Console.WriteLine("Warning: no active project loaded.");
            }

            var big = new BigArchiveFileV1
            {
                Endian        = manager.GetSetting("archive_endianness", Endian.Little),
                DataAlignment = manager.GetSetting <uint>("archive_alignment", 0x7FF00000),
            };
            var compressionType = manager.GetSetting("archive_compression_type", CompressionType.None);

            using (var input = File.OpenRead(inputPath))
            {
                big.Deserialize(input);
            }

            if (big.Entries.Any(e => e.CompressedSize != 0) == true &&
                compressionType == CompressionType.None)
            {
                throw new InvalidOperationException("compressed entries not supported");
            }

            var hashes = manager.LoadLists("*.filelist",
                                           s => s.HashFileName(),
                                           s => s.ToLowerInvariant());

            Directory.CreateDirectory(outputPath);

            var settings = new XmlWriterSettings()
            {
                Indent = true,
            };

            using (var xml = XmlWriter.Create(
                       Path.Combine(outputPath, "bigfile.xml"),
                       settings))
            {
                xml.WriteStartDocument();
                xml.WriteStartElement("files");
                xml.WriteAttributeString("endian", big.Endian.ToString().ToLowerInvariant());
                xml.WriteAttributeString("alignment", big.DataAlignment.ToString("X8"));

                Stream data             = null;
                uint?  currentBigFile   = null;
                uint?  lastLocale       = null;
                var    maxBlocksPerFile = big.DataAlignment / 2048;
                {
                    long current = 0;
                    long total   = big.Entries.Count;

                    foreach (var entry in big.Entries.OrderBy(e => e.Offset))
                    {
                        current++;

                        var entryBigFile = entry.Offset / maxBlocksPerFile;
                        var entryOffset  = (entry.Offset % maxBlocksPerFile) * 2048;

                        if (currentBigFile.HasValue == false ||
                            currentBigFile.Value != entryBigFile)
                        {
                            if (data != null)
                            {
                                data.Close();
                            }

                            currentBigFile = entryBigFile;

                            var bigPath = string.Format("{0}.{1}{2}",
                                                        bigPathBase,
                                                        currentBigFile.Value.ToString(CultureInfo.InvariantCulture)
                                                        .PadLeft(3, '0'),
                                                        bigPathSuffix);

                            if (verbose == true)
                            {
                                Console.WriteLine(bigPath);
                            }

                            data = File.OpenRead(bigPath);
                        }

                        string name = hashes[entry.NameHash];
                        if (name == null)
                        {
                            if (extractUnknowns.HasValue == true &&
                                extractUnknowns.Value == false)
                            {
                                continue;
                            }

                            string extension;
                            // detect type
                            {
                                var guess = new byte[64];
                                int read  = 0;

                                if (entry.UncompressedSize > 0)
                                {
                                    if (entry.CompressedSize != 0)
                                    {
                                        data.Seek(entryOffset, SeekOrigin.Begin);

                                        if (compressionType == CompressionType.Zlib)
                                        {
                                            var zlib = new InflaterInputStream(data);
                                            read = zlib.Read(guess,
                                                             0,
                                                             (int)Math.Min(
                                                                 entry.UncompressedSize,
                                                                 guess.Length));
                                        }
                                        else
                                        {
                                            throw new NotSupportedException();
                                        }
                                    }
                                    else
                                    {
                                        data.Seek(entryOffset, SeekOrigin.Begin);
                                        read = data.Read(guess,
                                                         0,
                                                         (int)Math.Min(
                                                             entry.UncompressedSize,
                                                             guess.Length));
                                    }
                                }

                                extension = FileExtensions.Detect(
                                    guess,
                                    Math.Min(guess.Length, read));
                            }

                            name = entry.NameHash.ToString("X8");
                            name = Path.ChangeExtension(name, "." + extension);
                            name = Path.Combine(extension, name);
                            name = Path.Combine("__UNKNOWN", name);
                        }
                        else
                        {
                            if (extractUnknowns.HasValue == true &&
                                extractUnknowns.Value == true)
                            {
                                continue;
                            }

                            name = name.Replace("/", "\\");
                            if (name.StartsWith("\\") == true)
                            {
                                name = name.Substring(1);
                            }
                        }

                        if (entry.Locale == 0xFFFFFFFF)
                        {
                            name = Path.Combine("default", name);
                        }
                        else
                        {
                            name = Path.Combine(entry.Locale.ToString("X8"), name);
                        }

                        if (filter != null &&
                            filter.IsMatch(name) == false)
                        {
                            continue;
                        }

                        var entryPath = Path.Combine(outputPath, name);

                        var entryParentPath = Path.GetDirectoryName(entryPath);
                        if (string.IsNullOrEmpty(entryParentPath) == false)
                        {
                            Directory.CreateDirectory(entryParentPath);
                        }

                        if (lastLocale.HasValue == false ||
                            lastLocale.Value != entry.Locale)
                        {
                            xml.WriteComment(string.Format(" {0} = {1} ",
                                                           entry.Locale.ToString("X8"),
                                                           ((ArchiveLocale)entry.Locale)));
                            lastLocale = entry.Locale;
                        }

                        xml.WriteStartElement("entry");
                        xml.WriteAttributeString("hash", entry.NameHash.ToString("X8"));
                        xml.WriteAttributeString("locale", entry.Locale.ToString("X8"));
                        xml.WriteValue(name);
                        xml.WriteEndElement();

                        if (overwriteFiles == false &&
                            File.Exists(entryPath) == true)
                        {
                            continue;
                        }

                        if (verbose == true)
                        {
                            Console.WriteLine("[{0}/{1}] {2}",
                                              current,
                                              total,
                                              name);
                        }

                        using (var output = File.Create(entryPath))
                        {
                            if (entry.UncompressedSize > 0)
                            {
                                if (entry.CompressedSize != 0)
                                {
                                    data.Seek(entryOffset, SeekOrigin.Begin);

                                    if (compressionType == CompressionType.Zlib)
                                    {
                                        using (var temp = data.ReadToMemoryStream((int)entry.CompressedSize))
                                        {
                                            var zlib = new InflaterInputStream(temp);
                                            output.WriteFromStream(zlib, entry.UncompressedSize);
                                        }
                                    }
                                    else
                                    {
                                        throw new NotSupportedException();
                                    }
                                }
                                else
                                {
                                    data.Seek(entryOffset, SeekOrigin.Begin);
                                    output.WriteFromStream(data, entry.UncompressedSize);
                                }
                            }
                        }
                    }
                }

                if (data != null)
                {
                    data.Close();
                }

                xml.WriteEndElement();
                xml.WriteEndDocument();
                xml.Flush();
            }
        }
        public void Deserialize(Stream input)
        {
            var magic = input.ReadValueU32(Endian.Little);

            if (magic != 0x666D726D && // fmrm
                magic.Swap() != 0x666D726D)
            {
                throw new FormatException();
            }
            var endian = magic == 0x666D726D ? Endian.Little : Endian.Big;

            var version = input.ReadValueU32(endian);

            if (version != 1)
            {
                throw new FormatException();
            }
            this.Version = version;

            /*var maxKeyLength =*/ input.ReadValueS32(endian);
            var maxValueLength = input.ReadValueS32(endian);

            var stringTableSize = input.ReadValueU32(endian);
            var huffmanSize     = input.ReadValueU32(endian);
            var indexSize       = input.ReadValueU32(endian);
            var dataSize        = input.ReadValueU32(endian);

            var strings = new List <KeyValuePair <uint, string> >();

            using (var data = input.ReadToMemoryStream(stringTableSize))
            {
                var localStringTableSize = data.ReadValueU32(endian);
                if (localStringTableSize != stringTableSize)
                {
                    throw new FormatException();
                }

                var count = data.ReadValueU32(endian);

                var offsets = new List <KeyValuePair <uint, uint> >();
                for (uint i = 0; i < count; i++)
                {
                    var hash   = data.ReadValueU32(endian);
                    var offset = data.ReadValueU32(endian);
                    offsets.Add(new KeyValuePair <uint, uint>(hash, offset));
                }

                foreach (var kv in offsets)
                {
                    var hash   = kv.Key;
                    var offset = kv.Value;

                    data.Seek(8 + offset, SeekOrigin.Begin);
                    var length = data.ReadValueU16(endian);
                    var text   = data.ReadString(length, Encoding.UTF8);

                    if (text.HashCrc32() != hash)
                    {
                        throw new InvalidOperationException();
                    }

                    strings.Add(new KeyValuePair <uint, string>(hash, text));
                }
            }

            Huffman.Pair[] huffmanTree;
            using (var data = input.ReadToMemoryStream(huffmanSize))
            {
                var count = data.ReadValueU16(endian);
                huffmanTree = new Huffman.Pair[count];
                for (ushort i = 0; i < count; i++)
                {
                    var left  = data.ReadValueS32(endian);
                    var right = data.ReadValueS32(endian);
                    huffmanTree[i] = new Huffman.Pair(left, right);
                }
            }

            using (var index = input.ReadToMemoryStream(indexSize))
            {
                var totalBits = input.ReadValueS32(endian);
                var data      = input.ReadBytes(dataSize);
                var bitArray  = new BitArray(data)
                {
                    Length = totalBits
                };

                var files     = new List <KeyValuePair <string, uint> >();
                var fileCount = index.ReadValueU16(endian);
                for (ushort i = 0; i < fileCount; i++)
                {
                    var nameIndex = index.ReadValueU16(endian);
                    var name      = strings[nameIndex].Value;
                    var offset    = index.ReadValueU32(endian);
                    files.Add(new KeyValuePair <string, uint>(name, offset));
                }

                foreach (var fileInfo in files.OrderBy(f => f.Key))
                {
                    var file = new Coalesced.File()
                    {
                        Name = fileInfo.Key
                    };

                    index.Seek(fileInfo.Value, SeekOrigin.Begin);
                    var sectionCount = index.ReadValueU16(endian);
                    var sections     = new List <KeyValuePair <string, uint> >();
                    for (ushort i = 0; i < sectionCount; i++)
                    {
                        var nameIndex = index.ReadValueU16(endian);
                        var name      = strings[nameIndex].Value;
                        var offset    = index.ReadValueU32(endian);
                        sections.Add(new KeyValuePair <string, uint>(name, offset));
                    }

                    foreach (var sectionInfo in sections.OrderBy(s => s.Key))
                    {
                        var section = new Dictionary <string, List <string> >();

                        index.Seek(fileInfo.Value + sectionInfo.Value, SeekOrigin.Begin);
                        var valueCount = index.ReadValueU16(endian);
                        var values     = new List <KeyValuePair <string, uint> >();
                        for (ushort i = 0; i < valueCount; i++)
                        {
                            var nameIndex = index.ReadValueU16(endian);
                            var name      = strings[nameIndex].Value;
                            var offset    = index.ReadValueU32(endian);
                            values.Add(new KeyValuePair <string, uint>(name, offset));
                        }

                        foreach (var valueInfo in values.OrderBy(v => v.Key))
                        {
                            var value = new List <string>();

                            index.Seek(fileInfo.Value + sectionInfo.Value + valueInfo.Value, SeekOrigin.Begin);
                            var itemCount = index.ReadValueU16(endian);

                            for (ushort i = 0; i < itemCount; i++)
                            {
                                var offset = index.ReadValueS32(endian);

                                var type = (offset & 0xE0000000) >> 29;
                                if (type == 1)
                                {
                                    value.Add(null);
                                }
                                else if (type == 2)
                                {
                                    offset &= 0x1FFFFFFF;
                                    var text = Huffman.Decoder.Decode(
                                        huffmanTree, bitArray, offset, maxValueLength);
                                    value.Add(text);
                                }

                                /*else if (type == 0 || type == 3)
                                 * {
                                 *  offset &= 0x1FFFFFFF;
                                 *  var text = Huffman.Decoder.Decode(
                                 *      huffmanTree, bitArray, offset, maxValueLength);
                                 *  value.Add("<<wtf" + type.ToString() + ">>" + text);
                                 * }*/
                                else
                                {
                                    throw new NotImplementedException();
                                }
                            }

                            section.Add(valueInfo.Key, value);
                        }

                        file.Sections.Add(sectionInfo.Key, section);
                    }

                    this.Files.Add(file);
                }
            }

            this.Endian = endian;
        }
Example #23
0
 public static MemoryStream ReadToMemoryStream(this Stream stream, long size)
 {
     return(stream.ReadToMemoryStream(size, 0x40000));
 }
Example #24
0
        public void Deserialize(Stream input)
        {
            var magic = input.ReadString(8, Encoding.ASCII);
            if (magic != _FileSignature)
            {
                throw new FormatException("invalid blob magic");
            }

            this.ParserHash = input.ReadValueU32();

            var flags = input.ReadValueU32();
            if (flags != 1)
            {
                throw new FormatException();
            }

            var type = input.ReadStringPascal(4096);
            if (type != _TypeSignature)
            {
                throw new FormatException("invalid blob type");
            }
            this.Type = type;

            var filesTag = input.ReadStringPascal(20);
            if (filesTag != "Files1")
            {
                throw new FormatException("invalid blob files tag");
            }

            var fileInfoSize = input.ReadValueU32();
            this.Files.Clear();
            using (var data = input.ReadToMemoryStream((int)fileInfoSize))
            {
                var count = data.ReadValueU32();
                for (uint i = 0; i < count; i++)
                {
                    // ReSharper disable UseObjectOrCollectionInitializer
                    var entry = new Blob.FileEntry();
                    // ReSharper restore UseObjectOrCollectionInitializer
                    entry.Name = data.ReadStringPascal(260);
                    entry.Timestamp = data.ReadValueU32();
                    this.Files.Add(entry);
                }

                if (data.Position != data.Length)
                {
                    throw new FormatException("did not read blob file entry correctly");
                }
            }

            var extraFilesTag = input.ReadStringPascal(20);
            if (extraFilesTag != "Files1")
            {
                throw new FormatException("invalid blob extra files tag");
            }

            var extraFileInfoSize = input.ReadValueU32();
            using (var data = input.ReadToMemoryStream((int)extraFileInfoSize))
            {
                var count = data.ReadValueU32();
                if (count != 0)
                {
                    throw new FormatException("did not read blob extra data correctly");
                }
            }

            var dependenciesTag = input.ReadStringPascal(20);
            if (dependenciesTag != "Depen1")
            {
                throw new FormatException("invalid blob dependencies tag");
            }

            var dependencyInfoSize = input.ReadValueU32();
            this.Dependencies.Clear();
            using (var data = input.ReadToMemoryStream((int)dependencyInfoSize))
            {
                var count = data.ReadValueU32();
                for (uint i = 0; i < count; i++)
                {
                    // ReSharper disable UseObjectOrCollectionInitializer
                    var entry = new Blob.DependencyEntry();
                    // ReSharper restore UseObjectOrCollectionInitializer
                    entry.Type = data.ReadValueU32();
                    entry.Name = data.ReadStringPascal(260);
                    entry.Hash = data.ReadValueU32();
                    this.Dependencies.Add(entry);
                }

                if (data.Position != data.Length)
                {
                    throw new FormatException("did not read blob dependency entry correctly");
                }
            }
        }
Example #25
0
        public void Deserialize(Stream input)
        {
            var version = input.ReadValueU16();

            if (version < 2 || version > 5)
            {
                throw new FormatException("unsupported cfs version");
            }

            var header = new Sprite.Header();

            if (version >= 5)
            {
                header = input.ReadStructure <Sprite.Header>();
            }
            else if (version >= 4)
            {
                var oldHeader = input.ReadStructure <Sprite.OldHeader4>();
                header.FrameCount       = oldHeader.FrameCount;
                header.AnimationTime    = oldHeader.AnimationTime;
                header.Width            = oldHeader.Width;
                header.Height           = oldHeader.Height;
                header.RowCount         = oldHeader.RowCount;
                header.ColumnCount      = oldHeader.ColumnCount;
                header.ShadowCount      = oldHeader.ShadowCount;
                header.LightCount       = oldHeader.LightCount;
                header.UserDataSize     = oldHeader.UserDataSize;
                header.CompressionFlags = (Sprite.CompressionFlags)oldHeader.CompressionFlags;
                header.MaxSolidIndex    = oldHeader.MaxSolidIndex;
                header.DataSize         = oldHeader.DataSize;
                header.Category         = oldHeader.Category;
                header.BlitMode         = oldHeader.BlitMode;
                header.RowMeaning       = oldHeader.RowMeaning;
                header.YSortAdjust      = oldHeader.YSortAdjust;
                header.SortTransform    = oldHeader.SortTransform;
                header.UserPaletteStart = oldHeader.UserPaletteStart;
                header.UserPalette      = oldHeader.UserPalette;
                header.Description      = oldHeader.Description;
            }
            else if (version >= 3)
            {
                var oldHeader = input.ReadStructure <Sprite.OldHeader3>();
                header.FrameCount       = oldHeader.FrameCount;
                header.AnimationTime    = oldHeader.AnimationTime;
                header.Width            = oldHeader.Width;
                header.Height           = oldHeader.Height;
                header.RowCount         = oldHeader.RowCount;
                header.ColumnCount      = oldHeader.ColumnCount;
                header.ShadowCount      = oldHeader.ShadowCount;
                header.LightCount       = oldHeader.LightCount;
                header.UserDataSize     = oldHeader.UserDataSize;
                header.CompressionFlags = (Sprite.CompressionFlags)oldHeader.CompressionFlags;
                header.MaxSolidIndex    = oldHeader.MaxSolidIndex;
                header.DataSize         = oldHeader.DataSize;
                header.Category         = oldHeader.Category;
                header.BlitMode         = oldHeader.BlitMode;
                header.RowMeaning       = oldHeader.RowMeaning;
                header.YSortAdjust      = oldHeader.YSortAdjust;
                header.SortTransform    = oldHeader.SortTransform;
                header.UserPaletteStart = oldHeader.UserPaletteStart;
                header.UserPalette      = oldHeader.UserPalette;
            }
            else if (version >= 1)
            {
                var oldHeader = input.ReadStructure <Sprite.OldHeader2>();
                header.FrameCount       = oldHeader.FrameCount;
                header.AnimationTime    = oldHeader.AnimationTime;
                header.Width            = oldHeader.Width;
                header.Height           = oldHeader.Height;
                header.RowCount         = oldHeader.RowCount;
                header.ColumnCount      = oldHeader.ColumnCount;
                header.ShadowCount      = oldHeader.ShadowCount;
                header.LightCount       = oldHeader.LightCount;
                header.UserDataSize     = oldHeader.UserDataSize;
                header.CompressionFlags = (Sprite.CompressionFlags)oldHeader.CompressionFlags;
                header.MaxSolidIndex    = oldHeader.MaxSolidIndex;
                header.DataSize         = oldHeader.DataSize;
            }

            if (header.LightCount != 0 &&
                header.LightCount != 32)
            {
                throw new FormatException();
            }

            if (header.ShadowCount != 0 &&
                header.ShadowCount != 8)
            {
                throw new FormatException();
            }

            this.AnimationTime    = header.AnimationTime;
            this.Width            = header.Width;
            this.Height           = header.Height;
            this.RowCount         = header.RowCount;
            this.ColumnCount      = header.ColumnCount;
            this.ShadowCount      = header.ShadowCount;
            this.LightCount       = header.LightCount;
            this.MaxSolidIndex    = header.MaxSolidIndex;
            this.CompressionFlags = header.CompressionFlags;
            this.Category         = header.Category;
            this.Description      = header.Description;

            for (int i = 0; i < this.Palette.Length; i++)
            {
                this.Palette[i] = input.ReadValueU32();
            }

            this.UserData = new byte[header.UserDataSize];
            if (input.Read(this.UserData, 0, this.UserData.Length) != this.UserData.Length)
            {
                throw new FormatException();
            }

            var infos = new Sprite.FrameInfo[header.FrameCount];

            for (int i = 0; i < infos.Length; i++)
            {
                infos[i] = input.ReadStructure <Sprite.FrameInfo>();
            }

            var compressionFlags = (uint)header.CompressionFlags;

            if ((compressionFlags & ~0x1FFu) != 0)
            {
                throw new FormatException("unknown compression flags");
            }

            if (header.Unknown20 != 0 &&
                header.Unknown20 != 3)
            {
                // WHAT DOES THIS VALUE MEAN AUGH
                throw new NotSupportedException();
            }

            if ((header.CompressionFlags &
                 Sprite.CompressionFlags.NoCompression) != 0)
            {
                if ((header.CompressionFlags &
                     ~(Sprite.CompressionFlags.NoPixels | Sprite.CompressionFlags.NoCompression)) != 0)
                {
                    throw new FormatException("other compression flags set with NoCompression flag");
                }
            }

            using (var data = input.ReadToMemoryStream(header.DataSize))
            {
                this.Frames = new Sprite.Frame[header.FrameCount];
                for (int i = 0; i < header.FrameCount; i++)
                {
                    var info = infos[i];
                    data.Seek(info.Offset, SeekOrigin.Begin);

                    var frame = this.Frames[i] = new Sprite.Frame();

                    frame.X      = info.X;
                    frame.Y      = info.Y;
                    frame.Width  = Math.Abs(info.Width);
                    frame.Height = Math.Abs(info.Height);
                    frame.Pixels = new byte[frame.Width * frame.Height];

                    if ((header.CompressionFlags &
                         Sprite.CompressionFlags.NoCompression) != 0)
                    {
                        // uncompressed data
                        data.Read(frame.Pixels, 0, frame.Pixels.Length);
                    }
                    else
                    {
                        // compressed data

                        var lengths = new int[frame.Height];
                        var max     = 0;
                        for (int y = 0; y < frame.Height; y++)
                        {
                            int length = data.ReadValueU8();
                            if (length == 0xFF)
                            {
                                length = data.ReadValueU16();
                            }
                            lengths[y] = length;
                            max        = Math.Max(max, length);
                        }

                        var scanline = new byte[max];
                        for (int y = 0, offset = 0; y < frame.Height; y++, offset = y * frame.Width)
                        {
                            var length = lengths[y];
                            if (data.Read(scanline, 0, length) != length)
                            {
                                throw new FormatException();
                            }

                            for (int x = 0; x < length;)
                            {
                                offset += (scanline[x] >> 4) & 0xF; // transparent
                                var literalCount = scanline[x] & 0xF;
                                if (literalCount > 0)
                                {
                                    Array.Copy(scanline, x + 1, frame.Pixels, offset, literalCount);
                                }
                                offset += literalCount;
                                x      += 1 + literalCount;
                            }
                        }
                    }

                    // flip horizontal
                    if (info.Width < 0)
                    {
                        for (int y = 0, offset = 0; y < frame.Height; y++, offset += frame.Width)
                        {
                            Array.Reverse(frame.Pixels, offset, frame.Width);
                        }
                    }

                    // flip vertical
                    if (info.Height < 0)
                    {
                        var scanline = new byte[frame.Height];

                        for (int x = 0; x < frame.Width; x++)
                        {
                            for (int y = 0, offset = x; y < frame.Height; y++, offset += frame.Width)
                            {
                                scanline[y] = frame.Pixels[offset];
                            }

                            for (int y = 0, offset = x; y < frame.Height; y++, offset += frame.Width)
                            {
                                frame.Pixels[offset] = scanline[frame.Height - 1 - y];
                            }
                        }
                    }
                }
            }
        }
        public void Deserialize(Stream input)
        {
            var basePosition = input.Position;

            // read as two unsigned longs so we don't have to actually
            // decode the strings
            var version1 = input.ReadValueU64(false);
            var version2 = input.ReadValueU64(false);

            if (version1 == 0x4552462056322E31) // ERF V2.1
            {
                input.Seek(basePosition + 8, SeekOrigin.Begin);
                throw new NotSupportedException();
            }
            else if (version1 == 0x4500520046002000 &&
                version2 == 0x560032002E003000) // ERF V2.0
            {
                input.Seek(basePosition + 16, SeekOrigin.Begin);
                this.Version = 1;

                var fileCount = input.ReadValueU32();
                var unknown14 = input.ReadValueU32();
                var unknown18 = input.ReadValueU32();
                var unknown1C = input.ReadValueU32();

                this.Flags = 0;
                this.Encryption = EncryptionScheme.None;
                this.Compression = CompressionScheme.None;
                this.ContentId = 0;
                this.PasswordDigest = null;

                this.Entries.Clear();
                for (uint i = 0; i < fileCount; i++)
                {
                    var entry = new Entry();

                    entry.Name = input.ReadString(64, true, Encoding.Unicode);
                    entry.CalculateHashes();
                    entry.Offset = input.ReadValueU32();
                    entry.UncompressedSize = input.ReadValueU32();
                    entry.CompressedSize = entry.UncompressedSize;

                    this.Entries.Add(entry);
                }
            }
            else if (version1 == 0x4500520046002000 &&
                version2 == 0x560032002E003200) // ERF V2.2
            {
                input.Seek(basePosition + 16, SeekOrigin.Begin);
                this.Version = 2;

                var fileCount = input.ReadValueU32();
                var year = input.ReadValueU32();
                var day = input.ReadValueU32();
                var unknown1C = input.ReadValueU32(); // always 0xFFFFFFFF?
                var flags = input.ReadValueU32();
                var contentId = input.ReadValueU32();
                var passwordDigest = new byte[16];
                input.Read(passwordDigest, 0, passwordDigest.Length);

                if (unknown1C != 0xFFFFFFFF)
                {
                    throw new InvalidOperationException();
                }

                this.Flags = (flags & 0x1FFFFF0F) >> 0;
                this.Encryption = (EncryptionScheme)((flags & 0x000000F0) >> 4);
                this.Compression = (CompressionScheme)((flags & 0xE0000000) >> 29);

                if (this.Flags != 0 && this.Flags != 1)
                {
                    throw new FormatException("unknown flags value");
                }

                this.ContentId = contentId;
                this.PasswordDigest = passwordDigest;

                this.Entries.Clear();
                for (uint i = 0; i < fileCount; i++)
                {
                    var entry = new Entry();

                    entry.Name = input.ReadString(64, true, Encoding.Unicode);
                    entry.CalculateHashes();
                    entry.Offset = input.ReadValueU32();
                    entry.CompressedSize = input.ReadValueU32();
                    entry.UncompressedSize = input.ReadValueU32();

                    this.Entries.Add(entry);
                }
            }
            else if (version1 == 0x4500520046002000 &&
                version2 == 0x560033002E003000) // ERF V3.0
            {
                input.Seek(basePosition + 16, SeekOrigin.Begin);
                this.Version = 3;

                var stringTableSize = input.ReadValueU32();
                var fileCount = input.ReadValueU32();
                var flags = input.ReadValueU32();
                var contentId = input.ReadValueU32();
                var passwordDigest = new byte[16];
                input.Read(passwordDigest, 0, passwordDigest.Length);

                this.Flags = (flags & 0x1FFFFF0F) >> 0;
                this.Encryption = (EncryptionScheme)((flags & 0x000000F0) >> 4);
                this.Compression = (CompressionScheme)((flags & 0xE0000000) >> 29);

                if (this.Flags != 0 && this.Flags != 1)
                {
                    throw new FormatException("unknown flags value");
                }

                this.ContentId = contentId;
                this.PasswordDigest = passwordDigest;

                MemoryStream stringTable = stringTableSize == 0 ?
                    null : input.ReadToMemoryStream(stringTableSize);

                this.Entries.Clear();
                for (uint i = 0; i < fileCount; i++)
                {
                    var entry = new Entry();

                    uint nameOffset = input.ReadValueU32();
                    entry.NameHash = input.ReadValueU64();

                    if (nameOffset != 0xFFFFFFFF)
                    {
                        if (nameOffset + 1 > stringTable.Length)
                        {
                            throw new FormatException("file name exceeds string table bounds");
                        }

                        stringTable.Position = nameOffset;
                        entry.Name = stringTable.ReadStringZ(Encoding.ASCII);

                        if (entry.Name.HashFNV64() != entry.NameHash)
                        {
                            throw new InvalidOperationException("hash mismatch");
                        }
                    }
                    else
                    {
                        entry.Name = null;
                    }

                    entry.TypeHash = input.ReadValueU32();
                    entry.Offset = input.ReadValueU32();
                    entry.CompressedSize = input.ReadValueU32();
                    entry.UncompressedSize = input.ReadValueU32();

                    this.Entries.Add(entry);
                }
            }
            else
            {
                throw new FormatException("unsupported / unknown ERF format");
            }
        }
Example #27
0
        public void Deserialize(Stream input)
        {
            if (input.ReadValueU32() != 0x39444350)
            {
                throw new FormatException();
            }

            this.Format = input.ReadValueEnum <PCD9.Format>();
            var dataSize = input.ReadValueU32();

            this.Unknown0C = input.ReadValueU32();
            this.Width     = input.ReadValueU16();
            this.Height    = input.ReadValueU16();
            this.BPP       = input.ReadValueU8();
            var mipMapCount = 1 + input.ReadValueU8();

            this.Unknown16 = input.ReadValueU16();
            if ((this.Unknown16 & 0x8000) != 0)
            {
                throw new NotSupportedException();
                this.unknownFlag = true;
            }

            this.Mipmaps.Clear();
            using (var data = input.ReadToMemoryStream(dataSize))
            {
                var mipWidth  = this.Width;
                var mipHeight = this.Height;

                for (int i = 0; i < mipMapCount; i++)
                {
                    if (mipWidth == 0)
                    {
                        mipWidth = 1;
                    }

                    if (mipHeight == 0)
                    {
                        mipHeight = 1;
                    }

                    int size;
                    switch (this.Format)
                    {
                    case PCD9.Format.A8R8G8B8:
                    {
                        size = mipWidth * mipHeight * 4;
                        break;
                    }

                    case PCD9.Format.DXT1:
                    case PCD9.Format.DXT3:
                    case PCD9.Format.DXT5:
                    {
                        int blockCount = ((mipWidth + 3) / 4) * ((mipHeight + 3) / 4);
                        int blockSize  = this.Format == PCD9.Format.DXT1 ? 8 : 16;
                        size = blockCount * blockSize;
                        break;
                    }

                    default:
                    {
                        throw new NotSupportedException();
                    }
                    }

                    var buffer = new byte[size];
                    if (data.Read(buffer, 0, buffer.Length) != buffer.Length)
                    {
                        throw new EndOfStreamException();
                    }

                    this.Mipmaps.Add(new PCD9.Mipmap()
                    {
                        Width  = mipWidth,
                        Height = mipHeight,
                        Data   = buffer,
                    });

                    mipWidth  >>= 1;
                    mipHeight >>= 1;
                }

                if (data.Position != data.Length)
                {
                    throw new InvalidOperationException();
                }
            }
        }
Example #28
0
        public void Deserialize(Stream input)
        {
            var magic = input.ReadValueU16(Endian.Little);

            if (magic != Signature && magic.Swap() != Signature)
            {
                throw new FormatException();
            }
            var endian = magic == Signature ? Endian.Little : Endian.Big;

            var nameCount      = input.ReadValueU16(endian);
            var directoryCount = input.ReadValueU16(endian);

            var unknown06 = input.ReadValueU16(endian);

            if (unknown06 != 4)
            {
                throw new FormatException();
            }

            var fileTableOffset = input.ReadValueU32(endian);
            var totalSize       = input.ReadValueU32(endian); // size of FILETABLE.BIN
            var titleId1        = input.ReadString(16, true, Encoding.ASCII);
            var titleId2        = input.ReadString(16, true, Encoding.ASCII);

            var unknown30     = input.ReadValueU16(endian);
            var unknown32     = input.ReadValueU8();
            var parentalLevel = input.ReadValueU8();

            if (unknown30 != 0 || (unknown32 != 0 && unknown32 != 1))
            {
                throw new FormatException();
            }

            var installDataCryptoKey = input.ReadBytes(16);

            var nameHeaders = new NameHeader[nameCount];

            for (int i = 0; i < nameCount; i++)
            {
                nameHeaders[i] = NameHeader.Read(input, endian);
            }

            var directoryHeaders = new DirectoryHeader[directoryCount];

            for (int i = 0; i < directoryCount; i++)
            {
                var directoryHeader = directoryHeaders[i] = DirectoryHeader.Read(input, endian);
                if (directoryHeader.Unknown02 != 0 ||
                    directoryHeader.Unknown08 != 0)
                {
                    throw new FormatException();
                }
            }

            var totalBatchCount = directoryHeaders.Sum(s => s.BatchCount);

            if (input.Position + (totalBatchCount * 8) != fileTableOffset)
            {
                throw new InvalidOperationException();
            }

            var batchHeaders = new BatchHeader[totalBatchCount];

            for (int i = 0; i < totalBatchCount; i++)
            {
                batchHeaders[i] = BatchHeader.Read(input, endian);
            }

            var totalFileCount = batchHeaders.Sum(d => d.FileCount);

            int fileTableSize = 0;

            foreach (var batchHeader in batchHeaders)
            {
                var fileTableEntrySizeIndex = (int)batchHeader.Flags;
                if (fileTableEntrySizeIndex == 1 || fileTableEntrySizeIndex > 5)
                {
                    throw new NotSupportedException();
                }
                fileTableSize += batchHeader.FileCount * _FileTableEntrySizes[fileTableEntrySizeIndex];
            }

            if (totalSize - fileTableOffset != fileTableSize)
            {
                throw new InvalidOperationException();
            }

            var directories = new List <DirectoryEntry>();

            using (var data = input.ReadToMemoryStream(fileTableSize))
            {
                foreach (var directoryHeader in directoryHeaders)
                {
                    var batchIndexBase = directoryHeader.BatchTableOffset / 8;

                    var directory = new DirectoryEntry()
                    {
                        Id              = directoryHeader.Id,
                        DataBlockSize   = directoryHeader.DataBlockSize,
                        DataBaseOffset  = directoryHeader.DataBaseOffset,
                        IsInInstallData = directoryHeader.IsInInstallData,
                    };

                    for (int i = 0; i < directoryHeader.BatchCount; i++)
                    {
                        if ((directoryHeader.BatchTableOffset % 8) != 0)
                        {
                            throw new FormatException();
                        }

                        var batchHeader = batchHeaders[batchIndexBase + i];

                        var readDataHeader = _FileTableEntryReaders[(int)batchHeader.Flags];
                        if (readDataHeader == null)
                        {
                            throw new NotSupportedException();
                        }

                        data.Position = batchHeader.FileTableOffset;
                        ushort fileId = batchHeader.BaseFileId;
                        for (int j = 0; j < batchHeader.FileCount; j++, fileId++)
                        {
                            var fileHeader = readDataHeader(data, endian);

                            uint?nameHash = null;
                            if (directoryHeader.NameTableCount > 0)
                            {
                                if (directoryHeader.NameTableIndex == 0xFFFF)
                                {
                                    throw new InvalidOperationException();
                                }

                                var nameIndex = Array.FindIndex(
                                    nameHeaders,
                                    directoryHeader.NameTableIndex,
                                    directoryHeader.NameTableCount,
                                    nte => nte.DirectoryId == directoryHeader.Id &&
                                    nte.FileId == fileId);
                                if (nameIndex >= 0)
                                {
                                    nameHash = nameHeaders[nameIndex].NameHash;
                                }
                            }

                            FileEntry file;
                            file.Id              = fileId;
                            file.NameHash        = nameHash;
                            file.DataBlockOffset = fileHeader.DataBlockOffset;
                            file.DataSize        = fileHeader.DataSize;
                            directory.Files.Add(file);
                        }
                    }

                    directories.Add(directory);
                }

                this.Endian               = endian;
                this.TitleId1             = titleId1;
                this.TitleId2             = titleId2;
                this.Unknown32            = unknown32;
                this.ParentalLevel        = parentalLevel;
                this.InstallDataCryptoKey = installDataCryptoKey;
                this.Directories.Clear();
                this.Directories.AddRange(directories);
            }
        }
		public void Deserialize(Stream input)
		{
			var magic = input.ReadUInt32();

			if (magic != 0x666D726D && magic.Swap() != 0x666D726D)
			{
				throw new FormatException();
			}

			var endian = magic == 0x666D726D ? ByteOrder.LittleEndian : ByteOrder.BigEndian;
			var version = input.ReadUInt32(endian);

			if (version != 1)
			{
				throw new FormatException();
			}

			Version = version;

			input.ReadInt32(endian);
			var maxValueLength = input.ReadInt32(endian);

			var stringTableSize = input.ReadUInt32(endian);
			var huffmanSize = input.ReadUInt32(endian);
			var indexSize = input.ReadUInt32(endian);
			var dataSize = input.ReadUInt32(endian);

			var strings = new List<KeyValuePair<uint, string>>();

			using (var data = input.ReadToMemoryStream(stringTableSize))
			{
				var localStringTableSize = data.ReadUInt32(endian);

				if (localStringTableSize != stringTableSize)
				{
					throw new FormatException();
				}

				var count = data.ReadUInt32(endian);

				var offsets = new List<KeyValuePair<uint, uint>>();

				for (uint i = 0; i < count; i++)
				{
					var hash = data.ReadUInt32(endian);
					var offset = data.ReadUInt32(endian);

					offsets.Add(new KeyValuePair<uint, uint>(hash, offset));
				}

				foreach (var kv in offsets)
				{
					var hash = kv.Key;
					var offset = kv.Value;

					data.Seek(8 + offset, SeekOrigin.Begin);
					var length = data.ReadUInt16(endian);
					var text = data.ReadString(length, Encoding.UTF8);

					if (text.HashCrc32() != hash)
					{
						throw new InvalidOperationException();
					}

					strings.Add(new KeyValuePair<uint, string>(hash, text));
				}
			}

			Pair[] huffmanTree;

			using (var data = input.ReadToMemoryStream(huffmanSize))
			{
				var count = data.ReadUInt16(endian);
				huffmanTree = new Pair[count];

				for (ushort i = 0; i < count; i++)
				{
					var left = data.ReadInt32(endian);
					var right = data.ReadInt32(endian);
					huffmanTree[i] = new Pair(left, right);
				}
			}

			using (var index = input.ReadToMemoryStream(indexSize))
			{
				var totalBits = input.ReadInt32(endian);
				var data = input.ReadBytes(dataSize);
				var bitArray = new BitArray(data)
				{
					Length = totalBits
				};

				var files = new List<KeyValuePair<string, uint>>();
				var fileCount = index.ReadUInt16(endian);

				for (ushort i = 0; i < fileCount; i++)
				{
					var nameIndex = index.ReadUInt16(endian);
					var name = strings[nameIndex].Value;
					var offset = index.ReadUInt32(endian);

					files.Add(new KeyValuePair<string, uint>(name, offset));
				}

				foreach (var fileInfo in files.OrderBy(f => f.Key))
				{
					var file = new FileEntry
					{
						Name = fileInfo.Key
					};

					index.Seek(fileInfo.Value, SeekOrigin.Begin);

					var sectionCount = index.ReadUInt16(endian);
					var sections = new List<KeyValuePair<string, uint>>();

					for (ushort i = 0; i < sectionCount; i++)
					{
						var nameIndex = index.ReadUInt16(endian);
						var name = strings[nameIndex].Value;
						var offset = index.ReadUInt32(endian);

						sections.Add(new KeyValuePair<string, uint>(name, offset));
					}

					foreach (var sectionInfo in sections.OrderBy(s => s.Key))
					{
						var section = new Dictionary<string, List<PropertyValue>>();

						index.Seek(fileInfo.Value + sectionInfo.Value, SeekOrigin.Begin);
						var valueCount = index.ReadUInt16(endian);
						var values = new List<KeyValuePair<string, uint>>();

						for (ushort i = 0; i < valueCount; i++)
						{
							var nameIndex = index.ReadUInt16(endian);
							var name = strings[nameIndex].Value;
							var offset = index.ReadUInt32(endian);

							values.Add(new KeyValuePair<string, uint>(name, offset));
						}

						foreach (var valueInfo in values.OrderBy(v => v.Key))
						{
							var value = new List<PropertyValue>();

							index.Seek(fileInfo.Value + sectionInfo.Value + valueInfo.Value, SeekOrigin.Begin);
							var itemCount = index.ReadUInt16(endian);

							for (ushort i = 0; i < itemCount; i++)
							{
								var offset = index.ReadInt32(endian);

								var type = (offset & 0xE0000000) >> 29;
								
								switch (type)
								{
									case 1:
									{
										value.Add(new PropertyValue(1, null));

										break;
									}
									case 0:
									case 2:
									case 3:
									case 4:
									{
										offset &= 0x1fffffff;
										var text = Decoder.Decode(huffmanTree, bitArray, offset, maxValueLength);

										value.Add(new PropertyValue((int) type, text));

										break;
									}
									default:
									{
										throw new NotImplementedException();
									}
								}
							}

							section.Add(valueInfo.Key, value);
						}

						file.Sections.Add(sectionInfo.Key, section);
					}

					Files.Add(file);
				}
			}

			ByteOrder = endian;
		}
Example #30
0
        public void Deserialize(Stream input)
        {
            input.Seek(0, SeekOrigin.Begin);

            var magic = input.ReadValueU32(false);
            if (magic != 0x47464620)
            {
                throw new FormatException();
            }

            var version = input.ReadValueU32(false);
            if (version != 0x56342E30 && // 4.0
                version != 0x56342E31) // 4.1
            {
                throw new FormatException("unsupported version");
            }

            this.FileVersion = (byte)(version - 0x56342E30);
            this.FilePlatform = input.ReadValueEnum<GFF.FilePlatform>(false);
            this.FormatType = input.ReadValueEnum<GFF.FormatType>(false);
            this.FormatVersion = input.ReadValueU32(false);

            var littleEndian = this.FilePlatform == GFF.FilePlatform.PC;

            var structCount = input.ReadValueU32(littleEndian);
            var stringCount = this.FileVersion < 1 ? 0 : input.ReadValueU32(littleEndian);
            var stringOffset = this.FileVersion < 1 ? 0 : input.ReadValueU32(littleEndian);
            var dataOffset = input.ReadValueU32(littleEndian);

            if (this.FileVersion < 1)
            {
                stringOffset = dataOffset;
            }
            else
            {
                if (dataOffset < stringOffset)
                {
                    throw new FormatException();
                }
            }

            this.Structures.Clear();
            for (uint i = 0; i < structCount; i++)
            {
                var structDef = new GFF.StructureDefinition();
                //structDef.Id = input.ReadValueU32(littleEndian);
                structDef.Id = input.ReadValueU32(false);
                var fieldCount = input.ReadValueU32(littleEndian);
                var fieldOffset = input.ReadValueU32(littleEndian);
                structDef.DataSize = input.ReadValueU32(littleEndian);

                long nextOffset = input.Position;

                structDef.Fields.Clear();
                input.Seek(fieldOffset, SeekOrigin.Begin);
                for (uint j = 0; j < fieldCount; j++)
                {
                    var fieldDef = new GFF.FieldDefinition();
                    fieldDef.Id = input.ReadValueS32(littleEndian);
                    var rawFlags = input.ReadValueU32(littleEndian);
                    fieldDef.Offset = input.ReadValueU32(littleEndian);

                    var type = (ushort)(rawFlags & 0xFFFF);
                    var flags = (GFF.FieldFlags)((rawFlags >> 16) & 0xFFFF);

                    if ((flags & GFF.FieldFlags.IsStructure) != 0)
                    {
                        flags &= ~GFF.FieldFlags.IsStructure;
                        fieldDef.Type = GFF.FieldType.Structure;
                        fieldDef.StructureId = type;
                    }
                    else
                    {
                        fieldDef.Type = (GFF.FieldType)type;
                    }

                    fieldDef.Flags = flags;
                    structDef.Fields.Add(fieldDef);
                }

                this.Structures.Add(structDef);
                input.Seek(nextOffset, SeekOrigin.Begin);
            }

            if (this.FileVersion >= 1)
            {
                input.Seek(stringOffset, SeekOrigin.Begin);
                this.StringTable = new List<string>();
                for (uint i = 0; i < stringCount; i++)
                {
                    this.StringTable.Add(input.ReadStringZ(Encoding.UTF8));
                }
            }

            input.Seek(dataOffset, SeekOrigin.Begin);
            this.Data = input.ReadToMemoryStream(input.Length - dataOffset);
        }
Example #31
0
        public void Deserialize(Stream input)
        {
            var magic = input.ReadValueU32(Endian.Little);
            if (magic != 0x666D726D && // fmrm
                magic.Swap() != 0x666D726D)
            {
                throw new FormatException();
            }
            var endian = magic == 0x666D726D ? Endian.Little : Endian.Big;

            var version = input.ReadValueU32(endian);
            if (version != 1)
            {
                throw new FormatException();
            }
            this.Version = version;

            /*var maxKeyLength =*/ input.ReadValueS32(endian);
            var maxValueLength = input.ReadValueS32(endian);

            var stringTableSize = input.ReadValueU32(endian);
            var huffmanSize = input.ReadValueU32(endian);
            var indexSize = input.ReadValueU32(endian);
            var dataSize = input.ReadValueU32(endian);

            var strings = new List<KeyValuePair<uint, string>>();
            using (var data = input.ReadToMemoryStream(stringTableSize))
            {
                var localStringTableSize = data.ReadValueU32(endian);
                if (localStringTableSize != stringTableSize)
                {
                    throw new FormatException();
                }

                var count = data.ReadValueU32(endian);

                var offsets = new List<KeyValuePair<uint, uint>>();
                for (uint i = 0; i < count; i++)
                {
                    var hash = data.ReadValueU32(endian);
                    var offset = data.ReadValueU32(endian);
                    offsets.Add(new KeyValuePair<uint, uint>(hash, offset));
                }

                foreach (var kv in offsets)
                {
                    var hash = kv.Key;
                    var offset = kv.Value;

                    data.Seek(8 + offset, SeekOrigin.Begin);
                    var length = data.ReadValueU16(endian);
                    var text = data.ReadString(length, Encoding.UTF8);

                    if (text.HashCrc32() != hash)
                    {
                        throw new InvalidOperationException();
                    }

                    strings.Add(new KeyValuePair<uint, string>(hash, text));
                }
            }

            Huffman.Pair[] huffmanTree;
            using (var data = input.ReadToMemoryStream(huffmanSize))
            {
                var count = data.ReadValueU16(endian);
                huffmanTree = new Huffman.Pair[count];
                for (ushort i = 0; i < count; i++)
                {
                    var left = data.ReadValueS32(endian);
                    var right = data.ReadValueS32(endian);
                    huffmanTree[i] = new Huffman.Pair(left, right);
                }
            }

            using (var index = input.ReadToMemoryStream(indexSize))
            {
                var totalBits = input.ReadValueS32(endian);
                var data = input.ReadBytes(dataSize);
                var bitArray = new BitArray(data) { Length = totalBits };

                var files = new List<KeyValuePair<string, uint>>();
                var fileCount = index.ReadValueU16(endian);
                for (ushort i = 0; i < fileCount; i++)
                {
                    var nameIndex = index.ReadValueU16(endian);
                    var name = strings[nameIndex].Value;
                    var offset = index.ReadValueU32(endian);
                    files.Add(new KeyValuePair<string, uint>(name, offset));
                }

                foreach (var fileInfo in files.OrderBy(f => f.Key))
                {
                    var file = new Coalesced.File() { Name = fileInfo.Key };

                    index.Seek(fileInfo.Value, SeekOrigin.Begin);
                    var sectionCount = index.ReadValueU16(endian);
                    var sections = new List<KeyValuePair<string, uint>>();
                    for (ushort i = 0; i < sectionCount; i++)
                    {
                        var nameIndex = index.ReadValueU16(endian);
                        var name = strings[nameIndex].Value;
                        var offset = index.ReadValueU32(endian);
                        sections.Add(new KeyValuePair<string, uint>(name, offset));
                    }

                    foreach (var sectionInfo in sections.OrderBy(s => s.Key))
                    {
                        var section = new Dictionary<string, List<Coalesced.Entry>>();

                        index.Seek(fileInfo.Value + sectionInfo.Value, SeekOrigin.Begin);
                        var valueCount = index.ReadValueU16(endian);
                        var values = new List<KeyValuePair<string, uint>>();
                        for (ushort i = 0; i < valueCount; i++)
                        {
                            var nameIndex = index.ReadValueU16(endian);
                            var name = strings[nameIndex].Value;
                            var offset = index.ReadValueU32(endian);
                            values.Add(new KeyValuePair<string, uint>(name, offset));
                        }

                        foreach (var valueInfo in values.OrderBy(v => v.Key))
                        {
                            var value = new List<Coalesced.Entry>();

                            index.Seek(fileInfo.Value + sectionInfo.Value + valueInfo.Value, SeekOrigin.Begin);
                            var itemCount = index.ReadValueU16(endian);

                            for (ushort i = 0; i < itemCount; i++)
                            {
                                var offset = index.ReadValueS32(endian);

                                var type = (offset & 0xE0000000) >> 29;
                                if (type == 1)
                                {
                                    value.Add(new Coalesced.Entry(1, null));
                                }
                                else if (type == 0 || type == 2 || type == 3 || type == 4)
                                {
                                    offset &= 0x1FFFFFFF;
                                    var text = Huffman.Decoder.Decode(
                                        huffmanTree, bitArray, offset, maxValueLength);
                                    value.Add(new Coalesced.Entry(2, text));
                                }
                                else
                                {
                                    throw new NotImplementedException();
                                }
                            }

                            section.Add(valueInfo.Key, value);
                        }

                        file.Sections.Add(sectionInfo.Key, section);
                    }

                    this.Files.Add(file);
                }
            }

            this.Endian = endian;
        }
Example #32
0
        public void Deserialize(Stream input)
        {
            var version = input.ReadValueU16();
            if (version < 2 || version > 5)
            {
                throw new FormatException("unsupported cfs version");
            }

            var header = new Sprite.Header();

            if (version >= 5)
            {
                header = input.ReadStructure<Sprite.Header>();
            }
            else if (version >= 4)
            {
                var oldHeader = input.ReadStructure<Sprite.OldHeader4>();
                header.FrameCount = oldHeader.FrameCount;
                header.AnimationTime = oldHeader.AnimationTime;
                header.Width = oldHeader.Width;
                header.Height = oldHeader.Height;
                header.RowCount = oldHeader.RowCount;
                header.ColumnCount = oldHeader.ColumnCount;
                header.ShadowCount = oldHeader.ShadowCount;
                header.LightCount = oldHeader.LightCount;
                header.UserDataSize = oldHeader.UserDataSize;
                header.CompressionFlags = (Sprite.CompressionFlags)oldHeader.CompressionFlags;
                header.MaxSolidIndex = oldHeader.MaxSolidIndex;
                header.DataSize = oldHeader.DataSize;
                header.Category = oldHeader.Category;
                header.BlitMode = oldHeader.BlitMode;
                header.RowMeaning = oldHeader.RowMeaning;
                header.YSortAdjust = oldHeader.YSortAdjust;
                header.SortTransform = oldHeader.SortTransform;
                header.UserPaletteStart = oldHeader.UserPaletteStart;
                header.UserPalette = oldHeader.UserPalette;
                header.Description = oldHeader.Description;
            }
            else if (version >= 3)
            {
                var oldHeader = input.ReadStructure<Sprite.OldHeader3>();
                header.FrameCount = oldHeader.FrameCount;
                header.AnimationTime = oldHeader.AnimationTime;
                header.Width = oldHeader.Width;
                header.Height = oldHeader.Height;
                header.RowCount = oldHeader.RowCount;
                header.ColumnCount = oldHeader.ColumnCount;
                header.ShadowCount = oldHeader.ShadowCount;
                header.LightCount = oldHeader.LightCount;
                header.UserDataSize = oldHeader.UserDataSize;
                header.CompressionFlags = (Sprite.CompressionFlags)oldHeader.CompressionFlags;
                header.MaxSolidIndex = oldHeader.MaxSolidIndex;
                header.DataSize = oldHeader.DataSize;
                header.Category = oldHeader.Category;
                header.BlitMode = oldHeader.BlitMode;
                header.RowMeaning = oldHeader.RowMeaning;
                header.YSortAdjust = oldHeader.YSortAdjust;
                header.SortTransform = oldHeader.SortTransform;
                header.UserPaletteStart = oldHeader.UserPaletteStart;
                header.UserPalette = oldHeader.UserPalette;
            }
            else if (version >= 1)
            {
                var oldHeader = input.ReadStructure<Sprite.OldHeader2>();
                header.FrameCount = oldHeader.FrameCount;
                header.AnimationTime = oldHeader.AnimationTime;
                header.Width = oldHeader.Width;
                header.Height = oldHeader.Height;
                header.RowCount = oldHeader.RowCount;
                header.ColumnCount = oldHeader.ColumnCount;
                header.ShadowCount = oldHeader.ShadowCount;
                header.LightCount = oldHeader.LightCount;
                header.UserDataSize = oldHeader.UserDataSize;
                header.CompressionFlags = (Sprite.CompressionFlags)oldHeader.CompressionFlags;
                header.MaxSolidIndex = oldHeader.MaxSolidIndex;
                header.DataSize = oldHeader.DataSize;
            }

            if (header.LightCount != 0 &&
                header.LightCount != 32)
            {
                throw new FormatException();
            }

            if (header.ShadowCount != 0 &&
                header.ShadowCount != 8)
            {
                throw new FormatException();
            }

            this.AnimationTime = header.AnimationTime;
            this.Width = header.Width;
            this.Height = header.Height;
            this.RowCount = header.RowCount;
            this.ColumnCount = header.ColumnCount;
            this.ShadowCount = header.ShadowCount;
            this.LightCount = header.LightCount;
            this.MaxSolidIndex = header.MaxSolidIndex;
            this.CompressionFlags = header.CompressionFlags;

            for (int i = 0; i < this.Palette.Length; i++)
            {
                this.Palette[i] = input.ReadValueU32();
            }

            this.UserData = new byte[header.UserDataSize];
            if (input.Read(this.UserData, 0, this.UserData.Length) != this.UserData.Length)
            {
                throw new FormatException();
            }

            var infos = new Sprite.FrameInfo[header.FrameCount];
            for (int i = 0; i < infos.Length; i++)
            {
                infos[i] = input.ReadStructure<Sprite.FrameInfo>();
            }

            var compressionFlags = (uint)header.CompressionFlags;
            if ((compressionFlags & ~0x1FFu) != 0)
            {
                throw new FormatException("unknown compression flags");
            }

            if (header.Unknown20 != 0 &&
                header.Unknown20 != 3)
            {
                // WHAT DOES THIS VALUE MEAN AUGH
                throw new NotSupportedException();
            }

            if ((header.CompressionFlags &
                 Sprite.CompressionFlags.NoCompression) != 0)
            {
                if ((header.CompressionFlags &
                     ~(Sprite.CompressionFlags.NoPixels | Sprite.CompressionFlags.NoCompression)) != 0)
                {
                    throw new FormatException("other compression flags set with NoCompression flag");
                }
            }

            using (var data = input.ReadToMemoryStream(header.DataSize))
            {
                this.Frames = new Sprite.Frame[header.FrameCount];
                for (int i = 0; i < header.FrameCount; i++)
                {
                    var info = infos[i];
                    data.Seek(info.Offset, SeekOrigin.Begin);

                    var frame = this.Frames[i] = new Sprite.Frame();

                    frame.X = info.X;
                    frame.Y = info.Y;
                    frame.Width = Math.Abs(info.Width);
                    frame.Height = Math.Abs(info.Height);
                    frame.Pixels = new byte[frame.Width * frame.Height];

                    if ((header.CompressionFlags &
                         Sprite.CompressionFlags.NoCompression) != 0)
                    {
                        // uncompressed data
                        data.Read(frame.Pixels, 0, frame.Pixels.Length);
                    }
                    else
                    {
                        // compressed data

                        var lengths = new int[frame.Height];
                        var max = 0;
                        for (int y = 0; y < frame.Height; y++)
                        {
                            int length = data.ReadValueU8();
                            if (length == 0xFF)
                            {
                                length = data.ReadValueU16();
                            }
                            lengths[y] = length;
                            max = Math.Max(max, length);
                        }

                        var scanline = new byte[max];
                        for (int y = 0, offset = 0; y < frame.Height; y++, offset = y * frame.Width)
                        {
                            var length = lengths[y];
                            if (data.Read(scanline, 0, length) != length)
                            {
                                throw new FormatException();
                            }

                            for (int x = 0; x < length;)
                            {
                                offset += (scanline[x] >> 4) & 0xF; // transparent
                                var literalCount = scanline[x] & 0xF;
                                if (literalCount > 0)
                                {
                                    Array.Copy(scanline, x + 1, frame.Pixels, offset, literalCount);
                                }
                                offset += literalCount;
                                x += 1 + literalCount;
                            }
                        }
                    }

                    // flip horizontal
                    if (info.Width < 0)
                    {
                        for (int y = 0, offset = 0; y < frame.Height; y++, offset += frame.Width)
                        {
                            Array.Reverse(frame.Pixels, offset, frame.Width);
                        }
                    }

                    // flip vertical
                    if (info.Height < 0)
                    {
                        var scanline = new byte[frame.Height];

                        for (int x = 0; x < frame.Width; x++)
                        {
                            for (int y = 0, offset = x; y < frame.Height; y++, offset += frame.Width)
                            {
                                scanline[y] = frame.Pixels[offset];
                            }

                            for (int y = 0, offset = x; y < frame.Height; y++, offset += frame.Width)
                            {
                                frame.Pixels[offset] = scanline[frame.Height - 1 - y];
                            }
                        }
                    }
                }
            }
        }
Example #33
0
        public static MemoryStream Decompress(Stream input)
        {
            var basePosition = input.Position;

            if (input.ReadValueU32(false) != Magic) // CDRM
            {
                throw new FormatException();
            }

            var version = input.ReadValueU32(true);

            if (version != 0 &&
                version != 2 && version.Swap() != 2)
            {
                throw new FormatException();
            }

            bool littleEndian;
            uint count;
            uint padding;

            if (version == 0)
            {
                count = input.ReadValueU32(true);

                if (count > 0x7FFFFF)
                {
                    count = count.Swap();
                    littleEndian = false;
                }
                else
                {
                    littleEndian = true;
                }

                input.ReadValueU32(littleEndian);

                padding = (uint)(basePosition + 16 + (count * 8));
                padding = padding.Align(16) - padding;
            }
            else
            {
                littleEndian = version == 2;
                count = input.ReadValueU32(littleEndian);
                padding = input.ReadValueU32(littleEndian);
            }

            var startOfData = basePosition + 16 + (count * 8) + padding;

            var blocks = new Block[count];
            using (var buffer = input.ReadToMemoryStream((count * 8).Align(16)))
            {
                for (uint i = 0; i < count; i++)
                {
                    var block = new Block();
                    var flags = buffer.ReadValueU32(littleEndian);
                    block.UncompressedSize = (flags >> 8) & 0xFFFFFF;
                    block.Type = (byte)(flags & 0xFF);
                    block.CompressedSize = buffer.ReadValueU32(littleEndian);
                    blocks[i] = block;
                }
            }

            if (startOfData != input.Position)
            {
                throw new InvalidOperationException();
            }

            var output = new MemoryStream();

            long offset = 0;
            foreach (var block in blocks)
            {
                var nextPosition = input.Position + block.CompressedSize.Align(16);

                using (var buffer = input.ReadToMemoryStream(block.CompressedSize))
                {
                    if (block.Type == 1)
                    {
                        if (block.CompressedSize != block.UncompressedSize)
                        {
                            throw new InvalidOperationException();
                        }

                        output.Seek(offset, SeekOrigin.Begin);
                        output.WriteFromStream(buffer, block.CompressedSize);
                        offset += block.CompressedSize.Align(16);
                    }
                    else if (block.Type == 2)
                    {
                        var zlib = new InflaterInputStream(buffer);
                        output.Seek(offset, SeekOrigin.Begin);
                        output.WriteFromStream(zlib, block.UncompressedSize);
                        offset += block.UncompressedSize.Align(16);
                    }
                    else
                    {
                        throw new FormatException();
                    }
                }

                input.Seek(nextPosition, SeekOrigin.Begin);
            }

            output.Position = 0;
            return output;
        }
        public static SaveFile Deserialize(Stream input, DeserializeSettings settings)
        {
            if (input.Position + 20 > input.Length)
            {
                throw new SaveCorruptionException("not enough data for save header");
            }

            var check = input.ReadValueU32(Endian.Big);
            if (check == 0x434F4E20)
            {
                throw new SaveFormatException("Xbox 360 save game loading is in the works");

            }
            input.Seek(-4, SeekOrigin.Current);

            var readSha1Hash = input.ReadBytes(20);
            using (var data = input.ReadToMemoryStream(input.Length - 20))
            {
                byte[] computedSha1Hash;
                using (var sha1 = new System.Security.Cryptography.SHA1Managed())
                {
                    computedSha1Hash = sha1.ComputeHash(data);
                }

                if ((settings & DeserializeSettings.IgnoreSha1Mismatch) == 0 &&
                    readSha1Hash.SequenceEqual(computedSha1Hash) == false)
                {
                    throw new SaveCorruptionException("invalid SHA1 hash");
                }

                data.Position = 0;
                var uncompressedSize = data.ReadValueU32(Endian.Big);

                var uncompressedBytes = new byte[uncompressedSize];
                if (uncompressedSize <= BlockSize)
                {
                    var actualUncompressedSize = (int)uncompressedSize;
                    var compressedSize = (uint)(data.Length - 4);
                    var compressedBytes = data.ReadBytes(compressedSize);
                    var result = LZO.Decompress(compressedBytes,
                                                0,
                                                (int)compressedSize,
                                                uncompressedBytes,
                                                0,
                                                ref actualUncompressedSize);
                    if (result != LZO.ErrorCode.Success)
                    {
                        throw new SaveCorruptionException(string.Format("LZO decompression failure ({0})", result));
                    }

                    if (actualUncompressedSize != (int)uncompressedSize)
                    {
                        throw new SaveCorruptionException("LZO decompression failure (uncompressed size mismatch)");
                    }
                }
                else
                {
                    var blockCount = data.ReadValueU32(Endian.Big);
                    var blockInfos = new List<Tuple<uint, uint>>();
                    for (uint i = 0; i < blockCount; i++)
                    {
                        var blockCompressedSize = data.ReadValueU32(Endian.Big);
                        var blockUncompressedSize = data.ReadValueU32(Endian.Big);
                        blockInfos.Add(new Tuple<uint, uint>(blockCompressedSize, blockUncompressedSize));
                    }

                    int uncompressedOffset = 0;
                    int uncompressedSizeLeft = (int)uncompressedSize;
                    foreach (var blockInfo in blockInfos)
                    {
                        var blockUncompressedSize = Math.Min((int)blockInfo.Item2, uncompressedSizeLeft);
                        var actualUncompressedSize = blockUncompressedSize;
                        var compressedSize = (int)blockInfo.Item1;
                        var compressedBytes = data.ReadBytes(compressedSize);
                        var result = LZO.Decompress(compressedBytes,
                                                    0,
                                                    compressedSize,
                                                    uncompressedBytes,
                                                    uncompressedOffset,
                                                    ref actualUncompressedSize);
                        if (result != LZO.ErrorCode.Success)
                        {
                            throw new SaveCorruptionException(string.Format("LZO decompression failure ({0})", result));
                        }

                        if (actualUncompressedSize != blockUncompressedSize)
                        {
                            throw new SaveCorruptionException("LZO decompression failure (uncompressed size mismatch)");
                        }

                        uncompressedOffset += blockUncompressedSize;
                        uncompressedSizeLeft -= blockUncompressedSize;
                    }

                    if (uncompressedSizeLeft != 0)
                    {
                        throw new SaveCorruptionException("LZO decompression failure (uncompressed size left != 0)");
                    }
                }

                using (var outerData = new MemoryStream(uncompressedBytes))
                {
                    var innerSize = outerData.ReadValueU32(Endian.Big);
                    var magic = outerData.ReadString(3);
                    if (magic != "WSG")
                    {
                        throw new SaveCorruptionException("invalid magic");
                    }

                    var version = outerData.ReadValueU32(Endian.Little);
                    if (version != 2 &&
                        version.Swap() != 2)
                    {
                        throw new SaveCorruptionException("invalid or unsupported version");
                    }
                    var endian = version == 2 ? Endian.Little : Endian.Big;

                    var readCRC32Hash = outerData.ReadValueU32(endian);
                    var innerUncompressedSize = outerData.ReadValueS32(endian);

                    var innerCompressedBytes = outerData.ReadBytes(innerSize - 3 - 4 - 4 - 4);
                    var innerUncompressedBytes = Huffman.Decoder.Decode(innerCompressedBytes,
                                                                        innerUncompressedSize);
                    if (innerUncompressedBytes.Length != innerUncompressedSize)
                    {
                        throw new SaveCorruptionException("huffman decompression failure");
                    }

                    var computedCRC32Hash = CRC32.Hash(innerUncompressedBytes, 0, innerUncompressedBytes.Length);
                    if ((settings & DeserializeSettings.IgnoreCrc32Mismatch) == 0 &&
                        computedCRC32Hash != readCRC32Hash)
                    {
                        throw new SaveCorruptionException("invalid CRC32 hash");
                    }

                    using (var innerUncompressedData = new MemoryStream(innerUncompressedBytes))
                    {
                        var saveGame =
                            ProtoBuf.Serializer.Deserialize<WillowTwoSave.WillowTwoPlayerSaveGame>(innerUncompressedData);

                        if ((settings & DeserializeSettings.IgnoreReencodeMismatch) == 0)
                        {
                            using (var testData = new MemoryStream())
                            {
                                ProtoBuf.Serializer.Serialize(testData, saveGame);

                                testData.Position = 0;
                                var testBytes = testData.ReadBytes((uint)testData.Length);
                                if (innerUncompressedBytes.SequenceEqual(testBytes) == false)
                                {
                                    throw new SaveCorruptionException("reencode mismatch");
                                }
                            }
                        }

                        saveGame.Decompose();
                        return new SaveFile()
                        {
                            Endian = endian,
                            SaveGame = saveGame,
                        };
                    }
                }
            }
        }
Example #35
0
        public static string Deserialize(Stream input, Endian endian)
        {
            if (input.ReadValueU8() != 4)
            {
                throw new FormatException();
            }

            var count = input.ReadValueU32(endian);

            if (count > 0x3FFFFFFF)
            {
                throw new FormatException();
            }

            // 0x00000393 = 915
            // 0x00000376 = 886
            var dataSize = input.ReadValueU32(endian);

            if (dataSize > 0x500000)
            {
                throw new FormatException();
            }
            var data = input.ReadToMemoryStream(dataSize);

            var nodes = new List <NodeEntry>();

            for (uint i = 0; i < count; i++)
            {
                var node = new NodeEntry()
                {
                    Name  = DeserializeData(data, input.ReadValueU32(endian), endian),
                    Value = DeserializeData(data, input.ReadValueU32(endian), endian),
                    Id    = input.ReadValueU32(),
                };

                if (node.Id != i)
                {
                    System.Diagnostics.Debugger.Break();
                }

                var childCount = input.ReadValueU32(endian);
                node.Children.Clear();
                for (uint j = 0; j < childCount; j++)
                {
                    node.Children.Add(input.ReadValueU32(endian));
                }

                var attributeCount = input.ReadValueU32(endian);
                node.Attributes.Clear();
                for (uint j = 0; j < attributeCount; j++)
                {
                    var attribute = new AttributeEntry()
                    {
                        Name  = DeserializeData(data, input.ReadValueU32(endian), endian),
                        Value = DeserializeData(data, input.ReadValueU32(endian), endian),
                    };
                    if (attribute.Name.Value.ToString() == "__type")
                    {
                        throw new FormatException("someone used __type?");
                    }
                    node.Attributes.Add(attribute);
                }

                nodes.Add(node);
            }

            var settings = new XmlWriterSettings();

            settings.Indent = true;

            var output = new StringBuilder();
            var writer = XmlWriter.Create(output, settings);

            writer.WriteStartDocument();
            if (nodes.Count > 0)
            {
                var root = nodes.SingleOrDefault(n => n.Id == 0);
                if (root == null)
                {
                    throw new InvalidOperationException();
                }

                if (root.Children.Count != 1 || root.Attributes.Count > 0 || root.Value != null)
                {
                    throw new FormatException();
                }

                foreach (var childId in root.Children)
                {
                    var child = nodes.SingleOrDefault(n => n.Id == childId);
                    if (child == null)
                    {
                        throw new KeyNotFoundException();
                    }

                    WriteXmlNode(writer, nodes, child);
                }
            }
            writer.WriteEndDocument();
            writer.Flush();

            return(output.ToString());
        }
        public static void Main(string[] args)
        {
            bool verbose        = false;
            bool overwriteFiles = true;
            bool showHelp       = false;
            bool debugMode      = false;

            OptionSet options = new OptionSet()
            {
                {
                    "v|verbose",
                    "be verbose (list files)",
                    v => verbose = v != null
                },
                {
                    "d|debug",
                    "debug mode",
                    v => debugMode = v != null
                },
                {
                    "o|overwrite",
                    "overwrite files if they already exist",
                    v => overwriteFiles = v != null
                },
                {
                    "h|help",
                    "show this message and exit",
                    v => showHelp = v != null
                },
            };

            List <string> extra;

            try
            {
                extra = options.Parse(args);
            }
            catch (OptionException e)
            {
                Console.Write("{0}: ", GetExecutableName());
                Console.WriteLine(e.Message);
                Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName());
                return;
            }

            if (extra.Count < 1 || extra.Count > 2 || showHelp == true)
            {
                Console.WriteLine("Usage: {0} [OPTIONS]+ input_str [output_directory]", GetExecutableName());
                Console.WriteLine("Unpack specified stream set.");
                Console.WriteLine();
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }

            string inputPath  = extra[0];
            string outputPath = extra.Count > 1 ? extra[1] : Path.ChangeExtension(inputPath, null) + "_unpacked";

            Stream input = File.OpenRead(inputPath);

            Directory.CreateDirectory(outputPath);

            var settings = new XmlWriterSettings();

            settings.Indent = true;

            using (var xml = XmlWriter.Create(
                       Path.Combine(outputPath, "@archive.xml"), settings))
            {
                xml.WriteStartDocument();
                xml.WriteStartElement("streams");

                var set = new StreamSetFile();
                set.Deserialize(input);

                int counter = 0;
                for (int i = 0; i < set.Contents.Count;)
                {
                    var headerInfo = set.Contents[i];
                    if (headerInfo.Type != StreamSet.ContentType.Header)
                    {
                        //throw new FormatException("excepted header");
                        i++;
                        continue;
                    }

                    input.Seek(headerInfo.Offset, SeekOrigin.Begin);

                    var fileInfo = new StreamSet.FileInfo();
                    fileInfo.Deserialize(input, set.LittleEndian);

                    if (input.Position > headerInfo.Offset + headerInfo.Size)
                    {
                        throw new FormatException("read too much header data?");
                    }

                    /*
                     * if (Enum.IsDefined(typeof(StreamSet.FileBuild), fileInfo.Build) == false)
                     * {
                     *  throw new FormatException("unsupported build type " + ((uint)fileInfo.Build).ToString("X8"));
                     * }*/
                    /*else if (fileInfo.Type != fileInfo.Type2)
                     * {
                     *  throw new FormatException("type hashes don't match");
                     * }
                     * else if (fileInfo.Type != fileInfo.TypeName.HashFileName())
                     * {
                     *  throw new FormatException("type name hash and type hash don't match");
                     * }*/

                    string fileName;

                    fileName =
                        counter.ToString("D4") + "_" +
                        fileInfo.GetSaneFileName();
                    counter++;

                    fileName =
                        Path.Combine(fileInfo.TypeName, fileName);

                    i++;

                    Console.WriteLine("{0}", fileInfo.FileName);

                    string outputName = Path.Combine(outputPath, fileName);

                    if (overwriteFiles == false &&
                        File.Exists(outputName) == true)
                    {
                        continue;
                    }

                    xml.WriteStartElement("stream");

                    //xml.WriteAttributeString("build", fileInfo.Build.ToString());

                    if (Enum.IsDefined(typeof(StreamSet.FileBuild), fileInfo.Build) == false)
                    {
                        xml.WriteAttributeString("build", ((uint)fileInfo.Build).ToString("X8"));
                    }
                    else
                    {
                        xml.WriteAttributeString("build", fileInfo.Build.ToString());
                    }

                    xml.WriteAttributeString("alignment", fileInfo.Alignment.ToString("X4"));
                    xml.WriteAttributeString("flags", fileInfo.Flags.ToString("X4"));
                    xml.WriteAttributeString("type", fileInfo.Type.ToString("X8"));
                    xml.WriteAttributeString("u0C", fileInfo.Unknown0C.ToString("X8"));
                    xml.WriteAttributeString("type2", fileInfo.Type2.ToString("X8"));
                    xml.WriteAttributeString("u14", fileInfo.Unknown14.ToString("X8"));
                    xml.WriteAttributeString("u18", fileInfo.Unknown18.ToString("X8"));
                    xml.WriteAttributeString("base_name", fileInfo.BaseName);
                    xml.WriteAttributeString("file_name", fileInfo.FileName);
                    xml.WriteAttributeString("type_name", fileInfo.TypeName);

                    if (debugMode == false)
                    {
                        xml.WriteString(fileName);
                    }

                    if (debugMode == true)
                    {
                        xml.WriteStartElement("blocks");
                    }

                    Directory.CreateDirectory(Path.GetDirectoryName(outputName));

                    using (var output = File.Create(outputName))
                    {
                        uint readSize = 0;
                        while (readSize < fileInfo.TotalSize)
                        {
                            uint leftSize = fileInfo.TotalSize - readSize;

                            var dataInfo = set.Contents[i];
                            if (dataInfo.Type != StreamSet.ContentType.Data &&
                                dataInfo.Type != StreamSet.ContentType.CompressedData)
                            {
                                throw new InvalidOperationException();
                            }

                            input.Seek(dataInfo.Offset, SeekOrigin.Begin);

                            if (debugMode == true)
                            {
                                xml.WriteStartElement("block");
                            }

                            if (dataInfo.Type == StreamSet.ContentType.CompressedData)
                            {
                                if (debugMode == true)
                                {
                                    xml.WriteAttributeString("type", "compressed");
                                }

                                var compressedSize = input.ReadValueU32(set.LittleEndian);
                                if (4 + compressedSize > dataInfo.Size)
                                {
                                    throw new InvalidOperationException();
                                }

                                var compressedStream = input.ReadToMemoryStream(compressedSize);
                                var compressedData   = Gibbed.RefPack.Decompression.Decompress(
                                    compressedStream);

                                uint writeSize = Math.Min(leftSize, (uint)compressedData.Length);
                                output.Write(compressedData, 0, (int)writeSize);
                                readSize += writeSize;

                                if (debugMode == true)
                                {
                                    xml.WriteAttributeString("offset", dataInfo.Offset.ToString("X8"));
                                    xml.WriteAttributeString("tsize", (dataInfo.Size + 12).ToString());
                                    xml.WriteAttributeString("size", dataInfo.Size.ToString());
                                    xml.WriteAttributeString("csize", compressedSize.ToString());
                                    xml.WriteAttributeString("usize1", writeSize.ToString());
                                    xml.WriteAttributeString("usize2", compressedData.Length.ToString());
                                }
                            }
                            else
                            {
                                if (debugMode == true)
                                {
                                    xml.WriteAttributeString("type", "uncompressed");
                                }

                                uint writeSize = Math.Min(leftSize, dataInfo.Size);
                                output.WriteFromStream(input, writeSize);
                                readSize += writeSize;

                                if (debugMode == true)
                                {
                                    xml.WriteAttributeString("offset", dataInfo.Offset.ToString("X8"));
                                    xml.WriteAttributeString("tsize", (dataInfo.Size + 12).ToString());
                                    xml.WriteAttributeString("size", dataInfo.Size.ToString());
                                }
                            }

                            if (debugMode == true)
                            {
                                xml.WriteEndElement();
                            }

                            ++i;
                        }
                    }

                    if (debugMode == true)
                    {
                        xml.WriteEndElement();
                    }

                    xml.WriteEndElement();
                }

                xml.WriteEndElement();
                xml.WriteEndDocument();
                xml.Flush();
            }
        }
Example #37
0
        public void Deserialize(Stream input)
        {
            var magic = input.ReadValueU32(false);
            input.Seek(-4, SeekOrigin.Current);

            if (magic == CDRMFile.Magic)
            {
                input = CDRMFile.Decompress(input);
            }

            if (input.Position + 32 > input.Length)
            {
                throw new FormatException("not enough data for header");
            }

            var version = input.ReadValueU32();
            if (version != 19 && version.Swap() != 19 &&
                version != 21 && version.Swap() != 21)
            {
                throw new FormatException();
            }

            this.LittleEndian =
                version == 19 ||
                version == 21;
            this.Version = this.LittleEndian == true ? version : version.Swap();

            if (this.Version == 19)
            {
                throw new NotSupportedException();
            }

            var unknown04_Size = input.ReadValueU32(this.LittleEndian);
            var unknown08_Size = input.ReadValueU32(this.LittleEndian);
            var unknown0C = input.ReadValueU32(this.LittleEndian); // extra data after first block?
            var unknown10 = input.ReadValueU32(this.LittleEndian);
            this.Flags = input.ReadValueU32(this.LittleEndian);
            var sectionCount = input.ReadValueU32(this.LittleEndian);
            var unknown1C_Count = input.ReadValueU32(this.LittleEndian);

            if (unknown0C != 0)
            {
                throw new FormatException();

                if ((this.Flags & 1) != 0)
                {
                    input.Seek(input.Position.Align(16), SeekOrigin.Begin);
                }
            }

            var sectionHeaders = new DRM.SectionHeader[sectionCount];
            for (uint i = 0; i < sectionCount; i++)
            {
                sectionHeaders[i] = new DRM.SectionHeader();
                sectionHeaders[i].Deserialize(input, this.LittleEndian);
            }

            this.Unknown08s.Clear();
            using (var unknown08_Data = input.ReadToMemoryStream(unknown08_Size))
            {
                while (unknown08_Data.Position < unknown08_Data.Length)
                {
                    this.Unknown08s.Add(unknown08_Data.ReadStringZ(Encoding.ASCII));
                }
            }

            this.Unknown04s.Clear();
            using (var unknown04_Data = input.ReadToMemoryStream(unknown04_Size))
            {
                while (unknown04_Data.Position < unknown04_Data.Length)
                {
                    this.Unknown04s.Add(unknown04_Data.ReadStringZ(Encoding.ASCII));
                }
            }

            if ((this.Flags & 1) != 0)
            {
                input.Seek(input.Position.Align(16), SeekOrigin.Begin);
            }

            var sections = new DRM.Section[sectionCount];
            for (int i = 0; i < sectionCount; i++)
            {
                var sectionHeader = sectionHeaders[i];

                var section = new DRM.Section();
                section.Id = sectionHeader.Id;
                section.Type = sectionHeader.Type;
                section.Flags = (byte)(sectionHeader.Flags & 0xFF);
                section.Unknown05 = sectionHeader.Unknown05;
                section.Unknown06 = sectionHeader.Unknown06;
                section.Unknown10 = sectionHeader.Unknown10;

                if ((sectionHeader.Unknown05 & 1) != 0)
                {
                    throw new NotImplementedException();
                }

                if (sectionHeader.HeaderSize > 0)
                {
                    using (var buffer = input.ReadToMemoryStream(sectionHeader.HeaderSize))
                    {
                        var resolver = new DRM.Resolver();
                        resolver.Deserialize(buffer, this.LittleEndian);
                        section.Resolver = resolver;
                    }
                }

                if ((this.Flags & 1) != 0)
                {
                    input.Seek(input.Position.Align(16), SeekOrigin.Begin);
                }

                if (sectionHeader.DataSize > 0)
                {
                    section.Data = input.ReadToMemoryStream(sectionHeader.DataSize);
                }
                else
                {
                    section.Data = null;
                }

                if ((this.Flags & 1) != 0)
                {
                    input.Seek(input.Position.Align(16), SeekOrigin.Begin);
                }

                sections[i] = section;
            }

            this.Sections.Clear();
            this.Sections.AddRange(sections);
        }
Example #38
0
        public static MemoryStream Decompress(Stream input)
        {
            var dcx = new CompressedFile();

            dcx.Deserialize(input);

            if (dcx._Setup.Scheme == CompressionScheme.Zlib)
            {
                if (dcx._Setup.Unknown1C != 0 ||
                    dcx._Setup.Unknown20 != 0 ||
                    dcx._Setup.Unknown24 != 0 ||
                    dcx._Setup.Flags != 0x00010100)
                {
                    throw new FormatException();
                }

                using (var temp = input.ReadToMemoryStream(dcx._Size.CompressedSize))
                {
                    var zlib = new InflaterInputStream(temp);
                    return(zlib.ReadToMemoryStream(dcx._Size.UncompressedSize));
                }
            }
            else if (dcx._Setup.Scheme == CompressionScheme.Edge)
            {
                if (dcx._Setup.Unknown1C != 0x00010000 ||
                    dcx._Setup.Unknown20 != 0 ||
                    dcx._Setup.Unknown24 != 0 ||
                    dcx._Setup.Flags != 0x00100100)
                {
                    throw new FormatException();
                }

                using (var table = new MemoryStream(dcx._Extra.Data))
                {
                    if (table.ReadValueU32(Endian.Big) != 0x45676454) // EdgT = Edge Table?
                    {
                        throw new FormatException();
                    }

                    var unknown04                  = table.ReadValueU32(Endian.Big);
                    var tableOffset                = table.ReadValueU32(Endian.Big);
                    var alignment                  = table.ReadValueU32(Endian.Big);
                    var uncompressedBlockSize      = table.ReadValueU32(Endian.Big);
                    var finalUncompressedBlockSize = table.ReadValueU32(Endian.Big);
                    var extraSize                  = table.ReadValueU32(Endian.Big);
                    var blockCount                 = table.ReadValueU32(Endian.Big);
                    var unknown20                  = table.ReadValueU32(Endian.Big);

                    if (extraSize != table.Length)
                    {
                        throw new FormatException();
                    }

                    if (unknown04 != 0x00010100 ||
                        tableOffset != 36 ||
                        alignment != 16 ||
                        uncompressedBlockSize != 0x00010000 ||
                        unknown20 != 0x00100000)
                    {
                        throw new FormatException();
                    }

                    var data = new MemoryStream();

                    for (uint i = 0; i < blockCount; i++)
                    {
                        var bunknown0   = table.ReadValueU32(Endian.Big);
                        var blockOffset = table.ReadValueU32(Endian.Big);
                        var blockSize   = table.ReadValueU32(Endian.Big);
                        var blockFlags  = table.ReadValueU32(Endian.Big);

                        if (bunknown0 != 0 ||
                            (blockFlags != 0 && blockFlags != 1))
                        {
                            throw new FormatException();
                        }

                        using (var temp = input.ReadToMemoryStream(blockSize.Align(alignment)))
                        {
                            if (blockFlags == 1)
                            {
                                var zlib = new InflaterInputStream(temp, new Inflater(true));
                                data.WriteFromStream(zlib,
                                                     i + 1 < blockCount
                                                         ? uncompressedBlockSize
                                                         : finalUncompressedBlockSize);
                            }
                            else if (blockFlags == 0)
                            {
                                data.WriteFromStream(temp,
                                                     i + 1 < blockCount
                                                         ? uncompressedBlockSize
                                                         : finalUncompressedBlockSize);
                            }
                            else
                            {
                                throw new NotImplementedException();
                            }
                        }
                    }

                    if (data.Length != dcx._Size.UncompressedSize)
                    {
                        throw new InvalidOperationException();
                    }

                    data.Position = 0;
                    return(data);
                }
            }
            else
            {
                throw new NotImplementedException();
            }
        }
Example #39
0
        public void Deserialize(Stream input)
        {
            if (input.ReadValueU32() != 0x39444350)
            {
                throw new FormatException();
            }

            this.Format = input.ReadValueEnum<PCD9.Format>();
            var dataSize = input.ReadValueU32();
            this.Unknown0C = input.ReadValueU32();
            this.Width = input.ReadValueU16();
            this.Height = input.ReadValueU16();
            this.BPP = input.ReadValueU8();
            var mipMapCount = 1 + input.ReadValueU8();
            this.Unknown16 = input.ReadValueU16();
            if ((this.Unknown16 & 0x8000) != 0)
            {
                throw new NotSupportedException();
                this.unknownFlag = true;
            }

            this.Mipmaps.Clear();
            using (var data = input.ReadToMemoryStream(dataSize))
            {
                var mipWidth = this.Width;
                var mipHeight = this.Height;

                for (int i = 0; i < mipMapCount; i++)
                {
                    if (mipWidth == 0)
                    {
                        mipWidth = 1;
                    }

                    if (mipHeight == 0)
                    {
                        mipHeight = 1;
                    }

                    int size;
                    switch (this.Format)
                    {
                        case PCD9.Format.A8R8G8B8:
                        {
                            size = mipWidth * mipHeight * 4;
                            break;
                        }

                        case PCD9.Format.DXT1:
                        case PCD9.Format.DXT3:
                        case PCD9.Format.DXT5:
                        {
                            int blockCount = ((mipWidth + 3) / 4) * ((mipHeight + 3) / 4);
                            int blockSize = this.Format == PCD9.Format.DXT1 ? 8 : 16;
                            size = blockCount * blockSize;
                            break;
                        }

                        default:
                        {
                            throw new NotSupportedException();
                        }
                    }

                    var buffer = new byte[size];
                    if (data.Read(buffer, 0, buffer.Length) != buffer.Length)
                    {
                        throw new EndOfStreamException();
                    }

                    this.Mipmaps.Add(new PCD9.Mipmap()
                        {
                            Width = mipWidth,
                            Height = mipHeight,
                            Data = buffer,
                        });

                    mipWidth >>= 1;
                    mipHeight >>= 1;
                }

                if (data.Position != data.Length)
                {
                    throw new InvalidOperationException();
                }
            }
        }