compression engine

pker:

再贴一个compression engine吧


这个也是刚放假写的,思想和benny的一样,但在encode和decode上对bit stream的处理不同(compress的第5步和整个decompress过程),我觉得还是我这个更好理解写,嘻嘻~~~~~~不过效率会低一些。。。
正准备写个别的算法的。。。。。。。不过还没想好,呵呵

;
; pker's Compression Engine for Win32
; -- Semi-Huffman Algorithm Version
; ===================================
;
;
; Description
; -----------
;
; Well, this is my first compression engine. This idea of this engine is from
; Benny's BCE32 (thnx Benny : P), BUT they not the same, NOT even a little. In
; this engine, I also compress bit groupz instead of bytez and I use the semi-
; huffman (I think this is a good name for that code :P) code which shows below,
; the diagram is ordered by frequency of each bit group of the byte streamz:
;
;     frequency       code
;     ---------       ----
;
;     0. highest       1B
;     1. 2nd highest     01B
;     2. 2nd lowest     001B
;     3. lowest       000B
;
; Now, I'll explain the biggest difference between this engine and the BCE32. I
; think an example is very good enough:
;
; Suppose we're gonna compress the byte stream: ADCBD, it's binary code shows
; blow:
;
; 0110 0101   0110 1000   0110 0111   0110 0110   0110 1000
; A         D         C         B         D
;
; Now, calculate the frequency of bit groupz and determin the semi-huffman code:
;
;     Group       Count       Semi-Huffman Code
;     -----       -----       -----------------
;
;     00         2           001
;     01         9           1
;     10         8           01
;     11         1           000
;
; Now comes the good part :D. Usually, also in BCE32, we regard the left side of
; the huffman code as the higher bitz, so we should encode the stream above like
; this (output in bytez):
;
; byte stream:
; 1101 1001   0101 1000   1011 0110   1100 1010   0000 0011
;
;
; When decoding, we have to read from the high bit to the low one. But remember,
; the lower byte's lowest bit is connected with the higher byte's highest bit in
; the semi-huffman code and the lower byte's highest bit is connected with the
; higher byte's lowest bit... @#$%%&, what a mess... I don't like that kind of
; thing. So, I decided to regard the right side of the semi-huffman code as the
; higher bit and fill the bit stream from lwo to high, bit to bit. According
; to the example above, my engine will output the encoded bit stream like this:
;
; bit stream:
; 1101100101011000101101101100101011
;
; With this bit stream, we just read bit after bit from the bit stream can we
; finally decompress the code. This process is much more clearer to me :D
;
;
; How to use it?
; --------------
;
; This engine is designed for FASM. Before using it, like BCE32, you have to
; prepare to bufferz to save the frequency and the sorted frequency. In order to
; use this engine properly, do the following:
;
;     freq     dd     0,0,0,0
;     freq_s     dd     0,0,0,0
;     compressed: times compressed_size   db 0
;     decompressed: times buf_size   db 0
;
;     ; ------------ compression ------------
;
;     compress:   mov   esi,buffer
;             mov   edi,compressed
;             mov   ecx,buf_size
;             mov   ebx,freq
;             mov   edx,freq_s
;             call   __pkce32_compress
;
;     ; ----------- decompression -----------
;
;     decompress: mov   esi,compressed
;             mov   edi,decompressed
;             mov   ecx,real_compressed_size
;             call   __pkce32_decompress
;
; Like what I've said, this engine is designed for FASM. But by adding PTR dire-
; ctive to every DWORD or WORD or BYTE directive, the engine could also use with
; TASM or MASM :)
;
; Enjoy it!!!
;
;
; Copyright
; ---------
;
; (c) 2004. No rightz reserved. Use without permission :P.
;


;
; __pkce32_compress procedure
; ===========================
;
;
; Parameterz and Return Valuez
; ----------------------------
;
; Input:
;     esi --- points to data which will be compressed
;     edi --- points to a buffer to save compressed data
;     ecx --- size of the buffer, which will be compressed
;     ebx --- points to the word frequency buffer 1
;     edx --- points to the word frequency buffer 2, this buffer is different
;           with buffer 1, 'cause this buffer will hold the sorted frequency
;           data. it will be used to determine which double-bitz has the
;           highest frequency, which the second highest...which...
;
; Output:
;     eax --- the compressed data length
;     CF --- CF = 0, positive compression
;           CF = 1, negative compression
;

__pkce32_compress:
          pushad

;
; 1st step...
; calculate how many timez 00, 01, 10, 11 appears, and save each number in the
; corresponding buffer (4 dwordz altogether)
;

pkc_next_byte: push   ecx
          push   4
          pop   ecx                 ; 2 bitz * 4 = 1 byte
          xor   eax,eax
          lodsb
pkc_next_2bitz: mov   ebp,eax
          and   ebp,3               ; lowest 2 bitz
          inc   dword [ebx+4*ebp]       ; increase the corresponding
          inc   dword [edx+4*ebp]       ; frequency field
          shr   eax,2               ; next 2 bitz
          loop   pkc_next_2bitz
          pop   ecx
          loop   pkc_next_byte

;
; 2nd step...
; we don't allow same frequency number exists, so we have to distinguish them
;

          push   4
          pop   ecx
pkc_c_index:   xor   ebp,ebp               ; use EBP as index
pkc_dif_l:     mov   eax,[ebx+4*ebp]
          inc   dword [ebx+4*ebp]       ; differ from myself...
          inc   dword [edx+4*ebp]       ; ...
          cmp   eax,[ebx]             ; same as 1st number?
          jz     pkc_d_inc
          cmp   eax,[ebx+4]           ; same as 2nd number?
          jz     pkc_d_inc
          cmp   eax,[ebx+8]           ; same as 3rd number?
          jz     pkc_d_inc
          cmp   eax,[ebx+12]           ; same as 4th number?
          jnz   pkc_d_ninc
pkc_d_inc:     inc   dword [ebx+4*ebp]       ; distinguishing
          inc   dword [edx+4*ebp]       ; ...
          inc   ecx                 ; have to loop one more time
pkc_d_ninc:   cmp   bp,3
          jz     pkc_c_index
          inc   ebp
          loop   pkc_dif_l

;
; 3rd step...
; bubble sort the frequency buffer (4 dwordz), save the result in buffer 2
;

          mov   esi,edx               ; let both ESI n' EDI
          mov   edi,edx               ; point to the buffer
          push   3                   ; and sortin' beginz...
          pop   ecx
pkc_sort_ol:   push   ecx
          push   esi
          push   edi
pkc_sort_il:   lodsd                     ; load a DWORD
          xchg   eax,ebp
          lodsd                     ; another DWORD
          lea   esi,[esi-4]           ; back up 4 bytez
          cmp   ebp,eax
          jg     pkc_no_swap
          stosd                     ; exchange the two DWORDz
          xchg   ebp,eax               ; ...
          stosd                     ; ...
          lea   edi,[edi-8]           ; and EDI + 4
pkc_no_swap:   lea   edi,[edi+4]           ; ...
          loop   pkc_sort_il
          pop   edi
          pop   esi
          pop   ecx
          loop   pkc_sort_ol

;
; 4th step...
; check the relationship of the two bufferz, perparing for encoding
;

          push   4
          pop   ecx
          mov   esi,ebx               ; unsorted buffer
          xor   ebp,ebp               ; initialize the index
          push   ebp                 ; squeeze out a DWORD
                                  ; in the stack...
pkc_cr_l:     xor   ebx,ebx
          push   esi                 ; save it
          mov   edi,[edx+4*ebp]
          lodsd
          cmp   edi,eax
          jz     pkc_cr_wr_en
          inc   ebx
          lodsd
          cmp   edi,eax
          jz     pkc_cr_wr_en
          inc   ebx
          lodsd
          cmp   edi,eax
          jz     pkc_cr_wr_en
          inc   ebx
pkc_cr_wr_en:   pop   esi                 ; restore
          shl   dword [esp],2           ; save the encrypt code
          or     [esp],bl
          inc   ebp
          loop   pkc_cr_l
          pop   ebx                 ; now EBX containz the
                                  ; encrypt code...

;
; 5th step...
; we could encode the buffer finally, i will encode the buffer with the code
; shows below according to the frequency:
;
;     frequency       code
;     ---------       ----
;
;     0. highest       1B
;     1. 2nd highest     01B
;     2. 2nd lowest     001B
;     3. lowest       000B
;

          mov   ecx,[esp+24]           ; restore ECX
          inc   ecx
          mov   esi,[esp+4]           ; restore ESI
          mov   edi,[esp]             ; restore EDI
          mov   al,bl               ; decrypt code
          stosb                     ; store...
          xor   ebp,ebp
          xor   eax,eax
          cdq
pkc_ec_nxt_byt: lodsb                     ; load one byte to encode
          xchg   bp,ax               ; save it
          push   ecx                 ; save byte counter
          push   4
          pop   ecx
pkc_ec_nxt_btz: mov   ax,bp               ; restore the byte to encode
          shr   bp,2

          and   al,3                 ; use lowest 2-bitz
          mov   dl,bl               ; get encrypt code
          and   dl,3                 ; also keep lowest 2-bitz
          cmp   al,dl
          jz     pkc_ec_3             ; lowest-freq. bit-group

          mov   dl,bl               ; restore
          shr   dl,2                 ; next bit-group
          and   dl,3
          cmp   al,dl
          jz     pkc_ec_2             ; 2nd-lowest-freq. bit-group

          mov   dl,bl
          shr   dl,4
          and   dl,3
          cmp   al,dl
          jz     pkc_ec_1             ; 2nd-highest-freq. bit-group

pkc_ec_0:     stc                       ; highest-freq. bit-group
          call   pkc_ec_wr
pkc_ec_rl:     loop   pkc_ec_nxt_btz
          pop   ecx                 ; restore byte counter
          loop   pkc_ec_nxt_byt

          sub   edi,[esp]             ; cal. new size
          mov   [esp+28],edi           ; save new size
          popad
          cmp   eax,ecx               ; negative compress?
          jg     pkc_ec_neg
          clc
          ret
pkc_ec_neg:   stc
          ret

pkc_ec_1:     clc
          call   pkc_ec_wr
          jmp   pkc_ec_0

pkc_ec_2:     clc
          call   pkc_ec_wr
          jmp   pkc_ec_1

pkc_ec_3:     clc
          call   pkc_ec_wr
          clc
          call   pkc_ec_wr
          clc
          call   pkc_ec_wr
          jmp   pkc_ec_rl


;
; This procedure use CF as bit stream to construct output (edcoded) bit stream,
; use high word of EBP as bit counter, and output the bit stream when it equalz
; 8 (1 byte). The bit stream will be saved in the high byte of EAX.
;

pkc_ec_wr:     rcl   edx,1               ; get one bit
          and   edx,1
          push   ecx                 ; save byte counter
          rol   ebp,16               ; bit counter :P
          push   8
          pop   ecx
          sub   cx,bp
          inc   bp                 ; increase it
          rol   eax,cl               ; bit stream
          or     al,dl               ; one more bit
          cmp   bp,8                 ; finish one byte?
          jnz   pkc_ec_no_out
          rol   eax,7
          stosb
          xor   eax,eax
          xor   bp,bp               ; clear bit counter
pkc_ec_no_out: ror   eax,cl               ; restore EAX
          ror   ebp,16               ; restore EBP
          pop   ecx                 ; restore byte counter
          ret


;
; __pkce32_decompress procedure
; =============================
;
;
; Parameterz and Return Valuez
; ----------------------------
;
; Input:
;     esi --- points to data which will be decompressed
;     edi --- points to a buffer to save decompressed data
;     ecx --- size of the buffer, which will be decompressed
;
; Output:
;     eax --- size of decompressed buffer
;

__pkce32_decompress:
          pushad
          xor   eax,eax
          lodsb                     ; load the decrypt code
          mov   ebx,eax               ; let EBX hold it
          xor   ebp,ebp               ; clear bit counter
          cdq

          call   pkc_dc_load           ; get one byte to decode
pkc_dc_bit_alz: shr   al,1
          rcl   dl,1                 ; move the bit to DL
          inc   bp
          cmp   bp,8
          jnz   pkc_dc_b0
          call   pkc_dc_load
pkc_dc_b0:     test   dl,1
          jnz   pkc_dc_0

          shr   al,1
          rcl   dl,1
          inc   bp
          cmp   bp,8
          jnz   pkc_dc_b1
          call   pkc_dc_load
pkc_dc_b1:     test   dl,1
          jnz   pkc_dc_1

          shr   al,1
          rcl   dl,1
          inc   bp
          cmp   bp,8
          jnz   pkc_dc_b2
          call   pkc_dc_load
pkc_dc_b2:     test   dl,1
          jnz   pkc_dc_2

          mov   dl,bl               ; lowest
          and   dl,3
          call   pkc_dc_wr
pkc_dc_lr:     or     ecx,ecx
          jz     pkc_dc_ret
          jmp   pkc_dc_bit_alz
pkc_dc_ret:   sub   edi,[esp]             ; cal. new size
          mov   [esp+28],edi
          popad
          ret

pkc_dc_2:     mov   dl,bl               ; 2nd-lowest
          shr   dl,2
          and   dl,3
          call   pkc_dc_wr
          jmp   pkc_dc_lr

pkc_dc_1:     mov   dl,bl               ; 2nd-highest
          shr   dl,4
          and   dl,3
          call   pkc_dc_wr
          jmp   pkc_dc_lr

pkc_dc_0:     mov   dl,bl               ; highest
          shr   dl,6
          call   pkc_dc_wr
          jmp   pkc_dc_lr

pkc_dc_load:   pushf
          lodsb                     ; load one byte
          xor   bp,bp
          dec   ecx
          popf
          ret

;
; This procedure BH as bit stream, high byte of EBP as bitz counter. The lowest
; byte of EBP is also a bit counter that used somewhere else.
;

pkc_dc_wr:     ror   dx,2
          rol   ebp,16               ; get the bit counter
          inc   bp                 ; increase a bit
          cmp   bp,4                 ; bit stream full?
          jnz   pkc_dc_no_out
          xchg   dh,al               ; output bit stream
          stosb                     ; ...
          xchg   dh,al               ; ...
          xor   bp,bp               ; clear bit counter
          xor   dh,dh               ; clear bit stream
pkc_dc_no_out: ror   ebp,16               ; restore EBP
          ret

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值