Fix some clang warnings with -Wmissing-braces in 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 "../../../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
167         if (nFind >= 0)
168                 return m_arrayGlobalData.GetAt(nFind);
169         else
170                 return NULL;
171 }
172
173 void CJS_GlobalData::SetGlobalVariableNumber(const FX_CHAR* propname, double dData)
174 {
175         ASSERT(propname != NULL);
176         CFX_ByteString sPropName = propname;
177
178         sPropName.TrimLeft();
179         sPropName.TrimRight();
180
181         if (sPropName.GetLength() == 0) return;
182
183         if (CJS_GlobalData_Element* pData = GetGlobalVariable(sPropName))
184         {
185                 pData->data.nType = JS_GLOBALDATA_TYPE_NUMBER;
186                 pData->data.dData = dData;
187         }
188         else
189         {
190                 CJS_GlobalData_Element* pNewData = new CJS_GlobalData_Element;
191                 pNewData->data.sKey = sPropName;
192                 pNewData->data.nType = JS_GLOBALDATA_TYPE_NUMBER;
193                 pNewData->data.dData = dData;
194
195                 m_arrayGlobalData.Add(pNewData);
196         }
197 }
198
199 void CJS_GlobalData::SetGlobalVariableBoolean(const FX_CHAR* propname, bool bData)
200 {
201         ASSERT(propname != NULL);
202         CFX_ByteString sPropName = propname;
203
204         sPropName.TrimLeft();
205         sPropName.TrimRight();
206
207         if (sPropName.GetLength() == 0) return;
208
209         if (CJS_GlobalData_Element* pData = GetGlobalVariable(sPropName))
210         {
211                 pData->data.nType = JS_GLOBALDATA_TYPE_BOOLEAN;
212                 pData->data.bData = bData;
213         }
214         else
215         {
216                 CJS_GlobalData_Element* pNewData = new CJS_GlobalData_Element;
217                 pNewData->data.sKey = sPropName;
218                 pNewData->data.nType = JS_GLOBALDATA_TYPE_BOOLEAN;
219                 pNewData->data.bData = bData;
220
221                 m_arrayGlobalData.Add(pNewData);
222         }
223 }
224
225 void CJS_GlobalData::SetGlobalVariableString(const FX_CHAR* propname, const CFX_ByteString& sData)
226 {
227         ASSERT(propname != NULL);
228         CFX_ByteString sPropName = propname;
229
230         sPropName.TrimLeft();
231         sPropName.TrimRight();
232
233         if (sPropName.GetLength() == 0) return;
234
235         if (CJS_GlobalData_Element* pData = GetGlobalVariable(sPropName))
236         {
237                 pData->data.nType = JS_GLOBALDATA_TYPE_STRING;
238                 pData->data.sData = sData;
239         }
240         else
241         {
242                 CJS_GlobalData_Element* pNewData = new CJS_GlobalData_Element;
243                 pNewData->data.sKey = sPropName;
244                 pNewData->data.nType = JS_GLOBALDATA_TYPE_STRING;
245                 pNewData->data.sData = sData;
246
247                 m_arrayGlobalData.Add(pNewData);
248         }
249 }
250
251 void CJS_GlobalData::SetGlobalVariableObject(const FX_CHAR* propname, const CJS_GlobalVariableArray& array)
252 {
253         ASSERT(propname != NULL);
254         CFX_ByteString sPropName = propname;
255
256         sPropName.TrimLeft();
257         sPropName.TrimRight();
258
259         if (sPropName.GetLength() == 0) return;
260
261         if (CJS_GlobalData_Element* pData = GetGlobalVariable(sPropName))
262         {
263                 pData->data.nType = JS_GLOBALDATA_TYPE_OBJECT;
264                 pData->data.objData.Copy(array);
265         }
266         else
267         {
268                 CJS_GlobalData_Element* pNewData = new CJS_GlobalData_Element;
269                 pNewData->data.sKey = sPropName;
270                 pNewData->data.nType = JS_GLOBALDATA_TYPE_OBJECT;
271                 pNewData->data.objData.Copy(array);
272
273                 m_arrayGlobalData.Add(pNewData);
274         }
275 }
276
277 void CJS_GlobalData::SetGlobalVariableNull(const FX_CHAR* propname)
278 {
279         ASSERT(propname != NULL);
280         CFX_ByteString sPropName = propname;
281
282         sPropName.TrimLeft();
283         sPropName.TrimRight();
284
285         if (sPropName.GetLength() == 0) return;
286
287         if (CJS_GlobalData_Element* pData = GetGlobalVariable(sPropName))
288         {
289                 pData->data.nType = JS_GLOBALDATA_TYPE_NULL;
290         }
291         else
292         {
293                 CJS_GlobalData_Element* pNewData = new CJS_GlobalData_Element;
294                 pNewData->data.sKey = sPropName;
295                 pNewData->data.nType = JS_GLOBALDATA_TYPE_NULL;
296
297                 m_arrayGlobalData.Add(pNewData);
298         }
299 }
300
301 FX_BOOL CJS_GlobalData::SetGlobalVariablePersistent(const FX_CHAR* propname, FX_BOOL bPersistent)
302 {
303         ASSERT(propname != NULL);
304         CFX_ByteString sPropName = propname;
305
306         sPropName.TrimLeft();
307         sPropName.TrimRight();
308
309         if (sPropName.GetLength() == 0) return FALSE;
310
311         if (CJS_GlobalData_Element* pData = GetGlobalVariable(sPropName))
312         {
313                 pData->bPersistent = bPersistent;
314                 return TRUE;
315         }
316
317         return FALSE;
318 }
319
320 FX_BOOL CJS_GlobalData::DeleteGlobalVariable(const FX_CHAR* propname)
321 {
322         ASSERT(propname != NULL);
323         CFX_ByteString sPropName = propname;
324
325         sPropName.TrimLeft();
326         sPropName.TrimRight();
327
328         if (sPropName.GetLength() == 0) return FALSE;
329
330         int     nFind = FindGlobalVariable(sPropName);
331
332         if (nFind >= 0)
333         {
334                 delete m_arrayGlobalData.GetAt(nFind);
335                 m_arrayGlobalData.RemoveAt(nFind);
336                 return TRUE;
337         }
338
339         return FALSE;
340 }
341
342 int32_t CJS_GlobalData::GetSize() const
343 {
344         return m_arrayGlobalData.GetSize();
345 }
346
347 CJS_GlobalData_Element* CJS_GlobalData::GetAt(int index) const
348 {
349         return m_arrayGlobalData.GetAt(index);
350 }
351
352 void CJS_GlobalData::LoadGlobalPersistentVariables()
353 {
354         uint8_t* pBuffer = NULL;
355         int32_t nLength = 0;
356
357         LoadFileBuffer(m_sFilePath.c_str(), pBuffer, nLength);
358         CRYPT_ArcFourCryptBlock(pBuffer, nLength, JS_RC4KEY, sizeof(JS_RC4KEY));
359
360         if (pBuffer)
361         {
362                 uint8_t* p = pBuffer;
363                 FX_WORD wType = *((FX_WORD*)p);
364                 p += sizeof(FX_WORD);
365
366                 //FX_WORD wTemp = (FX_WORD)(('X' << 8) | 'F');
367
368                 if (wType == (FX_WORD)(('X' << 8) | 'F'))
369                 {
370                         FX_WORD wVersion = *((FX_WORD*)p);
371                         p += sizeof(FX_WORD);
372
373                         ASSERT(wVersion <= 2);
374
375                         FX_DWORD dwCount = *((FX_DWORD*)p);
376                         p += sizeof(FX_DWORD);
377
378                         FX_DWORD dwSize = *((FX_DWORD*)p);
379                         p += sizeof(FX_DWORD);
380
381                         if (dwSize == nLength - sizeof(FX_WORD) * 2 - sizeof(FX_DWORD)* 2)
382                         {
383                                 for (int32_t i=0,sz=dwCount; i<sz; i++)
384                                 {
385                                         if (p > pBuffer + nLength)
386                                                 break;
387
388                                         FX_DWORD dwNameLen = *((FX_DWORD*)p);
389                                         p += sizeof(FX_DWORD);
390
391                                         if (p + dwNameLen > pBuffer + nLength)
392                                                 break;
393
394                                         CFX_ByteString sEntry = CFX_ByteString(p, dwNameLen);
395                                         p += sizeof(char) * dwNameLen;
396
397                                         FX_WORD wDataType = *((FX_WORD*)p);
398                                         p += sizeof(FX_WORD);
399
400                                         switch (wDataType)
401                                         {
402                                         case JS_GLOBALDATA_TYPE_NUMBER:
403                                                 {
404                                                         double dData = 0;
405                                                         switch (wVersion)
406                                                         {
407                                                         case 1:
408                                                                 {
409                                                                         FX_DWORD dwData = *((FX_DWORD*)p);
410                                                                         p += sizeof(FX_DWORD);
411                                                                         dData = dwData;
412                                                                 }
413                                                                 break;
414                                                         case 2:
415                                                                 {
416                                                                         dData = *((double*)p);
417                                                                         p += sizeof(double);
418                                                                 }
419                                                                 break;
420                                                         }
421                                                         SetGlobalVariableNumber(sEntry, dData);
422                                                         SetGlobalVariablePersistent(sEntry, TRUE);
423                                                 }
424                                                 break;
425                                         case JS_GLOBALDATA_TYPE_BOOLEAN:
426                                                 {
427                                                         FX_WORD wData = *((FX_WORD*)p);
428                                                         p += sizeof(FX_WORD);
429                                                         SetGlobalVariableBoolean(sEntry, (bool)(wData == 1));
430                                                         SetGlobalVariablePersistent(sEntry, TRUE);
431                                                 }
432                                                 break;
433                                         case JS_GLOBALDATA_TYPE_STRING:
434                                                 {
435                                                         FX_DWORD dwLength = *((FX_DWORD*)p);
436                                                         p += sizeof(FX_DWORD);
437
438                                                         if (p + dwLength > pBuffer + nLength)
439                                                                 break;
440
441                                                         SetGlobalVariableString(sEntry, CFX_ByteString(p, dwLength));
442                                                         SetGlobalVariablePersistent(sEntry, TRUE);
443                                                         p += sizeof(char) * dwLength;
444                                                 }
445                                                 break;
446                                         case JS_GLOBALDATA_TYPE_NULL:
447                                                 {
448                                                         SetGlobalVariableNull(sEntry);
449                                                         SetGlobalVariablePersistent(sEntry, TRUE);
450                                                 }
451                                         }
452                                 }
453                         }
454                 }
455                 FX_Free(pBuffer);
456         }
457 }
458
459 /*
460 struct js_global_datafile_header
461 {
462         FX_WORD type; //FX ('X' << 8) | 'F'
463         FX_WORD version; //1.0
464         FX_DWORD datacount;
465 };
466 struct js_global_datafile_data
467 {
468         FX_WORD type;
469         FX_DWORD nData;
470         FX_WORD bData;
471         FX_DWORD nStrLen;
472         char* pStr;
473 };
474 */
475
476 void CJS_GlobalData::SaveGlobalPersisitentVariables()
477 {
478         FX_DWORD nCount = 0;
479         CFX_BinaryBuf sData;
480
481         for (int i=0,sz=m_arrayGlobalData.GetSize(); i<sz; i++)
482         {
483                 CJS_GlobalData_Element* pElement = m_arrayGlobalData.GetAt(i);
484                 ASSERT(pElement != NULL);
485
486                 if (pElement->bPersistent)
487                 {
488                         CFX_BinaryBuf sElement;
489                         MakeByteString(pElement->data.sKey, &pElement->data, sElement);
490
491                         if (sData.GetSize() + sElement.GetSize() > JS_MAXGLOBALDATA)
492                                 break;
493
494                         sData.AppendBlock(sElement.GetBuffer(), sElement.GetSize());
495                         nCount++;
496                 }
497         }
498
499         CFX_BinaryBuf sFile;
500
501         FX_WORD wType = (FX_WORD)(('X' << 8) | 'F');
502         sFile.AppendBlock(&wType, sizeof(FX_WORD));
503         FX_WORD wVersion = 2;
504         sFile.AppendBlock(&wVersion, sizeof(FX_WORD));
505         sFile.AppendBlock(&nCount, sizeof(FX_DWORD));
506         FX_DWORD dwSize = sData.GetSize();
507         sFile.AppendBlock(&dwSize, sizeof(FX_DWORD));
508
509         sFile.AppendBlock(sData.GetBuffer(), sData.GetSize());
510
511         CRYPT_ArcFourCryptBlock(sFile.GetBuffer(), sFile.GetSize(), JS_RC4KEY, sizeof(JS_RC4KEY));
512         WriteFileBuffer(m_sFilePath.c_str(), (const FX_CHAR*)sFile.GetBuffer(), sFile.GetSize());
513 }
514
515 void CJS_GlobalData::LoadFileBuffer(const FX_WCHAR* sFilePath, uint8_t*& pBuffer, int32_t& nLength)
516 {
517 //UnSupport.
518 }
519
520 void CJS_GlobalData::WriteFileBuffer(const FX_WCHAR* sFilePath, const FX_CHAR* pBuffer, int32_t nLength)
521 {
522 //UnSupport.
523 }
524
525 void CJS_GlobalData::MakeByteString(const CFX_ByteString& name, CJS_KeyValue* pData, CFX_BinaryBuf& sData)
526 {
527         ASSERT(pData != NULL);
528
529         FX_WORD wType = (FX_WORD)pData->nType;
530
531         switch (wType)
532         {
533         case JS_GLOBALDATA_TYPE_NUMBER:
534                 {
535                         FX_DWORD dwNameLen = (FX_DWORD)name.GetLength();
536                         sData.AppendBlock(&dwNameLen, sizeof(FX_DWORD));
537                         sData.AppendString(name);
538
539                         sData.AppendBlock(&wType, sizeof(FX_WORD));
540                         double dData = pData->dData;
541                         sData.AppendBlock(&dData, sizeof(double));
542                 }
543                 break;
544         case JS_GLOBALDATA_TYPE_BOOLEAN:
545                 {
546                         FX_DWORD dwNameLen = (FX_DWORD)name.GetLength();
547                         sData.AppendBlock(&dwNameLen, sizeof(FX_DWORD));
548                         sData.AppendString(name);
549
550                         sData.AppendBlock(&wType, sizeof(FX_WORD));
551                         FX_WORD wData = (FX_WORD)pData->bData;
552                         sData.AppendBlock(&wData, sizeof(FX_WORD));
553                 }
554                 break;
555         case JS_GLOBALDATA_TYPE_STRING:
556                 {
557                         FX_DWORD dwNameLen = (FX_DWORD)name.GetLength();
558                         sData.AppendBlock(&dwNameLen, sizeof(FX_DWORD));
559                         sData.AppendString(name);
560
561                         sData.AppendBlock(&wType, sizeof(FX_WORD));
562
563                         FX_DWORD dwDataLen = (FX_DWORD)pData->sData.GetLength();
564                         sData.AppendBlock(&dwDataLen, sizeof(FX_DWORD));
565                         sData.AppendString(pData->sData);
566                 }
567                 break;
568         case JS_GLOBALDATA_TYPE_NULL:
569                 {
570                         FX_DWORD dwNameLen = (FX_DWORD)name.GetLength();
571                         sData.AppendBlock(&dwNameLen, sizeof(FX_DWORD));
572                         sData.AppendString(name);
573
574                         sData.AppendBlock(&wType, sizeof(FX_DWORD));
575                 }
576                 break;
577         default:
578                 break;
579         }
580 }
581