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