blob: fde019aa390a72adca8aec3882bf99d46fc1f577 [file] [log] [blame]
// Copyright 2014 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <string>
#include "archive.h"
#include "volume_archive.h"
// A namespace with constants used by VolumeArchiveLibarchive.
namespace volume_archive_constants {
const char kArchiveReadNewError[] = "Could not allocate archive.";
const char kFileNotFound[] = "File not found for read data request.";
const char kVolumeReaderError[] = "VolumeReader failed to retrieve data.";
const char kArchiveSupportErrorPrefix[] = "Error at support rar/zip format: ";
const char kArchiveOpenErrorPrefix[] = "Error at open archive: ";
const char kArchiveNextHeaderErrorPrefix[] =
"Error at reading next header for metadata: ";
const char kArchiveReadDataErrorPrefix[] = "Error at reading data: ";
const char kArchiveReadFreeErrorPrefix[] = "Error at archive free: ";
// The size of the buffer used to skip unnecessary data.
// Should be positive and less than size_t maximum.
const int64_t kDummyBufferSize = 512 * 1024; // 512 KB
// The size of the buffer used by ReadInProgress to decompress data.
// Should be positive and less than size_t maximum.
const int64_t kDecompressBufferSize = 512 * 1024; // 512 KB.
// The maximum data chunk size for VolumeReader::Read requests.
// Should be positive.
const int64_t kMaximumDataChunkSize = 512 * 1024; // 512 KB.
// The minimum data chunk size for VolumeReader::Read requests.
// Should be positive.
const int64_t kMinimumDataChunkSize = 32 * 1024; // 16 KB.
} // namespace volume_archive_constants
// Defines an implementation of VolumeArchive that wraps all libarchive
// operations.
class VolumeArchiveLibarchive : public VolumeArchive {
explicit VolumeArchiveLibarchive(VolumeReader* reader);
virtual ~VolumeArchiveLibarchive();
// See volume_archive_interface.h.
virtual bool Init(const std::string& encoding);
// See volume_archive_interface.h.
virtual Result GetNextHeader();
virtual Result GetNextHeader(const char** path_name,
int64_t* size,
bool* is_directory,
time_t* modification_time);
// See volume_archive_interface.h.
virtual bool SeekHeader(int64_t index);
// See volume_archive_interface.h.
virtual int64_t ReadData(int64_t offset,
int64_t length,
const char** buffer);
// See volume_archive_interface.h.
virtual void MaybeDecompressAhead();
// See volume_archive_interface.h.
virtual bool Cleanup();
int64_t reader_data_size() const { return reader_data_size_; }
// Decompress length bytes of data starting from offset.
void DecompressData(int64_t offset, int64_t length);
// The size of the requested data from VolumeReader.
int64_t reader_data_size_;
// The libarchive correspondent archive object.
archive* archive_;
// The last reached entry with VolumeArchiveLibarchive::GetNextHeader.
archive_entry* current_archive_entry_;
// The data offset, which will be offset + length after last read
// operation, where offset and length are method parameters for
// VolumeArchiveLibarchive::ReadData. Data offset is used to improve
// performance for consecutive calls to VolumeArchiveLibarchive::ReadData.
// Intead of starting the read from the beginning for every
// VolumeArchiveLibarchive::ReadData, the next call will start
// from last_read_data_offset_ in case the offset parameter of
// VolumeArchiveLibarchive::ReadData has the same value as
// last_read_data_offset_. This avoids decompressing again the bytes at
// the begninning of the file, which is the average case scenario.
// But in case the offset parameter is different than last_read_data_offset_,
// then dummy_buffer_ will be used to ignore unused bytes.
int64_t last_read_data_offset_;
// The length of the last VolumeArchiveLibarchive::ReadData. Used for
// decompress ahead.
int64_t last_read_data_length_;
// Dummy buffer for unused data read using VolumeArchiveLibarchive::ReadData.
// Sometimes VolumeArchiveLibarchive::ReadData can require reading from
// offsets different from last_read_data_offset_. In this case some bytes
// must be skipped. Because seeking is not possible inside compressed files,
// the bytes will be discarded using this buffer.
char dummy_buffer_[volume_archive_constants::kDummyBufferSize];
// The address where the decompressed data starting from
// decompressed_offset_ is stored. It should point to a valid location
// inside decompressed_data_buffer_. Necesssary in order to NOT throw
// away unused decompressed bytes as throwing them away would mean in some
// situations restarting decompressing the file from the beginning.
char* decompressed_data_;
// The actual buffer that contains the decompressed data.
char decompressed_data_buffer_
// The size of valid data starting from decompressed_data_ that is stored
// inside decompressed_data_buffer_.
int64_t decompressed_data_size_;
// True if VolumeArchiveLibarchive::DecompressData failed.
bool decompressed_error_;