mirror of https://github.com/madler/zlib.git
parent
0484693e17
commit
6b8233bfe0
63 changed files with 11616 additions and 8906 deletions
@ -0,0 +1,2 @@ |
||||
ml64.exe /Flinffasx64 /c /Zi inffasx64.asm |
||||
ml64.exe /Flgvmat64 /c /Zi gvmat64.asm |
@ -0,0 +1,464 @@ |
||||
;uInt longest_match_x64( |
||||
; deflate_state *s, |
||||
; IPos cur_match); /* current match */ |
||||
|
||||
; gvmat64.asm -- Asm portion of the optimized longest_match for 32 bits x86 |
||||
; Copyright (C) 1995-2005 Jean-loup Gailly, Brian Raiter and Gilles Vollant. |
||||
; File written by Gilles Vollant, by modifiying the longest_match |
||||
; from Jean-loup Gailly in deflate.c |
||||
; and modifying asm686 with masm, optimised assembly code from Brian Raiter, |
||||
; written 1998 |
||||
; http://www.zlib.net |
||||
; http://www.winimage.com/zLibDll |
||||
; http://www.muppetlabs.com/~breadbox/software/assembly.html |
||||
; |
||||
; to compile this file, I use option |
||||
; ml64.exe /Flgvmat64 /c /Zi gvmat64.asm |
||||
; with Microsoft Macro Assembler (x64) for AMD64 |
||||
; |
||||
; ml64.exe is given with Visual Studio 2005, Windows 2003 server DDK |
||||
; |
||||
; (you can get Windows 2003 server DDK with ml64 and cl for AMD64 from |
||||
; http://www.microsoft.com/whdc/devtools/ddk/default.mspx for low price) |
||||
; |
||||
; Be carrefull to adapt zlib1222add below to your version of zLib |
||||
|
||||
|
||||
;uInt longest_match(s, cur_match) |
||||
; deflate_state *s; |
||||
; IPos cur_match; /* current match */ |
||||
.code |
||||
longest_match PROC |
||||
|
||||
|
||||
;LocalVarsSize equ 88 |
||||
LocalVarsSize equ 72 |
||||
|
||||
; register used : rax,rbx,rcx,rdx,rsi,rdi,r8,r9,r10,r11,r12 |
||||
; free register : r14,r15 |
||||
; register can be saved : rsp |
||||
|
||||
chainlenwmask equ rsp + 8 - LocalVarsSize ; high word: current chain len |
||||
; low word: s->wmask |
||||
;window equ rsp + xx - LocalVarsSize ; local copy of s->window ; stored in r10 |
||||
;windowbestlen equ rsp + xx - LocalVarsSize ; s->window + bestlen , use r10+r11 |
||||
;scanstart equ rsp + xx - LocalVarsSize ; first two bytes of string ; stored in r12w |
||||
;scanend equ rsp + xx - LocalVarsSize ; last two bytes of string use ebx |
||||
;scanalign equ rsp + xx - LocalVarsSize ; dword-misalignment of string r13 |
||||
;bestlen equ rsp + xx - LocalVarsSize ; size of best match so far -> r11d |
||||
;scan equ rsp + xx - LocalVarsSize ; ptr to string wanting match -> r9 |
||||
nicematch equ rsp + 16 - LocalVarsSize ; a good enough match size -> r14 |
||||
|
||||
save_rdi equ rsp + 24 - LocalVarsSize |
||||
save_rsi equ rsp + 32 - LocalVarsSize |
||||
save_rbx equ rsp + 40 - LocalVarsSize |
||||
save_rbp equ rsp + 48 - LocalVarsSize |
||||
save_r12 equ rsp + 56 - LocalVarsSize |
||||
save_r13 equ rsp + 64 - LocalVarsSize |
||||
;save_r14 equ rsp + 72 - LocalVarsSize |
||||
;save_r15 equ rsp + 80 - LocalVarsSize |
||||
|
||||
|
||||
|
||||
; all the +4 offsets are due to the addition of pending_buf_size (in zlib |
||||
; in the deflate_state structure since the asm code was first written |
||||
; (if you compile with zlib 1.0.4 or older, remove the +4). |
||||
; Note : these value are good with a 8 bytes boundary pack structure |
||||
|
||||
|
||||
MAX_MATCH equ 258 |
||||
MIN_MATCH equ 3 |
||||
MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1) |
||||
|
||||
|
||||
;;; Offsets for fields in the deflate_state structure. These numbers |
||||
;;; are calculated from the definition of deflate_state, with the |
||||
;;; assumption that the compiler will dword-align the fields. (Thus, |
||||
;;; changing the definition of deflate_state could easily cause this |
||||
;;; program to crash horribly, without so much as a warning at |
||||
;;; compile time. Sigh.) |
||||
|
||||
; all the +zlib1222add offsets are due to the addition of fields |
||||
; in zlib in the deflate_state structure since the asm code was first written |
||||
; (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)"). |
||||
; (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0"). |
||||
; if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8"). |
||||
|
||||
zlib1222add equ 8 |
||||
|
||||
dsWSize equ 56+zlib1222add+(zlib1222add/2) |
||||
dsWMask equ 64+zlib1222add+(zlib1222add/2) |
||||
dsWindow equ 72+zlib1222add |
||||
dsPrev equ 88+zlib1222add |
||||
dsMatchLen equ 128+zlib1222add |
||||
dsPrevMatch equ 132+zlib1222add |
||||
dsStrStart equ 140+zlib1222add |
||||
dsMatchStart equ 144+zlib1222add |
||||
dsLookahead equ 148+zlib1222add |
||||
dsPrevLen equ 152+zlib1222add |
||||
dsMaxChainLen equ 156+zlib1222add |
||||
dsGoodMatch equ 172+zlib1222add |
||||
dsNiceMatch equ 176+zlib1222add |
||||
|
||||
|
||||
; parameter 1 in r8(deflate state s), param 2 in rdx (cur match) |
||||
|
||||
; see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and |
||||
; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp |
||||
; |
||||
; All registers must be preserved across the call, except for |
||||
; rax, rcx, rdx, r8, r-9, r10, and r11, which are scratch. |
||||
|
||||
|
||||
|
||||
;;; Save registers that the compiler may be using, and adjust esp to |
||||
;;; make room for our stack frame. |
||||
|
||||
|
||||
;;; Retrieve the function arguments. r8d will hold cur_match |
||||
;;; throughout the entire function. edx will hold the pointer to the |
||||
;;; deflate_state structure during the function's setup (before |
||||
;;; entering the main loop. |
||||
|
||||
; parameter 1 in rcx (deflate_state* s), param 2 in edx -> r8 (cur match) |
||||
|
||||
; this clear high 32 bits of r8, which can be garbage in both r8 and rdx |
||||
|
||||
|
||||
mov [save_rdi],rdi |
||||
mov [save_rsi],rsi |
||||
mov [save_rbx],rbx |
||||
mov [save_rbp],rbp |
||||
mov r8d,edx |
||||
mov [save_r12],r12 |
||||
mov [save_r13],r13 |
||||
; mov [save_r14],r14 |
||||
; mov [save_r15],r15 |
||||
|
||||
|
||||
;;; uInt wmask = s->w_mask; |
||||
;;; unsigned chain_length = s->max_chain_length; |
||||
;;; if (s->prev_length >= s->good_match) { |
||||
;;; chain_length >>= 2; |
||||
;;; } |
||||
|
||||
mov edi, [rcx + dsPrevLen] |
||||
mov esi, [rcx + dsGoodMatch] |
||||
mov eax, [rcx + dsWMask] |
||||
mov ebx, [rcx + dsMaxChainLen] |
||||
cmp edi, esi |
||||
jl LastMatchGood |
||||
shr ebx, 2 |
||||
LastMatchGood: |
||||
|
||||
;;; chainlen is decremented once beforehand so that the function can |
||||
;;; use the sign flag instead of the zero flag for the exit test. |
||||
;;; It is then shifted into the high word, to make room for the wmask |
||||
;;; value, which it will always accompany. |
||||
|
||||
dec ebx |
||||
shl ebx, 16 |
||||
or ebx, eax |
||||
mov [chainlenwmask], ebx |
||||
|
||||
;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; |
||||
|
||||
mov eax, [rcx + dsNiceMatch] |
||||
mov r10d, [rcx + dsLookahead] |
||||
cmp r10d, eax |
||||
cmovnl r10d, eax |
||||
mov [nicematch],r10d |
||||
LookaheadLess: |
||||
|
||||
;;; register Bytef *scan = s->window + s->strstart; |
||||
|
||||
mov r10, [rcx + dsWindow] |
||||
mov ebp, [rcx + dsStrStart] |
||||
lea r13, [r10 + rbp] |
||||
|
||||
;;; Determine how many bytes the scan ptr is off from being |
||||
;;; dword-aligned. |
||||
|
||||
mov r9,r13 |
||||
neg r13 |
||||
and r13,3 |
||||
|
||||
;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ? |
||||
;;; s->strstart - (IPos)MAX_DIST(s) : NIL; |
||||
|
||||
mov eax, [rcx + dsWSize] |
||||
sub eax, MIN_LOOKAHEAD |
||||
xor edi,edi |
||||
sub ebp, eax |
||||
|
||||
mov r11d, [rcx + dsPrevLen] |
||||
|
||||
cmovng ebp,edi |
||||
|
||||
;;; int best_len = s->prev_length; |
||||
|
||||
|
||||
;;; Store the sum of s->window + best_len in esi locally, and in esi. |
||||
|
||||
lea rsi,[r10+r11] |
||||
|
||||
;;; register ush scan_start = *(ushf*)scan; |
||||
;;; register ush scan_end = *(ushf*)(scan+best_len-1); |
||||
;;; Posf *prev = s->prev; |
||||
|
||||
movzx r12d,word ptr [r9] |
||||
movzx ebx, word ptr [r9 + r11 - 1] |
||||
mov rdi, [rcx + dsPrev] |
||||
|
||||
;;; Jump into the main loop. |
||||
|
||||
mov edx, [chainlenwmask] |
||||
|
||||
cmp bx,word ptr [rsi + r8 - 1] |
||||
jz LookupLoopIsZero |
||||
|
||||
LookupLoop1: |
||||
and r8d, edx |
||||
|
||||
movzx r8d, word ptr [rdi + r8*2] |
||||
cmp r8d, ebp |
||||
jbe LeaveNow |
||||
sub edx, 00010000h |
||||
js LeaveNow |
||||
|
||||
LoopEntry1: |
||||
cmp bx,word ptr [rsi + r8 - 1] |
||||
jz LookupLoopIsZero |
||||
|
||||
LookupLoop2: |
||||
and r8d, edx |
||||
|
||||
movzx r8d, word ptr [rdi + r8*2] |
||||
cmp r8d, ebp |
||||
jbe LeaveNow |
||||
sub edx, 00010000h |
||||
js LeaveNow |
||||
|
||||
LoopEntry2: |
||||
cmp bx,word ptr [rsi + r8 - 1] |
||||
jz LookupLoopIsZero |
||||
|
||||
LookupLoop4: |
||||
and r8d, edx |
||||
|
||||
movzx r8d, word ptr [rdi + r8*2] |
||||
cmp r8d, ebp |
||||
jbe LeaveNow |
||||
sub edx, 00010000h |
||||
js LeaveNow |
||||
|
||||
LoopEntry4: |
||||
|
||||
cmp bx,word ptr [rsi + r8 - 1] |
||||
jnz LookupLoop1 |
||||
jmp LookupLoopIsZero |
||||
|
||||
|
||||
;;; do { |
||||
;;; match = s->window + cur_match; |
||||
;;; if (*(ushf*)(match+best_len-1) != scan_end || |
||||
;;; *(ushf*)match != scan_start) continue; |
||||
;;; [...] |
||||
;;; } while ((cur_match = prev[cur_match & wmask]) > limit |
||||
;;; && --chain_length != 0); |
||||
;;; |
||||
;;; Here is the inner loop of the function. The function will spend the |
||||
;;; majority of its time in this loop, and majority of that time will |
||||
;;; be spent in the first ten instructions. |
||||
;;; |
||||
;;; Within this loop: |
||||
;;; ebx = scanend |
||||
;;; r8d = curmatch |
||||
;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask) |
||||
;;; esi = windowbestlen - i.e., (window + bestlen) |
||||
;;; edi = prev |
||||
;;; ebp = limit |
||||
|
||||
LookupLoop: |
||||
and r8d, edx |
||||
|
||||
movzx r8d, word ptr [rdi + r8*2] |
||||
cmp r8d, ebp |
||||
jbe LeaveNow |
||||
sub edx, 00010000h |
||||
js LeaveNow |
||||
|
||||
LoopEntry: |
||||
|
||||
cmp bx,word ptr [rsi + r8 - 1] |
||||
jnz LookupLoop1 |
||||
LookupLoopIsZero: |
||||
cmp r12w, word ptr [r10 + r8] |
||||
jnz LookupLoop1 |
||||
|
||||
|
||||
;;; Store the current value of chainlen. |
||||
mov [chainlenwmask], edx |
||||
|
||||
;;; Point edi to the string under scrutiny, and esi to the string we |
||||
;;; are hoping to match it up with. In actuality, esi and edi are |
||||
;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is |
||||
;;; initialized to -(MAX_MATCH_8 - scanalign). |
||||
|
||||
lea rsi,[r8+r10] |
||||
mov rdx, 0fffffffffffffef8h; -(MAX_MATCH_8) |
||||
lea rsi, [rsi + r13 + 0108h] ;MAX_MATCH_8] |
||||
lea rdi, [r9 + r13 + 0108h] ;MAX_MATCH_8] |
||||
|
||||
prefetcht1 [rsi+rdx] |
||||
prefetcht1 [rdi+rdx] |
||||
;;; Test the strings for equality, 8 bytes at a time. At the end, |
||||
;;; adjust edx so that it is offset to the exact byte that mismatched. |
||||
;;; |
||||
;;; We already know at this point that the first three bytes of the |
||||
;;; strings match each other, and they can be safely passed over before |
||||
;;; starting the compare loop. So what this code does is skip over 0-3 |
||||
;;; bytes, as much as necessary in order to dword-align the edi |
||||
;;; pointer. (esi will still be misaligned three times out of four.) |
||||
;;; |
||||
;;; It should be confessed that this loop usually does not represent |
||||
;;; much of the total running time. Replacing it with a more |
||||
;;; straightforward "rep cmpsb" would not drastically degrade |
||||
;;; performance. |
||||
|
||||
;LoopCmps: |
||||
; mov eax, [rsi + rdx] |
||||
; xor eax, [rdi + rdx] |
||||
; jnz LeaveLoopCmps |
||||
; mov eax, [rsi + rdx + 4] |
||||
; xor eax, [rdi + rdx + 4] |
||||
; jnz LeaveLoopCmps4 |
||||
; add rdx, 8 |
||||
; jnz LoopCmps |
||||
; jmp LenMaximum |
||||
;LeaveLoopCmps4: add rdx, 4 |
||||
;LeaveLoopCmps: test eax, 0000FFFFh |
||||
; jnz LenLower |
||||
; add rdx, 2 |
||||
; shr eax, 16 |
||||
;LenLower: sub al, 1 |
||||
; adc rdx, 0 |
||||
|
||||
|
||||
LoopCmps: |
||||
mov rax, [rsi + rdx] |
||||
xor rax, [rdi + rdx] |
||||
jnz LeaveLoopCmps |
||||
|
||||
mov rax, [rsi + rdx + 8] |
||||
xor rax, [rdi + rdx + 8] |
||||
jnz LeaveLoopCmps8 |
||||
|
||||
|
||||
mov rax, [rsi + rdx + 8+8] |
||||
xor rax, [rdi + rdx + 8+8] |
||||
jnz LeaveLoopCmps16 |
||||
|
||||
add rdx,8+8+8 |
||||
|
||||
jmp short LoopCmps |
||||
LeaveLoopCmps16: add rdx,8 |
||||
LeaveLoopCmps8: add rdx,8 |
||||
LeaveLoopCmps: |
||||
|
||||
test eax, 0000FFFFh |
||||
jnz LenLower |
||||
|
||||
test eax,0ffffffffh |
||||
|
||||
jnz LenLower32 |
||||
|
||||
add rdx,4 |
||||
shr rax,32 |
||||
or ax,ax |
||||
jnz LenLower |
||||
|
||||
LenLower32: |
||||
shr eax,16 |
||||
add rdx,2 |
||||
LenLower: sub al, 1 |
||||
adc rdx, 0 |
||||
;;; Calculate the length of the match. If it is longer than MAX_MATCH, |
||||
;;; then automatically accept it as the best possible match and leave. |
||||
|
||||
lea rax, [rdi + rdx] |
||||
sub rax, r9 |
||||
cmp eax, MAX_MATCH |
||||
jge LenMaximum |
||||
|
||||
;;; If the length of the match is not longer than the best match we |
||||
;;; have so far, then forget it and return to the lookup loop. |
||||
;/////////////////////////////////// |
||||
|
||||
cmp eax, r11d |
||||
jg LongerMatch |
||||
|
||||
lea rsi,[r10+r11] |
||||
|
||||
mov rdi, [rcx + dsPrev] |
||||
mov edx, [chainlenwmask] |
||||
jmp LookupLoop |
||||
|
||||
;;; s->match_start = cur_match; |
||||
;;; best_len = len; |
||||
;;; if (len >= nice_match) break; |
||||
;;; scan_end = *(ushf*)(scan+best_len-1); |
||||
|
||||
LongerMatch: |
||||
mov r11d, eax |
||||
mov [rcx + dsMatchStart], r8d |
||||
cmp eax, [nicematch] |
||||
jge LeaveNow |
||||
|
||||
lea rsi,[r10+rax] |
||||
|
||||
movzx ebx, word ptr [r9 + rax - 1] |
||||
mov rdi, [rcx + dsPrev] |
||||
mov edx, [chainlenwmask] |
||||
jmp LookupLoop |
||||
|
||||
;;; Accept the current string, with the maximum possible length. |
||||
|
||||
LenMaximum: |
||||
mov r11d,MAX_MATCH |
||||
mov [rcx + dsMatchStart], r8d |
||||
|
||||
;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len; |
||||
;;; return s->lookahead; |
||||
|
||||
LeaveNow: |
||||
mov eax, [rcx + dsLookahead] |
||||
cmp r11d, eax |
||||
cmovng eax, r11d |
||||
|
||||
|
||||
;;; Restore the stack and return from whence we came. |
||||
|
||||
|
||||
mov rsi,[save_rsi] |
||||
mov rdi,[save_rdi] |
||||
mov rbx,[save_rbx] |
||||
mov rbp,[save_rbp] |
||||
mov r12,[save_r12] |
||||
mov r13,[save_r13] |
||||
; mov r14,[save_r14] |
||||
; mov r15,[save_r15] |
||||
|
||||
|
||||
ret 0 |
||||
; please don't remove this string ! |
||||
; Your can freely use gvmat32 in any free or commercial app if you don't remove the string in the binary! |
||||
db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998, converted to amd 64 by Gilles Vollant 2005",0dh,0ah,0 |
||||
longest_match ENDP |
||||
|
||||
match_init PROC |
||||
ret 0 |
||||
match_init ENDP |
||||
|
||||
|
||||
END |
Binary file not shown.
@ -0,0 +1,186 @@ |
||||
/* inffas8664.c is a hand tuned assembler version of inffast.c - fast decoding
|
||||
* version for AMD64 on Windows using Microsoft C compiler |
||||
* |
||||
* Copyright (C) 1995-2003 Mark Adler |
||||
* For conditions of distribution and use, see copyright notice in zlib.h |
||||
* |
||||
* Copyright (C) 2003 Chris Anderson <christop@charm.net> |
||||
* Please use the copyright conditions above. |
||||
* |
||||
* 2005 - Adaptation to Microsoft C Compiler for AMD64 by Gilles Vollant |
||||
* |
||||
* inffas8664.c call function inffas8664fnc in inffasx64.asm |
||||
* inffasx64.asm is automatically convert from AMD64 portion of inffas86.c |
||||
* |
||||
* Dec-29-2003 -- I added AMD64 inflate asm support. This version is also |
||||
* slightly quicker on x86 systems because, instead of using rep movsb to copy |
||||
* data, it uses rep movsw, which moves data in 2-byte chunks instead of single |
||||
* bytes. I've tested the AMD64 code on a Fedora Core 1 + the x86_64 updates |
||||
* from http://fedora.linux.duke.edu/fc1_x86_64
|
||||
* which is running on an Athlon 64 3000+ / Gigabyte GA-K8VT800M system with |
||||
* 1GB ram. The 64-bit version is about 4% faster than the 32-bit version, |
||||
* when decompressing mozilla-source-1.3.tar.gz. |
||||
* |
||||
* Mar-13-2003 -- Most of this is derived from inffast.S which is derived from |
||||
* the gcc -S output of zlib-1.2.0/inffast.c. Zlib-1.2.0 is in beta release at |
||||
* the moment. I have successfully compiled and tested this code with gcc2.96, |
||||
* gcc3.2, icc5.0, msvc6.0. It is very close to the speed of inffast.S |
||||
* compiled with gcc -DNO_MMX, but inffast.S is still faster on the P3 with MMX |
||||
* enabled. I will attempt to merge the MMX code into this version. Newer |
||||
* versions of this and inffast.S can be found at |
||||
* http://www.eetbeetee.com/zlib/ and http://www.charm.net/~christop/zlib/
|
||||
* |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include "zutil.h" |
||||
#include "inftrees.h" |
||||
#include "inflate.h" |
||||
#include "inffast.h" |
||||
|
||||
/* Mark Adler's comments from inffast.c: */ |
||||
|
||||
/*
|
||||
Decode literal, length, and distance codes and write out the resulting |
||||
literal and match bytes until either not enough input or output is |
||||
available, an end-of-block is encountered, or a data error is encountered. |
||||
When large enough input and output buffers are supplied to inflate(), for |
||||
example, a 16K input buffer and a 64K output buffer, more than 95% of the |
||||
inflate execution time is spent in this routine. |
||||
|
||||
Entry assumptions: |
||||
|
||||
state->mode == LEN |
||||
strm->avail_in >= 6 |
||||
strm->avail_out >= 258 |
||||
start >= strm->avail_out |
||||
state->bits < 8 |
||||
|
||||
On return, state->mode is one of: |
||||
|
||||
LEN -- ran out of enough output space or enough available input |
||||
TYPE -- reached end of block code, inflate() to interpret next block |
||||
BAD -- error in block data |
||||
|
||||
Notes: |
||||
|
||||
- The maximum input bits used by a length/distance pair is 15 bits for the |
||||
length code, 5 bits for the length extra, 15 bits for the distance code, |
||||
and 13 bits for the distance extra. This totals 48 bits, or six bytes. |
||||
Therefore if strm->avail_in >= 6, then there is enough input to avoid |
||||
checking for available input while decoding. |
||||
|
||||
- The maximum bytes that a single length/distance pair can output is 258 |
||||
bytes, which is the maximum length that can be coded. inflate_fast() |
||||
requires strm->avail_out >= 258 for each loop to avoid checking for |
||||
output space. |
||||
*/ |
||||
|
||||
|
||||
|
||||
typedef struct inffast_ar { |
||||
/* 64 32 x86 x86_64 */ |
||||
/* ar offset register */ |
||||
/* 0 0 */ void *esp; /* esp save */ |
||||
/* 8 4 */ void *ebp; /* ebp save */ |
||||
/* 16 8 */ unsigned char FAR *in; /* esi rsi local strm->next_in */ |
||||
/* 24 12 */ unsigned char FAR *last; /* r9 while in < last */ |
||||
/* 32 16 */ unsigned char FAR *out; /* edi rdi local strm->next_out */ |
||||
/* 40 20 */ unsigned char FAR *beg; /* inflate()'s init next_out */ |
||||
/* 48 24 */ unsigned char FAR *end; /* r10 while out < end */ |
||||
/* 56 28 */ unsigned char FAR *window;/* size of window, wsize!=0 */ |
||||
/* 64 32 */ code const FAR *lcode; /* ebp rbp local strm->lencode */ |
||||
/* 72 36 */ code const FAR *dcode; /* r11 local strm->distcode */ |
||||
/* 80 40 */ size_t /*unsigned long */hold; /* edx rdx local strm->hold */ |
||||
/* 88 44 */ unsigned bits; /* ebx rbx local strm->bits */ |
||||
/* 92 48 */ unsigned wsize; /* window size */ |
||||
/* 96 52 */ unsigned write; /* window write index */ |
||||
/*100 56 */ unsigned lmask; /* r12 mask for lcode */ |
||||
/*104 60 */ unsigned dmask; /* r13 mask for dcode */ |
||||
/*108 64 */ unsigned len; /* r14 match length */ |
||||
/*112 68 */ unsigned dist; /* r15 match distance */ |
||||
/*116 72 */ unsigned status; /* set when state chng*/ |
||||
} type_ar; |
||||
#ifdef ASMINF |
||||
|
||||
void inflate_fast(strm, start) |
||||
z_streamp strm; |
||||
unsigned start; /* inflate()'s starting value for strm->avail_out */ |
||||
{ |
||||
struct inflate_state FAR *state; |
||||
type_ar ar; |
||||
void inffas8664fnc(struct inffast_ar * par); |
||||
|
||||
|
||||
|
||||
#if (defined( __GNUC__ ) && defined( __amd64__ ) && ! defined( __i386 )) || (defined(_MSC_VER) && defined(_M_AMD64)) |
||||
#define PAD_AVAIL_IN 6 |
||||
#define PAD_AVAIL_OUT 258 |
||||
#else |
||||
#define PAD_AVAIL_IN 5 |
||||
#define PAD_AVAIL_OUT 257 |
||||
#endif |
||||
|
||||
/* copy state to local variables */ |
||||
state = (struct inflate_state FAR *)strm->state; |
||||
|
||||
ar.in = strm->next_in; |
||||
ar.last = ar.in + (strm->avail_in - PAD_AVAIL_IN); |
||||
ar.out = strm->next_out; |
||||
ar.beg = ar.out - (start - strm->avail_out); |
||||
ar.end = ar.out + (strm->avail_out - PAD_AVAIL_OUT); |
||||
ar.wsize = state->wsize; |
||||
ar.write = state->write; |
||||
ar.window = state->window; |
||||
ar.hold = state->hold; |
||||
ar.bits = state->bits; |
||||
ar.lcode = state->lencode; |
||||
ar.dcode = state->distcode; |
||||
ar.lmask = (1U << state->lenbits) - 1; |
||||
ar.dmask = (1U << state->distbits) - 1; |
||||
|
||||
/* decode literals and length/distances until end-of-block or not enough
|
||||
input data or output space */ |
||||
|
||||
/* align in on 1/2 hold size boundary */ |
||||
while (((size_t)(void *)ar.in & (sizeof(ar.hold) / 2 - 1)) != 0) { |
||||
ar.hold += (unsigned long)*ar.in++ << ar.bits; |
||||
ar.bits += 8; |
||||
} |
||||
|
||||
inffas8664fnc(&ar); |
||||
|
||||
if (ar.status > 1) { |
||||
if (ar.status == 2) |
||||
strm->msg = "invalid literal/length code"; |
||||
else if (ar.status == 3) |
||||
strm->msg = "invalid distance code"; |
||||
else |
||||
strm->msg = "invalid distance too far back"; |
||||
state->mode = BAD; |
||||
} |
||||
else if ( ar.status == 1 ) { |
||||
state->mode = TYPE; |
||||
} |
||||
|
||||
/* return unused bytes (on entry, bits < 8, so in won't go too far back) */ |
||||
ar.len = ar.bits >> 3; |
||||
ar.in -= ar.len; |
||||
ar.bits -= ar.len << 3; |
||||
ar.hold &= (1U << ar.bits) - 1; |
||||
|
||||
/* update state and return */ |
||||
strm->next_in = ar.in; |
||||
strm->next_out = ar.out; |
||||
strm->avail_in = (unsigned)(ar.in < ar.last ? |
||||
PAD_AVAIL_IN + (ar.last - ar.in) : |
||||
PAD_AVAIL_IN - (ar.in - ar.last)); |
||||
strm->avail_out = (unsigned)(ar.out < ar.end ? |
||||
PAD_AVAIL_OUT + (ar.end - ar.out) : |
||||
PAD_AVAIL_OUT - (ar.out - ar.end)); |
||||
state->hold = (unsigned long)ar.hold; |
||||
state->bits = ar.bits; |
||||
return; |
||||
} |
||||
|
||||
#endif |
@ -0,0 +1,392 @@ |
||||
; inffasx64.asm is a hand tuned assembler version of inffast.c - fast decoding |
||||
; version for AMD64 on Windows using Microsoft C compiler |
||||
; |
||||
; inffasx64.asm is automatically convert from AMD64 portion of inffas86.c |
||||
; inffasx64.asm is called by inffas8664.c, which contain more info. |
||||
|
||||
|
||||
; to compile this file, I use option |
||||
; ml64.exe /Flinffasx64 /c /Zi inffasx64.asm |
||||
; with Microsoft Macro Assembler (x64) for AMD64 |
||||
; |
||||
; ml64.exe is given with Visual Studio 2005, Windows 2003 server DDK |
||||
; |
||||
; (you can get Windows 2003 server DDK with ml64 and cl.exe for AMD64 from |
||||
; http://www.microsoft.com/whdc/devtools/ddk/default.mspx for low price) |
||||
; |
||||
|
||||
.code |
||||
inffas8664fnc PROC |
||||
|
||||
; see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and |
||||
; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp |
||||
; |
||||
; All registers must be preserved across the call, except for |
||||
; rax, rcx, rdx, r8, r-9, r10, and r11, which are scratch. |
||||
|
||||
|
||||
mov [rsp-8],rsi |
||||
mov [rsp-16],rdi |
||||
mov [rsp-24],r12 |
||||
mov [rsp-32],r13 |
||||
mov [rsp-40],r14 |
||||
mov [rsp-48],r15 |
||||
mov [rsp-56],rbx |
||||
|
||||
mov rax,rcx |
||||
|
||||
mov [rax+8], rbp ; /* save regs rbp and rsp */ |
||||
mov [rax], rsp |
||||
|
||||
mov rsp, rax ; /* make rsp point to &ar */ |
||||
|
||||
mov rsi, [rsp+16] ; /* rsi = in */ |
||||
mov rdi, [rsp+32] ; /* rdi = out */ |
||||
mov r9, [rsp+24] ; /* r9 = last */ |
||||
mov r10, [rsp+48] ; /* r10 = end */ |
||||
mov rbp, [rsp+64] ; /* rbp = lcode */ |
||||
mov r11, [rsp+72] ; /* r11 = dcode */ |
||||
mov rdx, [rsp+80] ; /* rdx = hold */ |
||||
mov ebx, [rsp+88] ; /* ebx = bits */ |
||||
mov r12d, [rsp+100] ; /* r12d = lmask */ |
||||
mov r13d, [rsp+104] ; /* r13d = dmask */ |
||||
; /* r14d = len */ |
||||
; /* r15d = dist */ |
||||
|
||||
|
||||
cld |
||||
cmp r10, rdi |
||||
je L_one_time ; /* if only one decode left */ |
||||
cmp r9, rsi |
||||
|
||||
jne L_do_loop |
||||
|
||||
|
||||
L_one_time: |
||||
mov r8, r12 ; /* r8 = lmask */ |
||||
cmp bl, 32 |
||||
ja L_get_length_code_one_time |
||||
|
||||
lodsd ; /* eax = *(uint *)in++ */ |
||||
mov cl, bl ; /* cl = bits, needs it for shifting */ |
||||
add bl, 32 ; /* bits += 32 */ |
||||
shl rax, cl |
||||
or rdx, rax ; /* hold |= *((uint *)in)++ << bits */ |
||||
jmp L_get_length_code_one_time |
||||
|
||||
ALIGN 4 |
||||
L_while_test: |
||||
cmp r10, rdi |
||||
jbe L_break_loop |
||||
cmp r9, rsi |
||||
jbe L_break_loop |
||||
|
||||
L_do_loop: |
||||
mov r8, r12 ; /* r8 = lmask */ |
||||
cmp bl, 32 |
||||
ja L_get_length_code ; /* if (32 < bits) */ |
||||
|
||||
lodsd ; /* eax = *(uint *)in++ */ |
||||
mov cl, bl ; /* cl = bits, needs it for shifting */ |
||||
add bl, 32 ; /* bits += 32 */ |
||||
shl rax, cl |
||||
or rdx, rax ; /* hold |= *((uint *)in)++ << bits */ |
||||
|
||||
L_get_length_code: |
||||
and r8, rdx ; /* r8 &= hold */ |
||||
mov eax, [rbp+r8*4] ; /* eax = lcode[hold & lmask] */ |
||||
|
||||
mov cl, ah ; /* cl = this.bits */ |
||||
sub bl, ah ; /* bits -= this.bits */ |
||||
shr rdx, cl ; /* hold >>= this.bits */ |
||||
|
||||
test al, al |
||||
jnz L_test_for_length_base ; /* if (op != 0) 45.7% */ |
||||
|
||||
mov r8, r12 ; /* r8 = lmask */ |
||||
shr eax, 16 ; /* output this.val char */ |
||||
stosb |
||||
|
||||
L_get_length_code_one_time: |
||||
and r8, rdx ; /* r8 &= hold */ |
||||
mov eax, [rbp+r8*4] ; /* eax = lcode[hold & lmask] */ |
||||
|
||||
L_dolen: |
||||
mov cl, ah ; /* cl = this.bits */ |
||||
sub bl, ah ; /* bits -= this.bits */ |
||||
shr rdx, cl ; /* hold >>= this.bits */ |
||||
|
||||
test al, al |
||||
jnz L_test_for_length_base ; /* if (op != 0) 45.7% */ |
||||
|
||||
shr eax, 16 ; /* output this.val char */ |
||||
stosb |
||||
jmp L_while_test |
||||
|
||||
ALIGN 4 |
||||
L_test_for_length_base: |
||||
mov r14d, eax ; /* len = this */ |
||||
shr r14d, 16 ; /* len = this.val */ |
||||
mov cl, al |
||||
|
||||
test al, 16 |
||||
jz L_test_for_second_level_length ; /* if ((op & 16) == 0) 8% */ |
||||
and cl, 15 ; /* op &= 15 */ |
||||
jz L_decode_distance ; /* if (!op) */ |
||||
|
||||
L_add_bits_to_len: |
||||
sub bl, cl |
||||
xor eax, eax |
||||
inc eax |
||||
shl eax, cl |
||||
dec eax |
||||
and eax, edx ; /* eax &= hold */ |
||||
shr rdx, cl |
||||
add r14d, eax ; /* len += hold & mask[op] */ |
||||
|
||||
L_decode_distance: |
||||
mov r8, r13 ; /* r8 = dmask */ |
||||
cmp bl, 32 |
||||
ja L_get_distance_code ; /* if (32 < bits) */ |
||||
|
||||
lodsd ; /* eax = *(uint *)in++ */ |
||||
mov cl, bl ; /* cl = bits, needs it for shifting */ |
||||
add bl, 32 ; /* bits += 32 */ |
||||
shl rax, cl |
||||
or rdx, rax ; /* hold |= *((uint *)in)++ << bits */ |
||||
|
||||
L_get_distance_code: |
||||
and r8, rdx ; /* r8 &= hold */ |
||||
mov eax, [r11+r8*4] ; /* eax = dcode[hold & dmask] */ |
||||
|
||||
L_dodist: |
||||
mov r15d, eax ; /* dist = this */ |
||||
shr r15d, 16 ; /* dist = this.val */ |
||||
mov cl, ah |
||||
sub bl, ah ; /* bits -= this.bits */ |
||||
shr rdx, cl ; /* hold >>= this.bits */ |
||||
mov cl, al ; /* cl = this.op */ |
||||
|
||||
test al, 16 ; /* if ((op & 16) == 0) */ |
||||
jz L_test_for_second_level_dist |
||||
and cl, 15 ; /* op &= 15 */ |
||||
jz L_check_dist_one |
||||
|
||||
L_add_bits_to_dist: |
||||
sub bl, cl |
||||
xor eax, eax |
||||
inc eax |
||||
shl eax, cl |
||||
dec eax ; /* (1 << op) - 1 */ |
||||
and eax, edx ; /* eax &= hold */ |
||||
shr rdx, cl |
||||
add r15d, eax ; /* dist += hold & ((1 << op) - 1) */ |
||||
|
||||
L_check_window: |
||||
mov r8, rsi ; /* save in so from can use it's reg */ |
||||
mov rax, rdi |
||||
sub rax, [rsp+40] ; /* nbytes = out - beg */ |
||||
|
||||
cmp eax, r15d |
||||
jb L_clip_window ; /* if (dist > nbytes) 4.2% */ |
||||
|
||||
mov ecx, r14d ; /* ecx = len */ |
||||
mov rsi, rdi |
||||
sub rsi, r15 ; /* from = out - dist */ |
||||
|
||||
sar ecx, 1 |
||||
jnc L_copy_two ; /* if len % 2 == 0 */ |
||||
|
||||
rep movsw |
||||
mov al, [rsi] |
||||
mov [rdi], al |
||||
inc rdi |
||||
|
||||
mov rsi, r8 ; /* move in back to %rsi, toss from */ |
||||
jmp L_while_test |
||||
|
||||
L_copy_two: |
||||
rep movsw |
||||
mov rsi, r8 ; /* move in back to %rsi, toss from */ |
||||
jmp L_while_test |
||||
|
||||
ALIGN 4 |
||||
L_check_dist_one: |
||||
cmp r15d, 1 ; /* if dist 1, is a memset */ |
||||
jne L_check_window |
||||
cmp [rsp+40], rdi ; /* if out == beg, outside window */ |
||||
je L_check_window |
||||
|
||||
mov ecx, r14d ; /* ecx = len */ |
||||
mov al, [rdi-1] |
||||
mov ah, al |
||||
|
||||
sar ecx, 1 |
||||
jnc L_set_two |
||||
mov [rdi], al |
||||
inc rdi |
||||
|
||||
L_set_two: |
||||
rep stosw |
||||
jmp L_while_test |
||||
|
||||
ALIGN 4 |
||||
L_test_for_second_level_length: |
||||
test al, 64 |
||||
jnz L_test_for_end_of_block ; /* if ((op & 64) != 0) */ |
||||
|
||||
xor eax, eax |
||||
inc eax |
||||
shl eax, cl |
||||
dec eax |
||||
and eax, edx ; /* eax &= hold */ |
||||
add eax, r14d ; /* eax += len */ |
||||
mov eax, [rbp+rax*4] ; /* eax = lcode[val+(hold&mask[op])]*/ |
||||
jmp L_dolen |
||||
|
||||
ALIGN 4 |
||||
L_test_for_second_level_dist: |
||||
test al, 64 |
||||
jnz L_invalid_distance_code ; /* if ((op & 64) != 0) */ |
||||
|
||||
xor eax, eax |
||||
inc eax |
||||
shl eax, cl |
||||
dec eax |
||||
and eax, edx ; /* eax &= hold */ |
||||
add eax, r15d ; /* eax += dist */ |
||||
mov eax, [r11+rax*4] ; /* eax = dcode[val+(hold&mask[op])]*/ |
||||
jmp L_dodist |
||||
|
||||
ALIGN 4 |
||||
L_clip_window: |
||||
mov ecx, eax ; /* ecx = nbytes */ |
||||
mov eax, [rsp+92] ; /* eax = wsize, prepare for dist cmp */ |
||||
neg ecx ; /* nbytes = -nbytes */ |
||||
|
||||
cmp eax, r15d |
||||
jb L_invalid_distance_too_far ; /* if (dist > wsize) */ |
||||
|
||||
add ecx, r15d ; /* nbytes = dist - nbytes */ |
||||
cmp dword ptr [rsp+96], 0 |
||||
jne L_wrap_around_window ; /* if (write != 0) */ |
||||
|
||||
mov rsi, [rsp+56] ; /* from = window */ |
||||
sub eax, ecx ; /* eax -= nbytes */ |
||||
add rsi, rax ; /* from += wsize - nbytes */ |
||||
|
||||
mov eax, r14d ; /* eax = len */ |
||||
cmp r14d, ecx |
||||
jbe L_do_copy ; /* if (nbytes >= len) */ |
||||
|
||||
sub eax, ecx ; /* eax -= nbytes */ |
||||
rep movsb |
||||
mov rsi, rdi |
||||
sub rsi, r15 ; /* from = &out[ -dist ] */ |
||||
jmp L_do_copy |
||||
|
||||
ALIGN 4 |
||||
L_wrap_around_window: |
||||
mov eax, [rsp+96] ; /* eax = write */ |
||||
cmp ecx, eax |
||||
jbe L_contiguous_in_window ; /* if (write >= nbytes) */ |
||||
|
||||
mov esi, [rsp+92] ; /* from = wsize */ |
||||
add rsi, [rsp+56] ; /* from += window */ |
||||
add rsi, rax ; /* from += write */ |
||||
sub rsi, rcx ; /* from -= nbytes */ |
||||
sub ecx, eax ; /* nbytes -= write */ |
||||
|
||||
mov eax, r14d ; /* eax = len */ |
||||
cmp eax, ecx |
||||
jbe L_do_copy ; /* if (nbytes >= len) */ |
||||
|
||||
sub eax, ecx ; /* len -= nbytes */ |
||||
rep movsb |
||||
mov rsi, [rsp+56] ; /* from = window */ |
||||
mov ecx, [rsp+96] ; /* nbytes = write */ |
||||
cmp eax, ecx |
||||
jbe L_do_copy ; /* if (nbytes >= len) */ |
||||
|
||||
sub eax, ecx ; /* len -= nbytes */ |
||||
rep movsb |
||||
mov rsi, rdi |
||||
sub rsi, r15 ; /* from = out - dist */ |
||||
jmp L_do_copy |
||||
|
||||
ALIGN 4 |
||||
L_contiguous_in_window: |
||||
mov rsi, [rsp+56] ; /* rsi = window */ |
||||
add rsi, rax |
||||
sub rsi, rcx ; /* from += write - nbytes */ |
||||
|
||||
mov eax, r14d ; /* eax = len */ |
||||
cmp eax, ecx |
||||
jbe L_do_copy ; /* if (nbytes >= len) */ |
||||
|
||||
sub eax, ecx ; /* len -= nbytes */ |
||||
rep movsb |
||||
mov rsi, rdi |
||||
sub rsi, r15 ; /* from = out - dist */ |
||||
jmp L_do_copy ; /* if (nbytes >= len) */ |
||||
|
||||
ALIGN 4 |
||||
L_do_copy: |
||||
mov ecx, eax ; /* ecx = len */ |
||||
rep movsb |
||||
|
||||
mov rsi, r8 ; /* move in back to %esi, toss from */ |
||||
jmp L_while_test |
||||
|
||||
L_test_for_end_of_block: |
||||
test al, 32 |
||||
jz L_invalid_literal_length_code |
||||
mov dword ptr [rsp+116], 1 |
||||
jmp L_break_loop_with_status |
||||
|
||||
L_invalid_literal_length_code: |
||||
mov dword ptr [rsp+116], 2 |
||||
jmp L_break_loop_with_status |
||||
|
||||
L_invalid_distance_code: |
||||
mov dword ptr [rsp+116], 3 |
||||
jmp L_break_loop_with_status |
||||
|
||||
L_invalid_distance_too_far: |
||||
mov dword ptr [rsp+116], 4 |
||||
jmp L_break_loop_with_status |
||||
|
||||
L_break_loop: |
||||
mov dword ptr [rsp+116], 0 |
||||
|
||||
L_break_loop_with_status: |
||||
; /* put in, out, bits, and hold back into ar and pop esp */ |
||||
mov [rsp+16], rsi ; /* in */ |
||||
mov [rsp+32], rdi ; /* out */ |
||||
mov [rsp+88], ebx ; /* bits */ |
||||
mov [rsp+80], rdx ; /* hold */ |
||||
|
||||
mov rax, [rsp] ; /* restore rbp and rsp */ |
||||
mov rbp, [rsp+8] |
||||
mov rsp, rax |
||||
|
||||
|
||||
|
||||
mov rsi,[rsp-8] |
||||
mov rdi,[rsp-16] |
||||
mov r12,[rsp-24] |
||||
mov r13,[rsp-32] |
||||
mov r14,[rsp-40] |
||||
mov r15,[rsp-48] |
||||
mov rbx,[rsp-56] |
||||
|
||||
ret 0 |
||||
; : |
||||
; : "m" (ar) |
||||
; : "memory", "%rax", "%rbx", "%rcx", "%rdx", "%rsi", "%rdi", |
||||
; "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" |
||||
; ); |
||||
|
||||
inffas8664fnc ENDP |
||||
;_TEXT ENDS |
||||
END |
Binary file not shown.
@ -0,0 +1,28 @@ |
||||
Summary |
||||
------- |
||||
This directory contains ASM implementations of the functions |
||||
longest_match() and inflate_fast(), for 64 bits x86 (both AMD64 and Intel EM64t), |
||||
for use with Microsoft Macro Assembler (x64) for AMD64 and Microsoft C++ 64 bits. |
||||
|
||||
gvmat64.asm is written by Gilles Vollant (2005), by using Brian Raiter 686/32 bits |
||||
assembly optimized version from Jean-loup Gailly original longest_match function |
||||
|
||||
inffasx64.asm and inffas8664.c were written by Chris Anderson, by optimizing |
||||
original function from Mark Adler |
||||
|
||||
Use instructions |
||||
---------------- |
||||
Copy these files into the zlib source directory. |
||||
|
||||
define ASMV and ASMINF in your project. Include inffas8664.c in your source tree, |
||||
and inffasx64.obj and gvmat64.obj as object to link. |
||||
|
||||
|
||||
Build instructions |
||||
------------------ |
||||
run bld_64.bat with Microsoft Macro Assembler (x64) for AMD64 (ml64.exe) |
||||
|
||||
ml64.exe is given with Visual Studio 2005, Windows 2003 server DDK |
||||
|
||||
You can get Windows 2003 server DDK with ml64 and cl for AMD64 from |
||||
http://www.microsoft.com/whdc/devtools/ddk/default.mspx for low price) |
@ -0,0 +1,2 @@ |
||||
ml /coff /Zi /c /Flgvmat32.lst gvmat32.asm |
||||
ml /coff /Zi /c /Flinffas32.lst inffas32.asm |
@ -0,0 +1,18 @@ |
||||
; rdtsc64.asm |
||||
; |
||||
; unsigned _int64 myrdtsc(); |
||||
; |
||||
; return the performance rdtsc value, on AMD64/Intel EM64T |
||||
; |
||||
; compile with : |
||||
; ml64.exe" /Flrdtsc64 /c /Zi rdtsc64.asm |
||||
; |
||||
.code |
||||
myrdtsc PROC |
||||
rdtsc |
||||
shl rdx,32 |
||||
or rax,rdx |
||||
ret |
||||
myrdtsc ENDP |
||||
|
||||
END |
Binary file not shown.
@ -0,0 +1,10 @@ |
||||
To build testzLib with Visual Studio 2005: |
||||
|
||||
copy to a directory file from : |
||||
- root of zLib tree |
||||
- contrib/testzlib |
||||
- contrib/masmx86 |
||||
- contrib/masmx64 |
||||
- contrib/vstudio/vc7 |
||||
|
||||
and open testzlib8.sln |
@ -0,0 +1,638 @@ |
||||
<?xml version="1.0" encoding="Windows-1252"?> |
||||
<VisualStudioProject |
||||
ProjectType="Visual C++" |
||||
Version="8,00" |
||||
Name="testzlib8" |
||||
ProjectGUID="{AA6666AA-E09F-4135-9C0C-4FE50C3C654B}" |
||||
Keyword="Win32Proj" |
||||
> |
||||
<Platforms> |
||||
<Platform |
||||
Name="Win32" |
||||
/> |
||||
<Platform |
||||
Name="Win64 (AMD64)" |
||||
/> |
||||
</Platforms> |
||||
<ToolFiles> |
||||
<DefaultToolFile |
||||
FileName="masm.tool" |
||||
/> |
||||
</ToolFiles> |
||||
<Configurations> |
||||
<Configuration |
||||
Name="Debug|Win32" |
||||
OutputDirectory="x86\$(ConfigurationName)" |
||||
IntermediateDirectory="x86\$(ConfigurationName)" |
||||
ConfigurationType="1" |
||||
CharacterSet="2" |
||||
> |
||||
<Tool |
||||
Name="VCPreBuildEventTool" |
||||
/> |
||||
<Tool |
||||
Name="VCCustomBuildTool" |
||||
/> |
||||
<Tool |
||||
Name="MASM" |
||||
/> |
||||
<Tool |
||||
Name="VCXMLDataGeneratorTool" |
||||
/> |
||||
<Tool |
||||
Name="VCWebServiceProxyGeneratorTool" |
||||
/> |
||||
<Tool |
||||
Name="VCMIDLTool" |
||||
/> |
||||
<Tool |
||||
Name="VCCLCompilerTool" |
||||
Optimization="0" |
||||
PreprocessorDefinitions="ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE" |
||||
MinimalRebuild="TRUE" |
||||
BasicRuntimeChecks="3" |
||||
RuntimeLibrary="1" |
||||
UsePrecompiledHeader="0" |
||||
AssemblerOutput="4" |
||||
WarningLevel="3" |
||||
Detect64BitPortabilityProblems="TRUE" |
||||
DebugInformationFormat="4" |
||||
/> |
||||
<Tool |
||||
Name="VCManagedResourceCompilerTool" |
||||
/> |
||||
<Tool |
||||
Name="VCResourceCompilerTool" |
||||
/> |
||||
<Tool |
||||
Name="VCPreLinkEventTool" |
||||
/> |
||||
<Tool |
||||
Name="VCLinkerTool" |
||||
AdditionalDependencies="gvmat32.obj inffas32.obj" |
||||
OutputFile="$(OutDir)/testzlib.exe" |
||||
LinkIncremental="2" |
||||
GenerateDebugInformation="TRUE" |
||||
ProgramDatabaseFile="$(OutDir)/testzlib.pdb" |
||||
SubSystem="1" |
||||
TargetMachine="1" |
||||
/> |
||||
<Tool |
||||
Name="VCALinkTool" |
||||
/> |
||||
<Tool |
||||
Name="VCManifestTool" |
||||
/> |
||||
<Tool |
||||
Name="VCXDCMakeTool" |
||||
/> |
||||
<Tool |
||||
Name="VCBscMakeTool" |
||||
/> |
||||
<Tool |
||||
Name="VCAppVerifierTool" |
||||
/> |
||||
<Tool |
||||
Name="VCWebDeploymentTool" |
||||
/> |
||||
<Tool |
||||
Name="VCPostBuildEventTool" |
||||
/> |
||||
</Configuration> |
||||
<Configuration |
||||
Name="Debug|Win64 (AMD64)" |
||||
OutputDirectory="amd64\$(ConfigurationName)" |
||||
IntermediateDirectory="amd64\$(ConfigurationName)" |
||||
ConfigurationType="1" |
||||
CharacterSet="2" |
||||
> |
||||
<Tool |
||||
Name="VCPreBuildEventTool" |
||||
/> |
||||
<Tool |
||||
Name="VCCustomBuildTool" |
||||
/> |
||||
<Tool |
||||
Name="MASM" |
||||
/> |
||||
<Tool |
||||
Name="VCXMLDataGeneratorTool" |
||||
/> |
||||
<Tool |
||||
Name="VCWebServiceProxyGeneratorTool" |
||||
/> |
||||
<Tool |
||||
Name="VCMIDLTool" |
||||
TargetEnvironment="3" |
||||
/> |
||||
<Tool |
||||
Name="VCCLCompilerTool" |
||||
Optimization="0" |
||||
PreprocessorDefinitions="ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE" |
||||
MinimalRebuild="TRUE" |
||||
BasicRuntimeChecks="3" |
||||
RuntimeLibrary="1" |
||||
UsePrecompiledHeader="0" |
||||
AssemblerOutput="4" |
||||
WarningLevel="3" |
||||
Detect64BitPortabilityProblems="TRUE" |
||||
DebugInformationFormat="3" |
||||
/> |
||||
<Tool |
||||
Name="VCManagedResourceCompilerTool" |
||||
/> |
||||
<Tool |
||||
Name="VCResourceCompilerTool" |
||||
/> |
||||
<Tool |
||||
Name="VCPreLinkEventTool" |
||||
CommandLine="" |
||||
/> |
||||
<Tool |
||||
Name="VCLinkerTool" |
||||
AdditionalDependencies="gvmat64.obj inffasx64.obj rdtsc64.obj" |
||||
OutputFile="$(OutDir)/testzlib.exe" |
||||
LinkIncremental="2" |
||||
GenerateDebugInformation="TRUE" |
||||
ProgramDatabaseFile="$(OutDir)/testzlib.pdb" |
||||
SubSystem="1" |
||||
TargetMachine="17" |
||||
/> |
||||
<Tool |
||||
Name="VCALinkTool" |
||||
/> |
||||
<Tool |
||||
Name="VCManifestTool" |
||||
/> |
||||
<Tool |
||||
Name="VCXDCMakeTool" |
||||
/> |
||||
<Tool |
||||
Name="VCBscMakeTool" |
||||
/> |
||||
<Tool |
||||
Name="VCWebDeploymentTool" |
||||
/> |
||||
<Tool |
||||
Name="VCPostBuildEventTool" |
||||
/> |
||||
</Configuration> |
||||
<Configuration |
||||
Name="Release|Win32" |
||||
OutputDirectory="x86\$(ConfigurationName)" |
||||
IntermediateDirectory="x86\$(ConfigurationName)" |
||||
ConfigurationType="1" |
||||
CharacterSet="2" |
||||
> |
||||
<Tool |
||||
Name="VCPreBuildEventTool" |
||||
/> |
||||
<Tool |
||||
Name="VCCustomBuildTool" |
||||
/> |
||||
<Tool |
||||
Name="MASM" |
||||
/> |
||||
<Tool |
||||
Name="VCXMLDataGeneratorTool" |
||||
/> |
||||
<Tool |
||||
Name="VCWebServiceProxyGeneratorTool" |
||||
/> |
||||
<Tool |
||||
Name="VCMIDLTool" |
||||
/> |
||||
<Tool |
||||
Name="VCCLCompilerTool" |
||||
Optimization="2" |
||||
InlineFunctionExpansion="1" |
||||
OmitFramePointers="TRUE" |
||||
PreprocessorDefinitions="WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE" |
||||
StringPooling="TRUE" |
||||
RuntimeLibrary="0" |
||||
EnableFunctionLevelLinking="TRUE" |
||||
UsePrecompiledHeader="0" |
||||
WarningLevel="3" |
||||
Detect64BitPortabilityProblems="TRUE" |
||||
DebugInformationFormat="3" |
||||
/> |
||||
<Tool |
||||
Name="VCManagedResourceCompilerTool" |
||||
/> |
||||
<Tool |
||||
Name="VCResourceCompilerTool" |
||||
/> |
||||
<Tool |
||||
Name="VCPreLinkEventTool" |
||||
/> |
||||
<Tool |
||||
Name="VCLinkerTool" |
||||
OutputFile="$(OutDir)/testzlib.exe" |
||||
LinkIncremental="1" |
||||
GenerateDebugInformation="TRUE" |
||||
SubSystem="1" |
||||
OptimizeReferences="2" |
||||
EnableCOMDATFolding="2" |
||||
OptimizeForWindows98="1" |
||||
TargetMachine="1" |
||||
/> |
||||
<Tool |
||||
Name="VCALinkTool" |
||||
/> |
||||
<Tool |
||||
Name="VCManifestTool" |
||||
/> |
||||
<Tool |
||||
Name="VCXDCMakeTool" |
||||
/> |
||||
<Tool |
||||
Name="VCBscMakeTool" |
||||
/> |
||||
<Tool |
||||
Name="VCAppVerifierTool" |
||||
/> |
||||
<Tool |
||||
Name="VCWebDeploymentTool" |
||||
/> |
||||
<Tool |
||||
Name="VCPostBuildEventTool" |
||||
/> |
||||
</Configuration> |
||||
<Configuration |
||||
Name="Release|Win64 (AMD64)" |
||||
OutputDirectory="amd64\$(ConfigurationName)" |
||||
IntermediateDirectory="amd64\$(ConfigurationName)" |
||||
ConfigurationType="1" |
||||
CharacterSet="2" |
||||
> |
||||
<Tool |
||||
Name="VCPreBuildEventTool" |
||||
/> |
||||
<Tool |
||||
Name="VCCustomBuildTool" |
||||
/> |
||||
<Tool |
||||
Name="MASM" |
||||
/> |
||||
<Tool |
||||
Name="VCXMLDataGeneratorTool" |
||||
/> |
||||
<Tool |
||||
Name="VCWebServiceProxyGeneratorTool" |
||||
/> |
||||
<Tool |
||||
Name="VCMIDLTool" |
||||
TargetEnvironment="3" |
||||
/> |
||||
<Tool |
||||
Name="VCCLCompilerTool" |
||||
Optimization="2" |
||||
InlineFunctionExpansion="1" |
||||
OmitFramePointers="TRUE" |
||||
PreprocessorDefinitions="WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE" |
||||
StringPooling="TRUE" |
||||
RuntimeLibrary="0" |
||||
EnableFunctionLevelLinking="TRUE" |
||||
UsePrecompiledHeader="0" |
||||
WarningLevel="3" |
||||
Detect64BitPortabilityProblems="TRUE" |
||||
DebugInformationFormat="3" |
||||
/> |
||||
<Tool |
||||
Name="VCManagedResourceCompilerTool" |
||||
/> |
||||
<Tool |
||||
Name="VCResourceCompilerTool" |
||||
/> |
||||
<Tool |
||||
Name="VCPreLinkEventTool" |
||||
/> |
||||
<Tool |
||||
Name="VCLinkerTool" |
||||
AdditionalDependencies="rdtsc64.obj" |
||||
OutputFile="$(OutDir)/testzlib.exe" |
||||
LinkIncremental="1" |
||||
GenerateDebugInformation="TRUE" |
||||
SubSystem="1" |
||||
OptimizeReferences="2" |
||||
EnableCOMDATFolding="2" |
||||
OptimizeForWindows98="1" |
||||
TargetMachine="17" |
||||
/> |
||||
<Tool |
||||
Name="VCALinkTool" |
||||
/> |
||||
<Tool |
||||
Name="VCManifestTool" |
||||
/> |
||||
<Tool |
||||
Name="VCXDCMakeTool" |
||||
/> |
||||
<Tool |
||||
Name="VCBscMakeTool" |
||||
/> |
||||
<Tool |
||||
Name="VCWebDeploymentTool" |
||||
/> |
||||
<Tool |
||||
Name="VCPostBuildEventTool" |
||||
/> |
||||
</Configuration> |
||||
<Configuration |
||||
Name="ReleaseAsm|Win32" |
||||
OutputDirectory="x86\$(ConfigurationName)" |
||||
IntermediateDirectory="x86\$(ConfigurationName)" |
||||
ConfigurationType="1" |
||||
CharacterSet="2" |
||||
> |
||||
<Tool |
||||
Name="VCPreBuildEventTool" |
||||
/> |
||||
<Tool |
||||
Name="VCCustomBuildTool" |
||||
/> |
||||
<Tool |
||||
Name="MASM" |
||||
/> |
||||
<Tool |
||||
Name="VCXMLDataGeneratorTool" |
||||
/> |
||||
<Tool |
||||
Name="VCWebServiceProxyGeneratorTool" |
||||
/> |
||||
<Tool |
||||
Name="VCMIDLTool" |
||||
/> |
||||
<Tool |
||||
Name="VCCLCompilerTool" |
||||
Optimization="2" |
||||
InlineFunctionExpansion="1" |
||||
OmitFramePointers="TRUE" |
||||
PreprocessorDefinitions="ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE" |
||||
StringPooling="TRUE" |
||||
RuntimeLibrary="0" |
||||
EnableFunctionLevelLinking="TRUE" |
||||
UsePrecompiledHeader="0" |
||||
WarningLevel="3" |
||||
Detect64BitPortabilityProblems="TRUE" |
||||
DebugInformationFormat="3" |
||||
/> |
||||
<Tool |
||||
Name="VCManagedResourceCompilerTool" |
||||
/> |
||||
<Tool |
||||
Name="VCResourceCompilerTool" |
||||
/> |
||||
<Tool |
||||
Name="VCPreLinkEventTool" |
||||
/> |
||||
<Tool |
||||
Name="VCLinkerTool" |
||||
AdditionalDependencies="gvmat32.obj inffas32.obj" |
||||
OutputFile="$(OutDir)/testzlib.exe" |
||||
LinkIncremental="1" |
||||
GenerateDebugInformation="TRUE" |
||||
SubSystem="1" |
||||
OptimizeReferences="2" |
||||
EnableCOMDATFolding="2" |
||||
OptimizeForWindows98="1" |
||||
TargetMachine="1" |
||||
/> |
||||
<Tool |
||||
Name="VCALinkTool" |
||||
/> |
||||
<Tool |
||||
Name="VCManifestTool" |
||||
/> |
||||
<Tool |
||||
Name="VCXDCMakeTool" |
||||
/> |
||||
<Tool |
||||
Name="VCBscMakeTool" |
||||
/> |
||||
<Tool |
||||
Name="VCAppVerifierTool" |
||||
/> |
||||
<Tool |
||||
Name="VCWebDeploymentTool" |
||||
/> |
||||
<Tool |
||||
Name="VCPostBuildEventTool" |
||||
/> |
||||
</Configuration> |
||||
<Configuration |
||||
Name="ReleaseAsm|Win64 (AMD64)" |
||||
OutputDirectory="amd64\$(ConfigurationName)" |
||||
IntermediateDirectory="amd64\$(ConfigurationName)" |
||||
ConfigurationType="1" |
||||
CharacterSet="2" |
||||
> |
||||
<Tool |
||||
Name="VCPreBuildEventTool" |
||||
CommandLine="" |
||||
/> |
||||
<Tool |
||||
Name="VCCustomBuildTool" |
||||
/> |
||||
<Tool |
||||
Name="MASM" |
||||
/> |
||||
<Tool |
||||
Name="VCXMLDataGeneratorTool" |
||||
/> |
||||
<Tool |
||||
Name="VCWebServiceProxyGeneratorTool" |
||||
/> |
||||
<Tool |
||||
Name="VCMIDLTool" |
||||
TargetEnvironment="3" |
||||
/> |
||||
<Tool |
||||
Name="VCCLCompilerTool" |
||||
Optimization="2" |
||||
InlineFunctionExpansion="1" |
||||
OmitFramePointers="TRUE" |
||||
PreprocessorDefinitions="ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE" |
||||
StringPooling="TRUE" |
||||
RuntimeLibrary="0" |
||||
EnableFunctionLevelLinking="TRUE" |
||||
UsePrecompiledHeader="0" |
||||
AssemblerOutput="4" |
||||
WarningLevel="3" |
||||
Detect64BitPortabilityProblems="TRUE" |
||||
DebugInformationFormat="3" |
||||
/> |
||||
<Tool |
||||
Name="VCManagedResourceCompilerTool" |
||||
/> |
||||
<Tool |
||||
Name="VCResourceCompilerTool" |
||||
/> |
||||
<Tool |
||||
Name="VCPreLinkEventTool" |
||||
CommandLine="" |
||||
/> |
||||
<Tool |
||||
Name="VCLinkerTool" |
||||
AdditionalDependencies="gvmat64.obj inffasx64.obj rdtsc64.obj" |
||||
OutputFile="$(OutDir)/testzlib.exe" |
||||
LinkIncremental="1" |
||||
GenerateDebugInformation="TRUE" |
||||
SubSystem="1" |
||||
OptimizeReferences="2" |
||||
EnableCOMDATFolding="2" |
||||
OptimizeForWindows98="1" |
||||
TargetMachine="17" |
||||
/> |
||||
<Tool |
||||
Name="VCALinkTool" |
||||
/> |
||||
<Tool |
||||
Name="VCManifestTool" |
||||
/> |
||||
<Tool |
||||
Name="VCXDCMakeTool" |
||||
/> |
||||
<Tool |
||||
Name="VCBscMakeTool" |
||||
/> |
||||
<Tool |
||||
Name="VCWebDeploymentTool" |
||||
/> |
||||
<Tool |
||||
Name="VCPostBuildEventTool" |
||||
/> |
||||
</Configuration> |
||||
</Configurations> |
||||
<References> |
||||
</References> |
||||
<Files> |
||||
<Filter |
||||
Name="Source Files" |
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm" |
||||
> |
||||
<File |
||||
RelativePath=".\adler32.c" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\compress.c" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\crc32.c" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\deflate.c" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\gvmat32c.c" |
||||
> |
||||
<FileConfiguration |
||||
Name="Debug|Win64 (AMD64)" |
||||
ExcludedFromBuild="TRUE" |
||||
> |
||||
<Tool |
||||
Name="VCCLCompilerTool" |
||||
/> |
||||
</FileConfiguration> |
||||
<FileConfiguration |
||||
Name="Release|Win64 (AMD64)" |
||||
ExcludedFromBuild="TRUE" |
||||
> |
||||
<Tool |
||||
Name="VCCLCompilerTool" |
||||
/> |
||||
</FileConfiguration> |
||||
<FileConfiguration |
||||
Name="ReleaseAsm|Win32" |
||||
> |
||||
<Tool |
||||
Name="VCCLCompilerTool" |
||||
/> |
||||
</FileConfiguration> |
||||
<FileConfiguration |
||||
Name="ReleaseAsm|Win64 (AMD64)" |
||||
ExcludedFromBuild="TRUE" |
||||
> |
||||
<Tool |
||||
Name="VCCLCompilerTool" |
||||
/> |
||||
</FileConfiguration> |
||||
</File> |
||||
<File |
||||
RelativePath=".\infback.c" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\inffas8664.c" |
||||
> |
||||
<FileConfiguration |
||||
Name="Debug|Win32" |
||||
ExcludedFromBuild="TRUE" |
||||
> |
||||
<Tool |
||||
Name="VCCLCompilerTool" |
||||
/> |
||||
</FileConfiguration> |
||||
<FileConfiguration |
||||
Name="Release|Win32" |
||||
> |
||||
<Tool |
||||
Name="VCCLCompilerTool" |
||||
/> |
||||
</FileConfiguration> |
||||
<FileConfiguration |
||||
Name="ReleaseAsm|Win32" |
||||
ExcludedFromBuild="TRUE" |
||||
> |
||||
<Tool |
||||
Name="VCCLCompilerTool" |
||||
/> |
||||
</FileConfiguration> |
||||
</File> |
||||
<File |
||||
RelativePath=".\inffast.c" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\inflate.c" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\inftrees.c" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath="testzlib.c" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\trees.c" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\uncompr.c" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\zutil.c" |
||||
> |
||||
</File> |
||||
</Filter> |
||||
<Filter |
||||
Name="Header Files" |
||||
Filter="h;hpp;hxx;hm;inl;inc" |
||||
> |
||||
</Filter> |
||||
<Filter |
||||
Name="Resource Files" |
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" |
||||
> |
||||
</Filter> |
||||
</Files> |
||||
<Globals> |
||||
</Globals> |
||||
</VisualStudioProject> |
Binary file not shown.
Binary file not shown.
@ -0,0 +1,692 @@ |
||||
/* gun.c -- simple gunzip to give an example of the use of inflateBack()
|
||||
* Copyright (C) 2003, 2005 Mark Adler |
||||
* For conditions of distribution and use, see copyright notice in zlib.h |
||||
Version 1.2 20 March 2005 Mark Adler */ |
||||
|
||||
/* Version history:
|
||||
1.0 16 Feb 2003 First version for testing of inflateBack() |
||||
1.1 21 Feb 2005 Decompress concatenated gzip streams |
||||
Remove use of "this" variable (C++ keyword) |
||||
Fix return value for in() |
||||
Improve allocation failure checking |
||||
Add typecasting for void * structures |
||||
Add -h option for command version and usage |
||||
Add a bunch of comments |
||||
1.2 20 Mar 2005 Add Unix compress (LZW) decompression |
||||
Copy file attributes from input file to output file |
||||
*/ |
||||
|
||||
/*
|
||||
gun [ -t ] [ name ... ] |
||||
|
||||
decompresses the data in the named gzip files. If no arguments are given, |
||||
gun will decompress from stdin to stdout. The names must end in .gz, -gz, |
||||
.z, -z, _z, or .Z. The uncompressed data will be written to a file name |
||||
with the suffix stripped. On success, the original file is deleted. On |
||||
failure, the output file is deleted. For most failures, the command will |
||||
continue to process the remaining names on the command line. A memory |
||||
allocation failure will abort the command. If -t is specified, then the |
||||
listed files or stdin will be tested as gzip files for integrity (without |
||||
checking for a proper suffix), no output will be written, and no files |
||||
will be deleted. |
||||
|
||||
Like gzip, gun allows concatenated gzip streams and will decompress them, |
||||
writing all of the uncompressed data to the output. Unlike gzip, gun allows |
||||
an empty file on input, and will produce no error writing an empty output |
||||
file. |
||||
|
||||
gun will also decompress files made by Unix compress, which uses LZW |
||||
compression. These files are automatically detected by virtue of their |
||||
magic header bytes. Since the end of Unix compress stream is marked by the |
||||
end-of-file, they cannot be concantenated. If a Unix compress stream is |
||||
encountered in an input file, it is the last stream in that file. |
||||
|
||||
Like gunzip and uncompress, the file attributes of the orignal compressed |
||||
file are maintained in the final uncompressed file, to the extent that the |
||||
user permissions allow it. |
||||
|
||||
On my Mac OS X PowerPC G4, gun is almost twice as fast as gunzip (version |
||||
1.2.4) is on the same file, when gun is linked with zlib 1.2.2. Also the |
||||
LZW decompression provided by gun is about twice as fast as the standard |
||||
Unix uncompress command. |
||||
*/ |
||||
|
||||
/* external functions and related types and constants */ |
||||
#include <stdio.h> /* fprintf() */ |
||||
#include <stdlib.h> /* malloc(), free() */ |
||||
#include <string.h> /* strerror(), strcmp(), strlen(), memcpy() */ |
||||
#include <errno.h> /* errno */ |
||||
#include <fcntl.h> /* open() */ |
||||
#include <unistd.h> /* read(), write(), close(), chown(), unlink() */ |
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> /* stat(), chmod() */ |
||||
#include <utime.h> /* utime() */ |
||||
#include "zlib.h" /* inflateBackInit(), inflateBack(), */ |
||||
/* inflateBackEnd(), crc32() */ |
||||
|
||||
/* function declaration */ |
||||
#define local static |
||||
|
||||
/* buffer constants */ |
||||
#define SIZE 32768U /* input and output buffer sizes */ |
||||
#define PIECE 16384 /* limits i/o chunks for 16-bit int case */ |
||||
|
||||
/* structure for infback() to pass to input function in() -- it maintains the
|
||||
input file and a buffer of size SIZE */ |
||||
struct ind { |
||||
int infile; |
||||
unsigned char *inbuf; |
||||
}; |
||||
|
||||
/* Load input buffer, assumed to be empty, and return bytes loaded and a
|
||||
pointer to them. read() is called until the buffer is full, or until it |
||||
returns end-of-file or error. Return 0 on error. */ |
||||
local unsigned in(void *in_desc, unsigned char **buf) |
||||
{ |
||||
int ret; |
||||
unsigned len; |
||||
unsigned char *next; |
||||
struct ind *me = (struct ind *)in_desc; |
||||
|
||||
next = me->inbuf; |
||||
*buf = next; |
||||
len = 0; |
||||
do { |
||||
ret = PIECE; |
||||
if ((unsigned)ret > SIZE - len) |
||||
ret = (int)(SIZE - len); |
||||
ret = (int)read(me->infile, next, ret); |
||||
if (ret == -1) { |
||||
len = 0; |
||||
break; |
||||
} |
||||
next += ret; |
||||
len += ret; |
||||
} while (ret != 0 && len < SIZE); |
||||
return len; |
||||
} |
||||
|
||||
/* structure for infback() to pass to output function out() -- it maintains the
|
||||
output file, a running CRC-32 check on the output and the total number of |
||||
bytes output, both for checking against the gzip trailer. (The length in |
||||
the gzip trailer is stored modulo 2^32, so it's ok if a long is 32 bits and |
||||
the output is greater than 4 GB.) */ |
||||
struct outd { |
||||
int outfile; |
||||
int check; /* true if checking crc and total */ |
||||
unsigned long crc; |
||||
unsigned long total; |
||||
}; |
||||
|
||||
/* Write output buffer and update the CRC-32 and total bytes written. write()
|
||||
is called until all of the output is written or an error is encountered. |
||||
On success out() returns 0. For a write failure, out() returns 1. If the |
||||
output file descriptor is -1, then nothing is written. |
||||
*/ |
||||
local int out(void *out_desc, unsigned char *buf, unsigned len) |
||||
{ |
||||
int ret; |
||||
struct outd *me = (struct outd *)out_desc; |
||||
|
||||
if (me->check) { |
||||
me->crc = crc32(me->crc, buf, len); |
||||
me->total += len; |
||||
} |
||||
if (me->outfile != -1) |
||||
do { |
||||
ret = PIECE; |
||||
if ((unsigned)ret > len) |
||||
ret = (int)len; |
||||
ret = (int)write(me->outfile, buf, ret); |
||||
if (ret == -1) |
||||
return 1; |
||||
buf += ret; |
||||
len -= ret; |
||||
} while (len != 0); |
||||
return 0; |
||||
} |
||||
|
||||
/* next input byte macro for use inside lunpipe() and gunpipe() */ |
||||
#define NEXT() (have ? 0 : (have = in(indp, &next)), \ |
||||
last = have ? (have--, (int)(*next++)) : -1) |
||||
|
||||
/* memory for gunpipe() and lunpipe() --
|
||||
the first 256 entries of prefix[] and suffix[] are never used, could |
||||
have offset the index, but it's faster to waste the memory */ |
||||
unsigned char inbuf[SIZE]; /* input buffer */ |
||||
unsigned char outbuf[SIZE]; /* output buffer */ |
||||
unsigned short prefix[65536]; /* index to LZW prefix string */ |
||||
unsigned char suffix[65536]; /* one-character LZW suffix */ |
||||
unsigned char match[65280 + 2]; /* buffer for reversed match or gzip
|
||||
32K sliding window */ |
||||
|
||||
/* throw out what's left in the current bits byte buffer (this is a vestigial
|
||||
aspect of the compressed data format derived from an implementation that |
||||
made use of a special VAX machine instruction!) */ |
||||
#define FLUSHCODE() \ |
||||
do { \
|
||||
left = 0; \
|
||||
rem = 0; \
|
||||
if (chunk > have) { \
|
||||
chunk -= have; \
|
||||
have = 0; \
|
||||
if (NEXT() == -1) \
|
||||
break; \
|
||||
chunk--; \
|
||||
if (chunk > have) { \
|
||||
chunk = have = 0; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
have -= chunk; \
|
||||
next += chunk; \
|
||||
chunk = 0; \
|
||||
} while (0) |
||||
|
||||
/* Decompress a compress (LZW) file from indp to outfile. The compress magic
|
||||
header (two bytes) has already been read and verified. There are have bytes |
||||
of buffered input at next. strm is used for passing error information back |
||||
to gunpipe(). |
||||
|
||||
lunpipe() will return Z_OK on success, Z_BUF_ERROR for an unexpected end of |
||||
file, read error, or write error (a write error indicated by strm->next_in |
||||
not equal to Z_NULL), or Z_DATA_ERROR for invalid input. |
||||
*/ |
||||
local int lunpipe(unsigned have, unsigned char *next, struct ind *indp, |
||||
int outfile, z_stream *strm) |
||||
{ |
||||
int last; /* last byte read by NEXT(), or -1 if EOF */ |
||||
int chunk; /* bytes left in current chunk */ |
||||
int left; /* bits left in rem */ |
||||
unsigned rem; /* unused bits from input */ |
||||
int bits; /* current bits per code */ |
||||
unsigned code; /* code, table traversal index */ |
||||
unsigned mask; /* mask for current bits codes */ |
||||
int max; /* maximum bits per code for this stream */ |
||||
int flags; /* compress flags, then block compress flag */ |
||||
unsigned end; /* last valid entry in prefix/suffix tables */ |
||||
unsigned temp; /* current code */ |
||||
unsigned prev; /* previous code */ |
||||
unsigned final; /* last character written for previous code */ |
||||
unsigned stack; /* next position for reversed string */ |
||||
unsigned outcnt; /* bytes in output buffer */ |
||||
struct outd outd; /* output structure */ |
||||
|
||||
/* set up output */ |
||||
outd.outfile = outfile; |
||||
outd.check = 0; |
||||
|
||||
/* process remainder of compress header -- a flags byte */ |
||||
flags = NEXT(); |
||||
if (last == -1) |
||||
return Z_BUF_ERROR; |
||||
if (flags & 0x60) { |
||||
strm->msg = "unknown lzw flags set"; |
||||
return Z_DATA_ERROR; |
||||
} |
||||
max = flags & 0x1f; |
||||
if (max < 9 || max > 16) { |
||||
strm->msg = "lzw bits out of range"; |
||||
return Z_DATA_ERROR; |
||||
} |
||||
if (max == 9) /* 9 doesn't really mean 9 */ |
||||
max = 10; |
||||
flags &= 0x80; /* true if block compress */ |
||||
|
||||
/* clear table */ |
||||
bits = 9; |
||||
mask = 0x1ff; |
||||
end = flags ? 256 : 255; |
||||
|
||||
/* set up: get first 9-bit code, which is the first decompressed byte, but
|
||||
don't create a table entry until the next code */ |
||||
if (NEXT() == -1) /* no compressed data is ok */ |
||||
return Z_OK; |
||||
final = prev = (unsigned)last; /* low 8 bits of code */ |
||||
if (NEXT() == -1) /* missing a bit */ |
||||
return Z_BUF_ERROR; |
||||
if (last & 1) { /* code must be < 256 */ |
||||
strm->msg = "invalid lzw code"; |
||||
return Z_DATA_ERROR; |
||||
} |
||||
rem = (unsigned)last >> 1; /* remaining 7 bits */ |
||||
left = 7; |
||||
chunk = bits - 2; /* 7 bytes left in this chunk */ |
||||
outbuf[0] = (unsigned char)final; /* write first decompressed byte */ |
||||
outcnt = 1; |
||||
|
||||
/* decode codes */ |
||||
stack = 0; |
||||
for (;;) { |
||||
/* if the table will be full after this, increment the code size */ |
||||
if (end >= mask && bits < max) { |
||||
FLUSHCODE(); |
||||
bits++; |
||||
mask <<= 1; |
||||
mask++; |
||||
} |
||||
|
||||
/* get a code of length bits */ |
||||
if (chunk == 0) /* decrement chunk modulo bits */ |
||||
chunk = bits; |
||||
code = rem; /* low bits of code */ |
||||
if (NEXT() == -1) { /* EOF is end of compressed data */ |
||||
/* write remaining buffered output */ |
||||
if (outcnt && out(&outd, outbuf, outcnt)) { |
||||
strm->next_in = outbuf; /* signal write error */ |
||||
return Z_BUF_ERROR; |
||||
} |
||||
return Z_OK; |
||||
} |
||||
code += (unsigned)last << left; /* middle (or high) bits of code */ |
||||
left += 8; |
||||
chunk--; |
||||
if (bits > left) { /* need more bits */ |
||||
if (NEXT() == -1) /* can't end in middle of code */ |
||||
return Z_BUF_ERROR; |
||||
code += (unsigned)last << left; /* high bits of code */ |
||||
left += 8; |
||||
chunk--; |
||||
} |
||||
code &= mask; /* mask to current code length */ |
||||
left -= bits; /* number of unused bits */ |
||||
rem = (unsigned)last >> (8 - left); /* unused bits from last byte */ |
||||
|
||||
/* process clear code (256) */ |
||||
if (code == 256 && flags) { |
||||
FLUSHCODE(); |
||||
bits = 9; /* initialize bits and mask */ |
||||
mask = 0x1ff; |
||||
end = 255; /* empty table */ |
||||
continue; /* get next code */ |
||||
} |
||||
|
||||
/* special code to reuse last match */ |
||||
temp = code; /* save the current code */ |
||||
if (code > end) { |
||||
/* Be picky on the allowed code here, and make sure that the code
|
||||
we drop through (prev) will be a valid index so that random |
||||
input does not cause an exception. The code != end + 1 check is |
||||
empirically derived, and not checked in the original uncompress |
||||
code. If this ever causes a problem, that check could be safely |
||||
removed. Leaving this check in greatly improves gun's ability |
||||
to detect random or corrupted input after a compress header. |
||||
In any case, the prev > end check must be retained. */ |
||||
if (code != end + 1 || prev > end) { |
||||
strm->msg = "invalid lzw code"; |
||||
return Z_DATA_ERROR; |
||||
} |
||||
match[stack++] = (unsigned char)final; |
||||
code = prev; |
||||
} |
||||
|
||||
/* walk through linked list to generate output in reverse order */ |
||||
while (code >= 256) { |
||||
match[stack++] = suffix[code]; |
||||
code = prefix[code]; |
||||
} |
||||
match[stack++] = (unsigned char)code; |
||||
final = code; |
||||
|
||||
/* link new table entry */ |
||||
if (end < mask) { |
||||
end++; |
||||
prefix[end] = (unsigned short)prev; |
||||
suffix[end] = (unsigned char)final; |
||||
} |
||||
|
||||
/* set previous code for next iteration */ |
||||
prev = temp; |
||||
|
||||
/* write output in forward order */ |
||||
while (stack > SIZE - outcnt) { |
||||
while (outcnt < SIZE) |
||||
outbuf[outcnt++] = match[--stack]; |
||||
if (out(&outd, outbuf, outcnt)) { |
||||
strm->next_in = outbuf; /* signal write error */ |
||||
return Z_BUF_ERROR; |
||||
} |
||||
outcnt = 0; |
||||
} |
||||
do { |
||||
outbuf[outcnt++] = match[--stack]; |
||||
} while (stack); |
||||
|
||||
/* loop for next code with final and prev as the last match, rem and
|
||||
left provide the first 0..7 bits of the next code, end is the last |
||||
valid table entry */ |
||||
} |
||||
} |
||||
|
||||
/* Decompress a gzip file from infile to outfile. strm is assumed to have been
|
||||
successfully initialized with inflateBackInit(). The input file may consist |
||||
of a series of gzip streams, in which case all of them will be decompressed |
||||
to the output file. If outfile is -1, then the gzip stream(s) integrity is |
||||
checked and nothing is written. |
||||
|
||||
The return value is a zlib error code: Z_MEM_ERROR if out of memory, |
||||
Z_DATA_ERROR if the header or the compressed data is invalid, or if the |
||||
trailer CRC-32 check or length doesn't match, Z_BUF_ERROR if the input ends |
||||
prematurely or a write error occurs, or Z_ERRNO if junk (not a another gzip |
||||
stream) follows a valid gzip stream. |
||||
*/ |
||||
local int gunpipe(z_stream *strm, int infile, int outfile) |
||||
{ |
||||
int ret, first, last; |
||||
unsigned have, flags, len; |
||||
unsigned char *next; |
||||
struct ind ind, *indp; |
||||
struct outd outd; |
||||
|
||||
/* setup input buffer */ |
||||
ind.infile = infile; |
||||
ind.inbuf = inbuf; |
||||
indp = &ind; |
||||
|
||||
/* decompress concatenated gzip streams */ |
||||
have = 0; /* no input data read in yet */ |
||||
first = 1; /* looking for first gzip header */ |
||||
strm->next_in = Z_NULL; /* so Z_BUF_ERROR means EOF */ |
||||
for (;;) { |
||||
/* look for the two magic header bytes for a gzip stream */ |
||||
if (NEXT() == -1) { |
||||
ret = Z_OK; |
||||
break; /* empty gzip stream is ok */ |
||||
} |
||||
if (last != 31 || (NEXT() != 139 && last != 157)) { |
||||
strm->msg = "incorrect header check"; |
||||
ret = first ? Z_DATA_ERROR : Z_ERRNO; |
||||
break; /* not a gzip or compress header */ |
||||
} |
||||
first = 0; /* next non-header is junk */ |
||||
|
||||
/* process a compress (LZW) file -- can't be concatenated after this */ |
||||
if (last == 157) { |
||||
ret = lunpipe(have, next, indp, outfile, strm); |
||||
break; |
||||
} |
||||
|
||||
/* process remainder of gzip header */ |
||||
ret = Z_BUF_ERROR; |
||||
if (NEXT() != 8) { /* only deflate method allowed */ |
||||
if (last == -1) break; |
||||
strm->msg = "unknown compression method"; |
||||
ret = Z_DATA_ERROR; |
||||
break; |
||||
} |
||||
flags = NEXT(); /* header flags */ |
||||
NEXT(); /* discard mod time, xflgs, os */ |
||||
NEXT(); |
||||
NEXT(); |
||||
NEXT(); |
||||
NEXT(); |
||||
NEXT(); |
||||
if (last == -1) break; |
||||
if (flags & 0xe0) { |
||||
strm->msg = "unknown header flags set"; |
||||
ret = Z_DATA_ERROR; |
||||
break; |
||||
} |
||||
if (flags & 4) { /* extra field */ |
||||
len = NEXT(); |
||||
len += (unsigned)(NEXT()) << 8; |
||||
if (last == -1) break; |
||||
while (len > have) { |
||||
len -= have; |
||||
have = 0; |
||||
if (NEXT() == -1) break; |
||||
len--; |
||||
} |
||||
if (last == -1) break; |
||||
have -= len; |
||||
next += len; |
||||
} |
||||
if (flags & 8) /* file name */ |
||||
while (NEXT() != 0 && last != -1) |
||||
; |
||||
if (flags & 16) /* comment */ |
||||
while (NEXT() != 0 && last != -1) |
||||
; |
||||
if (flags & 2) { /* header crc */ |
||||
NEXT(); |
||||
NEXT(); |
||||
} |
||||
if (last == -1) break; |
||||
|
||||
/* set up output */ |
||||
outd.outfile = outfile; |
||||
outd.check = 1; |
||||
outd.crc = crc32(0L, Z_NULL, 0); |
||||
outd.total = 0; |
||||
|
||||
/* decompress data to output */ |
||||
strm->next_in = next; |
||||
strm->avail_in = have; |
||||
ret = inflateBack(strm, in, indp, out, &outd); |
||||
if (ret != Z_STREAM_END) break; |
||||
next = strm->next_in; |
||||
have = strm->avail_in; |
||||
strm->next_in = Z_NULL; /* so Z_BUF_ERROR means EOF */ |
||||
|
||||
/* check trailer */ |
||||
ret = Z_BUF_ERROR; |
||||
if (NEXT() != (outd.crc & 0xff) || |
||||
NEXT() != ((outd.crc >> 8) & 0xff) || |
||||
NEXT() != ((outd.crc >> 16) & 0xff) || |
||||
NEXT() != ((outd.crc >> 24) & 0xff)) { |
||||
/* crc error */ |
||||
if (last != -1) { |
||||
strm->msg = "incorrect data check"; |
||||
ret = Z_DATA_ERROR; |
||||
} |
||||
break; |
||||
} |
||||
if (NEXT() != (outd.total & 0xff) || |
||||
NEXT() != ((outd.total >> 8) & 0xff) || |
||||
NEXT() != ((outd.total >> 16) & 0xff) || |
||||
NEXT() != ((outd.total >> 24) & 0xff)) { |
||||
/* length error */ |
||||
if (last != -1) { |
||||
strm->msg = "incorrect length check"; |
||||
ret = Z_DATA_ERROR; |
||||
} |
||||
break; |
||||
} |
||||
|
||||
/* go back and look for another gzip stream */ |
||||
} |
||||
|
||||
/* clean up and return */ |
||||
return ret; |
||||
} |
||||
|
||||
/* Copy file attributes, from -> to, as best we can. This is best effort, so
|
||||
no errors are reported. The mode bits, including suid, sgid, and the sticky |
||||
bit are copied (if allowed), the owner's user id and group id are copied |
||||
(again if allowed), and the access and modify times are copied. */ |
||||
local void copymeta(char *from, char *to) |
||||
{ |
||||
struct stat was; |
||||
struct utimbuf when; |
||||
|
||||
/* get all of from's Unix meta data, return if not a regular file */ |
||||
if (stat(from, &was) != 0 || (was.st_mode & S_IFMT) != S_IFREG) |
||||
return; |
||||
|
||||
/* set to's mode bits, ignore errors */ |
||||
(void)chmod(to, was.st_mode & 07777); |
||||
|
||||
/* copy owner's user and group, ignore errors */ |
||||
(void)chown(to, was.st_uid, was.st_gid); |
||||
|
||||
/* copy access and modify times, ignore errors */ |
||||
when.actime = was.st_atime; |
||||
when.modtime = was.st_mtime; |
||||
(void)utime(to, &when); |
||||
} |
||||
|
||||
/* Decompress the file inname to the file outnname, of if test is true, just
|
||||
decompress without writing and check the gzip trailer for integrity. If |
||||
inname is NULL or an empty string, read from stdin. If outname is NULL or |
||||
an empty string, write to stdout. strm is a pre-initialized inflateBack |
||||
structure. When appropriate, copy the file attributes from inname to |
||||
outname. |
||||
|
||||
gunzip() returns 1 if there is an out-of-memory error or an unexpected |
||||
return code from gunpipe(). Otherwise it returns 0. |
||||
*/ |
||||
local int gunzip(z_stream *strm, char *inname, char *outname, int test) |
||||
{ |
||||
int ret; |
||||
int infile, outfile; |
||||
|
||||
/* open files */ |
||||
if (inname == NULL || *inname == 0) { |
||||
inname = "-"; |
||||
infile = 0; /* stdin */ |
||||
} |
||||
else { |
||||
infile = open(inname, O_RDONLY, 0); |
||||
if (infile == -1) { |
||||
fprintf(stderr, "gun cannot open %s\n", inname); |
||||
return 0; |
||||
} |
||||
} |
||||
if (test) |
||||
outfile = -1; |
||||
else if (outname == NULL || *outname == 0) { |
||||
outname = "-"; |
||||
outfile = 1; /* stdout */ |
||||
} |
||||
else { |
||||
outfile = open(outname, O_CREAT | O_TRUNC | O_WRONLY, 0666); |
||||
if (outfile == -1) { |
||||
close(infile); |
||||
fprintf(stderr, "gun cannot create %s\n", outname); |
||||
return 0; |
||||
} |
||||
} |
||||
errno = 0; |
||||
|
||||
/* decompress */ |
||||
ret = gunpipe(strm, infile, outfile); |
||||
if (outfile > 2) close(outfile); |
||||
if (infile > 2) close(infile); |
||||
|
||||
/* interpret result */ |
||||
switch (ret) { |
||||
case Z_OK: |
||||
case Z_ERRNO: |
||||
if (infile > 2 && outfile > 2) { |
||||
copymeta(inname, outname); /* copy attributes */ |
||||
unlink(inname); |
||||
} |
||||
if (ret == Z_ERRNO) |
||||
fprintf(stderr, "gun warning: trailing garbage ignored in %s\n", |
||||
inname); |
||||
break; |
||||
case Z_DATA_ERROR: |
||||
if (outfile > 2) unlink(outname); |
||||
fprintf(stderr, "gun data error on %s: %s\n", inname, strm->msg); |
||||
break; |
||||
case Z_MEM_ERROR: |
||||
if (outfile > 2) unlink(outname); |
||||
fprintf(stderr, "gun out of memory error--aborting\n"); |
||||
return 1; |
||||
case Z_BUF_ERROR: |
||||
if (outfile > 2) unlink(outname); |
||||
if (strm->next_in != Z_NULL) { |
||||
fprintf(stderr, "gun write error on %s: %s\n", |
||||
outname, strerror(errno)); |
||||
} |
||||
else if (errno) { |
||||
fprintf(stderr, "gun read error on %s: %s\n", |
||||
inname, strerror(errno)); |
||||
} |
||||
else { |
||||
fprintf(stderr, "gun unexpected end of file on %s\n", |
||||
inname); |
||||
} |
||||
break; |
||||
default: |
||||
if (outfile > 2) unlink(outname); |
||||
fprintf(stderr, "gun internal error--aborting\n"); |
||||
return 1; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
/* Process the gun command line arguments. See the command syntax near the
|
||||
beginning of this source file. */ |
||||
int main(int argc, char **argv) |
||||
{ |
||||
int ret, len, test; |
||||
char *outname; |
||||
unsigned char *window; |
||||
z_stream strm; |
||||
|
||||
/* initialize inflateBack state for repeated use */ |
||||
window = match; /* reuse LZW match buffer */ |
||||
strm.zalloc = Z_NULL; |
||||
strm.zfree = Z_NULL; |
||||
strm.opaque = Z_NULL; |
||||
ret = inflateBackInit(&strm, 15, window); |
||||
if (ret != Z_OK) { |
||||
fprintf(stderr, "gun out of memory error--aborting\n"); |
||||
return 1; |
||||
} |
||||
|
||||
/* decompress each file to the same name with the suffix removed */ |
||||
argc--; |
||||
argv++; |
||||
test = 0; |
||||
if (argc && strcmp(*argv, "-h") == 0) { |
||||
fprintf(stderr, "gun 1.2 (20 Mar 2005)\n"); |
||||
fprintf(stderr, "Copyright (c) 2005 Mark Adler\n"); |
||||
fprintf(stderr, "usage: gun [-t] [file1.gz [file2.Z ...]]\n"); |
||||
return 0; |
||||
} |
||||
if (argc && strcmp(*argv, "-t") == 0) { |
||||
test = 1; |
||||
argc--; |
||||
argv++; |
||||
} |
||||
if (argc) |
||||
do { |
||||
if (test) |
||||
outname = NULL; |
||||
else { |
||||
len = (int)strlen(*argv); |
||||
if (strcmp(*argv + len - 3, ".gz") == 0 || |
||||
strcmp(*argv + len - 3, "-gz") == 0) |
||||
len -= 3; |
||||
else if (strcmp(*argv + len - 2, ".z") == 0 || |
||||
strcmp(*argv + len - 2, "-z") == 0 || |
||||
strcmp(*argv + len - 2, "_z") == 0 || |
||||
strcmp(*argv + len - 2, ".Z") == 0) |
||||
len -= 2; |
||||
else { |
||||
fprintf(stderr, "gun error: no gz type on %s--skipping\n", |
||||
*argv); |
||||
continue; |
||||
} |
||||
outname = malloc(len + 1); |
||||
if (outname == NULL) { |
||||
fprintf(stderr, "gun out of memory error--aborting\n"); |
||||
ret = 1; |
||||
break; |
||||
} |
||||
memcpy(outname, *argv, len); |
||||
outname[len] = 0; |
||||
} |
||||
ret = gunzip(&strm, *argv, outname, test); |
||||
if (outname != NULL) free(outname); |
||||
if (ret) break; |
||||
} while (argv++, --argc); |
||||
else |
||||
ret = gunzip(&strm, NULL, NULL, test); |
||||
|
||||
/* clean up */ |
||||
inflateBackEnd(&strm); |
||||
return ret; |
||||
} |
Loading…
Reference in new issue