Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/tools/jar/Manifest.java
38918 views
1
/*
2
* Copyright (c) 1996, 2013, 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 sun.tools.jar;
27
28
import java.io.*;
29
import java.util.*;
30
import java.security.*;
31
32
import sun.net.www.MessageHeader;
33
import java.util.Base64;
34
35
/**
36
* This is OBSOLETE. DO NOT USE THIS. Use java.util.jar.Manifest
37
* instead. It has to stay here because some apps (namely HJ and HJV)
38
* call directly into it.
39
*
40
* @author David Brown
41
* @author Benjamin Renaud
42
*/
43
44
public class Manifest {
45
46
/* list of headers that all pertain to a particular
47
* file in the archive
48
*/
49
private Vector<MessageHeader> entries = new Vector<>();
50
private byte[] tmpbuf = new byte[512];
51
/* a hashtable of entries, for fast lookup */
52
private Hashtable<String, MessageHeader> tableEntries = new Hashtable<>();
53
54
static final String[] hashes = {"SHA"};
55
static final byte[] EOL = {(byte)'\r', (byte)'\n'};
56
57
static final boolean debug = false;
58
static final String VERSION = "1.0";
59
static final void debug(String s) {
60
if (debug)
61
System.out.println("man> " + s);
62
}
63
64
public Manifest() {}
65
66
public Manifest(byte[] bytes) throws IOException {
67
this(new ByteArrayInputStream(bytes), false);
68
}
69
70
public Manifest(InputStream is) throws IOException {
71
this(is, true);
72
}
73
74
/**
75
* Parse a manifest from a stream, optionally computing hashes
76
* for the files.
77
*/
78
public Manifest(InputStream is, boolean compute) throws IOException {
79
if (!is.markSupported()) {
80
is = new BufferedInputStream(is);
81
}
82
/* do not rely on available() here! */
83
while (true) {
84
is.mark(1);
85
if (is.read() == -1) { // EOF
86
break;
87
}
88
is.reset();
89
MessageHeader m = new MessageHeader(is);
90
if (compute) {
91
doHashes(m);
92
}
93
addEntry(m);
94
}
95
}
96
97
/* recursively generate manifests from directory tree */
98
public Manifest(String[] files) throws IOException {
99
MessageHeader globals = new MessageHeader();
100
globals.add("Manifest-Version", VERSION);
101
String jdkVersion = System.getProperty("java.version");
102
globals.add("Created-By", "Manifest JDK "+jdkVersion);
103
addEntry(globals);
104
addFiles(null, files);
105
}
106
107
public void addEntry(MessageHeader entry) {
108
entries.addElement(entry);
109
String name = entry.findValue("Name");
110
debug("addEntry for name: "+name);
111
if (name != null) {
112
tableEntries.put(name, entry);
113
}
114
}
115
116
public MessageHeader getEntry(String name) {
117
return tableEntries.get(name);
118
}
119
120
public MessageHeader entryAt(int i) {
121
return entries.elementAt(i);
122
}
123
124
public Enumeration<MessageHeader> entries() {
125
return entries.elements();
126
}
127
128
public void addFiles(File dir, String[] files) throws IOException {
129
if (files == null)
130
return;
131
for (int i = 0; i < files.length; i++) {
132
File file;
133
if (dir == null) {
134
file = new File(files[i]);
135
} else {
136
file = new File(dir, files[i]);
137
}
138
if (file.isDirectory()) {
139
addFiles(file, file.list());
140
} else {
141
addFile(file);
142
}
143
}
144
}
145
146
/**
147
* File names are represented internally using "/";
148
* they are converted to the local format for anything else
149
*/
150
151
private final String stdToLocal(String name) {
152
return name.replace('/', java.io.File.separatorChar);
153
}
154
155
private final String localToStd(String name) {
156
name = name.replace(java.io.File.separatorChar, '/');
157
if (name.startsWith("./"))
158
name = name.substring(2);
159
else if (name.startsWith("/"))
160
name = name.substring(1);
161
return name;
162
}
163
164
public void addFile(File f) throws IOException {
165
String stdName = localToStd(f.getPath());
166
if (tableEntries.get(stdName) == null) {
167
MessageHeader mh = new MessageHeader();
168
mh.add("Name", stdName);
169
addEntry(mh);
170
}
171
}
172
173
public void doHashes(MessageHeader mh) throws IOException {
174
// If unnamed or is a directory return immediately
175
String name = mh.findValue("Name");
176
if (name == null || name.endsWith("/")) {
177
return;
178
}
179
180
181
/* compute hashes, write over any other "Hash-Algorithms" (?) */
182
for (int j = 0; j < hashes.length; ++j) {
183
InputStream is = new FileInputStream(stdToLocal(name));
184
try {
185
MessageDigest dig = MessageDigest.getInstance(hashes[j]);
186
187
int len;
188
while ((len = is.read(tmpbuf, 0, tmpbuf.length)) != -1) {
189
dig.update(tmpbuf, 0, len);
190
}
191
mh.set(hashes[j] + "-Digest", Base64.getMimeEncoder().encodeToString(dig.digest()));
192
} catch (NoSuchAlgorithmException e) {
193
throw new JarException("Digest algorithm " + hashes[j] +
194
" not available.");
195
} finally {
196
is.close();
197
}
198
}
199
}
200
201
/* Add a manifest file at current position in a stream
202
*/
203
public void stream(OutputStream os) throws IOException {
204
205
PrintStream ps;
206
if (os instanceof PrintStream) {
207
ps = (PrintStream) os;
208
} else {
209
ps = new PrintStream(os);
210
}
211
212
/* the first header in the file should be the global one.
213
* It should say "Manifest-Version: x.x"; if not add it
214
*/
215
MessageHeader globals = entries.elementAt(0);
216
217
if (globals.findValue("Manifest-Version") == null) {
218
/* Assume this is a user-defined manifest. If it has a Name: <..>
219
* field, then it is not global, in which case we just add our own
220
* global Manifest-version: <version>
221
* If the first MessageHeader has no Name: <..>, we assume it
222
* is a global header and so prepend Manifest to it.
223
*/
224
String jdkVersion = System.getProperty("java.version");
225
226
if (globals.findValue("Name") == null) {
227
globals.prepend("Manifest-Version", VERSION);
228
globals.add("Created-By", "Manifest JDK "+jdkVersion);
229
} else {
230
ps.print("Manifest-Version: "+VERSION+"\r\n"+
231
"Created-By: "+jdkVersion+"\r\n\r\n");
232
}
233
ps.flush();
234
}
235
236
globals.print(ps);
237
238
for (int i = 1; i < entries.size(); ++i) {
239
MessageHeader mh = entries.elementAt(i);
240
mh.print(ps);
241
}
242
}
243
244
public static boolean isManifestName(String name) {
245
246
// remove leading /
247
if (name.charAt(0) == '/') {
248
name = name.substring(1, name.length());
249
}
250
// case insensitive
251
name = name.toUpperCase();
252
253
if (name.equals("META-INF/MANIFEST.MF")) {
254
return true;
255
}
256
return false;
257
}
258
}
259
260