xref: /aosp_15_r20/external/zucchini/patch_writer.h (revision a03ca8b91e029cd15055c20c78c2e087c84792e4)
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