@@ -33,6 +33,7 @@ static bool read_helper(ReadonlyBytes buffer, T* self)
3333}
3434
3535// NOTE: Due to the format of zip files compression is streamed and decompression is random access.
36+ // Zip format specification: https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
3637
3738static constexpr auto signature_length = 4 ;
3839
@@ -109,10 +110,16 @@ union ZipGeneralPurposeFlags {
109110};
110111static_assert (sizeof (ZipGeneralPurposeFlags) == sizeof (u16 ));
111112
113+ enum class ZipMadeBy : u8 {
114+ MSDOS = 0 ,
115+ Unix = 3 ,
116+ };
117+
112118struct [[gnu::packed]] CentralDirectoryRecord {
113119 static constexpr Array<u8 , signature_length> signature = { 0x50 , 0x4b , 0x01 , 0x02 }; // 'PK\x01\x02'
114120
115- u16 made_by_version;
121+ u8 supported_version; // lower byte of version made by
122+ ZipMadeBy made_by; // upper byte of version made by
116123 u16 minimum_version;
117124 ZipGeneralPurposeFlags general_purpose_flags;
118125 ZipCompressionMethod compression_method;
@@ -126,7 +133,8 @@ struct [[gnu::packed]] CentralDirectoryRecord {
126133 u16 comment_length;
127134 u16 start_disk;
128135 u16 internal_attributes;
129- u32 external_attributes;
136+ u16 msdos_attributes; // lower bytes of external file attributes
137+ u16 external_attributes; // upper bytes of external file attributes
130138 u32 local_file_header_offset;
131139 u8 const * name;
132140 u8 const * extra_data;
@@ -152,7 +160,8 @@ struct [[gnu::packed]] CentralDirectoryRecord {
152160 };
153161
154162 TRY (stream.write_until_depleted (signature));
155- TRY (write_value (made_by_version));
163+ TRY (write_value (supported_version));
164+ TRY (write_value (made_by));
156165 TRY (write_value (minimum_version));
157166 TRY (write_value (general_purpose_flags.flags ));
158167 TRY (write_value (compression_method));
@@ -166,6 +175,7 @@ struct [[gnu::packed]] CentralDirectoryRecord {
166175 TRY (write_value (comment_length));
167176 TRY (write_value (start_disk));
168177 TRY (write_value (internal_attributes));
178+ TRY (write_value (msdos_attributes));
169179 TRY (write_value (external_attributes));
170180 TRY (write_value (local_file_header_offset));
171181 if (name_length > 0 )
@@ -182,7 +192,7 @@ struct [[gnu::packed]] CentralDirectoryRecord {
182192 return signature.size () + (sizeof (CentralDirectoryRecord) - (sizeof (u8 *) * 3 )) + name_length + extra_data_length + comment_length;
183193 }
184194};
185- static constexpr u32 zip_directory_external_attribute = 1 << 4 ;
195+ static constexpr u16 zip_directory_msdos_attribute = 1 << 4 ;
186196
187197struct [[gnu::packed]] LocalFileHeader {
188198 static constexpr Array<u8 , signature_length> signature = { 0x50 , 0x4b , 0x03 , 0x04 }; // 'PK\x03\x04'
@@ -250,6 +260,7 @@ struct ZipMember {
250260 bool is_directory;
251261 DOSPackedTime modification_time;
252262 DOSPackedDate modification_date;
263+ Optional<mode_t > mode;
253264};
254265
255266class Zip {
@@ -282,11 +293,11 @@ class ZipOutputStream {
282293 ZipOutputStream (NonnullOwnPtr<Stream>);
283294
284295 ErrorOr<void > add_member (ZipMember const &);
285- ErrorOr<MemberInformation> add_member_from_stream (StringView, Stream&, Optional<Core::DateTime> const & = {});
296+ ErrorOr<MemberInformation> add_member_from_stream (StringView, Stream&, Optional<Core::DateTime> const & = {}, Optional< mode_t > mode = {} );
286297
287298 // NOTE: This does not add any of the files within the directory,
288299 // it just adds an entry for it.
289- ErrorOr<void > add_directory (StringView, Optional<Core::DateTime> const & = {});
300+ ErrorOr<void > add_directory (StringView, Optional<Core::DateTime> const & = {}, Optional< mode_t > mode = {} );
290301
291302 ErrorOr<void > finish ();
292303
0 commit comments