www.pudn.com > Compression.rar > LZW.cpp
// Implementation of Lempel-Ziv & Welch compression in its pure form. // Appear to be one of most popular looseless compression algorithms. // // Implemented by Arkadi Kagan // #include "LZW.h" #include#include "../Fatal/Fatal.h" CLZW::CLZW() { memset(&nill, 0, sizeof(nill)); nill.nill_key.next = nill.nill_key.prev = &nill.nill_key; nill.nill_key.pnode = &nill; LastKey = 0; border = 2; bits_len = 1; InitTable(); } CLZW::~CLZW() { CleanAll(); } void CLZW::CleanAll() { while (tree.root != tree.NIL) tree.deleteNode(tree.root); while (nill.nill_key.next != &nill.nill_key) DeleteKey(nill.nill_key.next); LastKey = 0; border = 2; bits_len = 1; InitTable(); } void CLZW::InitTable() { int i; for (i = 0; i < 256; i++) AddKey(&nill, GenerateKey(), (BYTE)i); } void CLZW::bitscpy(BYTE *target, long &toffset, BYTE *source, long &soffset, long bitslen) { long i; for (i = 0; i < bitslen; i++) target[(toffset+i)/8] |= ((source[(soffset+i)/8]>>((soffset+i)%8))&1) << ((toffset+i)%8); toffset += bitslen; soffset += bitslen; } CLZW::tagNode *CLZW::FindKeyWord(DWORD key_word) { tagNode tmpNode; tmpNode.key_word = key_word; RedBlackNode::Node *tnode = tree.findNode(&tmpNode); if (tnode == NULL) return NULL; return tnode->data; } CLZW::tagNode *CLZW::FindKey(CLZW::tagNode *node, BYTE key) { tagKey *cur; if (node == NULL) node = &nill; for (cur = node->nill_key.next; cur != &node->nill_key; cur = cur->next) if (cur->key == key) return cur->node; return NULL; } CLZW::tagNode *CLZW::AddKey(CLZW::tagNode *node, DWORD key_word, BYTE key) { if (node == NULL) node = &nill; tagKey *cur_key = new tagKey; tagNode *cur_node = new tagNode; memset(cur_key, 0, sizeof(tagKey)); memset(cur_node, 0, sizeof(tagNode)); cur_key->key = key; cur_key->node = cur_node; cur_key->pnode = node; cur_key->next = node->nill_key.next; cur_key->prev = &node->nill_key; cur_key->next->prev = cur_key; cur_key->prev->next = cur_key; cur_node->nill_key.next = cur_node->nill_key.prev = &cur_node->nill_key; cur_node->nill_key.pnode = cur_node; cur_node->key_word = key_word; cur_node->parent = cur_key; cur_node->level = node->level + 1; tree.insertNode(cur_node); return cur_node; } DWORD CLZW::GenerateKey() { if (LastKey >= border-1) { border = border << 1; bits_len++; } if (bits_len >= 8*sizeof(DWORD)) FatalError("Dictionary is full. Source is too big or demaged"); return ++LastKey; } void CLZW::DeleteNode(CLZW::tagNode *node) { while (node->nill_key.next != &node->nill_key) DeleteKey(node->nill_key.next); } void CLZW::DeleteKey(CLZW::tagKey *key) { DeleteNode(key->node); key->next->prev = key->prev; key->prev->next = key->next; delete key->node; delete key; } // slength must be length of source sequence in bytes long CLZW::EncodeOnce(BYTE *target, long &toffset, BYTE *source, long slength, CLZW::tagNode **last_node) { long i, offset; tagNode *node = &nill, *tnode; for (i = 0; i < slength; i++) { tnode = FindKey(node, source[i]); if (tnode == NULL) { offset = 0; bitscpy(target, toffset, (BYTE*)&node->key_word, offset, bits_len); if (*last_node != NULL) if (FindKey(*last_node, source[0]) == NULL) AddKey(*last_node, GenerateKey(), source[0]); *last_node = node; return i; } node = tnode; } if (node != &nill) { offset = 0; bitscpy(target, toffset, (BYTE*)&node->key_word, offset, bits_len); } return slength; } long CLZW::DecodeOnce(BYTE *target, BYTE *source, long &soffset, CLZW::tagNode **last_node) { tagNode *node, *fnode = NULL; long len = 0, offset = 0; DWORD key_word = 0; bitscpy((BYTE*)&key_word, offset, source, soffset, bits_len); node = FindKeyWord(key_word); if (node != NULL) { fnode = node; len = node->level; while (node->parent != NULL) { target[node->level-1] = node->parent->key; node = node->parent->pnode; } if (*last_node != NULL) if (FindKey(*last_node, target[0]) == NULL) AddKey(*last_node, GenerateKey(), target[0]); *last_node = fnode; } else FatalError("Source is damaged"); return len; } long CLZW::GetMaxEncoded(long len) { return len+sizeof(DWORD); } long CLZW::GetMaxDecoded(BYTE *source) { return ((DWORD*)source)[0]; } void CLZW::Encode(BYTE *target, long &tlen, BYTE *source, long slen) { long toffset = 0; long coded = 0; long tmp; tagNode *last_node = NULL; DWORD *size = (DWORD*)target; memset(target, 0, tlen); *size = slen; target += sizeof(DWORD); tlen = sizeof(DWORD); while ((tmp = EncodeOnce(target, toffset, source + coded, slen - coded, &last_node)) != 0) { coded += tmp; if (toffset/8 >= slen) { tlen = 0; return; } OnStep(); } tlen += toffset/8 + 1; CleanAll(); } long CLZW::Decode(BYTE *target, long &tlen, BYTE *source, long) { long coded = 0; long offset = 0; tagNode *last_node = NULL; tlen = ((DWORD*)source)[0]; source += sizeof(DWORD); memset(target, 0, tlen); while (coded < tlen) { coded += DecodeOnce(target + coded, source, offset, &last_node); OnStep(); } CleanAll(); return offset/8+1 + sizeof(DWORD); }