Studio:AutoScript Dynamic Objects
The Dynamic Object Model
The ascript object supports a rich dynamic property model for functions and messages. The dynamic property model depends on the database loaded when the ascript object is initialized.
All dynamic properties are rooted at the following, which are themselves dynamic properties:
These objects are collectively referred to as Dynamic Payload Objects and share a number of common traits as explained in the next section.
Dynamic Payload Objects
A dynamic payload object is used to represent values that are either to be passed as part of a function call/return or message send/receive. The property names, types and values depend on the SCL that was used to describe the interface payload.
Although represented as a variant, each property has an underlying C language type. The types are represented internally according to the host platform, and are unaffected by target platform. The underlying types below are referred to as the ”r;standard set”:
- C language struct. The struct may be ”r;synthesized” under certain conditions. For example a C language struct is synthesized to represent function parameter lists.
- C language union.
- integer scalar types represented as 32 bits or less (char, unsigned char, short, unsigned short, int, unsigned int, long, unsigned long)
- integer scalar types represented as 64 bits. (long long, unsigned long long)
- floating point types float, double, long double
- enumerated type or enumerated-like types synthesized by scl_values()
- pointer to void or unqualified pointer to function (treated as void*) or pointer to incomplete type that is never completed (also treated as void*)
- qualified pointer to function (qualified by scl_fptr_anonymous() or scl_fptr_named())
- Array qualified as string
- qualified single pointer. Qualified as either IN, OUT, INOUT, RETURN or INRETURN
- qualified single pointer and string. Qualified as string and IN, OUT, INOUT, RETURN or INRETURN
- qualified fixed sized pointer. Qualifed as either IN, OUT, INOUT, RETURN or INRETURN
- qualified variable sized pointer. Qualified as either IN, OUT, INOUT, RETURN or INRETURN
- Array of any of the aforementioned types.
Default values are applied to all fields within a dynamic payload when the ascript object is initialized. The default value for all property types of all values is 0; this includes pointed-to values. The default Null state of pointers is non-Null.
The following sections detail the semantics of each of these types:
Enumerated or enumerated-like types
Bulk unstructured data transfer
C language struct
When the underlying type is a struct, the variant value for the property is an IDispatch object containing one or more named properties. Each named property represents a member of the structure. The property types can be any of the standard set already defined.
C language union
When the underlying type is a union, the variant value for the property is an IDispatch object containing one or more named properties. Each named property represents a member of the union. The property types can be any of the standard set already defined. The script semantics for setting or retrieving the values of the union member do not depend on whether the union is discriminated, or has a fixed active member. Any and all union members may be accessed at any time and they are all treated as independent values — i.e., setting the value of one union member does not overwrite the value of other union members, as in C. In this respect, unions behave like structs.
Note that upon a call or receipt of a call, only the value of the currently active member is transmitted between agents. The values of other members are not communicated to the receiving agent.
Small integer scalar types
Small integer or scalar types are fields whose underlying C type is signed or unsigned versions of char, short, int or long. Versions of char are represented as 8-bit quantities, short as 16-bit quantities, and int and long as 32-bit quantities.
Attempts to set values whose magnitude will not fit in the underlying representation are met by throwing an exception.
Attempts to read the respective values will always yield a value whose magnitude ”r;fits”.
Large integer scalar types
The types long long and unsigned long long are represented by an object whose underlying type is a synthesized structure. The structure for long long is:
struct LongLong { int upper int lower };
The structure synthesized for unsigned long long is:
struct LongLong { unsigned int upper; int lower; };
The value is manipulated by setting (or retrieving) the 64-bit quantity in two 32-bit parts.
Floating point types
The type float is represented as a 4-byte IEEE floating point number. The type double and long double are represented as an 8-byte IEEE floating point number.
Enumerated (or enumerated-like) types
Enumerated and enumerated-like properties stem from fields that were defined to be of some C language enumerated type or were of a small integer scalar type that had scl_values() applied. For the purposes of the rest of this section, we refer to both as enumerated types.
Given a field whose underlying type is an enumerated type, its value can be successfully set in the following ways:
Set an in-range value of the field using the symbolic (string) name of one of the enumerated value pairs.
Set an in-range value of the field using the numeric value of one of the enumerated value pairs.
Set an out-of-range value in the field using a numeric value that does not correspond to one of the enumerated value pairs. The value is out-of-range in the sense that it does not correspond to any of the enumeration constants, but the value's magnitude must still be representable within the bit size of the underlying field, or a out-of-range exception will be thrown.
Given a field whose underlying type is an enumerated type, retrieval of its value will return the enumerated type's symbolic name if the present value is in-range. The retrieval will return an out-of-range integer value if the current value is out of range.
The ascript object always initializes enumerated values to be 0, even when 0 is out of range.
Pointers
Pointer to void
Any property is treated as pointer to void if its underlying C type is pointer to void, unqualified pointer to function, or pointer to incomplete type that is never completed. Pointer to void is treated as if the underlying type was int.
Arrays
Properties that correspond to an array type are represented as indexed properties. If the underlying element type of and array type is another array type (such as a multi-dimensional array), the property will have two indexes. In general, the property will have n indexes for an n-dimensional array.
All indexes of an array element read or write operation are validated to verify that they are within the bounds of the array. A runtime exception is thrown if the verification fails or if the incorrect number of indexes are given. (All indexes must be specified.)
Array qualified as string
A C language field whose type is a pointer to signed char, unsigned char, signed short, or unsigned short, may be qualified as a string. Qualification as a string means the array is not treated as an indexable array but rather as a string.
A set operation with a source string that has too many characters will cause and out-of-range exception.
Expressing pointers in a scripting environment
Expressing C language pointer operations in scripting languages is difficult. Generally speaking, the concept of dynamic memory is hidden in scripting environments to simplify the scripting.
Pointer auto-dereferencing
Pointers that occur in payloads are expressed in a specialized way — the pointer representations are moved "out of band" to synthesized objects, and the pointer is automatically dereferenced so that it represents the pointed-to value. This is known as pointer auto-dereferencing.
For example, given the interface
void f(int** ppInt);
the following members are available on the function’s ParameterList object:
Member Name (relative to ParameterList) |
Member Representation | Member Type |
ppInt | Value ultimately pointed to | int Value of **ppInt |
ppInt_Ptr.IsNull | Property that gets/sets pointer's NULL state | bool Controls ppInt |
ppInt_Ptr.Child | Property that provides access to a synthesized object that represents the child (pointed-to) pointer | PointerNuller object Represents *ppInt |
ppInt_Ptr.Child.IsNull | Property that gets/sets the child pointer's NULL state | bool Controls **ppInt |
For every synthesized PointerNuller object, the default value of IsNull is False, so to construct the desired example payload, only *ppInt needs to be Null. (By default, ppInt is non-Null.) The following JScript example demonstrates this:
// get the user function instance
var f = ascript.Functions.Item("f").User;
// access *ppInt and set it to NULL
f.ParameterList.ppInt_Ptr.Child.IsNull = true;
To continue with this example, upon return from the function, we want to test the value of **ppInt against an expected value. (Assume that **ppInt has been qualified as INOUT.) In JScript, retrieving the value after the call would look like this:
// get the user function instance
var f = ascript.Functions.Item("f").User;
// get the value of **ppInt (value that **ppInt ultimately points to)
var intValue = f.ParameterList.ppInt;
if (intValue != 5)
{
// raise error
}
// ... etc
Name collision resolution
This mechanism used for testing and setting pointer Null values requires the creation of an object named <pointer>_Ptr that may potentially name-collide with user-defined objects. If there is a collision, then additional '_’ characters are added until the name becomes unique. The synthesized name for the PointerNuller object can then be more completely specified as:
<pointer_name>_nPtr where n is 1 unless there is a collision with a user-defined object name. If the case of a collision, increment n by 1 (i.e., the number of underscores) until there is no collision.
Every qualified pointer takes on a direction of IN, OUT, INOUT, RETURN or INRETURN.
- Qualified pointers (and their descendants) with a direction of IN appear in all ParameterList objects in Functions and Command objects in Messages. The sibling Null properties also appear in the ParameterList and Command objects.
- Qualified pointers (and their descendants) with direction of INOUT appear in all ParameterList and OutPointer Objects. The sibling Null properties appear in all ParameterList and OutPointer objects. Messages cannot have pointers with direction of INOUT.
- Qualified pointers (and their descendants) with direction of OUT appear in all OutPointer objects. The sibling Null properties appear in all ParameterList objects. Message cannot have pointers with a direction of OUT.
- Qualified pointers (and their descendants) with direction of RETURN appear either in OutPointer or Response objects, depending on whether they are part of a parameter or the return value of a function. The sibling Null properties will appear in the same objects as the pointer. In messages, such pointers can only appear in Response objects.
- Qualified pointers (and their descendants) with direction of INRETURN appear in all Parameter list and OutPointer objects. The sibling Null properties will appear in all the same objects as the pointer. Messages cannot have INRETURN pointers.
Qualified single pointer
A qualified single pointer is a property that corresponds to a C language pointer type that has been qualified (either explicitly or implicitly) to point to a single object instance, rather than a sequence.
Pointer qualified as string
A C language field whose type is a pointer to signed char, unsigned char, signed short, or unsigned short, may be qualified as a string. The qualification includes a pointer direction along with a maximum size. When qualified in this manner, the property is treated as both a string as well as a pointer.
A set operation with a source string that has too many characters will cause an out-of-range exception.
Qualified fixed-size pointer
A qualified fixed-size pointer is treated as an indexed property, exactly as if the pointer had been an array.
As a result, the scripting syntax for reading/writing an element of a two-dimensional array and a pointed-to element stemming from an array of fixed-size pointers is identical.
Qualified variable-size pointer
A qualified variable-size pointer is treated as an indexed property, exactly as if the pointer had been an array with one additional constraint. The index corresponding to the sized pointer is validated on every read/write to ensure that is within the range dictated by the current value of the size field.
Preservation of pointed-to values beyond the current size If the pointed-to value at position i of a sized pointer is assigned a value and the size field is subsequently set to size < i, the pointed-to value at position i becomes inaccessible. However, it is preserved so that if the size field is changed so that size > i, the previously assigned value is available.
Bulk unstructured data transfer
To provide high performance access to data in an array, special virtual bulk transfer members are dynamically added to function payload fields (i.e. fields that are members of a ParameterList, ReturnValue, or OutPointers payload) that meet the following criteria:
1. The payload item is one of the following:
- a sized pointer
- an n-dimensional array
- a conformant array
- an n-level plain pointer to such.
2. The element type or pointed-to type is one of the following:
- unsigned or signed char
- unsigned or signed short
- unsigned or signed int
- unsigned or signed long
- unsigned or signed long long
- float, double, or long double
- void* (includes those items treated as void* by STRIDE by virtue of scl_ptr_opaque(), scl_cast(), unconstrained pointer to function type or incomplete type)
- or a typedef name for such.
For any field in a User or Owner function payload where the above criteria are met, the following read/write properties are synthesized and exposed:
- HexString: a hex encoding of the binary value consisting of the pointed-to block or array
- B64String: a Base 64 encoding of the binary value consisting of the pointed-to block or array
- SafeArray: a Win32 SafeArray representation of the pointed-to block or array
- The HexString, B64String and SafeArray propeties are all based on the host datatype sizes and byte ordering (host characteristics) and are independent of the target datatype sizes and byte ordering (target characteristics).
HexString Property
The HexString property’s type is String. Its value is a hex encoding of the data item’s value.
The length of the data item’s value is defined to be one of the following:
- the complete length of the array if the data item is an array. If the array has more than one dimension, all dimension are considered as part of the length.
- the fixed size of the block that is pointed to if the data item is a fixed-size pointer
- the current size of the block pointed to by the data item if it is a variable sized pointer. The current size is determined by the value of the count field. If the current size of the count field is larger than the maximum size, the maximum size is used. If the current size is negative, 0 is used.
- the current size of the conformant array as indicated by the size field. Out-of-range count field is treated the same as sized pointers.
Retrieval of the HexString property will yield a string with a predictable length – it is exactly two times the number of bytes comprising the data item’s value.
In the case of arrays with more than one dimension, the data is arranged in row major order, the same as the ANSI C Language representation of arrays.
On the host (Win32) platform all binary numbers are represented in Little Endian format. This is also true of the hex encoded string representation.
Setting the HexString property will yield a runtime exception if the length of the source string does not exactly match the value’s length as described above.
Retrieval of the HexString property will yield a string whose characters are composed from the set ’r;0’ thru ’r;9’ and ’r;A’ thru ’r;F’.
The string used to set a HexString property must be composed of the characters from the set ’r;0’ thru ’r;9’, ’r;a’ thru ’r;f’ and ’r;A’ thru ’r;F’ or a runtime exception will be thrown.
B64String Property
The B64String property is of type String and represents a Base 64 encoding as described by RFC 2045 (http://www.ietf.org/rfc/rfc2045.txt). The encoding is based on the entire length of the data item’s value which is:
- the complete length of the array if the data item is an array. If the array has more than one dimension, all dimensions are considered as part of the length.
- the fixed size of the block that is pointed to if the data item is a fixed size pointer
- the current size of the block pointed to by the data item if it is variable sized pointer. The current size is determined by the value of the count field. If the currrent size of the count field is larger than the maximum size, the maximum size is used. If the current size is negative, 0 is used.
- the current size of the conformant array as indicated by the size field. Out of range count field is treated the same as sized pointers.
Retrieval of the string using the B64String property will yield a string with a predictable length based on the rules set forth in RFC 2045.
In the case of arrays with more than one dimension, the data is arranged in row major order, the same as the ANSI C Language representation of arrays.
On the host (Win32) platform all binary numbers are represented in Little Endian format. This is also true for the Base 64 encoding.
Setting the B64String property will yield a runtime exception if the length of the source string does not exactly match the Base 64 encoding of the value’s length. The calculation of the value’s length is described above.
Retrieval of the B64String property will yield a string whose character set is described in RFC 2045.
The string used to set a B64String property must be composed of the character set described by RFC 2045.
SafeArray Property
The SafeArray property yields a Win32 SAFEARRAY representation of the data item’s value. In the case the data item is an array, the SAFEARRAY representation exactly corresponds to the array. In the case the data item is a fixed sized pointer, the SAFEARRAY represents contains a number of elements that exactly matches the fixed size of the pointer. In the case the data item is a variable sized pointer, then the SAFEARRAY contains exactly the number of elements as indicated by the current value of the count field.
Retrieval of the SafeArray property will yield a SAFEARRAY with a one dimension and a predictable number of elements as set forth above (e.g., multi-dimensional arrays are expressed as a one-dimensional SAFEARRAY in row-major order).
Setting the SafeArray property will yield a runtime exception if the number of elements in the source SAFEARRAY does not match that set forth above, or if the source SAFEARRAY has more than one dimension.