Files
LGram16 dd97ddec92 Restructure repository to include all source folders
Move git root from Client/ to src/ to track all source code:
- Client: Game client source (moved to Client/Client/)
- Server: Game server source
- GameTools: Development tools
- CryptoSource: Encryption utilities
- database: Database scripts
- Script: Game scripts
- rylCoder_16.02.2008_src: Legacy coder tools
- GMFont, Game: Additional resources

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 20:17:20 +09:00

147 lines
4.6 KiB
C++

// LZW.cpp: implementation of the LZW class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "BinaryTree.h"
//////////////////////////////////////////////////////////////////////
class CBuffer
{
public:
CBuffer() {}
CBuffer(BYTE* pBuffer, int nLength) { m_pBuffer = pBuffer, m_nLength = nLength; }
CBuffer(const CBuffer& buffer) { *this = buffer; }
public:
BYTE* m_pBuffer;
int m_nLength;
inline int compare(const CBuffer* buffer)
{
int nResult = memcmp(m_pBuffer, buffer->m_pBuffer, min(m_nLength, buffer->m_nLength));
if(nResult != 0 || m_nLength == buffer->m_nLength)
return nResult;
return m_nLength > buffer->m_nLength ? 1 : -1;
}
inline void operator=(const CBuffer* buffer) { m_pBuffer = buffer->m_pBuffer; m_nLength = buffer->m_nLength; }
};
bool CompressLZW(BYTE *pSrc, int nSrcLen, BYTE *&pDes, int &nDesLen, int nBitsPerSample)
{
nDesLen = (sizeof(DWORD)+1)<<3;
// allocate buffer for destination buffer
pDes = (BYTE*)malloc(nSrcLen*2);
memset(pDes, 0, nSrcLen*2);
// save source buffer length at the first DWORD
*(DWORD*)pDes = nSrcLen;
*(pDes+sizeof(DWORD)) = nBitsPerSample;
int nSample = *pSrc;
int nMaxSamples = 1 << nBitsPerSample;
// dictionary hash table
CBinaryTree<CBuffer, CBuffer*, int, int> dictionary;
dictionary.NoRepeat = true;
// keep first 256 IDs for ascii Samples
dictionary.Serial = 256;
// tree node to keep last success search to start with
CBinaryTreeNode<CBuffer, int>* pNode = dictionary.Root;
// left dictionary Samples points to the source buffer
CBuffer node(pSrc, 2);
// scan the input buffer
while(nSrcLen-- > 0)
{
if(dictionary.Serial == nMaxSamples)
{
dictionary.RemoveAll();
dictionary.Serial = 256;
}
pNode = dictionary.Insert(&node, -1, pNode);
if(pNode->Count > 1)
// (repeated Sample), save success Sample to be used next fail
nSample = pNode->ID, node.m_nLength++;
else
{ // write last success Sample
*(DWORD*)(pDes+(nDesLen>>3)) |= nSample << (nDesLen&7);
nDesLen += nBitsPerSample;
// initialize node to next Sample
node.m_pBuffer += node.m_nLength-1;
node.m_nLength = 2;
// copy first byte of the node as a new Sample
nSample = *node.m_pBuffer;
// initialize search root
pNode = dictionary.Root;
}
}
nDesLen = (nDesLen+7)/8;
pDes = (BYTE*)realloc(pDes, nDesLen);
return true;
}
void ClearDictionary(vector<CBuffer *>& dictionary)
{
for(vector<CBuffer*>::iterator i = dictionary.begin(); i != dictionary.end(); i++)
delete (*i);
dictionary.clear();
}
bool DecompressLZW(BYTE *pSrc, int nSrcLen, BYTE *&pDes, int &nDesLen)
{ // first two DWORDS (final buffer length, Samples sizes bitmap buffer start)
// copy destination final length
nDesLen = *(DWORD*)pSrc;
// copy bits pre Sample
int nBitsPerSample = *(pSrc+sizeof(DWORD));
// allocate buffer for decompressed buffer
pDes = (BYTE*)malloc(nDesLen+1);
// copy first char from source to destination
*pDes = *(pSrc+sizeof(DWORD)+1);
int nMaxSamples = 1 << nBitsPerSample;
int nSample, nSrcIndex = ((sizeof(DWORD)+1)<<3) + nBitsPerSample;
// dictionary array
vector<CBuffer *> dictionary;
// let dictionary Samples points to the destination buffer
CBuffer node(pDes, 2), *pNodeSample;
int nDesIndex = 1, nDesIndexSave, nSampleLen;
while(nDesIndex < nDesLen)
{
nSample = (*(DWORD*)(pSrc+(nSrcIndex>>3)))>>(nSrcIndex&7) & (nMaxSamples-1);
nSrcIndex += nBitsPerSample;
if(dictionary.size() == nMaxSamples-256)
ClearDictionary(dictionary);
if(nSample >= 256)
if(nSample-256 < (int)dictionary.size())
{ // normal case, valid dictionary Sample
nDesIndexSave = nDesIndex;
pNodeSample = dictionary.at(nSample-256);
nSampleLen = pNodeSample->m_nLength+1;
// copy dictionary node buffer to decompressed buffer
memcpy(pDes+nDesIndex, pNodeSample->m_pBuffer, pNodeSample->m_nLength);
nDesIndex += pNodeSample->m_nLength;
}
else
{ // out of range Sample
nSampleLen = nDesIndex-nDesIndexSave+2;
// copy previous decompressed Sample as a new one + ...
memcpy(pDes+nDesIndex, pDes+nDesIndexSave, nDesIndex-nDesIndexSave);
nDesIndex += nDesIndex-nDesIndexSave;
// add first char of the previous decompressed Sample
*(pDes+nDesIndex++) = *(pDes+nDesIndexSave);
nDesIndexSave += nSampleLen-2;
}
else
nDesIndexSave = nDesIndex, *(pDes+nDesIndex++) = (BYTE)nSample, nSampleLen = 2;
// add current segment to the dictionary
dictionary.push_back(new CBuffer(node));
// increment next node pointer to the last char of the added Sample
node.m_pBuffer += node.m_nLength-1;
node.m_nLength = nSampleLen;
}
// free dictionary Samples
ClearDictionary(dictionary);
return true;
}