//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_usenext_entry = &c->compress[i++]; if (i==c->free_limit) { c->next_bits_in_use++; c->free_limit=1<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_ptrdst_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_ptrstk_ptr!=c->stk_base) *dst_ptr++ = * -- c->stk_ptr; if (c->stk_ptr==c->stk_base && dst_ptrsaved_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_ptrsrc_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_ptrstk_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<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<min_bits; c->free_idx=c->min_table_entry; c->next_bits_in_use=c->min_bits+1; c->free_limit=1<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; }