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