diff --git a/index.js b/index.js index 07cf107..4f93f47 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,7 @@ var fs = require("fs"); var zlib = require("zlib"); var fd_slicer = require("fd-slicer"); +var crc32 = require("buffer-crc32"); var util = require("util"); var EventEmitter = require("events").EventEmitter; var Transform = require("stream").Transform; @@ -341,6 +342,34 @@ ZipFile.prototype.readEntry = function() { // 24 - Disk Start Number 4 bytes } + // check for Info-ZIP Unicode Path Extra Field (0x7075) + // see https://github.com/thejoshwolfe/yauzl/issues/33 + for (var i = 0; i < entry.extraFields.length; i++) { + var extraField = entry.extraFields[i]; + if (extraField.id === 0x7075) { + if (extraField.data.length < 5) { + // too short to be meaningful + continue; + } + // Version 1 byte version of this extra field, currently 1 + if (extraField.data.readUInt8(0) !== 1) { + // > Changes may not be backward compatible so this extra + // > field should not be used if the version is not recognized. + continue; + } + // NameCRC32 4 bytes File Name Field CRC32 Checksum + var oldNameCrc32 = extraField.data.readUInt32LE(1); + if (crc32.unsigned(buffer.slice(0, entry.fileNameLength)) !== oldNameCrc32) { + // > If the CRC check fails, this UTF-8 Path Extra Field should be + // > ignored and the File Name field in the header should be used instead. + continue; + } + // UnicodeName Variable UTF-8 version of the entry File Name + entry.fileName = bufferToString(extraField.data, 5, extraField.data.length, true); + break; + } + } + // validate file size if (entry.compressionMethod === 0) { if (entry.compressedSize !== entry.uncompressedSize) { diff --git a/package.json b/package.json index c930c8c..c8658f5 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,8 @@ }, "homepage": "https://github.com/thejoshwolfe/yauzl", "dependencies": { - "fd-slicer": "~1.0.1" + "fd-slicer": "~1.0.1", + "buffer-crc32": "~0.2.3" }, "devDependencies": { "bl": "~1.0.0", diff --git a/test/success/unicode-path-extra-field.zip b/test/success/unicode-path-extra-field.zip new file mode 100644 index 0000000..1a5f632 Binary files /dev/null and b/test/success/unicode-path-extra-field.zip differ diff --git a/test/success/unicode-path-extra-field/qi ge fangjian.txt b/test/success/unicode-path-extra-field/qi ge fangjian.txt new file mode 100644 index 0000000..e69de29 diff --git a/test/test.js b/test/test.js index 014ff27..479f3c7 100644 --- a/test/test.js +++ b/test/test.js @@ -312,6 +312,7 @@ function addUnicodeSupport(name) { // see https://github.com/thejoshwolfe/yauzl/issues/10 name = name.replace(/Turmion Katilot/g, "Turmion Kätilöt"); name = name.replace(/Mista veri pakenee/g, "Mistä veri pakenee"); + name = name.replace(/qi ge fangjian/g, "七个房间"); return name; } diff --git a/test/zip64.js b/test/zip64.js index 2ac0967..0512969 100644 --- a/test/zip64.js +++ b/test/zip64.js @@ -186,7 +186,7 @@ function runTest(cb) { if (expectedContents != null) { readStream.pipe(BufferList(function(err, data) { if (data.toString() !== expectedContents) throw new Error(logPrefix + "expected contents:\n" + expectedContents + "\ngot:\n" + data.toString() + "\n"); - console.log(logPrefix + entry.fileName + ": PASS"); + console.log(logPrefix + entry.fileName + ": pass"); })); } else { // make sure this is the big thing @@ -194,7 +194,7 @@ function runTest(cb) { getPrefixOfStream(readStream, function(actualPrefixBuffer) { readStream.destroy(); if (buffersEqual(expectedPrefixBuffer, actualPrefixBuffer)) { - console.log(logPrefix + entry.fileName + ": PASS"); + console.log(logPrefix + entry.fileName + ": pass"); } else { throw new Error(logPrefix + "large.bin contents read did not return expected stream") }