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 | 7 | 2013-02-28 Jay Berkenbilt <ejb@ql.org> |
| 2 | 8 | |
| 3 | 9 | * Favor fopen_s and strerror_s on MSVC to avoid CRT security | ... | ... |
include/qpdf/QPDFObjectHandle.hh
| ... | ... | @@ -83,6 +83,13 @@ class QPDFObjectHandle |
| 83 | 83 | } |
| 84 | 84 | virtual void handleObject(QPDFObjectHandle) = 0; |
| 85 | 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 | 23 | #include <stdlib.h> |
| 24 | 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 | 36 | QPDFObjectHandle::QPDFObjectHandle() : |
| 27 | 37 | initialized(false), |
| 28 | 38 | objid(0), |
| ... | ... | @@ -728,7 +738,14 @@ QPDFObjectHandle::parseContentStream(QPDFObjectHandle stream_or_array, |
| 728 | 738 | throw std::logic_error( |
| 729 | 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 | 750 | callbacks->handleEOF(); |
| 734 | 751 | } | ... | ... |
qpdf/qtest/qpdf.test
| ... | ... | @@ -199,7 +199,7 @@ $td->runtest("remove page we don't have", |
| 199 | 199 | show_ntests(); |
| 200 | 200 | # ---------- |
| 201 | 201 | $td->notify("--- Miscellaneous Tests ---"); |
| 202 | -$n_tests += 61; | |
| 202 | +$n_tests += 62; | |
| 203 | 203 | |
| 204 | 204 | $td->runtest("qpdf version", |
| 205 | 205 | {$td->COMMAND => "qpdf --version"}, |
| ... | ... | @@ -478,6 +478,11 @@ $td->runtest("tokenize content streams", |
| 478 | 478 | {$td->FILE => "tokenize-content-streams.out", |
| 479 | 479 | $td->EXIT_STATUS => 0}, |
| 480 | 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 | 486 | $td->runtest("content stream errors", |
| 482 | 487 | {$td->COMMAND => "qpdf --check content-stream-errors.pdf"}, |
| 483 | 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 | 72 | void |
| 73 | 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 | 80 | std::cout << obj.getTypeName() << ": "; |
| 76 | 81 | if (obj.isInlineImage()) |
| 77 | 82 | { | ... | ... |