PDF4QT/PdfForQtLib/sources/pdfutils.cpp

132 lines
3.8 KiB
C++
Raw Normal View History

2019-05-10 19:48:52 +02:00
// Copyright (C) 2019 Jakub Melka
//
// This file is part of PdfForQt.
//
// PdfForQt 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 3 of the License, or
// (at your option) any later version.
//
// PdfForQt 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 PDFForQt. If not, see <https://www.gnu.org/licenses/>.
#include "pdfutils.h"
#include "pdfexception.h"
namespace pdf
{
2019-09-15 16:50:34 +02:00
PDFBitReader::PDFBitReader(const QByteArray* stream, Value bitsPerComponent) :
2019-05-10 19:48:52 +02:00
m_stream(stream),
2019-09-15 16:50:34 +02:00
m_position(0),
2019-05-10 19:48:52 +02:00
m_bitsPerComponent(bitsPerComponent),
m_maximalValue((static_cast<Value>(1) << m_bitsPerComponent) - static_cast<Value>(1)),
m_buffer(0),
m_bitsInBuffer(0)
{
// We need reserve, so we allow number of length of component as 1-56 bits.
Q_ASSERT(bitsPerComponent > 0);
Q_ASSERT(bitsPerComponent < 56);
}
2019-09-15 16:50:34 +02:00
PDFBitReader::Value PDFBitReader::read(PDFBitReader::Value bits)
2019-05-10 19:48:52 +02:00
{
2019-09-15 16:50:34 +02:00
while (m_bitsInBuffer < bits)
2019-05-10 19:48:52 +02:00
{
2019-09-15 16:50:34 +02:00
if (m_position < m_stream->size())
2019-05-10 19:48:52 +02:00
{
2019-09-15 16:50:34 +02:00
uint8_t currentByte = static_cast<uint8_t>((*m_stream)[m_position++]);
2019-05-10 19:48:52 +02:00
m_buffer = (m_buffer << 8) | currentByte;
m_bitsInBuffer += 8;
}
else
{
throw PDFException(PDFTranslationContext::tr("Not enough data to read %1-bit value.").arg(bits));
2019-05-10 19:48:52 +02:00
}
}
// Now we have enough bits to read the data
2019-09-15 16:50:34 +02:00
Value value = (m_buffer >> (m_bitsInBuffer - bits)) & ((static_cast<Value>(1) << bits) - static_cast<Value>(1));
m_bitsInBuffer -= bits;
2019-05-10 19:48:52 +02:00
return value;
}
void PDFBitReader::seek(qint64 position)
{
2019-09-15 16:50:34 +02:00
if (position < m_stream->size())
2019-05-10 19:48:52 +02:00
{
2019-09-15 16:50:34 +02:00
m_position = position;
2019-05-10 19:48:52 +02:00
m_buffer = 0;
m_bitsInBuffer = 0;
}
else
{
throw PDFException(PDFTranslationContext::tr("Can't seek to position %1.").arg(position));
2019-05-10 19:48:52 +02:00
}
}
2019-09-15 16:50:34 +02:00
void PDFBitReader::alignToBytes()
{
const Value remainder = m_bitsInBuffer % 8;
if (remainder > 0)
{
read(remainder);
}
}
2019-09-22 13:18:42 +02:00
bool PDFBitReader::isAtEnd() const
{
return (m_position >= m_stream->size());
}
2019-10-05 17:38:15 +02:00
PDFBitWriter::PDFBitWriter(Value bitsPerComponent) :
m_bitsPerComponent(bitsPerComponent),
m_mask((static_cast<Value>(1) << m_bitsPerComponent) - static_cast<Value>(1)),
m_buffer(0),
m_bitsInBuffer(0)
{
}
void PDFBitWriter::write(Value value)
{
m_buffer = (m_buffer << m_bitsPerComponent) | (value & m_mask);
m_bitsInBuffer += m_bitsPerComponent;
flush(false);
}
void PDFBitWriter::flush(bool alignToByteBoundary)
{
if (m_bitsInBuffer >= 8)
{
Value remainder = m_bitsInBuffer % 8;
Value alignedBuffer = m_buffer >> remainder;
Value bitsToWrite = m_bitsInBuffer - remainder;
Value bytesToWrite = bitsToWrite / 8;
for (Value byteIndex = 0; byteIndex < bytesToWrite; ++byteIndex)
{
const Value shift = (bytesToWrite - 1 - byteIndex) * 8;
m_outputByteArray.push_back(static_cast<const char>(static_cast<uint8_t>((alignedBuffer >> shift) & 0xFF)));
}
m_bitsInBuffer = remainder;
}
if (alignToByteBoundary && m_bitsInBuffer > 0)
{
Value missingBits = 8 - m_bitsInBuffer % 8;
m_buffer = m_buffer << missingBits;
m_bitsInBuffer += missingBits;
flush(false);
}
}
2019-05-10 19:48:52 +02:00
} // namespace pdf