~ubuntu-branches/ubuntu/edgy/sope/edgy

« back to all changes in this revision

Viewing changes to sope-mime/NGMime/NGMimeType.m

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Ley
  • Date: 2005-08-19 16:53:31 UTC
  • Revision ID: james.westby@ubuntu.com-20050819165331-hs683wz1osm708pw
Tags: upstream-4.4rc.2
ImportĀ upstreamĀ versionĀ 4.4rc.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  Copyright (C) 2000-2005 SKYRIX Software AG
 
3
 
 
4
  This file is part of SOPE.
 
5
 
 
6
  SOPE is free software; you can redistribute it and/or modify it under
 
7
  the terms of the GNU Lesser General Public License as published by the
 
8
  Free Software Foundation; either version 2, or (at your option) any
 
9
  later version.
 
10
 
 
11
  SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
 
12
  WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
13
  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 
14
  License for more details.
 
15
 
 
16
  You should have received a copy of the GNU Lesser General Public
 
17
  License along with SOPE; see the file COPYING.  If not, write to the
 
18
  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
19
  02111-1307, USA.
 
20
*/
 
21
 
 
22
#include "NGMimeType.h"
 
23
#include "NGConcreteMimeType.h"
 
24
#include "NGMimeUtilities.h"
 
25
#include "common.h"
 
26
 
 
27
NGMime_DECLARE NSString *NGMimeTypeText        = @"text";
 
28
NGMime_DECLARE NSString *NGMimeTypeAudio       = @"audio";
 
29
NGMime_DECLARE NSString *NGMimeTypeVideo       = @"video";
 
30
NGMime_DECLARE NSString *NGMimeTypeImage       = @"image";
 
31
NGMime_DECLARE NSString *NGMimeTypeApplication = @"application";
 
32
NGMime_DECLARE NSString *NGMimeTypeMultipart   = @"multipart";
 
33
NGMime_DECLARE NSString *NGMimeTypeMessage     = @"message";
 
34
NGMime_DECLARE NSString *NGMimeParameterTextCharset = @"charset";
 
35
 
 
36
static BOOL _parseMimeType(id self, NSString *_str, NSString **type,
 
37
                           NSString **subType, NSDictionary **parameters);
 
38
 
 
39
@implementation NGMimeType
 
40
 
 
41
+ (int)version {
 
42
  return 2;
 
43
}
 
44
 
 
45
static NSMutableDictionary *typeToClass = nil;
 
46
 
 
47
static inline Class
 
48
classForType(NSString *_type, NSString *_subType, NSDictionary *_parameters)
 
49
{
 
50
  Class c = Nil;
 
51
  if (_type == nil) return Nil;
 
52
 
 
53
  if ([_type isEqualToString:@"*"] || [_subType isEqualToString:@"*"])
 
54
    return [NGConcreteWildcardType class];
 
55
 
 
56
  if ([_type isEqualToString:NGMimeTypeApplication]) {
 
57
    if ([_subType isEqualToString:@"octet"])
 
58
      return [NGConcreteAppOctetMimeType class];
 
59
  }
 
60
  if ([_type isEqualToString:NGMimeTypeText]) {
 
61
    if ([_subType isEqualToString:@"x-vcard"])
 
62
      return [NGConcreteTextVcardMimeType class];
 
63
  }
 
64
  
 
65
  c = [typeToClass objectForKey:_type];
 
66
  return c ? c : [NGConcreteGenericMimeType class];
 
67
}
 
68
static Class NSStringClass  = Nil;
 
69
 
 
70
+ (void)initialize {
 
71
  static BOOL isInitialized = NO;
 
72
  if (!isInitialized) {
 
73
    isInitialized = YES;
 
74
 
 
75
    typeToClass = [[NSMutableDictionary alloc] initWithCapacity:10];
 
76
    [typeToClass setObject:[NGConcreteTextMimeType  class] 
 
77
                 forKey:NGMimeTypeText];
 
78
    [typeToClass setObject:[NGConcreteVideoMimeType class] 
 
79
                 forKey:NGMimeTypeVideo];
 
80
    [typeToClass setObject:[NGConcreteAudioMimeType class] 
 
81
                 forKey:NGMimeTypeAudio];
 
82
    [typeToClass setObject:[NGConcreteImageMimeType class] 
 
83
                 forKey:NGMimeTypeImage];
 
84
    [typeToClass setObject:[NGConcreteApplicationMimeType class]
 
85
                 forKey:NGMimeTypeApplication];
 
86
    [typeToClass setObject:[NGConcreteMultipartMimeType class]
 
87
                 forKey:NGMimeTypeMultipart];
 
88
    [typeToClass setObject:[NGConcreteMessageMimeType class]
 
89
                 forKey:NGMimeTypeMessage];
 
90
  }
 
91
}
 
92
 
 
93
+ (NSStringEncoding)stringEncodingForCharset:(NSString *)_s {
 
94
  NSString         *charset;
 
95
  NSStringEncoding encoding;
 
96
  BOOL             foundUnsupported;
 
97
 
 
98
  foundUnsupported = NO;  
 
99
  charset          = [_s lowercaseString];
 
100
  
 
101
  if ([charset length] == 0)
 
102
    encoding = [NSString defaultCStringEncoding];
 
103
  
 
104
  /* UTF-, ASCII */
 
105
  else if ([charset isEqualToString:@"us-ascii"])
 
106
    encoding = NSASCIIStringEncoding;
 
107
  else if ([charset isEqualToString:@"utf-8"])
 
108
    encoding = NSUTF8StringEncoding;
 
109
  else if ([charset isEqualToString:@"utf-16"])
 
110
    encoding = NSUnicodeStringEncoding;
 
111
 
 
112
  /* ISO Latin 1 */
 
113
  else if ([charset isEqualToString:@"iso-latin-1"])
 
114
    encoding = NSISOLatin1StringEncoding;
 
115
  else if ([charset isEqualToString:@"iso-8859-1"])
 
116
    encoding = NSISOLatin1StringEncoding;
 
117
  else if ([charset isEqualToString:@"8859-1"])
 
118
    encoding = NSISOLatin1StringEncoding;
 
119
  
 
120
  /* some unsupported, but known encoding */
 
121
  else if ([charset isEqualToString:@"ks_c_5601-1987"]) {
 
122
    encoding = [NSString defaultCStringEncoding];
 
123
    foundUnsupported = YES;
 
124
  }
 
125
  else if ([charset isEqualToString:@"euc-kr"]) {
 
126
    encoding = [NSString defaultCStringEncoding];
 
127
    foundUnsupported = YES;
 
128
  }
 
129
  else if ([charset isEqualToString:@"big5"]) {
 
130
    encoding = [NSString defaultCStringEncoding];
 
131
    foundUnsupported = YES;
 
132
  }
 
133
  else if ([charset isEqualToString:@"iso-2022-jp"]) {
 
134
    encoding = [NSString defaultCStringEncoding];
 
135
    foundUnsupported = YES;
 
136
  }
 
137
  else if ([charset isEqualToString:@"gb2312"]) {
 
138
    encoding = [NSString defaultCStringEncoding];
 
139
    foundUnsupported = YES;
 
140
  }
 
141
  else if ([charset isEqualToString:@"koi8-r"]) {
 
142
    encoding = [NSString defaultCStringEncoding];
 
143
    foundUnsupported = YES;
 
144
  }
 
145
  
 
146
  else if ([charset isEqualToString:@"windows-1252"]) {
 
147
    encoding = NSWindowsCP1252StringEncoding;
 
148
  }
 
149
  else if ([charset isEqualToString:@"iso-8859-2"]) {
 
150
    encoding = NSISOLatin2StringEncoding;
 
151
  }
 
152
  else if ([charset isEqualToString:@"x-unknown"] ||
 
153
           [charset isEqualToString:@"unknown"]) {
 
154
    encoding = NSASCIIStringEncoding;
 
155
  }
 
156
  /* ISO Latin 9 */
 
157
#if !(NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY)
 
158
  else if ([charset isEqualToString:@"iso-latin-9"])
 
159
    encoding = NSISOLatin9StringEncoding;
 
160
  else if ([charset isEqualToString:@"iso-8859-15"])
 
161
    encoding = NSISOLatin9StringEncoding;
 
162
  else if ([charset isEqualToString:@"8859-15"])
 
163
    encoding = NSISOLatin9StringEncoding;
 
164
#endif
 
165
  else {
 
166
    [self logWithFormat:@"%s: unknown charset '%@'",
 
167
          __PRETTY_FUNCTION__, _s];
 
168
    encoding = [NSString defaultCStringEncoding];
 
169
  }
 
170
  return encoding;
 
171
}
 
172
 
 
173
// init
 
174
 
 
175
- (id)initWithType:(NSString *)_type subType:(NSString *)_subType
 
176
  parameters:(NSDictionary *)_parameters
 
177
{
 
178
  Class c;
 
179
 
 
180
  c = classForType(_type, _subType, _parameters);
 
181
  [self release];
 
182
  
 
183
  return [[c alloc] initWithType:_type subType:_subType
 
184
                    parameters:_parameters];
 
185
}
 
186
 
 
187
+ (id)mimeType:(NSString *)_type subType:(NSString *)_subType {
 
188
  Class c;
 
189
 
 
190
  c = classForType(_type, _subType, nil);
 
191
  
 
192
  NSAssert(c, @"did not find class for mimetype ..");
 
193
 
 
194
  return [[[c alloc] initWithType:_type subType:_subType
 
195
                     parameters:nil] autorelease];
 
196
}
 
197
 
 
198
+ (id)mimeType:(NSString *)_type subType:(NSString *)_subType
 
199
  parameters:(NSDictionary *)_parameters
 
200
{
 
201
  Class c;
 
202
 
 
203
  c = classForType(_type, _subType, _parameters);
 
204
  NSAssert(c, @"did not find class for mimetype ..");
 
205
  
 
206
  return [[[c alloc] initWithType:_type subType:_subType
 
207
                     parameters:_parameters] autorelease];
 
208
}
 
209
 
 
210
+ (id)mimeType:(NSString *)_stringValue {
 
211
  NSString     *type, *subType;
 
212
  NSDictionary *parameters;
 
213
 
 
214
  if ([_stringValue length] == 0)
 
215
    /* empty ... */
 
216
    return nil;
 
217
 
 
218
  parameters = nil;
 
219
  type       = nil;
 
220
  subType    = nil;
 
221
 
 
222
  if (_parseMimeType(self, _stringValue, &type, &subType, &parameters)) {
 
223
    Class c;
 
224
    id    result;
 
225
 
 
226
    c = classForType(type, subType, nil);
 
227
    NSAssert(c,       @"did not find class for mimetype ..");
 
228
    NSAssert(type,    @"didn't parse type ..");
 
229
    NSAssert(subType, @"didn't parse subtype ..");
 
230
 
 
231
    result = [c alloc];
 
232
    NSAssert(result, @"allocation of mimetype failed ..");
 
233
 
 
234
    result = [result initWithType:type subType:subType parameters:parameters];
 
235
    NSAssert(result, @"initialization of mimetype failed ..");
 
236
 
 
237
    result = [result autorelease];
 
238
    NSAssert(result, @"autorelease of mimetype failed ..");
 
239
 
 
240
    return result;
 
241
  }
 
242
  else {
 
243
    [self logWithFormat:@"ERROR[%s]: parsing of mimetype '%@' failed !",
 
244
          __PRETTY_FUNCTION__, _stringValue];
 
245
    return nil; // parsing failed
 
246
  }
 
247
}
 
248
 
 
249
/* types */
 
250
 
 
251
- (NSString *)type {
 
252
  [self subclassResponsibility:_cmd];
 
253
  return nil;
 
254
}
 
255
- (NSString *)subType {
 
256
  [self subclassResponsibility:_cmd];
 
257
  return nil;
 
258
}
 
259
- (BOOL)isCompositeType {
 
260
  [self subclassResponsibility:_cmd];
 
261
  return NO;
 
262
}
 
263
 
 
264
/* comparing types */
 
265
 
 
266
- (BOOL)isEqual:(id)_other {
 
267
  if (_other == nil)  return NO;
 
268
  if (_other == self) return YES;
 
269
 
 
270
  return ([_other isKindOfClass:[NGMimeType class]])
 
271
    ? [self isEqualToMimeType:_other]
 
272
    : NO;
 
273
}
 
274
 
 
275
- (BOOL)isEqualToMimeType:(NGMimeType *)_type {
 
276
  if (_type == nil)  return NO;
 
277
  if (_type == self) return YES;
 
278
 
 
279
  if (![self hasSameType:_type])
 
280
    return NO;
 
281
 
 
282
  if (![[_type parametersAsDictionary] isEqual:[self parametersAsDictionary]])
 
283
    return NO;
 
284
 
 
285
  return YES;
 
286
}
 
287
 
 
288
- (BOOL)hasSameGeneralType:(NGMimeType *)_other { // only the 'type' must match
 
289
  if (_other == self) return YES;
 
290
  if ([_other isCompositeType] != [self isCompositeType]) return NO;
 
291
  if (![[_other type]    isEqualToString:[self type]])    return NO;
 
292
  return YES;
 
293
}
 
294
- (BOOL)hasSameType:(NGMimeType *)_other { // parameters need not match
 
295
  if (_other == nil)  return NO;
 
296
  if (_other == self) return YES;
 
297
  if ([_other isCompositeType] != [self isCompositeType]) return NO;
 
298
  if (![[_other type]    isEqualToString:[self type]])    return NO;
 
299
  if (![[_other subType] isEqualToString:[self subType]]) return NO;
 
300
  return YES;
 
301
}
 
302
 
 
303
- (BOOL)doesMatchType:(NGMimeType *)_other { // interpretes wildcards
 
304
  NSString *t, *st, *ot, *ost;
 
305
 
 
306
  t   = [self type];
 
307
  st  = [self subType];
 
308
  ot  = [_other type];
 
309
  ost = [_other subType];
 
310
 
 
311
  if ([t isEqualToString:@"*"] || [ot isEqualToString:@"*"]) {
 
312
    t   = @"*";
 
313
    ot  = @"*";
 
314
  }
 
315
  if (![t  isEqualToString:ot]) return NO;
 
316
 
 
317
  if ([st isEqualToString:@"*"] || [ost isEqualToString:@"*"]) {
 
318
    ot  = @"*";
 
319
    ost = @"*";
 
320
  }
 
321
  if (![st isEqualToString:ost]) return NO;
 
322
  
 
323
  return YES;
 
324
}
 
325
 
 
326
/* parameters */
 
327
 
 
328
- (NSEnumerator *)parameterNames {
 
329
  [self doesNotRecognizeSelector:_cmd]; // subclass
 
330
  return nil;
 
331
}
 
332
- (id)valueOfParameter:(NSString *)_parameterName {
 
333
  [self doesNotRecognizeSelector:_cmd]; // subclass
 
334
  return nil;
 
335
}
 
336
 
 
337
/* representations */
 
338
 
 
339
- (NSDictionary *)parametersAsDictionary {
 
340
  NSMutableDictionary *parameters;
 
341
  NSString            *name;
 
342
  NSDictionary        *d;
 
343
  NSEnumerator        *names;
 
344
 
 
345
  if ((names = [self parameterNames]) == nil)
 
346
    return nil;
 
347
 
 
348
  parameters = [[NSMutableDictionary alloc] init];
 
349
  while ((name = [names nextObject]))
 
350
    [parameters setObject:[self valueOfParameter:name] forKey:name];
 
351
 
 
352
  d = [parameters copy];
 
353
  [parameters release];
 
354
  return [d autorelease];
 
355
}
 
356
 
 
357
- (NSString *)parametersAsString {
 
358
  NSEnumerator    *names;
 
359
  NSMutableString *result;
 
360
  NSString        *name;
 
361
 
 
362
  if ((names = [self parameterNames]) == nil)
 
363
    return nil;
 
364
  
 
365
  result = [NSMutableString stringWithCapacity:64];
 
366
  while ((name = [names nextObject])) {
 
367
    NSString *value;
 
368
 
 
369
    value = [[self valueOfParameter:name] stringValue];
 
370
    
 
371
    [result appendString:@"; "];
 
372
    [result appendString:name];
 
373
    [result appendString:@"="];
 
374
    
 
375
    if ([self valueNeedsQuotes:value]) {
 
376
      [result appendString:@"\""];
 
377
      [result appendString:value];
 
378
      [result appendString:@"\""];
 
379
    }
 
380
    else
 
381
      [result appendString:value];
 
382
  }
 
383
  return result;
 
384
}
 
385
 
 
386
- (BOOL)valueNeedsQuotes:(NSString *)_parameterValue {
 
387
  unsigned len = [_parameterValue cStringLength];
 
388
  char     buf[len + 15];
 
389
  char     *cstr;
 
390
 
 
391
  cstr = &(buf[0]);
 
392
 
 
393
  [_parameterValue getCString:cstr]; cstr[len] = '\0';
 
394
  while (*cstr) {
 
395
    if (isMime_SpecialByte(*cstr))
 
396
      return YES;
 
397
 
 
398
    if (*cstr == 32)
 
399
      return YES;
 
400
    
 
401
    cstr++;
 
402
  }
 
403
  return NO;
 
404
}
 
405
 
 
406
- (NSString *)stringValue {
 
407
  [self subclassResponsibility:_cmd];
 
408
  return nil;
 
409
}
 
410
 
 
411
// NSCoding
 
412
 
 
413
- (Class)classForCoder {
 
414
  return [NGMimeType class];
 
415
}
 
416
 
 
417
- (void)encodeWithCoder:(NSCoder *)_encoder {
 
418
  [_encoder encodeObject:[self type]];
 
419
  [_encoder encodeObject:[self subType]];
 
420
  [_encoder encodeObject:[self parametersAsDictionary]];
 
421
}
 
422
 
 
423
- (id)initWithCoder:(NSCoder *)_decoder {
 
424
  NSString     *type, *subType;
 
425
  NSDictionary *paras;
 
426
 
 
427
  type    = [_decoder decodeObject];
 
428
  subType = [_decoder decodeObject];
 
429
  paras   = [_decoder decodeObject];
 
430
 
 
431
  return [self initWithType:type subType:subType parameters:paras];
 
432
}
 
433
 
 
434
// NSCopying
 
435
 
 
436
- (id)copyWithZone:(NSZone *)_zone {
 
437
  return [[NGMimeType allocWithZone:_zone]
 
438
                      initWithType:[self type] subType:[self subType]
 
439
                      parameters:[self parametersAsDictionary]];
 
440
}
 
441
 
 
442
// description
 
443
 
 
444
- (NSString *)description {
 
445
  return [NSString stringWithFormat:@"<NGMimeType: %@>", [self stringValue]];
 
446
}
 
447
 
 
448
@end /* NGMimeType */
 
449
 
 
450
typedef struct {
 
451
  NSString *image;
 
452
  NSString *video;
 
453
  NSString *audio;
 
454
  NSString *text;
 
455
  NSString *star;
 
456
  NSString *application;
 
457
  NSString *multipart;
 
458
  NSString *message;
 
459
} NGMimeTypeConstants;
 
460
 
 
461
typedef struct {
 
462
  NSString *plain;
 
463
  NSString *star;
 
464
  NSString *mixed;
 
465
  NSString *jpeg;
 
466
  NSString *png;
 
467
  NSString *gif;
 
468
  NSString *xml;
 
469
  NSString *html;
 
470
  NSString *css;
 
471
  NSString *xMng;
 
472
  NSString *xhtmlXml;
 
473
  NSString *rfc822;
 
474
  NSString *octetStream;
 
475
} NGMimeSubTypeConstants;
 
476
 
 
477
static NGMimeTypeConstants      *MimeTypeConstants      = NULL;
 
478
static NGMimeSubTypeConstants   *MimeSubTypeConstants   = NULL;
 
479
 
 
480
static NSString *_stringForType(char *_type, int _len) {
 
481
  if (NSStringClass == Nil) NSStringClass = [NSString class];
 
482
 
 
483
  if (MimeTypeConstants == NULL) {
 
484
    MimeTypeConstants = malloc(sizeof(NGMimeTypeConstants));
 
485
    MimeTypeConstants->image       = NGMimeTypeImage;
 
486
    MimeTypeConstants->video       = NGMimeTypeVideo;
 
487
    MimeTypeConstants->audio       = NGMimeTypeAudio;
 
488
    MimeTypeConstants->text        = NGMimeTypeText;
 
489
    MimeTypeConstants->star        = @"*";
 
490
    MimeTypeConstants->application = NGMimeTypeApplication;
 
491
    MimeTypeConstants->multipart   = NGMimeTypeMultipart;
 
492
    MimeTypeConstants->message     = NGMimeTypeMessage;
 
493
  }
 
494
  switch (_len) {
 
495
    case 0:
 
496
      return @"";
 
497
    case 1:
 
498
      if (_type[0] == '*')
 
499
        return MimeTypeConstants->star;
 
500
      break;
 
501
    case 4:
 
502
      if (strncmp(_type, "text", 4) == 0) 
 
503
        return MimeTypeConstants->text;
 
504
      break;
 
505
    case 5:
 
506
      if (_type[0] == 'i') {
 
507
        if (strncmp(_type, "image", 5) == 0) 
 
508
          return MimeTypeConstants->image;
 
509
      }
 
510
      else if (_type[0] == 'v') {
 
511
        if (strncmp(_type, "video", 5) == 0) 
 
512
          return MimeTypeConstants->video;
 
513
      }
 
514
      else if (_type[0] == 'a') {
 
515
        if (strncmp(_type, "audio", 5) == 0) 
 
516
          return MimeTypeConstants->audio;
 
517
      }
 
518
      break;
 
519
    case 7:
 
520
      if (strncmp(_type, "message", 7) == 0)
 
521
        return MimeTypeConstants->message;
 
522
      break;
 
523
    case 9:
 
524
      if (strncmp(_type, "multipart", 9) == 0)
 
525
        return MimeTypeConstants->multipart;
 
526
      break;    case 11:
 
527
      if (strncmp(_type, "application", 11) == 0)
 
528
        return MimeTypeConstants->application;
 
529
      break;
 
530
  }
 
531
  return [NSStringClass stringWithCString:_type length:_len];
 
532
}
 
533
 
 
534
static NSString *_stringForSubType(char *_type, int _len) {
 
535
  if (NSStringClass == Nil) NSStringClass = [NSString class];
 
536
 
 
537
  if (MimeSubTypeConstants == NULL) {
 
538
    MimeSubTypeConstants = malloc(sizeof(NGMimeSubTypeConstants));
 
539
 
 
540
    MimeSubTypeConstants->plain       = @"plain";
 
541
    MimeSubTypeConstants->star        = @"*";
 
542
    MimeSubTypeConstants->mixed       = @"mixed";
 
543
    MimeSubTypeConstants->jpeg        = @"jpeg";
 
544
    MimeSubTypeConstants->png         = @"png";
 
545
    MimeSubTypeConstants->gif         = @"gif";
 
546
    MimeSubTypeConstants->xml         = @"xml";
 
547
    MimeSubTypeConstants->html        = @"html";
 
548
    MimeSubTypeConstants->css         = @"css";
 
549
    MimeSubTypeConstants->xMng        = @"xMng";
 
550
    MimeSubTypeConstants->xhtmlXml    = @"xhtmlXml";
 
551
    MimeSubTypeConstants->rfc822      = @"rfc822";
 
552
    MimeSubTypeConstants->octetStream = @"octet-stream";
 
553
  }
 
554
  switch (_len) {
 
555
    case 0:
 
556
      return @"";
 
557
 
 
558
    case 1:
 
559
      if (_type[0] == '*')
 
560
        return MimeSubTypeConstants->star;
 
561
      break;
 
562
    case 3:
 
563
      if (_type[0] == 'p') {
 
564
        if (strncmp(_type, "png", 3) == 0) 
 
565
          return MimeSubTypeConstants->png;
 
566
      }
 
567
      else if (_type[0] == 'g') {
 
568
        if (strncmp(_type, "gif", 3) == 0) 
 
569
          return MimeSubTypeConstants->gif;
 
570
      }
 
571
      else if (_type[0] == 'c') {
 
572
        if (strncmp(_type, "css", 3) == 0) 
 
573
          return MimeSubTypeConstants->css;
 
574
      }
 
575
      else if (_type[0] == 'x') {
 
576
        if (strncmp(_type, "xml", 3) == 0) 
 
577
          return MimeSubTypeConstants->xml;
 
578
      }
 
579
      break;
 
580
    case 4:
 
581
      if (_type[0] == 'h') {
 
582
        if (strncmp(_type, "html", 4) == 0) 
 
583
          return MimeSubTypeConstants->html;
 
584
      }
 
585
      else if (_type[0] == 'j') {
 
586
        if (strncmp(_type, "jpeg", 4) == 0) 
 
587
          return MimeSubTypeConstants->jpeg;
 
588
      }
 
589
      break;
 
590
    case 5:
 
591
      if (_type[0] == 'p') {
 
592
        if (strncmp(_type, "plain", 5) == 0) 
 
593
          return MimeSubTypeConstants->plain;
 
594
      }
 
595
      else if (_type[0] == 'm') {
 
596
        if (strncmp(_type, "mixed", 5) == 0) 
 
597
          return MimeSubTypeConstants->mixed;
 
598
      }
 
599
      else if (_type[0] == 'x') {
 
600
        if (strncmp(_type, "x-mng", 5) == 0) 
 
601
          return MimeSubTypeConstants->xMng;
 
602
      }
 
603
      break;
 
604
    case 6:
 
605
      if (strncmp(_type, "rfc822", 6) == 0) 
 
606
          return MimeSubTypeConstants->rfc822;
 
607
      break;
 
608
    case 9:
 
609
      if (strncmp(_type, "xhtml+xml", 9) == 0) 
 
610
          return MimeSubTypeConstants->xhtmlXml;
 
611
      break;
 
612
    case 12:
 
613
      if (strncmp(_type, "octet-stream", 12) == 0) 
 
614
          return MimeSubTypeConstants->octetStream;
 
615
      break;
 
616
  }
 
617
  return [NSStringClass stringWithCString:_type length:_len];
 
618
}
 
619
 
 
620
static BOOL _parseMimeType(id self, NSString *_str, NSString **type,
 
621
                           NSString **subType, NSDictionary **parameters)
 
622
{
 
623
  unsigned len;
 
624
  unichar  *cstr, *tmp;
 
625
  unsigned slen  = [_str length];
 
626
  unichar  buf[slen + 1];
 
627
 
 
628
  len  = 0;
 
629
  cstr = &(buf[0]);
 
630
 
 
631
  [_str getCharacters:buf]; buf[slen] = '\0';
 
632
 
 
633
  /* skip leading spaces */
 
634
  while (isRfc822_LWSP(*cstr) && (*cstr != '\0'))
 
635
    cstr++;
 
636
 
 
637
  /* type name */
 
638
  tmp = cstr; // keep beginning of type name
 
639
  len = 0;
 
640
  while ((*cstr != '/') && (*cstr != '\0') && (*cstr != ';')) {
 
641
    cstr++;
 
642
    len++;
 
643
  }
 
644
  if (len == 0) return NO; // no type was read
 
645
 
 
646
  {
 
647
    unsigned char     buf[len + 1];
 
648
    register unsigned i;
 
649
    
 
650
    buf[len] = '\0';
 
651
    for (i = 0; i < len; i++) buf[i] = tolower(tmp[i]);
 
652
    *type = _stringForType(buf, len);
 
653
  }
 
654
 
 
655
  if (*cstr == '/') { // subtype name
 
656
    cstr++; // skip '/'
 
657
 
 
658
    tmp = cstr; // keep beginning of subtype name
 
659
    len = 0;
 
660
    while ((*cstr != ';') && (!isRfc822_LWSP(*cstr)) && (*cstr != '\0')) {
 
661
      cstr++;
 
662
      len++;
 
663
    }
 
664
    if (len <= 0) {
 
665
      *subType = @"*";
 
666
      return YES; // no subtype was read      
 
667
    }
 
668
    else {
 
669
      unsigned char     buf[len + 1];
 
670
      register unsigned i;
 
671
      
 
672
      buf[len] = '\0';
 
673
      for (i = 0; i < len; i++) buf[i] = tolower(tmp[i]);
 
674
      *subType = _stringForSubType(buf, len);
 
675
    }
 
676
  }
 
677
  else {
 
678
    *subType = @"*";
 
679
  }
 
680
 
 
681
  // skip spaces
 
682
  while (isRfc822_LWSP(*cstr) && (*cstr != '\0'))
 
683
    cstr++;
 
684
  
 
685
  if (*cstr == ';') // skip ';' (parameter separator)
 
686
    cstr++;
 
687
 
 
688
  // skip spaces
 
689
  while (isRfc822_LWSP(*cstr) && (*cstr != '\0'))
 
690
    cstr++;
 
691
 
 
692
  if (*cstr == '\0') { // string ends, no parameters defined
 
693
    *parameters = nil;
 
694
    return YES;
 
695
  }
 
696
  // parse parameters
 
697
  *parameters = parseParameters(self, _str, cstr);
 
698
  if (![*parameters count])
 
699
    *parameters = nil;
 
700
 
 
701
  return YES;
 
702
}