2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
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
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.
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
22 #include <NGStreams/NGDataStream.h>
23 #include <NGStreams/NGStreamExceptions.h>
26 // TODO: cache -bytes and -length of NSData for immutable data!
28 @implementation NGDataStream
31 return [super version] + 2;
35 return [self streamWithData:[NSMutableData dataWithCapacity:1024]];
37 + (id)dataStreamWithCapacity:(int)_capacity {
38 return [self streamWithData:[NSMutableData dataWithCapacity:_capacity]];
41 + (id)streamWithData:(NSData *)_data {
42 return [[[self alloc] initWithData:_data] autorelease];
44 - (id)initWithData:(NSData *)_data mode:(NGStreamMode)_mode {
45 if ((self = [super init])) {
46 self->data = [_data retain];
49 if ([self->data respondsToSelector:@selector(methodForSelector:)] == YES) {
50 self->dataLength = (unsigned int(*)(id, SEL))
51 [self->data methodForSelector:@selector(length)];
52 self->dataBytes = (const void*(*)(id, SEL))
53 [self->data methodForSelector:@selector(bytes)];
56 self->dataLength = NULL;
57 self->dataBytes = NULL;
60 self->streamMode = _mode;
62 /* for read-only streams */
63 if (self->streamMode == NGStreamMode_readOnly) {
64 self->bytes = [self->data bytes];
65 self->length = [self->data length];
70 - (id)initWithData:(NSData *)_data {
73 smode = [data isKindOfClass:[NSMutableData class]]
74 ? NGStreamMode_readWrite
75 : NGStreamMode_readOnly;
76 return [self initWithData:_data mode:smode];
81 [self->lastException release];
87 /* NGTextInputStream */
89 - (NSException *)lastException {
90 return self->lastException;
92 - (void)setLastException:(NSException *)_exception {
93 ASSIGN(self->lastException, _exception);
95 - (void)resetLastException {
96 [self->lastException release];
97 self->lastException = nil;
104 - (unsigned)availableBytes {
105 // returns number of available bytes
106 register unsigned currentLength = 0;
108 if (self->bytes == NULL) {
109 currentLength = (self->dataLength == NULL)
110 ? [self->data length]
111 : self->dataLength(self->data, @selector(length));
114 currentLength = self->length;
116 return (currentLength == position)
118 : (currentLength - position);
123 - (unsigned)readBytes:(void *)_buf count:(unsigned)_len {
125 // NGStreamNotOpenException when the stream is not open
126 // NGEndOfStreamException when the end of the stream is reached
127 register unsigned currentLength = 0;
129 if (self->bytes == NULL) {
130 currentLength = (self->dataLength == NULL)
131 ? [self->data length]
132 : self->dataLength(self->data, @selector(length));
135 currentLength = self->length;
137 if (self->data == nil) {
140 e = [NGStreamNotOpenException exceptionWithStream:self reason:
141 @"tried to read from a data stream "
142 @"which was closed"];
143 [self setLastException:e];
144 return NGStreamError;
147 if (currentLength == position) {
148 [self setLastException:
149 [NGEndOfStreamException exceptionWithStream:self]];
150 return NGStreamError;
154 range.location = position;
156 if ((position + _len) > currentLength)
157 range.length = currentLength - position;
161 [self->data getBytes:_buf range:range];
163 position += range.length;
169 register const unsigned char *p;
170 register unsigned int currentLength = 0;
173 if (self->bytes == NULL) {
174 currentLength = (self->dataLength == NULL)
175 ? [self->data length]
176 : self->dataLength(self->data, @selector(length));
179 currentLength = self->length;
181 if (currentLength == position)
184 if (self->bytes == NULL) {
185 p = (self->dataBytes == NULL)
187 : self->dataBytes(self->data, @selector(bytes));
191 result = p[self->position];
196 - (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len {
198 // NGReadOnlyStreamException when the stream is not writeable
199 // NGStreamNotOpenException when the stream is not open
201 if (self->data == nil) {
204 e = [NGStreamNotOpenException exceptionWithStream:self reason:
205 @"tried to write to a data stream "
206 @"which was closed"];
207 [self setLastException:e];
208 return NGStreamError;
210 if (!NGCanWriteInStreamMode(streamMode)) {
213 e = [NGReadOnlyStreamException exceptionWithStream:self];
214 [self setLastException:e];
215 return NGStreamError;
217 [(NSMutableData *)self->data appendBytes:_buf length:_len];
223 ASSIGN(self->lastException, (id)nil);
224 [self->data release]; self->data = nil;
226 streamMode = NGStreamMode_undefined;
230 - (NGStreamMode)mode {
233 - (BOOL)isRootStream {
237 // NGPositionableStream
239 - (BOOL)moveToLocation:(unsigned)_location {
240 position = _location;
243 - (BOOL)moveByOffset:(int)_delta {
250 - (BOOL)wouldBlockInMode:(NGStreamMode)_mode {
255 return [super retain];
258 /* bytebuffer / lookahead API */
260 - (int)la:(unsigned)_la {
261 register unsigned int currentLength, newpos;
262 register const unsigned char *p;
265 if (self->bytes == NULL) {
266 currentLength = (self->dataLength == NULL)
267 ? [self->data length]
268 : self->dataLength(self->data, @selector(length));
271 currentLength = self->length;
273 if (currentLength == self->position) // already at EOF
276 newpos = (self->position + _la);
277 if (newpos >= currentLength)
278 return -1; /* a look into EOF */
280 if (self->bytes == NULL) {
281 p = (self->dataBytes == NULL)
283 : self->dataBytes(self->data, @selector(bytes));
292 - (void)consume { // consume one byte
293 register unsigned int currentLength = 0;
295 if (self->bytes == NULL) {
296 currentLength = (self->dataLength == NULL)
297 ? [self->data length]
298 : self->dataLength(self->data, @selector(length));
301 currentLength = self->length;
303 if (currentLength == self->position)
306 self->position++; // consume
308 - (void)consume:(unsigned)_cnt { // consume _cnt bytes
309 register unsigned int currentLength = 0;
311 if (self->bytes == NULL) {
312 currentLength = (self->dataLength == NULL)
313 ? [self->data length]
314 : self->dataLength(self->data, @selector(length));
317 currentLength = self->length;
319 if (currentLength == self->position)
322 self->position += _cnt; // consume
324 if (self->position > currentLength)
325 self->position = currentLength;
328 @end /* NGDataStream */