From 12f1eb15ca3fed6310402847559a7c99d3c77847 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Sat, 2 Apr 2022 17:14:10 -0400 Subject: Programmatically apply new formatting to code Run this: for i in **/*.cc **/*.c **/*.h **/*.hh; do clang-format < $i >| $i.new && mv $i.new $i done --- libqpdf/QPDFJob.cc | 2260 +++++++++++++++++++++------------------------------- 1 file changed, 896 insertions(+), 1364 deletions(-) (limited to 'libqpdf/QPDFJob.cc') diff --git a/libqpdf/QPDFJob.cc b/libqpdf/QPDFJob.cc index 1d0811ef..cfef7b8a 100644 --- a/libqpdf/QPDFJob.cc +++ b/libqpdf/QPDFJob.cc @@ -8,30 +8,30 @@ #include #include -#include -#include #include #include -#include -#include -#include #include +#include +#include #include +#include +#include +#include +#include #include -#include -#include -#include -#include #include -#include -#include -#include +#include #include #include -#include +#include +#include +#include +#include +#include +#include +#include #include -#include #include // JOB_SCHEMA_DATA @@ -40,18 +40,19 @@ namespace class ImageOptimizer: public QPDFObjectHandle::StreamDataProvider { public: - ImageOptimizer(QPDFJob& o, - size_t oi_min_width, - size_t oi_min_height, - size_t oi_min_area, - QPDFObjectHandle& image); + ImageOptimizer( + QPDFJob& o, + size_t oi_min_width, + size_t oi_min_height, + size_t oi_min_area, + QPDFObjectHandle& image); virtual ~ImageOptimizer() { } - virtual void provideStreamData(int objid, int generation, - Pipeline* pipeline); - std::shared_ptr makePipeline( - std::string const& description, Pipeline* next); + virtual void + provideStreamData(int objid, int generation, Pipeline* pipeline); + std::shared_ptr + makePipeline(std::string const& description, Pipeline* next); bool evaluate(std::string const& description); private: @@ -65,15 +66,23 @@ namespace class DiscardContents: public QPDFObjectHandle::ParserCallbacks { public: - virtual ~DiscardContents() {} - virtual void handleObject(QPDFObjectHandle) {} - virtual void handleEOF() {} + virtual ~DiscardContents() + { + } + virtual void + handleObject(QPDFObjectHandle) + { + } + virtual void + handleEOF() + { + } }; struct QPDFPageData { - QPDFPageData(std::string const& filename, - QPDF* qpdf, std::string const& range); + QPDFPageData( + std::string const& filename, QPDF* qpdf, std::string const& range); QPDFPageData(QPDFPageData const& other, int page); std::string filename; @@ -85,9 +94,10 @@ namespace class ProgressReporter: public QPDFWriter::ProgressReporter { public: - ProgressReporter(std::ostream& cout, - std::string const& prefix, - char const* filename) : + ProgressReporter( + std::ostream& cout, + std::string const& prefix, + char const* filename) : cout(cout), prefix(prefix), filename(filename) @@ -98,18 +108,20 @@ namespace } virtual void reportProgress(int); + private: std::ostream& cout; std::string prefix; std::string filename; }; -} - -ImageOptimizer::ImageOptimizer(QPDFJob& o, - size_t oi_min_width, - size_t oi_min_height, - size_t oi_min_area, - QPDFObjectHandle& image) : +} // namespace + +ImageOptimizer::ImageOptimizer( + QPDFJob& o, + size_t oi_min_width, + size_t oi_min_height, + size_t oi_min_area, + QPDFObjectHandle& image) : o(o), oi_min_width(oi_min_width), oi_min_height(oi_min_height), @@ -126,10 +138,8 @@ ImageOptimizer::makePipeline(std::string const& description, Pipeline* next) QPDFObjectHandle w_obj = dict.getKey("/Width"); QPDFObjectHandle h_obj = dict.getKey("/Height"); QPDFObjectHandle colorspace_obj = dict.getKey("/ColorSpace"); - if (! (w_obj.isNumber() && h_obj.isNumber())) - { - if (! description.empty()) - { + if (!(w_obj.isNumber() && h_obj.isNumber())) { + if (!description.empty()) { o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) { cout << prefix << ": " << description << ": not optimizing because image dictionary" @@ -139,11 +149,9 @@ ImageOptimizer::makePipeline(std::string const& description, Pipeline* next) return result; } QPDFObjectHandle components_obj = dict.getKey("/BitsPerComponent"); - if (! (components_obj.isInteger() && (components_obj.getIntValue() == 8))) - { + if (!(components_obj.isInteger() && (components_obj.getIntValue() == 8))) { QTC::TC("qpdf", "QPDFJob image optimize bits per component"); - if (! description.empty()) - { + if (!description.empty()) { o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) { cout << prefix << ": " << description << ": not optimizing because image has other than" @@ -155,48 +163,33 @@ ImageOptimizer::makePipeline(std::string const& description, Pipeline* next) // Files have been seen in the wild whose width and height are // floating point, which is goofy, but we can deal with it. JDIMENSION w = 0; - if (w_obj.isInteger()) - { + if (w_obj.isInteger()) { w = w_obj.getUIntValueAsUInt(); - } - else - { + } else { w = static_cast(w_obj.getNumericValue()); } JDIMENSION h = 0; - if (h_obj.isInteger()) - { + if (h_obj.isInteger()) { h = h_obj.getUIntValueAsUInt(); - } - else - { + } else { h = static_cast(h_obj.getNumericValue()); } - std::string colorspace = (colorspace_obj.isName() ? - colorspace_obj.getName() : - std::string()); + std::string colorspace = + (colorspace_obj.isName() ? colorspace_obj.getName() : std::string()); int components = 0; J_COLOR_SPACE cs = JCS_UNKNOWN; - if (colorspace == "/DeviceRGB") - { + if (colorspace == "/DeviceRGB") { components = 3; cs = JCS_RGB; - } - else if (colorspace == "/DeviceGray") - { + } else if (colorspace == "/DeviceGray") { components = 1; cs = JCS_GRAYSCALE; - } - else if (colorspace == "/DeviceCMYK") - { + } else if (colorspace == "/DeviceCMYK") { components = 4; cs = JCS_CMYK; - } - else - { + } else { QTC::TC("qpdf", "QPDFJob image optimize colorspace"); - if (! description.empty()) - { + if (!description.empty()) { o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) { cout << prefix << ": " << description << ": not optimizing because qpdf can't optimize" @@ -207,11 +200,9 @@ ImageOptimizer::makePipeline(std::string const& description, Pipeline* next) } if (((this->oi_min_width > 0) && (w <= this->oi_min_width)) || ((this->oi_min_height > 0) && (h <= this->oi_min_height)) || - ((this->oi_min_area > 0) && ((w * h) <= this->oi_min_area))) - { + ((this->oi_min_area > 0) && ((w * h) <= this->oi_min_area))) { QTC::TC("qpdf", "QPDFJob image optimize too small"); - if (! description.empty()) - { + if (!description.empty()) { o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) { cout << prefix << ": " << description << ": not optimizing because image" @@ -229,32 +220,27 @@ ImageOptimizer::makePipeline(std::string const& description, Pipeline* next) bool ImageOptimizer::evaluate(std::string const& description) { - if (! image.pipeStreamData(0, 0, qpdf_dl_specialized, true)) - { + if (!image.pipeStreamData(0, 0, qpdf_dl_specialized, true)) { QTC::TC("qpdf", "QPDFJob image optimize no pipeline"); o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) { cout << prefix << ": " << description << ": not optimizing because unable to decode data" - << " or data already uses DCT" - << std::endl; + << " or data already uses DCT" << std::endl; }); return false; } Pl_Discard d; Pl_Count c("count", &d); std::shared_ptr p = makePipeline(description, &c); - if (p.get() == nullptr) - { + if (p.get() == nullptr) { // message issued by makePipeline return false; } - if (! image.pipeStreamData(p.get(), 0, qpdf_dl_specialized)) - { + if (!image.pipeStreamData(p.get(), 0, qpdf_dl_specialized)) { return false; } long long orig_length = image.getDict().getKey("/Length").getIntValue(); - if (c.getCount() >= orig_length) - { + if (c.getCount() >= orig_length) { QTC::TC("qpdf", "QPDFJob image optimize no shrink"); o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) { cout << prefix << ": " << description @@ -265,9 +251,8 @@ ImageOptimizer::evaluate(std::string const& description) } o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) { cout << prefix << ": " << description - << ": optimizing image reduces size from " - << orig_length << " to " << c.getCount() - << std::endl; + << ": optimizing image reduces size from " << orig_length << " to " + << c.getCount() << std::endl; }); return true; } @@ -276,45 +261,38 @@ void ImageOptimizer::provideStreamData(int, int, Pipeline* pipeline) { std::shared_ptr p = makePipeline("", pipeline); - if (p.get() == nullptr) - { + if (p.get() == nullptr) { // Should not be possible image.warnIfPossible("unable to create pipeline after previous" " success; image data will be lost"); pipeline->finish(); return; } - image.pipeStreamData(p.get(), 0, qpdf_dl_specialized, - false, false); + image.pipeStreamData(p.get(), 0, qpdf_dl_specialized, false, false); } -QPDFJob::PageSpec::PageSpec(std::string const& filename, - char const* password, - std::string const& range) : +QPDFJob::PageSpec::PageSpec( + std::string const& filename, + char const* password, + std::string const& range) : filename(filename), range(range) { - if (password) - { + if (password) { this->password = QUtil::make_shared_cstr(password); } } -QPDFPageData::QPDFPageData(std::string const& filename, - QPDF* qpdf, - std::string const& range) : +QPDFPageData::QPDFPageData( + std::string const& filename, QPDF* qpdf, std::string const& range) : filename(filename), qpdf(qpdf), orig_pages(qpdf->getAllPages()) { - try - { - this->selected_pages = - QUtil::parse_numrange(range.c_str(), - QIntC::to_int(this->orig_pages.size())); - } - catch (std::runtime_error& e) - { + try { + this->selected_pages = QUtil::parse_numrange( + range.c_str(), QIntC::to_int(this->orig_pages.size())); + } catch (std::runtime_error& e) { throw std::runtime_error( "parsing numeric range for " + filename + ": " + e.what()); } @@ -331,8 +309,8 @@ QPDFPageData::QPDFPageData(QPDFPageData const& other, int page) : void ProgressReporter::reportProgress(int percentage) { - this->cout << prefix << ": " << filename << ": write progress: " - << percentage << "%" << std::endl; + this->cout << prefix << ": " << filename + << ": write progress: " << percentage << "%" << std::endl; } // These default values are duplicated in help and docs. @@ -452,7 +430,6 @@ QPDFJob::QPDFJob() : { } - void QPDFJob::usage(std::string const& msg) { @@ -476,8 +453,7 @@ void QPDFJob::doIfVerbose( std::function fn) { - if (this->m->verbose && (this->m->cout != nullptr)) - { + if (this->m->verbose && (this->m->cout != nullptr)) { fn(*(this->m->cout), this->m->message_prefix); } } @@ -501,61 +477,44 @@ QPDFJob::parseRotationParameter(std::string const& parameter) std::string range; size_t colon = parameter.find(':'); int relative = 0; - if (colon != std::string::npos) - { - if (colon > 0) - { + if (colon != std::string::npos) { + if (colon > 0) { angle_str = parameter.substr(0, colon); } - if (colon + 1 < parameter.length()) - { + if (colon + 1 < parameter.length()) { range = parameter.substr(colon + 1); } - } - else - { + } else { angle_str = parameter; } - if (angle_str.length() > 0) - { + if (angle_str.length() > 0) { char first = angle_str.at(0); - if ((first == '+') || (first == '-')) - { + if ((first == '+') || (first == '-')) { relative = ((first == '+') ? 1 : -1); angle_str = angle_str.substr(1); - } - else if (! QUtil::is_digit(angle_str.at(0))) - { + } else if (!QUtil::is_digit(angle_str.at(0))) { angle_str = ""; } } - if (range.empty()) - { + if (range.empty()) { range = "1-z"; } bool range_valid = false; - try - { + try { QUtil::parse_numrange(range.c_str(), 0); range_valid = true; - } - catch (std::runtime_error const&) - { + } catch (std::runtime_error const&) { // ignore } if (range_valid && - ((angle_str == "0") ||(angle_str == "90") || - (angle_str == "180") || (angle_str == "270"))) - { + ((angle_str == "0") || (angle_str == "90") || (angle_str == "180") || + (angle_str == "270"))) { int angle = QUtil::string_to_int(angle_str.c_str()); - if (relative == -1) - { + if (relative == -1) { angle = -angle; } m->rotations[range] = RotationSpec(angle, (relative != 0)); - } - else - { + } else { usage("invalid parameter to rotate: " + parameter); } } @@ -563,12 +522,9 @@ QPDFJob::parseRotationParameter(std::string const& parameter) std::vector QPDFJob::parseNumrange(char const* range, int max) { - try - { + try { return QUtil::parse_numrange(range, max); - } - catch (std::runtime_error& e) - { + } catch (std::runtime_error& e) { usage(e.what()); } return std::vector(); @@ -579,79 +535,58 @@ QPDFJob::run() { checkConfiguration(); std::shared_ptr pdf_ph; - try - { + try { pdf_ph = processFile(m->infilename.get(), m->password.get(), true); - } - catch (QPDFExc& e) - { + } catch (QPDFExc& e) { if ((e.getErrorCode() == qpdf_e_password) && - (m->check_is_encrypted || m->check_requires_password)) - { + (m->check_is_encrypted || m->check_requires_password)) { // Allow --is-encrypted and --requires-password to // work when an incorrect password is supplied. this->m->encryption_status = - qpdf_es_encrypted | - qpdf_es_password_incorrect; + qpdf_es_encrypted | qpdf_es_password_incorrect; return; } throw e; } QPDF& pdf = *pdf_ph; - if (pdf.isEncrypted()) - { + if (pdf.isEncrypted()) { this->m->encryption_status = qpdf_es_encrypted; } - if (m->check_is_encrypted || m->check_requires_password) - { + if (m->check_is_encrypted || m->check_requires_password) { return; } bool other_warnings = false; std::vector> page_heap; - if (! m->page_specs.empty()) - { + if (!m->page_specs.empty()) { handlePageSpecs(pdf, other_warnings, page_heap); } - if (! m->rotations.empty()) - { + if (!m->rotations.empty()) { handleRotations(pdf); } handleUnderOverlay(pdf); handleTransformations(pdf); - if (! createsOutput()) - { + if (!createsOutput()) { doInspection(pdf); - } - else if (m->split_pages) - { + } else if (m->split_pages) { doSplitPages(pdf, other_warnings); - } - else - { + } else { writeOutfile(pdf); } - if (! pdf.getWarnings().empty()) - { + if (!pdf.getWarnings().empty()) { this->m->warnings = true; } - if (this->m->warnings && (! this->m->suppress_warnings)) - { - if (createsOutput()) - { + if (this->m->warnings && (!this->m->suppress_warnings)) { + if (createsOutput()) { (*this->m->cerr) << this->m->message_prefix << ": operation succeeded with warnings;" - << " resulting file may have some problems" - << std::endl; - } - else - { + << " resulting file may have some problems" << std::endl; + } else { (*this->m->cerr) << this->m->message_prefix - << ": operation succeeded with warnings" - << std::endl; + << ": operation succeeded with warnings" << std::endl; } } } @@ -671,43 +606,30 @@ QPDFJob::createsOutput() const int QPDFJob::getExitCode() const { - if (this->m->check_is_encrypted) - { - if (this->m->encryption_status & qpdf_es_encrypted) - { + if (this->m->check_is_encrypted) { + if (this->m->encryption_status & qpdf_es_encrypted) { QTC::TC("qpdf", "QPDFJob check encrypted encrypted"); return 0; - } - else - { + } else { QTC::TC("qpdf", "QPDFJob check encrypted not encrypted"); return EXIT_IS_NOT_ENCRYPTED; } - } - else if (this->m->check_requires_password) - { - if (this->m->encryption_status & qpdf_es_encrypted) - { - if (this->m->encryption_status & qpdf_es_password_incorrect) - { + } else if (this->m->check_requires_password) { + if (this->m->encryption_status & qpdf_es_encrypted) { + if (this->m->encryption_status & qpdf_es_password_incorrect) { QTC::TC("qpdf", "QPDFJob check password password incorrect"); return 0; - } - else - { + } else { QTC::TC("qpdf", "QPDFJob check password password correct"); return EXIT_CORRECT_PASSWORD; } - } - else - { + } else { QTC::TC("qpdf", "QPDFJob check password not encrypted"); return EXIT_IS_NOT_ENCRYPTED; } } - if (this->m->warnings && (! this->m->warnings_exit_zero)) - { + if (this->m->warnings && (!this->m->warnings_exit_zero)) { return EXIT_WARNING; } return 0; @@ -716,43 +638,31 @@ QPDFJob::getExitCode() const void QPDFJob::checkConfiguration() { - if (m->replace_input) - { - if (m->outfilename) - { + if (m->replace_input) { + if (m->outfilename) { usage("--replace-input may not be used when" " an output file is specified"); - } - else if (m->split_pages) - { + } else if (m->split_pages) { usage("--split-pages may not be used with --replace-input"); } } - if (m->infilename == 0) - { + if (m->infilename == 0) { usage("an input file name is required"); - } - else if (m->require_outfile && - (m->outfilename == 0) && (! m->replace_input)) - { + } else if ( + m->require_outfile && (m->outfilename == 0) && (!m->replace_input)) { usage("an output file name is required; use - for standard output"); - } - else if ((! m->require_outfile) && - ((m->outfilename != 0) || m->replace_input)) - { + } else if ( + (!m->require_outfile) && ((m->outfilename != 0) || m->replace_input)) { usage("no output file may be given for this option"); } - if (m->check_requires_password && m->check_is_encrypted) - { + if (m->check_requires_password && m->check_is_encrypted) { usage("--requires-password and --is-encrypted may not be given" " together"); } - if (m->encrypt && (! m->allow_insecure) && - (m->owner_password.empty() && - (! m->user_password.empty()) && - (m->keylen == 256))) - { + if (m->encrypt && (!m->allow_insecure) && + (m->owner_password.empty() && (!m->user_password.empty()) && + (m->keylen == 256))) { // Note that empty owner passwords for R < 5 are copied from // the user password, so this lack of security is not an issue // for those files. Also we are consider only the ability to @@ -767,28 +677,23 @@ QPDFJob::checkConfiguration() } if (m->require_outfile && m->outfilename && - (strcmp(m->outfilename.get(), "-") == 0)) - { - if (m->split_pages) - { + (strcmp(m->outfilename.get(), "-") == 0)) { + if (m->split_pages) { usage("--split-pages may not be used when" " writing to standard output"); } - if (this->m->verbose) - { + if (this->m->verbose) { usage("--verbose may not be used when" " writing to standard output"); } - if (m->progress) - { + if (m->progress) { usage("--progress may not be used when" " writing to standard output"); } } - if ((! m->split_pages) && - QUtil::same_file(m->infilename.get(), m->outfilename.get())) - { + if ((!m->split_pages) && + QUtil::same_file(m->infilename.get(), m->outfilename.get())) { QTC::TC("qpdf", "QPDFJob same file error"); usage("input file and output file are the same;" " use --replace-input to intentionally" @@ -805,47 +710,44 @@ QPDFJob::getEncryptionStatus() void QPDFJob::setQPDFOptions(QPDF& pdf) { - if (m->ignore_xref_streams) - { + if (m->ignore_xref_streams) { pdf.setIgnoreXRefStreams(true); } - if (m->suppress_recovery) - { + if (m->suppress_recovery) { pdf.setAttemptRecovery(false); } - if (m->password_is_hex_key) - { + if (m->password_is_hex_key) { pdf.setPasswordIsHexKey(true); } - if (m->suppress_warnings) - { + if (m->suppress_warnings) { pdf.setSuppressWarnings(true); } } -static std::string show_bool(bool v) +static std::string +show_bool(bool v) { return v ? "allowed" : "not allowed"; } -static std::string show_encryption_method(QPDF::encryption_method_e method) +static std::string +show_encryption_method(QPDF::encryption_method_e method) { std::string result = "unknown"; - switch (method) - { - case QPDF::e_none: + switch (method) { + case QPDF::e_none: result = "none"; break; - case QPDF::e_unknown: + case QPDF::e_unknown: result = "unknown"; break; - case QPDF::e_rc4: + case QPDF::e_rc4: result = "RC4"; break; - case QPDF::e_aes: + case QPDF::e_aes: result = "AESv2"; break; - case QPDF::e_aesv3: + case QPDF::e_aesv3: result = "AESv3"; break; // no default so gcc will warn for missing case @@ -864,51 +766,43 @@ QPDFJob::showEncryption(QPDF& pdf) QPDF::encryption_method_e string_method = QPDF::e_unknown; QPDF::encryption_method_e file_method = QPDF::e_unknown; auto& cout = *this->m->cout; - if (! pdf.isEncrypted(R, P, V, - stream_method, string_method, file_method)) - { + if (!pdf.isEncrypted(R, P, V, stream_method, string_method, file_method)) { cout << "File is not encrypted" << std::endl; - } - else - { + } else { cout << "R = " << R << std::endl; cout << "P = " << P << std::endl; std::string user_password = pdf.getTrimmedUserPassword(); std::string encryption_key = pdf.getEncryptionKey(); cout << "User password = " << user_password << std::endl; - if (m->show_encryption_key) - { - cout << "Encryption key = " - << QUtil::hex_encode(encryption_key) << std::endl; + if (m->show_encryption_key) { + cout << "Encryption key = " << QUtil::hex_encode(encryption_key) + << std::endl; } - if (pdf.ownerPasswordMatched()) - { + if (pdf.ownerPasswordMatched()) { cout << "Supplied password is owner password" << std::endl; } - if (pdf.userPasswordMatched()) - { + if (pdf.userPasswordMatched()) { cout << "Supplied password is user password" << std::endl; } cout << "extract for accessibility: " << show_bool(pdf.allowAccessibility()) << std::endl - << "extract for any purpose: " - << show_bool(pdf.allowExtractAll()) << std::endl - << "print low resolution: " - << show_bool(pdf.allowPrintLowRes()) << std::endl - << "print high resolution: " - << show_bool(pdf.allowPrintHighRes()) << std::endl + << "extract for any purpose: " << show_bool(pdf.allowExtractAll()) + << std::endl + << "print low resolution: " << show_bool(pdf.allowPrintLowRes()) + << std::endl + << "print high resolution: " << show_bool(pdf.allowPrintHighRes()) + << std::endl << "modify document assembly: " << show_bool(pdf.allowModifyAssembly()) << std::endl - << "modify forms: " - << show_bool(pdf.allowModifyForm()) << std::endl - << "modify annotations: " - << show_bool(pdf.allowModifyAnnotation()) << std::endl - << "modify other: " - << show_bool(pdf.allowModifyOther()) << std::endl - << "modify anything: " - << show_bool(pdf.allowModifyAll()) << std::endl; - if (V >= 4) - { + << "modify forms: " << show_bool(pdf.allowModifyForm()) + << std::endl + << "modify annotations: " << show_bool(pdf.allowModifyAnnotation()) + << std::endl + << "modify other: " << show_bool(pdf.allowModifyOther()) + << std::endl + << "modify anything: " << show_bool(pdf.allowModifyAll()) + << std::endl; + if (V >= 4) { cout << "stream encryption method: " << show_encryption_method(stream_method) << std::endl << "string encryption method: " @@ -930,29 +824,23 @@ QPDFJob::doCheck(QPDF& pdf) bool warnings = false; auto& cout = *this->m->cout; cout << "checking " << m->infilename << std::endl; - try - { + try { int extension_level = pdf.getExtensionLevel(); cout << "PDF Version: " << pdf.getPDFVersion(); - if (extension_level > 0) - { + if (extension_level > 0) { cout << " extension level " << pdf.getExtensionLevel(); } cout << std::endl; showEncryption(pdf); - if (pdf.isLinearized()) - { + if (pdf.isLinearized()) { cout << "File is linearized\n"; // any errors or warnings are reported by // checkLinearization(). We treat all issues reported here // as warnings. - if (! pdf.checkLinearization()) - { + if (!pdf.checkLinearization()) { warnings = true; } - } - else - { + } else { cout << "File is not linearized\n"; } @@ -970,47 +858,33 @@ QPDFJob::doCheck(QPDF& pdf) std::vector pages = dh.getAllPages(); DiscardContents discard_contents; int pageno = 0; - for (std::vector::iterator iter = - pages.begin(); - iter != pages.end(); ++iter) - { + for (std::vector::iterator iter = pages.begin(); + iter != pages.end(); + ++iter) { QPDFPageObjectHelper& page(*iter); ++pageno; - try - { + try { page.parseContents(&discard_contents); - } - catch (QPDFExc& e) - { + } catch (QPDFExc& e) { okay = false; - *(this->m->cerr) - << "ERROR: page " << pageno << ": " - << e.what() << std::endl; + *(this->m->cerr) << "ERROR: page " << pageno << ": " << e.what() + << std::endl; } } - } - catch (std::exception& e) - { + } catch (std::exception& e) { (*this->m->cerr) << "ERROR: " << e.what() << std::endl; okay = false; } - if (! okay) - { + if (!okay) { throw std::runtime_error("errors detected"); } - if ((! pdf.getWarnings().empty()) || warnings) - { + if ((!pdf.getWarnings().empty()) || warnings) { this->m->warnings = true; - } - else - { - *(this->m->cout) - << "No syntax or stream encoding errors" - << " found; the file may still contain" - << std::endl - << "errors that qpdf cannot detect" - << std::endl; + } else { + *(this->m->cout) << "No syntax or stream encoding errors" + << " found; the file may still contain" << std::endl + << "errors that qpdf cannot detect" << std::endl; } } @@ -1018,29 +892,20 @@ void QPDFJob::doShowObj(QPDF& pdf) { QPDFObjectHandle obj; - if (m->show_trailer) - { + if (m->show_trailer) { obj = pdf.getTrailer(); - } - else - { + } else { obj = pdf.getObjectByID(m->show_obj, m->show_gen); } bool error = false; - if (obj.isStream()) - { - if (m->show_raw_stream_data || m->show_filtered_stream_data) - { + if (obj.isStream()) { + if (m->show_raw_stream_data || m->show_filtered_stream_data) { bool filter = m->show_filtered_stream_data; - if (filter && - (! obj.pipeStreamData(0, 0, qpdf_dl_all))) - { + if (filter && (!obj.pipeStreamData(0, 0, qpdf_dl_all))) { QTC::TC("qpdf", "QPDFJob unable to filter"); obj.warnIfPossible("unable to filter stream data"); error = true; - } - else - { + } else { QUtil::binary_stdout(); Pl_StdioFile out("stdout", stdout); obj.pipeStreamData( @@ -1048,20 +913,14 @@ QPDFJob::doShowObj(QPDF& pdf) (filter && m->normalize) ? qpdf_ef_normalize : 0, filter ? qpdf_dl_all : qpdf_dl_none); } + } else { + *(this->m->cout) << "Object is stream. Dictionary:" << std::endl + << obj.getDict().unparseResolved() << std::endl; } - else - { - *(this->m->cout) - << "Object is stream. Dictionary:" << std::endl - << obj.getDict().unparseResolved() << std::endl; - } - } - else - { + } else { *(this->m->cout) << obj.unparseResolved() << std::endl; } - if (error) - { + if (error) { throw std::runtime_error( "unable to get object " + obj.getObjGen().unparse()); } @@ -1075,43 +934,33 @@ QPDFJob::doShowPages(QPDF& pdf) int pageno = 0; auto& cout = *this->m->cout; for (std::vector::iterator iter = pages.begin(); - iter != pages.end(); ++iter) - { + iter != pages.end(); + ++iter) { QPDFPageObjectHelper& ph(*iter); QPDFObjectHandle page = ph.getObjectHandle(); ++pageno; - cout << "page " << pageno << ": " - << page.getObjectID() << " " + cout << "page " << pageno << ": " << page.getObjectID() << " " << page.getGeneration() << " R" << std::endl; - if (m->show_page_images) - { + if (m->show_page_images) { std::map images = ph.getImages(); - if (! images.empty()) - { + if (!images.empty()) { cout << " images:" << std::endl; - for (auto const& iter2: images) - { + for (auto const& iter2 : images) { std::string const& name = iter2.first; QPDFObjectHandle image = iter2.second; QPDFObjectHandle dict = image.getDict(); - int width = - dict.getKey("/Width").getIntValueAsInt(); - int height = - dict.getKey("/Height").getIntValueAsInt(); - cout << " " << name << ": " - << image.unparse() - << ", " << width << " x " << height - << std::endl; + int width = dict.getKey("/Width").getIntValueAsInt(); + int height = dict.getKey("/Height").getIntValueAsInt(); + cout << " " << name << ": " << image.unparse() << ", " + << width << " x " << height << std::endl; } } } cout << " content:" << std::endl; - std::vector content = - ph.getPageContents(); - for (auto& iter2: content) - { + std::vector content = ph.getPageContents(); + for (auto& iter2 : content) { cout << " " << iter2.unparse() << std::endl; } } @@ -1121,44 +970,35 @@ void QPDFJob::doListAttachments(QPDF& pdf) { QPDFEmbeddedFileDocumentHelper efdh(pdf); - if (efdh.hasEmbeddedFiles()) - { - for (auto const& i: efdh.getEmbeddedFiles()) - { + if (efdh.hasEmbeddedFiles()) { + for (auto const& i : efdh.getEmbeddedFiles()) { std::string const& key = i.first; auto efoh = i.second; *(this->m->cout) - << key << " -> " - << efoh->getEmbeddedFileStream().getObjGen() + << key << " -> " << efoh->getEmbeddedFileStream().getObjGen() << std::endl; doIfVerbose([&](std::ostream& cout, std::string const& prefix) { auto desc = efoh->getDescription(); - if (! desc.empty()) - { + if (!desc.empty()) { cout << " description: " << desc << std::endl; } cout << " preferred name: " << efoh->getFilename() << std::endl; cout << " all names:" << std::endl; - for (auto const& i2: efoh->getFilenames()) - { + for (auto const& i2 : efoh->getFilenames()) { cout << " " << i2.first << " -> " << i2.second << std::endl; } cout << " all data streams:" << std::endl; - for (auto i2: efoh->getEmbeddedFileStreams().ditems()) - { + for (auto i2 : efoh->getEmbeddedFileStreams().ditems()) { cout << " " << i2.first << " -> " - << i2.second.getObjGen() - << std::endl; + << i2.second.getObjGen() << std::endl; } }); } - } - else - { - *(this->m->cout) - << m->infilename << " has no embedded files" << std::endl; + } else { + *(this->m->cout) << m->infilename << " has no embedded files" + << std::endl; } } @@ -1167,8 +1007,7 @@ QPDFJob::doShowAttachment(QPDF& pdf) { QPDFEmbeddedFileDocumentHelper efdh(pdf); auto fs = efdh.getEmbeddedFile(m->attachment_to_show); - if (! fs) - { + if (!fs) { throw std::runtime_error( "attachment " + m->attachment_to_show + " not found"); } @@ -1179,20 +1018,16 @@ QPDFJob::doShowAttachment(QPDF& pdf) } void -QPDFJob::parse_object_id(std::string const& objspec, - bool& trailer, int& obj, int& gen) +QPDFJob::parse_object_id( + std::string const& objspec, bool& trailer, int& obj, int& gen) { - if (objspec == "trailer") - { + if (objspec == "trailer") { trailer = true; - } - else - { + } else { trailer = false; obj = QUtil::string_to_int(objspec.c_str()); size_t comma = objspec.find(','); - if ((comma != std::string::npos) && (comma + 1 < objspec.length())) - { + if ((comma != std::string::npos) && (comma + 1 < objspec.length())) { gen = QUtil::string_to_int( objspec.substr(1 + comma, std::string::npos).c_str()); } @@ -1203,14 +1038,12 @@ std::set QPDFJob::getWantedJSONObjects() { std::set wanted_og; - for (auto const& iter: m->json_objects) - { + for (auto const& iter : m->json_objects) { bool trailer; int obj = 0; int gen = 0; parse_object_id(iter, trailer, obj, gen); - if (obj) - { + if (obj) { wanted_og.insert(QPDFObjGen(obj, gen)); } } @@ -1226,17 +1059,15 @@ QPDFJob::doJSONObjects(QPDF& pdf, JSON& j) bool all_objects = m->json_objects.empty(); std::set wanted_og = getWantedJSONObjects(); JSON j_objects = j.addDictionaryMember("objects", JSON::makeDictionary()); - if (all_objects || m->json_objects.count("trailer")) - { + if (all_objects || m->json_objects.count("trailer")) { j_objects.addDictionaryMember( "trailer", pdf.getTrailer().getJSON(true)); } std::vector objects = pdf.getAllObjects(); for (std::vector::iterator iter = objects.begin(); - iter != objects.end(); ++iter) - { - if (all_objects || wanted_og.count((*iter).getObjGen())) - { + iter != objects.end(); + ++iter) { + if (all_objects || wanted_og.count((*iter).getObjGen())) { j_objects.addDictionaryMember( (*iter).unparse(), (*iter).getJSON(true)); } @@ -1250,29 +1081,24 @@ QPDFJob::doJSONObjectinfo(QPDF& pdf, JSON& j) // stuff like calling pushInheritedAttributesToPage. bool all_objects = m->json_objects.empty(); std::set wanted_og = getWantedJSONObjects(); - JSON j_objectinfo = j.addDictionaryMember( - "objectinfo", JSON::makeDictionary()); - for (auto& obj: pdf.getAllObjects()) - { - if (all_objects || wanted_og.count(obj.getObjGen())) - { + JSON j_objectinfo = + j.addDictionaryMember("objectinfo", JSON::makeDictionary()); + for (auto& obj : pdf.getAllObjects()) { + if (all_objects || wanted_og.count(obj.getObjGen())) { auto j_details = j_objectinfo.addDictionaryMember( obj.unparse(), JSON::makeDictionary()); - auto j_stream = j_details.addDictionaryMember( - "stream", JSON::makeDictionary()); + auto j_stream = + j_details.addDictionaryMember("stream", JSON::makeDictionary()); bool is_stream = obj.isStream(); - j_stream.addDictionaryMember( - "is", JSON::makeBool(is_stream)); + j_stream.addDictionaryMember("is", JSON::makeBool(is_stream)); j_stream.addDictionaryMember( "length", - (is_stream - ? obj.getDict().getKey("/Length").getJSON(true) - : JSON::makeNull())); + (is_stream ? obj.getDict().getKey("/Length").getJSON(true) + : JSON::makeNull())); j_stream.addDictionaryMember( "filter", - (is_stream - ? obj.getDict().getKey("/Filter").getJSON(true) - : JSON::makeNull())); + (is_stream ? obj.getDict().getKey("/Filter").getJSON(true) + : JSON::makeNull())); } } } @@ -1288,20 +1114,17 @@ QPDFJob::doJSONPages(QPDF& pdf, JSON& j) std::vector pages = pdh.getAllPages(); int pageno = 0; for (std::vector::iterator iter = pages.begin(); - iter != pages.end(); ++iter, ++pageno) - { + iter != pages.end(); + ++iter, ++pageno) { JSON j_page = j_pages.addArrayElement(JSON::makeDictionary()); QPDFPageObjectHelper& ph(*iter); QPDFObjectHandle page = ph.getObjectHandle(); j_page.addDictionaryMember("object", page.getJSON()); - JSON j_images = j_page.addDictionaryMember( - "images", JSON::makeArray()); + JSON j_images = j_page.addDictionaryMember("images", JSON::makeArray()); std::map images = ph.getImages(); - for (auto const& iter2: images) - { + for (auto const& iter2 : images) { JSON j_image = j_images.addArrayElement(JSON::makeDictionary()); - j_image.addDictionaryMember( - "name", JSON::makeString(iter2.first)); + j_image.addDictionaryMember("name", JSON::makeString(iter2.first)); QPDFObjectHandle image = iter2.second; QPDFObjectHandle dict = image.getDict(); j_image.addDictionaryMember("object", image.getJSON()); @@ -1314,19 +1137,14 @@ QPDFJob::doJSONPages(QPDF& pdf, JSON& j) j_image.addDictionaryMember( "bitspercomponent", dict.getKey("/BitsPerComponent").getJSON()); QPDFObjectHandle filters = dict.getKey("/Filter").wrapInArray(); - j_image.addDictionaryMember( - "filter", filters.getJSON()); + j_image.addDictionaryMember("filter", filters.getJSON()); QPDFObjectHandle decode_parms = dict.getKey("/DecodeParms"); QPDFObjectHandle dp_array; - if (decode_parms.isArray()) - { + if (decode_parms.isArray()) { dp_array = decode_parms; - } - else - { + } else { dp_array = QPDFObjectHandle::newArray(); - for (int i = 0; i < filters.getArrayNItems(); ++i) - { + for (int i = 0; i < filters.getArrayNItems(); ++i) { dp_array.appendItem(decode_parms); } } @@ -1337,23 +1155,22 @@ QPDFJob::doJSONPages(QPDF& pdf, JSON& j) image.pipeStreamData(0, 0, m->decode_level, true))); } j_page.addDictionaryMember("images", j_images); - JSON j_contents = j_page.addDictionaryMember( - "contents", JSON::makeArray()); + JSON j_contents = + j_page.addDictionaryMember("contents", JSON::makeArray()); std::vector content = ph.getPageContents(); - for (auto& iter2: content) - { + for (auto& iter2 : content) { j_contents.addArrayElement(iter2.getJSON()); } j_page.addDictionaryMember( "label", pldh.getLabelForPage(pageno).getJSON()); - JSON j_outlines = j_page.addDictionaryMember( - "outlines", JSON::makeArray()); + JSON j_outlines = + j_page.addDictionaryMember("outlines", JSON::makeArray()); std::vector outlines = odh.getOutlinesForPage(page.getObjGen()); for (std::vector::iterator oiter = outlines.begin(); - oiter != outlines.end(); ++oiter) - { + oiter != outlines.end(); + ++oiter) { JSON j_outline = j_outlines.addArrayElement(JSON::makeDictionary()); j_outline.addDictionaryMember( "object", (*oiter).getObjectHandle().getJSON()); @@ -1373,18 +1190,16 @@ QPDFJob::doJSONPageLabels(QPDF& pdf, JSON& j) QPDFPageLabelDocumentHelper pldh(pdf); QPDFPageDocumentHelper pdh(pdf); std::vector pages = pdh.getAllPages(); - if (pldh.hasPageLabels()) - { + if (pldh.hasPageLabels()) { std::vector labels; pldh.getLabelsForPageRange( 0, QIntC::to_int(pages.size()) - 1, 0, labels); for (std::vector::iterator iter = labels.begin(); - iter != labels.end(); ++iter) - { + iter != labels.end(); + ++iter) { std::vector::iterator next = iter; ++next; - if (next == labels.end()) - { + if (next == labels.end()) { // This can't happen, so ignore it. This could only // happen if getLabelsForPageRange somehow returned an // odd number of items. @@ -1398,13 +1213,15 @@ QPDFJob::doJSONPageLabels(QPDF& pdf, JSON& j) } } -static void add_outlines_to_json( - std::vector outlines, JSON& j, +static void +add_outlines_to_json( + std::vector outlines, + JSON& j, std::map& page_numbers) { for (std::vector::iterator iter = outlines.begin(); - iter != outlines.end(); ++iter) - { + iter != outlines.end(); + ++iter) { QPDFOutlineObjectHelper& ol = *iter; JSON jo = j.addArrayElement(JSON::makeDictionary()); jo.addDictionaryMember("object", ol.getObjectHandle().getJSON()); @@ -1413,11 +1230,9 @@ static void add_outlines_to_json( jo.addDictionaryMember("open", JSON::makeBool(ol.getCount() >= 0)); QPDFObjectHandle page = ol.getDestPage(); JSON j_destpage = JSON::makeNull(); - if (page.isIndirect()) - { + if (page.isIndirect()) { QPDFObjGen og = page.getObjGen(); - if (page_numbers.count(og)) - { + if (page_numbers.count(og)) { j_destpage = JSON::makeInt(page_numbers[og]); } } @@ -1435,14 +1250,13 @@ QPDFJob::doJSONOutlines(QPDF& pdf, JSON& j) std::vector pages = dh.getAllPages(); int n = 0; for (std::vector::iterator iter = pages.begin(); - iter != pages.end(); ++iter) - { + iter != pages.end(); + ++iter) { QPDFObjectHandle oh = (*iter).getObjectHandle(); page_numbers[oh.getObjGen()] = ++n; } - JSON j_outlines = j.addDictionaryMember( - "outlines", JSON::makeArray()); + JSON j_outlines = j.addDictionaryMember("outlines", JSON::makeArray()); QPDFOutlineDocumentHelper odh(pdf); add_outlines_to_json(odh.getTopLevelOutlines(), j_outlines, page_numbers); } @@ -1450,103 +1264,75 @@ QPDFJob::doJSONOutlines(QPDF& pdf, JSON& j) void QPDFJob::doJSONAcroform(QPDF& pdf, JSON& j) { - JSON j_acroform = j.addDictionaryMember( - "acroform", JSON::makeDictionary()); + JSON j_acroform = j.addDictionaryMember("acroform", JSON::makeDictionary()); QPDFAcroFormDocumentHelper afdh(pdf); j_acroform.addDictionaryMember( - "hasacroform", - JSON::makeBool(afdh.hasAcroForm())); + "hasacroform", JSON::makeBool(afdh.hasAcroForm())); j_acroform.addDictionaryMember( - "needappearances", - JSON::makeBool(afdh.getNeedAppearances())); - JSON j_fields = j_acroform.addDictionaryMember( - "fields", JSON::makeArray()); + "needappearances", JSON::makeBool(afdh.getNeedAppearances())); + JSON j_fields = j_acroform.addDictionaryMember("fields", JSON::makeArray()); QPDFPageDocumentHelper pdh(pdf); std::vector pages = pdh.getAllPages(); int pagepos1 = 0; - for (std::vector::iterator page_iter = - pages.begin(); - page_iter != pages.end(); ++page_iter) - { + for (std::vector::iterator page_iter = pages.begin(); + page_iter != pages.end(); + ++page_iter) { ++pagepos1; std::vector annotations = afdh.getWidgetAnnotationsForPage(*page_iter); for (std::vector::iterator annot_iter = annotations.begin(); - annot_iter != annotations.end(); ++annot_iter) - { + annot_iter != annotations.end(); + ++annot_iter) { QPDFAnnotationObjectHelper& aoh = *annot_iter; - QPDFFormFieldObjectHelper ffh = - afdh.getFieldForAnnotation(aoh); - JSON j_field = j_fields.addArrayElement( - JSON::makeDictionary()); - j_field.addDictionaryMember( - "object", - ffh.getObjectHandle().getJSON()); - j_field.addDictionaryMember( - "parent", - ffh.getObjectHandle().getKey("/Parent").getJSON()); + QPDFFormFieldObjectHelper ffh = afdh.getFieldForAnnotation(aoh); + JSON j_field = j_fields.addArrayElement(JSON::makeDictionary()); j_field.addDictionaryMember( - "pageposfrom1", - JSON::makeInt(pagepos1)); + "object", ffh.getObjectHandle().getJSON()); j_field.addDictionaryMember( - "fieldtype", - JSON::makeString(ffh.getFieldType())); + "parent", ffh.getObjectHandle().getKey("/Parent").getJSON()); j_field.addDictionaryMember( - "fieldflags", - JSON::makeInt(ffh.getFlags())); + "pageposfrom1", JSON::makeInt(pagepos1)); j_field.addDictionaryMember( - "fullname", - JSON::makeString(ffh.getFullyQualifiedName())); + "fieldtype", JSON::makeString(ffh.getFieldType())); j_field.addDictionaryMember( - "partialname", - JSON::makeString(ffh.getPartialName())); + "fieldflags", JSON::makeInt(ffh.getFlags())); j_field.addDictionaryMember( - "alternativename", - JSON::makeString(ffh.getAlternativeName())); + "fullname", JSON::makeString(ffh.getFullyQualifiedName())); j_field.addDictionaryMember( - "mappingname", - JSON::makeString(ffh.getMappingName())); + "partialname", JSON::makeString(ffh.getPartialName())); j_field.addDictionaryMember( - "value", - ffh.getValue().getJSON()); + "alternativename", JSON::makeString(ffh.getAlternativeName())); j_field.addDictionaryMember( - "defaultvalue", - ffh.getDefaultValue().getJSON()); + "mappingname", JSON::makeString(ffh.getMappingName())); + j_field.addDictionaryMember("value", ffh.getValue().getJSON()); j_field.addDictionaryMember( - "quadding", - JSON::makeInt(ffh.getQuadding())); + "defaultvalue", ffh.getDefaultValue().getJSON()); j_field.addDictionaryMember( - "ischeckbox", - JSON::makeBool(ffh.isCheckbox())); + "quadding", JSON::makeInt(ffh.getQuadding())); j_field.addDictionaryMember( - "isradiobutton", - JSON::makeBool(ffh.isRadioButton())); + "ischeckbox", JSON::makeBool(ffh.isCheckbox())); j_field.addDictionaryMember( - "ischoice", - JSON::makeBool(ffh.isChoice())); + "isradiobutton", JSON::makeBool(ffh.isRadioButton())); j_field.addDictionaryMember( - "istext", - JSON::makeBool(ffh.isText())); - JSON j_choices = j_field.addDictionaryMember( - "choices", JSON::makeArray()); + "ischoice", JSON::makeBool(ffh.isChoice())); + j_field.addDictionaryMember("istext", JSON::makeBool(ffh.isText())); + JSON j_choices = + j_field.addDictionaryMember("choices", JSON::makeArray()); std::vector choices = ffh.getChoices(); for (std::vector::iterator iter = choices.begin(); - iter != choices.end(); ++iter) - { + iter != choices.end(); + ++iter) { j_choices.addArrayElement(JSON::makeString(*iter)); } JSON j_annot = j_field.addDictionaryMember( "annotation", JSON::makeDictionary()); j_annot.addDictionaryMember( - "object", - aoh.getObjectHandle().getJSON()); + "object", aoh.getObjectHandle().getJSON()); j_annot.addDictionaryMember( - "appearancestate", - JSON::makeString(aoh.getAppearanceState())); + "appearancestate", JSON::makeString(aoh.getAppearanceState())); j_annot.addDictionaryMember( - "annotationflags", - JSON::makeInt(aoh.getFlags())); + "annotationflags", JSON::makeInt(aoh.getFlags())); } } } @@ -1560,69 +1346,54 @@ QPDFJob::doJSONEncrypt(QPDF& pdf, JSON& j) QPDF::encryption_method_e stream_method = QPDF::e_none; QPDF::encryption_method_e string_method = QPDF::e_none; QPDF::encryption_method_e file_method = QPDF::e_none; - bool is_encrypted = pdf.isEncrypted( - R, P, V, stream_method, string_method, file_method); - JSON j_encrypt = j.addDictionaryMember( - "encrypt", JSON::makeDictionary()); - j_encrypt.addDictionaryMember( - "encrypted", - JSON::makeBool(is_encrypted)); + bool is_encrypted = + pdf.isEncrypted(R, P, V, stream_method, string_method, file_method); + JSON j_encrypt = j.addDictionaryMember("encrypt", JSON::makeDictionary()); + j_encrypt.addDictionaryMember("encrypted", JSON::makeBool(is_encrypted)); j_encrypt.addDictionaryMember( "userpasswordmatched", JSON::makeBool(is_encrypted && pdf.userPasswordMatched())); j_encrypt.addDictionaryMember( "ownerpasswordmatched", JSON::makeBool(is_encrypted && pdf.ownerPasswordMatched())); - JSON j_capabilities = j_encrypt.addDictionaryMember( - "capabilities", JSON::makeDictionary()); + JSON j_capabilities = + j_encrypt.addDictionaryMember("capabilities", JSON::makeDictionary()); j_capabilities.addDictionaryMember( - "accessibility", - JSON::makeBool(pdf.allowAccessibility())); + "accessibility", JSON::makeBool(pdf.allowAccessibility())); j_capabilities.addDictionaryMember( - "extract", - JSON::makeBool(pdf.allowExtractAll())); + "extract", JSON::makeBool(pdf.allowExtractAll())); j_capabilities.addDictionaryMember( - "printlow", - JSON::makeBool(pdf.allowPrintLowRes())); + "printlow", JSON::makeBool(pdf.allowPrintLowRes())); j_capabilities.addDictionaryMember( - "printhigh", - JSON::makeBool(pdf.allowPrintHighRes())); + "printhigh", JSON::makeBool(pdf.allowPrintHighRes())); j_capabilities.addDictionaryMember( - "modifyassembly", - JSON::makeBool(pdf.allowModifyAssembly())); + "modifyassembly", JSON::makeBool(pdf.allowModifyAssembly())); j_capabilities.addDictionaryMember( - "modifyforms", - JSON::makeBool(pdf.allowModifyForm())); + "modifyforms", JSON::makeBool(pdf.allowModifyForm())); j_capabilities.addDictionaryMember( - "moddifyannotations", - JSON::makeBool(pdf.allowModifyAnnotation())); + "moddifyannotations", JSON::makeBool(pdf.allowModifyAnnotation())); j_capabilities.addDictionaryMember( - "modifyother", - JSON::makeBool(pdf.allowModifyOther())); + "modifyother", JSON::makeBool(pdf.allowModifyOther())); j_capabilities.addDictionaryMember( - "modify", - JSON::makeBool(pdf.allowModifyAll())); - JSON j_parameters = j_encrypt.addDictionaryMember( - "parameters", JSON::makeDictionary()); + "modify", JSON::makeBool(pdf.allowModifyAll())); + JSON j_parameters = + j_encrypt.addDictionaryMember("parameters", JSON::makeDictionary()); j_parameters.addDictionaryMember("R", JSON::makeInt(R)); j_parameters.addDictionaryMember("V", JSON::makeInt(V)); j_parameters.addDictionaryMember("P", JSON::makeInt(P)); int bits = 0; JSON key = JSON::makeNull(); - if (is_encrypted) - { + if (is_encrypted) { std::string encryption_key = pdf.getEncryptionKey(); bits = QIntC::to_int(encryption_key.length() * 8); - if (m->show_encryption_key) - { + if (m->show_encryption_key) { key = JSON::makeString(QUtil::hex_encode(encryption_key)); } } j_parameters.addDictionaryMember("bits", JSON::makeInt(bits)); j_parameters.addDictionaryMember("key", key); auto fix_method = [is_encrypted](QPDF::encryption_method_e& m) { - if (is_encrypted && m == QPDF::e_none) - { + if (is_encrypted && m == QPDF::e_none) { m = QPDF::e_rc4; } }; @@ -1633,13 +1404,9 @@ QPDFJob::doJSONEncrypt(QPDF& pdf, JSON& j) std::string s_string_method = show_encryption_method(string_method); std::string s_file_method = show_encryption_method(file_method); std::string s_overall_method; - if ((stream_method == string_method) && - (stream_method == file_method)) - { + if ((stream_method == string_method) && (stream_method == file_method)) { s_overall_method = s_stream_method; - } - else - { + } else { s_overall_method = "mixed"; } j_parameters.addDictionaryMember( @@ -1655,18 +1422,16 @@ QPDFJob::doJSONEncrypt(QPDF& pdf, JSON& j) void QPDFJob::doJSONAttachments(QPDF& pdf, JSON& j) { - JSON j_attachments = j.addDictionaryMember( - "attachments", JSON::makeDictionary()); + JSON j_attachments = + j.addDictionaryMember("attachments", JSON::makeDictionary()); QPDFEmbeddedFileDocumentHelper efdh(pdf); - for (auto const& iter: efdh.getEmbeddedFiles()) - { + for (auto const& iter : efdh.getEmbeddedFiles()) { std::string const& key = iter.first; auto fsoh = iter.second; - auto j_details = j_attachments.addDictionaryMember( - key, JSON::makeDictionary()); + auto j_details = + j_attachments.addDictionaryMember(key, JSON::makeDictionary()); j_details.addDictionaryMember( - "filespec", - JSON::makeString(fsoh->getObjectHandle().unparse())); + "filespec", JSON::makeString(fsoh->getObjectHandle().unparse())); j_details.addDictionaryMember( "preferredname", JSON::makeString(fsoh->getFilename())); j_details.addDictionaryMember( @@ -1696,10 +1461,10 @@ QPDFJob::json_schema(std::set* keys) // more depth in the manual. JSON schema = JSON::makeDictionary(); schema.addDictionaryMember( - "version", JSON::makeString( + "version", + JSON::makeString( "JSON format serial number; increased for non-compatible changes")); - JSON j_params = schema.addDictionaryMember( - "parameters", JSON::parse(R"({ + JSON j_params = schema.addDictionaryMember("parameters", JSON::parse(R"({ "decodelevel": "decode level used to determine stream filterability" })")); @@ -1708,17 +1473,14 @@ QPDFJob::json_schema(std::set* keys) // The list of selectable top-level keys id duplicated in the // following places: job.yml, QPDFJob::json_schema, and // QPDFJob::doJSON. - if (all_keys || keys->count("objects")) - { - schema.addDictionaryMember( - "objects", JSON::parse(R"({ + if (all_keys || keys->count("objects")) { + schema.addDictionaryMember("objects", JSON::parse(R"({ "": "json representation of object" })")); } - if (all_keys || keys->count("objectinfo")) - { - JSON objectinfo = schema.addDictionaryMember( - "objectinfo", JSON::parse(R"({ + if (all_keys || keys->count("objectinfo")) { + JSON objectinfo = + schema.addDictionaryMember("objectinfo", JSON::parse(R"({ "": { "stream": { "filter": "if stream, its filters, otherwise null", @@ -1728,8 +1490,7 @@ QPDFJob::json_schema(std::set* keys) } })")); } - if (all_keys || keys->count("pages")) - { + if (all_keys || keys->count("pages")) { JSON page = schema.addDictionaryMember("pages", JSON::parse(R"([ { "contents": [ @@ -1765,20 +1526,16 @@ QPDFJob::json_schema(std::set* keys) } ])")); } - if (all_keys || keys->count("pagelabels")) - { - JSON labels = schema.addDictionaryMember( - "pagelabels", JSON::parse(R"([ + if (all_keys || keys->count("pagelabels")) { + JSON labels = schema.addDictionaryMember("pagelabels", JSON::parse(R"([ { "index": "starting page position starting from zero", "label": "page label dictionary" } ])")); } - if (all_keys || keys->count("outlines")) - { - JSON outlines = schema.addDictionaryMember( - "outlines", JSON::parse(R"([ + if (all_keys || keys->count("outlines")) { + JSON outlines = schema.addDictionaryMember("outlines", JSON::parse(R"([ { "dest": "outline destination dictionary", "destpageposfrom1": "position of destination page in document numbered from 1; null if not known", @@ -1789,10 +1546,8 @@ QPDFJob::json_schema(std::set* keys) } ])")); } - if (all_keys || keys->count("acroform")) - { - JSON acroform = schema.addDictionaryMember( - "acroform", JSON::parse(R"({ + if (all_keys || keys->count("acroform")) { + JSON acroform = schema.addDictionaryMember("acroform", JSON::parse(R"({ "fields": [ { "alternativename": "alternative name of field -- this is the one usually shown to users", @@ -1823,10 +1578,8 @@ QPDFJob::json_schema(std::set* keys) "needappearances": "whether the form fields' appearance streams need to be regenerated" })")); } - if (all_keys || keys->count("encrypt")) - { - JSON encrypt = schema.addDictionaryMember( - "encrypt", JSON::parse(R"({ + if (all_keys || keys->count("encrypt")) { + JSON encrypt = schema.addDictionaryMember("encrypt", JSON::parse(R"({ "capabilities": { "accessibility": "allow extraction for accessibility?", "extract": "allow extraction?", @@ -1854,10 +1607,9 @@ QPDFJob::json_schema(std::set* keys) "userpasswordmatched": "whether supplied password matched user password; always false for non-encrypted files" })")); } - if (all_keys || keys->count("attachments")) - { - JSON attachments = schema.addDictionaryMember( - "attachments", JSON::parse(R"({ + if (all_keys || keys->count("attachments")) { + JSON attachments = + schema.addDictionaryMember("attachments", JSON::parse(R"({ "": { "filespec": "object containing the file spec", "preferredcontents": "most preferred embedded file stream", @@ -1883,21 +1635,19 @@ QPDFJob::doJSON(QPDF& pdf) // ignore unrecognized keys, so we only update the version of a // key disappears or if its value changes meaning. j.addDictionaryMember("version", JSON::makeInt(1)); - JSON j_params = j.addDictionaryMember( - "parameters", JSON::makeDictionary()); + JSON j_params = j.addDictionaryMember("parameters", JSON::makeDictionary()); std::string decode_level_str; - switch (m->decode_level) - { - case qpdf_dl_none: + switch (m->decode_level) { + case qpdf_dl_none: decode_level_str = "none"; break; - case qpdf_dl_generalized: + case qpdf_dl_generalized: decode_level_str = "generalized"; break; - case qpdf_dl_specialized: + case qpdf_dl_specialized: decode_level_str = "specialized"; break; - case qpdf_dl_all: + case qpdf_dl_all: decode_level_str = "all"; break; } @@ -1908,36 +1658,28 @@ QPDFJob::doJSON(QPDF& pdf) // The list of selectable top-level keys id duplicated in the // following places: job.yml, QPDFJob::json_schema, and // QPDFJob::doJSON. - if (all_keys || m->json_keys.count("objects")) - { + if (all_keys || m->json_keys.count("objects")) { doJSONObjects(pdf, j); } - if (all_keys || m->json_keys.count("objectinfo")) - { + if (all_keys || m->json_keys.count("objectinfo")) { doJSONObjectinfo(pdf, j); } - if (all_keys || m->json_keys.count("pages")) - { + if (all_keys || m->json_keys.count("pages")) { doJSONPages(pdf, j); } - if (all_keys || m->json_keys.count("pagelabels")) - { + if (all_keys || m->json_keys.count("pagelabels")) { doJSONPageLabels(pdf, j); } - if (all_keys || m->json_keys.count("outlines")) - { + if (all_keys || m->json_keys.count("outlines")) { doJSONOutlines(pdf, j); } - if (all_keys || m->json_keys.count("acroform")) - { + if (all_keys || m->json_keys.count("acroform")) { doJSONAcroform(pdf, j); } - if (all_keys || m->json_keys.count("encrypt")) - { + if (all_keys || m->json_keys.count("encrypt")) { doJSONEncrypt(pdf, j); } - if (all_keys || m->json_keys.count("attachments")) - { + if (all_keys || m->json_keys.count("attachments")) { doJSONAttachments(pdf, j); } @@ -1945,8 +1687,7 @@ QPDFJob::doJSON(QPDF& pdf) JSON schema = json_schema(&m->json_keys); std::list errors; - if (! j.checkSchema(schema, errors)) - { + if (!j.checkSchema(schema, errors)) { *(this->m->cerr) << "QPDFJob didn't create JSON that complies with its own rules.\n\ Please report this as a bug at\n\ @@ -1954,8 +1695,8 @@ Please report this as a bug at\n\ ideally with the file that caused the error and the output below. Thanks!\n\ \n"; for (std::list::iterator iter = errors.begin(); - iter != errors.end(); ++iter) - { + iter != errors.end(); + ++iter) { *(this->m->cerr) << (*iter) << std::endl; } } @@ -1966,75 +1707,56 @@ ideally with the file that caused the error and the output below. Thanks!\n\ void QPDFJob::doInspection(QPDF& pdf) { - if (m->check) - { + if (m->check) { doCheck(pdf); } - if (m->json_version) - { + if (m->json_version) { doJSON(pdf); } - if (m->show_npages) - { + if (m->show_npages) { QTC::TC("qpdf", "QPDFJob npages"); - *(this->m->cout) << pdf.getRoot().getKey("/Pages"). - getKey("/Count").getIntValue() << std::endl; + *(this->m->cout) + << pdf.getRoot().getKey("/Pages").getKey("/Count").getIntValue() + << std::endl; } - if (m->show_encryption) - { + if (m->show_encryption) { showEncryption(pdf); } - if (m->check_linearization) - { - if (! pdf.isLinearized()) - { + if (m->check_linearization) { + if (!pdf.isLinearized()) { *(this->m->cout) << m->infilename << " is not linearized" << std::endl; - } - else if (pdf.checkLinearization()) - { + } else if (pdf.checkLinearization()) { *(this->m->cout) << m->infilename << ": no linearization errors" << std::endl; - } - else - { + } else { this->m->warnings = true; } } - if (m->show_linearization) - { - if (pdf.isLinearized()) - { + if (m->show_linearization) { + if (pdf.isLinearized()) { pdf.showLinearizationData(); - } - else - { + } else { *(this->m->cout) << m->infilename << " is not linearized" << std::endl; } } - if (m->show_xref) - { + if (m->show_xref) { pdf.showXRefTable(); } - if ((m->show_obj > 0) || m->show_trailer) - { + if ((m->show_obj > 0) || m->show_trailer) { doShowObj(pdf); } - if (m->show_pages) - { + if (m->show_pages) { doShowPages(pdf); } - if (m->list_attachments) - { + if (m->list_attachments) { doListAttachments(pdf); } - if (! m->attachment_to_show.empty()) - { + if (!m->attachment_to_show.empty()) { doShowAttachment(pdf); } - if (! pdf.getWarnings().empty()) - { + if (!pdf.getWarnings().empty()) { this->m->warnings = true; } } @@ -2042,20 +1764,18 @@ QPDFJob::doInspection(QPDF& pdf) std::shared_ptr QPDFJob::doProcessOnce( std::function fn, - char const* password, bool empty, bool used_for_input) + char const* password, + bool empty, + bool used_for_input) { auto pdf = std::make_shared(); setQPDFOptions(*pdf); - if (empty) - { + if (empty) { pdf->emptyPDF(); - } - else - { + } else { fn(pdf.get(), password); } - if (used_for_input) - { + if (used_for_input) { this->m->max_input_version.updateIfGreater( pdf->getVersionAsPDFVersion()); } @@ -2065,7 +1785,9 @@ QPDFJob::doProcessOnce( std::shared_ptr QPDFJob::doProcess( std::function fn, - char const* password, bool empty, bool used_for_input) + char const* password, + bool empty, + bool used_for_input) { // If a password has been specified but doesn't work, try other // passwords that are equivalent in different character encodings. @@ -2078,10 +1800,8 @@ QPDFJob::doProcess( // good chance we'd succeed here. std::string ptemp; - if (password && (! m->password_is_hex_key)) - { - if (m->password_mode == QPDFJob::pm_hex_bytes) - { + if (password && (!m->password_is_hex_key)) { + if (m->password_mode == QPDFJob::pm_hex_bytes) { // Special case: handle --password-mode=hex-bytes for input // password as well as output password QTC::TC("qpdf", "QPDFJob input password hex-bytes"); @@ -2090,8 +1810,7 @@ QPDFJob::doProcess( } } if ((password == 0) || empty || m->password_is_hex_key || - m->suppress_password_recovery) - { + m->suppress_password_recovery) { // There is no password, or we're not doing recovery, so just // do the normal processing with the supplied password. return doProcessOnce(fn, password, empty, used_for_input); @@ -2104,8 +1823,8 @@ QPDFJob::doProcess( // Represent to char const*, as required by the QPDF class. std::vector passwords; for (std::vector::iterator iter = passwords_str.begin(); - iter != passwords_str.end(); ++iter) - { + iter != passwords_str.end(); + ++iter) { passwords.push_back((*iter).c_str()); } // We always try the supplied password first because it is the @@ -2113,8 +1832,7 @@ QPDFJob::doProcess( // is more than one option, go ahead and put the supplied password // at the end so that it's that decoding attempt whose exception // is thrown. - if (passwords.size() > 1) - { + if (passwords.size() > 1) { passwords.push_back(password); } @@ -2124,23 +1842,18 @@ QPDFJob::doProcess( // supplied password. bool warned = false; for (std::vector::iterator iter = passwords.begin(); - iter != passwords.end(); ++iter) - { - try - { + iter != passwords.end(); + ++iter) { + try { return doProcessOnce(fn, *iter, empty, used_for_input); - } - catch (QPDFExc& e) - { + } catch (QPDFExc& e) { std::vector::iterator next = iter; ++next; - if (next == passwords.end()) - { + if (next == passwords.end()) { throw e; } } - if (! warned) - { + if (!warned) { warned = true; doIfVerbose([&](std::ostream& cout, std::string const& prefix) { cout << prefix << ": supplied password didn't work;" @@ -2155,12 +1868,12 @@ QPDFJob::doProcess( } std::shared_ptr -QPDFJob::processFile(char const* filename, char const* password, - bool used_for_input) +QPDFJob::processFile( + char const* filename, char const* password, bool used_for_input) { auto f1 = std::mem_fn(&QPDF::processFile); - auto fn = std::bind( - f1, std::placeholders::_1, filename, std::placeholders::_2); + auto fn = + std::bind(f1, std::placeholders::_1, filename, std::placeholders::_2); return doProcess(fn, password, strcmp(filename, "") == 0, used_for_input); } @@ -2169,16 +1882,14 @@ QPDFJob::processInputSource( PointerHolder is, char const* password, bool used_for_input) { auto f1 = std::mem_fn(&QPDF::processInputSource); - auto fn = std::bind( - f1, std::placeholders::_1, is, std::placeholders::_2); + auto fn = std::bind(f1, std::placeholders::_1, is, std::placeholders::_2); return doProcess(fn, password, false, used_for_input); } void QPDFJob::validateUnderOverlay(QPDF& pdf, UnderOverlay* uo) { - if (uo->filename.empty()) - { + if (uo->filename.empty()) { return; } QPDFPageDocumentHelper main_pdh(pdf); @@ -2186,47 +1897,39 @@ QPDFJob::validateUnderOverlay(QPDF& pdf, UnderOverlay* uo) uo->pdf = processFile(uo->filename.c_str(), uo->password.get(), true); QPDFPageDocumentHelper uo_pdh(*(uo->pdf)); int uo_npages = QIntC::to_int(uo_pdh.getAllPages().size()); - try - { + try { uo->to_pagenos = QUtil::parse_numrange(uo->to_nr.c_str(), main_npages); - } - catch (std::runtime_error& e) - { + } catch (std::runtime_error& e) { throw std::runtime_error( "parsing numeric range for " + uo->which + " \"to\" pages: " + e.what()); } - try - { - if (uo->from_nr.empty()) - { + try { + if (uo->from_nr.empty()) { QTC::TC("qpdf", "QPDFJob from_nr from repeat_nr"); uo->from_nr = uo->repeat_nr; } uo->from_pagenos = QUtil::parse_numrange(uo->from_nr.c_str(), uo_npages); - if (! uo->repeat_nr.empty()) - { + if (!uo->repeat_nr.empty()) { uo->repeat_pagenos = QUtil::parse_numrange(uo->repeat_nr.c_str(), uo_npages); } - } - catch (std::runtime_error& e) - { + } catch (std::runtime_error& e) { throw std::runtime_error( - "parsing numeric range for " + uo->which + " file " + - uo->filename + ": " + e.what()); + "parsing numeric range for " + uo->which + " file " + uo->filename + + ": " + e.what()); } } -static QPDFAcroFormDocumentHelper* get_afdh_for_qpdf( - std::map>& afdh_map, +static QPDFAcroFormDocumentHelper* +get_afdh_for_qpdf( + std::map>& + afdh_map, QPDF* q) { auto uid = q->getUniqueId(); - if (! afdh_map.count(uid)) - { + if (!afdh_map.count(uid)) { afdh_map[uid] = std::make_shared(*q); } return afdh_map[uid].get(); @@ -2236,7 +1939,7 @@ void QPDFJob::doUnderOverlayForPage( QPDF& pdf, UnderOverlay& uo, - std::map >& pagenos, + std::map>& pagenos, size_t page_idx, std::map& fo, std::vector& pages, @@ -2244,13 +1947,12 @@ QPDFJob::doUnderOverlayForPage( bool before) { int pageno = 1 + QIntC::to_int(page_idx); - if (! pagenos.count(pageno)) - { + if (!pagenos.count(pageno)) { return; } - std::map> afdh; + std::map> + afdh; auto make_afdh = [&](QPDFPageObjectHelper& ph) { QPDF* q = ph.getObjectHandle().getOwningQPDF(); return get_afdh_for_qpdf(afdh, q); @@ -2260,25 +1962,22 @@ QPDFJob::doUnderOverlayForPage( std::string content; int min_suffix = 1; QPDFObjectHandle resources = dest_page.getAttribute("/Resources", true); - if (! resources.isDictionary()) - { + if (!resources.isDictionary()) { QTC::TC("qpdf", "QPDFJob overlay page with no resources"); resources = QPDFObjectHandle::newDictionary(); dest_page.getObjectHandle().replaceKey("/Resources", resources); } for (std::vector::iterator iter = pagenos[pageno].begin(); - iter != pagenos[pageno].end(); ++iter) - { + iter != pagenos[pageno].end(); + ++iter) { int from_pageno = *iter; doIfVerbose([&](std::ostream& cout, std::string const& prefix) { cout << " " << uo.which << " " << from_pageno << std::endl; }); auto from_page = pages.at(QIntC::to_size(from_pageno - 1)); - if (0 == fo.count(from_pageno)) - { + if (0 == fo.count(from_pageno)) { fo[from_pageno] = - pdf.copyForeignObject( - from_page.getFormXObjectForPage()); + pdf.copyForeignObject(from_page.getFormXObjectForPage()); } // If the same page is overlaid or underlaid multiple times, @@ -2288,31 +1987,27 @@ QPDFJob::doUnderOverlayForPage( std::string name = resources.getUniqueResourceName("/Fx", min_suffix); QPDFMatrix cm; std::string new_content = dest_page.placeFormXObject( - fo[from_pageno], name, - dest_page.getTrimBox().getArrayAsRectangle(), cm); + fo[from_pageno], + name, + dest_page.getTrimBox().getArrayAsRectangle(), + cm); dest_page.copyAnnotations( from_page, cm, dest_afdh, make_afdh(from_page)); - if (! new_content.empty()) - { + if (!new_content.empty()) { resources.mergeResources("<< /XObject << >> >>"_qpdf); auto xobject = resources.getKey("/XObject"); - if (xobject.isDictionary()) - { + if (xobject.isDictionary()) { xobject.replaceKey(name, fo[from_pageno]); } ++min_suffix; content += new_content; } } - if (! content.empty()) - { - if (before) - { + if (!content.empty()) { + if (before) { dest_page.addPageContents( QPDFObjectHandle::newStream(&pdf, content), true); - } - else - { + } else { dest_page.addPageContents( QPDFObjectHandle::newStream(&pdf, "q\n"), true); dest_page.addPageContents( @@ -2322,21 +2017,18 @@ QPDFJob::doUnderOverlayForPage( } void -QPDFJob::getUOPagenos(QPDFJob::UnderOverlay& uo, - std::map >& pagenos) +QPDFJob::getUOPagenos( + QPDFJob::UnderOverlay& uo, std::map>& pagenos) { size_t idx = 0; size_t from_size = uo.from_pagenos.size(); size_t repeat_size = uo.repeat_pagenos.size(); for (std::vector::iterator iter = uo.to_pagenos.begin(); - iter != uo.to_pagenos.end(); ++iter, ++idx) - { - if (idx < from_size) - { + iter != uo.to_pagenos.end(); + ++iter, ++idx) { + if (idx < from_size) { pagenos[*iter].push_back(uo.from_pagenos.at(idx)); - } - else if (repeat_size) - { + } else if (repeat_size) { pagenos[*iter].push_back( uo.repeat_pagenos.at((idx - from_size) % repeat_size)); } @@ -2349,24 +2041,21 @@ QPDFJob::handleUnderOverlay(QPDF& pdf) validateUnderOverlay(pdf, &m->underlay); validateUnderOverlay(pdf, &m->overlay); if ((nullptr == m->underlay.pdf.get()) && - (nullptr == m->overlay.pdf.get())) - { + (nullptr == m->overlay.pdf.get())) { return; } - std::map > underlay_pagenos; + std::map> underlay_pagenos; getUOPagenos(m->underlay, underlay_pagenos); - std::map > overlay_pagenos; + std::map> overlay_pagenos; getUOPagenos(m->overlay, overlay_pagenos); std::map underlay_fo; std::map overlay_fo; std::vector upages; - if (m->underlay.pdf.get()) - { + if (m->underlay.pdf.get()) { upages = QPDFPageDocumentHelper(*(m->underlay.pdf)).getAllPages(); } std::vector opages; - if (m->overlay.pdf.get()) - { + if (m->overlay.pdf.get()) { opages = QPDFPageDocumentHelper(*(m->overlay.pdf)).getAllPages(); } @@ -2376,25 +2065,36 @@ QPDFJob::handleUnderOverlay(QPDF& pdf) doIfVerbose([&](std::ostream& cout, std::string const& prefix) { cout << prefix << ": processing underlay/overlay" << std::endl; }); - for (size_t i = 0; i < main_npages; ++i) - { + for (size_t i = 0; i < main_npages; ++i) { doIfVerbose([&](std::ostream& cout, std::string const& prefix) { - cout << " page " << 1+i << std::endl; + cout << " page " << 1 + i << std::endl; }); - doUnderOverlayForPage(pdf, m->underlay, underlay_pagenos, i, - underlay_fo, upages, main_pages.at(i), - true); - doUnderOverlayForPage(pdf, m->overlay, overlay_pagenos, i, - overlay_fo, opages, main_pages.at(i), - false); - } -} - -static void maybe_set_pagemode(QPDF& pdf, std::string const& pagemode) + doUnderOverlayForPage( + pdf, + m->underlay, + underlay_pagenos, + i, + underlay_fo, + upages, + main_pages.at(i), + true); + doUnderOverlayForPage( + pdf, + m->overlay, + overlay_pagenos, + i, + overlay_fo, + opages, + main_pages.at(i), + false); + } +} + +static void +maybe_set_pagemode(QPDF& pdf, std::string const& pagemode) { auto root = pdf.getRoot(); - if (root.getKey("/PageMode").isNull()) - { + if (root.getKey("/PageMode").isNull()) { root.replaceKey("/PageMode", QPDFObjectHandle::newName(pagemode)); } } @@ -2405,50 +2105,40 @@ QPDFJob::addAttachments(QPDF& pdf) maybe_set_pagemode(pdf, "/UseAttachments"); QPDFEmbeddedFileDocumentHelper efdh(pdf); std::vector duplicated_keys; - for (auto const& to_add: m->attachments_to_add) - { - if ((! to_add.replace) && efdh.getEmbeddedFile(to_add.key)) - { + for (auto const& to_add : m->attachments_to_add) { + if ((!to_add.replace) && efdh.getEmbeddedFile(to_add.key)) { duplicated_keys.push_back(to_add.key); continue; } auto fs = QPDFFileSpecObjectHelper::createFileSpec( pdf, to_add.filename, to_add.path); - if (! to_add.description.empty()) - { + if (!to_add.description.empty()) { fs.setDescription(to_add.description); } auto efs = QPDFEFStreamObjectHelper(fs.getEmbeddedFileStream()); - efs.setCreationDate(to_add.creationdate) - .setModDate(to_add.moddate); - if (! to_add.mimetype.empty()) - { + efs.setCreationDate(to_add.creationdate).setModDate(to_add.moddate); + if (!to_add.mimetype.empty()) { efs.setSubtype(to_add.mimetype); } efdh.replaceEmbeddedFile(to_add.key, fs); doIfVerbose([&](std::ostream& cout, std::string const& prefix) { - cout << prefix << ": attached " << to_add.path - << " as " << to_add.filename - << " with key " << to_add.key << std::endl; + cout << prefix << ": attached " << to_add.path << " as " + << to_add.filename << " with key " << to_add.key << std::endl; }); } - if (! duplicated_keys.empty()) - { + if (!duplicated_keys.empty()) { std::string message; - for (auto const& k: duplicated_keys) - { - if (! message.empty()) - { + for (auto const& k : duplicated_keys) { + if (!message.empty()) { message += ", "; } message += k; } message = pdf.getFilename() + - " already has attachments with the following keys: " + - message + + " already has attachments with the following keys: " + message + "; use --replace to replace or --key to specify a different key"; throw std::runtime_error(message); } @@ -2460,58 +2150,49 @@ QPDFJob::copyAttachments(QPDF& pdf) maybe_set_pagemode(pdf, "/UseAttachments"); QPDFEmbeddedFileDocumentHelper efdh(pdf); std::vector duplicates; - for (auto const& to_copy: m->attachments_to_copy) - { + for (auto const& to_copy : m->attachments_to_copy) { doIfVerbose([&](std::ostream& cout, std::string const& prefix) { - cout << prefix << ": copying attachments from " - << to_copy.path << std::endl; + cout << prefix << ": copying attachments from " << to_copy.path + << std::endl; }); - auto other = processFile( - to_copy.path.c_str(), to_copy.password.c_str(), false); + auto other = + processFile(to_copy.path.c_str(), to_copy.password.c_str(), false); QPDFEmbeddedFileDocumentHelper other_efdh(*other); auto other_attachments = other_efdh.getEmbeddedFiles(); - for (auto const& iter: other_attachments) - { + for (auto const& iter : other_attachments) { std::string new_key = to_copy.prefix + iter.first; - if (efdh.getEmbeddedFile(new_key)) - { + if (efdh.getEmbeddedFile(new_key)) { duplicates.push_back( "file: " + to_copy.path + ", key: " + new_key); - } - else - { - auto new_fs_oh = pdf.copyForeignObject( - iter.second->getObjectHandle()); + } else { + auto new_fs_oh = + pdf.copyForeignObject(iter.second->getObjectHandle()); efdh.replaceEmbeddedFile( new_key, QPDFFileSpecObjectHelper(new_fs_oh)); - doIfVerbose([&](std::ostream& cout, - std::string const& prefix) { + doIfVerbose([&](std::ostream& cout, std::string const& prefix) { cout << " " << iter.first << " -> " << new_key << std::endl; }); } } - if (other->anyWarnings()) - { + if (other->anyWarnings()) { this->m->warnings = true; } } - if (! duplicates.empty()) - { + if (!duplicates.empty()) { std::string message; - for (auto const& i: duplicates) - { - if (! message.empty()) - { + for (auto const& i : duplicates) { + if (!message.empty()) { message += "; "; } message += i; } message = pdf.getFilename() + " already has attachments with keys that conflict with" - " attachments from other files: " + message + + " attachments from other files: " + + message + ". Use --prefix with --copy-attachments-from" " or manually copy individual attachments."; throw std::runtime_error(message); @@ -2524,44 +2205,43 @@ QPDFJob::handleTransformations(QPDF& pdf) QPDFPageDocumentHelper dh(pdf); std::shared_ptr afdh; auto make_afdh = [&]() { - if (! afdh.get()) - { + if (!afdh.get()) { afdh = std::make_shared(pdf); } }; if (m->externalize_inline_images || - (m->optimize_images && (! m->keep_inline_images))) - { + (m->optimize_images && (!m->keep_inline_images))) { std::vector pages = dh.getAllPages(); for (std::vector::iterator iter = pages.begin(); - iter != pages.end(); ++iter) - { + iter != pages.end(); + ++iter) { QPDFPageObjectHelper& ph(*iter); ph.externalizeInlineImages(m->ii_min_bytes); } } - if (m->optimize_images) - { + if (m->optimize_images) { int pageno = 0; std::vector pages = dh.getAllPages(); for (std::vector::iterator iter = pages.begin(); - iter != pages.end(); ++iter) - { + iter != pages.end(); + ++iter) { ++pageno; QPDFPageObjectHelper& ph(*iter); QPDFObjectHandle page = ph.getObjectHandle(); std::map images = ph.getImages(); - for (auto& iter2: images) - { + for (auto& iter2 : images) { std::string name = iter2.first; QPDFObjectHandle& image = iter2.second; ImageOptimizer* io = new ImageOptimizer( - *this, m->oi_min_width, m->oi_min_height, - m->oi_min_area, image); + *this, + m->oi_min_width, + m->oi_min_height, + m->oi_min_area, + image); PointerHolder sdp(io); - if (io->evaluate("image " + name + " on page " + - QUtil::int_to_string(pageno))) - { + if (io->evaluate( + "image " + name + " on page " + + QUtil::int_to_string(pageno))) { QPDFObjectHandle new_image = QPDFObjectHandle::newStream(&pdf); new_image.replaceDict(image.getDict().shallowCopy()); @@ -2569,69 +2249,55 @@ QPDFJob::handleTransformations(QPDF& pdf) sdp, QPDFObjectHandle::newName("/DCTDecode"), QPDFObjectHandle::newNull()); - ph.getAttribute("/Resources", true). - getKey("/XObject").replaceKey( - name, new_image); + ph.getAttribute("/Resources", true) + .getKey("/XObject") + .replaceKey(name, new_image); } } } } - if (m->generate_appearances) - { + if (m->generate_appearances) { make_afdh(); afdh->generateAppearancesIfNeeded(); } - if (m->flatten_annotations) - { - dh.flattenAnnotations(m->flatten_annotations_required, - m->flatten_annotations_forbidden); + if (m->flatten_annotations) { + dh.flattenAnnotations( + m->flatten_annotations_required, m->flatten_annotations_forbidden); } - if (m->coalesce_contents) - { + if (m->coalesce_contents) { std::vector pages = dh.getAllPages(); for (std::vector::iterator iter = pages.begin(); - iter != pages.end(); ++iter) - { + iter != pages.end(); + ++iter) { (*iter).coalesceContentStreams(); } } - if (m->flatten_rotation) - { + if (m->flatten_rotation) { make_afdh(); - for (auto& page: dh.getAllPages()) - { + for (auto& page : dh.getAllPages()) { page.flattenRotation(afdh.get()); } } - if (m->remove_page_labels) - { + if (m->remove_page_labels) { pdf.getRoot().removeKey("/PageLabels"); } - if (! m->attachments_to_remove.empty()) - { + if (!m->attachments_to_remove.empty()) { QPDFEmbeddedFileDocumentHelper efdh(pdf); - for (auto const& key: m->attachments_to_remove) - { - if (efdh.removeEmbeddedFile(key)) - { - doIfVerbose([&](std::ostream& cout, - std::string const& prefix) { - cout << prefix << - ": removed attachment " << key << std::endl; + for (auto const& key : m->attachments_to_remove) { + if (efdh.removeEmbeddedFile(key)) { + doIfVerbose([&](std::ostream& cout, std::string const& prefix) { + cout << prefix << ": removed attachment " << key + << std::endl; }); - } - else - { + } else { throw std::runtime_error("attachment " + key + " not found"); } } } - if (! m->attachments_to_add.empty()) - { + if (!m->attachments_to_add.empty()) { addAttachments(pdf); } - if (! m->attachments_to_copy.empty()) - { + if (!m->attachments_to_copy.empty()) { copyAttachments(pdf); } } @@ -2639,12 +2305,9 @@ QPDFJob::handleTransformations(QPDF& pdf) bool QPDFJob::shouldRemoveUnreferencedResources(QPDF& pdf) { - if (m->remove_unreferenced_page_resources == QPDFJob::re_no) - { + if (m->remove_unreferenced_page_resources == QPDFJob::re_no) { return false; - } - else if (m->remove_unreferenced_page_resources == QPDFJob::re_yes) - { + } else if (m->remove_unreferenced_page_resources == QPDFJob::re_yes) { return true; } @@ -2658,8 +2321,8 @@ QPDFJob::shouldRemoveUnreferencedResources(QPDF& pdf) // Return true as soon as we find any shared resources. - std::set resources_seen; // shared resources detection - std::set nodes_seen; // loop detection + std::set resources_seen; // shared resources detection + std::set nodes_seen; // loop detection doIfVerbose([&](std::ostream& cout, std::string const& prefix) { cout << prefix << ": " << pdf.getFilename() @@ -2668,90 +2331,70 @@ QPDFJob::shouldRemoveUnreferencedResources(QPDF& pdf) std::list queue; queue.push_back(pdf.getRoot().getKey("/Pages")); - while (! queue.empty()) - { + while (!queue.empty()) { QPDFObjectHandle node = *queue.begin(); queue.pop_front(); QPDFObjGen og = node.getObjGen(); - if (nodes_seen.count(og)) - { + if (nodes_seen.count(og)) { continue; } nodes_seen.insert(og); QPDFObjectHandle dict = node.isStream() ? node.getDict() : node; QPDFObjectHandle kids = dict.getKey("/Kids"); - if (kids.isArray()) - { + if (kids.isArray()) { // This is a non-leaf node. - if (dict.hasKey("/Resources")) - { + if (dict.hasKey("/Resources")) { QTC::TC("qpdf", "QPDFJob found resources in non-leaf"); - doIfVerbose([&](std::ostream& cout, - std::string const& prefix) { + doIfVerbose([&](std::ostream& cout, std::string const& prefix) { cout << " found resources in non-leaf page node " - << og.getObj() << " " << og.getGen() - << std::endl; + << og.getObj() << " " << og.getGen() << std::endl; }); return true; } int n = kids.getArrayNItems(); - for (int i = 0; i < n; ++i) - { + for (int i = 0; i < n; ++i) { queue.push_back(kids.getArrayItem(i)); } - } - else - { + } else { // This is a leaf node or a form XObject. QPDFObjectHandle resources = dict.getKey("/Resources"); - if (resources.isIndirect()) - { + if (resources.isIndirect()) { QPDFObjGen resources_og = resources.getObjGen(); - if (resources_seen.count(resources_og)) - { + if (resources_seen.count(resources_og)) { QTC::TC("qpdf", "QPDFJob found shared resources in leaf"); - doIfVerbose([&](std::ostream& cout, - std::string const& prefix) { - cout << " found shared resources in leaf node " - << og.getObj() << " " << og.getGen() - << ": " - << resources_og.getObj() << " " - << resources_og.getGen() - << std::endl; - }); + doIfVerbose( + [&](std::ostream& cout, std::string const& prefix) { + cout << " found shared resources in leaf node " + << og.getObj() << " " << og.getGen() << ": " + << resources_og.getObj() << " " + << resources_og.getGen() << std::endl; + }); return true; } resources_seen.insert(resources_og); } - QPDFObjectHandle xobject = (resources.isDictionary() ? - resources.getKey("/XObject") : - QPDFObjectHandle::newNull()); - if (xobject.isIndirect()) - { + QPDFObjectHandle xobject = + (resources.isDictionary() ? resources.getKey("/XObject") + : QPDFObjectHandle::newNull()); + if (xobject.isIndirect()) { QPDFObjGen xobject_og = xobject.getObjGen(); - if (resources_seen.count(xobject_og)) - { + if (resources_seen.count(xobject_og)) { QTC::TC("qpdf", "QPDFJob found shared xobject in leaf"); - doIfVerbose([&](std::ostream& cout, - std::string const& prefix) { - cout << " found shared xobject in leaf node " - << og.getObj() << " " << og.getGen() - << ": " - << xobject_og.getObj() << " " - << xobject_og.getGen() - << std::endl; - }); + doIfVerbose( + [&](std::ostream& cout, std::string const& prefix) { + cout << " found shared xobject in leaf node " + << og.getObj() << " " << og.getGen() << ": " + << xobject_og.getObj() << " " + << xobject_og.getGen() << std::endl; + }); return true; } resources_seen.insert(xobject_og); } - if (xobject.isDictionary()) - { - for (auto const& k: xobject.getKeys()) - { + if (xobject.isDictionary()) { + for (auto const& k : xobject.getKeys()) { QPDFObjectHandle xobj = xobject.getKey(k); - if (xobj.isFormXObject()) - { + if (xobj.isFormXObject()) { queue.push_back(xobj); } } @@ -2765,11 +2408,11 @@ QPDFJob::shouldRemoveUnreferencedResources(QPDF& pdf) return false; } -static QPDFObjectHandle added_page(QPDF& pdf, QPDFObjectHandle page) +static QPDFObjectHandle +added_page(QPDF& pdf, QPDFObjectHandle page) { QPDFObjectHandle result = page; - if (page.getOwningQPDF() != &pdf) - { + if (page.getOwningQPDF() != &pdf) { // Calling copyForeignObject on an object we already copied // will give us the already existing copy. result = pdf.copyForeignObject(page); @@ -2777,48 +2420,46 @@ static QPDFObjectHandle added_page(QPDF& pdf, QPDFObjectHandle page) return result; } -static QPDFObjectHandle added_page(QPDF& pdf, QPDFPageObjectHelper page) +static QPDFObjectHandle +added_page(QPDF& pdf, QPDFPageObjectHelper page) { return added_page(pdf, page.getObjectHandle()); } void QPDFJob::handlePageSpecs( - QPDF& pdf, bool& warnings, - std::vector>& page_heap) + QPDF& pdf, bool& warnings, std::vector>& page_heap) { // Parse all page specifications and translate them into lists of // actual pages. // Handle "." as a shortcut for the input file for (std::vector::iterator iter = m->page_specs.begin(); - iter != m->page_specs.end(); ++iter) - { + iter != m->page_specs.end(); + ++iter) { QPDFJob::PageSpec& page_spec = *iter; - if (page_spec.filename == ".") - { + if (page_spec.filename == ".") { page_spec.filename = m->infilename.get(); } } - if (! m->keep_files_open_set) - { + if (!m->keep_files_open_set) { // Count the number of distinct files to determine whether we // should keep files open or not. Rather than trying to code // some portable heuristic based on OS limits, just hard-code // this at a given number and allow users to override. std::set filenames; - for (auto& page_spec: m->page_specs) - { + for (auto& page_spec : m->page_specs) { filenames.insert(page_spec.filename); } m->keep_files_open = (filenames.size() <= m->keep_files_open_threshold); - QTC::TC("qpdf", "QPDFJob automatically set keep files open", - m->keep_files_open ? 0 : 1); + QTC::TC( + "qpdf", + "QPDFJob automatically set keep files open", + m->keep_files_open ? 0 : 1); doIfVerbose([&](std::ostream& cout, std::string const& prefix) { cout << prefix << ": selecting --keep-open-files=" - << (m->keep_files_open ? "y" : "n") - << std::endl; + << (m->keep_files_open ? "y" : "n") << std::endl; }); } @@ -2827,13 +2468,12 @@ QPDFJob::handlePageSpecs( std::map page_spec_cfis; page_spec_qpdfs[m->infilename.get()] = &pdf; std::vector parsed_specs; - std::map > copied_pages; + std::map> copied_pages; for (std::vector::iterator iter = m->page_specs.begin(); - iter != m->page_specs.end(); ++iter) - { + iter != m->page_specs.end(); + ++iter) { QPDFJob::PageSpec& page_spec = *iter; - if (page_spec_qpdfs.count(page_spec.filename) == 0) - { + if (page_spec_qpdfs.count(page_spec.filename) == 0) { // Open the PDF file and store the QPDF object. Throw a // std::shared_ptr to the qpdf into a heap so that it // survives through copying to the output but gets cleaned up @@ -2845,38 +2485,33 @@ QPDFJob::handlePageSpecs( // to the same underlying file with the same path to // achieve the same affect. char const* password = page_spec.password.get(); - if ((! m->encryption_file.empty()) && (password == 0) && - (page_spec.filename == m->encryption_file)) - { + if ((!m->encryption_file.empty()) && (password == 0) && + (page_spec.filename == m->encryption_file)) { QTC::TC("qpdf", "QPDFJob pages encryption password"); password = m->encryption_file_password.get(); } doIfVerbose([&](std::ostream& cout, std::string const& prefix) { - cout << prefix << ": processing " - << page_spec.filename << std::endl; + cout << prefix << ": processing " << page_spec.filename + << std::endl; }); PointerHolder is; ClosedFileInputSource* cis = 0; - if (! m->keep_files_open) - { + if (!m->keep_files_open) { QTC::TC("qpdf", "QPDFJob keep files open n"); cis = new ClosedFileInputSource(page_spec.filename.c_str()); is = PointerHolder(cis); cis->stayOpen(true); - } - else - { + } else { QTC::TC("qpdf", "QPDFJob keep files open y"); FileInputSource* fis = new FileInputSource(); is = PointerHolder(fis); fis->setFilename(page_spec.filename.c_str()); } - std::shared_ptr qpdf_ph = processInputSource( - is, password, true); + std::shared_ptr qpdf_ph = + processInputSource(is, password, true); page_heap.push_back(qpdf_ph); page_spec_qpdfs[page_spec.filename] = qpdf_ph.get(); - if (cis) - { + if (cis) { cis->stayOpen(false); page_spec_cfis[page_spec.filename] = cis; } @@ -2884,35 +2519,31 @@ QPDFJob::handlePageSpecs( // Read original pages from the PDF, and parse the page range // associated with this occurrence of the file. - parsed_specs.push_back( - QPDFPageData(page_spec.filename, - page_spec_qpdfs[page_spec.filename], - page_spec.range)); + parsed_specs.push_back(QPDFPageData( + page_spec.filename, + page_spec_qpdfs[page_spec.filename], + page_spec.range)); } std::map remove_unreferenced; - if (m->remove_unreferenced_page_resources != QPDFJob::re_no) - { + if (m->remove_unreferenced_page_resources != QPDFJob::re_no) { for (std::map::iterator iter = page_spec_qpdfs.begin(); - iter != page_spec_qpdfs.end(); ++iter) - { + iter != page_spec_qpdfs.end(); + ++iter) { std::string const& filename = (*iter).first; ClosedFileInputSource* cis = 0; - if (page_spec_cfis.count(filename)) - { + if (page_spec_cfis.count(filename)) { cis = page_spec_cfis[filename]; cis->stayOpen(true); } QPDF& other(*((*iter).second)); auto other_uuid = other.getUniqueId(); - if (remove_unreferenced.count(other_uuid) == 0) - { + if (remove_unreferenced.count(other_uuid) == 0) { remove_unreferenced[other_uuid] = shouldRemoveUnreferencedResources(other); } - if (cis) - { + if (cis) { cis->stayOpen(false); } } @@ -2924,21 +2555,18 @@ QPDFJob::handlePageSpecs( // things in the original file, such as outlines, to continue to // work. doIfVerbose([&](std::ostream& cout, std::string const& prefix) { - cout << prefix - << ": removing unreferenced pages from primary input" + cout << prefix << ": removing unreferenced pages from primary input" << std::endl; }); QPDFPageDocumentHelper dh(pdf); std::vector orig_pages = dh.getAllPages(); - for (std::vector::iterator iter = - orig_pages.begin(); - iter != orig_pages.end(); ++iter) - { + for (std::vector::iterator iter = orig_pages.begin(); + iter != orig_pages.end(); + ++iter) { dh.removePage(*iter); } - if (m->collate && (parsed_specs.size() > 1)) - { + if (m->collate && (parsed_specs.size() > 1)) { // Collate the pages by selecting one page from each spec in // order. When a spec runs out of pages, stop selecting from // it. @@ -2946,21 +2574,16 @@ QPDFJob::handlePageSpecs( size_t nspecs = parsed_specs.size(); size_t cur_page = 0; bool got_pages = true; - while (got_pages) - { + while (got_pages) { got_pages = false; - for (size_t i = 0; i < nspecs; ++i) - { + for (size_t i = 0; i < nspecs; ++i) { QPDFPageData& page_data = parsed_specs.at(i); - for (size_t j = 0; j < m->collate; ++j) - { - if (cur_page + j < page_data.selected_pages.size()) - { + for (size_t j = 0; j < m->collate; ++j) { + if (cur_page + j < page_data.selected_pages.size()) { got_pages = true; - new_parsed_specs.push_back( - QPDFPageData( - page_data, - page_data.selected_pages.at(cur_page + j))); + new_parsed_specs.push_back(QPDFPageData( + page_data, + page_data.selected_pages.at(cur_page + j))); } } } @@ -2976,64 +2599,56 @@ QPDFJob::handlePageSpecs( std::vector new_labels; bool any_page_labels = false; int out_pageno = 0; - std::map> afdh_map; + std::map> + afdh_map; auto this_afdh = get_afdh_for_qpdf(afdh_map, &pdf); std::set referenced_fields; - for (std::vector::iterator iter = - parsed_specs.begin(); - iter != parsed_specs.end(); ++iter) - { + for (std::vector::iterator iter = parsed_specs.begin(); + iter != parsed_specs.end(); + ++iter) { QPDFPageData& page_data = *iter; ClosedFileInputSource* cis = 0; - if (page_spec_cfis.count(page_data.filename)) - { + if (page_spec_cfis.count(page_data.filename)) { cis = page_spec_cfis[page_data.filename]; cis->stayOpen(true); } QPDFPageLabelDocumentHelper pldh(*page_data.qpdf); auto other_afdh = get_afdh_for_qpdf(afdh_map, page_data.qpdf); - if (pldh.hasPageLabels()) - { + if (pldh.hasPageLabels()) { any_page_labels = true; } doIfVerbose([&](std::ostream& cout, std::string const& prefix) { - cout << prefix << ": adding pages from " - << page_data.filename << std::endl; + cout << prefix << ": adding pages from " << page_data.filename + << std::endl; }); for (std::vector::iterator pageno_iter = page_data.selected_pages.begin(); pageno_iter != page_data.selected_pages.end(); - ++pageno_iter, ++out_pageno) - { + ++pageno_iter, ++out_pageno) { // Pages are specified from 1 but numbered from 0 in the // vector int pageno = *pageno_iter - 1; - pldh.getLabelsForPageRange(pageno, pageno, out_pageno, - new_labels); + pldh.getLabelsForPageRange(pageno, pageno, out_pageno, new_labels); QPDFPageObjectHelper to_copy = page_data.orig_pages.at(QIntC::to_size(pageno)); QPDFObjGen to_copy_og = to_copy.getObjectHandle().getObjGen(); unsigned long long from_uuid = page_data.qpdf->getUniqueId(); - if (copied_pages[from_uuid].count(to_copy_og)) - { - QTC::TC("qpdf", "QPDFJob copy same page more than once", - (page_data.qpdf == &pdf) ? 0 : 1); + if (copied_pages[from_uuid].count(to_copy_og)) { + QTC::TC( + "qpdf", + "QPDFJob copy same page more than once", + (page_data.qpdf == &pdf) ? 0 : 1); to_copy = to_copy.shallowCopyPage(); - } - else - { + } else { copied_pages[from_uuid].insert(to_copy_og); - if (remove_unreferenced[from_uuid]) - { + if (remove_unreferenced[from_uuid]) { to_copy.removeUnreferencedResources(); } } dh.addPage(to_copy, false); bool first_copy_from_orig = false; bool this_file = (page_data.qpdf == &pdf); - if (this_file) - { + if (this_file) { // This is a page from the original file. Keep track // of the fact that we are using it. first_copy_from_orig = (selected_from_orig.count(pageno) == 0); @@ -3051,47 +2666,40 @@ QPDFJob::handlePageSpecs( // more than once, that page would be in conflict with the // previous copy of itself. if (other_afdh->hasAcroForm() && - ((! this_file) || (! first_copy_from_orig))) - { - if (! this_file) - { + ((!this_file) || (!first_copy_from_orig))) { + if (!this_file) { QTC::TC("qpdf", "QPDFJob copy fields not this file"); - } - else if (! first_copy_from_orig) - { + } else if (!first_copy_from_orig) { QTC::TC("qpdf", "QPDFJob copy fields non-first from orig"); } - try - { + try { this_afdh->fixCopiedAnnotations( - new_page, to_copy.getObjectHandle(), *other_afdh, + new_page, + to_copy.getObjectHandle(), + *other_afdh, &referenced_fields); - } - catch (std::exception& e) - { - pdf.warn( - QPDFExc(qpdf_e_damaged_pdf, pdf.getFilename(), - "", 0, "Exception caught while fixing copied" - " annotations. This may be a qpdf bug. " + - std::string("Exception: ") + e.what())); + } catch (std::exception& e) { + pdf.warn(QPDFExc( + qpdf_e_damaged_pdf, + pdf.getFilename(), + "", + 0, + "Exception caught while fixing copied" + " annotations. This may be a qpdf bug. " + + std::string("Exception: ") + e.what())); } } } - if (page_data.qpdf->anyWarnings()) - { + if (page_data.qpdf->anyWarnings()) { warnings = true; } - if (cis) - { + if (cis) { cis->stayOpen(false); } } - if (any_page_labels) - { - QPDFObjectHandle page_labels = - QPDFObjectHandle::newDictionary(); - page_labels.replaceKey( - "/Nums", QPDFObjectHandle::newArray(new_labels)); + if (any_page_labels) { + QPDFObjectHandle page_labels = QPDFObjectHandle::newDictionary(); + page_labels.replaceKey("/Nums", QPDFObjectHandle::newArray(new_labels)); pdf.getRoot().replaceKey("/PageLabels", page_labels); } @@ -3099,50 +2707,37 @@ QPDFJob::handlePageSpecs( // those objects from being preserved by being referred to from // other places, such as the outlines dictionary. Also make sure // we keep form fields from pages we preserved. - for (size_t pageno = 0; pageno < orig_pages.size(); ++pageno) - { + for (size_t pageno = 0; pageno < orig_pages.size(); ++pageno) { auto page = orig_pages.at(pageno); - if (selected_from_orig.count(QIntC::to_int(pageno))) - { - for (auto field: this_afdh->getFormFieldsForPage(page)) - { + if (selected_from_orig.count(QIntC::to_int(pageno))) { + for (auto field : this_afdh->getFormFieldsForPage(page)) { QTC::TC("qpdf", "QPDFJob pages keeping field from original"); referenced_fields.insert(field.getObjectHandle().getObjGen()); } - } - else - { + } else { pdf.replaceObject( page.getObjectHandle().getObjGen(), QPDFObjectHandle::newNull()); } } // Remove unreferenced form fields - if (this_afdh->hasAcroForm()) - { + if (this_afdh->hasAcroForm()) { auto acroform = pdf.getRoot().getKey("/AcroForm"); auto fields = acroform.getKey("/Fields"); - if (fields.isArray()) - { + if (fields.isArray()) { auto new_fields = QPDFObjectHandle::newArray(); - if (fields.isIndirect()) - { + if (fields.isIndirect()) { new_fields = pdf.makeIndirectObject(new_fields); } - for (auto const& field: fields.aitems()) - { - if (referenced_fields.count(field.getObjGen())) - { + for (auto const& field : fields.aitems()) { + if (referenced_fields.count(field.getObjGen())) { new_fields.appendItem(field); } } - if (new_fields.getArrayNItems() > 0) - { + if (new_fields.getArrayNItems() > 0) { QTC::TC("qpdf", "QPDFJob keep some fields in pages"); acroform.replaceKey("/Fields", new_fields); - } - else - { + } else { QTC::TC("qpdf", "QPDFJob no more fields in pages"); pdf.getRoot().removeKey("/AcroForm"); } @@ -3158,21 +2753,20 @@ QPDFJob::handleRotations(QPDF& pdf) int npages = QIntC::to_int(pages.size()); for (std::map::iterator iter = m->rotations.begin(); - iter != m->rotations.end(); ++iter) - { + iter != m->rotations.end(); + ++iter) { std::string const& range = (*iter).first; QPDFJob::RotationSpec const& rspec = (*iter).second; // range has been previously validated std::vector to_rotate = QUtil::parse_numrange(range.c_str(), npages); for (std::vector::iterator i2 = to_rotate.begin(); - i2 != to_rotate.end(); ++i2) - { + i2 != to_rotate.end(); + ++i2) { int pageno = *i2 - 1; - if ((pageno >= 0) && (pageno < npages)) - { - pages.at(QIntC::to_size(pageno)).rotatePage( - rspec.angle, rspec.relative); + if ((pageno >= 0) && (pageno < npages)) { + pages.at(QIntC::to_size(pageno)) + .rotatePage(rspec.angle, rspec.relative); } } } @@ -3181,44 +2775,36 @@ QPDFJob::handleRotations(QPDF& pdf) void QPDFJob::maybeFixWritePassword(int R, std::string& password) { - switch (m->password_mode) - { - case QPDFJob::pm_bytes: + switch (m->password_mode) { + case QPDFJob::pm_bytes: QTC::TC("qpdf", "QPDFJob password mode bytes"); break; - case QPDFJob::pm_hex_bytes: + case QPDFJob::pm_hex_bytes: QTC::TC("qpdf", "QPDFJob password mode hex-bytes"); password = QUtil::hex_decode(password); break; - case QPDFJob::pm_unicode: - case QPDFJob::pm_auto: + case QPDFJob::pm_unicode: + case QPDFJob::pm_auto: { bool has_8bit_chars; bool is_valid_utf8; bool is_utf16; - QUtil::analyze_encoding(password, - has_8bit_chars, - is_valid_utf8, - is_utf16); - if (! has_8bit_chars) - { + QUtil::analyze_encoding( + password, has_8bit_chars, is_valid_utf8, is_utf16); + if (!has_8bit_chars) { return; } - if (m->password_mode == QPDFJob::pm_unicode) - { - if (! is_valid_utf8) - { + if (m->password_mode == QPDFJob::pm_unicode) { + if (!is_valid_utf8) { QTC::TC("qpdf", "QPDFJob password not unicode"); throw std::runtime_error( "supplied password is not valid UTF-8"); } - if (R < 5) - { + if (R < 5) { std::string encoded; - if (! QUtil::utf8_to_pdf_doc(password, encoded)) - { + if (!QUtil::utf8_to_pdf_doc(password, encoded)) { QTC::TC("qpdf", "QPDFJob password not encodable"); throw std::runtime_error( "supplied password cannot be encoded for" @@ -3226,28 +2812,21 @@ QPDFJob::maybeFixWritePassword(int R, std::string& password) } password = encoded; } - } - else - { - if ((R < 5) && is_valid_utf8) - { + } else { + if ((R < 5) && is_valid_utf8) { std::string encoded; - if (QUtil::utf8_to_pdf_doc(password, encoded)) - { + if (QUtil::utf8_to_pdf_doc(password, encoded)) { QTC::TC("qpdf", "QPDFJob auto-encode password"); - doIfVerbose([&](std::ostream& cout, - std::string const& prefix) { - cout - << prefix - << ": automatically converting Unicode" - << " password to single-byte encoding as" - << " required for 40-bit or 128-bit" - << " encryption" << std::endl; - }); + doIfVerbose( + [&](std::ostream& cout, std::string const& prefix) { + cout << prefix + << ": automatically converting Unicode" + << " password to single-byte encoding as" + << " required for 40-bit or 128-bit" + << " encryption" << std::endl; + }); password = encoded; - } - else - { + } else { QTC::TC("qpdf", "QPDFJob bytes fallback warning"); *(this->m->cerr) << this->m->message_prefix << ": WARNING: " @@ -3260,9 +2839,7 @@ QPDFJob::maybeFixWritePassword(int R, std::string& password) << " warning and use the password anyway.)" << std::endl; } - } - else if ((R >= 5) && (! is_valid_utf8)) - { + } else if ((R >= 5) && (!is_valid_utf8)) { QTC::TC("qpdf", "QPDFJob invalid utf-8 in auto"); throw std::runtime_error( "supplied password is not a valid Unicode password," @@ -3280,49 +2857,32 @@ void QPDFJob::setEncryptionOptions(QPDF& pdf, QPDFWriter& w) { int R = 0; - if (m->keylen == 40) - { + if (m->keylen == 40) { R = 2; - } - else if (m->keylen == 128) - { - if (m->force_V4 || m->cleartext_metadata || m->use_aes) - { + } else if (m->keylen == 128) { + if (m->force_V4 || m->cleartext_metadata || m->use_aes) { R = 4; - } - else - { + } else { R = 3; } - } - else if (m->keylen == 256) - { - if (m->force_R5) - { + } else if (m->keylen == 256) { + if (m->force_R5) { R = 5; - } - else - { + } else { R = 6; } - } - else - { + } else { throw std::logic_error("bad encryption keylen"); } - if ((R > 3) && (m->r3_accessibility == false)) - { - *(this->m->cerr) - << this->m->message_prefix - << ": -accessibility=n is ignored for modern" - << " encryption formats" << std::endl; + if ((R > 3) && (m->r3_accessibility == false)) { + *(this->m->cerr) << this->m->message_prefix + << ": -accessibility=n is ignored for modern" + << " encryption formats" << std::endl; } maybeFixWritePassword(R, m->user_password); maybeFixWritePassword(R, m->owner_password); - if ((R < 4) || ((R == 4) && (! m->use_aes))) - { - if (! m->allow_weak_crypto) - { + if ((R < 4) || ((R == 4) && (!m->use_aes))) { + if (!m->allow_weak_crypto) { // Do not set warnings = true for this case as this does // not reflect a potential problem with the input file. QTC::TC("qpdf", "QPDFJob weak crypto warning"); @@ -3330,68 +2890,92 @@ QPDFJob::setEncryptionOptions(QPDF& pdf, QPDFWriter& w) << this->m->message_prefix << ": writing a file with RC4, a weak cryptographic algorithm" << std::endl - << "Please use 256-bit keys for better security." - << std::endl + << "Please use 256-bit keys for better security." << std::endl << "Pass --allow-weak-crypto to suppress this warning." << std::endl << "This will become an error in a future version of qpdf." << std::endl; } } - switch (R) - { - case 2: + switch (R) { + case 2: w.setR2EncryptionParameters( - m->user_password.c_str(), m->owner_password.c_str(), - m->r2_print, m->r2_modify, m->r2_extract, m->r2_annotate); + m->user_password.c_str(), + m->owner_password.c_str(), + m->r2_print, + m->r2_modify, + m->r2_extract, + m->r2_annotate); break; - case 3: + case 3: w.setR3EncryptionParameters( - m->user_password.c_str(), m->owner_password.c_str(), - m->r3_accessibility, m->r3_extract, - m->r3_assemble, m->r3_annotate_and_form, - m->r3_form_filling, m->r3_modify_other, + m->user_password.c_str(), + m->owner_password.c_str(), + m->r3_accessibility, + m->r3_extract, + m->r3_assemble, + m->r3_annotate_and_form, + m->r3_form_filling, + m->r3_modify_other, m->r3_print); break; - case 4: + case 4: w.setR4EncryptionParameters( - m->user_password.c_str(), m->owner_password.c_str(), - m->r3_accessibility, m->r3_extract, - m->r3_assemble, m->r3_annotate_and_form, - m->r3_form_filling, m->r3_modify_other, - m->r3_print, !m->cleartext_metadata, m->use_aes); + m->user_password.c_str(), + m->owner_password.c_str(), + m->r3_accessibility, + m->r3_extract, + m->r3_assemble, + m->r3_annotate_and_form, + m->r3_form_filling, + m->r3_modify_other, + m->r3_print, + !m->cleartext_metadata, + m->use_aes); break; - case 5: + case 5: w.setR5EncryptionParameters( - m->user_password.c_str(), m->owner_password.c_str(), - m->r3_accessibility, m->r3_extract, - m->r3_assemble, m->r3_annotate_and_form, - m->r3_form_filling, m->r3_modify_other, - m->r3_print, !m->cleartext_metadata); + m->user_password.c_str(), + m->owner_password.c_str(), + m->r3_accessibility, + m->r3_extract, + m->r3_assemble, + m->r3_annotate_and_form, + m->r3_form_filling, + m->r3_modify_other, + m->r3_print, + !m->cleartext_metadata); break; - case 6: + case 6: w.setR6EncryptionParameters( - m->user_password.c_str(), m->owner_password.c_str(), - m->r3_accessibility, m->r3_extract, - m->r3_assemble, m->r3_annotate_and_form, - m->r3_form_filling, m->r3_modify_other, - m->r3_print, !m->cleartext_metadata); + m->user_password.c_str(), + m->owner_password.c_str(), + m->r3_accessibility, + m->r3_extract, + m->r3_assemble, + m->r3_annotate_and_form, + m->r3_form_filling, + m->r3_modify_other, + m->r3_print, + !m->cleartext_metadata); break; - default: + default: throw std::logic_error("bad encryption R value"); break; } } -static void parse_version(std::string const& full_version_string, - std::string& version, int& extension_level) +static void +parse_version( + std::string const& full_version_string, + std::string& version, + int& extension_level) { auto vp = QUtil::make_unique_cstr(full_version_string); char* v = vp.get(); char* p1 = strchr(v, '.'); char* p2 = (p1 ? strchr(1 + p1, '.') : 0); - if (p2 && *(p2 + 1)) - { + if (p2 && *(p2 + 1)) { *p2++ = '\0'; extension_level = QUtil::string_to_int(p2); } @@ -3401,107 +2985,86 @@ static void parse_version(std::string const& full_version_string, void QPDFJob::setWriterOptions(QPDF& pdf, QPDFWriter& w) { - if (m->compression_level >= 0) - { + if (m->compression_level >= 0) { Pl_Flate::setCompressionLevel(m->compression_level); } - if (m->qdf_mode) - { + if (m->qdf_mode) { w.setQDFMode(true); } - if (m->preserve_unreferenced_objects) - { + if (m->preserve_unreferenced_objects) { w.setPreserveUnreferencedObjects(true); } - if (m->newline_before_endstream) - { + if (m->newline_before_endstream) { w.setNewlineBeforeEndstream(true); } - if (m->normalize_set) - { + if (m->normalize_set) { w.setContentNormalization(m->normalize); } - if (m->stream_data_set) - { + if (m->stream_data_set) { w.setStreamDataMode(m->stream_data_mode); } - if (m->compress_streams_set) - { + if (m->compress_streams_set) { w.setCompressStreams(m->compress_streams); } - if (m->recompress_flate_set) - { + if (m->recompress_flate_set) { w.setRecompressFlate(m->recompress_flate); } - if (m->decode_level_set) - { + if (m->decode_level_set) { w.setDecodeLevel(m->decode_level); } - if (m->decrypt) - { + if (m->decrypt) { w.setPreserveEncryption(false); } - if (m->deterministic_id) - { + if (m->deterministic_id) { w.setDeterministicID(true); } - if (m->static_id) - { + if (m->static_id) { w.setStaticID(true); } - if (m->static_aes_iv) - { + if (m->static_aes_iv) { w.setStaticAesIV(true); } - if (m->suppress_original_object_id) - { + if (m->suppress_original_object_id) { w.setSuppressOriginalObjectIDs(true); } - if (m->copy_encryption) - { - std::shared_ptr encryption_pdf = - processFile(m->encryption_file.c_str(), - m->encryption_file_password.get(), false); + if (m->copy_encryption) { + std::shared_ptr encryption_pdf = processFile( + m->encryption_file.c_str(), + m->encryption_file_password.get(), + false); w.copyEncryptionParameters(*encryption_pdf); } - if (m->encrypt) - { + if (m->encrypt) { setEncryptionOptions(pdf, w); } - if (m->linearize) - { + if (m->linearize) { w.setLinearization(true); } - if (! m->linearize_pass1.empty()) - { + if (!m->linearize_pass1.empty()) { w.setLinearizationPass1Filename(m->linearize_pass1); } - if (m->object_stream_set) - { + if (m->object_stream_set) { w.setObjectStreamMode(m->object_stream_mode); } w.setMinimumPDFVersion(this->m->max_input_version); - if (! m->min_version.empty()) - { + if (!m->min_version.empty()) { std::string version; int extension_level = 0; parse_version(m->min_version, version, extension_level); w.setMinimumPDFVersion(version, extension_level); } - if (! m->force_version.empty()) - { + if (!m->force_version.empty()) { std::string version; int extension_level = 0; parse_version(m->force_version, version, extension_level); w.forcePDFVersion(version, extension_level); } - if (m->progress && m->outfilename) - { + if (m->progress && m->outfilename) { w.registerProgressReporter( - PointerHolder( - new ProgressReporter( - *(this->m->cout), this->m->message_prefix, - m->outfilename.get()))); + PointerHolder(new ProgressReporter( + *(this->m->cout), + this->m->message_prefix, + m->outfilename.get()))); } } @@ -3513,29 +3076,25 @@ QPDFJob::doSplitPages(QPDF& pdf, bool& warnings) std::string after; size_t len = strlen(m->outfilename.get()); char* num_spot = strstr(const_cast(m->outfilename.get()), "%d"); - if (num_spot != 0) - { + if (num_spot != 0) { QTC::TC("qpdf", "QPDFJob split-pages %d"); - before = std::string(m->outfilename.get(), - QIntC::to_size(num_spot - m->outfilename.get())); + before = std::string( + m->outfilename.get(), + QIntC::to_size(num_spot - m->outfilename.get())); after = num_spot + 2; - } - else if ((len >= 4) && - (QUtil::str_compare_nocase( - m->outfilename.get() + len - 4, ".pdf") == 0)) - { + } else if ( + (len >= 4) && + (QUtil::str_compare_nocase(m->outfilename.get() + len - 4, ".pdf") == + 0)) { QTC::TC("qpdf", "QPDFJob split-pages .pdf"); before = std::string(m->outfilename.get(), len - 4) + "-"; after = m->outfilename.get() + len - 4; - } - else - { + } else { QTC::TC("qpdf", "QPDFJob split-pages other"); before = std::string(m->outfilename.get()) + "-"; } - if (shouldRemoveUnreferencedResources(pdf)) - { + if (shouldRemoveUnreferencedResources(pdf)) { QPDFPageDocumentHelper dh(pdf); dh.removeUnreferencedResources(); } @@ -3544,70 +3103,60 @@ QPDFJob::doSplitPages(QPDF& pdf, bool& warnings) std::vector const& pages = pdf.getAllPages(); size_t pageno_len = QUtil::uint_to_string(pages.size()).length(); size_t num_pages = pages.size(); - for (size_t i = 0; i < num_pages; i += QIntC::to_size(m->split_pages)) - { + for (size_t i = 0; i < num_pages; i += QIntC::to_size(m->split_pages)) { size_t first = i + 1; size_t last = i + QIntC::to_size(m->split_pages); - if (last > num_pages) - { + if (last > num_pages) { last = num_pages; } QPDF outpdf; outpdf.emptyPDF(); std::shared_ptr out_afdh; - if (afdh.hasAcroForm()) - { + if (afdh.hasAcroForm()) { out_afdh = std::make_shared(outpdf); } - if (m->suppress_warnings) - { + if (m->suppress_warnings) { outpdf.setSuppressWarnings(true); } - for (size_t pageno = first; pageno <= last; ++pageno) - { + for (size_t pageno = first; pageno <= last; ++pageno) { QPDFObjectHandle page = pages.at(pageno - 1); outpdf.addPage(page, false); auto new_page = added_page(outpdf, page); - if (out_afdh.get()) - { + if (out_afdh.get()) { QTC::TC("qpdf", "QPDFJob copy form fields in split_pages"); - try - { + try { out_afdh->fixCopiedAnnotations(new_page, page, afdh); - } - catch (std::exception& e) - { - pdf.warn( - QPDFExc(qpdf_e_damaged_pdf, pdf.getFilename(), - "", 0, "Exception caught while fixing copied" - " annotations. This may be a qpdf bug." + - std::string("Exception: ") + e.what())); + } catch (std::exception& e) { + pdf.warn(QPDFExc( + qpdf_e_damaged_pdf, + pdf.getFilename(), + "", + 0, + "Exception caught while fixing copied" + " annotations. This may be a qpdf bug." + + std::string("Exception: ") + e.what())); } } } - if (pldh.hasPageLabels()) - { + if (pldh.hasPageLabels()) { std::vector labels; pldh.getLabelsForPageRange( QIntC::to_longlong(first - 1), QIntC::to_longlong(last - 1), - 0, labels); - QPDFObjectHandle page_labels = - QPDFObjectHandle::newDictionary(); - page_labels.replaceKey( - "/Nums", QPDFObjectHandle::newArray(labels)); + 0, + labels); + QPDFObjectHandle page_labels = QPDFObjectHandle::newDictionary(); + page_labels.replaceKey("/Nums", QPDFObjectHandle::newArray(labels)); outpdf.getRoot().replaceKey("/PageLabels", page_labels); } std::string page_range = QUtil::uint_to_string(first, QIntC::to_int(pageno_len)); - if (m->split_pages > 1) - { - page_range += "-" + - QUtil::uint_to_string(last, QIntC::to_int(pageno_len)); + if (m->split_pages > 1) { + page_range += + "-" + QUtil::uint_to_string(last, QIntC::to_int(pageno_len)); } std::string outfile = before + page_range + after; - if (QUtil::same_file(m->infilename.get(), outfile.c_str())) - { + if (QUtil::same_file(m->infilename.get(), outfile.c_str())) { throw std::runtime_error( "split pages would overwrite input file with " + outfile); } @@ -3617,8 +3166,7 @@ QPDFJob::doSplitPages(QPDF& pdf, bool& warnings) doIfVerbose([&](std::ostream& cout, std::string const& prefix) { cout << prefix << ": wrote file " << outfile << std::endl; }); - if (outpdf.anyWarnings()) - { + if (outpdf.anyWarnings()) { warnings = true; } } @@ -3628,8 +3176,7 @@ void QPDFJob::writeOutfile(QPDF& pdf) { std::shared_ptr temp_out; - if (m->replace_input) - { + if (m->replace_input) { // Append but don't prepend to the path to generate a // temporary name. This saves us from having to split the path // by directory and non-directory. @@ -3638,9 +3185,7 @@ QPDFJob::writeOutfile(QPDF& pdf) // m->outfilename will be restored to 0 before temp_out // goes out of scope. m->outfilename = temp_out; - } - else if (strcmp(m->outfilename.get(), "-") == 0) - { + } else if (strcmp(m->outfilename.get(), "-") == 0) { m->outfilename = 0; } { @@ -3649,50 +3194,37 @@ QPDFJob::writeOutfile(QPDF& pdf) setWriterOptions(pdf, w); w.write(); } - if (m->outfilename) - { + if (m->outfilename) { doIfVerbose([&](std::ostream& cout, std::string const& prefix) { cout << prefix << ": wrote file " << m->outfilename << std::endl; }); } - if (m->replace_input) - { + if (m->replace_input) { m->outfilename = 0; } - if (m->replace_input) - { + if (m->replace_input) { // We must close the input before we can rename files pdf.closeInputSource(); std::string backup = std::string(m->infilename.get()) + ".~qpdf-orig"; bool warnings = pdf.anyWarnings(); - if (! warnings) - { + if (!warnings) { backup.append(1, '#'); } QUtil::rename_file(m->infilename.get(), backup.c_str()); QUtil::rename_file(temp_out.get(), m->infilename.get()); - if (warnings) - { - *(this->m->cerr) - << this->m->message_prefix - << ": there are warnings; original file kept in " - << backup << std::endl; - } - else - { - try - { + if (warnings) { + *(this->m->cerr) << this->m->message_prefix + << ": there are warnings; original file kept in " + << backup << std::endl; + } else { + try { QUtil::remove_file(backup.c_str()); - } - catch (QPDFSystemError& e) - { + } catch (QPDFSystemError& e) { *(this->m->cerr) << this->m->message_prefix - << ": unable to delete original file (" - << e.what() << ");" + << ": unable to delete original file (" << e.what() << ");" << " original file left in " << backup - << ", but the input was successfully replaced" - << std::endl; + << ", but the input was successfully replaced" << std::endl; } } } -- cgit v1.2.3-54-g00ecf