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_WRITER_H_ 6 #define COMPONENTS_ZUCCHINI_PATCH_WRITER_H_ 7 8 #include <stddef.h> 9 #include <stdint.h> 10 11 #include <map> 12 #include <optional> 13 #include <utility> 14 #include <vector> 15 16 #include "base/check.h" 17 #include "components/zucchini/buffer_sink.h" 18 #include "components/zucchini/buffer_view.h" 19 #include "components/zucchini/image_utils.h" 20 #include "components/zucchini/patch_utils.h" 21 22 namespace zucchini { 23 24 namespace patch { 25 26 // If sufficient space is available, serializes |element_match| into |sink| and 27 // returns true. Otherwise returns false, and |sink| will be in an undefined 28 // state. 29 bool SerializeElementMatch(const ElementMatch& element_match, BufferSink* sink); 30 31 // Returns the size in bytes required to serialize |element_match|. 32 size_t SerializedElementMatchSize(const ElementMatch& element_match); 33 34 // If sufficient space is available, serializes |buffer| into |sink| and returns 35 // true. Otherwise returns false, and |sink| will be in an undefined state. 36 bool SerializeBuffer(const std::vector<uint8_t>& buffer, BufferSink* sink); 37 38 // Returns the size in bytes required to serialize |buffer|. 39 size_t SerializedBufferSize(const std::vector<uint8_t>& buffer); 40 41 } // namespace patch 42 43 // Each of *Sink classes below has an associated "main type", and performs the 44 // following: 45 // - Receives multiple "main type" elements (hence "Sink" in the name). 46 // - Encodes list of received data, and writes them to internal storage (e.g., 47 // applying delta encoding). 48 // - Writes encoded data to BufferSink. 49 // 50 // Common "core functions" implemented for *Sink classes are: 51 // - void PutNext(const MAIN_TYPE& inst): Encodes and writes an instance of 52 // MAIN_TYPE to internal storage. Assumptions may be applied to successive 53 // |inst| provided. 54 // - size_t SerializedSize() const: Returns the serialized size in bytes of 55 // internal storage. 56 // - bool SerializeInto(BufferSink* sink) const: If |sink| has enough space, 57 // serializes internal storage into |sink|, and returns true. Otherwise 58 // returns false. 59 // 60 // Usage of *Sink instances don't mix, and PuttNext() have dissimilar 61 // interfaces. Therefore we do not use inheritance to relate *Sink classes, 62 // simply implement "core functions" with matching names. 63 64 // Sink for equivalences. 65 class EquivalenceSink { 66 public: 67 EquivalenceSink(); 68 EquivalenceSink(const std::vector<uint8_t>& src_skip, 69 const std::vector<uint8_t>& dst_skip, 70 const std::vector<uint8_t>& copy_count); 71 72 EquivalenceSink(EquivalenceSink&&); 73 ~EquivalenceSink(); 74 75 // Core functions. 76 // Equivalences must be given by increasing |Equivalence::dst_offset|. 77 void PutNext(const Equivalence& equivalence); 78 size_t SerializedSize() const; 79 bool SerializeInto(BufferSink* sink) const; 80 81 private: 82 // Offset in source, delta-encoded starting from end of last equivalence, and 83 // stored as signed varint. 84 std::vector<uint8_t> src_skip_; 85 // Offset in destination, delta-encoded starting from end of last equivalence, 86 // and stored as unsigned varint. 87 std::vector<uint8_t> dst_skip_; 88 // Length of equivalence stored as unsigned varint. 89 // TODO(etiennep): Investigate on bias. 90 std::vector<uint8_t> copy_count_; 91 92 offset_t src_offset_ = 0; // Last offset in source. 93 offset_t dst_offset_ = 0; // Last offset in destination. 94 }; 95 96 // Sink for extra data. 97 class ExtraDataSink { 98 public: 99 ExtraDataSink(); 100 explicit ExtraDataSink(const std::vector<uint8_t>& extra_data); 101 ExtraDataSink(ExtraDataSink&&); 102 ~ExtraDataSink(); 103 104 // Core functions. 105 void PutNext(ConstBufferView region); 106 size_t SerializedSize() const; 107 bool SerializeInto(BufferSink* sink) const; 108 109 private: 110 std::vector<uint8_t> extra_data_; 111 }; 112 113 // Sink for raw delta. 114 class RawDeltaSink { 115 public: 116 RawDeltaSink(); 117 RawDeltaSink(const std::vector<uint8_t>& raw_delta_skip, 118 const std::vector<uint8_t>& raw_delta_diff); 119 RawDeltaSink(RawDeltaSink&&); 120 ~RawDeltaSink(); 121 122 // Core functions. 123 // Deltas must be given by increasing |RawDeltaUnit::copy_offset|. 124 void PutNext(const RawDeltaUnit& delta); 125 size_t SerializedSize() const; 126 bool SerializeInto(BufferSink* sink) const; 127 128 private: 129 std::vector<uint8_t> raw_delta_skip_; // Copy offset stating from last delta. 130 std::vector<uint8_t> raw_delta_diff_; // Bytewise difference. 131 132 // We keep track of the compensation needed for next copy offset, taking into 133 // accound delta encoding and bias of -1. Stored delta are biased by -1, so a 134 // sequence of single byte deltas is represented as a string of 0's. 135 offset_t copy_offset_compensation_ = 0; 136 }; 137 138 // Sink for reference delta. 139 class ReferenceDeltaSink { 140 public: 141 ReferenceDeltaSink(); 142 explicit ReferenceDeltaSink(const std::vector<uint8_t>& reference_delta); 143 ReferenceDeltaSink(ReferenceDeltaSink&&); 144 ~ReferenceDeltaSink(); 145 146 // Core functions. 147 void PutNext(int32_t diff); 148 size_t SerializedSize() const; 149 bool SerializeInto(BufferSink* sink) const; 150 151 private: 152 std::vector<uint8_t> reference_delta_; 153 }; 154 155 // Sink for additional targets. 156 class TargetSink { 157 public: 158 TargetSink(); 159 explicit TargetSink(const std::vector<uint8_t>& extra_targets); 160 TargetSink(TargetSink&&); 161 ~TargetSink(); 162 163 // Core functions. 164 // Targets must be given by increasing order. 165 void PutNext(uint32_t target); 166 size_t SerializedSize() const; 167 bool SerializeInto(BufferSink* sink) const; 168 169 private: 170 // Targets are delta-encoded and biaised by 1, stored as unsigned varint. 171 std::vector<uint8_t> extra_targets_; 172 173 // We keep track of the compensation needed for next target, taking into 174 // accound delta encoding and bias of -1. 175 offset_t target_compensation_ = 0; 176 }; 177 178 // Following are utility classes to write structured data forming a patch. 179 180 // Utility to write a patch element. A patch element contains all the 181 // information necessary to patch a single element. This class 182 // provides an interface to individually set different building blocks of data 183 // in the patch element. 184 class PatchElementWriter { 185 public: 186 PatchElementWriter(); 187 explicit PatchElementWriter(ElementMatch element_match); 188 PatchElementWriter(PatchElementWriter&&); 189 ~PatchElementWriter(); 190 element_match()191 const ElementMatch& element_match() const { return element_match_; } old_element()192 const Element& old_element() const { return element_match_.old_element; } new_element()193 const Element& new_element() const { return element_match_.new_element; } 194 195 // Following methods set individual blocks for this element. Previous 196 // corresponding block is replaced. All streams must be set before call to 197 // SerializedSize() of SerializeInto(). 198 SetEquivalenceSink(EquivalenceSink && equivalences)199 void SetEquivalenceSink(EquivalenceSink&& equivalences) { 200 equivalences_.emplace(std::move(equivalences)); 201 } SetExtraDataSink(ExtraDataSink && extra_data)202 void SetExtraDataSink(ExtraDataSink&& extra_data) { 203 extra_data_.emplace(std::move(extra_data)); 204 } SetRawDeltaSink(RawDeltaSink && raw_delta)205 void SetRawDeltaSink(RawDeltaSink&& raw_delta) { 206 raw_delta_.emplace(std::move(raw_delta)); 207 } SetReferenceDeltaSink(ReferenceDeltaSink reference_delta)208 void SetReferenceDeltaSink(ReferenceDeltaSink reference_delta) { 209 reference_delta_.emplace(std::move(reference_delta)); 210 } 211 // Set additional targets for pool identified with |pool_tag|. SetTargetSink(PoolTag pool_tag,TargetSink && extra_targets)212 void SetTargetSink(PoolTag pool_tag, TargetSink&& extra_targets) { 213 DCHECK(pool_tag != kNoPoolTag); 214 extra_targets_.emplace(pool_tag, std::move(extra_targets)); 215 } 216 217 // Returns the serialized size in bytes of the data this object is holding. 218 size_t SerializedSize() const; 219 220 // If sufficient space is available, serializes data into |sink|, which is at 221 // least SerializedSize() bytes, and returns true. Otherwise returns false. 222 bool SerializeInto(BufferSink* sink) const; 223 224 private: 225 ElementMatch element_match_; 226 std::optional<EquivalenceSink> equivalences_; 227 std::optional<ExtraDataSink> extra_data_; 228 std::optional<RawDeltaSink> raw_delta_; 229 std::optional<ReferenceDeltaSink> reference_delta_; 230 std::map<PoolTag, TargetSink> extra_targets_; 231 }; 232 233 // Utility to write a Zucchini ensemble patch. An ensemble patch is the 234 // concatenation of a patch header with a vector of patch elements. 235 class EnsemblePatchWriter { 236 public: 237 explicit EnsemblePatchWriter(const PatchHeader& header); 238 EnsemblePatchWriter(ConstBufferView old_image, ConstBufferView new_image); 239 EnsemblePatchWriter(const EnsemblePatchWriter&) = delete; 240 const EnsemblePatchWriter& operator=(const EnsemblePatchWriter&) = delete; 241 ~EnsemblePatchWriter(); 242 243 // Reserves space for |count| patch elements. ReserveElements(size_t count)244 void ReserveElements(size_t count) { elements_.reserve(count); } 245 246 // Adds an patch element into the patch. Patch elements must be ordered by 247 // their location in the new image file. 248 void AddElement(PatchElementWriter&& patch_element); 249 250 // Returns the serialized size in bytes of the data this object is holding. 251 size_t SerializedSize() const; 252 253 // If sufficient space is available, serializes data into |sink|, which is at 254 // least SerializedSize() bytes, and returns true. Otherwise returns false. 255 bool SerializeInto(BufferSink* sink) const; 256 257 // If sufficient space is available, serializes data into |buffer|, which is 258 // at least SerializedSize() bytes, and returns true. Otherwise returns false. SerializeInto(MutableBufferView buffer)259 bool SerializeInto(MutableBufferView buffer) const { 260 BufferSink sink(buffer); 261 return SerializeInto(&sink); 262 } 263 264 private: 265 PatchHeader header_; 266 std::vector<PatchElementWriter> elements_; 267 offset_t current_dst_offset_ = 0; 268 }; 269 270 } // namespace zucchini 271 272 #endif // COMPONENTS_ZUCCHINI_PATCH_WRITER_H_ 273