Decompilation Salamander Test
Program-Transformation.Org: The Program Transformation Wiki
Salamander .NET to C# Decompiler Tests
Salamander is a commercial .NET to C# decompiler.
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 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.
--
MikeVanEmmerik - 06 Mar 2003
CategoryDecompilation