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