]> err.no Git - sope/blob - sope-core/NGStreams/NGDataStream.m
Drop apache 1 build-dependency
[sope] / sope-core / NGStreams / NGDataStream.m
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/NGDataStream.h>
23 #include <NGStreams/NGStreamExceptions.h>
24 #include "common.h"
25
26 // TODO: cache -bytes and -length of NSData for immutable data!
27
28 @implementation NGDataStream
29
30 + (int)version {
31   return [super version] + 2;
32 }
33
34 + (id)dataStream {
35   return [self streamWithData:[NSMutableData dataWithCapacity:1024]];
36 }
37 + (id)dataStreamWithCapacity:(int)_capacity {
38   return [self streamWithData:[NSMutableData dataWithCapacity:_capacity]];
39 }
40
41 + (id)streamWithData:(NSData *)_data {
42   return [[[self alloc] initWithData:_data] autorelease];
43 }
44 - (id)initWithData:(NSData *)_data mode:(NGStreamMode)_mode {
45   if ((self = [super init])) {
46     self->data     = [_data retain];
47     self->position = 0;
48
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)];
54     }
55     else {
56       self->dataLength = NULL;
57       self->dataBytes  = NULL;
58     }
59     
60     self->streamMode = _mode;
61
62     /* for read-only streams */
63     if (self->streamMode == NGStreamMode_readOnly) {
64       self->bytes  = [self->data bytes];
65       self->length = [self->data length];
66     }
67   }
68   return self;
69 }
70 - (id)initWithData:(NSData *)_data {
71   NGStreamMode smode;
72   
73   smode = [data isKindOfClass:[NSMutableData class]]
74     ? NGStreamMode_readWrite
75     : NGStreamMode_readOnly;
76   return [self initWithData:_data mode:smode];
77 }
78
79 - (void)dealloc {
80   [self->data          release];
81   [self->lastException release];
82   [super dealloc];
83 }
84
85 /* accessors */
86
87 /* NGTextInputStream */
88
89 - (NSException *)lastException {
90   return self->lastException;
91 }
92 - (void)setLastException:(NSException *)_exception {
93   ASSIGN(self->lastException, _exception);
94 }
95 - (void)resetLastException {
96   [self->lastException release];
97   self->lastException = nil;
98 }
99
100 - (NSData *)data {
101   return self->data;
102 }
103
104 - (unsigned)availableBytes {
105   // returns number of available bytes
106   register unsigned currentLength = 0;
107   
108   if (self->bytes == NULL) {
109     currentLength = (self->dataLength == NULL)
110       ? [self->data length]
111       : self->dataLength(self->data, @selector(length));
112   }
113   else
114     currentLength = self->length;
115   
116   return (currentLength == position)
117     ? 0
118     : (currentLength - position);
119 }
120
121 /* primitives */
122
123 - (unsigned)readBytes:(void *)_buf count:(unsigned)_len {
124   // throws
125   //   NGStreamNotOpenException   when the stream is not open
126   //   NGEndOfStreamException     when the end of the stream is reached
127   register unsigned currentLength = 0;
128   
129   if (self->bytes == NULL) {
130     currentLength = (self->dataLength == NULL)
131       ? [self->data length]
132       : self->dataLength(self->data, @selector(length));
133   }
134   else
135     currentLength = self->length;
136
137   if (self->data == nil) {
138     NSException *e;
139     
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;
145   }
146
147   if (currentLength == position) {
148     [self setLastException:
149             [NGEndOfStreamException exceptionWithStream:self]];
150     return NGStreamError;
151   }
152   {
153     NSRange range;
154     range.location = position;
155
156     if ((position + _len) > currentLength)
157       range.length = currentLength - position;
158     else
159       range.length = _len;
160
161     [self->data getBytes:_buf range:range];
162
163     position += range.length;
164     return range.length;
165   }
166 }
167
168 - (int)readByte {
169   register const unsigned char *p;
170   register unsigned int currentLength = 0;
171   int result = 0;
172   
173   if (self->bytes == NULL) {
174     currentLength = (self->dataLength == NULL)
175       ? [self->data length]
176       : self->dataLength(self->data, @selector(length));
177   }
178   else
179     currentLength = self->length;
180   
181   if (currentLength == position)
182     return -1;
183   
184   if (self->bytes == NULL) {
185     p = (self->dataBytes == NULL)
186       ? [self->data bytes]
187       : self->dataBytes(self->data, @selector(bytes));
188   }
189   else
190     p = self->bytes;
191   result = p[self->position];
192   self->position++;
193   return result;
194 }
195
196 - (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len {
197   // throws
198   //   NGReadOnlyStreamException when the stream is not writeable
199   //   NGStreamNotOpenException  when the stream is not open
200   
201   if (self->data == nil) {
202     NSException *e;
203
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;
209   }
210   if (!NGCanWriteInStreamMode(streamMode)) {
211     NSException *e;
212     
213     e = [NGReadOnlyStreamException exceptionWithStream:self];
214     [self setLastException:e];
215     return NGStreamError;
216   }
217   [(NSMutableData *)self->data appendBytes:_buf length:_len];
218
219   return _len;
220 }
221
222 - (BOOL)close {
223   ASSIGN(self->lastException, (id)nil);
224   [self->data release]; self->data = nil;
225   position   = 0;
226   streamMode = NGStreamMode_undefined;
227   return YES;
228 }
229
230 - (NGStreamMode)mode {
231   return streamMode;
232 }
233 - (BOOL)isRootStream {
234   return YES;
235 }
236
237 // NGPositionableStream
238
239 - (BOOL)moveToLocation:(unsigned)_location {
240   position = _location;
241   return YES;
242 }
243 - (BOOL)moveByOffset:(int)_delta {
244   position += _delta;
245   return YES;
246 }
247
248 /* blocking .. */
249
250 - (BOOL)wouldBlockInMode:(NGStreamMode)_mode {
251   return NO;
252 }
253
254 - (id)retain {
255   return [super retain];
256 }
257
258 /* bytebuffer / lookahead API */
259
260 - (int)la:(unsigned)_la {
261   register unsigned int currentLength, newpos;
262   register const unsigned char *p;
263   int result = 0;
264   
265   if (self->bytes == NULL) {
266     currentLength = (self->dataLength == NULL)
267       ? [self->data length]
268       : self->dataLength(self->data, @selector(length));
269   }
270   else
271     currentLength = self->length;
272   
273   if (currentLength == self->position) // already at EOF
274     return -1;
275   
276   newpos = (self->position + _la);
277   if (newpos >= currentLength)
278     return -1; /* a look into EOF */
279   
280   if (self->bytes == NULL) {
281     p = (self->dataBytes == NULL)
282       ? [self->data bytes]
283       : self->dataBytes(self->data, @selector(bytes));
284   }
285   else
286     p = self->bytes;
287   
288   result = p[newpos];
289   return result;
290 }
291
292 - (void)consume { // consume one byte
293   register unsigned int currentLength = 0;
294   
295   if (self->bytes == NULL) {
296     currentLength = (self->dataLength == NULL)
297       ? [self->data length]
298       : self->dataLength(self->data, @selector(length));
299   }
300   else
301     currentLength = self->length;
302   
303   if (currentLength == self->position)
304     return;
305   
306   self->position++; // consume
307 }
308 - (void)consume:(unsigned)_cnt { // consume _cnt bytes
309   register unsigned int currentLength = 0;
310
311   if (self->bytes == NULL) {
312     currentLength = (self->dataLength == NULL)
313       ? [self->data length]
314       : self->dataLength(self->data, @selector(length));
315   }
316   else
317     currentLength = self->length;
318   
319   if (currentLength == self->position)
320     return;
321   
322   self->position += _cnt; // consume
323   
324   if (self->position > currentLength)
325     self->position = currentLength;
326 }
327
328 @end /* NGDataStream */