diff --git a/assets/BUILD.gn b/assets/BUILD.gn index df6a4253c0d..b1a09d5ddb1 100644 --- a/assets/BUILD.gn +++ b/assets/BUILD.gn @@ -13,6 +13,7 @@ source_set("assets") { ] deps = [ + "//flutter/fml", "//lib/ftl", "//lib/zip", "//third_party/zlib:minizip", diff --git a/assets/zip_asset_store.cc b/assets/zip_asset_store.cc index f05096149e8..6af97fdb920 100644 --- a/assets/zip_asset_store.cc +++ b/assets/zip_asset_store.cc @@ -7,34 +7,41 @@ #include #include +#include #include +#include "flutter/fml/trace_event.h" #include "lib/ftl/files/eintr_wrapper.h" #include "lib/ftl/files/unique_fd.h" #include "lib/zip/unique_unzipper.h" -#include "third_party/zlib/contrib/minizip/unzip.h" namespace blink { ZipAssetStore::ZipAssetStore(UnzipperProvider unzipper_provider) - : unzipper_provider_(std::move(unzipper_provider)) {} + : unzipper_provider_(std::move(unzipper_provider)) { + BuildStatCache(); +} -ZipAssetStore::~ZipAssetStore() {} +ZipAssetStore::~ZipAssetStore() = default; bool ZipAssetStore::GetAsBuffer(const std::string& asset_name, std::vector* data) { - zip::UniqueUnzipper unzipper = unzipper_provider_(); - if (!unzipper.is_valid()) - return false; + TRACE_EVENT0("flutter", "ZipAssetStore::GetAsBuffer"); + auto found = stat_cache_.find(asset_name); - int result = unzLocateFile(unzipper.get(), asset_name.c_str(), 0); - if (result != UNZ_OK) { + if (found == stat_cache_.end()) { return false; } - unz_file_info file_info; - result = unzGetCurrentFileInfo(unzipper.get(), &file_info, nullptr, 0, - nullptr, 0, nullptr, 0); + auto unzipper = unzipper_provider_(); + + if (!unzipper.is_valid()) { + return false; + } + + int result = UNZ_OK; + + result = unzGoToFilePos(unzipper.get(), &(found->second.file_pos)); if (result != UNZ_OK) { FTL_LOG(WARNING) << "unzGetCurrentFileInfo failed, error=" << result; return false; @@ -46,17 +53,60 @@ bool ZipAssetStore::GetAsBuffer(const std::string& asset_name, return false; } - data->resize(file_info.uncompressed_size); + data->resize(found->second.uncompressed_size); int total_read = 0; while (total_read < static_cast(data->size())) { int bytes_read = unzReadCurrentFile( unzipper.get(), data->data() + total_read, data->size() - total_read); - if (bytes_read <= 0) + if (bytes_read <= 0) { return false; + } total_read += bytes_read; } return true; } +void ZipAssetStore::BuildStatCache() { + TRACE_EVENT0("flutter", "ZipAssetStore::BuildStatCache"); + auto unzipper = unzipper_provider_(); + + if (!unzipper.is_valid()) { + return; + } + + if (unzGoToFirstFile(unzipper.get()) != UNZ_OK) { + return; + } + + do { + int result = UNZ_OK; + + // Get the current file name. + unz_file_info file_info = {}; + char file_name[255]; + result = unzGetCurrentFileInfo(unzipper.get(), &file_info, file_name, + sizeof(file_name), nullptr, 0, nullptr, 0); + if (result != UNZ_OK) { + continue; + } + + if (file_info.uncompressed_size == 0) { + continue; + } + + // Get the current file position. + unz_file_pos file_pos = {}; + result = unzGetFilePos(unzipper.get(), &file_pos); + if (result != UNZ_OK) { + continue; + } + + std::string file_name_key(file_name, file_info.size_filename); + CacheEntry entry(file_pos, file_info.uncompressed_size); + stat_cache_.emplace(std::move(file_name_key), std::move(entry)); + + } while (unzGoToNextFile(unzipper.get()) == UNZ_OK); +} + } // namespace blink diff --git a/assets/zip_asset_store.h b/assets/zip_asset_store.h index 3d4cc3ff346..971fafe9075 100644 --- a/assets/zip_asset_store.h +++ b/assets/zip_asset_store.h @@ -11,6 +11,7 @@ #include "flutter/assets/unzipper_provider.h" #include "lib/ftl/macros.h" #include "lib/ftl/memory/ref_counted.h" +#include "third_party/zlib/contrib/minizip/unzip.h" namespace blink { @@ -22,7 +23,17 @@ class ZipAssetStore : public ftl::RefCountedThreadSafe { bool GetAsBuffer(const std::string& asset_name, std::vector* data); private: + struct CacheEntry { + unz_file_pos file_pos; + size_t uncompressed_size; + CacheEntry(unz_file_pos p_file_pos, size_t p_uncompressed_size) + : file_pos(p_file_pos), uncompressed_size(p_uncompressed_size) {} + }; + UnzipperProvider unzipper_provider_; + std::map stat_cache_; + + void BuildStatCache(); FTL_DISALLOW_COPY_AND_ASSIGN(ZipAssetStore); };