fish.payara.micro.boot.loader.jar.CentralDirectoryFileHeader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of payara-micro Show documentation
Show all versions of payara-micro Show documentation
Micro Distribution of the Payara Project
/*
* Copyright 2012-2016 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package fish.payara.micro.boot.loader.jar;
import java.io.IOException;
import java.util.Calendar;
import java.util.GregorianCalendar;
import fish.payara.micro.boot.loader.data.RandomAccessData;
/**
* A ZIP File "Central directory file header record" (CDFH).
*
* @author Phillip Webb
* @author Andy Wilkinson
* @see Zip File Format
*/
final class CentralDirectoryFileHeader implements FileHeader {
private static final AsciiBytes SLASH = new AsciiBytes("/");
private static final byte[] NO_EXTRA = {};
private static final AsciiBytes NO_COMMENT = new AsciiBytes("");
private byte[] header;
private int headerOffset;
private AsciiBytes name;
private byte[] extra;
private AsciiBytes comment;
private long localHeaderOffset;
CentralDirectoryFileHeader() {
}
CentralDirectoryFileHeader(byte[] header, int headerOffset, AsciiBytes name,
byte[] extra, AsciiBytes comment, long localHeaderOffset) {
super();
this.header = header;
this.headerOffset = headerOffset;
this.name = name;
this.extra = extra;
this.comment = comment;
this.localHeaderOffset = localHeaderOffset;
}
void load(byte[] data, int dataOffset, RandomAccessData variableData,
int variableOffset, JarEntryFilter filter) throws IOException {
// Load fixed part
this.header = data;
this.headerOffset = dataOffset;
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);
// Load variable part
dataOffset += 46;
if (variableData != null) {
data = Bytes.get(variableData.getSubsection(variableOffset + 46,
nameLength + extraLength + commentLength));
dataOffset = 0;
}
this.name = new AsciiBytes(data, dataOffset, (int) nameLength);
if (filter != null) {
this.name = filter.apply(this.name);
}
this.extra = NO_EXTRA;
this.comment = NO_COMMENT;
if (extraLength > 0) {
this.extra = new byte[(int) extraLength];
System.arraycopy(data, (int) (dataOffset + nameLength), this.extra, 0,
this.extra.length);
}
if (commentLength > 0) {
this.comment = new AsciiBytes(data,
(int) (dataOffset + nameLength + extraLength), (int) commentLength);
}
}
public AsciiBytes getName() {
return this.name;
}
@Override
public boolean hasName(String name, String suffix) {
return this.name.equals(new AsciiBytes(suffix == null ? name : name + suffix));
}
public boolean isDirectory() {
return this.name.endsWith(SLASH);
}
@Override
public int getMethod() {
return (int) Bytes.littleEndianValue(this.header, this.headerOffset + 10, 2);
}
public long getTime() {
long date = Bytes.littleEndianValue(this.header, this.headerOffset + 14, 2);
long time = Bytes.littleEndianValue(this.header, this.headerOffset + 12, 2);
return decodeMsDosFormatDateTime(date, time).getTimeInMillis();
}
/**
* Decode MS-DOS Date Time details. See
* mindprod.com/jgloss/zip.html for
* more details of the format.
* @param date the date part
* @param time the time part
* @return a {@link Calendar} containing the decoded date.
*/
private Calendar decodeMsDosFormatDateTime(long date, long time) {
int year = (int) ((date >> 9) & 0x7F) + 1980;
int month = (int) ((date >> 5) & 0xF) - 1;
int day = (int) (date & 0x1F);
int hours = (int) ((time >> 11) & 0x1F);
int minutes = (int) ((time >> 5) & 0x3F);
int seconds = (int) ((time << 1) & 0x3E);
return new GregorianCalendar(year, month, day, hours, minutes, seconds);
}
public long getCrc() {
return Bytes.littleEndianValue(this.header, this.headerOffset + 16, 4);
}
@Override
public long getCompressedSize() {
return Bytes.littleEndianValue(this.header, this.headerOffset + 20, 4);
}
@Override
public long getSize() {
return Bytes.littleEndianValue(this.header, this.headerOffset + 24, 4);
}
public byte[] getExtra() {
return this.extra;
}
public AsciiBytes getComment() {
return this.comment;
}
@Override
public long getLocalHeaderOffset() {
return this.localHeaderOffset;
}
@Override
public CentralDirectoryFileHeader clone() {
byte[] header = new byte[46];
System.arraycopy(this.header, this.headerOffset, header, 0, header.length);
return new CentralDirectoryFileHeader(header, 0, this.name, header, this.comment,
this.localHeaderOffset);
}
public static CentralDirectoryFileHeader fromRandomAccessData(RandomAccessData data,
int offset, JarEntryFilter filter) throws IOException {
CentralDirectoryFileHeader fileHeader = new CentralDirectoryFileHeader();
byte[] bytes = Bytes.get(data.getSubsection(offset, 46));
fileHeader.load(bytes, 0, data, offset, filter);
return fileHeader;
}
}