Pack

(Engine-Level Function)

Description: Serializes an array of data or a set of parameters to the object parameter into a stream
Returns: Numeric
Usage: Script Only.
Function Groups: Advanced Module,  Stream and Socket
Related to: Unpack | BuffStream | TempFileStream
Format: Pack(Data, Start, End, StreamVarPtr, KeyDictionary)
Parameters:  
Data
Required. An object value, an array, or a structure. Contains the data or the object value of the module whose parameters are to be packed.
For example, if you have 5 numeric values to pack, you would allocate a 1-dimensional array, 5 elements in length. You would then assign the 5 numerics to this array's elements, and pass the array to this parameter. You would specify that you wish to pack from subscript 1 to 5. Refer to the example section for more information.
Start
Required. The starting array index (zero-based), or parameter number (one-based) of the data to pack.
End
Required. For arrays this is the last array index. For parameters, it is the parameter number of the data to pack. If packing a structure rather than an array, this must be the number of elements rather than the final index.
StreamVarPtr
Required. A pointer to a variable holding the stream into which the data will be packed. The variable can also hold Invalid - see Comments section for more details.
KeyDictionary

Optional. A dictionary that maps structure names to a number that will represent the structure in the packed stream. Within the dictionary, the key is the structure name and the value is the assigned number.

 

There is no requirement for the Pack KeyDictionary parameter and the Unpack MirrorKey parameter to have the same number of elements. All that is required is that the Unpack MirrorKey dictionary has all of the structures that are in that particular packed stream. If the KeyDictionary doesn’t have the structure that was packed, the returned data is a simple array rather than a structure.

If KeyDictionary is not used at all, structures packed using Pack() will also include additional data to allow UnPack to generate an equivalent structure. So use the KeyDictionary mechanism if you need to avoid the associated code bloat.

Comments: Pack() is recursive. If the values contain arrays, then those are packed and so on.

StreamVar must be a pointer to a variable, not simply the name of a variable that holds a stream. This is because the Pack function will create a new stream under certain circumstances and store the packed data in it.

If the variable that StreamVarPtr addresses contains a stream, then the data will be packed into that stream.
If the variable that StreamVarPtr addresses contains Invalid, Pack will create a new buffer stream, pack the data into it and store the new stream in the variable pointed at by StreamVarPtr.
If a buffer stream is supplied, or Pack creates a buffer stream, it will be replaced by a temporary file stream if the output stream exceeds 2Mb. This provides a balance between performance and memory use.
If a stream is provided, packing starts at the current stream position. After packing, the stream current position is left at the end of the packed data.
Only variables of numeric, text, or stream types will be packed. Arrays of those types, up to and including 3 dimensions, will also be packed.

Any illegal values are packed as Invalid. Further, the Pack function has been designed in such a way that multidimensional arrays that have not had a value assigned can be handled. After the stream is unpacked, the array elements are allocated, but are assigned Invalid.

Generally called in the form:

Pack(Self(), 1, NParm(Self()), &Stream);

This works because NParm(Self()) equals the highest index.

Example:

Pack(Self, 2, 2, &Stream);  { Pack only the second parameter }
Pack(Array, 1, 1, &Stream); { pack only the second array item }

Example: Multi-dimensional array

If you wish to pack 2 3-dimensional arrays, you would allocate a 1-dimensional array, 2 elements in length. You would then assign the 3-dimensional arrays to the 1-dimensional array elements, and then Pack the 1-dimensional array.

Array1D = New(2);
Array1D[0] = Array3D_1;
Array1D[1] = Array3D_2;
Pack(Array1D, 0, 1, &Stream);

Unpacking this is almost an identical operation:

Array1D = New(2);
UnPack(Array1D, 0, 1, Stream);
Array3D_1 = Array1D[0];
Array3D_2 = Array1D[1];

All you need to know is how many things you wish to pack and unpack, not the sizes or types of the things (a ValueType(Array1D[0]) will tell you the type). As the stream position is moved after each pack or unpack, you can simply unpack one item at a time and check the return value of UnPack.

Example: KeyDictionary

In this example, the presence of a Key parameter allows the example to be packed into a stream that is less than half the size that would be obtained without the Key parameter. (Exact number depending on the names used in the structure definitions.)

"Record", "Values", and "AA_Info" are all STRUCTs.

Rec = Record( GetGUID(1)             { GUID       },
              1                      { Priority   },
              Values(87, 54, "feet") { Values     },
              System.MakeDictionary("AA", 
                             AA_Info("AAData1", 2)) { Extensions });

{ Omitted: Place record in ArrayToPack }

Key = System.MakeDictionary("Record", 0,
                             "Values", 1,
                             "AA_Info", "AA")

Pack(ArrayToPack, 0, 0, &PackStream, Key);

{ Omitted: Rewind stream }

MirrorKey = System.MakeDictionary("0", Record,
                                   "1", Values,
                                   "AA", AA_Info));

UnPack(UnpackedArray, 0, 0, PackStream, Invalid, Invalid, MirrorKey);