2010-02-13 Jb Evain <jbevain@novell.com>
[mcs.git] / tools / lc / lc.cs
blob317932bd442d60c2760dc16d6943b83ecf6d0032
1 //
2 // License compiler for mono
3 //
4 // Authors:
5 // Carlo Kok (ck@remobjects.com)
6 //
7 // (C) 2009 RemObjects Software
8 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 //
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 //
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System;
32 using System.Collections;
33 using System.Collections.Generic;
34 using System.Linq;
35 using System.Text;
36 using Mono.Options;
37 using System.ComponentModel.Design;
38 using System.IO;
39 using System.Reflection;
40 using System.Globalization;
41 using System.ComponentModel;
42 using System.Runtime.Serialization.Formatters.Binary;
44 namespace LC
46 public class LCLicenseContext : DesigntimeLicenseContext
48 public string OutputFilename { get; set; }
49 public string LicxFilename { get; set; }
52 class Program
54 static List<String> privatePaths = new List<string>();
56 static int Main(string[] args)
58 bool verbose = false;
59 string target = null;
60 string complist = null;
61 string targetdir = ".";
62 List<string> references = new List<string>();
64 bool nologo = false;
65 bool help = false;
66 OptionSet p = new OptionSet() {
67 {"v|verbose", "Verbose output", v => verbose = v!= null },
68 {"t|target=", "Target assembly name", v => target = v },
69 {"c|complist=","licx file to compile", v => complist = v },
70 {"i|load=", "Reference to load", v=> {if (v != null) references.Add(v);}},
71 {"o|outdir=", "Output directory for the .licenses file", v=> targetdir = v },
72 {"nologo", "Do not display logo", v=> nologo = null != v },
73 {"h|?|help", "Show help", v=>help = v != null }
75 List<string> extra;
76 try
78 extra = p.Parse(args);
80 catch(OptionException e)
82 Console.WriteLine("lc: " + e.Message);
83 Console.WriteLine("try lc --help for more information");
84 return 1;
86 if (!nologo) {
87 Console.WriteLine("Mono License Compiler");
88 Console.WriteLine("Copyright (c) 2009 by RemObjects Software");
90 if (help) {
91 Console.WriteLine();
92 Console.WriteLine("lc -c filename -t targetassembly [-i references] [-v] [-o] [-nologo]");
93 Console.WriteLine();
94 Console.WriteLine("Options:");
95 p.WriteOptionDescriptions(Console.Out);
96 return 1;
98 if (extra.Count > 0) {
99 Console.WriteLine("Unexpected arguments passed on cmd line");
100 return 1;
102 if (target == null || complist == null){
103 Console.WriteLine("No target/complist passed");
104 return 1;
106 try {
107 if (!File.Exists(complist)) {
108 Console.WriteLine("Could not find file: "+complist);
109 return 1;
112 LCLicenseContext ctx = new LCLicenseContext();
113 ctx.LicxFilename = complist;
114 if (verbose) Console.WriteLine("Input file: "+complist);
115 ctx.OutputFilename = Path.Combine(targetdir ??".", target)+".licenses";
116 if (verbose) Console.WriteLine("Output filename: "+ctx.OutputFilename);
117 AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
118 privatePaths.Add(".");
119 Dictionary<string, Assembly> loaded = new Dictionary<string, Assembly>();
120 foreach (string reference in references) {
121 string path = Path.GetDirectoryName(reference);
122 if (!privatePaths.Contains(path))
124 if (verbose) Console.WriteLine("Adding " + Path.GetDirectoryName(reference) + " to private paths");
125 privatePaths.Add(path);
127 Assembly asm = Assembly.LoadFrom(reference);
128 loaded.Add(asm.GetName().Name, asm);
129 if (verbose) Console.WriteLine("Loaded assembly: "+asm.GetName().ToString());
133 using (StreamReader sr = new StreamReader(complist))
135 int lineno = 0;
136 string line = "";
137 while (sr.Peek() != -1)
141 line = sr.ReadLine();
142 if (line == null || line == "" || line[0] == '#' ) continue;
143 if (verbose) Console.WriteLine("Generating license for: "+line);
145 string[] sLine = line.Split(new char[] { ',' }, 2);
146 Type stype = null;
147 if (sLine.Length == 1)
149 stype = Type.GetType(line, false, true);
150 if (stype == null)
152 foreach (KeyValuePair<string, Assembly> et in loaded)
154 stype = et.Value.GetType(sLine[0], false, true);
155 if (stype != null) {
156 if (verbose) Console.WriteLine("Found type in "+et.Key);
157 break;
162 else
164 if (sLine[1].IndexOf(',') >= 0)
166 stype = Type.GetType(line, false, true);
168 else
170 string s = sLine[1].Trim();
171 foreach (KeyValuePair<string, Assembly> et in loaded)
173 if (String.Compare(et.Key, s, true, CultureInfo.InvariantCulture) == 0)
175 stype = et.Value.GetType(sLine[0], false, true);
176 if (stype != null) {
177 if (verbose) Console.WriteLine("Found type in "+et.Key);
178 break;
182 if (stype == null)
184 foreach (KeyValuePair<string, Assembly> et in loaded)
186 stype = et.Value.GetType(sLine[0], false, true);
187 if (stype != null) {
188 if (verbose) Console.WriteLine("Found type in "+et.Key);
189 break;
195 if (stype == null)
196 throw new Exception("Unable to find type: " + line);
197 LicenseManager.CreateWithContext(stype, ctx);
199 catch(Exception e)
201 Console.WriteLine("Exception during compiling " + complist + ": " + lineno);
202 Console.WriteLine(e.ToString());
207 using (FileStream fs = new FileStream(ctx.OutputFilename, FileMode.Create)) {
208 try {
209 DesigntimeLicenseContextSerializer.Serialize(fs, target.ToUpper(CultureInfo.InvariantCulture), ctx);
210 } catch {}
211 if (fs.Length == 0) // older mono does not support this, but when it does, we should use the proper version.
212 IntSerialize(fs, target.ToUpper(CultureInfo.InvariantCulture), ctx);
214 if (verbose)
215 Console.WriteLine("Saved to: "+ Path.GetFullPath(ctx.OutputFilename));
216 return 0;
217 } catch(Exception e){
218 Console.WriteLine("Exception: "+e.ToString());
219 return 1;
225 private static void IntSerialize(Stream o,
226 string cryptoKey,
227 DesigntimeLicenseContext context)
229 Object[] lData = new Object[2];
230 lData[0] = cryptoKey;
231 Hashtable lNewTable = new Hashtable();
232 FieldInfo fi =
233 typeof(DesigntimeLicenseContext).GetField("savedLicenseKeys", BindingFlags.NonPublic | BindingFlags.Instance) ??
234 typeof(DesigntimeLicenseContext).GetField("keys", BindingFlags.NonPublic | BindingFlags.Instance)
236 Hashtable lOrgTable = (Hashtable)fi.GetValue(context);
237 foreach (DictionaryEntry et in lOrgTable)
239 if (et.Key is string)
240 lNewTable.Add(et.Key, et.Value);
241 else
242 lNewTable.Add(((Type)et.Key).AssemblyQualifiedName, et.Value);
244 lData[1] = lNewTable;
246 BinaryFormatter lFormatter = new BinaryFormatter();
247 lFormatter.Serialize(o, lData);
250 static Dictionary<string, Assembly> loadedAssemblies = new Dictionary<string, Assembly>();
252 static bool CompareAssemblyName(string s1, string s2)
254 s1 = s1.ToLowerInvariant().Replace(" ", "");
255 s2 = s2.ToLowerInvariant().Replace(" ", "");
256 return s1 == s2;
259 static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
261 string[] lArgs = args.Name.Split(',');
262 string lName = lArgs[0].Trim();
263 if (loadedAssemblies.ContainsKey(args.Name))
265 return loadedAssemblies[args.Name];
267 for (int i = 0; i < privatePaths.Count; i++)
269 string sPath = Path.Combine(privatePaths[i].ToString(), lName);
270 if (File.Exists(sPath + ".dll"))
271 sPath += ".dll";
272 else if (File.Exists(sPath + ".DLL"))
273 sPath += ".DLL";
274 else if (File.Exists(sPath + ".exe"))
275 sPath += ".exe";
276 else if (File.Exists(sPath + ".EXE"))
277 sPath += ".EXE";
278 else
279 continue;
280 AssemblyName an2 = AssemblyName.GetAssemblyName(sPath);
281 if (CompareAssemblyName(an2.ToString(), args.Name) || (lArgs.Length == 1 && CompareAssemblyName(an2.Name, lName)))
283 Assembly asm;
286 asm = Assembly.LoadFrom(sPath);
288 catch
290 asm = Assembly.LoadFile(sPath);
292 if (asm != null)
294 loadedAssemblies.Add(args.Name, asm);
295 return asm;
299 throw new Exception("Unable to find assembly "+args.Name);