1 // Copyright 2017 The Chromium OS 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 _BSDIFF_PATCH_WRITER_H_
6 #define _BSDIFF_PATCH_WRITER_H_
7 
8 #include <memory>
9 #include <string>
10 #include <vector>
11 
12 #include "bsdiff/compressor_interface.h"
13 #include "bsdiff/patch_writer_interface.h"
14 
15 namespace bsdiff {
16 
17 // A PatchWriterInterface class with three compressors and a 32-byte header.
18 class BsdiffPatchWriter : public PatchWriterInterface {
19  public:
20   // Create the patch writer using the upstream's "BSDIFF40" format. It uses
21   // bz2 as the compression algorithm and the file |patch_filename| to write
22   // the patch data.
23   explicit BsdiffPatchWriter(const std::string& patch_filename);
24 
25   // Create the patch writer using the "BSDF2" format. It uses the compressor
26   // with algorithm |type|; and quality |brotli_quality| if it's brotli. This
27   // writer also writes the patch data to the file |patch_filename|.
28   BsdiffPatchWriter(const std::string& patch_filename,
29                     const std::vector<CompressorType>& types,
30                     int brotli_quality);
31 
32   // PatchWriterInterface overrides.
33   bool Init(size_t new_size) override;
34   bool WriteDiffStream(const uint8_t* data, size_t size) override;
35   bool WriteExtraStream(const uint8_t* data, size_t size) override;
36   bool AddControlEntry(const ControlEntry& entry) override;
37   bool Close() override;
38 
39  private:
40   // Add supported compressors to |compressor_list|; return false if we failed
41   // to initialize one of them.
42   bool InitializeCompressorList(
43       std::vector<std::unique_ptr<CompressorInterface>>* compressor_list);
44 
45   // Select the compressor in |compressor_list| that produces the smallest
46   // patch, and put the result in |smallest_compressor|.
47   bool SelectSmallestResult(
48       const std::vector<std::unique_ptr<CompressorInterface>>& compressor_list,
49       CompressorInterface** smallest_compressor);
50 
51 
52   // Write the BSDIFF patch header to the |fp_|.
53   // Arguments:
54   //   A three bytes array with the compressor types of ctrl|diff|extra stream
55   //   Size of the compressed control block
56   //   Size of the compressed diff block.
57   bool WriteHeader(uint8_t types[3], uint64_t ctrl_size, uint64_t diff_size);
58 
59   // Bytes of the new files already written. Needed to store the new length in
60   // the header of the file.
61   uint64_t written_output_{0};
62 
63   // The current file we are writing to.
64   FILE* fp_{nullptr};
65   std::string patch_filename_;
66 
67   // The format of bsdiff we're using.
68   BsdiffFormat format_;
69 
70   // The compressors we're using.
71   std::vector<CompressorType> types_;
72 
73   // The compression quality of the brotli compressor.
74   int brotli_quality_;
75 
76   // The list of compressors to try for each stream.
77   std::vector<std::unique_ptr<CompressorInterface>> ctrl_stream_list_;
78   std::vector<std::unique_ptr<CompressorInterface>> diff_stream_list_;
79   std::vector<std::unique_ptr<CompressorInterface>> extra_stream_list_;
80 };
81 
82 }  // namespace bsdiff
83 
84 #endif  // _BSDIFF_PATCH_WRITER_H_
85