ObjFW  Check-in [8ebf6ed443]

Overview
Comment:OFZIPArchive(Entry): Remove ZIP64 from extra field

Treating the ZIP64 extra field as part of the entry itself makes things
a lot easier when (re)writing the central directory.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 8ebf6ed4436f2dff9eeec2345a8488352857ad9dec84859e5d60dd6ca7ddce15
User & Date: js on 2017-08-13 22:34:33
Other Links: manifest | tags
Context
2017-08-13
22:38
Fix -[OFData description] check-in: 484c7987d2 user: js tags: trunk
22:34
OFZIPArchive(Entry): Remove ZIP64 from extra field check-in: 8ebf6ed443 user: js tags: trunk
13:50
OFArray: Fix MessagePack encoding check-in: ada612eac9 user: js tags: trunk
Changes

Modified src/OFZIPArchive.m from [7073d8b5b3] to [c1fa8a1f8d].

607
608
609
610
611
612
613


614
615
616
617
618
619
620
621
622
623

@implementation OFZIPArchive_LocalFileHeader
- initWithStream: (OFStream *)stream
{
	self = [super init];

	@try {


		uint16_t fileNameLength, extraFieldLength;
		of_string_encoding_t encoding;
		const uint8_t *ZIP64;
		uint16_t ZIP64Size;

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

		_minVersionNeeded = [stream readLittleEndianInt16];
		_generalPurposeBitFlag = [stream readLittleEndianInt16];







>
>


|







607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625

@implementation OFZIPArchive_LocalFileHeader
- initWithStream: (OFStream *)stream
{
	self = [super init];

	@try {
		void *pool = objc_autoreleasePoolPush();
		OFMutableData *extraField = nil;
		uint16_t fileNameLength, extraFieldLength;
		of_string_encoding_t encoding;
		size_t ZIP64Index;
		uint16_t ZIP64Size;

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

		_minVersionNeeded = [stream readLittleEndianInt16];
		_generalPurposeBitFlag = [stream readLittleEndianInt16];
631
632
633
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
		extraFieldLength = [stream readLittleEndianInt16];
		encoding = (_generalPurposeBitFlag & (1 << 11)
		    ? OF_STRING_ENCODING_UTF_8
		    : OF_STRING_ENCODING_CODEPAGE_437);

		_fileName = [[stream readStringWithLength: fileNameLength
						 encoding: encoding] copy];
		_extraField =
		    [[stream readDataWithCount: extraFieldLength] copy];


		of_zip_archive_entry_extra_field_find(_extraField,
		    OF_ZIP_ARCHIVE_ENTRY_EXTRA_FIELD_ZIP64, &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;
}







|
|
>


|

|
>
>
>









|
>
>
>
>
>
>
>
>







633
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
		extraFieldLength = [stream readLittleEndianInt16];
		encoding = (_generalPurposeBitFlag & (1 << 11)
		    ? OF_STRING_ENCODING_UTF_8
		    : OF_STRING_ENCODING_CODEPAGE_437);

		_fileName = [[stream readStringWithLength: fileNameLength
						 encoding: encoding] copy];
		if (extraFieldLength > 0)
			extraField = [[[stream readDataWithCount:
			    extraFieldLength] mutableCopy] autorelease];

		of_zip_archive_entry_extra_field_find(_extraField,
		    OF_ZIP_ARCHIVE_ENTRY_EXTRA_FIELD_ZIP64, &ZIP64Size);

		if (ZIP64Index != OF_NOT_FOUND) {
			const uint8_t *ZIP64 =
			    [extraField itemAtIndex: ZIP64Index];

			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];

			[extraField removeItemsInRange:
			    of_range(ZIP64Index - 4, ZIP64Size + 4)];
		}

		[extraField makeImmutable];
		_extraField = [extraField copy];

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

	return self;
}

Modified src/OFZIPArchiveEntry.h from [3a97414732] to [ce0ccead6f].

224
225
226
227
228
229
230
231
232
233


234
235
236
237
238
239
240
241
242
243
/*!
 * @brief Gets a pointer to and the size of the extensible data field with the
 *	  specified tag.
 *
 * @param extraField The extra field to search for an extensible data field with
 *		     the specified tag
 * @param tag The tag to look for
 * @param data A pointer to a pointer that should be set to the start of the
 *	       extra field with the specified tag
 * @param size A pointer to an uint16_t that should be set to the size


 */
extern void of_zip_archive_entry_extra_field_find(OFData *extraField,
    uint16_t tag, const uint8_t *_Nonnull *_Nonnull data, uint16_t *size);
#ifdef __cplusplus
}
#endif

OF_ASSUME_NONNULL_END

#import "OFMutableZIPArchiveEntry.h"







<
<

>
>

|
|







224
225
226
227
228
229
230


231
232
233
234
235
236
237
238
239
240
241
242
243
/*!
 * @brief Gets a pointer to and the size of the extensible data field with the
 *	  specified tag.
 *
 * @param extraField The extra field to search for an extensible data field with
 *		     the specified tag
 * @param tag The tag to look for


 * @param size A pointer to an uint16_t that should be set to the size
 * @return The index at which the extra field content starts in the OFData, or
 *	   OF_NOT_FOUND
 */
extern size_t of_zip_archive_entry_extra_field_find(OFData *extraField,
    uint16_t tag, uint16_t *size);
#ifdef __cplusplus
}
#endif

OF_ASSUME_NONNULL_END

#import "OFMutableZIPArchiveEntry.h"

Modified src/OFZIPArchiveEntry.m from [728d6fb127] to [1983c233dd].

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
		    (version & 0xFF) / 10, (version & 0xFF) % 10, attrCompat];
	else
		return [OFString stringWithFormat:
		    @"%u.%u, unknown %02X",
		    (version % 0xFF) / 10, (version & 0xFF) % 10, version >> 8];
}

void
of_zip_archive_entry_extra_field_find(OFData *extraField, uint16_t tag,
    const uint8_t **data, uint16_t *size)
{
	const uint8_t *bytes = [extraField items];
	size_t count = [extraField count];

	for (size_t 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;

}

@implementation OFZIPArchiveEntry
+ (instancetype)entryWithFileName: (OFString *)fileName
{
	return [[[self alloc] initWithFileName: fileName] autorelease];
}







|

|

















<

|





<

>







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
		    (version & 0xFF) / 10, (version & 0xFF) % 10, attrCompat];
	else
		return [OFString stringWithFormat:
		    @"%u.%u, unknown %02X",
		    (version % 0xFF) / 10, (version & 0xFF) % 10, version >> 8];
}

size_t
of_zip_archive_entry_extra_field_find(OFData *extraField, uint16_t tag,
    uint16_t *size)
{
	const uint8_t *bytes = [extraField items];
	size_t count = [extraField count];

	for (size_t 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) {

			*size = currentSize;
			return i + 4;
		}

		i += 4 + currentSize;
	}


	*size = 0;
	return OF_NOT_FOUND;
}

@implementation OFZIPArchiveEntry
+ (instancetype)entryWithFileName: (OFString *)fileName
{
	return [[[self alloc] initWithFileName: fileName] autorelease];
}
176
177
178
179
180
181
182

183
184
185
186
187
188
189
190
191
192

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

	@try {
		void *pool = objc_autoreleasePoolPush();

		uint16_t fileNameLength, extraFieldLength, fileCommentLength;
		of_string_encoding_t encoding;
		const uint8_t *ZIP64 = NULL;
		uint16_t ZIP64Size;

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

		_versionMadeBy = [stream readLittleEndianInt16];
		_minVersionNeeded = [stream readLittleEndianInt16];







>


|







175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192

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

	@try {
		void *pool = objc_autoreleasePoolPush();
		OFMutableData *extraField = nil;
		uint16_t fileNameLength, extraFieldLength, fileCommentLength;
		of_string_encoding_t encoding;
		size_t ZIP64Index;
		uint16_t ZIP64Size;

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

		_versionMadeBy = [stream readLittleEndianInt16];
		_minVersionNeeded = [stream readLittleEndianInt16];
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
		encoding = (_generalPurposeBitFlag & (1 << 11)
		    ? OF_STRING_ENCODING_UTF_8
		    : OF_STRING_ENCODING_CODEPAGE_437);

		_fileName = [[stream readStringWithLength: fileNameLength
						 encoding: encoding] copy];
		if (extraFieldLength > 0)
			_extraField =
			    [[stream readDataWithCount: extraFieldLength] copy];
		if (fileCommentLength > 0)
			_fileComment = [[stream
			    readStringWithLength: fileCommentLength
					encoding: encoding] copy];

		of_zip_archive_entry_extra_field_find(_extraField,
		    OF_ZIP_ARCHIVE_ENTRY_EXTRA_FIELD_ZIP64, &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 || _localFileHeaderOffset < 0)
				@throw [OFInvalidFormatException exception];
		}







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

	return self;







|
|





|
|

|
>
>
>
















|
>
>
|
>
>
>
>







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
		encoding = (_generalPurposeBitFlag & (1 << 11)
		    ? OF_STRING_ENCODING_UTF_8
		    : OF_STRING_ENCODING_CODEPAGE_437);

		_fileName = [[stream readStringWithLength: fileNameLength
						 encoding: encoding] copy];
		if (extraFieldLength > 0)
			extraField = [[[stream readDataWithCount:
			    extraFieldLength] mutableCopy] autorelease];
		if (fileCommentLength > 0)
			_fileComment = [[stream
			    readStringWithLength: fileCommentLength
					encoding: encoding] copy];

		ZIP64Index = of_zip_archive_entry_extra_field_find(_extraField,
		    OF_ZIP_ARCHIVE_ENTRY_EXTRA_FIELD_ZIP64, &ZIP64Size);

		if (ZIP64Index != OF_NOT_FOUND) {
			const uint8_t *ZIP64 =
			    [_extraField itemAtIndex: ZIP64Index];

			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 || _localFileHeaderOffset < 0)
				@throw [OFInvalidFormatException exception];

			[extraField removeItemsInRange:
			    of_range(ZIP64Index - 4, ZIP64Size + 4)];
		}

		[extraField makeImmutable];
		_extraField = [extraField copy];

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

	return self;