Introduction
When I was new to Symbian, The first thing I encountered was Symbian OS String handling and manipulations. It was then days of nightmare that struck me :). What I found was that it's a bit tricky to remember the descriptor stuffs, but once you get the trick it’s easy. No, I am not kidding..
So here I am trying to explain how I learned the basic Symbian OS string handling and tried to remember the things. I will not go into a war of words regarding whether having descriptors is a good approach or not, because whether it is good or bad you have to use it :(. Another thing I will not discuss here is how you can do similar things using plain C++ or how to do something with plain C++ string manipulation techniques. This article is just about descriptors.
The prerequisite of this article is a working knowledge of the Symbian OS.
Background
The very first thing you need to do is to remember the descriptor hierarchy. This is very important as all of the five descriptors you are going to use are derived from some classes and you must know from which class they are derived to be able to successfully decide which particular descriptor should be used and in which scenario. I am not going to explain what a buffer descriptor and Heap Descriptor mean, and also what is meant by modifiable and non modifiable descriptors. I believe you must be having enough information about what is meant by the above terminologies. I will also not use 8 and 16 bit variants, as functionality wise there is a similarity between these two and also these are not important in understanding the descriptors. The Symbian Descriptor Hierarchy looks fabulous. (Sorry for not providing fabulous pictures of Descriptor hierarchy). You can have a look at newlc for pictures.
Usage of TPtrC<n>
If you want a literal meaning for this, then it is a "Pointer to a data that cannot be manipulated". The basic thing to remember about TPtrC<n>
is that it contains no manipulation functionalities of its own and that it just contains constructors and set methods, and since it is derived directly from TDesC
it contains all the functionalities of TDesC
.
The pointer will point to data in one of the two ways:
- Create an empty
TPtrC<N>
and then point it to some data using Set(...)
functions.
- Pass the data while constructing by using any one of the overloaded constructors.
Let's see the above statements with the help of a few examples given below:
- Example 1:- Getting
TPtrC
from TBuf
and TBufC
:
LIT(KText , "Test Code");
TBufC<10> Buf ( KText ); OR(/) TBuf<10> Buf ( KText );
TPtrC Ptr (Buf);
TPtrC Ptr1;
Ptr1.Set(Buf);
- Example 2:- Getting
TPtrC
from TText*
:
The example below uses TText16
:
TText * text = _S("Hello World\n");
TPtrC ptr(text);
TPtrC Ptr1;
Ptr1.Set(text);
TPtrC ptr4 ( text , 5 );
- Example 3:- Getting
TPtrC
from another TPtrC
:
You can easily assign one TPtrC
to another.
TText * text = _S("Hello World\n");
TPtrC ptr(text);
TPtrC p1(ptr);
TPtrC p2;
p2.Set(ptr);
- Example 4:- Getting
TText *
from TPtrC
:
We can get the TText *
from TPtrC
by using the Ptr()
member.
_LIT(KText , "Test Code");
TBufC<10> Buf ( KText );
TPtrC Ptr1 (Buf);
TText * Text1 = (TText *)Ptr1.Ptr();
Usage of TBufC<n>
The examples used to describe the working TPtrC
gives some understanding about the usage of TBufC<n>
, Nevertheless here are a few examples on how to create TBufC<n>
.
- Example 5:- Instantiating the
TBufC<N>
:
_LIT(Ktext, "TestText");
TBufC<10> Buf (Ktext);
TBufC<10> Buf2;
Buf2 = Ktext;
TBufC<10> Buf3(Buf2);
TBufC<n>
is used generally for text data. For binary data, explicit TBufC8<n>
is used. Though TBufC<n>
means that the data cannot be modified ('C' stands for Constant), there are two ways by which this data can be modified:
- The data can be replaced by using assignment operator.
- By using
Des()
function to construct a TPtr
modifiable pointer descriptor for the buffer data.
Let's see the first way to change the contents of TBufC<n>
.
- Example 6:- Changing the contents of
TBufC<N>
:
_LIT(Ktext , "Test Text");
_LIT(Ktext1 , "Test1Text");
TBufC<10> Buf1 ( Ktext );
TBufC<10> Buf2 ( Ktext1 );
Buf2 = Buf1;
TBufC<10> Buf3;
Buf3 = Buf1;
Another way of changing the contents of TBufC<n>
is by using the Des()
member. This member function returns TPtr
modifiable pointer descriptor using members of the TPtr
. The maximum length of the TPtr
is the value of the TBufC<n>
template parameter. All the manipulating functions are from TDesC
base.
- Example 7:- Changing the contents of
TBufC<N>
using Des()
:
_LIT(Ktext , "Test Text");
_LIT(KXtraText , "New:");
TBufC<10> Buf1 ( Ktext );
TPtr Pointer = Buf1.Des();
Pointer.Delete(Pointer.Length()-4, 4 );
TInt Len = Pointer.Length();
Pointer.Append(KXtraText);
Len = Pointer.Length();
_LIT(NewText , "New1");
_LIT(NewText1 , "New2");
TBufC<10> Buf2(NewText);
Pointer.Copy(Buf2);
Pointer.Copy(NewText1);
Working with Heap Descriptor HBufC
HBufC
is the descriptor of choice when we don’t know the size of the data that we want to have in the descriptor. Here 'C' stands for constant that means the data is constant but it can also be changed in two ways as it was changed in the case of TBufC<n>
. First using the assignment operator and another by using the modifiable pointer descriptor, i.e. TPtr
using Des()
member function. There are two things to remember while using the HBufC
.
- If you need to pass
HBufC
to a function that takes TDesC &
as a parameter, you need to simply dereference the HBufC
pointer.
- The size of Heap Descriptor buffer can be changed using
ReAlloc
function as opposed to TBufC<N>
.
- Example 8:- Usage of
HBufC
:
HBufC * Buf = HBufC::NewL(15);
_LIT (KText , "Test Text");
TBufC<10> CBuf = KText;
HBufC * Buf1 = CBuf.AllocL();
TInt BufSize = Buf->Size();
TInt BufLength = Buf->Length();
_LIT ( KText1 , "Text1");
*Buf1 = KText1;
TPtr Pointer = Buf1->Des();
Pointer.Delete( Pointer.Length() - 2, 2 );
_LIT ( KNew, "New:");
Pointer.Append( KNew );
Usage of TPtr
Ahaa, we are using it in place of TBufC<N>
and HBufC
, so we know most of it. So let’s remember how we can create TPtr
.
- Another
TPtr
.
- From
TBufC<N>
, HBufC
using Des()
member function.
- From an explicit pointer to the memory and specifying the max length.
- From an explicit pointer to the memory and specifying the data as well as the maximum length.
- Example 9:- Usage of
TPtr
:
_LIT(KText, "Test Data");
TBufC<10> NBuf ( KText );
TPtr Pointer = NBuf.Des();
TPtr Pointer2 ( Pointer );
TText * Text = _S("Test Second");
TPtr Pointer3 ( Text ,11, 12);
_LIT(K1, "Text1");
_LIT(K2, "Text2");
Pointer2 = K1; Pointer.Copy(K2);
Pointer2.SetLength(2); Pointer2.Zero();
Usage of TBuf<n>
In this the data doesn't remain constant. The operations, instantiation and assignment will be similar to that of the TBufC<n>
along with the modification functions that can be applied to it as it was applied in the case of TPtr
, like Copy, Delete, assignments etc.. I hope I don’t need to give examples for this section.
History