Using Symbian OS String Descriptors
3 Mar 2005 - 15:16

Introduction

When I was new to Symbian, The first thing that I encountered is Symbian OS String handling and Manipulations. It was then day(s) of nightmare that struck me :). What I found that its 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 try to remember the things. I will not go here on the war of words whether having descriptors is a good approach or not, because be it be good or bad you have to use it :(. Another thing I will not discuss here is how you can do similar thing using plain C++ or how to do something you can do with plain C++ string manipulation techniques. This article is just regarding descriptors.

The prerequisite of this article is 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 5 descriptors you are going to use derived from some classes and you must know from which class this derives to be able to successfully decide which particular descriptor to use in which scenario. I am not going to explain what a buffer descriptor and Heap Descriptor means, and also what is meant by modifiable and non modifiable descriptors. I believe you must be having enough information on what is meant by above terminologies. I will also not use 8 and 16 bit variant as functionality wise there is a similarity between these two and also not important in understanding the descriptors. The Symbian Descriptor Hierarchy looks something like. (Sorry for not providing fabulous pictures of Descriptor hierarchy). You can have a look at String and Descriptors for picture.

Usage of TPtrC<n>

If we want a literal meaning for this, then it will be "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 it just contains constructors and set methods, and since it derives directly from the TDesC it contains all the functionalities of TDesC.

The pointer will point to data in one of the two ways:
-  Create an empty TPtrC and then point it to some data using Set(...) functions.
-  Pass the data while constructing by using any one of the overloaded constructors. Let see the above statements with the help of few examples below.

Example 1: Getting TPtrC from TBuf and TBufC

LIT(KText , "Test Code");
TBufC<10> Buf ( KText ); //or TBuf<10> Buf ( KText );
// Creation of TPtr using Constructor
TPtrC     Ptr (Buf);
// Creation of TPtr using Member Function
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);
// OR
TPtrC Ptr1;
Ptr1.Set(text);

// To store only a part of TText we can use the following
// This descriptor pointer will store only Hello
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);
// Get TPtrC from another TPtrC
TPtrC p1(ptr);
// OR
TPtrC p2;
p2.Set(ptr);

 
Example 4: Getting TText * from TPtrC We can get the TText * from TPtrC by using the Ptr() member

// Set the TPtrC
_LIT(KText , "Test Code");
TBufC<10> Buf ( KText );
TPtrC    Ptr1 (Buf);
// Get the TText *
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 few examples on how to create TBufC<n>.

Example 5: Instantiating the TBufC

// Instantiating the TBufC from Literals
_LIT(Ktext, "TestText");
TBufC<10> Buf (Ktext);
// or
TBufC<10> Buf2;
Buf2 = Ktext;
// Creating a new TBufC with existing TBufC
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), but 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 buffers data. Let see the first way to change the contents of TBufC<n>:

 
Example 6: Changing the contents of TBufC

// Describe some literals for Testing example
_LIT(Ktext , "Test Text");        
_LIT(Ktext1 , "Test1Text");
// Generate TPtrC
TBufC<10> Buf1 ( Ktext );
TBufC<10> Buf2 ( Ktext1 );
// Change the contents of Buf2
Buf2 = Buf1;
// Create an Empty TBufC and assign it to Buf1
TBufC<10> Buf3;
Buf3 = Buf1;

Another way of changing the contents of TBufC<n> 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 using Des()

_LIT(Ktext , "Test Text");
_LIT(KXtraText , "New:");
TBufC<10> Buf1 ( Ktext );
TPtr Pointer = Buf1.Des();
// delete the last 4 characters
Pointer.Delete(Pointer.Length()-4, 4 );
// the length should be changed now
TInt Len = Pointer.Length();
// Append the new one
Pointer.Append(KXtraText);
Len = Pointer.Length();
// To completly changed the buffer we can use following
_LIT(NewText , "New1");
_LIT(NewText1 , "New2");
TBufC<10> Buf2(NewText);
// change the context
Pointer.Copy(Buf2);
// or Directly from literal
Pointer.Copy(NewText1);
// All the above changed actually changing the contents of Buf1

Working with Heap Descriptor HBufC

HBufC is the descriptor of choice when we don't know the size of 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 and HBufC to a function that takes TDesC & as parameter, you need to simply dereference the HBufC pointer.
-  the Size of Heap Descriptor buffer can be changed using ReAlloc function as oppose to TBufC.

 
Example 8: Usage of HBufC

// Creation of a Heap Descriptor . There are 2 ways to do it
// 1st way use either New(), NewL(), or NewLC()  
// Let see the example for this. This wills construct the HBufC with
// a Data space for 15, but the current size is Zero.
HBufC * Buf = HBufC::NewL(15);
       
// 2nd way to used the Alloc(), AllocL(), or AllocLC() of
// the existing descriptors. The new Heap descriptor is automatically
// initialized with the content of descriptor.
_LIT (KText , "Test Text");
TBufC<10>  CBuf = KText;
HBufC * Buf1 = CBuf.AllocL();

// Lets Check the size and Length . The size will be 18
// and length will be 9
TInt BufSize = Buf->Size();
TInt BufLength = Buf->Length();            
       
// Changing what HBufC is pointing to
_LIT ( KText1 , "Text1");
// Change the buffer to Point to KText1 using assignment operator
*Buf1 = KText1;
       
// And now changing the Data through Modifiable pointer descriptor
TPtr Pointer = Buf1->Des();
Pointer.Delete( Pointer.Length() - 2, 2 );

// All operations that were done in case of TBufC<n> is applicable here also.
// here is one such operation      
_LIT ( KNew, "New:");
Pointer.Append( KNew );

Usage of TPtr

Ahaa, we are using it in case of TBufC and HBufC, so we know most of it. So let's remember how we can create TPtr.
-  Another TPtr.
-  From TBufC, HBufC using Des() member function.
-  From an explicit Pointer into the memory and specifying the max length.
-  From and explicit Pointer into the memory and specifying the data as well as the maximum length.

 
Example 9: Usage of TPtr

// First lets see 2nd way of Getting TPtr
_LIT(KText, "Test Data");
TBufC<10> NBuf ( KText );
TPtr     Pointer = NBuf.Des();
       
// 1st way
TPtr     Pointer2 ( Pointer );
       
//3rd way using a memory area , Data and max length
TText * Text = _S("Test Second");
TPtr    Pointer3 ( Text ,11, 12);
       
// Now we will see how to replace the data with TPtr ,it can
// be done completly by using assignment Operator or copy function        
_LIT(K1, "Text1");
_LIT(K2, "Text2");        
Pointer2 = K1; // Data will be Text1
Pointer.Copy(K2); // Data Will be Text2;

// we can also change the length of the data or set it to zero
Pointer2.SetLength(2); // Only Te will be there
Pointer2.Zero(); // Make length of data as Zero

// Data can be altered using the delete function as it used to alter
// in the earlier examples.

Usage of TBuf<n>

In this the data doesn't remains constant. The operations, Instantiation and assignment will be similar to that of the TBufC<n> along with the modification functions that can be applied into it as it was applied in the case of TPtr, like Copy, Delete, assignments etc. I hope I don't need to give some examples for this section.

Tutorial posted March 3rd, 2005 by deepakkumargupta

Submitted by Anonymous on Wed, 2005-03-16 13:24.

Is it possible to have buffer overflow while using Descriptors (buffer, pointer or heap)..?

For example if i have the sample code below:

TBuf<16> myBuf; // 16 characters

_LIT(KTxt,"hello worldddddd+++"); //19 characters myBuf.Copy(KTxt);

In a debug build (emulator) i get panic and the application/threads exit. What happens in a release build - is it actual buffer overflow? (when i run the application to the mobile also crashes)

Finally, is it possible to build an application for symbian using plain C++ (char *, char [] ) and functions as strcpy, etc...?

Thanks in advance!


Submitted by deepakkumargupta on Thu, 2005-03-17 05:34.

Hi ,

yes you will have buffer overflow if you do like that and you will have a Panic in that case.

Regarding your 2nd question , you can use data types of plain C++ and functions like strcpy() by using libc provided by the symbian library. For example you could include libc\string.h in your program and can have strcpy() on char *.

Hope this helps


Submitted by Anonymous on Thu, 2005-03-17 14:50.

>>>>yes you will have buffer overflow if you do like that and you will have a Panic in that case.

ok, but it will not be the classic buffer overflow(as happens in x86 processors) because the thread will immediately exit(panic) and prevent by overiding any return address and execute other code.. right..?

>>>>Regarding your 2nd question , you can use data types of plain C++ and functions like strcpy() by using libc provided by the symbian library. For example you could include libc\string.h in your program and can have strcpy() on char *.

I have read many articles and documentation about the descriptors and how to use them, but i didnt find anything about why was they implemented..?

What is the point of use them...?

Do they more secure than the plain C++..? Are there any memory management and memory allocation issues..?

Thanks in advance!


Submitted by .:floyd:. (not verified) on Tue, 2005-03-22 11:51.

I have read many articles and documentation about the descriptors and how to use them, but i didnt find anything about why was they implemented..?

What is the point of use them...?

Why does standard C++ offer std::vector or std::string? Same answer applies for descriptors: to make string and array handling both safer and easier to use.

Do they more secure than the plain C++..? Are there any memory management and memory allocation issues..?

Didn't your application crash when attempting to write past the end? Does that not make your application safer?

.f


Submitted by Anonymous on Mon, 2005-05-30 04:36.

Yeah, descriptors in symbian implemented very well. It distinguish basic usage for string. but what puzzle me is that as a virtual basic class TDesC, how does it implement without virtual function? BTW, why TDesC & TDes don't disable copy constructor & operator = ? this is very easy error it you use something as: const TDesC &Func(); ... const TDesC d = Func() which should be like const TDesC &rd = Func();

Submitted by Anonymous on Thu, 2005-06-30 17:16.

In case of assignement, you can ASSERT before copying. While manipulating you can use AppendFormat() using Overflowhandler - cf Symbian docs.

Submitted by Tim (not verified) on Wed, 2005-07-06 18:02.

This page may contain an answer to your question about "why use Descriptors?":

http://www.thecodeproject.com/ce/Symbian_OS_design_faults.asp


Submitted by dotcdotc (not verified) on Thu, 2005-05-12 15:22.

I have a function which takes TDesC& as argument but I have TPtr8. How would I covert TPtr8 to TDesC&.

Submitted by Anonymous on Wed, 2005-07-27 15:23.

<n>

Submitted by Anonymous on Wed, 2005-07-27 15:28.

Sorry. Definetely there in the article should be just "Usage of TPtrC" without "n" between "less than" and "more than" signs, isn't it?

Submitted by Nagaraj Koti (not verified) on Thu, 2005-09-22 12:53.

i gone through the descriptor tutorial really its good and also it,s help for the beginers, but i did not come across any where in the tutorial how to create an array of descriptor like usage char array[] and char array[][] in C or C++, i am looking for the code how to create a array of TDes type.

Submitted by Anonymous on Sat, 2005-10-08 10:05.

well, for descritor array you could use "RPointerArray"

/geri-m


Submitted by ad (not verified) on Sat, 2006-01-21 07:47.

how can i convert TBuf8<6> to TDesC16 to display the contents of a file

Submitted by Xufun on Tue, 2008-09-02 04:07.

Good Article,
I got it,
Thanks !



copyright 2003-2009 NewLC SARL