[api-minor] Add support, in getMetadata, for custom information dictionary entries (issue 5970, issue 10344) (#10346)

The custom entries, provided that they exist *and* that their types are safe to include, are exposed through a new `Custom` infoDict entry to clearly separate them from the standard ones.

Fixes 5970.
Fixes 10344.
This commit is contained in:
Jonas Jenwald 2018-12-18 23:26:02 +01:00 committed by Tim van der Meij
parent 811c8803b3
commit ba2edeae18
2 changed files with 58 additions and 8 deletions

View File

@ -14,8 +14,8 @@
*/
import {
assert, FormatError, getInheritableProperty, info, isArrayBuffer, isNum,
isSpace, isString, MissingDataException, OPS, shadow, stringToBytes,
assert, FormatError, getInheritableProperty, info, isArrayBuffer, isBool,
isNum, isSpace, isString, MissingDataException, OPS, shadow, stringToBytes,
stringToPDFString, Util, warn
} from '../shared/util';
import { Catalog, ObjectLoader, XRef } from './obj';
@ -544,17 +544,37 @@ var PDFDocument = (function PDFDocumentClosure() {
info('The document information dictionary is invalid.');
}
if (isDict(infoDict)) {
// Only fill the document info with valid entries from the spec.
for (let key in DocumentInfoValidators) {
if (infoDict.has(key)) {
const value = infoDict.get(key);
// Make sure the value conforms to the spec.
// Fill the document info with valid entries from the specification,
// as well as any existing well-formed custom entries.
for (let key of infoDict.getKeys()) {
const value = infoDict.get(key);
if (DocumentInfoValidators[key]) {
// Make sure the (standard) value conforms to the specification.
if (DocumentInfoValidators[key](value)) {
docInfo[key] = (typeof value !== 'string' ?
value : stringToPDFString(value));
} else {
info('Bad value in document info for "' + key + '"');
info(`Bad value in document info for "${key}".`);
}
} else if (typeof key === 'string') {
// For custom values, only accept white-listed types to prevent
// errors that would occur when trying to send non-serializable
// objects to the main-thread (for example `Dict` or `Stream`).
let customValue;
if (isString(value)) {
customValue = stringToPDFString(value);
} else if (isName(value) || isNum(value) || isBool(value)) {
customValue = value;
} else {
info(`Unsupported value in document info for (custom) "${key}".`);
continue;
}
if (!docInfo['Custom']) {
docInfo['Custom'] = Object.create(null);
}
docInfo['Custom'][key] = customValue;
}
}
}

View File

@ -829,6 +829,8 @@ describe('api', function() {
var promise = doc.getMetadata();
promise.then(function({ info, metadata, contentDispositionFilename, }) {
expect(info['Title']).toEqual('Basic API Test');
// Custom, non-standard, information dictionary entries.
expect(info['Custom']).toEqual(undefined);
// The following are PDF.js specific, non-standard, properties.
expect(info['PDFFormatVersion']).toEqual('1.7');
expect(info['IsLinearized']).toEqual(false);
@ -842,6 +844,34 @@ describe('api', function() {
done();
}).catch(done.fail);
});
it('gets metadata, with custom info dict entries', function(done) {
var loadingTask = getDocument(buildGetDocumentParams('tracemonkey.pdf'));
loadingTask.promise.then(function(pdfDocument) {
return pdfDocument.getMetadata();
}).then(function({ info, metadata, contentDispositionFilename, }) {
expect(info['Creator']).toEqual('TeX');
expect(info['Producer']).toEqual('pdfeTeX-1.21a');
expect(info['CreationDate']).toEqual('D:20090401163925-07\'00\'');
// Custom, non-standard, information dictionary entries.
const custom = info['Custom'];
expect(typeof custom === 'object' && custom !== null).toEqual(true);
expect(custom['PTEX.Fullbanner']).toEqual('This is pdfeTeX, ' +
'Version 3.141592-1.21a-2.2 (Web2C 7.5.4) kpathsea version 3.5.6');
// The following are PDF.js specific, non-standard, properties.
expect(info['PDFFormatVersion']).toEqual('1.4');
expect(info['IsLinearized']).toEqual(false);
expect(info['IsAcroFormPresent']).toEqual(false);
expect(info['IsXFAPresent']).toEqual(false);
expect(metadata).toEqual(null);
expect(contentDispositionFilename).toEqual(null);
loadingTask.destroy().then(done);
}).catch(done.fail);
});
it('gets data', function(done) {
var promise = doc.getData();
promise.then(function (data) {