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