xref: /aosp_15_r20/external/pdfium/fxjs/cfx_globaldata.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
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 
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,BinaryBuffer * result)41 void 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 
MakeByteString(const ByteString & name,const CFX_KeyValue & pData,BinaryBuffer * result)50 bool MakeByteString(const ByteString& name,
51                     const CFX_KeyValue& pData,
52                     BinaryBuffer* result) {
53   switch (pData.nType) {
54     case CFX_Value::DataType::kNumber: {
55       MakeNameTypeString(name, pData.nType, result);
56       result->AppendDouble(pData.dData);
57       return true;
58     }
59     case CFX_Value::DataType::kBoolean: {
60       MakeNameTypeString(name, pData.nType, result);
61       result->AppendUint16(static_cast<uint16_t>(pData.bData));
62       return true;
63     }
64     case CFX_Value::DataType::kString: {
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     }
72     case CFX_Value::DataType::kNull: {
73       MakeNameTypeString(name, pData.nType, result);
74       return true;
75     }
76     // Arrays don't get persisted per JS spec page 484.
77     case CFX_Value::DataType::kObject:
78       break;
79   }
80   return false;
81 }
82 
83 }  // namespace
84 
85 // static
GetRetainedInstance(Delegate * pDelegate)86 CFX_GlobalData* CFX_GlobalData::GetRetainedInstance(Delegate* pDelegate) {
87   if (!g_pInstance) {
88     g_pInstance = new CFX_GlobalData(pDelegate);
89   }
90   ++g_pInstance->m_RefCount;
91   return g_pInstance;
92 }
93 
Release()94 bool CFX_GlobalData::Release() {
95   if (--m_RefCount)
96     return false;
97 
98   delete g_pInstance;
99   g_pInstance = nullptr;
100   return true;
101 }
102 
CFX_GlobalData(Delegate * pDelegate)103 CFX_GlobalData::CFX_GlobalData(Delegate* pDelegate) : m_pDelegate(pDelegate) {
104   LoadGlobalPersistentVariables();
105 }
106 
~CFX_GlobalData()107 CFX_GlobalData::~CFX_GlobalData() {
108   SaveGlobalPersisitentVariables();
109 }
110 
FindGlobalVariable(const ByteString & propname)111 CFX_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 
GetGlobalVariable(const ByteString & propname)121 CFX_GlobalData::Element* CFX_GlobalData::GetGlobalVariable(
122     const ByteString& propname) {
123   auto iter = FindGlobalVariable(propname);
124   return iter != m_arrayGlobalData.end() ? iter->get() : nullptr;
125 }
126 
SetGlobalVariableNumber(ByteString sPropName,double dData)127 void 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 
SetGlobalVariableBoolean(ByteString sPropName,bool bData)145 void 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 
SetGlobalVariableString(ByteString sPropName,const ByteString & sData)163 void 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 
SetGlobalVariableObject(ByteString sPropName,std::vector<std::unique_ptr<CFX_KeyValue>> array)181 void CFX_GlobalData::SetGlobalVariableObject(
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 
SetGlobalVariableNull(ByteString sPropName)200 void 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 
SetGlobalVariablePersistent(ByteString sPropName,bool bPersistent)215 bool CFX_GlobalData::SetGlobalVariablePersistent(ByteString sPropName,
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 
DeleteGlobalVariable(ByteString sPropName)228 bool 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 
GetSize() const240 int32_t CFX_GlobalData::GetSize() const {
241   return fxcrt::CollectionSize<int32_t>(m_arrayGlobalData);
242 }
243 
GetAt(int index)244 CFX_GlobalData::Element* CFX_GlobalData::GetAt(int index) {
245   if (index < 0 || index >= GetSize())
246     return nullptr;
247   return m_arrayGlobalData[index].get();
248 }
249 
LoadGlobalPersistentVariables()250 bool 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 
LoadGlobalPersistentVariablesFromBuffer(pdfium::span<uint8_t> buffer)267 bool 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) {
315       case CFX_Value::DataType::kNumber: {
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);
331         SetGlobalVariablePersistent(sEntry, true);
332       } break;
333       case CFX_Value::DataType::kBoolean: {
334         uint16_t wData = 0;
335         memcpy(&wData, p, sizeof(uint16_t));
336         p += sizeof(uint16_t);
337         SetGlobalVariableBoolean(sEntry, (bool)(wData == 1));
338         SetGlobalVariablePersistent(sEntry, true);
339       } break;
340       case CFX_Value::DataType::kString: {
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));
348         SetGlobalVariablePersistent(sEntry, true);
349         p += sizeof(char) * dwLength;
350       } break;
351       case CFX_Value::DataType::kNull: {
352         SetGlobalVariableNull(sEntry);
353         SetGlobalVariablePersistent(sEntry, true);
354       } break;
355       case CFX_Value::DataType::kObject:
356         // Arrays aren't allowed in these buffers, nor are unrecognized tags.
357         return false;
358     }
359   }
360   return true;
361 }
362 
SaveGlobalPersisitentVariables()363 bool 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 
397 CFX_GlobalData::Element::Element() = default;
398 
399 CFX_GlobalData::Element::~Element() = default;
400