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