diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/archive/JarFileArchive.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/archive/JarFileArchive.java
index a136897e12..a304503843 100755
--- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/archive/JarFileArchive.java
+++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/archive/JarFileArchive.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2016 the original author or authors.
+ * Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -100,8 +100,14 @@ public class JarFileArchive implements Archive {
if (jarEntry.getComment().startsWith(UNPACK_MARKER)) {
return getUnpackedNestedArchive(jarEntry);
}
- JarFile jarFile = this.jarFile.getNestedJarFile(jarEntry);
- return new JarFileArchive(jarFile);
+ try {
+ JarFile jarFile = this.jarFile.getNestedJarFile(jarEntry);
+ return new JarFileArchive(jarFile);
+ }
+ catch (Exception ex) {
+ throw new IllegalStateException(
+ "Failed to get nested archive for entry " + entry.getName(), ex);
+ }
}
private Archive getUnpackedNestedArchive(JarEntry jarEntry) throws IOException {
diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/CentralDirectoryEndRecord.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/CentralDirectoryEndRecord.java
index 04fd941088..d30140d579 100644
--- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/CentralDirectoryEndRecord.java
+++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/CentralDirectoryEndRecord.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2015 the original author or authors.
+ * Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@ import org.springframework.boot.loader.data.RandomAccessData;
* A ZIP File "End of central directory record" (EOCD).
*
* @author Phillip Webb
+ * @author Andy Wilkinson
* @see Zip File Format
*/
class CentralDirectoryEndRecord {
@@ -118,7 +119,11 @@ class CentralDirectoryEndRecord {
* @return the number of records in the zip
*/
public int getNumberOfRecords() {
- return (int) Bytes.littleEndianValue(this.block, this.offset + 10, 2);
+ long numberOfRecords = Bytes.littleEndianValue(this.block, this.offset + 10, 2);
+ if (numberOfRecords == 0xFFFF) {
+ throw new IllegalStateException("Zip64 archives are not supported");
+ }
+ return (int) numberOfRecords;
}
}
diff --git a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/archive/JarFileArchiveTests.java b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/archive/JarFileArchiveTests.java
index ac7756d6d8..7474965874 100755
--- a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/archive/JarFileArchiveTests.java
+++ b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/archive/JarFileArchiveTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2016 the original author or authors.
+ * Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,20 +16,30 @@
package org.springframework.boot.loader.archive;
+import java.io.ByteArrayOutputStream;
import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import java.util.zip.CRC32;
+import java.util.zip.ZipEntry;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.springframework.boot.loader.TestJarCreator;
import org.springframework.boot.loader.archive.Archive.Entry;
+import org.springframework.util.FileCopyUtils;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.hamcrest.CoreMatchers.equalTo;
/**
* Tests for {@link JarFileArchive}.
@@ -42,6 +52,9 @@ public class JarFileArchiveTests {
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
private File rootJarFile;
private JarFileArchive archive;
@@ -120,6 +133,48 @@ public class JarFileArchiveTests {
assertThat(nested.getParent()).isEqualTo(anotherNested.getParent());
}
+ @Test
+ public void zip64ArchivesAreHandledGracefully() throws IOException {
+ File file = this.temporaryFolder.newFile("test.jar");
+ FileCopyUtils.copy(writeZip64Jar(), file);
+ this.thrown.expectMessage(equalTo("Zip64 archives are not supported"));
+ new JarFileArchive(file);
+ }
+
+ @Test
+ public void nestedZip64ArchivesAreHandledGracefully() throws IOException {
+ File file = this.temporaryFolder.newFile("test.jar");
+ JarOutputStream output = new JarOutputStream(new FileOutputStream(file));
+ JarEntry zip64JarEntry = new JarEntry("nested/zip64.jar");
+ output.putNextEntry(zip64JarEntry);
+ byte[] zip64JarData = writeZip64Jar();
+ zip64JarEntry.setSize(zip64JarData.length);
+ zip64JarEntry.setCompressedSize(zip64JarData.length);
+ zip64JarEntry.setMethod(ZipEntry.STORED);
+ CRC32 crc32 = new CRC32();
+ crc32.update(zip64JarData);
+ zip64JarEntry.setCrc(crc32.getValue());
+ output.write(zip64JarData);
+ output.closeEntry();
+ output.close();
+ JarFileArchive jarFileArchive = new JarFileArchive(file);
+ this.thrown.expectMessage(
+ equalTo("Failed to get nested archive for entry nested/zip64.jar"));
+ jarFileArchive
+ .getNestedArchive(getEntriesMap(jarFileArchive).get("nested/zip64.jar"));
+ }
+
+ private byte[] writeZip64Jar() throws IOException {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ JarOutputStream jarOutput = new JarOutputStream(bytes);
+ for (int i = 0; i < 65537; i++) {
+ jarOutput.putNextEntry(new JarEntry(i + ".dat"));
+ jarOutput.closeEntry();
+ }
+ jarOutput.close();
+ return bytes.toByteArray();
+ }
+
private Map getEntriesMap(Archive archive) {
Map entries = new HashMap();
for (Archive.Entry entry : archive) {