66#include < odr/internal/pdf/pdf_document_element.hpp>
77#include < odr/internal/pdf/pdf_file_parser.hpp>
88
9+ #include < functional>
10+ #include < iostream>
911#include < sstream>
1012
1113namespace odr ::internal::pdf {
@@ -27,7 +29,7 @@ pdf::Font *parse_font(DocumentParser &parser, const ObjectReference &reference,
2729 font->object = dictionary;
2830
2931 if (dictionary.has_key (" ToUnicode" )) {
30- auto to_unicode_obj =
32+ IndirectObject to_unicode_obj =
3133 parser.read_object (dictionary[" ToUnicode" ].as_reference ());
3234 std::string stream = parser.read_object_stream (to_unicode_obj);
3335 std::string inflate = crypto::util::zlib_inflate (stream);
@@ -39,26 +41,21 @@ pdf::Font *parse_font(DocumentParser &parser, const ObjectReference &reference,
3941 return font;
4042}
4143
42- pdf::Resources *parse_resources (DocumentParser &parser,
43- const ObjectReference &reference,
44+ pdf::Resources *parse_resources (DocumentParser &parser, const Object &object,
4445 Document &document) {
4546 Resources *resources = document.create_element <Resources>();
4647
47- IndirectObject object = parser.read_object (reference);
48- const Dictionary &dictionary = object.object .as_dictionary ();
48+ Dictionary dictionary = parser.resolve_object_copy (object).as_dictionary ();
4949
5050 resources->type = Type::resources;
51- resources->object_reference = reference;
5251 resources->object = dictionary;
5352
54- if (dictionary[" Font" ].is_reference ()) {
55- Dictionary table = parser. read_object (dictionary[ " Font " ]. as_reference ())
56- . object .as_dictionary ();
57- for (const auto &[key, value] : table ) {
53+ if (! dictionary[" Font" ].is_null ()) {
54+ Dictionary font_table =
55+ parser. resolve_object_copy (dictionary[ " Font " ]) .as_dictionary ();
56+ for (const auto &[key, value] : font_table ) {
5857 resources->font [key] = parse_font (parser, value.as_reference (), document);
5958 }
60- } else {
61- throw std::runtime_error (" problem" );
6259 }
6360
6461 return resources;
@@ -90,12 +87,21 @@ pdf::Page *parse_page(DocumentParser &parser, const ObjectReference &reference,
9087 page->object_reference = reference;
9188 page->object = dictionary;
9289 page->parent = dynamic_cast <Pages *>(parent);
93- page->contents_reference = dictionary[" Contents" ].as_reference ();
94- page->resources =
95- parse_resources (parser, dictionary[" Resources" ].as_reference (), document);
90+ page->resources = parse_resources (parser, dictionary[" Resources" ], document);
91+
92+ if (dictionary[" Contents" ].is_reference ()) {
93+ page->contents_reference = {dictionary[" Contents" ].as_reference ()};
94+ } else {
95+ for (const Object &e : dictionary[" Contents" ].as_array ()) {
96+ page->contents_reference .push_back (e.as_reference ());
97+ }
98+ }
9699
97100 if (dictionary.has_key (" Annots" )) {
98- for (Object annotation : dictionary[" Annots" ].as_array ()) {
101+ // TODO why rvalue not working?
102+ Array annotations =
103+ parser.resolve_object_copy (dictionary[" Annots" ]).as_array ();
104+ for (const Object &annotation : annotations) {
99105 page->annotations .push_back (
100106 parse_annotation (parser, annotation.as_reference (), document));
101107 }
@@ -116,7 +122,7 @@ pdf::Pages *parse_pages(DocumentParser &parser,
116122 pages->object = dictionary;
117123 pages->count = dictionary[" Count" ].as_integer ();
118124
119- for (const auto &kid : dictionary[" Kids" ].as_array ()) {
125+ for (const Object &kid : dictionary[" Kids" ].as_array ()) {
120126 pages->kids .push_back (
121127 parse_page_or_pages (parser, kid.as_reference (), document, pages));
122128 }
@@ -169,10 +175,17 @@ const FileParser &DocumentParser::parser() const { return m_parser; }
169175
170176const Xref &DocumentParser::xref () const { return m_xref; }
171177
172- IndirectObject DocumentParser::read_object (const ObjectReference &reference) {
173- std::uint32_t position = m_xref.table [reference.id ].position ;
178+ const IndirectObject &
179+ DocumentParser::read_object (const ObjectReference &reference) {
180+ if (auto it = m_objects.find (reference); it != std::end (m_objects)) {
181+ return it->second ;
182+ }
183+
184+ std::uint32_t position = m_xref.table .at (reference).position ;
174185 in ().seekg (position);
175- return parser ().read_indirect_object ();
186+ IndirectObject object = parser ().read_indirect_object ();
187+
188+ return m_objects.emplace (reference, std::move (object)).first ->second ;
176189}
177190
178191std::string
@@ -198,15 +211,64 @@ std::string DocumentParser::read_object_stream(const IndirectObject &object) {
198211std::unique_ptr<Document> DocumentParser::parse_document () {
199212 parser ().seek_start_xref ();
200213 StartXref start_xref = parser ().read_start_xref ();
201- in ().seekg (start_xref.start );
202214
203- m_xref = parser ().read_xref ();
204- parser ().parser ().skip_whitespace ();
205- Trailer trailer = parser ().read_trailer ();
215+ std::uint32_t xref_position = start_xref.start ;
216+ std::optional<Trailer> trailer;
217+
218+ while (true ) {
219+ in ().seekg (xref_position);
220+
221+ m_xref.append (parser ().read_xref ());
222+ parser ().parser ().skip_whitespace ();
223+ Trailer new_trailer = parser ().read_trailer ();
224+ if (!trailer) {
225+ trailer = new_trailer;
226+ }
227+
228+ if (new_trailer.dictionary .has_key (" Prev" )) {
229+ xref_position = new_trailer.dictionary [" Prev" ].as_integer ();
230+ continue ;
231+ }
232+
233+ break ;
234+ }
206235
207236 auto document = std::make_unique<Document>();
208- document->catalog = parse_catalog (*this , trailer.root_reference , *document);
237+ document->catalog =
238+ parse_catalog (*this , trailer->root_reference (), *document);
209239 return document;
210240}
211241
242+ void DocumentParser::resolve_object (Object &object) {
243+ if (object.is_reference ()) {
244+ object = read_object (object.as_reference ()).object ;
245+ }
246+ }
247+
248+ void DocumentParser::deep_resolve_object (Object &object) {
249+ if (object.is_reference ()) {
250+ object = read_object (object.as_reference ()).object ;
251+ } else if (object.is_array ()) {
252+ for (Object &e : object.as_array ()) {
253+ deep_resolve_object (e);
254+ }
255+ } else if (object.is_dictionary ()) {
256+ for (auto &[k, v] : object.as_dictionary ()) {
257+ deep_resolve_object (v);
258+ }
259+ }
260+ }
261+
262+ Object DocumentParser::resolve_object_copy (const Object &object) {
263+ Object result = object;
264+ resolve_object (result);
265+ return result;
266+ }
267+
268+ Object DocumentParser::deep_resolve_object_copy (const Object &object) {
269+ Object result = object;
270+ deep_resolve_object (result);
271+ return result;
272+ }
273+
212274} // namespace odr::internal::pdf
0 commit comments