Symbian Developer Library

SYMBIAN OS V6.1 EDITION FOR C++

[Index] [Glossary] [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.


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 theCResData 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 CResDataobject corresponds to a DATA struct within theDATAARRAY 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 idSECOND and constructs the CResDataArrayobject.

// 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 theCResDataArray object and calls ConstructL() to complete the construction process.

ConstructL() takes a reference to theTResourceReader that refers to the resource data itself. It constructs the array object before starting the process of creating theCResData 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. TheTResourceReader 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, theTResourceReader 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