Symbian OSDescriptorsv2.0a – 21 May 20081Andreas Jakl, 2008
DisclaimerThese slides are provided free of charge at http://www.symbianresources.com and are used during Symbian OS courses at the University of Applied Sciences in Hagenberg, Austria ( http://www.fh-hagenberg.at/ )Respecting the copyright laws, you are allowed to use them:for your own, personal, non-commercial usein the academic environmentIn all other cases (e.g. for commercial training), please contact andreas.jakl@fh-hagenberg.atThe correctness of the contents of these materials cannot be guaranteed. Andreas Jakl is not liable for incorrect information or damage that may arise from using the materials.Parts of these materials are based on information from Symbian Press-books published by John Wiley & Sons, Ltd. This document contains copyright materials which are proprietary to Symbian, UIQ, Nokia and SonyEricsson. “S60™” is a trademark of Nokia. “UIQ™” is a trademark of UIQ Technology. Pictures of mobile phones or applications are copyright their respective manufacturers / developers. “Symbian ™”, “Symbian OS ™” and all other Symbian-based marks and logos are trademarks of Symbian Software Limited and are used under license. © Symbian Software Limited 2006. Andreas Jakl, 20082
ContentsLiteralsDescriptorsTDes / TDesCTBuf / TBufCTPtr / TPtrCHBufCRBufDescriptorsasfunctionparameters / returnvaluesConvertingto/from UnicodeString NumberconversionAndreas Jakl, 20083
IntroductionWhy are they different to Strings?Andreas Jakl, 20084
Andreas Jakl, 20085hello\0Strings in Cchar* hello = "hello";Memory view:Function strlen()Reads from the beginning to '\0' and counts number of charschar*0x64243184
Descriptors – IntroductionDescriptor = Symbian OS string“self-describing”Holds length as well as type (= memory layout)Different to:CString (C++), Java Strings, ...  for descriptors, allocation and cleanup is managed by programmerC strings  Descriptors protect against buffer overrun and don’t use \0 terminationAndreas Jakl, 20086
Descriptors – MotivationWhy no normal strings?Minimal memory usageRequired efficiencyROM (Literals: _LIT!) – Stack – Heap?Constant – modifiable?Unicode(TBuf16 – TBuf8)Take a long time to get used to Andreas Jakl, 20087
UnicodeSymbian OS uses 16-bit text since Symbian OS v5u+All descriptors available twice8 bit (e.g. TBuf8)Used for binary data and ASCII text16 bit (e.g. TBuf16)Normally not used explicitly, instead:Build independent (e.g. TBuf)Currently always Unicodetypedef’d to 16 bit versionUse this for normal stringsAndreas Jakl, 20088
Literals_L, _LITAndreas Jakl, 20089
LiteralsIn reality _LIT is a macro, expands to create a:Constant descriptor, compiled to program binaryNot localisable  only use for testing, very simple applications or fixed strings (e.g. for protocols)!_LIT(KHello, “Hello”);Builds a named object called KHello of type TLitC16Stores the string Hello into the objectThe string is written to the program binaryAndreas Jakl, 200810
_LIT-MacroTLitChas the same memory layout like a descriptor can be used as a constant descriptor for function parameters (const TDesC&)_LIT(KHello, "Hello!");console->Printf(KHello);iLabel->SetTextL(KHello); can be casted to a descriptor through ()-operatorTInt length = KHello().Length();		// == 6Andreas Jakl, 200811
_L-Macro_L(“Hello”)Can be used directly as parameterconsole->Printf(_L(“Hello”));User::Panic(_L(“example.dll”), KErrNotSupported);Creates temporary TPtrC inefficient, deprecated!Both macros defined in e32def.hAndreas Jakl, 200812
ComparisonAndreas Jakl, 200813_L(“Hello”)(through macro)  TPtrC hello(_L(“Hello”))_LIT(KHello, “Hello”);ROMROMStack (temporary)‘H’5‘e’‘l’‘l’‘o’‘\0’‘H’5‘e’‘l’‘l’‘o’‘\0’<ptr>For completeness:Literals are actually ‘\0’-terminated because of the standard C++ compiler, but the additional ‘\0’-char not reflected in the saved lengthAll other descriptors are not ‘\0’-terminated!
DescriptorsTDes, TDesCAndreas Jakl, 200814
Modifiable?Do these methods modify the data?Andreas Jakl, 200815
Modifiable – SolutionDo these methods modify the data?Andreas Jakl, 200816 TDesC TDesdefined in ...
Constant – Modifiable?Modifiable (derived from TDes)Allow to modify data (replace chars, appending, ...)Non-modifiable (derived from TDesC)Constant data (read-only)Modify it anyway? Possible, if data is not in ROM:Get modifiable pointer descriptor to data using myText.Des();Andreas Jakl, 200817
Inheritance HierarchyAbstract base class because of:Generalisation(use base type for parameters!)Provide basic functions shared by all types (e.g. Compare(), Find(), Mid(), ...)Andreas Jakl, 200818constantmodifiable
TDesC / TDesBase class of all other descriptors (except Literals)Provide basic functionalityTDesC: Read-only access (compare, search, ...)TDes: Inherits from TDesC and adds modification functions.Saves maximum length to prevent overflow.Cannot be instantiatedAllow polymorphic use of descriptors Commonly used in function parametersDon’t care where data is storedAndreas Jakl, 200819
Storing the LengthConstant (TDesC)Modifiable (TDes)Andreas Jakl, 200820<length><string data>Depending on descriptor type:can directly contain the data or be a pointer to data on the stack,heap or ROM4 bytes<length><max.length><string data>4 bytes4 bytes
TypeFor Completeness:All Descriptors and Literals also store the type of the Descriptor (Stack, Heap, ROM, …)First 4 bits of iLength reduces max. length to 28 bitsUsed in common methods of TDesand TDesCto execute correct code depending on type using switch()-statement(Alternative: virtual functions, but that’d cause overhead)Andreas Jakl, 200821The type is normally not relevantfor the developer, therefore it is omitted in following slides for clarityTDesC<length><string data><type>4 bit28 bit4 bytes (32 bit)
Stack-Based Buffer DescriptorsTBuf, TBufCAndreas Jakl, 200822
Buffer DescriptorsComparable to (const) char[]of CDirectly contain the stringUse C++ templates to specify length (parameter)Andreas Jakl, 200823TBufC<5>Constant:‘H’5‘e’‘l’‘l’‘o’iLength(TDesC)Modifiable:TBuf<9>9‘H’5‘e’‘l’‘l’‘o’iLength(TDesC)iMaxLength(TDes)
Size, Length, MaxLengthTBuf<9> with text “Hello”Andreas Jakl, 2008249‘H’5‘e’‘l’‘l’‘o’...4 bytes4 bytes22Unicode characters!Length()  5 (characters)MaxLength()  9 (characters)Size()  10 (bytes)MaxSize()  18 (bytes)
Initializing the TBufDebugging in Carbide.c++: Assigning StringsAndreas Jakl, 200825// Define constant string literal_LIT(KString1, "Hello ");_LIT(KString2, "World");// Copy KString1 into new TBuf with max. length of 15TBuf<15> buf1(KString1);// Same as above, this time using Copy() and KString2TBuf<15> buf2;		// Initialize empty TBuf with max. length of 15buf2.Copy(KString2);// Append contents of buf2 to buf1buf1.Append(buf2);// Create constant descriptor based on KString1TBufC<15> cBuf1(KString1);// Replace contents of cBuf1 with contents of buf1cBuf1 = buf1;
Using the TBufAndreas Jakl, 200826_LIT(KHelloWorld, "Hello World");	// Defines constant string literalconstTIntmaxLength = 15;// Create a modifiable bufferTBuf<maxLength> buf;	TIntcurLength = buf.Length();		// ...... ?TInt maxLength2 = buf.MaxLength();	// ...... ?// Set the contents of the bufferbuf = KHelloWorld;curLength = buf.Length();			// ...... ?TIntcurSize = buf.Size();				// ...... ?TTextch = buf[1];					// ...... ?
Using the TBufAndreas Jakl, 200827_LIT(KHelloWorld, "Hello World");	// Defines constant string literalconstTIntmaxLength = 15;// Create a modifiable bufferTBuf<maxLength> buf;	TIntcurLength = buf.Length();		// == 0TInt maxLength2 = buf.MaxLength();	// == 20// Set the contents of the bufferbuf = KHelloWorld;curLength = buf.Length();			// == 11TIntcurSize = buf.Size();				// == 22TTextch = buf[1];					// == ‘e’
Maximum LengthAndreas Jakl, 200828_LIT(KHello, "Hello ");			// Defines constant string literalTBuf<15> buf(KHello);			// buf == “Hello ”buf.Append(KHello);			// buf == “Hello Hello “buf.Append(KHello);			// Exceeds maximum length  Panic!SDK-Doc for USER 11-panic:“This panic is raised when any operation that moves or copies data to a 16-bit variant descriptor, causes the length of that descriptor to exceed its maximum length. […]”
Pointer DescriptorsTPtr, TPtrCAndreas Jakl, 200829
Pointer DescriptorsComparable to (const) char* of CCan point to text on the heap, stack or ROMDo NOT own the data they point to!Andreas Jakl, 200830‘H’‘e’‘l’‘l’‘o’Constant:TPtrC0x642431845ROM, heaporstackiLength(TDesC)iPtr(TPtrC)‘H’‘e’‘l’‘l’‘o’TPtrModifiable:0x6424318459ROM, heaporstackiLength(TDesC)iPtr(TPtrC)iMaxLength(TDes)
TPtr – ExampleAndreas Jakl, 200831_LIT(KHelloWorld, "Hello World");	// Defines constant string literal// Create a constant buffer with contents of string literalTBufC<13> buf (KHelloWorld);// Get a pointer descriptor for the textTPtrptr = buf.Des();// Replace the 6th char with an '!', even though TBufC is actually constant!ptr[5] = '!';						// buf: "Hello!World"TBufC<13> (Stack)‘H’11‘e’‘l’‘l’‘o’‘!’‘W’‘o’‘r’‘l’‘d’TPtr(Stack)iLength(TDesC)11130x0303FE5CData iscopiedto thestackKHelloWorld(ROM)iLength(TDesC)iPtr(TPtrC)iMaxLength(TDes)‘H’11‘e’‘l’‘l’‘o’‘ ’‘W’‘o’‘r’‘l’‘d’‘\0’iLength
TPtrC: “=” versus “Set“Andreas Jakl, 200832// Create two literals_LIT(KHi, "Hi");_LIT(KSymbian, "Symbian");// Constant buffer descriptors, copy data from ROM to StackTBufC<10> bufHi(KHi);TBufC<10> bufSymbian(KSymbian);// ptr1 and ptr2 point to string data owned by TBufC'sTPtr ptr1(bufHi.Des());TPtr ptr2(bufSymbian.Des());ptr1 = ptr2;ptr1.Set(ptr2);ptr1  bufHi: “Symbian”ptr2  bufSymbian: “Symbian”bufHi: “Symbian”bufSymbian: “Symbian”… copies Data from buffer pointed toptr2 to buffer pointed to by ptr1ptr1  bufSymbian: “Symbian”ptr2  bufSymbian: “Symbian”bufHi: “Hi”bufSymbian: “Symbian”… sets ptr1 to point to same bufferas ptr2
Heap-Based Buffer DescriptorsHBufC, RBufAndreas Jakl, 200833
Use Heap-Based Buffer when…String data is not in ROM and not on stackStack size is a lot more limited than the heap!Length of buffer is not known at compile time, e.g.Loading strings from resource fileGetting strings from UI (query dialogs, ...)Receiving response from the webLonger lifetime than creatore.g. passing to an asynchronous functionAndreas Jakl, 200834
Constant Heap DescriptorComparable to (char*) malloc(length+1) of CData is stored on the heapAndreas Jakl, 200835Heap‘H’5‘e’‘l’‘l’‘o’HBufC*0x64243184Same layout as TBufC
HBufC ExampleAndreas Jakl, 200836Shorter variant:HBufC* hBuf = KHello().AllocLC();(Function of TDesC, creates and returns heap buffer based on a copy of its own data)_LIT(KHello, "Hello");// Create new HBufC with length of 5HBufC* hBuf = HBufC::NewLC(KHello().Length());// Copy data of KHello to heap allocated by hBuf*hBuf = KHello;[…]// Do cleanupCleanupStack::PopAndDestroy(1);Heap‘H’5‘e’‘l’‘l’‘o’HBufC*0x64243184KHello (ROM)Data is copiedto the heap‘H’5‘e’‘l’‘l’‘o’‘\0’iLength
Modifying HBufCModify HBufC through apointer descriptor:Andreas Jakl, 200837_LIT(KHello, "Hello!");_LIT(KWorld, "World!");HBufC* buf = HBufC::NewLC(KHello().Length());*buf = KHello;						// buf holds "Hello!", Length = 6// Increase heap buffer size - still holds "Hello!"buf = buf->ReAllocL(KHello().Length() + KWorld().Length());// New memory area has been reserved – update reference on CleanupStack!CleanupStack::Pop(buf);CleanupStack::PushL(buf);// Create pointer descriptor based on heap descriptorTPtrptr(buf->Des());				// Length = 6, MaxLength = 12ptr[KHello().Length() - 1] = ' ';		// buf holds "Hello "ptr.Append(KWorld);				// buf holds "Hello World!"CleanupStack::PopAndDestroy(buf);To access the data of an HBufC* (e.g. to use it for a TDesC&-parameter), you can write *hptr instead of creating a TPtrC with hptr->Des();
HBufC – Memory ViewAndreas Jakl, 200838TPtr12120x02704174iLength(TDesC)iPtr(TPtrC)iMaxLength(TDes)HeapHBufC*0x02704174‘H’12‘e’‘l’‘l’‘o’‘ ’‘W’‘o’‘r’‘l’‘d’‘!’
RBufAvailable since Symbian OS 8Owns and points to modifiable string data on the heapBehaves like a handle to a resource (Close() to free)Resize possible, but has to be done manuallySimilar to:TPtr, but owns data it points toHBufC, but easier to useCan be wrapper for HBufC-ObjectAndreas Jakl, 200839
RBuf – Memory LayoutAndreas Jakl, 200840HeapRBuf points directly to its owned data:‘H’‘e’‘l’‘l’‘o’RBuf0x6424318459iLength(TDesC)*iEPtrType(RBuf)iMaxLength(TDes)C++ Union (only one of both variables are used, depending on type)HeapRBuf points to owned HBufC:‘H’5‘e’‘l’‘l’‘o’RBuf590x64243184= contents of old HBufCiLength(TDesC)*iEBufCPtrType(RBuf)iMaxLength(TDes)
RBuf – ConstructionCreating an RBuf:Allocate own memoryRBufbuf;buf.CreateL(TIntaMaxLength);	// Create RBuf with max. lengthor: buf.CreateL(constTDesC &aDes);	// Copy data to own memoryTransfer ownership of HBufC(wrapper for HBufC)RBufbuf(HBufC* aHBuf);		// Transfer ownership of HBufC-dataor: buf.Assign(HBufC* aHBuf);Transfer ownership of existing memory areabuf.Assign(TUint16 *aHeapCell, TIntaMaxLength);Andreas Jakl, 200841
Using the RBufAndreas Jakl, 200842_LIT(KHelloWorld, "Hello World!");RBufheapBuf;// Create RBuf, copy contents of KHelloWorldheapBuf.CreateL(KHelloWorld);// Make sure Close() is called on RBuf in case of LeaveheapBuf.CleanupClosePushL();[…]// Calls Close() on the RBufCleanupStack::PopAndDestroy();Directly points to string data(ASCII 72 = “H” of “Hello World”)
RBuf – Memory viewAndreas Jakl, 200843Heap0x027d4174Hello WorldStackData iscopiedto theheap*iEPtrTypeROM11iMaxLengthRBufheapBufHello World\01111iLength
RBuf and HBufCAndreas Jakl, 200844_LIT(KHelloWorld, "Hello World!");HBufC* hptr;// Create heap descriptor which can hold up to 15 items. Current lenght = 0hptr = HBufC::NewL(15);// Assigns data to heap descriptor. Current length = 12*hptr = KHelloWorld;// Ownership of heap descriptor passed to RBufRBufbuf(hptr);// Close buffer and free resources - do not delete HBuf!buf.Close();
RBuf & HBufC – Memory ViewAndreas Jakl, 200845Heap0x027d4174Hello World11StackData is copiedto the heap*iEBufCPtrType11iMaxLengthRBuf bufROM11iLengthHello World\011HBufC* hptr... don’t delete twice, now the RBuf owns the memory!
One more ExampleIt’s recommended to use RBuf instead of HBufC*Andreas Jakl, 200846// Function returns HBufC*, we use RBuf to wrap it  simpler handling for us!RBufresString (iEikonEnv->AllocReadResourceL(someResourceId));// Leaving functions ahead, so push the RBuf on the CleanupStackresString.CleanupClosePushL();// Use modifiable descriptor to append new text...resString.ReAllocL(resString.Length() + 4);resString.Append(_L("-Foo"));[…]// Assign text to a label, resString is a TDesC as well, so it works without changes!SetLabelL(ELabel, resString);CleanupStack::PopAndDestroy(); 		// calls resString.Close();
RBuf vs. HBufC?Theoretically:Use HBufC for constant dataUse RBuf for modifiable dataHowever:As RBuf is a lot easier to use, consider always using RBufMost Symbian OS APIs operate using HBufCEither also use HBufC for these casesOr wrap HBufC with RBufAndreas Jakl, 200847
SummaryAbstract (TDes, TDesC)Base class of other descriptorsCannot be instantiatedUsed for function parametersLiteral (TLitC _LIT())Used to store non-modifiable, literal strings in codeBuffer (TBuf, TBufC)Data is stored on the stackSize specified at compile timeHeap (HBufC, RBuf)Data stored on the heapSize specified at run-timePointer (TPtr, TPtrC)References data stored outside the classAndreas Jakl, 200848
Lots of types? Decide:Andreas Jakl, 200849Is the descriptor modifiable?YESNOHas the memory for the descriptor data already been allocated elsewhere (heap or stack)?Has the memory for the descriptor data already been allocated elsewhere (heap or stack)?YESYESTPtrTPtrCWill the memory allocated be stack- or heap-based?Will the memory allocated be stack- or heap-based?HEAPHEAPRBufHBufCSTACKSTACKTBufTBufC
QuizAndreas Jakl, 200850TDesC::AllocLC()“Creates a new 16-bit heap descriptor, initializes it with a copy of this descriptor's data, and puts a pointer to the descriptor onto the cleanup stack.”Assign variables to the memory view:_LIT(KHello1, “Hello”);TPtrChello2 (KHello1);TBufC<5> hello3(KHello1);HBufC* hello4 = KHello1().AllocLC();Heaphello5Stack…?hello…?5ROM…?…?hello\055
Quiz – SolutionAssign variables to the memory view:Andreas Jakl, 200851_LIT(KHello1, “Hello”);TPtrChello2 (KHello1);TBufC<5> hello3(KHello1);HBufC* hello4 = KHello1().AllocLC();Heaphello5Stackhello4hellohello35ROMKHello1hello2hello\055
Using Descriptors in FunctionsThe daily life of a Symbian OS developer …Andreas Jakl, 200852
Function Argumentsvoid MyFunction(TBuf<8>aText)What if caller uses an RBuf, TPtr or TBuf<9>? References for base classes (TDes&, const TDesC&) should always be usedvoid SomeFunction(const TDesC& aReadOnlyDescriptor, TDes& aReadWriteDescriptor);Andreas Jakl, 200853
ExampleTInterrorCode = RFile.Read(TDes8& aDes);Function can find out max. length (aDes.MaxLength())Caller can get number of bytes read: des.Length()Compare that to the Win32-API …BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped); Andreas Jakl, 200854
Return HBufC*Make sure calling function knows it takes ownership!Don’t forget the cleanup stack if it is necessary!Andreas Jakl, 200855HBufC* CreateSomeDescriptorL() {	_LIT(KBert, "bert");// Createheap-baseddescriptorHBufC* newBert = KBert().AllocL();// Return ourHBufC*return (newBert);}HBufC* CreateSomeDescriptorLC() {	_LIT(KBert, "bert"); HBufC* newBert = KBert().AllocLC(); return (newBert);}
Better: RBufCreating a specific RBuf in a function:Andreas Jakl, 200856RBufmyBuf;myBuf.CleanupClosePushL();GetSomeDataL(myBuf);console->Printf(myBuf);CleanupStack::PopAndDestroy(myBuf);voidGetSomeDataL(RBuf&aBuf) {	_LIT(KHello, "Hello");// Allocatememory and copy „Hello“ to RBufaBuf.CreateL(KHello);}
Returning a TPtrCWhat’s wrong with the following code?Andreas Jakl, 200857TPtrCGetText() { // CreateTBufCbased on literaldescriptor	_LIT(KMyText, "My Text");TBufC<7> buf(KMyText());// Create a TPtrCbased on bufTPtrCbufPtr(buf);// Return theTPtrCreturn (bufPtr);}
Returning a TPtrC – SolutionbufPtr does not own the databuf is a local variable and ceases to exist when function is left Target of bufPtris no longer valid!Andreas Jakl, 200858TPtrCGetText() { // CreateTBufCbased on literaldescriptor	_LIT(KMyText, "My Text");TBufC<7> buf(KMyText());// Create a TPtrCbased on bufTPtrCbufPtr(buf);// Return theTPtrCreturn (bufPtr);}
Unicode and BinaryPainless conversionAndreas Jakl, 200859Conversion is more important than you might think: e.g. socket communication is 8 bit!
Converting from UnicodeSimple conversion by stripping alternate characters:Andreas Jakl, 200860TBuf8<3> cat(_L8("cat"));		// _L used for simplicityTBuf16<3> dog(_L16("dog"));cat.Copy(dog);				// cat now contains "dog"TDes8 catTDes16 dogcat.Copy(dog);Strips \0-paddingTDes8 cat
Converting to UnicodeSimple conversion by padding each character with trailing zero:Andreas Jakl, 200861TBuf8<5> small(_L8("small"));TBuf16<5> large(_L16("large"));large.Copy(small);				// large now contains "small"TDes8 smallTDes16 largelarge.Copy(small);Adds \0-paddingTDes8 large
Proper ConversionUse conversion library (charconv.lib)Requires:#include <charconv.h>#include <utf.h>Library: charconv.libAndreas Jakl, 200862// Russian text saved as UTF8_LIT8(KString8, "Телефон");TBufC8<20> source8(KString8);// Create target 16 bit buffer for Unicode stringRBuf target16;target16.CreateL(source8.Length());target16.CleanupClosePushL();// Use conversion library to convert from UTF8 to UnicodeCnvUtfConverter::ConvertToUnicodeFromUtf8(target16, source8);// Print results and do cleanupconsole->Printf(target16);CleanupStack::PopAndDestroy(1);
More about Descriptor UsageOther things you should knowAndreas Jakl, 200863
TLexGeneral string-parsing functions suitable for numeric format conversions and syntactical-element parsinge.g. parse GPS data (NMEA)Powerful, but very complexMore information at:http://descriptors.blogspot.com/2005/08/35-how-do-i-use-tlex.htmlAndreas Jakl, 200864
Conversion String  NumberString  Number: Provided by TDesNumber  String: Simple use of TLexAndreas Jakl, 200865_LIT(KTestString1, "54321");// Convertstring to numberTLexlex(KTestString1());TIntvalue = 0;User::LeaveIfError(lex.Val(value));ASSERT(value==54321);// Convertnumber to stringTBuf<8> buf;buf.Num(value);
Formatting TextIntegrate variables into textAppending text or numbersSimplest way: use the AppendNum()-function defined in TDesMake sure the target descriptor is large enough!Andreas Jakl, 200866_LIT(KText, "Number ");TBuf<15> myText(KText);myText.AppendNum(1);console->Printf(myText);
Formatting TextFormat stringsUse placeholders for elementsFull syntax in the SDK help: » Symbian OS vXX » Symbian OS guide » Base » Using User Library (E32) » Buffers and Strings » Using Descriptors » How to Use Descriptors » Format string syntaxConsole (format syntax directly integrated)Andreas Jakl, 200867_LIT(KName, "Joe Bloggs");_LIT(KText, "Name: %S, Age: %d");TBuf<30> myText;myText.Format(KText, &KName, 27);console->Printf(myText);TInt result = 0;_LIT(KFormatCompare1, "Compare() using str1 and str2 = %d\n");console->Printf(KFormatCompare1, result);
TFileNameDefinition of TFileName(e32const.h / e32cmn.h):const TIntKMaxFileName=0x100;		// = Decimal 256typedefTBuf<KMaxFileName> TFileName;Required size on the stack: 520 bytes2 x 256 data bytes (Unicode), 8 bytes for descriptor obj.Standard stack size in Symbian OS: 8kBTherefore:Do not allocate TFileName on the stack (however: instance var. of CBase-class is on the heap!)Do not pass it by value!… use RBuf instead!Andreas Jakl, 200868
Test your KnowledgeDid you understand everything?Andreas Jakl, 200869
ASD-like Question – Easy Which of the following statements about descriptors are correct?A. All descriptor classes, except RBuf, derive from TDesC.B. The first four bytes of a descriptor store the descriptor’s length and type.C. The descriptor classes do not use virtual functions to avoid the overhead of a virtual function pointer in every descriptor object.D. Modifiable descriptors use the NULL terminator to indicate the end of the descriptor data.E. All descriptors have “wide”, 16-bit characters.Andreas Jakl, 200870Copyright Meme Education, 2006http://www.meme-education.com/
SolutionA.Incorrect. RBuf derives from TDesC as well.B. Correct.C. Correct.D. Incorrect. The NULL terminator is not used by descriptors. Only Literals are \0-terminated because of the C++-compiler, but this is hidden from the developers.E. Incorrect. Descriptors are available as 8 bit and 16 bit variants.Andreas Jakl, 200871
ASD-like Question – MediumAndreas Jakl, 200872_LIT(KHello, "Hello!");TBufC<6> hello(KHello);_LIT(KBye, "Goodbye!");TBufC<8> bye(KBye);TPtrfoo(hello.Des());TIntlen = foo.Length();TIntmaxLen = foo.MaxLength();TPtr bar(bye.Des());foo.Set(bar);len = foo.Length();maxLen = foo.MaxLength();foo.Copy(KHello);len = foo.Length();maxLen = foo.MaxLength();Which of the following statements are correct?A. After executing line 2, a call to hello.MaxLength() returns 6.B. After executing line 6, len = 6; After line 7, maxLen = 6.C. After executing line 9, hello contains “Goodbye!”.D. After executing line 10, len = 8; After line 11, maxLen = 8.E. After executing line 13, len = 6; After line 14, maxLen = 6.Copyright Meme Education, 2006http://www.meme-education.com/
SolutionA.Incorrect. TBufC does not have a MaxLength()-function. This is defined in TDes base class.B. Correct.C. Incorrect. After the Set()-function, the foo-TPtr points to the same memory as the bar-TPtr. The buffers are not altered however. This would be the case with =.D. Correct. E. Incorrect. MaxLength = 8, as foo is now pointing to the buffer of the bar-TPtr, which is the bye-TBuf with a max. length of 8.Andreas Jakl, 200873
ASD-like Question – HardAndreas Jakl, 200874Which of the following uses of a descriptor should be reconsidered?A.	USE 1B.	USE 2C.	USE 3D.	USE 4E.	USE 5classCTestClass : publicCBase {public:staticCTestClass* NewL(constTFileNameaFilename); // USE 1public:inlineconstTDesC& FileName() {return (iFileName);}; // USE 2voidSendDataL(constTBufC<20>& aData); // USE 3voidReceiveDataL(TDes& aData); // USE 4private:	// Construction code omitted for clarityprivate:TFileNameiFileName; // USE 5};Copyright Meme Education, 2006http://www.meme-education.com/
SolutionA.Reconsider. TFileName should be passed by reference, not by value. B. OK.C. Reconsider. Use generic parameter instead (const TDesC& aData).D. OK. E. OK. Andreas Jakl, 200875
ResourcesFamous blogs with answers to common problems:http://descriptors.blogspot.com/http://descriptor-tips.blogspot.com/Detailed information in the books:Symbian OS C++ for Mobile Phones, Vol. 3Symbian OS ExplainedAndreas Jakl, 200876Unfortunately this book do not cover the most recent addition to Symbian OS, the RBuf. Apart from this minor disadvantage, it is very useful.
Thanks for your attentionThat’s it!Andreas Jakl, 200877

Symbian OS - Descriptors

  • 1.
    Symbian OSDescriptorsv2.0a –21 May 20081Andreas Jakl, 2008
  • 2.
    DisclaimerThese slides areprovided free of charge at http://www.symbianresources.com and are used during Symbian OS courses at the University of Applied Sciences in Hagenberg, Austria ( http://www.fh-hagenberg.at/ )Respecting the copyright laws, you are allowed to use them:for your own, personal, non-commercial usein the academic environmentIn all other cases (e.g. for commercial training), please contact andreas.jakl@fh-hagenberg.atThe correctness of the contents of these materials cannot be guaranteed. Andreas Jakl is not liable for incorrect information or damage that may arise from using the materials.Parts of these materials are based on information from Symbian Press-books published by John Wiley & Sons, Ltd. This document contains copyright materials which are proprietary to Symbian, UIQ, Nokia and SonyEricsson. “S60™” is a trademark of Nokia. “UIQ™” is a trademark of UIQ Technology. Pictures of mobile phones or applications are copyright their respective manufacturers / developers. “Symbian ™”, “Symbian OS ™” and all other Symbian-based marks and logos are trademarks of Symbian Software Limited and are used under license. © Symbian Software Limited 2006. Andreas Jakl, 20082
  • 3.
    ContentsLiteralsDescriptorsTDes / TDesCTBuf/ TBufCTPtr / TPtrCHBufCRBufDescriptorsasfunctionparameters / returnvaluesConvertingto/from UnicodeString NumberconversionAndreas Jakl, 20083
  • 4.
    IntroductionWhy are theydifferent to Strings?Andreas Jakl, 20084
  • 5.
    Andreas Jakl, 20085hello\0Stringsin Cchar* hello = "hello";Memory view:Function strlen()Reads from the beginning to '\0' and counts number of charschar*0x64243184
  • 6.
    Descriptors – IntroductionDescriptor= Symbian OS string“self-describing”Holds length as well as type (= memory layout)Different to:CString (C++), Java Strings, ...  for descriptors, allocation and cleanup is managed by programmerC strings  Descriptors protect against buffer overrun and don’t use \0 terminationAndreas Jakl, 20086
  • 7.
    Descriptors – MotivationWhyno normal strings?Minimal memory usageRequired efficiencyROM (Literals: _LIT!) – Stack – Heap?Constant – modifiable?Unicode(TBuf16 – TBuf8)Take a long time to get used to Andreas Jakl, 20087
  • 8.
    UnicodeSymbian OS uses16-bit text since Symbian OS v5u+All descriptors available twice8 bit (e.g. TBuf8)Used for binary data and ASCII text16 bit (e.g. TBuf16)Normally not used explicitly, instead:Build independent (e.g. TBuf)Currently always Unicodetypedef’d to 16 bit versionUse this for normal stringsAndreas Jakl, 20088
  • 9.
  • 10.
    LiteralsIn reality _LITis a macro, expands to create a:Constant descriptor, compiled to program binaryNot localisable  only use for testing, very simple applications or fixed strings (e.g. for protocols)!_LIT(KHello, “Hello”);Builds a named object called KHello of type TLitC16Stores the string Hello into the objectThe string is written to the program binaryAndreas Jakl, 200810
  • 11.
    _LIT-MacroTLitChas the samememory layout like a descriptor can be used as a constant descriptor for function parameters (const TDesC&)_LIT(KHello, "Hello!");console->Printf(KHello);iLabel->SetTextL(KHello); can be casted to a descriptor through ()-operatorTInt length = KHello().Length(); // == 6Andreas Jakl, 200811
  • 12.
    _L-Macro_L(“Hello”)Can be useddirectly as parameterconsole->Printf(_L(“Hello”));User::Panic(_L(“example.dll”), KErrNotSupported);Creates temporary TPtrC inefficient, deprecated!Both macros defined in e32def.hAndreas Jakl, 200812
  • 13.
    ComparisonAndreas Jakl, 200813_L(“Hello”)(throughmacro)  TPtrC hello(_L(“Hello”))_LIT(KHello, “Hello”);ROMROMStack (temporary)‘H’5‘e’‘l’‘l’‘o’‘\0’‘H’5‘e’‘l’‘l’‘o’‘\0’<ptr>For completeness:Literals are actually ‘\0’-terminated because of the standard C++ compiler, but the additional ‘\0’-char not reflected in the saved lengthAll other descriptors are not ‘\0’-terminated!
  • 14.
  • 15.
    Modifiable?Do these methodsmodify the data?Andreas Jakl, 200815
  • 16.
    Modifiable – SolutionDothese methods modify the data?Andreas Jakl, 200816 TDesC TDesdefined in ...
  • 17.
    Constant – Modifiable?Modifiable(derived from TDes)Allow to modify data (replace chars, appending, ...)Non-modifiable (derived from TDesC)Constant data (read-only)Modify it anyway? Possible, if data is not in ROM:Get modifiable pointer descriptor to data using myText.Des();Andreas Jakl, 200817
  • 18.
    Inheritance HierarchyAbstract baseclass because of:Generalisation(use base type for parameters!)Provide basic functions shared by all types (e.g. Compare(), Find(), Mid(), ...)Andreas Jakl, 200818constantmodifiable
  • 19.
    TDesC / TDesBaseclass of all other descriptors (except Literals)Provide basic functionalityTDesC: Read-only access (compare, search, ...)TDes: Inherits from TDesC and adds modification functions.Saves maximum length to prevent overflow.Cannot be instantiatedAllow polymorphic use of descriptors Commonly used in function parametersDon’t care where data is storedAndreas Jakl, 200819
  • 20.
    Storing the LengthConstant(TDesC)Modifiable (TDes)Andreas Jakl, 200820<length><string data>Depending on descriptor type:can directly contain the data or be a pointer to data on the stack,heap or ROM4 bytes<length><max.length><string data>4 bytes4 bytes
  • 21.
    TypeFor Completeness:All Descriptorsand Literals also store the type of the Descriptor (Stack, Heap, ROM, …)First 4 bits of iLength reduces max. length to 28 bitsUsed in common methods of TDesand TDesCto execute correct code depending on type using switch()-statement(Alternative: virtual functions, but that’d cause overhead)Andreas Jakl, 200821The type is normally not relevantfor the developer, therefore it is omitted in following slides for clarityTDesC<length><string data><type>4 bit28 bit4 bytes (32 bit)
  • 22.
    Stack-Based Buffer DescriptorsTBuf,TBufCAndreas Jakl, 200822
  • 23.
    Buffer DescriptorsComparable to(const) char[]of CDirectly contain the stringUse C++ templates to specify length (parameter)Andreas Jakl, 200823TBufC<5>Constant:‘H’5‘e’‘l’‘l’‘o’iLength(TDesC)Modifiable:TBuf<9>9‘H’5‘e’‘l’‘l’‘o’iLength(TDesC)iMaxLength(TDes)
  • 24.
    Size, Length, MaxLengthTBuf<9>with text “Hello”Andreas Jakl, 2008249‘H’5‘e’‘l’‘l’‘o’...4 bytes4 bytes22Unicode characters!Length()  5 (characters)MaxLength()  9 (characters)Size()  10 (bytes)MaxSize()  18 (bytes)
  • 25.
    Initializing the TBufDebuggingin Carbide.c++: Assigning StringsAndreas Jakl, 200825// Define constant string literal_LIT(KString1, "Hello ");_LIT(KString2, "World");// Copy KString1 into new TBuf with max. length of 15TBuf<15> buf1(KString1);// Same as above, this time using Copy() and KString2TBuf<15> buf2; // Initialize empty TBuf with max. length of 15buf2.Copy(KString2);// Append contents of buf2 to buf1buf1.Append(buf2);// Create constant descriptor based on KString1TBufC<15> cBuf1(KString1);// Replace contents of cBuf1 with contents of buf1cBuf1 = buf1;
  • 26.
    Using the TBufAndreasJakl, 200826_LIT(KHelloWorld, "Hello World"); // Defines constant string literalconstTIntmaxLength = 15;// Create a modifiable bufferTBuf<maxLength> buf; TIntcurLength = buf.Length(); // ...... ?TInt maxLength2 = buf.MaxLength(); // ...... ?// Set the contents of the bufferbuf = KHelloWorld;curLength = buf.Length(); // ...... ?TIntcurSize = buf.Size(); // ...... ?TTextch = buf[1]; // ...... ?
  • 27.
    Using the TBufAndreasJakl, 200827_LIT(KHelloWorld, "Hello World"); // Defines constant string literalconstTIntmaxLength = 15;// Create a modifiable bufferTBuf<maxLength> buf; TIntcurLength = buf.Length(); // == 0TInt maxLength2 = buf.MaxLength(); // == 20// Set the contents of the bufferbuf = KHelloWorld;curLength = buf.Length(); // == 11TIntcurSize = buf.Size(); // == 22TTextch = buf[1]; // == ‘e’
  • 28.
    Maximum LengthAndreas Jakl,200828_LIT(KHello, "Hello "); // Defines constant string literalTBuf<15> buf(KHello); // buf == “Hello ”buf.Append(KHello); // buf == “Hello Hello “buf.Append(KHello); // Exceeds maximum length  Panic!SDK-Doc for USER 11-panic:“This panic is raised when any operation that moves or copies data to a 16-bit variant descriptor, causes the length of that descriptor to exceed its maximum length. […]”
  • 29.
  • 30.
    Pointer DescriptorsComparable to(const) char* of CCan point to text on the heap, stack or ROMDo NOT own the data they point to!Andreas Jakl, 200830‘H’‘e’‘l’‘l’‘o’Constant:TPtrC0x642431845ROM, heaporstackiLength(TDesC)iPtr(TPtrC)‘H’‘e’‘l’‘l’‘o’TPtrModifiable:0x6424318459ROM, heaporstackiLength(TDesC)iPtr(TPtrC)iMaxLength(TDes)
  • 31.
    TPtr – ExampleAndreasJakl, 200831_LIT(KHelloWorld, "Hello World"); // Defines constant string literal// Create a constant buffer with contents of string literalTBufC<13> buf (KHelloWorld);// Get a pointer descriptor for the textTPtrptr = buf.Des();// Replace the 6th char with an '!', even though TBufC is actually constant!ptr[5] = '!'; // buf: "Hello!World"TBufC<13> (Stack)‘H’11‘e’‘l’‘l’‘o’‘!’‘W’‘o’‘r’‘l’‘d’TPtr(Stack)iLength(TDesC)11130x0303FE5CData iscopiedto thestackKHelloWorld(ROM)iLength(TDesC)iPtr(TPtrC)iMaxLength(TDes)‘H’11‘e’‘l’‘l’‘o’‘ ’‘W’‘o’‘r’‘l’‘d’‘\0’iLength
  • 32.
    TPtrC: “=” versus“Set“Andreas Jakl, 200832// Create two literals_LIT(KHi, "Hi");_LIT(KSymbian, "Symbian");// Constant buffer descriptors, copy data from ROM to StackTBufC<10> bufHi(KHi);TBufC<10> bufSymbian(KSymbian);// ptr1 and ptr2 point to string data owned by TBufC'sTPtr ptr1(bufHi.Des());TPtr ptr2(bufSymbian.Des());ptr1 = ptr2;ptr1.Set(ptr2);ptr1  bufHi: “Symbian”ptr2  bufSymbian: “Symbian”bufHi: “Symbian”bufSymbian: “Symbian”… copies Data from buffer pointed toptr2 to buffer pointed to by ptr1ptr1  bufSymbian: “Symbian”ptr2  bufSymbian: “Symbian”bufHi: “Hi”bufSymbian: “Symbian”… sets ptr1 to point to same bufferas ptr2
  • 33.
    Heap-Based Buffer DescriptorsHBufC,RBufAndreas Jakl, 200833
  • 34.
    Use Heap-Based Bufferwhen…String data is not in ROM and not on stackStack size is a lot more limited than the heap!Length of buffer is not known at compile time, e.g.Loading strings from resource fileGetting strings from UI (query dialogs, ...)Receiving response from the webLonger lifetime than creatore.g. passing to an asynchronous functionAndreas Jakl, 200834
  • 35.
    Constant Heap DescriptorComparableto (char*) malloc(length+1) of CData is stored on the heapAndreas Jakl, 200835Heap‘H’5‘e’‘l’‘l’‘o’HBufC*0x64243184Same layout as TBufC
  • 36.
    HBufC ExampleAndreas Jakl,200836Shorter variant:HBufC* hBuf = KHello().AllocLC();(Function of TDesC, creates and returns heap buffer based on a copy of its own data)_LIT(KHello, "Hello");// Create new HBufC with length of 5HBufC* hBuf = HBufC::NewLC(KHello().Length());// Copy data of KHello to heap allocated by hBuf*hBuf = KHello;[…]// Do cleanupCleanupStack::PopAndDestroy(1);Heap‘H’5‘e’‘l’‘l’‘o’HBufC*0x64243184KHello (ROM)Data is copiedto the heap‘H’5‘e’‘l’‘l’‘o’‘\0’iLength
  • 37.
    Modifying HBufCModify HBufCthrough apointer descriptor:Andreas Jakl, 200837_LIT(KHello, "Hello!");_LIT(KWorld, "World!");HBufC* buf = HBufC::NewLC(KHello().Length());*buf = KHello; // buf holds "Hello!", Length = 6// Increase heap buffer size - still holds "Hello!"buf = buf->ReAllocL(KHello().Length() + KWorld().Length());// New memory area has been reserved – update reference on CleanupStack!CleanupStack::Pop(buf);CleanupStack::PushL(buf);// Create pointer descriptor based on heap descriptorTPtrptr(buf->Des()); // Length = 6, MaxLength = 12ptr[KHello().Length() - 1] = ' '; // buf holds "Hello "ptr.Append(KWorld); // buf holds "Hello World!"CleanupStack::PopAndDestroy(buf);To access the data of an HBufC* (e.g. to use it for a TDesC&-parameter), you can write *hptr instead of creating a TPtrC with hptr->Des();
  • 38.
    HBufC – MemoryViewAndreas Jakl, 200838TPtr12120x02704174iLength(TDesC)iPtr(TPtrC)iMaxLength(TDes)HeapHBufC*0x02704174‘H’12‘e’‘l’‘l’‘o’‘ ’‘W’‘o’‘r’‘l’‘d’‘!’
  • 39.
    RBufAvailable since SymbianOS 8Owns and points to modifiable string data on the heapBehaves like a handle to a resource (Close() to free)Resize possible, but has to be done manuallySimilar to:TPtr, but owns data it points toHBufC, but easier to useCan be wrapper for HBufC-ObjectAndreas Jakl, 200839
  • 40.
    RBuf – MemoryLayoutAndreas Jakl, 200840HeapRBuf points directly to its owned data:‘H’‘e’‘l’‘l’‘o’RBuf0x6424318459iLength(TDesC)*iEPtrType(RBuf)iMaxLength(TDes)C++ Union (only one of both variables are used, depending on type)HeapRBuf points to owned HBufC:‘H’5‘e’‘l’‘l’‘o’RBuf590x64243184= contents of old HBufCiLength(TDesC)*iEBufCPtrType(RBuf)iMaxLength(TDes)
  • 41.
    RBuf – ConstructionCreatingan RBuf:Allocate own memoryRBufbuf;buf.CreateL(TIntaMaxLength); // Create RBuf with max. lengthor: buf.CreateL(constTDesC &aDes); // Copy data to own memoryTransfer ownership of HBufC(wrapper for HBufC)RBufbuf(HBufC* aHBuf); // Transfer ownership of HBufC-dataor: buf.Assign(HBufC* aHBuf);Transfer ownership of existing memory areabuf.Assign(TUint16 *aHeapCell, TIntaMaxLength);Andreas Jakl, 200841
  • 42.
    Using the RBufAndreasJakl, 200842_LIT(KHelloWorld, "Hello World!");RBufheapBuf;// Create RBuf, copy contents of KHelloWorldheapBuf.CreateL(KHelloWorld);// Make sure Close() is called on RBuf in case of LeaveheapBuf.CleanupClosePushL();[…]// Calls Close() on the RBufCleanupStack::PopAndDestroy();Directly points to string data(ASCII 72 = “H” of “Hello World”)
  • 43.
    RBuf – MemoryviewAndreas Jakl, 200843Heap0x027d4174Hello WorldStackData iscopiedto theheap*iEPtrTypeROM11iMaxLengthRBufheapBufHello World\01111iLength
  • 44.
    RBuf and HBufCAndreasJakl, 200844_LIT(KHelloWorld, "Hello World!");HBufC* hptr;// Create heap descriptor which can hold up to 15 items. Current lenght = 0hptr = HBufC::NewL(15);// Assigns data to heap descriptor. Current length = 12*hptr = KHelloWorld;// Ownership of heap descriptor passed to RBufRBufbuf(hptr);// Close buffer and free resources - do not delete HBuf!buf.Close();
  • 45.
    RBuf & HBufC– Memory ViewAndreas Jakl, 200845Heap0x027d4174Hello World11StackData is copiedto the heap*iEBufCPtrType11iMaxLengthRBuf bufROM11iLengthHello World\011HBufC* hptr... don’t delete twice, now the RBuf owns the memory!
  • 46.
    One more ExampleIt’srecommended to use RBuf instead of HBufC*Andreas Jakl, 200846// Function returns HBufC*, we use RBuf to wrap it  simpler handling for us!RBufresString (iEikonEnv->AllocReadResourceL(someResourceId));// Leaving functions ahead, so push the RBuf on the CleanupStackresString.CleanupClosePushL();// Use modifiable descriptor to append new text...resString.ReAllocL(resString.Length() + 4);resString.Append(_L("-Foo"));[…]// Assign text to a label, resString is a TDesC as well, so it works without changes!SetLabelL(ELabel, resString);CleanupStack::PopAndDestroy(); // calls resString.Close();
  • 47.
    RBuf vs. HBufC?Theoretically:UseHBufC for constant dataUse RBuf for modifiable dataHowever:As RBuf is a lot easier to use, consider always using RBufMost Symbian OS APIs operate using HBufCEither also use HBufC for these casesOr wrap HBufC with RBufAndreas Jakl, 200847
  • 48.
    SummaryAbstract (TDes, TDesC)Baseclass of other descriptorsCannot be instantiatedUsed for function parametersLiteral (TLitC _LIT())Used to store non-modifiable, literal strings in codeBuffer (TBuf, TBufC)Data is stored on the stackSize specified at compile timeHeap (HBufC, RBuf)Data stored on the heapSize specified at run-timePointer (TPtr, TPtrC)References data stored outside the classAndreas Jakl, 200848
  • 49.
    Lots of types?Decide:Andreas Jakl, 200849Is the descriptor modifiable?YESNOHas the memory for the descriptor data already been allocated elsewhere (heap or stack)?Has the memory for the descriptor data already been allocated elsewhere (heap or stack)?YESYESTPtrTPtrCWill the memory allocated be stack- or heap-based?Will the memory allocated be stack- or heap-based?HEAPHEAPRBufHBufCSTACKSTACKTBufTBufC
  • 50.
    QuizAndreas Jakl, 200850TDesC::AllocLC()“Createsa new 16-bit heap descriptor, initializes it with a copy of this descriptor's data, and puts a pointer to the descriptor onto the cleanup stack.”Assign variables to the memory view:_LIT(KHello1, “Hello”);TPtrChello2 (KHello1);TBufC<5> hello3(KHello1);HBufC* hello4 = KHello1().AllocLC();Heaphello5Stack…?hello…?5ROM…?…?hello\055
  • 51.
    Quiz – SolutionAssignvariables to the memory view:Andreas Jakl, 200851_LIT(KHello1, “Hello”);TPtrChello2 (KHello1);TBufC<5> hello3(KHello1);HBufC* hello4 = KHello1().AllocLC();Heaphello5Stackhello4hellohello35ROMKHello1hello2hello\055
  • 52.
    Using Descriptors inFunctionsThe daily life of a Symbian OS developer …Andreas Jakl, 200852
  • 53.
    Function Argumentsvoid MyFunction(TBuf<8>aText)Whatif caller uses an RBuf, TPtr or TBuf<9>? References for base classes (TDes&, const TDesC&) should always be usedvoid SomeFunction(const TDesC& aReadOnlyDescriptor, TDes& aReadWriteDescriptor);Andreas Jakl, 200853
  • 54.
    ExampleTInterrorCode = RFile.Read(TDes8&aDes);Function can find out max. length (aDes.MaxLength())Caller can get number of bytes read: des.Length()Compare that to the Win32-API …BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped); Andreas Jakl, 200854
  • 55.
    Return HBufC*Make surecalling function knows it takes ownership!Don’t forget the cleanup stack if it is necessary!Andreas Jakl, 200855HBufC* CreateSomeDescriptorL() { _LIT(KBert, "bert");// Createheap-baseddescriptorHBufC* newBert = KBert().AllocL();// Return ourHBufC*return (newBert);}HBufC* CreateSomeDescriptorLC() { _LIT(KBert, "bert"); HBufC* newBert = KBert().AllocLC(); return (newBert);}
  • 56.
    Better: RBufCreating aspecific RBuf in a function:Andreas Jakl, 200856RBufmyBuf;myBuf.CleanupClosePushL();GetSomeDataL(myBuf);console->Printf(myBuf);CleanupStack::PopAndDestroy(myBuf);voidGetSomeDataL(RBuf&aBuf) { _LIT(KHello, "Hello");// Allocatememory and copy „Hello“ to RBufaBuf.CreateL(KHello);}
  • 57.
    Returning a TPtrCWhat’swrong with the following code?Andreas Jakl, 200857TPtrCGetText() { // CreateTBufCbased on literaldescriptor _LIT(KMyText, "My Text");TBufC<7> buf(KMyText());// Create a TPtrCbased on bufTPtrCbufPtr(buf);// Return theTPtrCreturn (bufPtr);}
  • 58.
    Returning a TPtrC– SolutionbufPtr does not own the databuf is a local variable and ceases to exist when function is left Target of bufPtris no longer valid!Andreas Jakl, 200858TPtrCGetText() { // CreateTBufCbased on literaldescriptor _LIT(KMyText, "My Text");TBufC<7> buf(KMyText());// Create a TPtrCbased on bufTPtrCbufPtr(buf);// Return theTPtrCreturn (bufPtr);}
  • 59.
    Unicode and BinaryPainlessconversionAndreas Jakl, 200859Conversion is more important than you might think: e.g. socket communication is 8 bit!
  • 60.
    Converting from UnicodeSimpleconversion by stripping alternate characters:Andreas Jakl, 200860TBuf8<3> cat(_L8("cat")); // _L used for simplicityTBuf16<3> dog(_L16("dog"));cat.Copy(dog); // cat now contains "dog"TDes8 catTDes16 dogcat.Copy(dog);Strips \0-paddingTDes8 cat
  • 61.
    Converting to UnicodeSimpleconversion by padding each character with trailing zero:Andreas Jakl, 200861TBuf8<5> small(_L8("small"));TBuf16<5> large(_L16("large"));large.Copy(small); // large now contains "small"TDes8 smallTDes16 largelarge.Copy(small);Adds \0-paddingTDes8 large
  • 62.
    Proper ConversionUse conversionlibrary (charconv.lib)Requires:#include <charconv.h>#include <utf.h>Library: charconv.libAndreas Jakl, 200862// Russian text saved as UTF8_LIT8(KString8, "Телефон");TBufC8<20> source8(KString8);// Create target 16 bit buffer for Unicode stringRBuf target16;target16.CreateL(source8.Length());target16.CleanupClosePushL();// Use conversion library to convert from UTF8 to UnicodeCnvUtfConverter::ConvertToUnicodeFromUtf8(target16, source8);// Print results and do cleanupconsole->Printf(target16);CleanupStack::PopAndDestroy(1);
  • 63.
    More about DescriptorUsageOther things you should knowAndreas Jakl, 200863
  • 64.
    TLexGeneral string-parsing functionssuitable for numeric format conversions and syntactical-element parsinge.g. parse GPS data (NMEA)Powerful, but very complexMore information at:http://descriptors.blogspot.com/2005/08/35-how-do-i-use-tlex.htmlAndreas Jakl, 200864
  • 65.
    Conversion String NumberString  Number: Provided by TDesNumber  String: Simple use of TLexAndreas Jakl, 200865_LIT(KTestString1, "54321");// Convertstring to numberTLexlex(KTestString1());TIntvalue = 0;User::LeaveIfError(lex.Val(value));ASSERT(value==54321);// Convertnumber to stringTBuf<8> buf;buf.Num(value);
  • 66.
    Formatting TextIntegrate variablesinto textAppending text or numbersSimplest way: use the AppendNum()-function defined in TDesMake sure the target descriptor is large enough!Andreas Jakl, 200866_LIT(KText, "Number ");TBuf<15> myText(KText);myText.AppendNum(1);console->Printf(myText);
  • 67.
    Formatting TextFormat stringsUseplaceholders for elementsFull syntax in the SDK help: » Symbian OS vXX » Symbian OS guide » Base » Using User Library (E32) » Buffers and Strings » Using Descriptors » How to Use Descriptors » Format string syntaxConsole (format syntax directly integrated)Andreas Jakl, 200867_LIT(KName, "Joe Bloggs");_LIT(KText, "Name: %S, Age: %d");TBuf<30> myText;myText.Format(KText, &KName, 27);console->Printf(myText);TInt result = 0;_LIT(KFormatCompare1, "Compare() using str1 and str2 = %d\n");console->Printf(KFormatCompare1, result);
  • 68.
    TFileNameDefinition of TFileName(e32const.h/ e32cmn.h):const TIntKMaxFileName=0x100; // = Decimal 256typedefTBuf<KMaxFileName> TFileName;Required size on the stack: 520 bytes2 x 256 data bytes (Unicode), 8 bytes for descriptor obj.Standard stack size in Symbian OS: 8kBTherefore:Do not allocate TFileName on the stack (however: instance var. of CBase-class is on the heap!)Do not pass it by value!… use RBuf instead!Andreas Jakl, 200868
  • 69.
    Test your KnowledgeDidyou understand everything?Andreas Jakl, 200869
  • 70.
    ASD-like Question –Easy Which of the following statements about descriptors are correct?A. All descriptor classes, except RBuf, derive from TDesC.B. The first four bytes of a descriptor store the descriptor’s length and type.C. The descriptor classes do not use virtual functions to avoid the overhead of a virtual function pointer in every descriptor object.D. Modifiable descriptors use the NULL terminator to indicate the end of the descriptor data.E. All descriptors have “wide”, 16-bit characters.Andreas Jakl, 200870Copyright Meme Education, 2006http://www.meme-education.com/
  • 71.
    SolutionA.Incorrect. RBuf derivesfrom TDesC as well.B. Correct.C. Correct.D. Incorrect. The NULL terminator is not used by descriptors. Only Literals are \0-terminated because of the C++-compiler, but this is hidden from the developers.E. Incorrect. Descriptors are available as 8 bit and 16 bit variants.Andreas Jakl, 200871
  • 72.
    ASD-like Question –MediumAndreas Jakl, 200872_LIT(KHello, "Hello!");TBufC<6> hello(KHello);_LIT(KBye, "Goodbye!");TBufC<8> bye(KBye);TPtrfoo(hello.Des());TIntlen = foo.Length();TIntmaxLen = foo.MaxLength();TPtr bar(bye.Des());foo.Set(bar);len = foo.Length();maxLen = foo.MaxLength();foo.Copy(KHello);len = foo.Length();maxLen = foo.MaxLength();Which of the following statements are correct?A. After executing line 2, a call to hello.MaxLength() returns 6.B. After executing line 6, len = 6; After line 7, maxLen = 6.C. After executing line 9, hello contains “Goodbye!”.D. After executing line 10, len = 8; After line 11, maxLen = 8.E. After executing line 13, len = 6; After line 14, maxLen = 6.Copyright Meme Education, 2006http://www.meme-education.com/
  • 73.
    SolutionA.Incorrect. TBufC doesnot have a MaxLength()-function. This is defined in TDes base class.B. Correct.C. Incorrect. After the Set()-function, the foo-TPtr points to the same memory as the bar-TPtr. The buffers are not altered however. This would be the case with =.D. Correct. E. Incorrect. MaxLength = 8, as foo is now pointing to the buffer of the bar-TPtr, which is the bye-TBuf with a max. length of 8.Andreas Jakl, 200873
  • 74.
    ASD-like Question –HardAndreas Jakl, 200874Which of the following uses of a descriptor should be reconsidered?A. USE 1B. USE 2C. USE 3D. USE 4E. USE 5classCTestClass : publicCBase {public:staticCTestClass* NewL(constTFileNameaFilename); // USE 1public:inlineconstTDesC& FileName() {return (iFileName);}; // USE 2voidSendDataL(constTBufC<20>& aData); // USE 3voidReceiveDataL(TDes& aData); // USE 4private: // Construction code omitted for clarityprivate:TFileNameiFileName; // USE 5};Copyright Meme Education, 2006http://www.meme-education.com/
  • 75.
    SolutionA.Reconsider. TFileName shouldbe passed by reference, not by value. B. OK.C. Reconsider. Use generic parameter instead (const TDesC& aData).D. OK. E. OK. Andreas Jakl, 200875
  • 76.
    ResourcesFamous blogs withanswers to common problems:http://descriptors.blogspot.com/http://descriptor-tips.blogspot.com/Detailed information in the books:Symbian OS C++ for Mobile Phones, Vol. 3Symbian OS ExplainedAndreas Jakl, 200876Unfortunately this book do not cover the most recent addition to Symbian OS, the RBuf. Apart from this minor disadvantage, it is very useful.
  • 77.
    Thanks for yourattentionThat’s it!Andreas Jakl, 200877