diff --git a/UIXC/Properties/launchSettings.json b/UIXC/Properties/launchSettings.json index 3b316ad..2a51a7f 100644 --- a/UIXC/Properties/launchSettings.json +++ b/UIXC/Properties/launchSettings.json @@ -2,7 +2,12 @@ "profiles": { "UIXC": { "commandName": "Project", - "commandLineArgs": "decompile C:\\Users\\jjask\\Documents\\Dump\\Zune\\ZuneShellResources\\AboutDialog.uix -l xml -A ZuneShell.dll -A UIXControls.dll -A ZuneDBApi.dll -o C:\\Users\\jjask\\Documents\\Dump\\Zune\\ZuneShellResources_xml -t C:\\Users\\jjask\\Documents\\Dump\\Zune\\ZuneShellResources\\_DATATABLE.uib", + + "commandLineArgs": "decompile E:\\Repos\\ZuneDev\\ZuneUIXTools\\test\\ABOUTDIALOG.31_48.UIB -l xml -A ZuneShell.dll -A UIXControls.dll -A ZuneDBApi.dll -o E:\\Repos\\ZuneDev\\ZuneUIXTools\\test", + //"commandLineArgs": "compile E:\\Repos\\ZuneDev\\ZuneUIXTools\\test\\ADDTOCOLLECTION.31_48.UIX -A ZuneShell.dll -A UIXControls.dll -A ZuneDBApi.dll -o E:\\Repos\\ZuneDev\\ZuneUIXTools\\test", + + //"commandLineArgs": "decompile E:\\Documents\\REProj\\Zune\\Resources\\ZuneShellResources48\\ABOUTDIALOG.UIX -l xml -A ZuneShell.dll -A UIXControls.dll -A ZuneDBApi.dll -o E:\\Documents\\REProj\\Zune\\Resources\\ZuneShellResources48_xml -t E:\\Documents\\REProj\\Zune\\Resources\\ZuneShellResources48\\_DATATABLE.uib", + //"commandLineArgs": "decompile C:\\Users\\jjask\\Documents\\Dump\\Zune\\ZuneShellResources\\AboutDialog.uix -l xml -A ZuneShell.dll -A UIXControls.dll -A ZuneDBApi.dll -o C:\\Users\\jjask\\Documents\\Dump\\Zune\\ZuneShellResources_xml -t C:\\Users\\jjask\\Documents\\Dump\\Zune\\ZuneShellResources\\_DATATABLE.uib", //"commandLineArgs": "decompile C:\\Users\\jjask\\Documents\\Dump\\Zune\\ZuneShellResources -l xml -A ZuneShell.dll -A UIXControls.dll -A ZuneDBApi.dll -o C:\\Users\\jjask\\Documents\\Dump\\Zune\\ZuneShellResources_xml -t C:\\Users\\jjask\\Documents\\Dump\\Zune\\ZuneShellResources\\_DATATABLE.uib", //"commandLineArgs": "decompile C:\\Users\\jjask\\Documents\\Dump\\Zune\\ZuneShellResources\\_DATATABLE.UIB -A ZuneShell.dll -A UIXControls.dll -A ZuneDBApi.dll -o C:\\Users\\jjask\\Documents\\Dump\\Zune\\ZuneShellResources_uixa", diff --git a/UIXC/SourceLanguage.cs b/UIXC/SourceLanguage.cs index 88a2d2c..064ef8b 100644 --- a/UIXC/SourceLanguage.cs +++ b/UIXC/SourceLanguage.cs @@ -14,7 +14,7 @@ public static class SourceLanguageEx SourceLanguage.Xml => ".uix", SourceLanguage.Asm => ".uixa", - _ => throw new ArgumentException("Invalid source langauge", nameof(sourceLanguage)), + _ => throw new ArgumentException("Invalid source language", nameof(sourceLanguage)), }; } } diff --git a/libs/UIX.Asm/Disassembler.cs b/libs/UIX.Asm/Disassembler.cs index ca6d8f0..85388d8 100644 --- a/libs/UIX.Asm/Disassembler.cs +++ b/libs/UIX.Asm/Disassembler.cs @@ -314,7 +314,7 @@ public class Disassembler } } - private static IEnumerable EnumerateConstantInfo(MarkupLoadResult loadResult) + public static IEnumerable EnumerateConstantInfo(MarkupLoadResult loadResult) { var constantsTable = loadResult.ConstantsTable; bool hasPersistList = constantsTable.PersistList is not null; @@ -419,7 +419,7 @@ public class Disassembler throw new NotSupportedException($"Unable to encode constant value '{constantValue}' of type '{qualifiedTypeName}'"); } - private record RawConstantInfo(int Index, TypeSchema Type, object Value) + public record RawConstantInfo(int Index, TypeSchema Type, object Value) { public string GenerateDefaultName() => $"const{Index:D}"; } diff --git a/libs/UIX.DecompXml/Decompiler.cs b/libs/UIX.DecompXml/Decompiler.cs index d199a43..5566982 100644 --- a/libs/UIX.DecompXml/Decompiler.cs +++ b/libs/UIX.DecompXml/Decompiler.cs @@ -1,7 +1,6 @@ using Humanizer; using Microsoft.Iris.Asm; using Microsoft.Iris.Asm.Models; -using Microsoft.Iris.DecompXml.Mock; using Microsoft.Iris.Markup; using System; using System.Collections.Generic; @@ -20,6 +19,7 @@ public class Decompiler private readonly Dictionary _namespaces; private readonly Dictionary _uriAliasMap; private Instruction[] _instructions; + private Disassembler.RawConstantInfo[] _constants; private Decompiler(MarkupLoadResult loadResult, MarkupLoadResult dataTableLoadResult = null) { @@ -74,6 +74,8 @@ public class Decompiler .OfType() .ToArray(); + _constants = Disassembler.EnumerateConstantInfo(_loadResult).ToArray(); + XNamespace nsUix = XNamespace.Get("http://schemas.microsoft.com/2007/uix"); XElement xRoot = new(nsUix + "UIX", new XAttribute("xmlns", nsUix)); @@ -88,37 +90,66 @@ public class Decompiler new XAttribute("Name", name), new XAttribute("Base", baseTypeName)); - var initPropOffset = export.InitializePropertiesOffset; - - var defaultType = export.ConstructDefault(); - var initializedType = export.ConstructDefault(); - try - { - export.InitializeInstance(ref initializedType); - } - catch { } + var initPropsOffset = export.InitializePropertiesOffset; + var initPropsBody = _instructions + .SkipWhile(i => i.Offset < initPropsOffset) + .OrderBy(i => i.Offset) + .TakeWhile(i => i.OpCode is not (OpCode.ReturnValue or OpCode.ReturnVoid)) + .OrderBy(i => i.Offset) + .ToArray(); var propertyElements = new XElement[export.Properties.Length]; - for (int i = 0; i < export.Properties.Length; i++) + + Stack xStack = new([xExport]); + Stack constantsStack = new(); + + for (int i = 0; i < initPropsBody.Length; i++) { - PropertySchema property = export.Properties[i]; - var typeName = GetXName(property.PropertyType); + var instruction = initPropsBody[i]; - // TODO: Decode object section to get default property assignments - XElement xProperty = new(typeName, - new XAttribute("Name", property.Name)); + if (instruction.OpCode is OpCode.JumpIfDictionaryContains) + { + } + else if (instruction.OpCode is OpCode.PushConstant) + { + var constantOperand = (OperandReference)instruction.Operands.First(); + var constant = _constants[constantOperand.Index]; + constantsStack.Push(constant); + //xStack.Push(IntoXNode(constant.Value)); + } + else if (instruction.OpCode is OpCode.PushNull) + { + constantsStack.Push(null); + //xStack.Push(IntoXNode(null)); + } + else if (instruction.OpCode is OpCode.PropertyDictionaryAdd) + { + var targetProperty = _loadResult.ImportTables.PropertyImports[(ushort)instruction.Operands.ElementAt(0).Value]; - var defaultValue = property.GetValue(defaultType); - var initializedValue = property.GetValue(initializedType); - if (defaultValue != initializedValue) - xProperty.Add(new XAttribute("TODO_DEFAULT", initializedValue)); + var keyReference = (OperandReference)instruction.Operands.ElementAt(1); + var key = _constants[keyReference.Index].Value.ToString(); - propertyElements[i] = xProperty; + //var xValue = xStack.Pop(); + var value = constantsStack.Pop(); + + var targetInstance = xStack.Peek() as XElement; + var xDictionary = GetOrCreateElement(targetInstance, nsUix + targetProperty.Name); + + XElement xDictionaryEntry = new(GetXName(value.Type)); + xDictionaryEntry.SetAttributeValue("Name", key); + xDictionary.Add(xDictionaryEntry); + + if (value.Value is IStringEncodable valStrEnc) + { + xDictionaryEntry.SetAttributeValue(value.Type.Name, valStrEnc); + } + else + { + xDictionaryEntry.SetAttributeValue(value.Type.Name, value.Value.ToString()); + } + } } - XElement xProperties = new(nsUix + "Properties", propertyElements); - xExport.Add(xProperties); - xRoot.Add(xExport); } @@ -239,6 +270,33 @@ public class Decompiler return ns + schema.Name; } + private XElement GetOrCreateElement(XElement parent, XName name) + { + var elem = parent.Element(name); + + if (elem is null) + { + elem = new XElement(name); + parent.Add(elem); + } + + return elem; + } + + private XNode IntoXNode(object obj) + { + if (obj is null) + return new XText("{null}"); + + return obj switch + { + string str => new XText(str), + IStringEncodable strEnc => new XText(strEnc.EncodeString()), + + _ => throw new InvalidOperationException($"Cannot convert type '{obj.GetType().Name}' to an XNode") + }; + } + [MemberNotNullWhen(true, nameof(_dataTableLoadResult))] private bool UseSharedDataTable => _dataTableLoadResult is not null; }