diff options
Diffstat (limited to 'mimelib/mediatyp.cpp')
-rw-r--r-- | mimelib/mediatyp.cpp | 590 |
1 files changed, 590 insertions, 0 deletions
diff --git a/mimelib/mediatyp.cpp b/mimelib/mediatyp.cpp new file mode 100644 index 000000000..7c766fe3d --- /dev/null +++ b/mimelib/mediatyp.cpp @@ -0,0 +1,590 @@ +//============================================================================= +// File: mediatyp.cpp +// Contents: Definitions for DwMediaType +// 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 <ctype.h> +#include <stdlib.h> +#include <string.h> +#include <iostream> +#include <time.h> +#include <mimelib/string.h> +#include <mimelib/param.h> +#include <mimelib/mediatyp.h> +#include <mimelib/token.h> +#include <mimelib/utility.h> +#include <mimelib/enum.h> + + +const char* const DwMediaType::sClassName = "DwMediaType"; + + +DwMediaType* (*DwMediaType::sNewMediaType)(const DwString&, + DwMessageComponent*) = 0; + + +DwMediaType* DwMediaType::NewMediaType(const DwString& aStr, + DwMessageComponent* aParent) +{ + if (sNewMediaType) { + return sNewMediaType(aStr, aParent); + } + else { + return new DwMediaType(aStr, aParent); + } +} + + +DwMediaType::DwMediaType() +{ + mType = DwMime::kTypeNull; + mSubtype = DwMime::kSubtypeNull; + mFirstParameter = 0; + mClassId = kCidMediaType; + mClassName = sClassName; +} + + +DwMediaType::DwMediaType(const DwMediaType& aCntType) + : DwFieldBody(aCntType), + mTypeStr(aCntType.mTypeStr), + mSubtypeStr(aCntType.mSubtypeStr), + mBoundaryStr(aCntType.mBoundaryStr) +{ + mType = aCntType.mType; + mSubtype = aCntType.mSubtype; + mFirstParameter = 0; + + if (aCntType.mFirstParameter) { + CopyParameterList(aCntType.mFirstParameter); + } + + mClassId = kCidMediaType; + mClassName = sClassName; +} + + +DwMediaType::DwMediaType(const DwString& aStr, DwMessageComponent* aParent) + : DwFieldBody(aStr, aParent) +{ + mType = DwMime::kTypeNull; + mSubtype = DwMime::kSubtypeNull; + mFirstParameter = 0; + mClassId = kCidMediaType; + mClassName = sClassName; +} + + +DwMediaType::~DwMediaType() +{ + if (mFirstParameter) { + DeleteParameterList(); + } +} + + +const DwMediaType& DwMediaType::operator = (const DwMediaType& aCntType) +{ + if (this == &aCntType) return *this; + DwFieldBody::operator = (aCntType); + + mType = aCntType.mType; + mSubtype = aCntType.mSubtype; + mTypeStr = aCntType.mTypeStr; + mSubtypeStr = aCntType.mSubtypeStr; + mBoundaryStr = aCntType.mBoundaryStr; + + if (mFirstParameter) { + DeleteParameterList(); + } + if (aCntType.mFirstParameter) { + CopyParameterList(aCntType.mFirstParameter); + } + + if (mParent) { + mParent->SetModified(); + } + + return *this; +} + + +int DwMediaType::Type() const +{ + return mType; +} + + +void DwMediaType::SetType(int aType) +{ + mType = aType; + TypeEnumToStr(); + SetModified(); +} + + +const DwString& DwMediaType::TypeStr() const +{ + return mTypeStr; +} + + +void DwMediaType::SetTypeStr(const DwString& aStr) +{ + mTypeStr = aStr; + TypeStrToEnum(); + SetModified(); +} + + +int DwMediaType::Subtype() const +{ + return mSubtype; +} + + +void DwMediaType::SetSubtype(int aSubtype) +{ + mSubtype = aSubtype; + SubtypeEnumToStr(); + SetModified(); +} + + +const DwString& DwMediaType::SubtypeStr() const +{ + return mSubtypeStr; +} + + +void DwMediaType::SetSubtypeStr(const DwString& aStr) +{ + mSubtypeStr = aStr; + SubtypeStrToEnum(); + SetModified(); +} + + +const DwString& DwMediaType::Boundary() const +{ + // Implementation note: this member function is const, which + // forbids us from assigning to mBoundaryStr. The following + // trick gets around this. (ANSI implementations could use the + // "mutable" declaration). + DwMediaType* _this = (DwMediaType*) this; + _this->mBoundaryStr = ""; + DwParameter* param = mFirstParameter; + while (param) { + if (DwStrcasecmp(param->Attribute(), "boundary") == 0) { + // Boundary parameter found. Return its value. + _this->mBoundaryStr = param->Value(); + break; + } + param = param->Next(); + } + return mBoundaryStr; +} + + +void DwMediaType::SetBoundary(const DwString& aStr) +{ + mBoundaryStr = aStr; + // Search for boundary parameter in parameter list. If found, set its + // value. + DwParameter* param = mFirstParameter; + while (param) { + if (DwStrcasecmp(param->Attribute(), "boundary") == 0) { + param->SetValue(mBoundaryStr); + return; + } + param = param->Next(); + } + // Boundary parameter not found. Add it. + param = DwParameter::NewParameter("", 0); + param->SetAttribute("boundary"); + param->SetValue(aStr); + AddParameter(param); +} + + +void DwMediaType::CreateBoundary(unsigned aLevel) +{ + // Create a random printable string and set it as the boundary parameter + static const char c[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + const int cLen = 64; + char buf[80]; + strcpy(buf, "Boundary-"); + int pos = strlen(buf); + int n = aLevel / 10; + buf[pos++] = (n % 10) + '0'; + n = aLevel; + buf[pos++] = (n % 10) + '0'; + buf[pos++] = '='; + buf[pos++] = '_'; + DwUint32 r = (DwUint32) time(0); + buf[pos++] = c[r % cLen]; + r /= cLen; + buf[pos++] = c[r % cLen]; + r /= cLen; + buf[pos++] = c[r % cLen]; + r /= cLen; + buf[pos++] = c[r % cLen]; + r /= cLen; + buf[pos++] = c[r % cLen]; + for (int i=0; i < 2; ++i) { + r = rand(); + buf[pos++] = c[r % cLen]; + r >>= 6; + buf[pos++] = c[r % cLen]; + r >>= 6; + buf[pos++] = c[r % cLen]; + r >>= 6; + buf[pos++] = c[r % cLen]; + r >>= 6; + buf[pos++] = c[r % cLen]; + } + buf[pos] = 0; + SetBoundary(buf); +} + + +const DwString& DwMediaType::Name() const +{ + // Implementation note: this member function is const, which + // forbids us from assigning to mNameStr. The following + // trick gets around this. (ANSI implementations could use the + // "mutable" declaration). + DwMediaType* _this = (DwMediaType*) this; + _this->mNameStr = ""; + DwParameter* param = mFirstParameter; + while (param) { + if (DwStrcasecmp(param->Attribute(), "name") == 0) { + // Name parameter found. Return its value. + _this->mNameStr = param->Value(); + break; + } + param = param->Next(); + } + return mNameStr; +} + + +void DwMediaType::SetName(const DwString& aStr) +{ + mNameStr = aStr; + // Search for name parameter in parameter list. If found, set its + // value. + DwParameter* param = mFirstParameter; + while (param) { + if (DwStrcasecmp(param->Attribute(), "name") == 0) { + param->SetValue(mNameStr); + return; + } + param = param->Next(); + } + // Name parameter not found. Add it. + param = DwParameter::NewParameter("", 0); + param->SetAttribute("name"); + param->SetValue(aStr); + AddParameter(param); +} + + +DwParameter* DwMediaType::FirstParameter() const +{ + return mFirstParameter; +} + + +void DwMediaType::AddParameter(DwParameter* aParam) +{ + _AddParameter(aParam); + SetModified(); +} + + +void DwMediaType::_AddParameter(DwParameter* aParam) +{ + if (!mFirstParameter) { + mFirstParameter = aParam; + } + else { + DwParameter* cur = mFirstParameter; + DwParameter* next = cur->Next(); + while (next) { + cur = next; + next = cur->Next(); + } + cur->SetNext(aParam); + } + aParam->SetParent(this); +} + + +void DwMediaType::Parse() +{ + mIsModified = 0; + mTypeStr = ""; + mSubtypeStr = ""; + mType = DwMime::kTypeNull; + mSubtype = DwMime::kSubtypeNull; + if (mFirstParameter) { + DeleteParameterList(); + } + if (mString.length() == 0) return; + DwRfc1521Tokenizer tokenizer(mString); + + // Get type. + int found = 0; + while (!found && tokenizer.Type() != eTkNull) { + if (tokenizer.Type() == eTkToken) { + mTypeStr = tokenizer.Token(); + found = 1; + } + ++tokenizer; + } + // Get '/' + found = 0; + while (!found && tokenizer.Type() != eTkNull) { + if (tokenizer.Type() == eTkTspecial + && tokenizer.Token()[0] == '/') { + found = 1; + } + ++tokenizer; + } + // Get subtype + found = 0; + while (!found && tokenizer.Type() != eTkNull) { + if (tokenizer.Type() == eTkToken) { + mSubtypeStr = tokenizer.Token(); + found = 1; + } + ++tokenizer; + } + // Get parameters + DwTokenString tokenStr(mString); + while (1) { + // Get ';' + found = 0; + while (!found && tokenizer.Type() != eTkNull) { + if (tokenizer.Type() == eTkTspecial + && tokenizer.Token()[0] == ';') { + found = 1; + } + ++tokenizer; + } + if (tokenizer.Type() == eTkNull) { + // No more parameters + break; + } + tokenStr.SetFirst(tokenizer); + // Get attribute + DwString attrib; + int attribFound = 0; + while (!attribFound && tokenizer.Type() != eTkNull) { + if (tokenizer.Type() == eTkToken) { + attrib = tokenizer.Token(); + attribFound = 1; + } + ++tokenizer; + } + // Get '=' + found = 0; + while (!found && tokenizer.Type() != eTkNull) { + if (tokenizer.Type() == eTkTspecial + && tokenizer.Token()[0] == '=') { + found = 1; + } + ++tokenizer; + } + // Get value but do _not_ stop when finding a '/' in it + int valueFound = 0; + while (!valueFound && tokenizer.Type() != eTkNull) { + if (tokenizer.Type() == eTkToken + || tokenizer.Type() == eTkQuotedString) { + ++tokenizer; + if (tokenizer.Type() != eTkTspecial + || tokenizer.Token()[0] != '/') + valueFound = 1; + } + else + ++tokenizer; + } + if (attribFound && valueFound) { + tokenStr.ExtendTo(tokenizer); + DwParameter* param = + DwParameter::NewParameter(tokenStr.Tokens(), this); + param->Parse(); + _AddParameter(param); + } + } + TypeStrToEnum(); + SubtypeStrToEnum(); +} + + +void DwMediaType::Assemble() +{ + if (!mIsModified) return; + mString = ""; + if (mTypeStr.length() == 0 || mSubtypeStr.length() == 0) + return; + mString += mTypeStr; + mString += '/'; + mString += mSubtypeStr; + DwParameter* param = FirstParameter(); + while (param) { + param->Assemble(); + if (IsFolding()) { + mString += ";" DW_EOL " "; + } + else { + mString += "; "; + } + mString += param->AsString(); + param = param->Next(); + } + mIsModified = 0; +} + + +DwMessageComponent* DwMediaType::Clone() const +{ + return new DwMediaType(*this); +} + + +void DwMediaType::TypeEnumToStr() +{ + DwTypeEnumToStr(mType, mTypeStr); +} + + +void DwMediaType::TypeStrToEnum() +{ + mType = DwTypeStrToEnum(mTypeStr); + +} + + +void DwMediaType::SubtypeEnumToStr() +{ + DwSubtypeEnumToStr(mSubtype, mSubtypeStr); +} + + +void DwMediaType::SubtypeStrToEnum() +{ + mSubtype = DwSubtypeStrToEnum(mSubtypeStr); + +} + + +void DwMediaType::DeleteParameterList() +{ + DwParameter* param = mFirstParameter; + while (param) { + DwParameter* nextParam = param->Next(); + delete param; + param = nextParam; + } + mFirstParameter = 0; + SetModified(); +} + + +void DwMediaType::CopyParameterList(DwParameter* aFirst) +{ + DwParameter* param = aFirst; + while (param) { + DwParameter* newParam = (DwParameter*) param->Clone(); + AddParameter(newParam); + param = param->Next(); + } +} + + +#if defined(DW_DEBUG_VERSION) +void DwMediaType::PrintDebugInfo(std::ostream& aStrm, int aDepth) const +{ + aStrm << + "--------------- Debug info for DwMediaType class ---------------\n"; + _PrintDebugInfo(aStrm); + int depth = aDepth - 1; + depth = (depth >= 0) ? depth : 0; + if (aDepth == 0 || depth > 0) { + DwParameter* param = mFirstParameter; + while (param) { + param->PrintDebugInfo(aStrm, depth); + param = param->Next(); + } + } +} +#else +void DwMediaType::PrintDebugInfo(std::ostream& , int ) const {} +#endif // defined(DW_DEBUG_VERSION) + + +#if defined(DW_DEBUG_VERSION) +void DwMediaType::_PrintDebugInfo(std::ostream& aStrm) const +{ + DwFieldBody::_PrintDebugInfo(aStrm); + aStrm << "Type: " << mTypeStr << " (" << mType << ")\n"; + aStrm << "Subtype: " << mSubtypeStr << " (" << mSubtype << ")\n"; + aStrm << "Boundary: " << mBoundaryStr << '\n'; + aStrm << "Parameters: "; + DwParameter* param = mFirstParameter; + if (param) { + int count = 0; + while (param) { + if (count) aStrm << ' '; + aStrm << param->ObjectId(); + param = param->Next(); + ++count; + } + aStrm << '\n'; + } + else { + aStrm << "(none)\n"; + } +} +#else +void DwMediaType::_PrintDebugInfo(std::ostream& ) const {} +#endif // defined(DW_DEBUG_VERSION) + + +void DwMediaType::CheckInvariants() const +{ +#if defined(DW_DEBUG_VERSION) + mTypeStr.CheckInvariants(); + mSubtypeStr.CheckInvariants(); + mBoundaryStr.CheckInvariants(); + DwParameter* param = mFirstParameter; + while (param) { + param->CheckInvariants(); + assert((DwMessageComponent*) this == param->Parent()); + param = param->Next(); + } +#endif // defined(DW_DEBUG_VERSION) +} |