//============================================================================= // File: entity.cpp // Contents: Definitions for DwEntity // Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> // WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html // // Copyright (c) 1996, 1997 Douglas W. Sauder // All rights reserved. // // IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT, // INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF // THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER // HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT // NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A // PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" // BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE, // SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. // //============================================================================= #define DW_IMPLEMENTATION #include <mimelib/config.h> #include <mimelib/debug.h> #include <mimelib/string.h> #include <mimelib/enum.h> #include <mimelib/entity.h> #include <mimelib/headers.h> #include <mimelib/body.h> #include <mimelib/mediatyp.h> class DwEntityParser { friend class DwEntity; private: DwEntityParser(const DwString&); void Parse(); const DwString mString; DwString mHeaders; DwString mBody; }; DwEntityParser::DwEntityParser(const DwString& aStr) : mString(aStr) { Parse(); } void DwEntityParser::Parse() { const char* buf = mString.data(); size_t bufEnd = mString.length(); size_t pos = 0; size_t headersStart = 0; size_t headersLength = 0; size_t lineStart = pos; DwBool isHeaderLine = DwFalse; // If first character is a LF (ANSI C or UNIX) // or if first two characters are CR LF (MIME or DOS), // there are no headers. if (pos < bufEnd && buf[pos] != '\n' && ! (buf[pos] == '\r' && pos+1 < bufEnd && buf[pos+1] == '\n')) { while (pos < bufEnd) { // End of line marked by LF if (buf[pos] == '\n') { ++pos; if (!isHeaderLine) { pos = lineStart; break; } // Check for LF LF else if (pos < bufEnd && buf[pos] == '\n') { break; } lineStart = pos; isHeaderLine = DwFalse; } // End of line marked by CRLF else if (buf[pos] == '\r' && pos+1 < bufEnd && buf[pos+1] == '\n') { pos += 2; if (!isHeaderLine) { pos = lineStart; break; } // Check for CR LF CR LF else if (pos+1 < bufEnd && buf[pos] == '\r' && buf[pos+1] == '\n') { break; } lineStart = pos; isHeaderLine = DwFalse; } else if (buf[pos] == ':') { isHeaderLine = DwTrue; ++pos; } else if (pos == lineStart && (buf[pos] == ' ' || buf[pos] == '\t')) { isHeaderLine = DwTrue; ++pos; } else { ++pos; } } } headersLength = pos; mHeaders = mString.substr(headersStart, headersLength); // Skip blank line // LF (ANSI C or UNIX) if (pos < bufEnd && buf[pos] == '\n') { ++pos; } // CR LF (MIME or DOS) else if (pos < bufEnd && buf[pos] == '\r' && pos+1 < bufEnd && buf[pos+1] == '\n') { pos += 2; } size_t bodyStart = pos; size_t bodyLength = mString.length() - bodyStart; mBody = mString.substr(bodyStart, bodyLength); } //========================================================================== const char* const DwEntity::sClassName = "DwEntity"; DwEntity::DwEntity() { mHeaders = DwHeaders::NewHeaders("", this); ASSERT(mHeaders != 0); mBody = DwBody::NewBody("", this); ASSERT(mBody != 0); mClassId = kCidEntity; mClassName = sClassName; mBodySize = -1; } DwEntity::DwEntity(const DwEntity& aEntity) : DwMessageComponent(aEntity) { mHeaders = (DwHeaders*) aEntity.mHeaders->Clone(); ASSERT(mHeaders != 0); mHeaders->SetParent(this); mBody = (DwBody*) aEntity.mBody->Clone(); ASSERT(mBody != 0); mBody->SetParent(this); mClassId = kCidEntity; mClassName = sClassName; mBodySize = aEntity.mBodySize; } DwEntity::DwEntity(const DwString& aStr, DwMessageComponent* aParent) : DwMessageComponent(aStr, aParent) { mHeaders = DwHeaders::NewHeaders("", this); ASSERT(mHeaders != 0); mBody = DwBody::NewBody("", this); ASSERT(mBody != 0); mClassId = kCidEntity; mClassName = sClassName; mBodySize = -1; } DwEntity::~DwEntity() { delete mHeaders; delete mBody; } const DwEntity& DwEntity::operator = (const DwEntity& aEntity) { if (this == &aEntity) return *this; DwMessageComponent::operator = (aEntity); // Note: Because of the derived assignment problem, we cannot use the // assignment operator for DwHeaders and DwBody in the following. delete mHeaders; mHeaders = (DwHeaders*) aEntity.mHeaders->Clone(); ASSERT(mHeaders != 0); mHeaders->SetParent(this); delete mBody; mBody = (DwBody*) aEntity.mBody->Clone(); ASSERT(mBody != 0); mBody->SetParent(this); if (mParent) { mParent->SetModified(); } return *this; } void DwEntity::Parse() { mIsModified = 0; DwEntityParser parser(mString); mHeaders->FromString(parser.mHeaders); mHeaders->Parse(); mBody->FromString(parser.mBody); mBody->Parse(); } void DwEntity::Assemble(DwHeaders& aHeaders, DwBody& aBody) { mString = ""; mString += aHeaders.AsString(); // DwEntityParser skips the line separating the headers from the // body. So it's neither part of DwHeaders, nor of DwBody // -> we need to readd it here: mString += DW_EOL; mString += aBody.AsString(); mIsModified = 0; } void DwEntity::Assemble() { if (!mIsModified) return; mBody->Assemble(); mHeaders->Assemble(); Assemble( *mHeaders, *mBody ); } DwHeaders& DwEntity::Headers() const { ASSERT(mHeaders != 0); return *mHeaders; } DwBody& DwEntity::Body() const { return *mBody; } int DwEntity::BodySize() const { if ( mBody->AsString().length() > 0 ) return mBody->AsString().length(); else if ( mBodySize > 0 ) return mBodySize; else return 0; } #if defined(DW_DEBUG_VERSION) void DwEntity::PrintDebugInfo(std::ostream& aStrm, int aDepth) const { aStrm << "------------ Debug info for DwEntity class ------------\n"; _PrintDebugInfo(aStrm); int depth = aDepth - 1; depth = (depth >= 0) ? depth : 0; if (aDepth == 0 || depth > 0) { mHeaders->PrintDebugInfo(aStrm, depth); mBody->PrintDebugInfo(aStrm, depth); } } #else void DwEntity::PrintDebugInfo(std::ostream& , int ) const {} #endif // defined(DW_DEBUG_VERSION) #if defined(DW_DEBUG_VERSION) void DwEntity::_PrintDebugInfo(std::ostream& aStrm) const { DwMessageComponent::_PrintDebugInfo(aStrm); aStrm << "Headers: " << mHeaders->ObjectId() << '\n'; aStrm << "Body: " << mBody->ObjectId() << '\n'; } #else void DwEntity::_PrintDebugInfo(std::ostream& ) const {} #endif // defined(DW_DEBUG_VERSION) void DwEntity::CheckInvariants() const { #if defined(DW_DEBUG_VERSION) DwMessageComponent::CheckInvariants(); mHeaders->CheckInvariants(); assert((DwMessageComponent*) this == mHeaders->Parent()); mBody->CheckInvariants(); assert((DwMessageComponent*) this == mBody->Parent()); #endif // defined(DW_DEBUG_VERSION) }