1*a03ca8b9SKrzysztof Kosiński // Copyright 2017 The Chromium Authors. All rights reserved.
2*a03ca8b9SKrzysztof Kosiński // Use of this source code is governed by a BSD-style license that can be
3*a03ca8b9SKrzysztof Kosiński // found in the LICENSE file.
4*a03ca8b9SKrzysztof Kosiński
5*a03ca8b9SKrzysztof Kosiński #ifndef COMPONENTS_ZUCCHINI_PATCH_READER_H_
6*a03ca8b9SKrzysztof Kosiński #define COMPONENTS_ZUCCHINI_PATCH_READER_H_
7*a03ca8b9SKrzysztof Kosiński
8*a03ca8b9SKrzysztof Kosiński #include <stddef.h>
9*a03ca8b9SKrzysztof Kosiński #include <stdint.h>
10*a03ca8b9SKrzysztof Kosiński
11*a03ca8b9SKrzysztof Kosiński #include <map>
12*a03ca8b9SKrzysztof Kosiński #include <optional>
13*a03ca8b9SKrzysztof Kosiński #include <vector>
14*a03ca8b9SKrzysztof Kosiński
15*a03ca8b9SKrzysztof Kosiński #include "base/debug/stack_trace.h"
16*a03ca8b9SKrzysztof Kosiński #include "base/logging.h"
17*a03ca8b9SKrzysztof Kosiński #include "base/numerics/checked_math.h"
18*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/buffer_source.h"
19*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/buffer_view.h"
20*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/image_utils.h"
21*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/patch_utils.h"
22*a03ca8b9SKrzysztof Kosiński
23*a03ca8b9SKrzysztof Kosiński namespace zucchini {
24*a03ca8b9SKrzysztof Kosiński
25*a03ca8b9SKrzysztof Kosiński namespace patch {
26*a03ca8b9SKrzysztof Kosiński
27*a03ca8b9SKrzysztof Kosiński // The Parse*() functions below attempt to extract data of a specific type from
28*a03ca8b9SKrzysztof Kosiński // the beginning of |source|. A parse function: On success, consumes the used
29*a03ca8b9SKrzysztof Kosiński // portion of |source|, writes data into the output parameter, and returns
30*a03ca8b9SKrzysztof Kosiński // true. Otherwise returns false and does not consume |source|.
31*a03ca8b9SKrzysztof Kosiński
32*a03ca8b9SKrzysztof Kosiński // Parses |source| for the next ElementMatch.
33*a03ca8b9SKrzysztof Kosiński bool ParseElementMatch(BufferSource* source, ElementMatch* element_match);
34*a03ca8b9SKrzysztof Kosiński
35*a03ca8b9SKrzysztof Kosiński // Parses |source| for the next embedded BufferSource.
36*a03ca8b9SKrzysztof Kosiński bool ParseBuffer(BufferSource* source, BufferSource* buffer);
37*a03ca8b9SKrzysztof Kosiński
38*a03ca8b9SKrzysztof Kosiński // Parses |source| for the next VarUInt.
39*a03ca8b9SKrzysztof Kosiński template <class T>
ParseVarUInt(BufferSource * source,T * value)40*a03ca8b9SKrzysztof Kosiński bool ParseVarUInt(BufferSource* source, T* value) {
41*a03ca8b9SKrzysztof Kosiński auto bytes_read = DecodeVarUInt(source->begin(), source->end(), value);
42*a03ca8b9SKrzysztof Kosiński if (!bytes_read) {
43*a03ca8b9SKrzysztof Kosiński LOG(ERROR) << "Impossible to read VarUInt from source.";
44*a03ca8b9SKrzysztof Kosiński LOG(ERROR) << base::debug::StackTrace().ToString();
45*a03ca8b9SKrzysztof Kosiński return false;
46*a03ca8b9SKrzysztof Kosiński }
47*a03ca8b9SKrzysztof Kosiński // Advance |source| beyond the VarUInt value.
48*a03ca8b9SKrzysztof Kosiński source->Skip(bytes_read);
49*a03ca8b9SKrzysztof Kosiński return true;
50*a03ca8b9SKrzysztof Kosiński }
51*a03ca8b9SKrzysztof Kosiński
52*a03ca8b9SKrzysztof Kosiński // Parses |source| for the next VarInt.
53*a03ca8b9SKrzysztof Kosiński template <class T>
ParseVarInt(BufferSource * source,T * value)54*a03ca8b9SKrzysztof Kosiński bool ParseVarInt(BufferSource* source, T* value) {
55*a03ca8b9SKrzysztof Kosiński auto bytes_read = DecodeVarInt(source->begin(), source->end(), value);
56*a03ca8b9SKrzysztof Kosiński if (!bytes_read) {
57*a03ca8b9SKrzysztof Kosiński LOG(ERROR) << "Impossible to read VarInt from source.";
58*a03ca8b9SKrzysztof Kosiński LOG(ERROR) << base::debug::StackTrace().ToString();
59*a03ca8b9SKrzysztof Kosiński return false;
60*a03ca8b9SKrzysztof Kosiński }
61*a03ca8b9SKrzysztof Kosiński // Advance |source| beyond the VarInt value.
62*a03ca8b9SKrzysztof Kosiński source->Skip(bytes_read);
63*a03ca8b9SKrzysztof Kosiński return true;
64*a03ca8b9SKrzysztof Kosiński }
65*a03ca8b9SKrzysztof Kosiński
66*a03ca8b9SKrzysztof Kosiński } // namespace patch
67*a03ca8b9SKrzysztof Kosiński
68*a03ca8b9SKrzysztof Kosiński // The *Source classes below are light-weight (i.e., allows copying) visitors to
69*a03ca8b9SKrzysztof Kosiński // read patch data. Each of them has an associated "main type", and performs the
70*a03ca8b9SKrzysztof Kosiński // following:
71*a03ca8b9SKrzysztof Kosiński // - Consumes portions of a BufferSource (required to remain valid for the
72*a03ca8b9SKrzysztof Kosiński // lifetime of the object).
73*a03ca8b9SKrzysztof Kosiński // - Decodes consumed data, which represent a list of items with "main type".
74*a03ca8b9SKrzysztof Kosiński // - Dispenses "main type" elements (hence "Source" in the name).
75*a03ca8b9SKrzysztof Kosiński //
76*a03ca8b9SKrzysztof Kosiński // Common "core functions" implemented by *Source classes are:
77*a03ca8b9SKrzysztof Kosiński // - bool Initialize(BufferSource* source): Consumes data from BufferSource and
78*a03ca8b9SKrzysztof Kosiński // initializes internal states. Returns true if successful, and false
79*a03ca8b9SKrzysztof Kosiński // otherwise (|source| may be partially consumed).
80*a03ca8b9SKrzysztof Kosiński // - std::optional<MAIN_TYPE> GetNext(OPT_PARAMS): Decodes consumed data and
81*a03ca8b9SKrzysztof Kosiński // returns the next item as std::optional (returns std::nullopt on failure).
82*a03ca8b9SKrzysztof Kosiński // - bool Done() const: Returns true if no more items remain; otherwise false.
83*a03ca8b9SKrzysztof Kosiński //
84*a03ca8b9SKrzysztof Kosiński // Usage of *Source instances don't mix, and GetNext() have dissimilar
85*a03ca8b9SKrzysztof Kosiński // interfaces. Therefore we do not use inheritance to relate *Source classes,
86*a03ca8b9SKrzysztof Kosiński // and simply implement "core functions" with matching names.
87*a03ca8b9SKrzysztof Kosiński
88*a03ca8b9SKrzysztof Kosiński // Source for Equivalences.
89*a03ca8b9SKrzysztof Kosiński class EquivalenceSource {
90*a03ca8b9SKrzysztof Kosiński public:
91*a03ca8b9SKrzysztof Kosiński EquivalenceSource();
92*a03ca8b9SKrzysztof Kosiński EquivalenceSource(const EquivalenceSource&);
93*a03ca8b9SKrzysztof Kosiński ~EquivalenceSource();
94*a03ca8b9SKrzysztof Kosiński
95*a03ca8b9SKrzysztof Kosiński // Core functions.
96*a03ca8b9SKrzysztof Kosiński bool Initialize(BufferSource* source);
97*a03ca8b9SKrzysztof Kosiński std::optional<Equivalence> GetNext();
Done()98*a03ca8b9SKrzysztof Kosiński bool Done() const {
99*a03ca8b9SKrzysztof Kosiński return src_skip_.empty() && dst_skip_.empty() && copy_count_.empty();
100*a03ca8b9SKrzysztof Kosiński }
101*a03ca8b9SKrzysztof Kosiński
102*a03ca8b9SKrzysztof Kosiński // Accessors for unittest.
src_skip()103*a03ca8b9SKrzysztof Kosiński BufferSource src_skip() const { return src_skip_; }
dst_skip()104*a03ca8b9SKrzysztof Kosiński BufferSource dst_skip() const { return dst_skip_; }
copy_count()105*a03ca8b9SKrzysztof Kosiński BufferSource copy_count() const { return copy_count_; }
106*a03ca8b9SKrzysztof Kosiński
107*a03ca8b9SKrzysztof Kosiński private:
108*a03ca8b9SKrzysztof Kosiński BufferSource src_skip_;
109*a03ca8b9SKrzysztof Kosiński BufferSource dst_skip_;
110*a03ca8b9SKrzysztof Kosiński BufferSource copy_count_;
111*a03ca8b9SKrzysztof Kosiński
112*a03ca8b9SKrzysztof Kosiński base::CheckedNumeric<offset_t> previous_src_offset_ = 0;
113*a03ca8b9SKrzysztof Kosiński base::CheckedNumeric<offset_t> previous_dst_offset_ = 0;
114*a03ca8b9SKrzysztof Kosiński };
115*a03ca8b9SKrzysztof Kosiński
116*a03ca8b9SKrzysztof Kosiński // Source for extra data.
117*a03ca8b9SKrzysztof Kosiński class ExtraDataSource {
118*a03ca8b9SKrzysztof Kosiński public:
119*a03ca8b9SKrzysztof Kosiński ExtraDataSource();
120*a03ca8b9SKrzysztof Kosiński ExtraDataSource(const ExtraDataSource&);
121*a03ca8b9SKrzysztof Kosiński ~ExtraDataSource();
122*a03ca8b9SKrzysztof Kosiński
123*a03ca8b9SKrzysztof Kosiński // Core functions.
124*a03ca8b9SKrzysztof Kosiński bool Initialize(BufferSource* source);
125*a03ca8b9SKrzysztof Kosiński // |size| is the size in bytes of the buffer requested.
126*a03ca8b9SKrzysztof Kosiński std::optional<ConstBufferView> GetNext(offset_t size);
Done()127*a03ca8b9SKrzysztof Kosiński bool Done() const { return extra_data_.empty(); }
128*a03ca8b9SKrzysztof Kosiński
129*a03ca8b9SKrzysztof Kosiński // Accessors for unittest.
extra_data()130*a03ca8b9SKrzysztof Kosiński BufferSource extra_data() const { return extra_data_; }
131*a03ca8b9SKrzysztof Kosiński
132*a03ca8b9SKrzysztof Kosiński private:
133*a03ca8b9SKrzysztof Kosiński BufferSource extra_data_;
134*a03ca8b9SKrzysztof Kosiński };
135*a03ca8b9SKrzysztof Kosiński
136*a03ca8b9SKrzysztof Kosiński // Source for raw delta.
137*a03ca8b9SKrzysztof Kosiński class RawDeltaSource {
138*a03ca8b9SKrzysztof Kosiński public:
139*a03ca8b9SKrzysztof Kosiński RawDeltaSource();
140*a03ca8b9SKrzysztof Kosiński RawDeltaSource(const RawDeltaSource&);
141*a03ca8b9SKrzysztof Kosiński ~RawDeltaSource();
142*a03ca8b9SKrzysztof Kosiński
143*a03ca8b9SKrzysztof Kosiński // Core functions.
144*a03ca8b9SKrzysztof Kosiński bool Initialize(BufferSource* source);
145*a03ca8b9SKrzysztof Kosiński std::optional<RawDeltaUnit> GetNext();
Done()146*a03ca8b9SKrzysztof Kosiński bool Done() const {
147*a03ca8b9SKrzysztof Kosiński return raw_delta_skip_.empty() && raw_delta_diff_.empty();
148*a03ca8b9SKrzysztof Kosiński }
149*a03ca8b9SKrzysztof Kosiński
150*a03ca8b9SKrzysztof Kosiński // Accessors for unittest.
raw_delta_skip()151*a03ca8b9SKrzysztof Kosiński BufferSource raw_delta_skip() const { return raw_delta_skip_; }
raw_delta_diff()152*a03ca8b9SKrzysztof Kosiński BufferSource raw_delta_diff() const { return raw_delta_diff_; }
153*a03ca8b9SKrzysztof Kosiński
154*a03ca8b9SKrzysztof Kosiński private:
155*a03ca8b9SKrzysztof Kosiński BufferSource raw_delta_skip_;
156*a03ca8b9SKrzysztof Kosiński BufferSource raw_delta_diff_;
157*a03ca8b9SKrzysztof Kosiński
158*a03ca8b9SKrzysztof Kosiński base::CheckedNumeric<offset_t> copy_offset_compensation_ = 0;
159*a03ca8b9SKrzysztof Kosiński };
160*a03ca8b9SKrzysztof Kosiński
161*a03ca8b9SKrzysztof Kosiński // Source for reference delta.
162*a03ca8b9SKrzysztof Kosiński class ReferenceDeltaSource {
163*a03ca8b9SKrzysztof Kosiński public:
164*a03ca8b9SKrzysztof Kosiński ReferenceDeltaSource();
165*a03ca8b9SKrzysztof Kosiński ReferenceDeltaSource(const ReferenceDeltaSource&);
166*a03ca8b9SKrzysztof Kosiński ~ReferenceDeltaSource();
167*a03ca8b9SKrzysztof Kosiński
168*a03ca8b9SKrzysztof Kosiński // Core functions.
169*a03ca8b9SKrzysztof Kosiński bool Initialize(BufferSource* source);
170*a03ca8b9SKrzysztof Kosiński std::optional<int32_t> GetNext();
Done()171*a03ca8b9SKrzysztof Kosiński bool Done() const { return source_.empty(); }
172*a03ca8b9SKrzysztof Kosiński
173*a03ca8b9SKrzysztof Kosiński // Accessors for unittest.
reference_delta()174*a03ca8b9SKrzysztof Kosiński BufferSource reference_delta() const { return source_; }
175*a03ca8b9SKrzysztof Kosiński
176*a03ca8b9SKrzysztof Kosiński private:
177*a03ca8b9SKrzysztof Kosiński BufferSource source_;
178*a03ca8b9SKrzysztof Kosiński };
179*a03ca8b9SKrzysztof Kosiński
180*a03ca8b9SKrzysztof Kosiński // Source for additional targets.
181*a03ca8b9SKrzysztof Kosiński class TargetSource {
182*a03ca8b9SKrzysztof Kosiński public:
183*a03ca8b9SKrzysztof Kosiński TargetSource();
184*a03ca8b9SKrzysztof Kosiński TargetSource(const TargetSource&);
185*a03ca8b9SKrzysztof Kosiński ~TargetSource();
186*a03ca8b9SKrzysztof Kosiński
187*a03ca8b9SKrzysztof Kosiński // Core functions.
188*a03ca8b9SKrzysztof Kosiński bool Initialize(BufferSource* source);
189*a03ca8b9SKrzysztof Kosiński std::optional<offset_t> GetNext();
Done()190*a03ca8b9SKrzysztof Kosiński bool Done() const { return extra_targets_.empty(); }
191*a03ca8b9SKrzysztof Kosiński
192*a03ca8b9SKrzysztof Kosiński // Accessors for unittest.
extra_targets()193*a03ca8b9SKrzysztof Kosiński BufferSource extra_targets() const { return extra_targets_; }
194*a03ca8b9SKrzysztof Kosiński
195*a03ca8b9SKrzysztof Kosiński private:
196*a03ca8b9SKrzysztof Kosiński BufferSource extra_targets_;
197*a03ca8b9SKrzysztof Kosiński
198*a03ca8b9SKrzysztof Kosiński base::CheckedNumeric<offset_t> target_compensation_ = 0;
199*a03ca8b9SKrzysztof Kosiński };
200*a03ca8b9SKrzysztof Kosiński
201*a03ca8b9SKrzysztof Kosiński // Following are utility classes providing a structured view on data forming a
202*a03ca8b9SKrzysztof Kosiński // patch.
203*a03ca8b9SKrzysztof Kosiński
204*a03ca8b9SKrzysztof Kosiński // Utility to read a patch element. A patch element contains all the information
205*a03ca8b9SKrzysztof Kosiński // necessary to patch a single element. This class provide access
206*a03ca8b9SKrzysztof Kosiński // to the multiple streams of data forming the patch element.
207*a03ca8b9SKrzysztof Kosiński class PatchElementReader {
208*a03ca8b9SKrzysztof Kosiński public:
209*a03ca8b9SKrzysztof Kosiński PatchElementReader();
210*a03ca8b9SKrzysztof Kosiński PatchElementReader(PatchElementReader&&);
211*a03ca8b9SKrzysztof Kosiński ~PatchElementReader();
212*a03ca8b9SKrzysztof Kosiński
213*a03ca8b9SKrzysztof Kosiński // If data read from |source| is well-formed, initialize cached sources to
214*a03ca8b9SKrzysztof Kosiński // read from it, and returns true. Otherwise returns false.
215*a03ca8b9SKrzysztof Kosiński bool Initialize(BufferSource* source);
216*a03ca8b9SKrzysztof Kosiński
element_match()217*a03ca8b9SKrzysztof Kosiński const ElementMatch& element_match() const { return element_match_; }
old_element()218*a03ca8b9SKrzysztof Kosiński const Element& old_element() const { return element_match_.old_element; }
new_element()219*a03ca8b9SKrzysztof Kosiński const Element& new_element() const { return element_match_.new_element; }
220*a03ca8b9SKrzysztof Kosiński
221*a03ca8b9SKrzysztof Kosiński // The Get*() functions below return copies of cached sources. Callers may
222*a03ca8b9SKrzysztof Kosiński // assume the following:
223*a03ca8b9SKrzysztof Kosiński // - Equivalences satisfy basic boundary constraints
224*a03ca8b9SKrzysztof Kosiński // - "Old" / "new" blocks lie entirely in "old" / "new" images.
225*a03ca8b9SKrzysztof Kosiński // - "New" blocks are sorted.
GetEquivalenceSource()226*a03ca8b9SKrzysztof Kosiński EquivalenceSource GetEquivalenceSource() const { return equivalences_; }
GetExtraDataSource()227*a03ca8b9SKrzysztof Kosiński ExtraDataSource GetExtraDataSource() const { return extra_data_; }
GetRawDeltaSource()228*a03ca8b9SKrzysztof Kosiński RawDeltaSource GetRawDeltaSource() const { return raw_delta_; }
GetReferenceDeltaSource()229*a03ca8b9SKrzysztof Kosiński ReferenceDeltaSource GetReferenceDeltaSource() const {
230*a03ca8b9SKrzysztof Kosiński return reference_delta_;
231*a03ca8b9SKrzysztof Kosiński }
GetExtraTargetSource(PoolTag tag)232*a03ca8b9SKrzysztof Kosiński TargetSource GetExtraTargetSource(PoolTag tag) const {
233*a03ca8b9SKrzysztof Kosiński auto pos = extra_targets_.find(tag);
234*a03ca8b9SKrzysztof Kosiński return pos != extra_targets_.end() ? pos->second : TargetSource();
235*a03ca8b9SKrzysztof Kosiński }
236*a03ca8b9SKrzysztof Kosiński
237*a03ca8b9SKrzysztof Kosiński private:
238*a03ca8b9SKrzysztof Kosiński // Checks that "old" and "new" blocks of each item in |equivalences_| satisfy
239*a03ca8b9SKrzysztof Kosiński // basic order and image bound constraints (using |element_match_| data). Also
240*a03ca8b9SKrzysztof Kosiński // validates that the amount of extra data is correct. Returns true if
241*a03ca8b9SKrzysztof Kosiński // successful.
242*a03ca8b9SKrzysztof Kosiński bool ValidateEquivalencesAndExtraData();
243*a03ca8b9SKrzysztof Kosiński
244*a03ca8b9SKrzysztof Kosiński ElementMatch element_match_;
245*a03ca8b9SKrzysztof Kosiński
246*a03ca8b9SKrzysztof Kosiński // Cached sources.
247*a03ca8b9SKrzysztof Kosiński EquivalenceSource equivalences_;
248*a03ca8b9SKrzysztof Kosiński ExtraDataSource extra_data_;
249*a03ca8b9SKrzysztof Kosiński RawDeltaSource raw_delta_;
250*a03ca8b9SKrzysztof Kosiński ReferenceDeltaSource reference_delta_;
251*a03ca8b9SKrzysztof Kosiński std::map<PoolTag, TargetSource> extra_targets_;
252*a03ca8b9SKrzysztof Kosiński };
253*a03ca8b9SKrzysztof Kosiński
254*a03ca8b9SKrzysztof Kosiński // Utility to read a Zucchini ensemble patch. An ensemble patch is the
255*a03ca8b9SKrzysztof Kosiński // concatenation of a patch header with a vector of patch elements.
256*a03ca8b9SKrzysztof Kosiński class EnsemblePatchReader {
257*a03ca8b9SKrzysztof Kosiński public:
258*a03ca8b9SKrzysztof Kosiński // If data read from |buffer| is well-formed, initializes and returns
259*a03ca8b9SKrzysztof Kosiński // an instance of EnsemblePatchReader. Otherwise returns std::nullopt.
260*a03ca8b9SKrzysztof Kosiński static std::optional<EnsemblePatchReader> Create(ConstBufferView buffer);
261*a03ca8b9SKrzysztof Kosiński
262*a03ca8b9SKrzysztof Kosiński EnsemblePatchReader();
263*a03ca8b9SKrzysztof Kosiński EnsemblePatchReader(EnsemblePatchReader&&);
264*a03ca8b9SKrzysztof Kosiński ~EnsemblePatchReader();
265*a03ca8b9SKrzysztof Kosiński
266*a03ca8b9SKrzysztof Kosiński // If data read from |source| is well-formed, initialize internal state to
267*a03ca8b9SKrzysztof Kosiński // read from it, and returns true. Otherwise returns false.
268*a03ca8b9SKrzysztof Kosiński bool Initialize(BufferSource* source);
269*a03ca8b9SKrzysztof Kosiński
270*a03ca8b9SKrzysztof Kosiński // Check old / new image file validity, comparing against expected size and
271*a03ca8b9SKrzysztof Kosiński // CRC32. Return true if file matches expectations, false otherwise.
272*a03ca8b9SKrzysztof Kosiński bool CheckOldFile(ConstBufferView old_image) const;
273*a03ca8b9SKrzysztof Kosiński bool CheckNewFile(ConstBufferView new_image) const;
274*a03ca8b9SKrzysztof Kosiński
header()275*a03ca8b9SKrzysztof Kosiński const PatchHeader& header() const { return header_; }
elements()276*a03ca8b9SKrzysztof Kosiński const std::vector<PatchElementReader>& elements() const { return elements_; }
277*a03ca8b9SKrzysztof Kosiński
278*a03ca8b9SKrzysztof Kosiński private:
279*a03ca8b9SKrzysztof Kosiński PatchHeader header_;
280*a03ca8b9SKrzysztof Kosiński std::vector<PatchElementReader> elements_;
281*a03ca8b9SKrzysztof Kosiński };
282*a03ca8b9SKrzysztof Kosiński
283*a03ca8b9SKrzysztof Kosiński } // namespace zucchini
284*a03ca8b9SKrzysztof Kosiński
285*a03ca8b9SKrzysztof Kosiński #endif // COMPONENTS_ZUCCHINI_PATCH_READER_H_
286