mirror of
https://github.com/qpdf/qpdf.git
synced 2024-05-31 01:10:51 +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>
|
2009-10-18 Jay Berkenbilt <ejb@ql.org>
|
||||||
|
|
||||||
* If forcing version, disable object stream creation and/or
|
* 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
|
* Add comments for the security functions that map them back to the
|
||||||
items in Adobe's products.
|
items in Adobe's products.
|
||||||
|
|
||||||
* Add error codes to QPDFException. Change the error interface so
|
* Change the C error interface so that warnings and errors are
|
||||||
that warnings and errors are pointers that can be queried using
|
pointers that can be queried using more C API functions. We need a
|
||||||
more C API functions. We need a way to get a full string as well
|
way to get a full string as well as an error code, file name,
|
||||||
as an error code, file name, offset, and message. We should go
|
offset, and message.
|
||||||
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.
|
|
||||||
|
|
||||||
* "Delphi wrapper unit 'qpdf.pas' created by Zarko Gajic
|
* "Delphi wrapper unit 'qpdf.pas' created by Zarko Gajic
|
||||||
(http://delphi.about.com). .. use at your own risk and for whatever
|
(http://delphi.about.com). .. use at your own risk and for whatever
|
||||||
|
|
|
@ -30,7 +30,7 @@ $td->runtest("no bookmarks",
|
||||||
$td->runtest("bad",
|
$td->runtest("bad",
|
||||||
{$td->COMMAND => "pdf-bookmarks 3.pdf"},
|
{$td->COMMAND => "pdf-bookmarks 3.pdf"},
|
||||||
{$td->STRING => "pdf-bookmarks processing file 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->EXIT_STATUS => 2},
|
||||||
$td->NORMALIZE_NEWLINES);
|
$td->NORMALIZE_NEWLINES);
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ $td->runtest("normal",
|
||||||
|
|
||||||
$td->runtest("error",
|
$td->runtest("error",
|
||||||
{$td->COMMAND => "pdf-npages bad"},
|
{$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->EXIT_STATUS => 2},
|
||||||
$td->NORMALIZE_NEWLINES);
|
$td->NORMALIZE_NEWLINES);
|
||||||
|
|
||||||
|
|
|
@ -371,9 +371,11 @@ class DLL_EXPORT QPDF
|
||||||
int processXRefStream(off_t offset, QPDFObjectHandle& xref_stream);
|
int processXRefStream(off_t offset, QPDFObjectHandle& xref_stream);
|
||||||
void insertXrefEntry(int obj, int f0, int f1, int f2,
|
void insertXrefEntry(int obj, int f0, int f1, int f2,
|
||||||
bool overwrite = false);
|
bool overwrite = false);
|
||||||
|
void setLastObjectDescription(std::string const& description,
|
||||||
|
int objid, int generation);
|
||||||
QPDFObjectHandle readObject(
|
QPDFObjectHandle readObject(
|
||||||
InputSource*, int objid, int generation,
|
InputSource*, std::string const& description,
|
||||||
bool in_object_stream);
|
int objid, int generation, bool in_object_stream);
|
||||||
QPDFObjectHandle readObjectInternal(
|
QPDFObjectHandle readObjectInternal(
|
||||||
InputSource* input, int objid, int generation,
|
InputSource* input, int objid, int generation,
|
||||||
bool in_object_stream,
|
bool in_object_stream,
|
||||||
|
@ -383,7 +385,8 @@ class DLL_EXPORT QPDF
|
||||||
QPDFTokenizer::Token readToken(InputSource*);
|
QPDFTokenizer::Token readToken(InputSource*);
|
||||||
|
|
||||||
QPDFObjectHandle readObjectAtOffset(
|
QPDFObjectHandle readObjectAtOffset(
|
||||||
off_t offset,
|
bool attempt_recovery,
|
||||||
|
off_t offset, std::string const& description,
|
||||||
int exp_objid, int exp_generation,
|
int exp_objid, int exp_generation,
|
||||||
int& act_objid, int& act_generation);
|
int& act_objid, int& act_generation);
|
||||||
PointerHolder<QPDFObject> resolve(int objid, int generation);
|
PointerHolder<QPDFObject> resolve(int objid, int generation);
|
||||||
|
@ -734,6 +737,7 @@ class DLL_EXPORT QPDF
|
||||||
|
|
||||||
QPDFTokenizer tokenizer;
|
QPDFTokenizer tokenizer;
|
||||||
FileInputSource file;
|
FileInputSource file;
|
||||||
|
std::string last_object_description;
|
||||||
bool encrypted;
|
bool encrypted;
|
||||||
bool encryption_initialized;
|
bool encryption_initialized;
|
||||||
bool ignore_xref_streams;
|
bool ignore_xref_streams;
|
||||||
|
|
|
@ -9,15 +9,47 @@
|
||||||
#define __QPDFEXC_HH__
|
#define __QPDFEXC_HH__
|
||||||
|
|
||||||
#include <qpdf/DLL.h>
|
#include <qpdf/DLL.h>
|
||||||
|
#include <qpdf/Constants.h>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
class DLL_EXPORT QPDFExc: public std::runtime_error
|
class DLL_EXPORT QPDFExc: public std::runtime_error
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QPDFExc(std::string const& message);
|
QPDFExc(qpdf_error_code_e error_code,
|
||||||
QPDFExc(std::string const& filename, int offset,
|
std::string const& filename,
|
||||||
|
std::string const& object,
|
||||||
|
off_t offset,
|
||||||
std::string const& message);
|
std::string const& message);
|
||||||
virtual ~QPDFExc() throw ();
|
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__
|
#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);
|
size_t len = fread(buffer, 1, length, this->file);
|
||||||
if ((len == 0) && ferror(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 ") +
|
std::string("read ") +
|
||||||
QUtil::int_to_string(length) + " bytes");
|
QUtil::int_to_string(length) + " bytes");
|
||||||
}
|
}
|
||||||
|
@ -325,7 +327,8 @@ QPDF::parse()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF not a pdf file");
|
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
|
// PDF spec says %%EOF must be found within the last 1024 bytes of
|
||||||
|
@ -369,7 +372,8 @@ QPDF::parse()
|
||||||
if (! m2)
|
if (! m2)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF can't find startxref");
|
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());
|
off_t xref_offset = atoi(m2.getMatch(1).c_str());
|
||||||
read_xref(xref_offset);
|
read_xref(xref_offset);
|
||||||
|
@ -417,9 +421,28 @@ QPDF::reconstruct_xref(QPDFExc& e)
|
||||||
static PCRE endobj_re("^endobj\\b");
|
static PCRE endobj_re("^endobj\\b");
|
||||||
static PCRE trailer_re("^trailer\\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(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);
|
this->file.seek(0, SEEK_END);
|
||||||
off_t eof = this->file.tell();
|
off_t eof = this->file.tell();
|
||||||
|
@ -452,7 +475,8 @@ QPDF::reconstruct_xref(QPDFExc& e)
|
||||||
// read "trailer"
|
// read "trailer"
|
||||||
this->file.seek(this->file.getLastOffset(), SEEK_SET);
|
this->file.seek(this->file.getLastOffset(), SEEK_SET);
|
||||||
readToken(&this->file);
|
readToken(&this->file);
|
||||||
QPDFObjectHandle t = readObject(&this->file, 0, 0, false);
|
QPDFObjectHandle t =
|
||||||
|
readObject(&this->file, "trailer", 0, 0, false);
|
||||||
if (! t.isDictionary())
|
if (! t.isDictionary())
|
||||||
{
|
{
|
||||||
// Oh well. It was worth a try.
|
// 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
|
// with bad startxref pointers even when they have object
|
||||||
// streams.
|
// 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");
|
"dictionary while recovering damaged file");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -513,8 +538,8 @@ QPDF::read_xref(off_t xref_offset)
|
||||||
if (size != max_obj + 1)
|
if (size != max_obj + 1)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF xref size mismatch");
|
QTC::TC("qpdf", "QPDF xref size mismatch");
|
||||||
warn(QPDFExc(this->file.getName() +
|
warn(QPDFExc(qpdf_e_damaged_pdf, this->file.getName(), "", 0,
|
||||||
std::string(": reported number of objects (") +
|
std::string("reported number of objects (") +
|
||||||
QUtil::int_to_string(size) +
|
QUtil::int_to_string(size) +
|
||||||
") inconsistent with actual number of objects (" +
|
") inconsistent with actual number of objects (" +
|
||||||
QUtil::int_to_string(max_obj + 1) + ")"));
|
QUtil::int_to_string(max_obj + 1) + ")"));
|
||||||
|
@ -542,7 +567,8 @@ QPDF::read_xrefTable(off_t xref_offset)
|
||||||
if (! m1)
|
if (! m1)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF invalid xref");
|
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");
|
"xref syntax invalid");
|
||||||
}
|
}
|
||||||
int obj = atoi(m1.getMatch(1).c_str());
|
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");
|
QTC::TC("qpdf", "QPDF invalid xref entry");
|
||||||
throw QPDFExc(
|
throw QPDFExc(
|
||||||
this->file.getName(), this->file.getLastOffset(),
|
qpdf_e_damaged_pdf, this->file.getName(),
|
||||||
|
"xref table", this->file.getLastOffset(),
|
||||||
"invalid xref entry (obj=" +
|
"invalid xref entry (obj=" +
|
||||||
QUtil::int_to_string(i) + ")");
|
QUtil::int_to_string(i) + ")");
|
||||||
}
|
}
|
||||||
|
@ -595,11 +622,13 @@ QPDF::read_xrefTable(off_t xref_offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set offset to previous xref table if any
|
// 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())
|
if (! cur_trailer.isDictionary())
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF missing trailer");
|
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");
|
"expected trailer dictionary");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -610,13 +639,15 @@ QPDF::read_xrefTable(off_t xref_offset)
|
||||||
if (! this->trailer.hasKey("/Size"))
|
if (! this->trailer.hasKey("/Size"))
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF trailer lacks 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");
|
"trailer dictionary lacks /Size key");
|
||||||
}
|
}
|
||||||
if (! this->trailer.getKey("/Size").isInteger())
|
if (! this->trailer.getKey("/Size").isInteger())
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF trailer size not integer");
|
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 "
|
"/Size key in trailer dictionary is not "
|
||||||
"an integer");
|
"an integer");
|
||||||
}
|
}
|
||||||
|
@ -640,7 +671,8 @@ QPDF::read_xrefTable(off_t xref_offset)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw QPDFExc(this->file.getName(), xref_offset,
|
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||||
|
"xref stream", xref_offset,
|
||||||
"invalid /XRefStm");
|
"invalid /XRefStm");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -659,7 +691,8 @@ QPDF::read_xrefTable(off_t xref_offset)
|
||||||
if (! cur_trailer.getKey("/Prev").isInteger())
|
if (! cur_trailer.getKey("/Prev").isInteger())
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF trailer prev not integer");
|
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 "
|
"/Prev key in trailer dictionary is not "
|
||||||
"an integer");
|
"an integer");
|
||||||
}
|
}
|
||||||
|
@ -685,7 +718,8 @@ QPDF::read_xrefStream(off_t xref_offset)
|
||||||
QPDFObjectHandle xref_obj;
|
QPDFObjectHandle xref_obj;
|
||||||
try
|
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)
|
catch (QPDFExc& e)
|
||||||
{
|
{
|
||||||
|
@ -705,7 +739,8 @@ QPDF::read_xrefStream(off_t xref_offset)
|
||||||
if (! found)
|
if (! found)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF can't find xref");
|
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;
|
return xref_offset;
|
||||||
|
@ -725,7 +760,8 @@ QPDF::processXRefStream(off_t xref_offset, QPDFObjectHandle& xref_obj)
|
||||||
dict.getKey("/Size").isInteger() &&
|
dict.getKey("/Size").isInteger() &&
|
||||||
(Index_obj.isArray() || Index_obj.isNull())))
|
(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"
|
"Cross-reference stream does not have"
|
||||||
" proper /W and /Index keys");
|
" proper /W and /Index keys");
|
||||||
}
|
}
|
||||||
|
@ -735,7 +771,8 @@ QPDF::processXRefStream(off_t xref_offset, QPDFObjectHandle& xref_obj)
|
||||||
int n_index = Index_obj.getArrayNItems();
|
int n_index = Index_obj.getArrayNItems();
|
||||||
if ((n_index % 2) || (n_index < 2))
|
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"
|
"Cross-reference stream's /Index has an"
|
||||||
" invalid number of values");
|
" invalid number of values");
|
||||||
}
|
}
|
||||||
|
@ -747,7 +784,8 @@ QPDF::processXRefStream(off_t xref_offset, QPDFObjectHandle& xref_obj)
|
||||||
}
|
}
|
||||||
else
|
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 " +
|
"Cross-reference stream's /Index's item " +
|
||||||
QUtil::int_to_string(i) +
|
QUtil::int_to_string(i) +
|
||||||
" is not an integer");
|
" is not an integer");
|
||||||
|
@ -785,7 +823,8 @@ QPDF::processXRefStream(off_t xref_offset, QPDFObjectHandle& xref_obj)
|
||||||
|
|
||||||
if (expected_size != actual_size)
|
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;"
|
"Cross-reference stream data has the wrong size;"
|
||||||
" expected = " + QUtil::int_to_string(expected_size) +
|
" expected = " + QUtil::int_to_string(expected_size) +
|
||||||
"; actual = " + QUtil::int_to_string(actual_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())
|
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 "
|
"/Prev key in xref stream dictionary is not "
|
||||||
"an integer");
|
"an integer");
|
||||||
}
|
}
|
||||||
|
@ -935,7 +975,8 @@ QPDF::insertXrefEntry(int obj, int f0, int f1, int f2, bool overwrite)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
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 " +
|
"unknown xref stream entry type " +
|
||||||
QUtil::int_to_string(f0));
|
QUtil::int_to_string(f0));
|
||||||
break;
|
break;
|
||||||
|
@ -972,10 +1013,32 @@ QPDF::showXRefTable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QPDFObjectHandle
|
void
|
||||||
QPDF::readObject(InputSource* input, int objid, int generation,
|
QPDF::setLastObjectDescription(std::string const& description,
|
||||||
bool in_object_stream)
|
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();
|
off_t offset = input->tell();
|
||||||
QPDFObjectHandle object = readObjectInternal(
|
QPDFObjectHandle object = readObjectInternal(
|
||||||
input, objid, generation, in_object_stream, false, false);
|
input, objid, generation, in_object_stream, false, false);
|
||||||
|
@ -1017,7 +1080,9 @@ QPDF::readObjectInternal(InputSource* input,
|
||||||
case QPDFTokenizer::tt_brace_close:
|
case QPDFTokenizer::tt_brace_close:
|
||||||
// Don't know what to do with these for now
|
// Don't know what to do with these for now
|
||||||
QTC::TC("qpdf", "QPDF bad brace");
|
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");
|
"unexpected brace token");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1029,7 +1094,9 @@ QPDF::readObjectInternal(InputSource* input,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF bad array close");
|
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");
|
"unexpected array close token");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1042,7 +1109,9 @@ QPDF::readObjectInternal(InputSource* input,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF bad dictionary close");
|
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");
|
"unexpected dictionary close token");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1097,7 +1166,9 @@ QPDF::readObjectInternal(InputSource* input,
|
||||||
}
|
}
|
||||||
else
|
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 (" +
|
"unknown token while reading object (" +
|
||||||
value + ")");
|
value + ")");
|
||||||
}
|
}
|
||||||
|
@ -1116,7 +1187,9 @@ QPDF::readObjectInternal(InputSource* input,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
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");
|
"unknown token type while reading object");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1153,7 +1226,8 @@ QPDF::readObjectInternal(InputSource* input,
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF dictionary odd number of elements");
|
QTC::TC("qpdf", "QPDF dictionary odd number of elements");
|
||||||
throw QPDFExc(
|
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");
|
"dictionary ending here has an odd number of elements");
|
||||||
}
|
}
|
||||||
for (unsigned int i = 0; i < olist.size(); i += 2)
|
for (unsigned int i = 0; i < olist.size(); i += 2)
|
||||||
|
@ -1163,7 +1237,8 @@ QPDF::readObjectInternal(InputSource* input,
|
||||||
if (! key_obj.isName())
|
if (! key_obj.isName())
|
||||||
{
|
{
|
||||||
throw QPDFExc(
|
throw QPDFExc(
|
||||||
input->getName(), offset,
|
qpdf_e_damaged_pdf,
|
||||||
|
input->getName(), this->last_object_description, offset,
|
||||||
std::string("dictionary key not name (") +
|
std::string("dictionary key not name (") +
|
||||||
key_obj.unparse() + ")");
|
key_obj.unparse() + ")");
|
||||||
}
|
}
|
||||||
|
@ -1209,7 +1284,8 @@ QPDF::readObjectInternal(InputSource* input,
|
||||||
if (dict.count("/Length") == 0)
|
if (dict.count("/Length") == 0)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF stream without length");
|
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");
|
"stream dictionary lacks /Length key");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1217,7 +1293,8 @@ QPDF::readObjectInternal(InputSource* input,
|
||||||
if (! length_obj.isInteger())
|
if (! length_obj.isInteger())
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF stream length not integer");
|
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 "
|
"/Length key in stream dictionary is not "
|
||||||
"an integer");
|
"an integer");
|
||||||
}
|
}
|
||||||
|
@ -1229,7 +1306,9 @@ QPDF::readObjectInternal(InputSource* input,
|
||||||
QPDFTokenizer::tt_word, "endstream")))
|
QPDFTokenizer::tt_word, "endstream")))
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF missing 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");
|
"expected endstream");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1267,7 +1346,8 @@ QPDF::recoverStreamLength(InputSource* input,
|
||||||
|
|
||||||
// Try to reconstruct stream length by looking for
|
// Try to reconstruct stream length by looking for
|
||||||
// endstream(\r\n?|\n)endobj
|
// 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"));
|
"attempting to recover stream length"));
|
||||||
|
|
||||||
input->seek(0, SEEK_END);
|
input->seek(0, SEEK_END);
|
||||||
|
@ -1336,7 +1416,8 @@ QPDF::recoverStreamLength(InputSource* input,
|
||||||
|
|
||||||
if (length == 0)
|
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");
|
"unable to recover stream data");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1356,7 +1437,9 @@ QPDF::readToken(InputSource* input)
|
||||||
char ch;
|
char ch;
|
||||||
if (input->read(&ch, 1) == 0)
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -1376,7 +1459,9 @@ QPDF::readToken(InputSource* input)
|
||||||
|
|
||||||
if (token.getType() == QPDFTokenizer::tt_bad)
|
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);
|
input->setLastOffset(offset);
|
||||||
|
@ -1385,9 +1470,12 @@ QPDF::readToken(InputSource* input)
|
||||||
}
|
}
|
||||||
|
|
||||||
QPDFObjectHandle
|
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)
|
int& objid, int& generation)
|
||||||
{
|
{
|
||||||
|
setLastObjectDescription(description, exp_objid, exp_generation);
|
||||||
this->file.seek(offset, SEEK_SET);
|
this->file.seek(offset, SEEK_SET);
|
||||||
|
|
||||||
QPDFTokenizer::Token tobjid = readToken(&this->file);
|
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))
|
if (! (objidok && genok && objok))
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF expected n n obj");
|
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());
|
objid = atoi(tobjid.getValue().c_str());
|
||||||
generation = atoi(tgen.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))))
|
(! ((objid == exp_objid) && (generation == exp_generation))))
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF err wrong objid/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 ") +
|
std::string("expected ") +
|
||||||
QUtil::int_to_string(exp_objid) + " " +
|
QUtil::int_to_string(exp_objid) + " " +
|
||||||
QUtil::int_to_string(exp_generation) + " obj");
|
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)
|
catch (QPDFExc& e)
|
||||||
{
|
{
|
||||||
if (exp_objid && this->attempt_recovery)
|
if (exp_objid && try_recovery && this->attempt_recovery)
|
||||||
{
|
{
|
||||||
// Try again after reconstructing xref table
|
// Try again after reconstructing xref table
|
||||||
reconstruct_xref(e);
|
reconstruct_xref(e);
|
||||||
|
@ -1433,13 +1524,27 @@ QPDF::readObjectAtOffset(off_t offset, int exp_objid, int exp_generation,
|
||||||
(this->xref_table[og].getType() == 1))
|
(this->xref_table[og].getType() == 1))
|
||||||
{
|
{
|
||||||
off_t new_offset = this->xref_table[og].getOffset();
|
off_t new_offset = this->xref_table[og].getOffset();
|
||||||
// Call readObjectAtOffset with 0 for exp_objid to
|
QPDFObjectHandle result = readObjectAtOffset(
|
||||||
// avoid an infinite loop.
|
false, new_offset, description,
|
||||||
QPDFObjectHandle result =
|
exp_objid, exp_generation, objid, generation);
|
||||||
readObjectAtOffset(new_offset, 0, 0, objid, generation);
|
|
||||||
QTC::TC("qpdf", "QPDF recovered in readObjectAtOffset");
|
QTC::TC("qpdf", "QPDF recovered in readObjectAtOffset");
|
||||||
return result;
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -1448,13 +1553,14 @@ QPDF::readObjectAtOffset(off_t offset, int exp_objid, int exp_generation,
|
||||||
}
|
}
|
||||||
|
|
||||||
QPDFObjectHandle oh = readObject(
|
QPDFObjectHandle oh = readObject(
|
||||||
&this->file, objid, generation, false);
|
&this->file, description, objid, generation, false);
|
||||||
|
|
||||||
if (! (readToken(&this->file) ==
|
if (! (readToken(&this->file) ==
|
||||||
QPDFTokenizer::Token(QPDFTokenizer::tt_word, "endobj")))
|
QPDFTokenizer::Token(QPDFTokenizer::tt_word, "endobj")))
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF err expected 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"));
|
"expected endobj"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1487,7 +1593,8 @@ QPDF::readObjectAtOffset(off_t offset, int exp_objid, int exp_generation,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw QPDFExc(this->file.getName(), offset,
|
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||||
|
this->last_object_description, offset,
|
||||||
"EOF after endobj");
|
"EOF after endobj");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1526,7 +1633,7 @@ QPDF::resolve(int objid, int generation)
|
||||||
int aobjid;
|
int aobjid;
|
||||||
int ageneration;
|
int ageneration;
|
||||||
QPDFObjectHandle oh =
|
QPDFObjectHandle oh =
|
||||||
readObjectAtOffset(offset, objid, generation,
|
readObjectAtOffset(true, offset, "", objid, generation,
|
||||||
aobjid, ageneration);
|
aobjid, ageneration);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1536,7 +1643,7 @@ QPDF::resolve(int objid, int generation)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw QPDFExc(this->file.getName(), 0,
|
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(), "", 0,
|
||||||
"object " +
|
"object " +
|
||||||
QUtil::int_to_string(objid) + "/" +
|
QUtil::int_to_string(objid) + "/" +
|
||||||
QUtil::int_to_string(generation) +
|
QUtil::int_to_string(generation) +
|
||||||
|
@ -1554,7 +1661,9 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
|
||||||
QPDFObjectHandle obj_stream = getObjectByID(obj_stream_number, 0);
|
QPDFObjectHandle obj_stream = getObjectByID(obj_stream_number, 0);
|
||||||
if (! obj_stream.isStream())
|
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 " +
|
"supposed object stream " +
|
||||||
QUtil::int_to_string(obj_stream_number) +
|
QUtil::int_to_string(obj_stream_number) +
|
||||||
" is not a stream");
|
" is not a stream");
|
||||||
|
@ -1570,7 +1679,10 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
|
||||||
if (! (dict.getKey("/Type").isName() &&
|
if (! (dict.getKey("/Type").isName() &&
|
||||||
dict.getKey("/Type").getName() == "/ObjStm"))
|
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 " +
|
"supposed object stream " +
|
||||||
QUtil::int_to_string(obj_stream_number) +
|
QUtil::int_to_string(obj_stream_number) +
|
||||||
" has wrong type");
|
" has wrong type");
|
||||||
|
@ -1579,7 +1691,9 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
|
||||||
if (! (dict.getKey("/N").isInteger() &&
|
if (! (dict.getKey("/N").isInteger() &&
|
||||||
dict.getKey("/First").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 " +
|
"object stream " +
|
||||||
QUtil::int_to_string(obj_stream_number) +
|
QUtil::int_to_string(obj_stream_number) +
|
||||||
" has incorrect keys");
|
" has incorrect keys");
|
||||||
|
@ -1602,7 +1716,8 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
|
||||||
if (! ((tnum.getType() == QPDFTokenizer::tt_integer) &&
|
if (! ((tnum.getType() == QPDFTokenizer::tt_integer) &&
|
||||||
(toffset.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");
|
"expected integer in object stream header");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1617,7 +1732,7 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
|
||||||
int obj = (*iter).first;
|
int obj = (*iter).first;
|
||||||
int offset = (*iter).second;
|
int offset = (*iter).second;
|
||||||
input.seek(offset, SEEK_SET);
|
input.seek(offset, SEEK_SET);
|
||||||
QPDFObjectHandle oh = readObject(&input, obj, 0, true);
|
QPDFObjectHandle oh = readObject(&input, "", obj, 0, true);
|
||||||
|
|
||||||
// Store in cache
|
// Store in cache
|
||||||
ObjGen og(obj, 0);
|
ObjGen og(obj, 0);
|
||||||
|
@ -1830,17 +1945,25 @@ QPDF::pipeStreamData(int objid, int generation,
|
||||||
size_t len = this->file.read(buf, to_read);
|
size_t len = this->file.read(buf, to_read);
|
||||||
if (len == 0)
|
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");
|
"unexpected EOF reading stream data");
|
||||||
}
|
}
|
||||||
length -= len;
|
length -= len;
|
||||||
pipeline->write((unsigned char*)buf, len);
|
pipeline->write((unsigned char*)buf, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (QPDFExc& e)
|
||||||
|
{
|
||||||
|
warn(e);
|
||||||
|
}
|
||||||
catch (std::runtime_error& e)
|
catch (std::runtime_error& e)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF decoding error warning");
|
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 " +
|
"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()));
|
||||||
|
@ -1896,6 +2019,9 @@ QPDF::getAllPagesInternal(QPDFObjectHandle cur_pages,
|
||||||
}
|
}
|
||||||
else
|
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/QPDFExc.hh>
|
||||||
#include <qpdf/QUtil.hh>
|
#include <qpdf/QUtil.hh>
|
||||||
|
|
||||||
QPDFExc::QPDFExc(std::string const& message) :
|
QPDFExc::QPDFExc(qpdf_error_code_e error_code,
|
||||||
std::runtime_error(message)
|
std::string const& filename,
|
||||||
{
|
std::string const& object,
|
||||||
}
|
off_t offset,
|
||||||
|
|
||||||
QPDFExc::QPDFExc(std::string const& filename, int offset,
|
|
||||||
std::string const& message) :
|
std::string const& message) :
|
||||||
std::runtime_error(filename + ": offset " + QUtil::int_to_string(offset) +
|
std::runtime_error(createWhat(filename, object, offset, message)),
|
||||||
": " + message)
|
error_code(error_code),
|
||||||
|
filename(filename),
|
||||||
|
object(object),
|
||||||
|
offset(offset),
|
||||||
|
message(message)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
QPDFExc::~QPDFExc() throw ()
|
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))
|
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)
|
if (this->type != 1)
|
||||||
{
|
{
|
||||||
throw QPDFExc(
|
throw std::logic_error(
|
||||||
"getOffset called for xref entry of type != 1");
|
"getOffset called for xref entry of type != 1");
|
||||||
}
|
}
|
||||||
return this->field1;
|
return this->field1;
|
||||||
|
@ -42,7 +43,7 @@ QPDFXRefEntry::getObjStreamNumber() const
|
||||||
{
|
{
|
||||||
if (this->type != 2)
|
if (this->type != 2)
|
||||||
{
|
{
|
||||||
throw QPDFExc(
|
throw std::logic_error(
|
||||||
"getObjStreamNumber called for xref entry of type != 2");
|
"getObjStreamNumber called for xref entry of type != 2");
|
||||||
}
|
}
|
||||||
return this->field1;
|
return this->field1;
|
||||||
|
@ -53,7 +54,7 @@ QPDFXRefEntry::getObjStreamIndex() const
|
||||||
{
|
{
|
||||||
if (this->type != 2)
|
if (this->type != 2)
|
||||||
{
|
{
|
||||||
throw QPDFExc(
|
throw std::logic_error(
|
||||||
"getObjStreamIndex called for xref entry of type != 2");
|
"getObjStreamIndex called for xref entry of type != 2");
|
||||||
}
|
}
|
||||||
return this->field2;
|
return this->field2;
|
||||||
|
|
|
@ -59,7 +59,7 @@ QPDF_Stream::getStreamData()
|
||||||
Pl_Buffer buf("stream data buffer");
|
Pl_Buffer buf("stream data buffer");
|
||||||
if (! pipeStreamData(&buf, true, false, false))
|
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();
|
return buf.getBuffer();
|
||||||
}
|
}
|
||||||
|
@ -208,8 +208,9 @@ QPDF_Stream::filterable(std::vector<std::string>& filters,
|
||||||
if (! filters_okay)
|
if (! filters_okay)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF_Stream invalid filter");
|
QTC::TC("qpdf", "QPDF_Stream invalid filter");
|
||||||
throw QPDFExc(qpdf->getFilename(), this->offset,
|
throw QPDFExc(qpdf_e_damaged_pdf, qpdf->getFilename(),
|
||||||
"invalid filter object type for this stream");
|
"", this->offset,
|
||||||
|
"stream filter type is not name or array");
|
||||||
}
|
}
|
||||||
|
|
||||||
// `filters' now contains a list of filters to be applied in
|
// `filters' now contains a list of filters to be applied in
|
||||||
|
|
|
@ -337,14 +337,16 @@ QPDF::initializeEncryption()
|
||||||
(id_obj.getArrayNItems() == 2) &&
|
(id_obj.getArrayNItems() == 2) &&
|
||||||
id_obj.getArrayItem(0).isString()))
|
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");
|
"invalid /ID in trailer dictionary");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string id1 = id_obj.getArrayItem(0).getStringValue();
|
std::string id1 = id_obj.getArrayItem(0).getStringValue();
|
||||||
if (id1.length() != id_bytes)
|
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 "
|
"first /ID string in trailer dictionary has "
|
||||||
"incorrect length");
|
"incorrect length");
|
||||||
}
|
}
|
||||||
|
@ -352,19 +354,23 @@ QPDF::initializeEncryption()
|
||||||
QPDFObjectHandle encryption_dict = this->trailer.getKey("/Encrypt");
|
QPDFObjectHandle encryption_dict = this->trailer.getKey("/Encrypt");
|
||||||
if (! encryption_dict.isDictionary())
|
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");
|
"/Encrypt in trailer dictionary is not a dictionary");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! (encryption_dict.getKey("/Filter").isName() &&
|
if (! (encryption_dict.getKey("/Filter").isName() &&
|
||||||
(encryption_dict.getKey("/Filter").getName() == "/Standard")))
|
(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");
|
"unsupported encryption filter");
|
||||||
}
|
}
|
||||||
if (! encryption_dict.getKey("/SubFilter").isNull())
|
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,"
|
"file uses encryption SubFilters,"
|
||||||
" which qpdf does not support"));
|
" which qpdf does not support"));
|
||||||
}
|
}
|
||||||
|
@ -375,7 +381,8 @@ QPDF::initializeEncryption()
|
||||||
encryption_dict.getKey("/U").isString() &&
|
encryption_dict.getKey("/U").isString() &&
|
||||||
encryption_dict.getKey("/P").isInteger()))
|
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 "
|
"some encryption dictionary parameters are missing "
|
||||||
"or the wrong type");
|
"or the wrong type");
|
||||||
}
|
}
|
||||||
|
@ -389,7 +396,8 @@ QPDF::initializeEncryption()
|
||||||
if (! (((R == 2) || (R == 3) || (R == 4)) &&
|
if (! (((R == 2) || (R == 3) || (R == 4)) &&
|
||||||
((V == 1) || (V == 2) || (V == 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");
|
"Unsupported /R or /V in encryption dictionary");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,7 +405,8 @@ QPDF::initializeEncryption()
|
||||||
|
|
||||||
if (! ((O.length() == key_bytes) && (U.length() == key_bytes)))
|
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 "
|
"incorrect length for /O and/or /P in "
|
||||||
"encryption dictionary");
|
"encryption dictionary");
|
||||||
}
|
}
|
||||||
|
@ -408,7 +417,8 @@ QPDF::initializeEncryption()
|
||||||
Length = encryption_dict.getKey("/Length").getIntValue();
|
Length = encryption_dict.getKey("/Length").getIntValue();
|
||||||
if ((Length % 8) || (Length < 40) || (Length > 128))
|
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");
|
"invalid /Length value in encryption dictionary");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -471,7 +481,8 @@ QPDF::initializeEncryption()
|
||||||
}
|
}
|
||||||
if (this->cf_file != this->cf_stream)
|
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"
|
"This document has embedded files that are"
|
||||||
" encrypted differently from the rest of the file."
|
" encrypted differently from the rest of the file."
|
||||||
" qpdf does not presently support this due to"
|
" qpdf does not presently support this due to"
|
||||||
|
@ -492,7 +503,8 @@ QPDF::initializeEncryption()
|
||||||
}
|
}
|
||||||
else
|
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);
|
this->encryption_key = compute_encryption_key(this->user_password, data);
|
||||||
|
@ -542,7 +554,9 @@ QPDF::decryptString(std::string& str, int objid, int generation)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
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"
|
"unknown encryption filter for strings"
|
||||||
" (check /StrF in /Encrypt dictionary);"
|
" (check /StrF in /Encrypt dictionary);"
|
||||||
" strings may be decrypted improperly"));
|
" 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);
|
std::string key = getKeyForObject(objid, generation, use_aes);
|
||||||
if (use_aes)
|
try
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "QPDF_encryption aes decode string");
|
if (use_aes)
|
||||||
assert(key.length() == Pl_AES_PDF::key_size);
|
{
|
||||||
Pl_Buffer bufpl("decrypted string");
|
QTC::TC("qpdf", "QPDF_encryption aes decode string");
|
||||||
Pl_AES_PDF pl("aes decrypt string", &bufpl, false,
|
assert(key.length() == Pl_AES_PDF::key_size);
|
||||||
(unsigned char const*)key.c_str());
|
Pl_Buffer bufpl("decrypted string");
|
||||||
pl.write((unsigned char*)str.c_str(), str.length());
|
Pl_AES_PDF pl("aes decrypt string", &bufpl, false,
|
||||||
pl.finish();
|
(unsigned char const*)key.c_str());
|
||||||
Buffer* buf = bufpl.getBuffer();
|
pl.write((unsigned char*)str.c_str(), str.length());
|
||||||
str = std::string((char*)buf->getBuffer(), (size_t)buf->getSize());
|
pl.finish();
|
||||||
delete buf;
|
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");
|
throw;
|
||||||
unsigned int vlen = str.length();
|
}
|
||||||
char* tmp = QUtil::copy_string(str);
|
catch (std::runtime_error& e)
|
||||||
RC4 rc4((unsigned char const*)key.c_str(), key.length());
|
{
|
||||||
rc4.process((unsigned char*)tmp, vlen);
|
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||||
str = std::string(tmp, vlen);
|
this->last_object_description, this->file.getLastOffset(),
|
||||||
delete [] tmp;
|
"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:
|
default:
|
||||||
// filter local to this stream.
|
// 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"
|
"unknown encryption filter for streams"
|
||||||
" (check " + method_source + ");"
|
" (check " + method_source + ");"
|
||||||
" streams may be decrypted improperly"));
|
" streams may be decrypted improperly"));
|
||||||
|
|
|
@ -175,7 +175,8 @@ QPDF::readLinearizationData()
|
||||||
|
|
||||||
if (! isLinearized())
|
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()
|
// /L is read and stored in linp by isLinearized()
|
||||||
|
@ -193,7 +194,10 @@ QPDF::readLinearizationData()
|
||||||
T.isInteger() &&
|
T.isInteger() &&
|
||||||
(P.isInteger() || P.isNull())))
|
(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");
|
"the wrong type");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,7 +205,10 @@ QPDF::readLinearizationData()
|
||||||
unsigned int n_H_items = H.getArrayNItems();
|
unsigned int n_H_items = H.getArrayNItems();
|
||||||
if (! ((n_H_items == 2) || (n_H_items == 4)))
|
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;
|
std::vector<int> H_items;
|
||||||
|
@ -214,7 +221,10 @@ QPDF::readLinearizationData()
|
||||||
}
|
}
|
||||||
else
|
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 obj;
|
||||||
int gen;
|
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)];
|
ObjCache& oc = this->obj_cache[ObjGen(obj, gen)];
|
||||||
off_t min_end_offset = oc.end_before_space;
|
off_t min_end_offset = oc.end_before_space;
|
||||||
off_t max_end_offset = oc.end_after_space;
|
off_t max_end_offset = oc.end_after_space;
|
||||||
if (! H.isStream())
|
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();
|
QPDFObjectHandle Hdict = H.getDict();
|
||||||
|
@ -340,7 +354,10 @@ QPDF::readHintStream(Pipeline& pl, off_t offset, size_t length)
|
||||||
std::cout << "expected = " << computed_end
|
std::cout << "expected = " << computed_end
|
||||||
<< "; actual = " << min_end_offset << ".."
|
<< "; actual = " << min_end_offset << ".."
|
||||||
<< max_end_offset << std::endl;
|
<< 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);
|
H.pipeStreamData(&pl, true, false, false);
|
||||||
return Hdict;
|
return Hdict;
|
||||||
|
@ -651,8 +668,7 @@ QPDF::getLinearizationOffset(ObjGen const& og)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw QPDFExc(
|
throw std::logic_error(
|
||||||
this->file.getName(), 0,
|
|
||||||
"getLinearizationOffset called for xref entry not of type 1 or 2");
|
"getLinearizationOffset called for xref entry not of type 1 or 2");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -233,9 +233,12 @@ QPDF::optimizePagesTree(
|
||||||
{
|
{
|
||||||
if (! allow_changes)
|
if (! allow_changes)
|
||||||
{
|
{
|
||||||
throw QPDFExc(this->file.getName() +
|
throw QPDFExc(qpdf_e_internal, this->file.getName(),
|
||||||
": optimize detected an "
|
this->last_object_description,
|
||||||
"inheritable resource");
|
this->file.getLastOffset(),
|
||||||
|
"optimize detected an "
|
||||||
|
"inheritable resource when called "
|
||||||
|
"in no-change mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is an inheritable resource
|
// This is an inheritable resource
|
||||||
|
@ -338,7 +341,10 @@ QPDF::optimizePagesTree(
|
||||||
}
|
}
|
||||||
else
|
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 <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <qpdf/QUtil.hh>
|
#include <qpdf/QUtil.hh>
|
||||||
#include <qpdf/QTC.hh>
|
#include <qpdf/QTC.hh>
|
||||||
|
@ -533,6 +534,7 @@ parse_encrypt_options(
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
whoami = QUtil::getWhoami(argv[0]);
|
whoami = QUtil::getWhoami(argv[0]);
|
||||||
|
setlinebuf(stdout);
|
||||||
|
|
||||||
// For libtool's sake....
|
// For libtool's sake....
|
||||||
if (strncmp(whoami, "lt-", 3) == 0)
|
if (strncmp(whoami, "lt-", 3) == 0)
|
||||||
|
@ -892,7 +894,15 @@ int main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
if (show_linearization)
|
if (show_linearization)
|
||||||
{
|
{
|
||||||
pdf.showLinearizationData();
|
if (pdf.isLinearized())
|
||||||
|
{
|
||||||
|
pdf.showLinearizationData();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << infilename << " is not linearized"
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (show_xref)
|
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_r4_encryption_parameters 0
|
||||||
qpdf-c called qpdf_set_static_aes_IV 0
|
qpdf-c called qpdf_set_static_aes_IV 0
|
||||||
QPDF_encryption stream crypt filter 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
|
"unknown stream /Filter", # 31
|
||||||
"obj/gen mismatch", # 32
|
"obj/gen mismatch", # 32
|
||||||
"invalid stream /Filter and xref", # 33
|
"invalid stream /Filter and xref", # 33
|
||||||
|
"obj/gen in wrong place", # 34
|
||||||
|
"object stream of wrong type", # 35
|
||||||
);
|
);
|
||||||
|
|
||||||
$n_tests += @badfiles + 5;
|
$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
|
# though in some cases it may. Acrobat Reader would not be able to
|
||||||
# recover any of these files any better.
|
# recover any of these files any better.
|
||||||
my %recover_failures = ();
|
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;
|
$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: append-page-content-damaged.pdf: can't find startxref
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
WARNING: Attempting to reconstruct cross-reference table
|
||||||
version: 1.3
|
version: 1.3
|
||||||
linearized: 0
|
linearized: 0
|
||||||
encrypted: 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: append-page-content-damaged.pdf: can't find startxref
|
||||||
warning: Attempting to reconstruct cross-reference table
|
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: append-page-content-damaged.pdf: can't find startxref
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
WARNING: Attempting to reconstruct cross-reference table
|
||||||
checking append-page-content-damaged.pdf
|
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: append-page-content-damaged.pdf: can't find startxref
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
WARNING: Attempting to reconstruct cross-reference table
|
||||||
qpdf: operation succeeded with warnings; resulting file may have some problems
|
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: file is damaged
|
||||||
WARNING: bad10.pdf: offset 712: /Size key in trailer dictionary is not an integer
|
WARNING: bad10.pdf (trailer, file position 712): /Size key in trailer dictionary is not an integer
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
WARNING: Attempting to reconstruct cross-reference table
|
||||||
/QTest is implicit
|
/QTest is implicit
|
||||||
/QTest is direct
|
/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: file is damaged
|
||||||
WARNING: bad11.pdf: offset 905: /Prev key in trailer dictionary is not an integer
|
WARNING: bad11.pdf (trailer, file position 905): /Prev key in trailer dictionary is not an integer
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
WARNING: Attempting to reconstruct cross-reference table
|
||||||
/QTest is implicit
|
/QTest is implicit
|
||||||
/QTest is direct
|
/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: file is damaged
|
||||||
WARNING: bad13.pdf: offset 753: unexpected brace token
|
WARNING: bad13.pdf (trailer, file position 753): unexpected brace token
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
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: file is damaged
|
||||||
WARNING: bad14.pdf: offset 753: unexpected brace token
|
WARNING: bad14.pdf (trailer, file position 753): unexpected brace token
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
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: file is damaged
|
||||||
WARNING: bad15.pdf: offset 753: unexpected array close token
|
WARNING: bad15.pdf (trailer, file position 753): unexpected array close token
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
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: file is damaged
|
||||||
WARNING: bad16.pdf: offset 753: unexpected dictionary close token
|
WARNING: bad16.pdf (trailer, file position 753): unexpected dictionary close token
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
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: file is damaged
|
||||||
WARNING: bad17.pdf: offset 753: dictionary ending here has an odd number of elements
|
WARNING: bad17.pdf (trailer, file position 753): dictionary ending here has an odd number of elements
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
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: file is damaged
|
||||||
WARNING: bad18.pdf: offset 753: unexpected )
|
WARNING: bad18.pdf (trailer, file position 753): unexpected )
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
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: file is damaged
|
||||||
WARNING: bad19.pdf: offset 753: unexpected >
|
WARNING: bad19.pdf (trailer, file position 753): unexpected >
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
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: bad2.pdf: can't find startxref
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
WARNING: Attempting to reconstruct cross-reference table
|
||||||
/QTest is implicit
|
/QTest is implicit
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
WARNING: bad20.pdf: offset 0: file is damaged
|
WARNING: bad20.pdf: file is damaged
|
||||||
WARNING: bad20.pdf: offset 753: invalid character (q) in hexstring
|
WARNING: bad20.pdf (trailer, file position 753): invalid character (q) in hexstring
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
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: file is damaged
|
||||||
WARNING: bad21.pdf: offset 742: invalid name token
|
WARNING: bad21.pdf (trailer, file position 742): invalid name token
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
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 indirect
|
||||||
/QTest is a stream. Dictionary: << /Qength 44 >>
|
/QTest is a stream. Dictionary: << /Qength 44 >>
|
||||||
Raw stream data:
|
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 indirect
|
||||||
/QTest is a stream. Dictionary: << /Length () >>
|
/QTest is a stream. Dictionary: << /Length () >>
|
||||||
Raw stream data:
|
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
|
WARNING: bad24.pdf (object 4 0, file position 341): attempting to recover stream length
|
||||||
bad24.pdf: offset 341: unable to recover stream data
|
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: file is damaged
|
||||||
WARNING: bad25.pdf: offset 307: expected n n obj
|
WARNING: bad25.pdf (object 4 0, file position 307): expected n n obj
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
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: file is damaged
|
||||||
WARNING: bad26.pdf: offset 307: expected n n obj
|
WARNING: bad26.pdf (object 4 0, file position 307): expected n n obj
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
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: file is damaged
|
||||||
WARNING: bad27.pdf: offset 307: expected n n obj
|
WARNING: bad27.pdf (object 4 0, file position 307): expected n n obj
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
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 indirect
|
||||||
/QTest is a stream. Dictionary: << /Length 44 >>
|
/QTest is a stream. Dictionary: << /Length 44 >>
|
||||||
Raw stream data:
|
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 indirect
|
||||||
/QTest is a stream. Dictionary: << /Length 44 >>
|
/QTest is a stream. Dictionary: << /Length 44 >>
|
||||||
Raw stream data:
|
Raw stream data:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
WARNING: bad29.pdf: offset 0: file is damaged
|
WARNING: bad29.pdf: file is damaged
|
||||||
WARNING: bad29.pdf: offset 742: null character not allowed in name token
|
WARNING: bad29.pdf (trailer, file position 742): null character not allowed in name token
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
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: file is damaged
|
||||||
WARNING: bad3.pdf: offset 542: xref not found
|
WARNING: bad3.pdf (file position 542): xref not found
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
WARNING: Attempting to reconstruct cross-reference table
|
||||||
/QTest is implicit
|
/QTest is implicit
|
||||||
/QTest is direct
|
/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:
|
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ä
|
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:
|
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:
|
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ä
|
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:
|
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: file is damaged
|
||||||
WARNING: bad32.pdf: offset 307: expected 4 0 obj
|
WARNING: bad32.pdf (object 4 0, file position 307): expected 4 0 obj
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
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 implicit
|
||||||
/QTest is indirect
|
/QTest is indirect
|
||||||
/QTest is null
|
/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: file is damaged
|
||||||
WARNING: bad33.pdf: offset 1771: xref not found
|
WARNING: bad33.pdf (file position 1771): xref not found
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
WARNING: Attempting to reconstruct cross-reference table
|
||||||
/QTest is indirect
|
/QTest is indirect
|
||||||
/QTest is a stream. Dictionary: << /Filter (FlateDecode) /Length 123 >>
|
/QTest is a stream. Dictionary: << /Filter (FlateDecode) /Length 123 >>
|
||||||
Raw stream data:
|
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ä
|
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:
|
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: file is damaged
|
||||||
WARNING: bad4.pdf: offset 547: xref syntax invalid
|
WARNING: bad4.pdf (xref table, file position 547): xref syntax invalid
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
WARNING: Attempting to reconstruct cross-reference table
|
||||||
/QTest is implicit
|
/QTest is implicit
|
||||||
/QTest is direct
|
/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: file is damaged
|
||||||
WARNING: bad5.pdf: offset 591: invalid xref entry (obj=2)
|
WARNING: bad5.pdf (xref table, file position 591): invalid xref entry (obj=2)
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
WARNING: Attempting to reconstruct cross-reference table
|
||||||
/QTest is implicit
|
/QTest is implicit
|
||||||
/QTest is direct
|
/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: file is damaged
|
||||||
WARNING: bad7.pdf: offset 698: expected trailer dictionary
|
WARNING: bad7.pdf (file position 698): expected trailer dictionary
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
WARNING: Attempting to reconstruct cross-reference table
|
||||||
bad7.pdf: unable to find trailer dictionary while recovering damaged file
|
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: file is damaged
|
||||||
WARNING: bad8.pdf: offset 543: xref not found
|
WARNING: bad8.pdf (file position 543): xref not found
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
WARNING: Attempting to reconstruct cross-reference table
|
||||||
/QTest is implicit
|
/QTest is implicit
|
||||||
/QTest is direct
|
/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: file is damaged
|
||||||
WARNING: bad9.pdf: offset 712: trailer dictionary lacks /Size key
|
WARNING: bad9.pdf (trailer, file position 712): trailer dictionary lacks /Size key
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
WARNING: Attempting to reconstruct cross-reference table
|
||||||
/QTest is implicit
|
/QTest is implicit
|
||||||
/QTest is direct
|
/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: file is damaged
|
||||||
warning: bad17.pdf: offset 753: dictionary ending here has an odd number of elements
|
warning: bad17.pdf (trailer, file position 753): dictionary ending here has an odd number of elements
|
||||||
warning: Attempting to reconstruct cross-reference table
|
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: append-page-content-damaged.pdf: can't find startxref
|
||||||
warning: Attempting to reconstruct cross-reference table
|
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: file is damaged
|
||||||
warning: bad33.pdf: offset 1771: xref not found
|
warning: bad33.pdf (file position 1771): xref not found
|
||||||
warning: Attempting to reconstruct cross-reference table
|
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
|
PDF Version: 1.3
|
||||||
File is not encrypted
|
File is not encrypted
|
||||||
File is not linearized
|
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: file is damaged
|
||||||
WARNING: heifer.pdf: offset 92741: xref not found
|
WARNING: heifer.pdf (file position 92741): xref not found
|
||||||
WARNING: Attempting to reconstruct cross-reference table
|
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
|
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
|
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
|
1/0: compressed; stream = 5, index = 1
|
||||||
2/0: compressed; stream = 5, index = 0
|
2/0: compressed; stream = 5, index = 0
|
||||||
3/0: uncompressed; offset = 15
|
3/0: uncompressed; offset = 15
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <qpdf/Pl_Buffer.hh>
|
#include <qpdf/Pl_Buffer.hh>
|
||||||
#include <qpdf/QPDFWriter.hh>
|
#include <qpdf/QPDFWriter.hh>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
@ -319,6 +320,7 @@ void runtest(int n, char const* filename)
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
setlinebuf(stdout);
|
||||||
if ((whoami = strrchr(argv[0], '/')) == NULL)
|
if ((whoami = strrchr(argv[0], '/')) == NULL)
|
||||||
{
|
{
|
||||||
whoami = argv[0];
|
whoami = argv[0];
|
||||||
|
|
Loading…
Reference in New Issue
Block a user