---+ 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