mirror of
https://github.com/qpdf/qpdf.git
synced 2024-12-22 10:58:58 +00:00
categorize all error messages and include object information if available
git-svn-id: svn+q:///qpdf/trunk@829 71b93d88-0707-0410-a8cf-f5a4172ac649
This commit is contained in:
parent
b67a3c15e7
commit
3f8c4c2736
@ -1,3 +1,11 @@
|
||||
2009-10-19 Jay Berkenbilt <jberkenb@argonst.com>
|
||||
|
||||
* Include information about the last object read in most error
|
||||
messages. Most of the time, this will provide a good hint as to
|
||||
which object contains the error, but it's possible that the last
|
||||
object read may not necessarily be the one that has the error if
|
||||
the erroneous object was previously read and cached.
|
||||
|
||||
2009-10-18 Jay Berkenbilt <ejb@ql.org>
|
||||
|
||||
* If forcing version, disable object stream creation and/or
|
||||
|
23
TODO
23
TODO
@ -16,25 +16,10 @@
|
||||
* Add comments for the security functions that map them back to the
|
||||
items in Adobe's products.
|
||||
|
||||
* Add error codes to QPDFException. Change the error interface so
|
||||
that warnings and errors are pointers that can be queried using
|
||||
more C API functions. We need a way to get a full string as well
|
||||
as an error code, file name, offset, and message. We should go
|
||||
through all error messages to try to include all these fields as
|
||||
appropriate. Make sure invalid password is specifically
|
||||
detectable. I/O errors and so forth should also be
|
||||
distinguishable. Make sure all errors include information about
|
||||
the most recent read location including byte offset and
|
||||
object/generation number.
|
||||
|
||||
* It might be nice to be able to trap I/O errors separately from
|
||||
other errors; especially be able to separate errors that the user
|
||||
can fix (like permission errors) from errors that they probably
|
||||
can't fix like corrupted PDF files, unsupported filters, or
|
||||
internal errors. However, only QPDF::processFile(), which does the
|
||||
initial read, and QPDFWriter::QPDFWriter(), which does the initial
|
||||
write, are at all likely to generate such errors for a case other
|
||||
than a catastrophic failure.
|
||||
* Change the C error interface so that warnings and errors are
|
||||
pointers that can be queried using more C API functions. We need a
|
||||
way to get a full string as well as an error code, file name,
|
||||
offset, and message.
|
||||
|
||||
* "Delphi wrapper unit 'qpdf.pas' created by Zarko Gajic
|
||||
(http://delphi.about.com). .. use at your own risk and for whatever
|
||||
|
@ -30,7 +30,7 @@ $td->runtest("no bookmarks",
|
||||
$td->runtest("bad",
|
||||
{$td->COMMAND => "pdf-bookmarks 3.pdf"},
|
||||
{$td->STRING => "pdf-bookmarks processing file 3.pdf: " .
|
||||
"3.pdf: offset 0: not a PDF file\n",
|
||||
"3.pdf: not a PDF file\n",
|
||||
$td->EXIT_STATUS => 2},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
|
||||
|
@ -16,7 +16,7 @@ $td->runtest("normal",
|
||||
|
||||
$td->runtest("error",
|
||||
{$td->COMMAND => "pdf-npages bad"},
|
||||
{$td->STRING => "pdf-npages: bad: offset 0: not a PDF file\n",
|
||||
{$td->STRING => "pdf-npages: bad: not a PDF file\n",
|
||||
$td->EXIT_STATUS => 2},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
|
||||
|
@ -371,9 +371,11 @@ class DLL_EXPORT QPDF
|
||||
int processXRefStream(off_t offset, QPDFObjectHandle& xref_stream);
|
||||
void insertXrefEntry(int obj, int f0, int f1, int f2,
|
||||
bool overwrite = false);
|
||||
void setLastObjectDescription(std::string const& description,
|
||||
int objid, int generation);
|
||||
QPDFObjectHandle readObject(
|
||||
InputSource*, int objid, int generation,
|
||||
bool in_object_stream);
|
||||
InputSource*, std::string const& description,
|
||||
int objid, int generation, bool in_object_stream);
|
||||
QPDFObjectHandle readObjectInternal(
|
||||
InputSource* input, int objid, int generation,
|
||||
bool in_object_stream,
|
||||
@ -383,7 +385,8 @@ class DLL_EXPORT QPDF
|
||||
QPDFTokenizer::Token readToken(InputSource*);
|
||||
|
||||
QPDFObjectHandle readObjectAtOffset(
|
||||
off_t offset,
|
||||
bool attempt_recovery,
|
||||
off_t offset, std::string const& description,
|
||||
int exp_objid, int exp_generation,
|
||||
int& act_objid, int& act_generation);
|
||||
PointerHolder<QPDFObject> resolve(int objid, int generation);
|
||||
@ -734,6 +737,7 @@ class DLL_EXPORT QPDF
|
||||
|
||||
QPDFTokenizer tokenizer;
|
||||
FileInputSource file;
|
||||
std::string last_object_description;
|
||||
bool encrypted;
|
||||
bool encryption_initialized;
|
||||
bool ignore_xref_streams;
|
||||
|
@ -9,15 +9,47 @@
|
||||
#define __QPDFEXC_HH__
|
||||
|
||||
#include <qpdf/DLL.h>
|
||||
#include <qpdf/Constants.h>
|
||||
#include <stdexcept>
|
||||
#include <stddef.h>
|
||||
|
||||
class DLL_EXPORT QPDFExc: public std::runtime_error
|
||||
{
|
||||
public:
|
||||
QPDFExc(std::string const& message);
|
||||
QPDFExc(std::string const& filename, int offset,
|
||||
QPDFExc(qpdf_error_code_e error_code,
|
||||
std::string const& filename,
|
||||
std::string const& object,
|
||||
off_t offset,
|
||||
std::string const& message);
|
||||
virtual ~QPDFExc() throw ();
|
||||
|
||||
// To get a complete error string, call what(), provided by
|
||||
// std::exception. The accessors below return the original values
|
||||
// used to create the exception. Only the error code and message
|
||||
// are guaranteed to have non-zero/empty values.
|
||||
|
||||
// There is no lookup code that maps numeric error codes into
|
||||
// strings. The numeric error code is just another way to get at
|
||||
// the underlying issue, but it is more programmer-friendly than
|
||||
// trying to parse a string that is subject to change.
|
||||
|
||||
qpdf_error_code_e getErrorCode() const;
|
||||
std::string const& getFilename() const;
|
||||
std::string const& getObject() const;
|
||||
off_t getOffset() const;
|
||||
std::string const& getMessage() const;
|
||||
|
||||
private:
|
||||
static std::string createWhat(std::string const& filename,
|
||||
std::string const& object,
|
||||
off_t offset,
|
||||
std::string const& message);
|
||||
|
||||
qpdf_error_code_e error_code;
|
||||
std::string filename;
|
||||
std::string object;
|
||||
off_t offset;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
#endif // __QPDFEXC_HH__
|
||||
|
252
libqpdf/QPDF.cc
252
libqpdf/QPDF.cc
@ -140,7 +140,9 @@ QPDF::FileInputSource::read(char* buffer, int length)
|
||||
size_t len = fread(buffer, 1, length, this->file);
|
||||
if ((len == 0) && ferror(this->file))
|
||||
{
|
||||
throw QPDFExc(this->filename, this->last_offset,
|
||||
throw QPDFExc(qpdf_e_system,
|
||||
this->filename, "",
|
||||
this->last_offset,
|
||||
std::string("read ") +
|
||||
QUtil::int_to_string(length) + " bytes");
|
||||
}
|
||||
@ -325,7 +327,8 @@ QPDF::parse()
|
||||
else
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF not a pdf file");
|
||||
throw QPDFExc(this->file.getName(), 0, "not a PDF file");
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"", 0, "not a PDF file");
|
||||
}
|
||||
|
||||
// PDF spec says %%EOF must be found within the last 1024 bytes of
|
||||
@ -369,7 +372,8 @@ QPDF::parse()
|
||||
if (! m2)
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF can't find startxref");
|
||||
throw QPDFExc(this->file.getName() + ": can't find startxref");
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(), "", 0,
|
||||
"can't find startxref");
|
||||
}
|
||||
off_t xref_offset = atoi(m2.getMatch(1).c_str());
|
||||
read_xref(xref_offset);
|
||||
@ -417,9 +421,28 @@ QPDF::reconstruct_xref(QPDFExc& e)
|
||||
static PCRE endobj_re("^endobj\\b");
|
||||
static PCRE trailer_re("^trailer\\b");
|
||||
|
||||
warn(QPDFExc(this->file.getName(), 0, "file is damaged"));
|
||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->file.getName(), "", 0,
|
||||
"file is damaged"));
|
||||
warn(e);
|
||||
warn(QPDFExc("Attempting to reconstruct cross-reference table"));
|
||||
warn(QPDFExc(qpdf_e_damaged_pdf, "", "", 0,
|
||||
"Attempting to reconstruct cross-reference table"));
|
||||
|
||||
// Delete all references to type 1 (uncompressed) objects
|
||||
std::set<ObjGen> to_delete;
|
||||
for (std::map<ObjGen, QPDFXRefEntry>::iterator iter =
|
||||
this->xref_table.begin();
|
||||
iter != this->xref_table.end(); ++iter)
|
||||
{
|
||||
if (((*iter).second).getType() == 1)
|
||||
{
|
||||
to_delete.insert((*iter).first);
|
||||
}
|
||||
}
|
||||
for (std::set<ObjGen>::iterator iter = to_delete.begin();
|
||||
iter != to_delete.end(); ++iter)
|
||||
{
|
||||
this->xref_table.erase(*iter);
|
||||
}
|
||||
|
||||
this->file.seek(0, SEEK_END);
|
||||
off_t eof = this->file.tell();
|
||||
@ -452,7 +475,8 @@ QPDF::reconstruct_xref(QPDFExc& e)
|
||||
// read "trailer"
|
||||
this->file.seek(this->file.getLastOffset(), SEEK_SET);
|
||||
readToken(&this->file);
|
||||
QPDFObjectHandle t = readObject(&this->file, 0, 0, false);
|
||||
QPDFObjectHandle t =
|
||||
readObject(&this->file, "trailer", 0, 0, false);
|
||||
if (! t.isDictionary())
|
||||
{
|
||||
// Oh well. It was worth a try.
|
||||
@ -473,7 +497,8 @@ QPDF::reconstruct_xref(QPDFExc& e)
|
||||
// with bad startxref pointers even when they have object
|
||||
// streams.
|
||||
|
||||
throw QPDFExc(this->file.getName() + ": unable to find trailer "
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(), "", 0,
|
||||
"unable to find trailer "
|
||||
"dictionary while recovering damaged file");
|
||||
}
|
||||
|
||||
@ -513,8 +538,8 @@ QPDF::read_xref(off_t xref_offset)
|
||||
if (size != max_obj + 1)
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF xref size mismatch");
|
||||
warn(QPDFExc(this->file.getName() +
|
||||
std::string(": reported number of objects (") +
|
||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->file.getName(), "", 0,
|
||||
std::string("reported number of objects (") +
|
||||
QUtil::int_to_string(size) +
|
||||
") inconsistent with actual number of objects (" +
|
||||
QUtil::int_to_string(max_obj + 1) + ")"));
|
||||
@ -542,7 +567,8 @@ QPDF::read_xrefTable(off_t xref_offset)
|
||||
if (! m1)
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF invalid xref");
|
||||
throw QPDFExc(this->file.getName(), this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"xref table", this->file.getLastOffset(),
|
||||
"xref syntax invalid");
|
||||
}
|
||||
int obj = atoi(m1.getMatch(1).c_str());
|
||||
@ -563,7 +589,8 @@ QPDF::read_xrefTable(off_t xref_offset)
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF invalid xref entry");
|
||||
throw QPDFExc(
|
||||
this->file.getName(), this->file.getLastOffset(),
|
||||
qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"xref table", this->file.getLastOffset(),
|
||||
"invalid xref entry (obj=" +
|
||||
QUtil::int_to_string(i) + ")");
|
||||
}
|
||||
@ -595,11 +622,13 @@ QPDF::read_xrefTable(off_t xref_offset)
|
||||
}
|
||||
|
||||
// Set offset to previous xref table if any
|
||||
QPDFObjectHandle cur_trailer = readObject(&this->file, 0, 0, false);
|
||||
QPDFObjectHandle cur_trailer =
|
||||
readObject(&this->file, "trailer", 0, 0, false);
|
||||
if (! cur_trailer.isDictionary())
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF missing trailer");
|
||||
throw QPDFExc(this->file.getName(), this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"", this->file.getLastOffset(),
|
||||
"expected trailer dictionary");
|
||||
}
|
||||
|
||||
@ -610,13 +639,15 @@ QPDF::read_xrefTable(off_t xref_offset)
|
||||
if (! this->trailer.hasKey("/Size"))
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF trailer lacks size");
|
||||
throw QPDFExc(this->file.getName(), this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"trailer", this->file.getLastOffset(),
|
||||
"trailer dictionary lacks /Size key");
|
||||
}
|
||||
if (! this->trailer.getKey("/Size").isInteger())
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF trailer size not integer");
|
||||
throw QPDFExc(this->file.getName(), this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"trailer", this->file.getLastOffset(),
|
||||
"/Size key in trailer dictionary is not "
|
||||
"an integer");
|
||||
}
|
||||
@ -640,7 +671,8 @@ QPDF::read_xrefTable(off_t xref_offset)
|
||||
}
|
||||
else
|
||||
{
|
||||
throw QPDFExc(this->file.getName(), xref_offset,
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"xref stream", xref_offset,
|
||||
"invalid /XRefStm");
|
||||
}
|
||||
}
|
||||
@ -659,7 +691,8 @@ QPDF::read_xrefTable(off_t xref_offset)
|
||||
if (! cur_trailer.getKey("/Prev").isInteger())
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF trailer prev not integer");
|
||||
throw QPDFExc(this->file.getName(), this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"trailer", this->file.getLastOffset(),
|
||||
"/Prev key in trailer dictionary is not "
|
||||
"an integer");
|
||||
}
|
||||
@ -685,7 +718,8 @@ QPDF::read_xrefStream(off_t xref_offset)
|
||||
QPDFObjectHandle xref_obj;
|
||||
try
|
||||
{
|
||||
xref_obj = readObjectAtOffset(xref_offset, 0, 0, xobj, xgen);
|
||||
xref_obj = readObjectAtOffset(
|
||||
false, xref_offset, "xref stream", 0, 0, xobj, xgen);
|
||||
}
|
||||
catch (QPDFExc& e)
|
||||
{
|
||||
@ -705,7 +739,8 @@ QPDF::read_xrefStream(off_t xref_offset)
|
||||
if (! found)
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF can't find xref");
|
||||
throw QPDFExc(this->file.getName(), xref_offset, "xref not found");
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"", xref_offset, "xref not found");
|
||||
}
|
||||
|
||||
return xref_offset;
|
||||
@ -725,7 +760,8 @@ QPDF::processXRefStream(off_t xref_offset, QPDFObjectHandle& xref_obj)
|
||||
dict.getKey("/Size").isInteger() &&
|
||||
(Index_obj.isArray() || Index_obj.isNull())))
|
||||
{
|
||||
throw QPDFExc(this->file.getName(), xref_offset,
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"xref stream", xref_offset,
|
||||
"Cross-reference stream does not have"
|
||||
" proper /W and /Index keys");
|
||||
}
|
||||
@ -735,7 +771,8 @@ QPDF::processXRefStream(off_t xref_offset, QPDFObjectHandle& xref_obj)
|
||||
int n_index = Index_obj.getArrayNItems();
|
||||
if ((n_index % 2) || (n_index < 2))
|
||||
{
|
||||
throw QPDFExc(this->file.getName(), xref_offset,
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"xref stream", xref_offset,
|
||||
"Cross-reference stream's /Index has an"
|
||||
" invalid number of values");
|
||||
}
|
||||
@ -747,7 +784,8 @@ QPDF::processXRefStream(off_t xref_offset, QPDFObjectHandle& xref_obj)
|
||||
}
|
||||
else
|
||||
{
|
||||
throw QPDFExc(this->file.getName(), xref_offset,
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"xref stream", xref_offset,
|
||||
"Cross-reference stream's /Index's item " +
|
||||
QUtil::int_to_string(i) +
|
||||
" is not an integer");
|
||||
@ -785,7 +823,8 @@ QPDF::processXRefStream(off_t xref_offset, QPDFObjectHandle& xref_obj)
|
||||
|
||||
if (expected_size != actual_size)
|
||||
{
|
||||
QPDFExc x(this->file.getName(), xref_offset,
|
||||
QPDFExc x(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"xref stream", xref_offset,
|
||||
"Cross-reference stream data has the wrong size;"
|
||||
" expected = " + QUtil::int_to_string(expected_size) +
|
||||
"; actual = " + QUtil::int_to_string(actual_size));
|
||||
@ -866,7 +905,8 @@ QPDF::processXRefStream(off_t xref_offset, QPDFObjectHandle& xref_obj)
|
||||
{
|
||||
if (! dict.getKey("/Prev").isInteger())
|
||||
{
|
||||
throw QPDFExc(this->file.getName(), this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"xref stream", this->file.getLastOffset(),
|
||||
"/Prev key in xref stream dictionary is not "
|
||||
"an integer");
|
||||
}
|
||||
@ -935,7 +975,8 @@ QPDF::insertXrefEntry(int obj, int f0, int f1, int f2, bool overwrite)
|
||||
break;
|
||||
|
||||
default:
|
||||
throw QPDFExc(this->file.getName(), 0,
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"xref stream", this->file.getLastOffset(),
|
||||
"unknown xref stream entry type " +
|
||||
QUtil::int_to_string(f0));
|
||||
break;
|
||||
@ -972,10 +1013,32 @@ QPDF::showXRefTable()
|
||||
}
|
||||
}
|
||||
|
||||
QPDFObjectHandle
|
||||
QPDF::readObject(InputSource* input, int objid, int generation,
|
||||
bool in_object_stream)
|
||||
void
|
||||
QPDF::setLastObjectDescription(std::string const& description,
|
||||
int objid, int generation)
|
||||
{
|
||||
this->last_object_description.clear();
|
||||
if (! description.empty())
|
||||
{
|
||||
this->last_object_description += description;
|
||||
if (objid > 0)
|
||||
{
|
||||
this->last_object_description += ": ";
|
||||
}
|
||||
}
|
||||
if (objid > 0)
|
||||
{
|
||||
this->last_object_description += "object " +
|
||||
QUtil::int_to_string(objid) + " " +
|
||||
QUtil::int_to_string(generation);
|
||||
}
|
||||
}
|
||||
|
||||
QPDFObjectHandle
|
||||
QPDF::readObject(InputSource* input, std::string const& description,
|
||||
int objid, int generation, bool in_object_stream)
|
||||
{
|
||||
setLastObjectDescription(description, objid, generation);
|
||||
off_t offset = input->tell();
|
||||
QPDFObjectHandle object = readObjectInternal(
|
||||
input, objid, generation, in_object_stream, false, false);
|
||||
@ -1017,7 +1080,9 @@ QPDF::readObjectInternal(InputSource* input,
|
||||
case QPDFTokenizer::tt_brace_close:
|
||||
// Don't know what to do with these for now
|
||||
QTC::TC("qpdf", "QPDF bad brace");
|
||||
throw QPDFExc(input->getName(), input->getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, input->getName(),
|
||||
this->last_object_description,
|
||||
input->getLastOffset(),
|
||||
"unexpected brace token");
|
||||
break;
|
||||
|
||||
@ -1029,7 +1094,9 @@ QPDF::readObjectInternal(InputSource* input,
|
||||
else
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF bad array close");
|
||||
throw QPDFExc(input->getName(), input->getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, input->getName(),
|
||||
this->last_object_description,
|
||||
input->getLastOffset(),
|
||||
"unexpected array close token");
|
||||
}
|
||||
break;
|
||||
@ -1042,7 +1109,9 @@ QPDF::readObjectInternal(InputSource* input,
|
||||
else
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF bad dictionary close");
|
||||
throw QPDFExc(input->getName(), input->getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, input->getName(),
|
||||
this->last_object_description,
|
||||
input->getLastOffset(),
|
||||
"unexpected dictionary close token");
|
||||
}
|
||||
break;
|
||||
@ -1097,7 +1166,9 @@ QPDF::readObjectInternal(InputSource* input,
|
||||
}
|
||||
else
|
||||
{
|
||||
throw QPDFExc(input->getName(), input->getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, input->getName(),
|
||||
this->last_object_description,
|
||||
input->getLastOffset(),
|
||||
"unknown token while reading object (" +
|
||||
value + ")");
|
||||
}
|
||||
@ -1116,7 +1187,9 @@ QPDF::readObjectInternal(InputSource* input,
|
||||
break;
|
||||
|
||||
default:
|
||||
throw QPDFExc(input->getName(), input->getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, input->getName(),
|
||||
this->last_object_description,
|
||||
input->getLastOffset(),
|
||||
"unknown token type while reading object");
|
||||
break;
|
||||
}
|
||||
@ -1153,7 +1226,8 @@ QPDF::readObjectInternal(InputSource* input,
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF dictionary odd number of elements");
|
||||
throw QPDFExc(
|
||||
input->getName(), input->getLastOffset(),
|
||||
qpdf_e_damaged_pdf, input->getName(),
|
||||
this->last_object_description, input->getLastOffset(),
|
||||
"dictionary ending here has an odd number of elements");
|
||||
}
|
||||
for (unsigned int i = 0; i < olist.size(); i += 2)
|
||||
@ -1163,7 +1237,8 @@ QPDF::readObjectInternal(InputSource* input,
|
||||
if (! key_obj.isName())
|
||||
{
|
||||
throw QPDFExc(
|
||||
input->getName(), offset,
|
||||
qpdf_e_damaged_pdf,
|
||||
input->getName(), this->last_object_description, offset,
|
||||
std::string("dictionary key not name (") +
|
||||
key_obj.unparse() + ")");
|
||||
}
|
||||
@ -1209,7 +1284,8 @@ QPDF::readObjectInternal(InputSource* input,
|
||||
if (dict.count("/Length") == 0)
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF stream without length");
|
||||
throw QPDFExc(input->getName(), offset,
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, input->getName(),
|
||||
this->last_object_description, offset,
|
||||
"stream dictionary lacks /Length key");
|
||||
}
|
||||
|
||||
@ -1217,7 +1293,8 @@ QPDF::readObjectInternal(InputSource* input,
|
||||
if (! length_obj.isInteger())
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF stream length not integer");
|
||||
throw QPDFExc(input->getName(), offset,
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, input->getName(),
|
||||
this->last_object_description, offset,
|
||||
"/Length key in stream dictionary is not "
|
||||
"an integer");
|
||||
}
|
||||
@ -1229,7 +1306,9 @@ QPDF::readObjectInternal(InputSource* input,
|
||||
QPDFTokenizer::tt_word, "endstream")))
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF missing endstream");
|
||||
throw QPDFExc(input->getName(), input->getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, input->getName(),
|
||||
this->last_object_description,
|
||||
input->getLastOffset(),
|
||||
"expected endstream");
|
||||
}
|
||||
}
|
||||
@ -1267,7 +1346,8 @@ QPDF::recoverStreamLength(InputSource* input,
|
||||
|
||||
// Try to reconstruct stream length by looking for
|
||||
// endstream(\r\n?|\n)endobj
|
||||
warn(QPDFExc(input->getName(), stream_offset,
|
||||
warn(QPDFExc(qpdf_e_damaged_pdf, input->getName(),
|
||||
this->last_object_description, stream_offset,
|
||||
"attempting to recover stream length"));
|
||||
|
||||
input->seek(0, SEEK_END);
|
||||
@ -1336,7 +1416,8 @@ QPDF::recoverStreamLength(InputSource* input,
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
throw QPDFExc(input->getName(), stream_offset,
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, input->getName(),
|
||||
this->last_object_description, stream_offset,
|
||||
"unable to recover stream data");
|
||||
}
|
||||
|
||||
@ -1356,7 +1437,9 @@ QPDF::readToken(InputSource* input)
|
||||
char ch;
|
||||
if (input->read(&ch, 1) == 0)
|
||||
{
|
||||
throw QPDFExc(input->getName(), offset, "EOF while reading token");
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, input->getName(),
|
||||
this->last_object_description, offset,
|
||||
"EOF while reading token");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1376,7 +1459,9 @@ QPDF::readToken(InputSource* input)
|
||||
|
||||
if (token.getType() == QPDFTokenizer::tt_bad)
|
||||
{
|
||||
throw QPDFExc(input->getName(), offset, token.getErrorMessage());
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, input->getName(),
|
||||
this->last_object_description, offset,
|
||||
token.getErrorMessage());
|
||||
}
|
||||
|
||||
input->setLastOffset(offset);
|
||||
@ -1385,9 +1470,12 @@ QPDF::readToken(InputSource* input)
|
||||
}
|
||||
|
||||
QPDFObjectHandle
|
||||
QPDF::readObjectAtOffset(off_t offset, int exp_objid, int exp_generation,
|
||||
QPDF::readObjectAtOffset(bool try_recovery,
|
||||
off_t offset, std::string const& description,
|
||||
int exp_objid, int exp_generation,
|
||||
int& objid, int& generation)
|
||||
{
|
||||
setLastObjectDescription(description, exp_objid, exp_generation);
|
||||
this->file.seek(offset, SEEK_SET);
|
||||
|
||||
QPDFTokenizer::Token tobjid = readToken(&this->file);
|
||||
@ -1407,7 +1495,9 @@ QPDF::readObjectAtOffset(off_t offset, int exp_objid, int exp_generation,
|
||||
if (! (objidok && genok && objok))
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF expected n n obj");
|
||||
throw QPDFExc(this->file.getName(), offset, "expected n n obj");
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
this->last_object_description, offset,
|
||||
"expected n n obj");
|
||||
}
|
||||
objid = atoi(tobjid.getValue().c_str());
|
||||
generation = atoi(tgen.getValue().c_str());
|
||||
@ -1416,7 +1506,8 @@ QPDF::readObjectAtOffset(off_t offset, int exp_objid, int exp_generation,
|
||||
(! ((objid == exp_objid) && (generation == exp_generation))))
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF err wrong objid/generation");
|
||||
throw QPDFExc(this->file.getName(), offset,
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
this->last_object_description, offset,
|
||||
std::string("expected ") +
|
||||
QUtil::int_to_string(exp_objid) + " " +
|
||||
QUtil::int_to_string(exp_generation) + " obj");
|
||||
@ -1424,7 +1515,7 @@ QPDF::readObjectAtOffset(off_t offset, int exp_objid, int exp_generation,
|
||||
}
|
||||
catch (QPDFExc& e)
|
||||
{
|
||||
if (exp_objid && this->attempt_recovery)
|
||||
if (exp_objid && try_recovery && this->attempt_recovery)
|
||||
{
|
||||
// Try again after reconstructing xref table
|
||||
reconstruct_xref(e);
|
||||
@ -1433,13 +1524,27 @@ QPDF::readObjectAtOffset(off_t offset, int exp_objid, int exp_generation,
|
||||
(this->xref_table[og].getType() == 1))
|
||||
{
|
||||
off_t new_offset = this->xref_table[og].getOffset();
|
||||
// Call readObjectAtOffset with 0 for exp_objid to
|
||||
// avoid an infinite loop.
|
||||
QPDFObjectHandle result =
|
||||
readObjectAtOffset(new_offset, 0, 0, objid, generation);
|
||||
QPDFObjectHandle result = readObjectAtOffset(
|
||||
false, new_offset, description,
|
||||
exp_objid, exp_generation, objid, generation);
|
||||
QTC::TC("qpdf", "QPDF recovered in readObjectAtOffset");
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF object gone after xref reconstruction");
|
||||
warn(QPDFExc(
|
||||
qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"", 0,
|
||||
std::string(
|
||||
"object " +
|
||||
QUtil::int_to_string(exp_objid) +
|
||||
" " +
|
||||
QUtil::int_to_string(exp_generation) +
|
||||
" not found in file after regenerating"
|
||||
" cross reference table")));
|
||||
return QPDFObjectHandle::newNull();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1448,13 +1553,14 @@ QPDF::readObjectAtOffset(off_t offset, int exp_objid, int exp_generation,
|
||||
}
|
||||
|
||||
QPDFObjectHandle oh = readObject(
|
||||
&this->file, objid, generation, false);
|
||||
&this->file, description, objid, generation, false);
|
||||
|
||||
if (! (readToken(&this->file) ==
|
||||
QPDFTokenizer::Token(QPDFTokenizer::tt_word, "endobj")))
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF err expected endobj");
|
||||
warn(QPDFExc(this->file.getName(), this->file.getLastOffset(),
|
||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
this->last_object_description, this->file.getLastOffset(),
|
||||
"expected endobj"));
|
||||
}
|
||||
|
||||
@ -1487,7 +1593,8 @@ QPDF::readObjectAtOffset(off_t offset, int exp_objid, int exp_generation,
|
||||
}
|
||||
else
|
||||
{
|
||||
throw QPDFExc(this->file.getName(), offset,
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
this->last_object_description, offset,
|
||||
"EOF after endobj");
|
||||
}
|
||||
}
|
||||
@ -1526,7 +1633,7 @@ QPDF::resolve(int objid, int generation)
|
||||
int aobjid;
|
||||
int ageneration;
|
||||
QPDFObjectHandle oh =
|
||||
readObjectAtOffset(offset, objid, generation,
|
||||
readObjectAtOffset(true, offset, "", objid, generation,
|
||||
aobjid, ageneration);
|
||||
}
|
||||
break;
|
||||
@ -1536,7 +1643,7 @@ QPDF::resolve(int objid, int generation)
|
||||
break;
|
||||
|
||||
default:
|
||||
throw QPDFExc(this->file.getName(), 0,
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(), "", 0,
|
||||
"object " +
|
||||
QUtil::int_to_string(objid) + "/" +
|
||||
QUtil::int_to_string(generation) +
|
||||
@ -1554,7 +1661,9 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
|
||||
QPDFObjectHandle obj_stream = getObjectByID(obj_stream_number, 0);
|
||||
if (! obj_stream.isStream())
|
||||
{
|
||||
throw QPDFExc(this->file.getName(), this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
this->last_object_description,
|
||||
this->file.getLastOffset(),
|
||||
"supposed object stream " +
|
||||
QUtil::int_to_string(obj_stream_number) +
|
||||
" is not a stream");
|
||||
@ -1570,7 +1679,10 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
|
||||
if (! (dict.getKey("/Type").isName() &&
|
||||
dict.getKey("/Type").getName() == "/ObjStm"))
|
||||
{
|
||||
throw QPDFExc(this->file.getName(), this->file.getLastOffset(),
|
||||
QTC::TC("qpdf", "QPDF ERR object stream with wrong type");
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
this->last_object_description,
|
||||
this->file.getLastOffset(),
|
||||
"supposed object stream " +
|
||||
QUtil::int_to_string(obj_stream_number) +
|
||||
" has wrong type");
|
||||
@ -1579,7 +1691,9 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
|
||||
if (! (dict.getKey("/N").isInteger() &&
|
||||
dict.getKey("/First").isInteger()))
|
||||
{
|
||||
throw QPDFExc(this->file.getName(), this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
this->last_object_description,
|
||||
this->file.getLastOffset(),
|
||||
"object stream " +
|
||||
QUtil::int_to_string(obj_stream_number) +
|
||||
" has incorrect keys");
|
||||
@ -1602,7 +1716,8 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
|
||||
if (! ((tnum.getType() == QPDFTokenizer::tt_integer) &&
|
||||
(toffset.getType() == QPDFTokenizer::tt_integer)))
|
||||
{
|
||||
throw QPDFExc(input.getName(), input.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, input.getName(),
|
||||
this->last_object_description, input.getLastOffset(),
|
||||
"expected integer in object stream header");
|
||||
}
|
||||
|
||||
@ -1617,7 +1732,7 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
|
||||
int obj = (*iter).first;
|
||||
int offset = (*iter).second;
|
||||
input.seek(offset, SEEK_SET);
|
||||
QPDFObjectHandle oh = readObject(&input, obj, 0, true);
|
||||
QPDFObjectHandle oh = readObject(&input, "", obj, 0, true);
|
||||
|
||||
// Store in cache
|
||||
ObjGen og(obj, 0);
|
||||
@ -1830,17 +1945,25 @@ QPDF::pipeStreamData(int objid, int generation,
|
||||
size_t len = this->file.read(buf, to_read);
|
||||
if (len == 0)
|
||||
{
|
||||
throw QPDFExc(this->file.getName(), this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf,
|
||||
this->file.getName(),
|
||||
this->last_object_description,
|
||||
this->file.getLastOffset(),
|
||||
"unexpected EOF reading stream data");
|
||||
}
|
||||
length -= len;
|
||||
pipeline->write((unsigned char*)buf, len);
|
||||
}
|
||||
}
|
||||
catch (QPDFExc& e)
|
||||
{
|
||||
warn(e);
|
||||
}
|
||||
catch (std::runtime_error& e)
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF decoding error warning");
|
||||
warn(QPDFExc(this->file.getName(), this->file.getLastOffset(),
|
||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"", this->file.getLastOffset(),
|
||||
"error decoding stream data for object " +
|
||||
QUtil::int_to_string(objid) + " " +
|
||||
QUtil::int_to_string(generation) + ": " + e.what()));
|
||||
@ -1896,6 +2019,9 @@ QPDF::getAllPagesInternal(QPDFObjectHandle cur_pages,
|
||||
}
|
||||
else
|
||||
{
|
||||
throw QPDFExc(this->file.getName() + ": invalid Type in page tree");
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
this->last_object_description,
|
||||
this->file.getLastOffset(),
|
||||
+ ": invalid Type in page tree");
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,56 @@
|
||||
#include <qpdf/QPDFExc.hh>
|
||||
#include <qpdf/QUtil.hh>
|
||||
|
||||
QPDFExc::QPDFExc(std::string const& message) :
|
||||
std::runtime_error(message)
|
||||
{
|
||||
}
|
||||
|
||||
QPDFExc::QPDFExc(std::string const& filename, int offset,
|
||||
QPDFExc::QPDFExc(qpdf_error_code_e error_code,
|
||||
std::string const& filename,
|
||||
std::string const& object,
|
||||
off_t offset,
|
||||
std::string const& message) :
|
||||
std::runtime_error(filename + ": offset " + QUtil::int_to_string(offset) +
|
||||
": " + message)
|
||||
std::runtime_error(createWhat(filename, object, offset, message)),
|
||||
error_code(error_code),
|
||||
filename(filename),
|
||||
object(object),
|
||||
offset(offset),
|
||||
message(message)
|
||||
{
|
||||
}
|
||||
|
||||
QPDFExc::~QPDFExc() throw ()
|
||||
{
|
||||
}
|
||||
|
||||
std::string
|
||||
QPDFExc::createWhat(std::string const& filename,
|
||||
std::string const& object,
|
||||
off_t offset,
|
||||
std::string const& message)
|
||||
{
|
||||
std::string result;
|
||||
if (! filename.empty())
|
||||
{
|
||||
result += filename;
|
||||
}
|
||||
if (! (object.empty() && offset == 0))
|
||||
{
|
||||
result += " (";
|
||||
if (! object.empty())
|
||||
{
|
||||
result += object;
|
||||
if (offset > 0)
|
||||
{
|
||||
result += ", ";
|
||||
}
|
||||
}
|
||||
if (offset > 0)
|
||||
{
|
||||
result += "file position " + QUtil::int_to_string(offset);
|
||||
}
|
||||
result += ")";
|
||||
}
|
||||
if (! result.empty())
|
||||
{
|
||||
result += ": ";
|
||||
}
|
||||
result += message;
|
||||
return result;
|
||||
}
|
||||
|
@ -16,7 +16,8 @@ QPDFXRefEntry::QPDFXRefEntry(int type, int field1, int field2) :
|
||||
{
|
||||
if ((type < 1) || (type > 2))
|
||||
{
|
||||
throw QPDFExc("invalid xref type " + QUtil::int_to_string(type));
|
||||
throw std::logic_error(
|
||||
"invalid xref type " + QUtil::int_to_string(type));
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,7 +32,7 @@ QPDFXRefEntry::getOffset() const
|
||||
{
|
||||
if (this->type != 1)
|
||||
{
|
||||
throw QPDFExc(
|
||||
throw std::logic_error(
|
||||
"getOffset called for xref entry of type != 1");
|
||||
}
|
||||
return this->field1;
|
||||
@ -42,7 +43,7 @@ QPDFXRefEntry::getObjStreamNumber() const
|
||||
{
|
||||
if (this->type != 2)
|
||||
{
|
||||
throw QPDFExc(
|
||||
throw std::logic_error(
|
||||
"getObjStreamNumber called for xref entry of type != 2");
|
||||
}
|
||||
return this->field1;
|
||||
@ -53,7 +54,7 @@ QPDFXRefEntry::getObjStreamIndex() const
|
||||
{
|
||||
if (this->type != 2)
|
||||
{
|
||||
throw QPDFExc(
|
||||
throw std::logic_error(
|
||||
"getObjStreamIndex called for xref entry of type != 2");
|
||||
}
|
||||
return this->field2;
|
||||
|
@ -59,7 +59,7 @@ QPDF_Stream::getStreamData()
|
||||
Pl_Buffer buf("stream data buffer");
|
||||
if (! pipeStreamData(&buf, true, false, false))
|
||||
{
|
||||
throw QPDFExc("getStreamData called on unfilterable stream");
|
||||
throw std::logic_error("getStreamData called on unfilterable stream");
|
||||
}
|
||||
return buf.getBuffer();
|
||||
}
|
||||
@ -208,8 +208,9 @@ QPDF_Stream::filterable(std::vector<std::string>& filters,
|
||||
if (! filters_okay)
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF_Stream invalid filter");
|
||||
throw QPDFExc(qpdf->getFilename(), this->offset,
|
||||
"invalid filter object type for this stream");
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, qpdf->getFilename(),
|
||||
"", this->offset,
|
||||
"stream filter type is not name or array");
|
||||
}
|
||||
|
||||
// `filters' now contains a list of filters to be applied in
|
||||
|
@ -337,14 +337,16 @@ QPDF::initializeEncryption()
|
||||
(id_obj.getArrayNItems() == 2) &&
|
||||
id_obj.getArrayItem(0).isString()))
|
||||
{
|
||||
throw QPDFExc(this->file.getName(), this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"trailer", this->file.getLastOffset(),
|
||||
"invalid /ID in trailer dictionary");
|
||||
}
|
||||
|
||||
std::string id1 = id_obj.getArrayItem(0).getStringValue();
|
||||
if (id1.length() != id_bytes)
|
||||
{
|
||||
throw QPDFExc(this->file.getName(), this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"trailer", this->file.getLastOffset(),
|
||||
"first /ID string in trailer dictionary has "
|
||||
"incorrect length");
|
||||
}
|
||||
@ -352,19 +354,23 @@ QPDF::initializeEncryption()
|
||||
QPDFObjectHandle encryption_dict = this->trailer.getKey("/Encrypt");
|
||||
if (! encryption_dict.isDictionary())
|
||||
{
|
||||
throw QPDFExc(this->file.getName(), this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
this->last_object_description,
|
||||
this->file.getLastOffset(),
|
||||
"/Encrypt in trailer dictionary is not a dictionary");
|
||||
}
|
||||
|
||||
if (! (encryption_dict.getKey("/Filter").isName() &&
|
||||
(encryption_dict.getKey("/Filter").getName() == "/Standard")))
|
||||
{
|
||||
throw QPDFExc(this->file.getName(), this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"encryption dictionary", this->file.getLastOffset(),
|
||||
"unsupported encryption filter");
|
||||
}
|
||||
if (! encryption_dict.getKey("/SubFilter").isNull())
|
||||
{
|
||||
warn(QPDFExc(this->file.getName(), this->file.getLastOffset(),
|
||||
warn(QPDFExc(qpdf_e_unsupported, this->file.getName(),
|
||||
"encryption dictionary", this->file.getLastOffset(),
|
||||
"file uses encryption SubFilters,"
|
||||
" which qpdf does not support"));
|
||||
}
|
||||
@ -375,7 +381,8 @@ QPDF::initializeEncryption()
|
||||
encryption_dict.getKey("/U").isString() &&
|
||||
encryption_dict.getKey("/P").isInteger()))
|
||||
{
|
||||
throw QPDFExc(this->file.getName(), this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"encryption dictionary", this->file.getLastOffset(),
|
||||
"some encryption dictionary parameters are missing "
|
||||
"or the wrong type");
|
||||
}
|
||||
@ -389,7 +396,8 @@ QPDF::initializeEncryption()
|
||||
if (! (((R == 2) || (R == 3) || (R == 4)) &&
|
||||
((V == 1) || (V == 2) || (V == 4))))
|
||||
{
|
||||
throw QPDFExc(this->file.getName(), this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_unsupported, this->file.getName(),
|
||||
"encryption dictionary", this->file.getLastOffset(),
|
||||
"Unsupported /R or /V in encryption dictionary");
|
||||
}
|
||||
|
||||
@ -397,7 +405,8 @@ QPDF::initializeEncryption()
|
||||
|
||||
if (! ((O.length() == key_bytes) && (U.length() == key_bytes)))
|
||||
{
|
||||
throw QPDFExc(this->file.getName(), this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"encryption dictionary", this->file.getLastOffset(),
|
||||
"incorrect length for /O and/or /P in "
|
||||
"encryption dictionary");
|
||||
}
|
||||
@ -408,7 +417,8 @@ QPDF::initializeEncryption()
|
||||
Length = encryption_dict.getKey("/Length").getIntValue();
|
||||
if ((Length % 8) || (Length < 40) || (Length > 128))
|
||||
{
|
||||
throw QPDFExc(this->file.getName(), this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"encryption dictionary", this->file.getLastOffset(),
|
||||
"invalid /Length value in encryption dictionary");
|
||||
}
|
||||
}
|
||||
@ -471,7 +481,8 @@ QPDF::initializeEncryption()
|
||||
}
|
||||
if (this->cf_file != this->cf_stream)
|
||||
{
|
||||
throw QPDFExc(this->file.getName(), this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_unsupported, this->file.getName(),
|
||||
"encryption dictionary", this->file.getLastOffset(),
|
||||
"This document has embedded files that are"
|
||||
" encrypted differently from the rest of the file."
|
||||
" qpdf does not presently support this due to"
|
||||
@ -492,7 +503,8 @@ QPDF::initializeEncryption()
|
||||
}
|
||||
else
|
||||
{
|
||||
throw QPDFExc(this->file.getName() + ": invalid password");
|
||||
throw QPDFExc(qpdf_e_password, this->file.getName(),
|
||||
"", 0, "invalid password");
|
||||
}
|
||||
|
||||
this->encryption_key = compute_encryption_key(this->user_password, data);
|
||||
@ -542,7 +554,9 @@ QPDF::decryptString(std::string& str, int objid, int generation)
|
||||
break;
|
||||
|
||||
default:
|
||||
warn(QPDFExc(this->file.getName(), this->file.getLastOffset(),
|
||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
this->last_object_description,
|
||||
this->file.getLastOffset(),
|
||||
"unknown encryption filter for strings"
|
||||
" (check /StrF in /Encrypt dictionary);"
|
||||
" strings may be decrypted improperly"));
|
||||
@ -554,28 +568,47 @@ QPDF::decryptString(std::string& str, int objid, int generation)
|
||||
}
|
||||
|
||||
std::string key = getKeyForObject(objid, generation, use_aes);
|
||||
if (use_aes)
|
||||
try
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF_encryption aes decode string");
|
||||
assert(key.length() == Pl_AES_PDF::key_size);
|
||||
Pl_Buffer bufpl("decrypted string");
|
||||
Pl_AES_PDF pl("aes decrypt string", &bufpl, false,
|
||||
(unsigned char const*)key.c_str());
|
||||
pl.write((unsigned char*)str.c_str(), str.length());
|
||||
pl.finish();
|
||||
Buffer* buf = bufpl.getBuffer();
|
||||
str = std::string((char*)buf->getBuffer(), (size_t)buf->getSize());
|
||||
delete buf;
|
||||
if (use_aes)
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF_encryption aes decode string");
|
||||
assert(key.length() == Pl_AES_PDF::key_size);
|
||||
Pl_Buffer bufpl("decrypted string");
|
||||
Pl_AES_PDF pl("aes decrypt string", &bufpl, false,
|
||||
(unsigned char const*)key.c_str());
|
||||
pl.write((unsigned char*)str.c_str(), str.length());
|
||||
pl.finish();
|
||||
PointerHolder<Buffer> buf = bufpl.getBuffer();
|
||||
str = std::string((char*)buf.getPointer()->getBuffer(),
|
||||
(size_t)buf.getPointer()->getSize());
|
||||
}
|
||||
else
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF_encryption rc4 decode string");
|
||||
unsigned int vlen = str.length();
|
||||
// Using PointerHolder will cause a new char[] to be deleted
|
||||
// with delete instead of delete [], but it's okay since the
|
||||
// array is of a fundamental type, so there is no destructor
|
||||
// to be called. Using PointerHolder guarantees that tmp will
|
||||
// be freed even if rc4.process throws an exception.
|
||||
PointerHolder<char> tmp = QUtil::copy_string(str);
|
||||
RC4 rc4((unsigned char const*)key.c_str(), key.length());
|
||||
rc4.process((unsigned char*)tmp.getPointer(), vlen);
|
||||
str = std::string(tmp.getPointer(), vlen);
|
||||
}
|
||||
}
|
||||
else
|
||||
catch (QPDFExc& e)
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF_encryption rc4 decode string");
|
||||
unsigned int vlen = str.length();
|
||||
char* tmp = QUtil::copy_string(str);
|
||||
RC4 rc4((unsigned char const*)key.c_str(), key.length());
|
||||
rc4.process((unsigned char*)tmp, vlen);
|
||||
str = std::string(tmp, vlen);
|
||||
delete [] tmp;
|
||||
throw;
|
||||
}
|
||||
catch (std::runtime_error& e)
|
||||
{
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
this->last_object_description, this->file.getLastOffset(),
|
||||
"error decrypting string for object " +
|
||||
QUtil::int_to_string(objid) + " " +
|
||||
QUtil::int_to_string(generation) + ": " + e.what());
|
||||
}
|
||||
}
|
||||
|
||||
@ -645,7 +678,9 @@ QPDF::decryptStream(Pipeline*& pipeline, int objid, int generation,
|
||||
|
||||
default:
|
||||
// filter local to this stream.
|
||||
warn(QPDFExc(this->file.getName(), this->file.getLastOffset(),
|
||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
this->last_object_description,
|
||||
this->file.getLastOffset(),
|
||||
"unknown encryption filter for streams"
|
||||
" (check " + method_source + ");"
|
||||
" streams may be decrypted improperly"));
|
||||
|
@ -175,7 +175,8 @@ QPDF::readLinearizationData()
|
||||
|
||||
if (! isLinearized())
|
||||
{
|
||||
throw QPDFExc(this->file.getName() + " is not linearized");
|
||||
throw std::logic_error("called readLinearizationData for file"
|
||||
" that is not linearized");
|
||||
}
|
||||
|
||||
// /L is read and stored in linp by isLinearized()
|
||||
@ -193,7 +194,10 @@ QPDF::readLinearizationData()
|
||||
T.isInteger() &&
|
||||
(P.isInteger() || P.isNull())))
|
||||
{
|
||||
throw QPDFExc("some keys in linearization dictionary are of "
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"linearization dictionary",
|
||||
this->file.getLastOffset(),
|
||||
"some keys in linearization dictionary are of "
|
||||
"the wrong type");
|
||||
}
|
||||
|
||||
@ -201,7 +205,10 @@ QPDF::readLinearizationData()
|
||||
unsigned int n_H_items = H.getArrayNItems();
|
||||
if (! ((n_H_items == 2) || (n_H_items == 4)))
|
||||
{
|
||||
throw QPDFExc("H has the wrong number of items");
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"linearization dictionary",
|
||||
this->file.getLastOffset(),
|
||||
"H has the wrong number of items");
|
||||
}
|
||||
|
||||
std::vector<int> H_items;
|
||||
@ -214,7 +221,10 @@ QPDF::readLinearizationData()
|
||||
}
|
||||
else
|
||||
{
|
||||
throw QPDFExc("some H items are of the wrong type");
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"linearization dictionary",
|
||||
this->file.getLastOffset(),
|
||||
"some H items are of the wrong type");
|
||||
}
|
||||
}
|
||||
|
||||
@ -301,13 +311,17 @@ QPDF::readHintStream(Pipeline& pl, off_t offset, size_t length)
|
||||
{
|
||||
int obj;
|
||||
int gen;
|
||||
QPDFObjectHandle H = readObjectAtOffset(offset, 0, 0, obj, gen);
|
||||
QPDFObjectHandle H = readObjectAtOffset(
|
||||
false, offset, "linearization hint stream", 0, 0, obj, gen);
|
||||
ObjCache& oc = this->obj_cache[ObjGen(obj, gen)];
|
||||
off_t min_end_offset = oc.end_before_space;
|
||||
off_t max_end_offset = oc.end_after_space;
|
||||
if (! H.isStream())
|
||||
{
|
||||
throw QPDFExc("hint table is not a stream");
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"linearization dictionary",
|
||||
this->file.getLastOffset(),
|
||||
"hint table is not a stream");
|
||||
}
|
||||
|
||||
QPDFObjectHandle Hdict = H.getDict();
|
||||
@ -340,7 +354,10 @@ QPDF::readHintStream(Pipeline& pl, off_t offset, size_t length)
|
||||
std::cout << "expected = " << computed_end
|
||||
<< "; actual = " << min_end_offset << ".."
|
||||
<< max_end_offset << std::endl;
|
||||
throw QPDFExc("hint table length mismatch");
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"linearization dictionary",
|
||||
this->file.getLastOffset(),
|
||||
"hint table length mismatch");
|
||||
}
|
||||
H.pipeStreamData(&pl, true, false, false);
|
||||
return Hdict;
|
||||
@ -651,8 +668,7 @@ QPDF::getLinearizationOffset(ObjGen const& og)
|
||||
break;
|
||||
|
||||
default:
|
||||
throw QPDFExc(
|
||||
this->file.getName(), 0,
|
||||
throw std::logic_error(
|
||||
"getLinearizationOffset called for xref entry not of type 1 or 2");
|
||||
break;
|
||||
}
|
||||
|
@ -233,9 +233,12 @@ QPDF::optimizePagesTree(
|
||||
{
|
||||
if (! allow_changes)
|
||||
{
|
||||
throw QPDFExc(this->file.getName() +
|
||||
": optimize detected an "
|
||||
"inheritable resource");
|
||||
throw QPDFExc(qpdf_e_internal, this->file.getName(),
|
||||
this->last_object_description,
|
||||
this->file.getLastOffset(),
|
||||
"optimize detected an "
|
||||
"inheritable resource when called "
|
||||
"in no-change mode");
|
||||
}
|
||||
|
||||
// This is an inheritable resource
|
||||
@ -338,7 +341,10 @@ QPDF::optimizePagesTree(
|
||||
}
|
||||
else
|
||||
{
|
||||
throw QPDFExc(this->file.getName() + ": invalid Type in page tree");
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
this->last_object_description,
|
||||
this->file.getLastOffset(),
|
||||
"invalid Type in page tree");
|
||||
}
|
||||
}
|
||||
|
||||
|
12
qpdf/qpdf.cc
12
qpdf/qpdf.cc
@ -2,6 +2,7 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <qpdf/QUtil.hh>
|
||||
#include <qpdf/QTC.hh>
|
||||
@ -533,6 +534,7 @@ parse_encrypt_options(
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
whoami = QUtil::getWhoami(argv[0]);
|
||||
setlinebuf(stdout);
|
||||
|
||||
// For libtool's sake....
|
||||
if (strncmp(whoami, "lt-", 3) == 0)
|
||||
@ -892,7 +894,15 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
if (show_linearization)
|
||||
{
|
||||
pdf.showLinearizationData();
|
||||
if (pdf.isLinearized())
|
||||
{
|
||||
pdf.showLinearizationData();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << infilename << " is not linearized"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
if (show_xref)
|
||||
{
|
||||
|
@ -171,3 +171,5 @@ QPDFWriter forced version disabled encryption 0
|
||||
qpdf-c called qpdf_set_r4_encryption_parameters 0
|
||||
qpdf-c called qpdf_set_static_aes_IV 0
|
||||
QPDF_encryption stream crypt filter 0
|
||||
QPDF ERR object stream with wrong type 0
|
||||
QPDF object gone after xref reconstruction 0
|
||||
|
@ -191,6 +191,8 @@ my @badfiles = ("not a PDF file", # 1
|
||||
"unknown stream /Filter", # 31
|
||||
"obj/gen mismatch", # 32
|
||||
"invalid stream /Filter and xref", # 33
|
||||
"obj/gen in wrong place", # 34
|
||||
"object stream of wrong type", # 35
|
||||
);
|
||||
|
||||
$n_tests += @badfiles + 5;
|
||||
@ -249,7 +251,7 @@ $n_tests += @badfiles + 8;
|
||||
# though in some cases it may. Acrobat Reader would not be able to
|
||||
# recover any of these files any better.
|
||||
my %recover_failures = ();
|
||||
for (1, 7, 13..21, 24..27, 29..30, 33)
|
||||
for (1, 7, 13..21, 24, 29..30, 33, 35)
|
||||
{
|
||||
$recover_failures{$_} = 1;
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
WARNING: append-page-content-damaged.pdf: offset 0: file is damaged
|
||||
WARNING: append-page-content-damaged.pdf: file is damaged
|
||||
WARNING: append-page-content-damaged.pdf: can't find startxref
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
version: 1.3
|
||||
linearized: 0
|
||||
encrypted: 0
|
||||
warning: append-page-content-damaged.pdf: offset 0: file is damaged
|
||||
warning: append-page-content-damaged.pdf: file is damaged
|
||||
warning: append-page-content-damaged.pdf: can't find startxref
|
||||
warning: Attempting to reconstruct cross-reference table
|
||||
|
@ -1,4 +1,4 @@
|
||||
WARNING: append-page-content-damaged.pdf: offset 0: file is damaged
|
||||
WARNING: append-page-content-damaged.pdf: file is damaged
|
||||
WARNING: append-page-content-damaged.pdf: can't find startxref
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
checking append-page-content-damaged.pdf
|
||||
|
@ -1,4 +1,4 @@
|
||||
WARNING: append-page-content-damaged.pdf: offset 0: file is damaged
|
||||
WARNING: append-page-content-damaged.pdf: file is damaged
|
||||
WARNING: append-page-content-damaged.pdf: can't find startxref
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
qpdf: operation succeeded with warnings; resulting file may have some problems
|
||||
|
@ -1 +1 @@
|
||||
bad1.pdf: offset 0: not a PDF file
|
||||
bad1.pdf: not a PDF file
|
||||
|
@ -1 +1 @@
|
||||
bad1.pdf: offset 0: not a PDF file
|
||||
bad1.pdf: not a PDF file
|
||||
|
@ -1,5 +1,5 @@
|
||||
WARNING: bad10.pdf: offset 0: file is damaged
|
||||
WARNING: bad10.pdf: offset 712: /Size key in trailer dictionary is not an integer
|
||||
WARNING: bad10.pdf: file is damaged
|
||||
WARNING: bad10.pdf (trailer, file position 712): /Size key in trailer dictionary is not an integer
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
/QTest is implicit
|
||||
/QTest is direct
|
||||
|
@ -1 +1 @@
|
||||
bad10.pdf: offset 712: /Size key in trailer dictionary is not an integer
|
||||
bad10.pdf (trailer, file position 712): /Size key in trailer dictionary is not an integer
|
||||
|
@ -1,5 +1,5 @@
|
||||
WARNING: bad11.pdf: offset 0: file is damaged
|
||||
WARNING: bad11.pdf: offset 905: /Prev key in trailer dictionary is not an integer
|
||||
WARNING: bad11.pdf: file is damaged
|
||||
WARNING: bad11.pdf (trailer, file position 905): /Prev key in trailer dictionary is not an integer
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
/QTest is implicit
|
||||
/QTest is direct
|
||||
|
@ -1 +1 @@
|
||||
bad11.pdf: offset 905: /Prev key in trailer dictionary is not an integer
|
||||
bad11.pdf (trailer, file position 905): /Prev key in trailer dictionary is not an integer
|
||||
|
@ -1,4 +1,4 @@
|
||||
WARNING: bad13.pdf: offset 0: file is damaged
|
||||
WARNING: bad13.pdf: offset 753: unexpected brace token
|
||||
WARNING: bad13.pdf: file is damaged
|
||||
WARNING: bad13.pdf (trailer, file position 753): unexpected brace token
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
bad13.pdf: offset 753: unexpected brace token
|
||||
bad13.pdf (trailer, file position 753): unexpected brace token
|
||||
|
@ -1 +1 @@
|
||||
bad13.pdf: offset 753: unexpected brace token
|
||||
bad13.pdf (trailer, file position 753): unexpected brace token
|
||||
|
@ -1,4 +1,4 @@
|
||||
WARNING: bad14.pdf: offset 0: file is damaged
|
||||
WARNING: bad14.pdf: offset 753: unexpected brace token
|
||||
WARNING: bad14.pdf: file is damaged
|
||||
WARNING: bad14.pdf (trailer, file position 753): unexpected brace token
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
bad14.pdf: offset 753: unexpected brace token
|
||||
bad14.pdf (trailer, file position 753): unexpected brace token
|
||||
|
@ -1 +1 @@
|
||||
bad14.pdf: offset 753: unexpected brace token
|
||||
bad14.pdf (trailer, file position 753): unexpected brace token
|
||||
|
@ -1,4 +1,4 @@
|
||||
WARNING: bad15.pdf: offset 0: file is damaged
|
||||
WARNING: bad15.pdf: offset 753: unexpected array close token
|
||||
WARNING: bad15.pdf: file is damaged
|
||||
WARNING: bad15.pdf (trailer, file position 753): unexpected array close token
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
bad15.pdf: offset 753: unexpected array close token
|
||||
bad15.pdf (trailer, file position 753): unexpected array close token
|
||||
|
@ -1 +1 @@
|
||||
bad15.pdf: offset 753: unexpected array close token
|
||||
bad15.pdf (trailer, file position 753): unexpected array close token
|
||||
|
@ -1,4 +1,4 @@
|
||||
WARNING: bad16.pdf: offset 0: file is damaged
|
||||
WARNING: bad16.pdf: offset 753: unexpected dictionary close token
|
||||
WARNING: bad16.pdf: file is damaged
|
||||
WARNING: bad16.pdf (trailer, file position 753): unexpected dictionary close token
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
bad16.pdf: offset 753: unexpected dictionary close token
|
||||
bad16.pdf (trailer, file position 753): unexpected dictionary close token
|
||||
|
@ -1 +1 @@
|
||||
bad16.pdf: offset 753: unexpected dictionary close token
|
||||
bad16.pdf (trailer, file position 753): unexpected dictionary close token
|
||||
|
@ -1,4 +1,4 @@
|
||||
WARNING: bad17.pdf: offset 0: file is damaged
|
||||
WARNING: bad17.pdf: offset 753: dictionary ending here has an odd number of elements
|
||||
WARNING: bad17.pdf: file is damaged
|
||||
WARNING: bad17.pdf (trailer, file position 753): dictionary ending here has an odd number of elements
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
bad17.pdf: offset 753: dictionary ending here has an odd number of elements
|
||||
bad17.pdf (trailer, file position 753): dictionary ending here has an odd number of elements
|
||||
|
@ -1 +1 @@
|
||||
bad17.pdf: offset 753: dictionary ending here has an odd number of elements
|
||||
bad17.pdf (trailer, file position 753): dictionary ending here has an odd number of elements
|
||||
|
@ -1,4 +1,4 @@
|
||||
WARNING: bad18.pdf: offset 0: file is damaged
|
||||
WARNING: bad18.pdf: offset 753: unexpected )
|
||||
WARNING: bad18.pdf: file is damaged
|
||||
WARNING: bad18.pdf (trailer, file position 753): unexpected )
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
bad18.pdf: offset 753: unexpected )
|
||||
bad18.pdf (trailer, file position 753): unexpected )
|
||||
|
@ -1 +1 @@
|
||||
bad18.pdf: offset 753: unexpected )
|
||||
bad18.pdf (trailer, file position 753): unexpected )
|
||||
|
@ -1,4 +1,4 @@
|
||||
WARNING: bad19.pdf: offset 0: file is damaged
|
||||
WARNING: bad19.pdf: offset 753: unexpected >
|
||||
WARNING: bad19.pdf: file is damaged
|
||||
WARNING: bad19.pdf (trailer, file position 753): unexpected >
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
bad19.pdf: offset 753: unexpected >
|
||||
bad19.pdf (trailer, file position 753): unexpected >
|
||||
|
@ -1 +1 @@
|
||||
bad19.pdf: offset 753: unexpected >
|
||||
bad19.pdf (trailer, file position 753): unexpected >
|
||||
|
@ -1,4 +1,4 @@
|
||||
WARNING: bad2.pdf: offset 0: file is damaged
|
||||
WARNING: bad2.pdf: file is damaged
|
||||
WARNING: bad2.pdf: can't find startxref
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
/QTest is implicit
|
||||
|
@ -1,4 +1,4 @@
|
||||
WARNING: bad20.pdf: offset 0: file is damaged
|
||||
WARNING: bad20.pdf: offset 753: invalid character (q) in hexstring
|
||||
WARNING: bad20.pdf: file is damaged
|
||||
WARNING: bad20.pdf (trailer, file position 753): invalid character (q) in hexstring
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
bad20.pdf: offset 753: invalid character (q) in hexstring
|
||||
bad20.pdf (trailer, file position 753): invalid character (q) in hexstring
|
||||
|
@ -1 +1 @@
|
||||
bad20.pdf: offset 753: invalid character (q) in hexstring
|
||||
bad20.pdf (trailer, file position 753): invalid character (q) in hexstring
|
||||
|
@ -1,4 +1,4 @@
|
||||
WARNING: bad21.pdf: offset 0: file is damaged
|
||||
WARNING: bad21.pdf: offset 742: invalid name token
|
||||
WARNING: bad21.pdf: file is damaged
|
||||
WARNING: bad21.pdf (trailer, file position 742): invalid name token
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
bad21.pdf: offset 742: invalid name token
|
||||
bad21.pdf (trailer, file position 742): invalid name token
|
||||
|
@ -1 +1 @@
|
||||
bad21.pdf: offset 742: invalid name token
|
||||
bad21.pdf (trailer, file position 742): invalid name token
|
||||
|
@ -1,4 +1,4 @@
|
||||
WARNING: bad22.pdf: offset 341: attempting to recover stream length
|
||||
WARNING: bad22.pdf (object 4 0, file position 341): attempting to recover stream length
|
||||
/QTest is indirect
|
||||
/QTest is a stream. Dictionary: << /Qength 44 >>
|
||||
Raw stream data:
|
||||
|
@ -1 +1 @@
|
||||
bad22.pdf: offset 317: stream dictionary lacks /Length key
|
||||
bad22.pdf (object 4 0, file position 317): stream dictionary lacks /Length key
|
||||
|
@ -1,4 +1,4 @@
|
||||
WARNING: bad23.pdf: offset 341: attempting to recover stream length
|
||||
WARNING: bad23.pdf (object 4 0, file position 341): attempting to recover stream length
|
||||
/QTest is indirect
|
||||
/QTest is a stream. Dictionary: << /Length () >>
|
||||
Raw stream data:
|
||||
|
@ -1 +1 @@
|
||||
bad23.pdf: offset 317: /Length key in stream dictionary is not an integer
|
||||
bad23.pdf (object 4 0, file position 317): /Length key in stream dictionary is not an integer
|
||||
|
@ -1,2 +1,2 @@
|
||||
WARNING: bad24.pdf: offset 341: attempting to recover stream length
|
||||
bad24.pdf: offset 341: unable to recover stream data
|
||||
WARNING: bad24.pdf (object 4 0, file position 341): attempting to recover stream length
|
||||
bad24.pdf (object 4 0, file position 341): unable to recover stream data
|
||||
|
@ -1 +1 @@
|
||||
bad24.pdf: offset 385: expected endstream
|
||||
bad24.pdf (object 4 0, file position 385): expected endstream
|
||||
|
@ -1,4 +1,10 @@
|
||||
WARNING: bad25.pdf: offset 0: file is damaged
|
||||
WARNING: bad25.pdf: offset 307: expected n n obj
|
||||
WARNING: bad25.pdf: file is damaged
|
||||
WARNING: bad25.pdf (object 4 0, file position 307): expected n n obj
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
bad25.pdf: offset 307: expected n n obj
|
||||
WARNING: bad25.pdf: object 4 0 not found in file after regenerating cross reference table
|
||||
/QTest is implicit
|
||||
/QTest is indirect
|
||||
/QTest is null
|
||||
unparse: 4 0 R
|
||||
unparseResolved: null
|
||||
test 1 done
|
||||
|
@ -1 +1 @@
|
||||
bad25.pdf: offset 307: expected n n obj
|
||||
bad25.pdf (object 4 0, file position 307): expected n n obj
|
||||
|
@ -1,4 +1,10 @@
|
||||
WARNING: bad26.pdf: offset 0: file is damaged
|
||||
WARNING: bad26.pdf: offset 307: expected n n obj
|
||||
WARNING: bad26.pdf: file is damaged
|
||||
WARNING: bad26.pdf (object 4 0, file position 307): expected n n obj
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
bad26.pdf: offset 307: expected n n obj
|
||||
WARNING: bad26.pdf: object 4 0 not found in file after regenerating cross reference table
|
||||
/QTest is implicit
|
||||
/QTest is indirect
|
||||
/QTest is null
|
||||
unparse: 4 0 R
|
||||
unparseResolved: null
|
||||
test 1 done
|
||||
|
@ -1 +1 @@
|
||||
bad26.pdf: offset 307: expected n n obj
|
||||
bad26.pdf (object 4 0, file position 307): expected n n obj
|
||||
|
@ -1,4 +1,10 @@
|
||||
WARNING: bad27.pdf: offset 0: file is damaged
|
||||
WARNING: bad27.pdf: offset 307: expected n n obj
|
||||
WARNING: bad27.pdf: file is damaged
|
||||
WARNING: bad27.pdf (object 4 0, file position 307): expected n n obj
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
bad27.pdf: offset 307: expected n n obj
|
||||
WARNING: bad27.pdf: object 4 0 not found in file after regenerating cross reference table
|
||||
/QTest is implicit
|
||||
/QTest is indirect
|
||||
/QTest is null
|
||||
unparse: 4 0 R
|
||||
unparseResolved: null
|
||||
test 1 done
|
||||
|
@ -1 +1 @@
|
||||
bad27.pdf: offset 307: expected n n obj
|
||||
bad27.pdf (object 4 0, file position 307): expected n n obj
|
||||
|
@ -1,4 +1,4 @@
|
||||
WARNING: bad28.pdf: offset 395: expected endobj
|
||||
WARNING: bad28.pdf (object 4 0, file position 395): expected endobj
|
||||
/QTest is indirect
|
||||
/QTest is a stream. Dictionary: << /Length 44 >>
|
||||
Raw stream data:
|
||||
|
@ -1,4 +1,4 @@
|
||||
WARNING: bad28.pdf: offset 395: expected endobj
|
||||
WARNING: bad28.pdf (object 4 0, file position 395): expected endobj
|
||||
/QTest is indirect
|
||||
/QTest is a stream. Dictionary: << /Length 44 >>
|
||||
Raw stream data:
|
||||
|
@ -1,4 +1,4 @@
|
||||
WARNING: bad29.pdf: offset 0: file is damaged
|
||||
WARNING: bad29.pdf: offset 742: null character not allowed in name token
|
||||
WARNING: bad29.pdf: file is damaged
|
||||
WARNING: bad29.pdf (trailer, file position 742): null character not allowed in name token
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
bad29.pdf: offset 742: null character not allowed in name token
|
||||
bad29.pdf (trailer, file position 742): null character not allowed in name token
|
||||
|
@ -1 +1 @@
|
||||
bad29.pdf: offset 742: null character not allowed in name token
|
||||
bad29.pdf (trailer, file position 742): null character not allowed in name token
|
||||
|
@ -1,5 +1,5 @@
|
||||
WARNING: bad3.pdf: offset 0: file is damaged
|
||||
WARNING: bad3.pdf: offset 542: xref not found
|
||||
WARNING: bad3.pdf: file is damaged
|
||||
WARNING: bad3.pdf (file position 542): xref not found
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
/QTest is implicit
|
||||
/QTest is direct
|
||||
|
@ -1 +1 @@
|
||||
bad3.pdf: offset 542: xref not found
|
||||
bad3.pdf (file position 542): xref not found
|
||||
|
@ -3,4 +3,4 @@
|
||||
Raw stream data:
|
||||
xœ%<25>11û¼b;t<>à4| wXIDì Øå÷8G·«Í>rQ¨uŠOÒêEŒ:©IWìÃPlíµII)Ãr´p4~;§ÎAs/òÒ…jcúú¾÷Žs§åözû»ž<C2BB>T.?®uŽæ§<Ž¼…Ð*6ä
|
||||
Uncompressed stream data:
|
||||
bad30.pdf: offset 629: invalid filter object type for this stream
|
||||
bad30.pdf (file position 629): stream filter type is not name or array
|
||||
|
@ -3,4 +3,4 @@
|
||||
Raw stream data:
|
||||
xœ%<25>11û¼b;t<>à4| wXIDì Øå÷8G·«Í>rQ¨uŠOÒêEŒ:©IWìÃPlíµII)Ãr´p4~;§ÎAs/òÒ…jcúú¾÷Žs§åözû»ž<C2BB>T.?®uŽæ§<Ž¼…Ð*6ä
|
||||
Uncompressed stream data:
|
||||
bad30.pdf: offset 629: invalid filter object type for this stream
|
||||
bad30.pdf (file position 629): stream filter type is not name or array
|
||||
|
@ -1,6 +1,7 @@
|
||||
WARNING: bad32.pdf: offset 0: file is damaged
|
||||
WARNING: bad32.pdf: offset 307: expected 4 0 obj
|
||||
WARNING: bad32.pdf: file is damaged
|
||||
WARNING: bad32.pdf (object 4 0, file position 307): expected 4 0 obj
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
WARNING: bad32.pdf: object 4 0 not found in file after regenerating cross reference table
|
||||
/QTest is implicit
|
||||
/QTest is indirect
|
||||
/QTest is null
|
||||
|
@ -1 +1 @@
|
||||
bad32.pdf: offset 307: expected 4 0 obj
|
||||
bad32.pdf (object 4 0, file position 307): expected 4 0 obj
|
||||
|
@ -1,9 +1,9 @@
|
||||
WARNING: bad33.pdf: offset 0: file is damaged
|
||||
WARNING: bad33.pdf: offset 1771: xref not found
|
||||
WARNING: bad33.pdf: file is damaged
|
||||
WARNING: bad33.pdf (file position 1771): xref not found
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
/QTest is indirect
|
||||
/QTest is a stream. Dictionary: << /Filter (FlateDecode) /Length 123 >>
|
||||
Raw stream data:
|
||||
xœ%<25>11û¼b;t<>à4| wXIDì Øå÷8G·«Í>rQ¨uŠOÒêEŒ:©IWìÃPlíµII)Ãr´p4~;§ÎAs/òÒ…jcúú¾÷Žs§åözû»ž<C2BB>T.?®uŽæ§<Ž¼…Ð*6ä
|
||||
Uncompressed stream data:
|
||||
bad33.pdf: offset 629: invalid filter object type for this stream
|
||||
bad33.pdf (file position 629): stream filter type is not name or array
|
||||
|
@ -1 +1 @@
|
||||
bad33.pdf: offset 1771: xref not found
|
||||
bad33.pdf (file position 1771): xref not found
|
||||
|
23
qpdf/qtest/qpdf/bad34-recover.out
Normal file
23
qpdf/qtest/qpdf/bad34-recover.out
Normal file
@ -0,0 +1,23 @@
|
||||
WARNING: bad34.pdf: file is damaged
|
||||
WARNING: bad34.pdf (object 4 0, file position 322): expected n n obj
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
/QTest is indirect
|
||||
/QTest is a stream. Dictionary: << /Length 44 /Quack 9 0 R >>
|
||||
Raw stream data:
|
||||
BT
|
||||
/F1 24 Tf
|
||||
72 720 Td
|
||||
(Potato) Tj
|
||||
ET
|
||||
|
||||
Uncompressed stream data:
|
||||
BT
|
||||
/F1 24 Tf
|
||||
72 720 Td
|
||||
(Potato) Tj
|
||||
ET
|
||||
|
||||
End of stream data
|
||||
unparse: 4 0 R
|
||||
unparseResolved: 4 0 R
|
||||
test 1 done
|
1
qpdf/qtest/qpdf/bad34.out
Normal file
1
qpdf/qtest/qpdf/bad34.out
Normal file
@ -0,0 +1 @@
|
||||
bad34.pdf (object 4 0, file position 322): expected n n obj
|
81
qpdf/qtest/qpdf/bad34.pdf
Normal file
81
qpdf/qtest/qpdf/bad34.pdf
Normal file
@ -0,0 +1,81 @@
|
||||
%PDF-1.3
|
||||
1 0 obj
|
||||
<<
|
||||
/Type /Catalog
|
||||
/Pages 2 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<<
|
||||
/Type /Pages
|
||||
/Kids [
|
||||
3 0 R
|
||||
]
|
||||
/Count 1
|
||||
>>
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<<
|
||||
/Length 44
|
||||
/Quack 9 0 R
|
||||
>>
|
||||
stream
|
||||
BT
|
||||
/F1 24 Tf
|
||||
72 720 Td
|
||||
(Potato) Tj
|
||||
ET
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
<<
|
||||
/Type /Page
|
||||
/Parent 2 0 R
|
||||
/MediaBox [0 0 612 792]
|
||||
/Contents 4 0 R
|
||||
/Resources <<
|
||||
/ProcSet 5 0 R
|
||||
/Font <<
|
||||
/F1 6 0 R
|
||||
>>
|
||||
>>
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
[
|
||||
/PDF
|
||||
/Text
|
||||
]
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<<
|
||||
/Type /Font
|
||||
/Subtype /Type1
|
||||
/Name /F1
|
||||
/BaseFont /Helvetica
|
||||
/Encoding /WinAnsiEncoding
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000009 00000 n
|
||||
0000000063 00000 n
|
||||
0000000135 00000 n
|
||||
0000000322 00000 n
|
||||
0000000418 00000 n
|
||||
0000000453 00000 n
|
||||
trailer <<
|
||||
/Size 7
|
||||
/Root 1 0 R
|
||||
/QTest 4 0 R
|
||||
>>
|
||||
startxref
|
||||
571
|
||||
%%EOF
|
1
qpdf/qtest/qpdf/bad35-recover.out
Normal file
1
qpdf/qtest/qpdf/bad35-recover.out
Normal file
@ -0,0 +1 @@
|
||||
bad35.pdf (object 1 0, file position 521): supposed object stream 1 has wrong type
|
1
qpdf/qtest/qpdf/bad35.out
Normal file
1
qpdf/qtest/qpdf/bad35.out
Normal file
@ -0,0 +1 @@
|
||||
bad35.pdf (object 1 0, file position 521): supposed object stream 1 has wrong type
|
BIN
qpdf/qtest/qpdf/bad35.pdf
Normal file
BIN
qpdf/qtest/qpdf/bad35.pdf
Normal file
Binary file not shown.
@ -1,5 +1,5 @@
|
||||
WARNING: bad4.pdf: offset 0: file is damaged
|
||||
WARNING: bad4.pdf: offset 547: xref syntax invalid
|
||||
WARNING: bad4.pdf: file is damaged
|
||||
WARNING: bad4.pdf (xref table, file position 547): xref syntax invalid
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
/QTest is implicit
|
||||
/QTest is direct
|
||||
|
@ -1 +1 @@
|
||||
bad4.pdf: offset 547: xref syntax invalid
|
||||
bad4.pdf (xref table, file position 547): xref syntax invalid
|
||||
|
@ -1,5 +1,5 @@
|
||||
WARNING: bad5.pdf: offset 0: file is damaged
|
||||
WARNING: bad5.pdf: offset 591: invalid xref entry (obj=2)
|
||||
WARNING: bad5.pdf: file is damaged
|
||||
WARNING: bad5.pdf (xref table, file position 591): invalid xref entry (obj=2)
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
/QTest is implicit
|
||||
/QTest is direct
|
||||
|
@ -1 +1 @@
|
||||
bad5.pdf: offset 591: invalid xref entry (obj=2)
|
||||
bad5.pdf (xref table, file position 591): invalid xref entry (obj=2)
|
||||
|
@ -1,4 +1,4 @@
|
||||
WARNING: bad7.pdf: offset 0: file is damaged
|
||||
WARNING: bad7.pdf: offset 698: expected trailer dictionary
|
||||
WARNING: bad7.pdf: file is damaged
|
||||
WARNING: bad7.pdf (file position 698): expected trailer dictionary
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
bad7.pdf: unable to find trailer dictionary while recovering damaged file
|
||||
|
@ -1 +1 @@
|
||||
bad7.pdf: offset 698: expected trailer dictionary
|
||||
bad7.pdf (file position 698): expected trailer dictionary
|
||||
|
@ -1,5 +1,5 @@
|
||||
WARNING: bad8.pdf: offset 0: file is damaged
|
||||
WARNING: bad8.pdf: offset 543: xref not found
|
||||
WARNING: bad8.pdf: file is damaged
|
||||
WARNING: bad8.pdf (file position 543): xref not found
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
/QTest is implicit
|
||||
/QTest is direct
|
||||
|
@ -1 +1 @@
|
||||
bad8.pdf: offset 543: xref not found
|
||||
bad8.pdf (file position 543): xref not found
|
||||
|
@ -1,5 +1,5 @@
|
||||
WARNING: bad9.pdf: offset 0: file is damaged
|
||||
WARNING: bad9.pdf: offset 712: trailer dictionary lacks /Size key
|
||||
WARNING: bad9.pdf: file is damaged
|
||||
WARNING: bad9.pdf (trailer, file position 712): trailer dictionary lacks /Size key
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
/QTest is implicit
|
||||
/QTest is direct
|
||||
|
@ -1 +1 @@
|
||||
bad9.pdf: offset 712: trailer dictionary lacks /Size key
|
||||
bad9.pdf (trailer, file position 712): trailer dictionary lacks /Size key
|
||||
|
@ -1 +1 @@
|
||||
error: bad33.pdf: offset 1771: xref not found
|
||||
error: bad33.pdf (file position 1771): xref not found
|
||||
|
@ -1 +1 @@
|
||||
error: bad1.pdf: offset 0: not a PDF file
|
||||
error: bad1.pdf: not a PDF file
|
||||
|
@ -1,4 +1,4 @@
|
||||
warning: bad17.pdf: offset 0: file is damaged
|
||||
warning: bad17.pdf: offset 753: dictionary ending here has an odd number of elements
|
||||
warning: bad17.pdf: file is damaged
|
||||
warning: bad17.pdf (trailer, file position 753): dictionary ending here has an odd number of elements
|
||||
warning: Attempting to reconstruct cross-reference table
|
||||
error: bad17.pdf: offset 753: dictionary ending here has an odd number of elements
|
||||
error: bad17.pdf (trailer, file position 753): dictionary ending here has an odd number of elements
|
||||
|
@ -1,3 +1,3 @@
|
||||
warning: append-page-content-damaged.pdf: offset 0: file is damaged
|
||||
warning: append-page-content-damaged.pdf: file is damaged
|
||||
warning: append-page-content-damaged.pdf: can't find startxref
|
||||
warning: Attempting to reconstruct cross-reference table
|
||||
|
@ -1 +1 @@
|
||||
error: bad30.pdf: offset 629: invalid filter object type for this stream
|
||||
error: bad30.pdf (file position 629): stream filter type is not name or array
|
||||
|
@ -1,4 +1,4 @@
|
||||
warning: bad33.pdf: offset 0: file is damaged
|
||||
warning: bad33.pdf: offset 1771: xref not found
|
||||
warning: bad33.pdf: file is damaged
|
||||
warning: bad33.pdf (file position 1771): xref not found
|
||||
warning: Attempting to reconstruct cross-reference table
|
||||
error: bad33.pdf: offset 629: invalid filter object type for this stream
|
||||
error: bad33.pdf (file position 629): stream filter type is not name or array
|
||||
|
@ -2,4 +2,4 @@ checking damaged-stream.pdf
|
||||
PDF Version: 1.3
|
||||
File is not encrypted
|
||||
File is not linearized
|
||||
WARNING: damaged-stream.pdf: offset 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
|
||||
|
@ -1,5 +1,5 @@
|
||||
WARNING: heifer.pdf: offset 0: file is damaged
|
||||
WARNING: heifer.pdf: offset 92741: xref not found
|
||||
WARNING: heifer.pdf: file is damaged
|
||||
WARNING: heifer.pdf (file position 92741): xref not found
|
||||
WARNING: Attempting to reconstruct cross-reference table
|
||||
WARNING: heifer.pdf: offset 51: attempting to recover stream length
|
||||
WARNING: heifer.pdf (object 2 0, file position 51): attempting to recover stream length
|
||||
qpdf: operation succeeded with warnings; resulting file may have some problems
|
||||
|
@ -1,2 +1,2 @@
|
||||
WARNING: xref-with-short-size.pdf: offset 16227: Cross-reference stream data has the wrong size; expected = 52; actual = 56
|
||||
WARNING: xref-with-short-size.pdf (xref stream, file position 16227): Cross-reference stream data has the wrong size; expected = 52; actual = 56
|
||||
qpdf: operation succeeded with warnings; resulting file may have some problems
|
||||
|
@ -1,4 +1,4 @@
|
||||
WARNING: xref-with-short-size.pdf: offset 16227: Cross-reference stream data has the wrong size; expected = 52; actual = 56
|
||||
WARNING: xref-with-short-size.pdf (xref stream, file position 16227): Cross-reference stream data has the wrong size; expected = 52; actual = 56
|
||||
1/0: compressed; stream = 5, index = 1
|
||||
2/0: compressed; stream = 5, index = 0
|
||||
3/0: uncompressed; offset = 15
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <qpdf/Pl_Buffer.hh>
|
||||
#include <qpdf/QPDFWriter.hh>
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <map>
|
||||
@ -319,6 +320,7 @@ void runtest(int n, char const* filename)
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
setlinebuf(stdout);
|
||||
if ((whoami = strrchr(argv[0], '/')) == NULL)
|
||||
{
|
||||
whoami = argv[0];
|
||||
|
Loading…
Reference in New Issue
Block a user