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 "fxjs/cjs_publicmethods.h" 8 9 #include <algorithm> 10 #include <cmath> 11 #include <cwctype> 12 #include <iomanip> 13 #include <limits> 14 #include <sstream> 15 #include <string> 16 #include <vector> 17 18 #include "core/fpdfdoc/cpdf_interform.h" 19 #include "core/fxcrt/fx_extension.h" 20 #include "fpdfsdk/cpdfsdk_formfillenvironment.h" 21 #include "fpdfsdk/cpdfsdk_interform.h" 22 #include "fxjs/JS_Define.h" 23 #include "fxjs/cjs_color.h" 24 #include "fxjs/cjs_event_context.h" 25 #include "fxjs/cjs_eventhandler.h" 26 #include "fxjs/cjs_field.h" 27 #include "fxjs/cjs_object.h" 28 #include "fxjs/cjs_runtime.h" 29 #include "fxjs/cjs_util.h" 30 #include "fxjs/js_resources.h" 31 32 // static 33 const JSMethodSpec CJS_PublicMethods::GlobalFunctionSpecs[] = { 34 {"AFNumber_Format", AFNumber_Format_static}, 35 {"AFNumber_Keystroke", AFNumber_Keystroke_static}, 36 {"AFPercent_Format", AFPercent_Format_static}, 37 {"AFPercent_Keystroke", AFPercent_Keystroke_static}, 38 {"AFDate_FormatEx", AFDate_FormatEx_static}, 39 {"AFDate_KeystrokeEx", AFDate_KeystrokeEx_static}, 40 {"AFDate_Format", AFDate_Format_static}, 41 {"AFDate_Keystroke", AFDate_Keystroke_static}, 42 {"AFTime_FormatEx", AFTime_FormatEx_static}, 43 {"AFTime_KeystrokeEx", AFTime_KeystrokeEx_static}, 44 {"AFTime_Format", AFTime_Format_static}, 45 {"AFTime_Keystroke", AFTime_Keystroke_static}, 46 {"AFSpecial_Format", AFSpecial_Format_static}, 47 {"AFSpecial_Keystroke", AFSpecial_Keystroke_static}, 48 {"AFSpecial_KeystrokeEx", AFSpecial_KeystrokeEx_static}, 49 {"AFSimple", AFSimple_static}, 50 {"AFMakeNumber", AFMakeNumber_static}, 51 {"AFSimple_Calculate", AFSimple_Calculate_static}, 52 {"AFRange_Validate", AFRange_Validate_static}, 53 {"AFMergeChange", AFMergeChange_static}, 54 {"AFParseDateEx", AFParseDateEx_static}, 55 {"AFExtractNums", AFExtractNums_static}, 56 }; 57 58 namespace { 59 60 #if _FX_OS_ != _FX_OS_ANDROID_ 61 constexpr double kDoubleCorrect = 0.000000000000001; 62 #endif 63 64 const wchar_t* const kMonths[] = {L"Jan", L"Feb", L"Mar", L"Apr", 65 L"May", L"Jun", L"Jul", L"Aug", 66 L"Sep", L"Oct", L"Nov", L"Dec"}; 67 68 const wchar_t* const kFullMonths[] = {L"January", L"February", L"March", 69 L"April", L"May", L"June", 70 L"July", L"August", L"September", 71 L"October", L"November", L"December"}; 72 73 template <typename T> 74 T StrTrim(const T& str) { 75 T result = str; 76 result.Trim(' '); 77 return result; 78 } 79 80 void AlertIfPossible(CJS_EventContext* pContext, const wchar_t* swMsg) { 81 CPDFSDK_FormFillEnvironment* pFormFillEnv = pContext->GetFormFillEnv(); 82 if (pFormFillEnv) 83 pFormFillEnv->JS_appAlert(swMsg, nullptr, 0, 3); 84 } 85 86 #if _FX_OS_ != _FX_OS_ANDROID_ 87 ByteString CalculateString(double dValue, 88 int iDec, 89 int* iDec2, 90 bool* bNegative) { 91 *bNegative = dValue < 0; 92 if (*bNegative) 93 dValue = -dValue; 94 95 // Make sure the number of precision characters will fit. 96 iDec = std::min(iDec, std::numeric_limits<double>::digits10); 97 98 std::stringstream ss; 99 ss << std::fixed << std::setprecision(iDec) << dValue; 100 std::string value = ss.str(); 101 size_t pos = value.find('.'); 102 *iDec2 = pos == std::string::npos ? value.size() : static_cast<int>(pos); 103 return ByteString(value.c_str()); 104 } 105 #endif 106 107 WideString CalcMergedString(const CJS_EventHandler* event, 108 const WideString& value, 109 const WideString& change) { 110 WideString prefix = value.Left(event->SelStart()); 111 WideString postfix; 112 int end = event->SelEnd(); 113 if (end >= 0 && static_cast<size_t>(end) < value.GetLength()) 114 postfix = value.Right(value.GetLength() - static_cast<size_t>(end)); 115 return prefix + change + postfix; 116 } 117 118 template <CJS_Return (*F)(CJS_Runtime*, 119 const std::vector<v8::Local<v8::Value>>&)> 120 void JSGlobalFunc(const char* func_name_string, 121 const v8::FunctionCallbackInfo<v8::Value>& info) { 122 CJS_Runtime* pRuntime = 123 CJS_Runtime::CurrentRuntimeFromIsolate(info.GetIsolate()); 124 if (!pRuntime) 125 return; 126 127 std::vector<v8::Local<v8::Value>> parameters; 128 for (int i = 0; i < info.Length(); ++i) 129 parameters.push_back(info[i]); 130 131 CJS_Return result = (*F)(pRuntime, parameters); 132 if (result.HasError()) { 133 pRuntime->Error( 134 JSFormatErrorString(func_name_string, nullptr, result.Error())); 135 return; 136 } 137 138 if (result.HasReturn()) 139 info.GetReturnValue().Set(result.Return()); 140 } 141 142 int WithinBoundsOrZero(int value, size_t size) { 143 return value >= 0 && static_cast<size_t>(value) < size ? value : 0; 144 } 145 146 int ValidStyleOrZero(int style) { 147 return WithinBoundsOrZero(style, 4); 148 } 149 150 bool IsDigitSeparatorOrDecimalMark(int c) { 151 return c == '.' || c == ','; 152 } 153 154 #if _FX_OS_ != _FX_OS_ANDROID_ 155 bool IsStyleWithDigitSeparator(int style) { 156 return style == 0 || style == 2; 157 } 158 159 char DigitSeparatorForStyle(int style) { 160 ASSERT(IsStyleWithDigitSeparator(style)); 161 return style == 0 ? ',' : '.'; 162 } 163 #endif 164 165 bool IsStyleWithCommaDecimalMark(int style) { 166 return style >= 2; 167 } 168 169 char DecimalMarkForStyle(int style) { 170 return IsStyleWithCommaDecimalMark(style) ? ',' : '.'; 171 } 172 173 #if _FX_OS_ != _FX_OS_ANDROID_ 174 void NormalizeDecimalMark(ByteString* str) { 175 str->Replace(",", "."); 176 } 177 #endif 178 179 void NormalizeDecimalMarkW(WideString* str) { 180 str->Replace(L",", L"."); 181 } 182 183 bool IsValidMonth(int m) { 184 return m >= 1 && m <= 12; 185 } 186 187 // TODO(thestig): Should this take the month into consideration? 188 bool IsValidDay(int d) { 189 return d >= 1 && d <= 31; 190 } 191 192 // TODO(thestig): Should 24 be allowed? Similarly, 60 for minutes and seconds. 193 bool IsValid24Hour(int h) { 194 return h >= 0 && h <= 24; 195 } 196 197 bool IsValidMinute(int m) { 198 return m >= 0 && m <= 60; 199 } 200 201 bool IsValidSecond(int s) { 202 return s >= 0 && s <= 60; 203 } 204 205 } // namespace 206 207 CJS_PublicMethods::CJS_PublicMethods(v8::Local<v8::Object> pObject) 208 : CJS_Object(pObject) {} 209 210 CJS_PublicMethods::~CJS_PublicMethods() {} 211 212 // static 213 void CJS_PublicMethods::DefineJSObjects(CFXJS_Engine* pEngine) { 214 for (const auto& spec : GlobalFunctionSpecs) 215 pEngine->DefineGlobalMethod(spec.pName, spec.pMethodCall); 216 } 217 218 #define JS_STATIC_GLOBAL_FUN(fun_name) \ 219 void CJS_PublicMethods::fun_name##_static( \ 220 const v8::FunctionCallbackInfo<v8::Value>& info) { \ 221 JSGlobalFunc<fun_name>(#fun_name, info); \ 222 } 223 224 JS_STATIC_GLOBAL_FUN(AFNumber_Format); 225 JS_STATIC_GLOBAL_FUN(AFNumber_Keystroke); 226 JS_STATIC_GLOBAL_FUN(AFPercent_Format); 227 JS_STATIC_GLOBAL_FUN(AFPercent_Keystroke); 228 JS_STATIC_GLOBAL_FUN(AFDate_FormatEx); 229 JS_STATIC_GLOBAL_FUN(AFDate_KeystrokeEx); 230 JS_STATIC_GLOBAL_FUN(AFDate_Format); 231 JS_STATIC_GLOBAL_FUN(AFDate_Keystroke); 232 JS_STATIC_GLOBAL_FUN(AFTime_FormatEx); 233 JS_STATIC_GLOBAL_FUN(AFTime_KeystrokeEx); 234 JS_STATIC_GLOBAL_FUN(AFTime_Format); 235 JS_STATIC_GLOBAL_FUN(AFTime_Keystroke); 236 JS_STATIC_GLOBAL_FUN(AFSpecial_Format); 237 JS_STATIC_GLOBAL_FUN(AFSpecial_Keystroke); 238 JS_STATIC_GLOBAL_FUN(AFSpecial_KeystrokeEx); 239 JS_STATIC_GLOBAL_FUN(AFSimple); 240 JS_STATIC_GLOBAL_FUN(AFMakeNumber); 241 JS_STATIC_GLOBAL_FUN(AFSimple_Calculate); 242 JS_STATIC_GLOBAL_FUN(AFRange_Validate); 243 JS_STATIC_GLOBAL_FUN(AFMergeChange); 244 JS_STATIC_GLOBAL_FUN(AFParseDateEx); 245 JS_STATIC_GLOBAL_FUN(AFExtractNums); 246 247 bool CJS_PublicMethods::IsNumber(const WideString& str) { 248 WideString sTrim = StrTrim(str); 249 const wchar_t* pTrim = sTrim.c_str(); 250 const wchar_t* p = pTrim; 251 bool bDot = false; 252 bool bKXJS = false; 253 254 wchar_t c; 255 while ((c = *p) != L'\0') { 256 if (IsDigitSeparatorOrDecimalMark(c)) { 257 if (bDot) 258 return false; 259 bDot = true; 260 } else if (c == L'-' || c == L'+') { 261 if (p != pTrim) 262 return false; 263 } else if (c == L'e' || c == L'E') { 264 if (bKXJS) 265 return false; 266 267 p++; 268 c = *p; 269 if (c != L'+' && c != L'-') 270 return false; 271 bKXJS = true; 272 } else if (!std::iswdigit(c)) { 273 return false; 274 } 275 p++; 276 } 277 278 return true; 279 } 280 281 bool CJS_PublicMethods::MaskSatisfied(wchar_t c_Change, wchar_t c_Mask) { 282 switch (c_Mask) { 283 case L'9': 284 return !!std::iswdigit(c_Change); 285 case L'A': 286 return FXSYS_iswalpha(c_Change); 287 case L'O': 288 return FXSYS_iswalnum(c_Change); 289 case L'X': 290 return true; 291 default: 292 return (c_Change == c_Mask); 293 } 294 } 295 296 bool CJS_PublicMethods::IsReservedMaskChar(wchar_t ch) { 297 return ch == L'9' || ch == L'A' || ch == L'O' || ch == L'X'; 298 } 299 300 double CJS_PublicMethods::AF_Simple(const wchar_t* sFuction, 301 double dValue1, 302 double dValue2) { 303 if (FXSYS_wcsicmp(sFuction, L"AVG") == 0 || 304 FXSYS_wcsicmp(sFuction, L"SUM") == 0) { 305 return dValue1 + dValue2; 306 } 307 if (FXSYS_wcsicmp(sFuction, L"PRD") == 0) 308 return dValue1 * dValue2; 309 if (FXSYS_wcsicmp(sFuction, L"MIN") == 0) 310 return std::min(dValue1, dValue2); 311 if (FXSYS_wcsicmp(sFuction, L"MAX") == 0) 312 return std::max(dValue1, dValue2); 313 return dValue1; 314 } 315 316 v8::Local<v8::Array> CJS_PublicMethods::AF_MakeArrayFromList( 317 CJS_Runtime* pRuntime, 318 v8::Local<v8::Value> val) { 319 if (!val.IsEmpty() && val->IsArray()) 320 return pRuntime->ToArray(val); 321 322 WideString wsStr = pRuntime->ToWideString(val); 323 ByteString t = ByteString::FromUnicode(wsStr); 324 const char* p = t.c_str(); 325 326 int nIndex = 0; 327 v8::Local<v8::Array> StrArray = pRuntime->NewArray(); 328 while (*p) { 329 const char* pTemp = strchr(p, ','); 330 if (!pTemp) { 331 pRuntime->PutArrayElement( 332 StrArray, nIndex, 333 pRuntime->NewString(StrTrim(ByteString(p)).c_str())); 334 break; 335 } 336 337 pRuntime->PutArrayElement( 338 StrArray, nIndex, 339 pRuntime->NewString(StrTrim(ByteString(p, pTemp - p)).c_str())); 340 341 nIndex++; 342 p = ++pTemp; 343 } 344 return StrArray; 345 } 346 347 int CJS_PublicMethods::ParseStringInteger(const WideString& str, 348 size_t nStart, 349 size_t* pSkip, 350 size_t nMaxStep) { 351 int nRet = 0; 352 size_t nSkip = 0; 353 for (size_t i = nStart; i < str.GetLength(); ++i) { 354 if (i - nStart > 10) 355 break; 356 357 wchar_t c = str[i]; 358 if (!std::iswdigit(c)) 359 break; 360 361 nRet = nRet * 10 + FXSYS_DecimalCharToInt(c); 362 ++nSkip; 363 if (nSkip >= nMaxStep) 364 break; 365 } 366 367 *pSkip = nSkip; 368 return nRet; 369 } 370 371 WideString CJS_PublicMethods::ParseStringString(const WideString& str, 372 size_t nStart, 373 size_t* pSkip) { 374 WideString swRet; 375 swRet.Reserve(str.GetLength()); 376 for (size_t i = nStart; i < str.GetLength(); ++i) { 377 wchar_t c = str[i]; 378 if (!std::iswdigit(c)) 379 break; 380 381 swRet += c; 382 } 383 384 *pSkip = swRet.GetLength(); 385 return swRet; 386 } 387 388 double CJS_PublicMethods::ParseNormalDate(const WideString& value, 389 bool* bWrongFormat) { 390 double dt = JS_GetDateTime(); 391 392 int nYear = JS_GetYearFromTime(dt); 393 int nMonth = JS_GetMonthFromTime(dt) + 1; 394 int nDay = JS_GetDayFromTime(dt); 395 int nHour = JS_GetHourFromTime(dt); 396 int nMin = JS_GetMinFromTime(dt); 397 int nSec = JS_GetSecFromTime(dt); 398 399 int number[3]; 400 401 size_t nSkip = 0; 402 size_t nLen = value.GetLength(); 403 size_t nIndex = 0; 404 size_t i = 0; 405 while (i < nLen) { 406 if (nIndex > 2) 407 break; 408 409 wchar_t c = value[i]; 410 if (std::iswdigit(c)) { 411 number[nIndex++] = ParseStringInteger(value, i, &nSkip, 4); 412 i += nSkip; 413 } else { 414 i++; 415 } 416 } 417 418 if (nIndex == 2) { 419 // TODO(thestig): Should the else case set |bWrongFormat| to true? 420 // case2: month/day 421 // case3: day/month 422 if (IsValidMonth(number[0]) && IsValidDay(number[1])) { 423 nMonth = number[0]; 424 nDay = number[1]; 425 } else if (IsValidDay(number[0]) && IsValidMonth(number[1])) { 426 nDay = number[0]; 427 nMonth = number[1]; 428 } 429 430 if (bWrongFormat) 431 *bWrongFormat = false; 432 } else if (nIndex == 3) { 433 // TODO(thestig): Should the else case set |bWrongFormat| to true? 434 // case1: year/month/day 435 // case2: month/day/year 436 // case3: day/month/year 437 if (number[0] > 12 && IsValidMonth(number[1]) && IsValidDay(number[2])) { 438 nYear = number[0]; 439 nMonth = number[1]; 440 nDay = number[2]; 441 } else if (IsValidMonth(number[0]) && IsValidDay(number[1]) && 442 number[2] > 31) { 443 nMonth = number[0]; 444 nDay = number[1]; 445 nYear = number[2]; 446 } else if (IsValidDay(number[0]) && IsValidMonth(number[1]) && 447 number[2] > 31) { 448 nDay = number[0]; 449 nMonth = number[1]; 450 nYear = number[2]; 451 } 452 453 if (bWrongFormat) 454 *bWrongFormat = false; 455 } else { 456 if (bWrongFormat) 457 *bWrongFormat = true; 458 return dt; 459 } 460 461 // TODO(thestig): Should we set |bWrongFormat| to false here too? 462 return JS_DateParse(WideString::Format(L"%d/%d/%d %d:%d:%d", nMonth, nDay, 463 nYear, nHour, nMin, nSec)); 464 } 465 466 double CJS_PublicMethods::MakeRegularDate(const WideString& value, 467 const WideString& format, 468 bool* bWrongFormat) { 469 double dt = JS_GetDateTime(); 470 471 if (format.IsEmpty() || value.IsEmpty()) 472 return dt; 473 474 int nYear = JS_GetYearFromTime(dt); 475 int nMonth = JS_GetMonthFromTime(dt) + 1; 476 int nDay = JS_GetDayFromTime(dt); 477 int nHour = JS_GetHourFromTime(dt); 478 int nMin = JS_GetMinFromTime(dt); 479 int nSec = JS_GetSecFromTime(dt); 480 481 int nYearSub = 99; // nYear - 2000; 482 483 bool bPm = false; 484 bool bExit = false; 485 bool bBadFormat = false; 486 487 size_t i = 0; 488 size_t j = 0; 489 490 while (i < format.GetLength()) { 491 if (bExit) 492 break; 493 494 wchar_t c = format[i]; 495 switch (c) { 496 case ':': 497 case '.': 498 case '-': 499 case '\\': 500 case '/': 501 i++; 502 j++; 503 break; 504 505 case 'y': 506 case 'm': 507 case 'd': 508 case 'H': 509 case 'h': 510 case 'M': 511 case 's': 512 case 't': { 513 size_t oldj = j; 514 size_t nSkip = 0; 515 size_t remaining = format.GetLength() - i - 1; 516 517 if (remaining == 0 || format[i + 1] != c) { 518 switch (c) { 519 case 'y': 520 i++; 521 j++; 522 break; 523 case 'm': 524 nMonth = ParseStringInteger(value, j, &nSkip, 2); 525 i++; 526 j += nSkip; 527 break; 528 case 'd': 529 nDay = ParseStringInteger(value, j, &nSkip, 2); 530 i++; 531 j += nSkip; 532 break; 533 case 'H': 534 nHour = ParseStringInteger(value, j, &nSkip, 2); 535 i++; 536 j += nSkip; 537 break; 538 case 'h': 539 nHour = ParseStringInteger(value, j, &nSkip, 2); 540 i++; 541 j += nSkip; 542 break; 543 case 'M': 544 nMin = ParseStringInteger(value, j, &nSkip, 2); 545 i++; 546 j += nSkip; 547 break; 548 case 's': 549 nSec = ParseStringInteger(value, j, &nSkip, 2); 550 i++; 551 j += nSkip; 552 break; 553 case 't': 554 bPm = (j < value.GetLength() && value[j] == 'p'); 555 i++; 556 j++; 557 break; 558 } 559 } else if (remaining == 1 || format[i + 2] != c) { 560 switch (c) { 561 case 'y': 562 nYear = ParseStringInteger(value, j, &nSkip, 4); 563 i += 2; 564 j += nSkip; 565 break; 566 case 'm': 567 nMonth = ParseStringInteger(value, j, &nSkip, 2); 568 i += 2; 569 j += nSkip; 570 break; 571 case 'd': 572 nDay = ParseStringInteger(value, j, &nSkip, 2); 573 i += 2; 574 j += nSkip; 575 break; 576 case 'H': 577 nHour = ParseStringInteger(value, j, &nSkip, 2); 578 i += 2; 579 j += nSkip; 580 break; 581 case 'h': 582 nHour = ParseStringInteger(value, j, &nSkip, 2); 583 i += 2; 584 j += nSkip; 585 break; 586 case 'M': 587 nMin = ParseStringInteger(value, j, &nSkip, 2); 588 i += 2; 589 j += nSkip; 590 break; 591 case 's': 592 nSec = ParseStringInteger(value, j, &nSkip, 2); 593 i += 2; 594 j += nSkip; 595 break; 596 case 't': 597 bPm = (j + 1 < value.GetLength() && value[j] == 'p' && 598 value[j + 1] == 'm'); 599 i += 2; 600 j += 2; 601 break; 602 } 603 } else if (remaining == 2 || format[i + 3] != c) { 604 switch (c) { 605 case 'm': { 606 WideString sMonth = ParseStringString(value, j, &nSkip); 607 bool bFind = false; 608 for (int m = 0; m < 12; m++) { 609 if (sMonth.CompareNoCase(kMonths[m]) == 0) { 610 nMonth = m + 1; 611 i += 3; 612 j += nSkip; 613 bFind = true; 614 break; 615 } 616 } 617 618 if (!bFind) { 619 nMonth = ParseStringInteger(value, j, &nSkip, 3); 620 i += 3; 621 j += nSkip; 622 } 623 } break; 624 case 'y': 625 break; 626 default: 627 i += 3; 628 j += 3; 629 break; 630 } 631 } else if (remaining == 3 || format[i + 4] != c) { 632 switch (c) { 633 case 'y': 634 nYear = ParseStringInteger(value, j, &nSkip, 4); 635 j += nSkip; 636 i += 4; 637 break; 638 case 'm': { 639 bool bFind = false; 640 641 WideString sMonth = ParseStringString(value, j, &nSkip); 642 sMonth.MakeLower(); 643 644 for (int m = 0; m < 12; m++) { 645 WideString sFullMonths = kFullMonths[m]; 646 sFullMonths.MakeLower(); 647 648 if (sFullMonths.Contains(sMonth.c_str())) { 649 nMonth = m + 1; 650 i += 4; 651 j += nSkip; 652 bFind = true; 653 break; 654 } 655 } 656 657 if (!bFind) { 658 nMonth = ParseStringInteger(value, j, &nSkip, 4); 659 i += 4; 660 j += nSkip; 661 } 662 } break; 663 default: 664 i += 4; 665 j += 4; 666 break; 667 } 668 } else { 669 if (j >= value.GetLength() || format[i] != value[j]) { 670 bBadFormat = true; 671 bExit = true; 672 } 673 i++; 674 j++; 675 } 676 677 if (oldj == j) { 678 bBadFormat = true; 679 bExit = true; 680 } 681 break; 682 } 683 684 default: 685 if (value.GetLength() <= j) { 686 bExit = true; 687 } else if (format[i] != value[j]) { 688 bBadFormat = true; 689 bExit = true; 690 } 691 692 i++; 693 j++; 694 break; 695 } 696 } 697 698 if (bPm) 699 nHour += 12; 700 701 if (nYear >= 0 && nYear <= nYearSub) 702 nYear += 2000; 703 704 if (!bBadFormat) { 705 bBadFormat = !IsValidMonth(nMonth) || !IsValidDay(nDay) || 706 !IsValid24Hour(nHour) || !IsValidMinute(nMin) || 707 !IsValidSecond(nSec); 708 } 709 710 double dRet; 711 if (bBadFormat) { 712 dRet = ParseNormalDate(value, &bBadFormat); 713 } else { 714 dRet = JS_MakeDate(JS_MakeDay(nYear, nMonth - 1, nDay), 715 JS_MakeTime(nHour, nMin, nSec, 0)); 716 if (std::isnan(dRet)) 717 dRet = JS_DateParse(value); 718 } 719 720 if (std::isnan(dRet)) 721 dRet = ParseNormalDate(value, &bBadFormat); 722 723 if (bWrongFormat) 724 *bWrongFormat = bBadFormat; 725 726 return dRet; 727 } 728 729 WideString CJS_PublicMethods::MakeFormatDate(double dDate, 730 const WideString& format) { 731 WideString sRet; 732 WideString sPart; 733 734 int nYear = JS_GetYearFromTime(dDate); 735 int nMonth = JS_GetMonthFromTime(dDate) + 1; 736 int nDay = JS_GetDayFromTime(dDate); 737 int nHour = JS_GetHourFromTime(dDate); 738 int nMin = JS_GetMinFromTime(dDate); 739 int nSec = JS_GetSecFromTime(dDate); 740 741 size_t i = 0; 742 while (i < format.GetLength()) { 743 wchar_t c = format[i]; 744 size_t remaining = format.GetLength() - i - 1; 745 sPart.clear(); 746 switch (c) { 747 case 'y': 748 case 'm': 749 case 'd': 750 case 'H': 751 case 'h': 752 case 'M': 753 case 's': 754 case 't': 755 if (remaining == 0 || format[i + 1] != c) { 756 switch (c) { 757 case 'y': 758 sPart += c; 759 break; 760 case 'm': 761 sPart = WideString::Format(L"%d", nMonth); 762 break; 763 case 'd': 764 sPart = WideString::Format(L"%d", nDay); 765 break; 766 case 'H': 767 sPart = WideString::Format(L"%d", nHour); 768 break; 769 case 'h': 770 sPart = 771 WideString::Format(L"%d", nHour > 12 ? nHour - 12 : nHour); 772 break; 773 case 'M': 774 sPart = WideString::Format(L"%d", nMin); 775 break; 776 case 's': 777 sPart = WideString::Format(L"%d", nSec); 778 break; 779 case 't': 780 sPart += nHour > 12 ? 'p' : 'a'; 781 break; 782 } 783 i++; 784 } else if (remaining == 1 || format[i + 2] != c) { 785 switch (c) { 786 case 'y': 787 sPart = WideString::Format(L"%02d", nYear - (nYear / 100) * 100); 788 break; 789 case 'm': 790 sPart = WideString::Format(L"%02d", nMonth); 791 break; 792 case 'd': 793 sPart = WideString::Format(L"%02d", nDay); 794 break; 795 case 'H': 796 sPart = WideString::Format(L"%02d", nHour); 797 break; 798 case 'h': 799 sPart = 800 WideString::Format(L"%02d", nHour > 12 ? nHour - 12 : nHour); 801 break; 802 case 'M': 803 sPart = WideString::Format(L"%02d", nMin); 804 break; 805 case 's': 806 sPart = WideString::Format(L"%02d", nSec); 807 break; 808 case 't': 809 sPart = nHour > 12 ? L"pm" : L"am"; 810 break; 811 } 812 i += 2; 813 } else if (remaining == 2 || format[i + 3] != c) { 814 switch (c) { 815 case 'm': 816 i += 3; 817 if (IsValidMonth(nMonth)) 818 sPart += kMonths[nMonth - 1]; 819 break; 820 default: 821 i += 3; 822 sPart += c; 823 sPart += c; 824 sPart += c; 825 break; 826 } 827 } else if (remaining == 3 || format[i + 4] != c) { 828 switch (c) { 829 case 'y': 830 sPart = WideString::Format(L"%04d", nYear); 831 i += 4; 832 break; 833 case 'm': 834 i += 4; 835 if (IsValidMonth(nMonth)) 836 sPart += kFullMonths[nMonth - 1]; 837 break; 838 default: 839 i += 4; 840 sPart += c; 841 sPart += c; 842 sPart += c; 843 sPart += c; 844 break; 845 } 846 } else { 847 i++; 848 sPart += c; 849 } 850 break; 851 default: 852 i++; 853 sPart += c; 854 break; 855 } 856 857 sRet += sPart; 858 } 859 860 return sRet; 861 } 862 863 // function AFNumber_Format(nDec, sepStyle, negStyle, currStyle, strCurrency, 864 // bCurrencyPrepend) 865 CJS_Return CJS_PublicMethods::AFNumber_Format( 866 CJS_Runtime* pRuntime, 867 const std::vector<v8::Local<v8::Value>>& params) { 868 #if _FX_OS_ != _FX_OS_ANDROID_ 869 if (params.size() != 6) 870 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 871 872 CJS_EventHandler* pEvent = 873 pRuntime->GetCurrentEventContext()->GetEventHandler(); 874 if (!pEvent->m_pValue) 875 return CJS_Return(false); 876 877 WideString& Value = pEvent->Value(); 878 ByteString strValue = StrTrim(ByteString::FromUnicode(Value)); 879 if (strValue.IsEmpty()) 880 return CJS_Return(true); 881 882 int iDec = abs(pRuntime->ToInt32(params[0])); 883 int iSepStyle = ValidStyleOrZero(pRuntime->ToInt32(params[1])); 884 int iNegStyle = ValidStyleOrZero(pRuntime->ToInt32(params[2])); 885 // params[3] is iCurrStyle, it's not used. 886 WideString wstrCurrency = pRuntime->ToWideString(params[4]); 887 bool bCurrencyPrepend = pRuntime->ToBoolean(params[5]); 888 889 // Processing decimal places 890 NormalizeDecimalMark(&strValue); 891 double dValue = atof(strValue.c_str()); 892 if (iDec > 0) 893 dValue += kDoubleCorrect; 894 895 // Calculating number string 896 bool bNegative; 897 int iDec2; 898 strValue = CalculateString(dValue, iDec, &iDec2, &bNegative); 899 if (strValue.IsEmpty()) { 900 dValue = 0; 901 strValue = CalculateString(dValue, iDec, &iDec2, &bNegative); 902 if (strValue.IsEmpty()) { 903 strValue = "0"; 904 iDec2 = 1; 905 } 906 } 907 ASSERT(iDec2 >= 0); 908 909 // Processing separator style 910 if (static_cast<size_t>(iDec2) < strValue.GetLength()) { 911 if (IsStyleWithCommaDecimalMark(iSepStyle)) 912 strValue.Replace(".", ","); 913 914 if (iDec2 == 0) 915 strValue.Insert(iDec2, '0'); 916 } 917 if (IsStyleWithDigitSeparator(iSepStyle)) { 918 char cSeparator = DigitSeparatorForStyle(iSepStyle); 919 for (int iDecPositive = iDec2 - 3; iDecPositive > 0; iDecPositive -= 3) 920 strValue.Insert(iDecPositive, cSeparator); 921 } 922 923 // Processing currency string 924 Value = WideString::FromLocal(strValue.AsStringView()); 925 if (bCurrencyPrepend) 926 Value = wstrCurrency + Value; 927 else 928 Value = Value + wstrCurrency; 929 930 // Processing negative style 931 if (bNegative) { 932 if (iNegStyle == 0) { 933 Value.InsertAtFront(L'-'); 934 } else if (iNegStyle == 2 || iNegStyle == 3) { 935 Value.InsertAtFront(L'('); 936 Value += L')'; 937 } 938 if (iNegStyle == 1 || iNegStyle == 3) { 939 if (Field* fTarget = pEvent->Target_Field()) { 940 v8::Local<v8::Array> arColor = pRuntime->NewArray(); 941 pRuntime->PutArrayElement(arColor, 0, pRuntime->NewString(L"RGB")); 942 pRuntime->PutArrayElement(arColor, 1, pRuntime->NewNumber(1)); 943 pRuntime->PutArrayElement(arColor, 2, pRuntime->NewNumber(0)); 944 pRuntime->PutArrayElement(arColor, 3, pRuntime->NewNumber(0)); 945 fTarget->set_text_color(pRuntime, arColor); 946 } 947 } 948 } else { 949 if (iNegStyle == 1 || iNegStyle == 3) { 950 if (Field* fTarget = pEvent->Target_Field()) { 951 v8::Local<v8::Array> arColor = pRuntime->NewArray(); 952 pRuntime->PutArrayElement(arColor, 0, pRuntime->NewString(L"RGB")); 953 pRuntime->PutArrayElement(arColor, 1, pRuntime->NewNumber(0)); 954 pRuntime->PutArrayElement(arColor, 2, pRuntime->NewNumber(0)); 955 pRuntime->PutArrayElement(arColor, 3, pRuntime->NewNumber(0)); 956 957 CJS_Return result = fTarget->get_text_color(pRuntime); 958 CFX_Color crProp = color::ConvertArrayToPWLColor( 959 pRuntime, pRuntime->ToArray(result.Return())); 960 CFX_Color crColor = color::ConvertArrayToPWLColor(pRuntime, arColor); 961 if (crColor != crProp) 962 fTarget->set_text_color(pRuntime, arColor); 963 } 964 } 965 } 966 #endif 967 return CJS_Return(true); 968 } 969 970 // function AFNumber_Keystroke(nDec, sepStyle, negStyle, currStyle, strCurrency, 971 // bCurrencyPrepend) 972 CJS_Return CJS_PublicMethods::AFNumber_Keystroke( 973 CJS_Runtime* pRuntime, 974 const std::vector<v8::Local<v8::Value>>& params) { 975 if (params.size() < 2) 976 return CJS_Return(false); 977 978 CJS_EventContext* pContext = pRuntime->GetCurrentEventContext(); 979 CJS_EventHandler* pEvent = pContext->GetEventHandler(); 980 if (!pEvent->m_pValue) 981 return CJS_Return(false); 982 983 WideString& val = pEvent->Value(); 984 WideString& wstrChange = pEvent->Change(); 985 WideString wstrValue = val; 986 987 if (pEvent->WillCommit()) { 988 WideString swTemp = StrTrim(wstrValue); 989 if (swTemp.IsEmpty()) 990 return CJS_Return(true); 991 992 NormalizeDecimalMarkW(&swTemp); 993 if (!IsNumber(swTemp.c_str())) { 994 pEvent->Rc() = false; 995 WideString sError = JSGetStringFromID(JSMessage::kInvalidInputError); 996 AlertIfPossible(pContext, sError.c_str()); 997 return CJS_Return(sError); 998 } 999 // It happens after the last keystroke and before validating, 1000 return CJS_Return(true); 1001 } 1002 1003 WideString wstrSelected; 1004 if (pEvent->SelStart() != -1) { 1005 wstrSelected = wstrValue.Mid(pEvent->SelStart(), 1006 pEvent->SelEnd() - pEvent->SelStart()); 1007 } 1008 1009 bool bHasSign = wstrValue.Contains(L'-') && !wstrSelected.Contains(L'-'); 1010 if (bHasSign) { 1011 // can't insert "change" in front to sign postion. 1012 if (pEvent->SelStart() == 0) { 1013 pEvent->Rc() = false; 1014 return CJS_Return(true); 1015 } 1016 } 1017 1018 int iSepStyle = ValidStyleOrZero(pRuntime->ToInt32(params[1])); 1019 const wchar_t cSep = DecimalMarkForStyle(iSepStyle); 1020 1021 bool bHasSep = wstrValue.Contains(cSep); 1022 for (size_t i = 0; i < wstrChange.GetLength(); ++i) { 1023 if (wstrChange[i] == cSep) { 1024 if (bHasSep) { 1025 pEvent->Rc() = false; 1026 return CJS_Return(true); 1027 } 1028 bHasSep = true; 1029 continue; 1030 } 1031 if (wstrChange[i] == L'-') { 1032 if (bHasSign) { 1033 pEvent->Rc() = false; 1034 return CJS_Return(true); 1035 } 1036 // sign's position is not correct 1037 if (i != 0) { 1038 pEvent->Rc() = false; 1039 return CJS_Return(true); 1040 } 1041 if (pEvent->SelStart() != 0) { 1042 pEvent->Rc() = false; 1043 return CJS_Return(true); 1044 } 1045 bHasSign = true; 1046 continue; 1047 } 1048 1049 if (!std::iswdigit(wstrChange[i])) { 1050 pEvent->Rc() = false; 1051 return CJS_Return(true); 1052 } 1053 } 1054 1055 val = CalcMergedString(pEvent, wstrValue, wstrChange); 1056 return CJS_Return(true); 1057 } 1058 1059 // function AFPercent_Format(nDec, sepStyle) 1060 CJS_Return CJS_PublicMethods::AFPercent_Format( 1061 CJS_Runtime* pRuntime, 1062 const std::vector<v8::Local<v8::Value>>& params) { 1063 #if _FX_OS_ != _FX_OS_ANDROID_ 1064 if (params.size() != 2) 1065 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 1066 1067 CJS_EventHandler* pEvent = 1068 pRuntime->GetCurrentEventContext()->GetEventHandler(); 1069 if (!pEvent->m_pValue) 1070 return CJS_Return(false); 1071 1072 WideString& Value = pEvent->Value(); 1073 ByteString strValue = StrTrim(ByteString::FromUnicode(Value)); 1074 if (strValue.IsEmpty()) 1075 return CJS_Return(true); 1076 1077 int iDec = abs(pRuntime->ToInt32(params[0])); 1078 int iSepStyle = ValidStyleOrZero(pRuntime->ToInt32(params[1])); 1079 1080 // for processing decimal places 1081 double dValue = atof(strValue.c_str()); 1082 dValue *= 100; 1083 if (iDec > 0) 1084 dValue += kDoubleCorrect; 1085 1086 int iDec2; 1087 int iNegative = 0; 1088 strValue = fcvt(dValue, iDec, &iDec2, &iNegative); 1089 if (strValue.IsEmpty()) { 1090 dValue = 0; 1091 strValue = fcvt(dValue, iDec, &iDec2, &iNegative); 1092 } 1093 1094 if (iDec2 < 0) { 1095 ByteString zeros; 1096 char* zeros_ptr = zeros.GetBuffer(abs(iDec2)); 1097 memset(zeros_ptr, '0', abs(iDec2)); 1098 strValue = zeros + strValue; 1099 1100 iDec2 = 0; 1101 } 1102 int iMax = strValue.GetLength(); 1103 if (iDec2 > iMax) { 1104 for (int iNum = 0; iNum <= iDec2 - iMax; iNum++) 1105 strValue += '0'; 1106 1107 iMax = iDec2 + 1; 1108 } 1109 1110 // for processing seperator style 1111 if (iDec2 < iMax) { 1112 char mark = DecimalMarkForStyle(iSepStyle); 1113 strValue.Insert(iDec2, mark); 1114 iMax++; 1115 1116 if (iDec2 == 0) 1117 strValue.Insert(iDec2, '0'); 1118 } 1119 if (IsStyleWithDigitSeparator(iSepStyle)) { 1120 char cSeparator = DigitSeparatorForStyle(iSepStyle); 1121 for (int iDecPositive = iDec2 - 3; iDecPositive > 0; iDecPositive -= 3) { 1122 strValue.Insert(iDecPositive, cSeparator); 1123 iMax++; 1124 } 1125 } 1126 1127 // negative mark 1128 if (iNegative) 1129 strValue.InsertAtFront('-'); 1130 1131 strValue += '%'; 1132 Value = WideString::FromLocal(strValue.AsStringView()); 1133 #endif 1134 return CJS_Return(true); 1135 } 1136 1137 // AFPercent_Keystroke(nDec, sepStyle) 1138 CJS_Return CJS_PublicMethods::AFPercent_Keystroke( 1139 CJS_Runtime* pRuntime, 1140 const std::vector<v8::Local<v8::Value>>& params) { 1141 return AFNumber_Keystroke(pRuntime, params); 1142 } 1143 1144 // function AFDate_FormatEx(cFormat) 1145 CJS_Return CJS_PublicMethods::AFDate_FormatEx( 1146 CJS_Runtime* pRuntime, 1147 const std::vector<v8::Local<v8::Value>>& params) { 1148 if (params.size() != 1) 1149 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 1150 1151 CJS_EventContext* pContext = pRuntime->GetCurrentEventContext(); 1152 CJS_EventHandler* pEvent = pContext->GetEventHandler(); 1153 if (!pEvent->m_pValue) 1154 return CJS_Return(false); 1155 1156 WideString& val = pEvent->Value(); 1157 WideString strValue = val; 1158 if (strValue.IsEmpty()) 1159 return CJS_Return(true); 1160 1161 WideString sFormat = pRuntime->ToWideString(params[0]); 1162 double dDate; 1163 if (strValue.Contains(L"GMT")) { 1164 // for GMT format time 1165 // such as "Tue Aug 11 14:24:16 GMT+08002009" 1166 dDate = MakeInterDate(strValue); 1167 } else { 1168 dDate = MakeRegularDate(strValue, sFormat, nullptr); 1169 } 1170 1171 if (std::isnan(dDate)) { 1172 WideString swMsg = WideString::Format( 1173 JSGetStringFromID(JSMessage::kParseDateError).c_str(), sFormat.c_str()); 1174 AlertIfPossible(pContext, swMsg.c_str()); 1175 return CJS_Return(false); 1176 } 1177 1178 val = MakeFormatDate(dDate, sFormat); 1179 return CJS_Return(true); 1180 } 1181 1182 double CJS_PublicMethods::MakeInterDate(const WideString& strValue) { 1183 std::vector<WideString> wsArray; 1184 WideString sTemp; 1185 for (const auto& c : strValue) { 1186 if (c == L' ' || c == L':') { 1187 wsArray.push_back(sTemp); 1188 sTemp.clear(); 1189 continue; 1190 } 1191 sTemp += c; 1192 } 1193 wsArray.push_back(sTemp); 1194 if (wsArray.size() != 8) 1195 return 0; 1196 1197 int nMonth = 1; 1198 sTemp = wsArray[1]; 1199 for (size_t i = 0; i < FX_ArraySize(kMonths); ++i) { 1200 if (sTemp.Compare(kMonths[i]) == 0) { 1201 nMonth = i + 1; 1202 break; 1203 } 1204 } 1205 1206 int nDay = FX_atof(wsArray[2].AsStringView()); 1207 int nHour = FX_atof(wsArray[3].AsStringView()); 1208 int nMin = FX_atof(wsArray[4].AsStringView()); 1209 int nSec = FX_atof(wsArray[5].AsStringView()); 1210 int nYear = FX_atof(wsArray[7].AsStringView()); 1211 double dRet = JS_MakeDate(JS_MakeDay(nYear, nMonth - 1, nDay), 1212 JS_MakeTime(nHour, nMin, nSec, 0)); 1213 if (std::isnan(dRet)) 1214 dRet = JS_DateParse(strValue); 1215 1216 return dRet; 1217 } 1218 1219 // AFDate_KeystrokeEx(cFormat) 1220 CJS_Return CJS_PublicMethods::AFDate_KeystrokeEx( 1221 CJS_Runtime* pRuntime, 1222 const std::vector<v8::Local<v8::Value>>& params) { 1223 if (params.size() != 1) { 1224 return CJS_Return( 1225 WideString(L"AFDate_KeystrokeEx's parameters' size r not correct")); 1226 } 1227 1228 CJS_EventContext* pContext = pRuntime->GetCurrentEventContext(); 1229 CJS_EventHandler* pEvent = pContext->GetEventHandler(); 1230 if (pEvent->WillCommit()) { 1231 if (!pEvent->m_pValue) 1232 return CJS_Return(false); 1233 1234 const WideString& strValue = pEvent->Value(); 1235 if (strValue.IsEmpty()) 1236 return CJS_Return(true); 1237 1238 WideString sFormat = pRuntime->ToWideString(params[0]); 1239 bool bWrongFormat = false; 1240 double dRet = MakeRegularDate(strValue, sFormat, &bWrongFormat); 1241 if (bWrongFormat || std::isnan(dRet)) { 1242 WideString swMsg = WideString::Format( 1243 JSGetStringFromID(JSMessage::kParseDateError).c_str(), 1244 sFormat.c_str()); 1245 AlertIfPossible(pContext, swMsg.c_str()); 1246 pEvent->Rc() = false; 1247 return CJS_Return(true); 1248 } 1249 } 1250 return CJS_Return(true); 1251 } 1252 1253 CJS_Return CJS_PublicMethods::AFDate_Format( 1254 CJS_Runtime* pRuntime, 1255 const std::vector<v8::Local<v8::Value>>& params) { 1256 if (params.size() != 1) 1257 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 1258 1259 static constexpr const wchar_t* cFormats[] = {L"m/d", 1260 L"m/d/yy", 1261 L"mm/dd/yy", 1262 L"mm/yy", 1263 L"d-mmm", 1264 L"d-mmm-yy", 1265 L"dd-mmm-yy", 1266 L"yy-mm-dd", 1267 L"mmm-yy", 1268 L"mmmm-yy", 1269 L"mmm d, yyyy", 1270 L"mmmm d, yyyy", 1271 L"m/d/yy h:MM tt", 1272 L"m/d/yy HH:MM"}; 1273 1274 int iIndex = 1275 WithinBoundsOrZero(pRuntime->ToInt32(params[0]), FX_ArraySize(cFormats)); 1276 std::vector<v8::Local<v8::Value>> newParams; 1277 newParams.push_back(pRuntime->NewString(cFormats[iIndex])); 1278 return AFDate_FormatEx(pRuntime, newParams); 1279 } 1280 1281 // AFDate_KeystrokeEx(cFormat) 1282 CJS_Return CJS_PublicMethods::AFDate_Keystroke( 1283 CJS_Runtime* pRuntime, 1284 const std::vector<v8::Local<v8::Value>>& params) { 1285 if (params.size() != 1) 1286 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 1287 1288 static constexpr const wchar_t* cFormats[] = {L"m/d", 1289 L"m/d/yy", 1290 L"mm/dd/yy", 1291 L"mm/yy", 1292 L"d-mmm", 1293 L"d-mmm-yy", 1294 L"dd-mmm-yy", 1295 L"yy-mm-dd", 1296 L"mmm-yy", 1297 L"mmmm-yy", 1298 L"mmm d, yyyy", 1299 L"mmmm d, yyyy", 1300 L"m/d/yy h:MM tt", 1301 L"m/d/yy HH:MM"}; 1302 1303 int iIndex = 1304 WithinBoundsOrZero(pRuntime->ToInt32(params[0]), FX_ArraySize(cFormats)); 1305 std::vector<v8::Local<v8::Value>> newParams; 1306 newParams.push_back(pRuntime->NewString(cFormats[iIndex])); 1307 return AFDate_KeystrokeEx(pRuntime, newParams); 1308 } 1309 1310 // function AFTime_Format(ptf) 1311 CJS_Return CJS_PublicMethods::AFTime_Format( 1312 CJS_Runtime* pRuntime, 1313 const std::vector<v8::Local<v8::Value>>& params) { 1314 if (params.size() != 1) 1315 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 1316 1317 static constexpr const wchar_t* cFormats[] = {L"HH:MM", L"h:MM tt", 1318 L"HH:MM:ss", L"h:MM:ss tt"}; 1319 1320 int iIndex = 1321 WithinBoundsOrZero(pRuntime->ToInt32(params[0]), FX_ArraySize(cFormats)); 1322 std::vector<v8::Local<v8::Value>> newParams; 1323 newParams.push_back(pRuntime->NewString(cFormats[iIndex])); 1324 return AFDate_FormatEx(pRuntime, newParams); 1325 } 1326 1327 CJS_Return CJS_PublicMethods::AFTime_Keystroke( 1328 CJS_Runtime* pRuntime, 1329 const std::vector<v8::Local<v8::Value>>& params) { 1330 if (params.size() != 1) 1331 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 1332 1333 static constexpr const wchar_t* cFormats[] = {L"HH:MM", L"h:MM tt", 1334 L"HH:MM:ss", L"h:MM:ss tt"}; 1335 1336 int iIndex = 1337 WithinBoundsOrZero(pRuntime->ToInt32(params[0]), FX_ArraySize(cFormats)); 1338 std::vector<v8::Local<v8::Value>> newParams; 1339 newParams.push_back(pRuntime->NewString(cFormats[iIndex])); 1340 return AFDate_KeystrokeEx(pRuntime, newParams); 1341 } 1342 1343 CJS_Return CJS_PublicMethods::AFTime_FormatEx( 1344 CJS_Runtime* pRuntime, 1345 const std::vector<v8::Local<v8::Value>>& params) { 1346 return AFDate_FormatEx(pRuntime, params); 1347 } 1348 1349 CJS_Return CJS_PublicMethods::AFTime_KeystrokeEx( 1350 CJS_Runtime* pRuntime, 1351 const std::vector<v8::Local<v8::Value>>& params) { 1352 return AFDate_KeystrokeEx(pRuntime, params); 1353 } 1354 1355 // function AFSpecial_Format(psf) 1356 CJS_Return CJS_PublicMethods::AFSpecial_Format( 1357 CJS_Runtime* pRuntime, 1358 const std::vector<v8::Local<v8::Value>>& params) { 1359 if (params.size() != 1) 1360 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 1361 1362 CJS_EventHandler* pEvent = 1363 pRuntime->GetCurrentEventContext()->GetEventHandler(); 1364 if (!pEvent->m_pValue) 1365 return CJS_Return(false); 1366 1367 const WideString& wsSource = pEvent->Value(); 1368 WideString wsFormat; 1369 switch (pRuntime->ToInt32(params[0])) { 1370 case 0: 1371 wsFormat = L"99999"; 1372 break; 1373 case 1: 1374 wsFormat = L"99999-9999"; 1375 break; 1376 case 2: 1377 if (util::printx(L"9999999999", wsSource).GetLength() >= 10) 1378 wsFormat = L"(999) 999-9999"; 1379 else 1380 wsFormat = L"999-9999"; 1381 break; 1382 case 3: 1383 wsFormat = L"999-99-9999"; 1384 break; 1385 } 1386 1387 pEvent->Value() = util::printx(wsFormat, wsSource); 1388 return CJS_Return(true); 1389 } 1390 1391 // function AFSpecial_KeystrokeEx(mask) 1392 CJS_Return CJS_PublicMethods::AFSpecial_KeystrokeEx( 1393 CJS_Runtime* pRuntime, 1394 const std::vector<v8::Local<v8::Value>>& params) { 1395 if (params.size() < 1) 1396 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 1397 1398 CJS_EventContext* pContext = pRuntime->GetCurrentEventContext(); 1399 CJS_EventHandler* pEvent = pContext->GetEventHandler(); 1400 if (!pEvent->m_pValue) 1401 return CJS_Return(false); 1402 1403 const WideString& valEvent = pEvent->Value(); 1404 WideString wstrMask = pRuntime->ToWideString(params[0]); 1405 if (wstrMask.IsEmpty()) 1406 return CJS_Return(true); 1407 1408 if (pEvent->WillCommit()) { 1409 if (valEvent.IsEmpty()) 1410 return CJS_Return(true); 1411 1412 size_t iIndexMask = 0; 1413 for (; iIndexMask < valEvent.GetLength(); ++iIndexMask) { 1414 if (!MaskSatisfied(valEvent[iIndexMask], wstrMask[iIndexMask])) 1415 break; 1416 } 1417 1418 if (iIndexMask != wstrMask.GetLength() || 1419 (iIndexMask != valEvent.GetLength() && wstrMask.GetLength() != 0)) { 1420 AlertIfPossible(pContext, 1421 JSGetStringFromID(JSMessage::kInvalidInputError).c_str()); 1422 pEvent->Rc() = false; 1423 } 1424 return CJS_Return(true); 1425 } 1426 1427 WideString& wideChange = pEvent->Change(); 1428 if (wideChange.IsEmpty()) 1429 return CJS_Return(true); 1430 1431 WideString wChange = wideChange; 1432 size_t iIndexMask = pEvent->SelStart(); 1433 size_t combined_len = valEvent.GetLength() + wChange.GetLength() + 1434 pEvent->SelStart() - pEvent->SelEnd(); 1435 if (combined_len > wstrMask.GetLength()) { 1436 AlertIfPossible(pContext, 1437 JSGetStringFromID(JSMessage::kParamTooLongError).c_str()); 1438 pEvent->Rc() = false; 1439 return CJS_Return(true); 1440 } 1441 1442 if (iIndexMask >= wstrMask.GetLength() && !wChange.IsEmpty()) { 1443 AlertIfPossible(pContext, 1444 JSGetStringFromID(JSMessage::kParamTooLongError).c_str()); 1445 pEvent->Rc() = false; 1446 return CJS_Return(true); 1447 } 1448 1449 for (size_t i = 0; i < wChange.GetLength(); ++i) { 1450 if (iIndexMask >= wstrMask.GetLength()) { 1451 AlertIfPossible(pContext, 1452 JSGetStringFromID(JSMessage::kParamTooLongError).c_str()); 1453 pEvent->Rc() = false; 1454 return CJS_Return(true); 1455 } 1456 wchar_t wMask = wstrMask[iIndexMask]; 1457 if (!IsReservedMaskChar(wMask)) 1458 wChange.SetAt(i, wMask); 1459 1460 if (!MaskSatisfied(wChange[i], wMask)) { 1461 pEvent->Rc() = false; 1462 return CJS_Return(true); 1463 } 1464 iIndexMask++; 1465 } 1466 wideChange = wChange; 1467 return CJS_Return(true); 1468 } 1469 1470 // function AFSpecial_Keystroke(psf) 1471 CJS_Return CJS_PublicMethods::AFSpecial_Keystroke( 1472 CJS_Runtime* pRuntime, 1473 const std::vector<v8::Local<v8::Value>>& params) { 1474 if (params.size() != 1) 1475 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 1476 1477 CJS_EventHandler* pEvent = 1478 pRuntime->GetCurrentEventContext()->GetEventHandler(); 1479 if (!pEvent->m_pValue) 1480 return CJS_Return(false); 1481 1482 const char* cFormat = ""; 1483 switch (pRuntime->ToInt32(params[0])) { 1484 case 0: 1485 cFormat = "99999"; 1486 break; 1487 case 1: 1488 cFormat = "999999999"; 1489 break; 1490 case 2: 1491 if (pEvent->Value().GetLength() + pEvent->Change().GetLength() > 7) 1492 cFormat = "9999999999"; 1493 else 1494 cFormat = "9999999"; 1495 break; 1496 case 3: 1497 cFormat = "999999999"; 1498 break; 1499 } 1500 1501 std::vector<v8::Local<v8::Value>> params2; 1502 params2.push_back(pRuntime->NewString(cFormat)); 1503 return AFSpecial_KeystrokeEx(pRuntime, params2); 1504 } 1505 1506 CJS_Return CJS_PublicMethods::AFMergeChange( 1507 CJS_Runtime* pRuntime, 1508 const std::vector<v8::Local<v8::Value>>& params) { 1509 if (params.size() != 1) 1510 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 1511 1512 CJS_EventHandler* pEventHandler = 1513 pRuntime->GetCurrentEventContext()->GetEventHandler(); 1514 1515 WideString swValue; 1516 if (pEventHandler->m_pValue) 1517 swValue = pEventHandler->Value(); 1518 1519 if (pEventHandler->WillCommit()) 1520 return CJS_Return(pRuntime->NewString(swValue.c_str())); 1521 1522 WideString merged = 1523 CalcMergedString(pEventHandler, swValue, pEventHandler->Change()); 1524 return CJS_Return(pRuntime->NewString(merged.c_str())); 1525 } 1526 1527 CJS_Return CJS_PublicMethods::AFParseDateEx( 1528 CJS_Runtime* pRuntime, 1529 const std::vector<v8::Local<v8::Value>>& params) { 1530 if (params.size() != 2) 1531 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 1532 1533 WideString sValue = pRuntime->ToWideString(params[0]); 1534 WideString sFormat = pRuntime->ToWideString(params[1]); 1535 double dDate = MakeRegularDate(sValue, sFormat, nullptr); 1536 if (std::isnan(dDate)) { 1537 WideString swMsg = WideString::Format( 1538 JSGetStringFromID(JSMessage::kParseDateError).c_str(), sFormat.c_str()); 1539 AlertIfPossible(pRuntime->GetCurrentEventContext(), swMsg.c_str()); 1540 return CJS_Return(false); 1541 } 1542 return CJS_Return(pRuntime->NewNumber(dDate)); 1543 } 1544 1545 CJS_Return CJS_PublicMethods::AFSimple( 1546 CJS_Runtime* pRuntime, 1547 const std::vector<v8::Local<v8::Value>>& params) { 1548 if (params.size() != 3) 1549 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 1550 1551 return CJS_Return(pRuntime->NewNumber(static_cast<double>(AF_Simple( 1552 pRuntime->ToWideString(params[0]).c_str(), pRuntime->ToDouble(params[1]), 1553 pRuntime->ToDouble(params[2]))))); 1554 } 1555 1556 CJS_Return CJS_PublicMethods::AFMakeNumber( 1557 CJS_Runtime* pRuntime, 1558 const std::vector<v8::Local<v8::Value>>& params) { 1559 if (params.size() != 1) 1560 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 1561 1562 WideString ws = pRuntime->ToWideString(params[0]); 1563 NormalizeDecimalMarkW(&ws); 1564 1565 v8::Local<v8::Value> val = 1566 pRuntime->MaybeCoerceToNumber(pRuntime->NewString(ws.c_str())); 1567 if (!val->IsNumber()) 1568 return CJS_Return(pRuntime->NewNumber(0)); 1569 return CJS_Return(val); 1570 } 1571 1572 CJS_Return CJS_PublicMethods::AFSimple_Calculate( 1573 CJS_Runtime* pRuntime, 1574 const std::vector<v8::Local<v8::Value>>& params) { 1575 if (params.size() != 2) 1576 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 1577 1578 if ((params[1].IsEmpty() || !params[1]->IsArray()) && !params[1]->IsString()) 1579 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 1580 1581 CPDFSDK_InterForm* pReaderInterForm = 1582 pRuntime->GetFormFillEnv()->GetInterForm(); 1583 CPDF_InterForm* pInterForm = pReaderInterForm->GetInterForm(); 1584 1585 WideString sFunction = pRuntime->ToWideString(params[0]); 1586 double dValue = wcscmp(sFunction.c_str(), L"PRD") == 0 ? 1.0 : 0.0; 1587 1588 v8::Local<v8::Array> FieldNameArray = 1589 AF_MakeArrayFromList(pRuntime, params[0]); 1590 int nFieldsCount = 0; 1591 for (size_t i = 0; i < pRuntime->GetArrayLength(FieldNameArray); ++i) { 1592 WideString wsFieldName = 1593 pRuntime->ToWideString(pRuntime->GetArrayElement(FieldNameArray, i)); 1594 1595 for (size_t j = 0; j < pInterForm->CountFields(wsFieldName); ++j) { 1596 CPDF_FormField* pFormField = pInterForm->GetField(j, wsFieldName); 1597 if (!pFormField) 1598 continue; 1599 1600 double dTemp = 0.0; 1601 switch (pFormField->GetFieldType()) { 1602 case FormFieldType::kTextField: 1603 case FormFieldType::kComboBox: { 1604 WideString trimmed = pFormField->GetValue(); 1605 trimmed.TrimRight(); 1606 trimmed.TrimLeft(); 1607 dTemp = FX_atof(trimmed.AsStringView()); 1608 break; 1609 } 1610 case FormFieldType::kPushButton: 1611 break; 1612 case FormFieldType::kCheckBox: 1613 case FormFieldType::kRadioButton: 1614 for (int c = 0; c < pFormField->CountControls(); ++c) { 1615 CPDF_FormControl* pFormCtrl = pFormField->GetControl(c); 1616 if (!pFormField || !pFormCtrl->IsChecked()) 1617 continue; 1618 1619 WideString trimmed = pFormCtrl->GetExportValue(); 1620 trimmed.TrimRight(); 1621 trimmed.TrimLeft(); 1622 dTemp = FX_atof(trimmed.AsStringView()); 1623 break; 1624 } 1625 break; 1626 case FormFieldType::kListBox: 1627 if (pFormField->CountSelectedItems() <= 1) { 1628 WideString trimmed = pFormField->GetValue(); 1629 trimmed.TrimRight(); 1630 trimmed.TrimLeft(); 1631 dTemp = FX_atof(trimmed.AsStringView()); 1632 } 1633 break; 1634 default: 1635 break; 1636 } 1637 1638 if (i == 0 && j == 0 && 1639 (wcscmp(sFunction.c_str(), L"MIN") == 0 || 1640 wcscmp(sFunction.c_str(), L"MAX") == 0)) { 1641 dValue = dTemp; 1642 } 1643 dValue = AF_Simple(sFunction.c_str(), dValue, dTemp); 1644 1645 nFieldsCount++; 1646 } 1647 } 1648 1649 if (wcscmp(sFunction.c_str(), L"AVG") == 0 && nFieldsCount > 0) 1650 dValue /= nFieldsCount; 1651 1652 dValue = floor(dValue * FXSYS_pow(10, 6) + 0.49) / FXSYS_pow(10, 6); 1653 1654 CJS_EventContext* pContext = pRuntime->GetCurrentEventContext(); 1655 if (pContext->GetEventHandler()->m_pValue) { 1656 pContext->GetEventHandler()->Value() = 1657 pRuntime->ToWideString(pRuntime->NewNumber(dValue)); 1658 } 1659 1660 return CJS_Return(true); 1661 } 1662 1663 /* This function validates the current event to ensure that its value is 1664 ** within the specified range. */ 1665 CJS_Return CJS_PublicMethods::AFRange_Validate( 1666 CJS_Runtime* pRuntime, 1667 const std::vector<v8::Local<v8::Value>>& params) { 1668 if (params.size() != 4) 1669 CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 1670 1671 CJS_EventContext* pContext = pRuntime->GetCurrentEventContext(); 1672 CJS_EventHandler* pEvent = pContext->GetEventHandler(); 1673 if (!pEvent->m_pValue) 1674 return CJS_Return(false); 1675 1676 if (pEvent->Value().IsEmpty()) 1677 return CJS_Return(true); 1678 1679 double dEentValue = atof(ByteString::FromUnicode(pEvent->Value()).c_str()); 1680 bool bGreaterThan = pRuntime->ToBoolean(params[0]); 1681 double dGreaterThan = pRuntime->ToDouble(params[1]); 1682 bool bLessThan = pRuntime->ToBoolean(params[2]); 1683 double dLessThan = pRuntime->ToDouble(params[3]); 1684 WideString swMsg; 1685 1686 if (bGreaterThan && bLessThan) { 1687 if (dEentValue < dGreaterThan || dEentValue > dLessThan) 1688 swMsg = WideString::Format( 1689 JSGetStringFromID(JSMessage::kRangeBetweenError).c_str(), 1690 pRuntime->ToWideString(params[1]).c_str(), 1691 pRuntime->ToWideString(params[3]).c_str()); 1692 } else if (bGreaterThan) { 1693 if (dEentValue < dGreaterThan) 1694 swMsg = WideString::Format( 1695 JSGetStringFromID(JSMessage::kRangeGreaterError).c_str(), 1696 pRuntime->ToWideString(params[1]).c_str()); 1697 } else if (bLessThan) { 1698 if (dEentValue > dLessThan) 1699 swMsg = WideString::Format( 1700 JSGetStringFromID(JSMessage::kRangeLessError).c_str(), 1701 pRuntime->ToWideString(params[3]).c_str()); 1702 } 1703 1704 if (!swMsg.IsEmpty()) { 1705 AlertIfPossible(pContext, swMsg.c_str()); 1706 pEvent->Rc() = false; 1707 } 1708 return CJS_Return(true); 1709 } 1710 1711 CJS_Return CJS_PublicMethods::AFExtractNums( 1712 CJS_Runtime* pRuntime, 1713 const std::vector<v8::Local<v8::Value>>& params) { 1714 if (params.size() != 1) 1715 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 1716 1717 WideString str = pRuntime->ToWideString(params[0]); 1718 if (str.GetLength() > 0 && IsDigitSeparatorOrDecimalMark(str[0])) 1719 str.InsertAtFront(L'0'); 1720 1721 WideString sPart; 1722 v8::Local<v8::Array> nums = pRuntime->NewArray(); 1723 int nIndex = 0; 1724 for (const auto& wc : str) { 1725 if (std::iswdigit(wc)) { 1726 sPart += wc; 1727 } else if (sPart.GetLength() > 0) { 1728 pRuntime->PutArrayElement(nums, nIndex, 1729 pRuntime->NewString(sPart.c_str())); 1730 sPart.clear(); 1731 nIndex++; 1732 } 1733 } 1734 if (sPart.GetLength() > 0) 1735 pRuntime->PutArrayElement(nums, nIndex, pRuntime->NewString(sPart.c_str())); 1736 1737 if (pRuntime->GetArrayLength(nums) > 0) 1738 return CJS_Return(nums); 1739 return CJS_Return(pRuntime->NewUndefined()); 1740 } 1741