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 "fpdfsdk/src/javascript/util.h" 8 9 #include <time.h> 10 11 #include "core/include/fxcrt/fx_ext.h" 12 #include "fpdfsdk/include/javascript/IJavaScript.h" 13 #include "fpdfsdk/src/javascript/JS_Context.h" 14 #include "fpdfsdk/src/javascript/JS_Define.h" 15 #include "fpdfsdk/src/javascript/JS_EventHandler.h" 16 #include "fpdfsdk/src/javascript/JS_Object.h" 17 #include "fpdfsdk/src/javascript/JS_Runtime.h" 18 #include "fpdfsdk/src/javascript/JS_Value.h" 19 #include "fpdfsdk/src/javascript/PublicMethods.h" 20 #include "fpdfsdk/src/javascript/resource.h" 21 22 #if _FX_OS_ == _FX_ANDROID_ 23 #include <ctype.h> 24 #endif 25 26 BEGIN_JS_STATIC_CONST(CJS_Util) 27 END_JS_STATIC_CONST() 28 29 BEGIN_JS_STATIC_PROP(CJS_Util) 30 END_JS_STATIC_PROP() 31 32 BEGIN_JS_STATIC_METHOD(CJS_Util) 33 JS_STATIC_METHOD_ENTRY(printd) 34 JS_STATIC_METHOD_ENTRY(printf) 35 JS_STATIC_METHOD_ENTRY(printx) 36 JS_STATIC_METHOD_ENTRY(scand) 37 JS_STATIC_METHOD_ENTRY(byteToChar) 38 END_JS_STATIC_METHOD() 39 40 IMPLEMENT_JS_CLASS(CJS_Util, util) 41 42 util::util(CJS_Object* pJSObject) : CJS_EmbedObj(pJSObject) {} 43 44 util::~util() { 45 } 46 47 struct stru_TbConvert { 48 const FX_WCHAR* lpszJSMark; 49 const FX_WCHAR* lpszCppMark; 50 }; 51 52 const stru_TbConvert fcTable[] = { 53 {L"mmmm", L"%B"}, 54 {L"mmm", L"%b"}, 55 {L"mm", L"%m"}, 56 //"m" 57 {L"dddd", L"%A"}, 58 {L"ddd", L"%a"}, 59 {L"dd", L"%d"}, 60 //"d", "%w", 61 {L"yyyy", L"%Y"}, 62 {L"yy", L"%y"}, 63 {L"HH", L"%H"}, 64 //"H" 65 {L"hh", L"%I"}, 66 //"h" 67 {L"MM", L"%M"}, 68 //"M" 69 {L"ss", L"%S"}, 70 //"s 71 {L"TT", L"%p"}, 72 //"t" 73 #if defined(_WIN32) 74 {L"tt", L"%p"}, 75 {L"h", L"%#I"}, 76 #else 77 {L"tt", L"%P"}, 78 {L"h", L"%l"}, 79 #endif 80 }; 81 82 #define UTIL_INT 0 83 #define UTIL_DOUBLE 1 84 #define UTIL_STRING 2 85 86 int util::ParstDataType(std::wstring* sFormat) { 87 bool bPercent = FALSE; 88 for (size_t i = 0; i < sFormat->length(); ++i) { 89 wchar_t c = (*sFormat)[i]; 90 if (c == L'%') { 91 bPercent = true; 92 continue; 93 } 94 95 if (bPercent) { 96 if (c == L'c' || c == L'C' || c == L'd' || c == L'i' || c == L'o' || 97 c == L'u' || c == L'x' || c == L'X') { 98 return UTIL_INT; 99 } 100 if (c == L'e' || c == L'E' || c == L'f' || c == L'g' || c == L'G') { 101 return UTIL_DOUBLE; 102 } 103 if (c == L's' || c == L'S') { 104 // Map s to S since we always deal internally 105 // with wchar_t strings. 106 (*sFormat)[i] = L'S'; 107 return UTIL_STRING; 108 } 109 if (c == L'.' || c == L'+' || c == L'-' || c == L'#' || c == L' ' || 110 FXSYS_iswdigit(c)) { 111 continue; 112 } 113 break; 114 } 115 } 116 117 return -1; 118 } 119 120 FX_BOOL util::printf(IJS_Context* cc, 121 const std::vector<CJS_Value>& params, 122 CJS_Value& vRet, 123 CFX_WideString& sError) { 124 int iSize = params.size(); 125 if (iSize < 1) 126 return FALSE; 127 std::wstring c_ConvChar(params[0].ToCFXWideString().c_str()); 128 std::vector<std::wstring> c_strConvers; 129 int iOffset = 0; 130 int iOffend = 0; 131 c_ConvChar.insert(c_ConvChar.begin(), L'S'); 132 while (iOffset != -1) { 133 iOffend = c_ConvChar.find(L"%", iOffset + 1); 134 std::wstring strSub; 135 if (iOffend == -1) 136 strSub = c_ConvChar.substr(iOffset); 137 else 138 strSub = c_ConvChar.substr(iOffset, iOffend - iOffset); 139 c_strConvers.push_back(strSub); 140 iOffset = iOffend; 141 } 142 143 std::wstring c_strResult; 144 145 // for(int iIndex = 1;iIndex < params.size();iIndex++) 146 std::wstring c_strFormat; 147 for (int iIndex = 0; iIndex < (int)c_strConvers.size(); iIndex++) { 148 c_strFormat = c_strConvers[iIndex]; 149 if (iIndex == 0) { 150 c_strResult = c_strFormat; 151 continue; 152 } 153 154 CFX_WideString strSegment; 155 if (iIndex >= iSize) { 156 c_strResult += c_strFormat; 157 continue; 158 } 159 160 switch (ParstDataType(&c_strFormat)) { 161 case UTIL_INT: 162 strSegment.Format(c_strFormat.c_str(), params[iIndex].ToInt()); 163 break; 164 case UTIL_DOUBLE: 165 strSegment.Format(c_strFormat.c_str(), params[iIndex].ToDouble()); 166 break; 167 case UTIL_STRING: 168 strSegment.Format(c_strFormat.c_str(), 169 params[iIndex].ToCFXWideString().c_str()); 170 break; 171 default: 172 strSegment.Format(L"%S", c_strFormat.c_str()); 173 break; 174 } 175 c_strResult += strSegment.GetBuffer(strSegment.GetLength() + 1); 176 } 177 178 c_strResult.erase(c_strResult.begin()); 179 vRet = c_strResult.c_str(); 180 return TRUE; 181 } 182 183 FX_BOOL util::printd(IJS_Context* cc, 184 const std::vector<CJS_Value>& params, 185 CJS_Value& vRet, 186 CFX_WideString& sError) { 187 int iSize = params.size(); 188 if (iSize < 2) 189 return FALSE; 190 191 CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); 192 CJS_Value p1(pRuntime); 193 p1 = params[0]; 194 195 CJS_Value p2 = params[1]; 196 CJS_Date jsDate(pRuntime); 197 if (!p2.ConvertToDate(jsDate)) { 198 sError = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSPRINT1); 199 return FALSE; 200 } 201 202 if (!jsDate.IsValidDate()) { 203 sError = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSPRINT2); 204 return FALSE; 205 } 206 207 if (p1.GetType() == CJS_Value::VT_number) { 208 int nFormat = p1.ToInt(); 209 CFX_WideString swResult; 210 211 switch (nFormat) { 212 case 0: 213 swResult.Format(L"D:%04d%02d%02d%02d%02d%02d", jsDate.GetYear(), 214 jsDate.GetMonth() + 1, jsDate.GetDay(), 215 jsDate.GetHours(), jsDate.GetMinutes(), 216 jsDate.GetSeconds()); 217 break; 218 case 1: 219 swResult.Format(L"%04d.%02d.%02d %02d:%02d:%02d", jsDate.GetYear(), 220 jsDate.GetMonth() + 1, jsDate.GetDay(), 221 jsDate.GetHours(), jsDate.GetMinutes(), 222 jsDate.GetSeconds()); 223 break; 224 case 2: 225 swResult.Format(L"%04d/%02d/%02d %02d:%02d:%02d", jsDate.GetYear(), 226 jsDate.GetMonth() + 1, jsDate.GetDay(), 227 jsDate.GetHours(), jsDate.GetMinutes(), 228 jsDate.GetSeconds()); 229 break; 230 default: 231 return FALSE; 232 } 233 234 vRet = swResult.c_str(); 235 return TRUE; 236 } 237 if (p1.GetType() == CJS_Value::VT_string) { 238 std::basic_string<wchar_t> cFormat = p1.ToCFXWideString().c_str(); 239 240 bool bXFAPicture = false; 241 if (iSize > 2) { 242 bXFAPicture = params[2].ToBool(); 243 } 244 245 if (bXFAPicture) { 246 return FALSE; // currently, it doesn't support XFAPicture. 247 } 248 249 for (size_t i = 0; i < sizeof(fcTable) / sizeof(stru_TbConvert); ++i) { 250 int iStart = 0; 251 int iEnd; 252 while ((iEnd = cFormat.find(fcTable[i].lpszJSMark, iStart)) != -1) { 253 cFormat.replace(iEnd, FXSYS_wcslen(fcTable[i].lpszJSMark), 254 fcTable[i].lpszCppMark); 255 iStart = iEnd; 256 } 257 } 258 259 int iYear, iMonth, iDay, iHour, iMin, iSec; 260 iYear = jsDate.GetYear(); 261 iMonth = jsDate.GetMonth(); 262 iDay = jsDate.GetDay(); 263 iHour = jsDate.GetHours(); 264 iMin = jsDate.GetMinutes(); 265 iSec = jsDate.GetSeconds(); 266 267 struct tm time = {}; 268 time.tm_year = iYear - 1900; 269 time.tm_mon = iMonth; 270 time.tm_mday = iDay; 271 time.tm_hour = iHour; 272 time.tm_min = iMin; 273 time.tm_sec = iSec; 274 275 struct stru_TbConvertAd { 276 const FX_WCHAR* lpszJSMark; 277 int iValue; 278 }; 279 280 stru_TbConvertAd cTableAd[] = { 281 {L"m", iMonth + 1}, {L"d", iDay}, 282 {L"H", iHour}, {L"h", iHour > 12 ? iHour - 12 : iHour}, 283 {L"M", iMin}, {L"s", iSec}, 284 }; 285 286 for (size_t i = 0; i < sizeof(cTableAd) / sizeof(stru_TbConvertAd); ++i) { 287 wchar_t tszValue[10]; 288 CFX_WideString sValue; 289 sValue.Format(L"%d", cTableAd[i].iValue); 290 memcpy(tszValue, (wchar_t*)sValue.GetBuffer(sValue.GetLength() + 1), 291 (sValue.GetLength() + 1) * sizeof(wchar_t)); 292 293 int iStart = 0; 294 int iEnd; 295 while ((iEnd = cFormat.find(cTableAd[i].lpszJSMark, iStart)) != -1) { 296 if (iEnd > 0) { 297 if (cFormat[iEnd - 1] == L'%') { 298 iStart = iEnd + 1; 299 continue; 300 } 301 } 302 cFormat.replace(iEnd, FXSYS_wcslen(cTableAd[i].lpszJSMark), tszValue); 303 iStart = iEnd; 304 } 305 } 306 307 CFX_WideString strFormat; 308 wchar_t buf[64] = {}; 309 strFormat = wcsftime(buf, 64, cFormat.c_str(), &time); 310 cFormat = buf; 311 vRet = cFormat.c_str(); 312 return TRUE; 313 } 314 return FALSE; 315 } 316 317 void util::printd(const std::wstring& cFormat2, 318 CJS_Date jsDate, 319 bool bXFAPicture, 320 std::wstring& cPurpose) { 321 std::wstring cFormat = cFormat2; 322 323 if (bXFAPicture) { 324 return; // currently, it doesn't support XFAPicture. 325 } 326 327 for (size_t i = 0; i < sizeof(fcTable) / sizeof(stru_TbConvert); ++i) { 328 int iStart = 0; 329 int iEnd; 330 while ((iEnd = cFormat.find(fcTable[i].lpszJSMark, iStart)) != -1) { 331 cFormat.replace(iEnd, FXSYS_wcslen(fcTable[i].lpszJSMark), 332 fcTable[i].lpszCppMark); 333 iStart = iEnd; 334 } 335 } 336 337 int iYear, iMonth, iDay, iHour, iMin, iSec; 338 iYear = jsDate.GetYear(); 339 iMonth = jsDate.GetMonth(); 340 iDay = jsDate.GetDay(); 341 iHour = jsDate.GetHours(); 342 iMin = jsDate.GetMinutes(); 343 iSec = jsDate.GetSeconds(); 344 345 struct tm time = {}; 346 time.tm_year = iYear - 1900; 347 time.tm_mon = iMonth; 348 time.tm_mday = iDay; 349 time.tm_hour = iHour; 350 time.tm_min = iMin; 351 time.tm_sec = iSec; 352 // COleDateTime cppTm(iYear,iMonth+1,iDay,iHour,iMin,iSec); 353 // CString strFormat = cppTm.Format(cFormat.c_str()); 354 355 struct stru_TbConvertAd { 356 const FX_WCHAR* lpszJSMark; 357 int iValue; 358 }; 359 360 stru_TbConvertAd cTableAd[] = { 361 {L"m", iMonth + 1}, {L"d", iDay}, 362 {L"H", iHour}, {L"h", iHour > 12 ? iHour - 12 : iHour}, 363 {L"M", iMin}, {L"s", iSec}, 364 }; 365 366 // cFormat = strFormat.GetBuffer(strFormat.GetLength()+1); 367 for (size_t i = 0; i < sizeof(cTableAd) / sizeof(stru_TbConvertAd); ++i) { 368 wchar_t tszValue[10]; 369 CFX_WideString sValue; 370 sValue.Format(L"%d", cTableAd[i].iValue); 371 memcpy(tszValue, (wchar_t*)sValue.GetBuffer(sValue.GetLength() + 1), 372 sValue.GetLength() * sizeof(wchar_t)); 373 374 int iStart = 0; 375 int iEnd; 376 while ((iEnd = cFormat.find(cTableAd[i].lpszJSMark, iStart)) != -1) { 377 if (iEnd > 0) { 378 if (cFormat[iEnd - 1] == L'%') { 379 iStart = iEnd + 1; 380 continue; 381 } 382 } 383 cFormat.replace(iEnd, FXSYS_wcslen(cTableAd[i].lpszJSMark), tszValue); 384 iStart = iEnd; 385 } 386 } 387 388 CFX_WideString strFormat; 389 wchar_t buf[64] = {}; 390 strFormat = wcsftime(buf, 64, cFormat.c_str(), &time); 391 cFormat = buf; 392 cPurpose = cFormat; 393 } 394 395 FX_BOOL util::printx(IJS_Context* cc, 396 const std::vector<CJS_Value>& params, 397 CJS_Value& vRet, 398 CFX_WideString& sError) { 399 int iSize = params.size(); 400 if (iSize < 2) 401 return FALSE; 402 CFX_WideString sFormat = params[0].ToCFXWideString(); 403 CFX_WideString sSource = params[1].ToCFXWideString(); 404 std::string cFormat = CFX_ByteString::FromUnicode(sFormat).c_str(); 405 std::string cSource = CFX_ByteString::FromUnicode(sSource).c_str(); 406 std::string cDest; 407 printx(cFormat, cSource, cDest); 408 vRet = cDest.c_str(); 409 return TRUE; 410 } 411 412 void util::printx(const std::string& cFormat, 413 const std::string& cSource2, 414 std::string& cPurpose) { 415 std::string cSource(cSource2); 416 if (!cPurpose.empty()) 417 // cPurpose.clear(); 418 cPurpose.erase(); 419 int itSource = 0; 420 int iSize = cSource.size(); 421 for (int iIndex = 0; iIndex < (int)cFormat.size() && itSource < iSize; 422 iIndex++) { 423 char letter = cFormat[iIndex]; 424 switch (letter) { 425 case '?': 426 cPurpose += cSource[itSource]; 427 itSource++; 428 break; 429 case 'X': { 430 while (itSource < iSize) { 431 if (std::isdigit(cSource[itSource]) || 432 (cSource[itSource] >= 'a' && cSource[itSource] <= 'z') || 433 (cSource[itSource] >= 'A' && cSource[itSource] <= 'Z')) { 434 cPurpose += cSource[itSource]; 435 itSource++; 436 break; 437 } 438 itSource++; 439 } 440 break; 441 } break; 442 case 'A': { 443 while (itSource < iSize) { 444 if ((cSource[itSource] >= 'a' && cSource[itSource] <= 'z') || 445 (cSource[itSource] >= 'A' && cSource[itSource] <= 'Z')) { 446 cPurpose += cSource[itSource]; 447 itSource++; 448 break; 449 } 450 itSource++; 451 } 452 break; 453 } break; 454 case '9': { 455 while (itSource < iSize) { 456 if (std::isdigit(cSource[itSource])) { 457 cPurpose += cSource[itSource]; 458 itSource++; 459 break; 460 } 461 itSource++; 462 } 463 break; 464 } 465 case '*': { 466 cPurpose.append(cSource, itSource, iSize - itSource); 467 itSource = iSize - 1; 468 break; 469 } 470 case '\\': 471 break; 472 case '>': { 473 for (char& c : cSource) 474 c = toupper(c); 475 break; 476 } 477 case '<': { 478 for (char& c : cSource) 479 c = tolower(c); 480 break; 481 } 482 case '=': 483 break; 484 default: 485 cPurpose += letter; 486 break; 487 } 488 } 489 } 490 491 FX_BOOL util::scand(IJS_Context* cc, 492 const std::vector<CJS_Value>& params, 493 CJS_Value& vRet, 494 CFX_WideString& sError) { 495 int iSize = params.size(); 496 if (iSize < 2) 497 return FALSE; 498 499 CFX_WideString sFormat = params[0].ToCFXWideString(); 500 CFX_WideString sDate = params[1].ToCFXWideString(); 501 double dDate = JS_GetDateTime(); 502 if (sDate.GetLength() > 0) { 503 dDate = CJS_PublicMethods::MakeRegularDate(sDate, sFormat, nullptr); 504 } 505 506 if (!JS_PortIsNan(dDate)) { 507 vRet = CJS_Date(CJS_Runtime::FromContext(cc), dDate); 508 } else { 509 vRet.SetNull(); 510 } 511 512 return TRUE; 513 } 514 515 int64_t FX_atoi64(const char* nptr) { 516 int c; /* current char */ 517 int64_t total; /* current total */ 518 int sign; /* if '-', then negative, otherwise positive */ 519 520 /* skip whitespace */ 521 while (isspace((int)(unsigned char)*nptr)) 522 ++nptr; 523 524 c = (int)(unsigned char)*nptr++; 525 sign = c; /* save sign indication */ 526 if (c == '-' || c == '+') 527 c = (int)(unsigned char)*nptr++; /* skip sign */ 528 529 total = 0; 530 531 while (isdigit(c)) { 532 total = 10 * total + FXSYS_toDecimalDigit(c); /* accumulate digit */ 533 c = (int)(unsigned char)*nptr++; /* get next char */ 534 } 535 536 return sign == '-' ? -total : total; 537 } 538 539 FX_BOOL util::byteToChar(IJS_Context* cc, 540 const std::vector<CJS_Value>& params, 541 CJS_Value& vRet, 542 CFX_WideString& sError) { 543 int iSize = params.size(); 544 if (iSize == 0) 545 return FALSE; 546 int nByte = params[0].ToInt(); 547 unsigned char cByte = (unsigned char)nByte; 548 CFX_WideString csValue; 549 csValue.Format(L"%c", cByte); 550 vRet = csValue.c_str(); 551 return TRUE; 552 } 553