Repair the table of contents

    Whenever we replace a page wholesale, it gets assigned a new objgen number
    and other references to it within the PDF become invalid, most notably in
    the table of contents (/Outlines in PDF-speak).  In weave_layers we collect
    pageref_remap, a mapping that describes the new objgen number given an old
    one.  (objgen is a tuple, and the gen is almost always zero.)

    It may ultimately be better to find a way to rebuild a page in place.

def _fix_toc(pdf_base, pageref_remap, log):
    """Repair the table of contents

    Whenever we replace a page wholesale, it gets assigned a new objgen number
    and other references to it within the PDF become invalid, most notably in
    the table of contents (/Outlines in PDF-speak).  In weave_layers we collect
    pageref_remap, a mapping that describes the new objgen number given an old
    one.  (objgen is a tuple, and the gen is almost always zero.)

    It may ultimately be better to find a way to rebuild a page in place.

    """

    if not pageref_remap:
        return

    def remap_dest(dest_node):
        """
        Inner helper function: change the objgen for any page from the old we
        invalidated to its new one.
        """
        try:
            pageref = dest_node[0]
            if pageref['/Type'] == '/Page' and pageref.objgen in pageref_remap:
                new_objgen = pageref_remap[pageref.objgen]
                dest_node[0] = pdf_base.get_object(new_objgen)
        except (IndexError, TypeError) as e:
            log.warning("This file may contain invalid table of contents entries")
            log.debug(e)

    def visit_remap_dest(pdf_base, node, log):
        """
        Visitor function to fix ToC entries

        Test for the two types of references to pages that can occur in ToCs.
        Both types have the same final format (an indirect reference to the
        target page).
        """
        if '/Dest' in node:
            # /Dest reference to another page (old method)
            remap_dest(node['/Dest'])
        elif '/A' in node:
            # /A (action) command set to "GoTo" (newer method)
            if '/S' in node['/A'] and node['/A']['/S'] == '/GoTo':
                remap_dest(node['/A']['/D'])

    _traverse_toc(pdf_base, visit_remap_dest, log)