Browse Source

Merge branch '1.0'

pull/263/head
Daniel Grunwald 16 years ago
parent
commit
c43d47589a
  1. 6
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  2. 17
      ICSharpCode.Decompiler/Ast/NameVariables.cs
  3. 35
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  4. 1
      ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
  5. 4
      ICSharpCode.Decompiler/ILAst/ILCodes.cs
  6. 145
      ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs
  7. 35
      ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
  8. 133
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  9. 1
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  10. 79
      ICSharpCode.Decompiler/Tests/InitializerTests.cs
  11. 6
      ICSharpCode.Decompiler/Tests/TestRunner.cs
  12. 109
      ICSharpCode.Decompiler/Tests/TypeAnalysisTests.cs
  13. 3
      ILSpy.BamlDecompiler/CecilDependencyPropertyDescriptor.cs
  14. 2
      ILSpy.BamlDecompiler/CecilType.cs
  15. 2
      ILSpy.BamlDecompiler/CecilTypeResolver.cs
  16. 8
      ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj
  17. 183
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/AppDomainTypeResolver.cs
  18. 112
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlAssembly.cs
  19. 80
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlFile.cs
  20. 64
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/DotNetType.cs
  21. 6
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/KeyMapping.cs
  22. 4
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/KnownInfo.cs
  23. 68
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/NodesCollection.cs
  24. 80
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs
  25. 35
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/WpfDependencyPropertyDescriptor.cs
  26. 19
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlElement.cs
  27. 2
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlPropertyElement.cs
  28. 210
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs
  29. 23
      ILSpy.BamlDecompiler/Tests/Cases/Dictionary1.xaml
  30. 1
      ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj
  31. 17
      ILSpy.BamlDecompiler/Tests/TestRunner.cs
  32. 4
      ILSpy/AssemblyList.cs
  33. 9
      ILSpy/LoadedAssembly.cs
  34. 15
      ILSpy/MainWindow.xaml.cs
  35. 2
      ILSpy/XmlDoc/XmlDocKeyProvider.cs
  36. 4
      SharpTreeView/SharpTreeView.cs

6
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -782,9 +782,15 @@ namespace ICSharpCode.Decompiler.Ast
} }
} }
ObjectCreateExpression oce = arg1 as ObjectCreateExpression; ObjectCreateExpression oce = arg1 as ObjectCreateExpression;
DefaultValueExpression dve = arg1 as DefaultValueExpression;
if (oce != null) { if (oce != null) {
oce.Initializer = initializer; oce.Initializer = initializer;
return oce; return oce;
} else if (dve != null) {
oce = new ObjectCreateExpression(dve.Type.Detach());
oce.CopyAnnotationsFrom(dve);
oce.Initializer = initializer;
return oce;
} else { } else {
return new AssignmentExpression(arg1, initializer); return new AssignmentExpression(arg1, initializer);
} }

17
ICSharpCode.Decompiler/Ast/NameVariables.cs

@ -62,7 +62,7 @@ namespace ICSharpCode.Decompiler.Ast
nv.AddExistingName(v.Name); nv.AddExistingName(v.Name);
} else if (v.OriginalVariable != null && context.Settings.UseDebugSymbols) { } else if (v.OriginalVariable != null && context.Settings.UseDebugSymbols) {
string varName = v.OriginalVariable.Name; string varName = v.OriginalVariable.Name;
if (string.IsNullOrEmpty(varName) || varName.StartsWith("V_", StringComparison.Ordinal) || varName.StartsWith("CS$", StringComparison.Ordinal)) if (string.IsNullOrEmpty(varName) || varName.StartsWith("V_", StringComparison.Ordinal) || !IsValidName(varName))
{ {
// don't use the name from the debug symbols if it looks like a generated name // don't use the name from the debug symbols if it looks like a generated name
v.Name = null; v.Name = null;
@ -86,6 +86,19 @@ namespace ICSharpCode.Decompiler.Ast
} }
} }
static bool IsValidName(string varName)
{
if (string.IsNullOrEmpty(varName))
return false;
if (!(char.IsLetter(varName[0]) || varName[0] == '_'))
return false;
for (int i = 1; i < varName.Length; i++) {
if (!(char.IsLetterOrDigit(varName[i]) || varName[i] == '_'))
return false;
}
return true;
}
DecompilerContext context; DecompilerContext context;
List<string> fieldNamesInCurrentType; List<string> fieldNamesInCurrentType;
Dictionary<string, int> typeNames = new Dictionary<string, int>(); Dictionary<string, int> typeNames = new Dictionary<string, int>();
@ -139,7 +152,7 @@ namespace ICSharpCode.Decompiler.Ast
typeNames.Add(nameWithoutDigits, number - 1); typeNames.Add(nameWithoutDigits, number - 1);
} }
int count = ++typeNames[nameWithoutDigits]; int count = ++typeNames[nameWithoutDigits];
if (count > 1) { if (count != 1) {
return nameWithoutDigits + count.ToString(); return nameWithoutDigits + count.ToString();
} else { } else {
return nameWithoutDigits; return nameWithoutDigits;

35
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -42,6 +42,7 @@ namespace ICSharpCode.Decompiler.ILAst
SimplifyTernaryOperator, SimplifyTernaryOperator,
SimplifyNullCoalescing, SimplifyNullCoalescing,
JoinBasicBlocks, JoinBasicBlocks,
SimplifyShiftOperators,
TransformDecimalCtorToConstant, TransformDecimalCtorToConstant,
SimplifyLdObjAndStObj, SimplifyLdObjAndStObj,
SimplifyCustomShortCircuit, SimplifyCustomShortCircuit,
@ -54,6 +55,7 @@ namespace ICSharpCode.Decompiler.ILAst
FindLoops, FindLoops,
FindConditions, FindConditions,
FlattenNestedMovableBlocks, FlattenNestedMovableBlocks,
RemoveEndFinally,
RemoveRedundantCode2, RemoveRedundantCode2,
GotoRemoval, GotoRemoval,
DuplicateReturns, DuplicateReturns,
@ -131,7 +133,10 @@ namespace ICSharpCode.Decompiler.ILAst
if (abortBeforeStep == ILAstOptimizationStep.JoinBasicBlocks) return; if (abortBeforeStep == ILAstOptimizationStep.JoinBasicBlocks) return;
modified |= block.RunOptimization(new SimpleControlFlow(context, method).JoinBasicBlocks); modified |= block.RunOptimization(new SimpleControlFlow(context, method).JoinBasicBlocks);
if (abortBeforeStep == ILAstOptimizationStep.SimplifyShiftOperators) return;
modified |= block.RunOptimization(SimplifyShiftOperators);
if (abortBeforeStep == ILAstOptimizationStep.TransformDecimalCtorToConstant) return; if (abortBeforeStep == ILAstOptimizationStep.TransformDecimalCtorToConstant) return;
modified |= block.RunOptimization(TransformDecimalCtorToConstant); modified |= block.RunOptimization(TransformDecimalCtorToConstant);
modified |= block.RunOptimization(SimplifyLdcI4ConvI8); modified |= block.RunOptimization(SimplifyLdcI4ConvI8);
@ -178,6 +183,9 @@ namespace ICSharpCode.Decompiler.ILAst
if (abortBeforeStep == ILAstOptimizationStep.FlattenNestedMovableBlocks) return; if (abortBeforeStep == ILAstOptimizationStep.FlattenNestedMovableBlocks) return;
FlattenBasicBlocks(method); FlattenBasicBlocks(method);
if (abortBeforeStep == ILAstOptimizationStep.RemoveEndFinally) return;
RemoveEndFinally(method);
if (abortBeforeStep == ILAstOptimizationStep.RemoveRedundantCode2) return; if (abortBeforeStep == ILAstOptimizationStep.RemoveRedundantCode2) return;
RemoveRedundantCode(method); RemoveRedundantCode(method);
@ -534,6 +542,25 @@ namespace ICSharpCode.Decompiler.ILAst
} }
} }
/// <summary>
/// Replace endfinally with jump to the end of the finally block
/// </summary>
void RemoveEndFinally(ILBlock method)
{
// Go thought the list in reverse so that we do the nested blocks first
foreach(var tryCatch in method.GetSelfAndChildrenRecursive<ILTryCatchBlock>(tc => tc.FinallyBlock != null).Reverse()) {
ILLabel label = new ILLabel() { Name = "EndFinally_" + nextLabelIndex++ };
tryCatch.FinallyBlock.Body.Add(label);
foreach(var block in tryCatch.FinallyBlock.GetSelfAndChildrenRecursive<ILBlock>()) {
for (int i = 0; i < block.Body.Count; i++) {
if (block.Body[i].Match(ILCode.Endfinally)) {
block.Body[i] = new ILExpression(ILCode.Br, label).WithILRanges(((ILExpression)block.Body[i]).ILRanges);
}
}
}
}
}
/// <summary> /// <summary>
/// Reduce the nesting of conditions. /// Reduce the nesting of conditions.
/// It should be done on flat data that already had most gotos removed /// It should be done on flat data that already had most gotos removed
@ -766,6 +793,12 @@ namespace ICSharpCode.Decompiler.ILAst
} }
} }
public static ILExpression WithILRanges(this ILExpression expr, IEnumerable<ILRange> ilranges)
{
expr.ILRanges.AddRange(ilranges);
return expr;
}
public static void RemoveTail(this List<ILNode> body, params ILCode[] codes) public static void RemoveTail(this List<ILNode> body, params ILCode[] codes)
{ {
for (int i = 0; i < codes.Length; i++) { for (int i = 0; i < codes.Length; i++) {

1
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

@ -43,6 +43,7 @@ namespace ICSharpCode.Decompiler.ILAst
void AccumulateSelfAndChildrenRecursive<T>(List<T> list, Func<T, bool> predicate) where T:ILNode void AccumulateSelfAndChildrenRecursive<T>(List<T> list, Func<T, bool> predicate) where T:ILNode
{ {
// Note: RemoveEndFinally depends on self coming before children
T thisAsT = this as T; T thisAsT = this as T;
if (thisAsT != null && (predicate == null || predicate(thisAsT))) if (thisAsT != null && (predicate == null || predicate(thisAsT)))
list.Add(thisAsT); list.Add(thisAsT);

4
ICSharpCode.Decompiler/ILAst/ILCodes.cs

@ -261,8 +261,8 @@ namespace ICSharpCode.Decompiler.ILAst
// InitCollection(CallGetter(Collection, InitializedObject))), // InitCollection(CallGetter(Collection, InitializedObject))),
// Call(Add, InitializedObject, 2, 3), // Call(Add, InitializedObject, 2, 3),
// Call(Add, InitializedObject, 4, 5))) // Call(Add, InitializedObject, 4, 5)))
InitObject, // Object initializer: first arg is newobj, remaining args are the initializing statements InitObject, // Object initializer: first arg is newobj/defaultvalue, remaining args are the initializing statements
InitCollection, // Collection initializer: first arg is newobj, remaining args are the initializing statements InitCollection, // Collection initializer: first arg is newobj/defaultvalue, remaining args are the initializing statements
InitializedObject, // Refers the the object being initialized (refers to first arg in parent InitObject or InitCollection instruction) InitializedObject, // Refers the the object being initialized (refers to first arg in parent InitObject or InitCollection instruction)
TernaryOp, // ?: TernaryOp, // ?:

145
ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs

@ -93,9 +93,9 @@ namespace ICSharpCode.Decompiler.ILAst
List<ILExpression> ctorArgs; List<ILExpression> ctorArgs;
ArrayType arrayType; ArrayType arrayType;
if (expr.Match(ILCode.Stloc, out v, out newarrExpr) && if (expr.Match(ILCode.Stloc, out v, out newarrExpr) &&
newarrExpr.Match(ILCode.Newobj, out ctor, out ctorArgs) && newarrExpr.Match(ILCode.Newobj, out ctor, out ctorArgs) &&
(arrayType = (ctor.DeclaringType as ArrayType)) != null && (arrayType = (ctor.DeclaringType as ArrayType)) != null &&
arrayType.Rank == ctorArgs.Count) { arrayType.Rank == ctorArgs.Count) {
// Clone the type, so we can muck about with the Dimensions // Clone the type, so we can muck about with the Dimensions
arrayType = new ArrayType(arrayType.ElementType, arrayType.Rank); arrayType = new ArrayType(arrayType.ElementType, arrayType.Rank);
var arrayLengths = new int[arrayType.Rank]; var arrayLengths = new int[arrayType.Rank];
@ -124,19 +124,24 @@ namespace ICSharpCode.Decompiler.ILAst
MethodReference methodRef; MethodReference methodRef;
ILExpression methodArg1; ILExpression methodArg1;
ILExpression methodArg2; ILExpression methodArg2;
FieldDefinition field; FieldReference fieldRef;
if (body.ElementAtOrDefault(pos).Match(ILCode.Call, out methodRef, out methodArg1, out methodArg2) && if (body.ElementAtOrDefault(pos).Match(ILCode.Call, out methodRef, out methodArg1, out methodArg2) &&
methodRef.DeclaringType.FullName == "System.Runtime.CompilerServices.RuntimeHelpers" && methodRef.DeclaringType.FullName == "System.Runtime.CompilerServices.RuntimeHelpers" &&
methodRef.Name == "InitializeArray" && methodRef.Name == "InitializeArray" &&
methodArg1.Match(ILCode.Ldloc, out v2) && methodArg1.Match(ILCode.Ldloc, out v2) &&
array == v2 && array == v2 &&
methodArg2.Match(ILCode.Ldtoken, out field) && methodArg2.Match(ILCode.Ldtoken, out fieldRef))
field != null && field.InitialValue != null) { {
ILExpression[] newArr = new ILExpression[arrayLength]; FieldDefinition fieldDef = fieldRef.ResolveWithinSameModule();
if (DecodeArrayInitializer(TypeAnalysis.GetTypeCode(arrayType.GetElementType()), field.InitialValue, newArr)) { if (fieldDef != null && fieldDef.InitialValue != null) {
values = newArr; ILExpression[] newArr = new ILExpression[arrayLength];
foundPos = pos; if (DecodeArrayInitializer(TypeAnalysis.GetTypeCode(arrayType.GetElementType()),
return true; fieldDef.InitialValue, newArr))
{
values = newArr;
foundPos = pos;
return true;
}
} }
} }
values = null; values = null;
@ -148,7 +153,6 @@ namespace ICSharpCode.Decompiler.ILAst
{ {
switch (elementType) { switch (elementType) {
case TypeCode.Boolean: case TypeCode.Boolean:
case TypeCode.SByte:
case TypeCode.Byte: case TypeCode.Byte:
if (initialValue.Length == output.Length) { if (initialValue.Length == output.Length) {
for (int j = 0; j < output.Length; j++) { for (int j = 0; j < output.Length; j++) {
@ -157,9 +161,15 @@ namespace ICSharpCode.Decompiler.ILAst
return true; return true;
} }
return false; return false;
case TypeCode.Char: case TypeCode.SByte:
if (initialValue.Length == output.Length) {
for (int j = 0; j < output.Length; j++) {
output[j] = new ILExpression(ILCode.Ldc_I4, (int)unchecked((sbyte)initialValue[j]));
}
return true;
}
return false;
case TypeCode.Int16: case TypeCode.Int16:
case TypeCode.UInt16:
if (initialValue.Length == output.Length * 2) { if (initialValue.Length == output.Length * 2) {
for (int j = 0; j < output.Length; j++) { for (int j = 0; j < output.Length; j++) {
output[j] = new ILExpression(ILCode.Ldc_I4, (int)BitConverter.ToInt16(initialValue, j * 2)); output[j] = new ILExpression(ILCode.Ldc_I4, (int)BitConverter.ToInt16(initialValue, j * 2));
@ -167,6 +177,15 @@ namespace ICSharpCode.Decompiler.ILAst
return true; return true;
} }
return false; return false;
case TypeCode.Char:
case TypeCode.UInt16:
if (initialValue.Length == output.Length * 2) {
for (int j = 0; j < output.Length; j++) {
output[j] = new ILExpression(ILCode.Ldc_I4, (int)BitConverter.ToUInt16(initialValue, j * 2));
}
return true;
}
return false;
case TypeCode.Int32: case TypeCode.Int32:
case TypeCode.UInt32: case TypeCode.UInt32:
if (initialValue.Length == output.Length * 4) { if (initialValue.Length == output.Length * 4) {
@ -218,18 +237,45 @@ namespace ICSharpCode.Decompiler.ILAst
Debug.Assert(body[pos] == expr); // should be called for top-level expressions only Debug.Assert(body[pos] == expr); // should be called for top-level expressions only
ILVariable v; ILVariable v;
ILExpression newObjExpr; ILExpression newObjExpr;
TypeReference newObjType;
bool isValueType;
MethodReference ctor; MethodReference ctor;
List<ILExpression> ctorArgs; List<ILExpression> ctorArgs;
// v = newObj(ctor, ctorArgs) if (expr.Match(ILCode.Stloc, out v, out newObjExpr)) {
if (!(expr.Match(ILCode.Stloc, out v, out newObjExpr) && newObjExpr.Match(ILCode.Newobj, out ctor, out ctorArgs))) if (newObjExpr.Match(ILCode.Newobj, out ctor, out ctorArgs)) {
// v = newObj(ctor, ctorArgs)
newObjType = ctor.DeclaringType;
isValueType = false;
} else if (newObjExpr.Match(ILCode.DefaultValue, out newObjType)) {
// v = defaultvalue(type)
isValueType = true;
} else {
return false;
}
} else if (expr.Match(ILCode.Call, out ctor, out ctorArgs)) {
// call(SomeStruct::.ctor, ldloca(v), remainingArgs)
if (ctorArgs.Count > 0 && ctorArgs[0].Match(ILCode.Ldloca, out v)) {
isValueType = true;
newObjType = ctor.DeclaringType;
ctorArgs = new List<ILExpression>(ctorArgs);
ctorArgs.RemoveAt(0);
newObjExpr = new ILExpression(ILCode.Newobj, ctor, ctorArgs);
} else {
return false;
}
} else {
return false;
}
if (newObjType.IsValueType != isValueType)
return false; return false;
int originalPos = pos; int originalPos = pos;
// don't use object initializer syntax for closures // don't use object initializer syntax for closures
if (Ast.Transforms.DelegateConstruction.IsPotentialClosure(context, ctor.DeclaringType.ResolveWithinSameModule())) if (Ast.Transforms.DelegateConstruction.IsPotentialClosure(context, newObjType.ResolveWithinSameModule()))
return false; return false;
ILExpression initializer = ParseObjectInitializer(body, ref pos, v, newObjExpr, IsCollectionType(ctor.DeclaringType)); ILExpression initializer = ParseObjectInitializer(body, ref pos, v, newObjExpr, IsCollectionType(newObjType), isValueType);
if (initializer.Arguments.Count == 1) // only newobj argument, no initializer elements if (initializer.Arguments.Count == 1) // only newobj argument, no initializer elements
return false; return false;
@ -242,16 +288,36 @@ namespace ICSharpCode.Decompiler.ILAst
return false; // reached end of block, but there should be another instruction which consumes the initialized object return false; // reached end of block, but there should be another instruction which consumes the initialized object
ILInlining inlining = new ILInlining(method); ILInlining inlining = new ILInlining(method);
// one ldloc for each initializer argument, and another ldloc for the use of the initialized object if (isValueType) {
if (inlining.numLdloc.GetOrDefault(v) != totalElementCount + 1) // one ldloc for the use of the initialized object
return false; if (inlining.numLdloc.GetOrDefault(v) != 1)
if (!(inlining.numStloc.GetOrDefault(v) == 1 && inlining.numLdloca.GetOrDefault(v) == 0)) return false;
return false; // one ldloca for each initializer argument, and also for the ctor call (if it exists)
if (inlining.numLdloca.GetOrDefault(v) != totalElementCount + (expr.Code == ILCode.Call ? 1 : 0))
return false;
// one stloc for the initial store (if no ctor call was used)
if (inlining.numStloc.GetOrDefault(v) != (expr.Code == ILCode.Call ? 0 : 1))
return false;
} else {
// one ldloc for each initializer argument, and another ldloc for the use of the initialized object
if (inlining.numLdloc.GetOrDefault(v) != totalElementCount + 1)
return false;
if (!(inlining.numStloc.GetOrDefault(v) == 1 && inlining.numLdloca.GetOrDefault(v) == 0))
return false;
}
ILExpression nextExpr = body[pos] as ILExpression; ILExpression nextExpr = body[pos] as ILExpression;
if (!inlining.CanInlineInto(nextExpr, v, initializer)) if (!inlining.CanInlineInto(nextExpr, v, initializer))
return false; return false;
expr.Arguments[0] = initializer; if (expr.Code == ILCode.Stloc) {
expr.Arguments[0] = initializer;
} else {
Debug.Assert(expr.Code == ILCode.Call);
expr.Code = ILCode.Stloc;
expr.Operand = v;
expr.Arguments.Clear();
expr.Arguments.Add(initializer);
}
// remove all the instructions that were pulled into the initializer // remove all the instructions that were pulled into the initializer
body.RemoveRange(originalPos + 1, pos - originalPos - 1); body.RemoveRange(originalPos + 1, pos - originalPos - 1);
@ -288,7 +354,7 @@ namespace ICSharpCode.Decompiler.ILAst
{ {
if (expr == null) if (expr == null)
return false; return false;
if (expr.Code == ILCode.CallvirtSetter || expr.Code == ILCode.Stfld) { if (expr.Code == ILCode.CallvirtSetter || expr.Code == ILCode.CallSetter || expr.Code == ILCode.Stfld) {
return expr.Arguments.Count == 2; return expr.Arguments.Count == 2;
} }
return false; return false;
@ -320,9 +386,8 @@ namespace ICSharpCode.Decompiler.ILAst
/// <param name="v">The variable that holds the object being initialized</param> /// <param name="v">The variable that holds the object being initialized</param>
/// <param name="newObjExpr">The newobj instruction</param> /// <param name="newObjExpr">The newobj instruction</param>
/// <returns>InitObject instruction</returns> /// <returns>InitObject instruction</returns>
ILExpression ParseObjectInitializer(List<ILNode> body, ref int pos, ILVariable v, ILExpression newObjExpr, bool isCollection) ILExpression ParseObjectInitializer(List<ILNode> body, ref int pos, ILVariable v, ILExpression newObjExpr, bool isCollection, bool isValueType)
{ {
Debug.Assert(((ILExpression)body[pos]).Code == ILCode.Stloc);
// Take care not to modify any existing ILExpressions in here. // Take care not to modify any existing ILExpressions in here.
// We just construct new ones around the old ones, any modifications must wait until the whole // We just construct new ones around the old ones, any modifications must wait until the whole
// object/collection initializer was analyzed. // object/collection initializer was analyzed.
@ -332,13 +397,13 @@ namespace ICSharpCode.Decompiler.ILAst
while (++pos < body.Count) { while (++pos < body.Count) {
ILExpression nextExpr = body[pos] as ILExpression; ILExpression nextExpr = body[pos] as ILExpression;
if (IsSetterInObjectInitializer(nextExpr)) { if (IsSetterInObjectInitializer(nextExpr)) {
if (!AdjustInitializerStack(initializerStack, nextExpr.Arguments[0], v, false)) { if (!AdjustInitializerStack(initializerStack, nextExpr.Arguments[0], v, false, isValueType)) {
CleanupInitializerStackAfterFailedAdjustment(initializerStack); CleanupInitializerStackAfterFailedAdjustment(initializerStack);
break; break;
} }
initializerStack[initializerStack.Count - 1].Arguments.Add(nextExpr); initializerStack[initializerStack.Count - 1].Arguments.Add(nextExpr);
} else if (IsAddMethodCall(nextExpr)) { } else if (IsAddMethodCall(nextExpr)) {
if (!AdjustInitializerStack(initializerStack, nextExpr.Arguments[0], v, true)) { if (!AdjustInitializerStack(initializerStack, nextExpr.Arguments[0], v, true, isValueType)) {
CleanupInitializerStackAfterFailedAdjustment(initializerStack); CleanupInitializerStackAfterFailedAdjustment(initializerStack);
break; break;
} }
@ -351,20 +416,26 @@ namespace ICSharpCode.Decompiler.ILAst
return objectInitializer; return objectInitializer;
} }
static bool AdjustInitializerStack(List<ILExpression> initializerStack, ILExpression argument, ILVariable v, bool isCollection) static bool AdjustInitializerStack(List<ILExpression> initializerStack, ILExpression argument, ILVariable v, bool isCollection, bool isValueType)
{ {
// Argument is of the form 'getter(getter(...(v)))' // Argument is of the form 'getter(getter(...(v)))'
// Unpack it into a list of getters: // Unpack it into a list of getters:
List<ILExpression> getters = new List<ILExpression>(); List<ILExpression> getters = new List<ILExpression>();
while (argument.Code == ILCode.CallvirtGetter || argument.Code == ILCode.Ldfld) { while (argument.Code == ILCode.CallvirtGetter || argument.Code == ILCode.CallGetter || argument.Code == ILCode.Ldfld) {
getters.Add(argument); getters.Add(argument);
if (argument.Arguments.Count != 1) if (argument.Arguments.Count != 1)
return false; return false;
argument = argument.Arguments[0]; argument = argument.Arguments[0];
} }
// Ensure that the final argument is 'v' // Ensure that the final argument is 'v'
if (!argument.MatchLdloc(v)) if (isValueType) {
return false; ILVariable loadedVar;
if (!(argument.Match(ILCode.Ldloca, out loadedVar) && loadedVar == v))
return false;
} else {
if (!argument.MatchLdloc(v))
return false;
}
// Now compare the getters with those that are currently active on the initializer stack: // Now compare the getters with those that are currently active on the initializer stack:
int i; int i;
for (i = 1; i <= Math.Min(getters.Count, initializerStack.Count - 1); i++) { for (i = 1; i <= Math.Min(getters.Count, initializerStack.Count - 1); i++) {

35
ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs

@ -868,5 +868,40 @@ namespace ICSharpCode.Decompiler.ILAst
return false; return false;
} }
#endregion #endregion
#region SimplifyShiftOperators
static bool SimplifyShiftOperators(List<ILNode> body, ILExpression expr, int pos)
{
// C# compiles "a << b" to "a << (b & 31)", so we will remove the "& 31" if possible.
bool modified = false;
SimplifyShiftOperators(expr, ref modified);
return modified;
}
static void SimplifyShiftOperators(ILExpression expr, ref bool modified)
{
for (int i = 0; i < expr.Arguments.Count; i++)
SimplifyShiftOperators(expr.Arguments[i], ref modified);
if (expr.Code != ILCode.Shl && expr.Code != ILCode.Shr && expr.Code != ILCode.Shr_Un)
return;
var a = expr.Arguments[1];
if (a.Code != ILCode.And || a.Arguments[1].Code != ILCode.Ldc_I4 || expr.InferredType == null)
return;
int mask;
switch (expr.InferredType.MetadataType) {
case MetadataType.Int32:
case MetadataType.UInt32: mask = 31; break;
case MetadataType.Int64:
case MetadataType.UInt64: mask = 63; break;
default: return;
}
if ((int)a.Arguments[1].Operand != mask) return;
var res = a.Arguments[0];
res.ILRanges.AddRange(a.ILRanges);
res.ILRanges.AddRange(a.Arguments[1].ILRanges);
expr.Arguments[1] = res;
modified = true;
}
#endregion
} }
} }

133
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -323,13 +323,7 @@ namespace ICSharpCode.Decompiler.ILAst
if (forceInferChildren) { if (forceInferChildren) {
for (int i = 0; i < expr.Arguments.Count; i++) { for (int i = 0; i < expr.Arguments.Count; i++) {
if (i == 0 && method.HasThis) { if (i == 0 && method.HasThis) {
ILExpressionPrefix constraint = expr.GetPrefix(ILCode.Constrained); InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(method.DeclaringType, expr.GetPrefix(ILCode.Constrained)));
if (constraint != null)
InferTypeForExpression(expr.Arguments[i], new ByReferenceType((TypeReference)constraint.Operand));
else if (method.DeclaringType.IsValueType)
InferTypeForExpression(expr.Arguments[i], new ByReferenceType(method.DeclaringType));
else
InferTypeForExpression(expr.Arguments[i], method.DeclaringType);
} else { } else {
InferTypeForExpression(expr.Arguments[i], SubstituteTypeArgs(method.Parameters[method.HasThis ? i - 1 : i].ParameterType, method)); InferTypeForExpression(expr.Arguments[i], SubstituteTypeArgs(method.Parameters[method.HasThis ? i - 1 : i].ParameterType, method));
} }
@ -361,17 +355,22 @@ namespace ICSharpCode.Decompiler.ILAst
#endregion #endregion
#region Load/Store Fields #region Load/Store Fields
case ILCode.Ldfld: case ILCode.Ldfld:
if (forceInferChildren) if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], ((FieldReference)expr.Operand).DeclaringType); InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(((FieldReference)expr.Operand).DeclaringType, expr.GetPrefix(ILCode.Constrained)));
}
return GetFieldType((FieldReference)expr.Operand); return GetFieldType((FieldReference)expr.Operand);
case ILCode.Ldsfld: case ILCode.Ldsfld:
return GetFieldType((FieldReference)expr.Operand); return GetFieldType((FieldReference)expr.Operand);
case ILCode.Ldflda: case ILCode.Ldflda:
if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(((FieldReference)expr.Operand).DeclaringType, expr.GetPrefix(ILCode.Constrained)));
}
return new ByReferenceType(GetFieldType((FieldReference)expr.Operand));
case ILCode.Ldsflda: case ILCode.Ldsflda:
return new ByReferenceType(GetFieldType((FieldReference)expr.Operand)); return new ByReferenceType(GetFieldType((FieldReference)expr.Operand));
case ILCode.Stfld: case ILCode.Stfld:
if (forceInferChildren) { if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], ((FieldReference)expr.Operand).DeclaringType); InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(((FieldReference)expr.Operand).DeclaringType, expr.GetPrefix(ILCode.Constrained)));
InferTypeForExpression(expr.Arguments[1], GetFieldType((FieldReference)expr.Operand)); InferTypeForExpression(expr.Arguments[1], GetFieldType((FieldReference)expr.Operand));
} }
return GetFieldType((FieldReference)expr.Operand); return GetFieldType((FieldReference)expr.Operand);
@ -515,14 +514,47 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Rem_Un: case ILCode.Rem_Un:
return InferArgumentsInBinaryOperator(expr, false, expectedType); return InferArgumentsInBinaryOperator(expr, false, expectedType);
case ILCode.Shl: case ILCode.Shl:
case ILCode.Shr:
if (forceInferChildren) if (forceInferChildren)
InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
return InferTypeForExpression(expr.Arguments[0], typeSystem.Int32); if (expectedType != null && (
expectedType.MetadataType == MetadataType.Int32 || expectedType.MetadataType == MetadataType.UInt32 ||
expectedType.MetadataType == MetadataType.Int64 || expectedType.MetadataType == MetadataType.UInt64)
)
return NumericPromotion(InferTypeForExpression(expr.Arguments[0], expectedType));
else
return NumericPromotion(InferTypeForExpression(expr.Arguments[0], null));
case ILCode.Shr:
case ILCode.Shr_Un: case ILCode.Shr_Un:
if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); if (forceInferChildren)
return InferTypeForExpression(expr.Arguments[0], typeSystem.UInt32); InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
TypeReference type = NumericPromotion(InferTypeForExpression(expr.Arguments[0], null));
TypeReference expectedInputType = null;
switch (type.MetadataType) {
case MetadataType.Int32:
if (expr.Code == ILCode.Shr_Un)
expectedInputType = typeSystem.UInt32;
break;
case MetadataType.UInt32:
if (expr.Code == ILCode.Shr)
expectedInputType = typeSystem.Int32;
break;
case MetadataType.Int64:
if (expr.Code == ILCode.Shr_Un)
expectedInputType = typeSystem.UInt64;
break;
case MetadataType.UInt64:
if (expr.Code == ILCode.Shr)
expectedInputType = typeSystem.UInt64;
break;
}
if (expectedInputType != null) {
InferTypeForExpression(expr.Arguments[0], expectedInputType);
return expectedInputType;
} else {
return type;
}
}
case ILCode.CompoundAssignment: case ILCode.CompoundAssignment:
{ {
TypeReference varType = InferTypeForExpression(expr.Arguments[0].Arguments[0], null); TypeReference varType = InferTypeForExpression(expr.Arguments[0].Arguments[0], null);
@ -543,9 +575,19 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Ldc_I4: case ILCode.Ldc_I4:
if (IsBoolean(expectedType) && ((int)expr.Operand == 0 || (int)expr.Operand == 1)) if (IsBoolean(expectedType) && ((int)expr.Operand == 0 || (int)expr.Operand == 1))
return typeSystem.Boolean; return typeSystem.Boolean;
return (IsIntegerOrEnum(expectedType) || expectedType is PointerType) ? expectedType : typeSystem.Int32; if (expectedType is PointerType && (int)expr.Operand == 0)
return expectedType;
if (IsIntegerOrEnum(expectedType) && OperandFitsInType(expectedType, (int)expr.Operand))
return expectedType;
else
return typeSystem.Int32;
case ILCode.Ldc_I8: case ILCode.Ldc_I8:
return (IsIntegerOrEnum(expectedType) || expectedType is PointerType) ? expectedType : typeSystem.Int64; if (expectedType is PointerType && (long)expr.Operand == 0)
return expectedType;
if (IsIntegerOrEnum(expectedType) && GetInformationAmount(expectedType) >= NativeInt)
return expectedType;
else
return typeSystem.Int64;
case ILCode.Ldc_R4: case ILCode.Ldc_R4:
return typeSystem.Single; return typeSystem.Single;
case ILCode.Ldc_R8: case ILCode.Ldc_R8:
@ -753,6 +795,41 @@ namespace ICSharpCode.Decompiler.ILAst
} }
} }
/// <summary>
/// Wraps 'type' in a ByReferenceType if it is a value type. If a constrained prefix is specified,
/// returns the constrained type wrapped in a ByReferenceType.
/// </summary>
TypeReference MakeRefIfValueType(TypeReference type, ILExpressionPrefix constrainedPrefix)
{
if (constrainedPrefix != null)
return new ByReferenceType((TypeReference)constrainedPrefix.Operand);
if (type.IsValueType)
return new ByReferenceType(type);
else
return type;
}
/// <summary>
/// Promotes primitive types smaller than int32 to int32.
/// </summary>
/// <remarks>
/// Always promotes to signed int32.
/// </remarks>
TypeReference NumericPromotion(TypeReference type)
{
if (type == null)
return null;
switch (type.MetadataType) {
case MetadataType.SByte:
case MetadataType.Int16:
case MetadataType.Byte:
case MetadataType.UInt16:
return typeSystem.Int32;
default:
return type;
}
}
TypeReference HandleConversion(int targetBitSize, bool targetSigned, ILExpression arg, TypeReference expectedType, TypeReference targetType) TypeReference HandleConversion(int targetBitSize, bool targetSigned, ILExpression arg, TypeReference expectedType, TypeReference targetType)
{ {
if (targetBitSize >= NativeInt && expectedType is PointerType) { if (targetBitSize >= NativeInt && expectedType is PointerType) {
@ -1043,6 +1120,28 @@ namespace ICSharpCode.Decompiler.ILAst
} }
} }
static bool OperandFitsInType(TypeReference type, int num)
{
TypeDefinition typeDef = type.Resolve() as TypeDefinition;
if (typeDef != null && typeDef.IsEnum) {
type = typeDef.Fields.Single(f => f.IsRuntimeSpecialName && !f.IsStatic).FieldType;
}
switch (type.MetadataType) {
case MetadataType.SByte:
return sbyte.MinValue <= num && num <= sbyte.MaxValue;
case MetadataType.Int16:
return short.MinValue <= num && num <= short.MaxValue;
case MetadataType.Byte:
return byte.MinValue <= num && num <= byte.MaxValue;
case MetadataType.Char:
return char.MinValue <= num && num <= char.MaxValue;
case MetadataType.UInt16:
return ushort.MinValue <= num && num <= ushort.MaxValue;
default:
return true;
}
}
static bool IsArrayPointerOrReference(TypeReference type) static bool IsArrayPointerOrReference(TypeReference type)
{ {
TypeSpecification typeSpec = type as TypeSpecification; TypeSpecification typeSpec = type as TypeSpecification;

1
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -63,6 +63,7 @@
<Compile Include="PInvoke.cs" /> <Compile Include="PInvoke.cs" />
<Compile Include="QueryExpressions.cs" /> <Compile Include="QueryExpressions.cs" />
<Compile Include="Switch.cs" /> <Compile Include="Switch.cs" />
<Compile Include="TypeAnalysisTests.cs" />
<Compile Include="UndocumentedExpressions.cs" /> <Compile Include="UndocumentedExpressions.cs" />
<Compile Include="UnsafeCode.cs" /> <Compile Include="UnsafeCode.cs" />
<Compile Include="Types\S_TypeDeclarations.cs" /> <Compile Include="Types\S_TypeDeclarations.cs" />

79
ICSharpCode.Decompiler/Tests/InitializerTests.cs

@ -52,8 +52,37 @@ public class InitializerTests
get; get;
set; set;
} }
public InitializerTests.StructData NestedStruct
{
get;
set;
}
} }
private struct StructData
{
public int Field;
public int Property
{
get;
set;
}
public InitializerTests.Data MoreData
{
get;
set;
}
public StructData(int initialValue)
{
this = default(InitializerTests.StructData);
this.Field = initialValue;
this.Property = initialValue;
}
}
// Helper methods used to ensure initializers used within expressions work correctly // Helper methods used to ensure initializers used within expressions work correctly
private static void X(object a, object b) private static void X(object a, object b)
{ {
@ -456,7 +485,53 @@ public class InitializerTests
} }
}); });
} }
public static void StructInitializer_DefaultConstructor()
{
InitializerTests.X(InitializerTests.Y(), new InitializerTests.StructData
{
Field = 1,
Property = 2
});
}
public static void StructInitializer_ExplicitConstructor()
{
InitializerTests.X(InitializerTests.Y(), new InitializerTests.StructData(0)
{
Field = 1,
Property = 2
});
}
public static void StructInitializerWithInitializationOfNestedObjects()
{
InitializerTests.X(InitializerTests.Y(), new InitializerTests.StructData
{
MoreData =
{
a = InitializerTests.MyEnum.a,
FieldList =
{
InitializerTests.MyEnum2.c,
InitializerTests.MyEnum2.d
}
}
});
}
public static void StructInitializerWithinObjectInitializer()
{
InitializerTests.X(InitializerTests.Y(), new InitializerTests.Data
{
NestedStruct = new InitializerTests.StructData(2)
{
Field = 1,
Property = 2
}
});
}
public void MultidimensionalInit() public void MultidimensionalInit()
{ {
int[,] expr_09 = new int[, ] int[,] expr_09 = new int[, ]

6
ICSharpCode.Decompiler/Tests/TestRunner.cs

@ -142,6 +142,12 @@ namespace ICSharpCode.Decompiler.Tests
TestFile(@"..\..\Tests\YieldReturn.cs"); TestFile(@"..\..\Tests\YieldReturn.cs");
} }
[Test]
public void TypeAnalysis()
{
TestFile(@"..\..\Tests\TypeAnalysisTests.cs");
}
static void TestFile(string fileName) static void TestFile(string fileName)
{ {
string code = File.ReadAllText(fileName); string code = File.ReadAllText(fileName);

109
ICSharpCode.Decompiler/Tests/TypeAnalysisTests.cs

@ -0,0 +1,109 @@
// Copyright (c) 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.
using System;
public class TypeAnalysisTests
{
public byte SubtractFrom256(byte b)
{
return (byte)(256 - (int)b);
}
#region Shift
public int LShiftInteger(int num1, int num2)
{
return num1 << num2;
}
public uint LShiftUnsignedInteger(uint num1, uint num2)
{
return num1 << (int)num2;
}
public long LShiftLong(long num1, long num2)
{
return num1 << (int)num2;
}
public ulong LShiftUnsignedLong(ulong num1, ulong num2)
{
return num1 << (int)num2;
}
public int RShiftInteger(int num1, int num2)
{
return num1 >> num2;
}
public uint RShiftUnsignedInteger(uint num1, int num2)
{
return num1 >> num2;
}
public long RShiftLong(long num1, long num2)
{
return num1 >> (int)num2;
}
public ulong RShiftUnsignedLong(ulong num1, ulong num2)
{
return num1 >> (int)num2;
}
public int ShiftByte(byte num)
{
return (int)num << 8;
}
public int RShiftByte(byte num)
{
return num >> 8;
}
public uint RShiftByteWithZeroExtension(byte num)
{
return (uint)num >> 8;
}
public int RShiftByteAsSByte(byte num)
{
return (sbyte)num >> 8;
}
public int RShiftSByte(sbyte num)
{
return num >> 8;
}
public uint RShiftSByteWithZeroExtension(sbyte num)
{
return (uint)num >> 8;
}
public int RShiftSByteAsByte(sbyte num)
{
return (byte)num >> 8;
}
#endregion
public int GetHashCode(long num)
{
return (int)num ^ (int)(num >> 32);
}
}

3
ILSpy.BamlDecompiler/CecilDependencyPropertyDescriptor.cs

@ -2,6 +2,7 @@
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt) // This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System; using System;
using System.Diagnostics;
using System.Linq; using System.Linq;
using ICSharpCode.ILSpy; using ICSharpCode.ILSpy;
using Mono.Cecil; using Mono.Cecil;
@ -16,6 +17,8 @@ namespace ILSpy.BamlDecompiler
public CecilDependencyPropertyDescriptor(string member, TypeDefinition type) public CecilDependencyPropertyDescriptor(string member, TypeDefinition type)
{ {
if (type == null)
throw new ArgumentNullException("type");
this.member = member; this.member = member;
this.type = type; this.type = type;
} }

2
ILSpy.BamlDecompiler/CecilType.cs

@ -15,6 +15,8 @@ namespace ILSpy.BamlDecompiler
public CecilType(TypeDefinition type) public CecilType(TypeDefinition type)
{ {
if (type == null)
throw new ArgumentNullException("type");
this.type = type; this.type = type;
} }

2
ILSpy.BamlDecompiler/CecilTypeResolver.cs

@ -52,7 +52,7 @@ namespace ILSpy.BamlDecompiler
var otherAssembly = resolver.Resolve(assemblyName); var otherAssembly = resolver.Resolve(assemblyName);
if (otherAssembly == null) if (otherAssembly == null)
throw new Exception("could not resolve '" + assemblyName + "'!"); throw new Exception("could not resolve '" + assemblyName + "'!");
type = otherAssembly.MainModule.GetType(fullName); type = otherAssembly.MainModule.GetType(fullName.Replace('+', '/'));
} }
return new CecilType(type); return new CecilType(type);

8
ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj

@ -80,23 +80,17 @@
<Compile Include="ConnectMethodDecompiler.cs" /> <Compile Include="ConnectMethodDecompiler.cs" />
<Compile Include="Extensions.cs" /> <Compile Include="Extensions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\AppDomainTypeResolver.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\BamlAssembly.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\BamlBinaryReader.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\BamlBinaryReader.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\BamlFile.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\BamlRecordType.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\BamlRecordType.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\DotNetType.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\IDependencyPropertyDescriptor.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\IDependencyPropertyDescriptor.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\IType.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\IType.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\ITypeResolver.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\ITypeResolver.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\KeyMapping.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\KeyMapping.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\KnownInfo.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\KnownInfo.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\NodesCollection.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\PropertyDeclaration.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\PropertyDeclaration.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\ResourceName.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\ResourceName.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\TypeDeclaration.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\TypeDeclaration.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\WpfDependencyPropertyDescriptor.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\XmlBamlElement.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\XmlBamlElement.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\XmlBamlNode.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\XmlBamlNode.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\XmlBamlProperty.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\XmlBamlProperty.cs" />

183
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/AppDomainTypeResolver.cs

@ -1,183 +0,0 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Text;
using System.IO;
using System.Linq;
using Microsoft.Win32;
using System.Threading;
using System.Security.Permissions;
using System.Security;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
public delegate void AssemblyResolveEventHandler(object s, AssemblyResolveEventArgs e);
public class AppDomainTypeResolver : MarshalByRefObject, ITypeResolver
{
private readonly AppDomain _domain;
private string baseDir;
public event AssemblyResolveEventHandler AssemblyResolve;
public static AppDomainTypeResolver GetIntoNewAppDomain(string baseDir)
{
AppDomainSetup info = new AppDomainSetup();
info.ApplicationBase = Environment.CurrentDirectory;
AppDomain domain = AppDomain.CreateDomain("AppDomainTypeResolver", null, info, new PermissionSet(PermissionState.Unrestricted));
AppDomainTypeResolver resolver = (AppDomainTypeResolver)domain.CreateInstanceAndUnwrap(typeof(AppDomainTypeResolver).Assembly.FullName,
typeof(AppDomainTypeResolver).FullName, false, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.CreateInstance, null, new object[] { domain, baseDir }, null, null, null);
return resolver;
}
Assembly domain_AssemblyResolve(object sender, ResolveEventArgs args)
{
// Cerco di risolvere automaticamente
AssemblyName name = new AssemblyName(args.Name);
string fileName = Path.Combine(this.baseDir, name.Name + ".exe");
if (!File.Exists(fileName))
fileName = Path.Combine(this.baseDir, name.Name + ".dll");
// Carico il percorso autocalcolato
if (File.Exists(fileName))
return Assembly.LoadFile(fileName);
if (AssemblyResolve != null)
{
AssemblyResolveEventArgs e = new AssemblyResolveEventArgs(args.Name, this.baseDir);
AssemblyResolve(this, e);
if (!String.IsNullOrEmpty(e.Location) && File.Exists(e.Location))
return Assembly.LoadFile(e.Location);
}
return null;
}
public static void DestroyResolver(AppDomainTypeResolver resolver)
{
if (resolver == null) throw new ArgumentNullException("resolver");
ThreadPool.QueueUserWorkItem(delegate
{
AppDomain.Unload(resolver.Domain);
});
}
protected AppDomainTypeResolver(AppDomain domain, string baseDir)
{
_domain = domain;
this.baseDir = baseDir;
domain.AssemblyResolve += new ResolveEventHandler(domain_AssemblyResolve);
}
public BamlAssembly LoadAssembly(AssemblyName asm)
{
//return new BamlAssembly(Assembly.Load(asm));
return new BamlAssembly(_domain.Load(asm));
}
public BamlAssembly LoadAssembly(string location)
{
Assembly asm = Assembly.LoadFile(location);
return new BamlAssembly(asm);
//return _domain.Load(System.IO.File.ReadAllBytes(location));
//return Assembly.LoadFrom(location);
}
public BamlAssembly[] GetReferencedAssemblies(BamlAssembly asm)
{
AssemblyName[] list = asm.Assembly.GetReferencedAssemblies();
return (from an in list
select this.LoadAssembly(an)).ToArray();
}
public AppDomain Domain
{
get { return _domain; }
}
#region ITypeResolver Members
public IType GetTypeByAssemblyQualifiedName(string name)
{
return new DotNetType(name);
}
public IDependencyPropertyDescriptor GetDependencyPropertyDescriptor(string name, IType ownerType, IType targetType)
{
if (name == null) throw new ArgumentNullException("name");
if (ownerType == null) throw new ArgumentNullException("ownerType");
if (targetType == null) throw new ArgumentNullException("targetType");
Type dOwnerType = ((DotNetType)ownerType).Type;
Type dTargetType = ((DotNetType)targetType).Type;
try
{
DependencyPropertyDescriptor propertyDescriptor = DependencyPropertyDescriptor.FromName(name, dOwnerType, dTargetType);
if (propertyDescriptor != null)
return new WpfDependencyPropertyDescriptor(propertyDescriptor);
return null;
}
catch (Exception)
{
return null;
}
}
public bool IsLocalAssembly(string name)
{
return false;
}
public string RuntimeVersion {
get {
throw new NotImplementedException();
}
}
#endregion
public override object InitializeLifetimeService()
{
return null;
}
}
public class AssemblyResolveEventArgs : MarshalByRefObject
{
private string _location;
private string _name;
private string _baseDir;
public AssemblyResolveEventArgs(string name, string baseDir)
{
_name = name;
_baseDir = baseDir;
}
public string Location
{
get { return _location; }
set { _location = value; }
}
public string Name
{
get { return _name; }
}
public string BaseDir
{
get { return _baseDir; }
}
}
}

112
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlAssembly.cs

@ -1,112 +0,0 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Reflection;
using System.Resources;
using System.Text;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
public class BamlAssembly : MarshalByRefObject
{
private readonly string _filePath;
private Assembly _assembly;
private BamlFileList _bamlFile;
public BamlAssembly(Assembly assembly)
{
_assembly = assembly;
_filePath = assembly.CodeBase;
ReadBaml();
}
public BamlAssembly(string filePath)
{
this._filePath = Path.GetFullPath(filePath);
this._assembly = Assembly.LoadFile(this.FilePath);
if (String.Compare(this.Assembly.CodeBase, this.FilePath, true) != 0)
throw new ArgumentException("Cannot load filePath because Assembly is already loaded", "filePath");
ReadBaml();
}
private void ReadBaml()
{
// Get available names
string[] resources = this.Assembly.GetManifestResourceNames();
foreach (string res in resources)
{
// Solo le risorse
if (String.Compare(Path.GetExtension(res), ".resources", true) != 0) continue;
// Get stream
using (Stream stream = this.Assembly.GetManifestResourceStream(res))
{
try
{
ResourceReader reader = new ResourceReader(stream);
foreach (DictionaryEntry entry in reader)
{
if (String.Compare(Path.GetExtension(entry.Key.ToString()), ".baml", true) == 0 && entry.Value is Stream)
{
BamlFile bm = new BamlFile(GetAssemblyResourceUri(entry.Key.ToString()), (Stream)entry.Value);
this.BamlFiles.Add(bm);
}
}
}
catch (ArgumentException)
{}
}
}
}
private Uri GetAssemblyResourceUri(string resourceName)
{
AssemblyName asm = this.Assembly.GetName();
byte[] data = asm.GetPublicKeyToken();
StringBuilder token = new StringBuilder(data.Length * 2);
for (int x = 0; x < data.Length; x++)
{
token.Append(data[x].ToString("x", System.Globalization.CultureInfo.InvariantCulture));
}
return new Uri(String.Format(@"{0};V{1};{2};component\{3}", asm.Name, asm.Version, token, Path.ChangeExtension(resourceName, ".xaml")), UriKind.RelativeOrAbsolute);
}
public string FilePath
{
get { return _filePath; }
}
public Assembly Assembly
{
get { return _assembly; }
}
public BamlFileList BamlFiles
{
get
{
if (_bamlFile == null)
_bamlFile = new BamlFileList();
return _bamlFile;
}
}
public override object InitializeLifetimeService()
{
return null;
}
}
[Serializable()]
public class BamlFileList : Collection<BamlFile>
{}
}

80
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlFile.cs

@ -1,80 +0,0 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Resources;
using System.Text;
using System.Windows;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
/// <summary>
/// Rappresenta un singole file Baml all'interno di un assembly
/// </summary>
public class BamlFile : Component
{
private Uri _uri;
private readonly Stream _stream;
public BamlFile(Uri uri, Stream stream)
{
if (uri == null)
new ArgumentNullException("uri");
if (stream == null)
throw new ArgumentNullException("stream");
_uri = uri;
_stream = stream;
}
/// <summary>
/// Carica il Baml attraverso il motore di WPF con Application.LoadComponent
/// </summary>
/// <returns></returns>
public object LoadContent()
{
try
{
return Application.LoadComponent(this.Uri);
}
catch (Exception e)
{
throw new InvalidOperationException("Invalid baml file.", e);
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
this.Stream.Dispose();
}
public override object InitializeLifetimeService()
{
return null;
}
/// <summary>
/// Restituisce lo stream originale contenente il Baml
/// </summary>
public Stream Stream
{
get { return _stream; }
}
/// <summary>
/// Restituisce l'indirizzo secondo lo schema pack://
/// </summary>
public Uri Uri
{
get { return _uri; }
}
}
}

64
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/DotNetType.cs

@ -1,64 +0,0 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections.Generic;
using System.Text;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
public class DotNetType : MarshalByRefObject, IType
{
private readonly string _assemblyQualifiedName;
private Type _type;
public DotNetType(string assemblyQualifiedName)
{
if (assemblyQualifiedName == null) throw new ArgumentNullException("assemblyQualifiedName");
_assemblyQualifiedName = assemblyQualifiedName;
_type = Type.GetType(assemblyQualifiedName, false, true);
}
#region IType Members
public string AssemblyQualifiedName
{
get { return _assemblyQualifiedName; }
}
public bool IsSubclassOf(IType type)
{
if (type == null) throw new ArgumentNullException("type");
if (!(type is DotNetType)) throw new ArgumentException("type");
if (_type == null) return false;
return this._type.IsSubclassOf(((DotNetType)type).Type);
}
public bool Equals(IType type)
{
if (type == null) throw new ArgumentNullException("type");
if (!(type is DotNetType)) throw new ArgumentException("type");
if (_type == null) return false;
return this._type.Equals(((DotNetType)type).Type);
}
public IType BaseType {
get {
return new DotNetType(this._type.BaseType.AssemblyQualifiedName);
}
}
#endregion
public Type Type
{
get { return _type; }
}
public override object InitializeLifetimeService()
{
return null;
}
}
}

6
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/KeyMapping.cs

@ -36,5 +36,11 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
this.staticResources = new List<object>(); this.staticResources = new List<object>();
this.Position = -1; this.Position = -1;
} }
public override string ToString()
{
return '"' + KeyString + '"';
}
} }
} }

4
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/KnownInfo.cs

@ -58,7 +58,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
KnownTypeTable[9] = new TypeDeclaration(resolver, "Animatable", "System.Windows.Media.Animaton", 1); KnownTypeTable[9] = new TypeDeclaration(resolver, "Animatable", "System.Windows.Media.Animaton", 1);
KnownTypeTable[10] = new TypeDeclaration(resolver, "AnimationClock", "System.Windows.Media.Animation", 1); KnownTypeTable[10] = new TypeDeclaration(resolver, "AnimationClock", "System.Windows.Media.Animation", 1);
KnownTypeTable[11] = new TypeDeclaration(resolver, "AnimationTimeline", "System.Windows.Media.Animation", 1); KnownTypeTable[11] = new TypeDeclaration(resolver, "AnimationTimeline", "System.Windows.Media.Animation", 1);
KnownTypeTable[12] = new TypeDeclaration(resolver, "Application", "System.Net.Mime", 3); KnownTypeTable[12] = new TypeDeclaration(resolver, "Application", "System.Windows", 0);
KnownTypeTable[13] = new TypeDeclaration(resolver, "ArcSegment", "System.Windows.Media", 1); KnownTypeTable[13] = new TypeDeclaration(resolver, "ArcSegment", "System.Windows.Media", 1);
KnownTypeTable[14] = new TypeDeclaration(resolver, "ArrayExtension", "System.Windows.Markup", 0); KnownTypeTable[14] = new TypeDeclaration(resolver, "ArrayExtension", "System.Windows.Markup", 0);
KnownTypeTable[15] = new TypeDeclaration(resolver, "AxisAngleRotation3D", "System.Windows.Media.Media3D", 1); KnownTypeTable[15] = new TypeDeclaration(resolver, "AxisAngleRotation3D", "System.Windows.Media.Media3D", 1);
@ -127,7 +127,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
KnownTypeTable[0x4e] = new TypeDeclaration(resolver, "CollectionContainer", "System.Windows.Data", 0); KnownTypeTable[0x4e] = new TypeDeclaration(resolver, "CollectionContainer", "System.Windows.Data", 0);
KnownTypeTable[0x4f] = new TypeDeclaration(resolver, "CollectionView", "System.Windows.Data", 0); KnownTypeTable[0x4f] = new TypeDeclaration(resolver, "CollectionView", "System.Windows.Data", 0);
KnownTypeTable[80] = new TypeDeclaration(resolver, "CollectionViewSource", "System.Windows.Data", 0); KnownTypeTable[80] = new TypeDeclaration(resolver, "CollectionViewSource", "System.Windows.Data", 0);
KnownTypeTable[0x51] = new TypeDeclaration(resolver, "Color", "Microsoft.Win32", 2); KnownTypeTable[0x51] = new TypeDeclaration(resolver, "Color", "Win32Native", "Microsoft.Win32", 2);
KnownTypeTable[0x52] = new TypeDeclaration(resolver, "ColorAnimation", "System.Windows.Media.Animation", 1); KnownTypeTable[0x52] = new TypeDeclaration(resolver, "ColorAnimation", "System.Windows.Media.Animation", 1);
KnownTypeTable[0x53] = new TypeDeclaration(resolver, "ColorAnimationBase", "System.Windows.Media.Animation", 1); KnownTypeTable[0x53] = new TypeDeclaration(resolver, "ColorAnimationBase", "System.Windows.Media.Animation", 1);
KnownTypeTable[0x54] = new TypeDeclaration(resolver, "ColorAnimationUsingKeyFrames", "System.Windows.Media.Animation", 1); KnownTypeTable[0x54] = new TypeDeclaration(resolver, "ColorAnimationUsingKeyFrames", "System.Windows.Media.Animation", 1);

68
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/NodesCollection.cs

@ -0,0 +1,68 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Windows.Media;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
class NodesCollection : List<XmlBamlNode>
{
public XmlBamlNode Last
{
get
{
if (this.Count > 0)
{
int i = this.Count - 1;
return this[i];
}
return null;
}
}
public void RemoveLast()
{
if (this.Count > 0)
this.Remove(this.Last);
}
public XmlBamlNode Dequeue()
{
return DequeueInternal(true);
}
public XmlBamlNode Peek()
{
return DequeueInternal(false);
}
XmlBamlNode DequeueInternal(bool remove)
{
if (this.Count > 0)
{
XmlBamlNode node = this[0];
if (remove)
this.RemoveAt(0);
return node;
}
else
return null;
}
public void Enqueue(XmlBamlNode node)
{
this.Add(node);
}
}
}

80
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs

@ -8,11 +8,6 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
internal class TypeDeclaration internal class TypeDeclaration
{ {
private readonly XmlBamlReader reader; private readonly XmlBamlReader reader;
private readonly short _assemblyId;
private readonly bool _isKnown;
private readonly string _name;
private readonly string _namespaceName;
private readonly bool _isExtension; private readonly bool _isExtension;
private IType _type; private IType _type;
private bool _typeLoaded; private bool _typeLoaded;
@ -21,7 +16,12 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
public TypeDeclaration(ITypeResolver resolver, string name, string namespaceName, short assemblyId) public TypeDeclaration(ITypeResolver resolver, string name, string namespaceName, short assemblyId)
: this(null, resolver, name, namespaceName, assemblyId, true) : this(null, resolver, name, namespaceName, assemblyId, true)
{ {
}
public TypeDeclaration(ITypeResolver resolver, string name, string enclosingTypeName, string namespaceName, short assemblyId)
: this(null, resolver, name, namespaceName, assemblyId, true)
{
this.EnclosingTypeName = enclosingTypeName;
} }
public TypeDeclaration(ITypeResolver resolver, string name, string namespaceName, short assemblyId, bool isExtension) public TypeDeclaration(ITypeResolver resolver, string name, string namespaceName, short assemblyId, bool isExtension)
@ -39,10 +39,10 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
{ {
this.reader = reader; this.reader = reader;
this.resolver = resolver; this.resolver = resolver;
this._name = name; this.Name = name;
this._namespaceName = namespaceName; this.Namespace = namespaceName;
this._assemblyId = assemblyId; this.AssemblyId = assemblyId;
this._isKnown = isKnown; this.IsKnown = isKnown;
if (!_isExtension) if (!_isExtension)
_isExtension = name.EndsWith("Extension"); _isExtension = name.EndsWith("Extension");
@ -50,8 +50,10 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
public override string ToString() public override string ToString()
{ {
return this._name; return this.Name;
} }
public string EnclosingTypeName { get; private set; }
public bool IsExtension public bool IsExtension
{ {
@ -60,8 +62,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
public string Assembly public string Assembly
{ {
get get {
{
if (reader != null) if (reader != null)
return this.reader.GetAssembly(this.AssemblyId); return this.reader.GetAssembly(this.AssemblyId);
else else
@ -69,46 +70,19 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
} }
} }
public short AssemblyId public short AssemblyId { get; private set; }
{
get { return _assemblyId; }
}
public string Name public string Name { get; private set; }
{
get
{
return this._name;
}
}
public bool IsKnown public bool IsKnown { get; private set; }
{
get { return _isKnown; }
}
//public Type DotNetType public IType Type {
//{
// get
// {
// if (!_typeLoaded)
// {
// _type = Type.GetType(String.Format("{0}.{1}, {2}", this.Namespace, this.Name, this.Assembly), false, true);
// _typeLoaded = true;
// }
// return _type;
// }
//}
public IType Type
{
get get
{ {
if (!_typeLoaded) if (!_typeLoaded)
{ {
if (this.Name.Length > 0) if (this.Name.Length > 0)
_type = resolver.GetTypeByAssemblyQualifiedName(String.Format("{0}.{1}, {2}", this.Namespace, this.Name, this.Assembly)); _type = resolver.GetTypeByAssemblyQualifiedName(AssemblyQualifiedName);
_typeLoaded = true; _typeLoaded = true;
} }
@ -116,26 +90,28 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
} }
} }
public string Namespace public string Namespace { get; private set; }
{
get public string FullyQualifiedName {
{ get { return EnclosingTypeName == null ? string.Format("{0}.{1}", Namespace, Name) : string.Format("{0}.{1}+{2}", Namespace, EnclosingTypeName, Name); }
return this._namespaceName; }
}
public string AssemblyQualifiedName {
get { return string.Format("{0}, {1}", FullyQualifiedName, Assembly); }
} }
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
TypeDeclaration td = obj as TypeDeclaration; TypeDeclaration td = obj as TypeDeclaration;
if (td != null) if (td != null)
return (this.Name == td.Name && this.Namespace == td.Namespace && this.AssemblyId == td.AssemblyId); return (this.Name == td.Name && this.EnclosingTypeName == td.EnclosingTypeName && this.Namespace == td.Namespace && this.AssemblyId == td.AssemblyId);
else else
return false; return false;
} }
public override int GetHashCode() public override int GetHashCode()
{ {
return this.AssemblyId ^ this.Name.GetHashCode() ^ this.Namespace.GetHashCode(); return this.AssemblyId ^ this.Name.GetHashCode() ^ this.EnclosingTypeName.GetHashCode() ^ this.Namespace.GetHashCode();
} }
} }

35
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/WpfDependencyPropertyDescriptor.cs

@ -1,35 +0,0 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
public class WpfDependencyPropertyDescriptor : MarshalByRefObject, IDependencyPropertyDescriptor
{
private readonly DependencyPropertyDescriptor _propertyDescriptor;
public WpfDependencyPropertyDescriptor(DependencyPropertyDescriptor propertyDescriptor)
{
if (propertyDescriptor == null) throw new ArgumentNullException("propertyDescriptor");
_propertyDescriptor = propertyDescriptor;
}
#region IDependencyPropertyDescriptor Members
public bool IsAttached
{
get { return _propertyDescriptor.IsAttached; }
}
#endregion
public override object InitializeLifetimeService()
{
return null;
}
}
}

19
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlElement.cs

@ -23,8 +23,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
this.Namespaces.AddRange(parent.Namespaces); this.Namespaces.AddRange(parent.Namespaces);
} }
public XmlNamespaceCollection Namespaces public XmlNamespaceCollection Namespaces {
{
get { return _namespaces; } get { return _namespaces; }
} }
@ -42,11 +41,11 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
public override string ToString() public override string ToString()
{ {
return String.Format("Element: {0}", TypeDeclaration.Name); return string.Format("Element: {0}", TypeDeclaration.Name);
} }
} }
internal class XmlBamlEndElement : XmlBamlElement class XmlBamlEndElement : XmlBamlElement
{ {
public XmlBamlEndElement(XmlBamlElement start) public XmlBamlEndElement(XmlBamlElement start)
{ {
@ -54,19 +53,13 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
this.Namespaces.AddRange(start.Namespaces); this.Namespaces.AddRange(start.Namespaces);
} }
public override XmlNodeType NodeType public override XmlNodeType NodeType {
{ get { return XmlNodeType.EndElement; }
get
{
return XmlNodeType.EndElement;
}
} }
public override string ToString() public override string ToString()
{ {
return String.Format("EndElement: {0}", TypeDeclaration.Name); return string.Format("EndElement: {0}", TypeDeclaration.Name);
} }
} }
} }

2
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlPropertyElement.cs

@ -41,7 +41,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
public override string ToString() public override string ToString()
{ {
return String.Format("PropertyElement: {0}.{1}", TypeDeclaration.Name, PropertyDeclaration.Name); return String.Format("PropertyElement: {0}.{1}", TypeDeclaration.Name.Replace('+', '.'), PropertyDeclaration.Name);
} }
} }
} }

210
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs

@ -41,9 +41,6 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
bool intoAttribute = false; bool intoAttribute = false;
bool initialized; bool initialized;
bool _eof; bool _eof;
bool isPartialDefKeysClosed = true;
bool isDefKeysClosed = true;
#region Context #region Context
Stack<ReaderContext> layer = new Stack<ReaderContext>(); Stack<ReaderContext> layer = new Stack<ReaderContext>();
@ -79,13 +76,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
List<KeyMapping> keys = new List<KeyMapping>(); List<KeyMapping> keys = new List<KeyMapping>();
KeyMapping LastKey { KeyMapping LastKey {
get { get { return keys.LastOrDefault(); }
KeyMapping last = keys.LastOrDefault();
if (last == null)
keys.Add(last = new KeyMapping());
return last;
}
} }
void LayerPop() void LayerPop()
@ -112,11 +103,6 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
public const string XWPFNamespace = "http://schemas.microsoft.com/winfx/2006/xaml"; public const string XWPFNamespace = "http://schemas.microsoft.com/winfx/2006/xaml";
public const string DefaultWPFNamespace = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"; public const string DefaultWPFNamespace = "http://schemas.microsoft.com/winfx/2006/xaml/presentation";
public XmlBamlReader(Stream stream) : this (stream, AppDomainTypeResolver.GetIntoNewAppDomain(Environment.CurrentDirectory))
{
}
public XmlBamlReader(Stream stream, ITypeResolver resolver) public XmlBamlReader(Stream stream, ITypeResolver resolver)
{ {
if (stream == null) if (stream == null)
@ -339,7 +325,11 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
else else
currentType = (BamlRecordType)type; currentType = (BamlRecordType)type;
if (currentType.ToString().EndsWith("End"))
Debug.Unindent();
Debug.WriteLine(string.Format("{0} (0x{0:x})", currentType)); Debug.WriteLine(string.Format("{0} (0x{0:x})", currentType));
if (currentType.ToString().EndsWith("Start"))
Debug.Indent();
} }
bool SetNextNode() bool SetNextNode()
@ -402,6 +392,8 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
break; break;
case BamlRecordType.DeferableContentStart: case BamlRecordType.DeferableContentStart:
Current.IsDeferred = true; Current.IsDeferred = true;
keys = new List<KeyMapping>();
currentKey = 0;
reader.ReadInt32(); reader.ReadInt32();
break; break;
case BamlRecordType.DefAttribute: case BamlRecordType.DefAttribute:
@ -637,9 +629,9 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
{ {
get get
{ {
if (intoAttribute) return String.Empty; if (intoAttribute) return string.Empty;
String localName = String.Empty; String localName = string.Empty;
XmlBamlNode node = this.CurrentNode; XmlBamlNode node = this.CurrentNode;
if (node is XmlBamlSimpleProperty) { if (node is XmlBamlSimpleProperty) {
@ -689,13 +681,10 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
object GetResourceName(short identifier) object GetResourceName(short identifier)
{ {
if (identifier >= 0) if (identifier >= 0) {
{
PropertyDeclaration declaration = this.propertyTable[identifier]; PropertyDeclaration declaration = this.propertyTable[identifier];
return declaration; return declaration;
} } else {
else
{
identifier = (short)-identifier; identifier = (short)-identifier;
bool isNotKey = (identifier > 0xe8); bool isNotKey = (identifier > 0xe8);
if (isNotKey) if (isNotKey)
@ -998,6 +987,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
bool sharedSet = reader.ReadBoolean(); bool sharedSet = reader.ReadBoolean();
string text = this.stringTable[stringId]; string text = this.stringTable[stringId];
Debug.Print("KeyString: " + text);
if (text == null) if (text == null)
throw new NotSupportedException(); throw new NotSupportedException();
@ -1039,6 +1029,8 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
void ReadElementEnd() void ReadElementEnd()
{ {
CloseElement(); CloseElement();
if (Current.IsDeferred)
keys = null;
LayerPop(); LayerPop();
} }
@ -1095,12 +1087,12 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
// this property could be a markup extension // this property could be a markup extension
// try to convert it // try to convert it
int start = nodes.IndexOf(propertyElement) + 1; int start = nodes.IndexOf(propertyElement) + 1;
IEnumerator enumerator = nodes.GetEnumerator(); IEnumerator<XmlBamlNode> enumerator = nodes.GetEnumerator();
// move enumerator to the start of this property value // move enumerator to the start of this property value
for (int i = 0; i < start && enumerator.MoveNext(); i++) ; for (int i = 0; i < start && enumerator.MoveNext(); i++) ;
if (IsExtension(enumerator)) { if (IsExtension(enumerator) && start < nodes.Count - 1) {
start--; start--;
nodes.RemoveAt(start); nodes.RemoveAt(start);
nodes.RemoveLast(); nodes.RemoveLast();
@ -1173,11 +1165,11 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
} }
} }
bool IsExtension(IEnumerator enumerator) bool IsExtension(IEnumerator<XmlBamlNode> enumerator)
{ {
while (enumerator.MoveNext()) { while (enumerator.MoveNext()) {
object node = enumerator.Current; var node = enumerator.Current;
if (node is XmlBamlElement && !(node is XmlBamlEndElement) && !((XmlBamlElement)node).TypeDeclaration.IsExtension) if (node.NodeType == XmlNodeType.Element && !((XmlBamlElement)node).TypeDeclaration.IsExtension)
return false; return false;
} }
@ -1231,7 +1223,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
nodes.Enqueue(element); nodes.Enqueue(element);
if (oldDeclaration != null) { if (oldDeclaration != null) {
nodes.Enqueue(new XmlBamlSimpleProperty(XWPFNamespace, "Class", string.Format("{0}.{1}", oldDeclaration.Namespace, oldDeclaration.Name))); nodes.Enqueue(new XmlBamlSimpleProperty(XWPFNamespace, "Class", oldDeclaration.FullyQualifiedName.Replace('+', '.')));
} }
if (parentElement != null && complexPropertyOpened == 0 && !Current.IsInStaticResource && Current.Previous.IsDeferred) { if (parentElement != null && complexPropertyOpened == 0 && !Current.IsInStaticResource && Current.Previous.IsDeferred) {
@ -1342,9 +1334,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
CloseElement(); CloseElement();
complexPropertyOpened--; complexPropertyOpened--;
if (complexPropertyOpened == 0) if (complexPropertyOpened == 0) {
{
int start = nodes.IndexOf(propertyElement); int start = nodes.IndexOf(propertyElement);
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@ -1409,27 +1399,26 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
void ReadOptimizedStaticResource() void ReadOptimizedStaticResource()
{ {
byte num = reader.ReadByte(); byte flags = reader.ReadByte();
short typeIdentifier = reader.ReadInt16(); short typeIdentifier = reader.ReadInt16();
bool isValueType = (num & 1) == 1; bool isValueType = (flags & 1) == 1;
bool isStaticType = (num & 2) == 2; bool isStaticType = (flags & 2) == 2;
object resource; object resource;
if (isValueType) if (isValueType)
resource = this.GetTypeExtension(typeIdentifier); resource = GetTypeExtension(typeIdentifier);
else if (isStaticType) else if (isStaticType) {
{ object name = GetResourceName(typeIdentifier);
ResourceName resourceName = (ResourceName)this.GetResourceName(typeIdentifier); if (name is ResourceName)
resource = GetStaticExtension(resourceName.Name); resource = GetStaticExtension(((ResourceName)name).Name);
} else if (name is PropertyDeclaration)
else resource = GetStaticExtension(FormatPropertyDeclaration(((PropertyDeclaration)name), true, false, false));
{ else
throw new InvalidOperationException("Invalid resource: " + name.GetType());
} else {
resource = this.stringTable[typeIdentifier]; resource = this.stringTable[typeIdentifier];
} }
//this.staticResourceTable.Add(resource);
isPartialDefKeysClosed = true;
// Aggiungo la risorsa nell'ultimo gruppo
LastKey.StaticResources.Add(resource); LastKey.StaticResources.Add(resource);
} }
@ -1474,8 +1463,6 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
return String.Format("{0}:{1}", prefix, name); return String.Format("{0}:{1}", prefix, name);
} }
string FormatPropertyDeclaration(PropertyDeclaration propertyDeclaration, bool withPrefix, bool useReading, bool checkType) string FormatPropertyDeclaration(PropertyDeclaration propertyDeclaration, bool withPrefix, bool useReading, bool checkType)
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@ -1511,11 +1498,11 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
void ReadPropertyWithStaticResourceIdentifier() void ReadPropertyWithStaticResourceIdentifier()
{ {
short identifier = reader.ReadInt16(); short propertyId = reader.ReadInt16();
short staticIdentifier = reader.ReadInt16(); short index = reader.ReadInt16();
PropertyDeclaration pd = this.GetPropertyDeclaration(identifier); PropertyDeclaration pd = this.GetPropertyDeclaration(propertyId);
object staticResource = GetStaticResource(staticIdentifier); object staticResource = GetStaticResource(index);
string prefix = this.LookupPrefix(XmlPIMapping.PresentationNamespace, false); string prefix = this.LookupPrefix(XmlPIMapping.PresentationNamespace, false);
string value = String.Format("{{{0}{1}StaticResource {2}}}", prefix, (String.IsNullOrEmpty(prefix)) ? String.Empty : ":", staticResource); string value = String.Format("{{{0}{1}StaticResource {2}}}", prefix, (String.IsNullOrEmpty(prefix)) ? String.Empty : ":", staticResource);
@ -1528,10 +1515,10 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
object GetStaticResource(short identifier) object GetStaticResource(short identifier)
{ {
if (identifier < LastKey.StaticResources.Count) if (identifier < keys[currentKey - 1].StaticResources.Count)
return LastKey.StaticResources[(int)identifier]; return keys[currentKey - 1].StaticResources[(int)identifier];
// return "???" + identifier +"???"; // return "???" + identifier + "???";
throw new ArgumentException("Cannot find StaticResource", "identifier"); throw new ArgumentException("Cannot find StaticResource", "identifier");
} }
@ -1595,11 +1582,11 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
TypeDeclaration GetKnownTypeDeclarationByName(string name) TypeDeclaration GetKnownTypeDeclarationByName(string name)
{ {
foreach (var type in KnownInfo.KnownTypeTable) { foreach (var type in KnownInfo.KnownTypeTable) {
if (name == string.Format("{0}.{1}, {2}", type.Namespace, type.Name, type.Assembly)) if (name == type.AssemblyQualifiedName)
return type; return type;
} }
throw new NotSupportedException(); throw new NotSupportedException("Type '" + name + "' not found!");
} }
internal string GetAssembly(short identifier) internal string GetAssembly(short identifier)
@ -1607,26 +1594,18 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
return this.assemblyTable[identifier]; return this.assemblyTable[identifier];
} }
XmlBamlNode CurrentNode XmlBamlNode CurrentNode {
{ get { return _currentNode; }
get
{
return _currentNode;
}
} }
///<summary> ///<summary>
///When overridden in a derived class, gets the namespace URI (as defined in the W3C Namespace specification) of the node on which the reader is positioned. ///When overridden in a derived class, gets the namespace URI (as defined in the W3C Namespace specification) of the node on which the reader is positioned.
///</summary> ///</summary>
///
///<returns> ///<returns>
///The namespace URI of the current node; otherwise an empty string. ///The namespace URI of the current node; otherwise an empty string.
///</returns> ///</returns>
/// public override string NamespaceURI {
public override string NamespaceURI get {
{
get
{
if (intoAttribute) return String.Empty; if (intoAttribute) return String.Empty;
TypeDeclaration declaration; TypeDeclaration declaration;
@ -1664,11 +1643,9 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
///<summary> ///<summary>
///When overridden in a derived class, gets the namespace prefix associated with the current node. ///When overridden in a derived class, gets the namespace prefix associated with the current node.
///</summary> ///</summary>
///
///<returns> ///<returns>
///The namespace prefix associated with the current node. ///The namespace prefix associated with the current node.
///</returns> ///</returns>
///
public override string Prefix public override string Prefix
{ {
get get
@ -1682,11 +1659,9 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
///<summary> ///<summary>
///When overridden in a derived class, gets a value indicating whether the current node can have a <see cref="P:System.Xml.XmlReader.Value"></see>. ///When overridden in a derived class, gets a value indicating whether the current node can have a <see cref="P:System.Xml.XmlReader.Value"></see>.
///</summary> ///</summary>
///
///<returns> ///<returns>
///true if the node on which the reader is currently positioned can have a Value; otherwise, false. If false, the node has a value of String.Empty. ///true if the node on which the reader is currently positioned can have a Value; otherwise, false. If false, the node has a value of String.Empty.
///</returns> ///</returns>
///
public override bool HasValue public override bool HasValue
{ {
get { return this.Value != null; } get { return this.Value != null; }
@ -1703,11 +1678,9 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
///<summary> ///<summary>
///When overridden in a derived class, gets the text value of the current node. ///When overridden in a derived class, gets the text value of the current node.
///</summary> ///</summary>
///
///<returns> ///<returns>
///The value returned depends on the <see cref="P:System.Xml.XmlReader.NodeType"></see> of the node. The following table lists node types that have a value to return. All other node types return String.Empty.Node type Value AttributeThe value of the attribute. CDATAThe content of the CDATA section. CommentThe content of the comment. DocumentTypeThe internal subset. ProcessingInstructionThe entire content, excluding the target. SignificantWhitespaceThe white space between markup in a mixed content model. TextThe content of the text node. WhitespaceThe white space between markup. XmlDeclarationThe content of the declaration. ///The value returned depends on the <see cref="P:System.Xml.XmlReader.NodeType"></see> of the node. The following table lists node types that have a value to return. All other node types return String.Empty.Node type Value AttributeThe value of the attribute. CDATAThe content of the CDATA section. CommentThe content of the comment. DocumentTypeThe internal subset. ProcessingInstructionThe entire content, excluding the target. SignificantWhitespaceThe white space between markup in a mixed content model. TextThe content of the text node. WhitespaceThe white space between markup. XmlDeclarationThe content of the declaration.
///</returns> ///</returns>
///
public override string Value public override string Value
{ {
get get
@ -1737,11 +1710,9 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
///<summary> ///<summary>
///When overridden in a derived class, gets the depth of the current node in the XML document. ///When overridden in a derived class, gets the depth of the current node in the XML document.
///</summary> ///</summary>
///
///<returns> ///<returns>
///The depth of the current node in the XML document. ///The depth of the current node in the XML document.
///</returns> ///</returns>
///
public override int Depth public override int Depth
{ {
get { return this.readingElements.Count; } get { return this.readingElements.Count; }
@ -1750,11 +1721,9 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
///<summary> ///<summary>
///When overridden in a derived class, gets the base URI of the current node. ///When overridden in a derived class, gets the base URI of the current node.
///</summary> ///</summary>
///
///<returns> ///<returns>
///The base URI of the current node. ///The base URI of the current node.
///</returns> ///</returns>
///
public override string BaseURI public override string BaseURI
{ {
get { return String.Empty; } get { return String.Empty; }
@ -1763,62 +1732,42 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
///<summary> ///<summary>
///When overridden in a derived class, gets a value indicating whether the current node is an empty element (for example, &lt;MyElement/&gt;). ///When overridden in a derived class, gets a value indicating whether the current node is an empty element (for example, &lt;MyElement/&gt;).
///</summary> ///</summary>
///
///<returns> ///<returns>
///true if the current node is an element (<see cref="P:System.Xml.XmlReader.NodeType"></see> equals XmlNodeType.Element) that ends with /&gt;; otherwise, false. ///true if the current node is an element (<see cref="P:System.Xml.XmlReader.NodeType"></see> equals XmlNodeType.Element) that ends with /&gt;; otherwise, false.
///</returns> ///</returns>
///
public override bool IsEmptyElement public override bool IsEmptyElement
{ {
get { return false; } get { return false; }
} }
//public override bool IsDefault
//{
// get
// {
// return this.NamespaceURI == null;
// }
//}
///<summary> ///<summary>
///When overridden in a derived class, gets the number of attributes on the current node. ///When overridden in a derived class, gets the number of attributes on the current node.
///</summary> ///</summary>
///
///<returns> ///<returns>
///The number of attributes on the current node. ///The number of attributes on the current node.
///</returns> ///</returns>
/// public override int AttributeCount {
public override int AttributeCount
{
get { throw new NotImplementedException(); } get { throw new NotImplementedException(); }
} }
///<summary> ///<summary>
///When overridden in a derived class, gets a value indicating whether the reader is positioned at the end of the stream. ///When overridden in a derived class, gets a value indicating whether the reader is positioned at the end of the stream.
///</summary> ///</summary>
///
///<returns> ///<returns>
///true if the reader is positioned at the end of the stream; otherwise, false. ///true if the reader is positioned at the end of the stream; otherwise, false.
///</returns> ///</returns>
/// public override bool EOF {
public override bool EOF
{
get { return _eof; } get { return _eof; }
} }
///<summary> ///<summary>
///When overridden in a derived class, gets the state of the reader. ///When overridden in a derived class, gets the state of the reader.
///</summary> ///</summary>
///
///<returns> ///<returns>
///One of the <see cref="T:System.Xml.ReadState"></see> values. ///One of the <see cref="T:System.Xml.ReadState"></see> values.
///</returns> ///</returns>
/// public override ReadState ReadState {
public override ReadState ReadState get {
{
get
{
if (!initialized) if (!initialized)
return ReadState.Initial; return ReadState.Initial;
else if (reader == null) else if (reader == null)
@ -1838,11 +1787,9 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
///<summary> ///<summary>
///When overridden in a derived class, gets the <see cref="T:System.Xml.XmlNameTable"></see> associated with this implementation. ///When overridden in a derived class, gets the <see cref="T:System.Xml.XmlNameTable"></see> associated with this implementation.
///</summary> ///</summary>
///
///<returns> ///<returns>
///The XmlNameTable enabling you to get the atomized version of a string within the node. ///The XmlNameTable enabling you to get the atomized version of a string within the node.
///</returns> ///</returns>
///
public override XmlNameTable NameTable public override XmlNameTable NameTable
{ {
get { return _nameTable; } get { return _nameTable; }
@ -1938,60 +1885,5 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
} }
#endregion #endregion
#region NodesCollection
internal class NodesCollection : List<XmlBamlNode>
{
public XmlBamlNode Last
{
get
{
if (this.Count > 0)
{
int i = this.Count - 1;
return this[i];
}
return null;
}
}
public void RemoveLast()
{
if (this.Count > 0)
this.Remove(this.Last);
}
public XmlBamlNode Dequeue()
{
return DequeueInternal(true);
}
public XmlBamlNode Peek()
{
return DequeueInternal(false);
}
XmlBamlNode DequeueInternal(bool remove)
{
if (this.Count > 0)
{
XmlBamlNode node = this[0];
if (remove)
this.RemoveAt(0);
return node;
}
else
return null;
}
public void Enqueue(XmlBamlNode node)
{
this.Add(node);
}
}
#endregion
} }
} }

23
ILSpy.BamlDecompiler/Tests/Cases/Dictionary1.xaml

@ -0,0 +1,23 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Color x:Key="VeryDark" A="255" R="70" G="70" B="70" />
<Color x:Key="Dark" A="255" R="102" G="102" B="102" />
<Color x:Key="Medium" A="255" R="140" G="140" B="140" />
<Color x:Key="Light" A="255" R="204" G="204" B="204" />
<Color x:Key="VeryLight" A="255" R="241" G="241" B="241" />
<Color x:Key="OffWhite" A="255" R="255" G="255" B="255" />
<Color x:Key="Highlight" A="255" R="220" G="107" B="47" />
<SolidColorBrush x:Key="VeryDarkBrush" Color="{StaticResource VeryDark}" />
<SolidColorBrush x:Key="DarkBrush" Color="{StaticResource Dark}" />
<SolidColorBrush x:Key="MediumBrush" Color="{StaticResource Medium}" />
<SolidColorBrush x:Key="LightBrush" Color="{StaticResource Light}" />
<SolidColorBrush x:Key="VeryLightBrush" Color="{StaticResource VeryLight}" />
<SolidColorBrush x:Key="OffWhiteBrush" Color="{StaticResource OffWhite}" />
<SolidColorBrush x:Key="HighlightBrush" Color="{StaticResource Highlight}" />
<LinearGradientBrush x:Key="EdgeBorder" StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#0000" Offset="0" />
<GradientStop Color="#1000" Offset="0.65" />
<GradientStop Color="#3000" Offset="1" />
</LinearGradientBrush>
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="#6FFF" />
<SolidColorBrush x:Key="SelectedBackgroundBrush" Color="{StaticResource Light}" />
</ResourceDictionary>

1
ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj

@ -128,6 +128,7 @@
</Page> </Page>
<Page Include="Cases\SimpleDictionary.xaml" /> <Page Include="Cases\SimpleDictionary.xaml" />
<Page Include="Cases\SimpleNames.xaml" /> <Page Include="Cases\SimpleNames.xaml" />
<Page Include="Cases\Dictionary1.xaml" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
</Project> </Project>

17
ILSpy.BamlDecompiler/Tests/TestRunner.cs

@ -61,18 +61,27 @@ namespace ILSpy.BamlDecompiler.Tests
RunTest("cases/attachedevent"); RunTest("cases/attachedevent");
} }
[Test]
public void Dictionary1()
{
RunTest("cases/dictionary1");
}
#region RunTest #region RunTest
void RunTest(string name) void RunTest(string name)
{ {
string asmPath = typeof(TestRunner).Assembly.Location; RunTest(name, typeof(TestRunner).Assembly.Location, Path.Combine("..\\..\\Tests", name + ".xaml"));
}
void RunTest(string name, string asmPath, string sourcePath)
{
var assembly = AssemblyDefinition.ReadAssembly(asmPath); var assembly = AssemblyDefinition.ReadAssembly(asmPath);
Resource res = assembly.MainModule.Resources.First(); Resource res = assembly.MainModule.Resources.First();
Stream bamlStream = LoadBaml(res, name + ".baml"); Stream bamlStream = LoadBaml(res, name + ".baml");
Assert.IsNotNull(bamlStream); Assert.IsNotNull(bamlStream);
XDocument document = BamlResourceEntryNode.LoadIntoDocument(new DefaultAssemblyResolver(), assembly, bamlStream); XDocument document = BamlResourceEntryNode.LoadIntoDocument(new DefaultAssemblyResolver(), assembly, bamlStream);
string path = Path.Combine("..\\..\\Tests", name + ".xaml");
CodeAssert.AreEqual(File.ReadAllText(sourcePath), document.ToString());
CodeAssert.AreEqual(File.ReadAllText(path), document.ToString());
} }
Stream LoadBaml(Resource res, string name) Stream LoadBaml(Resource res, string name)

4
ILSpy/AssemblyList.cs

@ -41,6 +41,8 @@ namespace ICSharpCode.ILSpy
/// <summary>Dirty flag, used to mark modifications so that the list is saved later</summary> /// <summary>Dirty flag, used to mark modifications so that the list is saved later</summary>
bool dirty; bool dirty;
internal readonly ConcurrentDictionary<string, LoadedAssembly> assemblyLookupCache = new ConcurrentDictionary<string, LoadedAssembly>();
/// <summary> /// <summary>
/// The assemblies in this list. /// The assemblies in this list.
/// Needs locking for multi-threaded access! /// Needs locking for multi-threaded access!
@ -101,6 +103,7 @@ namespace ICSharpCode.ILSpy
void Assemblies_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) void Assemblies_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{ {
assemblyLookupCache.Clear();
// Whenever the assembly list is modified, mark it as dirty // Whenever the assembly list is modified, mark it as dirty
// and enqueue a task that saves it once the UI has finished modifying the assembly list. // and enqueue a task that saves it once the UI has finished modifying the assembly list.
if (!dirty) { if (!dirty) {
@ -111,6 +114,7 @@ namespace ICSharpCode.ILSpy
delegate { delegate {
dirty = false; dirty = false;
AssemblyListManager.SaveList(this); AssemblyListManager.SaveList(this);
assemblyLookupCache.Clear();
}) })
); );
} }

9
ILSpy/LoadedAssembly.cs

@ -17,11 +17,11 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.Concurrent;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Threading; using System.Windows.Threading;
using ICSharpCode.ILSpy.Options; using ICSharpCode.ILSpy.Options;
using Mono.Cecil; using Mono.Cecil;
@ -134,6 +134,8 @@ namespace ICSharpCode.ILSpy
if (!disposed) { if (!disposed) {
disposed = true; disposed = true;
assemblyLoadDisableCount--; assemblyLoadDisableCount--;
// clear the lookup cache since we might have stored the lookups failed due to DisableAssemblyLoad()
MainWindow.Instance.CurrentAssemblyList.assemblyLookupCache.Clear();
} }
} }
} }
@ -178,6 +180,11 @@ namespace ICSharpCode.ILSpy
} }
public LoadedAssembly LookupReferencedAssembly(string fullName) public LoadedAssembly LookupReferencedAssembly(string fullName)
{
return assemblyList.assemblyLookupCache.GetOrAdd(fullName, LookupReferencedAssemblyInternal);
}
LoadedAssembly LookupReferencedAssemblyInternal(string fullName)
{ {
foreach (LoadedAssembly asm in assemblyList.GetAssemblies()) { foreach (LoadedAssembly asm in assemblyList.GetAssemblies()) {
if (asm.AssemblyDefinition != null && fullName.Equals(asm.AssemblyDefinition.FullName, StringComparison.OrdinalIgnoreCase)) if (asm.AssemblyDefinition != null && fullName.Equals(asm.AssemblyDefinition.FullName, StringComparison.OrdinalIgnoreCase))

15
ILSpy/MainWindow.xaml.cs

@ -208,6 +208,8 @@ namespace ICSharpCode.ILSpy
} }
var args = new CommandLineArguments(lines); var args = new CommandLineArguments(lines);
if (HandleCommandLineArguments(args)) { if (HandleCommandLineArguments(args)) {
if (!args.NoActivate && WindowState == WindowState.Minimized)
WindowState = WindowState.Normal;
HandleCommandLineArgumentsAfterShowList(args); HandleCommandLineArgumentsAfterShowList(args);
handled = true; handled = true;
return (IntPtr)1; return (IntPtr)1;
@ -392,9 +394,16 @@ namespace ICSharpCode.ILSpy
internal void SelectNode(SharpTreeNode obj) internal void SelectNode(SharpTreeNode obj)
{ {
if (obj != null) { if (obj != null) {
// Set both the selection and focus to ensure that keyboard navigation works as expected. if (!obj.AncestorsAndSelf().Any(node => node.IsHidden)) {
treeView.FocusNode(obj); // Set both the selection and focus to ensure that keyboard navigation works as expected.
treeView.SelectedItem = obj; treeView.FocusNode(obj);
treeView.SelectedItem = obj;
} else {
MessageBox.Show("Navigation failed because the target is hidden or a compiler-generated class.\n" +
"Please disable all filters that might hide the item (i.e. activate " +
"\"View > Show internal types and members\") and try again.",
"ILSpy", MessageBoxButton.OK, MessageBoxImage.Exclamation);
}
} }
} }

2
ILSpy/XmlDoc/XmlDocKeyProvider.cs

@ -169,6 +169,7 @@ namespace ICSharpCode.ILSpy.XmlDoc
} else { } else {
dotPos = key.LastIndexOf('.'); dotPos = key.LastIndexOf('.');
} }
if (dotPos < 0) return null;
TypeDefinition type = FindType(module, key.Substring(2, dotPos - 2)); TypeDefinition type = FindType(module, key.Substring(2, dotPos - 2));
if (type == null) if (type == null)
return null; return null;
@ -192,6 +193,7 @@ namespace ICSharpCode.ILSpy.XmlDoc
} else { } else {
ns = string.Empty; ns = string.Empty;
} }
if (string.IsNullOrEmpty(name)) return null;
TypeDefinition type = module.GetType(ns, name); TypeDefinition type = module.GetType(ns, name);
if (type == null && ns.Length > 0) { if (type == null && ns.Length > 0) {
// try if this is a nested type // try if this is a nested type

4
SharpTreeView/SharpTreeView.cs

@ -152,6 +152,10 @@ namespace ICSharpCode.TreeView
var list = SelectedItems.Cast<SharpTreeNode>().Except(selectedOldItems).ToList(); var list = SelectedItems.Cast<SharpTreeNode>().Except(selectedOldItems).ToList();
SetSelectedItems(list); SetSelectedItems(list);
} }
// reset the focus to the previous node
SelectedIndex = Math.Max(0, e.OldStartingIndex - 1);
if (SelectedItem != null)
FocusNode((SharpTreeNode)SelectedItem);
} }
} }

Loading…
Cancel
Save