Commit dd3de38974328a9345e1e3b6baab5fd123d2bd54

Authored by m-holger
1 parent 256f0633

Refactor `Lin` linearization hints: rename and encapsulate data structures.

include/qpdf/QPDF.hh
@@ -787,16 +787,6 @@ class QPDF @@ -787,16 +787,6 @@ class QPDF
787 bool is_root_metadata, 787 bool is_root_metadata,
788 std::unique_ptr<Pipeline>& heap); 788 std::unique_ptr<Pipeline>& heap);
789 789
790 - struct HPageOffsetEntry;  
791 - struct HPageOffset;  
792 - struct HSharedObjectEntry;  
793 - struct HSharedObject;  
794 - struct HGeneric;  
795 - struct LinParameters;  
796 - struct CHPageOffsetEntry;  
797 - struct CHPageOffset;  
798 - struct CHSharedObjectEntry;  
799 - struct CHSharedObject;  
800 class PatternFinder; 790 class PatternFinder;
801 791
802 // Methods to support pattern finding 792 // Methods to support pattern finding
libqpdf/QPDF_linearization.cc
@@ -186,7 +186,7 @@ Lin::optimize_internal( @@ -186,7 +186,7 @@ Lin::optimize_internal(
186 } 186 }
187 187
188 ObjUser root_ou = ObjUser(ObjUser::ou_root); 188 ObjUser root_ou = ObjUser(ObjUser::ou_root);
189 - auto root_og =root.id_gen(); 189 + auto root_og = root.id_gen();
190 obj_user_to_objects_[root_ou].insert(root_og); 190 obj_user_to_objects_[root_ou].insert(root_og);
191 object_to_obj_users_[root_og].insert(root_ou); 191 object_to_obj_users_[root_og].insert(root_ou);
192 192
@@ -427,8 +427,8 @@ Lin::linearized() @@ -427,8 +427,8 @@ Lin::linearized()
427 if (L != m->file->tell()) { 427 if (L != m->file->tell()) {
428 return false; 428 return false;
429 } 429 }
430 - m->linp.file_size = L;  
431 - m->lindict = candidate; 430 + linp_.file_size = L;
  431 + lindict_ = candidate;
432 return true; 432 return true;
433 } 433 }
434 } 434 }
@@ -444,17 +444,17 @@ Lin::readLinearizationData() @@ -444,17 +444,17 @@ Lin::readLinearizationData()
444 // that prevent loading. 444 // that prevent loading.
445 445
446 // /L is read and stored in linp by isLinearized() 446 // /L is read and stored in linp by isLinearized()
447 - Array H = m->lindict["/H"]; // hint table offset/length for primary and overflow hint tables 447 + Array H = lindict_["/H"]; // hint table offset/length for primary and overflow hint tables
448 auto H_size = H.size(); 448 auto H_size = H.size();
449 Integer H_0 = H[0]; // hint table offset 449 Integer H_0 = H[0]; // hint table offset
450 Integer H_1 = H[1]; // hint table length 450 Integer H_1 = H[1]; // hint table length
451 Integer H_2 = H[2]; // hint table offset for overflow hint table 451 Integer H_2 = H[2]; // hint table offset for overflow hint table
452 Integer H_3 = H[3]; // hint table length for overflow hint table 452 Integer H_3 = H[3]; // hint table length for overflow hint table
453 - Integer O = m->lindict["/O"];  
454 - Integer E = m->lindict["/E"];  
455 - Integer N = m->lindict["/N"];  
456 - Integer T = m->lindict["/T"];  
457 - auto P_oh = m->lindict["/P"]; 453 + Integer O = lindict_["/O"];
  454 + Integer E = lindict_["/E"];
  455 + Integer N = lindict_["/N"];
  456 + Integer T = lindict_["/T"];
  457 + auto P_oh = lindict_["/P"];
458 Integer P = P_oh; // first page number 458 Integer P = P_oh; // first page number
459 QTC::TC("qpdf", "QPDF P absent in lindict", P ? 0 : 1); 459 QTC::TC("qpdf", "QPDF P absent in lindict", P ? 0 : 1);
460 460
@@ -487,13 +487,13 @@ Lin::readLinearizationData() @@ -487,13 +487,13 @@ Lin::readLinearizationData()
487 ); 487 );
488 488
489 // file_size initialized by isLinearized() 489 // file_size initialized by isLinearized()
490 - m->linp.first_page_object = O;  
491 - m->linp.first_page_end = E;  
492 - m->linp.npages = N;  
493 - m->linp.xref_zero_offset = T;  
494 - m->linp.first_page = P ? P : 0;  
495 - m->linp.H_offset = H_0;  
496 - m->linp.H_length = H_1; 490 + linp_.first_page_object = O;
  491 + linp_.first_page_end = E;
  492 + linp_.npages = N;
  493 + linp_.xref_zero_offset = T;
  494 + linp_.first_page = P ? P : 0;
  495 + linp_.H_offset = H_0;
  496 + linp_.H_length = H_1;
497 497
498 // Read hint streams 498 // Read hint streams
499 499
@@ -537,7 +537,7 @@ Lin::readLinearizationData() @@ -537,7 +537,7 @@ Lin::readLinearizationData()
537 "linearization dictionary" // 537 "linearization dictionary" //
538 ); 538 );
539 size_t HOi = HO; 539 size_t HOi = HO;
540 - readHGeneric(BitStream(h_buf + HO, h_size - HOi), m->outline_hints); 540 + readHGeneric(BitStream(h_buf + HO, h_size - HOi), outline_hints_);
541 } 541 }
542 } 542 }
543 543
@@ -581,7 +581,7 @@ Lin::readHPageOffset(BitStream h) @@ -581,7 +581,7 @@ Lin::readHPageOffset(BitStream h)
581 { 581 {
582 // All comments referring to the PDF spec refer to the spec for version 1.4. 582 // All comments referring to the PDF spec refer to the spec for version 1.4.
583 583
584 - HPageOffset& t = m->page_offset_hints; 584 + HPageOffset& t = page_offset_hints_;
585 585
586 t.min_nobjects = h.getBitsInt(32); // 1 586 t.min_nobjects = h.getBitsInt(32); // 1
587 t.first_page_offset = h.getBitsInt(32); // 2 587 t.first_page_offset = h.getBitsInt(32); // 2
@@ -599,7 +599,7 @@ Lin::readHPageOffset(BitStream h) @@ -599,7 +599,7 @@ Lin::readHPageOffset(BitStream h)
599 599
600 std::vector<HPageOffsetEntry>& entries = t.entries; 600 std::vector<HPageOffsetEntry>& entries = t.entries;
601 entries.clear(); 601 entries.clear();
602 - int nitems = toI(m->linp.npages); 602 + int nitems = toI(linp_.npages);
603 load_vector_int(h, nitems, entries, t.nbits_delta_nobjects, &HPageOffsetEntry::delta_nobjects); 603 load_vector_int(h, nitems, entries, t.nbits_delta_nobjects, &HPageOffsetEntry::delta_nobjects);
604 load_vector_int( 604 load_vector_int(
605 h, nitems, entries, t.nbits_delta_page_length, &HPageOffsetEntry::delta_page_length); 605 h, nitems, entries, t.nbits_delta_page_length, &HPageOffsetEntry::delta_page_length);
@@ -628,7 +628,7 @@ Lin::readHPageOffset(BitStream h) @@ -628,7 +628,7 @@ Lin::readHPageOffset(BitStream h)
628 void 628 void
629 Lin::readHSharedObject(BitStream h) 629 Lin::readHSharedObject(BitStream h)
630 { 630 {
631 - HSharedObject& t = m->shared_object_hints; 631 + HSharedObject& t = shared_object_hints_;
632 632
633 t.first_shared_obj = h.getBitsInt(32); // 1 633 t.first_shared_obj = h.getBitsInt(32); // 1
634 t.first_shared_offset = h.getBitsInt(32); // 2 634 t.first_shared_offset = h.getBitsInt(32); // 2
@@ -677,7 +677,7 @@ Lin::checkLinearizationInternal() @@ -677,7 +677,7 @@ Lin::checkLinearizationInternal()
677 677
678 // Check all values in linearization parameter dictionary 678 // Check all values in linearization parameter dictionary
679 679
680 - LinParameters& p = m->linp; 680 + LinParameters& p = linp_;
681 681
682 // L: file size in bytes -- checked by isLinearized 682 // L: file size in bytes -- checked by isLinearized
683 683
@@ -873,7 +873,7 @@ Lin::checkHPageOffset( @@ -873,7 +873,7 @@ Lin::checkHPageOffset(
873 // dictionary in with shared objects even when they are private. 873 // dictionary in with shared objects even when they are private.
874 874
875 size_t npages = pages.size(); 875 size_t npages = pages.size();
876 - qpdf_offset_t table_offset = adjusted_offset(m->page_offset_hints.first_page_offset); 876 + qpdf_offset_t table_offset = adjusted_offset(page_offset_hints_.first_page_offset);
877 QPDFObjGen first_page_og(pages.at(0).getObjGen()); 877 QPDFObjGen first_page_og(pages.at(0).getObjGen());
878 if (!m->xref_table.contains(first_page_og)) { 878 if (!m->xref_table.contains(first_page_og)) {
879 stopOnError("supposed first page object is not known"); 879 stopOnError("supposed first page object is not known");
@@ -891,9 +891,9 @@ Lin::checkHPageOffset( @@ -891,9 +891,9 @@ Lin::checkHPageOffset(
891 } 891 }
892 offset = getLinearizationOffset(page_og); 892 offset = getLinearizationOffset(page_og);
893 893
894 - HPageOffsetEntry& he = m->page_offset_hints.entries.at(toS(pageno));  
895 - CHPageOffsetEntry& ce = m->c_page_offset_data.entries.at(toS(pageno));  
896 - int h_nobjects = he.delta_nobjects + m->page_offset_hints.min_nobjects; 894 + HPageOffsetEntry& he = page_offset_hints_.entries.at(pageno);
  895 + CHPageOffsetEntry& ce = c_page_offset_data_.entries.at(pageno);
  896 + int h_nobjects = he.delta_nobjects + page_offset_hints_.min_nobjects;
897 if (h_nobjects != ce.nobjects) { 897 if (h_nobjects != ce.nobjects) {
898 // This happens with pdlin when there are thumbnails. 898 // This happens with pdlin when there are thumbnails.
899 linearizationWarning( 899 linearizationWarning(
@@ -904,7 +904,7 @@ Lin::checkHPageOffset( @@ -904,7 +904,7 @@ Lin::checkHPageOffset(
904 // Use value for number of objects in hint table rather than computed value if there is a 904 // Use value for number of objects in hint table rather than computed value if there is a
905 // discrepancy. 905 // discrepancy.
906 int length = lengthNextN(first_object, h_nobjects); 906 int length = lengthNextN(first_object, h_nobjects);
907 - int h_length = toI(he.delta_page_length + m->page_offset_hints.min_page_length); 907 + int h_length = toI(he.delta_page_length + page_offset_hints_.min_page_length);
908 if (length != h_length) { 908 if (length != h_length) {
909 // This condition almost certainly indicates a bad hint table or a bug in this code. 909 // This condition almost certainly indicates a bad hint table or a bug in this code.
910 linearizationWarning( 910 linearizationWarning(
@@ -937,11 +937,11 @@ Lin::checkHPageOffset( @@ -937,11 +937,11 @@ Lin::checkHPageOffset(
937 for (size_t i = 0; i < toS(ce.nshared_objects); ++i) { 937 for (size_t i = 0; i < toS(ce.nshared_objects); ++i) {
938 int idx = ce.shared_identifiers.at(i); 938 int idx = ce.shared_identifiers.at(i);
939 no_ci_stop_if( 939 no_ci_stop_if(
940 - idx >= m->c_shared_object_data.nshared_total, 940 + idx >= c_shared_object_data_.nshared_total,
941 "index out of bounds for shared object hint table" // 941 "index out of bounds for shared object hint table" //
942 ); 942 );
943 943
944 - int obj = m->c_shared_object_data.entries.at(toS(idx)).object; 944 + int obj = c_shared_object_data_.entries.at(toS(idx)).object;
945 computed_shared.insert(obj); 945 computed_shared.insert(obj);
946 } 946 }
947 947
@@ -983,7 +983,7 @@ Lin::checkHSharedObject(std::vector&lt;QPDFObjectHandle&gt; const&amp; pages, std::map&lt;int @@ -983,7 +983,7 @@ Lin::checkHSharedObject(std::vector&lt;QPDFObjectHandle&gt; const&amp; pages, std::map&lt;int
983 // Empirically, Acrobat and pdlin generate incorrect values for these whenever there are no 983 // Empirically, Acrobat and pdlin generate incorrect values for these whenever there are no
984 // shared objects not referenced by the first page (i.e., nshared_total == nshared_first_page). 984 // shared objects not referenced by the first page (i.e., nshared_total == nshared_first_page).
985 985
986 - HSharedObject& so = m->shared_object_hints; 986 + HSharedObject& so = shared_object_hints_;
987 if (so.nshared_total < so.nshared_first_page) { 987 if (so.nshared_total < so.nshared_first_page) {
988 linearizationWarning("shared object hint table: ntotal < nfirst_page"); 988 linearizationWarning("shared object hint table: ntotal < nfirst_page");
989 } else { 989 } else {
@@ -1044,12 +1044,12 @@ Lin::checkHOutlines() @@ -1044,12 +1044,12 @@ Lin::checkHOutlines()
1044 // correct number of objects from the wrong starting place). pdlin appears to generate correct 1044 // correct number of objects from the wrong starting place). pdlin appears to generate correct
1045 // values in those cases. 1045 // values in those cases.
1046 1046
1047 - if (m->c_outline_data.nobjects == m->outline_hints.nobjects) {  
1048 - if (m->c_outline_data.nobjects == 0) { 1047 + if (c_outline_data_.nobjects == outline_hints_.nobjects) {
  1048 + if (c_outline_data_.nobjects == 0) {
1049 return; 1049 return;
1050 } 1050 }
1051 1051
1052 - if (m->c_outline_data.first_object == m->outline_hints.first_object) { 1052 + if (c_outline_data_.first_object == outline_hints_.first_object) {
1053 // Check length and offset. Acrobat gets these wrong. 1053 // Check length and offset. Acrobat gets these wrong.
1054 QPDFObjectHandle outlines = qpdf.getRoot().getKey("/Outlines"); 1054 QPDFObjectHandle outlines = qpdf.getRoot().getKey("/Outlines");
1055 if (!outlines.isIndirect()) { 1055 if (!outlines.isIndirect()) {
@@ -1065,13 +1065,13 @@ Lin::checkHOutlines() @@ -1065,13 +1065,13 @@ Lin::checkHOutlines()
1065 qpdf_offset_t offset = getLinearizationOffset(og); 1065 qpdf_offset_t offset = getLinearizationOffset(og);
1066 ObjUser ou(ObjUser::ou_root_key, "/Outlines"); 1066 ObjUser ou(ObjUser::ou_root_key, "/Outlines");
1067 int length = toI(maxEnd(ou) - offset); 1067 int length = toI(maxEnd(ou) - offset);
1068 - qpdf_offset_t table_offset = adjusted_offset(m->outline_hints.first_object_offset); 1068 + qpdf_offset_t table_offset = adjusted_offset(outline_hints_.first_object_offset);
1069 if (offset != table_offset) { 1069 if (offset != table_offset) {
1070 linearizationWarning( 1070 linearizationWarning(
1071 "incorrect offset in outlines table: hint table = " + 1071 "incorrect offset in outlines table: hint table = " +
1072 std::to_string(table_offset) + "; computed = " + std::to_string(offset)); 1072 std::to_string(table_offset) + "; computed = " + std::to_string(offset));
1073 } 1073 }
1074 - int table_length = m->outline_hints.group_length; 1074 + int table_length = outline_hints_.group_length;
1075 if (length != table_length) { 1075 if (length != table_length) {
1076 linearizationWarning( 1076 linearizationWarning(
1077 "incorrect length in outlines table: hint table = " + 1077 "incorrect length in outlines table: hint table = " +
@@ -1110,14 +1110,14 @@ Lin::dumpLinearizationDataInternal() @@ -1110,14 +1110,14 @@ Lin::dumpLinearizationDataInternal()
1110 1110
1111 info << m->file->getName() << ": linearization data:\n\n"; 1111 info << m->file->getName() << ": linearization data:\n\n";
1112 1112
1113 - info << "file_size: " << m->linp.file_size << "\n"  
1114 - << "first_page_object: " << m->linp.first_page_object << "\n"  
1115 - << "first_page_end: " << m->linp.first_page_end << "\n"  
1116 - << "npages: " << m->linp.npages << "\n"  
1117 - << "xref_zero_offset: " << m->linp.xref_zero_offset << "\n"  
1118 - << "first_page: " << m->linp.first_page << "\n"  
1119 - << "H_offset: " << m->linp.H_offset << "\n"  
1120 - << "H_length: " << m->linp.H_length << "\n" 1113 + info << "file_size: " << linp_.file_size << "\n"
  1114 + << "first_page_object: " << linp_.first_page_object << "\n"
  1115 + << "first_page_end: " << linp_.first_page_end << "\n"
  1116 + << "npages: " << linp_.npages << "\n"
  1117 + << "xref_zero_offset: " << linp_.xref_zero_offset << "\n"
  1118 + << "first_page: " << linp_.first_page << "\n"
  1119 + << "H_offset: " << linp_.H_offset << "\n"
  1120 + << "H_length: " << linp_.H_length << "\n"
1121 << "\n"; 1121 << "\n";
1122 1122
1123 info << "Page Offsets Hint Table\n\n"; 1123 info << "Page Offsets Hint Table\n\n";
@@ -1125,9 +1125,9 @@ Lin::dumpLinearizationDataInternal() @@ -1125,9 +1125,9 @@ Lin::dumpLinearizationDataInternal()
1125 info << "\nShared Objects Hint Table\n\n"; 1125 info << "\nShared Objects Hint Table\n\n";
1126 dumpHSharedObject(); 1126 dumpHSharedObject();
1127 1127
1128 - if (m->outline_hints.nobjects > 0) { 1128 + if (outline_hints_.nobjects > 0) {
1129 info << "\nOutlines Hint Table\n\n"; 1129 info << "\nOutlines Hint Table\n\n";
1130 - dumpHGeneric(m->outline_hints); 1130 + dumpHGeneric(outline_hints_);
1131 } 1131 }
1132 } 1132 }
1133 1133
@@ -1136,8 +1136,8 @@ Lin::adjusted_offset(qpdf_offset_t offset) @@ -1136,8 +1136,8 @@ Lin::adjusted_offset(qpdf_offset_t offset)
1136 { 1136 {
1137 // All offsets >= H_offset have to be increased by H_length since all hint table location values 1137 // All offsets >= H_offset have to be increased by H_length since all hint table location values
1138 // disregard the hint table itself. 1138 // disregard the hint table itself.
1139 - if (offset >= m->linp.H_offset) {  
1140 - return offset + m->linp.H_length; 1139 + if (offset >= linp_.H_offset) {
  1140 + return offset + linp_.H_length;
1141 } 1141 }
1142 return offset; 1142 return offset;
1143 } 1143 }
@@ -1146,7 +1146,7 @@ void @@ -1146,7 +1146,7 @@ void
1146 Lin::dumpHPageOffset() 1146 Lin::dumpHPageOffset()
1147 { 1147 {
1148 auto& info = *cf.log()->getInfo(); 1148 auto& info = *cf.log()->getInfo();
1149 - HPageOffset& t = m->page_offset_hints; 1149 + HPageOffset& t = page_offset_hints_;
1150 info << "min_nobjects: " << t.min_nobjects << "\n" 1150 info << "min_nobjects: " << t.min_nobjects << "\n"
1151 << "first_page_offset: " << adjusted_offset(t.first_page_offset) << "\n" 1151 << "first_page_offset: " << adjusted_offset(t.first_page_offset) << "\n"
1152 << "nbits_delta_nobjects: " << t.nbits_delta_nobjects << "\n" 1152 << "nbits_delta_nobjects: " << t.nbits_delta_nobjects << "\n"
@@ -1161,7 +1161,7 @@ Lin::dumpHPageOffset() @@ -1161,7 +1161,7 @@ Lin::dumpHPageOffset()
1161 << "nbits_shared_numerator: " << t.nbits_shared_numerator << "\n" 1161 << "nbits_shared_numerator: " << t.nbits_shared_numerator << "\n"
1162 << "shared_denominator: " << t.shared_denominator << "\n"; 1162 << "shared_denominator: " << t.shared_denominator << "\n";
1163 1163
1164 - for (size_t i1 = 0; i1 < m->linp.npages; ++i1) { 1164 + for (size_t i1 = 0; i1 < linp_.npages; ++i1) {
1165 HPageOffsetEntry& pe = t.entries.at(i1); 1165 HPageOffsetEntry& pe = t.entries.at(i1);
1166 info << "Page " << i1 << ":\n" 1166 info << "Page " << i1 << ":\n"
1167 << " nobjects: " << pe.delta_nobjects + t.min_nobjects << "\n" 1167 << " nobjects: " << pe.delta_nobjects + t.min_nobjects << "\n"
@@ -1182,7 +1182,7 @@ void @@ -1182,7 +1182,7 @@ void
1182 Lin::dumpHSharedObject() 1182 Lin::dumpHSharedObject()
1183 { 1183 {
1184 auto& info = *cf.log()->getInfo(); 1184 auto& info = *cf.log()->getInfo();
1185 - HSharedObject& t = m->shared_object_hints; 1185 + HSharedObject& t = shared_object_hints_;
1186 info << "first_shared_obj: " << t.first_shared_obj << "\n" 1186 info << "first_shared_obj: " << t.first_shared_obj << "\n"
1187 << "first_shared_offset: " << adjusted_offset(t.first_shared_offset) << "\n" 1187 << "first_shared_offset: " << adjusted_offset(t.first_shared_offset) << "\n"
1188 << "nshared_first_page: " << t.nshared_first_page << "\n" 1188 << "nshared_first_page: " << t.nshared_first_page << "\n"
@@ -1280,10 +1280,10 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data) @@ -1280,10 +1280,10 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data)
1280 m->part7.clear(); 1280 m->part7.clear();
1281 m->part8.clear(); 1281 m->part8.clear();
1282 m->part9.clear(); 1282 m->part9.clear();
1283 - m->c_linp = LinParameters();  
1284 - m->c_page_offset_data = CHPageOffset();  
1285 - m->c_shared_object_data = CHSharedObject();  
1286 - m->c_outline_data = HGeneric(); 1283 + c_linp_ = LinParameters();
  1284 + c_page_offset_data_ = CHPageOffset();
  1285 + c_shared_object_data_ = CHSharedObject();
  1286 + c_outline_data_ = HGeneric();
1287 1287
1288 QPDFObjectHandle root = qpdf.getRoot(); 1288 QPDFObjectHandle root = qpdf.getRoot();
1289 bool outlines_in_first_page = false; 1289 bool outlines_in_first_page = false;
@@ -1417,8 +1417,8 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data) @@ -1417,8 +1417,8 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data)
1417 1417
1418 // npages is the size of the existing pages vector, which has been created by traversing the 1418 // npages is the size of the existing pages vector, which has been created by traversing the
1419 // pages tree, and as such is a reasonable size. 1419 // pages tree, and as such is a reasonable size.
1420 - m->c_linp.npages = npages;  
1421 - m->c_page_offset_data.entries = std::vector<CHPageOffsetEntry>(npages); 1420 + c_linp_.npages = npages;
  1421 + c_page_offset_data_.entries = std::vector<CHPageOffsetEntry>(npages);
1422 1422
1423 // Part 4: open document objects. We don't care about the order. 1423 // Part 4: open document objects. We don't care about the order.
1424 1424
@@ -1443,7 +1443,7 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data) @@ -1443,7 +1443,7 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data)
1443 no_ci_stop_if( 1443 no_ci_stop_if(
1444 !lc_first_page_private.erase(first_page_og), "unable to linearize first page" // 1444 !lc_first_page_private.erase(first_page_og), "unable to linearize first page" //
1445 ); 1445 );
1446 - m->c_linp.first_page_object = uc_pages.at(0).getObjectID(); 1446 + c_linp_.first_page_object = uc_pages.at(0).getObjectID();
1447 m->part6.emplace_back(uc_pages.at(0)); 1447 m->part6.emplace_back(uc_pages.at(0));
1448 1448
1449 // The PDF spec "recommends" an order for the rest of the objects, but we are going to disregard 1449 // The PDF spec "recommends" an order for the rest of the objects, but we are going to disregard
@@ -1467,7 +1467,7 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data) @@ -1467,7 +1467,7 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data)
1467 // nshared_objects should be zero for the first page. pdlin does not appear to obey this, but 1467 // nshared_objects should be zero for the first page. pdlin does not appear to obey this, but
1468 // it fills in garbage values for all the shared object identifiers on the first page. 1468 // it fills in garbage values for all the shared object identifiers on the first page.
1469 1469
1470 - m->c_page_offset_data.entries.at(0).nobjects = toI(m->part6.size()); 1470 + c_page_offset_data_.entries.at(0).nobjects = toI(m->part6.size());
1471 1471
1472 // Part 7: other pages' private objects 1472 // Part 7: other pages' private objects
1473 1473
@@ -1486,7 +1486,7 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data) @@ -1486,7 +1486,7 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data)
1486 // Place all non-shared objects referenced by this page, updating the page object count for 1486 // Place all non-shared objects referenced by this page, updating the page object count for
1487 // the hint table. 1487 // the hint table.
1488 1488
1489 - m->c_page_offset_data.entries.at(i).nobjects = 1; 1489 + c_page_offset_data_.entries.at(i).nobjects = 1;
1490 1490
1491 ObjUser ou(ObjUser::ou_page, i); 1491 ObjUser ou(ObjUser::ou_page, i);
1492 no_ci_stop_if( 1492 no_ci_stop_if(
@@ -1497,7 +1497,7 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data) @@ -1497,7 +1497,7 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data)
1497 for (auto const& og: obj_user_to_objects_[ou]) { 1497 for (auto const& og: obj_user_to_objects_[ou]) {
1498 if (lc_other_page_private.erase(og)) { 1498 if (lc_other_page_private.erase(og)) {
1499 m->part7.emplace_back(qpdf.getObject(og)); 1499 m->part7.emplace_back(qpdf.getObject(og));
1500 - ++m->c_page_offset_data.entries.at(i).nobjects; 1500 + ++c_page_offset_data_.entries.at(i).nobjects;
1501 } 1501 }
1502 } 1502 }
1503 } 1503 }
@@ -1599,11 +1599,11 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data) @@ -1599,11 +1599,11 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data)
1599 // only without regards to generation. 1599 // only without regards to generation.
1600 std::map<int, int> obj_to_index; 1600 std::map<int, int> obj_to_index;
1601 1601
1602 - m->c_shared_object_data.nshared_first_page = toI(m->part6.size());  
1603 - m->c_shared_object_data.nshared_total =  
1604 - m->c_shared_object_data.nshared_first_page + toI(m->part8.size()); 1602 + c_shared_object_data_.nshared_first_page = toI(m->part6.size());
  1603 + c_shared_object_data_.nshared_total =
  1604 + c_shared_object_data_.nshared_first_page + toI(m->part8.size());
1605 1605
1606 - std::vector<CHSharedObjectEntry>& shared = m->c_shared_object_data.entries; 1606 + std::vector<CHSharedObjectEntry>& shared = c_shared_object_data_.entries;
1607 for (auto& oh: m->part6) { 1607 for (auto& oh: m->part6) {
1608 int obj = oh.getObjectID(); 1608 int obj = oh.getObjectID();
1609 obj_to_index[obj] = toI(shared.size()); 1609 obj_to_index[obj] = toI(shared.size());
@@ -1611,7 +1611,7 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data) @@ -1611,7 +1611,7 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data)
1611 } 1611 }
1612 QTC::TC("qpdf", "QPDF lin part 8 empty", m->part8.empty() ? 1 : 0); 1612 QTC::TC("qpdf", "QPDF lin part 8 empty", m->part8.empty() ? 1 : 0);
1613 if (!m->part8.empty()) { 1613 if (!m->part8.empty()) {
1614 - m->c_shared_object_data.first_shared_obj = m->part8.at(0).getObjectID(); 1614 + c_shared_object_data_.first_shared_obj = m->part8.at(0).getObjectID();
1615 for (auto& oh: m->part8) { 1615 for (auto& oh: m->part8) {
1616 int obj = oh.getObjectID(); 1616 int obj = oh.getObjectID();
1617 obj_to_index[obj] = toI(shared.size()); 1617 obj_to_index[obj] = toI(shared.size());
@@ -1620,14 +1620,14 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data) @@ -1620,14 +1620,14 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data)
1620 } 1620 }
1621 no_ci_stop_if( 1621 no_ci_stop_if(
1622 std::cmp_not_equal( 1622 std::cmp_not_equal(
1623 - m->c_shared_object_data.nshared_total, m->c_shared_object_data.entries.size()), 1623 + c_shared_object_data_.nshared_total, c_shared_object_data_.entries.size()),
1624 "shared object hint table has wrong number of entries" // 1624 "shared object hint table has wrong number of entries" //
1625 ); 1625 );
1626 1626
1627 // Now compute the list of shared objects for each page after the first page. 1627 // Now compute the list of shared objects for each page after the first page.
1628 1628
1629 for (size_t i = 1; i < npages; ++i) { 1629 for (size_t i = 1; i < npages; ++i) {
1630 - CHPageOffsetEntry& pe = m->c_page_offset_data.entries.at(i); 1630 + CHPageOffsetEntry& pe = c_page_offset_data_.entries.at(i);
1631 ObjUser ou(ObjUser::ou_page, i); 1631 ObjUser ou(ObjUser::ou_page, i);
1632 no_ci_stop_if( 1632 no_ci_stop_if(
1633 !obj_user_to_objects_.contains(ou), 1633 !obj_user_to_objects_.contains(ou),
@@ -1668,15 +1668,15 @@ Lin::pushOutlinesToPart( @@ -1668,15 +1668,15 @@ Lin::pushOutlinesToPart(
1668 // Make sure outlines is in lc_outlines in case the file is damaged. in which case it may be 1668 // Make sure outlines is in lc_outlines in case the file is damaged. in which case it may be
1669 // included in an earlier part. 1669 // included in an earlier part.
1670 part.emplace_back(outlines); 1670 part.emplace_back(outlines);
1671 - m->c_outline_data.first_object = outlines_og.getObj();  
1672 - m->c_outline_data.nobjects = 1; 1671 + c_outline_data_.first_object = outlines_og.getObj();
  1672 + c_outline_data_.nobjects = 1;
1673 } 1673 }
1674 for (auto const& og: lc_outlines) { 1674 for (auto const& og: lc_outlines) {
1675 - if (!m->c_outline_data.first_object) {  
1676 - m->c_outline_data.first_object = og.getObj(); 1675 + if (!c_outline_data_.first_object) {
  1676 + c_outline_data_.first_object = og.getObj();
1677 } 1677 }
1678 part.emplace_back(qpdf.getObject(og)); 1678 part.emplace_back(qpdf.getObject(og));
1679 - ++m->c_outline_data.nobjects; 1679 + ++c_outline_data_.nobjects;
1680 } 1680 }
1681 } 1681 }
1682 1682
@@ -1734,7 +1734,7 @@ Lin::calculateHPageOffset(QPDFWriter::NewObjTable const&amp; new_obj, QPDFWriter::Ob @@ -1734,7 +1734,7 @@ Lin::calculateHPageOffset(QPDFWriter::NewObjTable const&amp; new_obj, QPDFWriter::Ob
1734 1734
1735 auto const& all_pages = pages.all(); 1735 auto const& all_pages = pages.all();
1736 size_t npages = all_pages.size(); 1736 size_t npages = all_pages.size();
1737 - CHPageOffset& cph = m->c_page_offset_data; 1737 + CHPageOffset& cph = c_page_offset_data_;
1738 std::vector<CHPageOffsetEntry>& cphe = cph.entries; 1738 std::vector<CHPageOffsetEntry>& cphe = cph.entries;
1739 1739
1740 // Calculate minimum and maximum values for number of objects per page and page length. 1740 // Calculate minimum and maximum values for number of objects per page and page length.
@@ -1745,7 +1745,7 @@ Lin::calculateHPageOffset(QPDFWriter::NewObjTable const&amp; new_obj, QPDFWriter::Ob @@ -1745,7 +1745,7 @@ Lin::calculateHPageOffset(QPDFWriter::NewObjTable const&amp; new_obj, QPDFWriter::Ob
1745 int max_length = 0; 1745 int max_length = 0;
1746 int max_shared = 0; 1746 int max_shared = 0;
1747 1747
1748 - HPageOffset& ph = m->page_offset_hints; 1748 + HPageOffset& ph = page_offset_hints_;
1749 std::vector<HPageOffsetEntry>& phe = ph.entries; 1749 std::vector<HPageOffsetEntry>& phe = ph.entries;
1750 // npages is the size of the existing pages array. 1750 // npages is the size of the existing pages array.
1751 phe = std::vector<HPageOffsetEntry>(npages); 1751 phe = std::vector<HPageOffsetEntry>(npages);
@@ -1780,7 +1780,7 @@ Lin::calculateHPageOffset(QPDFWriter::NewObjTable const&amp; new_obj, QPDFWriter::Ob @@ -1780,7 +1780,7 @@ Lin::calculateHPageOffset(QPDFWriter::NewObjTable const&amp; new_obj, QPDFWriter::Ob
1780 ph.min_page_length = min_length; 1780 ph.min_page_length = min_length;
1781 ph.nbits_delta_page_length = nbits(max_length - min_length); 1781 ph.nbits_delta_page_length = nbits(max_length - min_length);
1782 ph.nbits_nshared_objects = nbits(max_shared); 1782 ph.nbits_nshared_objects = nbits(max_shared);
1783 - ph.nbits_shared_identifier = nbits(m->c_shared_object_data.nshared_total); 1783 + ph.nbits_shared_identifier = nbits(c_shared_object_data_.nshared_total);
1784 ph.shared_denominator = 4; // doesn't matter 1784 ph.shared_denominator = 4; // doesn't matter
1785 1785
1786 // It isn't clear how to compute content offset and content length. Since we are not 1786 // It isn't clear how to compute content offset and content length. Since we are not
@@ -1812,9 +1812,9 @@ Lin::calculateHPageOffset(QPDFWriter::NewObjTable const&amp; new_obj, QPDFWriter::Ob @@ -1812,9 +1812,9 @@ Lin::calculateHPageOffset(QPDFWriter::NewObjTable const&amp; new_obj, QPDFWriter::Ob
1812 void 1812 void
1813 Lin::calculateHSharedObject(QPDFWriter::NewObjTable const& new_obj, QPDFWriter::ObjTable const& obj) 1813 Lin::calculateHSharedObject(QPDFWriter::NewObjTable const& new_obj, QPDFWriter::ObjTable const& obj)
1814 { 1814 {
1815 - CHSharedObject& cso = m->c_shared_object_data; 1815 + CHSharedObject& cso = c_shared_object_data_;
1816 std::vector<CHSharedObjectEntry>& csoe = cso.entries; 1816 std::vector<CHSharedObjectEntry>& csoe = cso.entries;
1817 - HSharedObject& so = m->shared_object_hints; 1817 + HSharedObject& so = shared_object_hints_;
1818 std::vector<HSharedObjectEntry>& soe = so.entries; 1818 std::vector<HSharedObjectEntry>& soe = so.entries;
1819 soe.clear(); 1819 soe.clear();
1820 1820
@@ -1857,13 +1857,13 @@ Lin::calculateHSharedObject(QPDFWriter::NewObjTable const&amp; new_obj, QPDFWriter:: @@ -1857,13 +1857,13 @@ Lin::calculateHSharedObject(QPDFWriter::NewObjTable const&amp; new_obj, QPDFWriter::
1857 void 1857 void
1858 Lin::calculateHOutline(QPDFWriter::NewObjTable const& new_obj, QPDFWriter::ObjTable const& obj) 1858 Lin::calculateHOutline(QPDFWriter::NewObjTable const& new_obj, QPDFWriter::ObjTable const& obj)
1859 { 1859 {
1860 - HGeneric& cho = m->c_outline_data; 1860 + HGeneric& cho = c_outline_data_;
1861 1861
1862 if (cho.nobjects == 0) { 1862 if (cho.nobjects == 0) {
1863 return; 1863 return;
1864 } 1864 }
1865 1865
1866 - HGeneric& ho = m->outline_hints; 1866 + HGeneric& ho = outline_hints_;
1867 1867
1868 ho.first_object = obj[cho.first_object].renumber; 1868 ho.first_object = obj[cho.first_object].renumber;
1869 ho.first_object_offset = new_obj[ho.first_object].xref.getOffset(); 1869 ho.first_object_offset = new_obj[ho.first_object].xref.getOffset();
@@ -1908,7 +1908,7 @@ write_vector_vector( @@ -1908,7 +1908,7 @@ write_vector_vector(
1908 void 1908 void
1909 Lin::writeHPageOffset(BitWriter& w) 1909 Lin::writeHPageOffset(BitWriter& w)
1910 { 1910 {
1911 - HPageOffset& t = m->page_offset_hints; 1911 + HPageOffset& t = page_offset_hints_;
1912 1912
1913 w.writeBitsInt(t.min_nobjects, 32); // 1 1913 w.writeBitsInt(t.min_nobjects, 32); // 1
1914 w.writeBits(toULL(t.first_page_offset), 32); // 2 1914 w.writeBits(toULL(t.first_page_offset), 32); // 2
@@ -1955,7 +1955,7 @@ Lin::writeHPageOffset(BitWriter&amp; w) @@ -1955,7 +1955,7 @@ Lin::writeHPageOffset(BitWriter&amp; w)
1955 void 1955 void
1956 Lin::writeHSharedObject(BitWriter& w) 1956 Lin::writeHSharedObject(BitWriter& w)
1957 { 1957 {
1958 - HSharedObject& t = m->shared_object_hints; 1958 + HSharedObject& t = shared_object_hints_;
1959 1959
1960 w.writeBitsInt(t.first_shared_obj, 32); // 1 1960 w.writeBitsInt(t.first_shared_obj, 32); // 1
1961 w.writeBits(toULL(t.first_shared_offset), 32); // 2 1961 w.writeBits(toULL(t.first_shared_offset), 32); // 2
@@ -2017,9 +2017,9 @@ Lin::generateHintStream( @@ -2017,9 +2017,9 @@ Lin::generateHintStream(
2017 S = toI(c.getCount()); 2017 S = toI(c.getCount());
2018 writeHSharedObject(w); 2018 writeHSharedObject(w);
2019 O = 0; 2019 O = 0;
2020 - if (m->outline_hints.nobjects > 0) { 2020 + if (outline_hints_.nobjects > 0) {
2021 O = toI(c.getCount()); 2021 O = toI(c.getCount());
2022 - writeHGeneric(w, m->outline_hints); 2022 + writeHGeneric(w, outline_hints_);
2023 } 2023 }
2024 if (compressed) { 2024 if (compressed) {
2025 hint_buffer = pl::pipe<Pl_Flate>(hint_buffer, Pl_Flate::a_deflate); 2025 hint_buffer = pl::pipe<Pl_Flate>(hint_buffer, Pl_Flate::a_deflate);
libqpdf/qpdf/QPDF_private.hh
@@ -236,134 +236,8 @@ class QPDF::StringDecrypter final: public QPDFObjectHandle::StringDecrypter @@ -236,134 +236,8 @@ class QPDF::StringDecrypter final: public QPDFObjectHandle::StringDecrypter
236 QPDF* qpdf; 236 QPDF* qpdf;
237 QPDFObjGen og; 237 QPDFObjGen og;
238 }; 238 };
239 -  
240 -// PDF 1.4: Table F.4  
241 -struct QPDF::HPageOffsetEntry  
242 -{  
243 - int delta_nobjects{0}; // 1  
244 - qpdf_offset_t delta_page_length{0}; // 2  
245 - // vectors' sizes = nshared_objects  
246 - int nshared_objects{0}; // 3  
247 - std::vector<int> shared_identifiers; // 4  
248 - std::vector<int> shared_numerators; // 5  
249 - qpdf_offset_t delta_content_offset{0}; // 6  
250 - qpdf_offset_t delta_content_length{0}; // 7  
251 -};  
252 -  
253 -// PDF 1.4: Table F.3  
254 -struct QPDF::HPageOffset  
255 -{  
256 - int min_nobjects{0}; // 1  
257 - qpdf_offset_t first_page_offset{0}; // 2  
258 - int nbits_delta_nobjects{0}; // 3  
259 - int min_page_length{0}; // 4  
260 - int nbits_delta_page_length{0}; // 5  
261 - int min_content_offset{0}; // 6  
262 - int nbits_delta_content_offset{0}; // 7  
263 - int min_content_length{0}; // 8  
264 - int nbits_delta_content_length{0}; // 9  
265 - int nbits_nshared_objects{0}; // 10  
266 - int nbits_shared_identifier{0}; // 11  
267 - int nbits_shared_numerator{0}; // 12  
268 - int shared_denominator{0}; // 13  
269 - // vector size is npages  
270 - std::vector<HPageOffsetEntry> entries;  
271 -};  
272 -  
273 -// PDF 1.4: Table F.6  
274 -struct QPDF::HSharedObjectEntry  
275 -{  
276 - // Item 3 is a 128-bit signature (unsupported by Acrobat)  
277 - int delta_group_length{0}; // 1  
278 - int signature_present{0}; // 2 -- always 0  
279 - int nobjects_minus_one{0}; // 4 -- always 0  
280 -};  
281 -  
282 -// PDF 1.4: Table F.5  
283 -struct QPDF::HSharedObject  
284 -{  
285 - int first_shared_obj{0}; // 1  
286 - qpdf_offset_t first_shared_offset{0}; // 2  
287 - int nshared_first_page{0}; // 3  
288 - int nshared_total{0}; // 4  
289 - int nbits_nobjects{0}; // 5  
290 - int min_group_length{0}; // 6  
291 - int nbits_delta_group_length{0}; // 7  
292 - // vector size is nshared_total  
293 - std::vector<HSharedObjectEntry> entries;  
294 -};  
295 -  
296 -// PDF 1.4: Table F.9  
297 -struct QPDF::HGeneric  
298 -{  
299 - int first_object{0}; // 1  
300 - qpdf_offset_t first_object_offset{0}; // 2  
301 - int nobjects{0}; // 3  
302 - int group_length{0}; // 4  
303 -};  
304 -  
305 // Other linearization data structures 239 // Other linearization data structures
306 240
307 -// Initialized from Linearization Parameter dictionary  
308 -struct QPDF::LinParameters  
309 -{  
310 - qpdf_offset_t file_size{0}; // /L  
311 - int first_page_object{0}; // /O  
312 - qpdf_offset_t first_page_end{0}; // /E  
313 - size_t npages{0}; // /N  
314 - qpdf_offset_t xref_zero_offset{0}; // /T  
315 - int first_page{0}; // /P  
316 - qpdf_offset_t H_offset{0}; // offset of primary hint stream  
317 - qpdf_offset_t H_length{0}; // length of primary hint stream  
318 -};  
319 -  
320 -// Computed hint table value data structures. These tables contain the computed values on which  
321 -// the hint table values are based. They exclude things like number of bits and store actual  
322 -// values instead of mins and deltas. File offsets are also absolute rather than being offset  
323 -// by the size of the primary hint table. We populate the hint table structures from these  
324 -// during writing and compare the hint table values with these during validation. We ignore  
325 -// some values for various reasons described in the code. Those values are omitted from these  
326 -// structures. Note also that object numbers are object numbers from the input file, not the  
327 -// output file.  
328 -  
329 -// Naming convention: CHSomething is analogous to HSomething above. "CH" is computed hint.  
330 -  
331 -struct QPDF::CHPageOffsetEntry  
332 -{  
333 - int nobjects{0};  
334 - int nshared_objects{0};  
335 - // vectors' sizes = nshared_objects  
336 - std::vector<int> shared_identifiers;  
337 -};  
338 -  
339 -struct QPDF::CHPageOffset  
340 -{  
341 - // vector size is npages  
342 - std::vector<CHPageOffsetEntry> entries;  
343 -};  
344 -  
345 -struct QPDF::CHSharedObjectEntry  
346 -{  
347 - CHSharedObjectEntry(int object) :  
348 - object(object)  
349 - {  
350 - }  
351 -  
352 - int object;  
353 -};  
354 -  
355 -// PDF 1.4: Table F.5  
356 -struct QPDF::CHSharedObject  
357 -{  
358 - int first_shared_obj{0};  
359 - int nshared_first_page{0};  
360 - int nshared_total{0};  
361 - // vector size is nshared_total  
362 - std::vector<CHSharedObjectEntry> entries;  
363 -};  
364 -  
365 -// No need for CHGeneric -- HGeneric is fine as is.  
366 -  
367 class QPDF::PatternFinder final: public InputSource::Finder 241 class QPDF::PatternFinder final: public InputSource::Finder
368 { 242 {
369 public: 243 public:
@@ -736,13 +610,140 @@ class QPDF::Doc::Linearization: Common @@ -736,13 +610,140 @@ class QPDF::Doc::Linearization: Common
736 610
737 struct UpdateObjectMapsFrame 611 struct UpdateObjectMapsFrame
738 { 612 {
739 - UpdateObjectMapsFrame(ObjUser const& ou, QPDFObjectHandle oh, bool top) ; 613 + UpdateObjectMapsFrame(ObjUser const& ou, QPDFObjectHandle oh, bool top);
740 614
741 ObjUser const& ou; 615 ObjUser const& ou;
742 QPDFObjectHandle oh; 616 QPDFObjectHandle oh;
743 bool top; 617 bool top;
744 }; 618 };
745 619
  620 + // PDF 1.4: Table F.4
  621 + struct HPageOffsetEntry
  622 + {
  623 + int delta_nobjects{0}; // 1
  624 + qpdf_offset_t delta_page_length{0}; // 2
  625 + // vectors' sizes = nshared_objects
  626 + int nshared_objects{0}; // 3
  627 + std::vector<int> shared_identifiers; // 4
  628 + std::vector<int> shared_numerators; // 5
  629 + qpdf_offset_t delta_content_offset{0}; // 6
  630 + qpdf_offset_t delta_content_length{0}; // 7
  631 + };
  632 +
  633 + // PDF 1.4: Table F.3
  634 + struct HPageOffset
  635 + {
  636 + int min_nobjects{0}; // 1
  637 + qpdf_offset_t first_page_offset{0}; // 2
  638 + int nbits_delta_nobjects{0}; // 3
  639 + int min_page_length{0}; // 4
  640 + int nbits_delta_page_length{0}; // 5
  641 + int min_content_offset{0}; // 6
  642 + int nbits_delta_content_offset{0}; // 7
  643 + int min_content_length{0}; // 8
  644 + int nbits_delta_content_length{0}; // 9
  645 + int nbits_nshared_objects{0}; // 10
  646 + int nbits_shared_identifier{0}; // 11
  647 + int nbits_shared_numerator{0}; // 12
  648 + int shared_denominator{0}; // 13
  649 + // vector size is npages
  650 + std::vector<HPageOffsetEntry> entries;
  651 + };
  652 +
  653 + // PDF 1.4: Table F.6
  654 + struct HSharedObjectEntry
  655 + {
  656 + // Item 3 is a 128-bit signature (unsupported by Acrobat)
  657 + int delta_group_length{0}; // 1
  658 + int signature_present{0}; // 2 -- always 0
  659 + int nobjects_minus_one{0}; // 4 -- always 0
  660 + };
  661 +
  662 + // PDF 1.4: Table F.5
  663 + struct HSharedObject
  664 + {
  665 + int first_shared_obj{0}; // 1
  666 + qpdf_offset_t first_shared_offset{0}; // 2
  667 + int nshared_first_page{0}; // 3
  668 + int nshared_total{0}; // 4
  669 + int nbits_nobjects{0}; // 5
  670 + int min_group_length{0}; // 6
  671 + int nbits_delta_group_length{0}; // 7
  672 + // vector size is nshared_total
  673 + std::vector<HSharedObjectEntry> entries;
  674 + };
  675 +
  676 + // PDF 1.4: Table F.9
  677 + struct HGeneric
  678 + {
  679 + int first_object{0}; // 1
  680 + qpdf_offset_t first_object_offset{0}; // 2
  681 + int nobjects{0}; // 3
  682 + int group_length{0}; // 4
  683 + };
  684 +
  685 + // Other linearization data structures
  686 +
  687 + // Initialized from Linearization Parameter dictionary
  688 + struct LinParameters
  689 + {
  690 + qpdf_offset_t file_size{0}; // /L
  691 + int first_page_object{0}; // /O
  692 + qpdf_offset_t first_page_end{0}; // /E
  693 + size_t npages{0}; // /N
  694 + qpdf_offset_t xref_zero_offset{0}; // /T
  695 + int first_page{0}; // /P
  696 + qpdf_offset_t H_offset{0}; // offset of primary hint stream
  697 + qpdf_offset_t H_length{0}; // length of primary hint stream
  698 + };
  699 +
  700 + // Computed hint table value data structures. These tables contain the computed values on which
  701 + // the hint table values are based. They exclude things like number of bits and store actual
  702 + // values instead of mins and deltas. File offsets are also absolute rather than being offset
  703 + // by the size of the primary hint table. We populate the hint table structures from these
  704 + // during writing and compare the hint table values with these during validation. We ignore
  705 + // some values for various reasons described in the code. Those values are omitted from these
  706 + // structures. Note also that object numbers are object numbers from the input file, not the
  707 + // output file.
  708 +
  709 + // Naming convention: CHSomething is analogous to HSomething above. "CH" is computed hint.
  710 +
  711 + struct CHPageOffsetEntry
  712 + {
  713 + int nobjects{0};
  714 + int nshared_objects{0};
  715 + // vectors' sizes = nshared_objects
  716 + std::vector<int> shared_identifiers;
  717 + };
  718 +
  719 + struct CHPageOffset
  720 + {
  721 + // vector size is npages
  722 + std::vector<CHPageOffsetEntry> entries;
  723 + };
  724 +
  725 + struct CHSharedObjectEntry
  726 + {
  727 + CHSharedObjectEntry(int object) :
  728 + object(object)
  729 + {
  730 + }
  731 +
  732 + int object;
  733 + };
  734 +
  735 + // PDF 1.4: Table F.5
  736 + struct CHSharedObject
  737 + {
  738 + int first_shared_obj{0};
  739 + int nshared_first_page{0};
  740 + int nshared_total{0};
  741 + // vector size is nshared_total
  742 + std::vector<CHSharedObjectEntry> entries;
  743 + };
  744 +
  745 + // No need for CHGeneric -- HGeneric is fine as is.
  746 +
746 // methods to support linearization checking -- implemented in QPDF_linearization.cc 747 // methods to support linearization checking -- implemented in QPDF_linearization.cc
747 748
748 void readLinearizationData(); 749 void readLinearizationData();
@@ -801,6 +802,23 @@ class QPDF::Doc::Linearization: Common @@ -801,6 +802,23 @@ class QPDF::Doc::Linearization: Common
801 // Optimization data 802 // Optimization data
802 std::map<ObjUser, std::set<QPDFObjGen>> obj_user_to_objects_; 803 std::map<ObjUser, std::set<QPDFObjGen>> obj_user_to_objects_;
803 std::map<QPDFObjGen, std::set<ObjUser>> object_to_obj_users_; 804 std::map<QPDFObjGen, std::set<ObjUser>> object_to_obj_users_;
  805 +
  806 + // Linearization data
  807 +
  808 + // Linearization parameter dictionary and hint table data: may be read from file or computed
  809 + // prior to writing a linearized file
  810 + QPDFObjectHandle lindict_;
  811 + LinParameters linp_;
  812 + HPageOffset page_offset_hints_;
  813 + HSharedObject shared_object_hints_;
  814 + HGeneric outline_hints_;
  815 +
  816 + // Computed linearization data: used to populate above tables during writing and to compare
  817 + // with them during validation. c_ means computed.
  818 + LinParameters c_linp_;
  819 + CHPageOffset c_page_offset_data_;
  820 + CHSharedObject c_shared_object_data_;
  821 + HGeneric c_outline_data_;
804 }; 822 };
805 823
806 class QPDF::Doc::Objects: Common 824 class QPDF::Doc::Objects: Common
@@ -1151,21 +1169,6 @@ class QPDF::Members: Doc @@ -1151,21 +1169,6 @@ class QPDF::Members: Doc
1151 bool uncompressed_after_compressed{false}; 1169 bool uncompressed_after_compressed{false};
1152 bool linearization_warnings{false}; // set by linearizationWarning, used by checkLinearization 1170 bool linearization_warnings{false}; // set by linearizationWarning, used by checkLinearization
1153 1171
1154 - // Linearization parameter dictionary and hint table data: may be read from file or computed  
1155 - // prior to writing a linearized file  
1156 - QPDFObjectHandle lindict;  
1157 - LinParameters linp;  
1158 - HPageOffset page_offset_hints;  
1159 - HSharedObject shared_object_hints;  
1160 - HGeneric outline_hints;  
1161 -  
1162 - // Computed linearization data: used to populate above tables during writing and to compare  
1163 - // with them during validation. c_ means computed.  
1164 - LinParameters c_linp;  
1165 - CHPageOffset c_page_offset_data;  
1166 - CHSharedObject c_shared_object_data;  
1167 - HGeneric c_outline_data;  
1168 -  
1169 // Object ordering data for linearized files: initialized by calculateLinearizationData(). 1172 // Object ordering data for linearized files: initialized by calculateLinearizationData().
1170 // Part numbers refer to the PDF 1.4 specification. 1173 // Part numbers refer to the PDF 1.4 specification.
1171 std::vector<QPDFObjectHandle> part4; 1174 std::vector<QPDFObjectHandle> part4;