306 lines
7.4 KiB
C++
306 lines
7.4 KiB
C++
//See $LK,"::/Doc/Credits.TXT"$.
|
|
//See $LK,"CArcCompress",A="MN:CArcCompress"$, $LK,"CArcEntry",A="MN:CArcEntry"$, and $LK,"CArcCtrl",A="MN:CArcCtrl"$
|
|
|
|
asm {
|
|
USE64
|
|
/****
|
|
U0 ArcGetEntry(CArcCtrl *c)
|
|
{
|
|
I64 i;
|
|
CArcEntry *temp,*temp1;
|
|
|
|
if (c->entry_used) {
|
|
i=c->free_index;
|
|
|
|
c->entry_used=FALSE;
|
|
c->cur_entry=c->next_entry;
|
|
c->cur_bits_in_use=c->next_bits_in_use;
|
|
if (c->next_bits_in_use<ARC_MAX_BITS) {
|
|
c->next_entry = &c->compress[i++];
|
|
if (i==c->free_limit) {
|
|
c->next_bits_in_use++;
|
|
c->free_limit=1<<c->next_bits_in_use;
|
|
}
|
|
} else {
|
|
do if (++i==c->free_limit)
|
|
i=c->min_table_entry;
|
|
while (c->hash[i]);
|
|
temp=&c->compress[i];
|
|
c->next_entry=temp;
|
|
temp1=&c->hash[temp->basecode];
|
|
while (temp1) {
|
|
if (temp1->next==temp) {
|
|
temp1->next=temp->next;
|
|
break;
|
|
} else
|
|
temp1=temp1->next;
|
|
}
|
|
}
|
|
c->free_index=i;
|
|
}
|
|
}
|
|
****/
|
|
_ARC_GET_ENTRY::
|
|
PUSH RBP
|
|
MOV RBP,RSP
|
|
PUSH RSI
|
|
PUSH RDI
|
|
MOV RSI,U64 SF_ARG1[RBP]
|
|
BTR U64 CArcCtrl.entry_used[RSI],0
|
|
JNC I32 @@30
|
|
MOV RDX,U64 CArcCtrl.free_index[RSI]
|
|
MOV RAX,U64 CArcCtrl.next_entry[RSI]
|
|
MOV U64 CArcCtrl.cur_entry[RSI],RAX
|
|
MOV RCX,U64 CArcCtrl.next_bits_in_use[RSI]
|
|
MOV U64 CArcCtrl.cur_bits_in_use[RSI],RCX
|
|
CMP RCX,ARC_MAX_BITS
|
|
JAE @@05
|
|
MOV RAX,RDX
|
|
SHL RAX,4
|
|
LEA RAX,U64 CArcCtrl.compress[RSI+RAX]
|
|
MOV U64 CArcCtrl.next_entry[RSI],RAX
|
|
INC RDX
|
|
CMP U64 CArcCtrl.free_limit[RSI],RDX
|
|
JNE @@25
|
|
INC RCX
|
|
MOV U64 CArcCtrl.next_bits_in_use[RSI],RCX
|
|
MOV RAX,1
|
|
SHL RAX,CL
|
|
MOV U64 CArcCtrl.free_limit[RSI],RAX
|
|
JMP @@25
|
|
@@05: INC RDX
|
|
CMP U64 CArcCtrl.free_limit[RSI],RDX
|
|
JNE @@10
|
|
MOV RDX,U64 CArcCtrl.min_table_entry[RSI]
|
|
@@10: MOV RAX,U64 CArcCtrl.hash[RSI+RDX*8]
|
|
TEST RAX,RAX
|
|
JNZ @@05
|
|
MOV RDI,RDX
|
|
SHL RDI,4
|
|
LEA RDI,U64 CArcCtrl.compress[RSI+RDI]
|
|
MOV U32 CArcCtrl.next_entry[RSI],EDI
|
|
MOVZX RBX,U16 CArcEntry.basecode[RDI]
|
|
LEA RCX,U64 CArcCtrl.hash[RSI+RBX*8]
|
|
@@15: TEST RCX,RCX
|
|
JZ @@25
|
|
MOV RAX,U64 CArcEntry.next[RCX]
|
|
CMP RDI,RAX
|
|
JNE @@20
|
|
MOV RAX,U64 CArcEntry.next[RDI]
|
|
MOV U64 CArcEntry.next[RCX],RAX
|
|
JMP @@25
|
|
@@20: MOV RCX,RAX
|
|
JMP @@15
|
|
@@25: MOV U64 CArcCtrl.free_index[RSI],RDX
|
|
@@30: POP RDI
|
|
POP RSI
|
|
POP RBP
|
|
RET1 8
|
|
}
|
|
|
|
_extern _ARC_GET_ENTRY U0 ArcGetEntry(CArcCtrl *c);
|
|
|
|
I64 ArcDetermineCompressionType(U8 *src,I64 size)
|
|
{
|
|
while (size--)
|
|
if (*src++&0x80)
|
|
return CT_8_BIT;
|
|
return CT_7_BIT;
|
|
}
|
|
|
|
U0 ArcCompressBuf(CArcCtrl *c)
|
|
{//Use $LK,"CompressBuf",A="MN:CompressBuf"$() unless doing more than one buf.
|
|
CArcEntry *temp,*temp1;
|
|
I64 ch,basecode;
|
|
U8 *src_ptr,*src_limit;
|
|
|
|
src_ptr=c->src_buf+c->src_pos;
|
|
src_limit=c->src_buf+c->src_size;
|
|
|
|
if (c->saved_basecode==MAX_U32)
|
|
basecode=*src_ptr++;
|
|
else
|
|
basecode=c->saved_basecode;
|
|
|
|
while (src_ptr<src_limit && c->dst_pos+c->cur_bits_in_use<=c->dst_size) {
|
|
ArcGetEntry(c);
|
|
ac_start:
|
|
if (src_ptr>=src_limit) goto ac_done;
|
|
ch=*src_ptr++;
|
|
if (temp=c->hash[basecode])
|
|
do {
|
|
if (temp->ch==ch) {
|
|
basecode=temp-&c->compress[0];
|
|
goto ac_start;
|
|
}
|
|
} while (temp=temp->next);
|
|
|
|
BFieldOrU32(c->dst_buf,c->dst_pos,basecode);
|
|
c->dst_pos+=c->cur_bits_in_use;
|
|
|
|
c->entry_used=TRUE;
|
|
temp=c->cur_entry;
|
|
temp->basecode=basecode;
|
|
temp->ch=ch;
|
|
temp1=&c->hash[basecode];
|
|
temp->next=temp1->next;
|
|
temp1->next=temp;
|
|
|
|
basecode=ch;
|
|
}
|
|
ac_done:
|
|
c->saved_basecode=basecode;
|
|
c->src_pos=src_ptr-c->src_buf;
|
|
}
|
|
|
|
Bool ArcFinishCompression(CArcCtrl *c)
|
|
{//Do closing touch on archivew ctrl struct.
|
|
if (c->dst_pos+c->cur_bits_in_use<=c->dst_size) {
|
|
BFieldOrU32(c->dst_buf,c->dst_pos,c->saved_basecode);
|
|
c->dst_pos+=c->next_bits_in_use;
|
|
return TRUE;
|
|
} else
|
|
return FALSE;
|
|
}
|
|
|
|
U0 ArcExpandBuf(CArcCtrl *c)
|
|
{//Use $LK,"ExpandBuf",A="MN:ExpandBuf"$() unless you know what you're doing.
|
|
U8 *dst_ptr,*dst_limit;
|
|
I64 basecode,lastcode,code;
|
|
CArcEntry *temp,*temp1;
|
|
|
|
dst_ptr=c->dst_buf+c->dst_pos;
|
|
dst_limit=c->dst_buf+c->dst_size;
|
|
|
|
while (dst_ptr<dst_limit && c->stk_ptr!=c->stk_base)
|
|
*dst_ptr++ = * -- c->stk_ptr;
|
|
|
|
if (c->stk_ptr==c->stk_base && dst_ptr<dst_limit) {
|
|
if (c->saved_basecode==MAX_U32) {
|
|
lastcode=BFieldExtU32(c->src_buf,c->src_pos,
|
|
c->next_bits_in_use);
|
|
c->src_pos+=c->next_bits_in_use;
|
|
*dst_ptr++=lastcode;
|
|
ArcGetEntry(c);
|
|
c->last_ch=lastcode;
|
|
} else
|
|
lastcode=c->saved_basecode;
|
|
while (dst_ptr<dst_limit && c->src_pos+c->next_bits_in_use<=c->src_size) {
|
|
basecode=BFieldExtU32(c->src_buf,c->src_pos,
|
|
c->next_bits_in_use);
|
|
c->src_pos+=c->next_bits_in_use;
|
|
if (c->cur_entry==&c->compress[basecode]) {
|
|
*c->stk_ptr++=c->last_ch;
|
|
code=lastcode;
|
|
} else
|
|
code=basecode;
|
|
while (code>=c->min_table_entry) {
|
|
*c->stk_ptr++=c->compress[code].ch;
|
|
code=c->compress[code].basecode;
|
|
}
|
|
*c->stk_ptr++=code;
|
|
c->last_ch=code;
|
|
|
|
c->entry_used=TRUE;
|
|
temp=c->cur_entry;
|
|
temp->basecode=lastcode;
|
|
temp->ch=c->last_ch;
|
|
temp1=&c->hash[lastcode];
|
|
temp->next=temp1->next;
|
|
temp1->next=temp;
|
|
|
|
ArcGetEntry(c);
|
|
while (dst_ptr<dst_limit && c->stk_ptr!=c->stk_base)
|
|
*dst_ptr++ = * -- c->stk_ptr;
|
|
lastcode=basecode;
|
|
}
|
|
c->saved_basecode=lastcode;
|
|
}
|
|
c->dst_pos=dst_ptr-c->dst_buf;
|
|
}
|
|
|
|
CArcCtrl *ArcCtrlNew(Bool expand,I64 compression_type=CT_8_BIT)
|
|
{//MAlloc archive ctrl struct.
|
|
CArcCtrl *c;
|
|
c=CAlloc(sizeof(CArcCtrl));
|
|
if (expand) {
|
|
c->stk_base=MAlloc(ARC_MAX_ENTRY+1);
|
|
c->stk_ptr=c->stk_base;
|
|
}
|
|
if (compression_type==CT_7_BIT)
|
|
c->min_bits=7;
|
|
else
|
|
c->min_bits=8;
|
|
c->min_table_entry=1<<c->min_bits;
|
|
c->free_index=c->min_table_entry;
|
|
c->next_bits_in_use=c->min_bits+1;
|
|
c->free_limit=1<<c->next_bits_in_use;
|
|
c->saved_basecode=MAX_U32;
|
|
c->entry_used=TRUE;
|
|
ArcGetEntry(c);
|
|
c->entry_used=TRUE;
|
|
return c;
|
|
}
|
|
|
|
U0 ArcCtrlDel(CArcCtrl *c)
|
|
{//Free archive ctrl struct.
|
|
Free(c->stk_base);
|
|
Free(c);
|
|
}
|
|
|
|
U8 *ExpandBuf(CArcCompress *r,CTask *mem_task=NULL)
|
|
{//See $LK,"::/Demo/Dsk/SerializeTree.CPP"$.
|
|
CArcCtrl *c;
|
|
U8 *result=MAlloc(r->expanded_size+1,mem_task);
|
|
result[r->expanded_size]=0; //terminate
|
|
switch (r->compression_type) {
|
|
case CT_NONE:
|
|
MemCpy(result,&r->body,r->expanded_size);
|
|
break;
|
|
case CT_7_BIT:
|
|
case CT_8_BIT:
|
|
c=ArcCtrlNew(TRUE,r->compression_type);
|
|
c->src_size=r->compressed_size<<3;
|
|
c->src_pos=sizeof(CArcCompress)<<3;
|
|
c->src_buf=r;
|
|
c->dst_size=r->expanded_size;
|
|
c->dst_buf=result;
|
|
c->dst_pos=0;
|
|
ArcExpandBuf(c);
|
|
ArcCtrlDel(c);
|
|
break;
|
|
default:
|
|
throw('Compress');
|
|
}
|
|
return result;
|
|
}
|
|
|
|
CArcCompress *CompressBuf(U8 *src,I64 size,CTask *mem_task=NULL)
|
|
{//See $LK,"::/Demo/Dsk/SerializeTree.CPP"$.
|
|
CArcCompress *result;
|
|
I64 size_out,compression_type=ArcDetermineCompressionType(src,size);
|
|
CArcCtrl *c=ArcCtrlNew(FALSE,compression_type);
|
|
c->src_size=size;
|
|
c->src_buf=src;
|
|
c->dst_size=(size+sizeof(CArcCompress))<<3;
|
|
c->dst_buf=CAlloc(c->dst_size>>3);
|
|
c->dst_pos=sizeof(CArcCompress)<<3;
|
|
ArcCompressBuf(c);
|
|
if (ArcFinishCompression(c) && c->src_pos==c->src_size) {
|
|
size_out=(c->dst_pos+7)>>3;
|
|
result=MAlloc(size_out,mem_task);
|
|
MemCpy(result,c->dst_buf,size_out);
|
|
result->compression_type=compression_type;
|
|
result->compressed_size=size_out;
|
|
} else {
|
|
result=MAlloc(size+sizeof(CArcCompress),mem_task);
|
|
MemCpy(&result->body,src,size);
|
|
result->compression_type=CT_NONE;
|
|
result->compressed_size=size+sizeof(CArcCompress);
|
|
}
|
|
result->expanded_size=size;
|
|
Free(c->dst_buf);
|
|
ArcCtrlDel(c);
|
|
return result;
|
|
}
|