Symbian OS Communications (779884), страница 61
Текст из файла (страница 61)
Note particularly the use of the cleanup stack, as thisindicates how ownership of the header (i.e., the responsibility for deleting the header) passes to the CObexHeaderSet when AddHeader()is called. Once AddHeader() has returned successfully, the CObexHeaderSet has responsibility for eventually deleting the header that waspassed in, and so whatever class or function had responsibility for thisbefore can relinquish that responsibility (in this case, the calling functioninitially has ownership, but gives that up following AddHeader() byusing CleanupStack::Pop())._LIT(KLengthOutputString, "Length == %d\n");298OBEXCObexHeader* findHeader = CObexHeader::NewL();headerSet->First();if ( headerSet->Find(KLengthHeaderHi,*findHeader)==KErrNone ){iTest.Printf(KLengthOutputString, findHeader->AsFourByte());}delete findHeader;Example 10.3Finding a header in a header setExample 10.3 shows how a populated header set can be easilysearched for a specific header.
Note that Find() searches from thecurrent element of the CObexHeaderSet onwards. This is the reason forthe use of First(), to reset the current element to be the start of the set.(Now is a good time for a quick diversion to discuss ordering withinheader sets. Elements – that is, headers – in a CObexHeaderSet areordered but not sorted; they are simply stored in order of addition. Theelement that was added earliest is at the start of the set, and the oneadded most recently at the end of the set. Elements can be deleted fromanywhere in the set, but additions always happen at the end.)Once the current element has been reset to the start of the set, Find()can be used to seek the first instance of a header with the specified HI.If such a header is found, the function will return KErrNone to indicatesuccess, and the CObexHeader passed in by reference will be updatedto the value of the matching header.
If no such header is found, thefunction will return an error code and the header parameter will not bechanged._LIT(KUnicodeOutputString, "Unicode,HI = 0x%02x, Value = %S\n");_LIT(KByteSeqOutputString, "Byte Seq, HI = 0x%02x, Value = %S\n");_LIT(KOneByteOutputString, "One Byte, HI = 0x%02x, Value = %d\n");_LIT(KFourByteOutputString, "Four Byte, HI = 0x%02x, Value = %d\n");CObexHeader* iterHeader = CObexHeader::NewL();CleanupStack::PushL(iterHeader);headerSet->First();while(headerSet->This(iterHeader) == KErrNone){switch (iterHeader->Type()){case CObexHeader::EUnicode:iTest.Printf(KUnicodeOutputString,iterHeader->HI(),&(iterHeader->AsUnicode()));break;case CObexHeader::EByteSeq:{HBufC* buf=HBufC::NewL(iterHeader->AsByteSeq().Length());OBEX IN SYMBIAN OS299buf->Des().Copy(iterHeader->AsByteSeq());iTest.Printf(KByteSeqOutputString, iterHeader->HI(), buf);delete buf;buf=NULL;}break;case CObexHeader::EByte:iTest.Printf(KOneByteOutputString,iterHeader->HI(),iterHeader->AsByte());break;case CObexHeader::EFourByte:iTest.Printf(KFourByteOutputString,iterHeader->HI(),iterHeader->AsFourByte());break;default:break;}headerSet->Next();}CleanupStack::PopAndDestroy(iterHeader);Example 10.4Iteration through a header setExample 10.4 shows iteration through a header set.
Again, First()is used to reset the current element to the start of the header set beforeThis() is used to attempt to get the value of the current element.If there is a current element, This() will return KErrNone, and willupdate the CObexHeader passed in by reference to be the value of thecurrent header. If there are no elements in the set, or iteration has movedthe current element beyond the end of the set, This() will return anerror code.Using MObexHeaderCheck In some circumstances, it can be useful toapply a filter to a header set, so that only headers of interest are includedin a search or an iteration through a header set. The means to achievethis is by the use of an MObexHeaderCheck-derived class.MObexHeaderCheck is an example of a ‘mixin’ class: a class withonly virtual (and often just pure virtual) functions and no member data.They are used to define an interface that can be inherited by any classthat is willing to implement the behaviour of all the functions.MObexHeaderCheck has a very simple API; it defines a single function5 that must be implemented by concrete derived classes, namely5Actually, in addition to this MObexHeaderCheck also has a Reset() function andan extension interface function, both of which have default implementations (i.e., they arevirtual rather than pure virtual).
Neither of these functions is normally of interest to theapplication writer.300OBEXInterested(). As a parameter, Interested() takes a TUint8 representing the HI value of a header, and returns a TBool. The developerwho implements Interested must ensure that the TBool return valueis set to ETrue if headers with this HI are of interest, and to EFalse theyare not of interest. This decision forms the basis of the filter.
An exampleof such an implementation follows.class TNameAndLengthMask : public MObexHeaderCheck{public:virtual TBool Interested(TUint8 aHi){ return aHi == KNameHeaderHi||aHi == KLengthHeaderHi; };};Example 10.5Example of MObexHeaderCheck implementationClasses like the one defined above could be used in a number ofdifferent ways:• It can be used as a mask during iteration. By passing in the addressof an instance of such a class to CObexHeaderSet::SetMask()prior to beginning an iteration, only headers representing the nameheader and length header would appear to be in the header set.• By passing in the address of an instance of such a class to CObexHeaderSet::SetMask(), it can be used to delete the headers thatare not of interest from the header set, by using CObexHeaderSet::DeleteMasked().• It can be used to make a copy of the header set that includes onlythe interesting headers, by using CObexHeaderSet::CopyL() andpassing in an instance of such a class.Having dealt with how non-body headers are handled in the CObexBaseObject, we now move onto seeing how body headers are handledin CObexBaseObject’s derived classes.
We start with the most important of these, CObexBufObject.CObexBufObjectCObexBufObject was originally intended as a means to send bodydata from, and receive body data to, a RAM-based buffer. Over time,it has been extended and modified beyond this original remit and nowallows receiving to files using a number of buffering strategies, and alsosending from files. These different strategies can be used to increasethe performance of OBEX transfers, and will be discussed individuallybelow.OBEX IN SYMBIAN OS301In general, the way CObexBufObject works when receiving anobject depends primarily on whether it is being used for sending (as asource) or receiving (as a sink), and what combination of file and bufferit has been set up with.
The combinations are listed in Table 10.4.On construction using the NewL() factory function, the CObexBufObject takes a pointer to a CBufFlat. This was the original method ofsetting up a CObexBufObject for use, and without further modification,the object will behave as in the ‘Buffer only’ column. Ownership of thebuffer remains with the code creating the CObexBufObject, so youshould be careful to explicitly delete the buffer when finished.It should also be noted that the pointer value passed in may be NULL,as the OBEX application can decide to set up the CObexBufObject fortransfer after construction time.To set up a CObexBufObject to a different file and buffer combination, the OBEX application writer has a few choices – this is againa combination of the gradual expansion of the capabilities of theCObexBufObject, and the necessity of maintaining source and binarycompatibility.6 The choices are:Table 10.4 OBEX behaviour with differing buffer/file combinationsFile/buffer RAM based buffer File only (using RAM-based buffer and filesetup only (using TObex TObexPure(using TObexFilenameUsageFor sendingBufferingDetails)Body data isextracted frombufferFor receiving Body data isreceived to buffer,with buffer beingexpanded asnecessary toaccommodatenew body dataFileBuffer) BackedBuffer or TObexRFileBackedBuffer)Body data isreaddirectlyfrom fileBody data is read directlyfrom fileBody data iswrittendirectly tofile, with nobufferingBody data is received tobuffer.
When buffer is filled(or transfer is complete) thebuffer is written to fileFurther modifications tothis buffering strategy canbe made in thiscombination – see below6Actually, the version of OBEX in version 7.0 of Symbian OS was not entirely sourceand binary compatible with other pre-v9.1 releases due primarily to differences in theMObexServerNotify class.