aboutsummaryrefslogtreecommitdiff
path: root/patch_writer.h
diff options
context:
space:
mode:
authorSamuel Huang <huangs@chromium.org>2018-03-13 18:19:34 +0000
committerEdward Lesmes <ehmaldonado@google.com>2021-07-23 21:50:59 +0000
commit06f1ae9aaca969ee95ef840f22b6b461c304542d (patch)
treef1e5c6624e70628e81fbf38d6cd14b974abe5d93 /patch_writer.h
downloadzucchini-06f1ae9aaca969ee95ef840f22b6b461c304542d.tar.gz
[Zucchini] Move Zucchini from /chrome/installer/ to /components/.
(Use "git log --follow" to see older revisions of files). /components/ is the most logical place to put Zucchini, which only depends on /base and /testing/gtest. This move also enables Zucchini to be used by the Component Updater. Details: - Move all files; run the following to change deps and guards: sed 's/chrome\/installer/components/' *.cc *.h -i sed 's/CHROME_INSTALLER/COMPONENTS/' *.cc *.h -i - Sorting works out pretty well! - Change all 'chrome/installer/zucchini' to 'components/zucchini' throughout other parts of the repo; sort if necessary. - Fix 6 'git cl lint' errors. - Change 1 Bind() usage to BindRepeated(). - Update OWNER. Bug: 729154 Change-Id: I50c5a7d411ea85f707b5994ab319dfb2a1acccf7 Reviewed-on: https://chromium-review.googlesource.com/954923 Reviewed-by: Greg Thompson <grt@chromium.org> Reviewed-by: Jochen Eisinger <jochen@chromium.org> Reviewed-by: Samuel Huang <huangs@chromium.org> Commit-Queue: Samuel Huang <huangs@chromium.org> Cr-Commit-Position: refs/heads/master@{#542857} NOKEYCHECK=True GitOrigin-RevId: 577ef6c435e8d43be6e3e60ccbcbd1881780f4ec
Diffstat (limited to 'patch_writer.h')
-rw-r--r--patch_writer.h276
1 files changed, 276 insertions, 0 deletions
diff --git a/patch_writer.h b/patch_writer.h
new file mode 100644
index 0000000..a7c3785
--- /dev/null
+++ b/patch_writer.h
@@ -0,0 +1,276 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_ZUCCHINI_PATCH_WRITER_H_
+#define COMPONENTS_ZUCCHINI_PATCH_WRITER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/optional.h"
+#include "components/zucchini/buffer_sink.h"
+#include "components/zucchini/buffer_view.h"
+#include "components/zucchini/image_utils.h"
+#include "components/zucchini/patch_utils.h"
+
+namespace zucchini {
+
+namespace patch {
+
+// If sufficient space is available, serializes |element_match| into |sink| and
+// returns true. Otherwise returns false, and |sink| will be in an undefined
+// state.
+bool SerializeElementMatch(const ElementMatch& element_match, BufferSink* sink);
+
+// Returns the size in bytes required to serialize |element_match|.
+size_t SerializedElementMatchSize(const ElementMatch& element_match);
+
+// If sufficient space is available, serializes |buffer| into |sink| and returns
+// true. Otherwise returns false, and |sink| will be in an undefined state.
+bool SerializeBuffer(const std::vector<uint8_t>& buffer, BufferSink* sink);
+
+// Returns the size in bytes required to serialize |buffer|.
+size_t SerializedBufferSize(const std::vector<uint8_t>& buffer);
+
+} // namespace patch
+
+// Each of *Sink classes below has an associated "main type", and performs the
+// following:
+// - Receives multiple "main type" elements (hence "Sink" in the name).
+// - Encodes list of received data, and writes them to internal storage (e.g.,
+// applying delta encoding).
+// - Writes encoded data to BufferSink.
+//
+// Common "core functions" implemented for *Sink classes are:
+// - void PutNext(const MAIN_TYPE& inst): Encodes and writes an instance of
+// MAIN_TYPE to internal storage. Assumptions may be applied to successive
+// |inst| provided.
+// - size_t SerializedSize() const: Returns the serialized size in bytes of
+// internal storage.
+// - bool SerializeInto(BufferSink* sink) const: If |sink| has enough space,
+// serializes internal storage into |sink|, and returns true. Otherwise
+// returns false.
+//
+// Usage of *Sink instances don't mix, and PuttNext() have dissimilar
+// interfaces. Therefore we do not use inheritance to relate *Sink classes,
+// simply implement "core functions" with matching names.
+
+// Sink for equivalences.
+class EquivalenceSink {
+ public:
+ EquivalenceSink();
+ EquivalenceSink(const std::vector<uint8_t>& src_skip,
+ const std::vector<uint8_t>& dst_skip,
+ const std::vector<uint8_t>& copy_count);
+
+ EquivalenceSink(EquivalenceSink&&);
+ ~EquivalenceSink();
+
+ // Core functions.
+ // Equivalences must be given by increasing |Equivalence::dst_offset|.
+ void PutNext(const Equivalence& equivalence);
+ size_t SerializedSize() const;
+ bool SerializeInto(BufferSink* sink) const;
+
+ private:
+ // Offset in source, delta-encoded starting from end of last equivalence, and
+ // stored as signed varint.
+ std::vector<uint8_t> src_skip_;
+ // Offset in destination, delta-encoded starting from end of last equivalence,
+ // and stored as unsigned varint.
+ std::vector<uint8_t> dst_skip_;
+ // Length of equivalence stored as unsigned varint.
+ // TODO(etiennep): Investigate on bias.
+ std::vector<uint8_t> copy_count_;
+
+ offset_t src_offset_ = 0; // Last offset in source.
+ offset_t dst_offset_ = 0; // Last offset in destination.
+};
+
+// Sink for extra data.
+class ExtraDataSink {
+ public:
+ ExtraDataSink();
+ explicit ExtraDataSink(const std::vector<uint8_t>& extra_data);
+ ExtraDataSink(ExtraDataSink&&);
+ ~ExtraDataSink();
+
+ // Core functions.
+ void PutNext(ConstBufferView region);
+ size_t SerializedSize() const;
+ bool SerializeInto(BufferSink* sink) const;
+
+ private:
+ std::vector<uint8_t> extra_data_;
+};
+
+// Sink for raw delta.
+class RawDeltaSink {
+ public:
+ RawDeltaSink();
+ RawDeltaSink(const std::vector<uint8_t>& raw_delta_skip,
+ const std::vector<uint8_t>& raw_delta_diff);
+ RawDeltaSink(RawDeltaSink&&);
+ ~RawDeltaSink();
+
+ // Core functions.
+ // Deltas must be given by increasing |RawDeltaUnit::copy_offset|.
+ void PutNext(const RawDeltaUnit& delta);
+ size_t SerializedSize() const;
+ bool SerializeInto(BufferSink* sink) const;
+
+ private:
+ std::vector<uint8_t> raw_delta_skip_; // Copy offset stating from last delta.
+ std::vector<uint8_t> raw_delta_diff_; // Bytewise difference.
+
+ // We keep track of the compensation needed for next copy offset, taking into
+ // accound delta encoding and bias of -1. Stored delta are biased by -1, so a
+ // sequence of single byte deltas is represented as a string of 0's.
+ offset_t copy_offset_compensation_ = 0;
+};
+
+// Sink for reference delta.
+class ReferenceDeltaSink {
+ public:
+ ReferenceDeltaSink();
+ explicit ReferenceDeltaSink(const std::vector<uint8_t>& reference_delta);
+ ReferenceDeltaSink(ReferenceDeltaSink&&);
+ ~ReferenceDeltaSink();
+
+ // Core functions.
+ void PutNext(int32_t diff);
+ size_t SerializedSize() const;
+ bool SerializeInto(BufferSink* sink) const;
+
+ private:
+ std::vector<uint8_t> reference_delta_;
+};
+
+// Sink for additional targets.
+class TargetSink {
+ public:
+ TargetSink();
+ explicit TargetSink(const std::vector<uint8_t>& extra_targets);
+ TargetSink(TargetSink&&);
+ ~TargetSink();
+
+ // Core functions.
+ // Targets must be given by increasing order.
+ void PutNext(uint32_t target);
+ size_t SerializedSize() const;
+ bool SerializeInto(BufferSink* sink) const;
+
+ private:
+ // Targets are delta-encoded and biaised by 1, stored as unsigned varint.
+ std::vector<uint8_t> extra_targets_;
+
+ // We keep track of the compensation needed for next target, taking into
+ // accound delta encoding and bias of -1.
+ offset_t target_compensation_ = 0;
+};
+
+// Following are utility classes to write structured data forming a patch.
+
+// Utility to write a patch element. A patch element contains all the
+// information necessary to patch a single element. This class
+// provides an interface to individually set different building blocks of data
+// in the patch element.
+class PatchElementWriter {
+ public:
+ PatchElementWriter();
+ explicit PatchElementWriter(ElementMatch element_match);
+ PatchElementWriter(PatchElementWriter&&);
+ ~PatchElementWriter();
+
+ const ElementMatch& element_match() const { return element_match_; }
+ const Element& old_element() const { return element_match_.old_element; }
+ const Element& new_element() const { return element_match_.new_element; }
+
+ // Following methods set individual blocks for this element. Previous
+ // corresponding block is replaced. All streams must be set before call to
+ // SerializedSize() of SerializeInto().
+
+ void SetEquivalenceSink(EquivalenceSink&& equivalences) {
+ equivalences_.emplace(std::move(equivalences));
+ }
+ void SetExtraDataSink(ExtraDataSink&& extra_data) {
+ extra_data_.emplace(std::move(extra_data));
+ }
+ void SetRawDeltaSink(RawDeltaSink&& raw_delta) {
+ raw_delta_.emplace(std::move(raw_delta));
+ }
+ void SetReferenceDeltaSink(ReferenceDeltaSink reference_delta) {
+ reference_delta_.emplace(std::move(reference_delta));
+ }
+ // Set additional targets for pool identified with |pool_tag|.
+ void SetTargetSink(PoolTag pool_tag, TargetSink&& extra_targets) {
+ DCHECK(pool_tag != kNoPoolTag);
+ extra_targets_.emplace(pool_tag, std::move(extra_targets));
+ }
+
+ // Returns the serialized size in bytes of the data this object is holding.
+ size_t SerializedSize() const;
+
+ // If sufficient space is available, serializes data into |sink|, which is at
+ // least SerializedSize() bytes, and returns true. Otherwise returns false.
+ bool SerializeInto(BufferSink* sink) const;
+
+ private:
+ ElementMatch element_match_;
+ base::Optional<EquivalenceSink> equivalences_;
+ base::Optional<ExtraDataSink> extra_data_;
+ base::Optional<RawDeltaSink> raw_delta_;
+ base::Optional<ReferenceDeltaSink> reference_delta_;
+ std::map<PoolTag, TargetSink> extra_targets_;
+};
+
+// Utility to write a Zucchini ensemble patch. An ensemble patch is the
+// concatenation of a patch header with a vector of patch elements.
+class EnsemblePatchWriter {
+ public:
+ explicit EnsemblePatchWriter(const PatchHeader& header);
+ EnsemblePatchWriter(ConstBufferView old_image, ConstBufferView new_image);
+ ~EnsemblePatchWriter();
+
+ void SetPatchType(PatchType patch_type) { patch_type_ = patch_type; }
+
+ // Reserves space for |count| patch elements.
+ void ReserveElements(size_t count) { elements_.reserve(count); }
+
+ // Adds an patch element into the patch. Patch elements must be ordered by
+ // their location in the new image file.
+ void AddElement(PatchElementWriter&& patch_element);
+
+ // Returns the serialized size in bytes of the data this object is holding.
+ size_t SerializedSize() const;
+
+ // If sufficient space is available, serializes data into |sink|, which is at
+ // least SerializedSize() bytes, and returns true. Otherwise returns false.
+ bool SerializeInto(BufferSink* sink) const;
+
+ // If sufficient space is available, serializes data into |buffer|, which is
+ // at least SerializedSize() bytes, and returns true. Otherwise returns false.
+ bool SerializeInto(MutableBufferView buffer) const {
+ BufferSink sink(buffer);
+ return SerializeInto(&sink);
+ }
+
+ private:
+ PatchHeader header_;
+ PatchType patch_type_ = PatchType::kUnrecognisedPatch;
+ std::vector<PatchElementWriter> elements_;
+ offset_t current_dst_offset_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(EnsemblePatchWriter);
+};
+
+} // namespace zucchini
+
+#endif // COMPONENTS_ZUCCHINI_PATCH_WRITER_H_