Symbian
Symbian Developer Library

SYMBIAN OS V9.4

Feedback

[Index] [Previous] [Next]


How to convert data from a resource containing an array of structs

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.

[Top]


Defining the resource

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.

[Top]


Converting from the array resource

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
        }
    }

See also

Converting data from a simple resource