Skip to content

Commit

Permalink
move local header creation to zipEntry file
Browse files Browse the repository at this point in the history
  • Loading branch information
5saviahv committed May 18, 2024
1 parent 21a4023 commit f0d945b
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 56 deletions.
14 changes: 7 additions & 7 deletions headers/entryHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ module.exports = function () {
// Without it file names may be corrupted for other apps when file names use unicode chars
_flags |= Constants.FLG_EFS;

var _dataHeader = {};
var _localHeader = {};

function setTime(val) {
val = new Date(val);
Expand Down Expand Up @@ -170,20 +170,20 @@ module.exports = function () {
},

get realDataOffset() {
return _offset + Constants.LOCHDR + _dataHeader.fnameLen + _dataHeader.extraLen;
return _offset + Constants.LOCHDR + _localHeader.fnameLen + _localHeader.extraLen;
},

get dataHeader() {
return _dataHeader;
get localHeader() {
return _localHeader;
},

loadDataHeaderFromBinary: function (/*Buffer*/ input) {
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 new Error(Utils.Errors.INVALID_LOC);
}
_dataHeader = {
_localHeader = {
// version needed to extract
version: data.readUInt16LE(Constants.LOCVER),
// general purpose bit flag
Expand Down Expand Up @@ -242,7 +242,7 @@ module.exports = function () {
_offset = data.readUInt32LE(Constants.CENOFF);
},

dataHeaderToBinary: function () {
localHeaderToBinary: function () {
// LOC header size (30 bytes)
var data = Buffer.alloc(Constants.LOCHDR);
// "PK\003\004"
Expand Down
26 changes: 13 additions & 13 deletions test/header.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,10 @@ describe("headers", () => {
expect(head.entryHeaderSize).to.equal(446);
});

describe("data-header", () => {
const dataheader = Buffer.from("504b030414000008080045618102efbeadde000100000002000000000000", "hex");
describe("local-header", () => {
const localHeader = Buffer.from("504b030414000008080045618102efbeadde000100000002000000000000", "hex");

const dataHeaderValues = {
const localHeaderValues = {
compressedSize: 0x100,
crc: 0xdeadbeef,
extraLen: 0,
Expand All @@ -197,22 +197,22 @@ describe("headers", () => {
it("compare binary header values with predetermined values", () => {
const head = new entryHeader();
head.loadFromBinary(readBuf);
head.loadDataHeaderFromBinary(dataheader);
head.loadLocalHeaderFromBinary(localHeader);

for (const name in dataHeaderValues) {
expect(head.dataHeader[name]).to.equal(dataHeaderValues[name]);
for (const name in localHeaderValues) {
expect(head.localHeader[name]).to.equal(localHeaderValues[name]);
}
});

it("read binary and create new binary from it, they have to be equal", () => {
const head = new entryHeader();
head.loadFromBinary(readBuf);
head.loadDataHeaderFromBinary(dataheader);
head.loadLocalHeaderFromBinary(localHeader);

const buf = head.dataHeaderToBinary();
const buf = head.localHeaderToBinary();

expect(buf.length).to.equal(dataheader.length);
expect(buf).to.eql(dataheader);
expect(buf.length).to.equal(localHeader.length);
expect(buf).to.eql(localHeader);
});

it("construct header by values and compare binaries have to be equal", () => {
Expand All @@ -229,10 +229,10 @@ describe("headers", () => {
// if time is constructed by new Date() it is also in local zone and so it cancels possible timezone difference
head.time = new Date(...datestamp);

const buf = head.dataHeaderToBinary();
const buf = head.localHeaderToBinary();

expect(buf.length).to.equal(dataheader.length);
expect(buf).to.eql(dataheader);
expect(buf.length).to.equal(localHeader.length);
expect(buf).to.eql(localHeader);
});
});
});
Expand Down
26 changes: 23 additions & 3 deletions zipEntry.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ module.exports = function (/*Buffer*/ input) {
if (!input || !Buffer.isBuffer(input)) {
return Buffer.alloc(0);
}
_entryHeader.loadDataHeaderFromBinary(input);
_entryHeader.loadLocalHeaderFromBinary(input);
return input.slice(_entryHeader.realDataOffset, _entryHeader.realDataOffset + _entryHeader.compressedSize);
}

function crc32OK(data) {
// if bit 3 (0x08) of the general-purpose flags field is set, then the CRC-32 and file sizes are not known when the header is written
if ((_entryHeader.flags & 0x8) !== 0x8) {
if (Utils.crc32(data) !== _entryHeader.dataHeader.crc) {
if (Utils.crc32(data) !== _entryHeader.localHeader.crc) {
return false;
}
} else {
Expand Down Expand Up @@ -291,7 +291,7 @@ module.exports = function (/*Buffer*/ input) {
return _entryHeader;
},

packHeader: function () {
packCentralHeader: function () {
// 1. create header (buffer)
var header = _entryHeader.entryHeaderToBinary();
var addpos = Utils.Constants.CENHDR;
Expand All @@ -310,6 +310,26 @@ module.exports = function (/*Buffer*/ input) {
return header;
},

packLocalHeader: function () {
let addpos = 0;

// 1. construct local header Buffer
const localHeaderBuf = _entryHeader.localHeaderToBinary();
// 2. localHeader - crate header buffer
const localHeader = Buffer.alloc(localHeaderBuf.length + _entryName.length + _extra.length);
// 2.1 add localheader
localHeaderBuf.copy(localHeader, addpos);
addpos += localHeaderBuf.length;
// 2.2 add file name
_entryName.copy(localHeader, addpos);
addpos += _entryName.length;
// 2.3 add extra field
_extra.copy(localHeader, addpos);
addpos += _extra.length;

return localHeader;
},

toJSON: function () {
const bytes = function (nr) {
return "<" + ((nr && nr.length + " bytes buffer") || "null") + ">";
Expand Down
62 changes: 29 additions & 33 deletions zipFile.js
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ module.exports = function (/*Buffer|null*/ inBuffer, /** object */ options) {
sortEntries();

const dataBlock = [];
const entryHeaders = [];
const headerBlocks = [];
let totalSize = 0;
let dindex = 0;

Expand All @@ -253,30 +253,25 @@ module.exports = function (/*Buffer|null*/ inBuffer, /** object */ options) {
for (const entry of entryList) {
// compress data and set local and entry header accordingly. Reason why is called first
const compressedData = entry.getCompressedData();
// 1. construct data header
entry.header.offset = dindex;
const dataHeader = entry.header.dataHeaderToBinary();
const entryNameLen = entry.rawEntryName.length;
// 1.2. postheader - data after data header
const postHeader = Buffer.alloc(entryNameLen + entry.extra.length);
entry.rawEntryName.copy(postHeader, 0);
entry.extra.copy(postHeader, entryNameLen);

// 1. construct local header
const localHeader = entry.packLocalHeader();

// 2. offsets
const dataLength = dataHeader.length + postHeader.length + compressedData.length;
const dataLength = localHeader.length + compressedData.length;
dindex += dataLength;

// 3. store values in sequence
dataBlock.push(dataHeader);
dataBlock.push(postHeader);
dataBlock.push(localHeader);
dataBlock.push(compressedData);

// 4. construct entry header
const entryHeader = entry.packHeader();
entryHeaders.push(entryHeader);
// 4. construct central header
const centralHeader = entry.packCentralHeader();
headerBlocks.push(centralHeader);
// 5. update main header
mainHeader.size += entryHeader.length;
totalSize += dataLength + entryHeader.length;
mainHeader.size += centralHeader.length;
totalSize += dataLength + centralHeader.length;
}

totalSize += mainHeader.mainHeaderSize; // also includes zip file comment length
Expand All @@ -292,7 +287,7 @@ module.exports = function (/*Buffer|null*/ inBuffer, /** object */ options) {
}

// write central directory entries
for (const content of entryHeaders) {
for (const content of headerBlocks) {
content.copy(outBuffer, dindex);
dindex += content.length;
}
Expand All @@ -315,37 +310,38 @@ module.exports = function (/*Buffer|null*/ inBuffer, /** object */ options) {
sortEntries();

const dataBlock = [];
const entryHeaders = [];
const centralHeaders = [];
let totalSize = 0;
let dindex = 0;

mainHeader.size = 0;
mainHeader.offset = 0;

const compress2Buffer = function (entryLists) {
if (entryLists.length) {
const entry = entryLists.pop();
if (entryLists.length > 0) {
const entry = entryLists.shift();
const name = entry.entryName + entry.extra.toString();
if (onItemStart) onItemStart(name);
entry.getCompressedDataAsync(function (compressedData) {
if (onItemEnd) onItemEnd(name);

entry.header.offset = dindex;
// data header
const dataHeader = entry.header.dataHeaderToBinary();
const postHeader = Buffer.alloc(name.length, name);
const dataLength = dataHeader.length + postHeader.length + compressedData.length;

// 1. construct local header
const localHeader = entry.packLocalHeader();

// 2. offsets
const dataLength = localHeader.length + compressedData.length;
dindex += dataLength;

dataBlock.push(dataHeader);
dataBlock.push(postHeader);
// 3. store values in sequence
dataBlock.push(localHeader);
dataBlock.push(compressedData);

const entryHeader = entry.packHeader();
entryHeaders.push(entryHeader);
mainHeader.size += entryHeader.length;
totalSize += dataLength + entryHeader.length;
// central header
const centalHeader = entry.packCentralHeader();
centralHeaders.push(centalHeader);
mainHeader.size += centalHeader.length;
totalSize += dataLength + centalHeader.length;

compress2Buffer(entryLists);
});
Expand All @@ -360,7 +356,7 @@ module.exports = function (/*Buffer|null*/ inBuffer, /** object */ options) {
content.copy(outBuffer, dindex); // write data blocks
dindex += content.length;
});
entryHeaders.forEach(function (content) {
centralHeaders.forEach(function (content) {
content.copy(outBuffer, dindex); // write central directory entries
dindex += content.length;
});
Expand All @@ -376,7 +372,7 @@ module.exports = function (/*Buffer|null*/ inBuffer, /** object */ options) {
}
};

compress2Buffer(entryList);
compress2Buffer(Array.from(entryList));
} catch (e) {
onFail(e);
}
Expand Down

0 comments on commit f0d945b

Please sign in to comment.