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