]> err.no Git - sope/blob - sope-core/NGStreams/NGStream.m
renamed packages as discussed in the developer list
[sope] / sope-core / NGStreams / NGStream.m
1 /*
2   Copyright (C) 2000-2004 SKYRIX Software AG
3
4   This file is part of OpenGroupware.org.
5
6   OGo is free software; you can redistribute it and/or modify it under
7   the terms of the GNU Lesser General Public License as published by the
8   Free Software Foundation; either version 2, or (at your option) any
9   later version.
10
11   OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14   License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with OGo; see the file COPYING.  If not, write to the
18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.
20 */
21 // $Id$
22
23 #include "common.h"
24 #include "NGStreamExceptions.h"
25 #include "NGStream.h"
26 #include "NGFilterStream.h"
27
28 @implementation NGStream
29
30 /* primitives */
31
32 - (void)setLastException:(NSException *)_exception {
33   [_exception raise];
34 }
35 - (NSException *)lastException {
36   return nil;
37 }
38
39 - (unsigned)readBytes:(void *)_buf count:(unsigned)_len {
40   [self subclassResponsibility:_cmd];
41   return 0;
42 }
43 - (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len {
44   [self subclassResponsibility:_cmd];
45   return 0;
46 }
47
48 - (BOOL)flush {
49   return YES;
50 }
51 - (BOOL)close {
52   return YES;
53 }
54
55 - (NGStreamMode)mode {
56   [self subclassResponsibility:_cmd];
57   return 0;
58 }
59 - (BOOL)isRootStream {
60   [self subclassResponsibility:_cmd];
61   return NO;
62 }
63
64 // methods method which write exactly _len bytes
65
66 - (BOOL)safeReadBytes:(void *)_buf count:(unsigned)_len {
67   return NGSafeReadBytesFromStream(self, _buf, _len);
68 }
69
70 - (BOOL)safeWriteBytes:(const void *)_buf count:(unsigned)_len {
71   return NGSafeWriteBytesToStream(self, _buf, _len);
72 }
73
74 /* marking */
75
76 - (BOOL)mark {
77   NSLog(@"WARNING: called mark on a stream which doesn't support marking !");
78   return NO;
79 }
80 - (BOOL)rewind {
81   [NGStreamException raiseWithStream:self reason:@"marking not supported"];
82   return NO;
83 }
84 - (BOOL)markSupported {
85   return NO;
86 }
87
88 /* convenience methods */
89
90 - (int)readByte {
91   return NGReadByteFromStream(self);
92 }
93
94 /* description */
95
96 - (NSString *)modeDescription {
97   NSString *result = @"unknown";
98   
99   switch ([self mode]) {
100     case NGStreamMode_undefined: result = @"undefined"; break;
101     case NGStreamMode_readOnly:  result = @"r";         break;
102     case NGStreamMode_writeOnly: result = @"w";         break;
103     case NGStreamMode_readWrite: result = @"rw";        break;
104     default:
105       [NGUnknownStreamModeException raiseWithStream:self];
106       break;
107   }
108   return result;
109 }
110
111 - (NSString *)description {
112   return [NSString stringWithFormat:
113                      @"<%@[0x%08X] mode=%@>",
114                      NSStringFromClass([self class]), (unsigned)self,
115                      [self modeDescription]];
116 }
117
118 @end /* NGStream */
119
120 @implementation NGStream(DataMethods)
121
122 - (NSData *)readDataOfLength:(unsigned int)_length {
123   unsigned readCount;
124   char buf[_length];
125   
126   if (_length == 0) return [NSData data];
127   
128   readCount = [self readBytes:buf count:_length];
129   if (readCount == NGStreamError)
130     return nil;
131   
132   return [NSData dataWithBytes:buf length:readCount];
133 }
134
135 - (NSData *)safeReadDataOfLength:(unsigned int)_length {
136   char buf[_length];
137   
138   if (_length == 0) return [NSData data];
139   if (![self safeReadBytes:buf count:_length])
140     return nil;
141   return [NSData dataWithBytes:buf length:_length];
142 }
143
144 - (unsigned int)writeData:(NSData *)_data {
145   return [self writeBytes:[_data bytes] count:[_data length]];
146 }
147 - (BOOL)safeWriteData:(NSData *)_data {
148   return [self safeWriteBytes:[_data bytes] count:[_data length]];
149 }
150
151 @end /* NGStream(DataMethods) */
152
153 // concrete implementations as functions
154
155 int NGReadByteFromStream(id<NGInputStream> _stream) {
156   volatile int  result = -1;
157   unsigned char c;
158
159   NS_DURING {
160     int l;
161     l = [_stream readBytes:&c count:sizeof(unsigned char)];
162     if (l == NGStreamError) {
163       NSException *e = [(id)_stream lastException];
164       if ([e isKindOfClass:[NGEndOfStreamException class]])
165         *(&result) = -1;
166       else
167         [e raise];
168     }
169     else
170       *(&result) = c;
171   }
172   NS_HANDLER {
173     if ([localException isKindOfClass:[NGEndOfStreamException class]])
174       *(&result) = -1;
175     else
176       [localException raise];
177   }
178   NS_ENDHANDLER;
179   
180   return result;
181 }
182
183 BOOL NGSafeReadBytesFromStream(id<NGInputStream> _in, void *_buf, unsigned _len){
184   volatile int toBeRead;
185   volatile int readResult;
186   volatile NGIOReadMethodType readBytes;
187
188   *(&toBeRead) = _len;
189   readBytes = (NGIOReadMethodType)
190     [(NSObject *)_in methodForSelector:@selector(readBytes:count:)];
191
192   NS_DURING {
193     void *pos = _buf;
194     
195     while (YES) {
196       *(&readResult) = (unsigned)readBytes(_in, @selector(readBytes:count:),
197                                            pos, toBeRead);
198
199       if (readResult == NGStreamError) {
200         /* TODO: improve exception handling ... */
201         [[(id)_in lastException] raise];
202       }
203       else if (readResult == toBeRead) {
204         // all bytes were read successfully, return
205         break;
206       }
207       
208       if (readResult < 1) {
209         [NSException raise:NSInternalInconsistencyException
210                      format:@"readBytes:count: returned a value < 1"];
211       }
212
213       toBeRead -= readResult;
214       pos += readResult;
215     }
216   }
217   NS_HANDLER {
218     if ([localException isKindOfClass:[NGEndOfStreamException class]]) {
219       [[[NGEndOfStreamException alloc]
220                                 initWithStream:(id)_in
221                                 readCount:(_len - toBeRead)
222                                 safeCount:_len
223                                 data:[NSData dataWithBytes:_buf
224                                              length:(_len - toBeRead)]]
225                                 raise];
226     }
227     else {
228       [localException raise];
229     }
230   }
231   NS_ENDHANDLER;
232   return YES;
233 }
234
235 BOOL NGSafeWriteBytesToStream(id<NGOutputStream> _o,const void *_b,unsigned _l) {
236   int  toBeWritten = _l;
237   int  writeResult;
238   void *pos = (void *)_b;
239   NGIOWriteMethodType writeBytes;
240   
241   writeBytes = (NGIOWriteMethodType)
242     [(NSObject *)_o methodForSelector:@selector(writeBytes:count:)];
243   
244   while (YES) {
245     writeResult =
246       (int)writeBytes(_o, @selector(writeBytes:count:), pos, toBeWritten);
247     
248     if (writeResult == NGStreamError) {
249       /* remember number of written bytes ??? */
250       return NO;
251     }
252     else if (writeResult == toBeWritten) {
253       // all bytes were written successfully, return
254       break;
255     }
256     
257     if (writeResult < 1) {
258       [NSException raise:NSInternalInconsistencyException
259                    format:@"writeBytes:count: returned a value<1 in %@", _o];
260     }
261
262     toBeWritten -= writeResult;
263     pos += writeResult;
264   }
265   return YES;
266 }