Skip to content

Commit

Permalink
parseExtraFields()
Browse files Browse the repository at this point in the history
  • Loading branch information
thejoshwolfe committed Feb 18, 2024
1 parent 5967cb5 commit ea39614
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 17 deletions.
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,18 @@ if (errorMessage != null) throw new Error(errorMessage);
This function is automatically run for each entry, as long as `decodeStrings` is `true`.
See `open()`, `strictFileNames`, and `Event: "entry"` for more information.

### parseExtraFields(extraFieldBuffer)

This function is used internally by yauzl to compute [`entry.extraFields`](#extrafields).
It is exported in case you want to call it on [`localFileHeader.extraField`](#class-localfileheader).

`extraFieldBuffer` is a `Buffer`, such as `localFileHeader.extraField`.
Returns an `Array` with each item in the form `{id: id, data: data}`,
where `id` is a `Number` and `data` is a `Buffer`.
Throws an `Error` if the data encodes an item with a size that exceeds the bounds of the buffer.

You may want to surround calls to this function with `try { ... } catch (err) { ... }` to handle the error.

### Class: ZipFile

The constructor for the class is not part of the public API.
Expand Down Expand Up @@ -437,7 +449,7 @@ Furthermore, no automatic file name validation is performed for this file name.

#### extraFields

`Array` with each entry in the form `{id: id, data: data}`,
`Array` with each item in the form `{id: id, data: data}`,
where `id` is a `Number` and `data` is a `Buffer`.

This library looks for and reads the ZIP64 Extended Information Extra Field (0x0001)
Expand Down Expand Up @@ -520,6 +532,7 @@ See the zipfile spec for what these fields mean.

Note that unlike `Class: Entry`, the `fileName` and `extraField` are completely unprocessed.
This notably lacks Unicode and ZIP64 handling as well as any kind of safety validation on the file name.
See also [`parseExtraFields()`](#parseextrafields-extrafieldbuffer).

Also note that if your object is missing some of these fields,
make sure to read the docs on the `minimal` option in `readLocalFileHeader()`.
Expand Down
40 changes: 25 additions & 15 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ exports.fromBuffer = fromBuffer;
exports.fromRandomAccessReader = fromRandomAccessReader;
exports.dosDateTimeToDate = dosDateTimeToDate;
exports.validateFileName = validateFileName;
exports.parseExtraFields = parseExtraFields;
exports.ZipFile = ZipFile;
exports.Entry = Entry;
exports.LocalFileHeader = LocalFileHeader;
Expand Down Expand Up @@ -305,21 +306,10 @@ ZipFile.prototype._readEntry = function() {
// 46+n - Extra field
var fileCommentStart = entry.fileNameLength + entry.extraFieldLength;
var extraFieldBuffer = buffer.slice(entry.fileNameLength, fileCommentStart);
entry.extraFields = [];
var i = 0;
while (i < extraFieldBuffer.length - 3) {
var headerId = extraFieldBuffer.readUInt16LE(i + 0);
var dataSize = extraFieldBuffer.readUInt16LE(i + 2);
var dataStart = i + 4;
var dataEnd = dataStart + dataSize;
if (dataEnd > extraFieldBuffer.length) return emitErrorAndAutoClose(self, new Error("extra field length exceeds extra field buffer size"));
var dataBuffer = newBuffer(dataSize);
extraFieldBuffer.copy(dataBuffer, 0, dataStart, dataEnd);
entry.extraFields.push({
id: headerId,
data: dataBuffer,
});
i = dataEnd;
try {
entry.extraFields = parseExtraFields(extraFieldBuffer);
} catch (err) {
return emitErrorAndAutoClose(self, err);
}

// 46+n+m - File comment
Expand Down Expand Up @@ -670,6 +660,26 @@ function validateFileName(fileName) {
return null;
}

function parseExtraFields(extraFieldBuffer) {
var extraFields = [];
var i = 0;
while (i < extraFieldBuffer.length - 3) {
var headerId = extraFieldBuffer.readUInt16LE(i + 0);
var dataSize = extraFieldBuffer.readUInt16LE(i + 2);
var dataStart = i + 4;
var dataEnd = dataStart + dataSize;
if (dataEnd > extraFieldBuffer.length) throw new Error("extra field length exceeds extra field buffer size");
var dataBuffer = newBuffer(dataSize);
extraFieldBuffer.copy(dataBuffer, 0, dataStart, dataEnd);
extraFields.push({
id: headerId,
data: dataBuffer,
});
i = dataEnd;
}
return extraFields;
}

function readAndAssertNoEof(reader, buffer, offset, length, position, callback) {
if (length === 0) {
// fs.read will throw an out-of-bounds error if you try to read 0 bytes from a 0 byte file
Expand Down
2 changes: 1 addition & 1 deletion test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ listZipFiles([path.join(__dirname, "success"), path.join(__dirname, "wrong-entry
// Do this asynchronously because it's not critical,
// and this way it might find race condition bugs with autoclose.
zipfile.readLocalFileHeader(entry, function(err, localFileHeader) {
// This is the one field unique to the local file header.
// Just check one of non-minumal fields fields.
if (localFileHeader.versionNeededToExtract == null) throw new Error(messagePrefix + "local file header missing versionNeededToExtract field");
// This field is the most mechnically important field.
if (localFileHeader.fileDataStart == null) throw new Error(messagePrefix + "local file header missing fileDataStart field");
Expand Down

0 comments on commit ea39614

Please sign in to comment.