ikvm-fork/ikvmstub/ikvmstub.cs

320 строки
8.6 KiB
C#
Исходник Обычный вид История

2002-12-18 19:00:25 +03:00
/*
Copyright (C) 2002, 2004, 2005, 2006, 2007 Jeroen Frijters
2002-12-18 19:00:25 +03:00
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jeroen Frijters
jeroen@frijters.net
*/
using System;
using System.Reflection;
using System.IO;
2003-10-22 20:34:22 +04:00
using System.Collections;
using java.util.zip;
using java.lang.reflect;
2002-12-18 19:00:25 +03:00
public class NetExp
{
private static ZipOutputStream zipFile;
2006-09-12 16:36:19 +04:00
private static Hashtable done = new Hashtable();
private static Hashtable todo = new Hashtable();
2005-12-19 18:12:49 +03:00
private static FileInfo file;
2002-12-18 19:00:25 +03:00
public static void Main(string[] args)
{
2006-08-04 17:13:22 +04:00
IKVM.Internal.Tracer.EnableTraceForDebug();
2004-06-07 12:28:57 +04:00
if(args.Length != 1)
{
2006-08-17 11:33:38 +04:00
Console.Error.WriteLine(ikvm.runtime.Startup.getVersionAndCopyrightInfo());
2006-01-31 13:13:12 +03:00
Console.Error.WriteLine();
2004-06-07 12:28:57 +04:00
Console.Error.WriteLine("usage: ikvmstub <assemblyNameOrPath>");
return;
}
2002-12-18 19:00:25 +03:00
Assembly assembly = null;
2004-06-07 12:28:57 +04:00
try
{
file = new FileInfo(args[0]);
}
catch(System.Exception x)
{
Console.Error.WriteLine("Error: unable to load \"{0}\"\n {1}", args[0], x.Message);
return;
}
if(file != null && file.Exists)
2002-12-18 19:00:25 +03:00
{
2005-12-07 12:06:32 +03:00
#if WHIDBEY
2005-12-19 18:12:49 +03:00
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += new ResolveEventHandler(CurrentDomain_ReflectionOnlyAssemblyResolve);
2005-12-07 12:06:32 +03:00
assembly = Assembly.ReflectionOnlyLoadFrom(args[0]);
#else
2003-08-26 15:24:17 +04:00
try
{
// If the same assembly can be found in the "Load" context, we prefer to use that
// http://blogs.gotdotnet.com/suzcook/permalink.aspx/d5c5e14a-3612-4af1-a9b7-0a144c8dbf16
// We use AssemblyName.FullName, because otherwise the assembly will be loaded in the
// "LoadFrom" context using the path inside the AssemblyName object.
assembly = Assembly.Load(AssemblyName.GetAssemblyName(args[0]).FullName);
Console.Error.WriteLine("Warning: Assembly loaded from {0} instead", assembly.Location);
}
catch
{
}
if(assembly == null)
{
2006-08-21 09:15:51 +04:00
// since we're loading the assembly in the LoadFrom context, we need to hook the AssemblyResolve event
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
2003-08-26 15:24:17 +04:00
assembly = Assembly.LoadFrom(args[0]);
}
2005-12-07 12:06:32 +03:00
#endif
2002-12-18 19:00:25 +03:00
}
2003-08-21 14:06:34 +04:00
else
{
assembly = Assembly.LoadWithPartialName(args[0]);
}
2005-02-02 18:11:26 +03:00
int rc = 0;
2002-12-18 19:00:25 +03:00
if(assembly == null)
{
Console.Error.WriteLine("Error: Assembly \"{0}\" not found", args[0]);
}
else
{
using(zipFile = new ZipOutputStream(new java.io.FileOutputStream(assembly.GetName().Name + ".jar")))
2006-07-21 14:18:13 +04:00
{
zipFile.setComment(ikvm.runtime.Startup.getVersionAndCopyrightInfo());
try
2006-07-21 14:18:13 +04:00
{
ProcessAssembly(assembly);
}
catch(ReflectionTypeLoadException x)
{
Console.WriteLine(x);
Console.WriteLine("LoaderExceptions:");
foreach (Exception n in x.LoaderExceptions)
{
Console.WriteLine(n);
}
}
catch(System.Exception x)
{
java.lang.Throwable.instancehelper_printStackTrace(ikvm.runtime.Util.mapException(x));
rc = 1;
2006-07-21 14:18:13 +04:00
}
}
2002-12-18 19:00:25 +03:00
}
2004-05-25 11:14:39 +04:00
// FXBUG if we run a static initializer that starts a thread, we would never end,
2003-08-21 14:06:34 +04:00
// so we force an exit here
2005-02-02 18:11:26 +03:00
Environment.Exit(rc);
2002-12-18 19:00:25 +03:00
}
2005-12-19 18:12:49 +03:00
#if WHIDBEY
private static Assembly CurrentDomain_ReflectionOnlyAssemblyResolve(object sender, ResolveEventArgs args)
{
foreach(Assembly a in AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies())
{
if(args.Name.StartsWith(a.GetName().Name + ", "))
{
return a;
}
}
2006-07-21 14:18:13 +04:00
Assembly asm = Assembly.ReflectionOnlyLoad(args.Name);
if(asm != null)
{
return asm;
}
2005-12-19 18:12:49 +03:00
string path = args.Name;
int index = path.IndexOf(',');
if(index > 0)
{
path = path.Substring(0, index);
}
path = file.DirectoryName + Path.DirectorySeparatorChar + path + ".dll";
Console.WriteLine("Loading referenced assembly: " + path);
return Assembly.ReflectionOnlyLoadFrom(path);
}
#endif
private static void WriteClass(java.lang.Class c)
2002-12-18 19:00:25 +03:00
{
string name = c.getName().Replace('.', '/');
java.io.InputStream inp = c.getResourceAsStream("/" + name + ".class");
if(inp == null)
{
Console.Error.WriteLine("Class {0} not found", name);
return;
}
byte[] buf = new byte[inp.available()];
if(inp.read(buf) != buf.Length || inp.read() != -1)
{
throw new NotImplementedException();
}
zipFile.putNextEntry(new ZipEntry(name + ".class"));
zipFile.write(buf, 0, buf.Length);
2002-12-18 19:00:25 +03:00
}
2003-08-21 14:06:34 +04:00
private static void ProcessAssembly(Assembly assembly)
2002-12-18 19:00:25 +03:00
{
foreach(System.Type t in assembly.GetTypes())
2002-12-18 19:00:25 +03:00
{
2003-08-21 14:06:34 +04:00
if(t.IsPublic)
2002-12-18 19:00:25 +03:00
{
2005-02-02 18:11:26 +03:00
java.lang.Class c;
// NOTE we use getClassFromTypeHandle instead of getFriendlyClassFromType, to make sure
// we don't get the remapped types when we're processing System.Object, System.String,
// System.Throwable and System.IComparable.
// NOTE we can't use getClassFromTypeHandle for ReflectionOnly assemblies
// (because Type.TypeHandle is not supported by ReflectionOnly types), but this
// isn't a problem because mscorlib is never loaded in the ReflectionOnly context.
2006-05-15 13:08:01 +04:00
#if WHIDBEY
if(assembly.ReflectionOnly)
{
c = ikvm.runtime.Util.getFriendlyClassFromType(t);
}
else
{
2006-08-17 11:33:38 +04:00
c = ikvm.runtime.Util.getClassFromTypeHandle(t.TypeHandle);
2004-10-04 23:30:53 +04:00
}
#else
c = ikvm.runtime.Util.getClassFromTypeHandle(t.TypeHandle);
#endif
if(c != null)
2004-10-04 23:30:53 +04:00
{
AddToExportList(c);
2004-10-04 23:30:53 +04:00
}
2002-12-18 19:00:25 +03:00
}
}
2003-10-22 20:34:22 +04:00
bool keepGoing;
do
{
keepGoing = false;
2006-09-12 16:36:19 +04:00
foreach(java.lang.Class c in new ArrayList(todo.Values))
2003-10-22 20:34:22 +04:00
{
if(!done.ContainsKey(c.getName()))
{
keepGoing = true;
done.Add(c.getName(), null);
2006-08-04 16:39:33 +04:00
ProcessClass(c);
WriteClass(c);
2003-10-22 20:34:22 +04:00
}
}
} while(keepGoing);
}
2005-06-22 17:02:03 +04:00
private static void AddToExportList(java.lang.Class c)
{
2005-06-22 18:24:16 +04:00
while(c.isArray())
{
c = c.getComponentType();
}
2006-09-12 16:36:19 +04:00
todo[c.getName()] = c;
2005-06-22 17:02:03 +04:00
}
private static bool IsGenericType(java.lang.Class c)
{
#if WHIDBEY
System.Type t = ikvm.runtime.Util.getInstanceTypeFromClass(c);
while(t == null && c.getDeclaringClass() != null)
{
// dynamic only inner class, so we look at the declaring class
c = c.getDeclaringClass();
t = ikvm.runtime.Util.getInstanceTypeFromClass(c);
}
return t.IsGenericType;
#else
2005-11-14 12:12:08 +03:00
return c.getName().IndexOf("$$0060") > 0;
#endif
2005-06-22 17:02:03 +04:00
}
private static void AddToExportListIfNeeded(java.lang.Class c)
{
if(IsGenericType(c) || (c.getModifiers() & Modifier.PUBLIC) == 0)
{
AddToExportList(c);
}
}
private static void AddToExportListIfNeeded(java.lang.Class[] classes)
{
foreach(java.lang.Class c in classes)
{
AddToExportListIfNeeded(c);
}
}
2006-08-04 16:39:33 +04:00
private static void ProcessClass(java.lang.Class c)
2002-12-18 19:00:25 +03:00
{
java.lang.Class superclass = c.getSuperclass();
if(superclass != null)
2003-04-14 13:41:58 +04:00
{
AddToExportListIfNeeded(c.getSuperclass());
2003-04-14 13:41:58 +04:00
}
foreach(java.lang.Class iface in c.getInterfaces())
2003-11-17 15:01:50 +03:00
{
AddToExportListIfNeeded(iface);
2003-11-17 15:01:50 +03:00
}
2006-09-12 16:36:19 +04:00
java.lang.Class outerClass = c.getDeclaringClass();
if(outerClass != null)
{
AddToExportList(outerClass);
}
foreach(java.lang.Class innerClass in c.getDeclaredClasses())
2002-12-18 19:00:25 +03:00
{
int mods = innerClass.getModifiers();
if((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0)
2002-12-18 19:00:25 +03:00
{
AddToExportList(innerClass);
2002-12-18 19:00:25 +03:00
}
}
foreach(Constructor constructor in c.getDeclaredConstructors())
2002-12-18 19:00:25 +03:00
{
int mods = constructor.getModifiers();
if((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0)
2002-12-18 19:00:25 +03:00
{
AddToExportListIfNeeded(constructor.getParameterTypes());
2002-12-18 19:00:25 +03:00
}
}
foreach(Method method in c.getDeclaredMethods())
2002-12-18 19:00:25 +03:00
{
int mods = method.getModifiers();
if((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0)
2005-10-01 15:16:11 +04:00
{
AddToExportListIfNeeded(method.getParameterTypes());
AddToExportListIfNeeded(method.getReturnType());
2002-12-18 19:00:25 +03:00
}
}
foreach(Field field in c.getDeclaredFields())
2002-12-18 19:00:25 +03:00
{
int mods = field.getModifiers();
if((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0)
2002-12-18 19:00:25 +03:00
{
AddToExportListIfNeeded(field.getType());
2002-12-18 19:00:25 +03:00
}
2003-08-21 14:06:34 +04:00
}
2005-10-01 15:16:11 +04:00
}
2006-08-21 09:15:51 +04:00
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
foreach(Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
{
if(asm.FullName == args.Name)
{
return asm;
}
}
return null;
}
2002-12-18 19:00:25 +03:00
}