2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-09-19 00:29:07 +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
70245.fuzz
70306.fuzz
70306a.fuzz
70306b.fuzz
)
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],
['runlength' => 6],
['tiffpredictor' => 2],
['qpdf' => 75], # increment when adding new files
['qpdf' => 77], # increment when adding new files
);
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
{
friend class QPDFParser;
@ -832,6 +833,13 @@ class QPDF
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()
{
if (qpdf) {
@ -900,8 +908,8 @@ class QPDF
}
ObjCache(
std::shared_ptr<QPDFObject> object,
qpdf_offset_t end_before_space,
qpdf_offset_t end_after_space) :
qpdf_offset_t end_before_space = 0,
qpdf_offset_t end_after_space = 0) :
object(object),
end_before_space(end_before_space),
end_after_space(end_after_space)
@ -1065,13 +1073,14 @@ class QPDF
QPDFObject* resolve(QPDFObjGen og);
void resolveObjectsInStream(int obj_stream_number);
void stopOnError(std::string const& message);
QPDFObjectHandle reserveObjectIfNotExists(QPDFObjGen const& og);
QPDFObjectHandle reserveStream(QPDFObjGen const& og);
QPDFObjGen nextObjGen();
QPDFObjectHandle newIndirect(QPDFObjGen const&, std::shared_ptr<QPDFObject> const&);
QPDFObjectHandle makeIndirectFromQPDFObject(std::shared_ptr<QPDFObject> const& obj);
bool isCached(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 updateCache(
QPDFObjGen const& og,

View File

@ -654,9 +654,11 @@ QPDF::reconstruct_xref(QPDFExc& e)
}
check_warnings();
if (!m->parsed) {
m->parsed = true;
getAllPages();
check_warnings();
if (m->all_pages.empty()) {
m->parsed = false;
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();
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) {
// 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.
@ -1484,8 +1487,9 @@ QPDF::readObject(std::string const& description, QPDFObjGen og)
StringDecrypter decrypter{this, og};
StringDecrypter* decrypter_ptr = m->encp->encrypted ? &decrypter : nullptr;
auto object = QPDFParser(m->file, m->last_object_description, m->tokenizer, decrypter_ptr, this)
.parse(empty, false);
auto object =
QPDFParser(m->file, m->last_object_description, m->tokenizer, decrypter_ptr, this, true)
.parse(empty, false);
if (empty) {
// 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.
@ -1604,7 +1608,7 @@ QPDF::readObjectInStream(std::shared_ptr<InputSource>& input, int obj)
m->last_object_description += " 0";
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);
if (empty) {
// 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;
}
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
QPDF::reserveStream(QPDFObjGen const& og)
{
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
QPDF::getObject(QPDFObjGen const& og)
{
// This method is called by the parser and therefore must not resolve any objects.
if (!isCached(og)) {
m->obj_cache[og] = ObjCache(QPDF_Unresolved::create(this, og), -1, -1);
if (auto it = m->obj_cache.find(og); it != m->obj_cache.end()) {
return {it->second.object};
} 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

View File

@ -2146,7 +2146,8 @@ QPDFObjectHandle::parseContentStream_data(
tokenizer.readToken(input, "content", true);
qpdf_offset_t offset = input->getLastOffset();
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()) {
// EOF
break;
@ -2205,7 +2206,8 @@ QPDFObjectHandle::parse(
StringDecrypter* decrypter,
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

View File

@ -71,7 +71,7 @@ QPDFOutlineDocumentHelper::resolveNamedDest(QPDFObjectHandle name)
m->dest_dict = qpdf.getRoot().getKey("/Dests");
}
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()) {
if (!m->names_dest) {
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 gen = QIntC::to_int(int_buffer[(int_count) % 2]);
if (!(id < 1 || gen < 0 || gen >= 65535)) {
// This action has the desirable side effect of causing dangling references
// (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));
add(QPDF::ParseGuard::getObject(context, id, gen, parse_pdf));
} else {
QTC::TC("qpdf", "QPDFParser invalid objgen");
addNull();

View File

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

View File

@ -3,15 +3,15 @@
#include <qpdf/JSON_writer.hh>
#include <qpdf/QPDFObject_private.hh>
QPDF_Null::QPDF_Null() :
QPDFValue(::ot_null, "null")
QPDF_Null::QPDF_Null(QPDF* qpdf, QPDFObjGen og) :
QPDFValue(::ot_null, "null", qpdf, og)
{
}
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>

View File

@ -240,11 +240,6 @@ class QPDF::JSONReactor: public JSON::Reactor
descr(std::make_shared<QPDFValue::Description>(
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;
void dictionaryStart() override;
@ -272,10 +267,10 @@ class QPDF::JSONReactor: public JSON::Reactor
struct StackFrame
{
StackFrame(state_e state) :
state(state){};
state(state) {};
StackFrame(state_e state, QPDFObjectHandle&& object) :
state(state),
object(object){};
object(object) {};
state_e state;
QPDFObjectHandle object;
};
@ -305,7 +300,6 @@ class QPDF::JSONReactor: public JSON::Reactor
bool saw_data{false};
bool saw_datafile{false};
bool this_stream_needs_data{false};
std::set<QPDFObjGen> reserved;
std::vector<StackFrame> stack;
QPDFObjectHandle next_obj;
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()) {
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)) {
this->cur_object = key;
if (setNextStateIfDictionary(key, value, st_object_top)) {
next_obj = pdf.reserveObjectIfNotExists(QPDFObjGen(obj, gen));
next_obj = pdf.getObjectForJSON(obj, gen);
}
} else {
QTC::TC("qpdf", "QPDF_json bad object key");
@ -767,7 +751,7 @@ QPDF::JSONReactor::makeObject(JSON const& value)
int gen = 0;
std::string str;
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)) {
result = QPDFObjectHandle::newUnicodeString(str);
} else if (is_binary_string(str_v, str)) {

View File

@ -16,14 +16,16 @@ class QPDFParser
std::string const& object_description,
QPDFTokenizer& tokenizer,
QPDFObjectHandle::StringDecrypter* decrypter,
QPDF* context) :
QPDF* context,
bool parse_pdf) :
input(input),
object_description(object_description),
tokenizer(tokenizer),
decrypter(decrypter),
context(context),
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;
@ -76,6 +78,8 @@ class QPDFParser
QPDFObjectHandle::StringDecrypter* decrypter;
QPDF* context;
std::shared_ptr<QPDFValue::Description> description;
bool parse_pdf;
std::vector<StackFrame> stack;
StackFrame* frame;
// Number of recent bad tokens.

View File

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

View File

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

View File

@ -90,17 +90,17 @@ main()
obj = QPDF_Array::create({10, "null"_qpdf.getObj()}, true);
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);
assert(b.at(3).isNull());
assert(b.at(8).isNull());
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 d = b.copy(false);
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(d->unparse() == "[ null null null null null 5 0 R null [ 0 1 2 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 3 0 R null [ 0 1 2 3 ] null null ]");
try {
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 trailer 0
QPDF_json ignore unknown key in stream 0
QPDF_json non-trivial null reserved 0
QPDF_json data and datafile 0
QPDF_json no stream data in update mode 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 (object 7 0, offset 10000): expected n n obj
WARNING: dangling-bad-xref.pdf: Attempting to reconstruct cross-reference table
new object: 13 0 R
new object: 12 0 R
all objects
1 0 R
2 0 R
@ -10,10 +10,6 @@ all objects
5 0 R
6 0 R
7 0 R
8 0 R
9 0 R
10 0 R
11 0 R
12 0 R
13 0 R
test 53 done

View File

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

View File

@ -7,5 +7,5 @@
/nesting is direct
/strings is direct
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

View File

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

View File

@ -5,7 +5,7 @@
item 2 is direct
item 3 is indirect
item 4 is direct
item 5 is indirect
item 5 is direct
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

View File

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

View File

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

View File

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

View File

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

View File

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