beta-0.89.2
[luatex.git] / source / libs / poppler / poppler-src / poppler / StructTreeRoot.cc
blobe46e3e2838895263232642a91146786b3c9ddb35
1 //========================================================================
2 //
3 // StructTreeRoot.cc
4 //
5 // This file is licensed under the GPLv2 or later
6 //
7 // Copyright 2013, 2014 Igalia S.L.
8 // Copyright 2014 Fabio D'Urso <fabiodurso@hotmail.it>
9 //
10 //========================================================================
12 #ifdef USE_GCC_PRAGMAS
13 #pragma interface
14 #endif
16 #include "goo/GooString.h"
17 #include "StructTreeRoot.h"
18 #include "StructElement.h"
19 #include "PDFDoc.h"
20 #include "Object.h"
21 #include "Dict.h"
22 #include <set>
23 #include <assert.h>
26 StructTreeRoot::StructTreeRoot(PDFDoc *docA, Dict *structTreeRootDict):
27 doc(docA)
29 assert(doc);
30 assert(structTreeRootDict);
31 parse(structTreeRootDict);
34 StructTreeRoot::~StructTreeRoot()
36 for (ElemPtrArray::iterator i = elements.begin(); i != elements.end(); ++i)
37 delete *i;
38 classMap.free();
39 roleMap.free();
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
46 // standard names.
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.
55 Object obj;
56 if (root->lookup("ParentTree", &obj)->isDict()) {
57 Object nums;
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) {
63 Object index, value;
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());
67 index.free();
68 continue;
70 if (index.getInt() < 0) {
71 error(errSyntaxError, -1, "Nums item at position {0:d} is invalid value ({1:d})", i, index.getInt());
72 index.free();
73 continue;
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++) {
83 Object itemvalue;
84 if (value.arrayGetNF(j, &itemvalue)->isRef())
85 parentTree[idx][j].ref = itemvalue.getRef();
86 else
87 error(errSyntaxError, -1, "Nums array item at position {0:d}/{1:d} is invalid type ({2:s})", i, j, itemvalue.getTypeName());
88 itemvalue.free();
90 } else {
91 error(errSyntaxError, -1, "Nums item at position {0:d} is wrong type ({1:s})", i + 1, value.getTypeName());
94 value.free();
95 index.free();
97 } else {
98 error(errSyntaxError, -1, "Nums array length is not a even ({0:d})", nums.arrayGetLength());
100 } else {
101 error(errSyntaxError, -1, "Nums object is wrong type ({0:s})", nums.getTypeName());
103 nums.free();
105 obj.free();
107 std::set<int> seenElements;
109 // Parse the children StructElements
110 const GBool marked = doc->getCatalog()->getMarkInfo() & Catalog::markInfoMarked;
111 Object kids;
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++) {
117 Object obj, ref;
118 kids.arrayGetNF(i, &ref);
119 if (ref.isRef()) {
120 seenElements.insert(ref.getRefNum());
122 if (kids.arrayGet(i, &obj)->isDict()) {
123 StructElement *child = new StructElement(obj.getDict(), this, NULL, seenElements);
124 if (child->isOk()) {
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());
131 appendChild(child);
132 if (ref.isRef()) {
133 parentTreeAdd(ref.getRef(), child);
135 } else {
136 error(errSyntaxWarning, -1, "StructTreeRoot element could not be parsed");
137 delete child;
139 } else {
140 error(errSyntaxWarning, -1, "K has a child of wrong type ({0:s})", obj.getTypeName());
142 obj.free();
143 ref.free();
145 } else if (kids.isDict()) {
146 if (marked) {
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);
150 if (child->isOk()) {
151 appendChild(child);
152 Object ref;
153 if (root->lookupNF("K", &ref)->isRef())
154 parentTreeAdd(ref.getRef(), child);
155 ref.free();
156 } else {
157 error(errSyntaxWarning, -1, "StructTreeRoot element could not be parsed");
158 delete child;
160 } else if (!kids.isNull()) {
161 error(errSyntaxWarning, -1, "K in StructTreeRoot is wrong type ({0:s})", kids.getTypeName());
164 kids.free();
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;