Commit ebb8d0c5 authored by Andy Wilkinson's avatar Andy Wilkinson

Read the time of a JarEntryData using MSDOS Date Time format

The format is rather unusual.

The time is 16 bits: 5 bits for the hour, 6 bits for the minutes, and 5
bits for the seconds. 5 bits only allows 32 values (0-31) so the number
must be doubled, meaning that the time is only accurate to the nearest
two seconds. Also, the JDK rounds this down by subtracting one. The
doubling and rounding is performed by shifting one place to the left
and masking off the right-most bit respectively.

The date is 16 bits: 7 bits for the year, 4 bits for the month, and 5
bits for the day. The year is from 1980, i.e. the earliest date that
can be represented is 1980-01-01.

See http://mindprod.com/jgloss/zip.html for more details of the format.

Fixes gh-2826
parent 764e34b9
......@@ -19,6 +19,7 @@ package org.springframework.boot.loader.jar;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.util.GregorianCalendar;
import java.util.zip.ZipEntry;
import org.springframework.boot.loader.data.RandomAccessData;
......@@ -145,7 +146,20 @@ public final class JarEntryData {
}
public long getTime() {
return Bytes.littleEndianValue(this.header, 12, 4);
long time = Bytes.littleEndianValue(this.header, 12, 2);
int seconds = (int) ((time << 1) & 0x3E);
int minutes = (int) ((time >> 5) & 0x3F);
int hours = (int) ((time >> 11) & 0x1F);
long date = Bytes.littleEndianValue(this.header, 14, 2);
int day = (int) (date & 0x1F);
int month = (int) ((date >> 5) & 0xF) - 1;
int year = (int) ((date >> 9) & 0x7F) + 1980;
return new GregorianCalendar(year, month, day, hours, minutes, seconds)
.getTimeInMillis();
}
public long getCrc() {
......
......@@ -170,6 +170,14 @@ public class JarFileTests {
assertThat(this.jarFile.size(), equalTo((int) this.rootJarFile.length()));
}
@Test
public void getEntryTime() throws Exception {
java.util.jar.JarFile jdkJarFile = new java.util.jar.JarFile(this.rootJarFile);
assertThat(this.jarFile.getEntry("META-INF/MANIFEST.MF").getTime(),
equalTo(jdkJarFile.getEntry("META-INF/MANIFEST.MF").getTime()));
jdkJarFile.close();
}
@Test
public void close() throws Exception {
RandomAccessDataFile randomAccessDataFile = spy(new RandomAccessDataFile(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment