ObjFW  Check-in [69749b6a5b]

Overview
Comment:Do not conform to OFReadyFor*Observing by default

Instead of letting OFStream conform to it, which itself does not really
conform to it, let all the subclasses that actually do conform to it.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 69749b6a5ba999100f63c5cece5649b1221ff4b899314acfadb01999914644da
User & Date: js on 2017-11-19 11:04:22
Other Links: manifest | tags
Context
2017-11-19
12:05
Fix warnings introduced by OFComparing change check-in: 11f24addd7 user: js tags: trunk
11:04
Do not conform to OFReadyFor*Observing by default check-in: 69749b6a5b user: js tags: trunk
2017-11-18
19:14
Fix the last Doxygen warnings check-in: bb281804a3 user: js tags: trunk
Changes

Modified configure.ac from [49cf0ecee8] to [1919a82c3d].

902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
902
903
904
905
906
907
908

909
910
911
912
913
914
915







-







AC_MSG_RESULT($atomic_ops)

AC_ARG_ENABLE(files,
	AS_HELP_STRING([--disable-files], [disable file support]))
AS_IF([test x"$enable_files" != x"no"], [
	AC_DEFINE(OF_HAVE_FILES, 1, [Whether we have files])
	AC_SUBST(USE_SRCS_FILES, '${SRCS_FILES}')
	AC_SUBST(USE_SRCS_FILES_NOINCLUDE, '${SRCS_FILES_NOINCLUDE}')
	AC_SUBST(OFHASH, "ofhash")
	AC_SUBST(OFZIP, "ofzip")

	case "$host_os" in
		msdosdjgpp*)
			dnl DJGPP has the type, but it's not really usable.
			;;

Modified extra.mk.in from [153d2e2b77] to [901b193c8a].

62
63
64
65
66
67
68
69
70
71
72
73
74
62
63
64
65
66
67
68

69
70
71
72
73







-





RUN_TESTS = @RUN_TESTS@
TESTPLUGIN = @TESTPLUGIN@
TESTS_LIBS = @TESTS_LIBS@
TESTS_OBJCFLAGS = @TESTS_OBJCFLAGS@
UNICODE_M = @UNICODE_M@
USE_INCLUDES_ATOMIC = @USE_INCLUDES_ATOMIC@
USE_SRCS_FILES = @USE_SRCS_FILES@
USE_SRCS_FILES_NOINCLUDE = @USE_SRCS_FILES_NOINCLUDE@
USE_SRCS_PLUGINS = @USE_SRCS_PLUGINS@
USE_SRCS_SOCKETS = @USE_SRCS_SOCKETS@
USE_SRCS_THREADS = @USE_SRCS_THREADS@
WEAK_NSFOUNDATIONVERSIONNUMBER = @WEAK_NSFOUNDATIONVERSIONNUMBER@
WRAPPER = @WRAPPER@

Modified src/Makefile from [8aff73e1a1] to [340ccc4065].

112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
112
113
114
115
116
117
118

119
120
121

122
123
124
125
126
127
128







-



-







       ${USE_SRCS_SOCKETS}		\
       ${USE_SRCS_THREADS}
SRCS_FILES = OFFile.m			\
	     OFFileManager.m		\
	     OFINICategory.m		\
	     OFINIFile.m		\
	     OFSettings.m
SRCS_FILES_NOINCLUDE = OFURLHandler_file.m
SRCS_PLUGINS = OFPlugin.m
SRCS_SOCKETS = OFHTTPClient.m			\
	       OFHTTPServer.m			\
	       OFKernelEventObserver.m		\
	       OFStreamSocket.m			\
	       OFTCPSocket.m			\
	       OFUDPSocket.m			\
	       resolver.m			\
	       socket.m
SRCS_THREADS = OFCondition.m		\
	       OFMutex.m		\
139
140
141
142
143
144
145

146
147
148
149
150
151
152
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151







+







		  atomic_powerpc.h		\
		  atomic_sync_builtins.h	\
		  atomic_x86.h
INCLUDES := ${SRCS:.m=.h}			\
	    OFCollection.h			\
	    OFCryptoHash.h			\
	    OFJSONRepresentation.h		\
	    OFKernelEventObserver.h		\
	    OFKeyValueCoding.h			\
	    OFLocking.h				\
	    OFMessagePackRepresentation.h	\
	    OFSerialization.h			\
	    OFTLSSocket.h			\
	    ObjFW.h				\
	    autorelease.h			\
169
170
171
172
173
174
175
176

177
178
179




180
181
182
183
184
185
186
168
169
170
171
172
173
174

175



176
177
178
179
180
181
182
183
184
185
186







-
+
-
-
-
+
+
+
+







	OFMutableDictionary_hashtable.m	\
	OFMutableSet_hashtable.m	\
	OFMutableString_UTF8.m		\
	OFSet_hashtable.m		\
	OFString_UTF8.m			\
	${AUTORELEASE_M}		\
	${FOUNDATION_COMPAT_M}		\
	${INSTANCE_M}			\
	${INSTANCE_M}
	${USE_SRCS_FILES_NOINCLUDE}
SRCS_FILES += OFSettings_INIFile.m
SRCS_SOCKETS += ${OFKERNELEVENTOBSERVER_EPOLL_M}	\
SRCS_FILES += OFSettings_INIFile.m	\
	      OFURLHandler_file.m
SRCS_SOCKETS += OFKernelEventObserver.m			\
		${OFKERNELEVENTOBSERVER_EPOLL_M}	\
		${OFKERNELEVENTOBSERVER_KQUEUE_M}	\
		${OFKERNELEVENTOBSERVER_POLL_M}		\
		${OFKERNELEVENTOBSERVER_SELECT_M}	\
		OFTCPSocket+SOCKS5.m

OBJS_EXTRA = ${RUNTIME_RUNTIME_A}	\
	     ${EXCEPTIONS_EXCEPTIONS_A} \

Modified src/OFFile.h from [92705fc93e] to [557607a4f8].

11
12
13
14
15
16
17

18
19
20
21
22
23
24
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25







+







 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#import "OFSeekableStream.h"
#import "OFKernelEventObserver.h"

#ifndef OF_MORPHOS
# define OF_FILE_HANDLE_IS_FD
# define OF_INVALID_FILE_HANDLE (-1)
typedef int of_file_handle_t;
#else
# define BOOL EXEC_BOOL
34
35
36
37
38
39
40



41
42
43
44
45
46
47
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51







+
+
+








/*!
 * @class OFFile OFFile.h ObjFW/OFFile.h
 *
 * @brief A class which provides methods to read and write files.
 */
@interface OFFile: OFSeekableStream
#ifdef OF_FILE_HANDLE_IS_FD
    <OFReadyForReadingObserving, OFReadyForWritingObserving>
#endif
{
	of_file_handle_t _handle;
	bool _atEndOfStream;
}

/*!
 * @brief Creates a new OFFile with the specified path and mode.

Modified src/OFHTTPClient.m from [69a4197ea4] to [a6980a9e89].

22
23
24
25
26
27
28

29
30
31
32
33
34
35
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36







+







#include <string.h>

#import "OFHTTPClient.h"
#import "OFData.h"
#import "OFDictionary.h"
#import "OFHTTPRequest.h"
#import "OFHTTPResponse.h"
#import "OFKernelEventObserver.h"
#import "OFNumber.h"
#import "OFString.h"
#import "OFTCPSocket.h"
#import "OFURL.h"

#import "OFAlreadyConnectedException.h"
#import "OFHTTPRequestFailedException.h"
61
62
63
64
65
66
67
68

69
70
71
72
73
74
75
62
63
64
65
66
67
68

69
70
71
72
73
74
75
76







-
+







		       request: (OFHTTPRequest *)request
		     redirects: (unsigned int)redirects
		       context: (id)context;
- (void)start;
- (void)closeAndReconnect;
@end

@interface OFHTTPClientResponse: OFHTTPResponse
@interface OFHTTPClientResponse: OFHTTPResponse <OFReadyForReadingObserving>
{
	OFTCPSocket *_socket;
	bool _hasContentLength, _chunked, _keepAlive, _atEndOfStream;
	size_t _toRead;
}

@property (nonatomic, setter=of_setKeepAlive:) bool of_keepAlive;

Modified src/OFHTTPServer.m from [3bc806eac7] to [1522d55623].

169
170
171
172
173
174
175
176

177
178
179
180
181
182
183
169
170
171
172
173
174
175

176
177
178
179
180
181
182
183







-
+







		tmp++;
	}

	return [OFString stringWithUTF8StringNoCopy: cString
				       freeWhenDone: true];
}

@interface OFHTTPServerResponse: OFHTTPResponse
@interface OFHTTPServerResponse: OFHTTPResponse <OFReadyForWritingObserving>
{
	OFTCPSocket *_socket;
	OFHTTPServer *_server;
	OFHTTPRequest *_request;
	bool _chunked, _headersSent;
}

Modified src/OFInflateStream.h from [e064c26fb9] to [a58b9e9e07].

11
12
13
14
15
16
17

18
19
20
21
22
23
24



25
26
27
28
29

30
31
32
33
34

35
36
37
38
39
40
41
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

33
34
35
36
37

38
39
40
41
42
43
44
45







+







+
+
+




-
+




-
+







 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#import "OFStream.h"
#import "OFKernelEventObserver.h"

OF_ASSUME_NONNULL_BEGIN

#define OF_INFLATE_STREAM_BUFFER_SIZE 4096

/*!
 * @class OFInflateStream OFInflateStream.h ObjFW/OFInflateStream.h
 *
 * @note This class only conforms to OFReadyForReadingObserving if the
 *	 underlying stream does so, too.
 *
 * @brief A class that handles Deflate decompression transparently for an
 *	  underlying stream.
 */
@interface OFInflateStream: OFStream
@interface OFInflateStream: OFStream <OFReadyForReadingObserving>
{
#ifdef OF_INFLATE_STREAM_M
@public
#endif
	OFStream *_stream;
	OF_KINDOF(OFStream *) _stream;
	uint8_t _buffer[OF_INFLATE_STREAM_BUFFER_SIZE];
	uint16_t _bufferIndex, _bufferLength;
	uint8_t _byte;
	uint8_t _bitIndex, _savedBitsLength;
	uint16_t _savedBits;
	uint8_t *_Nullable _slidingWindow;
	uint16_t _slidingWindowIndex, _slidingWindowMask;

Modified src/OFKernelEventObserver.h from [cad56e81b9] to [ee35836078].

12
13
14
15
16
17
18

19


20
21
22
23
24
25
26
12
13
14
15
16
17
18
19

20
21
22
23
24
25
26
27
28







+
-
+
+







 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#import "OFObject.h"

#ifdef OF_HAVE_SOCKETS
#import "socket.h"
# import "socket.h"
#endif

OF_ASSUME_NONNULL_BEGIN

@class OFMutableArray OF_GENERIC(ObjectType);
@class OFDate;
#ifdef OF_HAVE_THREADS
@class OFMutex;
86
87
88
89
90
91
92

93
94
95
96
97
98
99
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102







+







/*!
 * @brief The file descriptor for writing that should be checked by the
 *	  OFKernelEventObserver.
 */
@property (readonly, nonatomic) int fileDescriptorForWriting;
@end

#ifdef OF_HAVE_SOCKETS
/*!
 * @class OFKernelEventObserver
 *	  OFKernelEventObserver.h ObjFW/OFKernelEventObserver.h
 *
 * @brief A class that can observe multiple kernel events (e.g. streams being
 *	  ready to read) at once.
 *
201
202
203
204
205
206
207

208
209
204
205
206
207
208
209
210
211
212
213







+


 *
 * This is automatically done when a new object is added or removed by another
 * thread, but in some circumstances, it might be desirable for a thread to
 * manually stop the observe running in another thread.
 */
- (void)cancel;
@end
#endif

OF_ASSUME_NONNULL_END

Modified src/OFProcess.h from [b0f7aa5681] to [b5fba3c334].

24
25
26
27
28
29
30

31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47



48
49
50
51
52
53
54
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58







+

















+
+
+







#include "objfw-defs.h"

#ifdef OF_HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif

#import "OFStream.h"
#import "OFKernelEventObserver.h"
#import "OFString.h"

#ifdef OF_WINDOWS
# include <windows.h>
#endif

OF_ASSUME_NONNULL_BEGIN

@class OFArray OF_GENERIC(ObjectType);
@class OFDictionary OF_GENERIC(KeyType, ObjectType);

/*!
 * @class OFProcess OFProcess.h ObjFW/OFProcess.h
 *
 * @brief A class for stream-like communication with a newly created process.
 */
@interface OFProcess: OFStream
#ifndef OF_WINDOWS
    <OFReadyForReadingObserving, OFReadyForWritingObserving>
#endif
{
#ifndef OF_WINDOWS
	pid_t _pid;
	int _readPipe[2], _writePipe[2];
#else
	HANDLE _process, _readPipe[2], _writePipe[2];
#endif

Modified src/OFProcess.m from [47e26e30a9] to [b38c51b4de].

523
524
525
526
527
528
529

530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546

547
548
549
550
551
552
553
523
524
525
526
527
528
529
530
531
532

533



534
535
536
537

538



539
540
541
542
543
544
545
546
547







+


-

-
-
-




-

-
-
-

+







							     errNo: errNo];
	}
#endif

	return (size_t)bytesWritten;
}

#ifndef OF_WINDOWS
- (int)fileDescriptorForReading
{
#ifndef OF_WINDOWS
	return _readPipe[0];
#else
	OF_UNRECOGNIZED_SELECTOR
#endif
}

- (int)fileDescriptorForWriting
{
#ifndef OF_WINDOWS
	return _writePipe[1];
#else
	OF_UNRECOGNIZED_SELECTOR
#endif
}
#endif

- (void)closeForWriting
{
#ifndef OF_WINDOWS
	if (_writePipe[1] != -1)
		close(_writePipe[1]);

Modified src/OFRunLoop+Private.h from [f6fcbe1db8] to [ea09023939].

21
22
23
24
25
26
27
28


29
30
31
32
33
34


35
36
37
38
39
40


41
42
43
44
45


46
47
48
49
50
51
52
21
22
23
24
25
26
27

28
29
30
31
32
33
34

35
36
37
38
39
40
41

42
43
44
45
46
47

48
49
50
51
52
53
54
55
56







-
+
+





-
+
+





-
+
+




-
+
+







#endif

OF_ASSUME_NONNULL_BEGIN

@interface OFRunLoop ()
+ (void)of_setMainRunLoop: (OFRunLoop *)runLoop;
#ifdef OF_HAVE_SOCKETS
+ (void)of_addAsyncReadForStream: (OFStream *)stream
+ (void)of_addAsyncReadForStream: (OFStream <OFReadyForReadingObserving> *)
				      stream
			  buffer: (void *)buffer
			  length: (size_t)length
			  target: (id)target
			selector: (SEL)selector
			 context: (nullable id)context;
+ (void)of_addAsyncReadForStream: (OFStream *)stream
+ (void)of_addAsyncReadForStream: (OFStream <OFReadyForReadingObserving> *)
				      stream
			  buffer: (void *)buffer
		     exactLength: (size_t)length
			  target: (id)target
			selector: (SEL)selector
			 context: (nullable id)context;
+ (void)of_addAsyncReadLineForStream: (OFStream *)stream
+ (void)of_addAsyncReadLineForStream: (OFStream <OFReadyForReadingObserving> *)
					  stream
			    encoding: (of_string_encoding_t)encoding
			      target: (id)target
			    selector: (SEL)selector
			     context: (nullable id)context;
+ (void)of_addAsyncWriteForStream: (OFStream *)stream
+ (void)of_addAsyncWriteForStream: (OFStream <OFReadyForWritingObserving> *)
				       stream
			   buffer: (const void *)buffer
			   length: (size_t)length
			   target: (id)target
			 selector: (SEL)selector
			  context: (nullable id)context;
+ (void)of_addAsyncAcceptForTCPSocket: (OFTCPSocket *)socket
			       target: (id)target
62
63
64
65
66
67
68
69


70
71
72
73


74
75
76
77


78
79
80


81
82
83
84
85
86
87
66
67
68
69
70
71
72

73
74
75
76
77

78
79
80
81
82

83
84
85
86

87
88
89
90
91
92
93
94
95







-
+
+



-
+
+



-
+
+


-
+
+







			     buffer: (const void *)buffer
			     length: (size_t)length
			   receiver: (of_udp_socket_address_t)receiver
			     target: (id)target
			   selector: (SEL)selector
			    context: (nullable id)context;
# ifdef OF_HAVE_BLOCKS
+ (void)of_addAsyncReadForStream: (OFStream *)stream
+ (void)of_addAsyncReadForStream: (OFStream <OFReadyForReadingObserving> *)
				      stream
			  buffer: (void *)buffer
			  length: (size_t)length
			   block: (of_stream_async_read_block_t)block;
+ (void)of_addAsyncReadForStream: (OFStream *)stream
+ (void)of_addAsyncReadForStream: (OFStream <OFReadyForReadingObserving> *)
				      stream
			  buffer: (void *)buffer
		     exactLength: (size_t)length
			   block: (of_stream_async_read_block_t)block;
+ (void)of_addAsyncReadLineForStream: (OFStream *)stream
+ (void)of_addAsyncReadLineForStream: (OFStream <OFReadyForReadingObserving> *)
					  stream
			    encoding: (of_string_encoding_t)encoding
			       block: (of_stream_async_read_line_block_t)block;
+ (void)of_addAsyncWriteForStream: (OFStream *)stream
+ (void)of_addAsyncWriteForStream: (OFStream <OFReadyForWritingObserving> *)
				       stream
			   buffer: (const void *)buffer
			   length: (size_t)length
			    block: (of_stream_async_write_block_t)block;
+ (void)of_addAsyncAcceptForTCPSocket: (OFTCPSocket *)socket
				block: (of_tcp_socket_async_accept_block_t)
					   block;
+ (void)of_addAsyncReceiveForUDPSocket: (OFUDPSocket *)socket

Modified src/OFRunLoop.m from [2a10d90f42] to [5ad7583705].

525
526
527
528
529
530
531
532


533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548


549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564


565
566
567
568
569
570
571
572
573
574
575
576
577
578


579
580
581
582
583
584
585
525
526
527
528
529
530
531

532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548

549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565

566
567
568
569
570
571
572
573
574
575
576
577
578
579
580

581
582
583
584
585
586
587
588
589







-
+
+















-
+
+















-
+
+













-
+
+







									\
	queueItem = [[[type alloc] init] autorelease];			\
	code								\
	[queue appendObject: queueItem];				\
									\
	objc_autoreleasePoolPop(pool);

+ (void)of_addAsyncReadForStream: (OFStream *)stream
+ (void)of_addAsyncReadForStream: (OFStream <OFReadyForReadingObserving> *)
				      stream
			  buffer: (void *)buffer
			  length: (size_t)length
			  target: (id)target
			selector: (SEL)selector
			 context: (id)context
{
	ADD_READ(OFRunLoop_ReadQueueItem, stream, {
		queueItem->_target = [target retain];
		queueItem->_selector = selector;
		queueItem->_context = [context retain];
		queueItem->_buffer = buffer;
		queueItem->_length = length;
	})
}

+ (void)of_addAsyncReadForStream: (OFStream *)stream
+ (void)of_addAsyncReadForStream: (OFStream <OFReadyForReadingObserving> *)
				      stream
			  buffer: (void *)buffer
		     exactLength: (size_t)exactLength
			  target: (id)target
			selector: (SEL)selector
			 context: (id)context
{
	ADD_READ(OFRunLoop_ExactReadQueueItem, stream, {
		queueItem->_target = [target retain];
		queueItem->_selector = selector;
		queueItem->_context = [context retain];
		queueItem->_buffer = buffer;
		queueItem->_exactLength = exactLength;
	})
}

+ (void)of_addAsyncReadLineForStream: (OFStream *)stream
+ (void)of_addAsyncReadLineForStream: (OFStream <OFReadyForReadingObserving> *)
					  stream
			    encoding: (of_string_encoding_t)encoding
			      target: (id)target
			    selector: (SEL)selector
			     context: (id)context
{
	ADD_READ(OFRunLoop_ReadLineQueueItem, stream, {
		queueItem->_target = [target retain];
		queueItem->_selector = selector;
		queueItem->_context = [context retain];
		queueItem->_encoding = encoding;
	})
}

+ (void)of_addAsyncWriteForStream: (OFStream *)stream
+ (void)of_addAsyncWriteForStream: (OFStream <OFReadyForWritingObserving> *)
				       stream
			   buffer: (const void *)buffer
			   length: (size_t)length
			   target: (id)target
			 selector: (SEL)selector
			  context: (id)context
{
	ADD_WRITE(OFRunLoop_WriteQueueItem, stream, {
634
635
636
637
638
639
640
641


642
643
644
645
646
647
648
649
650
651
652
653


654
655
656
657
658
659
660
661
662
663
664
665


666
667
668
669
670
671
672
673
674
675


676
677
678
679
680
681
682
638
639
640
641
642
643
644

645
646
647
648
649
650
651
652
653
654
655
656
657

658
659
660
661
662
663
664
665
666
667
668
669
670

671
672
673
674
675
676
677
678
679
680
681

682
683
684
685
686
687
688
689
690







-
+
+











-
+
+











-
+
+









-
+
+







		queueItem->_buffer = buffer;
		queueItem->_length = length;
		queueItem->_receiver = receiver;
	})
}

# ifdef OF_HAVE_BLOCKS
+ (void)of_addAsyncReadForStream: (OFStream *)stream
+ (void)of_addAsyncReadForStream: (OFStream <OFReadyForReadingObserving> *)
				      stream
			  buffer: (void *)buffer
			  length: (size_t)length
			   block: (of_stream_async_read_block_t)block
{
	ADD_READ(OFRunLoop_ReadQueueItem, stream, {
		queueItem->_block = [block copy];
		queueItem->_buffer = buffer;
		queueItem->_length = length;
	})
}

+ (void)of_addAsyncReadForStream: (OFStream *)stream
+ (void)of_addAsyncReadForStream: (OFStream <OFReadyForReadingObserving> *)
				      stream
			  buffer: (void *)buffer
		     exactLength: (size_t)exactLength
			   block: (of_stream_async_read_block_t)block
{
	ADD_READ(OFRunLoop_ExactReadQueueItem, stream, {
		queueItem->_block = [block copy];
		queueItem->_buffer = buffer;
		queueItem->_exactLength = exactLength;
	})
}

+ (void)of_addAsyncReadLineForStream: (OFStream *)stream
+ (void)of_addAsyncReadLineForStream: (OFStream <OFReadyForReadingObserving> *)
					  stream
			    encoding: (of_string_encoding_t)encoding
			       block: (of_stream_async_read_line_block_t)block
{
	ADD_READ(OFRunLoop_ReadLineQueueItem, stream, {
		queueItem->_block = [block copy];
		queueItem->_encoding = encoding;
	})
}

+ (void)of_addAsyncWriteForStream: (OFStream *)stream
+ (void)of_addAsyncWriteForStream: (OFStream <OFReadyForWritingObserving> *)
				       stream
			   buffer: (const void *)buffer
			   length: (size_t)length
			    block: (of_stream_async_write_block_t)block
{
	ADD_WRITE(OFRunLoop_WriteQueueItem, stream, {
		queueItem->_block = [block copy];
		queueItem->_buffer = buffer;

Modified src/OFStdIOStream.h from [0ce400e3cf] to [9c739b6c2b].

11
12
13
14
15
16
17

18
19
20
21
22
23
24
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25







+







 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#import "OFStream.h"
#import "OFKernelEventObserver.h"

#ifdef OF_MORPHOS
# define BOOL EXEC_BOOL
# include <proto/dos.h>
# undef BOOL
#endif

32
33
34
35
36
37
38



39
40
41
42
43
44
45
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49







+
+
+







 * The global variables @ref of_stdin, @ref of_stdout and @ref of_stderr are
 * instances of this class and need no initialization.
 */
#ifdef OF_STDIO_STREAM_WIN32_CONSOLE_H
OF_SUBCLASSING_RESTRICTED
#endif
@interface OFStdIOStream: OFStream
#if !defined(OF_WINDOWS) && !defined(OF_MORPHOS)
    <OFReadyForReadingObserving, OFReadyForWritingObserving>
#endif
{
#ifndef OF_MORPHOS
	int _fd;
#else
	BPTR _handle;
	bool _closable;
#endif

Modified src/OFStream.h from [9a95fdcb49] to [cfa0bd1248].

100
101
102
103
104
105
106
107

108
109
110
111
112
113
114
115
116
117
118
100
101
102
103
104
105
106

107




108
109
110
111
112
113
114







-
+
-
-
-
-







 *	 @ref lowlevelReadIntoBuffer:length:, @ref lowlevelWriteBuffer:length:
 *	 and @ref lowlevelIsAtEndOfStream, but nothing else, as those are are
 *	 the methods that do the actual work. OFStream uses those for all other
 *	 methods and does all the caching and other stuff for you. If you
 *	 override these methods without the `lowlevel` prefix, you *will* break
 *	 caching and get broken results!
 */
@interface OFStream: OFObject <
@interface OFStream: OFObject <OFCopying>
#ifdef OF_HAVE_SOCKETS
    OFReadyForReadingObserving, OFReadyForWritingObserving,
#endif
    OFCopying>
{
#if !defined(OF_SEEKABLE_STREAM_M) && !defined(OF_TCP_SOCKET_M)
@private
#endif
	char *_Nullable _readBuffer, *_Nullable _readBufferMemory;
	char *_Nullable _writeBuffer;
	size_t _readBufferLength, _writeBufferLength;
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
136
137
138
139
140
141
142










143
144
145
146
147
148
149







-
-
-
-
-
-
-
-
-
-







 * @brief Whether the stream is in blocking mode.
 *
 * By default, a stream is in blocking mode.
 * On Win32, setting this currently only works for sockets!
 */
@property (readonly, nonatomic, getter=isBlocking) bool blocking;

/*!
 * @brief The file descriptor for the read end of the stream.
 */
@property (readonly, nonatomic) int fileDescriptorForReading;

/*!
 * @brief The file descriptor for the write end of the stream.
 */
@property (readonly, nonatomic) int fileDescriptorForWriting;

/*!
 * @brief Reads *at most* size bytes from the stream into a buffer.
 *
 * On network streams, this might read less than the specified number of bytes.
 * If you want to read exactly the specified number of bytes, use
 * @ref readIntoBuffer:exactLength:. Note that a read can even return 0 bytes -
 * this does not necessarily mean that the stream ended, so you still need to
196
197
198
199
200
201
202
203
204


205
206
207
208
209
210
211
182
183
184
185
186
187
188


189
190
191
192
193
194
195
196
197







-
-
+
+







 *
 * On network streams, this might read less than the specified number of bytes.
 * If you want to read exactly the specified number of bytes, use
 * @ref asyncReadIntoBuffer:exactLength:target:selector:context:. Note that a
 * read can even return 0 bytes - this does not necessarily mean that the
 * stream ended, so you still need to check @ref atEndOfStream.
 *
 * @note The stream must implement @ref fileDescriptorForReading and return a
 *	 valid file descriptor in order for this to work!
 * @note The stream must conform to @ref OFReadyForReadingObserving in order
 *	 for this to work!
 *
 * @param buffer The buffer into which the data is read.
 *		 The buffer must not be freed before the async read completed!
 * @param length The length of the data that should be read at most.
 *		 The buffer *must* be *at least* this big!
 * @param target The target on which the selector should be called when the
 *		 data has been received. If the method returns true, it will be
229
230
231
232
233
234
235
236
237


238
239
240
241
242
243
244
215
216
217
218
219
220
221


222
223
224
225
226
227
228
229
230







-
-
+
+







 *	  stream into a buffer.
 *
 * Unlike @ref asyncReadIntoBuffer:length:target:selector:context:, this method
 * does not call the method when less than the specified length has been read -
 * instead, it waits until it got exactly the specified length, the stream has
 * ended or an exception occurred.
 *
 * @note The stream must implement @ref fileDescriptorForReading and return a
 *	 valid file descriptor in order for this to work!
 * @note The stream must conform to @ref OFReadyForReadingObserving in order
 *	 for this to work!
 *
 * @param buffer The buffer into which the data is read
 * @param length The length of the data that should be read.
 *		 The buffer *must* be *at least* this big!
 * @param target The target on which the selector should be called when the
 *		 data has been received. If the method returns true, it will be
 *		 called again with the same buffer and exact length when more
263
264
265
266
267
268
269
270
271


272
273
274
275
276
277
278
249
250
251
252
253
254
255


256
257
258
259
260
261
262
263
264







-
-
+
+







 *
 * On network streams, this might read less than the specified number of bytes.
 * If you want to read exactly the specified number of bytes, use
 * @ref asyncReadIntoBuffer:exactLength:block:. Note that a read can even
 * return 0 bytes - this does not necessarily mean that the stream ended, so
 * you still need to check @ref atEndOfStream.
 *
 * @note The stream must implement @ref fileDescriptorForReading and return a
 *	 valid file descriptor in order for this to work!
 * @note The stream must conform to @ref OFReadyForReadingObserving in order
 *	 for this to work!
 *
 * @param buffer The buffer into which the data is read.
 *		 The buffer must not be freed before the async read completed!
 * @param length The length of the data that should be read at most.
 *		 The buffer *must* be *at least* this big!
 * @param block The block to call when the data has been received.
 *		If the block returns true, it will be called again with the same
289
290
291
292
293
294
295
296
297


298
299
300
301
302
303
304
275
276
277
278
279
280
281


282
283
284
285
286
287
288
289
290







-
-
+
+







 *	  stream into a buffer.
 *
 * Unlike @ref asyncReadIntoBuffer:length:block:, this method does not invoke
 * the block when less than the specified length has been read - instead, it
 * waits until it got exactly the specified length, the stream has ended or an
 * exception occurred.
 *
 * @note The stream must implement @ref fileDescriptorForReading and return a
 *	 valid file descriptor in order for this to work!
 * @note The stream must conform to @ref OFReadyForReadingObserving in order
 *	 for this to work!
 *
 * @param buffer The buffer into which the data is read
 * @param length The length of the data that should be read.
 *		 The buffer *must* be *at least* this big!
 * @param block The block to call when the data has been received.
 *		If the block returns true, it will be called again with the same
 *		buffer and exact length when more data has been received. If
658
659
660
661
662
663
664
665
666


667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687


688
689
690
691
692
693
694
644
645
646
647
648
649
650


651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671


672
673
674
675
676
677
678
679
680







-
-
+
+



















-
-
+
+







- (nullable OFString *)readLineWithEncoding: (of_string_encoding_t)encoding;

#ifdef OF_HAVE_SOCKETS
/*!
 * @brief Asynchronously reads until a newline, `\0`, end of stream or an
 *	  exception occurs.
 *
 * @note The stream must implement @ref fileDescriptorForReading and return a
 *	 valid file descriptor in order for this to work!
 * @note The stream must conform to @ref OFReadyForReadingObserving in order
 *	 for this to work!
 *
 * @param target The target on which to call the selector when the data has
 *		 been received. If the method returns true, it will be called
 *		 again when the next line has been received. If you want the
 *		 next method in the queue to handle the next line, you need to
 *		 return false from the method
 * @param selector The selector to call on the target. The signature must be
 *		   `bool (OFStream *stream, OFString *line, id context,
 *		   id exception)`.
 * @param context A context object to pass along to the target
 */
- (void)asyncReadLineWithTarget: (id)target
		       selector: (SEL)selector
			context: (nullable id)context;

/*!
 * @brief Asynchronously reads with the specified encoding until a newline,
 *	  `\0`, end of stream or an exception occurs.
 *
 * @note The stream must implement @ref fileDescriptorForReading and return a
 *	 valid file descriptor in order for this to work!
 * @note The stream must conform to @ref OFReadyForReadingObserving in order
 *	 for this to work!
 *
 * @param encoding The encoding used by the stream
 * @param target The target on which to call the selector when the data has
 *		 been received. If the method returns true, it will be called
 *		 again when the next line has been received. If you want the
 *		 next method in the queue to handle the next line, you need to
 *		 return false from the method
703
704
705
706
707
708
709
710
711


712
713
714
715
716
717
718
719
720
721
722
723
724
725
726


727
728
729
730
731
732
733
689
690
691
692
693
694
695


696
697
698
699
700
701
702
703
704
705
706
707
708
709
710


711
712
713
714
715
716
717
718
719







-
-
+
+













-
-
+
+







			  context: (nullable id)context;

# ifdef OF_HAVE_BLOCKS
/*!
 * @brief Asynchronously reads until a newline, `\0`, end of stream or an
 *	  exception occurs.
 *
 * @note The stream must implement @ref fileDescriptorForReading and return a
 *	 valid file descriptor in order for this to work!
 * @note The stream must conform to @ref OFReadyForReadingObserving in order
 *	 for this to work!
 *
 * @param block The block to call when the data has been received.
 *		If the block returns true, it will be called again when the next
 *		line has been received. If you want the next block in the queue
 *		to handle the next line, you need to return false from the
 *		block.
 */
- (void)asyncReadLineWithBlock: (of_stream_async_read_line_block_t)block;

/*!
 * @brief Asynchronously reads with the specified encoding until a newline,
 *	  `\0`, end of stream or an exception occurs.
 *
 * @note The stream must implement @ref fileDescriptorForReading and return a
 *	 valid file descriptor in order for this to work!
 * @note The stream must conform to @ref OFReadyForReadingObserving in order
 *	 for this to work!
 *
 * @param encoding The encoding used by the stream
 * @param block The block to call when the data has been received.
 *		If the block returns true, it will be called again when the next
 *		line has been received. If you want the next block in the queue
 *		to handle the next line, you need to return false from the
 *		block.
819
820
821
822
823
824
825
826
827


828
829
830
831
832
833
834
805
806
807
808
809
810
811


812
813
814
815
816
817
818
819
820







-
-
+
+







- (size_t)writeBuffer: (const void *)buffer
	       length: (size_t)length;

#ifdef OF_HAVE_SOCKETS
/*!
 * @brief Asynchronously writes a buffer into the stream.
 *
 * @note The stream must implement @ref fileDescriptorForWriting and return a
 *	 valid file descriptor in order for this to work!
 * @note The stream must conform to @ref OFReadyForWritingObserving in order
 *	 for this to work!
 *
 * @param buffer The buffer from which the data is written into the stream. The
 *		 buffer needs to be valid until the write request is completed!
 * @param length The length of the data that should be written
 * @param target The target on which the selector should be called when the
 *		 data has been written. The method should return the length for
 *		 the next write with the same callback or 0 if it should not
846
847
848
849
850
851
852
853
854


855
856
857
858
859
860
861
832
833
834
835
836
837
838


839
840
841
842
843
844
845
846
847







-
-
+
+







		selector: (SEL)selector
		 context: (nullable id)context;

# ifdef OF_HAVE_BLOCKS
/*!
 * @brief Asynchronously writes a buffer into the stream.
 *
 * @note The stream must implement @ref fileDescriptorForWriting and return a
 *	 valid file descriptor in order for this to work!
 * @note The stream must conform to @ref OFReadyForWritingObserving in order
 *	 for this to work!
 *
 * @param buffer The buffer from which the data is written into the stream. The
 *		 buffer needs to be valid until the write request is completed!
 * @param length The length of the data that should be written
 * @param block The block to call when the data has been written. It should
 *		return the length for the next write with the same callback or
 *		0 if it should not repeat. The buffer may be changed, so that

Modified src/OFStream.m from [3125ef69c3] to [e841a9f1c7].

191
192
193
194
195
196
197



198

199
200
201
202
203
204
205
206
207
208
209
210
211



212

213
214
215
216
217
218
219
220
221
222
223
224



225

226
227
228
229
230
231
232
233
234



235

236
237
238
239
240
241
242
191
192
193
194
195
196
197
198
199
200

201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217

218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233

234
235
236
237
238
239
240
241
242
243
244
245
246

247
248
249
250
251
252
253
254







+
+
+
-
+













+
+
+
-
+












+
+
+
-
+









+
+
+
-
+







#ifdef OF_HAVE_SOCKETS
- (void)asyncReadIntoBuffer: (void *)buffer
		     length: (size_t)length
		     target: (id)target
		   selector: (SEL)selector
		    context: (id)context
{
	OFStream <OFReadyForReadingObserving> *stream =
	    (OFStream <OFReadyForReadingObserving> *)self;

	[OFRunLoop of_addAsyncReadForStream: self
	[OFRunLoop of_addAsyncReadForStream: stream
				     buffer: buffer
				     length: length
				     target: target
				   selector: selector
				    context: context];
}

- (void)asyncReadIntoBuffer: (void *)buffer
		exactLength: (size_t)length
		     target: (id)target
		   selector: (SEL)selector
		    context: (id)context
{
	OFStream <OFReadyForReadingObserving> *stream =
	    (OFStream <OFReadyForReadingObserving> *)self;

	[OFRunLoop of_addAsyncReadForStream: self
	[OFRunLoop of_addAsyncReadForStream: stream
				     buffer: buffer
				exactLength: length
				     target: target
				   selector: selector
				    context: context];
}

# ifdef OF_HAVE_BLOCKS
- (void)asyncReadIntoBuffer: (void *)buffer
		     length: (size_t)length
		      block: (of_stream_async_read_block_t)block
{
	OFStream <OFReadyForReadingObserving> *stream =
	    (OFStream <OFReadyForReadingObserving> *)self;

	[OFRunLoop of_addAsyncReadForStream: self
	[OFRunLoop of_addAsyncReadForStream: stream
				     buffer: buffer
				     length: length
				      block: block];
}

- (void)asyncReadIntoBuffer: (void *)buffer
		exactLength: (size_t)length
		      block: (of_stream_async_read_block_t)block
{
	OFStream <OFReadyForReadingObserving> *stream =
	    (OFStream <OFReadyForReadingObserving> *)self;

	[OFRunLoop of_addAsyncReadForStream: self
	[OFRunLoop of_addAsyncReadForStream: stream
				     buffer: buffer
				exactLength: length
				      block: block];
}
# endif
#endif

826
827
828
829
830
831
832



833

834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849



850

851
852
853
854
855
856
857
838
839
840
841
842
843
844
845
846
847

848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867

868
869
870
871
872
873
874
875







+
+
+
-
+
















+
+
+
-
+







}

- (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding
			   target: (id)target
			 selector: (SEL)selector
			  context: (id)context
{
	OFStream <OFReadyForReadingObserving> *stream =
	    (OFStream <OFReadyForReadingObserving> *)self;

	[OFRunLoop of_addAsyncReadLineForStream: self
	[OFRunLoop of_addAsyncReadLineForStream: stream
				       encoding: encoding
					 target: target
				       selector: selector
					context: context];
}

# ifdef OF_HAVE_BLOCKS
- (void)asyncReadLineWithBlock: (of_stream_async_read_line_block_t)block
{
	[self asyncReadLineWithEncoding: OF_STRING_ENCODING_UTF_8
				  block: block];
}

- (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding
			    block: (of_stream_async_read_line_block_t)block
{
	OFStream <OFReadyForReadingObserving> *stream =
	    (OFStream <OFReadyForReadingObserving> *)self;

	[OFRunLoop of_addAsyncReadLineForStream: self
	[OFRunLoop of_addAsyncReadLineForStream: stream
				       encoding: encoding
					  block: block];
}
# endif
#endif

- (OFString *)tryReadLine
1075
1076
1077
1078
1079
1080
1081



1082

1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094



1095

1096
1097
1098
1099
1100
1101
1102
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102

1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118

1119
1120
1121
1122
1123
1124
1125
1126







+
+
+
-
+












+
+
+
-
+







#ifdef OF_HAVE_SOCKETS
- (void)asyncWriteBuffer: (const void *)buffer
		  length: (size_t)length
		  target: (id)target
		selector: (SEL)selector
		 context: (id)context
{
	OFStream <OFReadyForWritingObserving> *stream =
	    (OFStream <OFReadyForWritingObserving> *)self;

	[OFRunLoop of_addAsyncWriteForStream: self
	[OFRunLoop of_addAsyncWriteForStream: stream
				      buffer: buffer
				      length: length
				      target: target
				    selector: selector
				     context: context];
}

# ifdef OF_HAVE_BLOCKS
- (void)asyncWriteBuffer: (const void *)buffer
		  length: (size_t)length
		   block: (of_stream_async_write_block_t)block
{
	OFStream <OFReadyForWritingObserving> *stream =
	    (OFStream <OFReadyForWritingObserving> *)self;

	[OFRunLoop of_addAsyncWriteForStream: self
	[OFRunLoop of_addAsyncWriteForStream: stream
				      buffer: buffer
				      length: length
				       block: block];
}
# endif
#endif

Modified src/OFStreamSocket.h from [860d3abaef] to [b23fa26dc0].

21
22
23
24
25
26
27
28


29
30
31
32
33
34
35
21
22
23
24
25
26
27

28
29
30
31
32
33
34
35
36







-
+
+







OF_ASSUME_NONNULL_BEGIN

/*!
 * @class OFStreamSocket OFStreamSocket.h ObjFW/OFStreamSocket.h
 *
 * @brief A class which provides methods to create and use stream sockets.
 */
@interface OFStreamSocket: OFStream
@interface OFStreamSocket: OFStream <OFReadyForReadingObserving,
    OFReadyForWritingObserving>
{
	of_socket_t _socket;
	bool _atEndOfStream;
}

/*!
 * @brief Returns a new, autoreleased OFTCPSocket.

Modified src/OFTarArchive.h from [155fb2c98a] to [5395b52e6f].

11
12
13
14
15
16
17

18
19
20
21
22
23
24
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25







+







 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#import "OFObject.h"
#import "OFKernelEventObserver.h"
#import "OFTarArchiveEntry.h"

OF_ASSUME_NONNULL_BEGIN

@class OFString;
@class OFStream;

38
39
40
41
42
43
44



45
46


47
48
49
50
51
52
53
39
40
41
42
43
44
45
46
47
48
49

50
51
52
53
54
55
56
57
58







+
+
+

-
+
+







	OF_KINDOF(OFStream *) _Nullable _lastReturnedStream;
}

/*!
 * @brief A stream for reading the current entry
 *
 * @note This is only available in read mode.
 *
 * @note The returned stream only conforms to @ref OFReadyForReadingObserving if
 *	 the underlying stream does so, too.
 */
@property (readonly, nonatomic) OFStream *streamForReadingCurrentEntry;
@property (readonly, nonatomic)
    OFStream <OFReadyForReadingObserving> *streamForReadingCurrentEntry;

/*!
 * @brief Creates a new OFTarArchive object with the specified stream.
 *
 * @param stream A stream from which the tar archive will be read.
 *		 For append mode, this needs to be an OFSeekableStream.
 * @param mode The mode for the tar file. Valid modes are "r" for reading,
118
119
120
121
122
123
124



125
126
127
128
129
130
131
132
133
134

135

136
137
138
139
140
141
142
143
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143

144
145
146
147
148
149
150
151
152







+
+
+










+
-
+








 */
- (nullable OFTarArchiveEntry *)nextEntry;

/*!
 * @brief Returns a stream for writing the specified entry.
 *
 * @note This is only available in write and append mode.
 *
 * @note The returned stream only conforms to @ref OFReadyForWritingObserving if
 *	 the underlying stream does so, too.
 *
 * @warning Calling @ref nextEntry will invalidate all streams returned by
 *	    @ref streamForReadingCurrentEntry or
 *	    @ref streamForWritingEntry:! Reading from or writing to an
 *	    invalidated stream will throw an @ref OFReadFailedException or
 *	    @ref OFWriteFailedException!
 *
 * @param entry The entry for which a stream for writing should be returned
 * @return A stream for writing the specified entry
 */
- (OFStream <OFReadyForWritingObserving> *)
- (OFStream *)streamForWritingEntry: (OFTarArchiveEntry *)entry;
    streamForWritingEntry: (OFTarArchiveEntry *)entry;

/*!
 * @brief Closes the OFTarArchive.
 */
- (void)close;
@end

OF_ASSUME_NONNULL_END

Modified src/OFTarArchive.m from [72c8a07e42] to [247f54af17].

29
30
31
32
33
34
35
36

37
38
39
40
41
42
43
44
45
46
47
48
49

50
51
52

53
54
55
56
57
58
59
29
30
31
32
33
34
35

36
37
38
39
40
41
42
43
44
45
46
47
48

49
50
51

52
53
54
55
56
57
58
59







-
+












-
+


-
+







#import "OFInvalidArgumentException.h"
#import "OFInvalidFormatException.h"
#import "OFNotOpenException.h"
#import "OFOutOfRangeException.h"
#import "OFTruncatedDataException.h"
#import "OFWriteFailedException.h"

@interface OFTarArchive_FileReadStream: OFStream
@interface OFTarArchive_FileReadStream: OFStream <OFReadyForReadingObserving>
{
	OFTarArchiveEntry *_entry;
	OF_KINDOF(OFStream *) _stream;
	uint64_t _toRead;
	bool _atEndOfStream;
}

- (instancetype)initWithStream: (OFStream *)stream
			 entry: (OFTarArchiveEntry *)entry;
- (void)of_skip;
@end

@interface OFTarArchive_FileWriteStream: OFStream
@interface OFTarArchive_FileWriteStream: OFStream <OFReadyForWritingObserving>
{
	OFTarArchiveEntry *_entry;
	OFStream *_stream;
	OF_KINDOF(OFStream *) _stream;
	uint64_t _toWrite;
}

- (instancetype)initWithStream: (OFStream *)stream
			 entry: (OFTarArchiveEntry *)entry;
@end

199
200
201
202
203
204
205
206

207
208
209
210
211
212
213
214
215
216

217

218
219
220
221
222
223
224
199
200
201
202
203
204
205

206
207
208
209
210
211
212
213
214
215
216
217

218
219
220
221
222
223
224
225







-
+










+
-
+







	_lastReturnedStream = [[OFTarArchive_FileReadStream alloc]
	    initWithStream: _stream
		     entry: entry];

	return entry;
}

- (OFStream *)streamForReadingCurrentEntry
- (OFStream <OFReadyForReadingObserving> *)streamForReadingCurrentEntry
{
	if (_mode != OF_TAR_ARCHIVE_MODE_READ)
		@throw [OFInvalidArgumentException exception];

	if (_lastReturnedStream == nil)
		@throw [OFInvalidArgumentException exception];

	return [[_lastReturnedStream retain] autorelease];
}

- (OFStream <OFReadyForWritingObserving> *)
- (OFStream *)streamForWritingEntry: (OFTarArchiveEntry *)entry
    streamForWritingEntry: (OFTarArchiveEntry *)entry
{
	void *pool;

	if (_mode != OF_TAR_ARCHIVE_MODE_WRITE &&
	    _mode != OF_TAR_ARCHIVE_MODE_APPEND)
		@throw [OFInvalidArgumentException exception];