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