Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java
41159 views
1
/*
2
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package jdk.internal.module;
27
28
import java.io.IOException;
29
import java.io.InputStream;
30
import java.io.UncheckedIOException;
31
import java.lang.module.ModuleReader;
32
import java.lang.module.ModuleReference;
33
import java.nio.charset.StandardCharsets;
34
import java.security.MessageDigest;
35
import java.security.NoSuchAlgorithmException;
36
import java.util.Arrays;
37
import java.util.Collections;
38
import java.util.HashMap;
39
import java.util.Map;
40
import java.util.Objects;
41
import java.util.Set;
42
import java.util.TreeMap;
43
import java.util.function.Supplier;
44
45
/**
46
* The result of hashing the contents of a number of module artifacts.
47
*/
48
49
public final class ModuleHashes {
50
51
/**
52
* A supplier of a message digest.
53
*/
54
public static interface HashSupplier {
55
byte[] generate(String algorithm);
56
}
57
58
private final String algorithm;
59
private final Map<String, byte[]> nameToHash;
60
61
/**
62
* Creates a {@code ModuleHashes}.
63
*
64
* @param algorithm the algorithm used to create the hashes
65
* @param nameToHash the map of module name to hash value
66
*/
67
ModuleHashes(String algorithm, Map<String, byte[]> nameToHash) {
68
this.algorithm = Objects.requireNonNull(algorithm);
69
this.nameToHash = Collections.unmodifiableMap(nameToHash);
70
}
71
72
/**
73
* Returns the algorithm used to hash the modules ("SHA-256" for example).
74
*/
75
public String algorithm() {
76
return algorithm;
77
}
78
79
/**
80
* Returns the set of module names for which hashes are recorded.
81
*/
82
public Set<String> names() {
83
return nameToHash.keySet();
84
}
85
86
/**
87
* Returns the hash for the given module name, {@code null}
88
* if there is no hash recorded for the module.
89
*/
90
public byte[] hashFor(String mn) {
91
return nameToHash.get(mn);
92
}
93
94
/**
95
* Returns unmodifiable map of module name to hash
96
*/
97
public Map<String, byte[]> hashes() {
98
return nameToHash;
99
}
100
101
/**
102
* Computes a hash from the names and content of a module.
103
*
104
* @param reader the module reader to access the module content
105
* @param algorithm the name of the message digest algorithm to use
106
* @return the hash
107
* @throws IllegalArgumentException if digest algorithm is not supported
108
* @throws UncheckedIOException if an I/O error occurs
109
*/
110
private static byte[] computeHash(ModuleReader reader, String algorithm) {
111
MessageDigest md;
112
try {
113
md = MessageDigest.getInstance(algorithm);
114
} catch (NoSuchAlgorithmException e) {
115
throw new IllegalArgumentException(e);
116
}
117
try {
118
byte[] buf = new byte[32*1024];
119
reader.list().sorted().forEach(rn -> {
120
md.update(rn.getBytes(StandardCharsets.UTF_8));
121
try (InputStream in = reader.open(rn).orElseThrow()) {
122
int n;
123
while ((n = in.read(buf)) > 0) {
124
md.update(buf, 0, n);
125
}
126
} catch (IOException ioe) {
127
throw new UncheckedIOException(ioe);
128
}
129
});
130
} catch (IOException ioe) {
131
throw new UncheckedIOException(ioe);
132
}
133
return md.digest();
134
}
135
136
/**
137
* Computes a hash from the names and content of a module.
138
*
139
* @param supplier supplies the module reader to access the module content
140
* @param algorithm the name of the message digest algorithm to use
141
* @return the hash
142
* @throws IllegalArgumentException if digest algorithm is not supported
143
* @throws UncheckedIOException if an I/O error occurs
144
*/
145
static byte[] computeHash(Supplier<ModuleReader> supplier, String algorithm) {
146
try (ModuleReader reader = supplier.get()) {
147
return computeHash(reader, algorithm);
148
} catch (IOException ioe) {
149
throw new UncheckedIOException(ioe);
150
}
151
}
152
153
/**
154
* Computes the hash from the names and content of a set of modules. Returns
155
* a {@code ModuleHashes} to encapsulate the result.
156
*
157
* @param mrefs the set of modules
158
* @param algorithm the name of the message digest algorithm to use
159
* @return ModuleHashes that encapsulates the hashes
160
* @throws IllegalArgumentException if digest algorithm is not supported
161
* @throws UncheckedIOException if an I/O error occurs
162
*/
163
static ModuleHashes generate(Set<ModuleReference> mrefs, String algorithm) {
164
Map<String, byte[]> nameToHash = new TreeMap<>();
165
for (ModuleReference mref : mrefs) {
166
try (ModuleReader reader = mref.open()) {
167
byte[] hash = computeHash(reader, algorithm);
168
nameToHash.put(mref.descriptor().name(), hash);
169
} catch (IOException ioe) {
170
throw new UncheckedIOException(ioe);
171
}
172
}
173
return new ModuleHashes(algorithm, nameToHash);
174
}
175
176
@Override
177
public int hashCode() {
178
int h = algorithm.hashCode();
179
for (Map.Entry<String, byte[]> e : nameToHash.entrySet()) {
180
h = h * 31 + e.getKey().hashCode();
181
h = h * 31 + Arrays.hashCode(e.getValue());
182
}
183
return h;
184
}
185
186
@Override
187
public boolean equals(Object obj) {
188
if (!(obj instanceof ModuleHashes))
189
return false;
190
ModuleHashes other = (ModuleHashes) obj;
191
if (!algorithm.equals(other.algorithm)
192
|| nameToHash.size() != other.nameToHash.size())
193
return false;
194
for (Map.Entry<String, byte[]> e : nameToHash.entrySet()) {
195
String name = e.getKey();
196
byte[] hash = e.getValue();
197
if (!Arrays.equals(hash, other.nameToHash.get(name)))
198
return false;
199
}
200
return true;
201
}
202
203
@Override
204
public String toString() {
205
StringBuilder sb = new StringBuilder(algorithm);
206
sb.append(" ");
207
nameToHash.entrySet()
208
.stream()
209
.sorted(Map.Entry.comparingByKey())
210
.forEach(e -> {
211
sb.append(e.getKey());
212
sb.append("=");
213
byte[] ba = e.getValue();
214
for (byte b : ba) {
215
sb.append(String.format("%02x", b & 0xff));
216
}
217
});
218
return sb.toString();
219
}
220
221
/**
222
* This is used by jdk.internal.module.SystemModules class
223
* generated at link time.
224
*/
225
public static class Builder {
226
final String algorithm;
227
final Map<String, byte[]> nameToHash;
228
229
Builder(String algorithm, int initialCapacity) {
230
this.nameToHash = new HashMap<>(initialCapacity);
231
this.algorithm = Objects.requireNonNull(algorithm);
232
}
233
234
/**
235
* Sets the module hash for the given module name
236
*/
237
public Builder hashForModule(String mn, byte[] hash) {
238
nameToHash.put(mn, hash);
239
return this;
240
}
241
242
/**
243
* Builds a {@code ModuleHashes}.
244
*/
245
public ModuleHashes build() {
246
if (!nameToHash.isEmpty()) {
247
return new ModuleHashes(algorithm, nameToHash);
248
} else {
249
return null;
250
}
251
}
252
}
253
}
254
255