Merge pull request #4234 from kumpera/katia-flavia
[mono.git] / tools / nuget-hash-extractor / nuget-hash-extractor.cs
1 using System;
2 using System.Xml.Linq;
3 using System.Linq;
4 using System.IO;
5 using System.IO.Compression;
6 using System.Reflection;
7
8 class Driver {
9         static ZipArchiveEntry FindSpecFile (ZipArchive zip) {
10                 foreach (var entry in zip.Entries) {
11                         if (entry.Name.EndsWith (".nuspec"))
12                                 return entry;
13                 }
14                 throw new Exception ("Could not find nuspec file");
15         }
16
17         static void DumpNuget (string nupkg) {
18                 var zip = new ZipArchive(new FileStream (nupkg, FileMode.Open));
19
20                 var nuspec = FindSpecFile (zip);
21                 var l = XElement.Load (new StreamReader (nuspec.Open ()));
22                 var version = (from el in l.Descendants() where el.Name.LocalName == "version" select el.Value).FirstOrDefault ();
23
24                 foreach (var et in from e in zip.Entries where (e.FullName.StartsWith ("lib/net4") || e.FullName.StartsWith ("lib/netcore")) && e.Name.EndsWith (".dll") select e) {
25                         LoadAndDump (et, version);
26                 }
27         }
28         static void Main (string[] args) {
29                 foreach (var f in Directory.GetFiles (args [0], "*.nupkg")) {
30                         DumpNuget (f);
31                 }
32         }
33
34         static byte[] StreamToArray (Stream s) {
35                 using(var ms = new MemoryStream ()) {
36                         s.CopyTo (ms);
37                         return ms.ToArray ();
38                 }
39         }
40
41         static int domain_id = 1;
42         static void LoadAndDump (ZipArchiveEntry entry, string version) {
43                 // Console.WriteLine ("Dumping {0}", entry);
44                 var data = StreamToArray (entry.Open ());
45                 AppDomain ad = AppDomain.CreateDomain ("parse_" + ++domain_id);
46                 DoParse p = (DoParse)ad.CreateInstanceAndUnwrap (typeof (DoParse).Assembly.FullName, typeof (DoParse).FullName);
47                 p.ParseAssembly (data, version, entry.Name, entry.FullName);
48                 AppDomain.Unload (ad);
49         }
50 }
51
52 class DoParse : MarshalByRefObject {
53         static int Hash (string str) {
54                 int h = 5381;
55         for (int i = 0;  i < str.Length; ++i)
56             h = ((h << 5) + h) ^ str[i];
57                 return h;
58         }
59         static string FileToEnum (string name) {
60                 switch (name) {
61                 case "System.Runtime.InteropServices.RuntimeInformation.dll": return "SYS_RT_INTEROP_RUNTIME_INFO";
62                 case "System.Globalization.Extensions.dll": return "SYS_GLOBALIZATION_EXT";
63                 case "System.IO.Compression.dll": return "SYS_IO_COMPRESSION";
64                 case "System.Net.Http.dll": return "SYS_NET_HTTP";
65                 case "System.Text.Encoding.CodePages.dll": return "SYS_TEXT_ENC_CODEPAGES";
66                 default: throw new Exception ($"No idea what to do with {name}");
67                 }
68         }
69
70         static string FileToMoniker (string p) {
71                 var parts = p.Split (Path.DirectorySeparatorChar);
72                 return parts[parts.Length - 2];
73         }
74
75         public void ParseAssembly (byte[] data, string version, string name, string fullname) {
76                 var a = Assembly.ReflectionOnlyLoad (data);
77                 var m = a.GetModules ()[0];
78                 var id = m.ModuleVersionId.ToString ().ToUpper ();
79                 var hash_code = Hash (id).ToString ("X");
80                 var str = FileToEnum (name);
81
82                 string ver_str = version + " " + FileToMoniker (fullname);      
83                 Console.WriteLine ($"IGNORED_ASSEMBLY (0x{hash_code}, {str}, \"{id}\", \"{ver_str}\"),");
84         }
85 }