New SplitPatchWriter to split a bsdiff patch into multiple ones.

This new PatchWriterInterface derived class allows to split the
output patch of a bsdiff run into multiple files of a fixed new file
size. This allows to split long operations with minimal loss of patch
size due to splitting the compression blocks. For large enough new file
sections, this patch size reduction should be minimal.

Bug: 34220646
Test: Added unittests.
Change-Id: Ib90fddd5c55a38c87ce396f2792aa558ecd07b22
diff --git a/split_patch_writer.h b/split_patch_writer.h
new file mode 100644
index 0000000..81c913e
--- /dev/null
+++ b/split_patch_writer.h
@@ -0,0 +1,82 @@
+// Copyright 2017 The Chromium OS 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 _BSDIFF_SPLIT_PATCH_WRITER_H_
+#define _BSDIFF_SPLIT_PATCH_WRITER_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "bsdiff/patch_writer_interface.h"
+
+namespace bsdiff {
+
+// A PatchWriterInterface class that splits the output patch into multiple
+// patches of a fixed new-file size. The size of each patch data will depend on
+// the contents of the new file data, and won't necessarily be uniform.
+class SplitPatchWriter : public PatchWriterInterface {
+ public:
+  // Create a PatchWriter using that will split in several patches where each
+  // one will write |new_chunk_size| bytes of new file data. Each patch will
+  // use the old file as a whole input file.
+  SplitPatchWriter(uint64_t new_chunk_size,
+                   const std::vector<PatchWriterInterface*>& patches)
+      : new_chunk_size_(new_chunk_size), patches_(patches) {
+    diff_sizes_.resize(patches.size());
+    extra_sizes_.resize(patches.size());
+  }
+
+  // PatchWriterInterface overrides.
+  // Note: Calling WriteDiffStream/WriteExtraStream before calling the
+  // corresponding AddControlEntry() is not supported and will fail. The reason
+  // for this is because which underlying patch takes the bytes depends on the
+  // control entries.
+  bool Init() override;
+  bool WriteDiffStream(const uint8_t* data, size_t size) override;
+  bool WriteExtraStream(const uint8_t* data, size_t size) override;
+  bool AddControlEntry(const ControlEntry& entry) override;
+  bool Close() override;
+
+ private:
+  // Add a ControlEntry to the |current_patch_| without splitting it. Updates
+  // the internal structures of used data.
+  bool AddControlEntryToCurrentPatch(const ControlEntry& entry);
+
+  using WriteStreamMethod = bool (PatchWriterInterface::*)(const uint8_t* data,
+                                                           size_t size);
+
+  // Write to the diff or extra stream as determined by |method|.
+  bool WriteToStream(WriteStreamMethod method,
+                     std::vector<size_t>* sizes_vector,
+                     const uint8_t* data,
+                     size_t size);
+
+  // The size of each chunk of the new file written to.
+  uint64_t new_chunk_size_;
+  std::vector<PatchWriterInterface*> patches_;
+
+  // The size of the diff and extra streams that should go in each patch and has
+  // been written so far.
+  std::vector<size_t> diff_sizes_;
+  std::vector<size_t> extra_sizes_;
+
+  // The current patch number in the |patches_| array we are writing to.
+  size_t current_patch_{0};
+
+  // The number of patches we already called Close() on. The patches are always
+  // closed in order.
+  size_t closed_patches_{0};
+
+  // Bytes of the new files already written. Needed to store the new length in
+  // the header of the file.
+  uint64_t written_output_{0};
+
+  // The current pointer into the old stream.
+  uint64_t old_pos_{0};
+};
+
+}  // namespace bsdiff
+
+#endif  // _BSDIFF_SPLIT_PATCH_WRITER_H_