[go: up one dir, main page]

0% found this document useful (0 votes)
716 views115 pages

Descriptors: Fundamentals of Symbian C++

Download as pdf or txt
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 115

Fundamentals of Symbian C++

Descriptors
Part One

This work is licensed under the Creative Commons Attribution-Share Alike 2.0 UK: England & Wales License.

To view a copy of this license, visit http://creativecommons.org/licenses/bysa/2.0/uk/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California,
94105, USA.
Descriptors

Introduction

A Symbian OS string is known as a descriptor


•  As it is self-describing
•  A descriptor holds the length of the string of data it represents as well as
its type (which identifies the underlying memory layout of the descriptor
data)

Descriptors have something of a reputation among Symbian OS


programmers
•  The key point to remember is that they were designed to be very efficient
on low-memory devices,
•  Use the minimum amount of memory necessary to store a string while
describing it in terms of its length and layout

Fundamentals of Symbian C++ 2


Descriptors

Introduction

Descriptors are not like standard C++ strings, Java strings or the
MFC CString
•  Their underlying memory allocation and cleanup must be managed by
the programmer

Descriptors are also are also not like C strings


•  They protect against buffer overrun and do not rely on NULL
terminators to determine the length of the string

Fundamentals of Symbian C++ 3


Descriptors

Descriptors

Features of Symbian OS Descriptors


•  Understand that Symbian OS descriptors may contain text or binary
data
•  Know that descriptors may be narrow (8-bit), wide (16-bit) or
neutral (which is 16-bit since Symbian OS is built for Unicode)
•  Understand that descriptors do not dynamically extend the data
area they reference, so will panic if too small to store data resulting
from a method call

Fundamentals of Symbian C++ 4


Descriptors

Character Size

Symbian OS
•  Has been built to support Unicode character sets with wide (16-bit) characters
by default
•  The descriptors in early releases of Symbian OS (EPOC) up to Symbian OS v5
had 8-bit native characters

The character width of descriptor classes can be identified from their


names.
•  Class names ending in 8 (e.g. TPtr8) it have narrow (8-bit) characters
•  Class name ending with 16 (e.g. TPtr16) manipulates 16-bit character strings

Fundamentals of Symbian C++ 5


Descriptors

Character Size

There is also a set of neutral classes


•  Which have no number in their name (e.g. TPtr)
•  The neutral classes are typedef ’d to the character width set by the
platform
•  The neutral classes were defined for source compatibility purposes to
ease the switch between narrow and wide builds

Today Symbian OS is always built with wide characters


•  It is recommended practice to use the neutral descriptor classes where
the character width does not need to be stated explicitly.

Fundamentals of Symbian C++ 6


Descriptors

Memory Management

Descriptor classes do not dynamically manage the memory


used to store their data
•  The modification methods check that the maximum length of the
descriptor is sufficient for the operation to succeed
•  If it is not, they do not re-allocate memory for the operation
•  But instead panic to indicate that an overflow would have occurred

Fundamentals of Symbian C++ 7


Descriptors

Memory Management

The contents of the descriptor can shrink and expand


•  up to the maximum length allocated to the descriptor

Before calling a descriptor method which expands the data


•  The developer should implement the necessary checks to ensure
that there is sufficient space available in the descriptor
•  The contents of the descriptor can shrink and expand up to the
maximum length allocated to the descriptor

Fundamentals of Symbian C++ 8


Descriptors

Descriptors
The Symbian OS Descriptor Classes
•  Know the characteristics of the TDesC, TDes, TBufC, TBuf,
TPtrC, TPtr, RBuf and HBufC descriptor classes
•  Understand that the descriptor base classes TDesC and TDes
implement all generic descriptor manipulation code, while the
derived descriptor classes merely add construction and assignment
code specific to their type
•  Identify the correct and incorrect use of modifier methods in the
TDesC and TDes classes
•  Recognize that there is no HBuf class, but that RBuf can be used
instead as a modifiable dynamically allocated descriptor

Fundamentals of Symbian C++ 9


Descriptors

Key Descriptor Class Concepts

These will be covered later, but to proceed it is helpful to be aware of


the following points
•  TDesC is the base class for all descriptors
•  There are currently six derived descriptor classes (TPtrC, TPtr, TBufC,
TBuf, HBufC and RBuf)

Each subclass
•  Does not implement its own data access method using virtual function
overriding
•  This would add an extra 4 bytes to each derived descriptor object for a
virtual pointer (vptr) to access the virtual function table
•  4 bits of the 4 bytes that store the length of the descriptor object are used to
indicate the class type of the descriptor

Fundamentals of Symbian C++ 10


Descriptors

Key Descriptor Class Concepts

Descriptors come in two basic layouts:


•  Pointer descriptors - in which the descriptor holds a pointer to the
location of a character string stored elsewhere
•  Buffer descriptors - where a string of characters forms part of the
descriptor

Fundamentals of Symbian C++ 11


Descriptors

Descriptor Class Inheritance Hierarchy

TDesC

TPtrC TBufCBase TDes

TBufC<n> HBufC TPtr RBuf TBufBase

TBuf<n>

A first glance at the inheritance tree

Fundamentals of Symbian C++ 12


Descriptors

Symbian OS Descriptor Class: TDesC

TDesC

TPtrC TBufCBase TDes

TBufC<n> HBufC TPtr RBuf TBufBase

TBuf<n>

Fundamentals of Symbian C++ 13


Descriptors

Symbian OS Descriptor Class: TDesC

All the descriptor classes derive from the base class TDesC
•  Apart from the literal descriptors (discussed later)
•  The T prefix indicates a simple type class
•  The C suffix reflects that the class defines a non-modifiable type of
descriptor i.e. constant

Fundamentals of Symbian C++ 14


Descriptors

Symbian OS Descriptor Class: TDesC

TDesC defines the fundamental layout of every descriptor type:

TDesC
type iLength
0..3 4..31
4 bytes

To identify each of the derived classes


•  The top 4 bits are used to indicate the type of memory layout of descriptor
•  Remaining 28 bits are used to hold the length of the descriptor data
•  Thus the maximum length of a descriptor is limited to 2^28 bytes (256 MB)
Plenty!

Fundamentals of Symbian C++ 15


Descriptors

Symbian OS Descriptor Class: TDesC

TDesC provides methods


•  For determining the length of the descriptor - Length()
•  Accessing the data - Ptr()

Using Length() and Ptr() methods


•  The TDesC base class can implement all the operations typically possible
on a constant string object, such as data access, comparison and search

The derived classes


•  All inherit these methods but they are never overridden since they are
equally valid for all types of descriptor.
•  In consequence all constant descriptor manipulation is implemented by
TDesC regardless of the type of the descriptor
•  A good example of code reuse

Fundamentals of Symbian C++ 16


Descriptors

Symbian OS Descriptor Class: TDesC

Access to the descriptor data


•  Is different depending on the implementation of the derived descriptor
classes (buffer or pointer)
•  When a descriptor operation needs the correct address in memory for the
beginning of the descriptor data
•  It uses the Ptr() method of TDesC which looks up the type (the top 4 bits)
of descriptor
•  And returns the correct address for the beginning of the data

Fundamentals of Symbian C++ 17


Descriptors

Symbian OS Descriptor Class: TDes

TDesC

TPtrC TBufCBase TDes

TBufC<n> HBufC TPtr RBuf TBufBase

TBuf<n>

Fundamentals of Symbian C++ 18


Descriptors

Symbian OS Descriptor Class: TDes


The modifiable descriptor types all derive from the base class
TDes
•  A subclass of TDesC
•  TDes has an additional member variable to store the maximum
length of data allowed for the current memory allocated to the
descriptor
•  The MaxLength() method of TDes returns this value - it is not
overridden by derived classes
TDes
TDesC
type iLength iMaxLength
4 bytes 4 bytes

TDes defines a range of methods to manipulate modifiable


string data
•  Including appending, filling and formatting the descriptor data
•  All the manipulation code is implemented by TDes and inherited by
Fundamentals of Symbian C++
the derived classes. 19
Descriptors

Derived Descriptor Classes

Descriptors come in two basic layouts:


•  Pointer descriptors in which the descriptor holds a pointer to the
location of a character string stored elsewhere
•  Buffer descriptors where a string of characters forms part of the
descriptor.

Fundamentals of Symbian C++ 20


Descriptors

Pointer Descriptors: TPtrC and TPtr

TDesC

TPtrC TBufCBase TDes

TBufC<n> HBufC TPtr RBuf TBufBase

TBuf<n>

Fundamentals of Symbian C++ 12


21
Descriptors

Pointer Descriptors: TPtrC and TPtr

The string data of a pointer descriptor


•  Is separate from the descriptor object itself
•  Can be stored in ROM, on the heap or on the stack
•  The memory that holds the data is not “owned” by the descriptor

Pointer descriptors
•  Are agnostic about where the memory they point to is actually
stored
•  The pointer descriptors themselves are usually stack-based
•  But they can be used on the heap for example as a member
variable of a CBase-derived class

Fundamentals of Symbian C++ 22


Descriptors

Pointer Descriptors: TPtrC and TPtr

The non-modifiable pointer descriptor TPtrC

TPtrC
TDesC
iLength iPtr “hello world”
4 bytes 4 bytes

•  The pointer to the data follows the length word thus the total size of the
descriptor object is two words (8 bytes)
•  TPtrC is the equivalent of using const char* when handling strings in C
•  The data can be accessed but not modified i.e. the data in the descriptor is
constant
•  All the non-modifying operations defined in the TDesC base class are accessible
to objects of type TPtrC

Fundamentals of Symbian C++ 23


Descriptors

Pointer Descriptors: TPtrC and TPtr

The class also defines a range of constructors to allow TPtrC


to be constructed from another:
•  Descriptor
•  A pointer into memory
•  A zero-terminated C string

Fundamentals of Symbian C++ 24


Descriptors

Pointer Descriptors: TPtrC and TPtr


Examples of TPtrC constructors

_LIT(KDes, "abc ....");


Constructed from a literal descriptor TPtrC ptr(KDes);

Copy constructed from another TPtrC TPtrC copyPtr(ptr);

Constant buffer descriptor TBufC<100> constBuffer(KDes);

Constructed from a TBufC TPtrC myPtr(constBuffer);

TText8 is a single (8-bit) character, equivalent to const TText8* cString = (TText8*)"abc ...";

unsigned char

Constructed from a zero-terminated C string TPtrC8 anotherPtr(cString);

Pointer into memory initialized elsewhere TUint8* memoryLocation;

Length of memory to be represented TInt length;

...

TPtrC8 memPtr(memoryLocation,length);

Fundamentals of Symbian C++ 25


Descriptors

Pointer Descriptors: TPtrC and TPtr


A modifiable pointer descriptor TPtr

TPtr
TDes
TDesC
iLength iMaxLength iPtr “hello world”
4 bytes 4 bytes 4 bytes

•  The data location pointer (4 bytes) follows the maximum length of


TDes (4 bytes), which itself follows the length word of TDesC (4
bytes)
•  The descriptor object is three words in total (12 bytes)
•  The TPtr class can be used for access to, and modification of, a
character string or binary data
•  All the modifiable and non-modifiable base-class operations of
TDes and TDesC may be performed on a TPtr

Fundamentals of Symbian C++ 26


Descriptors

Pointer Descriptors: TPtrC and TPtr

The class defines constructors


•  To allow objects of type TPtr to be constructed from pointer into an
address in memory
•  Setting the length and maximum length as appropriate

The compiler
•  Also generates implicit default and copy constructors
•  Since they are not explicitly declared protected or private in the
class

A TPtr object
•  May be copy-constructed from another modifiable pointer descriptor
•  For example by calling the Des() method on a non-modifiable buffer

Fundamentals of Symbian C++ 27


Descriptors

Pointer Descriptors: TPtrC and TPtr

Examples of TPtr constructors

_LIT(KLiteralDes1, "abc ..");

TBufC<60> buf(KLiteralDes1);
TBufC is described later Copy construction - can TPtr ptr(buf.Des());

modify the data in buf Length=37 TInt length = ptr.Length();


charactersMaximum length=60 chars, as for buf
TInt maxLength = ptr.MaxLength();
Valid pointer into memory
TUint8* memoryLocation;

...
Length of data to be represented Maximum length to
TInt len = 12;
be representedConstruct a pointer descriptor from a
pointer into memory TInt maxLen = 32;

length=0, max=32 TPtr8 memPtr(memoryLocation, maxLen);

length=12, max=32 TPtr8 memPtr2(memoryLocation, len, maxLen);

Fundamentals of Symbian C++ 28


Descriptors

Stack-Based Buffer Descriptors TBufC and TBuf

TDesC

TPtrC TBufCBase TDes

TBufC<n> HBufC TPtr RBuf TBufBase

TBuf<n>

Fundamentals of Symbian C++ 12


29
Descriptors

Stack-Based Buffer Descriptors TBufC and TBuf

The stack-based buffer descriptors may be modifiable or


non-modifiable
•  The string data forms part of the descriptor object
•  Located after the length word in a non-modifiable descriptor
•  Located after the maximum-length word in a modifiable buffer descriptor

These descriptors are useful for fixed-size relatively small


strings (i.e. stack-based)
•  They may be considered equivalent to char[] in C
•  But with the benefit of overflow checking

Fundamentals of Symbian C++ 30


Descriptors

Stack-Based Buffer Descriptors TBufC and TBuf


TBufC is the non-modifiable buffer class

TBufC<n>
TDesC
iLength iBuf “hello world”
4 bytes n*sizeof(char)

•  Used to hold constant string or binary data.


•  The class derives from TBufCBase (which derives from TDesC and
exists as an inheritance convenience rather than to be used
directly)
•  TBufC<n> is a thin template class which uses an integer value to
determine the size of the data area allocated for the buffer
descriptor object

Fundamentals of Symbian C++ 31


Descriptors

Stack-Based Buffer Descriptors TBufC and TBuf

TBufC has several constructors


•  One to allow non-modifiable buffers to be constructed from a copy
of any other descriptor or from a zero-terminated string
•  TBufC can also be created empty and filled later

As the data is non-modifiable


•  The entire contents of the buffer is replaced by calling the
assignment operator defined by the class
•  The replacement data may be another non-modifiable descriptor or
a zero-terminated string

In each case
•  The new data length must not exceed the length specified in the
template parameter when the buffer was created.

Fundamentals of Symbian C++ 32


Descriptors

Stack-Based Buffer Descriptors TBufC and TBuf


Examples of TBufC constructors

_LIT(KPalindrome, "aabbaa");
Constructed from literal descriptor TBufC<50> buf1(KPalindrome);
Constructed from buf1 TBufC<50> buf2(buf1);

...
Constructed from a NULL-terminated C string
TBufC<30> buf3((TText16*)"Never odd or even");
TBufC<50> buf4;
Constructed empty length = 0
Copy and replace

buf4 contains data copied from buf1, length modified buf4 = buf1;
buf1 contains data copied from buf3, length modified
buf1 = buf3;
Panic! Max length of buf3 is insufficient for buf2 data
buf3 = buf2;

Fundamentals of Symbian C++ 33


Descriptors

Stack-Based Buffer Descriptors TBufC and TBuf

The TBuf<n> class for modifiable buffer data is a thin template class

TBuf<n>
TDes
TDesC
iLength iMaxLength iBuf “hello world”
4 bytes 4 bytes n*sizeof(char)

•  The integer value determining the maximum allowed length of the


buffer
•  It derives from TBufBase which itself derives from TDes
•  Inherits the full range of non-modifiable and modifiable descriptor
operations in TDes and TDesC

Fundamentals of Symbian C++ 34


Descriptors

Stack-Based Buffer Descriptors TBufC and TBuf


TBuf<n> defines a number of constructors and assignment operators
•  Similar to those offered by its non-modifiable counterpart TBufC<n>

_LIT(KPalindrome, "aabbaa");
Constructed from literal descriptor TBuf<40> buf1(KPalindrome);
Constructed from constant buffer descriptor TBuf<40> buf2(buf1);
Constructed from a NULL-terminated C string TBuf8<40> buf3((TText8*)"Do Geese see God?");
Constructed empty
length = 0 maximum length = 40
TBuf<40> buf4;

Copy and replace


...
buf2 copied into buf4, updating length and
buf4 = buf2;
max length
buf3 = (TText8*)"Murder for a jar of red rum";
updated from C string

Fundamentals of Symbian C++ 35


Descriptors

Dynamic Descriptors: HBufC

TDesC

TPtrC TBufCBase TDes

TBufC<n> HBufC TPtr RBuf TBufBase

TBuf<n>

Fundamentals of Symbian C++ 36


Descriptors

Dynamic Descriptors: HBufC

The class layout is similar to TBufC

HBuf
TDesC
iLength iBuf “hello world”
4 bytes n*sizeof(char)

Heap-based descriptors can be used


•  for string data that cannot be placed on the stack because it is too big
or its size is not known at compile time
•  where malloc ’d data would be used in C

Fundamentals of Symbian C++ 37


Descriptors

Dynamic Descriptors: HBufC

The HBufC8 and HBufC16 classes


•  Export a number of static NewL() factory functions to create
the descriptor on the heap
•  These methods follow the two-phase construction model and may
leave if there is insufficient memory available

There are no public constructors


•  All heap buffers must be constructed using one of these methods

TDesC::Alloc() or TDesC::AllocL()
•  May be used - these spawn an HBufC copy of any existing
descriptor

Fundamentals of Symbian C++ 38


Descriptors

Dynamic Descriptors: HBufC

These descriptors are not modifiable


•  In common with the stack-based non-modifiable buffer descriptors
the class provides a set of assignment operators
•  These replace the entire contents of the buffer
•  Objects of the class can also be modified at run-time by creating a
modifiable pointer descriptor TPtr using the Des() method

Heap descriptors
•  Can be created dynamically to the size required
•  But they are not automatically resized
•  The buffer must have sufficient memory available for the
modification operation to succeed or a panic will occur

Fundamentals of Symbian C++ 39


Descriptors

Dynamic Descriptors: HBufC


HBufC Constructor example
•  Pay close attention to the
modifiable ptr from heapBuf- _LIT(KPalindrome, "Do Geese see God?");

>Des() TBufC<20> stackBuf(KPalindrome);

Allocates an empty heap descriptor of ...

max length 20 HBufC* heapBuf = HBufC::NewLC(20);


TInt length = heapBuf->Length();

Current length = 0 TPtr ptr(heapBuf->Des());

Modification of the heap descriptor ptr = stackBuf;

Copies stackBuf contents into heapBuf length = heapBuf->Length();

length = 17 HBufC* heapBuf2 = stackBuf.AllocLC();

From stack buffer length = heapBuf2->Length();

length = 17 _LIT(KPalindrome2, "Palindrome");


*heapBuf2 = KPalindrome2;

Copy and replace data in heapBuf2 length = heapBuf2->Length();

length = 10 CleanupStack::PopAndDestroy(2, heapBuf);

Fundamentals of Symbian C++ 40


Descriptors

Dynamic Descriptors: RBuf

TDesC

TPtrC TBufCBase TDes

TBufC<n> HBufC TPtr RBuf TBufBase

TBuf<n>

Fundamentals of Symbian C++ 41


Descriptors

Dynamic Descriptors: RBuf

Class RBuf behaves like HBufC


•  The maximum length required can be specified dynamically
•  On instantiation, an RBuf object can allocate its own buffer, take ownership
of pre-allocated memory or a pre-existing heap descriptor
•  RBuf descriptors are typically created on the stack
•  But maintain a pointer to memory on the heap

RBuf is derived from TDes


•  An RBuf object can easily be modified and can be passed to any function
where a TDesC or TDes parameter is specified
•  There is no need to create a TPtr around the data in order to modify it
•  This makes it preferable to HBufC when dynamically allocating a descriptor
which is later modified.

Fundamentals of Symbian C++ 42


Descriptors

Dynamic Descriptors: RBuf


Internally RBuf behaves in one of two
ways: Heap

RBuf
TDes Union of ...
TDesC TUint16* iEPtrType ‘H’ ‘E’ ‘L’ ‘L’ ‘O’
iLength iMaxLength HBufC16* iEBufCPtrType
4 bytes 4 bytes 4 bytes

HBufC
‘H’ ‘E’ ‘L’ ‘L’ ‘O’

•  As a TPtr descriptor type which points to a buffer containing only descriptor


data
•  The RBuf object allocates or takes ownership of memory existing elsewhere

•  As a pointer to a heap descriptor HBufC*


•  TheRBuf object takes ownership of an existing heap descriptor thus the object pointed to
contains a complete descriptor object

Fundamentals of Symbian C++ 43


Descriptors

Dynamic Descriptors: RBuf

The handling of the internal union representation is transparent


•  There is no need to know how a specific RBuf object is represented
internally
•  The descriptor operations correspond to the usual base-class
methods of TDes and TDesC

The class is not named HBuf


•  As the objects are not directly created on the heap

It is an R class
•  As it manages a heap-based resource and is responsible for freeing
the memory at cleanup time

Fundamentals of Symbian C++ 44


Descriptors

Descriptors: Part One

  Features of Symbian OS Descriptors

  The Symbian OS Descriptor Classes

Fundamentals of Symbian C++ 45


Descriptors

Descriptors

Part Two

Fundamentals of Symbian C++


Descriptors

Descriptors

The Inheritance Hierarchy of the Descriptor Classes


•  Know the inheritance hierarchy of the descriptor classes
•  Understand the memory efficiency of the descriptor class
inheritance model and its implications

Fundamentals of Symbian C++ 47


Descriptors

The Inheritance Hierarchy of the Descriptor


Classes

TDesC

TPtrC TBufCBase TDes

TBufC<n> HBufC TPtr RBuf TBufBase

TBuf<n>

Fundamentals of Symbian C++ 48


Descriptors

The Inheritance Hierarchy of the Descriptor


Classes

The TDesC and TDes base classes


•  Provide the descriptor manipulation methods
•  Must know the type of derived class they are operating on in order to
correctly locate the data area

Each subclass
•  Does not implement its own data access method using virtual function
overriding
• This would add an extra 4 bytes to each derived descriptor object for a virtual pointer
(vptr) to access the virtual function table

Fundamentals of Symbian C++ 49


Descriptors

The Inheritance Hierarchy of the Descriptor


Classes

Descriptors were designed to be as efficient as possible


•  The size overhead to accommodate a C++ vptr was considered
undesirable

To allow for the specialization of derived classes


•  The top 4 bits of the 4 bytes that store the length of the descriptor
object are used to indicate the class type of the descriptor

Fundamentals of Symbian C++ 50


Descriptors

The Inheritance Hierarchy of the Descriptor


Classes

There are currently six derived descriptor classes: TPtrC,


TPtr, TBufC, TBuf, HBufC and RBuf
•  Each sets the identifying iType bits as appropriate upon
construction
•  The use of 4 bits to identify the type limits the number of different
types of descriptor to 2^4 (= 16)
•  It seems unlikely that the range will need to be extended
significantly in the future

Fundamentals of Symbian C++ 51


Descriptors

The Inheritance Hierarchy of the Descriptor


Classes

For all descriptors, access to the descriptor data goes through


the non-virtual Ptr() method of the base class TDesC
•  It uses a switch statement to check the 4 bits, identify the type of
descriptor and return the correct address for the beginning of its
data.
•  This requires that the TDesC base class has knowledge of the
memory layout of its subclasses hard-coded into Ptr()

Fundamentals of Symbian C++ 52


Descriptors

Descriptors

Using the Descriptor APIs


•  Understand that the descriptor base classes TDesC and TDes
cannot be instantiated
•  Understand the difference between Size(), Length() and
MaxLength() descriptor methods
•  Understand the difference between Copy() and Set() descriptor
methods and how to use assignment correctly

Fundamentals of Symbian C++ 53


Descriptors

Using the Descriptor APIs

The TDesC and TDes descriptor base classes


•  Provide and implement the APIs for all descriptor operations
•  Typically the derived descriptors only implement specific methods for
construction and copy assignment.

Objects of type TDesC and TDes


•  Cannot be instantiated directly because their default constructors are
protected.
•  It is the derived descriptor types that are actually instantiated and used

The descriptor API methods


•  Are fully documented in the Symbian OS Library of each SDK and the
course examples
•  This lecture focuses on some of the trickier areas of descriptor
manipulation

Fundamentals of Symbian C++ 54


Descriptors

Using the Descriptor APIs

The difference between Length()and Size()


•  The Size() method returns the size of the descriptor in bytes
•  The Length() method returns the number of characters it
contains
•  For 8-bit descriptors this is the same as the size i.e. the size of a
character is a byte

From Symbian OS v5u (version 5 unicode)


•  The native character is 16 bits wide i.e. each character occupies
two bytes
•  Size() always returns a value double that of Length() for
neutral and explicitly wide descriptors

Fundamentals of Symbian C++ 55


Descriptors

MaxLength() and Length Modification Methods

The MaxLength() method


•  Of TDes returns the maximum length of a modifiable descriptor value
•  Like the Length() method of TDesC it is not overridden by the
derived classes

The SetMax() method


•  Sets the current length of the descriptor to the maximum length
allowed
•  It does not change the maximum length of the descriptor thereby
expanding or contracting the data area

Fundamentals of Symbian C++ 56


Descriptors

MaxLength() and Length Modification Methods

The SetLength() method


•  Can be used to adjust the descriptor length to any value
between zero and its maximum length

The Zero() method


•  Sets the length to zero

Fundamentals of Symbian C++ 57


Descriptors

Set() and the Assignment Operator

The pointer descriptor types


•  Provide Set() methods which update them to point at different string data

_LIT(KDes1, "Sixty zippers were quickly picked from the woven jute bag");

_LIT(KDes2, "Waltz, bad nymph, for quick jigs vex");

TPtrC alpha(KDes1);

TPtrC beta(KDes2);

alpha.Set(KDes2); // alpha points to the data in KDes2

beta.Set(KDes1); // beta points to the data in KDes1

Literal descriptors are described later

Fundamentals of Symbian C++ 58


Descriptors

Set() and the Assignment Operator

TDes provides an assignment operator TDes::operator


=()
•  Used copy data into the memory referenced by any modifiable
descriptor
•  Provided the length of the data to be copied does not exceed the
maximum length of the descriptor which would cause a panic

It is easy to confuse Set() with TDes::operator =()


•  Set() resets a pointer descriptor to point at a new data area
•  Changes the length and maximum length members

•  TDes::operator =() merely copies data into an existing


descriptor
•  Modifies the descriptor length but not its maximum length

Fundamentals of Symbian C++ 59


Descriptors

Set() and operator =()

_LIT(KLiteralDes1, "Jackdaws love ...");

TBufC<60> buf(KLiteralDes1);

Points to the contents of buf TPtr ptr(buf.Des());

Valid pointer into memory TUint16* memoryLocation;


... ...

Maximum length to be represented max length=40 TInt maxLen = 40;

Copy and replace TPtr memPtr(memoryLocation, maxLen);

memPtr data is KLiteralDes1 (37 bytes), memPtr = ptr; // Assignment

max length=40 _LIT(KLiteralDes2, "The quick brown fox ...");

TBufC<100> buf2(KLiteralDes2);

Points to the data in buf2 TPtr ptr2(buf2.Des());


Replace what ptr points to
ptr points to contents of buf2, max length = 100
ptr.Set(ptr2);
Attempt to update memPtr, which panics because the
contents of ptr2 (43 bytes) exceeds memPtr = ptr2;
max length of memPtr (40 bytes)

Fundamentals of Symbian C++ 60


Descriptors

Modifying Data with Des()

The content of a non-modifiable buffer descriptor cannot be


altered directly other than by complete replacement of the data
•  The stack- and heap-based TBufC and HBufC descriptors provide
a method which returns a modifiable pointer descriptor to the data
represented by the buffer

But it is possible to change the data indirectly


•  by calling Des() and then operating on the data via the pointer

When the data is modified via the return value of Des()


•  The length members of both the pointer descriptor and the constant
buffer descriptor are updated

Fundamentals of Symbian C++ 61


Descriptors

Modifying Data with Des()


Note: All descriptors are 8 bit

Constructed from literal descriptor _LIT8(KPalindrome, "Satan, oscillate...");

Data is the string in buf, max length = 40


TBufC8<40> buf(KPalindrome);

TPtr8 ptr(buf.Des());

Use ptr to replace contents of buf


...

ptr = (TText8*)"Do Geese see God?";

ASSERT(ptr.Length()==buf.Length());

_LIT8(KPal2, "Are we not drawn onward...");


Panic! ptr = KPal2; // Assignment
KPal2 exceeds max length of buf (=40)

Fundamentals of Symbian C++ 62


Descriptors

Descriptors

Descriptors as Function Parameters


•  Understand that the correct way to specify a descriptor as a
function parameter is to use a reference, for both constant data and
data that may be modified by the function in question.

Fundamentals of Symbian C++ 63


Descriptors

Descriptors as Function Parameters

The TDesC and TDes descriptor base classes


•  Provide and implement the APIs for all descriptor operations
•  They can be used as function arguments and return types, allowing
descriptors to be passed around in code without forcing a dependency on a
particular type

An API client
•  Should not be constrained to using a TBuf because a particular function
requires it

Function providers
•  Should remain agnostic to the type of descriptor passed to them

Unless a function takes or returns ownership


•  It should not need to specify whether a descriptor is stack- or heap-based

Fundamentals of Symbian C++ 64


Descriptors

Descriptors as Function Parameters

When defining functions


•  The TDesC and TDes base classes should always be used as
parameters or return values
•  For efficiency, descriptor parameters should be passed by
reference
•  Either as const TDesC& for constant descriptors or TDes&
when modifiable

Except: When returning ownership of a heap-based


descriptor as a return value
•  It should be specified explicitly so that the caller can clean it up
appropriately and avoid a memory leak

Fundamentals of Symbian C++ 65


Descriptors

Descriptors

Correct Use of the Dynamic Descriptor Classes


•  Identify the correct techniques and methods to instantiate an
HBufC heap buffer object
•  Recognize and demonstrate knowledge of how to use the new
descriptor class RBuf

Fundamentals of Symbian C++ 66


Descriptors

Correct Use of the Dynamic Descriptor Classes

HBufC construction and usage


•  HBufC can be spawned from existing descriptors using the
Alloc() or AllocL() overloads implemented by TDesC
•  This example which shows how to replace inefficient code with use
of TDesC::AllocL()
void CSampleClass::UnnecessaryCodeL(const TDesC& aDes)
{
iHeapBuffer = HBufC::NewL(aDes.Length());
TPtr ptr(iHeapBuffer->Des());
ptr.Copy(aDes);
...
}
Could be replaced by a single line
{
iHeapBuffer = aDes.AllocL();
}

Fundamentals of Symbian C++ 67


Descriptors

HBufC Construction and Usage

An HBufC object
•  Can also be instantiated using the static NewL() factory methods
specified for the class
•  For HBufC16 the methods available are as follows:

static IMPORT_C HBufC16* NewL(TInt aMaxLength);

static IMPORT_C HBufC16* NewLC(TInt aMaxLength);

• Thesemethods create a new heap-based buffer descriptor with maximum


length as specified
• Leave if there is insufficient memory available for the allocation
• TheNewLC method leaves the successfully created descriptor object on the
cleanup stack

The heap descriptor is empty and its length is set to zero

Fundamentals of Symbian C++ 68


Descriptors

HBufC Construction and Usage

An HBufC16 object
•  Can also be instantiated using the non leaving method static
New() factory:

static IMPORT_C HBufC16* New(TInt aMaxLength);

This method creates a new heap-based buffer descriptor with maximum length
• 
as specified
It does not leave if there is no heap memory available to allocate the
• 
descriptor
The caller must compare the returned pointer against NULL to confirm that it
• 
has succeeded before dereferencing it

The heap descriptor is empty and its length is set to zero

Fundamentals of Symbian C++ 69


Descriptors

HBufC Construction and Usage

NewMax methods also set HBufC16’s length to the maximum


value
static IMPORT_C HBufC16* NewMax(TInt aMaxLength);

static IMPORT_C HBufC16* NewMaxL(TInt aMaxLength);

static IMPORT_C HBufC16* NewMaxLC(TInt aMaxLength);

• These methods create a new heap-based buffer descriptor with maximum


length as specified and set its length to the maximum value
•  No data is assigned to the descriptor

If insufficient memory is available for the allocation:


•  NewMax() return a NULL pointer ()
•  NewMaxL() and NewMaxLC() will leave

NewMaxLC() leaves the successfully allocated descriptor on the cleanup stack

Fundamentals of Symbian C++ 70


Descriptors

HBufC Construction and Usage

Initializing an HBufC16 from the contains of a RReadStream

static IMPORT_C HBufC16* NewL(RReadStream& aStream, TInt aMaxLength);

static IMPORT_C HBufC16* NewLC(RReadStream& aStream, TInt aMaxLength);

• These methods allocate a heap-based buffer descriptor and initialize it from


the contents of a read stream
Reads from the stream up to the maximum length specified (or the
• 
maximum length of the stream data - whichever is shortest) and allocates a
buffer to hold the contents
Typically used to reconstruct a descriptor that has previously been
• 
externalized to a write stream using the stream operators

Fundamentals of Symbian C++ 71


Descriptors

Descriptor Externalization and Internalization


An example of descriptor externalization and internalization using streams

Writes the contents of void CSampleClass::ExternalizeL(RWriteStream& aStream) const


iHeapBuffer to a writable stream {
aStream.WriteUint32L(iHeapBuffer->Length());
Write the descriptor’s length aStream.WriteL(*iHeapBuffer, iHeapBuffer->Length());
Write the descriptor’s data
}
/** */
Instantiates iHeapBuffer by void CSomeClass::InternalizeL(RReadStream& aStream)
reading the contents of the stream {

Read the descriptor’s length TInt size = aStream.ReadUint32L();


Allocate iHeapBuffer iHeapBuffer = HBufC::NewL(size);

Create a modifiable descriptor


TPtr ptr(iHeapBuffer->Des());
over iHeapBuffer
Read the descriptor data into
aStream.ReadL(ptr,size);
iHeapBuffer via ptr

72
Fundamentals of Symbian C++
}
Descriptors

Descriptor Externalization and Internalization

The following code


•  Shows the use of the stream operators as a more efficient
alternative
•  The stream operators have been optimized to compress the
descriptor’s meta-data as much as possible for efficiency and
space conservation
void CSampleClass::ExternalizeL(RWriteStream& aStream) const
{// Much more efficient, no wasted storage space
aStream << iHeapBuffer;
}

void CSampleClass::InternalizeL(RReadStream& aStream)


{// KMaxLength indicates the maximum length of
// data to be read from the stream
iHeapBuffer = HBufC::NewL(aStream, KMaxLength);
}

Fundamentals of Symbian C++ 73


Descriptors

RBuf

While there is a non-modifiable heap descriptor class HBufC


•  There is no corresponding modifiable HBuf class
•  Whichmight have been expected in order to make heap buffers symmetrical
with TBuf stack buffers.

The RBuf class was first introduced in Symbian OS v8.0


•  But first documented in Symbian OS v8.1 and used most
extensively in software designed for phones based on Symbian OS
v9 and later

Fundamentals of Symbian C++ 74


Descriptors

RBuf Construction and Usage


RBuf objects can be instantiated using
• Create(), CreateMax() or CreateL() to specify the maximum length of
descriptor data that can be stored
It is also possible to instantiate an RBuf to store a copy of the contents of another
• 
descriptor:

RBuf myRBuf;
_LIT(KHelloRBuf, "Hello RBuf!");
myRBuf.Create(KHelloRBuf());

•  Create() allocates a buffer for the RBuf to reference


•  If the RBuf previously owned a buffer, Create() will not clean it
up before assigning the new buffer reference
• Cleanup must be done explicitly by calling Close() first

An RBuf can alternatively take ownership of a pre-existing


section of memory using the Assign() method
•  Assign() will also orphan any data already owned
•  (Close() should be called first to avoid memory leaks)
Fundamentals of Symbian C++ 75
Descriptors

RBuf Construction and Usage

Using Assign() to take ownership

Taking ownership of HBufC HBufC* myHBufC = HBufC::NewL(20);


RBuf myRBuf.Assign(myHBufC);
Use and clean up ...
myRBuf.Close();

TInt maxSizeOfData = 20;


RBuf myRBuf;
Taking ownership of TUint16* pointer =

pre-allocated heap memory static_cast<TUint16*>(User::AllocL(maxSizeOfData*2));

myRBuf.Assign(pointer, maxSizeOfData);
Use and clean up ...
myRBuf.Close();

Fundamentals of Symbian C++ 76


Descriptors

RBuf Construction and Usage

The RBuf class


•  Does not manage the size of the buffer and reallocate it if more
memory is required
•  If Append() is called on an RBuf object for which there is insufficient
memory available - a panic will occur
•  This should be clear from the fact that the base-class methods are non-
leaving
•  i.e. there is no scope for the reallocation to fail in the event of low
memory

Fundamentals of Symbian C++ 77


Descriptors

RBuf Construction and Usage

The memory for RBuf operations must be managed by the


programmer
•  The ReAllocL() method can be used as follows:

myRBuf is the buffer to be resized e.g. for an Append()


operation

Push onto cleanup stack for leave-safety myRBuf.CleanupClosePushL();


Extend to newLength myRBuf.ReAllocL(newLength);
Remove from cleanup stack CleanupStack::Pop ();

Fundamentals of Symbian C++ 78


Descriptors

RBuf Construction and Usage

Using an RBuf is preferable to using an HBufC in that:


•  If the ReAllocL()method is used on the HBufC and causes the
heap cell to move any associated HBufC* and TPtr variables
need to be updated
•  This update is not required for RBuf objects as the pointer is
maintained internally

Fundamentals of Symbian C++ 79


Descriptors

RBuf Construction and Usage

The class is not named HBuf


•  Unlike HBufC objects of this type are not themselves directly created on
the heap

It is instead an R class
•  As it manages a heap-based resource and is responsible for freeing the
memory at cleanup time
•  As is usual for other R classes cleanup is performed by calling Close()

If the RBuf
•  Was pushed onto the cleanup stack by a call to CleanupClosePushL()
use CleanupStack::PopAndDestroy()

Fundamentals of Symbian C++ 80


Descriptors

RBuf Construction and Usage

It is possible to create an RBuf from an existing HBufC


•  The RBuf class is both modifiable and dynamically allocated and thus is an
advantage over HBufC
•  Being able to create an RBuf from an HBufC object is a good migration
route from pre-Symbian OS v8.1

Previously
•  It would have been necessary to instantiate an HBufC and then use a
companion TPtr object - constructed by calling Des() on the heap
descriptor

When to use RBuf or HBufC?


•  RBuf is recommended for use when a dynamically allocated buffer is
required to hold data that changes frequently
•  HBufC should be preferred when a dynamically allocated descriptor is
needed to hold data that rarely changes

Fundamentals of Symbian C++ 81


Descriptors

HBufC vs RBuf

Using HBufC for modifiable data Using RBuf for modifiable data
HBufC* socketName = NULL; RBuf socketName;
// KMaxNameLength is defined elsewhere ...

if(!socketName) if(socketName.Compare(KNullDesC)==0)
{ {
socketName = HBufC::NewL(KMaxNameLength); socketName.CreateL(KMaxNameLength);
} }
// Create writable ’companion’ TPtr
TPtr socketNamePtr(socketName->Des());
message.ReadL(message.Ptr0(), socketNamePtr); message.ReadL(message.Ptr0(), socketName);

The code is simpler - It is easier to understand and maintain

Fundamentals of Symbian C++ 82


Descriptors

Descriptors

Common Inefficiencies in Descriptor Usage


•  Know that TFileName objects should not be used indiscriminately,
because of the stack space each consumes
•  Understand when to dereference an HBufC object directly, and
when to call Des() to obtain a modifiable descriptor (TDes&)

Fundamentals of Symbian C++ 83


Descriptors

Common Inefficiencies in Descriptor Usage

TFileName objects waste stack space


•  The TFileName type is typedef’d as a modifiable stack buffer with
maximum length 256 characters
•  It can be useful when calling various file system functions to parse filenames
into complete paths - since the exact length of a filename is not always known
at compile time
•  For example to print out a directory’s contents

However, since each character is of 16-bit width


•  Every time a TFileName object is declared on the stack it consumes 2 × 256
= 512 bytes
•  Plus the 12 bytes required for the descriptor object itself
•  That’s just over 0.5 KB!
•  The default stack size for an application is only 8 KB

Fundamentals of Symbian C++ 84


Descriptors

TFileName Objects Waste Stack Space

On Symbian OS the stack space for each process is limited


•  By default it is just 8 KB
•  On the Windows emulator if more stack space is needed the stack will just
expand
•  This is not the case on a phone - a panic will be raised when the stack overflow
occurs
•  This can be hard to track down since it will not be seen when testing on the
emulator so cannot be easily debugged

Fundamentals of Symbian C++ 85


Descriptors

TFileName Objects Waste Stack Space

At 0.5 KB a single TFileName object


•  Can consume and potentially waste a significant proportion of the stack
space

It is good practice to use one of the dynamic heap descriptor types


•  Or limit the use of TFileName objects to members of C classes as these
types are always created on the heap

Fundamentals of Symbian C++ 86


Descriptors

Referencing HBufC through TDesC

The HBufC class derives from TDesC


•  The HBufC* pointer can simply be dereferenced when a reference to a non-
modifiable descriptor TDesC& is required

A common mistake is to call the Des() method on the heap descriptor


•  This creates a separate TPtr referencing the descriptor data
•  This is not incorrect it returns a TDes&
•  But it is clearer and more efficient simply to return the HBufC object directly

const TDesC& CSampleClass::AccidentalComplexity()


{
return (iHeapBuffer->Des());

// could be replaced more efficiently with

return (*iHeapBuffer);
}

Fundamentals of Symbian C++ 87


Descriptors

Descriptors

Literal Descriptors
•  Know how to manipulate literal descriptors and know that those
specified using _L are deprecated
•  Specify the difference between literal descriptors using _L and
those using _LIT and the disadvantages of using the former

Fundamentals of Symbian C++ 88


Descriptors

Literal Descriptors

Literal descriptors are different from the other descriptor types


•  They are equivalent to static char[] in C and can be built into
program binaries in ROM (if the code is part of the system)
because they are constant
•  There is a set of macros defined in e32def.h which can be used
to define Symbian OS literals of two different types, _LIT and _L

Fundamentals of Symbian C++ 89


Descriptors

Literal Descriptors

_LIT macro
•  The _LIT macro is preferred for Symbian OS literals since it is the
more efficient type
•  It has been used in the sample code throughout these lectures -
typically as follows:

_LIT(KFieldMarshalTait, "Field Marshal Tait");

• KFieldMarshalTait can then be used as a constant descriptor - for example


to write to a file or display to a user

Fundamentals of Symbian C++ 90


Descriptors

The _LIT Macro

The _LIT macro


•  Builds a named object (KFieldMarshalTait) of type TLitC16 into the
program binary
•  Storing the appropriate string in this case "Field Marshal Tait"
•  The explicit macros _LIT8 and _LIT16 behave similarly except that
_LIT8 builds a narrow string of type TLitC8

Fundamentals of Symbian C++ 91


Descriptors

The _LIT Macro

TLitC8 and TLitC16 do not derive from TDesC8 or


TDesC16
•  But they have the same binary layouts as TBufC8 or TBufC16
•  This allows objects of these types to be used wherever TDesC
is used
•  The string stored in the program binary has a NULL terminator
because the native compiler string is used to build it
•  The _LIT macro adjusts the length to the correct value for a
non-terminated descriptor

Fundamentals of Symbian C++ 92


Descriptors

The _LIT Macro

Symbian OS also defines literals yo represent a blank string


•  There are three variants of the null descriptor, defined as follows:
•  Build independent:

_LIT(KNULLDesC,"");

•  8-bit for non-Unicode strings:

_LIT8(KNULLDesC8,"");

•  16-bit for Unicode strings:

_LIT16(KNULLDesC16,"");

Fundamentals of Symbian C++ 93


Descriptors

_L Macro

Use of the _L macro


•  Is now deprecated in production code
•  It may still be used in test code (where memory use is less critical)
•  The advantage of using _L is that it can be used in place of a TPtrC
without having to declare it separately from where it is used:

User::Panic(_L("telephony.dll"), KErrNotSupported);

• For the example above, the string ("telephony.dll") is built into the program
binary as a basic, NULL-terminated string

Fundamentals of Symbian C++ 94


Descriptors

_L Macro

Unlike the TLitC built for the _LIT macro


•  It has no initial length member
•  This means the layout of the stored literal is not like that of a
descriptor i.e. no length word

Thus when the code executes


•  Each instance of _L will result in construction of a temporary
TPtrC
•  With the pointer being set to the address of the first byte of the
literal as it is stored in ROM

Fundamentals of Symbian C++ 95


Descriptors

_LIT and _L Memory Layouts


The difference memory layouts
•  In ROM for literals created using _LIT and _L macros

_LIT(KHello,”Hello World!”) TPtrC KHello(_L(”Hello World!”))

ROM Stack Temporary ROM


12 Hello World!\0 iLength 12 iPtr Hello World!\0

Fundamentals of Symbian C++ 96


Descriptors

Descriptors

Descriptor Conversion
•  Know how to convert 8-bit descriptors into 16-bit descriptors and
vice versa using the descriptor Copy() method or the
CnvUtfConverter class
•  Recognize how to read data from file into an 8-bit descriptor and
then ‘translate’ the data to 16-bit without padding, and vice versa
•  Know how to use the TLex class to convert a descriptor to a
number, and TDes::Num() to convert a number to a descriptor

Fundamentals of Symbian C++ 97


Descriptors

Descriptor Conversion

Conversion between narrow and wide descriptors


•  TDes implements an overloaded set of Copy() methods which allow
copying directly into descriptor data from:
•  Another descriptor
•  A NULL-terminated string
•  A pointer

The Copy()methods
•  Copy the data into the descriptor setting its length accordingly
•  The methods will panic if the maximum length of the receiving descriptor
is shorter than the incoming data

Fundamentals of Symbian C++ 98


Descriptors

Descriptor Conversion

The Copy() method


•  Is overloaded to take either an 8- or 16-bit descriptor

It is possible
•  To copy a narrow-width descriptor onto a narrow-width
descriptor
•  To copy a wide descriptor onto a wide descriptor

It is also possible
•  To copy between descriptor widths
•  i.e. carrying out an implicit conversion in the process

Fundamentals of Symbian C++ 99


Descriptors

Wide to Narrow
The Copy() method implemented by TDes8
•  Is to copy an incoming wide descriptor into a narrow descriptor
•  It strips out alternate characters assuming them to be zeroes - the
data values do not exceed 255 (decimal).
•  The Copy() method which copies a narrow descriptor into the data
area is a straight data copy

CAT
TBuf8<3> cat(_L8("CAT"));
D \0 O \0 G \0
NULL characters stripped out in wide-to- TBuf16<3> dog(_L16("DOG"));
narrow descriptor copy

DOG
cat.Copy(dog);

Fundamentals of Symbian C++ 100


Descriptors

Narrow to Wide
For class TDes16
•  An incoming 16-bit descriptor can be copied directly onto the data
area
•  The Copy() method that takes an 8-bit descriptor pads each
character with a trailing zero as part of the copy operation

S M ALL
TBuf8<5> small(_L8("SMALL"));
L \0 A \0 R \0 G \0 E \0
 NULL characters used to pad narrow- TBuf16<5> large(_L16("LARGE"));
to-wide descriptor copy

S \0 M \0 A \0 L \0 L \0

large.Copy(small);

Fundamentals of Symbian C++ 101


Descriptors

Copy() methods

The Copy() methods


•  Form a rudimentary means of copying and converting between 8- and
16-bit descriptors
•  When the character set is encoded by one byte per character
•  And the last byte of each wide character is simply a NULL character
padding

Fundamentals of Symbian C++ 102


Descriptors

The CnvUtfConverter Class

Is used to perform a proper conversion


•  In both directions between 16-bit Unicode (UCS-2) and 8-bit non-Unicode
character sets
•  Or between Unicode and the UTF-7 and UTF-8 transformation sets

The CnvUtfConverter class


•  Supplied by charconv.lib (see header file utf.h) is available
•  The class supplies a set of static methods such as
ConvertFromUnicodeToUtf8() and
ConvertToUnicodeFromUtf8()

Fundamentals of Symbian C++ 103


Descriptors

Converting Descriptors to Numbers

A descriptor can be converted to a number using the TLex class


•  This class provides general-purpose lexical analysis and performs
syntactical element parsing and string-to-number conversion
•  Using the locale-dependent functions of TChar to determine whether
each character is a digit, a letter or a symbol

Fundamentals of Symbian C++ 104


Descriptors

Converting Descriptors to Numbers

TLex is the build-width neutral class


•  Implicitly TLex16
•  TLex8 and TLex16 can also be used explicitly
•  The neutral form should be preferred unless a particular variant is
required
•  TLex can be constructed with the data for constructed empty and later
assigned the data
•  Both construction and assignment can take:
•  Another TLex object
•  A non-modifiable descriptor
•  A TUint16* or TUint8* (for TLex16 or TLex8 respectively) pointer to string data

Fundamentals of Symbian C++ 105


Descriptors

Converting Descriptors to Numbers

At the very simplest level


•  When the string contains just numerical data, the descriptor contents
can be converted to an integer using the Val() function of TLex

_LIT(KTestLex, "54321");
TLex lex(KTestLex());
TInt value = 0;
TInt err = lex.Val(value); // value == 54321 if no error occurred

The Val() function is overloaded for different signed integer types (TInt, TInt8,
• 
TInt16, TInt32, TInt64) with or without limit checking
There are also Val() overloads for the unsigned integer types, passing in a radix
• 
value (decimal, hexadecimal, binary or octal), and for TRealTLex provides a number
of other API methods for manipulation and parsing
These are documented in the Symbian OS Library in each SDK

Fundamentals of Symbian C++ 106


Descriptors

Converting Numbers to Descriptors

The descriptor classes


•  Provide several ways to convert a number to a descriptor
•  The various overloads of AppendNum(),
AppendNumFixedWidth(),Num() and NumFixedWidth()
convert the specified numerical parameter to a character
representation
•  Either completely replacing the contents of or appending the data to
the descriptor

Fundamentals of Symbian C++ 107


Descriptors

Converting Numbers to Descriptors

Formatting with conversion directives


•  The Format(), AppendFormat(), FormatList() and
AppendFormatList() methods of TDes each take a format string
•  Containing literal text embedded with conversion directives
•  And a trailing list of arguments

Each formatting directive


•  Consumes one or more arguments from the trailing list
•  And can be used to convert numbers into descriptor data

Fundamentals of Symbian C++ 108


Descriptors

Packaging Objects in Descriptors

Flat data objects


•  Can be stored within descriptors using the package buffer TPckgBuf and
package pointer TPckg and TPckgC classes
•  This is useful for inter-thread or inter-process data transfer when making
a client–server request

A T-class object
•  May be packaged whole into a descriptor (“descriptorized”) so it may be
passed in a type-safe manner between threads or processes

Fundamentals of Symbian C++ 109


Descriptors

Packaging Objects in Descriptors

The TPckgBuf, TPckg and TPckgC classes


•  Are thin template classes
•  Derived from TBuf<n>, TPtr and TPtrC respectively (see e32std.h)
•  The classes are type-safe and are templated on the type to be packaged

Fundamentals of Symbian C++ 110


Descriptors

Packaging Objects in Descriptors

There are two package pointer classes


•  Modifiable TPckg or non-modifiable TPckgC pointer descriptors which
refer to the existing instance of the template-packaged class
•  Functions may be called on the enclosed object (TSample theSample
next slides)
•  If it is enclosed in a TPckgC a constant reference to the packaged object is
returned from operator()

Fundamentals of Symbian C++ 111


Descriptors

Packaging Objects in Descriptors

There is one package buffer class


•  The package buffer TPckgBuf creates and stores a new instance of the
type to be encapsulated in a descriptor
•  The copied object is owned by the package buffer (next slide)

It is modifiable
•  Functions may be called on it after calling operator() on the TPckgBuf
object to retrieve it
•  The package buffer contains a copy of the original object thus only the copy
is modified, the original is unchanged

Fundamentals of Symbian C++ 112


Descriptors

Memory Layout of the TPckg, TPckgC and


TPckgBuf Classes

TPckg<TSample> TPtr
TDes
TDesC
iLength iMaxLength iPtr

TSample theSample
TPckgC<TSample> TPtrC
TDesC
iLength iPtr

TPckBuf<TSample> TBuf<n>
TDes
TDesC
iLength iMaxLength copy of theSample

Fundamentals of Symbian C++ 113


Descriptors

Packaging Objects in Descriptors


A simple T class encapsulated in each of the package types
TSample is the class to be
class TSample
packaged up inside the
{
descriptor packages
public:
void SampleFunction();
Methods that maybe called on the (enclosed) object
void ConstantSampleFunction() const;
private:
TInt iSampleData;
};
TSample theSample;

Modifiable package containing theSample TPckg<TSample> packagePtr(theSample);


TPckgC<TSample> packagePtrC(theSample);
Non-modifiable package containing theSample
TPckgBuf<TSample> packageBuf(theSample);
Modifiable package containing a copy of theSample packagePtr().SampleFunction();
Calling methods directly on the enclosed theSample object packagePtrC().SampleFunction();
Compile error! Non-const method
packagePtrC().ConstantSampleFunction();
Fine a const method called
packageBuf().SampleFunction();
Modifying a copy of theSample
Fundamentals of Symbian C++ 114
Descriptors

Descriptors: Part Two

  The Inheritance Hierarchy of the Descriptor Classes

  Using the Descriptor APIs

  Descriptors as Function Parameters

  Correct Use of the Dynamic Descriptor Classes

  Common Inefficiencies in Descriptor Usage

  Literal Descriptors

  Descriptor Conversion

Fundamentals of Symbian C++ 115

You might also like