ObjFW  Check-in [827819d93c]

Overview
Comment:Rename all enums in OFGZIPStream.h
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | new-naming-convention
Files: files | file ages | folders
SHA3-256: 827819d93c42f00bbe70823f5dbdc0d2f496166300c649db73dd49f8c151b428
User & Date: js on 2021-04-17 16:57:32
Other Links: branch diff | manifest | tags
Context
2021-04-17
17:49
Rename JSON representation options check-in: 5ce8c7cca7 user: js tags: new-naming-convention
16:57
Rename all enums in OFGZIPStream.h check-in: 827819d93c user: js tags: new-naming-convention
16:44
of_scrypt_parameters_t -> OFScryptParameters check-in: d309195903 user: js tags: new-naming-convention
Changes

Modified src/OFGZIPStream.h from [34d6d06fc9] to [5d6697a8b2].

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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
88
89
90
91
92
93
94
95
96
97
#import "OFStream.h"
#import "OFDate.h"

@class OFInflateStream;

OF_ASSUME_NONNULL_BEGIN






















/**
 * @class OFGZIPStream OFGZIPStream.h ObjFW/OFGZIPStream.h
 *
 * @brief A class that handles GZIP compression and decompression transparently
 *	  for an underlying stream.
 */
OF_SUBCLASSING_RESTRICTED
@interface OFGZIPStream: OFStream
{
	OFStream *_stream;
	OFInflateStream *_Nullable _inflateStream;
	enum of_gzip_stream_state {
		OF_GZIP_STREAM_ID1,
		OF_GZIP_STREAM_ID2,
		OF_GZIP_STREAM_COMPRESSION_METHOD,
		OF_GZIP_STREAM_FLAGS,
		OF_GZIP_STREAM_MODIFICATION_TIME,
		OF_GZIP_STREAM_EXTRA_FLAGS,
		OF_GZIP_STREAM_OPERATING_SYSTEM,
		OF_GZIP_STREAM_EXTRA_LENGTH,
		OF_GZIP_STREAM_EXTRA,
		OF_GZIP_STREAM_NAME,
		OF_GZIP_STREAM_COMMENT,
		OF_GZIP_STREAM_HEADER_CRC16,
		OF_GZIP_STREAM_DATA,
		OF_GZIP_STREAM_CRC32,
		OF_GZIP_STREAM_UNCOMPRESSED_SIZE
	} _state;
	enum of_gzip_stream_flags {
		OF_GZIP_STREAM_FLAG_TEXT	 = 0x01,
		OF_GZIP_STREAM_FLAG_HEADER_CRC16 = 0x02,
		OF_GZIP_STREAM_FLAG_EXTRA	 = 0x04,
		OF_GZIP_STREAM_FLAG_NAME	 = 0x08,
		OF_GZIP_STREAM_FLAG_COMMENT	 = 0x10
	} _flags;
	uint8_t _extraFlags;
	enum of_gzip_stream_operating_system {
		OF_GZIP_STREAM_OPERATING_SYSTEM_FAT		=   0,
		OF_GZIP_STREAM_OPERATING_SYSTEM_AMIGA		=   1,
		OF_GZIP_STREAM_OPERATING_SYSTEM_VMS		=   2,
		OF_GZIP_STREAM_OPERATING_SYSTEM_UNIX		=   3,
		OF_GZIP_STREAM_OPERATING_SYSTEM_VM_CMS		=   4,
		OF_GZIP_STREAM_OPERATING_SYSTEM_ATARI_TOS	=   5,
		OF_GZIP_STREAM_OPERATING_SYSTEM_HPFS		=   6,
		OF_GZIP_STREAM_OPERATING_SYSTEM_MACINTOSH	=   7,
		OF_GZIP_STREAM_OPERATING_SYSTEM_Z_SYSTEM	=   8,
		OF_GZIP_STREAM_OPERATING_SYSTEM_CP_M		=   9,
		OF_GZIP_STREAM_OPERATING_SYSTEM_TOPS_20		=  10,
		OF_GZIP_STREAM_OPERATING_SYSTEM_NTFS		=  11,
		OF_GZIP_STREAM_OPERATING_SYSTEM_QDO		=  12,
		OF_GZIP_STREAM_OPERATING_SYSTEM_ACORN_RISC_OS	=  13,
		OF_GZIP_STREAM_OPERATING_SYSTEM_UNKNOWN		= 255
	} _operatingSystemMadeOn;
	size_t _bytesRead;
	uint8_t _buffer[4];
	OFDate *_Nullable _modificationDate;
	uint16_t _extraLength;
	uint32_t _CRC32, _uncompressedSize;
}

/**
 * @brief The operating system on which the data was compressed.
 *
 * This property is only guaranteed to be available once @ref atEndOfStream is
 * true.
 */
@property (readonly, nonatomic)
    enum of_gzip_stream_operating_system operatingSystemMadeOn;

/**
 * @brief The modification date of the original file.
 *
 * This property is only guaranteed to be available once @ref atEndOfStream is
 * true.
 */







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>











|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|


<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|














|







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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#import "OFStream.h"
#import "OFDate.h"

@class OFInflateStream;

OF_ASSUME_NONNULL_BEGIN

/**
 * @brief The operating system on which compressed the data.
 */
typedef enum OFGZIPStreamOperatingSystem {
	OFGZIPStreamOperatingSystemFAT	       =   0,
	OFGZIPStreamOperatingSystemAmiga       =   1,
	OFGZIPStreamOperatingSystemVMS	       =   2,
	OFGZIPStreamOperatingSystemUNIX	       =   3,
	OFGZIPStreamOperatingSystemVM_CMS      =   4,
	OFGZIPStreamOperatingSystemAtariTOS    =   5,
	OFGZIPStreamOperatingSystemHPFS	       =   6,
	OFGZIPStreamOperatingSystemMacintosh   =   7,
	OFGZIPStreamOperatingSystemZSystem     =   8,
	OFGZIPStreamOperatingSystemCP_M	       =   9,
	OFGZIPStreamOperatingSystemTOPS20      =  10,
	OFGZIPStreamOperatingSystemNTFS	       =  11,
	OFGZIPStreamOperatingSystemQDO	       =  12,
	OFGZIPStreamOperatingSystemAcornRISCOS =  13,
	OFGZIPStreamOperatingSystemUnknown     = 255
} OFGZIPStreamOperatingSystem;

/**
 * @class OFGZIPStream OFGZIPStream.h ObjFW/OFGZIPStream.h
 *
 * @brief A class that handles GZIP compression and decompression transparently
 *	  for an underlying stream.
 */
OF_SUBCLASSING_RESTRICTED
@interface OFGZIPStream: OFStream
{
	OFStream *_stream;
	OFInflateStream *_Nullable _inflateStream;
	enum {
		OFGZIPStreamStateID1,
		OFGZIPStreamStateID2,
		OFGZIPStreamStateCompressionMethod,
		OFGZIPStreamStateFlags,
		OFGZIPStreamStateModificationDate,
		OFGZIPStreamStateExtraFlags,
		OFGZIPStreamStateOperatingSystem,
		OFGZIPStreamStateExtraLength,
		OFGZIPStreamStateExtra,
		OFGZIPStreamStateName,
		OFGZIPStreamStateComment,
		OFGZIPStreamStateHeaderCRC16,
		OFGZIPStreamStateData,
		OFGZIPStreamStateCRC32,
		OFGZIPStreamStateUncompressedSize
	} _state;
	enum {
		OFGZIPStreamFlagText	    = 0x01,
		OFGZIPStreamFlagHeaderCRC16 = 0x02,
		OFGZIPStreamFlagExtra	    = 0x04,
		OFGZIPStreamFlagName	    = 0x08,
		OFGZIPStreamFlagComment	    = 0x10
	} _flags;
	uint8_t _extraFlags;
















	OFGZIPStreamOperatingSystem _operatingSystemMadeOn;
	size_t _bytesRead;
	uint8_t _buffer[4];
	OFDate *_Nullable _modificationDate;
	uint16_t _extraLength;
	uint32_t _CRC32, _uncompressedSize;
}

/**
 * @brief The operating system on which the data was compressed.
 *
 * This property is only guaranteed to be available once @ref atEndOfStream is
 * true.
 */
@property (readonly, nonatomic)
    OFGZIPStreamOperatingSystem operatingSystemMadeOn;

/**
 * @brief The modification date of the original file.
 *
 * This property is only guaranteed to be available once @ref atEndOfStream is
 * true.
 */

Modified src/OFGZIPStream.m from [5c08122bde] to [c75aceb9b4].

48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
	@try {
		if (![mode isEqual: @"r"])
			@throw [OFNotImplementedException
			    exceptionWithSelector: _cmd
					   object: nil];

		_stream = [stream retain];
		_operatingSystemMadeOn =
		    OF_GZIP_STREAM_OPERATING_SYSTEM_UNKNOWN;
		_CRC32 = ~0;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;







|
<







48
49
50
51
52
53
54
55

56
57
58
59
60
61
62
	@try {
		if (![mode isEqual: @"r"])
			@throw [OFNotImplementedException
			    exceptionWithSelector: _cmd
					   object: nil];

		_stream = [stream retain];
		_operatingSystemMadeOn = OFGZIPStreamOperatingSystemUnknown;

		_CRC32 = ~0;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
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
255
256
257
258
259
260
261
		@throw [OFNotOpenException exceptionWithObject: self];

	for (;;) {
		uint8_t byte;
		uint32_t CRC32, uncompressedSize;

		if (_stream.atEndOfStream) {
			if (_state != OF_GZIP_STREAM_ID1)
				@throw [OFTruncatedDataException exception];

			return 0;
		}

		switch (_state) {
		case OF_GZIP_STREAM_ID1:
		case OF_GZIP_STREAM_ID2:
		case OF_GZIP_STREAM_COMPRESSION_METHOD:
			if ([_stream readIntoBuffer: &byte length: 1] < 1)
				return 0;

			if ((_state == OF_GZIP_STREAM_ID1 && byte != 0x1F) ||
			    (_state == OF_GZIP_STREAM_ID2 && byte != 0x8B) ||
			    (_state == OF_GZIP_STREAM_COMPRESSION_METHOD &&
			    byte != 8))
				@throw [OFInvalidFormatException exception];

			_state++;
			break;
		case OF_GZIP_STREAM_FLAGS:
			if ([_stream readIntoBuffer: &byte length: 1] < 1)
				return 0;

			_flags = byte;
			_state++;
			break;
		case OF_GZIP_STREAM_MODIFICATION_TIME:
			_bytesRead += [_stream
			    readIntoBuffer: _buffer + _bytesRead
				    length: 4 - _bytesRead];

			if (_bytesRead < 4)
				return 0;

			[_modificationDate release];
			_modificationDate = nil;

			_modificationDate = [[OFDate alloc]
			    initWithTimeIntervalSince1970:
			    (_buffer[3] << 24) | (_buffer[2] << 16) |
			    (_buffer[1] << 8) | _buffer[0]];

			_bytesRead = 0;
			_state++;
			break;
		case OF_GZIP_STREAM_EXTRA_FLAGS:
			if ([_stream readIntoBuffer: &byte length: 1] < 1)
				return 0;

			_extraFlags = byte;
			_state++;
			break;
		case OF_GZIP_STREAM_OPERATING_SYSTEM:
			if ([_stream readIntoBuffer: &byte length: 1] < 1)
				return 0;

			_operatingSystemMadeOn = byte;
			_state++;
			break;
		case OF_GZIP_STREAM_EXTRA_LENGTH:
			if (!(_flags & OF_GZIP_STREAM_FLAG_EXTRA)) {
				_state += 2;
				break;
			}

			_bytesRead += [_stream
			    readIntoBuffer: _buffer + _bytesRead
				    length: 2 - _bytesRead];

			if (_bytesRead < 2)
				return 0;

			_extraLength = (_buffer[1] << 8) | _buffer[0];
			_bytesRead = 0;
			_state++;
			break;
		case OF_GZIP_STREAM_EXTRA:
			{
				char tmp[512];
				size_t toRead = _extraLength - _bytesRead;

				if (toRead > 512)
					toRead = 512;

				_bytesRead += [_stream readIntoBuffer: tmp
							       length: toRead];
			}

			if (_bytesRead < _extraLength)
				return 0;

			_bytesRead = 0;
			_state++;
			break;
		case OF_GZIP_STREAM_NAME:
			if (!(_flags & OF_GZIP_STREAM_FLAG_NAME)) {
				_state++;
				break;
			}

			do {
				if ([_stream readIntoBuffer: &byte
						     length: 1] < 1)
					return 0;
			} while (byte != 0);

			_state++;
			break;
		case OF_GZIP_STREAM_COMMENT:
			if (!(_flags & OF_GZIP_STREAM_FLAG_COMMENT)) {
				_state++;
				break;
			}

			do {
				if ([_stream readIntoBuffer: &byte
						     length: 1] < 1)
					return 0;
			} while (byte != 0);

			_state++;
			break;
		case OF_GZIP_STREAM_HEADER_CRC16:
			if (!(_flags & OF_GZIP_STREAM_FLAG_HEADER_CRC16)) {
				_state++;
				break;
			}

			_bytesRead += [_stream
			    readIntoBuffer: _buffer + _bytesRead
				    length: 2 - _bytesRead];

			if (_bytesRead < 2)
				return 0;

			/*
			 * Header CRC16 is not checked, as I could not find a
			 * single file in the wild that actually has a header
			 * CRC16 - and thus no file to test against.
			 */

			_bytesRead = 0;
			_state++;
			break;
		case OF_GZIP_STREAM_DATA:
			if (_inflateStream == nil)
				_inflateStream = [[OFInflateStream alloc]
				    initWithStream: _stream];

			if (!_inflateStream.atEndOfStream) {
				size_t bytesRead = [_inflateStream
				    readIntoBuffer: buffer
					    length: length];

				_CRC32 = of_crc32(_CRC32, buffer, bytesRead);
				_uncompressedSize += bytesRead;

				return bytesRead;
			}

			[_inflateStream release];
			_inflateStream = nil;

			_state++;
			break;
		case OF_GZIP_STREAM_CRC32:
			_bytesRead += [_stream readIntoBuffer: _buffer
						       length: 4 - _bytesRead];

			if (_bytesRead < 4)
				return 0;

			CRC32 = ((uint32_t)_buffer[3] << 24) |







|






|
|
|



|
|
|





|






|


















|






|






|
|















|

















|
|












|
|












|
|




















|




















|







79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
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
255
256
257
258
259
260
		@throw [OFNotOpenException exceptionWithObject: self];

	for (;;) {
		uint8_t byte;
		uint32_t CRC32, uncompressedSize;

		if (_stream.atEndOfStream) {
			if (_state != OFGZIPStreamStateID1)
				@throw [OFTruncatedDataException exception];

			return 0;
		}

		switch (_state) {
		case OFGZIPStreamStateID1:
		case OFGZIPStreamStateID2:
		case OFGZIPStreamStateCompressionMethod:
			if ([_stream readIntoBuffer: &byte length: 1] < 1)
				return 0;

			if ((_state == OFGZIPStreamStateID1 && byte != 0x1F) ||
			    (_state == OFGZIPStreamStateID2 && byte != 0x8B) ||
			    (_state == OFGZIPStreamStateCompressionMethod &&
			    byte != 8))
				@throw [OFInvalidFormatException exception];

			_state++;
			break;
		case OFGZIPStreamStateFlags:
			if ([_stream readIntoBuffer: &byte length: 1] < 1)
				return 0;

			_flags = byte;
			_state++;
			break;
		case OFGZIPStreamStateModificationDate:
			_bytesRead += [_stream
			    readIntoBuffer: _buffer + _bytesRead
				    length: 4 - _bytesRead];

			if (_bytesRead < 4)
				return 0;

			[_modificationDate release];
			_modificationDate = nil;

			_modificationDate = [[OFDate alloc]
			    initWithTimeIntervalSince1970:
			    (_buffer[3] << 24) | (_buffer[2] << 16) |
			    (_buffer[1] << 8) | _buffer[0]];

			_bytesRead = 0;
			_state++;
			break;
		case OFGZIPStreamStateExtraFlags:
			if ([_stream readIntoBuffer: &byte length: 1] < 1)
				return 0;

			_extraFlags = byte;
			_state++;
			break;
		case OFGZIPStreamStateOperatingSystem:
			if ([_stream readIntoBuffer: &byte length: 1] < 1)
				return 0;

			_operatingSystemMadeOn = byte;
			_state++;
			break;
		case OFGZIPStreamStateExtraLength:
			if (!(_flags & OFGZIPStreamFlagExtra)) {
				_state += 2;
				break;
			}

			_bytesRead += [_stream
			    readIntoBuffer: _buffer + _bytesRead
				    length: 2 - _bytesRead];

			if (_bytesRead < 2)
				return 0;

			_extraLength = (_buffer[1] << 8) | _buffer[0];
			_bytesRead = 0;
			_state++;
			break;
		case OFGZIPStreamStateExtra:
			{
				char tmp[512];
				size_t toRead = _extraLength - _bytesRead;

				if (toRead > 512)
					toRead = 512;

				_bytesRead += [_stream readIntoBuffer: tmp
							       length: toRead];
			}

			if (_bytesRead < _extraLength)
				return 0;

			_bytesRead = 0;
			_state++;
			break;
		case OFGZIPStreamStateName:
			if (!(_flags & OFGZIPStreamFlagName)) {
				_state++;
				break;
			}

			do {
				if ([_stream readIntoBuffer: &byte
						     length: 1] < 1)
					return 0;
			} while (byte != 0);

			_state++;
			break;
		case OFGZIPStreamStateComment:
			if (!(_flags & OFGZIPStreamFlagComment)) {
				_state++;
				break;
			}

			do {
				if ([_stream readIntoBuffer: &byte
						     length: 1] < 1)
					return 0;
			} while (byte != 0);

			_state++;
			break;
		case OFGZIPStreamStateHeaderCRC16:
			if (!(_flags & OFGZIPStreamFlagHeaderCRC16)) {
				_state++;
				break;
			}

			_bytesRead += [_stream
			    readIntoBuffer: _buffer + _bytesRead
				    length: 2 - _bytesRead];

			if (_bytesRead < 2)
				return 0;

			/*
			 * Header CRC16 is not checked, as I could not find a
			 * single file in the wild that actually has a header
			 * CRC16 - and thus no file to test against.
			 */

			_bytesRead = 0;
			_state++;
			break;
		case OFGZIPStreamStateData:
			if (_inflateStream == nil)
				_inflateStream = [[OFInflateStream alloc]
				    initWithStream: _stream];

			if (!_inflateStream.atEndOfStream) {
				size_t bytesRead = [_inflateStream
				    readIntoBuffer: buffer
					    length: length];

				_CRC32 = of_crc32(_CRC32, buffer, bytesRead);
				_uncompressedSize += bytesRead;

				return bytesRead;
			}

			[_inflateStream release];
			_inflateStream = nil;

			_state++;
			break;
		case OFGZIPStreamStateCRC32:
			_bytesRead += [_stream readIntoBuffer: _buffer
						       length: 4 - _bytesRead];

			if (_bytesRead < 4)
				return 0;

			CRC32 = ((uint32_t)_buffer[3] << 24) |
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
					       expectedChecksum: expected];
			}

			_bytesRead = 0;
			_CRC32 = ~0;
			_state++;
			break;
		case OF_GZIP_STREAM_UNCOMPRESSED_SIZE:
			_bytesRead += [_stream readIntoBuffer: _buffer
						       length: 4 - _bytesRead];

			uncompressedSize = ((uint32_t)_buffer[3] << 24) |
			    (_buffer[2] << 16) | (_buffer[1] << 8) | _buffer[0];
			if (_uncompressedSize != uncompressedSize) {
				OFString *actual = [OFString stringWithFormat:
				    @"%" PRIu32, _uncompressedSize];
				OFString *expected = [OFString stringWithFormat:
				    @"%" PRIu32, uncompressedSize];

				@throw [OFChecksumMismatchException
				    exceptionWithActualChecksum: actual
					       expectedChecksum: expected];
			}

			_bytesRead = 0;
			_uncompressedSize = 0;
			_state = OF_GZIP_STREAM_ID1;
			break;
		}
	}
}

- (bool)lowlevelIsAtEndOfStream
{
	if (_stream == nil)
		@throw [OFNotOpenException exceptionWithObject: self];

	return _stream.atEndOfStream;
}

- (bool)hasDataInReadBuffer
{
	if (_state == OF_GZIP_STREAM_DATA)
		return (super.hasDataInReadBuffer ||
		    _inflateStream.hasDataInReadBuffer);

	return (super.hasDataInReadBuffer || _stream.hasDataInReadBuffer);
}

- (void)close







|


















|















|







270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
					       expectedChecksum: expected];
			}

			_bytesRead = 0;
			_CRC32 = ~0;
			_state++;
			break;
		case OFGZIPStreamStateUncompressedSize:
			_bytesRead += [_stream readIntoBuffer: _buffer
						       length: 4 - _bytesRead];

			uncompressedSize = ((uint32_t)_buffer[3] << 24) |
			    (_buffer[2] << 16) | (_buffer[1] << 8) | _buffer[0];
			if (_uncompressedSize != uncompressedSize) {
				OFString *actual = [OFString stringWithFormat:
				    @"%" PRIu32, _uncompressedSize];
				OFString *expected = [OFString stringWithFormat:
				    @"%" PRIu32, uncompressedSize];

				@throw [OFChecksumMismatchException
				    exceptionWithActualChecksum: actual
					       expectedChecksum: expected];
			}

			_bytesRead = 0;
			_uncompressedSize = 0;
			_state = OFGZIPStreamStateID1;
			break;
		}
	}
}

- (bool)lowlevelIsAtEndOfStream
{
	if (_stream == nil)
		@throw [OFNotOpenException exceptionWithObject: self];

	return _stream.atEndOfStream;
}

- (bool)hasDataInReadBuffer
{
	if (_state == OFGZIPStreamStateData)
		return (super.hasDataInReadBuffer ||
		    _inflateStream.hasDataInReadBuffer);

	return (super.hasDataInReadBuffer || _stream.hasDataInReadBuffer);
}

- (void)close