303 lines
13 KiB
C#
303 lines
13 KiB
C#
|
//
|
|||
|
// License compiler for mono
|
|||
|
//
|
|||
|
// Authors:
|
|||
|
// Carlo Kok (ck@remobjects.com)
|
|||
|
//
|
|||
|
// (C) 2009 RemObjects Software
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|||
|
// a copy of this software and associated documentation files (the
|
|||
|
// "Software"), to deal in the Software without restriction, including
|
|||
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|||
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|||
|
// permit persons to whom the Software is furnished to do so, subject to
|
|||
|
// the following conditions:
|
|||
|
//
|
|||
|
// The above copyright notice and this permission notice shall be
|
|||
|
// included in all copies or substantial portions of the Software.
|
|||
|
//
|
|||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|||
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|||
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|||
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|||
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
|
//
|
|||
|
|
|||
|
using System;
|
|||
|
using System.Collections;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Linq;
|
|||
|
using System.Text;
|
|||
|
using Mono.Options;
|
|||
|
using System.ComponentModel.Design;
|
|||
|
using System.IO;
|
|||
|
using System.Reflection;
|
|||
|
using System.Globalization;
|
|||
|
using System.ComponentModel;
|
|||
|
using System.Runtime.Serialization.Formatters.Binary;
|
|||
|
|
|||
|
namespace LC
|
|||
|
{
|
|||
|
public class LCLicenseContext : DesigntimeLicenseContext
|
|||
|
{
|
|||
|
public string OutputFilename { get; set; }
|
|||
|
public string LicxFilename { get; set; }
|
|||
|
}
|
|||
|
|
|||
|
class Program
|
|||
|
{
|
|||
|
static List<String> privatePaths = new List<string>();
|
|||
|
|
|||
|
static int Main(string[] args)
|
|||
|
{
|
|||
|
bool verbose = false;
|
|||
|
string target = null;
|
|||
|
string complist = null;
|
|||
|
string targetdir = ".";
|
|||
|
List<string> references = new List<string>();
|
|||
|
|
|||
|
bool nologo = false;
|
|||
|
bool help = false;
|
|||
|
OptionSet p = new OptionSet() {
|
|||
|
{"v|verbose", "Verbose output", v => verbose = v!= null },
|
|||
|
{"t|target=", "Target assembly name", v => target = v },
|
|||
|
{"c|complist=","licx file to compile", v => complist = v },
|
|||
|
{"i|load=", "Reference to load", v=> {if (v != null) references.Add(v);}},
|
|||
|
{"o|outdir=", "Output directory for the .licenses file", v=> targetdir = v },
|
|||
|
{"nologo", "Do not display logo", v=> nologo = null != v },
|
|||
|
{"h|?|help", "Show help", v=>help = v != null }
|
|||
|
};
|
|||
|
List<string> extra;
|
|||
|
try
|
|||
|
{
|
|||
|
extra = p.Parse(args);
|
|||
|
}
|
|||
|
catch(OptionException e)
|
|||
|
{
|
|||
|
Console.WriteLine("lc: " + e.Message);
|
|||
|
Console.WriteLine("try lc --help for more information");
|
|||
|
return 1;
|
|||
|
}
|
|||
|
if (!nologo) {
|
|||
|
Console.WriteLine("Mono License Compiler");
|
|||
|
Console.WriteLine("Copyright (c) 2009 by RemObjects Software");
|
|||
|
}
|
|||
|
if (help) {
|
|||
|
Console.WriteLine();
|
|||
|
Console.WriteLine("lc -c filename -t targetassembly [-i references] [-v] [-o] [-nologo]");
|
|||
|
Console.WriteLine();
|
|||
|
Console.WriteLine("Options:");
|
|||
|
p.WriteOptionDescriptions(Console.Out);
|
|||
|
return 1;
|
|||
|
}
|
|||
|
if (extra.Count > 0) {
|
|||
|
Console.WriteLine("Unexpected arguments passed on cmd line");
|
|||
|
return 1;
|
|||
|
}
|
|||
|
if (target == null || complist == null){
|
|||
|
Console.WriteLine("No target/complist passed");
|
|||
|
return 1;
|
|||
|
}
|
|||
|
try {
|
|||
|
if (!File.Exists(complist)) {
|
|||
|
Console.WriteLine("Could not find file: "+complist);
|
|||
|
return 1;
|
|||
|
}
|
|||
|
|
|||
|
LCLicenseContext ctx = new LCLicenseContext();
|
|||
|
ctx.LicxFilename = complist;
|
|||
|
if (verbose) Console.WriteLine("Input file: "+complist);
|
|||
|
ctx.OutputFilename = Path.Combine(targetdir ??".", target)+".licenses";
|
|||
|
if (verbose) Console.WriteLine("Output filename: "+ctx.OutputFilename);
|
|||
|
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
|
|||
|
privatePaths.Add(".");
|
|||
|
Dictionary<string, Assembly> loaded = new Dictionary<string, Assembly>();
|
|||
|
foreach (string reference in references) {
|
|||
|
string path = Path.GetDirectoryName(reference);
|
|||
|
if (!privatePaths.Contains(path))
|
|||
|
{
|
|||
|
if (verbose) Console.WriteLine("Adding " + Path.GetDirectoryName(reference) + " to private paths");
|
|||
|
privatePaths.Add(path);
|
|||
|
}
|
|||
|
Assembly asm = Assembly.LoadFrom(reference);
|
|||
|
loaded.Add(asm.GetName().Name, asm);
|
|||
|
if (verbose) Console.WriteLine("Loaded assembly: "+asm.GetName().ToString());
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
using (StreamReader sr = new StreamReader(complist))
|
|||
|
{
|
|||
|
int lineno = 0;
|
|||
|
string line = "";
|
|||
|
while (sr.Peek() != -1)
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
line = sr.ReadLine();
|
|||
|
if (line == null || line == "" || line[0] == '#' ) continue;
|
|||
|
if (verbose) Console.WriteLine("Generating license for: "+line);
|
|||
|
|
|||
|
string[] sLine = line.Split(new char[] { ',' }, 2);
|
|||
|
Type stype = null;
|
|||
|
if (sLine.Length == 1)
|
|||
|
{
|
|||
|
stype = Type.GetType(line, false, true);
|
|||
|
if (stype == null)
|
|||
|
{
|
|||
|
foreach (KeyValuePair<string, Assembly> et in loaded)
|
|||
|
{
|
|||
|
stype = et.Value.GetType(sLine[0], false, true);
|
|||
|
if (stype != null) {
|
|||
|
if (verbose) Console.WriteLine("Found type in "+et.Key);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (sLine[1].IndexOf(',') >= 0)
|
|||
|
{
|
|||
|
stype = Type.GetType(line, false, true);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
string s = sLine[1].Trim();
|
|||
|
foreach (KeyValuePair<string, Assembly> et in loaded)
|
|||
|
{
|
|||
|
if (String.Compare(et.Key, s, true, CultureInfo.InvariantCulture) == 0)
|
|||
|
{
|
|||
|
stype = et.Value.GetType(sLine[0], false, true);
|
|||
|
if (stype != null) {
|
|||
|
if (verbose) Console.WriteLine("Found type in "+et.Key);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
if (stype == null)
|
|||
|
{
|
|||
|
foreach (KeyValuePair<string, Assembly> et in loaded)
|
|||
|
{
|
|||
|
stype = et.Value.GetType(sLine[0], false, true);
|
|||
|
if (stype != null) {
|
|||
|
if (verbose) Console.WriteLine("Found type in "+et.Key);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
if (stype == null)
|
|||
|
throw new Exception("Unable to find type: " + line);
|
|||
|
LicenseManager.CreateWithContext(stype, ctx);
|
|||
|
}
|
|||
|
catch(Exception e)
|
|||
|
{
|
|||
|
Console.WriteLine("Exception during compiling " + complist + ": " + lineno);
|
|||
|
Console.WriteLine(e.ToString());
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
using (FileStream fs = new FileStream(ctx.OutputFilename, FileMode.Create)) {
|
|||
|
try {
|
|||
|
DesigntimeLicenseContextSerializer.Serialize(fs, target.ToUpper(CultureInfo.InvariantCulture), ctx);
|
|||
|
} catch {}
|
|||
|
if (fs.Length == 0) // older mono does not support this, but when it does, we should use the proper version.
|
|||
|
IntSerialize(fs, target.ToUpper(CultureInfo.InvariantCulture), ctx);
|
|||
|
}
|
|||
|
if (verbose)
|
|||
|
Console.WriteLine("Saved to: "+ Path.GetFullPath(ctx.OutputFilename));
|
|||
|
return 0;
|
|||
|
} catch(Exception e){
|
|||
|
Console.WriteLine("Exception: "+e.ToString());
|
|||
|
return 1;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
private static void IntSerialize(Stream o,
|
|||
|
string cryptoKey,
|
|||
|
DesigntimeLicenseContext context)
|
|||
|
{
|
|||
|
Object[] lData = new Object[2];
|
|||
|
lData[0] = cryptoKey;
|
|||
|
Hashtable lNewTable = new Hashtable();
|
|||
|
FieldInfo fi =
|
|||
|
typeof(DesigntimeLicenseContext).GetField("savedLicenseKeys", BindingFlags.NonPublic | BindingFlags.Instance) ??
|
|||
|
typeof(DesigntimeLicenseContext).GetField("keys", BindingFlags.NonPublic | BindingFlags.Instance)
|
|||
|
;
|
|||
|
Hashtable lOrgTable = (Hashtable)fi.GetValue(context);
|
|||
|
foreach (DictionaryEntry et in lOrgTable)
|
|||
|
{
|
|||
|
if (et.Key is string)
|
|||
|
lNewTable.Add(et.Key, et.Value);
|
|||
|
else
|
|||
|
lNewTable.Add(((Type)et.Key).AssemblyQualifiedName, et.Value);
|
|||
|
}
|
|||
|
lData[1] = lNewTable;
|
|||
|
|
|||
|
BinaryFormatter lFormatter = new BinaryFormatter();
|
|||
|
lFormatter.Serialize(o, lData);
|
|||
|
|
|||
|
}
|
|||
|
static Dictionary<string, Assembly> loadedAssemblies = new Dictionary<string, Assembly>();
|
|||
|
|
|||
|
static bool CompareAssemblyName(string s1, string s2)
|
|||
|
{
|
|||
|
s1 = s1.ToLowerInvariant().Replace(" ", "");
|
|||
|
s2 = s2.ToLowerInvariant().Replace(" ", "");
|
|||
|
return s1 == s2;
|
|||
|
}
|
|||
|
|
|||
|
static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
|
|||
|
{
|
|||
|
string[] lArgs = args.Name.Split(',');
|
|||
|
string lName = lArgs[0].Trim();
|
|||
|
if (loadedAssemblies.ContainsKey(args.Name))
|
|||
|
{
|
|||
|
return loadedAssemblies[args.Name];
|
|||
|
}
|
|||
|
for (int i = 0; i < privatePaths.Count; i++)
|
|||
|
{
|
|||
|
string sPath = Path.Combine(privatePaths[i].ToString(), lName);
|
|||
|
if (File.Exists(sPath + ".dll"))
|
|||
|
sPath += ".dll";
|
|||
|
else if (File.Exists(sPath + ".DLL"))
|
|||
|
sPath += ".DLL";
|
|||
|
else if (File.Exists(sPath + ".exe"))
|
|||
|
sPath += ".exe";
|
|||
|
else if (File.Exists(sPath + ".EXE"))
|
|||
|
sPath += ".EXE";
|
|||
|
else
|
|||
|
continue;
|
|||
|
AssemblyName an2 = AssemblyName.GetAssemblyName(sPath);
|
|||
|
if (CompareAssemblyName(an2.ToString(), args.Name) || (lArgs.Length == 1 && CompareAssemblyName(an2.Name, lName)))
|
|||
|
{
|
|||
|
Assembly asm;
|
|||
|
try
|
|||
|
{
|
|||
|
asm = Assembly.LoadFrom(sPath);
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
asm = Assembly.LoadFile(sPath);
|
|||
|
}
|
|||
|
if (asm != null)
|
|||
|
{
|
|||
|
loadedAssemblies.Add(args.Name, asm);
|
|||
|
return asm;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
throw new Exception("Unable to find assembly "+args.Name);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|