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