summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--include/qpdf/QPDFObjectHandle.hh7
-rw-r--r--libqpdf/QPDFObjectHandle.cc19
-rw-r--r--qpdf/qtest/qpdf.test7
-rw-r--r--qpdf/qtest/qpdf/terminate-parsing.out86
-rw-r--r--qpdf/qtest/qpdf/terminate-parsing.pdfbin0 -> 1539 bytes
-rw-r--r--qpdf/test_driver.cc5
7 files changed, 128 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 90b110e2..11d99646 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2013-03-03 Jay Berkenbilt <ejb@ql.org>
+
+ * Add protected terminateParsing method to
+ QPDFObjectHandle::ParserCallbacks that implementor can call to
+ terminate parsing of a content stream.
+
2013-02-28 Jay Berkenbilt <ejb@ql.org>
* Favor fopen_s and strerror_s on MSVC to avoid CRT security
diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh
index e2c8b529..c42fa719 100644
--- a/include/qpdf/QPDFObjectHandle.hh
+++ b/include/qpdf/QPDFObjectHandle.hh
@@ -83,6 +83,13 @@ class QPDFObjectHandle
}
virtual void handleObject(QPDFObjectHandle) = 0;
virtual void handleEOF() = 0;
+
+ protected:
+ // Implementors may call this method during parsing to
+ // terminate parsing early. This method throws an exception
+ // that is caught by parseContentStream, so its effect is
+ // immediate.
+ void terminateParsing();
};
diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc
index e6f53d08..0c6b0a9d 100644
--- a/libqpdf/QPDFObjectHandle.cc
+++ b/libqpdf/QPDFObjectHandle.cc
@@ -23,6 +23,16 @@
#include <stdlib.h>
#include <ctype.h>
+class TerminateParsing
+{
+};
+
+void
+QPDFObjectHandle::ParserCallbacks::terminateParsing()
+{
+ throw TerminateParsing();
+}
+
QPDFObjectHandle::QPDFObjectHandle() :
initialized(false),
objid(0),
@@ -728,7 +738,14 @@ QPDFObjectHandle::parseContentStream(QPDFObjectHandle stream_or_array,
throw std::logic_error(
"QPDFObjectHandle: parseContentStream called on non-stream");
}
- parseContentStream_internal(stream, callbacks);
+ try
+ {
+ parseContentStream_internal(stream, callbacks);
+ }
+ catch (TerminateParsing&)
+ {
+ return;
+ }
}
callbacks->handleEOF();
}
diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test
index 8375e5f2..5ae2ae3c 100644
--- a/qpdf/qtest/qpdf.test
+++ b/qpdf/qtest/qpdf.test
@@ -199,7 +199,7 @@ $td->runtest("remove page we don't have",
show_ntests();
# ----------
$td->notify("--- Miscellaneous Tests ---");
-$n_tests += 61;
+$n_tests += 62;
$td->runtest("qpdf version",
{$td->COMMAND => "qpdf --version"},
@@ -478,6 +478,11 @@ $td->runtest("tokenize content streams",
{$td->FILE => "tokenize-content-streams.out",
$td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
+$td->runtest("terminate parsing",
+ {$td->COMMAND => "test_driver 37 terminate-parsing.pdf"},
+ {$td->FILE => "terminate-parsing.out",
+ $td->EXIT_STATUS => 0},
+ $td->NORMALIZE_NEWLINES);
$td->runtest("content stream errors",
{$td->COMMAND => "qpdf --check content-stream-errors.pdf"},
{$td->FILE => "content-stream-errors.out",
diff --git a/qpdf/qtest/qpdf/terminate-parsing.out b/qpdf/qtest/qpdf/terminate-parsing.out
new file mode 100644
index 00000000..a0050974
--- /dev/null
+++ b/qpdf/qtest/qpdf/terminate-parsing.out
@@ -0,0 +1,86 @@
+name: /potato
+test suite: terminating parsing
+real: 0.1
+integer: 0
+integer: 0
+real: 0.1
+integer: 0
+integer: 0
+operator: cm
+operator: q
+integer: 0
+real: 1.1999
+real: -1.1999
+integer: 0
+real: 121.19
+real: 150.009
+operator: cm
+operator: BI
+name: /CS
+name: /G
+name: /W
+integer: 1
+name: /H
+integer: 1
+name: /BPC
+integer: 8
+name: /F
+name: /Fl
+name: /DP
+dictionary: << /Columns 1 /Predictor 15 >>
+operator: ID
+inline-image: 789c63fc0f0001030101
+operator: EI
+operator: Q
+operator: q
+integer: 0
+real: 35.997
+real: -128.389
+integer: 0
+real: 431.964
+real: 7269.02
+operator: cm
+operator: BI
+name: /CS
+name: /G
+name: /W
+integer: 30
+name: /H
+integer: 107
+name: /BPC
+integer: 8
+name: /F
+name: /Fl
+name: /DP
+dictionary: << /Columns 30 /Predictor 15 >>
+operator: ID
+inline-image: 789cedd1a11100300800b1b2ffd06503148283bc8dfcf8af2a306ee352eff2e06318638c31c63b3801627b620a
+operator: EI
+operator: Q
+operator: q
+integer: 0
+real: 38.3968
+real: -93.5922
+integer: 0
+real: 431.964
+real: 7567.79
+operator: cm
+operator: BI
+name: /CS
+name: /G
+name: /W
+integer: 32
+name: /H
+integer: 78
+name: /BPC
+integer: 8
+name: /F
+name: /Fl
+name: /DP
+dictionary: << /Columns 32 /Predictor 15 >>
+operator: ID
+inline-image: 789c63fccf801f308e2a185530aa60882a20203faa605401890a0643aa1e5530aa6054010d140000bdd03c13
+operator: EI
+operator: Q
+-EOF-
+test 37 done
diff --git a/qpdf/qtest/qpdf/terminate-parsing.pdf b/qpdf/qtest/qpdf/terminate-parsing.pdf
new file mode 100644
index 00000000..ec848f82
--- /dev/null
+++ b/qpdf/qtest/qpdf/terminate-parsing.pdf
Binary files differ
diff --git a/qpdf/test_driver.cc b/qpdf/test_driver.cc
index 75f5b973..3863cdbe 100644
--- a/qpdf/test_driver.cc
+++ b/qpdf/test_driver.cc
@@ -72,6 +72,11 @@ class ParserCallbacks: public QPDFObjectHandle::ParserCallbacks
void
ParserCallbacks::handleObject(QPDFObjectHandle obj)
{
+ if (obj.isName() && (obj.getName() == "/Abort"))
+ {
+ std::cout << "test suite: terminating parsing" << std::endl;
+ terminateParsing();
+ }
std::cout << obj.getTypeName() << ": ";
if (obj.isInlineImage())
{