Revert "Kill operator LPCWSTR from CFX_WideString()."
[pdfium.git] / fpdfsdk / src / javascript / global.cpp
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/IJavaScript.h"
8 #include "../../include/javascript/JS_Context.h"
9 #include "../../include/javascript/JS_Define.h"
10 #include "../../include/javascript/JS_EventHandler.h"
11 #include "../../include/javascript/JS_GlobalData.h"
12 #include "../../include/javascript/JS_Object.h"
13 #include "../../include/javascript/JS_Value.h"
14 #include "../../include/javascript/JavaScript.h"
15 #include "../../include/javascript/global.h"
16 #include "../../include/javascript/resource.h"
17
18 /* ---------------------------- global ---------------------------- */
19
20 // Helper class for compile-time calculation of hash values in order to
21 // avoid having global object initializers.
22 template <unsigned ACC, wchar_t... Ns>
23 struct CHash;
24
25 // Only needed to hash single-character strings.
26 template <wchar_t N>
27 struct CHash<N> {
28   static const unsigned value = N;
29 };
30
31 template <unsigned ACC, wchar_t N>
32 struct CHash<ACC, N> {
33   static const unsigned value = (ACC * 1313LLU + N) & 0xFFFFFFFF;
34 };
35
36 template <unsigned ACC, wchar_t N, wchar_t... Ns>
37 struct CHash<ACC, N, Ns...> {
38   static const unsigned value = CHash<CHash<ACC, N>::value, Ns...>::value;
39 };
40
41 extern const unsigned int JSCONST_nStringHash =
42   CHash<'s','t','r','i','n','g'>::value;
43 extern const unsigned int JSCONST_nNumberHash =
44   CHash<'n','u','m','b','e','r'>::value;
45 extern const unsigned int JSCONST_nBoolHash =
46   CHash<'b','o','o','l','e','a','n'>::value;
47 extern const unsigned int JSCONST_nDateHash =
48   CHash<'d','a','t','e'>::value;
49 extern const unsigned int JSCONST_nObjectHash =
50   CHash<'o','b','j','e','c','t'>::value;
51 extern const unsigned int JSCONST_nFXobjHash =
52   CHash<'f','x','o','b','j'>::value;
53 extern const unsigned int JSCONST_nNullHash =
54   CHash<'n','u','l','l'>::value;
55 extern const unsigned int JSCONST_nUndefHash =
56   CHash<'u','n','d','e','f','i','n','e','d'>::value;
57
58 #ifdef _DEBUG
59 class HashVerify
60 {
61 public:
62   HashVerify();
63 } g_hashVerify;
64
65 HashVerify::HashVerify()
66 {
67   ASSERT(JSCONST_nStringHash ==
68     JS_CalcHash(VALUE_NAME_STRING,wcslen(VALUE_NAME_STRING)));
69   ASSERT(JSCONST_nNumberHash ==
70     JS_CalcHash(VALUE_NAME_NUMBER,wcslen(VALUE_NAME_NUMBER)));
71   ASSERT(JSCONST_nBoolHash ==
72     JS_CalcHash(VALUE_NAME_BOOLEAN,wcslen(VALUE_NAME_BOOLEAN)));
73   ASSERT(JSCONST_nDateHash ==
74     JS_CalcHash(VALUE_NAME_DATE,wcslen(VALUE_NAME_DATE)));
75   ASSERT(JSCONST_nObjectHash ==
76     JS_CalcHash(VALUE_NAME_OBJECT,wcslen(VALUE_NAME_OBJECT)));
77   ASSERT(JSCONST_nFXobjHash ==
78     JS_CalcHash(VALUE_NAME_FXOBJ,wcslen(VALUE_NAME_FXOBJ)));
79   ASSERT(JSCONST_nNullHash ==
80     JS_CalcHash(VALUE_NAME_NULL,wcslen(VALUE_NAME_NULL)));
81   ASSERT(JSCONST_nUndefHash ==
82     JS_CalcHash(VALUE_NAME_UNDEFINED,wcslen(VALUE_NAME_UNDEFINED)));
83 }
84 #endif
85
86
87 BEGIN_JS_STATIC_CONST(CJS_Global)
88 END_JS_STATIC_CONST()
89
90 BEGIN_JS_STATIC_PROP(CJS_Global)
91 END_JS_STATIC_PROP()
92
93 BEGIN_JS_STATIC_METHOD(CJS_Global)
94         JS_STATIC_METHOD_ENTRY(setPersistent)
95 END_JS_STATIC_METHOD()
96
97 IMPLEMENT_SPECIAL_JS_CLASS(CJS_Global, global_alternate, global);
98
99 FX_BOOL CJS_Global::InitInstance(IFXJS_Context* cc)
100 {
101         CJS_Context* pContext = (CJS_Context*)cc;
102         ASSERT(pContext != NULL);
103
104         global_alternate* pGlobal = (global_alternate*)GetEmbedObject();
105         ASSERT(pGlobal != NULL);
106         
107         pGlobal->Initial(pContext->GetReaderApp());
108         
109         return TRUE;
110 };
111
112 global_alternate::global_alternate(CJS_Object* pJSObject)
113         : CJS_EmbedObj(pJSObject),
114         m_pApp(NULL)
115 {
116 }
117
118 global_alternate::~global_alternate(void)
119 {
120         ASSERT(m_pApp != NULL);
121
122 //      CommitGlobalPersisitentVariables();
123         DestroyGlobalPersisitentVariables();
124
125         CJS_RuntimeFactory* pFactory = m_pApp->m_pJSRuntimeFactory;
126         ASSERT(pFactory);
127
128         pFactory->ReleaseGlobalData();
129 }
130   
131 void global_alternate::Initial(CPDFDoc_Environment* pApp)
132 {
133         m_pApp = pApp;
134
135         CJS_RuntimeFactory* pFactory = pApp->m_pJSRuntimeFactory;
136         ASSERT(pFactory);
137         m_pGlobalData = pFactory->NewGlobalData(pApp);
138         UpdateGlobalPersistentVariables();
139 }
140
141 FX_BOOL global_alternate::QueryProperty(FX_LPCWSTR propname)
142 {
143         return CFX_WideString(propname) != L"setPersistent";
144 }
145
146 FX_BOOL global_alternate::DelProperty(IFXJS_Context* cc, FX_LPCWSTR propname, CFX_WideString& sError)
147 {
148         js_global_data* pData = NULL;
149         CFX_ByteString sPropName = CFX_ByteString::FromUnicode(propname);
150
151         if (m_mapGlobal.Lookup(sPropName, (FX_LPVOID&)pData))
152         {
153                 pData->bDeleted = TRUE;
154                 return TRUE;
155         }
156
157         return FALSE;
158 }
159
160 FX_BOOL global_alternate::DoProperty(IFXJS_Context* cc, FX_LPCWSTR propname, CJS_PropValue& vp, CFX_WideString& sError)
161 {
162         if (vp.IsSetting())
163         {
164                 CFX_ByteString sPropName = CFX_ByteString::FromUnicode(propname);
165                 switch (vp.GetType())
166                 {
167                 case VT_number:
168                         {
169                                 double dData;
170                                 vp >> dData;
171                                 return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_NUMBER, dData, false, "", v8::Handle<v8::Object>(), FALSE);
172                         }
173                 case VT_boolean:
174                         {
175                                 bool bData;
176                                 vp >> bData;
177                                 return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_BOOLEAN, 0, bData, "", v8::Handle<v8::Object>(), FALSE);
178                         }
179                 case VT_string:
180                         {
181                                 CFX_ByteString sData;
182                                 vp >> sData;
183                                 return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_STRING, 0, false, sData, v8::Handle<v8::Object>(), FALSE);
184                         }
185                 case VT_object:
186                         {
187                                 JSObject pData;
188                                 vp >> pData;
189                                 return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_OBJECT, 0, false, "", pData, FALSE);
190                         }
191                 case VT_null:
192                         {
193                                 return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_NULL, 0, false, "", v8::Handle<v8::Object>(), FALSE);
194                         }
195                 case VT_undefined:
196                         {
197                                 DelProperty(cc, propname, sError);
198                                 return TRUE;
199                         }
200                 default:
201                         return FALSE;
202                 }
203         }
204         else
205         {
206                 js_global_data* pData = NULL;
207                 CFX_ByteString sPropName = CFX_ByteString::FromUnicode(propname);
208
209                 if (m_mapGlobal.Lookup(sPropName, (FX_LPVOID&)pData))
210                 {
211                         if (pData)
212                         {
213                                 if (!pData->bDeleted)
214                                 {
215                                         switch (pData->nType)
216                                         {
217                                         case JS_GLOBALDATA_TYPE_NUMBER:
218                                                 vp << pData->dData;
219                                                 break;
220                                         case JS_GLOBALDATA_TYPE_BOOLEAN:
221                                                 vp << pData->bData;
222                                                 break;
223                                         case JS_GLOBALDATA_TYPE_STRING:
224                                                 vp << pData->sData;
225                                                 break;
226                                         case JS_GLOBALDATA_TYPE_OBJECT:
227                                                 {
228                                                         v8::Handle<v8::Object> obj = v8::Local<v8::Object>::New(vp.GetIsolate(),pData->pData);
229                                                         vp << obj;
230                                                         break;
231                                                 }
232                                         case JS_GLOBALDATA_TYPE_NULL:
233                                                 vp.SetNull();
234                                                 break;
235                                         default:
236                                                 return FALSE;
237                                         }
238                                         return TRUE;
239                                 }
240                                 else
241                                 {
242                                         return TRUE;
243                                 }
244                         }
245                         else
246                         {
247                                 vp.SetNull();
248                                 return TRUE;
249                         }
250                 }
251                 else
252                 {
253                         vp.SetNull();
254                         return TRUE;
255                 }
256         }
257
258         return FALSE;
259 }
260
261 FX_BOOL global_alternate::setPersistent(IFXJS_Context* cc, const CJS_Parameters& params, CJS_Value& vRet, CFX_WideString& sError)
262 {
263         CJS_Context* pContext = static_cast<CJS_Context*>(cc);
264         if (params.size() != 2)
265         {
266                 sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
267                 return FALSE;
268         }
269
270         CFX_ByteString sName = params[0].ToCFXByteString();
271
272         js_global_data* pData = NULL;
273         if (m_mapGlobal.Lookup(sName, (FX_LPVOID&)pData))
274         {
275                 if (pData && !pData->bDeleted)
276                 {
277                         pData->bPersistent = params[1].ToBool();
278                         return TRUE;
279                 }
280         }
281
282         sError = JSGetStringFromID(pContext, IDS_STRING_JSNOGLOBAL);
283         return FALSE;
284 }
285
286 void global_alternate::UpdateGlobalPersistentVariables()
287 {
288         ASSERT(m_pGlobalData != NULL);
289
290         for (int i=0,sz=m_pGlobalData->GetSize(); i<sz; i++)
291         {
292                 CJS_GlobalData_Element* pData = m_pGlobalData->GetAt(i);
293                 ASSERT(pData != NULL);
294
295                 switch (pData->data.nType)
296                 {
297                 case JS_GLOBALDATA_TYPE_NUMBER:
298                         this->SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_NUMBER, pData->data.dData, false, "", v8::Handle<v8::Object>(), pData->bPersistent == 1);
299                         JS_PutObjectNumber(NULL,(JSFXObject)(*m_pJSObject),
300                                 pData->data.sKey.UTF8Decode(), pData->data.dData);
301                         break;
302                 case JS_GLOBALDATA_TYPE_BOOLEAN:
303                         this->SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_BOOLEAN, 0, (bool)(pData->data.bData == 1), "", v8::Handle<v8::Object>(), pData->bPersistent == 1);
304                         JS_PutObjectBoolean(NULL,(JSFXObject)(*m_pJSObject),
305                                 pData->data.sKey.UTF8Decode(), (bool)(pData->data.bData == 1));
306                         break;
307                 case JS_GLOBALDATA_TYPE_STRING:
308                         this->SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_STRING, 0, false, pData->data.sData, v8::Handle<v8::Object>(), pData->bPersistent == 1);
309                         JS_PutObjectString(NULL,(JSFXObject)(*m_pJSObject),
310                                 pData->data.sKey.UTF8Decode(), 
311                                 pData->data.sData.UTF8Decode());
312                         break;
313                 case JS_GLOBALDATA_TYPE_OBJECT:
314                         {
315                                 IJS_Runtime* pRuntime = JS_GetRuntime((JSFXObject)(*m_pJSObject));
316                                 v8::Handle<v8::Object> pObj = JS_NewFxDynamicObj(pRuntime, NULL, -1);
317
318                                 PutObjectProperty(pObj, &pData->data);
319
320                                 this->SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_OBJECT, 0, false, "", 
321                                         (JSObject)pObj, pData->bPersistent == 1);
322                                 JS_PutObjectObject(NULL,(JSFXObject)(*m_pJSObject),
323                                         pData->data.sKey.UTF8Decode(), (JSObject)pObj);
324                         }
325                         break;
326                 case JS_GLOBALDATA_TYPE_NULL:
327                         this->SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_NULL, 0, false, "", v8::Handle<v8::Object>(), pData->bPersistent == 1);
328                         JS_PutObjectNull(NULL,(JSFXObject)(*m_pJSObject),
329                                 pData->data.sKey.UTF8Decode());
330                         break;
331                 }
332         }
333 }
334
335 void global_alternate::CommitGlobalPersisitentVariables()
336 {
337         ASSERT(m_pGlobalData != NULL);
338
339         FX_POSITION      pos = m_mapGlobal.GetStartPosition();
340         while (pos)
341         {
342                 CFX_ByteString name; 
343                 js_global_data* pData = NULL;
344                 m_mapGlobal.GetNextAssoc(pos, name, (FX_LPVOID&)pData);
345                 
346                 if (pData)
347                 {
348                         if (pData->bDeleted)
349                         {
350                                 m_pGlobalData->DeleteGlobalVariable(name);
351                         }
352                         else
353                         {
354                                 switch (pData->nType)
355                                 {
356                                 case JS_GLOBALDATA_TYPE_NUMBER:
357                                         m_pGlobalData->SetGlobalVariableNumber(name, pData->dData);
358                                         m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
359                                         break;
360                                 case JS_GLOBALDATA_TYPE_BOOLEAN:
361                                         m_pGlobalData->SetGlobalVariableBoolean(name, pData->bData);
362                                         m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
363                                         break;
364                                 case JS_GLOBALDATA_TYPE_STRING:
365                                         m_pGlobalData->SetGlobalVariableString(name, pData->sData);
366                                         m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
367                                         break;
368                                 case JS_GLOBALDATA_TYPE_OBJECT:
369                                         //if (pData->pData)
370                                         {
371                                                 CJS_GlobalVariableArray array;
372                                                 v8::Handle<v8::Object> obj = v8::Local<v8::Object>::New(GetJSObject()->GetIsolate(),pData->pData);
373                                                 ObjectToArray(obj, array);
374                                                 m_pGlobalData->SetGlobalVariableObject(name, array);
375                                                 m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
376                                         }
377                                         break;
378                                 case JS_GLOBALDATA_TYPE_NULL:
379                                         m_pGlobalData->SetGlobalVariableNull(name);
380                                         m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
381                                         break;
382                                 }
383                         }
384                 }
385         }
386 }
387
388 void global_alternate::ObjectToArray(v8::Handle<v8::Object> pObj, CJS_GlobalVariableArray& array)
389 {
390         v8::Handle<v8::Array> pKeyList = JS_GetObjectElementNames(pObj);
391         int     nObjElements = pKeyList->Length();
392
393         v8::Local<v8::Context> context = pObj->CreationContext();
394         v8::Isolate* isolate = context->GetIsolate();
395
396         for (int i=0; i<nObjElements; i++)
397         {
398                 
399                 CFX_WideString ws = JS_ToString(JS_GetArrayElemnet(pKeyList, i));
400                 CFX_ByteString sKey = ws.UTF8Encode();
401
402                 v8::Handle<v8::Value> v = JS_GetObjectElement(isolate, pObj, ws.c_str());
403                 FXJSVALUETYPE vt = GET_VALUE_TYPE(v);
404                 switch (vt)
405                 {
406                 case VT_number:
407                         {
408                                 CJS_KeyValue* pObjElement = new CJS_KeyValue;
409                                 pObjElement->nType = JS_GLOBALDATA_TYPE_NUMBER;
410                                 pObjElement->sKey = sKey;
411                                 pObjElement->dData = JS_ToNumber(v);
412                                 array.Add(pObjElement);
413                         }
414                         break;
415                 case VT_boolean:
416                         {
417                                 CJS_KeyValue* pObjElement = new CJS_KeyValue;
418                                 pObjElement->nType = JS_GLOBALDATA_TYPE_BOOLEAN;
419                                 pObjElement->sKey = sKey;
420                                 pObjElement->dData = JS_ToBoolean(v);
421                                 array.Add(pObjElement);
422                         }
423                         break;
424                 case VT_string:
425                         {
426                                 CFX_ByteString sValue = CJS_Value(isolate, v, VT_string).ToCFXByteString();
427                                 CJS_KeyValue* pObjElement = new CJS_KeyValue;
428                                 pObjElement->nType = JS_GLOBALDATA_TYPE_STRING;
429                                 pObjElement->sKey = sKey;
430                                 pObjElement->sData = sValue;
431                                 array.Add(pObjElement);
432                         }
433                         break;
434                 case VT_object:
435                         {
436                                 CJS_KeyValue* pObjElement = new CJS_KeyValue;
437                                 pObjElement->nType = JS_GLOBALDATA_TYPE_OBJECT;
438                                 pObjElement->sKey = sKey;
439                                 ObjectToArray(JS_ToObject(v), pObjElement->objData);
440                                 array.Add(pObjElement);
441                         }
442                         break;
443                 case VT_null:
444                         {
445                                 CJS_KeyValue* pObjElement = new CJS_KeyValue;
446                                 pObjElement->nType = JS_GLOBALDATA_TYPE_NULL;
447                                 pObjElement->sKey = sKey;
448                                 array.Add(pObjElement);
449                         }
450                         break;
451                 default:
452                         break;
453                 }
454         }
455 }
456
457 void global_alternate::PutObjectProperty(v8::Handle<v8::Object> pObj, CJS_KeyValue* pData)
458 {
459         ASSERT(pData != NULL);
460
461         for (int i=0,sz=pData->objData.Count(); i<sz; i++)
462         {
463                 CJS_KeyValue* pObjData = pData->objData.GetAt(i);
464                 ASSERT(pObjData != NULL);
465
466                 switch (pObjData->nType)
467                 {
468                 case JS_GLOBALDATA_TYPE_NUMBER:
469                         JS_PutObjectNumber(NULL,(JSObject)pObj, pObjData->sKey.UTF8Decode(), pObjData->dData);
470                         break;
471                 case JS_GLOBALDATA_TYPE_BOOLEAN:
472                         JS_PutObjectBoolean(NULL,(JSObject)pObj, pObjData->sKey.UTF8Decode(), (bool)(pObjData->bData == 1));
473                         break;
474                 case JS_GLOBALDATA_TYPE_STRING:
475                         JS_PutObjectString(NULL,(JSObject)pObj, pObjData->sKey.UTF8Decode(), pObjData->sData.UTF8Decode());
476                         break;
477                 case JS_GLOBALDATA_TYPE_OBJECT:
478                         {
479                                 IJS_Runtime* pRuntime = JS_GetRuntime((JSFXObject)(*m_pJSObject));
480                                 v8::Handle<v8::Object> pNewObj = JS_NewFxDynamicObj(pRuntime, NULL, -1);
481                                 PutObjectProperty(pNewObj, pObjData);
482                                 JS_PutObjectObject(NULL, (JSObject)pObj, pObjData->sKey.UTF8Decode(), (JSObject)pNewObj);
483                         }
484                         break;
485                 case JS_GLOBALDATA_TYPE_NULL:
486                         JS_PutObjectNull(NULL,(JSObject)pObj, pObjData->sKey.UTF8Decode());
487                         break;
488                 }
489         }
490 }
491
492 void global_alternate::DestroyGlobalPersisitentVariables()
493 {
494         FX_POSITION      pos = m_mapGlobal.GetStartPosition();
495         while (pos)
496         {
497                 CFX_ByteString name; 
498                 js_global_data* pData = NULL;
499                 m_mapGlobal.GetNextAssoc(pos, name, (FX_LPVOID&)pData);
500                 delete pData;
501         }
502
503         m_mapGlobal.RemoveAll();
504 }
505
506
507 FX_BOOL global_alternate::SetGlobalVariables(FX_LPCSTR propname, int nType, 
508                                 double dData, bool bData, const CFX_ByteString& sData, JSObject pData, bool bDefaultPersistent)
509 {
510         if (propname == NULL) return FALSE;
511
512         js_global_data* pTemp = NULL;
513         m_mapGlobal.Lookup(propname, (FX_LPVOID&)pTemp);
514
515         if (pTemp)
516         {
517                 if (pTemp->bDeleted || pTemp->nType != nType)
518                 {
519                         pTemp->dData = 0;
520                         pTemp->bData = 0;
521                         pTemp->sData = "";
522                         pTemp->nType = nType;
523                 }
524
525                 pTemp->bDeleted = FALSE;
526
527                 switch (nType)
528                 {
529                 case JS_GLOBALDATA_TYPE_NUMBER:
530                         {
531                                 pTemp->dData = dData;
532                         }
533                         break;
534                 case JS_GLOBALDATA_TYPE_BOOLEAN:
535                         {
536                                 pTemp->bData = bData;
537                         }
538                         break;
539                 case JS_GLOBALDATA_TYPE_STRING:
540                         {
541                                 pTemp->sData = sData;
542                         }
543                         break;
544                 case JS_GLOBALDATA_TYPE_OBJECT:
545                         {
546                                 pTemp->pData.Reset(JS_GetRuntime(pData), pData);
547                         }
548                         break;
549                 case JS_GLOBALDATA_TYPE_NULL:
550                         break;
551                 default:
552                         return FALSE;
553                 }       
554
555                 return TRUE;
556         }
557
558         js_global_data* pNewData = NULL;
559
560         switch (nType)
561         {
562         case JS_GLOBALDATA_TYPE_NUMBER:
563                 {
564                         pNewData = new js_global_data;
565                         pNewData->nType = JS_GLOBALDATA_TYPE_NUMBER;
566                         pNewData->dData = dData;
567                         pNewData->bPersistent = bDefaultPersistent;
568                 }
569                 break;
570         case JS_GLOBALDATA_TYPE_BOOLEAN:
571                 {
572                         pNewData = new js_global_data;
573                         pNewData->nType = JS_GLOBALDATA_TYPE_BOOLEAN;
574                         pNewData->bData = bData;
575                         pNewData->bPersistent = bDefaultPersistent;
576                 }
577                 break;
578         case JS_GLOBALDATA_TYPE_STRING:
579                 {
580                         pNewData = new js_global_data;
581                         pNewData->nType = JS_GLOBALDATA_TYPE_STRING;
582                         pNewData->sData = sData;
583                         pNewData->bPersistent = bDefaultPersistent;
584                 }
585                 break;
586         case JS_GLOBALDATA_TYPE_OBJECT:
587                 {
588                         pNewData = new js_global_data;
589                         pNewData->nType = JS_GLOBALDATA_TYPE_OBJECT;
590                         pNewData->pData.Reset(JS_GetRuntime(pData), pData);
591                         pNewData->bPersistent = bDefaultPersistent;
592                 }
593                 break;
594         case JS_GLOBALDATA_TYPE_NULL:
595                 {
596                         pNewData = new js_global_data;
597                         pNewData->nType = JS_GLOBALDATA_TYPE_NULL;
598                         pNewData->bPersistent = bDefaultPersistent;
599                 }
600                 break;
601         default:
602                 return FALSE;
603         }       
604
605         m_mapGlobal.SetAt(propname, (FX_LPVOID)pNewData);
606
607         return TRUE;
608 }
609
610 FXJSVALUETYPE GET_VALUE_TYPE(v8::Handle<v8::Value> p)
611 {
612   const unsigned int nHash = JS_CalcHash(JS_GetTypeof(p));
613
614   if (nHash == JSCONST_nUndefHash)
615     return VT_undefined;
616   if (nHash == JSCONST_nNullHash)
617     return VT_null;
618   if (nHash == JSCONST_nStringHash)
619     return VT_string;
620   if (nHash == JSCONST_nNumberHash)
621     return VT_number;
622   if (nHash == JSCONST_nBoolHash)
623     return VT_boolean;
624   if (nHash == JSCONST_nDateHash)
625     return VT_date;
626   if (nHash == JSCONST_nObjectHash)
627     return VT_object;
628   if (nHash == JSCONST_nFXobjHash)
629     return VT_fxobject;
630
631   return VT_unknown;
632 }
633