---+ Salamander .NET to C# Decompiler Tests Salamander is a commercial .NET to C# decompiler. %TOC% ---++ Fibo For source, see DecompilerFiboDotNetSource. Decompiled source from Salamander: // Decompiled by Salamander version 1.0.9 // Copyright 2002 Remotesoft Inc. All rights reserved. // http://www.remotesoft.com/salamander using System; class Fibo { private static int fib(int x) { if (x > 1) { return fib(x - 1) + fib(x - 2); } else { return x; } } // Decompilation not complete! (2) public static int Main(string[] args) { int j = 0; try { j = Convert.ToInt32(args[0]); } catch (Exception e) { Console.WriteLine("Input error"); int k = 1; return k; } goto IL_0027; IL_0022: leave IL_0027 IL_0027: int i = fib(j); Console.WriteLine("fibonacci({0}) = {1}", j, i); return 0; } } The decompilation is complete, except for a goto over a =leave= opcode. This is presumably because Salamander has been tested only on Microsoft compilers (and mostly only on the C# compiler, according to the web page). (However, see the [[#Image_Viewer][Image Viewer test]] below). When the line with _leave_ is commented out, the result compiles and runs correctly. ---++ Casting For source, see DecompilerCastingDotNetSource. A few casts are required to get this program to compile correctly. Here is the output from Salamander: // Decompiled by Salamander version 1.0.9 using System; public class Casting { public static void Main(string[] args) { for (char ch1 = '\0'; ch1 < '\u0080'; ch1++) { Console.WriteLine("ascii {0} character {1}", ch1, ch1); } } } The main cast is missing in the =WriteLine= statement. When the cast is inserted, the program compiles and is correct. ---++ Inner Classes For source, see DecompilerInnerClassesDotNetSource. When decompiled with Salamander, the result is // Decompiled by Salamander version 1.0.9 using System; public class Usa { public class England { public class Ireland { public string name = "Dublin"; public void print_names() { Console.WriteLine(name); } } public string name = "London"; } public string name = "Detroit"; public static void Main(string[] args) { } } It reproduced the inner classes correctly. The output compiled with no errors. ---++ Sable Test Program For source, see DecompilerSableDotNetSource. Here is the result for class =MainClass= (as produced by Salamander):
public class MainClass
{
  public static void f(short i)
  {
	 Drawable drawable;

	 bool flag;

	 if (i > 10)
	 {
		Rectangle rectangle = new Rectangle(i, i);
		flag = rectangle.isFat();
		drawable = rectangle;
	 }
	 else
	 {
		Circle circle = new Circle(i);
		flag = circle.isFat();
		drawable = circle;
	 }
	 if (!flag)
	 {
		drawable.draw();
	 }
  }
  public static void Main(string[] args)
  {
	 f(11);
  }
The code is reproduced correctly, and no unnecessary casts are generated. Note the lack of a cast to the constant =11= in =Main()=; unlike Java, no cast is necessary in C#. ---++ Simple Control Flow For source, see DecompilerControlFlowDotNetSource. For function =foo=, Salamander produces: // Decompiled by Salamander version 1.0.9 // Decompilation not complete! (1) public static int foo(int i, int j) { Exception e; for (; i < j; i = j++ / i) { } IL_0018: leave IL_002c IL_001d: stloc.0 i = 10; IL_0022: leave IL_0000 IL_0027: leave IL_002c return j; } It has moved the divide out of the =try= block into the =for= loop, which is not correct. The exception code is missing, and the output is obviously wrong. ---++ Image Viewer For source, see DecompilerImageViewerDotNetSource. This is a slightly larger example, compiled with the Microsoft C# compiler. Still, it has problems with branches over leave instructions, e.g. private static Pixbuf GetPixbufFromFile(string filename) { Pixbuf pixbuf2; try { Pixbuf pixbuf1 = new Pixbuf(filename); pixbuf2 = pixbuf1; } catch (GException e) { Console.WriteLine(e.GetType()); Console.WriteLine("Cannot Open file."); Environment.Exit(1); pixbuf2 = null; } goto IL_003c; IL_000f: leave IL_003c IL_0037: leave IL_003c IL_003c: return pixbuf2; } The rest appears to have decompiled successfully, e.g. public static void Main(string[] args) { if (args.Length > 0 != false) { Console.WriteLine("\nUSAGE: ImageViewer.exe \n"); return; } string str = args[0]; Application.Init(); window = new Window("File Viewer"); window.SetDefaultSize(200, 200); window.DeleteEvent += new EventHandler(null.Window_Delete); ScrolledWindow scrolledWindow = new ScrolledWindow( new Adjustment(IntPtr.Zero), new Adjustment(IntPtr.Zero)); VBox vBox1 = new VBox(false, 2); VBox vBox2 = new VBox(false, 0); MenuBar menuBar = new MenuBar(); Menu menu = new Menu(); MenuItem menuItem1 = new ImageMenuItem("gtk-close", new AccelGroup(IntPtr.Zero)); MenuItem menuItem2 = new ImageMenuItem("gtk-open", new AccelGroup(IntPtr.Zero)); menuItem1.Activated += new EventHandler(null.Window_Delete); menuItem2.Activated += new EventHandler(null.Window_Open); menu.Append(menuItem2); menu.Append(new SeparatorMenuItem()); menu.Append(menuItem1); MenuItem menuItem3 = new MenuItem("_File"); menuItem3.Submenu = menu; menuBar.Append(menuItem3); vBox2.PackStart(menuBar, false, false, 0); Toolbar toolbar = new Toolbar(); toolbar.InsertStock("gtk-open", "Open", String.Empty, new SignalFunc(null, Window_Open), IntPtr.Zero, 0); toolbar.InsertStock("gtk-close", "Close", String.Empty, new SignalFunc(null, Window_Delete), IntPtr.Zero, 1); vBox2.PackStart(toolbar, false, false, 0); vBox1.PackStart(vBox2, false, false, 0); Pixbuf pixbuf = GetPixbufFromFile(str); image = new Image(pixbuf); Refresh(str, pixbuf); scrolledWindow.AddWithViewport(image); vBox1.PackStart(scrolledWindow, true, true, 0); scrolledWindow.SetPolicy(1, 1); window.Add(vBox1); window.ShowAll(); Application.Run(); } The translation "if (args.Length > 0 != false)" seems clumsy. -- Main.MikeVanEmmerik - 06 Mar 2003
CategoryDecompilation