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 "xfa/fgas/crt/cfgas_formatstring.h" 8 9 #include <algorithm> 10 #include <vector> 11 12 #include "core/fxcrt/cfx_decimal.h" 13 #include "core/fxcrt/fx_extension.h" 14 #include "core/fxcrt/xml/cxml_element.h" 15 16 #define FX_LOCALECATEGORY_DateHash 0xbde9abde 17 #define FX_LOCALECATEGORY_TimeHash 0x2d71b00f 18 #define FX_LOCALECATEGORY_DateTimeHash 0x158c72ed 19 #define FX_LOCALECATEGORY_NumHash 0x0b4ff870 20 #define FX_LOCALECATEGORY_TextHash 0x2d08af85 21 #define FX_LOCALECATEGORY_ZeroHash 0x568cb500 22 #define FX_LOCALECATEGORY_NullHash 0x052931bb 23 24 #define FX_NUMSTYLE_Percent 0x01 25 #define FX_NUMSTYLE_Exponent 0x02 26 #define FX_NUMSTYLE_DotVorv 0x04 27 28 namespace { 29 30 struct FX_LOCALESUBCATEGORYINFO { 31 uint32_t uHash; 32 const wchar_t* pName; 33 int32_t eSubCategory; 34 }; 35 36 const FX_LOCALESUBCATEGORYINFO g_FXLocaleDateTimeSubCatData[] = { 37 {0x14da2125, L"default", FX_LOCALEDATETIMESUBCATEGORY_Default}, 38 {0x9041d4b0, L"short", FX_LOCALEDATETIMESUBCATEGORY_Short}, 39 {0xa084a381, L"medium", FX_LOCALEDATETIMESUBCATEGORY_Medium}, 40 {0xcdce56b3, L"full", FX_LOCALEDATETIMESUBCATEGORY_Full}, 41 {0xf6b4afb0, L"long", FX_LOCALEDATETIMESUBCATEGORY_Long}, 42 }; 43 const int32_t g_iFXLocaleDateTimeSubCatCount = 44 sizeof(g_FXLocaleDateTimeSubCatData) / sizeof(FX_LOCALESUBCATEGORYINFO); 45 46 const FX_LOCALESUBCATEGORYINFO g_FXLocaleNumSubCatData[] = { 47 {0x46f95531, L"percent", FX_LOCALENUMPATTERN_Percent}, 48 {0x4c4e8acb, L"currency", FX_LOCALENUMPATTERN_Currency}, 49 {0x54034c2f, L"decimal", FX_LOCALENUMPATTERN_Decimal}, 50 {0x7568e6ae, L"integer", FX_LOCALENUMPATTERN_Integer}, 51 }; 52 const int32_t g_iFXLocaleNumSubCatCount = 53 sizeof(g_FXLocaleNumSubCatData) / sizeof(FX_LOCALESUBCATEGORYINFO); 54 55 struct FX_LOCALETIMEZONEINFO { 56 const wchar_t* name; 57 int16_t iHour; 58 int16_t iMinute; 59 }; 60 61 const FX_LOCALETIMEZONEINFO g_FXLocaleTimeZoneData[] = { 62 {L"CDT", -5, 0}, {L"CST", -6, 0}, {L"EDT", -4, 0}, {L"EST", -5, 0}, 63 {L"MDT", -6, 0}, {L"MST", -7, 0}, {L"PDT", -7, 0}, {L"PST", -8, 0}, 64 }; 65 66 const wchar_t gs_wsTimeSymbols[] = L"hHkKMSFAzZ"; 67 const wchar_t gs_wsDateSymbols[] = L"DJMEeGgYwW"; 68 const wchar_t gs_wsConstChars[] = L",-:/. "; 69 70 int32_t ParseTimeZone(const wchar_t* pStr, int32_t iLen, FX_TIMEZONE* tz) { 71 tz->tzHour = 0; 72 tz->tzMinute = 0; 73 if (iLen < 0) 74 return 0; 75 76 int32_t iStart = 1; 77 int32_t iEnd = iStart + 2; 78 while (iStart < iLen && iStart < iEnd) 79 tz->tzHour = tz->tzHour * 10 + FXSYS_DecimalCharToInt(pStr[iStart++]); 80 81 if (iStart < iLen && pStr[iStart] == ':') 82 iStart++; 83 84 iEnd = iStart + 2; 85 while (iStart < iLen && iStart < iEnd) 86 tz->tzMinute = tz->tzMinute * 10 + FXSYS_DecimalCharToInt(pStr[iStart++]); 87 88 if (pStr[0] == '-') 89 tz->tzHour = -tz->tzHour; 90 91 return iStart; 92 } 93 94 int32_t ConvertHex(int32_t iKeyValue, wchar_t ch) { 95 if (FXSYS_isHexDigit(ch)) 96 return iKeyValue * 16 + FXSYS_HexCharToInt(ch); 97 return iKeyValue; 98 } 99 100 WideString GetLiteralText(const wchar_t* pStrPattern, 101 int32_t* iPattern, 102 int32_t iLenPattern) { 103 WideString wsOutput; 104 if (pStrPattern[*iPattern] != '\'') 105 return wsOutput; 106 107 (*iPattern)++; 108 int32_t iQuote = 1; 109 while (*iPattern < iLenPattern) { 110 if (pStrPattern[*iPattern] == '\'') { 111 iQuote++; 112 if ((*iPattern + 1 >= iLenPattern) || 113 ((pStrPattern[*iPattern + 1] != '\'') && (iQuote % 2 == 0))) { 114 break; 115 } 116 iQuote++; 117 (*iPattern)++; 118 } else if (pStrPattern[*iPattern] == '\\' && 119 (*iPattern + 1 < iLenPattern) && 120 pStrPattern[*iPattern + 1] == 'u') { 121 int32_t iKeyValue = 0; 122 *iPattern += 2; 123 int32_t i = 0; 124 while (*iPattern < iLenPattern && i++ < 4) { 125 wchar_t ch = pStrPattern[(*iPattern)++]; 126 iKeyValue = ConvertHex(iKeyValue, ch); 127 } 128 if (iKeyValue != 0) 129 wsOutput += static_cast<wchar_t>(iKeyValue & 0x0000FFFF); 130 131 continue; 132 } 133 wsOutput += pStrPattern[(*iPattern)++]; 134 } 135 return wsOutput; 136 } 137 138 WideString GetLiteralTextReverse(const wchar_t* pStrPattern, 139 int32_t* iPattern) { 140 WideString wsOutput; 141 if (pStrPattern[*iPattern] != '\'') 142 return wsOutput; 143 144 (*iPattern)--; 145 int32_t iQuote = 1; 146 while (*iPattern >= 0) { 147 if (pStrPattern[*iPattern] == '\'') { 148 iQuote++; 149 if (*iPattern - 1 >= 0 || 150 ((pStrPattern[*iPattern - 1] != '\'') && (iQuote % 2 == 0))) { 151 break; 152 } 153 iQuote++; 154 (*iPattern)--; 155 } else if (pStrPattern[*iPattern] == '\\' && 156 pStrPattern[*iPattern + 1] == 'u') { 157 (*iPattern)--; 158 int32_t iKeyValue = 0; 159 int32_t iLen = wsOutput.GetLength(); 160 int32_t i = 1; 161 for (; i < iLen && i < 5; i++) { 162 wchar_t ch = wsOutput[i]; 163 iKeyValue = ConvertHex(iKeyValue, ch); 164 } 165 if (iKeyValue != 0) { 166 wsOutput.Delete(0, i); 167 wsOutput = (wchar_t)(iKeyValue & 0x0000FFFF) + wsOutput; 168 } 169 continue; 170 } 171 wsOutput = pStrPattern[(*iPattern)--] + wsOutput; 172 } 173 return wsOutput; 174 } 175 176 bool GetNumericDotIndex(const WideString& wsNum, 177 const WideString& wsDotSymbol, 178 int32_t* iDotIndex) { 179 int32_t ccf = 0; 180 int32_t iLenf = wsNum.GetLength(); 181 const wchar_t* pStr = wsNum.c_str(); 182 int32_t iLenDot = wsDotSymbol.GetLength(); 183 while (ccf < iLenf) { 184 if (pStr[ccf] == '\'') { 185 GetLiteralText(pStr, &ccf, iLenf); 186 } else if (ccf + iLenDot <= iLenf && 187 !wcsncmp(pStr + ccf, wsDotSymbol.c_str(), iLenDot)) { 188 *iDotIndex = ccf; 189 return true; 190 } 191 ccf++; 192 } 193 auto result = wsNum.Find('.'); 194 *iDotIndex = result.value_or(iLenf); 195 return result.has_value(); 196 } 197 198 bool ExtractCountDigits(const wchar_t* str, 199 int len, 200 int count, 201 int* cc, 202 uint32_t* value) { 203 for (int i = count; i > 0; --i) { 204 if (*cc >= len) 205 return false; 206 if (!FXSYS_isDecimalDigit(str[*cc])) 207 return false; 208 *value = *value * 10 + FXSYS_DecimalCharToInt(str[(*cc)++]); 209 } 210 return true; 211 } 212 213 bool ExtractCountDigitsWithOptional(const wchar_t* str, 214 int len, 215 int count, 216 int* cc, 217 uint32_t* value) { 218 if (!ExtractCountDigits(str, len, count, cc, value)) 219 return false; 220 ExtractCountDigits(str, len, 1, cc, value); 221 return true; 222 } 223 224 bool ParseLocaleDate(const WideString& wsDate, 225 const WideString& wsDatePattern, 226 IFX_Locale* pLocale, 227 CFX_DateTime* datetime, 228 int32_t* cc) { 229 uint32_t year = 1900; 230 uint32_t month = 1; 231 uint32_t day = 1; 232 int32_t ccf = 0; 233 const wchar_t* str = wsDate.c_str(); 234 int32_t len = wsDate.GetLength(); 235 const wchar_t* strf = wsDatePattern.c_str(); 236 int32_t lenf = wsDatePattern.GetLength(); 237 WideStringView wsDateSymbols(gs_wsDateSymbols); 238 while (*cc < len && ccf < lenf) { 239 if (strf[ccf] == '\'') { 240 WideString wsLiteral = GetLiteralText(strf, &ccf, lenf); 241 int32_t iLiteralLen = wsLiteral.GetLength(); 242 if (*cc + iLiteralLen > len || 243 wcsncmp(str + *cc, wsLiteral.c_str(), iLiteralLen)) { 244 return false; 245 } 246 *cc += iLiteralLen; 247 ccf++; 248 continue; 249 } 250 if (!wsDateSymbols.Contains(strf[ccf])) { 251 if (strf[ccf] != str[*cc]) 252 return false; 253 (*cc)++; 254 ccf++; 255 continue; 256 } 257 258 WideString symbol; 259 symbol.Reserve(4); 260 symbol += strf[ccf++]; 261 while (ccf < lenf && strf[ccf] == symbol[0]) 262 symbol += strf[ccf++]; 263 264 if (symbol == L"D" || symbol == L"DD") { 265 day = 0; 266 if (!ExtractCountDigitsWithOptional(str, len, 1, cc, &day)) 267 return false; 268 } else if (symbol == L"J") { 269 uint32_t val = 0; 270 ExtractCountDigits(str, len, 3, cc, &val); 271 } else if (symbol == L"M" || symbol == L"MM") { 272 month = 0; 273 if (!ExtractCountDigitsWithOptional(str, len, 1, cc, &month)) 274 return false; 275 } else if (symbol == L"MMM" || symbol == L"MMMM") { 276 for (uint16_t i = 0; i < 12; i++) { 277 WideString wsMonthName = pLocale->GetMonthName(i, symbol == L"MMM"); 278 if (wsMonthName.IsEmpty()) 279 continue; 280 if (!wcsncmp(wsMonthName.c_str(), str + *cc, wsMonthName.GetLength())) { 281 *cc += wsMonthName.GetLength(); 282 month = i + 1; 283 break; 284 } 285 } 286 } else if (symbol == L"EEE" || symbol == L"EEEE") { 287 for (uint16_t i = 0; i < 7; i++) { 288 WideString wsDayName = pLocale->GetDayName(i, symbol == L"EEE"); 289 if (wsDayName.IsEmpty()) 290 continue; 291 if (!wcsncmp(wsDayName.c_str(), str + *cc, wsDayName.GetLength())) { 292 *cc += wsDayName.GetLength(); 293 break; 294 } 295 } 296 } else if (symbol == L"YY" || symbol == L"YYYY") { 297 if (*cc + pdfium::base::checked_cast<int32_t>(symbol.GetLength()) > len) 298 return false; 299 300 year = 0; 301 if (!ExtractCountDigits(str, len, symbol.GetLength(), cc, &year)) 302 return false; 303 if (symbol == L"YY") { 304 if (year <= 29) 305 year += 2000; 306 else 307 year += 1900; 308 } 309 } else if (symbol == L"G") { 310 *cc += 2; 311 } else if (symbol == L"JJJ" || symbol == L"E" || symbol == L"e" || 312 symbol == L"w" || symbol == L"WW") { 313 *cc += symbol.GetLength(); 314 } 315 } 316 if (*cc < len) 317 return false; 318 319 datetime->SetDate(year, month, day); 320 return !!(*cc); 321 } 322 323 void ResolveZone(FX_TIMEZONE tzDiff, 324 IFX_Locale* pLocale, 325 uint32_t* wHour, 326 uint32_t* wMinute) { 327 int32_t iMinuteDiff = *wHour * 60 + *wMinute; 328 FX_TIMEZONE tzLocale = pLocale->GetTimeZone(); 329 iMinuteDiff += tzLocale.tzHour * 60 + 330 (tzLocale.tzHour < 0 ? -tzLocale.tzMinute : tzLocale.tzMinute); 331 iMinuteDiff -= tzDiff.tzHour * 60 + 332 (tzDiff.tzHour < 0 ? -tzDiff.tzMinute : tzDiff.tzMinute); 333 334 iMinuteDiff %= 1440; 335 if (iMinuteDiff < 0) 336 iMinuteDiff += 1440; 337 338 *wHour = iMinuteDiff / 60; 339 *wMinute = iMinuteDiff % 60; 340 } 341 342 bool ParseLocaleTime(const WideString& wsTime, 343 const WideString& wsTimePattern, 344 IFX_Locale* pLocale, 345 CFX_DateTime* datetime, 346 int32_t* cc) { 347 uint32_t hour = 0; 348 uint32_t minute = 0; 349 uint32_t second = 0; 350 uint32_t millisecond = 0; 351 int32_t ccf = 0; 352 const wchar_t* str = wsTime.c_str(); 353 int len = wsTime.GetLength(); 354 const wchar_t* strf = wsTimePattern.c_str(); 355 int lenf = wsTimePattern.GetLength(); 356 bool bHasA = false; 357 bool bPM = false; 358 WideStringView wsTimeSymbols(gs_wsTimeSymbols); 359 while (*cc < len && ccf < lenf) { 360 if (strf[ccf] == '\'') { 361 WideString wsLiteral = GetLiteralText(strf, &ccf, lenf); 362 int32_t iLiteralLen = wsLiteral.GetLength(); 363 if (*cc + iLiteralLen > len || 364 wcsncmp(str + *cc, wsLiteral.c_str(), iLiteralLen)) { 365 return false; 366 } 367 *cc += iLiteralLen; 368 ccf++; 369 continue; 370 } 371 if (!wsTimeSymbols.Contains(strf[ccf])) { 372 if (strf[ccf] != str[*cc]) 373 return false; 374 (*cc)++; 375 ccf++; 376 continue; 377 } 378 379 WideString symbol; 380 symbol.Reserve(4); 381 symbol += strf[ccf++]; 382 while (ccf < lenf && strf[ccf] == symbol[0]) 383 symbol += strf[ccf++]; 384 385 if (symbol == L"k" || symbol == L"K" || symbol == L"h" || symbol == L"H") { 386 hour = 0; 387 if (!ExtractCountDigitsWithOptional(str, len, 1, cc, &hour)) 388 return false; 389 if (symbol == L"K" && hour == 24) 390 hour = 0; 391 } else if (symbol == L"kk" || symbol == L"KK" || symbol == L"hh" || 392 symbol == L"HH") { 393 hour = 0; 394 if (!ExtractCountDigits(str, len, 2, cc, &hour)) 395 return false; 396 if (symbol == L"KK" && hour == 24) 397 hour = 0; 398 } else if (symbol == L"M") { 399 minute = 0; 400 if (!ExtractCountDigitsWithOptional(str, len, 1, cc, &minute)) 401 return false; 402 } else if (symbol == L"MM") { 403 minute = 0; 404 if (!ExtractCountDigits(str, len, 2, cc, &minute)) 405 return false; 406 } else if (symbol == L"S") { 407 second = 0; 408 if (!ExtractCountDigitsWithOptional(str, len, 1, cc, &second)) 409 return false; 410 } else if (symbol == L"SS") { 411 second = 0; 412 if (!ExtractCountDigits(str, len, 2, cc, &second)) 413 return false; 414 } else if (symbol == L"FFF") { 415 millisecond = 0; 416 if (!ExtractCountDigits(str, len, 3, cc, &millisecond)) 417 return false; 418 } else if (symbol == L"A") { 419 WideString wsAM = pLocale->GetMeridiemName(true); 420 WideString wsPM = pLocale->GetMeridiemName(false); 421 if ((*cc + pdfium::base::checked_cast<int32_t>(wsAM.GetLength()) <= 422 len) && 423 (WideStringView(str + *cc, wsAM.GetLength()) == wsAM)) { 424 *cc += wsAM.GetLength(); 425 bHasA = true; 426 } else if ((*cc + pdfium::base::checked_cast<int32_t>(wsPM.GetLength()) <= 427 len) && 428 (WideStringView(str + *cc, wsPM.GetLength()) == wsPM)) { 429 *cc += wsPM.GetLength(); 430 bHasA = true; 431 bPM = true; 432 } 433 } else if (symbol == L"Z") { 434 if (*cc + 3 > len) 435 continue; 436 437 WideString tz(str[(*cc)++]); 438 tz += str[(*cc)++]; 439 tz += str[(*cc)++]; 440 if (tz == L"GMT") { 441 FX_TIMEZONE tzDiff; 442 tzDiff.tzHour = 0; 443 tzDiff.tzMinute = 0; 444 if (*cc < len && (str[*cc] == '-' || str[*cc] == '+')) 445 *cc += ParseTimeZone(str + *cc, len - *cc, &tzDiff); 446 447 ResolveZone(tzDiff, pLocale, &hour, &minute); 448 } else { 449 // Search the timezone list. There are only 8 of them, so linear scan. 450 for (size_t i = 0; i < FX_ArraySize(g_FXLocaleTimeZoneData); ++i) { 451 const FX_LOCALETIMEZONEINFO& info = g_FXLocaleTimeZoneData[i]; 452 if (tz != info.name) 453 continue; 454 455 hour += info.iHour; 456 minute += info.iHour > 0 ? info.iMinute : -info.iMinute; 457 break; 458 } 459 } 460 } else if (symbol == L"z") { 461 if (str[*cc] != 'Z') { 462 FX_TIMEZONE tzDiff; 463 *cc += ParseTimeZone(str + *cc, len - *cc, &tzDiff); 464 ResolveZone(tzDiff, pLocale, &hour, &minute); 465 } else { 466 (*cc)++; 467 } 468 } 469 } 470 if (bHasA) { 471 if (bPM) { 472 hour += 12; 473 if (hour == 24) 474 hour = 12; 475 } else { 476 if (hour == 12) 477 hour = 0; 478 } 479 } 480 datetime->SetTime(hour, minute, second, millisecond); 481 return !!(*cc); 482 } 483 484 int32_t GetNumTrailingLimit(const WideString& wsFormat, 485 int iDotPos, 486 bool* bTrimTailZeros) { 487 if (iDotPos < 0) 488 return 0; 489 490 int32_t iCount = wsFormat.GetLength(); 491 int32_t iTreading = 0; 492 for (iDotPos++; iDotPos < iCount; iDotPos++) { 493 wchar_t wc = wsFormat[iDotPos]; 494 if (wc == L'z' || wc == L'9' || wc == 'Z') { 495 iTreading++; 496 *bTrimTailZeros = wc != L'9'; 497 } 498 } 499 return iTreading; 500 } 501 502 bool IsLeapYear(uint32_t year) { 503 return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; 504 } 505 506 bool MonthHas30Days(uint32_t month) { 507 return month == 4 || month == 6 || month == 9 || month == 11; 508 } 509 510 bool MonthHas31Days(uint32_t month) { 511 return month != 2 && !MonthHas30Days(month); 512 } 513 514 // |month| is 1-based. e.g. 1 means January. 515 uint16_t GetSolarMonthDays(uint16_t year, uint16_t month) { 516 if (month == 2) 517 return FX_IsLeapYear(year) ? 29 : 28; 518 519 return MonthHas30Days(month) ? 30 : 31; 520 } 521 522 uint16_t GetWeekDay(uint16_t year, uint16_t month, uint16_t day) { 523 static const uint16_t month_day[] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5}; 524 uint16_t nDays = 525 (year - 1) % 7 + (year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400; 526 nDays += month_day[month - 1] + day; 527 if (FX_IsLeapYear(year) && month > 2) 528 nDays++; 529 return nDays % 7; 530 } 531 532 uint16_t GetWeekOfMonth(uint16_t year, uint16_t month, uint16_t day) { 533 uint16_t week_day = GetWeekDay(year, month, 1); 534 uint16_t week_index = 0; 535 week_index += day / 7; 536 day = day % 7; 537 if (week_day + day > 7) 538 week_index++; 539 return week_index; 540 } 541 542 uint16_t GetWeekOfYear(uint16_t year, uint16_t month, uint16_t day) { 543 uint16_t nDays = 0; 544 for (uint16_t i = 1; i < month; i++) 545 nDays += GetSolarMonthDays(year, i); 546 547 nDays += day; 548 uint16_t week_day = GetWeekDay(year, 1, 1); 549 uint16_t week_index = 1; 550 week_index += nDays / 7; 551 nDays = nDays % 7; 552 if (week_day + nDays > 7) 553 week_index++; 554 return week_index; 555 } 556 557 WideString NumToString(size_t fmt_size, int32_t value) { 558 return WideString::Format( 559 fmt_size == 1 ? L"%d" : fmt_size == 2 ? L"%02d" : L"%03d", value); 560 } 561 562 WideString DateFormat(const WideString& wsDatePattern, 563 IFX_Locale* pLocale, 564 const CFX_DateTime& datetime) { 565 WideString wsResult; 566 int32_t year = datetime.GetYear(); 567 uint8_t month = datetime.GetMonth(); 568 uint8_t day = datetime.GetDay(); 569 int32_t ccf = 0; 570 const wchar_t* strf = wsDatePattern.c_str(); 571 int32_t lenf = wsDatePattern.GetLength(); 572 WideStringView wsDateSymbols(gs_wsDateSymbols); 573 while (ccf < lenf) { 574 if (strf[ccf] == '\'') { 575 wsResult += GetLiteralText(strf, &ccf, lenf); 576 ccf++; 577 continue; 578 } 579 if (!wsDateSymbols.Contains(strf[ccf])) { 580 wsResult += strf[ccf++]; 581 continue; 582 } 583 584 WideString symbol; 585 symbol.Reserve(4); 586 symbol += strf[ccf++]; 587 while (ccf < lenf && strf[ccf] == symbol[0]) 588 symbol += strf[ccf++]; 589 590 if (symbol == L"D" || symbol == L"DD") { 591 wsResult += NumToString(symbol.GetLength(), day); 592 } else if (symbol == L"J" || symbol == L"JJJ") { 593 uint16_t nDays = 0; 594 for (int i = 1; i < month; i++) 595 nDays += GetSolarMonthDays(year, i); 596 nDays += day; 597 wsResult += NumToString(symbol.GetLength(), nDays); 598 } else if (symbol == L"M" || symbol == L"MM") { 599 wsResult += NumToString(symbol.GetLength(), month); 600 } else if (symbol == L"MMM" || symbol == L"MMMM") { 601 wsResult += pLocale->GetMonthName(month - 1, symbol == L"MMM"); 602 } else if (symbol == L"E" || symbol == L"e") { 603 uint16_t wWeekDay = GetWeekDay(year, month, day); 604 wsResult += NumToString( 605 1, symbol == L"E" ? wWeekDay + 1 : (wWeekDay ? wWeekDay : 7)); 606 } else if (symbol == L"EEE" || symbol == L"EEEE") { 607 wsResult += 608 pLocale->GetDayName(GetWeekDay(year, month, day), symbol == L"EEE"); 609 } else if (symbol == L"G") { 610 wsResult += pLocale->GetEraName(year > 0); 611 } else if (symbol == L"YY") { 612 wsResult += NumToString(2, year % 100); 613 } else if (symbol == L"YYYY") { 614 wsResult += NumToString(1, year); 615 } else if (symbol == L"w") { 616 wsResult += NumToString(1, GetWeekOfMonth(year, month, day)); 617 } else if (symbol == L"WW") { 618 wsResult += NumToString(2, GetWeekOfYear(year, month, day)); 619 } 620 } 621 return wsResult; 622 } 623 624 WideString TimeFormat(const WideString& wsTimePattern, 625 IFX_Locale* pLocale, 626 const CFX_DateTime& datetime) { 627 WideString wsResult; 628 uint8_t hour = datetime.GetHour(); 629 uint8_t minute = datetime.GetMinute(); 630 uint8_t second = datetime.GetSecond(); 631 uint16_t millisecond = datetime.GetMillisecond(); 632 int32_t ccf = 0; 633 const wchar_t* strf = wsTimePattern.c_str(); 634 int32_t lenf = wsTimePattern.GetLength(); 635 uint16_t wHour = hour; 636 bool bPM = false; 637 if (wsTimePattern.Contains('A')) { 638 if (wHour >= 12) 639 bPM = true; 640 } 641 642 WideStringView wsTimeSymbols(gs_wsTimeSymbols); 643 while (ccf < lenf) { 644 if (strf[ccf] == '\'') { 645 wsResult += GetLiteralText(strf, &ccf, lenf); 646 ccf++; 647 continue; 648 } 649 if (!wsTimeSymbols.Contains(strf[ccf])) { 650 wsResult += strf[ccf++]; 651 continue; 652 } 653 654 WideString symbol; 655 symbol.Reserve(4); 656 symbol += strf[ccf++]; 657 while (ccf < lenf && strf[ccf] == symbol[0]) 658 symbol += strf[ccf++]; 659 660 if (symbol == L"h" || symbol == L"hh") { 661 if (wHour > 12) 662 wHour -= 12; 663 wsResult += NumToString(symbol.GetLength(), wHour == 0 ? 12 : wHour); 664 } else if (symbol == L"K" || symbol == L"KK") { 665 wsResult += NumToString(symbol.GetLength(), wHour == 0 ? 24 : wHour); 666 } else if (symbol == L"k" || symbol == L"kk") { 667 if (wHour > 12) 668 wHour -= 12; 669 wsResult += NumToString(symbol.GetLength(), wHour); 670 } else if (symbol == L"H" || symbol == L"HH") { 671 wsResult += NumToString(symbol.GetLength(), wHour); 672 } else if (symbol == L"M" || symbol == L"MM") { 673 wsResult += NumToString(symbol.GetLength(), minute); 674 } else if (symbol == L"S" || symbol == L"SS") { 675 wsResult += NumToString(symbol.GetLength(), second); 676 } else if (symbol == L"FFF") { 677 wsResult += NumToString(3, millisecond); 678 } else if (symbol == L"A") { 679 wsResult += pLocale->GetMeridiemName(!bPM); 680 } else if (symbol == L"Z" || symbol == L"z") { 681 if (symbol == L"Z") 682 wsResult += L"GMT"; 683 684 FX_TIMEZONE tz = pLocale->GetTimeZone(); 685 if (tz.tzHour != 0 || tz.tzMinute != 0) { 686 wsResult += tz.tzHour < 0 ? L"-" : L"+"; 687 wsResult += 688 WideString::Format(L"%02d:%02d", abs(tz.tzHour), tz.tzMinute); 689 } 690 } 691 } 692 return wsResult; 693 } 694 695 WideString FormatDateTimeInternal(const CFX_DateTime& dt, 696 const WideString& wsDatePattern, 697 const WideString& wsTimePattern, 698 bool bDateFirst, 699 IFX_Locale* pLocale) { 700 WideString wsDateOut; 701 if (!wsDatePattern.IsEmpty()) 702 wsDateOut = DateFormat(wsDatePattern, pLocale, dt); 703 704 WideString wsTimeOut; 705 if (!wsTimePattern.IsEmpty()) 706 wsTimeOut = TimeFormat(wsTimePattern, pLocale, dt); 707 708 return bDateFirst ? wsDateOut + wsTimeOut : wsTimeOut + wsDateOut; 709 } 710 711 } // namespace 712 713 bool FX_DateFromCanonical(const WideString& wsDate, CFX_DateTime* datetime) { 714 const wchar_t* str = wsDate.c_str(); 715 int len = wsDate.GetLength(); 716 if (len > 10) 717 return false; 718 719 int cc = 0; 720 uint32_t year = 0; 721 if (!ExtractCountDigits(str, len, 4, &cc, &year)) 722 return false; 723 if (year < 1900) 724 return false; 725 if (cc >= len) { 726 datetime->SetDate(year, 1, 1); 727 return true; 728 } 729 730 if (str[cc] == '-') 731 cc++; 732 733 uint32_t month = 0; 734 if (!ExtractCountDigits(str, len, 2, &cc, &month)) 735 return false; 736 if (month > 12 || month < 1) 737 return false; 738 if (cc >= len) { 739 datetime->SetDate(year, month, 1); 740 return true; 741 } 742 743 if (str[cc] == '-') 744 cc++; 745 746 uint32_t day = 0; 747 if (!ExtractCountDigits(str, len, 2, &cc, &day)) 748 return false; 749 if (day < 1) 750 return false; 751 if ((MonthHas31Days(month) && day > 31) || 752 (MonthHas30Days(month) && day > 30)) { 753 return false; 754 } 755 if (month == 2 && day > (IsLeapYear(year) ? 29U : 28U)) 756 return false; 757 758 datetime->SetDate(year, month, day); 759 return true; 760 } 761 762 bool FX_TimeFromCanonical(const WideStringView& wsTime, 763 CFX_DateTime* datetime, 764 IFX_Locale* pLocale) { 765 if (wsTime.GetLength() == 0) 766 return false; 767 768 const wchar_t* str = wsTime.unterminated_c_str(); 769 int len = wsTime.GetLength(); 770 771 int cc = 0; 772 uint32_t hour = 0; 773 if (!ExtractCountDigits(str, len, 2, &cc, &hour)) 774 return false; 775 if (hour >= 24) 776 return false; 777 if (cc >= len) { 778 datetime->SetTime(hour, 0, 0, 0); 779 return true; 780 } 781 782 if (str[cc] == ':') 783 cc++; 784 785 uint32_t minute = 0; 786 if (!ExtractCountDigits(str, len, 2, &cc, &minute)) 787 return false; 788 if (minute >= 60) 789 return false; 790 791 if (cc >= len) { 792 datetime->SetTime(hour, minute, 0, 0); 793 return true; 794 } 795 796 if (str[cc] == ':') 797 cc++; 798 799 uint32_t second = 0; 800 uint32_t millisecond = 0; 801 if (str[cc] != 'Z') { 802 if (!ExtractCountDigits(str, len, 2, &cc, &second)) 803 return false; 804 if (second >= 60) 805 return false; 806 if (cc < len && str[cc] == '.') { 807 cc++; 808 if (!ExtractCountDigits(str, len, 3, &cc, &millisecond)) 809 return false; 810 } 811 } 812 813 // Skip until we find a + or - for the time zone. 814 while (cc < len) { 815 if (str[cc] == '+' || str[cc] == '-') 816 break; 817 ++cc; 818 } 819 820 if (cc < len) { 821 FX_TIMEZONE tzDiff; 822 tzDiff.tzHour = 0; 823 tzDiff.tzMinute = 0; 824 if (str[cc] != 'Z') 825 cc += ParseTimeZone(str + cc, len - cc, &tzDiff); 826 827 ResolveZone(tzDiff, pLocale, &hour, &minute); 828 } 829 830 datetime->SetTime(hour, minute, second, millisecond); 831 return true; 832 } 833 834 CFGAS_FormatString::CFGAS_FormatString(CXFA_LocaleMgr* pLocaleMgr) 835 : m_pLocaleMgr(pLocaleMgr) {} 836 837 CFGAS_FormatString::~CFGAS_FormatString() {} 838 839 void CFGAS_FormatString::SplitFormatString( 840 const WideString& wsFormatString, 841 std::vector<WideString>* wsPatterns) { 842 int32_t iStrLen = wsFormatString.GetLength(); 843 const wchar_t* pStr = wsFormatString.c_str(); 844 const wchar_t* pToken = pStr; 845 const wchar_t* pEnd = pStr + iStrLen; 846 bool iQuote = false; 847 while (true) { 848 if (pStr >= pEnd) { 849 wsPatterns->push_back(WideString(pToken, pStr - pToken)); 850 return; 851 } 852 if (*pStr == '\'') { 853 iQuote = !iQuote; 854 } else if (*pStr == L'|' && !iQuote) { 855 wsPatterns->push_back(WideString(pToken, pStr - pToken)); 856 pToken = pStr + 1; 857 } 858 pStr++; 859 } 860 } 861 862 FX_LOCALECATEGORY CFGAS_FormatString::GetCategory(const WideString& wsPattern) { 863 FX_LOCALECATEGORY eCategory = FX_LOCALECATEGORY_Unknown; 864 int32_t ccf = 0; 865 int32_t iLenf = wsPattern.GetLength(); 866 const wchar_t* pStr = wsPattern.c_str(); 867 bool bBraceOpen = false; 868 WideStringView wsConstChars(gs_wsConstChars); 869 while (ccf < iLenf) { 870 if (pStr[ccf] == '\'') { 871 GetLiteralText(pStr, &ccf, iLenf); 872 } else if (!bBraceOpen && !wsConstChars.Contains(pStr[ccf])) { 873 WideString wsCategory(pStr[ccf]); 874 ccf++; 875 while (true) { 876 if (ccf == iLenf) 877 return eCategory; 878 if (pStr[ccf] == '.' || pStr[ccf] == '(') 879 break; 880 if (pStr[ccf] == '{') { 881 bBraceOpen = true; 882 break; 883 } 884 wsCategory += pStr[ccf]; 885 ccf++; 886 } 887 888 uint32_t dwHash = FX_HashCode_GetW(wsCategory.AsStringView(), false); 889 if (dwHash == FX_LOCALECATEGORY_DateTimeHash) 890 return FX_LOCALECATEGORY_DateTime; 891 if (dwHash == FX_LOCALECATEGORY_TextHash) 892 return FX_LOCALECATEGORY_Text; 893 if (dwHash == FX_LOCALECATEGORY_NumHash) 894 return FX_LOCALECATEGORY_Num; 895 if (dwHash == FX_LOCALECATEGORY_ZeroHash) 896 return FX_LOCALECATEGORY_Zero; 897 if (dwHash == FX_LOCALECATEGORY_NullHash) 898 return FX_LOCALECATEGORY_Null; 899 if (dwHash == FX_LOCALECATEGORY_DateHash) { 900 if (eCategory == FX_LOCALECATEGORY_Time) 901 return FX_LOCALECATEGORY_DateTime; 902 eCategory = FX_LOCALECATEGORY_Date; 903 } else if (dwHash == FX_LOCALECATEGORY_TimeHash) { 904 if (eCategory == FX_LOCALECATEGORY_Date) 905 return FX_LOCALECATEGORY_DateTime; 906 eCategory = FX_LOCALECATEGORY_Time; 907 } 908 } else if (pStr[ccf] == '}') { 909 bBraceOpen = false; 910 } 911 ccf++; 912 } 913 return eCategory; 914 } 915 916 WideString CFGAS_FormatString::GetTextFormat(const WideString& wsPattern, 917 const WideStringView& wsCategory) { 918 int32_t ccf = 0; 919 int32_t iLenf = wsPattern.GetLength(); 920 const wchar_t* pStr = wsPattern.c_str(); 921 bool bBrackOpen = false; 922 WideStringView wsConstChars(gs_wsConstChars); 923 WideString wsPurgePattern; 924 while (ccf < iLenf) { 925 if (pStr[ccf] == '\'') { 926 int32_t iCurChar = ccf; 927 GetLiteralText(pStr, &ccf, iLenf); 928 wsPurgePattern += WideStringView(pStr + iCurChar, ccf - iCurChar + 1); 929 } else if (!bBrackOpen && !wsConstChars.Contains(pStr[ccf])) { 930 WideString wsSearchCategory(pStr[ccf]); 931 ccf++; 932 while (ccf < iLenf && pStr[ccf] != '{' && pStr[ccf] != '.' && 933 pStr[ccf] != '(') { 934 wsSearchCategory += pStr[ccf]; 935 ccf++; 936 } 937 if (wsSearchCategory != wsCategory) 938 continue; 939 940 while (ccf < iLenf) { 941 if (pStr[ccf] == '(') { 942 ccf++; 943 // Skip over the encoding name. 944 while (ccf < iLenf && pStr[ccf] != ')') 945 ccf++; 946 } else if (pStr[ccf] == '{') { 947 bBrackOpen = true; 948 break; 949 } 950 ccf++; 951 } 952 } else if (pStr[ccf] != '}') { 953 wsPurgePattern += pStr[ccf]; 954 } 955 ccf++; 956 } 957 if (!bBrackOpen) 958 wsPurgePattern = wsPattern; 959 960 return wsPurgePattern; 961 } 962 963 IFX_Locale* CFGAS_FormatString::GetNumericFormat(const WideString& wsPattern, 964 int32_t* iDotIndex, 965 uint32_t* dwStyle, 966 WideString* wsPurgePattern) { 967 *dwStyle = 0; 968 IFX_Locale* pLocale = nullptr; 969 int32_t ccf = 0; 970 int32_t iLenf = wsPattern.GetLength(); 971 const wchar_t* pStr = wsPattern.c_str(); 972 bool bFindDot = false; 973 bool bBrackOpen = false; 974 WideStringView wsConstChars(gs_wsConstChars); 975 while (ccf < iLenf) { 976 if (pStr[ccf] == '\'') { 977 int32_t iCurChar = ccf; 978 GetLiteralText(pStr, &ccf, iLenf); 979 *wsPurgePattern += WideStringView(pStr + iCurChar, ccf - iCurChar + 1); 980 } else if (!bBrackOpen && !wsConstChars.Contains(pStr[ccf])) { 981 WideString wsCategory(pStr[ccf]); 982 ccf++; 983 while (ccf < iLenf && pStr[ccf] != '{' && pStr[ccf] != '.' && 984 pStr[ccf] != '(') { 985 wsCategory += pStr[ccf]; 986 ccf++; 987 } 988 if (wsCategory != L"num") { 989 bBrackOpen = true; 990 ccf = 0; 991 continue; 992 } 993 while (ccf < iLenf) { 994 if (pStr[ccf] == '{') { 995 bBrackOpen = true; 996 break; 997 } 998 if (pStr[ccf] == '(') { 999 ccf++; 1000 WideString wsLCID; 1001 while (ccf < iLenf && pStr[ccf] != ')') 1002 wsLCID += pStr[ccf++]; 1003 1004 pLocale = m_pLocaleMgr->GetLocaleByName(wsLCID); 1005 } else if (pStr[ccf] == '.') { 1006 WideString wsSubCategory; 1007 ccf++; 1008 while (ccf < iLenf && pStr[ccf] != '(' && pStr[ccf] != '{') 1009 wsSubCategory += pStr[ccf++]; 1010 1011 uint32_t dwSubHash = 1012 FX_HashCode_GetW(wsSubCategory.AsStringView(), false); 1013 FX_LOCALENUMSUBCATEGORY eSubCategory = FX_LOCALENUMPATTERN_Decimal; 1014 for (int32_t i = 0; i < g_iFXLocaleNumSubCatCount; i++) { 1015 if (g_FXLocaleNumSubCatData[i].uHash == dwSubHash) { 1016 eSubCategory = (FX_LOCALENUMSUBCATEGORY)g_FXLocaleNumSubCatData[i] 1017 .eSubCategory; 1018 break; 1019 } 1020 } 1021 if (!pLocale) 1022 pLocale = m_pLocaleMgr->GetDefLocale(); 1023 1024 ASSERT(pLocale); 1025 1026 wsSubCategory = pLocale->GetNumPattern(eSubCategory); 1027 auto result = wsSubCategory.Find('.'); 1028 if (result.has_value() && result.value() != 0) { 1029 *iDotIndex += wsPurgePattern->GetLength(); 1030 bFindDot = true; 1031 *dwStyle |= FX_NUMSTYLE_DotVorv; 1032 } 1033 *wsPurgePattern += wsSubCategory; 1034 if (eSubCategory == FX_LOCALENUMPATTERN_Percent) 1035 *dwStyle |= FX_NUMSTYLE_Percent; 1036 1037 continue; 1038 } 1039 ccf++; 1040 } 1041 } else if (pStr[ccf] == 'E') { 1042 *dwStyle |= FX_NUMSTYLE_Exponent; 1043 *wsPurgePattern += pStr[ccf]; 1044 } else if (pStr[ccf] == '%') { 1045 *dwStyle |= FX_NUMSTYLE_Percent; 1046 *wsPurgePattern += pStr[ccf]; 1047 } else if (pStr[ccf] != '}') { 1048 *wsPurgePattern += pStr[ccf]; 1049 } 1050 if (!bFindDot) { 1051 if (pStr[ccf] == '.' || pStr[ccf] == 'V' || pStr[ccf] == 'v') { 1052 bFindDot = true; 1053 *iDotIndex = wsPurgePattern->GetLength() - 1; 1054 *dwStyle |= FX_NUMSTYLE_DotVorv; 1055 } 1056 } 1057 ccf++; 1058 } 1059 if (!bFindDot) 1060 *iDotIndex = wsPurgePattern->GetLength(); 1061 if (!pLocale) 1062 pLocale = m_pLocaleMgr->GetDefLocale(); 1063 return pLocale; 1064 } 1065 1066 bool CFGAS_FormatString::ParseText(const WideString& wsSrcText, 1067 const WideString& wsPattern, 1068 WideString* wsValue) { 1069 wsValue->clear(); 1070 if (wsSrcText.IsEmpty() || wsPattern.IsEmpty()) 1071 return false; 1072 1073 WideString wsTextFormat = GetTextFormat(wsPattern, L"text"); 1074 if (wsTextFormat.IsEmpty()) 1075 return false; 1076 1077 int32_t iText = 0; 1078 int32_t iPattern = 0; 1079 const wchar_t* pStrText = wsSrcText.c_str(); 1080 int32_t iLenText = wsSrcText.GetLength(); 1081 const wchar_t* pStrPattern = wsTextFormat.c_str(); 1082 int32_t iLenPattern = wsTextFormat.GetLength(); 1083 while (iPattern < iLenPattern && iText < iLenText) { 1084 switch (pStrPattern[iPattern]) { 1085 case '\'': { 1086 WideString wsLiteral = 1087 GetLiteralText(pStrPattern, &iPattern, iLenPattern); 1088 int32_t iLiteralLen = wsLiteral.GetLength(); 1089 if (iText + iLiteralLen > iLenText || 1090 wcsncmp(pStrText + iText, wsLiteral.c_str(), iLiteralLen)) { 1091 *wsValue = wsSrcText; 1092 return false; 1093 } 1094 iText += iLiteralLen; 1095 iPattern++; 1096 break; 1097 } 1098 case 'A': 1099 if (FXSYS_iswalpha(pStrText[iText])) { 1100 *wsValue += pStrText[iText]; 1101 iText++; 1102 } 1103 iPattern++; 1104 break; 1105 case 'X': 1106 *wsValue += pStrText[iText]; 1107 iText++; 1108 iPattern++; 1109 break; 1110 case 'O': 1111 case '0': 1112 if (FXSYS_isDecimalDigit(pStrText[iText]) || 1113 FXSYS_iswalpha(pStrText[iText])) { 1114 *wsValue += pStrText[iText]; 1115 iText++; 1116 } 1117 iPattern++; 1118 break; 1119 case '9': 1120 if (FXSYS_isDecimalDigit(pStrText[iText])) { 1121 *wsValue += pStrText[iText]; 1122 iText++; 1123 } 1124 iPattern++; 1125 break; 1126 default: 1127 if (pStrPattern[iPattern] != pStrText[iText]) { 1128 *wsValue = wsSrcText; 1129 return false; 1130 } 1131 iPattern++; 1132 iText++; 1133 break; 1134 } 1135 } 1136 return iPattern == iLenPattern && iText == iLenText; 1137 } 1138 1139 bool CFGAS_FormatString::ParseNum(const WideString& wsSrcNum, 1140 const WideString& wsPattern, 1141 WideString* wsValue) { 1142 wsValue->clear(); 1143 if (wsSrcNum.IsEmpty() || wsPattern.IsEmpty()) 1144 return false; 1145 1146 int32_t dot_index_f = -1; 1147 uint32_t dwFormatStyle = 0; 1148 WideString wsNumFormat; 1149 IFX_Locale* pLocale = 1150 GetNumericFormat(wsPattern, &dot_index_f, &dwFormatStyle, &wsNumFormat); 1151 if (!pLocale || wsNumFormat.IsEmpty()) 1152 return false; 1153 1154 int32_t iExponent = 0; 1155 WideString wsDotSymbol = 1156 pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Decimal); 1157 WideString wsGroupSymbol = 1158 pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Grouping); 1159 int32_t iGroupLen = wsGroupSymbol.GetLength(); 1160 WideString wsMinus = pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus); 1161 int32_t iMinusLen = wsMinus.GetLength(); 1162 const wchar_t* str = wsSrcNum.c_str(); 1163 int len = wsSrcNum.GetLength(); 1164 const wchar_t* strf = wsNumFormat.c_str(); 1165 int lenf = wsNumFormat.GetLength(); 1166 bool bHavePercentSymbol = false; 1167 bool bNeg = false; 1168 bool bReverseParse = false; 1169 int32_t dot_index = 0; 1170 1171 // If we're looking for a '.', 'V' or 'v' and the input string does not 1172 // have a dot index for one of those, then we disable parsing the decimal. 1173 if (!GetNumericDotIndex(wsSrcNum, wsDotSymbol, &dot_index) && 1174 (dwFormatStyle & FX_NUMSTYLE_DotVorv)) 1175 bReverseParse = true; 1176 1177 // This parse is broken into two parts based on the '.' in the number 1178 // (or 'V' or 'v'). |dot_index_f| is the location of the dot in the format and 1179 // |dot_index| is the location of the dot in the number. 1180 // 1181 // This first while() starts at the '.' and walks backwards to the start of 1182 // the number. The second while() walks from the dot forwards to the end of 1183 // the decimal. 1184 1185 int ccf = dot_index_f - 1; 1186 int cc = dot_index - 1; 1187 while (ccf >= 0 && cc >= 0) { 1188 switch (strf[ccf]) { 1189 case '\'': { 1190 WideString wsLiteral = GetLiteralTextReverse(strf, &ccf); 1191 int32_t iLiteralLen = wsLiteral.GetLength(); 1192 cc -= iLiteralLen - 1; 1193 if (cc < 0 || wcsncmp(str + cc, wsLiteral.c_str(), iLiteralLen)) 1194 return false; 1195 1196 cc--; 1197 ccf--; 1198 break; 1199 } 1200 case '9': 1201 if (!FXSYS_isDecimalDigit(str[cc])) 1202 return false; 1203 1204 wsValue->InsertAtFront(str[cc]); 1205 cc--; 1206 ccf--; 1207 break; 1208 case 'z': 1209 case 'Z': 1210 if (strf[ccf] == 'z' || str[cc] != ' ') { 1211 if (FXSYS_isDecimalDigit(str[cc])) { 1212 wsValue->InsertAtFront(str[cc]); 1213 cc--; 1214 } 1215 } else { 1216 cc--; 1217 } 1218 ccf--; 1219 break; 1220 case 'S': 1221 case 's': 1222 if (str[cc] == '+' || (strf[ccf] == 'S' && str[cc] == ' ')) { 1223 cc--; 1224 } else { 1225 cc -= iMinusLen - 1; 1226 if (cc < 0 || wcsncmp(str + cc, wsMinus.c_str(), iMinusLen)) 1227 return false; 1228 1229 cc--; 1230 bNeg = true; 1231 } 1232 ccf--; 1233 break; 1234 case 'E': { 1235 bool bExpSign = false; 1236 while (cc >= 0) { 1237 if (str[cc] == 'E' || str[cc] == 'e') 1238 break; 1239 if (FXSYS_isDecimalDigit(str[cc])) { 1240 iExponent = iExponent + FXSYS_DecimalCharToInt(str[cc]) * 10; 1241 cc--; 1242 continue; 1243 } 1244 if (str[cc] == '+') { 1245 cc--; 1246 continue; 1247 } 1248 if (cc - iMinusLen + 1 > 0 && !wcsncmp(str + (cc - iMinusLen + 1), 1249 wsMinus.c_str(), iMinusLen)) { 1250 bExpSign = true; 1251 cc -= iMinusLen; 1252 continue; 1253 } 1254 1255 return false; 1256 } 1257 cc--; 1258 iExponent = bExpSign ? -iExponent : iExponent; 1259 ccf--; 1260 break; 1261 } 1262 case '$': { 1263 WideString wsSymbol = 1264 pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_CurrencySymbol); 1265 int32_t iSymbolLen = wsSymbol.GetLength(); 1266 cc -= iSymbolLen - 1; 1267 if (cc < 0 || wcsncmp(str + cc, wsSymbol.c_str(), iSymbolLen)) 1268 return false; 1269 1270 cc--; 1271 ccf--; 1272 break; 1273 } 1274 case 'r': 1275 case 'R': 1276 if (ccf - 1 >= 0 && ((strf[ccf] == 'R' && strf[ccf - 1] == 'C') || 1277 (strf[ccf] == 'r' && strf[ccf - 1] == 'c'))) { 1278 if (strf[ccf] == 'R' && str[cc] == ' ') { 1279 cc -= 2; 1280 } else if (str[cc] == 'R' && cc - 1 >= 0 && str[cc - 1] == 'C') { 1281 bNeg = true; 1282 cc -= 2; 1283 } 1284 ccf -= 2; 1285 } else { 1286 ccf--; 1287 } 1288 break; 1289 case 'b': 1290 case 'B': 1291 if (ccf - 1 >= 0 && ((strf[ccf] == 'B' && strf[ccf - 1] == 'D') || 1292 (strf[ccf] == 'b' && strf[ccf - 1] == 'd'))) { 1293 if (strf[ccf] == 'B' && str[cc] == ' ') { 1294 cc -= 2; 1295 } else if (str[cc] == 'B' && cc - 1 >= 0 && str[cc - 1] == 'D') { 1296 bNeg = true; 1297 cc -= 2; 1298 } 1299 ccf -= 2; 1300 } else { 1301 ccf--; 1302 } 1303 break; 1304 case '%': { 1305 WideString wsSymbol = 1306 pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Percent); 1307 int32_t iSysmbolLen = wsSymbol.GetLength(); 1308 cc -= iSysmbolLen - 1; 1309 if (cc < 0 || wcsncmp(str + cc, wsSymbol.c_str(), iSysmbolLen)) 1310 return false; 1311 1312 cc--; 1313 ccf--; 1314 bHavePercentSymbol = true; 1315 break; 1316 } 1317 case '.': 1318 case 'V': 1319 case 'v': 1320 case '8': 1321 return false; 1322 case ',': { 1323 if (cc >= 0) { 1324 cc -= iGroupLen - 1; 1325 if (cc >= 0 && 1326 wcsncmp(str + cc, wsGroupSymbol.c_str(), iGroupLen) == 0) { 1327 cc--; 1328 } else { 1329 cc += iGroupLen - 1; 1330 } 1331 } 1332 ccf--; 1333 break; 1334 } 1335 case '(': 1336 case ')': 1337 if (str[cc] == strf[ccf]) 1338 bNeg = true; 1339 else if (str[cc] != L' ') 1340 return false; 1341 1342 cc--; 1343 ccf--; 1344 break; 1345 default: 1346 if (strf[ccf] != str[cc]) 1347 return false; 1348 1349 cc--; 1350 ccf--; 1351 } 1352 } 1353 if (cc >= 0) { 1354 if (str[cc] == '-') { 1355 bNeg = true; 1356 cc--; 1357 } 1358 if (cc >= 0) 1359 return false; 1360 } 1361 if (dot_index < len && (dwFormatStyle & FX_NUMSTYLE_DotVorv)) 1362 *wsValue += '.'; 1363 if (!bReverseParse) { 1364 ccf = dot_index_f + 1; 1365 cc = (dot_index == len) ? len : dot_index + 1; 1366 while (cc < len && ccf < lenf) { 1367 switch (strf[ccf]) { 1368 case '\'': { 1369 WideString wsLiteral = GetLiteralText(strf, &ccf, lenf); 1370 int32_t iLiteralLen = wsLiteral.GetLength(); 1371 if (cc + iLiteralLen > len || 1372 wcsncmp(str + cc, wsLiteral.c_str(), iLiteralLen)) { 1373 return false; 1374 } 1375 cc += iLiteralLen; 1376 ccf++; 1377 break; 1378 } 1379 case '9': 1380 if (!FXSYS_isDecimalDigit(str[cc])) 1381 return false; 1382 1383 *wsValue += str[cc]; 1384 cc++; 1385 ccf++; 1386 break; 1387 case 'z': 1388 case 'Z': 1389 if (strf[ccf] == 'z' || str[cc] != ' ') { 1390 if (FXSYS_isDecimalDigit(str[cc])) { 1391 *wsValue += str[cc]; 1392 cc++; 1393 } 1394 } else { 1395 cc++; 1396 } 1397 ccf++; 1398 break; 1399 case 'S': 1400 case 's': 1401 if (str[cc] == '+' || (strf[ccf] == 'S' && str[cc] == ' ')) { 1402 cc++; 1403 } else { 1404 if (cc + iMinusLen > len || 1405 wcsncmp(str + cc, wsMinus.c_str(), iMinusLen)) { 1406 return false; 1407 } 1408 bNeg = true; 1409 cc += iMinusLen; 1410 } 1411 ccf++; 1412 break; 1413 case 'E': { 1414 if (cc >= len || (str[cc] != 'E' && str[cc] != 'e')) 1415 return false; 1416 1417 bool bExpSign = false; 1418 cc++; 1419 if (cc < len) { 1420 if (str[cc] == '+') { 1421 cc++; 1422 } else if (str[cc] == '-') { 1423 bExpSign = true; 1424 cc++; 1425 } 1426 } 1427 while (cc < len) { 1428 if (!FXSYS_isDecimalDigit(str[cc])) 1429 break; 1430 1431 iExponent = iExponent * 10 + FXSYS_DecimalCharToInt(str[cc]); 1432 cc++; 1433 } 1434 iExponent = bExpSign ? -iExponent : iExponent; 1435 ccf++; 1436 break; 1437 } 1438 case '$': { 1439 WideString wsSymbol = 1440 pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_CurrencySymbol); 1441 int32_t iSymbolLen = wsSymbol.GetLength(); 1442 if (cc + iSymbolLen > len || 1443 wcsncmp(str + cc, wsSymbol.c_str(), iSymbolLen)) { 1444 return false; 1445 } 1446 cc += iSymbolLen; 1447 ccf++; 1448 break; 1449 } 1450 case 'c': 1451 case 'C': 1452 if (ccf + 1 < lenf && ((strf[ccf] == 'C' && strf[ccf + 1] == 'R') || 1453 (strf[ccf] == 'c' && strf[ccf + 1] == 'r'))) { 1454 if (strf[ccf] == 'C' && str[cc] == ' ') { 1455 cc++; 1456 } else if (str[cc] == 'C' && cc + 1 < len && str[cc + 1] == 'R') { 1457 bNeg = true; 1458 cc += 2; 1459 } 1460 ccf += 2; 1461 } 1462 break; 1463 case 'd': 1464 case 'D': 1465 if (ccf + 1 < lenf && ((strf[ccf] == 'D' && strf[ccf + 1] == 'B') || 1466 (strf[ccf] == 'd' && strf[ccf + 1] == 'b'))) { 1467 if (strf[ccf] == 'D' && str[cc] == ' ') { 1468 cc++; 1469 } else if (str[cc] == 'D' && cc + 1 < len && str[cc + 1] == 'B') { 1470 bNeg = true; 1471 cc += 2; 1472 } 1473 ccf += 2; 1474 } 1475 break; 1476 case '.': 1477 case 'V': 1478 case 'v': 1479 return false; 1480 case '%': { 1481 WideString wsSymbol = 1482 pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Percent); 1483 int32_t iSysmbolLen = wsSymbol.GetLength(); 1484 if (cc + iSysmbolLen <= len && 1485 !wcsncmp(str + cc, wsSymbol.c_str(), iSysmbolLen)) { 1486 cc += iSysmbolLen; 1487 } 1488 ccf++; 1489 bHavePercentSymbol = true; 1490 } break; 1491 case '8': { 1492 while (ccf < lenf && strf[ccf] == '8') 1493 ccf++; 1494 1495 while (cc < len && FXSYS_isDecimalDigit(str[cc])) { 1496 *wsValue += str[cc]; 1497 cc++; 1498 } 1499 } break; 1500 case ',': { 1501 if (cc + iGroupLen <= len && 1502 wcsncmp(str + cc, wsGroupSymbol.c_str(), iGroupLen) == 0) { 1503 cc += iGroupLen; 1504 } 1505 ccf++; 1506 break; 1507 } 1508 case '(': 1509 case ')': 1510 if (str[cc] == strf[ccf]) 1511 bNeg = true; 1512 else if (str[cc] != L' ') 1513 return false; 1514 1515 cc++; 1516 ccf++; 1517 break; 1518 default: 1519 if (strf[ccf] != str[cc]) 1520 return false; 1521 1522 cc++; 1523 ccf++; 1524 } 1525 } 1526 if (cc != len) 1527 return false; 1528 } 1529 if (iExponent || bHavePercentSymbol) { 1530 CFX_Decimal decimal = CFX_Decimal(wsValue->AsStringView()); 1531 if (iExponent) { 1532 decimal = decimal * 1533 CFX_Decimal(FXSYS_pow(10, static_cast<float>(iExponent)), 3); 1534 } 1535 if (bHavePercentSymbol) 1536 decimal = decimal / CFX_Decimal(100); 1537 1538 *wsValue = decimal; 1539 } 1540 if (bNeg) 1541 wsValue->InsertAtFront(L'-'); 1542 1543 return true; 1544 } 1545 1546 FX_DATETIMETYPE CFGAS_FormatString::GetDateTimeFormat( 1547 const WideString& wsPattern, 1548 IFX_Locale** pLocale, 1549 WideString* wsDatePattern, 1550 WideString* wsTimePattern) { 1551 *pLocale = nullptr; 1552 WideString wsTempPattern; 1553 FX_LOCALECATEGORY eCategory = FX_LOCALECATEGORY_Unknown; 1554 int32_t ccf = 0; 1555 int32_t iLenf = wsPattern.GetLength(); 1556 const wchar_t* pStr = wsPattern.c_str(); 1557 int32_t iFindCategory = 0; 1558 bool bBraceOpen = false; 1559 WideStringView wsConstChars(gs_wsConstChars); 1560 while (ccf < iLenf) { 1561 if (pStr[ccf] == '\'') { 1562 int32_t iCurChar = ccf; 1563 GetLiteralText(pStr, &ccf, iLenf); 1564 wsTempPattern += WideStringView(pStr + iCurChar, ccf - iCurChar + 1); 1565 } else if (!bBraceOpen && iFindCategory != 3 && 1566 !wsConstChars.Contains(pStr[ccf])) { 1567 WideString wsCategory(pStr[ccf]); 1568 ccf++; 1569 while (ccf < iLenf && pStr[ccf] != '{' && pStr[ccf] != '.' && 1570 pStr[ccf] != '(') { 1571 if (pStr[ccf] == 'T') { 1572 *wsDatePattern = wsPattern.Left(ccf); 1573 *wsTimePattern = wsPattern.Right(wsPattern.GetLength() - ccf); 1574 wsTimePattern->SetAt(0, ' '); 1575 if (!*pLocale) 1576 *pLocale = m_pLocaleMgr->GetDefLocale(); 1577 1578 return FX_DATETIMETYPE_DateTime; 1579 } 1580 wsCategory += pStr[ccf]; 1581 ccf++; 1582 } 1583 if (!(iFindCategory & 1) && wsCategory == L"date") { 1584 iFindCategory |= 1; 1585 eCategory = FX_LOCALECATEGORY_Date; 1586 if (iFindCategory & 2) 1587 iFindCategory = 4; 1588 } else if (!(iFindCategory & 2) && wsCategory == L"time") { 1589 iFindCategory |= 2; 1590 eCategory = FX_LOCALECATEGORY_Time; 1591 } else if (wsCategory == L"datetime") { 1592 iFindCategory = 3; 1593 eCategory = FX_LOCALECATEGORY_DateTime; 1594 } else { 1595 continue; 1596 } 1597 while (ccf < iLenf) { 1598 if (pStr[ccf] == '{') { 1599 bBraceOpen = true; 1600 break; 1601 } 1602 if (pStr[ccf] == '(') { 1603 ccf++; 1604 WideString wsLCID; 1605 while (ccf < iLenf && pStr[ccf] != ')') 1606 wsLCID += pStr[ccf++]; 1607 1608 *pLocale = m_pLocaleMgr->GetLocaleByName(wsLCID); 1609 } else if (pStr[ccf] == '.') { 1610 WideString wsSubCategory; 1611 ccf++; 1612 while (ccf < iLenf && pStr[ccf] != '(' && pStr[ccf] != '{') 1613 wsSubCategory += pStr[ccf++]; 1614 1615 uint32_t dwSubHash = 1616 FX_HashCode_GetW(wsSubCategory.AsStringView(), false); 1617 FX_LOCALEDATETIMESUBCATEGORY eSubCategory = 1618 FX_LOCALEDATETIMESUBCATEGORY_Medium; 1619 for (int32_t i = 0; i < g_iFXLocaleDateTimeSubCatCount; i++) { 1620 if (g_FXLocaleDateTimeSubCatData[i].uHash == dwSubHash) { 1621 eSubCategory = 1622 (FX_LOCALEDATETIMESUBCATEGORY)g_FXLocaleDateTimeSubCatData[i] 1623 .eSubCategory; 1624 break; 1625 } 1626 } 1627 if (!*pLocale) 1628 *pLocale = m_pLocaleMgr->GetDefLocale(); 1629 ASSERT(*pLocale); 1630 1631 switch (eCategory) { 1632 case FX_LOCALECATEGORY_Date: 1633 *wsDatePattern = 1634 wsTempPattern + (*pLocale)->GetDatePattern(eSubCategory); 1635 break; 1636 case FX_LOCALECATEGORY_Time: 1637 *wsTimePattern = 1638 wsTempPattern + (*pLocale)->GetTimePattern(eSubCategory); 1639 break; 1640 case FX_LOCALECATEGORY_DateTime: 1641 *wsDatePattern = 1642 wsTempPattern + (*pLocale)->GetDatePattern(eSubCategory); 1643 *wsTimePattern = (*pLocale)->GetTimePattern(eSubCategory); 1644 break; 1645 default: 1646 break; 1647 } 1648 wsTempPattern.clear(); 1649 continue; 1650 } 1651 ccf++; 1652 } 1653 } else if (pStr[ccf] == '}') { 1654 bBraceOpen = false; 1655 if (!wsTempPattern.IsEmpty()) { 1656 if (eCategory == FX_LOCALECATEGORY_Time) 1657 *wsTimePattern = wsTempPattern; 1658 else if (eCategory == FX_LOCALECATEGORY_Date) 1659 *wsDatePattern = wsTempPattern; 1660 1661 wsTempPattern.clear(); 1662 } 1663 } else { 1664 wsTempPattern += pStr[ccf]; 1665 } 1666 ccf++; 1667 } 1668 1669 if (!wsTempPattern.IsEmpty()) { 1670 if (eCategory == FX_LOCALECATEGORY_Date) 1671 *wsDatePattern += wsTempPattern; 1672 else 1673 *wsTimePattern += wsTempPattern; 1674 } 1675 if (!*pLocale) 1676 *pLocale = m_pLocaleMgr->GetDefLocale(); 1677 if (!iFindCategory) { 1678 wsTimePattern->clear(); 1679 *wsDatePattern = wsPattern; 1680 } 1681 return (FX_DATETIMETYPE)iFindCategory; 1682 } 1683 1684 bool CFGAS_FormatString::ParseDateTime(const WideString& wsSrcDateTime, 1685 const WideString& wsPattern, 1686 FX_DATETIMETYPE eDateTimeType, 1687 CFX_DateTime* dtValue) { 1688 dtValue->Reset(); 1689 if (wsSrcDateTime.IsEmpty() || wsPattern.IsEmpty()) 1690 return false; 1691 1692 WideString wsDatePattern; 1693 WideString wsTimePattern; 1694 IFX_Locale* pLocale = nullptr; 1695 FX_DATETIMETYPE eCategory = 1696 GetDateTimeFormat(wsPattern, &pLocale, &wsDatePattern, &wsTimePattern); 1697 if (!pLocale) 1698 return false; 1699 if (eCategory == FX_DATETIMETYPE_Unknown) 1700 eCategory = eDateTimeType; 1701 if (eCategory == FX_DATETIMETYPE_Unknown) 1702 return false; 1703 if (eCategory == FX_DATETIMETYPE_TimeDate) { 1704 int32_t iStart = 0; 1705 if (!ParseLocaleTime(wsSrcDateTime, wsTimePattern, pLocale, dtValue, 1706 &iStart)) { 1707 return false; 1708 } 1709 if (!ParseLocaleDate(wsSrcDateTime, wsDatePattern, pLocale, dtValue, 1710 &iStart)) { 1711 return false; 1712 } 1713 } else { 1714 int32_t iStart = 0; 1715 if ((eCategory & FX_DATETIMETYPE_Date) && 1716 !ParseLocaleDate(wsSrcDateTime, wsDatePattern, pLocale, dtValue, 1717 &iStart)) { 1718 return false; 1719 } 1720 if ((eCategory & FX_DATETIMETYPE_Time) && 1721 !ParseLocaleTime(wsSrcDateTime, wsTimePattern, pLocale, dtValue, 1722 &iStart)) { 1723 return false; 1724 } 1725 } 1726 return true; 1727 } 1728 1729 bool CFGAS_FormatString::ParseZero(const WideString& wsSrcText, 1730 const WideString& wsPattern) { 1731 WideString wsTextFormat = GetTextFormat(wsPattern, L"zero"); 1732 1733 int32_t iText = 0; 1734 int32_t iPattern = 0; 1735 const wchar_t* pStrText = wsSrcText.c_str(); 1736 int32_t iLenText = wsSrcText.GetLength(); 1737 const wchar_t* pStrPattern = wsTextFormat.c_str(); 1738 int32_t iLenPattern = wsTextFormat.GetLength(); 1739 while (iPattern < iLenPattern && iText < iLenText) { 1740 if (pStrPattern[iPattern] == '\'') { 1741 WideString wsLiteral = 1742 GetLiteralText(pStrPattern, &iPattern, iLenPattern); 1743 int32_t iLiteralLen = wsLiteral.GetLength(); 1744 if (iText + iLiteralLen > iLenText || 1745 wcsncmp(pStrText + iText, wsLiteral.c_str(), iLiteralLen)) { 1746 return false; 1747 } 1748 iText += iLiteralLen; 1749 iPattern++; 1750 continue; 1751 } 1752 if (pStrPattern[iPattern] != pStrText[iText]) 1753 return false; 1754 1755 iText++; 1756 iPattern++; 1757 } 1758 return iPattern == iLenPattern && iText == iLenText; 1759 } 1760 1761 bool CFGAS_FormatString::ParseNull(const WideString& wsSrcText, 1762 const WideString& wsPattern) { 1763 WideString wsTextFormat = GetTextFormat(wsPattern, L"null"); 1764 1765 int32_t iText = 0; 1766 int32_t iPattern = 0; 1767 const wchar_t* pStrText = wsSrcText.c_str(); 1768 int32_t iLenText = wsSrcText.GetLength(); 1769 const wchar_t* pStrPattern = wsTextFormat.c_str(); 1770 int32_t iLenPattern = wsTextFormat.GetLength(); 1771 while (iPattern < iLenPattern && iText < iLenText) { 1772 if (pStrPattern[iPattern] == '\'') { 1773 WideString wsLiteral = 1774 GetLiteralText(pStrPattern, &iPattern, iLenPattern); 1775 int32_t iLiteralLen = wsLiteral.GetLength(); 1776 if (iText + iLiteralLen > iLenText || 1777 wcsncmp(pStrText + iText, wsLiteral.c_str(), iLiteralLen)) { 1778 return false; 1779 } 1780 iText += iLiteralLen; 1781 iPattern++; 1782 continue; 1783 } 1784 if (pStrPattern[iPattern] != pStrText[iText]) 1785 return false; 1786 1787 iText++; 1788 iPattern++; 1789 } 1790 return iPattern == iLenPattern && iText == iLenText; 1791 } 1792 1793 bool CFGAS_FormatString::FormatText(const WideString& wsSrcText, 1794 const WideString& wsPattern, 1795 WideString* wsOutput) { 1796 if (wsPattern.IsEmpty()) 1797 return false; 1798 1799 int32_t iLenText = wsSrcText.GetLength(); 1800 if (iLenText == 0) 1801 return false; 1802 1803 WideString wsTextFormat = GetTextFormat(wsPattern, L"text"); 1804 1805 int32_t iText = 0; 1806 int32_t iPattern = 0; 1807 const wchar_t* pStrText = wsSrcText.c_str(); 1808 const wchar_t* pStrPattern = wsTextFormat.c_str(); 1809 int32_t iLenPattern = wsTextFormat.GetLength(); 1810 while (iPattern < iLenPattern) { 1811 switch (pStrPattern[iPattern]) { 1812 case '\'': { 1813 *wsOutput += GetLiteralText(pStrPattern, &iPattern, iLenPattern); 1814 iPattern++; 1815 break; 1816 } 1817 case 'A': 1818 if (iText >= iLenText || !FXSYS_iswalpha(pStrText[iText])) 1819 return false; 1820 1821 *wsOutput += pStrText[iText++]; 1822 iPattern++; 1823 break; 1824 case 'X': 1825 if (iText >= iLenText) 1826 return false; 1827 1828 *wsOutput += pStrText[iText++]; 1829 iPattern++; 1830 break; 1831 case 'O': 1832 case '0': 1833 if (iText >= iLenText || (!FXSYS_isDecimalDigit(pStrText[iText]) && 1834 !FXSYS_iswalpha(pStrText[iText]))) { 1835 return false; 1836 } 1837 *wsOutput += pStrText[iText++]; 1838 iPattern++; 1839 break; 1840 case '9': 1841 if (iText >= iLenText || !FXSYS_isDecimalDigit(pStrText[iText])) 1842 return false; 1843 1844 *wsOutput += pStrText[iText++]; 1845 iPattern++; 1846 break; 1847 default: 1848 *wsOutput += pStrPattern[iPattern++]; 1849 break; 1850 } 1851 } 1852 return iText == iLenText; 1853 } 1854 1855 bool CFGAS_FormatString::FormatStrNum(const WideStringView& wsInputNum, 1856 const WideString& wsPattern, 1857 WideString* wsOutput) { 1858 if (wsInputNum.IsEmpty() || wsPattern.IsEmpty()) 1859 return false; 1860 1861 int32_t dot_index_f = -1; 1862 uint32_t dwNumStyle = 0; 1863 WideString wsNumFormat; 1864 IFX_Locale* pLocale = 1865 GetNumericFormat(wsPattern, &dot_index_f, &dwNumStyle, &wsNumFormat); 1866 if (!pLocale || wsNumFormat.IsEmpty()) 1867 return false; 1868 1869 int32_t cc = 0, ccf = 0; 1870 const wchar_t* strf = wsNumFormat.c_str(); 1871 int lenf = wsNumFormat.GetLength(); 1872 WideString wsSrcNum(wsInputNum); 1873 wsSrcNum.TrimLeft('0'); 1874 if (wsSrcNum.IsEmpty() || wsSrcNum[0] == '.') 1875 wsSrcNum.InsertAtFront('0'); 1876 1877 CFX_Decimal decimal = CFX_Decimal(wsSrcNum.AsStringView()); 1878 if (dwNumStyle & FX_NUMSTYLE_Percent) { 1879 decimal = decimal * CFX_Decimal(100); 1880 wsSrcNum = decimal; 1881 } 1882 1883 int32_t exponent = 0; 1884 if (dwNumStyle & FX_NUMSTYLE_Exponent) { 1885 int fixed_count = 0; 1886 while (ccf < dot_index_f) { 1887 switch (strf[ccf]) { 1888 case '\'': 1889 GetLiteralText(strf, &ccf, dot_index_f); 1890 break; 1891 case '9': 1892 case 'z': 1893 case 'Z': 1894 fixed_count++; 1895 break; 1896 } 1897 ccf++; 1898 } 1899 1900 int threshold = 1; 1901 while (fixed_count > 1) { 1902 threshold *= 10; 1903 fixed_count--; 1904 } 1905 if (decimal != CFX_Decimal(0)) { 1906 if (decimal < CFX_Decimal(threshold)) { 1907 decimal = decimal * CFX_Decimal(10); 1908 exponent = -1; 1909 while (decimal < CFX_Decimal(threshold)) { 1910 decimal = decimal * CFX_Decimal(10); 1911 exponent -= 1; 1912 } 1913 } else if (decimal > CFX_Decimal(threshold)) { 1914 threshold *= 10; 1915 while (decimal > CFX_Decimal(threshold)) { 1916 decimal = decimal / CFX_Decimal(10); 1917 exponent += 1; 1918 } 1919 } 1920 } 1921 } 1922 1923 bool bTrimTailZeros = false; 1924 int32_t iTreading = 1925 GetNumTrailingLimit(wsNumFormat, dot_index_f, &bTrimTailZeros); 1926 int32_t scale = decimal.GetScale(); 1927 if (iTreading < scale) { 1928 decimal.SetScale(iTreading); 1929 wsSrcNum = decimal; 1930 } 1931 if (bTrimTailZeros && scale > 0 && iTreading > 0) { 1932 wsSrcNum.TrimRight(L"0"); 1933 wsSrcNum.TrimRight(L"."); 1934 } 1935 1936 WideString wsGroupSymbol = 1937 pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Grouping); 1938 bool bNeg = false; 1939 if (wsSrcNum[0] == '-') { 1940 bNeg = true; 1941 wsSrcNum.Delete(0, 1); 1942 } 1943 1944 bool bAddNeg = false; 1945 const wchar_t* str = wsSrcNum.c_str(); 1946 int len = wsSrcNum.GetLength(); 1947 auto dot_index = wsSrcNum.Find('.'); 1948 if (!dot_index.has_value()) 1949 dot_index = len; 1950 1951 ccf = dot_index_f - 1; 1952 cc = dot_index.value() - 1; 1953 while (ccf >= 0) { 1954 switch (strf[ccf]) { 1955 case '9': 1956 if (cc >= 0) { 1957 if (!FXSYS_isDecimalDigit(str[cc])) 1958 return false; 1959 1960 wsOutput->InsertAtFront(str[cc]); 1961 cc--; 1962 } else { 1963 wsOutput->InsertAtFront(L'0'); 1964 } 1965 ccf--; 1966 break; 1967 case 'z': 1968 if (cc >= 0) { 1969 if (!FXSYS_isDecimalDigit(str[cc])) 1970 return false; 1971 if (str[0] != '0') 1972 wsOutput->InsertAtFront(str[cc]); 1973 1974 cc--; 1975 } 1976 ccf--; 1977 break; 1978 case 'Z': 1979 if (cc >= 0) { 1980 if (!FXSYS_isDecimalDigit(str[cc])) 1981 return false; 1982 1983 wsOutput->InsertAtFront(str[0] == '0' ? L' ' : str[cc]); 1984 cc--; 1985 } else { 1986 wsOutput->InsertAtFront(L' '); 1987 } 1988 ccf--; 1989 break; 1990 case 'S': 1991 if (bNeg) { 1992 *wsOutput = 1993 pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus) + *wsOutput; 1994 bAddNeg = true; 1995 } else { 1996 wsOutput->InsertAtFront(L' '); 1997 } 1998 ccf--; 1999 break; 2000 case 's': 2001 if (bNeg) { 2002 *wsOutput = 2003 pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus) + *wsOutput; 2004 bAddNeg = true; 2005 } 2006 ccf--; 2007 break; 2008 case 'E': { 2009 *wsOutput = WideString::Format(L"E%+d", exponent) + *wsOutput; 2010 ccf--; 2011 break; 2012 } 2013 case '$': { 2014 *wsOutput = 2015 pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_CurrencySymbol) + 2016 *wsOutput; 2017 ccf--; 2018 break; 2019 } 2020 case 'r': 2021 if (ccf - 1 >= 0 && strf[ccf - 1] == 'c') { 2022 if (bNeg) 2023 *wsOutput = L"CR" + *wsOutput; 2024 2025 ccf -= 2; 2026 bAddNeg = true; 2027 } 2028 break; 2029 case 'R': 2030 if (ccf - 1 >= 0 && strf[ccf - 1] == 'C') { 2031 *wsOutput = bNeg ? L"CR" : L" " + *wsOutput; 2032 ccf -= 2; 2033 bAddNeg = true; 2034 } 2035 break; 2036 case 'b': 2037 if (ccf - 1 >= 0 && strf[ccf - 1] == 'd') { 2038 if (bNeg) 2039 *wsOutput = L"db" + *wsOutput; 2040 2041 ccf -= 2; 2042 bAddNeg = true; 2043 } 2044 break; 2045 case 'B': 2046 if (ccf - 1 >= 0 && strf[ccf - 1] == 'D') { 2047 *wsOutput = bNeg ? L"DB" : L" " + *wsOutput; 2048 ccf -= 2; 2049 bAddNeg = true; 2050 } 2051 break; 2052 case '%': { 2053 *wsOutput = 2054 pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Percent) + *wsOutput; 2055 ccf--; 2056 break; 2057 } 2058 case ',': 2059 if (cc >= 0) 2060 *wsOutput = wsGroupSymbol + *wsOutput; 2061 2062 ccf--; 2063 break; 2064 case '(': 2065 wsOutput->InsertAtFront(bNeg ? L'(' : L' '); 2066 bAddNeg = true; 2067 ccf--; 2068 break; 2069 case ')': 2070 wsOutput->InsertAtFront(bNeg ? L')' : L' '); 2071 ccf--; 2072 break; 2073 case '\'': 2074 *wsOutput = GetLiteralTextReverse(strf, &ccf) + *wsOutput; 2075 ccf--; 2076 break; 2077 default: 2078 wsOutput->InsertAtFront(strf[ccf]); 2079 ccf--; 2080 } 2081 } 2082 2083 if (cc >= 0) { 2084 int nPos = dot_index.value() % 3; 2085 wsOutput->clear(); 2086 for (int32_t i = 0; 2087 i < pdfium::base::checked_cast<int32_t>(dot_index.value()); i++) { 2088 if (i % 3 == nPos && i != 0) 2089 *wsOutput += wsGroupSymbol; 2090 *wsOutput += wsSrcNum[i]; 2091 } 2092 if (pdfium::base::checked_cast<int32_t>(dot_index.value()) < len) { 2093 *wsOutput += pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Decimal); 2094 *wsOutput += wsSrcNum.Right(len - dot_index.value() - 1); 2095 } 2096 if (bNeg) { 2097 *wsOutput = 2098 pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus) + *wsOutput; 2099 } 2100 return false; 2101 } 2102 if (dot_index_f == 2103 pdfium::base::checked_cast<int32_t>(wsNumFormat.GetLength())) { 2104 if (!bAddNeg && bNeg) { 2105 *wsOutput = 2106 pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus) + *wsOutput; 2107 } 2108 return true; 2109 } 2110 2111 WideString wsDotSymbol = 2112 pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Decimal); 2113 if (strf[dot_index_f] == 'V') { 2114 *wsOutput += wsDotSymbol; 2115 } else if (strf[dot_index_f] == '.') { 2116 if (pdfium::base::checked_cast<int32_t>(dot_index.value()) < len) 2117 *wsOutput += wsDotSymbol; 2118 else if (strf[dot_index_f + 1] == '9' || strf[dot_index_f + 1] == 'Z') 2119 *wsOutput += wsDotSymbol; 2120 } 2121 2122 ccf = dot_index_f + 1; 2123 cc = dot_index.value() + 1; 2124 while (ccf < lenf) { 2125 switch (strf[ccf]) { 2126 case '\'': 2127 *wsOutput += GetLiteralText(strf, &ccf, lenf); 2128 ccf++; 2129 break; 2130 case '9': 2131 if (cc < len) { 2132 if (!FXSYS_isDecimalDigit(str[cc])) 2133 return false; 2134 2135 *wsOutput += str[cc]; 2136 cc++; 2137 } else { 2138 *wsOutput += L'0'; 2139 } 2140 ccf++; 2141 break; 2142 case 'z': 2143 if (cc < len) { 2144 if (!FXSYS_isDecimalDigit(str[cc])) 2145 return false; 2146 2147 *wsOutput += str[cc]; 2148 cc++; 2149 } 2150 ccf++; 2151 break; 2152 case 'Z': 2153 if (cc < len) { 2154 if (!FXSYS_isDecimalDigit(str[cc])) 2155 return false; 2156 2157 *wsOutput += str[cc]; 2158 cc++; 2159 } else { 2160 *wsOutput += L'0'; 2161 } 2162 ccf++; 2163 break; 2164 case 'E': { 2165 *wsOutput += WideString::Format(L"E%+d", exponent); 2166 ccf++; 2167 break; 2168 } 2169 case '$': 2170 *wsOutput += 2171 pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_CurrencySymbol); 2172 ccf++; 2173 break; 2174 case 'c': 2175 if (ccf + 1 < lenf && strf[ccf + 1] == 'r') { 2176 if (bNeg) 2177 *wsOutput += L"CR"; 2178 2179 ccf += 2; 2180 bAddNeg = true; 2181 } 2182 break; 2183 case 'C': 2184 if (ccf + 1 < lenf && strf[ccf + 1] == 'R') { 2185 *wsOutput += bNeg ? L"CR" : L" "; 2186 ccf += 2; 2187 bAddNeg = true; 2188 } 2189 break; 2190 case 'd': 2191 if (ccf + 1 < lenf && strf[ccf + 1] == 'b') { 2192 if (bNeg) 2193 *wsOutput += L"db"; 2194 2195 ccf += 2; 2196 bAddNeg = true; 2197 } 2198 break; 2199 case 'D': 2200 if (ccf + 1 < lenf && strf[ccf + 1] == 'B') { 2201 *wsOutput += bNeg ? L"DB" : L" "; 2202 ccf += 2; 2203 bAddNeg = true; 2204 } 2205 break; 2206 case '%': 2207 *wsOutput += pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Percent); 2208 ccf++; 2209 break; 2210 case '8': 2211 while (ccf < lenf && strf[ccf] == '8') 2212 ccf++; 2213 while (cc < len && FXSYS_isDecimalDigit(str[cc])) { 2214 *wsOutput += str[cc]; 2215 cc++; 2216 } 2217 break; 2218 case ',': 2219 *wsOutput += wsGroupSymbol; 2220 ccf++; 2221 break; 2222 case '(': 2223 *wsOutput += bNeg ? '(' : ' '; 2224 bAddNeg = true; 2225 ccf++; 2226 break; 2227 case ')': 2228 *wsOutput += bNeg ? ')' : ' '; 2229 ccf++; 2230 break; 2231 default: 2232 ccf++; 2233 } 2234 } 2235 if (!bAddNeg && bNeg) { 2236 *wsOutput = pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus) + 2237 (*wsOutput)[0] + wsOutput->Right(wsOutput->GetLength() - 1); 2238 } 2239 return true; 2240 } 2241 2242 bool CFGAS_FormatString::FormatNum(const WideString& wsSrcNum, 2243 const WideString& wsPattern, 2244 WideString* wsOutput) { 2245 if (wsSrcNum.IsEmpty() || wsPattern.IsEmpty()) 2246 return false; 2247 return FormatStrNum(wsSrcNum.AsStringView(), wsPattern, wsOutput); 2248 } 2249 2250 bool CFGAS_FormatString::FormatDateTime(const WideString& wsSrcDateTime, 2251 const WideString& wsPattern, 2252 FX_DATETIMETYPE eDateTimeType, 2253 WideString* wsOutput) { 2254 if (wsSrcDateTime.IsEmpty() || wsPattern.IsEmpty()) 2255 return false; 2256 2257 WideString wsDatePattern; 2258 WideString wsTimePattern; 2259 IFX_Locale* pLocale = nullptr; 2260 FX_DATETIMETYPE eCategory = 2261 GetDateTimeFormat(wsPattern, &pLocale, &wsDatePattern, &wsTimePattern); 2262 if (!pLocale) 2263 return false; 2264 2265 if (eCategory == FX_DATETIMETYPE_Unknown) { 2266 if (eDateTimeType == FX_DATETIMETYPE_Time) { 2267 wsTimePattern = wsDatePattern; 2268 wsDatePattern.clear(); 2269 } 2270 eCategory = eDateTimeType; 2271 } 2272 if (eCategory == FX_DATETIMETYPE_Unknown) 2273 return false; 2274 2275 CFX_DateTime dt; 2276 auto iT = wsSrcDateTime.Find(L"T"); 2277 if (!iT.has_value()) { 2278 if (eCategory == FX_DATETIMETYPE_Date && 2279 FX_DateFromCanonical(wsSrcDateTime, &dt)) { 2280 *wsOutput = FormatDateTimeInternal(dt, wsDatePattern, wsTimePattern, true, 2281 pLocale); 2282 return true; 2283 } 2284 if (eCategory == FX_DATETIMETYPE_Time && 2285 FX_TimeFromCanonical(wsSrcDateTime.AsStringView(), &dt, pLocale)) { 2286 *wsOutput = FormatDateTimeInternal(dt, wsDatePattern, wsTimePattern, true, 2287 pLocale); 2288 return true; 2289 } 2290 } else { 2291 WideString wsSrcDate(wsSrcDateTime.c_str(), iT.value()); 2292 WideStringView wsSrcTime(wsSrcDateTime.c_str() + iT.value() + 1, 2293 wsSrcDateTime.GetLength() - iT.value() - 1); 2294 if (wsSrcDate.IsEmpty() || wsSrcTime.IsEmpty()) 2295 return false; 2296 if (FX_DateFromCanonical(wsSrcDate, &dt) && 2297 FX_TimeFromCanonical(wsSrcTime, &dt, pLocale)) { 2298 *wsOutput = FormatDateTimeInternal(dt, wsDatePattern, wsTimePattern, 2299 eCategory != FX_DATETIMETYPE_TimeDate, 2300 pLocale); 2301 return true; 2302 } 2303 } 2304 return false; 2305 } 2306 2307 bool CFGAS_FormatString::FormatZero(const WideString& wsPattern, 2308 WideString* wsOutput) { 2309 if (wsPattern.IsEmpty()) 2310 return false; 2311 2312 WideString wsTextFormat = GetTextFormat(wsPattern, L"zero"); 2313 int32_t iPattern = 0; 2314 const wchar_t* pStrPattern = wsTextFormat.c_str(); 2315 int32_t iLenPattern = wsTextFormat.GetLength(); 2316 while (iPattern < iLenPattern) { 2317 if (pStrPattern[iPattern] == '\'') { 2318 *wsOutput += GetLiteralText(pStrPattern, &iPattern, iLenPattern); 2319 iPattern++; 2320 } else { 2321 *wsOutput += pStrPattern[iPattern++]; 2322 } 2323 } 2324 return true; 2325 } 2326 2327 bool CFGAS_FormatString::FormatNull(const WideString& wsPattern, 2328 WideString* wsOutput) { 2329 if (wsPattern.IsEmpty()) 2330 return false; 2331 2332 WideString wsTextFormat = GetTextFormat(wsPattern, L"null"); 2333 int32_t iPattern = 0; 2334 const wchar_t* pStrPattern = wsTextFormat.c_str(); 2335 int32_t iLenPattern = wsTextFormat.GetLength(); 2336 while (iPattern < iLenPattern) { 2337 if (pStrPattern[iPattern] == '\'') { 2338 *wsOutput += GetLiteralText(pStrPattern, &iPattern, iLenPattern); 2339 iPattern++; 2340 continue; 2341 } 2342 *wsOutput += pStrPattern[iPattern++]; 2343 } 2344 return true; 2345 } 2346