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 static void Export(AdfFile adf, XmlWriter writer) { writer.WriteStartDocument(); writer.WriteStartElement("string-lookup"); writer.WriteAttributeString("extension", adf.extension); writer.WriteAttributeString("endian", adf.Endian.ToString()); writer.WriteAttributeString("comment", adf.Comment); if (adf.TypeDefinitions.Count > 0) { writer.WriteStartElement("type-definitions"); writer.WriteAttributeString("WARNING", "DO NOT TOUCH THAT F*****G THING"); foreach (var typeDef in adf.TypeDefinitions) { ExportTypeDefinition(typeDef, writer); } writer.WriteEndElement(); } if (adf.InstanceInfos.Count > 0) { writer.WriteStartElement("instances"); writer.WriteAttributeString("NOTE", "HERE YOU CAN TOUCH, BUT BE GENTLE"); foreach (var instanceInfo in adf.InstanceInfos) { ExportInstanceInfo(instanceInfo, writer); } writer.WriteEndElement(); } writer.WriteEndElement(); writer.WriteEndDocument(); }
private static uint ComputeHash(AdfFile adf, string value) { if (string.IsNullOrEmpty(value) == true) { return(0); } uint valueHash; if (value[0] == '#') { if (uint.TryParse(value.Substring(1), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out valueHash) == false) { throw new FormatException(); } } else { valueHash = value.HashJenkins(); if (valueHash != 0 && adf.StringHashInfos.Any(shi => shi.ValueHash == valueHash) == false) { adf.StringHashInfos.Add(new AdfFile.StringHashInfo() { Value = value, ValueHash = valueHash, }); } } return(valueHash); }
public void ReadSector() { var t = new AdfFile(@"u:\Emulation\Amiga\WinUAE4100_x64\DiskImages\games\HLS_NHL_2018_2019 - Kopie.adf"); var bytSector = t.GetSector(0); Assert.IsTrue(bytSector.Length == 512, System.Text.Encoding.ASCII.GetString(bytSector, 0, 25)); }
private static string ResolveHash(AdfFile adf, uint valueHash) { if (valueHash == 0) { return(""); } var stringHashInfo = adf.StringHashInfos.FirstOrDefault(shi => shi.ValueHash == valueHash); return(stringHashInfo == default(FileFormats.AdfFile.StringHashInfo) ? string.Format(CultureInfo.InvariantCulture, "#{0:X8}", valueHash) : stringHashInfo.Value); }
public void TestMethod1() { try { var t = new AdfFile(@"u:\Emulation\Amiga\WinUAE4100_x64\DiskImages\games\HLS_NHL_2018_2019 - Kopie.adf"); Assert.IsTrue(true); } catch (Exception e) { Assert.IsFalse(true, e.Message); } }
public InstanceExporter(AdfFile adf, RuntimeTypeLibrary runtime) { if (adf == null) { throw new ArgumentNullException("adf"); } if (runtime == null) { throw new ArgumentNullException("runtime"); } this._Adf = adf; this._Runtime = runtime; this._WorkQueue = new Queue <WorkItem>(); }
private static void ImportInstanceInfo(XPathNavigator instanceNode, AdfFile adf) { InstanceInfo instance = new InstanceInfo() { Name = instanceNode.GetAttribute("name", ""), NameHash = uint.Parse(instanceNode.GetAttribute("name-hash", "")), }; TypeDefinitionType type; Enum.TryParse(instanceNode.GetAttribute("type", ""), out type); uint typeHash = uint.Parse(instanceNode.GetAttribute("type-hash", ""), CultureInfo.InvariantCulture); string typeString = instanceNode.GetAttribute("type-name", ""); instance.Type = adf.Runtime.GetTypeDefinition(typeHash); instance.TypeHash = instance.Type.NameHash; if (!int.TryParse(instanceNode.GetAttribute("inline-array-copy-index", ""), out instance.InlineArrayIndex)) { instance.InlineArrayIndex = -1; } if (!uint.TryParse(instanceNode.GetAttribute("inline-array-copy-minsz", ""), out instance.MinInlineArraySize)) { instance.MinInlineArraySize = 0; } if (type != instance.Type.Type) { throw new InvalidOperationException("do not touch things like type and type-name in the xml file, yo"); } instance.Members = new List <AdfFile.InstanceMemberInfo>(); // parse members var membersList = instanceNode.Select("member"); // normal array or structure foreach (XPathNavigator memberNode in membersList) { instance.Members.Add(ImportInstanceMemberInfo(memberNode, adf)); } // add it adf.AddInstanceInfo(instance); }
public static AdfFile Import(XPathNavigator root) { AdfFile adf = new AdfFile() { Endian = Endian.Little, }; adf.Comment = root.GetAttribute("comment", ""); Endian adfEndian; Enum.TryParse(root.GetAttribute("endian", ""), out adfEndian); adf.Endian = adfEndian; var typeDefNode = root.SelectSingleNode("type-definitions"); if (typeDefNode != null) { var typesList = typeDefNode.Select("type"); foreach (XPathNavigator typeNode in typesList) { ImportTypeDefinition(typeNode, adf); } // loop the loop adf.Runtime.AddTypeDefinitions(adf); } var instancesNode = root.SelectSingleNode("instances"); if (instancesNode != null) { var instancesList = instancesNode.Select("instance"); foreach (XPathNavigator instanceNode in instancesList) { ImportInstanceInfo(instanceNode, adf); } } return(adf); }
private static void ImportTypeDefinition(XPathNavigator typeNode, AdfFile adf) { TypeDefinition typeDef = new TypeDefinition() { Size = uint.Parse(typeNode.GetAttribute("size", "")), Alignment = uint.Parse(typeNode.GetAttribute("alignment", ""), CultureInfo.InvariantCulture), Name = typeNode.GetAttribute("name", ""), NameHash = uint.Parse(typeNode.GetAttribute("name-hash", ""), CultureInfo.InvariantCulture), Flags = uint.Parse(typeNode.GetAttribute("flags", ""), CultureInfo.InvariantCulture), ElementLength = uint.Parse(typeNode.GetAttribute("length", ""), CultureInfo.InvariantCulture), ElementTypeHash = uint.Parse(typeNode.GetAttribute("eltypehash", ""), CultureInfo.InvariantCulture), }; Enum.TryParse(typeNode.GetAttribute("type", ""), out typeDef.Type); if (typeDef.Type == TypeDefinitionType.Structure) { // it has members var membersList = typeNode.Select("member"); // so we will parse them typeDef.Members = new AdfFile.MemberDefinition[membersList.Count]; int i = 0; foreach (XPathNavigator memberNode in membersList) { typeDef.Members[i].Name = memberNode.GetAttribute("name", ""); typeDef.Members[i].TypeHash = uint.Parse(memberNode.GetAttribute("type-hash", ""), CultureInfo.InvariantCulture); typeDef.Members[i].Size = uint.Parse(memberNode.GetAttribute("size", ""), CultureInfo.InvariantCulture); typeDef.Members[i].Offset = uint.Parse(memberNode.GetAttribute("offset", ""), CultureInfo.InvariantCulture); typeDef.Members[i].DefaultType = uint.Parse(memberNode.GetAttribute("deftype", ""), CultureInfo.InvariantCulture); typeDef.Members[i].DefaultValue = ulong.Parse(memberNode.GetAttribute("defval", ""), CultureInfo.InvariantCulture); ++i; } } // Add it adf.TypeDefinitions.Add(typeDef); }
private static void Main(string[] args) { var mode = Mode.Unknown; bool showHelp = false; var options = new OptionSet { // ReSharper disable AccessToModifiedClosure { "e|export", "convert from binary to JSON", v => SetOption(v, ref mode, Mode.Export) }, { "i|import", "convert from JSON to binary", v => SetOption(v, ref mode, Mode.Import) }, // ReSharper restore AccessToModifiedClosure { "h|help", "show this message and exit", v => showHelp = v != null }, }; 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 (mode == Mode.Unknown && extras.Count >= 1) { var extension = Path.GetExtension(extras[0]); if (extension != null && extension.ToLowerInvariant() == ".json") { mode = Mode.Import; } else { mode = Mode.Export; } } if (extras.Count < 1 || extras.Count > 2 || showHelp == true || mode == Mode.Unknown) { Console.WriteLine("Usage: {0} [OPTIONS]+ [-e] task.onlinec [output_json]", GetExecutableName()); Console.WriteLine(" {0} [OPTIONS]+ [-i] input_json [task.onlinec]", GetExecutableName()); Console.WriteLine("Convert an task file between binary and JSON format."); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } if (mode == Mode.Export) { string inputPath = extras[0]; string outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(inputPath, ".json"); var adf = new AdfFile(); var taskRoot = new TaskRoot(); using (var input = File.OpenRead(inputPath)) { adf.Deserialize(input); var taskRootInfo = adf.InstanceInfos.FirstOrDefault(i => i.Name == "Profile"); if (taskRootInfo.TypeHash != TaskRoot.TypeHash) { throw new FormatException(); } input.Position = taskRootInfo.Offset; taskRoot.Deserialize(input, adf.Endian); } using (var output = File.Create(outputPath)) using (var textWriter = new StreamWriter(output)) using (var writer = new JsonTextWriter(textWriter)) { writer.Indentation = 2; writer.IndentChar = ' '; writer.Formatting = Formatting.Indented; var jsonTasks = taskRoot.Tasks.Select( t => { var jsonTask = new TaskRootJson.Task() { Name = ResolveHash(adf, t.Name), TaskGroup = ResolveHash(adf, t.TaskGroup), Type = t.Type, ProvinceWeight = t.ProvinceWeight, LiberationPercent = t.LiberationPercent, RepeatableRewardSemantics = t.RepeatableRewardSemantics, RepeatableReward = new TaskRootJson.Reward() { Skillpoints = t.RepeatableReward.Skillpoints, Chaos = t.RepeatableReward.Chaos, ItemRewardSemantics = t.RepeatableReward.ItemRewardSemantics, }, HasChurch = t.HasChurch, ShownOnMap = t.ShownOnMap, UIName = ResolveHash(adf, t.UIName), UIDescription = ResolveHash(adf, t.UIDescription), UITip = ResolveHash(adf, t.UITip), UIOrderHint = t.UIOrderHint, }; if (t.RepeatableReward.Items != null) { jsonTask.RepeatableReward.Items.AddRange( t.RepeatableReward.Items.Select(i => new TaskRootJson.ItemReward() { Item = ResolveHash(adf, i.Item), Permanent = i.Permanent, Duration = i.Duration, Quantity = i.Quantity, Delivery = i.Delivery, })); } if (t.RewardThresholds != null) { jsonTask.RewardThresholds.AddRange( t.RewardThresholds.Select( rt => { var jsonRewardThreshold = new TaskRootJson.RewardThreshold() { Threshold = rt.Threshold, Reward = new TaskRootJson.Reward() { Skillpoints = rt.Reward.Skillpoints, Chaos = rt.Reward.Chaos, ItemRewardSemantics = rt.Reward.ItemRewardSemantics, }, }; if (rt.Reward.Items != null) { jsonRewardThreshold.Reward.Items.AddRange( rt.Reward.Items.Select(i => new TaskRootJson.ItemReward() { Item = ResolveHash(adf, i.Item), Permanent = i.Permanent, Duration = i.Duration, Quantity = i.Quantity, Delivery = i.Delivery, })); } return(jsonRewardThreshold); })); } if (t.Prerequisites != null) { jsonTask.Prerequisites.AddRange( t.Prerequisites.Select(p => new TaskRootJson.Prerequisite() { Name = ResolveHash(adf, p.Name), RewardIndex = p.RewardIndex, Tag = ResolveHash(adf, p.Tag), })); } return(jsonTask); }).ToArray(); var serializer = JsonSerializer.Create(); serializer.Serialize(writer, jsonTasks); } } else if (mode == Mode.Import) { string inputPath = extras[0]; string outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(inputPath, ".onlinec"); var adf = new AdfFile() { Endian = Endian.Little, }; var taskRoot = new TaskRoot(); using (var input = File.OpenRead(inputPath)) using (var textReader = new StreamReader(input)) using (var reader = new JsonTextReader(textReader)) { var serializer = JsonSerializer.Create(); var jsonTasks = serializer.Deserialize <TaskRootJson.Task[]>(reader); taskRoot.Tasks.AddRange(jsonTasks.Select( jt => { var task = new TaskRoot.Task() { Name = ComputeHash(adf, jt.Name), TaskGroup = ComputeHash(adf, jt.TaskGroup), Type = jt.Type, ProvinceWeight = jt.ProvinceWeight, LiberationPercent = jt.LiberationPercent, RepeatableRewardSemantics = jt.RepeatableRewardSemantics, RepeatableReward = new TaskRoot.Reward() { Skillpoints = jt.RepeatableReward.Skillpoints, Chaos = jt.RepeatableReward.Chaos, ItemRewardSemantics = jt.RepeatableReward.ItemRewardSemantics, }, HasChurch = jt.HasChurch, ShownOnMap = jt.ShownOnMap, UIName = ComputeHash(adf, jt.UIName), UIDescription = ComputeHash(adf, jt.UIDescription), UITip = ComputeHash(adf, jt.UITip), UIOrderHint = jt.UIOrderHint, }; task.RepeatableReward.Items = jt.RepeatableReward.Items.Select(ji => new TaskRoot.ItemReward() { Item = ComputeHash(adf, ji.Item), Permanent = ji.Permanent, Duration = ji.Duration, Quantity = ji.Quantity, Delivery = ji.Delivery, }).ToArray(); task.RewardThresholds = jt.RewardThresholds.Select( jrt => { var rewardThreshold = new TaskRoot.RewardThreshold() { Threshold = jrt.Threshold, Reward = new TaskRoot.Reward() { Skillpoints = jrt.Reward.Skillpoints, Chaos = jrt.Reward.Chaos, ItemRewardSemantics = jrt.Reward.ItemRewardSemantics, }, }; rewardThreshold.Reward.Items = jrt.Reward.Items.Select(ji => new TaskRoot.ItemReward() { Item = ComputeHash(adf, ji.Item), Permanent = ji.Permanent, Duration = ji.Duration, Quantity = ji.Quantity, Delivery = ji.Delivery, }).ToArray(); return(rewardThreshold); }).ToArray(); task.Prerequisites = jt.Prerequisites.Select(jp => new TaskRoot.Prerequisite() { Name = ComputeHash(adf, jp.Name), RewardIndex = jp.RewardIndex, Tag = ComputeHash(adf, jp.Tag), }).ToArray(); return(task); })); } using (var output = File.Create(outputPath)) { using (var data = new MemoryStream()) { taskRoot.Serialize(data, adf.Endian); data.Flush(); data.Position = 0; output.Position = adf.EstimateHeaderSize(); var itemRootPosition = output.Position; output.WriteFromStream(data, data.Length); adf.InstanceInfos.Add(new AdfFile.InstanceInfo() { Name = "Profile", NameHash = "Profile".HashJenkins(), Offset = (uint)itemRootPosition, Size = (uint)data.Length, TypeHash = TaskRoot.TypeHash, }); adf.Serialize(output, 0); } } } else { throw new NotSupportedException(); } }
private static AdfFile.InstanceMemberInfo ImportInstanceMemberInfo(XPathNavigator memberNode, AdfFile adf) { AdfFile.InstanceMemberInfo member = new AdfFile.InstanceMemberInfo(); member.Name = memberNode.GetAttribute("name", ""); string stringId = memberNode.GetAttribute("id", ""); string ownIACopy = memberNode.GetAttribute("own-copy-of-inline-arrays", ""); if (!string.IsNullOrEmpty(stringId)) { member.Id = long.Parse(stringId, CultureInfo.InvariantCulture); } member.isReferenceToId = !string.IsNullOrEmpty(memberNode.GetAttribute("is-reference", "")); if (!string.IsNullOrEmpty(ownIACopy)) { member.HasOwnCopyOfInlineArrays = true; } Enum.TryParse(memberNode.GetAttribute("gbltype", ""), out member.Type); string typeString = memberNode.GetAttribute("type", ""); // Load the value if (member.Type == TypeDefinitionType.Primitive) { switch (typeString) { case "int8": member.Data.WriteValueS8(sbyte.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.Int8; break; case "uint8": member.Data.WriteValueU8(byte.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.UInt8; break; case "int16": member.Data.WriteValueS16(short.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.Int16; break; case "uint16": member.Data.WriteValueU16(ushort.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.UInt16; break; case "int32": member.Data.WriteValueS32(int.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.Int32; break; case "uint32": member.Data.WriteValueU32(uint.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.UInt32; break; case "int64": member.Data.WriteValueS64(long.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.Int64; break; case "uint64": member.Data.WriteValueU64(ulong.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.UInt64; break; case "float": member.Data.WriteValueF32(float.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.Float; break; case "double": member.Data.WriteValueF64(double.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.Double; break; case "string": string strRef = memberNode.GetAttribute("reference-string-from", ""); if (!string.IsNullOrEmpty(strRef)) { member.ReferenceToString = true; member.StringTableId = int.Parse(strRef, CultureInfo.InvariantCulture); } member.StringData = memberNode.Value; member.TypeHash = AdfTypeHashes.String; break; } } else { uint typeHash = uint.Parse(memberNode.GetAttribute("type-hash", ""), CultureInfo.InvariantCulture); member.TypeDef = adf.Runtime.GetTypeDefinition(typeHash); member.TypeHash = typeHash; if (member.TypeDef.Type != member.Type) { throw new InvalidOperationException("do not touch things like type and type-name in the xml file, yo"); } if (member.Type == TypeDefinitionType.StringHash) { member.StringData = memberNode.Value; } } // handle sub members if (memberNode.GetAttribute("int8-array-is-string-array", "") == "yay") { // we found an array of inline-strings var subMembersList = memberNode.Select("inline-string"); foreach (XPathNavigator subMemberNode in subMembersList) { // it is an inline string. Get its value and write the string byte[] str = Encoding.UTF8.GetBytes(subMemberNode.Value); foreach (byte b in str) { AdfFile.InstanceMemberInfo subMember = new AdfFile.InstanceMemberInfo(); subMember.TypeHash = AdfTypeHashes.Primitive.Int8; subMember.Type = TypeDefinitionType.Primitive; subMember.Data.WriteValueU8(b); member.Members.Add(subMember); } AdfFile.InstanceMemberInfo lastByteMember = new AdfFile.InstanceMemberInfo(); lastByteMember.TypeHash = AdfTypeHashes.Primitive.Int8; lastByteMember.Type = TypeDefinitionType.Primitive; lastByteMember.Data.WriteValueU8(0); member.Members.Add(lastByteMember); } } else { var subMembersList = memberNode.Select("member"); foreach (XPathNavigator subMemberNode in subMembersList) { member.Members.Add(ImportInstanceMemberInfo(subMemberNode, adf)); } } return(member); }
static void Main(string[] args) { if (args.Length != 1) { Console.WriteLine("Usage:"); Console.WriteLine(" {0} file.stringlookup", GetExecutableName()); Console.WriteLine(" {0} file.xml", GetExecutableName()); return; } string inputPath = args[0]; if (Path.GetExtension(inputPath).ToLowerInvariant() == ".xml") // IMPORT { using (var input = File.OpenRead(inputPath)) { var doc = new XPathDocument(input); var nav = doc.CreateNavigator(); var root = nav.SelectSingleNode("/string-lookup"); if (root == null) { throw new FormatException(); } // retrieve the original extension as stored in the XML file var outputExtension = root.GetAttribute("extension", ""); string outputPath = Path.ChangeExtension(inputPath, outputExtension); AdfFile adf = Importer.Import(root); using (var output = File.Create(outputPath)) { output.Position = adf.EstimateHeaderSize(); adf.Serialize(output, 0); } } } else // EXPORT (to XML) { string outputPath = Path.ChangeExtension(inputPath, ".xml"); using (var input = File.OpenRead(inputPath)) { var adf = new AdfFile(Path.GetExtension(inputPath)); adf.Deserialize(input); var settings = new XmlWriterSettings { Indent = true, IndentChars = " ", CheckCharacters = false, }; using (var output = File.Create(outputPath)) { var writer = XmlWriter.Create(output, settings); Exporter.Export(adf, writer); writer.Flush(); } } } }
private static void ImportInstanceInfo(XPathNavigator instanceNode, AdfFile adf) { InstanceInfo instance = new InstanceInfo() { Name = instanceNode.GetAttribute("name", ""), NameHash = uint.Parse(instanceNode.GetAttribute("name-hash", "")), }; TypeDefinitionType type; Enum.TryParse(instanceNode.GetAttribute("type", ""), out type); uint typeHash = uint.Parse(instanceNode.GetAttribute("type-hash", ""), CultureInfo.InvariantCulture); string typeString = instanceNode.GetAttribute("type-name", ""); instance.Type = adf.Runtime.GetTypeDefinition(typeHash); instance.TypeHash = instance.Type.NameHash; if (!int.TryParse(instanceNode.GetAttribute("inline-array-copy-index", ""), out instance.InlineArrayIndex)) { instance.InlineArrayIndex = -1; } if (!uint.TryParse(instanceNode.GetAttribute("inline-array-copy-minsz", ""), out instance.MinInlineArraySize)) { instance.MinInlineArraySize = 0; } if (type != instance.Type.Type) { throw new InvalidOperationException("do not touch things like type and type-name in the xml file, yo"); } instance.Members = new List <AdfFile.InstanceMemberInfo>(); // Hold the contents of the last Array (A[int8]) List <byte> stringArray = new List <byte>(); // parse members instance.Members.Add(null); // prepare the future var memberNode = instanceNode.SelectSingleNode("member"); instance.Members[0] = (ImportInstanceMemberInfo(memberNode, instance, adf, stringArray)); var stringArrayMemberIndex = 0; foreach (var member in instance.Members) { if (member.Id == 2) { break; } ++stringArrayMemberIndex; } var stringArrayMember = instance.Members[stringArrayMemberIndex]; // Generate the string array (type is array of int8) foreach (byte b in stringArray) // the foreach is sooo overkill... { var subMember = new AdfFile.InstanceMemberInfo() { Type = TypeDefinitionType.Primitive, TypeHash = AdfTypeHashes.Primitive.Int8, Name = null, }; subMember.Data.WriteByte(b); stringArrayMember.Members.Add(subMember); } // add instance to ADF structure adf.AddInstanceInfo(instance); }
private static AdfFile.InstanceMemberInfo ImportTextOffset(XPathNavigator memberNode, AdfFile.InstanceMemberInfo member, InstanceInfo ii, AdfFile adf, List <byte> stringArray) { member.TypeHash = AdfTypeHashes.Primitive.UInt32; member.Data.WriteValueU32((uint)stringArray.Count); // write the offset byte[] str = Encoding.UTF8.GetBytes(memberNode.Value); stringArray.AddRange(str); stringArray.Add(0); // the null byte to terminate the string return(member); }
private static AdfFile.InstanceMemberInfo ImportInstanceMemberInfo(XPathNavigator memberNode, AdfFile.InstanceInfo ii, AdfFile adf, List <byte> stringArray) { AdfFile.InstanceMemberInfo member = new AdfFile.InstanceMemberInfo(); member.Name = memberNode.GetAttribute("name", ""); string stringId = memberNode.GetAttribute("id", ""); string ownIACopy = memberNode.GetAttribute("own-copy-of-inline-arrays", ""); if (!string.IsNullOrEmpty(stringId)) { member.Id = long.Parse(stringId, CultureInfo.InvariantCulture); } else { member.Id = -1; } member.isReferenceToId = !string.IsNullOrEmpty(memberNode.GetAttribute("is-reference", "")); if (!string.IsNullOrEmpty(ownIACopy)) { member.HasOwnCopyOfInlineArrays = true; } Enum.TryParse(memberNode.GetAttribute("gbltype", ""), out member.Type); string typeString = memberNode.GetAttribute("type", ""); if (member.Name == "TextOffset" || member.Name == "NameOffset") // hardcoded :( thingy to handle string lookup { return(ImportTextOffset(memberNode, member, ii, adf, stringArray)); } // Load the value if (member.Type == TypeDefinitionType.Primitive) { switch (typeString) { case "int8": member.Data.WriteValueS8(sbyte.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.Int8; break; case "uint8": member.Data.WriteValueU8(byte.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.UInt8; break; case "int16": member.Data.WriteValueS16(short.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.Int16; break; case "uint16": member.Data.WriteValueU16(ushort.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.UInt16; break; case "int32": member.Data.WriteValueS32(int.Parse(memberNode.Value, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.Int32; break; case "uint32": member.Data.WriteValueU32(uint.Parse(memberNode.Value, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.UInt32; break; case "int64": member.Data.WriteValueS64(long.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.Int64; break; case "uint64": member.Data.WriteValueU64(ulong.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.UInt64; break; case "float": member.Data.WriteValueF32(float.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.Float; break; case "double": member.Data.WriteValueF64(double.Parse(memberNode.Value, CultureInfo.InvariantCulture)); member.TypeHash = AdfTypeHashes.Primitive.Double; break; case "string": string strRef = memberNode.GetAttribute("reference-string-from", ""); if (!string.IsNullOrEmpty(strRef)) { member.ReferenceToString = true; member.StringTableId = int.Parse(strRef, CultureInfo.InvariantCulture); } member.StringData = memberNode.Value; member.TypeHash = AdfTypeHashes.String; break; } } else { uint typeHash = uint.Parse(memberNode.GetAttribute("type-hash", ""), CultureInfo.InvariantCulture); member.TypeDef = adf.Runtime.GetTypeDefinition(typeHash); member.TypeHash = typeHash; if (member.TypeDef.Type != member.Type) { throw new InvalidOperationException("do not touch things like type and type-name in the xml file, yo"); } if (member.Type == TypeDefinitionType.StringHash) { member.StringData = memberNode.Value; } if (member.Type == TypeDefinitionType.Array && member.isReferenceToId == true && member.Id != -1) { // No child, create an empty element if (!memberNode.HasChildren) { var subMember = new AdfFile.InstanceMemberInfo() { Name = member.Name, Id = member.Id, isReferenceToId = false, Type = member.Type, TypeHash = member.TypeHash, TypeDef = member.TypeDef, HasOwnCopyOfInlineArrays = false, // maybe _that_ will cause some issues... }; ii.Members.Add(subMember); return(member); } // the child node is in fact a global element. XPathNavigator subMemberNode = memberNode.SelectSingleNode("member"); ii.Members.Add(ImportInstanceMemberInfo(subMemberNode, ii, adf, stringArray)); return(member); } } // handle sub members var subMembersList = memberNode.Select("member"); foreach (XPathNavigator subMemberNode in subMembersList) { var subMember = ImportInstanceMemberInfo(subMemberNode, ii, adf, stringArray); if (member.Name != "SortedPairs") // another hardcoded thing { member.Members.Add(subMember); } else // insert the new member at the right place { subMember.Members[0].Data.Position = 0; uint hash = subMember.Members[0].Data.ReadValueU32(); subMember.Members[0].Data.Position = 0; int i = 0; for (; i < member.Members.Count; ++i) { member.Members[i].Members[0].Data.Position = 0; uint cmpHash = member.Members[i].Members[0].Data.ReadValueU32(); member.Members[i].Members[0].Data.Position = 0; if (cmpHash > hash) { break; } } member.Members.Insert(i, subMember); } } return(member); }
private static void Main(string[] args) { var mode = Mode.Unknown; bool showHelp = false; var typeLibraryPaths = new List <string>(); var options = new OptionSet { // ReSharper disable AccessToModifiedClosure { "e|export", "convert from binary to XML", v => SetOption(v, ref mode, Mode.Export) }, { "i|import", "convert from XML to binary", v => SetOption(v, ref mode, Mode.Import) }, // ReSharper restore AccessToModifiedClosure { "t|type-library=", "load type library from file", v => typeLibraryPaths.Add(v) }, { "h|help", "show this message and exit", v => showHelp = v != null }, }; 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 (mode == Mode.Unknown && extras.Count >= 1) { var extension = Path.GetExtension(extras[0]); if (extension != null && extension.ToLowerInvariant() == ".xml") { mode = Mode.Import; } else { mode = Mode.Export; } } if (extras.Count < 1 || extras.Count > 2 || showHelp == true || mode == Mode.Unknown) { Console.WriteLine("Usage: {0} [OPTIONS]+ [-e] input_adf [output_xml]", GetExecutableName()); Console.WriteLine(" {0} [OPTIONS]+ [-i] input_xml [output_adf]", GetExecutableName()); Console.WriteLine("Convert an ADF file between binary and XML format."); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } var runtime = new RuntimeTypeLibrary(); foreach (var typeLibraryPath in typeLibraryPaths) { var adf = new FileFormats.AdfFile(""); using (var input = File.OpenRead(typeLibraryPath)) { adf.Deserialize(input); } runtime.AddTypeDefinitions(adf); } if (mode == Mode.Export) { string inputPath = extras[0]; string outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(inputPath, ".xml"); using (var input = File.OpenRead(inputPath)) { var adf = new AdfFile(Path.GetExtension(inputPath)); adf.Deserialize(input); runtime.AddTypeDefinitions(adf); var settings = new XmlWriterSettings { Indent = true, IndentChars = " ", CheckCharacters = false, }; using (var output = File.Create(outputPath)) { var writer = XmlWriter.Create(output, settings); Exporter.Export(adf, writer /*, runtime, input, writer*/); writer.Flush(); } } } else if (mode == Mode.Import) { string inputPath = extras[0]; using (var input = File.OpenRead(inputPath)) { var doc = new XPathDocument(input); var nav = doc.CreateNavigator(); var root = nav.SelectSingleNode("/adf"); if (root == null) { throw new FormatException(); } // retrieve the original extension as stored in the XML file var outputExtension = root.GetAttribute("extension", ""); string outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(inputPath, outputExtension); AdfFile adf = Importer.Import(root); using (var output = File.Create(outputPath)) { output.Position = adf.EstimateHeaderSize(); adf.Serialize(output, 0); } } } }
private static void Main(string[] args) { var mode = Mode.Unknown; bool showHelp = false; var options = new OptionSet { // ReSharper disable AccessToModifiedClosure { "e|export", "convert from binary to JSON", v => SetOption(v, ref mode, Mode.Export) }, { "i|import", "convert from JSON to binary", v => SetOption(v, ref mode, Mode.Import) }, // ReSharper restore AccessToModifiedClosure { "h|help", "show this message and exit", v => showHelp = v != null }, }; 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 (mode == Mode.Unknown && extras.Count >= 1) { var extension = Path.GetExtension(extras[0]); if (extension != null && extension.ToLowerInvariant() == ".json") { mode = Mode.Import; } else { mode = Mode.Export; } } if (extras.Count < 1 || extras.Count > 2 || showHelp == true || mode == Mode.Unknown) { Console.WriteLine("Usage: {0} [OPTIONS]+ [-e] input_upgrade_onlinec [output_json]", GetExecutableName()); Console.WriteLine(" {0} [OPTIONS]+ [-i] input_json [output_upgrade_onlinec]", GetExecutableName()); Console.WriteLine("Convert an upgrade file between binary and JSON format."); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } if (mode == Mode.Export) { string inputPath = extras[0]; string outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(inputPath, ".json"); var adf = new FileFormats.AdfFile(); var itemRoot = new UpgradeRoot(); using (var input = File.OpenRead(inputPath)) { adf.Deserialize(input); var itemRootInfo = adf.InstanceInfos.FirstOrDefault(i => i.Name == "Profile"); if (itemRootInfo.TypeHash != UpgradeRoot.TypeHash) { throw new FormatException(); } input.Position = itemRootInfo.Offset; itemRoot.Deserialize(input, adf.Endian); } using (var output = File.Create(outputPath)) using (var textWriter = new StreamWriter(output)) using (var writer = new JsonTextWriter(textWriter)) { writer.Indentation = 2; writer.IndentChar = ' '; writer.Formatting = Formatting.Indented; var jsonItems = itemRoot.Upgrades.Select( u => { var jsonItem = new UpgradeRootJson.Upgrade() { Name = ResolveHash(adf, u.Name), TaskGroup = ResolveHash(adf, u.TaskGroup), StarThreshold = u.StarThreshold, Cost = u.Cost, Ability = ResolveHash(adf, u.Ability), UIName = ResolveHash(adf, u.UIName), UIDescription = ResolveHash(adf, u.UIDescription), UIDisplayOrder = u.UIDisplayOrder, UIImage = u.UIImage, UIVideo = u.UIVideo, UITreeName = ResolveHash(adf, u.UITreeName), UITreeOrder = u.UITreeOrder, }; jsonItem.Prerequisites.AddRange(u.Prerequisites.Select(f => ResolveHash(adf, f))); return(jsonItem); }).ToArray(); var serializer = JsonSerializer.Create(); serializer.Serialize(writer, jsonItems); } } else if (mode == Mode.Import) { string inputPath = extras[0]; string outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(inputPath, ".onlinec"); var adf = new AdfFile() { Endian = Endian.Little, }; var itemRoot = new UpgradeRoot(); using (var input = File.OpenRead(inputPath)) using (var textReader = new StreamReader(input)) using (var reader = new JsonTextReader(textReader)) { var serializer = JsonSerializer.Create(); var jsonItems = serializer.Deserialize <UpgradeRootJson.Upgrade[]>(reader); itemRoot.Upgrades.AddRange(jsonItems.Select( ju => new UpgradeRoot.Upgrade() { Name = ComputeHash(adf, ju.Name), TaskGroup = ComputeHash(adf, ju.TaskGroup), StarThreshold = ju.StarThreshold, Prerequisites = ju.Prerequisites.Select(f => ComputeHash(adf, f)).ToArray(), Cost = ju.Cost, Ability = ComputeHash(adf, ju.Ability), UIName = ComputeHash(adf, ju.UIName), UIDescription = ComputeHash(adf, ju.UIDescription), UIDisplayOrder = ju.UIDisplayOrder, UIImage = ju.UIImage, UIVideo = ju.UIVideo, UITreeName = ComputeHash(adf, ju.UITreeName), UITreeOrder = ju.UITreeOrder, })); } using (var output = File.Create(outputPath)) { using (var data = new MemoryStream()) { itemRoot.Serialize(data, adf.Endian); data.Flush(); data.Position = 0; output.Position = adf.EstimateHeaderSize(); var itemRootPosition = output.Position; output.WriteFromStream(data, data.Length); adf.InstanceInfos.Add(new AdfFile.InstanceInfo() { Name = "Profile", NameHash = "Profile".HashJenkins(), Offset = (uint)itemRootPosition, Size = (uint)data.Length, TypeHash = UpgradeRoot.TypeHash, }); adf.Serialize(output, 0); } } } else { throw new NotSupportedException(); } }
private void ADFExtractStrings(AdfFile adf) { // load strings from the hash string table foreach (var stringItem in adf.StringHashInfos) { AddString(stringItem.Value); } // load strings from type definitions (why ? because an ADF file can contain types that aren't used !) foreach (var typeDef in adf.TypeDefinitions) { AddString(typeDef.Name); if (typeDef.Type != AdfFile.TypeDefinitionType.Structure) { continue; } foreach (var member in typeDef.Members) { AddString(member.Name); } } // load strings from the instance members (unfold the whole tree) foreach (var instance in adf.InstanceInfos) { AddString(instance.Name); foreach (var rootMember in instance.Members) { var imiQueue = new Queue <AdfFile.InstanceMemberInfo>(); imiQueue.Enqueue(rootMember); while (imiQueue.Count > 0) { var member = imiQueue.Dequeue(); AddString(member.Name); AddString(member.StringData); // this is a special case for stringlookup files, where there's a sometime a // HUGE int8 array that contains and UTF-8 encoded string. // so for the sake of finding the more string, we will need to parse // int8 arrays that ends with a null byte // We may be poluted with strings from other languages... bool isString = false; if (member.Type == AdfFile.TypeDefinitionType.Array && !member.isReferenceToId && member.Members.Count > 0 && (member.TypeDef.ElementTypeHash == AdfTypeHashes.Primitive.Int8 || member.TypeDef.ElementTypeHash == AdfTypeHashes.Primitive.UInt8)) { // check if that's a string: it should end with \0 sbyte last = (sbyte)member.Members.Last().Data.ReadByte(); member.Members.Last().Data.Position = 0; if (last == 0) { isString = true; List <byte> accum = new List <byte>(); foreach (var character in member.Members) { byte current = (byte)character.Data.ReadByte(); if (current != 0) { accum.Add(current); } else // write the string { var str = Encoding.UTF8.GetString(accum.ToArray()); if (!this._StringLookupList.Contains(str)) { this._StringLookupList.Add(str); } accum.Clear(); } } } } // if that's not a hidden string array: if (!isString) { foreach (var subMember in member.Members) { imiQueue.Enqueue(subMember); } } } } } }
private void HandleStream(Stream file, string type) { file.Position = 0; if (type == "ADF") { // Got some AAF file bool inc = false; try { var adf = new AdfFile(); try { adf.Deserialize(file); ++ADFReadCount; } catch { inc = true; ++ADFSkipCount; } ADFExtractStrings(adf); } catch { if (!inc) { ++ADFSkipCount; } } } else if (type == "RTPC") { // Got some RTPC file try { var propertyContainerFile = new PropertyContainerFile(); propertyContainerFile.Deserialize(file); RTPCExtractStrings(propertyContainerFile); ++RTPCReadCount; } catch { ++RTPCSkipCount; } } else if (type == "AAF") { // Got some AAF Archive using (var cool = CreateCoolArchiveStream(file)) { var input = cool ?? file; var smallArchive = new SmallArchiveFile(); smallArchive.Deserialize(input); foreach (var entry in smallArchive.Entries) { this.AddString(entry.Name); if (entry.Offset == 0) { continue; } ++this.FileCount; this.PrintProgress(); input.Position = entry.Offset; string subtype = this.GetType(input); if (string.IsNullOrEmpty(subtype)) { continue; } using (var entryStream = entry.ReadToMemoryStream(input)) { this.HandleStream(entryStream, subtype); } } ++this.AAFExtractCount; } } }
private static void Main(string[] args) { var mode = Mode.Unknown; bool showHelp = false; var options = new OptionSet { // ReSharper disable AccessToModifiedClosure { "e|export", "convert from binary to JSON", v => SetOption(v, ref mode, Mode.Export) }, { "i|import", "convert from JSON to binary", v => SetOption(v, ref mode, Mode.Import) }, // ReSharper restore AccessToModifiedClosure { "h|help", "show this message and exit", v => showHelp = v != null }, }; 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 (mode == Mode.Unknown && extras.Count >= 1) { var extension = Path.GetExtension(extras[0]); if (extension != null && extension.ToLowerInvariant() == ".json") { mode = Mode.Import; } else { mode = Mode.Export; } } if (extras.Count < 1 || extras.Count > 2 || showHelp == true || mode == Mode.Unknown) { Console.WriteLine("Usage: {0} [OPTIONS]+ [-e] input_item_onlinec [output_json]", GetExecutableName()); Console.WriteLine(" {0} [OPTIONS]+ [-i] input_json [output_item_onlinec]", GetExecutableName()); Console.WriteLine("Convert an item file between binary and JSON format."); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } if (mode == Mode.Export) { string inputPath = extras[0]; string outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(inputPath, ".json"); var adf = new AdfFile(); var itemRoot = new ItemRoot(); using (var input = File.OpenRead(inputPath)) { adf.Deserialize(input); var itemRootInfo = adf.InstanceInfos.FirstOrDefault(i => i.Name == "Profile"); if (itemRootInfo.TypeHash != ItemRoot.TypeHash) { throw new FormatException(); } input.Position = itemRootInfo.Offset; itemRoot.Deserialize(input, adf.Endian); } using (var output = File.Create(outputPath)) using (var textWriter = new StreamWriter(output)) using (var writer = new JsonTextWriter(textWriter)) { writer.Indentation = 2; writer.IndentChar = ' '; writer.Formatting = Formatting.Indented; var jsonItems = itemRoot.Items.Select( i => { var jsonItem = new ItemRootJson.Item() { Name = ResolveHash(adf, i.Name), BaseName = ResolveHash(adf, i.BaseName), Type = i.Type, Purchasable = i.Purchasable, Consumable = i.Consumable, Rewardable = i.Rewardable, Collectable = i.Collectable, Region = ResolveHash(adf, i.Region), RebelDropTimer = i.RebelDropTimer, MaxInventory = i.MaxInventory, UIType = (UIItemType)i.UIType, UIFlag = (UIItemSubtype)i.UIFlag, UIDisplayOrder = i.UIDisplayOrder, UIName = ResolveHash(adf, i.UIName), UIDescription = ResolveHash(adf, i.UIDescription), UITypeDescription = ResolveHash(adf, i.UITypeDescription), UIFlagDescription = ResolveHash(adf, i.UIFlagDescription), UIImagePath = i.UIImagePath, UIVideoPath = i.UIVideoPath, UIPar0 = i.UIPar0, UIPar1 = i.UIPar1, UIPar2 = i.UIPar2, UIPar3 = i.UIPar3, UIPar4 = i.UIPar4, }; jsonItem.Feats.AddRange(i.Feats.Select(f => ResolveHash(adf, f))); return(jsonItem); }).ToArray(); var serializer = JsonSerializer.Create(); serializer.Serialize(writer, jsonItems); } } else if (mode == Mode.Import) { string inputPath = extras[0]; string outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(inputPath, ".onlinec"); var adf = new AdfFile() { Endian = Endian.Little, }; var itemRoot = new ItemRoot(); using (var input = File.OpenRead(inputPath)) using (var textReader = new StreamReader(input)) using (var reader = new JsonTextReader(textReader)) { var serializer = JsonSerializer.Create(); var jsonItems = serializer.Deserialize <ItemRootJson.Item[]>(reader); itemRoot.Items.AddRange(jsonItems.Select( ji => new ItemRoot.Item() { Name = ComputeHash(adf, ji.Name), BaseName = ComputeHash(adf, ji.BaseName), Type = ji.Type, Purchasable = ji.Purchasable, Consumable = ji.Consumable, Rewardable = ji.Rewardable, Collectable = ji.Collectable, Feats = ji.Feats.Select(f => ComputeHash(adf, f)).ToArray(), Region = ComputeHash(adf, ji.Region), RebelDropTimer = ji.RebelDropTimer, MaxInventory = ji.MaxInventory, UIType = (int)ji.UIType, UIFlag = (int)ji.UIFlag, UIDisplayOrder = ji.UIDisplayOrder, UIName = ComputeHash(adf, ji.UIName), UIDescription = ComputeHash(adf, ji.UIDescription), UITypeDescription = ComputeHash(adf, ji.UITypeDescription), UIFlagDescription = ComputeHash(adf, ji.UIFlagDescription), UIImagePath = ji.UIImagePath, UIVideoPath = ji.UIVideoPath, UIPar0 = ji.UIPar0, UIPar1 = ji.UIPar1, UIPar2 = ji.UIPar2, UIPar3 = ji.UIPar3, UIPar4 = ji.UIPar4, })); } using (var output = File.Create(outputPath)) { using (var data = new MemoryStream()) { itemRoot.Serialize(data, adf.Endian); data.Flush(); data.Position = 0; output.Position = adf.EstimateHeaderSize(); var itemRootPosition = output.Position; output.WriteFromStream(data, data.Length); adf.InstanceInfos.Add(new AdfFile.InstanceInfo() { Name = "Profile", NameHash = "Profile".HashJenkins(), Offset = (uint)itemRootPosition, Size = (uint)data.Length, TypeHash = ItemRoot.TypeHash, }); adf.Serialize(output, 0); } } } else { throw new NotSupportedException(); } }
private void HandleStream(Stream file, string type) { // flush if the limit is reached if (this._EntryCount > 300000) { this.flush(); } //file.Position = 0; if (type == "ADF") { // Got some AAF file bool inc = false; try { var adf = new AdfFile(); try { adf.Deserialize(file); ++ADFReadCount; } catch { inc = true; ++ADFSkipCount; } ADFExtractStrings(adf); } catch { if (!inc) { ++ADFSkipCount; } } } else if (type == "RTPC") { // Got some RTPC file try { var propertyContainerFile = new PropertyContainerFile(); propertyContainerFile.Deserialize(file); RTPCExtractStrings(propertyContainerFile); ++RTPCReadCount; } catch { ++RTPCSkipCount; } } else if (type == "AAF") { // Got some AAF Archive using (var cool = CreateCoolArchiveStream(file)) { var input = cool ?? file; var smallArchive = new SmallArchiveFile(); smallArchive.Deserialize(input); this._CurrentFile.Add(null); foreach (var entry in smallArchive.Entries) { this.AddString(entry.Name); if (entry.Offset == 0) { continue; } ++this.FileCount; this.PrintProgress(); input.Position = entry.Offset; string subtype = this.GetType(input); if (string.IsNullOrEmpty(subtype)) { continue; } // insert the name this._CurrentFile[this._CurrentFile.Count - 1] = entry.Name; this.UpdateCurrentFile(); // process the file using (var entryStream = entry.ReadToMemoryStream(input)) { // I know that this copies a copy of a memory (that's a stupid thing) // but without this the memories goes crazy and if I force GC Collect // that's even worse. So a little copy doesn't look bad in front of // the horrors produced when you don't have it. // to see what it's like, replace entryStream with input. this.HandleStream(entryStream, subtype); } } this._CurrentFile.RemoveAt(this._CurrentFile.Count - 1); ++this.AAFExtractCount; } } }