• 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/fpdfdoc/fpdf_doc.h"
8 
FPDFDOC_OCG_FindGroup(const CPDF_Object * pObject,const CPDF_Dictionary * pGroupDict)9 static int32_t FPDFDOC_OCG_FindGroup(const CPDF_Object* pObject,
10                                      const CPDF_Dictionary* pGroupDict) {
11   if (!pObject || !pGroupDict)
12     return -1;
13 
14   if (const CPDF_Array* pArray = pObject->AsArray()) {
15     FX_DWORD dwCount = pArray->GetCount();
16     for (FX_DWORD i = 0; i < dwCount; i++) {
17       if (pArray->GetDict(i) == pGroupDict)
18         return i;
19     }
20     return -1;
21   }
22   return pObject->GetDict() == pGroupDict ? 0 : -1;
23 }
FPDFDOC_OCG_HasIntent(const CPDF_Dictionary * pDict,const CFX_ByteStringC & csElement,const CFX_ByteStringC & csDef="")24 static FX_BOOL FPDFDOC_OCG_HasIntent(const CPDF_Dictionary* pDict,
25                                      const CFX_ByteStringC& csElement,
26                                      const CFX_ByteStringC& csDef = "") {
27   CPDF_Object* pIntent = pDict->GetElementValue("Intent");
28   if (!pIntent) {
29     return csElement == csDef;
30   }
31   CFX_ByteString bsIntent;
32   if (CPDF_Array* pArray = pIntent->AsArray()) {
33     FX_DWORD dwCount = pArray->GetCount();
34     for (FX_DWORD i = 0; i < dwCount; i++) {
35       bsIntent = pArray->GetString(i);
36       if (bsIntent == "All" || bsIntent == csElement)
37         return TRUE;
38     }
39     return FALSE;
40   }
41   bsIntent = pIntent->GetString();
42   return bsIntent == "All" || bsIntent == csElement;
43 }
FPDFDOC_OCG_GetConfig(CPDF_Document * pDoc,const CPDF_Dictionary * pOCGDict,const CFX_ByteStringC & bsState)44 static CPDF_Dictionary* FPDFDOC_OCG_GetConfig(CPDF_Document* pDoc,
45                                               const CPDF_Dictionary* pOCGDict,
46                                               const CFX_ByteStringC& bsState) {
47   FXSYS_assert(pDoc && pOCGDict);
48   CPDF_Dictionary* pOCProperties = pDoc->GetRoot()->GetDict("OCProperties");
49   if (!pOCProperties) {
50     return NULL;
51   }
52   CPDF_Array* pOCGs = pOCProperties->GetArray("OCGs");
53   if (!pOCGs) {
54     return NULL;
55   }
56   if (FPDFDOC_OCG_FindGroup(pOCGs, pOCGDict) < 0) {
57     return NULL;
58   }
59   CPDF_Dictionary* pConfig = pOCProperties->GetDict("D");
60   CPDF_Array* pConfigs = pOCProperties->GetArray("Configs");
61   if (pConfigs) {
62     CPDF_Dictionary* pFind;
63     int32_t iCount = pConfigs->GetCount();
64     for (int32_t i = 0; i < iCount; i++) {
65       pFind = pConfigs->GetDict(i);
66       if (!pFind) {
67         continue;
68       }
69       if (!FPDFDOC_OCG_HasIntent(pFind, "View", "View")) {
70         continue;
71       }
72       pConfig = pFind;
73       break;
74     }
75   }
76   return pConfig;
77 }
FPDFDOC_OCG_GetUsageTypeString(CPDF_OCContext::UsageType eType)78 static CFX_ByteString FPDFDOC_OCG_GetUsageTypeString(
79     CPDF_OCContext::UsageType eType) {
80   CFX_ByteString csState = "View";
81   if (eType == CPDF_OCContext::Design) {
82     csState = "Design";
83   } else if (eType == CPDF_OCContext::Print) {
84     csState = "Print";
85   } else if (eType == CPDF_OCContext::Export) {
86     csState = "Export";
87   }
88   return csState;
89 }
CPDF_OCContext(CPDF_Document * pDoc,UsageType eUsageType)90 CPDF_OCContext::CPDF_OCContext(CPDF_Document* pDoc, UsageType eUsageType) {
91   FXSYS_assert(pDoc);
92   m_pDocument = pDoc;
93   m_eUsageType = eUsageType;
94 }
~CPDF_OCContext()95 CPDF_OCContext::~CPDF_OCContext() {
96   m_OCGStates.clear();
97 }
LoadOCGStateFromConfig(const CFX_ByteStringC & csConfig,const CPDF_Dictionary * pOCGDict,FX_BOOL & bValidConfig) const98 FX_BOOL CPDF_OCContext::LoadOCGStateFromConfig(const CFX_ByteStringC& csConfig,
99                                                const CPDF_Dictionary* pOCGDict,
100                                                FX_BOOL& bValidConfig) const {
101   CPDF_Dictionary* pConfig =
102       FPDFDOC_OCG_GetConfig(m_pDocument, pOCGDict, csConfig);
103   if (!pConfig) {
104     return TRUE;
105   }
106   bValidConfig = TRUE;
107   FX_BOOL bState = pConfig->GetString("BaseState", "ON") != "OFF";
108   CPDF_Array* pArray = pConfig->GetArray("ON");
109   if (pArray) {
110     if (FPDFDOC_OCG_FindGroup(pArray, pOCGDict) >= 0) {
111       bState = TRUE;
112     }
113   }
114   pArray = pConfig->GetArray("OFF");
115   if (pArray) {
116     if (FPDFDOC_OCG_FindGroup(pArray, pOCGDict) >= 0) {
117       bState = FALSE;
118     }
119   }
120   pArray = pConfig->GetArray("AS");
121   if (pArray) {
122     CFX_ByteString csFind = csConfig + "State";
123     int32_t iCount = pArray->GetCount();
124     for (int32_t i = 0; i < iCount; i++) {
125       CPDF_Dictionary* pUsage = pArray->GetDict(i);
126       if (!pUsage) {
127         continue;
128       }
129       if (pUsage->GetString("Event", "View") != csConfig) {
130         continue;
131       }
132       CPDF_Array* pOCGs = pUsage->GetArray("OCGs");
133       if (!pOCGs) {
134         continue;
135       }
136       if (FPDFDOC_OCG_FindGroup(pOCGs, pOCGDict) < 0) {
137         continue;
138       }
139       CPDF_Dictionary* pState = pUsage->GetDict(csConfig);
140       if (!pState) {
141         continue;
142       }
143       bState = pState->GetString(csFind) != "OFF";
144     }
145   }
146   return bState;
147 }
LoadOCGState(const CPDF_Dictionary * pOCGDict) const148 FX_BOOL CPDF_OCContext::LoadOCGState(const CPDF_Dictionary* pOCGDict) const {
149   if (!FPDFDOC_OCG_HasIntent(pOCGDict, "View", "View")) {
150     return TRUE;
151   }
152   CFX_ByteString csState = FPDFDOC_OCG_GetUsageTypeString(m_eUsageType);
153   CPDF_Dictionary* pUsage = pOCGDict->GetDict("Usage");
154   if (pUsage) {
155     CPDF_Dictionary* pState = pUsage->GetDict(csState);
156     if (pState) {
157       CFX_ByteString csFind = csState + "State";
158       if (pState->KeyExist(csFind)) {
159         return pState->GetString(csFind) != "OFF";
160       }
161     }
162     if (csState != "View") {
163       pState = pUsage->GetDict("View");
164       if (pState && pState->KeyExist("ViewState")) {
165         return pState->GetString("ViewState") != "OFF";
166       }
167     }
168   }
169   FX_BOOL bDefValid = FALSE;
170   return LoadOCGStateFromConfig(csState, pOCGDict, bDefValid);
171 }
172 
GetOCGVisible(const CPDF_Dictionary * pOCGDict)173 FX_BOOL CPDF_OCContext::GetOCGVisible(const CPDF_Dictionary* pOCGDict) {
174   if (!pOCGDict)
175     return FALSE;
176 
177   const auto it = m_OCGStates.find(pOCGDict);
178   if (it != m_OCGStates.end())
179     return it->second;
180 
181   FX_BOOL bState = LoadOCGState(pOCGDict);
182   m_OCGStates[pOCGDict] = bState;
183   return bState;
184 }
185 
GetOCGVE(CPDF_Array * pExpression,FX_BOOL bFromConfig,int nLevel)186 FX_BOOL CPDF_OCContext::GetOCGVE(CPDF_Array* pExpression,
187                                  FX_BOOL bFromConfig,
188                                  int nLevel) {
189   if (nLevel > 32) {
190     return FALSE;
191   }
192   if (!pExpression) {
193     return FALSE;
194   }
195   int32_t iCount = pExpression->GetCount();
196   CPDF_Object* pOCGObj;
197   CFX_ByteString csOperator = pExpression->GetString(0);
198   if (csOperator == "Not") {
199     pOCGObj = pExpression->GetElementValue(1);
200     if (!pOCGObj)
201       return FALSE;
202     if (CPDF_Dictionary* pDict = pOCGObj->AsDictionary())
203       return !(bFromConfig ? LoadOCGState(pDict) : GetOCGVisible(pDict));
204     if (CPDF_Array* pArray = pOCGObj->AsArray())
205       return !GetOCGVE(pArray, bFromConfig, nLevel + 1);
206     return FALSE;
207   }
208   if (csOperator == "Or" || csOperator == "And") {
209     FX_BOOL bValue = FALSE;
210     for (int32_t i = 1; i < iCount; i++) {
211       pOCGObj = pExpression->GetElementValue(1);
212       if (!pOCGObj) {
213         continue;
214       }
215       FX_BOOL bItem = FALSE;
216       if (CPDF_Dictionary* pDict = pOCGObj->AsDictionary())
217         bItem = bFromConfig ? LoadOCGState(pDict) : GetOCGVisible(pDict);
218       else if (CPDF_Array* pArray = pOCGObj->AsArray())
219         bItem = GetOCGVE(pArray, bFromConfig, nLevel + 1);
220 
221       if (i == 1) {
222         bValue = bItem;
223       } else {
224         if (csOperator == "Or") {
225           bValue = bValue || bItem;
226         } else {
227           bValue = bValue && bItem;
228         }
229       }
230     }
231     return bValue;
232   }
233   return FALSE;
234 }
LoadOCMDState(const CPDF_Dictionary * pOCMDDict,FX_BOOL bFromConfig)235 FX_BOOL CPDF_OCContext::LoadOCMDState(const CPDF_Dictionary* pOCMDDict,
236                                       FX_BOOL bFromConfig) {
237   CPDF_Array* pVE = pOCMDDict->GetArray("VE");
238   if (pVE) {
239     return GetOCGVE(pVE, bFromConfig);
240   }
241   CFX_ByteString csP = pOCMDDict->GetString("P", "AnyOn");
242   CPDF_Object* pOCGObj = pOCMDDict->GetElementValue("OCGs");
243   if (!pOCGObj)
244     return TRUE;
245   if (const CPDF_Dictionary* pDict = pOCGObj->AsDictionary())
246     return bFromConfig ? LoadOCGState(pDict) : GetOCGVisible(pDict);
247 
248   CPDF_Array* pArray = pOCGObj->AsArray();
249   if (!pArray)
250     return TRUE;
251 
252   FX_BOOL bState = FALSE;
253   if (csP == "AllOn" || csP == "AllOff") {
254     bState = TRUE;
255   }
256   int32_t iCount = pArray->GetCount();
257   for (int32_t i = 0; i < iCount; i++) {
258     FX_BOOL bItem = TRUE;
259     CPDF_Dictionary* pItemDict = pArray->GetDict(i);
260     if (pItemDict)
261       bItem = bFromConfig ? LoadOCGState(pItemDict) : GetOCGVisible(pItemDict);
262 
263     if ((csP == "AnyOn" && bItem) || (csP == "AnyOff" && !bItem))
264       return TRUE;
265     if ((csP == "AllOn" && !bItem) || (csP == "AllOff" && bItem))
266       return FALSE;
267   }
268   return bState;
269 }
CheckOCGVisible(const CPDF_Dictionary * pOCGDict)270 FX_BOOL CPDF_OCContext::CheckOCGVisible(const CPDF_Dictionary* pOCGDict) {
271   if (!pOCGDict) {
272     return TRUE;
273   }
274   CFX_ByteString csType = pOCGDict->GetString("Type", "OCG");
275   if (csType == "OCG") {
276     return GetOCGVisible(pOCGDict);
277   }
278   return LoadOCMDState(pOCGDict, FALSE);
279 }
ResetOCContext()280 void CPDF_OCContext::ResetOCContext() {
281   m_OCGStates.clear();
282 }
283