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"
9extern FX_LPVOID PDFPreviewInitCache(CPDF_Document* pDoc);
10extern void PDFPreviewClearCache(FX_LPVOID pCache);
11CPDF_Document::CPDF_Document(IPDF_DocParser* pParser) : CPDF_IndirectObjects(pParser)
12{
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}
22CPDF_DocPageData* CPDF_Document::GetValidatePageData()
23{
24    if (m_pDocPage) {
25        return m_pDocPage;
26    }
27    m_pDocPage = CPDF_ModuleMgr::Get()->GetPageModule()->CreateDocData(this);
28    return m_pDocPage;
29}
30CPDF_DocRenderData* CPDF_Document::GetValidateRenderData()
31{
32    if (m_pDocRender) {
33        return m_pDocRender;
34    }
35    m_pDocRender = CPDF_ModuleMgr::Get()->GetRenderModule()->CreateDocData(this);
36    return m_pDocRender;
37}
38void CPDF_Document::LoadDoc()
39{
40    m_LastObjNum = m_pParser->GetLastObjNum();
41    CPDF_Object* pRootObj = GetIndirectObject(m_pParser->GetRootObjNum());
42    if (pRootObj == NULL) {
43        return;
44    }
45    m_pRootDict = pRootObj->GetDict();
46    if (m_pRootDict == NULL) {
47        return;
48    }
49    CPDF_Object* pInfoObj = GetIndirectObject(m_pParser->GetInfoObjNum());
50    if (pInfoObj) {
51        m_pInfoDict = pInfoObj->GetDict();
52    }
53    CPDF_Array* pIDArray = m_pParser->GetIDArray();
54    if (pIDArray) {
55        m_ID1 = pIDArray->GetString(0);
56        m_ID2 = pIDArray->GetString(1);
57    }
58    m_PageList.SetSize(_GetPageCount());
59}
60void CPDF_Document::LoadAsynDoc(CPDF_Dictionary *pLinearized)
61{
62    m_bLinearized = TRUE;
63    m_LastObjNum = m_pParser->GetLastObjNum();
64    m_pRootDict = GetIndirectObject(m_pParser->GetRootObjNum())->GetDict();
65    if (m_pRootDict == NULL) {
66        return;
67    }
68    m_pInfoDict = GetIndirectObject(m_pParser->GetInfoObjNum())->GetDict();
69    CPDF_Array* pIDArray = m_pParser->GetIDArray();
70    if (pIDArray) {
71        m_ID1 = pIDArray->GetString(0);
72        m_ID2 = pIDArray->GetString(1);
73    }
74    FX_DWORD dwPageCount = 0;
75    CPDF_Object *pCount = pLinearized->GetElement(FX_BSTRC("N"));
76    if (pCount && pCount->GetType() == PDFOBJ_NUMBER) {
77        dwPageCount = pCount->GetInteger();
78    }
79    m_PageList.SetSize(dwPageCount);
80    CPDF_Object *pNo = pLinearized->GetElement(FX_BSTRC("P"));
81    if (pNo && pNo->GetType() == PDFOBJ_NUMBER) {
82        m_dwFirstPageNo = pNo->GetInteger();
83    }
84    CPDF_Object *pObjNum = pLinearized->GetElement(FX_BSTRC("O"));
85    if (pObjNum && pObjNum->GetType() == PDFOBJ_NUMBER) {
86        m_dwFirstPageObjNum = pObjNum->GetInteger();
87    }
88}
89void CPDF_Document::LoadPages()
90{
91    m_PageList.SetSize(_GetPageCount());
92}
93extern void FPDF_TTFaceMapper_ReleaseDoc(CPDF_Document*);
94CPDF_Document::~CPDF_Document()
95{
96    if (m_pDocRender) {
97        CPDF_ModuleMgr::Get()->GetRenderModule()->DestroyDocData(m_pDocRender);
98    }
99    if (m_pDocPage) {
100        CPDF_ModuleMgr::Get()->GetPageModule()->ReleaseDoc(this);
101        CPDF_ModuleMgr::Get()->GetPageModule()->ClearStockFont(this);
102    }
103}
104#define		FX_MAX_PAGE_LEVEL			1024
105CPDF_Dictionary* CPDF_Document::_FindPDFPage(CPDF_Dictionary* pPages, int iPage, int nPagesToGo, int level)
106{
107    CPDF_Array* pKidList = pPages->GetArray(FX_BSTRC("Kids"));
108    if (pKidList == NULL) {
109        if (nPagesToGo == 0) {
110            return pPages;
111        }
112        return NULL;
113    }
114    if (level >= FX_MAX_PAGE_LEVEL) {
115        return NULL;
116    }
117    int nKids = pKidList->GetCount();
118    for (int i = 0; i < nKids; i ++) {
119        CPDF_Dictionary* pKid = pKidList->GetDict(i);
120        if (pKid == NULL) {
121            nPagesToGo --;
122            continue;
123        }
124        if (pKid == pPages) {
125            continue;
126        }
127        if (!pKid->KeyExist(FX_BSTRC("Kids"))) {
128            if (nPagesToGo == 0) {
129                return pKid;
130            }
131            m_PageList.SetAt(iPage - nPagesToGo, pKid->GetObjNum());
132            nPagesToGo --;
133        } else {
134            int nPages = pKid->GetInteger(FX_BSTRC("Count"));
135            if (nPagesToGo < nPages) {
136                return _FindPDFPage(pKid, iPage, nPagesToGo, level + 1);
137            }
138            nPagesToGo -= nPages;
139        }
140    }
141    return NULL;
142}
143CPDF_Dictionary* CPDF_Document::GetPage(int iPage)
144{
145    if (iPage < 0 || iPage >= m_PageList.GetSize()) {
146        return NULL;
147    }
148    if (m_bLinearized && (iPage == (int)m_dwFirstPageNo)) {
149        CPDF_Object* pObj = GetIndirectObject(m_dwFirstPageObjNum);
150        if (pObj && pObj->GetType() == PDFOBJ_DICTIONARY) {
151            return (CPDF_Dictionary*)pObj;
152        }
153    }
154    int objnum = m_PageList.GetAt(iPage);
155    if (objnum) {
156        CPDF_Object* pObj = GetIndirectObject(objnum);
157        ASSERT(pObj->GetType() == PDFOBJ_DICTIONARY);
158        return (CPDF_Dictionary*)pObj;
159    }
160    CPDF_Dictionary* pRoot = GetRoot();
161    if (pRoot == NULL) {
162        return NULL;
163    }
164    CPDF_Dictionary* pPages = pRoot->GetDict(FX_BSTRC("Pages"));
165    if (pPages == NULL) {
166        return NULL;
167    }
168    CPDF_Dictionary* pPage = _FindPDFPage(pPages, iPage, iPage, 0);
169    if (pPage == NULL) {
170        return NULL;
171    }
172    m_PageList.SetAt(iPage, pPage->GetObjNum());
173    return pPage;
174}
175int CPDF_Document::_FindPageIndex(CPDF_Dictionary* pNode, FX_DWORD& skip_count, FX_DWORD objnum, int& index, int level)
176{
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                CPDF_Reference* pKid = (CPDF_Reference*)pKidList->GetElement(i);
194                if (pKid && pKid->GetType() == PDFOBJ_REFERENCE) {
195                    if (pKid->GetRefObjNum() == objnum) {
196                        m_PageList.SetAt(index + i, objnum);
197                        return index + i;
198                    }
199                }
200            }
201        }
202        for (FX_DWORD i = 0; i < pKidList->GetCount(); i ++) {
203            CPDF_Dictionary* pKid = pKidList->GetDict(i);
204            if (pKid == NULL) {
205                continue;
206            }
207            if (pKid == pNode) {
208                continue;
209            }
210            int found_index = _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}
226int CPDF_Document::GetPageIndex(FX_DWORD objnum)
227{
228    FX_DWORD nPages = m_PageList.GetSize();
229    FX_DWORD skip_count = 0;
230    FX_BOOL bSkipped = FALSE;
231    for (FX_DWORD i = 0; i < nPages; i ++) {
232        FX_DWORD objnum1 = m_PageList.GetAt(i);
233        if (objnum1 == objnum) {
234            return i;
235        }
236        if (!bSkipped && objnum1 == 0) {
237            skip_count = i;
238            bSkipped = TRUE;
239        }
240    }
241    CPDF_Dictionary* pRoot = GetRoot();
242    if (pRoot == NULL) {
243        return -1;
244    }
245    CPDF_Dictionary* pPages = pRoot->GetDict(FX_BSTRC("Pages"));
246    if (pPages == NULL) {
247        return -1;
248    }
249    int index = 0;
250    return _FindPageIndex(pPages, skip_count, objnum, index);
251}
252int CPDF_Document::GetPageCount() const
253{
254    return m_PageList.GetSize();
255}
256static int _CountPages(CPDF_Dictionary* pPages, int level)
257{
258    if (level > 128) {
259        return 0;
260    }
261    int count = pPages->GetInteger(FX_BSTRC("Count"));
262    if (count > 0 && count < FPDF_PAGE_MAX_NUM) {
263        return count;
264    }
265    CPDF_Array* pKidList = pPages->GetArray(FX_BSTRC("Kids"));
266    if (pKidList == NULL) {
267        return 0;
268    }
269    count = 0;
270    for (FX_DWORD i = 0; i < pKidList->GetCount(); i ++) {
271        CPDF_Dictionary* pKid = pKidList->GetDict(i);
272        if (pKid == NULL) {
273            continue;
274        }
275        if (!pKid->KeyExist(FX_BSTRC("Kids"))) {
276            count ++;
277        } else {
278            count += _CountPages(pKid, level + 1);
279        }
280    }
281    pPages->SetAtInteger(FX_BSTRC("Count"), count);
282    return count;
283}
284int CPDF_Document::_GetPageCount() const
285{
286    CPDF_Dictionary* pRoot = GetRoot();
287    if (pRoot == NULL) {
288        return 0;
289    }
290    CPDF_Dictionary* pPages = pRoot->GetDict(FX_BSTRC("Pages"));
291    if (pPages == NULL) {
292        return 0;
293    }
294    if (!pPages->KeyExist(FX_BSTRC("Kids"))) {
295        return 1;
296    }
297    return _CountPages(pPages, 0);
298}
299static FX_BOOL _EnumPages(CPDF_Dictionary* pPages, IPDF_EnumPageHandler* pHandler)
300{
301    CPDF_Array* pKidList = pPages->GetArray(FX_BSTRC("Kids"));
302    if (pKidList == NULL) {
303        return pHandler->EnumPage(pPages);
304    }
305    for (FX_DWORD i = 0; i < pKidList->GetCount(); i ++) {
306        CPDF_Dictionary* pKid = pKidList->GetDict(i);
307        if (pKid == NULL) {
308            continue;
309        }
310        if (!pKid->KeyExist(FX_BSTRC("Kids"))) {
311            if (!pHandler->EnumPage(pKid)) {
312                return FALSE;
313            }
314        } else {
315            return _EnumPages(pKid, pHandler);
316        }
317    }
318    return TRUE;
319}
320void CPDF_Document::EnumPages(IPDF_EnumPageHandler* pHandler)
321{
322    CPDF_Dictionary* pRoot = GetRoot();
323    if (pRoot == NULL) {
324        return;
325    }
326    CPDF_Dictionary* pPages = pRoot->GetDict(FX_BSTRC("Pages"));
327    if (pPages == NULL) {
328        return;
329    }
330    _EnumPages(pPages, pHandler);
331}
332FX_BOOL CPDF_Document::IsContentUsedElsewhere(FX_DWORD objnum, CPDF_Dictionary* pThisPageDict)
333{
334    for (int i = 0; i < m_PageList.GetSize(); i ++) {
335        CPDF_Dictionary* pPageDict = GetPage(i);
336        if (pPageDict == pThisPageDict) {
337            continue;
338        }
339        CPDF_Object* pContents = pPageDict->GetElement(FX_BSTRC("Contents"));
340        if (pContents == NULL) {
341            continue;
342        }
343        if (pContents->GetDirectType() == PDFOBJ_ARRAY) {
344            CPDF_Array* pArray = (CPDF_Array*)pContents->GetDirect();
345            for (FX_DWORD j = 0; j < pArray->GetCount(); j ++) {
346                CPDF_Reference* pRef = (CPDF_Reference*)pArray->GetElement(j);
347                if (pRef->GetRefObjNum() == objnum) {
348                    return TRUE;
349                }
350            }
351        } else if (pContents->GetObjNum() == objnum) {
352            return TRUE;
353        }
354    }
355    return FALSE;
356}
357FX_DWORD CPDF_Document::GetUserPermissions(FX_BOOL bCheckRevision) const
358{
359    if (m_pParser == NULL) {
360        return (FX_DWORD) - 1;
361    }
362    return m_pParser->GetPermissions(bCheckRevision);
363}
364FX_BOOL CPDF_Document::IsOwner() const
365{
366    if (m_pParser == NULL) {
367        return TRUE;
368    }
369    return m_pParser->IsOwner();
370}
371FX_BOOL CPDF_Document::IsFormStream(FX_DWORD objnum, FX_BOOL& bForm) const
372{
373    {
374        CPDF_Object* pObj;
375        if (m_IndirectObjs.Lookup((FX_LPVOID)(FX_UINTPTR)objnum, (FX_LPVOID&)pObj)) {
376            bForm = pObj->GetType() == PDFOBJ_STREAM &&
377                    ((CPDF_Stream*)pObj)->GetDict()->GetString(FX_BSTRC("Subtype")) == FX_BSTRC("Form");
378            return TRUE;
379        }
380    }
381    if (m_pParser == NULL) {
382        bForm = FALSE;
383        return TRUE;
384    }
385    return m_pParser->IsFormStream(objnum, bForm);
386}
387void CPDF_Document::ClearPageData()
388{
389    if (m_pDocPage) {
390        CPDF_ModuleMgr::Get()->GetPageModule()->ClearDoc(this);
391    }
392}
393void CPDF_Document::ClearRenderData()
394{
395    if (m_pDocRender) {
396        CPDF_ModuleMgr::Get()->GetRenderModule()->ClearDocData(m_pDocRender);
397    }
398}
399