309 lines
7.4 KiB
HolyC
309 lines
7.4 KiB
HolyC
|
//See $LK,"::/Doc/Credits.DD"$.
|
||
|
//See $LK,"CArcCompress",A="MN:CArcCompress"$, $LK,"CArcEntry",A="MN:CArcEntry"$, and $LK,"CArcCtrl",A="MN:CArcCtrl"$
|
||
|
|
||
|
asm {
|
||
|
/****
|
||
|
U0 ArcEntryGet(CArcCtrl *c)
|
||
|
{
|
||
|
I64 i;
|
||
|
CArcEntry *tmp,*tmp1;
|
||
|
|
||
|
if (c->entry_used) {
|
||
|
i=c->free_idx;
|
||
|
|
||
|
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_BITS_MAX) {
|
||
|
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]);
|
||
|
tmp=&c->compress[i];
|
||
|
c->next_entry=tmp;
|
||
|
tmp1=&c->hash[tmp->basecode];
|
||
|
while (tmp1) {
|
||
|
if (tmp1->next==tmp) {
|
||
|
tmp1->next=tmp->next;
|
||
|
break;
|
||
|
} else
|
||
|
tmp1=tmp1->next;
|
||
|
}
|
||
|
}
|
||
|
c->free_idx=i;
|
||
|
}
|
||
|
}
|
||
|
****/
|
||
|
_ARC_ENTRY_GET::
|
||
|
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_idx[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_BITS_MAX
|
||
|
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_idx[RSI],RDX
|
||
|
@@30: POP RDI
|
||
|
POP RSI
|
||
|
POP RBP
|
||
|
RET1 8
|
||
|
}
|
||
|
|
||
|
_extern _ARC_ENTRY_GET U0 ArcEntryGet(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 *tmp,*tmp1;
|
||
|
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==U32_MAX)
|
||
|
basecode=*src_ptr++;
|
||
|
else
|
||
|
basecode=c->saved_basecode;
|
||
|
|
||
|
while (src_ptr<src_limit && c->dst_pos+c->cur_bits_in_use<=c->dst_size) {
|
||
|
ArcEntryGet(c);
|
||
|
ac_start:
|
||
|
if (src_ptr>=src_limit) goto ac_done;
|
||
|
ch=*src_ptr++;
|
||
|
if (tmp=c->hash[basecode])
|
||
|
do {
|
||
|
if (tmp->ch==ch) {
|
||
|
basecode=tmp-&c->compress[0];
|
||
|
goto ac_start;
|
||
|
}
|
||
|
} while (tmp=tmp->next);
|
||
|
|
||
|
BFieldOrU32(c->dst_buf,c->dst_pos,basecode);
|
||
|
c->dst_pos+=c->cur_bits_in_use;
|
||
|
|
||
|
c->entry_used=TRUE;
|
||
|
tmp=c->cur_entry;
|
||
|
tmp->basecode=basecode;
|
||
|
tmp->ch=ch;
|
||
|
tmp1=&c->hash[basecode];
|
||
|
tmp->next=tmp1->next;
|
||
|
tmp1->next=tmp;
|
||
|
|
||
|
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 *tmp,*tmp1;
|
||
|
|
||
|
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==U32_MAX) {
|
||
|
lastcode=BFieldExtU32(c->src_buf,c->src_pos,
|
||
|
c->next_bits_in_use);
|
||
|
c->src_pos+=c->next_bits_in_use;
|
||
|
*dst_ptr++=lastcode;
|
||
|
ArcEntryGet(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;
|
||
|
tmp=c->cur_entry;
|
||
|
tmp->basecode=lastcode;
|
||
|
tmp->ch=c->last_ch;
|
||
|
tmp1=&c->hash[lastcode];
|
||
|
tmp->next=tmp1->next;
|
||
|
tmp1->next=tmp;
|
||
|
|
||
|
ArcEntryGet(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(1<<ARC_BITS_MAX);
|
||
|
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_idx=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=U32_MAX;
|
||
|
c->entry_used=TRUE;
|
||
|
ArcEntryGet(c);
|
||
|
c->entry_used=TRUE;
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
U0 ArcCtrlDel(CArcCtrl *c)
|
||
|
{//Free archive ctrl struct.
|
||
|
Free(c->stk_base);
|
||
|
Free(c);
|
||
|
}
|
||
|
|
||
|
U8 *ExpandBuf(CArcCompress *arc,CTask *mem_task=NULL)
|
||
|
{//See $LK,"::/Demo/Dsk/SerializeTree.HC"$.
|
||
|
CArcCtrl *c;
|
||
|
U8 *res;
|
||
|
|
||
|
if (!(CT_NONE<=arc->compression_type<=CT_8_BIT) ||
|
||
|
arc->expanded_size>mem_mapped_space)
|
||
|
throw('Compress');
|
||
|
|
||
|
res=MAlloc(arc->expanded_size+1,mem_task);
|
||
|
res[arc->expanded_size]=0; //terminate
|
||
|
switch [arc->compression_type] {
|
||
|
case CT_NONE:
|
||
|
MemCpy(res,&arc->body,arc->expanded_size);
|
||
|
break;
|
||
|
case CT_7_BIT:
|
||
|
case CT_8_BIT:
|
||
|
c=ArcCtrlNew(TRUE,arc->compression_type);
|
||
|
c->src_size=arc->compressed_size<<3;
|
||
|
c->src_pos=sizeof(CArcCompress)<<3;
|
||
|
c->src_buf=arc;
|
||
|
c->dst_size=arc->expanded_size;
|
||
|
c->dst_buf=res;
|
||
|
c->dst_pos=0;
|
||
|
ArcExpandBuf(c);
|
||
|
ArcCtrlDel(c);
|
||
|
break;
|
||
|
}
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
CArcCompress *CompressBuf(U8 *src,I64 size,CTask *mem_task=NULL)
|
||
|
{//See $LK,"::/Demo/Dsk/SerializeTree.HC"$.
|
||
|
CArcCompress *arc;
|
||
|
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;
|
||
|
arc=MAlloc(size_out,mem_task);
|
||
|
MemCpy(arc,c->dst_buf,size_out);
|
||
|
arc->compression_type=compression_type;
|
||
|
arc->compressed_size=size_out;
|
||
|
} else {
|
||
|
arc=MAlloc(size+sizeof(CArcCompress),mem_task);
|
||
|
MemCpy(&arc->body,src,size);
|
||
|
arc->compression_type=CT_NONE;
|
||
|
arc->compressed_size=size+sizeof(CArcCompress);
|
||
|
}
|
||
|
arc->expanded_size=size;
|
||
|
Free(c->dst_buf);
|
||
|
ArcCtrlDel(c);
|
||
|
return arc;
|
||
|
}
|