From 3a7a689b87d85948b10b769ea5b562c90c6be63a Mon Sep 17 00:00:00 2001 From: AnotherTest Date: Mon, 13 Jul 2020 12:38:59 +0430 Subject: [PATCH] unzip: Remove some magic numbers and create directories when needed This commit also adds an assert about the compression method instead of just writing out the compressed data. --- Userland/unzip.cpp | 85 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 63 insertions(+), 22 deletions(-) diff --git a/Userland/unzip.cpp b/Userland/unzip.cpp index d14f6ca660..453d20abf2 100644 --- a/Userland/unzip.cpp +++ b/Userland/unzip.cpp @@ -64,49 +64,90 @@ bool find_next_central_directory(off_t file_size, const MappedFile& file, off_t bool unpack_file_for_central_directory_index(off_t central_directory_index, const MappedFile& file) { + enum CentralFileDirectoryHeaderOffsets { + CFDHCompressionMethodOffset = 10, + CFDHLocalFileHeaderIndexOffset = 42, + }; + enum LocalFileHeaderOffsets { + LFHCompressionMethodOffset = 10, + LFHCompressedSizeOffset = 18, + LFHFileNameLengthOffset = 26, + LFHExtraFieldLengthOffset = 28, + LFHFileNameBaseOffset = 30, + }; + enum CompressionMethod { + None = 0, + Shrunk = 1, + Factor1 = 2, + Factor2 = 3, + Factor3 = 4, + Factor4 = 5, + Implode = 6, + Deflate = 8, + EnhancedDeflate = 9, + PKWareDCLImplode = 10, + BZIP2 = 12, + LZMA = 14, + TERSE = 18, + LZ77 = 19, + }; + u8 buffer[4]; - if (!seek_and_read(buffer, file, central_directory_index + 42, 4)) + if (!seek_and_read(buffer, file, central_directory_index + CFDHLocalFileHeaderIndexOffset, 4)) return false; off_t local_file_header_index = buffer[3] << 24 | buffer[2] << 16 | buffer[1] << 8 | buffer[0]; - if (!seek_and_read(buffer, file, local_file_header_index + 18, 4)) + if (!seek_and_read(buffer, file, local_file_header_index + LFHCompressionMethodOffset, 2)) + return false; + auto compression_method = buffer[1] << 8 | buffer[0]; + // FIXME: Remove once any decompression is supported. + ASSERT(compression_method == None); + + if (!seek_and_read(buffer, file, local_file_header_index + LFHCompressedSizeOffset, 4)) return false; off_t compressed_file_size = buffer[3] << 24 | buffer[2] << 16 | buffer[1] << 8 | buffer[0]; - if (!seek_and_read(buffer, file, local_file_header_index + 26, 2)) + if (!seek_and_read(buffer, file, local_file_header_index + LFHFileNameLengthOffset, 2)) return false; off_t file_name_length = buffer[1] << 8 | buffer[0]; - if (!seek_and_read(buffer, file, local_file_header_index + 28, 2)) + if (!seek_and_read(buffer, file, local_file_header_index + LFHExtraFieldLengthOffset, 2)) return false; off_t extra_field_length = buffer[1] << 8 | buffer[0]; - if (!seek_and_read(buffer, file, local_file_header_index + 30, file_name_length)) + if (!seek_and_read(buffer, file, local_file_header_index + LFHFileNameBaseOffset, file_name_length)) return false; char file_name[file_name_length + 1]; memcpy(file_name, buffer, file_name_length); file_name[file_name_length] = '\0'; - auto new_file = Core::File::construct(String { file_name }); - if (!new_file->open(Core::IODevice::WriteOnly)) { - fprintf(stderr, "Can't write file %s: %s\n", file_name, new_file->error_string()); - return false; - } + if (file_name[file_name_length - 1] == '/') { + if (mkdir(file_name, 0755) < 0) { + perror("mkdir"); + return false; + } + } else { + auto new_file = Core::File::construct(String { file_name }); + if (!new_file->open(Core::IODevice::WriteOnly)) { + fprintf(stderr, "Can't write file %s: %s\n", file_name, new_file->error_string()); + return false; + } - printf(" extracting: %s\n", file_name); - u8 raw_file_contents[compressed_file_size]; - if (!seek_and_read(raw_file_contents, file, local_file_header_index + 30 + file_name_length + extra_field_length, compressed_file_size)) - return false; + printf(" extracting: %s\n", file_name); + u8 raw_file_contents[compressed_file_size]; + if (!seek_and_read(raw_file_contents, file, local_file_header_index + LFHFileNameBaseOffset + file_name_length + extra_field_length, compressed_file_size)) + return false; - // FIXME: Try to uncompress data here. We're just ignoring it as no decompression methods are implemented yet. - if (!new_file->write(raw_file_contents, compressed_file_size)) { - fprintf(stderr, "Can't write file contents in %s: %s\n", file_name, new_file->error_string()); - return false; - } + // FIXME: Try to uncompress data here. We're just ignoring it as no decompression methods are implemented yet. + if (!new_file->write(raw_file_contents, compressed_file_size)) { + fprintf(stderr, "Can't write file contents in %s: %s\n", file_name, new_file->error_string()); + return false; + } - if (!new_file->close()) { - fprintf(stderr, "Can't close file %s: %s\n", file_name, new_file->error_string()); - return false; + if (!new_file->close()) { + fprintf(stderr, "Can't close file %s: %s\n", file_name, new_file->error_string()); + return false; + } } return true;