Merge to XFA: Remove typdefs for pointer types in fx_system.h.
[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)
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         DestroyGlobalPersisitentVariables();
123
124         CJS_RuntimeFactory* pFactory = CPDFXFA_App::GetInstance()->GetRuntimeFactory();
125         pFactory->ReleaseGlobalData();
126 }
127
128 void global_alternate::Initial(CPDFDoc_Environment* pApp)
129 {
130         m_pApp = pApp;
131
132         CJS_RuntimeFactory* pFactory = CPDFXFA_App::GetInstance()->GetRuntimeFactory();
133         m_pGlobalData = pFactory->NewGlobalData(pApp);
134         UpdateGlobalPersistentVariables();
135 }
136
137 FX_BOOL global_alternate::QueryProperty(const FX_WCHAR* propname)
138 {
139         return CFX_WideString(propname) != L"setPersistent";
140 }
141
142 FX_BOOL global_alternate::DelProperty(IFXJS_Context* cc, const FX_WCHAR* propname, CFX_WideString& sError)
143 {
144         js_global_data* pData = NULL;
145         CFX_ByteString sPropName = CFX_ByteString::FromUnicode(propname);
146
147         if (m_mapGlobal.Lookup(sPropName, (void*&)pData))
148         {
149                 pData->bDeleted = TRUE;
150                 return TRUE;
151         }
152
153         return FALSE;
154 }
155
156 FX_BOOL global_alternate::DoProperty(IFXJS_Context* cc, const FX_WCHAR* propname, CJS_PropValue& vp, CFX_WideString& sError)
157 {
158         if (vp.IsSetting())
159         {
160                 CFX_ByteString sPropName = CFX_ByteString::FromUnicode(propname);
161                 switch (vp.GetType())
162                 {
163                 case VT_number:
164                         {
165                                 double dData;
166                                 vp >> dData;
167                                 return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_NUMBER, dData, false, "", v8::Local<v8::Object>(), FALSE);
168                         }
169                 case VT_boolean:
170                         {
171                                 bool bData;
172                                 vp >> bData;
173                                 return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_BOOLEAN, 0, bData, "", v8::Local<v8::Object>(), FALSE);
174                         }
175                 case VT_string:
176                         {
177                                 CFX_ByteString sData;
178                                 vp >> sData;
179                                 return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_STRING, 0, false, sData, v8::Local<v8::Object>(), FALSE);
180                         }
181                 case VT_object:
182                         {
183                                 JSObject pData;
184                                 vp >> pData;
185                                 return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_OBJECT, 0, false, "", pData, FALSE);
186                         }
187                 case VT_null:
188                         {
189                                 return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_NULL, 0, false, "", v8::Local<v8::Object>(), FALSE);
190                         }
191                 case VT_undefined:
192                         {
193                                 DelProperty(cc, propname, sError);
194                                 return TRUE;
195                         }
196                 default:
197                         return FALSE;
198                 }
199         }
200         else
201         {
202                 js_global_data* pData = NULL;
203                 CFX_ByteString sPropName = CFX_ByteString::FromUnicode(propname);
204
205                 if (m_mapGlobal.Lookup(sPropName, (void*&)pData))
206                 {
207                         if (pData)
208                         {
209                                 if (!pData->bDeleted)
210                                 {
211                                         switch (pData->nType)
212                                         {
213                                         case JS_GLOBALDATA_TYPE_NUMBER:
214                                                 vp << pData->dData;
215                                                 break;
216                                         case JS_GLOBALDATA_TYPE_BOOLEAN:
217                                                 vp << pData->bData;
218                                                 break;
219                                         case JS_GLOBALDATA_TYPE_STRING:
220                                                 vp << pData->sData;
221                                                 break;
222                                         case JS_GLOBALDATA_TYPE_OBJECT:
223                                                 {
224                                                         v8::Local<v8::Object> obj = v8::Local<v8::Object>::New(vp.GetIsolate(),pData->pData);
225                                                         vp << obj;
226                                                         break;
227                                                 }
228                                         case JS_GLOBALDATA_TYPE_NULL:
229                                                 vp.SetNull();
230                                                 break;
231                                         default:
232                                                 return FALSE;
233                                         }
234                                         return TRUE;
235                                 }
236                                 else
237                                 {
238                                         return TRUE;
239                                 }
240                         }
241                         else
242                         {
243                                 vp.SetNull();
244                                 return TRUE;
245                         }
246                 }
247                 else
248                 {
249                         vp.SetNull();
250                         return TRUE;
251                 }
252         }
253
254         return FALSE;
255 }
256
257 FX_BOOL global_alternate::setPersistent(IFXJS_Context* cc, const CJS_Parameters& params, CJS_Value& vRet, CFX_WideString& sError)
258 {
259         CJS_Context* pContext = static_cast<CJS_Context*>(cc);
260         if (params.size() != 2)
261         {
262                 sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
263                 return FALSE;
264         }
265
266         CFX_ByteString sName = params[0].ToCFXByteString();
267
268         js_global_data* pData = NULL;
269         if (m_mapGlobal.Lookup(sName, (void*&)pData))
270         {
271                 if (pData && !pData->bDeleted)
272                 {
273                         pData->bPersistent = params[1].ToBool();
274                         return TRUE;
275                 }
276         }
277
278         sError = JSGetStringFromID(pContext, IDS_STRING_JSNOGLOBAL);
279         return FALSE;
280 }
281
282 void global_alternate::UpdateGlobalPersistentVariables()
283 {
284         ASSERT(m_pGlobalData != NULL);
285
286         for (int i=0,sz=m_pGlobalData->GetSize(); i<sz; i++)
287         {
288                 CJS_GlobalData_Element* pData = m_pGlobalData->GetAt(i);
289                 ASSERT(pData != NULL);
290
291                 switch (pData->data.nType)
292                 {
293                 case JS_GLOBALDATA_TYPE_NUMBER:
294                         this->SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_NUMBER, pData->data.dData, false, "", v8::Local<v8::Object>(), pData->bPersistent == 1);
295                         JS_PutObjectNumber(NULL,(JSFXObject)(*m_pJSObject),
296                                                            pData->data.sKey.UTF8Decode().c_str(), pData->data.dData);
297                         break;
298                 case JS_GLOBALDATA_TYPE_BOOLEAN:
299                         this->SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_BOOLEAN, 0, (bool)(pData->data.bData == 1), "", v8::Local<v8::Object>(), pData->bPersistent == 1);
300                         JS_PutObjectBoolean(NULL,(JSFXObject)(*m_pJSObject),
301                                                                 pData->data.sKey.UTF8Decode().c_str(), (bool)(pData->data.bData == 1));
302                         break;
303                 case JS_GLOBALDATA_TYPE_STRING:
304                         this->SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_STRING, 0, false, pData->data.sData, v8::Local<v8::Object>(), pData->bPersistent == 1);
305                         JS_PutObjectString(NULL, (JSFXObject)(*m_pJSObject),
306                                                            pData->data.sKey.UTF8Decode().c_str(),
307                                                            pData->data.sData.UTF8Decode().c_str());
308                         break;
309                 case JS_GLOBALDATA_TYPE_OBJECT:
310                         {
311                                 IJS_Runtime* pRuntime = JS_GetRuntime((JSFXObject)(*m_pJSObject));
312                                 v8::Local<v8::Object> pObj = JS_NewFxDynamicObj(pRuntime, NULL, -1);
313
314                                 PutObjectProperty(pObj, &pData->data);
315
316                                 this->SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_OBJECT, 0, false, "", 
317                                         (JSObject)pObj, pData->bPersistent == 1);
318                                 JS_PutObjectObject(NULL,(JSFXObject)(*m_pJSObject),
319                                                                    pData->data.sKey.UTF8Decode().c_str(), (JSObject)pObj);
320                         }
321                         break;
322                 case JS_GLOBALDATA_TYPE_NULL:
323                         this->SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_NULL, 0, false, "", v8::Local<v8::Object>(), pData->bPersistent == 1);
324                         JS_PutObjectNull(NULL,(JSFXObject)(*m_pJSObject),
325                                                          pData->data.sKey.UTF8Decode().c_str());
326                         break;
327                 }
328         }
329 }
330
331 void global_alternate::CommitGlobalPersisitentVariables()
332 {
333         ASSERT(m_pGlobalData != NULL);
334
335         FX_POSITION      pos = m_mapGlobal.GetStartPosition();
336         while (pos)
337         {
338                 CFX_ByteString name; 
339                 js_global_data* pData = NULL;
340                 m_mapGlobal.GetNextAssoc(pos, name, (void*&)pData);
341                 
342                 if (pData)
343                 {
344                         if (pData->bDeleted)
345                         {
346                                 m_pGlobalData->DeleteGlobalVariable(name);
347                         }
348                         else
349                         {
350                                 switch (pData->nType)
351                                 {
352                                 case JS_GLOBALDATA_TYPE_NUMBER:
353                                         m_pGlobalData->SetGlobalVariableNumber(name, pData->dData);
354                                         m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
355                                         break;
356                                 case JS_GLOBALDATA_TYPE_BOOLEAN:
357                                         m_pGlobalData->SetGlobalVariableBoolean(name, pData->bData);
358                                         m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
359                                         break;
360                                 case JS_GLOBALDATA_TYPE_STRING:
361                                         m_pGlobalData->SetGlobalVariableString(name, pData->sData);
362                                         m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
363                                         break;
364                                 case JS_GLOBALDATA_TYPE_OBJECT:
365                                         //if (pData->pData)
366                                         {
367                                                 CJS_GlobalVariableArray array;
368                                                 v8::Local<v8::Object> obj = v8::Local<v8::Object>::New(GetJSObject()->GetIsolate(),pData->pData);
369                                                 ObjectToArray(obj, array);
370                                                 m_pGlobalData->SetGlobalVariableObject(name, array);
371                                                 m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
372                                         }
373                                         break;
374                                 case JS_GLOBALDATA_TYPE_NULL:
375                                         m_pGlobalData->SetGlobalVariableNull(name);
376                                         m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
377                                         break;
378                                 }
379                         }
380                 }
381         }
382 }
383
384 void global_alternate::ObjectToArray(v8::Local<v8::Object> pObj, CJS_GlobalVariableArray& array)
385 {
386         v8::Local<v8::Context> context = pObj->CreationContext();
387         v8::Isolate* isolate = context->GetIsolate();
388         v8::Local<v8::Array> pKeyList = JS_GetObjectElementNames(isolate, pObj);
389         int     nObjElements = pKeyList->Length();
390
391         for (int i=0; i<nObjElements; i++)
392         {
393                 
394                 CFX_WideString ws = JS_ToString(isolate, JS_GetArrayElement(isolate, pKeyList, i));
395                 CFX_ByteString sKey = ws.UTF8Encode();
396
397                 v8::Local<v8::Value> v = JS_GetObjectElement(isolate, pObj, ws.c_str());
398                 FXJSVALUETYPE vt = GET_VALUE_TYPE(v);
399                 switch (vt)
400                 {
401                 case VT_number:
402                         {
403                                 CJS_KeyValue* pObjElement = new CJS_KeyValue;
404                                 pObjElement->nType = JS_GLOBALDATA_TYPE_NUMBER;
405                                 pObjElement->sKey = sKey;
406                                 pObjElement->dData = JS_ToNumber(isolate, v);
407                                 array.Add(pObjElement);
408                         }
409                         break;
410                 case VT_boolean:
411                         {
412                                 CJS_KeyValue* pObjElement = new CJS_KeyValue;
413                                 pObjElement->nType = JS_GLOBALDATA_TYPE_BOOLEAN;
414                                 pObjElement->sKey = sKey;
415                                 pObjElement->dData = JS_ToBoolean(isolate, v);
416                                 array.Add(pObjElement);
417                         }
418                         break;
419                 case VT_string:
420                         {
421                                 CFX_ByteString sValue = CJS_Value(isolate, v, VT_string).ToCFXByteString();
422                                 CJS_KeyValue* pObjElement = new CJS_KeyValue;
423                                 pObjElement->nType = JS_GLOBALDATA_TYPE_STRING;
424                                 pObjElement->sKey = sKey;
425                                 pObjElement->sData = sValue;
426                                 array.Add(pObjElement);
427                         }
428                         break;
429                 case VT_object:
430                         {
431                                 CJS_KeyValue* pObjElement = new CJS_KeyValue;
432                                 pObjElement->nType = JS_GLOBALDATA_TYPE_OBJECT;
433                                 pObjElement->sKey = sKey;
434                                 ObjectToArray(JS_ToObject(isolate, v), pObjElement->objData);
435                                 array.Add(pObjElement);
436                         }
437                         break;
438                 case VT_null:
439                         {
440                                 CJS_KeyValue* pObjElement = new CJS_KeyValue;
441                                 pObjElement->nType = JS_GLOBALDATA_TYPE_NULL;
442                                 pObjElement->sKey = sKey;
443                                 array.Add(pObjElement);
444                         }
445                         break;
446                 default:
447                         break;
448                 }
449         }
450 }
451
452 void global_alternate::PutObjectProperty(v8::Local<v8::Object> pObj, CJS_KeyValue* pData)
453 {
454         ASSERT(pData != NULL);
455
456         for (int i=0,sz=pData->objData.Count(); i<sz; i++)
457         {
458                 CJS_KeyValue* pObjData = pData->objData.GetAt(i);
459                 ASSERT(pObjData != NULL);
460
461                 switch (pObjData->nType)
462                 {
463                 case JS_GLOBALDATA_TYPE_NUMBER:
464                         JS_PutObjectNumber(NULL,(JSObject)pObj, pObjData->sKey.UTF8Decode().c_str(), pObjData->dData);
465                         break;
466                 case JS_GLOBALDATA_TYPE_BOOLEAN:
467                         JS_PutObjectBoolean(NULL,(JSObject)pObj, pObjData->sKey.UTF8Decode().c_str(), (bool)(pObjData->bData == 1));
468                         break;
469                 case JS_GLOBALDATA_TYPE_STRING:
470                         JS_PutObjectString(NULL,(JSObject)pObj, pObjData->sKey.UTF8Decode().c_str(), pObjData->sData.UTF8Decode().c_str());
471                         break;
472                 case JS_GLOBALDATA_TYPE_OBJECT:
473                         {
474                                 IJS_Runtime* pRuntime = JS_GetRuntime((JSFXObject)(*m_pJSObject));
475                                 v8::Local<v8::Object> pNewObj = JS_NewFxDynamicObj(pRuntime, NULL, -1);
476                                 PutObjectProperty(pNewObj, pObjData);
477                                 JS_PutObjectObject(NULL, (JSObject)pObj, pObjData->sKey.UTF8Decode().c_str(), (JSObject)pNewObj);
478                         }
479                         break;
480                 case JS_GLOBALDATA_TYPE_NULL:
481                         JS_PutObjectNull(NULL,(JSObject)pObj, pObjData->sKey.UTF8Decode().c_str());
482                         break;
483                 }
484         }
485 }
486
487 void global_alternate::DestroyGlobalPersisitentVariables()
488 {
489         FX_POSITION      pos = m_mapGlobal.GetStartPosition();
490         while (pos)
491         {
492                 CFX_ByteString name; 
493                 js_global_data* pData = NULL;
494                 m_mapGlobal.GetNextAssoc(pos, name, (void*&)pData);
495                 delete pData;
496         }
497
498         m_mapGlobal.RemoveAll();
499 }
500
501
502 FX_BOOL global_alternate::SetGlobalVariables(const FX_CHAR* propname, int nType, 
503                                 double dData, bool bData, const CFX_ByteString& sData, JSObject pData, bool bDefaultPersistent)
504 {
505         if (propname == NULL) return FALSE;
506
507         js_global_data* pTemp = NULL;
508         m_mapGlobal.Lookup(propname, (void*&)pTemp);
509
510         if (pTemp)
511         {
512                 if (pTemp->bDeleted || pTemp->nType != nType)
513                 {
514                         pTemp->dData = 0;
515                         pTemp->bData = 0;
516                         pTemp->sData = "";
517                         pTemp->nType = nType;
518                 }
519
520                 pTemp->bDeleted = FALSE;
521
522                 switch (nType)
523                 {
524                 case JS_GLOBALDATA_TYPE_NUMBER:
525                         {
526                                 pTemp->dData = dData;
527                         }
528                         break;
529                 case JS_GLOBALDATA_TYPE_BOOLEAN:
530                         {
531                                 pTemp->bData = bData;
532                         }
533                         break;
534                 case JS_GLOBALDATA_TYPE_STRING:
535                         {
536                                 pTemp->sData = sData;
537                         }
538                         break;
539                 case JS_GLOBALDATA_TYPE_OBJECT:
540                         {
541                                 pTemp->pData.Reset(JS_GetRuntime(pData), pData);
542                         }
543                         break;
544                 case JS_GLOBALDATA_TYPE_NULL:
545                         break;
546                 default:
547                         return FALSE;
548                 }       
549
550                 return TRUE;
551         }
552
553         js_global_data* pNewData = NULL;
554
555         switch (nType)
556         {
557         case JS_GLOBALDATA_TYPE_NUMBER:
558                 {
559                         pNewData = new js_global_data;
560                         pNewData->nType = JS_GLOBALDATA_TYPE_NUMBER;
561                         pNewData->dData = dData;
562                         pNewData->bPersistent = bDefaultPersistent;
563                 }
564                 break;
565         case JS_GLOBALDATA_TYPE_BOOLEAN:
566                 {
567                         pNewData = new js_global_data;
568                         pNewData->nType = JS_GLOBALDATA_TYPE_BOOLEAN;
569                         pNewData->bData = bData;
570                         pNewData->bPersistent = bDefaultPersistent;
571                 }
572                 break;
573         case JS_GLOBALDATA_TYPE_STRING:
574                 {
575                         pNewData = new js_global_data;
576                         pNewData->nType = JS_GLOBALDATA_TYPE_STRING;
577                         pNewData->sData = sData;
578                         pNewData->bPersistent = bDefaultPersistent;
579                 }
580                 break;
581         case JS_GLOBALDATA_TYPE_OBJECT:
582                 {
583                         pNewData = new js_global_data;
584                         pNewData->nType = JS_GLOBALDATA_TYPE_OBJECT;
585                         pNewData->pData.Reset(JS_GetRuntime(pData), pData);
586                         pNewData->bPersistent = bDefaultPersistent;
587                 }
588                 break;
589         case JS_GLOBALDATA_TYPE_NULL:
590                 {
591                         pNewData = new js_global_data;
592                         pNewData->nType = JS_GLOBALDATA_TYPE_NULL;
593                         pNewData->bPersistent = bDefaultPersistent;
594                 }
595                 break;
596         default:
597                 return FALSE;
598         }       
599
600         m_mapGlobal.SetAt(propname, (void*)pNewData);
601
602         return TRUE;
603 }
604
605 FXJSVALUETYPE GET_VALUE_TYPE(v8::Local<v8::Value> p)
606 {
607   const unsigned int nHash = JS_CalcHash(JS_GetTypeof(p));
608
609   if (nHash == JSCONST_nUndefHash)
610     return VT_undefined;
611   if (nHash == JSCONST_nNullHash)
612     return VT_null;
613   if (nHash == JSCONST_nStringHash)
614     return VT_string;
615   if (nHash == JSCONST_nNumberHash)
616     return VT_number;
617   if (nHash == JSCONST_nBoolHash)
618     return VT_boolean;
619   if (nHash == JSCONST_nDateHash)
620     return VT_date;
621   if (nHash == JSCONST_nObjectHash)
622     return VT_object;
623   if (nHash == JSCONST_nFXobjHash)
624     return VT_fxobject;
625
626   return VT_unknown;
627 }
628