| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374 | var Utils = require("../util"),    Constants = Utils.Constants;/* The central directory file header */module.exports = function () {    var _verMade = 20, // v2.0        _version = 10, // v1.0        _flags = 0,        _method = 0,        _time = 0,        _crc = 0,        _compressedSize = 0,        _size = 0,        _fnameLen = 0,        _extraLen = 0,        _comLen = 0,        _diskStart = 0,        _inattr = 0,        _attr = 0,        _offset = 0;    _verMade |= Utils.isWin ? 0x0a00 : 0x0300;    // Set EFS flag since filename and comment fields are all by default encoded using UTF-8.    // Without it file names may be corrupted for other apps when file names use unicode chars    _flags |= Constants.FLG_EFS;    const _localHeader = {        extraLen: 0    };    // casting    const uint32 = (val) => Math.max(0, val) >>> 0;    const uint16 = (val) => Math.max(0, val) & 0xffff;    const uint8 = (val) => Math.max(0, val) & 0xff;    _time = Utils.fromDate2DOS(new Date());    return {        get made() {            return _verMade;        },        set made(val) {            _verMade = val;        },        get version() {            return _version;        },        set version(val) {            _version = val;        },        get flags() {            return _flags;        },        set flags(val) {            _flags = val;        },        get flags_efs() {            return (_flags & Constants.FLG_EFS) > 0;        },        set flags_efs(val) {            if (val) {                _flags |= Constants.FLG_EFS;            } else {                _flags &= ~Constants.FLG_EFS;            }        },        get flags_desc() {            return (_flags & Constants.FLG_DESC) > 0;        },        set flags_desc(val) {            if (val) {                _flags |= Constants.FLG_DESC;            } else {                _flags &= ~Constants.FLG_DESC;            }        },        get method() {            return _method;        },        set method(val) {            switch (val) {                case Constants.STORED:                    this.version = 10;                case Constants.DEFLATED:                default:                    this.version = 20;            }            _method = val;        },        get time() {            return Utils.fromDOS2Date(this.timeval);        },        set time(val) {            this.timeval = Utils.fromDate2DOS(val);        },        get timeval() {            return _time;        },        set timeval(val) {            _time = uint32(val);        },        get timeHighByte() {            return uint8(_time >>> 8);        },        get crc() {            return _crc;        },        set crc(val) {            _crc = uint32(val);        },        get compressedSize() {            return _compressedSize;        },        set compressedSize(val) {            _compressedSize = uint32(val);        },        get size() {            return _size;        },        set size(val) {            _size = uint32(val);        },        get fileNameLength() {            return _fnameLen;        },        set fileNameLength(val) {            _fnameLen = val;        },        get extraLength() {            return _extraLen;        },        set extraLength(val) {            _extraLen = val;        },        get extraLocalLength() {            return _localHeader.extraLen;        },        set extraLocalLength(val) {            _localHeader.extraLen = val;        },        get commentLength() {            return _comLen;        },        set commentLength(val) {            _comLen = val;        },        get diskNumStart() {            return _diskStart;        },        set diskNumStart(val) {            _diskStart = uint32(val);        },        get inAttr() {            return _inattr;        },        set inAttr(val) {            _inattr = uint32(val);        },        get attr() {            return _attr;        },        set attr(val) {            _attr = uint32(val);        },        // get Unix file permissions        get fileAttr() {            return (_attr || 0) >> 16 & 0xfff;        },        get offset() {            return _offset;        },        set offset(val) {            _offset = uint32(val);        },        get encrypted() {            return (_flags & Constants.FLG_ENC) === Constants.FLG_ENC;        },        get centralHeaderSize() {            return Constants.CENHDR + _fnameLen + _extraLen + _comLen;        },        get realDataOffset() {            return _offset + Constants.LOCHDR + _localHeader.fnameLen + _localHeader.extraLen;        },        get localHeader() {            return _localHeader;        },        loadLocalHeaderFromBinary: function (/*Buffer*/ input) {            var data = input.slice(_offset, _offset + Constants.LOCHDR);            // 30 bytes and should start with "PK\003\004"            if (data.readUInt32LE(0) !== Constants.LOCSIG) {                throw Utils.Errors.INVALID_LOC();            }            // version needed to extract            _localHeader.version = data.readUInt16LE(Constants.LOCVER);            // general purpose bit flag            _localHeader.flags = data.readUInt16LE(Constants.LOCFLG);            // compression method            _localHeader.method = data.readUInt16LE(Constants.LOCHOW);            // modification time (2 bytes time, 2 bytes date)            _localHeader.time = data.readUInt32LE(Constants.LOCTIM);            // uncompressed file crc-32 valu            _localHeader.crc = data.readUInt32LE(Constants.LOCCRC);            // compressed size            _localHeader.compressedSize = data.readUInt32LE(Constants.LOCSIZ);            // uncompressed size            _localHeader.size = data.readUInt32LE(Constants.LOCLEN);            // filename length            _localHeader.fnameLen = data.readUInt16LE(Constants.LOCNAM);            // extra field length            _localHeader.extraLen = data.readUInt16LE(Constants.LOCEXT);            // read extra data            const extraStart = _offset + Constants.LOCHDR + _localHeader.fnameLen;            const extraEnd = extraStart + _localHeader.extraLen;            return input.slice(extraStart, extraEnd);        },        loadFromBinary: function (/*Buffer*/ data) {            // data should be 46 bytes and start with "PK 01 02"            if (data.length !== Constants.CENHDR || data.readUInt32LE(0) !== Constants.CENSIG) {                throw Utils.Errors.INVALID_CEN();            }            // version made by            _verMade = data.readUInt16LE(Constants.CENVEM);            // version needed to extract            _version = data.readUInt16LE(Constants.CENVER);            // encrypt, decrypt flags            _flags = data.readUInt16LE(Constants.CENFLG);            // compression method            _method = data.readUInt16LE(Constants.CENHOW);            // modification time (2 bytes time, 2 bytes date)            _time = data.readUInt32LE(Constants.CENTIM);            // uncompressed file crc-32 value            _crc = data.readUInt32LE(Constants.CENCRC);            // compressed size            _compressedSize = data.readUInt32LE(Constants.CENSIZ);            // uncompressed size            _size = data.readUInt32LE(Constants.CENLEN);            // filename length            _fnameLen = data.readUInt16LE(Constants.CENNAM);            // extra field length            _extraLen = data.readUInt16LE(Constants.CENEXT);            // file comment length            _comLen = data.readUInt16LE(Constants.CENCOM);            // volume number start            _diskStart = data.readUInt16LE(Constants.CENDSK);            // internal file attributes            _inattr = data.readUInt16LE(Constants.CENATT);            // external file attributes            _attr = data.readUInt32LE(Constants.CENATX);            // LOC header offset            _offset = data.readUInt32LE(Constants.CENOFF);        },        localHeaderToBinary: function () {            // LOC header size (30 bytes)            var data = Buffer.alloc(Constants.LOCHDR);            // "PK\003\004"            data.writeUInt32LE(Constants.LOCSIG, 0);            // version needed to extract            data.writeUInt16LE(_version, Constants.LOCVER);            // general purpose bit flag            data.writeUInt16LE(_flags, Constants.LOCFLG);            // compression method            data.writeUInt16LE(_method, Constants.LOCHOW);            // modification time (2 bytes time, 2 bytes date)            data.writeUInt32LE(_time, Constants.LOCTIM);            // uncompressed file crc-32 value            data.writeUInt32LE(_crc, Constants.LOCCRC);            // compressed size            data.writeUInt32LE(_compressedSize, Constants.LOCSIZ);            // uncompressed size            data.writeUInt32LE(_size, Constants.LOCLEN);            // filename length            data.writeUInt16LE(_fnameLen, Constants.LOCNAM);            // extra field length            data.writeUInt16LE(_localHeader.extraLen, Constants.LOCEXT);            return data;        },        centralHeaderToBinary: function () {            // CEN header size (46 bytes)            var data = Buffer.alloc(Constants.CENHDR + _fnameLen + _extraLen + _comLen);            // "PK\001\002"            data.writeUInt32LE(Constants.CENSIG, 0);            // version made by            data.writeUInt16LE(_verMade, Constants.CENVEM);            // version needed to extract            data.writeUInt16LE(_version, Constants.CENVER);            // encrypt, decrypt flags            data.writeUInt16LE(_flags, Constants.CENFLG);            // compression method            data.writeUInt16LE(_method, Constants.CENHOW);            // modification time (2 bytes time, 2 bytes date)            data.writeUInt32LE(_time, Constants.CENTIM);            // uncompressed file crc-32 value            data.writeUInt32LE(_crc, Constants.CENCRC);            // compressed size            data.writeUInt32LE(_compressedSize, Constants.CENSIZ);            // uncompressed size            data.writeUInt32LE(_size, Constants.CENLEN);            // filename length            data.writeUInt16LE(_fnameLen, Constants.CENNAM);            // extra field length            data.writeUInt16LE(_extraLen, Constants.CENEXT);            // file comment length            data.writeUInt16LE(_comLen, Constants.CENCOM);            // volume number start            data.writeUInt16LE(_diskStart, Constants.CENDSK);            // internal file attributes            data.writeUInt16LE(_inattr, Constants.CENATT);            // external file attributes            data.writeUInt32LE(_attr, Constants.CENATX);            // LOC header offset            data.writeUInt32LE(_offset, Constants.CENOFF);            return data;        },        toJSON: function () {            const bytes = function (nr) {                return nr + " bytes";            };            return {                made: _verMade,                version: _version,                flags: _flags,                method: Utils.methodToString(_method),                time: this.time,                crc: "0x" + _crc.toString(16).toUpperCase(),                compressedSize: bytes(_compressedSize),                size: bytes(_size),                fileNameLength: bytes(_fnameLen),                extraLength: bytes(_extraLen),                commentLength: bytes(_comLen),                diskNumStart: _diskStart,                inAttr: _inattr,                attr: _attr,                offset: _offset,                centralHeaderSize: bytes(Constants.CENHDR + _fnameLen + _extraLen + _comLen)            };        },        toString: function () {            return JSON.stringify(this.toJSON(), null, "\t");        }    };};
 |