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,6 +26,7 @@ | ||
| 26 | #include <qpdf/QPDF_Null.hh> | 26 | #include <qpdf/QPDF_Null.hh> |
| 27 | #include <qpdf/QPDF_Reserved.hh> | 27 | #include <qpdf/QPDF_Reserved.hh> |
| 28 | #include <qpdf/QPDF_Stream.hh> | 28 | #include <qpdf/QPDF_Stream.hh> |
| 29 | +#include <qpdf/QPDF_Unresolved.hh> | ||
| 29 | #include <qpdf/QTC.hh> | 30 | #include <qpdf/QTC.hh> |
| 30 | #include <qpdf/QUtil.hh> | 31 | #include <qpdf/QUtil.hh> |
| 31 | 32 | ||
| @@ -1397,7 +1398,7 @@ QPDF::fixDanglingReferences(bool force) | @@ -1397,7 +1398,7 @@ QPDF::fixDanglingReferences(bool force) | ||
| 1397 | std::list<QPDFObjectHandle> queue; | 1398 | std::list<QPDFObjectHandle> queue; |
| 1398 | queue.push_back(this->m->trailer); | 1399 | queue.push_back(this->m->trailer); |
| 1399 | for (auto const& og: to_process) { | 1400 | for (auto const& og: to_process) { |
| 1400 | - auto obj = getObjectByObjGen(og); | 1401 | + auto obj = getObject(og); |
| 1401 | if (obj.isDictionary() || obj.isArray()) { | 1402 | if (obj.isDictionary() || obj.isArray()) { |
| 1402 | queue.push_back(obj); | 1403 | queue.push_back(obj); |
| 1403 | } else if (obj.isStream()) { | 1404 | } else if (obj.isStream()) { |
| @@ -1424,11 +1425,10 @@ QPDF::fixDanglingReferences(bool force) | @@ -1424,11 +1425,10 @@ QPDF::fixDanglingReferences(bool force) | ||
| 1424 | } | 1425 | } |
| 1425 | for (auto sub: to_check) { | 1426 | for (auto sub: to_check) { |
| 1426 | if (sub.isIndirect()) { | 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 | } else { | 1433 | } else { |
| 1434 | queue.push_back(sub); | 1434 | queue.push_back(sub); |
| @@ -1885,7 +1885,7 @@ QPDF::readObjectAtOffset( | @@ -1885,7 +1885,7 @@ QPDF::readObjectAtOffset( | ||
| 1885 | "expected endobj"); | 1885 | "expected endobj"); |
| 1886 | } | 1886 | } |
| 1887 | 1887 | ||
| 1888 | - if (!isCached(og)) { | 1888 | + if (isUnresolved(og)) { |
| 1889 | // Store the object in the cache here so it gets cached | 1889 | // Store the object in the cache here so it gets cached |
| 1890 | // whether we first know the offset or whether we first know | 1890 | // whether we first know the offset or whether we first know |
| 1891 | // the object ID and generation (in which we case we would get | 1891 | // the object ID and generation (in which we case we would get |
| @@ -1916,8 +1916,8 @@ QPDF::readObjectAtOffset( | @@ -1916,8 +1916,8 @@ QPDF::readObjectAtOffset( | ||
| 1916 | } | 1916 | } |
| 1917 | } | 1917 | } |
| 1918 | qpdf_offset_t end_after_space = this->m->file->tell(); | 1918 | qpdf_offset_t end_after_space = this->m->file->tell(); |
| 1919 | - | ||
| 1920 | - this->m->obj_cache[og] = ObjCache( | 1919 | + updateCache( |
| 1920 | + og, | ||
| 1921 | QPDFObjectHandle::ObjAccessor::getObject(oh), | 1921 | QPDFObjectHandle::ObjAccessor::getObject(oh), |
| 1922 | end_before_space, | 1922 | end_before_space, |
| 1923 | end_after_space); | 1923 | end_after_space); |
| @@ -1929,6 +1929,11 @@ QPDF::readObjectAtOffset( | @@ -1929,6 +1929,11 @@ QPDF::readObjectAtOffset( | ||
| 1929 | std::shared_ptr<QPDFObject> | 1929 | std::shared_ptr<QPDFObject> |
| 1930 | QPDF::resolve(QPDFObjGen const& og) | 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 | // Check object cache before checking xref table. This allows us | 1937 | // Check object cache before checking xref table. This allows us |
| 1933 | // to insert things into the object cache that don't actually | 1938 | // to insert things into the object cache that don't actually |
| 1934 | // exist in the file. | 1939 | // exist in the file. |
| @@ -1942,11 +1947,13 @@ QPDF::resolve(QPDFObjGen const& og) | @@ -1942,11 +1947,13 @@ QPDF::resolve(QPDFObjGen const& og) | ||
| 1942 | "", | 1947 | "", |
| 1943 | this->m->file->getLastOffset(), | 1948 | this->m->file->getLastOffset(), |
| 1944 | ("loop detected resolving object " + og.unparse(' '))); | 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 | ResolveRecorder rr(this, og); | 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 | QPDFXRefEntry const& entry = this->m->xref_table[og]; | 1957 | QPDFXRefEntry const& entry = this->m->xref_table[og]; |
| 1951 | try { | 1958 | try { |
| 1952 | switch (entry.getType()) { | 1959 | switch (entry.getType()) { |
| @@ -1984,12 +1991,11 @@ QPDF::resolve(QPDFObjGen const& og) | @@ -1984,12 +1991,11 @@ QPDF::resolve(QPDFObjGen const& og) | ||
| 1984 | ": error reading object: " + e.what())); | 1991 | ": error reading object: " + e.what())); |
| 1985 | } | 1992 | } |
| 1986 | } | 1993 | } |
| 1987 | - if (!isCached(og)) { | 1994 | + |
| 1995 | + if (isUnresolved(og)) { | ||
| 1988 | // PDF spec says unknown objects resolve to the null object. | 1996 | // PDF spec says unknown objects resolve to the null object. |
| 1989 | QTC::TC("qpdf", "QPDF resolve failure to null"); | 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 | std::shared_ptr<QPDFObject> result(this->m->obj_cache[og].object); | 2001 | std::shared_ptr<QPDFObject> result(this->m->obj_cache[og].object); |
| @@ -2084,15 +2090,15 @@ QPDF::resolveObjectsInStream(int obj_stream_number) | @@ -2084,15 +2090,15 @@ QPDF::resolveObjectsInStream(int obj_stream_number) | ||
| 2084 | // objects appended to the file, so it is necessary to recheck the | 2090 | // objects appended to the file, so it is necessary to recheck the |
| 2085 | // xref table and only cache what would actually be resolved here. | 2091 | // xref table and only cache what would actually be resolved here. |
| 2086 | for (auto const& iter: offsets) { | 2092 | for (auto const& iter: offsets) { |
| 2087 | - int obj = iter.first; | ||
| 2088 | - QPDFObjGen og(obj, 0); | 2093 | + QPDFObjGen og(iter.first, 0); |
| 2089 | QPDFXRefEntry const& entry = this->m->xref_table[og]; | 2094 | QPDFXRefEntry const& entry = this->m->xref_table[og]; |
| 2090 | if ((entry.getType() == 2) && | 2095 | if ((entry.getType() == 2) && |
| 2091 | (entry.getObjStreamNumber() == obj_stream_number)) { | 2096 | (entry.getObjStreamNumber() == obj_stream_number)) { |
| 2092 | int offset = iter.second; | 2097 | int offset = iter.second; |
| 2093 | input->seek(offset, SEEK_SET); | 2098 | input->seek(offset, SEEK_SET); |
| 2094 | QPDFObjectHandle oh = readObject(input, "", og, true); | 2099 | QPDFObjectHandle oh = readObject(input, "", og, true); |
| 2095 | - this->m->obj_cache[og] = ObjCache( | 2100 | + updateCache( |
| 2101 | + og, | ||
| 2096 | QPDFObjectHandle::ObjAccessor::getObject(oh), | 2102 | QPDFObjectHandle::ObjAccessor::getObject(oh), |
| 2097 | end_before_space, | 2103 | end_before_space, |
| 2098 | end_after_space); | 2104 | end_after_space); |
| @@ -2176,8 +2182,14 @@ QPDF::reserveStream(QPDFObjGen const& og) | @@ -2176,8 +2182,14 @@ QPDF::reserveStream(QPDFObjGen const& og) | ||
| 2176 | QPDFObjectHandle | 2182 | QPDFObjectHandle |
| 2177 | QPDF::getObject(QPDFObjGen const& og) | 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 | QPDFObjectHandle | 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,7 +9,6 @@ WARNING: issue-51.pdf (object 2 0, offset 26): /Length key in stream dictionary | ||
| 9 | WARNING: issue-51.pdf (object 2 0, offset 71): attempting to recover stream length | 9 | WARNING: issue-51.pdf (object 2 0, offset 71): attempting to recover stream length |
| 10 | WARNING: issue-51.pdf (object 2 0, offset 71): unable to recover stream data; treating stream as empty | 10 | WARNING: issue-51.pdf (object 2 0, offset 71): unable to recover stream data; treating stream as empty |
| 11 | WARNING: issue-51.pdf (object 2 0, offset 977): expected endobj | 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 | WARNING: issue-51.pdf (object 3 0): object has offset 0 | 12 | WARNING: issue-51.pdf (object 3 0): object has offset 0 |
| 14 | WARNING: issue-51.pdf (object 4 0): object has offset 0 | 13 | WARNING: issue-51.pdf (object 4 0): object has offset 0 |
| 15 | WARNING: issue-51.pdf (object 5 0): object has offset 0 | 14 | WARNING: issue-51.pdf (object 5 0): object has offset 0 |