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