Commit fbcbb781d79a98dfc74df7fc10693ee00606e953

Authored by m-holger
1 parent dbd437e2

Refactor ADBE handling logic in QPDFWriter.

Reorganized and cleaned up the logic for managing ADBE entries in the /Extensions dictionary, improving clarity and maintainability. Adjusted object shallow copying to avoid unnecessary copying.
Showing 1 changed file with 81 additions and 83 deletions
libqpdf/QPDFWriter.cc
@@ -1375,93 +1375,84 @@ QPDFWriter::unparseObject( @@ -1375,93 +1375,84 @@ QPDFWriter::unparseObject(
1375 writeString(indent); 1375 writeString(indent);
1376 writeString("]"); 1376 writeString("]");
1377 } else if (tc == ::ot_dictionary) { 1377 } else if (tc == ::ot_dictionary) {
1378 - // Make a shallow copy of this object so we can modify it safely without affecting the  
1379 - // original. This code has logic to skip certain keys in agreement with prepareFileForWrite  
1380 - // and with skip_stream_parameters so that replacing them doesn't leave unreferenced objects  
1381 - // in the output. We can use unsafeShallowCopy here because all we are doing is removing or  
1382 - // replacing top-level keys.  
1383 - object = object.unsafeShallowCopy();  
1384 -  
1385 // Handle special cases for specific dictionaries. 1378 // Handle special cases for specific dictionaries.
1386 1379
1387 - // Extensions dictionaries.  
1388 -  
1389 - // We have one of several cases:  
1390 - //  
1391 - // * We need ADBE  
1392 - // - We already have Extensions  
1393 - // - If it has the right ADBE, preserve it  
1394 - // - Otherwise, replace ADBE  
1395 - // - We don't have Extensions: create one from scratch  
1396 - // * We don't want ADBE  
1397 - // - We already have Extensions  
1398 - // - If it only has ADBE, remove it  
1399 - // - If it has other things, keep those and remove ADBE  
1400 - // - We have no extensions: no action required  
1401 - //  
1402 - // Before writing, we guarantee that /Extensions, if present, is direct through the ADBE  
1403 - // dictionary, so we can modify in place.  
1404 -  
1405 - const bool is_root = (old_og == m->root_og);  
1406 - bool have_extensions_other = false;  
1407 - bool have_extensions_adbe = false;  
1408 -  
1409 - QPDFObjectHandle extensions;  
1410 - if (is_root) {  
1411 - if (object.hasKey("/Extensions") && object.getKey("/Extensions").isDictionary()) {  
1412 - extensions = object.getKey("/Extensions");  
1413 - }  
1414 - }  
1415 -  
1416 - if (extensions) {  
1417 - std::set<std::string> keys = extensions.getKeys();  
1418 - if (keys.contains("/ADBE")) {  
1419 - have_extensions_adbe = true;  
1420 - keys.erase("/ADBE");  
1421 - }  
1422 - if (!keys.empty()) {  
1423 - have_extensions_other = true;  
1424 - }  
1425 - } 1380 + if (old_og == m->root_og) {
  1381 + // Extensions dictionaries.
  1382 +
  1383 + // We have one of several cases:
  1384 + //
  1385 + // * We need ADBE
  1386 + // - We already have Extensions
  1387 + // - If it has the right ADBE, preserve it
  1388 + // - Otherwise, replace ADBE
  1389 + // - We don't have Extensions: create one from scratch
  1390 + // * We don't want ADBE
  1391 + // - We already have Extensions
  1392 + // - If it only has ADBE, remove it
  1393 + // - If it has other things, keep those and remove ADBE
  1394 + // - We have no extensions: no action required
  1395 + //
  1396 + // Before writing, we guarantee that /Extensions, if present, is direct through the ADBE
  1397 + // dictionary, so we can modify in place.
  1398 +
  1399 + auto extensions = object.getKey("/Extensions");
  1400 + const bool has_extensions = extensions.isDictionary();
  1401 + const bool need_extensions_adbe = m->final_extension_level > 0;
  1402 +
  1403 + if (has_extensions || need_extensions_adbe) {
  1404 + // Make a shallow copy of this object so we can modify it safely without affecting
  1405 + // the original. This code has logic to skip certain keys in agreement with
  1406 + // prepareFileForWrite and with skip_stream_parameters so that replacing them
  1407 + // doesn't leave unreferenced objects in the output. We can use unsafeShallowCopy
  1408 + // here because all we are doing is removing or replacing top-level keys.
  1409 + object = object.unsafeShallowCopy();
  1410 + if (!has_extensions) {
  1411 + extensions = QPDFObjectHandle();
  1412 + }
1426 1413
1427 - bool need_extensions_adbe = (m->final_extension_level > 0); 1414 + const bool have_extensions_adbe = extensions && extensions.hasKey("/ADBE");
  1415 + const bool have_extensions_other =
  1416 + extensions && extensions.getKeys().size() > (have_extensions_adbe ? 1u : 0u);
1428 1417
1429 - if (is_root) {  
1430 - if (need_extensions_adbe) {  
1431 - if (!(have_extensions_other || have_extensions_adbe)) {  
1432 - // We need Extensions and don't have it. Create it here.  
1433 - QTC::TC("qpdf", "QPDFWriter create Extensions", m->qdf_mode ? 0 : 1);  
1434 - extensions = object.replaceKeyAndGetNew(  
1435 - "/Extensions", QPDFObjectHandle::newDictionary());  
1436 - }  
1437 - } else if (!have_extensions_other) {  
1438 - // We have Extensions dictionary and don't want one.  
1439 - if (have_extensions_adbe) {  
1440 - QTC::TC("qpdf", "QPDFWriter remove existing Extensions");  
1441 - object.removeKey("/Extensions");  
1442 - extensions = QPDFObjectHandle(); // uninitialized 1418 + if (need_extensions_adbe) {
  1419 + if (!(have_extensions_other || have_extensions_adbe)) {
  1420 + // We need Extensions and don't have it. Create it here.
  1421 + QTC::TC("qpdf", "QPDFWriter create Extensions", m->qdf_mode ? 0 : 1);
  1422 + extensions = object.replaceKeyAndGetNew(
  1423 + "/Extensions", QPDFObjectHandle::newDictionary());
  1424 + }
  1425 + } else if (!have_extensions_other) {
  1426 + // We have Extensions dictionary and don't want one.
  1427 + if (have_extensions_adbe) {
  1428 + QTC::TC("qpdf", "QPDFWriter remove existing Extensions");
  1429 + object.removeKey("/Extensions");
  1430 + extensions = QPDFObjectHandle(); // uninitialized
  1431 + }
1443 } 1432 }
1444 - }  
1445 - }  
1446 1433
1447 - if (extensions) {  
1448 - QTC::TC("qpdf", "QPDFWriter preserve Extensions");  
1449 - QPDFObjectHandle adbe = extensions.getKey("/ADBE");  
1450 - if (adbe.isDictionary() &&  
1451 - adbe.getKey("/BaseVersion").isNameAndEquals("/" + m->final_pdf_version) &&  
1452 - adbe.getKey("/ExtensionLevel").isInteger() &&  
1453 - (adbe.getKey("/ExtensionLevel").getIntValue() == m->final_extension_level)) {  
1454 - QTC::TC("qpdf", "QPDFWriter preserve ADBE");  
1455 - } else {  
1456 - if (need_extensions_adbe) {  
1457 - extensions.replaceKey(  
1458 - "/ADBE",  
1459 - QPDFObjectHandle::parse(  
1460 - "<< /BaseVersion /" + m->final_pdf_version + " /ExtensionLevel " +  
1461 - std::to_string(m->final_extension_level) + " >>"));  
1462 - } else {  
1463 - QTC::TC("qpdf", "QPDFWriter remove ADBE");  
1464 - extensions.removeKey("/ADBE"); 1434 + if (extensions) {
  1435 + QTC::TC("qpdf", "QPDFWriter preserve Extensions");
  1436 + QPDFObjectHandle adbe = extensions.getKey("/ADBE");
  1437 + if (adbe.isDictionary() &&
  1438 + adbe.getKey("/BaseVersion").isNameAndEquals("/" + m->final_pdf_version) &&
  1439 + adbe.getKey("/ExtensionLevel").isInteger() &&
  1440 + (adbe.getKey("/ExtensionLevel").getIntValue() ==
  1441 + m->final_extension_level)) {
  1442 + QTC::TC("qpdf", "QPDFWriter preserve ADBE");
  1443 + } else {
  1444 + if (need_extensions_adbe) {
  1445 + extensions.replaceKey(
  1446 + "/ADBE",
  1447 + QPDFObjectHandle::parse(
  1448 + "<< /BaseVersion /" + m->final_pdf_version +
  1449 + " /ExtensionLevel " + std::to_string(m->final_extension_level) +
  1450 + " >>"));
  1451 + } else {
  1452 + QTC::TC("qpdf", "QPDFWriter remove ADBE");
  1453 + extensions.removeKey("/ADBE");
  1454 + }
  1455 + }
1465 } 1456 }
1466 } 1457 }
1467 } 1458 }
@@ -1470,6 +1461,14 @@ QPDFWriter::unparseObject( @@ -1470,6 +1461,14 @@ QPDFWriter::unparseObject(
1470 1461
1471 if (flags & f_stream) { 1462 if (flags & f_stream) {
1472 // Suppress /Length since we will write it manually 1463 // Suppress /Length since we will write it manually
  1464 +
  1465 + // Make a shallow copy of this object so we can modify it safely without affecting the
  1466 + // original. This code has logic to skip certain keys in agreement with
  1467 + // prepareFileForWrite and with skip_stream_parameters so that replacing them doesn't
  1468 + // leave unreferenced objects in the output. We can use unsafeShallowCopy here because
  1469 + // all we are doing is removing or replacing top-level keys.
  1470 + object = object.unsafeShallowCopy();
  1471 +
1473 object.removeKey("/Length"); 1472 object.removeKey("/Length");
1474 1473
1475 // If /DecodeParms is an empty list, remove it. 1474 // If /DecodeParms is an empty list, remove it.
@@ -1480,8 +1479,7 @@ QPDFWriter::unparseObject( @@ -1480,8 +1479,7 @@ QPDFWriter::unparseObject(
1480 } 1479 }
1481 1480
1482 if (flags & f_filtered) { 1481 if (flags & f_filtered) {
1483 - // We will supply our own filter and decode  
1484 - // parameters. 1482 + // We will supply our own filter and decode parameters.
1485 object.removeKey("/Filter"); 1483 object.removeKey("/Filter");
1486 object.removeKey("/DecodeParms"); 1484 object.removeKey("/DecodeParms");
1487 } else { 1485 } else {