Make Dict handle all the fetching of Refs.

This commit is contained in:
Brendan Dahl 2012-04-04 11:43:04 -07:00
parent 6ec62cd148
commit 8a45177be0
8 changed files with 109 additions and 102 deletions

View File

@ -70,7 +70,7 @@ var ColorSpace = (function ColorSpaceClosure() {
ColorSpace.parseToIR = function colorSpaceParseToIR(cs, xref, res) { ColorSpace.parseToIR = function colorSpaceParseToIR(cs, xref, res) {
if (isName(cs)) { if (isName(cs)) {
var colorSpaces = xref.fetchIfRef(res.get('ColorSpace')); var colorSpaces = res.get('ColorSpace');
if (isDict(colorSpaces)) { if (isDict(colorSpaces)) {
var refcs = colorSpaces.get(cs.name); var refcs = colorSpaces.get(cs.name);
if (refcs) if (refcs)
@ -152,7 +152,7 @@ var ColorSpace = (function ColorSpaceClosure() {
var tintFnIR = PDFFunction.getIR(xref, xref.fetchIfRef(cs[3])); var tintFnIR = PDFFunction.getIR(xref, xref.fetchIfRef(cs[3]));
return ['AlternateCS', numComps, alt, tintFnIR]; return ['AlternateCS', numComps, alt, tintFnIR];
case 'Lab': case 'Lab':
var params = cs[1].map; var params = cs[1].getAll();
return ['LabCS', params]; return ['LabCS', params];
default: default:
error('unimplemented color space object "' + mode + '"'); error('unimplemented color space object "' + mode + '"');

View File

@ -73,13 +73,13 @@ var Page = (function PageClosure() {
Page.prototype = { Page.prototype = {
getPageProp: function pageGetPageProp(key) { getPageProp: function pageGetPageProp(key) {
return this.xref.fetchIfRef(this.pageDict.get(key)); return this.pageDict.get(key);
}, },
inheritPageProp: function pageInheritPageProp(key) { inheritPageProp: function pageInheritPageProp(key) {
var dict = this.pageDict; var dict = this.pageDict;
var obj = dict.get(key); var obj = dict.get(key);
while (obj === undefined) { while (obj === undefined) {
dict = this.xref.fetchIfRef(dict.get('Parent')); dict = dict.get('Parent');
if (!dict) if (!dict)
break; break;
obj = dict.get(key); obj = dict.get(key);
@ -199,8 +199,8 @@ var Page = (function PageClosure() {
this.stats.time('Build IR Queue'); this.stats.time('Build IR Queue');
var xref = this.xref; var xref = this.xref;
var content = xref.fetchIfRef(this.content); var content = this.content;
var resources = xref.fetchIfRef(this.resources); var resources = this.resources;
if (isArray(content)) { if (isArray(content)) {
// fetching items // fetching items
var i, n = content.length; var i, n = content.length;
@ -242,8 +242,8 @@ var Page = (function PageClosure() {
var stats = this.stats; var stats = this.stats;
stats.time('Rendering'); stats.time('Rendering');
var xref = this.xref; var xref = this.xref;
var resources = xref.fetchIfRef(this.resources); var resources = this.resources;
var mediaBox = xref.fetchIfRef(this.mediaBox); var mediaBox = this.mediaBox;
assertWellFormed(isDict(resources), 'invalid page resources'); assertWellFormed(isDict(resources), 'invalid page resources');
gfx.xref = xref; gfx.xref = xref;
@ -307,7 +307,7 @@ var Page = (function PageClosure() {
function getInheritableProperty(annotation, name) { function getInheritableProperty(annotation, name) {
var item = annotation; var item = annotation;
while (item && !item.has(name)) { while (item && !item.has(name)) {
item = xref.fetchIfRef(item.get('Parent')); item = item.get('Parent');
} }
if (!item) if (!item)
return null; return null;
@ -330,7 +330,7 @@ var Page = (function PageClosure() {
} }
} }
var annotations = xref.fetchIfRef(this.annotations) || []; var annotations = this.annotations || [];
var i, n = annotations.length; var i, n = annotations.length;
var items = []; var items = [];
for (i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {
@ -353,7 +353,7 @@ var Page = (function PageClosure() {
item.height = Math.abs(topLeftCorner.y - bottomRightCorner.y); item.height = Math.abs(topLeftCorner.y - bottomRightCorner.y);
switch (subtype.name) { switch (subtype.name) {
case 'Link': case 'Link':
var a = this.xref.fetchIfRef(annotation.get('A')); var a = annotation.get('A');
if (a) { if (a) {
switch (a.get('S').name) { switch (a.get('S').name) {
case 'URI': case 'URI':
@ -386,21 +386,22 @@ var Page = (function PageClosure() {
var fieldName = []; var fieldName = [];
var namedItem = annotation, ref = annotationRef; var namedItem = annotation, ref = annotationRef;
while (namedItem) { while (namedItem) {
var parentRef = namedItem.get('Parent'); var parent = namedItem.get('Parent');
var parent = xref.fetchIfRef(parentRef); var parentRef = namedItem.getRaw('Parent');
var name = namedItem.get('T'); var name = namedItem.get('T');
if (name) if (name) {
fieldName.unshift(stringToPDFString(name)); fieldName.unshift(stringToPDFString(name));
else { } else {
// The field name is absent, that means more than one field // The field name is absent, that means more than one field
// with the same name may exist. Replacing the empty name // with the same name may exist. Replacing the empty name
// with the '`' plus index in the parent's 'Kids' array. // with the '`' plus index in the parent's 'Kids' array.
// This is not in the PDF spec but necessary to id the // This is not in the PDF spec but necessary to id the
// the input controls. // the input controls.
var kids = xref.fetchIfRef(parent.get('Kids')); var kids = parent.get('Kids');
var j, jj; var j, jj;
for (j = 0, jj = kids.length; j < jj; j++) { for (j = 0, jj = kids.length; j < jj; j++) {
if (kids[j].num == ref.num && kids[j].gen == ref.gen) var kidRef = kids[j];
if (kidRef.num == ref.num && kidRef.gen == ref.gen)
break; break;
} }
fieldName.unshift('`' + j); fieldName.unshift('`' + j);
@ -490,7 +491,7 @@ var PDFDocModel = (function PDFDocModelClosure() {
assertWellFormed(stream.length > 0, 'stream must have data'); assertWellFormed(stream.length > 0, 'stream must have data');
this.stream = stream; this.stream = stream;
this.setup(); this.setup();
this.acroForm = this.xref.fetchIfRef(this.catalog.catDict.get('AcroForm')); this.acroForm = this.catalog.catDict.get('AcroForm');
} }
function find(stream, needle, limit, backwards) { function find(stream, needle, limit, backwards) {
@ -597,7 +598,7 @@ var PDFDocModel = (function PDFDocModelClosure() {
getDocumentInfo: function pdfDocGetDocumentInfo() { getDocumentInfo: function pdfDocGetDocumentInfo() {
var info; var info;
if (this.xref.trailer.has('Info')) if (this.xref.trailer.has('Info'))
info = this.xref.fetch(this.xref.trailer.get('Info')); info = this.xref.trailer.get('Info');
return shadow(this, 'getDocumentInfo', info); return shadow(this, 'getDocumentInfo', info);
}, },
@ -605,7 +606,7 @@ var PDFDocModel = (function PDFDocModelClosure() {
var xref = this.xref, fileID; var xref = this.xref, fileID;
if (xref.trailer.has('ID')) { if (xref.trailer.has('ID')) {
fileID = ''; fileID = '';
var id = xref.fetchIfRef(xref.trailer.get('ID'))[0]; var id = xref.trailer.get('ID')[0];
id.split('').forEach(function(el) { id.split('').forEach(function(el) {
fileID += Number(el.charCodeAt(0)).toString(16); fileID += Number(el.charCodeAt(0)).toString(16);
}); });

View File

@ -131,16 +131,14 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
} }
} }
function handleSetFont(fontName, fontRef) { function handleSetFont(fontName, font) {
var loadedName = null; var loadedName = null;
var fontRes = resources.get('Font'); var fontRes = resources.get('Font');
assert(fontRes, 'fontRes not available'); assert(fontRes, 'fontRes not available');
fontRes = xref.fetchIfRef(fontRes); font = xref.fetchIfRef(font) || fontRes.get(fontName);
fontRef = fontRef || fontRes.get(fontName);
var font = xref.fetchIfRef(fontRef);
assertWellFormed(isDict(font)); assertWellFormed(isDict(font));
if (!font.translated) { if (!font.translated) {
font.translated = self.translateFont(font, xref, resources, font.translated = self.translateFont(font, xref, resources,
@ -250,10 +248,10 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var fnArray = queue.fnArray, argsArray = queue.argsArray; var fnArray = queue.fnArray, argsArray = queue.argsArray;
var dependencyArray = dependency || []; var dependencyArray = dependency || [];
resources = xref.fetchIfRef(resources) || new Dict(); resources = resources || new Dict();
var xobjs = xref.fetchIfRef(resources.get('XObject')) || new Dict(); var xobjs = resources.get('XObject') || new Dict();
var patterns = xref.fetchIfRef(resources.get('Pattern')) || new Dict(); var patterns = resources.get('Pattern') || new Dict();
var parser = new Parser(new Lexer(stream), false); var parser = new Parser(new Lexer(stream), false, xref);
var res = resources; var res = resources;
var args = [], obj; var args = [], obj;
var getObjBt = function getObjBt() { var getObjBt = function getObjBt() {
@ -285,7 +283,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var patternName = args[args.length - 1]; var patternName = args[args.length - 1];
// SCN/scn applies patterns along with normal colors // SCN/scn applies patterns along with normal colors
if (isName(patternName)) { if (isName(patternName)) {
var pattern = xref.fetchIfRef(patterns.get(patternName.name)); var pattern = patterns.get(patternName.name);
if (pattern) { if (pattern) {
var dict = isStream(pattern) ? pattern.dict : pattern; var dict = isStream(pattern) ? pattern.dict : pattern;
var typeNum = dict.get('PatternType'); var typeNum = dict.get('PatternType');
@ -303,7 +301,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
args = TilingPattern.getIR(operatorList, dict, args); args = TilingPattern.getIR(operatorList, dict, args);
} }
else if (typeNum == SHADING_PATTERN) { else if (typeNum == SHADING_PATTERN) {
var shading = xref.fetchIfRef(dict.get('Shading')); var shading = dict.get('Shading');
var matrix = dict.get('Matrix'); var matrix = dict.get('Matrix');
var pattern = Pattern.parseShading(shading, matrix, xref, res, var pattern = Pattern.parseShading(shading, matrix, xref, res,
null /*ctx*/); null /*ctx*/);
@ -318,7 +316,6 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var name = args[0].name; var name = args[0].name;
var xobj = xobjs.get(name); var xobj = xobjs.get(name);
if (xobj) { if (xobj) {
xobj = xref.fetchIfRef(xobj);
assertWellFormed(isStream(xobj), 'XObject should be a stream'); assertWellFormed(isStream(xobj), 'XObject should be a stream');
var type = xobj.dict.get('Subtype'); var type = xobj.dict.get('Subtype');
@ -369,11 +366,11 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
args = [ColorSpace.parseToIR(args[0], xref, resources)]; args = [ColorSpace.parseToIR(args[0], xref, resources)];
break; break;
case 'shadingFill': case 'shadingFill':
var shadingRes = xref.fetchIfRef(res.get('Shading')); var shadingRes = res.get('Shading');
if (!shadingRes) if (!shadingRes)
error('No shading resource found'); error('No shading resource found');
var shading = xref.fetchIfRef(shadingRes.get(args[0].name)); var shading = shadingRes.get(args[0].name);
if (!shading) if (!shading)
error('No shading object found'); error('No shading object found');
@ -385,12 +382,12 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
break; break;
case 'setGState': case 'setGState':
var dictName = args[0]; var dictName = args[0];
var extGState = xref.fetchIfRef(resources.get('ExtGState')); var extGState = resources.get('ExtGState');
if (!isDict(extGState) || !extGState.has(dictName.name)) if (!isDict(extGState) || !extGState.has(dictName.name))
break; break;
var gsState = xref.fetchIfRef(extGState.get(dictName.name)); var gsState = extGState.get(dictName.name);
// This array holds the converted/processed state data. // This array holds the converted/processed state data.
var gsStateObj = []; var gsStateObj = [];
@ -469,7 +466,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
if (properties.composite) { if (properties.composite) {
// CIDSystemInfo helps to match CID to glyphs // CIDSystemInfo helps to match CID to glyphs
var cidSystemInfo = xref.fetchIfRef(dict.get('CIDSystemInfo')); var cidSystemInfo = dict.get('CIDSystemInfo');
if (isDict(cidSystemInfo)) { if (isDict(cidSystemInfo)) {
properties.cidSystemInfo = { properties.cidSystemInfo = {
registry: cidSystemInfo.get('Registry'), registry: cidSystemInfo.get('Registry'),
@ -478,7 +475,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}; };
} }
var cidToGidMap = xref.fetchIfRef(dict.get('CIDToGIDMap')); var cidToGidMap = dict.get('CIDToGIDMap');
if (isStream(cidToGidMap)) if (isStream(cidToGidMap))
properties.cidToGidMap = this.readCidToGidMap(cidToGidMap); properties.cidToGidMap = this.readCidToGidMap(cidToGidMap);
} }
@ -489,7 +486,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
Encodings.symbolsEncoding : Encodings.StandardEncoding; Encodings.symbolsEncoding : Encodings.StandardEncoding;
var hasEncoding = dict.has('Encoding'); var hasEncoding = dict.has('Encoding');
if (hasEncoding) { if (hasEncoding) {
var encoding = xref.fetchIfRef(dict.get('Encoding')); var encoding = dict.get('Encoding');
if (isDict(encoding)) { if (isDict(encoding)) {
var baseName = encoding.get('BaseEncoding'); var baseName = encoding.get('BaseEncoding');
if (baseName) if (baseName)
@ -523,7 +520,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
readToUnicode: readToUnicode:
function partialEvaluatorReadToUnicode(toUnicode, xref) { function partialEvaluatorReadToUnicode(toUnicode, xref) {
var cmapObj = xref.fetchIfRef(toUnicode); var cmapObj = toUnicode;
var charToUnicode = []; var charToUnicode = [];
if (isName(cmapObj)) { if (isName(cmapObj)) {
var isIdentityMap = cmapObj.name.substr(0, 9) == 'Identity-'; var isIdentityMap = cmapObj.name.substr(0, 9) == 'Identity-';
@ -666,9 +663,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var glyphsWidths = []; var glyphsWidths = [];
var defaultWidth = 0; var defaultWidth = 0;
if (properties.composite) { if (properties.composite) {
defaultWidth = xref.fetchIfRef(dict.get('DW')) || 1000; defaultWidth = dict.get('DW') || 1000;
var widths = xref.fetchIfRef(dict.get('W')); var widths = dict.get('W');
if (widths) { if (widths) {
var start = 0, end = 0; var start = 0, end = 0;
for (var i = 0, ii = widths.length; i < ii; i++) { for (var i = 0, ii = widths.length; i < ii; i++) {
@ -689,7 +686,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
} }
} else { } else {
var firstChar = properties.firstChar; var firstChar = properties.firstChar;
var widths = xref.fetchIfRef(dict.get('Widths')); var widths = dict.get('Widths');
if (widths) { if (widths) {
var j = firstChar; var j = firstChar;
for (var i = 0, ii = widths.length; i < ii; i++) for (var i = 0, ii = widths.length; i < ii; i++)
@ -742,10 +739,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
if (!df) if (!df)
return null; return null;
if (isRef(df)) dict = isArray(df) ? xref.fetchIfRef(df[0]) : df;
df = xref.fetch(df);
dict = xref.fetchIfRef(isRef(df) ? df : df[0]);
type = dict.get('Subtype'); type = dict.get('Subtype');
assertWellFormed(isName(type), 'invalid font Subtype'); assertWellFormed(isName(type), 'invalid font Subtype');
@ -753,7 +747,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
} }
var maxCharIndex = composite ? 0xFFFF : 0xFF; var maxCharIndex = composite ? 0xFFFF : 0xFF;
var descriptor = xref.fetchIfRef(dict.get('FontDescriptor')); var descriptor = dict.get('FontDescriptor');
if (!descriptor) { if (!descriptor) {
if (type.name == 'Type3') { if (type.name == 'Type3') {
// FontDescriptor is only required for Type3 fonts when the document // FontDescriptor is only required for Type3 fonts when the document
@ -802,9 +796,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
// to ignore this rule when a variant of a standart font is used. // to ignore this rule when a variant of a standart font is used.
// TODO Fill the width array depending on which of the base font this is // TODO Fill the width array depending on which of the base font this is
// a variant. // a variant.
var firstChar = xref.fetchIfRef(dict.get('FirstChar')) || 0; var firstChar = dict.get('FirstChar') || 0;
var lastChar = xref.fetchIfRef(dict.get('LastChar')) || maxCharIndex; var lastChar = dict.get('LastChar') || maxCharIndex;
var fontName = xref.fetchIfRef(descriptor.get('FontName')); var fontName = descriptor.get('FontName');
// Some bad pdf's have a string as the font name. // Some bad pdf's have a string as the font name.
if (isString(fontName)) if (isString(fontName))
fontName = new Name(fontName); fontName = new Name(fontName);
@ -812,19 +806,14 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var fontFile = descriptor.get('FontFile', 'FontFile2', 'FontFile3'); var fontFile = descriptor.get('FontFile', 'FontFile2', 'FontFile3');
if (fontFile) { if (fontFile) {
fontFile = xref.fetchIfRef(fontFile);
if (fontFile.dict) { if (fontFile.dict) {
var subtype = fontFile.dict.get('Subtype'); var subtype = fontFile.dict.get('Subtype');
if (subtype) if (subtype)
subtype = subtype.name; subtype = subtype.name;
var length1 = fontFile.dict.get('Length1'); var length1 = fontFile.dict.get('Length1');
if (!isInt(length1))
length1 = xref.fetchIfRef(length1);
var length2 = fontFile.dict.get('Length2'); var length2 = fontFile.dict.get('Length2');
if (!isInt(length2))
length2 = xref.fetchIfRef(length2);
} }
} }
@ -853,12 +842,12 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
if (type.name === 'Type3') { if (type.name === 'Type3') {
properties.coded = true; properties.coded = true;
var charProcs = xref.fetchIfRef(dict.get('CharProcs')); var charProcs = dict.get('CharProcs').getAll();
var fontResources = xref.fetchIfRef(dict.get('Resources')) || resources; var fontResources = dict.get('Resources') || resources;
properties.resources = fontResources; properties.resources = fontResources;
properties.charProcOperatorList = {}; properties.charProcOperatorList = {};
for (var key in charProcs.map) { for (var key in charProcs) {
var glyphStream = xref.fetchIfRef(charProcs.map[key]); var glyphStream = charProcs[key];
properties.charProcOperatorList[key] = properties.charProcOperatorList[key] =
this.getOperatorList(glyphStream, fontResources, dependency); this.getOperatorList(glyphStream, fontResources, dependency);
} }

View File

@ -268,13 +268,13 @@ var PDFFunction = (function PDFFunctionClosure() {
if (inputSize != 1) if (inputSize != 1)
error('Bad domain for stiched function'); error('Bad domain for stiched function');
var fnRefs = xref.fetchIfRef(dict.get('Functions')); var fnRefs = dict.get('Functions');
var fns = []; var fns = [];
for (var i = 0, ii = fnRefs.length; i < ii; ++i) for (var i = 0, ii = fnRefs.length; i < ii; ++i)
fns.push(PDFFunction.getIR(xref, xref.fetchIfRef(fnRefs[i]))); fns.push(PDFFunction.getIR(xref, xref.fetchIfRef(fnRefs[i])));
var bounds = xref.fetchIfRef(dict.get('Bounds')); var bounds = dict.get('Bounds');
var encode = xref.fetchIfRef(dict.get('Encode')); var encode = dict.get('Encode');
return [CONSTRUCT_STICHED, domain, bounds, encode, fns]; return [CONSTRUCT_STICHED, domain, bounds, encode, fns];
}, },

View File

@ -94,7 +94,7 @@ var PDFImage = (function PDFImageClosure() {
} }
} }
var mask = xref.fetchIfRef(dict.get('Mask')); var mask = dict.get('Mask');
if (mask) { if (mask) {
TODO('masked images'); TODO('masked images');
@ -120,7 +120,7 @@ var PDFImage = (function PDFImageClosure() {
handleImageData(handler, xref, res, image, imageDataPromise); handleImageData(handler, xref, res, image, imageDataPromise);
var smask = xref.fetchIfRef(image.dict.get('SMask')); var smask = image.dict.get('SMask');
if (smask) if (smask)
handleImageData(handler, xref, res, smask, smaskPromise); handleImageData(handler, xref, res, smask, smaskPromise);
else else

View File

@ -34,23 +34,39 @@ var Cmd = (function CmdClosure() {
})(); })();
var Dict = (function DictClosure() { var Dict = (function DictClosure() {
function Dict() { // xref is optional
function Dict(xref) {
// Map should only be used internally, use functions below to access.
this.map = Object.create(null); this.map = Object.create(null);
this.xref = xref;
} }
Dict.prototype = { Dict.prototype = {
// automatically dereferences Ref objects
get: function dictGet(key1, key2, key3) { get: function dictGet(key1, key2, key3) {
var value; var value;
var xref = this.xref;
if (typeof (value = this.map[key1]) != 'undefined' || key1 in this.map || if (typeof (value = this.map[key1]) != 'undefined' || key1 in this.map ||
typeof key2 == 'undefined') { typeof key2 == 'undefined') {
return value; return xref ? this.xref.fetchIfRef(value) : value;
} }
if (typeof (value = this.map[key2]) != 'undefined' || key2 in this.map || if (typeof (value = this.map[key2]) != 'undefined' || key2 in this.map ||
typeof key3 == 'undefined') { typeof key3 == 'undefined') {
return value; return xref ? this.xref.fetchIfRef(value) : value;
} }
value = this.map[key3] || null;
return this.map[key3] || null; return xref ? this.xref.fetchIfRef(value) : value;
},
// no dereferencing
getRaw: function dictGetRaw(key) {
return this.map[key];
},
// creates new map and dereferences all Refs
getAll: function dictGetAll() {
var all = {};
for (var key in this.map)
all[key] = this.get(key);
return all;
}, },
set: function dictSet(key, value) { set: function dictSet(key, value) {
@ -63,7 +79,7 @@ var Dict = (function DictClosure() {
forEach: function dictForEach(callback) { forEach: function dictForEach(callback) {
for (var key in this.map) { for (var key in this.map) {
callback(key, this.map[key]); callback(key, this.get(key));
} }
} }
}; };
@ -112,8 +128,7 @@ var Catalog = (function CatalogClosure() {
Catalog.prototype = { Catalog.prototype = {
get metadata() { get metadata() {
var ref = this.catDict.get('Metadata'); var stream = this.catDict.get('Metadata');
var stream = this.xref.fetchIfRef(ref);
var metadata; var metadata;
if (stream && isDict(stream.dict)) { if (stream && isDict(stream.dict)) {
var type = stream.dict.get('Type'); var type = stream.dict.get('Type');
@ -129,40 +144,39 @@ var Catalog = (function CatalogClosure() {
}, },
get toplevelPagesDict() { get toplevelPagesDict() {
var pagesObj = this.catDict.get('Pages'); var pagesObj = this.catDict.get('Pages');
assertWellFormed(isRef(pagesObj), 'invalid top-level pages reference'); assertWellFormed(isDict(pagesObj), 'invalid top-level pages dictionary');
var xrefObj = this.xref.fetch(pagesObj);
assertWellFormed(isDict(xrefObj), 'invalid top-level pages dictionary');
// shadow the prototype getter // shadow the prototype getter
return shadow(this, 'toplevelPagesDict', xrefObj); return shadow(this, 'toplevelPagesDict', pagesObj);
}, },
get documentOutline() { get documentOutline() {
var xref = this.xref; var xref = this.xref;
var obj = xref.fetchIfRef(this.catDict.get('Outlines')); var obj = this.catDict.get('Outlines');
var root = { items: [] }; var root = { items: [] };
if (isDict(obj)) { if (isDict(obj)) {
var ref = obj.getRaw('First');
obj = obj.get('First'); obj = obj.get('First');
var processed = new RefSet(); var processed = new RefSet();
if (isRef(obj)) { if (isRef(ref)) {
var queue = [{obj: obj, parent: root}]; var queue = [{obj: obj, parent: root}];
// to avoid recursion keeping track of the items // to avoid recursion keeping track of the items
// in the processed dictionary // in the processed dictionary
processed.put(obj); processed.put(ref);
while (queue.length > 0) { while (queue.length > 0) {
var i = queue.shift(); var i = queue.shift();
var outlineDict = xref.fetch(i.obj); var outlineDict = i.obj;
if (outlineDict === null) if (outlineDict === null)
continue; continue;
if (!outlineDict.has('Title')) if (!outlineDict.has('Title'))
error('Invalid outline item'); error('Invalid outline item');
var dest = outlineDict.get('A'); var dest = outlineDict.get('A');
if (dest) if (dest)
dest = xref.fetchIfRef(dest).get('D'); dest = dest.get('D');
else if (outlineDict.has('Dest')) { else if (outlineDict.has('Dest')) {
dest = outlineDict.get('Dest'); dest = outlineDict.getRaw('Dest');
if (isName(dest)) if (isName(dest))
dest = dest.name; dest = dest.name;
} }
var title = xref.fetchIfRef(outlineDict.get('Title')); var title = outlineDict.get('Title');
var outlineItem = { var outlineItem = {
dest: dest, dest: dest,
title: stringToPDFString(title), title: stringToPDFString(title),
@ -173,15 +187,17 @@ var Catalog = (function CatalogClosure() {
items: [] items: []
}; };
i.parent.items.push(outlineItem); i.parent.items.push(outlineItem);
obj = outlineDict.get('First'); ref = outlineDict.getRaw('First');
if (isRef(obj) && !processed.has(obj)) { if (isRef(ref) && !processed.has(ref)) {
obj = outlineDict.get('First');
queue.push({obj: obj, parent: outlineItem}); queue.push({obj: obj, parent: outlineItem});
processed.put(obj); processed.put(ref);
} }
obj = outlineDict.get('Next'); ref = outlineDict.getRaw('Next');
if (isRef(obj) && !processed.has(obj)) { if (isRef(ref) && !processed.has(ref)) {
obj = outlineDict.get('Next');
queue.push({obj: obj, parent: i.parent}); queue.push({obj: obj, parent: i.parent});
processed.put(obj); processed.put(ref);
} }
} }
} }
@ -206,7 +222,7 @@ var Catalog = (function CatalogClosure() {
for (var i = 0, ii = kids.length; i < ii; ++i) { for (var i = 0, ii = kids.length; i < ii; ++i) {
var kid = kids[i]; var kid = kids[i];
assertWellFormed(isRef(kid), assertWellFormed(isRef(kid),
'page dictionary kid is not a reference'); 'page dictionary kid is not a reference');
var obj = this.xref.fetch(kid); var obj = this.xref.fetch(kid);
if (isDict(obj, 'Page') || (isDict(obj) && !obj.has('Kids'))) { if (isDict(obj, 'Page') || (isDict(obj) && !obj.has('Kids'))) {
pageCache.push(new Page(this.xref, pageCache.length, obj, kid)); pageCache.push(new Page(this.xref, pageCache.length, obj, kid));
@ -221,7 +237,7 @@ var Catalog = (function CatalogClosure() {
}, },
get destinations() { get destinations() {
function fetchDestination(xref, ref) { function fetchDestination(xref, ref) {
var dest = xref.fetchIfRef(ref); var dest = ref;
return isDict(dest) ? dest.get('D') : dest; return isDict(dest) ? dest.get('D') : dest;
} }
@ -229,13 +245,13 @@ var Catalog = (function CatalogClosure() {
var dests = {}, nameTreeRef, nameDictionaryRef; var dests = {}, nameTreeRef, nameDictionaryRef;
var obj = this.catDict.get('Names'); var obj = this.catDict.get('Names');
if (obj) if (obj)
nameTreeRef = xref.fetchIfRef(obj).get('Dests'); nameTreeRef = obj.getRaw('Dests');
else if (this.catDict.has('Dests')) else if (this.catDict.has('Dests'))
nameDictionaryRef = this.catDict.get('Dests'); nameDictionaryRef = this.catDict.get('Dests');
if (nameDictionaryRef) { if (nameDictionaryRef) {
// reading simple destination dictionary // reading simple destination dictionary
obj = xref.fetchIfRef(nameDictionaryRef); obj = nameDictionaryRef;
obj.forEach(function catalogForEach(key, value) { obj.forEach(function catalogForEach(key, value) {
if (!value) return; if (!value) return;
dests[key] = fetchDestination(xref, value); dests[key] = fetchDestination(xref, value);
@ -287,6 +303,7 @@ var XRef = (function XRefClosure() {
this.entries = []; this.entries = [];
this.xrefstms = {}; this.xrefstms = {};
var trailerDict = this.readXRef(startXRef); var trailerDict = this.readXRef(startXRef);
trailerDict.xref = this;
this.trailer = trailerDict; this.trailer = trailerDict;
// prepare the XRef cache // prepare the XRef cache
this.cache = []; this.cache = [];
@ -294,12 +311,12 @@ var XRef = (function XRefClosure() {
var encrypt = trailerDict.get('Encrypt'); var encrypt = trailerDict.get('Encrypt');
if (encrypt) { if (encrypt) {
var fileId = trailerDict.get('ID'); var fileId = trailerDict.get('ID');
this.encrypt = new CipherTransformFactory(this.fetch(encrypt), this.encrypt = new CipherTransformFactory(encrypt,
fileId[0] /*, password */); fileId[0] /*, password */);
} }
// get the root dictionary (catalog) object // get the root dictionary (catalog) object
if (!isRef(this.root = trailerDict.get('Root'))) if (!(this.root = trailerDict.get('Root')))
error('Invalid root reference'); error('Invalid root reference');
} }
@ -514,7 +531,7 @@ var XRef = (function XRefClosure() {
var dict; var dict;
for (var i = 0, ii = trailers.length; i < ii; ++i) { for (var i = 0, ii = trailers.length; i < ii; ++i) {
stream.pos = trailers[i]; stream.pos = trailers[i];
var parser = new Parser(new Lexer(stream), true); var parser = new Parser(new Lexer(stream), true, null);
var obj = parser.getObj(); var obj = parser.getObj();
if (!isCmd(obj, 'trailer')) if (!isCmd(obj, 'trailer'))
continue; continue;
@ -536,7 +553,7 @@ var XRef = (function XRefClosure() {
stream.pos = startXRef; stream.pos = startXRef;
try { try {
var parser = new Parser(new Lexer(stream), true); var parser = new Parser(new Lexer(stream), true, null);
var obj = parser.getObj(); var obj = parser.getObj();
var dict; var dict;
@ -596,6 +613,7 @@ var XRef = (function XRefClosure() {
return this.fetch(obj); return this.fetch(obj);
}, },
fetch: function xRefFetch(ref, suppressEncryption) { fetch: function xRefFetch(ref, suppressEncryption) {
assertWellFormed(isRef(ref), 'ref object is not a reference');
var num = ref.num; var num = ref.num;
if (num in this.cache) if (num in this.cache)
return this.cache[num]; return this.cache[num];
@ -657,7 +675,7 @@ var XRef = (function XRefClosure() {
if (!isInt(first) || !isInt(n)) { if (!isInt(first) || !isInt(n)) {
error('invalid first and n parameters for ObjStm stream'); error('invalid first and n parameters for ObjStm stream');
} }
parser = new Parser(new Lexer(stream), false); parser = new Parser(new Lexer(stream), false, this);
var i, entries = [], nums = []; var i, entries = [], nums = [];
// read the object numbers to populate cache // read the object numbers to populate cache
for (i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {
@ -683,7 +701,7 @@ var XRef = (function XRefClosure() {
return e; return e;
}, },
getCatalogObj: function xRefGetCatalogObj() { getCatalogObj: function xRefGetCatalogObj() {
return this.fetch(this.root); return this.root;
} }
}; };

View File

@ -51,7 +51,7 @@ var Parser = (function ParserClosure() {
} }
if (isCmd(this.buf1, '<<')) { // dictionary or stream if (isCmd(this.buf1, '<<')) { // dictionary or stream
this.shift(); this.shift();
var dict = new Dict(); var dict = new Dict(this.xref);
while (!isCmd(this.buf1, '>>') && !isEOF(this.buf1)) { while (!isCmd(this.buf1, '>>') && !isEOF(this.buf1)) {
if (!isName(this.buf1)) if (!isName(this.buf1))
error('Dictionary key must be a name object'); error('Dictionary key must be a name object');
@ -564,7 +564,7 @@ var Lexer = (function LexerClosure() {
var Linearization = (function LinearizationClosure() { var Linearization = (function LinearizationClosure() {
function Linearization(stream) { function Linearization(stream) {
this.parser = new Parser(new Lexer(stream), false); this.parser = new Parser(new Lexer(stream), false, null);
var obj1 = this.parser.getObj(); var obj1 = this.parser.getObj();
var obj2 = this.parser.getObj(); var obj2 = this.parser.getObj();
var obj3 = this.parser.getObj(); var obj3 = this.parser.getObj();

View File

@ -79,7 +79,6 @@ Shadings.RadialAxial = (function RadialAxialClosure() {
this.extendEnd = extendEnd; this.extendEnd = extendEnd;
var fnObj = dict.get('Function'); var fnObj = dict.get('Function');
fnObj = xref.fetchIfRef(fnObj);
if (isArray(fnObj)) if (isArray(fnObj))
error('No support for array of functions'); error('No support for array of functions');
if (!isPDFFunction(fnObj)) if (!isPDFFunction(fnObj))