// 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 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* 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& dictionary) { for(vector::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 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; }