blob: 6563a10f970897849eb58f0e31b5a974b15a4893 [file] [log] [blame]
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001// 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[] = {
Nico Weber6c554952014-07-29 10:13:17 -070066 { (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" },
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070069 //"m"
Nico Weber6c554952014-07-29 10:13:17 -070070 { (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" },
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070073 //"d", "%w",
Nico Weber6c554952014-07-29 10:13:17 -070074 { (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" },
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070077 //"H"
Nico Weber6c554952014-07-29 10:13:17 -070078 { (FX_LPCWSTR)L"hh", (FX_LPCWSTR)L"%I" },
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070079 //"h"
Nico Weber6c554952014-07-29 10:13:17 -070080 { (FX_LPCWSTR)L"MM", (FX_LPCWSTR)L"%M" },
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070081 //"M"
Nico Weber6c554952014-07-29 10:13:17 -070082 { (FX_LPCWSTR)L"ss", (FX_LPCWSTR)L"%S" },
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070083 //"s
Nico Weber6c554952014-07-29 10:13:17 -070084 { (FX_LPCWSTR)L"TT", (FX_LPCWSTR)L"%p" },
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070085 //"t"
86#if defined(_WIN32)
Nico Weber6c554952014-07-29 10:13:17 -070087 { (FX_LPCWSTR)L"tt", (FX_LPCWSTR)L"%p" },
88 { (FX_LPCWSTR)L"h", (FX_LPCWSTR)L"%#I" },
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070089#else
Nico Weber6c554952014-07-29 10:13:17 -070090 { (FX_LPCWSTR)L"tt", (FX_LPCWSTR)L"%P" },
91 { (FX_LPCWSTR)L"h", (FX_LPCWSTR)L"%l" },
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070092#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}