Let us examine a real use of a data object. This example is the code behind the StorePersistentField and PersistentField methods. These methods are generic inter-frame data methods that allow a decoder writer to save a field value from frame to frame.
DECODER_STATIC Persist_
// Declare the class just like in C++
private:
int64 m_i64Value;
int m_iSize;
bool m_bIsSet;
public:
void Set( int64 i64Value, int iSize)
{
m_i64Value = i64Value;
m_iSize = iSize;
m_bIsSet = true;
};
bool Get( int64& i64FieldValue, int& iSize) const
{
// be sure the object is initialized
ASSERT((m_bIsSet == false) || (m_bIsSet == true));
i64FieldValue = m_i64Value;
iSize = m_iSize;
return m_bIsSet;
};
void Clear()
{
_Reset();
}
@CTOR
// Nothing has to be initialized here, so this section can be
// omitted. This is for initializing one-time items. The RESET
// section will be called right after the initialization.
@DTOR
// This is for freeing memory that we've allocated. In this case,
// there is nothing to free, so this section can be omitted.
@PUT_DATA_INTO_A_BYTE_ARRAY
// If the data needs to be remembered for new frames, then we
// need a way to save and restore it to the FRM file. This
// section saves the class as a BYTE array that can be streamed
// to the FRM file. It is important to keep the size of the array
// to the smallest needed, to keep the size of the FRM file down.
//
// If this section is omitted, then the RESET section will be
// called at the beginning of each frame.
//
// abStatic is to be filled in
if (m_bIsSet)
{
int iSize = (m_iSize+7)/8 + 1;
abStatic.SetSize(iSize);
BYTE* pb = abStatic.GetData();
*pb++ = (BYTE)m_iSize;
memcpy(pb, (BYTE*)&m_i64Value, iSize-1);
}
else
abStatic.RemoveAll();
@GET_DATA_FROM_A_BYTE_ARRAY
// This is the complement of the above section. It takes the BYTE
// stream and turns it back into the class data.
//
//abStatic contains the static
m_bIsSet = true;
const BYTE* pb = abStatic.GetData();
m_iSize = *pb++;
m_i64Value = 0;
int iSize = (m_iSize+7)/8 + 1;
memcpy((BYTE*)&m_i64Value, pb, iSize-1);
@RESET
// This is called right after the object is constructed, and
// through various other events. It should set the object to a
// known state.
m_i64Value = -1;
m_iSize = 0;
m_bIsSet = false;
@END_STATIC
Here is the method that uses this Decoder Data Object:
RETRIEVING_DATA
METHOD StorePersistentField_USES_STATIC Persist_
/*
Saves the value of the current field in the data object specified. The item after the method name must be the name of the data object in which the field is to be stored.
Data is retrieved using the PersistentField_method.
*/
CODE
pStatic->Set(i64CurrentField, isizbitCurrentField);
ENDCODE
RETRIEVING_DATA
METHOD PersistentField_USES_STATIC Persist_
/*
Retrieves a field stored previously by a StorePersistentField method.
When using this method, the first item after the method name must be the name of the data object in which the field was stored.
*/
CODE
if (!pStatic->Get(i64FieldValue, iFieldSize))
throw CFdFieldException("Data not present (The field that the data comes from was not encountered.)");
ENDCODE
In one decoder, declare a field like this --
FIELD code (Fixed 1) RETRIEVE (StorePersistentField KeepThisCode) (Decimal) "Code"
In another decoder, or in a different path in the same decoder, declare a field like this --
FIELD retrieved_code (Fixed 0 bits) RETRIEVE (PersistentField KeepThisCode) (Hex) "Retrieved Code"