| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 The Chromium OS Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #ifndef VOLUME_ARCHIVE_MINIZIP_H_ | |
| 6 #define VOLUME_ARCHIVE_MINIZIP_H_ | |
| 7 | |
| 8 #include <string> | |
| 9 | |
| 10 #include "third_party/zlib/contrib/minizip/unzip.h" | |
| 11 #include "third_party/zlib/contrib/minizip/zip.h" | |
| 12 | |
| 13 #include "volume_archive.h" | |
| 14 | |
| 15 // A namespace with constants used by VolumeArchiveMinizip. | |
| 16 namespace volume_archive_constants { | |
| 17 | |
| 18 const char kArchiveReadNewError[] = "Could not allocate archive."; | |
| 19 const char kFileNotFound[] = "File not found for read data request."; | |
| 20 const char kVolumeReaderError[] = "VolumeReader failed to retrieve data."; | |
| 21 const char kArchiveOpenError[] = "Failed to open archive."; | |
| 22 const char kArchiveNextHeaderError[] = | |
| 23 "Failed to open current file in archive."; | |
| 24 const char kArchiveReadDataError[] = "Failed to read archive data."; | |
| 25 const char kArchiveReadFreeError[] = "Failed to close archive."; | |
| 26 | |
| 27 // The size of the buffer used to skip unnecessary data. | |
| 28 // Should be positive and less than size_t maximum. | |
| 29 const int64_t kDummyBufferSize = 512 * 1024; // 512 KB | |
| 30 | |
| 31 // The size of the buffer used by ReadInProgress to decompress data. | |
| 32 // Should be positive and less than size_t maximum. | |
| 33 const int64_t kDecompressBufferSize = 512 * 1024; // 512 KB. | |
| 34 | |
| 35 // The maximum data chunk size for VolumeReader::Read requests. | |
| 36 // Should be positive. | |
| 37 const int64_t kMaximumDataChunkSize = 512 * 1024; // 512 KB. | |
| 38 | |
| 39 // The minimum data chunk size for VolumeReader::Read requests. | |
| 40 // Should be positive. | |
| 41 const int64_t kMinimumDataChunkSize = 32 * 1024; // 16 KB. | |
| 42 | |
| 43 // Maximum length of filename in zip archive. | |
| 44 const int kZipMaxPath = 256; | |
| 45 | |
| 46 // The size of the static cache. We need at least 64KB to cache whole | |
| 47 // 'end of central directory' data. | |
| 48 const int64_t kStaticCacheSize = 128 * 1024; | |
| 49 | |
| 50 } // namespace volume_archive_constants | |
| 51 | |
| 52 class VolumeArchiveMinizip; | |
| 53 | |
| 54 // A namespace with custom functions passed to minizip. | |
| 55 namespace volume_archive_functions { | |
| 56 | |
| 57 int64_t DynamicCache(VolumeArchiveMinizip* archive, int64_t unz_size); | |
| 58 | |
| 59 uLong CustomArchiveRead(void* archive, void* stream, void* buf, uLong size); | |
| 60 | |
| 61 // Returns the offset from the beginning of the data. | |
| 62 long CustomArchiveTell(void* archive, void* stream); | |
| 63 | |
| 64 // Moves the current offset to the specified position. | |
| 65 long CustomArchiveSeek(void* archive, | |
| 66 void* stream, | |
| 67 uLong offset, | |
| 68 int origin); | |
| 69 | |
| 70 } // compressor_archive_functions | |
| 71 | |
| 72 | |
| 73 class VolumeArchiveMinizip; | |
| 74 | |
| 75 // Defines an implementation of VolumeArchive that wraps all minizip | |
| 76 // operations. | |
| 77 class VolumeArchiveMinizip : public VolumeArchive { | |
| 78 public: | |
| 79 explicit VolumeArchiveMinizip(VolumeReader* reader); | |
| 80 | |
| 81 virtual ~VolumeArchiveMinizip(); | |
| 82 | |
| 83 // See volume_archive_interface.h. | |
| 84 virtual bool Init(const std::string& encoding); | |
| 85 | |
| 86 // See volume_archive_interface.h. | |
| 87 virtual VolumeArchive::Result GetCurrentFileInfo(std::string* path_name, | |
| 88 int64_t* size, | |
| 89 bool* is_directory, | |
| 90 time_t* modification_time); | |
| 91 | |
| 92 virtual VolumeArchive::Result GoToNextFile(); | |
| 93 | |
| 94 // See volume_archive_interface.h. | |
| 95 virtual bool SeekHeader(const std::string& path_name); | |
| 96 | |
| 97 // See volume_archive_interface.h. | |
| 98 virtual int64_t ReadData(int64_t offset, int64_t length, const char** buffer); | |
| 99 | |
| 100 // See volume_archive_interface.h. | |
| 101 virtual void MaybeDecompressAhead(); | |
| 102 | |
| 103 // See volume_archive_interface.h. | |
| 104 virtual bool Cleanup(); | |
| 105 | |
| 106 int64_t reader_data_size() const { return reader_data_size_; } | |
| 107 | |
| 108 // Custom functions need to access private variables of | |
| 109 // CompressorArchiveMinizip frequently. | |
| 110 friend int64_t volume_archive_functions::DynamicCache( | |
| 111 VolumeArchiveMinizip* va, int64_t unz_size); | |
| 112 | |
| 113 friend uLong volume_archive_functions::CustomArchiveRead( | |
| 114 void* archive, void* stream, void* buf, uLong size); | |
| 115 | |
| 116 friend long volume_archive_functions::CustomArchiveTell( | |
| 117 void* archive, void* stream); | |
| 118 | |
| 119 friend long volume_archive_functions::CustomArchiveSeek( | |
| 120 void* archive, void* stream, uLong offset, int origin); | |
| 121 | |
| 122 private: | |
| 123 // Decompress length bytes of data starting from offset. | |
| 124 void DecompressData(int64_t offset, int64_t length); | |
| 125 | |
| 126 // The size of the requested data from VolumeReader. | |
| 127 int64_t reader_data_size_; | |
| 128 | |
| 129 // The minizip correspondent archive object. | |
| 130 zipFile zip_file_; | |
| 131 | |
| 132 // We use two kinds of cache strategies here: dynamic and static. | |
| 133 // Dynamic cache is a common cache strategy used in most of IO streams such as | |
| 134 // fread. When a file chunk is requested and if the size of the requested | |
| 135 // chunk is small, we load larger size of bytes from the archive and cache | |
| 136 // them in dynamic_cache_. If the range of the next requested chunk is within | |
| 137 // the cache, we don't read the archive and just return the data in the cache. | |
| 138 char dynamic_cache_[volume_archive_constants::kMaximumDataChunkSize]; | |
| 139 | |
| 140 // The offset from which dynamic_cache_ has the data of the archive. | |
| 141 int64_t dynamic_cache_offset_; | |
| 142 | |
| 143 // The size of the data in dynamic_cache_. | |
| 144 int64_t dynamic_cache_size_; | |
| 145 | |
| 146 // Although dynamic cache works in most situations, it doesn't work when | |
| 147 // MiniZip is looking for the front index of the central directory. Since | |
| 148 // MiniZip reads the data little by little backwards from the end to find the | |
| 149 // index, dynamic_cache will be reloaded every time. To avoid this, we first | |
| 150 // cache a certain length of data from the end into static_cache_. The data | |
| 151 // in this buffer is also used when the data in the central directory is | |
| 152 // requested by MiniZip later. | |
| 153 char static_cache_[volume_archive_constants::kStaticCacheSize]; | |
| 154 | |
| 155 // The offset from which static_cache_ has the data of the archive. | |
| 156 int64_t static_cache_offset_; | |
| 157 | |
| 158 // The size of the data in static_cache_. The End Of Central Directory header | |
| 159 // is guaranteed to be in the last 64(global comment) + 1(other fields) of the | |
| 160 // file. This cache is used to store the header. | |
| 161 int64_t static_cache_size_; | |
| 162 | |
| 163 // The data offset, which will be offset + length after last read | |
| 164 // operation, where offset and length are method parameters for | |
| 165 // VolumeArchiveMinizip::ReadData. Data offset is used to improve | |
| 166 // performance for consecutive calls to VolumeArchiveMinizip::ReadData. | |
| 167 // | |
| 168 // Intead of starting the read from the beginning for every | |
| 169 // VolumeArchiveMinizip::ReadData, the next call will start | |
| 170 // from last_read_data_offset_ in case the offset parameter of | |
| 171 // VolumeArchiveMinizip::ReadData has the same value as | |
| 172 // last_read_data_offset_. This avoids decompressing again the bytes at | |
| 173 // the begninning of the file, which is the average case scenario. | |
| 174 // But in case the offset parameter is different than last_read_data_offset_, | |
| 175 // then dummy_buffer_ will be used to ignore unused bytes. | |
| 176 int64_t last_read_data_offset_; | |
| 177 | |
| 178 // The length of the last VolumeArchiveMinizip::ReadData. Used for | |
| 179 // decompress ahead. | |
| 180 int64_t last_read_data_length_; | |
| 181 | |
| 182 // Dummy buffer for unused data read using VolumeArchiveMinizip::ReadData. | |
| 183 // Sometimes VolumeArchiveMinizip::ReadData can require reading from | |
| 184 // offsets different from last_read_data_offset_. In this case some bytes | |
| 185 // must be skipped. Because seeking is not possible inside compressed files, | |
| 186 // the bytes will be discarded using this buffer. | |
| 187 char dummy_buffer_[volume_archive_constants::kDummyBufferSize]; | |
| 188 | |
| 189 // The address where the decompressed data starting from | |
| 190 // decompressed_offset_ is stored. It should point to a valid location | |
| 191 // inside decompressed_data_buffer_. Necesssary in order to NOT throw | |
| 192 // away unused decompressed bytes as throwing them away would mean in some | |
| 193 // situations restarting decompressing the file from the beginning. | |
| 194 char* decompressed_data_; | |
| 195 | |
| 196 // The actual buffer that contains the decompressed data. | |
| 197 char decompressed_data_buffer_ | |
| 198 [volume_archive_constants::kDecompressBufferSize]; | |
| 199 | |
| 200 // The size of valid data starting from decompressed_data_ that is stored | |
| 201 // inside decompressed_data_buffer_. | |
| 202 int64_t decompressed_data_size_; | |
| 203 | |
| 204 // True if VolumeArchiveMinizip::DecompressData failed. | |
| 205 bool decompressed_error_; | |
| 206 }; | |
| 207 | |
| 208 #endif // VOLUME_ARCHIVE_MINIZIP_H_ | |
| OLD | NEW |