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