| 
                   | 
               
                  
                   | 
            |
An application often needs to convert data from a resource defined as an array of structs. The example code here shows how this can be done.
The following code fragment defines a simple struct that forms an element of the resource array.
// for defining a single data resource
STRUCT DATA
    {
    WORD      wrd=16;
    WORD      flags=0;
    LONG      lng;
    BYTE      byt; 
    DOUBLE    dbl=0.0;
    LTEXT     ltxt;        // variable length
    }
The resource itself is defined in terms of an array, in this
            example, the DATAARRAY struct. This is defined as:
         
// for defining an array of data
STRUCT DATAARRAY
    {
    STRUCT dataments[];
    }
The resource is composed of a number of DATA struct
            elements.
         
 The convention is to place such struct definitions in resource
            header files that, by convention, have the .rh extension. Resource
            header files are included in resource definition files, that have a
            .rss extension. This is analogous to the conventions for C++
            header and source files.
         
The resource itself is defined within the resource file, the
            .rss file, and must include the resource header file, the
            .rh file, so that the resource compiler can find the definition of
            the DATA and DATAARRAY structs. In this example, the
            resource header file is called ReadArray.rh.
         
#include "ReadArray.rh"
RESOURCE DATA first
    {
    ...
    }
RESOURCE DATAARRAY second
    {
    dataments=
        {
        DATA
            {
            flags=EFlagItem1;
            lng=654;
            byt=-1;
            ltxt=This text has a leading byte count;
            },
        DATA
            {
            wrd=999;
            flags=EFlagItem1+EFlagItem2;
            lng=3;
            byt=255;
            dbl=1.0;
            ltxt=Extremely large text indeed abcd efghijklm;
            },
        DATA
            {
            wrd=0;
            flags=EFlagItem16;
            lng=-1;
            byt=127;
            dbl=12.34;
            ltxt=;
            },
        DATA
            {
            wrd=-1;
            flags=EFlagItem1+EFlagItem8+EFlagItem16;
            lng=2147483647;
            byt=128;
            dbl=-3.4e+3;
            ltxt={[@@@@@@@@@@@@@@]};
            }
        };
    }
After resource compilation, the generated .rsg header
            file contains:
         
#define SECOND 2
Note that in the example from which this is taken, this resource is the second resource definition.
The following code fragment defines an example
            class, CResDataArray, that uses the resource data as a construction
            parameter. The class definition is placed in a C++ header file,
            a .h file. This header file also includes a definition of
            the CResData class.
         
The CResData class is defined as:
         
class CResData : public CBase
    {
public:
    ~CResData()
    static    CResData* NewLC(TResourceReader& aReader);
    void      ShowData(const TInt aStructNum = 0);
private:
    void      ConstructL(TResourceReader& aReader);
private:
    TInt           iWrd;   // STRUCT member type: WORD,
    TInt           iFlags; // WORD
    TInt           iLng;   // LONG,
    TInt           iByt;   // BYTE,
    TReal          iDbl;   // DOUBLE,
    HBufC*         iLtxt;  // LTEXT
    };
The CResDataArray class acts as a container for an array of
            pointers to CResData objects, where each
            CResData object corresponds to a DATA struct within
            the DATAARRAY type resource. The CResDataArray class
            is defined as:
         
class CResDataArray : public CBase
    {
public:
    ~CResDataArray();
    static    CResDataArray* NewLC(TResourceReader& aReader);
    void      AddDataL(TResourceReader& aReader);
    void      ShowAllData();
private:
    void      ConstructL(TResourceReader& aReader);
private:
    CArrayPtrFlat<CResData>* iDataArray;
    };
The following example code fragment loads the resource with
            id SECOND and constructs the
            CResDataArray object.
         
    // Read the second resource
HBufC8* res = resourceFile.AllocReadLC(SECOND);
TResourceReader theReader;
theReader.SetBuffer(res);
    // Construct a CResDataArray object to contain
    // the array of CResData objects, and add the elements to it
CResDataArray* resDataArray = CResDataArray::NewLC(theReader);
CResDataArray::NewLC() allocates
            the CResDataArray object and calls ConstructL() to
            complete the construction process.
         
ConstructL() takes a reference to
            the TResourceReader that refers to the resource data itself. It
            constructs the array object before starting the process of creating
            the CResData elements using the AddDataL() member
            function.
         
Note that raw resource data is always treated as general binary data.
void CResDataArray::ConstructL(TResourceReader& aReader)
    {
    iDataArray = new (ELeave) CArrayPtrFlat<CResData> (3);
    TRAPD(error,AddDataL(aReader));
    if (error)
        {
        iDataArray->ResetAndDestroy();
        delete iDataArray;
        User::Leave(error);
        }
    }
AddDataL() interprets the first two bytes of the resource
            data as the number of elements in the array.
         
On construction, each new CResData object is passed a
            reference to the TResourceReader object.
            The TResourceReader refers to that part of the resource data
            corresponding to the start of a struct.
         
As each CResData object constructs its own data members from
            the resource data using the services of the TResourceReader,
            the TResourceReader object updates its internal pointers to the
            resource data.
         
void CResDataArray::AddDataL(TResourceReader& aReader)
    {
    TInt index;
    TInt number;
            // The first WORD contains the number 
            // of DATA structs within the resource
    number = aReader.ReadInt16();
            // Add all newly created CResData objects 
            // to the cleanup stack before adding 
            // to the array
    for (index = 0; index < number ; index++)
        {
        CResData* resData = CResData::NewLC(aReader);
        iDataArray->AppendL(resData);
        CleanupStack::Pop(); // now resData safely in array
        }
    }