public void Export(FieldDefinition fieldDef, FieldType arrayFieldType, byte[] data, int offset, int count, XmlWriter writer, out int read) { if (Helpers.HasLeft(data, 0, data.Length, 5) == false) { throw new FormatException("Rml requires at least 5 bytes"); } var rez = new XmlResourceFile(); using (var input = new MemoryStream(data, 0, data.Length, false)) { rez.Deserialize(input); read = data.Length; } writer.WriteStartElement("rml"); ConvertXml.Program.WriteNode(writer, rez.Root); writer.WriteEndElement(); }
public byte[] Import(FieldDefinition def, FieldType arrayFieldType, System.Xml.XPath.XPathNavigator nav) { var rml = new XmlResourceFile { Root = ConvertXml.Program.ReadNode(nav.SelectSingleNode("rml/*")) }; using (var temp = new MemoryStream()) { rml.Serialize(temp); temp.Position = 0; return(temp.ReadBytes((uint)temp.Length)); } }
public static void Main(string[] args) { var mode = Mode.Unknown; bool showHelp = false; OptionSet options = new OptionSet() { { "rml", "convert XML to RML", v => mode = v != null ? Mode.ToRML : mode }, { "xml", "convert RML to XML", v => mode = v != null ? Mode.ToXML : mode }, { "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 == ".rml") { mode = Mode.ToXML; } else if (extension == ".xml") { mode = Mode.ToRML; } } if (showHelp == true || mode == Mode.Unknown || extras.Count < 1 || extras.Count > 2) { Console.WriteLine("Usage: {0} [OPTIONS]+ input [output]", GetExecutableName()); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } if (mode == Mode.ToRML) { string inputPath = extras[0]; string outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(Path.ChangeExtension(inputPath, null) + "_converted", ".rml"); var rez = new XmlResourceFile(); using (var input = File.OpenRead(inputPath)) { var doc = new XPathDocument(input); var nav = doc.CreateNavigator(); if (nav.MoveToFirstChild() == false) { throw new FormatException(); } rez.Root = ReadNode(nav); } using (var output = File.Create(outputPath)) { rez.Serialize(output); } } else if (mode == Mode.ToXML) { string inputPath = extras[0]; string outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(Path.ChangeExtension(inputPath, null) + "_converted", ".xml"); var rez = new XmlResourceFile(); using (var input = File.OpenRead(inputPath)) { rez.Deserialize(input); } var settings = new XmlWriterSettings(); settings.Encoding = Encoding.UTF8; settings.Indent = true; settings.OmitXmlDeclaration = true; using (var writer = XmlWriter.Create(outputPath, settings)) { writer.WriteStartDocument(); WriteNode(writer, rez.Root); writer.WriteEndDocument(); } } else { throw new InvalidOperationException(); } }
private static void WriteNode( XmlWriter writer, BinaryResourceFile.Object node, IDefinitionProvider provider) { var def = provider.GetClassDefinition(node.TypeHash); writer.WriteStartElement("object"); if (def.Name != null) { writer.WriteAttributeString("type", def.Name); } else { writer.WriteAttributeString("hash", node.TypeHash.ToString("X8")); } if (node.Values != null && node.Values.Count > 0) { foreach (var kv in node.Values) { writer.WriteStartElement("value"); var member = def.GetMemberDefinition(kv.Key); if (member != null && member.Name != null) { writer.WriteAttributeString("name", member.Name); } else { writer.WriteAttributeString("hash", kv.Key.ToString("X8")); } if (member == null) { writer.WriteAttributeString("type", MemberType.BinHex.ToString()); writer.WriteBinHex(kv.Value, 0, kv.Value.Length); } else { writer.WriteAttributeString("type", member.Type.ToString()); switch (member.Type) { case MemberType.BinHex: { writer.WriteBinHex(kv.Value, 0, kv.Value.Length); break; } case MemberType.Hash: { if (kv.Value.Length != 4) { throw new FormatException(); } writer.WriteString(BitConverter.ToUInt32(kv.Value, 0).ToString("X8", CultureInfo.InvariantCulture)); break; } case MemberType.String: { if (kv.Value.Length < 1) { throw new FormatException(); } else if (kv.Value[kv.Value.Length - 1] != 0) { throw new FormatException(); } writer.WriteString(Encoding.UTF8.GetString(kv.Value, 0, kv.Value.Length - 1)); break; } case MemberType.Enum: { if (kv.Value.Length != 4) { throw new FormatException(); } writer.WriteString(BitConverter.ToUInt32(kv.Value, 0).ToString(CultureInfo.InvariantCulture)); break; } case MemberType.Bool: { if (kv.Value.Length != 1) { throw new FormatException(); } writer.WriteString((kv.Value[0] != 0 ? true : false).ToString()); break; } case MemberType.Float: { if (kv.Value.Length != 4) { throw new FormatException(); } writer.WriteString(BitConverter.ToSingle(kv.Value, 0).ToString(CultureInfo.InvariantCulture)); break; } case MemberType.Int32: { if (kv.Value.Length != 4) { throw new FormatException(); } writer.WriteString(BitConverter.ToInt32(kv.Value, 0).ToString(CultureInfo.InvariantCulture)); break; } case MemberType.UInt32: { if (kv.Value.Length != 4) { throw new FormatException(); } writer.WriteString(BitConverter.ToUInt32(kv.Value, 0).ToString(CultureInfo.InvariantCulture)); break; } case MemberType.Int64: { if (kv.Value.Length != 8) { throw new FormatException(); } writer.WriteString(BitConverter.ToInt64(kv.Value, 0).ToString(CultureInfo.InvariantCulture)); break; } case MemberType.UInt64: { if (kv.Value.Length != 8) { throw new FormatException(); } writer.WriteString(BitConverter.ToUInt64(kv.Value, 0).ToString(CultureInfo.InvariantCulture)); break; } case MemberType.Vector2: { if (kv.Value.Length != 4 * 2) { throw new FormatException(); } writer.WriteElementString("x", BitConverter.ToSingle(kv.Value, 0).ToString(CultureInfo.InvariantCulture)); writer.WriteElementString("y", BitConverter.ToSingle(kv.Value, 4).ToString(CultureInfo.InvariantCulture)); break; } case MemberType.Vector3: { if (kv.Value.Length != 4 * 3) { throw new FormatException(); } writer.WriteElementString("x", BitConverter.ToSingle(kv.Value, 0).ToString(CultureInfo.InvariantCulture)); writer.WriteElementString("y", BitConverter.ToSingle(kv.Value, 4).ToString(CultureInfo.InvariantCulture)); writer.WriteElementString("z", BitConverter.ToSingle(kv.Value, 8).ToString(CultureInfo.InvariantCulture)); break; } case MemberType.Vector4: { if (kv.Value.Length != 4 * 4) { throw new FormatException(); } writer.WriteElementString("x", BitConverter.ToSingle(kv.Value, 0).ToString(CultureInfo.InvariantCulture)); writer.WriteElementString("y", BitConverter.ToSingle(kv.Value, 4).ToString(CultureInfo.InvariantCulture)); writer.WriteElementString("z", BitConverter.ToSingle(kv.Value, 8).ToString(CultureInfo.InvariantCulture)); writer.WriteElementString("w", BitConverter.ToSingle(kv.Value, 12).ToString(CultureInfo.InvariantCulture)); break; } case MemberType.UInt32Array: { if (kv.Value.Length < 4) { throw new FormatException(); } var count = BitConverter.ToInt32(kv.Value, 0); if (kv.Value.Length != 4 + (count * 4)) { throw new FormatException(); } for (int i = 0, offset = 4; i < count; i++, offset += 4) { writer.WriteElementString("item", BitConverter.ToUInt32(kv.Value, offset).ToString(CultureInfo.InvariantCulture)); } break; } case MemberType.HashArray: { if (kv.Value.Length < 4) { throw new FormatException(); } var count = BitConverter.ToInt32(kv.Value, 0); if (kv.Value.Length != 4 + (count * 4)) { throw new FormatException(); } for (int i = 0, offset = 4; i < count; i++, offset += 4) { writer.WriteElementString("item", BitConverter.ToUInt32(kv.Value, offset).ToString("X8")); } break; } case MemberType.Rml: { var rez = new XmlResourceFile(); using (var input = new MemoryStream(kv.Value)) { rez.Deserialize(input); } writer.WriteStartElement("rml"); ConvertXml.Program.WriteNode(writer, rez.Root); writer.WriteEndElement(); break; } default: { throw new NotSupportedException(); } } } writer.WriteEndElement(); } } if (node.Children != null && node.Children.Count > 0) { foreach (var child in node.Children) { WriteNode(writer, child, def); } } writer.WriteEndElement(); }
private static BinaryResourceFile.Object ReadNode(string basePath, XPathNavigator node) { string className; uint classHash; Definitions.LoadTypeAndHash(node, out className, out classHash); var parent = new BinaryResourceFile.Object(); parent.TypeHash = classHash; var values = node.Select("value"); while (values.MoveNext() == true) { string valueName; uint valueHash; Definitions.LoadNameAndHash(values.Current, out valueName, out valueHash); MemberType valueType; string _valueType; _valueType = values.Current.GetAttribute("type", ""); if (string.IsNullOrWhiteSpace(_valueType) == true || Enum.IsDefined(typeof(MemberType), _valueType) == false) { throw new FormatException(); } valueType = (MemberType)Enum.Parse(typeof(MemberType), _valueType); byte[] valueData; switch (valueType) { case MemberType.BinHex: { using (var reader = new XmlTextReader(new StringReader(values.Current.OuterXml))) { reader.MoveToContent(); valueData = new byte[0]; int read = 0; do { Array.Resize(ref valueData, valueData.Length + 4096); read += reader.ReadBinHex(valueData, read, 4096); }while (reader.EOF == false); Array.Resize(ref valueData, read); } break; } case MemberType.Hash: { valueData = BitConverter.GetBytes(uint.Parse(values.Current.Value, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture)); break; } case MemberType.String: { valueData = Encoding.UTF8.GetBytes(values.Current.Value); Array.Resize(ref valueData, valueData.Length + 1); break; } case MemberType.Enum: { valueData = BitConverter.GetBytes(uint.Parse(values.Current.Value, CultureInfo.InvariantCulture)); break; } case MemberType.Bool: { valueData = new byte[1]; valueData[0] = (byte)(bool.Parse(values.Current.Value) == true ? 1 : 0); break; } case MemberType.Int32: { valueData = BitConverter.GetBytes(int.Parse(values.Current.Value, CultureInfo.InvariantCulture)); break; } case MemberType.UInt32: { valueData = BitConverter.GetBytes(uint.Parse(values.Current.Value, CultureInfo.InvariantCulture)); break; } case MemberType.Int64: { valueData = BitConverter.GetBytes(long.Parse(values.Current.Value, CultureInfo.InvariantCulture)); break; } case MemberType.UInt64: { valueData = BitConverter.GetBytes(ulong.Parse(values.Current.Value, CultureInfo.InvariantCulture)); break; } case MemberType.Float: { valueData = BitConverter.GetBytes(float.Parse(values.Current.Value, CultureInfo.InvariantCulture)); break; } case MemberType.Vector2: { valueData = new byte[8]; Array.Copy(BitConverter.GetBytes(float.Parse(values.Current.SelectSingleNode("x").Value, CultureInfo.InvariantCulture)), 0, valueData, 0, 4); Array.Copy(BitConverter.GetBytes(float.Parse(values.Current.SelectSingleNode("y").Value, CultureInfo.InvariantCulture)), 0, valueData, 4, 4); break; } case MemberType.Vector3: { valueData = new byte[12]; Array.Copy(BitConverter.GetBytes(float.Parse(values.Current.SelectSingleNode("x").Value, CultureInfo.InvariantCulture)), 0, valueData, 0, 4); Array.Copy(BitConverter.GetBytes(float.Parse(values.Current.SelectSingleNode("y").Value, CultureInfo.InvariantCulture)), 0, valueData, 4, 4); Array.Copy(BitConverter.GetBytes(float.Parse(values.Current.SelectSingleNode("z").Value, CultureInfo.InvariantCulture)), 0, valueData, 8, 4); break; } case MemberType.Vector4: { valueData = new byte[16]; Array.Copy(BitConverter.GetBytes(float.Parse(values.Current.SelectSingleNode("x").Value, CultureInfo.InvariantCulture)), 0, valueData, 0, 4); Array.Copy(BitConverter.GetBytes(float.Parse(values.Current.SelectSingleNode("y").Value, CultureInfo.InvariantCulture)), 0, valueData, 4, 4); Array.Copy(BitConverter.GetBytes(float.Parse(values.Current.SelectSingleNode("z").Value, CultureInfo.InvariantCulture)), 0, valueData, 8, 4); Array.Copy(BitConverter.GetBytes(float.Parse(values.Current.SelectSingleNode("w").Value, CultureInfo.InvariantCulture)), 0, valueData, 12, 4); break; } case MemberType.Rml: { var rez = new XmlResourceFile(); var nav = values.Current.SelectSingleNode("rml"); rez.Root = ConvertXml.Program.ReadNode(nav); using (var output = new MemoryStream()) { rez.Serialize(output); output.Position = 0; valueData = new byte[output.Length]; output.Read(valueData, 0, valueData.Length); } break; } default: { throw new FormatException(); } } parent.Values.Add(valueHash, valueData); } var children = node.Select("object"); while (children.MoveNext() == true) { parent.Children.Add(LoadNode(basePath, children.Current)); } return(parent); }
public static byte[] Serialize(FieldDefinition fieldDef, FieldType fieldType, FieldType arrayFieldType, XPathNavigator nav) { switch (fieldType) { case FieldType.BinHex: { using (var reader = new XmlTextReader(new StringReader(nav.OuterXml))) { reader.MoveToContent(); var data = new byte[0]; int read = 0; do { Array.Resize(ref data, data.Length + 4096); read += reader.ReadBinHex(data, read, 4096); }while (reader.EOF == false); Array.Resize(ref data, read); return(data); } } case FieldType.Boolean: case FieldType.UInt8: case FieldType.Int8: case FieldType.UInt16: case FieldType.Int16: case FieldType.UInt32: case FieldType.Int32: case FieldType.UInt64: case FieldType.Int64: case FieldType.Float32: case FieldType.Float64: case FieldType.Vector2: case FieldType.Vector3: case FieldType.Vector4: case FieldType.String: { return(Serialize(fieldType, nav.Value)); } case FieldType.Enum: { var enumDef = fieldDef != null ? fieldDef.Enum : null; var text = nav.Value; var elementDef = enumDef != null ? enumDef.Elements.FirstOrDefault(ed => ed.Name == text) : null; int value; if (elementDef != null) { value = elementDef.Value; } else { if (TryParseInt32(nav.Value, out value) == false) { if (enumDef == null) { throw new FormatException( string.Format( "could not parse enum value '{0}' as an Int32 (perhaps enum definition is missing?)", nav.Value)); } throw new FormatException( string.Format( "could not parse enum value '{0}' as an Int32 (perhaps enum element definition is missing from {1}?)", nav.Value, enumDef.Name)); } } return(BitConverter.GetBytes(value)); } case FieldType.Hash32: case FieldType.Hash64: case FieldType.Id32: case FieldType.Id64: { return(Serialize(fieldType, nav.Value)); } case FieldType.Rml: { var rml = new XmlResourceFile { Root = ConvertXml.Program.ReadNode(nav.SelectSingleNode("rml/*")) }; using (var temp = new MemoryStream()) { rml.Serialize(temp); temp.Position = 0; return(temp.ReadBytes((uint)temp.Length)); } } case FieldType.ComputeHash32: { return(Serialize(fieldType, nav.Value)); } case FieldType.ComputeHash64: { return(Serialize(fieldType, nav.Value)); } case FieldType.Array32: { using (var temp = new MemoryStream()) { var items = nav.Select("item"); temp.WriteValueS32(items.Count); while (items.MoveNext() == true) { temp.WriteBytes(Serialize(arrayFieldType, items.Current.Value)); } return(temp.ToArray()); } } } throw new NotSupportedException("unsupported field type"); }
public static void Deserialize(XmlWriter writer, FieldDefinition fieldDef, byte[] data) { int read; switch (fieldDef.Type) { case FieldType.BinHex: { writer.WriteBinHex(data, 0, data.Length); read = data.Length; break; } case FieldType.Boolean: case FieldType.UInt8: case FieldType.Int8: case FieldType.UInt16: case FieldType.Int16: case FieldType.UInt32: case FieldType.Int32: case FieldType.UInt64: case FieldType.Int64: case FieldType.Float32: case FieldType.Float64: case FieldType.Vector2: case FieldType.Vector3: case FieldType.Vector4: case FieldType.String: case FieldType.Hash32: case FieldType.Hash64: case FieldType.Id32: case FieldType.Id64: { Deserialize(writer, fieldDef.Type, data, 0, data.Length, out read); break; } case FieldType.Enum: { var value = Deserialize <int>(fieldDef.Type, data, 0, data.Length, out read); if (fieldDef.Enum != null) { var enumDef = fieldDef.Enum.Elements.FirstOrDefault(ed => ed.Value == value); if (enumDef != null) { writer.WriteString(enumDef.Name); break; } } writer.WriteString(value.ToString(CultureInfo.InvariantCulture)); break; } case FieldType.Rml: { if (HasLeft(data, 0, data.Length, 5) == false) { throw new FormatException("field type Rml requires at least 5 bytes"); } var rez = new XmlResourceFile(); using (var input = new MemoryStream(data, 0, data.Length, false)) { rez.Deserialize(input); read = data.Length; } writer.WriteStartElement("rml"); ConvertXml.Program.WriteNode(writer, rez.Root); writer.WriteEndElement(); break; } case FieldType.Array32: { if (HasLeft(data, 0, data.Length, 4) == false) { throw new FormatException("field type Array32 requires at least 4 bytes"); } var itemCount = BitConverter.ToUInt32(data, 0); read = 4; int offset = 4; int remaining = data.Length - offset; for (uint i = 0; i < itemCount; i++) { writer.WriteStartElement("item"); int itemRead; Deserialize(writer, fieldDef.ArrayType, data, offset, remaining, out itemRead); offset += itemRead; remaining -= itemRead; writer.WriteEndElement(); read += itemRead; } break; } default: { throw new NotSupportedException("unsupported field type"); } } if (read != data.Length) { if (string.IsNullOrEmpty(fieldDef.Name) == false) { throw new FormatException( string.Format("did not consume all data for field '{0}' (read {1}, total {2})", fieldDef.Name, read, data.Length)); } throw new FormatException( string.Format("did not consume all data for field 0x{0:X8} (read {1}, total {2})", fieldDef.Hash, read, data.Length)); } }