/* * $Id: encode.c,v 1.7 2004/05/31 16:08:41 andrew_belov Exp $ * --------------------------------------------------------------------------- * The data compression procedures are located in this module. * */ #include "arj.h" #ifdef TILED #include /* Weird, eh? */ #endif DEBUGHDR(__FILE__) /* Debug information block */ static int st_n; unsigned short *c_freq; unsigned short FAR *c_code; unsigned short FAR *heap; unsigned short len_cnt[17]; unsigned short p_freq[2*NP-1]; unsigned short pt_code[NPT]; int depth; unsigned char FAR *buf; unsigned char output_mask; unsigned short output_pos; int dicbit; unsigned short t_freq[2*NT-1]; int heapsize; unsigned short FAR *sortptr; unsigned char *len; unsigned short *freq; unsigned short fpcount; short FAR *fpbuf; short FAR *dtree; unsigned short treesize; unsigned char *tree=NULL; unsigned short numchars; unsigned short dicsiz_cur; unsigned short dicpos; unsigned short tc_passes; short FAR *ftree; unsigned int dic_alloc; unsigned long encoded_bytes; /* Inline functions */ #define encode_c(c) \ putbits(c_len[c], c_code[c]) #define encode_p(p) \ { \ unsigned int qc, q; \ qc=0; \ q=p; \ while(q) \ { \ q>>=1; \ qc++; \ } \ putbits(pt_len[qc], pt_code[qc]); \ if(qc>1) \ putbits(qc-1, p); \ } /* Bitwise output routine */ void putbits(int n_c, unsigned short n_x) { #ifdef ASM8086 asm{ mov cl, byte ptr n_c mov dx, n_x mov ch, cl sub cl, 16 neg cl shl dx, cl mov cl, byte ptr bitcount mov ax, dx shr ax, cl or bitbuf, ax add cl, ch cmp cl, 8 jge chunk1 mov byte ptr bitcount, cl jmp procend } chunk1: asm{ push si mov si, out_bytes cmp si, out_avail jge flush } acc_loop: asm{ mov bx, out_buffer mov ah, byte ptr bitbuf+1 mov [bx+si], ah inc si sub cl, 8 cmp cl, 8 jge avail_chk #if TARGET==OS2 shl bitbuf, 8 #else mov ah, byte ptr bitbuf mov al, 0 mov bitbuf, ax #endif jmp endpoint } avail_chk: asm{ cmp si, out_avail jge r_flush } cpoint: asm{ mov al, byte ptr bitbuf mov [bx+si], al inc si sub cl, 8 sub ch, cl xchg cl, ch shl dx, cl mov bitbuf, dx mov cl, ch jmp endpoint } flush: asm{ push dx push cx } flush_compdata(); asm{ pop cx pop dx mov si, out_bytes jmp short acc_loop } r_flush: asm{ mov out_bytes, si push dx push cx push bx } flush_compdata(); asm{ pop bx pop cx pop dx mov si, out_bytes jmp short cpoint } endpoint: asm{ mov out_bytes, si pop si mov byte ptr bitcount, cl } procend:; #else int p_n; int bt; p_n=n_c; n_c=16-n_c; n_x<<=n_c; n_c=bitcount; bitbuf|=(n_x>>n_c); n_c+=p_n; if(n_c<8) { bitcount=n_c; return; } bt=out_bytes; if(bt>=out_avail) { flush_compdata(); bt=out_bytes; } out_buffer[bt++]=bitbuf>>8; n_c-=8; if(n_c<8) { bitbuf<<=8; out_bytes=bt; bitcount=n_c; return; } if(bt>=out_avail) { out_bytes=bt; flush_compdata(); bt=out_bytes; } out_buffer[bt++]=bitbuf; n_c-=8; p_n-=n_c; bitbuf=n_x<=ARJ int fetch_uncomp(char *dest, int n) { unsigned int fetch_size; if(file_packing) return(fread_crc(dest, n, encstream)); else { if(encmem_remain==0) return(0); fetch_size=min((unsigned int)n, encmem_remain); far_memmove((char FAR *)dest, encblock_ptr, fetch_size); crc32_for_block(dest, fetch_size); encmem_remain-=fetch_size; encblock_ptr+=fetch_size; return(fetch_size); } } #endif /* Fills the length table depending on the leaf depth (call with i==root) */ static void count_len(int i) { static int depth=0; if(i0; i--) cum+=len_cnt[i]<<(16-i); while(cum!=0) { if(debug_enabled&&strchr(debug_opt, 'f')!=NULL) msg_cprintf(0, M_HDF_FIX); len_cnt[16]--; for(i=15; i>0; i--) { if(len_cnt[i]!=0) { len_cnt[i]--; len_cnt[i+1]+=2; break; } } cum--; } for(i=16; i>0; i--) { k=len_cnt[i]; while(--k>=0) len[*sortptr++]=i; } } /* Sends i-th entry down the heap */ static void NEAR downheap(int i) { int j, k; k=heap[i]; while((j=2*i)<=heapsize) { if(jfreq[heap[j+1]]) j++; if(freq[k]<=freq[heap[j]]) break; heap[i]=heap[j]; i=j; } heap[i]=k; } /* Encodes a length table element */ static void NEAR make_code(int n, unsigned char *len, unsigned short FAR *code) { int i; unsigned short start[18]; start[1]=0; for(i=1; i<=16; i++) start[i+1]=(start[i]+len_cnt[i])<<1; for(i=0; i>1; i>=1; i--) downheap(i); /* Make priority queue */ sortptr=codeparm; /* While queue has at least two entries */ do { i=heap[1]; /* Take out least-freq entry */ if(i1); sortptr=codeparm; make_len(k); make_code(nparm, lenparm, codeparm); return(k); /* Return root */ } /* Counts the cumulative frequency */ void count_t_freq() { int i, k, n, count; for(i=0; i0&&c_len[n-1]==0) n--; i=0; while(i0&&pt_len[n-1]==0) n--; putbits(nbit, n); i=0; while(i0&&c_len[n-1]==0) n--; putbits(CBIT, n); i=0; while(i=NC) { count_t_freq(); root=make_tree(NT, t_freq, pt_len, (unsigned short FAR *)pt_code); if(root>=NT) write_pt_len(NT, TBIT, 3); else { putbits(TBIT, 0); putbits(TBIT, root); } write_c_len(); } else { putbits(TBIT, 0); putbits(TBIT, 0); putbits(CBIT, 0); putbits(CBIT, root); } root=make_tree(NP, p_freq, pt_len, (unsigned short FAR *)pt_code); if(root>=NP) write_pt_len(NP, PBIT, -1); else { putbits(PBIT, 0); putbits(PBIT, root); } pos=0; for(i=0; i=0) { tptr=tree+n_c; tdptr=tree+r_bx; r_ax=word_ptr(tptr); r_dx=numchars; if(--r_dx>=0) goto ut_loop; ut_fetch: r_ax=word_ptr(tptr+r_bp-1); select_pos: tdptr=tree+r_bp; do { if(--r_dx<0) goto upd_finish; r_bx=dptr[r_bx]; if(r_bx<0) goto upd_finish; } while(r_ax!=word_ptr(tdptr+r_bx-1)); tdptr+=r_bx-r_bp; ut_loop: #ifdef ALIGN_POINTERS if (_diff(tptr,tdptr)) #else if(word_ptr(tptr)!=word_ptr(tdptr)) #endif goto select_pos; prev_tptr=tptr; prev_tdptr=tdptr; tptr+=2; tdptr+=2; for(c=128; c>0; c--) { #ifdef ALIGN_POINTERS if (_diff(tptr,tdptr)) #else if(word_ptr(tptr)!=word_ptr(tdptr)) #endif break; tptr+=2; tdptr+=2; } diff=*(tdptr)-*(tptr); remainder=tdptr-prev_tdptr; if(diff==0) remainder+=1; tptr=prev_tptr; tdptr=prev_tdptr; if(remainder<=r_bp) goto ut_fetch; if(tptr-tdptr<=dicsiz_cur) { dicpos=tptr-tdptr-1; r_bp=remainder; if(r_bp<256) goto ut_fetch; } upd_finish: if(r_bp>256) r_bp=256; } return(tc_passes=r_bp); #endif } /* Optimized output routine */ static void output(int c, unsigned short p) { unsigned char FAR *bptr; unsigned char cy; unsigned short r_dx; unsigned short r_bx; bptr=buf; r_dx=cpos; cy=output_mask&1; output_mask=(cy?0x80:0)|((output_mask&0xFF)>>1); if(cy) { if(r_dx>=bufsiz) { send_block(); if(unpackable) { cpos=bptr-buf; return; } r_dx=0; } output_pos=r_dx; buf[r_dx]=0; r_dx++; } bptr+=r_dx; *bptr++=c; c_freq[c]++; if(c>=256) { buf[output_pos]|=output_mask; *bptr++=p&0xFF; *bptr++=(p>>8); for(r_bx=0; p!=0; p>>=1) r_bx++; p_freq[r_bx]++; } cpos=bptr-buf; } /* Unstubbed optimized output routine */ static void output_opt(unsigned char c) { unsigned char FAR *bptr, FAR *cptr; unsigned short r_dx; unsigned char cy; cptr=bptr=buf; r_dx=cpos; cy=output_mask&1; output_mask=(cy?0x80:0)|((output_mask&0xFF)>>1); if(cy) { if(r_dx>=bufsiz) { send_block(); r_dx=0; if(unpackable) { cpos=r_dx; return; } } output_pos=r_dx; cptr[r_dx]=0; r_dx++; } bptr+=r_dx; *bptr++=c; c_freq[c]++; cpos=bptr-cptr; } /* Initializes memory for encoding */ void allocate_memory() { int i; if((c_freq=calloc(NC*2-1, sizeof(*c_freq)))==NULL) error(M_OUT_OF_NEAR_MEMORY); if((c_code=farcalloc(NC, sizeof(*c_code)))==NULL) error(M_OUT_OF_MEMORY); if((heap=farcalloc(NC+1, sizeof(*heap)))==NULL) error(M_OUT_OF_MEMORY); for(i=0; i=MAX_BUFSIZ-BUFSIZ_INCREMENT) bufsiz=MAX_BUFSIZ-1; #ifdef FINETUNE_BUFSIZ i=1; #endif /* Adjust the buffer size if there's not enough memory for it */ while((buf=farmalloc(bufsiz))==NULL) { #ifndef FINETUNE_BUFSIZ bufsiz=bufsiz/10U*9U; #else if(i<2048) bufsiz-=i++; else bufsiz=bufsiz/16U*15U; #endif if(bufsiz>4), 0); #else ftree=dtree=farcalloc((unsigned long)treesize+16L, sizeof(*ftree)); #endif fpbuf=farcalloc((unsigned long)fpcount+4L, 2L); if(ftree==NULL||fpbuf==NULL) error(M_OUT_OF_MEMORY); } if(dic_alloc<1024) dic_alloc=1024; allocate_memory(); nchars=(UCHAR_MAX+THRESHOLD)*2; display_indicator(0L); encoded_bytes=0L; tc_passes=0; dicpos=0; i=j=0; while(!unpackable) { tree_el=0; k=0; if(j!=0) { tree_el=dic_alloc; if((k=j-tree_el)<=0) { k=0; tree_el=j; } else memmove(tree, tree+k, tree_el); } max_fetch=fetch=(unsigned int)(treesize-tree_el); if(multivolume_option) fetch=check_multivolume(fetch); if(max_fetch!=fetch) nchars=4; if((fetch=fetch_uncomp(tree+tree_el, fetch))==0) { if(tree_el==0||k==0) break; memmove(tree+k, tree, tree_el); dicsiz_cur=min(tree_el-i-1, dicsiz_cur); break; } j=fetch+tree_el; encoded_bytes+=(unsigned long)fetch; display_indicator(encoded_bytes); m=0; if(k<=0) fill_fpbuf(); else { fptr=fpbuf; for(l=fpcount>>2; l>0; l--) { *fptr=max(*fptr-k, -1); fptr++; *fptr=max(*fptr-k, -1); fptr++; *fptr=max(*fptr-k, -1); fptr++; *fptr=max(*fptr-k, -1); fptr++; } dtptr=dtree; for(l=tree_el>>3; l>0; l--) { *dtptr=max(dtptr[k]-k, -1); dtptr++; *dtptr=max(dtptr[k]-k, -1); dtptr++; *dtptr=max(dtptr[k]-k, -1); dtptr++; *dtptr=max(dtptr[k]-k, -1); dtptr++; *dtptr=max(dtptr[k]-k, -1); dtptr++; *dtptr=max(dtptr[k]-k, -1); dtptr++; *dtptr=max(dtptr[k]-k, -1); dtptr++; *dtptr=max(dtptr[k]-k, -1); dtptr++; } /* Store the remainder */ for(l=tree_el%8; l>0; l--) { *dtptr=max(dtptr[k]-k, -1); dtptr++; } m+=tree_el; if(m>=2) m-=2; } tptr=&tree[m]; r_dx=(unsigned short)*(tptr++); r_cx=(fp_max&0xFF00)|(hash_bits&0xFF); r_dx<<=(hash_bits&0xFF); r_dx^=(unsigned short)*(tptr++); r_dx&=(r_cx|0xFF); for(l=j-2; mnchars) { i--; pm=m; m++; n_passes=(unsigned int)tc_passes; f_dicpos=(int)dicpos; if((r_ax=upd_tree(m))>i) r_ax=tc_passes=i; if(n_passes16384)||--r_ax>n_passes||(r_ax==n_passes&&dicpos>>1i) tc_passes=i; } } } while(i>0) { i--; pm=m; m++; n_passes=tc_passes; f_dicpos=dicpos; if((r_ax=upd_tree(m))>i) r_ax=tc_passes=i; if(n_passes16384)||--r_ax>n_passes||(r_ax==n_passes&&dicpos>>1i) tc_passes=i; } } huf_encode_end(); #ifdef ASM8086 farfree_based(ftree); #else farfree(ftree); #endif farfree(fpbuf); free(tree); tree=NULL; } /* Encoding stub for -m3 */ static void NEAR huf_encode_m3() { int hash_bits; unsigned short fp_max; int i, j, m; unsigned short t; /* Exchange variable */ short k, l; int tree_el; unsigned int fetch; unsigned char *tptr; unsigned short r_cx, r_dx; short r_ax; hash_bits=(dicbit+2)/3; fpcount=1U<>4), 0); #else ftree=dtree=farcalloc((unsigned long)treesize+16L, sizeof(*ftree)); #endif fpbuf=farcalloc((unsigned long)fpcount+4L, 2L); if(ftree==NULL||fpbuf==NULL) error(M_OUT_OF_MEMORY); } allocate_memory(); display_indicator(encoded_bytes=0L); j=0; while(!unpackable) { tree_el=0; if(dic_alloc!=0&&j!=0) { tree_el=dic_alloc; if((k=j-tree_el)<=0) { k=0; tree_el=j; } else memmove(tree, tree+k, tree_el); } fetch=(unsigned int)(treesize-tree_el); if(multivolume_option) fetch=check_multivolume(fetch); if((fetch=fetch_uncomp(tree+tree_el, fetch))==0) break; else { j=fetch+tree_el; encoded_bytes+=(unsigned long)fetch; display_indicator(encoded_bytes); fill_fpbuf(); l=fetch; tptr=tree; r_dx=(unsigned short)*(tptr++); r_cx=(fp_max&0xFF00)|(hash_bits&0xFF); r_dx<<=(hash_bits&0xFF); r_dx^=(unsigned short)*(tptr++); r_dx&=(r_cx|0xFF); for(m=0; m0) { r_ax=upd_tree(m); if((r_ax=upd_tree(m))>i) r_ax=tc_passes=i; if(r_axDICSIZ_MAX) error(M_LARGE_DICTIONARY); if(dic_alloc>treesize) error(M_LARGE_GSIZE); if(method==3) huf_encode_m3(); else huf_encode(); } /* Fast search stub for method 4 */ static void enc4_pass1(int n_c) { #ifdef ASM8086 asm{ mov dx, n_c mov bx, 1 mov cx, 0 cmp dx, bx jl cease_search } binsearch: asm{ sub dx, bx inc cx shl bx, 1 cmp dx, bx jl cease_search sub dx, bx inc cx shl bx, 1 cmp dx, bx jl cease_search sub dx, bx inc cx shl bx, 1 cmp dx, bx jl cease_search sub dx, bx inc cx shl bx, 1 cmp dx, bx jl cease_search sub dx, bx inc cx shl bx, 1 cmp dx, bx jl cease_search jmp binsearch } cease_search: asm{ or cx, cx jz chk_ctr_bounds push dx push cx mov ax, 65535 push ax push cx call far ptr putbits add sp, 4 pop cx pop dx } chk_ctr_bounds: asm{ cmp cx, 7 jge p1exit inc cx } p1exit: asm{ push dx push cx call far ptr putbits add sp, 4 } #else short r_bx=1; int r_cx=0; while(n_c>=r_bx) { n_c-=r_bx; r_cx++; r_bx<<=1; } if(r_cx!=0) putbits(r_cx, -1); if(r_cx<7) r_cx++; putbits(r_cx, n_c); #endif } /* Dictionary position lookup */ static void enc4_pass2(int n_c) { #ifdef ASM8086 asm{ mov dx, n_c mov bx, 512 mov cx, 9 cmp dx, bx jl p2_cease_search } p2_bsearch: asm{ sub dx, bx inc cx shl bx, 1 cmp dx, bx jl p2_cease_search sub dx, bx inc cx shl bx, 1 cmp dx, bx jl p2_cease_search sub dx, bx inc cx shl bx, 1 cmp dx, bx jl p2_cease_search sub dx, bx inc cx shl bx, 1 cmp dx, bx jl p2_cease_search sub dx, bx inc cx shl bx, 1 cmp dx, bx jge p2_bsearch } p2_cease_search: asm{ mov ch, cl sub cl, 9 jz p2_chk_ctr push cx push dx mov ax, 65535 push ax push cx call far ptr putbits add sp, 4 pop dx pop cx } p2_chk_ctr: asm{ cmp ch, 13 jge p2exit inc ch } p2exit: asm{ mov cl, ch push dx push cx call far ptr putbits add sp, 4 } #else unsigned short r_bx=1<<9; int r_cx=9; while(n_c>=r_bx) { n_c-=r_bx; r_cx++; r_bx<<=1; } if(r_cx!=9) putbits(r_cx-9, -1); if(r_cx<13) r_cx++; putbits(r_cx, n_c); #endif } /* Encodes a single file, using method 4 */ void encode_f() { int fetch; int hash_bits; unsigned short fp_max; unsigned char *tptr; int i, m; unsigned short r_cx, r_dx, r_ax; unsigned short t; dicbit=14; numchars=32; dicsiz_cur=15800; treesize=30720; adjust_dicbit(); hash_bits=(dicbit+2)/3; fpcount=1U<>4), 0); #else ftree=dtree=farcalloc((unsigned long)treesize+16L, sizeof(*ftree)); #endif fpbuf=farcalloc((unsigned long)fpcount+4L, 2L); if(ftree==NULL||fpbuf==NULL) error(M_OUT_OF_MEMORY); } init_putbits(); cpos=0; display_indicator(encoded_bytes=0L); while(!unpackable) { fetch=treesize; if(multivolume_option) fetch=check_multivolume(fetch); if((fetch=fetch_uncomp(tree, fetch))==0) break; encoded_bytes+=(unsigned long)fetch; display_indicator(encoded_bytes); fill_fpbuf(); m=0; tptr=tree; r_dx=(unsigned short)*(tptr++); r_cx=(fp_max&0xFF00)|(hash_bits&0xFF); r_dx<<=(hash_bits&0xFF); r_dx^=(unsigned short)*(tptr++); r_dx&=(r_cx|0xFF); for(m=0; m0) { if((r_ax=upd_tree(m))>i) r_ax=tc_passes=i; if(r_ax