Continue png writing.
This commit is contained in:
parent
5400a232dd
commit
8f97e9b7a1
29 changed files with 714 additions and 302 deletions
|
@ -1,5 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "AbstractChecksumCalculator.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class BitStream;
|
||||
|
||||
class AbstractEncoder
|
||||
|
@ -14,10 +18,17 @@ public:
|
|||
|
||||
virtual ~AbstractEncoder() = default;
|
||||
|
||||
void addChecksumCalculator(AbstractChecksumCalculator* calculator)
|
||||
{
|
||||
mChecksumCalculators.push_back(calculator);
|
||||
}
|
||||
|
||||
virtual bool encode() = 0;
|
||||
virtual bool decode() = 0;
|
||||
|
||||
protected:
|
||||
|
||||
std::vector<AbstractChecksumCalculator*> mChecksumCalculators;
|
||||
BitStream* mInputStream{nullptr};
|
||||
BitStream* mOutputStream{nullptr};
|
||||
};
|
||||
|
|
29
src/compression/Adler32Checksum.h
Normal file
29
src/compression/Adler32Checksum.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include "AbstractChecksumCalculator.h"
|
||||
|
||||
class Adler32Checksum : public AbstractChecksumCalculator
|
||||
{
|
||||
public:
|
||||
void addValue(unsigned char val) override
|
||||
{
|
||||
mSum1 = (mSum1 + val) % MOD_ADLER32;
|
||||
mSum2 = (mSum2 + mSum1) % MOD_ADLER32;
|
||||
}
|
||||
|
||||
uint32_t getChecksum() const override
|
||||
{
|
||||
return (mSum2 << 16) | mSum1;
|
||||
}
|
||||
|
||||
void reset() override
|
||||
{
|
||||
mSum1 = 1;
|
||||
mSum2 = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr unsigned MOD_ADLER32{65536};
|
||||
uint32_t mSum1{1};
|
||||
uint32_t mSum2{0};
|
||||
};
|
|
@ -3,10 +3,9 @@ list(APPEND compression_LIB_INCLUDES
|
|||
StreamCompressor.cpp
|
||||
HuffmanEncoder.cpp
|
||||
RunLengthEncoder.cpp
|
||||
ZlibData.cpp
|
||||
ZlibEncoder.cpp
|
||||
DeflateEncoder.cpp
|
||||
DeflateBlock.cpp
|
||||
deflate/DeflateEncoder.cpp
|
||||
deflate/DeflateBlock.cpp
|
||||
Lz77Encoder.cpp
|
||||
CyclicRedundancyChecker.cpp
|
||||
)
|
||||
|
@ -14,9 +13,10 @@ list(APPEND compression_LIB_INCLUDES
|
|||
add_library(compression SHARED ${compression_LIB_INCLUDES})
|
||||
|
||||
target_include_directories(compression PUBLIC
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/deflate
|
||||
)
|
||||
|
||||
target_link_libraries(compression PUBLIC core)
|
||||
set_property(TARGET compression PROPERTY FOLDER src)
|
||||
set_target_properties( compression PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
||||
set_target_properties( compression PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
#include "DeflateEncoder.h"
|
||||
|
||||
#include "BitStream.h"
|
||||
#include "DeflateBlock.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
DeflateEncoder::DeflateEncoder(BitStream* inputStream, BitStream* outputStream)
|
||||
: AbstractEncoder(inputStream, outputStream)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
DeflateEncoder::~DeflateEncoder()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool DeflateEncoder::encode()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeflateEncoder::decode()
|
||||
{
|
||||
auto working_block = std::make_unique<DeflateBlock>(mInputStream, mOutputStream);
|
||||
working_block->readHeader();
|
||||
|
||||
DeflateBlock* raw_block = working_block.get();
|
||||
|
||||
while(!raw_block->isFinalBlock())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1,107 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "ByteUtils.h"
|
||||
#include "BitStream.h"
|
||||
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
class ZlibData
|
||||
{
|
||||
public:
|
||||
void setByte(unsigned idx, unsigned char data)
|
||||
{
|
||||
mBitStream.setByte(idx, data);
|
||||
}
|
||||
|
||||
void setDataSize(std::size_t size)
|
||||
{
|
||||
mBitStream.setBufferSize(size);
|
||||
}
|
||||
|
||||
void setCompressionMethod(unsigned char method)
|
||||
{
|
||||
std::cout << "Got compression input " << static_cast<int>(method) << std::endl;
|
||||
mCmf = method;
|
||||
mCompressionMethod = ByteUtils::getLowerNBits(method, 4);
|
||||
mCompressionInfo = ByteUtils::getHigherNBits(method, 4);
|
||||
|
||||
std::cout << "Got compression method " << static_cast<int>(mCompressionMethod) << " and info " << static_cast<int>(mCompressionInfo) << std::endl;
|
||||
}
|
||||
|
||||
void setExtraFlags(unsigned char extraFlags)
|
||||
{
|
||||
std::cout << "Got flags " << static_cast<int>(extraFlags) << std::endl;
|
||||
|
||||
mFlg = extraFlags;
|
||||
mFlagCheck = ByteUtils::getLowerNBits(extraFlags, 5);
|
||||
mFlagDict = ByteUtils::getBitN(extraFlags, 5);
|
||||
mFlagLevel = ByteUtils::getHigherNBits(extraFlags, 2);
|
||||
|
||||
std::cout << "Got flag check " << static_cast<int>(mFlagCheck) << " and dict " << static_cast<int>(mFlagDict) << " and level " << static_cast<int>(mFlagLevel) << std::endl;
|
||||
}
|
||||
|
||||
void processData()
|
||||
{
|
||||
unsigned char NO_COMPRESSION = 0x00;
|
||||
unsigned char FIXED_HUFFMAN = 0x01;
|
||||
unsigned char DYNAMIC_HUFFMAN = 0x02;
|
||||
unsigned char ERROR = 0x03;
|
||||
|
||||
bool in_final_block = false;
|
||||
while(mBitStream.loadNextByte())
|
||||
{
|
||||
auto working_byte = mBitStream.getCurrentByte();
|
||||
std::cout << "Into process data, byte is: " << static_cast<unsigned>(working_byte) << std::endl;
|
||||
|
||||
unsigned char final_block{0};
|
||||
mBitStream.getNextNBits(1, final_block);
|
||||
if (final_block)
|
||||
{
|
||||
std::cout << "Got final block" << std::endl;
|
||||
in_final_block = true;
|
||||
}
|
||||
|
||||
unsigned char compress_type{0};
|
||||
mBitStream.getNextNBits(2, compress_type);
|
||||
std::cout << "Compress type byte is: " << static_cast<unsigned>(compress_type) << std::endl;
|
||||
if (compress_type == NO_COMPRESSION)
|
||||
{
|
||||
std::cout << "Got NO_COMPRESSION" << std::endl;
|
||||
}
|
||||
else if (compress_type == FIXED_HUFFMAN)
|
||||
{
|
||||
std::cout << "Got FIXED_HUFFMAN" << std::endl;
|
||||
}
|
||||
else if (compress_type == DYNAMIC_HUFFMAN)
|
||||
{
|
||||
std::cout << "Got DYNAMIC_HUFFMAN" << std::endl;
|
||||
|
||||
unsigned char h_list{0};
|
||||
mBitStream.getNextNBits(5, h_list);
|
||||
mHlist = h_list + 257;
|
||||
std::cout << "Got HLIST " << mHlist << std::endl;
|
||||
|
||||
}
|
||||
else if (compress_type == ERROR)
|
||||
{
|
||||
std::cout << "Got ERROR" << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
BitStream mBitStream;
|
||||
|
||||
unsigned mHlist{0};
|
||||
|
||||
unsigned char mCmf{0};
|
||||
unsigned char mFlg{0};
|
||||
unsigned char mCompressionMethod{0};
|
||||
unsigned char mCompressionInfo{0};
|
||||
unsigned char mFlagCheck{0};
|
||||
unsigned char mFlagDict{0};
|
||||
unsigned char mFlagLevel{0};
|
||||
unsigned char mCheckValue{0};
|
||||
};
|
|
@ -3,13 +3,18 @@
|
|||
#include "ByteUtils.h"
|
||||
#include "DeflateEncoder.h"
|
||||
#include "FileLogger.h"
|
||||
#include "BitStream.h"
|
||||
|
||||
#include "Adler32Checksum.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
ZlibEncoder::ZlibEncoder(BitStream* inputStream, BitStream* outputStream)
|
||||
: AbstractEncoder(inputStream, outputStream)
|
||||
{
|
||||
|
||||
mChecksumCalculator = std::make_unique<Adler32Checksum>();
|
||||
}
|
||||
|
||||
ZlibEncoder::~ZlibEncoder()
|
||||
|
@ -17,58 +22,132 @@ ZlibEncoder::~ZlibEncoder()
|
|||
|
||||
}
|
||||
|
||||
void ZlibEncoder::setCompressionMethod(unsigned char method)
|
||||
void ZlibEncoder::setWindowSize(unsigned size)
|
||||
{
|
||||
std::cout << "Got compression input " << static_cast<int>(method) << std::endl;
|
||||
mCmf = method;
|
||||
mCompressionMethod = ByteUtils::getLowerNBits(method, 4);
|
||||
mCompressionInfo = ByteUtils::getHigherNBits(method, 4);
|
||||
|
||||
std::cout << "Got compression method " << static_cast<int>(mCompressionMethod) << " and info " << static_cast<int>(mCompressionInfo) << std::endl;
|
||||
mWindowSize = size;
|
||||
}
|
||||
|
||||
void ZlibEncoder::setExtraFlags(unsigned char extraFlags)
|
||||
std::string ZlibEncoder::toString(CompressionLevel level) const
|
||||
{
|
||||
switch(level)
|
||||
{
|
||||
case CompressionLevel::FASTEST:
|
||||
return "FASTEST";
|
||||
case CompressionLevel::FAST:
|
||||
return "FAST";
|
||||
case CompressionLevel::DEFAULT:
|
||||
return "DEFAULT";
|
||||
case CompressionLevel::MAX_COMPRESSION:
|
||||
return "MAX_COMPRESSION";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
std::string ZlibEncoder::toString(CompressionMethod method) const
|
||||
{
|
||||
return method == CompressionMethod::DEFLATE ? "DEFLATE" : "UNKNOWN";
|
||||
}
|
||||
|
||||
void ZlibEncoder::parseCompressionMethod(unsigned char method)
|
||||
{
|
||||
std::cout << "Got compression input " << static_cast<int>(method) << std::endl;
|
||||
mCompressionMethod = static_cast<CompressionMethod>(ByteUtils::getLowerNBits(method, 4));
|
||||
auto compression_info = ByteUtils::getHigherNBits(method, 4);
|
||||
|
||||
if (mCompressionMethod == CompressionMethod::DEFLATE)
|
||||
{
|
||||
mWindowSize = pow(2, compression_info + 8);
|
||||
}
|
||||
}
|
||||
|
||||
void ZlibEncoder::parseExtraFlags(unsigned char extraFlags)
|
||||
{
|
||||
std::cout << "Got flags " << static_cast<int>(extraFlags) << std::endl;
|
||||
|
||||
mFlg = extraFlags;
|
||||
mFlagCheck = ByteUtils::getLowerNBits(extraFlags, 5);
|
||||
mFlagDict = ByteUtils::getBitN(extraFlags, 5);
|
||||
mFlagLevel = ByteUtils::getHigherNBits(extraFlags, 2);
|
||||
mUseDictionary = bool(ByteUtils::getBitN(extraFlags, 5));
|
||||
mFlagLevel = static_cast<CompressionLevel>(ByteUtils::getHigherNBits(extraFlags, 2));
|
||||
}
|
||||
|
||||
std::string ZlibEncoder::getData() const
|
||||
{
|
||||
std::stringstream sstream;
|
||||
sstream << "ZlibEncoder data \n";
|
||||
sstream << "Compression method: " << toString(mCompressionMethod) << '\n';
|
||||
sstream << "Window size: " << mWindowSize << '\n';
|
||||
sstream << "Flag check: " << mFlagCheck << '\n';
|
||||
sstream << "Use dictionary: " << mUseDictionary << '\n';
|
||||
sstream << "Flag level: " << toString(mFlagLevel) << '\n';
|
||||
return sstream.str();
|
||||
|
||||
std::cout << "Got flag check " << static_cast<int>(mFlagCheck) << " and dict " << static_cast<int>(mFlagDict) << " and level " << static_cast<int>(mFlagLevel) << std::endl;
|
||||
}
|
||||
|
||||
bool ZlibEncoder::encode()
|
||||
{
|
||||
DeflateEncoder* deflate_encoder{nullptr};
|
||||
if (!mWorkingEncoder)
|
||||
{
|
||||
if (mCompressionMethod == 8)
|
||||
if (mCompressionMethod == CompressionMethod::DEFLATE)
|
||||
{
|
||||
mWorkingEncoder = std::make_unique<DeflateEncoder>(mInputStream, mOutputStream);
|
||||
auto uq_deflate_encoder = std::make_unique<DeflateEncoder>(mInputStream, mOutputStream);
|
||||
deflate_encoder = uq_deflate_encoder.get();
|
||||
mWorkingEncoder = std::move(uq_deflate_encoder);
|
||||
mWorkingEncoder->addChecksumCalculator(mChecksumCalculator.get());
|
||||
}
|
||||
else
|
||||
{
|
||||
MLOG_ERROR("Zib requested decoder not recognized: " << mCompressionMethod << " aborting encode");
|
||||
MLOG_ERROR("Zib requested decoder not recognized: " << static_cast<int>(mCompressionMethod) << " aborting encode");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return mWorkingEncoder->encode();
|
||||
deflate_encoder->setCompressionMethod(mDeflateCompressionMethod);
|
||||
|
||||
auto compression_info = static_cast<unsigned char>(log2(mWindowSize) - 8);
|
||||
const unsigned char compression_byte = (compression_info << 4) | static_cast<unsigned char>(mCompressionMethod);
|
||||
|
||||
std::cout << "ZlibEncoder Writing compression byte " << static_cast<int>(compression_byte) << " with info " << static_cast<int>(compression_info) << std::endl;
|
||||
mOutputStream->writeByte(compression_byte);
|
||||
|
||||
unsigned char flag_byte{0};
|
||||
flag_byte |= (static_cast<unsigned char>(mUseDictionary) << 5);
|
||||
flag_byte |= (static_cast<unsigned char>(mFlagLevel) << 6);
|
||||
|
||||
const auto mod = (unsigned(compression_byte)*256 + flag_byte) % 31;
|
||||
flag_byte += (31 - mod);
|
||||
|
||||
std::cout << "ZlibEncoder Writing Flag byte " << static_cast<int>(flag_byte) << std::endl;
|
||||
mOutputStream->writeByte(flag_byte);
|
||||
|
||||
if(!mWorkingEncoder->encode())
|
||||
{
|
||||
MLOG_ERROR("Sub-Encoder failed - aborting zlib encode");
|
||||
//return false;
|
||||
}
|
||||
|
||||
const auto checksum = mChecksumCalculator->getChecksum();
|
||||
std::cout << "ZlibEncoder Writing Checksum " << checksum << std::endl;
|
||||
mOutputStream->write(checksum);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZlibEncoder::decode()
|
||||
{
|
||||
parseCompressionMethod(*mInputStream->readNextByte());
|
||||
parseExtraFlags(*mInputStream->readNextByte());
|
||||
|
||||
if (!mWorkingEncoder)
|
||||
{
|
||||
if (mCompressionMethod == 8)
|
||||
if (mCompressionMethod == CompressionMethod::DEFLATE)
|
||||
{
|
||||
mWorkingEncoder = std::make_unique<DeflateEncoder>(mInputStream, mOutputStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
MLOG_ERROR("Zib requested decoder not recognized: " << mCompressionMethod << " aborting decode");
|
||||
MLOG_ERROR("Zib requested decoder not recognized: " << static_cast<int>(mCompressionMethod) << " aborting decode");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return mWorkingEncoder->decode();
|
||||
}
|
||||
|
|
|
@ -2,33 +2,54 @@
|
|||
|
||||
#include "AbstractEncoder.h"
|
||||
|
||||
#include "DeflateElements.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
class AbstractChecksumCalculator;
|
||||
|
||||
class ZlibEncoder : public AbstractEncoder
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
enum class CompressionMethod : unsigned char
|
||||
{
|
||||
DEFLATE = 8,
|
||||
};
|
||||
|
||||
enum class CompressionLevel : unsigned char
|
||||
{
|
||||
FASTEST,
|
||||
FAST,
|
||||
DEFAULT,
|
||||
MAX_COMPRESSION
|
||||
};
|
||||
|
||||
ZlibEncoder(BitStream* inputStream, BitStream* outputStream);
|
||||
~ZlibEncoder();
|
||||
|
||||
void setCompressionMethod(unsigned char method);
|
||||
|
||||
void setExtraFlags(unsigned char extraFlags);
|
||||
void setWindowSize(unsigned size);
|
||||
|
||||
bool encode() override;
|
||||
|
||||
bool decode() override;
|
||||
|
||||
private:
|
||||
unsigned char mCmf{0};
|
||||
unsigned char mFlg{0};
|
||||
unsigned char mCompressionMethod{8};
|
||||
unsigned char mCompressionInfo{0};
|
||||
unsigned char mFlagCheck{0};
|
||||
unsigned char mFlagDict{0};
|
||||
unsigned char mFlagLevel{0};
|
||||
unsigned char mCheckValue{0};
|
||||
std::string getData() const;
|
||||
std::string toString(CompressionLevel level) const;
|
||||
std::string toString(CompressionMethod method) const;
|
||||
|
||||
private:
|
||||
void parseCompressionMethod(unsigned char method);
|
||||
void parseExtraFlags(unsigned char extraFlags);
|
||||
|
||||
CompressionMethod mCompressionMethod{CompressionMethod::DEFLATE};
|
||||
Deflate::CompressionMethod mDeflateCompressionMethod{Deflate::CompressionMethod::NONE};
|
||||
unsigned mWindowSize{32768}; // Window size, n in 2^(n+8) bytes
|
||||
|
||||
unsigned char mFlagCheck{0};
|
||||
bool mUseDictionary{false};
|
||||
CompressionLevel mFlagLevel{CompressionLevel::DEFAULT};
|
||||
|
||||
std::unique_ptr<AbstractChecksumCalculator> mChecksumCalculator;
|
||||
std::unique_ptr<AbstractEncoder> mWorkingEncoder;
|
||||
};
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
#include "DeflateBlock.h"
|
||||
|
||||
#include "ByteUtils.h"
|
||||
#include "AbstractChecksumCalculator.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
DeflateBlock::DeflateBlock(BitStream* inputStream, BitStream* outputStream)
|
||||
: mInputStream(inputStream),
|
||||
|
@ -88,7 +90,7 @@ void DeflateBlock::setDistanceTableLength(unsigned length)
|
|||
|
||||
void DeflateBlock::setIsFinalBlock(bool isFinal)
|
||||
{
|
||||
|
||||
mInFinalBlock = isFinal;
|
||||
}
|
||||
|
||||
void DeflateBlock::flushToStream()
|
||||
|
@ -224,6 +226,22 @@ void DeflateBlock::readDynamicHuffmanTable()
|
|||
readLiteralCodeLengths();
|
||||
}
|
||||
|
||||
std::string DeflateBlock::getMetaData() const
|
||||
{
|
||||
std::stringstream sstr;
|
||||
sstr << "DeflateBlock Metadata \n";
|
||||
|
||||
sstr << "Final block: " << mInFinalBlock << '\n';
|
||||
sstr << "Compression method: " << Deflate::toString(mCompressionMethod) << '\n';
|
||||
|
||||
return sstr.str();
|
||||
}
|
||||
|
||||
bool DeflateBlock::isFinalBlock() const
|
||||
{
|
||||
return mInFinalBlock;
|
||||
}
|
||||
|
||||
void DeflateBlock::readHeader()
|
||||
{
|
||||
auto working_byte = mInputStream->getCurrentByte();
|
||||
|
@ -234,29 +252,33 @@ void DeflateBlock::readHeader()
|
|||
mInputStream->readNextNBits(1, final_block);
|
||||
mInFinalBlock = bool(final_block);
|
||||
|
||||
if (mInFinalBlock)
|
||||
{
|
||||
std::cout << "Got final block" << std::endl;
|
||||
}
|
||||
|
||||
mInputStream->readNextNBits(2, mCompressionType);
|
||||
std::cout << "Compress type byte is: " << static_cast<unsigned>(mCompressionType) << std::endl;
|
||||
if (mCompressionType == NO_COMPRESSION)
|
||||
{
|
||||
std::cout << "Got NO_COMPRESSION" << std::endl;
|
||||
}
|
||||
else if (mCompressionType == FIXED_HUFFMAN)
|
||||
{
|
||||
std::cout << "Got FIXED_HUFFMAN" << std::endl;
|
||||
}
|
||||
else if (mCompressionType == DYNAMIC_HUFFMAN)
|
||||
{
|
||||
std::cout << "Got DYNAMIC_HUFFMAN" << std::endl;
|
||||
readDynamicHuffmanTable();
|
||||
}
|
||||
else if (mCompressionType == ERROR)
|
||||
{
|
||||
std::cout << "Got ERROR" << std::endl;
|
||||
}
|
||||
|
||||
unsigned char compression_type{0};
|
||||
mInputStream->readNextNBits(2, compression_type);
|
||||
mCompressionMethod = static_cast<Deflate::CompressionMethod>(compression_type);
|
||||
}
|
||||
|
||||
void DeflateBlock::write(uint16_t datalength)
|
||||
{
|
||||
unsigned char working_block{0};
|
||||
working_block |= static_cast<unsigned char>(mInFinalBlock);
|
||||
working_block |= static_cast<unsigned char>(mCompressionMethod) << 1;
|
||||
|
||||
if (mCompressionMethod == Deflate::CompressionMethod::NONE)
|
||||
{
|
||||
std::cout << "Writing compression block header " << static_cast<int>(working_block) << std::endl;
|
||||
mOutputStream->writeByte(working_block);
|
||||
|
||||
std::cout << "Writing data length " << datalength << " " << ByteUtils::toString(datalength) << std::endl;
|
||||
mOutputStream->writeWord(datalength);
|
||||
|
||||
std::cout << "Writing iverse data length " << ~datalength << " " << ByteUtils::toString(~datalength) << std::endl;
|
||||
mOutputStream->writeWord(static_cast<uint16_t>(~datalength));
|
||||
|
||||
for(unsigned idx=0; idx<datalength;idx++)
|
||||
{
|
||||
auto byte = *mInputStream->readNextByte();
|
||||
std::cout << "Writing next byte " << static_cast<int>(byte) << std::endl;
|
||||
mOutputStream->writeByte(byte);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,27 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#include "DeflateElements.h"
|
||||
|
||||
#include "BitStream.h"
|
||||
|
||||
class AbstractChecksumCalculator;
|
||||
|
||||
class DeflateBlock
|
||||
{
|
||||
public:
|
||||
DeflateBlock(BitStream* inputStream, BitStream* outputStream);
|
||||
|
||||
void buildCodeLengthMapping();
|
||||
|
||||
std::string getMetaData() const;
|
||||
|
||||
void flushToStream();
|
||||
|
||||
bool isFinalBlock() const;
|
||||
|
||||
void readHeader();
|
||||
|
||||
void readDynamicHuffmanTable();
|
||||
|
||||
void buildCodeLengthMapping();
|
||||
|
||||
void readLiteralCodeLengths();
|
||||
|
||||
bool readNextCodeLengthSymbol(unsigned char& buffer);
|
||||
|
||||
bool isFinalBlock() const
|
||||
{
|
||||
return mInFinalBlock;
|
||||
}
|
||||
|
||||
void setCodeLengthAlphabetLengths(const std::vector<unsigned char>& lengths);
|
||||
|
||||
void setCodeLengthLength(unsigned length);
|
||||
|
@ -32,7 +37,7 @@ public:
|
|||
|
||||
void setIsFinalBlock(bool isFinal);
|
||||
|
||||
void flushToStream();
|
||||
void write(uint16_t datalength);
|
||||
|
||||
private:
|
||||
BitStream* mInputStream;
|
||||
|
@ -49,12 +54,6 @@ private:
|
|||
std::vector<unsigned char> mCodeLengthAlphabetLengths;
|
||||
static constexpr unsigned CODE_LENGTH_ALPHABET_PERMUTATION[19]{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
|
||||
|
||||
unsigned char mCompressionType{0};
|
||||
|
||||
bool mInFinalBlock{false};
|
||||
|
||||
static constexpr unsigned char NO_COMPRESSION = 0x00;
|
||||
static constexpr unsigned char FIXED_HUFFMAN = 0x01;
|
||||
static constexpr unsigned char DYNAMIC_HUFFMAN = 0x02;
|
||||
static constexpr unsigned char ERROR = 0x03;
|
||||
Deflate::CompressionMethod mCompressionMethod{Deflate::CompressionMethod::NONE};
|
||||
};
|
33
src/compression/deflate/DeflateElements.h
Normal file
33
src/compression/deflate/DeflateElements.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Deflate
|
||||
{
|
||||
enum class CompressionMethod
|
||||
{
|
||||
NONE,
|
||||
FIXED_HUFFMAN,
|
||||
DYNAMIC_HUFFMAN,
|
||||
ERROR
|
||||
};
|
||||
|
||||
inline std::string toString(CompressionMethod method)
|
||||
{
|
||||
switch (method)
|
||||
{
|
||||
case CompressionMethod::NONE:
|
||||
return "NONE";
|
||||
case CompressionMethod::FIXED_HUFFMAN:
|
||||
return "FIXED_HUFFMAN";
|
||||
case CompressionMethod::DYNAMIC_HUFFMAN:
|
||||
return "DYNAMIC_HUFFMAN";
|
||||
case CompressionMethod::ERROR:
|
||||
return "ERROR";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
78
src/compression/deflate/DeflateEncoder.cpp
Normal file
78
src/compression/deflate/DeflateEncoder.cpp
Normal file
|
@ -0,0 +1,78 @@
|
|||
#include "DeflateEncoder.h"
|
||||
|
||||
#include "BitStream.h"
|
||||
#include "DeflateBlock.h"
|
||||
#include "BufferBitStream.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
DeflateEncoder::DeflateEncoder(BitStream* inputStream, BitStream* outputStream)
|
||||
: AbstractEncoder(inputStream, outputStream)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
DeflateEncoder::~DeflateEncoder()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool DeflateEncoder::encode()
|
||||
{
|
||||
uint16_t count = 0;
|
||||
BufferBitStream stream;
|
||||
std::unique_ptr<DeflateBlock> working_block = std::make_unique<DeflateBlock>(&stream, mOutputStream);
|
||||
|
||||
AbstractChecksumCalculator* checksum_calc;
|
||||
if (mChecksumCalculators.size() > 0)
|
||||
{
|
||||
std::cout << "Setting checksum calculator " << std::endl;
|
||||
mOutputStream->setChecksumCalculator(mChecksumCalculators[0]);
|
||||
}
|
||||
|
||||
while(true)
|
||||
{
|
||||
if (count == mMaxBlockSize)
|
||||
{
|
||||
std::cout << working_block->getMetaData();
|
||||
working_block->write(count);
|
||||
|
||||
working_block = std::make_unique<DeflateBlock>(&stream, mOutputStream);
|
||||
stream.reset();
|
||||
}
|
||||
|
||||
if (auto byte = mInputStream->readNextByte())
|
||||
{
|
||||
stream.writeByte(*byte);
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.resetOffsets();
|
||||
working_block->setIsFinalBlock(true);
|
||||
|
||||
std::cout << working_block->getMetaData();
|
||||
working_block->write(count);
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
mOutputStream->clearChecksumCalculator();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeflateEncoder::decode()
|
||||
{
|
||||
auto working_block = std::make_unique<DeflateBlock>(mInputStream, mOutputStream);
|
||||
working_block->readHeader();
|
||||
|
||||
DeflateBlock* raw_block = working_block.get();
|
||||
|
||||
while(!raw_block->isFinalBlock())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "AbstractEncoder.h"
|
||||
#include "DeflateElements.h"
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
@ -18,8 +19,15 @@ public:
|
|||
|
||||
bool decode() override;
|
||||
|
||||
void setCompressionMethod(Deflate::CompressionMethod method)
|
||||
{
|
||||
mCompressionMethod = method;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<DeflateBlock > > mBlocks;
|
||||
uint16_t mMaxBlockSize{65535};
|
||||
Deflate::CompressionMethod mCompressionMethod{Deflate::CompressionMethod::NONE};
|
||||
std::unique_ptr<DeflateBlock > mLastBlock;
|
||||
};
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue