Add type cast definitions for CPDF_Dictionary.
[pdfium.git] / core / src / fpdfapi / fpdf_parser / fpdf_parser_document.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_module.h"
9
10
11 CPDF_Document::CPDF_Document(CPDF_Parser* pParser)
12     : CPDF_IndirectObjects(pParser) {
13   ASSERT(pParser != NULL);
14   m_pRootDict = NULL;
15   m_pInfoDict = NULL;
16   m_bLinearized = FALSE;
17   m_dwFirstPageNo = 0;
18   m_dwFirstPageObjNum = 0;
19   m_pDocPage = CPDF_ModuleMgr::Get()->GetPageModule()->CreateDocData(this);
20   m_pDocRender = CPDF_ModuleMgr::Get()->GetRenderModule()->CreateDocData(this);
21 }
22 CPDF_DocPageData* CPDF_Document::GetValidatePageData() {
23   if (m_pDocPage) {
24     return m_pDocPage;
25   }
26   m_pDocPage = CPDF_ModuleMgr::Get()->GetPageModule()->CreateDocData(this);
27   return m_pDocPage;
28 }
29 CPDF_DocRenderData* CPDF_Document::GetValidateRenderData() {
30   if (m_pDocRender) {
31     return m_pDocRender;
32   }
33   m_pDocRender = CPDF_ModuleMgr::Get()->GetRenderModule()->CreateDocData(this);
34   return m_pDocRender;
35 }
36 void CPDF_Document::LoadDoc() {
37   m_LastObjNum = m_pParser->GetLastObjNum();
38   CPDF_Object* pRootObj = GetIndirectObject(m_pParser->GetRootObjNum());
39   if (pRootObj == NULL) {
40     return;
41   }
42   m_pRootDict = pRootObj->GetDict();
43   if (m_pRootDict == NULL) {
44     return;
45   }
46   CPDF_Object* pInfoObj = GetIndirectObject(m_pParser->GetInfoObjNum());
47   if (pInfoObj) {
48     m_pInfoDict = pInfoObj->GetDict();
49   }
50   CPDF_Array* pIDArray = m_pParser->GetIDArray();
51   if (pIDArray) {
52     m_ID1 = pIDArray->GetString(0);
53     m_ID2 = pIDArray->GetString(1);
54   }
55   m_PageList.SetSize(_GetPageCount());
56 }
57 void CPDF_Document::LoadAsynDoc(CPDF_Dictionary* pLinearized) {
58   m_bLinearized = TRUE;
59   m_LastObjNum = m_pParser->GetLastObjNum();
60   CPDF_Object* indirectObj = GetIndirectObject(m_pParser->GetRootObjNum());
61   m_pRootDict = indirectObj ? indirectObj->GetDict() : NULL;
62   if (m_pRootDict == NULL) {
63     return;
64   }
65   indirectObj = GetIndirectObject(m_pParser->GetInfoObjNum());
66   m_pInfoDict = indirectObj ? indirectObj->GetDict() : NULL;
67   CPDF_Array* pIDArray = m_pParser->GetIDArray();
68   if (pIDArray) {
69     m_ID1 = pIDArray->GetString(0);
70     m_ID2 = pIDArray->GetString(1);
71   }
72   FX_DWORD dwPageCount = 0;
73   CPDF_Object* pCount = pLinearized->GetElement(FX_BSTRC("N"));
74   if (pCount && pCount->GetType() == PDFOBJ_NUMBER) {
75     dwPageCount = pCount->GetInteger();
76   }
77   m_PageList.SetSize(dwPageCount);
78   CPDF_Object* pNo = pLinearized->GetElement(FX_BSTRC("P"));
79   if (pNo && pNo->GetType() == PDFOBJ_NUMBER) {
80     m_dwFirstPageNo = pNo->GetInteger();
81   }
82   CPDF_Object* pObjNum = pLinearized->GetElement(FX_BSTRC("O"));
83   if (pObjNum && pObjNum->GetType() == PDFOBJ_NUMBER) {
84     m_dwFirstPageObjNum = pObjNum->GetInteger();
85   }
86 }
87 void CPDF_Document::LoadPages() {
88   m_PageList.SetSize(_GetPageCount());
89 }
90 CPDF_Document::~CPDF_Document() {
91   if (m_pDocPage) {
92     CPDF_ModuleMgr::Get()->GetPageModule()->ReleaseDoc(this);
93     CPDF_ModuleMgr::Get()->GetPageModule()->ClearStockFont(this);
94   }
95   if (m_pDocRender) {
96     CPDF_ModuleMgr::Get()->GetRenderModule()->DestroyDocData(m_pDocRender);
97   }
98 }
99 #define FX_MAX_PAGE_LEVEL 1024
100 CPDF_Dictionary* CPDF_Document::_FindPDFPage(CPDF_Dictionary* pPages,
101                                              int iPage,
102                                              int nPagesToGo,
103                                              int level) {
104   CPDF_Array* pKidList = pPages->GetArray(FX_BSTRC("Kids"));
105   if (pKidList == NULL) {
106     if (nPagesToGo == 0) {
107       return pPages;
108     }
109     return NULL;
110   }
111   if (level >= FX_MAX_PAGE_LEVEL) {
112     return NULL;
113   }
114   int nKids = pKidList->GetCount();
115   for (int i = 0; i < nKids; i++) {
116     CPDF_Dictionary* pKid = pKidList->GetDict(i);
117     if (pKid == NULL) {
118       nPagesToGo--;
119       continue;
120     }
121     if (pKid == pPages) {
122       continue;
123     }
124     if (!pKid->KeyExist(FX_BSTRC("Kids"))) {
125       if (nPagesToGo == 0) {
126         return pKid;
127       }
128       m_PageList.SetAt(iPage - nPagesToGo, pKid->GetObjNum());
129       nPagesToGo--;
130     } else {
131       int nPages = pKid->GetInteger(FX_BSTRC("Count"));
132       if (nPagesToGo < nPages) {
133         return _FindPDFPage(pKid, iPage, nPagesToGo, level + 1);
134       }
135       nPagesToGo -= nPages;
136     }
137   }
138   return NULL;
139 }
140
141 CPDF_Dictionary* CPDF_Document::GetPage(int iPage) {
142   if (iPage < 0 || iPage >= m_PageList.GetSize())
143     return nullptr;
144
145   if (m_bLinearized && (iPage == (int)m_dwFirstPageNo)) {
146     if (CPDF_Dictionary* pDict =
147             ToDictionary(GetIndirectObject(m_dwFirstPageObjNum)))
148       return pDict;
149   }
150
151   int objnum = m_PageList.GetAt(iPage);
152   if (objnum) {
153     if (CPDF_Dictionary* pDict = ToDictionary(GetIndirectObject(objnum)))
154       return pDict;
155   }
156
157   CPDF_Dictionary* pRoot = GetRoot();
158   if (!pRoot)
159     return nullptr;
160
161   CPDF_Dictionary* pPages = pRoot->GetDict(FX_BSTRC("Pages"));
162   if (!pPages)
163     return nullptr;
164
165   CPDF_Dictionary* pPage = _FindPDFPage(pPages, iPage, iPage, 0);
166   if (!pPage)
167     return nullptr;
168
169   m_PageList.SetAt(iPage, pPage->GetObjNum());
170   return pPage;
171 }
172
173 int CPDF_Document::_FindPageIndex(CPDF_Dictionary* pNode,
174                                   FX_DWORD& skip_count,
175                                   FX_DWORD objnum,
176                                   int& index,
177                                   int level) {
178   if (pNode->KeyExist(FX_BSTRC("Kids"))) {
179     CPDF_Array* pKidList = pNode->GetArray(FX_BSTRC("Kids"));
180     if (pKidList == NULL) {
181       return -1;
182     }
183     if (level >= FX_MAX_PAGE_LEVEL) {
184       return -1;
185     }
186     FX_DWORD count = pNode->GetInteger(FX_BSTRC("Count"));
187     if (count <= skip_count) {
188       skip_count -= count;
189       index += count;
190       return -1;
191     }
192     if (count && count == pKidList->GetCount()) {
193       for (FX_DWORD i = 0; i < count; i++) {
194         CPDF_Object* pKid = pKidList->GetElement(i);
195         if (pKid && pKid->GetType() == PDFOBJ_REFERENCE) {
196           if (((CPDF_Reference*)pKid)->GetRefObjNum() == objnum) {
197             m_PageList.SetAt(index + i, objnum);
198             return index + i;
199           }
200         }
201       }
202     }
203     for (FX_DWORD i = 0; i < pKidList->GetCount(); i++) {
204       CPDF_Dictionary* pKid = pKidList->GetDict(i);
205       if (pKid == NULL) {
206         continue;
207       }
208       if (pKid == pNode) {
209         continue;
210       }
211       int found_index =
212           _FindPageIndex(pKid, skip_count, objnum, index, level + 1);
213       if (found_index >= 0) {
214         return found_index;
215       }
216     }
217   } else {
218     if (objnum == pNode->GetObjNum()) {
219       return index;
220     }
221     if (skip_count) {
222       skip_count--;
223     }
224     index++;
225   }
226   return -1;
227 }
228 int CPDF_Document::GetPageIndex(FX_DWORD objnum) {
229   FX_DWORD nPages = m_PageList.GetSize();
230   FX_DWORD skip_count = 0;
231   FX_BOOL bSkipped = FALSE;
232   for (FX_DWORD i = 0; i < nPages; i++) {
233     FX_DWORD objnum1 = m_PageList.GetAt(i);
234     if (objnum1 == objnum) {
235       return i;
236     }
237     if (!bSkipped && objnum1 == 0) {
238       skip_count = i;
239       bSkipped = TRUE;
240     }
241   }
242   CPDF_Dictionary* pRoot = GetRoot();
243   if (pRoot == NULL) {
244     return -1;
245   }
246   CPDF_Dictionary* pPages = pRoot->GetDict(FX_BSTRC("Pages"));
247   if (pPages == NULL) {
248     return -1;
249   }
250   int index = 0;
251   return _FindPageIndex(pPages, skip_count, objnum, index);
252 }
253 int CPDF_Document::GetPageCount() const {
254   return m_PageList.GetSize();
255 }
256 static int _CountPages(CPDF_Dictionary* pPages, int level) {
257   if (level > 128) {
258     return 0;
259   }
260   int count = pPages->GetInteger(FX_BSTRC("Count"));
261   if (count > 0 && count < FPDF_PAGE_MAX_NUM) {
262     return count;
263   }
264   CPDF_Array* pKidList = pPages->GetArray(FX_BSTRC("Kids"));
265   if (pKidList == NULL) {
266     return 0;
267   }
268   count = 0;
269   for (FX_DWORD i = 0; i < pKidList->GetCount(); i++) {
270     CPDF_Dictionary* pKid = pKidList->GetDict(i);
271     if (pKid == NULL) {
272       continue;
273     }
274     if (!pKid->KeyExist(FX_BSTRC("Kids"))) {
275       count++;
276     } else {
277       count += _CountPages(pKid, level + 1);
278     }
279   }
280   pPages->SetAtInteger(FX_BSTRC("Count"), count);
281   return count;
282 }
283 int CPDF_Document::_GetPageCount() const {
284   CPDF_Dictionary* pRoot = GetRoot();
285   if (pRoot == NULL) {
286     return 0;
287   }
288   CPDF_Dictionary* pPages = pRoot->GetDict(FX_BSTRC("Pages"));
289   if (pPages == NULL) {
290     return 0;
291   }
292   if (!pPages->KeyExist(FX_BSTRC("Kids"))) {
293     return 1;
294   }
295   return _CountPages(pPages, 0);
296 }
297 FX_BOOL CPDF_Document::IsContentUsedElsewhere(FX_DWORD objnum,
298                                               CPDF_Dictionary* pThisPageDict) {
299   for (int i = 0; i < m_PageList.GetSize(); i++) {
300     CPDF_Dictionary* pPageDict = GetPage(i);
301     if (pPageDict == pThisPageDict) {
302       continue;
303     }
304     CPDF_Object* pContents =
305         pPageDict ? pPageDict->GetElement(FX_BSTRC("Contents")) : NULL;
306     if (pContents == NULL) {
307       continue;
308     }
309     if (pContents->GetDirectType() == PDFOBJ_ARRAY) {
310       CPDF_Array* pArray = (CPDF_Array*)pContents->GetDirect();
311       for (FX_DWORD j = 0; j < pArray->GetCount(); j++) {
312         CPDF_Object* pRef = pArray->GetElement(j);
313         if (pRef == NULL || pRef->GetType() != PDFOBJ_REFERENCE) {
314           continue;
315         }
316         if (((CPDF_Reference*)pRef)->GetRefObjNum() == objnum) {
317           return TRUE;
318         }
319       }
320     } else if (pContents->GetObjNum() == objnum) {
321       return TRUE;
322     }
323   }
324   return FALSE;
325 }
326 FX_DWORD CPDF_Document::GetUserPermissions(FX_BOOL bCheckRevision) const {
327   if (m_pParser == NULL) {
328     return (FX_DWORD)-1;
329   }
330   return m_pParser->GetPermissions(bCheckRevision);
331 }
332 FX_BOOL CPDF_Document::IsOwner() const {
333   if (m_pParser == NULL) {
334     return TRUE;
335   }
336   return m_pParser->IsOwner();
337 }
338 FX_BOOL CPDF_Document::IsFormStream(FX_DWORD objnum, FX_BOOL& bForm) const {
339   {
340     CPDF_Object* pObj;
341     if (m_IndirectObjs.Lookup((void*)(uintptr_t)objnum, (void*&)pObj)) {
342       bForm = pObj->GetType() == PDFOBJ_STREAM &&
343               ((CPDF_Stream*)pObj)->GetDict()->GetString(FX_BSTRC("Subtype")) ==
344                   FX_BSTRC("Form");
345       return TRUE;
346     }
347   }
348   if (m_pParser == NULL) {
349     bForm = FALSE;
350     return TRUE;
351   }
352   return m_pParser->IsFormStream(objnum, bForm);
353 }
354 void CPDF_Document::ClearPageData() {
355   if (m_pDocPage) {
356     CPDF_ModuleMgr::Get()->GetPageModule()->ClearDoc(this);
357   }
358 }
359 void CPDF_Document::ClearRenderData() {
360   if (m_pDocRender) {
361     CPDF_ModuleMgr::Get()->GetRenderModule()->ClearDocData(m_pDocRender);
362   }
363 }