mirror of
https://github.com/qpdf/qpdf.git
synced 2024-12-22 19:08:59 +00:00
convert file to a PointerHolder<InputSource> so it could be either a file or a buffer; also fix a bug in BufferInputSource::seek
git-svn-id: svn+q:///qpdf/trunk@1030 71b93d88-0707-0410-a8cf-f5a4172ac649
This commit is contained in:
parent
aa035961b3
commit
ce8b1ba6a5
@ -423,15 +423,16 @@ class QPDF
|
||||
void setLastObjectDescription(std::string const& description,
|
||||
int objid, int generation);
|
||||
QPDFObjectHandle readObject(
|
||||
InputSource*, std::string const& description,
|
||||
PointerHolder<InputSource>, std::string const& description,
|
||||
int objid, int generation, bool in_object_stream);
|
||||
QPDFObjectHandle readObjectInternal(
|
||||
InputSource* input, int objid, int generation,
|
||||
PointerHolder<InputSource> input, int objid, int generation,
|
||||
bool in_object_stream,
|
||||
bool in_array, bool in_dictionary);
|
||||
int recoverStreamLength(
|
||||
InputSource* input, int objid, int generation, off_t stream_offset);
|
||||
QPDFTokenizer::Token readToken(InputSource*);
|
||||
PointerHolder<InputSource> input, int objid, int generation,
|
||||
off_t stream_offset);
|
||||
QPDFTokenizer::Token readToken(PointerHolder<InputSource>);
|
||||
|
||||
QPDFObjectHandle readObjectAtOffset(
|
||||
bool attempt_recovery,
|
||||
@ -785,7 +786,7 @@ class QPDF
|
||||
|
||||
|
||||
QPDFTokenizer tokenizer;
|
||||
FileInputSource file;
|
||||
PointerHolder<InputSource> file;
|
||||
std::string last_object_description;
|
||||
bool encrypted;
|
||||
bool encryption_initialized;
|
||||
|
213
libqpdf/QPDF.cc
213
libqpdf/QPDF.cc
@ -303,7 +303,9 @@ QPDF::~QPDF()
|
||||
void
|
||||
QPDF::processFile(char const* filename, char const* password)
|
||||
{
|
||||
this->file.setFilename(filename);
|
||||
FileInputSource* fi = new FileInputSource();
|
||||
this->file = fi;
|
||||
fi->setFilename(filename);
|
||||
if (password)
|
||||
{
|
||||
this->provided_password = password;
|
||||
@ -343,7 +345,7 @@ QPDF::parse()
|
||||
static PCRE header_re("^%PDF-(1.\\d+)\\b");
|
||||
static PCRE eof_re("(?s:startxref\\s+(\\d+)\\s+%%EOF\\b)");
|
||||
|
||||
std::string line = this->file.readLine();
|
||||
std::string line = this->file->readLine();
|
||||
PCRE::Match m1 = header_re.match(line.c_str());
|
||||
if (m1)
|
||||
{
|
||||
@ -356,7 +358,7 @@ QPDF::parse()
|
||||
else
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF not a pdf file");
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"", 0, "not a PDF file");
|
||||
}
|
||||
|
||||
@ -364,14 +366,14 @@ QPDF::parse()
|
||||
// the file. We add an extra 30 characters to leave room for the
|
||||
// startxref stuff.
|
||||
static int const tbuf_size = 1054;
|
||||
this->file.seek(0, SEEK_END);
|
||||
if (this->file.tell() > tbuf_size)
|
||||
this->file->seek(0, SEEK_END);
|
||||
if (this->file->tell() > tbuf_size)
|
||||
{
|
||||
this->file.seek(-tbuf_size, SEEK_END);
|
||||
this->file->seek(-tbuf_size, SEEK_END);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->file.rewind();
|
||||
this->file->rewind();
|
||||
}
|
||||
char* buf = new char[tbuf_size + 1];
|
||||
// Put buf in a PointerHolder to guarantee deletion of buf. This
|
||||
@ -379,7 +381,7 @@ QPDF::parse()
|
||||
// an array of fundamental types.
|
||||
PointerHolder<char> b(buf);
|
||||
memset(buf, '\0', tbuf_size + 1);
|
||||
this->file.read(buf, tbuf_size);
|
||||
this->file->read(buf, tbuf_size);
|
||||
|
||||
// Since buf may contain null characters, we can't do a regexp
|
||||
// search on buf directly. Find the last occurrence within buf
|
||||
@ -401,7 +403,7 @@ QPDF::parse()
|
||||
if (! m2)
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF can't find startxref");
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(), "", 0,
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), "", 0,
|
||||
"can't find startxref");
|
||||
}
|
||||
off_t xref_offset = atoi(m2.getMatch(1).c_str());
|
||||
@ -450,10 +452,10 @@ QPDF::reconstruct_xref(QPDFExc& e)
|
||||
static PCRE endobj_re("^\\s*endobj\\b");
|
||||
static PCRE trailer_re("^\\s*trailer\\b");
|
||||
|
||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->file.getName(), "", 0,
|
||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), "", 0,
|
||||
"file is damaged"));
|
||||
warn(e);
|
||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->file.getName(), "", 0,
|
||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), "", 0,
|
||||
"Attempting to reconstruct cross-reference table"));
|
||||
|
||||
// Delete all references to type 1 (uncompressed) objects
|
||||
@ -473,13 +475,13 @@ QPDF::reconstruct_xref(QPDFExc& e)
|
||||
this->xref_table.erase(*iter);
|
||||
}
|
||||
|
||||
this->file.seek(0, SEEK_END);
|
||||
off_t eof = this->file.tell();
|
||||
this->file.seek(0, SEEK_SET);
|
||||
this->file->seek(0, SEEK_END);
|
||||
off_t eof = this->file->tell();
|
||||
this->file->seek(0, SEEK_SET);
|
||||
bool in_obj = false;
|
||||
while (this->file.tell() < eof)
|
||||
while (this->file->tell() < eof)
|
||||
{
|
||||
std::string line = this->file.readLine();
|
||||
std::string line = this->file->readLine();
|
||||
if (in_obj)
|
||||
{
|
||||
if (endobj_re.match(line.c_str()))
|
||||
@ -495,17 +497,17 @@ QPDF::reconstruct_xref(QPDFExc& e)
|
||||
in_obj = true;
|
||||
int obj = atoi(m.getMatch(1).c_str());
|
||||
int gen = atoi(m.getMatch(2).c_str());
|
||||
int offset = this->file.getLastOffset();
|
||||
int offset = this->file->getLastOffset();
|
||||
insertXrefEntry(obj, 1, offset, gen, true);
|
||||
}
|
||||
else if ((! this->trailer.isInitialized()) &&
|
||||
trailer_re.match(line.c_str()))
|
||||
{
|
||||
// read "trailer"
|
||||
this->file.seek(this->file.getLastOffset(), SEEK_SET);
|
||||
readToken(&this->file);
|
||||
this->file->seek(this->file->getLastOffset(), SEEK_SET);
|
||||
readToken(this->file);
|
||||
QPDFObjectHandle t =
|
||||
readObject(&this->file, "trailer", 0, 0, false);
|
||||
readObject(this->file, "trailer", 0, 0, false);
|
||||
if (! t.isDictionary())
|
||||
{
|
||||
// Oh well. It was worth a try.
|
||||
@ -526,7 +528,7 @@ QPDF::reconstruct_xref(QPDFExc& e)
|
||||
// with bad startxref pointers even when they have object
|
||||
// streams.
|
||||
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(), "", 0,
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), "", 0,
|
||||
"unable to find trailer "
|
||||
"dictionary while recovering damaged file");
|
||||
}
|
||||
@ -546,11 +548,11 @@ QPDF::read_xref(off_t xref_offset)
|
||||
std::map<int, int> free_table;
|
||||
while (xref_offset)
|
||||
{
|
||||
this->file.seek(xref_offset, SEEK_SET);
|
||||
std::string line = this->file.readLine();
|
||||
this->file->seek(xref_offset, SEEK_SET);
|
||||
std::string line = this->file->readLine();
|
||||
if (line == "xref")
|
||||
{
|
||||
xref_offset = read_xrefTable(this->file.tell());
|
||||
xref_offset = read_xrefTable(this->file->tell());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -571,7 +573,7 @@ QPDF::read_xref(off_t xref_offset)
|
||||
if (size != max_obj + 1)
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF xref size mismatch");
|
||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->file.getName(), "", 0,
|
||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), "", 0,
|
||||
std::string("reported number of objects (") +
|
||||
QUtil::int_to_string(size) +
|
||||
") inconsistent with actual number of objects (" +
|
||||
@ -591,17 +593,17 @@ QPDF::read_xrefTable(off_t xref_offset)
|
||||
|
||||
std::vector<ObjGen> deleted_items;
|
||||
|
||||
this->file.seek(xref_offset, SEEK_SET);
|
||||
this->file->seek(xref_offset, SEEK_SET);
|
||||
bool done = false;
|
||||
while (! done)
|
||||
{
|
||||
std::string line = this->file.readLine();
|
||||
std::string line = this->file->readLine();
|
||||
PCRE::Match m1 = xref_first_re.match(line.c_str());
|
||||
if (! m1)
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF invalid xref");
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"xref table", this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"xref table", this->file->getLastOffset(),
|
||||
"xref syntax invalid");
|
||||
}
|
||||
int obj = atoi(m1.getMatch(1).c_str());
|
||||
@ -613,17 +615,17 @@ QPDF::read_xrefTable(off_t xref_offset)
|
||||
if (i == 0)
|
||||
{
|
||||
// This is needed by checkLinearization()
|
||||
this->first_xref_item_offset = this->file.tell();
|
||||
this->first_xref_item_offset = this->file->tell();
|
||||
}
|
||||
memset(xref_entry, 0, sizeof(xref_entry));
|
||||
this->file.read(xref_entry, xref_entry_size);
|
||||
this->file->read(xref_entry, xref_entry_size);
|
||||
PCRE::Match m2 = xref_entry_re.match(xref_entry);
|
||||
if (! m2)
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF invalid xref entry");
|
||||
throw QPDFExc(
|
||||
qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"xref table", this->file.getLastOffset(),
|
||||
qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"xref table", this->file->getLastOffset(),
|
||||
"invalid xref entry (obj=" +
|
||||
QUtil::int_to_string(i) + ")");
|
||||
}
|
||||
@ -642,26 +644,26 @@ QPDF::read_xrefTable(off_t xref_offset)
|
||||
insertXrefEntry(i, 1, f1, f2);
|
||||
}
|
||||
}
|
||||
off_t pos = this->file.tell();
|
||||
QPDFTokenizer::Token t = readToken(&this->file);
|
||||
off_t pos = this->file->tell();
|
||||
QPDFTokenizer::Token t = readToken(this->file);
|
||||
if (t == QPDFTokenizer::Token(QPDFTokenizer::tt_word, "trailer"))
|
||||
{
|
||||
done = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->file.seek(pos, SEEK_SET);
|
||||
this->file->seek(pos, SEEK_SET);
|
||||
}
|
||||
}
|
||||
|
||||
// Set offset to previous xref table if any
|
||||
QPDFObjectHandle cur_trailer =
|
||||
readObject(&this->file, "trailer", 0, 0, false);
|
||||
readObject(this->file, "trailer", 0, 0, false);
|
||||
if (! cur_trailer.isDictionary())
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF missing trailer");
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"", this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"", this->file->getLastOffset(),
|
||||
"expected trailer dictionary");
|
||||
}
|
||||
|
||||
@ -672,15 +674,15 @@ QPDF::read_xrefTable(off_t xref_offset)
|
||||
if (! this->trailer.hasKey("/Size"))
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF trailer lacks size");
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"trailer", this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"trailer", this->file->getLastOffset(),
|
||||
"trailer dictionary lacks /Size key");
|
||||
}
|
||||
if (! this->trailer.getKey("/Size").isInteger())
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF trailer size not integer");
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"trailer", this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"trailer", this->file->getLastOffset(),
|
||||
"/Size key in trailer dictionary is not "
|
||||
"an integer");
|
||||
}
|
||||
@ -704,7 +706,7 @@ QPDF::read_xrefTable(off_t xref_offset)
|
||||
}
|
||||
else
|
||||
{
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"xref stream", xref_offset,
|
||||
"invalid /XRefStm");
|
||||
}
|
||||
@ -724,8 +726,8 @@ QPDF::read_xrefTable(off_t xref_offset)
|
||||
if (! cur_trailer.getKey("/Prev").isInteger())
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF trailer prev not integer");
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"trailer", this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"trailer", this->file->getLastOffset(),
|
||||
"/Prev key in trailer dictionary is not "
|
||||
"an integer");
|
||||
}
|
||||
@ -772,7 +774,7 @@ QPDF::read_xrefStream(off_t xref_offset)
|
||||
if (! found)
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF can't find xref");
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"", xref_offset, "xref not found");
|
||||
}
|
||||
|
||||
@ -793,7 +795,7 @@ QPDF::processXRefStream(off_t xref_offset, QPDFObjectHandle& xref_obj)
|
||||
dict.getKey("/Size").isInteger() &&
|
||||
(Index_obj.isArray() || Index_obj.isNull())))
|
||||
{
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"xref stream", xref_offset,
|
||||
"Cross-reference stream does not have"
|
||||
" proper /W and /Index keys");
|
||||
@ -804,7 +806,7 @@ QPDF::processXRefStream(off_t xref_offset, QPDFObjectHandle& xref_obj)
|
||||
int n_index = Index_obj.getArrayNItems();
|
||||
if ((n_index % 2) || (n_index < 2))
|
||||
{
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"xref stream", xref_offset,
|
||||
"Cross-reference stream's /Index has an"
|
||||
" invalid number of values");
|
||||
@ -817,7 +819,7 @@ QPDF::processXRefStream(off_t xref_offset, QPDFObjectHandle& xref_obj)
|
||||
}
|
||||
else
|
||||
{
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"xref stream", xref_offset,
|
||||
"Cross-reference stream's /Index's item " +
|
||||
QUtil::int_to_string(i) +
|
||||
@ -856,7 +858,7 @@ QPDF::processXRefStream(off_t xref_offset, QPDFObjectHandle& xref_obj)
|
||||
|
||||
if (expected_size != actual_size)
|
||||
{
|
||||
QPDFExc x(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
QPDFExc x(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"xref stream", xref_offset,
|
||||
"Cross-reference stream data has the wrong size;"
|
||||
" expected = " + QUtil::int_to_string(expected_size) +
|
||||
@ -938,8 +940,8 @@ QPDF::processXRefStream(off_t xref_offset, QPDFObjectHandle& xref_obj)
|
||||
{
|
||||
if (! dict.getKey("/Prev").isInteger())
|
||||
{
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"xref stream", this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"xref stream", this->file->getLastOffset(),
|
||||
"/Prev key in xref stream dictionary is not "
|
||||
"an integer");
|
||||
}
|
||||
@ -1008,8 +1010,8 @@ QPDF::insertXrefEntry(int obj, int f0, int f1, int f2, bool overwrite)
|
||||
break;
|
||||
|
||||
default:
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"xref stream", this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"xref stream", this->file->getLastOffset(),
|
||||
"unknown xref stream entry type " +
|
||||
QUtil::int_to_string(f0));
|
||||
break;
|
||||
@ -1068,7 +1070,8 @@ QPDF::setLastObjectDescription(std::string const& description,
|
||||
}
|
||||
|
||||
QPDFObjectHandle
|
||||
QPDF::readObject(InputSource* input, std::string const& description,
|
||||
QPDF::readObject(PointerHolder<InputSource> input,
|
||||
std::string const& description,
|
||||
int objid, int generation, bool in_object_stream)
|
||||
{
|
||||
setLastObjectDescription(description, objid, generation);
|
||||
@ -1082,7 +1085,7 @@ QPDF::readObject(InputSource* input, std::string const& description,
|
||||
}
|
||||
|
||||
QPDFObjectHandle
|
||||
QPDF::readObjectInternal(InputSource* input,
|
||||
QPDF::readObjectInternal(PointerHolder<InputSource> input,
|
||||
int objid, int generation,
|
||||
bool in_object_stream,
|
||||
bool in_array, bool in_dictionary)
|
||||
@ -1197,20 +1200,6 @@ QPDF::readObjectInternal(InputSource* input,
|
||||
olist.pop_back();
|
||||
olist.pop_back();
|
||||
}
|
||||
else if ((value == "endobj") &&
|
||||
(! (in_array || in_dictionary)))
|
||||
{
|
||||
// Nothing in the PDF spec appears to allow empty
|
||||
// objects, but they have been encountered in
|
||||
// actual PDF files and Adobe Reader appears to
|
||||
// ignore them.
|
||||
warn(QPDFExc(qpdf_e_damaged_pdf, input->getName(),
|
||||
this->last_object_description,
|
||||
input->getLastOffset(),
|
||||
"empty object treated as null"));
|
||||
object = QPDFObjectHandle::newNull();
|
||||
input->seek(input->getLastOffset(), SEEK_SET);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, input->getName(),
|
||||
@ -1386,7 +1375,7 @@ QPDF::readObjectInternal(InputSource* input,
|
||||
}
|
||||
|
||||
int
|
||||
QPDF::recoverStreamLength(InputSource* input,
|
||||
QPDF::recoverStreamLength(PointerHolder<InputSource> input,
|
||||
int objid, int generation, off_t stream_offset)
|
||||
{
|
||||
static PCRE endobj_re("^\\s*endobj\\b");
|
||||
@ -1473,7 +1462,7 @@ QPDF::recoverStreamLength(InputSource* input,
|
||||
}
|
||||
|
||||
QPDFTokenizer::Token
|
||||
QPDF::readToken(InputSource* input)
|
||||
QPDF::readToken(PointerHolder<InputSource> input)
|
||||
{
|
||||
off_t offset = input->tell();
|
||||
QPDFTokenizer::Token token;
|
||||
@ -1523,11 +1512,11 @@ QPDF::readObjectAtOffset(bool try_recovery,
|
||||
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 tgen = readToken(&this->file);
|
||||
QPDFTokenizer::Token tobj = readToken(&this->file);
|
||||
QPDFTokenizer::Token tobjid = readToken(this->file);
|
||||
QPDFTokenizer::Token tgen = readToken(this->file);
|
||||
QPDFTokenizer::Token tobj = readToken(this->file);
|
||||
|
||||
bool objidok = (tobjid.getType() == QPDFTokenizer::tt_integer);
|
||||
int genok = (tgen.getType() == QPDFTokenizer::tt_integer);
|
||||
@ -1542,7 +1531,7 @@ QPDF::readObjectAtOffset(bool try_recovery,
|
||||
if (! (objidok && genok && objok))
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF expected n n obj");
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
this->last_object_description, offset,
|
||||
"expected n n obj");
|
||||
}
|
||||
@ -1553,7 +1542,7 @@ QPDF::readObjectAtOffset(bool try_recovery,
|
||||
(! ((objid == exp_objid) && (generation == exp_generation))))
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF err wrong objid/generation");
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
this->last_object_description, offset,
|
||||
std::string("expected ") +
|
||||
QUtil::int_to_string(exp_objid) + " " +
|
||||
@ -1581,7 +1570,7 @@ QPDF::readObjectAtOffset(bool try_recovery,
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF object gone after xref reconstruction");
|
||||
warn(QPDFExc(
|
||||
qpdf_e_damaged_pdf, this->file.getName(),
|
||||
qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"", 0,
|
||||
std::string(
|
||||
"object " +
|
||||
@ -1600,14 +1589,14 @@ QPDF::readObjectAtOffset(bool try_recovery,
|
||||
}
|
||||
|
||||
QPDFObjectHandle oh = readObject(
|
||||
&this->file, description, objid, generation, false);
|
||||
this->file, description, objid, generation, false);
|
||||
|
||||
if (! (readToken(&this->file) ==
|
||||
if (! (readToken(this->file) ==
|
||||
QPDFTokenizer::Token(QPDFTokenizer::tt_word, "endobj")))
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF err expected endobj");
|
||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
this->last_object_description, this->file.getLastOffset(),
|
||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
this->last_object_description, this->file->getLastOffset(),
|
||||
"expected endobj"));
|
||||
}
|
||||
|
||||
@ -1624,28 +1613,28 @@ QPDF::readObjectAtOffset(bool try_recovery,
|
||||
// linearization hint tables. Offsets and lengths of objects
|
||||
// may imply the end of an object to be anywhere between these
|
||||
// values.
|
||||
off_t end_before_space = this->file.tell();
|
||||
off_t end_before_space = this->file->tell();
|
||||
|
||||
// skip over spaces
|
||||
while (true)
|
||||
{
|
||||
char ch;
|
||||
if (this->file.read(&ch, 1))
|
||||
if (this->file->read(&ch, 1))
|
||||
{
|
||||
if (! isspace((unsigned char)ch))
|
||||
{
|
||||
this->file.seek(-1, SEEK_CUR);
|
||||
this->file->seek(-1, SEEK_CUR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
this->last_object_description, offset,
|
||||
"EOF after endobj");
|
||||
}
|
||||
}
|
||||
off_t end_after_space = this->file.tell();
|
||||
off_t end_after_space = this->file->tell();
|
||||
|
||||
this->obj_cache[og] =
|
||||
ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh),
|
||||
@ -1690,7 +1679,7 @@ QPDF::resolve(int objid, int generation)
|
||||
break;
|
||||
|
||||
default:
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(), "", 0,
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), "", 0,
|
||||
"object " +
|
||||
QUtil::int_to_string(objid) + "/" +
|
||||
QUtil::int_to_string(generation) +
|
||||
@ -1708,9 +1697,9 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
|
||||
QPDFObjectHandle obj_stream = getObjectByID(obj_stream_number, 0);
|
||||
if (! obj_stream.isStream())
|
||||
{
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
this->last_object_description,
|
||||
this->file.getLastOffset(),
|
||||
this->file->getLastOffset(),
|
||||
"supposed object stream " +
|
||||
QUtil::int_to_string(obj_stream_number) +
|
||||
" is not a stream");
|
||||
@ -1727,9 +1716,9 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
|
||||
dict.getKey("/Type").getName() == "/ObjStm"))
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF ERR object stream with wrong type");
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
this->last_object_description,
|
||||
this->file.getLastOffset(),
|
||||
this->file->getLastOffset(),
|
||||
"supposed object stream " +
|
||||
QUtil::int_to_string(obj_stream_number) +
|
||||
" has wrong type");
|
||||
@ -1738,9 +1727,9 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
|
||||
if (! (dict.getKey("/N").isInteger() &&
|
||||
dict.getKey("/First").isInteger()))
|
||||
{
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
this->last_object_description,
|
||||
this->file.getLastOffset(),
|
||||
this->file->getLastOffset(),
|
||||
"object stream " +
|
||||
QUtil::int_to_string(obj_stream_number) +
|
||||
" has incorrect keys");
|
||||
@ -1752,19 +1741,19 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
|
||||
std::map<int, int> offsets;
|
||||
|
||||
PointerHolder<Buffer> bp = obj_stream.getStreamData();
|
||||
BufferInputSource input(
|
||||
PointerHolder<InputSource> input = new BufferInputSource(
|
||||
"object stream " + QUtil::int_to_string(obj_stream_number),
|
||||
bp.getPointer());
|
||||
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
QPDFTokenizer::Token tnum = readToken(&input);
|
||||
QPDFTokenizer::Token toffset = readToken(&input);
|
||||
QPDFTokenizer::Token tnum = readToken(input);
|
||||
QPDFTokenizer::Token toffset = readToken(input);
|
||||
if (! ((tnum.getType() == QPDFTokenizer::tt_integer) &&
|
||||
(toffset.getType() == QPDFTokenizer::tt_integer)))
|
||||
{
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, input.getName(),
|
||||
this->last_object_description, input.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, input->getName(),
|
||||
this->last_object_description, input->getLastOffset(),
|
||||
"expected integer in object stream header");
|
||||
}
|
||||
|
||||
@ -1778,8 +1767,8 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
|
||||
{
|
||||
int obj = (*iter).first;
|
||||
int offset = (*iter).second;
|
||||
input.seek(offset, SEEK_SET);
|
||||
QPDFObjectHandle oh = readObject(&input, "", obj, 0, true);
|
||||
input->seek(offset, SEEK_SET);
|
||||
QPDFObjectHandle oh = readObject(input, "", obj, 0, true);
|
||||
|
||||
// Store in cache
|
||||
ObjGen og(obj, 0);
|
||||
@ -1839,7 +1828,7 @@ QPDF::trimTrailerForWrite()
|
||||
std::string
|
||||
QPDF::getFilename() const
|
||||
{
|
||||
return this->file.getName();
|
||||
return this->file->getName();
|
||||
}
|
||||
|
||||
std::string
|
||||
@ -1988,18 +1977,18 @@ QPDF::pipeStreamData(int objid, int generation,
|
||||
|
||||
try
|
||||
{
|
||||
this->file.seek(offset, SEEK_SET);
|
||||
this->file->seek(offset, SEEK_SET);
|
||||
char buf[10240];
|
||||
while (length > 0)
|
||||
{
|
||||
size_t to_read = (sizeof(buf) < length ? sizeof(buf) : length);
|
||||
size_t len = this->file.read(buf, to_read);
|
||||
size_t len = this->file->read(buf, to_read);
|
||||
if (len == 0)
|
||||
{
|
||||
throw QPDFExc(qpdf_e_damaged_pdf,
|
||||
this->file.getName(),
|
||||
this->file->getName(),
|
||||
this->last_object_description,
|
||||
this->file.getLastOffset(),
|
||||
this->file->getLastOffset(),
|
||||
"unexpected EOF reading stream data");
|
||||
}
|
||||
length -= len;
|
||||
@ -2013,8 +2002,8 @@ QPDF::pipeStreamData(int objid, int generation,
|
||||
catch (std::runtime_error& e)
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF decoding error warning");
|
||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"", this->file.getLastOffset(),
|
||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"", this->file->getLastOffset(),
|
||||
"error decoding stream data for object " +
|
||||
QUtil::int_to_string(objid) + " " +
|
||||
QUtil::int_to_string(generation) + ": " + e.what()));
|
||||
@ -2070,9 +2059,9 @@ QPDF::getAllPagesInternal(QPDFObjectHandle cur_pages,
|
||||
}
|
||||
else
|
||||
{
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
this->last_object_description,
|
||||
this->file.getLastOffset(),
|
||||
this->file->getLastOffset(),
|
||||
": invalid Type in page tree");
|
||||
}
|
||||
}
|
||||
|
@ -336,8 +336,8 @@ QPDF::initializeEncryption()
|
||||
(id_obj.getArrayNItems() == 2) &&
|
||||
id_obj.getArrayItem(0).isString()))
|
||||
{
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"trailer", this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"trailer", this->file->getLastOffset(),
|
||||
"invalid /ID in trailer dictionary");
|
||||
}
|
||||
|
||||
@ -345,23 +345,23 @@ QPDF::initializeEncryption()
|
||||
QPDFObjectHandle encryption_dict = this->trailer.getKey("/Encrypt");
|
||||
if (! encryption_dict.isDictionary())
|
||||
{
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
this->last_object_description,
|
||||
this->file.getLastOffset(),
|
||||
this->file->getLastOffset(),
|
||||
"/Encrypt in trailer dictionary is not a dictionary");
|
||||
}
|
||||
|
||||
if (! (encryption_dict.getKey("/Filter").isName() &&
|
||||
(encryption_dict.getKey("/Filter").getName() == "/Standard")))
|
||||
{
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"encryption dictionary", this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"encryption dictionary", this->file->getLastOffset(),
|
||||
"unsupported encryption filter");
|
||||
}
|
||||
if (! encryption_dict.getKey("/SubFilter").isNull())
|
||||
{
|
||||
warn(QPDFExc(qpdf_e_unsupported, this->file.getName(),
|
||||
"encryption dictionary", this->file.getLastOffset(),
|
||||
warn(QPDFExc(qpdf_e_unsupported, this->file->getName(),
|
||||
"encryption dictionary", this->file->getLastOffset(),
|
||||
"file uses encryption SubFilters,"
|
||||
" which qpdf does not support"));
|
||||
}
|
||||
@ -372,8 +372,8 @@ QPDF::initializeEncryption()
|
||||
encryption_dict.getKey("/U").isString() &&
|
||||
encryption_dict.getKey("/P").isInteger()))
|
||||
{
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"encryption dictionary", this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"encryption dictionary", this->file->getLastOffset(),
|
||||
"some encryption dictionary parameters are missing "
|
||||
"or the wrong type");
|
||||
}
|
||||
@ -387,8 +387,8 @@ QPDF::initializeEncryption()
|
||||
if (! (((R == 2) || (R == 3) || (R == 4)) &&
|
||||
((V == 1) || (V == 2) || (V == 4))))
|
||||
{
|
||||
throw QPDFExc(qpdf_e_unsupported, this->file.getName(),
|
||||
"encryption dictionary", this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_unsupported, this->file->getName(),
|
||||
"encryption dictionary", this->file->getLastOffset(),
|
||||
"Unsupported /R or /V in encryption dictionary");
|
||||
}
|
||||
|
||||
@ -396,8 +396,8 @@ QPDF::initializeEncryption()
|
||||
|
||||
if (! ((O.length() == key_bytes) && (U.length() == key_bytes)))
|
||||
{
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"encryption dictionary", this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"encryption dictionary", this->file->getLastOffset(),
|
||||
"incorrect length for /O and/or /P in "
|
||||
"encryption dictionary");
|
||||
}
|
||||
@ -408,8 +408,8 @@ QPDF::initializeEncryption()
|
||||
Length = encryption_dict.getKey("/Length").getIntValue();
|
||||
if ((Length % 8) || (Length < 40) || (Length > 128))
|
||||
{
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
"encryption dictionary", this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"encryption dictionary", this->file->getLastOffset(),
|
||||
"invalid /Length value in encryption dictionary");
|
||||
}
|
||||
}
|
||||
@ -472,8 +472,8 @@ QPDF::initializeEncryption()
|
||||
}
|
||||
if (this->cf_file != this->cf_stream)
|
||||
{
|
||||
throw QPDFExc(qpdf_e_unsupported, this->file.getName(),
|
||||
"encryption dictionary", this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_unsupported, this->file->getName(),
|
||||
"encryption dictionary", this->file->getLastOffset(),
|
||||
"This document has embedded files that are"
|
||||
" encrypted differently from the rest of the file."
|
||||
" qpdf does not presently support this due to"
|
||||
@ -494,7 +494,7 @@ QPDF::initializeEncryption()
|
||||
}
|
||||
else
|
||||
{
|
||||
throw QPDFExc(qpdf_e_password, this->file.getName(),
|
||||
throw QPDFExc(qpdf_e_password, this->file->getName(),
|
||||
"", 0, "invalid password");
|
||||
}
|
||||
|
||||
@ -545,9 +545,9 @@ QPDF::decryptString(std::string& str, int objid, int generation)
|
||||
break;
|
||||
|
||||
default:
|
||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
this->last_object_description,
|
||||
this->file.getLastOffset(),
|
||||
this->file->getLastOffset(),
|
||||
"unknown encryption filter for strings"
|
||||
" (check /StrF in /Encrypt dictionary);"
|
||||
" strings may be decrypted improperly"));
|
||||
@ -595,8 +595,9 @@ QPDF::decryptString(std::string& str, int objid, int generation)
|
||||
}
|
||||
catch (std::runtime_error& e)
|
||||
{
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
this->last_object_description, this->file.getLastOffset(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
this->last_object_description,
|
||||
this->file->getLastOffset(),
|
||||
"error decrypting string for object " +
|
||||
QUtil::int_to_string(objid) + " " +
|
||||
QUtil::int_to_string(generation) + ": " + e.what());
|
||||
@ -669,9 +670,9 @@ QPDF::decryptStream(Pipeline*& pipeline, int objid, int generation,
|
||||
|
||||
default:
|
||||
// filter local to this stream.
|
||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
this->last_object_description,
|
||||
this->file.getLastOffset(),
|
||||
this->file->getLastOffset(),
|
||||
"unknown encryption filter for streams"
|
||||
" (check " + method_source + ");"
|
||||
" streams may be decrypted improperly"));
|
||||
|
@ -87,10 +87,10 @@ QPDF::isLinearized()
|
||||
static int const tbuf_size = 1025;
|
||||
|
||||
char* buf = new char[tbuf_size];
|
||||
this->file.seek(0, SEEK_SET);
|
||||
this->file->seek(0, SEEK_SET);
|
||||
PointerHolder<char> b(buf); // guarantee deletion
|
||||
memset(buf, '\0', tbuf_size);
|
||||
this->file.read(buf, tbuf_size - 1);
|
||||
this->file->read(buf, tbuf_size - 1);
|
||||
|
||||
static PCRE lindict_re("(?s:(\\d+)\\s+0\\s+obj\\s*<<)");
|
||||
|
||||
@ -147,8 +147,8 @@ QPDF::isLinearized()
|
||||
if (L.isInteger())
|
||||
{
|
||||
int Li = L.getIntValue();
|
||||
this->file.seek(0, SEEK_END);
|
||||
if (Li != this->file.tell())
|
||||
this->file->seek(0, SEEK_END);
|
||||
if (Li != this->file->tell())
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF /L mismatch");
|
||||
return false;
|
||||
@ -194,9 +194,9 @@ QPDF::readLinearizationData()
|
||||
T.isInteger() &&
|
||||
(P.isInteger() || P.isNull())))
|
||||
{
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"linearization dictionary",
|
||||
this->file.getLastOffset(),
|
||||
this->file->getLastOffset(),
|
||||
"some keys in linearization dictionary are of "
|
||||
"the wrong type");
|
||||
}
|
||||
@ -205,9 +205,9 @@ QPDF::readLinearizationData()
|
||||
unsigned int n_H_items = H.getArrayNItems();
|
||||
if (! ((n_H_items == 2) || (n_H_items == 4)))
|
||||
{
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"linearization dictionary",
|
||||
this->file.getLastOffset(),
|
||||
this->file->getLastOffset(),
|
||||
"H has the wrong number of items");
|
||||
}
|
||||
|
||||
@ -221,9 +221,9 @@ QPDF::readLinearizationData()
|
||||
}
|
||||
else
|
||||
{
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"linearization dictionary",
|
||||
this->file.getLastOffset(),
|
||||
this->file->getLastOffset(),
|
||||
"some H items are of the wrong type");
|
||||
}
|
||||
}
|
||||
@ -318,9 +318,9 @@ QPDF::readHintStream(Pipeline& pl, off_t offset, size_t length)
|
||||
off_t max_end_offset = oc.end_after_space;
|
||||
if (! H.isStream())
|
||||
{
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"linearization dictionary",
|
||||
this->file.getLastOffset(),
|
||||
this->file->getLastOffset(),
|
||||
"hint table is not a stream");
|
||||
}
|
||||
|
||||
@ -354,9 +354,9 @@ QPDF::readHintStream(Pipeline& pl, off_t offset, size_t length)
|
||||
std::cout << "expected = " << computed_end
|
||||
<< "; actual = " << min_end_offset << ".."
|
||||
<< max_end_offset << std::endl;
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
"linearization dictionary",
|
||||
this->file.getLastOffset(),
|
||||
this->file->getLastOffset(),
|
||||
"hint table length mismatch");
|
||||
}
|
||||
H.pipeStreamData(&pl, true, false, false);
|
||||
@ -509,24 +509,25 @@ QPDF::checkLinearizationInternal()
|
||||
}
|
||||
|
||||
// T: offset of whitespace character preceding xref entry for object 0
|
||||
this->file.seek(p.xref_zero_offset, SEEK_SET);
|
||||
this->file->seek(p.xref_zero_offset, SEEK_SET);
|
||||
while (1)
|
||||
{
|
||||
char ch;
|
||||
this->file.read(&ch, 1);
|
||||
this->file->read(&ch, 1);
|
||||
if (! ((ch == ' ') || (ch == '\r') || (ch == '\n')))
|
||||
{
|
||||
this->file.seek(-1, SEEK_CUR);
|
||||
this->file->seek(-1, SEEK_CUR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (this->file.tell() != this->first_xref_item_offset)
|
||||
if (this->file->tell() != this->first_xref_item_offset)
|
||||
{
|
||||
QTC::TC("qpdf", "QPDF err /T mismatch");
|
||||
errors.push_back("space before first xref item (/T) mismatch "
|
||||
"(computed = " +
|
||||
QUtil::int_to_string(this->first_xref_item_offset) +
|
||||
"; file = " + QUtil::int_to_string(this->file.tell()));
|
||||
"; file = " +
|
||||
QUtil::int_to_string(this->file->tell()));
|
||||
}
|
||||
|
||||
// P: first page number -- Implementation note 124 says Acrobat
|
||||
@ -1014,7 +1015,7 @@ QPDF::showLinearizationData()
|
||||
void
|
||||
QPDF::dumpLinearizationDataInternal()
|
||||
{
|
||||
std::cout << this->file.getName() << ": linearization data:" << std::endl
|
||||
std::cout << this->file->getName() << ": linearization data:" << std::endl
|
||||
<< std::endl;
|
||||
|
||||
std::cout
|
||||
|
@ -246,9 +246,9 @@ QPDF::optimizePagesTree(
|
||||
{
|
||||
if (! allow_changes)
|
||||
{
|
||||
throw QPDFExc(qpdf_e_internal, this->file.getName(),
|
||||
throw QPDFExc(qpdf_e_internal, this->file->getName(),
|
||||
this->last_object_description,
|
||||
this->file.getLastOffset(),
|
||||
this->file->getLastOffset(),
|
||||
"optimize detected an "
|
||||
"inheritable resource when called "
|
||||
"in no-change mode");
|
||||
@ -354,9 +354,9 @@ QPDF::optimizePagesTree(
|
||||
}
|
||||
else
|
||||
{
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file.getName(),
|
||||
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
|
||||
this->last_object_description,
|
||||
this->file.getLastOffset(),
|
||||
this->file->getLastOffset(),
|
||||
"invalid Type in page tree");
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user