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 15CJS_GlobalVariableArray::CJS_GlobalVariableArray() 16{ 17} 18 19CJS_GlobalVariableArray::~CJS_GlobalVariableArray() 20{ 21 Empty(); 22} 23 24void 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 80void CJS_GlobalVariableArray::Add(CJS_KeyValue* p) 81{ 82 array.Add(p); 83} 84 85int CJS_GlobalVariableArray::Count() const 86{ 87 return array.GetSize(); 88} 89 90CJS_KeyValue* CJS_GlobalVariableArray::GetAt(int index) const 91{ 92 return array.GetAt(index); 93} 94 95void 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 108static const FX_BYTE 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 120CJS_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 131CJS_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 141int 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 160CJS_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 172void 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 198void 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 224void 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 250void 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 276void 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 300FX_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 319FX_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 341FX_INT32 CJS_GlobalData::GetSize() const 342{ 343 return m_arrayGlobalData.GetSize(); 344} 345 346CJS_GlobalData_Element* CJS_GlobalData::GetAt(int index) const 347{ 348 return m_arrayGlobalData.GetAt(index); 349} 350 351void CJS_GlobalData::LoadGlobalPersistentVariables() 352{ 353 FX_LPBYTE pBuffer = NULL; 354 FX_INT32 nLength = 0; 355 356 LoadFileBuffer(m_sFilePath, pBuffer, nLength); 357 358 CRYPT_ArcFourCryptBlock(pBuffer, nLength, JS_RC4KEY, sizeof(JS_RC4KEY)); 359 360 if (pBuffer) 361 { 362 FX_LPBYTE 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 (FX_INT32 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/* 460struct js_global_datafile_header 461{ 462 FX_WORD type; //FX ('X' << 8) | 'F' 463 FX_WORD version; //1.0 464 FX_DWORD datacount; 465}; 466struct 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 476void 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, (FX_LPCSTR)sFile.GetBuffer(), sFile.GetSize()); 513} 514 515void CJS_GlobalData::LoadFileBuffer(FX_LPCWSTR sFilePath, FX_LPBYTE& pBuffer, FX_INT32& nLength) 516{ 517//UnSupport. 518} 519 520void CJS_GlobalData::WriteFileBuffer(FX_LPCWSTR sFilePath, FX_LPCSTR pBuffer, FX_INT32 nLength) 521{ 522//UnSupport. 523} 524 525void 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 582