xref: /aosp_15_r20/external/bsdiff/diff_encoder.cc (revision a3a45f308bd90ef1a6e6a5e8fb92fe449b895909)
1*a3a45f30SXin Li // Copyright 2017 The Chromium OS Authors. All rights reserved.
2*a3a45f30SXin Li // Use of this source code is governed by a BSD-style license that can be
3*a3a45f30SXin Li // found in the LICENSE file.
4*a3a45f30SXin Li 
5*a3a45f30SXin Li #include "bsdiff/diff_encoder.h"
6*a3a45f30SXin Li 
7*a3a45f30SXin Li #include <vector>
8*a3a45f30SXin Li 
9*a3a45f30SXin Li #include "bsdiff/logging.h"
10*a3a45f30SXin Li 
11*a3a45f30SXin Li namespace {
12*a3a45f30SXin Li 
13*a3a45f30SXin Li // The maximum positive number that we should encode. A number larger than this
14*a3a45f30SXin Li // for unsigned fields will be interpreted as a negative value and thus a
15*a3a45f30SXin Li // corrupt patch.
16*a3a45f30SXin Li const uint64_t kMaxEncodedUint64Value = (1ULL << 63) - 1;
17*a3a45f30SXin Li 
18*a3a45f30SXin Li }  // namespace
19*a3a45f30SXin Li 
20*a3a45f30SXin Li namespace bsdiff {
21*a3a45f30SXin Li 
Init()22*a3a45f30SXin Li bool DiffEncoder::Init() {
23*a3a45f30SXin Li   return patch_->Init(new_size_);
24*a3a45f30SXin Li }
25*a3a45f30SXin Li 
AddControlEntry(const ControlEntry & entry)26*a3a45f30SXin Li bool DiffEncoder::AddControlEntry(const ControlEntry& entry) {
27*a3a45f30SXin Li   if (entry.diff_size > kMaxEncodedUint64Value) {
28*a3a45f30SXin Li     LOG(ERROR) << "Encoding value out of range " << entry.diff_size;
29*a3a45f30SXin Li     return false;
30*a3a45f30SXin Li   }
31*a3a45f30SXin Li 
32*a3a45f30SXin Li   if (entry.extra_size > kMaxEncodedUint64Value) {
33*a3a45f30SXin Li     LOG(ERROR) << "Encoding value out of range " << entry.extra_size;
34*a3a45f30SXin Li     return false;
35*a3a45f30SXin Li   }
36*a3a45f30SXin Li 
37*a3a45f30SXin Li   // entry.diff_size + entry.extra_size don't overflow in uint64_t since we
38*a3a45f30SXin Li   // checked the kMaxEncodedUint64Value limit before.
39*a3a45f30SXin Li   if (entry.diff_size + entry.extra_size > new_size_ - written_output_) {
40*a3a45f30SXin Li     LOG(ERROR) << "Wrote more output than the declared new_size";
41*a3a45f30SXin Li     return false;
42*a3a45f30SXin Li   }
43*a3a45f30SXin Li 
44*a3a45f30SXin Li   if (entry.diff_size > 0 &&
45*a3a45f30SXin Li       (old_pos_ < 0 ||
46*a3a45f30SXin Li        static_cast<uint64_t>(old_pos_) + entry.diff_size > old_size_)) {
47*a3a45f30SXin Li     LOG(ERROR) << "The pointer in the old stream [" << old_pos_ << ", "
48*a3a45f30SXin Li                << (static_cast<uint64_t>(old_pos_) + entry.diff_size)
49*a3a45f30SXin Li                << ") is out of bounds [0, " << old_size_ << ")";
50*a3a45f30SXin Li     return false;
51*a3a45f30SXin Li   }
52*a3a45f30SXin Li 
53*a3a45f30SXin Li   // Pass down the control entry.
54*a3a45f30SXin Li   if (!patch_->AddControlEntry(entry))
55*a3a45f30SXin Li     return false;
56*a3a45f30SXin Li 
57*a3a45f30SXin Li   // Generate the diff stream.
58*a3a45f30SXin Li   std::vector<uint8_t> diff(entry.diff_size);
59*a3a45f30SXin Li   for (uint64_t i = 0; i < entry.diff_size; ++i) {
60*a3a45f30SXin Li     diff[i] = new_buf_[written_output_ + i] - old_buf_[old_pos_ + i];
61*a3a45f30SXin Li   }
62*a3a45f30SXin Li   if (!patch_->WriteDiffStream(diff.data(), diff.size())) {
63*a3a45f30SXin Li     LOG(ERROR) << "Writing " << diff.size() << " bytes to the diff stream";
64*a3a45f30SXin Li     return false;
65*a3a45f30SXin Li   }
66*a3a45f30SXin Li 
67*a3a45f30SXin Li   if (!patch_->WriteExtraStream(new_buf_ + written_output_ + entry.diff_size,
68*a3a45f30SXin Li                                 entry.extra_size)) {
69*a3a45f30SXin Li     LOG(ERROR) << "Writing " << entry.extra_size
70*a3a45f30SXin Li                << " bytes to the extra stream";
71*a3a45f30SXin Li     return false;
72*a3a45f30SXin Li   }
73*a3a45f30SXin Li 
74*a3a45f30SXin Li   old_pos_ += entry.diff_size + entry.offset_increment;
75*a3a45f30SXin Li   written_output_ += entry.diff_size + entry.extra_size;
76*a3a45f30SXin Li 
77*a3a45f30SXin Li   return true;
78*a3a45f30SXin Li }
79*a3a45f30SXin Li 
Close()80*a3a45f30SXin Li bool DiffEncoder::Close() {
81*a3a45f30SXin Li   if (written_output_ != new_size_) {
82*a3a45f30SXin Li     LOG(ERROR) << "Close() called but not all the output was written";
83*a3a45f30SXin Li     return false;
84*a3a45f30SXin Li   }
85*a3a45f30SXin Li   return patch_->Close();
86*a3a45f30SXin Li }
87*a3a45f30SXin Li 
88*a3a45f30SXin Li }  // namespace bsdiff
89