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 
CPDF_Document(CPDF_Parser * pParser)10 CPDF_Document::CPDF_Document(CPDF_Parser* pParser) : CPDF_IndirectObjects(pParser)
11 {
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 }
GetValidatePageData()21 CPDF_DocPageData* CPDF_Document::GetValidatePageData()
22 {
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 {
31     if (m_pDocRender) {
32         return m_pDocRender;
33     }
34     m_pDocRender = CPDF_ModuleMgr::Get()->GetRenderModule()->CreateDocData(this);
35     return m_pDocRender;
36 }
LoadDoc()37 void CPDF_Document::LoadDoc()
38 {
39     m_LastObjNum = m_pParser->GetLastObjNum();
40     CPDF_Object* pRootObj = GetIndirectObject(m_pParser->GetRootObjNum());
41     if (pRootObj == NULL) {
42         return;
43     }
44     m_pRootDict = pRootObj->GetDict();
45     if (m_pRootDict == NULL) {
46         return;
47     }
48     CPDF_Object* pInfoObj = GetIndirectObject(m_pParser->GetInfoObjNum());
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 {
61     m_bLinearized = TRUE;
62     m_LastObjNum = m_pParser->GetLastObjNum();
63     CPDF_Object* indirectObj = GetIndirectObject(m_pParser->GetRootObjNum());
64     m_pRootDict = indirectObj ? indirectObj->GetDict() : NULL;
65     if (m_pRootDict == NULL) {
66         return;
67     }
68     indirectObj = GetIndirectObject(m_pParser->GetInfoObjNum());
69     m_pInfoDict = indirectObj ? indirectObj->GetDict() : NULL;
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(FX_BSTRC("N"));
77     if (pCount && pCount->GetType() == PDFOBJ_NUMBER) {
78         dwPageCount = pCount->GetInteger();
79     }
80     m_PageList.SetSize(dwPageCount);
81     CPDF_Object *pNo = pLinearized->GetElement(FX_BSTRC("P"));
82     if (pNo && pNo->GetType() == PDFOBJ_NUMBER) {
83         m_dwFirstPageNo = pNo->GetInteger();
84     }
85     CPDF_Object *pObjNum = pLinearized->GetElement(FX_BSTRC("O"));
86     if (pObjNum && pObjNum->GetType() == PDFOBJ_NUMBER) {
87         m_dwFirstPageObjNum = pObjNum->GetInteger();
88     }
89 }
LoadPages()90 void CPDF_Document::LoadPages()
91 {
92     m_PageList.SetSize(_GetPageCount());
93 }
94 extern void FPDF_TTFaceMapper_ReleaseDoc(CPDF_Document*);
~CPDF_Document()95 CPDF_Document::~CPDF_Document()
96 {
97     if (m_pDocPage) {
98         CPDF_ModuleMgr::Get()->GetPageModule()->ReleaseDoc(this);
99         CPDF_ModuleMgr::Get()->GetPageModule()->ClearStockFont(this);
100     }
101     if (m_pDocRender) {
102         CPDF_ModuleMgr::Get()->GetRenderModule()->DestroyDocData(m_pDocRender);
103     }
104 }
105 #define		FX_MAX_PAGE_LEVEL			1024
_FindPDFPage(CPDF_Dictionary * pPages,int iPage,int nPagesToGo,int level)106 CPDF_Dictionary* CPDF_Document::_FindPDFPage(CPDF_Dictionary* pPages, int iPage, int nPagesToGo, int level)
107 {
108     CPDF_Array* pKidList = pPages->GetArray(FX_BSTRC("Kids"));
109     if (pKidList == NULL) {
110         if (nPagesToGo == 0) {
111             return pPages;
112         }
113         return NULL;
114     }
115     if (level >= FX_MAX_PAGE_LEVEL) {
116         return NULL;
117     }
118     int nKids = pKidList->GetCount();
119     for (int i = 0; i < nKids; i ++) {
120         CPDF_Dictionary* pKid = pKidList->GetDict(i);
121         if (pKid == NULL) {
122             nPagesToGo --;
123             continue;
124         }
125         if (pKid == pPages) {
126             continue;
127         }
128         if (!pKid->KeyExist(FX_BSTRC("Kids"))) {
129             if (nPagesToGo == 0) {
130                 return pKid;
131             }
132             m_PageList.SetAt(iPage - nPagesToGo, pKid->GetObjNum());
133             nPagesToGo --;
134         } else {
135             int nPages = pKid->GetInteger(FX_BSTRC("Count"));
136             if (nPagesToGo < nPages) {
137                 return _FindPDFPage(pKid, iPage, nPagesToGo, level + 1);
138             }
139             nPagesToGo -= nPages;
140         }
141     }
142     return NULL;
143 }
GetPage(int iPage)144 CPDF_Dictionary* CPDF_Document::GetPage(int iPage)
145 {
146     if (iPage < 0 || iPage >= m_PageList.GetSize()) {
147         return NULL;
148     }
149     if (m_bLinearized && (iPage == (int)m_dwFirstPageNo)) {
150         CPDF_Object* pObj = GetIndirectObject(m_dwFirstPageObjNum);
151         if (pObj && pObj->GetType() == PDFOBJ_DICTIONARY) {
152             return (CPDF_Dictionary*)pObj;
153         }
154     }
155     int objnum = m_PageList.GetAt(iPage);
156     if (objnum) {
157         CPDF_Object* pObj = GetIndirectObject(objnum);
158         ASSERT(pObj->GetType() == PDFOBJ_DICTIONARY);
159         return (CPDF_Dictionary*)pObj;
160     }
161     CPDF_Dictionary* pRoot = GetRoot();
162     if (pRoot == NULL) {
163         return NULL;
164     }
165     CPDF_Dictionary* pPages = pRoot->GetDict(FX_BSTRC("Pages"));
166     if (pPages == NULL) {
167         return NULL;
168     }
169     CPDF_Dictionary* pPage = _FindPDFPage(pPages, iPage, iPage, 0);
170     if (pPage == NULL) {
171         return NULL;
172     }
173     m_PageList.SetAt(iPage, pPage->GetObjNum());
174     return pPage;
175 }
_FindPageIndex(CPDF_Dictionary * pNode,FX_DWORD & skip_count,FX_DWORD objnum,int & index,int level)176 int CPDF_Document::_FindPageIndex(CPDF_Dictionary* pNode, FX_DWORD& skip_count, FX_DWORD objnum, int& index, int level)
177 {
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 = _FindPageIndex(pKid, skip_count, objnum, index, level + 1);
212             if (found_index >= 0) {
213                 return found_index;
214             }
215         }
216     } else {
217         if (objnum == pNode->GetObjNum()) {
218             return index;
219         }
220         if (skip_count) {
221             skip_count--;
222         }
223         index ++;
224     }
225     return -1;
226 }
GetPageIndex(FX_DWORD objnum)227 int CPDF_Document::GetPageIndex(FX_DWORD objnum)
228 {
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 }
GetPageCount() const253 int CPDF_Document::GetPageCount() const
254 {
255     return m_PageList.GetSize();
256 }
_CountPages(CPDF_Dictionary * pPages,int level)257 static int _CountPages(CPDF_Dictionary* pPages, int level)
258 {
259     if (level > 128) {
260         return 0;
261     }
262     int count = pPages->GetInteger(FX_BSTRC("Count"));
263     if (count > 0 && count < FPDF_PAGE_MAX_NUM) {
264         return count;
265     }
266     CPDF_Array* pKidList = pPages->GetArray(FX_BSTRC("Kids"));
267     if (pKidList == NULL) {
268         return 0;
269     }
270     count = 0;
271     for (FX_DWORD i = 0; i < pKidList->GetCount(); i ++) {
272         CPDF_Dictionary* pKid = pKidList->GetDict(i);
273         if (pKid == NULL) {
274             continue;
275         }
276         if (!pKid->KeyExist(FX_BSTRC("Kids"))) {
277             count ++;
278         } else {
279             count += _CountPages(pKid, level + 1);
280         }
281     }
282     pPages->SetAtInteger(FX_BSTRC("Count"), count);
283     return count;
284 }
_GetPageCount() const285 int CPDF_Document::_GetPageCount() const
286 {
287     CPDF_Dictionary* pRoot = GetRoot();
288     if (pRoot == NULL) {
289         return 0;
290     }
291     CPDF_Dictionary* pPages = pRoot->GetDict(FX_BSTRC("Pages"));
292     if (pPages == NULL) {
293         return 0;
294     }
295     if (!pPages->KeyExist(FX_BSTRC("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, CPDF_Dictionary* pThisPageDict)
301 {
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 = pPageDict ? pPageDict->GetElement(FX_BSTRC("Contents")) : NULL;
308         if (pContents == NULL) {
309             continue;
310         }
311         if (pContents->GetDirectType() == PDFOBJ_ARRAY) {
312             CPDF_Array* pArray = (CPDF_Array*)pContents->GetDirect();
313             for (FX_DWORD j = 0; j < pArray->GetCount(); j ++) {
314                 CPDF_Object* pRef = pArray->GetElement(j);
315                 if (pRef == NULL || pRef->GetType() != PDFOBJ_REFERENCE) {
316                     continue;
317                 }
318                 if (((CPDF_Reference*) pRef)->GetRefObjNum() == objnum) {
319                     return TRUE;
320                 }
321             }
322         } else if (pContents->GetObjNum() == objnum) {
323             return TRUE;
324         }
325     }
326     return FALSE;
327 }
GetUserPermissions(FX_BOOL bCheckRevision) const328 FX_DWORD CPDF_Document::GetUserPermissions(FX_BOOL bCheckRevision) const
329 {
330     if (m_pParser == NULL) {
331         return (FX_DWORD) - 1;
332     }
333     return m_pParser->GetPermissions(bCheckRevision);
334 }
IsOwner() const335 FX_BOOL CPDF_Document::IsOwner() const
336 {
337     if (m_pParser == NULL) {
338         return TRUE;
339     }
340     return m_pParser->IsOwner();
341 }
IsFormStream(FX_DWORD objnum,FX_BOOL & bForm) const342 FX_BOOL CPDF_Document::IsFormStream(FX_DWORD objnum, FX_BOOL& bForm) const
343 {
344     {
345         CPDF_Object* pObj;
346         if (m_IndirectObjs.Lookup((FX_LPVOID)(FX_UINTPTR)objnum, (FX_LPVOID&)pObj)) {
347             bForm = pObj->GetType() == PDFOBJ_STREAM &&
348                     ((CPDF_Stream*)pObj)->GetDict()->GetString(FX_BSTRC("Subtype")) == FX_BSTRC("Form");
349             return TRUE;
350         }
351     }
352     if (m_pParser == NULL) {
353         bForm = FALSE;
354         return TRUE;
355     }
356     return m_pParser->IsFormStream(objnum, bForm);
357 }
ClearPageData()358 void CPDF_Document::ClearPageData()
359 {
360     if (m_pDocPage) {
361         CPDF_ModuleMgr::Get()->GetPageModule()->ClearDoc(this);
362     }
363 }
ClearRenderData()364 void CPDF_Document::ClearRenderData()
365 {
366     if (m_pDocRender) {
367         CPDF_ModuleMgr::Get()->GetRenderModule()->ClearDocData(m_pDocRender);
368     }
369 }
370