John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 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. |
Lei Zhang | a6d9f0e | 2015-06-13 00:48:38 -0700 | [diff] [blame] | 4 | |
John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 5 | // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
| 6 | |
Dan Sinclair | f766ad2 | 2016-03-14 13:51:24 -0400 | [diff] [blame] | 7 | #include "fpdfsdk/javascript/util.h" |
Tom Sepez | 3745841 | 2015-10-06 11:33:46 -0700 | [diff] [blame] | 8 | |
Lei Zhang | 6b37a5f | 2015-12-25 00:20:59 -0800 | [diff] [blame] | 9 | #include <time.h> |
| 10 | |
tsepez | 86a61dc | 2016-03-25 10:00:11 -0700 | [diff] [blame] | 11 | #include <algorithm> |
Tom Sepez | df950b8 | 2017-08-04 11:33:49 -0700 | [diff] [blame] | 12 | #include <cmath> |
Lei Zhang | e247ec4 | 2017-04-20 21:41:36 -0700 | [diff] [blame] | 13 | #include <cwctype> |
Dan Sinclair | 3ebd121 | 2016-03-09 09:59:23 -0500 | [diff] [blame] | 14 | #include <string> |
| 15 | #include <vector> |
| 16 | |
Dan Sinclair | cfb1944 | 2017-04-20 13:13:04 -0400 | [diff] [blame] | 17 | #include "core/fxcrt/fx_extension.h" |
Dan Sinclair | f766ad2 | 2016-03-14 13:51:24 -0400 | [diff] [blame] | 18 | #include "fpdfsdk/javascript/JS_Define.h" |
| 19 | #include "fpdfsdk/javascript/JS_EventHandler.h" |
| 20 | #include "fpdfsdk/javascript/JS_Object.h" |
Dan Sinclair | f766ad2 | 2016-03-14 13:51:24 -0400 | [diff] [blame] | 21 | #include "fpdfsdk/javascript/JS_Value.h" |
| 22 | #include "fpdfsdk/javascript/PublicMethods.h" |
Tom Sepez | d6ae2af | 2017-02-16 11:49:55 -0800 | [diff] [blame] | 23 | #include "fpdfsdk/javascript/cjs_event_context.h" |
dsinclair | 64376be | 2016-03-31 20:03:24 -0700 | [diff] [blame] | 24 | #include "fpdfsdk/javascript/cjs_runtime.h" |
Dan Sinclair | f766ad2 | 2016-03-14 13:51:24 -0400 | [diff] [blame] | 25 | #include "fpdfsdk/javascript/resource.h" |
John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 26 | |
Dan Sinclair | 698aed7 | 2017-09-26 16:24:49 -0400 | [diff] [blame] | 27 | #if _FX_OS_ == _FX_OS_ANDROID_ |
John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 28 | #include <ctype.h> |
| 29 | #endif |
| 30 | |
Tom Sepez | 04557b8 | 2017-02-16 09:43:10 -0800 | [diff] [blame] | 31 | JSConstSpec CJS_Util::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}}; |
John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 32 | |
Tom Sepez | 04557b8 | 2017-02-16 09:43:10 -0800 | [diff] [blame] | 33 | JSPropertySpec CJS_Util::PropertySpecs[] = {{0, 0, 0}}; |
John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 34 | |
Tom Sepez | 04557b8 | 2017-02-16 09:43:10 -0800 | [diff] [blame] | 35 | JSMethodSpec CJS_Util::MethodSpecs[] = { |
Tom Sepez | 9b99b63 | 2017-02-21 15:05:57 -0800 | [diff] [blame] | 36 | {"printd", printd_static}, {"printf", printf_static}, |
| 37 | {"printx", printx_static}, {"scand", scand_static}, |
| 38 | {"byteToChar", byteToChar_static}, {0, 0}}; |
John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 39 | |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 40 | IMPLEMENT_JS_CLASS(CJS_Util, util) |
John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 41 | |
tsepez | 86a61dc | 2016-03-25 10:00:11 -0700 | [diff] [blame] | 42 | namespace { |
| 43 | |
| 44 | // Map PDF-style directives to equivalent wcsftime directives. Not |
| 45 | // all have direct equivalents, though. |
| 46 | struct TbConvert { |
Dan Sinclair | 812e96c | 2017-03-13 16:43:37 -0400 | [diff] [blame] | 47 | const wchar_t* lpszJSMark; |
| 48 | const wchar_t* lpszCppMark; |
tsepez | 86a61dc | 2016-03-25 10:00:11 -0700 | [diff] [blame] | 49 | }; |
| 50 | |
| 51 | // Map PDF-style directives lacking direct wcsftime directives to |
| 52 | // the value with which they will be replaced. |
| 53 | struct TbConvertAdditional { |
Dan Sinclair | 812e96c | 2017-03-13 16:43:37 -0400 | [diff] [blame] | 54 | const wchar_t* lpszJSMark; |
tsepez | 86a61dc | 2016-03-25 10:00:11 -0700 | [diff] [blame] | 55 | int iValue; |
| 56 | }; |
| 57 | |
| 58 | const TbConvert TbConvertTable[] = { |
| 59 | {L"mmmm", L"%B"}, {L"mmm", L"%b"}, {L"mm", L"%m"}, {L"dddd", L"%A"}, |
| 60 | {L"ddd", L"%a"}, {L"dd", L"%d"}, {L"yyyy", L"%Y"}, {L"yy", L"%y"}, |
| 61 | {L"HH", L"%H"}, {L"hh", L"%I"}, {L"MM", L"%M"}, {L"ss", L"%S"}, |
| 62 | {L"TT", L"%p"}, |
| 63 | #if defined(_WIN32) |
| 64 | {L"tt", L"%p"}, {L"h", L"%#I"}, |
| 65 | #else |
| 66 | {L"tt", L"%P"}, {L"h", L"%l"}, |
| 67 | #endif |
| 68 | }; |
| 69 | |
tsepez | 86a61dc | 2016-03-25 10:00:11 -0700 | [diff] [blame] | 70 | } // namespace |
| 71 | |
| 72 | util::util(CJS_Object* pJSObject) : CJS_EmbedObj(pJSObject) {} |
| 73 | |
| 74 | util::~util() {} |
| 75 | |
Tom Sepez | b1670b5 | 2017-02-16 17:01:00 -0800 | [diff] [blame] | 76 | bool util::printf(CJS_Runtime* pRuntime, |
tsepez | 4cf5515 | 2016-11-02 14:37:54 -0700 | [diff] [blame] | 77 | const std::vector<CJS_Value>& params, |
| 78 | CJS_Value& vRet, |
Ryan Harrison | 275e260 | 2017-09-18 14:23:18 -0400 | [diff] [blame] | 79 | WideString& sError) { |
Lei Zhang | 574b574 | 2017-03-30 12:41:55 -0700 | [diff] [blame] | 80 | const size_t iSize = params.size(); |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 81 | if (iSize < 1) |
tsepez | 4cf5515 | 2016-11-02 14:37:54 -0700 | [diff] [blame] | 82 | return false; |
Lei Zhang | 574b574 | 2017-03-30 12:41:55 -0700 | [diff] [blame] | 83 | |
Tom Sepez | ffbc0d9 | 2017-07-17 09:29:05 -0700 | [diff] [blame] | 84 | std::wstring unsafe_fmt_string(params[0].ToCFXWideString(pRuntime).c_str()); |
| 85 | std::vector<std::wstring> unsafe_conversion_specifiers; |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 86 | int iOffset = 0; |
| 87 | int iOffend = 0; |
Tom Sepez | ffbc0d9 | 2017-07-17 09:29:05 -0700 | [diff] [blame] | 88 | unsafe_fmt_string.insert(unsafe_fmt_string.begin(), L'S'); |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 89 | while (iOffset != -1) { |
Tom Sepez | ffbc0d9 | 2017-07-17 09:29:05 -0700 | [diff] [blame] | 90 | iOffend = unsafe_fmt_string.find(L"%", iOffset + 1); |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 91 | std::wstring strSub; |
| 92 | if (iOffend == -1) |
Tom Sepez | ffbc0d9 | 2017-07-17 09:29:05 -0700 | [diff] [blame] | 93 | strSub = unsafe_fmt_string.substr(iOffset); |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 94 | else |
Tom Sepez | ffbc0d9 | 2017-07-17 09:29:05 -0700 | [diff] [blame] | 95 | strSub = unsafe_fmt_string.substr(iOffset, iOffend - iOffset); |
| 96 | unsafe_conversion_specifiers.push_back(strSub); |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 97 | iOffset = iOffend; |
| 98 | } |
| 99 | |
| 100 | std::wstring c_strResult; |
Tom Sepez | ffbc0d9 | 2017-07-17 09:29:05 -0700 | [diff] [blame] | 101 | for (size_t iIndex = 0; iIndex < unsafe_conversion_specifiers.size(); |
| 102 | ++iIndex) { |
| 103 | std::wstring c_strFormat = unsafe_conversion_specifiers[iIndex]; |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 104 | if (iIndex == 0) { |
| 105 | c_strResult = c_strFormat; |
| 106 | continue; |
| 107 | } |
| 108 | |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 109 | if (iIndex >= iSize) { |
| 110 | c_strResult += c_strFormat; |
| 111 | continue; |
| 112 | } |
| 113 | |
Ryan Harrison | 275e260 | 2017-09-18 14:23:18 -0400 | [diff] [blame] | 114 | WideString strSegment; |
tsepez | 86a61dc | 2016-03-25 10:00:11 -0700 | [diff] [blame] | 115 | switch (ParseDataType(&c_strFormat)) { |
Tom Sepez | ffbc0d9 | 2017-07-17 09:29:05 -0700 | [diff] [blame] | 116 | case UTIL_INT: |
tsepez | b469424 | 2016-08-15 16:44:55 -0700 | [diff] [blame] | 117 | strSegment.Format(c_strFormat.c_str(), params[iIndex].ToInt(pRuntime)); |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 118 | break; |
| 119 | case UTIL_DOUBLE: |
tsepez | f3dc8c6 | 2016-08-10 06:29:29 -0700 | [diff] [blame] | 120 | strSegment.Format(c_strFormat.c_str(), |
tsepez | b469424 | 2016-08-15 16:44:55 -0700 | [diff] [blame] | 121 | params[iIndex].ToDouble(pRuntime)); |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 122 | break; |
| 123 | case UTIL_STRING: |
tsepez | b469424 | 2016-08-15 16:44:55 -0700 | [diff] [blame] | 124 | strSegment.Format(c_strFormat.c_str(), |
| 125 | params[iIndex].ToCFXWideString(pRuntime).c_str()); |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 126 | break; |
| 127 | default: |
Tom Sepez | ffbc0d9 | 2017-07-17 09:29:05 -0700 | [diff] [blame] | 128 | strSegment.Format(L"%ls", c_strFormat.c_str()); |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 129 | break; |
| 130 | } |
Lei Zhang | 1e25e12 | 2017-06-16 02:14:40 -0700 | [diff] [blame] | 131 | c_strResult += strSegment.c_str(); |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 132 | } |
| 133 | |
| 134 | c_strResult.erase(c_strResult.begin()); |
tsepez | f3dc8c6 | 2016-08-10 06:29:29 -0700 | [diff] [blame] | 135 | vRet = CJS_Value(pRuntime, c_strResult.c_str()); |
tsepez | 4cf5515 | 2016-11-02 14:37:54 -0700 | [diff] [blame] | 136 | return true; |
John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 137 | } |
| 138 | |
Tom Sepez | b1670b5 | 2017-02-16 17:01:00 -0800 | [diff] [blame] | 139 | bool util::printd(CJS_Runtime* pRuntime, |
tsepez | 4cf5515 | 2016-11-02 14:37:54 -0700 | [diff] [blame] | 140 | const std::vector<CJS_Value>& params, |
| 141 | CJS_Value& vRet, |
Ryan Harrison | 275e260 | 2017-09-18 14:23:18 -0400 | [diff] [blame] | 142 | WideString& sError) { |
Lei Zhang | 574b574 | 2017-03-30 12:41:55 -0700 | [diff] [blame] | 143 | const size_t iSize = params.size(); |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 144 | if (iSize < 2) |
tsepez | 4cf5515 | 2016-11-02 14:37:54 -0700 | [diff] [blame] | 145 | return false; |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 146 | |
Lei Zhang | 574b574 | 2017-03-30 12:41:55 -0700 | [diff] [blame] | 147 | const CJS_Value& p1 = params[0]; |
| 148 | const CJS_Value& p2 = params[1]; |
tsepez | f3c8832 | 2016-08-09 07:30:38 -0700 | [diff] [blame] | 149 | CJS_Date jsDate; |
tsepez | b469424 | 2016-08-15 16:44:55 -0700 | [diff] [blame] | 150 | if (!p2.ConvertToDate(pRuntime, jsDate)) { |
tsepez | cd5dc85 | 2016-09-08 11:23:24 -0700 | [diff] [blame] | 151 | sError = JSGetStringFromID(IDS_STRING_JSPRINT1); |
tsepez | 4cf5515 | 2016-11-02 14:37:54 -0700 | [diff] [blame] | 152 | return false; |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 153 | } |
| 154 | |
tsepez | b469424 | 2016-08-15 16:44:55 -0700 | [diff] [blame] | 155 | if (!jsDate.IsValidDate(pRuntime)) { |
tsepez | cd5dc85 | 2016-09-08 11:23:24 -0700 | [diff] [blame] | 156 | sError = JSGetStringFromID(IDS_STRING_JSPRINT2); |
tsepez | 4cf5515 | 2016-11-02 14:37:54 -0700 | [diff] [blame] | 157 | return false; |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 158 | } |
| 159 | |
Tom Sepez | 39bfe12 | 2015-09-17 15:25:23 -0700 | [diff] [blame] | 160 | if (p1.GetType() == CJS_Value::VT_number) { |
Ryan Harrison | 275e260 | 2017-09-18 14:23:18 -0400 | [diff] [blame] | 161 | WideString swResult; |
tsepez | b469424 | 2016-08-15 16:44:55 -0700 | [diff] [blame] | 162 | switch (p1.ToInt(pRuntime)) { |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 163 | case 0: |
tsepez | b469424 | 2016-08-15 16:44:55 -0700 | [diff] [blame] | 164 | swResult.Format(L"D:%04d%02d%02d%02d%02d%02d", jsDate.GetYear(pRuntime), |
| 165 | jsDate.GetMonth(pRuntime) + 1, jsDate.GetDay(pRuntime), |
| 166 | jsDate.GetHours(pRuntime), jsDate.GetMinutes(pRuntime), |
| 167 | jsDate.GetSeconds(pRuntime)); |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 168 | break; |
| 169 | case 1: |
tsepez | f3c8832 | 2016-08-09 07:30:38 -0700 | [diff] [blame] | 170 | swResult.Format(L"%04d.%02d.%02d %02d:%02d:%02d", |
tsepez | b469424 | 2016-08-15 16:44:55 -0700 | [diff] [blame] | 171 | jsDate.GetYear(pRuntime), jsDate.GetMonth(pRuntime) + 1, |
| 172 | jsDate.GetDay(pRuntime), jsDate.GetHours(pRuntime), |
| 173 | jsDate.GetMinutes(pRuntime), |
| 174 | jsDate.GetSeconds(pRuntime)); |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 175 | break; |
| 176 | case 2: |
tsepez | f3c8832 | 2016-08-09 07:30:38 -0700 | [diff] [blame] | 177 | swResult.Format(L"%04d/%02d/%02d %02d:%02d:%02d", |
tsepez | b469424 | 2016-08-15 16:44:55 -0700 | [diff] [blame] | 178 | jsDate.GetYear(pRuntime), jsDate.GetMonth(pRuntime) + 1, |
| 179 | jsDate.GetDay(pRuntime), jsDate.GetHours(pRuntime), |
| 180 | jsDate.GetMinutes(pRuntime), |
| 181 | jsDate.GetSeconds(pRuntime)); |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 182 | break; |
| 183 | default: |
tsepez | cd5dc85 | 2016-09-08 11:23:24 -0700 | [diff] [blame] | 184 | sError = JSGetStringFromID(IDS_STRING_JSVALUEERROR); |
tsepez | 4cf5515 | 2016-11-02 14:37:54 -0700 | [diff] [blame] | 185 | return false; |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 186 | } |
| 187 | |
tsepez | f3dc8c6 | 2016-08-10 06:29:29 -0700 | [diff] [blame] | 188 | vRet = CJS_Value(pRuntime, swResult.c_str()); |
tsepez | 4cf5515 | 2016-11-02 14:37:54 -0700 | [diff] [blame] | 189 | return true; |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 190 | } |
tsepez | 86a61dc | 2016-03-25 10:00:11 -0700 | [diff] [blame] | 191 | |
Tom Sepez | 39bfe12 | 2015-09-17 15:25:23 -0700 | [diff] [blame] | 192 | if (p1.GetType() == CJS_Value::VT_string) { |
tsepez | b469424 | 2016-08-15 16:44:55 -0700 | [diff] [blame] | 193 | if (iSize > 2 && params[2].ToBool(pRuntime)) { |
tsepez | cd5dc85 | 2016-09-08 11:23:24 -0700 | [diff] [blame] | 194 | sError = JSGetStringFromID(IDS_STRING_JSNOTSUPPORT); |
tsepez | 4cf5515 | 2016-11-02 14:37:54 -0700 | [diff] [blame] | 195 | return false; // currently, it doesn't support XFAPicture. |
Tom Sepez | 2f2ffec | 2015-07-23 14:42:09 -0700 | [diff] [blame] | 196 | } |
John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 197 | |
tsepez | 86a61dc | 2016-03-25 10:00:11 -0700 | [diff] [blame] | 198 | // Convert PDF-style format specifiers to wcsftime specifiers. Remove any |
| 199 | // pre-existing %-directives before inserting our own. |
tsepez | b469424 | 2016-08-15 16:44:55 -0700 | [diff] [blame] | 200 | std::basic_string<wchar_t> cFormat = p1.ToCFXWideString(pRuntime).c_str(); |
tsepez | 86a61dc | 2016-03-25 10:00:11 -0700 | [diff] [blame] | 201 | cFormat.erase(std::remove(cFormat.begin(), cFormat.end(), '%'), |
| 202 | cFormat.end()); |
| 203 | |
| 204 | for (size_t i = 0; i < FX_ArraySize(TbConvertTable); ++i) { |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 205 | int iStart = 0; |
| 206 | int iEnd; |
tsepez | 86a61dc | 2016-03-25 10:00:11 -0700 | [diff] [blame] | 207 | while ((iEnd = cFormat.find(TbConvertTable[i].lpszJSMark, iStart)) != |
| 208 | -1) { |
| 209 | cFormat.replace(iEnd, FXSYS_wcslen(TbConvertTable[i].lpszJSMark), |
| 210 | TbConvertTable[i].lpszCppMark); |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 211 | iStart = iEnd; |
| 212 | } |
Tom Sepez | 2f2ffec | 2015-07-23 14:42:09 -0700 | [diff] [blame] | 213 | } |
John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 214 | |
tsepez | b469424 | 2016-08-15 16:44:55 -0700 | [diff] [blame] | 215 | int iYear = jsDate.GetYear(pRuntime); |
Lei Zhang | 2bf942d | 2017-06-16 13:48:19 -0700 | [diff] [blame] | 216 | if (iYear < 0) { |
| 217 | sError = JSGetStringFromID(IDS_STRING_JSVALUEERROR); |
| 218 | return false; |
| 219 | } |
| 220 | |
tsepez | b469424 | 2016-08-15 16:44:55 -0700 | [diff] [blame] | 221 | int iMonth = jsDate.GetMonth(pRuntime); |
| 222 | int iDay = jsDate.GetDay(pRuntime); |
| 223 | int iHour = jsDate.GetHours(pRuntime); |
| 224 | int iMin = jsDate.GetMinutes(pRuntime); |
| 225 | int iSec = jsDate.GetSeconds(pRuntime); |
John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 226 | |
Lei Zhang | 1e25e12 | 2017-06-16 02:14:40 -0700 | [diff] [blame] | 227 | static const TbConvertAdditional cTableAd[] = { |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 228 | {L"m", iMonth + 1}, {L"d", iDay}, |
| 229 | {L"H", iHour}, {L"h", iHour > 12 ? iHour - 12 : iHour}, |
| 230 | {L"M", iMin}, {L"s", iSec}, |
Tom Sepez | 2f2ffec | 2015-07-23 14:42:09 -0700 | [diff] [blame] | 231 | }; |
John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 232 | |
tsepez | 86a61dc | 2016-03-25 10:00:11 -0700 | [diff] [blame] | 233 | for (size_t i = 0; i < FX_ArraySize(cTableAd); ++i) { |
Ryan Harrison | 275e260 | 2017-09-18 14:23:18 -0400 | [diff] [blame] | 234 | WideString sValue; |
Lei Zhang | b9c3197 | 2015-08-11 14:09:35 -0700 | [diff] [blame] | 235 | sValue.Format(L"%d", cTableAd[i].iValue); |
John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 236 | |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 237 | int iStart = 0; |
| 238 | int iEnd; |
Lei Zhang | b9c3197 | 2015-08-11 14:09:35 -0700 | [diff] [blame] | 239 | while ((iEnd = cFormat.find(cTableAd[i].lpszJSMark, iStart)) != -1) { |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 240 | if (iEnd > 0) { |
| 241 | if (cFormat[iEnd - 1] == L'%') { |
| 242 | iStart = iEnd + 1; |
| 243 | continue; |
| 244 | } |
Tom Sepez | 2f2ffec | 2015-07-23 14:42:09 -0700 | [diff] [blame] | 245 | } |
Lei Zhang | 1e25e12 | 2017-06-16 02:14:40 -0700 | [diff] [blame] | 246 | cFormat.replace(iEnd, FXSYS_wcslen(cTableAd[i].lpszJSMark), |
| 247 | sValue.c_str()); |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 248 | iStart = iEnd; |
| 249 | } |
Tom Sepez | 2f2ffec | 2015-07-23 14:42:09 -0700 | [diff] [blame] | 250 | } |
John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 251 | |
tsepez | 86a61dc | 2016-03-25 10:00:11 -0700 | [diff] [blame] | 252 | struct tm time = {}; |
| 253 | time.tm_year = iYear - 1900; |
| 254 | time.tm_mon = iMonth; |
| 255 | time.tm_mday = iDay; |
| 256 | time.tm_hour = iHour; |
| 257 | time.tm_min = iMin; |
| 258 | time.tm_sec = iSec; |
| 259 | |
Tom Sepez | 2f2ffec | 2015-07-23 14:42:09 -0700 | [diff] [blame] | 260 | wchar_t buf[64] = {}; |
Lei Zhang | 2bf942d | 2017-06-16 13:48:19 -0700 | [diff] [blame] | 261 | FXSYS_wcsftime(buf, 64, cFormat.c_str(), &time); |
Tom Sepez | 2f2ffec | 2015-07-23 14:42:09 -0700 | [diff] [blame] | 262 | cFormat = buf; |
tsepez | f3dc8c6 | 2016-08-10 06:29:29 -0700 | [diff] [blame] | 263 | vRet = CJS_Value(pRuntime, cFormat.c_str()); |
tsepez | 4cf5515 | 2016-11-02 14:37:54 -0700 | [diff] [blame] | 264 | return true; |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 265 | } |
tsepez | 86a61dc | 2016-03-25 10:00:11 -0700 | [diff] [blame] | 266 | |
tsepez | cd5dc85 | 2016-09-08 11:23:24 -0700 | [diff] [blame] | 267 | sError = JSGetStringFromID(IDS_STRING_JSTYPEERROR); |
tsepez | 4cf5515 | 2016-11-02 14:37:54 -0700 | [diff] [blame] | 268 | return false; |
John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 269 | } |
| 270 | |
Tom Sepez | b1670b5 | 2017-02-16 17:01:00 -0800 | [diff] [blame] | 271 | bool util::printx(CJS_Runtime* pRuntime, |
tsepez | 4cf5515 | 2016-11-02 14:37:54 -0700 | [diff] [blame] | 272 | const std::vector<CJS_Value>& params, |
| 273 | CJS_Value& vRet, |
Ryan Harrison | 275e260 | 2017-09-18 14:23:18 -0400 | [diff] [blame] | 274 | WideString& sError) { |
tsepez | 4f1f41f | 2016-03-28 14:13:16 -0700 | [diff] [blame] | 275 | if (params.size() < 2) { |
tsepez | cd5dc85 | 2016-09-08 11:23:24 -0700 | [diff] [blame] | 276 | sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR); |
tsepez | 4cf5515 | 2016-11-02 14:37:54 -0700 | [diff] [blame] | 277 | return false; |
tsepez | 4f1f41f | 2016-03-28 14:13:16 -0700 | [diff] [blame] | 278 | } |
tsepez | f3dc8c6 | 2016-08-10 06:29:29 -0700 | [diff] [blame] | 279 | |
tsepez | b469424 | 2016-08-15 16:44:55 -0700 | [diff] [blame] | 280 | vRet = CJS_Value(pRuntime, printx(params[0].ToCFXWideString(pRuntime), |
| 281 | params[1].ToCFXWideString(pRuntime)) |
| 282 | .c_str()); |
tsepez | f3dc8c6 | 2016-08-10 06:29:29 -0700 | [diff] [blame] | 283 | |
tsepez | 4cf5515 | 2016-11-02 14:37:54 -0700 | [diff] [blame] | 284 | return true; |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 285 | } |
| 286 | |
tsepez | 4f1f41f | 2016-03-28 14:13:16 -0700 | [diff] [blame] | 287 | enum CaseMode { kPreserveCase, kUpperCase, kLowerCase }; |
| 288 | |
Dan Sinclair | 812e96c | 2017-03-13 16:43:37 -0400 | [diff] [blame] | 289 | static wchar_t TranslateCase(wchar_t input, CaseMode eMode) { |
Lei Zhang | ef002c8 | 2017-04-24 16:28:07 -0700 | [diff] [blame] | 290 | if (eMode == kLowerCase && FXSYS_isupper(input)) |
tsepez | 4f1f41f | 2016-03-28 14:13:16 -0700 | [diff] [blame] | 291 | return input | 0x20; |
Lei Zhang | ef002c8 | 2017-04-24 16:28:07 -0700 | [diff] [blame] | 292 | if (eMode == kUpperCase && FXSYS_islower(input)) |
tsepez | 4f1f41f | 2016-03-28 14:13:16 -0700 | [diff] [blame] | 293 | return input & ~0x20; |
| 294 | return input; |
| 295 | } |
| 296 | |
Ryan Harrison | 275e260 | 2017-09-18 14:23:18 -0400 | [diff] [blame] | 297 | WideString util::printx(const WideString& wsFormat, |
| 298 | const WideString& wsSource) { |
| 299 | WideString wsResult; |
tsepez | 4f1f41f | 2016-03-28 14:13:16 -0700 | [diff] [blame] | 300 | FX_STRSIZE iSourceIdx = 0; |
| 301 | FX_STRSIZE iFormatIdx = 0; |
| 302 | CaseMode eCaseMode = kPreserveCase; |
| 303 | bool bEscaped = false; |
| 304 | while (iFormatIdx < wsFormat.GetLength()) { |
| 305 | if (bEscaped) { |
| 306 | bEscaped = false; |
| 307 | wsResult += wsFormat[iFormatIdx]; |
| 308 | ++iFormatIdx; |
| 309 | continue; |
| 310 | } |
| 311 | switch (wsFormat[iFormatIdx]) { |
| 312 | case '\\': { |
| 313 | bEscaped = true; |
| 314 | ++iFormatIdx; |
| 315 | } break; |
| 316 | case '<': { |
| 317 | eCaseMode = kLowerCase; |
| 318 | ++iFormatIdx; |
| 319 | } break; |
| 320 | case '>': { |
| 321 | eCaseMode = kUpperCase; |
| 322 | ++iFormatIdx; |
| 323 | } break; |
| 324 | case '=': { |
| 325 | eCaseMode = kPreserveCase; |
| 326 | ++iFormatIdx; |
| 327 | } break; |
| 328 | case '?': { |
| 329 | if (iSourceIdx < wsSource.GetLength()) { |
| 330 | wsResult += TranslateCase(wsSource[iSourceIdx], eCaseMode); |
| 331 | ++iSourceIdx; |
Tom Sepez | 2f2ffec | 2015-07-23 14:42:09 -0700 | [diff] [blame] | 332 | } |
tsepez | 4f1f41f | 2016-03-28 14:13:16 -0700 | [diff] [blame] | 333 | ++iFormatIdx; |
| 334 | } break; |
| 335 | case 'X': { |
| 336 | if (iSourceIdx < wsSource.GetLength()) { |
Lei Zhang | ef002c8 | 2017-04-24 16:28:07 -0700 | [diff] [blame] | 337 | if (FXSYS_iswalnum(wsSource[iSourceIdx])) { |
tsepez | 4f1f41f | 2016-03-28 14:13:16 -0700 | [diff] [blame] | 338 | wsResult += TranslateCase(wsSource[iSourceIdx], eCaseMode); |
| 339 | ++iFormatIdx; |
| 340 | } |
| 341 | ++iSourceIdx; |
| 342 | } else { |
| 343 | ++iFormatIdx; |
| 344 | } |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 345 | } break; |
| 346 | case 'A': { |
tsepez | 4f1f41f | 2016-03-28 14:13:16 -0700 | [diff] [blame] | 347 | if (iSourceIdx < wsSource.GetLength()) { |
Lei Zhang | ef002c8 | 2017-04-24 16:28:07 -0700 | [diff] [blame] | 348 | if (FXSYS_iswalpha(wsSource[iSourceIdx])) { |
tsepez | 4f1f41f | 2016-03-28 14:13:16 -0700 | [diff] [blame] | 349 | wsResult += TranslateCase(wsSource[iSourceIdx], eCaseMode); |
| 350 | ++iFormatIdx; |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 351 | } |
tsepez | 4f1f41f | 2016-03-28 14:13:16 -0700 | [diff] [blame] | 352 | ++iSourceIdx; |
| 353 | } else { |
| 354 | ++iFormatIdx; |
John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 355 | } |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 356 | } break; |
| 357 | case '9': { |
tsepez | 4f1f41f | 2016-03-28 14:13:16 -0700 | [diff] [blame] | 358 | if (iSourceIdx < wsSource.GetLength()) { |
Lei Zhang | ef002c8 | 2017-04-24 16:28:07 -0700 | [diff] [blame] | 359 | if (std::iswdigit(wsSource[iSourceIdx])) { |
tsepez | 4f1f41f | 2016-03-28 14:13:16 -0700 | [diff] [blame] | 360 | wsResult += wsSource[iSourceIdx]; |
| 361 | ++iFormatIdx; |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 362 | } |
tsepez | 4f1f41f | 2016-03-28 14:13:16 -0700 | [diff] [blame] | 363 | ++iSourceIdx; |
| 364 | } else { |
| 365 | ++iFormatIdx; |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 366 | } |
tsepez | 4f1f41f | 2016-03-28 14:13:16 -0700 | [diff] [blame] | 367 | } break; |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 368 | case '*': { |
tsepez | 4f1f41f | 2016-03-28 14:13:16 -0700 | [diff] [blame] | 369 | if (iSourceIdx < wsSource.GetLength()) { |
| 370 | wsResult += TranslateCase(wsSource[iSourceIdx], eCaseMode); |
| 371 | ++iSourceIdx; |
| 372 | } else { |
| 373 | ++iFormatIdx; |
| 374 | } |
| 375 | } break; |
| 376 | default: { |
| 377 | wsResult += wsFormat[iFormatIdx]; |
| 378 | ++iFormatIdx; |
| 379 | } break; |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 380 | } |
| 381 | } |
tsepez | 4f1f41f | 2016-03-28 14:13:16 -0700 | [diff] [blame] | 382 | return wsResult; |
John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 383 | } |
| 384 | |
Tom Sepez | b1670b5 | 2017-02-16 17:01:00 -0800 | [diff] [blame] | 385 | bool util::scand(CJS_Runtime* pRuntime, |
tsepez | 4cf5515 | 2016-11-02 14:37:54 -0700 | [diff] [blame] | 386 | const std::vector<CJS_Value>& params, |
| 387 | CJS_Value& vRet, |
Ryan Harrison | 275e260 | 2017-09-18 14:23:18 -0400 | [diff] [blame] | 388 | WideString& sError) { |
Lei Zhang | 574b574 | 2017-03-30 12:41:55 -0700 | [diff] [blame] | 389 | if (params.size() < 2) |
tsepez | 4cf5515 | 2016-11-02 14:37:54 -0700 | [diff] [blame] | 390 | return false; |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 391 | |
Ryan Harrison | 275e260 | 2017-09-18 14:23:18 -0400 | [diff] [blame] | 392 | WideString sFormat = params[0].ToCFXWideString(pRuntime); |
| 393 | WideString sDate = params[1].ToCFXWideString(pRuntime); |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 394 | double dDate = JS_GetDateTime(); |
| 395 | if (sDate.GetLength() > 0) { |
Lei Zhang | 9559b7a | 2015-12-21 11:12:20 -0800 | [diff] [blame] | 396 | dDate = CJS_PublicMethods::MakeRegularDate(sDate, sFormat, nullptr); |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 397 | } |
| 398 | |
Tom Sepez | df950b8 | 2017-08-04 11:33:49 -0700 | [diff] [blame] | 399 | if (!std::isnan(dDate)) { |
tsepez | b469424 | 2016-08-15 16:44:55 -0700 | [diff] [blame] | 400 | vRet = CJS_Value(pRuntime, CJS_Date(pRuntime, dDate)); |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 401 | } else { |
tsepez | f3dc8c6 | 2016-08-10 06:29:29 -0700 | [diff] [blame] | 402 | vRet.SetNull(pRuntime); |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 403 | } |
| 404 | |
tsepez | 4cf5515 | 2016-11-02 14:37:54 -0700 | [diff] [blame] | 405 | return true; |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 406 | } |
| 407 | |
Tom Sepez | b1670b5 | 2017-02-16 17:01:00 -0800 | [diff] [blame] | 408 | bool util::byteToChar(CJS_Runtime* pRuntime, |
tsepez | 4cf5515 | 2016-11-02 14:37:54 -0700 | [diff] [blame] | 409 | const std::vector<CJS_Value>& params, |
| 410 | CJS_Value& vRet, |
Ryan Harrison | 275e260 | 2017-09-18 14:23:18 -0400 | [diff] [blame] | 411 | WideString& sError) { |
tsepez | 90d8779 | 2016-03-29 09:21:54 -0700 | [diff] [blame] | 412 | if (params.size() < 1) { |
tsepez | cd5dc85 | 2016-09-08 11:23:24 -0700 | [diff] [blame] | 413 | sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR); |
tsepez | 4cf5515 | 2016-11-02 14:37:54 -0700 | [diff] [blame] | 414 | return false; |
tsepez | 90d8779 | 2016-03-29 09:21:54 -0700 | [diff] [blame] | 415 | } |
tsepez | f3dc8c6 | 2016-08-10 06:29:29 -0700 | [diff] [blame] | 416 | |
tsepez | b469424 | 2016-08-15 16:44:55 -0700 | [diff] [blame] | 417 | int arg = params[0].ToInt(pRuntime); |
tsepez | 90d8779 | 2016-03-29 09:21:54 -0700 | [diff] [blame] | 418 | if (arg < 0 || arg > 255) { |
tsepez | cd5dc85 | 2016-09-08 11:23:24 -0700 | [diff] [blame] | 419 | sError = JSGetStringFromID(IDS_STRING_JSVALUEERROR); |
tsepez | 4cf5515 | 2016-11-02 14:37:54 -0700 | [diff] [blame] | 420 | return false; |
tsepez | 90d8779 | 2016-03-29 09:21:54 -0700 | [diff] [blame] | 421 | } |
tsepez | f3dc8c6 | 2016-08-10 06:29:29 -0700 | [diff] [blame] | 422 | |
Ryan Harrison | 275e260 | 2017-09-18 14:23:18 -0400 | [diff] [blame] | 423 | WideString wStr(static_cast<wchar_t>(arg)); |
tsepez | f3dc8c6 | 2016-08-10 06:29:29 -0700 | [diff] [blame] | 424 | vRet = CJS_Value(pRuntime, wStr.c_str()); |
tsepez | 4cf5515 | 2016-11-02 14:37:54 -0700 | [diff] [blame] | 425 | return true; |
John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 426 | } |
Henrique Nakashima | 3a4ebcc | 2017-07-14 14:24:42 -0400 | [diff] [blame] | 427 | |
Tom Sepez | ffbc0d9 | 2017-07-17 09:29:05 -0700 | [diff] [blame] | 428 | // Ensure that sFormat contains at most one well-understood printf formatting |
| 429 | // directive which is safe to use with a single argument, and return the type |
| 430 | // of argument expected, or -1 otherwise. If -1 is returned, it is NOT safe |
| 431 | // to use sFormat with printf() and it must be copied byte-by-byte. |
Henrique Nakashima | 3a4ebcc | 2017-07-14 14:24:42 -0400 | [diff] [blame] | 432 | int util::ParseDataType(std::wstring* sFormat) { |
Tom Sepez | ffbc0d9 | 2017-07-17 09:29:05 -0700 | [diff] [blame] | 433 | enum State { BEFORE, FLAGS, WIDTH, PRECISION, SPECIFIER, AFTER }; |
| 434 | |
| 435 | int result = -1; |
| 436 | State state = BEFORE; |
| 437 | size_t precision_digits = 0; |
| 438 | size_t i = 0; |
| 439 | while (i < sFormat->length()) { |
Henrique Nakashima | 3a4ebcc | 2017-07-14 14:24:42 -0400 | [diff] [blame] | 440 | wchar_t c = (*sFormat)[i]; |
Tom Sepez | ffbc0d9 | 2017-07-17 09:29:05 -0700 | [diff] [blame] | 441 | switch (state) { |
| 442 | case BEFORE: |
| 443 | if (c == L'%') |
| 444 | state = FLAGS; |
| 445 | break; |
| 446 | case FLAGS: |
| 447 | if (c == L'+' || c == L'-' || c == L'#' || c == L' ') { |
| 448 | // Stay in same state. |
| 449 | } else { |
| 450 | state = WIDTH; |
| 451 | continue; // Re-process same character. |
| 452 | } |
| 453 | break; |
| 454 | case WIDTH: |
| 455 | if (c == L'*') |
| 456 | return -1; |
| 457 | if (std::iswdigit(c)) { |
| 458 | // Stay in same state. |
| 459 | } else if (c == L'.') { |
| 460 | state = PRECISION; |
| 461 | } else { |
| 462 | state = SPECIFIER; |
| 463 | continue; // Re-process same character. |
| 464 | } |
| 465 | break; |
| 466 | case PRECISION: |
| 467 | if (c == L'*') |
| 468 | return -1; |
| 469 | if (std::iswdigit(c)) { |
| 470 | // Stay in same state. |
| 471 | ++precision_digits; |
| 472 | } else { |
| 473 | state = SPECIFIER; |
| 474 | continue; // Re-process same character. |
| 475 | } |
| 476 | break; |
| 477 | case SPECIFIER: |
| 478 | if (c == L'c' || c == L'C' || c == L'd' || c == L'i' || c == L'o' || |
| 479 | c == L'u' || c == L'x' || c == L'X') { |
| 480 | result = UTIL_INT; |
| 481 | } else if (c == L'e' || c == L'E' || c == L'f' || c == L'g' || |
| 482 | c == L'G') { |
| 483 | result = UTIL_DOUBLE; |
| 484 | } else if (c == L's' || c == L'S') { |
| 485 | // Map s to S since we always deal internally with wchar_t strings. |
| 486 | // TODO(tsepez): Probably 100% borked. %S is not a standard |
| 487 | // conversion. |
| 488 | (*sFormat)[i] = L'S'; |
| 489 | result = UTIL_STRING; |
| 490 | } else { |
| 491 | return -1; |
| 492 | } |
| 493 | state = AFTER; |
| 494 | break; |
| 495 | case AFTER: |
| 496 | if (c == L'%') |
| 497 | return -1; |
| 498 | // Stay in same state until string exhausted. |
| 499 | break; |
Henrique Nakashima | 3a4ebcc | 2017-07-14 14:24:42 -0400 | [diff] [blame] | 500 | } |
Tom Sepez | ffbc0d9 | 2017-07-17 09:29:05 -0700 | [diff] [blame] | 501 | ++i; |
Henrique Nakashima | 3a4ebcc | 2017-07-14 14:24:42 -0400 | [diff] [blame] | 502 | } |
Tom Sepez | ffbc0d9 | 2017-07-17 09:29:05 -0700 | [diff] [blame] | 503 | // See https://crbug.com/740166 |
| 504 | if (result == UTIL_INT && precision_digits > 2) |
| 505 | return -1; |
Henrique Nakashima | 3a4ebcc | 2017-07-14 14:24:42 -0400 | [diff] [blame] | 506 | |
Tom Sepez | ffbc0d9 | 2017-07-17 09:29:05 -0700 | [diff] [blame] | 507 | return result; |
Henrique Nakashima | 3a4ebcc | 2017-07-14 14:24:42 -0400 | [diff] [blame] | 508 | } |