• 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 "fxjs/cfx_globaldata.h"
8 
9 #include <utility>
10 
11 #include "core/fdrm/fx_crypt.h"
12 #include "third_party/base/ptr_util.h"
13 #include "third_party/base/stl_util.h"
14 
15 namespace {
16 
17 constexpr size_t kMinGlobalDataBytes = 12;
18 constexpr size_t kMaxGlobalDataBytes = 4 * 1024 - 8;
19 constexpr uint16_t kMagic = ('X' << 8) | 'F';
20 constexpr uint16_t kMaxVersion = 2;
21 
22 const uint8_t kRC4KEY[] = {
23     0x19, 0xa8, 0xe8, 0x01, 0xf6, 0xa8, 0xb6, 0x4d, 0x82, 0x04, 0x45, 0x6d,
24     0xb4, 0xcf, 0xd7, 0x77, 0x67, 0xf9, 0x75, 0x9f, 0xf0, 0xe0, 0x1e, 0x51,
25     0xee, 0x46, 0xfd, 0x0b, 0xc9, 0x93, 0x25, 0x55, 0x4a, 0xee, 0xe0, 0x16,
26     0xd0, 0xdf, 0x8c, 0xfa, 0x2a, 0xa9, 0x49, 0xfd, 0x97, 0x1c, 0x0e, 0x22,
27     0x13, 0x28, 0x7c, 0xaf, 0xc4, 0xfc, 0x9c, 0x12, 0x65, 0x8c, 0x4e, 0x5b,
28     0x04, 0x75, 0x89, 0xc9, 0xb1, 0xed, 0x50, 0xca, 0x96, 0x6f, 0x1a, 0x7a,
29     0xfe, 0x58, 0x5d, 0xec, 0x19, 0x4a, 0xf6, 0x35, 0x6a, 0x97, 0x14, 0x00,
30     0x0e, 0xd0, 0x6b, 0xbb, 0xd5, 0x75, 0x55, 0x8b, 0x6e, 0x6b, 0x19, 0xa0,
31     0xf8, 0x77, 0xd5, 0xa3};
32 
33 CFX_GlobalData* g_pInstance = nullptr;
34 
35 // Returns true if non-empty, setting sPropName
TrimPropName(ByteString * sPropName)36 bool TrimPropName(ByteString* sPropName) {
37   sPropName->Trim();
38   return sPropName->GetLength() != 0;
39 }
40 
MakeNameTypeString(const ByteString & name,CFX_Value::DataType eType,CFX_BinaryBuf * result)41 void MakeNameTypeString(const ByteString& name,
42                         CFX_Value::DataType eType,
43                         CFX_BinaryBuf* result) {
44   uint32_t dwNameLen = (uint32_t)name.GetLength();
45   result->AppendBlock(&dwNameLen, sizeof(uint32_t));
46   result->AppendString(name);
47 
48   uint16_t wType = static_cast<uint16_t>(eType);
49   result->AppendBlock(&wType, sizeof(uint16_t));
50 }
51 
MakeByteString(const ByteString & name,const CFX_KeyValue & pData,CFX_BinaryBuf * result)52 bool MakeByteString(const ByteString& name,
53                     const CFX_KeyValue& pData,
54                     CFX_BinaryBuf* result) {
55   switch (pData.nType) {
56     case CFX_Value::DataType::NUMBER: {
57       MakeNameTypeString(name, pData.nType, result);
58       double dData = pData.dData;
59       result->AppendBlock(&dData, sizeof(double));
60       return true;
61     }
62     case CFX_Value::DataType::BOOLEAN: {
63       MakeNameTypeString(name, pData.nType, result);
64       uint16_t wData = static_cast<uint16_t>(pData.bData);
65       result->AppendBlock(&wData, sizeof(uint16_t));
66       return true;
67     }
68     case CFX_Value::DataType::STRING: {
69       MakeNameTypeString(name, pData.nType, result);
70       uint32_t dwDataLen = (uint32_t)pData.sData.GetLength();
71       result->AppendBlock(&dwDataLen, sizeof(uint32_t));
72       result->AppendString(pData.sData);
73       return true;
74     }
75     case CFX_Value::DataType::NULLOBJ: {
76       MakeNameTypeString(name, pData.nType, result);
77       return true;
78     }
79     // Arrays don't get persisted per JS spec page 484.
80     case CFX_Value::DataType::OBJECT:
81     default:
82       break;
83   }
84   return false;
85 }
86 
87 }  // namespace
88 
89 // static
GetRetainedInstance(Delegate * pDelegate)90 CFX_GlobalData* CFX_GlobalData::GetRetainedInstance(Delegate* pDelegate) {
91   if (!g_pInstance) {
92     g_pInstance = new CFX_GlobalData(pDelegate);
93   }
94   ++g_pInstance->m_RefCount;
95   return g_pInstance;
96 }
97 
Release()98 bool CFX_GlobalData::Release() {
99   if (--m_RefCount)
100     return false;
101 
102   delete g_pInstance;
103   g_pInstance = nullptr;
104   return true;
105 }
106 
CFX_GlobalData(Delegate * pDelegate)107 CFX_GlobalData::CFX_GlobalData(Delegate* pDelegate) : m_pDelegate(pDelegate) {
108   LoadGlobalPersistentVariables();
109 }
110 
~CFX_GlobalData()111 CFX_GlobalData::~CFX_GlobalData() {
112   SaveGlobalPersisitentVariables();
113 }
114 
FindGlobalVariable(const ByteString & propname)115 CFX_GlobalData::iterator CFX_GlobalData::FindGlobalVariable(
116     const ByteString& propname) {
117   for (auto it = m_arrayGlobalData.begin(); it != m_arrayGlobalData.end();
118        ++it) {
119     if ((*it)->data.sKey == propname)
120       return it;
121   }
122   return m_arrayGlobalData.end();
123 }
124 
GetGlobalVariable(const ByteString & propname)125 CFX_GlobalData::Element* CFX_GlobalData::GetGlobalVariable(
126     const ByteString& propname) {
127   auto iter = FindGlobalVariable(propname);
128   return iter != m_arrayGlobalData.end() ? iter->get() : nullptr;
129 }
130 
SetGlobalVariableNumber(ByteString sPropName,double dData)131 void CFX_GlobalData::SetGlobalVariableNumber(ByteString sPropName,
132                                              double dData) {
133   if (!TrimPropName(&sPropName))
134     return;
135 
136   CFX_GlobalData::Element* pData = GetGlobalVariable(sPropName);
137   if (pData) {
138     pData->data.nType = CFX_Value::DataType::NUMBER;
139     pData->data.dData = dData;
140     return;
141   }
142   auto pNewData = pdfium::MakeUnique<CFX_GlobalData::Element>();
143   pNewData->data.sKey = std::move(sPropName);
144   pNewData->data.nType = CFX_Value::DataType::NUMBER;
145   pNewData->data.dData = dData;
146   m_arrayGlobalData.push_back(std::move(pNewData));
147 }
148 
SetGlobalVariableBoolean(ByteString sPropName,bool bData)149 void CFX_GlobalData::SetGlobalVariableBoolean(ByteString sPropName,
150                                               bool bData) {
151   if (!TrimPropName(&sPropName))
152     return;
153 
154   CFX_GlobalData::Element* pData = GetGlobalVariable(sPropName);
155   if (pData) {
156     pData->data.nType = CFX_Value::DataType::BOOLEAN;
157     pData->data.bData = bData;
158     return;
159   }
160   auto pNewData = pdfium::MakeUnique<CFX_GlobalData::Element>();
161   pNewData->data.sKey = std::move(sPropName);
162   pNewData->data.nType = CFX_Value::DataType::BOOLEAN;
163   pNewData->data.bData = bData;
164   m_arrayGlobalData.push_back(std::move(pNewData));
165 }
166 
SetGlobalVariableString(ByteString sPropName,const ByteString & sData)167 void CFX_GlobalData::SetGlobalVariableString(ByteString sPropName,
168                                              const ByteString& sData) {
169   if (!TrimPropName(&sPropName))
170     return;
171 
172   CFX_GlobalData::Element* pData = GetGlobalVariable(sPropName);
173   if (pData) {
174     pData->data.nType = CFX_Value::DataType::STRING;
175     pData->data.sData = sData;
176     return;
177   }
178   auto pNewData = pdfium::MakeUnique<CFX_GlobalData::Element>();
179   pNewData->data.sKey = std::move(sPropName);
180   pNewData->data.nType = CFX_Value::DataType::STRING;
181   pNewData->data.sData = sData;
182   m_arrayGlobalData.push_back(std::move(pNewData));
183 }
184 
SetGlobalVariableObject(ByteString sPropName,std::vector<std::unique_ptr<CFX_KeyValue>> array)185 void CFX_GlobalData::SetGlobalVariableObject(
186     ByteString sPropName,
187     std::vector<std::unique_ptr<CFX_KeyValue>> array) {
188   if (!TrimPropName(&sPropName))
189     return;
190 
191   CFX_GlobalData::Element* pData = GetGlobalVariable(sPropName);
192   if (pData) {
193     pData->data.nType = CFX_Value::DataType::OBJECT;
194     pData->data.objData = std::move(array);
195     return;
196   }
197   auto pNewData = pdfium::MakeUnique<CFX_GlobalData::Element>();
198   pNewData->data.sKey = std::move(sPropName);
199   pNewData->data.nType = CFX_Value::DataType::OBJECT;
200   pNewData->data.objData = std::move(array);
201   m_arrayGlobalData.push_back(std::move(pNewData));
202 }
203 
SetGlobalVariableNull(ByteString sPropName)204 void CFX_GlobalData::SetGlobalVariableNull(ByteString sPropName) {
205   if (!TrimPropName(&sPropName))
206     return;
207 
208   CFX_GlobalData::Element* pData = GetGlobalVariable(sPropName);
209   if (pData) {
210     pData->data.nType = CFX_Value::DataType::NULLOBJ;
211     return;
212   }
213   auto pNewData = pdfium::MakeUnique<CFX_GlobalData::Element>();
214   pNewData->data.sKey = std::move(sPropName);
215   pNewData->data.nType = CFX_Value::DataType::NULLOBJ;
216   m_arrayGlobalData.push_back(std::move(pNewData));
217 }
218 
SetGlobalVariablePersistent(ByteString sPropName,bool bPersistent)219 bool CFX_GlobalData::SetGlobalVariablePersistent(ByteString sPropName,
220                                                  bool bPersistent) {
221   if (!TrimPropName(&sPropName))
222     return false;
223 
224   CFX_GlobalData::Element* pData = GetGlobalVariable(sPropName);
225   if (!pData)
226     return false;
227 
228   pData->bPersistent = bPersistent;
229   return true;
230 }
231 
DeleteGlobalVariable(ByteString sPropName)232 bool CFX_GlobalData::DeleteGlobalVariable(ByteString sPropName) {
233   if (!TrimPropName(&sPropName))
234     return false;
235 
236   auto iter = FindGlobalVariable(sPropName);
237   if (iter == m_arrayGlobalData.end())
238     return false;
239 
240   m_arrayGlobalData.erase(iter);
241   return true;
242 }
243 
GetSize() const244 int32_t CFX_GlobalData::GetSize() const {
245   return pdfium::CollectionSize<int32_t>(m_arrayGlobalData);
246 }
247 
GetAt(int index)248 CFX_GlobalData::Element* CFX_GlobalData::GetAt(int index) {
249   if (index < 0 || index >= GetSize())
250     return nullptr;
251   return m_arrayGlobalData[index].get();
252 }
253 
LoadGlobalPersistentVariables()254 bool CFX_GlobalData::LoadGlobalPersistentVariables() {
255   if (!m_pDelegate)
256     return false;
257 
258   bool ret;
259   {
260     // Span can't outlive call to BufferDone().
261     Optional<pdfium::span<uint8_t>> buffer = m_pDelegate->LoadBuffer();
262     if (!buffer.has_value() || buffer.value().empty())
263       return false;
264 
265     ret = LoadGlobalPersistentVariablesFromBuffer(buffer.value());
266   }
267   m_pDelegate->BufferDone();
268   return ret;
269 }
270 
LoadGlobalPersistentVariablesFromBuffer(pdfium::span<uint8_t> buffer)271 bool CFX_GlobalData::LoadGlobalPersistentVariablesFromBuffer(
272     pdfium::span<uint8_t> buffer) {
273   if (buffer.size() < kMinGlobalDataBytes)
274     return false;
275 
276   CRYPT_ArcFourCryptBlock(buffer, kRC4KEY);
277 
278   uint8_t* p = buffer.data();
279   uint16_t wType = *((uint16_t*)p);
280   p += sizeof(uint16_t);
281   if (wType != kMagic)
282     return false;
283 
284   uint16_t wVersion = *((uint16_t*)p);
285   p += sizeof(uint16_t);
286   if (wVersion > kMaxVersion)
287     return false;
288 
289   uint32_t dwCount = *((uint32_t*)p);
290   p += sizeof(uint32_t);
291 
292   uint32_t dwSize = *((uint32_t*)p);
293   p += sizeof(uint32_t);
294 
295   if (dwSize != buffer.size() - sizeof(uint16_t) * 2 - sizeof(uint32_t) * 2)
296     return false;
297 
298   for (int32_t i = 0, sz = dwCount; i < sz; i++) {
299     if (p > buffer.end())
300       break;
301 
302     uint32_t dwNameLen = *((uint32_t*)p);
303     p += sizeof(uint32_t);
304     if (p + dwNameLen > buffer.end())
305       break;
306 
307     ByteString sEntry = ByteString(p, dwNameLen);
308     p += sizeof(char) * dwNameLen;
309 
310     CFX_Value::DataType wDataType =
311         static_cast<CFX_Value::DataType>(*((uint16_t*)p));
312     p += sizeof(uint16_t);
313 
314     switch (wDataType) {
315       case CFX_Value::DataType::NUMBER: {
316         double dData = 0;
317         switch (wVersion) {
318           case 1: {
319             uint32_t dwData = *((uint32_t*)p);
320             p += sizeof(uint32_t);
321             dData = dwData;
322           } break;
323           case 2: {
324             dData = *((double*)p);
325             p += sizeof(double);
326           } break;
327         }
328         SetGlobalVariableNumber(sEntry, dData);
329         SetGlobalVariablePersistent(sEntry, true);
330       } break;
331       case CFX_Value::DataType::BOOLEAN: {
332         uint16_t wData = *((uint16_t*)p);
333         p += sizeof(uint16_t);
334         SetGlobalVariableBoolean(sEntry, (bool)(wData == 1));
335         SetGlobalVariablePersistent(sEntry, true);
336       } break;
337       case CFX_Value::DataType::STRING: {
338         uint32_t dwLength = *((uint32_t*)p);
339         p += sizeof(uint32_t);
340         if (p + dwLength > buffer.end())
341           break;
342 
343         SetGlobalVariableString(sEntry, ByteString(p, dwLength));
344         SetGlobalVariablePersistent(sEntry, true);
345         p += sizeof(char) * dwLength;
346       } break;
347       case CFX_Value::DataType::NULLOBJ: {
348         SetGlobalVariableNull(sEntry);
349         SetGlobalVariablePersistent(sEntry, true);
350       } break;
351       case CFX_Value::DataType::OBJECT:
352       default:
353         // Arrays aren't allowed in these buffers, nor are unrecoginzed tags.
354         return false;
355     }
356   }
357   return true;
358 }
359 
SaveGlobalPersisitentVariables()360 bool CFX_GlobalData::SaveGlobalPersisitentVariables() {
361   if (!m_pDelegate)
362     return false;
363 
364   uint32_t nCount = 0;
365   CFX_BinaryBuf sData;
366   for (const auto& pElement : m_arrayGlobalData) {
367     if (!pElement->bPersistent)
368       continue;
369 
370     CFX_BinaryBuf sElement;
371     if (!MakeByteString(pElement->data.sKey, pElement->data, &sElement))
372       continue;
373 
374     if (sData.GetSize() + sElement.GetSize() > kMaxGlobalDataBytes)
375       break;
376 
377     sData.AppendSpan(sElement.GetSpan());
378     nCount++;
379   }
380 
381   CFX_BinaryBuf sFile;
382   uint16_t wType = kMagic;
383   uint16_t wVersion = 2;
384   sFile.AppendBlock(&wType, sizeof(uint16_t));
385   sFile.AppendBlock(&wVersion, sizeof(uint16_t));
386   sFile.AppendBlock(&nCount, sizeof(uint32_t));
387 
388   uint32_t dwSize = sData.GetSize();
389   sFile.AppendBlock(&dwSize, sizeof(uint32_t));
390   sFile.AppendSpan(sData.GetSpan());
391 
392   CRYPT_ArcFourCryptBlock(sFile.GetSpan(), kRC4KEY);
393 
394   return m_pDelegate->StoreBuffer({sFile.GetBuffer(), sFile.GetSize()});
395 }
396 
397 CFX_GlobalData::Element::Element() = default;
398 
399 CFX_GlobalData::Element::~Element() = default;
400