| // 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_ |