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 "../../include/javascript/JavaScript.h"
8#include "../../include/javascript/IJavaScript.h"
9#include "../../include/javascript/JS_Define.h"
10#include "../../include/javascript/JS_Object.h"
11#include "../../include/javascript/JS_Value.h"
12#include "../../include/javascript/util.h"
13#include "../../include/javascript/PublicMethods.h"
14#include "../../include/javascript/resource.h"
15#include "../../include/javascript/JS_Context.h"
16#include "../../include/javascript/JS_EventHandler.h"
17#include "../../include/javascript/JS_Runtime.h"
18
19#if _FX_OS_  == _FX_ANDROID_
20#include <ctype.h>
21#endif
22
23static v8::Isolate* GetIsolate(IFXJS_Context* cc)
24{
25	CJS_Context* pContext = (CJS_Context *)cc;
26	ASSERT(pContext != NULL);
27
28	CJS_Runtime* pRuntime = pContext->GetJSRuntime();
29	ASSERT(pRuntime != NULL);
30
31	return pRuntime->GetIsolate();
32}
33
34BEGIN_JS_STATIC_CONST(CJS_Util)
35END_JS_STATIC_CONST()
36
37BEGIN_JS_STATIC_PROP(CJS_Util)
38END_JS_STATIC_PROP()
39
40BEGIN_JS_STATIC_METHOD(CJS_Util)
41	JS_STATIC_METHOD_ENTRY(printd, 3)
42	JS_STATIC_METHOD_ENTRY(printf, 20)
43	JS_STATIC_METHOD_ENTRY(printx, 2)
44	JS_STATIC_METHOD_ENTRY(scand, 2)
45	JS_STATIC_METHOD_ENTRY(byteToChar, 1)
46END_JS_STATIC_METHOD()
47
48IMPLEMENT_JS_CLASS(CJS_Util,util)
49
50util::util(CJS_Object *pJSObject) : CJS_EmbedObj(pJSObject)
51{
52}
53
54util::~util(void)
55{
56}
57
58
59struct stru_TbConvert
60{
61	FX_LPCWSTR lpszJSMark;
62	FX_LPCWSTR lpszCppMark;
63};
64
65const stru_TbConvert fcTable[] = {
66	(FX_LPCWSTR)L"mmmm", (FX_LPCWSTR)L"%B",
67	(FX_LPCWSTR)L"mmm", (FX_LPCWSTR)L"%b",
68	(FX_LPCWSTR)L"mm",  (FX_LPCWSTR)L"%m",
69	//"m"
70	(FX_LPCWSTR)L"dddd", (FX_LPCWSTR)L"%A",
71	(FX_LPCWSTR)L"ddd", (FX_LPCWSTR)L"%a",
72	(FX_LPCWSTR)L"dd",  (FX_LPCWSTR)L"%d",
73	//"d",   "%w",
74	(FX_LPCWSTR)L"yyyy", (FX_LPCWSTR)L"%Y",
75	(FX_LPCWSTR)L"yy",  (FX_LPCWSTR)L"%y",
76	(FX_LPCWSTR)L"HH",  (FX_LPCWSTR)L"%H",
77	//"H"
78	(FX_LPCWSTR)L"hh",  (FX_LPCWSTR)L"%I",
79	//"h"
80	(FX_LPCWSTR)L"MM",  (FX_LPCWSTR)L"%M",
81	//"M"
82	(FX_LPCWSTR)L"ss",  (FX_LPCWSTR)L"%S",
83	//"s
84	(FX_LPCWSTR)L"TT",  (FX_LPCWSTR)L"%p",
85	//"t"
86#if defined(_WIN32)
87	(FX_LPCWSTR)L"tt",  (FX_LPCWSTR)L"%p",
88	(FX_LPCWSTR)L"h",  (FX_LPCWSTR)L"%#I",
89#else
90	(FX_LPCWSTR)L"tt",  (FX_LPCWSTR)L"%P",
91	(FX_LPCWSTR)L"h",  (FX_LPCWSTR)L"%l",
92#endif
93};
94
95#define UTIL_INT			0
96#define UTIL_DOUBLE			1
97#define UTIL_STRING			2
98
99int util::ParstDataType(std::wstring* sFormat)
100{
101        size_t i = 0;
102	bool bPercent = FALSE;
103	for (i=0; i<sFormat->length(); ++i)
104	{
105		wchar_t c = (*sFormat)[i];
106		if (c == L'%')
107		{
108			bPercent = true;
109			continue;
110		}
111
112		if (bPercent)
113		{
114			if (c == L'c' || c == L'C' || c == L'd' || c == L'i' || c == L'o' || c == L'u' || c == L'x' || c == L'X')
115			{
116				return UTIL_INT;
117			}
118			else if (c == L'e' || c == L'E' || c == L'f' || c == L'g' || c == L'G')
119			{
120				return UTIL_DOUBLE;
121			}
122			else if (c == L's' || c == L'S')
123			{
124				// Map s to S since we always deal internally
125				// with wchar_t strings.
126				(*sFormat)[i] = L'S';
127				return UTIL_STRING;
128			}
129			else if (c == L'.' || c == L'+' || c == L'-' || c == L'#' || c == L' ' || CJS_PublicMethods::IsDigit(c))
130			{
131				continue;
132			}
133			else break;
134		}
135	}
136
137	return -1;
138}
139
140FX_BOOL util::printf(OBJ_METHOD_PARAMS)
141{
142	int iSize = params.size();
143	if (iSize < 1)
144		return FALSE;
145	std::wstring  c_ConvChar((const wchar_t*)(FX_LPCWSTR)params[0].operator CFX_WideString());
146	std::vector<std::wstring> c_strConvers;
147	int iOffset = 0;
148	int iOffend = 0;
149	c_ConvChar.insert(c_ConvChar.begin(),L'S');
150	while(iOffset != -1)
151	{
152		iOffend = c_ConvChar.find(L"%",iOffset+1);
153		std::wstring strSub;
154		if (iOffend == -1)
155			strSub = c_ConvChar.substr(iOffset);
156		else
157			strSub = c_ConvChar.substr(iOffset ,iOffend - iOffset);
158		c_strConvers.push_back(strSub);
159		iOffset = iOffend ;
160	}
161
162	std::wstring c_strResult;
163
164	//for(int iIndex = 1;iIndex < params.size();iIndex++)
165	std::wstring c_strFormat;
166	for(int iIndex = 0;iIndex < (int)c_strConvers.size();iIndex++)
167	{
168		c_strFormat = c_strConvers[iIndex];
169		if (iIndex == 0)
170		{
171			c_strResult = c_strFormat;
172			continue;
173		}
174
175
176		CFX_WideString strSegment;
177		if (iIndex >= iSize) {
178			c_strResult += c_strFormat;
179			continue;
180		}
181
182		switch (ParstDataType(&c_strFormat))
183		{
184			case UTIL_INT:
185				strSegment.Format((FX_LPCWSTR)c_strFormat.c_str(),(int)params[iIndex]);
186				break;
187			case UTIL_DOUBLE:
188				strSegment.Format((FX_LPCWSTR)c_strFormat.c_str(),(double)params[iIndex]);
189				break;
190			case UTIL_STRING:
191				strSegment.Format((FX_LPCWSTR)c_strFormat.c_str(),(FX_LPCWSTR)params[iIndex].operator CFX_WideString());
192				break;
193			default:
194				strSegment.Format((FX_LPCWSTR)L"%S", (FX_LPCWSTR)c_strFormat.c_str());
195				break;
196		}
197		c_strResult += (wchar_t*)strSegment.GetBuffer(strSegment.GetLength()+1);
198	}
199
200	c_strResult.erase(c_strResult.begin());
201	vRet = (FX_LPCWSTR)c_strResult.c_str();
202	return TRUE;
203}
204
205FX_BOOL util::printd(OBJ_METHOD_PARAMS)
206{
207	v8::Isolate* isolate = GetIsolate(cc);
208
209	int iSize = params.size();
210	if (iSize < 2)
211		return FALSE;
212
213	CJS_Value p1(isolate);
214	p1 = params[0];
215
216	CJS_Value p2 = params[1];
217	CJS_Date jsDate(isolate);
218	if (!p2.ConvertToDate(jsDate))
219	{
220		sError = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSPRINT1);
221		return FALSE;
222	}
223
224	if (!jsDate.IsValidDate())
225	{
226		sError = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSPRINT2);
227		return FALSE;
228	}
229
230	if (p1.GetType() == VT_number)
231	{
232		int nFormat = p1;
233
234		CFX_WideString swResult;
235
236		switch (nFormat)
237		{
238		case 0:
239			swResult.Format((FX_LPCWSTR)L"D:%04d%02d%02d%02d%02d%02d",
240				jsDate.GetYear(),
241				jsDate.GetMonth() + 1,
242				jsDate.GetDay(),
243				jsDate.GetHours(),
244				jsDate.GetMinutes(),
245				jsDate.GetSeconds());
246			break;
247		case 1:
248			swResult.Format((FX_LPCWSTR)L"%04d.%02d.%02d %02d:%02d:%02d",
249				jsDate.GetYear(),
250				jsDate.GetMonth() + 1,
251				jsDate.GetDay(),
252				jsDate.GetHours(),
253				jsDate.GetMinutes(),
254				jsDate.GetSeconds());
255			break;
256		case 2:
257			swResult.Format((FX_LPCWSTR)L"%04d/%02d/%02d %02d:%02d:%02d",
258				jsDate.GetYear(),
259				jsDate.GetMonth() + 1,
260				jsDate.GetDay(),
261				jsDate.GetHours(),
262				jsDate.GetMinutes(),
263				jsDate.GetSeconds());
264			break;
265		default:
266			return FALSE;
267		}
268
269		vRet = swResult;
270		return TRUE;
271	}
272	else if (p1.GetType() == VT_string)
273	{
274		std::basic_string<wchar_t> cFormat = (wchar_t*)(FX_LPCWSTR)p1.operator CFX_WideString();
275
276		bool bXFAPicture = false;
277		if (iSize > 2)
278		{
279			//CJS_Value value;
280			bXFAPicture = params[2];
281		}
282
283		if (bXFAPicture)
284		{
285			return FALSE; //currently, it doesn't support XFAPicture.
286		}
287
288        int iIndex;
289		for(iIndex = 0;iIndex<sizeof(fcTable)/sizeof(stru_TbConvert);iIndex++)
290		{
291			int iStart = 0;
292			int iEnd;
293			while((iEnd = cFormat.find((CFX_WideString)fcTable[iIndex].lpszJSMark, iStart)) != -1)
294			{
295				cFormat.replace(iEnd, FXSYS_wcslen(fcTable[iIndex].lpszJSMark), (CFX_WideString)fcTable[iIndex].lpszCppMark);
296				iStart = iEnd;
297			}
298		}
299
300		int iYear,iMonth,iDay,iHour,iMin,iSec;
301		iYear = jsDate.GetYear();
302		iMonth = jsDate.GetMonth();
303		iDay = jsDate.GetDay();
304		iHour = jsDate.GetHours();
305		iMin = jsDate.GetMinutes();
306		iSec = jsDate.GetSeconds();
307
308		struct tm time = {0};
309		time.tm_year = iYear-1900;
310		time.tm_mon = iMonth;
311		time.tm_mday = iDay;
312		time.tm_hour = iHour;
313		time.tm_min = iMin;
314		time.tm_sec = iSec;
315		//COleDateTime cppTm(iYear,iMonth+1,iDay,iHour,iMin,iSec);
316		//CString strFormat = cppTm.Format(cFormat.c_str());
317
318		struct stru_TbConvertAd
319		{
320			FX_LPCWSTR lpszJSMark;
321			int     iValue;
322		};
323
324		stru_TbConvertAd cTableAd[] ={
325			(FX_LPCWSTR)L"m", iMonth+1,
326				(FX_LPCWSTR)L"d", iDay,
327				(FX_LPCWSTR)L"H", iHour,
328				(FX_LPCWSTR)L"h", iHour>12?iHour-12:iHour,
329				(FX_LPCWSTR)L"M", iMin,
330				(FX_LPCWSTR)L"s", iSec
331		};
332
333		//cFormat = strFormat.GetBuffer(strFormat.GetLength()+1);
334		for(iIndex = 0;iIndex<sizeof(cTableAd)/sizeof(stru_TbConvertAd);iIndex++)
335		{
336			wchar_t tszValue[10];
337			//_itot(cTableAd[iIndex].iValue,tszValue,10);
338			CFX_WideString sValue;
339			sValue.Format((FX_LPCWSTR)L"%d",cTableAd[iIndex].iValue);
340			memcpy(tszValue, (wchar_t *)sValue.GetBuffer(sValue.GetLength()+1),
341                               (sValue.GetLength()+1)*sizeof(wchar_t));
342
343			//strFormat.Replace(cTableAd[iIndex].lpszJSMark,"%d");
344			//strFormat.Format(strFormat,cTableAd[iIndex].iValue);
345			int iStart = 0;
346			int iEnd;
347			while((iEnd = cFormat.find((CFX_WideString)cTableAd[iIndex].lpszJSMark,iStart)) != -1)
348			{
349				if (iEnd > 0)
350				{
351					if (cFormat[iEnd-1] == L'%')
352					{
353						iStart = iEnd+1;
354						continue;
355					}
356				}
357				cFormat.replace(iEnd, FXSYS_wcslen(cTableAd[iIndex].lpszJSMark), tszValue);
358				iStart = iEnd;
359			}
360		}
361
362		CFX_WideString strFormat;
363//		strFormat.Format((FX_LPCWSTR)L"%d,%d,%d,%d,%d,%d",iYear, iMonth, iDay, iHour, iMin, iSec);
364//		CString strFormat = cppTm.Format(cFormat.c_str());
365		wchar_t buf[64] = {0};
366		strFormat = wcsftime(buf, 64, cFormat.c_str(), &time);
367		cFormat = buf;
368		vRet = (FX_LPCWSTR)cFormat.c_str();
369		//rtRet = strFormat.GetBuffer(strFormat.GetLength()+1);
370		return TRUE;
371	}
372	return FALSE;
373}
374
375void util::printd(const std::wstring &cFormat2, CJS_Date jsDate, bool bXFAPicture, std::wstring &cPurpose)
376{
377	std::wstring cFormat = cFormat2;
378
379	if (bXFAPicture)
380	{
381		return ; //currently, it doesn't support XFAPicture.
382	}
383
384    int iIndex;
385	for(iIndex = 0;iIndex<sizeof(fcTable)/sizeof(stru_TbConvert);iIndex++)
386	{
387		int iStart = 0;
388		int iEnd;
389		while((iEnd = cFormat.find((CFX_WideString)fcTable[iIndex].lpszJSMark,iStart)) != -1)
390		{
391			cFormat.replace(iEnd,FXSYS_wcslen(fcTable[iIndex].lpszJSMark), (CFX_WideString)fcTable[iIndex].lpszCppMark);
392			iStart = iEnd;
393		}
394	}
395
396	int iYear,iMonth,iDay,iHour,iMin,iSec;
397	iYear = jsDate.GetYear();
398	iMonth = jsDate.GetMonth();
399	iDay = jsDate.GetDay();
400	iHour = jsDate.GetHours();
401	iMin = jsDate.GetMinutes();
402	iSec = jsDate.GetSeconds();
403
404	struct tm time = {0};
405	time.tm_year = iYear-1900;
406	time.tm_mon = iMonth;
407	time.tm_mday = iDay;
408	time.tm_hour = iHour;
409	time.tm_min = iMin;
410	time.tm_sec = iSec;
411//	COleDateTime cppTm(iYear,iMonth+1,iDay,iHour,iMin,iSec);
412	//CString strFormat = cppTm.Format(cFormat.c_str());
413
414	struct stru_TbConvertAd
415	{
416		FX_LPCWSTR lpszJSMark;
417		int     iValue;
418	};
419
420	stru_TbConvertAd cTableAd[] ={
421		(FX_LPCWSTR)L"m", iMonth+1,
422			(FX_LPCWSTR)L"d", iDay,
423			(FX_LPCWSTR)L"H", iHour,
424			(FX_LPCWSTR)L"h", iHour>12?iHour-12:iHour,
425			(FX_LPCWSTR)L"M", iMin,
426			(FX_LPCWSTR)L"s", iSec
427	};
428
429	//cFormat = strFormat.GetBuffer(strFormat.GetLength()+1);
430	for(iIndex = 0;iIndex<sizeof(cTableAd)/sizeof(stru_TbConvertAd);iIndex++)
431	{
432		wchar_t tszValue[10];
433		//_itot(cTableAd[iIndex].iValue,tszValue,10);
434		CFX_WideString sValue;
435		sValue.Format((FX_LPCWSTR)L"%d",cTableAd[iIndex].iValue);
436		memcpy(tszValue, (wchar_t *)sValue.GetBuffer(sValue.GetLength()+1),sValue.GetLength()*sizeof(wchar_t));
437
438
439		//strFormat.Replace(cTableAd[iIndex].lpszJSMark,"%d");
440		//strFormat.Format(strFormat,cTableAd[iIndex].iValue);
441		int iStart = 0;
442		int iEnd;
443		while((iEnd = cFormat.find((CFX_WideString)cTableAd[iIndex].lpszJSMark,iStart)) != -1)
444		{
445			if (iEnd > 0)
446			{
447				if (cFormat[iEnd-1] == L'%')
448				{
449					iStart = iEnd+1;
450					continue;
451				}
452			}
453			cFormat.replace(iEnd,FXSYS_wcslen(cTableAd[iIndex].lpszJSMark),tszValue);
454			iStart = iEnd;
455		}
456	}
457
458		CFX_WideString strFormat;
459//		strFormat.Format((FX_LPCWSTR)L"%d,%d,%d,%d,%d,%d",iYear, iMonth, iDay, iHour, iMin, iSec);
460//		CString strFormat = cppTm.Format(cFormat.c_str());
461		wchar_t buf[64] = {0};
462		strFormat = wcsftime(buf, 64, cFormat.c_str(), &time);
463		cFormat = buf;
464		cPurpose = cFormat;
465}
466
467FX_BOOL util::printx(OBJ_METHOD_PARAMS)
468{
469	int iSize = params.size();
470	if (iSize<2)
471		return FALSE;
472	CFX_WideString sFormat = params[0].operator CFX_WideString();
473	CFX_WideString sSource = params[1].operator CFX_WideString();
474	std::string cFormat = (FX_LPCSTR)CFX_ByteString::FromUnicode(sFormat);
475	std::string cSource = (FX_LPCSTR)CFX_ByteString::FromUnicode(sSource);
476	std::string cDest;
477	printx(cFormat,cSource,cDest);
478	vRet = cDest.c_str();
479	return TRUE;
480}
481
482void util::printx(const std::string &cFormat,const std::string &cSource2,std::string &cPurpose)
483{
484	std::string cSource(cSource2);
485	if (!cPurpose.empty())
486		//cPurpose.clear();
487		cPurpose.erase();
488	int itSource = 0;
489	int iSize = cSource.size();
490	for(int iIndex = 0; iIndex < (int)cFormat.size() && itSource<iSize; iIndex++)
491	{
492		char letter = cFormat[iIndex];
493		switch(letter)
494		{
495		case '?':
496			//cPurpose.push_back(cSource[itSource]);
497			cPurpose += cSource[itSource];
498			itSource++;
499			break;
500		case 'X':
501			{
502				while(itSource < iSize)
503				{
504					if ((cSource[itSource]>='0'&&cSource[itSource]<='9') || (cSource[itSource]>='a' && cSource[itSource]<='z') || (cSource[itSource]>='A' && cSource[itSource]<='Z'))
505					{
506						//cPurpose.push_back(cSource[itSource]);
507						cPurpose += cSource[itSource];
508						itSource++;
509						break;
510					}
511					itSource++;
512				}
513				break;
514			}
515			break;
516		case 'A':
517			{
518				while(itSource < iSize)
519				{
520					if ((cSource[itSource]>='a' && cSource[itSource]<='z') || (cSource[itSource]>='A' && cSource[itSource]<='Z'))
521					{
522						//cPurpose.push_back(cSource[itSource]);
523						cPurpose += cSource[itSource];
524						itSource++;
525						break;
526					}
527					itSource++;
528				}
529				break;
530			}
531			break;
532		case '9':
533			{
534				while(itSource < iSize)
535				{
536					if (cSource[itSource]>='0'&&cSource[itSource]<='9')
537					{
538						//cPurpose.push_back(cSource[itSource]);
539						cPurpose += cSource[itSource];
540						itSource++;
541						break;
542					}
543					itSource++;
544				}
545				break;
546			}
547		case '*':
548			{
549				cPurpose.append(cSource,itSource,iSize-itSource);
550				itSource = iSize-1;
551				break;
552			}
553		case '\\':
554			break;
555		case '>':
556			{
557				for(std::string::iterator it = cSource.begin();it != cSource.end(); it++)
558				{
559					*it = toupper(*it);
560				}
561				break;
562			}
563		case '<':
564			{
565				for(std::string::iterator it = cSource.begin();it != cSource.end(); it++)
566				{
567					*it = tolower(*it);
568				}
569				break;
570			}
571		case '=':
572			break;
573		default:
574			//cPurpose.push_back(letter);
575			cPurpose += letter;
576			break;
577		}
578	}
579}
580
581FX_BOOL util::scand(OBJ_METHOD_PARAMS)
582{
583	v8::Isolate* isolate = GetIsolate(cc);
584	int iSize = params.size();
585	if (iSize < 2)
586		return FALSE;
587	CFX_WideString sFormat = params[0].operator CFX_WideString();
588	CFX_WideString sDate = params[1].operator CFX_WideString();
589
590	double dDate = JS_GetDateTime();
591	if (sDate.GetLength() > 0)
592	{
593		FX_BOOL bWrongFormat = FALSE;
594		dDate = CJS_PublicMethods::MakeRegularDate(sDate,sFormat,bWrongFormat);
595	}
596
597	if (!JS_PortIsNan(dDate))
598	{
599		CJS_Date date(isolate,dDate);
600		vRet = date;
601	}
602	else
603	{
604		vRet.SetNull();
605	}
606
607	return TRUE;
608}
609
610FX_INT64 FX_atoi64(const char *nptr)
611{
612        int c;              /* current char */
613        FX_INT64 total;      /* current total */
614        int sign;           /* if '-', then negative, otherwise positive */
615
616        /* skip whitespace */
617        while ( isspace((int)(unsigned char)*nptr) )
618            ++nptr;
619
620        c = (int)(unsigned char)*nptr++;
621        sign = c;           /* save sign indication */
622        if (c == '-' || c == '+')
623            c = (int)(unsigned char)*nptr++;    /* skip sign */
624
625        total = 0;
626
627        while (isdigit(c)) {
628            total = 10 * total + (c - '0');     /* accumulate digit */
629            c = (int)(unsigned char)*nptr++;    /* get next char */
630        }
631
632        if (sign == '-')
633            return -total;
634        else
635            return total;   /* return result, negated if necessary */
636}
637
638FX_BOOL util::byteToChar(OBJ_METHOD_PARAMS)
639{
640	int iSize = params.size();
641	if (iSize == 0)
642		return FALSE;
643	int nByte = (int)params[0];
644	unsigned char cByte = (unsigned char)nByte;
645	CFX_WideString csValue;
646	csValue.Format((FX_LPCWSTR)L"%c", cByte);
647	vRet = csValue;
648	return TRUE;
649}
650