7#include "fxjs/cjs_util.h"
16#include "build/build_config.h"
17#include "core/fxcrt/check_op.h"
18#include "core/fxcrt/compiler_specific.h"
19#include "core/fxcrt/fx_extension.h"
20#include "core/fxcrt/span.h"
21#include "fxjs/cjs_event_context.h"
22#include "fxjs/cjs_object.h"
23#include "fxjs/cjs_publicmethods.h"
24#include "fxjs/cjs_runtime.h"
25#include "fxjs/fx_date_helpers.h"
27#include "fxjs/js_define.h"
28#include "fxjs/js_resources.h"
29#include "v8/include/v8-date.h"
31#if BUILDFLAG(IS_ANDROID)
40 const wchar_t* lpszJSMark;
41 const wchar_t* lpszCppMark;
46struct TbConvertAdditional {
51const TbConvert kTbConvertTable[] = {
52 {L"mmmm", L"%B"}, {L"mmm", L"%b"}, {L"mm", L"%m"}, {L"dddd", L"%A"},
53 {L"ddd", L"%a"}, {L"dd", L"%d"}, {L"yyyy", L"%Y"}, {L"yy", L"%y"},
54 {L"HH", L"%H"}, {L"hh", L"%I"}, {L"MM", L"%M"}, {L"ss", L"%S"},
57 {L"tt", L"%p"}, {L"h", L"%#I"},
59 {L"tt", L"%P"}, {L"h", L"%l"},
63enum CaseMode { kPreserveCase, kUpperCase, kLowerCase };
65wchar_t TranslateCase(
wchar_t input, CaseMode eMode) {
76 {
"printd", printd_static},
77 {
"printf", printf_static},
78 {
"printx", printx_static},
79 {
"scand", scand_static},
80 {
"byteToChar", byteToChar_static}};
82uint32_t CJS_Util::ObjDefnID = 0;
83const char CJS_Util::kName[] =
"util";
93 JSConstructor<CJS_Util>, JSDestructor);
94 DefineMethods(pEngine, ObjDefnID, MethodSpecs);
97CJS_Util::
CJS_Util(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime)
102CJS_Result CJS_Util::printf(CJS_Runtime* pRuntime,
103 pdfium::span<v8::Local<v8::Value>> params) {
104 const size_t num_params = params.size();
110 WideString unsafe_fmt_string = L'S' + pRuntime->ToWideString(params[0]);
111 std::vector<WideString> unsafe_conversion_specifiers;
116 std::optional<size_t> offset_end =
117 unsafe_fmt_string.Find(L"%", offset + 1);
118 if (!offset_end.has_value()) {
119 unsafe_conversion_specifiers.push_back(
120 unsafe_fmt_string.Last(unsafe_fmt_string.GetLength() - offset));
124 unsafe_conversion_specifiers.push_back(
125 unsafe_fmt_string.Substr(offset, offset_end.value() - offset));
126 offset = offset_end.value();
130 WideString result = unsafe_conversion_specifiers[0];
131 for (size_t i = 1; i < unsafe_conversion_specifiers.size(); ++i) {
132 WideString fmt = unsafe_conversion_specifiers[i];
133 if (i >= num_params) {
141 segment = WideString::Format(fmt.c_str(), pRuntime->ToInt32(params[i]));
143 case DataType::kDouble:
145 WideString::Format(fmt.c_str(), pRuntime->ToDouble(params[i]));
147 case DataType::kString:
148 segment = WideString::Format(fmt.c_str(),
149 pRuntime->ToWideString(params[i]).c_str());
160 auto result_view = result.AsStringView();
162 pRuntime->NewString(result_view.Last(result_view.GetLength() - 1))
);
165CJS_Result CJS_Util::printd(CJS_Runtime* pRuntime,
166 pdfium::span<v8::Local<v8::Value>> params) {
167 const size_t iSize = params.size();
171 if (!fxv8::IsDate(params[1]))
174 v8::Local<v8::Date> v8_date = params[1].As<v8::Date>();
175 if (v8_date.IsEmpty() || isnan(pRuntime->ToDouble(v8_date)))
178 double date = FX_LocalTime(pRuntime->ToDouble(v8_date));
186 if (params[0]->IsNumber()) {
188 switch (pRuntime->ToInt32(params[0])) {
191 month
, day
, hour
, min
, sec
);
195 month
, day
, hour
, min
, sec
);
199 month
, day
, hour
, min
, sec
);
208 if (!params[0]->IsString())
212 if (iSize > 2 && pRuntime->ToBoolean(params[2]))
217 std::wstring cFormat = pRuntime->ToWideString(params[0]).c_str();
218 cFormat.erase(
std::remove(cFormat.begin(), cFormat.end(),
'%'),
221 for (
const auto& conversion : kTbConvertTable) {
224 nFound = cFormat.find(conversion.lpszJSMark, nFound);
225 if (nFound == std::wstring::npos) {
228 cFormat.replace(nFound, wcslen(conversion.lpszJSMark),
229 conversion.lpszCppMark);
236 const TbConvertAdditional table_additional[] = {
237 {L'm', month}, {L'd', day},
238 {L'H', hour}, {L'h', hour > 12 ? hour - 12 : hour},
239 {L'M', min}, {L's', sec},
242 for (
const auto& conversion : table_additional) {
245 nFound = cFormat.find(conversion.js_mark, nFound);
246 if (nFound == std::wstring::npos) {
249 if (nFound != 0 && cFormat[nFound - 1] == L'%') {
253 cFormat.replace(nFound, 1,
259 time.tm_year = year - 1900;
260 time.tm_mon = month - 1;
266 wchar_t buf[64] = {};
272CJS_Result CJS_Util::printx(CJS_Runtime* pRuntime,
273 pdfium::span<v8::Local<v8::Value>> params) {
274 if (params.size() < 2)
277 return CJS_Result::Success(
278 pRuntime->NewString(StringPrintx(pRuntime->ToWideString(params[0]),
279 pRuntime->ToWideString(params[1]))
287 wsResult.Reserve(wsFormat.GetLength());
288 size_t iSourceIdx = 0;
289 size_t iFormatIdx = 0;
290 CaseMode eCaseMode = kPreserveCase;
291 bool bEscaped =
false;
292 while (iFormatIdx < wsFormat.GetLength()) {
295 wsResult += wsFormat[iFormatIdx];
299 switch (wsFormat[iFormatIdx]) {
305 eCaseMode = kLowerCase;
309 eCaseMode = kUpperCase;
313 eCaseMode = kPreserveCase;
317 if (iSourceIdx < wsSource.GetLength()) {
318 wsResult += TranslateCase(wsSource[iSourceIdx], eCaseMode);
324 if (iSourceIdx < wsSource.GetLength()) {
325 if (isascii(wsSource[iSourceIdx]) && isalnum(wsSource[iSourceIdx])) {
326 wsResult += TranslateCase(wsSource[iSourceIdx], eCaseMode);
335 if (iSourceIdx < wsSource.GetLength()) {
336 if (isascii(wsSource[iSourceIdx]) && isalpha(wsSource[iSourceIdx])) {
337 wsResult += TranslateCase(wsSource[iSourceIdx], eCaseMode);
346 if (iSourceIdx < wsSource.GetLength()) {
347 if (FXSYS_IsDecimalDigit(wsSource[iSourceIdx])) {
348 wsResult += wsSource[iSourceIdx];
357 if (iSourceIdx < wsSource.GetLength()) {
358 wsResult += TranslateCase(wsSource[iSourceIdx], eCaseMode);
365 wsResult += wsFormat[iFormatIdx];
373CJS_Result CJS_Util::scand(CJS_Runtime* pRuntime,
374 pdfium::span<v8::Local<v8::Value>> params) {
375 if (params.size() < 2)
378 WideString sFormat = pRuntime->ToWideString(params[0]);
379 WideString sDate = pRuntime->ToWideString(params[1]);
381 if (sDate.GetLength() > 0)
382 dDate = CJS_PublicMethods::ParseDateUsingFormat(pRuntime->GetIsolate(),
383 sDate, sFormat,
nullptr);
390CJS_Result CJS_Util::byteToChar(CJS_Runtime* pRuntime,
391 pdfium::span<v8::Local<v8::Value>> params) {
392 if (params.size() < 1)
395 int arg = pRuntime->ToInt32(params[0]);
396 if (arg < 0 || arg > 255)
405 enum State { kBefore, kFlags, kWidth, kPrecision, kSpecifier, kAfter };
408 State state = kBefore;
409 size_t precision_digits = 0;
411 while (i < sFormat->GetLength()) {
412 wchar_t c = (*sFormat)[i];
419 if (c == L'+' || c == L'-' || c == L'#' || c == L' ') {
431 }
else if (c == L'.') {
450 if (c == L'c' || c == L'C' || c == L'd' || c == L'i' || c == L'o' ||
451 c == L'u' || c == L'x' || c == L'X') {
453 }
else if (c == L'e' || c == L'E' || c == L'f' || c == L'g' ||
456 }
else if (c == L's' || c == L'S') {
460 sFormat->SetAt(i, L'S');
static CJS_Result Success()
static CJS_Result Failure(JSMessage id)
CJS_Util(v8::Local< v8::Object > pObject, CJS_Runtime *pRuntime)
static uint32_t GetObjDefnID()
static void DefineJSObjects(CFXJS_Engine *pEngine)
static DataType ParseDataType(WideString *sFormat)
static WideString StringPrintx(const WideString &cFormat, const WideString &cSource)
WideString & operator+=(const WideString &str)
static WideString Format(const wchar_t *pFormat,...)
WideString & operator=(WideString &&that) noexcept
static WideString FormatInteger(int i)
bool FXSYS_IsDecimalDigit(wchar_t c)
bool FXSYS_iswlower(int32_t c)
bool FXSYS_iswupper(int32_t c)
@ kSecondParamNotDateError
@ kSecondParamInvalidDateError
int FX_GetMonthFromTime(double dt)
int FX_GetYearFromTime(double dt)
int FX_GetDayFromTime(double dt)
int FX_GetSecFromTime(double dt)
int FX_GetHourFromTime(double dt)
int FX_GetMinFromTime(double dt)
fxcrt::WideString WideString