Add type cast definitions for CPDF_Array.
[pdfium.git] / core / src / fpdfdoc / doc_tagged.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "../../include/fpdfapi/fpdf_parser.h"
8 #include "../../include/fpdfapi/fpdf_page.h"
9 #include "../../include/fpdfdoc/fpdf_tagged.h"
10 #include "tagged_int.h"
11 const int nMaxRecursion = 32;
12 static FX_BOOL IsTagged(const CPDF_Document* pDoc) {
13   CPDF_Dictionary* pCatalog = pDoc->GetRoot();
14   CPDF_Dictionary* pMarkInfo = pCatalog->GetDict(FX_BSTRC("MarkInfo"));
15   return pMarkInfo != NULL && pMarkInfo->GetInteger(FX_BSTRC("Marked"));
16 }
17 CPDF_StructTree* CPDF_StructTree::LoadPage(const CPDF_Document* pDoc,
18                                            const CPDF_Dictionary* pPageDict) {
19   if (!IsTagged(pDoc)) {
20     return NULL;
21   }
22   CPDF_StructTreeImpl* pTree = new CPDF_StructTreeImpl(pDoc);
23   pTree->LoadPageTree(pPageDict);
24   return pTree;
25 }
26 CPDF_StructTree* CPDF_StructTree::LoadDoc(const CPDF_Document* pDoc) {
27   if (!IsTagged(pDoc)) {
28     return NULL;
29   }
30   CPDF_StructTreeImpl* pTree = new CPDF_StructTreeImpl(pDoc);
31   pTree->LoadDocTree();
32   return pTree;
33 }
34 CPDF_StructTreeImpl::CPDF_StructTreeImpl(const CPDF_Document* pDoc) {
35   CPDF_Dictionary* pCatalog = pDoc->GetRoot();
36   m_pTreeRoot = pCatalog->GetDict(FX_BSTRC("StructTreeRoot"));
37   if (m_pTreeRoot == NULL) {
38     return;
39   }
40   m_pRoleMap = m_pTreeRoot->GetDict(FX_BSTRC("RoleMap"));
41 }
42 CPDF_StructTreeImpl::~CPDF_StructTreeImpl() {
43   for (int i = 0; i < m_Kids.GetSize(); i++)
44     if (m_Kids[i]) {
45       m_Kids[i]->Release();
46     }
47 }
48 void CPDF_StructTreeImpl::LoadDocTree() {
49   m_pPage = nullptr;
50   if (!m_pTreeRoot)
51     return;
52
53   CPDF_Object* pKids = m_pTreeRoot->GetElementValue(FX_BSTRC("K"));
54   if (!pKids)
55     return;
56   if (CPDF_Dictionary* pDict = pKids->AsDictionary()) {
57     CPDF_StructElementImpl* pStructElementImpl =
58         new CPDF_StructElementImpl(this, nullptr, pDict);
59     m_Kids.Add(pStructElementImpl);
60     return;
61   }
62   CPDF_Array* pArray = pKids->AsArray();
63   if (!pArray)
64     return;
65
66   for (FX_DWORD i = 0; i < pArray->GetCount(); i++) {
67     CPDF_Dictionary* pKid = pArray->GetDict(i);
68     CPDF_StructElementImpl* pStructElementImpl =
69         new CPDF_StructElementImpl(this, nullptr, pKid);
70     m_Kids.Add(pStructElementImpl);
71   }
72 }
73 void CPDF_StructTreeImpl::LoadPageTree(const CPDF_Dictionary* pPageDict) {
74   m_pPage = pPageDict;
75   if (!m_pTreeRoot)
76     return;
77
78   CPDF_Object* pKids = m_pTreeRoot->GetElementValue(FX_BSTRC("K"));
79   if (!pKids)
80     return;
81
82   FX_DWORD dwKids = 0;
83   if (pKids->IsDictionary())
84     dwKids = 1;
85   else if (CPDF_Array* pArray = pKids->AsArray())
86     dwKids = pArray->GetCount();
87   else
88     return;
89
90   FX_DWORD i;
91   m_Kids.SetSize(dwKids);
92   for (i = 0; i < dwKids; i++) {
93     m_Kids[i] = NULL;
94   }
95   CFX_MapPtrToPtr element_map;
96   CPDF_Dictionary* pParentTree = m_pTreeRoot->GetDict(FX_BSTRC("ParentTree"));
97   if (pParentTree == NULL) {
98     return;
99   }
100   CPDF_NumberTree parent_tree(pParentTree);
101   int parents_id = pPageDict->GetInteger(FX_BSTRC("StructParents"), -1);
102   if (parents_id >= 0) {
103     CPDF_Array* pParentArray = ToArray(parent_tree.LookupValue(parents_id));
104     if (!pParentArray)
105       return;
106
107     for (i = 0; i < pParentArray->GetCount(); i++) {
108       CPDF_Dictionary* pParent = pParentArray->GetDict(i);
109       if (pParent == NULL) {
110         continue;
111       }
112       AddPageNode(pParent, element_map);
113     }
114   }
115 }
116 CPDF_StructElementImpl* CPDF_StructTreeImpl::AddPageNode(CPDF_Dictionary* pDict,
117                                                          CFX_MapPtrToPtr& map,
118                                                          int nLevel) {
119   if (nLevel > nMaxRecursion) {
120     return NULL;
121   }
122   CPDF_StructElementImpl* pElement = NULL;
123   if (map.Lookup(pDict, (void*&)pElement)) {
124     return pElement;
125   }
126   pElement = new CPDF_StructElementImpl(this, NULL, pDict);
127   map.SetAt(pDict, pElement);
128   CPDF_Dictionary* pParent = pDict->GetDict(FX_BSTRC("P"));
129   if (pParent == NULL ||
130       pParent->GetString(FX_BSTRC("Type")) == FX_BSTRC("StructTreeRoot")) {
131     if (!AddTopLevelNode(pDict, pElement)) {
132       pElement->Release();
133       map.RemoveKey(pDict);
134     }
135   } else {
136     CPDF_StructElementImpl* pParentElement =
137         AddPageNode(pParent, map, nLevel + 1);
138     FX_BOOL bSave = FALSE;
139     for (int i = 0; i < pParentElement->m_Kids.GetSize(); i++) {
140       if (pParentElement->m_Kids[i].m_Type != CPDF_StructKid::Element) {
141         continue;
142       }
143       if (pParentElement->m_Kids[i].m_Element.m_pDict != pDict) {
144         continue;
145       }
146       pParentElement->m_Kids[i].m_Element.m_pElement = pElement->Retain();
147       bSave = TRUE;
148     }
149     if (!bSave) {
150       pElement->Release();
151       map.RemoveKey(pDict);
152     }
153   }
154   return pElement;
155 }
156 FX_BOOL CPDF_StructTreeImpl::AddTopLevelNode(CPDF_Dictionary* pDict,
157                                              CPDF_StructElementImpl* pElement) {
158   CPDF_Object* pObj = m_pTreeRoot->GetElementValue(FX_BSTRC("K"));
159   if (!pObj) {
160     return FALSE;
161   }
162   if (pObj->IsDictionary()) {
163     if (pObj->GetObjNum() == pDict->GetObjNum()) {
164       if (m_Kids[0]) {
165         m_Kids[0]->Release();
166       }
167       m_Kids[0] = pElement->Retain();
168     } else {
169       return FALSE;
170     }
171   }
172   if (CPDF_Array* pTopKids = pObj->AsArray()) {
173     FX_DWORD i;
174     FX_BOOL bSave = FALSE;
175     for (i = 0; i < pTopKids->GetCount(); i++) {
176       CPDF_Object* pKidRef = pTopKids->GetElement(i);
177       if (!pKidRef || pKidRef->GetType() != PDFOBJ_REFERENCE)
178         continue;
179       if (((CPDF_Reference*)pKidRef)->GetRefObjNum() != pDict->GetObjNum())
180         continue;
181
182       if (m_Kids[i])
183         m_Kids[i]->Release();
184       m_Kids[i] = pElement->Retain();
185       bSave = TRUE;
186     }
187     if (!bSave)
188       return FALSE;
189   }
190   return TRUE;
191 }
192 CPDF_StructElementImpl::CPDF_StructElementImpl(CPDF_StructTreeImpl* pTree,
193                                                CPDF_StructElementImpl* pParent,
194                                                CPDF_Dictionary* pDict)
195     : m_RefCount(0) {
196   m_pTree = pTree;
197   m_pDict = pDict;
198   m_Type = pDict->GetString(FX_BSTRC("S"));
199   if (pTree->m_pRoleMap) {
200     CFX_ByteString mapped = pTree->m_pRoleMap->GetString(m_Type);
201     if (!mapped.IsEmpty()) {
202       m_Type = mapped;
203     }
204   }
205   m_pParent = pParent;
206   LoadKids(pDict);
207 }
208 CPDF_StructElementImpl::~CPDF_StructElementImpl() {
209   for (int i = 0; i < m_Kids.GetSize(); i++) {
210     if (m_Kids[i].m_Type == CPDF_StructKid::Element &&
211         m_Kids[i].m_Element.m_pElement) {
212       ((CPDF_StructElementImpl*)m_Kids[i].m_Element.m_pElement)->Release();
213     }
214   }
215 }
216 CPDF_StructElementImpl* CPDF_StructElementImpl::Retain() {
217   m_RefCount++;
218   return this;
219 }
220 void CPDF_StructElementImpl::Release() {
221   if (--m_RefCount < 1) {
222     delete this;
223   }
224 }
225 void CPDF_StructElementImpl::LoadKids(CPDF_Dictionary* pDict) {
226   CPDF_Object* pObj = pDict->GetElement(FX_BSTRC("Pg"));
227   FX_DWORD PageObjNum = 0;
228   if (pObj && pObj->GetType() == PDFOBJ_REFERENCE)
229     PageObjNum = ((CPDF_Reference*)pObj)->GetRefObjNum();
230
231   CPDF_Object* pKids = pDict->GetElementValue(FX_BSTRC("K"));
232   if (!pKids)
233     return;
234
235   if (CPDF_Array* pArray = pKids->AsArray()) {
236     m_Kids.SetSize(pArray->GetCount());
237     for (FX_DWORD i = 0; i < pArray->GetCount(); i++) {
238       CPDF_Object* pKid = pArray->GetElementValue(i);
239       LoadKid(PageObjNum, pKid, &m_Kids[i]);
240     }
241   } else {
242     m_Kids.SetSize(1);
243     LoadKid(PageObjNum, pKids, &m_Kids[0]);
244   }
245 }
246 void CPDF_StructElementImpl::LoadKid(FX_DWORD PageObjNum,
247                                      CPDF_Object* pKidObj,
248                                      CPDF_StructKid* pKid) {
249   pKid->m_Type = CPDF_StructKid::Invalid;
250   if (!pKidObj)
251     return;
252
253   if (pKidObj->IsNumber()) {
254     if (m_pTree->m_pPage && m_pTree->m_pPage->GetObjNum() != PageObjNum) {
255       return;
256     }
257     pKid->m_Type = CPDF_StructKid::PageContent;
258     pKid->m_PageContent.m_ContentId = pKidObj->GetInteger();
259     pKid->m_PageContent.m_PageObjNum = PageObjNum;
260     return;
261   }
262
263   CPDF_Dictionary* pKidDict = pKidObj->AsDictionary();
264   if (!pKidDict)
265     return;
266
267   CPDF_Object* pPageObj = pKidDict->GetElement(FX_BSTRC("Pg"));
268   if (pPageObj && pPageObj->GetType() == PDFOBJ_REFERENCE) {
269     PageObjNum = ((CPDF_Reference*)pPageObj)->GetRefObjNum();
270   }
271   CFX_ByteString type = pKidDict->GetString(FX_BSTRC("Type"));
272   if (type == FX_BSTRC("MCR")) {
273     if (m_pTree->m_pPage && m_pTree->m_pPage->GetObjNum() != PageObjNum) {
274       return;
275     }
276     pKid->m_Type = CPDF_StructKid::StreamContent;
277     CPDF_Object* pStreamObj = pKidDict->GetElement(FX_BSTRC("Stm"));
278     if (pStreamObj && pStreamObj->GetType() == PDFOBJ_REFERENCE) {
279       pKid->m_StreamContent.m_RefObjNum =
280           ((CPDF_Reference*)pStreamObj)->GetRefObjNum();
281     } else {
282       pKid->m_StreamContent.m_RefObjNum = 0;
283     }
284     pKid->m_StreamContent.m_PageObjNum = PageObjNum;
285     pKid->m_StreamContent.m_ContentId = pKidDict->GetInteger(FX_BSTRC("MCID"));
286   } else if (type == FX_BSTRC("OBJR")) {
287     if (m_pTree->m_pPage && m_pTree->m_pPage->GetObjNum() != PageObjNum) {
288       return;
289     }
290     pKid->m_Type = CPDF_StructKid::Object;
291     CPDF_Object* pObj = pKidDict->GetElement(FX_BSTRC("Obj"));
292     if (pObj && pObj->GetType() == PDFOBJ_REFERENCE) {
293       pKid->m_Object.m_RefObjNum = ((CPDF_Reference*)pObj)->GetRefObjNum();
294     } else {
295       pKid->m_Object.m_RefObjNum = 0;
296     }
297     pKid->m_Object.m_PageObjNum = PageObjNum;
298   } else {
299     pKid->m_Type = CPDF_StructKid::Element;
300     pKid->m_Element.m_pDict = pKidDict;
301     if (m_pTree->m_pPage == NULL) {
302       pKid->m_Element.m_pElement =
303           new CPDF_StructElementImpl(m_pTree, this, pKidDict);
304     } else {
305       pKid->m_Element.m_pElement = NULL;
306     }
307   }
308 }
309 static CPDF_Dictionary* FindAttrDict(CPDF_Object* pAttrs,
310                                      const CFX_ByteStringC& owner,
311                                      FX_FLOAT nLevel = 0.0F) {
312   if (nLevel > nMaxRecursion)
313     return nullptr;
314   if (!pAttrs)
315     return nullptr;
316
317   CPDF_Dictionary* pDict = nullptr;
318   if (pAttrs->IsDictionary()) {
319     pDict = pAttrs->AsDictionary();
320   } else if (pAttrs->GetType() == PDFOBJ_STREAM) {
321     pDict = ((CPDF_Stream*)pAttrs)->GetDict();
322   } else if (CPDF_Array* pArray = pAttrs->AsArray()) {
323     for (FX_DWORD i = 0; i < pArray->GetCount(); i++) {
324       CPDF_Object* pElement = pArray->GetElementValue(i);
325       pDict = FindAttrDict(pElement, owner, nLevel + 1);
326       if (pDict)
327         return pDict;
328     }
329   }
330   if (pDict && pDict->GetString(FX_BSTRC("O")) == owner) {
331     return pDict;
332   }
333   return NULL;
334 }
335 CPDF_Object* CPDF_StructElementImpl::GetAttr(const CFX_ByteStringC& owner,
336                                              const CFX_ByteStringC& name,
337                                              FX_BOOL bInheritable,
338                                              FX_FLOAT fLevel) {
339   if (fLevel > nMaxRecursion) {
340     return NULL;
341   }
342   if (bInheritable) {
343     CPDF_Object* pAttr = GetAttr(owner, name, FALSE);
344     if (pAttr) {
345       return pAttr;
346     }
347     if (m_pParent == NULL) {
348       return NULL;
349     }
350     return m_pParent->GetAttr(owner, name, TRUE, fLevel + 1);
351   }
352   CPDF_Object* pA = m_pDict->GetElementValue(FX_BSTRC("A"));
353   if (pA) {
354     CPDF_Dictionary* pAttrDict = FindAttrDict(pA, owner);
355     if (pAttrDict) {
356       CPDF_Object* pAttr = pAttrDict->GetElementValue(name);
357       if (pAttr) {
358         return pAttr;
359       }
360     }
361   }
362   CPDF_Object* pC = m_pDict->GetElementValue(FX_BSTRC("C"));
363   if (!pC)
364     return nullptr;
365
366   CPDF_Dictionary* pClassMap =
367       m_pTree->m_pTreeRoot->GetDict(FX_BSTRC("ClassMap"));
368   if (!pClassMap)
369     return nullptr;
370
371   if (CPDF_Array* pArray = pC->AsArray()) {
372     for (FX_DWORD i = 0; i < pArray->GetCount(); i++) {
373       CFX_ByteString class_name = pArray->GetString(i);
374       CPDF_Dictionary* pClassDict = pClassMap->GetDict(class_name);
375       if (pClassDict && pClassDict->GetString(FX_BSTRC("O")) == owner)
376         return pClassDict->GetElementValue(name);
377     }
378     return nullptr;
379   }
380   CFX_ByteString class_name = pC->GetString();
381   CPDF_Dictionary* pClassDict = pClassMap->GetDict(class_name);
382   if (pClassDict && pClassDict->GetString(FX_BSTRC("O")) == owner)
383     return pClassDict->GetElementValue(name);
384   return nullptr;
385 }
386 CPDF_Object* CPDF_StructElementImpl::GetAttr(const CFX_ByteStringC& owner,
387                                              const CFX_ByteStringC& name,
388                                              FX_BOOL bInheritable,
389                                              int subindex) {
390   CPDF_Object* pAttr = GetAttr(owner, name, bInheritable);
391   CPDF_Array* pArray = ToArray(pAttr);
392   if (!pArray || subindex == -1)
393     return pAttr;
394
395   if (subindex >= static_cast<int>(pArray->GetCount()))
396     return pAttr;
397   return pArray->GetElementValue(subindex);
398 }
399 CFX_ByteString CPDF_StructElementImpl::GetName(
400     const CFX_ByteStringC& owner,
401     const CFX_ByteStringC& name,
402     const CFX_ByteStringC& default_value,
403     FX_BOOL bInheritable,
404     int subindex) {
405   CPDF_Object* pAttr = GetAttr(owner, name, bInheritable, subindex);
406   if (ToName(pAttr))
407     return pAttr->GetString();
408   return default_value;
409 }
410
411 FX_ARGB CPDF_StructElementImpl::GetColor(const CFX_ByteStringC& owner,
412                                          const CFX_ByteStringC& name,
413                                          FX_ARGB default_value,
414                                          FX_BOOL bInheritable,
415                                          int subindex) {
416   CPDF_Array* pArray = ToArray(GetAttr(owner, name, bInheritable, subindex));
417   if (!pArray)
418     return default_value;
419   return 0xff000000 | ((int)(pArray->GetNumber(0) * 255) << 16) |
420          ((int)(pArray->GetNumber(1) * 255) << 8) |
421          (int)(pArray->GetNumber(2) * 255);
422 }
423 FX_FLOAT CPDF_StructElementImpl::GetNumber(const CFX_ByteStringC& owner,
424                                            const CFX_ByteStringC& name,
425                                            FX_FLOAT default_value,
426                                            FX_BOOL bInheritable,
427                                            int subindex) {
428   CPDF_Object* pAttr = GetAttr(owner, name, bInheritable, subindex);
429   return ToNumber(pAttr) ? pAttr->GetNumber() : default_value;
430 }
431 int CPDF_StructElementImpl::GetInteger(const CFX_ByteStringC& owner,
432                                        const CFX_ByteStringC& name,
433                                        int default_value,
434                                        FX_BOOL bInheritable,
435                                        int subindex) {
436   CPDF_Object* pAttr = GetAttr(owner, name, bInheritable, subindex);
437   return ToNumber(pAttr) ? pAttr->GetInteger() : default_value;
438 }