Merge pull request #13415 from Snuffleupagus/getDestination-out-of-order
Improve handling of named destinations in out-of-order NameTrees (PR 10274 follow-up)
This commit is contained in:
		
						commit
						d1d9b9043d
					
				@ -53,7 +53,10 @@ import { MetadataParser } from "./metadata_parser.js";
 | 
				
			|||||||
import { StructTreeRoot } from "./struct_tree.js";
 | 
					import { StructTreeRoot } from "./struct_tree.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function fetchDestination(dest) {
 | 
					function fetchDestination(dest) {
 | 
				
			||||||
  return isDict(dest) ? dest.get("D") : dest;
 | 
					  if (dest instanceof Dict) {
 | 
				
			||||||
 | 
					    dest = dest.get("D");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return Array.isArray(dest) ? dest : null;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Catalog {
 | 
					class Catalog {
 | 
				
			||||||
@ -515,22 +518,41 @@ class Catalog {
 | 
				
			|||||||
      dests = Object.create(null);
 | 
					      dests = Object.create(null);
 | 
				
			||||||
    if (obj instanceof NameTree) {
 | 
					    if (obj instanceof NameTree) {
 | 
				
			||||||
      for (const [key, value] of obj.getAll()) {
 | 
					      for (const [key, value] of obj.getAll()) {
 | 
				
			||||||
        dests[key] = fetchDestination(value);
 | 
					        const dest = fetchDestination(value);
 | 
				
			||||||
 | 
					        if (dest) {
 | 
				
			||||||
 | 
					          dests[key] = dest;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    } else if (obj instanceof Dict) {
 | 
					    } else if (obj instanceof Dict) {
 | 
				
			||||||
      obj.forEach(function (key, value) {
 | 
					      obj.forEach(function (key, value) {
 | 
				
			||||||
        if (value) {
 | 
					        const dest = fetchDestination(value);
 | 
				
			||||||
          dests[key] = fetchDestination(value);
 | 
					        if (dest) {
 | 
				
			||||||
 | 
					          dests[key] = dest;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return shadow(this, "destinations", dests);
 | 
					    return shadow(this, "destinations", dests);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getDestination(destinationId) {
 | 
					  getDestination(id) {
 | 
				
			||||||
    const obj = this._readDests();
 | 
					    const obj = this._readDests();
 | 
				
			||||||
    if (obj instanceof NameTree || obj instanceof Dict) {
 | 
					    if (obj instanceof NameTree) {
 | 
				
			||||||
      return fetchDestination(obj.get(destinationId) || null);
 | 
					      const dest = fetchDestination(obj.get(id));
 | 
				
			||||||
 | 
					      if (dest) {
 | 
				
			||||||
 | 
					        return dest;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      // Fallback to checking the *entire* NameTree, in an attempt to handle
 | 
				
			||||||
 | 
					      // corrupt PDF documents with out-of-order NameTrees (fixes issue 10272).
 | 
				
			||||||
 | 
					      const allDest = this.destinations[id];
 | 
				
			||||||
 | 
					      if (allDest) {
 | 
				
			||||||
 | 
					        warn(`Found "${id}" at an incorrect position in the NameTree.`);
 | 
				
			||||||
 | 
					        return allDest;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else if (obj instanceof Dict) {
 | 
				
			||||||
 | 
					      const dest = fetchDestination(obj.get(id));
 | 
				
			||||||
 | 
					      if (dest) {
 | 
				
			||||||
 | 
					        return dest;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return null;
 | 
					    return null;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -13,7 +13,7 @@
 | 
				
			|||||||
 * limitations under the License.
 | 
					 * limitations under the License.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { FormatError, info, unreachable, warn } from "../shared/util.js";
 | 
					import { FormatError, unreachable, warn } from "../shared/util.js";
 | 
				
			||||||
import { isDict, RefSet } from "./primitives.js";
 | 
					import { isDict, RefSet } from "./primitives.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -133,23 +133,6 @@ class NameOrNumberTree {
 | 
				
			|||||||
          return xref.fetchIfRef(entries[m + 1]);
 | 
					          return xref.fetchIfRef(entries[m + 1]);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Fallback to an exhaustive search, in an attempt to handle corrupt
 | 
					 | 
				
			||||||
      // PDF files where keys are not correctly ordered (fixes issue 10272).
 | 
					 | 
				
			||||||
      info(
 | 
					 | 
				
			||||||
        `Falling back to an exhaustive search, for key "${key}", ` +
 | 
					 | 
				
			||||||
          `in "${this._type}" tree.`
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
      for (let m = 0, mm = entries.length; m < mm; m += 2) {
 | 
					 | 
				
			||||||
        const currentKey = xref.fetchIfRef(entries[m]);
 | 
					 | 
				
			||||||
        if (currentKey === key) {
 | 
					 | 
				
			||||||
          warn(
 | 
					 | 
				
			||||||
            `The "${key}" key was found at an incorrect, ` +
 | 
					 | 
				
			||||||
              `i.e. out-of-order, position in "${this._type}" tree.`
 | 
					 | 
				
			||||||
          );
 | 
					 | 
				
			||||||
          return xref.fetchIfRef(entries[m + 1]);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return null;
 | 
					    return null;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -730,8 +730,9 @@ class PDFDocumentProxy {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * @param {string} id - The named destination to get.
 | 
					   * @param {string} id - The named destination to get.
 | 
				
			||||||
   * @returns {Promise<Array<any>>} A promise that is resolved with all
 | 
					   * @returns {Promise<Array<any> | null>} A promise that is resolved with all
 | 
				
			||||||
   *   information of the given named destination.
 | 
					   *   information of the given named destination, or `null` when the named
 | 
				
			||||||
 | 
					   *   destination is not present in the PDF file.
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  getDestination(id) {
 | 
					  getDestination(id) {
 | 
				
			||||||
    return this._transport.getDestination(id);
 | 
					    return this._transport.getDestination(id);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										1
									
								
								test/pdfs/issue10272.pdf.link
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/pdfs/issue10272.pdf.link
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					https://github.com/mozilla/pdf.js/files/2598691/ATS_TEST_PVC_2_1.pdf
 | 
				
			||||||
@ -917,6 +917,12 @@
 | 
				
			|||||||
       "link": true,
 | 
					       "link": true,
 | 
				
			||||||
       "type": "load"
 | 
					       "type": "load"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    {  "id": "issue10272",
 | 
				
			||||||
 | 
					       "file": "pdfs/issue10272.pdf",
 | 
				
			||||||
 | 
					       "md5": "bf3b2f74c6878d38a70dc0825f1b9a02",
 | 
				
			||||||
 | 
					       "link": true,
 | 
				
			||||||
 | 
					       "type": "other"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    {  "id": "issue10388",
 | 
					    {  "id": "issue10388",
 | 
				
			||||||
       "file": "pdfs/issue10388_reduced.pdf",
 | 
					       "file": "pdfs/issue10388_reduced.pdf",
 | 
				
			||||||
       "md5": "62a6b2adbea1535432bd94a3516e2d4c",
 | 
					       "md5": "62a6b2adbea1535432bd94a3516e2d4c",
 | 
				
			||||||
 | 
				
			|||||||
@ -669,6 +669,24 @@ describe("api", function () {
 | 
				
			|||||||
      await loadingTask.destroy();
 | 
					      await loadingTask.destroy();
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it("gets a destination, from out-of-order /Names (NameTree) dictionary (issue 10272)", async function () {
 | 
				
			||||||
 | 
					      if (isNodeJS) {
 | 
				
			||||||
 | 
					        pending("Linked test-cases are not supported in Node.js.");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      const loadingTask = getDocument(buildGetDocumentParams("issue10272.pdf"));
 | 
				
			||||||
 | 
					      const pdfDoc = await loadingTask.promise;
 | 
				
			||||||
 | 
					      const destination = await pdfDoc.getDestination("link_1");
 | 
				
			||||||
 | 
					      expect(destination).toEqual([
 | 
				
			||||||
 | 
					        { num: 17, gen: 0 },
 | 
				
			||||||
 | 
					        { name: "XYZ" },
 | 
				
			||||||
 | 
					        69,
 | 
				
			||||||
 | 
					        125,
 | 
				
			||||||
 | 
					        0,
 | 
				
			||||||
 | 
					      ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await loadingTask.destroy();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it("gets non-string destination", async function () {
 | 
					    it("gets non-string destination", async function () {
 | 
				
			||||||
      let numberPromise = pdfDocument.getDestination(4.3);
 | 
					      let numberPromise = pdfDocument.getDestination(4.3);
 | 
				
			||||||
      let booleanPromise = pdfDocument.getDestination(true);
 | 
					      let booleanPromise = pdfDocument.getDestination(true);
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user