1 //=============================================================================
2 // File:       mediatyp.cpp
3 // Contents:   Definitions for DwMediaType
4 // Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
5 // WWW:        http://www.fwb.gulf.net/~dwsauder/mimepp.html
6 // $Revision: 1.6 $
7 // $Date: 1997/09/27 11:54:04 $
8 //
9 // Copyright (c) 1996, 1997 Douglas W. Sauder
10 // All rights reserved.
11 //
12 // IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
13 // INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
14 // THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
15 // HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16 //
17 // DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
18 // NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
19 // PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
20 // BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
21 // SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
22 //
23 //=============================================================================
24 
25 #define DW_IMPLEMENTATION
26 
27 #include <mimelib/config.h>
28 #include <mimelib/debug.h>
29 #include <ctype.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <iostream>
33 #include <mimelib/string.h>
34 #include <mimelib/param.h>
35 #include <mimelib/mediatyp.h>
36 #include <mimelib/token.h>
37 #include <mimelib/utility.h>
38 #include <mimelib/enum.h>
39 
40 
41 const char* const DwMediaType::sClassName = "DwMediaType";
42 
43 
44 DwMediaType* (*DwMediaType::sNewMediaType)(const DwString&,
45     DwMessageComponent*) = 0;
46 
47 
NewMediaType(const DwString & aStr,DwMessageComponent * aParent)48 DwMediaType* DwMediaType::NewMediaType(const DwString& aStr,
49     DwMessageComponent* aParent)
50 {
51     if (sNewMediaType) {
52         return sNewMediaType(aStr, aParent);
53     }
54     else {
55         return new DwMediaType(aStr, aParent);
56     }
57 }
58 
59 
DwMediaType()60 DwMediaType::DwMediaType()
61 {
62     mType = DwMime::kTypeNull;
63     mSubtype = DwMime::kSubtypeNull;
64     mFirstParameter = 0;
65     mClassId = kCidMediaType;
66     mClassName = sClassName;
67 }
68 
69 
DwMediaType(const DwMediaType & aCntType)70 DwMediaType::DwMediaType(const DwMediaType& aCntType)
71   : DwFieldBody(aCntType),
72     mTypeStr(aCntType.mTypeStr),
73     mSubtypeStr(aCntType.mSubtypeStr),
74     mBoundaryStr(aCntType.mBoundaryStr)
75 {
76     mType = aCntType.mType;
77     mSubtype = aCntType.mSubtype;
78     mFirstParameter = 0;
79 
80     if (aCntType.mFirstParameter) {
81         CopyParameterList(aCntType.mFirstParameter);
82     }
83 
84     mClassId = kCidMediaType;
85     mClassName = sClassName;
86 }
87 
88 
DwMediaType(const DwString & aStr,DwMessageComponent * aParent)89 DwMediaType::DwMediaType(const DwString& aStr, DwMessageComponent* aParent)
90   : DwFieldBody(aStr, aParent)
91 {
92     mType = DwMime::kTypeNull;
93     mSubtype = DwMime::kSubtypeNull;
94     mFirstParameter = 0;
95     mClassId = kCidMediaType;
96     mClassName = sClassName;
97 }
98 
99 
~DwMediaType()100 DwMediaType::~DwMediaType()
101 {
102     if (mFirstParameter) {
103         DeleteParameterList();
104     }
105 }
106 
107 
operator =(const DwMediaType & aCntType)108 const DwMediaType& DwMediaType::operator = (const DwMediaType& aCntType)
109 {
110     if (this == &aCntType) return *this;
111     DwFieldBody::operator = (aCntType);
112 
113     mType        = aCntType.mType;
114     mSubtype     = aCntType.mSubtype;
115     mTypeStr     = aCntType.mTypeStr;
116     mSubtypeStr  = aCntType.mSubtypeStr;
117     mBoundaryStr = aCntType.mBoundaryStr;
118 
119     if (mFirstParameter) {
120         DeleteParameterList();
121     }
122     if (aCntType.mFirstParameter) {
123         CopyParameterList(aCntType.mFirstParameter);
124     }
125 
126     if (mParent) {
127         mParent->SetModified();
128     }
129 
130     return *this;
131 }
132 
133 
Type() const134 int DwMediaType::Type() const
135 {
136     return mType;
137 }
138 
139 
SetType(int aType)140 void DwMediaType::SetType(int aType)
141 {
142     mType = aType;
143     TypeEnumToStr();
144     SetModified();
145 }
146 
147 
TypeStr() const148 const DwString& DwMediaType::TypeStr() const
149 {
150     return mTypeStr;
151 }
152 
153 
SetTypeStr(const DwString & aStr)154 void DwMediaType::SetTypeStr(const DwString& aStr)
155 {
156     mTypeStr = aStr;
157     TypeStrToEnum();
158     SetModified();
159 }
160 
161 
Subtype() const162 int DwMediaType::Subtype() const
163 {
164     return mSubtype;
165 }
166 
167 
SetSubtype(int aSubtype)168 void DwMediaType::SetSubtype(int aSubtype)
169 {
170     mSubtype = aSubtype;
171     SubtypeEnumToStr();
172     SetModified();
173 }
174 
175 
SubtypeStr() const176 const DwString& DwMediaType::SubtypeStr() const
177 {
178     return mSubtypeStr;
179 }
180 
181 
SetSubtypeStr(const DwString & aStr)182 void DwMediaType::SetSubtypeStr(const DwString& aStr)
183 {
184     mSubtypeStr = aStr;
185     SubtypeStrToEnum();
186     SetModified();
187 }
188 
189 
Boundary() const190 const DwString& DwMediaType::Boundary() const
191 {
192     // Implementation note: this member function is const, which
193     // forbids us from assigning to mBoundaryStr.  The following
194     // trick gets around this.  (ANSI implementations could use the
195     // "mutable" declaration).
196     DwMediaType* _this = (DwMediaType*) this;
197     _this->mBoundaryStr = "";
198     DwParameter* param = mFirstParameter;
199     while (param) {
200         if (DwStrcasecmp(param->Attribute(), "boundary") == 0) {
201             // Boundary parameter found. Return its value.
202             _this->mBoundaryStr = param->Value();
203             break;
204         }
205         param = param->Next();
206     }
207     return mBoundaryStr;
208 }
209 
210 
SetBoundary(const DwString & aStr)211 void DwMediaType::SetBoundary(const DwString& aStr)
212 {
213     mBoundaryStr = aStr;
214     // Search for boundary parameter in parameter list.  If found, set its
215     // value.
216     DwParameter* param = mFirstParameter;
217     while (param) {
218         if (DwStrcasecmp(param->Attribute(), "boundary") == 0) {
219             param->SetValue(mBoundaryStr);
220             return;
221         }
222         param = param->Next();
223     }
224     // Boundary parameter not found. Add it.
225     param = DwParameter::NewParameter("", 0);
226     param->SetAttribute("boundary");
227     param->SetValue(aStr);
228     AddParameter(param);
229 }
230 
231 
CreateBoundary(unsigned aLevel)232 void DwMediaType::CreateBoundary(unsigned aLevel)
233 {
234     // Create a random printable string and set it as the boundary parameter
235     char buf[40];
236     strcpy(buf, "Boundary-");
237     int pos = 9;
238     if (aLevel > 0) {
239         int n = aLevel / 100;
240         if (n != 0) {
241             buf[pos++] = (char) ((n % 10) + '0');
242         }
243         n = aLevel / 10;
244         if (n != 0) {
245            buf[pos++] = (char) ((n % 10) + '0');
246         }
247         n = aLevel;
248         buf[pos++] = (char) ((n % 10) + '0');
249     }
250     buf[pos++] = '=';
251     buf[pos++] = '_';
252     while (pos < 39) {
253         int ch = rand() % 52;
254         if (ch < 26) {
255             buf[pos++] = (char) ('A' + ch);
256         }
257         else {
258             buf[pos++] = (char) ('a' + ch - 26);
259         }
260     }
261     buf[pos] = 0;
262     SetBoundary(buf);
263 }
264 
265 
Name() const266 const DwString& DwMediaType::Name() const
267 {
268     // Implementation note: this member function is const, which
269     // forbids us from assigning to mNameStr.  The following
270     // trick gets around this.  (ANSI implementations could use the
271     // "mutable" declaration).
272     DwMediaType* _this = (DwMediaType*) this;
273     _this->mNameStr = "";
274     DwParameter* param = mFirstParameter;
275     while (param) {
276         if (DwStrcasecmp(param->Attribute(), "name") == 0) {
277             // Name parameter found. Return its value.
278             _this->mNameStr = param->Value();
279             break;
280         }
281         param = param->Next();
282     }
283     return mNameStr;
284 }
285 
286 
SetName(const DwString & aStr)287 void DwMediaType::SetName(const DwString& aStr)
288 {
289     mNameStr = aStr;
290     // Search for name parameter in parameter list.  If found, set its
291     // value.
292     DwParameter* param = mFirstParameter;
293     while (param) {
294         if (DwStrcasecmp(param->Attribute(), "name") == 0) {
295             param->SetValue(mNameStr);
296             return;
297         }
298         param = param->Next();
299     }
300     // Name parameter not found. Add it.
301     param = DwParameter::NewParameter("", 0);
302     param->SetAttribute("name");
303     param->SetValue(aStr);
304     AddParameter(param);
305 }
306 
307 
FirstParameter() const308 DwParameter* DwMediaType::FirstParameter() const
309 {
310     return mFirstParameter;
311 }
312 
313 
AddParameter(DwParameter * aParam)314 void DwMediaType::AddParameter(DwParameter* aParam)
315 {
316     _AddParameter(aParam);
317     SetModified();
318 }
319 
320 
_AddParameter(DwParameter * aParam)321 void DwMediaType::_AddParameter(DwParameter* aParam)
322 {
323     if (!mFirstParameter) {
324         mFirstParameter = aParam;
325     }
326     else {
327         DwParameter* cur = mFirstParameter;
328         DwParameter* next = cur->Next();
329         while (next) {
330             cur = next;
331             next = cur->Next();
332         }
333         cur->SetNext(aParam);
334     }
335     aParam->SetParent(this);
336 }
337 
338 
Parse()339 void DwMediaType::Parse()
340 {
341     mIsModified = 0;
342     mTypeStr = "";
343     mSubtypeStr = "";
344     mType = DwMime::kTypeNull;
345     mSubtype = DwMime::kSubtypeNull;
346     if (mFirstParameter) {
347         DeleteParameterList();
348     }
349     if (mString.length() == 0) return;
350     DwRfc1521Tokenizer tokenizer(mString);
351 
352     // Get type.
353     int found = 0;
354     while (!found && tokenizer.Type() != eTkNull) {
355         if (tokenizer.Type() == eTkToken) {
356             mTypeStr = tokenizer.Token();
357             found = 1;
358         }
359         ++tokenizer;
360     }
361     // Get '/'
362     found = 0;
363     while (!found && tokenizer.Type() != eTkNull) {
364         if (tokenizer.Type() == eTkTspecial
365             && tokenizer.Token()[0] == '/') {
366             found = 1;
367         }
368         ++tokenizer;
369     }
370     // Get subtype
371     found = 0;
372     while (!found && tokenizer.Type() != eTkNull) {
373         if (tokenizer.Type() == eTkToken) {
374             mSubtypeStr = tokenizer.Token();
375             found = 1;
376         }
377         ++tokenizer;
378     }
379     // Get parameters
380     DwTokenString tokenStr(mString);
381     while (1) {
382         // Get ';'
383         found = 0;
384         while (!found && tokenizer.Type() != eTkNull) {
385             if (tokenizer.Type() == eTkTspecial
386                 && tokenizer.Token()[0] == ';') {
387                 found = 1;
388             }
389             ++tokenizer;
390         }
391         if (tokenizer.Type() == eTkNull) {
392             // No more parameters
393             break;
394         }
395         tokenStr.SetFirst(tokenizer);
396         // Get attribute
397         DwString attrib;
398         int attribFound = 0;
399         while (!attribFound && tokenizer.Type() != eTkNull) {
400             if (tokenizer.Type() == eTkToken) {
401                 attrib = tokenizer.Token();
402                 attribFound = 1;
403             }
404             ++tokenizer;
405         }
406         // Get '='
407         found = 0;
408         while (!found && tokenizer.Type() != eTkNull) {
409             if (tokenizer.Type() == eTkTspecial
410                 && tokenizer.Token()[0] == '=') {
411                 found = 1;
412             }
413             ++tokenizer;
414         }
415         // Get value
416         int valueFound = 0;
417         while (!valueFound && tokenizer.Type() != eTkNull) {
418             if (tokenizer.Type() == eTkToken
419                 || tokenizer.Type() == eTkQuotedString) {
420                 valueFound = 1;
421             }
422             ++tokenizer;
423         }
424         if (attribFound && valueFound) {
425             tokenStr.ExtendTo(tokenizer);
426             DwParameter* param =
427                 DwParameter::NewParameter(tokenStr.Tokens(), this);
428             param->Parse();
429             _AddParameter(param);
430         }
431     }
432     TypeStrToEnum();
433     SubtypeStrToEnum();
434 }
435 
436 
Assemble()437 void DwMediaType::Assemble()
438 {
439     if (!mIsModified) return;
440     mString = "";
441     if (mTypeStr.length() == 0 || mSubtypeStr.length() == 0)
442         return;
443     mString += mTypeStr;
444     mString += '/';
445     mString += mSubtypeStr;
446     DwParameter* param = FirstParameter();
447     while (param) {
448         param->Assemble();
449         if (IsFolding()) {
450             mString += ";" DW_EOL "  ";
451         }
452         else {
453             mString += "; ";
454         }
455         mString += param->AsString();
456         param = param->Next();
457     }
458     mIsModified = 0;
459 }
460 
461 
Clone() const462 DwMessageComponent* DwMediaType::Clone() const
463 {
464     return new DwMediaType(*this);
465 }
466 
467 
TypeEnumToStr()468 void DwMediaType::TypeEnumToStr()
469 {
470     DwTypeEnumToStr(mType, mTypeStr);
471 }
472 
473 
TypeStrToEnum()474 void DwMediaType::TypeStrToEnum()
475 {
476     mType = DwTypeStrToEnum(mTypeStr);
477 }
478 
479 
SubtypeEnumToStr()480 void DwMediaType::SubtypeEnumToStr()
481 {
482     DwSubtypeEnumToStr(mSubtype, mSubtypeStr);
483 }
484 
485 
SubtypeStrToEnum()486 void DwMediaType::SubtypeStrToEnum()
487 {
488     mSubtype = DwSubtypeStrToEnum(mSubtypeStr);
489 }
490 
491 
DeleteParameterList()492 void DwMediaType::DeleteParameterList()
493 {
494     DwParameter* param = mFirstParameter;
495     while (param) {
496         DwParameter* nextParam = param->Next();
497         delete param;
498         param = nextParam;
499     }
500     mFirstParameter = 0;
501     SetModified();
502 }
503 
504 
CopyParameterList(DwParameter * aFirst)505 void DwMediaType::CopyParameterList(DwParameter* aFirst)
506 {
507     DwParameter* param = aFirst;
508     while (param) {
509         DwParameter* newParam = (DwParameter*) param->Clone();
510         AddParameter(newParam);
511         param = param->Next();
512     }
513 }
514 
515 
PrintDebugInfo(ostream & aStrm,int aDepth) const516 void DwMediaType::PrintDebugInfo(ostream& aStrm, int aDepth) const
517 {
518 #if defined(DW_DEBUG_VERSION)
519     aStrm <<
520     "--------------- Debug info for DwMediaType class ---------------\n";
521     _PrintDebugInfo(aStrm);
522     int depth = aDepth - 1;
523     depth = (depth >= 0) ? depth : 0;
524     if (aDepth == 0 || depth > 0) {
525         DwParameter* param = mFirstParameter;
526         while (param) {
527             param->PrintDebugInfo(aStrm, depth);
528             param = param->Next();
529         }
530     }
531 #endif // defined(DW_DEBUG_VERSION)
532 }
533 
534 
_PrintDebugInfo(ostream & aStrm) const535 void DwMediaType::_PrintDebugInfo(ostream& aStrm) const
536 {
537 #if defined(DW_DEBUG_VERSION)
538     DwFieldBody::_PrintDebugInfo(aStrm);
539     aStrm << "Type:             " << mTypeStr    << " (" << mType    << ")\n";
540     aStrm << "Subtype:          " << mSubtypeStr << " (" << mSubtype << ")\n";
541     aStrm << "Boundary:         " << mBoundaryStr << '\n';
542     aStrm << "Parameters:       ";
543     DwParameter* param = mFirstParameter;
544     if (param) {
545         int count = 0;
546         while (param) {
547             if (count) aStrm << ' ';
548             aStrm << param->ObjectId();
549             param = param->Next();
550             ++count;
551         }
552         aStrm << '\n';
553     }
554     else {
555         aStrm << "(none)\n";
556     }
557 #endif // defined(DW_DEBUG_VERSION)
558 }
559 
560 
CheckInvariants() const561 void DwMediaType::CheckInvariants() const
562 {
563 #if defined(DW_DEBUG_VERSION)
564     mTypeStr.CheckInvariants();
565     mSubtypeStr.CheckInvariants();
566     mBoundaryStr.CheckInvariants();
567     DwParameter* param = mFirstParameter;
568     while (param) {
569         param->CheckInvariants();
570         assert((DwMessageComponent*) this == param->Parent());
571         param = param->Next();
572     }
573 #endif // defined(DW_DEBUG_VERSION)
574 }
575