Commit 98c14e7740cb879be05ce95a22a3c1f2c403bea0

Authored by m-holger
1 parent 7775aec3

Refactor QPDF::checkLinearizationInternal

include/qpdf/QPDF.hh
... ... @@ -836,6 +836,7 @@ class QPDF
836 836 void optimize(
837 837 QPDFWriter::ObjTable const& obj,
838 838 std::function<int(QPDFObjectHandle&)> skip_stream_parameters);
  839 + void optimize(Xref_table const& obj);
839 840 size_t tableSize();
840 841  
841 842 // Get lists of all objects in order according to the part of a linearized file that they belong
... ... @@ -935,6 +936,7 @@ class QPDF
935 936 QPDFObjectHandle
936 937 getUncompressedObject(QPDFObjectHandle&, std::map<int, int> const& object_stream_data);
937 938 QPDFObjectHandle getUncompressedObject(QPDFObjectHandle&, QPDFWriter::ObjTable const& obj);
  939 + QPDFObjectHandle getUncompressedObject(QPDFObjectHandle&, Xref_table const& obj);
938 940 int lengthNextN(int first_object, int n);
939 941 void
940 942 checkHPageOffset(std::vector<QPDFObjectHandle> const& pages, std::map<int, int>& idx_to_obj);
... ... @@ -980,6 +982,7 @@ class QPDF
980 982 std::function<int(QPDFObjectHandle&)> skip_stream_parameters);
981 983 void filterCompressedObjects(std::map<int, int> const& object_stream_data);
982 984 void filterCompressedObjects(QPDFWriter::ObjTable const& object_stream_data);
  985 + void filterCompressedObjects(Xref_table const& object_stream_data);
983 986  
984 987 // JSON import
985 988 void importJSON(std::shared_ptr<InputSource>, bool must_be_complete);
... ...
libqpdf/QPDF_linearization.cc
... ... @@ -484,18 +484,9 @@ QPDF::checkLinearizationInternal()
484 484 // Further checking requires optimization and order calculation. Don't allow optimization to
485 485 // make changes. If it has to, then the file is not properly linearized. We use the xref table
486 486 // to figure out which objects are compressed and which are uncompressed.
487   - { // local scope
488   - std::map<int, int> object_stream_data;
489   - for (auto const& iter: m->xref_table.as_map()) {
490   - QPDFObjGen const& og = iter.first;
491   - QPDFXRefEntry const& entry = iter.second;
492   - if (entry.getType() == 2) {
493   - object_stream_data[og.getObj()] = entry.getObjStreamNumber();
494   - }
495   - }
496   - optimize(object_stream_data, false);
497   - calculateLinearizationData(object_stream_data);
498   - }
  487 +
  488 + optimize(m->xref_table);
  489 + calculateLinearizationData(m->xref_table);
499 490  
500 491 // E: offset of end of first page -- Implementation note 123 says Acrobat includes on extra
501 492 // object here by mistake. pdlin fails to place thumbnail images in section 9, so when
... ... @@ -582,6 +573,16 @@ QPDF::getUncompressedObject(QPDFObjectHandle&amp; obj, std::map&lt;int, int&gt; const&amp; obj
582 573 }
583 574  
584 575 QPDFObjectHandle
  576 +QPDF::getUncompressedObject(QPDFObjectHandle& obj, Xref_table const& xref)
  577 +{
  578 + auto og = obj.getObjGen();
  579 + if (obj.isNull() || xref.type(og) != 2) {
  580 + return obj;
  581 + }
  582 + return getObject(xref.stream_number(og.getObj()), 0);
  583 +}
  584 +
  585 +QPDFObjectHandle
585 586 QPDF::getUncompressedObject(QPDFObjectHandle& oh, QPDFWriter::ObjTable const& obj)
586 587 {
587 588 if (obj.contains(oh)) {
... ...
libqpdf/QPDF_optimization.cc
... ... @@ -78,6 +78,12 @@ QPDF::optimize(
78 78 optimize_internal(obj, true, skip_stream_parameters);
79 79 }
80 80  
  81 +void
  82 +QPDF::optimize(QPDF::Xref_table const& xref)
  83 +{
  84 + optimize_internal(xref, false, nullptr);
  85 +}
  86 +
81 87 template <typename T>
82 88 void
83 89 QPDF::optimize_internal(
... ... @@ -442,3 +448,45 @@ QPDF::filterCompressedObjects(QPDFWriter::ObjTable const&amp; obj)
442 448 m->obj_user_to_objects = t_obj_user_to_objects;
443 449 m->object_to_obj_users = t_object_to_obj_users;
444 450 }
  451 +
  452 +void
  453 +QPDF::filterCompressedObjects(QPDF::Xref_table const& xref)
  454 +{
  455 + if (!xref.object_streams()) {
  456 + return;
  457 + }
  458 +
  459 + // Transform object_to_obj_users and obj_user_to_objects so that they refer only to uncompressed
  460 + // objects. If something is a user of a compressed object, then it is really a user of the
  461 + // object stream that contains it.
  462 +
  463 + std::map<ObjUser, std::set<QPDFObjGen>> t_obj_user_to_objects;
  464 + std::map<QPDFObjGen, std::set<ObjUser>> t_object_to_obj_users;
  465 +
  466 + for (auto const& i1: m->obj_user_to_objects) {
  467 + ObjUser const& ou = i1.first;
  468 + // Loop over objects.
  469 + for (auto const& og: i1.second) {
  470 + if (auto stream = xref.stream_number(og.getObj())) {
  471 + t_obj_user_to_objects[ou].insert(QPDFObjGen(stream, 0));
  472 + } else {
  473 + t_obj_user_to_objects[ou].insert(og);
  474 + }
  475 + }
  476 + }
  477 +
  478 + for (auto const& i1: m->object_to_obj_users) {
  479 + QPDFObjGen const& og = i1.first;
  480 + // Loop over obj_users.
  481 + for (auto const& ou: i1.second) {
  482 + if (auto stream = xref.stream_number(og.getObj())) {
  483 + t_object_to_obj_users[QPDFObjGen(stream, 0)].insert(ou);
  484 + } else {
  485 + t_object_to_obj_users[og].insert(ou);
  486 + }
  487 + }
  488 + }
  489 +
  490 + m->obj_user_to_objects = t_obj_user_to_objects;
  491 + m->object_to_obj_users = t_object_to_obj_users;
  492 +}
... ...