Merge pull request #10392 from Snuffleupagus/checkFirstPage
Check that the first page can be successfully loaded, to try and ascertain the validity of the XRef table (issue 7496, issue 10326)
This commit is contained in:
commit
e53877f372
@ -16,7 +16,7 @@
|
|||||||
import {
|
import {
|
||||||
assert, FormatError, getInheritableProperty, info, isArrayBuffer, isBool,
|
assert, FormatError, getInheritableProperty, info, isArrayBuffer, isBool,
|
||||||
isNum, isSpace, isString, MissingDataException, OPS, shadow, stringToBytes,
|
isNum, isSpace, isString, MissingDataException, OPS, shadow, stringToBytes,
|
||||||
stringToPDFString, Util, warn
|
stringToPDFString, Util, warn, XRefEntryException, XRefParseException
|
||||||
} from '../shared/util';
|
} from '../shared/util';
|
||||||
import { Catalog, ObjectLoader, XRef } from './obj';
|
import { Catalog, ObjectLoader, XRef } from './obj';
|
||||||
import { Dict, isDict, isName, isStream, Ref } from './primitives';
|
import { Dict, isDict, isName, isStream, Ref } from './primitives';
|
||||||
@ -649,6 +649,20 @@ var PDFDocument = (function PDFDocumentClosure() {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
checkFirstPage() {
|
||||||
|
return this.getPage(0).catch((reason) => {
|
||||||
|
if (reason instanceof XRefEntryException) {
|
||||||
|
// Clear out the various caches to ensure that we haven't stored any
|
||||||
|
// inconsistent and/or incorrect state, since that could easily break
|
||||||
|
// subsequent `this.getPage` calls.
|
||||||
|
this._pagePromises.length = 0;
|
||||||
|
this.cleanup();
|
||||||
|
|
||||||
|
throw new XRefParseException();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
cleanup: function PDFDocument_cleanup() {
|
cleanup: function PDFDocument_cleanup() {
|
||||||
return this.catalog.cleanup();
|
return this.catalog.cleanup();
|
||||||
},
|
},
|
||||||
|
@ -17,7 +17,7 @@ import {
|
|||||||
bytesToString, createPromiseCapability, createValidAbsoluteUrl, FormatError,
|
bytesToString, createPromiseCapability, createValidAbsoluteUrl, FormatError,
|
||||||
info, InvalidPDFException, isBool, isNum, isString, MissingDataException,
|
info, InvalidPDFException, isBool, isNum, isString, MissingDataException,
|
||||||
PermissionFlag, shadow, stringToPDFString, stringToUTF8String,
|
PermissionFlag, shadow, stringToPDFString, stringToUTF8String,
|
||||||
toRomanNumerals, unreachable, warn, XRefParseException
|
toRomanNumerals, unreachable, warn, XRefEntryException, XRefParseException
|
||||||
} from '../shared/util';
|
} from '../shared/util';
|
||||||
import {
|
import {
|
||||||
Dict, isCmd, isDict, isName, isRef, isRefsEqual, isStream, Ref, RefSet,
|
Dict, isCmd, isDict, isName, isRef, isRefsEqual, isStream, Ref, RefSet,
|
||||||
@ -1473,7 +1473,7 @@ var XRef = (function XRefClosure() {
|
|||||||
if (xrefEntry.uncompressed) {
|
if (xrefEntry.uncompressed) {
|
||||||
xrefEntry = this.fetchUncompressed(ref, xrefEntry, suppressEncryption);
|
xrefEntry = this.fetchUncompressed(ref, xrefEntry, suppressEncryption);
|
||||||
} else {
|
} else {
|
||||||
xrefEntry = this.fetchCompressed(xrefEntry, suppressEncryption);
|
xrefEntry = this.fetchCompressed(ref, xrefEntry, suppressEncryption);
|
||||||
}
|
}
|
||||||
if (isDict(xrefEntry)) {
|
if (isDict(xrefEntry)) {
|
||||||
xrefEntry.objId = ref.toString();
|
xrefEntry.objId = ref.toString();
|
||||||
@ -1483,12 +1483,11 @@ var XRef = (function XRefClosure() {
|
|||||||
return xrefEntry;
|
return xrefEntry;
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchUncompressed: function XRef_fetchUncompressed(ref, xrefEntry,
|
fetchUncompressed(ref, xrefEntry, suppressEncryption = false) {
|
||||||
suppressEncryption) {
|
|
||||||
var gen = ref.gen;
|
var gen = ref.gen;
|
||||||
var num = ref.num;
|
var num = ref.num;
|
||||||
if (xrefEntry.gen !== gen) {
|
if (xrefEntry.gen !== gen) {
|
||||||
throw new FormatError('inconsistent generation in XRef');
|
throw new XRefEntryException(`Inconsistent generation in XRef: ${ref}`);
|
||||||
}
|
}
|
||||||
var stream = this.stream.makeSubStream(xrefEntry.offset +
|
var stream = this.stream.makeSubStream(xrefEntry.offset +
|
||||||
this.stream.start);
|
this.stream.start);
|
||||||
@ -1504,7 +1503,7 @@ var XRef = (function XRefClosure() {
|
|||||||
obj2 = parseInt(obj2, 10);
|
obj2 = parseInt(obj2, 10);
|
||||||
}
|
}
|
||||||
if (obj1 !== num || obj2 !== gen || !isCmd(obj3)) {
|
if (obj1 !== num || obj2 !== gen || !isCmd(obj3)) {
|
||||||
throw new FormatError('bad XRef entry');
|
throw new XRefEntryException(`Bad (uncompressed) XRef entry: ${ref}`);
|
||||||
}
|
}
|
||||||
if (obj3.cmd !== 'obj') {
|
if (obj3.cmd !== 'obj') {
|
||||||
// some bad PDFs use "obj1234" and really mean 1234
|
// some bad PDFs use "obj1234" and really mean 1234
|
||||||
@ -1514,7 +1513,7 @@ var XRef = (function XRefClosure() {
|
|||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new FormatError('bad XRef entry');
|
throw new XRefEntryException(`Bad (uncompressed) XRef entry: ${ref}`);
|
||||||
}
|
}
|
||||||
if (this.encrypt && !suppressEncryption) {
|
if (this.encrypt && !suppressEncryption) {
|
||||||
xrefEntry = parser.getObj(this.encrypt.createCipherTransform(num, gen));
|
xrefEntry = parser.getObj(this.encrypt.createCipherTransform(num, gen));
|
||||||
@ -1527,8 +1526,7 @@ var XRef = (function XRefClosure() {
|
|||||||
return xrefEntry;
|
return xrefEntry;
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchCompressed: function XRef_fetchCompressed(xrefEntry,
|
fetchCompressed(ref, xrefEntry, suppressEncryption = false) {
|
||||||
suppressEncryption) {
|
|
||||||
var tableOffset = xrefEntry.offset;
|
var tableOffset = xrefEntry.offset;
|
||||||
var stream = this.fetch(new Ref(tableOffset, 0));
|
var stream = this.fetch(new Ref(tableOffset, 0));
|
||||||
if (!isStream(stream)) {
|
if (!isStream(stream)) {
|
||||||
@ -1573,7 +1571,7 @@ var XRef = (function XRefClosure() {
|
|||||||
}
|
}
|
||||||
xrefEntry = entries[xrefEntry.gen];
|
xrefEntry = entries[xrefEntry.gen];
|
||||||
if (xrefEntry === undefined) {
|
if (xrefEntry === undefined) {
|
||||||
throw new FormatError('bad XRef entry for compressed object');
|
throw new XRefEntryException(`Bad (compressed) XRef entry: ${ref}`);
|
||||||
}
|
}
|
||||||
return xrefEntry;
|
return xrefEntry;
|
||||||
},
|
},
|
||||||
|
@ -258,33 +258,22 @@ var WorkerMessageHandler = {
|
|||||||
WorkerTasks.splice(i, 1);
|
WorkerTasks.splice(i, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadDocument(recoveryMode) {
|
async function loadDocument(recoveryMode) {
|
||||||
var loadDocumentCapability = createPromiseCapability();
|
await pdfManager.ensureDoc('checkHeader');
|
||||||
|
await pdfManager.ensureDoc('parseStartXRef');
|
||||||
|
await pdfManager.ensureDoc('parse', [recoveryMode]);
|
||||||
|
|
||||||
var parseSuccess = function parseSuccess() {
|
if (!recoveryMode) {
|
||||||
Promise.all([
|
// Check that at least the first page can be successfully loaded,
|
||||||
pdfManager.ensureDoc('numPages'),
|
// since otherwise the XRef table is definitely not valid.
|
||||||
pdfManager.ensureDoc('fingerprint'),
|
await pdfManager.ensureDoc('checkFirstPage');
|
||||||
]).then(function([numPages, fingerprint]) {
|
}
|
||||||
loadDocumentCapability.resolve({
|
|
||||||
numPages,
|
|
||||||
fingerprint,
|
|
||||||
});
|
|
||||||
}, parseFailure);
|
|
||||||
};
|
|
||||||
|
|
||||||
var parseFailure = function parseFailure(e) {
|
const [numPages, fingerprint] = await Promise.all([
|
||||||
loadDocumentCapability.reject(e);
|
pdfManager.ensureDoc('numPages'),
|
||||||
};
|
pdfManager.ensureDoc('fingerprint'),
|
||||||
|
]);
|
||||||
pdfManager.ensureDoc('checkHeader', []).then(function() {
|
return { numPages, fingerprint, };
|
||||||
pdfManager.ensureDoc('parseStartXRef', []).then(function() {
|
|
||||||
pdfManager.ensureDoc('parse', [recoveryMode]).then(
|
|
||||||
parseSuccess, parseFailure);
|
|
||||||
}, parseFailure);
|
|
||||||
}, parseFailure);
|
|
||||||
|
|
||||||
return loadDocumentCapability.promise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPdfManager(data, evaluatorOptions) {
|
function getPdfManager(data, evaluatorOptions) {
|
||||||
|
@ -472,6 +472,18 @@ var MissingDataException = (function MissingDataExceptionClosure() {
|
|||||||
return MissingDataException;
|
return MissingDataException;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
const XRefEntryException = (function XRefEntryExceptionClosure() {
|
||||||
|
function XRefEntryException(msg) {
|
||||||
|
this.message = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
XRefEntryException.prototype = new Error();
|
||||||
|
XRefEntryException.prototype.name = 'XRefEntryException';
|
||||||
|
XRefEntryException.constructor = XRefEntryException;
|
||||||
|
|
||||||
|
return XRefEntryException;
|
||||||
|
})();
|
||||||
|
|
||||||
var XRefParseException = (function XRefParseExceptionClosure() {
|
var XRefParseException = (function XRefParseExceptionClosure() {
|
||||||
function XRefParseException(msg) {
|
function XRefParseException(msg) {
|
||||||
this.message = msg;
|
this.message = msg;
|
||||||
@ -1033,6 +1045,7 @@ export {
|
|||||||
UnknownErrorException,
|
UnknownErrorException,
|
||||||
Util,
|
Util,
|
||||||
toRomanNumerals,
|
toRomanNumerals,
|
||||||
|
XRefEntryException,
|
||||||
XRefParseException,
|
XRefParseException,
|
||||||
FormatError,
|
FormatError,
|
||||||
arrayByteLength,
|
arrayByteLength,
|
||||||
|
1
test/pdfs/issue10326.pdf.link
Normal file
1
test/pdfs/issue10326.pdf.link
Normal file
@ -0,0 +1 @@
|
|||||||
|
https://github.com/mozilla/pdf.js/files/2643238/test.1.pdf
|
1
test/pdfs/issue7496.pdf.link
Normal file
1
test/pdfs/issue7496.pdf.link
Normal file
@ -0,0 +1 @@
|
|||||||
|
https://github.com/mozilla/pdf.js/files/369694/repro-pdf.pdf
|
@ -1275,6 +1275,22 @@
|
|||||||
"rounds": 1,
|
"rounds": 1,
|
||||||
"type": "eq"
|
"type": "eq"
|
||||||
},
|
},
|
||||||
|
{ "id": "issue7496",
|
||||||
|
"file": "pdfs/issue7496.pdf",
|
||||||
|
"md5": "b422981ae781166e75c0fb4c3634ed96",
|
||||||
|
"link": true,
|
||||||
|
"rounds": 1,
|
||||||
|
"lastPage": 1,
|
||||||
|
"type": "load"
|
||||||
|
},
|
||||||
|
{ "id": "issue10326",
|
||||||
|
"file": "pdfs/issue10326.pdf",
|
||||||
|
"md5": "015c13b09ef735ea1204f38992c60487",
|
||||||
|
"link": true,
|
||||||
|
"rounds": 1,
|
||||||
|
"lastPage": 1,
|
||||||
|
"type": "load"
|
||||||
|
},
|
||||||
{ "id": "issue7544",
|
{ "id": "issue7544",
|
||||||
"file": "pdfs/issue7544.pdf",
|
"file": "pdfs/issue7544.pdf",
|
||||||
"md5": "87e3a9fc7d6a6c1bd5b53af6926ce48e",
|
"md5": "87e3a9fc7d6a6c1bd5b53af6926ce48e",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user