--- /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: <randomNumber@homeTime>
+//
+// 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: <randomNumber@homeTime>
+//
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void SenMultiPartUtils::HeaderBinaryDataL(TUint aIndex,
+ RArray<TXmlEngDataContainer>& 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<TXmlEngAttr> 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<TXmlEngDataContainer>& 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<TXmlEngDataContainer>& 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<RBuf8>& 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<RBuf8>& 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<RBuf8>& 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
+