1/* sane - Scanner Access Now Easy. 2 3 Copyright (C) 2019 Povilas Kanapickas <povilas@radix.lt> 4 5 This file is part of the SANE package. 6 7 This program is free software; you can redistribute it and/or 8 modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the 10 License, or (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <https://www.gnu.org/licenses/>. 19*/ 20 21#define DEBUG_DECLARE_ONLY 22 23#include "image_buffer.h" 24#include "image.h" 25#include "utilities.h" 26 27namespace genesys { 28 29ImageBuffer::ImageBuffer(std::size_t size, ProducerCallback producer) : 30 producer_{producer}, 31 size_{size} 32{ 33 buffer_.resize(size_); 34} 35 36bool ImageBuffer::get_data(std::size_t size, std::uint8_t* out_data) 37{ 38 const std::uint8_t* out_data_end = out_data + size; 39 40 auto copy_buffer = [&]() 41 { 42 std::size_t bytes_copy = std::min<std::size_t>(out_data_end - out_data, available()); 43 std::memcpy(out_data, buffer_.data() + buffer_offset_, bytes_copy); 44 out_data += bytes_copy; 45 buffer_offset_ += bytes_copy; 46 }; 47 48 // first, read remaining data from buffer 49 if (available() > 0) { 50 copy_buffer(); 51 } 52 53 if (out_data == out_data_end) { 54 return true; 55 } 56 57 // now the buffer is empty and there's more data to be read 58 bool got_data = true; 59 do { 60 buffer_offset_ = 0; 61 62 std::size_t size_to_read = size_; 63 if (remaining_size_ != BUFFER_SIZE_UNSET) { 64 size_to_read = std::min<std::uint64_t>(size_to_read, remaining_size_); 65 remaining_size_ -= size_to_read; 66 } 67 68 std::size_t aligned_size_to_read = size_to_read; 69 if (remaining_size_ == 0 && last_read_multiple_ != BUFFER_SIZE_UNSET) { 70 aligned_size_to_read = align_multiple_ceil(size_to_read, last_read_multiple_); 71 } 72 73 got_data &= producer_(aligned_size_to_read, buffer_.data()); 74 curr_size_ = size_to_read; 75 76 copy_buffer(); 77 78 if (remaining_size_ == 0 && out_data < out_data_end) { 79 got_data = false; 80 } 81 82 } while (out_data < out_data_end && got_data); 83 84 return got_data; 85} 86 87} // namespace genesys 88