ikvm-fork/ikvmstub/ikvmstub.cs

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

2002-12-18 19:00:25 +03:00
/*
Copyright (C) 2002, 2004, 2005, 2006, 2007, 2008 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 int zipCount;
2002-12-18 19:00:25 +03:00
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
2007-11-26 19:00:15 +03:00
public static int Main(string[] args)
2002-12-18 19:00:25 +03:00
{
2006-08-04 17:13:22 +04:00
IKVM.Internal.Tracer.EnableTraceForDebug();
string assemblyNameOrPath = null;
bool continueOnError = false;
foreach(string s in args)
{
if(s.StartsWith("-") || assemblyNameOrPath != null)
{
if(s == "-serialver")
{
java.lang.System.setProperty("ikvm.stubgen.serialver", "true");
}
else if(s == "-skiperror")
{
continueOnError = true;
}
else if(s.StartsWith("-r:") || s.StartsWith("-reference:"))
{
string path = s.Substring(s.IndexOf(':') + 1);
try
{
Assembly.ReflectionOnlyLoadFrom(path);
}
catch (Exception x)
{
Console.Error.WriteLine("Error: unable to load reference {0}", path);
Console.Error.WriteLine(" ({0})", x.Message);
return 1;
}
}
else
{
// unrecognized option, or multiple assemblies, print usage message and exit
assemblyNameOrPath = null;
break;
}
}
else
{
assemblyNameOrPath = s;
}
}
if(assemblyNameOrPath == null)
2004-06-07 12:28:57 +04:00
{
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();
Console.Error.WriteLine("usage: ikvmstub [-serialver] [-skiperror] <assemblyNameOrPath>");
2007-11-26 19:00:15 +03:00
return 1;
2004-06-07 12:28:57 +04:00
}
2002-12-18 19:00:25 +03:00
Assembly assembly = null;
2004-06-07 12:28:57 +04:00
try
{
file = new FileInfo(assemblyNameOrPath);
2004-06-07 12:28:57 +04:00
}
catch(System.Exception x)
{
Console.Error.WriteLine("Error: unable to load \"{0}\"\n {1}", assemblyNameOrPath, x.Message);
2007-11-26 19:00:15 +03:00
return 1;
2004-06-07 12:28:57 +04:00
}
if(file != null && file.Exists)
2002-12-18 19:00:25 +03:00
{
2007-12-17 10:43:06 +03:00
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += new ResolveEventHandler(CurrentDomain_ReflectionOnlyAssemblyResolve);
assembly = Assembly.ReflectionOnlyLoadFrom(assemblyNameOrPath);
2002-12-18 19:00:25 +03:00
}
2003-08-21 14:06:34 +04:00
else
{
#pragma warning disable 618
// Assembly.LoadWithPartialName is obsolete
assembly = Assembly.LoadWithPartialName(assemblyNameOrPath);
#pragma warning restore
2003-08-21 14:06:34 +04:00
}
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", assemblyNameOrPath);
2002-12-18 19:00:25 +03:00
}
else
{
try
2006-07-21 14:18:13 +04:00
{
using (zipFile = new ZipOutputStream(new java.io.FileOutputStream(assembly.GetName().Name + ".jar")))
{
zipFile.setComment(ikvm.runtime.Startup.getVersionAndCopyrightInfo());
try
{
rc = ProcessAssembly(assembly, continueOnError);
}
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));
if (!continueOnError)
{
Console.Error.WriteLine("Warning: Assembly reflection encountered an error. Resultant JAR may be incomplete.");
}
rc = 1;
}
}
}
catch (ZipException x)
{
rc = 1;
if (zipCount == 0)
{
Console.Error.WriteLine("Error: Assembly contains no public IKVM.NET compatible types");
}
else
{
Console.Error.WriteLine("Error: {0}", x.Message);
2006-07-21 14:18:13 +04:00
}
}
2002-12-18 19:00:25 +03:00
}
2007-11-26 19:00:15 +03:00
return rc;
2002-12-18 19:00:25 +03:00
}
2005-12-19 18:12:49 +03:00
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;
}
}
string path = args.Name;
int index = path.IndexOf(',');
if(index > 0)
{
path = path.Substring(0, index);
}
path = file.DirectoryName + Path.DirectorySeparatorChar + path + ".dll";
if(File.Exists(path))
{
return Assembly.ReflectionOnlyLoadFrom(path);
}
return Assembly.ReflectionOnlyLoad(args.Name);
2005-12-19 18:12:49 +03:00
}
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();
}
zipCount++;
zipFile.putNextEntry(new ZipEntry(name + ".class"));
zipFile.write(buf, 0, buf.Length);
2002-12-18 19:00:25 +03:00
}
private static int ProcessAssembly(Assembly assembly, bool continueOnError)
2002-12-18 19:00:25 +03:00
{
int rc = 0;
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.
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
}
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);
try
{
ProcessClass(c);
}
catch (Exception x)
{
if (continueOnError)
{
rc = 1;
java.lang.Throwable.instancehelper_printStackTrace(ikvm.runtime.Util.mapException(x));
}
else
{
throw;
}
}
WriteClass(c);
2003-10-22 20:34:22 +04:00
}
}
} while(keepGoing);
return rc;
2003-10-22 20:34:22 +04:00
}
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)
{
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;
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
}
2002-12-18 19:00:25 +03:00
}