aboutsummaryrefslogtreecommitdiff
path: root/patch_reader.h
blob: 93d64b04747d3670e2d2bf108b7d638851132715 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
// 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_