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 Libool DiffEncoder::Init() { 23*a3a45f30SXin Li return patch_->Init(new_size_); 24*a3a45f30SXin Li } 25*a3a45f30SXin Li AddControlEntry(const ControlEntry & entry)26*a3a45f30SXin Libool 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 Libool 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