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