2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-11-09 14:50:58 +00:00

Merge pull request #1171 from m-holger/unresolved

Refactor the creation of unresolved objects
This commit is contained in:
m-holger 2024-08-06 14:39:16 +01:00 committed by GitHub
commit 6aa6c01303
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 233 additions and 253 deletions

View File

@ -133,6 +133,8 @@ set(CORPUS_OTHER
70055.fuzz 70055.fuzz
70245.fuzz 70245.fuzz
70306.fuzz 70306.fuzz
70306a.fuzz
70306b.fuzz
) )
set(CORPUS_DIR ${CMAKE_CURRENT_BINARY_DIR}/qpdf_corpus) set(CORPUS_DIR ${CMAKE_CURRENT_BINARY_DIR}/qpdf_corpus)

BIN
fuzz/qpdf_extra/70306a.fuzz Normal file

Binary file not shown.

BIN
fuzz/qpdf_extra/70306b.fuzz Normal file

Binary file not shown.

View File

@ -21,7 +21,7 @@ my @fuzzers = (
['pngpredictor' => 1], ['pngpredictor' => 1],
['runlength' => 6], ['runlength' => 6],
['tiffpredictor' => 2], ['tiffpredictor' => 2],
['qpdf' => 75], # increment when adding new files ['qpdf' => 77], # increment when adding new files
); );
my $n_tests = 0; my $n_tests = 0;

View File

@ -819,7 +819,8 @@ class QPDF
} }
}; };
// The ParseGuard class allows QPDFParser to detect re-entrant parsing. // The ParseGuard class allows QPDFParser to detect re-entrant parsing. It also provides
// special access to allow the parser to create unresolved objects and dangling references.
class ParseGuard class ParseGuard
{ {
friend class QPDFParser; friend class QPDFParser;
@ -832,6 +833,13 @@ class QPDF
qpdf->inParse(true); qpdf->inParse(true);
} }
} }
static std::shared_ptr<QPDFObject>
getObject(QPDF* qpdf, int id, int gen, bool parse_pdf)
{
return qpdf->getObjectForParser(id, gen, parse_pdf);
}
~ParseGuard() ~ParseGuard()
{ {
if (qpdf) { if (qpdf) {
@ -900,8 +908,8 @@ class QPDF
} }
ObjCache( ObjCache(
std::shared_ptr<QPDFObject> object, std::shared_ptr<QPDFObject> object,
qpdf_offset_t end_before_space, qpdf_offset_t end_before_space = 0,
qpdf_offset_t end_after_space) : qpdf_offset_t end_after_space = 0) :
object(object), object(object),
end_before_space(end_before_space), end_before_space(end_before_space),
end_after_space(end_after_space) end_after_space(end_after_space)
@ -1065,13 +1073,14 @@ class QPDF
QPDFObject* resolve(QPDFObjGen og); QPDFObject* resolve(QPDFObjGen og);
void resolveObjectsInStream(int obj_stream_number); void resolveObjectsInStream(int obj_stream_number);
void stopOnError(std::string const& message); void stopOnError(std::string const& message);
QPDFObjectHandle reserveObjectIfNotExists(QPDFObjGen const& og);
QPDFObjectHandle reserveStream(QPDFObjGen const& og); QPDFObjectHandle reserveStream(QPDFObjGen const& og);
QPDFObjGen nextObjGen(); QPDFObjGen nextObjGen();
QPDFObjectHandle newIndirect(QPDFObjGen const&, std::shared_ptr<QPDFObject> const&); QPDFObjectHandle newIndirect(QPDFObjGen const&, std::shared_ptr<QPDFObject> const&);
QPDFObjectHandle makeIndirectFromQPDFObject(std::shared_ptr<QPDFObject> const& obj); QPDFObjectHandle makeIndirectFromQPDFObject(std::shared_ptr<QPDFObject> const& obj);
bool isCached(QPDFObjGen const& og); bool isCached(QPDFObjGen const& og);
bool isUnresolved(QPDFObjGen const& og); bool isUnresolved(QPDFObjGen const& og);
std::shared_ptr<QPDFObject> getObjectForParser(int id, int gen, bool parse_pdf);
std::shared_ptr<QPDFObject> getObjectForJSON(int id, int gen);
void removeObject(QPDFObjGen og); void removeObject(QPDFObjGen og);
void updateCache( void updateCache(
QPDFObjGen const& og, QPDFObjGen const& og,

View File

@ -654,9 +654,11 @@ QPDF::reconstruct_xref(QPDFExc& e)
} }
check_warnings(); check_warnings();
if (!m->parsed) { if (!m->parsed) {
m->parsed = true;
getAllPages(); getAllPages();
check_warnings(); check_warnings();
if (m->all_pages.empty()) { if (m->all_pages.empty()) {
m->parsed = false;
throw damagedPDF("", 0, "unable to find any pages while recovering damaged file"); throw damagedPDF("", 0, "unable to find any pages while recovering damaged file");
} }
} }
@ -1462,7 +1464,8 @@ QPDF::readTrailer()
{ {
qpdf_offset_t offset = m->file->tell(); qpdf_offset_t offset = m->file->tell();
bool empty = false; bool empty = false;
auto object = QPDFParser(m->file, "trailer", m->tokenizer, nullptr, this).parse(empty, false); auto object =
QPDFParser(m->file, "trailer", m->tokenizer, nullptr, this, true).parse(empty, false);
if (empty) { if (empty) {
// Nothing in the PDF spec appears to allow empty objects, but they have been encountered in // 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. // actual PDF files and Adobe Reader appears to ignore them.
@ -1484,8 +1487,9 @@ QPDF::readObject(std::string const& description, QPDFObjGen og)
StringDecrypter decrypter{this, og}; StringDecrypter decrypter{this, og};
StringDecrypter* decrypter_ptr = m->encp->encrypted ? &decrypter : nullptr; StringDecrypter* decrypter_ptr = m->encp->encrypted ? &decrypter : nullptr;
auto object = QPDFParser(m->file, m->last_object_description, m->tokenizer, decrypter_ptr, this) auto object =
.parse(empty, false); QPDFParser(m->file, m->last_object_description, m->tokenizer, decrypter_ptr, this, true)
.parse(empty, false);
if (empty) { if (empty) {
// Nothing in the PDF spec appears to allow empty objects, but they have been encountered in // 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. // actual PDF files and Adobe Reader appears to ignore them.
@ -1604,7 +1608,7 @@ QPDF::readObjectInStream(std::shared_ptr<InputSource>& input, int obj)
m->last_object_description += " 0"; m->last_object_description += " 0";
bool empty = false; bool empty = false;
auto object = QPDFParser(input, m->last_object_description, m->tokenizer, nullptr, this) auto object = QPDFParser(input, m->last_object_description, m->tokenizer, nullptr, this, true)
.parse(empty, false); .parse(empty, false);
if (empty) { if (empty) {
// Nothing in the PDF spec appears to allow empty objects, but they have been encountered in // Nothing in the PDF spec appears to allow empty objects, but they have been encountered in
@ -2093,31 +2097,53 @@ QPDF::newStream(std::string const& data)
return result; return result;
} }
QPDFObjectHandle
QPDF::reserveObjectIfNotExists(QPDFObjGen const& og)
{
if (!isCached(og) && m->xref_table.count(og) == 0) {
updateCache(og, QPDF_Reserved::create(), -1, -1);
return newIndirect(og, m->obj_cache[og].object);
} else {
return getObject(og);
}
}
QPDFObjectHandle QPDFObjectHandle
QPDF::reserveStream(QPDFObjGen const& og) QPDF::reserveStream(QPDFObjGen const& og)
{ {
return {QPDF_Stream::create(this, og, QPDFObjectHandle::newDictionary(), 0, 0)}; return {QPDF_Stream::create(this, og, QPDFObjectHandle::newDictionary(), 0, 0)};
} }
std::shared_ptr<QPDFObject>
QPDF::getObjectForParser(int id, int gen, bool parse_pdf)
{
// This method is called by the parser and therefore must not resolve any objects.
auto og = QPDFObjGen(id, gen);
if (auto iter = m->obj_cache.find(og); iter != m->obj_cache.end()) {
return iter->second.object;
}
if (m->xref_table.count(og) || !m->parsed) {
return m->obj_cache.insert({og, QPDF_Unresolved::create(this, og)}).first->second.object;
}
if (parse_pdf) {
return QPDF_Null::create();
}
return m->obj_cache.insert({og, QPDF_Null::create(this, og)}).first->second.object;
}
std::shared_ptr<QPDFObject>
QPDF::getObjectForJSON(int id, int gen)
{
auto og = QPDFObjGen(id, gen);
auto [it, inserted] = m->obj_cache.try_emplace(og);
auto& obj = it->second.object;
if (inserted) {
obj = (m->parsed && !m->xref_table.count(og)) ? QPDF_Null::create(this, og)
: QPDF_Unresolved::create(this, og);
}
return obj;
}
QPDFObjectHandle QPDFObjectHandle
QPDF::getObject(QPDFObjGen const& og) QPDF::getObject(QPDFObjGen const& og)
{ {
// This method is called by the parser and therefore must not resolve any objects. if (auto it = m->obj_cache.find(og); it != m->obj_cache.end()) {
if (!isCached(og)) { return {it->second.object};
m->obj_cache[og] = ObjCache(QPDF_Unresolved::create(this, og), -1, -1); } else if (m->parsed && !m->xref_table.count(og)) {
return QPDF_Null::create();
} else {
auto result = m->obj_cache.try_emplace(og, QPDF_Unresolved::create(this, og), -1, -1);
return {result.first->second.object};
} }
return newIndirect(og, m->obj_cache[og].object);
} }
QPDFObjectHandle QPDFObjectHandle

View File

@ -2146,7 +2146,8 @@ QPDFObjectHandle::parseContentStream_data(
tokenizer.readToken(input, "content", true); tokenizer.readToken(input, "content", true);
qpdf_offset_t offset = input->getLastOffset(); qpdf_offset_t offset = input->getLastOffset();
input->seek(offset, SEEK_SET); input->seek(offset, SEEK_SET);
auto obj = QPDFParser(input, "content", tokenizer, nullptr, context).parse(empty, true); auto obj =
QPDFParser(input, "content", tokenizer, nullptr, context, false).parse(empty, true);
if (!obj.isInitialized()) { if (!obj.isInitialized()) {
// EOF // EOF
break; break;
@ -2205,7 +2206,8 @@ QPDFObjectHandle::parse(
StringDecrypter* decrypter, StringDecrypter* decrypter,
QPDF* context) QPDF* context)
{ {
return QPDFParser(input, object_description, tokenizer, decrypter, context).parse(empty, false); return QPDFParser(input, object_description, tokenizer, decrypter, context, false)
.parse(empty, false);
} }
#ifndef QPDF_FUTURE #ifndef QPDF_FUTURE

View File

@ -71,7 +71,7 @@ QPDFOutlineDocumentHelper::resolveNamedDest(QPDFObjectHandle name)
m->dest_dict = qpdf.getRoot().getKey("/Dests"); m->dest_dict = qpdf.getRoot().getKey("/Dests");
} }
QTC::TC("qpdf", "QPDFOutlineDocumentHelper name named dest"); QTC::TC("qpdf", "QPDFOutlineDocumentHelper name named dest");
result= m->dest_dict.getKeyIfDict(name.getName()); result = m->dest_dict.getKeyIfDict(name.getName());
} else if (name.isString()) { } else if (name.isString()) {
if (!m->names_dest) { if (!m->names_dest) {
auto dests = qpdf.getRoot().getKey("/Names").getKeyIfDict("/Dests"); auto dests = qpdf.getRoot().getKey("/Names").getKeyIfDict("/Dests");

View File

@ -166,10 +166,7 @@ QPDFParser::parseRemainder(bool content_stream)
auto id = QIntC::to_int(int_buffer[(int_count - 1) % 2]); auto id = QIntC::to_int(int_buffer[(int_count - 1) % 2]);
auto gen = QIntC::to_int(int_buffer[(int_count) % 2]); auto gen = QIntC::to_int(int_buffer[(int_count) % 2]);
if (!(id < 1 || gen < 0 || gen >= 65535)) { if (!(id < 1 || gen < 0 || gen >= 65535)) {
// This action has the desirable side effect of causing dangling references add(QPDF::ParseGuard::getObject(context, id, gen, parse_pdf));
// (references to indirect objects that don't appear in the PDF) in any parsed
// object to appear in the object cache.
add(std::move(context->getObject(id, gen).obj));
} else { } else {
QTC::TC("qpdf", "QPDFParser invalid objgen"); QTC::TC("qpdf", "QPDFParser invalid objgen");
addNull(); addNull();

View File

@ -1237,7 +1237,7 @@ bool
QPDFWriter::willFilterStream( QPDFWriter::willFilterStream(
QPDFObjectHandle stream, QPDFObjectHandle stream,
bool& compress_stream, // out only bool& compress_stream, // out only
bool& is_metadata, // out only bool& is_metadata, // out only
std::shared_ptr<Buffer>* stream_data) std::shared_ptr<Buffer>* stream_data)
{ {
compress_stream = false; compress_stream = false;

View File

@ -3,15 +3,15 @@
#include <qpdf/JSON_writer.hh> #include <qpdf/JSON_writer.hh>
#include <qpdf/QPDFObject_private.hh> #include <qpdf/QPDFObject_private.hh>
QPDF_Null::QPDF_Null() : QPDF_Null::QPDF_Null(QPDF* qpdf, QPDFObjGen og) :
QPDFValue(::ot_null, "null") QPDFValue(::ot_null, "null", qpdf, og)
{ {
} }
std::shared_ptr<QPDFObject> std::shared_ptr<QPDFObject>
QPDF_Null::create() QPDF_Null::create(QPDF* qpdf, QPDFObjGen og)
{ {
return do_create(new QPDF_Null()); return do_create(new QPDF_Null(qpdf, og));
} }
std::shared_ptr<QPDFObject> std::shared_ptr<QPDFObject>

View File

@ -240,11 +240,6 @@ class QPDF::JSONReactor: public JSON::Reactor
descr(std::make_shared<QPDFValue::Description>( descr(std::make_shared<QPDFValue::Description>(
QPDFValue::JSON_Descr(std::make_shared<std::string>(is->getName()), ""))) QPDFValue::JSON_Descr(std::make_shared<std::string>(is->getName()), "")))
{ {
for (auto& oc: pdf.m->obj_cache) {
if (oc.second.object->getTypeCode() == ::ot_reserved) {
reserved.insert(oc.first);
}
}
} }
~JSONReactor() override = default; ~JSONReactor() override = default;
void dictionaryStart() override; void dictionaryStart() override;
@ -272,10 +267,10 @@ class QPDF::JSONReactor: public JSON::Reactor
struct StackFrame struct StackFrame
{ {
StackFrame(state_e state) : StackFrame(state_e state) :
state(state){}; state(state) {};
StackFrame(state_e state, QPDFObjectHandle&& object) : StackFrame(state_e state, QPDFObjectHandle&& object) :
state(state), state(state),
object(object){}; object(object) {};
state_e state; state_e state;
QPDFObjectHandle object; QPDFObjectHandle object;
}; };
@ -305,7 +300,6 @@ class QPDF::JSONReactor: public JSON::Reactor
bool saw_data{false}; bool saw_data{false};
bool saw_datafile{false}; bool saw_datafile{false};
bool this_stream_needs_data{false}; bool this_stream_needs_data{false};
std::set<QPDFObjGen> reserved;
std::vector<StackFrame> stack; std::vector<StackFrame> stack;
QPDFObjectHandle next_obj; QPDFObjectHandle next_obj;
state_e next_state{st_top}; state_e next_state{st_top};
@ -416,16 +410,6 @@ QPDF::JSONReactor::containerEnd(JSON const& value)
} }
} }
} }
} else if (from_state == st_qpdf) {
// Handle dangling indirect object references which the PDF spec says to treat as nulls.
// It's tempting to make this an error, but that would be wrong since valid input files may
// have these.
for (auto& oc: pdf.m->obj_cache) {
if (oc.second.object->getTypeCode() == ::ot_reserved && reserved.count(oc.first) == 0) {
QTC::TC("qpdf", "QPDF_json non-trivial null reserved");
pdf.updateCache(oc.first, QPDF_Null::create(), -1, -1);
}
}
} }
if (!stack.empty()) { if (!stack.empty()) {
auto state = stack.back().state; auto state = stack.back().state;
@ -565,7 +549,7 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value)
} else if (is_obj_key(key, obj, gen)) { } else if (is_obj_key(key, obj, gen)) {
this->cur_object = key; this->cur_object = key;
if (setNextStateIfDictionary(key, value, st_object_top)) { if (setNextStateIfDictionary(key, value, st_object_top)) {
next_obj = pdf.reserveObjectIfNotExists(QPDFObjGen(obj, gen)); next_obj = pdf.getObjectForJSON(obj, gen);
} }
} else { } else {
QTC::TC("qpdf", "QPDF_json bad object key"); QTC::TC("qpdf", "QPDF_json bad object key");
@ -767,7 +751,7 @@ QPDF::JSONReactor::makeObject(JSON const& value)
int gen = 0; int gen = 0;
std::string str; std::string str;
if (is_indirect_object(str_v, obj, gen)) { if (is_indirect_object(str_v, obj, gen)) {
result = pdf.reserveObjectIfNotExists(QPDFObjGen(obj, gen)); result = pdf.getObjectForJSON(obj, gen);
} else if (is_unicode_string(str_v, str)) { } else if (is_unicode_string(str_v, str)) {
result = QPDFObjectHandle::newUnicodeString(str); result = QPDFObjectHandle::newUnicodeString(str);
} else if (is_binary_string(str_v, str)) { } else if (is_binary_string(str_v, str)) {

View File

@ -16,14 +16,16 @@ class QPDFParser
std::string const& object_description, std::string const& object_description,
QPDFTokenizer& tokenizer, QPDFTokenizer& tokenizer,
QPDFObjectHandle::StringDecrypter* decrypter, QPDFObjectHandle::StringDecrypter* decrypter,
QPDF* context) : QPDF* context,
bool parse_pdf) :
input(input), input(input),
object_description(object_description), object_description(object_description),
tokenizer(tokenizer), tokenizer(tokenizer),
decrypter(decrypter), decrypter(decrypter),
context(context), context(context),
description(std::make_shared<QPDFValue::Description>( description(std::make_shared<QPDFValue::Description>(
std::string(input->getName() + ", " + object_description + " at offset $PO"))) std::string(input->getName() + ", " + object_description + " at offset $PO"))),
parse_pdf(parse_pdf)
{ {
} }
virtual ~QPDFParser() = default; virtual ~QPDFParser() = default;
@ -76,6 +78,8 @@ class QPDFParser
QPDFObjectHandle::StringDecrypter* decrypter; QPDFObjectHandle::StringDecrypter* decrypter;
QPDF* context; QPDF* context;
std::shared_ptr<QPDFValue::Description> description; std::shared_ptr<QPDFValue::Description> description;
bool parse_pdf;
std::vector<StackFrame> stack; std::vector<StackFrame> stack;
StackFrame* frame; StackFrame* frame;
// Number of recent bad tokens. // Number of recent bad tokens.

View File

@ -7,7 +7,7 @@ class QPDF_Null: public QPDFValue
{ {
public: public:
~QPDF_Null() override = default; ~QPDF_Null() override = default;
static std::shared_ptr<QPDFObject> create(); static std::shared_ptr<QPDFObject> create(QPDF* qpdf = nullptr, QPDFObjGen og = QPDFObjGen());
static std::shared_ptr<QPDFObject> create( static std::shared_ptr<QPDFObject> create(
std::shared_ptr<QPDFObject> parent, std::shared_ptr<QPDFObject> parent,
std::string_view const& static_descr, std::string_view const& static_descr,
@ -21,7 +21,7 @@ class QPDF_Null: public QPDFValue
void writeJSON(int json_version, JSON::Writer& p) override; void writeJSON(int json_version, JSON::Writer& p) override;
private: private:
QPDF_Null(); QPDF_Null(QPDF* qpdf = nullptr, QPDFObjGen og = QPDFObjGen());
}; };
#endif // QPDF_NULL_HH #endif // QPDF_NULL_HH

View File

@ -16,7 +16,7 @@ struct _qpdf_data
_qpdf_data() = default; _qpdf_data() = default;
_qpdf_data(std::unique_ptr<QPDF>&& qpdf) : _qpdf_data(std::unique_ptr<QPDF>&& qpdf) :
qpdf(std::move(qpdf)){}; qpdf(std::move(qpdf)) {};
~_qpdf_data() = default; ~_qpdf_data() = default;

View File

@ -90,17 +90,17 @@ main()
obj = QPDF_Array::create({10, "null"_qpdf.getObj()}, true); obj = QPDF_Array::create({10, "null"_qpdf.getObj()}, true);
QPDF_Array& b = *obj->as<QPDF_Array>(); QPDF_Array& b = *obj->as<QPDF_Array>();
b.setAt(5, pdf.getObject(5, 0)); b.setAt(5, pdf.newIndirectNull());
b.setAt(7, "[0 1 2 3]"_qpdf); b.setAt(7, "[0 1 2 3]"_qpdf);
assert(b.at(3).isNull()); assert(b.at(3).isNull());
assert(b.at(8).isNull()); assert(b.at(8).isNull());
assert(b.at(5).isIndirect()); assert(b.at(5).isIndirect());
assert(b.unparse() == "[ null null null null null 5 0 R null [ 0 1 2 3 ] null null ]"); assert(b.unparse() == "[ null null null null null 3 0 R null [ 0 1 2 3 ] null null ]");
auto c = b.copy(true); auto c = b.copy(true);
auto d = b.copy(false); auto d = b.copy(false);
b.at(7).setArrayItem(2, "42"_qpdf); b.at(7).setArrayItem(2, "42"_qpdf);
assert(c->unparse() == "[ null null null null null 5 0 R null [ 0 1 42 3 ] null null ]"); assert(c->unparse() == "[ null null null null null 3 0 R null [ 0 1 42 3 ] null null ]");
assert(d->unparse() == "[ null null null null null 5 0 R null [ 0 1 2 3 ] null null ]"); assert(d->unparse() == "[ null null null null null 3 0 R null [ 0 1 2 3 ] null null ]");
try { try {
b.setAt(3, {}); b.setAt(3, {});

View File

@ -675,7 +675,6 @@ QPDF_json ignore second-level key 0
QPDF_json ignore unknown key in object_top 0 QPDF_json ignore unknown key in object_top 0
QPDF_json ignore unknown key in trailer 0 QPDF_json ignore unknown key in trailer 0
QPDF_json ignore unknown key in stream 0 QPDF_json ignore unknown key in stream 0
QPDF_json non-trivial null reserved 0
QPDF_json data and datafile 0 QPDF_json data and datafile 0
QPDF_json no stream data in update mode 0 QPDF_json no stream data in update mode 0
QPDF_json updating existing stream 0 QPDF_json updating existing stream 0

View File

@ -1,7 +1,7 @@
WARNING: dangling-bad-xref.pdf: file is damaged WARNING: dangling-bad-xref.pdf: file is damaged
WARNING: dangling-bad-xref.pdf (object 7 0, offset 10000): expected n n obj WARNING: dangling-bad-xref.pdf (object 7 0, offset 10000): expected n n obj
WARNING: dangling-bad-xref.pdf: Attempting to reconstruct cross-reference table WARNING: dangling-bad-xref.pdf: Attempting to reconstruct cross-reference table
new object: 13 0 R new object: 12 0 R
all objects all objects
1 0 R 1 0 R
2 0 R 2 0 R
@ -10,10 +10,6 @@ all objects
5 0 R 5 0 R
6 0 R 6 0 R
7 0 R 7 0 R
8 0 R
9 0 R
10 0 R
11 0 R 11 0 R
12 0 R 12 0 R
13 0 R
test 53 done test 53 done

View File

@ -1,4 +1,4 @@
new object: 11 0 R new object: 8 0 R
all objects all objects
1 0 R 1 0 R
2 0 R 2 0 R
@ -8,7 +8,4 @@ all objects
6 0 R 6 0 R
7 0 R 7 0 R
8 0 R 8 0 R
9 0 R
10 0 R
11 0 R
test 53 done test 53 done

View File

@ -7,5 +7,5 @@
/nesting is direct /nesting is direct
/strings is direct /strings is direct
unparse: 7 0 R unparse: 7 0 R
unparseResolved: << /dangling-ref-for-json-test [ 9 0 R ] /hex#20strings [ (Potato) <01020300040560> (AB) ] /indirect 8 0 R /names [ /nesting /hex#20strings /text#2fplain ] /nesting << /a [ 1 2 << /x (y) >> [ (z) ] ] /b << / (legal) /a [ 1 2 ] >> >> /strings [ (one) <24a2> () (\(\)) (\() (\)) (a\f\b\t\r\nb) (") ("") ("\("\)") <410042> (a\nb) (a b) <efbbbfcf80> <efbbbff09fa594> ] >> unparseResolved: << /dangling-ref-for-json-test [ null ] /hex#20strings [ (Potato) <01020300040560> (AB) ] /indirect 8 0 R /names [ /nesting /hex#20strings /text#2fplain ] /nesting << /a [ 1 2 << /x (y) >> [ (z) ] ] /b << / (legal) /a [ 1 2 ] >> >> /strings [ (one) <24a2> () (\(\)) (\() (\)) (a\f\b\t\r\nb) (") ("") ("\("\)") <410042> (a\nb) (a b) <efbbbfcf80> <efbbbff09fa594> ] >>
test 1 done test 1 done

View File

@ -14,14 +14,14 @@ endobj
2 0 obj 2 0 obj
<< <<
/dangling-ref-for-json-test [ /dangling-ref-for-json-test [
4 0 R null
] ]
/hex#20strings [ /hex#20strings [
(Potato) (Potato)
<01020300040560> <01020300040560>
(AB) (AB)
] ]
/indirect 5 0 R /indirect 4 0 R
/names [ /names [
/nesting /nesting
/hex#20strings /hex#20strings
@ -71,27 +71,22 @@ endobj
<< <<
/Count 1 /Count 1
/Kids [ /Kids [
6 0 R 5 0 R
] ]
/Type /Pages /Type /Pages
>> >>
endobj endobj
%% Original object ID: 9 0
4 0 obj
null
endobj
%% Original object ID: 8 0 %% Original object ID: 8 0
5 0 obj 4 0 obj
(hello) (hello)
endobj endobj
%% Page 1 %% Page 1
%% Original object ID: 3 0 %% Original object ID: 3 0
6 0 obj 5 0 obj
<< <<
/Contents 7 0 R /Contents 6 0 R
/MediaBox [ /MediaBox [
0 0
0 0
@ -101,9 +96,9 @@ endobj
/Parent 3 0 R /Parent 3 0 R
/Resources << /Resources <<
/Font << /Font <<
/F1 9 0 R /F1 8 0 R
>> >>
/ProcSet 10 0 R /ProcSet 9 0 R
>> >>
/Type /Page /Type /Page
>> >>
@ -111,9 +106,9 @@ endobj
%% Contents for page 1 %% Contents for page 1
%% Original object ID: 4 0 %% Original object ID: 4 0
7 0 obj 6 0 obj
<< <<
/Length 8 0 R /Length 7 0 R
>> >>
stream stream
BT BT
@ -124,12 +119,12 @@ ET
endstream endstream
endobj endobj
8 0 obj 7 0 obj
44 44
endobj endobj
%% Original object ID: 6 0 %% Original object ID: 6 0
9 0 obj 8 0 obj
<< <<
/BaseFont /Helvetica /BaseFont /Helvetica
/Encoding /WinAnsiEncoding /Encoding /WinAnsiEncoding
@ -140,7 +135,7 @@ endobj
endobj endobj
%% Original object ID: 5 0 %% Original object ID: 5 0
10 0 obj 9 0 obj
[ [
/PDF /PDF
/Text /Text
@ -148,24 +143,23 @@ endobj
endobj endobj
xref xref
0 11 0 10
0000000000 65535 f 0000000000 65535 f
0000000052 00000 n 0000000052 00000 n
0000000133 00000 n 0000000133 00000 n
0000000756 00000 n 0000000755 00000 n
0000000855 00000 n 0000000854 00000 n
0000000903 00000 n 0000000915 00000 n
0000000964 00000 n 0000001157 00000 n
0000001207 00000 n 0000001256 00000 n
0000001306 00000 n 0000001302 00000 n
0000001352 00000 n 0000001447 00000 n
0000001497 00000 n
trailer << trailer <<
/QTest 2 0 R /QTest 2 0 R
/Root 1 0 R /Root 1 0 R
/Size 11 /Size 10
/ID [<31415926535897932384626433832795><31415926535897932384626433832795>] /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
>> >>
startxref startxref
1533 1482
%%EOF %%EOF

View File

@ -5,7 +5,7 @@
item 2 is direct item 2 is direct
item 3 is indirect item 3 is indirect
item 4 is direct item 4 is direct
item 5 is indirect item 5 is direct
unparse: 9 0 R unparse: 9 0 R
unparseResolved: [ /literal null /indirect 8 0 R /undefined 10 0 R ] unparseResolved: [ /literal null /indirect 8 0 R /undefined null ]
test 1 done test 1 done

View File

@ -18,7 +18,7 @@ endobj
/indirect /indirect
4 0 R 4 0 R
/undefined /undefined
5 0 R null
] ]
endobj endobj
@ -27,7 +27,7 @@ endobj
<< <<
/Count 1 /Count 1
/Kids [ /Kids [
6 0 R 5 0 R
] ]
/Type /Pages /Type /Pages
>> >>
@ -38,16 +38,11 @@ endobj
null null
endobj endobj
%% Original object ID: 10 0
5 0 obj
null
endobj
%% Page 1 %% Page 1
%% Original object ID: 3 0 %% Original object ID: 3 0
6 0 obj 5 0 obj
<< <<
/Contents 7 0 R /Contents 6 0 R
/MediaBox [ /MediaBox [
0 0
0 0
@ -57,9 +52,9 @@ endobj
/Parent 3 0 R /Parent 3 0 R
/Resources << /Resources <<
/Font << /Font <<
/F1 9 0 R /F1 8 0 R
>> >>
/ProcSet 10 0 R /ProcSet 9 0 R
>> >>
/Type /Page /Type /Page
>> >>
@ -67,9 +62,9 @@ endobj
%% Contents for page 1 %% Contents for page 1
%% Original object ID: 4 0 %% Original object ID: 4 0
7 0 obj 6 0 obj
<< <<
/Length 8 0 R /Length 7 0 R
>> >>
stream stream
BT BT
@ -80,12 +75,12 @@ ET
endstream endstream
endobj endobj
8 0 obj 7 0 obj
44 44
endobj endobj
%% Original object ID: 6 0 %% Original object ID: 6 0
9 0 obj 8 0 obj
<< <<
/BaseFont /Helvetica /BaseFont /Helvetica
/Encoding /WinAnsiEncoding /Encoding /WinAnsiEncoding
@ -96,7 +91,7 @@ endobj
endobj endobj
%% Original object ID: 7 0 %% Original object ID: 7 0
10 0 obj 9 0 obj
[ [
/PDF /PDF
/Text /Text
@ -104,24 +99,23 @@ endobj
endobj endobj
xref xref
0 11 0 10
0000000000 65535 f 0000000000 65535 f
0000000052 00000 n 0000000052 00000 n
0000000133 00000 n 0000000133 00000 n
0000000239 00000 n 0000000238 00000 n
0000000338 00000 n 0000000337 00000 n
0000000387 00000 n 0000000395 00000 n
0000000445 00000 n 0000000637 00000 n
0000000688 00000 n 0000000736 00000 n
0000000787 00000 n 0000000782 00000 n
0000000833 00000 n 0000000927 00000 n
0000000978 00000 n
trailer << trailer <<
/QTest 2 0 R /QTest 2 0 R
/Root 1 0 R /Root 1 0 R
/Size 11 /Size 10
/ID [<06c2c8fc54c5f9cc9246898e1e1a7146><31415926535897932384626433832795>] /ID [<06c2c8fc54c5f9cc9246898e1e1a7146><31415926535897932384626433832795>]
>> >>
startxref startxref
1014 962
%%EOF %%EOF

View File

@ -14,14 +14,14 @@ endobj
2 0 obj 2 0 obj
<< <<
/dangling-ref-for-json-test [ /dangling-ref-for-json-test [
4 0 R null
] ]
/hex#20strings [ /hex#20strings [
(Potato) (Potato)
<01020300040560> <01020300040560>
(AB) (AB)
] ]
/indirect 5 0 R /indirect 4 0 R
/names [ /names [
/nesting /nesting
/hex#20strings /hex#20strings
@ -71,27 +71,22 @@ endobj
<< <<
/Count 1 /Count 1
/Kids [ /Kids [
6 0 R 5 0 R
] ]
/Type /Pages /Type /Pages
>> >>
endobj endobj
%% Original object ID: 9 0
4 0 obj
null
endobj
%% Original object ID: 8 0 %% Original object ID: 8 0
5 0 obj 4 0 obj
(hello) (hello)
endobj endobj
%% Page 1 %% Page 1
%% Original object ID: 3 0 %% Original object ID: 3 0
6 0 obj 5 0 obj
<< <<
/Contents 7 0 R /Contents 6 0 R
/MediaBox [ /MediaBox [
0 0
0 0
@ -101,9 +96,9 @@ endobj
/Parent 3 0 R /Parent 3 0 R
/Resources << /Resources <<
/Font << /Font <<
/F1 9 0 R /F1 8 0 R
>> >>
/ProcSet 10 0 R /ProcSet 9 0 R
>> >>
/Type /Page /Type /Page
>> >>
@ -111,9 +106,9 @@ endobj
%% Contents for page 1 %% Contents for page 1
%% Original object ID: 4 0 %% Original object ID: 4 0
7 0 obj 6 0 obj
<< <<
/Length 8 0 R /Length 7 0 R
>> >>
stream stream
BT BT
@ -124,12 +119,12 @@ ET
endstream endstream
endobj endobj
8 0 obj 7 0 obj
44 44
endobj endobj
%% Original object ID: 6 0 %% Original object ID: 6 0
9 0 obj 8 0 obj
<< <<
/BaseFont /Helvetica /BaseFont /Helvetica
/Encoding /WinAnsiEncoding /Encoding /WinAnsiEncoding
@ -140,7 +135,7 @@ endobj
endobj endobj
%% Original object ID: 5 0 %% Original object ID: 5 0
10 0 obj 9 0 obj
[ [
/PDF /PDF
/Text /Text
@ -148,24 +143,23 @@ endobj
endobj endobj
xref xref
0 11 0 10
0000000000 65535 f 0000000000 65535 f
0000000052 00000 n 0000000052 00000 n
0000000133 00000 n 0000000133 00000 n
0000000752 00000 n 0000000751 00000 n
0000000851 00000 n 0000000850 00000 n
0000000899 00000 n 0000000911 00000 n
0000000960 00000 n 0000001153 00000 n
0000001203 00000 n 0000001252 00000 n
0000001302 00000 n 0000001298 00000 n
0000001348 00000 n 0000001443 00000 n
0000001493 00000 n
trailer << trailer <<
/QTest 2 0 R /QTest 2 0 R
/Root 1 0 R /Root 1 0 R
/Size 11 /Size 10
/ID [<31415926535897932384626433832795><31415926535897932384626433832795>] /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
>> >>
startxref startxref
1529 1478
%%EOF %%EOF

View File

@ -14,14 +14,14 @@ endobj
2 0 obj 2 0 obj
<< <<
/dangling-ref-for-json-test [ /dangling-ref-for-json-test [
4 0 R null
] ]
/hex#20strings [ /hex#20strings [
(Potato) (Potato)
<01020300040560> <01020300040560>
(AB) (AB)
] ]
/indirect 5 0 R /indirect 4 0 R
/names [ /names [
/nesting /nesting
/hex#20strings /hex#20strings
@ -71,37 +71,32 @@ endobj
<< <<
/Count 1 /Count 1
/Kids [ /Kids [
7 0 R 6 0 R
] ]
/Type /Pages /Type /Pages
>> >>
endobj endobj
%% Original object ID: 9 0
4 0 obj
null
endobj
%% Original object ID: 8 0 %% Original object ID: 8 0
5 0 obj 4 0 obj
<< <<
/K /V /K /V
/Length 6 0 R /Length 5 0 R
>> >>
stream stream
new-stream-here new-stream-here
endstream endstream
endobj endobj
6 0 obj 5 0 obj
16 16
endobj endobj
%% Page 1 %% Page 1
%% Original object ID: 3 0 %% Original object ID: 3 0
7 0 obj 6 0 obj
<< <<
/Contents 8 0 R /Contents 7 0 R
/MediaBox [ /MediaBox [
0 0
0 0
@ -111,9 +106,9 @@ endobj
/Parent 3 0 R /Parent 3 0 R
/Resources << /Resources <<
/Font << /Font <<
/F1 10 0 R /F1 9 0 R
>> >>
/ProcSet 11 0 R /ProcSet 10 0 R
>> >>
/Type /Page /Type /Page
>> >>
@ -121,9 +116,9 @@ endobj
%% Contents for page 1 %% Contents for page 1
%% Original object ID: 4 0 %% Original object ID: 4 0
8 0 obj 7 0 obj
<< <<
/Length 9 0 R /Length 8 0 R
>> >>
stream stream
BT BT
@ -134,12 +129,12 @@ ET
endstream endstream
endobj endobj
9 0 obj 8 0 obj
44 44
endobj endobj
%% Original object ID: 6 0 %% Original object ID: 6 0
10 0 obj 9 0 obj
<< <<
/BaseFont /Helvetica /BaseFont /Helvetica
/Encoding /WinAnsiEncoding /Encoding /WinAnsiEncoding
@ -150,7 +145,7 @@ endobj
endobj endobj
%% Original object ID: 5 0 %% Original object ID: 5 0
11 0 obj 10 0 obj
[ [
/PDF /PDF
/Text /Text
@ -158,25 +153,24 @@ endobj
endobj endobj
xref xref
0 12 0 11
0000000000 65535 f 0000000000 65535 f
0000000052 00000 n 0000000052 00000 n
0000000133 00000 n 0000000133 00000 n
0000000756 00000 n 0000000755 00000 n
0000000855 00000 n 0000000854 00000 n
0000000903 00000 n 0000000933 00000 n
0000000982 00000 n 0000000989 00000 n
0000001038 00000 n 0000001232 00000 n
0000001282 00000 n 0000001331 00000 n
0000001381 00000 n 0000001377 00000 n
0000001427 00000 n 0000001522 00000 n
0000001573 00000 n
trailer << trailer <<
/QTest 2 0 R /QTest 2 0 R
/Root 1 0 R /Root 1 0 R
/Size 12 /Size 11
/ID [<31415926535897932384626433832795><31415926535897932384626433832795>] /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
>> >>
startxref startxref
1609 1558
%%EOF %%EOF

View File

@ -14,14 +14,14 @@ endobj
2 0 obj 2 0 obj
<< <<
/dangling-ref-for-json-test [ /dangling-ref-for-json-test [
4 0 R null
] ]
/hex#20strings [ /hex#20strings [
(Potato) (Potato)
<01020300040560> <01020300040560>
(AB) (AB)
] ]
/indirect 5 0 R /indirect 4 0 R
/names [ /names [
/nesting /nesting
/hex#20strings /hex#20strings
@ -71,27 +71,22 @@ endobj
<< <<
/Count 1 /Count 1
/Kids [ /Kids [
6 0 R 5 0 R
] ]
/Type /Pages /Type /Pages
>> >>
endobj endobj
%% Original object ID: 9 0
4 0 obj
null
endobj
%% Original object ID: 8 0 %% Original object ID: 8 0
5 0 obj 4 0 obj
(hello) (hello)
endobj endobj
%% Page 1 %% Page 1
%% Original object ID: 3 0 %% Original object ID: 3 0
6 0 obj 5 0 obj
<< <<
/Contents 7 0 R /Contents 6 0 R
/MediaBox [ /MediaBox [
0 0
0 0
@ -101,9 +96,9 @@ endobj
/Parent 3 0 R /Parent 3 0 R
/Resources << /Resources <<
/Font << /Font <<
/F1 9 0 R /F1 8 0 R
>> >>
/ProcSet 10 0 R /ProcSet 9 0 R
>> >>
/Type /Page /Type /Page
>> >>
@ -111,9 +106,9 @@ endobj
%% Contents for page 1 %% Contents for page 1
%% Original object ID: 4 0 %% Original object ID: 4 0
7 0 obj 6 0 obj
<< <<
/Length 8 0 R /Length 7 0 R
>> >>
stream stream
BT BT
@ -124,12 +119,12 @@ ET
endstream endstream
endobj endobj
8 0 obj 7 0 obj
43 43
endobj endobj
%% Original object ID: 6 0 %% Original object ID: 6 0
9 0 obj 8 0 obj
<< <<
/BaseFont /Helvetica /BaseFont /Helvetica
/Encoding /WinAnsiEncoding /Encoding /WinAnsiEncoding
@ -140,7 +135,7 @@ endobj
endobj endobj
%% Original object ID: 5 0 %% Original object ID: 5 0
10 0 obj 9 0 obj
[ [
/PDF /PDF
/Text /Text
@ -148,24 +143,23 @@ endobj
endobj endobj
xref xref
0 11 0 10
0000000000 65535 f 0000000000 65535 f
0000000052 00000 n 0000000052 00000 n
0000000133 00000 n 0000000133 00000 n
0000000756 00000 n 0000000755 00000 n
0000000855 00000 n 0000000854 00000 n
0000000903 00000 n 0000000915 00000 n
0000000964 00000 n 0000001157 00000 n
0000001207 00000 n 0000001255 00000 n
0000001305 00000 n 0000001301 00000 n
0000001351 00000 n 0000001446 00000 n
0000001496 00000 n
trailer << trailer <<
/QTest 2 0 R /QTest 2 0 R
/Root 1 0 R /Root 1 0 R
/Size 11 /Size 10
/ID [<31415926535897932384626433832795><31415926535897932384626433832795>] /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
>> >>
startxref startxref
1532 1481
%%EOF %%EOF

View File

@ -14,14 +14,14 @@ endobj
2 0 obj 2 0 obj
<< <<
/dangling-ref-for-json-test [ /dangling-ref-for-json-test [
4 0 R null
] ]
/hex#20strings [ /hex#20strings [
(Potato) (Potato)
<01020300040560> <01020300040560>
(AB) (AB)
] ]
/indirect 5 0 R /indirect 4 0 R
/names [ /names [
/nesting /nesting
/hex#20strings /hex#20strings
@ -71,27 +71,22 @@ endobj
<< <<
/Count 1 /Count 1
/Kids [ /Kids [
6 0 R 5 0 R
] ]
/Type /Pages /Type /Pages
>> >>
endobj endobj
%% Original object ID: 9 0
4 0 obj
null
endobj
%% Original object ID: 8 0 %% Original object ID: 8 0
5 0 obj 4 0 obj
(hello) (hello)
endobj endobj
%% Page 1 %% Page 1
%% Original object ID: 3 0 %% Original object ID: 3 0
6 0 obj 5 0 obj
<< <<
/Contents 7 0 R /Contents 6 0 R
/MediaBox [ /MediaBox [
0 0
0 0
@ -101,9 +96,9 @@ endobj
/Parent 3 0 R /Parent 3 0 R
/Resources << /Resources <<
/Font << /Font <<
/F1 9 0 R /F1 8 0 R
>> >>
/ProcSet 10 0 R /ProcSet 9 0 R
>> >>
/Type /Page /Type /Page
>> >>
@ -111,10 +106,10 @@ endobj
%% Contents for page 1 %% Contents for page 1
%% Original object ID: 4 0 %% Original object ID: 4 0
7 0 obj 6 0 obj
<< <<
/Potato (salad) /Potato (salad)
/Length 8 0 R /Length 7 0 R
>> >>
stream stream
BT BT
@ -125,12 +120,12 @@ ET
endstream endstream
endobj endobj
8 0 obj 7 0 obj
44 44
endobj endobj
%% Original object ID: 6 0 %% Original object ID: 6 0
9 0 obj 8 0 obj
<< <<
/BaseFont /Helvetica /BaseFont /Helvetica
/Encoding /WinAnsiEncoding /Encoding /WinAnsiEncoding
@ -141,7 +136,7 @@ endobj
endobj endobj
%% Original object ID: 5 0 %% Original object ID: 5 0
10 0 obj 9 0 obj
[ [
/PDF /PDF
/Text /Text
@ -149,24 +144,23 @@ endobj
endobj endobj
xref xref
0 11 0 10
0000000000 65535 f 0000000000 65535 f
0000000052 00000 n 0000000052 00000 n
0000000133 00000 n 0000000133 00000 n
0000000756 00000 n 0000000755 00000 n
0000000855 00000 n 0000000854 00000 n
0000000903 00000 n 0000000915 00000 n
0000000964 00000 n 0000001157 00000 n
0000001207 00000 n 0000001274 00000 n
0000001324 00000 n 0000001320 00000 n
0000001370 00000 n 0000001465 00000 n
0000001515 00000 n
trailer << trailer <<
/QTest 2 0 R /QTest 2 0 R
/Root 1 0 R /Root 1 0 R
/Size 11 /Size 10
/ID [<31415926535897932384626433832795><31415926535897932384626433832795>] /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
>> >>
startxref startxref
1551 1500
%%EOF %%EOF