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 "PublicMethods.h" 8 9 #include <algorithm> 10 11 #include "Field.h" 12 #include "JS_Context.h" 13 #include "JS_Define.h" 14 #include "JS_EventHandler.h" 15 #include "JS_Object.h" 16 #include "JS_Runtime.h" 17 #include "JS_Value.h" 18 #include "color.h" 19 #include "core/include/fxcrt/fx_ext.h" 20 #include "fpdfsdk/include/fsdk_mgr.h" // For CPDFDoc_Environment. 21 #include "fpdfsdk/include/javascript/IJavaScript.h" 22 #include "resource.h" 23 #include "util.h" 24 25 #define DOUBLE_CORRECT 0.000000000000001 26 27 BEGIN_JS_STATIC_GLOBAL_FUN(CJS_PublicMethods) 28 JS_STATIC_GLOBAL_FUN_ENTRY(AFNumber_Format) 29 JS_STATIC_GLOBAL_FUN_ENTRY(AFNumber_Keystroke) 30 JS_STATIC_GLOBAL_FUN_ENTRY(AFPercent_Format) 31 JS_STATIC_GLOBAL_FUN_ENTRY(AFPercent_Keystroke) 32 JS_STATIC_GLOBAL_FUN_ENTRY(AFDate_FormatEx) 33 JS_STATIC_GLOBAL_FUN_ENTRY(AFDate_KeystrokeEx) 34 JS_STATIC_GLOBAL_FUN_ENTRY(AFDate_Format) 35 JS_STATIC_GLOBAL_FUN_ENTRY(AFDate_Keystroke) 36 JS_STATIC_GLOBAL_FUN_ENTRY(AFTime_FormatEx) 37 JS_STATIC_GLOBAL_FUN_ENTRY(AFTime_KeystrokeEx) 38 JS_STATIC_GLOBAL_FUN_ENTRY(AFTime_Format) 39 JS_STATIC_GLOBAL_FUN_ENTRY(AFTime_Keystroke) 40 JS_STATIC_GLOBAL_FUN_ENTRY(AFSpecial_Format) 41 JS_STATIC_GLOBAL_FUN_ENTRY(AFSpecial_Keystroke) 42 JS_STATIC_GLOBAL_FUN_ENTRY(AFSpecial_KeystrokeEx) 43 JS_STATIC_GLOBAL_FUN_ENTRY(AFSimple) 44 JS_STATIC_GLOBAL_FUN_ENTRY(AFMakeNumber) 45 JS_STATIC_GLOBAL_FUN_ENTRY(AFSimple_Calculate) 46 JS_STATIC_GLOBAL_FUN_ENTRY(AFRange_Validate) 47 JS_STATIC_GLOBAL_FUN_ENTRY(AFMergeChange) 48 JS_STATIC_GLOBAL_FUN_ENTRY(AFParseDateEx) 49 JS_STATIC_GLOBAL_FUN_ENTRY(AFExtractNums) 50 END_JS_STATIC_GLOBAL_FUN() 51 52 IMPLEMENT_JS_STATIC_GLOBAL_FUN(CJS_PublicMethods) 53 54 static const FX_WCHAR* const months[] = {L"Jan", 55 L"Feb", 56 L"Mar", 57 L"Apr", 58 L"May", 59 L"Jun", 60 L"Jul", 61 L"Aug", 62 L"Sep", 63 L"Oct", 64 L"Nov", 65 L"Dec"}; 66 67 static const FX_WCHAR* const fullmonths[] = {L"January", 68 L"February", 69 L"March", 70 L"April", 71 L"May", 72 L"June", 73 L"July", 74 L"August", 75 L"September", 76 L"October", 77 L"November", 78 L"December"}; 79 80 FX_BOOL CJS_PublicMethods::IsNumber(const FX_WCHAR* string) { 81 CFX_WideString sTrim = StrTrim(string); 82 const FX_WCHAR* pTrim = sTrim.c_str(); 83 const FX_WCHAR* p = pTrim; 84 85 FX_BOOL bDot = FALSE; 86 FX_BOOL bKXJS = FALSE; 87 88 wchar_t c; 89 while ((c = *p)) { 90 if (c == '.' || c == ',') { 91 if (bDot) 92 return FALSE; 93 bDot = TRUE; 94 } else if (c == '-' || c == '+') { 95 if (p != pTrim) 96 return FALSE; 97 } else if (c == 'e' || c == 'E') { 98 if (bKXJS) 99 return FALSE; 100 101 p++; 102 c = *p; 103 if (c == '+' || c == '-') { 104 bKXJS = TRUE; 105 } else { 106 return FALSE; 107 } 108 } else if (!FXSYS_iswdigit(c)) { 109 return FALSE; 110 } 111 p++; 112 } 113 114 return TRUE; 115 } 116 117 FX_BOOL CJS_PublicMethods::maskSatisfied(wchar_t c_Change, wchar_t c_Mask) { 118 switch (c_Mask) { 119 case L'9': 120 return FXSYS_iswdigit(c_Change); 121 case L'A': 122 return FXSYS_iswalpha(c_Change); 123 case L'O': 124 return FXSYS_iswalnum(c_Change); 125 case L'X': 126 return TRUE; 127 default: 128 return (c_Change == c_Mask); 129 } 130 } 131 132 FX_BOOL CJS_PublicMethods::isReservedMaskChar(wchar_t ch) { 133 return ch == L'9' || ch == L'A' || ch == L'O' || ch == L'X'; 134 } 135 136 double CJS_PublicMethods::AF_Simple(const FX_WCHAR* sFuction, 137 double dValue1, 138 double dValue2) { 139 if (FXSYS_wcsicmp(sFuction, L"AVG") == 0 || 140 FXSYS_wcsicmp(sFuction, L"SUM") == 0) { 141 return dValue1 + dValue2; 142 } 143 if (FXSYS_wcsicmp(sFuction, L"PRD") == 0) { 144 return dValue1 * dValue2; 145 } 146 if (FXSYS_wcsicmp(sFuction, L"MIN") == 0) { 147 return std::min(dValue1, dValue2); 148 } 149 if (FXSYS_wcsicmp(sFuction, L"MAX") == 0) { 150 return std::max(dValue1, dValue2); 151 } 152 return dValue1; 153 } 154 155 CFX_WideString CJS_PublicMethods::StrLTrim(const FX_WCHAR* pStr) { 156 while (*pStr && *pStr == L' ') 157 pStr++; 158 159 return pStr; 160 } 161 162 CFX_WideString CJS_PublicMethods::StrRTrim(const FX_WCHAR* pStr) { 163 const FX_WCHAR* p = pStr; 164 while (*p) 165 p++; 166 while (p > pStr && *(p - 1) == L' ') 167 p--; 168 169 return CFX_WideString(pStr, p - pStr); 170 } 171 172 CFX_WideString CJS_PublicMethods::StrTrim(const FX_WCHAR* pStr) { 173 return StrRTrim(StrLTrim(pStr).c_str()); 174 } 175 176 CFX_ByteString CJS_PublicMethods::StrLTrim(const FX_CHAR* pStr) { 177 while (*pStr && *pStr == ' ') 178 pStr++; 179 180 return pStr; 181 } 182 183 CFX_ByteString CJS_PublicMethods::StrRTrim(const FX_CHAR* pStr) { 184 const FX_CHAR* p = pStr; 185 while (*p) 186 p++; 187 while (p > pStr && *(p - 1) == L' ') 188 p--; 189 190 return CFX_ByteString(pStr, p - pStr); 191 } 192 193 CFX_ByteString CJS_PublicMethods::StrTrim(const FX_CHAR* pStr) { 194 return StrRTrim(StrLTrim(pStr)); 195 } 196 197 double CJS_PublicMethods::ParseNumber(const FX_WCHAR* swSource, 198 FX_BOOL& bAllDigits, 199 FX_BOOL& bDot, 200 FX_BOOL& bSign, 201 FX_BOOL& bKXJS) { 202 bDot = FALSE; 203 bSign = FALSE; 204 bKXJS = FALSE; 205 206 FX_BOOL bDigitExist = FALSE; 207 208 const FX_WCHAR* p = swSource; 209 wchar_t c; 210 211 const FX_WCHAR* pStart = NULL; 212 const FX_WCHAR* pEnd = NULL; 213 214 while ((c = *p)) { 215 if (!pStart && c != L' ') { 216 pStart = p; 217 } 218 219 pEnd = p; 220 p++; 221 } 222 223 if (!pStart) { 224 bAllDigits = FALSE; 225 return 0; 226 } 227 228 while (pEnd != pStart) { 229 if (*pEnd == L' ') 230 pEnd--; 231 else 232 break; 233 } 234 235 double dRet = 0; 236 p = pStart; 237 bAllDigits = TRUE; 238 CFX_WideString swDigits; 239 240 while (p <= pEnd) { 241 c = *p; 242 243 if (FXSYS_iswdigit(c)) { 244 swDigits += c; 245 bDigitExist = TRUE; 246 } else { 247 switch (c) { 248 case L' ': 249 bAllDigits = FALSE; 250 break; 251 case L'.': 252 case L',': 253 if (!bDot) { 254 if (bDigitExist) { 255 swDigits += L'.'; 256 } else { 257 swDigits += L'0'; 258 swDigits += L'.'; 259 bDigitExist = TRUE; 260 } 261 262 bDot = TRUE; 263 break; 264 } 265 case 'e': 266 case 'E': 267 if (!bKXJS) { 268 p++; 269 c = *p; 270 if (c == '+' || c == '-') { 271 bKXJS = TRUE; 272 swDigits += 'e'; 273 swDigits += c; 274 } 275 break; 276 } 277 case L'-': 278 if (!bDigitExist && !bSign) { 279 swDigits += c; 280 bSign = TRUE; 281 break; 282 } 283 default: 284 bAllDigits = FALSE; 285 286 if (p != pStart && !bDot && bDigitExist) { 287 swDigits += L'.'; 288 bDot = TRUE; 289 } else { 290 bDot = FALSE; 291 bDigitExist = FALSE; 292 swDigits = L""; 293 } 294 break; 295 } 296 } 297 298 p++; 299 } 300 301 if (swDigits.GetLength() > 0 && swDigits.GetLength() < 17) { 302 CFX_ByteString sDigits = swDigits.UTF8Encode(); 303 304 if (bKXJS) { 305 dRet = atof(sDigits); 306 } else { 307 if (bDot) { 308 char* pStopString; 309 dRet = ::strtod(sDigits, &pStopString); 310 } else { 311 dRet = atol(sDigits); 312 } 313 } 314 } 315 316 return dRet; 317 } 318 319 double CJS_PublicMethods::ParseStringToNumber(const FX_WCHAR* swSource) { 320 FX_BOOL bAllDigits = FALSE; 321 FX_BOOL bDot = FALSE; 322 FX_BOOL bSign = FALSE; 323 FX_BOOL bKXJS = FALSE; 324 325 return ParseNumber(swSource, bAllDigits, bDot, bSign, bKXJS); 326 } 327 328 FX_BOOL CJS_PublicMethods::ConvertStringToNumber(const FX_WCHAR* swSource, 329 double& dRet, 330 FX_BOOL& bDot) { 331 FX_BOOL bAllDigits = FALSE; 332 FX_BOOL bSign = FALSE; 333 FX_BOOL bKXJS = FALSE; 334 335 dRet = ParseNumber(swSource, bAllDigits, bDot, bSign, bKXJS); 336 337 return bAllDigits; 338 } 339 340 CJS_Array CJS_PublicMethods::AF_MakeArrayFromList(CJS_Runtime* pRuntime, 341 CJS_Value val) { 342 CJS_Array StrArray(pRuntime); 343 if (val.IsArrayObject()) { 344 val.ConvertToArray(StrArray); 345 return StrArray; 346 } 347 CFX_WideString wsStr = val.ToCFXWideString(); 348 CFX_ByteString t = CFX_ByteString::FromUnicode(wsStr); 349 const char* p = (const char*)t; 350 351 int ch = ','; 352 int nIndex = 0; 353 354 while (*p) { 355 const char* pTemp = strchr(p, ch); 356 if (!pTemp) { 357 StrArray.SetElement(nIndex, CJS_Value(pRuntime, StrTrim(p).c_str())); 358 break; 359 } 360 361 char* pSub = new char[pTemp - p + 1]; 362 strncpy(pSub, p, pTemp - p); 363 *(pSub + (pTemp - p)) = '\0'; 364 365 StrArray.SetElement(nIndex, CJS_Value(pRuntime, StrTrim(pSub).c_str())); 366 delete[] pSub; 367 368 nIndex++; 369 p = ++pTemp; 370 } 371 return StrArray; 372 } 373 374 int CJS_PublicMethods::ParseStringInteger(const CFX_WideString& string, 375 int nStart, 376 int& nSkip, 377 int nMaxStep) { 378 int nRet = 0; 379 nSkip = 0; 380 for (int i = nStart, sz = string.GetLength(); i < sz; i++) { 381 if (i - nStart > 10) 382 break; 383 384 FX_WCHAR c = string.GetAt(i); 385 if (!FXSYS_iswdigit(c)) 386 break; 387 388 nRet = nRet * 10 + FXSYS_toDecimalDigitWide(c); 389 nSkip = i - nStart + 1; 390 if (nSkip >= nMaxStep) 391 break; 392 } 393 394 return nRet; 395 } 396 397 CFX_WideString CJS_PublicMethods::ParseStringString( 398 const CFX_WideString& string, 399 int nStart, 400 int& nSkip) { 401 CFX_WideString swRet; 402 nSkip = 0; 403 for (int i = nStart, sz = string.GetLength(); i < sz; i++) { 404 FX_WCHAR c = string.GetAt(i); 405 if (!FXSYS_iswdigit(c)) 406 break; 407 408 swRet += c; 409 nSkip = i - nStart + 1; 410 } 411 412 return swRet; 413 } 414 415 double CJS_PublicMethods::ParseNormalDate(const CFX_WideString& value, 416 bool* bWrongFormat) { 417 double dt = JS_GetDateTime(); 418 419 int nYear = JS_GetYearFromTime(dt); 420 int nMonth = JS_GetMonthFromTime(dt) + 1; 421 int nDay = JS_GetDayFromTime(dt); 422 int nHour = JS_GetHourFromTime(dt); 423 int nMin = JS_GetMinFromTime(dt); 424 int nSec = JS_GetSecFromTime(dt); 425 426 int number[3]; 427 428 int nSkip = 0; 429 int nLen = value.GetLength(); 430 int nIndex = 0; 431 int i = 0; 432 while (i < nLen) { 433 if (nIndex > 2) 434 break; 435 436 FX_WCHAR c = value.GetAt(i); 437 if (FXSYS_iswdigit(c)) { 438 number[nIndex++] = ParseStringInteger(value, i, nSkip, 4); 439 i += nSkip; 440 } else { 441 i++; 442 } 443 } 444 445 if (nIndex == 2) { 446 // case2: month/day 447 // case3: day/month 448 if ((number[0] >= 1 && number[0] <= 12) && 449 (number[1] >= 1 && number[1] <= 31)) { 450 nMonth = number[0]; 451 nDay = number[1]; 452 } else if ((number[0] >= 1 && number[0] <= 31) && 453 (number[1] >= 1 && number[1] <= 12)) { 454 nDay = number[0]; 455 nMonth = number[1]; 456 } 457 458 if (bWrongFormat) 459 *bWrongFormat = false; 460 } else if (nIndex == 3) { 461 // case1: year/month/day 462 // case2: month/day/year 463 // case3: day/month/year 464 465 if (number[0] > 12 && (number[1] >= 1 && number[1] <= 12) && 466 (number[2] >= 1 && number[2] <= 31)) { 467 nYear = number[0]; 468 nMonth = number[1]; 469 nDay = number[2]; 470 } else if ((number[0] >= 1 && number[0] <= 12) && 471 (number[1] >= 1 && number[1] <= 31) && number[2] > 31) { 472 nMonth = number[0]; 473 nDay = number[1]; 474 nYear = number[2]; 475 } else if ((number[0] >= 1 && number[0] <= 31) && 476 (number[1] >= 1 && number[1] <= 12) && number[2] > 31) { 477 nDay = number[0]; 478 nMonth = number[1]; 479 nYear = number[2]; 480 } 481 482 if (bWrongFormat) 483 *bWrongFormat = false; 484 } else { 485 if (bWrongFormat) 486 *bWrongFormat = true; 487 return dt; 488 } 489 490 CFX_WideString swTemp; 491 swTemp.Format(L"%d/%d/%d %d:%d:%d", nMonth, nDay, nYear, nHour, nMin, nSec); 492 return JS_DateParse(swTemp.c_str()); 493 } 494 495 double CJS_PublicMethods::MakeRegularDate(const CFX_WideString& value, 496 const CFX_WideString& format, 497 bool* bWrongFormat) { 498 double dt = JS_GetDateTime(); 499 500 if (format.IsEmpty() || value.IsEmpty()) 501 return dt; 502 503 int nYear = JS_GetYearFromTime(dt); 504 int nMonth = JS_GetMonthFromTime(dt) + 1; 505 int nDay = JS_GetDayFromTime(dt); 506 int nHour = JS_GetHourFromTime(dt); 507 int nMin = JS_GetMinFromTime(dt); 508 int nSec = JS_GetSecFromTime(dt); 509 510 int nYearSub = 99; // nYear - 2000; 511 512 FX_BOOL bPm = FALSE; 513 FX_BOOL bExit = FALSE; 514 bool bBadFormat = false; 515 516 int i = 0; 517 int j = 0; 518 519 while (i < format.GetLength()) { 520 if (bExit) 521 break; 522 523 FX_WCHAR c = format.GetAt(i); 524 switch (c) { 525 case ':': 526 case '.': 527 case '-': 528 case '\\': 529 case '/': 530 i++; 531 j++; 532 break; 533 534 case 'y': 535 case 'm': 536 case 'd': 537 case 'H': 538 case 'h': 539 case 'M': 540 case 's': 541 case 't': { 542 int oldj = j; 543 int nSkip = 0; 544 int remaining = format.GetLength() - i - 1; 545 546 if (remaining == 0 || format.GetAt(i + 1) != c) { 547 switch (c) { 548 case 'y': 549 i++; 550 j++; 551 break; 552 case 'm': 553 nMonth = ParseStringInteger(value, j, nSkip, 2); 554 i++; 555 j += nSkip; 556 break; 557 case 'd': 558 nDay = ParseStringInteger(value, j, nSkip, 2); 559 i++; 560 j += nSkip; 561 break; 562 case 'H': 563 nHour = ParseStringInteger(value, j, nSkip, 2); 564 i++; 565 j += nSkip; 566 break; 567 case 'h': 568 nHour = ParseStringInteger(value, j, nSkip, 2); 569 i++; 570 j += nSkip; 571 break; 572 case 'M': 573 nMin = ParseStringInteger(value, j, nSkip, 2); 574 i++; 575 j += nSkip; 576 break; 577 case 's': 578 nSec = ParseStringInteger(value, j, nSkip, 2); 579 i++; 580 j += nSkip; 581 break; 582 case 't': 583 bPm = (j < value.GetLength() && value.GetAt(j) == 'p'); 584 i++; 585 j++; 586 break; 587 } 588 } else if (remaining == 1 || format.GetAt(i + 2) != c) { 589 switch (c) { 590 case 'y': 591 nYear = ParseStringInteger(value, j, nSkip, 4); 592 i += 2; 593 j += nSkip; 594 break; 595 case 'm': 596 nMonth = ParseStringInteger(value, j, nSkip, 2); 597 i += 2; 598 j += nSkip; 599 break; 600 case 'd': 601 nDay = ParseStringInteger(value, j, nSkip, 2); 602 i += 2; 603 j += nSkip; 604 break; 605 case 'H': 606 nHour = ParseStringInteger(value, j, nSkip, 2); 607 i += 2; 608 j += nSkip; 609 break; 610 case 'h': 611 nHour = ParseStringInteger(value, j, nSkip, 2); 612 i += 2; 613 j += nSkip; 614 break; 615 case 'M': 616 nMin = ParseStringInteger(value, j, nSkip, 2); 617 i += 2; 618 j += nSkip; 619 break; 620 case 's': 621 nSec = ParseStringInteger(value, j, nSkip, 2); 622 i += 2; 623 j += nSkip; 624 break; 625 case 't': 626 bPm = (j + 1 < value.GetLength() && value.GetAt(j) == 'p' && 627 value.GetAt(j + 1) == 'm'); 628 i += 2; 629 j += 2; 630 break; 631 } 632 } else if (remaining == 2 || format.GetAt(i + 3) != c) { 633 switch (c) { 634 case 'm': { 635 CFX_WideString sMonth = ParseStringString(value, j, nSkip); 636 FX_BOOL bFind = FALSE; 637 for (int m = 0; m < 12; m++) { 638 if (sMonth.CompareNoCase(months[m]) == 0) { 639 nMonth = m + 1; 640 i += 3; 641 j += nSkip; 642 bFind = TRUE; 643 break; 644 } 645 } 646 647 if (!bFind) { 648 nMonth = ParseStringInteger(value, j, nSkip, 3); 649 i += 3; 650 j += nSkip; 651 } 652 } break; 653 case 'y': 654 break; 655 default: 656 i += 3; 657 j += 3; 658 break; 659 } 660 } else if (remaining == 3 || format.GetAt(i + 4) != c) { 661 switch (c) { 662 case 'y': 663 nYear = ParseStringInteger(value, j, nSkip, 4); 664 j += nSkip; 665 i += 4; 666 break; 667 case 'm': { 668 FX_BOOL bFind = FALSE; 669 670 CFX_WideString sMonth = ParseStringString(value, j, nSkip); 671 sMonth.MakeLower(); 672 673 for (int m = 0; m < 12; m++) { 674 CFX_WideString sFullMonths = fullmonths[m]; 675 sFullMonths.MakeLower(); 676 677 if (sFullMonths.Find(sMonth.c_str(), 0) != -1) { 678 nMonth = m + 1; 679 i += 4; 680 j += nSkip; 681 bFind = TRUE; 682 break; 683 } 684 } 685 686 if (!bFind) { 687 nMonth = ParseStringInteger(value, j, nSkip, 4); 688 i += 4; 689 j += nSkip; 690 } 691 } break; 692 default: 693 i += 4; 694 j += 4; 695 break; 696 } 697 } else { 698 if (j >= value.GetLength() || format.GetAt(i) != value.GetAt(j)) { 699 bBadFormat = true; 700 bExit = TRUE; 701 } 702 i++; 703 j++; 704 } 705 706 if (oldj == j) { 707 bBadFormat = true; 708 bExit = TRUE; 709 } 710 } 711 712 break; 713 default: 714 if (value.GetLength() <= j) { 715 bExit = TRUE; 716 } else if (format.GetAt(i) != value.GetAt(j)) { 717 bBadFormat = true; 718 bExit = TRUE; 719 } 720 721 i++; 722 j++; 723 break; 724 } 725 } 726 727 if (bPm) 728 nHour += 12; 729 730 if (nYear >= 0 && nYear <= nYearSub) 731 nYear += 2000; 732 733 if (nMonth < 1 || nMonth > 12) 734 bBadFormat = true; 735 736 if (nDay < 1 || nDay > 31) 737 bBadFormat = true; 738 739 if (nHour < 0 || nHour > 24) 740 bBadFormat = true; 741 742 if (nMin < 0 || nMin > 60) 743 bBadFormat = true; 744 745 if (nSec < 0 || nSec > 60) 746 bBadFormat = true; 747 748 double dRet = 0; 749 750 if (bBadFormat) { 751 dRet = ParseNormalDate(value, &bBadFormat); 752 } else { 753 dRet = JS_MakeDate(JS_MakeDay(nYear, nMonth - 1, nDay), 754 JS_MakeTime(nHour, nMin, nSec, 0)); 755 756 if (JS_PortIsNan(dRet)) { 757 dRet = JS_DateParse(value.c_str()); 758 } 759 } 760 761 if (JS_PortIsNan(dRet)) { 762 dRet = ParseNormalDate(value, &bBadFormat); 763 } 764 765 if (bWrongFormat) 766 *bWrongFormat = bBadFormat; 767 return dRet; 768 } 769 770 CFX_WideString CJS_PublicMethods::MakeFormatDate(double dDate, 771 const CFX_WideString& format) { 772 CFX_WideString sRet = L"", sPart = L""; 773 774 int nYear = JS_GetYearFromTime(dDate); 775 int nMonth = JS_GetMonthFromTime(dDate) + 1; 776 int nDay = JS_GetDayFromTime(dDate); 777 int nHour = JS_GetHourFromTime(dDate); 778 int nMin = JS_GetMinFromTime(dDate); 779 int nSec = JS_GetSecFromTime(dDate); 780 781 int i = 0; 782 while (i < format.GetLength()) { 783 FX_WCHAR c = format.GetAt(i); 784 int remaining = format.GetLength() - i - 1; 785 sPart = L""; 786 switch (c) { 787 case 'y': 788 case 'm': 789 case 'd': 790 case 'H': 791 case 'h': 792 case 'M': 793 case 's': 794 case 't': 795 if (remaining == 0 || format.GetAt(i + 1) != c) { 796 switch (c) { 797 case 'y': 798 sPart += c; 799 break; 800 case 'm': 801 sPart.Format(L"%d", nMonth); 802 break; 803 case 'd': 804 sPart.Format(L"%d", nDay); 805 break; 806 case 'H': 807 sPart.Format(L"%d", nHour); 808 break; 809 case 'h': 810 sPart.Format(L"%d", nHour > 12 ? nHour - 12 : nHour); 811 break; 812 case 'M': 813 sPart.Format(L"%d", nMin); 814 break; 815 case 's': 816 sPart.Format(L"%d", nSec); 817 break; 818 case 't': 819 sPart += nHour > 12 ? 'p' : 'a'; 820 break; 821 } 822 i++; 823 } else if (remaining == 1 || format.GetAt(i + 2) != c) { 824 switch (c) { 825 case 'y': 826 sPart.Format(L"%02d", nYear - (nYear / 100) * 100); 827 break; 828 case 'm': 829 sPart.Format(L"%02d", nMonth); 830 break; 831 case 'd': 832 sPart.Format(L"%02d", nDay); 833 break; 834 case 'H': 835 sPart.Format(L"%02d", nHour); 836 break; 837 case 'h': 838 sPart.Format(L"%02d", nHour > 12 ? nHour - 12 : nHour); 839 break; 840 case 'M': 841 sPart.Format(L"%02d", nMin); 842 break; 843 case 's': 844 sPart.Format(L"%02d", nSec); 845 break; 846 case 't': 847 sPart = nHour > 12 ? L"pm" : L"am"; 848 break; 849 } 850 i += 2; 851 } else if (remaining == 2 || format.GetAt(i + 3) != c) { 852 switch (c) { 853 case 'm': 854 i += 3; 855 if (nMonth > 0 && nMonth <= 12) 856 sPart += months[nMonth - 1]; 857 break; 858 default: 859 i += 3; 860 sPart += c; 861 sPart += c; 862 sPart += c; 863 break; 864 } 865 } else if (remaining == 3 || format.GetAt(i + 4) != c) { 866 switch (c) { 867 case 'y': 868 sPart.Format(L"%04d", nYear); 869 i += 4; 870 break; 871 case 'm': 872 i += 4; 873 if (nMonth > 0 && nMonth <= 12) 874 sPart += fullmonths[nMonth - 1]; 875 break; 876 default: 877 i += 4; 878 sPart += c; 879 sPart += c; 880 sPart += c; 881 sPart += c; 882 break; 883 } 884 } else { 885 i++; 886 sPart += c; 887 } 888 break; 889 default: 890 i++; 891 sPart += c; 892 break; 893 } 894 895 sRet += sPart; 896 } 897 898 return sRet; 899 } 900 901 /* -------------------------------------------------------------------------- */ 902 903 // function AFNumber_Format(nDec, sepStyle, negStyle, currStyle, strCurrency, 904 // bCurrencyPrepend) 905 FX_BOOL CJS_PublicMethods::AFNumber_Format(IJS_Context* cc, 906 const std::vector<CJS_Value>& params, 907 CJS_Value& vRet, 908 CFX_WideString& sError) { 909 #if _FX_OS_ != _FX_ANDROID_ 910 CJS_Context* pContext = (CJS_Context*)cc; 911 if (params.size() != 6) { 912 sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); 913 return FALSE; 914 } 915 916 CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); 917 CJS_EventHandler* pEvent = pContext->GetEventHandler(); 918 if (!pEvent->m_pValue) 919 return FALSE; 920 921 CFX_WideString& Value = pEvent->Value(); 922 CFX_ByteString strValue = StrTrim(CFX_ByteString::FromUnicode(Value)); 923 if (strValue.IsEmpty()) 924 return TRUE; 925 926 int iDec = params[0].ToInt(); 927 int iSepStyle = params[1].ToInt(); 928 int iNegStyle = params[2].ToInt(); 929 // params[3] is iCurrStyle, it's not used. 930 std::wstring wstrCurrency(params[4].ToCFXWideString().c_str()); 931 FX_BOOL bCurrencyPrepend = params[5].ToBool(); 932 933 if (iDec < 0) 934 iDec = -iDec; 935 936 if (iSepStyle < 0 || iSepStyle > 3) 937 iSepStyle = 0; 938 939 if (iNegStyle < 0 || iNegStyle > 3) 940 iNegStyle = 0; 941 942 ////////////////////////////////////////////////////// 943 // for processing decimal places 944 strValue.Replace(",", "."); 945 double dValue = atof(strValue); 946 if (iDec > 0) 947 dValue += DOUBLE_CORRECT; 948 949 int iDec2; 950 int iNegative = 0; 951 952 strValue = fcvt(dValue, iDec, &iDec2, &iNegative); 953 if (strValue.IsEmpty()) { 954 dValue = 0; 955 strValue = fcvt(dValue, iDec, &iDec2, &iNegative); 956 if (strValue.IsEmpty()) { 957 strValue = "0"; 958 iDec2 = 1; 959 } 960 } 961 962 if (iDec2 < 0) { 963 for (int iNum = 0; iNum < abs(iDec2); iNum++) { 964 strValue = "0" + strValue; 965 } 966 iDec2 = 0; 967 } 968 int iMax = strValue.GetLength(); 969 if (iDec2 > iMax) { 970 for (int iNum = 0; iNum <= iDec2 - iMax; iNum++) { 971 strValue += "0"; 972 } 973 iMax = iDec2 + 1; 974 } 975 /////////////////////////////////////////////////////// 976 // for processing seperator style 977 if (iDec2 < iMax) { 978 if (iSepStyle == 0 || iSepStyle == 1) { 979 strValue.Insert(iDec2, '.'); 980 iMax++; 981 } else if (iSepStyle == 2 || iSepStyle == 3) { 982 strValue.Insert(iDec2, ','); 983 iMax++; 984 } 985 986 if (iDec2 == 0) 987 strValue.Insert(iDec2, '0'); 988 } 989 if (iSepStyle == 0 || iSepStyle == 2) { 990 char cSeperator; 991 if (iSepStyle == 0) 992 cSeperator = ','; 993 else 994 cSeperator = '.'; 995 996 for (int iDecPositive = iDec2 - 3; iDecPositive > 0; iDecPositive -= 3) { 997 strValue.Insert(iDecPositive, cSeperator); 998 iMax++; 999 } 1000 } 1001 1002 ////////////////////////////////////////////////////////////////////// 1003 // for processing currency string 1004 1005 Value = CFX_WideString::FromLocal(strValue); 1006 std::wstring strValue2 = Value.c_str(); 1007 1008 if (bCurrencyPrepend) 1009 strValue2 = wstrCurrency + strValue2; 1010 else 1011 strValue2 = strValue2 + wstrCurrency; 1012 1013 ///////////////////////////////////////////////////////////////////////// 1014 // for processing negative style 1015 if (iNegative) { 1016 if (iNegStyle == 0) { 1017 strValue2.insert(0, L"-"); 1018 } 1019 if (iNegStyle == 2 || iNegStyle == 3) { 1020 strValue2.insert(0, L"("); 1021 strValue2.insert(strValue2.length(), L")"); 1022 } 1023 if (iNegStyle == 1 || iNegStyle == 3) { 1024 if (Field* fTarget = pEvent->Target_Field()) { 1025 CJS_Array arColor(pRuntime); 1026 CJS_Value vColElm(pRuntime); 1027 vColElm = L"RGB"; 1028 arColor.SetElement(0, vColElm); 1029 vColElm = 1; 1030 arColor.SetElement(1, vColElm); 1031 vColElm = 0; 1032 arColor.SetElement(2, vColElm); 1033 1034 arColor.SetElement(3, vColElm); 1035 1036 CJS_PropValue vProp(pRuntime); 1037 vProp.StartGetting(); 1038 vProp << arColor; 1039 vProp.StartSetting(); 1040 fTarget->textColor(cc, vProp, sError); // red 1041 } 1042 } 1043 } else { 1044 if (iNegStyle == 1 || iNegStyle == 3) { 1045 if (Field* fTarget = pEvent->Target_Field()) { 1046 CJS_Array arColor(pRuntime); 1047 CJS_Value vColElm(pRuntime); 1048 vColElm = L"RGB"; 1049 arColor.SetElement(0, vColElm); 1050 vColElm = 0; 1051 arColor.SetElement(1, vColElm); 1052 arColor.SetElement(2, vColElm); 1053 arColor.SetElement(3, vColElm); 1054 1055 CJS_PropValue vProp(pRuntime); 1056 vProp.StartGetting(); 1057 fTarget->textColor(cc, vProp, sError); 1058 1059 CJS_Array aProp(pRuntime); 1060 vProp.ConvertToArray(aProp); 1061 1062 CPWL_Color crProp; 1063 CPWL_Color crColor; 1064 color::ConvertArrayToPWLColor(aProp, crProp); 1065 color::ConvertArrayToPWLColor(arColor, crColor); 1066 1067 if (crColor != crProp) { 1068 CJS_PropValue vProp2(pRuntime); 1069 vProp2.StartGetting(); 1070 vProp2 << arColor; 1071 vProp2.StartSetting(); 1072 fTarget->textColor(cc, vProp2, sError); 1073 } 1074 } 1075 } 1076 } 1077 Value = strValue2.c_str(); 1078 #endif 1079 return TRUE; 1080 } 1081 1082 // function AFNumber_Keystroke(nDec, sepStyle, negStyle, currStyle, strCurrency, 1083 // bCurrencyPrepend) 1084 FX_BOOL CJS_PublicMethods::AFNumber_Keystroke( 1085 IJS_Context* cc, 1086 const std::vector<CJS_Value>& params, 1087 CJS_Value& vRet, 1088 CFX_WideString& sError) { 1089 CJS_Context* pContext = (CJS_Context*)cc; 1090 CJS_EventHandler* pEvent = pContext->GetEventHandler(); 1091 1092 if (params.size() < 2) 1093 return FALSE; 1094 int iSepStyle = params[1].ToInt(); 1095 1096 if (iSepStyle < 0 || iSepStyle > 3) 1097 iSepStyle = 0; 1098 if (!pEvent->m_pValue) 1099 return FALSE; 1100 CFX_WideString& val = pEvent->Value(); 1101 CFX_WideString& w_strChange = pEvent->Change(); 1102 CFX_WideString w_strValue = val; 1103 1104 if (pEvent->WillCommit()) { 1105 CFX_WideString wstrChange = w_strChange; 1106 CFX_WideString wstrValue = StrLTrim(w_strValue.c_str()); 1107 if (wstrValue.IsEmpty()) 1108 return TRUE; 1109 1110 CFX_WideString swTemp = wstrValue; 1111 swTemp.Replace(L",", L"."); 1112 if (!IsNumber(swTemp.c_str())) { 1113 pEvent->Rc() = FALSE; 1114 sError = JSGetStringFromID(pContext, IDS_STRING_JSAFNUMBER_KEYSTROKE); 1115 Alert(pContext, sError.c_str()); 1116 return TRUE; 1117 } 1118 return TRUE; // it happens after the last keystroke and before validating, 1119 } 1120 1121 std::wstring w_strValue2 = w_strValue.c_str(); 1122 std::wstring w_strChange2 = w_strChange.c_str(); 1123 std::wstring w_strSelected; 1124 if (-1 != pEvent->SelStart()) 1125 w_strSelected = w_strValue2.substr(pEvent->SelStart(), 1126 (pEvent->SelEnd() - pEvent->SelStart())); 1127 bool bHasSign = (w_strValue2.find('-') != std::wstring::npos) && 1128 (w_strSelected.find('-') == std::wstring::npos); 1129 if (bHasSign) { 1130 // can't insert "change" in front to sign postion. 1131 if (pEvent->SelStart() == 0) { 1132 FX_BOOL& bRc = pEvent->Rc(); 1133 bRc = FALSE; 1134 return TRUE; 1135 } 1136 } 1137 1138 char cSep = L'.'; 1139 1140 switch (iSepStyle) { 1141 case 0: 1142 case 1: 1143 cSep = L'.'; 1144 break; 1145 case 2: 1146 case 3: 1147 cSep = L','; 1148 break; 1149 } 1150 1151 bool bHasSep = (w_strValue2.find(cSep) != std::wstring::npos); 1152 for (std::wstring::iterator it = w_strChange2.begin(); 1153 it != w_strChange2.end(); it++) { 1154 if (*it == cSep) { 1155 if (bHasSep) { 1156 FX_BOOL& bRc = pEvent->Rc(); 1157 bRc = FALSE; 1158 return TRUE; 1159 } 1160 bHasSep = TRUE; 1161 continue; 1162 } 1163 if (*it == L'-') { 1164 if (bHasSign) { 1165 FX_BOOL& bRc = pEvent->Rc(); 1166 bRc = FALSE; 1167 return TRUE; 1168 } 1169 // sign's position is not correct 1170 if (it != w_strChange2.begin()) { 1171 FX_BOOL& bRc = pEvent->Rc(); 1172 bRc = FALSE; 1173 return TRUE; 1174 } 1175 if (pEvent->SelStart() != 0) { 1176 FX_BOOL& bRc = pEvent->Rc(); 1177 bRc = FALSE; 1178 return TRUE; 1179 } 1180 bHasSign = TRUE; 1181 continue; 1182 } 1183 1184 if (!FXSYS_iswdigit(*it)) { 1185 FX_BOOL& bRc = pEvent->Rc(); 1186 bRc = FALSE; 1187 return TRUE; 1188 } 1189 } 1190 1191 std::wstring w_prefix = w_strValue2.substr(0, pEvent->SelStart()); 1192 std::wstring w_postfix; 1193 if (pEvent->SelEnd() < (int)w_strValue2.length()) 1194 w_postfix = w_strValue2.substr(pEvent->SelEnd()); 1195 w_strValue2 = w_prefix + w_strChange2 + w_postfix; 1196 w_strValue = w_strValue2.c_str(); 1197 val = w_strValue; 1198 return TRUE; 1199 } 1200 1201 // function AFPercent_Format(nDec, sepStyle) 1202 FX_BOOL CJS_PublicMethods::AFPercent_Format( 1203 IJS_Context* cc, 1204 const std::vector<CJS_Value>& params, 1205 CJS_Value& vRet, 1206 CFX_WideString& sError) { 1207 #if _FX_OS_ != _FX_ANDROID_ 1208 CJS_Context* pContext = (CJS_Context*)cc; 1209 CJS_EventHandler* pEvent = pContext->GetEventHandler(); 1210 1211 if (params.size() != 2) { 1212 sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); 1213 return FALSE; 1214 } 1215 if (!pEvent->m_pValue) 1216 return FALSE; 1217 1218 CFX_WideString& Value = pEvent->Value(); 1219 CFX_ByteString strValue = StrTrim(CFX_ByteString::FromUnicode(Value)); 1220 if (strValue.IsEmpty()) 1221 return TRUE; 1222 1223 int iDec = params[0].ToInt(); 1224 if (iDec < 0) 1225 iDec = -iDec; 1226 1227 int iSepStyle = params[1].ToInt(); 1228 if (iSepStyle < 0 || iSepStyle > 3) 1229 iSepStyle = 0; 1230 1231 ////////////////////////////////////////////////////// 1232 // for processing decimal places 1233 double dValue = atof(strValue); 1234 dValue *= 100; 1235 if (iDec > 0) 1236 dValue += DOUBLE_CORRECT; 1237 1238 int iDec2; 1239 int iNegative = 0; 1240 strValue = fcvt(dValue, iDec, &iDec2, &iNegative); 1241 if (strValue.IsEmpty()) { 1242 dValue = 0; 1243 strValue = fcvt(dValue, iDec, &iDec2, &iNegative); 1244 } 1245 1246 if (iDec2 < 0) { 1247 for (int iNum = 0; iNum < abs(iDec2); iNum++) { 1248 strValue = "0" + strValue; 1249 } 1250 iDec2 = 0; 1251 } 1252 int iMax = strValue.GetLength(); 1253 if (iDec2 > iMax) { 1254 for (int iNum = 0; iNum <= iDec2 - iMax; iNum++) { 1255 strValue += "0"; 1256 } 1257 iMax = iDec2 + 1; 1258 } 1259 /////////////////////////////////////////////////////// 1260 // for processing seperator style 1261 if (iDec2 < iMax) { 1262 if (iSepStyle == 0 || iSepStyle == 1) { 1263 strValue.Insert(iDec2, '.'); 1264 iMax++; 1265 } else if (iSepStyle == 2 || iSepStyle == 3) { 1266 strValue.Insert(iDec2, ','); 1267 iMax++; 1268 } 1269 1270 if (iDec2 == 0) 1271 strValue.Insert(iDec2, '0'); 1272 } 1273 if (iSepStyle == 0 || iSepStyle == 2) { 1274 char cSeperator; 1275 if (iSepStyle == 0) 1276 cSeperator = ','; 1277 else 1278 cSeperator = '.'; 1279 1280 for (int iDecPositive = iDec2 - 3; iDecPositive > 0; iDecPositive -= 3) { 1281 strValue.Insert(iDecPositive, cSeperator); 1282 iMax++; 1283 } 1284 } 1285 //////////////////////////////////////////////////////////////////// 1286 // negative mark 1287 if (iNegative) 1288 strValue = "-" + strValue; 1289 strValue += "%"; 1290 Value = CFX_WideString::FromLocal(strValue); 1291 #endif 1292 return TRUE; 1293 } 1294 // AFPercent_Keystroke(nDec, sepStyle) 1295 FX_BOOL CJS_PublicMethods::AFPercent_Keystroke( 1296 IJS_Context* cc, 1297 const std::vector<CJS_Value>& params, 1298 CJS_Value& vRet, 1299 CFX_WideString& sError) { 1300 return AFNumber_Keystroke(cc, params, vRet, sError); 1301 } 1302 1303 // function AFDate_FormatEx(cFormat) 1304 FX_BOOL CJS_PublicMethods::AFDate_FormatEx(IJS_Context* cc, 1305 const std::vector<CJS_Value>& params, 1306 CJS_Value& vRet, 1307 CFX_WideString& sError) { 1308 CJS_Context* pContext = (CJS_Context*)cc; 1309 CJS_EventHandler* pEvent = pContext->GetEventHandler(); 1310 1311 if (params.size() != 1) { 1312 sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); 1313 return FALSE; 1314 } 1315 if (!pEvent->m_pValue) 1316 return FALSE; 1317 1318 CFX_WideString& val = pEvent->Value(); 1319 CFX_WideString strValue = val; 1320 if (strValue.IsEmpty()) 1321 return TRUE; 1322 1323 CFX_WideString sFormat = params[0].ToCFXWideString(); 1324 double dDate = 0.0f; 1325 1326 if (strValue.Find(L"GMT") != -1) { 1327 // for GMT format time 1328 // such as "Tue Aug 11 14:24:16 GMT+08002009" 1329 dDate = MakeInterDate(strValue); 1330 } else { 1331 dDate = MakeRegularDate(strValue, sFormat, nullptr); 1332 } 1333 1334 if (JS_PortIsNan(dDate)) { 1335 CFX_WideString swMsg; 1336 swMsg.Format(JSGetStringFromID(pContext, IDS_STRING_JSPARSEDATE).c_str(), 1337 sFormat.c_str()); 1338 Alert(pContext, swMsg.c_str()); 1339 return FALSE; 1340 } 1341 1342 val = MakeFormatDate(dDate, sFormat); 1343 return TRUE; 1344 } 1345 1346 double CJS_PublicMethods::MakeInterDate(CFX_WideString strValue) { 1347 int nHour; 1348 int nMin; 1349 int nSec; 1350 int nYear; 1351 int nMonth; 1352 int nDay; 1353 1354 CFX_WideStringArray wsArray; 1355 CFX_WideString sMonth = L""; 1356 CFX_WideString sTemp = L""; 1357 int nSize = strValue.GetLength(); 1358 1359 for (int i = 0; i < nSize; i++) { 1360 FX_WCHAR c = strValue.GetAt(i); 1361 if (c == L' ' || c == L':') { 1362 wsArray.Add(sTemp); 1363 sTemp = L""; 1364 continue; 1365 } 1366 1367 sTemp += c; 1368 } 1369 1370 wsArray.Add(sTemp); 1371 if (wsArray.GetSize() != 8) 1372 return 0; 1373 1374 sTemp = wsArray[1]; 1375 if (sTemp.Compare(L"Jan") == 0) 1376 nMonth = 1; 1377 if (sTemp.Compare(L"Feb") == 0) 1378 nMonth = 2; 1379 if (sTemp.Compare(L"Mar") == 0) 1380 nMonth = 3; 1381 if (sTemp.Compare(L"Apr") == 0) 1382 nMonth = 4; 1383 if (sTemp.Compare(L"May") == 0) 1384 nMonth = 5; 1385 if (sTemp.Compare(L"Jun") == 0) 1386 nMonth = 6; 1387 if (sTemp.Compare(L"Jul") == 0) 1388 nMonth = 7; 1389 if (sTemp.Compare(L"Aug") == 0) 1390 nMonth = 8; 1391 if (sTemp.Compare(L"Sep") == 0) 1392 nMonth = 9; 1393 if (sTemp.Compare(L"Oct") == 0) 1394 nMonth = 10; 1395 if (sTemp.Compare(L"Nov") == 0) 1396 nMonth = 11; 1397 if (sTemp.Compare(L"Dec") == 0) 1398 nMonth = 12; 1399 1400 nDay = (int)ParseStringToNumber(wsArray[2].c_str()); 1401 nHour = (int)ParseStringToNumber(wsArray[3].c_str()); 1402 nMin = (int)ParseStringToNumber(wsArray[4].c_str()); 1403 nSec = (int)ParseStringToNumber(wsArray[5].c_str()); 1404 nYear = (int)ParseStringToNumber(wsArray[7].c_str()); 1405 1406 double dRet = JS_MakeDate(JS_MakeDay(nYear, nMonth - 1, nDay), 1407 JS_MakeTime(nHour, nMin, nSec, 0)); 1408 1409 if (JS_PortIsNan(dRet)) { 1410 dRet = JS_DateParse(strValue.c_str()); 1411 } 1412 1413 return dRet; 1414 } 1415 1416 // AFDate_KeystrokeEx(cFormat) 1417 FX_BOOL CJS_PublicMethods::AFDate_KeystrokeEx( 1418 IJS_Context* cc, 1419 const std::vector<CJS_Value>& params, 1420 CJS_Value& vRet, 1421 CFX_WideString& sError) { 1422 CJS_Context* pContext = (CJS_Context*)cc; 1423 CJS_EventHandler* pEvent = pContext->GetEventHandler(); 1424 1425 if (params.size() != 1) { 1426 sError = L"AFDate_KeystrokeEx's parameters' size r not correct"; 1427 return FALSE; 1428 } 1429 1430 if (pEvent->WillCommit()) { 1431 if (!pEvent->m_pValue) 1432 return FALSE; 1433 CFX_WideString strValue = pEvent->Value(); 1434 if (strValue.IsEmpty()) 1435 return TRUE; 1436 1437 CFX_WideString sFormat = params[0].ToCFXWideString(); 1438 bool bWrongFormat = FALSE; 1439 double dRet = MakeRegularDate(strValue, sFormat, &bWrongFormat); 1440 if (bWrongFormat || JS_PortIsNan(dRet)) { 1441 CFX_WideString swMsg; 1442 swMsg.Format(JSGetStringFromID(pContext, IDS_STRING_JSPARSEDATE).c_str(), 1443 sFormat.c_str()); 1444 Alert(pContext, swMsg.c_str()); 1445 pEvent->Rc() = FALSE; 1446 return TRUE; 1447 } 1448 } 1449 return TRUE; 1450 } 1451 1452 FX_BOOL CJS_PublicMethods::AFDate_Format(IJS_Context* cc, 1453 const std::vector<CJS_Value>& params, 1454 CJS_Value& vRet, 1455 CFX_WideString& sError) { 1456 CJS_Context* pContext = (CJS_Context*)cc; 1457 if (params.size() != 1) { 1458 sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); 1459 return FALSE; 1460 } 1461 1462 int iIndex = params[0].ToInt(); 1463 const FX_WCHAR* cFormats[] = {L"m/d", 1464 L"m/d/yy", 1465 L"mm/dd/yy", 1466 L"mm/yy", 1467 L"d-mmm", 1468 L"d-mmm-yy", 1469 L"dd-mmm-yy", 1470 L"yy-mm-dd", 1471 L"mmm-yy", 1472 L"mmmm-yy", 1473 L"mmm d, yyyy", 1474 L"mmmm d, yyyy", 1475 L"m/d/yy h:MM tt", 1476 L"m/d/yy HH:MM"}; 1477 1478 if (iIndex < 0 || (static_cast<size_t>(iIndex) >= FX_ArraySize(cFormats))) 1479 iIndex = 0; 1480 1481 std::vector<CJS_Value> newParams; 1482 newParams.push_back( 1483 CJS_Value(CJS_Runtime::FromContext(cc), cFormats[iIndex])); 1484 return AFDate_FormatEx(cc, newParams, vRet, sError); 1485 } 1486 1487 // AFDate_KeystrokeEx(cFormat) 1488 FX_BOOL CJS_PublicMethods::AFDate_Keystroke( 1489 IJS_Context* cc, 1490 const std::vector<CJS_Value>& params, 1491 CJS_Value& vRet, 1492 CFX_WideString& sError) { 1493 CJS_Context* pContext = (CJS_Context*)cc; 1494 if (params.size() != 1) { 1495 sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); 1496 return FALSE; 1497 } 1498 1499 int iIndex = params[0].ToInt(); 1500 const FX_WCHAR* cFormats[] = {L"m/d", 1501 L"m/d/yy", 1502 L"mm/dd/yy", 1503 L"mm/yy", 1504 L"d-mmm", 1505 L"d-mmm-yy", 1506 L"dd-mmm-yy", 1507 L"yy-mm-dd", 1508 L"mmm-yy", 1509 L"mmmm-yy", 1510 L"mmm d, yyyy", 1511 L"mmmm d, yyyy", 1512 L"m/d/yy h:MM tt", 1513 L"m/d/yy HH:MM"}; 1514 1515 if (iIndex < 0 || (static_cast<size_t>(iIndex) >= FX_ArraySize(cFormats))) 1516 iIndex = 0; 1517 1518 std::vector<CJS_Value> newParams; 1519 newParams.push_back( 1520 CJS_Value(CJS_Runtime::FromContext(cc), cFormats[iIndex])); 1521 return AFDate_KeystrokeEx(cc, newParams, vRet, sError); 1522 } 1523 1524 // function AFTime_Format(ptf) 1525 FX_BOOL CJS_PublicMethods::AFTime_Format(IJS_Context* cc, 1526 const std::vector<CJS_Value>& params, 1527 CJS_Value& vRet, 1528 CFX_WideString& sError) { 1529 CJS_Context* pContext = (CJS_Context*)cc; 1530 if (params.size() != 1) { 1531 sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); 1532 return FALSE; 1533 } 1534 1535 int iIndex = params[0].ToInt(); 1536 const FX_WCHAR* cFormats[] = {L"HH:MM", L"h:MM tt", L"HH:MM:ss", 1537 L"h:MM:ss tt"}; 1538 1539 if (iIndex < 0 || (static_cast<size_t>(iIndex) >= FX_ArraySize(cFormats))) 1540 iIndex = 0; 1541 1542 std::vector<CJS_Value> newParams; 1543 newParams.push_back( 1544 CJS_Value(CJS_Runtime::FromContext(cc), cFormats[iIndex])); 1545 return AFDate_FormatEx(cc, newParams, vRet, sError); 1546 } 1547 1548 FX_BOOL CJS_PublicMethods::AFTime_Keystroke( 1549 IJS_Context* cc, 1550 const std::vector<CJS_Value>& params, 1551 CJS_Value& vRet, 1552 CFX_WideString& sError) { 1553 CJS_Context* pContext = (CJS_Context*)cc; 1554 if (params.size() != 1) { 1555 sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); 1556 return FALSE; 1557 } 1558 1559 int iIndex = params[0].ToInt(); 1560 const FX_WCHAR* cFormats[] = {L"HH:MM", L"h:MM tt", L"HH:MM:ss", 1561 L"h:MM:ss tt"}; 1562 1563 if (iIndex < 0 || (static_cast<size_t>(iIndex) >= FX_ArraySize(cFormats))) 1564 iIndex = 0; 1565 1566 std::vector<CJS_Value> newParams; 1567 newParams.push_back( 1568 CJS_Value(CJS_Runtime::FromContext(cc), cFormats[iIndex])); 1569 return AFDate_KeystrokeEx(cc, newParams, vRet, sError); 1570 } 1571 1572 FX_BOOL CJS_PublicMethods::AFTime_FormatEx(IJS_Context* cc, 1573 const std::vector<CJS_Value>& params, 1574 CJS_Value& vRet, 1575 CFX_WideString& sError) { 1576 return AFDate_FormatEx(cc, params, vRet, sError); 1577 } 1578 1579 FX_BOOL CJS_PublicMethods::AFTime_KeystrokeEx( 1580 IJS_Context* cc, 1581 const std::vector<CJS_Value>& params, 1582 CJS_Value& vRet, 1583 CFX_WideString& sError) { 1584 return AFDate_KeystrokeEx(cc, params, vRet, sError); 1585 } 1586 1587 // function AFSpecial_Format(psf) 1588 FX_BOOL CJS_PublicMethods::AFSpecial_Format( 1589 IJS_Context* cc, 1590 const std::vector<CJS_Value>& params, 1591 CJS_Value& vRet, 1592 CFX_WideString& sError) { 1593 CJS_Context* pContext = (CJS_Context*)cc; 1594 1595 if (params.size() != 1) { 1596 sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); 1597 return FALSE; 1598 } 1599 1600 std::string cFormat; 1601 int iIndex = params[0].ToInt(); 1602 1603 CJS_EventHandler* pEvent = pContext->GetEventHandler(); 1604 if (!pEvent->m_pValue) 1605 return FALSE; 1606 CFX_WideString& Value = pEvent->Value(); 1607 std::string strSrc = CFX_ByteString::FromUnicode(Value).c_str(); 1608 1609 switch (iIndex) { 1610 case 0: 1611 cFormat = "99999"; 1612 break; 1613 case 1: 1614 cFormat = "99999-9999"; 1615 break; 1616 case 2: { 1617 std::string NumberStr; 1618 util::printx("9999999999", strSrc, NumberStr); 1619 if (NumberStr.length() >= 10) 1620 cFormat = "(999) 999-9999"; 1621 else 1622 cFormat = "999-9999"; 1623 break; 1624 } 1625 case 3: 1626 cFormat = "999-99-9999"; 1627 break; 1628 } 1629 1630 std::string strDes; 1631 util::printx(cFormat, strSrc, strDes); 1632 Value = CFX_WideString::FromLocal(strDes.c_str()); 1633 return TRUE; 1634 } 1635 1636 // function AFSpecial_KeystrokeEx(mask) 1637 FX_BOOL CJS_PublicMethods::AFSpecial_KeystrokeEx( 1638 IJS_Context* cc, 1639 const std::vector<CJS_Value>& params, 1640 CJS_Value& vRet, 1641 CFX_WideString& sError) { 1642 CJS_Context* pContext = (CJS_Context*)cc; 1643 CJS_EventHandler* pEvent = pContext->GetEventHandler(); 1644 1645 if (params.size() < 1) { 1646 sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); 1647 return FALSE; 1648 } 1649 1650 if (!pEvent->m_pValue) 1651 return FALSE; 1652 CFX_WideString& valEvent = pEvent->Value(); 1653 1654 CFX_WideString wstrMask = params[0].ToCFXWideString(); 1655 if (wstrMask.IsEmpty()) 1656 return TRUE; 1657 1658 const size_t wstrMaskLen = wstrMask.GetLength(); 1659 const std::wstring wstrValue = valEvent.c_str(); 1660 1661 if (pEvent->WillCommit()) { 1662 if (wstrValue.empty()) 1663 return TRUE; 1664 size_t iIndexMask = 0; 1665 for (const auto& w_Value : wstrValue) { 1666 if (!maskSatisfied(w_Value, wstrMask[iIndexMask])) 1667 break; 1668 iIndexMask++; 1669 } 1670 1671 if (iIndexMask != wstrMaskLen || 1672 (iIndexMask != wstrValue.size() && wstrMaskLen != 0)) { 1673 Alert( 1674 pContext, 1675 JSGetStringFromID(pContext, IDS_STRING_JSAFNUMBER_KEYSTROKE).c_str()); 1676 pEvent->Rc() = FALSE; 1677 } 1678 return TRUE; 1679 } 1680 1681 CFX_WideString& wideChange = pEvent->Change(); 1682 std::wstring wChange = wideChange.c_str(); 1683 if (wChange.empty()) 1684 return TRUE; 1685 1686 int iIndexMask = pEvent->SelStart(); 1687 1688 size_t combined_len = wstrValue.length() + wChange.length() - 1689 (pEvent->SelEnd() - pEvent->SelStart()); 1690 if (combined_len > wstrMaskLen) { 1691 Alert(pContext, 1692 JSGetStringFromID(pContext, IDS_STRING_JSPARAM_TOOLONG).c_str()); 1693 pEvent->Rc() = FALSE; 1694 return TRUE; 1695 } 1696 1697 if (iIndexMask >= wstrMaskLen && (!wChange.empty())) { 1698 Alert(pContext, 1699 JSGetStringFromID(pContext, IDS_STRING_JSPARAM_TOOLONG).c_str()); 1700 pEvent->Rc() = FALSE; 1701 return TRUE; 1702 } 1703 1704 for (std::wstring::iterator it = wChange.begin(); it != wChange.end(); it++) { 1705 if (iIndexMask >= wstrMaskLen) { 1706 Alert(pContext, 1707 JSGetStringFromID(pContext, IDS_STRING_JSPARAM_TOOLONG).c_str()); 1708 pEvent->Rc() = FALSE; 1709 return TRUE; 1710 } 1711 wchar_t w_Mask = wstrMask[iIndexMask]; 1712 if (!isReservedMaskChar(w_Mask)) { 1713 *it = w_Mask; 1714 } 1715 wchar_t w_Change = *it; 1716 if (!maskSatisfied(w_Change, w_Mask)) { 1717 pEvent->Rc() = FALSE; 1718 return TRUE; 1719 } 1720 iIndexMask++; 1721 } 1722 1723 wideChange = wChange.c_str(); 1724 return TRUE; 1725 } 1726 1727 // function AFSpecial_Keystroke(psf) 1728 FX_BOOL CJS_PublicMethods::AFSpecial_Keystroke( 1729 IJS_Context* cc, 1730 const std::vector<CJS_Value>& params, 1731 CJS_Value& vRet, 1732 CFX_WideString& sError) { 1733 CJS_Context* pContext = (CJS_Context*)cc; 1734 if (params.size() != 1) { 1735 sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); 1736 return FALSE; 1737 } 1738 1739 CJS_EventHandler* pEvent = pContext->GetEventHandler(); 1740 if (!pEvent->m_pValue) 1741 return FALSE; 1742 1743 std::string cFormat; 1744 int iIndex = params[0].ToInt(); 1745 CFX_WideString& val = pEvent->Value(); 1746 std::string strSrc = CFX_ByteString::FromUnicode(val).c_str(); 1747 std::wstring wstrChange = pEvent->Change().c_str(); 1748 1749 switch (iIndex) { 1750 case 0: 1751 cFormat = "99999"; 1752 break; 1753 case 1: 1754 // cFormat = "99999-9999"; 1755 cFormat = "999999999"; 1756 break; 1757 case 2: { 1758 std::string NumberStr; 1759 util::printx("9999999999", strSrc, NumberStr); 1760 if (strSrc.length() + wstrChange.length() > 7) 1761 // cFormat = "(999) 999-9999"; 1762 cFormat = "9999999999"; 1763 else 1764 // cFormat = "999-9999"; 1765 cFormat = "9999999"; 1766 break; 1767 } 1768 case 3: 1769 // cFormat = "999-99-9999"; 1770 cFormat = "999999999"; 1771 break; 1772 } 1773 1774 std::vector<CJS_Value> params2; 1775 params2.push_back(CJS_Value(CJS_Runtime::FromContext(cc), cFormat.c_str())); 1776 return AFSpecial_KeystrokeEx(cc, params2, vRet, sError); 1777 } 1778 1779 FX_BOOL CJS_PublicMethods::AFMergeChange(IJS_Context* cc, 1780 const std::vector<CJS_Value>& params, 1781 CJS_Value& vRet, 1782 CFX_WideString& sError) { 1783 CJS_Context* pContext = (CJS_Context*)cc; 1784 CJS_EventHandler* pEventHandler = pContext->GetEventHandler(); 1785 1786 if (params.size() != 1) { 1787 sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); 1788 return FALSE; 1789 } 1790 1791 CFX_WideString swValue; 1792 if (pEventHandler->m_pValue) 1793 swValue = pEventHandler->Value(); 1794 1795 if (pEventHandler->WillCommit()) { 1796 vRet = swValue.c_str(); 1797 return TRUE; 1798 } 1799 1800 CFX_WideString prefix, postfix; 1801 1802 if (pEventHandler->SelStart() >= 0) 1803 prefix = swValue.Mid(0, pEventHandler->SelStart()); 1804 else 1805 prefix = L""; 1806 1807 if (pEventHandler->SelEnd() >= 0 && 1808 pEventHandler->SelEnd() <= swValue.GetLength()) 1809 postfix = swValue.Mid(pEventHandler->SelEnd(), 1810 swValue.GetLength() - pEventHandler->SelEnd()); 1811 else 1812 postfix = L""; 1813 1814 vRet = (prefix + pEventHandler->Change() + postfix).c_str(); 1815 1816 return TRUE; 1817 } 1818 1819 FX_BOOL CJS_PublicMethods::AFParseDateEx(IJS_Context* cc, 1820 const std::vector<CJS_Value>& params, 1821 CJS_Value& vRet, 1822 CFX_WideString& sError) { 1823 CJS_Context* pContext = (CJS_Context*)cc; 1824 ASSERT(pContext); 1825 1826 if (params.size() != 2) { 1827 sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); 1828 return FALSE; 1829 } 1830 1831 CFX_WideString sValue = params[0].ToCFXWideString(); 1832 CFX_WideString sFormat = params[1].ToCFXWideString(); 1833 1834 double dDate = MakeRegularDate(sValue, sFormat, nullptr); 1835 1836 if (JS_PortIsNan(dDate)) { 1837 CFX_WideString swMsg; 1838 swMsg.Format(JSGetStringFromID(pContext, IDS_STRING_JSPARSEDATE).c_str(), 1839 sFormat.c_str()); 1840 Alert((CJS_Context*)cc, swMsg.c_str()); 1841 return FALSE; 1842 } 1843 1844 vRet = dDate; 1845 return TRUE; 1846 } 1847 1848 FX_BOOL CJS_PublicMethods::AFSimple(IJS_Context* cc, 1849 const std::vector<CJS_Value>& params, 1850 CJS_Value& vRet, 1851 CFX_WideString& sError) { 1852 if (params.size() != 3) { 1853 CJS_Context* pContext = (CJS_Context*)cc; 1854 ASSERT(pContext); 1855 1856 sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); 1857 return FALSE; 1858 } 1859 1860 vRet = (double)AF_Simple(params[0].ToCFXWideString().c_str(), 1861 params[1].ToDouble(), params[2].ToDouble()); 1862 return TRUE; 1863 } 1864 1865 FX_BOOL CJS_PublicMethods::AFMakeNumber(IJS_Context* cc, 1866 const std::vector<CJS_Value>& params, 1867 CJS_Value& vRet, 1868 CFX_WideString& sError) { 1869 if (params.size() != 1) { 1870 CJS_Context* pContext = (CJS_Context*)cc; 1871 ASSERT(pContext); 1872 1873 sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); 1874 return FALSE; 1875 } 1876 vRet = ParseStringToNumber(params[0].ToCFXWideString().c_str()); 1877 return TRUE; 1878 } 1879 1880 FX_BOOL CJS_PublicMethods::AFSimple_Calculate( 1881 IJS_Context* cc, 1882 const std::vector<CJS_Value>& params, 1883 CJS_Value& vRet, 1884 CFX_WideString& sError) { 1885 CJS_Context* pContext = (CJS_Context*)cc; 1886 if (params.size() != 2) { 1887 sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); 1888 return FALSE; 1889 } 1890 1891 CJS_Value params1 = params[1]; 1892 if (!params1.IsArrayObject() && params1.GetType() != CJS_Value::VT_string) { 1893 sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); 1894 return FALSE; 1895 } 1896 1897 CPDFSDK_Document* pReaderDoc = pContext->GetReaderDocument(); 1898 CPDFSDK_InterForm* pReaderInterForm = pReaderDoc->GetInterForm(); 1899 CPDF_InterForm* pInterForm = pReaderInterForm->GetInterForm(); 1900 1901 CFX_WideString sFunction = params[0].ToCFXWideString(); 1902 double dValue = wcscmp(sFunction.c_str(), L"PRD") == 0 ? 1.0 : 0.0; 1903 1904 CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); 1905 CJS_Array FieldNameArray = AF_MakeArrayFromList(pRuntime, params1); 1906 int nFieldsCount = 0; 1907 1908 for (int i = 0, isz = FieldNameArray.GetLength(); i < isz; i++) { 1909 CJS_Value jsValue(pRuntime); 1910 FieldNameArray.GetElement(i, jsValue); 1911 CFX_WideString wsFieldName = jsValue.ToCFXWideString(); 1912 1913 for (int j = 0, jsz = pInterForm->CountFields(wsFieldName); j < jsz; j++) { 1914 if (CPDF_FormField* pFormField = pInterForm->GetField(j, wsFieldName)) { 1915 double dTemp = 0.0; 1916 1917 switch (pFormField->GetFieldType()) { 1918 case FIELDTYPE_TEXTFIELD: 1919 case FIELDTYPE_COMBOBOX: { 1920 dTemp = ParseStringToNumber(pFormField->GetValue().c_str()); 1921 break; 1922 } 1923 case FIELDTYPE_PUSHBUTTON: { 1924 dTemp = 0.0; 1925 break; 1926 } 1927 case FIELDTYPE_CHECKBOX: 1928 case FIELDTYPE_RADIOBUTTON: { 1929 dTemp = 0.0; 1930 for (int c = 0, csz = pFormField->CountControls(); c < csz; c++) { 1931 if (CPDF_FormControl* pFormCtrl = pFormField->GetControl(c)) { 1932 if (pFormCtrl->IsChecked()) { 1933 dTemp += 1934 ParseStringToNumber(pFormCtrl->GetExportValue().c_str()); 1935 break; 1936 } 1937 } 1938 } 1939 break; 1940 } 1941 case FIELDTYPE_LISTBOX: { 1942 if (pFormField->CountSelectedItems() > 1) 1943 break; 1944 1945 dTemp = ParseStringToNumber(pFormField->GetValue().c_str()); 1946 break; 1947 } 1948 default: 1949 break; 1950 } 1951 1952 if (i == 0 && j == 0 && (wcscmp(sFunction.c_str(), L"MIN") == 0 || 1953 wcscmp(sFunction.c_str(), L"MAX") == 0)) 1954 dValue = dTemp; 1955 1956 dValue = AF_Simple(sFunction.c_str(), dValue, dTemp); 1957 1958 nFieldsCount++; 1959 } 1960 } 1961 } 1962 1963 if (wcscmp(sFunction.c_str(), L"AVG") == 0 && nFieldsCount > 0) 1964 dValue /= nFieldsCount; 1965 1966 dValue = (double)floor(dValue * FXSYS_pow((double)10, (double)6) + 0.49) / 1967 FXSYS_pow((double)10, (double)6); 1968 CJS_Value jsValue(pRuntime, dValue); 1969 if (pContext->GetEventHandler()->m_pValue) 1970 pContext->GetEventHandler()->Value() = jsValue.ToCFXWideString(); 1971 1972 return TRUE; 1973 } 1974 1975 /* This function validates the current event to ensure that its value is 1976 ** within the specified range. */ 1977 1978 FX_BOOL CJS_PublicMethods::AFRange_Validate( 1979 IJS_Context* cc, 1980 const std::vector<CJS_Value>& params, 1981 CJS_Value& vRet, 1982 CFX_WideString& sError) { 1983 CJS_Context* pContext = (CJS_Context*)cc; 1984 CJS_EventHandler* pEvent = pContext->GetEventHandler(); 1985 1986 if (params.size() != 4) { 1987 sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); 1988 return FALSE; 1989 } 1990 1991 if (!pEvent->m_pValue) 1992 return FALSE; 1993 if (pEvent->Value().IsEmpty()) 1994 return TRUE; 1995 double dEentValue = atof(CFX_ByteString::FromUnicode(pEvent->Value())); 1996 FX_BOOL bGreaterThan = params[0].ToBool(); 1997 double dGreaterThan = params[1].ToDouble(); 1998 FX_BOOL bLessThan = params[2].ToBool(); 1999 double dLessThan = params[3].ToDouble(); 2000 CFX_WideString swMsg; 2001 2002 if (bGreaterThan && bLessThan) { 2003 if (dEentValue < dGreaterThan || dEentValue > dLessThan) 2004 swMsg.Format(JSGetStringFromID(pContext, IDS_STRING_JSRANGE1).c_str(), 2005 params[1].ToCFXWideString().c_str(), 2006 params[3].ToCFXWideString().c_str()); 2007 } else if (bGreaterThan) { 2008 if (dEentValue < dGreaterThan) 2009 swMsg.Format(JSGetStringFromID(pContext, IDS_STRING_JSRANGE2).c_str(), 2010 params[1].ToCFXWideString().c_str()); 2011 } else if (bLessThan) { 2012 if (dEentValue > dLessThan) 2013 swMsg.Format(JSGetStringFromID(pContext, IDS_STRING_JSRANGE3).c_str(), 2014 params[3].ToCFXWideString().c_str()); 2015 } 2016 2017 if (!swMsg.IsEmpty()) { 2018 Alert(pContext, swMsg.c_str()); 2019 pEvent->Rc() = FALSE; 2020 } 2021 return TRUE; 2022 } 2023 2024 FX_BOOL CJS_PublicMethods::AFExtractNums(IJS_Context* cc, 2025 const std::vector<CJS_Value>& params, 2026 CJS_Value& vRet, 2027 CFX_WideString& sError) { 2028 CJS_Context* pContext = (CJS_Context*)cc; 2029 if (params.size() != 1) { 2030 sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); 2031 return FALSE; 2032 } 2033 2034 CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); 2035 CJS_Array nums(pRuntime); 2036 2037 CFX_WideString str = params[0].ToCFXWideString(); 2038 CFX_WideString sPart; 2039 2040 if (str.GetAt(0) == L'.' || str.GetAt(0) == L',') 2041 str = L"0" + str; 2042 2043 int nIndex = 0; 2044 for (int i = 0, sz = str.GetLength(); i < sz; i++) { 2045 FX_WCHAR wc = str.GetAt(i); 2046 if (FXSYS_iswdigit(wc)) { 2047 sPart += wc; 2048 } else { 2049 if (sPart.GetLength() > 0) { 2050 nums.SetElement(nIndex, CJS_Value(pRuntime, sPart.c_str())); 2051 sPart = L""; 2052 nIndex++; 2053 } 2054 } 2055 } 2056 2057 if (sPart.GetLength() > 0) { 2058 nums.SetElement(nIndex, CJS_Value(pRuntime, sPart.c_str())); 2059 } 2060 2061 if (nums.GetLength() > 0) 2062 vRet = nums; 2063 else 2064 vRet.SetNull(); 2065 2066 return TRUE; 2067 } 2068