18
18
19
19
import java .io .BufferedInputStream ;
20
20
import java .io .BufferedWriter ;
21
- import java .io .ByteArrayInputStream ;
22
- import java .io .ByteArrayOutputStream ;
23
21
import java .io .IOException ;
24
22
import java .io .InputStream ;
25
23
import java .io .OutputStream ;
26
24
import java .io .OutputStreamWriter ;
27
25
import java .net .URL ;
28
26
import java .nio .charset .StandardCharsets ;
27
+ import java .security .MessageDigest ;
28
+ import java .security .NoSuchAlgorithmException ;
29
29
import java .util .Collection ;
30
30
import java .util .Enumeration ;
31
31
import java .util .HashSet ;
32
+ import java .util .HexFormat ;
32
33
import java .util .Set ;
33
34
import java .util .function .Function ;
34
35
import java .util .jar .JarEntry ;
40
41
41
42
import org .apache .commons .compress .archivers .jar .JarArchiveEntry ;
42
43
import org .apache .commons .compress .archivers .zip .UnixStat ;
44
+ import org .apache .commons .compress .archivers .zip .ZipArchiveEntry ;
43
45
44
46
/**
45
47
* Abstract base class for JAR writers.
@@ -97,20 +99,21 @@ final void writeEntries(JarFile jarFile, EntryTransformer entryTransformer, Unpa
97
99
98
100
private void writeEntry (JarFile jarFile , EntryTransformer entryTransformer , UnpackHandler unpackHandler ,
99
101
JarArchiveEntry entry , Library library ) throws IOException {
100
- setUpEntry (jarFile , entry );
102
+ setUpEntry (jarFile , entry , unpackHandler );
101
103
try (ZipHeaderPeekInputStream inputStream = new ZipHeaderPeekInputStream (jarFile .getInputStream (entry ))) {
102
104
EntryWriter entryWriter = new InputStreamEntryWriter (inputStream );
103
105
JarArchiveEntry transformedEntry = entryTransformer .transform (entry );
104
106
if (transformedEntry != null ) {
105
- writeEntry (transformedEntry , library , entryWriter , unpackHandler );
107
+ writeEntry (transformedEntry , library , entryWriter );
106
108
}
107
109
}
108
110
}
109
111
110
- private void setUpEntry (JarFile jarFile , JarArchiveEntry entry ) throws IOException {
112
+ private void setUpEntry (JarFile jarFile , JarArchiveEntry entry , UnpackHandler unpackHandler ) throws IOException {
111
113
try (ZipHeaderPeekInputStream inputStream = new ZipHeaderPeekInputStream (jarFile .getInputStream (entry ))) {
112
114
if (inputStream .hasZipHeader () && entry .getMethod () != ZipEntry .STORED ) {
113
- new CrcAndSize (inputStream ).setupStoredEntry (entry );
115
+ new StoredEntryPreparator (inputStream , unpackHandler .requiresUnpack (entry .getName ()))
116
+ .prepareStoredEntry (entry );
114
117
}
115
118
else {
116
119
entry .setCompressedSize (-1 );
@@ -151,9 +154,10 @@ public void writeEntry(String entryName, EntryWriter entryWriter) throws IOExcep
151
154
public void writeNestedLibrary (String location , Library library ) throws IOException {
152
155
JarArchiveEntry entry = new JarArchiveEntry (location + library .getName ());
153
156
entry .setTime (getNestedLibraryTime (library ));
154
- new CrcAndSize (library ::openStream ).setupStoredEntry (entry );
157
+ new StoredEntryPreparator (library .openStream (), new LibraryUnpackHandler (library ).requiresUnpack (location ))
158
+ .prepareStoredEntry (entry );
155
159
try (InputStream inputStream = library .openStream ()) {
156
- writeEntry (entry , library , new InputStreamEntryWriter (inputStream ), new LibraryUnpackHandler ( library ) );
160
+ writeEntry (entry , library , new InputStreamEntryWriter (inputStream ));
157
161
}
158
162
}
159
163
@@ -240,7 +244,7 @@ private boolean isServicesEntry(JarEntry entry) {
240
244
}
241
245
242
246
private void writeEntry (JarArchiveEntry entry , EntryWriter entryWriter ) throws IOException {
243
- writeEntry (entry , null , entryWriter , UnpackHandler . NEVER );
247
+ writeEntry (entry , null , entryWriter );
244
248
}
245
249
246
250
/**
@@ -249,11 +253,9 @@ private void writeEntry(JarArchiveEntry entry, EntryWriter entryWriter) throws I
249
253
* @param entry the entry to write
250
254
* @param library the library for the entry or {@code null}
251
255
* @param entryWriter the entry writer or {@code null} if there is no content
252
- * @param unpackHandler handles possible unpacking for the entry
253
256
* @throws IOException in case of I/O errors
254
257
*/
255
- private void writeEntry (JarArchiveEntry entry , Library library , EntryWriter entryWriter ,
256
- UnpackHandler unpackHandler ) throws IOException {
258
+ private void writeEntry (JarArchiveEntry entry , Library library , EntryWriter entryWriter ) throws IOException {
257
259
String name = entry .getName ();
258
260
if (this .writtenEntries .add (name )) {
259
261
writeParentDirectoryEntries (name );
@@ -263,7 +265,6 @@ private void writeEntry(JarArchiveEntry entry, Library library, EntryWriter entr
263
265
entryWriter = SizeCalculatingEntryWriter .get (entryWriter );
264
266
entry .setSize (entryWriter .size ());
265
267
}
266
- entryWriter = addUnpackCommentIfNecessary (entry , entryWriter , unpackHandler );
267
268
updateLayerIndex (entry , library );
268
269
writeToArchive (entry , entryWriter );
269
270
}
@@ -283,22 +284,11 @@ private void writeParentDirectoryEntries(String name) throws IOException {
283
284
while (parent .lastIndexOf ('/' ) != -1 ) {
284
285
parent = parent .substring (0 , parent .lastIndexOf ('/' ));
285
286
if (!parent .isEmpty ()) {
286
- writeEntry (new JarArchiveEntry (parent + "/" ), null , null , UnpackHandler . NEVER );
287
+ writeEntry (new JarArchiveEntry (parent + "/" ), null , null );
287
288
}
288
289
}
289
290
}
290
291
291
- private EntryWriter addUnpackCommentIfNecessary (JarArchiveEntry entry , EntryWriter entryWriter ,
292
- UnpackHandler unpackHandler ) throws IOException {
293
- if (entryWriter == null || !unpackHandler .requiresUnpack (entry .getName ())) {
294
- return entryWriter ;
295
- }
296
- ByteArrayOutputStream output = new ByteArrayOutputStream ();
297
- entryWriter .write (output );
298
- entry .setComment ("UNPACK:" + unpackHandler .sha1Hash (entry .getName ()));
299
- return new InputStreamEntryWriter (new ByteArrayInputStream (output .toByteArray ()));
300
- }
301
-
302
292
/**
303
293
* {@link EntryWriter} that writes content from an {@link InputStream}.
304
294
*/
@@ -323,38 +313,55 @@ public void write(OutputStream outputStream) throws IOException {
323
313
}
324
314
325
315
/**
326
- * Data holder for CRC and Size.
316
+ * Prepares a {@link ZipEntry#STORED stored} {@link ZipArchiveEntry entry} with CRC
317
+ * and size information. Also adds an {@code UNPACK} comment, if needed.
327
318
*/
328
- private static class CrcAndSize {
319
+ private static class StoredEntryPreparator {
320
+
321
+ private static final int BUFFER_SIZE = 32 * 1024 ;
322
+
323
+ private final MessageDigest messageDigest ;
329
324
330
325
private final CRC32 crc = new CRC32 ();
331
326
332
327
private long size ;
333
328
334
- CrcAndSize (InputStreamSupplier supplier ) throws IOException {
335
- try (InputStream inputStream = supplier .openStream ()) {
329
+ StoredEntryPreparator (InputStream inputStream , boolean unpack ) throws IOException {
330
+ this .messageDigest = (unpack ) ? sha1Digest () : null ;
331
+ try (inputStream ) {
336
332
load (inputStream );
337
333
}
338
334
}
339
335
340
- CrcAndSize (InputStream inputStream ) throws IOException {
341
- load (inputStream );
336
+ private static MessageDigest sha1Digest () {
337
+ try {
338
+ return MessageDigest .getInstance ("SHA-1" );
339
+ }
340
+ catch (NoSuchAlgorithmException ex ) {
341
+ throw new IllegalStateException (ex );
342
+ }
342
343
}
343
344
344
345
private void load (InputStream inputStream ) throws IOException {
345
346
byte [] buffer = new byte [BUFFER_SIZE ];
346
347
int bytesRead ;
347
348
while ((bytesRead = inputStream .read (buffer )) != -1 ) {
348
349
this .crc .update (buffer , 0 , bytesRead );
350
+ if (this .messageDigest != null ) {
351
+ this .messageDigest .update (buffer , 0 , bytesRead );
352
+ }
349
353
this .size += bytesRead ;
350
354
}
351
355
}
352
356
353
- void setupStoredEntry ( JarArchiveEntry entry ) {
357
+ void prepareStoredEntry ( ZipArchiveEntry entry ) {
354
358
entry .setSize (this .size );
355
359
entry .setCompressedSize (this .size );
356
360
entry .setCrc (this .crc .getValue ());
357
361
entry .setMethod (ZipEntry .STORED );
362
+ if (this .messageDigest != null ) {
363
+ entry .setComment ("UNPACK:" + HexFormat .of ().formatHex (this .messageDigest .digest ()));
364
+ }
358
365
}
359
366
360
367
}
@@ -381,24 +388,10 @@ interface EntryTransformer {
381
388
*/
382
389
interface UnpackHandler {
383
390
384
- UnpackHandler NEVER = new UnpackHandler () {
385
-
386
- @ Override
387
- public boolean requiresUnpack (String name ) {
388
- return false ;
389
- }
390
-
391
- @ Override
392
- public String sha1Hash (String name ) throws IOException {
393
- throw new UnsupportedOperationException ();
394
- }
395
-
396
- };
391
+ UnpackHandler NEVER = (name ) -> false ;
397
392
398
393
boolean requiresUnpack (String name );
399
394
400
- String sha1Hash (String name ) throws IOException ;
401
-
402
395
}
403
396
404
397
/**
@@ -417,11 +410,6 @@ public boolean requiresUnpack(String name) {
417
410
return this .library .isUnpackRequired ();
418
411
}
419
412
420
- @ Override
421
- public String sha1Hash (String name ) throws IOException {
422
- return Digest .sha1 (this .library ::openStream );
423
- }
424
-
425
413
}
426
414
427
415
}
0 commit comments