diff options
| author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2020-02-02 17:13:01 +0100 | 
|---|---|---|
| committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2020-02-02 17:13:01 +0100 | 
| commit | ffa8801644a7d53cc1c785e3450f794c07a14eb0 (patch) | |
| tree | 8d72a18a9a08b9151d12badcb1c78ce06a059f62 /backend/genesys/image_buffer.cpp | |
| parent | 1687222e1b9e74c89cafbb5910e72d8ec7bfd40f (diff) | |
New upstream version 1.0.29upstream/1.0.29
Diffstat (limited to 'backend/genesys/image_buffer.cpp')
| -rw-r--r-- | backend/genesys/image_buffer.cpp | 203 | 
1 files changed, 203 insertions, 0 deletions
| diff --git a/backend/genesys/image_buffer.cpp b/backend/genesys/image_buffer.cpp new file mode 100644 index 0000000..07c6987 --- /dev/null +++ b/backend/genesys/image_buffer.cpp @@ -0,0 +1,203 @@ +/* sane - Scanner Access Now Easy. + +   Copyright (C) 2019 Povilas Kanapickas <povilas@radix.lt> + +   This file is part of the SANE package. + +   This program is free software; you can redistribute it and/or +   modify it under the terms of the GNU General Public License as +   published by the Free Software Foundation; either version 2 of the +   License, or (at your option) any later version. + +   This program 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 +   General Public License for more details. + +   You should have received a copy of the GNU General Public License +   along with this program; if not, write to the Free Software +   Foundation, Inc., 59 Temple Place - Suite 330, Boston, +   MA 02111-1307, USA. + +   As a special exception, the authors of SANE give permission for +   additional uses of the libraries contained in this release of SANE. + +   The exception is that, if you link a SANE library with other files +   to produce an executable, this does not by itself cause the +   resulting executable to be covered by the GNU General Public +   License.  Your use of that executable is in no way restricted on +   account of linking the SANE library code into it. + +   This exception does not, however, invalidate any other reasons why +   the executable file might be covered by the GNU General Public +   License. + +   If you submit changes to SANE to the maintainers to be included in +   a subsequent release, you agree by submitting the changes that +   those changes may be distributed with this exception intact. + +   If you write modifications of your own for SANE, it is your choice +   whether to permit this exception to apply to your modifications. +   If you do not wish that, delete this exception notice. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "image_buffer.h" +#include "image.h" + +namespace genesys { + +ImageBuffer::ImageBuffer(std::size_t size, ProducerCallback producer) : +    producer_{producer}, +    size_{size}, +    buffer_offset_{size} +{ +    buffer_.resize(size_); +} + +bool ImageBuffer::get_data(std::size_t size, std::uint8_t* out_data) +{ +    const std::uint8_t* out_data_end = out_data + size; + +    auto copy_buffer = [&]() +    { +        std::size_t bytes_copy = std::min<std::size_t>(out_data_end - out_data, available()); +        std::memcpy(out_data, buffer_.data() + buffer_offset_, bytes_copy); +        out_data += bytes_copy; +        buffer_offset_ += bytes_copy; +    }; + +    // first, read remaining data from buffer +    if (available() > 0) { +        copy_buffer(); +    } + +    if (out_data == out_data_end) { +        return true; +    } + +    // now the buffer is empty and there's more data to be read +    bool got_data = true; +    do { +        buffer_offset_ = 0; +        got_data &= producer_(size_, buffer_.data()); + +        copy_buffer(); +    } while(out_data < out_data_end && got_data); + +    return got_data; +} + +void FakeBufferModel::push_step(std::size_t buffer_size, std::size_t row_bytes) +{ +    sizes_.push_back(buffer_size); +    available_sizes_.push_back(0); +    row_bytes_.push_back(row_bytes); +} + +std::size_t FakeBufferModel::available_space() const +{ +    if (sizes_.empty()) +        throw SaneException("Model has not been setup"); +    return sizes_.front() - available_sizes_.front(); +} + +void FakeBufferModel::simulate_read(std::size_t size) +{ +    if (sizes_.empty()) { +        throw SaneException("Model has not been setup"); +    } +    if (available_space() < size) { +        throw SaneException("Attempted to simulate read of too much memory"); +    } + +    available_sizes_.front() += size; + +    for (unsigned i = 1; i < sizes_.size(); ++i) { +        auto avail_src = available_sizes_[i - 1]; +        auto avail_dst = sizes_[i] - available_sizes_[i]; + +        auto avail = (std::min(avail_src, avail_dst) / row_bytes_[i]) * row_bytes_[i]; +        available_sizes_[i - 1] -= avail; +        available_sizes_[i] += avail; +    } +    available_sizes_.back() = 0; +} + +ImageBufferGenesysUsb::ImageBufferGenesysUsb(std::size_t total_size, +                                             const FakeBufferModel& buffer_model, +                                             ProducerCallback producer) : +    remaining_size_{total_size}, +    buffer_model_{buffer_model}, +    producer_{producer} +{} + +bool ImageBufferGenesysUsb::get_data(std::size_t size, std::uint8_t* out_data) +{ +    const std::uint8_t* out_data_end = out_data + size; + +    auto copy_buffer = [&]() +    { +        std::size_t bytes_copy = std::min<std::size_t>(out_data_end - out_data, available()); +        std::memcpy(out_data, buffer_.data() + buffer_offset_, bytes_copy); +        out_data += bytes_copy; +        buffer_offset_ += bytes_copy; +    }; + +    // first, read remaining data from buffer +    if (available() > 0) { +        copy_buffer(); +    } + +    if (out_data == out_data_end) { +        return true; +    } + +    // now the buffer is empty and there's more data to be read +    do { +        if (remaining_size_ == 0) +            return false; + +        auto bytes_to_read = get_read_size(); +        buffer_offset_ = 0; +        buffer_end_ = bytes_to_read; +        buffer_.resize(bytes_to_read); + +        producer_(bytes_to_read, buffer_.data()); + +        if (remaining_size_ < bytes_to_read) { +            remaining_size_ = 0; +        } else { +            remaining_size_ -= bytes_to_read; +        } + +        copy_buffer(); +    } while(out_data < out_data_end); +    return true; +} + +std::size_t ImageBufferGenesysUsb::get_read_size() +{ +    std::size_t size = buffer_model_.available_space(); + +    // never read an odd number. exception: last read +    // the chip internal counter does not count half words. +    size &= ~1; + +    // Some setups need the reads to be multiples of 256 bytes +    size &= ~0xff; + +    if (remaining_size_ < size) { +        size = remaining_size_; +        /*round up to a multiple of 256 bytes */ +        size += (size & 0xff) ? 0x100 : 0x00; +        size &= ~0xff; +    } + +    buffer_model_.simulate_read(size); + +    return size; +} + +} // namespace genesys | 
