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