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/CryEngine/CrySystem/Huffman.h

154 lines
4.9 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#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);
void GetMemoryUsage(ICrySizer* pSizer) const
{
pSizer->AddObject(this, sizeof(*this));
if (m_Counts != NULL)
{
pSizer->AddObject(m_Counts, sizeof(uint32), MAX_NUM_SYMBOLS);
}
if (m_TreeNodes != NULL)
{
pSizer->AddObject(m_TreeNodes, sizeof(HuffmanTreeNode), MAX_NUM_NODES);
}
if (m_Codes != NULL)
{
pSizer->AddObject(m_Codes, sizeof(HuffmanSymbolCode), MAX_NUM_CODES);
}
}
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