Tidyup lock code.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@14631 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
CaS 2002-10-02 12:23:36 +00:00
parent c2504d8e73
commit 43385f8be9
3 changed files with 240 additions and 168 deletions

View file

@ -50,6 +50,9 @@
BOOL atEnd; /* Flag to say that data has ended. */ BOOL atEnd; /* Flag to say that data has ended. */
} }
- (BOOL) atEnd; - (BOOL) atEnd;
- (BOOL) decodeData: (const void*)sData
length: (unsigned)length
intoData: (NSMutableData*)dData;
- (void) setAtEnd: (BOOL)flag; - (void) setAtEnd: (BOOL)flag;
@end @end
@ -62,6 +65,8 @@
} }
+ (NSString*) makeQuoted: (NSString*)v; + (NSString*) makeQuoted: (NSString*)v;
+ (NSString*) makeToken: (NSString*)t; + (NSString*) makeToken: (NSString*)t;
- (id) initWithName: (NSString*)n
value: (NSString*)v;
- (id) initWithName: (NSString*)n - (id) initWithName: (NSString*)n
value: (NSString*)v value: (NSString*)v
parameters: (NSDictionary*)p; parameters: (NSDictionary*)p;
@ -116,6 +121,8 @@
- (NSMutableData*) rawMimeData; - (NSMutableData*) rawMimeData;
- (NSMutableData*) rawMimeData: (BOOL)isOuter; - (NSMutableData*) rawMimeData: (BOOL)isOuter;
- (void) setContent: (id)newContent; - (void) setContent: (id)newContent;
- (void) setContent: (id)newContent
type: (NSString*)type;
- (void) setContent: (id)newContent - (void) setContent: (id)newContent
type: (NSString*)type type: (NSString*)type
name: (NSString*)name; name: (NSString*)name;

View file

@ -327,8 +327,10 @@ wordData(NSString *word)
} }
/** /**
* Coding contexts are objects used by the parser to store the state of
* decoding incoming data while it is being incrementally parsed.<br />
* The most rudimentary context ... this is used for decoding plain * The most rudimentary context ... this is used for decoding plain
* text and binary dat (ie data which is not really decoded at all) * text and binary data (ie data which is not really decoded at all)
* and all other decoding work is done by a subclass. * and all other decoding work is done by a subclass.
*/ */
@implementation GSMimeCodingContext @implementation GSMimeCodingContext
@ -348,6 +350,21 @@ wordData(NSString *word)
return RETAIN(self); return RETAIN(self);
} }
/**
* Decode length bytes of data from sData and append the results to dData.<br />
* Return YES on succes, NO if there is an error.
*/
- (BOOL) decodeData: (const void*)sData
length: (unsigned)length
intoData: (NSMutableData*)dData
{
unsigned size = [dData length];
[dData setLength: size + length];
memcpy([dData mutableBytes] + size, sData, length);
return YES;
}
/** /**
* Sets the current value of the 'atEnd' flag. * Sets the current value of the 'atEnd' flag.
*/ */
@ -365,6 +382,96 @@ wordData(NSString *word)
} }
@end @end
@implementation GSMimeBase64DecoderContext @implementation GSMimeBase64DecoderContext
- (BOOL) decodeData: (const void*)sData
length: (unsigned)length
intoData: (NSMutableData*)dData
{
unsigned size = [dData length];
unsigned char *src = (unsigned char*)sData;
unsigned char *end = src + length;
unsigned char *beg;
unsigned char *dst;
/*
* Expand destination data buffer to have capacity to handle info.
*/
[dData setLength: size + (3 * (end + 8 - src))/4];
dst = (unsigned char*)[dData mutableBytes];
beg = dst;
/*
* Now decode data into buffer, keeping count and temporary
* data in context.
*/
while (src < end)
{
int cc = *src++;
if (isupper(cc))
{
cc -= 'A';
}
else if (islower(cc))
{
cc = cc - 'a' + 26;
}
else if (isdigit(cc))
{
cc = cc - '0' + 52;
}
else if (cc == '+')
{
cc = 62;
}
else if (cc == '/')
{
cc = 63;
}
else if (cc == '=')
{
[self setAtEnd: YES];
cc = -1;
}
else if (cc == '-')
{
[self setAtEnd: YES];
break;
}
else
{
cc = -1; /* ignore */
}
if (cc >= 0)
{
buf[pos++] = cc;
if (pos == 4)
{
pos = 0;
decodebase64(dst, buf);
dst += 3;
}
}
}
/*
* Odd characters at end of decoded data need to be added separately.
*/
if ([self atEnd] == YES && pos > 0)
{
unsigned len = pos - 1;;
while (pos < 4)
{
buf[pos++] = '\0';
}
pos = 0;
decodebase64(dst, buf);
size += len;
}
[dData setLength: size + dst - beg];
return YES;
}
@end @end
@interface GSMimeQuotedDecoderContext : GSMimeCodingContext @interface GSMimeQuotedDecoderContext : GSMimeCodingContext
@ -375,6 +482,62 @@ wordData(NSString *word)
} }
@end @end
@implementation GSMimeQuotedDecoderContext @implementation GSMimeQuotedDecoderContext
- (BOOL) decodeData: (const void*)sData
length: (unsigned)length
intoData: (NSMutableData*)dData
{
unsigned size = [dData length];
unsigned char *src = (unsigned char*)sData;
unsigned char *end = src + length;
unsigned char *beg;
unsigned char *dst;
/*
* Expand destination data buffer to have capacity to handle info.
*/
[dData setLength: size + (end - src)];
dst = (unsigned char*)[dData mutableBytes];
beg = dst;
while (src < end)
{
if (pos > 0)
{
if ((*src == '\n') || (*src == '\r'))
{
pos = 0;
}
else
{
buf[pos++] = *src;
if (pos == 3)
{
int c;
int val;
pos = 0;
c = buf[1];
val = isdigit(c) ? (c - '0') : (c - 55);
val *= 0x10;
c = buf[2];
val += isdigit(c) ? (c - '0') : (c - 55);
*dst++ = val;
}
}
}
else if (*src == '=')
{
buf[pos++] = '=';
}
else
{
*dst++ = *src;
}
src++;
}
[dData setLength: size + dst - beg];
return YES;
}
@end @end
@interface GSMimeChunkedDecoderContext : GSMimeCodingContext @interface GSMimeChunkedDecoderContext : GSMimeCodingContext
@ -429,14 +592,14 @@ wordData(NSString *word)
* </p> * </p>
* <p> * <p>
* You supply the document to be parsed as one or more data * You supply the document to be parsed as one or more data
* items passed to the <code>Parse:</code> method, and (if * items passed to the -parse: method, and (if
* the method always returns <code>YES</code>, you give it * the method always returns YES, you give it
* a final <code>nil</code> argument to mark the end of the * a final nil argument to mark the end of the
* document. * document.
* </p> * </p>
* <p> * <p>
* On completion of parsing a valid document, the * On completion of parsing a valid document, the
* <code>document</code> method returns the resulting parsed document. * -document method returns the resulting parsed document.
* </p> * </p>
*/ */
@implementation GSMimeParser @implementation GSMimeParser
@ -487,6 +650,9 @@ wordData(NSString *word)
* <item>8bit (no coding actually performed)</item> * <item>8bit (no coding actually performed)</item>
* <item>chunked (for HTTP/1.1)</item> * <item>chunked (for HTTP/1.1)</item>
* </list> * </list>
* To add new coding schemes to the parser, you need to ovrride
* this method to return a new coding context for your scheme
* when the info argument indicates that this is appropriate.
*/ */
- (GSMimeCodingContext*) contextFor: (GSMimeHeader*)info - (GSMimeCodingContext*) contextFor: (GSMimeHeader*)info
{ {
@ -575,8 +741,10 @@ wordData(NSString *word)
* object. * object.
* </p> * </p>
* <p> * <p>
* You may override this method in order to implement * You may override this method in order to implement additional
* additional coding schemes. * coding schemes, but usually it should be enough for you to
* implement a custom GSMimeCodingContext subclass fotr this method
* to use.
* </p> * </p>
*/ */
- (BOOL) decodeData: (NSData*)sData - (BOOL) decodeData: (NSData*)sData
@ -584,13 +752,8 @@ wordData(NSString *word)
intoData: (NSMutableData*)dData intoData: (NSMutableData*)dData
withContext: (GSMimeCodingContext*)con withContext: (GSMimeCodingContext*)con
{ {
unsigned size = [dData length];
unsigned len = [sData length]; unsigned len = [sData length];
unsigned char *beg; BOOL result = YES;
unsigned char *dst;
const char *src;
const char *end;
Class ccls;
if (dData == nil || [con isKindOfClass: [GSMimeCodingContext class]] == NO) if (dData == nil || [con isKindOfClass: [GSMimeCodingContext class]] == NO)
{ {
@ -601,156 +764,29 @@ wordData(NSString *word)
GS_RANGE_CHECK(aRange, len); GS_RANGE_CHECK(aRange, len);
/* /*
* Get pointers into source data buffer. * Chunked decoding is relatively complex ... it makes sense to do it
* here, in order to make use of parser facilities, rather than having
* the decoding context do the work. In this case the context is used
* solely to store state information.
*/ */
src = (const char *)[sData bytes]; if ([con class] == [GSMimeChunkedDecoderContext class])
src += aRange.location;
end = src + aRange.length;
ccls = [con class];
if (ccls == [GSMimeBase64DecoderContext class])
{
GSMimeBase64DecoderContext *ctxt;
ctxt = (GSMimeBase64DecoderContext*)con;
/*
* Expand destination data buffer to have capacity to handle info.
*/
[dData setLength: size + (3 * (end + 8 - src))/4];
dst = (unsigned char*)[dData mutableBytes];
beg = dst;
/*
* Now decode data into buffer, keeping count and temporary
* data in context.
*/
while (src < end)
{
int cc = *src++;
if (isupper(cc))
{
cc -= 'A';
}
else if (islower(cc))
{
cc = cc - 'a' + 26;
}
else if (isdigit(cc))
{
cc = cc - '0' + 52;
}
else if (cc == '+')
{
cc = 62;
}
else if (cc == '/')
{
cc = 63;
}
else if (cc == '=')
{
[ctxt setAtEnd: YES];
cc = -1;
}
else if (cc == '-')
{
[ctxt setAtEnd: YES];
break;
}
else
{
cc = -1; /* ignore */
}
if (cc >= 0)
{
ctxt->buf[ctxt->pos++] = cc;
if (ctxt->pos == 4)
{
ctxt->pos = 0;
decodebase64(dst, ctxt->buf);
dst += 3;
}
}
}
/*
* Odd characters at end of decoded data need to be added separately.
*/
if ([ctxt atEnd] == YES && ctxt->pos > 0)
{
unsigned len = ctxt->pos - 1;;
while (ctxt->pos < 4)
{
ctxt->buf[ctxt->pos++] = '\0';
}
ctxt->pos = 0;
decodebase64(dst, ctxt->buf);
size += len;
}
[dData setLength: size + dst - beg];
}
else if (ccls == [GSMimeQuotedDecoderContext class])
{
GSMimeQuotedDecoderContext *ctxt;
ctxt = (GSMimeQuotedDecoderContext*)con;
/*
* Expand destination data buffer to have capacity to handle info.
*/
[dData setLength: size + (end - src)];
dst = (unsigned char*)[dData mutableBytes];
beg = dst;
while (src < end)
{
if (ctxt->pos > 0)
{
if ((*src == '\n') || (*src == '\r'))
{
ctxt->pos = 0;
}
else
{
ctxt->buf[ctxt->pos++] = *src;
if (ctxt->pos == 3)
{
int c;
int val;
ctxt->pos = 0;
c = ctxt->buf[1];
val = isdigit(c) ? (c - '0') : (c - 55);
val *= 0x10;
c = ctxt->buf[2];
val += isdigit(c) ? (c - '0') : (c - 55);
*dst++ = val;
}
}
}
else if (*src == '=')
{
ctxt->buf[ctxt->pos++] = '=';
}
else
{
*dst++ = *src;
}
src++;
}
[dData setLength: size + dst - beg];
}
else if (ccls == [GSMimeChunkedDecoderContext class])
{ {
GSMimeChunkedDecoderContext *ctxt; GSMimeChunkedDecoderContext *ctxt;
const char *footers = src; unsigned size = [dData length];
unsigned char *beg;
unsigned char *dst;
const char *src;
const char *end;
const char *footers = src;
ctxt = (GSMimeChunkedDecoderContext*)con; ctxt = (GSMimeChunkedDecoderContext*)con;
/*
* Get pointers into source data buffer.
*/
src = (const char *)[sData bytes];
src += aRange.location;
end = src + aRange.length;
beg = 0; beg = 0;
/* /*
* Make sure buffer is big enough, and set up output pointers. * Make sure buffer is big enough, and set up output pointers.
@ -949,12 +985,9 @@ wordData(NSString *word)
} }
else else
{ {
/* result = [con decodeData: [sData bytes] + aRange.location
* Assume binary (no) decoding required. length: aRange.length
*/ intoData: dData];
[dData setLength: size + (end - src)];
dst = (unsigned char*)[dData mutableBytes];
memcpy(&dst[size], src, (end - src));
} }
/* /*
@ -965,7 +998,7 @@ wordData(NSString *word)
[con setAtEnd: YES]; [con setAtEnd: YES];
} }
return YES; return result;
} }
- (NSString*) description - (NSString*) description
@ -2552,6 +2585,16 @@ static NSCharacterSet *tokenSet = nil;
return [self initWithName: @"unknown" value: @"none" parameters: nil]; return [self initWithName: @"unknown" value: @"none" parameters: nil];
} }
/**
* Convenience method calling -initWithName:value:parameters: with the
* supplied argument and nil parameters.
*/
- (id) initWithName: (NSString*)n
value: (NSString*)v
{
return [self initWithName: n value: v parameters: nil];
}
/** /**
* <init /> * <init />
* Initialise a GSMimeHeader supplying a name, a value and a dictionary * Initialise a GSMimeHeader supplying a name, a value and a dictionary
@ -2585,6 +2628,9 @@ static NSCharacterSet *tokenSet = nil;
return [objects objectForKey: k]; return [objects objectForKey: k];
} }
/**
* Returns a dictionary of all the additional objects for the header.
*/
- (NSDictionary*) objects - (NSDictionary*) objects
{ {
return AUTORELEASE([objects copy]); return AUTORELEASE([objects copy]);
@ -2607,7 +2653,7 @@ static NSCharacterSet *tokenSet = nil;
/** /**
* Returns the parameters of this header ... a dictionary whose keys * Returns the parameters of this header ... a dictionary whose keys
* are all lowercase strings, and whosre value is a string which may * are all lowercase strings, and whose values are strings which may
* contain mixed case. * contain mixed case.
*/ */
- (NSDictionary*) parameters - (NSDictionary*) parameters
@ -2723,7 +2769,7 @@ static NSCharacterSet *tokenSet = nil;
/** /**
* Method to store specific information for particular types of * Method to store specific information for particular types of
* header. * header. This is used for non-standard parts of headers.
*/ */
- (void) setObject: (id)o forKey: (NSString*)k - (void) setObject: (id)o forKey: (NSString*)k
{ {
@ -3858,6 +3904,18 @@ static NSCharacterSet *tokenSet = nil;
} }
} }
/**
* Convenience method calling -setContent:type:name: to set document
* content and type without specifying a name ... useful for top-level
* documents rather than parts within a daocument (parts should really
* be named).
*/
- (void) setContent: (id)newContent
type: (NSString*)type
{
[self setContent: newContent type: type name: nil];
}
/** /**
* Convenience method calling -setContent:type:subType:name: to set * Convenience method calling -setContent:type:subType:name: to set
* content and type. If the type argument contains a slash '/') * content and type. If the type argument contains a slash '/')

View file

@ -46,6 +46,10 @@ static NSFileManager *mgr = nil;
} }
} }
/**
* Return a distributed lock for aPath.
* See -initWithPath: for details.
*/
+ (NSDistributedLock*) lockWithPath: (NSString*)aPath + (NSDistributedLock*) lockWithPath: (NSString*)aPath
{ {
return AUTORELEASE([[self alloc] initWithPath: aPath]); return AUTORELEASE([[self alloc] initWithPath: aPath]);
@ -67,7 +71,7 @@ static NSFileManager *mgr = nil;
if ([mgr removeFileAtPath: _lockPath handler: nil] == NO) if ([mgr removeFileAtPath: _lockPath handler: nil] == NO)
{ {
NSString *err = GSLastErrorStr(errno); const char *err = GSLastErrorStr(errno);
attributes = [mgr fileAttributesAtPath: _lockPath traverseLink: YES]; attributes = [mgr fileAttributesAtPath: _lockPath traverseLink: YES];
if ([modDate isEqual: [attributes fileModificationDate]] == YES) if ([modDate isEqual: [attributes fileModificationDate]] == YES)
@ -90,7 +94,10 @@ static NSFileManager *mgr = nil;
/** /**
* Initialises the reciever with the specified filesystem path.<br /> * Initialises the reciever with the specified filesystem path.<br />
* The location in the filesystem must be accessible for this * The location in the filesystem must be accessible for this
* to be usable. * to be usable. That is, the processes using the lock must be able
* to access, create, and destroy files at the path.<br />
* The directory in which the last path component resides must already
* exist ... create it using NSFileManager if you need to.
*/ */
- (NSDistributedLock*) initWithPath: (NSString*)aPath - (NSDistributedLock*) initWithPath: (NSString*)aPath
{ {