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