blob: 515da500144c7d574c80673f2904b7c5e05143a0 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_ZUCCHINI_PATCH_READER_H_
#define COMPONENTS_ZUCCHINI_PATCH_READER_H_
#include <stddef.h>
#include <stdint.h>
#include <map>
#include <vector>
#include "base/debug/stack_trace.h"
#include "base/logging.h"
#include "base/numerics/checked_math.h"
#include "base/optional.h"
#include "components/zucchini/buffer_source.h"
#include "components/zucchini/buffer_view.h"
#include "components/zucchini/image_utils.h"
#include "components/zucchini/patch_utils.h"
namespace zucchini {
namespace patch {
// The Parse*() functions below attempt to extract data of a specific type from
// the beginning of |source|. A parse function: On success, consumes the used
// portion of |source|, writes data into the output parameter, and returns
// true. Otherwise returns false and does not consume |source|.
// Parses |source| for the next ElementMatch.
bool ParseElementMatch(BufferSource* source, ElementMatch* element_match);
// Parses |source| for the next embedded BufferSource.
bool ParseBuffer(BufferSource* source, BufferSource* buffer);
// Parses |source| for the next VarUInt.
template <class T>
bool ParseVarUInt(BufferSource* source, T* value) {
auto bytes_read = DecodeVarUInt(source->begin(), source->end(), value);
if (!bytes_read) {
LOG(ERROR) << "Impossible to read VarUInt from source.";
LOG(ERROR) << base::debug::StackTrace().ToString();
return false;
}
// Advance |source| beyond the VarUInt value.
source->Skip(bytes_read);
return true;
}
// Parses |source| for the next VarInt.
template <class T>
bool ParseVarInt(BufferSource* source, T* value) {
auto bytes_read = DecodeVarInt(source->begin(), source->end(), value);
if (!bytes_read) {
LOG(ERROR) << "Impossible to read VarInt from source.";
LOG(ERROR) << base::debug::StackTrace().ToString();
return false;
}
// Advance |source| beyond the VarInt value.
source->Skip(bytes_read);
return true;
}
} // namespace patch
// The *Source classes below are light-weight (i.e., allows copying) visitors to
// read patch data. Each of them has an associated "main type", and performs the
// following:
// - Consumes portions of a BufferSource (required to remain valid for the
// lifetime of the object).
// - Decodes consumed data, which represent a list of items with "main type".
// - Dispenses "main type" elements (hence "Source" in the name).
//
// Common "core functions" implemented by *Source classes are:
// - bool Initialize(BufferSource* source): Consumes data from BufferSource and
// initializes internal states. Returns true if successful, and false
// otherwise (|source| may be partially consumed).
// - base::Optional<MAIN_TYPE> GetNext(OPT_PARAMS): Decodes consumed data and
// returns the next item as base::Optional (returns base::nullopt on failure).
// - bool Done() const: Returns true if no more items remain; otherwise false.
//
// Usage of *Source instances don't mix, and GetNext() have dissimilar
// interfaces. Therefore we do not use inheritance to relate *Source classes,
// and simply implement "core functions" with matching names.
// Source for Equivalences.
class EquivalenceSource {
public:
EquivalenceSource();
EquivalenceSource(const EquivalenceSource&);
~EquivalenceSource();
// Core functions.
bool Initialize(BufferSource* source);
base::Optional<Equivalence> GetNext();
bool Done() const {
return src_skip_.empty() && dst_skip_.empty() && copy_count_.empty();
}
// Accessors for unittest.
BufferSource src_skip() const { return src_skip_; }
BufferSource dst_skip() const { return dst_skip_; }
BufferSource copy_count() const { return copy_count_; }
private:
BufferSource src_skip_;
BufferSource dst_skip_;
BufferSource copy_count_;
base::CheckedNumeric<offset_t> previous_src_offset_ = 0;
base::CheckedNumeric<offset_t> previous_dst_offset_ = 0;
};
// Source for extra data.
class ExtraDataSource {
public:
ExtraDataSource();
ExtraDataSource(const ExtraDataSource&);
~ExtraDataSource();
// Core functions.
bool Initialize(BufferSource* source);
// |size| is the size in bytes of the buffer requested.
base::Optional<ConstBufferView> GetNext(offset_t size);
bool Done() const { return extra_data_.empty(); }
// Accessors for unittest.
BufferSource extra_data() const { return extra_data_; }
private:
BufferSource extra_data_;
};
// Source for raw delta.
class RawDeltaSource {
public:
RawDeltaSource();
RawDeltaSource(const RawDeltaSource&);
~RawDeltaSource();
// Core functions.
bool Initialize(BufferSource* source);
base::Optional<RawDeltaUnit> GetNext();
bool Done() const {
return raw_delta_skip_.empty() && raw_delta_diff_.empty();
}
// Accessors for unittest.
BufferSource raw_delta_skip() const { return raw_delta_skip_; }
BufferSource raw_delta_diff() const { return raw_delta_diff_; }
private:
BufferSource raw_delta_skip_;
BufferSource raw_delta_diff_;
base::CheckedNumeric<offset_t> copy_offset_compensation_ = 0;
};
// Source for reference delta.
class ReferenceDeltaSource {
public:
ReferenceDeltaSource();
ReferenceDeltaSource(const ReferenceDeltaSource&);
~ReferenceDeltaSource();
// Core functions.
bool Initialize(BufferSource* source);
base::Optional<int32_t> GetNext();
bool Done() const { return source_.empty(); }
// Accessors for unittest.
BufferSource reference_delta() const { return source_; }
private:
BufferSource source_;
};
// Source for additional targets.
class TargetSource {
public:
TargetSource();
TargetSource(const TargetSource&);
~TargetSource();
// Core functions.
bool Initialize(BufferSource* source);
base::Optional<offset_t> GetNext();
bool Done() const { return extra_targets_.empty(); }
// Accessors for unittest.
BufferSource extra_targets() const { return extra_targets_; }
private:
BufferSource extra_targets_;
base::CheckedNumeric<offset_t> target_compensation_ = 0;
};
// Following are utility classes providing a structured view on data forming a
// patch.
// Utility to read a patch element. A patch element contains all the information
// necessary to patch a single element. This class provide access
// to the multiple streams of data forming the patch element.
class PatchElementReader {
public:
PatchElementReader();
PatchElementReader(PatchElementReader&&);
~PatchElementReader();
// If data read from |source| is well-formed, initialize cached sources to
// read from it, and returns true. Otherwise returns false.
bool Initialize(BufferSource* source);
const ElementMatch& element_match() const { return element_match_; }
const Element& old_element() const { return element_match_.old_element; }
const Element& new_element() const { return element_match_.new_element; }
// The Get*() functions below return copies of cached sources. Callers may
// assume the following:
// - Equivalences satisfy basic boundary constraints
// - "Old" / "new" blocks lie entirely in "old" / "new" images.
// - "New" blocks are sorted.
EquivalenceSource GetEquivalenceSource() const { return equivalences_; }
ExtraDataSource GetExtraDataSource() const { return extra_data_; }
RawDeltaSource GetRawDeltaSource() const { return raw_delta_; }
ReferenceDeltaSource GetReferenceDeltaSource() const {
return reference_delta_;
}
TargetSource GetExtraTargetSource(PoolTag tag) const {
auto pos = extra_targets_.find(tag);
return pos != extra_targets_.end() ? pos->second : TargetSource();
}
private:
// Checks that "old" and "new" blocks of each item in |equivalences_| satisfy
// basic order and image bound constraints (using |element_match_| data). Also
// validates that the amount of extra data is correct. Returns true if
// successful.
bool ValidateEquivalencesAndExtraData();
ElementMatch element_match_;
// Cached sources.
EquivalenceSource equivalences_;
ExtraDataSource extra_data_;
RawDeltaSource raw_delta_;
ReferenceDeltaSource reference_delta_;
std::map<PoolTag, TargetSource> extra_targets_;
};
// Utility to read a Zucchini ensemble patch. An ensemble patch is the
// concatenation of a patch header with a vector of patch elements.
class EnsemblePatchReader {
public:
// If data read from |buffer| is well-formed, initializes and returns
// an instance of EnsemblePatchReader. Otherwise returns base::nullopt.
static base::Optional<EnsemblePatchReader> Create(ConstBufferView buffer);
EnsemblePatchReader();
EnsemblePatchReader(EnsemblePatchReader&&);
~EnsemblePatchReader();
// If data read from |source| is well-formed, initialize internal state to
// read from it, and returns true. Otherwise returns false.
bool Initialize(BufferSource* source);
// Check old / new image file validity, comparing against expected size and
// CRC32. Return true if file matches expectations, false otherwise.
bool CheckOldFile(ConstBufferView old_image) const;
bool CheckNewFile(ConstBufferView new_image) const;
const PatchHeader& header() const { return header_; }
const std::vector<PatchElementReader>& elements() const { return elements_; }
private:
PatchHeader header_;
std::vector<PatchElementReader> elements_;
};
} // namespace zucchini
#endif // COMPONENTS_ZUCCHINI_PATCH_READER_H_