mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-30 00:11:26 +00:00
Various URL handling improvments.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@25154 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
cc25eedb9e
commit
9a44af0e80
9 changed files with 969 additions and 278 deletions
|
@ -40,6 +40,7 @@ Additions_OBJC_FILES =\
|
|||
GSMime.m \
|
||||
GSXML.m \
|
||||
GSFunctions.m \
|
||||
GSInsensitiveDictionary.m \
|
||||
behavior.m
|
||||
|
||||
ifneq ($(OBJC_RUNTIME_LIB), gnu)
|
||||
|
|
482
Source/Additions/GSInsensitiveDictionary.m
Normal file
482
Source/Additions/GSInsensitiveDictionary.m
Normal file
|
@ -0,0 +1,482 @@
|
|||
/** Interface to concrete implementation of NSDictionary
|
||||
Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
||||
Date: May 2007
|
||||
|
||||
This file is part of the GNUstep Base Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02111 USA.
|
||||
*/
|
||||
|
||||
|
||||
#include "config.h"
|
||||
#include "Foundation/NSDictionary.h"
|
||||
#include "Foundation/NSAutoreleasePool.h"
|
||||
#include "Foundation/NSUtilities.h"
|
||||
#include "Foundation/NSString.h"
|
||||
#include "Foundation/NSException.h"
|
||||
#include "Foundation/NSPortCoder.h"
|
||||
#include "Foundation/NSDebug.h"
|
||||
// For private method _decodeArrayOfObjectsForKey:
|
||||
#include "Foundation/NSKeyedArchiver.h"
|
||||
|
||||
#include "GNUstepBase/GSObjCRuntime.h"
|
||||
|
||||
/*
|
||||
* The 'Fastmap' stuff provides an inline implementation of a mapping
|
||||
* table - for maximum performance.
|
||||
*/
|
||||
#define GSI_MAP_KTYPES GSUNION_OBJ
|
||||
#define GSI_MAP_VTYPES GSUNION_OBJ
|
||||
#define GSI_MAP_HASH(M, X) [[X.obj lowercaseString] hash]
|
||||
#define GSI_MAP_EQUAL(M, X,Y) (([X.obj caseInsensitiveCompare: Y.obj]\
|
||||
== NSOrderedSame) ? YES : NO)
|
||||
#define GSI_MAP_RETAIN_KEY(M, X) ((X).obj) = \
|
||||
[((id)(X).obj) copyWithZone: map->zone]
|
||||
|
||||
#include "GNUstepBase/GSIMap.h"
|
||||
|
||||
@interface _GSInsensitiveDictionary : NSDictionary
|
||||
{
|
||||
@public
|
||||
GSIMapTable_t map;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface _GSMutableInsensitiveDictionary : NSMutableDictionary
|
||||
{
|
||||
@public
|
||||
GSIMapTable_t map;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface _GSInsensitiveDictionaryKeyEnumerator : NSEnumerator
|
||||
{
|
||||
_GSInsensitiveDictionary *dictionary;
|
||||
GSIMapEnumerator_t enumerator;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface _GSInsensitiveDictionaryObjectEnumerator : _GSInsensitiveDictionaryKeyEnumerator
|
||||
@end
|
||||
|
||||
@implementation _GSInsensitiveDictionary
|
||||
|
||||
static SEL nxtSel;
|
||||
static SEL objSel;
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
if (self == [_GSInsensitiveDictionary class])
|
||||
{
|
||||
nxtSel = @selector(nextObject);
|
||||
objSel = @selector(objectForKey:);
|
||||
}
|
||||
}
|
||||
|
||||
- (id) copyWithZone: (NSZone*)zone
|
||||
{
|
||||
return RETAIN(self);
|
||||
}
|
||||
|
||||
- (unsigned) count
|
||||
{
|
||||
return map.nodeCount;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
GSIMapEmptyMap(&map);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) encodeWithCoder: (NSCoder*)aCoder
|
||||
{
|
||||
if ([aCoder allowsKeyedCoding])
|
||||
{
|
||||
[super encodeWithCoder: aCoder];
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned count = map.nodeCount;
|
||||
SEL sel = @selector(encodeObject:);
|
||||
IMP imp = [aCoder methodForSelector: sel];
|
||||
GSIMapEnumerator_t enumerator = GSIMapEnumeratorForMap(&map);
|
||||
GSIMapNode node = GSIMapEnumeratorNextNode(&enumerator);
|
||||
|
||||
[aCoder encodeValueOfObjCType: @encode(unsigned) at: &count];
|
||||
while (node != 0)
|
||||
{
|
||||
(*imp)(aCoder, sel, node->key.obj);
|
||||
(*imp)(aCoder, sel, node->value.obj);
|
||||
node = GSIMapEnumeratorNextNode(&enumerator);
|
||||
}
|
||||
GSIMapEndEnumerator(&enumerator);
|
||||
}
|
||||
}
|
||||
|
||||
- (unsigned) hash
|
||||
{
|
||||
return map.nodeCount;
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
return [self initWithObjects: 0 forKeys: 0 count: 0];
|
||||
}
|
||||
|
||||
- (id) initWithCoder: (NSCoder*)aCoder
|
||||
{
|
||||
if ([aCoder allowsKeyedCoding])
|
||||
{
|
||||
self = [super initWithCoder: aCoder];
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned count;
|
||||
id key;
|
||||
id value;
|
||||
SEL sel = @selector(decodeValueOfObjCType:at:);
|
||||
IMP imp = [aCoder methodForSelector: sel];
|
||||
const char *type = @encode(id);
|
||||
|
||||
[aCoder decodeValueOfObjCType: @encode(unsigned)
|
||||
at: &count];
|
||||
|
||||
GSIMapInitWithZoneAndCapacity(&map, GSObjCZone(self), count);
|
||||
while (count-- > 0)
|
||||
{
|
||||
(*imp)(aCoder, sel, type, &key);
|
||||
(*imp)(aCoder, sel, type, &value);
|
||||
GSIMapAddPairNoRetain(&map, (GSIMapKey)key, (GSIMapVal)value);
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/* Designated initialiser */
|
||||
- (id) initWithObjects: (id*)objs forKeys: (id*)keys count: (unsigned)c
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
GSIMapInitWithZoneAndCapacity(&map, GSObjCZone(self), c);
|
||||
for (i = 0; i < c; i++)
|
||||
{
|
||||
GSIMapNode node;
|
||||
|
||||
if (keys[i] == nil)
|
||||
{
|
||||
IF_NO_GC(AUTORELEASE(self));
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Tried to init dictionary with nil key"];
|
||||
}
|
||||
if (objs[i] == nil)
|
||||
{
|
||||
IF_NO_GC(AUTORELEASE(self));
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Tried to init dictionary with nil value"];
|
||||
}
|
||||
|
||||
node = GSIMapNodeForKey(&map, (GSIMapKey)keys[i]);
|
||||
if (node)
|
||||
{
|
||||
IF_NO_GC(RETAIN(objs[i]));
|
||||
RELEASE(node->value.obj);
|
||||
node->value.obj = objs[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
GSIMapAddPair(&map, (GSIMapKey)keys[i], (GSIMapVal)objs[i]);
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/*
|
||||
* This avoids using the designated initialiser for performance reasons.
|
||||
*/
|
||||
- (id) initWithDictionary: (NSDictionary*)other
|
||||
copyItems: (BOOL)shouldCopy
|
||||
{
|
||||
NSZone *z = GSObjCZone(self);
|
||||
unsigned c = [other count];
|
||||
|
||||
GSIMapInitWithZoneAndCapacity(&map, z, c);
|
||||
|
||||
if (c > 0)
|
||||
{
|
||||
NSEnumerator *e = [other keyEnumerator];
|
||||
IMP nxtObj = [e methodForSelector: nxtSel];
|
||||
IMP otherObj = [other methodForSelector: objSel];
|
||||
BOOL isProxy = [other isProxy];
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < c; i++)
|
||||
{
|
||||
GSIMapNode node;
|
||||
id k;
|
||||
id o;
|
||||
|
||||
if (isProxy == YES)
|
||||
{
|
||||
k = [e nextObject];
|
||||
o = [other objectForKey: k];
|
||||
}
|
||||
else
|
||||
{
|
||||
k = (*nxtObj)(e, nxtSel);
|
||||
o = (*otherObj)(other, objSel, k);
|
||||
}
|
||||
k = [k copyWithZone: z];
|
||||
if (k == nil)
|
||||
{
|
||||
IF_NO_GC(AUTORELEASE(self));
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Tried to init dictionary with nil key"];
|
||||
}
|
||||
if (shouldCopy)
|
||||
{
|
||||
o = [o copyWithZone: z];
|
||||
}
|
||||
else
|
||||
{
|
||||
o = RETAIN(o);
|
||||
}
|
||||
if (o == nil)
|
||||
{
|
||||
IF_NO_GC(AUTORELEASE(self));
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Tried to init dictionary with nil value"];
|
||||
}
|
||||
|
||||
node = GSIMapNodeForKey(&map, (GSIMapKey)k);
|
||||
if (node)
|
||||
{
|
||||
RELEASE(node->value.obj);
|
||||
node->value.obj = o;
|
||||
}
|
||||
else
|
||||
{
|
||||
GSIMapAddPairNoRetain(&map, (GSIMapKey)k, (GSIMapVal)o);
|
||||
}
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL) isEqualToDictionary: (NSDictionary*)other
|
||||
{
|
||||
unsigned count;
|
||||
|
||||
if (other == self)
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
count = map.nodeCount;
|
||||
if (count == [other count])
|
||||
{
|
||||
if (count > 0)
|
||||
{
|
||||
GSIMapEnumerator_t enumerator;
|
||||
GSIMapNode node;
|
||||
IMP otherObj = [other methodForSelector: objSel];
|
||||
|
||||
enumerator = GSIMapEnumeratorForMap(&map);
|
||||
while ((node = GSIMapEnumeratorNextNode(&enumerator)) != 0)
|
||||
{
|
||||
id o1 = node->value.obj;
|
||||
id o2 = (*otherObj)(other, objSel, node->key.obj);
|
||||
|
||||
if (o1 != o2 && [o1 isEqual: o2] == NO)
|
||||
{
|
||||
GSIMapEndEnumerator(&enumerator);
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
GSIMapEndEnumerator(&enumerator);
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSEnumerator*) keyEnumerator
|
||||
{
|
||||
return AUTORELEASE([[_GSInsensitiveDictionaryKeyEnumerator allocWithZone:
|
||||
NSDefaultMallocZone()] initWithDictionary: self]);
|
||||
}
|
||||
|
||||
- (NSEnumerator*) objectEnumerator
|
||||
{
|
||||
return AUTORELEASE([[_GSInsensitiveDictionaryObjectEnumerator allocWithZone:
|
||||
NSDefaultMallocZone()] initWithDictionary: self]);
|
||||
}
|
||||
|
||||
- (id) objectForKey: aKey
|
||||
{
|
||||
if (aKey != nil)
|
||||
{
|
||||
GSIMapNode node = GSIMapNodeForKey(&map, (GSIMapKey)aKey);
|
||||
|
||||
if (node)
|
||||
{
|
||||
return node->value.obj;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _GSMutableInsensitiveDictionary
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
if (self == [_GSMutableInsensitiveDictionary class])
|
||||
{
|
||||
GSObjCAddClassBehavior(self, [_GSInsensitiveDictionary class]);
|
||||
}
|
||||
}
|
||||
|
||||
- (id) copyWithZone: (NSZone*)zone
|
||||
{
|
||||
NSDictionary *copy = [_GSInsensitiveDictionary allocWithZone: zone];
|
||||
|
||||
return [copy initWithDictionary: self copyItems: NO];
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
return [self initWithCapacity: 0];
|
||||
}
|
||||
|
||||
/* Designated initialiser */
|
||||
- (id) initWithCapacity: (unsigned)cap
|
||||
{
|
||||
GSIMapInitWithZoneAndCapacity(&map, GSObjCZone(self), cap);
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id) makeImmutableCopyOnFail: (BOOL)force
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
GSDebugAllocationRemove(isa, self);
|
||||
#endif
|
||||
isa = [_GSInsensitiveDictionary class];
|
||||
#ifndef NDEBUG
|
||||
GSDebugAllocationAdd(isa, self);
|
||||
#endif
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) setObject: (id)anObject forKey: (id)aKey
|
||||
{
|
||||
GSIMapNode node;
|
||||
|
||||
if (aKey == nil)
|
||||
{
|
||||
NSException *e;
|
||||
|
||||
e = [NSException exceptionWithName: NSInvalidArgumentException
|
||||
reason: @"Tried to add nil key to dictionary"
|
||||
userInfo: self];
|
||||
[e raise];
|
||||
}
|
||||
if ([aKey isKindOfClass: [NSString class]] == NO)
|
||||
{
|
||||
NSException *e;
|
||||
|
||||
e = [NSException exceptionWithName: NSInvalidArgumentException
|
||||
reason: @"Tried to add non-string key"
|
||||
userInfo: self];
|
||||
[e raise];
|
||||
}
|
||||
node = GSIMapNodeForKey(&map, (GSIMapKey)aKey);
|
||||
if (node)
|
||||
{
|
||||
IF_NO_GC(RETAIN(anObject));
|
||||
RELEASE(node->value.obj);
|
||||
node->value.obj = anObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
GSIMapAddPair(&map, (GSIMapKey)aKey, (GSIMapVal)anObject);
|
||||
}
|
||||
}
|
||||
|
||||
- (void) removeAllObjects
|
||||
{
|
||||
GSIMapCleanMap(&map);
|
||||
}
|
||||
|
||||
- (void) removeObjectForKey: (id)aKey
|
||||
{
|
||||
if (aKey == nil)
|
||||
{
|
||||
NSWarnMLog(@"attempt to remove nil key from dictionary %@", self);
|
||||
return;
|
||||
}
|
||||
GSIMapRemoveKey(&map, (GSIMapKey)aKey);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _GSInsensitiveDictionaryKeyEnumerator
|
||||
|
||||
- (id) initWithDictionary: (NSDictionary*)d
|
||||
{
|
||||
[super init];
|
||||
dictionary = (_GSInsensitiveDictionary*)RETAIN(d);
|
||||
enumerator = GSIMapEnumeratorForMap(&dictionary->map);
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id) nextObject
|
||||
{
|
||||
GSIMapNode node = GSIMapEnumeratorNextNode(&enumerator);
|
||||
|
||||
if (node == 0)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
return node->key.obj;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
GSIMapEndEnumerator(&enumerator);
|
||||
RELEASE(dictionary);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _GSInsensitiveDictionaryObjectEnumerator
|
||||
|
||||
- (id) nextObject
|
||||
{
|
||||
GSIMapNode node = GSIMapEnumeratorNextNode(&enumerator);
|
||||
|
||||
if (node == 0)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
return node->value.obj;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -52,13 +52,16 @@
|
|||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <Foundation/Foundation.h>
|
||||
#include "GNUstepBase/GSMime.h"
|
||||
#include "GNUstepBase/GSXML.h"
|
||||
#include "GNUstepBase/GSCategories.h"
|
||||
#include "GNUstepBase/Unicode.h"
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "GNUstepBase/GSMime.h"
|
||||
#import "GNUstepBase/GSXML.h"
|
||||
#import "GNUstepBase/GSCategories.h"
|
||||
#import "GNUstepBase/Unicode.h"
|
||||
|
||||
#include "../GSPrivate.h"
|
||||
|
||||
static NSCharacterSet *whitespace = nil;
|
||||
static NSCharacterSet *rfc822Specials = nil;
|
||||
|
@ -1373,6 +1376,16 @@ wordData(NSString *word)
|
|||
bytes = (unsigned char*)[data mutableBytes];
|
||||
dataEnd = [data length];
|
||||
|
||||
/* If we are parsing an HTTP response, but it doesn't start
|
||||
* with HTTP/ then it is a very old version where we just
|
||||
* get the body and no headers.
|
||||
*/
|
||||
if (flags.isHttp == 1 && dataEnd > 4
|
||||
&& memcmp(bytes, "HTTP/", 5) != 0)
|
||||
{
|
||||
flags.inBody = 1;
|
||||
}
|
||||
|
||||
while (flags.inBody == 0)
|
||||
{
|
||||
if ([self _unfoldHeader] == NO)
|
||||
|
@ -1418,7 +1431,7 @@ wordData(NSString *word)
|
|||
GSMimeHeader *hdr;
|
||||
|
||||
info = [[document headersNamed: @"http"] lastObject];
|
||||
if (info != nil)
|
||||
if (info != nil && flags.isHttp == 1)
|
||||
{
|
||||
NSString *val;
|
||||
|
||||
|
@ -2158,6 +2171,7 @@ NSDebugMLLog(@"GSMime", @"Header parsed - %@", info);
|
|||
{
|
||||
flags.isHttp = 1;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation GSMimeParser (Private)
|
||||
|
@ -2977,38 +2991,57 @@ static NSCharacterSet *tokenSet = nil;
|
|||
}
|
||||
|
||||
/**
|
||||
* Convert the supplied string to a standardized token by making it
|
||||
* lowercase and removing all illegal characters.
|
||||
* Convert the supplied string to a standardized token by removing
|
||||
* all illegal characters. If preserve is NO then the result is
|
||||
* converted to lowercase.<br />
|
||||
* Returns an autoreleased (and possibly modified) copy of the original.
|
||||
*/
|
||||
+ (NSString*) makeToken: (NSString*)t
|
||||
+ (NSString*) makeToken: (NSString*)t preservingCase: (BOOL)preserve
|
||||
{
|
||||
NSRange r;
|
||||
NSMutableString *m = nil;
|
||||
NSRange r;
|
||||
|
||||
t = [t lowercaseString];
|
||||
r = [t rangeOfCharacterFromSet: nonToken];
|
||||
if (r.length > 0)
|
||||
{
|
||||
NSMutableString *m = [t mutableCopy];
|
||||
|
||||
m = [t mutableCopy];
|
||||
while (r.length > 0)
|
||||
{
|
||||
[m deleteCharactersInRange: r];
|
||||
r = [m rangeOfCharacterFromSet: nonToken];
|
||||
}
|
||||
t = AUTORELEASE(m);
|
||||
t = m;
|
||||
}
|
||||
if (preserve == YES)
|
||||
{
|
||||
t = [t lowercaseString];
|
||||
}
|
||||
else
|
||||
{
|
||||
t = AUTORELEASE([t copy]);
|
||||
}
|
||||
TEST_RELEASE(m);
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the supplied string to a standardized token by making it
|
||||
* lowercase and removing all illegal characters.
|
||||
*/
|
||||
+ (NSString*) makeToken: (NSString*)t
|
||||
{
|
||||
return [self makeToken: t preservingCase: NO];
|
||||
}
|
||||
|
||||
- (id) copyWithZone: (NSZone*)z
|
||||
{
|
||||
GSMimeHeader *c = [GSMimeHeader allocWithZone: z];
|
||||
NSEnumerator *e;
|
||||
NSString *k;
|
||||
|
||||
c = [c initWithName: [self name]
|
||||
c = [c initWithName: [self namePreservingCase: YES]
|
||||
value: [self value]
|
||||
parameters: [self parameters]];
|
||||
parameters: [self parametersPreservingCase: YES]];
|
||||
e = [objects keyEnumerator];
|
||||
while ((k = [e nextObject]) != nil)
|
||||
{
|
||||
|
@ -3021,8 +3054,8 @@ static NSCharacterSet *tokenSet = nil;
|
|||
{
|
||||
RELEASE(name);
|
||||
RELEASE(value);
|
||||
RELEASE(objects);
|
||||
RELEASE(params);
|
||||
TEST_RELEASE(objects);
|
||||
TEST_RELEASE(params);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
@ -3061,8 +3094,6 @@ static NSCharacterSet *tokenSet = nil;
|
|||
value: (NSString*)v
|
||||
parameters: (NSDictionary*)p
|
||||
{
|
||||
objects = [NSMutableDictionary new];
|
||||
params = [NSMutableDictionary new];
|
||||
[self setName: n];
|
||||
[self setValue: v];
|
||||
[self setParameters: p];
|
||||
|
@ -3074,7 +3105,24 @@ static NSCharacterSet *tokenSet = nil;
|
|||
*/
|
||||
- (NSString*) name
|
||||
{
|
||||
return name;
|
||||
return [self namePreservingCase: NO];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this header as originally set (without conversion
|
||||
* to lowercase) if preserve is YES, but as a lowercase string if preserve
|
||||
* is NO.
|
||||
*/
|
||||
- (NSString*) namePreservingCase: (BOOL)preserve
|
||||
{
|
||||
if (preserve == YES)
|
||||
{
|
||||
return name;
|
||||
}
|
||||
else
|
||||
{
|
||||
return [name lowercaseString];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3105,7 +3153,7 @@ static NSCharacterSet *tokenSet = nil;
|
|||
k = [GSMimeHeader makeToken: k];
|
||||
p = [params objectForKey: k];
|
||||
}
|
||||
return p;
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3115,7 +3163,37 @@ static NSCharacterSet *tokenSet = nil;
|
|||
*/
|
||||
- (NSDictionary*) parameters
|
||||
{
|
||||
return AUTORELEASE([params copy]);
|
||||
return [self parametersPreservingCase: NO];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parameters of this header ... a dictionary whose keys
|
||||
* are strings preserving the case originally used to set the values
|
||||
* or all lowercase depending on the preserve argument.
|
||||
*/
|
||||
- (NSDictionary*) parametersPreservingCase: (BOOL)preserve
|
||||
{
|
||||
NSMutableDictionary *m;
|
||||
NSEnumerator *e;
|
||||
NSString *k;
|
||||
|
||||
m = [NSMutableDictionary dictionaryWithCapacity: [params count]];
|
||||
e = [params objectEnumerator];
|
||||
if (preserve == YES)
|
||||
{
|
||||
while ((k = [e nextObject]) != nil)
|
||||
{
|
||||
[m setObject: [params objectForKey: k] forKey: k];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((k = [e nextObject]) != nil)
|
||||
{
|
||||
[m setObject: [params objectForKey: k] forKey: [k lowercaseString]];
|
||||
}
|
||||
}
|
||||
return [m makeImmutableCopyOnFail: NO];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3123,48 +3201,80 @@ static NSCharacterSet *tokenSet = nil;
|
|||
* and including a terminating CR-LF
|
||||
*/
|
||||
- (NSMutableData*) rawMimeData
|
||||
{
|
||||
return [self rawMimeDataPreservingCase: NO];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full text of the header, built from its component parts,
|
||||
* and including a terminating CR-LF.<br />
|
||||
* If preserve is YES then we attempt to build the text using the same
|
||||
* case as it was originally parsed/set from, otherwise we use common
|
||||
* onventions of capitalising the header names and using lowercase
|
||||
* parameter names.
|
||||
*/
|
||||
- (NSMutableData*) rawMimeDataPreservingCase: (BOOL)preserve
|
||||
{
|
||||
NSMutableData *md = [NSMutableData dataWithCapacity: 128];
|
||||
NSEnumerator *e = [params keyEnumerator];
|
||||
NSString *k;
|
||||
NSData *d = [[self name] dataUsingEncoding: NSASCIIStringEncoding];
|
||||
NSString *n = [self namePreservingCase: preserve];
|
||||
NSData *d = [n dataUsingEncoding: NSASCIIStringEncoding];
|
||||
unsigned l = [d length];
|
||||
char buf[l];
|
||||
unsigned int i = 0;
|
||||
BOOL conv = YES;
|
||||
|
||||
#define LIM 120
|
||||
/*
|
||||
* Capitalise the header name. However, the version header is a special
|
||||
* case - it is defined as being literally 'MIME-Version'
|
||||
*/
|
||||
memcpy(buf, [d bytes], l);
|
||||
if (l == 12 && memcmp(buf, "mime-version", 12) == 0)
|
||||
if (preserve == YES)
|
||||
{
|
||||
memcpy(buf, "MIME-Version", 12);
|
||||
/* Protect the user ... MIME-Version *must* have the correct case.
|
||||
*/
|
||||
if ([n caseInsensitiveCompare: @"MIME-Version"] == NSOrderedSame)
|
||||
{
|
||||
[md appendBytes: "MIME-Version" length: 12];
|
||||
}
|
||||
else
|
||||
{
|
||||
[md appendData: d];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (i < l)
|
||||
char buf[l];
|
||||
unsigned i = 0;
|
||||
|
||||
#define LIM 120
|
||||
/*
|
||||
* Capitalise the header name. However, the version header is a special
|
||||
* case - it is defined as being literally 'MIME-Version'
|
||||
*/
|
||||
memcpy(buf, [d bytes], l);
|
||||
if (l == 12 && memcmp(buf, "mime-version", 12) == 0)
|
||||
{
|
||||
if (conv == YES)
|
||||
memcpy(buf, "MIME-Version", 12);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (i < l)
|
||||
{
|
||||
if (islower(buf[i]))
|
||||
if (conv == YES)
|
||||
{
|
||||
buf[i] = toupper(buf[i]);
|
||||
if (islower(buf[i]))
|
||||
{
|
||||
buf[i] = toupper(buf[i]);
|
||||
}
|
||||
}
|
||||
if (buf[i++] == '-')
|
||||
{
|
||||
conv = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
conv = NO;
|
||||
}
|
||||
}
|
||||
if (buf[i++] == '-')
|
||||
{
|
||||
conv = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
conv = NO;
|
||||
}
|
||||
}
|
||||
[md appendBytes: buf length: l];
|
||||
}
|
||||
[md appendBytes: buf length: l];
|
||||
|
||||
d = wordData(value);
|
||||
if ([md length] + [d length] + 2 > LIM)
|
||||
{
|
||||
|
@ -3188,6 +3298,10 @@ static NSCharacterSet *tokenSet = nil;
|
|||
unsigned vl;
|
||||
|
||||
v = [GSMimeHeader makeQuoted: [params objectForKey: k] always: NO];
|
||||
if (preserve == NO)
|
||||
{
|
||||
k = [k lowercaseString];
|
||||
}
|
||||
kd = wordData(k);
|
||||
vd = wordData(v);
|
||||
kl = [kd length];
|
||||
|
@ -3216,13 +3330,14 @@ static NSCharacterSet *tokenSet = nil;
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the name of this header ... converts to lowercase and removes
|
||||
* illegal characters. If given a nil or empty string argument,
|
||||
* sets the name to 'unknown'.
|
||||
* Sets the name of this header ... and removes illegal characters.<br />
|
||||
* If given a nil or empty string argument, sets the name to 'unknown'.<br />
|
||||
* NB. The value returned by the -name method will be a lowercase version
|
||||
* of thae name.
|
||||
*/
|
||||
- (void) setName: (NSString*)s
|
||||
{
|
||||
s = [GSMimeHeader makeToken: s];
|
||||
s = [GSMimeHeader makeToken: s preservingCase: YES];
|
||||
if ([s length] == 0)
|
||||
{
|
||||
s = @"unknown";
|
||||
|
@ -3244,6 +3359,10 @@ static NSCharacterSet *tokenSet = nil;
|
|||
}
|
||||
else
|
||||
{
|
||||
if (objects == nil)
|
||||
{
|
||||
objects = [NSMutableDictionary new];
|
||||
}
|
||||
[objects setObject: o forKey: k];
|
||||
}
|
||||
}
|
||||
|
@ -3256,13 +3375,17 @@ static NSCharacterSet *tokenSet = nil;
|
|||
*/
|
||||
- (void) setParameter: (NSString*)v forKey: (NSString*)k
|
||||
{
|
||||
k = [GSMimeHeader makeToken: k];
|
||||
k = [GSMimeHeader makeToken: k preservingCase: YES];
|
||||
if (v == nil)
|
||||
{
|
||||
[params removeObjectForKey: k];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (params == nil)
|
||||
{
|
||||
params = [_GSMutableInsensitiveDictionary new];
|
||||
}
|
||||
[params setObject: v forKey: k];
|
||||
}
|
||||
}
|
||||
|
@ -3273,13 +3396,20 @@ static NSCharacterSet *tokenSet = nil;
|
|||
*/
|
||||
- (void) setParameters: (NSDictionary*)d
|
||||
{
|
||||
NSMutableDictionary *m = [NSMutableDictionary new];
|
||||
NSEnumerator *e = [d keyEnumerator];
|
||||
NSString *k;
|
||||
NSMutableDictionary *m = nil;
|
||||
unsigned c = [d count];
|
||||
|
||||
while ((k = [e nextObject]) != nil)
|
||||
if (c > 0)
|
||||
{
|
||||
[m setObject: [d objectForKey: k] forKey: [GSMimeHeader makeToken: k]];
|
||||
NSEnumerator *e = [d keyEnumerator];
|
||||
NSString *k;
|
||||
|
||||
m = [[_GSMutableInsensitiveDictionary alloc] initWithCapacity: c];
|
||||
while ((k = [e nextObject]) != nil)
|
||||
{
|
||||
[m setObject: [d objectForKey: k]
|
||||
forKey: [GSMimeHeader makeToken: k preservingCase: YES]];
|
||||
}
|
||||
}
|
||||
DESTROY(params);
|
||||
params = m;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue