home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FreeWare Collection 2
/
FreeSoftwareCollection2pd199x-jp.img
/
fbasic
/
pmgf
/
compress.asm
next >
Wrap
Assembly Source File
|
1990-06-14
|
22KB
|
750 lines
.386p
PUBLIC GSAVE
PUBLIC nlength,CMPAGR,L_CPAG,CPAGe,CPAG2,LINE,L_SET5
PUBLIC SET5in,CHK3,LINEND0,GSET,SKIPg,GSETe,LINEND1,PAT1
PUBLIC PAT1j,PAT12,PAT2,PAT2j,PAT22,PAT3,L_PAT3
PUBLIC PAT3j,PAT32,PAT4,PAT4j,PAT42,PAT5,L_PAT5,PAT5e,PAT5o
PUBLIC PAT5j,PAT52,PATEND,LINEND,LINED2,LINTRS,HIGCMP,L_HIGC
PUBLIC HIGCm,L_HICm,L_HICc,NONEQU,L_NOEQ,NOEQe,NOEQ1,NOEQST
PUBLIC NOEQ2,CHGr,RECOMP,CMPe,COMPt,HIHEAD,LOWCMP
PUBLIC L_LWC,LOWCm,L_LOWC,LOWCe,LOWCtr,LOWH1,LOWH2,CMPEND
PUBLIC CHKLIN,CHKLOW,CHKHIG,CHKEND,TRSNON,TRSLIN,TRSin,CHKED2
PUBLIC TRSHIG,TRSLOW
param struc
point dd ? ;データ格納ポインタ
linbuf dd ?,?
ngc dd ? ;捨てられたデータの数を示すカウンタ
;
dd ? ;使用禁止
nrefer dd ? ;参照できるライン数
lngth dd ? ;1ラインのバイト数
data dd ? ;圧縮元データ格納アドレス
refer dd ? ;参照データ格納アドレス
outd dd ? ;出力データ格納アドレス
work dd ? ;ワークエリア先頭アドレス
bml dd ? ;ビットマップ長
trsbuf dd ? ;圧縮後に登録する参照バッファ
dflag dd ? ;デバッグパラメータ
param ends
nlength EQU 1024 ;1ラインの最大長(参照データ1ライン分のデータ長も兼ねる)
wlength EQU 1536 ;ワークエリアの1モード分の長さ
worklng EQU 4*4
dbf EQU 0
; MACRO
debug macro val
pushf
push eax
push edx
mov eax,val
and eax,4fh
mov edx,04ech ;Volume Meter
out dx,al
pop edx
pop eax
popf
endm
debugs macro val,val2
pushf
push eax
push edx
mov eax,val
shl eax,val2
and eax,4fh
mov edx,04ech ;Volume Meter
out dx,al
pop edx
pop eax
popf
endm
debugl macro val,val2
pushf
push eax
push edx
mov eax,val
and eax,4fh
mov edx,04ech ;Volume Meter
out dx,al
mov eax,val2
out dx,al
pop edx
pop eax
popf
endm
dbret macro
add esp,worklng
mov eax,0fffffffh
ret
endm
djmp macro val,val2
if dbf
cmp dword PTR dflag[ebp],val
je val2
endif
endm
CODE segment dword public ER use32 'CODE'
assume cs:CODE, ds:CODE
; Graphics Data Compress Routine for F-BASIC386
EXEC proc near
GSAVE: sub esp,worklng ;ワークエリア確保
cld ;自動増加を指定
mov ebp,esp ;パラメータ用にespの値をebpに転送
; ;完全一致モード
CMPAGR: mov ebx,nrefer[ebp] ;参照できるライン数を読み込む
cmp ebx,0 ;それは0か
je LINE ;0なら1次元圧縮モードへ
dec ebx ;計算のため-1する
;
L_CPAG: mov esi,refer[ebp] ;参照データの先頭アドレスをesiにセット
mov edi,data[ebp] ;圧縮対象データの先頭アドレスをediにセット
mov eax,nlength ;1ライン分のデータ領域長を得る(最大値)
mul ebx
add esi,eax
mov ecx,lngth[ebp]
;
repe cmpsb
jz CPAGe
sub ebx,1
jnc L_CPAG
jmp LINE
CPAGe:
mov edi,outd[ebp]
mov eax,ebx
cmp ebx,7
ja CPAG2
;
or al,0C8h
mov [edi],al
mov eax,1
jmp REGBUF
;
CPAG2: and ah,7h
or al,88h
xchg al,ah ;完全一致モードに適合したなら、それが一番短い mov [edi],ax ;データ(つまり圧縮率が高い)になるため、以下のサ
mov eax,2 ;ーチは行わず、呼び出し元へリターン
jmp REGBUF
;
;
LINE: ;1次元圧縮モード
mov ngc[ebp],dword PTR 0 ;非パターンデータのカウンタをクリア
mov esi,data[ebp] ;圧縮対象データのアドレスをセット
mov edi,outd[ebp] ;出力アドレスをセット
mov ecx,lngth[ebp] ;対象データの長さをセット
mov point[ebp],edi ;比較のための値をセット(非圧縮時の長さ)
add point[ebp],ecx
;
L_SET5: ;非パターンデータバッファに対象ポイントの先頭から5バイトを転送
mov eax,[esi]
mov linbuf[ebp],eax
mov bl,[esi+4]
mov byte PTR linbuf+4[ebp],bl
;
cmp ecx,5 ;対象データの残りが5バイト以上あるか?
jbe CHK2 ;なければ分岐
SET5in:
mov eax,[esi]
xor eax,[esi+1] ;対象の5バイトはすべて同じバイトデータか
jz PAT1 ;同じなら1パターン圧縮を行う
;
CHK2: mov ax,[esi]
cmp ax,[esi+2] ;5バイト中の先頭2バイトと次の2バイトが同じか
jne CHK5 ;違うなら5バイトパターンチェックへ
cmp ah,al ;先頭1バイトと次のバイトが同じか
jne PAT2 ;違うなら2バイト圧縮を行う
jmp PAT1 ;同じなら1パターン圧縮を行う
;
CHK5: cmp ecx,5 ;対象データの残りが5バイト以上あるか?
jbe LSTCHK ;なければ分岐
mov eax,[esi]
xor eax,[esi+5] ;現在の5バイトと次の5バイトが同じか
jnz CHK3 ;違うなら3バイトパターンチェックへ
mov bl,[esi+4]
xor bl,[esi+9]
jz PAT5 ;同じなら5パターン圧縮を行う
;
CHK3: mov eax,[esi]
xor eax,[esi+3]
and eax,0ffffffh ;5バイト中の先頭3バイトと次の3バイトが同じか
jz PAT3 ;同じなら3パターン圧縮を行う
;
mov eax,[esi]
xor eax,[esi+4] ;5バイト中の先頭4バイトと次の4バイトが同じか
jz PAT4 ;同じなら4パターン圧縮を行う
;
LSTCHK: mov ax,[esi] ;5バイト中の先頭バイトと次のバイトと
cmp al,ah ;その次のバイトが同じなら1パターン圧縮を行う
jne CHK5BT
xor al,[esi+2]
jz PAT1
CHK5BT: cmp ecx,5 ;対象データの残りが5バイト以上あるか?
jbe LINEND1 ;なければ分岐
;
NXTCHK: inc byte PTR ngc[ebp] ;非パターンデータカウンタをインクリメントする
add esi,1 ;ポインタをインクリメントする
dec ecx ;データ数をデクリメントする
jz LINEND0 ;0になったら分岐
cmp byte PTR ngc[ebp],5 ;5バイト溜まったかチェック
jb SET5in ;溜まっていなければループ
;
LINEND0:
call GSET ;非パターンデータを(あれば)セット
jmp PATEND ;ジャンプ
;
GSET: push ecx ;ecxを保存
mov ecx,ngc[ebp] ;非パターンデータ数をセット
cmp ecx,0 ;もし非パターンデータがなければ
je GSETe ;分岐(リターン)
cmp ecx,5 ;データ数は5未満か
jb SKIPg ;未満なら分岐
mov ecx,5 ;以上なら念のため5をセット
SKIPg:
mov ax,cx ;データ数をaxにコピー
shl al,5 ;ブロックヘッダにデータ数をセットするためシフト
or al,11h ;ヘッダ生成
stosb ;ブロックヘッダストア
push esi ;esiを保存
lea esi,linbuf[ebp] ;非パターンデータの格納アドレスをセット
rep movsb ;データ転送
mov dword PTR ngc[ebp],0 ;カウンタをクリア
pop esi ;データ復帰
GSETe: pop ecx ;データ復帰
ret
;
LINEND1: ;残りデータが5バイト未満の時はここにくる
mov ngc[ebp],ecx ;非パターンカウンタに値をセット
mov ecx,0 ;ecxを補正する
jmp LINEND0 ;ジャンプ
;
; 1バイトパターンモード
PAT1: call GSET ;非パターンデータをクリアする
mov edx,ecx ;ブロック数計算のためecxの内容をedxに保存しておく
lodsb ;パターンデータを読み込む
dec ecx ;カウンタ補正
push edi ;保存
mov edi,esi ;ディストネーションアドレスセット
repe scasb ;違うデータが現れるまでサーチ
jz PAT1j ;カウントエンドでループアウトなら分岐
inc ecx ;カウンタ補正
sub edi,1 ;次のサーチアドレスをセットしておく
PAT1j: mov esi,edi
pop edi ;復帰
sub edx,ecx ;ブロック数計算
cmp edx,15 ;ブロック数が15以上か
ja PAT12 ;以上なら2バイトヘッダモードに分岐
mov ah,dl ;ブロック数をahにセット(alにはブロックデータが格納済)
or ah,30h ;ヘッダ生成
xchg al,ah ;ahを先にストアするために上下位交換
stosw ;データストア
jmp PATEND ;ジャンプ
PAT12: mov [edi+2],al ;先にブロックデータをストア
or dx,2000h ;ヘッダ生成
xchg dl,dh ;dhを先にストアするため上下位交換
mov [edi],dx ;ヘッダストア
add edi,3 ;ポインタ補正
jmp PATEND ;ジャンプ
;
PAT2: call GSET
mov ebx,ecx ;ループエンド時のカウンタ復帰の為にecxをebxにコピー
and ebx,1 ;mod 2
shr ecx,1 ;\ 2 ループ回数計算
mov edx,ecx ;ブロック数計算のためecxの内容をedxに保存しておく
lodsw ;パターンデータを読み込む
dec ecx ;カウンタ補正
push edi ;保存
mov edi,esi ;アドレスセット
repe scasw ;違うデータが出てくるまでサーチ
jz PAT2j ;カウントエンドでループアウトなら分岐
inc ecx ;カウンタ補正
sub edi,2 ;サーチアドレスセット
PAT2j: mov esi,edi
pop edi ;復帰
sub edx,ecx ;ブロック数計算
shl ecx,1 ;カウンタをバイト長に直す
or ecx,ebx ;復帰
cmp edx,15 ;ブロック数は15以上か
ja PAT22 ;以上なら分岐
or dl,50h ;ヘッダ生成
mov [edi],dl;ヘッダストア
inc edi ;ポインタ補正
stosw ;データストア
jmp PATEND ;ジャンプ
PAT22: mov [edi+2],ax ;データストア
or dx,4000h ;ヘッダ生成
xchg dl,dh ;上下位交換
mov [edi],dx ;ヘッダストア
add edi,4 ;ポインタ補正
jmp PATEND ;ジャンプ
;
PAT3: call GSET
mov ebx,3 ;残りデータ長を3で割る
xor edx,edx
mov eax,ecx
div bx ;商:ax 余り:dx
mov ebx,edx ;最後のecx補正のため余りをebxに保存しておく
mov ecx,eax ;商をカウンタに転送
push ecx ;ブロック数計算のためecxの内容を保存しておく
lodsd ;パターンデータを読み込む
dec ecx ;カウンタ補正
and eax,0ffffffh ;4バイト目をマスク
mov edx,eax ;転送
dec esi ;ポインタ補正
L_PAT3: lodsd ;4バイト読み込む
dec esi ;3バイトだけ読んだことにするためポインタを補正する
and eax,0ffffffh ;4バイト目をマスク
cmp eax,edx ;比較
jnz PAT3j ;違ったらループアウト
loop L_PAT3 ;ループチェック
jmp PAT3j2
PAT3j: sub esi,3 ;ポインタ補正
PAT3j2: mov eax,edx ;データ転送
pop edx ;ecx(Stack)->edx
sub edx,ecx ;ブロック数計算
lea ecx,[ecx][ecx*2] ;ecx=ecx*3
add ecx,ebx ;残りデータ長を復活
cmp edx,15 ;ブロック数は15を越えているか
ja PAT32 ;上なら2バイトヘッダモードへ
or dl,70h ;ヘッダ生成
shl eax,8 ;ヘッダのスペースをアキュムレータ上に空ける
mov al,dl ;ヘッダをアキュムレータにストア
stosd ;データストア
jmp PATEND ;ジャンプ
PAT32: mov [edi+2],eax ;データストア
or dx,6000h ;ヘッダ生成
xchg dl,dh ;上下交換
mov [edi],dx ;ヘッダストア
add edi,5 ;ポインタ補正
jmp PATEND ;ジャンプ
;
PAT4: call GSET
mov ebx,ecx
and ebx,3
shr ecx,2
mov edx,ecx ;ブロック数計算のためecxの内容をedxに保存しておく
lodsd ;パターンデータを読み込む
dec ecx ;カウンタ補正
push edi
mov edi,esi
repe scasd
jz PAT4j ;カウントエンドでループアウトなら分岐
inc ecx ;カウンタ補正
sub edi,4
PAT4j: mov esi,edi
pop edi
sub edx,ecx ;ブロック数計算
shl ecx,2
add ecx,ebx
cmp edx,15
ja PAT42
or dl,90h
mov [edi],dl
inc edi
stosd ;データストア
jmp PATEND
PAT42: mov [edi+2],eax
or dx,8000h
xchg dl,dh
mov [edi],dx
add edi,6
jmp PATEND
;
PAT5: call GSET
mov ebx,5 ;残りデータ長を5で割る
xor edx,edx
mov eax,ecx
div bx
push edx ;最後のecx補正のため余りを保存しておく
mov ecx,eax ;商をカウンタに転送
mov edx,ecx ;ブロック数計算のためecxの内容を保存しておく
lodsb ;最初の1バイトのパターンデータを読み込む
mov bl,al ;blに転送
lodsd ;後の4バイトを読み込む
dec ecx ;カウンタ補正
push edi ;保存
mov edi,esi ;アドレスセット
L_PAT5: inc edi ;最初の1バイトの比較
cmp bl,[edi-1]
jnz PAT5o ;違えばループアウト
scasd ;次の4バイトの比較
jnz PAT5e ;違えばループアウト
loop L_PAT5 ;ループチェック
jmp PAT5j
PAT5e: sub edi,4 ;ポインタ補正
PAT5o: sub edi,1 ;ポインタ補正
PAT5j: mov esi,edi
pop edi ;復帰
sub edx,ecx ;ブロック数計算
lea ecx,[ecx][ecx*4] ;ecx=ecx*5
cmp edx,15 ;ブロック数は15を越えたか
ja PAT52 ;上なら2バイトヘッダモードへ
or dl,0B0h ;ヘッダ生成
mov dh,bl ;データを転送
mov [edi],dx ;データストア
add edi,2 ;ポインタ補正
stosd ;データストア
pop ebx ;edx(Stack)->ebx
add ecx,ebx ;残りデータ長計算
jmp PATEND ;ジャンプ
PAT52: mov [edi+2],bl ;データストア
mov [edi+3],eax ;データストア
or dx,0A000h ;ヘッダ生成
xchg dl,dh ;上下交換
mov [edi],dx ;ヘッダストア
add edi,7 ;ポインタ補正
pop ebx ;edx(Stack)->ebx
add ecx,ebx ;残りデータ長計算
;
PATEND: cmp point[ebp],edi ;非圧縮時より長いデータとなっていないか?
jbe NONLINE ;長ければモードエンド
cmp ecx,0 ;データを全てチェックしたか
ja L_SET5 ;まだのこっていたら分岐
;
LINEND: mov eax,outd[ebp] ;出力データ格納アドレスの先頭を得る
sub edi,eax ;ブロックデータバイト数計算
mov eax,edi
mov esi,outd[ebp] ;出力データ格納アドレスの先頭をセット
mov edi,work[ebp] ;最後に比較するため格納しておくアドレスをセット
mov edx,eax ;データ数を退避しておく
stosd ;最後の比較の為の数値をストア
inc dword PTR [edi-4] ;数値の補正(ヘッダの分)
cmp eax,7 ;データ数は7以上か
ja LINED2 ;以上なら分岐
;
or al,0C0h ;ヘッダ生成
stosb ;ヘッダストア
jmp LINTRS ;分岐
;
NONLINE: ;圧縮データを生成出来なかったのでこのモードを
mov work[ebp],0fffffffh ;選ばない様に、データをセットしておく
jmp HIGCMP ;高圧縮モードへ
;
LINED2: inc dword PTR [edi-4] ;2バイトヘッダなので数値をインクリメント
or ax,8000h ;ヘッダ生成
xchg ah,al ;上下交換
stosw ;ヘッダストア
;
LINTRS: mov ecx,edx ;退避しておいた値を復帰
rep movsb ;データ転送
; 高圧縮モード
HIGCMP:
mov edx,lngth[ebp] ;現モードの比較の為にあらかじめ値を入れておく
add edx,2
mov ebx,work[ebp] ;比較の為のワーク領域の先頭アドレスを得る
add ebx,wlength*4 ;現モードのアドレスを計算
mov [ebx],edx ;ダミーカウンタ
mov eax,nrefer[ebp] ;参照できるライン数を得る
cmp eax,0 ;0か
je LOWCMP ;0なら現モード終了
dec eax ;計算の為-1する
;
L_HIGC: mov edi,outd[ebp] ;出力データアドレスをセット
mov point[ebp],edi ;値を保存
mov esi,data[ebp] ;圧縮対象データアドレスをセット
mov edi,refer[ebp] ;参照バッファアドレスを読み込む
mov ecx,lngth[ebp] ;データ長を得る
mov ngc[ebp],eax ;参照データナンバーを保存
imul ax,nlength ;参照データアドレス計算
add edi,eax
;
call HIGCm ;高圧縮を行う
;
mov eax,ngc[ebp] ;参照データナンバーを復帰
sub eax,1 ;データナンバーをデクリメント
jnc L_HIGC ;マイナスになって(全て参照)いなければループ
jmp LOWCMP ;参照しおわったら低圧縮モードへ
;
HIGCm: push ebx ;データバッファアドレス保存
push edx ;生成データ長チェック値保存
;
L_HICm: mov ebx,1 ;同データカウンタ(オフセットカウンタ)を初期化
xor edx,edx ;異データカウンタをクリア
L_HICc: cmpsb ;1バイト比較する
jnz NONEQU ;違うデータなら分岐
inc ebx ;同じなら同データカウンタをインクリメント
loop L_HICc ;全てチェックしたか?していなければループ
jmp HIEDin ;終わっていたら終了処理へ
;
NONEQU: dec esi ;ポインタ補正
dec edi ;ポインタ補正
mov point+4[ebp],esi ;後のデータ転送の為ポインタを保存
L_NOEQ: cmpsb ;1バイト比較する
jz NOEQe ;同じデータなら分岐
inc edx ;違うなら異データカウンタをインクリメント
loop L_NOEQ ;全てチェックしたか?していなければループ
NOEQe: dec esi ;ポインタ補正
dec edi ;ポインタ補正
xchg edi,point[ebp] ;出力データと参照データのアドレスを交換
xchg esi,point+4[ebp] ;異データの先頭と現在の対象ポインタを交換
cmp ebx,63 ;同データカウンタは63未満か
ja NOEQ2 ;越えていたら2バイトブロックヘッダモードへ
cmp edx,3 ;異データカウンタは3未満か
ja NOEQ2 ;越えていたら2バイトブロックヘッダモードへ
;
NOEQ1: jne NOEQST ;異データカウンタが3でなければ分岐
dec edx ;異データカウンタをデクリメント
mov eax,ebx ;同データカウンタをオフセットとしてeaxにセット
or al,80h ;ヘッダ生成
stosb ;ヘッダストア
movsb ;データストア
mov ebx,1 ;データオフセットカウンタを初期化
NOEQST: mov eax,edx ;異データカウンタをeaxにセット
dec eax ;データ2バイトフラグを作るためカウンタを-1
shl al,6 ;データ2バイトフラグ生成
or al,80h ;ヘッダ生成
or al,bl ;データオフセットをヘッダにセット
stosb ;ヘッダストア
push ecx ;転送のためecxを保存
mov ecx,edx ;データ数をセット
rep movsb ;データ転送
pop ecx ;ecx復帰
jmp RECOMP ;データ長チェックへ分岐
;
NOEQ2: mov eax,edx ;異データカウンタをeaxにセット
xor edx,edx ;異データストアループためにカウンタをクリア
cmp eax,15 ;異データカウンタは15以下か
jbe CHGr ;以下なら分岐
mov edx,eax ;異データ長セット
sub edx,15 ;残りデータ長セット
mov eax,15 ;取り合えず最初の15バイトをセット
CHGr: push ecx ;対象データカウンタ保存
mov ecx,eax ;転送データ長セット
shl eax,11 ;異データ長をヘッダにセット
or eax,ebx ;データオフセットをヘッダにセット
mov ebx,1 ;データオフセットを初期化
xchg al,ah ;上下交換
stosw ;ヘッダストア
rep movsb ;データ転送
pop ecx ;対象データカウンタ復帰
cmp edx,0 ;異データは残っているか
jne NOEQ2 ;残っていたらループ
;
RECOMP: xchg edi,point[ebp] ;出力データと参照データのアドレスを交換
xchg esi,point+4[ebp] ;異データの先頭と現在の対象ポインタを交換
cmp ecx,0 ;まだ圧縮していないデータは残っているか
jne L_HICm ;残っていたらループ
;
HIEDin: xchg edi,point[ebp] ;出力データと参照データのアドレスを交換
sub edi,outd[ebp] ;圧縮データ長計算
pop edx ;生成データ長復帰
cmp edi,edx ;今までの値より今圧縮した方が短いか
jb COMPt ;短ければワークエリアに転送
CMPe: pop ebx ;長ければebxを復帰して
ret ;リターン
;
COMPt: mov edx,edi ;生成データ長を新しいものに交換
mov esi,outd[ebp] ;転送元アドレスセット
pop ebx ;転送先アドレスを復帰
mov edi,ebx ;転送先アドレスをセット
mov ecx,edx ;転送データ長セット
mov eax,edx ;比較データ長セット
add eax,2 ;ヘッダ長を足す
stosd ;比較データ長ストア
mov eax,ngc[ebp] ;参照ラインナンバーを得る
or al,0D0h ;ヘッダ生成
stosb ;トップヘッダストア
mov eax,ecx ;ヘッダにデータ長をセット
cmp eax,127 ;127バイトを越えたか
jbe HIHEAD ;越えていなければ分岐
inc dword PTR [edi-5] ;越えていれば比較データ長をインクリメント
xchg ah,al ;上下交換
stosw ;データカウンタヘッダストア
rep movsb ;バッファにデータを転送する
ret
HIHEAD: or al,80h ;ヘッダ生成
stosb ;ヘッダストア
rep movsb ;バッファにデータを転送する
ret
;
; 低圧縮モード
LOWCMP:
mov edi,work[ebp] ;比較のための保存アドレス計算
add edi,wlength*2
mov eax,0ffffffffh ;圧縮後のデータ長とヘッダをダミーで埋める
stosd ;ダミーカウンタ
stosb ;ダミートップヘッダ
mov eax,nrefer[ebp] ;参照できるライン数を得る
cmp eax,0 ;0か
je CMPEND ;0なら分岐
mov ebx,bml[ebp] ;ビットマップ長を読み込む
add ebx,outd[ebp] ;データ格納領域先頭アドレス計算
dec eax ;計算のため参照ラインナンバーを-1する
mov edx,lngth[ebp] ;現モードの比較の為にあらかじめ値を入れておく
add edx,2
;
L_LWC:
push eax ;参照ラインナンバー保存
push edx ;mulにより下位16ビットが壊されるので保存
mov esi,data[ebp] ;対象データ格納アドレスセット
mov edi,refer[ebp] ;参照データ格納アドレス計算
mov ecx,nlength
mul ecx
add edi,eax ;参照データ格納アドレスセット
pop edx ;復帰
;
call LOWCm ;低圧縮を行う
;
pop eax ;復帰
sub eax,1 ;データナンバーをデクリメント
jnc L_LWC ;-1になって(全て参照)いなければループ
jmp CMPEND ;参照しおわったら最終比較へ
;
LOWCm: xor eax,eax ;ビットマップをクリアするためにeaxを0にする
push edi ;参照データ格納アドレス保存
mov edi,outd[ebp]
mov ecx,bml[ebp] ;ビットマップ長セット
rep stosb ;ビットマップクリア
pop edi ;復帰
mov ecx,lngth[ebp] ;データ長セット
;
push ebx ;データ格納アドレス保存
push edx ;生成データ長チェック値保存
push ecx ;データ長保存
dec dword PTR [esp]
L_LOWC:
repe cmpsb ;異データが見つかるまで比較
jz LOWCe ;カウントエンドでループアウトなら分岐
mov al,[esi-1] ;異データをロード
mov [ebx],al ;異データをストア
inc ebx ;データ格納ポインタを進める
mov edx,[esp] ;全データ長を得る
sub edx,ecx ;何ビット目で異データが出たか計算する
mov eax,edx ;それをeaxにコピー
shr edx,3 ;8で割る [ビットマップ先頭から何バイト目か]
and eax,7 ;下位3ビットのみ有効 [そのバイトのどのビットか]
add edx,outd[ebp] ;変更ビットマップのアドレスを得る
bts [edx],ax ;対応ビットを立てる [ MSB:bit7 LSB:bit0 ]
cmp ecx,0 ;全てのデータを処理したか
ja L_LOWC ;していなければループ
;
LOWCe: pop ecx ;スタック補正
sub ebx,outd[ebp] ;処理済データ長を計算する
pop edx ;生成データ長復帰
cmp edx,ebx ;今までの値より今圧縮した方が短いか
ja LOWCtr ;短ければワークエリアに転送
;
pop ebx ;長ければebxを復帰して
ret ;リターン
;
LOWCtr: mov edx,ebx ;生成データ長を新しいものに交換
mov eax,ebx ;現在のデータ長をeaxにコピー
mov ecx,ebx ; 〃 ecxにコピー
mov esi,outd[ebp] ;転送元アドレスセット
mov edi,work[ebp] ;転送先アドレス計算
add edi,wlength*2
add eax,2 ;ヘッダ長(仮に2)を足す
stosd ;カウンタストア
mov eax,[esp+8] ;コール前に保存した参照ラインナンバーを得る
or al,0D8h ;トップヘッダ生成
stosb ;トップヘッダストア
mov eax,ebx ;データバイト数をeaxにセット
cmp eax,128 ;128以上か
jae LOWH2 ;データバイト数ヘッダ2バイトモードへ
or al,80h ;データバイト数ヘッダ生成
stosb ; 〃 ストア
jmp LOWH1 ;ジャンプ
LOWH2: inc dword PTR [edi-5] ;データ長をインクリメント
xchg al,ah ;上下交換
stosw ;データバイト数ヘッダストア
LOWH1: pop ebx ;ebx復帰
rep movsb ;データ転送
ret ;リターン
;
;
CMPEND: ;圧縮後の各データ長比較
mov ecx,lngth[ebp] ;非圧縮時のデータ長を得る
xor ebx,ebx ;圧縮種類インデックスを初期化(0)
mov edi,work[ebp] ;1次元圧縮モードのデータ長格納アドレスを得る
;
CHKLIN:
inc ecx ;非圧縮時のデータ長にヘッダ長を加える
cmp ecx,[edi] ;非圧縮時と1次元圧縮時のデータ長を加える
jbe CHKLOW ;非圧縮時の方が小さいか等しければ次の比較へ
mov ebx,1 ;大きければインデックスを1次元圧縮モードに
mov ecx,[edi] ;データ長を1次元圧縮モードに
CHKLOW:
cmp ecx,[edi+wlength*2] ;チェックしたデータ長と低圧縮モードを比べる
jbe CHKHIG ;低圧縮モードの方が大きければ分岐
mov ebx,2 ;小さければインデックスを低圧縮モードに
mov ecx,[edi+wlength*2] ;データ長を低圧縮モードに
CHKHIG:
cmp ecx,[edi+wlength*4] ;チェックしたデータ長と高圧縮モードを比べる
jbe CHKEND ;高圧縮モードの方が大きければ分岐
mov ebx,3 ;インデックスを高圧縮モードに
mov ecx,[edi+wlength*4] ;データ長を高圧縮モードに
CHKEND:
mov edi,outd[ebp] ;出力データ格納アドレスをセット
cmp ebx,2 ;インデックスは2より小さいか
jae CHKED2 ;小さくなければ分岐
cmp ebx,0 ;インデックスは0より大きいか
ja TRSLIN ;大きければ1次元圧縮データを転送
; ;大きくなければ非圧縮データを転送
TRSNON:
dec ecx ;ヘッダの分のデータ長を引く
mov al,40h ;ヘッダ生成
stosb ;ヘッダストア
mov esi,data[ebp] ;非圧縮データの格納アドレスを得る
rep movsb ;転送
mov eax,lngth[ebp] ;本プログラム呼出元に返す値をセット
inc eax ;ヘッダ長を加える
jmp REGBUF
; 1次元圧縮データ転送
TRSLIN:
mov esi,work[ebp] ;1次元圧縮データの格納アドレスを得る
TRSin: lodsd ;データ長を得る
mov edx,eax ;呼出元へ渡すためにedxに保存しておく
rep movsb ;転送
mov eax,edx ;呼出元に返す値を復帰
;
REGBUF: push eax
mov esi,data[ebp] ;参照バッファを新たに登録しなおす
mov eax,trsbuf[ebp]
mov edi,nlength
xor edx,edx
mul edi
add eax,refer[ebp]
mov edi,eax
mov ecx,lngth[ebp]
mov edx,ecx
and edx,3
mov eax,[esi]
mov [edi],eax
add edi,edx
add esi,edx
shr ecx,2
rep movsd
pop eax
;
add esp,worklng ;ワークエリア解放
ret ;呼出元へリターン
;
CHKED2: je TRSLOW
;
TRSHIG:
mov esi,work[ebp]
add esi,wlength*4
jmp TRSin
;
TRSLOW:
mov esi,work[ebp]
add esi,wlength*2
jmp TRSin
;
;
;
EXEC endp
CODE ends
end