The optional Store Clause allows you to copy the current field value into what is essentially a variable. The format is:
STORE variable_name [<Retrieve-Clause>]
Syntactically a variable name is the same as a field name. In fact, a variable is implemented as a special kind of field, a field that just has a value and a size. (Note that a proper field also has an offset associated with it, along with formatting options.) Like most data-holding entities, a variable holds a 64-bit value which, of course, means that you can only STORE the value for a field that is 64 bits or less.
A variable is defined by its use. In other words, you create a variable by writing its name in a Store Clause - and that is the only way to create one. You use a variable just as you would use a field - by passing its name as a parameter to a suitable method. Here is an example:
FIELD string (FromField Bytes my_variable) (StringOfAscii) "String"
Here we have a field that contains a character string of variable length. The Size Method FromField indicates that the length of the field, in bytes, is the value of the field called my_variable, which is really a variable. Now you may well ask, why is a variable needed here? Surely you can pick up the length of the string directly from the field that defines it? The answer is best given by an example. Suppose that the string may be very, very long. And that its length may be defined by a one-byte or a two-byte field depending on what it takes, as in:
FIELD s1_or_2 (Fixed 1 Bit) (Binary) SUPPRESS_DETAIL
FIELD len_1 (Fixed 1 Byte) IF (FieldIs EqualTo s1_or_2 0) (Decimal) "Length of string" STORE string_ length
FIELD len_2 (Fixed 1 Word) IF (FieldIs EqualTo s1_or_2 1) (Decimal) "Length of string" STORE
string_length
FIELD string (FromField Bytes string_length) (StringOfAscii) "String"
This DecoderScript fragment decodes three successive fields. The first field is a single bit that indicates whether the next field, which contains the length of the character string, is a byte (0) or a word (1). The IF clauses on the next two statements ensure that the next field is decoded appropriately and that the correct length of the string is stored into the variable string_length. The final statement then decodes the string itself.
Now you might possibly wonder why you could not code this sequence as:
FIELD s1_or_2 (Fixed 1 Bit) (Binary) SUPPRESS_DETAIL
FIELD string_length (Fixed 1 Byte) IF (FieldIs EqualTo s1_or_2 0) (Decimal) "Length of string"
FIELD string_length (Fixed 2 Bytes) IF (FieldIs EqualTo s1_or_2 1) (Decimal) "Length of string"
FIELD string (FromField Bytes string_length) (StringOfAscii) "String"
This bypasses the variable and would simply decode a field called string_length as a one- or two-byte value as appropriate. If it worked that is. In practice, it fails because the string_length field has two definitions and that is forbidden. The only solution is to use a variable and this is exactly the type of thing that variables are intended for.
The optional Retrieve Clause within the Store Clause allows you to perform some transformations on the field value prior to storing it in the variable. For example, assume you have a 2 bit field. The value of the field indicates the length of the data according to the following table:
Data Length for Field Values
|
Value |
Length |
|
0 |
1 byte |
|
1 |
2 bytes |
|
2 |
4 bytes |
|
3 |
8 bytes |
You need to decode the field and somehow get the right value in the something called "length" so you can use it later. You could do a bunch of IF tests and then store each field into a variable called "length" or you could use a nifty method called ReplaceWithExtraData, which replaces the value in the field with the extra data from a table. Here's the table and decoder you could use:
TABLE length_table
{ 0 "" "1 byte" 1}
{ 1 "" "2 bytes" 2}
{ 2 "" "4 bytes" 4}
{ 3 "" "8 bytes" 8}
ENDTABLE
FIELD length_index (Fixed 2 Bits) (Table length_table) "Length" STORE length RETRIEVE (ReplaceWithExtraData length_table)
The lifetime of a variable is from the first encounter with it through the end of the decoding of a layer. This is what programmers call its scope. This means that, if you are careless, you can use a variable before setting it. Should you do so, no error will occur, but the value obtained will be garbage. Note that you cannot use variables to pass data to the decoder for another layer nor to a future instance of your own decoder (that is effectively to the decoding of a subsequent frame). Instead you must use what we call a Decoder Data Object.