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