381 lines
7.4 KiB
JavaScript
381 lines
7.4 KiB
JavaScript
import { inherits } from "util";
|
|
import normalizePath from "normalize-path";
|
|
import ArchiveEntry from "../archive-entry.js";
|
|
import GeneralPurposeBit from "./general-purpose-bit.js";
|
|
import UnixStat from "./unix-stat.js";
|
|
import {
|
|
EMPTY,
|
|
MIN_VERSION_INITIAL,
|
|
MODE_MASK,
|
|
PLATFORM_FAT,
|
|
PLATFORM_UNIX,
|
|
S_DOS_A,
|
|
S_DOS_D,
|
|
S_IFDIR,
|
|
S_IFREG,
|
|
SHORT_MASK,
|
|
SHORT_SHIFT,
|
|
ZIP64_MAGIC,
|
|
} from "./constants.js";
|
|
import { dateToDos, dosToDate } from "./util.js";
|
|
|
|
export default class ZipArchiveEntry extends ArchiveEntry {
|
|
constructor(name) {
|
|
super();
|
|
this.platform = PLATFORM_FAT;
|
|
this.method = -1;
|
|
this.name = null;
|
|
this.size = 0;
|
|
this.csize = 0;
|
|
this.gpb = new GeneralPurposeBit();
|
|
this.crc = 0;
|
|
this.time = -1;
|
|
this.minver = MIN_VERSION_INITIAL;
|
|
this.mode = -1;
|
|
this.extra = null;
|
|
this.exattr = 0;
|
|
this.inattr = 0;
|
|
this.comment = null;
|
|
if (name) {
|
|
this.setName(name);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the extra fields related to the entry.
|
|
*
|
|
* @returns {Buffer}
|
|
*/
|
|
getCentralDirectoryExtra() {
|
|
return this.getExtra();
|
|
}
|
|
|
|
/**
|
|
* Returns the comment set for the entry.
|
|
*
|
|
* @returns {string}
|
|
*/
|
|
getComment() {
|
|
return this.comment !== null ? this.comment : "";
|
|
}
|
|
|
|
/**
|
|
* Returns the compressed size of the entry.
|
|
*
|
|
* @returns {number}
|
|
*/
|
|
getCompressedSize() {
|
|
return this.csize;
|
|
}
|
|
|
|
/**
|
|
* Returns the CRC32 digest for the entry.
|
|
*
|
|
* @returns {number}
|
|
*/
|
|
getCrc() {
|
|
return this.crc;
|
|
}
|
|
|
|
/**
|
|
* Returns the external file attributes for the entry.
|
|
*
|
|
* @returns {number}
|
|
*/
|
|
getExternalAttributes = function () {
|
|
return this.exattr;
|
|
};
|
|
|
|
/**
|
|
* Returns the extra fields related to the entry.
|
|
*
|
|
* @returns {Buffer}
|
|
*/
|
|
getExtra() {
|
|
return this.extra !== null ? this.extra : EMPTY;
|
|
}
|
|
|
|
/**
|
|
* Returns the general purpose bits related to the entry.
|
|
*
|
|
* @returns {GeneralPurposeBit}
|
|
*/
|
|
getGeneralPurposeBit() {
|
|
return this.gpb;
|
|
}
|
|
|
|
/**
|
|
* Returns the internal file attributes for the entry.
|
|
*
|
|
* @returns {number}
|
|
*/
|
|
getInternalAttributes() {
|
|
return this.inattr;
|
|
}
|
|
|
|
/**
|
|
* Returns the last modified date of the entry.
|
|
*
|
|
* @returns {number}
|
|
*/
|
|
getLastModifiedDate() {
|
|
return this.getTime();
|
|
}
|
|
|
|
/**
|
|
* Returns the extra fields related to the entry.
|
|
*
|
|
* @returns {Buffer}
|
|
*/
|
|
getLocalFileDataExtra() {
|
|
return this.getExtra();
|
|
}
|
|
|
|
/**
|
|
* Returns the compression method used on the entry.
|
|
*
|
|
* @returns {number}
|
|
*/
|
|
getMethod() {
|
|
return this.method;
|
|
}
|
|
|
|
/**
|
|
* Returns the filename of the entry.
|
|
*
|
|
* @returns {string}
|
|
*/
|
|
getName() {
|
|
return this.name;
|
|
}
|
|
|
|
/**
|
|
* Returns the platform on which the entry was made.
|
|
*
|
|
* @returns {number}
|
|
*/
|
|
getPlatform() {
|
|
return this.platform;
|
|
}
|
|
/**
|
|
* Returns the size of the entry.
|
|
*
|
|
* @returns {number}
|
|
*/
|
|
getSize() {
|
|
return this.size;
|
|
}
|
|
/**
|
|
* Returns a date object representing the last modified date of the entry.
|
|
*
|
|
* @returns {number|Date}
|
|
*/
|
|
getTime() {
|
|
return this.time !== -1 ? dosToDate(this.time) : -1;
|
|
}
|
|
/**
|
|
* Returns the DOS timestamp for the entry.
|
|
*
|
|
* @returns {number}
|
|
*/
|
|
getTimeDos() {
|
|
return this.time !== -1 ? this.time : 0;
|
|
}
|
|
/**
|
|
* Returns the UNIX file permissions for the entry.
|
|
*
|
|
* @returns {number}
|
|
*/
|
|
getUnixMode() {
|
|
return this.platform !== PLATFORM_UNIX
|
|
? 0
|
|
: (this.getExternalAttributes() >> SHORT_SHIFT) & SHORT_MASK;
|
|
}
|
|
/**
|
|
* Returns the version of ZIP needed to extract the entry.
|
|
*
|
|
* @returns {number}
|
|
*/
|
|
getVersionNeededToExtract() {
|
|
return this.minver;
|
|
}
|
|
/**
|
|
* Sets the comment of the entry.
|
|
*
|
|
* @param comment
|
|
*/
|
|
setComment(comment) {
|
|
if (Buffer.byteLength(comment) !== comment.length) {
|
|
this.getGeneralPurposeBit().useUTF8ForNames(true);
|
|
}
|
|
this.comment = comment;
|
|
}
|
|
/**
|
|
* Sets the compressed size of the entry.
|
|
*
|
|
* @param size
|
|
*/
|
|
setCompressedSize(size) {
|
|
if (size < 0) {
|
|
throw new Error("invalid entry compressed size");
|
|
}
|
|
this.csize = size;
|
|
}
|
|
/**
|
|
* Sets the checksum of the entry.
|
|
*
|
|
* @param crc
|
|
*/
|
|
setCrc(crc) {
|
|
if (crc < 0) {
|
|
throw new Error("invalid entry crc32");
|
|
}
|
|
this.crc = crc;
|
|
}
|
|
/**
|
|
* Sets the external file attributes of the entry.
|
|
*
|
|
* @param attr
|
|
*/
|
|
setExternalAttributes(attr) {
|
|
this.exattr = attr >>> 0;
|
|
}
|
|
/**
|
|
* Sets the extra fields related to the entry.
|
|
*
|
|
* @param extra
|
|
*/
|
|
setExtra(extra) {
|
|
this.extra = extra;
|
|
}
|
|
/**
|
|
* Sets the general purpose bits related to the entry.
|
|
*
|
|
* @param gpb
|
|
*/
|
|
setGeneralPurposeBit(gpb) {
|
|
if (!(gpb instanceof GeneralPurposeBit)) {
|
|
throw new Error("invalid entry GeneralPurposeBit");
|
|
}
|
|
this.gpb = gpb;
|
|
}
|
|
/**
|
|
* Sets the internal file attributes of the entry.
|
|
*
|
|
* @param attr
|
|
*/
|
|
setInternalAttributes(attr) {
|
|
this.inattr = attr;
|
|
}
|
|
/**
|
|
* Sets the compression method of the entry.
|
|
*
|
|
* @param method
|
|
*/
|
|
setMethod(method) {
|
|
if (method < 0) {
|
|
throw new Error("invalid entry compression method");
|
|
}
|
|
this.method = method;
|
|
}
|
|
/**
|
|
* Sets the name of the entry.
|
|
*
|
|
* @param name
|
|
* @param prependSlash
|
|
*/
|
|
setName(name, prependSlash = false) {
|
|
name = normalizePath(name, false)
|
|
.replace(/^\w+:/, "")
|
|
.replace(/^(\.\.\/|\/)+/, "");
|
|
if (prependSlash) {
|
|
name = `/${name}`;
|
|
}
|
|
if (Buffer.byteLength(name) !== name.length) {
|
|
this.getGeneralPurposeBit().useUTF8ForNames(true);
|
|
}
|
|
this.name = name;
|
|
}
|
|
/**
|
|
* Sets the platform on which the entry was made.
|
|
*
|
|
* @param platform
|
|
*/
|
|
setPlatform(platform) {
|
|
this.platform = platform;
|
|
}
|
|
/**
|
|
* Sets the size of the entry.
|
|
*
|
|
* @param size
|
|
*/
|
|
setSize(size) {
|
|
if (size < 0) {
|
|
throw new Error("invalid entry size");
|
|
}
|
|
this.size = size;
|
|
}
|
|
/**
|
|
* Sets the time of the entry.
|
|
*
|
|
* @param time
|
|
* @param forceLocalTime
|
|
*/
|
|
setTime(time, forceLocalTime) {
|
|
if (!(time instanceof Date)) {
|
|
throw new Error("invalid entry time");
|
|
}
|
|
this.time = dateToDos(time, forceLocalTime);
|
|
}
|
|
/**
|
|
* Sets the UNIX file permissions for the entry.
|
|
*
|
|
* @param mode
|
|
*/
|
|
setUnixMode(mode) {
|
|
mode |= this.isDirectory() ? S_IFDIR : S_IFREG;
|
|
var extattr = 0;
|
|
extattr |= (mode << SHORT_SHIFT) | (this.isDirectory() ? S_DOS_D : S_DOS_A);
|
|
this.setExternalAttributes(extattr);
|
|
this.mode = mode & MODE_MASK;
|
|
this.platform = PLATFORM_UNIX;
|
|
}
|
|
/**
|
|
* Sets the version of ZIP needed to extract this entry.
|
|
*
|
|
* @param minver
|
|
*/
|
|
setVersionNeededToExtract(minver) {
|
|
this.minver = minver;
|
|
}
|
|
/**
|
|
* Returns true if this entry represents a directory.
|
|
*
|
|
* @returns {boolean}
|
|
*/
|
|
isDirectory() {
|
|
return this.getName().slice(-1) === "/";
|
|
}
|
|
/**
|
|
* Returns true if this entry represents a unix symlink,
|
|
* in which case the entry's content contains the target path
|
|
* for the symlink.
|
|
*
|
|
* @returns {boolean}
|
|
*/
|
|
isUnixSymlink() {
|
|
return (
|
|
(this.getUnixMode() & UnixStat.FILE_TYPE_FLAG) === UnixStat.LINK_FLAG
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Returns true if this entry is using the ZIP64 extension of ZIP.
|
|
*
|
|
* @returns {boolean}
|
|
*/
|
|
isZip64() {
|
|
return this.csize > ZIP64_MAGIC || this.size > ZIP64_MAGIC;
|
|
}
|
|
}
|