You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
132 lines
4.0 KiB
C++
132 lines
4.0 KiB
C++
/*
|
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
*
|
|
*/
|
|
|
|
|
|
#ifndef CRYINCLUDE_CRYSYSTEM_HUFFMAN_H
|
|
#define CRYINCLUDE_CRYSYSTEM_HUFFMAN_H
|
|
#pragma once
|
|
|
|
|
|
class HuffmanCoder
|
|
{
|
|
private:
|
|
struct HuffmanTreeNode
|
|
{
|
|
uint32 count;
|
|
uint32 savedCount;
|
|
int child0;
|
|
int child1;
|
|
};
|
|
|
|
struct HuffmanSymbolCode
|
|
{
|
|
uint32 value;
|
|
uint32 numBits;
|
|
};
|
|
|
|
struct BitStreamBuilder
|
|
{
|
|
enum EModes
|
|
{
|
|
eM_WRITE,
|
|
eM_READ
|
|
};
|
|
union buf_ptr
|
|
{
|
|
uint8* ptr;
|
|
const uint8* const_ptr;
|
|
};
|
|
EModes m_mode;
|
|
uint8 m_mask;
|
|
buf_ptr m_pBufferStart;
|
|
buf_ptr m_pBufferCursor;
|
|
buf_ptr m_pBufferEnd; //Pointer to the last byte in the buffer
|
|
|
|
BitStreamBuilder(uint8* pBufferStart, uint8* pBufferEnd)
|
|
: m_mode(eM_WRITE)
|
|
, m_mask(0x80)
|
|
{
|
|
m_pBufferStart.ptr = pBufferStart;
|
|
m_pBufferCursor.ptr = pBufferStart;
|
|
m_pBufferEnd.ptr = pBufferEnd;
|
|
}
|
|
BitStreamBuilder(const uint8* pBufferStart, const uint8* pBufferEnd)
|
|
: m_mode(eM_READ)
|
|
, m_mask(0x80)
|
|
{
|
|
m_pBufferStart.const_ptr = pBufferStart;
|
|
m_pBufferCursor.const_ptr = pBufferStart;
|
|
m_pBufferEnd.const_ptr = pBufferEnd;
|
|
}
|
|
|
|
void AddBits(uint32 value, uint32 numBits);
|
|
void AddBits(uint8 value, uint32 numBits);
|
|
//Returns 1 or 0 for valid values. Returns 2 if the buffer has run out or is the wrong type of builder.
|
|
uint8 GetBit();
|
|
};
|
|
|
|
const static int MAX_SYMBOL_VALUE = (255);
|
|
const static int MAX_NUM_SYMBOLS = (MAX_SYMBOL_VALUE + 1);
|
|
const static int END_OF_STREAM = (MAX_NUM_SYMBOLS);
|
|
const static int MAX_NUM_CODES = (MAX_NUM_SYMBOLS + 1);
|
|
const static int MAX_NUM_NODES = (MAX_NUM_CODES * 2);
|
|
const static int MAX_NODE = (MAX_NUM_NODES - 1);
|
|
|
|
enum EHuffmanCoderState
|
|
{
|
|
eHCS_NEW, //Has been created, Init not called
|
|
eHCS_OPEN, //Init has been called, tree not yet constructed. Can accept new data.
|
|
eHCS_FINAL //Finalize has been called. Can no longer accept data, but can encode/decode.
|
|
};
|
|
|
|
HuffmanTreeNode* m_TreeNodes;
|
|
HuffmanSymbolCode* m_Codes;
|
|
uint32* m_Counts;
|
|
int m_RootNode;
|
|
uint32 m_RefCount;
|
|
EHuffmanCoderState m_State;
|
|
|
|
public:
|
|
HuffmanCoder()
|
|
: m_TreeNodes(NULL)
|
|
, m_Codes(NULL)
|
|
, m_Counts(NULL)
|
|
, m_State(eHCS_NEW)
|
|
, m_RootNode(0)
|
|
, m_RefCount(0) {}
|
|
~HuffmanCoder()
|
|
{
|
|
SAFE_DELETE_ARRAY(m_TreeNodes);
|
|
SAFE_DELETE_ARRAY(m_Codes);
|
|
SAFE_DELETE_ARRAY(m_Counts);
|
|
}
|
|
|
|
//A bit like an MD5 generator, has three phases.
|
|
//Clears the existing data
|
|
void Init();
|
|
//Adds the values of an array of chars to the counts
|
|
void Update(const uint8* const pSource, const size_t numBytes);
|
|
//Construct the coding tree using the counts
|
|
void Finalize();
|
|
|
|
//We typically create a Huffman Coder per localized string table loaded. Since we can and do unload strings at runtime, it's useful to keep a ref count of each coder.
|
|
inline void AddRef() { m_RefCount++; }
|
|
inline void DecRef() { m_RefCount = m_RefCount > 0 ? m_RefCount - 1 : 0; }
|
|
inline uint32 RefCount() { return m_RefCount; }
|
|
|
|
void CompressInput(const uint8* const pInput, const size_t numBytes, uint8* const pOutput, size_t* const outputSize);
|
|
size_t UncompressInput(const uint8* const pInput, const size_t numBytes, uint8* const pOutput, const size_t maxOutputSize);
|
|
|
|
private:
|
|
void ScaleCountsAndUpdateNodes();
|
|
int BuildTree();
|
|
void ConvertTreeToCode(const HuffmanTreeNode* const pNodes, HuffmanSymbolCode* const pCodes, const unsigned int value, const unsigned int numBits, const int node);
|
|
};
|
|
|
|
#endif // CRYINCLUDE_CRYSYSTEM_HUFFMAN_H
|