]>
git.ipfire.org Git - thirdparty/cups.git/blob - pdftops/Catalog.cxx
1 //========================================================================
5 // Copyright 1996-2003 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
26 // This define is used to limit the depth of recursive readPageTree calls
27 // This is needed because the page tree nodes can reference their parents
28 // leaving us in an infinite loop
29 // Most sane pdf documents don't have a call depth higher than 10
30 #define MAX_CALL_DEPTH 1000
32 //------------------------------------------------------------------------
34 //------------------------------------------------------------------------
36 Catalog :: Catalog ( XRef
* xrefA
) {
37 Object catDict
, pagesDict
;
46 numPages
= pagesSize
= 0 ;
49 xref
-> getCatalog (& catDict
);
50 if (! catDict
. isDict ()) {
51 error (- 1 , "Catalog object is wrong type (%s)" , catDict
. getTypeName ());
56 catDict
. dictLookup ( "Pages" , & pagesDict
);
57 // This should really be isDict("Pages"), but I've seen at least one
58 // PDF file where the /Type entry is missing.
59 if (! pagesDict
. isDict ()) {
60 error (- 1 , "Top-level pages object is wrong type (%s)" ,
61 pagesDict
. getTypeName ());
64 pagesDict
. dictLookup ( "Count" , & obj
);
65 // some PDF files actually use real numbers here ("/Count 9.0")
67 error (- 1 , "Page count in top-level pages object is wrong type (%s)" ,
71 pagesSize
= numPages0
= ( int ) obj
. getNum ();
73 pages
= ( Page
**) gmallocn ( pagesSize
, sizeof ( Page
*));
74 pageRefs
= ( Ref
*) gmallocn ( pagesSize
, sizeof ( Ref
));
75 for ( i
= 0 ; i
< pagesSize
; ++ i
) {
80 numPages
= readPageTree ( pagesDict
. getDict (), NULL
, 0 , 0 );
81 if ( numPages
!= numPages0
) {
82 error (- 1 , "Page count in top-level pages object is incorrect" );
86 // read named destination dictionary
87 catDict
. dictLookup ( "Dests" , & dests
);
89 // read root of named destination tree
90 if ( catDict
. dictLookup ( "Names" , & obj
)-> isDict ())
91 obj
. dictLookup ( "Dests" , & nameTree
);
97 if ( catDict
. dictLookup ( "URI" , & obj
)-> isDict ()) {
98 if ( obj
. dictLookup ( "Base" , & obj2
)-> isString ()) {
99 baseURI
= obj2
. getString ()-> copy ();
105 // get the metadata stream
106 catDict
. dictLookup ( "Metadata" , & metadata
);
108 // get the structure tree root
109 catDict
. dictLookup ( "StructTreeRoot" , & structTreeRoot
);
111 // get the outline dictionary
112 catDict
. dictLookup ( "Outlines" , & outline
);
114 // get the AcroForm dictionary
115 catDict
. dictLookup ( "AcroForm" , & acroForm
);
131 Catalog ::~ Catalog () {
135 for ( i
= 0 ; i
< pagesSize
; ++ i
) {
149 structTreeRoot
. free ();
154 GString
* Catalog :: readMetadata () {
160 if (! metadata
. isStream ()) {
163 dict
= metadata
. streamGetDict ();
164 if (! dict
-> lookup ( "Subtype" , & obj
)-> isName ( "XML" )) {
165 error (- 1 , "Unknown Metadata type: '%s'" ,
166 obj
. isName () ? obj
. getName () : "???" );
170 metadata
. streamReset ();
171 while (( c
= metadata
. streamGetChar ()) != EOF
) {
174 metadata
. streamClose ();
178 int Catalog :: readPageTree ( Dict
* pagesDict
, PageAttrs
* attrs
, int start
, int callDepth
) {
182 PageAttrs
* attrs1
, * attrs2
;
186 attrs1
= new PageAttrs ( attrs
, pagesDict
);
187 pagesDict
-> lookup ( "Kids" , & kids
);
188 if (! kids
. isArray ()) {
189 error (- 1 , "Kids object (page %d) is wrong type (%s)" ,
190 start
+ 1 , kids
. getTypeName ());
193 for ( i
= 0 ; i
< kids
. arrayGetLength (); ++ i
) {
194 kids
. arrayGet ( i
, & kid
);
195 if ( kid
. isDict ( "Page" )) {
196 attrs2
= new PageAttrs ( attrs1
, kid
. getDict ());
197 page
= new Page ( xref
, start
+ 1 , kid
. getDict (), attrs2
);
202 if ( start
>= pagesSize
) {
204 pages
= ( Page
**) greallocn ( pages
, pagesSize
, sizeof ( Page
*));
205 pageRefs
= ( Ref
*) greallocn ( pageRefs
, pagesSize
, sizeof ( Ref
));
206 for ( j
= pagesSize
- 32 ; j
< pagesSize
; ++ j
) {
208 pageRefs
[ j
]. num
= - 1 ;
209 pageRefs
[ j
]. gen
= - 1 ;
213 kids
. arrayGetNF ( i
, & kidRef
);
214 if ( kidRef
. isRef ()) {
215 pageRefs
[ start
]. num
= kidRef
. getRefNum ();
216 pageRefs
[ start
]. gen
= kidRef
. getRefGen ();
220 // This should really be isDict("Pages"), but I've seen at least one
221 // PDF file where the /Type entry is missing.
222 } else if ( kid
. isDict ()) {
223 if ( callDepth
> MAX_CALL_DEPTH
) {
224 error (- 1 , "Limit of %d recursive calls reached while reading the page tree. If your document is correct and not a test to try to force a crash, please report a bug." , MAX_CALL_DEPTH
);
226 if (( start
= readPageTree ( kid
. getDict (), attrs1
, start
, callDepth
+ 1 ))
231 error (- 1 , "Kid object (page %d) is wrong type (%s)" ,
232 start
+ 1 , kid
. getTypeName ());
251 int Catalog :: findPage ( int num
, int gen
) {
254 for ( i
= 0 ; i
< numPages
; ++ i
) {
255 if ( pageRefs
[ i
]. num
== num
&& pageRefs
[ i
]. gen
== gen
)
261 LinkDest
* Catalog :: findDest ( GString
* name
) {
266 // try named destination dictionary then name tree
268 if ( dests
. isDict ()) {
269 if (! dests
. dictLookup ( name
-> getCString (), & obj1
)-> isNull ())
274 if (! found
&& nameTree
. isDict ()) {
275 if (! findDestInTree (& nameTree
, name
, & obj1
)-> isNull ())
283 // construct LinkDest
285 if ( obj1
. isArray ()) {
286 dest
= new LinkDest ( obj1
. getArray ());
287 } else if ( obj1
. isDict ()) {
288 if ( obj1
. dictLookup ( "D" , & obj2
)-> isArray ())
289 dest
= new LinkDest ( obj2
. getArray ());
291 error (- 1 , "Bad named destination value" );
294 error (- 1 , "Bad named destination value" );
297 if ( dest
&& ! dest
-> isOk ()) {
305 Object
* Catalog :: findDestInTree ( Object
* tree
, GString
* name
, Object
* obj
) {
307 Object kids
, kid
, limits
, low
, high
;
312 if ( tree
-> dictLookup ( "Names" , & names
)-> isArray ()) {
313 done
= found
= gFalse
;
314 for ( i
= 0 ; ! done
&& i
< names
. arrayGetLength (); i
+= 2 ) {
315 if ( names
. arrayGet ( i
, & name1
)-> isString ()) {
316 cmp
= name
-> cmp ( name1
. getString ());
318 names
. arrayGet ( i
+ 1 , obj
);
321 } else if ( cmp
< 0 ) {
334 // root or intermediate node
336 if ( tree
-> dictLookup ( "Kids" , & kids
)-> isArray ()) {
337 for ( i
= 0 ; ! done
&& i
< kids
. arrayGetLength (); ++ i
) {
338 if ( kids
. arrayGet ( i
, & kid
)-> isDict ()) {
339 if ( kid
. dictLookup ( "Limits" , & limits
)-> isArray ()) {
340 if ( limits
. arrayGet ( 0 , & low
)-> isString () &&
341 name
-> cmp ( low
. getString ()) >= 0 ) {
342 if ( limits
. arrayGet ( 1 , & high
)-> isString () &&
343 name
-> cmp ( high
. getString ()) <= 0 ) {
344 findDestInTree (& kid
, name
, obj
);
358 // name was outside of ranges of all kids