All Downloads are FREE. Search and download functionalities are using the official Maven repository.

software.coley.llzip.format.model.AbstractZipFileHeader Maven / Gradle / Ivy

package software.coley.llzip.format.model;

import software.coley.llzip.format.compression.Decompressor;
import software.coley.llzip.format.compression.ZipCompressions;
import software.coley.llzip.util.ByteData;
import software.coley.llzip.util.ByteDataUtil;
import software.coley.llzip.util.lazy.LazyByteData;
import software.coley.llzip.util.lazy.LazyInt;
import software.coley.llzip.util.lazy.LazyLong;

/**
 * Common base for shared elements of {@link CentralDirectoryFileHeader} and {@link LocalFileHeader}.
 *
 * @author Matt Coley
 */
public abstract class AbstractZipFileHeader implements ZipPart, ZipRead {
	// Zip spec elements, all lazily read, common between central/local file headers
	protected LazyInt versionNeededToExtract;
	protected LazyInt generalPurposeBitFlag;
	protected LazyInt compressionMethod;
	protected LazyInt lastModFileTime;
	protected LazyInt lastModFileDate;
	protected LazyInt crc32;
	protected LazyLong compressedSize;
	protected LazyLong uncompressedSize;
	protected LazyInt fileNameLength;
	protected LazyInt extraFieldLength;
	protected LazyByteData fileName;
	protected LazyByteData extraField;

	// Offset into the data this part is read from
	protected transient long offset = -1L;

	// String cache values
	private transient String fileNameCache;
	private transient String extraFieldCache;

	@Override
	public long offset() {
		return offset;
	}

	@Override
	public void read(ByteData data, long offset) {
		this.offset = offset;
	}

	/**
	 * @return Version of zip software required to read the archive features.
	 */
	public int getVersionNeededToExtract() {
		return versionNeededToExtract.get();
	}

	/**
	 * @param versionNeededToExtract
	 * 		Version of zip software required to read the archive features.
	 */
	public void setVersionNeededToExtract(int versionNeededToExtract) {
		this.versionNeededToExtract.set(versionNeededToExtract);
	}

	/**
	 * @return Used primarily to expand on details of file compression.
	 */
	public int getGeneralPurposeBitFlag() {
		return generalPurposeBitFlag.get();
	}

	/**
	 * @param generalPurposeBitFlag
	 * 		Used primarily to expand on details of file compression.
	 */
	public void setGeneralPurposeBitFlag(int generalPurposeBitFlag) {
		this.generalPurposeBitFlag.set(generalPurposeBitFlag);
	}

	/**
	 * @return Method to use for {@link LocalFileHeader#decompress(Decompressor) decompressing data}.
	 *
	 * @see ZipCompressions Possible methods.
	 */
	public int getCompressionMethod() {
		return compressionMethod.get();
	}

	/**
	 * @param compressionMethod
	 * 		Method to use for {@link LocalFileHeader#decompress(Decompressor) decompressing data}.
	 *
	 * @see ZipCompressions Possible methods.
	 */
	public void setCompressionMethod(int compressionMethod) {
		this.compressionMethod.set(compressionMethod);
	}

	/**
	 * @return Modification time of the file.
	 */
	public int getLastModFileTime() {
		return lastModFileTime.get();
	}

	/**
	 * @param lastModFileTime
	 * 		Modification time of the file.
	 */
	public void setLastModFileTime(int lastModFileTime) {
		this.lastModFileTime.set(lastModFileTime);
	}

	/**
	 * @return Modification date of the file.
	 */
	public int getLastModFileDate() {
		return lastModFileDate.get();
	}

	/**
	 * @param lastModFileDate
	 * 		Modification date of the file.
	 */
	public void setLastModFileDate(int lastModFileDate) {
		this.lastModFileDate.set(lastModFileDate);
	}

	/**
	 * @return File checksum.
	 */
	public int getCrc32() {
		return crc32.get();
	}

	/**
	 * @param crc32
	 * 		File checksum.
	 */
	public void setCrc32(int crc32) {
		this.crc32.set(crc32);
	}

	/**
	 * Be aware that these attributes can be falsified.
	 * Different zip-parsing programs treat the files differently
	 * and may not adhere to what you expect from the zip specification.
	 * 

* When in doubt, trust {@code data.length()} from {@link LocalFileHeader#getFileData()}. * * @return Compressed size of {@link LocalFileHeader#getFileData()}. */ public long getCompressedSize() { return compressedSize.get(); } /** * @param compressedSize * Compressed size of {@link LocalFileHeader#getFileData()}. */ public void setCompressedSize(long compressedSize) { this.compressedSize.set(compressedSize & 0xFFFFFFFFL); } /** * Be aware that these attributes can be falsified. * Different zip-parsing programs treat the files differently * and may not adhere to what you expect from the zip specification. * * @return Uncompressed size after {@link LocalFileHeader#decompress(Decompressor)} is used on {@link LocalFileHeader#getFileData()}. */ public long getUncompressedSize() { return uncompressedSize.get(); } /** * @param uncompressedSize * Uncompressed size after {@link LocalFileHeader#decompress(Decompressor)} is used on {@link LocalFileHeader#getFileData()}. */ public void setUncompressedSize(long uncompressedSize) { this.uncompressedSize.set(uncompressedSize & 0xFFFFFFFFL); } /** * @return Length of {@link #getFileName()}. */ public int getFileNameLength() { return fileNameLength.get(); } /** * @param fileNameLength * Length of {@link #getFileName()}. */ public void setFileNameLength(int fileNameLength) { this.fileNameLength.set(fileNameLength & 0xFFFF); } /** * @return Length of {@link #getExtraField()} */ public int getExtraFieldLength() { return extraFieldLength.get(); } /** * @param extraFieldLength * Length of {@link #getExtraField()} */ public void setExtraFieldLength(int extraFieldLength) { this.extraFieldLength.set(extraFieldLength & 0xFFFF); } /** * Should match {@link LocalFileHeader#getFileName()} but is not a strict requirement. * If they do not match, trust this value instead. * * @return File name. */ public ByteData getFileName() { return fileName.get(); } /** * @param fileName * File name. */ public void setFileName(ByteData fileName) { if (this.fileName != fileName) fileNameCache = null; this.fileName.set(fileName); } /** * Should match {@link CentralDirectoryFileHeader#getFileName()} but is not a strict requirement. * If they do not match, the central directory file name should be trusted instead. * * @return File name. */ public String getFileNameAsString() { String fileNameCache = this.fileNameCache; if (fileNameCache == null) { return this.fileNameCache = ByteDataUtil.toString(fileName.get()); } return fileNameCache; } /** * @return May be used for extra compression information, * depending on the {@link #getCompressionMethod() compression method} used. */ public ByteData getExtraField() { return extraField.get(); } /** * @param extraField * Extra field bytes. */ public void setExtraField(ByteData extraField) { this.extraField.set(extraField); } /** * @return Extra field. */ public String getExtraFieldAsString() { String fileCommentCache = this.extraFieldCache; if (fileCommentCache == null) { return this.extraFieldCache = ByteDataUtil.toString(extraField.get()); } return fileCommentCache; } protected LazyInt readWord(ByteData data, int localOffset) { return new LazyInt(() -> { if (data.isClosed()) throw new IllegalStateException("Cannot read from closed data source"); return ByteDataUtil.readWord(data, offset + localOffset); }); } protected LazyInt readQuad(ByteData data, int localOffset) { return new LazyInt(() -> { if (data.isClosed()) throw new IllegalStateException("Cannot read from closed data source"); return ByteDataUtil.readQuad(data, offset + localOffset); }); } protected LazyInt readMaskedQuad(ByteData data, int localOffset) { return new LazyInt(() -> { if (data.isClosed()) throw new IllegalStateException("Cannot read from closed data source"); return ByteDataUtil.readQuad(data, offset + localOffset) & 0xFFFF; }); } protected LazyLong readLongWord(ByteData data, int localOffset) { return new LazyLong(() -> { if (data.isClosed()) throw new IllegalStateException("Cannot read from closed data source"); return ByteDataUtil.readWord(data, offset + localOffset); }); } protected LazyLong readMaskedLongQuad(ByteData data, int localOffset) { return new LazyLong(() -> { if (data.isClosed()) throw new IllegalStateException("Cannot read from closed data source"); return ByteDataUtil.readQuad(data, offset + localOffset) & 0xFFFFFFFFL; }); } protected LazyByteData readSlice(ByteData data, LazyInt localOffset, LazyInt length) { return new LazyByteData(() -> { if (data.isClosed()) throw new IllegalStateException("Cannot read from closed data source"); return data.sliceOf(offset + localOffset.get(), length.get()); }); } protected LazyByteData readLongSlice(ByteData data, LazyInt localOffset, LazyLong length) { return new LazyByteData(() -> { if (data.isClosed()) throw new IllegalStateException("Cannot read from closed data source"); return data.sliceOf(offset + localOffset.get(), length.get()); }); } protected LazyByteData readLongSlice(ByteData data, LazyLong localOffset, LazyLong length) { return new LazyByteData(() -> { if (data.isClosed()) throw new IllegalStateException("Cannot read from closed data source"); return data.sliceOf(offset + localOffset.get(), length.get()); }); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy