Home | History | Annotate | Download | only in javascript
      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 
     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 }
    491