diff -r 000000000000 -r c8caa15ef882 simpleengine/xmlutils/src/simpledocument.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simpleengine/xmlutils/src/simpledocument.cpp Tue Feb 02 01:05:17 2010 +0200 @@ -0,0 +1,745 @@ +/* +* 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: Simple Engine +* +*/ + + + + +// INCLUDE FILES + +#include // First to avoid NULL redefine warning (no #ifndef NULL). +#include +#include + +#include + +// #include +#include +#include +#include +#include +#include +#include + +#include +#include + +// own simple +#include "simplecommon.h" +#include "simpleelement.h" +#include "simplenamespace.h" +#include "simpleattribute.h" +#include "simpledocument.h" +#include "simplebasedocument.h" +#include "simpleutils.h" +#include "simplecontent.h" + + +_LIT8 ( KSimpleEntity, "entity"); + +// Multipart CONSTANTS + +const char Multipart_CRLF_Text[] = {"\r\n"}; +const char Multipart_DoubleCRLF_Text[] = {"\r\n\r\n"}; + +// MACROS +#define MULTIPART_CONTENT_LOCATION_LENGTH 17 +#define MULTIPART_CONTENT_TYPE_LENGTH 13 +#define MULTIPART_CONTENT_TRANSFER_ENCODING_LENGTH 26 +// violates RFC2045; but upon vodafone request +#define MULTIPART_CONTENT_ENCODING_LENGTH 17 +#define MULTIPART_CONTENT_LENGTH_LENGTH 15 +#define MULTIPART_LAST_MODIFIED_LENGTH 14 +#define MULTIPART_CONTENT_ID_LENGTH 11 + +#define MULTIPART_CONTENT_LOCATION 2 +#define MULTIPART_CONTENT_TRANSFER_ENCODING 3 +#define MULTIPART_CONTENT_TYPE 4 +#define MULTIPART_CONTENT_ID 5 + +#define MULTIPART_INTERNET_DATE_STRING_LENGTH 29 + +#define SLASH_CHAR '/' +#define DOT_CHAR '.' +#define AT_CHAR '@' +#define COLON_CHAR ':' +// :// +// #define SCHEME_SEPARATOR_LENGTH 3 +// ================= MEMBER FUNCTIONS ======================= +// + +// ---------------------------------------------------------- +// CSimpleDocument::CSimpleDocument +// ---------------------------------------------------------- +// +CSimpleDocument::CSimpleDocument( ) +: CSimpleBaseDocument() + { + } + +// ---------------------------------------------------------- +// CSimpleDocument::~CSimpleDocument +// ---------------------------------------------------------- +// +CSimpleDocument::~CSimpleDocument() + { + iContents.ResetAndDestroy(); + iContents.Close(); + } + +// ---------------------------------------------------------- +// CSimpleDocument::ConstructL +// ---------------------------------------------------------- +// +void CSimpleDocument::ConstructL( + const TDesC8& aNsUri, + const TDesC8& aLocalName ) + { + BaseConstructL(aNsUri, aLocalName); + } + +// ---------------------------------------------------------- +// CSimpleDocument::ConstructMultiPartL +// ---------------------------------------------------------- +// +void CSimpleDocument::ConstructMultiPartL( + const TDesC8& aData, const TDesC8& aBoundary, const TDesC8& aStart ) + { + _LIT(KUrl, "http://dummy.com/d1/d.html"); + + // body part array + RPointerArray bodyPartArray; + TCleanupItem clItem( ResetAndDestroy, &bodyPartArray ); + CleanupStack::PushL( clItem ); + + // remove "..." characters from boundary if needed + TPtrC8 pUnQuoted = aBoundary; + TInt quoted = aBoundary.Locate('"'); + if (!quoted) + { + pUnQuoted.Set( aBoundary.Mid( 1, aBoundary.Length() - 2 )); + } + // parse + MultipartParser::ParseL( aData, KSimpleMultipartType, pUnQuoted, KUrl, bodyPartArray ); + DoConstructL( bodyPartArray, aStart ); + + CleanupStack::PopAndDestroy( ); // bodyPartArray + } + +// ---------------------------------------------------------- +// CSimpleDocument::ConstructL +// ---------------------------------------------------------- +// +void CSimpleDocument::ConstructL( + const TDesC8& aXml ) + { + BaseConstructL( aXml ); + } + +// ---------------------------------------------------------- +// CSimpleDocument::NewL +// ---------------------------------------------------------- +// +CSimpleDocument* CSimpleDocument::NewL( ) + { + CSimpleDocument* self = new (ELeave) CSimpleDocument( ); + CleanupStack::PushL( self ); + self->ConstructL( KSimpleNsDefault, KDocumentLocalName ); + CleanupStack::Pop( self ); + return self; + } + +// ---------------------------------------------------------- +// CSimpleDocument::NewL +// ---------------------------------------------------------- +// +CSimpleDocument* CSimpleDocument::NewL( const TDesC8& aXml ) + { + CSimpleDocument* self = new (ELeave) CSimpleDocument( ); + CleanupStack::PushL( self ); + self->ConstructL( aXml ); + CleanupStack::Pop( self ); + return self; + } + +// ---------------------------------------------------------- +// CSimpleDocument::NewInMultiPartL +// ---------------------------------------------------------- +// +CSimpleDocument* CSimpleDocument::NewInMultiPartL( + const TDesC8& aData, const TDesC8& aBoundary, const TDesC8& aStart ) + { + CSimpleDocument* self = new (ELeave) CSimpleDocument( ); + CleanupStack::PushL( self ); + self->ConstructMultiPartL( aData, aBoundary, aStart ); + CleanupStack::Pop( self ); + return self; + } + +// ---------------------------------------------------------- +// CSimpleDocument::GetDirectContentsL +// ---------------------------------------------------------- +// +void CSimpleDocument::GetDirectContentsL( + RPointerArray& aContents ) + { + aContents.Reset(); + TInt myCount = iContents.Count(); + for ( TInt i = 0; iCopyBodyL( aContent.Body() ); + } + else + { + content->SetBody( aContent.GiveBodyOwnerShip() ); + } + } + +// ---------------------------------------------------------- +// CSimpleDocument::ValidateXmlL +// ---------------------------------------------------------- +// +void CSimpleDocument::ValidateXmlL( const TDesC8& aName ) + { + if ( aName.CompareF( KDocumentLocalName ) ) + { + User::Leave( KErrCorrupt ); + } + } + +// ---------------------------------------------------------- +// CSimpleDocument::EntityURI +// ---------------------------------------------------------- +// +const TDesC8* CSimpleDocument::EntityURI() + { + return Root()->AttrValue( KSimpleEntity ); + } + +// ---------------------------------------------------------- +// CSimpleDocument::SetEntityURIL +// ---------------------------------------------------------- +// +void CSimpleDocument::SetEntityURIL( const TDesC8& aValue ) + { + Root()->AddAttr8L( KSimpleEntity, aValue ); + } + +// ---------------------------------------------------------- +// CSimpleDocument::DefaultNamespace +// ---------------------------------------------------------- +// + +TPtrC8 CSimpleDocument::DefaultNamespace() + { + return CSimpleBaseDocument::DefaultNamespace(); + } + + +// ---------------------------------------------------------- +// CSimpleDocument::AddNamespaceL +// ---------------------------------------------------------- +// +void CSimpleDocument::AddNamespaceL( + const TDesC8& aPrefix, + const TDesC8& aUri ) + { + CSimpleBaseDocument::AddNamespaceL( aPrefix, aUri ); + } + +// ---------------------------------------------------------- +// CSimpleDocument::NamespacesL +// ---------------------------------------------------------- +// +RPointerArray& CSimpleDocument::NamespacesL() + { + return CSimpleBaseDocument::NamespacesL(); + } + +// ---------------------------------------------------------- +// CSimpleDocument::ExternalizeL +// ---------------------------------------------------------- +// +void CSimpleDocument::ExternalizeL( RWriteStream& aStream ) + { + + // notice: check the max message size + + if ( !iContents.Count() ) + { + // single pidf+xml + CSimpleBaseDocument::ExternalizeL( aStream ); + } + else + { + RPointerArray bodyPartsArray; + RPointerArray bufferArray; + + TRAPD( err, DoExternalizeMultiPartL( bodyPartsArray, bufferArray, aStream ) ); + + bufferArray.ResetAndDestroy(); + bodyPartsArray.ResetAndDestroy(); + bufferArray.Close(); + bodyPartsArray.Close(); + + User::LeaveIfError( err ); + } + } + +// ---------------------------------------------------------- +// CSimpleDocument::Close +// ---------------------------------------------------------- +// +void CSimpleDocument::Close() + { + CSimpleBaseDocument::Close(); + } + +// ---------------------------------------------------------- +// CSimpleDocument::LocalName +// ---------------------------------------------------------- +// +const TDesC8& CSimpleDocument::LocalName() + { + return CSimpleBaseDocument::LocalName(); + } + +// ---------------------------------------------------------- +// CSimpleDocument::DefNamespaceL +// ---------------------------------------------------------- +// +MSimpleNamespace* CSimpleDocument::DefNamespaceL() + { + return CSimpleBaseDocument::DefNamespaceL(); + } + +// ---------------------------------------------------------- +// CSimpleDocument::HasContent +// ---------------------------------------------------------- +// +TBool CSimpleDocument::HasContent() + { + return CSimpleBaseDocument::HasContent(); + } + +// ---------------------------------------------------------- +// CSimpleDocument::ContentUnicodeL +// ---------------------------------------------------------- +// +HBufC* CSimpleDocument::ContentUnicodeL() + { + return CSimpleBaseDocument::ContentUnicodeL(); + } + +// ---------------------------------------------------------- +// CSimpleDocument::SetContentUnicodeL +// ---------------------------------------------------------- +// +void CSimpleDocument::SetContentUnicodeL( const TDesC& aContent ) + { + CSimpleBaseDocument::SetContentUnicodeL( aContent ); + } + +// ---------------------------------------------------------- +// CSimpleDocument::SimpleElementsL +// ---------------------------------------------------------- +// +TInt CSimpleDocument::SimpleElementsL( RPointerArray& aElementArray ) + { + return CSimpleBaseDocument::SimpleElementsL( aElementArray ); + } + +// ---------------------------------------------------------- +// CSimpleDocument::AttrValueLC +// ---------------------------------------------------------- +// +HBufC* CSimpleDocument::AttrValueLC( const TDesC8& aName ) + { + return CSimpleBaseDocument::AttrValueLC( aName ); + } + +// ---------------------------------------------------------- +// CSimpleDocument::AttrValue +// ---------------------------------------------------------- +// +const TDesC8* CSimpleDocument::AttrValue( const TDesC8& aName ) + { + return CSimpleBaseDocument::AttrValue( aName ); + } + +// ---------------------------------------------------------- +// CSimpleDocument::AddAttrL +// ---------------------------------------------------------- +// +void CSimpleDocument::AddAttrL( const TDesC8& aName, const TDesC& aValue ) + { + CSimpleBaseDocument::AddAttrL( aName, aValue ); + } + +// ---------------------------------------------------------- +// CSimpleDocument::SimpleAttributesL +// ---------------------------------------------------------- +// +TInt CSimpleDocument::SimpleAttributesL( RPointerArray& aArray ) + { + return CSimpleBaseDocument::SimpleAttributesL( aArray ); + } + +// ---------------------------------------------------------- +// CSimpleDocument::SimpleParentL +// ---------------------------------------------------------- +// +MSimpleElement* CSimpleDocument::SimpleParentL() + { + return NULL; + } + +// ---------------------------------------------------------- +// CSimpleDocument::DetachSimpleL +// ---------------------------------------------------------- +// +void CSimpleDocument::DetachSimpleL() + { + User::Leave( KErrNotFound ); + } + + +// ---------------------------------------------------------- +// CSimpleDocument::AddSimpleElementL +// ---------------------------------------------------------- +// +MSimpleElement* CSimpleDocument::AddSimpleElementL( + const TDesC8& aNsUri, + const TDesC8& aLocalName ) + { + return CSimpleBaseDocument::AddSimpleElementL( aNsUri, aLocalName ); + } + +// ---------------------------------------------------------- +// CSimpleDocument::AddSimpleElementL +// ---------------------------------------------------------- +// +MSimpleElement* CSimpleDocument::AddSimpleElementL( + const TDesC8& aLocalName ) + { + return CSimpleBaseDocument::AddSimpleElementL( aLocalName ); + } + + +// ---------------------------------------------------------- +// CSimpleDocument::RemoveSimpleElement +// ---------------------------------------------------------- +// +void CSimpleDocument::RemoveSimpleElement( + const TDesC8& aNsUri, + const TDesC8& aLocalName ) + { + CSimpleBaseDocument::RemoveSimpleElement( aNsUri, aLocalName ); + } + +// ---------------------------------------------------------- +// CSimpleDocument::ResetAndDestroy +// ---------------------------------------------------------- +// +void CSimpleDocument::ResetAndDestroy( TAny* aPtrArray ) + { + RPointerArray* array = + static_cast*>( aPtrArray ); + array->ResetAndDestroy(); + array->Close(); + } + +// ---------------------------------------------------------- +// CSimpleDocument::DoConstructL +// ---------------------------------------------------------- +// +void CSimpleDocument::DoConstructL( + RPointerArray& aParts, const TDesC8& aStart ) + { + // Handle body parts one by one + TInt size = aParts.Count(); + TInt i; + CBodyPart* cp = NULL; + TPtrC8 boundary; + TPtrC8 start; + + TBool pidfOk ( EFalse ); + + + for (i = 0; i < size; i++) + { + cp = aParts[i]; + + if ( (( aStart.Length() > 0 && !aStart.Compare( cp->ContentID()) ) || + !pidfOk ) && + !cp->ContentType().Left(sizeof(KSimpleDocumentType)).CompareF( KSimpleDocumentType )) + { + // Multipart root is in the pidf+xml format + BaseConstructL( cp->Body() ); + pidfOk = ETrue; + } + else + { + // Direct contents, as a separate MIME multipart parts + CSimpleContent* cd = CSimpleContent::NewL( + cp->ContentID(), cp->ContentType() ); + cd->CopyBodyL( cp->Body() ); + CleanupStack::PushL( cd ); + User::LeaveIfError( iContents.Append( cd ) ); + CleanupStack::Pop( cd ); + } + } + } + +// ------------------------------------------------------------------------- +// CSimpleDocument::DoComposeMultiPartL +// ------------------------------------------------------------------------- +HBufC8* CSimpleDocument::DoComposeMultiPartL( RPointerArray& aBodyArray, + const TDesC8& aBoundary ) + { + // --(aBoundary) + using namespace NSimpleDocument; + HBufC8* boundary = HBufC8::NewLC( aBoundary.Length() + 4 ); + boundary->Des().Format( KBoundary, &aBoundary ); + + // CALCULATE the size of this document. + TInt bodySize = 0; + // a. for each CBodyPart + // boundaries + CRLF between headers and body (constant addition) + bodySize += (boundary->Length() + strlen(Multipart_CRLF_Text)) * aBodyArray.Count() ; + TInt bodyCounter = aBodyArray.Count(); + for (TInt i = 0; i < bodyCounter; i++) + { + if (!(aBodyArray[i]->Headers().Length() + + aBodyArray[i]->Body().Length())) + { + // one less boundary + bodySize -= boundary->Length() + strlen(Multipart_CRLF_Text); + // skip empty bodypart + continue; + } + bodySize += aBodyArray[i]->Headers().Length(); + // ensure there are only 2 CRLFs between header and body + if (aBodyArray[i]->Headers().Length() > 0) + { + TPtrC8 bodyHeaders(aBodyArray[i]->Headers().Ptr(), aBodyArray[i]->Headers().Length()); + TUint newEnd = bodyHeaders.Length() - 1; + while( bodyHeaders[ newEnd ] == '\r' || bodyHeaders[ newEnd ] == '\n' ) + { + --newEnd; + --bodySize; + } + // two CRLFs + bodySize += strlen(Multipart_CRLF_Text); + } + bodySize += aBodyArray[i]->Body().Length(); + // CRLF (end of body, add one only if there is body AND does not end with CRLF) + TPtrC8 bodyBody(aBodyArray[i]->Body().Ptr(), aBodyArray[i]->Body().Length()); + if (bodyBody.Length() > 0 + && bodyBody.Right(2) != TPtrC8((TUint8*)Multipart_CRLF_Text, strlen(Multipart_CRLF_Text))) + { + bodySize += strlen(Multipart_CRLF_Text); + } + } + // end boundary (boundary - '\r\n' + "--") + bodySize += boundary->Length(); + TInt docSize = bodySize; + + // CALCULATE the size of Headers + using namespace NSimpleDocument::NSimpleMulti; + + // extra CRLF for separating header and body + docSize += strlen(Multipart_CRLF_Text); + // CALCULATION COMPLETE + // at this point, bodySize contains the size of bodyparts, i.e. Content-Length: + // and docSize contains the size of the entire document (use it to create HBufC8* + // of appropriate size) + + // CONSTRUCT MULTIPART DOCUMENT + HBufC8* document = HBufC8::NewLC(docSize); + + TPtr8 docAppend(document->Des()); + + // BODYPARTS + for (TInt i = 0; i < aBodyArray.Count(); i++) + { + if (!(aBodyArray[i]->Headers().Length() + + aBodyArray[i]->Body().Length())) + { + // skip empty bodypart + continue; + } + docAppend.Append( *boundary ); + TInt headerLength = aBodyArray[i]->Headers().Length() - 1; + while ( headerLength > 0 && + (aBodyArray[i]->Headers()[headerLength] == '\r' + || aBodyArray[i]->Headers()[headerLength] == '\n' )) + { + --headerLength; + } + docAppend.Append( aBodyArray[i]->Headers().Ptr(), headerLength + 1 ); + + if ( headerLength > 0 ) + { + docAppend.Append((TUint8*)Multipart_DoubleCRLF_Text, strlen(Multipart_DoubleCRLF_Text)); + } + else + { + docAppend.Append((TUint8*)Multipart_CRLF_Text, strlen(Multipart_CRLF_Text)); + } + // body + TPtrC8 opa = aBodyArray[i]->Body(); + docAppend.Append(aBodyArray[i]->Body()); + // CRLF only if body exists and doesn't end with CRLF + TPtrC8 bodyBody(aBodyArray[i]->Body().Ptr(), aBodyArray[i]->Body().Length()); + if (bodyBody.Length() > 0 + && bodyBody.Right(2) != TPtrC8((TUint8*)Multipart_CRLF_Text, strlen(Multipart_CRLF_Text))) + { + docAppend.Append((TUint8*)Multipart_CRLF_Text, strlen(Multipart_CRLF_Text)); + } + } + // end boundary + docAppend.AppendFormat(KEndBoundary, &aBoundary); + CleanupStack::Pop( document ); + CleanupStack::PopAndDestroy( boundary ); + return document; + } + +// ------------------------------------------------------------------------- +// CSimpleDocument::DoExternalizeMultiPartL +// ------------------------------------------------------------------------- +void CSimpleDocument::DoExternalizeMultiPartL( + RPointerArray& aBodies, + RPointerArray& aBuffers, + RWriteStream& aStream ) + { + const TReal KB64Expand = 1.5; // reserve room for Base64 encoding + const TInt KBufferSize = 500; + + // Convert all the multipart into CBodyPart. + + // Let's convert first ROOT element into CBodyPart + CBodyPart* root = CBodyPart::NewL(); + // Add into cleanup array + aBodies.Append( root ); + CSenElement* e = Root()->BaseElement(); + + // externalize the document into stream + CBufFlat* myBuffer = CBufFlat::NewL( KBufferSize ); + CleanupStack::PushL( myBuffer ); + myBuffer->Reset(); + + RBufWriteStream stream( *myBuffer ); + stream.Open( *myBuffer ); + CSimpleBaseDocument::ExternalizeL( stream ); + stream.Close(); + + // Add content, no need to transfer encode + TPtrC8 body ( myBuffer->Ptr(0) ); + root->SetBody( body ); + + // Handle the headers of the ROOT part + using namespace NSimpleDocument::NSimpleRoot; + + // calculate the size of headers + TInt headerSize = KContentTypeSize + KCIDSize; + HBufC8* headers = HBufC8::NewL( headerSize ); + aBuffers.Append( headers ); + TPtr8 pH(headers->Des()); + // append to MIME headers for the root part + pH.Append( NSimpleDocument::NSimpleRoot::KContentType ); + pH.Append( NSimpleDocument::NSimpleRoot::KCID ); + root->SetHeaders( pH ); + + // handle the direct contents one by one + TInt contCount = iContents.Count(); + for ( TInt i=0; iContentID().Length(); + headerSize += (iContents[i])->ContentType().Length(); + + headers = HBufC8::NewL( headerSize ); + // Append to cleanup array + aBuffers.Append( headers ); + pH.Set( headers->Des() ); + + // _LIT8( KMyContentType, "Content-Type: %S\r\n"); + TPtrC8 myValue = (iContents[i])->ContentType(); + pH.Format( NSimpleDocument::NSimpleContent::KContentType, &myValue ); + myValue.Set((iContents[i])->ContentID() ); + pH.AppendFormat( NSimpleDocument::NSimpleContent::KCID, &myValue ); + pH.Append( NSimpleDocument::NSimpleContent::KContentEncoding ); + // append to MIME headers + cp->SetHeaders( pH ); + + // Body + + // BASE64 encode + HBufC8* body64 = HBufC8::NewL( (iContents[i])->Body().Length() * KB64Expand ); + aBuffers.Append( body64 ); + TImCodecB64 codec64; + codec64.Initialise(); + TPtr8 desti8 = body64->Des(); + + // notice: leave if error? + TInt err = codec64.Encode( (iContents[i])->Body(), desti8 ); + + cp->SetBody( body64->Des() ); + } + + // Compose the multipart MIME flat data + HBufC8* entireMsg = NULL; + entireMsg = DoComposeMultiPartL( aBodies, NSimpleDocument::KSimpleBoundary ); + CleanupStack::PushL( entireMsg ); + // Finally stream entireMsg, + // Notice: later DoComposeMultiPartL could stream directly? + aStream.WriteL( entireMsg->Des() ); + CleanupStack::PopAndDestroy( entireMsg ); + CleanupStack::PopAndDestroy( myBuffer ); + + } + + + + +