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
10CPDF_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}
21CPDF_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}
29CPDF_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}
37void 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}
59void 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}
90void CPDF_Document::LoadPages()
91{
92    m_PageList.SetSize(_GetPageCount());
93}
94extern void FPDF_TTFaceMapper_ReleaseDoc(CPDF_Document*);
95CPDF_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
106CPDF_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}
144CPDF_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}
176int 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}
227int 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}
253int CPDF_Document::GetPageCount() const
254{
255    return m_PageList.GetSize();
256}
257static 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}
285int 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}
300FX_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}
328FX_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}
335FX_BOOL CPDF_Document::IsOwner() const
336{
337    if (m_pParser == NULL) {
338        return TRUE;
339    }
340    return m_pParser->IsOwner();
341}
342FX_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}
358void CPDF_Document::ClearPageData()
359{
360    if (m_pDocPage) {
361        CPDF_ModuleMgr::Get()->GetPageModule()->ClearDoc(this);
362    }
363}
364void CPDF_Document::ClearRenderData()
365{
366    if (m_pDocRender) {
367        CPDF_ModuleMgr::Get()->GetRenderModule()->ClearDocData(m_pDocRender);
368    }
369}
370