Initial commit

This commit is contained in:
jiapengyu
2026-07-27 13:37:48 +08:00
commit ecba71e2a5
39123 changed files with 5989154 additions and 0 deletions
+6
View File
@@ -0,0 +1,6 @@
export default class ArchiveEntry {
getName() {}
getSize() {}
getLastModifiedDate() {}
isDirectory() {}
}
+98
View File
@@ -0,0 +1,98 @@
import { inherits } from "util";
import { isStream } from "is-stream";
import { Transform } from "readable-stream";
import ArchiveEntry from "./archive-entry.js";
import { normalizeInputSource } from "../util/index.js";
export default class ArchiveOutputStream extends Transform {
constructor(options) {
super(options);
this.offset = 0;
this._archive = {
finish: false,
finished: false,
processing: false,
};
}
_appendBuffer(zae, source, callback) {
// scaffold only
}
_appendStream(zae, source, callback) {
// scaffold only
}
_emitErrorCallback = function (err) {
if (err) {
this.emit("error", err);
}
};
_finish(ae) {
// scaffold only
}
_normalizeEntry(ae) {
// scaffold only
}
_transform(chunk, encoding, callback) {
callback(null, chunk);
}
entry(ae, source, callback) {
source = source || null;
if (typeof callback !== "function") {
callback = this._emitErrorCallback.bind(this);
}
if (!(ae instanceof ArchiveEntry)) {
callback(new Error("not a valid instance of ArchiveEntry"));
return;
}
if (this._archive.finish || this._archive.finished) {
callback(new Error("unacceptable entry after finish"));
return;
}
if (this._archive.processing) {
callback(new Error("already processing an entry"));
return;
}
this._archive.processing = true;
this._normalizeEntry(ae);
this._entry = ae;
source = normalizeInputSource(source);
if (Buffer.isBuffer(source)) {
this._appendBuffer(ae, source, callback);
} else if (isStream(source)) {
this._appendStream(ae, source, callback);
} else {
this._archive.processing = false;
callback(
new Error("input source must be valid Stream or Buffer instance"),
);
return;
}
return this;
}
finish() {
if (this._archive.processing) {
this._archive.finish = true;
return;
}
this._finish();
}
getBytesWritten() {
return this.offset;
}
write(chunk, cb) {
if (chunk) {
this.offset += chunk.length;
}
return super.write(chunk, cb);
}
}
+100
View File
@@ -0,0 +1,100 @@
export const WORD = 4;
export const DWORD = 8;
export const EMPTY = Buffer.alloc(0);
export const SHORT = 2;
export const SHORT_MASK = 0xffff;
export const SHORT_SHIFT = 16;
export const SHORT_ZERO = Buffer.from(Array(2));
export const LONG = 4;
export const LONG_ZERO = Buffer.from(Array(4));
export const MIN_VERSION_INITIAL = 10;
export const MIN_VERSION_DATA_DESCRIPTOR = 20;
export const MIN_VERSION_ZIP64 = 45;
export const VERSION_MADEBY = 45;
export const METHOD_STORED = 0;
export const METHOD_DEFLATED = 8;
export const PLATFORM_UNIX = 3;
export const PLATFORM_FAT = 0;
export const SIG_LFH = 0x04034b50;
export const SIG_DD = 0x08074b50;
export const SIG_CFH = 0x02014b50;
export const SIG_EOCD = 0x06054b50;
export const SIG_ZIP64_EOCD = 0x06064b50;
export const SIG_ZIP64_EOCD_LOC = 0x07064b50;
export const ZIP64_MAGIC_SHORT = 0xffff;
export const ZIP64_MAGIC = 0xffffffff;
export const ZIP64_EXTRA_ID = 0x0001;
export const ZLIB_NO_COMPRESSION = 0;
export const ZLIB_BEST_SPEED = 1;
export const ZLIB_BEST_COMPRESSION = 9;
export const ZLIB_DEFAULT_COMPRESSION = -1;
export const MODE_MASK = 0xfff;
export const DEFAULT_FILE_MODE = 33188;
export const DEFAULT_DIR_MODE = 16877;
export const EXT_FILE_ATTR_DIR = 1106051088;
export const EXT_FILE_ATTR_FILE = 2175008800;
export const S_IFMT = 61440;
export const S_IFIFO = 4096;
export const S_IFCHR = 8192;
export const S_IFDIR = 16384;
export const S_IFBLK = 24576;
export const S_IFREG = 32768;
export const S_IFLNK = 40960;
export const S_IFSOCK = 49152;
export const S_DOS_A = 32;
export const S_DOS_D = 16;
export const S_DOS_V = 8;
export const S_DOS_S = 4;
export const S_DOS_H = 2;
export const S_DOS_R = 1; // 01 Read Only
export default {
WORD,
DWORD,
EMPTY,
SHORT,
SHORT_MASK,
SHORT_SHIFT,
SHORT_ZERO,
LONG,
LONG_ZERO,
MIN_VERSION_INITIAL,
MIN_VERSION_DATA_DESCRIPTOR,
MIN_VERSION_ZIP64,
VERSION_MADEBY,
METHOD_STORED,
METHOD_DEFLATED,
PLATFORM_UNIX,
PLATFORM_FAT,
SIG_LFH,
SIG_DD,
SIG_CFH,
SIG_EOCD,
SIG_ZIP64_EOCD,
SIG_ZIP64_EOCD_LOC,
ZIP64_MAGIC_SHORT,
ZIP64_MAGIC,
ZIP64_EXTRA_ID,
ZLIB_NO_COMPRESSION,
ZLIB_BEST_SPEED,
ZLIB_BEST_COMPRESSION,
ZLIB_DEFAULT_COMPRESSION,
MODE_MASK,
DEFAULT_FILE_MODE,
DEFAULT_DIR_MODE,
EXT_FILE_ATTR_DIR,
EXT_FILE_ATTR_FILE,
S_IFMT,
S_IFIFO,
S_IFCHR,
S_IFDIR,
S_IFBLK,
S_IFREG,
S_IFLNK,
S_IFSOCK,
S_DOS_A,
S_DOS_D,
S_DOS_V,
S_DOS_S,
S_DOS_H,
S_DOS_R,
};
+79
View File
@@ -0,0 +1,79 @@
import { getShortBytes, getShortBytesValue } from "./util.js";
var DATA_DESCRIPTOR_FLAG = 1 << 3;
var ENCRYPTION_FLAG = 1 << 0;
var NUMBER_OF_SHANNON_FANO_TREES_FLAG = 1 << 2;
var SLIDING_DICTIONARY_SIZE_FLAG = 1 << 1;
var STRONG_ENCRYPTION_FLAG = 1 << 6;
var UFT8_NAMES_FLAG = 1 << 11;
export default class GeneralPurposeBit {
constructor() {
this.descriptor = false;
this.encryption = false;
this.utf8 = false;
this.numberOfShannonFanoTrees = 0;
this.strongEncryption = false;
this.slidingDictionarySize = 0;
return this;
}
encode() {
return getShortBytes(
(this.descriptor ? DATA_DESCRIPTOR_FLAG : 0) |
(this.utf8 ? UFT8_NAMES_FLAG : 0) |
(this.encryption ? ENCRYPTION_FLAG : 0) |
(this.strongEncryption ? STRONG_ENCRYPTION_FLAG : 0),
);
}
static parse(buf, offset) {
var flag = getShortBytesValue(buf, offset);
var gbp = new GeneralPurposeBit();
gbp.useDataDescriptor((flag & DATA_DESCRIPTOR_FLAG) !== 0);
gbp.useUTF8ForNames((flag & UFT8_NAMES_FLAG) !== 0);
gbp.useStrongEncryption((flag & STRONG_ENCRYPTION_FLAG) !== 0);
gbp.useEncryption((flag & ENCRYPTION_FLAG) !== 0);
gbp.setSlidingDictionarySize(
(flag & SLIDING_DICTIONARY_SIZE_FLAG) !== 0 ? 8192 : 4096,
);
gbp.setNumberOfShannonFanoTrees(
(flag & NUMBER_OF_SHANNON_FANO_TREES_FLAG) !== 0 ? 3 : 2,
);
return gbp;
}
setNumberOfShannonFanoTrees(n) {
this.numberOfShannonFanoTrees = n;
}
getNumberOfShannonFanoTrees() {
return this.numberOfShannonFanoTrees;
}
setSlidingDictionarySize(n) {
this.slidingDictionarySize = n;
}
getSlidingDictionarySize() {
return this.slidingDictionarySize;
}
useDataDescriptor(b) {
this.descriptor = b;
}
usesDataDescriptor() {
return this.descriptor;
}
useEncryption(b) {
this.encryption = b;
}
usesEncryption() {
return this.encryption;
}
useStrongEncryption(b) {
this.strongEncryption = b;
}
usesStrongEncryption() {
return this.strongEncryption;
}
useUTF8ForNames(b) {
this.utf8 = b;
}
usesUTF8ForNames() {
return this.utf8;
}
}
+19
View File
@@ -0,0 +1,19 @@
export const PERM_MASK = 4095;
export const FILE_TYPE_FLAG = 61440;
export const LINK_FLAG = 40960;
export const FILE_FLAG = 32768;
export const DIR_FLAG = 16384;
export const DEFAULT_LINK_PERM = 511;
export const DEFAULT_DIR_PERM = 493;
export const DEFAULT_FILE_PERM = 420; // 0644
export default {
PERM_MASK,
FILE_TYPE_FLAG,
LINK_FLAG,
FILE_FLAG,
DIR_FLAG,
DEFAULT_LINK_PERM,
DEFAULT_DIR_PERM,
DEFAULT_FILE_PERM,
};
+74
View File
@@ -0,0 +1,74 @@
export function dateToDos(d, forceLocalTime) {
forceLocalTime = forceLocalTime || false;
var year = forceLocalTime ? d.getFullYear() : d.getUTCFullYear();
if (year < 1980) {
return 2162688; // 1980-1-1 00:00:00
} else if (year >= 2044) {
return 2141175677; // 2043-12-31 23:59:58
}
var val = {
year: year,
month: forceLocalTime ? d.getMonth() : d.getUTCMonth(),
date: forceLocalTime ? d.getDate() : d.getUTCDate(),
hours: forceLocalTime ? d.getHours() : d.getUTCHours(),
minutes: forceLocalTime ? d.getMinutes() : d.getUTCMinutes(),
seconds: forceLocalTime ? d.getSeconds() : d.getUTCSeconds(),
};
return (
((val.year - 1980) << 25) |
((val.month + 1) << 21) |
(val.date << 16) |
(val.hours << 11) |
(val.minutes << 5) |
(val.seconds / 2)
);
}
export function dosToDate(dos) {
return new Date(
((dos >> 25) & 0x7f) + 1980,
((dos >> 21) & 0x0f) - 1,
(dos >> 16) & 0x1f,
(dos >> 11) & 0x1f,
(dos >> 5) & 0x3f,
(dos & 0x1f) << 1,
);
}
export function fromDosTime(buf) {
return dosToDate(buf.readUInt32LE(0));
}
export function getEightBytes(v) {
var buf = Buffer.alloc(8);
buf.writeUInt32LE(v % 0x0100000000, 0);
buf.writeUInt32LE((v / 0x0100000000) | 0, 4);
return buf;
}
export function getShortBytes(v) {
var buf = Buffer.alloc(2);
buf.writeUInt16LE((v & 0xffff) >>> 0, 0);
return buf;
}
export function getShortBytesValue(buf, offset) {
return buf.readUInt16LE(offset);
}
export function getLongBytes(v) {
var buf = Buffer.alloc(4);
buf.writeUInt32LE((v & 0xffffffff) >>> 0, 0);
return buf;
}
export function getLongBytesValue(buf, offset) {
return buf.readUInt32LE(offset);
}
export function toDosTime(d) {
return getLongBytes(util.dateToDos(d));
}
export default {
dateToDos,
dosToDate,
fromDosTime,
getEightBytes,
getShortBytes,
getShortBytesValue,
getLongBytes,
getLongBytesValue,
toDosTime,
};
+380
View File
@@ -0,0 +1,380 @@
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;
}
}
@@ -0,0 +1,371 @@
import { inherits } from "util";
import crc32 from "crc-32";
import { CRC32Stream, DeflateCRC32Stream } from "crc32-stream";
import ArchiveOutputStream from "../archive-output-stream.js";
import ZipArchiveEntry from "./zip-archive-entry.js";
import GeneralPurposeBit from "./general-purpose-bit.js";
import {
LONG_ZERO,
METHOD_DEFLATED,
METHOD_STORED,
MIN_VERSION_DATA_DESCRIPTOR,
MIN_VERSION_ZIP64,
SHORT_ZERO,
SIG_EOCD,
SIG_DD,
SIG_CFH,
SIG_LFH,
SIG_ZIP64_EOCD,
SIG_ZIP64_EOCD_LOC,
VERSION_MADEBY,
ZIP64_EXTRA_ID,
ZIP64_MAGIC,
ZIP64_MAGIC_SHORT,
ZLIB_BEST_SPEED,
} from "./constants.js";
import { getEightBytes, getLongBytes, getShortBytes } from "./util.js";
function _defaults(o) {
if (typeof o !== "object") {
o = {};
}
if (typeof o.zlib !== "object") {
o.zlib = {};
}
if (typeof o.zlib.level !== "number") {
o.zlib.level = ZLIB_BEST_SPEED;
}
o.forceZip64 = !!o.forceZip64;
o.forceLocalTime = !!o.forceLocalTime;
return o;
}
export default class ZipArchiveOutputStream extends ArchiveOutputStream {
constructor(options) {
const _options = _defaults(options);
super(_options);
this.options = _options;
this._entry = null;
this._entries = [];
this._archive = {
centralLength: 0,
centralOffset: 0,
comment: "",
finish: false,
finished: false,
processing: false,
forceZip64: _options.forceZip64,
forceLocalTime: _options.forceLocalTime,
};
}
_afterAppend(ae) {
this._entries.push(ae);
if (ae.getGeneralPurposeBit().usesDataDescriptor()) {
this._writeDataDescriptor(ae);
}
this._archive.processing = false;
this._entry = null;
if (this._archive.finish && !this._archive.finished) {
this._finish();
}
}
_appendBuffer(ae, source, callback) {
if (source.length === 0) {
ae.setMethod(METHOD_STORED);
}
var method = ae.getMethod();
if (method === METHOD_STORED) {
ae.setSize(source.length);
ae.setCompressedSize(source.length);
ae.setCrc(crc32.buf(source) >>> 0);
}
this._writeLocalFileHeader(ae);
if (method === METHOD_STORED) {
this.write(source);
this._afterAppend(ae);
callback(null, ae);
return;
} else if (method === METHOD_DEFLATED) {
this._smartStream(ae, callback).end(source);
return;
} else {
callback(new Error("compression method " + method + " not implemented"));
return;
}
}
_appendStream(ae, source, callback) {
ae.getGeneralPurposeBit().useDataDescriptor(true);
ae.setVersionNeededToExtract(MIN_VERSION_DATA_DESCRIPTOR);
this._writeLocalFileHeader(ae);
var smart = this._smartStream(ae, callback);
source.once("error", function (err) {
smart.emit("error", err);
smart.end();
});
source.pipe(smart);
}
_finish() {
this._archive.centralOffset = this.offset;
this._entries.forEach(
function (ae) {
this._writeCentralFileHeader(ae);
}.bind(this),
);
this._archive.centralLength = this.offset - this._archive.centralOffset;
if (this.isZip64()) {
this._writeCentralDirectoryZip64();
}
this._writeCentralDirectoryEnd();
this._archive.processing = false;
this._archive.finish = true;
this._archive.finished = true;
this.end();
}
_normalizeEntry(ae) {
if (ae.getMethod() === -1) {
ae.setMethod(METHOD_DEFLATED);
}
if (ae.getMethod() === METHOD_DEFLATED) {
ae.getGeneralPurposeBit().useDataDescriptor(true);
ae.setVersionNeededToExtract(MIN_VERSION_DATA_DESCRIPTOR);
}
if (ae.getTime() === -1) {
ae.setTime(new Date(), this._archive.forceLocalTime);
}
ae._offsets = {
file: 0,
data: 0,
contents: 0,
};
}
_smartStream(ae, callback) {
var deflate = ae.getMethod() === METHOD_DEFLATED;
var process = deflate
? new DeflateCRC32Stream(this.options.zlib)
: new CRC32Stream();
var error = null;
function handleStuff() {
var digest = process.digest().readUInt32BE(0);
ae.setCrc(digest);
ae.setSize(process.size());
ae.setCompressedSize(process.size(true));
this._afterAppend(ae);
callback(error, ae);
}
process.once("end", handleStuff.bind(this));
process.once("error", function (err) {
error = err;
});
process.pipe(this, { end: false });
return process;
}
_writeCentralDirectoryEnd() {
var records = this._entries.length;
var size = this._archive.centralLength;
var offset = this._archive.centralOffset;
if (this.isZip64()) {
records = ZIP64_MAGIC_SHORT;
size = ZIP64_MAGIC;
offset = ZIP64_MAGIC;
}
// signature
this.write(getLongBytes(SIG_EOCD));
// disk numbers
this.write(SHORT_ZERO);
this.write(SHORT_ZERO);
// number of entries
this.write(getShortBytes(records));
this.write(getShortBytes(records));
// length and location of CD
this.write(getLongBytes(size));
this.write(getLongBytes(offset));
// archive comment
var comment = this.getComment();
var commentLength = Buffer.byteLength(comment);
this.write(getShortBytes(commentLength));
this.write(comment);
}
_writeCentralDirectoryZip64() {
// signature
this.write(getLongBytes(SIG_ZIP64_EOCD));
// size of the ZIP64 EOCD record
this.write(getEightBytes(44));
// version made by
this.write(getShortBytes(MIN_VERSION_ZIP64));
// version to extract
this.write(getShortBytes(MIN_VERSION_ZIP64));
// disk numbers
this.write(LONG_ZERO);
this.write(LONG_ZERO);
// number of entries
this.write(getEightBytes(this._entries.length));
this.write(getEightBytes(this._entries.length));
// length and location of CD
this.write(getEightBytes(this._archive.centralLength));
this.write(getEightBytes(this._archive.centralOffset));
// extensible data sector
// not implemented at this time
// end of central directory locator
this.write(getLongBytes(SIG_ZIP64_EOCD_LOC));
// disk number holding the ZIP64 EOCD record
this.write(LONG_ZERO);
// relative offset of the ZIP64 EOCD record
this.write(
getEightBytes(this._archive.centralOffset + this._archive.centralLength),
);
// total number of disks
this.write(getLongBytes(1));
}
_writeCentralFileHeader(ae) {
var gpb = ae.getGeneralPurposeBit();
var method = ae.getMethod();
var fileOffset = ae._offsets.file;
var size = ae.getSize();
var compressedSize = ae.getCompressedSize();
if (ae.isZip64() || fileOffset > ZIP64_MAGIC) {
size = ZIP64_MAGIC;
compressedSize = ZIP64_MAGIC;
fileOffset = ZIP64_MAGIC;
ae.setVersionNeededToExtract(MIN_VERSION_ZIP64);
var extraBuf = Buffer.concat(
[
getShortBytes(ZIP64_EXTRA_ID),
getShortBytes(24),
getEightBytes(ae.getSize()),
getEightBytes(ae.getCompressedSize()),
getEightBytes(ae._offsets.file),
],
28,
);
ae.setExtra(extraBuf);
}
// signature
this.write(getLongBytes(SIG_CFH));
// version made by
this.write(getShortBytes((ae.getPlatform() << 8) | VERSION_MADEBY));
// version to extract and general bit flag
this.write(getShortBytes(ae.getVersionNeededToExtract()));
this.write(gpb.encode());
// compression method
this.write(getShortBytes(method));
// datetime
this.write(getLongBytes(ae.getTimeDos()));
// crc32 checksum
this.write(getLongBytes(ae.getCrc()));
// sizes
this.write(getLongBytes(compressedSize));
this.write(getLongBytes(size));
var name = ae.getName();
var comment = ae.getComment();
var extra = ae.getCentralDirectoryExtra();
if (gpb.usesUTF8ForNames()) {
name = Buffer.from(name);
comment = Buffer.from(comment);
}
// name length
this.write(getShortBytes(name.length));
// extra length
this.write(getShortBytes(extra.length));
// comments length
this.write(getShortBytes(comment.length));
// disk number start
this.write(SHORT_ZERO);
// internal attributes
this.write(getShortBytes(ae.getInternalAttributes()));
// external attributes
this.write(getLongBytes(ae.getExternalAttributes()));
// relative offset of LFH
this.write(getLongBytes(fileOffset));
// name
this.write(name);
// extra
this.write(extra);
// comment
this.write(comment);
}
_writeDataDescriptor(ae) {
// signature
this.write(getLongBytes(SIG_DD));
// crc32 checksum
this.write(getLongBytes(ae.getCrc()));
// sizes
if (ae.isZip64()) {
this.write(getEightBytes(ae.getCompressedSize()));
this.write(getEightBytes(ae.getSize()));
} else {
this.write(getLongBytes(ae.getCompressedSize()));
this.write(getLongBytes(ae.getSize()));
}
}
_writeLocalFileHeader(ae) {
var gpb = ae.getGeneralPurposeBit();
var method = ae.getMethod();
var name = ae.getName();
var extra = ae.getLocalFileDataExtra();
if (ae.isZip64()) {
gpb.useDataDescriptor(true);
ae.setVersionNeededToExtract(MIN_VERSION_ZIP64);
}
if (gpb.usesUTF8ForNames()) {
name = Buffer.from(name);
}
ae._offsets.file = this.offset;
// signature
this.write(getLongBytes(SIG_LFH));
// version to extract and general bit flag
this.write(getShortBytes(ae.getVersionNeededToExtract()));
this.write(gpb.encode());
// compression method
this.write(getShortBytes(method));
// datetime
this.write(getLongBytes(ae.getTimeDos()));
ae._offsets.data = this.offset;
// crc32 checksum and sizes
if (gpb.usesDataDescriptor()) {
this.write(LONG_ZERO);
this.write(LONG_ZERO);
this.write(LONG_ZERO);
} else {
this.write(getLongBytes(ae.getCrc()));
this.write(getLongBytes(ae.getCompressedSize()));
this.write(getLongBytes(ae.getSize()));
}
// name length
this.write(getShortBytes(name.length));
// extra length
this.write(getShortBytes(extra.length));
// name
this.write(name);
// extra
this.write(extra);
ae._offsets.contents = this.offset;
}
getComment(comment) {
return this._archive.comment !== null ? this._archive.comment : "";
}
isZip64() {
return (
this._archive.forceZip64 ||
this._entries.length > ZIP64_MAGIC_SHORT ||
this._archive.centralLength > ZIP64_MAGIC ||
this._archive.centralOffset > ZIP64_MAGIC
);
}
setComment(comment) {
this._archive.comment = comment;
}
}
+18
View File
@@ -0,0 +1,18 @@
import ArchiveEntry from "./archivers/archive-entry.js";
import ZipArchiveEntry from "./archivers/zip/zip-archive-entry.js";
import ArchiveOutputStream from "./archivers/archive-output-stream.js";
import ZipArchiveOutputStream from "./archivers/zip/zip-archive-output-stream.js";
export {
ArchiveEntry,
ZipArchiveEntry,
ArchiveOutputStream,
ZipArchiveOutputStream,
};
export default {
ArchiveEntry,
ZipArchiveEntry,
ArchiveOutputStream,
ZipArchiveOutputStream,
};
+20
View File
@@ -0,0 +1,20 @@
import { Stream } from "stream";
import { PassThrough } from "readable-stream";
import { isStream } from "is-stream";
export function normalizeInputSource(source) {
if (source === null) {
return Buffer.alloc(0);
} else if (typeof source === "string") {
return Buffer.from(source);
} else if (isStream(source) && !source._readableState) {
var normalized = new PassThrough();
source.pipe(normalized);
return normalized;
}
return source;
}
export default {
normalizeInputSource,
};