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.
o3de/Code/Legacy/CrySystem/Huffman.h

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