mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-29 16:01:38 +00:00
mingw stream improvements
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@23254 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
068ca34b74
commit
d0852086a5
6 changed files with 665 additions and 253 deletions
|
@ -31,6 +31,7 @@
|
|||
#include <Foundation/NSError.h>
|
||||
#include <Foundation/NSValue.h>
|
||||
#include <Foundation/NSHost.h>
|
||||
#include <Foundation/NSDebug.h>
|
||||
|
||||
#include "GSStream.h"
|
||||
|
||||
|
@ -132,9 +133,14 @@ static RunLoopEventType typeForStream(NSStream *aStream)
|
|||
|
||||
- (void) close
|
||||
{
|
||||
NSAssert(_currentStatus != NSStreamStatusNotOpen
|
||||
&& _currentStatus != NSStreamStatusClosed,
|
||||
@"Attempt to close a stream not yet opened.");
|
||||
if (_currentStatus == NSStreamStatusNotOpen)
|
||||
{
|
||||
NSDebugMLog(@"Attempt to close unopened stream %@", self);
|
||||
}
|
||||
if (_currentStatus == NSStreamStatusClosed)
|
||||
{
|
||||
NSDebugMLog(@"Attempt to close already closed stream %@", self);
|
||||
}
|
||||
if (_runloop)
|
||||
{
|
||||
unsigned i = [_modes count];
|
||||
|
@ -186,9 +192,10 @@ static RunLoopEventType typeForStream(NSStream *aStream)
|
|||
|
||||
- (void) open
|
||||
{
|
||||
NSAssert(_currentStatus == NSStreamStatusNotOpen
|
||||
|| _currentStatus == NSStreamStatusOpening,
|
||||
@"Attempt to open a stream already opened.");
|
||||
if (_currentStatus != NSStreamStatusNotOpen)
|
||||
{
|
||||
NSDebugMLog(@"Attempt to re-open stream %@", self);
|
||||
}
|
||||
[self _setStatus: NSStreamStatusOpen];
|
||||
if (_runloop)
|
||||
{
|
||||
|
@ -364,9 +371,6 @@ static RunLoopEventType typeForStream(NSStream *aStream)
|
|||
|
||||
- (void) _sendEvent: (NSStreamEvent)event
|
||||
{
|
||||
NSStreamStatus last = [self streamStatus];
|
||||
NSStreamStatus current;
|
||||
|
||||
if (event == NSStreamEventNone)
|
||||
{
|
||||
return;
|
||||
|
@ -454,21 +458,6 @@ static RunLoopEventType typeForStream(NSStream *aStream)
|
|||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Unknown event (%d) passed to _sendEvent:", event];
|
||||
}
|
||||
|
||||
/* If our status changed while the handler was dealing with an
|
||||
* event, we may need to send it the new event to let it know.
|
||||
*/
|
||||
if ((current = [self streamStatus]) != last)
|
||||
{
|
||||
if (current == NSStreamStatusAtEnd)
|
||||
{
|
||||
[self _sendEvent: NSStreamEventEndEncountered];
|
||||
}
|
||||
else if (current == NSStreamStatusError)
|
||||
{
|
||||
[self _sendEvent: NSStreamEventErrorOccurred];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void) _setLoopID: (void *)ref
|
||||
|
@ -493,18 +482,35 @@ static RunLoopEventType typeForStream(NSStream *aStream)
|
|||
|
||||
- (BOOL) runLoopShouldBlock: (BOOL*)trigger
|
||||
{
|
||||
if ([self _unhandledData] == YES
|
||||
|| _currentStatus == NSStreamStatusError
|
||||
|| _currentStatus == NSStreamStatusAtEnd)
|
||||
if (_events
|
||||
& (NSStreamEventHasBytesAvailable | NSStreamEventHasSpaceAvailable))
|
||||
{
|
||||
/* If we have an unhandled data event, we should not watch for more
|
||||
* or trigger until the appropriate rad or write has been done.
|
||||
* If an error has occurred, we should not watch for any events at all.
|
||||
* or trigger until the appropriate read or write has been done.
|
||||
*/
|
||||
*trigger = NO;
|
||||
return NO;
|
||||
}
|
||||
else if (_loopID == (void*)self)
|
||||
if (_currentStatus == NSStreamStatusError &&
|
||||
(_events & NSStreamEventErrorOccurred) == NSStreamEventErrorOccurred)
|
||||
{
|
||||
/* If an error has occurred (and been handled),
|
||||
* we should not watch for any events at all.
|
||||
*/
|
||||
*trigger = NO;
|
||||
return NO;
|
||||
}
|
||||
if (_currentStatus == NSStreamStatusAtEnd &&
|
||||
(_events & NSStreamEventEndEncountered) == NSStreamEventEndEncountered)
|
||||
{
|
||||
/* If an error has occurred (and been handled),
|
||||
* we should not watch for any events at all.
|
||||
*/
|
||||
*trigger = NO;
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (_loopID == (void*)self)
|
||||
{
|
||||
/* If _loopID is the receiver, the stream is not receiving external
|
||||
* input, so it must trigger an event when the loop runs and must not
|
||||
|
@ -522,6 +528,7 @@ static RunLoopEventType typeForStream(NSStream *aStream)
|
|||
@end
|
||||
|
||||
@implementation GSInputStream
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
if (self == [GSInputStream class])
|
||||
|
@ -529,9 +536,31 @@ static RunLoopEventType typeForStream(NSStream *aStream)
|
|||
GSObjCAddClassBehavior(self, [GSStream class]);
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL) hasBytesAvailable
|
||||
{
|
||||
if (_currentStatus == NSStreamStatusOpen)
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
if (_currentStatus == NSStreamStatusAtEnd)
|
||||
{
|
||||
if ((_events & NSStreamEventEndEncountered) == 0)
|
||||
{
|
||||
/* We have not sent the appropriate event yet, so the
|
||||
* client must not have issued a read:maxLength:
|
||||
* (which is the point at which we should send).
|
||||
*/
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation GSOutputStream
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
if (self == [GSOutputStream class])
|
||||
|
@ -539,6 +568,27 @@ static RunLoopEventType typeForStream(NSStream *aStream)
|
|||
GSObjCAddClassBehavior(self, [GSStream class]);
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL) hasSpaceAvailable
|
||||
{
|
||||
if (_currentStatus == NSStreamStatusOpen)
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
if (_currentStatus == NSStreamStatusAtEnd)
|
||||
{
|
||||
if ((_events & NSStreamEventEndEncountered) == 0)
|
||||
{
|
||||
/* We have not sent the appropriate event yet, so the
|
||||
* client must not have issued a write:maxLength:
|
||||
* (which is the point at which we should send).
|
||||
*/
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
@implementation GSAbstractServerStream
|
||||
+ (void) initialize
|
||||
|
@ -551,7 +601,7 @@ static RunLoopEventType typeForStream(NSStream *aStream)
|
|||
@end
|
||||
|
||||
|
||||
@implementation GSMemoryInputStream
|
||||
@implementation GSDataInputStream
|
||||
|
||||
/**
|
||||
* the designated initializer
|
||||
|
@ -576,10 +626,28 @@ static RunLoopEventType typeForStream(NSStream *aStream)
|
|||
|
||||
- (int) read: (uint8_t *)buffer maxLength: (unsigned int)len
|
||||
{
|
||||
unsigned long dataSize = [_data length];
|
||||
unsigned long dataSize;
|
||||
unsigned long copySize;
|
||||
|
||||
if (buffer == 0)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"null pointer for buffer"];
|
||||
}
|
||||
if (len == 0)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"zero byte read write requested"];
|
||||
}
|
||||
|
||||
_events &= ~NSStreamEventHasSpaceAvailable;
|
||||
|
||||
if ([self streamStatus] == NSStreamStatusClosed)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
dataSize = [_data length];
|
||||
NSAssert(dataSize >= _pointer, @"Buffer overflow!");
|
||||
if (len + _pointer > dataSize)
|
||||
{
|
||||
|
@ -597,6 +665,7 @@ static RunLoopEventType typeForStream(NSStream *aStream)
|
|||
else
|
||||
{
|
||||
[self _setStatus: NSStreamStatusAtEnd];
|
||||
[self _sendEvent: NSStreamEventEndEncountered];
|
||||
}
|
||||
return copySize;
|
||||
}
|
||||
|
@ -639,71 +708,132 @@ static RunLoopEventType typeForStream(NSStream *aStream)
|
|||
@end
|
||||
|
||||
|
||||
@implementation GSMemoryOutputStream
|
||||
@implementation GSBufferOutputStream
|
||||
|
||||
- (id) initToBuffer: (uint8_t *)buffer capacity: (unsigned int)capacity
|
||||
{
|
||||
if ((self = [super init]) != nil)
|
||||
{
|
||||
if (!buffer)
|
||||
{
|
||||
_data = [NSMutableData new];
|
||||
_fixedSize = NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
_data = [[NSMutableData alloc] initWithBytesNoCopy: buffer
|
||||
length: capacity freeWhenDone: NO];
|
||||
_fixedSize = YES;
|
||||
}
|
||||
_buffer = buffer;
|
||||
_capacity = capacity;
|
||||
_pointer = 0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
RELEASE(_data);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (int) write: (const uint8_t *)buffer maxLength: (unsigned int)len
|
||||
{
|
||||
_events &= ~NSStreamEventHasBytesAvailable;
|
||||
if (_fixedSize)
|
||||
if (buffer == 0)
|
||||
{
|
||||
unsigned long dataLen = [_data length];
|
||||
uint8_t *origin = (uint8_t *)[_data mutableBytes];
|
||||
|
||||
if (_pointer+len>dataLen)
|
||||
len = dataLen - _pointer;
|
||||
memcpy(origin+_pointer, buffer, len);
|
||||
_pointer = _pointer + len;
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"null pointer for buffer"];
|
||||
}
|
||||
if (len == 0)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"zero byte length write requested"];
|
||||
}
|
||||
else
|
||||
[_data appendBytes: buffer length: len];
|
||||
return len;
|
||||
}
|
||||
|
||||
- (BOOL) hasSpaceAvailable
|
||||
{
|
||||
if (_fixedSize)
|
||||
return [_data length]>_pointer;
|
||||
else
|
||||
return YES;
|
||||
_events &= ~NSStreamEventHasBytesAvailable;
|
||||
|
||||
if ([self streamStatus] == NSStreamStatusClosed)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((_pointer + len) > _capacity)
|
||||
{
|
||||
len = _capacity - _pointer;
|
||||
if (len == 0)
|
||||
{
|
||||
[self _setStatus: NSStreamStatusAtEnd];
|
||||
[self _sendEvent: NSStreamEventEndEncountered];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
memcpy((_buffer + _pointer), buffer, len);
|
||||
_pointer += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
- (id) propertyForKey: (NSString *)key
|
||||
{
|
||||
if ([key isEqualToString: NSStreamFileCurrentOffsetKey])
|
||||
{
|
||||
if (_fixedSize)
|
||||
return [NSNumber numberWithLong: _pointer];
|
||||
else
|
||||
return [NSNumber numberWithLong:[_data length]];
|
||||
return [NSNumber numberWithLong: _pointer];
|
||||
}
|
||||
return [super propertyForKey: key];
|
||||
}
|
||||
|
||||
- (void) _dispatch
|
||||
{
|
||||
BOOL av = [self hasSpaceAvailable];
|
||||
NSStreamEvent myEvent = av ? NSStreamEventHasSpaceAvailable :
|
||||
NSStreamEventEndEncountered;
|
||||
|
||||
[self _sendEvent: myEvent];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation GSDataOutputStream
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]) != nil)
|
||||
{
|
||||
_data = [NSMutableData new];
|
||||
_pointer = 0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
RELEASE(_data);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (int) write: (const uint8_t *)buffer maxLength: (unsigned int)len
|
||||
{
|
||||
if (buffer == 0)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"null pointer for buffer"];
|
||||
}
|
||||
if (len == 0)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"zero byte length write requested"];
|
||||
}
|
||||
|
||||
_events &= ~NSStreamEventHasBytesAvailable;
|
||||
|
||||
if ([self streamStatus] == NSStreamStatusClosed)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
[_data appendBytes: buffer length: len];
|
||||
_pointer += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
- (BOOL) hasSpaceAvailable
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (id) propertyForKey: (NSString *)key
|
||||
{
|
||||
if ([key isEqualToString: NSStreamFileCurrentOffsetKey])
|
||||
{
|
||||
return [NSNumber numberWithLong: _pointer];
|
||||
}
|
||||
else if ([key isEqualToString: NSStreamDataWrittenToMemoryStreamKey])
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
else if ([key isEqualToString: NSStreamDataWrittenToMemoryStreamKey])
|
||||
return _data;
|
||||
return [super propertyForKey: key];
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue