diff --git a/src/core/jpg.js b/src/core/jpg.js index 9f25683a8..0842dd0ae 100644 --- a/src/core/jpg.js +++ b/src/core/jpg.js @@ -28,6 +28,19 @@ let JpegError = (function JpegErrorClosure() { return JpegError; })(); +let DNLMarkerError = (function DNLMarkerErrorClosure() { + function DNLMarkerError(message, scanLines) { + this.message = message; + this.scanLines = scanLines; + } + + DNLMarkerError.prototype = new Error(); + DNLMarkerError.prototype.name = 'DNLMarkerError'; + DNLMarkerError.constructor = DNLMarkerError; + + return DNLMarkerError; +})(); + /** * This code was forked from https://github.com/notmasteryet/jpgjs. * The original version was created by GitHub user notmasteryet. @@ -112,7 +125,8 @@ var JpegImage = (function JpegImageClosure() { } function decodeScan(data, offset, frame, components, resetInterval, - spectralStart, spectralEnd, successivePrev, successive) { + spectralStart, spectralEnd, successivePrev, successive, + parseDNLMarker = false) { var mcusPerLine = frame.mcusPerLine; var progressive = frame.progressive; @@ -127,6 +141,14 @@ var JpegImage = (function JpegImageClosure() { if (bitsData === 0xFF) { var nextByte = data[offset++]; if (nextByte) { + if (nextByte === 0xDC && parseDNLMarker) { // DNL == 0xFFDC + offset += 2; // Skip data length. + const scanLines = (data[offset++] << 8) | data[offset++]; + if (scanLines > 0 && scanLines !== frame.scanLines) { + throw new DNLMarkerError( + 'Found DNL marker (0xFFDC) while parsing scan data', scanLines); + } + } throw new JpegError( `unexpected marker ${((bitsData << 8) | nextByte).toString(16)}`); } @@ -635,7 +657,7 @@ var JpegImage = (function JpegImageClosure() { } JpegImage.prototype = { - parse: function parse(data) { + parse(data, { dnlScanLines = null, } = {}) { function readUint16() { var value = (data[offset] << 8) | data[offset + 1]; @@ -685,6 +707,7 @@ var JpegImage = (function JpegImageClosure() { var jfif = null; var adobe = null; var frame, resetInterval; + let numSOSMarkers = 0; var quantizationTables = []; var huffmanTablesAC = [], huffmanTablesDC = []; var fileMarker = readUint16(); @@ -781,7 +804,8 @@ var JpegImage = (function JpegImageClosure() { frame.extended = (fileMarker === 0xFFC1); frame.progressive = (fileMarker === 0xFFC2); frame.precision = data[offset++]; - frame.scanLines = readUint16(); + const sofScanLines = readUint16(); + frame.scanLines = dnlScanLines || sofScanLines; frame.samplesPerLine = readUint16(); frame.components = []; frame.componentIds = {}; @@ -839,6 +863,12 @@ var JpegImage = (function JpegImageClosure() { break; case 0xFFDA: // SOS (Start of Scan) + // A DNL marker (0xFFDC), if it exists, is only allowed at the end + // of the first scan segment and may only occur once in an image. + // Furthermore, to prevent an infinite loop, do *not* attempt to + // parse DNL markers during re-parsing of the JPEG scan data. + const parseDNLMarker = (++numSOSMarkers) === 1 && !dnlScanLines; + readUint16(); // scanLength var selectorsCount = data[offset++]; var components = [], component; @@ -853,11 +883,26 @@ var JpegImage = (function JpegImageClosure() { var spectralStart = data[offset++]; var spectralEnd = data[offset++]; var successiveApproximation = data[offset++]; - var processed = decodeScan(data, offset, - frame, components, resetInterval, - spectralStart, spectralEnd, - successiveApproximation >> 4, successiveApproximation & 15); - offset += processed; + try { + var processed = decodeScan(data, offset, + frame, components, resetInterval, + spectralStart, spectralEnd, + successiveApproximation >> 4, successiveApproximation & 15, + parseDNLMarker); + offset += processed; + } catch (ex) { + if (ex instanceof DNLMarkerError) { + warn('Attempting to re-parse JPEG image using "scanLines" ' + + 'parameter found in DNL marker (0xFFDC) segment.'); + return this.parse(data, { dnlScanLines: ex.scanLines, }); + } + throw ex; + } + break; + + case 0xFFDC: // DNL (Define Number of Lines) + // Ignore the marker, since it's being handled in `decodeScan`. + offset += 4; break; case 0xFFFF: // Fill bytes diff --git a/test/pdfs/issue8614.pdf.link b/test/pdfs/issue8614.pdf.link new file mode 100644 index 000000000..04cccb01c --- /dev/null +++ b/test/pdfs/issue8614.pdf.link @@ -0,0 +1 @@ +https://github.com/mozilla/pdf.js/files/1125123/OBW-OVK.pdf diff --git a/test/test_manifest.json b/test/test_manifest.json index 5d56a8a00..7a68a2963 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -3194,6 +3194,14 @@ "link": true, "type": "eq" }, + { "id": "issue8614", + "file": "pdfs/issue8614.pdf", + "md5": "7e8b66cf674ac2b79d6b267d0c6f2fa2", + "rounds": 1, + "link": true, + "lastPage": 1, + "type": "eq" + }, { "id": "bug1108753", "file": "pdfs/bug1108753.pdf", "md5": "a7aaf92d55b4602afb0ca3d75198b56b",