Skip to content

Commit

Permalink
Merge branch '2.4.x' into 2.5.x
Browse files Browse the repository at this point in the history
Closes gh-27900
  • Loading branch information
wilkinsona committed Sep 9, 2021
2 parents ba19577 + 47163af commit 37240bd
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 41 deletions.
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2021 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.
Expand Down Expand Up @@ -34,8 +34,6 @@ class CentralDirectoryEndRecord {

private static final int MAXIMUM_COMMENT_LENGTH = 0xFFFF;

private static final int ZIP64_MAGICCOUNT = 0xFFFF;

private static final int MAXIMUM_SIZE = MINIMUM_SIZE + MAXIMUM_COMMENT_LENGTH;

private static final int SIGNATURE = 0x06054b50;
Expand Down Expand Up @@ -74,8 +72,9 @@ class CentralDirectoryEndRecord {
}
this.offset = this.block.length - this.size;
}
int startOfCentralDirectoryEndRecord = (int) (data.getSize() - this.size);
this.zip64End = isZip64() ? new Zip64End(data, startOfCentralDirectoryEndRecord) : null;
long startOfCentralDirectoryEndRecord = data.getSize() - this.size;
Zip64Locator zip64Locator = Zip64Locator.find(data, startOfCentralDirectoryEndRecord);
this.zip64End = (zip64Locator != null) ? new Zip64End(data, zip64Locator) : null;
}

private byte[] createBlockFromEndOfData(RandomAccessData data, int size) throws IOException {
Expand All @@ -92,10 +91,6 @@ private boolean isValid() {
return this.size == MINIMUM_SIZE + commentLength;
}

private boolean isZip64() {
return (int) Bytes.littleEndianValue(this.block, this.offset + 10, 2) == ZIP64_MAGICCOUNT;
}

/**
* 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
Expand All @@ -105,7 +100,8 @@ private boolean isZip64() {
*/
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 specifiedOffset = (this.zip64End != null) ? this.zip64End.centralDirectoryOffset
: Bytes.littleEndianValue(this.block, this.offset + 16, 4);
long zip64EndSize = (this.zip64End != null) ? this.zip64End.getSize() : 0L;
int zip64LocSize = (this.zip64End != null) ? Zip64Locator.ZIP64_LOCSIZE : 0;
long actualOffset = data.getSize() - this.size - length - zip64EndSize - zip64LocSize;
Expand Down Expand Up @@ -145,6 +141,10 @@ String getComment() {
return comment.toString();
}

boolean isZip64() {
return this.zip64End != null;
}

/**
* A Zip64 end of central directory record.
*
Expand All @@ -167,10 +167,6 @@ private static final class Zip64End {

private final int numberOfRecords;

private Zip64End(RandomAccessData data, int centralDirectoryEndOffset) throws IOException {
this(data, new Zip64Locator(data, centralDirectoryEndOffset));
}

private Zip64End(RandomAccessData data, Zip64Locator locator) throws IOException {
this.locator = locator;
byte[] block = data.read(locator.getZip64EndOffset(), 56);
Expand Down Expand Up @@ -215,16 +211,18 @@ private int getNumberOfRecords() {
*/
private static final class Zip64Locator {

static final int SIGNATURE = 0x07064b50;

static final int ZIP64_LOCSIZE = 20; // locator size

static final int ZIP64_LOCOFF = 8; // offset of zip64 end

private final long zip64EndOffset;

private final int offset;
private final long offset;

private Zip64Locator(RandomAccessData data, int centralDirectoryEndOffset) throws IOException {
this.offset = centralDirectoryEndOffset - ZIP64_LOCSIZE;
byte[] block = data.read(this.offset, ZIP64_LOCSIZE);
private Zip64Locator(long offset, byte[] block) throws IOException {
this.offset = offset;
this.zip64EndOffset = Bytes.littleEndianValue(block, ZIP64_LOCOFF, 8);
}

Expand All @@ -244,6 +242,17 @@ private long getZip64EndOffset() {
return this.zip64EndOffset;
}

private static Zip64Locator find(RandomAccessData data, long centralDirectoryEndOffset) throws IOException {
long offset = centralDirectoryEndOffset - ZIP64_LOCSIZE;
if (offset >= 0) {
byte[] block = data.read(offset, ZIP64_LOCSIZE);
if (Bytes.littleEndianValue(block, 0, 4) == SIGNATURE) {
return new Zip64Locator(offset, block);
}
}
return null;
}

}

}
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2021 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.
Expand Down Expand Up @@ -67,15 +67,17 @@ final class CentralDirectoryFileHeader implements FileHeader {
this.localHeaderOffset = localHeaderOffset;
}

void load(byte[] data, int dataOffset, RandomAccessData variableData, int variableOffset, JarEntryFilter filter)
void load(byte[] data, int dataOffset, RandomAccessData variableData, long variableOffset, JarEntryFilter filter)
throws IOException {
// Load fixed part
this.header = data;
this.headerOffset = dataOffset;
long compressedSize = Bytes.littleEndianValue(data, dataOffset + 20, 4);
long uncompressedSize = Bytes.littleEndianValue(data, dataOffset + 24, 4);
long nameLength = Bytes.littleEndianValue(data, dataOffset + 28, 2);
long extraLength = Bytes.littleEndianValue(data, dataOffset + 30, 2);
long commentLength = Bytes.littleEndianValue(data, dataOffset + 32, 2);
this.localHeaderOffset = Bytes.littleEndianValue(data, dataOffset + 42, 4);
long localHeaderOffset = Bytes.littleEndianValue(data, dataOffset + 42, 4);
// Load variable part
dataOffset += 46;
if (variableData != null) {
Expand All @@ -92,11 +94,37 @@ void load(byte[] data, int dataOffset, RandomAccessData variableData, int variab
this.extra = new byte[(int) extraLength];
System.arraycopy(data, (int) (dataOffset + nameLength), this.extra, 0, this.extra.length);
}
this.localHeaderOffset = getLocalHeaderOffset(compressedSize, uncompressedSize, localHeaderOffset, this.extra);
if (commentLength > 0) {
this.comment = new AsciiBytes(data, (int) (dataOffset + nameLength + extraLength), (int) commentLength);
}
}

private long getLocalHeaderOffset(long compressedSize, long uncompressedSize, long localHeaderOffset, byte[] extra)
throws IOException {
if (localHeaderOffset != 0xFFFFFFFFL) {
return localHeaderOffset;
}
int extraOffset = 0;
while (extraOffset < extra.length - 2) {
int id = (int) Bytes.littleEndianValue(extra, extraOffset, 2);
int length = (int) Bytes.littleEndianValue(extra, extraOffset, 2);
extraOffset += 4;
if (id == 1) {
int localHeaderExtraOffset = 0;
if (compressedSize == 0xFFFFFFFFL) {
localHeaderExtraOffset += 4;
}
if (uncompressedSize == 0xFFFFFFFFL) {
localHeaderExtraOffset += 4;
}
return Bytes.littleEndianValue(extra, extraOffset + localHeaderExtraOffset, 8);
}
extraOffset += length;
}
throw new IOException("Zip64 Extended Information Extra Field not found");
}

AsciiBytes getName() {
return this.name;
}
Expand Down Expand Up @@ -176,7 +204,7 @@ public CentralDirectoryFileHeader clone() {
return new CentralDirectoryFileHeader(header, 0, this.name, header, this.comment, this.localHeaderOffset);
}

static CentralDirectoryFileHeader fromRandomAccessData(RandomAccessData data, int offset, JarEntryFilter filter)
static CentralDirectoryFileHeader fromRandomAccessData(RandomAccessData data, long offset, JarEntryFilter filter)
throws IOException {
CentralDirectoryFileHeader fileHeader = new CentralDirectoryFileHeader();
byte[] bytes = data.read(offset, 46);
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2021 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.
Expand Down Expand Up @@ -86,7 +86,7 @@ private void visitStart(CentralDirectoryEndRecord endRecord, RandomAccessData ce
}
}

private void visitFileHeader(int dataOffset, CentralDirectoryFileHeader fileHeader) {
private void visitFileHeader(long dataOffset, CentralDirectoryFileHeader fileHeader) {
for (CentralDirectoryVisitor visitor : this.visitors) {
visitor.visitFileHeader(fileHeader, dataOffset);
}
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2021 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.
Expand Down Expand Up @@ -27,7 +27,7 @@ interface CentralDirectoryVisitor {

void visitStart(CentralDirectoryEndRecord endRecord, RandomAccessData centralDirectoryData);

void visitFileHeader(CentralDirectoryFileHeader fileHeader, int dataOffset);
void visitFileHeader(CentralDirectoryFileHeader fileHeader, long dataOffset);

void visitEnd();

Expand Down
Expand Up @@ -169,7 +169,7 @@ public void visitStart(CentralDirectoryEndRecord endRecord, RandomAccessData cen
}

@Override
public void visitFileHeader(CentralDirectoryFileHeader fileHeader, int dataOffset) {
public void visitFileHeader(CentralDirectoryFileHeader fileHeader, long dataOffset) {
AsciiBytes name = fileHeader.getName();
if (name.startsWith(META_INF) && name.endsWith(SIGNATURE_FILE_EXTENSION)) {
JarFile.this.signed = true;
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2021 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.
Expand Down Expand Up @@ -89,7 +89,7 @@ class JarFileEntries implements CentralDirectoryVisitor, Iterable<JarEntry> {

private int[] hashCodes;

private int[] centralDirectoryOffsets;
private Offsets centralDirectoryOffsets;

private int[] positions;

Expand Down Expand Up @@ -120,21 +120,21 @@ public void visitStart(CentralDirectoryEndRecord endRecord, RandomAccessData cen
int maxSize = endRecord.getNumberOfRecords();
this.centralDirectoryData = centralDirectoryData;
this.hashCodes = new int[maxSize];
this.centralDirectoryOffsets = new int[maxSize];
this.centralDirectoryOffsets = Offsets.of(endRecord);
this.positions = new int[maxSize];
}

@Override
public void visitFileHeader(CentralDirectoryFileHeader fileHeader, int dataOffset) {
public void visitFileHeader(CentralDirectoryFileHeader fileHeader, long dataOffset) {
AsciiBytes name = applyFilter(fileHeader.getName());
if (name != null) {
add(name, dataOffset);
}
}

private void add(AsciiBytes name, int dataOffset) {
private void add(AsciiBytes name, long dataOffset) {
this.hashCodes[this.size] = name.hashCode();
this.centralDirectoryOffsets[this.size] = dataOffset;
this.centralDirectoryOffsets.set(this.size, dataOffset);
this.positions[this.size] = this.size;
this.size++;
}
Expand Down Expand Up @@ -183,11 +183,11 @@ private void sort(int left, int right) {

private void swap(int i, int j) {
swap(this.hashCodes, i, j);
swap(this.centralDirectoryOffsets, i, j);
this.centralDirectoryOffsets.swap(i, j);
swap(this.positions, i, j);
}

private void swap(int[] array, int i, int j) {
private static void swap(int[] array, int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
Expand Down Expand Up @@ -316,9 +316,10 @@ private <T extends FileHeader> T getEntry(int hashCode, CharSequence name, char
@SuppressWarnings("unchecked")
private <T extends FileHeader> T getEntry(int index, Class<T> type, boolean cacheEntry, AsciiBytes nameAlias) {
try {
long offset = this.centralDirectoryOffsets.get(index);
FileHeader cached = this.entriesCache.get(index);
FileHeader entry = (cached != null) ? cached : CentralDirectoryFileHeader
.fromRandomAccessData(this.centralDirectoryData, this.centralDirectoryOffsets[index], this.filter);
FileHeader entry = (cached != null) ? cached
: CentralDirectoryFileHeader.fromRandomAccessData(this.centralDirectoryData, offset, this.filter);
if (CentralDirectoryFileHeader.class.equals(entry.getClass()) && type.equals(JarEntry.class)) {
entry = new JarEntry(this.jarFile, index, (CentralDirectoryFileHeader) entry, nameAlias);
}
Expand Down Expand Up @@ -420,4 +421,71 @@ public JarEntry next() {

}

private interface Offsets {

void set(int index, long value);

long get(int index);

void swap(int i, int j);

static Offsets of(CentralDirectoryEndRecord endRecord) {
return endRecord.isZip64() ? new Zip64Offsets(endRecord.getNumberOfRecords())
: new ZipOffsets(endRecord.getNumberOfRecords());
}

}

private static final class ZipOffsets implements Offsets {

private final int[] offsets;

private ZipOffsets(int size) {
this.offsets = new int[size];
}

@Override
public void swap(int i, int j) {
JarFileEntries.swap(this.offsets, i, j);
}

@Override
public void set(int index, long value) {
this.offsets[index] = (int) value;
}

@Override
public long get(int index) {
return this.offsets[index];
}

}

private static final class Zip64Offsets implements Offsets {

private final long[] offsets;

private Zip64Offsets(int size) {
this.offsets = new long[size];
}

@Override
public void swap(int i, int j) {
long temp = this.offsets[i];
this.offsets[i] = this.offsets[j];
this.offsets[j] = temp;
}

@Override
public void set(int index, long value) {
this.offsets[index] = value;
}

@Override
public long get(int index) {
return this.offsets[index];
}

}

}
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2021 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.
Expand Down Expand Up @@ -97,7 +97,7 @@ public void visitStart(CentralDirectoryEndRecord endRecord, RandomAccessData cen
}

@Override
public void visitFileHeader(CentralDirectoryFileHeader fileHeader, int dataOffset) {
public void visitFileHeader(CentralDirectoryFileHeader fileHeader, long dataOffset) {
this.headers.add(fileHeader.clone());
}

Expand All @@ -121,7 +121,7 @@ public void visitStart(CentralDirectoryEndRecord endRecord, RandomAccessData cen
}

@Override
public void visitFileHeader(CentralDirectoryFileHeader fileHeader, int dataOffset) {
public void visitFileHeader(CentralDirectoryFileHeader fileHeader, long dataOffset) {
this.invocations.add("visitFileHeader");
}

Expand Down

0 comments on commit 37240bd

Please sign in to comment.