Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(286)

Unified Diff: ui/file_manager/zip_archiver/cpp/compressor_archive_libarchive.cc

Issue 2807063002: Replace Libarchive with MiniZip. (Closed)
Patch Set: Delete BUILD.gn Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ui/file_manager/zip_archiver/cpp/compressor_archive_libarchive.cc
diff --git a/ui/file_manager/zip_archiver/cpp/compressor_archive_libarchive.cc b/ui/file_manager/zip_archiver/cpp/compressor_archive_libarchive.cc
index 92ac415c33ed5aca13d3606d0bba7c6fbe51bb56..371c94d34ae7e891b3c6f0263be0446f1aba8752 100644
--- a/ui/file_manager/zip_archiver/cpp/compressor_archive_libarchive.cc
+++ b/ui/file_manager/zip_archiver/cpp/compressor_archive_libarchive.cc
@@ -7,141 +7,232 @@
#include <cerrno>
#include <cstring>
-#include "archive_entry.h"
+#include "base/time/time.h"
#include "ppapi/cpp/logging.h"
-namespace {
- // Nothing to do here because JavaScript takes care of file open operations.
- int CustomArchiveOpen(archive* archive_object, void* client_data) {
- return ARCHIVE_OK;
- }
+namespace compressor_archive_functions {
+// Called when minizip tries to open a zip archive file. We do nothing here
mtomasz 2017/04/10 07:15:08 nit: Let's add \n after the namespace line for bet
takise 2017/04/11 06:00:51 Done.
+// because JavaScript takes care of file opening operation.
+void* CustomArchiveOpen(void* opaque, const char* filename, int mode) {
+ return opaque;
+}
- // Called when any data chunk must be written on the archive. It copies data
- // from the given buffer processed by libarchive to an array buffer and passes
- // it to compressor_stream.
- ssize_t CustomArchiveWrite(archive* archive_object, void* client_data,
- const void* buffer, size_t length) {
- CompressorArchiveLibarchive* compressor_libarchive =
- static_cast<CompressorArchiveLibarchive*>(client_data);
-
- const char* char_buffer = static_cast<const char*>(buffer);
-
- // Copy the data in buffer to array_buffer.
- PP_DCHECK(length > 0);
- pp::VarArrayBuffer array_buffer(length);
- char* array_buffer_data = static_cast<char*>(array_buffer.Map());
- memcpy(array_buffer_data, char_buffer, length);
- array_buffer.Unmap();
-
- ssize_t written_bytes =
- compressor_libarchive->compressor_stream()->Write(length, array_buffer);
-
- // Negative written_bytes represents an error.
- if (written_bytes < 0) {
- // When writing fails, archive_set_error() should be called and -1 should
- // be returned.
- archive_set_error(
- compressor_libarchive->archive(), EIO, "Failed to write a chunk.");
- return -1;
- }
- return written_bytes;
- }
+// This function is not called because we don't unpack zip files here.
+uLong CustomArchiveRead(void* opaque, void* /*stream*/, void* buf, uLong size) {
mtomasz 2017/04/10 07:15:08 nit: We usually comment out unused arguments. So l
takise 2017/04/11 06:00:51 Done.
+ return 0 /* Success */;
+}
+
+// Called when data chunk must be written on the archive. It copies data
+// from the given buffer processed by minizip to an array buffer and passes
+// it to compressor_stream.
+uLong CustomArchiveWrite(void* opaque,
mtomasz 2017/04/10 07:15:08 Why is this argument called opaque? Can we rename
takise 2017/04/11 06:00:51 Done.
+ void* /*stream*/,
+ const void* zip_buffer,
+ uLong zip_length) {
+ CompressorArchiveLibarchive* compressor_libarchive =
+ static_cast<CompressorArchiveLibarchive*>(opaque);
+
+ int64_t written_bytes = compressor_libarchive->compressor_stream()->Write(
+ compressor_libarchive->offset_, zip_length, zip_buffer);
+
+ if (written_bytes != zip_length)
+ return 0 /* Error */;
+
+ // Update offset_ and length_.
+ compressor_libarchive->offset_ += written_bytes;
+ if (compressor_libarchive->offset_ > compressor_libarchive->length_)
+ compressor_libarchive->length_ = compressor_libarchive->offset_;
+ return static_cast<uLong>(written_bytes);
+}
- // Nothing to do here because JavaScript takes care of file close operations.
- int CustomArchiveClose(archive* archive_object, void* client_data) {
- return ARCHIVE_OK;
+// Returns the offset from the beginning of the data.
+long CustomArchiveTell(void* opaque, void* /*stream*/) {
+ CompressorArchiveLibarchive* compressor_libarchive =
mtomasz 2017/04/10 07:15:08 Can we rename libarchive from variable/class/metho
+ static_cast<CompressorArchiveLibarchive*>(opaque);
+ return static_cast<long>(compressor_libarchive->offset_);
+}
+
+// Moves the current offset to the specified position.
+long CustomArchiveSeek(void* opaque,
+ void* /*stream*/,
+ uLong offset,
+ int origin) {
+ CompressorArchiveLibarchive* compressor_libarchive =
+ static_cast<CompressorArchiveLibarchive*>(opaque);
+
+ if (origin == ZLIB_FILEFUNC_SEEK_CUR) {
+ compressor_libarchive->offset_ =
+ std::min(compressor_libarchive->offset_ + static_cast<int64_t>(offset),
+ compressor_libarchive->length_);
+ return 0 /* Success */;
+ }
+ if (origin == ZLIB_FILEFUNC_SEEK_END) {
+ compressor_libarchive->offset_ =
+ std::max(compressor_libarchive->length_ - static_cast<int64_t>(offset),
+ 0);
+ return 0 /* Success */;
}
+ if (origin == ZLIB_FILEFUNC_SEEK_SET) {
+ compressor_libarchive->offset_ =
+ std::min(static_cast<int64_t>(offset), compressor_libarchive->length_);
+ return 0 /* Success */;
+ }
+ return -1 /* Error */;
+}
+
+// Releases all used resources. opaque points to compressor_libarchive and
+// it is deleted elsewhere, so we don't need to delete it here.
mtomasz 2017/04/10 07:15:08 nit: elsewhere -> ... Can we write a method name i
takise 2017/04/11 06:00:51 Done.
+int CustomArchiveClose(void* opaque, void* /*stream*/) {
+ return 0 /* Success */;
}
+// Returns the last error that happened when writing data. This function always
+// returns zero, which means there are no errors.
+int CustomArchiveError(void* /*opaque*/, void* /*stream*/) {
+ return 0 /* Success */;
+}
+
+} // compressor_archive_functions
+
CompressorArchiveLibarchive::CompressorArchiveLibarchive(
CompressorStream* compressor_stream)
: CompressorArchive(compressor_stream),
- compressor_stream_(compressor_stream) {
+ compressor_stream_(compressor_stream),
+ zip_file_(NULL),
+ offset_(0),
+ length_(0) {
destination_buffer_ =
- new char[compressor_archive_constants::kMaximumDataChunkSize];
+ new char[compressor_stream_constants::kMaximumDataChunkSize];
}
CompressorArchiveLibarchive::~CompressorArchiveLibarchive() {
delete destination_buffer_;
}
-void CompressorArchiveLibarchive::CreateArchive() {
- archive_ = archive_write_new();
- archive_write_set_format_zip(archive_);
-
- // Passing 1 as the second argument causes the final chunk not to be padded.
- archive_write_set_bytes_in_last_block(archive_, 1);
- archive_write_set_bytes_per_block(
- archive_, compressor_archive_constants::kMaximumDataChunkSize);
- archive_write_open(archive_, this, CustomArchiveOpen,
- CustomArchiveWrite, CustomArchiveClose);
+bool CompressorArchiveLibarchive::CreateArchive() {
+ // Set up archive object.
+ zlib_filefunc_def zip_funcs;
+ zip_funcs.zopen_file = compressor_archive_functions::CustomArchiveOpen;
+ zip_funcs.zread_file = compressor_archive_functions::CustomArchiveRead;
+ zip_funcs.zwrite_file = compressor_archive_functions::CustomArchiveWrite;
+ zip_funcs.ztell_file = compressor_archive_functions::CustomArchiveTell;
+ zip_funcs.zseek_file = compressor_archive_functions::CustomArchiveSeek;
+ zip_funcs.zclose_file = compressor_archive_functions::CustomArchiveClose;
+ zip_funcs.zerror_file = compressor_archive_functions::CustomArchiveError;
+ zip_funcs.opaque = this;
+
+ zip_file_ = zipOpen2(NULL /* pathname */,
mtomasz 2017/04/10 07:15:08 NULL -> nullptr here and in other places
takise 2017/04/11 06:00:51 Done.
+ APPEND_STATUS_CREATE,
+ NULL /* globalcomment */,
+ &zip_funcs);
+ if (!zip_file_) {
+ set_error_message(compressor_archive_constants::kCreateArchiveError);
+ return false /* Error */;
+ }
+ return true /* Success */;
}
-void CompressorArchiveLibarchive::AddToArchive(
- const std::string& filename,
- int64_t file_size,
- time_t modification_time,
- bool is_directory) {
- entry = archive_entry_new();
-
- archive_entry_set_pathname(entry, filename.c_str());
- archive_entry_set_size(entry, file_size);
- archive_entry_set_mtime(entry, modification_time, 0 /* millisecond */);
-
- if (is_directory) {
- archive_entry_set_filetype(entry, AE_IFDIR);
- archive_entry_set_perm(
- entry, compressor_archive_constants::kDirectoryPermission);
- } else {
- archive_entry_set_filetype(entry, AE_IFREG);
- archive_entry_set_perm(
- entry, compressor_archive_constants::kFilePermission);
- }
- archive_write_header(archive_, entry);
- // If archive_errno() returns 0, the header was written correctly.
- if (archive_errno(archive_) != 0) {
- CloseArchive(true /* hasError */);
- return;
+bool CompressorArchiveLibarchive::AddToArchive(const std::string& _filename,
mtomasz 2017/04/10 07:15:08 nit: We never prefix with _. Can we keep filename
takise 2017/04/11 06:00:51 Done.
+ int64_t file_size,
+ int64_t modification_time,
+ bool is_directory) {
+ // Minizip takes filenames that end with '/' as directories.
+ std::string filename = _filename;
+ if (is_directory)
+ filename += "/";
mtomasz 2017/04/10 07:15:08 Does it work with Windows paths? If not, did it wo
+
+ // Fill zipfileMetadata with modification_time.
+ zip_fileinfo zipfileMetadata;
+ // modification_time is millisecond-based, while FromTimeT takes seconds.
+ base::Time tm = base::Time::FromTimeT((int64_t)modification_time / 1000);
+ base::Time::Exploded exploded_time = {};
+ tm.LocalExplode(&exploded_time);
+ zipfileMetadata.tmz_date.tm_sec = exploded_time.second;
+ zipfileMetadata.tmz_date.tm_min = exploded_time.minute;
+ zipfileMetadata.tmz_date.tm_hour = exploded_time.hour;
+ zipfileMetadata.tmz_date.tm_year = exploded_time.year;
+ zipfileMetadata.tmz_date.tm_mday = exploded_time.day_of_month;
+ // Convert from 1-based to 0-based.
+ zipfileMetadata.tmz_date.tm_mon = exploded_time.month - 1;
+
+ // Section 4.4.4 http://www.pkware.com/documents/casestudies/APPNOTE.TXT
+ // Setting the Language encoding flag so the file is told to be in utf-8.
+ const uLong LANGUAGE_ENCODING_FLAG = 0x1 << 11;
+
+ int open_result = zipOpenNewFileInZip4(zip_file_, // file
+ filename.c_str(), // filename
+ &zipfileMetadata, // zipfi
+ NULL, // extrafield_local
+ 0u, // size_extrafield_local
+ NULL, // extrafield_global
+ 0u, // size_extrafield_global
+ NULL, // comment
+ Z_DEFLATED, // method
+ Z_DEFAULT_COMPRESSION, // level
+ 0, // raw
+ -MAX_WBITS, // windowBits
+ DEF_MEM_LEVEL, // memLevel
+ Z_DEFAULT_STRATEGY, // strategy
+ NULL, // password
+ 0, // crcForCrypting
+ 0, // versionMadeBy
+ LANGUAGE_ENCODING_FLAG); // flagBase
+ if (open_result != ZIP_OK) {
+ CloseArchive(true /* has_error */);
+ set_error_message(compressor_archive_constants::kAddtoArchiveError);
+ return false /* Error */;
}
+ bool has_error = false;
if (!is_directory) {
int64_t remaining_size = file_size;
while (remaining_size > 0) {
int64_t chunk_size = std::min(remaining_size,
- compressor_archive_constants::kMaximumDataChunkSize);
+ compressor_stream_constants::kMaximumDataChunkSize);
PP_DCHECK(chunk_size > 0);
int64_t read_bytes =
compressor_stream_->Read(chunk_size, destination_buffer_);
+
// Negative read_bytes indicates an error occurred when reading chunks.
- if (read_bytes < 0) {
- CloseArchive(true /* hasError */);
+ // 0 just means there is no more data available, but here we need positive
+ // length of bytes, so this is also an error here.
+ if (read_bytes <= 0) {
+ has_error = true;
break;
}
- int64_t written_bytes =
- archive_write_data(archive_, destination_buffer_, read_bytes);
- // If archive_errno() returns 0, the buffer was written correctly.
- if (archive_errno(archive_) != 0) {
- CloseArchive(true /* hasError */);
+ if (zipWriteInFileInZip(zip_file_, destination_buffer_, read_bytes) !=
+ ZIP_OK) {
+ has_error = true;
break;
}
- PP_DCHECK(written_bytes > 0);
-
- remaining_size -= written_bytes;
+ remaining_size -= read_bytes;
}
}
- archive_entry_free(entry);
+ if (!has_error && zipCloseFileInZip(zip_file_) != ZIP_OK)
+ has_error = true;
+
+ if (has_error) {
+ CloseArchive(true /* has_error */);
+ set_error_message(compressor_archive_constants::kAddtoArchiveError);
+ return false /* Error */;
+ }
+
+ return true /* Success */;
}
-void CompressorArchiveLibarchive::CloseArchive(bool has_error) {
- // If has_error is true, mark the archive object as being unusable and
- // release resources without writing no more data on the archive.
- if (has_error)
- archive_write_fail(archive_);
- if (archive_) {
- archive_write_free(archive_);
- archive_ = NULL;
+bool CompressorArchiveLibarchive::CloseArchive(bool has_error) {
+ if (zipClose(zip_file_, NULL /* global_comment */) != ZIP_OK) {
+ set_error_message(compressor_archive_constants::kCloseArchiveError);
+ return false /* Error */;
+ }
+ if (!has_error) {
+ if (compressor_stream()->Flush() < 0) {
+ set_error_message(compressor_archive_constants::kCloseArchiveError);
+ return false /* Error */;
+ }
}
+ return true /* Success */;
}

Powered by Google App Engine
This is Rietveld 408576698