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