ObjFW  Check-in [7d11e6e4e6]

Overview
Comment:OFZIPArchive: Add support for ZIP64.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 7d11e6e4e6ed0a8e1ef17b1feeb54805fabc8b9941dace203651a1105e9d2ea4
User & Date: js on 2013-11-06 11:36:38
Other Links: manifest | tags
Context
2013-11-06
20:29
Add OFDeflate64Stream. check-in: 7aef43d648 user: js tags: trunk
11:36
OFZIPArchive: Add support for ZIP64. check-in: 7d11e6e4e6 user: js tags: trunk
2013-10-30
17:06
OFZIPArchive: Return entries in a sorted array. check-in: 95f6035588 user: js tags: trunk
Changes

Modified src/OFZIPArchive.h from [71d41cfc2a] to [321e6d1503].

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/*!
 * @brief A class for accessing and manipulating ZIP files.
 */
@interface OFZIPArchive: OFObject
{
	OFFile *_file;
	OFString *_path;
	uint16_t _diskNumber, _centralDirectoryDisk;
	uint16_t _centralDirectoryEntriesInDisk, _centralDirectoryEntries;
	uint32_t _centralDirectorySize, _centralDirectoryOffset;
	OFString *_archiveComment;
	OFMutableArray *_entries;
	OFMutableDictionary *_pathToEntryMap;
}

#ifdef OF_HAVE_PROPERTIES
@property (readonly, copy) OFString *archiveComment;







|
|
|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/*!
 * @brief A class for accessing and manipulating ZIP files.
 */
@interface OFZIPArchive: OFObject
{
	OFFile *_file;
	OFString *_path;
	uint32_t _diskNumber, _centralDirectoryDisk;
	uint64_t _centralDirectoryEntriesInDisk, _centralDirectoryEntries;
	uint64_t _centralDirectorySize, _centralDirectoryOffset;
	OFString *_archiveComment;
	OFMutableArray *_entries;
	OFMutableDictionary *_pathToEntryMap;
}

#ifdef OF_HAVE_PROPERTIES
@property (readonly, copy) OFString *archiveComment;

Modified src/OFZIPArchive.m from [dd9b24a859] to [180a7ad71a].

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
 * 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.
 */

#include "config.h"

#include <stdio.h>

#import "OFZIPArchive.h"
#import "OFZIPArchiveEntry.h"
#import "OFZIPArchiveEntry+Private.h"
#import "OFDataArray.h"
#import "OFArray.h"
#import "OFDictionary.h"
#import "OFFile.h"
#import "OFDeflateStream.h"

#import "OFChecksumFailedException.h"
#import "OFInvalidArgumentException.h"
#import "OFInvalidFormatException.h"
#import "OFNotImplementedException.h"
#import "OFOpenFileFailedException.h"

#import "OFReadFailedException.h"
#import "OFUnsupportedVersionException.h"

#import "autorelease.h"
#import "macros.h"

#define CRC32_MAGIC 0xEDB88320

/*
 * FIXME: Current limitations:
 *  - Split archives are not supported.
 *  - Write support is missing.
 *  - The ZIP has to be a file on the local file system.
 *  - No support for ZIP64.
 *  - Encrypted files cannot be read.
 */

@interface OFZIPArchive (OF_PRIVATE_CATEGORY)
- (void)OF_readZIPInfo;
- (void)OF_readEntries;
@end

@interface OFZIPArchive_LocalFileHeader: OFObject
{
@public
	uint16_t _minVersion, _generalPurposeBitFlag, _compressionMethod;
	uint16_t _lastModifiedFileTime, _lastModifiedFileDate;

	uint32_t _CRC32, _compressedSize, _uncompressedSize;
	OFString *_fileName;
	OFDataArray *_extraField;
}

- initWithFile: (OFFile*)file;
- (bool)matchesEntry: (OFZIPArchiveEntry*)entry;
@end







<
<














>













<













>
|







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
 * 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.
 */

#include "config.h"



#import "OFZIPArchive.h"
#import "OFZIPArchiveEntry.h"
#import "OFZIPArchiveEntry+Private.h"
#import "OFDataArray.h"
#import "OFArray.h"
#import "OFDictionary.h"
#import "OFFile.h"
#import "OFDeflateStream.h"

#import "OFChecksumFailedException.h"
#import "OFInvalidArgumentException.h"
#import "OFInvalidFormatException.h"
#import "OFNotImplementedException.h"
#import "OFOpenFileFailedException.h"
#import "OFOutOfRangeException.h"
#import "OFReadFailedException.h"
#import "OFUnsupportedVersionException.h"

#import "autorelease.h"
#import "macros.h"

#define CRC32_MAGIC 0xEDB88320

/*
 * FIXME: Current limitations:
 *  - Split archives are not supported.
 *  - Write support is missing.
 *  - The ZIP has to be a file on the local file system.

 *  - Encrypted files cannot be read.
 */

@interface OFZIPArchive (OF_PRIVATE_CATEGORY)
- (void)OF_readZIPInfo;
- (void)OF_readEntries;
@end

@interface OFZIPArchive_LocalFileHeader: OFObject
{
@public
	uint16_t _minVersion, _generalPurposeBitFlag, _compressionMethod;
	uint16_t _lastModifiedFileTime, _lastModifiedFileDate;
	uint32_t _CRC32;
	uint64_t _compressedSize, _uncompressedSize;
	OFString *_fileName;
	OFDataArray *_extraField;
}

- initWithFile: (OFFile*)file;
- (bool)matchesEntry: (OFZIPArchiveEntry*)entry;
@end
79
80
81
82
83
84
85







































































86
87
88
89
90
91
92
	bool _atEndOfStream;
}

- initWithArchiveFile: (OFString*)path
	       offset: (off_t)offset
      localFileHeader: (OFZIPArchive_LocalFileHeader*)localFileHeader;
@end








































































static uint32_t
crc32(uint32_t crc, uint8_t *bytes, size_t length)
{
	size_t i;

	for (i = 0; i < length; i++) {







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







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
	bool _atEndOfStream;
}

- initWithArchiveFile: (OFString*)path
	       offset: (off_t)offset
      localFileHeader: (OFZIPArchive_LocalFileHeader*)localFileHeader;
@end

void
of_zip_archive_find_extra_field(OFDataArray *extraField, uint16_t tag,
    uint8_t **data, uint16_t *size)
{
	uint8_t *bytes;
	size_t i, count;

	bytes = [extraField items];
	count = [extraField count];

	for (i = 0; i < count;) {
		uint16_t currentTag, currentSize;

		if (i + 3 >= count)
			@throw [OFInvalidFormatException exception];

		currentTag = (bytes[i + 1] << 8) | bytes[i];
		currentSize = (bytes[i + 3] << 8) | bytes[i + 2];

		if (i + 3 + currentSize >= count)
			@throw [OFInvalidFormatException exception];

		if (currentTag == tag) {
			*data = bytes + i + 4;
			*size = currentSize;
			return;
		}

		i += 4 + currentSize;
	}

	*data = NULL;
	*size = 0;
}

uint32_t
of_zip_archive_read_field32(uint8_t **data, uint16_t *size)
{
	uint32_t field = 0;
	uint_fast8_t i;

	if (*size < 4)
		@throw [OFInvalidFormatException exception];

	for (i = 0; i < 4; i++)
		field |= (uint32_t)(*data)[i] << (i * 8);

	*data += 4;
	*size -= 4;

	return field;
}

uint64_t
of_zip_archive_read_field64(uint8_t **data, uint16_t *size)
{
	uint64_t field = 0;
	uint_fast8_t i;

	if (*size < 8)
		@throw [OFInvalidFormatException exception];

	for (i = 0; i < 8; i++)
		field |= (uint64_t)(*data)[i] << (i * 8);

	*data += 8;
	*size -= 8;

	return field;
}

static uint32_t
crc32(uint32_t crc, uint8_t *bytes, size_t length)
{
	size_t i;

	for (i = 0; i < length; i++) {
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
	[super dealloc];
}

- (void)OF_readZIPInfo
{
	void *pool = objc_autoreleasePoolPush();
	uint16_t commentLength;
	size_t offset = 0;
	bool valid = false;


	[_file seekToOffset: -22
		     whence: SEEK_END];

	while (offset++ < 65536) {
		if ([_file readLittleEndianInt32] == 0x06054B50) {
			valid = true;
			break;
		} else
			[_file seekToOffset: -5
				     whence: SEEK_CUR];
	}


	if (!valid)
		@throw [OFInvalidFormatException exception];

	_diskNumber = [_file readLittleEndianInt16],
	_centralDirectoryDisk = [_file readLittleEndianInt16];
	_centralDirectoryEntriesInDisk = [_file readLittleEndianInt16];
	_centralDirectoryEntries = [_file readLittleEndianInt16];
	_centralDirectorySize = [_file readLittleEndianInt32];
	_centralDirectoryOffset = [_file readLittleEndianInt32];

	commentLength = [_file readLittleEndianInt16];
	_archiveComment = [[_file
	    readStringWithLength: commentLength
			encoding: OF_STRING_ENCODING_CODEPAGE_437] copy];





















































	objc_autoreleasePoolPop(pool);
}

- (void)OF_readEntries
{
	void *pool = objc_autoreleasePoolPush();
	size_t i;




	[_file seekToOffset: _centralDirectoryOffset
		     whence: SEEK_SET];

	_entries = [[OFMutableArray alloc] init];
	_pathToEntryMap = [[OFMutableDictionary alloc] init];








|


>
|
|

<



<
<
<
|
>















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








>
>
>







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
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
320
321
322
	[super dealloc];
}

- (void)OF_readZIPInfo
{
	void *pool = objc_autoreleasePoolPush();
	uint16_t commentLength;
	off_t offset = -22;
	bool valid = false;

	do {
		[_file seekToOffset: offset
			     whence: SEEK_END];


		if ([_file readLittleEndianInt32] == 0x06054B50) {
			valid = true;
			break;



		}
	} while (--offset >= -65557);

	if (!valid)
		@throw [OFInvalidFormatException exception];

	_diskNumber = [_file readLittleEndianInt16],
	_centralDirectoryDisk = [_file readLittleEndianInt16];
	_centralDirectoryEntriesInDisk = [_file readLittleEndianInt16];
	_centralDirectoryEntries = [_file readLittleEndianInt16];
	_centralDirectorySize = [_file readLittleEndianInt32];
	_centralDirectoryOffset = [_file readLittleEndianInt32];

	commentLength = [_file readLittleEndianInt16];
	_archiveComment = [[_file
	    readStringWithLength: commentLength
			encoding: OF_STRING_ENCODING_CODEPAGE_437] copy];

	if (_diskNumber == 0xFFFF ||
	    _centralDirectoryDisk == 0xFFFF ||
	    _centralDirectoryEntriesInDisk == 0xFFFF ||
	    _centralDirectoryEntries == 0xFFFF ||
	    _centralDirectorySize == 0xFFFFFFFF ||
	    _centralDirectoryOffset == 0xFFFFFFFF) {
		uint64_t offset64, size;

		[_file seekToOffset: offset - 20
			     whence: SEEK_END];

		if ([_file readLittleEndianInt32] != 0x07064B50) {
			objc_autoreleasePoolPop(pool);
			return;
		}

		/*
		 * FIXME: Handle number of the disk containing ZIP64 end of
		 * central directory record.
		 */
		[_file readLittleEndianInt32];
		offset64 = [_file readLittleEndianInt64];

		if ((off_t)offset64 != offset64)
			@throw [OFOutOfRangeException exception];

		[_file seekToOffset: (off_t)offset64
			     whence: SEEK_SET];

		if ([_file readLittleEndianInt32] != 0x06064B50)
			@throw [OFInvalidFormatException exception];

		size = [_file readLittleEndianInt64];
		if (size < 44)
			@throw [OFInvalidFormatException exception];

		/* version made by */
		[_file readLittleEndianInt16];
		/* version needed to extract */
		[_file readLittleEndianInt16];

		_diskNumber = [_file readLittleEndianInt32];
		_centralDirectoryDisk = [_file readLittleEndianInt32];
		_centralDirectoryEntriesInDisk = [_file readLittleEndianInt64];
		_centralDirectoryEntries = [_file readLittleEndianInt64];
		_centralDirectorySize = [_file readLittleEndianInt64];
		_centralDirectoryOffset = [_file readLittleEndianInt64];

		if ((off_t)_centralDirectoryOffset != _centralDirectoryOffset)
			@throw [OFOutOfRangeException exception];
	}

	objc_autoreleasePoolPop(pool);
}

- (void)OF_readEntries
{
	void *pool = objc_autoreleasePoolPush();
	size_t i;

	if ((off_t)_centralDirectoryOffset != _centralDirectoryOffset)
		@throw [OFOutOfRangeException exception];

	[_file seekToOffset: _centralDirectoryOffset
		     whence: SEEK_SET];

	_entries = [[OFMutableArray alloc] init];
	_pathToEntryMap = [[OFMutableDictionary alloc] init];

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

- (OFStream*)streamForReadingFile: (OFString*)path
{
	OFStream *ret;
	void *pool = objc_autoreleasePoolPush();
	OFZIPArchiveEntry *entry = [_pathToEntryMap objectForKey: path];
	OFZIPArchive_LocalFileHeader *localFileHeader;


	if (entry == nil) {
		errno = ENOENT;
		@throw [OFOpenFileFailedException exceptionWithPath: path
							       mode: @"rb"];
	}





	[_file seekToOffset: [entry OF_localFileHeaderOffset]
		     whence: SEEK_SET];
	localFileHeader = [[[OFZIPArchive_LocalFileHeader alloc]
	    initWithFile: _file] autorelease];

	if (![localFileHeader matchesEntry: entry])
		@throw [OFInvalidFormatException exception];

	if ((localFileHeader->_minVersion & 0xFF) > 20) {
		OFString *version = [OFString stringWithFormat: @"%u.%u",
		    (localFileHeader->_minVersion & 0xFF) / 10,
		    (localFileHeader->_minVersion & 0xFF) % 10];

		@throw [OFUnsupportedVersionException
		    exceptionWithVersion: version];
	}







>







>
>
>
>
|







|







351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385

- (OFStream*)streamForReadingFile: (OFString*)path
{
	OFStream *ret;
	void *pool = objc_autoreleasePoolPush();
	OFZIPArchiveEntry *entry = [_pathToEntryMap objectForKey: path];
	OFZIPArchive_LocalFileHeader *localFileHeader;
	uint64_t offset;

	if (entry == nil) {
		errno = ENOENT;
		@throw [OFOpenFileFailedException exceptionWithPath: path
							       mode: @"rb"];
	}

	offset = [entry OF_localFileHeaderOffset];
	if ((off_t)offset != offset)
		@throw [OFOutOfRangeException exception];

	[_file seekToOffset: offset
		     whence: SEEK_SET];
	localFileHeader = [[[OFZIPArchive_LocalFileHeader alloc]
	    initWithFile: _file] autorelease];

	if (![localFileHeader matchesEntry: entry])
		@throw [OFInvalidFormatException exception];

	if ((localFileHeader->_minVersion & 0xFF) > 45) {
		OFString *version = [OFString stringWithFormat: @"%u.%u",
		    (localFileHeader->_minVersion & 0xFF) / 10,
		    (localFileHeader->_minVersion & 0xFF) % 10];

		@throw [OFUnsupportedVersionException
		    exceptionWithVersion: version];
	}
272
273
274
275
276
277
278


279
280
281
282
283
284
285
- initWithFile: (OFFile*)file
{
	self = [super init];

	@try {
		uint16_t fileNameLength, extraFieldLength;
		of_string_encoding_t encoding;



		if ([file readLittleEndianInt32] != 0x04034B50)
			@throw [OFInvalidFormatException exception];

		_minVersion = [file readLittleEndianInt16];
		_generalPurposeBitFlag = [file readLittleEndianInt16];
		_compressionMethod = [file readLittleEndianInt16];







>
>







400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
- initWithFile: (OFFile*)file
{
	self = [super init];

	@try {
		uint16_t fileNameLength, extraFieldLength;
		of_string_encoding_t encoding;
		uint8_t *ZIP64;
		uint16_t ZIP64Size;

		if ([file readLittleEndianInt32] != 0x04034B50)
			@throw [OFInvalidFormatException exception];

		_minVersion = [file readLittleEndianInt16];
		_generalPurposeBitFlag = [file readLittleEndianInt16];
		_compressionMethod = [file readLittleEndianInt16];
294
295
296
297
298
299
300















301
302
303
304
305
306
307
		    ? OF_STRING_ENCODING_UTF_8
		    : OF_STRING_ENCODING_CODEPAGE_437);

		_fileName = [[file readStringWithLength: fileNameLength
					       encoding: encoding] copy];
		_extraField = [[file
		    readDataArrayWithCount: extraFieldLength] retain];















	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}







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







424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
		    ? OF_STRING_ENCODING_UTF_8
		    : OF_STRING_ENCODING_CODEPAGE_437);

		_fileName = [[file readStringWithLength: fileNameLength
					       encoding: encoding] copy];
		_extraField = [[file
		    readDataArrayWithCount: extraFieldLength] retain];

		of_zip_archive_find_extra_field(_extraField, 0x0001,
		    &ZIP64, &ZIP64Size);

		if (ZIP64 != NULL) {
			if (_uncompressedSize == 0xFFFFFFFF)
				_uncompressedSize = of_zip_archive_read_field64(
				    &ZIP64, &ZIP64Size);
			if (_compressedSize == 0xFFFFFFFF)
				_compressedSize = of_zip_archive_read_field64(
				    &ZIP64, &ZIP64Size);

			if (ZIP64Size > 0)
				@throw [OFInvalidFormatException exception];
		}
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
408
409
410
411
412
413
414





415
416
417
418
419
420
421
			CRC32 = [_file readLittleEndianInt32];
			if (CRC32 == 0x08074B50)
				CRC32 = [_file readLittleEndianInt32];

			if (~_CRC32 != CRC32)
				@throw [OFChecksumFailedException exception];






			return 0;
		}

		ret = [_stream readIntoBuffer: buffer
				       length: length];
	} else {
		if (_size == 0) {







>
>
>
>
>







553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
			CRC32 = [_file readLittleEndianInt32];
			if (CRC32 == 0x08074B50)
				CRC32 = [_file readLittleEndianInt32];

			if (~_CRC32 != CRC32)
				@throw [OFChecksumFailedException exception];

			/*
			 * FIXME: Check (un)compressed length!
			 * (Note: Both are 64 bit if the entry uses ZIP64!)
			 */

			return 0;
		}

		ret = [_stream readIntoBuffer: buffer
				       length: length];
	} else {
		if (_size == 0) {

Modified src/OFZIPArchiveEntry+Private.h from [1b066367d9] to [0d465e1238].

26
27
28
29
30
31
32
33
34
- (uint16_t)OF_compressionMethod;
- (uint16_t)OF_lastModifiedFileTime;
- (uint16_t)OF_lastModifiedFileDate;
- (OFDataArray*)OF_extraFieldNoCopy;
- (uint16_t)OF_startDiskNumber;
- (uint16_t)OF_internalAttributes;
- (uint32_t)OF_externalAttributes;
- (uint32_t)OF_localFileHeaderOffset;
@end







|

26
27
28
29
30
31
32
33
34
- (uint16_t)OF_compressionMethod;
- (uint16_t)OF_lastModifiedFileTime;
- (uint16_t)OF_lastModifiedFileDate;
- (OFDataArray*)OF_extraFieldNoCopy;
- (uint16_t)OF_startDiskNumber;
- (uint16_t)OF_internalAttributes;
- (uint32_t)OF_externalAttributes;
- (uint64_t)OF_localFileHeaderOffset;
@end

Modified src/OFZIPArchiveEntry.h from [6ec34bda0a] to [0760c88839].

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
 *	  archive.
 */
@interface OFZIPArchiveEntry: OFObject
{
	uint16_t _madeWithVersion, _minVersion, _generalPurposeBitFlag;
	uint16_t _compressionMethod, _lastModifiedFileTime;
	uint16_t _lastModifiedFileDate;

	uint32_t _CRC32, _compressedSize, _uncompressedSize;
	OFString *_fileName;
	OFDataArray *_extraField;
	OFString *_fileComment;

	uint16_t _startDiskNumber, _internalAttributes;
	uint32_t _externalAttributes, _localFileHeaderOffset;

}

#ifdef OF_HAVE_PROPERTIES
@property (readonly, copy) OFString *fileName, *fileComment;
@property (readonly) off_t compressedSize, uncompressedSize;
@property (readonly, retain) OFDate *modificationDate;
@property (readonly) uint32_t CRC32;
@property (readonly, copy) OFDataArray *extraField;
#endif

/*!
 * @brief Returns the file name of the entry.







>
|



>
|
|
>




|







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
 *	  archive.
 */
@interface OFZIPArchiveEntry: OFObject
{
	uint16_t _madeWithVersion, _minVersion, _generalPurposeBitFlag;
	uint16_t _compressionMethod, _lastModifiedFileTime;
	uint16_t _lastModifiedFileDate;
	uint32_t _CRC32;
	uint64_t _compressedSize, _uncompressedSize;
	OFString *_fileName;
	OFDataArray *_extraField;
	OFString *_fileComment;
	uint32_t _startDiskNumber;
	uint16_t _internalAttributes;
	uint32_t _externalAttributes;
	uint64_t _localFileHeaderOffset;
}

#ifdef OF_HAVE_PROPERTIES
@property (readonly, copy) OFString *fileName, *fileComment;
@property (readonly) uint64_t compressedSize, uncompressedSize;
@property (readonly, retain) OFDate *modificationDate;
@property (readonly) uint32_t CRC32;
@property (readonly, copy) OFDataArray *extraField;
#endif

/*!
 * @brief Returns the file name of the entry.
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
- (OFString*)fileComment;

/*!
 * @brief Returns the compressed size of the entry's file.
 *
 * @return The compressed size of the entry's file
 */
- (off_t)compressedSize;

/*!
 * @brief Returns the uncompressed size of the entry's file.
 *
 * @return The uncompressed size of the entry's file
 */
- (off_t)uncompressedSize;

/*!
 * @brief Returns the last modification date of the entry's file.
 *
 * @return The last modification date of the entry's file
 */
- (OFDate*)modificationDate;







|






|







66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
- (OFString*)fileComment;

/*!
 * @brief Returns the compressed size of the entry's file.
 *
 * @return The compressed size of the entry's file
 */
- (uint64_t)compressedSize;

/*!
 * @brief Returns the uncompressed size of the entry's file.
 *
 * @return The uncompressed size of the entry's file
 */
- (uint64_t)uncompressedSize;

/*!
 * @brief Returns the last modification date of the entry's file.
 *
 * @return The last modification date of the entry's file
 */
- (OFDate*)modificationDate;

Modified src/OFZIPArchiveEntry.m from [8411857262] to [fded94162f].

25
26
27
28
29
30
31





32
33
34
35
36
37
38
39
40


41
42
43
44
45
46
47

#import "autorelease.h"
#import "macros.h"

#import "OFInvalidArgumentException.h"
#import "OFInvalidFormatException.h"






@implementation OFZIPArchiveEntry
- (instancetype)OF_initWithFile: (OFFile*)file
{
	self = [super init];

	@try {
		void *pool = objc_autoreleasePoolPush();
		uint16_t fileNameLength, extraFieldLength, fileCommentLength;
		of_string_encoding_t encoding;



		if ([file readLittleEndianInt32] != 0x02014B50)
			@throw [OFInvalidFormatException exception];

		_madeWithVersion = [file readLittleEndianInt16];
		_minVersion = [file readLittleEndianInt16];
		_generalPurposeBitFlag = [file readLittleEndianInt16];







>
>
>
>
>









>
>







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

#import "autorelease.h"
#import "macros.h"

#import "OFInvalidArgumentException.h"
#import "OFInvalidFormatException.h"

extern void of_zip_archive_find_extra_field(OFDataArray*, uint16_t, uint8_t**,
    uint16_t*);
extern uint32_t of_zip_archive_read_field32(uint8_t**, uint16_t*);
extern uint64_t of_zip_archive_read_field64(uint8_t**, uint16_t*);

@implementation OFZIPArchiveEntry
- (instancetype)OF_initWithFile: (OFFile*)file
{
	self = [super init];

	@try {
		void *pool = objc_autoreleasePoolPush();
		uint16_t fileNameLength, extraFieldLength, fileCommentLength;
		of_string_encoding_t encoding;
		uint8_t *ZIP64 = NULL;
		uint16_t ZIP64Size;

		if ([file readLittleEndianInt32] != 0x02014B50)
			@throw [OFInvalidFormatException exception];

		_madeWithVersion = [file readLittleEndianInt16];
		_minVersion = [file readLittleEndianInt16];
		_generalPurposeBitFlag = [file readLittleEndianInt16];
65
66
67
68
69
70
71






















72
73
74
75
76
77
78

		_fileName = [[file readStringWithLength: fileNameLength
					       encoding: encoding] copy];
		_extraField = [[file
		    readDataArrayWithCount: extraFieldLength] retain];
		_fileComment = [[file readStringWithLength: fileCommentLength
						  encoding: encoding] copy];























		objc_autoreleasePoolPop(pool);
	} @catch (id e) {
		[self release];
		@throw e;
	}








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







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

		_fileName = [[file readStringWithLength: fileNameLength
					       encoding: encoding] copy];
		_extraField = [[file
		    readDataArrayWithCount: extraFieldLength] retain];
		_fileComment = [[file readStringWithLength: fileCommentLength
						  encoding: encoding] copy];

		of_zip_archive_find_extra_field(_extraField, 0x0001,
		    &ZIP64, &ZIP64Size);

		if (ZIP64 != NULL) {
			if (_uncompressedSize == 0xFFFFFFFF)
				_uncompressedSize = of_zip_archive_read_field64(
				    &ZIP64, &ZIP64Size);
			if (_compressedSize == 0xFFFFFFFF)
				_compressedSize = of_zip_archive_read_field64(
				    &ZIP64, &ZIP64Size);
			if (_localFileHeaderOffset == 0xFFFFFFFF)
				_localFileHeaderOffset =
				    of_zip_archive_read_field64(&ZIP64,
				    &ZIP64Size);
			if (_startDiskNumber == 0xFFFF)
				_startDiskNumber = of_zip_archive_read_field32(
				    &ZIP64, &ZIP64Size);

			if (ZIP64Size > 0)
				@throw [OFInvalidFormatException exception];
		}

		objc_autoreleasePoolPop(pool);
	} @catch (id e) {
		[self release];
		@throw e;
	}

94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
}

- (OFString*)fileComment
{
	OF_GETTER(_fileComment, true)
}

- (off_t)compressedSize
{
	return _compressedSize;
}

- (off_t)uncompressedSize
{
	return _uncompressedSize;
}

- (OFDate*)modificationDate
{
	void *pool = objc_autoreleasePoolPush();







|




|







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

- (OFString*)fileComment
{
	OF_GETTER(_fileComment, true)
}

- (uint64_t)compressedSize
{
	return _compressedSize;
}

- (uint64_t)uncompressedSize
{
	return _uncompressedSize;
}

- (OFDate*)modificationDate
{
	void *pool = objc_autoreleasePoolPush();
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
}

- (uint32_t)OF_externalAttributes
{
	return _externalAttributes;
}

- (uint32_t)OF_localFileHeaderOffset
{
	return _localFileHeaderOffset;
}

- (of_comparison_result_t)compare: (id)object
{
	OFZIPArchiveEntry *entry;







|







243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
}

- (uint32_t)OF_externalAttributes
{
	return _externalAttributes;
}

- (uint64_t)OF_localFileHeaderOffset
{
	return _localFileHeaderOffset;
}

- (of_comparison_result_t)compare: (id)object
{
	OFZIPArchiveEntry *entry;