"Fossies" - the Fresh Open Source Software Archive

Member "AutoHotkey_L-1.1.33.09/source/script_object.cpp" (8 May 2021, 74132 Bytes) of package /windows/misc/AutoHotkey_L-1.1.33.09.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "script_object.cpp" see the Fossies "Dox" file reference documentation.

    1 #include "stdafx.h" // pre-compiled headers
    2 #include "defines.h"
    3 #include "globaldata.h"
    4 #include "script.h"
    5 #include "application.h"
    6 
    7 #include "script_object.h"
    8 #include "script_func_impl.h"
    9 
   10 
   11 //
   12 //  Internal: CallFunc - Call a script function with given params.
   13 //
   14 
   15 ResultType CallFunc(Func &aFunc, ExprTokenType &aResultToken, ExprTokenType *aParam[], int aParamCount)
   16 // Caller should pass an aResultToken with the usual setup:
   17 //  buf points to a buffer the called function may use: TCHAR[MAX_NUMBER_SIZE]
   18 //  mem_to_free is NULL; if it is non-NULL on return, caller (or caller's caller) is responsible for it.
   19 // Caller is responsible for making a persistent copy of the result, if appropriate.
   20 {
   21     if (aParamCount < aFunc.mMinParams)
   22     {
   23         aResultToken.symbol = SYM_STRING;
   24         aResultToken.marker = _T("");
   25         return OK; // Not FAIL, which would cause the entire thread to exit.
   26     }
   27 
   28     // When this variable goes out of scope, Var::FreeAndRestoreFunctionVars() is called (if appropriate):
   29     UDFCallInfo func_call;
   30     ResultType result;
   31 
   32     // CALL THE FUNCTION.
   33     if (aFunc.Call(func_call, result, aResultToken, aParam, aParamCount)
   34         // Make return value persistent if applicable:
   35         && aResultToken.symbol == SYM_STRING && !aFunc.mIsBuiltIn)
   36     {
   37         // Make a persistent copy of the string in case it is the contents of one of the function's local variables.
   38         if ( !*aResultToken.marker || !TokenSetResult(aResultToken, aResultToken.marker) )
   39             // Above failed or the result is an empty string, so make sure it remains valid after we return:
   40             aResultToken.marker = _T("");
   41     }
   42 
   43     return result;
   44 }
   45 
   46 
   47 //
   48 // CallMethod - Invoke a method with no parameters, discarding the result.
   49 //
   50 
   51 ResultType CallMethod(IObject *aInvokee, IObject *aThis, LPTSTR aMethodName
   52     , ExprTokenType *aParamValue, int aParamCount, INT_PTR *aRetVal // For event handlers.
   53     , int aExtraFlags) // For Object.__Delete().
   54 {
   55     ExprTokenType result_token, this_token, name_token;
   56         
   57     TCHAR result_buf[MAX_NUMBER_SIZE];
   58     result_token.marker = _T("");
   59     result_token.symbol = SYM_STRING;
   60     result_token.mem_to_free = NULL;
   61     result_token.buf = result_buf;
   62 
   63     this_token.symbol = SYM_OBJECT;
   64     this_token.object = aThis;
   65 
   66     ++aParamCount; // For the method name.
   67     ExprTokenType **param = (ExprTokenType **)_alloca(aParamCount * sizeof(ExprTokenType *));
   68     name_token.symbol = SYM_STRING;
   69     name_token.marker = aMethodName;
   70     param[0] = &name_token;
   71     for (int i = 1; i < aParamCount; ++i)
   72         param[i] = aParamValue + (i-1);
   73 
   74     ResultType result = aInvokee->Invoke(result_token, this_token, IT_CALL | aExtraFlags, param, aParamCount);
   75 
   76     if (result != EARLY_EXIT && result != FAIL)
   77     {
   78         // Indicate to caller whether an integer value was returned (for MsgMonitor()).
   79         result = TokenIsEmptyString(result_token) ? OK : EARLY_RETURN;
   80     }
   81     
   82     if (aRetVal) // Always set this as some callers don't initialize it:
   83         *aRetVal = result == EARLY_RETURN ? (INT_PTR)TokenToInt64(result_token) : 0;
   84 
   85     if (result_token.mem_to_free)
   86         free(result_token.mem_to_free);
   87     if (result_token.symbol == SYM_OBJECT)
   88         result_token.object->Release();
   89 
   90     return result;
   91 }
   92     
   93 
   94 //
   95 // Object::Create - Called by BIF_ObjCreate to create a new object, optionally passing key/value pairs to set.
   96 //
   97 
   98 Object *Object::Create(ExprTokenType *aParam[], int aParamCount)
   99 {
  100     if (aParamCount & 1)
  101         return NULL; // Odd number of parameters - reserved for future use.
  102 
  103     Object *obj = new Object();
  104     if (obj && aParamCount)
  105     {
  106         ExprTokenType result_token, this_token;
  107         TCHAR buf[MAX_NUMBER_SIZE];
  108 
  109         this_token.symbol = SYM_OBJECT;
  110         this_token.object = obj;
  111         
  112         for (int i = 0; i + 1 < aParamCount; i += 2)
  113         {
  114             if (aParam[i]->symbol == SYM_MISSING || aParam[i+1]->symbol == SYM_MISSING)
  115                 continue; // For simplicity.
  116 
  117             result_token.symbol = SYM_STRING;
  118             result_token.marker = _T("");
  119             result_token.mem_to_free = NULL;
  120             result_token.buf = buf;
  121 
  122             // This is used rather than a more direct approach to ensure it is equivalent to assignment.
  123             // For instance, Object("base",MyBase,"a",1,"b",2) invokes meta-functions contained by MyBase.
  124             // For future consideration: Maybe it *should* bypass the meta-mechanism?
  125             obj->Invoke(result_token, this_token, IT_SET, aParam + i, 2);
  126 
  127             if (result_token.symbol == SYM_OBJECT) // L33: Bugfix.  Invoke must assume the result will be used and as a result we must account for this object reference:
  128                 result_token.object->Release();
  129             if (result_token.mem_to_free) // Comment may be obsolete: Currently should never happen, but may happen in future.
  130                 free(result_token.mem_to_free);
  131         }
  132     }
  133     return obj;
  134 }
  135 
  136 Object *Object::CreateArray(ExprTokenType *aValue[], int aValueCount)
  137 {
  138     Object *obj = new Object();
  139     if (obj && aValueCount && !obj->InsertAt(0, 1, aValue, aValueCount))
  140     {
  141         obj->Release(); // InsertAt failed.
  142         obj = NULL;
  143     }
  144     return obj;
  145 }
  146 
  147 
  148 //
  149 // Object::Clone - Used for variadic function-calls.
  150 //
  151 
  152 Object *Object::Clone(BOOL aExcludeIntegerKeys)
  153 // Creates an object and copies to it the fields at and after the given offset.
  154 {
  155     IndexType aStartOffset = aExcludeIntegerKeys ? mKeyOffsetObject : 0;
  156 
  157     Object *objptr = new Object();
  158     if (!objptr|| aStartOffset >= mFieldCount)
  159         return objptr;
  160     
  161     Object &obj = *objptr;
  162 
  163     // Allocate space in destination object.
  164     IndexType field_count = mFieldCount - aStartOffset;
  165     if (!obj.SetInternalCapacity(field_count))
  166     {
  167         obj.Release();
  168         return NULL;
  169     }
  170 
  171     FieldType *fields = obj.mFields; // Newly allocated by above.
  172     int failure_count = 0; // See comment below.
  173     IndexType i;
  174 
  175     obj.mFieldCount = field_count;
  176     obj.mKeyOffsetObject = mKeyOffsetObject - aStartOffset;
  177     obj.mKeyOffsetString = mKeyOffsetString - aStartOffset;
  178     if (obj.mKeyOffsetObject < 0) // Currently might always evaluate to false.
  179     {
  180         obj.mKeyOffsetObject = 0; // aStartOffset excluded all integer and some or all object keys.
  181         if (obj.mKeyOffsetString < 0)
  182             obj.mKeyOffsetString = 0; // aStartOffset also excluded some string keys.
  183     }
  184     //else no need to check mKeyOffsetString since it should always be >= mKeyOffsetObject.
  185 
  186     for (i = 0; i < field_count; ++i)
  187     {
  188         FieldType &dst = fields[i];
  189         FieldType &src = mFields[aStartOffset + i];
  190 
  191         // Copy key.
  192         if (i >= obj.mKeyOffsetString)
  193         {
  194             if ( !(dst.key.s = _tcsdup(src.key.s)) )
  195             {
  196                 // Key allocation failed. At this point, all int and object keys
  197                 // have been set and values for previous fields have been copied.
  198                 // Rather than trying to set up the object so that what we have
  199                 // so far is valid in order to break out of the loop, continue,
  200                 // make all fields valid and then allow them to be freed. 
  201                 ++failure_count;
  202             }
  203         }
  204         else if (i >= obj.mKeyOffsetObject)
  205             (dst.key.p = src.key.p)->AddRef();
  206         else
  207             dst.key.i = src.key.i;
  208 
  209         // Copy value.
  210         switch (dst.symbol = src.symbol)
  211         {
  212         case SYM_OPERAND:
  213             if (dst.size = src.size)
  214             {
  215                 if (dst.marker = tmalloc(dst.size))
  216                 {
  217                     // Since user may have stored binary data, copy the entire field:
  218                     tmemcpy(dst.marker, src.marker, src.size);
  219                     continue;
  220                 }
  221                 // Since above didn't continue: allocation failed.
  222                 ++failure_count; // See failure comment further above.
  223             }
  224             dst.marker = Var::sEmptyString;
  225             dst.size = 0;
  226             break;
  227 
  228         case SYM_OBJECT:
  229             (dst.object = src.object)->AddRef();
  230             break;
  231 
  232         //case SYM_INTEGER:
  233         //case SYM_FLOAT:
  234         default:
  235             dst.n_int64 = src.n_int64; // Union copy.
  236         }
  237     }
  238     if (failure_count)
  239     {
  240         // One or more memory allocations failed.  It seems best to return a clear failure
  241         // indication rather than an incomplete copy.  Now that the loop above has finished,
  242         // the object's contents are at least valid and it is safe to free the object:
  243         obj.Release();
  244         return NULL;
  245     }
  246     return &obj;
  247 }
  248 
  249 
  250 //
  251 // Object::ArrayToParams - Used for variadic function-calls.
  252 //
  253 
  254 void Object::ArrayToParams(ExprTokenType *token, ExprTokenType **param_list, int extra_params
  255     , ExprTokenType **aParam, int aParamCount)
  256 // Expands this object's contents into the parameter list.  Due to the nature
  257 // of the parameter list, only fields with integer keys are used (named params
  258 // aren't supported).
  259 // Return value is FAIL if a required parameter was omitted or malloc() failed.
  260 {
  261     // Find the first and last field to be used.
  262     int start = (int)mKeyOffsetInt;
  263     int end = (int)mKeyOffsetObject; // For readability.
  264     while (start < end && mFields[start].key.i < 1)
  265         ++start; // Skip any keys <= 0 (consistent with UDF-calling behaviour).
  266     
  267     int param_index;
  268     IndexType field_index;
  269 
  270     // For each extra param...
  271     for (field_index = start, param_index = 0; field_index < end; ++field_index, ++param_index)
  272     {
  273         for ( ; param_index + 1 < (int)mFields[field_index].key.i; ++param_index)
  274         {
  275             token[param_index].symbol = SYM_MISSING;
  276             token[param_index].marker = _T("");
  277         }
  278         mFields[field_index].ToToken(token[param_index]);
  279     }
  280     
  281     ExprTokenType **param_ptr = param_list;
  282 
  283     // Init the array of param token pointers.
  284     for (param_index = 0; param_index < aParamCount; ++param_index)
  285         *param_ptr++ = aParam[param_index]; // Caller-supplied param token.
  286     for (param_index = 0; param_index < extra_params; ++param_index)
  287         *param_ptr++ = &token[param_index]; // New param.
  288 }
  289 
  290 
  291 //
  292 // Object::ArrayToStrings - Used by BIF_StrSplit.
  293 //
  294 
  295 ResultType Object::ArrayToStrings(LPTSTR *aStrings, int &aStringCount, int aStringsMax)
  296 {
  297     int i, j;
  298     for (i = 0, j = 0; i < aStringsMax && j < mKeyOffsetObject; ++j)
  299         if (SYM_OPERAND == mFields[j].symbol)
  300             aStrings[i++] = mFields[j].marker;
  301         else
  302             return FAIL;
  303     aStringCount = i;
  304     return OK;
  305 }
  306 
  307 
  308 //
  309 // Object::Delete - Called immediately before the object is deleted.
  310 //                  Returns false if object should not be deleted yet.
  311 //
  312 
  313 bool Object::Delete()
  314 {
  315     if (mBase)
  316     {
  317         KeyType key;
  318         IndexType insert_pos;
  319         key.s = _T("__Class");
  320         if (FindField(SYM_STRING, key, insert_pos))
  321             // This object appears to be a class definition, so it would probably be
  322             // undesirable to call the super-class' __Delete() meta-function for this.
  323             return ObjectBase::Delete();
  324 
  325         // L33: Privatize the last recursion layer's deref buffer in case it is in use by our caller.
  326         // It's done here rather than in Var::FreeAndRestoreFunctionVars or CallFunc (even though the
  327         // below might not actually call any script functions) because this function is probably
  328         // executed much less often in most cases.
  329         PRIVATIZE_S_DEREF_BUF;
  330 
  331         Line *curr_line = g_script.mCurrLine;
  332 
  333         // If an exception has been thrown, temporarily clear it for execution of __Delete.
  334         ExprTokenType *exc = g->ThrownToken;
  335         g->ThrownToken = NULL;
  336         
  337         // This prevents an erroneous "The current thread will exit" message when an error occurs,
  338         // by causing LineError() to throw an exception:
  339         int outer_excptmode = g->ExcptMode;
  340         g->ExcptMode |= EXCPTMODE_DELETE;
  341 
  342         CallMethod(mBase, this, sMetaFuncName[3], NULL, 0, NULL, IF_METAOBJ); // base.__Delete()
  343 
  344         g->ExcptMode = outer_excptmode;
  345 
  346         // Exceptions thrown by __Delete are reported immediately because they would not be handled
  347         // consistently by the caller (they would typically be "thrown" by the next function call),
  348         // and because the caller must be allowed to make additional __Delete calls.
  349         if (g->ThrownToken)
  350             g_script.FreeExceptionToken(g->ThrownToken);
  351 
  352         // If an exception has been thrown by our caller, it's likely that it can and should be handled
  353         // reliably by our caller, so restore it.
  354         if (exc)
  355             g->ThrownToken = exc;
  356 
  357         g_script.mCurrLine = curr_line; // Prevent misleading error reports/Exception() stack trace.
  358 
  359         DEPRIVATIZE_S_DEREF_BUF; // L33: See above.
  360 
  361         // Above may pass the script a reference to this object to allow cleanup routines to free any
  362         // associated resources.  Deleting it is only safe if the script no longer holds any references
  363         // to it.  Since cleanup routines may (intentionally or unintentionally) copy this reference,
  364         // ensure this object really has no more references before proceeding with deletion:
  365         if (mRefCount > 1)
  366             return false;
  367     }
  368     return ObjectBase::Delete();
  369 }
  370 
  371 
  372 Object::~Object()
  373 {
  374     if (mBase)
  375         mBase->Release();
  376 
  377     if (mFields)
  378     {
  379         if (mFieldCount)
  380         {
  381             IndexType i = mFieldCount - 1;
  382             // Free keys: first strings, then objects (objects have a lower index in the mFields array).
  383             for ( ; i >= mKeyOffsetString; --i)
  384                 free(mFields[i].key.s);
  385             for ( ; i >= mKeyOffsetObject; --i)
  386                 mFields[i].key.p->Release();
  387             // Free values.
  388             while (mFieldCount) 
  389                 mFields[--mFieldCount].Free();
  390         }
  391         // Free fields array.
  392         free(mFields);
  393     }
  394 }
  395 
  396 
  397 //
  398 // Object::Invoke - Called by BIF_ObjInvoke when script explicitly interacts with an object.
  399 //
  400 
  401 ResultType STDMETHODCALLTYPE Object::Invoke(
  402                                             ExprTokenType &aResultToken,
  403                                             ExprTokenType &aThisToken,
  404                                             int aFlags,
  405                                             ExprTokenType *aParam[],
  406                                             int aParamCount
  407                                             )
  408 // L40: Revised base mechanism for flexibility and to simplify some aspects.
  409 //      obj[] -> obj.base.__Get -> obj.base[] -> obj.base.__Get etc.
  410 {
  411     SymbolType key_type;
  412     KeyType key;
  413     FieldType *field, *prop_field;
  414     IndexType insert_pos;
  415     Property *prop = NULL; // Set default.
  416 
  417     // If this is some object's base and is being invoked in that capacity, call
  418     //  __Get/__Set/__Call as defined in this base object before searching further.
  419     if (SHOULD_INVOKE_METAFUNC)
  420     {
  421         key.s = sMetaFuncName[INVOKE_TYPE];
  422         // Look for a meta-function definition directly in this base object.
  423         if (field = FindField(SYM_STRING, key, /*out*/ insert_pos))
  424         {
  425             // Seems more maintainable to copy params rather than assume aParam[-1] is always valid.
  426             ExprTokenType **meta_params = (ExprTokenType **)_alloca((aParamCount + 1) * sizeof(ExprTokenType *));
  427             // Shallow copy; points to the same tokens.  Leave a space for param[0], which must be the param which
  428             // identified the field (or in this case an empty space) to replace with aThisToken when appropriate.
  429             memcpy(meta_params + 1, aParam, aParamCount * sizeof(ExprTokenType*));
  430 
  431             Line *curr_line = g_script.mCurrLine;
  432             ResultType r = CallField(field, aResultToken, aThisToken, aFlags, meta_params, aParamCount + 1);
  433             g_script.mCurrLine = curr_line; // Allows exceptions thrown by later meta-functions to report a more appropriate line.
  434             //if (r == EARLY_RETURN)
  435                 // Propagate EARLY_RETURN in case this was the __Call meta-function of a
  436                 // "function object" which is used as a meta-function of some other object.
  437                 //return EARLY_RETURN; // TODO: Detection of 'return' vs 'return empty_value'.
  438             if (r != OK) // Likely EARLY_RETURN, FAIL or EARLY_EXIT.
  439                 return r;
  440         }
  441     }
  442     
  443     int param_count_excluding_rvalue = aParamCount;
  444 
  445     if (IS_INVOKE_SET)
  446     {
  447         // Due to the way expression parsing works, the result should never be negative
  448         // (and any direct callers of Invoke must always pass aParamCount >= 1):
  449         --param_count_excluding_rvalue;
  450     }
  451     
  452     if (param_count_excluding_rvalue && aParam[0]->symbol != SYM_MISSING)
  453     {
  454         field = FindField(*aParam[0], aResultToken.buf, /*out*/ key_type, /*out*/ key, /*out*/ insert_pos);
  455 
  456         // There used to be a check prior to the FindField() call above which avoided searching
  457         // for base[field] when performing an assignment.  As an unintended side-effect, it was
  458         // possible for base.base.__Set to be called even if base[field] exists, which is
  459         // inconsistent with __Get and __Call.  That check was removed for v1.1.16 in order
  460         // to implement property accessors, and a check was added below to retain the old
  461         // behaviour for compatibility -- this should be changed in v2.
  462 
  463         static Property sProperty;
  464 
  465         // v1.1.16: Handle class property accessors:
  466         if (field && field->symbol == SYM_OBJECT && *(void **)field->object == *(void **)&sProperty)
  467         {
  468             // The "type check" above is used for speed.  Simple benchmarks of x[1] where x := [[]]
  469             // shows this check to not affect performance, whereas dynamic_cast<> hurt performance by
  470             // about 25% and typeid()== by about 20%.  We can safely assume that the vtable pointer is
  471             // stored at the beginning of the object even though it isn't guaranteed by the C++ standard,
  472             // since COM fundamentally requires it:  http://msdn.microsoft.com/en-us/library/dd757710
  473             prop = (Property *)field->object;
  474             prop_field = field;
  475             if (IS_INVOKE_SET ? prop->CanSet() : prop->CanGet())
  476             {
  477                 if (aParamCount > 2 && IS_INVOKE_SET)
  478                 {
  479                     // Do some shuffling to put value before the other parameters.  This relies on above
  480                     // having verified that we're handling this invocation; otherwise the parameters would
  481                     // need to be swapped back later in case they're passed to a base's meta-function.
  482                     ExprTokenType *value = aParam[aParamCount - 1];
  483                     for (int i = aParamCount - 1; i > 1; --i)
  484                         aParam[i] = aParam[i - 1];
  485                     aParam[1] = value; // Corresponds to the setter's hidden "value" parameter.
  486                 }
  487                 ExprTokenType *name_token = aParam[0];
  488                 aParam[0] = &aThisToken; // For the hidden "this" parameter in the getter/setter.
  489                 // Pass IF_FUNCOBJ so that it'll pass all parameters to the getter/setter.
  490                 // For a functor Object, we would need to pass a token representing "this" Property,
  491                 // but since Property::Invoke doesn't use it, we pass our aThisToken for simplicity.
  492                 ResultType result = prop->Invoke(aResultToken, aThisToken, aFlags | IF_FUNCOBJ, aParam, aParamCount);
  493                 aParam[0] = name_token;
  494                 return result == EARLY_RETURN ? OK : result;
  495             }
  496             // The property was missing get/set (whichever this invocation is), so continue as
  497             // if the property itself wasn't defined.
  498             field = NULL;
  499         }
  500         else if (IS_INVOKE_META && IS_INVOKE_SET && param_count_excluding_rvalue == 1) // v1.1.16: For compatibility with earlier versions - see above.
  501         {
  502             key_type = SYM_INVALID;
  503             field = NULL;
  504         }
  505     }
  506     else
  507     {
  508         key_type = SYM_INVALID; // Allow key_type checks below without requiring that param_count_excluding_rvalue also be checked.
  509         field = NULL;
  510     }
  511     
  512     if (!field)
  513     {
  514         // This field doesn't exist, so let our base object define what happens:
  515         //      1) __Get, __Set or __Call.  If these don't return a value, processing continues.
  516         //      2) For GET and CALL only, check the base object's own fields.
  517         //      3) Repeat 1 through 3 for the base object's own base.
  518         if (mBase)
  519         {
  520             // aFlags: If caller specified IF_METAOBJ but not IF_METAFUNC, they want to recursively
  521             // find and execute a specific meta-function (__new or __delete) but don't want any base
  522             // object to invoke __call.  So if this is already a meta-invocation, don't change aFlags.
  523             ResultType r = mBase->Invoke(aResultToken, aThisToken, aFlags | (IS_INVOKE_META ? 0 : IF_META), aParam, aParamCount);
  524             if (r != INVOKE_NOT_HANDLED // Base handled it.
  525                 || key_type == SYM_INVALID) // Nothing left to do in this case.
  526                 return r;
  527 
  528             // Since the above may have inserted or removed fields (including the specified one),
  529             // insert_pos may no longer be correct or safe.  Updating field also allows a meta-function
  530             // to initialize a field and allow processing to continue as if it already existed.
  531             field = FindField(key_type, key, /*out*/ insert_pos);
  532             if (prop)
  533             {
  534                 // This field was a property.
  535                 if (field && field->symbol == SYM_OBJECT && field->object == prop)
  536                 {
  537                     // This field is still a property (and the same one).
  538                     prop_field = field; // Must update this pointer in case the field is to be overwritten.
  539                     field = NULL; // Act like the field doesn't exist (until the time comes to insert a value).
  540                 }
  541                 else
  542                     prop = NULL; // field was reassigned or removed, so ignore the property.
  543             }
  544         }
  545 
  546         // Since the base object didn't handle this op, check for built-in properties/methods.
  547         // This must apply only to the original target object (aThisToken), not one of its bases.
  548         if (!IS_INVOKE_META && key_type == SYM_STRING && !field) // v1.1.16: Check field again so if __Call sets a field, it gets called.
  549         {
  550             //
  551             // BUILT-IN METHODS
  552             //
  553             if (IS_INVOKE_CALL)
  554             {
  555                 // Since above has not handled this call and no field exists,
  556                 // it can only be a built-in method or unknown.  This handles both:
  557                 return CallBuiltin(GetBuiltinID(key.s), aResultToken, aParam + 1, aParamCount - 1); // +/- 1 to exclude the method identifier.
  558             }
  559             //
  560             // BUILT-IN "BASE" PROPERTY
  561             //
  562             else if (param_count_excluding_rvalue == 1 && !_tcsicmp(key.s, _T("base")))
  563             {
  564                 if (IS_INVOKE_SET)
  565                 // "base" must be handled before inserting a new field.
  566                 {
  567                     IObject *obj = TokenToObject(*aParam[1]);
  568                     if (obj)
  569                     {
  570                         obj->AddRef(); // for mBase
  571                         obj->AddRef(); // for aResultToken
  572                         aResultToken.symbol = SYM_OBJECT;
  573                         aResultToken.object = obj;
  574                     }
  575                     // else leave as empty string.
  576                     if (mBase)
  577                         mBase->Release();
  578                     mBase = obj; // May be NULL.
  579                     return OK;
  580                 }
  581                 else // GET
  582                 {
  583                     if (mBase)
  584                     {
  585                         aResultToken.symbol = SYM_OBJECT;
  586                         aResultToken.object = mBase;
  587                         mBase->AddRef();
  588                     }
  589                     // else leave as empty string.
  590                     return OK;
  591                 }
  592             }
  593         } // if (!IS_INVOKE_META && key_type == SYM_STRING)
  594     } // if (!field)
  595 
  596     //
  597     // OPERATE ON A FIELD WITHIN THIS OBJECT
  598     //
  599 
  600     // CALL
  601     if (IS_INVOKE_CALL)
  602     {
  603         if (!field)
  604             return INVOKE_NOT_HANDLED;
  605         // v1.1.18: The following flag is set whenever a COM client invokes with METHOD|PROPERTYGET,
  606         // such as X.Y in VBScript or C#.  Some convenience is gained at the expense of purity by treating
  607         // it as METHOD if X.Y is a Func object or PROPERTYGET in any other case.
  608         // v1.1.19: Handling this flag here rather than in CallField() has the following benefits:
  609         //  - Reduces code duplication.
  610         //  - Fixes X.__Call being returned instead of being called, if X.__Call is a string.
  611         //  - Allows X.Y(Z) and similar to work like X.Y[Z], instead of ignoring the extra parameters.
  612         if ( !(aFlags & IF_CALL_FUNC_ONLY) || (field->symbol == SYM_OBJECT && dynamic_cast<Func *>(field->object)) )
  613             return CallField(field, aResultToken, aThisToken, aFlags, aParam, aParamCount);
  614         aFlags = (aFlags & ~(IT_BITMASK | IF_CALL_FUNC_ONLY)) | IT_GET;
  615     }
  616 
  617     // MULTIPARAM[x,y] -- may be SET[x,y]:=z or GET[x,y], but always treated like GET[x].
  618     if (param_count_excluding_rvalue > 1)
  619     {
  620         // This is something like this[x,y] or this[x,y]:=z.  Since it wasn't handled by a meta-mechanism above,
  621         // handle only the "x" part (automatically creating and storing an object if this[x] didn't already exist
  622         // and an assignment is being made) and recursively invoke.  This has at least two benefits:
  623         //  1) Objects natively function as multi-dimensional arrays.
  624         //  2) Automatic initialization of object-fields.
  625         //      For instance, this["base","__Get"]:="MyObjGet" does not require a prior this.base:=Object().
  626         IObject *obj = NULL;
  627         if (field)
  628         {
  629             if (field->symbol == SYM_OBJECT)
  630                 // AddRef not used.  See below.
  631                 obj = field->object;
  632         }
  633         else if (!IS_INVOKE_META)
  634         {
  635             // This section applies only to the target object (aThisToken) and not any of its base objects.
  636             // Allow obj["base",x] to access a field of obj.base; L40: This also fixes obj.base[x] which was broken by L36.
  637             if (key_type == SYM_STRING && !_tcsicmp(key.s, _T("base")))
  638             {
  639                 if (!mBase && IS_INVOKE_SET)
  640                     mBase = new Object();
  641                 obj = mBase; // If NULL, above failed and below will detect it.
  642             }
  643             // Automatically create a new object for the x part of obj[x,y]:=z.
  644             else if (IS_INVOKE_SET)
  645             {
  646                 Object *new_obj = new Object();
  647                 if (new_obj)
  648                 {
  649                     if ( field = prop ? prop_field : Insert(key_type, key, insert_pos) )
  650                     {
  651                         if (prop) // Otherwise, field is already empty.
  652                             prop->Release();
  653                         // Don't do field->Assign() since it would do AddRef() and we would need to counter with Release().
  654                         field->symbol = SYM_OBJECT;
  655                         field->object = obj = new_obj;
  656                     }
  657                     else
  658                     {   // Create() succeeded but Insert() failed, so free the newly created obj.
  659                         new_obj->Release();
  660                     }
  661                 }
  662             }
  663         }
  664         if (obj) // Object was successfully found or created.
  665         {
  666             // obj now contains a pointer to the object contained by this field, possibly newly created above.
  667             ExprTokenType obj_token;
  668             obj_token.symbol = SYM_OBJECT;
  669             obj_token.object = obj;
  670             // References in obj_token and obj weren't counted (AddRef wasn't called), so Release() does not
  671             // need to be called before returning, and accessing obj after calling Invoke() would not be safe
  672             // since it could Release() the object (by overwriting our field via script) as a side-effect.
  673             // Recursively invoke obj, passing remaining parameters; remove IF_META to correctly treat obj as target:
  674             return obj->Invoke(aResultToken, obj_token, aFlags & ~IF_META, aParam + 1, aParamCount - 1);
  675             // Above may return INVOKE_NOT_HANDLED in cases such as obj[a,b] where obj[a] exists but obj[a][b] does not.
  676         }
  677     } // MULTIPARAM[x,y]
  678 
  679     // SET
  680     else if (IS_INVOKE_SET)
  681     {
  682         if (!IS_INVOKE_META && param_count_excluding_rvalue)
  683         {
  684             ExprTokenType &value_param = *aParam[1];
  685             // L34: Assigning an empty string no longer removes the field.
  686             if ( (field || (field = prop ? prop_field : Insert(key_type, key, insert_pos)))
  687                 && field->Assign(value_param) )
  688             {
  689                 if (field->symbol == SYM_OPERAND)
  690                 {
  691                     // Use value_param since our copy may be freed prematurely in some (possibly rare) cases:
  692                     aResultToken.symbol = SYM_STRING;
  693                     aResultToken.marker = TokenToString(value_param);
  694                     // Below: no longer used as other areas expect string results to always be SYM_STRING.
  695                     // If it is ever used in future, we MUST copy marker and buf separately for x64 support.
  696                     // However, it seems appropriate *not* to return a SYM_OPERAND with cached binary integer
  697                     // since above has stored only the string part of it.
  698                     //aResultToken.symbol        = value_param.symbol;
  699                     //aResultToken.value_int64 = value_param.value_int64; // Copy marker and buf (via union) in case it is SYM_OPERAND with a cached integer.
  700                 }
  701                 else
  702                     field->Get(aResultToken); // L34: Corrected this to be aResultToken instead of value_param (broken by L33).
  703             }
  704             return OK;
  705         }
  706     }
  707 
  708     // GET
  709     else if (field)
  710     {
  711         if (field->symbol == SYM_OPERAND)
  712         {
  713             // Use SYM_STRING and not SYM_OPERAND, since SYM_OPERAND's use of aResultToken.buf
  714             // would conflict with the use of mem_to_free/buf to return a memory allocation.
  715             aResultToken.symbol = SYM_STRING;
  716             // L33: Make a persistent copy; our copy might be freed indirectly by releasing this object.
  717             //      Prior to L33, callers took care of this UNLESS this was the last op in an expression.
  718             if (!TokenSetResult(aResultToken, field->marker))
  719                 aResultToken.marker = _T("");
  720         }
  721         else
  722             field->Get(aResultToken);
  723 
  724         return OK;
  725     }
  726 
  727     return INVOKE_NOT_HANDLED;
  728 }
  729 
  730 
  731 int Object::GetBuiltinID(LPCTSTR aName)
  732 {
  733     // Newer methods which do not support the _ prefix:
  734     switch (toupper(*aName))
  735     {
  736     case 'L':
  737         if (!_tcsicmp(aName, _T("Length")))
  738             return FID_ObjLength;
  739         break;
  740     case 'P':
  741         if (!_tcsicmp(aName, _T("Push")))
  742             return FID_ObjPush;
  743         if (!_tcsicmp(aName, _T("Pop")))
  744             return FID_ObjPop;
  745         break;
  746     case 'I':
  747         if (!_tcsicmp(aName, _T("InsertAt")))
  748             return FID_ObjInsertAt;
  749         break;
  750     case 'R':
  751         if (!_tcsicmp(aName, _T("RemoveAt")))
  752             return FID_ObjRemoveAt;
  753         break;
  754     case 'D':
  755         if (!_tcsicmp(aName, _T("Delete")))
  756             return FID_ObjDelete;
  757     case 'C':
  758         if (!_tcsicmp(aName, _T("Count")))
  759             return FID_ObjCount;
  760         break;
  761     }
  762     // Older methods which support the _ prefix:
  763     if (*aName == '_')
  764         ++aName; // Exclude the prefix from further consideration.
  765     switch (toupper(*aName))
  766     {
  767     case 'H':
  768         if (!_tcsicmp(aName, _T("HasKey")))
  769             return FID_ObjHasKey;
  770         break;
  771     case 'N':
  772         if (!_tcsicmp(aName, _T("NewEnum")))
  773             return FID_ObjNewEnum;
  774         break;
  775     case 'G':
  776         if (!_tcsicmp(aName, _T("GetAddress")))
  777             return FID_ObjGetAddress;
  778         if (!_tcsicmp(aName, _T("GetCapacity")))
  779             return FID_ObjGetCapacity;
  780         break;
  781     case 'S':
  782         if (!_tcsicmp(aName, _T("SetCapacity")))
  783             return FID_ObjSetCapacity;
  784         break;
  785     case 'C':
  786         if (!_tcsicmp(aName, _T("Clone")))
  787             return FID_ObjClone;
  788         break;
  789     case 'M':
  790         if (!_tcsicmp(aName, _T("MaxIndex")))
  791             return FID_ObjMaxIndex;
  792         if (!_tcsicmp(aName, _T("MinIndex")))
  793             return FID_ObjMinIndex;
  794         break;
  795     // Deprecated methods:
  796     case 'I':
  797         if (!_tcsicmp(aName, _T("Insert")))
  798             return FID_ObjInsert;
  799         break;
  800     case 'R':
  801         if (!_tcsicmp(aName, _T("Remove")))
  802             return FID_ObjRemove;
  803         break;
  804     }
  805     return -1;
  806 }
  807 
  808 
  809 ResultType Object::CallBuiltin(int aID, ExprTokenType &aResultToken, ExprTokenType *aParam[], int aParamCount)
  810 {
  811     switch (aID)
  812     {
  813     #define case_method(name) \
  814         case FID_Obj##name: \
  815             return _##name(aResultToken, aParam, aParamCount)
  816     // Putting more frequently called methods first might help performance.
  817     case_method(Length);
  818     case_method(HasKey);
  819     case_method(MaxIndex);
  820     case_method(NewEnum);
  821     case_method(Push);
  822     case_method(Pop);
  823     case_method(InsertAt);
  824     case_method(RemoveAt);
  825     case_method(Delete);
  826     case_method(Count);
  827     case_method(MinIndex);
  828     case_method(GetAddress);
  829     case_method(SetCapacity);
  830     case_method(GetCapacity);
  831     case_method(Clone);
  832     // Deprecated methods:
  833     case_method(Insert);
  834     case_method(Remove);
  835     #undef case_method
  836     }
  837     return INVOKE_NOT_HANDLED;
  838 }
  839 
  840 
  841 //
  842 // Helper function for WinMain()
  843 //
  844 
  845 Object *Object::CreateFromArgV(LPTSTR *aArgV, int aArgC)
  846 {
  847     ExprTokenType *token = (ExprTokenType *)_alloca(aArgC * sizeof(ExprTokenType));
  848     ExprTokenType **param = (ExprTokenType **)_alloca(aArgC * sizeof(ExprTokenType*));
  849     for (int j = 0; j < aArgC; ++j)
  850     {
  851         token[j].SetValue(aArgV[j]);
  852         param[j] = &token[j];
  853     }
  854     return CreateArray(param, aArgC);
  855 }
  856 
  857 
  858 //
  859 // Internal: Object::CallField - Used by Object::Invoke to call a function/method stored in this object.
  860 //
  861 
  862 ResultType Object::CallField(FieldType *aField, ExprTokenType &aResultToken, ExprTokenType &aThisToken, int aFlags, ExprTokenType *aParam[], int aParamCount)
  863 // aParam[0] contains the identifier of this field or an empty space (for __Get etc.).
  864 {
  865     if (aField->symbol == SYM_OBJECT)
  866     {
  867         ExprTokenType field_token;
  868         field_token.symbol = SYM_OBJECT;
  869         field_token.object = aField->object;
  870         ExprTokenType *tmp = aParam[0];
  871         // Something must be inserted into the parameter list to remove any ambiguity between an intentionally
  872         // and directly called function of 'that' object and one of our parameters matching an existing name.
  873         // Rather than inserting something like an empty string, it seems more useful to insert 'this' object,
  874         // allowing 'that' to change (via __Call) the behaviour of a "function-call" which operates on 'this'.
  875         // Consequently, if 'that[this]' contains a value, it is invoked; seems obscure but rare, and could
  876         // also be of use (for instance, as a means to remove the 'this' parameter or replace it with 'that').
  877         aParam[0] = &aThisToken;
  878         ResultType r = aField->object->Invoke(aResultToken, field_token, IT_CALL | IF_FUNCOBJ, aParam, aParamCount);
  879         aParam[0] = tmp;
  880         return r;
  881     }
  882     if (aField->symbol == SYM_OPERAND)
  883     {
  884         Func *func = g_script.FindFunc(aField->marker);
  885         if (func)
  886         {
  887             // At this point, aIdCount == 1 and aParamCount includes only the explicit parameters for the call.
  888             if (IS_INVOKE_META)
  889             {
  890                 ExprTokenType *tmp = aParam[0];
  891                 // Called indirectly by means of the meta-object mechanism (mBase); treat it as a "method call".
  892                 // For this type of call, "this" object is included as the first parameter.  To do this, aParam[0] is
  893                 // temporarily overwritten with a pointer to aThisToken.  Note that aThisToken contains the original
  894                 // object specified in script, not the real "this" which is actually a meta-object/base of that object.
  895                 aParam[0] = &aThisToken;
  896                 ResultType r = CallFunc(*func, aResultToken, aParam, aParamCount);
  897                 aParam[0] = tmp;
  898                 return r;
  899             }
  900             else
  901                 // This object directly contains a function name.  Assume this object is intended
  902                 // as a simple array of functions; do not pass aThisToken as is done above.
  903                 // aParam + 1 vs aParam because aParam[0] is the key which was used to find this field, not a parameter of the call.
  904                 return CallFunc(*func, aResultToken, aParam + 1, aParamCount - 1);
  905         }
  906     }
  907     return INVOKE_NOT_HANDLED;
  908 }
  909 
  910 
  911 //
  912 // Helper function for StringSplit()
  913 //
  914 
  915 bool Object::Append(LPTSTR aValue, size_t aValueLength)
  916 {
  917     if (mFieldCount == mFieldCountMax && !Expand()) // Attempt to expand if at capacity.
  918         return false;
  919 
  920     if (aValueLength == -1)
  921         aValueLength = _tcslen(aValue);
  922 
  923     FieldType &field = mFields[mKeyOffsetObject];
  924     if (mKeyOffsetObject < mFieldCount)
  925         // For maintainability. This might never be done, because our caller
  926         // doesn't use string/object keys. Move existing fields to make room:
  927         memmove(&field + 1, &field, (mFieldCount - mKeyOffsetObject) * sizeof(FieldType));
  928     ++mFieldCount; // Only after memmove above.
  929     ++mKeyOffsetObject;
  930     ++mKeyOffsetString;
  931 
  932     // The following relies on the fact that callers of this function ONLY use
  933     // this function, so the last integer key == the number of integer keys.
  934     field.key.i = mKeyOffsetObject;
  935 
  936     field.symbol = SYM_OPERAND;
  937     if (aValueLength) // i.e. a non-empty string was supplied.
  938     {
  939         ++aValueLength; // Convert length to size.
  940         if (field.marker = tmalloc(aValueLength))
  941         {
  942             tmemcpy(field.marker, aValue, aValueLength);
  943             field.marker[aValueLength-1] = '\0';
  944             field.size = aValueLength;
  945             return true;
  946         }
  947         // Otherwise, mem alloc failed; assign an empty string.
  948     }
  949     field.marker = Var::sEmptyString;
  950     field.size = 0;
  951     return (aValueLength == 0); // i.e. true if caller supplied an empty string.
  952 }
  953 
  954 
  955 //
  956 // Helper function used with class definitions.
  957 //
  958 
  959 void Object::EndClassDefinition()
  960 {
  961     // Instance variables were previously created as keys in the class object to prevent duplicate or
  962     // conflicting declarations.  Since these variables will be added at run-time to the derived objects,
  963     // we don't want them in the class object.  So delete any key-value pairs with the special marker
  964     // value (currently any integer, since static initializers haven't been evaluated yet).
  965     for (IndexType i = mFieldCount - 1; i >= 0; --i)
  966         if (mFields[i].symbol == SYM_INTEGER)
  967         {
  968             if (i >= mKeyOffsetString) // Must be checked since key can be an integer, such as for "0 := (expr)".
  969                 free(mFields[i].key.s);
  970             if (i < --mFieldCount)
  971                 memmove(mFields + i, mFields + i + 1, (mFieldCount - i) * sizeof(FieldType));
  972         }
  973 }
  974     
  975 
  976 //
  977 // Object::Type() - Returns the object's type/class name.
  978 //
  979 
  980 LPTSTR Object::Type()
  981 {
  982     IObject *ibase;
  983     Object *base;
  984     ExprTokenType value;
  985     if (GetItem(value, _T("__Class")))
  986         return _T("Class"); // This object is a class.
  987     for (ibase = mBase; base = dynamic_cast<Object *>(ibase); ibase = base->mBase)
  988         if (base->GetItem(value, _T("__Class")))
  989             return TokenToString(value); // This object is an instance of base.
  990     return _T("Object"); // This is an Object of undetermined type, like Object(), {} or [].
  991 }
  992 
  993     
  994 
  995 //
  996 // Object:: Built-in Methods
  997 //
  998 
  999 bool Object::InsertAt(INT_PTR aOffset, INT_PTR aKey, ExprTokenType *aValue[], int aValueCount)
 1000 {
 1001     IndexType actual_count = (IndexType)aValueCount;
 1002     for (int i = 0; i < aValueCount; ++i)
 1003         if (aValue[i]->symbol == SYM_MISSING)
 1004             actual_count--;
 1005     IndexType need_capacity = mFieldCount + actual_count;
 1006     if (need_capacity > mFieldCountMax && !SetInternalCapacity(need_capacity))
 1007         // Fail.
 1008         return false;
 1009     FieldType *field = mFields + aOffset;
 1010     if (aOffset < mFieldCount)
 1011         memmove(field + actual_count, field, (mFieldCount - aOffset) * sizeof(FieldType));
 1012     mFieldCount += actual_count;
 1013     mKeyOffsetObject += actual_count; // ints before objects
 1014     mKeyOffsetString += actual_count; // and strings
 1015     FieldType *field_end;
 1016     // Set keys and copy value params into the fields.
 1017     for (int i = 0; i < aValueCount; ++i, ++aKey)
 1018     {
 1019         ExprTokenType &value = *(aValue[i]);
 1020         if (value.symbol != SYM_MISSING)
 1021         {
 1022             field->key.i = aKey;
 1023             field->symbol = SYM_INTEGER; // Must be init'd for Assign().
 1024             field->Assign(value);
 1025             field++;
 1026         }
 1027     }
 1028     // Adjust keys of fields which have been moved.
 1029     for (field_end = mFields + mKeyOffsetObject; field < field_end; ++field)
 1030     {
 1031         field->key.i += aValueCount; // NOT =++key.i since keys might not be contiguous.
 1032     }
 1033     return true;
 1034 }
 1035 
 1036 ResultType Object::_Insert(ExprTokenType &aResultToken, ExprTokenType *aParam[], int aParamCount)
 1037 {
 1038     if (!aParamCount)
 1039         return OK;
 1040     ResultType result;
 1041     if (aParamCount == 1)
 1042         result = _Push(aResultToken, aParam, aParamCount);
 1043     else if (TokenIsPureNumeric(*aParam[0]) == PURE_INTEGER)
 1044         result = _InsertAt(aResultToken, aParam, aParamCount);
 1045     else
 1046         if (!SetItem(*aParam[0], *aParam[1]))
 1047             result = g_script.ScriptError(ERR_OUTOFMEM); // For consistency with Push/InsertAt.
 1048         else
 1049             result = OK;
 1050     // It seems best to always return true on success, for backward-compatibility.  An exception
 1051     // is thrown on out-of-memory instead of the old behaviour of returning an empty string, but
 1052     // that seems okay due to the rarity of out-of-memory or any scripts handling that condition.
 1053     if (result)
 1054     {
 1055         aResultToken.symbol = SYM_INTEGER;
 1056         aResultToken.value_int64 = 1;
 1057     }
 1058     return result;
 1059 }
 1060 
 1061 ResultType Object::_InsertAt(ExprTokenType &aResultToken, ExprTokenType *aParam[], int aParamCount)
 1062 // InsertAt(index, value1, ...)
 1063 {
 1064     if (aParamCount < 2)
 1065         return g_script.ScriptError(ERR_TOO_FEW_PARAMS);
 1066 
 1067     SymbolType key_type;
 1068     KeyType key;
 1069     IndexType insert_pos;
 1070     FieldType *field = FindField(**aParam, aResultToken.buf, /*out*/ key_type, /*out*/ key, /*out*/ insert_pos);
 1071     if (key_type != SYM_INTEGER)
 1072         return g_script.ScriptError(ERR_PARAM1_INVALID, key_type == SYM_STRING ? key.s : _T(""));
 1073         
 1074     if (field)
 1075     {
 1076         insert_pos = field - mFields; // insert_pos wasn't set in this case.
 1077         field = NULL; // Insert, don't overwrite.
 1078     }
 1079 
 1080     if (!InsertAt(insert_pos, key.i, aParam + 1, aParamCount - 1))
 1081         return g_script.ScriptError(ERR_OUTOFMEM);
 1082     
 1083     // Leave aResultToken at its default empty value.
 1084     return OK;
 1085 }
 1086 
 1087 ResultType Object::_Push(ExprTokenType &aResultToken, ExprTokenType *aParam[], int aParamCount)
 1088 // Push(value1, ...)
 1089 {
 1090     IndexType insert_pos = mKeyOffsetObject; // int keys end here.;
 1091     IntKeyType start_index = (insert_pos ? mFields[insert_pos - 1].key.i + 1 : 1);
 1092     if (!InsertAt(insert_pos, start_index, aParam, aParamCount))
 1093         return g_script.ScriptError(ERR_OUTOFMEM);
 1094 
 1095     // Return the new "length" of the array.
 1096     aResultToken.symbol = SYM_INTEGER;
 1097     aResultToken.value_int64 = start_index + aParamCount - 1;
 1098     return OK;
 1099 }
 1100 
 1101 ResultType Object::_Remove_impl(ExprTokenType &aResultToken, ExprTokenType *aParam[], int aParamCount, RemoveMode aMode)
 1102 // Remove(first_key [, last_key := first_key])
 1103 // RemoveAt(index [, virtual_count := 1])
 1104 // Pop()
 1105 {
 1106     FieldType *min_field;
 1107     IndexType min_pos, max_pos, pos;
 1108     SymbolType min_key_type;
 1109     KeyType min_key, max_key;
 1110     IntKeyType logical_count_removed = 1;
 1111 
 1112     // Find the position of "min".
 1113     if (!aParamCount) // Pop or invalid.
 1114     {
 1115         if (aMode != RM_Pop && aMode != RM_RemoveKeyOrIndex)
 1116             return g_script.ScriptError(ERR_TOO_FEW_PARAMS);
 1117 
 1118         if (mKeyOffsetObject) // i.e. at least one int field; use _MaxIndex()
 1119         {
 1120             min_field = &mFields[min_pos = mKeyOffsetObject - 1];
 1121             min_key = min_field->key;
 1122             min_key_type = SYM_INTEGER;
 1123         }
 1124         else // No appropriate field to remove, just return "".
 1125             return OK;
 1126     }
 1127     else
 1128     {
 1129         if (min_field = FindField(*aParam[0], aResultToken.buf, min_key_type, min_key, min_pos))
 1130             min_pos = min_field - mFields; // else min_pos was already set by FindField.
 1131         
 1132         if (min_key_type != SYM_INTEGER && aMode == RM_RemoveAt)
 1133             return g_script.ScriptError(ERR_PARAM1_INVALID);
 1134     }
 1135 
 1136     if (aMode == RM_RemoveKeyOrIndex && aParamCount > 1 && min_key_type == SYM_INTEGER && TokenIsEmptyString(*aParam[1]))
 1137     {
 1138         // Allow Remove(i,"") to mean "remove [i] but don't adjust keys".
 1139         aMode = RM_RemoveKey;
 1140         aParamCount = 1;
 1141     }
 1142     
 1143     if (aParamCount > 1) // Removing a range of keys.
 1144     {
 1145         SymbolType max_key_type;
 1146         FieldType *max_field;
 1147         if (aMode == RM_RemoveAt)
 1148         {
 1149             logical_count_removed = (IntKeyType)TokenToInt64(*aParam[1]);
 1150             // Find the next position >= [aParam[1] + Count].
 1151             max_key_type = SYM_INTEGER;
 1152             max_key.i = min_key.i + logical_count_removed;
 1153             if (max_field = FindField(max_key_type, max_key, max_pos))
 1154                 max_pos = max_field - mFields;
 1155         }
 1156         else
 1157         {
 1158             // Find the next position > [aParam[1]].
 1159             if (max_field = FindField(*aParam[1], aResultToken.buf, max_key_type, max_key, max_pos))
 1160                 max_pos = max_field - mFields + 1;
 1161         }
 1162         // Since the order of key-types in mFields is of no logical consequence, require that both keys be the same type.
 1163         // Do not allow removing a range of object keys since there is probably no meaning to their order.
 1164         if (max_key_type != min_key_type || max_key_type == SYM_OBJECT || max_pos < min_pos
 1165             // min and max are different types, are objects, or max < min.
 1166             || (max_pos == min_pos && (max_key_type == SYM_INTEGER ? max_key.i < min_key.i : _tcsicmp(max_key.s, min_key.s) < 0)))
 1167             // max < min, but no keys exist in that range so (max_pos < min_pos) check above didn't catch it.
 1168         {
 1169             return aMode == RM_RemoveKeyOrIndex ? OK // For backward-compatibility.
 1170                 : g_script.ScriptError(ERR_PARAM2_INVALID);
 1171         }
 1172         //else if (max_pos == min_pos): specified range is valid, but doesn't match any keys.
 1173         //  Continue on, adjust integer keys as necessary and return 0.
 1174     }
 1175     else // Removing a single item.
 1176     {
 1177         if (!min_field) // Nothing to remove.
 1178         {
 1179             if (aMode == RM_RemoveAt || (aMode == RM_RemoveKeyOrIndex && min_key_type == SYM_INTEGER))
 1180                 for (pos = min_pos; pos < mKeyOffsetObject; ++pos)
 1181                     mFields[pos].key.i--;
 1182             // Our return value when only one key is given is supposed to be the value
 1183             // previously at this[key], which has just been removed.  Since this[key]
 1184             // would return "", it makes sense to return an empty string in this case.
 1185             aResultToken.symbol = SYM_STRING;   
 1186             aResultToken.marker = _T("");
 1187             return OK;
 1188         }
 1189         // Since only one field (at maximum) can be removed in this mode, it
 1190         // seems more useful to return the field being removed than a count.
 1191         switch (aResultToken.symbol = min_field->symbol)
 1192         {
 1193         case SYM_OPERAND:
 1194             aResultToken.symbol = SYM_STRING;
 1195             if (min_field->size)
 1196             {
 1197                 // Detach the memory allocated for this field's string and pass it back to caller.
 1198                 aResultToken.mem_to_free = aResultToken.marker = min_field->marker;
 1199                 aResultToken.marker_length = _tcslen(aResultToken.marker); // NOT min_field->size, which is the allocation size.
 1200                 min_field->size = 0; // Prevent Free() from freeing min_field->marker.
 1201             }
 1202             //else aResultToken already contains an empty string.
 1203             break;
 1204         case SYM_OBJECT:
 1205             aResultToken.object = min_field->object;
 1206             min_field->symbol = SYM_INTEGER; // Prevent Free() from calling object->Release(), instead of calling AddRef().
 1207             break;
 1208         default:
 1209             aResultToken.value_int64 = min_field->n_int64; // Effectively also value_double = n_double.
 1210         }
 1211         // If the key is an object, release it now because Free() doesn't.
 1212         // Note that object keys can only be removed in the single-item mode.
 1213         if (min_key_type == SYM_OBJECT)
 1214             min_field->key.p->Release();
 1215         // Set these up as if caller did Remove(min_key, min_key):
 1216         max_pos = min_pos + 1;
 1217         max_key.i = min_key.i; // Union copy. Used only if min_key_type == SYM_INTEGER; has no effect in other cases.
 1218     }
 1219 
 1220     for (pos = min_pos; pos < max_pos; ++pos)
 1221         // Free each field in the range being removed.
 1222         mFields[pos].Free();
 1223 
 1224     if (min_key_type == SYM_STRING)
 1225         // Free all string keys in the range being removed.
 1226         for (pos = min_pos; pos < max_pos; ++pos)
 1227             free(mFields[pos].key.s);
 1228 
 1229     IndexType remaining_fields = mFieldCount - max_pos;
 1230     if (remaining_fields)
 1231         // Move remaining fields left to fill the gap left by the removed range.
 1232         memmove(mFields + min_pos, mFields + max_pos, remaining_fields * sizeof(FieldType));
 1233     // Adjust count by the actual number of fields in the removed range.
 1234     IndexType actual_count_removed = max_pos - min_pos;
 1235     mFieldCount -= actual_count_removed;
 1236     // Adjust key offsets and numeric keys as necessary.
 1237     if (min_key_type != SYM_STRING) // i.e. SYM_OBJECT or SYM_INTEGER
 1238     {
 1239         mKeyOffsetString -= actual_count_removed;
 1240         if (min_key_type == SYM_INTEGER)
 1241         {
 1242             mKeyOffsetObject -= actual_count_removed;
 1243             if (aMode == RM_RemoveAt || aMode == RM_RemoveKeyOrIndex)
 1244             {
 1245                 if (aMode == RM_RemoveKeyOrIndex) // In this case, logical_count_removed wasn't set.
 1246                     logical_count_removed = max_key.i - min_key.i + 1;
 1247                 // Regardless of whether any fields were removed, min_pos contains the position of the field which
 1248                 // immediately followed the specified range.  Decrement each numeric key from this position onward.
 1249                 if (logical_count_removed > 0)
 1250                     for (pos = min_pos; pos < mKeyOffsetObject; ++pos)
 1251                         mFields[pos].key.i -= logical_count_removed;
 1252             }
 1253         }
 1254     }
 1255     if (aParamCount > 1)
 1256     {
 1257         // Return actual number of fields removed:
 1258         aResultToken.symbol = SYM_INTEGER;
 1259         aResultToken.value_int64 = actual_count_removed;
 1260     }
 1261     //else result was set above.
 1262     return OK;
 1263 }
 1264 
 1265 ResultType Object::_Remove(ExprTokenType &aResultToken, ExprTokenType *aParam[], int aParamCount)
 1266 {
 1267     return _Remove_impl(aResultToken, aParam, aParamCount, RM_RemoveKeyOrIndex);
 1268 }
 1269 
 1270 ResultType Object::_Delete(ExprTokenType &aResultToken, ExprTokenType *aParam[], int aParamCount)
 1271 {
 1272     return _Remove_impl(aResultToken, aParam, aParamCount, RM_RemoveKey);
 1273 }
 1274 
 1275 ResultType Object::_RemoveAt(ExprTokenType &aResultToken, ExprTokenType *aParam[], int aParamCount)
 1276 {
 1277     return _Remove_impl(aResultToken, aParam, aParamCount, RM_RemoveAt);
 1278 }
 1279 
 1280 ResultType Object::_Pop(ExprTokenType &aResultToken, ExprTokenType *aParam[], int aParamCount)
 1281 {
 1282     // Unwanted parameters are ignored, as is conventional for dynamic calls.
 1283     // _Remove_impl relies on aParamCount == 0 for Pop().
 1284     return _Remove_impl(aResultToken, NULL, 0, RM_Pop);
 1285 }
 1286 
 1287 
 1288 ResultType Object::_MinIndex(ExprTokenType &aResultToken, ExprTokenType *aParam[], int aParamCount)
 1289 {
 1290     if (aParamCount)
 1291         return OK;
 1292 
 1293     if (mKeyOffsetObject) // i.e. there are fields with integer keys
 1294     {
 1295         aResultToken.symbol = SYM_INTEGER;
 1296         aResultToken.value_int64 = (__int64)mFields[0].key.i;
 1297     }
 1298     // else no integer keys; leave aResultToken at default, empty string.
 1299     return OK;
 1300 }
 1301 
 1302 ResultType Object::_Count(ExprTokenType &aResultToken, ExprTokenType *aParam[], int aParamCount)
 1303 {
 1304     aResultToken.SetValue((__int64)mFieldCount);
 1305     return OK;
 1306 }
 1307 
 1308 ResultType Object::_Length(ExprTokenType &aResultToken, ExprTokenType *aParam[], int aParamCount)
 1309 {
 1310     IntKeyType max_index = mKeyOffsetObject ? mFields[mKeyOffsetObject - 1].key.i : 0;
 1311     
 1312     aResultToken.symbol = SYM_INTEGER;
 1313     aResultToken.value_int64 = (__int64)(max_index > 0 ? max_index : 0);
 1314     return OK;
 1315 }
 1316 
 1317 ResultType Object::_MaxIndex(ExprTokenType &aResultToken, ExprTokenType *aParam[], int aParamCount)
 1318 {
 1319     if (aParamCount)
 1320         return OK;
 1321 
 1322     if (mKeyOffsetObject) // i.e. there are fields with integer keys
 1323     {
 1324         aResultToken.symbol = SYM_INTEGER;
 1325         aResultToken.value_int64 = (__int64)mFields[mKeyOffsetObject - 1].key.i;
 1326     }
 1327     // else no integer keys; leave aResultToken at default, empty string.
 1328     return OK;
 1329 }
 1330 
 1331 ResultType Object::_GetCapacity(ExprTokenType &aResultToken, ExprTokenType *aParam[], int aParamCount)
 1332 {
 1333     if (aParamCount == 1)
 1334     {
 1335         SymbolType key_type;
 1336         KeyType key;
 1337         IndexType insert_pos;
 1338         FieldType *field;
 1339 
 1340         if ( (field = FindField(*aParam[0], aResultToken.buf, /*out*/ key_type, /*out*/ key, /*out*/ insert_pos))
 1341             && field->symbol == SYM_OPERAND )
 1342         {
 1343             aResultToken.symbol = SYM_INTEGER;
 1344             aResultToken.value_int64 = field->size ? _TSIZE(field->size - 1) : 0; // -1 to exclude null-terminator.
 1345         }
 1346         // else wrong type of field; leave aResultToken at default, empty string.
 1347     }
 1348     else if (aParamCount == 0)
 1349     {
 1350         aResultToken.symbol = SYM_INTEGER;
 1351         aResultToken.value_int64 = mFieldCountMax;
 1352     }
 1353     return OK;
 1354 }
 1355 
 1356 ResultType Object::_SetCapacity(ExprTokenType &aResultToken, ExprTokenType *aParam[], int aParamCount)
 1357 // _SetCapacity( [field_name,] new_capacity )
 1358 {
 1359     if ((aParamCount != 1 && aParamCount != 2) || !TokenIsPureNumeric(*aParam[aParamCount - 1]))
 1360         // Invalid or missing param(s); return default empty string.
 1361         return OK;
 1362     __int64 desired_capacity = TokenToInt64(*aParam[aParamCount - 1], TRUE);
 1363     if (aParamCount == 2) // Field name was specified.
 1364     {
 1365         if (desired_capacity < 0) // Check before sign is dropped.
 1366             // Bad param.
 1367             return OK;
 1368         size_t desired_size = (size_t)desired_capacity;
 1369 
 1370         SymbolType key_type;
 1371         KeyType key;
 1372         IndexType insert_pos;
 1373         FieldType *field;
 1374         LPTSTR buf;
 1375 
 1376         if ( (field = FindField(*aParam[0], aResultToken.buf, /*out*/ key_type, /*out*/ key, /*out*/ insert_pos))
 1377             || (field = Insert(key_type, key, insert_pos)) )
 1378         {   
 1379             // Field was successfully found or inserted.
 1380             if (field->symbol != SYM_OPERAND)
 1381                 // Wrong type of field.
 1382                 return OK;
 1383             if (!desired_size)
 1384             {   // Caller specified zero - empty the field but do not remove it.
 1385                 field->Assign(NULL);
 1386                 aResultToken.symbol = SYM_INTEGER;
 1387                 aResultToken.value_int64 = 0;
 1388                 return OK;
 1389             }
 1390 #ifdef UNICODE
 1391             // Convert size in bytes to size in chars.
 1392             desired_size = (desired_size >> 1) + (desired_size & 1);
 1393 #endif
 1394             // Like VarSetCapacity, always reserve one char for the null-terminator.
 1395             ++desired_size;
 1396             // Unlike VarSetCapacity, allow fields to shrink; preserve existing data up to min(new size, old size).
 1397             // size is checked because if it is 0, marker is Var::sEmptyString which we can't pass to realloc.
 1398             if (buf = trealloc(field->size ? field->marker : NULL, desired_size))
 1399             {
 1400                 buf[desired_size - 1] = '\0'; // Terminate at the new end of data.
 1401                 field->marker = buf;
 1402                 field->size = desired_size;
 1403                 // Return new size, minus one char reserved for null-terminator.
 1404                 aResultToken.symbol = SYM_INTEGER;
 1405                 aResultToken.value_int64 = _TSIZE(desired_size - 1);
 1406             }
 1407             //else out of memory.
 1408         }
 1409         return OK;
 1410     }
 1411     IndexType desired_count = (IndexType)desired_capacity;
 1412     // else aParamCount == 1: set the capacity of this object.
 1413     if (desired_count < mFieldCount)
 1414     {   // It doesn't seem intuitive to allow _SetCapacity to truncate the fields array.
 1415         desired_count = mFieldCount;
 1416     }
 1417     if (!desired_count)
 1418     {   // Caller wants to shrink object to current contents but there aren't any, so free mFields.
 1419         if (mFields)
 1420         {
 1421             free(mFields);
 1422             mFields = NULL;
 1423             mFieldCountMax = 0;
 1424         }
 1425         //else mFieldCountMax should already be 0.
 1426         // Since mFieldCountMax and desired_size are both 0, below will return 0 and won't call SetInternalCapacity.
 1427     }
 1428     if (desired_count == mFieldCountMax || SetInternalCapacity(desired_count))
 1429     {
 1430         aResultToken.symbol = SYM_INTEGER;
 1431         aResultToken.value_int64 = mFieldCountMax;
 1432     }
 1433     return OK;
 1434 }
 1435 
 1436 ResultType Object::_GetAddress(ExprTokenType &aResultToken, ExprTokenType *aParam[], int aParamCount)
 1437 // _GetAddress( key )
 1438 {
 1439     if (aParamCount == 1)
 1440     {
 1441         SymbolType key_type;
 1442         KeyType key;
 1443         IndexType insert_pos;
 1444         FieldType *field;
 1445 
 1446         if ( (field = FindField(*aParam[0], aResultToken.buf, /*out*/ key_type, /*out*/ key, /*out*/ insert_pos))
 1447             && field->symbol == SYM_OPERAND && field->size )
 1448         {
 1449             aResultToken.symbol = SYM_INTEGER;
 1450             aResultToken.value_int64 = (__int64)field->marker;
 1451         }
 1452         // else field has no memory allocated; leave aResultToken at default, empty string.
 1453     }
 1454     return OK;
 1455 }
 1456 
 1457 ResultType Object::_NewEnum(ExprTokenType &aResultToken, ExprTokenType *aParam[], int aParamCount)
 1458 {
 1459     if (aParamCount == 0)
 1460     {
 1461         IObject *newenum;
 1462         if (newenum = new Enumerator(this))
 1463         {
 1464             aResultToken.symbol = SYM_OBJECT;
 1465             aResultToken.object = newenum;
 1466         }
 1467     }
 1468     return OK;
 1469 }
 1470 
 1471 ResultType Object::_HasKey(ExprTokenType &aResultToken, ExprTokenType *aParam[], int aParamCount)
 1472 {
 1473     if (aParamCount == 1)
 1474     {
 1475         SymbolType key_type;
 1476         KeyType key;
 1477         INT_PTR insert_pos;
 1478         FieldType *field = FindField(**aParam, aResultToken.buf, key_type, key, insert_pos);
 1479         aResultToken.symbol = SYM_INTEGER;
 1480         aResultToken.value_int64 = (field != NULL);
 1481     }
 1482     return OK;
 1483 }
 1484 
 1485 ResultType Object::_Clone(ExprTokenType &aResultToken, ExprTokenType *aParam[], int aParamCount)
 1486 {
 1487     if (aParamCount == 0)
 1488     {
 1489         Object *clone = Clone();
 1490         if (clone)
 1491         {
 1492             if (mBase)
 1493                 (clone->mBase = mBase)->AddRef();
 1494             aResultToken.object = clone;
 1495             aResultToken.symbol = SYM_OBJECT;
 1496         }
 1497     }
 1498     return OK;
 1499 }
 1500 
 1501 
 1502 //
 1503 // Object::FieldType
 1504 //
 1505 
 1506 bool Object::FieldType::Assign(LPTSTR str, size_t len, bool exact_size)
 1507 {
 1508     if (!str || !*str && (len == -1 || !len)) // If empty string or null pointer, free our contents.  Passing len >= 1 allows copying \0, so don't check *str in that case.  Ordered for short-circuit performance (len is usually -1).
 1509     {
 1510         Free();
 1511         symbol = SYM_OPERAND;
 1512         marker = Var::sEmptyString;
 1513         size = 0;
 1514         return true;
 1515     }
 1516     
 1517     if (len == -1)
 1518         len = _tcslen(str);
 1519 
 1520     if (symbol != SYM_OPERAND || len >= size)
 1521     {
 1522         Free(); // Free object or previous buffer (which was too small).
 1523         symbol = SYM_OPERAND;
 1524         size_t new_size = len + 1;
 1525         if (!exact_size)
 1526         {
 1527             // Use size calculations equivalent to Var:
 1528             if (new_size < 16) // v1.0.45.03: Added this new size to prevent all local variables in a recursive
 1529                 new_size = 16; // function from having a minimum size of MAX_PATH.  16 seems like a good size because it holds nearly any number.  It seems counterproductive to go too small because each malloc, no matter how small, could have around 40 bytes of overhead.
 1530             else if (new_size < MAX_PATH)
 1531                 new_size = MAX_PATH;  // An amount that will fit all standard filenames seems good.
 1532             else if (new_size < (160 * 1024)) // MAX_PATH to 160 KB or less -> 10% extra.
 1533                 new_size = (size_t)(new_size * 1.1);
 1534             else if (new_size < (1600 * 1024))  // 160 to 1600 KB -> 16 KB extra
 1535                 new_size += (16 * 1024);
 1536             else if (new_size < (6400 * 1024)) // 1600 to 6400 KB -> 1% extra
 1537                 new_size += (new_size / 100);
 1538             else  // 6400 KB or more: Cap the extra margin at some reasonable compromise of speed vs. mem usage: 64 KB
 1539                 new_size += (64 * 1024);
 1540         }
 1541         if ( !(marker = tmalloc(new_size)) )
 1542         {
 1543             marker = Var::sEmptyString;
 1544             size = 0;
 1545             return false; // See "Sanity check" above.
 1546         }
 1547         size = new_size;
 1548     }
 1549     // else we have a buffer with sufficient capacity already.
 1550 
 1551     tmemcpy(marker, str, len + 1); // +1 for null-terminator.
 1552     return true; // Success.
 1553 }
 1554 
 1555 bool Object::FieldType::Assign(ExprTokenType &aParam)
 1556 {
 1557     ExprTokenType temp, *val; // Seems more maintainable to use a copy; avoid any possible side-effects.
 1558     if (aParam.symbol == SYM_VAR)
 1559     {
 1560         // Primary reason for this check: If var has a cached binary integer, we want to use it and
 1561         // not the stringified copy of it.  It seems unlikely that scripts will depend on the string
 1562         // format of a literal number such as 0x123 or 00001, and even less likely for a number stored
 1563         // in an object (even implicitly via a variadic function).  If the value is eventually passed
 1564         // to a COM method call, it can be important that it is passed as VT_I4 and not VT_BSTR.
 1565         aParam.var->ToToken(temp);
 1566         val = &temp;
 1567     }
 1568     else
 1569         val = &aParam;
 1570 
 1571     switch (val->symbol)
 1572     {
 1573     case SYM_OPERAND:
 1574         if (val->buf)
 1575         {
 1576             // Store this integer literal as a pure integer.  See above for comments.
 1577             Free();
 1578             symbol = SYM_INTEGER;
 1579             n_int64 = *(__int64 *)val->buf;
 1580             break;
 1581         }
 1582         // FALL THROUGH to the next case.
 1583     case SYM_STRING:
 1584         return Assign(val->marker);
 1585     case SYM_INTEGER:
 1586     case SYM_FLOAT:
 1587         Free(); // Free string or object, if applicable.
 1588         symbol = val->symbol; // Either SYM_INTEGER or SYM_FLOAT.  Set symbol *after* calling Free().
 1589         n_int64 = val->value_int64; // Also handles value_double via union.
 1590         break;
 1591     case SYM_OBJECT:
 1592         Free(); // Free string or object, if applicable.
 1593         symbol = SYM_OBJECT; // Set symbol *after* calling Free().
 1594         object = val->object;
 1595         if (aParam.symbol != SYM_VAR)
 1596             object->AddRef();
 1597         // Otherwise, take ownership of the ref in temp.
 1598         break;
 1599     default:
 1600         ASSERT(FALSE);
 1601     }
 1602     return true;
 1603 }
 1604 
 1605 void Object::FieldType::Get(ExprTokenType &result)
 1606 {
 1607     result.symbol = symbol;
 1608     result.value_int64 = n_int64; // Union copy.
 1609     if (symbol == SYM_OBJECT)
 1610         object->AddRef();
 1611 }
 1612 
 1613 void Object::FieldType::Free()
 1614 // Only the value is freed, since keys only need to be freed when a field is removed
 1615 // entirely or the Object is being deleted.  See Object::Delete.
 1616 // CONTAINED VALUE WILL NOT BE VALID AFTER THIS FUNCTION RETURNS.
 1617 {
 1618     if (symbol == SYM_OPERAND) {
 1619         if (size)
 1620             free(marker);
 1621     } else if (symbol == SYM_OBJECT)
 1622         object->Release();
 1623 }
 1624 
 1625 
 1626 //
 1627 // Enumerator
 1628 //
 1629 
 1630 ResultType STDMETHODCALLTYPE EnumBase::Invoke(ExprTokenType &aResultToken, ExprTokenType &aThisToken, int aFlags, ExprTokenType *aParam[], int aParamCount)
 1631 {
 1632     if (IS_INVOKE_SET)
 1633         return INVOKE_NOT_HANDLED;
 1634 
 1635     if (IS_INVOKE_CALL)
 1636     {
 1637         if (aParamCount && !_tcsicmp(ParamIndexToString(0), _T("Next")))
 1638         {   // This is something like enum.Next(var); exclude "Next" so it is treated below as enum[var].
 1639             ++aParam; --aParamCount;
 1640         }
 1641         else
 1642             return INVOKE_NOT_HANDLED;
 1643     }
 1644     Var *var0 = ParamIndexToOptionalVar(0);
 1645     Var *var1 = ParamIndexToOptionalVar(1);
 1646     aResultToken.symbol = SYM_INTEGER;
 1647     aResultToken.value_int64 = Next(var0, var1);
 1648     return OK;
 1649 }
 1650 
 1651 int Object::Enumerator::Next(Var *aKey, Var *aVal)
 1652 {
 1653     if (++mOffset < mObject->mFieldCount)
 1654     {
 1655         FieldType &field = mObject->mFields[mOffset];
 1656         if (aKey)
 1657         {
 1658             if (mOffset < mObject->mKeyOffsetObject) // mKeyOffsetInt < mKeyOffsetObject
 1659                 aKey->Assign(field.key.i);
 1660             else if (mOffset < mObject->mKeyOffsetString) // mKeyOffsetObject < mKeyOffsetString
 1661                 aKey->Assign(field.key.p);
 1662             else // mKeyOffsetString < mFieldCount
 1663                 aKey->Assign(field.key.s);
 1664         }
 1665         if (aVal)
 1666         {
 1667             switch (field.symbol)
 1668             {
 1669             case SYM_OPERAND:   aVal->AssignString(field.marker);   break;
 1670             case SYM_INTEGER:   aVal->Assign(field.n_int64);            break;
 1671             case SYM_FLOAT:     aVal->Assign(field.n_double);       break;
 1672             case SYM_OBJECT:    aVal->Assign(field.object);         break;
 1673             }
 1674         }
 1675         return true;
 1676     }
 1677     return false;
 1678 }
 1679 
 1680     
 1681 
 1682 //
 1683 // Object:: Internal Methods
 1684 //
 1685 
 1686 template<typename T>
 1687 Object::FieldType *Object::FindField(T val, INT_PTR left, INT_PTR right, INT_PTR &insert_pos)
 1688 // Template used below.  left and right must be set by caller to the appropriate bounds within mFields.
 1689 {
 1690     INT_PTR mid, result;
 1691     while (left <= right)
 1692     {
 1693         mid = (left + right) / 2;
 1694         
 1695         FieldType &field = mFields[mid];
 1696         
 1697         result = field.CompareKey(val);
 1698         
 1699         if (result < 0)
 1700             right = mid - 1;
 1701         else if (result > 0)
 1702             left = mid + 1;
 1703         else
 1704             return &field;
 1705     }
 1706     insert_pos = left;
 1707     return NULL;
 1708 }
 1709 
 1710 Object::FieldType *Object::FindField(SymbolType key_type, KeyType key, IndexType &insert_pos)
 1711 // Searches for a field with the given key.  If found, a pointer to the field is returned.  Otherwise
 1712 // NULL is returned and insert_pos is set to the index a newly created field should be inserted at.
 1713 // key_type and key are output for creating a new field or removing an existing one correctly.
 1714 // left and right must indicate the appropriate section of mFields to search, based on key type.
 1715 {
 1716     IndexType left, right;
 1717 
 1718     if (key_type == SYM_STRING)
 1719     {
 1720         left = mKeyOffsetString;
 1721         right = mFieldCount - 1; // String keys are last in the mFields array.
 1722 
 1723         return FindField<LPTSTR>(key.s, left, right, insert_pos);
 1724     }
 1725     else // key_type == SYM_INTEGER || key_type == SYM_OBJECT
 1726     {
 1727         if (key_type == SYM_INTEGER)
 1728         {
 1729             left = mKeyOffsetInt;
 1730             right = mKeyOffsetObject - 1; // Int keys end where Object keys begin.
 1731         }
 1732         else
 1733         {
 1734             left = mKeyOffsetObject;
 1735             right = mKeyOffsetString - 1; // Object keys end where String keys begin.
 1736         }
 1737         // Both may be treated as integer since left/right exclude keys of an incorrect type:
 1738         return FindField<IntKeyType>(key.i, left, right, insert_pos);
 1739     }
 1740 }
 1741 
 1742 Object::FieldType *Object::FindField(ExprTokenType &key_token, LPTSTR aBuf, SymbolType &key_type, KeyType &key, IndexType &insert_pos)
 1743 // Searches for a field with the given key, where the key is a token passed from script.
 1744 {
 1745     if (TokenIsPureNumeric(key_token) == PURE_INTEGER)
 1746     {   // Treat all integer keys (even numeric strings) as pure integers for consistency and performance.
 1747         key.i = (IntKeyType)TokenToInt64(key_token, TRUE);
 1748         key_type = SYM_INTEGER;
 1749     }
 1750     else if (key.p = TokenToObject(key_token))
 1751     {   // SYM_OBJECT or SYM_VAR containing object.
 1752         key_type = SYM_OBJECT;
 1753     }
 1754     else
 1755     {   // SYM_STRING, SYM_FLOAT, SYM_OPERAND or SYM_VAR (all confirmed not to be an integer at this point).
 1756         key.s = TokenToString(key_token, aBuf); // L41: Pass aBuf to allow float->string conversion as documented (but not previously working).
 1757         key_type = SYM_STRING;
 1758     }
 1759     return FindField(key_type, key, insert_pos);
 1760 }
 1761     
 1762 bool Object::SetInternalCapacity(IndexType new_capacity)
 1763 // Expands mFields to the specified number if fields.
 1764 // Caller *must* ensure new_capacity >= 1 && new_capacity >= mFieldCount.
 1765 {
 1766     FieldType *new_fields = (FieldType *)realloc(mFields, new_capacity * sizeof(FieldType));
 1767     if (!new_fields)
 1768         return false;
 1769     mFields = new_fields;
 1770     mFieldCountMax = new_capacity;
 1771     return true;
 1772 }
 1773     
 1774 Object::FieldType *Object::Insert(SymbolType key_type, KeyType key, IndexType at)
 1775 // Inserts a single field with the given key at the given offset.
 1776 // Caller must ensure 'at' is the correct offset for this key.
 1777 {
 1778     if (mFieldCount == mFieldCountMax && !Expand()  // Attempt to expand if at capacity.
 1779         || key_type == SYM_STRING && !(key.s = _tcsdup(key.s)))  // Attempt to duplicate key-string.
 1780     {   // Out of memory.
 1781         return NULL;
 1782     }
 1783     // There is now definitely room in mFields for a new field.
 1784 
 1785     FieldType &field = mFields[at];
 1786     if (at < mFieldCount)
 1787         // Move existing fields to make room.
 1788         memmove(&field + 1, &field, (mFieldCount - at) * sizeof(FieldType));
 1789     ++mFieldCount; // Only after memmove above.
 1790     
 1791     // Update key-type offsets based on where and what was inserted; also update this key's ref count:
 1792     if (key_type != SYM_STRING)
 1793     {
 1794         // Must be either SYM_INTEGER or SYM_OBJECT, which both precede SYM_STRING.
 1795         ++mKeyOffsetString;
 1796 
 1797         if (key_type != SYM_OBJECT)
 1798             // Must be SYM_INTEGER, which precedes SYM_OBJECT.
 1799             ++mKeyOffsetObject;
 1800         else
 1801             key.p->AddRef();
 1802     }
 1803     
 1804     field.marker = _T(""); // Init for maintainability.
 1805     field.size = 0; // Init to ensure safe behaviour in Assign().
 1806     field.key = key; // Above has already copied string or called key.p->AddRef() as appropriate.
 1807     field.symbol = SYM_OPERAND;
 1808 
 1809     return &field;
 1810 }
 1811 
 1812 
 1813 //
 1814 // Property: Invoked when a derived object gets/sets the corresponding key.
 1815 //
 1816 
 1817 ResultType STDMETHODCALLTYPE Property::Invoke(ExprTokenType &aResultToken, ExprTokenType &aThisToken, int aFlags, ExprTokenType *aParam[], int aParamCount)
 1818 {
 1819     Func **member;
 1820 
 1821     if (aFlags & IF_FUNCOBJ)
 1822     {
 1823         // Use mGet even if IS_INVOKE_CALL, for symmetry:
 1824         //   obj.prop()         ; Get
 1825         //   obj.prop() := val  ; Set (translation is performed by the preparser).
 1826         member = IS_INVOKE_SET ? &mSet : &mGet;
 1827     }
 1828     else
 1829     {
 1830         if (!aParamCount)
 1831             return INVOKE_NOT_HANDLED;
 1832 
 1833         LPTSTR name = TokenToString(*aParam[0]);
 1834         
 1835         if (!_tcsicmp(name, _T("Get")))
 1836         {
 1837             member = &mGet;
 1838         }
 1839         else if (!_tcsicmp(name, _T("Set")))
 1840         {
 1841             member = &mSet;
 1842         }
 1843         else
 1844             return INVOKE_NOT_HANDLED;
 1845         // ALL CODE PATHS ABOVE MUST RETURN OR SET member.
 1846 
 1847         if (!IS_INVOKE_CALL)
 1848         {
 1849             if (IS_INVOKE_SET)
 1850             {
 1851                 if (aParamCount != 2)
 1852                     return OK;
 1853                 // Allow changing the GET/SET function, since it's simple and seems harmless.
 1854                 *member = TokenToFunc(*aParam[1]); // Can be NULL.
 1855                 --aParamCount;
 1856             }
 1857             if (*member && aParamCount == 1)
 1858             {
 1859                 aResultToken.symbol = SYM_OBJECT;
 1860                 aResultToken.object = *member;
 1861             }
 1862             return OK;
 1863         }
 1864         // Since above did not return, we're explicitly calling Get or Set.
 1865         ++aParam;      // Omit method name.
 1866         --aParamCount; // 
 1867     }
 1868     // Since above did not return, member must have been set to either &mGet or &mSet.
 1869     // However, their actual values might be NULL:
 1870     if (!*member)
 1871         return INVOKE_NOT_HANDLED;
 1872     return CallFunc(**member, aResultToken, aParam, aParamCount);
 1873 }
 1874 
 1875 
 1876 //
 1877 // Func: Script interface, accessible via "function reference".
 1878 //
 1879 
 1880 ResultType STDMETHODCALLTYPE Func::Invoke(ExprTokenType &aResultToken, ExprTokenType &aThisToken, int aFlags, ExprTokenType *aParam[], int aParamCount)
 1881 {
 1882     LPTSTR member;
 1883 
 1884     if (!aParamCount)
 1885         aFlags |= IF_FUNCOBJ;
 1886     else
 1887         member = TokenToString(*aParam[0]);
 1888 
 1889     if (!IS_INVOKE_CALL && !(aFlags & IF_FUNCOBJ))
 1890     {
 1891         if (IS_INVOKE_SET || aParamCount > 1)
 1892             return INVOKE_NOT_HANDLED;
 1893 
 1894         if (!_tcsicmp(member, _T("Name")))
 1895         {
 1896             aResultToken.symbol = SYM_STRING;
 1897             aResultToken.marker = mName;
 1898         }
 1899         else if (!_tcsicmp(member, _T("MinParams")))
 1900         {
 1901             aResultToken.symbol = SYM_INTEGER;
 1902             aResultToken.value_int64 = mMinParams;
 1903         }
 1904         else if (!_tcsicmp(member, _T("MaxParams")))
 1905         {
 1906             aResultToken.symbol = SYM_INTEGER;
 1907             aResultToken.value_int64 = mParamCount;
 1908         }
 1909         else if (!_tcsicmp(member, _T("IsBuiltIn")))
 1910         {
 1911             aResultToken.symbol = SYM_INTEGER;
 1912             aResultToken.value_int64 = mIsBuiltIn;
 1913         }
 1914         else if (!_tcsicmp(member, _T("IsVariadic")))
 1915         {
 1916             aResultToken.symbol = SYM_INTEGER;
 1917             aResultToken.value_int64 = mIsVariadic;
 1918         }
 1919         else
 1920             return INVOKE_NOT_HANDLED;
 1921 
 1922         return OK;
 1923     }
 1924     
 1925     if (  !(aFlags & IF_FUNCOBJ)  )
 1926     {
 1927         if (!_tcsicmp(member, _T("IsOptional")) && aParamCount <= 2)
 1928         {
 1929             if (aParamCount == 2)
 1930             {
 1931                 int param = (int)TokenToInt64(*aParam[1]); // One-based.
 1932                 if (param > 0 && (param <= mParamCount || mIsVariadic))
 1933                 {
 1934                     aResultToken.symbol = SYM_INTEGER;
 1935                     aResultToken.value_int64 = param > mMinParams;
 1936                 }
 1937             }
 1938             else
 1939             {
 1940                 aResultToken.symbol = SYM_INTEGER;
 1941                 aResultToken.value_int64 = mMinParams != mParamCount || mIsVariadic; // True if any params are optional.
 1942             }
 1943             return OK;
 1944         }
 1945         else if (!_tcsicmp(member, _T("IsByRef")) && aParamCount <= 2 && !mIsBuiltIn)
 1946         {
 1947             if (aParamCount == 2)
 1948             {
 1949                 int param = (int)TokenToInt64(*aParam[1]); // One-based.
 1950                 if (param > 0 && (param <= mParamCount || mIsVariadic))
 1951                 {
 1952                     aResultToken.symbol = SYM_INTEGER;
 1953                     aResultToken.value_int64 = param <= mParamCount && mParam[param-1].is_byref;
 1954                 }
 1955             }
 1956             else
 1957             {
 1958                 aResultToken.symbol = SYM_INTEGER;
 1959                 aResultToken.value_int64 = FALSE;
 1960                 for (int param = 0; param < mParamCount; ++param)
 1961                     if (mParam[param].is_byref)
 1962                     {
 1963                         aResultToken.value_int64 = TRUE;
 1964                         break;
 1965                     }
 1966             }
 1967             return OK;
 1968         }
 1969         else if (!_tcsicmp(member, _T("Bind")))
 1970         {
 1971             if (BoundFunc *bf = BoundFunc::Bind(this, aParam+1, aParamCount-1, IT_CALL | IF_FUNCOBJ))
 1972             {
 1973                 aResultToken.symbol = SYM_OBJECT;
 1974                 aResultToken.object = bf;
 1975                 return OK;
 1976             }
 1977             return g_script.ScriptError(ERR_OUTOFMEM);
 1978         }
 1979         if (_tcsicmp(member, _T("Call")) && !TokenIsEmptyString(*aParam[0]))
 1980             return INVOKE_NOT_HANDLED; // Reserved.
 1981         // Called explicitly by script, such as by "obj.funcref.()" or "x := obj.funcref, x.()"
 1982         // rather than implicitly, like "obj.funcref()".
 1983         ++aParam;       // Discard the "method name" parameter.
 1984         --aParamCount;  // 
 1985     }
 1986     return CallFunc(*this, aResultToken, aParam, aParamCount);
 1987 }
 1988 
 1989 
 1990 ResultType STDMETHODCALLTYPE BoundFunc::Invoke(ExprTokenType &aResultToken, ExprTokenType &aThisToken, int aFlags, ExprTokenType *aParam[], int aParamCount)
 1991 {
 1992     if (  !(aFlags & IF_FUNCOBJ) && aParamCount  )
 1993     {
 1994         // No methods/properties implemented yet, except Call().
 1995         if (!TokenIsEmptyString(*aParam[0]) && _tcsicmp(TokenToString(*aParam[0]), _T("Call")))
 1996             return INVOKE_NOT_HANDLED; // Reserved.
 1997         ++aParam;
 1998         --aParamCount;
 1999     }
 2000 
 2001     // Combine the bound parameters with the supplied parameters.
 2002     int bound_count = mParams->MaxIndex();
 2003     if (bound_count > 0)
 2004     {
 2005         ExprTokenType *token = (ExprTokenType *)_alloca(bound_count * sizeof(ExprTokenType));
 2006         ExprTokenType **param = (ExprTokenType **)_alloca((bound_count + aParamCount) * sizeof(ExprTokenType *));
 2007         mParams->ArrayToParams(token, param, bound_count, NULL, 0);
 2008         memcpy(param + bound_count, aParam, aParamCount * sizeof(ExprTokenType *));
 2009         aParam = param;
 2010         aParamCount += bound_count;
 2011     }
 2012 
 2013     ExprTokenType this_token;
 2014     this_token.symbol = SYM_OBJECT;
 2015     this_token.object = mFunc;
 2016 
 2017     // Call the function or object.
 2018     return mFunc->Invoke(aResultToken, this_token, mFlags, aParam, aParamCount);
 2019     //return CallFunc(*mFunc, aResultToken, params, param_count);
 2020 }
 2021 
 2022 BoundFunc *BoundFunc::Bind(IObject *aFunc, ExprTokenType **aParam, int aParamCount, int aFlags)
 2023 {
 2024     if (Object *params = Object::CreateArray(aParam, aParamCount))
 2025     {
 2026         if (BoundFunc *bf = new BoundFunc(aFunc, params, aFlags))
 2027         {
 2028             aFunc->AddRef();
 2029             // bf has taken over our reference to params.
 2030             return bf;
 2031         }
 2032         // malloc failure; release params and return.
 2033         params->Release();
 2034     }
 2035     return NULL;
 2036 }
 2037 
 2038 BoundFunc::~BoundFunc()
 2039 {
 2040     mFunc->Release();
 2041     mParams->Release();
 2042 }
 2043 
 2044 
 2045 ResultType STDMETHODCALLTYPE Label::Invoke(ExprTokenType &aResultToken, ExprTokenType &aThisToken, int aFlags, ExprTokenType *aParam[], int aParamCount)
 2046 {
 2047     // Labels are never returned to script, so no need to check flags or parameters.
 2048     return Execute();
 2049 }
 2050 
 2051 ResultType LabelPtr::ExecuteInNewThread(TCHAR *aNewThreadDesc, ExprTokenType *aParamValue, int aParamCount, INT_PTR *aRetVal) const
 2052 {
 2053     DEBUGGER_STACK_PUSH(aNewThreadDesc)
 2054     ResultType result = CallMethod(mObject, mObject, _T("call"), aParamValue, aParamCount, aRetVal); // Lower-case "call" for compatibility with JScript.
 2055     DEBUGGER_STACK_POP()
 2056     return result;
 2057 }
 2058 
 2059 
 2060 LabelPtr::CallableType LabelPtr::getType(IObject *aObject)
 2061 {
 2062     static const Func sFunc(NULL, false);
 2063     // Comparing [[vfptr]] produces smaller code and is perhaps 10% faster than dynamic_cast<>.
 2064     void *vfptr = *(void **)aObject;
 2065     if (vfptr == *(void **)g_script.mPlaceholderLabel)
 2066         return Callable_Label;
 2067     if (vfptr == *(void **)&sFunc)
 2068         return Callable_Func;
 2069     return Callable_Object;
 2070 }
 2071 
 2072 Line *LabelPtr::getJumpToLine(IObject *aObject)
 2073 {
 2074     switch (getType(aObject))
 2075     {
 2076     case Callable_Label: return ((Label *)aObject)->mJumpToLine;
 2077     case Callable_Func: return ((Func *)aObject)->mJumpToLine;
 2078     default: return NULL;
 2079     }
 2080 }
 2081 
 2082 bool LabelPtr::IsExemptFromSuspend() const
 2083 {
 2084     if (Line *line = getJumpToLine(mObject))
 2085         return line->IsExemptFromSuspend();
 2086     return false;
 2087 }
 2088 
 2089 ActionTypeType LabelPtr::TypeOfFirstLine() const
 2090 {
 2091     if (Line *line = getJumpToLine(mObject))
 2092         return line->mActionType;
 2093     return ACT_INVALID;
 2094 }
 2095 
 2096 LPTSTR LabelPtr::Name() const
 2097 {
 2098     switch (getType(mObject))
 2099     {
 2100     case Callable_Label: return ((Label *)mObject)->mName;
 2101     case Callable_Func: return ((Func *)mObject)->mName;
 2102     default: return _T("Object");
 2103     }
 2104 }
 2105 
 2106 
 2107 
 2108 ResultType MsgMonitorList::Call(ExprTokenType *aParamValue, int aParamCount, int aInitNewThreadIndex)
 2109 {
 2110     ResultType result = OK;
 2111     INT_PTR retval = 0;
 2112     
 2113     for (MsgMonitorInstance inst (*this); inst.index < inst.count; ++inst.index)
 2114     {
 2115         if (inst.index >= aInitNewThreadIndex) // Re-initialize the thread.
 2116             InitNewThread(0, true, false, ACT_INVALID);
 2117         
 2118         IObject *func = mMonitor[inst.index].func;
 2119 
 2120         if (!CallMethod(func, func, _T("call"), aParamValue, aParamCount, &retval))
 2121         {
 2122             result = FAIL; // Callback encountered an error.
 2123             break;
 2124         }
 2125         if (retval)
 2126         {
 2127             result = CONDITION_TRUE;
 2128             break;
 2129         }
 2130     }
 2131     return result;
 2132 }
 2133 
 2134 
 2135 
 2136 //
 2137 // MetaObject - Defines behaviour of object syntax when used on a non-object value.
 2138 //
 2139 
 2140 MetaObject g_MetaObject;
 2141 
 2142 LPTSTR Object::sMetaFuncName[] = { _T("__Get"), _T("__Set"), _T("__Call"), _T("__Delete"), _T("__New") };
 2143 
 2144 ResultType STDMETHODCALLTYPE MetaObject::Invoke(ExprTokenType &aResultToken, ExprTokenType &aThisToken, int aFlags, ExprTokenType *aParam[], int aParamCount)
 2145 {
 2146     // For something like base.Method() in a class-defined method:
 2147     // It seems more useful and intuitive for this special behaviour to take precedence over
 2148     // the default meta-functions, especially since "base" may become a reserved word in future.
 2149     if (aThisToken.symbol == SYM_VAR && !_tcsicmp(aThisToken.var->mName, _T("base"))
 2150         && !aThisToken.var->HasContents() // Since scripts are able to assign to it, may as well let them use the assigned value.
 2151         && g->CurrentFunc && g->CurrentFunc->mClass) // We're in a function defined within a class (i.e. a method).
 2152     {
 2153         if (IObject *this_class_base = g->CurrentFunc->mClass->Base())
 2154         {
 2155             ExprTokenType this_token;
 2156             this_token.symbol = SYM_VAR;
 2157             this_token.var = g->CurrentFunc->mParam[0].var;
 2158             ResultType result = this_class_base->Invoke(aResultToken, this_token, (aFlags & ~IF_METAFUNC) | IF_METAOBJ, aParam, aParamCount);
 2159             // Avoid returning INVOKE_NOT_HANDLED in this case so that our caller never
 2160             // shows an "uninitialized var" warning for base.Foo() in a class method.
 2161             if (result != INVOKE_NOT_HANDLED)
 2162                 return result;
 2163         }
 2164         return OK;
 2165     }
 2166 
 2167     // Allow script-defined meta-functions to override the default behaviour:
 2168     ResultType result = Object::Invoke(aResultToken, aThisToken, aFlags, aParam, aParamCount);
 2169     
 2170     if (result != INVOKE_NOT_HANDLED || !aParamCount)
 2171         return result;
 2172 
 2173     if (IS_INVOKE_CALL && TokenIsEmptyString(*aParam[0]))
 2174     {
 2175         // Support func_var.(params) as a means to call either a function or an object-function.
 2176         // This can be done fairly easily in script, but not in a way that supports ByRef;
 2177         // and as a default behaviour, it might be more appealing for func lib authors.
 2178         LPCTSTR func_name = TokenToString(aThisToken, aResultToken.buf);
 2179         Func *func = g_script.FindFunc(func_name, EXPR_TOKEN_LENGTH((&aThisToken), func_name));
 2180         if (func)
 2181             return CallFunc(*func, aResultToken, aParam + 1, aParamCount - 1);
 2182     }
 2183 
 2184     return result;
 2185 }
 2186 
 2187 
 2188 #ifdef CONFIG_DEBUGGER
 2189 
 2190 void ObjectBase::DebugWriteProperty(IDebugProperties *aDebugger, int aPage, int aPageSize, int aMaxDepth)
 2191 {
 2192     DebugCookie cookie;
 2193     aDebugger->BeginProperty(NULL, "object", 0, cookie);
 2194     //if (aPage == 0)
 2195     //{
 2196     //  // This is mostly a workaround for debugger clients which make it difficult to
 2197     //  // tell when a property contains an object with no child properties of its own:
 2198     //  aDebugger->WriteProperty("Note", _T("This object doesn't support debugging."));
 2199     //}
 2200     aDebugger->EndProperty(cookie);
 2201 }
 2202 
 2203 void Func::DebugWriteProperty(IDebugProperties *aDebugger, int aPage, int aPageSize, int aMaxDepth)
 2204 {
 2205     DebugCookie cookie;
 2206     aDebugger->BeginProperty(NULL, "object", 1, cookie);
 2207     if (aPage == 0)
 2208         aDebugger->WriteProperty("Name", ExprTokenType(mName));
 2209     aDebugger->EndProperty(cookie);
 2210 }
 2211 
 2212 #endif