diff -r 000000000000 -r 62f9d29f7211 webservices/wsframework/src/senmultipartutils.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/webservices/wsframework/src/senmultipartutils.cpp Thu Jan 07 16:19:19 2010 +0200 @@ -0,0 +1,347 @@ +/* +* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: Preparation XOP message for HTTP transmission in case +* of request and extracting BLOBs from XOP message responsed +* through HTTP channel in case of response +* +*/ + + + + + + + + +#include "senmultipartutils.h" + + + +// ======== MEMBER FUNCTIONS ======== + +// --------------------------------------------------------------------------- +// Serializes SoapEnvelope message in XOP message +// --------------------------------------------------------------------------- +// +EXPORT_C void SenMultiPartUtils::SerializeMessageL(CSenFragmentBase& aMessage, + RBuf8& aMultiPartMessage, + TXmlEngSerializerType aType) + { + __ASSERT_ALWAYS(&aMessage, + User::Panic(KMultiPartNoRequestMessagePanicText, EMultiPartNoRequestMessage)); + RSenDocument doc = aMessage.AsDocumentL(); + CXmlEngSerializer* serializer = CXmlEngSerializer::NewL(aType); + __ASSERT_ALWAYS(serializer, User::Panic(KMultiPartPanicText, KErrNotFound)); + CleanupStack::PushL(serializer); + TXmlEngSerializationOptions options(TXmlEngSerializationOptions::KOptionIndent & TXmlEngSerializationOptions::KOptionOmitXMLDeclaration); + serializer->SetOutput(aMultiPartMessage); + serializer->SetSerializationOptions(options); + serializer->SerializeL(doc); + CleanupStack::PopAndDestroy(serializer); + } + +// --------------------------------------------------------------------------- +// Generates random content-ID for header of XOP message and for headers of BLOBs +// as randomNumber@homeTime +// @param aRootCid is ReAlloc'd, which means that any existing data is freed +// prior the generated root cid is assinged to that buffer. +// --------------------------------------------------------------------------- +// +EXPORT_C void SenMultiPartUtils::GenerateRandomRootCidL(RBuf8& aRootCid) + { + _LIT8(KAt, "@"); + TTime now; + now.HomeTime(); + TInt64 homeTime = now.Int64(); + TInt64 randomNumber = Math::Random(); + aRootCid.ReAllocL(32+KAt().Length()); + aRootCid.AppendNum(randomNumber); + aRootCid.Append(KAt); + aRootCid.AppendNum(homeTime); + } + +// --------------------------------------------------------------------------- +// Generates random boundary for mime header as randomNumber +// @param aBoundary is ReAlloc'd, which means that any existing data is freed +// prior the generated root cid is assinged to that buffer. +// --------------------------------------------------------------------------- +// +EXPORT_C void SenMultiPartUtils::GenerateRandomBoundaryL(RBuf8& aBoundary) + { + TInt64 randomNumber = Math::Random(); + aBoundary.ReAllocL(16); + aBoundary.AppendNum(randomNumber); + } + +// --------------------------------------------------------------------------- +// Generates MimeBoundary to separate mime parts of the message +// as --randomNumber +// --------------------------------------------------------------------------- +// +EXPORT_C void SenMultiPartUtils::BoundaryLineStartL(const RBuf8& aBoundary, RBuf8& aBoundaryStart) + { + aBoundaryStart.ReAllocL(KNewLine().Length()+KDush().Length()+aBoundary.Length()); + aBoundaryStart.Append(KDush); + aBoundaryStart.Append(aBoundary); + aBoundaryStart.Append(KNewLine); + } + +// --------------------------------------------------------------------------- +// Generates MimeBoundaryEnd to end the multipart message (MultiPart message) +// as --randomNumber-- +// --------------------------------------------------------------------------- +// +EXPORT_C void SenMultiPartUtils::BoundaryLineEndL(const RBuf8& aBoundary, RBuf8& aBoundaryEnd) + { + aBoundaryEnd.ReAllocL(3*KNewLine().Length()+2*KDush().Length()+aBoundary.Length()); + aBoundaryEnd.Append(KNewLine); + aBoundaryEnd.Append(KNewLine); + aBoundaryEnd.Append(KDush); + aBoundaryEnd.Append(aBoundary); + aBoundaryEnd.Append(KDush); + aBoundaryEnd.Append(KNewLine); + } + +// --------------------------------------------------------------------------- +// Creates header for root of XOP message or other multiPart message +// The header sould be the next: +// +// Content-Type: application/xop+xml; +// charset=UTF-8; +// type="text/xml" (for SOAP 1.1) or "application/soap+xml" (for SOAP 1.2) +// Content-Transfer-Encoding: 8bit +// Content-ID: +// +// where "Content-ID" is the same as "start" in Header of Outer Package +// --------------------------------------------------------------------------- +// +EXPORT_C void SenMultiPartUtils::HeaderRootL(MSenMessage* aMessage, + const RBuf8& aRootCid, RBuf8& aHeaderRoot) + { + + if( aMessage->IsSafeToCast(MSenMessage::ESoapEnvelope2 )) + { + CSenSoapEnvelope2* pSoapEnvelope2 = (CSenSoapEnvelope2*)aMessage; + switch (pSoapEnvelope2->SoapVersion()) + { + case ESOAP11: + { + aHeaderRoot.ReAllocL(KMultiPartHeaderRootStart11().Length()+KMultiPartHeaderRootEnd().Length()+aRootCid.Length()); + aHeaderRoot.Append(KMultiPartHeaderRootStart11); + break; + } + case ESOAP12: + { + aHeaderRoot.ReAllocL(KMultiPartHeaderRootStart12().Length()+KMultiPartHeaderRootEnd().Length()+aRootCid.Length()); + aHeaderRoot.Append(KMultiPartHeaderRootStart12); + break; + } + default: + { + User::Panic(KMultiPartSoapVersionInvalidPanicText, EMultiPartSoapVersionInvalid); + } + } + } + else if( aMessage->IsSafeToCast(MSenMessage::EAtomMessage )) + { + aHeaderRoot.ReAllocL(KMultiPartAtomHeaderRootStart().Length()+KMultiPartHeaderRootEnd().Length()+aRootCid.Length()); + aHeaderRoot.Append(KMultiPartAtomHeaderRootStart); + } + aHeaderRoot.Append(aRootCid); + aHeaderRoot.Append(KMultiPartHeaderRootEnd); + } + +// --------------------------------------------------------------------------- +// Creates the header for binary data[aIndex] of XOP message +// The header sould be the next: +// +// --MIME_boundary +// Content-Type: image/png (for images) or some other type for other BLOBs +// Content-Transfer-Encoding: binary +// Content-ID: +// +// --------------------------------------------------------------------------- +// +EXPORT_C void SenMultiPartUtils::HeaderBinaryDataL(TUint aIndex, + RArray& aBinaryDataList, + RBuf8& aHeaderBinaryData) + { + __ASSERT_ALWAYS(aBinaryDataList.Count(), User::Panic(KMultiPartNoBlobsPanicText, EMultiPartNoBlobs)); + __ASSERT_ALWAYS((aIndex < aBinaryDataList.Count()), User::Panic(KMultiPartPanicText, KErrArgument)); + + TPtrC8 cid = aBinaryDataList[aIndex].Cid(); + + RXmlEngNodeList attributes; // to take value of "ContentType" attribute + aBinaryDataList[aIndex].ParentNode().AsElement().GetAttributes(attributes); + CleanupClosePushL(attributes); + + RBuf8 contentType; + CleanupClosePushL(contentType); + while (attributes.HasNext()) + { + TXmlEngAttr attr = attributes.Next(); + if (attr.Name() == KMultiPartContentTypeName) + { + contentType.ReAllocL(attr.Value().Length()); + contentType.Copy(attr.Value()); + break; + } + } + if (contentType == KNullDesC8) + { + contentType.ReAllocL(KMultiPartDefaultBinaryContentTypeValue().Length()); + contentType.Copy(KMultiPartDefaultBinaryContentTypeValue); + } + + + aHeaderBinaryData.ReAllocL(KMultiPartHeaderBinaryDataContentType().Length()+ + KMultiPartHeaderBinaryDataContentID().Length()+ + KMultiPartHeaderBinaryDataEnd().Length()+ + contentType.Length()+ + cid.Length()); + aHeaderBinaryData.Append(KMultiPartHeaderBinaryDataContentType); + aHeaderBinaryData.Append(contentType); + aHeaderBinaryData.Append(KMultiPartHeaderBinaryDataContentID); + aHeaderBinaryData.Append(cid); + aHeaderBinaryData.Append(KMultiPartHeaderBinaryDataEnd); + + CleanupStack::PopAndDestroy(&contentType); + CleanupStack::PopAndDestroy(&attributes); + } + +// --------------------------------------------------------------------------- +// Extracts a part of BLOB (10KB) from a file +// --------------------------------------------------------------------------- +// +EXPORT_C void SenMultiPartUtils::FileDataPartL(TUint aPart, TUint aIndex, + RArray& aBinaryDataList, + RBuf8& aBinaryData) + { + __ASSERT_ALWAYS(aBinaryDataList.Count(), User::Panic(KMultiPartNoBlobsPanicText, EMultiPartNoBlobs)); + __ASSERT_ALWAYS((aIndex < aBinaryDataList.Count()), User::Panic(KMultiPartPanicText, KErrArgument)); + + aBinaryData.ReAllocL(KTenKBytes); + + RFile& file = aBinaryDataList[aIndex].AsFileContainer().File(); + file.Flush(); + file.Read(aPart*KTenKBytes, aBinaryData, KTenKBytes); + } + +// --------------------------------------------------------------------------- +// Extracts the rest of BLOB (less than 10KB) from a file +// --------------------------------------------------------------------------- +// +EXPORT_C void SenMultiPartUtils::FileDataRestL(TUint aParts, TUint aRest, TUint aIndex, + RArray& aBinaryDataList, + RBuf8& aBinaryData) + { + __ASSERT_ALWAYS(aBinaryDataList.Count(), User::Panic(KMultiPartNoBlobsPanicText, EMultiPartNoBlobs)); + __ASSERT_ALWAYS((aIndex < aBinaryDataList.Count()), User::Panic(KMultiPartPanicText, KErrArgument)); + + aBinaryData.ReAllocL(aRest); + RFile& file = aBinaryDataList[aIndex].AsFileContainer().File(); + file.Flush(); + file.Read(aParts*KTenKBytes, aBinaryData, aRest); + } + +// --------------------------------------------------------------------------- +// Extracts CIDs of BLOBs from response MultiPart message +// --------------------------------------------------------------------------- +// +EXPORT_C void SenMultiPartUtils::CidL(const RBuf8& aBlobHeader, RArray& aCids) + { + _LIT8(KContentIDName, "Content-ID: <"); + _LIT8(KGreaterThan,">"); + TInt offset = aBlobHeader.Find(KContentIDName); + if (offset == KErrNotFound) + { + User::Panic(KMultiPartNoCidPanicText, EMultiPartNoCid); + } + TPtrC8 blobHeaderPtr; // to extract BLOB header from Response message + blobHeaderPtr.Set(aBlobHeader.Right(aBlobHeader.Length()-offset-KContentIDName().Length())); + + offset = blobHeaderPtr.Find(KGreaterThan);//CodeScannerWarning + if (offset == KErrNotFound) + { + User::Panic(KMultiPartCidInvalidPanicText, EMultiPartCidInvalid); + } + RBuf8 cid; // CID of the BLOB + cid.ReAllocL(offset); + cid.Copy(blobHeaderPtr.Left(offset)); + aCids.AppendL(cid); // collects CIDs of all BLOBs + } + +// --------------------------------------------------------------------------- +// Generates the file name for BLOB of response MultiPart message +// and collects it in array of file names for the all BLOBs +// --------------------------------------------------------------------------- +// +void SenMultiPartUtils::FileNameL(TUint aIndex, RArray& aFileNames) + { + RBuf8 fileName; + fileName.ReAllocL(KFileName().Length()+7); + fileName.Append(KFileName); + fileName.AppendNum(aIndex); + aFileNames.Append(fileName); + } + +// --------------------------------------------------------------------------- +// Extracts BLOB from response MultiPart message and writes it in a file +// --------------------------------------------------------------------------- +// +EXPORT_C TInt SenMultiPartUtils::SetFileL(TUint aIndex, TBool aFirst, TDesC8& aBlob, + RArray& aFileNames) + { + RFs rfs; + RFile file; + + User::LeaveIfError(rfs.Connect()); + CleanupClosePushL(rfs); + TInt retVal = rfs.ShareProtected(); + CleanupClosePushL(file); + + TInt sizeFile = 0; + RBuf fileName; //fileName is necessary to convert from 8bites(aFileNames[aIndex]) to 16 + CleanupClosePushL(fileName); + if (aFirst) // check if is it the first part of a BLOB to write in a file + { + FileNameL(aIndex, aFileNames); // generates the new file + fileName.ReAllocL(aFileNames[aIndex].Length()); + fileName.Copy(aFileNames[aIndex]); + User::LeaveIfError(file.Replace(rfs, fileName, EFileWrite)); // replases the old one to the new one + } + else // if it's not the first part of BLOB then only open the existing file and write a BLOB part in it + { + fileName.ReAllocL(aFileNames[aIndex].Length()); + fileName.Copy(aFileNames[aIndex]); + User::LeaveIfError(file.Open(rfs, fileName, EFileWrite)); + } + + file.Size(sizeFile); + User::LeaveIfError(file.Write(sizeFile, aBlob, aBlob.Length())); + + file.Flush(); + file.Close(); + + User::LeaveIfError(file.Open(rfs, fileName, EFileRead)); + + //fileName.Close(); + CleanupStack::PopAndDestroy(&fileName); + CleanupStack::PopAndDestroy(&file); + CleanupStack::PopAndDestroy(&rfs); + return (sizeFile+aBlob.Length()); + } + +// End of file +