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