|
|
|
@ -457,6 +457,38 @@ var Catalog = (function CatalogClosure() {
@@ -457,6 +457,38 @@ var Catalog = (function CatalogClosure() {
|
|
|
|
|
} |
|
|
|
|
return shadow(this, 'destinations', dests); |
|
|
|
|
}, |
|
|
|
|
getDestination: function Catalog_getDestination(destinationId) { |
|
|
|
|
function fetchDestination(dest) { |
|
|
|
|
return isDict(dest) ? dest.get('D') : dest; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var xref = this.xref; |
|
|
|
|
var dest, 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; |
|
|
|
|
} |
|
|
|
|
if (key === destinationId) { |
|
|
|
|
dest = fetchDestination(value); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
if (nameTreeRef) { |
|
|
|
|
var nameTree = new NameTree(nameTreeRef, xref); |
|
|
|
|
dest = fetchDestination(nameTree.get(destinationId)); |
|
|
|
|
} |
|
|
|
|
return dest; |
|
|
|
|
}, |
|
|
|
|
get attachments() { |
|
|
|
|
var xref = this.xref; |
|
|
|
|
var attachments = null, nameTreeRef; |
|
|
|
@ -1358,6 +1390,76 @@ var NameTree = (function NameTreeClosure() {
@@ -1358,6 +1390,76 @@ var NameTree = (function NameTreeClosure() {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return dict; |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
get: function NameTree_get(destinationId) { |
|
|
|
|
if (!this.root) { |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var xref = this.xref; |
|
|
|
|
var kidsOrNames = xref.fetchIfRef(this.root); |
|
|
|
|
var loopCount = 0; |
|
|
|
|
var MAX_NAMES_LEVELS = 10; |
|
|
|
|
var l, r, m; |
|
|
|
|
|
|
|
|
|
// Perform a binary search to quickly find the entry that
|
|
|
|
|
// contains the named destination we are looking for.
|
|
|
|
|
while (kidsOrNames.has('Kids')) { |
|
|
|
|
loopCount++; |
|
|
|
|
if (loopCount > MAX_NAMES_LEVELS) { |
|
|
|
|
warn('Search depth limit for named destionations has been reached.'); |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var kids = kidsOrNames.get('Kids'); |
|
|
|
|
if (!isArray(kids)) { |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
l = 0; |
|
|
|
|
r = kids.length - 1; |
|
|
|
|
while (l <= r) { |
|
|
|
|
m = (l + r) >> 1; |
|
|
|
|
var kid = xref.fetchIfRef(kids[m]); |
|
|
|
|
var limits = kid.get('Limits'); |
|
|
|
|
|
|
|
|
|
if (destinationId < limits[0]) { |
|
|
|
|
r = m - 1; |
|
|
|
|
} else if (destinationId > limits[1]) { |
|
|
|
|
l = m + 1; |
|
|
|
|
} else { |
|
|
|
|
kidsOrNames = xref.fetchIfRef(kids[m]); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (l > r) { |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// If we get here, then we have found the right entry. Now
|
|
|
|
|
// go through the named destinations in the Named dictionary
|
|
|
|
|
// until we find the exact destination we're looking for.
|
|
|
|
|
var names = kidsOrNames.get('Names'); |
|
|
|
|
if (isArray(names)) { |
|
|
|
|
// Perform a binary search to reduce the lookup time.
|
|
|
|
|
l = 0; |
|
|
|
|
r = names.length - 2; |
|
|
|
|
while (l <= r) { |
|
|
|
|
// Check only even indices (0, 2, 4, ...) because the
|
|
|
|
|
// odd indices contain the actual D array.
|
|
|
|
|
m = (l + r) & ~1; |
|
|
|
|
if (destinationId < names[m]) { |
|
|
|
|
r = m - 2; |
|
|
|
|
} else if (destinationId > names[m]) { |
|
|
|
|
l = m + 2; |
|
|
|
|
} else { |
|
|
|
|
return xref.fetchIfRef(names[m + 1]); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
return NameTree; |
|
|
|
|