aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/qpdf/QPDF.hh20
-rw-r--r--libqpdf/QPDF.cc7
-rw-r--r--libqpdf/QPDFJob.cc1
-rw-r--r--qpdf/qtest/invalid-objects.test7
-rw-r--r--qpdf/qtest/qpdf/catalgg.out6
-rw-r--r--qpdf/qtest/qpdf/catalgg.pdf79
6 files changed, 116 insertions, 4 deletions
diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh
index 13b66977..4541db64 100644
--- a/include/qpdf/QPDF.hh
+++ b/include/qpdf/QPDF.hh
@@ -910,8 +910,7 @@ class QPDF
}
};
- // The ParseGuard class allows QPDFObjectHandle to detect
- // re-entrant parsing.
+ // The ParseGuard class allows QPDFParser to detect re-entrant parsing.
class ParseGuard
{
friend class QPDFParser;
@@ -933,7 +932,7 @@ class QPDF
QPDF* qpdf;
};
- // Pipe class is restricted to QPDF_Stream
+ // Pipe class is restricted to QPDF_Stream.
class Pipe
{
friend class QPDF_Stream;
@@ -961,6 +960,20 @@ class QPDF
}
};
+ // JobSetter class is restricted to QPDFJob.
+ class JobSetter
+ {
+ friend class QPDFJob;
+
+ private:
+ // Enable enhanced warnings for pdf file checking.
+ static void
+ setCheckMode(QPDF& qpdf, bool val)
+ {
+ qpdf.m->check_mode = val;
+ }
+ };
+
// For testing only -- do not add to DLL
static bool test_json_validators();
@@ -1698,6 +1711,7 @@ class QPDF
bool ignore_xref_streams{false};
bool suppress_warnings{false};
bool attempt_recovery{true};
+ bool check_mode{false};
std::shared_ptr<EncryptionParameters> encp;
std::string pdf_version;
std::map<QPDFObjGen, QPDFXRefEntry> xref_table;
diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc
index 69508b08..c6f6ae6e 100644
--- a/libqpdf/QPDF.cc
+++ b/libqpdf/QPDF.cc
@@ -2461,6 +2461,13 @@ QPDF::getRoot()
QPDFObjectHandle root = this->m->trailer.getKey("/Root");
if (!root.isDictionary()) {
throw damagedPDF("", 0, "unable to find /Root dictionary");
+ } else if (
+ // Check_mode is an interim solution to request #810 pending a more
+ // comprehensive review of the approach to more extensive checks and
+ // warning levels.
+ m->check_mode && !root.getKey("/Type").isNameAndEquals("/Catalog")) {
+ warn(damagedPDF("", 0, "catalog /Type entry missing or invalid"));
+ root.replaceKey("/Type", "/Catalog"_qpdf);
}
return root;
}
diff --git a/libqpdf/QPDFJob.cc b/libqpdf/QPDFJob.cc
index 4916be41..b700378e 100644
--- a/libqpdf/QPDFJob.cc
+++ b/libqpdf/QPDFJob.cc
@@ -798,6 +798,7 @@ QPDFJob::doCheck(QPDF& pdf)
bool okay = true;
auto& cout = *this->m->log->getInfo();
cout << "checking " << m->infilename.get() << "\n";
+ QPDF::JobSetter::setCheckMode(pdf, true);
try {
int extension_level = pdf.getExtensionLevel();
cout << "PDF Version: " << pdf.getPDFVersion();
diff --git a/qpdf/qtest/invalid-objects.test b/qpdf/qtest/invalid-objects.test
index 6491ccdb..1ece3810 100644
--- a/qpdf/qtest/invalid-objects.test
+++ b/qpdf/qtest/invalid-objects.test
@@ -14,7 +14,7 @@ cleanup();
my $td = new TestDriver('invalid-objects');
-my $n_tests = 3;
+my $n_tests = 4;
$td->runtest("closed input source",
{$td->COMMAND => "test_driver 73 minimal.pdf"},
@@ -33,5 +33,10 @@ $td->runtest("object with zero offset",
{$td->FILE => "zero-offset.out", $td->EXIT_STATUS => 3},
$td->NORMALIZE_NEWLINES);
+$td->runtest("catalog with invalid type entry",
+ {$td->COMMAND => "qpdf --check catalgg.pdf"},
+ {$td->FILE => "catalgg.out", $td->EXIT_STATUS => 3},
+ $td->NORMALIZE_NEWLINES);
+
cleanup();
$td->report($n_tests);
diff --git a/qpdf/qtest/qpdf/catalgg.out b/qpdf/qtest/qpdf/catalgg.out
new file mode 100644
index 00000000..58fb244c
--- /dev/null
+++ b/qpdf/qtest/qpdf/catalgg.out
@@ -0,0 +1,6 @@
+checking catalgg.pdf
+WARNING: catalgg.pdf: catalog /Type entry missing or invalid
+PDF Version: 1.3
+File is not encrypted
+File is not linearized
+qpdf: operation succeeded with warnings
diff --git a/qpdf/qtest/qpdf/catalgg.pdf b/qpdf/qtest/qpdf/catalgg.pdf
new file mode 100644
index 00000000..7208c4b6
--- /dev/null
+++ b/qpdf/qtest/qpdf/catalgg.pdf
@@ -0,0 +1,79 @@
+%PDF-1.3
+1 0 obj
+<<
+ /Type /Catalgg
+ /Pages 2 0 R
+>>
+endobj
+
+2 0 obj
+<<
+ /Type /Pages
+ /Kids [
+ 3 0 R
+ ]
+ /Count 1
+>>
+endobj
+
+3 0 obj
+<<
+ /Type /Page
+ /Parent 2 0 R
+ /MediaBox [0 0 612 792]
+ /Contents 4 0 R
+ /Resources <<
+ /ProcSet 5 0 R
+ /Font <<
+ /F1 6 0 R
+ >>
+ >>
+>>
+endobj
+
+4 0 obj
+<<
+ /Length 44
+>>
+stream
+BT
+ /F1 24 Tf
+ 72 720 Td
+ (Potato) Tj
+ET
+endstream
+endobj
+
+5 0 obj
+[
+ /PDF
+ /Text
+]
+endobj
+
+6 0 obj
+<<
+ /Type /Font
+ /Subtype /Type1
+ /Name /F1
+ /BaseFont /Helvetica
+ /Encoding /WinAnsiEncoding
+>>
+endobj
+
+xref
+0 7
+0000000000 65535 f
+0000000009 00000 n
+0000000063 00000 n
+0000000135 00000 n
+0000000307 00000 n
+0000000403 00000 n
+0000000438 00000 n
+trailer <<
+ /Size 7
+ /Root 1 0 R
+>>
+startxref
+556
+%%EOF