| OLD | NEW |
| 1 // Copyright 2014 The Chromium OS Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "volume_archive_libarchive.h" | 5 #include "volume_archive_libarchive.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <cerrno> | 8 #include <cerrno> |
| 9 #include <cstring> | 9 #include <cstring> |
| 10 #include <limits> | 10 #include <limits> |
| 11 #include <time.h> | 11 #include <time.h> |
| 12 | 12 |
| 13 #include "base/strings/string_util.h" | 13 #include "base/strings/string_util.h" |
| 14 #include "base/time/time.h" | 14 #include "base/time/time.h" |
| 15 #include "ppapi/cpp/logging.h" | 15 #include "ppapi/cpp/logging.h" |
| 16 | 16 |
| 17 namespace volume_archive_functions { | 17 namespace volume_archive_functions { |
| 18 void* CustomArchiveOpen(void* archive, | 18 void* CustomArchiveOpen(void* archive, |
| 19 const char* /* filename */, | 19 const char* /* filename */, |
| 20 int /* mode */) { | 20 int /* mode */) { |
| 21 return archive; | 21 return archive; |
| 22 } | 22 } |
| 23 | 23 |
| 24 int64_t DynamicCache(VolumeArchiveLibarchive* archive, int64_t unzip_size) { | 24 int64_t DynamicCache(VolumeArchiveMinizip* archive, int64_t unzip_size) { |
| 25 int64_t offset = archive->reader()->offset(); | 25 int64_t offset = archive->reader()->offset(); |
| 26 if (archive->reader()->Seek(static_cast<int64_t>(offset), | 26 if (archive->reader()->Seek(static_cast<int64_t>(offset), |
| 27 ZLIB_FILEFUNC_SEEK_SET) < 0) { | 27 ZLIB_FILEFUNC_SEEK_SET) < 0) { |
| 28 return -1 /* Error */; | 28 return -1 /* Error */; |
| 29 } | 29 } |
| 30 | 30 |
| 31 int64_t bytes_to_read = | 31 int64_t bytes_to_read = |
| 32 std::min(volume_archive_constants::kMaximumDataChunkSize, | 32 std::min(volume_archive_constants::kMaximumDataChunkSize, |
| 33 archive->reader()->archive_size() - offset); | 33 archive->reader()->archive_size() - offset); |
| 34 PP_DCHECK(bytes_to_read > 0); | 34 PP_DCHECK(bytes_to_read > 0); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 56 archive->dynamic_cache_size_ = bytes_to_read - left_length; | 56 archive->dynamic_cache_size_ = bytes_to_read - left_length; |
| 57 archive->dynamic_cache_offset_ = offset; | 57 archive->dynamic_cache_offset_ = offset; |
| 58 | 58 |
| 59 return unzip_size - left_length; | 59 return unzip_size - left_length; |
| 60 } | 60 } |
| 61 | 61 |
| 62 uLong CustomArchiveRead(void* archive, | 62 uLong CustomArchiveRead(void* archive, |
| 63 void* /* stream */, | 63 void* /* stream */, |
| 64 void* buffer, | 64 void* buffer, |
| 65 uLong size) { | 65 uLong size) { |
| 66 VolumeArchiveLibarchive* archive_minizip = | 66 VolumeArchiveMinizip* archive_minizip = |
| 67 static_cast<VolumeArchiveLibarchive*>(archive); | 67 static_cast<VolumeArchiveMinizip*>(archive); |
| 68 int64_t offset = archive_minizip->reader()->offset(); | 68 int64_t offset = archive_minizip->reader()->offset(); |
| 69 | 69 |
| 70 // When minizip requests a chunk in static_cache_. | 70 // When minizip requests a chunk in static_cache_. |
| 71 if (offset >= archive_minizip->static_cache_offset_) { | 71 if (offset >= archive_minizip->static_cache_offset_) { |
| 72 // Relative offset in the central directory. | 72 // Relative offset in the central directory. |
| 73 int64_t offset_in_cache = offset - archive_minizip->static_cache_offset_; | 73 int64_t offset_in_cache = offset - archive_minizip->static_cache_offset_; |
| 74 memcpy(buffer, archive_minizip->static_cache_ + offset_in_cache, size); | 74 memcpy(buffer, archive_minizip->static_cache_ + offset_in_cache, size); |
| 75 if (archive_minizip->reader()->Seek(static_cast<int64_t>(size), | 75 if (archive_minizip->reader()->Seek(static_cast<int64_t>(size), |
| 76 ZLIB_FILEFUNC_SEEK_CUR) < 0) { | 76 ZLIB_FILEFUNC_SEEK_CUR) < 0) { |
| 77 return -1 /* Error */; | 77 return -1 /* Error */; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 114 } | 114 } |
| 115 | 115 |
| 116 uLong CustomArchiveWrite(void* /*archive*/, | 116 uLong CustomArchiveWrite(void* /*archive*/, |
| 117 void* /*stream*/, | 117 void* /*stream*/, |
| 118 const void* /*buffer*/, | 118 const void* /*buffer*/, |
| 119 uLong /*length*/) { | 119 uLong /*length*/) { |
| 120 return 0 /* Success */; | 120 return 0 /* Success */; |
| 121 } | 121 } |
| 122 | 122 |
| 123 long CustomArchiveTell(void* archive, void* /*stream*/) { | 123 long CustomArchiveTell(void* archive, void* /*stream*/) { |
| 124 VolumeArchiveLibarchive* archive_minizip = | 124 VolumeArchiveMinizip* archive_minizip = |
| 125 static_cast<VolumeArchiveLibarchive*>(archive); | 125 static_cast<VolumeArchiveMinizip*>(archive); |
| 126 return static_cast<long>(archive_minizip->reader()->offset()); | 126 return static_cast<long>(archive_minizip->reader()->offset()); |
| 127 } | 127 } |
| 128 | 128 |
| 129 long CustomArchiveSeek(void* archive, | 129 long CustomArchiveSeek(void* archive, |
| 130 void* /*stream*/, | 130 void* /*stream*/, |
| 131 uLong offset, | 131 uLong offset, |
| 132 int origin) { | 132 int origin) { |
| 133 VolumeArchiveLibarchive* archive_minizip = | 133 VolumeArchiveMinizip* archive_minizip = |
| 134 static_cast<VolumeArchiveLibarchive*>(archive); | 134 static_cast<VolumeArchiveMinizip*>(archive); |
| 135 | 135 |
| 136 long return_value = static_cast<long>(archive_minizip->reader()->Seek( | 136 long return_value = static_cast<long>(archive_minizip->reader()->Seek( |
| 137 static_cast<int64_t>(offset), static_cast<int64_t>(origin))); | 137 static_cast<int64_t>(offset), static_cast<int64_t>(origin))); |
| 138 if (return_value >= 0) | 138 if (return_value >= 0) |
| 139 return 0 /* Success */; | 139 return 0 /* Success */; |
| 140 return -1 /* Error */; | 140 return -1 /* Error */; |
| 141 } | 141 } |
| 142 | 142 |
| 143 int CustomArchiveClose(void* /*opaque*/, void* /*stream*/) { | 143 int CustomArchiveClose(void* /*opaque*/, void* /*stream*/) { |
| 144 return 0; | 144 return 0; |
| 145 } | 145 } |
| 146 | 146 |
| 147 int CustomArchiveError(void* /*opaque*/, void* /*stream*/) { | 147 int CustomArchiveError(void* /*opaque*/, void* /*stream*/) { |
| 148 return 0; | 148 return 0; |
| 149 } | 149 } |
| 150 | 150 |
| 151 const char* GetPassphrase(VolumeArchiveLibarchive* archive_minizip) { | 151 const char* GetPassphrase(VolumeArchiveMinizip* archive_minizip) { |
| 152 const char* password = archive_minizip->reader()->Passphrase(); | 152 const char* password = archive_minizip->reader()->Passphrase(); |
| 153 return password; | 153 return password; |
| 154 } | 154 } |
| 155 | 155 |
| 156 } // volume_archive_functions | 156 } // volume_archive_functions |
| 157 | 157 |
| 158 VolumeArchiveLibarchive::VolumeArchiveLibarchive(VolumeReader* reader) | 158 VolumeArchiveMinizip::VolumeArchiveMinizip(VolumeReader* reader) |
| 159 : VolumeArchive(reader), | 159 : VolumeArchive(reader), |
| 160 reader_data_size_(volume_archive_constants::kMinimumDataChunkSize), | 160 reader_data_size_(volume_archive_constants::kMinimumDataChunkSize), |
| 161 zip_file_(nullptr), | 161 zip_file_(nullptr), |
| 162 dynamic_cache_offset_(0), | 162 dynamic_cache_offset_(0), |
| 163 dynamic_cache_size_(0), | 163 dynamic_cache_size_(0), |
| 164 static_cache_offset_(0), | 164 static_cache_offset_(0), |
| 165 static_cache_size_(0), | 165 static_cache_size_(0), |
| 166 last_read_data_offset_(0), | 166 last_read_data_offset_(0), |
| 167 last_read_data_length_(0), | 167 last_read_data_length_(0), |
| 168 decompressed_data_(nullptr), | 168 decompressed_data_(nullptr), |
| 169 decompressed_data_size_(0), | 169 decompressed_data_size_(0), |
| 170 decompressed_error_(false) {} | 170 decompressed_error_(false) {} |
| 171 | 171 |
| 172 VolumeArchiveLibarchive::~VolumeArchiveLibarchive() { | 172 VolumeArchiveMinizip::~VolumeArchiveMinizip() { |
| 173 Cleanup(); | 173 Cleanup(); |
| 174 } | 174 } |
| 175 | 175 |
| 176 bool VolumeArchiveLibarchive::Init(const std::string& encoding) { | 176 bool VolumeArchiveMinizip::Init(const std::string& encoding) { |
| 177 // Set up minizip object. | 177 // Set up minizip object. |
| 178 zlib_filefunc_def zip_funcs; | 178 zlib_filefunc_def zip_funcs; |
| 179 zip_funcs.zopen_file = volume_archive_functions::CustomArchiveOpen; | 179 zip_funcs.zopen_file = volume_archive_functions::CustomArchiveOpen; |
| 180 zip_funcs.zread_file = volume_archive_functions::CustomArchiveRead; | 180 zip_funcs.zread_file = volume_archive_functions::CustomArchiveRead; |
| 181 zip_funcs.zwrite_file = volume_archive_functions::CustomArchiveWrite; | 181 zip_funcs.zwrite_file = volume_archive_functions::CustomArchiveWrite; |
| 182 zip_funcs.ztell_file = volume_archive_functions::CustomArchiveTell; | 182 zip_funcs.ztell_file = volume_archive_functions::CustomArchiveTell; |
| 183 zip_funcs.zseek_file = volume_archive_functions::CustomArchiveSeek; | 183 zip_funcs.zseek_file = volume_archive_functions::CustomArchiveSeek; |
| 184 zip_funcs.zclose_file = volume_archive_functions::CustomArchiveClose; | 184 zip_funcs.zclose_file = volume_archive_functions::CustomArchiveClose; |
| 185 zip_funcs.zerror_file = volume_archive_functions::CustomArchiveError; | 185 zip_funcs.zerror_file = volume_archive_functions::CustomArchiveError; |
| 186 zip_funcs.opaque = static_cast<void*>(this); | 186 zip_funcs.opaque = static_cast<void*>(this); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 215 | 215 |
| 216 zip_file_ = unzOpen2(nullptr /* filename */, &zip_funcs); | 216 zip_file_ = unzOpen2(nullptr /* filename */, &zip_funcs); |
| 217 if (!zip_file_) { | 217 if (!zip_file_) { |
| 218 set_error_message(volume_archive_constants::kArchiveOpenError); | 218 set_error_message(volume_archive_constants::kArchiveOpenError); |
| 219 return false; | 219 return false; |
| 220 } | 220 } |
| 221 | 221 |
| 222 return true; | 222 return true; |
| 223 } | 223 } |
| 224 | 224 |
| 225 VolumeArchive::Result VolumeArchiveLibarchive::GetCurrentFileInfo( | 225 VolumeArchive::Result VolumeArchiveMinizip::GetCurrentFileInfo( |
| 226 std::string* pathname, | 226 std::string* pathname, |
| 227 int64_t* size, | 227 int64_t* size, |
| 228 bool* is_directory, | 228 bool* is_directory, |
| 229 time_t* modification_time) { | 229 time_t* modification_time) { |
| 230 | 230 |
| 231 // Headers are being read from the central directory (in the ZIP format), so | 231 // Headers are being read from the central directory (in the ZIP format), so |
| 232 // use a large block size to save on IPC calls. The headers in EOCD are | 232 // use a large block size to save on IPC calls. The headers in EOCD are |
| 233 // grouped one by one. | 233 // grouped one by one. |
| 234 reader_data_size_ = volume_archive_constants::kMaximumDataChunkSize; | 234 reader_data_size_ = volume_archive_constants::kMaximumDataChunkSize; |
| 235 | 235 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 281 base::Time local_time; | 281 base::Time local_time; |
| 282 // If the modification time is not available, we set the value to the current | 282 // If the modification time is not available, we set the value to the current |
| 283 // local time. | 283 // local time. |
| 284 if (!base::Time::FromLocalExploded(exploded_time, &local_time)) | 284 if (!base::Time::FromLocalExploded(exploded_time, &local_time)) |
| 285 local_time = base::Time::UnixEpoch(); | 285 local_time = base::Time::UnixEpoch(); |
| 286 *modification_time = local_time.ToTimeT(); | 286 *modification_time = local_time.ToTimeT(); |
| 287 | 287 |
| 288 return VolumeArchive::RESULT_SUCCESS; | 288 return VolumeArchive::RESULT_SUCCESS; |
| 289 } | 289 } |
| 290 | 290 |
| 291 VolumeArchive::Result VolumeArchiveLibarchive::GoToNextFile() { | 291 VolumeArchive::Result VolumeArchiveMinizip::GoToNextFile() { |
| 292 int return_value = unzGoToNextFile(zip_file_); | 292 int return_value = unzGoToNextFile(zip_file_); |
| 293 if (return_value == UNZ_END_OF_LIST_OF_FILE) { | 293 if (return_value == UNZ_END_OF_LIST_OF_FILE) { |
| 294 return VolumeArchive::RESULT_EOF; | 294 return VolumeArchive::RESULT_EOF; |
| 295 } | 295 } |
| 296 if (return_value == UNZ_OK) | 296 if (return_value == UNZ_OK) |
| 297 return VolumeArchive::RESULT_SUCCESS; | 297 return VolumeArchive::RESULT_SUCCESS; |
| 298 | 298 |
| 299 set_error_message(volume_archive_constants::kArchiveNextHeaderError); | 299 set_error_message(volume_archive_constants::kArchiveNextHeaderError); |
| 300 return VolumeArchive::RESULT_FAIL; | 300 return VolumeArchive::RESULT_FAIL; |
| 301 } | 301 } |
| 302 | 302 |
| 303 bool VolumeArchiveLibarchive::SeekHeader(const std::string& path_name) { | 303 bool VolumeArchiveMinizip::SeekHeader(const std::string& path_name) { |
| 304 // Reset to 0 for new VolumeArchive::ReadData operation. | 304 // Reset to 0 for new VolumeArchive::ReadData operation. |
| 305 last_read_data_offset_ = 0; | 305 last_read_data_offset_ = 0; |
| 306 decompressed_data_size_ = 0; | 306 decompressed_data_size_ = 0; |
| 307 | 307 |
| 308 const int kDefaultCaseSensivityOfOS = 0; | 308 const int kDefaultCaseSensivityOfOS = 0; |
| 309 if (unzLocateFile(zip_file_, path_name.c_str(), kDefaultCaseSensivityOfOS) != | 309 if (unzLocateFile(zip_file_, path_name.c_str(), kDefaultCaseSensivityOfOS) != |
| 310 UNZ_OK) { | 310 UNZ_OK) { |
| 311 set_error_message(volume_archive_constants::kArchiveNextHeaderError); | 311 set_error_message(volume_archive_constants::kArchiveNextHeaderError); |
| 312 return false; | 312 return false; |
| 313 } | 313 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 345 } | 345 } |
| 346 | 346 |
| 347 if (open_result != UNZ_OK) { | 347 if (open_result != UNZ_OK) { |
| 348 set_error_message(volume_archive_constants::kArchiveNextHeaderError); | 348 set_error_message(volume_archive_constants::kArchiveNextHeaderError); |
| 349 return false; | 349 return false; |
| 350 } | 350 } |
| 351 | 351 |
| 352 return true; | 352 return true; |
| 353 } | 353 } |
| 354 | 354 |
| 355 void VolumeArchiveLibarchive::DecompressData(int64_t offset, int64_t length) { | 355 void VolumeArchiveMinizip::DecompressData(int64_t offset, int64_t length) { |
| 356 // TODO(cmihail): As an optimization consider using archive_read_data_block | 356 // TODO(cmihail): As an optimization consider using archive_read_data_block |
| 357 // which avoids extra copying in case offset != last_read_data_offset_. | 357 // which avoids extra copying in case offset != last_read_data_offset_. |
| 358 // The logic will be more complicated because archive_read_data_block offset | 358 // The logic will be more complicated because archive_read_data_block offset |
| 359 // will not be aligned with the offset of the read request from JavaScript. | 359 // will not be aligned with the offset of the read request from JavaScript. |
| 360 | 360 |
| 361 // Requests with offset smaller than last read offset are not supported. | 361 // Requests with offset smaller than last read offset are not supported. |
| 362 if (offset < last_read_data_offset_) { | 362 if (offset < last_read_data_offset_) { |
| 363 set_error_message( | 363 set_error_message( |
| 364 std::string(volume_archive_constants::kArchiveReadDataError)); | 364 std::string(volume_archive_constants::kArchiveReadDataError)); |
| 365 decompressed_error_ = true; | 365 decompressed_error_ = true; |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 425 left_length); | 425 left_length); |
| 426 if (size < 0) { // Error. | 426 if (size < 0) { // Error. |
| 427 set_error_message(volume_archive_constants::kArchiveReadDataError); | 427 set_error_message(volume_archive_constants::kArchiveReadDataError); |
| 428 decompressed_error_ = true; | 428 decompressed_error_ = true; |
| 429 return; | 429 return; |
| 430 } | 430 } |
| 431 bytes_read += size; | 431 bytes_read += size; |
| 432 left_length -= size; | 432 left_length -= size; |
| 433 } while (left_length > 0 && size != 0); // There is still data to read. | 433 } while (left_length > 0 && size != 0); // There is still data to read. |
| 434 | 434 |
| 435 // VolumeArchiveLibarchive::DecompressData always stores the data from | 435 // VolumeArchiveMinizip::DecompressData always stores the data from |
| 436 // beginning of the buffer. VolumeArchiveLibarchive::ConsumeData is used | 436 // beginning of the buffer. VolumeArchiveMinizip::ConsumeData is used |
| 437 // to preserve the bytes that are decompressed but not required by | 437 // to preserve the bytes that are decompressed but not required by |
| 438 // VolumeArchiveLibarchive::ReadData. | 438 // VolumeArchiveMinizip::ReadData. |
| 439 decompressed_data_ = decompressed_data_buffer_; | 439 decompressed_data_ = decompressed_data_buffer_; |
| 440 decompressed_data_size_ = bytes_read; | 440 decompressed_data_size_ = bytes_read; |
| 441 } | 441 } |
| 442 | 442 |
| 443 bool VolumeArchiveLibarchive::Cleanup() { | 443 bool VolumeArchiveMinizip::Cleanup() { |
| 444 bool returnValue = true; | 444 bool returnValue = true; |
| 445 if (zip_file_) { | 445 if (zip_file_) { |
| 446 if (unzClose(zip_file_) != UNZ_OK) { | 446 if (unzClose(zip_file_) != UNZ_OK) { |
| 447 set_error_message(volume_archive_constants::kArchiveReadFreeError); | 447 set_error_message(volume_archive_constants::kArchiveReadFreeError); |
| 448 returnValue = false; | 448 returnValue = false; |
| 449 } | 449 } |
| 450 } | 450 } |
| 451 zip_file_ = nullptr; | 451 zip_file_ = nullptr; |
| 452 | 452 |
| 453 CleanupReader(); | 453 CleanupReader(); |
| 454 | 454 |
| 455 return returnValue; | 455 return returnValue; |
| 456 } | 456 } |
| 457 | 457 |
| 458 int64_t VolumeArchiveLibarchive::ReadData(int64_t offset, | 458 int64_t VolumeArchiveMinizip::ReadData(int64_t offset, |
| 459 int64_t length, | 459 int64_t length, |
| 460 const char** buffer) { | 460 const char** buffer) { |
| 461 PP_DCHECK(length > 0); // Length must be at least 1. | 461 PP_DCHECK(length > 0); // Length must be at least 1. |
| 462 PP_DCHECK(current_archive_entry_); // Check that GetNextHeader was called at | 462 PP_DCHECK(current_archive_entry_); // Check that GetNextHeader was called at |
| 463 // least once. In case it wasn't, this is | 463 // least once. In case it wasn't, this is |
| 464 // a programmer error. | 464 // a programmer error. |
| 465 // In case of first read or no more available data in the internal buffer or | 465 // In case of first read or no more available data in the internal buffer or |
| 466 // offset is different from the last_read_data_offset_, then force | 466 // offset is different from the last_read_data_offset_, then force |
| 467 // VolumeArchiveLibarchive::DecompressData as the decompressed data is | 467 // VolumeArchiveMinizip::DecompressData as the decompressed data is |
| 468 // invalid. | 468 // invalid. |
| 469 if (!decompressed_data_ || last_read_data_offset_ != offset || | 469 if (!decompressed_data_ || last_read_data_offset_ != offset || |
| 470 decompressed_data_size_ == 0) | 470 decompressed_data_size_ == 0) |
| 471 DecompressData(offset, length); | 471 DecompressData(offset, length); |
| 472 | 472 |
| 473 // Decompressed failed. | 473 // Decompressed failed. |
| 474 if (decompressed_error_) { | 474 if (decompressed_error_) { |
| 475 set_error_message(volume_archive_constants::kArchiveReadDataError); | 475 set_error_message(volume_archive_constants::kArchiveReadDataError); |
| 476 return -1 /* Error */; | 476 return -1 /* Error */; |
| 477 } | 477 } |
| 478 | 478 |
| 479 last_read_data_length_ = length; // Used for decompress ahead. | 479 last_read_data_length_ = length; // Used for decompress ahead. |
| 480 | 480 |
| 481 // Assign the output *buffer parameter to the internal buffer. | 481 // Assign the output *buffer parameter to the internal buffer. |
| 482 *buffer = decompressed_data_; | 482 *buffer = decompressed_data_; |
| 483 | 483 |
| 484 // Advance internal buffer for next ReadData call. | 484 // Advance internal buffer for next ReadData call. |
| 485 int64_t read_bytes = std::min(decompressed_data_size_, length); | 485 int64_t read_bytes = std::min(decompressed_data_size_, length); |
| 486 decompressed_data_ = decompressed_data_ + read_bytes; | 486 decompressed_data_ = decompressed_data_ + read_bytes; |
| 487 decompressed_data_size_ -= read_bytes; | 487 decompressed_data_size_ -= read_bytes; |
| 488 last_read_data_offset_ += read_bytes; | 488 last_read_data_offset_ += read_bytes; |
| 489 | 489 |
| 490 PP_DCHECK(decompressed_data_ + decompressed_data_size_ <= | 490 PP_DCHECK(decompressed_data_ + decompressed_data_size_ <= |
| 491 decompressed_data_buffer_ + | 491 decompressed_data_buffer_ + |
| 492 volume_archive_constants::kDecompressBufferSize); | 492 volume_archive_constants::kDecompressBufferSize); |
| 493 | 493 |
| 494 return read_bytes; | 494 return read_bytes; |
| 495 } | 495 } |
| 496 | 496 |
| 497 void VolumeArchiveLibarchive::MaybeDecompressAhead() { | 497 void VolumeArchiveMinizip::MaybeDecompressAhead() { |
| 498 if (decompressed_data_size_ == 0) | 498 if (decompressed_data_size_ == 0) |
| 499 DecompressData(last_read_data_offset_, last_read_data_length_); | 499 DecompressData(last_read_data_offset_, last_read_data_length_); |
| 500 } | 500 } |
| OLD | NEW |