JsiContext.cpp
上传用户:xqtpzdz
上传日期:2022-05-21
资源大小:1764k
文件大小:55k
源码类别:

xml/soap/webservice

开发平台:

Visual C++

  1. /****************License************************************************
  2.  * Vocalocity OpenVXI
  3.  * Copyright (C) 2004-2005 by Vocalocity, Inc. All Rights Reserved.
  4.  * This program is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU General Public License
  6.  * as published by the Free Software Foundation; either version 2
  7.  * of the License, or (at your option) any later version.
  8.  *  
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  17.  * Vocalocity, the Vocalocity logo, and VocalOS are trademarks or 
  18.  * registered trademarks of Vocalocity, Inc. 
  19.  * OpenVXI is a trademark of Scansoft, Inc. and used under license 
  20.  * by Vocalocity.
  21.  ***********************************************************************/
  22. /*****************************************************************************
  23.  *
  24.  * JsiContext, class for managing JavaScript contexts 
  25.  *
  26.  * The JsiContext class represents a JavaScript context, a script
  27.  * execution state. All JavaScript variables are maintained in a
  28.  * context, and all scripts are executed in reference to a context
  29.  * (for accessing variables and maintaining script side-effects). Each
  30.  * context may have one or more scopes that are used to layer the
  31.  * state information so that it is possible for clients to control the
  32.  * lifetime of state information within the context.
  33.  * SBjsiInterface, definition of the real SBjsi resource object
  34.  *
  35.  ****************************************************************************/
  36. // -----1=0-------2=0-------3=0-------4=0-------5=0-------6=0-------7=0-------8
  37. #include "SBjsiInternal.h"
  38. #include "JsiRuntime.hpp"
  39. #include "JsiContext.hpp"
  40. #include <string.h>
  41. #include <deque>
  42. #include "SBjsiLog.h"
  43. #include "SBjsiString.hpp"
  44. #include "JsiCharCvt.hpp"
  45. #include "dom/JSDOMNode.hpp"
  46. #include "dom/JSDOMDocument.hpp"
  47. #include "dom/JSDOMNodeList.hpp"
  48. #include "dom/JSDOMNamedNodeMap.hpp"
  49. #include "dom/JSDOMCharacterData.hpp"
  50. #include "dom/JSDOMElement.hpp"
  51. #include "dom/JSDOMAttr.hpp"
  52. #include "dom/JSDOMText.hpp"
  53. #include "dom/JSDOMComment.hpp"
  54. #include "dom/JSDOMEntityReference.hpp"
  55. #include "dom/JSDOMProcessingInstruction.hpp"
  56. #include "dom/JSDOMCDATA.hpp"
  57. #include "dom/JSDOMException.hpp"
  58. // SpiderMonkey class that describes our scope objects which we use
  59. // as contexts
  60. static JSClass SCOPE_CLASS = {
  61.     "__SBjsiScope", JSCLASS_HAS_PRIVATE,
  62.     JS_PropertyStub,  JS_PropertyStub, JS_PropertyStub, JsiContext::SCOPE_CLASS_SetProperty,
  63.     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,  
  64.     JsiContext::ScopeFinalize, JSCLASS_NO_OPTIONAL_MEMBERS
  65. };
  66. // SpiderMonkey class that describes our content objects which we use
  67. // to point at VXIContent objects
  68. static JSClass CONTENT_CLASS = {
  69.     "__SBjsiContent", JSCLASS_HAS_PRIVATE,
  70.     JS_PropertyStub,  JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
  71.     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,  
  72.     JsiContext::ContentFinalize, JSCLASS_NO_OPTIONAL_MEMBERS
  73. };
  74. // SpiderMonkey class that describes our objects which we create from
  75. // a VXIMap, just very simple objects
  76. static JSClass MAP_CLASS = {
  77.     "__SBjsiMap", 0,
  78.     JS_PropertyStub,  JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
  79.     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,  
  80.     JS_FinalizeStub, JSCLASS_NO_OPTIONAL_MEMBERS
  81. };
  82. // Names for JS objects we protect from garbage collection, only used
  83. // for SpiderMonkey debugging purposes
  84. static const char GLOBAL_SCOPE_NAME[]  = "__SBjsiGlobalScope";
  85. static const wchar_t GLOBAL_SCOPE_NAME_W[]  = L"__SBjsiGlobalScope";
  86. static const char SCRIPT_OBJECT_NAME[] = "__SBjsiScriptObject";
  87. static const char PROTECTED_JSVAL_NAME[] = "__SBjsiProtectedJsval";
  88. // Global variable we use for temporaries
  89. static const char GLOBAL_TEMP_VAR[] = "__SBjsiTempVar";
  90. static const wchar_t GLOBAL_TEMP_VAR_W[] = L"__SBjsiTempVar";
  91. // -----1=0-------2=0-------3=0-------4=0-------5=0-------6=0-------7=0-------8
  92. #ifndef GET_VXICHAR_FROM_JSCHAR
  93. #define GET_VXICHAR_FROM_JSCHAR(out, in) 
  94.   JscharToVXIchar convert_##out(in); 
  95.   const VXIchar *out = convert_##out.c_str()
  96. #endif
  97. #ifndef GET_JSCHAR_FROM_VXICHAR
  98. #define GET_JSCHAR_FROM_VXICHAR(out, outlen, in) 
  99.   VXIcharToJschar convert_##out(in); 
  100.   const jschar *out = convert_##out.c_str(); 
  101.   size_t outlen = convert_##out.length()
  102. #endif
  103. // -----1=0-------2=0-------3=0-------4=0-------5=0-------6=0-------7=0-------8
  104. // Wrapper class around jsval that automatically protects the held
  105. // jsval from garbage collection
  106. class JsiProtectedJsval {
  107.  public:
  108.   // Constructor and destructor
  109.   JsiProtectedJsval(JSContext *c) : context(c), val(JSVAL_VOID) { }
  110.   ~JsiProtectedJsval() { Clear(); }
  111.   // Clear the value
  112.   VXIjsiResult Clear() { 
  113.     VXIjsiResult rc;
  114.     rc = (((JSVAL_IS_GCTHING(val)) && !JS_RemoveRoot(context, &val)) ?
  115.     VXIjsi_RESULT_FATAL_ERROR : VXIjsi_RESULT_SUCCESS);
  116.     val = JSVAL_VOID;
  117.     return rc;
  118.   }
  119.   
  120.   // Set the value
  121.   VXIjsiResult Set(jsval v) {
  122.     VXIjsiResult rc = Clear();
  123.     val = v;
  124.     if (JSVAL_IS_GCTHING(val) &&
  125.         (!JS_AddNamedRoot(context, &val, PROTECTED_JSVAL_NAME) )){
  126.       rc = VXIjsi_RESULT_OUT_OF_MEMORY; // blown away by GC already!
  127.     }
  128.     return rc;
  129.   }
  130.   // Accessor
  131.   const jsval Get() const { return val; }
  132.  private:
  133.   // Disabled copy constructor and assignment operator
  134.   JsiProtectedJsval(const JsiProtectedJsval &v);
  135.   JsiProtectedJsval &operator=(const JsiProtectedJsval &v);
  136.  private:
  137.   JSContext  *context;
  138.   jsval      val;
  139. };
  140. // -----1=0-------2=0-------3=0-------4=0-------5=0-------6=0-------7=0-------8
  141. // Scope chain class, used to keep the scope chain independantly of
  142. // the actual user visible scope chain to avoid crashes from invalid
  143. // or malicious scripts (push a scope called "session", then overwrite
  144. // that variable with an integer named "session", then try to do more
  145. // work in that scope)
  146. class JsiScopeChainNode {
  147.  public:
  148.   // Constructor and destructor
  149.   JsiScopeChainNode(JSContext *context, JsiScopeChainNode *p, 
  150.          const VXIchar *n) :
  151.     pushAliasFlag(false), name(n), parent(p), child(NULL), jsVal(context) { }
  152.   ~JsiScopeChainNode() { }
  153.   // Creation method
  154.   VXIjsiResult Create(JSObject *scopeObj) { 
  155.     return jsVal.Set(OBJECT_TO_JSVAL(scopeObj)); }
  156.   // Accessors
  157.   const SBjsiString & GetName()   const { return name; }
  158.   jsval                GetJsval()  { return jsVal.Get(); }
  159.   JSObject           * GetJsobj()  { return JSVAL_TO_OBJECT(jsVal.Get()); }
  160.   JsiScopeChainNode  * GetParent() { return parent; }
  161.   JsiScopeChainNode  * GetChild()  { return child; }
  162.   // Set the child scope
  163.   void SetChild(JsiScopeChainNode *c) { child = c; }
  164.   // Release this scope and all under it
  165.   VXIjsiResult Release();
  166.   
  167.   // Alias functions
  168.   VXIjsiResult PushAlias(JsiScopeChainNode *_alias) 
  169.   { 
  170.     VXIjsiResult rc = VXIjsi_RESULT_SUCCESS;
  171.     if (_alias)
  172.       aliasList.push_front(_alias);
  173.     else
  174.       rc = VXIjsi_RESULT_FAILURE;
  175.     return rc;
  176.   } 
  177.   
  178.   JsiScopeChainNode* PopAlias(void) 
  179.   {
  180.     JsiScopeChainNode *a = NULL;
  181.     if (!aliasList.empty())
  182.     {
  183.       a = aliasList.front();
  184.       aliasList.pop_front();  
  185.     }
  186.     return a;
  187.   }
  188.   bool HasAlias(void) { return !aliasList.empty(); }
  189.   const SBjsiString & GetAliasName(void) const
  190.   {
  191.     if (!aliasList.empty())
  192.       return aliasList.front()->GetName();
  193.     return GetName();
  194.   }
  195.   
  196.   void SetAliasScopeFlag(void)   { pushAliasFlag = true; }
  197.   bool IsSetAliasScopeFlag(void) { return pushAliasFlag; }
  198.   void ResetAliasScopeFlag(void) { pushAliasFlag = false; }
  199.   
  200.  private:
  201.   SBjsiString        name;      // Name of this scope
  202.   JsiScopeChainNode  *parent;    // Parent scope
  203.   JsiScopeChainNode  *child;     // Child scope, may be NULL
  204.   JsiProtectedJsval   jsVal;     // JS object for the scope
  205.   // alias list
  206.   std::deque<JsiScopeChainNode*> aliasList;
  207.   bool               pushAliasFlag;
  208. };
  209. VXIjsiResult JsiScopeChainNode::Release()
  210. {
  211.   JsiScopeChainNode *node = this, *next = NULL, *alias = NULL;
  212.   while (node) {
  213.     // if node is an alias, just pop the alias and continue
  214.     if (node->HasAlias())
  215.     {
  216.       alias = node->PopAlias();
  217.       if (alias) alias->jsVal.Clear();
  218.       continue;
  219.     }
  220.     // Release the lock on the underlying object
  221.     node->jsVal.Clear();
  222.     // Clear pointers for safety and advance to child scopes
  223.     next = node->child;
  224.     node->parent = NULL;
  225.     node->child = NULL;
  226.     node = next;
  227.     // NOTE: the deletion of this node and the child nodes is handled
  228.     // by the ScopeFinalize() method that is called when the JS
  229.     // object is garbage collected
  230.   }
  231.   return VXIjsi_RESULT_SUCCESS;
  232. }
  233. // To support VXML 2.0 SPEC, that added the read-only attribute to a namespace.
  234. // Therefore any attempt to modify, create any variable in this namespace will result
  235. // in java script semantic error.  This is the callback that will be called
  236. // every time set property function is called.  It will check for read-only flag
  237. // of the current scope to determine if it is read-only, if so return false.
  238. JSBool JsiContext::SCOPE_CLASS_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  239. {
  240.   uintN attrp;
  241.   JSBool foundp;
  242.   JsiScopeChainNode * prdata = (JsiScopeChainNode *) JS_GetPrivate(cx, obj);
  243.   if (prdata)
  244.   {
  245.     // return true, if pushing alias scope
  246.     if (prdata->IsSetAliasScopeFlag() )
  247.       return JS_TRUE;
  248.     GET_JSCHAR_FROM_VXICHAR(tmpname, tmpnamelen, prdata->GetName().c_str());
  249.     JSObject *pobj = (prdata->GetParent() ? prdata->GetParent()->GetJsobj() : prdata->GetJsobj());
  250.     if (JS_GetUCPropertyAttributes(cx, pobj,
  251.                            tmpname, tmpnamelen,
  252.                            &attrp, &foundp))
  253.     {
  254.       if (foundp && (attrp & JSPROP_READONLY))
  255.       {
  256.         return JS_FALSE;
  257.       }
  258.     }
  259.   }
  260.   return JS_TRUE;
  261. }
  262. VXIjsiResult JsiContext::CheckWriteable(JSContext *cx, JSObject *obj, const VXIchar* varname)
  263. {
  264.   VXIjsiResult rc = VXIjsi_RESULT_SUCCESS;
  265.   uintN attrp;
  266.   JSBool foundp;
  267.   JsiScopeChainNode * prdata = (JsiScopeChainNode *) JS_GetPrivate(cx, obj);
  268.   // evaluate var name to get the root, i.e a.b.c, then the root is a
  269.   // if there is no root i.e, a then we don't need to evaluate
  270.   if (wcschr(varname, L'.'))
  271.   {
  272.     VXIchar* rootvar, *state = NULL;
  273.     VXIchar _varname[1024];
  274.     wcscpy(_varname, varname);
  275. #ifdef WIN32
  276.     rootvar = wcstok(_varname, L".");
  277. #else
  278.     rootvar = wcstok(_varname, L".", &state);
  279. #endif
  280.     if (rootvar) {
  281.       JsiProtectedJsval val(context);
  282.       VXIjsiResult rc = EvaluateScript(rootvar, &val);
  283.       JSObject *classobj = JSVAL_TO_OBJECT(val.Get());
  284.       // if this object is scope class then get the private data,
  285.       // otherwise just ignore it
  286.       if ((rc == VXIjsi_RESULT_SUCCESS) && JS_InstanceOf(cx, classobj, &SCOPE_CLASS, NULL))
  287.         prdata = (JsiScopeChainNode *) JS_GetPrivate(cx, classobj);
  288.       val.Clear();
  289.     }
  290.   }    
  291.   
  292.   if (prdata)
  293.   {
  294.     // get scope from the current parent
  295.     JSObject* pscope = (prdata->GetParent() ? prdata->GetParent()->GetJsobj() : prdata->GetJsobj());
  296.     // retrieve read-only attribute 
  297.     GET_JSCHAR_FROM_VXICHAR(tmpname, tmpnamelen, prdata->GetName().c_str());
  298.     if (JS_GetUCPropertyAttributes(cx, pscope,
  299.                            tmpname, tmpnamelen,
  300.                            &attrp, &foundp))
  301.     {
  302.       if (foundp && (attrp & JSPROP_READONLY))
  303.         return rc = VXIjsi_RESULT_NON_FATAL_ERROR;
  304.     }
  305.   }
  306.   return rc;
  307. }
  308. // -----1=0-------2=0-------3=0-------4=0-------5=0-------6=0-------7=0-------8
  309. // Constructor, only does initialization that cannot fail
  310. JsiContext::JsiContext() : SBjsiLogger(MODULE_SBJSI, NULL, 0),
  311.   version(JSVERSION_DEFAULT), runtime(NULL), context(NULL),
  312.   contextRefs(0), scopeChain(NULL), currentScope(NULL), logEnabled(true),
  313.   maxBranches(0L), numBranches(0L), exception(NULL)
  314. {
  315. }
  316. // Destructor
  317. JsiContext::~JsiContext()
  318. {
  319.   Diag(SBJSI_LOG_CONTEXT, L"JsiContext::~JsiContext", 
  320.   L"start 0x%p, JS context 0x%p", this, context);
  321.     
  322.   ClearException();
  323.   if (context) {
  324.     // Lock the context for access
  325. #ifdef JS_THREADSAFE
  326.     JS_ResumeRequest(context, contextRefs);
  327. #else
  328.     if (!AccessBegin())
  329.       return;
  330. #endif
  331.     // Destroy the scope chain, which automatically unroots the global
  332.     // scope to allow garbage collection of everything
  333.     if (scopeChain)
  334.       scopeChain->Release();
  335.     // Release the lock, must be done before destroying the context
  336. #ifdef JS_THREADSAFE
  337.     JS_EndRequest(context);
  338. #else
  339.     AccessEnd();
  340. #endif
  341.     // Destroy the context, is set to NULL
  342.     runtime->DestroyContext(&context);
  343.   }
  344.   Diag(SBJSI_LOG_CONTEXT, L"JsiContext::~JsiContext", L"end 0x%p", this);
  345. }
  346. // Creation method
  347. VXIjsiResult JsiContext::Create(
  348.     JsiRuntime        *rt, 
  349.     long               contextSize, 
  350.     long               mb,
  351.     VXIlogInterface   *l,
  352.     VXIunsigned        diagTagBase)
  353. {
  354.   ClearException();
  355.   if ((rt == NULL) || (contextSize < 1) || (mb < 1) ||
  356.       (l == NULL))
  357.     return VXIjsi_RESULT_INVALID_ARGUMENT;
  358.   // Copy simple variables
  359.   runtime = rt;
  360.   maxBranches = mb;
  361.   // Base logging class initialization
  362.   SetLog(l, diagTagBase);
  363.   Diag(SBJSI_LOG_CONTEXT, L"JsiContext::Create", L"start 0x%p", this);
  364.   // Create the context
  365.   VXIjsiResult rc = runtime->NewContext(contextSize, &context);
  366.   if (rc != VXIjsi_RESULT_SUCCESS)
  367.     return rc;
  368.   // Lock the context for access
  369. #ifdef JS_THREADSAFE
  370.   JS_BeginRequest(context);
  371. #else
  372.   if (!AccessBegin())
  373.     rc = VXIjsi_RESULT_SYSTEM_ERROR;
  374. #endif
  375.   // Attach this as private data to the context for use in callbacks
  376.   if (rc == VXIjsi_RESULT_SUCCESS)
  377.     JS_SetContextPrivate(context, this);
  378.   // Set the callback to enforce maxBranches
  379.   if (rc == VXIjsi_RESULT_SUCCESS)
  380.     JS_SetBranchCallback(context, JsiContext::BranchCallback);
  381.   
  382.   // Set the callback for reporting errors
  383.   if (rc == VXIjsi_RESULT_SUCCESS)
  384.     JS_SetErrorReporter(context, JsiContext::ErrorReporter);
  385.   // Add JSOPTION_STRICT to enable strictness, which provides
  386.   // additional warnings/errors.
  387.   // 
  388.   // TBD make these flags run-time configurable? Would be helpful for
  389.   // migrating older apps to VoiceXML 2.0 April 2002 (April 2002
  390.   // requires declaring variables prior to use, older VoiceXML does
  391.   // not).
  392. #if defined(JSI_MUST_DECLARE_VARS) || defined(JSI_STRICT)
  393.   if (rc == VXIjsi_RESULT_SUCCESS)
  394.     JS_SetOptions(context, JSOPTION_STRICT | JSOPTION_WERROR);
  395. #endif
  396.   // Create and intialize the global scope we require in the context,
  397.   // the scope chain node object locks it to protect it from the
  398.   // garbage collector
  399.   if (rc == VXIjsi_RESULT_SUCCESS) {
  400.     JSObject *globalScope = JS_NewObject(context, &SCOPE_CLASS, NULL, NULL);
  401.     if (!globalScope)
  402.       rc = VXIjsi_RESULT_OUT_OF_MEMORY;
  403.     else {
  404.       Diag(SBJSI_LOG_SCOPE, L"JsiContext::Create", 
  405.           L"global scope 0x%p, context 0x%p", globalScope, context);
  406.       scopeChain = new JsiScopeChainNode(context, NULL, GLOBAL_SCOPE_NAME_W);
  407.       if (!scopeChain)
  408.         rc = VXIjsi_RESULT_OUT_OF_MEMORY;
  409.   else {
  410.         rc = scopeChain->Create(globalScope);
  411.         if (rc == VXIjsi_RESULT_SUCCESS) {
  412.           if (JS_SetPrivate(context, globalScope, scopeChain))
  413.             currentScope = scopeChain;
  414.           else
  415.             rc = VXIjsi_RESULT_FATAL_ERROR;
  416.         }
  417.       }
  418.     }
  419.   }
  420.   // Initialize the standard JavaScript classes, like Array, Math, String, etc.
  421.   if ((rc == VXIjsi_RESULT_SUCCESS) &&
  422.       !JS_InitStandardClasses(context, currentScope->GetJsobj()))
  423.     rc = VXIjsi_RESULT_OUT_OF_MEMORY;
  424.   // Set version only after there is a valid global scope object
  425.   if ((rc == VXIjsi_RESULT_SUCCESS) &&
  426.       (version != JSVERSION_DEFAULT))
  427.     JS_SetVersion(context, version);
  428.   if (rc == VXIjsi_RESULT_SUCCESS) {
  429.     JSDOMNode::JSInit(context, currentScope->GetJsobj());
  430.     JSDOMDocument::JSInit(context, currentScope->GetJsobj());
  431.     JSDOMNodeList::JSInit(context, currentScope->GetJsobj());
  432.     JSDOMNamedNodeMap::JSInit(context, currentScope->GetJsobj());
  433.     JSDOMCharacterData::JSInit(context, currentScope->GetJsobj());
  434.     JSDOMElement::JSInit(context, currentScope->GetJsobj());
  435.     JSDOMAttr::JSInit(context, currentScope->GetJsobj());
  436.     JSDOMText::JSInit(context, currentScope->GetJsobj());
  437.     JSDOMComment::JSInit(context, currentScope->GetJsobj());
  438.     JSDOMCDATA::JSInit(context, currentScope->GetJsobj());
  439.     JSDOMEntityReference::JSInit(context, currentScope->GetJsobj());
  440.     JSDOMProcessingInstruction::JSInit(context, currentScope->GetJsobj());
  441.     JSDOMException::JSInit(context, currentScope->GetJsobj());
  442.   }
  443.   // On failure, destroy the context here to avoid use of it
  444.   if (rc != VXIjsi_RESULT_SUCCESS) {
  445.     if (context) {
  446. #ifdef JS_THREADSAFE
  447.       JS_EndRequest(context);
  448. #endif
  449.       runtime->DestroyContext(&context);
  450.     }
  451.   }
  452. #ifdef JS_THREADSAFE
  453.   else {
  454.     contextRefs = JS_SuspendRequest(context);
  455.   }
  456. #else
  457.   if (!AccessEnd())
  458.     rc = VXIjsi_RESULT_SYSTEM_ERROR;
  459. #endif
  460.   Diag(SBJSI_LOG_CONTEXT, L"JsiContext::Create", 
  461.       L"end 0x%p, JS context 0x%p", this, context);
  462.   return rc;
  463. }
  464. void JsiContext::ClearException()
  465. {
  466.   if (exception)
  467.     VXIValueDestroy(&exception);
  468. }
  469. // Create a script variable relative to the current scope
  470. VXIjsiResult JsiContext::CreateVar(const VXIchar  *name, 
  471.             const VXIchar  *expr)
  472. {
  473.   ClearException();
  474.   if ((name == NULL) || (name[0] == 0))
  475.     return VXIjsi_RESULT_INVALID_ARGUMENT;
  476.   // If this is a fully qualified name, just do a SetVar() as that
  477.   // handles explicitly scoped variables and this doesn't. No
  478.   // functional effect to doing so, the only difference is that
  479.   // CreateVar() masks vars of the same name from prior scopes when
  480.   // SetVar() just sets the old one, having an explicit scope makes
  481.   // that irrelevant since then JS knows exactly what to do.
  482.   if (wcschr(name, L'.'))
  483.     return SetVar(name, expr);
  484.   if (!AccessBegin())
  485.     return VXIjsi_RESULT_SYSTEM_ERROR;
  486.   // Evaluate the expression, need to eval before setting so we can
  487.   // deal with things like "1; 2;" which can't be handled if we just
  488.   // make a temporary script
  489.   VXIjsiResult rc = VXIjsi_RESULT_SUCCESS;
  490.   JsiProtectedJsval val(context);
  491.   
  492.   // Check if the current scope is writeable
  493.   rc = CheckWriteable(context, currentScope->GetJsobj(), name);
  494.   
  495.   if ((rc == VXIjsi_RESULT_SUCCESS) && (expr != NULL) && (expr[0] != 0))
  496.     rc = EvaluateScript(expr, &val);
  497.   // Set the variable in the current scope directly, ensures we mask
  498.   // any var of the same name from earlier scopes
  499.   if (rc == VXIjsi_RESULT_SUCCESS) {
  500.     if (IsValidVarName(context, currentScope->GetJsobj(), name))
  501.     {
  502.       GET_JSCHAR_FROM_VXICHAR(tmpname, tmpnamelen, name);
  503.       if (!JS_DefineUCProperty(context, currentScope->GetJsobj(), 
  504.         tmpname, tmpnamelen, val.Get(), NULL, NULL,
  505.         JSPROP_ENUMERATE) )
  506.         rc = VXIjsi_RESULT_OUT_OF_MEMORY;
  507.     }
  508.     else
  509.       rc = VXIjsi_RESULT_SYNTAX_ERROR;
  510.   }
  511.   // Must unroot before unlocking
  512.   val.Clear();
  513.   if (!AccessEnd())
  514.     rc = VXIjsi_RESULT_SYSTEM_ERROR;
  515.   return rc;
  516. }
  517. // Create a script variable relative to the current scope
  518. VXIjsiResult JsiContext::CreateVar(const VXIchar  *name, 
  519.             const VXIValue *value)
  520. {
  521.   ClearException();
  522.   if ((name == NULL) || (name[0] == 0))
  523.     return VXIjsi_RESULT_INVALID_ARGUMENT;
  524.   // If this is a fully qualified name, just do a SetVar() as that
  525.   // handles explicitly scoped variables and this doesn't. No
  526.   // functional effect to doing so, the only difference is that
  527.   // CreateVar() masks vars of the same name from prior scopes when
  528.   // SetVar() just sets the old one, having an explicit scope makes
  529.   // that irrelevant since then JS knows exactly what to do.
  530.   if (wcschr(name, L'.'))
  531.     return SetVar(name, value);
  532.   if (!AccessBegin())
  533.     return VXIjsi_RESULT_SYSTEM_ERROR;
  534.   // Convert the value to a JavaScript variable
  535.   VXIjsiResult rc = VXIjsi_RESULT_SUCCESS;
  536.   JsiProtectedJsval val(context);
  537.   // Check if the current scope is writeable
  538.   rc = CheckWriteable(context, currentScope->GetJsobj(), name);
  539.   
  540.   if ((rc == VXIjsi_RESULT_SUCCESS) && value)
  541.     rc = VXIValueToJsval(context, value, &val);
  542.   // Set the variable in the current scope directly, ensures we mask
  543.   // any var of the same name from earlier scopes
  544.   if (rc == VXIjsi_RESULT_SUCCESS) {
  545.     // check if variable name is valid
  546.     if (IsValidVarName(context, currentScope->GetJsobj(), name))
  547.     {
  548.       GET_JSCHAR_FROM_VXICHAR(tmpname, tmpnamelen, name);
  549.       if (!JS_DefineUCProperty(context, currentScope->GetJsobj(), 
  550.             tmpname, tmpnamelen, val.Get(), NULL, NULL,
  551.             JSPROP_ENUMERATE))
  552.         rc = VXIjsi_RESULT_OUT_OF_MEMORY;
  553.     }
  554.     else
  555.       rc = VXIjsi_RESULT_SYNTAX_ERROR;
  556.   }
  557.   // Must unroot before unlocking
  558.   val.Clear();
  559.   if (!AccessEnd())
  560.     rc = VXIjsi_RESULT_SYSTEM_ERROR;
  561.   return rc;
  562. }
  563. // Set a script variable relative to the current scope
  564. VXIjsiResult JsiContext::SetVar(const VXIchar     *name, 
  565.          const VXIchar     *expr)
  566. {
  567.   ClearException();
  568.   if ((name == NULL) || (name[0] == 0) ||
  569.       (expr == NULL) || (expr[0] == 0))
  570.     return VXIjsi_RESULT_INVALID_ARGUMENT;
  571.   if (!AccessBegin())
  572.     return VXIjsi_RESULT_SYSTEM_ERROR;
  573.   JsiProtectedJsval val(context);
  574.   VXIjsiResult rc = VXIjsi_RESULT_SUCCESS;
  575.   // Evaluate the expression, need to eval before setting so we can
  576.   // deal with things like "1; 2;" which can't be handled if we just
  577.   // make a temporary script
  578.   if (rc == VXIjsi_RESULT_SUCCESS)
  579.     rc = EvaluateScript(expr, &val);
  580.   // assign the var
  581.   if (rc == VXIjsi_RESULT_SUCCESS)
  582.     rc = AssignVar(name, val);
  583.   // Must unroot before unlocking
  584.   val.Clear();
  585.   if (!AccessEnd())
  586.     rc = VXIjsi_RESULT_SYSTEM_ERROR;
  587.   return rc;
  588. }
  589. VXIjsiResult JsiContext::CreateVar(
  590.    const VXIchar  *name, 
  591.    DOMDocument    *doc)
  592. {
  593.   ClearException();
  594.   if ((name == NULL) || (name[0] == 0) || (doc == NULL))
  595.     return VXIjsi_RESULT_INVALID_ARGUMENT;
  596.   if (!AccessBegin())
  597.     return VXIjsi_RESULT_SYSTEM_ERROR;
  598.   JSDOMDocument *jsdoc = new JSDOMDocument(doc);
  599.   // Convert the value to a JavaScript variable
  600.   VXIjsiResult rc = VXIjsi_RESULT_SUCCESS;
  601.   JsiProtectedJsval val(context);
  602.   // Check if the current scope is writeable
  603.   rc = CheckWriteable(context, currentScope->GetJsobj(), name);
  604.   if (rc == VXIjsi_RESULT_SUCCESS)
  605.     val.Set(OBJECT_TO_JSVAL(jsdoc->getJSObject(context)));
  606.   // Set the variable in the current scope directly, ensures we mask
  607.   // any var of the same name from earlier scopes
  608.   if (rc == VXIjsi_RESULT_SUCCESS) {
  609.     // check if variable name is valid
  610.     if (IsValidVarName(context, currentScope->GetJsobj(), name))
  611.     {
  612.       GET_JSCHAR_FROM_VXICHAR(tmpname, tmpnamelen, name);
  613.       if (!JS_DefineUCProperty(context, currentScope->GetJsobj(), 
  614.             tmpname, tmpnamelen, val.Get(), NULL, NULL,
  615.             JSPROP_ENUMERATE))
  616.         rc = VXIjsi_RESULT_OUT_OF_MEMORY;
  617.     }
  618.     else
  619.       rc = VXIjsi_RESULT_SYNTAX_ERROR;
  620.   }
  621.   // Must unroot before unlocking
  622.   val.Clear();
  623.   if (!AccessEnd())
  624.     rc = VXIjsi_RESULT_SYSTEM_ERROR;
  625.   return rc;
  626. }
  627. // Set a script variable relative to the current scope
  628. VXIjsiResult JsiContext::SetVar(const VXIchar   *name, 
  629.          const VXIValue  *value)
  630. {
  631.   ClearException();
  632.   if ((name == NULL) || (name[0] == 0) || (value == NULL))
  633.     return VXIjsi_RESULT_INVALID_ARGUMENT;
  634.   if (!AccessBegin())
  635.     return VXIjsi_RESULT_SYSTEM_ERROR;
  636.   // Convert the value to a JavaScript variable
  637.   JsiProtectedJsval val(context);
  638.   VXIjsiResult rc = VXIjsi_RESULT_SUCCESS;
  639.   if (rc == VXIjsi_RESULT_SUCCESS)
  640.     rc = VXIValueToJsval(context, value, &val);
  641.   // assign the var
  642.   if (rc == VXIjsi_RESULT_SUCCESS)
  643.     rc = AssignVar(name, val);
  644.   // Must unroot before unlocking
  645.   val.Clear();
  646.   if (!AccessEnd())
  647.     rc = VXIjsi_RESULT_SYSTEM_ERROR;
  648.   return rc;
  649. }
  650. VXIjsiResult JsiContext::AssignVar(const VXIchar *name, JsiProtectedJsval &val)
  651. {
  652.   VXIjsiResult rc = VXIjsi_RESULT_SUCCESS;
  653.   // make sure the var is writable
  654.   rc = CheckWriteable(context, currentScope->GetJsobj(), name);
  655.   if (rc == VXIjsi_RESULT_SUCCESS) {
  656.     // What we'd like to do is lookup the variable, then set it to the
  657.     // jsval we got above. (The lookup is complex because it could be
  658.     // a partially or fully qualified name, with potential scope
  659.     // chain/prototype chain lookups.) However, that isn't possible in
  660.     // SpiderMonkey. So instead we set a temporary variable in the
  661.     // global scope, then assign the specified object to that, then
  662.     // destroy the temporary.
  663.     if (JS_DefineProperty(context, currentScope->GetJsobj(),
  664.           GLOBAL_TEMP_VAR, val.Get(), NULL, NULL, 0)) {
  665.       // Do the copy using a temporary script
  666.       SBjsiString script(name);
  667.       script += L"=";
  668.       script += GLOBAL_TEMP_VAR_W;
  669.       rc = EvaluateScript(script.c_str(), NULL);
  670.       // Destroy the temporary variable
  671.       jsval ignored = JSVAL_VOID;
  672.       if (!JS_DeleteProperty2(context, currentScope->GetJsobj(), 
  673.          GLOBAL_TEMP_VAR, &ignored))
  674.         rc = VXIjsi_RESULT_FATAL_ERROR;
  675.     } else {
  676.       rc = VXIjsi_RESULT_OUT_OF_MEMORY;
  677.     }
  678.   }
  679.   return rc;
  680. }
  681. // Set the given scope namespace to read-only attribute
  682. VXIjsiResult JsiContext::SetReadOnly(const VXIchar *name) const
  683. {
  684.   const_cast<JsiContext *>(this)->ClearException();
  685.   if ((name == NULL) || (name[0] == 0))
  686.     return VXIjsi_RESULT_INVALID_ARGUMENT;
  687.   if (!AccessBegin())
  688.     return VXIjsi_RESULT_SYSTEM_ERROR;
  689.   
  690.   // setting the attribute of the given object's name
  691.   // to read-only status.  By evaluating the object's name we'll
  692.   // get to the correct scope.
  693.   JSBool foundp; 
  694.   JsiProtectedJsval val(context);
  695.   VXIjsiResult rc = EvaluateScript(name, &val);
  696.   
  697.   // Check if this  variable is an object
  698.   if ((rc == VXIjsi_RESULT_SUCCESS) && JSVAL_IS_OBJECT(val.Get()))
  699.   {
  700.     // Check if it is an instance of SCOPE_CLASS object
  701.     JSObject *robj = JSVAL_TO_OBJECT(val.Get());    
  702.     if (JS_InstanceOf(context, robj, &SCOPE_CLASS, NULL))
  703.     {
  704.       // find the parent node of the current scope because JS_SetUCPropertyAttributes
  705.       // only works from top-down
  706.       JsiScopeChainNode * prdata = (JsiScopeChainNode *) JS_GetPrivate(context, robj);
  707.       if (prdata && prdata->GetParent())
  708.       {
  709.         // Set the property to read-only
  710.         JSObject *pobj = prdata->GetParent()->GetJsobj(); 
  711.         GET_JSCHAR_FROM_VXICHAR(tmpname, tmpnamelen, name);
  712.         if (JS_SetUCPropertyAttributes(context, pobj, tmpname, tmpnamelen, 
  713.             JSPROP_ENUMERATE | JSPROP_READONLY, &foundp))
  714.         {
  715.           if (!foundp)
  716.             rc = VXIjsi_RESULT_FAILURE;         
  717.         } 
  718.         else
  719.           rc = VXIjsi_RESULT_FAILURE;             
  720.       }
  721.     }
  722.   }
  723.     
  724.   // Must unroot before unlocking
  725.   val.Clear();
  726.     
  727.   if (!AccessEnd())
  728.     rc = VXIjsi_RESULT_SYSTEM_ERROR;
  729.   
  730.   return rc;
  731. }
  732. // Get the value of a variable
  733. VXIjsiResult JsiContext::GetVar(const VXIchar     *name,
  734.          VXIValue         **value) const
  735. {
  736.   const_cast<JsiContext *>(this)->ClearException();
  737.   if ((name == NULL) || (name[0] == 0) || (value == NULL))
  738.     return VXIjsi_RESULT_INVALID_ARGUMENT;
  739.   *value = NULL;
  740.   if (!AccessBegin())
  741.     return VXIjsi_RESULT_SYSTEM_ERROR;
  742.   // Get the variable, we need to evaluate instead of just calling
  743.   // JS_GetUCProperty() in order to have it automatically look back
  744.   // through the scope chain, as well as to permit explicit scope
  745.   // references like "myscope.myvar"
  746.   JsiProtectedJsval val(context);
  747.   VXIjsiResult rc = EvaluateScript(name, &val);
  748.   if (rc == VXIjsi_RESULT_SUCCESS) {
  749.     rc = JsvalToVXIValue(context, val.Get(), value);
  750.     if (rc == VXIjsi_RESULT_SYNTAX_ERROR)
  751.       Error(405, L"%s%s", L"Invalid evaluation of javascript scope variable", name);
  752.   }
  753.   else if ((rc == VXIjsi_RESULT_SYNTAX_ERROR) ||
  754.      (rc == VXIjsi_RESULT_SCRIPT_EXCEPTION))
  755.     rc = VXIjsi_RESULT_NON_FATAL_ERROR;
  756.   // Must unroot before unlocking
  757.   val.Clear();
  758.   if (!AccessEnd())
  759.     rc = VXIjsi_RESULT_SYSTEM_ERROR;
  760.   return rc;
  761. }
  762. // Check whether a variable is defined (not void, could be NULL)
  763. VXIjsiResult JsiContext::CheckVar(const VXIchar   *name) const
  764. {
  765.   const_cast<JsiContext *>(this)->ClearException();
  766.   if ((name == NULL) || (name[0] == 0))
  767.     return VXIjsi_RESULT_INVALID_ARGUMENT;
  768.   if (!AccessBegin())
  769.     return VXIjsi_RESULT_SYSTEM_ERROR;
  770.   // Get the variable, we need to evaluate instead of just calling
  771.   // JS_GetUCProperty() in order to have it automatically look back
  772.   // through the scope chain, as well as to permit explicit scope
  773.   // references like "myscope.myvar". We disable logging because
  774.   // we don't want JavaScript error reports about this var being
  775.   // undefined.
  776.   JsiProtectedJsval val(context);
  777.   VXIjsiResult rc = EvaluateScript(name, &val, false);
  778.   if ((rc == VXIjsi_RESULT_SYNTAX_ERROR) ||
  779.       (rc == VXIjsi_RESULT_SCRIPT_EXCEPTION) ||
  780.       (rc == VXIjsi_RESULT_NON_FATAL_ERROR) )
  781.     rc = VXIjsi_RESULT_NON_FATAL_ERROR;
  782.   else if ((rc == VXIjsi_RESULT_SUCCESS) &&
  783.   (JSVAL_IS_VOID(val.Get()))) {   // JavaScript undefined
  784.       rc = VXIjsi_RESULT_FAILURE;
  785.   }
  786.   // Must unroot before unlocking
  787.   val.Clear();
  788.   if (!AccessEnd())
  789.     rc = VXIjsi_RESULT_SYSTEM_ERROR;
  790.   return rc;
  791. }
  792. // Execute a script, optionally returning any execution result
  793. VXIjsiResult JsiContext::Eval(const VXIchar       *expr,
  794.              VXIValue           **result)
  795. {
  796.   if ((expr == NULL) || (expr[0] == 0))
  797.     return VXIjsi_RESULT_INVALID_ARGUMENT;
  798.   if (result)
  799.     *result = NULL;
  800.   // Execute the script
  801.   if (!AccessBegin())
  802.     return VXIjsi_RESULT_SYSTEM_ERROR;
  803.   JsiProtectedJsval val(context);
  804.   VXIjsiResult rc = EvaluateScript(expr, &val);
  805.  
  806.   if (result && (rc == VXIjsi_RESULT_SUCCESS) &&
  807.       (val.Get() != JSVAL_VOID))
  808.     rc = JsvalToVXIValue(context, val.Get(), result);
  809.   // Must unroot before unlocking
  810.   val.Clear();
  811.   if (!AccessEnd())
  812.     rc = VXIjsi_RESULT_SYSTEM_ERROR;
  813.   return rc;
  814. }
  815. // Push a new context onto the scope chain (add a nested scope)
  816. VXIjsiResult JsiContext::PushScope(const VXIchar *name, const VXIjsiScopeAttr attr)
  817. {
  818.   ClearException();
  819.   if (!name || !name[0])
  820.     return VXIjsi_RESULT_INVALID_ARGUMENT;
  821.   if (!AccessBegin())
  822.     return VXIjsi_RESULT_SYSTEM_ERROR;
  823.   // Create an object for the scope, the current scope is its parent
  824.   VXIjsiResult rc = VXIjsi_RESULT_SUCCESS;
  825.   if (attr == VXIjsi_NATIVE_SCOPE){
  826.     JSObject *scope = JS_NewObject(context, &SCOPE_CLASS, NULL, 
  827.             currentScope->GetJsobj());
  828.     if (!scope) {
  829.       rc = VXIjsi_RESULT_OUT_OF_MEMORY;
  830.     } else {
  831.       Diag(SBJSI_LOG_SCOPE, L"JsiContext::PushScope", 
  832.             L"scope %s (0x%p), context 0x%p", name, scope, context);
  833.         
  834.       // The scope chain node object locks it to protect this from
  835.       // garbage collection in case someone (possibly a malicious
  836.       // script) destroys the data member pointing at this in the global
  837.       // scope
  838.       JsiScopeChainNode *newScope = 
  839.         new JsiScopeChainNode(context, currentScope, name);
  840.       if (newScope) {
  841.         rc = newScope->Create(scope);
  842.         if ((rc == VXIjsi_RESULT_SUCCESS) &&
  843.             (!JS_SetPrivate(context, scope, newScope) ))
  844.           rc = VXIjsi_RESULT_FATAL_ERROR;
  845.       } else {
  846.         rc = VXIjsi_RESULT_OUT_OF_MEMORY;
  847.       }
  848.   
  849.       // Set this scope as a property of the parent scope
  850.       if (rc == VXIjsi_RESULT_SUCCESS) {
  851.         GET_JSCHAR_FROM_VXICHAR(tmpname, tmpnamelen, name);
  852.         if (JS_DefineUCProperty(context, currentScope->GetJsobj(), tmpname,
  853.             tmpnamelen, newScope->GetJsval(), NULL, NULL, JSPROP_ENUMERATE) ) {
  854.           // Add it to the scope chain and set it as the current scope
  855.           currentScope->SetChild(newScope);
  856.           currentScope = newScope;
  857.         } else {
  858.           rc = VXIjsi_RESULT_FATAL_ERROR;
  859.         }
  860.       }
  861.     }
  862.   }
  863.   else if (attr == VXIjsi_ALIAS_SCOPE)
  864.   {
  865.     JSObject *aliasScope = JS_NewObject(context, &SCOPE_CLASS, NULL, 
  866.             currentScope->GetJsobj());
  867.     if (!aliasScope) {
  868.       rc = VXIjsi_RESULT_OUT_OF_MEMORY;
  869.     } else {
  870.       Diag(SBJSI_LOG_SCOPE, L"JsiContext::PushScope", 
  871.             L"alias scope %s (0x%p), context 0x%p", name, aliasScope, context);
  872.       // The scope chain node object locks it to protect this from
  873.       // garbage collection in case someone (possibly a malicious
  874.       // script) destroys the data member pointing at this in the global
  875.       // scope
  876.       JsiScopeChainNode *newAliasScope = 
  877.         new JsiScopeChainNode(context, currentScope->GetParent(), name);
  878.       if (newAliasScope) {
  879.         rc = newAliasScope->Create(aliasScope);
  880.         if ((rc == VXIjsi_RESULT_SUCCESS) &&
  881.             !JS_SetPrivate(context, aliasScope, newAliasScope))
  882.           rc = VXIjsi_RESULT_FATAL_ERROR;
  883.       } else {
  884.         rc = VXIjsi_RESULT_OUT_OF_MEMORY;
  885.       }
  886.   
  887.       // Set this scope as a property of the parent scope
  888.       if (rc == VXIjsi_RESULT_SUCCESS) {
  889.         GET_JSCHAR_FROM_VXICHAR(tmpname, tmpnamelen, name);
  890.         if (JS_DefineUCProperty(context, currentScope->GetJsobj(), tmpname,
  891.             tmpnamelen, newAliasScope->GetJsval(), NULL, NULL, JSPROP_ENUMERATE)) {
  892.           // set the alias scope to current scope by evaluating a javascript
  893.           SBjsiString aliasScript(name);
  894.           aliasScript += " = ";
  895.           aliasScript += currentScope->GetName().c_str();
  896.           currentScope->SetAliasScopeFlag();
  897.           rc = EvaluateScript(aliasScript.c_str(), NULL);
  898.           currentScope->ResetAliasScopeFlag();
  899.           // Add it to the scope chain and set it as the current scope
  900.           if (rc == VXIjsi_RESULT_SUCCESS)
  901.             rc = currentScope->PushAlias(newAliasScope);
  902.         } else {
  903.           rc = VXIjsi_RESULT_FATAL_ERROR;
  904.         }
  905.       }
  906.     }
  907.   }
  908.   else
  909.     rc = VXIjsi_RESULT_INVALID_ARGUMENT;
  910.     
  911.   if (!AccessEnd())
  912.     rc = VXIjsi_RESULT_SYSTEM_ERROR;
  913.   return rc;
  914. }
  915. // Pop a context from the scope chain (remove a nested scope)
  916. VXIjsiResult JsiContext::PopScope()
  917. {
  918.   ClearException();
  919.   // Don't pop up past the global scope
  920.   if (currentScope == scopeChain)
  921.     return VXIjsi_RESULT_NON_FATAL_ERROR;
  922.   if (!AccessBegin())
  923.     return VXIjsi_RESULT_SYSTEM_ERROR;
  924.   // make sure we retrieve correct native scope name and alias
  925.   const VXIchar* scopeName = (currentScope->HasAlias() ? 
  926.                               currentScope->GetAliasName().c_str() : currentScope->GetName().c_str());
  927.   
  928.   Diag(SBJSI_LOG_SCOPE, L"JsiContext::PopScope", 
  929.   L"scope %s (0x%p), context 0x%p", 
  930.   scopeName, currentScope->GetJsobj(), context);
  931.   VXIjsiResult rc = VXIjsi_RESULT_SUCCESS;
  932.   
  933.   // if the current scope is an alias, we pop the alias then unlock and return
  934.   if (currentScope->HasAlias())
  935.   {
  936.     JsiScopeChainNode *oldAlias = currentScope->PopAlias();
  937.     // Release the old scope variable within the parent scope to permit
  938.     // it to be garbage collected
  939.     rc = (oldAlias == NULL ? VXIjsi_RESULT_FAILURE : rc);
  940.     if (rc == VXIjsi_RESULT_SUCCESS)
  941.     {
  942.       jsval rval;
  943.       GET_JSCHAR_FROM_VXICHAR(tmpname, tmpnamelen, oldAlias->GetName().c_str());
  944.       if (!JS_DeleteUCProperty2(context, currentScope->GetJsobj(), tmpname,
  945.              tmpnamelen, &rval))
  946.         rc = VXIjsi_RESULT_FATAL_ERROR;
  947.       // Now finish releasing the old scope, the actual wrapper object is
  948.       // freed by the scope finalize method when garbage collection occurs
  949.       rc = oldAlias->Release();
  950.     }
  951.     
  952.     if (!AccessEnd())
  953.       return VXIjsi_RESULT_SYSTEM_ERROR;
  954.     return rc;
  955.   }
  956.   
  957.   // Revert to the parent scope
  958.   JsiScopeChainNode *oldScope = currentScope;
  959.   currentScope = currentScope->GetParent();
  960.   currentScope->SetChild(NULL);
  961.   // Release the old scope variable within the parent scope to permit
  962.   // it to be garbage collected
  963.   jsval rval;
  964.   GET_JSCHAR_FROM_VXICHAR(tmpname, tmpnamelen, oldScope->GetName().c_str());
  965.   if (!JS_DeleteUCProperty2(context, currentScope->GetJsobj(), tmpname,
  966.              tmpnamelen, &rval))
  967.     rc = VXIjsi_RESULT_FATAL_ERROR;
  968.   // Now finish releasing the old scope, the actual wrapper object is
  969.   // freed by the scope finalize method when garbage collection occurs
  970.   rc = oldScope->Release();
  971.   if (!AccessEnd())
  972.     rc = VXIjsi_RESULT_SYSTEM_ERROR;
  973.   return rc;
  974. }
  975. // Reset the scope chain to the global scope (pop all nested scopes)
  976. VXIjsiResult JsiContext::ClearScopes()
  977. {
  978.   ClearException();
  979.   // See if there is anything to do
  980.   if (currentScope == scopeChain)
  981.     return VXIjsi_RESULT_SUCCESS;
  982.   if (!AccessBegin())
  983.     return VXIjsi_RESULT_SYSTEM_ERROR;
  984.   Diag(SBJSI_LOG_SCOPE, L"JsiContext::ClearScopes", L"context 0x%p", context);
  985.   // Revert to the global scope
  986.   JsiScopeChainNode *oldScope = scopeChain->GetChild();
  987.   currentScope = scopeChain;
  988.   currentScope->SetChild(NULL);
  989.   // Release the old child scope variable within the global scope to
  990.   // permit it and all its descendants to be garbage collected
  991.   VXIjsiResult rc = VXIjsi_RESULT_SUCCESS;
  992.   jsval rval;
  993.   GET_JSCHAR_FROM_VXICHAR(tmpname, tmpnamelen, oldScope->GetName().c_str());
  994.   if (!JS_DeleteUCProperty2(context, currentScope->GetJsobj(), tmpname,
  995.              tmpnamelen, &rval))
  996.     rc = VXIjsi_RESULT_FATAL_ERROR;
  997.   
  998.   // Now finish releasing the old scope, the actual wrapper object is
  999.   // freed by the scope finalize method when garbage collection occurs
  1000.   rc = oldScope->Release();
  1001.   if (!AccessEnd())
  1002.     rc = VXIjsi_RESULT_SYSTEM_ERROR;
  1003.   return rc;
  1004. }
  1005. // Script evaluation
  1006. VXIjsiResult JsiContext::EvaluateScript(const VXIchar *script, 
  1007.            JsiProtectedJsval *retval,
  1008.            bool loggingEnabled) const
  1009. {
  1010.   if ((script == NULL) || (script[0] == 0))
  1011.     return VXIjsi_RESULT_INVALID_ARGUMENT;
  1012.   // Reset our private data for evaluation callbacks
  1013.   EvaluatePrepare(loggingEnabled);
  1014.   if (retval)
  1015.     retval->Clear();
  1016.   // Compile the script
  1017.   VXIjsiResult rc = VXIjsi_RESULT_SUCCESS;
  1018.   GET_JSCHAR_FROM_VXICHAR(tmpscript, tmpscriptlen, script);
  1019.   JSScript *jsScript = JS_CompileUCScript(context, currentScope->GetJsobj(), 
  1020.                                            tmpscript, tmpscriptlen, NULL, 1);
  1021.   if (!jsScript)
  1022.     rc = VXIjsi_RESULT_SYNTAX_ERROR;
  1023.   else {
  1024.     // Create a script object and root it to protect the script from
  1025.     // garbage collection, note that once this object exists it owns
  1026.     // the jsScript and thus we must not free it ourselves
  1027.     JSObject *jsScriptObj = JS_NewScriptObject(context, jsScript);
  1028.     if (!jsScriptObj || !JS_AddNamedRoot(context, &jsScriptObj, SCRIPT_OBJECT_NAME)) {
  1029.       JS_DestroyScript(context, jsScript);
  1030.       rc = VXIjsi_RESULT_OUT_OF_MEMORY;
  1031.     } else {
  1032.       // Evaluate the script
  1033.       jsval val = JSVAL_VOID;
  1034.       if (JS_ExecuteScript(context, currentScope->GetJsobj(), jsScript, &val)) {
  1035.         if (retval)
  1036.           rc = retval->Set(val);
  1037.       } else if (exception) {
  1038.         rc = VXIjsi_RESULT_SCRIPT_EXCEPTION;
  1039.       } else if (numBranches > maxBranches) {
  1040.         rc = VXIjsi_RESULT_SECURITY_VIOLATION;
  1041.       } else {
  1042.         rc = VXIjsi_RESULT_NON_FATAL_ERROR;
  1043.       }
  1044.       
  1045.       // Release the script object
  1046.       if (!JS_RemoveRoot(context, &jsScriptObj))
  1047.         rc = VXIjsi_RESULT_FATAL_ERROR;
  1048.     }
  1049.   }
  1050.   
  1051.   return rc;
  1052. }
  1053. #include <iostream>
  1054. // Convert JS values to VXIValue types
  1055. VXIjsiResult JsiContext::JsvalToVXIValue (JSContext *context,
  1056.             const jsval val,
  1057.             VXIValue **value)
  1058. {
  1059.   if (value == NULL)
  1060.     return VXIjsi_RESULT_INVALID_ARGUMENT;
  1061.   
  1062.   *value = NULL;
  1063.   VXIjsiResult rc = VXIjsi_RESULT_SUCCESS;
  1064.   if (JSVAL_IS_STRING(val)) {
  1065.     GET_VXICHAR_FROM_JSCHAR(tmpval, JS_GetStringChars(JSVAL_TO_STRING(val)));
  1066.     *value = (VXIValue *) VXIStringCreate(tmpval);
  1067.   
  1068.   } else if (JSVAL_IS_INT(val))
  1069.     *value = (VXIValue *) VXIIntegerCreate(JSVAL_TO_INT (val));
  1070.   
  1071.   else if (JSVAL_IS_DOUBLE(val))
  1072.   // older version does not support double, unsigned long, etc.
  1073. #if (VXI_CURRENT_VERSION < 0x00030000)
  1074.     *value = (VXIValue *) VXIFloatCreate((double) *JSVAL_TO_DOUBLE(val));
  1075. #else    
  1076.     *value = (VXIValue *) VXIDoubleCreate((double) *JSVAL_TO_DOUBLE(val));
  1077. #endif
  1078.   
  1079.   else if (JSVAL_IS_BOOLEAN(val))
  1080.     *value = (VXIValue *) 
  1081.       VXIBooleanCreate((JSVAL_TO_BOOLEAN(val) ? TRUE : FALSE));
  1082.   
  1083.   else if (JSVAL_IS_NULL(val))  // JavaScript null
  1084.     rc = VXIjsi_RESULT_FAILURE;
  1085.   else if (JSVAL_IS_OBJECT(val)) {
  1086.     JSObject *obj = JSVAL_TO_OBJECT(val);
  1087.     if (JS_InstanceOf(context, obj, &SCOPE_CLASS, NULL))
  1088.     {
  1089.       // Not allowed to convert scope variable to VXIvalue
  1090.       rc = VXIjsi_RESULT_SYNTAX_ERROR;   
  1091.     }
  1092.     else if (JS_IsArrayObject(context, obj)) {
  1093.       // Array, create a VXIVector
  1094.       jsuint elements = 0;
  1095.       VXIVector *vec = NULL;
  1096.       if (!JS_GetArrayLength(context, obj, &elements)) {
  1097.         rc = VXIjsi_RESULT_FATAL_ERROR;
  1098.       } 
  1099.       else if ((vec = VXIVectorCreate()) == NULL) {
  1100.         rc = VXIjsi_RESULT_OUT_OF_MEMORY;
  1101.       } 
  1102.       else {
  1103.         // Traverse through the elements in the vector (could be empty,
  1104.         // in which case we want to return an empty VXIVector)
  1105.         for (jsuint i = 0; 
  1106.             ((rc == VXIjsi_RESULT_SUCCESS) && (i < elements)); i++) {
  1107.           // Convert the element to a VXIValue, then insert
  1108.           jsval elVal = JSVAL_VOID;
  1109.           if (JS_GetElement(context, obj, i, &elVal)) {
  1110.             VXIValue *elValue;
  1111.             rc = JsvalToVXIValue(context, elVal, &elValue);
  1112.             if ((rc == VXIjsi_RESULT_SUCCESS) &&
  1113.                 (VXIVectorAddElement(vec, elValue) != 
  1114.                   VXIvalue_RESULT_SUCCESS)) {
  1115.               rc = VXIjsi_RESULT_OUT_OF_MEMORY;
  1116.               VXIValueDestroy(&elValue);
  1117.             }
  1118.           } else {
  1119.             rc = VXIjsi_RESULT_FATAL_ERROR;
  1120.           }
  1121.         }
  1122.         if (rc == VXIjsi_RESULT_SUCCESS)
  1123.           *value = (VXIValue *) vec;
  1124.         else
  1125.           VXIVectorDestroy(&vec);
  1126.       }
  1127.     } 
  1128.     else if (JS_InstanceOf(context, obj, &CONTENT_CLASS, NULL)) {
  1129.       // Content object, retrieve the VXIContent
  1130.       *value = (VXIValue *) JS_GetPrivate(context, obj);
  1131.       if (*value == NULL)
  1132.         rc = VXIjsi_RESULT_FATAL_ERROR;
  1133.       else 
  1134.         *value = VXIValueClone(*value);
  1135.     } else {
  1136.       // Regular object, create a VXIMap
  1137.       JSIdArray *props = JS_Enumerate(context, obj);
  1138.       VXIMap *vmap = NULL;
  1139.       if (!props) {
  1140.         rc = VXIjsi_RESULT_FATAL_ERROR;
  1141.       } else if ((vmap = VXIMapCreate()) == NULL) {
  1142.         rc = VXIjsi_RESULT_OUT_OF_MEMORY;
  1143.       } else {
  1144.         // Traverse through the properties in the object (could be empty,
  1145.         // in which case we want to return an empty VXIMap)
  1146.         jsint i = 0;
  1147.         for (i = 0;
  1148.             ((rc == VXIjsi_RESULT_SUCCESS) && (i < props->length)); i++) {
  1149.           // Get the property name, looks funky but this was
  1150.           // recommended by one of the SpiderMonkey contributors in a
  1151.           // newsgroup thread
  1152.           jsval prName = JSVAL_VOID, prVal = JSVAL_VOID;
  1153.           if (JS_IdToValue(context, props->vector[i], &prName)) {
  1154.             const jschar *name = NULL;
  1155.             size_t namelen = 0;
  1156.             if (JSVAL_IS_STRING(prName)) {
  1157.               name = JS_GetStringChars(JSVAL_TO_STRING(prName));
  1158.               namelen = JS_GetStringLength(JSVAL_TO_STRING(prName));
  1159.             } else if (JSVAL_IS_INT(prName)) {
  1160.               JSString *str = JS_ValueToString(context, prName);
  1161.               name = JS_GetStringChars(str);
  1162.               namelen = JS_GetStringLength(str);
  1163.             }
  1164.       
  1165.             // Lookup the property, convert to a value, then add to the map
  1166.             if (name &&
  1167.                 JS_GetUCProperty(context, obj, name, namelen, &prVal)) {
  1168.               VXIValue *prValue = NULL;
  1169.               GET_VXICHAR_FROM_JSCHAR(tmpname, name);
  1170.               rc = JsvalToVXIValue(context, prVal, &prValue);
  1171.               if ((rc == VXIjsi_RESULT_SUCCESS) &&
  1172.                   (VXIMapSetProperty(vmap, tmpname, prValue) 
  1173.                                 != VXIvalue_RESULT_SUCCESS)) {
  1174.                 rc = VXIjsi_RESULT_OUT_OF_MEMORY;
  1175.                 VXIValueDestroy(&prValue);
  1176.               }
  1177.               if (rc == VXIjsi_RESULT_NON_FATAL_ERROR)
  1178.                 rc = VXIjsi_RESULT_SUCCESS;
  1179.             } else {
  1180.               rc = VXIjsi_RESULT_FATAL_ERROR;
  1181.             }
  1182.           } else {
  1183.             rc = VXIjsi_RESULT_FATAL_ERROR;
  1184.           }
  1185.         }
  1186.         if (rc == VXIjsi_RESULT_SUCCESS)
  1187.           *value = (VXIValue *) vmap;
  1188.         else
  1189.           VXIMapDestroy(&vmap);
  1190.       }
  1191.       // Free the ID array
  1192.       if (props)
  1193.         JS_DestroyIdArray(context, props);
  1194.     }
  1195.   }
  1196.   else                             // JavaScript undefined (VOID)
  1197.     rc = VXIjsi_RESULT_NON_FATAL_ERROR;
  1198.   // Check for out of memory during VXIValue type create
  1199.   if ((rc == VXIjsi_RESULT_SUCCESS) && (*value == NULL))
  1200.     rc = VXIjsi_RESULT_OUT_OF_MEMORY;
  1201.   return rc;
  1202. }
  1203. // Convert VXIValue types to JS values
  1204. VXIjsiResult JsiContext::VXIValueToJsval(JSContext *context,
  1205.             const VXIValue *value,
  1206.             JsiProtectedJsval *val)
  1207. {
  1208.   VXIjsiResult rc = VXIjsi_RESULT_SUCCESS;
  1209.   if ((value == NULL) || (val == NULL))
  1210.     return VXIjsi_RESULT_INVALID_ARGUMENT;
  1211.   switch (VXIValueGetType(value)) {
  1212.   case VALUE_BOOLEAN: {
  1213.     VXIbool i = VXIBooleanValue((const VXIBoolean *) value);
  1214.     rc = val->Set(BOOLEAN_TO_JSVAL(i));
  1215.     } break;
  1216.   case VALUE_INTEGER: {
  1217.     VXIint32 i = VXIIntegerValue((const VXIInteger *) value);
  1218.     if (INT_FITS_IN_JSVAL(i))
  1219.       rc = val->Set(INT_TO_JSVAL(i));
  1220.     else
  1221.       rc = VXIjsi_RESULT_NON_FATAL_ERROR;
  1222.     } break;
  1223.   case VALUE_FLOAT: {
  1224.     jsdouble *d = JS_NewDouble(context, 
  1225.          (double) VXIFloatValue((const VXIFloat *) value));
  1226.     if (d)
  1227.       rc = val->Set(DOUBLE_TO_JSVAL(d));
  1228.     else
  1229.       rc = VXIjsi_RESULT_OUT_OF_MEMORY;
  1230.     } break;
  1231.   // older version does not support double, unsigned long, etc.
  1232. #if (VXI_CURRENT_VERSION >= 0x00030000)
  1233.   case VALUE_DOUBLE: {
  1234.     jsdouble *d = JS_NewDouble(context, 
  1235.          (double) VXIDoubleValue((const VXIDouble *) value));
  1236.     if (d)
  1237.       rc = val->Set(DOUBLE_TO_JSVAL(d));
  1238.     else
  1239.       rc = VXIjsi_RESULT_OUT_OF_MEMORY;
  1240.     } break;
  1241. #endif
  1242.     
  1243.   case VALUE_STRING: {
  1244.     GET_JSCHAR_FROM_VXICHAR(tmpvalue, tmpvaluelen, 
  1245.           VXIStringCStr((const VXIString *) value));
  1246.     JSString *s = JS_NewUCStringCopyZ(context, tmpvalue);
  1247.     if (s)
  1248.       rc = val->Set(STRING_TO_JSVAL(s));
  1249.     else
  1250.       rc = VXIjsi_RESULT_OUT_OF_MEMORY;
  1251.     } break;
  1252.   case VALUE_PTR:
  1253.     // Not supported in JavaScript
  1254.     rc = VXIjsi_RESULT_NON_FATAL_ERROR;
  1255.     break;
  1256.   case VALUE_CONTENT: {
  1257.     // Create an object for the content, attach the passed content as
  1258.     // private data. We set the return value prior to setting the
  1259.     // private data to avoid getting garbage collected in the
  1260.     // meantime.
  1261.     VXIValue *c = NULL;
  1262.     JSObject *content = JS_NewObject(context, &CONTENT_CLASS, NULL, NULL);
  1263.     if (!content || 
  1264.         (val->Set(OBJECT_TO_JSVAL(content)) != VXIjsi_RESULT_SUCCESS) ||
  1265.         ((c = VXIValueClone(value)) == NULL)) {
  1266.       val->Clear();
  1267.       rc = VXIjsi_RESULT_OUT_OF_MEMORY; // JS object gets garbage collected
  1268.     } else if (!JS_SetPrivate(context, content, c)) {
  1269.       val->Clear();
  1270.       rc = VXIjsi_RESULT_FATAL_ERROR;
  1271.     }
  1272.   } break;
  1273.   case VALUE_MAP: {
  1274.     // Create an object for the map, temporarily root it so the data
  1275.     // added underneath is not garbage collected on us
  1276.     JSObject *mapObj = JS_NewObject(context, &MAP_CLASS, NULL, NULL);
  1277.     if (!mapObj) {
  1278.       rc = VXIjsi_RESULT_OUT_OF_MEMORY;
  1279.     } else if ((rc = val->Set(OBJECT_TO_JSVAL(mapObj))) ==
  1280.     VXIjsi_RESULT_SUCCESS ) {
  1281.       // Walk the map and add object properties, the map may be empty
  1282.       const VXIchar *prop;
  1283.       const VXIValue *propValue;
  1284.       VXIMapIterator *it = VXIMapGetFirstProperty((const VXIMap *) value, 
  1285.                &prop, &propValue);
  1286.       while (it  && (rc == VXIjsi_RESULT_SUCCESS)) {
  1287.         JsiProtectedJsval propVal(context);
  1288.         rc = VXIValueToJsval(context, propValue, &propVal);
  1289.         if (rc == VXIjsi_RESULT_SUCCESS) {
  1290.         GET_JSCHAR_FROM_VXICHAR(tmpprop, tmpproplen, prop);
  1291.         if (!JS_DefineUCProperty(context, mapObj, tmpprop, tmpproplen,
  1292.               propVal.Get(), NULL, NULL, 
  1293.               JSPROP_ENUMERATE))
  1294.           rc = VXIjsi_RESULT_OUT_OF_MEMORY;
  1295.         }
  1296.   
  1297.         if (VXIMapGetNextProperty(it, &prop, &propValue) != 
  1298.              VXIvalue_RESULT_SUCCESS) {
  1299.           VXIMapIteratorDestroy(&it);
  1300.           it = NULL;
  1301.         }
  1302.       }
  1303.       if (it)
  1304.         VXIMapIteratorDestroy(&it);
  1305.     }
  1306.   } break;
  1307.   case VALUE_VECTOR: {
  1308.     // Create a vector for the map, temporarily root it so the data
  1309.     // added underneath is not garbage collected on us
  1310.     JSObject *vecObj = JS_NewArrayObject(context, 0, NULL);
  1311.     if (!vecObj) {
  1312.       rc = VXIjsi_RESULT_OUT_OF_MEMORY;
  1313.     } else if ((rc = val->Set(OBJECT_TO_JSVAL(vecObj))) ==
  1314.                  VXIjsi_RESULT_SUCCESS) {
  1315.       // Walk the map and add object properties, the map may be empty
  1316.       const VXIVector *vec = (const VXIVector *) value;
  1317.       VXIunsigned i = 0;
  1318.       const VXIValue *elValue;
  1319.       while ((rc == VXIjsi_RESULT_SUCCESS) &&
  1320.             ((elValue = VXIVectorGetElement(vec, i)) != NULL )) {
  1321.         JsiProtectedJsval elVal(context);
  1322.         rc = VXIValueToJsval(context, elValue, &elVal);
  1323.         if ((rc == VXIjsi_RESULT_SUCCESS) &&
  1324.             (!JS_DefineElement(context, vecObj, i, elVal.Get(), NULL,
  1325.               NULL, JSPROP_ENUMERATE) ))
  1326.           rc = VXIjsi_RESULT_OUT_OF_MEMORY;
  1327.         i++;
  1328.       }
  1329.     }
  1330.   } break;
  1331.   default:
  1332.     rc = VXIjsi_RESULT_UNSUPPORTED;
  1333.   }
  1334.   if (rc != VXIjsi_RESULT_SUCCESS)
  1335.     val->Clear();
  1336.   return rc;
  1337. }
  1338. // Static callback for finalizing scopes
  1339. void JS_DLL_CALLBACK 
  1340. JsiContext::ScopeFinalize(JSContext *context, JSObject *obj)
  1341. {
  1342.   // Get this for logging the destruction
  1343.   JsiContext *pThis = (JsiContext *) JS_GetContextPrivate(context);
  1344.   // Get the scope node from the private data and delete it
  1345.   JsiScopeChainNode *scopeNode = 
  1346.     (JsiScopeChainNode *) JS_GetPrivate(context, obj);
  1347.   if (scopeNode) {
  1348.     if (pThis)
  1349.       pThis->Diag(SBJSI_LOG_SCOPE, L"JsiContext::ScopeFinalize",
  1350.           L"scope garbage collected %s (0x%p), context 0x%p", 
  1351.           scopeNode->GetName().c_str(), obj, context);
  1352.     delete scopeNode;
  1353.   }
  1354. }
  1355. // Static callback for finalizing content objects
  1356. void JS_DLL_CALLBACK JsiContext::ContentFinalize(JSContext *cx, JSObject *obj)
  1357. {
  1358.   // Get the scope name from the private data and delete it
  1359.   VXIContent *content = (VXIContent *) JS_GetPrivate(cx, obj);
  1360.   if (content) {
  1361.     VXIValue *tmp = (VXIValue *) content;
  1362.     VXIValueDestroy (&tmp);
  1363.   }
  1364. }
  1365. // Static callback for enforcing maxBranches
  1366. JSBool JS_DLL_CALLBACK 
  1367. JsiContext::BranchCallback(JSContext *context, JSScript *script)
  1368. {
  1369.   if (!context)
  1370.     return JS_FALSE;
  1371.   // Get ourself from our private data
  1372.   JsiContext *pThis = (JsiContext *) JS_GetContextPrivate(context);
  1373.   if (!pThis) {
  1374.     // Severe error
  1375.     return JS_FALSE;
  1376.   }
  1377.   pThis->numBranches++;
  1378.   JSBool rc = JS_TRUE;
  1379.   if (pThis->numBranches > pThis->maxBranches) {
  1380.     rc = JS_FALSE;
  1381.     pThis->Error(JSI_WARN_MAX_BRANCHES_EXCEEDED, L"%s%ld", 
  1382.         L"maxBranches", pThis->maxBranches);
  1383.   }
  1384.   return rc;
  1385. }
  1386. // Static callback for reporting JavaScript errors
  1387. void JS_DLL_CALLBACK JsiContext::ErrorReporter(JSContext *context, 
  1388.             const char *message,
  1389.             JSErrorReport *report)
  1390. {
  1391.   if (!context)
  1392.     return;
  1393.   // Get ourself from our private data
  1394.   JsiContext *pThis = (JsiContext *) JS_GetContextPrivate(context);
  1395.   if (!pThis)
  1396.     return;
  1397.   // Convert the ASCII string to wide characters
  1398.   wchar_t wmessage[1024];
  1399.   size_t len = strlen(message);
  1400.   if (len > 1023)
  1401.     len = 1023;
  1402.   for (size_t i = 0; i < len; i++)
  1403.     wmessage[i] = (wchar_t) message[i];
  1404.   wmessage[len] = 0;
  1405.   // Save exception information, ownership of the value is passed
  1406.   if (pThis->exception)
  1407.     VXIValueDestroy(&pThis->exception);
  1408.   jsval ex = JSVAL_VOID;
  1409.   VXIValue *exception = NULL;
  1410.   if ((JS_IsExceptionPending(context)) &&
  1411.       (JS_GetPendingException(context, &ex)) &&
  1412.       (JsvalToVXIValue(context, ex, &exception) == VXIjsi_RESULT_SUCCESS)) {
  1413.     pThis->exception = exception;
  1414.     // update the message value with something more meaningful
  1415.     VXIMapSetProperty(
  1416.         reinterpret_cast<VXIMap *>(exception),
  1417.         L"message", 
  1418.         reinterpret_cast<VXIValue *>(VXIStringCreate(wmessage)));
  1419.   }
  1420.   if (pThis->logEnabled) {
  1421.     // Determine the error number to log
  1422.     unsigned int errNum;
  1423.     if (JSREPORT_IS_WARNING(report->flags))
  1424.       errNum = JSI_WARN_SM_SCRIPT_WARNING;
  1425.     else if (JSREPORT_IS_EXCEPTION(report->flags))
  1426.       errNum = JSI_ERROR_SM_SCRIPT_EXCEPTION;
  1427.     else if (JSREPORT_IS_STRICT(report->flags))
  1428.       errNum = JSI_WARN_SM_SCRIPT_STRICT;
  1429.     else
  1430.       errNum = JSI_ERROR_SM_SCRIPT_ERROR;
  1431.     
  1432.     // Log the error
  1433.     GET_VXICHAR_FROM_JSCHAR(tmpuclinebuf, report->uclinebuf);
  1434.     GET_VXICHAR_FROM_JSCHAR(tmpuctokenptr, report->uctokenptr);
  1435.     pThis->Error(errNum, L"%s%s%s%ld%s%s%s%s", 
  1436.         L"errmsg", wmessage,
  1437.         L"line", report->lineno, 
  1438.         L"linetxt", (tmpuclinebuf ? tmpuclinebuf : L""), 
  1439.         L"tokentxt", (tmpuctokenptr ? tmpuctokenptr : L""));
  1440.   }
  1441. }
  1442. // Check if the variable name is valid at declaration
  1443. bool JsiContext::IsValidVarName(JSContext *context, JSObject *obj, const VXIchar* vname)
  1444. {
  1445.   bool ret = true;
  1446.   SBjsiString tscript(L"var ");
  1447.   tscript += vname;
  1448.   GET_JSCHAR_FROM_VXICHAR(tmpscript, tmpscriptlen, tscript.c_str());
  1449.     // check if the variable name is valid
  1450.   JSScript *jsScript = JS_CompileUCScript(context, obj, 
  1451.                                            tmpscript, tmpscriptlen, NULL, 1);
  1452.   if (!jsScript) 
  1453.     ret = false;
  1454.   else
  1455.     JS_DestroyScript(context, jsScript);
  1456.   return ret;
  1457. }