Commit 119f2a4b684aae7cec8841412a5fc89bcbae404d
1 parent
7be97b3e
Add method to terminate content stream parsing
Showing
7 changed files
with
128 additions
and
2 deletions
ChangeLog
| 1 | +2013-03-03 Jay Berkenbilt <ejb@ql.org> | ||
| 2 | + | ||
| 3 | + * Add protected terminateParsing method to | ||
| 4 | + QPDFObjectHandle::ParserCallbacks that implementor can call to | ||
| 5 | + terminate parsing of a content stream. | ||
| 6 | + | ||
| 1 | 2013-02-28 Jay Berkenbilt <ejb@ql.org> | 7 | 2013-02-28 Jay Berkenbilt <ejb@ql.org> |
| 2 | 8 | ||
| 3 | * Favor fopen_s and strerror_s on MSVC to avoid CRT security | 9 | * Favor fopen_s and strerror_s on MSVC to avoid CRT security |
include/qpdf/QPDFObjectHandle.hh
| @@ -83,6 +83,13 @@ class QPDFObjectHandle | @@ -83,6 +83,13 @@ class QPDFObjectHandle | ||
| 83 | } | 83 | } |
| 84 | virtual void handleObject(QPDFObjectHandle) = 0; | 84 | virtual void handleObject(QPDFObjectHandle) = 0; |
| 85 | virtual void handleEOF() = 0; | 85 | virtual void handleEOF() = 0; |
| 86 | + | ||
| 87 | + protected: | ||
| 88 | + // Implementors may call this method during parsing to | ||
| 89 | + // terminate parsing early. This method throws an exception | ||
| 90 | + // that is caught by parseContentStream, so its effect is | ||
| 91 | + // immediate. | ||
| 92 | + void terminateParsing(); | ||
| 86 | }; | 93 | }; |
| 87 | 94 | ||
| 88 | 95 |
libqpdf/QPDFObjectHandle.cc
| @@ -23,6 +23,16 @@ | @@ -23,6 +23,16 @@ | ||
| 23 | #include <stdlib.h> | 23 | #include <stdlib.h> |
| 24 | #include <ctype.h> | 24 | #include <ctype.h> |
| 25 | 25 | ||
| 26 | +class TerminateParsing | ||
| 27 | +{ | ||
| 28 | +}; | ||
| 29 | + | ||
| 30 | +void | ||
| 31 | +QPDFObjectHandle::ParserCallbacks::terminateParsing() | ||
| 32 | +{ | ||
| 33 | + throw TerminateParsing(); | ||
| 34 | +} | ||
| 35 | + | ||
| 26 | QPDFObjectHandle::QPDFObjectHandle() : | 36 | QPDFObjectHandle::QPDFObjectHandle() : |
| 27 | initialized(false), | 37 | initialized(false), |
| 28 | objid(0), | 38 | objid(0), |
| @@ -728,7 +738,14 @@ QPDFObjectHandle::parseContentStream(QPDFObjectHandle stream_or_array, | @@ -728,7 +738,14 @@ QPDFObjectHandle::parseContentStream(QPDFObjectHandle stream_or_array, | ||
| 728 | throw std::logic_error( | 738 | throw std::logic_error( |
| 729 | "QPDFObjectHandle: parseContentStream called on non-stream"); | 739 | "QPDFObjectHandle: parseContentStream called on non-stream"); |
| 730 | } | 740 | } |
| 731 | - parseContentStream_internal(stream, callbacks); | 741 | + try |
| 742 | + { | ||
| 743 | + parseContentStream_internal(stream, callbacks); | ||
| 744 | + } | ||
| 745 | + catch (TerminateParsing&) | ||
| 746 | + { | ||
| 747 | + return; | ||
| 748 | + } | ||
| 732 | } | 749 | } |
| 733 | callbacks->handleEOF(); | 750 | callbacks->handleEOF(); |
| 734 | } | 751 | } |
qpdf/qtest/qpdf.test
| @@ -199,7 +199,7 @@ $td->runtest("remove page we don't have", | @@ -199,7 +199,7 @@ $td->runtest("remove page we don't have", | ||
| 199 | show_ntests(); | 199 | show_ntests(); |
| 200 | # ---------- | 200 | # ---------- |
| 201 | $td->notify("--- Miscellaneous Tests ---"); | 201 | $td->notify("--- Miscellaneous Tests ---"); |
| 202 | -$n_tests += 61; | 202 | +$n_tests += 62; |
| 203 | 203 | ||
| 204 | $td->runtest("qpdf version", | 204 | $td->runtest("qpdf version", |
| 205 | {$td->COMMAND => "qpdf --version"}, | 205 | {$td->COMMAND => "qpdf --version"}, |
| @@ -478,6 +478,11 @@ $td->runtest("tokenize content streams", | @@ -478,6 +478,11 @@ $td->runtest("tokenize content streams", | ||
| 478 | {$td->FILE => "tokenize-content-streams.out", | 478 | {$td->FILE => "tokenize-content-streams.out", |
| 479 | $td->EXIT_STATUS => 0}, | 479 | $td->EXIT_STATUS => 0}, |
| 480 | $td->NORMALIZE_NEWLINES); | 480 | $td->NORMALIZE_NEWLINES); |
| 481 | +$td->runtest("terminate parsing", | ||
| 482 | + {$td->COMMAND => "test_driver 37 terminate-parsing.pdf"}, | ||
| 483 | + {$td->FILE => "terminate-parsing.out", | ||
| 484 | + $td->EXIT_STATUS => 0}, | ||
| 485 | + $td->NORMALIZE_NEWLINES); | ||
| 481 | $td->runtest("content stream errors", | 486 | $td->runtest("content stream errors", |
| 482 | {$td->COMMAND => "qpdf --check content-stream-errors.pdf"}, | 487 | {$td->COMMAND => "qpdf --check content-stream-errors.pdf"}, |
| 483 | {$td->FILE => "content-stream-errors.out", | 488 | {$td->FILE => "content-stream-errors.out", |
qpdf/qtest/qpdf/terminate-parsing.out
0 → 100644
| 1 | +name: /potato | ||
| 2 | +test suite: terminating parsing | ||
| 3 | +real: 0.1 | ||
| 4 | +integer: 0 | ||
| 5 | +integer: 0 | ||
| 6 | +real: 0.1 | ||
| 7 | +integer: 0 | ||
| 8 | +integer: 0 | ||
| 9 | +operator: cm | ||
| 10 | +operator: q | ||
| 11 | +integer: 0 | ||
| 12 | +real: 1.1999 | ||
| 13 | +real: -1.1999 | ||
| 14 | +integer: 0 | ||
| 15 | +real: 121.19 | ||
| 16 | +real: 150.009 | ||
| 17 | +operator: cm | ||
| 18 | +operator: BI | ||
| 19 | +name: /CS | ||
| 20 | +name: /G | ||
| 21 | +name: /W | ||
| 22 | +integer: 1 | ||
| 23 | +name: /H | ||
| 24 | +integer: 1 | ||
| 25 | +name: /BPC | ||
| 26 | +integer: 8 | ||
| 27 | +name: /F | ||
| 28 | +name: /Fl | ||
| 29 | +name: /DP | ||
| 30 | +dictionary: << /Columns 1 /Predictor 15 >> | ||
| 31 | +operator: ID | ||
| 32 | +inline-image: 789c63fc0f0001030101 | ||
| 33 | +operator: EI | ||
| 34 | +operator: Q | ||
| 35 | +operator: q | ||
| 36 | +integer: 0 | ||
| 37 | +real: 35.997 | ||
| 38 | +real: -128.389 | ||
| 39 | +integer: 0 | ||
| 40 | +real: 431.964 | ||
| 41 | +real: 7269.02 | ||
| 42 | +operator: cm | ||
| 43 | +operator: BI | ||
| 44 | +name: /CS | ||
| 45 | +name: /G | ||
| 46 | +name: /W | ||
| 47 | +integer: 30 | ||
| 48 | +name: /H | ||
| 49 | +integer: 107 | ||
| 50 | +name: /BPC | ||
| 51 | +integer: 8 | ||
| 52 | +name: /F | ||
| 53 | +name: /Fl | ||
| 54 | +name: /DP | ||
| 55 | +dictionary: << /Columns 30 /Predictor 15 >> | ||
| 56 | +operator: ID | ||
| 57 | +inline-image: 789cedd1a11100300800b1b2ffd06503148283bc8dfcf8af2a306ee352eff2e06318638c31c63b3801627b620a | ||
| 58 | +operator: EI | ||
| 59 | +operator: Q | ||
| 60 | +operator: q | ||
| 61 | +integer: 0 | ||
| 62 | +real: 38.3968 | ||
| 63 | +real: -93.5922 | ||
| 64 | +integer: 0 | ||
| 65 | +real: 431.964 | ||
| 66 | +real: 7567.79 | ||
| 67 | +operator: cm | ||
| 68 | +operator: BI | ||
| 69 | +name: /CS | ||
| 70 | +name: /G | ||
| 71 | +name: /W | ||
| 72 | +integer: 32 | ||
| 73 | +name: /H | ||
| 74 | +integer: 78 | ||
| 75 | +name: /BPC | ||
| 76 | +integer: 8 | ||
| 77 | +name: /F | ||
| 78 | +name: /Fl | ||
| 79 | +name: /DP | ||
| 80 | +dictionary: << /Columns 32 /Predictor 15 >> | ||
| 81 | +operator: ID | ||
| 82 | +inline-image: 789c63fccf801f308e2a185530aa60882a20203faa605401890a0643aa1e5530aa6054010d140000bdd03c13 | ||
| 83 | +operator: EI | ||
| 84 | +operator: Q | ||
| 85 | +-EOF- | ||
| 86 | +test 37 done |
qpdf/qtest/qpdf/terminate-parsing.pdf
0 → 100644
No preview for this file type
qpdf/test_driver.cc
| @@ -72,6 +72,11 @@ class ParserCallbacks: public QPDFObjectHandle::ParserCallbacks | @@ -72,6 +72,11 @@ class ParserCallbacks: public QPDFObjectHandle::ParserCallbacks | ||
| 72 | void | 72 | void |
| 73 | ParserCallbacks::handleObject(QPDFObjectHandle obj) | 73 | ParserCallbacks::handleObject(QPDFObjectHandle obj) |
| 74 | { | 74 | { |
| 75 | + if (obj.isName() && (obj.getName() == "/Abort")) | ||
| 76 | + { | ||
| 77 | + std::cout << "test suite: terminating parsing" << std::endl; | ||
| 78 | + terminateParsing(); | ||
| 79 | + } | ||
| 75 | std::cout << obj.getTypeName() << ": "; | 80 | std::cout << obj.getTypeName() << ": "; |
| 76 | if (obj.isInlineImage()) | 81 | if (obj.isInlineImage()) |
| 77 | { | 82 | { |