1818
1919import java .io .BufferedInputStream ;
2020import java .io .BufferedWriter ;
21- import java .io .ByteArrayInputStream ;
22- import java .io .ByteArrayOutputStream ;
2321import java .io .IOException ;
2422import java .io .InputStream ;
2523import java .io .OutputStream ;
2624import java .io .OutputStreamWriter ;
2725import java .net .URL ;
2826import java .nio .charset .StandardCharsets ;
27+ import java .security .MessageDigest ;
28+ import java .security .NoSuchAlgorithmException ;
2929import java .util .Collection ;
3030import java .util .Enumeration ;
3131import java .util .HashSet ;
32+ import java .util .HexFormat ;
3233import java .util .Set ;
3334import java .util .function .Function ;
3435import java .util .jar .JarEntry ;
4041
4142import org .apache .commons .compress .archivers .jar .JarArchiveEntry ;
4243import org .apache .commons .compress .archivers .zip .UnixStat ;
44+ import org .apache .commons .compress .archivers .zip .ZipArchiveEntry ;
4345
4446/**
4547 * Abstract base class for JAR writers.
@@ -97,20 +99,21 @@ final void writeEntries(JarFile jarFile, EntryTransformer entryTransformer, Unpa
9799
98100 private void writeEntry (JarFile jarFile , EntryTransformer entryTransformer , UnpackHandler unpackHandler ,
99101 JarArchiveEntry entry , Library library ) throws IOException {
100- setUpEntry (jarFile , entry );
102+ setUpEntry (jarFile , entry , unpackHandler );
101103 try (ZipHeaderPeekInputStream inputStream = new ZipHeaderPeekInputStream (jarFile .getInputStream (entry ))) {
102104 EntryWriter entryWriter = new InputStreamEntryWriter (inputStream );
103105 JarArchiveEntry transformedEntry = entryTransformer .transform (entry );
104106 if (transformedEntry != null ) {
105- writeEntry (transformedEntry , library , entryWriter , unpackHandler );
107+ writeEntry (transformedEntry , library , entryWriter );
106108 }
107109 }
108110 }
109111
110- private void setUpEntry (JarFile jarFile , JarArchiveEntry entry ) throws IOException {
112+ private void setUpEntry (JarFile jarFile , JarArchiveEntry entry , UnpackHandler unpackHandler ) throws IOException {
111113 try (ZipHeaderPeekInputStream inputStream = new ZipHeaderPeekInputStream (jarFile .getInputStream (entry ))) {
112114 if (inputStream .hasZipHeader () && entry .getMethod () != ZipEntry .STORED ) {
113- new CrcAndSize (inputStream ).setupStoredEntry (entry );
115+ new StoredEntryPreparator (inputStream , unpackHandler .requiresUnpack (entry .getName ()))
116+ .prepareStoredEntry (entry );
114117 }
115118 else {
116119 entry .setCompressedSize (-1 );
@@ -151,9 +154,10 @@ public void writeEntry(String entryName, EntryWriter entryWriter) throws IOExcep
151154 public void writeNestedLibrary (String location , Library library ) throws IOException {
152155 JarArchiveEntry entry = new JarArchiveEntry (location + library .getName ());
153156 entry .setTime (getNestedLibraryTime (library ));
154- new CrcAndSize (library ::openStream ).setupStoredEntry (entry );
157+ new StoredEntryPreparator (library .openStream (), new LibraryUnpackHandler (library ).requiresUnpack (location ))
158+ .prepareStoredEntry (entry );
155159 try (InputStream inputStream = library .openStream ()) {
156- writeEntry (entry , library , new InputStreamEntryWriter (inputStream ), new LibraryUnpackHandler ( library ) );
160+ writeEntry (entry , library , new InputStreamEntryWriter (inputStream ));
157161 }
158162 }
159163
@@ -240,7 +244,7 @@ private boolean isServicesEntry(JarEntry entry) {
240244 }
241245
242246 private void writeEntry (JarArchiveEntry entry , EntryWriter entryWriter ) throws IOException {
243- writeEntry (entry , null , entryWriter , UnpackHandler . NEVER );
247+ writeEntry (entry , null , entryWriter );
244248 }
245249
246250 /**
@@ -249,11 +253,9 @@ private void writeEntry(JarArchiveEntry entry, EntryWriter entryWriter) throws I
249253 * @param entry the entry to write
250254 * @param library the library for the entry or {@code null}
251255 * @param entryWriter the entry writer or {@code null} if there is no content
252- * @param unpackHandler handles possible unpacking for the entry
253256 * @throws IOException in case of I/O errors
254257 */
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 {
257259 String name = entry .getName ();
258260 if (this .writtenEntries .add (name )) {
259261 writeParentDirectoryEntries (name );
@@ -263,7 +265,6 @@ private void writeEntry(JarArchiveEntry entry, Library library, EntryWriter entr
263265 entryWriter = SizeCalculatingEntryWriter .get (entryWriter );
264266 entry .setSize (entryWriter .size ());
265267 }
266- entryWriter = addUnpackCommentIfNecessary (entry , entryWriter , unpackHandler );
267268 updateLayerIndex (entry , library );
268269 writeToArchive (entry , entryWriter );
269270 }
@@ -283,22 +284,11 @@ private void writeParentDirectoryEntries(String name) throws IOException {
283284 while (parent .lastIndexOf ('/' ) != -1 ) {
284285 parent = parent .substring (0 , parent .lastIndexOf ('/' ));
285286 if (!parent .isEmpty ()) {
286- writeEntry (new JarArchiveEntry (parent + "/" ), null , null , UnpackHandler . NEVER );
287+ writeEntry (new JarArchiveEntry (parent + "/" ), null , null );
287288 }
288289 }
289290 }
290291
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-
302292 /**
303293 * {@link EntryWriter} that writes content from an {@link InputStream}.
304294 */
@@ -323,38 +313,55 @@ public void write(OutputStream outputStream) throws IOException {
323313 }
324314
325315 /**
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.
327318 */
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 ;
329324
330325 private final CRC32 crc = new CRC32 ();
331326
332327 private long size ;
333328
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 ) {
336332 load (inputStream );
337333 }
338334 }
339335
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+ }
342343 }
343344
344345 private void load (InputStream inputStream ) throws IOException {
345346 byte [] buffer = new byte [BUFFER_SIZE ];
346347 int bytesRead ;
347348 while ((bytesRead = inputStream .read (buffer )) != -1 ) {
348349 this .crc .update (buffer , 0 , bytesRead );
350+ if (this .messageDigest != null ) {
351+ this .messageDigest .update (buffer , 0 , bytesRead );
352+ }
349353 this .size += bytesRead ;
350354 }
351355 }
352356
353- void setupStoredEntry ( JarArchiveEntry entry ) {
357+ void prepareStoredEntry ( ZipArchiveEntry entry ) {
354358 entry .setSize (this .size );
355359 entry .setCompressedSize (this .size );
356360 entry .setCrc (this .crc .getValue ());
357361 entry .setMethod (ZipEntry .STORED );
362+ if (this .messageDigest != null ) {
363+ entry .setComment ("UNPACK:" + HexFormat .of ().formatHex (this .messageDigest .digest ()));
364+ }
358365 }
359366
360367 }
@@ -381,24 +388,10 @@ interface EntryTransformer {
381388 */
382389 interface UnpackHandler {
383390
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 ;
397392
398393 boolean requiresUnpack (String name );
399394
400- String sha1Hash (String name ) throws IOException ;
401-
402395 }
403396
404397 /**
@@ -417,11 +410,6 @@ public boolean requiresUnpack(String name) {
417410 return this .library .isUnpackRequired ();
418411 }
419412
420- @ Override
421- public String sha1Hash (String name ) throws IOException {
422- return Digest .sha1 (this .library ::openStream );
423- }
424-
425413 }
426414
427415}
0 commit comments