Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shortened View around changes only + Export #11

Open
cocoon opened this issue Jan 16, 2021 · 0 comments
Open

Shortened View around changes only + Export #11

cocoon opened this issue Jan 16, 2021 · 0 comments
Labels
enhancement New feature or request

Comments

@cocoon
Copy link

cocoon commented Jan 16, 2021

Hi, I really like how Aehnlich works!

When using it I missed a "short view" where it gets rid of nearly all similar code and shrinks it to only the changed parts and maybe a bit around (configure lines around).

And an "export function" to export it maybe as:

  • html file with diff view (side by side)
  • patch file (diff )
  • ...

Would be a great addition at least for me.

And I successfully extended it as an experiment to diff dotnet assemblies with adding ilspy functions to it.
(just as an alternative to JustAssembly)
Doubleclicking an assembly triggers the comparison.

CompareType.cs

/// <summary>
		/// Diff files as binary files.
		/// </summary>
		Binary,
		
		/// <summary>
		/// Diff files as assembly files.
		/// </summary>
		Assembly
	}

...

FileCompInfo.cs

public enum FileType
	{
		Unknown,
		NotExisting,
		Binary,
		Assembly,
		Text,
		Xml
	}

ProcessTextDiff


    using ICSharpCode.Decompiler;
    using ICSharpCode.Decompiler.CSharp;
    using ICSharpCode.Decompiler.Disassembler;
    using ICSharpCode.Decompiler.Metadata;
    using System.Threading;

private DiffBinaryTextResults GetFileLines(FileCompInfo fileA
												,FileCompInfo fileB
												,TextBinaryDiffArgs args
												,IDiffProgress progress)
		{
			// Nothing to compare if both files do not exist
			if (fileA.FileExists == false && fileB.FileExists == false)
				return new DiffBinaryTextResults(CompareType.Text, new FileContentInfo(), new FileContentInfo());

			if (args.CompareType == CompareType.Assembly ||
				(args.IsAuto && fileA.Is == FileType.Assembly || fileB.Is == FileType.Assembly))
				return GetAssemblyFileLines(fileA, fileB, args, progress);

			if (args.CompareType == CompareType.Binary ||
				(args.IsAuto && fileA.Is == FileType.Binary || fileB.Is == FileType.Binary))
				return GetBinaryFileLines(fileA, fileB, args, progress);
...





private string DecompileAssembly(string assemblyFilePath)
        {
			if (String.IsNullOrEmpty(assemblyFilePath) || !File.Exists(assemblyFilePath)) return String.Empty;

			try
			{
				var settings = new DecompilerSettings();
				//settings = new DecompilerSettings { UsingDeclarations = false, ShowXmlDocumentation = false };
				var decompiler = new CSharpDecompiler(assemblyFilePath, settings);
				return decompiler.DecompileWholeModuleAsString();
			}
			catch(Exception ex)
            {
				Console.WriteLine(ex.ToString());

				//Try to decompile as IL
				try
				{
					using (var peFileStream = new FileStream(assemblyFilePath, FileMode.Open, FileAccess.Read))
					using (var peFile = new PEFile(assemblyFilePath, peFileStream))
					using (var writer = new StringWriter())
					{
						var output = new PlainTextOutput(writer);

						ReflectionDisassembler rd = new ReflectionDisassembler(output, CancellationToken.None);
						rd.DetectControlStructure = false;
						//rd.ShowMetadataTokens = false;
						//rd.ShowSequencePoints = false;


						rd.WriteAssemblyReferences(peFile.Metadata);
						var metadata = peFile.Metadata;
						if (metadata.IsAssembly)
							rd.WriteAssemblyHeader(peFile);
						output.WriteLine();
						rd.WriteModuleHeader(peFile);
						output.WriteLine();
						

						bool filterRvaAndCodeSize = true;
						if (filterRvaAndCodeSize)
						{
							/*
							StringBuilder result = new StringBuilder();
							var sb = writer.GetStringBuilder(); //get the underlying StringBuilder
							foreach (string line in sb.ToString().ReadLines())
							{
								if (!line.TrimStart().StartsWith("// Method begins at RVA") && !line.TrimStart().StartsWith("// Code size")) result.Append(line + Environment.NewLine);

							}
							return result.ToString();
							*/
							rd.WriteModuleContents(peFile, false);
						}
						else
						{
							rd.WriteModuleContents(peFile);
						}
						return writer.ToString();
					}
				}
				catch (Exception ex2)
				{
					Console.WriteLine(ex2.ToString());
				}
            }

			return string.Empty;
		}


		/// <summary>
		/// Get Assembly file contents disassembled and rendered as text lines with line number marker at beginning of each line.
		/// </summary>
		/// <param name="fileA"></param>
		/// <param name="fileB"></param>
		/// <param name="args"></param>
		/// <param name="progress"></param>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <param name="leadingCharactersToIgnore">Leading number of characters to ignore for diff in each line.
		/// This space is used in binary diff to display 8 digit line number and 4 digit space.</param>
		private DiffBinaryTextResults GetAssemblyFileLines(FileCompInfo fileA, FileCompInfo fileB
														, TextBinaryDiffArgs args
														, IDiffProgress progress)
		{
			// Neither left nor right file exist or cannot be accessed
			if (fileA.FileExists == false && fileB.FileExists == false)
				return new DiffBinaryTextResults(CompareType.Assembly, new FileContentInfo(), new FileContentInfo());

			string textA = DecompileAssembly(fileA.FileNamePath);
			string textB = DecompileAssembly(fileB.FileNamePath);

			FileContentInfo af = null, bf = null;

			if (af == null || bf == null)
			{
				af = new FileContentInfo();
				bf = new FileContentInfo();

				af.Lines = DiffUtility.GetStringTextLines(textA, progress);
				bf.Lines = DiffUtility.GetStringTextLines(textB, progress);
			}

			af.TextContent = textA;
			bf.TextContent = textB;
			DiffBinaryTextResults result = new DiffBinaryTextResults(CompareType.Text, af, bf);
			return result;
		}


Thanks for it!

@Dirkster99 Dirkster99 added the enhancement New feature or request label Apr 5, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants