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 b3c40eb5992..748aa9ce55d 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 @@ -87,6 +87,20 @@ class CentralDirectoryEndRecord { return this.size == MINIMUM_SIZE + commentLength; } + /** + * Returns the location in the data that the archive actually starts. For most files + * the archive data will start at 0, however, it is possible to have prefixed bytes + * (often used for startup scripts) at the beginning of the data. + * @param data the source data + * @return the offset within the data where the archive begins + */ + public long getStartOfArchive(RandomAccessData data) { + long length = Bytes.littleEndianValue(this.block, this.offset + 12, 4); + long specifiedOffset = Bytes.littleEndianValue(this.block, this.offset + 16, 4); + long actualOffset = data.getSize() - this.size - length; + return actualOffset - specifiedOffset; + } + /** * Return the bytes of the "Central directory" based on the offset indicated in this * record. diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java index 576f6c675eb..0e2ff7cbd20 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java @@ -119,15 +119,25 @@ public class JarFile extends java.util.jar.JarFile implements Iterable(numberOfRecords); diff --git a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/JarFileTests.java b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/JarFileTests.java index 1cdf36c0661..81edda650e1 100644 --- a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/JarFileTests.java +++ b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/JarFileTests.java @@ -17,11 +17,14 @@ package org.springframework.boot.loader.jar; import java.io.File; +import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLClassLoader; +import java.nio.charset.Charset; import java.util.Enumeration; import java.util.jar.JarEntry; import java.util.jar.Manifest; @@ -35,6 +38,8 @@ import org.junit.rules.TemporaryFolder; import org.springframework.boot.loader.TestJarCreator; import org.springframework.boot.loader.data.RandomAccessDataFile; import org.springframework.boot.loader.util.AsciiBytes; +import org.springframework.util.FileCopyUtils; +import org.springframework.util.StreamUtils; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThan; @@ -389,4 +394,18 @@ public class JarFileTests { } jarFile.close(); } + + @Test + public void jarFileWithScriptAtTheStart() throws Exception { + File file = this.temporaryFolder.newFile(); + InputStream sourceJarContent = new FileInputStream(this.rootJarFile); + FileOutputStream outputStream = new FileOutputStream(file); + StreamUtils.copy("#/bin/bash", Charset.defaultCharset(), outputStream); + FileCopyUtils.copy(sourceJarContent, outputStream); + this.rootJarFile = file; + this.jarFile = new JarFile(file); + // Call some other tests to verify + getEntries(); + getNestedJarFile(); + } }