23d8926bd3b1e8ef547e8a717cb1a0c6293d58a3
[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 #include "../../include/fpdfxfa/fpdfxfa_app.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>\r
23 struct CHash;\r
24 \r
25 // Only needed to hash single-character strings.\r
26 template <wchar_t N>\r
27 struct CHash<N> {\r
28   static const unsigned value = N;\r
29 };\r
30 \r
31 template <unsigned ACC, wchar_t N>\r
32 struct CHash<ACC, N> {\r
33   static const unsigned value = (ACC * 1313LLU + N) & 0xFFFFFFFF;\r
34 };\r
35 \r
36 template <unsigned ACC, wchar_t N, wchar_t... Ns>\r
37 struct CHash<ACC, N, Ns...> {\r
38   static const unsigned value = CHash<CHash<ACC, N>::value, Ns...>::value;\r
39 };\r
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 = FPDFXFA_GetApp()->GetRuntimeFactory();
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 = FPDFXFA_GetApp()->GetRuntimeFactory();
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(OBJ_METHOD_PARAMS)
273 {
274         if (params.size() != 2)
275         {
276                 //sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);  
277                 return FALSE;
278         }
279
280         CFX_ByteString sName = params[0];
281
282         js_global_data* pData = NULL;
283         if (m_mapGlobal.Lookup(sName, (FX_LPVOID&)pData))
284         {
285                 if (pData && !pData->bDeleted)
286                 {
287                         pData->bPersistent = (bool)params[1];
288                         return TRUE;
289                 }
290         }
291
292         //sError = JSGetStringFromID(IDS_JSPARAM_INCORRECT);    
293         return FALSE;
294 }
295
296 void global_alternate::UpdateGlobalPersistentVariables()
297 {
298         ASSERT(m_pGlobalData != NULL);
299
300         for (int i=0,sz=m_pGlobalData->GetSize(); i<sz; i++)
301         {
302                 CJS_GlobalData_Element* pData = m_pGlobalData->GetAt(i);
303                 ASSERT(pData != NULL);
304
305                 switch (pData->data.nType)
306                 {
307                 case JS_GLOBALDATA_TYPE_NUMBER:
308                         this->SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_NUMBER, pData->data.dData, false, "", v8::Handle<v8::Object>(), pData->bPersistent == 1);
309                         JS_PutObjectNumber(NULL,(JSFXObject)(*m_pJSObject),
310                                 pData->data.sKey.UTF8Decode(), pData->data.dData);
311                         break;
312                 case JS_GLOBALDATA_TYPE_BOOLEAN:
313                         this->SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_BOOLEAN, 0, (bool)(pData->data.bData == 1), "", v8::Handle<v8::Object>(), pData->bPersistent == 1);
314                         JS_PutObjectBoolean(NULL,(JSFXObject)(*m_pJSObject),
315                                 pData->data.sKey.UTF8Decode(), (bool)(pData->data.bData == 1));
316                         break;
317                 case JS_GLOBALDATA_TYPE_STRING:
318                         this->SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_STRING, 0, false, pData->data.sData, v8::Handle<v8::Object>(), pData->bPersistent == 1);
319                         JS_PutObjectString(NULL,(JSFXObject)(*m_pJSObject),
320                                 pData->data.sKey.UTF8Decode(), 
321                                 pData->data.sData.UTF8Decode());
322                         break;
323                 case JS_GLOBALDATA_TYPE_OBJECT:
324                         {
325                                 IJS_Runtime* pRuntime = JS_GetRuntime((JSFXObject)(*m_pJSObject));
326                                 v8::Handle<v8::Object> pObj = JS_NewFxDynamicObj(pRuntime, NULL, -1);
327
328                                 PutObjectProperty(pObj, &pData->data);
329
330                                 this->SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_OBJECT, 0, false, "", 
331                                         (JSObject)pObj, pData->bPersistent == 1);
332                                 JS_PutObjectObject(NULL,(JSFXObject)(*m_pJSObject),
333                                         pData->data.sKey.UTF8Decode(), (JSObject)pObj);
334                         }
335                         break;
336                 case JS_GLOBALDATA_TYPE_NULL:
337                         this->SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_NULL, 0, false, "", v8::Handle<v8::Object>(), pData->bPersistent == 1);
338                         JS_PutObjectNull(NULL,(JSFXObject)(*m_pJSObject),
339                                 pData->data.sKey.UTF8Decode());
340                         break;
341                 }
342         }
343 }
344
345 void global_alternate::CommitGlobalPersisitentVariables()
346 {
347         ASSERT(m_pGlobalData != NULL);
348
349         FX_POSITION      pos = m_mapGlobal.GetStartPosition();
350         while (pos)
351         {
352                 CFX_ByteString name; 
353                 js_global_data* pData = NULL;
354                 m_mapGlobal.GetNextAssoc(pos, name, (FX_LPVOID&)pData);
355                 
356                 if (pData)
357                 {
358                         if (pData->bDeleted)
359                         {
360                                 m_pGlobalData->DeleteGlobalVariable(name);
361                         }
362                         else
363                         {
364                                 switch (pData->nType)
365                                 {
366                                 case JS_GLOBALDATA_TYPE_NUMBER:
367                                         m_pGlobalData->SetGlobalVariableNumber(name, pData->dData);
368                                         m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
369                                         break;
370                                 case JS_GLOBALDATA_TYPE_BOOLEAN:
371                                         m_pGlobalData->SetGlobalVariableBoolean(name, pData->bData);
372                                         m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
373                                         break;
374                                 case JS_GLOBALDATA_TYPE_STRING:
375                                         m_pGlobalData->SetGlobalVariableString(name, pData->sData);
376                                         m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
377                                         break;
378                                 case JS_GLOBALDATA_TYPE_OBJECT:
379                                         //if (pData->pData)
380                                         {
381                                                 CJS_GlobalVariableArray array;
382                                                 v8::Handle<v8::Object> obj = v8::Local<v8::Object>::New(GetJSObject()->GetIsolate(),pData->pData);
383                                                 ObjectToArray(obj, array);
384                                                 m_pGlobalData->SetGlobalVariableObject(name, array);
385                                                 m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
386                                         }
387                                         break;
388                                 case JS_GLOBALDATA_TYPE_NULL:
389                                         m_pGlobalData->SetGlobalVariableNull(name);
390                                         m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
391                                         break;
392                                 }
393                         }
394                 }
395         }
396 }
397
398 void global_alternate::ObjectToArray(v8::Handle<v8::Object> pObj, CJS_GlobalVariableArray& array)
399 {
400         v8::Handle<v8::Array> pKeyList = JS_GetObjectElementNames(pObj);
401         int     nObjElements = pKeyList->Length();
402
403         v8::Local<v8::Context> context = pObj->CreationContext();
404         v8::Isolate* isolate = context->GetIsolate();
405
406         for (int i=0; i<nObjElements; i++)
407         {
408                 
409                 CFX_WideString ws = JS_ToString(JS_GetArrayElemnet(pKeyList, i));
410                 CFX_ByteString sKey = ws.UTF8Encode();
411
412                 v8::Handle<v8::Value> v = JS_GetObjectElement(isolate, pObj, ws.c_str());
413                 FXJSVALUETYPE vt = GET_VALUE_TYPE(v);
414                 switch (vt)
415                 {
416                 case VT_number:
417                         {
418                                 CJS_KeyValue* pObjElement = new CJS_KeyValue;
419                                 pObjElement->nType = JS_GLOBALDATA_TYPE_NUMBER;
420                                 pObjElement->sKey = sKey;
421                                 pObjElement->dData = JS_ToNumber(v);
422                                 array.Add(pObjElement);
423                         }
424                         break;
425                 case VT_boolean:
426                         {
427                                 CJS_KeyValue* pObjElement = new CJS_KeyValue;
428                                 pObjElement->nType = JS_GLOBALDATA_TYPE_BOOLEAN;
429                                 pObjElement->sKey = sKey;
430                                 pObjElement->dData = JS_ToBoolean(v);
431                                 array.Add(pObjElement);
432                         }
433                         break;
434                 case VT_string:
435                         {
436                                 CFX_ByteString sValue = CJS_Value(isolate, v, VT_string);
437                                 CJS_KeyValue* pObjElement = new CJS_KeyValue;
438                                 pObjElement->nType = JS_GLOBALDATA_TYPE_STRING;
439                                 pObjElement->sKey = sKey;
440                                 pObjElement->sData = sValue;
441                                 array.Add(pObjElement);
442                         }
443                         break;
444                 case VT_object:
445                         {
446                                 CJS_KeyValue* pObjElement = new CJS_KeyValue;
447                                 pObjElement->nType = JS_GLOBALDATA_TYPE_OBJECT;
448                                 pObjElement->sKey = sKey;
449                                 ObjectToArray(JS_ToObject(v), pObjElement->objData);
450                                 array.Add(pObjElement);
451                         }
452                         break;
453                 case VT_null:
454                         {
455                                 CJS_KeyValue* pObjElement = new CJS_KeyValue;
456                                 pObjElement->nType = JS_GLOBALDATA_TYPE_NULL;
457                                 pObjElement->sKey = sKey;
458                                 array.Add(pObjElement);
459                         }
460                         break;
461                 default:
462                         break;
463                 }
464         }
465 }
466
467 void global_alternate::PutObjectProperty(v8::Handle<v8::Object> pObj, CJS_KeyValue* pData)
468 {
469         ASSERT(pData != NULL);
470
471         for (int i=0,sz=pData->objData.Count(); i<sz; i++)
472         {
473                 CJS_KeyValue* pObjData = pData->objData.GetAt(i);
474                 ASSERT(pObjData != NULL);
475
476                 switch (pObjData->nType)
477                 {
478                 case JS_GLOBALDATA_TYPE_NUMBER:
479                         JS_PutObjectNumber(NULL,(JSObject)pObj, pObjData->sKey.UTF8Decode(), pObjData->dData);
480                         break;
481                 case JS_GLOBALDATA_TYPE_BOOLEAN:
482                         JS_PutObjectBoolean(NULL,(JSObject)pObj, pObjData->sKey.UTF8Decode(), (bool)(pObjData->bData == 1));
483                         break;
484                 case JS_GLOBALDATA_TYPE_STRING:
485                         JS_PutObjectString(NULL,(JSObject)pObj, pObjData->sKey.UTF8Decode(), pObjData->sData.UTF8Decode());
486                         break;
487                 case JS_GLOBALDATA_TYPE_OBJECT:
488                         {
489                                 IJS_Runtime* pRuntime = JS_GetRuntime((JSFXObject)(*m_pJSObject));
490                                 v8::Handle<v8::Object> pNewObj = JS_NewFxDynamicObj(pRuntime, NULL, -1);
491                                 PutObjectProperty(pNewObj, pObjData);
492                                 JS_PutObjectObject(NULL, (JSObject)pObj, pObjData->sKey.UTF8Decode(), (JSObject)pNewObj);
493                         }
494                         break;
495                 case JS_GLOBALDATA_TYPE_NULL:
496                         JS_PutObjectNull(NULL,(JSObject)pObj, pObjData->sKey.UTF8Decode());
497                         break;
498                 }
499         }
500 }
501
502 void global_alternate::DestroyGlobalPersisitentVariables()
503 {
504         FX_POSITION      pos = m_mapGlobal.GetStartPosition();
505         while (pos)
506         {
507                 CFX_ByteString name; 
508                 js_global_data* pData = NULL;
509                 m_mapGlobal.GetNextAssoc(pos, name, (FX_LPVOID&)pData);
510                 delete pData;
511         }
512
513         m_mapGlobal.RemoveAll();
514 }
515
516
517 FX_BOOL global_alternate::SetGlobalVariables(FX_LPCSTR propname, int nType, 
518                                 double dData, bool bData, const CFX_ByteString& sData, JSObject pData, bool bDefaultPersistent)
519 {
520         if (propname == NULL) return FALSE;
521
522         js_global_data* pTemp = NULL;
523         m_mapGlobal.Lookup(propname, (FX_LPVOID&)pTemp);
524
525         if (pTemp)
526         {
527                 if (pTemp->bDeleted || pTemp->nType != nType)
528                 {
529                         pTemp->dData = 0;
530                         pTemp->bData = 0;
531                         pTemp->sData = "";
532                         pTemp->nType = nType;
533                 }
534
535                 pTemp->bDeleted = FALSE;
536
537                 switch (nType)
538                 {
539                 case JS_GLOBALDATA_TYPE_NUMBER:
540                         {
541                                 pTemp->dData = dData;
542                         }
543                         break;
544                 case JS_GLOBALDATA_TYPE_BOOLEAN:
545                         {
546                                 pTemp->bData = bData;
547                         }
548                         break;
549                 case JS_GLOBALDATA_TYPE_STRING:
550                         {
551                                 pTemp->sData = sData;
552                         }
553                         break;
554                 case JS_GLOBALDATA_TYPE_OBJECT:
555                         {
556                                 pTemp->pData.Reset(JS_GetRuntime(pData), pData);
557                         }
558                         break;
559                 case JS_GLOBALDATA_TYPE_NULL:
560                         break;
561                 default:
562                         return FALSE;
563                 }       
564
565                 return TRUE;
566         }
567
568         js_global_data* pNewData = NULL;
569
570         switch (nType)
571         {
572         case JS_GLOBALDATA_TYPE_NUMBER:
573                 {
574                         pNewData = new js_global_data;
575                         pNewData->nType = JS_GLOBALDATA_TYPE_NUMBER;
576                         pNewData->dData = dData;
577                         pNewData->bPersistent = bDefaultPersistent;
578                 }
579                 break;
580         case JS_GLOBALDATA_TYPE_BOOLEAN:
581                 {
582                         pNewData = new js_global_data;
583                         pNewData->nType = JS_GLOBALDATA_TYPE_BOOLEAN;
584                         pNewData->bData = bData;
585                         pNewData->bPersistent = bDefaultPersistent;
586                 }
587                 break;
588         case JS_GLOBALDATA_TYPE_STRING:
589                 {
590                         pNewData = new js_global_data;
591                         pNewData->nType = JS_GLOBALDATA_TYPE_STRING;
592                         pNewData->sData = sData;
593                         pNewData->bPersistent = bDefaultPersistent;
594                 }
595                 break;
596         case JS_GLOBALDATA_TYPE_OBJECT:
597                 {
598                         pNewData = new js_global_data;
599                         pNewData->nType = JS_GLOBALDATA_TYPE_OBJECT;
600                         pNewData->pData.Reset(JS_GetRuntime(pData), pData);
601                         pNewData->bPersistent = bDefaultPersistent;
602                 }
603                 break;
604         case JS_GLOBALDATA_TYPE_NULL:
605                 {
606                         pNewData = new js_global_data;
607                         pNewData->nType = JS_GLOBALDATA_TYPE_NULL;
608                         pNewData->bPersistent = bDefaultPersistent;
609                 }
610                 break;
611         default:
612                 return FALSE;
613         }       
614
615         m_mapGlobal.SetAt(propname, (FX_LPVOID)pNewData);
616
617         return TRUE;
618 }