Commit ff09d99466d46d8e42aaf9797844c9007cc76746

Authored by m-holger
1 parent ba1ded84

Refactor `QPDFWriter`: move multiple write-related methods to `QPDFWriter::Membe…

…rs`, update encryption and stream handling logic, and remove obsolete test coverage entries.
include/qpdf/QPDFWriter.hh
@@ -458,32 +458,6 @@ class QPDFWriter @@ -458,32 +458,6 @@ class QPDFWriter
458 458
459 enum trailer_e { t_normal, t_lin_first, t_lin_second }; 459 enum trailer_e { t_normal, t_lin_first, t_lin_second };
460 460
461 - unsigned int bytesNeeded(long long n);  
462 - void writeBinary(unsigned long long val, unsigned int bytes);  
463 - QPDFWriter& write(std::string_view str);  
464 - QPDFWriter& write(size_t count, char c);  
465 - QPDFWriter& write(std::integral auto val);  
466 - QPDFWriter& write_name(std::string const& str);  
467 - QPDFWriter& write_string(std::string const& str, bool force_binary = false);  
468 - QPDFWriter& write_encrypted(std::string_view str);  
469 -  
470 - template <typename... Args>  
471 - QPDFWriter& write_qdf(Args&&... args);  
472 - template <typename... Args>  
473 - QPDFWriter& write_no_qdf(Args&&... args);  
474 - void writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offsets, int first_obj);  
475 - void writeObjectStream(QPDFObjectHandle object);  
476 - void writeObject(QPDFObjectHandle object, int object_stream_index = -1);  
477 - void writeTrailer(  
478 - trailer_e which, int size, bool xref_stream, qpdf_offset_t prev, int linearization_pass);  
479 - void unparseObject(  
480 - QPDFObjectHandle object,  
481 - size_t level,  
482 - int flags,  
483 - // for stream dictionaries  
484 - size_t stream_length = 0,  
485 - bool compress = false);  
486 - void unparseChild(QPDFObjectHandle const& child, size_t level, int flags);  
487 void interpretR3EncryptionParameters( 461 void interpretR3EncryptionParameters(
488 bool allow_accessibility, 462 bool allow_accessibility,
489 bool allow_extract, 463 bool allow_extract,
@@ -496,50 +470,7 @@ class QPDFWriter @@ -496,50 +470,7 @@ class QPDFWriter
496 void setEncryptionParameters(char const* user_password, char const* owner_password); 470 void setEncryptionParameters(char const* user_password, char const* owner_password);
497 void setEncryptionMinimumVersion(); 471 void setEncryptionMinimumVersion();
498 void setDataKey(int objid); 472 void setDataKey(int objid);
499 - int openObject(int objid = 0);  
500 - void closeObject(int objid);  
501 void indicateProgress(bool decrement, bool finished); 473 void indicateProgress(bool decrement, bool finished);
502 - void writeStandard();  
503 - void writeLinearized();  
504 - void writeEncryptionDictionary();  
505 - void writeHeader();  
506 - void writeHintStream(int hint_id);  
507 - qpdf_offset_t writeXRefTable(trailer_e which, int first, int last, int size);  
508 - qpdf_offset_t writeXRefTable(  
509 - trailer_e which,  
510 - int first,  
511 - int last,  
512 - int size,  
513 - // for linearization  
514 - qpdf_offset_t prev,  
515 - bool suppress_offsets,  
516 - int hint_id,  
517 - qpdf_offset_t hint_offset,  
518 - qpdf_offset_t hint_length,  
519 - int linearization_pass);  
520 - qpdf_offset_t writeXRefStream(  
521 - int objid,  
522 - int max_id,  
523 - qpdf_offset_t max_offset,  
524 - trailer_e which,  
525 - int first,  
526 - int last,  
527 - int size);  
528 - qpdf_offset_t writeXRefStream(  
529 - int objid,  
530 - int max_id,  
531 - qpdf_offset_t max_offset,  
532 - trailer_e which,  
533 - int first,  
534 - int last,  
535 - int size,  
536 - // for linearization  
537 - qpdf_offset_t prev,  
538 - int hint_id,  
539 - qpdf_offset_t hint_offset,  
540 - qpdf_offset_t hint_length,  
541 - bool skip_compression,  
542 - int linearization_pass);  
543 size_t calculateXrefStreamPadding(qpdf_offset_t xref_bytes); 474 size_t calculateXrefStreamPadding(qpdf_offset_t xref_bytes);
544 475
545 // When filtering subsections, push additional pipelines to the stack. When ready to switch, 476 // When filtering subsections, push additional pipelines to the stack. When ready to switch,
libqpdf/QPDFWriter.cc
@@ -310,6 +310,75 @@ class QPDFWriter::Members @@ -310,6 +310,75 @@ class QPDFWriter::Members
310 bool& compress_stream, 310 bool& compress_stream,
311 bool& is_metadata, 311 bool& is_metadata,
312 std::string* stream_data); 312 std::string* stream_data);
  313 + unsigned int bytesNeeded(long long n);
  314 + void writeBinary(unsigned long long val, unsigned int bytes);
  315 + Members& write(std::string_view str);
  316 + Members& write(size_t count, char c);
  317 + Members& write(std::integral auto val);
  318 + Members& write_name(std::string const& str);
  319 + Members& write_string(std::string const& str, bool force_binary = false);
  320 + Members& write_encrypted(std::string_view str);
  321 +
  322 + template <typename... Args>
  323 + Members& write_qdf(Args&&... args);
  324 + template <typename... Args>
  325 + Members& write_no_qdf(Args&&... args);
  326 + void writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offsets, int first_obj);
  327 + void writeObjectStream(QPDFObjectHandle object);
  328 + void writeObject(QPDFObjectHandle object, int object_stream_index = -1);
  329 + void writeTrailer(
  330 + trailer_e which, int size, bool xref_stream, qpdf_offset_t prev, int linearization_pass);
  331 + void unparseObject(
  332 + QPDFObjectHandle object,
  333 + size_t level,
  334 + int flags,
  335 + // for stream dictionaries
  336 + size_t stream_length = 0,
  337 + bool compress = false);
  338 + void unparseChild(QPDFObjectHandle const& child, size_t level, int flags);
  339 + int openObject(int objid = 0);
  340 + void closeObject(int objid);
  341 + void writeStandard();
  342 + void writeLinearized();
  343 + void writeEncryptionDictionary();
  344 + void writeHeader();
  345 + void writeHintStream(int hint_id);
  346 + qpdf_offset_t writeXRefTable(trailer_e which, int first, int last, int size);
  347 + qpdf_offset_t writeXRefTable(
  348 + trailer_e which,
  349 + int first,
  350 + int last,
  351 + int size,
  352 + // for linearization
  353 + qpdf_offset_t prev,
  354 + bool suppress_offsets,
  355 + int hint_id,
  356 + qpdf_offset_t hint_offset,
  357 + qpdf_offset_t hint_length,
  358 + int linearization_pass);
  359 + qpdf_offset_t writeXRefStream(
  360 + int objid,
  361 + int max_id,
  362 + qpdf_offset_t max_offset,
  363 + trailer_e which,
  364 + int first,
  365 + int last,
  366 + int size);
  367 + qpdf_offset_t writeXRefStream(
  368 + int objid,
  369 + int max_id,
  370 + qpdf_offset_t max_offset,
  371 + trailer_e which,
  372 + int first,
  373 + int last,
  374 + int size,
  375 + // for linearization
  376 + qpdf_offset_t prev,
  377 + int hint_id,
  378 + qpdf_offset_t hint_offset,
  379 + qpdf_offset_t hint_length,
  380 + bool skip_compression,
  381 + int linearization_pass);
313 382
314 private: 383 private:
315 QPDFWriter& w; 384 QPDFWriter& w;
@@ -1047,7 +1116,7 @@ QPDFWriter::setDataKey(int objid) @@ -1047,7 +1116,7 @@ QPDFWriter::setDataKey(int objid)
1047 } 1116 }
1048 1117
1049 unsigned int 1118 unsigned int
1050 -QPDFWriter::bytesNeeded(long long n) 1119 +QPDFWriter::Members::bytesNeeded(long long n)
1051 { 1120 {
1052 unsigned int bytes = 0; 1121 unsigned int bytes = 0;
1053 while (n) { 1122 while (n) {
@@ -1058,7 +1127,7 @@ QPDFWriter::bytesNeeded(long long n) @@ -1058,7 +1127,7 @@ QPDFWriter::bytesNeeded(long long n)
1058 } 1127 }
1059 1128
1060 void 1129 void
1061 -QPDFWriter::writeBinary(unsigned long long val, unsigned int bytes) 1130 +QPDFWriter::Members::writeBinary(unsigned long long val, unsigned int bytes)
1062 { 1131 {
1063 if (bytes > sizeof(unsigned long long)) { 1132 if (bytes > sizeof(unsigned long long)) {
1064 throw std::logic_error("QPDFWriter::writeBinary called with too many bytes"); 1133 throw std::logic_error("QPDFWriter::writeBinary called with too many bytes");
@@ -1068,60 +1137,60 @@ QPDFWriter::writeBinary(unsigned long long val, unsigned int bytes) @@ -1068,60 +1137,60 @@ QPDFWriter::writeBinary(unsigned long long val, unsigned int bytes)
1068 data[bytes - i - 1] = static_cast<unsigned char>(val & 0xff); 1137 data[bytes - i - 1] = static_cast<unsigned char>(val & 0xff);
1069 val >>= 8; 1138 val >>= 8;
1070 } 1139 }
1071 - m->pipeline->write(data, bytes); 1140 + pipeline->write(data, bytes);
1072 } 1141 }
1073 1142
1074 -QPDFWriter&  
1075 -QPDFWriter::write(std::string_view str) 1143 +QPDFWriter::Members&
  1144 +QPDFWriter::Members::write(std::string_view str)
1076 { 1145 {
1077 - m->pipeline->write(str); 1146 + pipeline->write(str);
1078 return *this; 1147 return *this;
1079 } 1148 }
1080 1149
1081 -QPDFWriter&  
1082 -QPDFWriter::write(std::integral auto val) 1150 +QPDFWriter::Members&
  1151 +QPDFWriter::Members::write(std::integral auto val)
1083 { 1152 {
1084 - m->pipeline->write(std::to_string(val)); 1153 + pipeline->write(std::to_string(val));
1085 return *this; 1154 return *this;
1086 } 1155 }
1087 1156
1088 -QPDFWriter&  
1089 -QPDFWriter::write(size_t count, char c) 1157 +QPDFWriter::Members&
  1158 +QPDFWriter::Members::write(size_t count, char c)
1090 { 1159 {
1091 - m->pipeline->write(count, c); 1160 + pipeline->write(count, c);
1092 return *this; 1161 return *this;
1093 } 1162 }
1094 1163
1095 -QPDFWriter&  
1096 -QPDFWriter::write_name(std::string const& str) 1164 +QPDFWriter::Members&
  1165 +QPDFWriter::Members::write_name(std::string const& str)
1097 { 1166 {
1098 - m->pipeline->write(Name::normalize(str)); 1167 + pipeline->write(Name::normalize(str));
1099 return *this; 1168 return *this;
1100 } 1169 }
1101 1170
1102 -QPDFWriter&  
1103 -QPDFWriter::write_string(std::string const& str, bool force_binary) 1171 +QPDFWriter::Members&
  1172 +QPDFWriter::Members::write_string(std::string const& str, bool force_binary)
1104 { 1173 {
1105 - m->pipeline->write(QPDF_String(str).unparse(force_binary)); 1174 + pipeline->write(QPDF_String(str).unparse(force_binary));
1106 return *this; 1175 return *this;
1107 } 1176 }
1108 1177
1109 template <typename... Args> 1178 template <typename... Args>
1110 -QPDFWriter&  
1111 -QPDFWriter::write_qdf(Args&&... args) 1179 +QPDFWriter::Members&
  1180 +QPDFWriter::Members::write_qdf(Args&&... args)
1112 { 1181 {
1113 - if (m->qdf_mode) {  
1114 - m->pipeline->write(std::forward<Args>(args)...); 1182 + if (qdf_mode) {
  1183 + pipeline->write(std::forward<Args>(args)...);
1115 } 1184 }
1116 return *this; 1185 return *this;
1117 } 1186 }
1118 1187
1119 template <typename... Args> 1188 template <typename... Args>
1120 -QPDFWriter&  
1121 -QPDFWriter::write_no_qdf(Args&&... args) 1189 +QPDFWriter::Members&
  1190 +QPDFWriter::Members::write_no_qdf(Args&&... args)
1122 { 1191 {
1123 - if (!m->qdf_mode) {  
1124 - m->pipeline->write(std::forward<Args>(args)...); 1192 + if (!qdf_mode) {
  1193 + pipeline->write(std::forward<Args>(args)...);
1125 } 1194 }
1126 return *this; 1195 return *this;
1127 } 1196 }
@@ -1136,15 +1205,15 @@ QPDFWriter::adjustAESStreamLength(size_t&amp; length) @@ -1136,15 +1205,15 @@ QPDFWriter::adjustAESStreamLength(size_t&amp; length)
1136 } 1205 }
1137 } 1206 }
1138 1207
1139 -QPDFWriter&  
1140 -QPDFWriter::write_encrypted(std::string_view str) 1208 +QPDFWriter::Members&
  1209 +QPDFWriter::Members::write_encrypted(std::string_view str)
1141 { 1210 {
1142 - if (!(m->encryption && !m->cur_data_key.empty())) { 1211 + if (!(encryption && !cur_data_key.empty())) {
1143 write(str); 1212 write(str);
1144 - } else if (m->encrypt_use_aes) {  
1145 - write(pl::pipe<Pl_AES_PDF>(str, true, m->cur_data_key)); 1213 + } else if (encrypt_use_aes) {
  1214 + write(pl::pipe<Pl_AES_PDF>(str, true, cur_data_key));
1146 } else { 1215 } else {
1147 - write(pl::pipe<Pl_RC4>(str, m->cur_data_key)); 1216 + write(pl::pipe<Pl_RC4>(str, cur_data_key));
1148 } 1217 }
1149 1218
1150 return *this; 1219 return *this;
@@ -1163,23 +1232,23 @@ QPDFWriter::computeDeterministicIDData() @@ -1163,23 +1232,23 @@ QPDFWriter::computeDeterministicIDData()
1163 } 1232 }
1164 1233
1165 int 1234 int
1166 -QPDFWriter::openObject(int objid) 1235 +QPDFWriter::Members::openObject(int objid)
1167 { 1236 {
1168 if (objid == 0) { 1237 if (objid == 0) {
1169 - objid = m->next_objid++; 1238 + objid = next_objid++;
1170 } 1239 }
1171 - m->new_obj[objid].xref = QPDFXRefEntry(m->pipeline->getCount()); 1240 + new_obj[objid].xref = QPDFXRefEntry(pipeline->getCount());
1172 write(objid).write(" 0 obj\n"); 1241 write(objid).write(" 0 obj\n");
1173 return objid; 1242 return objid;
1174 } 1243 }
1175 1244
1176 void 1245 void
1177 -QPDFWriter::closeObject(int objid) 1246 +QPDFWriter::Members::closeObject(int objid)
1178 { 1247 {
1179 // Write a newline before endobj as it makes the file easier to repair. 1248 // Write a newline before endobj as it makes the file easier to repair.
1180 write("\nendobj\n").write_qdf("\n"); 1249 write("\nendobj\n").write_qdf("\n");
1181 - auto& new_obj = m->new_obj[objid];  
1182 - new_obj.length = m->pipeline->getCount() - new_obj.xref.getOffset(); 1250 + auto& no = new_obj[objid];
  1251 + no.length = pipeline->getCount() - no.xref.getOffset();
1183 } 1252 }
1184 1253
1185 void 1254 void
@@ -1268,25 +1337,25 @@ QPDFWriter::Members::enqueueObject(QPDFObjectHandle object) @@ -1268,25 +1337,25 @@ QPDFWriter::Members::enqueueObject(QPDFObjectHandle object)
1268 } 1337 }
1269 1338
1270 void 1339 void
1271 -QPDFWriter::unparseChild(QPDFObjectHandle const& child, size_t level, int flags) 1340 +QPDFWriter::Members::unparseChild(QPDFObjectHandle const& child, size_t level, int flags)
1272 { 1341 {
1273 - if (!m->linearized) {  
1274 - m->enqueueObject(child); 1342 + if (!linearized) {
  1343 + enqueueObject(child);
1275 } 1344 }
1276 if (child.isIndirect()) { 1345 if (child.isIndirect()) {
1277 - write(m->obj[child].renumber).write(" 0 R"); 1346 + write(obj[child].renumber).write(" 0 R");
1278 } else { 1347 } else {
1279 unparseObject(child, level, flags); 1348 unparseObject(child, level, flags);
1280 } 1349 }
1281 } 1350 }
1282 1351
1283 void 1352 void
1284 -QPDFWriter::writeTrailer( 1353 +QPDFWriter::Members::writeTrailer(
1285 trailer_e which, int size, bool xref_stream, qpdf_offset_t prev, int linearization_pass) 1354 trailer_e which, int size, bool xref_stream, qpdf_offset_t prev, int linearization_pass)
1286 { 1355 {
1287 - QPDFObjectHandle trailer = m->getTrimmedTrailer(); 1356 + QPDFObjectHandle trailer = getTrimmedTrailer();
1288 if (xref_stream) { 1357 if (xref_stream) {
1289 - m->cur_data_key.clear(); 1358 + cur_data_key.clear();
1290 } else { 1359 } else {
1291 write("trailer <<"); 1360 write("trailer <<");
1292 } 1361 }
@@ -1303,8 +1372,8 @@ QPDFWriter::writeTrailer( @@ -1303,8 +1372,8 @@ QPDFWriter::writeTrailer(
1303 write(size); 1372 write(size);
1304 if (which == t_lin_first) { 1373 if (which == t_lin_first) {
1305 write(" /Prev "); 1374 write(" /Prev ");
1306 - qpdf_offset_t pos = m->pipeline->getCount();  
1307 - write(prev).write(QIntC::to_size(pos - m->pipeline->getCount() + 21), ' '); 1375 + qpdf_offset_t pos = pipeline->getCount();
  1376 + write(prev).write(QIntC::to_size(pos - pipeline->getCount() + 21), ' ');
1308 } 1377 }
1309 } else { 1378 } else {
1310 unparseChild(value, 1, 0); 1379 unparseChild(value, 1, 0);
@@ -1316,7 +1385,7 @@ QPDFWriter::writeTrailer( @@ -1316,7 +1385,7 @@ QPDFWriter::writeTrailer(
1316 // Write ID 1385 // Write ID
1317 write_qdf(" ").write(" /ID ["); 1386 write_qdf(" ").write(" /ID [");
1318 if (linearization_pass == 1) { 1387 if (linearization_pass == 1) {
1319 - std::string original_id1 = m->getOriginalID1(); 1388 + std::string original_id1 = getOriginalID1();
1320 if (original_id1.empty()) { 1389 if (original_id1.empty()) {
1321 write("<00000000000000000000000000000000>"); 1390 write("<00000000000000000000000000000000>");
1322 } else { 1391 } else {
@@ -1329,18 +1398,18 @@ QPDFWriter::writeTrailer( @@ -1329,18 +1398,18 @@ QPDFWriter::writeTrailer(
1329 } 1398 }
1330 write("<00000000000000000000000000000000>"); 1399 write("<00000000000000000000000000000000>");
1331 } else { 1400 } else {
1332 - if (linearization_pass == 0 && m->deterministic_id) {  
1333 - computeDeterministicIDData(); 1401 + if (linearization_pass == 0 && deterministic_id) {
  1402 + w.computeDeterministicIDData();
1334 } 1403 }
1335 - m->generateID(m->encryption.get());  
1336 - write_string(m->id1, true).write_string(m->id2, true); 1404 + generateID(encryption.get());
  1405 + write_string(id1, true).write_string(id2, true);
1337 } 1406 }
1338 write("]"); 1407 write("]");
1339 1408
1340 if (which != t_lin_second) { 1409 if (which != t_lin_second) {
1341 // Write reference to encryption dictionary 1410 // Write reference to encryption dictionary
1342 - if (m->encryption) {  
1343 - write(" /Encrypt ").write(m->encryption_dict_objid).write(" 0 R"); 1411 + if (encryption) {
  1412 + write(" /Encrypt ").write(encryption_dict_objid).write(" 0 R");
1344 } 1413 }
1345 } 1414 }
1346 1415
@@ -1442,7 +1511,7 @@ QPDFWriter::Members::willFilterStream( @@ -1442,7 +1511,7 @@ QPDFWriter::Members::willFilterStream(
1442 } 1511 }
1443 1512
1444 void 1513 void
1445 -QPDFWriter::unparseObject( 1514 +QPDFWriter::Members::unparseObject(
1446 QPDFObjectHandle object, size_t level, int flags, size_t stream_length, bool compress) 1515 QPDFObjectHandle object, size_t level, int flags, size_t stream_length, bool compress)
1447 { 1516 {
1448 QPDFObjGen old_og = object.getObjGen(); 1517 QPDFObjGen old_og = object.getObjGen();
@@ -1450,11 +1519,11 @@ QPDFWriter::unparseObject( @@ -1450,11 +1519,11 @@ QPDFWriter::unparseObject(
1450 // For non-qdf, "indent" and "indent_large" are a single space between tokens. For qdf, they 1519 // For non-qdf, "indent" and "indent_large" are a single space between tokens. For qdf, they
1451 // include the preceding newline. 1520 // include the preceding newline.
1452 std::string indent_large = " "; 1521 std::string indent_large = " ";
1453 - if (m->qdf_mode) { 1522 + if (qdf_mode) {
1454 indent_large.append(2 * (level + 1), ' '); 1523 indent_large.append(2 * (level + 1), ' ');
1455 indent_large[0] = '\n'; 1524 indent_large[0] = '\n';
1456 } 1525 }
1457 - std::string_view indent{indent_large.data(), m->qdf_mode ? indent_large.size() - 2 : 1}; 1526 + std::string_view indent{indent_large.data(), qdf_mode ? indent_large.size() - 2 : 1};
1458 1527
1459 if (auto const tc = object.getTypeCode(); tc == ::ot_array) { 1528 if (auto const tc = object.getTypeCode(); tc == ::ot_array) {
1460 // Note: PDF spec 1.4 implementation note 121 states that Acrobat requires a space after the 1529 // Note: PDF spec 1.4 implementation note 121 states that Acrobat requires a space after the
@@ -1469,7 +1538,7 @@ QPDFWriter::unparseObject( @@ -1469,7 +1538,7 @@ QPDFWriter::unparseObject(
1469 } else if (tc == ::ot_dictionary) { 1538 } else if (tc == ::ot_dictionary) {
1470 // Handle special cases for specific dictionaries. 1539 // Handle special cases for specific dictionaries.
1471 1540
1472 - if (old_og == m->root_og) { 1541 + if (old_og == root_og) {
1473 // Extensions dictionaries. 1542 // Extensions dictionaries.
1474 1543
1475 // We have one of several cases: 1544 // We have one of several cases:
@@ -1490,7 +1559,7 @@ QPDFWriter::unparseObject( @@ -1490,7 +1559,7 @@ QPDFWriter::unparseObject(
1490 1559
1491 auto extensions = object.getKey("/Extensions"); 1560 auto extensions = object.getKey("/Extensions");
1492 const bool has_extensions = extensions.isDictionary(); 1561 const bool has_extensions = extensions.isDictionary();
1493 - const bool need_extensions_adbe = m->final_extension_level > 0; 1562 + const bool need_extensions_adbe = final_extension_level > 0;
1494 1563
1495 if (has_extensions || need_extensions_adbe) { 1564 if (has_extensions || need_extensions_adbe) {
1496 // Make a shallow copy of this object so we can modify it safely without affecting 1565 // Make a shallow copy of this object so we can modify it safely without affecting
@@ -1510,7 +1579,7 @@ QPDFWriter::unparseObject( @@ -1510,7 +1579,7 @@ QPDFWriter::unparseObject(
1510 if (need_extensions_adbe) { 1579 if (need_extensions_adbe) {
1511 if (!(have_extensions_other || have_extensions_adbe)) { 1580 if (!(have_extensions_other || have_extensions_adbe)) {
1512 // We need Extensions and don't have it. Create it here. 1581 // We need Extensions and don't have it. Create it here.
1513 - QTC::TC("qpdf", "QPDFWriter create Extensions", m->qdf_mode ? 0 : 1); 1582 + QTC::TC("qpdf", "QPDFWriter create Extensions", qdf_mode ? 0 : 1);
1514 extensions = object.replaceKeyAndGetNew( 1583 extensions = object.replaceKeyAndGetNew(
1515 "/Extensions", QPDFObjectHandle::newDictionary()); 1584 "/Extensions", QPDFObjectHandle::newDictionary());
1516 } 1585 }
@@ -1527,21 +1596,17 @@ QPDFWriter::unparseObject( @@ -1527,21 +1596,17 @@ QPDFWriter::unparseObject(
1527 QTC::TC("qpdf", "QPDFWriter preserve Extensions"); 1596 QTC::TC("qpdf", "QPDFWriter preserve Extensions");
1528 QPDFObjectHandle adbe = extensions.getKey("/ADBE"); 1597 QPDFObjectHandle adbe = extensions.getKey("/ADBE");
1529 if (adbe.isDictionary() && 1598 if (adbe.isDictionary() &&
1530 - adbe.getKey("/BaseVersion").isNameAndEquals("/" + m->final_pdf_version) && 1599 + adbe.getKey("/BaseVersion").isNameAndEquals("/" + final_pdf_version) &&
1531 adbe.getKey("/ExtensionLevel").isInteger() && 1600 adbe.getKey("/ExtensionLevel").isInteger() &&
1532 - (adbe.getKey("/ExtensionLevel").getIntValue() ==  
1533 - m->final_extension_level)) {  
1534 - QTC::TC("qpdf", "QPDFWriter preserve ADBE"); 1601 + (adbe.getKey("/ExtensionLevel").getIntValue() == final_extension_level)) {
1535 } else { 1602 } else {
1536 if (need_extensions_adbe) { 1603 if (need_extensions_adbe) {
1537 extensions.replaceKey( 1604 extensions.replaceKey(
1538 "/ADBE", 1605 "/ADBE",
1539 QPDFObjectHandle::parse( 1606 QPDFObjectHandle::parse(
1540 - "<< /BaseVersion /" + m->final_pdf_version +  
1541 - " /ExtensionLevel " + std::to_string(m->final_extension_level) +  
1542 - " >>")); 1607 + "<< /BaseVersion /" + final_pdf_version + " /ExtensionLevel " +
  1608 + std::to_string(final_extension_level) + " >>"));
1543 } else { 1609 } else {
1544 - QTC::TC("qpdf", "QPDFWriter remove ADBE");  
1545 extensions.removeKey("/ADBE"); 1610 extensions.removeKey("/ADBE");
1546 } 1611 }
1547 } 1612 }
@@ -1619,10 +1684,10 @@ QPDFWriter::unparseObject( @@ -1619,10 +1684,10 @@ QPDFWriter::unparseObject(
1619 if (flags & f_stream) { 1684 if (flags & f_stream) {
1620 write(indent_large).write("/Length "); 1685 write(indent_large).write("/Length ");
1621 1686
1622 - if (m->direct_stream_lengths) { 1687 + if (direct_stream_lengths) {
1623 write(stream_length); 1688 write(stream_length);
1624 } else { 1689 } else {
1625 - write(m->cur_stream_length_id).write(" 0 R"); 1690 + write(cur_stream_length_id).write(" 0 R");
1626 } 1691 }
1627 if (compress && (flags & f_filtered)) { 1692 if (compress && (flags & f_filtered)) {
1628 write(indent_large).write("/Filter /FlateDecode"); 1693 write(indent_large).write("/Filter /FlateDecode");
@@ -1632,38 +1697,38 @@ QPDFWriter::unparseObject( @@ -1632,38 +1697,38 @@ QPDFWriter::unparseObject(
1632 write(indent).write(">>"); 1697 write(indent).write(">>");
1633 } else if (tc == ::ot_stream) { 1698 } else if (tc == ::ot_stream) {
1634 // Write stream data to a buffer. 1699 // Write stream data to a buffer.
1635 - if (!m->direct_stream_lengths) {  
1636 - m->cur_stream_length_id = m->obj[old_og].renumber + 1; 1700 + if (!direct_stream_lengths) {
  1701 + cur_stream_length_id = obj[old_og].renumber + 1;
1637 } 1702 }
1638 1703
1639 flags |= f_stream; 1704 flags |= f_stream;
1640 bool compress_stream = false; 1705 bool compress_stream = false;
1641 bool is_metadata = false; 1706 bool is_metadata = false;
1642 std::string stream_data; 1707 std::string stream_data;
1643 - if (m->willFilterStream(object, compress_stream, is_metadata, &stream_data)) { 1708 + if (willFilterStream(object, compress_stream, is_metadata, &stream_data)) {
1644 flags |= f_filtered; 1709 flags |= f_filtered;
1645 } 1710 }
1646 QPDFObjectHandle stream_dict = object.getDict(); 1711 QPDFObjectHandle stream_dict = object.getDict();
1647 1712
1648 - m->cur_stream_length = stream_data.size();  
1649 - if (is_metadata && m->encryption && !m->encryption->getEncryptMetadata()) { 1713 + cur_stream_length = stream_data.size();
  1714 + if (is_metadata && encryption && !encryption->getEncryptMetadata()) {
1650 // Don't encrypt stream data for the metadata stream 1715 // Don't encrypt stream data for the metadata stream
1651 - m->cur_data_key.clear(); 1716 + cur_data_key.clear();
1652 } 1717 }
1653 - adjustAESStreamLength(m->cur_stream_length);  
1654 - unparseObject(stream_dict, 0, flags, m->cur_stream_length, compress_stream); 1718 + w.adjustAESStreamLength(cur_stream_length);
  1719 + unparseObject(stream_dict, 0, flags, cur_stream_length, compress_stream);
1655 char last_char = stream_data.empty() ? '\0' : stream_data.back(); 1720 char last_char = stream_data.empty() ? '\0' : stream_data.back();
1656 write("\nstream\n").write_encrypted(stream_data); 1721 write("\nstream\n").write_encrypted(stream_data);
1657 - m->added_newline = m->newline_before_endstream || (m->qdf_mode && last_char != '\n');  
1658 - write(m->added_newline ? "\nendstream" : "endstream"); 1722 + added_newline = newline_before_endstream || (qdf_mode && last_char != '\n');
  1723 + write(added_newline ? "\nendstream" : "endstream");
1659 } else if (tc == ::ot_string) { 1724 } else if (tc == ::ot_string) {
1660 std::string val; 1725 std::string val;
1661 - if (m->encryption && !(flags & f_in_ostream) && !(flags & f_no_encryption) &&  
1662 - !m->cur_data_key.empty()) { 1726 + if (encryption && !(flags & f_in_ostream) && !(flags & f_no_encryption) &&
  1727 + !cur_data_key.empty()) {
1663 val = object.getStringValue(); 1728 val = object.getStringValue();
1664 - if (m->encrypt_use_aes) { 1729 + if (encrypt_use_aes) {
1665 Pl_Buffer bufpl("encrypted string"); 1730 Pl_Buffer bufpl("encrypted string");
1666 - Pl_AES_PDF pl("aes encrypt string", &bufpl, true, m->cur_data_key); 1731 + Pl_AES_PDF pl("aes encrypt string", &bufpl, true, cur_data_key);
1667 pl.writeString(val); 1732 pl.writeString(val);
1668 pl.finish(); 1733 pl.finish();
1669 val = QPDF_String(bufpl.getString()).unparse(true); 1734 val = QPDF_String(bufpl.getString()).unparse(true);
@@ -1672,8 +1737,8 @@ QPDFWriter::unparseObject( @@ -1672,8 +1737,8 @@ QPDFWriter::unparseObject(
1672 char* tmp = tmp_ph.get(); 1737 char* tmp = tmp_ph.get();
1673 size_t vlen = val.length(); 1738 size_t vlen = val.length();
1674 RC4 rc4( 1739 RC4 rc4(
1675 - QUtil::unsigned_char_pointer(m->cur_data_key),  
1676 - QIntC::to_int(m->cur_data_key.length())); 1740 + QUtil::unsigned_char_pointer(cur_data_key),
  1741 + QIntC::to_int(cur_data_key.length()));
1677 auto data = QUtil::unsigned_char_pointer(tmp); 1742 auto data = QUtil::unsigned_char_pointer(tmp);
1678 rc4.process(data, vlen, data); 1743 rc4.process(data, vlen, data);
1679 val = QPDF_String(std::string(tmp, vlen)).unparse(); 1744 val = QPDF_String(std::string(tmp, vlen)).unparse();
@@ -1690,7 +1755,7 @@ QPDFWriter::unparseObject( @@ -1690,7 +1755,7 @@ QPDFWriter::unparseObject(
1690 } 1755 }
1691 1756
1692 void 1757 void
1693 -QPDFWriter::writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offsets, int first_obj) 1758 +QPDFWriter::Members::writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offsets, int first_obj)
1694 { 1759 {
1695 qpdf_assert_debug(first_obj > 0); 1760 qpdf_assert_debug(first_obj > 0);
1696 bool is_first = true; 1761 bool is_first = true;
@@ -1709,7 +1774,7 @@ QPDFWriter::writeObjectStreamOffsets(std::vector&lt;qpdf_offset_t&gt;&amp; offsets, int fi @@ -1709,7 +1774,7 @@ QPDFWriter::writeObjectStreamOffsets(std::vector&lt;qpdf_offset_t&gt;&amp; offsets, int fi
1709 } 1774 }
1710 1775
1711 void 1776 void
1712 -QPDFWriter::writeObjectStream(QPDFObjectHandle object) 1777 +QPDFWriter::Members::writeObjectStream(QPDFObjectHandle object)
1713 { 1778 {
1714 // Note: object might be null if this is a place-holder for an object stream that we are 1779 // Note: object might be null if this is a place-holder for an object stream that we are
1715 // generating from scratch. 1780 // generating from scratch.
@@ -1717,7 +1782,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) @@ -1717,7 +1782,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object)
1717 QPDFObjGen old_og = object.getObjGen(); 1782 QPDFObjGen old_og = object.getObjGen();
1718 qpdf_assert_debug(old_og.getGen() == 0); 1783 qpdf_assert_debug(old_og.getGen() == 0);
1719 int old_id = old_og.getObj(); 1784 int old_id = old_og.getObj();
1720 - int new_stream_id = m->obj[old_og].renumber; 1785 + int new_stream_id = obj[old_og].renumber;
1721 1786
1722 std::vector<qpdf_offset_t> offsets; 1787 std::vector<qpdf_offset_t> offsets;
1723 qpdf_offset_t first = 0; 1788 qpdf_offset_t first = 0;
@@ -1727,39 +1792,38 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) @@ -1727,39 +1792,38 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object)
1727 std::string stream_buffer_pass1; 1792 std::string stream_buffer_pass1;
1728 std::string stream_buffer_pass2; 1793 std::string stream_buffer_pass2;
1729 int first_obj = -1; 1794 int first_obj = -1;
1730 - const bool compressed = m->compress_streams && !m->qdf_mode; 1795 + const bool compressed = compress_streams && !qdf_mode;
1731 { 1796 {
1732 // Pass 1 1797 // Pass 1
1733 - auto pp_ostream_pass1 = m->pipeline_stack.activate(stream_buffer_pass1); 1798 + auto pp_ostream_pass1 = pipeline_stack.activate(stream_buffer_pass1);
1734 1799
1735 int count = -1; 1800 int count = -1;
1736 - for (auto const& obj: m->object_stream_to_objects[old_id]) { 1801 + for (auto const& og: object_stream_to_objects[old_id]) {
1737 ++count; 1802 ++count;
1738 - int new_obj = m->obj[obj].renumber; 1803 + int new_o = obj[og].renumber;
1739 if (first_obj == -1) { 1804 if (first_obj == -1) {
1740 - first_obj = new_obj; 1805 + first_obj = new_o;
1741 } 1806 }
1742 - if (m->qdf_mode) {  
1743 - write("%% Object stream: object ").write(new_obj).write(", index ").write(count);  
1744 - if (!m->suppress_original_object_ids) {  
1745 - write("; original object ID: ").write(obj.getObj()); 1807 + if (qdf_mode) {
  1808 + write("%% Object stream: object ").write(new_o).write(", index ").write(count);
  1809 + if (!suppress_original_object_ids) {
  1810 + write("; original object ID: ").write(og.getObj());
1746 // For compatibility, only write the generation if non-zero. While object 1811 // For compatibility, only write the generation if non-zero. While object
1747 // streams only allow objects with generation 0, if we are generating object 1812 // streams only allow objects with generation 0, if we are generating object
1748 // streams, the old object could have a non-zero generation. 1813 // streams, the old object could have a non-zero generation.
1749 - if (obj.getGen() != 0) {  
1750 - QTC::TC("qpdf", "QPDFWriter original obj non-zero gen");  
1751 - write(" ").write(obj.getGen()); 1814 + if (og.getGen() != 0) {
  1815 + write(" ").write(og.getGen());
1752 } 1816 }
1753 } 1817 }
1754 write("\n"); 1818 write("\n");
1755 } 1819 }
1756 1820
1757 - offsets.push_back(m->pipeline->getCount()); 1821 + offsets.push_back(pipeline->getCount());
1758 // To avoid double-counting objects being written in object streams for progress 1822 // To avoid double-counting objects being written in object streams for progress
1759 // reporting, decrement in pass 1. 1823 // reporting, decrement in pass 1.
1760 - indicateProgress(true, false); 1824 + w.indicateProgress(true, false);
1761 1825
1762 - QPDFObjectHandle obj_to_write = m->pdf.getObject(obj); 1826 + QPDFObjectHandle obj_to_write = pdf.getObject(og);
1763 if (obj_to_write.isStream()) { 1827 if (obj_to_write.isStream()) {
1764 // This condition occurred in a fuzz input. Ideally we should block it at parse 1828 // This condition occurred in a fuzz input. Ideally we should block it at parse
1765 // time, but it's not clear to me how to construct a case for this. 1829 // time, but it's not clear to me how to construct a case for this.
@@ -1768,7 +1832,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) @@ -1768,7 +1832,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object)
1768 } 1832 }
1769 writeObject(obj_to_write, count); 1833 writeObject(obj_to_write, count);
1770 1834
1771 - m->new_obj[new_obj].xref = QPDFXRefEntry(new_stream_id, count); 1835 + new_obj[new_o].xref = QPDFXRefEntry(new_stream_id, count);
1772 } 1836 }
1773 } 1837 }
1774 { 1838 {
@@ -1780,13 +1844,13 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) @@ -1780,13 +1844,13 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object)
1780 1844
1781 // Take one pass at writing pairs of numbers so we can get their size information 1845 // Take one pass at writing pairs of numbers so we can get their size information
1782 { 1846 {
1783 - auto pp_discard = m->pipeline_stack.activate(true); 1847 + auto pp_discard = pipeline_stack.activate(true);
1784 writeObjectStreamOffsets(offsets, first_obj); 1848 writeObjectStreamOffsets(offsets, first_obj);
1785 - first += m->pipeline->getCount(); 1849 + first += pipeline->getCount();
1786 } 1850 }
1787 1851
1788 // Set up a stream to write the stream data into a buffer. 1852 // Set up a stream to write the stream data into a buffer.
1789 - auto pp_ostream = m->pipeline_stack.activate(stream_buffer_pass2); 1853 + auto pp_ostream = pipeline_stack.activate(stream_buffer_pass2);
1790 1854
1791 writeObjectStreamOffsets(offsets, first_obj); 1855 writeObjectStreamOffsets(offsets, first_obj);
1792 write(stream_buffer_pass1); 1856 write(stream_buffer_pass1);
@@ -1799,10 +1863,10 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) @@ -1799,10 +1863,10 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object)
1799 1863
1800 // Write the object 1864 // Write the object
1801 openObject(new_stream_id); 1865 openObject(new_stream_id);
1802 - setDataKey(new_stream_id); 1866 + w.setDataKey(new_stream_id);
1803 write("<<").write_qdf("\n ").write(" /Type /ObjStm").write_qdf("\n "); 1867 write("<<").write_qdf("\n ").write(" /Type /ObjStm").write_qdf("\n ");
1804 size_t length = stream_buffer_pass2.size(); 1868 size_t length = stream_buffer_pass2.size();
1805 - adjustAESStreamLength(length); 1869 + w.adjustAESStreamLength(length);
1806 write(" /Length ").write(length).write_qdf("\n "); 1870 write(" /Length ").write(length).write_qdf("\n ");
1807 if (compressed) { 1871 if (compressed) {
1808 write(" /Filter /FlateDecode"); 1872 write(" /Filter /FlateDecode");
@@ -1818,57 +1882,57 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) @@ -1818,57 +1882,57 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object)
1818 } 1882 }
1819 } 1883 }
1820 write_qdf("\n").write_no_qdf(" ").write(">>\nstream\n").write_encrypted(stream_buffer_pass2); 1884 write_qdf("\n").write_no_qdf(" ").write(">>\nstream\n").write_encrypted(stream_buffer_pass2);
1821 - if (m->encryption) { 1885 + if (encryption) {
1822 QTC::TC("qpdf", "QPDFWriter encrypt object stream"); 1886 QTC::TC("qpdf", "QPDFWriter encrypt object stream");
1823 } 1887 }
1824 - write(m->newline_before_endstream ? "\nendstream" : "endstream");  
1825 - m->cur_data_key.clear(); 1888 + write(newline_before_endstream ? "\nendstream" : "endstream");
  1889 + cur_data_key.clear();
1826 closeObject(new_stream_id); 1890 closeObject(new_stream_id);
1827 } 1891 }
1828 1892
1829 void 1893 void
1830 -QPDFWriter::writeObject(QPDFObjectHandle object, int object_stream_index) 1894 +QPDFWriter::Members::writeObject(QPDFObjectHandle object, int object_stream_index)
1831 { 1895 {
1832 QPDFObjGen old_og = object.getObjGen(); 1896 QPDFObjGen old_og = object.getObjGen();
1833 1897
1834 if (object_stream_index == -1 && old_og.getGen() == 0 && 1898 if (object_stream_index == -1 && old_og.getGen() == 0 &&
1835 - m->object_stream_to_objects.contains(old_og.getObj())) { 1899 + object_stream_to_objects.contains(old_og.getObj())) {
1836 writeObjectStream(object); 1900 writeObjectStream(object);
1837 return; 1901 return;
1838 } 1902 }
1839 1903
1840 - indicateProgress(false, false);  
1841 - auto new_id = m->obj[old_og].renumber;  
1842 - if (m->qdf_mode) {  
1843 - if (m->page_object_to_seq.contains(old_og)) {  
1844 - write("%% Page ").write(m->page_object_to_seq[old_og]).write("\n"); 1904 + w.indicateProgress(false, false);
  1905 + auto new_id = obj[old_og].renumber;
  1906 + if (qdf_mode) {
  1907 + if (page_object_to_seq.contains(old_og)) {
  1908 + write("%% Page ").write(page_object_to_seq[old_og]).write("\n");
1845 } 1909 }
1846 - if (m->contents_to_page_seq.contains(old_og)) {  
1847 - write("%% Contents for page ").write(m->contents_to_page_seq[old_og]).write("\n"); 1910 + if (contents_to_page_seq.contains(old_og)) {
  1911 + write("%% Contents for page ").write(contents_to_page_seq[old_og]).write("\n");
1848 } 1912 }
1849 } 1913 }
1850 if (object_stream_index == -1) { 1914 if (object_stream_index == -1) {
1851 - if (m->qdf_mode && (!m->suppress_original_object_ids)) { 1915 + if (qdf_mode && !suppress_original_object_ids) {
1852 write("%% Original object ID: ").write(object.getObjGen().unparse(' ')).write("\n"); 1916 write("%% Original object ID: ").write(object.getObjGen().unparse(' ')).write("\n");
1853 } 1917 }
1854 openObject(new_id); 1918 openObject(new_id);
1855 - setDataKey(new_id); 1919 + w.setDataKey(new_id);
1856 unparseObject(object, 0, 0); 1920 unparseObject(object, 0, 0);
1857 - m->cur_data_key.clear(); 1921 + cur_data_key.clear();
1858 closeObject(new_id); 1922 closeObject(new_id);
1859 } else { 1923 } else {
1860 unparseObject(object, 0, f_in_ostream); 1924 unparseObject(object, 0, f_in_ostream);
1861 write("\n"); 1925 write("\n");
1862 } 1926 }
1863 1927
1864 - if (!m->direct_stream_lengths && object.isStream()) {  
1865 - if (m->qdf_mode) {  
1866 - if (m->added_newline) { 1928 + if (!direct_stream_lengths && object.isStream()) {
  1929 + if (qdf_mode) {
  1930 + if (added_newline) {
1867 write("%QDF: ignore_newline\n"); 1931 write("%QDF: ignore_newline\n");
1868 } 1932 }
1869 } 1933 }
1870 openObject(new_id + 1); 1934 openObject(new_id + 1);
1871 - write(m->cur_stream_length); 1935 + write(cur_stream_length);
1872 closeObject(new_id + 1); 1936 closeObject(new_id + 1);
1873 } 1937 }
1874 } 1938 }
@@ -2289,9 +2353,9 @@ QPDFWriter::write() @@ -2289,9 +2353,9 @@ QPDFWriter::write()
2289 m->prepareFileForWrite(); 2353 m->prepareFileForWrite();
2290 2354
2291 if (m->linearized) { 2355 if (m->linearized) {
2292 - writeLinearized(); 2356 + m->writeLinearized();
2293 } else { 2357 } else {
2294 - writeStandard(); 2358 + m->writeStandard();
2295 } 2359 }
2296 2360
2297 m->pipeline->finish(); 2361 m->pipeline->finish();
@@ -2335,20 +2399,20 @@ QPDFWriter::Members::enqueuePart(std::vector&lt;QPDFObjectHandle&gt;&amp; part) @@ -2335,20 +2399,20 @@ QPDFWriter::Members::enqueuePart(std::vector&lt;QPDFObjectHandle&gt;&amp; part)
2335 } 2399 }
2336 2400
2337 void 2401 void
2338 -QPDFWriter::writeEncryptionDictionary() 2402 +QPDFWriter::Members::writeEncryptionDictionary()
2339 { 2403 {
2340 - m->encryption_dict_objid = openObject(m->encryption_dict_objid);  
2341 - auto& enc = *m->encryption; 2404 + encryption_dict_objid = openObject(encryption_dict_objid);
  2405 + auto& enc = *encryption;
2342 auto const V = enc.getV(); 2406 auto const V = enc.getV();
2343 2407
2344 write("<<"); 2408 write("<<");
2345 if (V >= 4) { 2409 if (V >= 4) {
2346 write(" /CF << /StdCF << /AuthEvent /DocOpen /CFM "); 2410 write(" /CF << /StdCF << /AuthEvent /DocOpen /CFM ");
2347 - write(m->encrypt_use_aes ? ((V < 5) ? "/AESV2" : "/AESV3") : "/V2"); 2411 + write(encrypt_use_aes ? ((V < 5) ? "/AESV2" : "/AESV3") : "/V2");
2348 // The PDF spec says the /Length key is optional, but the PDF previewer on some versions of 2412 // The PDF spec says the /Length key is optional, but the PDF previewer on some versions of
2349 // MacOS won't open encrypted files without it. 2413 // MacOS won't open encrypted files without it.
2350 write((V < 5) ? " /Length 16 >> >>" : " /Length 32 >> >>"); 2414 write((V < 5) ? " /Length 16 >> >>" : " /Length 32 >> >>");
2351 - if (!m->encryption->getEncryptMetadata()) { 2415 + if (!encryption->getEncryptMetadata()) {
2352 write(" /EncryptMetadata false"); 2416 write(" /EncryptMetadata false");
2353 } 2417 }
2354 } 2418 }
@@ -2371,7 +2435,7 @@ QPDFWriter::writeEncryptionDictionary() @@ -2371,7 +2435,7 @@ QPDFWriter::writeEncryptionDictionary()
2371 write(" /UE ").write_string(enc.getUE(), true); 2435 write(" /UE ").write_string(enc.getUE(), true);
2372 } 2436 }
2373 write(" /V ").write(enc.getV()).write(" >>"); 2437 write(" /V ").write(enc.getV()).write(" >>");
2374 - closeObject(m->encryption_dict_objid); 2438 + closeObject(encryption_dict_objid);
2375 } 2439 }
2376 2440
2377 std::string 2441 std::string
@@ -2382,10 +2446,10 @@ QPDFWriter::getFinalVersion() @@ -2382,10 +2446,10 @@ QPDFWriter::getFinalVersion()
2382 } 2446 }
2383 2447
2384 void 2448 void
2385 -QPDFWriter::writeHeader() 2449 +QPDFWriter::Members::writeHeader()
2386 { 2450 {
2387 - write("%PDF-").write(m->final_pdf_version);  
2388 - if (m->pclm) { 2451 + write("%PDF-").write(final_pdf_version);
  2452 + if (pclm) {
2389 // PCLm version 2453 // PCLm version
2390 write("\n%PCLm 1.0\n"); 2454 write("\n%PCLm 1.0\n");
2391 } else { 2455 } else {
@@ -2402,16 +2466,16 @@ QPDFWriter::writeHeader() @@ -2402,16 +2466,16 @@ QPDFWriter::writeHeader()
2402 } 2466 }
2403 2467
2404 void 2468 void
2405 -QPDFWriter::writeHintStream(int hint_id) 2469 +QPDFWriter::Members::writeHintStream(int hint_id)
2406 { 2470 {
2407 std::string hint_buffer; 2471 std::string hint_buffer;
2408 int S = 0; 2472 int S = 0;
2409 int O = 0; 2473 int O = 0;
2410 - bool compressed = m->compress_streams && !m->qdf_mode;  
2411 - QPDF::Writer::generateHintStream(m->pdf, m->new_obj, m->obj, hint_buffer, S, O, compressed); 2474 + bool compressed = compress_streams && !qdf_mode;
  2475 + QPDF::Writer::generateHintStream(pdf, new_obj, obj, hint_buffer, S, O, compressed);
2412 2476
2413 openObject(hint_id); 2477 openObject(hint_id);
2414 - setDataKey(hint_id); 2478 + w.setDataKey(hint_id);
2415 2479
2416 size_t hlen = hint_buffer.size(); 2480 size_t hlen = hint_buffer.size();
2417 2481
@@ -2423,11 +2487,11 @@ QPDFWriter::writeHintStream(int hint_id) @@ -2423,11 +2487,11 @@ QPDFWriter::writeHintStream(int hint_id)
2423 if (O) { 2487 if (O) {
2424 write(" /O ").write(O); 2488 write(" /O ").write(O);
2425 } 2489 }
2426 - adjustAESStreamLength(hlen); 2490 + w.adjustAESStreamLength(hlen);
2427 write(" /Length ").write(hlen); 2491 write(" /Length ").write(hlen);
2428 write(" >>\nstream\n").write_encrypted(hint_buffer); 2492 write(" >>\nstream\n").write_encrypted(hint_buffer);
2429 2493
2430 - if (m->encryption) { 2494 + if (encryption) {
2431 QTC::TC("qpdf", "QPDFWriter encrypted hint stream"); 2495 QTC::TC("qpdf", "QPDFWriter encrypted hint stream");
2432 } 2496 }
2433 2497
@@ -2436,7 +2500,7 @@ QPDFWriter::writeHintStream(int hint_id) @@ -2436,7 +2500,7 @@ QPDFWriter::writeHintStream(int hint_id)
2436 } 2500 }
2437 2501
2438 qpdf_offset_t 2502 qpdf_offset_t
2439 -QPDFWriter::writeXRefTable(trailer_e which, int first, int last, int size) 2503 +QPDFWriter::Members::writeXRefTable(trailer_e which, int first, int last, int size)
2440 { 2504 {
2441 // There are too many extra arguments to replace overloaded function with defaults in the header 2505 // There are too many extra arguments to replace overloaded function with defaults in the header
2442 // file...too much risk of leaving something off. 2506 // file...too much risk of leaving something off.
@@ -2444,7 +2508,7 @@ QPDFWriter::writeXRefTable(trailer_e which, int first, int last, int size) @@ -2444,7 +2508,7 @@ QPDFWriter::writeXRefTable(trailer_e which, int first, int last, int size)
2444 } 2508 }
2445 2509
2446 qpdf_offset_t 2510 qpdf_offset_t
2447 -QPDFWriter::writeXRefTable( 2511 +QPDFWriter::Members::writeXRefTable(
2448 trailer_e which, 2512 trailer_e which,
2449 int first, 2513 int first,
2450 int last, 2514 int last,
@@ -2457,7 +2521,7 @@ QPDFWriter::writeXRefTable( @@ -2457,7 +2521,7 @@ QPDFWriter::writeXRefTable(
2457 int linearization_pass) 2521 int linearization_pass)
2458 { 2522 {
2459 write("xref\n").write(first).write(" ").write(last - first + 1); 2523 write("xref\n").write(first).write(" ").write(last - first + 1);
2460 - qpdf_offset_t space_before_zero = m->pipeline->getCount(); 2524 + qpdf_offset_t space_before_zero = pipeline->getCount();
2461 write("\n"); 2525 write("\n");
2462 if (first == 0) { 2526 if (first == 0) {
2463 write("0000000000 65535 f \n"); 2527 write("0000000000 65535 f \n");
@@ -2466,7 +2530,7 @@ QPDFWriter::writeXRefTable( @@ -2466,7 +2530,7 @@ QPDFWriter::writeXRefTable(
2466 for (int i = first; i <= last; ++i) { 2530 for (int i = first; i <= last; ++i) {
2467 qpdf_offset_t offset = 0; 2531 qpdf_offset_t offset = 0;
2468 if (!suppress_offsets) { 2532 if (!suppress_offsets) {
2469 - offset = m->new_obj[i].xref.getOffset(); 2533 + offset = new_obj[i].xref.getOffset();
2470 if ((hint_id != 0) && (i != hint_id) && (offset >= hint_offset)) { 2534 if ((hint_id != 0) && (i != hint_id) && (offset >= hint_offset)) {
2471 offset += hint_length; 2535 offset += hint_length;
2472 } 2536 }
@@ -2479,7 +2543,7 @@ QPDFWriter::writeXRefTable( @@ -2479,7 +2543,7 @@ QPDFWriter::writeXRefTable(
2479 } 2543 }
2480 2544
2481 qpdf_offset_t 2545 qpdf_offset_t
2482 -QPDFWriter::writeXRefStream( 2546 +QPDFWriter::Members::writeXRefStream(
2483 int objid, int max_id, qpdf_offset_t max_offset, trailer_e which, int first, int last, int size) 2547 int objid, int max_id, qpdf_offset_t max_offset, trailer_e which, int first, int last, int size)
2484 { 2548 {
2485 // There are too many extra arguments to replace overloaded function with defaults in the header 2549 // There are too many extra arguments to replace overloaded function with defaults in the header
@@ -2489,7 +2553,7 @@ QPDFWriter::writeXRefStream( @@ -2489,7 +2553,7 @@ QPDFWriter::writeXRefStream(
2489 } 2553 }
2490 2554
2491 qpdf_offset_t 2555 qpdf_offset_t
2492 -QPDFWriter::writeXRefStream( 2556 +QPDFWriter::Members::writeXRefStream(
2493 int xref_id, 2557 int xref_id,
2494 int max_id, 2558 int max_id,
2495 qpdf_offset_t max_offset, 2559 qpdf_offset_t max_offset,
@@ -2504,28 +2568,28 @@ QPDFWriter::writeXRefStream( @@ -2504,28 +2568,28 @@ QPDFWriter::writeXRefStream(
2504 bool skip_compression, 2568 bool skip_compression,
2505 int linearization_pass) 2569 int linearization_pass)
2506 { 2570 {
2507 - qpdf_offset_t xref_offset = m->pipeline->getCount(); 2571 + qpdf_offset_t xref_offset = pipeline->getCount();
2508 qpdf_offset_t space_before_zero = xref_offset - 1; 2572 qpdf_offset_t space_before_zero = xref_offset - 1;
2509 2573
2510 // field 1 contains offsets and object stream identifiers 2574 // field 1 contains offsets and object stream identifiers
2511 unsigned int f1_size = std::max(bytesNeeded(max_offset + hint_length), bytesNeeded(max_id)); 2575 unsigned int f1_size = std::max(bytesNeeded(max_offset + hint_length), bytesNeeded(max_id));
2512 2576
2513 // field 2 contains object stream indices 2577 // field 2 contains object stream indices
2514 - unsigned int f2_size = bytesNeeded(QIntC::to_longlong(m->max_ostream_index)); 2578 + unsigned int f2_size = bytesNeeded(QIntC::to_longlong(max_ostream_index));
2515 2579
2516 unsigned int esize = 1 + f1_size + f2_size; 2580 unsigned int esize = 1 + f1_size + f2_size;
2517 2581
2518 // Must store in xref table in advance of writing the actual data rather than waiting for 2582 // Must store in xref table in advance of writing the actual data rather than waiting for
2519 // openObject to do it. 2583 // openObject to do it.
2520 - m->new_obj[xref_id].xref = QPDFXRefEntry(m->pipeline->getCount()); 2584 + new_obj[xref_id].xref = QPDFXRefEntry(pipeline->getCount());
2521 2585
2522 std::string xref_data; 2586 std::string xref_data;
2523 - const bool compressed = m->compress_streams && !m->qdf_mode; 2587 + const bool compressed = compress_streams && !qdf_mode;
2524 { 2588 {
2525 - auto pp_xref = m->pipeline_stack.activate(xref_data); 2589 + auto pp_xref = pipeline_stack.activate(xref_data);
2526 2590
2527 for (int i = first; i <= last; ++i) { 2591 for (int i = first; i <= last; ++i) {
2528 - QPDFXRefEntry& e = m->new_obj[i].xref; 2592 + QPDFXRefEntry& e = new_obj[i].xref;
2529 switch (e.getType()) { 2593 switch (e.getType()) {
2530 case 0: 2594 case 0:
2531 writeBinary(0, 1); 2595 writeBinary(0, 1);
@@ -2597,7 +2661,7 @@ QPDFWriter::calculateXrefStreamPadding(qpdf_offset_t xref_bytes) @@ -2597,7 +2661,7 @@ QPDFWriter::calculateXrefStreamPadding(qpdf_offset_t xref_bytes)
2597 } 2661 }
2598 2662
2599 void 2663 void
2600 -QPDFWriter::writeLinearized() 2664 +QPDFWriter::Members::writeLinearized()
2601 { 2665 {
2602 // Optimize file and enqueue objects in order 2666 // Optimize file and enqueue objects in order
2603 2667
@@ -2608,7 +2672,7 @@ QPDFWriter::writeLinearized() @@ -2608,7 +2672,7 @@ QPDFWriter::writeLinearized()
2608 if (result == 0) { 2672 if (result == 0) {
2609 bool compress_stream; 2673 bool compress_stream;
2610 bool is_metadata; 2674 bool is_metadata;
2611 - if (m->willFilterStream(stream, compress_stream, is_metadata, nullptr)) { 2675 + if (willFilterStream(stream, compress_stream, is_metadata, nullptr)) {
2612 result = 2; 2676 result = 2;
2613 } else { 2677 } else {
2614 result = 1; 2678 result = 1;
@@ -2617,14 +2681,14 @@ QPDFWriter::writeLinearized() @@ -2617,14 +2681,14 @@ QPDFWriter::writeLinearized()
2617 return result; 2681 return result;
2618 }; 2682 };
2619 2683
2620 - QPDF::Writer::optimize(m->pdf, m->obj, skip_stream_parameters); 2684 + QPDF::Writer::optimize(pdf, obj, skip_stream_parameters);
2621 2685
2622 std::vector<QPDFObjectHandle> part4; 2686 std::vector<QPDFObjectHandle> part4;
2623 std::vector<QPDFObjectHandle> part6; 2687 std::vector<QPDFObjectHandle> part6;
2624 std::vector<QPDFObjectHandle> part7; 2688 std::vector<QPDFObjectHandle> part7;
2625 std::vector<QPDFObjectHandle> part8; 2689 std::vector<QPDFObjectHandle> part8;
2626 std::vector<QPDFObjectHandle> part9; 2690 std::vector<QPDFObjectHandle> part9;
2627 - QPDF::Writer::getLinearizedParts(m->pdf, m->obj, part4, part6, part7, part8, part9); 2691 + QPDF::Writer::getLinearizedParts(pdf, obj, part4, part6, part7, part8, part9);
2628 2692
2629 // Object number sequence: 2693 // Object number sequence:
2630 // 2694 //
@@ -2646,48 +2710,48 @@ QPDFWriter::writeLinearized() @@ -2646,48 +2710,48 @@ QPDFWriter::writeLinearized()
2646 int second_half_uncompressed = QIntC::to_int(part7.size() + part8.size() + part9.size()); 2710 int second_half_uncompressed = QIntC::to_int(part7.size() + part8.size() + part9.size());
2647 int second_half_first_obj = 1; 2711 int second_half_first_obj = 1;
2648 int after_second_half = 1 + second_half_uncompressed; 2712 int after_second_half = 1 + second_half_uncompressed;
2649 - m->next_objid = after_second_half; 2713 + next_objid = after_second_half;
2650 int second_half_xref = 0; 2714 int second_half_xref = 0;
2651 - bool need_xref_stream = !m->obj.streams_empty; 2715 + bool need_xref_stream = !obj.streams_empty;
2652 if (need_xref_stream) { 2716 if (need_xref_stream) {
2653 - second_half_xref = m->next_objid++; 2717 + second_half_xref = next_objid++;
2654 } 2718 }
2655 // Assign numbers to all compressed objects in the second half. 2719 // Assign numbers to all compressed objects in the second half.
2656 std::vector<QPDFObjectHandle>* vecs2[] = {&part7, &part8, &part9}; 2720 std::vector<QPDFObjectHandle>* vecs2[] = {&part7, &part8, &part9};
2657 for (int i = 0; i < 3; ++i) { 2721 for (int i = 0; i < 3; ++i) {
2658 for (auto const& oh: *vecs2[i]) { 2722 for (auto const& oh: *vecs2[i]) {
2659 - m->assignCompressedObjectNumbers(oh.getObjGen()); 2723 + assignCompressedObjectNumbers(oh.getObjGen());
2660 } 2724 }
2661 } 2725 }
2662 - int second_half_end = m->next_objid - 1;  
2663 - int second_trailer_size = m->next_objid; 2726 + int second_half_end = next_objid - 1;
  2727 + int second_trailer_size = next_objid;
2664 2728
2665 // First half objects 2729 // First half objects
2666 - int first_half_start = m->next_objid;  
2667 - int lindict_id = m->next_objid++; 2730 + int first_half_start = next_objid;
  2731 + int lindict_id = next_objid++;
2668 int first_half_xref = 0; 2732 int first_half_xref = 0;
2669 if (need_xref_stream) { 2733 if (need_xref_stream) {
2670 - first_half_xref = m->next_objid++; 2734 + first_half_xref = next_objid++;
2671 } 2735 }
2672 - int part4_first_obj = m->next_objid;  
2673 - m->next_objid += QIntC::to_int(part4.size());  
2674 - int after_part4 = m->next_objid;  
2675 - if (m->encryption) {  
2676 - m->encryption_dict_objid = m->next_objid++; 2736 + int part4_first_obj = next_objid;
  2737 + next_objid += QIntC::to_int(part4.size());
  2738 + int after_part4 = next_objid;
  2739 + if (encryption) {
  2740 + encryption_dict_objid = next_objid++;
2677 } 2741 }
2678 - int hint_id = m->next_objid++;  
2679 - int part6_first_obj = m->next_objid;  
2680 - m->next_objid += QIntC::to_int(part6.size());  
2681 - int after_part6 = m->next_objid; 2742 + int hint_id = next_objid++;
  2743 + int part6_first_obj = next_objid;
  2744 + next_objid += QIntC::to_int(part6.size());
  2745 + int after_part6 = next_objid;
2682 // Assign numbers to all compressed objects in the first half 2746 // Assign numbers to all compressed objects in the first half
2683 std::vector<QPDFObjectHandle>* vecs1[] = {&part4, &part6}; 2747 std::vector<QPDFObjectHandle>* vecs1[] = {&part4, &part6};
2684 for (int i = 0; i < 2; ++i) { 2748 for (int i = 0; i < 2; ++i) {
2685 for (auto const& oh: *vecs1[i]) { 2749 for (auto const& oh: *vecs1[i]) {
2686 - m->assignCompressedObjectNumbers(oh.getObjGen()); 2750 + assignCompressedObjectNumbers(oh.getObjGen());
2687 } 2751 }
2688 } 2752 }
2689 - int first_half_end = m->next_objid - 1;  
2690 - int first_trailer_size = m->next_objid; 2753 + int first_half_end = next_objid - 1;
  2754 + int first_trailer_size = next_objid;
2691 2755
2692 int part4_end_marker = part4.back().getObjectID(); 2756 int part4_end_marker = part4.back().getObjectID();
2693 int part6_end_marker = part6.back().getObjectID(); 2757 int part6_end_marker = part6.back().getObjectID();
@@ -2699,23 +2763,23 @@ QPDFWriter::writeLinearized() @@ -2699,23 +2763,23 @@ QPDFWriter::writeLinearized()
2699 qpdf_offset_t first_xref_end = 0; 2763 qpdf_offset_t first_xref_end = 0;
2700 qpdf_offset_t second_xref_end = 0; 2764 qpdf_offset_t second_xref_end = 0;
2701 2765
2702 - m->next_objid = part4_first_obj;  
2703 - m->enqueuePart(part4);  
2704 - if (m->next_objid != after_part4) { 2766 + next_objid = part4_first_obj;
  2767 + enqueuePart(part4);
  2768 + if (next_objid != after_part4) {
2705 // This can happen with very botched files as in the fuzzer test. There are likely some 2769 // This can happen with very botched files as in the fuzzer test. There are likely some
2706 // faulty assumptions in calculateLinearizationData 2770 // faulty assumptions in calculateLinearizationData
2707 throw std::runtime_error("error encountered after writing part 4 of linearized data"); 2771 throw std::runtime_error("error encountered after writing part 4 of linearized data");
2708 } 2772 }
2709 - m->next_objid = part6_first_obj;  
2710 - m->enqueuePart(part6);  
2711 - if (m->next_objid != after_part6) { 2773 + next_objid = part6_first_obj;
  2774 + enqueuePart(part6);
  2775 + if (next_objid != after_part6) {
2712 throw std::runtime_error("error encountered after writing part 6 of linearized data"); 2776 throw std::runtime_error("error encountered after writing part 6 of linearized data");
2713 } 2777 }
2714 - m->next_objid = second_half_first_obj;  
2715 - m->enqueuePart(part7);  
2716 - m->enqueuePart(part8);  
2717 - m->enqueuePart(part9);  
2718 - if (m->next_objid != after_second_half) { 2778 + next_objid = second_half_first_obj;
  2779 + enqueuePart(part7);
  2780 + enqueuePart(part8);
  2781 + enqueuePart(part9);
  2782 + if (next_objid != after_second_half) {
2719 throw std::runtime_error("error encountered after writing part 9 of linearized data"); 2783 throw std::runtime_error("error encountered after writing part 9 of linearized data");
2720 } 2784 }
2721 2785
@@ -2725,20 +2789,20 @@ QPDFWriter::writeLinearized() @@ -2725,20 +2789,20 @@ QPDFWriter::writeLinearized()
2725 // Write file in two passes. Part numbers refer to PDF spec 1.4. 2789 // Write file in two passes. Part numbers refer to PDF spec 1.4.
2726 2790
2727 FILE* lin_pass1_file = nullptr; 2791 FILE* lin_pass1_file = nullptr;
2728 - auto pp_pass1 = m->pipeline_stack.popper();  
2729 - auto pp_md5 = m->pipeline_stack.popper(); 2792 + auto pp_pass1 = pipeline_stack.popper();
  2793 + auto pp_md5 = pipeline_stack.popper();
2730 for (int pass: {1, 2}) { 2794 for (int pass: {1, 2}) {
2731 if (pass == 1) { 2795 if (pass == 1) {
2732 - if (!m->lin_pass1_filename.empty()) {  
2733 - lin_pass1_file = QUtil::safe_fopen(m->lin_pass1_filename.c_str(), "wb");  
2734 - m->pipeline_stack.activate( 2796 + if (!lin_pass1_filename.empty()) {
  2797 + lin_pass1_file = QUtil::safe_fopen(lin_pass1_filename.c_str(), "wb");
  2798 + pipeline_stack.activate(
2735 pp_pass1, 2799 pp_pass1,
2736 std::make_unique<Pl_StdioFile>("linearization pass1", lin_pass1_file)); 2800 std::make_unique<Pl_StdioFile>("linearization pass1", lin_pass1_file));
2737 } else { 2801 } else {
2738 - m->pipeline_stack.activate(pp_pass1, true); 2802 + pipeline_stack.activate(pp_pass1, true);
2739 } 2803 }
2740 - if (m->deterministic_id) {  
2741 - m->pipeline_stack.activate_md5(pp_md5); 2804 + if (deterministic_id) {
  2805 + pipeline_stack.activate_md5(pp_md5);
2742 } 2806 }
2743 } 2807 }
2744 2808
@@ -2752,16 +2816,16 @@ QPDFWriter::writeLinearized() @@ -2752,16 +2816,16 @@ QPDFWriter::writeLinearized()
2752 // linearization parameter dictionary must appear within the first 1024 characters of the 2816 // linearization parameter dictionary must appear within the first 1024 characters of the
2753 // file. 2817 // file.
2754 2818
2755 - qpdf_offset_t pos = m->pipeline->getCount(); 2819 + qpdf_offset_t pos = pipeline->getCount();
2756 openObject(lindict_id); 2820 openObject(lindict_id);
2757 write("<<"); 2821 write("<<");
2758 if (pass == 2) { 2822 if (pass == 2) {
2759 - std::vector<QPDFObjectHandle> const& pages = m->pdf.getAllPages();  
2760 - int first_page_object = m->obj[pages.at(0)].renumber; 2823 + std::vector<QPDFObjectHandle> const& pages = pdf.getAllPages();
  2824 + int first_page_object = obj[pages.at(0)].renumber;
2761 2825
2762 write(" /Linearized 1 /L ").write(file_size + hint_length); 2826 write(" /Linearized 1 /L ").write(file_size + hint_length);
2763 // Implementation note 121 states that a space is mandatory after this open bracket. 2827 // Implementation note 121 states that a space is mandatory after this open bracket.
2764 - write(" /H [ ").write(m->new_obj[hint_id].xref.getOffset()).write(" "); 2828 + write(" /H [ ").write(new_obj[hint_id].xref.getOffset()).write(" ");
2765 write(hint_length); 2829 write(hint_length);
2766 write(" ] /O ").write(first_page_object); 2830 write(" ] /O ").write(first_page_object);
2767 write(" /E ").write(part6_end_offset + hint_length); 2831 write(" /E ").write(part6_end_offset + hint_length);
@@ -2771,18 +2835,18 @@ QPDFWriter::writeLinearized() @@ -2771,18 +2835,18 @@ QPDFWriter::writeLinearized()
2771 write(" >>"); 2835 write(" >>");
2772 closeObject(lindict_id); 2836 closeObject(lindict_id);
2773 static int const pad = 200; 2837 static int const pad = 200;
2774 - write(QIntC::to_size(pos - m->pipeline->getCount() + pad), ' ').write("\n"); 2838 + write(QIntC::to_size(pos - pipeline->getCount() + pad), ' ').write("\n");
2775 2839
2776 // If the user supplied any additional header text, write it here after the linearization 2840 // If the user supplied any additional header text, write it here after the linearization
2777 // parameter dictionary. 2841 // parameter dictionary.
2778 - write(m->extra_header_text); 2842 + write(extra_header_text);
2779 2843
2780 // Part 3: first page cross reference table and trailer. 2844 // Part 3: first page cross reference table and trailer.
2781 2845
2782 - qpdf_offset_t first_xref_offset = m->pipeline->getCount(); 2846 + qpdf_offset_t first_xref_offset = pipeline->getCount();
2783 qpdf_offset_t hint_offset = 0; 2847 qpdf_offset_t hint_offset = 0;
2784 if (pass == 2) { 2848 if (pass == 2) {
2785 - hint_offset = m->new_obj[hint_id].xref.getOffset(); 2849 + hint_offset = new_obj[hint_id].xref.getOffset();
2786 } 2850 }
2787 if (need_xref_stream) { 2851 if (need_xref_stream) {
2788 // Must pad here too. 2852 // Must pad here too.
@@ -2794,7 +2858,7 @@ QPDFWriter::writeLinearized() @@ -2794,7 +2858,7 @@ QPDFWriter::writeLinearized()
2794 // value for this, but it's okay if it's smaller. 2858 // value for this, but it's okay if it's smaller.
2795 first_half_max_obj_offset = 1 << 25; 2859 first_half_max_obj_offset = 1 << 25;
2796 } 2860 }
2797 - pos = m->pipeline->getCount(); 2861 + pos = pipeline->getCount();
2798 writeXRefStream( 2862 writeXRefStream(
2799 first_half_xref, 2863 first_half_xref,
2800 first_half_end, 2864 first_half_end,
@@ -2809,16 +2873,16 @@ QPDFWriter::writeLinearized() @@ -2809,16 +2873,16 @@ QPDFWriter::writeLinearized()
2809 hint_length, 2873 hint_length,
2810 (pass == 1), 2874 (pass == 1),
2811 pass); 2875 pass);
2812 - qpdf_offset_t endpos = m->pipeline->getCount(); 2876 + qpdf_offset_t endpos = pipeline->getCount();
2813 if (pass == 1) { 2877 if (pass == 1) {
2814 // Pad so we have enough room for the real xref stream. 2878 // Pad so we have enough room for the real xref stream.
2815 - write(calculateXrefStreamPadding(endpos - pos), ' ');  
2816 - first_xref_end = m->pipeline->getCount(); 2879 + write(w.calculateXrefStreamPadding(endpos - pos), ' ');
  2880 + first_xref_end = pipeline->getCount();
2817 } else { 2881 } else {
2818 // Pad so that the next object starts at the same place as in pass 1. 2882 // Pad so that the next object starts at the same place as in pass 1.
2819 write(QIntC::to_size(first_xref_end - endpos), ' '); 2883 write(QIntC::to_size(first_xref_end - endpos), ' ');
2820 2884
2821 - if (m->pipeline->getCount() != first_xref_end) { 2885 + if (pipeline->getCount() != first_xref_end) {
2822 throw std::logic_error( 2886 throw std::logic_error(
2823 "insufficient padding for first pass xref stream; first_xref_end=" + 2887 "insufficient padding for first pass xref stream; first_xref_end=" +
2824 std::to_string(first_xref_end) + "; endpos=" + std::to_string(endpos)); 2888 std::to_string(first_xref_end) + "; endpos=" + std::to_string(endpos));
@@ -2842,24 +2906,24 @@ QPDFWriter::writeLinearized() @@ -2842,24 +2906,24 @@ QPDFWriter::writeLinearized()
2842 2906
2843 // Parts 4 through 9 2907 // Parts 4 through 9
2844 2908
2845 - for (auto const& cur_object: m->object_queue) { 2909 + for (auto const& cur_object: object_queue) {
2846 if (cur_object.getObjectID() == part6_end_marker) { 2910 if (cur_object.getObjectID() == part6_end_marker) {
2847 - first_half_max_obj_offset = m->pipeline->getCount(); 2911 + first_half_max_obj_offset = pipeline->getCount();
2848 } 2912 }
2849 writeObject(cur_object); 2913 writeObject(cur_object);
2850 if (cur_object.getObjectID() == part4_end_marker) { 2914 if (cur_object.getObjectID() == part4_end_marker) {
2851 - if (m->encryption) { 2915 + if (encryption) {
2852 writeEncryptionDictionary(); 2916 writeEncryptionDictionary();
2853 } 2917 }
2854 if (pass == 1) { 2918 if (pass == 1) {
2855 - m->new_obj[hint_id].xref = QPDFXRefEntry(m->pipeline->getCount()); 2919 + new_obj[hint_id].xref = QPDFXRefEntry(pipeline->getCount());
2856 } else { 2920 } else {
2857 // Part 5: hint stream 2921 // Part 5: hint stream
2858 write(hint_buffer); 2922 write(hint_buffer);
2859 } 2923 }
2860 } 2924 }
2861 if (cur_object.getObjectID() == part6_end_marker) { 2925 if (cur_object.getObjectID() == part6_end_marker) {
2862 - part6_end_offset = m->pipeline->getCount(); 2926 + part6_end_offset = pipeline->getCount();
2863 } 2927 }
2864 } 2928 }
2865 2929
@@ -2867,9 +2931,9 @@ QPDFWriter::writeLinearized() @@ -2867,9 +2931,9 @@ QPDFWriter::writeLinearized()
2867 2931
2868 // Part 11: main cross reference table and trailer 2932 // Part 11: main cross reference table and trailer
2869 2933
2870 - second_xref_offset = m->pipeline->getCount(); 2934 + second_xref_offset = pipeline->getCount();
2871 if (need_xref_stream) { 2935 if (need_xref_stream) {
2872 - pos = m->pipeline->getCount(); 2936 + pos = pipeline->getCount();
2873 space_before_zero = writeXRefStream( 2937 space_before_zero = writeXRefStream(
2874 second_half_xref, 2938 second_half_xref,
2875 second_half_end, 2939 second_half_end,
@@ -2884,21 +2948,21 @@ QPDFWriter::writeLinearized() @@ -2884,21 +2948,21 @@ QPDFWriter::writeLinearized()
2884 0, 2948 0,
2885 (pass == 1), 2949 (pass == 1),
2886 pass); 2950 pass);
2887 - qpdf_offset_t endpos = m->pipeline->getCount(); 2951 + qpdf_offset_t endpos = pipeline->getCount();
2888 2952
2889 if (pass == 1) { 2953 if (pass == 1) {
2890 // Pad so we have enough room for the real xref stream. See comments for previous 2954 // Pad so we have enough room for the real xref stream. See comments for previous
2891 // xref stream on how we calculate the padding. 2955 // xref stream on how we calculate the padding.
2892 - write(calculateXrefStreamPadding(endpos - pos), ' ').write("\n");  
2893 - second_xref_end = m->pipeline->getCount(); 2956 + write(w.calculateXrefStreamPadding(endpos - pos), ' ').write("\n");
  2957 + second_xref_end = pipeline->getCount();
2894 } else { 2958 } else {
2895 // Make the file size the same. 2959 // Make the file size the same.
2896 auto padding = 2960 auto padding =
2897 - QIntC::to_size(second_xref_end + hint_length - 1 - m->pipeline->getCount()); 2961 + QIntC::to_size(second_xref_end + hint_length - 1 - pipeline->getCount());
2898 write(padding, ' ').write("\n"); 2962 write(padding, ' ').write("\n");
2899 2963
2900 // If this assertion fails, maybe we didn't have enough padding above. 2964 // If this assertion fails, maybe we didn't have enough padding above.
2901 - if (m->pipeline->getCount() != second_xref_end + hint_length) { 2965 + if (pipeline->getCount() != second_xref_end + hint_length) {
2902 throw std::logic_error( 2966 throw std::logic_error(
2903 "count mismatch after xref stream; possible insufficient padding?"); 2967 "count mismatch after xref stream; possible insufficient padding?");
2904 } 2968 }
@@ -2910,28 +2974,28 @@ QPDFWriter::writeLinearized() @@ -2910,28 +2974,28 @@ QPDFWriter::writeLinearized()
2910 write("startxref\n").write(first_xref_offset).write("\n%%EOF\n"); 2974 write("startxref\n").write(first_xref_offset).write("\n%%EOF\n");
2911 2975
2912 if (pass == 1) { 2976 if (pass == 1) {
2913 - if (m->deterministic_id) { 2977 + if (deterministic_id) {
2914 QTC::TC("qpdf", "QPDFWriter linearized deterministic ID", need_xref_stream ? 0 : 1); 2978 QTC::TC("qpdf", "QPDFWriter linearized deterministic ID", need_xref_stream ? 0 : 1);
2915 - computeDeterministicIDData(); 2979 + w.computeDeterministicIDData();
2916 pp_md5.pop(); 2980 pp_md5.pop();
2917 } 2981 }
2918 2982
2919 // Close first pass pipeline 2983 // Close first pass pipeline
2920 - file_size = m->pipeline->getCount(); 2984 + file_size = pipeline->getCount();
2921 pp_pass1.pop(); 2985 pp_pass1.pop();
2922 2986
2923 // Save hint offset since it will be set to zero by calling openObject. 2987 // Save hint offset since it will be set to zero by calling openObject.
2924 - qpdf_offset_t hint_offset1 = m->new_obj[hint_id].xref.getOffset(); 2988 + qpdf_offset_t hint_offset1 = new_obj[hint_id].xref.getOffset();
2925 2989
2926 // Write hint stream to a buffer 2990 // Write hint stream to a buffer
2927 { 2991 {
2928 - auto pp_hint = m->pipeline_stack.activate(hint_buffer); 2992 + auto pp_hint = pipeline_stack.activate(hint_buffer);
2929 writeHintStream(hint_id); 2993 writeHintStream(hint_id);
2930 } 2994 }
2931 hint_length = QIntC::to_offset(hint_buffer.size()); 2995 hint_length = QIntC::to_offset(hint_buffer.size());
2932 2996
2933 // Restore hint offset 2997 // Restore hint offset
2934 - m->new_obj[hint_id].xref = QPDFXRefEntry(hint_offset1); 2998 + new_obj[hint_id].xref = QPDFXRefEntry(hint_offset1);
2935 if (lin_pass1_file) { 2999 if (lin_pass1_file) {
2936 // Write some debugging information 3000 // Write some debugging information
2937 fprintf( 3001 fprintf(
@@ -3040,53 +3104,52 @@ QPDFWriter::registerProgressReporter(std::shared_ptr&lt;ProgressReporter&gt; pr) @@ -3040,53 +3104,52 @@ QPDFWriter::registerProgressReporter(std::shared_ptr&lt;ProgressReporter&gt; pr)
3040 } 3104 }
3041 3105
3042 void 3106 void
3043 -QPDFWriter::writeStandard() 3107 +QPDFWriter::Members::writeStandard()
3044 { 3108 {
3045 - auto pp_md5 = m->pipeline_stack.popper();  
3046 - if (m->deterministic_id) {  
3047 - m->pipeline_stack.activate_md5(pp_md5); 3109 + auto pp_md5 = pipeline_stack.popper();
  3110 + if (deterministic_id) {
  3111 + pipeline_stack.activate_md5(pp_md5);
3048 } 3112 }
3049 3113
3050 // Start writing 3114 // Start writing
3051 3115
3052 writeHeader(); 3116 writeHeader();
3053 - write(m->extra_header_text); 3117 + write(extra_header_text);
3054 3118
3055 - if (m->pclm) {  
3056 - m->enqueueObjectsPCLm(); 3119 + if (pclm) {
  3120 + enqueueObjectsPCLm();
3057 } else { 3121 } else {
3058 - m->enqueueObjectsStandard(); 3122 + enqueueObjectsStandard();
3059 } 3123 }
3060 3124
3061 // Now start walking queue, outputting each object. 3125 // Now start walking queue, outputting each object.
3062 - while (m->object_queue_front < m->object_queue.size()) {  
3063 - QPDFObjectHandle cur_object = m->object_queue.at(m->object_queue_front);  
3064 - ++m->object_queue_front; 3126 + while (object_queue_front < object_queue.size()) {
  3127 + QPDFObjectHandle cur_object = object_queue.at(object_queue_front);
  3128 + ++object_queue_front;
3065 writeObject(cur_object); 3129 writeObject(cur_object);
3066 } 3130 }
3067 3131
3068 // Write out the encryption dictionary, if any 3132 // Write out the encryption dictionary, if any
3069 - if (m->encryption) { 3133 + if (encryption) {
3070 writeEncryptionDictionary(); 3134 writeEncryptionDictionary();
3071 } 3135 }
3072 3136
3073 // Now write out xref. next_objid is now the number of objects. 3137 // Now write out xref. next_objid is now the number of objects.
3074 - qpdf_offset_t xref_offset = m->pipeline->getCount();  
3075 - if (m->object_stream_to_objects.empty()) { 3138 + qpdf_offset_t xref_offset = pipeline->getCount();
  3139 + if (object_stream_to_objects.empty()) {
3076 // Write regular cross-reference table 3140 // Write regular cross-reference table
3077 - writeXRefTable(t_normal, 0, m->next_objid - 1, m->next_objid); 3141 + writeXRefTable(t_normal, 0, next_objid - 1, next_objid);
3078 } else { 3142 } else {
3079 // Write cross-reference stream. 3143 // Write cross-reference stream.
3080 - int xref_id = m->next_objid++;  
3081 - writeXRefStream(  
3082 - xref_id, xref_id, xref_offset, t_normal, 0, m->next_objid - 1, m->next_objid); 3144 + int xref_id = next_objid++;
  3145 + writeXRefStream(xref_id, xref_id, xref_offset, t_normal, 0, next_objid - 1, next_objid);
3083 } 3146 }
3084 write("startxref\n").write(xref_offset).write("\n%%EOF\n"); 3147 write("startxref\n").write(xref_offset).write("\n%%EOF\n");
3085 3148
3086 - if (m->deterministic_id) { 3149 + if (deterministic_id) {
3087 QTC::TC( 3150 QTC::TC(
3088 "qpdf", 3151 "qpdf",
3089 "QPDFWriter standard deterministic ID", 3152 "QPDFWriter standard deterministic ID",
3090 - m->object_stream_to_objects.empty() ? 0 : 1); 3153 + object_stream_to_objects.empty() ? 0 : 1);
3091 } 3154 }
3092 } 3155 }
qpdf/qpdf.testcov
@@ -198,9 +198,7 @@ QPDFWriter make Extensions direct 0 @@ -198,9 +198,7 @@ QPDFWriter make Extensions direct 0
198 QPDFWriter make ADBE direct 1 198 QPDFWriter make ADBE direct 1
199 QPDFWriter preserve Extensions 0 199 QPDFWriter preserve Extensions 0
200 QPDFWriter create Extensions 1 200 QPDFWriter create Extensions 1
201 -QPDFWriter remove ADBE 0  
202 QPDFWriter remove existing Extensions 0 201 QPDFWriter remove existing Extensions 0
203 -QPDFWriter preserve ADBE 0  
204 QPDF_encryption skip 0x28 0 202 QPDF_encryption skip 0x28 0
205 qpdf-c called qpdf_get_pdf_extension_level 0 203 qpdf-c called qpdf_get_pdf_extension_level 0
206 qpdf-c called qpdf_set_r5_encryption_parameters 0 204 qpdf-c called qpdf_set_r5_encryption_parameters 0
@@ -208,7 +206,6 @@ qpdf-c called qpdf_set_r6_encryption_parameters 0 @@ -208,7 +206,6 @@ qpdf-c called qpdf_set_r6_encryption_parameters 0
208 QPDFObjectHandle EOF in inline image 0 206 QPDFObjectHandle EOF in inline image 0
209 QPDFObjectHandle inline image token 0 207 QPDFObjectHandle inline image token 0
210 QPDF not caching overridden objstm object 0 208 QPDF not caching overridden objstm object 0
211 -QPDFWriter original obj non-zero gen 0  
212 QPDF_optimization indirect outlines 0 209 QPDF_optimization indirect outlines 0
213 QPDF xref space 2 210 QPDF xref space 2
214 QPDFJob pages range omitted in middle 0 211 QPDFJob pages range omitted in middle 0