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
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;
		const uint8_t *ZIP64;
		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
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];
		_extraField =
		    [[stream readDataWithCount: extraFieldLength] 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, &ZIP64, &ZIP64Size);
		    OF_ZIP_ARCHIVE_ENTRY_EXTRA_FIELD_ZIP64, &ZIP64Size);

		if (ZIP64 != NULL) {
		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
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
 * @return The index at which the extra field content starts in the OFData, or
 *	   OF_NOT_FOUND
 */
extern void of_zip_archive_entry_extra_field_find(OFData *extraField,
    uint16_t tag, const uint8_t *_Nonnull *_Nonnull data, uint16_t *size);
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
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];
}

void
size_t
of_zip_archive_entry_extra_field_find(OFData *extraField, uint16_t tag,
    const uint8_t **data, uint16_t *size)
    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;
			return i + 4;
		}

		i += 4 + currentSize;
	}

	*data = NULL;
	*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
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;
		const uint8_t *ZIP64 = NULL;
		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
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] copy];
			extraField = [[[stream readDataWithCount:
			    extraFieldLength] mutableCopy] autorelease];
		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);
		ZIP64Index = of_zip_archive_entry_extra_field_find(_extraField,
		    OF_ZIP_ARCHIVE_ENTRY_EXTRA_FIELD_ZIP64, &ZIP64Size);

		if (ZIP64 != NULL) {
		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;