quick_recipes (779892), страница 9
Текст из файла (страница 9)
However, to work with binary data,the 8-bit descriptor classes should be used explicitly, and some SymbianOS APIs (e.g., those to read from and write to a file) all take an 8-bitdescriptor.DESCRIPTORS – SYMBIAN OS STRINGS3.8.245TDesCAll Symbian OS descriptor classes derive from the base class TDesC, apartfrom the literal descriptors which we will discuss later in Section 3.8.9.In naming this class, the T prefix indicates a simple type class, whilethe C suffix reflects that the class defines a non-modifiable type ofdescriptor – that is, one whose contents are constant.TDesC provides methods for determining the length of the descriptor(Length()) and accessing its data (Ptr()).
Using these methods, italso implements all the standard operations required on a constant stringobject, such as data access, matching and searching. The derived classesall inherit these methods, and all constant descriptor manipulation isimplemented by TDesC, regardless of the derived type of the descriptorused.3.8.3TDesThe modifiable descriptor types all derive from the base class TDes,which is itself a subclass of TDesC. TDes stores the maximum lengthof data allowed for the current memory allocated to the descriptor. TheMaxLength() method of TDes returns this value. Like the Length()method of TDesC, it is not overridden by derived classes. The contentsof the descriptor can shrink and expand up to this value.TDes defines a range of methods to manipulate modifiable stringdata, including those to append, fill and format the descriptor.
All themanipulation code for descriptor modification is implemented by TDesand inherited by its derived classes. The descriptor API methods forboth modifiable and non-modifiable descriptor base classes are fullydocumented in the Symbian Developer Library.3.8.4 The Derived Descriptor ClassesThe descriptor base classes TDesC and TDes implement all the genericdescriptor manipulation code, but cannot be instantiated.
Derived destriptor classes, which add their own construction and assignment code,are the classes that are actually used to manipulate strings on Symbian OS.The derived descriptor types come in two basic memory layouts:pointer descriptors, in which the descriptor points to data stored elsewhere; and buffer descriptors, where the data forms part of the descriptor.Figure 3.1 shows the inheritance hierarchy of the descriptor classes.3.8.5 Pointer Descriptors: TPtrC and TPtrThe string data of a pointer descriptor is separate from the descriptorobject itself and is stored elsewhere, for example, in ROM, on the heapor on the stack. The memory that holds the data is not ‘owned’ by46SYMBIAN OS DEVELOPMENT BASICSTDesC- Type- iLength- read only descriptor methodsTDes- iMaxLength- methods that modify dataTBufCBaseTBufBaseTBuf<n>TPtrRBufFigure 3.1TPtrCTBufC<n>HBufCDescriptor Class Inheritancethe pointer descriptor, which is agnostic about where the memory islocated.
The class defines a range of constructors to allow TPtrC objectsto be constructed from other descriptors, a pointer into memory, or azero-terminated C string.TPtrC is the equivalent of using const char* when handling stringsin C. The data can be accessed but not modified; that is, the data in thedescriptor is constant. All the non-modifying operations defined in theTDesC base class are accessible to objects of type TPtrC, but none ofthe modification methods of TDes.In comparison, the TPtr class can be used for access to, and modification of, a character string or binary data. All the modifiable andnon-modifiable base-class operations of TDes and TDesC, respectively,are accessible to a TPtr.3.8.6 Stack-Based Buffer Descriptors TBufC and TBufThe stack-based buffer descriptors may be modifiable or non-modifiable.Unlike the pointer descriptors, the string data forms part of the descriptorobject.DESCRIPTORS – SYMBIAN OS STRINGS47TBufC<n> is the non-modifiable buffer class, used to hold constantstring or binary data.
The class derives from TBufCBase (which derivesfrom TDesC, and exists only as an inheritance convenience). TBufC<n>is a thin template class which uses an integer value to fix the size of thedata area for the buffer descriptor object at compile time.TBuf<n> is used when a modifiable buffer is required. It derives fromTBufBase, which itself derives from TDes, and inherits the full range ofdescriptor operations in TDes and TDesC.
The class defines a numberof constructors and assignment operators, similar to those offered by itsnon-modifiable counterpart, TBufC<n>. The buffer descriptors are usefulfor fixed-size strings, but should be used conservatively since they arestack-based except when used as members of a class whose objects areinstantiated on the heap.3.8.7 Dynamic Descriptors: HBufC and RBufThe HBufC and RBuf descriptor classes are used for dynamic string datawhose size is not known at compile time, and for data that cannot bestack-based because it is too big. These classes are used where malloc’ddata would be used in C.HBufCThe HBufC8 and HBufC16 classes (and the neutral version HBufC, whichis typedef’d to HBufC16) provide a number of static NewL() functionsto create the descriptor on the heap. These methods may leave if thereis insufficient memory available.
All heap buffers must be constructedusing one of these methods or from one of the Alloc() or AllocL()methods of the TDesC class, which spawn an HBufC copy of any existingdescriptor. Once the descriptor has been created to the size required, it isnot automatically resized if more space is required. Additional memorymust be reallocated using the ReAlloc() or ReAllocL() methods.As the C suffix of the class name, and the inheritance hierarchy shownin Figure 3.1, indicates, HBufC descriptors are not directly modifiable,although the class provides assignment operators to allow the entirecontents of the buffer to be replaced. To modify an HBufC object atruntime, a modifiable pointer descriptor, TPtr, must first be createdusing the HBufC::Des() method._LIT(KTestBuffer, "Heap Based");// create a heap-based descriptor and place it on cleanup stackHBufC* pHeap = HBufC::NewLC(32);// create a pointer descriptor around pHeapTPtr ptr(pHeap->Des());// modify pHeap indirectly via ptrptr = KTestBuffer;...48SYMBIAN OS DEVELOPMENT BASICS// clean upCleanupStack::PopAndDestroy(pHeap);RBufClass RBuf is derived from TDes, so an RBuf object can be modifiedwithout the need to create a TPtr around the data first, which oftenmakes it preferable to HBufC.
On instantiation, an RBuf object canallocate its own buffer or take ownership of pre-allocated memory or apre-existing heap descriptor. To comply with the Symbian OS class-nameconventions discussed at the beginning of this chapter, the RBuf classis not named HBuf because, unlike HBufC, it is not directly created onthe heap. RBuf descriptors are typically created on the stack, and hold apointer to a resource on the heap for which it is responsible at cleanuptime.Internally, RBuf behaves in one of two ways:• Like a TPtr, which points directly to the descriptor data stored inmemory, which the RBuf object allocates or takes ownership of.• As a pointer to an existing heap descriptor, HBufC*.
The RBuf objecttakes ownership of the HBufC, and holds a pointer to memory thatcontains a complete descriptor object (compared to a pointer to asimple block of data as in the former case).However, this is all transparent, and there is no need to know how aspecific RBuf object is represented internally. Using this descriptor classis straightforward too, through the methods inherited from TDes andTDesC, just as for the other descriptor classes.RBuf is a relatively recent addition to Symbian OS, first documentedin Symbian OS v8.1 and used most extensively in software designed forphones based on Symbian OS v9 and later.
A lot of original examplecode won’t use it, but it is a simpler class to use than HBufC if you needa dynamically allocated buffer to hold data that changes frequently. Thenext subsection will examine how to instantiate and use RBuf in moredetail.HBufC is still ideal when a dynamically allocated descriptor is neededto hold data that doesn’t change; that is, if no modifiable access to thedata is required.3.8.8 Using RBufRBuf objects can be instantiated using the Create(), CreateMax() orCreateL() methods to specify the maximum length of descriptor datathat can be stored. It is also possible to instantiate an RBuf and copy thecontents of another descriptor into it, as follows:DESCRIPTORS – SYMBIAN OS STRINGS49RBuf myRBuf;LIT(KHelloRBuf, "Hello RBuf!"); // Literal descriptormyRBuf.CreateL(KHelloRBuf());CreateL() allocates a buffer for the RBuf to reference.
If that RBufpreviously owned a buffer, CreateL() will not clean it up beforeassigning the new buffer reference, so this must be done first by callingClose() to free any pre-existing owned memory.Alternatively, an RBuf can be instantiated and take ownership of apre-existing section of memory using the Assign() method.// Taking ownership of HBufCHBufC* myHBufC = HBufC::NewL(20);RBuf myRBuf;myRBuf.Assign(myHBufC);Assign() will also orphan any data already owned by the RBuf, soClose() should be called before reassignment, to avoid memory leaks.The RBuf class doesn’t manage the size of the buffer or reallocate itif more memory is required for a particular operation.
If a modificationmethod, such as Append(), is called on an RBuf object for which thereis insufficient memory available, a panic will occur. As a programmer, youare responsible for making sure that the RBuf object has sufficient spacein its internal buffer, by using the ReAllocL() method if necessary:// myRBuf is the buffer to be resized e.g.