Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-factor destinations/getDestination to reduce unnecessary duplication, and reject non-string inputs #9975

Merged
merged 2 commits into from
Aug 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 26 additions & 49 deletions src/core/obj.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ import { ChunkedStream } from './chunked_stream';
import { CipherTransformFactory } from './crypto';
import { ColorSpace } from './colorspace';

function fetchDestination(dest) {
return isDict(dest) ? dest.get('D') : dest;
}

var Catalog = (function CatalogClosure() {
function Catalog(pdfManager, xref) {
this.pdfManager = pdfManager;
Expand Down Expand Up @@ -173,64 +177,37 @@ var Catalog = (function CatalogClosure() {
// shadow the prototype getter
return shadow(this, 'numPages', obj);
},
get destinations() {
function fetchDestination(dest) {
return isDict(dest) ? dest.get('D') : dest;
}

var xref = this.xref;
var dests = {}, nameTreeRef, nameDictionaryRef;
var obj = this.catDict.get('Names');
if (obj && obj.has('Dests')) {
nameTreeRef = obj.getRaw('Dests');
} else if (this.catDict.has('Dests')) {
nameDictionaryRef = this.catDict.get('Dests');
}

if (nameDictionaryRef) {
// reading simple destination dictionary
obj = nameDictionaryRef;
obj.forEach(function catalogForEach(key, value) {
if (!value) {
return;
}
dests[key] = fetchDestination(value);
});
}
if (nameTreeRef) {
var nameTree = new NameTree(nameTreeRef, xref);
var names = nameTree.getAll();
for (var name in names) {
get destinations() {
const obj = this._readDests(), dests = Object.create(null);
if (obj instanceof NameTree) {
const names = obj.getAll();
for (let name in names) {
dests[name] = fetchDestination(names[name]);
}
} else if (obj instanceof Dict) {
obj.forEach(function(key, value) {
if (value) {
dests[key] = fetchDestination(value);
}
});
}
return shadow(this, 'destinations', dests);
},
getDestination: function Catalog_getDestination(destinationId) {
function fetchDestination(dest) {
return isDict(dest) ? dest.get('D') : dest;
getDestination(destinationId) {
const obj = this._readDests();
if (obj instanceof NameTree || obj instanceof Dict) {
return fetchDestination(obj.get(destinationId) || null);
}

var xref = this.xref;
var dest = null, nameTreeRef, nameDictionaryRef;
var obj = this.catDict.get('Names');
return null;
},
_readDests() {
const obj = this.catDict.get('Names');
if (obj && obj.has('Dests')) {
nameTreeRef = obj.getRaw('Dests');
} else if (this.catDict.has('Dests')) {
nameDictionaryRef = this.catDict.get('Dests');
}

if (nameDictionaryRef) { // Simple destination dictionary.
var value = nameDictionaryRef.get(destinationId);
if (value) {
dest = fetchDestination(value);
}
}
if (nameTreeRef) {
var nameTree = new NameTree(nameTreeRef, xref);
dest = fetchDestination(nameTree.get(destinationId));
return new NameTree(obj.getRaw('Dests'), this.xref);
} else if (this.catDict.has('Dests')) { // Simple destination dictionary.
return this.catDict.get('Dests');
}
return dest;
},

get pageLabels() {
Expand Down
5 changes: 4 additions & 1 deletion src/display/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
return this.transport.getDestinations();
},
/**
* @param {string} id The named destination to get.
* @param {string} id - The named destination to get.
* @return {Promise} A promise that is resolved with all information
* of the given named destination.
*/
Expand Down Expand Up @@ -2119,6 +2119,9 @@ var WorkerTransport = (function WorkerTransportClosure() {
},

getDestination: function WorkerTransport_getDestination(id) {
if (typeof id !== 'string') {
return Promise.reject(new Error('Invalid destination request.'));
}
return this.messageHandler.sendWithPromise('GetDestination', {
id,
});
Expand Down
26 changes: 26 additions & 0 deletions test/unit/api_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,32 @@ describe('api', function() {
});
});

it('gets non-string destination', function(done) {
let numberPromise = doc.getDestination(4.3);
let booleanPromise = doc.getDestination(true);
let arrayPromise = doc.getDestination([
{ num: 17, gen: 0, }, { name: 'XYZ', }, 0, 841.89, null]);

numberPromise = numberPromise.then(function() {
throw new Error('shall fail for non-string destination.');
}, function(reason) {
expect(reason instanceof Error).toEqual(true);
});
booleanPromise = booleanPromise.then(function() {
throw new Error('shall fail for non-string destination.');
}, function(reason) {
expect(reason instanceof Error).toEqual(true);
});
arrayPromise = arrayPromise.then(function() {
throw new Error('shall fail for non-string destination.');
}, function(reason) {
expect(reason instanceof Error).toEqual(true);
});

Promise.all([numberPromise, booleanPromise, arrayPromise]).then(
done, done.fail);
});

it('gets non-existent page labels', function (done) {
var promise = doc.getPageLabels();
promise.then(function (data) {
Expand Down