Commit 98c14e7740cb879be05ce95a22a3c1f2c403bea0

Authored by m-holger
1 parent 7775aec3

Refactor QPDF::checkLinearizationInternal

include/qpdf/QPDF.hh
@@ -836,6 +836,7 @@ class QPDF @@ -836,6 +836,7 @@ class QPDF
836 void optimize( 836 void optimize(
837 QPDFWriter::ObjTable const& obj, 837 QPDFWriter::ObjTable const& obj,
838 std::function<int(QPDFObjectHandle&)> skip_stream_parameters); 838 std::function<int(QPDFObjectHandle&)> skip_stream_parameters);
  839 + void optimize(Xref_table const& obj);
839 size_t tableSize(); 840 size_t tableSize();
840 841
841 // Get lists of all objects in order according to the part of a linearized file that they belong 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,6 +936,7 @@ class QPDF
935 QPDFObjectHandle 936 QPDFObjectHandle
936 getUncompressedObject(QPDFObjectHandle&, std::map<int, int> const& object_stream_data); 937 getUncompressedObject(QPDFObjectHandle&, std::map<int, int> const& object_stream_data);
937 QPDFObjectHandle getUncompressedObject(QPDFObjectHandle&, QPDFWriter::ObjTable const& obj); 938 QPDFObjectHandle getUncompressedObject(QPDFObjectHandle&, QPDFWriter::ObjTable const& obj);
  939 + QPDFObjectHandle getUncompressedObject(QPDFObjectHandle&, Xref_table const& obj);
938 int lengthNextN(int first_object, int n); 940 int lengthNextN(int first_object, int n);
939 void 941 void
940 checkHPageOffset(std::vector<QPDFObjectHandle> const& pages, std::map<int, int>& idx_to_obj); 942 checkHPageOffset(std::vector<QPDFObjectHandle> const& pages, std::map<int, int>& idx_to_obj);
@@ -980,6 +982,7 @@ class QPDF @@ -980,6 +982,7 @@ class QPDF
980 std::function<int(QPDFObjectHandle&)> skip_stream_parameters); 982 std::function<int(QPDFObjectHandle&)> skip_stream_parameters);
981 void filterCompressedObjects(std::map<int, int> const& object_stream_data); 983 void filterCompressedObjects(std::map<int, int> const& object_stream_data);
982 void filterCompressedObjects(QPDFWriter::ObjTable const& object_stream_data); 984 void filterCompressedObjects(QPDFWriter::ObjTable const& object_stream_data);
  985 + void filterCompressedObjects(Xref_table const& object_stream_data);
983 986
984 // JSON import 987 // JSON import
985 void importJSON(std::shared_ptr<InputSource>, bool must_be_complete); 988 void importJSON(std::shared_ptr<InputSource>, bool must_be_complete);
libqpdf/QPDF_linearization.cc
@@ -484,18 +484,9 @@ QPDF::checkLinearizationInternal() @@ -484,18 +484,9 @@ QPDF::checkLinearizationInternal()
484 // Further checking requires optimization and order calculation. Don't allow optimization to 484 // Further checking requires optimization and order calculation. Don't allow optimization to
485 // make changes. If it has to, then the file is not properly linearized. We use the xref table 485 // make changes. If it has to, then the file is not properly linearized. We use the xref table
486 // to figure out which objects are compressed and which are uncompressed. 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 // E: offset of end of first page -- Implementation note 123 says Acrobat includes on extra 491 // E: offset of end of first page -- Implementation note 123 says Acrobat includes on extra
501 // object here by mistake. pdlin fails to place thumbnail images in section 9, so when 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,6 +573,16 @@ QPDF::getUncompressedObject(QPDFObjectHandle&amp; obj, std::map&lt;int, int&gt; const&amp; obj
582 } 573 }
583 574
584 QPDFObjectHandle 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 QPDF::getUncompressedObject(QPDFObjectHandle& oh, QPDFWriter::ObjTable const& obj) 586 QPDF::getUncompressedObject(QPDFObjectHandle& oh, QPDFWriter::ObjTable const& obj)
586 { 587 {
587 if (obj.contains(oh)) { 588 if (obj.contains(oh)) {
libqpdf/QPDF_optimization.cc
@@ -78,6 +78,12 @@ QPDF::optimize( @@ -78,6 +78,12 @@ QPDF::optimize(
78 optimize_internal(obj, true, skip_stream_parameters); 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 template <typename T> 87 template <typename T>
82 void 88 void
83 QPDF::optimize_internal( 89 QPDF::optimize_internal(
@@ -442,3 +448,45 @@ QPDF::filterCompressedObjects(QPDFWriter::ObjTable const&amp; obj) @@ -442,3 +448,45 @@ QPDF::filterCompressedObjects(QPDFWriter::ObjTable const&amp; obj)
442 m->obj_user_to_objects = t_obj_user_to_objects; 448 m->obj_user_to_objects = t_obj_user_to_objects;
443 m->object_to_obj_users = t_object_to_obj_users; 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 +}