ObjFW  Diff

Differences From Artifact [4ed53f9a5c]:

To Artifact [072d5c3fec]:


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
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
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
262
263
264
265
266
267
268
269
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#import "OFGZIPStream.h"
#import "OFInflateStream.h"
#import "OFDate.h"

#import "crc32.h"

#import "OFChecksumMismatchException.h"
#import "OFInvalidFormatException.h"
#import "OFNotImplementedException.h"
#import "OFNotOpenException.h"
#import "OFTruncatedDataException.h"

@implementation OFGZIPStream
@synthesize operatingSystemMadeOn = _operatingSystemMadeOn;
@synthesize modificationDate = _modificationDate;

+ (instancetype)streamWithStream: (OFStream *)stream
			    mode: (OFString *)mode
{
	return [[[self alloc] initWithStream: stream
					mode: mode] autorelease];
}

- (instancetype)init
{
	OF_INVALID_INIT_METHOD
}

- (instancetype)initWithStream: (OFStream *)stream
			  mode: (OFString *)mode
{
	self = [super init];

	@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;
}

- (void)dealloc
{
	if (_stream != nil)
		[self close];

	[_inflateStream release];
	[_modificationDate release];

	[super dealloc];
}

- (size_t)lowlevelReadIntoBuffer: (void *)buffer
			  length: (size_t)length
{
	if (_stream == nil)
		@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) |







|

<
|











|
<

|
<







|
<










|
<




















|
<









|






|
|
|
|
<


|
|
|





|
|
<





|


















|
|
<





|
|
<





|
|















|

















|
|












|
|












|
|




















|









|










|







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
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
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
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#import "OFGZIPStream.h"
#import "OFCRC32.h"
#import "OFDate.h"

#import "OFInflateStream.h"

#import "OFChecksumMismatchException.h"
#import "OFInvalidFormatException.h"
#import "OFNotImplementedException.h"
#import "OFNotOpenException.h"
#import "OFTruncatedDataException.h"

@implementation OFGZIPStream
@synthesize operatingSystemMadeOn = _operatingSystemMadeOn;
@synthesize modificationDate = _modificationDate;

+ (instancetype)streamWithStream: (OFStream *)stream mode: (OFString *)mode

{
	return [[[self alloc] initWithStream: stream mode: mode] autorelease];

}

- (instancetype)init
{
	OF_INVALID_INIT_METHOD
}

- (instancetype)initWithStream: (OFStream *)stream mode: (OFString *)mode

{
	self = [super init];

	@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;
}

- (void)dealloc
{
	if (_stream != nil)
		[self close];

	[_inflateStream release];
	[_modificationDate release];

	[super dealloc];
}

- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length

{
	if (_stream == nil)
		@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 = OFCRC32(_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) |
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
321
322
323
324
325
326
327
328
					       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







|


















|















|







269
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
					       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