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