xref: /aosp_15_r20/external/zucchini/patch_reader.h (revision a03ca8b91e029cd15055c20c78c2e087c84792e4)
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