Commit c5d0428da21c9b2531fcf6b83f08a52eb7a86a4a

Authored by m-holger
1 parent 556c34f0

Modify QPDF::getObject to not to resolve the object

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&amp; og) @@ -1942,11 +1947,13 @@ QPDF::resolve(QPDFObjGen const&amp; 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&amp; og) @@ -1984,12 +1991,11 @@ QPDF::resolve(QPDFObjGen const&amp; 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&amp; og) @@ -2176,8 +2182,14 @@ QPDF::reserveStream(QPDFObjGen const&amp; 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