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; }
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(); } }
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(); }
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); } }
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); } }
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), }); } }
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); }
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)); } }
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(); }
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); } }
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(); } }
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); } } }
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); } }
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)); } } }
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; }
public static MemoryStream ReadToMemoryStream(this Stream stream, long size) { return(stream.ReadToMemoryStream(size, 0x40000)); }
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"); } } }
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"); } }
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(); } } }
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; }
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); }
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; }
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]; } } } } } }
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, }; } } } }
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(); } }
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); }
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(); } }
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(); } } }