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