Skip to content

Commit

Permalink
Improve message for stream decoding error
Browse files Browse the repository at this point in the history
Tweak the message so that we inform the user that we are mitigating
data loss.
  • Loading branch information
jberkenbilt committed Sep 12, 2017
1 parent eaacf94 commit d31a7b7
Show file tree
Hide file tree
Showing 16 changed files with 59 additions and 16 deletions.
5 changes: 5 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
2017-09-12 Jay Berkenbilt <[email protected]>

* Improve the error message that is issued when QPDFWriter
encounters a stream that can't be decoded. In particular, mention
that the stream will be copied without filtering to avoid data
loss.

* Add new methods to the C API to correspond to new additions to
QPDFWriter:
- qpdf_set_compress_streams
Expand Down
4 changes: 0 additions & 4 deletions TODO
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@ Before final 7.0.0

* Create release notes

* See if the error message that gets generated when retrying a stream
without filtering after error detection can be less scary.
Communicate that the original stream data is being preserved.

Soon
====

Expand Down
9 changes: 6 additions & 3 deletions include/qpdf/QPDF.hh
Original file line number Diff line number Diff line change
Expand Up @@ -554,11 +554,13 @@ class QPDF
static bool pipeStreamData(QPDF* qpdf, int objid, int generation,
qpdf_offset_t offset, size_t length,
QPDFObjectHandle dict,
Pipeline* pipeline, bool suppress_warnings)
Pipeline* pipeline,
bool suppress_warnings,
bool will_retry)
{
return qpdf->pipeStreamData(
objid, generation, offset, length, dict, pipeline,
suppress_warnings);
suppress_warnings, will_retry);
}
};
friend class Pipe;
Expand Down Expand Up @@ -688,7 +690,8 @@ class QPDF
qpdf_offset_t offset, size_t length,
QPDFObjectHandle dict,
Pipeline* pipeline,
bool suppress_warnings);
bool suppress_warnings,
bool will_retry);

// For QPDFWriter:

Expand Down
11 changes: 10 additions & 1 deletion include/qpdf/QPDFObjectHandle.hh
Original file line number Diff line number Diff line change
Expand Up @@ -420,12 +420,21 @@ class QPDFObjectHandle
// configured filters. QPDFWriter handles this by attempting to
// get the stream data without filtering, but callers should
// consider a false return value when decode_level is not
// qpdf_dl_none to be a potential loss of data.
// qpdf_dl_none to be a potential loss of data. If you intend to
// retry in that case, pass true as the value of will_retry. This
// changes the warning issued by the library to indicate that the
// operation will be retried without filtering to avoid data loss.
QPDF_DLL
bool pipeStreamData(Pipeline*,
unsigned long encode_flags,
qpdf_stream_decode_level_e decode_level,
bool suppress_warnings = false);
QPDF_DLL
bool pipeStreamData(Pipeline*,
unsigned long encode_flags,
qpdf_stream_decode_level_e decode_level,
bool suppress_warnings,
bool will_retry);

// Legacy pipeStreamData. This maps to the the flags-based
// pipeStreamData as follows:
Expand Down
10 changes: 9 additions & 1 deletion libqpdf/QPDF.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2382,7 +2382,8 @@ QPDF::pipeStreamData(int objid, int generation,
qpdf_offset_t offset, size_t length,
QPDFObjectHandle stream_dict,
Pipeline* pipeline,
bool suppress_warnings)
bool suppress_warnings,
bool will_retry)
{
bool success = false;
std::vector<PointerHolder<Pipeline> > to_delete;
Expand Down Expand Up @@ -2430,6 +2431,13 @@ QPDF::pipeStreamData(int objid, int generation,
"error decoding stream data for object " +
QUtil::int_to_string(objid) + " " +
QUtil::int_to_string(generation) + ": " + e.what()));
if (will_retry)
{
warn(QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(),
"", this->m->file->getLastOffset(),
"stream will be re-processed without"
" filtering to avoid data loss"));
}
}
}
if (! success)
Expand Down
12 changes: 11 additions & 1 deletion libqpdf/QPDFObjectHandle.cc
Original file line number Diff line number Diff line change
Expand Up @@ -500,10 +500,20 @@ QPDFObjectHandle::pipeStreamData(Pipeline* p,
unsigned long encode_flags,
qpdf_stream_decode_level_e decode_level,
bool suppress_warnings)
{
return pipeStreamData(
p, encode_flags, decode_level, suppress_warnings, false);
}

bool
QPDFObjectHandle::pipeStreamData(Pipeline* p,
unsigned long encode_flags,
qpdf_stream_decode_level_e decode_level,
bool suppress_warnings, bool will_retry)
{
assertStream();
return dynamic_cast<QPDF_Stream*>(obj.getPointer())->pipeStreamData(
p, encode_flags, decode_level, suppress_warnings);
p, encode_flags, decode_level, suppress_warnings, will_retry);
}

bool
Expand Down
2 changes: 1 addition & 1 deletion libqpdf/QPDFWriter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1623,7 +1623,7 @@ QPDFWriter::unparseObject(QPDFObjectHandle object, int level,
((filter && compress) ? qpdf_ef_compress : 0)),
(filter
? (uncompress ? qpdf_dl_all : this->m->stream_decode_level)
: qpdf_dl_none));
: qpdf_dl_none), false, (attempt == 1));
popPipelineStack(&stream_data);
if (filter && (! filtered))
{
Expand Down
9 changes: 5 additions & 4 deletions libqpdf/QPDF_Stream.cc
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ PointerHolder<Buffer>
QPDF_Stream::getStreamData(qpdf_stream_decode_level_e decode_level)
{
Pl_Buffer buf("stream data buffer");
if (! pipeStreamData(&buf, 0, decode_level, false))
if (! pipeStreamData(&buf, 0, decode_level, false, false))
{
throw std::logic_error("getStreamData called on unfilterable stream");
}
Expand All @@ -106,7 +106,7 @@ PointerHolder<Buffer>
QPDF_Stream::getRawStreamData()
{
Pl_Buffer buf("stream data buffer");
pipeStreamData(&buf, 0, qpdf_dl_none, false);
pipeStreamData(&buf, 0, qpdf_dl_none, false, false);
QTC::TC("qpdf", "QPDF_Stream getRawStreamData");
return buf.getBuffer();
}
Expand Down Expand Up @@ -373,7 +373,7 @@ bool
QPDF_Stream::pipeStreamData(Pipeline* pipeline,
unsigned long encode_flags,
qpdf_stream_decode_level_e decode_level,
bool suppress_warnings)
bool suppress_warnings, bool will_retry)
{
std::vector<std::string> filters;
int predictor = 1;
Expand Down Expand Up @@ -540,7 +540,8 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline,
if (! QPDF::Pipe::pipeStreamData(this->qpdf, this->objid, this->generation,
this->offset, this->length,
this->stream_dict, pipeline,
suppress_warnings))
suppress_warnings,
will_retry))
{
filter = false;
}
Expand Down
2 changes: 1 addition & 1 deletion libqpdf/qpdf/QPDF_Stream.hh
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class QPDF_Stream: public QPDFObject
bool pipeStreamData(Pipeline*,
unsigned long encode_flags,
qpdf_stream_decode_level_e decode_level,
bool suppress_warnings);
bool suppress_warnings, bool will_retry);
PointerHolder<Buffer> getStreamData(qpdf_stream_decode_level_e);
PointerHolder<Buffer> getRawStreamData();
void replaceStreamData(PointerHolder<Buffer> data,
Expand Down
1 change: 1 addition & 0 deletions qpdf/qtest/qpdf/bad-data.out
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
WARNING: bad-data.pdf (file position 319): error decoding stream data for object 4 0: LZWDecoder: bad code received
WARNING: bad-data.pdf (file position 319): stream will be re-processed without filtering to avoid data loss
qpdf: operation succeeded with warnings; resulting file may have some problems
1 change: 1 addition & 0 deletions qpdf/qtest/qpdf/bad-jpeg-check.out
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ PDF Version: 1.3
File is not encrypted
File is not linearized
WARNING: bad-jpeg.pdf (file position 735): error decoding stream data for object 6 0: Not a JPEG file: starts with 0x77 0x77
WARNING: bad-jpeg.pdf (file position 735): stream will be re-processed without filtering to avoid data loss
1 change: 1 addition & 0 deletions qpdf/qtest/qpdf/bad-jpeg.out
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
WARNING: bad-jpeg.pdf (file position 735): error decoding stream data for object 6 0: Not a JPEG file: starts with 0x77 0x77
WARNING: bad-jpeg.pdf (file position 735): stream will be re-processed without filtering to avoid data loss
qpdf: operation succeeded with warnings; resulting file may have some problems
5 changes: 5 additions & 0 deletions qpdf/qtest/qpdf/damaged-stream-c-check.out
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,8 @@ warning: damaged-stream.pdf (file position 426): error decoding stream data for
file: damaged-stream.pdf
pos : 426
text: error decoding stream data for object 5 0: LZWDecoder: bad code received
warning: damaged-stream.pdf (file position 426): stream will be re-processed without filtering to avoid data loss
code: 5
file: damaged-stream.pdf
pos : 426
text: stream will be re-processed without filtering to avoid data loss
1 change: 1 addition & 0 deletions qpdf/qtest/qpdf/damaged-stream.out
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ PDF Version: 1.3
File is not encrypted
File is not linearized
WARNING: damaged-stream.pdf (file position 426): error decoding stream data for object 5 0: LZWDecoder: bad code received
WARNING: damaged-stream.pdf (file position 426): stream will be re-processed without filtering to avoid data loss
1 change: 1 addition & 0 deletions qpdf/qtest/qpdf/issue-106.out
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ WARNING: issue-106.pdf: file is damaged
WARNING: issue-106.pdf (file position 809): xref not found
WARNING: issue-106.pdf: Attempting to reconstruct cross-reference table
WARNING: issue-106.pdf (file position 965): error decoding stream data for object 8 0: stream inflate: inflate: data: incorrect data check
WARNING: issue-106.pdf (file position 965): stream will be re-processed without filtering to avoid data loss
qpdf: operation succeeded with warnings; resulting file may have some problems
1 change: 1 addition & 0 deletions qpdf/qtest/qpdf/split-content-stream-errors.out
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ PDF Version: 1.3
File is not encrypted
File is not linearized
WARNING: split-content-stream-errors.pdf (file position 557): error decoding stream data for object 6 0: LZWDecoder: bad code received
WARNING: split-content-stream-errors.pdf (file position 557): stream will be re-processed without filtering to avoid data loss
WARNING: content stream: ignoring non-stream while parsing content streams
WARNING: split-content-stream-errors.pdf (file position 557): error decoding stream data for object 6 0: LZWDecoder: bad code received
WARNING: content stream (content stream object 6 0): errors while decoding content stream

0 comments on commit d31a7b7

Please sign in to comment.