Commit ce21a65188c99f1b305a773223267cdfaf97b782

Authored by m-holger
1 parent db2a22ea

Refactor `QPDFWriter`: move `Members` functionality into `impl::Writer`, consoli…

…date logic, and improve encapsulation.
libqpdf/QPDFWriter.cc
... ... @@ -299,6 +299,127 @@ namespace qpdf::impl
299 299 {
300 300 }
301 301  
  302 + void write();
  303 + std::map<QPDFObjGen, QPDFXRefEntry> getWrittenXRefTable();
  304 + void setMinimumPDFVersion(std::string const& version, int extension_level);
  305 + void copyEncryptionParameters(QPDF&);
  306 + void doWriteSetup();
  307 + void prepareFileForWrite();
  308 +
  309 + void disableIncompatibleEncryption(int major, int minor, int extension_level);
  310 + void interpretR3EncryptionParameters(
  311 + bool allow_accessibility,
  312 + bool allow_extract,
  313 + bool allow_assemble,
  314 + bool allow_annotate_and_form,
  315 + bool allow_form_filling,
  316 + bool allow_modify_other,
  317 + qpdf_r3_print_e print,
  318 + qpdf_r3_modify_e modify);
  319 + void setEncryptionParameters(char const* user_password, char const* owner_password);
  320 + void setEncryptionMinimumVersion();
  321 + void parseVersion(std::string const& version, int& major, int& minor) const;
  322 + int compareVersions(int major1, int minor1, int major2, int minor2) const;
  323 + void generateID(bool encrypted);
  324 + std::string getOriginalID1();
  325 + void initializeTables(size_t extra = 0);
  326 + void preserveObjectStreams();
  327 + void generateObjectStreams();
  328 + void initializeSpecialStreams();
  329 + void enqueue(QPDFObjectHandle const& object);
  330 + void enqueueObjectsStandard();
  331 + void enqueueObjectsPCLm();
  332 + void enqueuePart(std::vector<QPDFObjectHandle>& part);
  333 + void assignCompressedObjectNumbers(QPDFObjGen og);
  334 + Dictionary trimmed_trailer();
  335 +
  336 + // Returns tuple<filter, compress_stream, is_root_metadata>
  337 + std::tuple<const bool, const bool, const bool>
  338 + will_filter_stream(QPDFObjectHandle stream, std::string* stream_data);
  339 +
  340 + // Test whether stream would be filtered if it were written.
  341 + bool will_filter_stream(QPDFObjectHandle stream);
  342 + unsigned int bytesNeeded(long long n);
  343 + void writeBinary(unsigned long long val, unsigned int bytes);
  344 + Writer& write(std::string_view str);
  345 + Writer& write(size_t count, char c);
  346 + Writer& write(std::integral auto val);
  347 + Writer& write_name(std::string const& str);
  348 + Writer& write_string(std::string const& str, bool force_binary = false);
  349 + Writer& write_encrypted(std::string_view str);
  350 +
  351 + template <typename... Args>
  352 + Writer& write_qdf(Args&&... args);
  353 + template <typename... Args>
  354 + Writer& write_no_qdf(Args&&... args);
  355 + void writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offsets, int first_obj);
  356 + void writeObjectStream(QPDFObjectHandle object);
  357 + void writeObject(QPDFObjectHandle object, int object_stream_index = -1);
  358 + void writeTrailer(
  359 + trailer_e which,
  360 + int size,
  361 + bool xref_stream,
  362 + qpdf_offset_t prev,
  363 + int linearization_pass);
  364 + void unparseObject(
  365 + QPDFObjectHandle object,
  366 + size_t level,
  367 + int flags,
  368 + // for stream dictionaries
  369 + size_t stream_length = 0,
  370 + bool compress = false);
  371 + void unparseChild(QPDFObjectHandle const& child, size_t level, int flags);
  372 + int openObject(int objid = 0);
  373 + void closeObject(int objid);
  374 + void writeStandard();
  375 + void writeLinearized();
  376 + void writeEncryptionDictionary();
  377 + void writeHeader();
  378 + void writeHintStream(int hint_id);
  379 + qpdf_offset_t writeXRefTable(trailer_e which, int first, int last, int size);
  380 + qpdf_offset_t writeXRefTable(
  381 + trailer_e which,
  382 + int first,
  383 + int last,
  384 + int size,
  385 + // for linearization
  386 + qpdf_offset_t prev,
  387 + bool suppress_offsets,
  388 + int hint_id,
  389 + qpdf_offset_t hint_offset,
  390 + qpdf_offset_t hint_length,
  391 + int linearization_pass);
  392 + qpdf_offset_t writeXRefStream(
  393 + int objid,
  394 + int max_id,
  395 + qpdf_offset_t max_offset,
  396 + trailer_e which,
  397 + int first,
  398 + int last,
  399 + int size);
  400 + qpdf_offset_t writeXRefStream(
  401 + int objid,
  402 + int max_id,
  403 + qpdf_offset_t max_offset,
  404 + trailer_e which,
  405 + int first,
  406 + int last,
  407 + int size,
  408 + // for linearization
  409 + qpdf_offset_t prev,
  410 + int hint_id,
  411 + qpdf_offset_t hint_offset,
  412 + qpdf_offset_t hint_length,
  413 + bool skip_compression,
  414 + int linearization_pass);
  415 +
  416 + void setDataKey(int objid);
  417 + void indicateProgress(bool decrement, bool finished);
  418 + size_t calculateXrefStreamPadding(qpdf_offset_t xref_bytes);
  419 +
  420 + void adjustAESStreamLength(size_t& length);
  421 + void computeDeterministicIDData();
  422 +
302 423 protected:
303 424 Doc::Linearization& lin;
304 425  
... ... @@ -347,7 +468,8 @@ namespace qpdf::impl
347 468 int events_expected{0};
348 469 int events_seen{0};
349 470 int next_progress_report{0};
350   - };
  471 + }; // class qpdf::impl::Writer
  472 +
351 473 } // namespace qpdf::impl
352 474  
353 475 class QPDFWriter::Members: impl::Writer
... ... @@ -359,123 +481,6 @@ class QPDFWriter::Members: impl::Writer
359 481 impl::Writer(qpdf, w)
360 482 {
361 483 }
362   -
363   - void write();
364   - std::map<QPDFObjGen, QPDFXRefEntry> getWrittenXRefTable();
365   - void setMinimumPDFVersion(std::string const& version, int extension_level);
366   - void copyEncryptionParameters(QPDF&);
367   - void doWriteSetup();
368   - void prepareFileForWrite();
369   -
370   - void disableIncompatibleEncryption(int major, int minor, int extension_level);
371   - void interpretR3EncryptionParameters(
372   - bool allow_accessibility,
373   - bool allow_extract,
374   - bool allow_assemble,
375   - bool allow_annotate_and_form,
376   - bool allow_form_filling,
377   - bool allow_modify_other,
378   - qpdf_r3_print_e print,
379   - qpdf_r3_modify_e modify);
380   - void setEncryptionParameters(char const* user_password, char const* owner_password);
381   - void setEncryptionMinimumVersion();
382   - void parseVersion(std::string const& version, int& major, int& minor) const;
383   - int compareVersions(int major1, int minor1, int major2, int minor2) const;
384   - void generateID(bool encrypted);
385   - std::string getOriginalID1();
386   - void initializeTables(size_t extra = 0);
387   - void preserveObjectStreams();
388   - void generateObjectStreams();
389   - void initializeSpecialStreams();
390   - void enqueue(QPDFObjectHandle const& object);
391   - void enqueueObjectsStandard();
392   - void enqueueObjectsPCLm();
393   - void enqueuePart(std::vector<QPDFObjectHandle>& part);
394   - void assignCompressedObjectNumbers(QPDFObjGen og);
395   - Dictionary trimmed_trailer();
396   -
397   - // Returns tuple<filter, compress_stream, is_root_metadata>
398   - std::tuple<const bool, const bool, const bool>
399   - will_filter_stream(QPDFObjectHandle stream, std::string* stream_data);
400   -
401   - // Test whether stream would be filtered if it were written.
402   - bool will_filter_stream(QPDFObjectHandle stream);
403   - unsigned int bytesNeeded(long long n);
404   - void writeBinary(unsigned long long val, unsigned int bytes);
405   - Members& write(std::string_view str);
406   - Members& write(size_t count, char c);
407   - Members& write(std::integral auto val);
408   - Members& write_name(std::string const& str);
409   - Members& write_string(std::string const& str, bool force_binary = false);
410   - Members& write_encrypted(std::string_view str);
411   -
412   - template <typename... Args>
413   - Members& write_qdf(Args&&... args);
414   - template <typename... Args>
415   - Members& write_no_qdf(Args&&... args);
416   - void writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offsets, int first_obj);
417   - void writeObjectStream(QPDFObjectHandle object);
418   - void writeObject(QPDFObjectHandle object, int object_stream_index = -1);
419   - void writeTrailer(
420   - trailer_e which, int size, bool xref_stream, qpdf_offset_t prev, int linearization_pass);
421   - void unparseObject(
422   - QPDFObjectHandle object,
423   - size_t level,
424   - int flags,
425   - // for stream dictionaries
426   - size_t stream_length = 0,
427   - bool compress = false);
428   - void unparseChild(QPDFObjectHandle const& child, size_t level, int flags);
429   - int openObject(int objid = 0);
430   - void closeObject(int objid);
431   - void writeStandard();
432   - void writeLinearized();
433   - void writeEncryptionDictionary();
434   - void writeHeader();
435   - void writeHintStream(int hint_id);
436   - qpdf_offset_t writeXRefTable(trailer_e which, int first, int last, int size);
437   - qpdf_offset_t writeXRefTable(
438   - trailer_e which,
439   - int first,
440   - int last,
441   - int size,
442   - // for linearization
443   - qpdf_offset_t prev,
444   - bool suppress_offsets,
445   - int hint_id,
446   - qpdf_offset_t hint_offset,
447   - qpdf_offset_t hint_length,
448   - int linearization_pass);
449   - qpdf_offset_t writeXRefStream(
450   - int objid,
451   - int max_id,
452   - qpdf_offset_t max_offset,
453   - trailer_e which,
454   - int first,
455   - int last,
456   - int size);
457   - qpdf_offset_t writeXRefStream(
458   - int objid,
459   - int max_id,
460   - qpdf_offset_t max_offset,
461   - trailer_e which,
462   - int first,
463   - int last,
464   - int size,
465   - // for linearization
466   - qpdf_offset_t prev,
467   - int hint_id,
468   - qpdf_offset_t hint_offset,
469   - qpdf_offset_t hint_length,
470   - bool skip_compression,
471   - int linearization_pass);
472   -
473   - void setDataKey(int objid);
474   - void indicateProgress(bool decrement, bool finished);
475   - size_t calculateXrefStreamPadding(qpdf_offset_t xref_bytes);
476   -
477   - void adjustAESStreamLength(size_t& length);
478   - void computeDeterministicIDData();
479 484 };
480 485  
481 486 QPDFWriter::QPDFWriter(QPDF& pdf) :
... ... @@ -632,7 +637,7 @@ QPDFWriter::setMinimumPDFVersion(std::string const&amp; version, int extension_level
632 637 }
633 638  
634 639 void
635   -QPDFWriter::Members::setMinimumPDFVersion(std::string const& version, int extension_level)
  640 +impl::Writer::setMinimumPDFVersion(std::string const& version, int extension_level)
636 641 {
637 642 bool set_version = false;
638 643 bool set_extension_level = false;
... ... @@ -882,7 +887,7 @@ QPDFWriter::setR6EncryptionParameters(
882 887 }
883 888  
884 889 void
885   -QPDFWriter::Members::interpretR3EncryptionParameters(
  890 +impl::Writer::interpretR3EncryptionParameters(
886 891 bool allow_accessibility,
887 892 bool allow_extract,
888 893 bool allow_assemble,
... ... @@ -981,7 +986,7 @@ QPDFWriter::Members::interpretR3EncryptionParameters(
981 986 }
982 987  
983 988 void
984   -QPDFWriter::Members::setEncryptionParameters(char const* user_password, char const* owner_password)
  989 +impl::Writer::setEncryptionParameters(char const* user_password, char const* owner_password)
985 990 {
986 991 generateID(true);
987 992 encryption->setId1(id1);
... ... @@ -996,7 +1001,7 @@ QPDFWriter::copyEncryptionParameters(QPDF&amp; qpdf)
996 1001 }
997 1002  
998 1003 void
999   -QPDFWriter::Members::copyEncryptionParameters(QPDF& qpdf)
  1004 +impl::Writer::copyEncryptionParameters(QPDF& qpdf)
1000 1005 {
1001 1006 cfg.preserve_encryption_ = false;
1002 1007 QPDFObjectHandle trailer = qpdf.getTrailer();
... ... @@ -1042,7 +1047,7 @@ QPDFWriter::Members::copyEncryptionParameters(QPDF&amp; qpdf)
1042 1047 }
1043 1048  
1044 1049 void
1045   -QPDFWriter::Members::disableIncompatibleEncryption(int major, int minor, int extension_level)
  1050 +impl::Writer::disableIncompatibleEncryption(int major, int minor, int extension_level)
1046 1051 {
1047 1052 if (!encryption) {
1048 1053 return;
... ... @@ -1079,7 +1084,7 @@ QPDFWriter::Members::disableIncompatibleEncryption(int major, int minor, int ext
1079 1084 }
1080 1085  
1081 1086 void
1082   -QPDFWriter::Members::parseVersion(std::string const& version, int& major, int& minor) const
  1087 +impl::Writer::parseVersion(std::string const& version, int& major, int& minor) const
1083 1088 {
1084 1089 major = QUtil::string_to_int(version.c_str());
1085 1090 minor = 0;
... ... @@ -1096,7 +1101,7 @@ QPDFWriter::Members::parseVersion(std::string const&amp; version, int&amp; major, int&amp; m
1096 1101 }
1097 1102  
1098 1103 int
1099   -QPDFWriter::Members::compareVersions(int major1, int minor1, int major2, int minor2) const
  1104 +impl::Writer::compareVersions(int major1, int minor1, int major2, int minor2) const
1100 1105 {
1101 1106 if (major1 < major2) {
1102 1107 return -1;
... ... @@ -1111,7 +1116,7 @@ QPDFWriter::Members::compareVersions(int major1, int minor1, int major2, int min
1111 1116 }
1112 1117  
1113 1118 void
1114   -QPDFWriter::Members::setEncryptionMinimumVersion()
  1119 +impl::Writer::setEncryptionMinimumVersion()
1115 1120 {
1116 1121 auto const R = encryption->getR();
1117 1122 if (R >= 6) {
... ... @@ -1128,7 +1133,7 @@ QPDFWriter::Members::setEncryptionMinimumVersion()
1128 1133 }
1129 1134  
1130 1135 void
1131   -QPDFWriter::Members::setDataKey(int objid)
  1136 +impl::Writer::setDataKey(int objid)
1132 1137 {
1133 1138 if (encryption) {
1134 1139 cur_data_key = QPDF::compute_data_key(
... ... @@ -1137,7 +1142,7 @@ QPDFWriter::Members::setDataKey(int objid)
1137 1142 }
1138 1143  
1139 1144 unsigned int
1140   -QPDFWriter::Members::bytesNeeded(long long n)
  1145 +impl::Writer::bytesNeeded(long long n)
1141 1146 {
1142 1147 unsigned int bytes = 0;
1143 1148 while (n) {
... ... @@ -1148,7 +1153,7 @@ QPDFWriter::Members::bytesNeeded(long long n)
1148 1153 }
1149 1154  
1150 1155 void
1151   -QPDFWriter::Members::writeBinary(unsigned long long val, unsigned int bytes)
  1156 +impl::Writer::writeBinary(unsigned long long val, unsigned int bytes)
1152 1157 {
1153 1158 if (bytes > sizeof(unsigned long long)) {
1154 1159 throw std::logic_error("QPDFWriter::writeBinary called with too many bytes");
... ... @@ -1161,44 +1166,44 @@ QPDFWriter::Members::writeBinary(unsigned long long val, unsigned int bytes)
1161 1166 pipeline->write(data, bytes);
1162 1167 }
1163 1168  
1164   -QPDFWriter::Members&
1165   -QPDFWriter::Members::write(std::string_view str)
  1169 +impl::Writer&
  1170 +impl::Writer::write(std::string_view str)
1166 1171 {
1167 1172 pipeline->write(str);
1168 1173 return *this;
1169 1174 }
1170 1175  
1171   -QPDFWriter::Members&
1172   -QPDFWriter::Members::write(std::integral auto val)
  1176 +impl::Writer&
  1177 +impl::Writer::write(std::integral auto val)
1173 1178 {
1174 1179 pipeline->write(std::to_string(val));
1175 1180 return *this;
1176 1181 }
1177 1182  
1178   -QPDFWriter::Members&
1179   -QPDFWriter::Members::write(size_t count, char c)
  1183 +impl::Writer&
  1184 +impl::Writer::write(size_t count, char c)
1180 1185 {
1181 1186 pipeline->write(count, c);
1182 1187 return *this;
1183 1188 }
1184 1189  
1185   -QPDFWriter::Members&
1186   -QPDFWriter::Members::write_name(std::string const& str)
  1190 +impl::Writer&
  1191 +impl::Writer::write_name(std::string const& str)
1187 1192 {
1188 1193 pipeline->write(Name::normalize(str));
1189 1194 return *this;
1190 1195 }
1191 1196  
1192   -QPDFWriter::Members&
1193   -QPDFWriter::Members::write_string(std::string const& str, bool force_binary)
  1197 +impl::Writer&
  1198 +impl::Writer::write_string(std::string const& str, bool force_binary)
1194 1199 {
1195 1200 pipeline->write(QPDF_String(str).unparse(force_binary));
1196 1201 return *this;
1197 1202 }
1198 1203  
1199 1204 template <typename... Args>
1200   -QPDFWriter::Members&
1201   -QPDFWriter::Members::write_qdf(Args&&... args)
  1205 +impl::Writer&
  1206 +impl::Writer::write_qdf(Args&&... args)
1202 1207 {
1203 1208 if (cfg.qdf_mode_) {
1204 1209 pipeline->write(std::forward<Args>(args)...);
... ... @@ -1207,8 +1212,8 @@ QPDFWriter::Members::write_qdf(Args&amp;&amp;... args)
1207 1212 }
1208 1213  
1209 1214 template <typename... Args>
1210   -QPDFWriter::Members&
1211   -QPDFWriter::Members::write_no_qdf(Args&&... args)
  1215 +impl::Writer&
  1216 +impl::Writer::write_no_qdf(Args&&... args)
1212 1217 {
1213 1218 if (!cfg.qdf_mode_) {
1214 1219 pipeline->write(std::forward<Args>(args)...);
... ... @@ -1217,7 +1222,7 @@ QPDFWriter::Members::write_no_qdf(Args&amp;&amp;... args)
1217 1222 }
1218 1223  
1219 1224 void
1220   -QPDFWriter::Members::adjustAESStreamLength(size_t& length)
  1225 +impl::Writer::adjustAESStreamLength(size_t& length)
1221 1226 {
1222 1227 if (encryption && !cur_data_key.empty() && cfg.encrypt_use_aes_) {
1223 1228 // Stream length will be padded with 1 to 16 bytes to end up as a multiple of 16. It will
... ... @@ -1226,8 +1231,8 @@ QPDFWriter::Members::adjustAESStreamLength(size_t&amp; length)
1226 1231 }
1227 1232 }
1228 1233  
1229   -QPDFWriter::Members&
1230   -QPDFWriter::Members::write_encrypted(std::string_view str)
  1234 +impl::Writer&
  1235 +impl::Writer::write_encrypted(std::string_view str)
1231 1236 {
1232 1237 if (!(encryption && !cur_data_key.empty())) {
1233 1238 write(str);
... ... @@ -1241,7 +1246,7 @@ QPDFWriter::Members::write_encrypted(std::string_view str)
1241 1246 }
1242 1247  
1243 1248 void
1244   -QPDFWriter::Members::computeDeterministicIDData()
  1249 +impl::Writer::computeDeterministicIDData()
1245 1250 {
1246 1251 if (!id2.empty()) {
1247 1252 // Can't happen in the code
... ... @@ -1253,7 +1258,7 @@ QPDFWriter::Members::computeDeterministicIDData()
1253 1258 }
1254 1259  
1255 1260 int
1256   -QPDFWriter::Members::openObject(int objid)
  1261 +impl::Writer::openObject(int objid)
1257 1262 {
1258 1263 if (objid == 0) {
1259 1264 objid = next_objid++;
... ... @@ -1264,7 +1269,7 @@ QPDFWriter::Members::openObject(int objid)
1264 1269 }
1265 1270  
1266 1271 void
1267   -QPDFWriter::Members::closeObject(int objid)
  1272 +impl::Writer::closeObject(int objid)
1268 1273 {
1269 1274 // Write a newline before endobj as it makes the file easier to repair.
1270 1275 write("\nendobj\n").write_qdf("\n");
... ... @@ -1273,7 +1278,7 @@ QPDFWriter::Members::closeObject(int objid)
1273 1278 }
1274 1279  
1275 1280 void
1276   -QPDFWriter::Members::assignCompressedObjectNumbers(QPDFObjGen og)
  1281 +impl::Writer::assignCompressedObjectNumbers(QPDFObjGen og)
1277 1282 {
1278 1283 int objid = og.getObj();
1279 1284 if (og.getGen() != 0 || !object_stream_to_objects.contains(objid)) {
... ... @@ -1288,7 +1293,7 @@ QPDFWriter::Members::assignCompressedObjectNumbers(QPDFObjGen og)
1288 1293 }
1289 1294  
1290 1295 void
1291   -QPDFWriter::Members::enqueue(QPDFObjectHandle const& object)
  1296 +impl::Writer::enqueue(QPDFObjectHandle const& object)
1292 1297 {
1293 1298 if (object.indirect()) {
1294 1299 util::assertion(
... ... @@ -1359,7 +1364,7 @@ QPDFWriter::Members::enqueue(QPDFObjectHandle const&amp; object)
1359 1364 }
1360 1365  
1361 1366 void
1362   -QPDFWriter::Members::unparseChild(QPDFObjectHandle const& child, size_t level, int flags)
  1367 +impl::Writer::unparseChild(QPDFObjectHandle const& child, size_t level, int flags)
1363 1368 {
1364 1369 if (!cfg.linearized_) {
1365 1370 enqueue(child);
... ... @@ -1372,7 +1377,7 @@ QPDFWriter::Members::unparseChild(QPDFObjectHandle const&amp; child, size_t level, i
1372 1377 }
1373 1378  
1374 1379 void
1375   -QPDFWriter::Members::writeTrailer(
  1380 +impl::Writer::writeTrailer(
1376 1381 trailer_e which, int size, bool xref_stream, qpdf_offset_t prev, int linearization_pass)
1377 1382 {
1378 1383 auto trailer = trimmed_trailer();
... ... @@ -1439,7 +1444,7 @@ QPDFWriter::Members::writeTrailer(
1439 1444 }
1440 1445  
1441 1446 bool
1442   -QPDFWriter::Members::will_filter_stream(QPDFObjectHandle stream)
  1447 +impl::Writer::will_filter_stream(QPDFObjectHandle stream)
1443 1448 {
1444 1449 std::string s;
1445 1450 [[maybe_unused]] auto [filter, ignore1, ignore2] = will_filter_stream(stream, &s);
... ... @@ -1447,7 +1452,7 @@ QPDFWriter::Members::will_filter_stream(QPDFObjectHandle stream)
1447 1452 }
1448 1453  
1449 1454 std::tuple<const bool, const bool, const bool>
1450   -QPDFWriter::Members::will_filter_stream(QPDFObjectHandle stream, std::string* stream_data)
  1455 +impl::Writer::will_filter_stream(QPDFObjectHandle stream, std::string* stream_data)
1451 1456 {
1452 1457 const bool is_root_metadata = stream.isRootMetadata();
1453 1458 bool filter = false;
... ... @@ -1520,7 +1525,7 @@ QPDFWriter::Members::will_filter_stream(QPDFObjectHandle stream, std::string* st
1520 1525 }
1521 1526  
1522 1527 void
1523   -QPDFWriter::Members::unparseObject(
  1528 +impl::Writer::unparseObject(
1524 1529 QPDFObjectHandle object, size_t level, int flags, size_t stream_length, bool compress)
1525 1530 {
1526 1531 QPDFObjGen old_og = object.getObjGen();
... ... @@ -1763,7 +1768,7 @@ QPDFWriter::Members::unparseObject(
1763 1768 }
1764 1769  
1765 1770 void
1766   -QPDFWriter::Members::writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offsets, int first_obj)
  1771 +impl::Writer::writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offsets, int first_obj)
1767 1772 {
1768 1773 qpdf_assert_debug(first_obj > 0);
1769 1774 bool is_first = true;
... ... @@ -1782,7 +1787,7 @@ QPDFWriter::Members::writeObjectStreamOffsets(std::vector&lt;qpdf_offset_t&gt;&amp; offset
1782 1787 }
1783 1788  
1784 1789 void
1785   -QPDFWriter::Members::writeObjectStream(QPDFObjectHandle object)
  1790 +impl::Writer::writeObjectStream(QPDFObjectHandle object)
1786 1791 {
1787 1792 // Note: object might be null if this is a place-holder for an object stream that we are
1788 1793 // generating from scratch.
... ... @@ -1899,7 +1904,7 @@ QPDFWriter::Members::writeObjectStream(QPDFObjectHandle object)
1899 1904 }
1900 1905  
1901 1906 void
1902   -QPDFWriter::Members::writeObject(QPDFObjectHandle object, int object_stream_index)
  1907 +impl::Writer::writeObject(QPDFObjectHandle object, int object_stream_index)
1903 1908 {
1904 1909 QPDFObjGen old_og = object.getObjGen();
1905 1910  
... ... @@ -1946,7 +1951,7 @@ QPDFWriter::Members::writeObject(QPDFObjectHandle object, int object_stream_inde
1946 1951 }
1947 1952  
1948 1953 std::string
1949   -QPDFWriter::Members::getOriginalID1()
  1954 +impl::Writer::getOriginalID1()
1950 1955 {
1951 1956 QPDFObjectHandle trailer = qpdf.getTrailer();
1952 1957 if (trailer.hasKey("/ID")) {
... ... @@ -1957,7 +1962,7 @@ QPDFWriter::Members::getOriginalID1()
1957 1962 }
1958 1963  
1959 1964 void
1960   -QPDFWriter::Members::generateID(bool encrypted)
  1965 +impl::Writer::generateID(bool encrypted)
1961 1966 {
1962 1967 // Generate the ID lazily so that we can handle the user's preference to use static or
1963 1968 // deterministic ID generation.
... ... @@ -2047,7 +2052,7 @@ QPDFWriter::Members::generateID(bool encrypted)
2047 2052 }
2048 2053  
2049 2054 void
2050   -QPDFWriter::Members::initializeSpecialStreams()
  2055 +impl::Writer::initializeSpecialStreams()
2051 2056 {
2052 2057 // Mark all page content streams in case we are filtering or normalizing.
2053 2058 int num = 0;
... ... @@ -2072,7 +2077,7 @@ QPDFWriter::Members::initializeSpecialStreams()
2072 2077 }
2073 2078  
2074 2079 void
2075   -QPDFWriter::Members::preserveObjectStreams()
  2080 +impl::Writer::preserveObjectStreams()
2076 2081 {
2077 2082 auto const& xref = objects.xref_table();
2078 2083 // Our object_to_object_stream map has to map ObjGen -> ObjGen since we may be generating object
... ... @@ -2120,7 +2125,7 @@ QPDFWriter::Members::preserveObjectStreams()
2120 2125 }
2121 2126  
2122 2127 void
2123   -QPDFWriter::Members::generateObjectStreams()
  2128 +impl::Writer::generateObjectStreams()
2124 2129 {
2125 2130 // Basic strategy: make a list of objects that can go into an object stream. Then figure out
2126 2131 // how many object streams are needed so that we can distribute objects approximately evenly
... ... @@ -2159,7 +2164,7 @@ QPDFWriter::Members::generateObjectStreams()
2159 2164 }
2160 2165  
2161 2166 Dictionary
2162   -QPDFWriter::Members::trimmed_trailer()
  2167 +impl::Writer::trimmed_trailer()
2163 2168 {
2164 2169 // Remove keys from the trailer that necessarily have to be replaced when writing the file.
2165 2170  
... ... @@ -2186,7 +2191,7 @@ QPDFWriter::Members::trimmed_trailer()
2186 2191  
2187 2192 // Make document extension level information direct as required by the spec.
2188 2193 void
2189   -QPDFWriter::Members::prepareFileForWrite()
  2194 +impl::Writer::prepareFileForWrite()
2190 2195 {
2191 2196 qpdf.fixDanglingReferences();
2192 2197 auto root = qpdf.getRoot();
... ... @@ -2209,7 +2214,7 @@ QPDFWriter::Members::prepareFileForWrite()
2209 2214 }
2210 2215  
2211 2216 void
2212   -QPDFWriter::Members::initializeTables(size_t extra)
  2217 +impl::Writer::initializeTables(size_t extra)
2213 2218 {
2214 2219 auto size = objects.table_size() + 100u + extra;
2215 2220 obj.resize(size);
... ... @@ -2217,7 +2222,7 @@ QPDFWriter::Members::initializeTables(size_t extra)
2217 2222 }
2218 2223  
2219 2224 void
2220   -QPDFWriter::Members::doWriteSetup()
  2225 +impl::Writer::doWriteSetup()
2221 2226 {
2222 2227 if (did_write_setup) {
2223 2228 return;
... ... @@ -2355,7 +2360,7 @@ QPDFWriter::write()
2355 2360 }
2356 2361  
2357 2362 void
2358   -QPDFWriter::Members::write()
  2363 +impl::Writer::write()
2359 2364 {
2360 2365 doWriteSetup();
2361 2366  
... ... @@ -2396,7 +2401,7 @@ QPDFWriter::getWrittenXRefTable()
2396 2401 }
2397 2402  
2398 2403 std::map<QPDFObjGen, QPDFXRefEntry>
2399   -QPDFWriter::Members::getWrittenXRefTable()
  2404 +impl::Writer::getWrittenXRefTable()
2400 2405 {
2401 2406 std::map<QPDFObjGen, QPDFXRefEntry> result;
2402 2407  
... ... @@ -2410,7 +2415,7 @@ QPDFWriter::Members::getWrittenXRefTable()
2410 2415 }
2411 2416  
2412 2417 void
2413   -QPDFWriter::Members::enqueuePart(std::vector<QPDFObjectHandle>& part)
  2418 +impl::Writer::enqueuePart(std::vector<QPDFObjectHandle>& part)
2414 2419 {
2415 2420 for (auto const& oh: part) {
2416 2421 enqueue(oh);
... ... @@ -2418,7 +2423,7 @@ QPDFWriter::Members::enqueuePart(std::vector&lt;QPDFObjectHandle&gt;&amp; part)
2418 2423 }
2419 2424  
2420 2425 void
2421   -QPDFWriter::Members::writeEncryptionDictionary()
  2426 +impl::Writer::writeEncryptionDictionary()
2422 2427 {
2423 2428 encryption_dict_objid = openObject(encryption_dict_objid);
2424 2429 auto& enc = *encryption;
... ... @@ -2465,7 +2470,7 @@ QPDFWriter::getFinalVersion()
2465 2470 }
2466 2471  
2467 2472 void
2468   -QPDFWriter::Members::writeHeader()
  2473 +impl::Writer::writeHeader()
2469 2474 {
2470 2475 write("%PDF-").write(final_pdf_version);
2471 2476 if (cfg.pclm_) {
... ... @@ -2485,7 +2490,7 @@ QPDFWriter::Members::writeHeader()
2485 2490 }
2486 2491  
2487 2492 void
2488   -QPDFWriter::Members::writeHintStream(int hint_id)
  2493 +impl::Writer::writeHintStream(int hint_id)
2489 2494 {
2490 2495 std::string hint_buffer;
2491 2496 int S = 0;
... ... @@ -2519,7 +2524,7 @@ QPDFWriter::Members::writeHintStream(int hint_id)
2519 2524 }
2520 2525  
2521 2526 qpdf_offset_t
2522   -QPDFWriter::Members::writeXRefTable(trailer_e which, int first, int last, int size)
  2527 +impl::Writer::writeXRefTable(trailer_e which, int first, int last, int size)
2523 2528 {
2524 2529 // There are too many extra arguments to replace overloaded function with defaults in the header
2525 2530 // file...too much risk of leaving something off.
... ... @@ -2527,7 +2532,7 @@ QPDFWriter::Members::writeXRefTable(trailer_e which, int first, int last, int si
2527 2532 }
2528 2533  
2529 2534 qpdf_offset_t
2530   -QPDFWriter::Members::writeXRefTable(
  2535 +impl::Writer::writeXRefTable(
2531 2536 trailer_e which,
2532 2537 int first,
2533 2538 int last,
... ... @@ -2562,7 +2567,7 @@ QPDFWriter::Members::writeXRefTable(
2562 2567 }
2563 2568  
2564 2569 qpdf_offset_t
2565   -QPDFWriter::Members::writeXRefStream(
  2570 +impl::Writer::writeXRefStream(
2566 2571 int objid, int max_id, qpdf_offset_t max_offset, trailer_e which, int first, int last, int size)
2567 2572 {
2568 2573 // There are too many extra arguments to replace overloaded function with defaults in the header
... ... @@ -2572,7 +2577,7 @@ QPDFWriter::Members::writeXRefStream(
2572 2577 }
2573 2578  
2574 2579 qpdf_offset_t
2575   -QPDFWriter::Members::writeXRefStream(
  2580 +impl::Writer::writeXRefStream(
2576 2581 int xref_id,
2577 2582 int max_id,
2578 2583 qpdf_offset_t max_offset,
... ... @@ -2668,7 +2673,7 @@ QPDFWriter::Members::writeXRefStream(
2668 2673 }
2669 2674  
2670 2675 size_t
2671   -QPDFWriter::Members::calculateXrefStreamPadding(qpdf_offset_t xref_bytes)
  2676 +impl::Writer::calculateXrefStreamPadding(qpdf_offset_t xref_bytes)
2672 2677 {
2673 2678 // This routine is called right after a linearization first pass xref stream has been written
2674 2679 // without compression. Calculate the amount of padding that would be required in the worst
... ... @@ -2680,7 +2685,7 @@ QPDFWriter::Members::calculateXrefStreamPadding(qpdf_offset_t xref_bytes)
2680 2685 }
2681 2686  
2682 2687 void
2683   -QPDFWriter::Members::writeLinearized()
  2688 +impl::Writer::writeLinearized()
2684 2689 {
2685 2690 // Optimize file and enqueue objects in order
2686 2691  
... ... @@ -3027,7 +3032,7 @@ QPDFWriter::Members::writeLinearized()
3027 3032 }
3028 3033  
3029 3034 void
3030   -QPDFWriter::Members::enqueueObjectsStandard()
  3035 +impl::Writer::enqueueObjectsStandard()
3031 3036 {
3032 3037 if (cfg.preserve_unreferenced_objects_) {
3033 3038 for (auto const& oh: qpdf.getAllObjects()) {
... ... @@ -3049,7 +3054,7 @@ QPDFWriter::Members::enqueueObjectsStandard()
3049 3054 }
3050 3055  
3051 3056 void
3052   -QPDFWriter::Members::enqueueObjectsPCLm()
  3057 +impl::Writer::enqueueObjectsPCLm()
3053 3058 {
3054 3059 // Image transform stream content for page strip images. Each of this new stream has to come
3055 3060 // after every page image strip written in the pclm file.
... ... @@ -3073,7 +3078,7 @@ QPDFWriter::Members::enqueueObjectsPCLm()
3073 3078 }
3074 3079  
3075 3080 void
3076   -QPDFWriter::Members::indicateProgress(bool decrement, bool finished)
  3081 +impl::Writer::indicateProgress(bool decrement, bool finished)
3077 3082 {
3078 3083 if (decrement) {
3079 3084 --events_seen;
... ... @@ -3107,7 +3112,7 @@ QPDFWriter::registerProgressReporter(std::shared_ptr&lt;ProgressReporter&gt; pr)
3107 3112 }
3108 3113  
3109 3114 void
3110   -QPDFWriter::Members::writeStandard()
  3115 +impl::Writer::writeStandard()
3111 3116 {
3112 3117 auto pp_md5 = pipeline_stack.popper();
3113 3118 if (cfg.deterministic_id_) {
... ...
libqpdf/qpdf/ObjTable.hh
... ... @@ -75,7 +75,6 @@ class ObjTable: public std::vector&lt;T&gt;
75 75 return contains(static_cast<size_t>(oh.getObjectID()));
76 76 }
77 77  
78   - protected:
79 78 inline T&
80 79 operator[](int id)
81 80 {
... ...
libqpdf/qpdf/QPDFObject_private.hh
... ... @@ -30,6 +30,11 @@ namespace qpdf
30 30 class Integer;
31 31 class Name;
32 32 class Stream;
  33 +
  34 + namespace impl
  35 + {
  36 + class Writer;
  37 + }
33 38 } // namespace qpdf
34 39  
35 40 class QPDF_Array final
... ... @@ -256,7 +261,7 @@ class QPDF_String final
256 261 {
257 262 friend class QPDFObject;
258 263 friend class qpdf::BaseHandle;
259   - friend class QPDFWriter;
  264 + friend class qpdf::impl::Writer;
260 265  
261 266 public:
262 267 static std::shared_ptr<QPDFObject> create_utf16(std::string const& utf8_val);
... ...
libqpdf/qpdf/QPDFWriter_private.hh
... ... @@ -10,40 +10,6 @@
10 10 // This file is intended for inclusion by QPDFWriter, QPDF, QPDF_optimization and QPDF_linearization
11 11 // only.
12 12  
13   -struct QPDFWriter::Object
14   -{
15   - int renumber{0};
16   - int gen{0};
17   - int object_stream{0};
18   -};
19   -
20   -struct QPDFWriter::NewObject
21   -{
22   - QPDFXRefEntry xref;
23   - qpdf_offset_t length{0};
24   -};
25   -
26   -class QPDFWriter::ObjTable: public ::ObjTable<QPDFWriter::Object>
27   -{
28   - friend class QPDFWriter;
29   -
30   - public:
31   - bool
32   - getStreamsEmpty() const noexcept
33   - {
34   - return streams_empty;
35   - }
36   -
37   - private:
38   - // For performance, set by QPDFWriter rather than tracked by ObjTable.
39   - bool streams_empty{false};
40   -};
41   -
42   -class QPDFWriter::NewObjTable: public ::ObjTable<QPDFWriter::NewObject>
43   -{
44   - friend class QPDFWriter;
45   -};
46   -
47 13 namespace qpdf
48 14 {
49 15 namespace impl
... ... @@ -90,4 +56,38 @@ namespace qpdf
90 56 }; // class Writer
91 57 } // namespace qpdf
92 58  
  59 +struct QPDFWriter::Object
  60 +{
  61 + int renumber{0};
  62 + int gen{0};
  63 + int object_stream{0};
  64 +};
  65 +
  66 +struct QPDFWriter::NewObject
  67 +{
  68 + QPDFXRefEntry xref;
  69 + qpdf_offset_t length{0};
  70 +};
  71 +
  72 +class QPDFWriter::ObjTable: public ::ObjTable<QPDFWriter::Object>
  73 +{
  74 + friend class qpdf::impl::Writer;
  75 +
  76 + public:
  77 + bool
  78 + getStreamsEmpty() const noexcept
  79 + {
  80 + return streams_empty;
  81 + }
  82 +
  83 + private:
  84 + // For performance, set by QPDFWriter rather than tracked by ObjTable.
  85 + bool streams_empty{false};
  86 +};
  87 +
  88 +class QPDFWriter::NewObjTable: public ::ObjTable<QPDFWriter::NewObject>
  89 +{
  90 + friend class QPDFWriter;
  91 +};
  92 +
93 93 #endif // QPDFWRITER_PRIVATE_HH
... ...