QPDF::updateObjectMapsInternal(ObjUser const& ou, QPDFObjectHandle oh,
			       std::set<QPDFObjGen>& visited, bool top)
{
    // Traverse the object tree from this point taking care to avoid
    // crossing page boundaries.

    bool is_page_node = false;

    if (oh.isDictionary() && oh.hasKey("/Type"))
    {
	std::string type = oh.getKey("/Type").getName();
	if (type == "/Page")
	{
	    is_page_node = true;
	    if (! top)
	    {
		return;
	    }
	}
    }

    if (oh.isIndirect())
    {
	QPDFObjGen og(oh.getObjGen());
	if (visited.count(og))
	{
	    QTC::TC("qpdf", "QPDF opt loop detected");
	    return;
	}
	this->m->obj_user_to_objects[ou].insert(og);
	this->m->object_to_obj_users[og].insert(ou);
	visited.insert(og);
    }

    if (oh.isArray())
    {
	int n = oh.getArrayNItems();
	for (int i = 0; i < n; ++i)
	{
	    updateObjectMapsInternal(ou, oh.getArrayItem(i), visited, false);
	}
    }
    else if (oh.isDictionary() || oh.isStream())
    {
	QPDFObjectHandle dict = oh;
	if (oh.isStream())
	{
	    dict = oh.getDict();
	}

	std::set<std::string> keys = dict.getKeys();
	for (std::set<std::string>::iterator iter = keys.begin();
	     iter != keys.end(); ++iter)
	{
	    std::string const& key = *iter;
	    if (is_page_node && (key == "/Thumb"))
	    {
		// Traverse page thumbnail dictionaries as a special
		// case.
		updateObjectMaps(ObjUser(ObjUser::ou_thumb, ou.pageno),
				 dict.getKey(key));
	    }
	    else if (is_page_node && (key == "/Parent"))
	    {
		// Don't traverse back up the page tree
	    }
	    else
	    {
		updateObjectMapsInternal(ou, dict.getKey(key),
					 visited, false);
	    }
	}
    }
}
QPDF::updateObjectMapsInternal(ObjUser const& ou, QPDFObjectHandle oh,
			       std::set<QPDFObjGen>& visited, bool top)
{
     
     

    bool is_page_node = false;

    if (oh.isDictionary() && oh.hasKey("/Type"))
    {
	std::string type = oh.getKey("/Type").getName();
	if (type == "/Page")
	{
	    is_page_node = true;
	    if (! top)
	    {
		return;
	    }
	}
    }

    if (oh.isIndirect())
    {
	QPDFObjGen og(oh.getObjGen());
	if (visited.count(og))
	{
	    QTC::TC("qpdf", "QPDF opt loop detected");
	    return;
	}
	this->m->obj_user_to_objects[ou].insert(og);
	this->m->object_to_obj_users[og].insert(ou);
	visited.insert(og);
    }

    if (oh.isArray())
    {
	int n = oh.getArrayNItems();
	for (int i = 0; i < n; ++i)
	{
	    updateObjectMapsInternal(ou, oh.getArrayItem(i), visited, false);
	}
    }
    else if (oh.isDictionary() || oh.isStream())
    {
	QPDFObjectHandle dict = oh;
	if (oh.isStream())
	{
	    dict = oh.getDict();
	}

	std::set<std::string> keys = dict.getKeys();
	for (std::set<std::string>::iterator iter = keys.begin();
	     iter != keys.end(); ++iter)
	{
	    std::string const& key = *iter;
	    if (is_page_node && (key == "/Thumb"))
	    {
		 
		 
		updateObjectMaps(ObjUser(ObjUser::ou_thumb, ou.pageno),
				 dict.getKey(key));
	    }
	    else if (is_page_node && (key == "/Parent"))
	    {
		 
	    }
	    else
	    {
		updateObjectMapsInternal(ou, dict.getKey(key),
					 visited, false);
	    }
	}
    }
}