Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
-- v2: opcservices: Mark entries according to compression mode. opcservices: Use explicit field for the part name. opcservices: Set compression method according to part's compression options. opcservices: Use stdint types for the file header. opcservices: Improve error handling when writing archives. opcservices: Add support for writing Zip64 packages. opcservices: Use 64-bit file sizes. opcservices: Make it clear which structures are specific to zip32. opcservices/tests: Use message context in some tests.
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/tests/opcservices.c | 62 ++++++++++++++++++---------- 1 file changed, 41 insertions(+), 21 deletions(-)
diff --git a/dlls/opcservices/tests/opcservices.c b/dlls/opcservices/tests/opcservices.c index 396364037b8..9ead97f9c62 100644 --- a/dlls/opcservices/tests/opcservices.c +++ b/dlls/opcservices/tests/opcservices.c @@ -545,6 +545,8 @@ static void test_rel_part_uri(void) IOpcPartUri *rel_uri; IOpcUri *part_uri;
+ winetest_push_context("Test %u", i); + if (!wcscmp(rel_part_uri_tests[i].uri, L"/")) { hr = IOpcFactory_CreatePackageRootUri(factory, &part_uri); @@ -599,18 +601,20 @@ static void test_rel_part_uri(void) hr = IOpcPartUri_GetRawUri(rel_uri, &str); ok(hr == S_OK, "Failed to get rel uri, hr %#lx.\n", hr); todo_wine_if(i == 3 || i == 4 || i == 8 || i == 9) - ok(!lstrcmpW(str, rel_part_uri_tests[i].rel_uri), "%u: unexpected rel uri %s, expected %s.\n", - i, wine_dbgstr_w(str), wine_dbgstr_w(rel_part_uri_tests[i].rel_uri)); + ok(!lstrcmpW(str, rel_part_uri_tests[i].rel_uri), "Unexpected rel uri %s, expected %s.\n", + wine_dbgstr_w(str), wine_dbgstr_w(rel_part_uri_tests[i].rel_uri)); SysFreeString(str);
IOpcPartUri_Release(rel_uri); } else { - ok(hr == rel_part_uri_tests[i].hr, "%u: unexpected hr %#lx.\n", i, hr); - ok(rel_uri == NULL, "%u: unexpected out pointer.\n", i); + ok(hr == rel_part_uri_tests[i].hr, "Unexpected hr %#lx.\n", hr); + ok(rel_uri == NULL, "Unexpected out pointer.\n"); }
+ winetest_pop_context(); + IOpcUri_Release(part_uri); }
@@ -619,15 +623,19 @@ static void test_rel_part_uri(void) IOpcPartUri *part_uri; BOOL ret;
+ winetest_push_context("Test %u", i); + hr = IOpcFactory_CreatePartUri(factory, is_rel_part_tests[i].uri, &part_uri); ok(hr == S_OK, "Failed to create part uri, hr %#lx.\n", hr);
ret = 123; hr = IOpcPartUri_IsRelationshipsPartUri(part_uri, &ret); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(ret == is_rel_part_tests[i].ret, "%u: unexpected result %d.\n", i, ret); + ok(ret == is_rel_part_tests[i].ret, "Unexpected result %d.\n", ret);
IOpcPartUri_Release(part_uri); + + winetest_pop_context(); }
IOpcFactory_Release(factory); @@ -1005,36 +1013,40 @@ static void test_relative_uri(void) HRESULT hr; BSTR str;
+ winetest_push_context("Test %u", i); + relative_broken = relative_uri_tests[i].relative_broken;
if (!wcscmp(relative_uri_tests[i].part, L"/")) hr = IOpcFactory_CreatePackageRootUri(factory, &part_uri); else hr = IOpcFactory_CreatePartUri(factory, relative_uri_tests[i].part, (IOpcPartUri **)&part_uri); - ok(hr == S_OK, "%u: failed to create part uri, hr %#lx.\n", i, hr); + ok(hr == S_OK, "Failed to create part uri, hr %#lx.\n", hr);
hr = IOpcFactory_CreatePartUri(factory, relative_uri_tests[i].combined, &combined_uri); - ok(hr == S_OK, "%u: failed to create part uri, hr %#lx.\n", i, hr); + ok(hr == S_OK, "Failed to create part uri, hr %#lx.\n", hr);
hr = IOpcUri_GetRelativeUri(part_uri, combined_uri, &relative_uri); todo_wine - ok(hr == S_OK, "%u: failed t oget relative uri, hr %#lx.\n", i, hr); + ok(hr == S_OK, "Failed to get relative uri, hr %#lx.\n", hr);
if (hr == S_OK) { hr = IUri_QueryInterface(relative_uri, &IID_IOpcUri, (void **)&unk); - ok(hr == E_NOINTERFACE, "%u: unexpected hr %#lx.\n", i, hr); + ok(hr == E_NOINTERFACE, "Unexpected hr %#lx.\n", hr);
hr = IUri_GetRawUri(relative_uri, &str); - ok(hr == S_OK, "%u: failed to get raw uri, hr %#lx.\n", i, hr); + ok(hr == S_OK, "Failed to get raw uri, hr %#lx.\n", hr); ok(!lstrcmpW(str, relative_uri_tests[i].relative) || broken(relative_broken && !lstrcmpW(str, relative_broken)), - "%u: unexpected relative uri %s.\n", i, wine_dbgstr_w(str)); + "Unexpected relative uri %s.\n", wine_dbgstr_w(str)); SysFreeString(str);
IUri_Release(relative_uri); } IOpcUri_Release(part_uri); IOpcPartUri_Release(combined_uri); + + winetest_pop_context(); }
IOpcFactory_Release(factory); @@ -1068,36 +1080,40 @@ static void test_combine_uri(void) HRESULT hr; BSTR str;
+ winetest_push_context("Test %u", i); + if (!wcscmp(combine_tests[i].uri, L"/")) hr = IOpcFactory_CreatePackageRootUri(factory, &uri); else hr = IOpcFactory_CreatePartUri(factory, combine_tests[i].uri, (IOpcPartUri **)&uri); - ok(hr == S_OK, "%u: failed to create uri, hr %#lx.\n", i, hr); + ok(hr == S_OK, "Failed to create uri, hr %#lx.\n", hr);
hr = CreateUri(combine_tests[i].relative, Uri_CREATE_ALLOW_RELATIVE, 0, &relative_uri); - ok(hr == S_OK, "%u: failed to create relative uri, hr %#lx.\n", i, hr); + ok(hr == S_OK, "Failed to create relative uri, hr %#lx.\n", hr);
combined_uri = (void *)0xdeadbeef; hr = IOpcUri_CombinePartUri(uri, NULL, &combined_uri); - ok(hr == E_POINTER, "%u: failed to combine uris, hr %#lx.\n", i, hr); + ok(hr == E_POINTER, "Failed to combine uris, hr %#lx.\n", hr); ok(!combined_uri, "Unexpected instance.\n");
hr = IOpcUri_CombinePartUri(uri, relative_uri, NULL); - ok(hr == E_POINTER, "%u: failed to combine uris, hr %#lx.\n", i, hr); + ok(hr == E_POINTER, "Failed to combine uris, hr %#lx.\n", hr);
hr = IOpcUri_CombinePartUri(uri, relative_uri, &combined_uri); - ok(hr == S_OK, "%u: failed to combine uris, hr %#lx.\n", i, hr); + ok(hr == S_OK, "Failed to combine uris, hr %#lx.\n", hr);
hr = IOpcPartUri_GetRawUri(combined_uri, &str); - ok(hr == S_OK, "%u: failed to get raw uri, hr %#lx.\n", i, hr); + ok(hr == S_OK, "Failed to get raw uri, hr %#lx.\n", hr); todo_wine_if(i == 2 || i == 3) - ok(!lstrcmpW(str, combine_tests[i].combined), "%u: unexpected uri %s.\n", i, wine_dbgstr_w(str)); + ok(!lstrcmpW(str, combine_tests[i].combined), "Unexpected uri %s.\n", wine_dbgstr_w(str)); SysFreeString(str);
IOpcPartUri_Release(combined_uri);
IOpcUri_Release(uri); IUri_Release(relative_uri); + + winetest_pop_context(); }
IOpcFactory_Release(factory); @@ -1132,13 +1148,15 @@ static void test_create_part_uri(void) BSTR str; BOOL ret;
+ winetest_push_context("Test %u", i); + hr = IOpcFactory_CreatePartUri(factory, create_part_uri_tests[i].input, &part_uri); - ok(hr == S_OK, "%u: failed to create part uri, hr %#lx.\n", i, hr); + ok(hr == S_OK, "Failed to create part uri, hr %#lx.\n", hr);
hr = IOpcPartUri_GetRawUri(part_uri, &str); ok(hr == S_OK, "Failed to get raw uri, hr %#lx.\n", hr); todo_wine_if(i == 1 || i == 2 || i == 4) - ok(!lstrcmpW(str, raw_uri), "%u: unexpected raw uri %s.\n", i, wine_dbgstr_w(str)); + ok(!lstrcmpW(str, raw_uri), "Unexpected raw uri %s.\n", wine_dbgstr_w(str)); SysFreeString(str);
hr = CreateUri(raw_uri, Uri_CREATE_ALLOW_RELATIVE, 0, &uri); @@ -1148,10 +1166,12 @@ static void test_create_part_uri(void) hr = IOpcPartUri_IsEqual(part_uri, uri, &ret); ok(hr == S_OK, "IsEqual failed, hr %#lx.\n", hr); todo_wine_if(i == 1 || i == 2 || i == 4) - ok(!!ret, "%u: unexpected result %d.\n", i, ret); + ok(!!ret, "Unexpected result %d.\n", ret);
IOpcPartUri_Release(part_uri); IUri_Release(uri); + + winetest_pop_context(); }
IOpcFactory_Release(factory);
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/compress.c | 39 +++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 19 deletions(-)
diff --git a/dlls/opcservices/compress.c b/dlls/opcservices/compress.c index 748293d7acd..542c7f84a99 100644 --- a/dlls/opcservices/compress.c +++ b/dlls/opcservices/compress.c @@ -19,6 +19,7 @@ #define COBJMACROS
#include <stdarg.h> +#include <stdint.h> #include <zlib.h>
#include "windef.h" @@ -46,12 +47,12 @@ struct local_file_header WORD extra_length; };
-struct data_descriptor +struct zip32_data_descriptor { - DWORD signature; - DWORD crc32; - DWORD compressed_size; - DWORD uncompressed_size; + uint32_t signature; + uint32_t crc32; + uint32_t compressed_size; + uint32_t uncompressed_size; };
struct central_directory_header @@ -74,16 +75,16 @@ struct central_directory_header DWORD local_file_offset; };
-struct central_directory_end +struct zip32_end_of_central_directory { - DWORD signature; - WORD diskid; - WORD firstdisk; - WORD records_num; - WORD records_total; - DWORD directory_size; - DWORD directory_offset; - WORD comment_length; + uint32_t signature; + uint16_t diskid; + uint16_t firstdisk; + uint16_t records_num; + uint16_t records_total; + uint32_t directory_size; + uint32_t directory_offset; + uint16_t comment_length; }; #pragma pack(pop)
@@ -91,7 +92,7 @@ struct central_directory_end #define LOCAL_HEADER_SIGNATURE 0x04034b50 #define DIRECTORY_END_SIGNATURE 0x06054b50 #define DATA_DESCRIPTOR_SIGNATURE 0x08074b50 -#define VERSION 20 +#define ZIP32_VERSION 20
enum entry_flags { @@ -157,7 +158,7 @@ static void compress_write(struct zip_archive *archive, void *data, ULONG size)
void compress_finalize_archive(struct zip_archive *archive) { - struct central_directory_end dir_end = { 0 }; + struct zip32_end_of_central_directory dir_end = { 0 }; size_t i;
dir_end.directory_offset = archive->position; @@ -195,7 +196,7 @@ static void zfree(void *opaque, void *ptr) }
static void compress_write_content(struct zip_archive *archive, IStream *content, - OPC_COMPRESSION_OPTIONS options, struct data_descriptor *data_desc) + OPC_COMPRESSION_OPTIONS options, struct zip32_data_descriptor *data_desc) { int level, flush; z_stream z_str; @@ -277,7 +278,7 @@ HRESULT compress_add_file(struct zip_archive *archive, const WCHAR *path, { struct central_directory_header *entry; struct local_file_header local_header; - struct data_descriptor data_desc; + struct zip32_data_descriptor data_desc; DWORD local_header_pos; char *name; DWORD len; @@ -289,7 +290,7 @@ HRESULT compress_add_file(struct zip_archive *archive, const WCHAR *path,
/* Local header */ local_header.signature = LOCAL_HEADER_SIGNATURE; - local_header.version = VERSION; + local_header.version = ZIP32_VERSION; local_header.flags = USE_DATA_DESCRIPTOR; local_header.method = 8; /* Z_DEFLATED */ local_header.mtime = archive->mtime;
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/compress.c | 39 +++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-)
diff --git a/dlls/opcservices/compress.c b/dlls/opcservices/compress.c index 542c7f84a99..b35a51d664f 100644 --- a/dlls/opcservices/compress.c +++ b/dlls/opcservices/compress.c @@ -55,6 +55,14 @@ struct zip32_data_descriptor uint32_t uncompressed_size; };
+struct zip64_data_descriptor +{ + uint32_t signature; + uint32_t crc32; + uint64_t compressed_size; + uint64_t uncompressed_size; +}; + struct central_directory_header { DWORD signature; @@ -107,7 +115,7 @@ struct zip_archive
DWORD mtime; IStream *output; - DWORD position; + uint64_t position; HRESULT write_result;
unsigned char input_buffer[0x8000]; @@ -196,7 +204,7 @@ static void zfree(void *opaque, void *ptr) }
static void compress_write_content(struct zip_archive *archive, IStream *content, - OPC_COMPRESSION_OPTIONS options, struct zip32_data_descriptor *data_desc) + OPC_COMPRESSION_OPTIONS options, struct zip64_data_descriptor *data_desc) { int level, flush; z_stream z_str; @@ -205,7 +213,10 @@ static void compress_write_content(struct zip_archive *archive, IStream *content HRESULT hr; int init_ret;
+ data_desc->signature = DATA_DESCRIPTOR_SIGNATURE; data_desc->crc32 = RtlComputeCrc32(0, NULL, 0); + data_desc->compressed_size = data_desc->uncompressed_size = 0; + move.QuadPart = 0; IStream_Seek(content, move, STREAM_SEEK_SET, NULL);
@@ -250,6 +261,7 @@ static void compress_write_content(struct zip_archive *archive, IStream *content z_str.avail_in = num_read; z_str.next_in = archive->input_buffer; data_desc->crc32 = RtlComputeCrc32(data_desc->crc32, archive->input_buffer, num_read); + data_desc->uncompressed_size += num_read;
flush = sizeof(archive->input_buffer) > num_read ? Z_FINISH : Z_NO_FLUSH;
@@ -264,21 +276,21 @@ static void compress_write_content(struct zip_archive *archive, IStream *content WARN("Failed to deflate, ret %d.\n", ret); have = sizeof(archive->output_buffer) - z_str.avail_out; compress_write(archive, archive->output_buffer, have); + + data_desc->compressed_size += have; } while (z_str.avail_out == 0); } while (flush != Z_FINISH);
deflateEnd(&z_str); - - data_desc->compressed_size = z_str.total_out; - data_desc->uncompressed_size = z_str.total_in; }
HRESULT compress_add_file(struct zip_archive *archive, const WCHAR *path, IStream *content, OPC_COMPRESSION_OPTIONS options) { + struct zip32_data_descriptor zip32_data_desc; + struct zip64_data_descriptor zip64_data_desc; struct central_directory_header *entry; struct local_file_header local_header; - struct zip32_data_descriptor data_desc; DWORD local_header_pos; char *name; DWORD len; @@ -306,11 +318,14 @@ HRESULT compress_add_file(struct zip_archive *archive, const WCHAR *path, compress_write(archive, name, local_header.name_length);
/* Content */ - compress_write_content(archive, content, options, &data_desc); + compress_write_content(archive, content, options, &zip64_data_desc);
/* Data descriptor */ - data_desc.signature = DATA_DESCRIPTOR_SIGNATURE; - compress_write(archive, &data_desc, sizeof(data_desc)); + zip32_data_desc.signature = DATA_DESCRIPTOR_SIGNATURE; + zip32_data_desc.crc32 = zip64_data_desc.crc32; + zip32_data_desc.compressed_size = zip64_data_desc.compressed_size; + zip32_data_desc.uncompressed_size = zip64_data_desc.uncompressed_size; + compress_write(archive, &zip32_data_desc, sizeof(zip32_data_desc));
if (FAILED(archive->write_result)) return archive->write_result; @@ -328,9 +343,9 @@ HRESULT compress_add_file(struct zip_archive *archive, const WCHAR *path, entry->flags = local_header.flags; entry->method = local_header.method; entry->mtime = local_header.mtime; - entry->crc32 = data_desc.crc32; - entry->compressed_size = data_desc.compressed_size; - entry->uncompressed_size = data_desc.uncompressed_size; + entry->crc32 = zip32_data_desc.crc32; + entry->compressed_size = zip32_data_desc.compressed_size; + entry->uncompressed_size = zip32_data_desc.uncompressed_size; entry->name_length = local_header.name_length; entry->local_file_offset = local_header_pos; memcpy(entry + 1, name, entry->name_length);
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/compress.c | 341 ++++++++++++++++++++++++--------- dlls/opcservices/opc_private.h | 4 +- dlls/opcservices/package.c | 5 +- 3 files changed, 257 insertions(+), 93 deletions(-)
diff --git a/dlls/opcservices/compress.c b/dlls/opcservices/compress.c index b35a51d664f..33858a01c48 100644 --- a/dlls/opcservices/compress.c +++ b/dlls/opcservices/compress.c @@ -55,32 +55,24 @@ struct zip32_data_descriptor uint32_t uncompressed_size; };
-struct zip64_data_descriptor +struct zip32_central_directory_header { uint32_t signature; + uint16_t version; + uint16_t min_version; + uint16_t flags; + uint16_t method; + uint32_t mtime; uint32_t crc32; - uint64_t compressed_size; - uint64_t uncompressed_size; -}; - -struct central_directory_header -{ - DWORD signature; - WORD version; - WORD min_version; - WORD flags; - WORD method; - DWORD mtime; - DWORD crc32; - DWORD compressed_size; - DWORD uncompressed_size; - WORD name_length; - WORD extra_length; - WORD comment_length; - WORD diskid; - WORD internal_attributes; - DWORD external_attributes; - DWORD local_file_offset; + uint32_t compressed_size; + uint32_t uncompressed_size; + uint16_t name_length; + uint16_t extra_length; + uint16_t comment_length; + uint16_t diskid; + uint16_t internal_attributes; + uint32_t external_attributes; + uint32_t local_file_offset; };
struct zip32_end_of_central_directory @@ -94,22 +86,81 @@ struct zip32_end_of_central_directory uint32_t directory_offset; uint16_t comment_length; }; + +struct zip64_data_descriptor +{ + uint32_t signature; + uint32_t crc32; + uint64_t compressed_size; + uint64_t uncompressed_size; +}; + +struct zip64_extra_field +{ + uint16_t id; + uint16_t size; + uint64_t uncompressed_size; + uint64_t compressed_size; + uint64_t offset; + uint32_t diskid; +}; + +struct zip64_end_of_central_directory +{ + uint32_t signature; + uint64_t size; + uint16_t version; + uint16_t min_version; + uint32_t diskid; + uint32_t directory_diskid; + uint64_t records_num; + uint64_t records_total; + uint64_t directory_size; + uint64_t directory_offset; +}; + +struct zip64_end_of_central_directory_locator +{ + uint32_t signature; + uint32_t eocd64_disk; + uint64_t eocd64_offset; + uint32_t disk_num; +}; #pragma pack(pop)
-#define CENTRAL_DIR_SIGNATURE 0x02014b50 -#define LOCAL_HEADER_SIGNATURE 0x04034b50 -#define DIRECTORY_END_SIGNATURE 0x06054b50 -#define DATA_DESCRIPTOR_SIGNATURE 0x08074b50 -#define ZIP32_VERSION 20 +enum zip_signatures +{ + ZIP32_CDFH = 0x02014b50, + LOCAL_HEADER_SIGNATURE = 0x04034b50, + ZIP32_EOCD = 0x06054b50, + ZIP64_EOCD64 = 0x06064b50, + ZIP64_EOCD64_LOCATOR = 0x07064b50, + DATA_DESCRIPTOR_SIGNATURE = 0x08074b50, +}; + +enum zip_versions +{ + ZIP32_VERSION = 20, + ZIP64_VERSION = 45, +};
enum entry_flags { USE_DATA_DESCRIPTOR = 0x8, };
+struct zip_file +{ + uint64_t compressed_size; + uint64_t uncompressed_size; + uint64_t offset; + uint32_t crc32; + uint16_t name_length; +}; + struct zip_archive { - struct central_directory_header **files; + struct zip_file **files; size_t file_count; size_t file_size;
@@ -118,11 +169,13 @@ struct zip_archive uint64_t position; HRESULT write_result;
+ bool zip64; + unsigned char input_buffer[0x8000]; unsigned char output_buffer[0x8000]; };
-HRESULT compress_create_archive(IStream *output, struct zip_archive **out) +HRESULT compress_create_archive(IStream *output, bool zip64, struct zip_archive **out) { struct zip_archive *archive; WORD date, time; @@ -144,6 +197,8 @@ HRESULT compress_create_archive(IStream *output, struct zip_archive **out) FileTimeToDosDateTime(&ft, &date, &time); archive->mtime = date << 16 | time;
+ archive->zip64 = zip64; + *out = archive;
return S_OK; @@ -166,24 +221,125 @@ static void compress_write(struct zip_archive *archive, void *data, ULONG size)
void compress_finalize_archive(struct zip_archive *archive) { - struct zip32_end_of_central_directory dir_end = { 0 }; + struct zip32_end_of_central_directory dir_end; + struct zip32_central_directory_header cdh; + uint64_t cd_offset, cd_size = 0; size_t i;
- dir_end.directory_offset = archive->position; - dir_end.records_num = archive->file_count; - dir_end.records_total = archive->file_count; - /* Directory entries */ - for (i = 0; i < archive->file_count; ++i) + cd_offset = archive->position; + + if (archive->zip64) { - compress_write(archive, archive->files[i], sizeof(*archive->files[i])); - compress_write(archive, archive->files[i] + 1, archive->files[i]->name_length); - dir_end.directory_size += archive->files[i]->name_length + sizeof(*archive->files[i]); + struct zip64_end_of_central_directory_locator locator; + struct zip64_end_of_central_directory eocd64; + uint64_t eocd64_offset = archive->position; + struct zip64_extra_field extra_field; + + for (i = 0; i < archive->file_count; ++i) + { + const struct zip_file *file = archive->files[i]; + + cdh.signature = ZIP32_CDFH; + cdh.version = ZIP64_VERSION; + cdh.min_version = ZIP64_VERSION; + cdh.flags = USE_DATA_DESCRIPTOR; + cdh.method = 8; /* Z_DEFLATED */ + cdh.mtime = archive->mtime; + cdh.crc32 = file->crc32; + cdh.compressed_size = ~0u; + cdh.uncompressed_size = ~0u; + cdh.name_length = file->name_length; + cdh.extra_length = sizeof(extra_field); + cdh.comment_length = 0; + cdh.diskid = 0; + cdh.internal_attributes = 0; + cdh.external_attributes = 0; + cdh.local_file_offset = ~0u; + compress_write(archive, &cdh, sizeof(cdh)); + + /* File name */ + compress_write(archive, archive->files[i] + 1, file->name_length); + + /* Extra field */ + extra_field.id = 1; + extra_field.size = sizeof(extra_field); + extra_field.uncompressed_size = file->uncompressed_size; + extra_field.compressed_size = file->compressed_size; + extra_field.offset = file->offset; + extra_field.diskid = 0; + compress_write(archive, &extra_field, sizeof(extra_field)); + + cd_size += cdh.name_length + cdh.extra_length + sizeof(cdh); + } + + /* ZIP64 end of central directory */ + eocd64.signature = ZIP64_EOCD64; + eocd64.size = sizeof(eocd64) - 12; + eocd64.version = ZIP64_VERSION; + eocd64.min_version = ZIP64_VERSION; + eocd64.diskid = 0; + eocd64.directory_diskid = 0; + eocd64.records_num = archive->file_count; + eocd64.records_total = archive->file_count; + eocd64.directory_size = cd_size; + eocd64.directory_offset = cd_offset; + compress_write(archive, &eocd64, sizeof(eocd64)); + + /* ZIP64 end of central directory locator */ + locator.signature = ZIP64_EOCD64_LOCATOR; + locator.eocd64_disk = 0; + locator.eocd64_offset = eocd64_offset; + locator.disk_num = 0; + compress_write(archive, &locator, sizeof(locator)); + + /* End of central directory */ + memset(&dir_end, 0xff, sizeof(dir_end)); + dir_end.signature = ZIP32_EOCD; + dir_end.comment_length = 0; + compress_write(archive, &dir_end, sizeof(dir_end)); } + else + { + for (i = 0; i < archive->file_count; ++i) + { + const struct zip_file *file = archive->files[i]; + + cdh.signature = ZIP32_CDFH; + cdh.version = ZIP32_VERSION; + cdh.min_version = ZIP32_VERSION; + cdh.flags = USE_DATA_DESCRIPTOR; + cdh.method = 8; /* Z_DEFLATED */ + cdh.mtime = archive->mtime; + cdh.crc32 = file->crc32; + cdh.compressed_size = file->compressed_size; + cdh.uncompressed_size = file->uncompressed_size; + cdh.name_length = file->name_length; + cdh.extra_length = 0; + cdh.comment_length = 0; + cdh.diskid = 0; + cdh.internal_attributes = 0; + cdh.external_attributes = 0; + cdh.local_file_offset = file->offset; + compress_write(archive, &cdh, sizeof(cdh)); + + /* File name */ + compress_write(archive, archive->files[i] + 1, file->name_length); + + cd_size += cdh.name_length + sizeof(cdh); + }
- /* End record */ - dir_end.signature = DIRECTORY_END_SIGNATURE; - compress_write(archive, &dir_end, sizeof(dir_end)); + /* End of central directory */ + dir_end.signature = ZIP32_EOCD; + dir_end.diskid = 0; + dir_end.firstdisk = 0; + dir_end.records_num = archive->file_count; + dir_end.records_total = archive->file_count; + dir_end.directory_size = cd_size; + dir_end.directory_offset = cd_offset; + dir_end.comment_length = 0; + compress_write(archive, &dir_end, sizeof(dir_end)); + }
IStream_Release(archive->output);
@@ -204,7 +360,7 @@ static void zfree(void *opaque, void *ptr) }
static void compress_write_content(struct zip_archive *archive, IStream *content, - OPC_COMPRESSION_OPTIONS options, struct zip64_data_descriptor *data_desc) + OPC_COMPRESSION_OPTIONS options, struct zip_file *file) { int level, flush; z_stream z_str; @@ -213,9 +369,8 @@ static void compress_write_content(struct zip_archive *archive, IStream *content HRESULT hr; int init_ret;
- data_desc->signature = DATA_DESCRIPTOR_SIGNATURE; - data_desc->crc32 = RtlComputeCrc32(0, NULL, 0); - data_desc->compressed_size = data_desc->uncompressed_size = 0; + file->crc32 = RtlComputeCrc32(0, NULL, 0); + file->compressed_size = file->uncompressed_size = 0;
move.QuadPart = 0; IStream_Seek(content, move, STREAM_SEEK_SET, NULL); @@ -260,8 +415,8 @@ static void compress_write_content(struct zip_archive *archive, IStream *content
z_str.avail_in = num_read; z_str.next_in = archive->input_buffer; - data_desc->crc32 = RtlComputeCrc32(data_desc->crc32, archive->input_buffer, num_read); - data_desc->uncompressed_size += num_read; + file->crc32 = RtlComputeCrc32(file->crc32, archive->input_buffer, num_read); + file->uncompressed_size += num_read;
flush = sizeof(archive->input_buffer) > num_read ? Z_FINISH : Z_NO_FLUSH;
@@ -277,7 +432,7 @@ static void compress_write_content(struct zip_archive *archive, IStream *content have = sizeof(archive->output_buffer) - z_str.avail_out; compress_write(archive, archive->output_buffer, have);
- data_desc->compressed_size += have; + file->compressed_size += have; } while (z_str.avail_out == 0); } while (flush != Z_FINISH);
@@ -287,11 +442,8 @@ static void compress_write_content(struct zip_archive *archive, IStream *content HRESULT compress_add_file(struct zip_archive *archive, const WCHAR *path, IStream *content, OPC_COMPRESSION_OPTIONS options) { - struct zip32_data_descriptor zip32_data_desc; - struct zip64_data_descriptor zip64_data_desc; - struct central_directory_header *entry; struct local_file_header local_header; - DWORD local_header_pos; + struct zip_file *file; char *name; DWORD len;
@@ -300,65 +452,78 @@ HRESULT compress_add_file(struct zip_archive *archive, const WCHAR *path, return E_OUTOFMEMORY; WideCharToMultiByte(CP_ACP, 0, path, -1, name, len, NULL, NULL);
- /* Local header */ + if (!(file = calloc(1, sizeof(*file) + len))) + { + free(name); + return E_OUTOFMEMORY; + } + file->offset = archive->position; + file->name_length = len - 1; + memcpy(file + 1, name, file->name_length); + free(name); + local_header.signature = LOCAL_HEADER_SIGNATURE; - local_header.version = ZIP32_VERSION; local_header.flags = USE_DATA_DESCRIPTOR; local_header.method = 8; /* Z_DEFLATED */ local_header.mtime = archive->mtime; local_header.crc32 = 0; - local_header.compressed_size = 0; - local_header.uncompressed_size = 0; local_header.name_length = len - 1; local_header.extra_length = 0; - - local_header_pos = archive->position; + if (archive->zip64) + { + local_header.version = ZIP64_VERSION; + local_header.compressed_size = ~0u; + local_header.uncompressed_size = ~0u; + } + else + { + local_header.version = ZIP32_VERSION; + local_header.compressed_size = 0; + local_header.uncompressed_size = 0; + }
compress_write(archive, &local_header, sizeof(local_header)); - compress_write(archive, name, local_header.name_length); + compress_write(archive, file + 1, file->name_length);
/* Content */ - compress_write_content(archive, content, options, &zip64_data_desc); + compress_write_content(archive, content, options, file);
/* Data descriptor */ - zip32_data_desc.signature = DATA_DESCRIPTOR_SIGNATURE; - zip32_data_desc.crc32 = zip64_data_desc.crc32; - zip32_data_desc.compressed_size = zip64_data_desc.compressed_size; - zip32_data_desc.uncompressed_size = zip64_data_desc.uncompressed_size; - compress_write(archive, &zip32_data_desc, sizeof(zip32_data_desc)); - - if (FAILED(archive->write_result)) - return archive->write_result; + if (archive->zip64) + { + struct zip64_data_descriptor zip64_data_desc;
- /* Set directory entry */ - if (!(entry = calloc(1, sizeof(*entry) + local_header.name_length))) + zip64_data_desc.signature = DATA_DESCRIPTOR_SIGNATURE; + zip64_data_desc.crc32 = file->crc32; + zip64_data_desc.compressed_size = file->compressed_size; + zip64_data_desc.uncompressed_size = file->uncompressed_size; + compress_write(archive, &zip64_data_desc, sizeof(zip64_data_desc)); + } + else { - free(name); - return E_OUTOFMEMORY; + struct zip32_data_descriptor zip32_data_desc; + + zip32_data_desc.signature = DATA_DESCRIPTOR_SIGNATURE; + zip32_data_desc.crc32 = file->crc32; + zip32_data_desc.compressed_size = file->compressed_size; + zip32_data_desc.uncompressed_size = file->uncompressed_size; + compress_write(archive, &zip32_data_desc, sizeof(zip32_data_desc)); }
- entry->signature = CENTRAL_DIR_SIGNATURE; - entry->version = local_header.version; - entry->min_version = local_header.version; - entry->flags = local_header.flags; - entry->method = local_header.method; - entry->mtime = local_header.mtime; - entry->crc32 = zip32_data_desc.crc32; - entry->compressed_size = zip32_data_desc.compressed_size; - entry->uncompressed_size = zip32_data_desc.uncompressed_size; - entry->name_length = local_header.name_length; - entry->local_file_offset = local_header_pos; - memcpy(entry + 1, name, entry->name_length); - free(name); + if (FAILED(archive->write_result)) + { + free(file); + return archive->write_result; + }
if (!opc_array_reserve((void **)&archive->files, &archive->file_size, archive->file_count + 1, sizeof(*archive->files))) { - free(entry); + free(file); return E_OUTOFMEMORY; }
- archive->files[archive->file_count++] = entry; + archive->files[archive->file_count++] = file;
return S_OK; } diff --git a/dlls/opcservices/opc_private.h b/dlls/opcservices/opc_private.h index cfd8ee864b2..afb308b0726 100644 --- a/dlls/opcservices/opc_private.h +++ b/dlls/opcservices/opc_private.h @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#include <stdbool.h> + #include "msopc.h"
static inline BOOL opc_array_reserve(void **elements, size_t *capacity, size_t count, size_t size) @@ -62,7 +64,7 @@ extern HRESULT opc_root_uri_create(IOpcUri **opc_uri); extern HRESULT opc_package_write(IOpcPackage *package, OPC_WRITE_FLAGS flags, IStream *stream);
struct zip_archive; -extern HRESULT compress_create_archive(IStream *output, struct zip_archive **archive); +extern HRESULT compress_create_archive(IStream *output, bool zip64, struct zip_archive **archive); extern HRESULT compress_add_file(struct zip_archive *archive, const WCHAR *path, IStream *content, OPC_COMPRESSION_OPTIONS options); extern void compress_finalize_archive(struct zip_archive *archive); diff --git a/dlls/opcservices/package.c b/dlls/opcservices/package.c index 17175006433..deb4af80b1f 100644 --- a/dlls/opcservices/package.c +++ b/dlls/opcservices/package.c @@ -2019,13 +2019,10 @@ HRESULT opc_package_write(IOpcPackage *package, OPC_WRITE_FLAGS flags, IStream * IXmlWriter *writer; HRESULT hr;
- if (flags != OPC_WRITE_FORCE_ZIP32) - FIXME("Unsupported write flags %#x.\n", flags); - if (FAILED(hr = CreateXmlWriter(&IID_IXmlWriter, (void **)&writer, NULL))) return hr;
- if (FAILED(hr = compress_create_archive(stream, &archive))) + if (FAILED(hr = compress_create_archive(stream, flags != OPC_WRITE_FORCE_ZIP32, &archive))) { IXmlWriter_Release(writer); return hr;
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/compress.c | 46 ++++++++++++++++++++++++---------- dlls/opcservices/opc_private.h | 3 ++- dlls/opcservices/package.c | 4 ++- include/opcbase.idl | 1 + 4 files changed, 39 insertions(+), 15 deletions(-)
diff --git a/dlls/opcservices/compress.c b/dlls/opcservices/compress.c index 33858a01c48..07504a20ac1 100644 --- a/dlls/opcservices/compress.c +++ b/dlls/opcservices/compress.c @@ -167,7 +167,7 @@ struct zip_archive DWORD mtime; IStream *output; uint64_t position; - HRESULT write_result; + HRESULT status;
bool zip64;
@@ -187,7 +187,7 @@ HRESULT compress_create_archive(IStream *output, bool zip64, struct zip_archive archive->files = NULL; archive->file_size = 0; archive->file_count = 0; - archive->write_result = S_OK; + archive->status = S_OK;
archive->output = output; IStream_AddRef(archive->output); @@ -208,18 +208,20 @@ static void compress_write(struct zip_archive *archive, void *data, ULONG size) { ULONG written;
- archive->write_result = IStream_Write(archive->output, data, size, &written); + if (FAILED(archive->status)) + return; + + archive->status = IStream_Write(archive->output, data, size, &written); if (written != size) - archive->write_result = E_FAIL; + archive->status = E_FAIL; else archive->position += written;
- if (FAILED(archive->write_result)) - WARN("Failed to write output %p, size %lu, written %lu, hr %#lx.\n", - data, size, written, archive->write_result); + if (FAILED(archive->status)) + WARN("Failed to write output %p, size %lu, written %lu, hr %#lx.\n", data, size, written, archive->status); }
-void compress_finalize_archive(struct zip_archive *archive) +HRESULT compress_finalize_archive(struct zip_archive *archive) { struct zip32_end_of_central_directory dir_end; struct zip32_central_directory_header cdh; @@ -341,6 +343,13 @@ void compress_finalize_archive(struct zip_archive *archive) compress_write(archive, &dir_end, sizeof(dir_end)); }
+ return archive->status; +} + +void compress_release_archive(struct zip_archive *archive) +{ + size_t i; + IStream_Release(archive->output);
for (i = 0; i < archive->file_count; i++) @@ -369,6 +378,9 @@ static void compress_write_content(struct zip_archive *archive, IStream *content HRESULT hr; int init_ret;
+ if (FAILED(archive->status)) + return; + file->crc32 = RtlComputeCrc32(0, NULL, 0); file->compressed_size = file->uncompressed_size = 0;
@@ -401,7 +413,11 @@ static void compress_write_content(struct zip_archive *archive, IStream *content z_str.zalloc = zalloc; z_str.zfree = zfree; if ((init_ret = deflateInit2(&z_str, level, Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY)) != Z_OK) - WARN("Failed to allocate memory in deflateInit2, ret %d.\n", init_ret); + { + WARN("deflateInit2() failed, ret %d.\n", init_ret); + archive->status = OPC_E_ZIP_COMPRESSION_FAILED; + return; + }
do { @@ -409,7 +425,7 @@ static void compress_write_content(struct zip_archive *archive, IStream *content
if (FAILED(hr = IStream_Read(content, archive->input_buffer, sizeof(archive->input_buffer), &num_read))) { - archive->write_result = hr; + archive->status = hr; break; }
@@ -428,7 +444,11 @@ static void compress_write_content(struct zip_archive *archive, IStream *content z_str.next_out = archive->output_buffer;
if ((ret = deflate(&z_str, flush)) < 0) - WARN("Failed to deflate, ret %d.\n", ret); + { + WARN("Failed to deflate(), ret %d.\n", ret); + archive->status = OPC_E_ZIP_COMPRESSION_FAILED; + break; + } have = sizeof(archive->output_buffer) - z_str.avail_out; compress_write(archive, archive->output_buffer, have);
@@ -510,10 +530,10 @@ HRESULT compress_add_file(struct zip_archive *archive, const WCHAR *path, compress_write(archive, &zip32_data_desc, sizeof(zip32_data_desc)); }
- if (FAILED(archive->write_result)) + if (FAILED(archive->status)) { free(file); - return archive->write_result; + return archive->status; }
if (!opc_array_reserve((void **)&archive->files, &archive->file_size, archive->file_count + 1, diff --git a/dlls/opcservices/opc_private.h b/dlls/opcservices/opc_private.h index afb308b0726..8365916eebb 100644 --- a/dlls/opcservices/opc_private.h +++ b/dlls/opcservices/opc_private.h @@ -67,4 +67,5 @@ struct zip_archive; extern HRESULT compress_create_archive(IStream *output, bool zip64, struct zip_archive **archive); extern HRESULT compress_add_file(struct zip_archive *archive, const WCHAR *path, IStream *content, OPC_COMPRESSION_OPTIONS options); -extern void compress_finalize_archive(struct zip_archive *archive); +extern HRESULT compress_finalize_archive(struct zip_archive *archive); +extern void compress_release_archive(struct zip_archive *archive); diff --git a/dlls/opcservices/package.c b/dlls/opcservices/package.c index deb4af80b1f..7b62224b846 100644 --- a/dlls/opcservices/package.c +++ b/dlls/opcservices/package.c @@ -2040,13 +2040,15 @@ HRESULT opc_package_write(IOpcPackage *package, OPC_WRITE_FLAGS flags, IStream * /* Parts. */ if (SUCCEEDED(hr)) hr = opc_package_write_parts(archive, package, writer); + if (SUCCEEDED(hr)) + hr = compress_finalize_archive(archive);
if (rels) IOpcRelationshipSet_Release(rels); if (uri) IOpcUri_Release(uri);
- compress_finalize_archive(archive); + compress_release_archive(archive); IXmlWriter_Release(writer);
return hr; diff --git a/include/opcbase.idl b/include/opcbase.idl index 1d4aa253aa5..a34c4ec27c1 100644 --- a/include/opcbase.idl +++ b/include/opcbase.idl @@ -52,3 +52,4 @@ cpp_quote("#define OPC_E_ENUM_COLLECTION_CHANGED MAKE_HRESULT(SEVERITY_ERROR, FA cpp_quote("#define OPC_E_ENUM_CANNOT_MOVE_NEXT MAKE_HRESULT(SEVERITY_ERROR, FACILITY_OPC, 0x51)") cpp_quote("#define OPC_E_ENUM_CANNOT_MOVE_PREVIOUS MAKE_HRESULT(SEVERITY_ERROR, FACILITY_OPC, 0x52)") cpp_quote("#define OPC_E_ENUM_INVALID_POSITION MAKE_HRESULT(SEVERITY_ERROR, FACILITY_OPC, 0x53)") +cpp_quote("#define OPC_E_ZIP_COMPRESSION_FAILED MAKE_HRESULT(SEVERITY_ERROR, FACILITY_OPC, 0x1003)")
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/compress.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/dlls/opcservices/compress.c b/dlls/opcservices/compress.c index 07504a20ac1..2ef9ef9843c 100644 --- a/dlls/opcservices/compress.c +++ b/dlls/opcservices/compress.c @@ -35,16 +35,16 @@ WINE_DEFAULT_DEBUG_CHANNEL(msopc); #pragma pack(push,2) struct local_file_header { - DWORD signature; - WORD version; - WORD flags; - WORD method; - DWORD mtime; - DWORD crc32; - DWORD compressed_size; - DWORD uncompressed_size; - WORD name_length; - WORD extra_length; + uint32_t signature; + uint16_t version; + uint16_t flags; + uint16_t method; + uint32_t mtime; + uint32_t crc32; + uint32_t compressed_size; + uint32_t uncompressed_size; + uint16_t name_length; + uint16_t extra_length; };
struct zip32_data_descriptor
From: Nikolay Sivov nsivov@codeweavers.com
This is either DEFLATE (8) or no compression (0).
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/compress.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/dlls/opcservices/compress.c b/dlls/opcservices/compress.c index 2ef9ef9843c..75f779ab7ab 100644 --- a/dlls/opcservices/compress.c +++ b/dlls/opcservices/compress.c @@ -156,6 +156,7 @@ struct zip_file uint64_t offset; uint32_t crc32; uint16_t name_length; + uint16_t method; };
struct zip_archive @@ -246,7 +247,7 @@ HRESULT compress_finalize_archive(struct zip_archive *archive) cdh.version = ZIP64_VERSION; cdh.min_version = ZIP64_VERSION; cdh.flags = USE_DATA_DESCRIPTOR; - cdh.method = 8; /* Z_DEFLATED */ + cdh.method = file->method; cdh.mtime = archive->mtime; cdh.crc32 = file->crc32; cdh.compressed_size = ~0u; @@ -311,7 +312,7 @@ HRESULT compress_finalize_archive(struct zip_archive *archive) cdh.version = ZIP32_VERSION; cdh.min_version = ZIP32_VERSION; cdh.flags = USE_DATA_DESCRIPTOR; - cdh.method = 8; /* Z_DEFLATED */ + cdh.method = file->method; cdh.mtime = archive->mtime; cdh.crc32 = file->crc32; cdh.compressed_size = file->compressed_size; @@ -479,12 +480,14 @@ HRESULT compress_add_file(struct zip_archive *archive, const WCHAR *path, } file->offset = archive->position; file->name_length = len - 1; + if (options != OPC_COMPRESSION_NONE) + file->method = Z_DEFLATED; memcpy(file + 1, name, file->name_length); free(name);
local_header.signature = LOCAL_HEADER_SIGNATURE; local_header.flags = USE_DATA_DESCRIPTOR; - local_header.method = 8; /* Z_DEFLATED */ + local_header.method = file->method; local_header.mtime = archive->mtime; local_header.crc32 = 0; local_header.name_length = len - 1;
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/compress.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/dlls/opcservices/compress.c b/dlls/opcservices/compress.c index 75f779ab7ab..c596eb8f895 100644 --- a/dlls/opcservices/compress.c +++ b/dlls/opcservices/compress.c @@ -157,6 +157,7 @@ struct zip_file uint32_t crc32; uint16_t name_length; uint16_t method; + char name[1]; };
struct zip_archive @@ -205,7 +206,7 @@ HRESULT compress_create_archive(IStream *output, bool zip64, struct zip_archive return S_OK; }
-static void compress_write(struct zip_archive *archive, void *data, ULONG size) +static void compress_write(struct zip_archive *archive, const void *data, ULONG size) { ULONG written;
@@ -262,7 +263,7 @@ HRESULT compress_finalize_archive(struct zip_archive *archive) compress_write(archive, &cdh, sizeof(cdh));
/* File name */ - compress_write(archive, archive->files[i] + 1, file->name_length); + compress_write(archive, file->name, file->name_length);
/* Extra field */ extra_field.id = 1; @@ -327,7 +328,7 @@ HRESULT compress_finalize_archive(struct zip_archive *archive) compress_write(archive, &cdh, sizeof(cdh));
/* File name */ - compress_write(archive, archive->files[i] + 1, file->name_length); + compress_write(archive, file->name, file->name_length);
cd_size += cdh.name_length + sizeof(cdh); } @@ -473,7 +474,7 @@ HRESULT compress_add_file(struct zip_archive *archive, const WCHAR *path, return E_OUTOFMEMORY; WideCharToMultiByte(CP_ACP, 0, path, -1, name, len, NULL, NULL);
- if (!(file = calloc(1, sizeof(*file) + len))) + if (!(file = calloc(1, offsetof(struct zip_file, name[len])))) { free(name); return E_OUTOFMEMORY; @@ -482,7 +483,7 @@ HRESULT compress_add_file(struct zip_archive *archive, const WCHAR *path, file->name_length = len - 1; if (options != OPC_COMPRESSION_NONE) file->method = Z_DEFLATED; - memcpy(file + 1, name, file->name_length); + memcpy(file->name, name, file->name_length); free(name);
local_header.signature = LOCAL_HEADER_SIGNATURE; @@ -506,7 +507,7 @@ HRESULT compress_add_file(struct zip_archive *archive, const WCHAR *path, }
compress_write(archive, &local_header, sizeof(local_header)); - compress_write(archive, file + 1, file->name_length); + compress_write(archive, file->name, file->name_length);
/* Content */ compress_write_content(archive, content, options, file);
From: Vibhav Pant vibhavp@gmail.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/compress.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
diff --git a/dlls/opcservices/compress.c b/dlls/opcservices/compress.c index c596eb8f895..6590fec1b19 100644 --- a/dlls/opcservices/compress.c +++ b/dlls/opcservices/compress.c @@ -146,6 +146,10 @@ enum zip_versions
enum entry_flags { + DEFLATE_NORMAL = 0x0, + DEFLATE_MAX = 0x2, + DEFLATE_FAST = 0x4, + DEFLATE_SUPERFAST = 0x6, USE_DATA_DESCRIPTOR = 0x8, };
@@ -157,6 +161,7 @@ struct zip_file uint32_t crc32; uint16_t name_length; uint16_t method; + uint16_t flags; char name[1]; };
@@ -482,7 +487,18 @@ HRESULT compress_add_file(struct zip_archive *archive, const WCHAR *path, file->offset = archive->position; file->name_length = len - 1; if (options != OPC_COMPRESSION_NONE) + { file->method = Z_DEFLATED; + if (options == OPC_COMPRESSION_MAXIMUM) + file->flags = DEFLATE_MAX; + else if (options == OPC_COMPRESSION_FAST) + file->flags = DEFLATE_FAST; + else if (options == OPC_COMPRESSION_SUPERFAST) + file->flags = DEFLATE_SUPERFAST; + else + file->flags = DEFLATE_NORMAL; + } + file->flags |= USE_DATA_DESCRIPTOR; memcpy(file->name, name, file->name_length); free(name);
This merge request was approved by Vibhav Pant.