286 lines
9.3 KiB
C
286 lines
9.3 KiB
C
|
// 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 "components/zucchini/buffer_source.h"
|
||
|
#include "components/zucchini/buffer_view.h"
|
||
|
#include "components/zucchini/image_utils.h"
|
||
|
#include "components/zucchini/patch_utils.h"
|
||
|
#include "third_party/abseil-cpp/absl/types/optional.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).
|
||
|
// - absl::optional<MAIN_TYPE> GetNext(OPT_PARAMS): Decodes consumed data and
|
||
|
// returns the next item as absl::optional (returns absl::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);
|
||
|
absl::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.
|
||
|
absl::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);
|
||
|
absl::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);
|
||
|
absl::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);
|
||
|
absl::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 absl::nullopt.
|
||
|
static absl::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_
|