2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-12-23 03:18:59 +00:00
qpdf/libqpdf/BufferInputSource.cc
Jay Berkenbilt 79f6b4823b Convert remaining public classes to use Members pattern
Have classes contain only a single private member of type
PointerHolder<Members>. This makes it safe to change the structure of
the Members class without breaking binary compatibility. Many of the
classes already follow this pattern quite successfully. This brings in
the rest of the class that are part of the public API.
2019-06-22 10:13:27 -04:00

171 lines
3.8 KiB
C++

#include <qpdf/BufferInputSource.hh>
#include <qpdf/QIntC.hh>
#include <string.h>
#include <stdexcept>
#include <algorithm>
BufferInputSource::Members::Members(bool own_memory,
std::string const& description,
Buffer* buf) :
own_memory(own_memory),
description(description),
buf(buf),
cur_offset(0)
{
}
BufferInputSource::Members::~Members()
{
}
BufferInputSource::BufferInputSource(std::string const& description,
Buffer* buf, bool own_memory) :
m(new Members(own_memory, description, buf))
{
}
BufferInputSource::BufferInputSource(std::string const& description,
std::string const& contents) :
m(new Members(true, description, 0))
{
this->m->buf = new Buffer(contents.length());
unsigned char* bp = this->m->buf->getBuffer();
memcpy(bp, contents.c_str(), contents.length());
}
BufferInputSource::~BufferInputSource()
{
if (this->m->own_memory)
{
delete this->m->buf;
}
}
qpdf_offset_t const
BufferInputSource::bufSizeAsOffset() const
{
return QIntC::to_offset(this->m->buf->getSize());
}
qpdf_offset_t
BufferInputSource::findAndSkipNextEOL()
{
if (this->m->cur_offset < 0)
{
throw std::logic_error("INTERNAL ERROR: BufferInputSource offset < 0");
}
qpdf_offset_t end_pos = bufSizeAsOffset();
if (this->m->cur_offset >= end_pos)
{
this->last_offset = end_pos;
this->m->cur_offset = end_pos;
return end_pos;
}
qpdf_offset_t result = 0;
size_t len = QIntC::to_size(end_pos - this->m->cur_offset);
unsigned char const* buffer = this->m->buf->getBuffer();
void* start = const_cast<unsigned char*>(buffer) + this->m->cur_offset;
unsigned char* p1 = static_cast<unsigned char*>(memchr(start, '\r', len));
unsigned char* p2 = static_cast<unsigned char*>(memchr(start, '\n', len));
unsigned char* p = (p1 && p2) ? std::min(p1, p2) : p1 ? p1 : p2;
if (p)
{
result = p - buffer;
this->m->cur_offset = result + 1;
++p;
while ((this->m->cur_offset < end_pos) &&
((*p == '\r') || (*p == '\n')))
{
++p;
++this->m->cur_offset;
}
}
else
{
this->m->cur_offset = end_pos;
result = end_pos;
}
return result;
}
std::string const&
BufferInputSource::getName() const
{
return this->m->description;
}
qpdf_offset_t
BufferInputSource::tell()
{
return this->m->cur_offset;
}
void
BufferInputSource::seek(qpdf_offset_t offset, int whence)
{
switch (whence)
{
case SEEK_SET:
this->m->cur_offset = offset;
break;
case SEEK_END:
this->m->cur_offset = bufSizeAsOffset() + offset;
break;
case SEEK_CUR:
this->m->cur_offset += offset;
break;
default:
throw std::logic_error(
"INTERNAL ERROR: invalid argument to BufferInputSource::seek");
break;
}
if (this->m->cur_offset < 0)
{
throw std::runtime_error(
this->m->description + ": seek before beginning of buffer");
}
}
void
BufferInputSource::rewind()
{
this->m->cur_offset = 0;
}
size_t
BufferInputSource::read(char* buffer, size_t length)
{
if (this->m->cur_offset < 0)
{
throw std::logic_error("INTERNAL ERROR: BufferInputSource offset < 0");
}
qpdf_offset_t end_pos = bufSizeAsOffset();
if (this->m->cur_offset >= end_pos)
{
this->last_offset = end_pos;
return 0;
}
this->last_offset = this->m->cur_offset;
size_t len = std::min(
QIntC::to_size(end_pos - this->m->cur_offset), length);
memcpy(buffer, this->m->buf->getBuffer() + this->m->cur_offset, len);
this->m->cur_offset += QIntC::to_offset(len);
return len;
}
void
BufferInputSource::unreadCh(char ch)
{
if (this->m->cur_offset > 0)
{
--this->m->cur_offset;
}
}