diff --git a/examples/pdf-bookmarks.cc b/examples/pdf-bookmarks.cc index 802cdbac..5d11fb32 100644 --- a/examples/pdf-bookmarks.cc +++ b/examples/pdf-bookmarks.cc @@ -9,7 +9,7 @@ static char const* whoami = 0; static enum { st_none, st_numbers, st_lines } style = st_none; static bool show_open = false; static bool show_targets = false; -static std::map page_map; +static std::map page_map; void usage() { @@ -50,7 +50,7 @@ void generate_page_map(QPDF& qpdf) iter != pages.end(); ++iter) { QPDFObjectHandle& oh = *iter; - page_map[oh.getObjectID()] = ++n; + page_map[oh.getObjGen()] = ++n; } } @@ -121,10 +121,10 @@ void extract_bookmarks(QPDFObjectHandle outlines, std::vector& numbers) if ((dest.isArray()) && (dest.getArrayNItems() > 0)) { QPDFObjectHandle first = dest.getArrayItem(0); - int object_id = first.getObjectID(); - if (page_map.count(object_id)) + QPDFObjGen og = first.getObjGen(); + if (page_map.count(og)) { - target = QUtil::int_to_string(page_map[object_id]); + target = QUtil::int_to_string(page_map[og]); } } diff --git a/examples/pdf-invert-images.cc b/examples/pdf-invert-images.cc index 60f4e8d1..f4a4e4ab 100644 --- a/examples/pdf-invert-images.cc +++ b/examples/pdf-invert-images.cc @@ -34,10 +34,10 @@ class ImageInverter: public QPDFObjectHandle::StreamDataProvider virtual void provideStreamData(int objid, int generation, Pipeline* pipeline); - // Map [obj][gen] = image object - std::map > image_objects; - // Map [obj][gen] = image data - std::map > > image_data; + // Map [og] = image object + std::map image_objects; + // Map [og] = image data + std::map > image_data; }; void @@ -47,7 +47,8 @@ ImageInverter::provideStreamData(int objid, int generation, // Use the object and generation number supplied to look up the // image data. Then invert the image data and write the inverted // data to the pipeline. - PointerHolder data = this->image_data[objid][generation]; + PointerHolder data = + this->image_data[QPDFObjGen(objid, generation)]; size_t size = data->getSize(); unsigned char* buf = data->getBuffer(); unsigned char ch; @@ -120,12 +121,11 @@ int main(int argc, char* argv[]) // Store information about the images based on the // object and generation number. Recall that a single // image object may be used more than once. - int objid = image.getObjectID(); - int gen = image.getGeneration(); - if (inv->image_objects[objid].count(gen) == 0) + QPDFObjGen og = image.getObjGen(); + if (inv->image_objects.count(og) == 0) { - inv->image_objects[objid][gen] = image; - inv->image_data[objid][gen] = image.getStreamData(); + inv->image_objects[og] = image; + inv->image_data[og] = image.getStreamData(); // Register our stream data provider for this // stream. Future calls to getStreamData or diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index 6f78c687..fd0c9b54 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -159,6 +159,8 @@ class QPDF // Retrieve an object by object ID and generation. Returns an // indirect reference to it. QPDF_DLL + QPDFObjectHandle getObjectByObjGen(QPDFObjGen const&); + QPDF_DLL QPDFObjectHandle getObjectByID(int objid, int generation); // Replace the object with the given object id with the given @@ -175,6 +177,8 @@ class QPDF // object. To replace a reserved object, call replaceReserved // instead. QPDF_DLL + void replaceObject(QPDFObjGen const& og, QPDFObjectHandle); + QPDF_DLL void replaceObject(int objid, int generation, QPDFObjectHandle); // Swap two objects given by ID. Calling this method can have @@ -189,6 +193,8 @@ class QPDF // to the swapped objects with new ones, possibly by calling // getObjectByID. QPDF_DLL + void swapObjects(QPDFObjGen const& og1, QPDFObjGen const& og2); + QPDF_DLL void swapObjects(int objid1, int generation1, int objid2, int generation2); @@ -623,7 +629,7 @@ class QPDF void getAllPagesInternal(QPDFObjectHandle cur_pages, std::vector& result); void insertPage(QPDFObjectHandle newpage, int pos); - int findPage(int objid, int generation); + int findPage(QPDFObjGen const& og); int findPage(QPDFObjectHandle& page); void flattenPagesTree(); void insertPageobjToPage(QPDFObjectHandle const& obj, int pos, diff --git a/include/qpdf/QPDFObjGen.hh b/include/qpdf/QPDFObjGen.hh index 5f789197..67ef1b0f 100644 --- a/include/qpdf/QPDFObjGen.hh +++ b/include/qpdf/QPDFObjGen.hh @@ -23,6 +23,8 @@ class QPDFObjGen QPDF_DLL bool operator<(QPDFObjGen const&) const; QPDF_DLL + bool operator==(QPDFObjGen const&) const; + QPDF_DLL int getObj() const; QPDF_DLL int getGen() const; diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 053aeaa8..5c5e0e79 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -1573,12 +1573,24 @@ QPDF::makeIndirectObject(QPDFObjectHandle oh) this, next.getObj(), next.getGen()); } +QPDFObjectHandle +QPDF::getObjectByObjGen(QPDFObjGen const& og) +{ + return getObjectByID(og.getObj(), og.getGen()); +} + QPDFObjectHandle QPDF::getObjectByID(int objid, int generation) { return QPDFObjectHandle::Factory::newIndirect(this, objid, generation); } +void +QPDF::replaceObject(QPDFObjGen const& og, QPDFObjectHandle oh) +{ + replaceObject(og.getObj(), og.getGen(), oh); +} + void QPDF::replaceObject(int objid, int generation, QPDFObjectHandle oh) { @@ -1604,9 +1616,7 @@ QPDF::replaceReserved(QPDFObjectHandle reserved, { QTC::TC("qpdf", "QPDF replaceReserved"); reserved.assertReserved(); - replaceObject(reserved.getObjectID(), - reserved.getGeneration(), - replacement); + replaceObject(reserved.getObjGen(), replacement); } QPDFObjectHandle @@ -1663,14 +1673,13 @@ QPDF::copyForeignObject(QPDFObjectHandle foreign, bool allow_page) replaceForeignIndirectObjects(to_copy, obj_copier, true); if (! to_copy.isStream()) { - QPDFObjGen og(to_copy.getObjectID(), to_copy.getGeneration()); + QPDFObjGen og(to_copy.getObjGen()); replaceReserved(obj_copier.object_map[og], copy); } } obj_copier.to_copy.clear(); - return obj_copier.object_map[QPDFObjGen(foreign.getObjectID(), - foreign.getGeneration())]; + return obj_copier.object_map[foreign.getObjGen()]; } void @@ -1697,7 +1706,7 @@ QPDF::reserveObjects(QPDFObjectHandle foreign, ObjCopier& obj_copier, if (foreign.isIndirect()) { - QPDFObjGen foreign_og(foreign.getObjectID(), foreign.getGeneration()); + QPDFObjGen foreign_og(foreign.getObjGen()); if (obj_copier.visiting.find(foreign_og) != obj_copier.visiting.end()) { QTC::TC("qpdf", "QPDF loop reserving objects"); @@ -1750,7 +1759,7 @@ QPDF::reserveObjects(QPDFObjectHandle foreign, ObjCopier& obj_copier, if (foreign.isIndirect()) { - QPDFObjGen foreign_og(foreign.getObjectID(), foreign.getGeneration()); + QPDFObjGen foreign_og(foreign.getObjGen()); obj_copier.visiting.erase(foreign_og); } } @@ -1763,7 +1772,7 @@ QPDF::replaceForeignIndirectObjects( if ((! top) && foreign.isIndirect()) { QTC::TC("qpdf", "QPDF replace indirect"); - QPDFObjGen foreign_og(foreign.getObjectID(), foreign.getGeneration()); + QPDFObjGen foreign_og(foreign.getObjGen()); std::map::iterator mapping = obj_copier.object_map.find(foreign_og); if (mapping == obj_copier.object_map.end()) @@ -1807,7 +1816,7 @@ QPDF::replaceForeignIndirectObjects( else if (foreign.isStream()) { QTC::TC("qpdf", "QPDF replace stream"); - QPDFObjGen foreign_og(foreign.getObjectID(), foreign.getGeneration()); + QPDFObjGen foreign_og(foreign.getObjGen()); result = obj_copier.object_map[foreign_og]; result.assertStream(); QPDFObjectHandle dict = result.getDict(); @@ -1826,7 +1835,7 @@ QPDF::replaceForeignIndirectObjects( this->copied_stream_data_provider = new CopiedStreamDataProvider(); this->copied_streams = this->copied_stream_data_provider; } - QPDFObjGen local_og(result.getObjectID(), result.getGeneration()); + QPDFObjGen local_og(result.getObjGen()); this->copied_stream_data_provider->registerForeignStream( local_og, foreign); result.replaceStreamData(this->copied_streams, @@ -1848,6 +1857,12 @@ QPDF::replaceForeignIndirectObjects( return result; } +void +QPDF::swapObjects(QPDFObjGen const& og1, QPDFObjGen const& og2) +{ + swapObjects(og1.getObj(), og1.getGen(), og2.getObj(), og2.getGen()); +} + void QPDF::swapObjects(int objid1, int generation1, int objid2, int generation2) { @@ -2101,8 +2116,7 @@ QPDF::findAttachmentStreams() item.getKey("/EF").getKey("/F").isStream()) { QPDFObjectHandle stream = item.getKey("/EF").getKey("/F"); - this->attachment_streams.insert( - QPDFObjGen(stream.getObjectID(), stream.getGeneration())); + this->attachment_streams.insert(stream.getObjGen()); } } } diff --git a/libqpdf/QPDFObjGen.cc b/libqpdf/QPDFObjGen.cc index e43a0aea..817e660e 100644 --- a/libqpdf/QPDFObjGen.cc +++ b/libqpdf/QPDFObjGen.cc @@ -13,6 +13,12 @@ QPDFObjGen::operator<(QPDFObjGen const& rhs) const ((this->obj == rhs.obj) && (this->gen < rhs.gen))); } +bool +QPDFObjGen::operator==(QPDFObjGen const& rhs) const +{ + return ((this->obj == rhs.obj) && (this->gen == rhs.gen)); +} + int QPDFObjGen::getObj() const { diff --git a/libqpdf/QPDF_linearization.cc b/libqpdf/QPDF_linearization.cc index fc57c115..4b1f5c09 100644 --- a/libqpdf/QPDF_linearization.cc +++ b/libqpdf/QPDF_linearization.cc @@ -336,9 +336,7 @@ QPDF::readHintStream(Pipeline& pl, qpdf_offset_t offset, size_t length) QTC::TC("qpdf", "QPDF hint table length indirect"); // Force resolution (void) length_obj.getIntValue(); - ObjCache& oc = this->obj_cache - [QPDFObjGen(length_obj.getObjectID(), - length_obj.getGeneration())]; + ObjCache& oc = this->obj_cache[length_obj.getObjGen()]; min_end_offset = oc.end_before_space; max_end_offset = oc.end_after_space; } @@ -499,7 +497,7 @@ QPDF::checkLinearizationInternal() for (int i = 0; i < npages; ++i) { QPDFObjectHandle const& page = pages[i]; - QPDFObjGen og(page.getObjectID(), page.getGeneration()); + QPDFObjGen og(page.getObjGen()); if (this->xref_table[og].getType() == 2) { errors.push_back("page dictionary for page " + @@ -582,7 +580,7 @@ QPDF::checkLinearizationInternal() for (std::vector::iterator iter = this->part6.begin(); iter != this->part6.end(); ++iter) { - QPDFObjGen og((*iter).getObjectID(), (*iter).getGeneration()); + QPDFObjGen og((*iter).getObjGen()); // All objects have to have been dereferenced to be classified. assert(this->obj_cache.count(og) > 0); ObjCache const& oc = this->obj_cache[og]; @@ -740,7 +738,7 @@ QPDF::checkHPageOffset(std::list& errors, unsigned int npages = pages.size(); int table_offset = adjusted_offset( this->page_offset_hints.first_page_offset); - QPDFObjGen first_page_og(pages[0].getObjectID(), pages[0].getGeneration()); + QPDFObjGen first_page_og(pages[0].getObjGen()); assert(this->xref_table.count(first_page_og) > 0); int offset = getLinearizationOffset(first_page_og); if (table_offset != offset) @@ -750,8 +748,7 @@ QPDF::checkHPageOffset(std::list& errors, for (unsigned int pageno = 0; pageno < npages; ++pageno) { - QPDFObjGen page_og(pages[pageno].getObjectID(), - pages[pageno].getGeneration()); + QPDFObjGen page_og(pages[pageno].getObjGen()); int first_object = page_og.getObj(); assert(this->xref_table.count(page_og) > 0); offset = getLinearizationOffset(page_og); @@ -961,7 +958,7 @@ QPDF::checkHOutlines(std::list& warnings) { // Check length and offset. Acrobat gets these wrong. QPDFObjectHandle outlines = getRoot().getKey("/Outlines"); - QPDFObjGen og(outlines.getObjectID(), outlines.getGeneration()); + QPDFObjGen og(outlines.getObjGen()); assert(this->xref_table.count(og) > 0); int offset = getLinearizationOffset(og); ObjUser ou(ObjUser::ou_root_key, "/Outlines"); @@ -1466,7 +1463,7 @@ QPDF::calculateLinearizationData(std::map const& object_stream_data) // will do the same. // First, place the actual first page object itself. - QPDFObjGen first_page_og(pages[0].getObjectID(), pages[0].getGeneration()); + QPDFObjGen first_page_og(pages[0].getObjGen()); if (! lc_first_page_private.count(first_page_og)) { throw std::logic_error( @@ -1515,7 +1512,7 @@ QPDF::calculateLinearizationData(std::map const& object_stream_data) { // Place this page's page object - QPDFObjGen page_og(pages[i].getObjectID(), pages[i].getGeneration()); + QPDFObjGen page_og(pages[i].getObjGen()); if (! lc_other_page_private.count(page_og)) { throw std::logic_error( @@ -1598,7 +1595,7 @@ QPDF::calculateLinearizationData(std::map const& object_stream_data) if (! thumb.isNull()) { // Output the thumbnail itself - QPDFObjGen thumb_og(thumb.getObjectID(), thumb.getGeneration()); + QPDFObjGen thumb_og(thumb.getObjGen()); if (lc_thumbnail_private.count(thumb_og)) { lc_thumbnail_private.erase(thumb_og); @@ -1753,7 +1750,7 @@ QPDF::pushOutlinesToPart( return; } outlines = getUncompressedObject(outlines, object_stream_data); - QPDFObjGen outlines_og(outlines.getObjectID(), outlines.getGeneration()); + QPDFObjGen outlines_og(outlines.getObjGen()); QTC::TC("qpdf", "QPDF lin outlines in part", ((&part == (&this->part6)) ? 0 : (&part == (&this->part9)) ? 1 diff --git a/libqpdf/QPDF_optimization.cc b/libqpdf/QPDF_optimization.cc index 271c6610..0286fdb9 100644 --- a/libqpdf/QPDF_optimization.cc +++ b/libqpdf/QPDF_optimization.cc @@ -115,7 +115,7 @@ QPDF::optimize(std::map const& object_stream_data, } ObjUser root_ou = ObjUser(ObjUser::ou_root); - QPDFObjGen root_og = QPDFObjGen(root.getObjectID(), root.getGeneration()); + QPDFObjGen root_og = QPDFObjGen(root.getObjGen()); obj_user_to_objects[root_ou].insert(root_og); object_to_obj_users[root_og].insert(root_ou); @@ -338,7 +338,7 @@ QPDF::updateObjectMapsInternal(ObjUser const& ou, QPDFObjectHandle oh, if (oh.isIndirect()) { - QPDFObjGen og(oh.getObjectID(), oh.getGeneration()); + QPDFObjGen og(oh.getObjGen()); if (visited.count(og)) { QTC::TC("qpdf", "QPDF opt loop detected"); diff --git a/libqpdf/QPDF_pages.cc b/libqpdf/QPDF_pages.cc index 4f1525e7..0604cd40 100644 --- a/libqpdf/QPDF_pages.cc +++ b/libqpdf/QPDF_pages.cc @@ -127,7 +127,7 @@ void QPDF::insertPageobjToPage(QPDFObjectHandle const& obj, int pos, bool check_duplicate) { - QPDFObjGen og(obj.getObjectID(), obj.getGeneration()); + QPDFObjGen og(obj.getObjGen()); if (check_duplicate) { if (! this->pageobj_to_pages_pos.insert(std::make_pair(og, pos)).second) @@ -214,8 +214,7 @@ QPDF::removePage(QPDFObjectHandle page) pages.replaceKey("/Count", QPDFObjectHandle::newInteger(npages)); this->all_pages.erase(this->all_pages.begin() + pos); assert(this->all_pages.size() == static_cast(npages)); - this->pageobj_to_pages_pos.erase( - QPDFObjGen(page.getObjectID(), page.getGeneration())); + this->pageobj_to_pages_pos.erase(page.getObjGen()); assert(this->pageobj_to_pages_pos.size() == static_cast(npages)); for (int i = pos; i < npages; ++i) { @@ -253,18 +252,18 @@ int QPDF::findPage(QPDFObjectHandle& page) { page.assertPageObject(); - return findPage(page.getObjectID(), page.getGeneration()); + return findPage(page.getObjGen()); } int -QPDF::findPage(int objid, int generation) +QPDF::findPage(QPDFObjGen const& og) { flattenPagesTree(); std::map::iterator it = - this->pageobj_to_pages_pos.find(QPDFObjGen(objid, generation)); + this->pageobj_to_pages_pos.find(og); if (it == this->pageobj_to_pages_pos.end()) { - setLastObjectDescription("page object", objid, generation); + setLastObjectDescription("page object", og.getObj(), og.getGen()); throw QPDFExc(qpdf_e_pages, this->file->getName(), this->last_object_description, 0, "page object not referenced in /Pages tree"); diff --git a/qpdf/qpdf.cc b/qpdf/qpdf.cc index 7a0a50dd..39a536d9 100644 --- a/qpdf/qpdf.cc +++ b/qpdf/qpdf.cc @@ -1621,8 +1621,7 @@ int main(int argc, char* argv[]) { if (selected_from_orig.count(pageno) == 0) { - pdf.replaceObject(orig_pages[pageno].getObjectID(), - orig_pages[pageno].getGeneration(), + pdf.replaceObject(orig_pages[pageno].getObjGen(), QPDFObjectHandle::newNull()); } } diff --git a/qpdf/test_driver.cc b/qpdf/test_driver.cc index ec6fcff0..31fc0525 100644 --- a/qpdf/test_driver.cc +++ b/qpdf/test_driver.cc @@ -659,8 +659,7 @@ void runtest(int n, char const* filename1, char const* arg2) " not called 4-page file"); } // Swap pages 2 and 3 - pdf.swapObjects(pages[1].getObjectID(), pages[1].getGeneration(), - pages[2].getObjectID(), pages[2].getGeneration()); + pdf.swapObjects(pages[1].getObjGen(), pages[2].getObjGen()); // Replace object and swap objects QPDFObjectHandle trailer = pdf.getTrailer(); QPDFObjectHandle qdict = trailer.getKey("/QDict"); @@ -672,21 +671,18 @@ void runtest(int n, char const* filename1, char const* arg2) try { // Do it wrong first... - pdf.replaceObject(qdict.getObjectID(), qdict.getGeneration(), - qdict); + pdf.replaceObject(qdict.getObjGen(), qdict); } catch (std::logic_error) { std::cout << "caught logic error as expected" << std::endl; } - pdf.replaceObject(qdict.getObjectID(), qdict.getGeneration(), - new_dict); + pdf.replaceObject(qdict.getObjGen(), new_dict); // Now qdict still points to the old dictionary std::cout << "old dict: " << qdict.getKey("/Dict").getIntValue() << std::endl; // Swap dict and array - pdf.swapObjects(qdict.getObjectID(), qdict.getGeneration(), - qarray.getObjectID(), qarray.getGeneration()); + pdf.swapObjects(qdict.getObjGen(), qarray.getObjGen()); // Now qarray will resolve to new object but qdict is still // the old object std::cout << "old dict: " << qdict.getKey("/Dict").getIntValue() @@ -694,7 +690,7 @@ void runtest(int n, char const* filename1, char const* arg2) std::cout << "new dict: " << qarray.getKey("/NewDict").getIntValue() << std::endl; // Reread qdict, now pointing to an array - qdict = pdf.getObjectByID(qdict.getObjectID(), qdict.getGeneration()); + qdict = pdf.getObjectByObjGen(qdict.getObjGen()); std::cout << "swapped array: " << qdict.getArrayItem(0).getName() << std::endl; @@ -788,14 +784,14 @@ void runtest(int n, char const* filename1, char const* arg2) pdf.addPage(new_pages[0], true); checkPageContents(pages[0], "New page 1"); pdf.addPageAt(new_pages[1], true, pages[0]); - assert(pages[0].getObjectID() == new_pages[1].getObjectID()); + assert(pages[0].getObjGen() == new_pages[1].getObjGen()); pdf.addPageAt(new_pages[2], true, pages[5]); - assert(pages[5].getObjectID() == new_pages[2].getObjectID()); + assert(pages[5].getObjGen() == new_pages[2].getObjGen()); pdf.addPageAt(new_pages[3], false, pages[5]); - assert(pages[6].getObjectID() == new_pages[3].getObjectID()); + assert(pages[6].getObjGen() == new_pages[3].getObjGen()); assert(pages.size() == 11); pdf.addPage(new_pages[4], false); - assert(pages[11].getObjectID() == new_pages[4].getObjectID()); + assert(pages[11].getObjGen() == new_pages[4].getObjGen()); pdf.addPageAt(new_pages[5], false, pages.back()); assert(pages.size() == 13); checkPageContents(pages[0], "New page 0"); @@ -835,7 +831,7 @@ void runtest(int n, char const* filename1, char const* arg2) assert(all_pages.size() == 10); pdf.updateAllPagesCache(); assert(all_pages.size() == 11); - assert(all_pages.back().getObjectID() == page.getObjectID()); + assert(all_pages.back().getObjGen() == page.getObjGen()); QPDFWriter w(pdf, "a.pdf"); w.setStaticID(true); @@ -862,7 +858,7 @@ void runtest(int n, char const* filename1, char const* arg2) pdf.removePage(page5); pdf.addPage(page5, false); assert(pages.size() == 10); - assert(pages.back().getObjectID() == page5.getObjectID()); + assert(pages.back().getObjGen() == page5.getObjGen()); QPDFWriter w(pdf, "a.pdf"); w.setStaticID(true);