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