/* This file is part of the HandBrake source code.
Homepage: .
It may be used under the terms of the GNU General Public License. */
#import "HBRedirect.h"
@interface HBOutputRedirectListenerEntry : NSObject
{
@public
id listener;
dispatch_queue_t queue;
}
- (instancetype)initWithListener:(id)listener queue:(dispatch_queue_t)queue;
@end
@implementation HBOutputRedirectListenerEntry
- (instancetype)initWithListener:(id)entryListener queue:(dispatch_queue_t)entryQueue
{
self = [super init];
if (self)
{
self->listener = entryListener;
self->queue = entryQueue;
}
return self;
}
@end
@interface HBRedirect ()
/// Set that contains all registered listeners for this output.
@property (nonatomic, readonly) NSMutableSet *listenerEntries;
/// Selector that is called on listeners to forward the output.
@property (nonatomic, readonly) HBRedirectType type;
@end
@implementation HBRedirect
/**
* Returns HBOutputRedirect object used to redirect stdout.
*/
+ (instancetype)stdoutRedirect
{
return [[HBRedirect alloc] initWithType:HBRedirectTypeOutput];
}
/**
* Returns HBOutputRedirect object used to redirect stderr.
*/
+ (instancetype)stderrRedirect
{
return [[HBRedirect alloc] initWithType:HBRedirectTypeError];
}
- (HBOutputRedirectListenerEntry *)entryForListener:(id )listener
{
for (HBOutputRedirectListenerEntry *entry in _listenerEntries)
{
if (entry->listener == listener)
{
return entry;
}
}
return nil;
}
- (BOOL)containsListener:(id )listener
{
HBOutputRedirectListenerEntry *entry = [self entryForListener:listener];
return entry && [_listenerEntries containsObject:listener];
}
/**
* Adds specified object as listener for this output. Method @c stdoutRedirect:
* or @c stderrRedirect: of the listener is called to redirect the output.
*/
- (void)addListener:(id )listener queue:(dispatch_queue_t)queue
{
NSAssert2([listener respondsToSelector:@selector(redirect:type:)], @"Object %@ doesn't respond to selector \"%@\"", listener, NSStringFromSelector(@selector(redirect:type:)));
if (![self containsListener:listener])
{
HBOutputRedirectListenerEntry *entry = [[HBOutputRedirectListenerEntry alloc] initWithListener:listener queue:queue];
[_listenerEntries addObject:entry];
}
if (_listenerEntries.count > 0)
{
[self startRedirect];
}
}
/**
* Stops forwarding for this output to the specified listener object.
*/
- (void)removeListener:(id )listener
{
HBOutputRedirectListenerEntry *entry = [self entryForListener:listener];
if (entry)
{
[_listenerEntries removeObject:entry];
}
// If last listener is removed, stop redirecting output and autorelease
// self. Remember to set proper global pointer to NULL so the object is
// recreated again when needed.
if (_listenerEntries.count == 0)
{
[self stopRedirect];
}
}
- (instancetype)initWithType:(HBRedirectType)type
{
if (self = [super init])
{
_listenerEntries = [[NSMutableSet alloc] init];
_type = type;
}
return self;
}
- (void)startRedirect {}
- (void)stopRedirect {}
/**
* Called from @c stdoutwrite() and @c stderrwrite() to forward the output to
* listeners.
*/
- (void)forwardOutput:(NSString *)string
{
for (HBOutputRedirectListenerEntry *entry in _listenerEntries)
{
dispatch_async(entry->queue, ^{
[entry->listener redirect:string type:self->_type];
});
}
}
@end