mirror of
https://github.com/qpdf/qpdf.git
synced 2024-12-22 19:08:59 +00:00
Add QPDF::Xref_table methods type, offset, stream_number and stream_index
This commit is contained in:
parent
d64b14912d
commit
5fc257f0f7
@ -1769,20 +1769,17 @@ QPDF::readObjectAtOffset(
|
|||||||
if (try_recovery) {
|
if (try_recovery) {
|
||||||
// Try again after reconstructing xref table
|
// Try again after reconstructing xref table
|
||||||
m->xref_table.reconstruct(e);
|
m->xref_table.reconstruct(e);
|
||||||
if (m->xref_table.count(exp_og) && (m->xref_table[exp_og].getType() == 1)) {
|
if (m->xref_table.type(exp_og) == 1) {
|
||||||
qpdf_offset_t new_offset = m->xref_table[exp_og].getOffset();
|
|
||||||
QPDFObjectHandle result =
|
|
||||||
readObjectAtOffset(false, new_offset, description, exp_og, og, false);
|
|
||||||
QTC::TC("qpdf", "QPDF recovered in readObjectAtOffset");
|
QTC::TC("qpdf", "QPDF recovered in readObjectAtOffset");
|
||||||
return result;
|
return readObjectAtOffset(
|
||||||
|
false, m->xref_table.offset(exp_og), description, exp_og, og, false);
|
||||||
} else {
|
} else {
|
||||||
QTC::TC("qpdf", "QPDF object gone after xref reconstruction");
|
QTC::TC("qpdf", "QPDF object gone after xref reconstruction");
|
||||||
warn(damagedPDF(
|
warn(damagedPDF(
|
||||||
"",
|
"",
|
||||||
0,
|
0,
|
||||||
("object " + exp_og.unparse(' ') +
|
("object " + exp_og.unparse(' ') +
|
||||||
" not found in file after regenerating cross reference "
|
" not found in file after regenerating cross reference table")));
|
||||||
"table")));
|
|
||||||
return QPDFObjectHandle::newNull();
|
return QPDFObjectHandle::newNull();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1815,7 +1812,7 @@ QPDF::readObjectAtOffset(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
qpdf_offset_t end_after_space = m->file->tell();
|
qpdf_offset_t end_after_space = m->file->tell();
|
||||||
if (skip_cache_if_in_xref && m->xref_table.count(og)) {
|
if (skip_cache_if_in_xref && m->xref_table.type(og)) {
|
||||||
// Ordinarily, an object gets read here when resolved through xref table or stream. In
|
// Ordinarily, an object gets read here when resolved through xref table or stream. In
|
||||||
// the special case of the xref stream and linearization hint tables, the offset comes
|
// the special case of the xref stream and linearization hint tables, the offset comes
|
||||||
// from another source. For the specific case of xref streams, the xref stream is read
|
// from another source. For the specific case of xref streams, the xref stream is read
|
||||||
@ -1867,33 +1864,32 @@ QPDF::resolve(QPDFObjGen og)
|
|||||||
}
|
}
|
||||||
ResolveRecorder rr(this, og);
|
ResolveRecorder rr(this, og);
|
||||||
|
|
||||||
if (m->xref_table.count(og) != 0) {
|
try {
|
||||||
QPDFXRefEntry const& entry = m->xref_table[og];
|
switch (m->xref_table.type(og)) {
|
||||||
try {
|
case 0:
|
||||||
switch (entry.getType()) {
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
qpdf_offset_t offset = entry.getOffset();
|
// Object stored in cache by readObjectAtOffset
|
||||||
// Object stored in cache by readObjectAtOffset
|
QPDFObjGen a_og;
|
||||||
QPDFObjGen a_og;
|
QPDFObjectHandle oh =
|
||||||
QPDFObjectHandle oh = readObjectAtOffset(true, offset, "", og, a_og, false);
|
readObjectAtOffset(true, m->xref_table.offset(og), "", og, a_og, false);
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
resolveObjectsInStream(entry.getObjStreamNumber());
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw damagedPDF(
|
|
||||||
"", 0, ("object " + og.unparse('/') + " has unexpected xref entry type"));
|
|
||||||
}
|
}
|
||||||
} catch (QPDFExc& e) {
|
break;
|
||||||
warn(e);
|
|
||||||
} catch (std::exception& e) {
|
case 2:
|
||||||
warn(damagedPDF(
|
resolveObjectsInStream(m->xref_table.stream_number(og.getObj()));
|
||||||
"", 0, ("object " + og.unparse('/') + ": error reading object: " + e.what())));
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw damagedPDF(
|
||||||
|
"", 0, ("object " + og.unparse('/') + " has unexpected xref entry type"));
|
||||||
}
|
}
|
||||||
|
} catch (QPDFExc& e) {
|
||||||
|
warn(e);
|
||||||
|
} catch (std::exception& e) {
|
||||||
|
warn(damagedPDF(
|
||||||
|
"", 0, ("object " + og.unparse('/') + ": error reading object: " + e.what())));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isUnresolved(og)) {
|
if (isUnresolved(og)) {
|
||||||
@ -2107,7 +2103,7 @@ QPDF::getObjectForParser(int id, int gen, bool parse_pdf)
|
|||||||
if (auto iter = m->obj_cache.find(og); iter != m->obj_cache.end()) {
|
if (auto iter = m->obj_cache.find(og); iter != m->obj_cache.end()) {
|
||||||
return iter->second.object;
|
return iter->second.object;
|
||||||
}
|
}
|
||||||
if (m->xref_table.count(og) || !m->xref_table.parsed) {
|
if (m->xref_table.type(og) || !m->xref_table.parsed) {
|
||||||
return m->obj_cache.insert({og, QPDF_Unresolved::create(this, og)}).first->second.object;
|
return m->obj_cache.insert({og, QPDF_Unresolved::create(this, og)}).first->second.object;
|
||||||
}
|
}
|
||||||
if (parse_pdf) {
|
if (parse_pdf) {
|
||||||
@ -2123,9 +2119,8 @@ QPDF::getObjectForJSON(int id, int gen)
|
|||||||
auto [it, inserted] = m->obj_cache.try_emplace(og);
|
auto [it, inserted] = m->obj_cache.try_emplace(og);
|
||||||
auto& obj = it->second.object;
|
auto& obj = it->second.object;
|
||||||
if (inserted) {
|
if (inserted) {
|
||||||
obj = (m->xref_table.parsed && !m->xref_table.count(og))
|
obj = (m->xref_table.parsed && !m->xref_table.type(og)) ? QPDF_Null::create(this, og)
|
||||||
? QPDF_Null::create(this, og)
|
: QPDF_Unresolved::create(this, og);
|
||||||
: QPDF_Unresolved::create(this, og);
|
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
@ -2135,7 +2130,7 @@ QPDF::getObject(QPDFObjGen const& og)
|
|||||||
{
|
{
|
||||||
if (auto it = m->obj_cache.find(og); it != m->obj_cache.end()) {
|
if (auto it = m->obj_cache.find(og); it != m->obj_cache.end()) {
|
||||||
return {it->second.object};
|
return {it->second.object};
|
||||||
} else if (m->xref_table.parsed && !m->xref_table.count(og)) {
|
} else if (m->xref_table.parsed && !m->xref_table.type(og)) {
|
||||||
return QPDF_Null::create();
|
return QPDF_Null::create();
|
||||||
} else {
|
} else {
|
||||||
auto result = m->obj_cache.try_emplace(og, QPDF_Unresolved::create(this, og), -1, -1);
|
auto result = m->obj_cache.try_emplace(og, QPDF_Unresolved::create(this, og), -1, -1);
|
||||||
|
@ -445,7 +445,7 @@ QPDF::checkLinearizationInternal()
|
|||||||
for (size_t i = 0; i < toS(npages); ++i) {
|
for (size_t i = 0; i < toS(npages); ++i) {
|
||||||
QPDFObjectHandle const& page = pages.at(i);
|
QPDFObjectHandle const& page = pages.at(i);
|
||||||
QPDFObjGen og(page.getObjGen());
|
QPDFObjGen og(page.getObjGen());
|
||||||
if (m->xref_table[og].getType() == 2) {
|
if (m->xref_table.type(og) == 2) {
|
||||||
linearizationWarning(
|
linearizationWarning(
|
||||||
"page dictionary for page " + std::to_string(i) + " is compressed");
|
"page dictionary for page " + std::to_string(i) + " is compressed");
|
||||||
}
|
}
|
||||||
@ -556,23 +556,18 @@ QPDF::maxEnd(ObjUser const& ou)
|
|||||||
qpdf_offset_t
|
qpdf_offset_t
|
||||||
QPDF::getLinearizationOffset(QPDFObjGen const& og)
|
QPDF::getLinearizationOffset(QPDFObjGen const& og)
|
||||||
{
|
{
|
||||||
QPDFXRefEntry entry = m->xref_table[og];
|
switch (m->xref_table.type(og)) {
|
||||||
qpdf_offset_t result = 0;
|
|
||||||
switch (entry.getType()) {
|
|
||||||
case 1:
|
case 1:
|
||||||
result = entry.getOffset();
|
return m->xref_table.offset(og);
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
// For compressed objects, return the offset of the object stream that contains them.
|
// For compressed objects, return the offset of the object stream that contains them.
|
||||||
result = getLinearizationOffset(QPDFObjGen(entry.getObjStreamNumber(), 0));
|
return getLinearizationOffset(QPDFObjGen(m->xref_table.stream_number(og.getObj()), 0));
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
stopOnError("getLinearizationOffset called for xref entry not of type 1 or 2");
|
stopOnError("getLinearizationOffset called for xref entry not of type 1 or 2");
|
||||||
break;
|
return 0; // unreachable
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QPDFObjectHandle
|
QPDFObjectHandle
|
||||||
@ -603,7 +598,7 @@ QPDF::lengthNextN(int first_object, int n)
|
|||||||
int length = 0;
|
int length = 0;
|
||||||
for (int i = 0; i < n; ++i) {
|
for (int i = 0; i < n; ++i) {
|
||||||
QPDFObjGen og(first_object + i, 0);
|
QPDFObjGen og(first_object + i, 0);
|
||||||
if (m->xref_table.count(og) == 0) {
|
if (m->xref_table.type(og) == 0) {
|
||||||
linearizationWarning(
|
linearizationWarning(
|
||||||
"no xref table entry for " + std::to_string(first_object + i) + " 0");
|
"no xref table entry for " + std::to_string(first_object + i) + " 0");
|
||||||
} else {
|
} else {
|
||||||
@ -635,7 +630,7 @@ QPDF::checkHPageOffset(
|
|||||||
int npages = toI(pages.size());
|
int npages = toI(pages.size());
|
||||||
qpdf_offset_t table_offset = adjusted_offset(m->page_offset_hints.first_page_offset);
|
qpdf_offset_t table_offset = adjusted_offset(m->page_offset_hints.first_page_offset);
|
||||||
QPDFObjGen first_page_og(pages.at(0).getObjGen());
|
QPDFObjGen first_page_og(pages.at(0).getObjGen());
|
||||||
if (m->xref_table.count(first_page_og) == 0) {
|
if (m->xref_table.type(first_page_og) == 0) {
|
||||||
stopOnError("supposed first page object is not known");
|
stopOnError("supposed first page object is not known");
|
||||||
}
|
}
|
||||||
qpdf_offset_t offset = getLinearizationOffset(first_page_og);
|
qpdf_offset_t offset = getLinearizationOffset(first_page_og);
|
||||||
@ -646,7 +641,7 @@ QPDF::checkHPageOffset(
|
|||||||
for (int pageno = 0; pageno < npages; ++pageno) {
|
for (int pageno = 0; pageno < npages; ++pageno) {
|
||||||
QPDFObjGen page_og(pages.at(toS(pageno)).getObjGen());
|
QPDFObjGen page_og(pages.at(toS(pageno)).getObjGen());
|
||||||
int first_object = page_og.getObj();
|
int first_object = page_og.getObj();
|
||||||
if (m->xref_table.count(page_og) == 0) {
|
if (m->xref_table.type(page_og) == 0) {
|
||||||
stopOnError("unknown object in page offset hint table");
|
stopOnError("unknown object in page offset hint table");
|
||||||
}
|
}
|
||||||
offset = getLinearizationOffset(page_og);
|
offset = getLinearizationOffset(page_og);
|
||||||
@ -768,7 +763,7 @@ QPDF::checkHSharedObject(std::vector<QPDFObjectHandle> const& pages, std::map<in
|
|||||||
cur_object = so.first_shared_obj;
|
cur_object = so.first_shared_obj;
|
||||||
|
|
||||||
QPDFObjGen og(cur_object, 0);
|
QPDFObjGen og(cur_object, 0);
|
||||||
if (m->xref_table.count(og) == 0) {
|
if (m->xref_table.type(og) == 0) {
|
||||||
stopOnError("unknown object in shared object hint table");
|
stopOnError("unknown object in shared object hint table");
|
||||||
}
|
}
|
||||||
qpdf_offset_t offset = getLinearizationOffset(og);
|
qpdf_offset_t offset = getLinearizationOffset(og);
|
||||||
@ -819,7 +814,7 @@ QPDF::checkHOutlines()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QPDFObjGen og(outlines.getObjGen());
|
QPDFObjGen og(outlines.getObjGen());
|
||||||
if (m->xref_table.count(og) == 0) {
|
if (m->xref_table.type(og) == 0) {
|
||||||
stopOnError("unknown object in outlines hint table");
|
stopOnError("unknown object in outlines hint table");
|
||||||
}
|
}
|
||||||
qpdf_offset_t offset = getLinearizationOffset(og);
|
qpdf_offset_t offset = getLinearizationOffset(og);
|
||||||
@ -838,8 +833,7 @@ QPDF::checkHOutlines()
|
|||||||
std::to_string(table_length) + "; computed = " + std::to_string(length));
|
std::to_string(table_length) + "; computed = " + std::to_string(length));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
linearizationWarning("incorrect first object number in outline "
|
linearizationWarning("incorrect first object number in outline hints table.");
|
||||||
"hints table.");
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
linearizationWarning("incorrect object count in outline hint table");
|
linearizationWarning("incorrect object count in outline hint table");
|
||||||
|
@ -19,6 +19,37 @@ class QPDF::Xref_table: public std::map<QPDFObjGen, QPDFXRefEntry>
|
|||||||
void show();
|
void show();
|
||||||
bool resolve();
|
bool resolve();
|
||||||
|
|
||||||
|
// Returns 0 if og is not in table.
|
||||||
|
int
|
||||||
|
type(QPDFObjGen og) const
|
||||||
|
{
|
||||||
|
auto it = find(og);
|
||||||
|
return it == end() ? 0 : it->second.getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns 0 if og is not in table.
|
||||||
|
qpdf_offset_t
|
||||||
|
offset(QPDFObjGen og) const
|
||||||
|
{
|
||||||
|
auto it = find(og);
|
||||||
|
return it == end() ? 0 : it->second.getOffset();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns 0 if og is not in table.
|
||||||
|
int
|
||||||
|
stream_number(int id) const
|
||||||
|
{
|
||||||
|
auto it = find(QPDFObjGen(id, 0));
|
||||||
|
return it == end() ? 0 : it->second.getObjStreamNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
stream_index(int id) const
|
||||||
|
{
|
||||||
|
auto it = find(QPDFObjGen(id, 0));
|
||||||
|
return it == end() ? 0 : it->second.getObjStreamIndex();
|
||||||
|
}
|
||||||
|
|
||||||
QPDFObjectHandle trailer;
|
QPDFObjectHandle trailer;
|
||||||
bool reconstructed{false};
|
bool reconstructed{false};
|
||||||
// Various tables are indexed by object id, with potential size id + 1
|
// Various tables are indexed by object id, with potential size id + 1
|
||||||
|
Loading…
Reference in New Issue
Block a user