1 //========================================================================
5 // This file is licensed under the GPLv2 or later
7 // Copyright 2013, 2014 Igalia S.L.
8 // Copyright 2014 Fabio D'Urso <fabiodurso@hotmail.it>
10 //========================================================================
12 #ifdef USE_GCC_PRAGMAS
16 #include "goo/GooString.h"
17 #include "StructTreeRoot.h"
18 #include "StructElement.h"
26 StructTreeRoot::StructTreeRoot(PDFDoc
*docA
, Dict
*structTreeRootDict
):
30 assert(structTreeRootDict
);
31 parse(structTreeRootDict
);
34 StructTreeRoot::~StructTreeRoot()
36 for (ElemPtrArray::iterator i
= elements
.begin(); i
!= elements
.end(); ++i
)
42 void StructTreeRoot::parse(Dict
*root
)
44 // The RoleMap/ClassMap dictionaries are needed by all the parsing
45 // functions, which will resolve the custom names to canonical
47 root
->lookup("RoleMap", &roleMap
);
48 root
->lookup("ClassMap", &classMap
);
50 // ParentTree (optional). If present, it must be a number tree,
51 // otherwise it is not possible to map stream objects to their
52 // corresponsing structure element. Here only the references are
53 // loaded into the array, the pointers to the StructElements will
54 // be filled-in later when parsing them.
56 if (root
->lookup("ParentTree", &obj
)->isDict()) {
58 if (obj
.dictLookup("Nums", &nums
)->isArray()) {
59 if (nums
.arrayGetLength() % 2 == 0) {
60 parentTree
.resize(nums
.arrayGetLength() / 2);
61 // Index numbers in even positions, references in odd ones
62 for (int i
= 0; i
< nums
.arrayGetLength(); i
+= 2) {
65 if (!nums
.arrayGet(i
, &index
)->isInt()) {
66 error(errSyntaxError
, -1, "Nums item at position {0:d} is wrong type ({1:s})", i
, index
.getTypeName());
70 if (index
.getInt() < 0) {
71 error(errSyntaxError
, -1, "Nums item at position {0:d} is invalid value ({1:d})", i
, index
.getInt());
76 const unsigned idx
= index
.getInt();
77 if (nums
.arrayGetNF(i
+ 1, &value
)->isRef()) {
78 parentTree
[idx
].resize(1);
79 parentTree
[idx
][0].ref
= value
.getRef();
80 } else if (nums
.arrayGet(i
+ 1, &value
)->isArray()) {
81 parentTree
[idx
].resize(value
.arrayGetLength());
82 for (int j
= 0; j
< value
.arrayGetLength(); j
++) {
84 if (value
.arrayGetNF(j
, &itemvalue
)->isRef())
85 parentTree
[idx
][j
].ref
= itemvalue
.getRef();
87 error(errSyntaxError
, -1, "Nums array item at position {0:d}/{1:d} is invalid type ({2:s})", i
, j
, itemvalue
.getTypeName());
91 error(errSyntaxError
, -1, "Nums item at position {0:d} is wrong type ({1:s})", i
+ 1, value
.getTypeName());
98 error(errSyntaxError
, -1, "Nums array length is not a even ({0:d})", nums
.arrayGetLength());
101 error(errSyntaxError
, -1, "Nums object is wrong type ({0:s})", nums
.getTypeName());
107 std::set
<int> seenElements
;
109 // Parse the children StructElements
110 const GBool marked
= doc
->getCatalog()->getMarkInfo() & Catalog::markInfoMarked
;
112 if (root
->lookup("K", &kids
)->isArray()) {
113 if (marked
&& kids
.arrayGetLength() > 1) {
114 error(errSyntaxWarning
, -1, "K in StructTreeRoot has more than one children in a tagged PDF");
116 for (int i
= 0; i
< kids
.arrayGetLength(); i
++) {
118 kids
.arrayGetNF(i
, &ref
);
120 seenElements
.insert(ref
.getRefNum());
122 if (kids
.arrayGet(i
, &obj
)->isDict()) {
123 StructElement
*child
= new StructElement(obj
.getDict(), this, NULL
, seenElements
);
125 if (marked
&& !(child
->getType() == StructElement::Document
||
126 child
->getType() == StructElement::Part
||
127 child
->getType() == StructElement::Art
||
128 child
->getType() == StructElement::Div
)) {
129 error(errSyntaxWarning
, -1, "StructTreeRoot element of tagged PDF is wrong type ({0:s})", child
->getTypeName());
133 parentTreeAdd(ref
.getRef(), child
);
136 error(errSyntaxWarning
, -1, "StructTreeRoot element could not be parsed");
140 error(errSyntaxWarning
, -1, "K has a child of wrong type ({0:s})", obj
.getTypeName());
145 } else if (kids
.isDict()) {
147 error(errSyntaxWarning
, -1, "K has a child of wrong type for a tagged PDF ({0:s})", kids
.getTypeName());
149 StructElement
*child
= new StructElement(kids
.getDict(), this, NULL
, seenElements
);
153 if (root
->lookupNF("K", &ref
)->isRef())
154 parentTreeAdd(ref
.getRef(), child
);
157 error(errSyntaxWarning
, -1, "StructTreeRoot element could not be parsed");
160 } else if (!kids
.isNull()) {
161 error(errSyntaxWarning
, -1, "K in StructTreeRoot is wrong type ({0:s})", kids
.getTypeName());
167 void StructTreeRoot::parentTreeAdd(const Ref
&objectRef
, StructElement
*element
)
169 for (std::vector
< std::vector
<Parent
> >::iterator i
= parentTree
.begin(); i
!= parentTree
.end(); ++i
) {
170 for (std::vector
<Parent
>::iterator j
= i
->begin(); j
!= i
->end(); ++j
) {
171 if (j
->ref
.num
== objectRef
.num
&& j
->ref
.gen
== objectRef
.gen
)
172 j
->element
= element
;