mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-23 17:52:26 -05:00
LibArchive: Implement ZipOutputStream for zip archive creation
This output stream can be used to create zip archives, and will be used in the implementation of the zip utility.
This commit is contained in:
parent
8eceef0b1b
commit
550ae23e80
Notes:
sideshowbarker
2024-07-18 21:07:42 +09:00
Author: https://github.com/IdanHo Commit: https://github.com/SerenityOS/serenity/commit/550ae23e801 Pull-request: https://github.com/SerenityOS/serenity/pull/5917
2 changed files with 89 additions and 0 deletions
|
@ -117,4 +117,79 @@ bool Zip::for_each_member(Function<IterationDecision(const ZipMember&)> callback
|
|||
return true;
|
||||
}
|
||||
|
||||
ZipOutputStream::ZipOutputStream(OutputStream& stream)
|
||||
: m_stream(stream)
|
||||
{
|
||||
}
|
||||
|
||||
void ZipOutputStream::add_member(const ZipMember& member)
|
||||
{
|
||||
VERIFY(!m_finished);
|
||||
VERIFY(member.name.length() <= UINT16_MAX);
|
||||
VERIFY(member.compressed_data.size() <= UINT32_MAX);
|
||||
m_members.append(member);
|
||||
|
||||
LocalFileHeader local_file_header {};
|
||||
local_file_header.minimum_version = member.compression_method == ZipCompressionMethod::Deflate ? 20 : 10; // Deflate was added in PKZip 2.0
|
||||
local_file_header.general_purpose_flags = 0;
|
||||
local_file_header.compression_method = static_cast<u16>(member.compression_method);
|
||||
local_file_header.modification_time = 0; // TODO: support modification time
|
||||
local_file_header.modification_date = 0;
|
||||
local_file_header.crc32 = member.crc32;
|
||||
local_file_header.compressed_size = member.compressed_data.size();
|
||||
local_file_header.uncompressed_size = member.uncompressed_size;
|
||||
local_file_header.name_length = member.name.length();
|
||||
local_file_header.extra_data_length = 0;
|
||||
local_file_header.name = (const u8*)(member.name.characters());
|
||||
local_file_header.extra_data = nullptr;
|
||||
local_file_header.compressed_data = member.compressed_data.data();
|
||||
local_file_header.write(m_stream);
|
||||
}
|
||||
|
||||
void ZipOutputStream::finish()
|
||||
{
|
||||
VERIFY(!m_finished);
|
||||
m_finished = true;
|
||||
|
||||
auto file_header_offset = 0;
|
||||
auto central_directory_size = 0;
|
||||
for (const ZipMember& member : m_members) {
|
||||
CentralDirectoryRecord central_directory_record {};
|
||||
auto zip_version = member.compression_method == ZipCompressionMethod::Deflate ? 20 : 10; // Deflate was added in PKZip 2.0
|
||||
central_directory_record.made_by_version = zip_version;
|
||||
central_directory_record.minimum_version = zip_version;
|
||||
central_directory_record.general_purpose_flags = 0;
|
||||
central_directory_record.compression_method = static_cast<u16>(member.compression_method);
|
||||
central_directory_record.modification_time = 0; // TODO: support modification time
|
||||
central_directory_record.modification_date = 0;
|
||||
central_directory_record.crc32 = member.crc32;
|
||||
central_directory_record.compressed_size = member.compressed_data.size();
|
||||
central_directory_record.uncompressed_size = member.uncompressed_size;
|
||||
central_directory_record.name_length = member.name.length();
|
||||
central_directory_record.extra_data_length = 0;
|
||||
central_directory_record.comment_length = 0;
|
||||
central_directory_record.start_disk = 0;
|
||||
central_directory_record.internal_attributes = 0;
|
||||
central_directory_record.external_attributes = member.is_directory ? zip_directory_external_attribute : 0;
|
||||
central_directory_record.local_file_header_offset = file_header_offset; // FIXME: we assume the wrapped output stream was never written to before us
|
||||
file_header_offset += sizeof(local_file_header_signature) + (sizeof(LocalFileHeader) - (sizeof(u8*) * 3)) + member.name.length() + member.compressed_data.size();
|
||||
central_directory_record.name = (const u8*)(member.name.characters());
|
||||
central_directory_record.extra_data = nullptr;
|
||||
central_directory_record.comment = nullptr;
|
||||
central_directory_record.write(m_stream);
|
||||
central_directory_size += central_directory_record.size();
|
||||
}
|
||||
|
||||
EndOfCentralDirectory end_of_central_directory {};
|
||||
end_of_central_directory.disk_number = 0;
|
||||
end_of_central_directory.central_directory_start_disk = 0;
|
||||
end_of_central_directory.disk_records_count = m_members.size();
|
||||
end_of_central_directory.total_records_count = m_members.size();
|
||||
end_of_central_directory.central_directory_size = central_directory_size;
|
||||
end_of_central_directory.central_directory_offset = file_header_offset;
|
||||
end_of_central_directory.comment_length = 0;
|
||||
end_of_central_directory.comment = nullptr;
|
||||
end_of_central_directory.write(m_stream);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <AK/Span.h>
|
||||
#include <AK/Stream.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace Archive {
|
||||
|
@ -231,4 +232,17 @@ private:
|
|||
ReadonlyBytes m_input_data;
|
||||
};
|
||||
|
||||
class ZipOutputStream {
|
||||
public:
|
||||
ZipOutputStream(OutputStream&);
|
||||
void add_member(const ZipMember&);
|
||||
void finish();
|
||||
|
||||
private:
|
||||
OutputStream& m_stream;
|
||||
Vector<ZipMember> m_members;
|
||||
|
||||
bool m_finished { false };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue