IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
JarFileUtil.cs
Go to the documentation of this file.
1using System;
2using System.IO;
3using System.Text.RegularExpressions;
4
7
8namespace IKVM.Util.Jar
9{
10
14 internal static class JarFileUtil
15 {
16
20 public class ModuleInfo
21 {
22
26 public ModuleInfo()
27 {
28
29 }
30
36 public ModuleInfo(string name, ModuleVersion version)
37 {
38 Name = name;
39 Version = version;
40 }
41
45 public string Name { get; set; }
46
50 public ModuleVersion Version { get; set; }
51
52 }
53
62 public static ModuleInfo GetModuleInfo(string path)
63 {
64 if (path is null)
65 throw new ArgumentNullException(nameof(path));
66 if (path.EndsWith(".jar", StringComparison.OrdinalIgnoreCase) == false)
67 throw new ArgumentException("Path must refer to a JAR file.", nameof(path));
68 if (File.Exists(path) == false)
69 throw new FileNotFoundException("Cannot find JAR file.", path);
70
71 using var jar = new JarFile(path, JarFile.RUNTIME_VERSION);
72 var info = jar.GetModuleInfo() ?? new ModuleInfo();
73 if (info.Name is null || info.Version.IsValid == false)
74 {
75 var fromFileName = GetModuleNameAndVersionFromFileName(path);
76 if (info.Name is null && fromFileName.Name is not null)
77 info.Name = fromFileName.Name;
78 if (info.Version.IsValid == false && fromFileName.Version.IsValid)
79 info.Version = fromFileName.Version;
80 }
81
82 return info;
83 }
84
90 static ModuleInfo GetModuleNameAndVersionFromFileName(string name)
91 {
92 var info = new ModuleInfo();
93
94 // The ".jar" suffix is removed.
95 name = Path.GetFileNameWithoutExtension(name);
96 var span = (Span<char>)stackalloc char[name.Length];
97 name.AsSpan().CopyTo(span);
98
99 // If the name matches the regular expression "-(\\d+(\\.|$))" then the module name will be derived from the subsequence preceding the hyphen of the first occurrence.
100 if (Regex.Match(name, @"-(\d+(\.|$))") is Match m)
101 {
102 info.Version = TryParseVersion(span.Slice(m.Index + 1));
103 span = span.Slice(0, m.Index);
104 }
105
106 // All non-alphanumeric characters ([^A-Za-z0-9]) in the module name are replaced with a dot ("."),
107 for (var i = 0; i < span.Length; i++)
108 if (char.IsLetterOrDigit(span[i]) == false)
109 span[i] = '.';
110
111 // all repeating dots are replaced with one dot,
112 name = span.ToString();
113 while (name.IndexOf("..") is int i && i != -1)
114 name = name.Remove(i, 1);
115
116 // and all leading and trailing dots are removed.
117 info.Name = name.Trim('.');
118
119 return info;
120 }
121
127 static ModuleVersion TryParseVersion(ReadOnlySpan<char> span)
128 {
129 return ModuleVersion.TryParse(span, out var v) ? v : default;
130 }
131
132 }
133
134}
global::java.lang.invoke.LambdaForm.Name Name
ModuleInfo(string name, ModuleVersion version)
Initializes a new instance.
ModuleInfo()
Initializes a new instance.
ModuleVersion Version
Version of the module.