diff --git a/Debugger/ILSpy.Debugger/Services/ImageService/ImageService.cs b/Debugger/ILSpy.Debugger/Services/ImageService/ImageService.cs index 7a5fc14a1..a71f1ad67 100644 --- a/Debugger/ILSpy.Debugger/Services/ImageService/ImageService.cs +++ b/Debugger/ILSpy.Debugger/Services/ImageService/ImageService.cs @@ -27,7 +27,7 @@ namespace ICSharpCode.ILSpy.Debugger.Services static BitmapImage LoadBitmap(string name) { try { - BitmapImage image = new BitmapImage(new Uri("pack://application:,,,/ILSpy.Debugger;component/Images/" + name + ".png")); + BitmapImage image = new BitmapImage(new Uri("pack://application:,,,/ILSpy.Debugger.Plugin;component/Images/" + name + ".png")); if (image == null) return null; image.Freeze(); diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index 2a2af5d2c..0927ec865 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -301,6 +301,7 @@ namespace ICSharpCode.Decompiler.Ast } } else { EnumMemberDeclaration enumMember = new EnumMemberDeclaration(); + enumMember.AddAnnotation(field); enumMember.Name = CleanName(field.Name); long memberValue = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false); if (forcePrintingInitializers || memberValue != expectedEnumMemberValue) { diff --git a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs index 1958b083a..dfeff794e 100644 --- a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs @@ -349,8 +349,7 @@ namespace ICSharpCode.Decompiler.Ast } #endregion #region Arrays - case ILCode.Newarr: - case ILCode.InitArray: { + case ILCode.Newarr: { var ace = new Ast.ArrayCreateExpression(); ace.Type = operandAsTypeRef; ComposedType ct = operandAsTypeRef as ComposedType; @@ -366,7 +365,39 @@ namespace ICSharpCode.Decompiler.Ast } return ace; } - case ILCode.Ldlen: return arg1.Member("Length"); + case ILCode.InitArray: { + var ace = new Ast.ArrayCreateExpression(); + ace.Type = operandAsTypeRef; + ComposedType ct = operandAsTypeRef as ComposedType; + var arrayType = (ArrayType) operand; + if (ct != null) + { + // change "new (int[,])[10] to new int[10][,]" + ct.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers); + ace.Initializer = new ArrayInitializerExpression(); + var first = ace.AdditionalArraySpecifiers.First(); + first.Remove(); + ace.Arguments.AddRange(Enumerable.Repeat(0, first.Dimensions).Select(i => new EmptyExpression())); + } + var newArgs = new List(); + foreach (var arrayDimension in arrayType.Dimensions.Skip(1).Reverse()) + { + int length = (int)arrayDimension.UpperBound - (int)arrayDimension.LowerBound; + for (int j = 0; j < args.Count; j += length) + { + var child = new ArrayInitializerExpression(); + child.Elements.AddRange(args.GetRange(j, length)); + newArgs.Add(child); + } + var temp = args; + args = newArgs; + newArgs = temp; + newArgs.Clear(); + } + ace.Initializer.Elements.AddRange(args); + return ace; + } + case ILCode.Ldlen: return arg1.Member("Length"); case ILCode.Ldelem_I: case ILCode.Ldelem_I1: case ILCode.Ldelem_I2: diff --git a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs index 31bfc741f..42c2893e5 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs @@ -46,6 +46,7 @@ namespace ICSharpCode.Decompiler.ILAst SimplifyLdObjAndStObj, SimplifyCustomShortCircuit, TransformArrayInitializers, + TransformMultidimensionalArrayInitializers, TransformObjectInitializers, MakeAssignmentExpression, IntroducePostIncrement, @@ -143,6 +144,9 @@ namespace ICSharpCode.Decompiler.ILAst if (abortBeforeStep == ILAstOptimizationStep.TransformArrayInitializers) return; modified |= block.RunOptimization(TransformArrayInitializers); + + if (abortBeforeStep == ILAstOptimizationStep.TransformMultidimensionalArrayInitializers) return; + modified |= block.RunOptimization(TransformMultidimensionalArrayInitializers); if (abortBeforeStep == ILAstOptimizationStep.TransformObjectInitializers) return; modified |= block.RunOptimization(TransformObjectInitializers); @@ -738,9 +742,24 @@ namespace ICSharpCode.Decompiler.ILAst // property getters can't be expression statements, but all other method calls can be MethodReference mr = (MethodReference)expr.Operand; return !mr.Name.StartsWith("get_", StringComparison.Ordinal); + case ILCode.CallSetter: + case ILCode.CallvirtSetter: case ILCode.Newobj: case ILCode.Newarr: case ILCode.Stloc: + case ILCode.Stobj: + case ILCode.Stsfld: + case ILCode.Stfld: + case ILCode.Stind_Ref: + case ILCode.Stelem_Any: + case ILCode.Stelem_I: + case ILCode.Stelem_I1: + case ILCode.Stelem_I2: + case ILCode.Stelem_I4: + case ILCode.Stelem_I8: + case ILCode.Stelem_R4: + case ILCode.Stelem_R8: + case ILCode.Stelem_Ref: return true; default: return false; diff --git a/ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs b/ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs index b1de6cd77..1a9ad78cf 100644 --- a/ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs +++ b/ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs @@ -32,37 +32,23 @@ namespace ICSharpCode.Decompiler.ILAst #region Array Initializers bool TransformArrayInitializers(List body, ILExpression expr, int pos) { - ILVariable v, v2, v3; + ILVariable v, v3; ILExpression newarrExpr; - TypeReference arrayType; + TypeReference elementType; ILExpression lengthExpr; int arrayLength; if (expr.Match(ILCode.Stloc, out v, out newarrExpr) && - newarrExpr.Match(ILCode.Newarr, out arrayType, out lengthExpr) && + newarrExpr.Match(ILCode.Newarr, out elementType, out lengthExpr) && lengthExpr.Match(ILCode.Ldc_I4, out arrayLength) && - arrayLength > 0) - { - MethodReference methodRef; - ILExpression methodArg1; - ILExpression methodArg2; - FieldDefinition field; - if (body.ElementAtOrDefault(pos + 1).Match(ILCode.Call, out methodRef, out methodArg1, out methodArg2) && - methodRef.DeclaringType.FullName == "System.Runtime.CompilerServices.RuntimeHelpers" && - methodRef.Name == "InitializeArray" && - methodArg1.Match(ILCode.Ldloc, out v2) && - v == v2 && - methodArg2.Match(ILCode.Ldtoken, out field) && - field != null && field.InitialValue != null) - { - ILExpression[] newArr = new ILExpression[arrayLength]; - if (DecodeArrayInitializer(TypeAnalysis.GetTypeCode(arrayType), field.InitialValue, newArr)) { - body[pos] = new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.InitArray, arrayType, newArr)); - body.RemoveAt(pos + 1); - new ILInlining(method).InlineIfPossible(body, ref pos); - return true; - } + arrayLength > 0) { + ILExpression[] newArr; + int initArrayPos; + if (ForwardScanInitializeArrayRuntimeHelper(body, pos + 1, v, elementType, arrayLength, out newArr, out initArrayPos)) { + var arrayType = new ArrayType(elementType, 1); + arrayType.Dimensions[0] = new ArrayDimension(0, arrayLength); + body[pos] = new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.InitArray, arrayType, newArr)); + body.RemoveAt(initArrayPos); } - // Put in a limit so that we don't consume too much memory if the code allocates a huge array // and populates it extremely sparsly. However, 255 "null" elements in a row actually occur in the Mono C# compiler! const int maxConsecutiveDefaultValueExpressions = 300; @@ -77,10 +63,9 @@ namespace ICSharpCode.Decompiler.ILAst v == v3 && nextExpr.Arguments[1].Match(ILCode.Ldc_I4, out arrayPos) && arrayPos >= operands.Count && - arrayPos <= operands.Count + maxConsecutiveDefaultValueExpressions) - { + arrayPos <= operands.Count + maxConsecutiveDefaultValueExpressions) { while (operands.Count < arrayPos) - operands.Add(new ILExpression(ILCode.DefaultValue, arrayType)); + operands.Add(new ILExpression(ILCode.DefaultValue, elementType)); operands.Add(nextExpr.Arguments[2]); numberOfInstructionsToRemove++; } else { @@ -88,16 +73,77 @@ namespace ICSharpCode.Decompiler.ILAst } } if (operands.Count == arrayLength) { + var arrayType = new ArrayType(elementType, 1); + arrayType.Dimensions[0] = new ArrayDimension(0, arrayLength); expr.Arguments[0] = new ILExpression(ILCode.InitArray, arrayType, operands); body.RemoveRange(pos + 1, numberOfInstructionsToRemove); - + new ILInlining(method).InlineIfPossible(body, ref pos); return true; } } return false; } - + + bool TransformMultidimensionalArrayInitializers(List body, ILExpression expr, int pos) + { + ILVariable v; + ILExpression newarrExpr; + MethodReference ctor; + List ctorArgs; + ArrayType arrayType; + if (expr.Match(ILCode.Stloc, out v, out newarrExpr) && + newarrExpr.Match(ILCode.Newobj, out ctor, out ctorArgs) && + (arrayType = (ctor.DeclaringType as ArrayType)) != null && + arrayType.Rank == ctorArgs.Count) { + // Clone the type, so we can muck about with the Dimensions + arrayType = new ArrayType(arrayType.ElementType, arrayType.Rank); + var arrayLengths = new int[arrayType.Rank]; + for (int i = 0; i < arrayType.Rank; i++) { + if (!ctorArgs[i].Match(ILCode.Ldc_I4, out arrayLengths[i])) return false; + if (arrayLengths[i] <= 0) return false; + arrayType.Dimensions[i] = new ArrayDimension(0, arrayLengths[i]); + } + + var totalElements = arrayLengths.Aggregate(1, (t, l) => t * l); + ILExpression[] newArr; + int initArrayPos; + if (ForwardScanInitializeArrayRuntimeHelper(body, pos + 1, v, arrayType, totalElements, out newArr, out initArrayPos)) { + var mdArr = Array.CreateInstance(typeof(ILExpression), arrayLengths); + body[pos] = new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.InitArray, arrayType, newArr)); + body.RemoveAt(initArrayPos); + return true; + } + } + return false; + } + + bool ForwardScanInitializeArrayRuntimeHelper(List body, int pos, ILVariable array, TypeReference arrayType, int arrayLength, out ILExpression[] values, out int foundPos) + { + ILVariable v2; + MethodReference methodRef; + ILExpression methodArg1; + ILExpression methodArg2; + FieldDefinition field; + if (body.ElementAtOrDefault(pos).Match(ILCode.Call, out methodRef, out methodArg1, out methodArg2) && + methodRef.DeclaringType.FullName == "System.Runtime.CompilerServices.RuntimeHelpers" && + methodRef.Name == "InitializeArray" && + methodArg1.Match(ILCode.Ldloc, out v2) && + array == v2 && + methodArg2.Match(ILCode.Ldtoken, out field) && + field != null && field.InitialValue != null) { + ILExpression[] newArr = new ILExpression[arrayLength]; + if (DecodeArrayInitializer(TypeAnalysis.GetTypeCode(arrayType.GetElementType()), field.InitialValue, newArr)) { + values = newArr; + foundPos = pos; + return true; + } + } + values = null; + foundPos = -1; + return false; + } + static bool DecodeArrayInitializer(TypeCode elementType, byte[] initialValue, ILExpression[] output) { switch (elementType) { @@ -160,7 +206,7 @@ namespace ICSharpCode.Decompiler.ILAst } } #endregion - + /// /// Handles both object and collection initializers. /// @@ -168,7 +214,7 @@ namespace ICSharpCode.Decompiler.ILAst { if (!context.Settings.ObjectOrCollectionInitializers) return false; - + Debug.Assert(body[pos] == expr); // should be called for top-level expressions only ILVariable v; ILExpression newObjExpr; @@ -182,19 +228,19 @@ namespace ICSharpCode.Decompiler.ILAst // don't use object initializer syntax for closures if (Ast.Transforms.DelegateConstruction.IsPotentialClosure(context, ctor.DeclaringType.ResolveWithinSameModule())) return false; - + ILExpression initializer = ParseObjectInitializer(body, ref pos, v, newObjExpr, IsCollectionType(ctor.DeclaringType)); - + if (initializer.Arguments.Count == 1) // only newobj argument, no initializer elements return false; int totalElementCount = pos - originalPos - 1; // totalElementCount: includes elements from nested collections Debug.Assert(totalElementCount >= initializer.Arguments.Count - 1); - + // Verify that we can inline 'v' into the next instruction: - + if (pos >= body.Count) return false; // reached end of block, but there should be another instruction which consumes the initialized object - + ILInlining inlining = new ILInlining(method); // one ldloc for each initializer argument, and another ldloc for the use of the initialized object if (inlining.numLdloc.GetOrDefault(v) != totalElementCount + 1) @@ -204,20 +250,20 @@ namespace ICSharpCode.Decompiler.ILAst ILExpression nextExpr = body[pos] as ILExpression; if (!inlining.CanInlineInto(nextExpr, v, initializer)) return false; - + expr.Arguments[0] = initializer; // remove all the instructions that were pulled into the initializer body.RemoveRange(originalPos + 1, pos - originalPos - 1); - + // now that we know that it's an object initializer, change all the first arguments to 'InitializedObject' ChangeFirstArgumentToInitializedObject(initializer); - + inlining = new ILInlining(method); inlining.InlineIfPossible(body, ref originalPos); - + return true; } - + /// /// Gets whether the type supports collection initializers. /// @@ -233,7 +279,7 @@ namespace ICSharpCode.Decompiler.ILAst } return false; } - + /// /// Gets whether 'expr' represents a setter in an object initializer. /// ('CallvirtSetter(Property, v, value)') @@ -247,7 +293,7 @@ namespace ICSharpCode.Decompiler.ILAst } return false; } - + /// /// Gets whether 'expr' represents the invocation of an 'Add' method in a collection initializer. /// @@ -262,7 +308,7 @@ namespace ICSharpCode.Decompiler.ILAst } return false; } - + /// /// Parses an object initializer. /// @@ -304,7 +350,7 @@ namespace ICSharpCode.Decompiler.ILAst } return objectInitializer; } - + static bool AdjustInitializerStack(List initializerStack, ILExpression argument, ILVariable v, bool isCollection) { // Argument is of the form 'getter(getter(...(v)))' @@ -340,7 +386,7 @@ namespace ICSharpCode.Decompiler.ILAst returnType = TypeAnalysis.GetFieldType((FieldReference)mr); else returnType = TypeAnalysis.SubstituteTypeArgs(((MethodReference)mr).ReturnType, mr); - + ILExpression nestedInitializer = new ILExpression( IsCollectionType(returnType) ? ILCode.InitCollection : ILCode.InitObject, null, g); @@ -375,7 +421,7 @@ namespace ICSharpCode.Decompiler.ILAst } } } - + static void CleanupInitializerStackAfterFailedAdjustment(List initializerStack) { // There might be empty nested initializers left over; so we'll remove those: @@ -386,7 +432,7 @@ namespace ICSharpCode.Decompiler.ILAst initializerStack.RemoveAt(initializerStack.Count - 1); } } - + static void ChangeFirstArgumentToInitializedObject(ILExpression initializer) { // Go through all elements in the initializer (so skip the newobj-instr. at the start) diff --git a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs index 9eacc13d7..4755ea4c7 100644 --- a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs +++ b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs @@ -568,11 +568,13 @@ namespace ICSharpCode.Decompiler.ILAst InferTypeForExpression(expr.Arguments.Single(), typeSystem.Int32); return new ArrayType((TypeReference)expr.Operand); case ILCode.InitArray: - if (forceInferChildren) { + var operandAsArrayType = (ArrayType)expr.Operand; + if (forceInferChildren) + { foreach (ILExpression arg in expr.Arguments) - InferTypeForExpression(arg, (TypeReference)expr.Operand); + InferTypeForExpression(arg, operandAsArrayType.ElementType); } - return new ArrayType((TypeReference)expr.Operand); + return operandAsArrayType; case ILCode.Ldlen: return typeSystem.Int32; case ILCode.Ldelem_U1: @@ -955,7 +957,7 @@ namespace ICSharpCode.Decompiler.ILAst { if (type == null) return 0; - if (type.IsValueType) { + if (type.IsValueType && !IsArrayPointerOrReference(type)) { // value type might be an enum TypeDefinition typeDef = type.Resolve() as TypeDefinition; if (typeDef != null && typeDef.IsEnum) { @@ -1003,7 +1005,9 @@ namespace ICSharpCode.Decompiler.ILAst public static bool IsEnum(TypeReference type) { - if (type == null) + // Arrays/Pointers/ByReference resolve to their element type, but we don't want to consider those to be enums + // However, GenericInstanceTypes, ModOpts etc. should be considered enums. + if (type == null || IsArrayPointerOrReference(type)) return false; // unfortunately we cannot rely on type.IsValueType here - it's not set when the instruction operand is a typeref (as opposed to a typespec) TypeDefinition typeDef = type.Resolve() as TypeDefinition; @@ -1012,7 +1016,7 @@ namespace ICSharpCode.Decompiler.ILAst static bool? IsSigned(TypeReference type) { - if (type == null) + if (type == null || IsArrayPointerOrReference(type)) return null; // unfortunately we cannot rely on type.IsValueType here - it's not set when the instruction operand is a typeref (as opposed to a typespec) TypeDefinition typeDef = type.Resolve() as TypeDefinition; @@ -1039,6 +1043,17 @@ namespace ICSharpCode.Decompiler.ILAst } } + static bool IsArrayPointerOrReference(TypeReference type) + { + TypeSpecification typeSpec = type as TypeSpecification; + while (typeSpec != null) { + if (typeSpec is ArrayType || typeSpec is PointerType || typeSpec is ByReferenceType) + return true; + typeSpec = typeSpec.ElementType as TypeSpecification; + } + return false; + } + public static TypeCode GetTypeCode(TypeReference type) { if (type == null) diff --git a/ICSharpCode.Decompiler/Tests/Helpers/CodeAssert.cs b/ICSharpCode.Decompiler/Tests/Helpers/CodeAssert.cs index e403bf898..0a82fb82a 100644 --- a/ICSharpCode.Decompiler/Tests/Helpers/CodeAssert.cs +++ b/ICSharpCode.Decompiler/Tests/Helpers/CodeAssert.cs @@ -89,6 +89,8 @@ namespace ICSharpCode.Decompiler.Tests.Helpers var index = line.IndexOf("//"); if (index >= 0) { return line.Substring(0, index); + } else if (line.StartsWith("#")) { + return string.Empty; } else { return line; } diff --git a/ICSharpCode.Decompiler/Tests/InitializerTests.cs b/ICSharpCode.Decompiler/Tests/InitializerTests.cs index 593db221f..80fbe7478 100644 --- a/ICSharpCode.Decompiler/Tests/InitializerTests.cs +++ b/ICSharpCode.Decompiler/Tests/InitializerTests.cs @@ -21,20 +21,21 @@ using System.Collections.Generic; public class InitializerTests { - enum MyEnum + private enum MyEnum { a, b } - - enum MyEnum2 + + private enum MyEnum2 { c, d } - - class Data + + private class Data { + public List FieldList = new List(); public InitializerTests.MyEnum a { get; @@ -45,218 +46,749 @@ public class InitializerTests get; set; } - public List FieldList = new List(); - - public InitializerTests.Data MoreData { get; set; } + + public InitializerTests.Data MoreData + { + get; + set; + } } // Helper methods used to ensure initializers used within expressions work correctly - static void X(object a, object b) + private static void X(object a, object b) { } - - static object Y() + + private static object Y() { return null; } - + #region Array Initializers public static void Array1() { - X(Y(), new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + InitializerTests.X(InitializerTests.Y(), new int[] + { + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + }); } - + public static void Array2(int a, int b, int c) { - X(Y(), new int[] { a, 0, b, 0, c }); + InitializerTests.X(InitializerTests.Y(), new int[] + { + a, + 0, + b, + 0, + c + }); } - + public static void NestedArray(int a, int b, int c) { - X(Y(), new int[][] { - new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, - new int[] { a, b, c }, - new int[] { 1, 2, 3, 4, 5, 6 } + InitializerTests.X(InitializerTests.Y(), new int[][] + { + new int[] + { + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + }, + new int[] + { + a, + b, + c + }, + new int[] + { + 1, + 2, + 3, + 4, + 5, + 6 + } }); } - + public static void ArrayBoolean() { - X(Y(), new bool[] { true, false, true, false, false, false, true, true }); + InitializerTests.X(InitializerTests.Y(), new bool[] + { + true, + false, + true, + false, + false, + false, + true, + true + }); } - + public static void ArrayByte() { - X(Y(), new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 254, 255 }); + InitializerTests.X(InitializerTests.Y(), new byte[] + { + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 254, + 255 + }); } - + public static void ArraySByte() { - X(Y(), new sbyte[] { -128, -127, 0, 1, 2, 3, 4, 127 }); + InitializerTests.X(InitializerTests.Y(), new sbyte[] + { + -128, + -127, + 0, + 1, + 2, + 3, + 4, + 127 + }); } - + public static void ArrayShort() { - X(Y(), new short[] { -32768, -1, 0, 1, 32767 }); + InitializerTests.X(InitializerTests.Y(), new short[] + { + -32768, + -1, + 0, + 1, + 32767 + }); } - + public static void ArrayUShort() { - X(Y(), new ushort[] { 0, 1, 32767, 32768, 65534, 65535 }); + InitializerTests.X(InitializerTests.Y(), new ushort[] + { + 0, + 1, + 32767, + 32768, + 65534, + 65535 + }); } - + public static void ArrayInt() { - X(Y(), new int[] { 1, -2, 2000000000, 4, 5, -6, 7, 8, 9, 10 }); + InitializerTests.X(InitializerTests.Y(), new int[] + { + 1, + -2, + 2000000000, + 4, + 5, + -6, + 7, + 8, + 9, + 10 + }); } - + public static void ArrayUInt() { - X(Y(), new uint[] { 1, 2000000000, 3000000000, 4, 5, 6, 7, 8, 9, 10 }); + InitializerTests.X(InitializerTests.Y(), new uint[] + { + 1u, + 2000000000u, + 3000000000u, + 4u, + 5u, + 6u, + 7u, + 8u, + 9u, + 10u + }); } - + public static void ArrayLong() { - X(Y(), new long[] { -4999999999999999999, -1, 0, 1, 4999999999999999999 }); + InitializerTests.X(InitializerTests.Y(), new long[] + { + -4999999999999999999L, + -1L, + 0L, + 1L, + 4999999999999999999L + }); } - + public static void ArrayULong() { - X(Y(), new ulong[] { 1, 2000000000, 3000000000, 4, 5, 6, 7, 8, 4999999999999999999, 9999999999999999999 }); + InitializerTests.X(InitializerTests.Y(), new ulong[] + { + 1uL, + 2000000000uL, + 3000000000uL, + 4uL, + 5uL, + 6uL, + 7uL, + 8uL, + 4999999999999999999uL, + 9999999999999999999uL + }); } - + public static void ArrayFloat() { - X(Y(), new float[] { -1.5f, 0f, 1.5f, float.NegativeInfinity, float.PositiveInfinity, float.NaN }); + InitializerTests.X(InitializerTests.Y(), new float[] + { + -1.5f, + 0f, + 1.5f, + float.NegativeInfinity, + float.PositiveInfinity, + float.NaN + }); } - + public static void ArrayDouble() { - X(Y(), new double[] { -1.5, 0.0, 1.5, double.NegativeInfinity, double.PositiveInfinity, double.NaN }); + InitializerTests.X(InitializerTests.Y(), new double[] + { + -1.5, + 0.0, + 1.5, + double.NegativeInfinity, + double.PositiveInfinity, + double.NaN + }); } - + public static void ArrayDecimal() { - X(Y(), new decimal[] { -100m, 0m, 100m, decimal.MinValue, decimal.MaxValue, 0.0000001m }); + InitializerTests.X(InitializerTests.Y(), new decimal[] + { + -100m, + 0m, + 100m, + -79228162514264337593543950335m, + 79228162514264337593543950335m, + 0.0000001m + }); } - + public static void ArrayString() { - X(Y(), new string[] { "", null, "Hello", "World" }); + InitializerTests.X(InitializerTests.Y(), new string[] + { + "", + null, + "Hello", + "World" + }); } - + public static void ArrayEnum() { - X(Y(), new InitializerTests.MyEnum[] { InitializerTests.MyEnum.a, InitializerTests.MyEnum.b, InitializerTests.MyEnum.a, InitializerTests.MyEnum.b }); + InitializerTests.X(InitializerTests.Y(), new InitializerTests.MyEnum[] + { + InitializerTests.MyEnum.a, + InitializerTests.MyEnum.b, + InitializerTests.MyEnum.a, + InitializerTests.MyEnum.b + }); } #endregion - + public static void CollectionInitializerList() { - X(Y(), new List { 1, 2, 3 }); + InitializerTests.X(InitializerTests.Y(), new List + { + 1, + 2, + 3 + }); } - + public static void CollectionInitializerDictionary() { - X(Y(), new Dictionary { - { "First", 1 }, - { "Second", 2 }, - { "Third" , 3 } + InitializerTests.X(InitializerTests.Y(), new Dictionary + { + { + "First", + 1 + }, + { + "Second", + 2 + }, + { + "Third", + 3 + } }); } - + public static void CollectionInitializerDictionaryWithEnumTypes() { - X(Y(), new Dictionary { - { InitializerTests.MyEnum.a, InitializerTests.MyEnum2.c }, - { InitializerTests.MyEnum.b, InitializerTests.MyEnum2.d } + InitializerTests.X(InitializerTests.Y(), new Dictionary + { + { + InitializerTests.MyEnum.a, + InitializerTests.MyEnum2.c + }, + { + InitializerTests.MyEnum.b, + InitializerTests.MyEnum2.d + } }); } - + public static void NotACollectionInitializer() { List list = new List(); list.Add(1); list.Add(2); list.Add(3); - X(Y(), list); + InitializerTests.X(InitializerTests.Y(), list); } - + public static void ObjectInitializer() { - X(Y(), new Data + InitializerTests.X(InitializerTests.Y(), new InitializerTests.Data { - a = InitializerTests.MyEnum.a + a = InitializerTests.MyEnum.a }); } - + public static void NotAObjectInitializer() { - Data data = new InitializerTests.Data(); + InitializerTests.Data data = new InitializerTests.Data(); data.a = InitializerTests.MyEnum.a; - X(Y(), data); + InitializerTests.X(InitializerTests.Y(), data); } - + public static void ObjectInitializerAssignCollectionToField() { - X(Y(), new InitializerTests.Data + InitializerTests.X(InitializerTests.Y(), new InitializerTests.Data { - a = InitializerTests.MyEnum.a, - FieldList = new List - { - InitializerTests.MyEnum2.c, - InitializerTests.MyEnum2.d - } + a = InitializerTests.MyEnum.a, + FieldList = new List + { + InitializerTests.MyEnum2.c, + InitializerTests.MyEnum2.d + } }); } - + public static void ObjectInitializerAddToCollectionInField() { - X(Y(), new InitializerTests.Data + InitializerTests.X(InitializerTests.Y(), new InitializerTests.Data { - a = InitializerTests.MyEnum.a, - FieldList = - { - InitializerTests.MyEnum2.c, - InitializerTests.MyEnum2.d - } + a = InitializerTests.MyEnum.a, + FieldList = + { + InitializerTests.MyEnum2.c, + InitializerTests.MyEnum2.d + } }); } - + public static void ObjectInitializerAssignCollectionToProperty() { - X(Y(), new InitializerTests.Data + InitializerTests.X(InitializerTests.Y(), new InitializerTests.Data { - a = InitializerTests.MyEnum.a, - PropertyList = new List - { - InitializerTests.MyEnum2.c, - InitializerTests.MyEnum2.d - } + a = InitializerTests.MyEnum.a, + PropertyList = new List + { + InitializerTests.MyEnum2.c, + InitializerTests.MyEnum2.d + } }); } - + public static void ObjectInitializerAddToCollectionInProperty() { - X(Y(), new InitializerTests.Data + InitializerTests.X(InitializerTests.Y(), new InitializerTests.Data { - a = InitializerTests.MyEnum.a, - PropertyList = - { - InitializerTests.MyEnum2.c, - InitializerTests.MyEnum2.d - } + a = InitializerTests.MyEnum.a, + PropertyList = + { + InitializerTests.MyEnum2.c, + InitializerTests.MyEnum2.d + } }); } - + public static void ObjectInitializerWithInitializationOfNestedObjects() { - X(Y(), new InitializerTests.Data + InitializerTests.X(InitializerTests.Y(), new InitializerTests.Data { - MoreData = - { - a = InitializerTests.MyEnum.a - } + MoreData = + { + a = InitializerTests.MyEnum.a + } }); } + + public void MultidimensionalInit() + { + int[,] expr_09 = new int[, ] + { + + { + 0, + 0, + 0, + 0 + }, + + { + 1, + 1, + 1, + 1 + }, + + { + 0, + 0, + 0, + 0 + }, + + { + 0, + 0, + 0, + 0 + }, + + { + 0, + 0, + 1, + 0 + }, + + { + 0, + 0, + 1, + 0 + }, + + { + 0, + 0, + 1, + 0 + }, + + { + 0, + 0, + 1, + 0 + }, + + { + 0, + 0, + 0, + 0 + }, + + { + 1, + 1, + 1, + 1 + }, + + { + 0, + 0, + 0, + 0 + }, + + { + 0, + 0, + 0, + 0 + }, + + { + 0, + 0, + 1, + 0 + }, + + { + 0, + 0, + 1, + 0 + }, + + { + 0, + 0, + 1, + 0 + }, + + { + 0, + 0, + 1, + 0 + } + }; + } + + public void MultidimensionalInit2() + { + int[][,] array = new int[][,] + { + new int[, ] + { + + { + 0, + 0, + 0, + 0 + }, + + { + 1, + 1, + 1, + 1 + }, + + { + 0, + 0, + 0, + 0 + }, + + { + 0, + 0, + 0, + 0 + } + + }, + new int[, ] + { + + { + 0, + 0, + 1, + 0 + }, + + { + 0, + 0, + 1, + 0 + }, + + { + 0, + 0, + 1, + 0 + }, + + { + 0, + 0, + 1, + 0 + } + + }, + new int[, ] + { + + { + 0, + 0, + 0, + 0 + }, + + { + 1, + 1, + 1, + 1 + }, + + { + 0, + 0, + 0, + 0 + }, + + { + 0, + 0, + 0, + 0 + } + }, + new int[, ] + { + + { + 0, + 0, + 1, + 0 + }, + + { + 0, + 0, + 1, + 0 + }, + + { + 0, + 0, + 1, + 0 + }, + + { + 0, + 0, + 1, + 0 + } + + } + }; + } + + public void ArrayOfArrayOfArrayInit() + { + int[][,,] array = new int[][,,] + { + new int[, , ] + { + { + { + 1, + 2, + 3 + }, + { + 4, + 5, + 6 + }, + { + 7, + 8, + 9 + } + }, + { + { + 11, + 12, + 13 + }, + { + 14, + 15, + 16 + }, + { + 17, + 18, + 19 + } + } + }, + + new int[, , ] + { + { + { + 21, + 22, + 23 + }, + { + 24, + 25, + 26 + }, + { + 27, + 28, + 29 + } + }, + { + { + 31, + 32, + 33 + }, + { + 34, + 35, + 36 + }, + { + 37, + 38, + 39 + } + } + } + }; + } } diff --git a/ICSharpCode.Decompiler/Tests/TestRunner.cs b/ICSharpCode.Decompiler/Tests/TestRunner.cs index 52bef700c..cdfde87af 100644 --- a/ICSharpCode.Decompiler/Tests/TestRunner.cs +++ b/ICSharpCode.Decompiler/Tests/TestRunner.cs @@ -76,7 +76,7 @@ namespace ICSharpCode.Decompiler.Tests TestFile(@"..\..\Tests\IncrementDecrement.cs"); } - [Test, Ignore("Formatting issues (array initializers not on single line)")] + [Test] public void InitializerTests() { TestFile(@"..\..\Tests\InitializerTests.cs"); diff --git a/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs b/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs index b79492d1f..f6d1addf7 100644 --- a/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs +++ b/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs @@ -59,11 +59,22 @@ namespace ILSpy.BamlDecompiler XDocument xamlDocument; using (XmlBamlReader reader = new XmlBamlReader(stream, new CecilTypeResolver(resolver, asm))) xamlDocument = XDocument.Load(reader); + ConvertConnectionIds(xamlDocument, asm); ConvertToEmptyElements(xamlDocument.Root); MoveNamespacesToRoot(xamlDocument); return xamlDocument; } + static void ConvertConnectionIds(XDocument xamlDocument, AssemblyDefinition asm) + { + var attr = xamlDocument.Root.Attribute(XName.Get("Class", XmlBamlReader.XWPFNamespace)); + if (attr != null) { + string fullTypeName = attr.Value; + var mappings = new ConnectMethodDecompiler(asm).DecompileEventMappings(fullTypeName); + RemoveConnectionIds(xamlDocument.Root, mappings); + } + } + static void MoveNamespacesToRoot(XDocument xamlDocument) { var additionalXmlns = new List { @@ -98,5 +109,32 @@ namespace ILSpy.BamlDecompiler ConvertToEmptyElements(el); } } + + static void RemoveConnectionIds(XElement element, Dictionary eventMappings) + { + foreach (var child in element.Elements()) + RemoveConnectionIds(child, eventMappings); + + var removableAttrs = new List(); + var addableAttrs = new List(); + foreach (var attr in element.Attributes(XName.Get("ConnectionId", XmlBamlReader.XWPFNamespace))) { + int id; + if (int.TryParse(attr.Value, out id) && eventMappings.ContainsKey(id)) { + var map = eventMappings[id]; + foreach (var entry in map) { + string xmlns = ""; // TODO : implement xmlns resolver! + if (entry.IsAttached) { + addableAttrs.Add(new XAttribute(xmlns + entry.AttachSourceType.Name + "." + entry.EventName, entry.MethodName)); + } else { + addableAttrs.Add(new XAttribute(xmlns + entry.EventName, entry.MethodName)); + } + } + removableAttrs.Add(attr); + } + } + foreach (var attr in removableAttrs) + attr.Remove(); + element.Add(addableAttrs); + } } } \ No newline at end of file diff --git a/ILSpy.BamlDecompiler/CecilTypeResolver.cs b/ILSpy.BamlDecompiler/CecilTypeResolver.cs index 702c37c38..bc42696ea 100644 --- a/ILSpy.BamlDecompiler/CecilTypeResolver.cs +++ b/ILSpy.BamlDecompiler/CecilTypeResolver.cs @@ -25,7 +25,16 @@ namespace ILSpy.BamlDecompiler public bool IsLocalAssembly(string name) { - return name == this.thisAssembly.Name.Name; + return MakeShort(name) == this.thisAssembly.Name.Name; + } + + string MakeShort(string name) + { + int endOffset = name.IndexOf(','); + if (endOffset == -1) + return name; + + return name.Substring(0, endOffset); } public IType GetTypeByAssemblyQualifiedName(string name) diff --git a/ILSpy/ConnectMethodDecompiler.cs b/ILSpy.BamlDecompiler/ConnectMethodDecompiler.cs similarity index 64% rename from ILSpy/ConnectMethodDecompiler.cs rename to ILSpy.BamlDecompiler/ConnectMethodDecompiler.cs index 7cb2c1760..2ae4fd076 100644 --- a/ILSpy/ConnectMethodDecompiler.cs +++ b/ILSpy.BamlDecompiler/ConnectMethodDecompiler.cs @@ -1,47 +1,34 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team +// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt) using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; + using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.ILAst; using Mono.Cecil; -using Mono.Cecil.Cil; -namespace ICSharpCode.ILSpy.Baml +namespace ILSpy.BamlDecompiler { - [Serializable] + /// + /// Represents an event registration of a XAML code-behind class. + /// sealed class EventRegistration { - public string EventName, MethodName, AttachSourceType; + public string EventName, MethodName; + public TypeDefinition AttachSourceType; public bool IsAttached; } /// - /// Description of ConnectMethodDecompiler. + /// Decompiles event and name mappings of XAML code-behind classes. /// - sealed class ConnectMethodDecompiler : MarshalByRefObject + sealed class ConnectMethodDecompiler { - LoadedAssembly assembly; + AssemblyDefinition assembly; - public ConnectMethodDecompiler(LoadedAssembly assembly) + public ConnectMethodDecompiler(AssemblyDefinition assembly) { this.assembly = assembly; } @@ -49,7 +36,7 @@ namespace ICSharpCode.ILSpy.Baml public Dictionary DecompileEventMappings(string fullTypeName) { var result = new Dictionary(); - TypeDefinition type = this.assembly.AssemblyDefinition.MainModule.GetType(fullTypeName); + TypeDefinition type = this.assembly.MainModule.GetType(fullTypeName); if (type == null) return result; @@ -98,7 +85,8 @@ namespace ICSharpCode.ILSpy.Baml foreach (var node in block.Body) { var expr = node as ILExpression; - string eventName, handlerName, attachSource; + string eventName, handlerName; + TypeDefinition attachSource; if (IsAddEvent(expr, out eventName, out handlerName)) events.Add(new EventRegistration { EventName = eventName, @@ -116,11 +104,11 @@ namespace ICSharpCode.ILSpy.Baml return events.ToArray(); } - bool IsAddAttachedEvent(ILExpression expr, out string eventName, out string handlerName, out string attachSource) + bool IsAddAttachedEvent(ILExpression expr, out string eventName, out string handlerName, out TypeDefinition attachSource) { eventName = ""; handlerName = ""; - attachSource = ""; + attachSource = null; if (expr == null || !(expr.Code == ILCode.Callvirt || expr.Code == ILCode.Call)) return false; @@ -133,7 +121,7 @@ namespace ICSharpCode.ILSpy.Baml if (arg.Code != ILCode.Ldsfld || arg.Arguments.Any() || !(arg.Operand is FieldReference)) return false; FieldReference fldRef = (FieldReference)arg.Operand; - attachSource = GetAssemblyQualifiedName(fldRef.DeclaringType); + attachSource = fldRef.DeclaringType.Resolve(); eventName = fldRef.Name; if (eventName.EndsWith("Event") && eventName.Length > "Event".Length) eventName = eventName.Remove(eventName.Length - "Event".Length); @@ -153,18 +141,6 @@ namespace ICSharpCode.ILSpy.Baml return false; } - string GetAssemblyQualifiedName(TypeReference declaringType) - { - string fullName = declaringType.FullName; - - if (declaringType.Scope is AssemblyNameReference) - fullName += ", " + ((AssemblyNameReference)declaringType.Scope).FullName; - else if (declaringType.Scope is ModuleDefinition) - fullName += ", " + ((ModuleDefinition)declaringType.Scope).Assembly.FullName; - - return fullName; - } - bool IsAddEvent(ILExpression expr, out string eventName, out string handlerName) { eventName = ""; @@ -193,20 +169,4 @@ namespace ICSharpCode.ILSpy.Baml return false; } } - - sealed class AssemblyResolver : MarshalByRefObject - { - LoadedAssembly assembly; - - public AssemblyResolver(LoadedAssembly assembly) - { - this.assembly = assembly; - } - - public string FindAssembly(string name) - { - var asm = assembly.LookupReferencedAssembly(name); - return asm == null ? null : asm.FileName; - } - } } diff --git a/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj b/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj index a681f07fd..3274b3c08 100644 --- a/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj +++ b/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj @@ -77,17 +77,21 @@ + - + + Component + + @@ -103,9 +107,7 @@ - - - + {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1} diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlBinaryReader.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlBinaryReader.cs index 6df206561..f31e0f5f2 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlBinaryReader.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlBinaryReader.cs @@ -17,22 +17,15 @@ namespace Ricciolo.StylesExplorer.MarkupReflection public virtual double ReadCompressedDouble() { - switch (this.ReadByte()) - { + switch (this.ReadByte()) { case 1: return 0; - case 2: return 1; - case 3: return -1; - case 4: - { - double num = this.ReadInt32(); - return (num * 1E-06); - } + return ReadInt32() * 1E-06; case 5: return this.ReadDouble(); } diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/KeyMapping.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/KeyMapping.cs new file mode 100644 index 000000000..0b20620fc --- /dev/null +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/KeyMapping.cs @@ -0,0 +1,40 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team +// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt) + +using System; +using System.Collections.Generic; + +namespace Ricciolo.StylesExplorer.MarkupReflection +{ + public class KeyMapping + { + List staticResources; + + public List StaticResources { + get { return staticResources; } + } + + public bool HasStaticResources { + get { return staticResources != null && staticResources.Count > 0; } + } + + public string KeyString { get; set; } + public bool Shared { get; set; } + public bool SharedSet { get; set; } + + public int Position { get; set; } + + public KeyMapping() + { + this.staticResources = new List(); + this.Position = -1; + } + + public KeyMapping(string key) + { + this.KeyString = key; + this.staticResources = new List(); + this.Position = -1; + } + } +} diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlElement.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlElement.cs index 393ac5c70..25d8f466f 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlElement.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlElement.cs @@ -9,21 +9,17 @@ using System.Xml; namespace Ricciolo.StylesExplorer.MarkupReflection { - internal class XmlBamlElement : XmlBamlNode + class XmlBamlElement : XmlBamlNode { - private ArrayList _arguments = new ArrayList(); - private XmlNamespaceCollection _namespaces = new XmlNamespaceCollection(); - private TypeDeclaration _typeDeclaration; - private KeysResourcesCollection _keysResources = new KeysResourcesCollection(); - private long _position; + XmlNamespaceCollection _namespaces = new XmlNamespaceCollection(); public XmlBamlElement() { } - public XmlBamlElement(XmlBamlElement parent) { + this.Parent = parent; this.Namespaces.AddRange(parent.Namespaces); } @@ -31,32 +27,18 @@ namespace Ricciolo.StylesExplorer.MarkupReflection { get { return _namespaces; } } + + public XmlBamlElement Parent { get; private set; } + + public TypeDeclaration TypeDeclaration { get; set; } - public TypeDeclaration TypeDeclaration - { - get - { - return this._typeDeclaration; - } - set - { - this._typeDeclaration = value; - } + public override XmlNodeType NodeType { + get { return XmlNodeType.Element; } } - public override XmlNodeType NodeType - { - get - { - return XmlNodeType.Element; - } - } - - public long Position - { - get { return _position; } - set { _position = value; } - } + public long Position { get; set; } + + public bool IsImplicit { get; set; } public override string ToString() { @@ -86,108 +68,5 @@ namespace Ricciolo.StylesExplorer.MarkupReflection } } - internal class KeyMapping - { - private string _key; - private TypeDeclaration _declaration; - private string _trueKey; - - public KeyMapping(string key, TypeDeclaration declaration, string trueKey) - { - _key = key; - _declaration = declaration; - _trueKey = trueKey; - } - - public string Key - { - get { return _key; } - } - - public TypeDeclaration Declaration - { - get { return _declaration; } - } - - public string TrueKey - { - get { return _trueKey; } - } - - public override string ToString() - { - return String.Format("{0} - {1} - {2}", Key, Declaration, TrueKey); - } - } - - internal class KeysResourcesCollection : List - { - public KeysResource Last - { - get - { - if (this.Count == 0) - return null; - return this[this.Count - 1]; - } - } - - public KeysResource First - { - get - { - if (this.Count == 0) - return null; - return this[0]; - } - } - } - - internal class KeysResource - { - private KeysTable _keys = new KeysTable(); - private ArrayList _staticResources = new ArrayList(); - - public KeysTable Keys - { - get { return _keys; } - } - - public ArrayList StaticResources - { - get { return _staticResources; } - } - } - - internal class KeysTable - { - private Hashtable table = new Hashtable(); - - public String this[long position] - { - get - { - return (string)this.table[position]; - } - set - { - this.table[position] = value; - } - } - public int Count - { - get { return this.table.Count; } - } - - public void Remove(long position) - { - this.table.Remove(position); - } - - public bool HasKey(long position) - { - return this.table.ContainsKey(position); - } - } } diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlProperty.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlProperty.cs index 2da34dd90..9207f936f 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlProperty.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlProperty.cs @@ -10,18 +10,18 @@ namespace Ricciolo.StylesExplorer.MarkupReflection { internal class XmlBamlProperty : XmlBamlNode { - private PropertyDeclaration propertyDeclaration; - private PropertyType propertyType; - private object value; + PropertyType propertyType; - public XmlBamlProperty(PropertyType propertyType) + public XmlBamlProperty(XmlBamlElement parent, PropertyType propertyType) { + this.Parent = parent; this.propertyType = propertyType; } - public XmlBamlProperty(PropertyType propertyType, PropertyDeclaration propertyDeclaration) + public XmlBamlProperty(XmlBamlElement parent, PropertyType propertyType, PropertyDeclaration propertyDeclaration) { - this.propertyDeclaration = propertyDeclaration; + this.Parent = parent; + this.PropertyDeclaration = propertyDeclaration; this.propertyType = propertyType; } @@ -29,45 +29,19 @@ namespace Ricciolo.StylesExplorer.MarkupReflection { return this.PropertyDeclaration.Name; } + + public XmlBamlElement Parent { get; set; } + + public PropertyDeclaration PropertyDeclaration { get; set; } - public PropertyDeclaration PropertyDeclaration - { - get - { - return this.propertyDeclaration; - } - set - { - this.propertyDeclaration = value; - } + public PropertyType PropertyType { + get { return this.propertyType; } } - public PropertyType PropertyType - { - get - { - return this.propertyType; - } - } + public object Value { get; set; } - public object Value - { - get - { - return this.value; - } - set - { - this.value = value; - } - } - - public override XmlNodeType NodeType - { - get - { - return XmlNodeType.Attribute; - } + public override XmlNodeType NodeType { + get { return XmlNodeType.Attribute; } } } diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlPropertyElement.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlPropertyElement.cs index fbb312cf0..a6ce053d9 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlPropertyElement.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlPropertyElement.cs @@ -11,8 +11,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection { private readonly PropertyType _propertyType; private PropertyDeclaration propertyDeclaration; - - + public XmlBamlPropertyElement(PropertyType propertyType, PropertyDeclaration propertyDeclaration) { _propertyType = propertyType; diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs index 6417549f7..eb5887901 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs @@ -18,49 +18,100 @@ namespace Ricciolo.StylesExplorer.MarkupReflection { public class XmlBamlReader : XmlReader, IXmlNamespaceResolver { + BamlBinaryReader reader; + Dictionary assemblyTable = new Dictionary(); + Dictionary stringTable = new Dictionary(); + Dictionary typeTable = new Dictionary(); + Dictionary propertyTable = new Dictionary(); - #region Variables + readonly ITypeResolver _resolver; - private BamlBinaryReader reader; - private Dictionary assemblyTable = new Dictionary(); - private Dictionary stringTable = new Dictionary(); - private Dictionary typeTable = new Dictionary(); - private Dictionary propertyTable = new Dictionary(); + BamlRecordType currentType; - private readonly ITypeResolver _resolver; + Stack elements = new Stack(); + Stack readingElements = new Stack(); + NodesCollection nodes = new NodesCollection(); + List _mappings = new List(); + XmlBamlNode _currentNode; - private BamlRecordType currentType; + readonly KnownInfo KnownInfo; - private Stack elements = new Stack(); - private Stack readingElements = new Stack(); - private Stack keysResources = new Stack(); - private NodesCollection nodes = new NodesCollection(); - private List _mappings = new List(); - private XmlBamlNode _currentNode; + int complexPropertyOpened = 0; - private readonly KnownInfo KnownInfo; + bool intoAttribute = false; + bool initialized; + bool _eof; - private int complexPropertyOpened = 0; - - private bool intoAttribute = false; - private bool initialized; - private bool _eof; + bool isPartialDefKeysClosed = true; + bool isDefKeysClosed = true; + + #region Context + Stack layer = new Stack(); + + class ReaderContext + { + public bool IsDeferred { get; set; } + public bool IsInStaticResource { get; set; } - private bool isPartialDefKeysClosed = true; - private bool isDefKeysClosed = true; + public ReaderContext Previous { get; private set; } + + public ReaderContext() + { + this.Previous = this; + } + + public ReaderContext(ReaderContext previous) + { + this.Previous = previous; + } + } + + ReaderContext Current { + get { + if (!layer.Any()) + layer.Push(new ReaderContext()); + + return layer.Peek(); + } + } + + int currentKey; + List keys = new List(); + + KeyMapping LastKey { + get { + KeyMapping last = keys.LastOrDefault(); + if (last == null) + keys.Add(last = new KeyMapping()); + + return last; + } + } + + void LayerPop() + { + layer.Pop(); + } + + void LayerPush() + { + if (layer.Any()) + layer.Push(new ReaderContext(layer.Peek())); + else + layer.Push(new ReaderContext()); + } + #endregion - private int bytesToSkip; + int bytesToSkip; - private static readonly MethodInfo staticConvertCustomBinaryToObjectMethod = Type.GetType("System.Windows.Markup.XamlPathDataSerializer,PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35").GetMethod("StaticConvertCustomBinaryToObject", BindingFlags.Static | BindingFlags.Public); - private readonly TypeDeclaration XamlTypeDeclaration; - private readonly XmlNameTable _nameTable = new NameTable(); - private IDictionary _rootNamespaces; + static readonly MethodInfo staticConvertCustomBinaryToObjectMethod = Type.GetType("System.Windows.Markup.XamlPathDataSerializer,PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35").GetMethod("StaticConvertCustomBinaryToObject", BindingFlags.Static | BindingFlags.Public); + readonly TypeDeclaration XamlTypeDeclaration; + readonly XmlNameTable _nameTable = new NameTable(); + IDictionary _rootNamespaces; public const string XWPFNamespace = "http://schemas.microsoft.com/winfx/2006/xaml"; public const string DefaultWPFNamespace = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"; - #endregion - public XmlBamlReader(Stream stream) : this (stream, AppDomainTypeResolver.GetIntoNewAppDomain(Environment.CurrentDirectory)) { @@ -240,7 +291,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection return ReadInternal(); } - private bool ReadInternal() + bool ReadInternal() { EnsureInit(); @@ -288,10 +339,10 @@ namespace Ricciolo.StylesExplorer.MarkupReflection else currentType = (BamlRecordType)type; -// Debug.WriteLine(currentType); + Debug.WriteLine(string.Format("{0} (0x{0:x})", currentType)); } - private bool SetNextNode() + bool SetNextNode() { while (nodes.Count > 0) { @@ -315,7 +366,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection return false; } - private void ProcessNext() + void ProcessNext() { switch (currentType) { @@ -347,9 +398,10 @@ namespace Ricciolo.StylesExplorer.MarkupReflection this.ReadXmlnsProperty(); break; case BamlRecordType.ConnectionId: - reader.ReadInt32(); + this.ReadConnectionId(); break; case BamlRecordType.DeferableContentStart: + Current.IsDeferred = true; reader.ReadInt32(); break; case BamlRecordType.DefAttribute: @@ -453,6 +505,12 @@ namespace Ricciolo.StylesExplorer.MarkupReflection } } + void ReadConnectionId() + { + int id = reader.ReadInt32(); + nodes.Enqueue(new XmlBamlSimpleProperty(XWPFNamespace, "ConnectionId", id.ToString())); + } + void ReadTextWithId() { short textId = reader.ReadInt16(); @@ -460,7 +518,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection nodes.Enqueue(new XmlBamlText(text)); } - private void ComputeBytesToSkip() + void ComputeBytesToSkip() { bytesToSkip = 0; switch (currentType) @@ -485,7 +543,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection } } - private void EnsureInit() + void EnsureInit() { if (!initialized) { @@ -595,7 +653,12 @@ namespace Ricciolo.StylesExplorer.MarkupReflection else if (node is XmlBamlPropertyElement) { XmlBamlPropertyElement property = (XmlBamlPropertyElement)node; - localName = String.Format("{0}.{1}", property.TypeDeclaration.Name, property.PropertyDeclaration.Name); + string typeName = property.TypeDeclaration.Name; + + if (property.Parent.TypeDeclaration.Type.IsSubclassOf(property.PropertyDeclaration.DeclaringType.Type)) + typeName = property.Parent.TypeDeclaration.Name; + + localName = String.Format("{0}.{1}", typeName, property.PropertyDeclaration.Name); } else if (node is XmlBamlElement) localName = ((XmlBamlElement)node).TypeDeclaration.Name; @@ -606,7 +669,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection } } - private PropertyDeclaration GetPropertyDeclaration(short identifier) + PropertyDeclaration GetPropertyDeclaration(short identifier) { PropertyDeclaration declaration; if (identifier >= 0) @@ -624,7 +687,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection return declaration; } - private object GetResourceName(short identifier) + object GetResourceName(short identifier) { if (identifier >= 0) { @@ -644,7 +707,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection } } - private void ReadPropertyDictionaryStart() + void ReadPropertyDictionaryStart() { short identifier = reader.ReadInt16(); @@ -653,19 +716,14 @@ namespace Ricciolo.StylesExplorer.MarkupReflection XmlBamlPropertyElement property = new XmlBamlPropertyElement(element, PropertyType.Dictionary, pd); elements.Push(property); nodes.Enqueue(property); - - isDefKeysClosed = true; - isPartialDefKeysClosed = true; } - private void ReadPropertyDictionaryEnd() + void ReadPropertyDictionaryEnd() { - keysResources.Pop(); - CloseElement(); } - private void ReadPropertyCustom() + void ReadPropertyCustom() { short identifier = reader.ReadInt16(); short serializerTypeId = reader.ReadInt16(); @@ -719,13 +777,13 @@ namespace Ricciolo.StylesExplorer.MarkupReflection return; } - XmlBamlProperty property = new XmlBamlProperty(PropertyType.Value, pd); + XmlBamlProperty property = new XmlBamlProperty(elements.Peek(), PropertyType.Value, pd); property.Value = value; nodes.Enqueue(property); } - private string DeserializePoints() + string DeserializePoints() { using (StringWriter writer = new StringWriter()) { @@ -745,7 +803,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection } } - private String Deserialize3DPoints() + String Deserialize3DPoints() { using (StringWriter writer = new StringWriter()) { @@ -769,7 +827,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection } } - private static Int32Collection DeserializeInt32CollectionFrom(BinaryReader reader) + static Int32Collection DeserializeInt32CollectionFrom(BinaryReader reader) { IntegerCollectionType type = (IntegerCollectionType)reader.ReadByte(); int capacity = reader.ReadInt32(); @@ -799,7 +857,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection throw new ArgumentException(); } - private void ReadPropertyWithExtension() + void ReadPropertyWithExtension() { short identifier = reader.ReadInt16(); short x = reader.ReadInt16(); @@ -812,8 +870,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection short extensionIdentifier = (short)-(x & 0xfff); string value = String.Empty; - switch (x) - { + switch (x) { case 0x25a: // StaticExtension object resource = this.GetResourceName(valueIdentifier); @@ -849,62 +906,62 @@ namespace Ricciolo.StylesExplorer.MarkupReflection throw new NotSupportedException("Unknown property with extension"); } - XmlBamlProperty property = new XmlBamlProperty(PropertyType.Value, pd); + XmlBamlProperty property = new XmlBamlProperty(elements.Peek(), PropertyType.Value, pd); property.Value = value; nodes.Enqueue(property); } - private void ReadProperty() + void ReadProperty() { short identifier = reader.ReadInt16(); string text = reader.ReadString(); PropertyDeclaration pd = this.GetPropertyDeclaration(identifier); - XmlBamlProperty property = new XmlBamlProperty(PropertyType.Value, pd); + XmlBamlProperty property = new XmlBamlProperty(elements.Peek(), PropertyType.Value, pd); property.Value = text; nodes.Enqueue(property); } - private void ReadPropertyWithConverter() + void ReadPropertyWithConverter() { short identifier = reader.ReadInt16(); string text = reader.ReadString(); reader.ReadInt16(); PropertyDeclaration pd = this.GetPropertyDeclaration(identifier); - XmlBamlProperty property = new XmlBamlProperty(PropertyType.Value, pd); + XmlBamlProperty property = new XmlBamlProperty(elements.Peek(), PropertyType.Value, pd); property.Value = text; nodes.Enqueue(property); } - private void ReadAttributeInfo() + void ReadAttributeInfo() { short key = reader.ReadInt16(); short identifier = reader.ReadInt16(); reader.ReadByte(); string name = reader.ReadString(); TypeDeclaration declaringType = this.GetTypeDeclaration(identifier); - PropertyDeclaration declaration2 = new PropertyDeclaration(name, declaringType); - this.propertyTable.Add(key, declaration2); + PropertyDeclaration property = new PropertyDeclaration(name, declaringType); + this.propertyTable.Add(key, property); } - private void ReadDefAttributeKeyType() + void ReadDefAttributeKeyType() { short typeIdentifier = reader.ReadInt16(); reader.ReadByte(); int position = reader.ReadInt32(); - // TODO: shared bool shared = reader.ReadBoolean(); bool sharedSet = reader.ReadBoolean(); - - // TODO: handle shared - AddDefKey(position, this.GetTypeExtension(typeIdentifier)); + + string extension = GetTypeExtension(typeIdentifier); + + keys.Add(new KeyMapping(extension) { Shared = shared, SharedSet = sharedSet, Position = position }); } - private void ReadDefAttribute() + void ReadDefAttribute() { string text = reader.ReadString(); short identifier = reader.ReadInt16(); @@ -923,53 +980,31 @@ namespace Ricciolo.StylesExplorer.MarkupReflection if (recordName != "Key") throw new NotSupportedException(recordName); pd = new PropertyDeclaration(recordName, XamlTypeDeclaration); - AddDefKey(-1, text); + keys.Add(new KeyMapping(text) { Position = -1 }); break; } - XmlBamlProperty property = new XmlBamlProperty(PropertyType.Key, pd); + XmlBamlProperty property = new XmlBamlProperty(elements.Peek(), PropertyType.Key, pd); property.Value = text; nodes.Enqueue(property); } - private void ReadDefAttributeKeyString() + void ReadDefAttributeKeyString() { - short num = reader.ReadInt16(); + short stringId = reader.ReadInt16(); int position = reader.ReadInt32(); - //bool shared = reader.ReadBoolean(); - //bool sharedSet = reader.ReadBoolean(); - string text = this.stringTable[num]; + bool shared = reader.ReadBoolean(); + bool sharedSet = reader.ReadBoolean(); + + string text = this.stringTable[stringId]; if (text == null) throw new NotSupportedException(); - AddDefKey(position, text); + keys.Add(new KeyMapping(text) { Position = position }); } - private void AddDefKey(long position, string text) - { - // Guardo se la dichiarazione delle chiavi risulta chiusa - // Se è aperta c'è un sotto ResourceDictionary oppure è il root ResourceDictionary - if (isDefKeysClosed) - { - keysResources.Push(new KeysResourcesCollection()); - } - - // Guardo se è stata chiusa la dichiarazione parziale (mediante dichiarazione OptimizedStaticResource) - // Si chiude il ciclo di chiavi - if (isPartialDefKeysClosed) - { - keysResources.Peek().Add(new KeysResource()); - } - isDefKeysClosed = false; - isPartialDefKeysClosed = false; - - // TODO: handle shared - if (position >= 0) - keysResources.Peek().Last.Keys[position] = text; - } - - private void ReadXmlnsProperty() + void ReadXmlnsProperty() { string prefix = reader.ReadString(); string @namespace = reader.ReadString(); @@ -1001,19 +1036,13 @@ namespace Ricciolo.StylesExplorer.MarkupReflection namespaces.Add(new XmlNamespace(prefix, @namespace)); } - private void ReadElementEnd() + void ReadElementEnd() { CloseElement(); - - // Provvedo all'eliminazione del gruppo di chiavi se sono sul root ResourceDictionary - // e si è chiuso uno degli elementi di primo livello e tutte le chiavi sono state usate - // Passo alla prossima lista - KeysResource keysResource = (elements.Count == 1 && keysResources.Count > 0) ? keysResources.Peek().First : null; - if (keysResource != null && keysResource.Keys.Count == 0) - keysResources.Peek().RemoveAt(0); + LayerPop(); } - private void ReadPropertyComplexStart() + void ReadPropertyComplexStart() { short identifier = reader.ReadInt16(); @@ -1026,7 +1055,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection complexPropertyOpened++; } - private XmlBamlElement FindXmlBamlElement() + XmlBamlElement FindXmlBamlElement() { return elements.Peek(); @@ -1040,7 +1069,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection //return element; } - private void ReadPropertyListStart() + void ReadPropertyListStart() { short identifier = reader.ReadInt16(); @@ -1051,28 +1080,27 @@ namespace Ricciolo.StylesExplorer.MarkupReflection nodes.Enqueue(property); } - private void ReadPropertyListEnd() + void ReadPropertyListEnd() { CloseElement(); } - private void ReadPropertyComplexEnd() + void ReadPropertyComplexEnd() { XmlBamlPropertyElement propertyElement = (XmlBamlPropertyElement) elements.Peek(); CloseElement(); complexPropertyOpened--; - // Valuto se contiene tutte extension + // this property could be a markup extension + // try to convert it int start = nodes.IndexOf(propertyElement) + 1; IEnumerator enumerator = nodes.GetEnumerator(); + + // move enumerator to the start of this property value + for (int i = 0; i < start && enumerator.MoveNext(); i++) ; - int c = 0; - while (c < start && enumerator.MoveNext()) - c++; - - if (IsExtension(enumerator)) - { + if (IsExtension(enumerator)) { start--; nodes.RemoveAt(start); nodes.RemoveLast(); @@ -1081,15 +1109,13 @@ namespace Ricciolo.StylesExplorer.MarkupReflection FormatElementExtension((XmlBamlElement) nodes[start], sb); XmlBamlProperty property = - new XmlBamlProperty(PropertyType.Complex, propertyElement.PropertyDeclaration); + new XmlBamlProperty(elements.Peek(), PropertyType.Complex, propertyElement.PropertyDeclaration); property.Value = sb.ToString(); nodes.Add(property); - - return; } } - private void FormatElementExtension(XmlBamlElement element, StringBuilder sb) + void FormatElementExtension(XmlBamlElement element, StringBuilder sb) { sb.Append("{"); sb.Append(FormatTypeDeclaration(element.TypeDeclaration)); @@ -1143,36 +1169,37 @@ namespace Ricciolo.StylesExplorer.MarkupReflection sb.Append(sep); sb.Append(((XmlBamlText)node).Text); } - sep = ","; + sep = ", "; } } - private static bool IsExtension(IEnumerator enumerator) + bool IsExtension(IEnumerator enumerator) { - bool r = true; - while (enumerator.MoveNext() && r) - { + while (enumerator.MoveNext()) { object node = enumerator.Current; if (node is XmlBamlElement && !(node is XmlBamlEndElement) && !((XmlBamlElement)node).TypeDeclaration.IsExtension) - { - r = false; - } + return false; } - return r; + return true; } - private void CloseElement() + void CloseElement() { - nodes.Enqueue(new XmlBamlEndElement(elements.Pop())); + var e = elements.Pop(); + if (!e.IsImplicit) + nodes.Enqueue(new XmlBamlEndElement(e)); } - private void ReadElementStart() + void ReadElementStart() { + LayerPush(); short identifier = reader.ReadInt16(); sbyte flags = reader.ReadSByte(); if (flags < 0 || flags > 3) throw new NotImplementedException(); + Debug.Print("ElementFlags: " + flags); + TypeDeclaration declaration = GetTypeDeclaration(identifier); XmlBamlElement element; @@ -1197,47 +1224,41 @@ namespace Ricciolo.StylesExplorer.MarkupReflection oldDeclaration = declaration; declaration = GetKnownTypeDeclarationByName(declaration.Type.BaseType.AssemblyQualifiedName); } - element.TypeDeclaration = declaration; + element.IsImplicit = (flags & 2) == 2; elements.Push(element); - nodes.Enqueue(element); + if (!element.IsImplicit) + nodes.Enqueue(element); if (oldDeclaration != null) { nodes.Enqueue(new XmlBamlSimpleProperty(XWPFNamespace, "Class", string.Format("{0}.{1}", oldDeclaration.Namespace, oldDeclaration.Name))); } - if (parentElement != null && complexPropertyOpened == 0) - { - // Calcolo la posizione dell'elemento rispetto al padre - long position = element.Position - parentElement.Position; - KeysResource keysResource = (keysResources.Count > 0) ? keysResources.Peek().First : null; - if (keysResource != null && keysResource.Keys.HasKey(position)) - { - string key = keysResource.Keys[position]; - // Rimuovo la chiave perché è stata usata - keysResource.Keys.Remove(position); - + if (parentElement != null && complexPropertyOpened == 0 && !Current.IsInStaticResource && Current.Previous.IsDeferred) { + if (keys != null && keys.Count > currentKey) { + string key = keys[currentKey].KeyString; AddKeyToElement(key); + currentKey++; } } } - private void AddKeyToElement(string key) + void AddKeyToElement(string key) { PropertyDeclaration pd = new PropertyDeclaration("Key", XamlTypeDeclaration); - XmlBamlProperty property = new XmlBamlProperty(PropertyType.Key, pd); + XmlBamlProperty property = new XmlBamlProperty(elements.Peek(), PropertyType.Key, pd); property.Value = key; nodes.Enqueue(property); } - private XmlPIMapping FindByClrNamespaceAndAssemblyId(TypeDeclaration declaration) + XmlPIMapping FindByClrNamespaceAndAssemblyId(TypeDeclaration declaration) { return FindByClrNamespaceAndAssemblyId(declaration.Namespace, declaration.AssemblyId); } - private XmlPIMapping FindByClrNamespaceAndAssemblyId(string clrNamespace, int assemblyId) + XmlPIMapping FindByClrNamespaceAndAssemblyId(string clrNamespace, int assemblyId) { if (clrNamespace == XamlTypeDeclaration.Namespace && assemblyId == XamlTypeDeclaration.AssemblyId) return new XmlPIMapping(XmlPIMapping.XamlNamespace, 0, clrNamespace); @@ -1252,7 +1273,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection return null; } - private void ReadPIMapping() + void ReadPIMapping() { string xmlNamespace = reader.ReadString(); string clrNamespace = reader.ReadString(); @@ -1261,26 +1282,26 @@ namespace Ricciolo.StylesExplorer.MarkupReflection Mappings.Add(new XmlPIMapping(xmlNamespace, assemblyId, clrNamespace)); } - private void ReadContentProperty() + void ReadContentProperty() { reader.ReadInt16(); // Non serve aprire niente, è il default } - private static void ReadConstructorParametersStart() + static void ReadConstructorParametersStart() { //this.constructorParameterTable.Add(this.elements.Peek()); //PromoteDataToComplexProperty(); } - private static void ReadConstructorParametersEnd() + static void ReadConstructorParametersEnd() { //this.constructorParameterTable.Remove(this.elements.Peek()); //properties.Pop(); } - private void ReadConstructorParameterType() + void ReadConstructorParameterType() { short identifier = reader.ReadInt16(); @@ -1288,14 +1309,14 @@ namespace Ricciolo.StylesExplorer.MarkupReflection nodes.Enqueue(new XmlBamlText(GetTypeExtension(identifier))); } - private void ReadText() + void ReadText() { string text = reader.ReadString(); nodes.Enqueue(new XmlBamlText(text)); } - private void ReadKeyElementStart() + void ReadKeyElementStart() { short typeIdentifier = reader.ReadInt16(); byte valueIdentifier = reader.ReadByte(); @@ -1315,7 +1336,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection complexPropertyOpened++; } - private void ReadKeyElementEnd() + void ReadKeyElementEnd() { XmlBamlPropertyElement propertyElement = (XmlBamlPropertyElement)elements.Peek(); @@ -1328,46 +1349,51 @@ namespace Ricciolo.StylesExplorer.MarkupReflection StringBuilder sb = new StringBuilder(); FormatElementExtension((XmlBamlElement)nodes[start], sb); - AddDefKey(propertyElement.Position, sb.ToString()); + keys.Add(new KeyMapping(sb.ToString()) { Position = -1 }); } } - private static void ReadStaticResourceStart() + void ReadStaticResourceStart() { - //short identifier = reader.ReadInt16(); - //byte n = reader.ReadByte(); - //TypeDeclaration declaration = this.GetTypeDeclaration(identifier); - //this.staticResourceTable.Add(declaration); - - throw new NotImplementedException("StaticResourceStart"); + Current.IsInStaticResource = true; + short identifier = reader.ReadInt16(); + byte flags = reader.ReadByte(); + TypeDeclaration declaration = GetTypeDeclaration(identifier); + LastKey.StaticResources.Add(declaration); + XmlBamlElement element; + if (elements.Any()) + element = new XmlBamlElement(elements.Peek()); + else + element = new XmlBamlElement(); + element.TypeDeclaration = declaration; + elements.Push(element); + nodes.Enqueue(element); } - private static void ReadStaticResourceEnd() + void ReadStaticResourceEnd() { - throw new NotImplementedException("ReadStaticResourceEnd"); + CloseElement(); + Current.IsInStaticResource = false; } - private static void ReadStaticResourceId() + void ReadStaticResourceId() { - //short identifier = reader.ReadInt16(); - //object staticResource = this.GetStaticResource(identifier); - //TypeDeclaration declaration = this.GetTypeDeclaration(-603); - - throw new NotImplementedException("StaticResourceId"); + short identifier = reader.ReadInt16(); + object staticResource = GetStaticResource(identifier); } - private void ReadPresentationOptionsAttribute() + void ReadPresentationOptionsAttribute() { string text = reader.ReadString(); short valueIdentifier = reader.ReadInt16(); PropertyDeclaration pd = new PropertyDeclaration(this.stringTable[valueIdentifier].ToString()); - XmlBamlProperty property = new XmlBamlProperty(PropertyType.Value, pd); + XmlBamlProperty property = new XmlBamlProperty(elements.Peek(), PropertyType.Value, pd); property.Value = text; } - private void ReadPropertyTypeReference() + void ReadPropertyTypeReference() { short identifier = reader.ReadInt16(); short typeIdentifier = reader.ReadInt16(); @@ -1375,13 +1401,13 @@ namespace Ricciolo.StylesExplorer.MarkupReflection PropertyDeclaration pd = this.GetPropertyDeclaration(identifier); string value = this.GetTypeExtension(typeIdentifier); - XmlBamlProperty property = new XmlBamlProperty(PropertyType.Value, pd); + XmlBamlProperty property = new XmlBamlProperty(elements.Peek(), PropertyType.Value, pd); property.Value = value; nodes.Enqueue(property); } - private void ReadOptimizedStaticResource() + void ReadOptimizedStaticResource() { byte num = reader.ReadByte(); short typeIdentifier = reader.ReadInt16(); @@ -1404,15 +1430,15 @@ namespace Ricciolo.StylesExplorer.MarkupReflection //this.staticResourceTable.Add(resource); isPartialDefKeysClosed = true; // Aggiungo la risorsa nell'ultimo gruppo - keysResources.Peek().Last.StaticResources.Add(resource); + LastKey.StaticResources.Add(resource); } - private string GetTemplateBindingExtension(PropertyDeclaration propertyDeclaration) + string GetTemplateBindingExtension(PropertyDeclaration propertyDeclaration) { return String.Format("{{TemplateBinding {0}}}", FormatPropertyDeclaration(propertyDeclaration, true, false, false)); } - private string GetStaticExtension(string name) + string GetStaticExtension(string name) { string prefix = this.LookupPrefix(XmlPIMapping.XamlNamespace, false); if (String.IsNullOrEmpty(prefix)) @@ -1421,12 +1447,12 @@ namespace Ricciolo.StylesExplorer.MarkupReflection return String.Format("{{{0}:Static {1}}}", prefix, name); } - private string GetExtension(TypeDeclaration declaration, string value) + string GetExtension(TypeDeclaration declaration, string value) { return String.Format("{{{0} {1}}}", FormatTypeDeclaration(declaration), value); } - private string GetTypeExtension(short typeIdentifier) + string GetTypeExtension(short typeIdentifier) { string prefix = this.LookupPrefix(XmlPIMapping.XamlNamespace, false); if (String.IsNullOrEmpty(prefix)) @@ -1435,7 +1461,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection return String.Format("{{{0}:Type {1}}}", prefix, FormatTypeDeclaration(GetTypeDeclaration(typeIdentifier))); } - private string FormatTypeDeclaration(TypeDeclaration typeDeclaration) + string FormatTypeDeclaration(TypeDeclaration typeDeclaration) { XmlPIMapping mapping = FindByClrNamespaceAndAssemblyId(typeDeclaration.Namespace, typeDeclaration.AssemblyId); string prefix = (mapping != null) ? this.LookupPrefix(mapping.XmlNamespace, false) : null; @@ -1450,7 +1476,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection - private string FormatPropertyDeclaration(PropertyDeclaration propertyDeclaration, bool withPrefix, bool useReading, bool checkType) + string FormatPropertyDeclaration(PropertyDeclaration propertyDeclaration, bool withPrefix, bool useReading, bool checkType) { StringBuilder sb = new StringBuilder(); @@ -1465,19 +1491,16 @@ namespace Ricciolo.StylesExplorer.MarkupReflection bool isAttached = (descriptor != null && descriptor.IsAttached); bool differentType = ((propertyDeclaration.DeclaringType != propertyDeclaration.DeclaringType || !isDescendant)); - if (withPrefix) - { + if (withPrefix) { XmlPIMapping mapping = FindByClrNamespaceAndAssemblyId(propertyDeclaration.DeclaringType.Namespace, propertyDeclaration.DeclaringType.AssemblyId); string prefix = (mapping != null) ? this.LookupPrefix(mapping.XmlNamespace, false) : null; - if (!String.IsNullOrEmpty(prefix)) - { + if (!String.IsNullOrEmpty(prefix)) { sb.Append(prefix); sb.Append(":"); } } - if ((differentType || isAttached || !checkType) && propertyDeclaration.DeclaringType.Name.Length > 0) - { + if ((differentType || isAttached || !checkType) && propertyDeclaration.DeclaringType.Name.Length > 0) { sb.Append(propertyDeclaration.DeclaringType.Name); sb.Append("."); } @@ -1486,47 +1509,33 @@ namespace Ricciolo.StylesExplorer.MarkupReflection return sb.ToString(); } - private void ReadPropertyWithStaticResourceIdentifier() + void ReadPropertyWithStaticResourceIdentifier() { short identifier = reader.ReadInt16(); short staticIdentifier = reader.ReadInt16(); PropertyDeclaration pd = this.GetPropertyDeclaration(identifier); - object staticResource = this.GetStaticResource(staticIdentifier); + object staticResource = GetStaticResource(staticIdentifier); string prefix = this.LookupPrefix(XmlPIMapping.PresentationNamespace, false); string value = String.Format("{{{0}{1}StaticResource {2}}}", prefix, (String.IsNullOrEmpty(prefix)) ? String.Empty : ":", staticResource); - XmlBamlProperty property = new XmlBamlProperty(PropertyType.Value, pd); + XmlBamlProperty property = new XmlBamlProperty(elements.Peek(), PropertyType.Value, pd); property.Value = value; nodes.Enqueue(property); } - - private object GetStaticResource(short identifier) + object GetStaticResource(short identifier) { - // Recupero la risorsa nel gruppo corrente - foreach (KeysResourcesCollection resource in keysResources) - { - // TODO: controllare. Se non lo trova nel gruppo corrente, va in quello successivo - for (int x = 0; x < resource.Count; x++) - { - KeysResource resourceGroup = resource[x]; - if (resourceGroup.StaticResources.Count > identifier) - if (x > 0) - break; - //return "%" + resourceGroup.StaticResources[identifier] + "%"; - else - return resourceGroup.StaticResources[identifier]; - } - } + if (identifier < LastKey.StaticResources.Count) + return LastKey.StaticResources[(int)identifier]; - //return "???"; +// return "???" + identifier +"???"; throw new ArgumentException("Cannot find StaticResource", "identifier"); } - private void ReadTextWithConverter() + void ReadTextWithConverter() { string text = reader.ReadString(); reader.ReadInt16(); @@ -1534,7 +1543,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection nodes.Enqueue(new XmlBamlText(text)); } - private void ReadTypeInfo() + void ReadTypeInfo() { short typeId = reader.ReadInt16(); short assemblyId = reader.ReadInt16(); @@ -1555,21 +1564,21 @@ namespace Ricciolo.StylesExplorer.MarkupReflection this.typeTable.Add(typeId, declaration); } - private void ReadAssemblyInfo() + void ReadAssemblyInfo() { short key = reader.ReadInt16(); string text = reader.ReadString(); this.assemblyTable.Add(key, text); } - private void ReadStringInfo() + void ReadStringInfo() { short key = reader.ReadInt16(); string text = reader.ReadString(); this.stringTable.Add(key, text); } - private TypeDeclaration GetTypeDeclaration(short identifier) + TypeDeclaration GetTypeDeclaration(short identifier) { TypeDeclaration declaration; if (identifier >= 0) @@ -1598,7 +1607,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection return this.assemblyTable[identifier]; } - private XmlBamlNode CurrentNode + XmlBamlNode CurrentNode { get { @@ -1624,13 +1633,17 @@ namespace Ricciolo.StylesExplorer.MarkupReflection XmlBamlNode node = this.CurrentNode; if (node is XmlBamlSimpleProperty) return ((XmlBamlSimpleProperty)node).NamespaceName; - else if (node is XmlBamlProperty) - { + else if (node is XmlBamlProperty) { declaration = ((XmlBamlProperty)node).PropertyDeclaration.DeclaringType; TypeDeclaration elementDeclaration = this.readingElements.Peek().TypeDeclaration; XmlPIMapping propertyMapping = FindByClrNamespaceAndAssemblyId(declaration) ?? XmlPIMapping.Presentation; XmlPIMapping elementMapping = FindByClrNamespaceAndAssemblyId(elementDeclaration) ?? XmlPIMapping.Presentation; + + if (((XmlBamlProperty)node).PropertyDeclaration.Name == "Name" && + _resolver.IsLocalAssembly(((XmlBamlProperty)node).Parent.TypeDeclaration.Assembly)) + return XWPFNamespace; + if (String.CompareOrdinal(propertyMapping.XmlNamespace, elementMapping.XmlNamespace) == 0 || (elementDeclaration.Type != null && declaration.Type != null && elementDeclaration.Type.IsSubclassOf(declaration.Type))) return String.Empty; @@ -1886,7 +1899,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection return this.LookupPrefix(namespaceName, true); } - private string LookupPrefix(string namespaceName, bool useReading) + string LookupPrefix(string namespaceName, bool useReading) { Stack elements; if (useReading) @@ -1900,7 +1913,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection return LookupPrefix(namespaceName, namespaces); } - private static string LookupPrefix(string namespaceName, XmlNamespaceCollection namespaces) + static string LookupPrefix(string namespaceName, XmlNamespaceCollection namespaces) { for (int x = 0; x < namespaces.Count; x++) { @@ -1959,7 +1972,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection return DequeueInternal(false); } - private XmlBamlNode DequeueInternal(bool remove) + XmlBamlNode DequeueInternal(bool remove) { if (this.Count > 0) { diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlSimpleProperty.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlSimpleProperty.cs index be00e41e1..9440ded4b 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlSimpleProperty.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlSimpleProperty.cs @@ -30,5 +30,11 @@ namespace Ricciolo.StylesExplorer.MarkupReflection public override XmlNodeType NodeType { get { return XmlNodeType.Attribute; } } + + public override string ToString() + { + return string.Format("{{{0}}}{1}=\"{2}\"", NamespaceName, LocalName, Value); + } + } } diff --git a/ILSpy.BamlDecompiler/Tests/Cases/AttachedEvent.xaml b/ILSpy.BamlDecompiler/Tests/Cases/AttachedEvent.xaml new file mode 100644 index 000000000..866abc9b6 --- /dev/null +++ b/ILSpy.BamlDecompiler/Tests/Cases/AttachedEvent.xaml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/ILSpy.BamlDecompiler/Tests/Cases/AttachedEvent.xaml.cs b/ILSpy.BamlDecompiler/Tests/Cases/AttachedEvent.xaml.cs new file mode 100644 index 000000000..f0ec0f875 --- /dev/null +++ b/ILSpy.BamlDecompiler/Tests/Cases/AttachedEvent.xaml.cs @@ -0,0 +1,31 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; + +namespace ILSpy.BamlDecompiler.Tests.Cases +{ + /// + /// Interaction logic for AttachedEvent.xaml + /// + public partial class AttachedEvent : Window + { + public AttachedEvent() + { + InitializeComponent(); + } + + void GridAccessKeyPressed(object sender, AccessKeyPressedEventArgs e) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/ILSpy.BamlDecompiler/Tests/Cases/AvalonDockBrushes.xaml b/ILSpy.BamlDecompiler/Tests/Cases/AvalonDockBrushes.xaml new file mode 100644 index 000000000..cc7e517c9 --- /dev/null +++ b/ILSpy.BamlDecompiler/Tests/Cases/AvalonDockBrushes.xaml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ILSpy.BamlDecompiler/Tests/Cases/AvalonDockCommon.xaml b/ILSpy.BamlDecompiler/Tests/Cases/AvalonDockCommon.xaml new file mode 100644 index 000000000..2f4435793 --- /dev/null +++ b/ILSpy.BamlDecompiler/Tests/Cases/AvalonDockCommon.xaml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ILSpy.BamlDecompiler/Tests/Cases/MyControl.xaml b/ILSpy.BamlDecompiler/Tests/Cases/MyControl.xaml new file mode 100644 index 000000000..4e8c218e0 --- /dev/null +++ b/ILSpy.BamlDecompiler/Tests/Cases/MyControl.xaml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/ILSpy.BamlDecompiler/Tests/Cases/MyControl.xaml.cs b/ILSpy.BamlDecompiler/Tests/Cases/MyControl.xaml.cs new file mode 100644 index 000000000..6a0932d4e --- /dev/null +++ b/ILSpy.BamlDecompiler/Tests/Cases/MyControl.xaml.cs @@ -0,0 +1,26 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; + +namespace ILSpy.BamlDecompiler.Tests.Cases +{ + /// + /// Interaction logic for MyControl.xaml + /// + public partial class MyControl : UserControl + { + public MyControl() + { + InitializeComponent(); + } + } +} \ No newline at end of file diff --git a/ILSpy.BamlDecompiler/Tests/Cases/Resources.xaml b/ILSpy.BamlDecompiler/Tests/Cases/Resources.xaml new file mode 100644 index 000000000..7e1a0514a --- /dev/null +++ b/ILSpy.BamlDecompiler/Tests/Cases/Resources.xaml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ILSpy.BamlDecompiler/Tests/Cases/Resources.xaml.cs b/ILSpy.BamlDecompiler/Tests/Cases/Resources.xaml.cs new file mode 100644 index 000000000..1dbef3631 --- /dev/null +++ b/ILSpy.BamlDecompiler/Tests/Cases/Resources.xaml.cs @@ -0,0 +1,26 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; + +namespace ILSpy.BamlDecompiler.Tests.Cases +{ + /// + /// Interaction logic for Resources.xaml + /// + public partial class Resources : Window + { + public Resources() + { + InitializeComponent(); + } + } +} \ No newline at end of file diff --git a/ILSpy.BamlDecompiler/Tests/Cases/SimpleNames.xaml b/ILSpy.BamlDecompiler/Tests/Cases/SimpleNames.xaml new file mode 100644 index 000000000..3d94c5052 --- /dev/null +++ b/ILSpy.BamlDecompiler/Tests/Cases/SimpleNames.xaml @@ -0,0 +1,6 @@ + + +