Commit fbcbb781d79a98dfc74df7fc10693ee00606e953
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 { |