Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cfx_globaldata.cpp
Go to the documentation of this file.
1// Copyright 2014 The PDFium Authors
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 "core/fxcrt/stl_util.h"
13#include "third_party/base/numerics/safe_conversions.h"
14
15namespace {
16
17constexpr size_t kMinGlobalDataBytes = 12;
18constexpr size_t kMaxGlobalDataBytes = 4 * 1024 - 8;
19constexpr uint16_t kMagic = ('X' << 8) | 'F';
20constexpr uint16_t kMaxVersion = 2;
21
22const 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
33CFX_GlobalData* g_pInstance = nullptr;
34
35// Returns true if non-empty, setting sPropName
36bool TrimPropName(ByteString* sPropName) {
37 sPropName->Trim();
38 return sPropName->GetLength() != 0;
39}
40
41void MakeNameTypeString(const ByteString& name,
42 CFX_Value::DataType eType,
43 BinaryBuffer* result) {
44 uint32_t dwNameLen = pdfium::base::checked_cast<uint32_t>(name.GetLength());
45 result->AppendUint32(dwNameLen);
46 result->AppendString(name);
47 result->AppendUint16(static_cast<uint16_t>(eType));
48}
49
50bool MakeByteString(const ByteString& name,
51 const CFX_KeyValue& pData,
52 BinaryBuffer* result) {
53 switch (pData.nType) {
55 MakeNameTypeString(name, pData.nType, result);
56 result->AppendDouble(pData.dData);
57 return true;
58 }
60 MakeNameTypeString(name, pData.nType, result);
61 result->AppendUint16(static_cast<uint16_t>(pData.bData));
62 return true;
63 }
65 MakeNameTypeString(name, pData.nType, result);
66 uint32_t dwDataLen =
67 pdfium::base::checked_cast<uint32_t>(pData.sData.GetLength());
68 result->AppendUint32(dwDataLen);
69 result->AppendString(pData.sData);
70 return true;
71 }
73 MakeNameTypeString(name, pData.nType, result);
74 return true;
75 }
76 // Arrays don't get persisted per JS spec page 484.
78 break;
79 }
80 return false;
81}
82
83} // namespace
84
85// static
87 if (!g_pInstance) {
88 g_pInstance = new CFX_GlobalData(pDelegate);
89 }
90 ++g_pInstance->m_RefCount;
91 return g_pInstance;
92}
93
95 if (--m_RefCount)
96 return false;
97
98 delete g_pInstance;
99 g_pInstance = nullptr;
100 return true;
101}
102
103CFX_GlobalData::CFX_GlobalData(Delegate* pDelegate) : m_pDelegate(pDelegate) {
104 LoadGlobalPersistentVariables();
105}
106
107CFX_GlobalData::~CFX_GlobalData() {
108 SaveGlobalPersisitentVariables();
109}
110
111CFX_GlobalData::iterator CFX_GlobalData::FindGlobalVariable(
112 const ByteString& propname) {
113 for (auto it = m_arrayGlobalData.begin(); it != m_arrayGlobalData.end();
114 ++it) {
115 if ((*it)->data.sKey == propname)
116 return it;
117 }
118 return m_arrayGlobalData.end();
119}
120
122 const ByteString& propname) {
123 auto iter = FindGlobalVariable(propname);
124 return iter != m_arrayGlobalData.end() ? iter->get() : nullptr;
125}
126
127void CFX_GlobalData::SetGlobalVariableNumber(ByteString sPropName,
128 double dData) {
129 if (!TrimPropName(&sPropName))
130 return;
131
132 CFX_GlobalData::Element* pData = GetGlobalVariable(sPropName);
133 if (pData) {
134 pData->data.nType = CFX_Value::DataType::kNumber;
135 pData->data.dData = dData;
136 return;
137 }
138 auto pNewData = std::make_unique<CFX_GlobalData::Element>();
139 pNewData->data.sKey = std::move(sPropName);
140 pNewData->data.nType = CFX_Value::DataType::kNumber;
141 pNewData->data.dData = dData;
142 m_arrayGlobalData.push_back(std::move(pNewData));
143}
144
145void CFX_GlobalData::SetGlobalVariableBoolean(ByteString sPropName,
146 bool bData) {
147 if (!TrimPropName(&sPropName))
148 return;
149
150 CFX_GlobalData::Element* pData = GetGlobalVariable(sPropName);
151 if (pData) {
152 pData->data.nType = CFX_Value::DataType::kBoolean;
153 pData->data.bData = bData;
154 return;
155 }
156 auto pNewData = std::make_unique<CFX_GlobalData::Element>();
157 pNewData->data.sKey = std::move(sPropName);
158 pNewData->data.nType = CFX_Value::DataType::kBoolean;
159 pNewData->data.bData = bData;
160 m_arrayGlobalData.push_back(std::move(pNewData));
161}
162
163void CFX_GlobalData::SetGlobalVariableString(ByteString sPropName,
164 const ByteString& sData) {
165 if (!TrimPropName(&sPropName))
166 return;
167
168 CFX_GlobalData::Element* pData = GetGlobalVariable(sPropName);
169 if (pData) {
170 pData->data.nType = CFX_Value::DataType::kString;
171 pData->data.sData = sData;
172 return;
173 }
174 auto pNewData = std::make_unique<CFX_GlobalData::Element>();
175 pNewData->data.sKey = std::move(sPropName);
176 pNewData->data.nType = CFX_Value::DataType::kString;
177 pNewData->data.sData = sData;
178 m_arrayGlobalData.push_back(std::move(pNewData));
179}
180
182 ByteString sPropName,
183 std::vector<std::unique_ptr<CFX_KeyValue>> array) {
184 if (!TrimPropName(&sPropName))
185 return;
186
187 CFX_GlobalData::Element* pData = GetGlobalVariable(sPropName);
188 if (pData) {
189 pData->data.nType = CFX_Value::DataType::kObject;
190 pData->data.objData = std::move(array);
191 return;
192 }
193 auto pNewData = std::make_unique<CFX_GlobalData::Element>();
194 pNewData->data.sKey = std::move(sPropName);
195 pNewData->data.nType = CFX_Value::DataType::kObject;
196 pNewData->data.objData = std::move(array);
197 m_arrayGlobalData.push_back(std::move(pNewData));
198}
199
200void CFX_GlobalData::SetGlobalVariableNull(ByteString sPropName) {
201 if (!TrimPropName(&sPropName))
202 return;
203
204 CFX_GlobalData::Element* pData = GetGlobalVariable(sPropName);
205 if (pData) {
206 pData->data.nType = CFX_Value::DataType::kNull;
207 return;
208 }
209 auto pNewData = std::make_unique<CFX_GlobalData::Element>();
210 pNewData->data.sKey = std::move(sPropName);
211 pNewData->data.nType = CFX_Value::DataType::kNull;
212 m_arrayGlobalData.push_back(std::move(pNewData));
213}
214
216 bool bPersistent) {
217 if (!TrimPropName(&sPropName))
218 return false;
219
220 CFX_GlobalData::Element* pData = GetGlobalVariable(sPropName);
221 if (!pData)
222 return false;
223
224 pData->bPersistent = bPersistent;
225 return true;
226}
227
228bool CFX_GlobalData::DeleteGlobalVariable(ByteString sPropName) {
229 if (!TrimPropName(&sPropName))
230 return false;
231
232 auto iter = FindGlobalVariable(sPropName);
233 if (iter == m_arrayGlobalData.end())
234 return false;
235
236 m_arrayGlobalData.erase(iter);
237 return true;
238}
239
240int32_t CFX_GlobalData::GetSize() const {
241 return fxcrt::CollectionSize<int32_t>(m_arrayGlobalData);
242}
243
245 if (index < 0 || index >= GetSize())
246 return nullptr;
247 return m_arrayGlobalData[index].get();
248}
249
250bool CFX_GlobalData::LoadGlobalPersistentVariables() {
251 if (!m_pDelegate)
252 return false;
253
254 bool ret;
255 {
256 // Span can't outlive call to BufferDone().
257 absl::optional<pdfium::span<uint8_t>> buffer = m_pDelegate->LoadBuffer();
258 if (!buffer.has_value() || buffer.value().empty())
259 return false;
260
261 ret = LoadGlobalPersistentVariablesFromBuffer(buffer.value());
262 }
263 m_pDelegate->BufferDone();
264 return ret;
265}
266
267bool CFX_GlobalData::LoadGlobalPersistentVariablesFromBuffer(
268 pdfium::span<uint8_t> buffer) {
269 if (buffer.size() < kMinGlobalDataBytes)
270 return false;
271
272 CRYPT_ArcFourCryptBlock(buffer, kRC4KEY);
273
274 uint8_t* p = buffer.data();
275 uint16_t wType = *((uint16_t*)p);
276 p += sizeof(uint16_t);
277 if (wType != kMagic)
278 return false;
279
280 uint16_t wVersion = *((uint16_t*)p);
281 p += sizeof(uint16_t);
282 if (wVersion > kMaxVersion)
283 return false;
284
285 uint32_t dwCount = *((uint32_t*)p);
286 p += sizeof(uint32_t);
287
288 uint32_t dwSize = *((uint32_t*)p);
289 p += sizeof(uint32_t);
290
291 if (dwSize != buffer.size() - sizeof(uint16_t) * 2 - sizeof(uint32_t) * 2)
292 return false;
293
294 for (int32_t i = 0, sz = dwCount; i < sz; i++) {
295 if (p + sizeof(uint32_t) >= buffer.end()) {
296 break;
297 }
298
299 uint32_t dwNameLen = 0;
300 memcpy(&dwNameLen, p, sizeof(uint32_t));
301 p += sizeof(uint32_t);
302 if (p + dwNameLen > buffer.end())
303 break;
304
305 ByteString sEntry = ByteString(p, dwNameLen);
306 p += sizeof(char) * dwNameLen;
307
308 uint16_t wDataType = 0;
309 memcpy(&wDataType, p, sizeof(uint16_t));
310 p += sizeof(uint16_t);
311
312 CFX_Value::DataType eDataType = static_cast<CFX_Value::DataType>(wDataType);
313
314 switch (eDataType) {
316 double dData = 0;
317 switch (wVersion) {
318 case 1: {
319 uint32_t dwData = 0;
320 memcpy(&dwData, p, sizeof(uint32_t));
321 p += sizeof(uint32_t);
322 dData = dwData;
323 } break;
324 case 2: {
325 dData = 0;
326 memcpy(&dData, p, sizeof(double));
327 p += sizeof(double);
328 } break;
329 }
330 SetGlobalVariableNumber(sEntry, dData);
332 } break;
334 uint16_t wData = 0;
335 memcpy(&wData, p, sizeof(uint16_t));
336 p += sizeof(uint16_t);
337 SetGlobalVariableBoolean(sEntry, (bool)(wData == 1));
339 } break;
341 uint32_t dwLength = 0;
342 memcpy(&dwLength, p, sizeof(uint32_t));
343 p += sizeof(uint32_t);
344 if (p + dwLength > buffer.end())
345 break;
346
347 SetGlobalVariableString(sEntry, ByteString(p, dwLength));
349 p += sizeof(char) * dwLength;
350 } break;
354 } break;
356 // Arrays aren't allowed in these buffers, nor are unrecognized tags.
357 return false;
358 }
359 }
360 return true;
361}
362
363bool CFX_GlobalData::SaveGlobalPersisitentVariables() {
364 if (!m_pDelegate)
365 return false;
366
367 uint32_t nCount = 0;
368 BinaryBuffer sData;
369 for (const auto& pElement : m_arrayGlobalData) {
370 if (!pElement->bPersistent)
371 continue;
372
373 BinaryBuffer sElement;
374 if (!MakeByteString(pElement->data.sKey, pElement->data, &sElement))
375 continue;
376
377 if (sData.GetSize() + sElement.GetSize() > kMaxGlobalDataBytes)
378 break;
379
380 sData.AppendSpan(sElement.GetSpan());
381 nCount++;
382 }
383
384 BinaryBuffer sFile;
385 sFile.AppendUint16(kMagic);
386 sFile.AppendUint16(kMaxVersion);
387 sFile.AppendUint32(nCount);
388
389 uint32_t dwSize = pdfium::base::checked_cast<uint32_t>(sData.GetSize());
390 sFile.AppendUint32(dwSize);
391 sFile.AppendSpan(sData.GetSpan());
392
393 CRYPT_ArcFourCryptBlock(sFile.GetMutableSpan(), kRC4KEY);
394 return m_pDelegate->StoreBuffer(sFile.GetSpan());
395}
396
397CFX_GlobalData::Element::Element() = default;
398
399CFX_GlobalData::Element::~Element() = default;
bool SetGlobalVariablePersistent(ByteString propname, bool bPersistent)
Element * GetAt(int index)
void SetGlobalVariableObject(ByteString propname, std::vector< std::unique_ptr< CFX_KeyValue > > array)
void SetGlobalVariableNull(ByteString propname)
void SetGlobalVariableNumber(ByteString propname, double dData)
bool DeleteGlobalVariable(ByteString propname)
static CFX_GlobalData * GetRetainedInstance(Delegate *pDelegate)
void SetGlobalVariableBoolean(ByteString propname, bool bData)
Element * GetGlobalVariable(const ByteString &sPropname)
void SetGlobalVariableString(ByteString propname, const ByteString &sData)
int32_t GetSize() const
double dData
DataType nType
void AppendUint16(uint16_t value)
void AppendSpan(pdfium::span< const uint8_t > span)
pdfium::span< const uint8_t > GetSpan() const
void AppendDouble(double value)
void AppendString(const ByteString &str)
void AppendUint32(uint32_t value)
pdfium::span< uint8_t > GetMutableSpan()