Converting strings and buffers between Symbian and Qt

Symbian's strings are called descriptors and in most cases are easily converted to Qt strings. Binary data buffers work in a similar way. Both Symbian and Qt have different strengths for character conversion.

Symbian strings

Symbian C++ uses descriptors to handle both text and data. Descriptors are self-describing: they use the minimum amount of memory to store the string data and information about its length and memory layout. Descriptors do not resize automatically, and instead panic if an operation goes over the buffer length. This promotes robust code on devices that are designed to be rarely or never rebooted. As mentioned above, they can be used for both text and data because the length is not determined from the presence of NULL ('\0') terminators.

Symbian's descriptor class hierarchy is complicated; providing concrete modifiable and non-modifiable descriptors that store their data on the stack or heap, and a number of base classes that are used for function return types and parameters, but which are not intended for instantiation (such as TDes and TDesC). There are even some pointer descriptors (TPtr, TPtrC) which simply point to data stored in other locations.

Every descriptor class comes in a narrow (8 bit) and wide (16 bit) variant (such as RBuf8 and RBuf16, respectively). The 8 bit variant is primarily used for data, while the 16 bit variant is used for Unicode text. For string data you actually use the bare version of the descriptors (such as RBuf) shown in the figure. This is a typedef over the 16 bit variant on all current versions of the Symbian platform.

For detailed information on descriptors, see Descriptors Overview and Using Descriptors. You should also be aware of TLex (which is used for lexical parsing and converting numeric strings into number types), the various typdef classes used for characters: TText, TChar, and Charconv for conversion between character sets. (Charconv converts more sets than Qt and is extensible.)

Qt strings

Qt uses a single class, QString for almost all Unicode string handling. The class provides almost all functionality you might need, including string comparison, conversion to and from numeric types, and conversion between character sets. The class integrates with Qt's regular expression classes to provide powerful parsing and string manipulation. Its also works seamlessly with Qt's Internationalization APIs.

QString automatically resizes if necessary to accommodate a larger string. (If the string cannot be reallocated the operation throws.) QString uses implicit sharing (copy-on-write) to reduce memory usage and to avoid the needless copying of data. This means that while the variable is stored on the stack, the associated data is stored on the heap.

Note: In terms of memory usage, Symbian C++ developers may find it helpful to think of QStrings (and any implicitly shared objects) as reference-counted R-Classes. The object data is allocated on the heap; copy operations that do not change the data simply increase the count without needing to create a new object. The data is only freed when all objects that use it go out of scope.)

The QString API is much easier to understand than the descriptor hierarchy, and is more powerful in many respects. QString is less memory efficient than the descriptor classes, but still relatively efficient and robust.

Qt also provides QByteArray (an array of bytes) which can be used for string operations. QByteArray is often used for data, and is discussed in the section Converting Input/output, binary and geometry data.

Converting a descriptor to a QString

Use QString::fromUtf16() to create a new QString with a deep copy of the data at a specified address and length. The address and length are obtained with TDesC16::Ptr() and TDesC::Length() respectively:

QString myString = QString::fromUtf16(theDescriptor.Ptr(), theDescriptor.Length());

Note: qcore_symbian_p.h defines QString qt_TDesC2QStringL(const TDesC& aDescriptor), which does this conversion. Because this file is not part of the public API, you may choose to copy the source code from qcore_symbian_p.cpp into your own project.

In most cases you can use the above method to create a copy of the data. If you need to do a zero copy transfer of data, and you can guarantee that theDescriptor's lifetime exceeds that of possible Qt variables, you can use QString::fromRawData() to get a QString pointing at the Descriptor's data:

QString myString = 
    QString::fromRawData(reinterpret_cast<const QChar*>(theDescriptor.Ptr()),theDescriptor.Length());

8 bit descriptors containing text may be converted to Unicode within Symbian C++ and then transferred as above. This has advantages because Symbian's character conversion classes allow auto-detection of the character set, and provide out-of-the-box support for conversion between more character sets.

However, you may find it easier to convert them within Qt code. You can use const TUint8* TDesC8::Ptr() const to get a pointer to the data in the descriptor. If you know the character set, you can use QString's fromAscii(), fromLatin1(), or fromUtf8() to do the conversion. If you just know the data is in the current locale's default set you can use QString::fromLocal8Bit().

Converting a QString to a descriptor

Use QString::utf16() or QString::constData() to get a pointer to the data in the QString myString and cast this to a TPtrC16 (TPtrC) as shown:

TPtrC myDescriptor (static_cast<const TUint16*>(myString.utf16()), myString.length());

or

TPtrC myDescriptor (reinterpret_cast<const TText*>(myString.constData()),myString.length());

The pointer descriptor is valid while the original QString (or any shallow copies) are still in scope. Unless you can guarantee this, you should copy the string into a heap or buffer descriptor. Using an (RBuf) heap descriptor do this:

    RBuf buffer;
    qt_symbian_throwIfError(buffer.Create(myDescriptor));

For a buffer descriptor you can do this:

TBuf buffer(myDescriptor);

or:

TBuf<KBufLength> buffer(text.utf16());

The above approach is used in the Dialpad example to copy the phone number from the QString into a TBuf (see implementation of TelephonyPrivate::startCall() ) in Converting active objects to Qt signals and slots.

Note: qcore_symbian_p.h defines HBufC* qt_QString2HBufC(const QString& aString) and TPtrC qt_QString2TPtrC( const QString& string ) which do these conversions. Because this file is not part of the public API, you may choose to copy the source code from qcore_symbian_p.cpp into your own project.

Copyright note

Most of the material in this topic is based with permission on a Symbian Foundation wiki article Apps:Using Qt and Symbian C++ Together . The version used was that available at Symbian Foundation on 3 November 2010. The content in this page is licensed under the Creative Commons Attribution-Share Alike 2.0 UK: England & Wales License (http://creativecommons.org/licenses/by-sa/2.0/uk).