Commit c5d0428da21c9b2531fcf6b83f08a52eb7a86a4a
1 parent
556c34f0
Modify QPDF::getObject to not to resolve the object
Showing
2 changed files
with
32 additions
and
21 deletions
libqpdf/QPDF.cc
| ... | ... | @@ -26,6 +26,7 @@ |
| 26 | 26 | #include <qpdf/QPDF_Null.hh> |
| 27 | 27 | #include <qpdf/QPDF_Reserved.hh> |
| 28 | 28 | #include <qpdf/QPDF_Stream.hh> |
| 29 | +#include <qpdf/QPDF_Unresolved.hh> | |
| 29 | 30 | #include <qpdf/QTC.hh> |
| 30 | 31 | #include <qpdf/QUtil.hh> |
| 31 | 32 | |
| ... | ... | @@ -1397,7 +1398,7 @@ QPDF::fixDanglingReferences(bool force) |
| 1397 | 1398 | std::list<QPDFObjectHandle> queue; |
| 1398 | 1399 | queue.push_back(this->m->trailer); |
| 1399 | 1400 | for (auto const& og: to_process) { |
| 1400 | - auto obj = getObjectByObjGen(og); | |
| 1401 | + auto obj = getObject(og); | |
| 1401 | 1402 | if (obj.isDictionary() || obj.isArray()) { |
| 1402 | 1403 | queue.push_back(obj); |
| 1403 | 1404 | } else if (obj.isStream()) { |
| ... | ... | @@ -1424,11 +1425,10 @@ QPDF::fixDanglingReferences(bool force) |
| 1424 | 1425 | } |
| 1425 | 1426 | for (auto sub: to_check) { |
| 1426 | 1427 | if (sub.isIndirect()) { |
| 1427 | - if (sub.getOwningQPDF() == this) { | |
| 1428 | - if (!isCached(sub.getObjGen())) { | |
| 1429 | - QTC::TC("qpdf", "QPDF detected dangling ref"); | |
| 1430 | - queue.push_back(sub); | |
| 1431 | - } | |
| 1428 | + if ((sub.getOwningQPDF() == this) && | |
| 1429 | + isUnresolved(sub.getObjGen())) { | |
| 1430 | + QTC::TC("qpdf", "QPDF detected dangling ref"); | |
| 1431 | + queue.push_back(sub); | |
| 1432 | 1432 | } |
| 1433 | 1433 | } else { |
| 1434 | 1434 | queue.push_back(sub); |
| ... | ... | @@ -1885,7 +1885,7 @@ QPDF::readObjectAtOffset( |
| 1885 | 1885 | "expected endobj"); |
| 1886 | 1886 | } |
| 1887 | 1887 | |
| 1888 | - if (!isCached(og)) { | |
| 1888 | + if (isUnresolved(og)) { | |
| 1889 | 1889 | // Store the object in the cache here so it gets cached |
| 1890 | 1890 | // whether we first know the offset or whether we first know |
| 1891 | 1891 | // the object ID and generation (in which we case we would get |
| ... | ... | @@ -1916,8 +1916,8 @@ QPDF::readObjectAtOffset( |
| 1916 | 1916 | } |
| 1917 | 1917 | } |
| 1918 | 1918 | qpdf_offset_t end_after_space = this->m->file->tell(); |
| 1919 | - | |
| 1920 | - this->m->obj_cache[og] = ObjCache( | |
| 1919 | + updateCache( | |
| 1920 | + og, | |
| 1921 | 1921 | QPDFObjectHandle::ObjAccessor::getObject(oh), |
| 1922 | 1922 | end_before_space, |
| 1923 | 1923 | end_after_space); |
| ... | ... | @@ -1929,6 +1929,11 @@ QPDF::readObjectAtOffset( |
| 1929 | 1929 | std::shared_ptr<QPDFObject> |
| 1930 | 1930 | QPDF::resolve(QPDFObjGen const& og) |
| 1931 | 1931 | { |
| 1932 | + if (isCached(og) && !isUnresolved(og)) { | |
| 1933 | + // We only need to resolve unresolved objects | |
| 1934 | + return m->obj_cache[og].object; | |
| 1935 | + } | |
| 1936 | + | |
| 1932 | 1937 | // Check object cache before checking xref table. This allows us |
| 1933 | 1938 | // to insert things into the object cache that don't actually |
| 1934 | 1939 | // exist in the file. |
| ... | ... | @@ -1942,11 +1947,13 @@ QPDF::resolve(QPDFObjGen const& og) |
| 1942 | 1947 | "", |
| 1943 | 1948 | this->m->file->getLastOffset(), |
| 1944 | 1949 | ("loop detected resolving object " + og.unparse(' '))); |
| 1945 | - return QPDF_Null::create(); | |
| 1950 | + | |
| 1951 | + updateCache(og, QPDF_Null::create(), -1, -1); | |
| 1952 | + return m->obj_cache[og].object; | |
| 1946 | 1953 | } |
| 1947 | 1954 | ResolveRecorder rr(this, og); |
| 1948 | 1955 | |
| 1949 | - if ((!isCached(og)) && this->m->xref_table.count(og)) { | |
| 1956 | + if (m->xref_table.count(og) != 0) { | |
| 1950 | 1957 | QPDFXRefEntry const& entry = this->m->xref_table[og]; |
| 1951 | 1958 | try { |
| 1952 | 1959 | switch (entry.getType()) { |
| ... | ... | @@ -1984,12 +1991,11 @@ QPDF::resolve(QPDFObjGen const& og) |
| 1984 | 1991 | ": error reading object: " + e.what())); |
| 1985 | 1992 | } |
| 1986 | 1993 | } |
| 1987 | - if (!isCached(og)) { | |
| 1994 | + | |
| 1995 | + if (isUnresolved(og)) { | |
| 1988 | 1996 | // PDF spec says unknown objects resolve to the null object. |
| 1989 | 1997 | QTC::TC("qpdf", "QPDF resolve failure to null"); |
| 1990 | - QPDFObjectHandle oh = QPDFObjectHandle::newNull(); | |
| 1991 | - this->m->obj_cache[og] = | |
| 1992 | - ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh), -1, -1); | |
| 1998 | + updateCache(og, QPDF_Null::create(), -1, -1); | |
| 1993 | 1999 | } |
| 1994 | 2000 | |
| 1995 | 2001 | std::shared_ptr<QPDFObject> result(this->m->obj_cache[og].object); |
| ... | ... | @@ -2084,15 +2090,15 @@ QPDF::resolveObjectsInStream(int obj_stream_number) |
| 2084 | 2090 | // objects appended to the file, so it is necessary to recheck the |
| 2085 | 2091 | // xref table and only cache what would actually be resolved here. |
| 2086 | 2092 | for (auto const& iter: offsets) { |
| 2087 | - int obj = iter.first; | |
| 2088 | - QPDFObjGen og(obj, 0); | |
| 2093 | + QPDFObjGen og(iter.first, 0); | |
| 2089 | 2094 | QPDFXRefEntry const& entry = this->m->xref_table[og]; |
| 2090 | 2095 | if ((entry.getType() == 2) && |
| 2091 | 2096 | (entry.getObjStreamNumber() == obj_stream_number)) { |
| 2092 | 2097 | int offset = iter.second; |
| 2093 | 2098 | input->seek(offset, SEEK_SET); |
| 2094 | 2099 | QPDFObjectHandle oh = readObject(input, "", og, true); |
| 2095 | - this->m->obj_cache[og] = ObjCache( | |
| 2100 | + updateCache( | |
| 2101 | + og, | |
| 2096 | 2102 | QPDFObjectHandle::ObjAccessor::getObject(oh), |
| 2097 | 2103 | end_before_space, |
| 2098 | 2104 | end_after_space); |
| ... | ... | @@ -2176,8 +2182,14 @@ QPDF::reserveStream(QPDFObjGen const& og) |
| 2176 | 2182 | QPDFObjectHandle |
| 2177 | 2183 | QPDF::getObject(QPDFObjGen const& og) |
| 2178 | 2184 | { |
| 2179 | - auto obj = (og.getObj() != 0) ? resolve(og) : QPDF_Null::create(); | |
| 2180 | - return newIndirect(og, obj); | |
| 2185 | + if (!og.isIndirect()) { | |
| 2186 | + return QPDFObjectHandle::newNull(); | |
| 2187 | + } | |
| 2188 | + // auto obj = (og.getObj() != 0) ? resolve(og) : QPDF_Null::create(); | |
| 2189 | + if (!m->obj_cache.count(og)) { | |
| 2190 | + m->obj_cache[og] = ObjCache(QPDF_Unresolved::create(), -1, -1); | |
| 2191 | + } | |
| 2192 | + return newIndirect(og, m->obj_cache[og].object); | |
| 2181 | 2193 | } |
| 2182 | 2194 | |
| 2183 | 2195 | QPDFObjectHandle | ... | ... |
qpdf/qtest/qpdf/issue-51.out
| ... | ... | @@ -9,7 +9,6 @@ WARNING: issue-51.pdf (object 2 0, offset 26): /Length key in stream dictionary |
| 9 | 9 | WARNING: issue-51.pdf (object 2 0, offset 71): attempting to recover stream length |
| 10 | 10 | WARNING: issue-51.pdf (object 2 0, offset 71): unable to recover stream data; treating stream as empty |
| 11 | 11 | WARNING: issue-51.pdf (object 2 0, offset 977): expected endobj |
| 12 | -WARNING: issue-51.pdf (object 2 0, offset 977): EOF after endobj | |
| 13 | 12 | WARNING: issue-51.pdf (object 3 0): object has offset 0 |
| 14 | 13 | WARNING: issue-51.pdf (object 4 0): object has offset 0 |
| 15 | 14 | WARNING: issue-51.pdf (object 5 0): object has offset 0 | ... | ... |