• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "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 
CJS_GlobalVariableArray()16 CJS_GlobalVariableArray::CJS_GlobalVariableArray() {}
17 
~CJS_GlobalVariableArray()18 CJS_GlobalVariableArray::~CJS_GlobalVariableArray() {
19   Empty();
20 }
21 
Copy(const CJS_GlobalVariableArray & array)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 
Add(CJS_KeyValue * p)65 void CJS_GlobalVariableArray::Add(CJS_KeyValue* p) {
66   array.Add(p);
67 }
68 
Count() const69 int CJS_GlobalVariableArray::Count() const {
70   return array.GetSize();
71 }
72 
GetAt(int index) const73 CJS_KeyValue* CJS_GlobalVariableArray::GetAt(int index) const {
74   return array.GetAt(index);
75 }
76 
Empty()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
GetRetainedInstance(CPDFDoc_Environment * pApp)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 
Release()111 void CJS_GlobalData::Release() {
112   if (!--m_RefCount) {
113     delete g_Instance;
114     g_Instance = nullptr;
115   }
116 }
117 
CJS_GlobalData()118 CJS_GlobalData::CJS_GlobalData() : m_RefCount(0) {
119   m_sFilePath += SDK_JS_GLOBALDATA_FILENAME;
120   LoadGlobalPersistentVariables();
121 }
122 
~CJS_GlobalData()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 
FindGlobalVariable(const FX_CHAR * propname)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 
GetGlobalVariable(const FX_CHAR * propname)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 
SetGlobalVariableNumber(const FX_CHAR * propname,double dData)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 
SetGlobalVariableBoolean(const FX_CHAR * propname,bool bData)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 
SetGlobalVariableString(const FX_CHAR * propname,const CFX_ByteString & sData)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 
SetGlobalVariableObject(const FX_CHAR * propname,const CJS_GlobalVariableArray & array)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 
SetGlobalVariableNull(const FX_CHAR * propname)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 
SetGlobalVariablePersistent(const FX_CHAR * propname,FX_BOOL bPersistent)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 
DeleteGlobalVariable(const FX_CHAR * propname)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 
GetSize() const303 int32_t CJS_GlobalData::GetSize() const {
304   return m_arrayGlobalData.GetSize();
305 }
306 
GetAt(int index) const307 CJS_GlobalData_Element* CJS_GlobalData::GetAt(int index) const {
308   return m_arrayGlobalData.GetAt(index);
309 }
310 
LoadGlobalPersistentVariables()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 
SaveGlobalPersisitentVariables()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 
LoadFileBuffer(const FX_WCHAR * sFilePath,uint8_t * & pBuffer,int32_t & nLength)436 void CJS_GlobalData::LoadFileBuffer(const FX_WCHAR* sFilePath,
437                                     uint8_t*& pBuffer,
438                                     int32_t& nLength) {
439   // UnSupport.
440 }
441 
WriteFileBuffer(const FX_WCHAR * sFilePath,const FX_CHAR * pBuffer,int32_t nLength)442 void CJS_GlobalData::WriteFileBuffer(const FX_WCHAR* sFilePath,
443                                      const FX_CHAR* pBuffer,
444                                      int32_t nLength) {
445   // UnSupport.
446 }
447 
MakeByteString(const CFX_ByteString & name,CJS_KeyValue * pData,CFX_BinaryBuf & sData)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 }
491