.rss
.rsc
This section details the source text resource file format, and is a useful reference for developers in C++ and OPL.
Topics covered include; the lexical conventions obeyed, the C++ pre-processor statements supported, and a description of the native resource compiler statements.
Section Contents
RESOURCE SIMPLE quote_example
{
string="\"text\"";
}
where string is of type BUF.
RESOURCE SIMPLE backslash_example
{
string="\\text\\";
}
The following pre-processor statements are supported by the resource compiler:
The resource compiler supports conditional compilation such as
#ifdef SOMETHING
// do something
#else
// do something else
#endif
or
#ifndef WHATEVER
// do something
#endif
You can include files within the source file by using a #include directive, for example:
#include <eikdef.rh>
or
#include "eikdef.hrh"
The searching algorithm used by the resource compiler depends on whether the item to be included is enclosed in double-quotes or angled brackets.
If the filename is enclosed in double-quotes, the resource compiler searches for that file through the following directories in the given order:
..\inc
\epoc32\include
If the filename is enclosed in angled brackets, the resource compiler searches for that file through the following directories in the given order:
..\inc
\epoc32\include
A source file consists of any number of statements.
The most usual forms of statement are a struct-statement and a resource-statement. The struct statement defines a type of resource, see STRUCT statement. The resource statement defines an actual resource instance of the type defined in a struct, gives it a resource id, see Generated resource ids, and causes it to be generated in the resource file, see RESOURCE statement.
By default, the resource ids in the generated header file are allocated from 1 in ascending sequence. The sequence can be made to begin from another value using the NAME statement, see NAME statement.
A STRUCT statement defines the format of a struct; all resources are defined in terms of structs. The struct has a name designated by struct-name, and some items designated by struct-member-list.
The length of most structs is variable. A resources entire length can be deduced from the position of the next resource; this information is available in a resource files index. If the struct is embedded within a resource, however, its length must be identified another way.
The following are valid STRUCT statements:
STRUCT STRING { TEXT str; }
STRUCT TEST BYTE { WORD status; STRUCT text; }
The first example defines a struct called STRING which contains a single TEXT item.
The second example defines a struct called TEST which contains a WORD and an embedded struct. The total length of TEST is unknown, but should not exceed 255 bytes: the BYTE directive in the definition indicates that, when this struct is embedded within another, it should be preceded with a byte indicating its length (zero to 255 bytes).
The struct-member-list is a sequence of struct-members where each member is terminated by a semi-colon. The complete list is enclosed within a pair of braces as demonstrated by the struct called TEST.
The following rules must be observed for struct-names:
So the following struct definition will generate an error
STRUCT BUFTHING { BUF buffer; }
whereas this struct definition will compile correctly
STRUCT ABUFTHING { BUF buffer; }
STRUCT TEST { WORD length; }
There are twelve valid types:
BYTE |
A single byte. Can be treated as a signed integer (128 to +127) or unsigned integer (0 to 255). |
WORD |
Two bytes. Can be treated as a signed integer (32,768 to +32,767) or unsigned integer (0 to 65,535). |
LONG |
Four bytes. Can be treated as a signed integer (2,147,483,648 to 2147483647) or an unsigned integer (0 to 4,294,967,295). |
DOUBLE |
Eight byte real for double precision floating point numbers (approximately |
TEXT |
An ASCII string, terminated by a null. |
LTEXT |
An ASCII string with a leading byte count, and no terminating null. |
BUF |
An ASCII string with no terminating null and no leading byte count. |
BUF<n> |
An ASCII string with no terminating null and no leading byte count but which has a maximum length n. This type is an alternative to using the length-limit with BUF types, |
LINK |
The id of another resource (16 bits), rather like a pointer to that resource. |
LLINK |
The id of another resource (32 bits). |
SRLINK |
A self-referencing link. This is a 32 bit link which contains the resource id of the resource it is defined in. |
STRUCT |
Any struct, rather like including that struct as a member in this struct. STRUCT members are useful because it means that once a struct has been defined it can be re-used for a variety of resources. |
STRUCT TEST { WORD length; STRUCT text; // should be a STRING }
STRUCT TEST { TEXT string1(9); LTEXT string2(MAX); BUF string3; }
string1 has a maximum of 9 characters, string2 a maximum of MAX characters (where MAX has been #defined elsewhere) and string3 has no maximum length. Note that this maximum applies only to the actual characters and does not take account of the terminating zero (for TEXT members) or leading byte count (for LTEXT members).
STRUCT TEST { BUF<4> string; }
RESOURCE TEST test1 { string="abcd"; }
RESOURCE TEST test2 { string="ab"; }
RESOURCE TEST test3 { string="abcdef"; }
test1 generates 0x61 0x62 0x63 0x64
test2 generates 0x61 0x62
but test3 generates an error because the maximum length of string permitted by the definition of the STRUCT is 4.
Recall the member-declaration syntax; look at a specific subset of this (see Defining struct members for the full syntax of a struct member:
A declaration of a struct member may either be a simple type-name member-name, or it may be an array of values of identical type.
Arrays are always indicated by square brackets:
STRUCT HAS_ARRAY { STRUCT elements[]; }
In the example above, the HAS_ARRAY struct has one array member, elements. Each member of elements is of STRUCT type.
If you specify the array size, inside the square brackets, then the generated resource will contain no count of the number of elements. So this resource:
STRUCT FIXED_ARRAY { WORD elements[3]; } RESOURCE FIXED_ARRAY example1 { elements={9,8,7}; }
will generate the output
0x09 0x00 0x08 0x00 0x07 0x00
For variable length arrays a count of the number of elements precedes the resource. The default for this is a word, but by prefixing the struct definition with LEN BYTE it will be a byte count. So the following resource:
STRUCT VAR_ARRAY { WORD elements []; } RESOURCE VAR_ARRAY example2 { elements={9,8,7}; }
will generate the output
0x03 0x00 0x09 0x00 0x08 0x00 0x07 0x00
whereas this resource:
STRUCT VAR_ARRAY2 { LEN BYTE WORD elements[]; } RESOURCE VAR_ARRAY2 example3 { elements={9,8,7}; }
will generate this output
0x03 0x09 0x00 0x08 0x00 0x07 0x00
The compiler allows you to prefix LEN BYTE or LEN WORD even for fixed length arrays but it has no effect. Fixed length arrays do not generate an element count.
See also the section on initialising array items in Initialising resource members.
The RESOURCE statement is used to generate a resource in the resource file. The statement specifies three things:
It must have been defined in a previous STRUCT statement and must be in upper case.
The resource-name must be in lower case.
The resource-name causes a symbolic constant to be generated in the resource compilers output header file, so that a resource
RESOURCE TEST my_test { /* etc */ }
will result in a definition of the form
#define MY_TEST 1
in the generated header file see the .rsg
file referred to in Command line syntax.
The default id for the first resource defined in the file is one with subsequent resources ids generated in ascending sequence. See Generated resource ids for more information on how resource ids are generated.
If no resource name is specified then the resource is generated in the object file and assigned a resource id as usual, but will not be published in the header file. Anonymous resources are used mainly for playback scripts where the resources are read in sequentially by default, so that assigning names to them would be superfluous.
The resource-name may also be used by the resource compiler for LINK and LLINK members see Resource identifiers for LINKs and LLINKs.
As an example, given the struct definition
STRUCT NCEDIT { WORD current; WORD low; WORD high=65535; }
you could define a resource:
RESOURCE NCEDIT MEMORY_SIZE { low=640; high=1024; }
Thus, in the resource file, current has the value compiler default value of 0, low has the value 640 (specified in the resource definition) and high has the value 1024 (specified in the resource definition, overriding the default for the struct type).
The resource initialiser has different forms depending on whether a single, simple, member is being initialised, or whether a struct or an array is being initialised:
Resource members may be initialised by default (in the struct definition) or explicitly initialised (in the resource definition).
In general,
STRUCT TEST2
{
WORD value;
STRUCT tester;
}
The following RESOURCE statement only generates the two bytes 0xFF 0x00.
RESOURCE TEST2 item
{
value=255;
}
Default values can be specified for struct members by using an initialiser, for example
STRUCT NCEDIT { WORD current; WORD low; WORD high=65535; }
With this specification, any NCEDIT resource will, by default, have a high member whose value is 65,535. If the RESOURCE statement specifies a different value, it will be used instead.
RESOURCE THING { string(20)="Very long string"; }
will compile correctly even if the struct definition specified a maximum length of 10 for string.
A LINK or LLINK member must be initialised with a resource-identifier. This resource identifier may be in the form of a resource name or a number.
It is not necessary for the resource to be defined at the time the statement is processed, but an error will result if the resource is not defined in the entire file. When declared in lower case any NAME specified in the file will be added onto the resource id.
To reference it you must #include the relevant header file containing the resource. All resource names are turned into upper case when their #defines are generated in the header file this is how the resource compiler recognises that it must look for the resource in another file. If this resource does not exist in any #included file then an error is generated.
If no such resource id exists either in the file or any #included header files, no error is generated by the compiler. The programmer must therefore ensure that the id is a valid reference.
See Generated resource ids for information on how resource ids are generated. See also NAME statement and related statements.
To initialise a member of array type, give the items in the array in sequence. Each initialiser must be of a type compatible with the member being initialised.
If the member was declared as a fixed-length array (e.g., WORD elements[10]), then it is an error to specify any more items than were given in the length (either in the STRUCT or the RESOURCE definition). If fewer items are specified in the default initialisation (i.e. in the STRUCT definition) then an error also results. Note that if fewer elements are specified when initialising the array in the RESOURCE statement, then any elements not specified after the specified values will be lost, even if they have been default initialised in the STRUCT definition. Take the following example:
STRUCT SAMPLE { BYTE bts[3]={1,2,3}; }
In the following resource:
RESOURCE SAMPLE default {}
the output will be the whole default array
0x01 0x02 0x03
but in this resource:
RESOURCE SAMPLE first_specified { bts={5}; }
the output is:
0x05
with the second and third elements lost. If you specify only the second element in the RESOURCE definition then the first element is taken from the default initialisation, the second from the explicit initialisation and the third element is lost. The following resource:
RESOURCE SAMPLE second_specified { bts[1]=5; }
results in the 2-byte output:
0x01 0x05
If, however, you explicitly initialise an element in the middle of an array without having supplied default values for array members before it, then an error will result.
If the array was not declared fixed-length then the number of elements is worked out from the initialiser and prepended to the resource. The default for this element count is a word: you may specify it as a byte by declaring LEN BYTE in front of the array declaration in the STRUCT definition; e.g.
STRUCT VAR_ARRAY { LEN BYTE WORD []; }
You may initialise array elements with expressions. You must explicitly initialise each member component of the array otherwise the expressions will be evaluated incorrectly. The following resource:
RESOURCE SAMPLE correct_expression { bts[0]=3+1; bts[1]=2; bts[2]=3; }
will generate the correct output 0x04 0x02 0x03. However, if you use the following syntax:
RESOURCE SAMPLE incorrect_expression { bts={3+1,2,3}; }
the output will be 0x03 0x02 0x03. This is because the pre-processor treats 3+1 as a literal string which is then interpreted by the compiler as 3. In the resource correct_expression above the = sign forces the pre-processor to evaluate the expression.
STRUCT members may only be initialised in the resource definition.
To initialise a member of STRUCT type, give the struct-name with which you wish to initialise it, and then specify each member of that struct which you wish to initialise.
The member-names listed must be members of the struct-name struct. Each initialise must be of a type compatible with the member it is initialising.
The compiler does not enforce type safety. Any struct can be used to initialise a member declared to be of struct type. Usually, however, the designer of the struct will have intended only one or a limited number of structs ever be used to initialise a member. You should ensure that you initialise struct members with the intended struct type.
Given the previously defined struct types
STRUCT STRINGCOUNT { BUF message; WORD num; }
STRUCT SAMPLE { WORD anynumber; STRUCT text; // should be a STRINGCOUNT }
the following example shows how to define the struct within a resource:
RESOURCE SAMPLE show_how { anynumber=10; text=STRINGCOUNT { message="Hello" num=5; }; }
Note the trailing semicolon after the closing } of the text struct member initialisation: this is because a semicolon follows all member initialisations. For longer, more complicated resources deciding where semicolons must be placed may become confusing. As shown in the following example, array lists are separated by commas and terminated without a semi-colon. Similarly, resources are not terminated by a semi-colon.
RESOURCE DIALOG example_dialog { title="Example"; topsection=DLAY_SECTION { control_list= { ACLIST { butlist_flags=BUTLIST_HORIZONTAL; rid=R_HCIL_BUTTONS_OK_CANCEL; }, // array member so comma needed ACLIST { butlist_flags=BUTLIST_HORIZONTAL; rid=R_HCIL_BUTTONS_OK_CANCEL; } // last item in array so nothing needed }; // end of struct member control_list so ; needed }; // end of struct member topsection so ; needed } // end of resource so nothing needed
The rules to remember are as follows:
type of entity |
Punctuation needed after closing } |
resource |
nothing |
array member (not last one) |
, |
last array member |
nothing |
struct member |
; |
See the definitions of resource-statement, struct-statement, struct-member and array-initialiser for a complete explanation of the syntax.
Use this statement to ensure that the resources in the file have a unique id so that an application can use multiple resource files without resource id conflict.
This statement must the first non-comment statement in the file.
The short-name must be between one and four alphabetic characters long and be unique (no other file may use the same one). For the sake of consistency this constant should be in upper case although lower case is allowed (and will be converted to upper case by the compiler). This short-name is then converted into a number and shifted onto the leading 20 bits of the resource id, leaving the bottom 12 bits for the number of the resource in the file. This allows a maximum of 4095 resources to be defined in a source file.
So with NAME set to AAAA, if this resource is the first resource in the file
RESOURCE STRING one { wd=5; }
the first entry in the generated header file will be
#define ONE 0x04FD8001
04FD8 is the leading 20 bits for all ids in the file and 001 is the reference of that resource within the file.
Since the NAME statement maps all resource ids within the file onto 32-bit numbers, only LLINKs may be used for resource references in that file. Using the NAME statement in a resource file means that any attempt to use a LINK will generate an error.
Use a CHARACTER_SET statement to define the character set to be used. The permitted values for character_set-name are defined as:
If the CHARACTER_SET statement is omitted from a resource file, character set CP1252 is taken as default.
Use an enum (or an ENUM) statement to define a set of integer values. The values are associated with symbols defined in the enum-list; the syntax and the semantics are compatible with those of C++ enumerations.
Each member of the enum-list is followed by a comma except for the last one. The syntax of a member is defined as:
The defined enumerator symbols can be used in both C++ code and resource scripts and are commonly defined in files which have the conventional file extension hrh
. The .hrh
files are included in both C++ files and resource source files.
For example, the enum definition:
enum { EExampleCmdIdFirst=0x100, EExampleCmdIdSecond, EExampleCmdIdThird, EExampleCmdIdFourth };
defines the enumerators EExampleCmdIdFirst, EExampleCmdIdSecond etc. and assigns values to them.
In general, each enumerator can be assigned a specific value. If no value is explicitly assigned, the value generated by the resource compiler is the value of the previous enumerator plus one. Thus, in the above example, EExampleCmdIdFirst is assigned the value 0x100 (decimal 256), EExampleCmdIdSecond is assigned the value 0x101 (decimal 257) etc.
If the first enumerator is not assigned an explicit value, it defaults to 0.
More than one enumerator may be assigned an explicit value.
The assigned value can be coded in either hexadecimal or plain decimal notation.
enum { testvalue1=10, testvalue2, testvalue3=20, testvalue4 };
STRUCT TEST1 { BYTE b1; BYTE b2; BYTE b3; BYTE b4; }
RESOURCE TEST1 test { b1=testvalue1; b2=testvalue2; b3=testvalue3; b4=testvalue4; }
In this example the resource generated is: 0x0A 0x0B 0x14 0x15
Note that the final semi-colon in an enum may be omitted; however, to retain compatibility with the C++ compiler, it is advisable to retain it.
.rsc
All resource files have the following format:
header |
resources |
index table |
where:
header |
is always four bytes long. It consists of two 16-bit numbers: the first gives the file offset of the start of the index table, the second gives the length in bytes of the index table |
resources |
are a series of variable-length data items generated in the order specified in the source file |
index table |
is a sequence of 16-bit numbers, the first giving the file offset of the start of the first resource, the second giving the file offset of the start of the second resource and so on up to the last resource in the file. The last 16-bit number gives the file offset of the end of the last resource (i.e. the beginning of the index table) |
So for example the following source file:
STRUCT SIMPLE { WORD wd; LONG lg; BUF name; }
RESOURCE SIMPLE one { wd=5; lg=10000; name="Simon"; }
RESOURCE SIMPLE two { name="John"; }
when compiled, will produce the following output resource file:
0: 19 00 06 00 05 00 10 27 00 00 53 69 6d 6f 6e 00 ....... ..Simon.
10: 00 00 00 00 00 4a 6f 68 6e 04 00 0f 00 19 00 .....Joh n......