From 894d9fe085b369b8857b87e277bbf67bc98fa2f6 Mon Sep 17 00:00:00 2001 From: fkaelberer Date: Wed, 30 Apr 2014 09:00:17 +0200 Subject: [PATCH 1/3] Fix #3591 / list unsupported options --- src/core/jpx.js | 99 ++++++++++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 42 deletions(-) diff --git a/src/core/jpx.js b/src/core/jpx.js index a533d9b29..120e04cb0 100644 --- a/src/core/jpx.js +++ b/src/core/jpx.js @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* globals ArithmeticDecoder, error, globalScope, log2, readUint16, readUint32, +/* globals ArithmeticDecoder, globalScope, log2, readUint16, readUint32, warn */ 'use strict'; @@ -58,7 +58,7 @@ var JpxImage = (function JpxImageClosure() { lbox = length - position + headerSize; } if (lbox < headerSize) { - error('JPX error: Invalid box field size'); + throw 'JPX error: Invalid box field size'; } var dataLength = lbox - headerSize; var jumpDataLength = true; @@ -82,41 +82,34 @@ var JpxImage = (function JpxImageClosure() { } }, parseImageProperties: function JpxImage_parseImageProperties(stream) { - try { - var newByte = stream.getByte(); - while (newByte >= 0) { - var oldByte = newByte; - newByte = stream.getByte(); - var code = (oldByte << 8) | newByte; - // Image and tile size (SIZ) - if (code == 0xFF51) { - stream.skip(4); - var Xsiz = stream.getInt32() >>> 0; // Byte 4 - var Ysiz = stream.getInt32() >>> 0; // Byte 8 - var XOsiz = stream.getInt32() >>> 0; // Byte 12 - var YOsiz = stream.getInt32() >>> 0; // Byte 16 - stream.skip(16); - var Csiz = stream.getUint16(); // Byte 36 - this.width = Xsiz - XOsiz; - this.height = Ysiz - YOsiz; - this.componentsCount = Csiz; - // Results are always returned as Uint8Arrays - this.bitsPerComponent = 8; - return; - } - } - throw 'No size marker found in JPX stream'; - } catch (e) { - if (this.failOnCorruptedImage) { - error('JPX error: ' + e); - } else { - warn('JPX error: ' + e + '. Trying to recover'); + var newByte = stream.getByte(); + while (newByte >= 0) { + var oldByte = newByte; + newByte = stream.getByte(); + var code = (oldByte << 8) | newByte; + // Image and tile size (SIZ) + if (code == 0xFF51) { + stream.skip(4); + var Xsiz = stream.getInt32() >>> 0; // Byte 4 + var Ysiz = stream.getInt32() >>> 0; // Byte 8 + var XOsiz = stream.getInt32() >>> 0; // Byte 12 + var YOsiz = stream.getInt32() >>> 0; // Byte 16 + stream.skip(16); + var Csiz = stream.getUint16(); // Byte 36 + this.width = Xsiz - XOsiz; + this.height = Ysiz - YOsiz; + this.componentsCount = Csiz; + // Results are always returned as Uint8Arrays + this.bitsPerComponent = 8; + return; } } + throw 'JPX error: No size marker found in JPX stream'; }, parseCodestream: function JpxImage_parseCodestream(data, start, end) { var context = {}; try { + var doNotRecover = false; var position = start; while (position + 1 < end) { var code = readUint16(data, position); @@ -160,6 +153,11 @@ var JpxImage = (function JpxImageClosure() { context.QCC = []; context.COC = []; break; + case 0xFF55: // Tile-part lengths, main header (TLM) + var Ltlm = readUint16(data, position); // Marker segment length + // Skip tile length markers + position += Ltlm; + break; case 0xFF5C: // Quantization default (QCD) length = readUint16(data, position); var qcd = {}; @@ -291,16 +289,33 @@ var JpxImage = (function JpxImageClosure() { } cod.precinctsSizes = precinctsSizes; } - - if (cod.sopMarkerUsed || cod.ephMarkerUsed || - cod.selectiveArithmeticCodingBypass || - cod.resetContextProbabilities || - cod.terminationOnEachCodingPass || - cod.verticalyStripe || cod.predictableTermination) { - throw 'Unsupported COD options: ' + - globalScope.JSON.stringify(cod); + var unsupported = []; + if (cod.sopMarkerUsed) { + unsupported.push('sopMarkerUsed'); + } + if (cod.ephMarkerUsed) { + unsupported.push('ephMarkerUsed'); + } + if (cod.selectiveArithmeticCodingBypass) { + unsupported.push('selectiveArithmeticCodingBypass'); + } + if (cod.resetContextProbabilities) { + unsupported.push('resetContextProbabilities'); + } + if (cod.terminationOnEachCodingPass) { + unsupported.push('terminationOnEachCodingPass'); + } + if (cod.verticalyStripe) { + unsupported.push('verticalyStripe'); + } + if (cod.predictableTermination) { + unsupported.push('predictableTermination'); + } + if (unsupported.length > 0) { + doNotRecover = true; + throw 'Unsupported COD options (' + unsupported.join(', ') + + ')'; } - if (context.mainHeader) { context.COD = cod; } else { @@ -350,8 +365,8 @@ var JpxImage = (function JpxImageClosure() { position += length; } } catch (e) { - if (this.failOnCorruptedImage) { - error('JPX error: ' + e); + if (doNotRecover || this.failOnCorruptedImage) { + throw 'JPX error: ' + e; } else { warn('JPX error: ' + e + '. Trying to recover'); } From 34298e4ba7373585dc7fa37f69ba436e51ae2270 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Fri, 13 Jun 2014 18:22:22 -0500 Subject: [PATCH 2/3] Adds test case for JPX COC marker --- test/pdfs/issue3591.pdf.link | 1 + test/test_manifest.json | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 test/pdfs/issue3591.pdf.link diff --git a/test/pdfs/issue3591.pdf.link b/test/pdfs/issue3591.pdf.link new file mode 100644 index 000000000..b7860fcef --- /dev/null +++ b/test/pdfs/issue3591.pdf.link @@ -0,0 +1 @@ +http://web.archive.org/web/20130425084432/http://harpers.org/wp-content/uploads/HarpersMagazine-1989-09-0059029.pdf diff --git a/test/test_manifest.json b/test/test_manifest.json index 143935840..77306d0d8 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -1507,6 +1507,16 @@ "rounds": 1, "type": "eq" }, + { "id": "issue3591", + "file": "pdfs/issue3591.pdf", + "md5": "f76b3e9d1a44621b73063cf10556c6ff", + "link": true, + "firstPage": 1, + "lastPage": 1, + "rounds": 1, + "type": "eq", + "about": "JPX with 0xFF55 marker" + }, { "id": "bug766138", "file": "pdfs/bug766138.pdf", "md5": "b171f5cf8d9834348112fba60ee54f8c", From 9f51e46917eed1e1f5213f9fa3cdbeb56aa2b0cd Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Fri, 13 Jun 2014 18:18:49 -0500 Subject: [PATCH 3/3] Refactoring error reporting in JPX --- src/core/jpx.js | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/core/jpx.js b/src/core/jpx.js index 120e04cb0..228725468 100644 --- a/src/core/jpx.js +++ b/src/core/jpx.js @@ -58,7 +58,7 @@ var JpxImage = (function JpxImageClosure() { lbox = length - position + headerSize; } if (lbox < headerSize) { - throw 'JPX error: Invalid box field size'; + throw new Error('JPX Error: Invalid box field size'); } var dataLength = lbox - headerSize; var jumpDataLength = true; @@ -104,7 +104,7 @@ var JpxImage = (function JpxImageClosure() { return; } } - throw 'JPX error: No size marker found in JPX stream'; + throw new Error('JPX Error: No size marker found in JPX stream'); }, parseCodestream: function JpxImage_parseCodestream(data, start, end) { var context = {}; @@ -177,7 +177,7 @@ var JpxImage = (function JpxImageClosure() { scalarExpounded = true; break; default: - throw 'Invalid SQcd value ' + sqcd; + throw new Error('JPX Error: Invalid SQcd value ' + sqcd); } qcd.noQuantization = (spqcdSize == 8); qcd.scalarExpounded = scalarExpounded; @@ -229,7 +229,7 @@ var JpxImage = (function JpxImageClosure() { scalarExpounded = true; break; default: - throw 'Invalid SQcd value ' + sqcd; + throw new Error('JPX Error: Invalid SQcd value ' + sqcd); } qcc.noQuantization = (spqcdSize == 8); qcc.scalarExpounded = scalarExpounded; @@ -313,8 +313,8 @@ var JpxImage = (function JpxImageClosure() { } if (unsupported.length > 0) { doNotRecover = true; - throw 'Unsupported COD options (' + unsupported.join(', ') + - ')'; + throw new Error('JPX Error: Unsupported COD options (' + + unsupported.join(', ') + ')'); } if (context.mainHeader) { context.COD = cod; @@ -358,17 +358,19 @@ var JpxImage = (function JpxImageClosure() { // skipping content break; case 0xFF53: // Coding style component (COC) - throw 'Codestream code 0xFF53 (COC) is not implemented'; + throw new Error('JPX Error: Codestream code 0xFF53 (COC) is ' + + 'not implemented'); default: - throw 'Unknown codestream code: ' + code.toString(16); + throw new Error('JPX Error: Unknown codestream code: ' + + code.toString(16)); } position += length; } } catch (e) { if (doNotRecover || this.failOnCorruptedImage) { - throw 'JPX error: ' + e; + throw e; } else { - warn('JPX error: ' + e + '. Trying to recover'); + warn('Trying to recover from ' + e.message); } } this.tiles = transformComponents(context); @@ -596,7 +598,7 @@ var JpxImage = (function JpxImageClosure() { } r = 0; } - throw 'Out of packets'; + throw new Error('JPX Error: Out of packets'); }; } function ResolutionLayerComponentPositionIterator(context) { @@ -636,7 +638,7 @@ var JpxImage = (function JpxImageClosure() { } l = 0; } - throw 'Out of packets'; + throw new Error('JPX Error: Out of packets'); }; } function buildPackets(context) { @@ -731,7 +733,8 @@ var JpxImage = (function JpxImageClosure() { new ResolutionLayerComponentPositionIterator(context); break; default: - throw 'Unsupported progression order ' + progressionOrder; + throw new Error('JPX Error: Unsupported progression order ' + + progressionOrder); } } function parseTilePackets(context, data, offset, dataLength) { @@ -1644,7 +1647,7 @@ var JpxImage = (function JpxImageClosure() { (decoder.readBit(contexts, UNIFORM_CONTEXT) << 1) | decoder.readBit(contexts, UNIFORM_CONTEXT); if (symbol != 0xA) { - throw 'Invalid segmentation symbol'; + throw new Error('JPX Error: Invalid segmentation symbol'); } } };