From 6111c17c8aa3e196743aa34185a6e9330b37aa53 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Thu, 5 May 2016 19:16:35 +0200 Subject: [PATCH] Use `Dict_getArray` in more places in `src/core/` to avoid issues when Arrays contain indirect objects As evident from e.g. PRs 6485 and 7118, some bad PDF generators unfortunately create Arrays where *some* elements are indirect objects (i.e. `Ref`s). This seems to mostly affect Arrays that contain numbers, such as e.g. `Matrix/FontMatrix/BBox/FontBBox/Rect/Color/...`, and has manifested itself in PDF files that fail to render correctly (some elements are missing). The problem in both the cases above, besides broken rendering, was that there were *no* errors/warnings that indicated what the problem was, making it difficult to pinpoint the issue. Hence this patch, where I've audited all usages of `Dict_get` in `src/core/` files, and replaced it with `Dict_getArray` where appropriate to try and prevent unnecessary future bugs. --- src/core/annotation.js | 12 ++++++------ src/core/colorspace.js | 18 +++++++++--------- src/core/evaluator.js | 16 ++++++++-------- src/core/function.js | 22 +++++++++++----------- src/core/image.js | 2 +- src/core/obj.js | 2 +- src/core/pattern.js | 14 +++++++------- src/core/stream.js | 8 ++++---- 8 files changed, 47 insertions(+), 47 deletions(-) diff --git a/src/core/annotation.js b/src/core/annotation.js index 83f4385231141..55c7531a95925 100644 --- a/src/core/annotation.js +++ b/src/core/annotation.js @@ -174,7 +174,7 @@ var Annotation = (function AnnotationClosure() { this.setFlags(dict.get('F')); this.setRectangle(dict.getArray('Rect')); - this.setColor(dict.get('C')); + this.setColor(dict.getArray('C')); this.setBorderStyle(dict); this.appearance = getDefaultAppearance(dict); @@ -325,10 +325,10 @@ var Annotation = (function AnnotationClosure() { dictType.name === 'Border')) { this.borderStyle.setWidth(dict.get('W')); this.borderStyle.setStyle(dict.get('S')); - this.borderStyle.setDashArray(dict.get('D')); + this.borderStyle.setDashArray(dict.getArray('D')); } } else if (borderStyle.has('Border')) { - var array = borderStyle.get('Border'); + var array = borderStyle.getArray('Border'); if (isArray(array) && array.length >= 3) { this.borderStyle.setHorizontalCornerRadius(array[0]); this.borderStyle.setVerticalCornerRadius(array[1]); @@ -400,8 +400,8 @@ var Annotation = (function AnnotationClosure() { // ProcSet // Properties ]); - var bbox = appearanceDict.get('BBox') || [0, 0, 1, 1]; - var matrix = appearanceDict.get('Matrix') || [1, 0, 0, 1, 0 ,0]; + var bbox = appearanceDict.getArray('BBox') || [0, 0, 1, 1]; + var matrix = appearanceDict.getArray('Matrix') || [1, 0, 0, 1, 0 ,0]; var transform = getTransformMatrix(data.rect, bbox, matrix); var self = this; @@ -820,7 +820,7 @@ var PopupAnnotation = (function PopupAnnotationClosure() { // Fall back to the default background color. this.data.color = null; } else { - this.setColor(parentItem.get('C')); + this.setColor(parentItem.getArray('C')); this.data.color = this.color; } } diff --git a/src/core/colorspace.js b/src/core/colorspace.js index 5281140be468c..3c545e1871de0 100644 --- a/src/core/colorspace.js +++ b/src/core/colorspace.js @@ -332,16 +332,16 @@ var ColorSpace = (function ColorSpaceClosure() { return 'DeviceCmykCS'; case 'CalGray': params = xref.fetchIfRef(cs[1]); - whitePoint = params.get('WhitePoint'); - blackPoint = params.get('BlackPoint'); + whitePoint = params.getArray('WhitePoint'); + blackPoint = params.getArray('BlackPoint'); gamma = params.get('Gamma'); return ['CalGrayCS', whitePoint, blackPoint, gamma]; case 'CalRGB': params = xref.fetchIfRef(cs[1]); - whitePoint = params.get('WhitePoint'); - blackPoint = params.get('BlackPoint'); - gamma = params.get('Gamma'); - var matrix = params.get('Matrix'); + whitePoint = params.getArray('WhitePoint'); + blackPoint = params.getArray('BlackPoint'); + gamma = params.getArray('Gamma'); + var matrix = params.getArray('Matrix'); return ['CalRGBCS', whitePoint, blackPoint, gamma, matrix]; case 'ICCBased': var stream = xref.fetchIfRef(cs[1]); @@ -395,9 +395,9 @@ var ColorSpace = (function ColorSpaceClosure() { return ['AlternateCS', numComps, alt, tintFnIR]; case 'Lab': params = xref.fetchIfRef(cs[1]); - whitePoint = params.get('WhitePoint'); - blackPoint = params.get('BlackPoint'); - var range = params.get('Range'); + whitePoint = params.getArray('WhitePoint'); + blackPoint = params.getArray('BlackPoint'); + var range = params.getArray('Range'); return ['LabCS', whitePoint, blackPoint, range]; default: error('unimplemented color space object "' + mode + '"'); diff --git a/src/core/evaluator.js b/src/core/evaluator.js index 92bcb07730457..4bbd2aa0ce7ab 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -148,7 +148,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { function NativeImageDecoder_isSupported(image, xref, res) { var cs = ColorSpace.parse(image.dict.get('ColorSpace', 'CS'), xref, res); return (cs.name === 'DeviceGray' || cs.name === 'DeviceRGB') && - cs.isDefaultDecode(image.dict.get('Decode', 'D')); + cs.isDefaultDecode(image.dict.getArray('Decode', 'D')); }; /** * Checks if the image can be decoded by the browser. @@ -157,7 +157,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { function NativeImageDecoder_isDecodable(image, xref, res) { var cs = ColorSpace.parse(image.dict.get('ColorSpace', 'CS'), xref, res); return (cs.numComps === 1 || cs.numComps === 3) && - cs.isDefaultDecode(image.dict.get('Decode', 'D')); + cs.isDefaultDecode(image.dict.getArray('Decode', 'D')); }; function PartialEvaluator(pdfManager, xref, handler, pageIndex, @@ -347,7 +347,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { var height = dict.get('Height', 'H'); var bitStrideLength = (width + 7) >> 3; var imgArray = image.getBytes(bitStrideLength * height); - var decode = dict.get('Decode', 'D'); + var decode = dict.getArray('Decode', 'D'); var inverseDecode = (!!decode && decode[0] > 0); imgData = PDFImage.createMask(imgArray, width, height, @@ -788,7 +788,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { dict, operatorList, task); } else if (typeNum === SHADING_PATTERN) { var shading = dict.get('Shading'); - var matrix = dict.get('Matrix'); + var matrix = dict.getArray('Matrix'); pattern = Pattern.parseShading(shading, matrix, xref, resources, this.handler); operatorList.addOp(fn, pattern.getIR()); @@ -1569,7 +1569,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { } stateManager.save(); - var matrix = xobj.dict.get('Matrix'); + var matrix = xobj.dict.getArray('Matrix'); if (isArray(matrix) && matrix.length === 6) { stateManager.transform(matrix); } @@ -2166,7 +2166,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { // is a tagged pdf. Create a barbebones one to get by. descriptor = new Dict(null); descriptor.set('FontName', Name.get(type)); - descriptor.set('FontBBox', dict.get('FontBBox')); + descriptor.set('FontBBox', dict.getArray('FontBBox')); } else { // Before PDF 1.5 if the font was one of the base 14 fonts, having a // FontDescriptor was not required. @@ -2268,10 +2268,10 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { composite: composite, wideChars: composite, fixedPitch: false, - fontMatrix: (dict.get('FontMatrix') || FONT_IDENTITY_MATRIX), + fontMatrix: (dict.getArray('FontMatrix') || FONT_IDENTITY_MATRIX), firstChar: firstChar || 0, lastChar: (lastChar || maxCharIndex), - bbox: descriptor.get('FontBBox'), + bbox: descriptor.getArray('FontBBox'), ascent: descriptor.get('Ascent'), descent: descriptor.get('Descent'), xHeight: descriptor.get('XHeight'), diff --git a/src/core/function.js b/src/core/function.js index 3d2aaf4b2a490..a6d89032e4a5a 100644 --- a/src/core/function.js +++ b/src/core/function.js @@ -144,8 +144,8 @@ var PDFFunction = (function PDFFunctionClosure() { } return out; } - var domain = dict.get('Domain'); - var range = dict.get('Range'); + var domain = dict.getArray('Domain'); + var range = dict.getArray('Range'); if (!domain || !range) { error('No domain or range'); @@ -166,7 +166,7 @@ var PDFFunction = (function PDFFunctionClosure() { info('No support for cubic spline interpolation: ' + order); } - var encode = dict.get('Encode'); + var encode = dict.getArray('Encode'); if (!encode) { encode = []; for (var i = 0; i < inputSize; ++i) { @@ -176,7 +176,7 @@ var PDFFunction = (function PDFFunctionClosure() { } encode = toMultiArray(encode); - var decode = dict.get('Decode'); + var decode = dict.getArray('Decode'); if (!decode) { decode = range; } else { @@ -278,8 +278,8 @@ var PDFFunction = (function PDFFunctionClosure() { constructInterpolated: function PDFFunction_constructInterpolated(str, dict) { - var c0 = dict.get('C0') || [0]; - var c1 = dict.get('C1') || [1]; + var c0 = dict.getArray('C0') || [0]; + var c1 = dict.getArray('C1') || [1]; var n = dict.get('N'); if (!isArray(c0) || !isArray(c1)) { @@ -314,7 +314,7 @@ var PDFFunction = (function PDFFunctionClosure() { }, constructStiched: function PDFFunction_constructStiched(fn, dict, xref) { - var domain = dict.get('Domain'); + var domain = dict.getArray('Domain'); if (!domain) { error('No domain'); @@ -331,8 +331,8 @@ var PDFFunction = (function PDFFunctionClosure() { fns.push(PDFFunction.getIR(xref, xref.fetchIfRef(fnRefs[i]))); } - var bounds = dict.get('Bounds'); - var encode = dict.get('Encode'); + var bounds = dict.getArray('Bounds'); + var encode = dict.getArray('Encode'); return [CONSTRUCT_STICHED, domain, bounds, encode, fns]; }, @@ -394,8 +394,8 @@ var PDFFunction = (function PDFFunctionClosure() { constructPostScript: function PDFFunction_constructPostScript(fn, dict, xref) { - var domain = dict.get('Domain'); - var range = dict.get('Range'); + var domain = dict.getArray('Domain'); + var range = dict.getArray('Range'); if (!domain) { error('No domain.'); diff --git a/src/core/image.js b/src/core/image.js index b724ede88c3db..9f2b68a158244 100644 --- a/src/core/image.js +++ b/src/core/image.js @@ -167,7 +167,7 @@ var PDFImage = (function PDFImageClosure() { this.numComps = this.colorSpace.numComps; } - this.decode = dict.get('Decode', 'D'); + this.decode = dict.getArray('Decode', 'D'); this.needsDecode = false; if (this.decode && ((this.colorSpace && !this.colorSpace.isDefaultDecode(this.decode)) || diff --git a/src/core/obj.js b/src/core/obj.js index fc5c52d91cffd..2c0f705a14d26 100644 --- a/src/core/obj.js +++ b/src/core/obj.js @@ -172,7 +172,7 @@ var Catalog = (function CatalogClosure() { var title = outlineDict.get('Title'); var flags = outlineDict.get('F') || 0; - var color = outlineDict.get('C'), rgbColor = blackColor; + var color = outlineDict.getArray('C'), rgbColor = blackColor; // We only need to parse the color when it's valid, and non-default. if (isArray(color) && color.length === 3 && (color[0] !== 0 || color[1] !== 0 || color[2] !== 0)) { diff --git a/src/core/pattern.js b/src/core/pattern.js index 2f5c4bd387364..b69d9dd4fac5d 100644 --- a/src/core/pattern.js +++ b/src/core/pattern.js @@ -110,7 +110,7 @@ Shadings.SMALL_NUMBER = 1e-6; Shadings.RadialAxial = (function RadialAxialClosure() { function RadialAxial(dict, matrix, xref, res) { this.matrix = matrix; - this.coordsArr = dict.get('Coords'); + this.coordsArr = dict.getArray('Coords'); this.shadingType = dict.get('ShadingType'); this.type = 'Pattern'; var cs = dict.get('ColorSpace', 'CS'); @@ -119,14 +119,14 @@ Shadings.RadialAxial = (function RadialAxialClosure() { var t0 = 0.0, t1 = 1.0; if (dict.has('Domain')) { - var domainArr = dict.get('Domain'); + var domainArr = dict.getArray('Domain'); t0 = domainArr[0]; t1 = domainArr[1]; } var extendStart = false, extendEnd = false; if (dict.has('Extend')) { - var extendArr = dict.get('Extend'); + var extendArr = dict.getArray('Extend'); extendStart = extendArr[0]; extendEnd = extendArr[1]; } @@ -731,7 +731,7 @@ Shadings.Mesh = (function MeshClosure() { this.matrix = matrix; this.shadingType = dict.get('ShadingType'); this.type = 'Pattern'; - this.bbox = dict.get('BBox'); + this.bbox = dict.getArray('BBox'); var cs = dict.get('ColorSpace', 'CS'); cs = ColorSpace.parse(cs, xref, res); this.cs = cs; @@ -749,7 +749,7 @@ Shadings.Mesh = (function MeshClosure() { bitsPerCoordinate: dict.get('BitsPerCoordinate'), bitsPerComponent: dict.get('BitsPerComponent'), bitsPerFlag: dict.get('BitsPerFlag'), - decode: dict.get('Decode'), + decode: dict.getArray('Decode'), colorFn: fn, colorSpace: cs, numComps: fn ? 1 : cs.numComps @@ -816,8 +816,8 @@ Shadings.Dummy = (function DummyClosure() { })(); function getTilingPatternIR(operatorList, dict, args) { - var matrix = dict.get('Matrix'); - var bbox = dict.get('BBox'); + var matrix = dict.getArray('Matrix'); + var bbox = dict.getArray('BBox'); var xstep = dict.get('XStep'); var ystep = dict.get('YStep'); var paintType = dict.get('PaintType'); diff --git a/src/core/stream.js b/src/core/stream.js index 42d9ee9c1fd13..cada73292aefe 100644 --- a/src/core/stream.js +++ b/src/core/stream.js @@ -926,7 +926,7 @@ var JpegStream = (function JpegStreamClosure() { // checking if values needs to be transformed before conversion if (this.forceRGB && this.dict && isArray(this.dict.get('Decode'))) { - var decodeArr = this.dict.get('Decode'); + var decodeArr = this.dict.getArray('Decode'); var bitsPerComponent = this.dict.get('BitsPerComponent') || 8; var decodeArrLength = decodeArr.length; var transform = new Int32Array(decodeArrLength); @@ -1066,8 +1066,8 @@ var Jbig2Stream = (function Jbig2StreamClosure() { var jbig2Image = new Jbig2Image(); - var chunks = [], xref = this.dict.xref; - var decodeParams = xref.fetchIfRef(this.dict.get('DecodeParms')); + var chunks = []; + var decodeParams = this.dict.getArray('DecodeParms'); // According to the PDF specification, DecodeParms can be either // a dictionary, or an array whose elements are dictionaries. @@ -1076,7 +1076,7 @@ var Jbig2Stream = (function Jbig2StreamClosure() { warn('JBIG2 - \'DecodeParms\' array with multiple elements ' + 'not supported.'); } - decodeParams = xref.fetchIfRef(decodeParams[0]); + decodeParams = decodeParams[0]; } if (decodeParams && decodeParams.has('JBIG2Globals')) { var globalsStream = decodeParams.get('JBIG2Globals');