1/* 2 Copyright (C) 2000-2005 SKYRIX Software AG 3 4 This file is part of SOPE. 5 6 SOPE 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 SOPE 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 SOPE; 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 22#include <NGStreams/NGStreamExceptions.h> 23#include <NGStreams/NGStream.h> 24#include <NGStreams/NGFilterStream.h> 25#include "common.h" 26 27@implementation NGStream 28 29/* primitives */ 30 31- (void)setLastException:(NSException *)_exception { 32 [_exception raise]; 33} 34- (NSException *)lastException { 35 return nil; 36} 37 38- (unsigned)readBytes:(void *)_buf count:(unsigned)_len { 39 [self subclassResponsibility:_cmd]; 40 return 0; 41} 42- (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len { 43 [self subclassResponsibility:_cmd]; 44 return 0; 45} 46 47- (BOOL)flush { 48 return YES; 49} 50- (BOOL)close { 51 return YES; 52} 53 54- (NGStreamMode)mode { 55 [self subclassResponsibility:_cmd]; 56 return 0; 57} 58- (BOOL)isRootStream { 59 [self subclassResponsibility:_cmd]; 60 return NO; 61} 62 63// methods method which write exactly _len bytes 64 65- (BOOL)safeReadBytes:(void *)_buf count:(unsigned)_len { 66 return NGSafeReadBytesFromStream(self, _buf, _len); 67} 68 69- (BOOL)safeWriteBytes:(const void *)_buf count:(unsigned)_len { 70 return NGSafeWriteBytesToStream(self, _buf, _len); 71} 72 73/* marking */ 74 75- (BOOL)mark { 76 NSLog(@"WARNING: called mark on a stream which doesn't support marking !"); 77 return NO; 78} 79- (BOOL)rewind { 80 [NGStreamException raiseWithStream:self reason:@"marking not supported"]; 81 return NO; 82} 83- (BOOL)markSupported { 84 return NO; 85} 86 87/* convenience methods */ 88 89- (int)readByte { 90 return NGReadByteFromStream(self); 91} 92 93/* description */ 94 95- (NSString *)modeDescription { 96 NSString *result = @"unknown"; 97 98 switch ([self mode]) { 99 case NGStreamMode_undefined: result = @"undefined"; break; 100 case NGStreamMode_readOnly: result = @"r"; break; 101 case NGStreamMode_writeOnly: result = @"w"; break; 102 case NGStreamMode_readWrite: result = @"rw"; break; 103 default: 104 [NGUnknownStreamModeException raiseWithStream:self]; 105 break; 106 } 107 return result; 108} 109 110- (NSString *)description { 111 return [NSString stringWithFormat: 112 @"<%@[0x%p] mode=%@>", 113 NSStringFromClass([self class]), self, 114 [self modeDescription]]; 115} 116 117@end /* NGStream */ 118 119@implementation NGStream(DataMethods) 120 121- (NSData *)readDataOfLength:(unsigned int)_length { 122 unsigned readCount; 123 char buf[_length]; 124 125 if (_length == 0) return [NSData data]; 126 127 readCount = [self readBytes:buf count:_length]; 128 if (readCount == NGStreamError) 129 return nil; 130 131 return [NSData dataWithBytes:buf length:readCount]; 132} 133 134- (NSData *)safeReadDataOfLength:(unsigned int)_length { 135 char buf[_length]; 136 137 if (_length == 0) return [NSData data]; 138 if (![self safeReadBytes:buf count:_length]) 139 return nil; 140 return [NSData dataWithBytes:buf length:_length]; 141} 142 143- (unsigned int)writeData:(NSData *)_data { 144 return [self writeBytes:[_data bytes] count:[_data length]]; 145} 146- (BOOL)safeWriteData:(NSData *)_data { 147 return [self safeWriteBytes:[_data bytes] count:[_data length]]; 148} 149 150@end /* NGStream(DataMethods) */ 151 152// concrete implementations as functions 153 154int NGReadByteFromStream(id<NGInputStream> _stream) { 155 volatile int result = -1; 156 unsigned char c; 157 158 NS_DURING { 159 int l; 160 l = [_stream readBytes:&c count:sizeof(unsigned char)]; 161 if (l == NGStreamError) { 162 NSException *e = [(id)_stream lastException]; 163 if ([e isKindOfClass:[NGEndOfStreamException class]]) 164 *(&result) = -1; 165 else 166 [e raise]; 167 } 168 else 169 *(&result) = c; 170 } 171 NS_HANDLER { 172 if ([localException isKindOfClass:[NGEndOfStreamException class]]) 173 *(&result) = -1; 174 else 175 [localException raise]; 176 } 177 NS_ENDHANDLER; 178 179 return result; 180} 181 182BOOL NGSafeReadBytesFromStream(id<NGInputStream> _in, void *_buf, unsigned _len){ 183 volatile int toBeRead; 184 volatile int readResult; 185 volatile NGIOReadMethodType readBytes; 186 187 *(&toBeRead) = _len; 188 readBytes = (NGIOReadMethodType) 189 [(NSObject *)_in methodForSelector:@selector(readBytes:count:)]; 190 191 NS_DURING { 192 void *pos = _buf; 193 194 while (YES) { 195 *(&readResult) = (unsigned)readBytes(_in, @selector(readBytes:count:), 196 pos, toBeRead); 197 198 if (readResult == NGStreamError) { 199 /* TODO: improve exception handling ... */ 200 [[(id)_in lastException] raise]; 201 } 202 else if (readResult == toBeRead) { 203 // all bytes were read successfully, return 204 break; 205 } 206 207 if (readResult < 1) { 208 [NSException raise:NSInternalInconsistencyException 209 format:@"readBytes:count: returned a value < 1"]; 210 } 211 212 toBeRead -= readResult; 213 pos += readResult; 214 } 215 } 216 NS_HANDLER { 217 if ([localException isKindOfClass:[NGEndOfStreamException class]]) { 218 [[[NGEndOfStreamException alloc] 219 initWithStream:(id)_in 220 readCount:(_len - toBeRead) 221 safeCount:_len 222 data:[NSData dataWithBytes:_buf 223 length:(_len - toBeRead)]] 224 raise]; 225 } 226 else { 227 [localException raise]; 228 } 229 } 230 NS_ENDHANDLER; 231 return YES; 232} 233 234BOOL NGSafeWriteBytesToStream(id<NGOutputStream> _o,const void *_b,unsigned _l) { 235 int toBeWritten = _l; 236 int writeResult; 237 void *pos = (void *)_b; 238 NGIOWriteMethodType writeBytes; 239 240 writeBytes = (NGIOWriteMethodType) 241 [(NSObject *)_o methodForSelector:@selector(writeBytes:count:)]; 242 243 while (YES) { 244 writeResult = 245 (int)writeBytes(_o, @selector(writeBytes:count:), pos, toBeWritten); 246 247 if (writeResult == NGStreamError) { 248 /* remember number of written bytes ??? */ 249 return NO; 250 } 251 else if (writeResult == toBeWritten) { 252 // all bytes were written successfully, return 253 break; 254 } 255 256 if (writeResult < 1) { 257 [NSException raise:NSInternalInconsistencyException 258 format:@"writeBytes:count: returned a value<1 in %@", _o]; 259 } 260 261 toBeWritten -= writeResult; 262 pos += writeResult; 263 } 264 return YES; 265} 266