Improve message for stream decoding error

Tweak the message so that we inform the user that we are mitigating
data loss.
This commit is contained in:
Jay Berkenbilt 2017-09-12 15:48:08 -04:00
parent eaacf94005
commit d31a7b76e7
16 changed files with 59 additions and 16 deletions

View File

@ -1,5 +1,10 @@
2017-09-12 Jay Berkenbilt <ejb@ql.org> 2017-09-12 Jay Berkenbilt <ejb@ql.org>
* 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 * Add new methods to the C API to correspond to new additions to
QPDFWriter: QPDFWriter:
- qpdf_set_compress_streams - qpdf_set_compress_streams

4
TODO
View File

@ -3,10 +3,6 @@ Before final 7.0.0
* Create release notes * 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 Soon
==== ====

View File

@ -554,11 +554,13 @@ class QPDF
static bool pipeStreamData(QPDF* qpdf, int objid, int generation, static bool pipeStreamData(QPDF* qpdf, int objid, int generation,
qpdf_offset_t offset, size_t length, qpdf_offset_t offset, size_t length,
QPDFObjectHandle dict, QPDFObjectHandle dict,
Pipeline* pipeline, bool suppress_warnings) Pipeline* pipeline,
bool suppress_warnings,
bool will_retry)
{ {
return qpdf->pipeStreamData( return qpdf->pipeStreamData(
objid, generation, offset, length, dict, pipeline, objid, generation, offset, length, dict, pipeline,
suppress_warnings); suppress_warnings, will_retry);
} }
}; };
friend class Pipe; friend class Pipe;
@ -688,7 +690,8 @@ class QPDF
qpdf_offset_t offset, size_t length, qpdf_offset_t offset, size_t length,
QPDFObjectHandle dict, QPDFObjectHandle dict,
Pipeline* pipeline, Pipeline* pipeline,
bool suppress_warnings); bool suppress_warnings,
bool will_retry);
// For QPDFWriter: // For QPDFWriter:

View File

@ -420,12 +420,21 @@ class QPDFObjectHandle
// configured filters. QPDFWriter handles this by attempting to // configured filters. QPDFWriter handles this by attempting to
// get the stream data without filtering, but callers should // get the stream data without filtering, but callers should
// consider a false return value when decode_level is not // 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 QPDF_DLL
bool pipeStreamData(Pipeline*, bool pipeStreamData(Pipeline*,
unsigned long encode_flags, unsigned long encode_flags,
qpdf_stream_decode_level_e decode_level, qpdf_stream_decode_level_e decode_level,
bool suppress_warnings = false); 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 // Legacy pipeStreamData. This maps to the the flags-based
// pipeStreamData as follows: // pipeStreamData as follows:

View File

@ -2382,7 +2382,8 @@ QPDF::pipeStreamData(int objid, int generation,
qpdf_offset_t offset, size_t length, qpdf_offset_t offset, size_t length,
QPDFObjectHandle stream_dict, QPDFObjectHandle stream_dict,
Pipeline* pipeline, Pipeline* pipeline,
bool suppress_warnings) bool suppress_warnings,
bool will_retry)
{ {
bool success = false; bool success = false;
std::vector<PointerHolder<Pipeline> > to_delete; std::vector<PointerHolder<Pipeline> > to_delete;
@ -2430,6 +2431,13 @@ QPDF::pipeStreamData(int objid, int generation,
"error decoding stream data for object " + "error decoding stream data for object " +
QUtil::int_to_string(objid) + " " + QUtil::int_to_string(objid) + " " +
QUtil::int_to_string(generation) + ": " + e.what())); 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) if (! success)

View File

@ -500,10 +500,20 @@ QPDFObjectHandle::pipeStreamData(Pipeline* p,
unsigned long encode_flags, unsigned long encode_flags,
qpdf_stream_decode_level_e decode_level, qpdf_stream_decode_level_e decode_level,
bool suppress_warnings) 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(); assertStream();
return dynamic_cast<QPDF_Stream*>(obj.getPointer())->pipeStreamData( 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 bool

View File

@ -1623,7 +1623,7 @@ QPDFWriter::unparseObject(QPDFObjectHandle object, int level,
((filter && compress) ? qpdf_ef_compress : 0)), ((filter && compress) ? qpdf_ef_compress : 0)),
(filter (filter
? (uncompress ? qpdf_dl_all : this->m->stream_decode_level) ? (uncompress ? qpdf_dl_all : this->m->stream_decode_level)
: qpdf_dl_none)); : qpdf_dl_none), false, (attempt == 1));
popPipelineStack(&stream_data); popPipelineStack(&stream_data);
if (filter && (! filtered)) if (filter && (! filtered))
{ {

View File

@ -94,7 +94,7 @@ PointerHolder<Buffer>
QPDF_Stream::getStreamData(qpdf_stream_decode_level_e decode_level) QPDF_Stream::getStreamData(qpdf_stream_decode_level_e decode_level)
{ {
Pl_Buffer buf("stream data buffer"); 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"); throw std::logic_error("getStreamData called on unfilterable stream");
} }
@ -106,7 +106,7 @@ PointerHolder<Buffer>
QPDF_Stream::getRawStreamData() QPDF_Stream::getRawStreamData()
{ {
Pl_Buffer buf("stream data buffer"); 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"); QTC::TC("qpdf", "QPDF_Stream getRawStreamData");
return buf.getBuffer(); return buf.getBuffer();
} }
@ -373,7 +373,7 @@ bool
QPDF_Stream::pipeStreamData(Pipeline* pipeline, QPDF_Stream::pipeStreamData(Pipeline* pipeline,
unsigned long encode_flags, unsigned long encode_flags,
qpdf_stream_decode_level_e decode_level, qpdf_stream_decode_level_e decode_level,
bool suppress_warnings) bool suppress_warnings, bool will_retry)
{ {
std::vector<std::string> filters; std::vector<std::string> filters;
int predictor = 1; int predictor = 1;
@ -540,7 +540,8 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline,
if (! QPDF::Pipe::pipeStreamData(this->qpdf, this->objid, this->generation, if (! QPDF::Pipe::pipeStreamData(this->qpdf, this->objid, this->generation,
this->offset, this->length, this->offset, this->length,
this->stream_dict, pipeline, this->stream_dict, pipeline,
suppress_warnings)) suppress_warnings,
will_retry))
{ {
filter = false; filter = false;
} }

View File

@ -25,7 +25,7 @@ class QPDF_Stream: public QPDFObject
bool pipeStreamData(Pipeline*, bool pipeStreamData(Pipeline*,
unsigned long encode_flags, unsigned long encode_flags,
qpdf_stream_decode_level_e decode_level, 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> getStreamData(qpdf_stream_decode_level_e);
PointerHolder<Buffer> getRawStreamData(); PointerHolder<Buffer> getRawStreamData();
void replaceStreamData(PointerHolder<Buffer> data, void replaceStreamData(PointerHolder<Buffer> data,

View File

@ -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): 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 qpdf: operation succeeded with warnings; resulting file may have some problems

View File

@ -3,3 +3,4 @@ PDF Version: 1.3
File is not encrypted File is not encrypted
File is not linearized 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): 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

View File

@ -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): 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 qpdf: operation succeeded with warnings; resulting file may have some problems

View File

@ -3,3 +3,8 @@ warning: damaged-stream.pdf (file position 426): error decoding stream data for
file: damaged-stream.pdf file: damaged-stream.pdf
pos : 426 pos : 426
text: error decoding stream data for object 5 0: LZWDecoder: bad code received 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

View File

@ -3,3 +3,4 @@ PDF Version: 1.3
File is not encrypted File is not encrypted
File is not linearized 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): 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

View File

@ -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 (file position 809): xref not found
WARNING: issue-106.pdf: Attempting to reconstruct cross-reference table 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): 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 qpdf: operation succeeded with warnings; resulting file may have some problems

View File

@ -3,6 +3,7 @@ PDF Version: 1.3
File is not encrypted File is not encrypted
File is not linearized 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): 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: 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: 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 WARNING: content stream (content stream object 6 0): errors while decoding content stream