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