// 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 #include #include #include #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 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 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 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 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 previous_src_offset_ = 0; base::CheckedNumeric 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 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 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 copy_offset_compensation_ = 0; }; // Source for reference delta. class ReferenceDeltaSource { public: ReferenceDeltaSource(); ReferenceDeltaSource(const ReferenceDeltaSource&); ~ReferenceDeltaSource(); // Core functions. bool Initialize(BufferSource* source); absl::optional 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 GetNext(); bool Done() const { return extra_targets_.empty(); } // Accessors for unittest. BufferSource extra_targets() const { return extra_targets_; } private: BufferSource extra_targets_; base::CheckedNumeric 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 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 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& elements() const { return elements_; } private: PatchHeader header_; std::vector elements_; }; } // namespace zucchini #endif // COMPONENTS_ZUCCHINI_PATCH_READER_H_