OSDN Git Service

MacGui: fix character encodings in the log file as well as the title popup string...
[handbrake-jp/handbrake-jp-git.git] / macosx / HBOutputRedirect.m
1 /**
2  * @file
3  * @date 17.5.2007
4  *
5  * Implementation of class HBOutputRedirect.
6  */
7
8 #import "HBOutputRedirect.h"
9
10 /// Global pointer to HBOutputRedirect object that manages redirects for stdout.
11 static HBOutputRedirect *g_stdoutRedirect = nil;
12
13 /// Global pointer to HBOutputRedirect object that manages redirects for stderr.
14 static HBOutputRedirect *g_stderrRedirect = nil;
15
16 @interface HBOutputRedirect (Private)
17 - (id)initWithStream:(FILE *)aStream selector:(SEL)aSelector;
18 - (void)startRedirect;
19 - (void)stopRedirect;
20 - (void)forwardOutput:(NSData *)data;
21 @end
22
23 /**
24  * Function that replaces stdout->_write and forwards stdout to g_stdoutRedirect.
25  */
26 int     stdoutwrite(void *inFD, const char *buffer, int size)
27 {
28         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
29         NSData *data = [[NSData alloc] initWithBytes:buffer length:size];
30         [g_stdoutRedirect performSelectorOnMainThread:@selector(forwardOutput:) withObject:data waitUntilDone:NO];
31         [data release];
32         [pool release];
33         return size;
34 }
35
36 /**
37  * Function that replaces stderr->_write and forwards stderr to g_stderrRedirect.
38  */
39 int     stderrwrite(void *inFD, const char *buffer, int size)
40 {
41         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
42         NSData *data = [[NSData alloc] initWithBytes:buffer length:size];
43         [g_stderrRedirect performSelectorOnMainThread:@selector(forwardOutput:) withObject:data waitUntilDone:NO];
44         [data release];
45         [pool release];
46         return size;
47 }
48
49 @implementation HBOutputRedirect
50
51 /**
52  * Returns HBOutputRedirect object used to redirect stdout.
53  */
54 + (id)stdoutRedirect
55 {
56         if (!g_stdoutRedirect)
57                 g_stdoutRedirect = [[HBOutputRedirect alloc] initWithStream:stdout selector:@selector(stdoutRedirect:)];
58                 
59         return g_stdoutRedirect;
60 }
61
62 /**
63  * Returns HBOutputRedirect object used to redirect stderr.
64  */
65 + (id)stderrRedirect
66 {
67         if (!g_stderrRedirect)
68                 g_stderrRedirect = [[HBOutputRedirect alloc] initWithStream:stderr selector:@selector(stderrRedirect:)];
69                 
70         return g_stderrRedirect;
71 }
72
73 /**
74  * Adds specified object as listener for this output. Method @c stdoutRedirect:
75  * or @c stderrRedirect: of the listener is called to redirect the output.
76  */
77 - (void)addListener:(id)aListener
78 {
79         NSAssert2([aListener respondsToSelector:forwardingSelector], @"Object %@ doesn't respond to selector \"%@\"", aListener, NSStringFromSelector(forwardingSelector));
80
81         if (![listeners containsObject:aListener])
82         {
83                 [listeners addObject:aListener];
84                 [aListener release];
85         }
86         
87         if ([listeners count] > 0)
88                 [self startRedirect];
89 }
90
91 /**
92  * Stops forwarding for this output to the specified listener object.
93  */
94 - (void)removeListener:(id)aListener
95 {
96         if ([listeners containsObject:aListener])
97         {
98                 [aListener retain];
99                 [listeners removeObject:aListener];
100         }
101
102         // If last listener is removed, stop redirecting output and autorelease
103         // self. Remember to set proper global pointer to NULL so the object is
104         // recreated again when needed.
105         if ([listeners count] == 0)
106         {
107                 [self stopRedirect];
108                 [self autorelease];
109
110                 if (self == g_stdoutRedirect)
111                         g_stdoutRedirect = nil;
112                 else if (self == g_stderrRedirect)
113                         g_stderrRedirect = nil;
114         }
115 }
116
117 @end
118
119 @implementation HBOutputRedirect (Private)
120
121 /**
122  * Private constructor which should not be called from outside. This is used to
123  * initialize the class at @c stdoutRedirect and @c stderrRedirect.
124  *
125  * @param aStream       Stream that wil be redirected (stdout or stderr).
126  * @param aSelector     Selector that will be called in listeners to redirect the stream.
127  *
128  * @return New HBOutputRedirect object.
129  */
130 - (id)initWithStream:(FILE *)aStream selector:(SEL)aSelector
131 {
132         if (self = [super init])
133         {
134                 listeners = [[NSMutableSet alloc] init];
135                 forwardingSelector = aSelector;
136                 stream = aStream;
137                 oldWriteFunc = NULL;
138                 lock = [[NSLock alloc] init];
139         }
140         return self;
141 }
142
143 /**
144  * Frees all the listeners and deallocs the object.
145  */
146 - (void)dealloc
147 {
148         [listeners release];
149         [super dealloc];
150 }
151
152 /**
153  * Starts redirecting the stream by redirecting its output to function
154  * @c stdoutwrite() or @c stderrwrite(). Old _write function is stored to
155  * @c oldWriteFunc so it can be restored. 
156  */
157 - (void)startRedirect
158 {
159         if (!oldWriteFunc)
160         {
161                 oldWriteFunc = stream->_write;
162                 stream->_write = stream == stdout ? stdoutwrite : stderrwrite;
163         }
164 }
165
166 /**
167  * Stops redirecting of the stream by returning the stream's _write function
168  * to original.
169  */
170 - (void)stopRedirect
171 {
172         if (oldWriteFunc)
173         {
174                 stream->_write = oldWriteFunc;
175                 oldWriteFunc = NULL;
176         }
177 }
178
179 /**
180  * Called from @c stdoutwrite() and @c stderrwrite() to forward the output to 
181  * listeners.
182  */ 
183 - (void)forwardOutput:(NSData *)data
184 {
185         NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
186         [listeners makeObjectsPerformSelector:forwardingSelector withObject:string];
187         [string release];
188 }
189
190 @end