mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-23 00:02:38 -05:00
144 lines
3.2 KiB
C++
144 lines
3.2 KiB
C++
/*
|
|
===============================================================================
|
|
|
|
FILE: filestream.cpp
|
|
|
|
CONTENTS:
|
|
Stream abstractions
|
|
|
|
PROGRAMMERS:
|
|
|
|
uday.karan@gmail.com - Hobu, Inc.
|
|
|
|
COPYRIGHT:
|
|
|
|
(c) 2014, Uday Verma, Hobu, Inc.
|
|
|
|
This is free software; you can redistribute and/or modify it under the
|
|
terms of the Apache Public License 2.0 published by the Apache Software
|
|
Foundation. See the COPYING file for more information.
|
|
|
|
This software is distributed WITHOUT ANY WARRANTY and without even the
|
|
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
CHANGE HISTORY:
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
#include <algorithm>
|
|
|
|
#include "filestream.hpp"
|
|
#include "excepts.hpp"
|
|
|
|
namespace lazperf
|
|
{
|
|
|
|
OutFileStream::OutFileStream(std::ostream& out) : f_(out)
|
|
{}
|
|
|
|
// Should probably write to memory to avoid all these calls to a file that can't
|
|
// be seen by the compiler.
|
|
void OutFileStream::putBytes(const unsigned char *c, size_t len)
|
|
{
|
|
f_.write(reinterpret_cast<const char *>(c), len);
|
|
}
|
|
|
|
OutputCb OutFileStream::cb()
|
|
{
|
|
using namespace std::placeholders;
|
|
|
|
return std::bind(&OutFileStream::putBytes, this, _1, _2);
|
|
}
|
|
|
|
// InFileStream
|
|
|
|
struct InFileStream::Private
|
|
{
|
|
// Setting the offset_ to the buffer size will force a fill on the first read.
|
|
Private(std::istream& in) : f_(in)
|
|
{ reset(); }
|
|
|
|
void getBytes(unsigned char *buf, size_t request);
|
|
size_t fillit();
|
|
void reset()
|
|
{
|
|
buf_.resize(1 << 20);
|
|
offset_ = buf_.size();
|
|
}
|
|
|
|
std::istream& f_;
|
|
std::vector<unsigned char> buf_;
|
|
size_t offset_;
|
|
};
|
|
|
|
InFileStream::InFileStream(std::istream& in) : p_(new Private(in))
|
|
{}
|
|
|
|
InFileStream::~InFileStream()
|
|
{}
|
|
|
|
// This will force a fill on the next fetch.
|
|
void InFileStream::reset()
|
|
{
|
|
p_->reset();
|
|
}
|
|
|
|
InputCb InFileStream::cb()
|
|
{
|
|
using namespace std::placeholders;
|
|
|
|
return std::bind(&InFileStream::Private::getBytes, p_.get(), _1, _2);
|
|
}
|
|
|
|
void InFileStream::Private::getBytes(unsigned char *buf, size_t request)
|
|
{
|
|
// Almost all requests are size 1.
|
|
if (request == 1)
|
|
{
|
|
if (offset_ >= buf_.size())
|
|
fillit();
|
|
*buf = buf_[offset_++];
|
|
return;
|
|
}
|
|
|
|
size_t available = buf_.size() - offset_;
|
|
if (request <= available)
|
|
{
|
|
unsigned char *begin = buf_.data() + offset_;
|
|
unsigned char *end = begin + request;
|
|
std::copy(begin, end, buf);
|
|
offset_ += request;
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
size_t bytes = (std::min)(request, available);
|
|
unsigned char *begin = buf_.data() + offset_;
|
|
unsigned char *end = begin + bytes;
|
|
std::copy(begin, end, buf);
|
|
offset_ += bytes;
|
|
request -= bytes;
|
|
if (request == 0)
|
|
break;
|
|
buf += bytes;
|
|
available = fillit();
|
|
} while (true);
|
|
}
|
|
}
|
|
|
|
size_t InFileStream::Private::fillit()
|
|
{
|
|
offset_ = 0;
|
|
f_.read(reinterpret_cast<char *>(buf_.data()), buf_.size());
|
|
size_t filled = f_.gcount();
|
|
|
|
if (filled == 0)
|
|
throw error("Unexpected end of file.");
|
|
buf_.resize(filled);
|
|
return filled;
|
|
}
|
|
|
|
} // namespace lazperf
|