/* This file is part of TON Blockchain Library. TON Blockchain Library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. TON Blockchain Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . Copyright 2017-2019 Telegram Systems LLP */ #include "BinlogReaderHelper.h" #include "BinlogReaderInterface.h" #include "td/utils/misc.h" namespace td { td::Status BinlogReaderHelper::parse(BinlogReaderInterface& reader, td::Slice data) { SCOPE_EXIT { reader.flush(); }; while (true) { if (expected_prefix_size_ > 0 && expected_prefix_size_ == prefix_size_) { TRY_RESULT(size, reader.parse(MutableSlice(buf_.data(), prefix_size_))); if (size < 0) { if (expected_prefix_size_ > td::narrow_cast(-size)) { return td::Status::Error("BinlogReader decreased logevent size estimation (1)"); } expected_prefix_size_ = static_cast(-size); } else { if (expected_prefix_size_ != td::narrow_cast(size)) { return td::Status::Error("BinlogReader changed logevent"); } prefix_size_ = 0; expected_prefix_size_ = 0; } } if (data.empty()) { break; } if (expected_prefix_size_ > 0) { CHECK(expected_prefix_size_ < buf_.size()); CHECK(prefix_size_ < expected_prefix_size_); auto got = data.copy().truncate(expected_prefix_size_ - prefix_size_); reader.flush(); auto dest = td::MutableSlice(buf_.data(), buf_.size()).substr(prefix_size_); if (dest.size() < got.size()) { return td::Status::Error("Too big logevent"); } dest.copy_from(got); prefix_size_ += got.size(); data = data.substr(got.size()); continue; } CHECK(!data.empty()); TRY_RESULT(size, reader.parse(data)); if (size < 0) { expected_prefix_size_ = td::narrow_cast(-size); prefix_size_ = data.size(); if (expected_prefix_size_ < prefix_size_) { return td::Status::Error("BinlogReader waits for less data than it already has"); } if (expected_prefix_size_ > buf_.size()) { return td::Status::Error("BinlogReader waits for too big logevent"); } reader.flush(); td::MutableSlice(buf_.data(), prefix_size_).copy_from(data); break; } if (size == 0) { return td::Status::Error("BinlogReader parseed nothing and asked for nothing"); } if (td::narrow_cast(size) > data.size()) { return td::Status::Error("BinlogReader parseed more than was given"); } data = data.substr(static_cast(size)); } return td::Status::OK(); } size_t BinlogReaderHelper::unparsed_size() const { return prefix_size_; } } // namespace td