OLD | NEW |
| (Empty) |
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 "fpdfsdk/src/javascript/JS_GlobalData.h" | |
8 | |
9 #include "core/include/fdrm/fx_crypt.h" | |
10 #include "fpdfsdk/include/javascript/IJavaScript.h" | |
11 | |
12 #define JS_MAXGLOBALDATA (1024 * 4 - 8) | |
13 | |
14 /* --------------------- CJS_GlobalVariableArray --------------------- */ | |
15 | |
16 CJS_GlobalVariableArray::CJS_GlobalVariableArray() {} | |
17 | |
18 CJS_GlobalVariableArray::~CJS_GlobalVariableArray() { | |
19 Empty(); | |
20 } | |
21 | |
22 void CJS_GlobalVariableArray::Copy(const CJS_GlobalVariableArray& array) { | |
23 Empty(); | |
24 for (int i = 0, sz = array.Count(); i < sz; i++) { | |
25 CJS_KeyValue* pOldObjData = array.GetAt(i); | |
26 switch (pOldObjData->nType) { | |
27 case JS_GLOBALDATA_TYPE_NUMBER: { | |
28 CJS_KeyValue* pNewObjData = new CJS_KeyValue; | |
29 pNewObjData->sKey = pOldObjData->sKey; | |
30 pNewObjData->nType = pOldObjData->nType; | |
31 pNewObjData->dData = pOldObjData->dData; | |
32 Add(pNewObjData); | |
33 } break; | |
34 case JS_GLOBALDATA_TYPE_BOOLEAN: { | |
35 CJS_KeyValue* pNewObjData = new CJS_KeyValue; | |
36 pNewObjData->sKey = pOldObjData->sKey; | |
37 pNewObjData->nType = pOldObjData->nType; | |
38 pNewObjData->bData = pOldObjData->bData; | |
39 Add(pNewObjData); | |
40 } break; | |
41 case JS_GLOBALDATA_TYPE_STRING: { | |
42 CJS_KeyValue* pNewObjData = new CJS_KeyValue; | |
43 pNewObjData->sKey = pOldObjData->sKey; | |
44 pNewObjData->nType = pOldObjData->nType; | |
45 pNewObjData->sData = pOldObjData->sData; | |
46 Add(pNewObjData); | |
47 } break; | |
48 case JS_GLOBALDATA_TYPE_OBJECT: { | |
49 CJS_KeyValue* pNewObjData = new CJS_KeyValue; | |
50 pNewObjData->sKey = pOldObjData->sKey; | |
51 pNewObjData->nType = pOldObjData->nType; | |
52 pNewObjData->objData.Copy(pOldObjData->objData); | |
53 Add(pNewObjData); | |
54 } break; | |
55 case JS_GLOBALDATA_TYPE_NULL: { | |
56 CJS_KeyValue* pNewObjData = new CJS_KeyValue; | |
57 pNewObjData->sKey = pOldObjData->sKey; | |
58 pNewObjData->nType = pOldObjData->nType; | |
59 Add(pNewObjData); | |
60 } break; | |
61 } | |
62 } | |
63 } | |
64 | |
65 void CJS_GlobalVariableArray::Add(CJS_KeyValue* p) { | |
66 array.Add(p); | |
67 } | |
68 | |
69 int CJS_GlobalVariableArray::Count() const { | |
70 return array.GetSize(); | |
71 } | |
72 | |
73 CJS_KeyValue* CJS_GlobalVariableArray::GetAt(int index) const { | |
74 return array.GetAt(index); | |
75 } | |
76 | |
77 void CJS_GlobalVariableArray::Empty() { | |
78 for (int i = 0, sz = array.GetSize(); i < sz; i++) | |
79 delete array.GetAt(i); | |
80 array.RemoveAll(); | |
81 } | |
82 | |
83 /* -------------------------- CJS_GlobalData -------------------------- */ | |
84 | |
85 #define READER_JS_GLOBALDATA_FILENAME L"Reader_JsGlobal.Data" | |
86 #define PHANTOM_JS_GLOBALDATA_FILENAME L"Phantom_JsGlobal.Data" | |
87 #define SDK_JS_GLOBALDATA_FILENAME L"SDK_JsGlobal.Data" | |
88 | |
89 static const uint8_t JS_RC4KEY[] = { | |
90 0x19, 0xa8, 0xe8, 0x01, 0xf6, 0xa8, 0xb6, 0x4d, 0x82, 0x04, 0x45, 0x6d, | |
91 0xb4, 0xcf, 0xd7, 0x77, 0x67, 0xf9, 0x75, 0x9f, 0xf0, 0xe0, 0x1e, 0x51, | |
92 0xee, 0x46, 0xfd, 0x0b, 0xc9, 0x93, 0x25, 0x55, 0x4a, 0xee, 0xe0, 0x16, | |
93 0xd0, 0xdf, 0x8c, 0xfa, 0x2a, 0xa9, 0x49, 0xfd, 0x97, 0x1c, 0x0e, 0x22, | |
94 0x13, 0x28, 0x7c, 0xaf, 0xc4, 0xfc, 0x9c, 0x12, 0x65, 0x8c, 0x4e, 0x5b, | |
95 0x04, 0x75, 0x89, 0xc9, 0xb1, 0xed, 0x50, 0xca, 0x96, 0x6f, 0x1a, 0x7a, | |
96 0xfe, 0x58, 0x5d, 0xec, 0x19, 0x4a, 0xf6, 0x35, 0x6a, 0x97, 0x14, 0x00, | |
97 0x0e, 0xd0, 0x6b, 0xbb, 0xd5, 0x75, 0x55, 0x8b, 0x6e, 0x6b, 0x19, 0xa0, | |
98 0xf8, 0x77, 0xd5, 0xa3}; | |
99 | |
100 CJS_GlobalData* CJS_GlobalData::g_Instance = nullptr; | |
101 | |
102 // static | |
103 CJS_GlobalData* CJS_GlobalData::GetRetainedInstance(CPDFDoc_Environment* pApp) { | |
104 if (!g_Instance) { | |
105 g_Instance = new CJS_GlobalData(); | |
106 } | |
107 ++g_Instance->m_RefCount; | |
108 return g_Instance; | |
109 } | |
110 | |
111 void CJS_GlobalData::Release() { | |
112 if (!--m_RefCount) { | |
113 delete g_Instance; | |
114 g_Instance = nullptr; | |
115 } | |
116 } | |
117 | |
118 CJS_GlobalData::CJS_GlobalData() : m_RefCount(0) { | |
119 m_sFilePath += SDK_JS_GLOBALDATA_FILENAME; | |
120 LoadGlobalPersistentVariables(); | |
121 } | |
122 | |
123 CJS_GlobalData::~CJS_GlobalData() { | |
124 SaveGlobalPersisitentVariables(); | |
125 for (int i = 0, sz = m_arrayGlobalData.GetSize(); i < sz; i++) | |
126 delete m_arrayGlobalData.GetAt(i); | |
127 | |
128 m_arrayGlobalData.RemoveAll(); | |
129 } | |
130 | |
131 int CJS_GlobalData::FindGlobalVariable(const FX_CHAR* propname) { | |
132 for (int i = 0, sz = m_arrayGlobalData.GetSize(); i < sz; i++) { | |
133 CJS_GlobalData_Element* pTemp = m_arrayGlobalData.GetAt(i); | |
134 if (pTemp->data.sKey[0] == *propname && pTemp->data.sKey == propname) | |
135 return i; | |
136 } | |
137 return -1; | |
138 } | |
139 | |
140 CJS_GlobalData_Element* CJS_GlobalData::GetGlobalVariable( | |
141 const FX_CHAR* propname) { | |
142 ASSERT(propname); | |
143 | |
144 int nFind = FindGlobalVariable(propname); | |
145 return nFind >= 0 ? m_arrayGlobalData.GetAt(nFind) : nullptr; | |
146 } | |
147 | |
148 void CJS_GlobalData::SetGlobalVariableNumber(const FX_CHAR* propname, | |
149 double dData) { | |
150 ASSERT(propname); | |
151 CFX_ByteString sPropName = propname; | |
152 sPropName.TrimLeft(); | |
153 sPropName.TrimRight(); | |
154 if (sPropName.GetLength() == 0) | |
155 return; | |
156 | |
157 if (CJS_GlobalData_Element* pData = GetGlobalVariable(sPropName)) { | |
158 pData->data.nType = JS_GLOBALDATA_TYPE_NUMBER; | |
159 pData->data.dData = dData; | |
160 } else { | |
161 CJS_GlobalData_Element* pNewData = new CJS_GlobalData_Element; | |
162 pNewData->data.sKey = sPropName; | |
163 pNewData->data.nType = JS_GLOBALDATA_TYPE_NUMBER; | |
164 pNewData->data.dData = dData; | |
165 m_arrayGlobalData.Add(pNewData); | |
166 } | |
167 } | |
168 | |
169 void CJS_GlobalData::SetGlobalVariableBoolean(const FX_CHAR* propname, | |
170 bool bData) { | |
171 ASSERT(propname); | |
172 CFX_ByteString sPropName = propname; | |
173 | |
174 sPropName.TrimLeft(); | |
175 sPropName.TrimRight(); | |
176 | |
177 if (sPropName.GetLength() == 0) | |
178 return; | |
179 | |
180 if (CJS_GlobalData_Element* pData = GetGlobalVariable(sPropName)) { | |
181 pData->data.nType = JS_GLOBALDATA_TYPE_BOOLEAN; | |
182 pData->data.bData = bData; | |
183 } else { | |
184 CJS_GlobalData_Element* pNewData = new CJS_GlobalData_Element; | |
185 pNewData->data.sKey = sPropName; | |
186 pNewData->data.nType = JS_GLOBALDATA_TYPE_BOOLEAN; | |
187 pNewData->data.bData = bData; | |
188 | |
189 m_arrayGlobalData.Add(pNewData); | |
190 } | |
191 } | |
192 | |
193 void CJS_GlobalData::SetGlobalVariableString(const FX_CHAR* propname, | |
194 const CFX_ByteString& sData) { | |
195 ASSERT(propname); | |
196 CFX_ByteString sPropName = propname; | |
197 | |
198 sPropName.TrimLeft(); | |
199 sPropName.TrimRight(); | |
200 | |
201 if (sPropName.GetLength() == 0) | |
202 return; | |
203 | |
204 if (CJS_GlobalData_Element* pData = GetGlobalVariable(sPropName)) { | |
205 pData->data.nType = JS_GLOBALDATA_TYPE_STRING; | |
206 pData->data.sData = sData; | |
207 } else { | |
208 CJS_GlobalData_Element* pNewData = new CJS_GlobalData_Element; | |
209 pNewData->data.sKey = sPropName; | |
210 pNewData->data.nType = JS_GLOBALDATA_TYPE_STRING; | |
211 pNewData->data.sData = sData; | |
212 | |
213 m_arrayGlobalData.Add(pNewData); | |
214 } | |
215 } | |
216 | |
217 void CJS_GlobalData::SetGlobalVariableObject( | |
218 const FX_CHAR* propname, | |
219 const CJS_GlobalVariableArray& array) { | |
220 ASSERT(propname); | |
221 CFX_ByteString sPropName = propname; | |
222 | |
223 sPropName.TrimLeft(); | |
224 sPropName.TrimRight(); | |
225 | |
226 if (sPropName.GetLength() == 0) | |
227 return; | |
228 | |
229 if (CJS_GlobalData_Element* pData = GetGlobalVariable(sPropName)) { | |
230 pData->data.nType = JS_GLOBALDATA_TYPE_OBJECT; | |
231 pData->data.objData.Copy(array); | |
232 } else { | |
233 CJS_GlobalData_Element* pNewData = new CJS_GlobalData_Element; | |
234 pNewData->data.sKey = sPropName; | |
235 pNewData->data.nType = JS_GLOBALDATA_TYPE_OBJECT; | |
236 pNewData->data.objData.Copy(array); | |
237 | |
238 m_arrayGlobalData.Add(pNewData); | |
239 } | |
240 } | |
241 | |
242 void CJS_GlobalData::SetGlobalVariableNull(const FX_CHAR* propname) { | |
243 ASSERT(propname); | |
244 CFX_ByteString sPropName = propname; | |
245 | |
246 sPropName.TrimLeft(); | |
247 sPropName.TrimRight(); | |
248 | |
249 if (sPropName.GetLength() == 0) | |
250 return; | |
251 | |
252 if (CJS_GlobalData_Element* pData = GetGlobalVariable(sPropName)) { | |
253 pData->data.nType = JS_GLOBALDATA_TYPE_NULL; | |
254 } else { | |
255 CJS_GlobalData_Element* pNewData = new CJS_GlobalData_Element; | |
256 pNewData->data.sKey = sPropName; | |
257 pNewData->data.nType = JS_GLOBALDATA_TYPE_NULL; | |
258 | |
259 m_arrayGlobalData.Add(pNewData); | |
260 } | |
261 } | |
262 | |
263 FX_BOOL CJS_GlobalData::SetGlobalVariablePersistent(const FX_CHAR* propname, | |
264 FX_BOOL bPersistent) { | |
265 ASSERT(propname); | |
266 CFX_ByteString sPropName = propname; | |
267 | |
268 sPropName.TrimLeft(); | |
269 sPropName.TrimRight(); | |
270 | |
271 if (sPropName.GetLength() == 0) | |
272 return FALSE; | |
273 | |
274 if (CJS_GlobalData_Element* pData = GetGlobalVariable(sPropName)) { | |
275 pData->bPersistent = bPersistent; | |
276 return TRUE; | |
277 } | |
278 | |
279 return FALSE; | |
280 } | |
281 | |
282 FX_BOOL CJS_GlobalData::DeleteGlobalVariable(const FX_CHAR* propname) { | |
283 ASSERT(propname); | |
284 CFX_ByteString sPropName = propname; | |
285 | |
286 sPropName.TrimLeft(); | |
287 sPropName.TrimRight(); | |
288 | |
289 if (sPropName.GetLength() == 0) | |
290 return FALSE; | |
291 | |
292 int nFind = FindGlobalVariable(sPropName); | |
293 | |
294 if (nFind >= 0) { | |
295 delete m_arrayGlobalData.GetAt(nFind); | |
296 m_arrayGlobalData.RemoveAt(nFind); | |
297 return TRUE; | |
298 } | |
299 | |
300 return FALSE; | |
301 } | |
302 | |
303 int32_t CJS_GlobalData::GetSize() const { | |
304 return m_arrayGlobalData.GetSize(); | |
305 } | |
306 | |
307 CJS_GlobalData_Element* CJS_GlobalData::GetAt(int index) const { | |
308 return m_arrayGlobalData.GetAt(index); | |
309 } | |
310 | |
311 void CJS_GlobalData::LoadGlobalPersistentVariables() { | |
312 uint8_t* pBuffer = NULL; | |
313 int32_t nLength = 0; | |
314 | |
315 LoadFileBuffer(m_sFilePath.c_str(), pBuffer, nLength); | |
316 CRYPT_ArcFourCryptBlock(pBuffer, nLength, JS_RC4KEY, sizeof(JS_RC4KEY)); | |
317 | |
318 if (pBuffer) { | |
319 uint8_t* p = pBuffer; | |
320 FX_WORD wType = *((FX_WORD*)p); | |
321 p += sizeof(FX_WORD); | |
322 | |
323 // FX_WORD wTemp = (FX_WORD)(('X' << 8) | 'F'); | |
324 | |
325 if (wType == (FX_WORD)(('X' << 8) | 'F')) { | |
326 FX_WORD wVersion = *((FX_WORD*)p); | |
327 p += sizeof(FX_WORD); | |
328 | |
329 ASSERT(wVersion <= 2); | |
330 | |
331 FX_DWORD dwCount = *((FX_DWORD*)p); | |
332 p += sizeof(FX_DWORD); | |
333 | |
334 FX_DWORD dwSize = *((FX_DWORD*)p); | |
335 p += sizeof(FX_DWORD); | |
336 | |
337 if (dwSize == nLength - sizeof(FX_WORD) * 2 - sizeof(FX_DWORD) * 2) { | |
338 for (int32_t i = 0, sz = dwCount; i < sz; i++) { | |
339 if (p > pBuffer + nLength) | |
340 break; | |
341 | |
342 FX_DWORD dwNameLen = *((FX_DWORD*)p); | |
343 p += sizeof(FX_DWORD); | |
344 | |
345 if (p + dwNameLen > pBuffer + nLength) | |
346 break; | |
347 | |
348 CFX_ByteString sEntry = CFX_ByteString(p, dwNameLen); | |
349 p += sizeof(char) * dwNameLen; | |
350 | |
351 FX_WORD wDataType = *((FX_WORD*)p); | |
352 p += sizeof(FX_WORD); | |
353 | |
354 switch (wDataType) { | |
355 case JS_GLOBALDATA_TYPE_NUMBER: { | |
356 double dData = 0; | |
357 switch (wVersion) { | |
358 case 1: { | |
359 FX_DWORD dwData = *((FX_DWORD*)p); | |
360 p += sizeof(FX_DWORD); | |
361 dData = dwData; | |
362 } break; | |
363 case 2: { | |
364 dData = *((double*)p); | |
365 p += sizeof(double); | |
366 } break; | |
367 } | |
368 SetGlobalVariableNumber(sEntry, dData); | |
369 SetGlobalVariablePersistent(sEntry, TRUE); | |
370 } break; | |
371 case JS_GLOBALDATA_TYPE_BOOLEAN: { | |
372 FX_WORD wData = *((FX_WORD*)p); | |
373 p += sizeof(FX_WORD); | |
374 SetGlobalVariableBoolean(sEntry, (bool)(wData == 1)); | |
375 SetGlobalVariablePersistent(sEntry, TRUE); | |
376 } break; | |
377 case JS_GLOBALDATA_TYPE_STRING: { | |
378 FX_DWORD dwLength = *((FX_DWORD*)p); | |
379 p += sizeof(FX_DWORD); | |
380 | |
381 if (p + dwLength > pBuffer + nLength) | |
382 break; | |
383 | |
384 SetGlobalVariableString(sEntry, CFX_ByteString(p, dwLength)); | |
385 SetGlobalVariablePersistent(sEntry, TRUE); | |
386 p += sizeof(char) * dwLength; | |
387 } break; | |
388 case JS_GLOBALDATA_TYPE_NULL: { | |
389 SetGlobalVariableNull(sEntry); | |
390 SetGlobalVariablePersistent(sEntry, TRUE); | |
391 } | |
392 } | |
393 } | |
394 } | |
395 } | |
396 FX_Free(pBuffer); | |
397 } | |
398 } | |
399 | |
400 void CJS_GlobalData::SaveGlobalPersisitentVariables() { | |
401 FX_DWORD nCount = 0; | |
402 CFX_BinaryBuf sData; | |
403 | |
404 for (int i = 0, sz = m_arrayGlobalData.GetSize(); i < sz; i++) { | |
405 CJS_GlobalData_Element* pElement = m_arrayGlobalData.GetAt(i); | |
406 if (pElement->bPersistent) { | |
407 CFX_BinaryBuf sElement; | |
408 MakeByteString(pElement->data.sKey, &pElement->data, sElement); | |
409 | |
410 if (sData.GetSize() + sElement.GetSize() > JS_MAXGLOBALDATA) | |
411 break; | |
412 | |
413 sData.AppendBlock(sElement.GetBuffer(), sElement.GetSize()); | |
414 nCount++; | |
415 } | |
416 } | |
417 | |
418 CFX_BinaryBuf sFile; | |
419 | |
420 FX_WORD wType = (FX_WORD)(('X' << 8) | 'F'); | |
421 sFile.AppendBlock(&wType, sizeof(FX_WORD)); | |
422 FX_WORD wVersion = 2; | |
423 sFile.AppendBlock(&wVersion, sizeof(FX_WORD)); | |
424 sFile.AppendBlock(&nCount, sizeof(FX_DWORD)); | |
425 FX_DWORD dwSize = sData.GetSize(); | |
426 sFile.AppendBlock(&dwSize, sizeof(FX_DWORD)); | |
427 | |
428 sFile.AppendBlock(sData.GetBuffer(), sData.GetSize()); | |
429 | |
430 CRYPT_ArcFourCryptBlock(sFile.GetBuffer(), sFile.GetSize(), JS_RC4KEY, | |
431 sizeof(JS_RC4KEY)); | |
432 WriteFileBuffer(m_sFilePath.c_str(), (const FX_CHAR*)sFile.GetBuffer(), | |
433 sFile.GetSize()); | |
434 } | |
435 | |
436 void CJS_GlobalData::LoadFileBuffer(const FX_WCHAR* sFilePath, | |
437 uint8_t*& pBuffer, | |
438 int32_t& nLength) { | |
439 // UnSupport. | |
440 } | |
441 | |
442 void CJS_GlobalData::WriteFileBuffer(const FX_WCHAR* sFilePath, | |
443 const FX_CHAR* pBuffer, | |
444 int32_t nLength) { | |
445 // UnSupport. | |
446 } | |
447 | |
448 void CJS_GlobalData::MakeByteString(const CFX_ByteString& name, | |
449 CJS_KeyValue* pData, | |
450 CFX_BinaryBuf& sData) { | |
451 FX_WORD wType = (FX_WORD)pData->nType; | |
452 switch (wType) { | |
453 case JS_GLOBALDATA_TYPE_NUMBER: { | |
454 FX_DWORD dwNameLen = (FX_DWORD)name.GetLength(); | |
455 sData.AppendBlock(&dwNameLen, sizeof(FX_DWORD)); | |
456 sData.AppendString(name); | |
457 sData.AppendBlock(&wType, sizeof(FX_WORD)); | |
458 | |
459 double dData = pData->dData; | |
460 sData.AppendBlock(&dData, sizeof(double)); | |
461 } break; | |
462 case JS_GLOBALDATA_TYPE_BOOLEAN: { | |
463 FX_DWORD dwNameLen = (FX_DWORD)name.GetLength(); | |
464 sData.AppendBlock(&dwNameLen, sizeof(FX_DWORD)); | |
465 sData.AppendString(name); | |
466 sData.AppendBlock(&wType, sizeof(FX_WORD)); | |
467 | |
468 FX_WORD wData = (FX_WORD)pData->bData; | |
469 sData.AppendBlock(&wData, sizeof(FX_WORD)); | |
470 } break; | |
471 case JS_GLOBALDATA_TYPE_STRING: { | |
472 FX_DWORD dwNameLen = (FX_DWORD)name.GetLength(); | |
473 sData.AppendBlock(&dwNameLen, sizeof(FX_DWORD)); | |
474 sData.AppendString(name); | |
475 sData.AppendBlock(&wType, sizeof(FX_WORD)); | |
476 | |
477 FX_DWORD dwDataLen = (FX_DWORD)pData->sData.GetLength(); | |
478 sData.AppendBlock(&dwDataLen, sizeof(FX_DWORD)); | |
479 sData.AppendString(pData->sData); | |
480 } break; | |
481 case JS_GLOBALDATA_TYPE_NULL: { | |
482 FX_DWORD dwNameLen = (FX_DWORD)name.GetLength(); | |
483 sData.AppendBlock(&dwNameLen, sizeof(FX_DWORD)); | |
484 sData.AppendString(name); | |
485 sData.AppendBlock(&wType, sizeof(FX_DWORD)); | |
486 } break; | |
487 default: | |
488 break; | |
489 } | |
490 } | |
OLD | NEW |