mirror of https://github.com/madler/zlib.git
parent
0484693e17
commit
6b8233bfe0
63 changed files with 11616 additions and 8906 deletions
@ -1,354 +1,364 @@ |
||||
/* match.s -- Pentium-optimized version of longest_match() |
||||
* Written for zlib 1.1.2 |
||||
* Copyright (C) 1998 Brian Raiter <breadbox@muppetlabs.com>
|
||||
* |
||||
* This is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License. |
||||
*/ |
||||
|
||||
#ifndef NO_UNDERLINE |
||||
#define match_init _match_init |
||||
#define longest_match _longest_match |
||||
#endif |
||||
|
||||
#define MAX_MATCH (258) |
||||
#define MIN_MATCH (3) |
||||
#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1) |
||||
#define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7) |
||||
|
||||
/* stack frame offsets */ |
||||
|
||||
#define wmask 0 /* local copy of s->wmask */ |
||||
#define window 4 /* local copy of s->window */ |
||||
#define windowbestlen 8 /* s->window + bestlen */ |
||||
#define chainlenscanend 12 /* high word: current chain len */ |
||||
/* low word: last bytes sought */ |
||||
#define scanstart 16 /* first two bytes of string */ |
||||
#define scanalign 20 /* dword-misalignment of string */ |
||||
#define nicematch 24 /* a good enough match size */ |
||||
#define bestlen 28 /* size of best match so far */ |
||||
#define scan 32 /* ptr to string wanting match */ |
||||
|
||||
#define LocalVarsSize (36) |
||||
/* saved ebx 36 */ |
||||
/* saved edi 40 */ |
||||
/* saved esi 44 */ |
||||
/* saved ebp 48 */ |
||||
/* return address 52 */ |
||||
#define deflatestate 56 /* the function arguments */ |
||||
#define curmatch 60 |
||||
|
||||
/* 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.) |
||||
*/ |
||||
#define dsWSize 36 |
||||
#define dsWMask 44 |
||||
#define dsWindow 48 |
||||
#define dsPrev 56 |
||||
#define dsMatchLen 88 |
||||
#define dsPrevMatch 92 |
||||
#define dsStrStart 100 |
||||
#define dsMatchStart 104 |
||||
#define dsLookahead 108 |
||||
#define dsPrevLen 112 |
||||
#define dsMaxChainLen 116 |
||||
#define dsGoodMatch 132 |
||||
#define dsNiceMatch 136 |
||||
|
||||
|
||||
.file "match.S" |
||||
|
||||
.globl match_init, longest_match |
||||
|
||||
.text |
||||
|
||||
/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */ |
||||
|
||||
longest_match: |
||||
|
||||
/* Save registers that the compiler may be using, and adjust %esp to */ |
||||
/* make room for our stack frame. */ |
||||
|
||||
pushl %ebp |
||||
pushl %edi |
||||
pushl %esi |
||||
pushl %ebx |
||||
subl $LocalVarsSize, %esp |
||||
|
||||
/* Retrieve the function arguments. %ecx 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). */ |
||||
|
||||
movl deflatestate(%esp), %edx |
||||
movl curmatch(%esp), %ecx |
||||
|
||||
/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */ |
||||
|
||||
movl dsNiceMatch(%edx), %eax |
||||
movl dsLookahead(%edx), %ebx |
||||
cmpl %eax, %ebx |
||||
jl LookaheadLess |
||||
movl %eax, %ebx |
||||
LookaheadLess: movl %ebx, nicematch(%esp) |
||||
|
||||
/* register Bytef *scan = s->window + s->strstart; */ |
||||
|
||||
movl dsWindow(%edx), %esi |
||||
movl %esi, window(%esp) |
||||
movl dsStrStart(%edx), %ebp |
||||
lea (%esi,%ebp), %edi |
||||
movl %edi, scan(%esp) |
||||
|
||||
/* Determine how many bytes the scan ptr is off from being */ |
||||
/* dword-aligned. */ |
||||
|
||||
movl %edi, %eax |
||||
negl %eax |
||||
andl $3, %eax |
||||
movl %eax, scanalign(%esp) |
||||
|
||||
/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */ |
||||
/* s->strstart - (IPos)MAX_DIST(s) : NIL; */ |
||||
|
||||
movl dsWSize(%edx), %eax |
||||
subl $MIN_LOOKAHEAD, %eax |
||||
subl %eax, %ebp |
||||
jg LimitPositive |
||||
xorl %ebp, %ebp |
||||
LimitPositive: |
||||
|
||||
/* unsigned chain_length = s->max_chain_length; */ |
||||
/* if (s->prev_length >= s->good_match) { */ |
||||
/* chain_length >>= 2; */ |
||||
/* } */ |
||||
|
||||
movl dsPrevLen(%edx), %eax |
||||
movl dsGoodMatch(%edx), %ebx |
||||
cmpl %ebx, %eax |
||||
movl dsMaxChainLen(%edx), %ebx |
||||
jl LastMatchGood |
||||
shrl $2, %ebx |
||||
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 scanend */ |
||||
/* scanend value, which it will always accompany. */ |
||||
|
||||
decl %ebx |
||||
shll $16, %ebx |
||||
|
||||
/* int best_len = s->prev_length; */ |
||||
|
||||
movl dsPrevLen(%edx), %eax |
||||
movl %eax, bestlen(%esp) |
||||
|
||||
/* Store the sum of s->window + best_len in %esi locally, and in %esi. */ |
||||
|
||||
addl %eax, %esi |
||||
movl %esi, windowbestlen(%esp) |
||||
|
||||
/* register ush scan_start = *(ushf*)scan; */ |
||||
/* register ush scan_end = *(ushf*)(scan+best_len-1); */ |
||||
|
||||
movw (%edi), %bx |
||||
movw %bx, scanstart(%esp) |
||||
movw -1(%edi,%eax), %bx |
||||
movl %ebx, chainlenscanend(%esp) |
||||
|
||||
/* Posf *prev = s->prev; */ |
||||
/* uInt wmask = s->w_mask; */ |
||||
|
||||
movl dsPrev(%edx), %edi |
||||
movl dsWMask(%edx), %edx |
||||
mov %edx, wmask(%esp) |
||||
|
||||
/* Jump into the main loop. */ |
||||
|
||||
jmp LoopEntry |
||||
|
||||
.balign 16
|
||||
|
||||
/* 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 = chainlenscanend - i.e., ((chainlen << 16) | scanend) |
||||
* %ecx = curmatch |
||||
* %edx = curmatch & wmask |
||||
* %esi = windowbestlen - i.e., (window + bestlen) |
||||
* %edi = prev |
||||
* %ebp = limit |
||||
* |
||||
* Two optimization notes on the choice of instructions: |
||||
* |
||||
* The first instruction uses a 16-bit address, which costs an extra, |
||||
* unpairable cycle. This is cheaper than doing a 32-bit access and |
||||
* zeroing the high word, due to the 3-cycle misalignment penalty which |
||||
* would occur half the time. This also turns out to be cheaper than |
||||
* doing two separate 8-bit accesses, as the memory is so rarely in the |
||||
* L1 cache. |
||||
* |
||||
* The window buffer, however, apparently spends a lot of time in the |
||||
* cache, and so it is faster to retrieve the word at the end of the |
||||
* match string with two 8-bit loads. The instructions that test the |
||||
* word at the beginning of the match string, however, are executed |
||||
* much less frequently, and there it was cheaper to use 16-bit |
||||
* instructions, which avoided the necessity of saving off and |
||||
* subsequently reloading one of the other registers. |
||||
*/ |
||||
LookupLoop: |
||||
/* 1 U & V */ |
||||
movw (%edi,%edx,2), %cx /* 2 U pipe */ |
||||
movl wmask(%esp), %edx /* 2 V pipe */ |
||||
cmpl %ebp, %ecx /* 3 U pipe */ |
||||
jbe LeaveNow /* 3 V pipe */ |
||||
subl $0x00010000, %ebx /* 4 U pipe */ |
||||
js LeaveNow /* 4 V pipe */ |
||||
LoopEntry: movb -1(%esi,%ecx), %al /* 5 U pipe */ |
||||
andl %ecx, %edx /* 5 V pipe */ |
||||
cmpb %bl, %al /* 6 U pipe */ |
||||
jnz LookupLoop /* 6 V pipe */ |
||||
movb (%esi,%ecx), %ah |
||||
cmpb %bh, %ah |
||||
jnz LookupLoop |
||||
movl window(%esp), %eax |
||||
movw (%eax,%ecx), %ax |
||||
cmpw scanstart(%esp), %ax |
||||
jnz LookupLoop |
||||
|
||||
/* Store the current value of chainlen. */ |
||||
|
||||
movl %ebx, chainlenscanend(%esp) |
||||
|
||||
/* 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). */ |
||||
|
||||
movl window(%esp), %esi |
||||
movl scan(%esp), %edi |
||||
addl %ecx, %esi |
||||
movl scanalign(%esp), %eax |
||||
movl $(-MAX_MATCH_8), %edx |
||||
lea MAX_MATCH_8(%edi,%eax), %edi |
||||
lea MAX_MATCH_8(%esi,%eax), %esi |
||||
|
||||
/* 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: |
||||
movl (%esi,%edx), %eax |
||||
movl (%edi,%edx), %ebx |
||||
xorl %ebx, %eax |
||||
jnz LeaveLoopCmps |
||||
movl 4(%esi,%edx), %eax |
||||
movl 4(%edi,%edx), %ebx |
||||
xorl %ebx, %eax |
||||
jnz LeaveLoopCmps4 |
||||
addl $8, %edx |
||||
jnz LoopCmps |
||||
jmp LenMaximum |
||||
LeaveLoopCmps4: addl $4, %edx |
||||
LeaveLoopCmps: testl $0x0000FFFF, %eax |
||||
jnz LenLower |
||||
addl $2, %edx |
||||
shrl $16, %eax |
||||
LenLower: subb $1, %al |
||||
adcl $0, %edx |
||||
|
||||
/* 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 (%edi,%edx), %eax |
||||
movl scan(%esp), %edi |
||||
subl %edi, %eax |
||||
cmpl $MAX_MATCH, %eax |
||||
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. */ |
||||
|
||||
movl deflatestate(%esp), %edx |
||||
movl bestlen(%esp), %ebx |
||||
cmpl %ebx, %eax |
||||
jg LongerMatch |
||||
movl chainlenscanend(%esp), %ebx |
||||
movl windowbestlen(%esp), %esi |
||||
movl dsPrev(%edx), %edi |
||||
movl wmask(%esp), %edx |
||||
andl %ecx, %edx |
||||
jmp LookupLoop |
||||
|
||||
/* s->match_start = cur_match; */ |
||||
/* best_len = len; */ |
||||
/* if (len >= nice_match) break; */ |
||||
/* scan_end = *(ushf*)(scan+best_len-1); */ |
||||
|
||||
LongerMatch: movl nicematch(%esp), %ebx |
||||
movl %eax, bestlen(%esp) |
||||
movl %ecx, dsMatchStart(%edx) |
||||
cmpl %ebx, %eax |
||||
jge LeaveNow |
||||
movl window(%esp), %esi |
||||
addl %eax, %esi |
||||
movl %esi, windowbestlen(%esp) |
||||
movl chainlenscanend(%esp), %ebx |
||||
movw -1(%edi,%eax), %bx |
||||
movl dsPrev(%edx), %edi |
||||
movl %ebx, chainlenscanend(%esp) |
||||
movl wmask(%esp), %edx |
||||
andl %ecx, %edx |
||||
jmp LookupLoop |
||||
|
||||
/* Accept the current string, with the maximum possible length. */ |
||||
|
||||
LenMaximum: movl deflatestate(%esp), %edx |
||||
movl $MAX_MATCH, bestlen(%esp) |
||||
movl %ecx, dsMatchStart(%edx) |
||||
|
||||
/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */ |
||||
/* return s->lookahead; */ |
||||
|
||||
LeaveNow: |
||||
movl deflatestate(%esp), %edx |
||||
movl bestlen(%esp), %ebx |
||||
movl dsLookahead(%edx), %eax |
||||
cmpl %eax, %ebx |
||||
jg LookaheadRet |
||||
movl %ebx, %eax |
||||
LookaheadRet: |
||||
|
||||
/* Restore the stack and return from whence we came. */ |
||||
|
||||
addl $LocalVarsSize, %esp |
||||
popl %ebx |
||||
popl %esi |
||||
popl %edi |
||||
popl %ebp |
||||
match_init: ret |
||||
/* match.s -- Pentium-optimized version of longest_match() |
||||
* Written for zlib 1.1.2 |
||||
* Copyright (C) 1998 Brian Raiter <breadbox@muppetlabs.com>
|
||||
* |
||||
* This is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License. |
||||
*/ |
||||
|
||||
#ifndef NO_UNDERLINE |
||||
#define match_init _match_init |
||||
#define longest_match _longest_match |
||||
#endif |
||||
|
||||
#define MAX_MATCH (258) |
||||
#define MIN_MATCH (3) |
||||
#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1) |
||||
#define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7) |
||||
|
||||
/* stack frame offsets */ |
||||
|
||||
#define wmask 0 /* local copy of s->wmask */ |
||||
#define window 4 /* local copy of s->window */ |
||||
#define windowbestlen 8 /* s->window + bestlen */ |
||||
#define chainlenscanend 12 /* high word: current chain len */ |
||||
/* low word: last bytes sought */ |
||||
#define scanstart 16 /* first two bytes of string */ |
||||
#define scanalign 20 /* dword-misalignment of string */ |
||||
#define nicematch 24 /* a good enough match size */ |
||||
#define bestlen 28 /* size of best match so far */ |
||||
#define scan 32 /* ptr to string wanting match */ |
||||
|
||||
#define LocalVarsSize (36) |
||||
/* saved ebx 36 */ |
||||
/* saved edi 40 */ |
||||
/* saved esi 44 */ |
||||
/* saved ebp 48 */ |
||||
/* return address 52 */ |
||||
#define deflatestate 56 /* the function arguments */ |
||||
#define curmatch 60 |
||||
|
||||
/* 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"). |
||||
*/ |
||||
|
||||
#define zlib1222add (8) |
||||
|
||||
#define dsWSize (36+zlib1222add) |
||||
#define dsWMask (44+zlib1222add) |
||||
#define dsWindow (48+zlib1222add) |
||||
#define dsPrev (56+zlib1222add) |
||||
#define dsMatchLen (88+zlib1222add) |
||||
#define dsPrevMatch (92+zlib1222add) |
||||
#define dsStrStart (100+zlib1222add) |
||||
#define dsMatchStart (104+zlib1222add) |
||||
#define dsLookahead (108+zlib1222add) |
||||
#define dsPrevLen (112+zlib1222add) |
||||
#define dsMaxChainLen (116+zlib1222add) |
||||
#define dsGoodMatch (132+zlib1222add) |
||||
#define dsNiceMatch (136+zlib1222add) |
||||
|
||||
|
||||
.file "match.S" |
||||
|
||||
.globl match_init, longest_match |
||||
|
||||
.text |
||||
|
||||
/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */ |
||||
|
||||
longest_match: |
||||
|
||||
/* Save registers that the compiler may be using, and adjust %esp to */ |
||||
/* make room for our stack frame. */ |
||||
|
||||
pushl %ebp |
||||
pushl %edi |
||||
pushl %esi |
||||
pushl %ebx |
||||
subl $LocalVarsSize, %esp |
||||
|
||||
/* Retrieve the function arguments. %ecx 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). */ |
||||
|
||||
movl deflatestate(%esp), %edx |
||||
movl curmatch(%esp), %ecx |
||||
|
||||
/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */ |
||||
|
||||
movl dsNiceMatch(%edx), %eax |
||||
movl dsLookahead(%edx), %ebx |
||||
cmpl %eax, %ebx |
||||
jl LookaheadLess |
||||
movl %eax, %ebx |
||||
LookaheadLess: movl %ebx, nicematch(%esp) |
||||
|
||||
/* register Bytef *scan = s->window + s->strstart; */ |
||||
|
||||
movl dsWindow(%edx), %esi |
||||
movl %esi, window(%esp) |
||||
movl dsStrStart(%edx), %ebp |
||||
lea (%esi,%ebp), %edi |
||||
movl %edi, scan(%esp) |
||||
|
||||
/* Determine how many bytes the scan ptr is off from being */ |
||||
/* dword-aligned. */ |
||||
|
||||
movl %edi, %eax |
||||
negl %eax |
||||
andl $3, %eax |
||||
movl %eax, scanalign(%esp) |
||||
|
||||
/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */ |
||||
/* s->strstart - (IPos)MAX_DIST(s) : NIL; */ |
||||
|
||||
movl dsWSize(%edx), %eax |
||||
subl $MIN_LOOKAHEAD, %eax |
||||
subl %eax, %ebp |
||||
jg LimitPositive |
||||
xorl %ebp, %ebp |
||||
LimitPositive: |
||||
|
||||
/* unsigned chain_length = s->max_chain_length; */ |
||||
/* if (s->prev_length >= s->good_match) { */ |
||||
/* chain_length >>= 2; */ |
||||
/* } */ |
||||
|
||||
movl dsPrevLen(%edx), %eax |
||||
movl dsGoodMatch(%edx), %ebx |
||||
cmpl %ebx, %eax |
||||
movl dsMaxChainLen(%edx), %ebx |
||||
jl LastMatchGood |
||||
shrl $2, %ebx |
||||
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 scanend */ |
||||
/* scanend value, which it will always accompany. */ |
||||
|
||||
decl %ebx |
||||
shll $16, %ebx |
||||
|
||||
/* int best_len = s->prev_length; */ |
||||
|
||||
movl dsPrevLen(%edx), %eax |
||||
movl %eax, bestlen(%esp) |
||||
|
||||
/* Store the sum of s->window + best_len in %esi locally, and in %esi. */ |
||||
|
||||
addl %eax, %esi |
||||
movl %esi, windowbestlen(%esp) |
||||
|
||||
/* register ush scan_start = *(ushf*)scan; */ |
||||
/* register ush scan_end = *(ushf*)(scan+best_len-1); */ |
||||
|
||||
movw (%edi), %bx |
||||
movw %bx, scanstart(%esp) |
||||
movw -1(%edi,%eax), %bx |
||||
movl %ebx, chainlenscanend(%esp) |
||||
|
||||
/* Posf *prev = s->prev; */ |
||||
/* uInt wmask = s->w_mask; */ |
||||
|
||||
movl dsPrev(%edx), %edi |
||||
movl dsWMask(%edx), %edx |
||||
mov %edx, wmask(%esp) |
||||
|
||||
/* Jump into the main loop. */ |
||||
|
||||
jmp LoopEntry |
||||
|
||||
.balign 16
|
||||
|
||||
/* 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 = chainlenscanend - i.e., ((chainlen << 16) | scanend) |
||||
* %ecx = curmatch |
||||
* %edx = curmatch & wmask |
||||
* %esi = windowbestlen - i.e., (window + bestlen) |
||||
* %edi = prev |
||||
* %ebp = limit |
||||
* |
||||
* Two optimization notes on the choice of instructions: |
||||
* |
||||
* The first instruction uses a 16-bit address, which costs an extra, |
||||
* unpairable cycle. This is cheaper than doing a 32-bit access and |
||||
* zeroing the high word, due to the 3-cycle misalignment penalty which |
||||
* would occur half the time. This also turns out to be cheaper than |
||||
* doing two separate 8-bit accesses, as the memory is so rarely in the |
||||
* L1 cache. |
||||
* |
||||
* The window buffer, however, apparently spends a lot of time in the |
||||
* cache, and so it is faster to retrieve the word at the end of the |
||||
* match string with two 8-bit loads. The instructions that test the |
||||
* word at the beginning of the match string, however, are executed |
||||
* much less frequently, and there it was cheaper to use 16-bit |
||||
* instructions, which avoided the necessity of saving off and |
||||
* subsequently reloading one of the other registers. |
||||
*/ |
||||
LookupLoop: |
||||
/* 1 U & V */ |
||||
movw (%edi,%edx,2), %cx /* 2 U pipe */ |
||||
movl wmask(%esp), %edx /* 2 V pipe */ |
||||
cmpl %ebp, %ecx /* 3 U pipe */ |
||||
jbe LeaveNow /* 3 V pipe */ |
||||
subl $0x00010000, %ebx /* 4 U pipe */ |
||||
js LeaveNow /* 4 V pipe */ |
||||
LoopEntry: movb -1(%esi,%ecx), %al /* 5 U pipe */ |
||||
andl %ecx, %edx /* 5 V pipe */ |
||||
cmpb %bl, %al /* 6 U pipe */ |
||||
jnz LookupLoop /* 6 V pipe */ |
||||
movb (%esi,%ecx), %ah |
||||
cmpb %bh, %ah |
||||
jnz LookupLoop |
||||
movl window(%esp), %eax |
||||
movw (%eax,%ecx), %ax |
||||
cmpw scanstart(%esp), %ax |
||||
jnz LookupLoop |
||||
|
||||
/* Store the current value of chainlen. */ |
||||
|
||||
movl %ebx, chainlenscanend(%esp) |
||||
|
||||
/* 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). */ |
||||
|
||||
movl window(%esp), %esi |
||||
movl scan(%esp), %edi |
||||
addl %ecx, %esi |
||||
movl scanalign(%esp), %eax |
||||
movl $(-MAX_MATCH_8), %edx |
||||
lea MAX_MATCH_8(%edi,%eax), %edi |
||||
lea MAX_MATCH_8(%esi,%eax), %esi |
||||
|
||||
/* 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: |
||||
movl (%esi,%edx), %eax |
||||
movl (%edi,%edx), %ebx |
||||
xorl %ebx, %eax |
||||
jnz LeaveLoopCmps |
||||
movl 4(%esi,%edx), %eax |
||||
movl 4(%edi,%edx), %ebx |
||||
xorl %ebx, %eax |
||||
jnz LeaveLoopCmps4 |
||||
addl $8, %edx |
||||
jnz LoopCmps |
||||
jmp LenMaximum |
||||
LeaveLoopCmps4: addl $4, %edx |
||||
LeaveLoopCmps: testl $0x0000FFFF, %eax |
||||
jnz LenLower |
||||
addl $2, %edx |
||||
shrl $16, %eax |
||||
LenLower: subb $1, %al |
||||
adcl $0, %edx |
||||
|
||||
/* 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 (%edi,%edx), %eax |
||||
movl scan(%esp), %edi |
||||
subl %edi, %eax |
||||
cmpl $MAX_MATCH, %eax |
||||
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. */ |
||||
|
||||
movl deflatestate(%esp), %edx |
||||
movl bestlen(%esp), %ebx |
||||
cmpl %ebx, %eax |
||||
jg LongerMatch |
||||
movl chainlenscanend(%esp), %ebx |
||||
movl windowbestlen(%esp), %esi |
||||
movl dsPrev(%edx), %edi |
||||
movl wmask(%esp), %edx |
||||
andl %ecx, %edx |
||||
jmp LookupLoop |
||||
|
||||
/* s->match_start = cur_match; */ |
||||
/* best_len = len; */ |
||||
/* if (len >= nice_match) break; */ |
||||
/* scan_end = *(ushf*)(scan+best_len-1); */ |
||||
|
||||
LongerMatch: movl nicematch(%esp), %ebx |
||||
movl %eax, bestlen(%esp) |
||||
movl %ecx, dsMatchStart(%edx) |
||||
cmpl %ebx, %eax |
||||
jge LeaveNow |
||||
movl window(%esp), %esi |
||||
addl %eax, %esi |
||||
movl %esi, windowbestlen(%esp) |
||||
movl chainlenscanend(%esp), %ebx |
||||
movw -1(%edi,%eax), %bx |
||||
movl dsPrev(%edx), %edi |
||||
movl %ebx, chainlenscanend(%esp) |
||||
movl wmask(%esp), %edx |
||||
andl %ecx, %edx |
||||
jmp LookupLoop |
||||
|
||||
/* Accept the current string, with the maximum possible length. */ |
||||
|
||||
LenMaximum: movl deflatestate(%esp), %edx |
||||
movl $MAX_MATCH, bestlen(%esp) |
||||
movl %ecx, dsMatchStart(%edx) |
||||
|
||||
/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */ |
||||
/* return s->lookahead; */ |
||||
|
||||
LeaveNow: |
||||
movl deflatestate(%esp), %edx |
||||
movl bestlen(%esp), %ebx |
||||
movl dsLookahead(%edx), %eax |
||||
cmpl %eax, %ebx |
||||
jg LookaheadRet |
||||
movl %ebx, %eax |
||||
LookaheadRet: |
||||
|
||||
/* Restore the stack and return from whence we came. */ |
||||
|
||||
addl $LocalVarsSize, %esp |
||||
popl %ebx |
||||
popl %esi |
||||
popl %edi |
||||
popl %ebp |
||||
match_init: ret |
||||
|
@ -1,327 +1,329 @@ |
||||
/* match.s -- Pentium-Pro-optimized version of longest_match() |
||||
* Written for zlib 1.1.2 |
||||
* Copyright (C) 1998 Brian Raiter <breadbox@muppetlabs.com>
|
||||
* |
||||
* This is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License. |
||||
*/ |
||||
|
||||
#ifndef NO_UNDERLINE |
||||
#define match_init _match_init |
||||
#define longest_match _longest_match |
||||
#endif |
||||
|
||||
#define MAX_MATCH (258) |
||||
#define MIN_MATCH (3) |
||||
#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1) |
||||
#define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7) |
||||
|
||||
/* stack frame offsets */ |
||||
|
||||
#define chainlenwmask 0 /* high word: current chain len */ |
||||
/* low word: s->wmask */ |
||||
#define window 4 /* local copy of s->window */ |
||||
#define windowbestlen 8 /* s->window + bestlen */ |
||||
#define scanstart 16 /* first two bytes of string */ |
||||
#define scanend 12 /* last two bytes of string */ |
||||
#define scanalign 20 /* dword-misalignment of string */ |
||||
#define nicematch 24 /* a good enough match size */ |
||||
#define bestlen 28 /* size of best match so far */ |
||||
#define scan 32 /* ptr to string wanting match */ |
||||
|
||||
#define LocalVarsSize (36) |
||||
/* saved ebx 36 */ |
||||
/* saved edi 40 */ |
||||
/* saved esi 44 */ |
||||
/* saved ebp 48 */ |
||||
/* return address 52 */ |
||||
#define deflatestate 56 /* the function arguments */ |
||||
#define curmatch 60 |
||||
|
||||
/* 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.) |
||||
*/ |
||||
#define dsWSize 36 |
||||
#define dsWMask 44 |
||||
#define dsWindow 48 |
||||
#define dsPrev 56 |
||||
#define dsMatchLen 88 |
||||
#define dsPrevMatch 92 |
||||
#define dsStrStart 100 |
||||
#define dsMatchStart 104 |
||||
#define dsLookahead 108 |
||||
#define dsPrevLen 112 |
||||
#define dsMaxChainLen 116 |
||||
#define dsGoodMatch 132 |
||||
#define dsNiceMatch 136 |
||||
|
||||
|
||||
.file "match.S" |
||||
|
||||
.globl match_init, longest_match |
||||
|
||||
.text |
||||
|
||||
/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */ |
||||
|
||||
longest_match: |
||||
|
||||
/* Save registers that the compiler may be using, and adjust %esp to */ |
||||
/* make room for our stack frame. */ |
||||
|
||||
pushl %ebp |
||||
pushl %edi |
||||
pushl %esi |
||||
pushl %ebx |
||||
subl $LocalVarsSize, %esp |
||||
|
||||
/* Retrieve the function arguments. %ecx 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). */ |
||||
|
||||
movl deflatestate(%esp), %edx |
||||
movl curmatch(%esp), %ecx |
||||
|
||||
/* uInt wmask = s->w_mask; */ |
||||
/* unsigned chain_length = s->max_chain_length; */ |
||||
/* if (s->prev_length >= s->good_match) { */ |
||||
/* chain_length >>= 2; */ |
||||
/* } */ |
||||
|
||||
movl dsPrevLen(%edx), %eax |
||||
movl dsGoodMatch(%edx), %ebx |
||||
cmpl %ebx, %eax |
||||
movl dsWMask(%edx), %eax |
||||
movl dsMaxChainLen(%edx), %ebx |
||||
jl LastMatchGood |
||||
shrl $2, %ebx |
||||
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. */ |
||||
|
||||
decl %ebx |
||||
shll $16, %ebx |
||||
orl %eax, %ebx |
||||
movl %ebx, chainlenwmask(%esp) |
||||
|
||||
/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */ |
||||
|
||||
movl dsNiceMatch(%edx), %eax |
||||
movl dsLookahead(%edx), %ebx |
||||
cmpl %eax, %ebx |
||||
jl LookaheadLess |
||||
movl %eax, %ebx |
||||
LookaheadLess: movl %ebx, nicematch(%esp) |
||||
|
||||
/* register Bytef *scan = s->window + s->strstart; */ |
||||
|
||||
movl dsWindow(%edx), %esi |
||||
movl %esi, window(%esp) |
||||
movl dsStrStart(%edx), %ebp |
||||
lea (%esi,%ebp), %edi |
||||
movl %edi, scan(%esp) |
||||
|
||||
/* Determine how many bytes the scan ptr is off from being */ |
||||
/* dword-aligned. */ |
||||
|
||||
movl %edi, %eax |
||||
negl %eax |
||||
andl $3, %eax |
||||
movl %eax, scanalign(%esp) |
||||
|
||||
/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */ |
||||
/* s->strstart - (IPos)MAX_DIST(s) : NIL; */ |
||||
|
||||
movl dsWSize(%edx), %eax |
||||
subl $MIN_LOOKAHEAD, %eax |
||||
subl %eax, %ebp |
||||
jg LimitPositive |
||||
xorl %ebp, %ebp |
||||
LimitPositive: |
||||
|
||||
/* int best_len = s->prev_length; */ |
||||
|
||||
movl dsPrevLen(%edx), %eax |
||||
movl %eax, bestlen(%esp) |
||||
|
||||
/* Store the sum of s->window + best_len in %esi locally, and in %esi. */ |
||||
|
||||
addl %eax, %esi |
||||
movl %esi, windowbestlen(%esp) |
||||
|
||||
/* register ush scan_start = *(ushf*)scan; */ |
||||
/* register ush scan_end = *(ushf*)(scan+best_len-1); */ |
||||
/* Posf *prev = s->prev; */ |
||||
|
||||
movzwl (%edi), %ebx |
||||
movl %ebx, scanstart(%esp) |
||||
movzwl -1(%edi,%eax), %ebx |
||||
movl %ebx, scanend(%esp) |
||||
movl dsPrev(%edx), %edi |
||||
|
||||
/* Jump into the main loop. */ |
||||
|
||||
movl chainlenwmask(%esp), %edx |
||||
jmp LoopEntry |
||||
|
||||
.balign 16
|
||||
|
||||
/* 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 |
||||
* %ecx = curmatch |
||||
* %edx = chainlenwmask - i.e., ((chainlen << 16) | wmask) |
||||
* %esi = windowbestlen - i.e., (window + bestlen) |
||||
* %edi = prev |
||||
* %ebp = limit |
||||
*/ |
||||
LookupLoop: |
||||
andl %edx, %ecx |
||||
movzwl (%edi,%ecx,2), %ecx |
||||
cmpl %ebp, %ecx |
||||
jbe LeaveNow |
||||
subl $0x00010000, %edx |
||||
js LeaveNow |
||||
LoopEntry: movzwl -1(%esi,%ecx), %eax |
||||
cmpl %ebx, %eax |
||||
jnz LookupLoop |
||||
movl window(%esp), %eax |
||||
movzwl (%eax,%ecx), %eax |
||||
cmpl scanstart(%esp), %eax |
||||
jnz LookupLoop |
||||
|
||||
/* Store the current value of chainlen. */ |
||||
|
||||
movl %edx, chainlenwmask(%esp) |
||||
|
||||
/* 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). */ |
||||
|
||||
movl window(%esp), %esi |
||||
movl scan(%esp), %edi |
||||
addl %ecx, %esi |
||||
movl scanalign(%esp), %eax |
||||
movl $(-MAX_MATCH_8), %edx |
||||
lea MAX_MATCH_8(%edi,%eax), %edi |
||||
lea MAX_MATCH_8(%esi,%eax), %esi |
||||
|
||||
/* 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: |
||||
movl (%esi,%edx), %eax |
||||
xorl (%edi,%edx), %eax |
||||
jnz LeaveLoopCmps |
||||
movl 4(%esi,%edx), %eax |
||||
xorl 4(%edi,%edx), %eax |
||||
jnz LeaveLoopCmps4 |
||||
addl $8, %edx |
||||
jnz LoopCmps |
||||
jmp LenMaximum |
||||
LeaveLoopCmps4: addl $4, %edx |
||||
LeaveLoopCmps: testl $0x0000FFFF, %eax |
||||
jnz LenLower |
||||
addl $2, %edx |
||||
shrl $16, %eax |
||||
LenLower: subb $1, %al |
||||
adcl $0, %edx |
||||
|
||||
/* 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 (%edi,%edx), %eax |
||||
movl scan(%esp), %edi |
||||
subl %edi, %eax |
||||
cmpl $MAX_MATCH, %eax |
||||
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. */ |
||||
|
||||
movl deflatestate(%esp), %edx |
||||
movl bestlen(%esp), %ebx |
||||
cmpl %ebx, %eax |
||||
jg LongerMatch |
||||
movl windowbestlen(%esp), %esi |
||||
movl dsPrev(%edx), %edi |
||||
movl scanend(%esp), %ebx |
||||
movl chainlenwmask(%esp), %edx |
||||
jmp LookupLoop |
||||
|
||||
/* s->match_start = cur_match; */ |
||||
/* best_len = len; */ |
||||
/* if (len >= nice_match) break; */ |
||||
/* scan_end = *(ushf*)(scan+best_len-1); */ |
||||
|
||||
LongerMatch: movl nicematch(%esp), %ebx |
||||
movl %eax, bestlen(%esp) |
||||
movl %ecx, dsMatchStart(%edx) |
||||
cmpl %ebx, %eax |
||||
jge LeaveNow |
||||
movl window(%esp), %esi |
||||
addl %eax, %esi |
||||
movl %esi, windowbestlen(%esp) |
||||
movzwl -1(%edi,%eax), %ebx |
||||
movl dsPrev(%edx), %edi |
||||
movl %ebx, scanend(%esp) |
||||
movl chainlenwmask(%esp), %edx |
||||
jmp LookupLoop |
||||
|
||||
/* Accept the current string, with the maximum possible length. */ |
||||
|
||||
LenMaximum: movl deflatestate(%esp), %edx |
||||
movl $MAX_MATCH, bestlen(%esp) |
||||
movl %ecx, dsMatchStart(%edx) |
||||
|
||||
/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */ |
||||
/* return s->lookahead; */ |
||||
|
||||
LeaveNow: |
||||
movl deflatestate(%esp), %edx |
||||
movl bestlen(%esp), %ebx |
||||
movl dsLookahead(%edx), %eax |
||||
cmpl %eax, %ebx |
||||
jg LookaheadRet |
||||
movl %ebx, %eax |
||||
LookaheadRet: |
||||
|
||||
/* Restore the stack and return from whence we came. */ |
||||
|
||||
addl $LocalVarsSize, %esp |
||||
popl %ebx |
||||
popl %esi |
||||
popl %edi |
||||
popl %ebp |
||||
match_init: ret |
||||
/* match.s -- Pentium-Pro-optimized version of longest_match() |
||||
* Written for zlib 1.1.2 |
||||
* Copyright (C) 1998 Brian Raiter <breadbox@muppetlabs.com>
|
||||
* |
||||
* This is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License. |
||||
*/ |
||||
|
||||
#ifndef NO_UNDERLINE |
||||
#define match_init _match_init |
||||
#define longest_match _longest_match |
||||
#endif |
||||
|
||||
#define MAX_MATCH (258) |
||||
#define MIN_MATCH (3) |
||||
#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1) |
||||
#define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7) |
||||
|
||||
/* stack frame offsets */ |
||||
|
||||
#define chainlenwmask 0 /* high word: current chain len */ |
||||
/* low word: s->wmask */ |
||||
#define window 4 /* local copy of s->window */ |
||||
#define windowbestlen 8 /* s->window + bestlen */ |
||||
#define scanstart 16 /* first two bytes of string */ |
||||
#define scanend 12 /* last two bytes of string */ |
||||
#define scanalign 20 /* dword-misalignment of string */ |
||||
#define nicematch 24 /* a good enough match size */ |
||||
#define bestlen 28 /* size of best match so far */ |
||||
#define scan 32 /* ptr to string wanting match */ |
||||
|
||||
#define LocalVarsSize (36) |
||||
/* saved ebx 36 */ |
||||
/* saved edi 40 */ |
||||
/* saved esi 44 */ |
||||
/* saved ebp 48 */ |
||||
/* return address 52 */ |
||||
#define deflatestate 56 /* the function arguments */ |
||||
#define curmatch 60 |
||||
|
||||
/* 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"). |
||||
*/ |
||||
|
||||
#define zlib1222add (8) |
||||
|
||||
#define dsWSize (36+zlib1222add) |
||||
#define dsWMask (44+zlib1222add) |
||||
#define dsWindow (48+zlib1222add) |
||||
#define dsPrev (56+zlib1222add) |
||||
#define dsMatchLen (88+zlib1222add) |
||||
#define dsPrevMatch (92+zlib1222add) |
||||
#define dsStrStart (100+zlib1222add) |
||||
#define dsMatchStart (104+zlib1222add) |
||||
#define dsLookahead (108+zlib1222add) |
||||
#define dsPrevLen (112+zlib1222add) |
||||
#define dsMaxChainLen (116+zlib1222add) |
||||
#define dsGoodMatch (132+zlib1222add) |
||||
#define dsNiceMatch (136+zlib1222add) |
||||
|
||||
|
||||
.file "match.S" |
||||
|
||||
.globl match_init, longest_match |
||||
|
||||
.text |
||||
|
||||
/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */ |
||||
|
||||
longest_match: |
||||
|
||||
/* Save registers that the compiler may be using, and adjust %esp to */ |
||||
/* make room for our stack frame. */ |
||||
|
||||
pushl %ebp |
||||
pushl %edi |
||||
pushl %esi |
||||
pushl %ebx |
||||
subl $LocalVarsSize, %esp |
||||
|
||||
/* Retrieve the function arguments. %ecx 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). */ |
||||
|
||||
movl deflatestate(%esp), %edx |
||||
movl curmatch(%esp), %ecx |
||||
|
||||
/* uInt wmask = s->w_mask; */ |
||||
/* unsigned chain_length = s->max_chain_length; */ |
||||
/* if (s->prev_length >= s->good_match) { */ |
||||
/* chain_length >>= 2; */ |
||||
/* } */ |
||||
|
||||
movl dsPrevLen(%edx), %eax |
||||
movl dsGoodMatch(%edx), %ebx |
||||
cmpl %ebx, %eax |
||||
movl dsWMask(%edx), %eax |
||||
movl dsMaxChainLen(%edx), %ebx |
||||
jl LastMatchGood |
||||
shrl $2, %ebx |
||||
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. */ |
||||
|
||||
decl %ebx |
||||
shll $16, %ebx |
||||
orl %eax, %ebx |
||||
movl %ebx, chainlenwmask(%esp) |
||||
|
||||
/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */ |
||||
|
||||
movl dsNiceMatch(%edx), %eax |
||||
movl dsLookahead(%edx), %ebx |
||||
cmpl %eax, %ebx |
||||
jl LookaheadLess |
||||
movl %eax, %ebx |
||||
LookaheadLess: movl %ebx, nicematch(%esp) |
||||
|
||||
/* register Bytef *scan = s->window + s->strstart; */ |
||||
|
||||
movl dsWindow(%edx), %esi |
||||
movl %esi, window(%esp) |
||||
movl dsStrStart(%edx), %ebp |
||||
lea (%esi,%ebp), %edi |
||||
movl %edi, scan(%esp) |
||||
|
||||
/* Determine how many bytes the scan ptr is off from being */ |
||||
/* dword-aligned. */ |
||||
|
||||
movl %edi, %eax |
||||
negl %eax |
||||
andl $3, %eax |
||||
movl %eax, scanalign(%esp) |
||||
|
||||
/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */ |
||||
/* s->strstart - (IPos)MAX_DIST(s) : NIL; */ |
||||
|
||||
movl dsWSize(%edx), %eax |
||||
subl $MIN_LOOKAHEAD, %eax |
||||
subl %eax, %ebp |
||||
jg LimitPositive |
||||
xorl %ebp, %ebp |
||||
LimitPositive: |
||||
|
||||
/* int best_len = s->prev_length; */ |
||||
|
||||
movl dsPrevLen(%edx), %eax |
||||
movl %eax, bestlen(%esp) |
||||
|
||||
/* Store the sum of s->window + best_len in %esi locally, and in %esi. */ |
||||
|
||||
addl %eax, %esi |
||||
movl %esi, windowbestlen(%esp) |
||||
|
||||
/* register ush scan_start = *(ushf*)scan; */ |
||||
/* register ush scan_end = *(ushf*)(scan+best_len-1); */ |
||||
/* Posf *prev = s->prev; */ |
||||
|
||||
movzwl (%edi), %ebx |
||||
movl %ebx, scanstart(%esp) |
||||
movzwl -1(%edi,%eax), %ebx |
||||
movl %ebx, scanend(%esp) |
||||
movl dsPrev(%edx), %edi |
||||
|
||||
/* Jump into the main loop. */ |
||||
|
||||
movl chainlenwmask(%esp), %edx |
||||
jmp LoopEntry |
||||
|
||||
.balign 16
|
||||
|
||||
/* 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 |
||||
* %ecx = curmatch |
||||
* %edx = chainlenwmask - i.e., ((chainlen << 16) | wmask) |
||||
* %esi = windowbestlen - i.e., (window + bestlen) |
||||
* %edi = prev |
||||
* %ebp = limit |
||||
*/ |
||||
LookupLoop: |
||||
andl %edx, %ecx |
||||
movzwl (%edi,%ecx,2), %ecx |
||||
cmpl %ebp, %ecx |
||||
jbe LeaveNow |
||||
subl $0x00010000, %edx |
||||
js LeaveNow |
||||
LoopEntry: movzwl -1(%esi,%ecx), %eax |
||||
cmpl %ebx, %eax |
||||
jnz LookupLoop |
||||
movl window(%esp), %eax |
||||
movzwl (%eax,%ecx), %eax |
||||
cmpl scanstart(%esp), %eax |
||||
jnz LookupLoop |
||||
|
||||
/* Store the current value of chainlen. */ |
||||
|
||||
movl %edx, chainlenwmask(%esp) |
||||
|
||||
/* 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). */ |
||||
|
||||
movl window(%esp), %esi |
||||
movl scan(%esp), %edi |
||||
addl %ecx, %esi |
||||
movl scanalign(%esp), %eax |
||||
movl $(-MAX_MATCH_8), %edx |
||||
lea MAX_MATCH_8(%edi,%eax), %edi |
||||
lea MAX_MATCH_8(%esi,%eax), %esi |
||||
|
||||
/* 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: |
||||
movl (%esi,%edx), %eax |
||||
xorl (%edi,%edx), %eax |
||||
jnz LeaveLoopCmps |
||||
movl 4(%esi,%edx), %eax |
||||
xorl 4(%edi,%edx), %eax |
||||
jnz LeaveLoopCmps4 |
||||
addl $8, %edx |
||||
jnz LoopCmps |
||||
jmp LenMaximum |
||||
LeaveLoopCmps4: addl $4, %edx |
||||
LeaveLoopCmps: testl $0x0000FFFF, %eax |
||||
jnz LenLower |
||||
addl $2, %edx |
||||
shrl $16, %eax |
||||
LenLower: subb $1, %al |
||||
adcl $0, %edx |
||||
|
||||
/* 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 (%edi,%edx), %eax |
||||
movl scan(%esp), %edi |
||||
subl %edi, %eax |
||||
cmpl $MAX_MATCH, %eax |
||||
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. */ |
||||
|
||||
movl deflatestate(%esp), %edx |
||||
movl bestlen(%esp), %ebx |
||||
cmpl %ebx, %eax |
||||
jg LongerMatch |
||||
movl windowbestlen(%esp), %esi |
||||
movl dsPrev(%edx), %edi |
||||
movl scanend(%esp), %ebx |
||||
movl chainlenwmask(%esp), %edx |
||||
jmp LookupLoop |
||||
|
||||
/* s->match_start = cur_match; */ |
||||
/* best_len = len; */ |
||||
/* if (len >= nice_match) break; */ |
||||
/* scan_end = *(ushf*)(scan+best_len-1); */ |
||||
|
||||
LongerMatch: movl nicematch(%esp), %ebx |
||||
movl %eax, bestlen(%esp) |
||||
movl %ecx, dsMatchStart(%edx) |
||||
cmpl %ebx, %eax |
||||
jge LeaveNow |
||||
movl window(%esp), %esi |
||||
addl %eax, %esi |
||||
movl %esi, windowbestlen(%esp) |
||||
movzwl -1(%edi,%eax), %ebx |
||||
movl dsPrev(%edx), %edi |
||||
movl %ebx, scanend(%esp) |
||||
movl chainlenwmask(%esp), %edx |
||||
jmp LookupLoop |
||||
|
||||
/* Accept the current string, with the maximum possible length. */ |
||||
|
||||
LenMaximum: movl deflatestate(%esp), %edx |
||||
movl $MAX_MATCH, bestlen(%esp) |
||||
movl %ecx, dsMatchStart(%edx) |
||||
|
||||
/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */ |
||||
/* return s->lookahead; */ |
||||
|
||||
LeaveNow: |
||||
movl deflatestate(%esp), %edx |
||||
movl bestlen(%esp), %ebx |
||||
movl dsLookahead(%edx), %eax |
||||
cmpl %eax, %ebx |
||||
jg LookaheadRet |
||||
movl %ebx, %eax |
||||
LookaheadRet: |
||||
|
||||
/* Restore the stack and return from whence we came. */ |
||||
|
||||
addl $LocalVarsSize, %esp |
||||
popl %ebx |
||||
popl %esi |
||||
popl %edi |
||||
popl %ebp |
||||
match_init: ret |
||||
|
@ -1,408 +1,413 @@ |
||||
|
||||
; match.asm -- Pentium-Pro optimized version of longest_match() |
||||
; |
||||
; Updated for zlib 1.1.3 and converted to MASM 6.1x |
||||
; Copyright (C) 2000 Dan Higdon <hdan@kinesoft.com> |
||||
; and Chuck Walbourn <chuckw@kinesoft.com> |
||||
; Corrections by Cosmin Truta <cosmint@cs.ubbcluj.ro> |
||||
; |
||||
; This is free software; you can redistribute it and/or modify it |
||||
; under the terms of the GNU General Public License. |
||||
|
||||
; Based on match.S |
||||
; Written for zlib 1.1.2 |
||||
; Copyright (C) 1998 Brian Raiter <breadbox@muppetlabs.com> |
||||
|
||||
.686P |
||||
.MODEL FLAT |
||||
|
||||
;=========================================================================== |
||||
; EQUATES |
||||
;=========================================================================== |
||||
|
||||
MAX_MATCH EQU 258 |
||||
MIN_MATCH EQU 3 |
||||
MIN_LOOKAHEAD EQU (MAX_MATCH + MIN_MATCH + 1) |
||||
MAX_MATCH_8 EQU ((MAX_MATCH + 7) AND (NOT 7)) |
||||
|
||||
;=========================================================================== |
||||
; STRUCTURES |
||||
;=========================================================================== |
||||
|
||||
; This STRUCT assumes a 4-byte alignment |
||||
|
||||
DEFLATE_STATE STRUCT |
||||
ds_strm dd ? |
||||
ds_status dd ? |
||||
ds_pending_buf dd ? |
||||
ds_pending_buf_size dd ? |
||||
ds_pending_out dd ? |
||||
ds_pending dd ? |
||||
ds_wrap dd ? |
||||
ds_data_type db ? |
||||
ds_method db ? |
||||
db ? ; padding |
||||
db ? ; padding |
||||
ds_last_flush dd ? |
||||
ds_w_size dd ? ; used |
||||
ds_w_bits dd ? |
||||
ds_w_mask dd ? ; used |
||||
ds_window dd ? ; used |
||||
ds_window_size dd ? |
||||
ds_prev dd ? ; used |
||||
ds_head dd ? |
||||
ds_ins_h dd ? |
||||
ds_hash_size dd ? |
||||
ds_hash_bits dd ? |
||||
ds_hash_mask dd ? |
||||
ds_hash_shift dd ? |
||||
ds_block_start dd ? |
||||
ds_match_length dd ? ; used |
||||
ds_prev_match dd ? ; used |
||||
ds_match_available dd ? |
||||
ds_strstart dd ? ; used |
||||
ds_match_start dd ? ; used |
||||
ds_lookahead dd ? ; used |
||||
ds_prev_length dd ? ; used |
||||
ds_max_chain_length dd ? ; used |
||||
ds_max_laxy_match dd ? |
||||
ds_level dd ? |
||||
ds_strategy dd ? |
||||
ds_good_match dd ? ; used |
||||
ds_nice_match dd ? ; used |
||||
|
||||
; Don't need anymore of the struct for match |
||||
DEFLATE_STATE ENDS |
||||
|
||||
;=========================================================================== |
||||
; CODE |
||||
;=========================================================================== |
||||
_TEXT SEGMENT |
||||
|
||||
;--------------------------------------------------------------------------- |
||||
; match_init |
||||
;--------------------------------------------------------------------------- |
||||
ALIGN 4 |
||||
PUBLIC _match_init |
||||
_match_init PROC |
||||
; no initialization needed |
||||
ret |
||||
_match_init ENDP |
||||
|
||||
;--------------------------------------------------------------------------- |
||||
; uInt longest_match(deflate_state *deflatestate, IPos curmatch) |
||||
;--------------------------------------------------------------------------- |
||||
ALIGN 4 |
||||
|
||||
PUBLIC _longest_match |
||||
_longest_match PROC |
||||
|
||||
; Since this code uses EBP for a scratch register, the stack frame must |
||||
; be manually constructed and referenced relative to the ESP register. |
||||
|
||||
; Stack image |
||||
; Variables |
||||
chainlenwmask = 0 ; high word: current chain len |
||||
; low word: s->wmask |
||||
window = 4 ; local copy of s->window |
||||
windowbestlen = 8 ; s->window + bestlen |
||||
scanend = 12 ; last two bytes of string |
||||
scanstart = 16 ; first two bytes of string |
||||
scanalign = 20 ; dword-misalignment of string |
||||
nicematch = 24 ; a good enough match size |
||||
bestlen = 28 ; size of best match so far |
||||
scan = 32 ; ptr to string wanting match |
||||
varsize = 36 ; number of bytes (also offset to last saved register) |
||||
|
||||
; Saved Registers (actually pushed into place) |
||||
ebx_save = 36 |
||||
edi_save = 40 |
||||
esi_save = 44 |
||||
ebp_save = 48 |
||||
|
||||
; Parameters |
||||
retaddr = 52 |
||||
deflatestate = 56 |
||||
curmatch = 60 |
||||
|
||||
; Save registers that the compiler may be using |
||||
push ebp |
||||
push edi |
||||
push esi |
||||
push ebx |
||||
|
||||
; Allocate local variable space |
||||
sub esp,varsize |
||||
|
||||
; Retrieve the function arguments. ecx 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). |
||||
|
||||
mov edx, [esp+deflatestate] |
||||
ASSUME edx:PTR DEFLATE_STATE |
||||
|
||||
mov ecx, [esp+curmatch] |
||||
|
||||
; uInt wmask = s->w_mask; |
||||
; unsigned chain_length = s->max_chain_length; |
||||
; if (s->prev_length >= s->good_match) { |
||||
; chain_length >>= 2; |
||||
; } |
||||
|
||||
mov eax, [edx].ds_prev_length |
||||
mov ebx, [edx].ds_good_match |
||||
cmp eax, ebx |
||||
mov eax, [edx].ds_w_mask |
||||
mov ebx, [edx].ds_max_chain_length |
||||
jl SHORT 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 [esp+chainlenwmask], ebx |
||||
|
||||
; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; |
||||
|
||||
mov eax, [edx].ds_nice_match |
||||
mov ebx, [edx].ds_lookahead |
||||
cmp ebx, eax |
||||
jl SHORT LookaheadLess |
||||
mov ebx, eax |
||||
LookaheadLess: |
||||
mov [esp+nicematch], ebx |
||||
|
||||
;/* register Bytef *scan = s->window + s->strstart; */ |
||||
|
||||
mov esi, [edx].ds_window |
||||
mov [esp+window], esi |
||||
mov ebp, [edx].ds_strstart |
||||
lea edi, [esi+ebp] |
||||
mov [esp+scan],edi |
||||
|
||||
;/* Determine how many bytes the scan ptr is off from being */ |
||||
;/* dword-aligned. */ |
||||
|
||||
mov eax, edi |
||||
neg eax |
||||
and eax, 3 |
||||
mov [esp+scanalign], eax |
||||
|
||||
;/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */ |
||||
;/* s->strstart - (IPos)MAX_DIST(s) : NIL; */ |
||||
|
||||
mov eax, [edx].ds_w_size |
||||
sub eax, MIN_LOOKAHEAD |
||||
sub ebp, eax |
||||
jg SHORT LimitPositive |
||||
xor ebp, ebp |
||||
LimitPositive: |
||||
|
||||
;/* int best_len = s->prev_length; */ |
||||
|
||||
mov eax, [edx].ds_prev_length |
||||
mov [esp+bestlen], eax |
||||
|
||||
;/* Store the sum of s->window + best_len in %esi locally, and in %esi. */ |
||||
|
||||
add esi, eax |
||||
mov [esp+windowbestlen], esi |
||||
|
||||
;/* register ush scan_start = *(ushf*)scan; */ |
||||
;/* register ush scan_end = *(ushf*)(scan+best_len-1); */ |
||||
;/* Posf *prev = s->prev; */ |
||||
|
||||
movzx ebx, WORD PTR[edi] |
||||
mov [esp+scanstart], ebx |
||||
movzx ebx, WORD PTR[eax+edi-1] |
||||
mov [esp+scanend], ebx |
||||
mov edi, [edx].ds_prev |
||||
|
||||
;/* Jump into the main loop. */ |
||||
|
||||
mov edx, [esp+chainlenwmask] |
||||
jmp SHORT LoopEntry |
||||
|
||||
;/* 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 |
||||
; * %ecx = curmatch |
||||
; * %edx = chainlenwmask - i.e., ((chainlen << 16) | wmask) |
||||
; * %esi = windowbestlen - i.e., (window + bestlen) |
||||
; * %edi = prev |
||||
; * %ebp = limit |
||||
; */ |
||||
|
||||
ALIGN 4 |
||||
LookupLoop: |
||||
and ecx, edx |
||||
movzx ecx, WORD PTR[edi+ecx*2] |
||||
cmp ecx, ebp |
||||
jbe LeaveNow |
||||
sub edx, 000010000H |
||||
js LeaveNow |
||||
|
||||
LoopEntry: |
||||
movzx eax, WORD PTR[esi+ecx-1] |
||||
cmp eax, ebx |
||||
jnz SHORT LookupLoop |
||||
|
||||
mov eax, [esp+window] |
||||
movzx eax, WORD PTR[eax+ecx] |
||||
cmp eax, [esp+scanstart] |
||||
jnz SHORT LookupLoop |
||||
|
||||
;/* Store the current value of chainlen. */ |
||||
|
||||
mov [esp+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). */ |
||||
|
||||
mov esi, [esp+window] |
||||
mov edi, [esp+scan] |
||||
add esi, ecx |
||||
mov eax, [esp+scanalign] |
||||
mov edx, -MAX_MATCH_8 |
||||
lea edi, [edi+eax+MAX_MATCH_8] |
||||
lea esi, [esi+eax+MAX_MATCH_8] |
||||
|
||||
;/* 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, DWORD PTR[esi+edx] |
||||
xor eax, DWORD PTR[edi+edx] |
||||
jnz SHORT LeaveLoopCmps |
||||
|
||||
mov eax, DWORD PTR[esi+edx+4] |
||||
xor eax, DWORD PTR[edi+edx+4] |
||||
jnz SHORT LeaveLoopCmps4 |
||||
|
||||
add edx, 8 |
||||
jnz SHORT LoopCmps |
||||
jmp LenMaximum |
||||
ALIGN 4 |
||||
|
||||
LeaveLoopCmps4: |
||||
add edx, 4 |
||||
|
||||
LeaveLoopCmps: |
||||
test eax, 00000FFFFH |
||||
jnz SHORT LenLower |
||||
|
||||
add edx, 2 |
||||
shr eax, 16 |
||||
|
||||
LenLower: |
||||
sub al, 1 |
||||
adc edx, 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 eax, [edi+edx] |
||||
mov edi, [esp+scan] |
||||
sub eax, edi |
||||
cmp eax, MAX_MATCH |
||||
jge SHORT 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. */ |
||||
|
||||
mov edx, [esp+deflatestate] |
||||
mov ebx, [esp+bestlen] |
||||
cmp eax, ebx |
||||
jg SHORT LongerMatch |
||||
mov esi, [esp+windowbestlen] |
||||
mov edi, [edx].ds_prev |
||||
mov ebx, [esp+scanend] |
||||
mov edx, [esp+chainlenwmask] |
||||
jmp LookupLoop |
||||
ALIGN 4 |
||||
|
||||
;/* s->match_start = cur_match; */ |
||||
;/* best_len = len; */ |
||||
;/* if (len >= nice_match) break; */ |
||||
;/* scan_end = *(ushf*)(scan+best_len-1); */ |
||||
|
||||
LongerMatch: |
||||
mov ebx, [esp+nicematch] |
||||
mov [esp+bestlen], eax |
||||
mov [edx].ds_match_start, ecx |
||||
cmp eax, ebx |
||||
jge SHORT LeaveNow |
||||
mov esi, [esp+window] |
||||
add esi, eax |
||||
mov [esp+windowbestlen], esi |
||||
movzx ebx, WORD PTR[edi+eax-1] |
||||
mov edi, [edx].ds_prev |
||||
mov [esp+scanend], ebx |
||||
mov edx, [esp+chainlenwmask] |
||||
jmp LookupLoop |
||||
ALIGN 4 |
||||
|
||||
;/* Accept the current string, with the maximum possible length. */ |
||||
|
||||
LenMaximum: |
||||
mov edx, [esp+deflatestate] |
||||
mov DWORD PTR[esp+bestlen], MAX_MATCH |
||||
mov [edx].ds_match_start, ecx |
||||
|
||||
;/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */ |
||||
;/* return s->lookahead; */ |
||||
|
||||
LeaveNow: |
||||
mov edx, [esp+deflatestate] |
||||
mov ebx, [esp+bestlen] |
||||
mov eax, [edx].ds_lookahead |
||||
cmp ebx, eax |
||||
jg SHORT LookaheadRet |
||||
mov eax, ebx |
||||
LookaheadRet: |
||||
|
||||
; Restore the stack and return from whence we came. |
||||
|
||||
add esp, varsize |
||||
pop ebx |
||||
pop esi |
||||
pop edi |
||||
pop ebp |
||||
ret |
||||
|
||||
_longest_match ENDP |
||||
|
||||
_TEXT ENDS |
||||
END |
||||
|
||||
; match.asm -- Pentium-Pro optimized version of longest_match() |
||||
; |
||||
; Updated for zlib 1.1.3 and converted to MASM 6.1x |
||||
; Copyright (C) 2000 Dan Higdon <hdan@kinesoft.com> |
||||
; and Chuck Walbourn <chuckw@kinesoft.com> |
||||
; Corrections by Cosmin Truta <cosmint@cs.ubbcluj.ro> |
||||
; |
||||
; This is free software; you can redistribute it and/or modify it |
||||
; under the terms of the GNU General Public License. |
||||
|
||||
; Based on match.S |
||||
; Written for zlib 1.1.2 |
||||
; Copyright (C) 1998 Brian Raiter <breadbox@muppetlabs.com> |
||||
; |
||||
; Modified by Gilles Vollant (2005) for add gzhead and gzindex |
||||
|
||||
.686P |
||||
.MODEL FLAT |
||||
|
||||
;=========================================================================== |
||||
; EQUATES |
||||
;=========================================================================== |
||||
|
||||
MAX_MATCH EQU 258 |
||||
MIN_MATCH EQU 3 |
||||
MIN_LOOKAHEAD EQU (MAX_MATCH + MIN_MATCH + 1) |
||||
MAX_MATCH_8 EQU ((MAX_MATCH + 7) AND (NOT 7)) |
||||
|
||||
;=========================================================================== |
||||
; STRUCTURES |
||||
;=========================================================================== |
||||
|
||||
; This STRUCT assumes a 4-byte alignment |
||||
|
||||
DEFLATE_STATE STRUCT |
||||
ds_strm dd ? |
||||
ds_status dd ? |
||||
ds_pending_buf dd ? |
||||
ds_pending_buf_size dd ? |
||||
ds_pending_out dd ? |
||||
ds_pending dd ? |
||||
ds_wrap dd ? |
||||
; gzhead and gzindex are added in zlib 1.2.2.2 (see deflate.h) |
||||
ds_gzhead dd ? |
||||
ds_gzindex dd ? |
||||
ds_data_type db ? |
||||
ds_method db ? |
||||
db ? ; padding |
||||
db ? ; padding |
||||
ds_last_flush dd ? |
||||
ds_w_size dd ? ; used |
||||
ds_w_bits dd ? |
||||
ds_w_mask dd ? ; used |
||||
ds_window dd ? ; used |
||||
ds_window_size dd ? |
||||
ds_prev dd ? ; used |
||||
ds_head dd ? |
||||
ds_ins_h dd ? |
||||
ds_hash_size dd ? |
||||
ds_hash_bits dd ? |
||||
ds_hash_mask dd ? |
||||
ds_hash_shift dd ? |
||||
ds_block_start dd ? |
||||
ds_match_length dd ? ; used |
||||
ds_prev_match dd ? ; used |
||||
ds_match_available dd ? |
||||
ds_strstart dd ? ; used |
||||
ds_match_start dd ? ; used |
||||
ds_lookahead dd ? ; used |
||||
ds_prev_length dd ? ; used |
||||
ds_max_chain_length dd ? ; used |
||||
ds_max_laxy_match dd ? |
||||
ds_level dd ? |
||||
ds_strategy dd ? |
||||
ds_good_match dd ? ; used |
||||
ds_nice_match dd ? ; used |
||||
|
||||
; Don't need anymore of the struct for match |
||||
DEFLATE_STATE ENDS |
||||
|
||||
;=========================================================================== |
||||
; CODE |
||||
;=========================================================================== |
||||
_TEXT SEGMENT |
||||
|
||||
;--------------------------------------------------------------------------- |
||||
; match_init |
||||
;--------------------------------------------------------------------------- |
||||
ALIGN 4 |
||||
PUBLIC _match_init |
||||
_match_init PROC |
||||
; no initialization needed |
||||
ret |
||||
_match_init ENDP |
||||
|
||||
;--------------------------------------------------------------------------- |
||||
; uInt longest_match(deflate_state *deflatestate, IPos curmatch) |
||||
;--------------------------------------------------------------------------- |
||||
ALIGN 4 |
||||
|
||||
PUBLIC _longest_match |
||||
_longest_match PROC |
||||
|
||||
; Since this code uses EBP for a scratch register, the stack frame must |
||||
; be manually constructed and referenced relative to the ESP register. |
||||
|
||||
; Stack image |
||||
; Variables |
||||
chainlenwmask = 0 ; high word: current chain len |
||||
; low word: s->wmask |
||||
window = 4 ; local copy of s->window |
||||
windowbestlen = 8 ; s->window + bestlen |
||||
scanend = 12 ; last two bytes of string |
||||
scanstart = 16 ; first two bytes of string |
||||
scanalign = 20 ; dword-misalignment of string |
||||
nicematch = 24 ; a good enough match size |
||||
bestlen = 28 ; size of best match so far |
||||
scan = 32 ; ptr to string wanting match |
||||
varsize = 36 ; number of bytes (also offset to last saved register) |
||||
|
||||
; Saved Registers (actually pushed into place) |
||||
ebx_save = 36 |
||||
edi_save = 40 |
||||
esi_save = 44 |
||||
ebp_save = 48 |
||||
|
||||
; Parameters |
||||
retaddr = 52 |
||||
deflatestate = 56 |
||||
curmatch = 60 |
||||
|
||||
; Save registers that the compiler may be using |
||||
push ebp |
||||
push edi |
||||
push esi |
||||
push ebx |
||||
|
||||
; Allocate local variable space |
||||
sub esp,varsize |
||||
|
||||
; Retrieve the function arguments. ecx 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). |
||||
|
||||
mov edx, [esp+deflatestate] |
||||
ASSUME edx:PTR DEFLATE_STATE |
||||
|
||||
mov ecx, [esp+curmatch] |
||||
|
||||
; uInt wmask = s->w_mask; |
||||
; unsigned chain_length = s->max_chain_length; |
||||
; if (s->prev_length >= s->good_match) { |
||||
; chain_length >>= 2; |
||||
; } |
||||
|
||||
mov eax, [edx].ds_prev_length |
||||
mov ebx, [edx].ds_good_match |
||||
cmp eax, ebx |
||||
mov eax, [edx].ds_w_mask |
||||
mov ebx, [edx].ds_max_chain_length |
||||
jl SHORT 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 [esp+chainlenwmask], ebx |
||||
|
||||
; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; |
||||
|
||||
mov eax, [edx].ds_nice_match |
||||
mov ebx, [edx].ds_lookahead |
||||
cmp ebx, eax |
||||
jl SHORT LookaheadLess |
||||
mov ebx, eax |
||||
LookaheadLess: |
||||
mov [esp+nicematch], ebx |
||||
|
||||
;/* register Bytef *scan = s->window + s->strstart; */ |
||||
|
||||
mov esi, [edx].ds_window |
||||
mov [esp+window], esi |
||||
mov ebp, [edx].ds_strstart |
||||
lea edi, [esi+ebp] |
||||
mov [esp+scan],edi |
||||
|
||||
;/* Determine how many bytes the scan ptr is off from being */ |
||||
;/* dword-aligned. */ |
||||
|
||||
mov eax, edi |
||||
neg eax |
||||
and eax, 3 |
||||
mov [esp+scanalign], eax |
||||
|
||||
;/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */ |
||||
;/* s->strstart - (IPos)MAX_DIST(s) : NIL; */ |
||||
|
||||
mov eax, [edx].ds_w_size |
||||
sub eax, MIN_LOOKAHEAD |
||||
sub ebp, eax |
||||
jg SHORT LimitPositive |
||||
xor ebp, ebp |
||||
LimitPositive: |
||||
|
||||
;/* int best_len = s->prev_length; */ |
||||
|
||||
mov eax, [edx].ds_prev_length |
||||
mov [esp+bestlen], eax |
||||
|
||||
;/* Store the sum of s->window + best_len in %esi locally, and in %esi. */ |
||||
|
||||
add esi, eax |
||||
mov [esp+windowbestlen], esi |
||||
|
||||
;/* register ush scan_start = *(ushf*)scan; */ |
||||
;/* register ush scan_end = *(ushf*)(scan+best_len-1); */ |
||||
;/* Posf *prev = s->prev; */ |
||||
|
||||
movzx ebx, WORD PTR[edi] |
||||
mov [esp+scanstart], ebx |
||||
movzx ebx, WORD PTR[eax+edi-1] |
||||
mov [esp+scanend], ebx |
||||
mov edi, [edx].ds_prev |
||||
|
||||
;/* Jump into the main loop. */ |
||||
|
||||
mov edx, [esp+chainlenwmask] |
||||
jmp SHORT LoopEntry |
||||
|
||||
;/* 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 |
||||
; * %ecx = curmatch |
||||
; * %edx = chainlenwmask - i.e., ((chainlen << 16) | wmask) |
||||
; * %esi = windowbestlen - i.e., (window + bestlen) |
||||
; * %edi = prev |
||||
; * %ebp = limit |
||||
; */ |
||||
|
||||
ALIGN 4 |
||||
LookupLoop: |
||||
and ecx, edx |
||||
movzx ecx, WORD PTR[edi+ecx*2] |
||||
cmp ecx, ebp |
||||
jbe LeaveNow |
||||
sub edx, 000010000H |
||||
js LeaveNow |
||||
|
||||
LoopEntry: |
||||
movzx eax, WORD PTR[esi+ecx-1] |
||||
cmp eax, ebx |
||||
jnz SHORT LookupLoop |
||||
|
||||
mov eax, [esp+window] |
||||
movzx eax, WORD PTR[eax+ecx] |
||||
cmp eax, [esp+scanstart] |
||||
jnz SHORT LookupLoop |
||||
|
||||
;/* Store the current value of chainlen. */ |
||||
|
||||
mov [esp+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). */ |
||||
|
||||
mov esi, [esp+window] |
||||
mov edi, [esp+scan] |
||||
add esi, ecx |
||||
mov eax, [esp+scanalign] |
||||
mov edx, -MAX_MATCH_8 |
||||
lea edi, [edi+eax+MAX_MATCH_8] |
||||
lea esi, [esi+eax+MAX_MATCH_8] |
||||
|
||||
;/* 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, DWORD PTR[esi+edx] |
||||
xor eax, DWORD PTR[edi+edx] |
||||
jnz SHORT LeaveLoopCmps |
||||
|
||||
mov eax, DWORD PTR[esi+edx+4] |
||||
xor eax, DWORD PTR[edi+edx+4] |
||||
jnz SHORT LeaveLoopCmps4 |
||||
|
||||
add edx, 8 |
||||
jnz SHORT LoopCmps |
||||
jmp LenMaximum |
||||
ALIGN 4 |
||||
|
||||
LeaveLoopCmps4: |
||||
add edx, 4 |
||||
|
||||
LeaveLoopCmps: |
||||
test eax, 00000FFFFH |
||||
jnz SHORT LenLower |
||||
|
||||
add edx, 2 |
||||
shr eax, 16 |
||||
|
||||
LenLower: |
||||
sub al, 1 |
||||
adc edx, 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 eax, [edi+edx] |
||||
mov edi, [esp+scan] |
||||
sub eax, edi |
||||
cmp eax, MAX_MATCH |
||||
jge SHORT 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. */ |
||||
|
||||
mov edx, [esp+deflatestate] |
||||
mov ebx, [esp+bestlen] |
||||
cmp eax, ebx |
||||
jg SHORT LongerMatch |
||||
mov esi, [esp+windowbestlen] |
||||
mov edi, [edx].ds_prev |
||||
mov ebx, [esp+scanend] |
||||
mov edx, [esp+chainlenwmask] |
||||
jmp LookupLoop |
||||
ALIGN 4 |
||||
|
||||
;/* s->match_start = cur_match; */ |
||||
;/* best_len = len; */ |
||||
;/* if (len >= nice_match) break; */ |
||||
;/* scan_end = *(ushf*)(scan+best_len-1); */ |
||||
|
||||
LongerMatch: |
||||
mov ebx, [esp+nicematch] |
||||
mov [esp+bestlen], eax |
||||
mov [edx].ds_match_start, ecx |
||||
cmp eax, ebx |
||||
jge SHORT LeaveNow |
||||
mov esi, [esp+window] |
||||
add esi, eax |
||||
mov [esp+windowbestlen], esi |
||||
movzx ebx, WORD PTR[edi+eax-1] |
||||
mov edi, [edx].ds_prev |
||||
mov [esp+scanend], ebx |
||||
mov edx, [esp+chainlenwmask] |
||||
jmp LookupLoop |
||||
ALIGN 4 |
||||
|
||||
;/* Accept the current string, with the maximum possible length. */ |
||||
|
||||
LenMaximum: |
||||
mov edx, [esp+deflatestate] |
||||
mov DWORD PTR[esp+bestlen], MAX_MATCH |
||||
mov [edx].ds_match_start, ecx |
||||
|
||||
;/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */ |
||||
;/* return s->lookahead; */ |
||||
|
||||
LeaveNow: |
||||
mov edx, [esp+deflatestate] |
||||
mov ebx, [esp+bestlen] |
||||
mov eax, [edx].ds_lookahead |
||||
cmp ebx, eax |
||||
jg SHORT LookaheadRet |
||||
mov eax, ebx |
||||
LookaheadRet: |
||||
|
||||
; Restore the stack and return from whence we came. |
||||
|
||||
add esp, varsize |
||||
pop ebx |
||||
pop esi |
||||
pop edi |
||||
pop ebp |
||||
ret |
||||
|
||||
_longest_match ENDP |
||||
|
||||
_TEXT ENDS |
||||
END |
||||
|
@ -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 |
File diff suppressed because it is too large
Load Diff
@ -1,206 +1,62 @@ |
||||
/* gvmat32.c -- C portion of the optimized longest_match for 32 bits x86
|
||||
* Copyright (C) 1995-1996 Jean-loup Gailly and Gilles Vollant. |
||||
* File written by Gilles Vollant, by modifiying the longest_match |
||||
* from Jean-loup Gailly in deflate.c |
||||
* it prepare all parameters and call the assembly longest_match_gvasm |
||||
* longest_match execute standard C code is wmask != 0x7fff |
||||
* (assembly code is faster with a fixed wmask) |
||||
* |
||||
*/ |
||||
|
||||
#include "deflate.h" |
||||
|
||||
#ifdef ASMV |
||||
#define NIL 0 |
||||
|
||||
#define UNALIGNED_OK |
||||
|
||||
|
||||
/* if your C compiler don't add underline before function name,
|
||||
define ADD_UNDERLINE_ASMFUNC */ |
||||
#ifdef ADD_UNDERLINE_ASMFUNC |
||||
#define longest_match_7fff _longest_match_7fff |
||||
#define longest_match_686 _longest_match_686 |
||||
#define cpudetect32 _cpudetect32 |
||||
#endif |
||||
|
||||
|
||||
|
||||
void match_init() |
||||
{ |
||||
} |
||||
|
||||
unsigned long cpudetect32(); |
||||
|
||||
uInt longest_match_c( |
||||
deflate_state *s, |
||||
IPos cur_match); /* current match */ |
||||
|
||||
|
||||
uInt longest_match_7fff( |
||||
deflate_state *s, |
||||
IPos cur_match); /* current match */ |
||||
|
||||
uInt longest_match_686( |
||||
deflate_state *s, |
||||
IPos cur_match); /* current match */ |
||||
|
||||
uInt longest_match( |
||||
deflate_state *s, |
||||
IPos cur_match) /* current match */ |
||||
{ |
||||
static uInt iIsPPro=2; |
||||
|
||||
if ((s->w_mask == 0x7fff) && (iIsPPro==0)) |
||||
return longest_match_7fff(s,cur_match); |
||||
|
||||
if (iIsPPro==1) |
||||
return longest_match_686(s,cur_match); |
||||
|
||||
if (iIsPPro==2) |
||||
iIsPPro = (((cpudetect32()/0x100)&0xf)>=6) ? 1 : 0; |
||||
|
||||
return longest_match_c(s,cur_match); |
||||
} |
||||
|
||||
|
||||
|
||||
uInt longest_match_c(s, cur_match) |
||||
deflate_state *s; |
||||
IPos cur_match; /* current match */ |
||||
{ |
||||
unsigned chain_length = s->max_chain_length;/* max hash chain length */ |
||||
register Bytef *scan = s->window + s->strstart; /* current string */ |
||||
register Bytef *match; /* matched string */ |
||||
register int len; /* length of current match */ |
||||
int best_len = s->prev_length; /* best match length so far */ |
||||
int nice_match = s->nice_match; /* stop if match long enough */ |
||||
IPos limit = s->strstart > (IPos)MAX_DIST(s) ? |
||||
s->strstart - (IPos)MAX_DIST(s) : NIL; |
||||
/* Stop when cur_match becomes <= limit. To simplify the code,
|
||||
* we prevent matches with the string of window index 0. |
||||
*/ |
||||
Posf *prev = s->prev; |
||||
uInt wmask = s->w_mask; |
||||
|
||||
#ifdef UNALIGNED_OK |
||||
/* Compare two bytes at a time. Note: this is not always beneficial.
|
||||
* Try with and without -DUNALIGNED_OK to check. |
||||
*/ |
||||
register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; |
||||
register ush scan_start = *(ushf*)scan; |
||||
register ush scan_end = *(ushf*)(scan+best_len-1); |
||||
#else |
||||
register Bytef *strend = s->window + s->strstart + MAX_MATCH; |
||||
register Byte scan_end1 = scan[best_len-1]; |
||||
register Byte scan_end = scan[best_len]; |
||||
#endif |
||||
|
||||
/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
|
||||
* It is easy to get rid of this optimization if necessary. |
||||
*/ |
||||
Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); |
||||
|
||||
/* Do not waste too much time if we already have a good match: */ |
||||
if (s->prev_length >= s->good_match) { |
||||
chain_length >>= 2; |
||||
} |
||||
/* Do not look for matches beyond the end of the input. This is necessary
|
||||
* to make deflate deterministic. |
||||
*/ |
||||
if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; |
||||
|
||||
Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); |
||||
|
||||
do { |
||||
Assert(cur_match < s->strstart, "no future"); |
||||
match = s->window + cur_match; |
||||
|
||||
/* Skip to next match if the match length cannot increase
|
||||
* or if the match length is less than 2: |
||||
*/ |
||||
#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) |
||||
/* This code assumes sizeof(unsigned short) == 2. Do not use
|
||||
* UNALIGNED_OK if your compiler uses a different size. |
||||
*/ |
||||
if (*(ushf*)(match+best_len-1) != scan_end || |
||||
*(ushf*)match != scan_start) continue; |
||||
|
||||
/* It is not necessary to compare scan[2] and match[2] since they are
|
||||
* always equal when the other bytes match, given that the hash keys |
||||
* are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at |
||||
* strstart+3, +5, ... up to strstart+257. We check for insufficient |
||||
* lookahead only every 4th comparison; the 128th check will be made |
||||
* at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is |
||||
* necessary to put more guard bytes at the end of the window, or |
||||
* to check more often for insufficient lookahead. |
||||
*/ |
||||
Assert(scan[2] == match[2], "scan[2]?"); |
||||
scan++, match++; |
||||
do { |
||||
} while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && |
||||
*(ushf*)(scan+=2) == *(ushf*)(match+=2) && |
||||
*(ushf*)(scan+=2) == *(ushf*)(match+=2) && |
||||
*(ushf*)(scan+=2) == *(ushf*)(match+=2) && |
||||
scan < strend); |
||||
/* The funny "do {}" generates better code on most compilers */ |
||||
|
||||
/* Here, scan <= window+strstart+257 */ |
||||
Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); |
||||
if (*scan == *match) scan++; |
||||
|
||||
len = (MAX_MATCH - 1) - (int)(strend-scan); |
||||
scan = strend - (MAX_MATCH-1); |
||||
|
||||
#else /* UNALIGNED_OK */ |
||||
|
||||
if (match[best_len] != scan_end || |
||||
match[best_len-1] != scan_end1 || |
||||
*match != *scan || |
||||
*++match != scan[1]) continue; |
||||
|
||||
/* The check at best_len-1 can be removed because it will be made
|
||||
* again later. (This heuristic is not always a win.) |
||||
* It is not necessary to compare scan[2] and match[2] since they |
||||
* are always equal when the other bytes match, given that |
||||
* the hash keys are equal and that HASH_BITS >= 8. |
||||
*/ |
||||
scan += 2, match++; |
||||
Assert(*scan == *match, "match[2]?"); |
||||
|
||||
/* We check for insufficient lookahead only every 8th comparison;
|
||||
* the 256th check will be made at strstart+258. |
||||
*/ |
||||
do { |
||||
} while (*++scan == *++match && *++scan == *++match && |
||||
*++scan == *++match && *++scan == *++match && |
||||
*++scan == *++match && *++scan == *++match && |
||||
*++scan == *++match && *++scan == *++match && |
||||
scan < strend); |
||||
|
||||
Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); |
||||
|
||||
len = MAX_MATCH - (int)(strend - scan); |
||||
scan = strend - MAX_MATCH; |
||||
|
||||
#endif /* UNALIGNED_OK */ |
||||
|
||||
if (len > best_len) { |
||||
s->match_start = cur_match; |
||||
best_len = len; |
||||
if (len >= nice_match) break; |
||||
#ifdef UNALIGNED_OK |
||||
scan_end = *(ushf*)(scan+best_len-1); |
||||
#else |
||||
scan_end1 = scan[best_len-1]; |
||||
scan_end = scan[best_len]; |
||||
#endif |
||||
} |
||||
} while ((cur_match = prev[cur_match & wmask]) > limit |
||||
&& --chain_length != 0); |
||||
|
||||
if ((uInt)best_len <= s->lookahead) return (uInt)best_len; |
||||
return s->lookahead; |
||||
} |
||||
|
||||
#endif /* ASMV */ |
||||
/* gvmat32.c -- C portion of the optimized longest_match for 32 bits x86
|
||||
* Copyright (C) 1995-1996 Jean-loup Gailly and Gilles Vollant. |
||||
* File written by Gilles Vollant, by modifiying the longest_match |
||||
* from Jean-loup Gailly in deflate.c |
||||
* it prepare all parameters and call the assembly longest_match_gvasm |
||||
* longest_match execute standard C code is wmask != 0x7fff |
||||
* (assembly code is faster with a fixed wmask) |
||||
* |
||||
* Read comment at beginning of gvmat32.asm for more information |
||||
*/ |
||||
|
||||
#if defined(ASMV) && (!defined(NOOLDPENTIUMCODE)) |
||||
#include "deflate.h" |
||||
|
||||
/* if your C compiler don't add underline before function name,
|
||||
define ADD_UNDERLINE_ASMFUNC */ |
||||
#ifdef ADD_UNDERLINE_ASMFUNC |
||||
#define longest_match_7fff _longest_match_7fff |
||||
#define longest_match_686 _longest_match_686 |
||||
#define cpudetect32 _cpudetect32 |
||||
#endif |
||||
|
||||
|
||||
unsigned long cpudetect32(); |
||||
|
||||
uInt longest_match_c( |
||||
deflate_state *s, |
||||
IPos cur_match); /* current match */ |
||||
|
||||
|
||||
uInt longest_match_7fff( |
||||
deflate_state *s, |
||||
IPos cur_match); /* current match */ |
||||
|
||||
uInt longest_match_686( |
||||
deflate_state *s, |
||||
IPos cur_match); /* current match */ |
||||
|
||||
|
||||
static uInt iIsPPro=2; |
||||
|
||||
void match_init () |
||||
{ |
||||
iIsPPro = (((cpudetect32()/0x100)&0xf)>=6) ? 1 : 0; |
||||
} |
||||
|
||||
uInt longest_match( |
||||
deflate_state *s, |
||||
IPos cur_match) /* current match */ |
||||
{ |
||||
if (iIsPPro!=0) |
||||
return longest_match_686(s,cur_match); |
||||
|
||||
if (s->w_mask != 0x7fff) |
||||
return longest_match_686(s,cur_match); |
||||
|
||||
/* now ((s->w_mask == 0x7fff) && (iIsPPro==0)) */ |
||||
return longest_match_7fff(s,cur_match); |
||||
} |
||||
|
||||
|
||||
#endif /* defined(ASMV) && (!defined(NOOLDPENTIUMCODE)) */ |
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,63 +1,67 @@ |
||||
Change in 1.01b (20 may 04) |
||||
- Integrate patch from Debian package (submited by Mark Brown) |
||||
- Add tools mztools from Xavier Roche |
||||
|
||||
Change in 1.01 (8 may 04) |
||||
- fix buffer overrun risk in unzip.c (Xavier Roche) |
||||
- fix a minor buffer insecurity in minizip.c (Mike Whittaker) |
||||
|
||||
Change in 1.00: (10 sept 03) |
||||
- rename to 1.00 |
||||
- cosmetic code change |
||||
|
||||
Change in 0.22: (19 May 03) |
||||
- crypting support (unless you define NOCRYPT) |
||||
- append file in existing zipfile |
||||
|
||||
Change in 0.21: (10 Mar 03) |
||||
- bug fixes |
||||
|
||||
Change in 0.17: (27 Jan 02) |
||||
- bug fixes |
||||
|
||||
Change in 0.16: (19 Jan 02) |
||||
- Support of ioapi for virtualize zip file access |
||||
|
||||
Change in 0.15: (19 Mar 98) |
||||
- fix memory leak in minizip.c |
||||
|
||||
Change in 0.14: (10 Mar 98) |
||||
- fix bugs in minizip.c sample for zipping big file |
||||
- fix problem in month in date handling |
||||
- fix bug in unzlocal_GetCurrentFileInfoInternal in unzip.c for |
||||
comment handling |
||||
|
||||
Change in 0.13: (6 Mar 98) |
||||
- fix bugs in zip.c |
||||
- add real minizip sample |
||||
|
||||
Change in 0.12: (4 Mar 98) |
||||
- add zip.c and zip.h for creates .zip file |
||||
- fix change_file_date in miniunz.c for Unix (Jean-loup Gailly) |
||||
- fix miniunz.c for file without specific record for directory |
||||
|
||||
Change in 0.11: (3 Mar 98) |
||||
- fix bug in unzGetCurrentFileInfo for get extra field and comment |
||||
- enhance miniunz sample, remove the bad unztst.c sample |
||||
|
||||
Change in 0.10: (2 Mar 98) |
||||
- fix bug in unzReadCurrentFile |
||||
- rename unzip* to unz* function and structure |
||||
- remove Windows-like hungary notation variable name |
||||
- modify some structure in unzip.h |
||||
- add somes comment in source |
||||
- remove unzipGetcCurrentFile function |
||||
- replace ZUNZEXPORT by ZEXPORT |
||||
- add unzGetLocalExtrafield for get the local extrafield info |
||||
- add a new sample, miniunz.c |
||||
|
||||
Change in 0.4: (25 Feb 98) |
||||
- suppress the type unzipFileInZip. |
||||
Only on file in the zipfile can be open at the same time |
||||
- fix somes typo in code |
||||
- added tm_unz structure in unzip_file_info (date/time in readable format) |
||||
Change in 1.01e (12 feb 05) |
||||
- Fix in zipOpen2 for globalcomment (Rolf Kalbermatter) |
||||
- Fix possible memory leak in unzip.c (Zoran Stevanovic) |
||||
|
||||
Change in 1.01b (20 may 04) |
||||
- Integrate patch from Debian package (submited by Mark Brown) |
||||
- Add tools mztools from Xavier Roche |
||||
|
||||
Change in 1.01 (8 may 04) |
||||
- fix buffer overrun risk in unzip.c (Xavier Roche) |
||||
- fix a minor buffer insecurity in minizip.c (Mike Whittaker) |
||||
|
||||
Change in 1.00: (10 sept 03) |
||||
- rename to 1.00 |
||||
- cosmetic code change |
||||
|
||||
Change in 0.22: (19 May 03) |
||||
- crypting support (unless you define NOCRYPT) |
||||
- append file in existing zipfile |
||||
|
||||
Change in 0.21: (10 Mar 03) |
||||
- bug fixes |
||||
|
||||
Change in 0.17: (27 Jan 02) |
||||
- bug fixes |
||||
|
||||
Change in 0.16: (19 Jan 02) |
||||
- Support of ioapi for virtualize zip file access |
||||
|
||||
Change in 0.15: (19 Mar 98) |
||||
- fix memory leak in minizip.c |
||||
|
||||
Change in 0.14: (10 Mar 98) |
||||
- fix bugs in minizip.c sample for zipping big file |
||||
- fix problem in month in date handling |
||||
- fix bug in unzlocal_GetCurrentFileInfoInternal in unzip.c for |
||||
comment handling |
||||
|
||||
Change in 0.13: (6 Mar 98) |
||||
- fix bugs in zip.c |
||||
- add real minizip sample |
||||
|
||||
Change in 0.12: (4 Mar 98) |
||||
- add zip.c and zip.h for creates .zip file |
||||
- fix change_file_date in miniunz.c for Unix (Jean-loup Gailly) |
||||
- fix miniunz.c for file without specific record for directory |
||||
|
||||
Change in 0.11: (3 Mar 98) |
||||
- fix bug in unzGetCurrentFileInfo for get extra field and comment |
||||
- enhance miniunz sample, remove the bad unztst.c sample |
||||
|
||||
Change in 0.10: (2 Mar 98) |
||||
- fix bug in unzReadCurrentFile |
||||
- rename unzip* to unz* function and structure |
||||
- remove Windows-like hungary notation variable name |
||||
- modify some structure in unzip.h |
||||
- add somes comment in source |
||||
- remove unzipGetcCurrentFile function |
||||
- replace ZUNZEXPORT by ZEXPORT |
||||
- add unzGetLocalExtrafield for get the local extrafield info |
||||
- add a new sample, miniunz.c |
||||
|
||||
Change in 0.4: (25 Feb 98) |
||||
- suppress the type unzipFileInZip. |
||||
Only on file in the zipfile can be open at the same time |
||||
- fix somes typo in code |
||||
- added tm_unz structure in unzip_file_info (date/time in readable format) |
||||
|
@ -1,25 +1,25 @@ |
||||
CC=cc
|
||||
CFLAGS=-O -I../..
|
||||
|
||||
UNZ_OBJS = miniunz.o unzip.o ioapi.o ../../libz.a
|
||||
ZIP_OBJS = minizip.o zip.o ioapi.o ../../libz.a
|
||||
|
||||
.c.o: |
||||
$(CC) -c $(CFLAGS) $*.c
|
||||
|
||||
all: miniunz minizip |
||||
|
||||
miniunz: $(UNZ_OBJS) |
||||
$(CC) $(CFLAGS) -o $@ $(UNZ_OBJS)
|
||||
|
||||
minizip: $(ZIP_OBJS) |
||||
$(CC) $(CFLAGS) -o $@ $(ZIP_OBJS)
|
||||
|
||||
test: miniunz minizip |
||||
./minizip test readme.txt
|
||||
./miniunz -l test.zip
|
||||
mv readme.txt readme.old
|
||||
./miniunz test.zip
|
||||
|
||||
clean: |
||||
/bin/rm -f *.o *~ minizip miniunz
|
||||
CC=cc
|
||||
CFLAGS=-O -I../..
|
||||
|
||||
UNZ_OBJS = miniunz.o unzip.o ioapi.o ../../libz.a
|
||||
ZIP_OBJS = minizip.o zip.o ioapi.o ../../libz.a
|
||||
|
||||
.c.o: |
||||
$(CC) -c $(CFLAGS) $*.c
|
||||
|
||||
all: miniunz minizip |
||||
|
||||
miniunz: $(UNZ_OBJS) |
||||
$(CC) $(CFLAGS) -o $@ $(UNZ_OBJS)
|
||||
|
||||
minizip: $(ZIP_OBJS) |
||||
$(CC) $(CFLAGS) -o $@ $(ZIP_OBJS)
|
||||
|
||||
test: miniunz minizip |
||||
./minizip test readme.txt
|
||||
./miniunz -l test.zip
|
||||
mv readme.txt readme.old
|
||||
./miniunz test.zip
|
||||
|
||||
clean: |
||||
/bin/rm -f *.o *~ minizip miniunz
|
||||
|
@ -1,132 +1,132 @@ |
||||
/* crypt.h -- base code for crypt/uncrypt ZIPfile
|
||||
|
||||
|
||||
Version 1.01, May 8th, 2004 |
||||
|
||||
Copyright (C) 1998-2004 Gilles Vollant |
||||
|
||||
This code is a modified version of crypting code in Infozip distribution |
||||
|
||||
The encryption/decryption parts of this source code (as opposed to the |
||||
non-echoing password parts) were originally written in Europe. The |
||||
whole source package can be freely distributed, including from the USA. |
||||
(Prior to January 2000, re-export from the US was a violation of US law.) |
||||
|
||||
This encryption code is a direct transcription of the algorithm from |
||||
Roger Schlafly, described by Phil Katz in the file appnote.txt. This |
||||
file (appnote.txt) is distributed with the PKZIP program (even in the |
||||
version without encryption capabilities). |
||||
|
||||
If you don't need crypting in your application, just define symbols |
||||
NOCRYPT and NOUNCRYPT. |
||||
|
||||
This code support the "Traditional PKWARE Encryption". |
||||
|
||||
The new AES encryption added on Zip format by Winzip (see the page |
||||
http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong
|
||||
Encryption is not supported. |
||||
*/ |
||||
|
||||
#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) |
||||
|
||||
/***********************************************************************
|
||||
* Return the next byte in the pseudo-random sequence |
||||
*/ |
||||
static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) |
||||
{ |
||||
unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an
|
||||
* unpredictable manner on 16-bit systems; not a problem |
||||
* with any known compiler so far, though */ |
||||
|
||||
temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; |
||||
return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); |
||||
} |
||||
|
||||
/***********************************************************************
|
||||
* Update the encryption keys with the next byte of plain text |
||||
*/ |
||||
static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) |
||||
{ |
||||
(*(pkeys+0)) = CRC32((*(pkeys+0)), c); |
||||
(*(pkeys+1)) += (*(pkeys+0)) & 0xff; |
||||
(*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; |
||||
{ |
||||
register int keyshift = (int)((*(pkeys+1)) >> 24); |
||||
(*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); |
||||
} |
||||
return c; |
||||
} |
||||
|
||||
|
||||
/***********************************************************************
|
||||
* Initialize the encryption keys and the random header according to |
||||
* the given password. |
||||
*/ |
||||
static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) |
||||
{ |
||||
*(pkeys+0) = 305419896L; |
||||
*(pkeys+1) = 591751049L; |
||||
*(pkeys+2) = 878082192L; |
||||
while (*passwd != '\0') { |
||||
update_keys(pkeys,pcrc_32_tab,(int)*passwd); |
||||
passwd++; |
||||
} |
||||
} |
||||
|
||||
#define zdecode(pkeys,pcrc_32_tab,c) \ |
||||
(update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) |
||||
|
||||
#define zencode(pkeys,pcrc_32_tab,c,t) \ |
||||
(t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) |
||||
|
||||
#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED |
||||
|
||||
#define RAND_HEAD_LEN 12 |
||||
/* "last resort" source for second part of crypt seed pattern */ |
||||
# ifndef ZCR_SEED2 |
||||
# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ |
||||
# endif |
||||
|
||||
static int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting) |
||||
const char *passwd; /* password string */ |
||||
unsigned char *buf; /* where to write header */ |
||||
int bufSize; |
||||
unsigned long* pkeys; |
||||
const unsigned long* pcrc_32_tab; |
||||
unsigned long crcForCrypting; |
||||
{ |
||||
int n; /* index in random header */ |
||||
int t; /* temporary */ |
||||
int c; /* random byte */ |
||||
unsigned char header[RAND_HEAD_LEN-2]; /* random header */ |
||||
static unsigned calls = 0; /* ensure different random header each time */ |
||||
|
||||
if (bufSize<RAND_HEAD_LEN) |
||||
return 0; |
||||
|
||||
/* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the
|
||||
* output of rand() to get less predictability, since rand() is |
||||
* often poorly implemented. |
||||
*/ |
||||
if (++calls == 1) |
||||
{ |
||||
srand((unsigned)(time(NULL) ^ ZCR_SEED2)); |
||||
} |
||||
init_keys(passwd, pkeys, pcrc_32_tab); |
||||
for (n = 0; n < RAND_HEAD_LEN-2; n++) |
||||
{ |
||||
c = (rand() >> 7) & 0xff; |
||||
header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); |
||||
} |
||||
/* Encrypt random header (last two bytes is high word of crc) */ |
||||
init_keys(passwd, pkeys, pcrc_32_tab); |
||||
for (n = 0; n < RAND_HEAD_LEN-2; n++) |
||||
{ |
||||
buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); |
||||
} |
||||
buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); |
||||
buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); |
||||
return n; |
||||
} |
||||
|
||||
#endif |
||||
/* crypt.h -- base code for crypt/uncrypt ZIPfile
|
||||
|
||||
|
||||
Version 1.01e, February 12th, 2005 |
||||
|
||||
Copyright (C) 1998-2005 Gilles Vollant |
||||
|
||||
This code is a modified version of crypting code in Infozip distribution |
||||
|
||||
The encryption/decryption parts of this source code (as opposed to the |
||||
non-echoing password parts) were originally written in Europe. The |
||||
whole source package can be freely distributed, including from the USA. |
||||
(Prior to January 2000, re-export from the US was a violation of US law.) |
||||
|
||||
This encryption code is a direct transcription of the algorithm from |
||||
Roger Schlafly, described by Phil Katz in the file appnote.txt. This |
||||
file (appnote.txt) is distributed with the PKZIP program (even in the |
||||
version without encryption capabilities). |
||||
|
||||
If you don't need crypting in your application, just define symbols |
||||
NOCRYPT and NOUNCRYPT. |
||||
|
||||
This code support the "Traditional PKWARE Encryption". |
||||
|
||||
The new AES encryption added on Zip format by Winzip (see the page |
||||
http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong
|
||||
Encryption is not supported. |
||||
*/ |
||||
|
||||
#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) |
||||
|
||||
/***********************************************************************
|
||||
* Return the next byte in the pseudo-random sequence |
||||
*/ |
||||
static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) |
||||
{ |
||||
unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an
|
||||
* unpredictable manner on 16-bit systems; not a problem |
||||
* with any known compiler so far, though */ |
||||
|
||||
temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; |
||||
return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); |
||||
} |
||||
|
||||
/***********************************************************************
|
||||
* Update the encryption keys with the next byte of plain text |
||||
*/ |
||||
static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) |
||||
{ |
||||
(*(pkeys+0)) = CRC32((*(pkeys+0)), c); |
||||
(*(pkeys+1)) += (*(pkeys+0)) & 0xff; |
||||
(*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; |
||||
{ |
||||
register int keyshift = (int)((*(pkeys+1)) >> 24); |
||||
(*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); |
||||
} |
||||
return c; |
||||
} |
||||
|
||||
|
||||
/***********************************************************************
|
||||
* Initialize the encryption keys and the random header according to |
||||
* the given password. |
||||
*/ |
||||
static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) |
||||
{ |
||||
*(pkeys+0) = 305419896L; |
||||
*(pkeys+1) = 591751049L; |
||||
*(pkeys+2) = 878082192L; |
||||
while (*passwd != '\0') { |
||||
update_keys(pkeys,pcrc_32_tab,(int)*passwd); |
||||
passwd++; |
||||
} |
||||
} |
||||
|
||||
#define zdecode(pkeys,pcrc_32_tab,c) \ |
||||
(update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) |
||||
|
||||
#define zencode(pkeys,pcrc_32_tab,c,t) \ |
||||
(t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) |
||||
|
||||
#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED |
||||
|
||||
#define RAND_HEAD_LEN 12 |
||||
/* "last resort" source for second part of crypt seed pattern */ |
||||
# ifndef ZCR_SEED2 |
||||
# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ |
||||
# endif |
||||
|
||||
static int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting) |
||||
const char *passwd; /* password string */ |
||||
unsigned char *buf; /* where to write header */ |
||||
int bufSize; |
||||
unsigned long* pkeys; |
||||
const unsigned long* pcrc_32_tab; |
||||
unsigned long crcForCrypting; |
||||
{ |
||||
int n; /* index in random header */ |
||||
int t; /* temporary */ |
||||
int c; /* random byte */ |
||||
unsigned char header[RAND_HEAD_LEN-2]; /* random header */ |
||||
static unsigned calls = 0; /* ensure different random header each time */ |
||||
|
||||
if (bufSize<RAND_HEAD_LEN) |
||||
return 0; |
||||
|
||||
/* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the
|
||||
* output of rand() to get less predictability, since rand() is |
||||
* often poorly implemented. |
||||
*/ |
||||
if (++calls == 1) |
||||
{ |
||||
srand((unsigned)(time(NULL) ^ ZCR_SEED2)); |
||||
} |
||||
init_keys(passwd, pkeys, pcrc_32_tab); |
||||
for (n = 0; n < RAND_HEAD_LEN-2; n++) |
||||
{ |
||||
c = (rand() >> 7) & 0xff; |
||||
header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); |
||||
} |
||||
/* Encrypt random header (last two bytes is high word of crc) */ |
||||
init_keys(passwd, pkeys, pcrc_32_tab); |
||||
for (n = 0; n < RAND_HEAD_LEN-2; n++) |
||||
{ |
||||
buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); |
||||
} |
||||
buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); |
||||
buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); |
||||
return n; |
||||
} |
||||
|
||||
#endif |
||||
|
@ -1,177 +1,177 @@ |
||||
/* ioapi.c -- IO base function header for compress/uncompress .zip
|
||||
files using zlib + zip or unzip API |
||||
|
||||
Version 1.01, May 8th, 2004 |
||||
|
||||
Copyright (C) 1998-2004 Gilles Vollant |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
|
||||
#include "zlib.h" |
||||
#include "ioapi.h" |
||||
|
||||
|
||||
|
||||
/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ |
||||
|
||||
#ifndef SEEK_CUR |
||||
#define SEEK_CUR 1 |
||||
#endif |
||||
|
||||
#ifndef SEEK_END |
||||
#define SEEK_END 2 |
||||
#endif |
||||
|
||||
#ifndef SEEK_SET |
||||
#define SEEK_SET 0 |
||||
#endif |
||||
|
||||
voidpf ZCALLBACK fopen_file_func OF(( |
||||
voidpf opaque, |
||||
const char* filename, |
||||
int mode)); |
||||
|
||||
uLong ZCALLBACK fread_file_func OF(( |
||||
voidpf opaque, |
||||
voidpf stream, |
||||
void* buf, |
||||
uLong size)); |
||||
|
||||
uLong ZCALLBACK fwrite_file_func OF(( |
||||
voidpf opaque, |
||||
voidpf stream, |
||||
const void* buf, |
||||
uLong size)); |
||||
|
||||
long ZCALLBACK ftell_file_func OF(( |
||||
voidpf opaque, |
||||
voidpf stream)); |
||||
|
||||
long ZCALLBACK fseek_file_func OF(( |
||||
voidpf opaque, |
||||
voidpf stream, |
||||
uLong offset, |
||||
int origin)); |
||||
|
||||
int ZCALLBACK fclose_file_func OF(( |
||||
voidpf opaque, |
||||
voidpf stream)); |
||||
|
||||
int ZCALLBACK ferror_file_func OF(( |
||||
voidpf opaque, |
||||
voidpf stream)); |
||||
|
||||
|
||||
voidpf ZCALLBACK fopen_file_func (opaque, filename, mode) |
||||
voidpf opaque; |
||||
const char* filename; |
||||
int mode; |
||||
{ |
||||
FILE* file = NULL; |
||||
const char* mode_fopen = NULL; |
||||
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) |
||||
mode_fopen = "rb"; |
||||
else |
||||
if (mode & ZLIB_FILEFUNC_MODE_EXISTING) |
||||
mode_fopen = "r+b"; |
||||
else |
||||
if (mode & ZLIB_FILEFUNC_MODE_CREATE) |
||||
mode_fopen = "wb"; |
||||
|
||||
if ((filename!=NULL) && (mode_fopen != NULL)) |
||||
file = fopen(filename, mode_fopen); |
||||
return file; |
||||
} |
||||
|
||||
|
||||
uLong ZCALLBACK fread_file_func (opaque, stream, buf, size) |
||||
voidpf opaque; |
||||
voidpf stream; |
||||
void* buf; |
||||
uLong size; |
||||
{ |
||||
uLong ret; |
||||
ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); |
||||
return ret; |
||||
} |
||||
|
||||
|
||||
uLong ZCALLBACK fwrite_file_func (opaque, stream, buf, size) |
||||
voidpf opaque; |
||||
voidpf stream; |
||||
const void* buf; |
||||
uLong size; |
||||
{ |
||||
uLong ret; |
||||
ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); |
||||
return ret; |
||||
} |
||||
|
||||
long ZCALLBACK ftell_file_func (opaque, stream) |
||||
voidpf opaque; |
||||
voidpf stream; |
||||
{ |
||||
long ret; |
||||
ret = ftell((FILE *)stream); |
||||
return ret; |
||||
} |
||||
|
||||
long ZCALLBACK fseek_file_func (opaque, stream, offset, origin) |
||||
voidpf opaque; |
||||
voidpf stream; |
||||
uLong offset; |
||||
int origin; |
||||
{ |
||||
int fseek_origin=0; |
||||
long ret; |
||||
switch (origin) |
||||
{ |
||||
case ZLIB_FILEFUNC_SEEK_CUR : |
||||
fseek_origin = SEEK_CUR; |
||||
break; |
||||
case ZLIB_FILEFUNC_SEEK_END : |
||||
fseek_origin = SEEK_END; |
||||
break; |
||||
case ZLIB_FILEFUNC_SEEK_SET : |
||||
fseek_origin = SEEK_SET; |
||||
break; |
||||
default: return -1; |
||||
} |
||||
ret = 0; |
||||
fseek((FILE *)stream, offset, fseek_origin); |
||||
return ret; |
||||
} |
||||
|
||||
int ZCALLBACK fclose_file_func (opaque, stream) |
||||
voidpf opaque; |
||||
voidpf stream; |
||||
{ |
||||
int ret; |
||||
ret = fclose((FILE *)stream); |
||||
return ret; |
||||
} |
||||
|
||||
int ZCALLBACK ferror_file_func (opaque, stream) |
||||
voidpf opaque; |
||||
voidpf stream; |
||||
{ |
||||
int ret; |
||||
ret = ferror((FILE *)stream); |
||||
return ret; |
||||
} |
||||
|
||||
void fill_fopen_filefunc (pzlib_filefunc_def) |
||||
zlib_filefunc_def* pzlib_filefunc_def; |
||||
{ |
||||
pzlib_filefunc_def->zopen_file = fopen_file_func; |
||||
pzlib_filefunc_def->zread_file = fread_file_func; |
||||
pzlib_filefunc_def->zwrite_file = fwrite_file_func; |
||||
pzlib_filefunc_def->ztell_file = ftell_file_func; |
||||
pzlib_filefunc_def->zseek_file = fseek_file_func; |
||||
pzlib_filefunc_def->zclose_file = fclose_file_func; |
||||
pzlib_filefunc_def->zerror_file = ferror_file_func; |
||||
pzlib_filefunc_def->opaque = NULL; |
||||
} |
||||
/* ioapi.c -- IO base function header for compress/uncompress .zip
|
||||
files using zlib + zip or unzip API |
||||
|
||||
Version 1.01e, February 12th, 2005 |
||||
|
||||
Copyright (C) 1998-2005 Gilles Vollant |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
|
||||
#include "zlib.h" |
||||
#include "ioapi.h" |
||||
|
||||
|
||||
|
||||
/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ |
||||
|
||||
#ifndef SEEK_CUR |
||||
#define SEEK_CUR 1 |
||||
#endif |
||||
|
||||
#ifndef SEEK_END |
||||
#define SEEK_END 2 |
||||
#endif |
||||
|
||||
#ifndef SEEK_SET |
||||
#define SEEK_SET 0 |
||||
#endif |
||||
|
||||
voidpf ZCALLBACK fopen_file_func OF(( |
||||
voidpf opaque, |
||||
const char* filename, |
||||
int mode)); |
||||
|
||||
uLong ZCALLBACK fread_file_func OF(( |
||||
voidpf opaque, |
||||
voidpf stream, |
||||
void* buf, |
||||
uLong size)); |
||||
|
||||
uLong ZCALLBACK fwrite_file_func OF(( |
||||
voidpf opaque, |
||||
voidpf stream, |
||||
const void* buf, |
||||
uLong size)); |
||||
|
||||
long ZCALLBACK ftell_file_func OF(( |
||||
voidpf opaque, |
||||
voidpf stream)); |
||||
|
||||
long ZCALLBACK fseek_file_func OF(( |
||||
voidpf opaque, |
||||
voidpf stream, |
||||
uLong offset, |
||||
int origin)); |
||||
|
||||
int ZCALLBACK fclose_file_func OF(( |
||||
voidpf opaque, |
||||
voidpf stream)); |
||||
|
||||
int ZCALLBACK ferror_file_func OF(( |
||||
voidpf opaque, |
||||
voidpf stream)); |
||||
|
||||
|
||||
voidpf ZCALLBACK fopen_file_func (opaque, filename, mode) |
||||
voidpf opaque; |
||||
const char* filename; |
||||
int mode; |
||||
{ |
||||
FILE* file = NULL; |
||||
const char* mode_fopen = NULL; |
||||
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) |
||||
mode_fopen = "rb"; |
||||
else |
||||
if (mode & ZLIB_FILEFUNC_MODE_EXISTING) |
||||
mode_fopen = "r+b"; |
||||
else |
||||
if (mode & ZLIB_FILEFUNC_MODE_CREATE) |
||||
mode_fopen = "wb"; |
||||
|
||||
if ((filename!=NULL) && (mode_fopen != NULL)) |
||||
file = fopen(filename, mode_fopen); |
||||
return file; |
||||
} |
||||
|
||||
|
||||
uLong ZCALLBACK fread_file_func (opaque, stream, buf, size) |
||||
voidpf opaque; |
||||
voidpf stream; |
||||
void* buf; |
||||
uLong size; |
||||
{ |
||||
uLong ret; |
||||
ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); |
||||
return ret; |
||||
} |
||||
|
||||
|
||||
uLong ZCALLBACK fwrite_file_func (opaque, stream, buf, size) |
||||
voidpf opaque; |
||||
voidpf stream; |
||||
const void* buf; |
||||
uLong size; |
||||
{ |
||||
uLong ret; |
||||
ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); |
||||
return ret; |
||||
} |
||||
|
||||
long ZCALLBACK ftell_file_func (opaque, stream) |
||||
voidpf opaque; |
||||
voidpf stream; |
||||
{ |
||||
long ret; |
||||
ret = ftell((FILE *)stream); |
||||
return ret; |
||||
} |
||||
|
||||
long ZCALLBACK fseek_file_func (opaque, stream, offset, origin) |
||||
voidpf opaque; |
||||
voidpf stream; |
||||
uLong offset; |
||||
int origin; |
||||
{ |
||||
int fseek_origin=0; |
||||
long ret; |
||||
switch (origin) |
||||
{ |
||||
case ZLIB_FILEFUNC_SEEK_CUR : |
||||
fseek_origin = SEEK_CUR; |
||||
break; |
||||
case ZLIB_FILEFUNC_SEEK_END : |
||||
fseek_origin = SEEK_END; |
||||
break; |
||||
case ZLIB_FILEFUNC_SEEK_SET : |
||||
fseek_origin = SEEK_SET; |
||||
break; |
||||
default: return -1; |
||||
} |
||||
ret = 0; |
||||
fseek((FILE *)stream, offset, fseek_origin); |
||||
return ret; |
||||
} |
||||
|
||||
int ZCALLBACK fclose_file_func (opaque, stream) |
||||
voidpf opaque; |
||||
voidpf stream; |
||||
{ |
||||
int ret; |
||||
ret = fclose((FILE *)stream); |
||||
return ret; |
||||
} |
||||
|
||||
int ZCALLBACK ferror_file_func (opaque, stream) |
||||
voidpf opaque; |
||||
voidpf stream; |
||||
{ |
||||
int ret; |
||||
ret = ferror((FILE *)stream); |
||||
return ret; |
||||
} |
||||
|
||||
void fill_fopen_filefunc (pzlib_filefunc_def) |
||||
zlib_filefunc_def* pzlib_filefunc_def; |
||||
{ |
||||
pzlib_filefunc_def->zopen_file = fopen_file_func; |
||||
pzlib_filefunc_def->zread_file = fread_file_func; |
||||
pzlib_filefunc_def->zwrite_file = fwrite_file_func; |
||||
pzlib_filefunc_def->ztell_file = ftell_file_func; |
||||
pzlib_filefunc_def->zseek_file = fseek_file_func; |
||||
pzlib_filefunc_def->zclose_file = fclose_file_func; |
||||
pzlib_filefunc_def->zerror_file = ferror_file_func; |
||||
pzlib_filefunc_def->opaque = NULL; |
||||
} |
||||
|
@ -1,75 +1,75 @@ |
||||
/* ioapi.h -- IO base function header for compress/uncompress .zip
|
||||
files using zlib + zip or unzip API |
||||
|
||||
Version 1.01, May 8th, 2004 |
||||
|
||||
Copyright (C) 1998-2004 Gilles Vollant |
||||
*/ |
||||
|
||||
#ifndef _ZLIBIOAPI_H |
||||
#define _ZLIBIOAPI_H |
||||
|
||||
|
||||
#define ZLIB_FILEFUNC_SEEK_CUR (1) |
||||
#define ZLIB_FILEFUNC_SEEK_END (2) |
||||
#define ZLIB_FILEFUNC_SEEK_SET (0) |
||||
|
||||
#define ZLIB_FILEFUNC_MODE_READ (1) |
||||
#define ZLIB_FILEFUNC_MODE_WRITE (2) |
||||
#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) |
||||
|
||||
#define ZLIB_FILEFUNC_MODE_EXISTING (4) |
||||
#define ZLIB_FILEFUNC_MODE_CREATE (8) |
||||
|
||||
|
||||
#ifndef ZCALLBACK |
||||
|
||||
#if (defined(WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) |
||||
#define ZCALLBACK CALLBACK |
||||
#else |
||||
#define ZCALLBACK |
||||
#endif |
||||
#endif |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); |
||||
typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); |
||||
typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); |
||||
typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); |
||||
typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); |
||||
typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); |
||||
typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); |
||||
|
||||
typedef struct zlib_filefunc_def_s |
||||
{ |
||||
open_file_func zopen_file; |
||||
read_file_func zread_file; |
||||
write_file_func zwrite_file; |
||||
tell_file_func ztell_file; |
||||
seek_file_func zseek_file; |
||||
close_file_func zclose_file; |
||||
testerror_file_func zerror_file; |
||||
voidpf opaque; |
||||
} zlib_filefunc_def; |
||||
|
||||
|
||||
|
||||
void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); |
||||
|
||||
#define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size)) |
||||
#define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size)) |
||||
#define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream)) |
||||
#define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode)) |
||||
#define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream)) |
||||
#define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream)) |
||||
|
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif |
||||
|
||||
/* ioapi.h -- IO base function header for compress/uncompress .zip
|
||||
files using zlib + zip or unzip API |
||||
|
||||
Version 1.01e, February 12th, 2005 |
||||
|
||||
Copyright (C) 1998-2005 Gilles Vollant |
||||
*/ |
||||
|
||||
#ifndef _ZLIBIOAPI_H |
||||
#define _ZLIBIOAPI_H |
||||
|
||||
|
||||
#define ZLIB_FILEFUNC_SEEK_CUR (1) |
||||
#define ZLIB_FILEFUNC_SEEK_END (2) |
||||
#define ZLIB_FILEFUNC_SEEK_SET (0) |
||||
|
||||
#define ZLIB_FILEFUNC_MODE_READ (1) |
||||
#define ZLIB_FILEFUNC_MODE_WRITE (2) |
||||
#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) |
||||
|
||||
#define ZLIB_FILEFUNC_MODE_EXISTING (4) |
||||
#define ZLIB_FILEFUNC_MODE_CREATE (8) |
||||
|
||||
|
||||
#ifndef ZCALLBACK |
||||
|
||||
#if (defined(WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) |
||||
#define ZCALLBACK CALLBACK |
||||
#else |
||||
#define ZCALLBACK |
||||
#endif |
||||
#endif |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); |
||||
typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); |
||||
typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); |
||||
typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); |
||||
typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); |
||||
typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); |
||||
typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); |
||||
|
||||
typedef struct zlib_filefunc_def_s |
||||
{ |
||||
open_file_func zopen_file; |
||||
read_file_func zread_file; |
||||
write_file_func zwrite_file; |
||||
tell_file_func ztell_file; |
||||
seek_file_func zseek_file; |
||||
close_file_func zclose_file; |
||||
testerror_file_func zerror_file; |
||||
voidpf opaque; |
||||
} zlib_filefunc_def; |
||||
|
||||
|
||||
|
||||
void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); |
||||
|
||||
#define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size)) |
||||
#define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size)) |
||||
#define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream)) |
||||
#define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode)) |
||||
#define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream)) |
||||
#define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream)) |
||||
|
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif |
||||
|
||||
|
@ -1,270 +1,270 @@ |
||||
/* iowin32.c -- IO base function header for compress/uncompress .zip
|
||||
files using zlib + zip or unzip API |
||||
This IO API version uses the Win32 API (for Microsoft Windows) |
||||
|
||||
Version 1.01, May 8th, 2004 |
||||
|
||||
Copyright (C) 1998-2004 Gilles Vollant |
||||
*/ |
||||
|
||||
#include <stdlib.h> |
||||
|
||||
#include "zlib.h" |
||||
#include "ioapi.h" |
||||
#include "iowin32.h" |
||||
|
||||
#ifndef INVALID_HANDLE_VALUE |
||||
#define INVALID_HANDLE_VALUE (0xFFFFFFFF) |
||||
#endif |
||||
|
||||
#ifndef INVALID_SET_FILE_POINTER |
||||
#define INVALID_SET_FILE_POINTER ((DWORD)-1) |
||||
#endif |
||||
|
||||
voidpf ZCALLBACK win32_open_file_func OF(( |
||||
voidpf opaque, |
||||
const char* filename, |
||||
int mode)); |
||||
|
||||
uLong ZCALLBACK win32_read_file_func OF(( |
||||
voidpf opaque, |
||||
voidpf stream, |
||||
void* buf, |
||||
uLong size)); |
||||
|
||||
uLong ZCALLBACK win32_write_file_func OF(( |
||||
voidpf opaque, |
||||
voidpf stream, |
||||
const void* buf, |
||||
uLong size)); |
||||
|
||||
long ZCALLBACK win32_tell_file_func OF(( |
||||
voidpf opaque, |
||||
voidpf stream)); |
||||
|
||||
long ZCALLBACK win32_seek_file_func OF(( |
||||
voidpf opaque, |
||||
voidpf stream, |
||||
uLong offset, |
||||
int origin)); |
||||
|
||||
int ZCALLBACK win32_close_file_func OF(( |
||||
voidpf opaque, |
||||
voidpf stream)); |
||||
|
||||
int ZCALLBACK win32_error_file_func OF(( |
||||
voidpf opaque, |
||||
voidpf stream)); |
||||
|
||||
typedef struct |
||||
{ |
||||
HANDLE hf; |
||||
int error; |
||||
} WIN32FILE_IOWIN; |
||||
|
||||
voidpf ZCALLBACK win32_open_file_func (opaque, filename, mode) |
||||
voidpf opaque; |
||||
const char* filename; |
||||
int mode; |
||||
{ |
||||
const char* mode_fopen = NULL; |
||||
DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; |
||||
HANDLE hFile = 0; |
||||
voidpf ret=NULL; |
||||
|
||||
dwDesiredAccess = dwShareMode = dwFlagsAndAttributes = 0; |
||||
|
||||
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) |
||||
{ |
||||
dwDesiredAccess = GENERIC_READ; |
||||
dwCreationDisposition = OPEN_EXISTING; |
||||
dwShareMode = FILE_SHARE_READ; |
||||
} |
||||
else |
||||
if (mode & ZLIB_FILEFUNC_MODE_EXISTING) |
||||
{ |
||||
dwDesiredAccess = GENERIC_WRITE | GENERIC_READ; |
||||
dwCreationDisposition = OPEN_EXISTING; |
||||
} |
||||
else |
||||
if (mode & ZLIB_FILEFUNC_MODE_CREATE) |
||||
{ |
||||
dwDesiredAccess = GENERIC_WRITE | GENERIC_READ; |
||||
dwCreationDisposition = CREATE_ALWAYS; |
||||
} |
||||
|
||||
if ((filename!=NULL) && (dwDesiredAccess != 0)) |
||||
hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, |
||||
dwCreationDisposition, dwFlagsAndAttributes, NULL); |
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE) |
||||
hFile = NULL; |
||||
|
||||
if (hFile != NULL) |
||||
{ |
||||
WIN32FILE_IOWIN w32fiow; |
||||
w32fiow.hf = hFile; |
||||
w32fiow.error = 0; |
||||
ret = malloc(sizeof(WIN32FILE_IOWIN)); |
||||
if (ret==NULL) |
||||
CloseHandle(hFile); |
||||
else *((WIN32FILE_IOWIN*)ret) = w32fiow; |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
|
||||
uLong ZCALLBACK win32_read_file_func (opaque, stream, buf, size) |
||||
voidpf opaque; |
||||
voidpf stream; |
||||
void* buf; |
||||
uLong size; |
||||
{ |
||||
uLong ret=0; |
||||
HANDLE hFile = NULL; |
||||
if (stream!=NULL) |
||||
hFile = ((WIN32FILE_IOWIN*)stream) -> hf; |
||||
if (hFile != NULL) |
||||
if (!ReadFile(hFile, buf, size, &ret, NULL)) |
||||
{ |
||||
DWORD dwErr = GetLastError(); |
||||
if (dwErr == ERROR_HANDLE_EOF) |
||||
dwErr = 0; |
||||
((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; |
||||
} |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
|
||||
uLong ZCALLBACK win32_write_file_func (opaque, stream, buf, size) |
||||
voidpf opaque; |
||||
voidpf stream; |
||||
const void* buf; |
||||
uLong size; |
||||
{ |
||||
uLong ret=0; |
||||
HANDLE hFile = NULL; |
||||
if (stream!=NULL) |
||||
hFile = ((WIN32FILE_IOWIN*)stream) -> hf; |
||||
|
||||
if (hFile !=NULL) |
||||
if (!WriteFile(hFile, buf, size, &ret, NULL)) |
||||
{ |
||||
DWORD dwErr = GetLastError(); |
||||
if (dwErr == ERROR_HANDLE_EOF) |
||||
dwErr = 0; |
||||
((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; |
||||
} |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
long ZCALLBACK win32_tell_file_func (opaque, stream) |
||||
voidpf opaque; |
||||
voidpf stream; |
||||
{ |
||||
long ret=-1; |
||||
HANDLE hFile = NULL; |
||||
if (stream!=NULL) |
||||
hFile = ((WIN32FILE_IOWIN*)stream) -> hf; |
||||
if (hFile != NULL) |
||||
{ |
||||
DWORD dwSet = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); |
||||
if (dwSet == INVALID_SET_FILE_POINTER) |
||||
{ |
||||
DWORD dwErr = GetLastError(); |
||||
((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; |
||||
ret = -1; |
||||
} |
||||
else |
||||
ret=(long)dwSet; |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
long ZCALLBACK win32_seek_file_func (opaque, stream, offset, origin) |
||||
voidpf opaque; |
||||
voidpf stream; |
||||
uLong offset; |
||||
int origin; |
||||
{ |
||||
DWORD dwMoveMethod=0xFFFFFFFF; |
||||
HANDLE hFile = NULL; |
||||
|
||||
long ret=-1; |
||||
if (stream!=NULL) |
||||
hFile = ((WIN32FILE_IOWIN*)stream) -> hf; |
||||
switch (origin) |
||||
{ |
||||
case ZLIB_FILEFUNC_SEEK_CUR : |
||||
dwMoveMethod = FILE_CURRENT; |
||||
break; |
||||
case ZLIB_FILEFUNC_SEEK_END : |
||||
dwMoveMethod = FILE_END; |
||||
break; |
||||
case ZLIB_FILEFUNC_SEEK_SET : |
||||
dwMoveMethod = FILE_BEGIN; |
||||
break; |
||||
default: return -1; |
||||
} |
||||
|
||||
if (hFile != NULL) |
||||
{ |
||||
DWORD dwSet = SetFilePointer(hFile, offset, NULL, dwMoveMethod); |
||||
if (dwSet == INVALID_SET_FILE_POINTER) |
||||
{ |
||||
DWORD dwErr = GetLastError(); |
||||
((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; |
||||
ret = -1; |
||||
} |
||||
else |
||||
ret=0; |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
int ZCALLBACK win32_close_file_func (opaque, stream) |
||||
voidpf opaque; |
||||
voidpf stream; |
||||
{ |
||||
int ret=-1; |
||||
|
||||
if (stream!=NULL) |
||||
{ |
||||
HANDLE hFile; |
||||
hFile = ((WIN32FILE_IOWIN*)stream) -> hf; |
||||
if (hFile != NULL) |
||||
{ |
||||
CloseHandle(hFile); |
||||
ret=0; |
||||
} |
||||
free(stream); |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
int ZCALLBACK win32_error_file_func (opaque, stream) |
||||
voidpf opaque; |
||||
voidpf stream; |
||||
{ |
||||
int ret=-1; |
||||
if (stream!=NULL) |
||||
{ |
||||
ret = ((WIN32FILE_IOWIN*)stream) -> error; |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
void fill_win32_filefunc (pzlib_filefunc_def) |
||||
zlib_filefunc_def* pzlib_filefunc_def; |
||||
{ |
||||
pzlib_filefunc_def->zopen_file = win32_open_file_func; |
||||
pzlib_filefunc_def->zread_file = win32_read_file_func; |
||||
pzlib_filefunc_def->zwrite_file = win32_write_file_func; |
||||
pzlib_filefunc_def->ztell_file = win32_tell_file_func; |
||||
pzlib_filefunc_def->zseek_file = win32_seek_file_func; |
||||
pzlib_filefunc_def->zclose_file = win32_close_file_func; |
||||
pzlib_filefunc_def->zerror_file = win32_error_file_func; |
||||
pzlib_filefunc_def->opaque=NULL; |
||||
} |
||||
/* iowin32.c -- IO base function header for compress/uncompress .zip
|
||||
files using zlib + zip or unzip API |
||||
This IO API version uses the Win32 API (for Microsoft Windows) |
||||
|
||||
Version 1.01e, February 12th, 2005 |
||||
|
||||
Copyright (C) 1998-2005 Gilles Vollant |
||||
*/ |
||||
|
||||
#include <stdlib.h> |
||||
|
||||
#include "zlib.h" |
||||
#include "ioapi.h" |
||||
#include "iowin32.h" |
||||
|
||||
#ifndef INVALID_HANDLE_VALUE |
||||
#define INVALID_HANDLE_VALUE (0xFFFFFFFF) |
||||
#endif |
||||
|
||||
#ifndef INVALID_SET_FILE_POINTER |
||||
#define INVALID_SET_FILE_POINTER ((DWORD)-1) |
||||
#endif |
||||
|
||||
voidpf ZCALLBACK win32_open_file_func OF(( |
||||
voidpf opaque, |
||||
const char* filename, |
||||
int mode)); |
||||
|
||||
uLong ZCALLBACK win32_read_file_func OF(( |
||||
voidpf opaque, |
||||
voidpf stream, |
||||
void* buf, |
||||
uLong size)); |
||||
|
||||
uLong ZCALLBACK win32_write_file_func OF(( |
||||
voidpf opaque, |
||||
voidpf stream, |
||||
const void* buf, |
||||
uLong size)); |
||||
|
||||
long ZCALLBACK win32_tell_file_func OF(( |
||||
voidpf opaque, |
||||
voidpf stream)); |
||||
|
||||
long ZCALLBACK win32_seek_file_func OF(( |
||||
voidpf opaque, |
||||
voidpf stream, |
||||
uLong offset, |
||||
int origin)); |
||||
|
||||
int ZCALLBACK win32_close_file_func OF(( |
||||
voidpf opaque, |
||||
voidpf stream)); |
||||
|
||||
int ZCALLBACK win32_error_file_func OF(( |
||||
voidpf opaque, |
||||
voidpf stream)); |
||||
|
||||
typedef struct |
||||
{ |
||||
HANDLE hf; |
||||
int error; |
||||
} WIN32FILE_IOWIN; |
||||
|
||||
voidpf ZCALLBACK win32_open_file_func (opaque, filename, mode) |
||||
voidpf opaque; |
||||
const char* filename; |
||||
int mode; |
||||
{ |
||||
const char* mode_fopen = NULL; |
||||
DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; |
||||
HANDLE hFile = 0; |
||||
voidpf ret=NULL; |
||||
|
||||
dwDesiredAccess = dwShareMode = dwFlagsAndAttributes = 0; |
||||
|
||||
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) |
||||
{ |
||||
dwDesiredAccess = GENERIC_READ; |
||||
dwCreationDisposition = OPEN_EXISTING; |
||||
dwShareMode = FILE_SHARE_READ; |
||||
} |
||||
else |
||||
if (mode & ZLIB_FILEFUNC_MODE_EXISTING) |
||||
{ |
||||
dwDesiredAccess = GENERIC_WRITE | GENERIC_READ; |
||||
dwCreationDisposition = OPEN_EXISTING; |
||||
} |
||||
else |
||||
if (mode & ZLIB_FILEFUNC_MODE_CREATE) |
||||
{ |
||||
dwDesiredAccess = GENERIC_WRITE | GENERIC_READ; |
||||
dwCreationDisposition = CREATE_ALWAYS; |
||||
} |
||||
|
||||
if ((filename!=NULL) && (dwDesiredAccess != 0)) |
||||
hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, |
||||
dwCreationDisposition, dwFlagsAndAttributes, NULL); |
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE) |
||||
hFile = NULL; |
||||
|
||||
if (hFile != NULL) |
||||
{ |
||||
WIN32FILE_IOWIN w32fiow; |
||||
w32fiow.hf = hFile; |
||||
w32fiow.error = 0; |
||||
ret = malloc(sizeof(WIN32FILE_IOWIN)); |
||||
if (ret==NULL) |
||||
CloseHandle(hFile); |
||||
else *((WIN32FILE_IOWIN*)ret) = w32fiow; |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
|
||||
uLong ZCALLBACK win32_read_file_func (opaque, stream, buf, size) |
||||
voidpf opaque; |
||||
voidpf stream; |
||||
void* buf; |
||||
uLong size; |
||||
{ |
||||
uLong ret=0; |
||||
HANDLE hFile = NULL; |
||||
if (stream!=NULL) |
||||
hFile = ((WIN32FILE_IOWIN*)stream) -> hf; |
||||
if (hFile != NULL) |
||||
if (!ReadFile(hFile, buf, size, &ret, NULL)) |
||||
{ |
||||
DWORD dwErr = GetLastError(); |
||||
if (dwErr == ERROR_HANDLE_EOF) |
||||
dwErr = 0; |
||||
((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; |
||||
} |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
|
||||
uLong ZCALLBACK win32_write_file_func (opaque, stream, buf, size) |
||||
voidpf opaque; |
||||
voidpf stream; |
||||
const void* buf; |
||||
uLong size; |
||||
{ |
||||
uLong ret=0; |
||||
HANDLE hFile = NULL; |
||||
if (stream!=NULL) |
||||
hFile = ((WIN32FILE_IOWIN*)stream) -> hf; |
||||
|
||||
if (hFile !=NULL) |
||||
if (!WriteFile(hFile, buf, size, &ret, NULL)) |
||||
{ |
||||
DWORD dwErr = GetLastError(); |
||||
if (dwErr == ERROR_HANDLE_EOF) |
||||
dwErr = 0; |
||||
((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; |
||||
} |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
long ZCALLBACK win32_tell_file_func (opaque, stream) |
||||
voidpf opaque; |
||||
voidpf stream; |
||||
{ |
||||
long ret=-1; |
||||
HANDLE hFile = NULL; |
||||
if (stream!=NULL) |
||||
hFile = ((WIN32FILE_IOWIN*)stream) -> hf; |
||||
if (hFile != NULL) |
||||
{ |
||||
DWORD dwSet = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); |
||||
if (dwSet == INVALID_SET_FILE_POINTER) |
||||
{ |
||||
DWORD dwErr = GetLastError(); |
||||
((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; |
||||
ret = -1; |
||||
} |
||||
else |
||||
ret=(long)dwSet; |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
long ZCALLBACK win32_seek_file_func (opaque, stream, offset, origin) |
||||
voidpf opaque; |
||||
voidpf stream; |
||||
uLong offset; |
||||
int origin; |
||||
{ |
||||
DWORD dwMoveMethod=0xFFFFFFFF; |
||||
HANDLE hFile = NULL; |
||||
|
||||
long ret=-1; |
||||
if (stream!=NULL) |
||||
hFile = ((WIN32FILE_IOWIN*)stream) -> hf; |
||||
switch (origin) |
||||
{ |
||||
case ZLIB_FILEFUNC_SEEK_CUR : |
||||
dwMoveMethod = FILE_CURRENT; |
||||
break; |
||||
case ZLIB_FILEFUNC_SEEK_END : |
||||
dwMoveMethod = FILE_END; |
||||
break; |
||||
case ZLIB_FILEFUNC_SEEK_SET : |
||||
dwMoveMethod = FILE_BEGIN; |
||||
break; |
||||
default: return -1; |
||||
} |
||||
|
||||
if (hFile != NULL) |
||||
{ |
||||
DWORD dwSet = SetFilePointer(hFile, offset, NULL, dwMoveMethod); |
||||
if (dwSet == INVALID_SET_FILE_POINTER) |
||||
{ |
||||
DWORD dwErr = GetLastError(); |
||||
((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; |
||||
ret = -1; |
||||
} |
||||
else |
||||
ret=0; |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
int ZCALLBACK win32_close_file_func (opaque, stream) |
||||
voidpf opaque; |
||||
voidpf stream; |
||||
{ |
||||
int ret=-1; |
||||
|
||||
if (stream!=NULL) |
||||
{ |
||||
HANDLE hFile; |
||||
hFile = ((WIN32FILE_IOWIN*)stream) -> hf; |
||||
if (hFile != NULL) |
||||
{ |
||||
CloseHandle(hFile); |
||||
ret=0; |
||||
} |
||||
free(stream); |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
int ZCALLBACK win32_error_file_func (opaque, stream) |
||||
voidpf opaque; |
||||
voidpf stream; |
||||
{ |
||||
int ret=-1; |
||||
if (stream!=NULL) |
||||
{ |
||||
ret = ((WIN32FILE_IOWIN*)stream) -> error; |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
void fill_win32_filefunc (pzlib_filefunc_def) |
||||
zlib_filefunc_def* pzlib_filefunc_def; |
||||
{ |
||||
pzlib_filefunc_def->zopen_file = win32_open_file_func; |
||||
pzlib_filefunc_def->zread_file = win32_read_file_func; |
||||
pzlib_filefunc_def->zwrite_file = win32_write_file_func; |
||||
pzlib_filefunc_def->ztell_file = win32_tell_file_func; |
||||
pzlib_filefunc_def->zseek_file = win32_seek_file_func; |
||||
pzlib_filefunc_def->zclose_file = win32_close_file_func; |
||||
pzlib_filefunc_def->zerror_file = win32_error_file_func; |
||||
pzlib_filefunc_def->opaque=NULL; |
||||
} |
||||
|
@ -1,21 +1,21 @@ |
||||
/* iowin32.h -- IO base function header for compress/uncompress .zip
|
||||
files using zlib + zip or unzip API |
||||
This IO API version uses the Win32 API (for Microsoft Windows) |
||||
|
||||
Version 1.01, May 8th, 2004 |
||||
|
||||
Copyright (C) 1998-2004 Gilles Vollant |
||||
*/ |
||||
|
||||
#include <windows.h> |
||||
|
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
void fill_win32_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
/* iowin32.h -- IO base function header for compress/uncompress .zip
|
||||
files using zlib + zip or unzip API |
||||
This IO API version uses the Win32 API (for Microsoft Windows) |
||||
|
||||
Version 1.01e, February 12th, 2005 |
||||
|
||||
Copyright (C) 1998-2005 Gilles Vollant |
||||
*/ |
||||
|
||||
#include <windows.h> |
||||
|
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
void fill_win32_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,420 +1,420 @@ |
||||
/*
|
||||
minizip.c |
||||
Version 1.01b, May 30th, 2004 |
||||
|
||||
Copyright (C) 1998-2004 Gilles Vollant |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <time.h> |
||||
#include <errno.h> |
||||
#include <fcntl.h> |
||||
|
||||
#ifdef unix |
||||
# include <unistd.h> |
||||
# include <utime.h> |
||||
# include <sys/types.h> |
||||
# include <sys/stat.h> |
||||
#else |
||||
# include <direct.h> |
||||
# include <io.h> |
||||
#endif |
||||
|
||||
#include "zip.h" |
||||
|
||||
#ifdef WIN32 |
||||
#define USEWIN32IOAPI |
||||
#include "iowin32.h" |
||||
#endif |
||||
|
||||
|
||||
|
||||
#define WRITEBUFFERSIZE (16384) |
||||
#define MAXFILENAME (256) |
||||
|
||||
#ifdef WIN32 |
||||
uLong filetime(f, tmzip, dt) |
||||
char *f; /* name of file to get info on */ |
||||
tm_zip *tmzip; /* return value: access, modific. and creation times */ |
||||
uLong *dt; /* dostime */ |
||||
{ |
||||
int ret = 0; |
||||
{ |
||||
FILETIME ftLocal; |
||||
HANDLE hFind; |
||||
WIN32_FIND_DATA ff32; |
||||
|
||||
hFind = FindFirstFile(f,&ff32); |
||||
if (hFind != INVALID_HANDLE_VALUE) |
||||
{ |
||||
FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal); |
||||
FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0); |
||||
FindClose(hFind); |
||||
ret = 1; |
||||
} |
||||
} |
||||
return ret; |
||||
} |
||||
#else |
||||
#ifdef unix |
||||
uLong filetime(f, tmzip, dt) |
||||
char *f; /* name of file to get info on */ |
||||
tm_zip *tmzip; /* return value: access, modific. and creation times */ |
||||
uLong *dt; /* dostime */ |
||||
{ |
||||
int ret=0; |
||||
struct stat s; /* results of stat() */ |
||||
struct tm* filedate; |
||||
time_t tm_t=0; |
||||
|
||||
if (strcmp(f,"-")!=0) |
||||
{ |
||||
char name[MAXFILENAME+1]; |
||||
int len = strlen(f); |
||||
if (len > MAXFILENAME) |
||||
len = MAXFILENAME; |
||||
|
||||
strncpy(name, f,MAXFILENAME-1); |
||||
/* strncpy doesnt append the trailing NULL, of the string is too long. */ |
||||
name[ MAXFILENAME ] = '\0'; |
||||
|
||||
if (name[len - 1] == '/') |
||||
name[len - 1] = '\0'; |
||||
/* not all systems allow stat'ing a file with / appended */ |
||||
if (stat(name,&s)==0) |
||||
{ |
||||
tm_t = s.st_mtime; |
||||
ret = 1; |
||||
} |
||||
} |
||||
filedate = localtime(&tm_t); |
||||
|
||||
tmzip->tm_sec = filedate->tm_sec; |
||||
tmzip->tm_min = filedate->tm_min; |
||||
tmzip->tm_hour = filedate->tm_hour; |
||||
tmzip->tm_mday = filedate->tm_mday; |
||||
tmzip->tm_mon = filedate->tm_mon ; |
||||
tmzip->tm_year = filedate->tm_year; |
||||
|
||||
return ret; |
||||
} |
||||
#else |
||||
uLong filetime(f, tmzip, dt) |
||||
char *f; /* name of file to get info on */ |
||||
tm_zip *tmzip; /* return value: access, modific. and creation times */ |
||||
uLong *dt; /* dostime */ |
||||
{ |
||||
return 0; |
||||
} |
||||
#endif |
||||
#endif |
||||
|
||||
|
||||
|
||||
|
||||
int check_exist_file(filename) |
||||
const char* filename; |
||||
{ |
||||
FILE* ftestexist; |
||||
int ret = 1; |
||||
ftestexist = fopen(filename,"rb"); |
||||
if (ftestexist==NULL) |
||||
ret = 0; |
||||
else |
||||
fclose(ftestexist); |
||||
return ret; |
||||
} |
||||
|
||||
void do_banner() |
||||
{ |
||||
printf("MiniZip 1.01b, demo of zLib + Zip package written by Gilles Vollant\n"); |
||||
printf("more info at http://www.winimage.com/zLibDll/unzip.html\n\n"); |
||||
} |
||||
|
||||
void do_help() |
||||
{ |
||||
printf("Usage : minizip [-o] [-a] [-0 to -9] [-p password] file.zip [files_to_add]\n\n" \
|
||||
" -o Overwrite existing file.zip\n" \
|
||||
" -a Append to existing file.zip\n" \
|
||||
" -0 Store only\n" \
|
||||
" -1 Compress faster\n" \
|
||||
" -9 Compress better\n\n"); |
||||
} |
||||
|
||||
/* calculate the CRC32 of a file,
|
||||
because to encrypt a file, we need known the CRC32 of the file before */ |
||||
int getFileCrc(const char* filenameinzip,void*buf,unsigned long size_buf,unsigned long* result_crc) |
||||
{ |
||||
unsigned long calculate_crc=0; |
||||
int err=ZIP_OK; |
||||
FILE * fin = fopen(filenameinzip,"rb"); |
||||
unsigned long size_read = 0; |
||||
unsigned long total_read = 0; |
||||
if (fin==NULL) |
||||
{ |
||||
err = ZIP_ERRNO; |
||||
} |
||||
|
||||
if (err == ZIP_OK) |
||||
do |
||||
{ |
||||
err = ZIP_OK; |
||||
size_read = (int)fread(buf,1,size_buf,fin); |
||||
if (size_read < size_buf) |
||||
if (feof(fin)==0) |
||||
{ |
||||
printf("error in reading %s\n",filenameinzip); |
||||
err = ZIP_ERRNO; |
||||
} |
||||
|
||||
if (size_read>0) |
||||
calculate_crc = crc32(calculate_crc,buf,size_read); |
||||
total_read += size_read; |
||||
|
||||
} while ((err == ZIP_OK) && (size_read>0)); |
||||
|
||||
if (fin) |
||||
fclose(fin); |
||||
|
||||
*result_crc=calculate_crc; |
||||
printf("file %s crc %x\n",filenameinzip,calculate_crc); |
||||
return err; |
||||
} |
||||
|
||||
int main(argc,argv) |
||||
int argc; |
||||
char *argv[]; |
||||
{ |
||||
int i; |
||||
int opt_overwrite=0; |
||||
int opt_compress_level=Z_DEFAULT_COMPRESSION; |
||||
int zipfilenamearg = 0; |
||||
char filename_try[MAXFILENAME+16]; |
||||
int zipok; |
||||
int err=0; |
||||
int size_buf=0; |
||||
void* buf=NULL; |
||||
const char* password=NULL; |
||||
|
||||
|
||||
do_banner(); |
||||
if (argc==1) |
||||
{ |
||||
do_help(); |
||||
return 0; |
||||
} |
||||
else |
||||
{ |
||||
for (i=1;i<argc;i++) |
||||
{ |
||||
if ((*argv[i])=='-') |
||||
{ |
||||
const char *p=argv[i]+1; |
||||
|
||||
while ((*p)!='\0') |
||||
{ |
||||
char c=*(p++);; |
||||
if ((c=='o') || (c=='O')) |
||||
opt_overwrite = 1; |
||||
if ((c=='a') || (c=='A')) |
||||
opt_overwrite = 2; |
||||
if ((c>='0') && (c<='9')) |
||||
opt_compress_level = c-'0'; |
||||
|
||||
if (((c=='p') || (c=='P')) && (i+1<argc)) |
||||
{ |
||||
password=argv[i+1]; |
||||
i++; |
||||
} |
||||
} |
||||
} |
||||
else |
||||
if (zipfilenamearg == 0) |
||||
zipfilenamearg = i ; |
||||
} |
||||
} |
||||
|
||||
size_buf = WRITEBUFFERSIZE; |
||||
buf = (void*)malloc(size_buf); |
||||
if (buf==NULL) |
||||
{ |
||||
printf("Error allocating memory\n"); |
||||
return ZIP_INTERNALERROR; |
||||
} |
||||
|
||||
if (zipfilenamearg==0) |
||||
zipok=0; |
||||
else |
||||
{ |
||||
int i,len; |
||||
int dot_found=0; |
||||
|
||||
zipok = 1 ; |
||||
strncpy(filename_try, argv[zipfilenamearg],MAXFILENAME-1); |
||||
/* strncpy doesnt append the trailing NULL, of the string is too long. */ |
||||
filename_try[ MAXFILENAME ] = '\0'; |
||||
|
||||
len=(int)strlen(filename_try); |
||||
for (i=0;i<len;i++) |
||||
if (filename_try[i]=='.') |
||||
dot_found=1; |
||||
|
||||
if (dot_found==0) |
||||
strcat(filename_try,".zip"); |
||||
|
||||
if (opt_overwrite==2) |
||||
{ |
||||
/* if the file don't exist, we not append file */ |
||||
if (check_exist_file(filename_try)==0) |
||||
opt_overwrite=1; |
||||
} |
||||
else |
||||
if (opt_overwrite==0) |
||||
if (check_exist_file(filename_try)!=0) |
||||
{ |
||||
char rep=0; |
||||
do |
||||
{ |
||||
char answer[128]; |
||||
int ret; |
||||
printf("The file %s exists. Overwrite ? [y]es, [n]o, [a]ppend : ",filename_try); |
||||
ret = scanf("%1s",answer); |
||||
if (ret != 1) |
||||
{ |
||||
exit(EXIT_FAILURE); |
||||
} |
||||
rep = answer[0] ; |
||||
if ((rep>='a') && (rep<='z')) |
||||
rep -= 0x20; |
||||
} |
||||
while ((rep!='Y') && (rep!='N') && (rep!='A')); |
||||
if (rep=='N') |
||||
zipok = 0; |
||||
if (rep=='A') |
||||
opt_overwrite = 2; |
||||
} |
||||
} |
||||
|
||||
if (zipok==1) |
||||
{ |
||||
zipFile zf; |
||||
int errclose; |
||||
# ifdef USEWIN32IOAPI |
||||
zlib_filefunc_def ffunc; |
||||
fill_win32_filefunc(&ffunc); |
||||
zf = zipOpen2(filename_try,(opt_overwrite==2) ? 2 : 0,NULL,&ffunc); |
||||
# else |
||||
zf = zipOpen(filename_try,(opt_overwrite==2) ? 2 : 0); |
||||
# endif |
||||
|
||||
if (zf == NULL) |
||||
{ |
||||
printf("error opening %s\n",filename_try); |
||||
err= ZIP_ERRNO; |
||||
} |
||||
else |
||||
printf("creating %s\n",filename_try); |
||||
|
||||
for (i=zipfilenamearg+1;(i<argc) && (err==ZIP_OK);i++) |
||||
{ |
||||
if (!((((*(argv[i]))=='-') || ((*(argv[i]))=='/')) && |
||||
((argv[i][1]=='o') || (argv[i][1]=='O') || |
||||
(argv[i][1]=='a') || (argv[i][1]=='A') || |
||||
(argv[i][1]=='p') || (argv[i][1]=='P') || |
||||
((argv[i][1]>='0') || (argv[i][1]<='9'))) && |
||||
(strlen(argv[i]) == 2))) |
||||
{ |
||||
FILE * fin; |
||||
int size_read; |
||||
const char* filenameinzip = argv[i]; |
||||
zip_fileinfo zi; |
||||
unsigned long crcFile=0; |
||||
|
||||
zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour = |
||||
zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0; |
||||
zi.dosDate = 0; |
||||
zi.internal_fa = 0; |
||||
zi.external_fa = 0; |
||||
filetime(filenameinzip,&zi.tmz_date,&zi.dosDate); |
||||
|
||||
/*
|
||||
err = zipOpenNewFileInZip(zf,filenameinzip,&zi, |
||||
NULL,0,NULL,0,NULL / * comment * /, |
||||
(opt_compress_level != 0) ? Z_DEFLATED : 0, |
||||
opt_compress_level); |
||||
*/ |
||||
if ((password != NULL) && (err==ZIP_OK)) |
||||
err = getFileCrc(filenameinzip,buf,size_buf,&crcFile); |
||||
|
||||
err = zipOpenNewFileInZip3(zf,filenameinzip,&zi, |
||||
NULL,0,NULL,0,NULL /* comment*/, |
||||
(opt_compress_level != 0) ? Z_DEFLATED : 0, |
||||
opt_compress_level,0, |
||||
/* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */ |
||||
-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, |
||||
password,crcFile); |
||||
|
||||
if (err != ZIP_OK) |
||||
printf("error in opening %s in zipfile\n",filenameinzip); |
||||
else |
||||
{ |
||||
fin = fopen(filenameinzip,"rb"); |
||||
if (fin==NULL) |
||||
{ |
||||
err=ZIP_ERRNO; |
||||
printf("error in opening %s for reading\n",filenameinzip); |
||||
} |
||||
} |
||||
|
||||
if (err == ZIP_OK) |
||||
do |
||||
{ |
||||
err = ZIP_OK; |
||||
size_read = (int)fread(buf,1,size_buf,fin); |
||||
if (size_read < size_buf) |
||||
if (feof(fin)==0) |
||||
{ |
||||
printf("error in reading %s\n",filenameinzip); |
||||
err = ZIP_ERRNO; |
||||
} |
||||
|
||||
if (size_read>0) |
||||
{ |
||||
err = zipWriteInFileInZip (zf,buf,size_read); |
||||
if (err<0) |
||||
{ |
||||
printf("error in writing %s in the zipfile\n", |
||||
filenameinzip); |
||||
} |
||||
|
||||
} |
||||
} while ((err == ZIP_OK) && (size_read>0)); |
||||
|
||||
if (fin) |
||||
fclose(fin); |
||||
|
||||
if (err<0) |
||||
err=ZIP_ERRNO; |
||||
else |
||||
{ |
||||
err = zipCloseFileInZip(zf); |
||||
if (err!=ZIP_OK) |
||||
printf("error in closing %s in the zipfile\n", |
||||
filenameinzip); |
||||
} |
||||
} |
||||
} |
||||
errclose = zipClose(zf,NULL); |
||||
if (errclose != ZIP_OK) |
||||
printf("error in closing %s\n",filename_try); |
||||
} |
||||
else |
||||
{ |
||||
do_help(); |
||||
} |
||||
|
||||
free(buf); |
||||
return 0; |
||||
} |
||||
/*
|
||||
minizip.c |
||||
Version 1.01e, February 12th, 2005 |
||||
|
||||
Copyright (C) 1998-2005 Gilles Vollant |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <time.h> |
||||
#include <errno.h> |
||||
#include <fcntl.h> |
||||
|
||||
#ifdef unix |
||||
# include <unistd.h> |
||||
# include <utime.h> |
||||
# include <sys/types.h> |
||||
# include <sys/stat.h> |
||||
#else |
||||
# include <direct.h> |
||||
# include <io.h> |
||||
#endif |
||||
|
||||
#include "zip.h" |
||||
|
||||
#ifdef WIN32 |
||||
#define USEWIN32IOAPI |
||||
#include "iowin32.h" |
||||
#endif |
||||
|
||||
|
||||
|
||||
#define WRITEBUFFERSIZE (16384) |
||||
#define MAXFILENAME (256) |
||||
|
||||
#ifdef WIN32 |
||||
uLong filetime(f, tmzip, dt) |
||||
char *f; /* name of file to get info on */ |
||||
tm_zip *tmzip; /* return value: access, modific. and creation times */ |
||||
uLong *dt; /* dostime */ |
||||
{ |
||||
int ret = 0; |
||||
{ |
||||
FILETIME ftLocal; |
||||
HANDLE hFind; |
||||
WIN32_FIND_DATA ff32; |
||||
|
||||
hFind = FindFirstFile(f,&ff32); |
||||
if (hFind != INVALID_HANDLE_VALUE) |
||||
{ |
||||
FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal); |
||||
FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0); |
||||
FindClose(hFind); |
||||
ret = 1; |
||||
} |
||||
} |
||||
return ret; |
||||
} |
||||
#else |
||||
#ifdef unix |
||||
uLong filetime(f, tmzip, dt) |
||||
char *f; /* name of file to get info on */ |
||||
tm_zip *tmzip; /* return value: access, modific. and creation times */ |
||||
uLong *dt; /* dostime */ |
||||
{ |
||||
int ret=0; |
||||
struct stat s; /* results of stat() */ |
||||
struct tm* filedate; |
||||
time_t tm_t=0; |
||||
|
||||
if (strcmp(f,"-")!=0) |
||||
{ |
||||
char name[MAXFILENAME+1]; |
||||
int len = strlen(f); |
||||
if (len > MAXFILENAME) |
||||
len = MAXFILENAME; |
||||
|
||||
strncpy(name, f,MAXFILENAME-1); |
||||
/* strncpy doesnt append the trailing NULL, of the string is too long. */ |
||||
name[ MAXFILENAME ] = '\0'; |
||||
|
||||
if (name[len - 1] == '/') |
||||
name[len - 1] = '\0'; |
||||
/* not all systems allow stat'ing a file with / appended */ |
||||
if (stat(name,&s)==0) |
||||
{ |
||||
tm_t = s.st_mtime; |
||||
ret = 1; |
||||
} |
||||
} |
||||
filedate = localtime(&tm_t); |
||||
|
||||
tmzip->tm_sec = filedate->tm_sec; |
||||
tmzip->tm_min = filedate->tm_min; |
||||
tmzip->tm_hour = filedate->tm_hour; |
||||
tmzip->tm_mday = filedate->tm_mday; |
||||
tmzip->tm_mon = filedate->tm_mon ; |
||||
tmzip->tm_year = filedate->tm_year; |
||||
|
||||
return ret; |
||||
} |
||||
#else |
||||
uLong filetime(f, tmzip, dt) |
||||
char *f; /* name of file to get info on */ |
||||
tm_zip *tmzip; /* return value: access, modific. and creation times */ |
||||
uLong *dt; /* dostime */ |
||||
{ |
||||
return 0; |
||||
} |
||||
#endif |
||||
#endif |
||||
|
||||
|
||||
|
||||
|
||||
int check_exist_file(filename) |
||||
const char* filename; |
||||
{ |
||||
FILE* ftestexist; |
||||
int ret = 1; |
||||
ftestexist = fopen(filename,"rb"); |
||||
if (ftestexist==NULL) |
||||
ret = 0; |
||||
else |
||||
fclose(ftestexist); |
||||
return ret; |
||||
} |
||||
|
||||
void do_banner() |
||||
{ |
||||
printf("MiniZip 1.01b, demo of zLib + Zip package written by Gilles Vollant\n"); |
||||
printf("more info at http://www.winimage.com/zLibDll/unzip.html\n\n"); |
||||
} |
||||
|
||||
void do_help() |
||||
{ |
||||
printf("Usage : minizip [-o] [-a] [-0 to -9] [-p password] file.zip [files_to_add]\n\n" \
|
||||
" -o Overwrite existing file.zip\n" \
|
||||
" -a Append to existing file.zip\n" \
|
||||
" -0 Store only\n" \
|
||||
" -1 Compress faster\n" \
|
||||
" -9 Compress better\n\n"); |
||||
} |
||||
|
||||
/* calculate the CRC32 of a file,
|
||||
because to encrypt a file, we need known the CRC32 of the file before */ |
||||
int getFileCrc(const char* filenameinzip,void*buf,unsigned long size_buf,unsigned long* result_crc) |
||||
{ |
||||
unsigned long calculate_crc=0; |
||||
int err=ZIP_OK; |
||||
FILE * fin = fopen(filenameinzip,"rb"); |
||||
unsigned long size_read = 0; |
||||
unsigned long total_read = 0; |
||||
if (fin==NULL) |
||||
{ |
||||
err = ZIP_ERRNO; |
||||
} |
||||
|
||||
if (err == ZIP_OK) |
||||
do |
||||
{ |
||||
err = ZIP_OK; |
||||
size_read = (int)fread(buf,1,size_buf,fin); |
||||
if (size_read < size_buf) |
||||
if (feof(fin)==0) |
||||
{ |
||||
printf("error in reading %s\n",filenameinzip); |
||||
err = ZIP_ERRNO; |
||||
} |
||||
|
||||
if (size_read>0) |
||||
calculate_crc = crc32(calculate_crc,buf,size_read); |
||||
total_read += size_read; |
||||
|
||||
} while ((err == ZIP_OK) && (size_read>0)); |
||||
|
||||
if (fin) |
||||
fclose(fin); |
||||
|
||||
*result_crc=calculate_crc; |
||||
printf("file %s crc %x\n",filenameinzip,calculate_crc); |
||||
return err; |
||||
} |
||||
|
||||
int main(argc,argv) |
||||
int argc; |
||||
char *argv[]; |
||||
{ |
||||
int i; |
||||
int opt_overwrite=0; |
||||
int opt_compress_level=Z_DEFAULT_COMPRESSION; |
||||
int zipfilenamearg = 0; |
||||
char filename_try[MAXFILENAME+16]; |
||||
int zipok; |
||||
int err=0; |
||||
int size_buf=0; |
||||
void* buf=NULL; |
||||
const char* password=NULL; |
||||
|
||||
|
||||
do_banner(); |
||||
if (argc==1) |
||||
{ |
||||
do_help(); |
||||
return 0; |
||||
} |
||||
else |
||||
{ |
||||
for (i=1;i<argc;i++) |
||||
{ |
||||
if ((*argv[i])=='-') |
||||
{ |
||||
const char *p=argv[i]+1; |
||||
|
||||
while ((*p)!='\0') |
||||
{ |
||||
char c=*(p++);; |
||||
if ((c=='o') || (c=='O')) |
||||
opt_overwrite = 1; |
||||
if ((c=='a') || (c=='A')) |
||||
opt_overwrite = 2; |
||||
if ((c>='0') && (c<='9')) |
||||
opt_compress_level = c-'0'; |
||||
|
||||
if (((c=='p') || (c=='P')) && (i+1<argc)) |
||||
{ |
||||
password=argv[i+1]; |
||||
i++; |
||||
} |
||||
} |
||||
} |
||||
else |
||||
if (zipfilenamearg == 0) |
||||
zipfilenamearg = i ; |
||||
} |
||||
} |
||||
|
||||
size_buf = WRITEBUFFERSIZE; |
||||
buf = (void*)malloc(size_buf); |
||||
if (buf==NULL) |
||||
{ |
||||
printf("Error allocating memory\n"); |
||||
return ZIP_INTERNALERROR; |
||||
} |
||||
|
||||
if (zipfilenamearg==0) |
||||
zipok=0; |
||||
else |
||||
{ |
||||
int i,len; |
||||
int dot_found=0; |
||||
|
||||
zipok = 1 ; |
||||
strncpy(filename_try, argv[zipfilenamearg],MAXFILENAME-1); |
||||
/* strncpy doesnt append the trailing NULL, of the string is too long. */ |
||||
filename_try[ MAXFILENAME ] = '\0'; |
||||
|
||||
len=(int)strlen(filename_try); |
||||
for (i=0;i<len;i++) |
||||
if (filename_try[i]=='.') |
||||
dot_found=1; |
||||
|
||||
if (dot_found==0) |
||||
strcat(filename_try,".zip"); |
||||
|
||||
if (opt_overwrite==2) |
||||
{ |
||||
/* if the file don't exist, we not append file */ |
||||
if (check_exist_file(filename_try)==0) |
||||
opt_overwrite=1; |
||||
} |
||||
else |
||||
if (opt_overwrite==0) |
||||
if (check_exist_file(filename_try)!=0) |
||||
{ |
||||
char rep=0; |
||||
do |
||||
{ |
||||
char answer[128]; |
||||
int ret; |
||||
printf("The file %s exists. Overwrite ? [y]es, [n]o, [a]ppend : ",filename_try); |
||||
ret = scanf("%1s",answer); |
||||
if (ret != 1) |
||||
{ |
||||
exit(EXIT_FAILURE); |
||||
} |
||||
rep = answer[0] ; |
||||
if ((rep>='a') && (rep<='z')) |
||||
rep -= 0x20; |
||||
} |
||||
while ((rep!='Y') && (rep!='N') && (rep!='A')); |
||||
if (rep=='N') |
||||
zipok = 0; |
||||
if (rep=='A') |
||||
opt_overwrite = 2; |
||||
} |
||||
} |
||||
|
||||
if (zipok==1) |
||||
{ |
||||
zipFile zf; |
||||
int errclose; |
||||
# ifdef USEWIN32IOAPI |
||||
zlib_filefunc_def ffunc; |
||||
fill_win32_filefunc(&ffunc); |
||||
zf = zipOpen2(filename_try,(opt_overwrite==2) ? 2 : 0,NULL,&ffunc); |
||||
# else |
||||
zf = zipOpen(filename_try,(opt_overwrite==2) ? 2 : 0); |
||||
# endif |
||||
|
||||
if (zf == NULL) |
||||
{ |
||||
printf("error opening %s\n",filename_try); |
||||
err= ZIP_ERRNO; |
||||
} |
||||
else |
||||
printf("creating %s\n",filename_try); |
||||
|
||||
for (i=zipfilenamearg+1;(i<argc) && (err==ZIP_OK);i++) |
||||
{ |
||||
if (!((((*(argv[i]))=='-') || ((*(argv[i]))=='/')) && |
||||
((argv[i][1]=='o') || (argv[i][1]=='O') || |
||||
(argv[i][1]=='a') || (argv[i][1]=='A') || |
||||
(argv[i][1]=='p') || (argv[i][1]=='P') || |
||||
((argv[i][1]>='0') || (argv[i][1]<='9'))) && |
||||
(strlen(argv[i]) == 2))) |
||||
{ |
||||
FILE * fin; |
||||
int size_read; |
||||
const char* filenameinzip = argv[i]; |
||||
zip_fileinfo zi; |
||||
unsigned long crcFile=0; |
||||
|
||||
zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour = |
||||
zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0; |
||||
zi.dosDate = 0; |
||||
zi.internal_fa = 0; |
||||
zi.external_fa = 0; |
||||
filetime(filenameinzip,&zi.tmz_date,&zi.dosDate); |
||||
|
||||
/*
|
||||
err = zipOpenNewFileInZip(zf,filenameinzip,&zi, |
||||
NULL,0,NULL,0,NULL / * comment * /, |
||||
(opt_compress_level != 0) ? Z_DEFLATED : 0, |
||||
opt_compress_level); |
||||
*/ |
||||
if ((password != NULL) && (err==ZIP_OK)) |
||||
err = getFileCrc(filenameinzip,buf,size_buf,&crcFile); |
||||
|
||||
err = zipOpenNewFileInZip3(zf,filenameinzip,&zi, |
||||
NULL,0,NULL,0,NULL /* comment*/, |
||||
(opt_compress_level != 0) ? Z_DEFLATED : 0, |
||||
opt_compress_level,0, |
||||
/* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */ |
||||
-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, |
||||
password,crcFile); |
||||
|
||||
if (err != ZIP_OK) |
||||
printf("error in opening %s in zipfile\n",filenameinzip); |
||||
else |
||||
{ |
||||
fin = fopen(filenameinzip,"rb"); |
||||
if (fin==NULL) |
||||
{ |
||||
err=ZIP_ERRNO; |
||||
printf("error in opening %s for reading\n",filenameinzip); |
||||
} |
||||
} |
||||
|
||||
if (err == ZIP_OK) |
||||
do |
||||
{ |
||||
err = ZIP_OK; |
||||
size_read = (int)fread(buf,1,size_buf,fin); |
||||
if (size_read < size_buf) |
||||
if (feof(fin)==0) |
||||
{ |
||||
printf("error in reading %s\n",filenameinzip); |
||||
err = ZIP_ERRNO; |
||||
} |
||||
|
||||
if (size_read>0) |
||||
{ |
||||
err = zipWriteInFileInZip (zf,buf,size_read); |
||||
if (err<0) |
||||
{ |
||||
printf("error in writing %s in the zipfile\n", |
||||
filenameinzip); |
||||
} |
||||
|
||||
} |
||||
} while ((err == ZIP_OK) && (size_read>0)); |
||||
|
||||
if (fin) |
||||
fclose(fin); |
||||
|
||||
if (err<0) |
||||
err=ZIP_ERRNO; |
||||
else |
||||
{ |
||||
err = zipCloseFileInZip(zf); |
||||
if (err!=ZIP_OK) |
||||
printf("error in closing %s in the zipfile\n", |
||||
filenameinzip); |
||||
} |
||||
} |
||||
} |
||||
errclose = zipClose(zf,NULL); |
||||
if (errclose != ZIP_OK) |
||||
printf("error in closing %s\n",filename_try); |
||||
} |
||||
else |
||||
{ |
||||
do_help(); |
||||
} |
||||
|
||||
free(buf); |
||||
return 0; |
||||
} |
||||
|
@ -1,281 +1,281 @@ |
||||
/*
|
||||
Additional tools for Minizip |
||||
Code: Xavier Roche '2004 |
||||
License: Same as ZLIB (www.gzip.org) |
||||
*/ |
||||
|
||||
/* Code */ |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include "zlib.h" |
||||
#include "unzip.h" |
||||
|
||||
#define READ_8(adr) ((unsigned char)*(adr)) |
||||
#define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) ) |
||||
#define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) ) |
||||
|
||||
#define WRITE_8(buff, n) do { \ |
||||
*((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \
|
||||
} while(0) |
||||
#define WRITE_16(buff, n) do { \ |
||||
WRITE_8((unsigned char*)(buff), n); \
|
||||
WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \
|
||||
} while(0) |
||||
#define WRITE_32(buff, n) do { \ |
||||
WRITE_16((unsigned char*)(buff), (n) & 0xffff); \
|
||||
WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \
|
||||
} while(0) |
||||
|
||||
extern int ZEXPORT unzRepair(file, fileOut, fileOutTmp, nRecovered, bytesRecovered) |
||||
const char* file; |
||||
const char* fileOut; |
||||
const char* fileOutTmp; |
||||
uLong* nRecovered; |
||||
uLong* bytesRecovered; |
||||
{ |
||||
int err = Z_OK; |
||||
FILE* fpZip = fopen(file, "rb"); |
||||
FILE* fpOut = fopen(fileOut, "wb"); |
||||
FILE* fpOutCD = fopen(fileOutTmp, "wb"); |
||||
if (fpZip != NULL && fpOut != NULL) { |
||||
int entries = 0; |
||||
uLong totalBytes = 0; |
||||
char header[30]; |
||||
char filename[256]; |
||||
char extra[1024]; |
||||
int offset = 0; |
||||
int offsetCD = 0; |
||||
while ( fread(header, 1, 30, fpZip) == 30 ) { |
||||
int currentOffset = offset; |
||||
|
||||
/* File entry */ |
||||
if (READ_32(header) == 0x04034b50) { |
||||
unsigned int version = READ_16(header + 4); |
||||
unsigned int gpflag = READ_16(header + 6); |
||||
unsigned int method = READ_16(header + 8); |
||||
unsigned int filetime = READ_16(header + 10); |
||||
unsigned int filedate = READ_16(header + 12); |
||||
unsigned int crc = READ_32(header + 14); /* crc */ |
||||
unsigned int cpsize = READ_32(header + 18); /* compressed size */ |
||||
unsigned int uncpsize = READ_32(header + 22); /* uncompressed sz */ |
||||
unsigned int fnsize = READ_16(header + 26); /* file name length */ |
||||
unsigned int extsize = READ_16(header + 28); /* extra field length */ |
||||
filename[0] = extra[0] = '\0'; |
||||
|
||||
/* Header */ |
||||
if (fwrite(header, 1, 30, fpOut) == 30) { |
||||
offset += 30; |
||||
} else { |
||||
err = Z_ERRNO; |
||||
break; |
||||
} |
||||
|
||||
/* Filename */ |
||||
if (fnsize > 0) { |
||||
if (fread(filename, 1, fnsize, fpZip) == fnsize) { |
||||
if (fwrite(filename, 1, fnsize, fpOut) == fnsize) { |
||||
offset += fnsize; |
||||
} else { |
||||
err = Z_ERRNO; |
||||
break; |
||||
} |
||||
} else { |
||||
err = Z_ERRNO; |
||||
break; |
||||
} |
||||
} else { |
||||
err = Z_STREAM_ERROR; |
||||
break; |
||||
} |
||||
|
||||
/* Extra field */ |
||||
if (extsize > 0) { |
||||
if (fread(extra, 1, extsize, fpZip) == extsize) { |
||||
if (fwrite(extra, 1, extsize, fpOut) == extsize) { |
||||
offset += extsize; |
||||
} else { |
||||
err = Z_ERRNO; |
||||
break; |
||||
} |
||||
} else { |
||||
err = Z_ERRNO; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
/* Data */ |
||||
{ |
||||
int dataSize = cpsize; |
||||
if (dataSize == 0) { |
||||
dataSize = uncpsize; |
||||
} |
||||
if (dataSize > 0) { |
||||
char* data = malloc(dataSize); |
||||
if (data != NULL) { |
||||
if ((int)fread(data, 1, dataSize, fpZip) == dataSize) { |
||||
if ((int)fwrite(data, 1, dataSize, fpOut) == dataSize) { |
||||
offset += dataSize; |
||||
totalBytes += dataSize; |
||||
} else { |
||||
err = Z_ERRNO; |
||||
} |
||||
} else { |
||||
err = Z_ERRNO; |
||||
} |
||||
free(data); |
||||
if (err != Z_OK) { |
||||
break; |
||||
} |
||||
} else { |
||||
err = Z_MEM_ERROR; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/* Central directory entry */ |
||||
{ |
||||
char header[46]; |
||||
char* comment = ""; |
||||
int comsize = (int) strlen(comment); |
||||
WRITE_32(header, 0x02014b50); |
||||
WRITE_16(header + 4, version); |
||||
WRITE_16(header + 6, version); |
||||
WRITE_16(header + 8, gpflag); |
||||
WRITE_16(header + 10, method); |
||||
WRITE_16(header + 12, filetime); |
||||
WRITE_16(header + 14, filedate); |
||||
WRITE_32(header + 16, crc); |
||||
WRITE_32(header + 20, cpsize); |
||||
WRITE_32(header + 24, uncpsize); |
||||
WRITE_16(header + 28, fnsize); |
||||
WRITE_16(header + 30, extsize); |
||||
WRITE_16(header + 32, comsize); |
||||
WRITE_16(header + 34, 0); /* disk # */ |
||||
WRITE_16(header + 36, 0); /* int attrb */ |
||||
WRITE_32(header + 38, 0); /* ext attrb */ |
||||
WRITE_32(header + 42, currentOffset); |
||||
/* Header */ |
||||
if (fwrite(header, 1, 46, fpOutCD) == 46) { |
||||
offsetCD += 46; |
||||
|
||||
/* Filename */ |
||||
if (fnsize > 0) { |
||||
if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) { |
||||
offsetCD += fnsize; |
||||
} else { |
||||
err = Z_ERRNO; |
||||
break; |
||||
} |
||||
} else { |
||||
err = Z_STREAM_ERROR; |
||||
break; |
||||
} |
||||
|
||||
/* Extra field */ |
||||
if (extsize > 0) { |
||||
if (fwrite(extra, 1, extsize, fpOutCD) == extsize) { |
||||
offsetCD += extsize; |
||||
} else { |
||||
err = Z_ERRNO; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
/* Comment field */ |
||||
if (comsize > 0) { |
||||
if ((int)fwrite(comment, 1, comsize, fpOutCD) == comsize) { |
||||
offsetCD += comsize; |
||||
} else { |
||||
err = Z_ERRNO; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
|
||||
} else { |
||||
err = Z_ERRNO; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
/* Success */ |
||||
entries++; |
||||
|
||||
} else { |
||||
break; |
||||
} |
||||
} |
||||
|
||||
/* Final central directory */ |
||||
{ |
||||
int entriesZip = entries; |
||||
char header[22]; |
||||
char* comment = ""; // "ZIP File recovered by zlib/minizip/mztools";
|
||||
int comsize = (int) strlen(comment); |
||||
if (entriesZip > 0xffff) { |
||||
entriesZip = 0xffff; |
||||
} |
||||
WRITE_32(header, 0x06054b50); |
||||
WRITE_16(header + 4, 0); /* disk # */ |
||||
WRITE_16(header + 6, 0); /* disk # */ |
||||
WRITE_16(header + 8, entriesZip); /* hack */ |
||||
WRITE_16(header + 10, entriesZip); /* hack */ |
||||
WRITE_32(header + 12, offsetCD); /* size of CD */ |
||||
WRITE_32(header + 16, offset); /* offset to CD */ |
||||
WRITE_16(header + 20, comsize); /* comment */ |
||||
|
||||
/* Header */ |
||||
if (fwrite(header, 1, 22, fpOutCD) == 22) { |
||||
|
||||
/* Comment field */ |
||||
if (comsize > 0) { |
||||
if ((int)fwrite(comment, 1, comsize, fpOutCD) != comsize) { |
||||
err = Z_ERRNO; |
||||
} |
||||
} |
||||
|
||||
} else { |
||||
err = Z_ERRNO; |
||||
} |
||||
} |
||||
|
||||
/* Final merge (file + central directory) */ |
||||
fclose(fpOutCD); |
||||
if (err == Z_OK) { |
||||
fpOutCD = fopen(fileOutTmp, "rb"); |
||||
if (fpOutCD != NULL) { |
||||
int nRead; |
||||
char buffer[8192]; |
||||
while ( (nRead = fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) { |
||||
if ((int)fwrite(buffer, 1, nRead, fpOut) != nRead) { |
||||
err = Z_ERRNO; |
||||
break; |
||||
} |
||||
} |
||||
fclose(fpOutCD); |
||||
} |
||||
} |
||||
|
||||
/* Close */ |
||||
fclose(fpZip); |
||||
fclose(fpOut); |
||||
|
||||
/* Wipe temporary file */ |
||||
(void)remove(fileOutTmp); |
||||
|
||||
/* Number of recovered entries */ |
||||
if (err == Z_OK) { |
||||
if (nRecovered != NULL) { |
||||
*nRecovered = entries; |
||||
} |
||||
if (bytesRecovered != NULL) { |
||||
*bytesRecovered = totalBytes; |
||||
} |
||||
} |
||||
} else { |
||||
err = Z_STREAM_ERROR; |
||||
} |
||||
return err; |
||||
} |
||||
/*
|
||||
Additional tools for Minizip |
||||
Code: Xavier Roche '2004 |
||||
License: Same as ZLIB (www.gzip.org) |
||||
*/ |
||||
|
||||
/* Code */ |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include "zlib.h" |
||||
#include "unzip.h" |
||||
|
||||
#define READ_8(adr) ((unsigned char)*(adr)) |
||||
#define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) ) |
||||
#define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) ) |
||||
|
||||
#define WRITE_8(buff, n) do { \ |
||||
*((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \
|
||||
} while(0) |
||||
#define WRITE_16(buff, n) do { \ |
||||
WRITE_8((unsigned char*)(buff), n); \
|
||||
WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \
|
||||
} while(0) |
||||
#define WRITE_32(buff, n) do { \ |
||||
WRITE_16((unsigned char*)(buff), (n) & 0xffff); \
|
||||
WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \
|
||||
} while(0) |
||||
|
||||
extern int ZEXPORT unzRepair(file, fileOut, fileOutTmp, nRecovered, bytesRecovered) |
||||
const char* file; |
||||
const char* fileOut; |
||||
const char* fileOutTmp; |
||||
uLong* nRecovered; |
||||
uLong* bytesRecovered; |
||||
{ |
||||
int err = Z_OK; |
||||
FILE* fpZip = fopen(file, "rb"); |
||||
FILE* fpOut = fopen(fileOut, "wb"); |
||||
FILE* fpOutCD = fopen(fileOutTmp, "wb"); |
||||
if (fpZip != NULL && fpOut != NULL) { |
||||
int entries = 0; |
||||
uLong totalBytes = 0; |
||||
char header[30]; |
||||
char filename[256]; |
||||
char extra[1024]; |
||||
int offset = 0; |
||||
int offsetCD = 0; |
||||
while ( fread(header, 1, 30, fpZip) == 30 ) { |
||||
int currentOffset = offset; |
||||
|
||||
/* File entry */ |
||||
if (READ_32(header) == 0x04034b50) { |
||||
unsigned int version = READ_16(header + 4); |
||||
unsigned int gpflag = READ_16(header + 6); |
||||
unsigned int method = READ_16(header + 8); |
||||
unsigned int filetime = READ_16(header + 10); |
||||
unsigned int filedate = READ_16(header + 12); |
||||
unsigned int crc = READ_32(header + 14); /* crc */ |
||||
unsigned int cpsize = READ_32(header + 18); /* compressed size */ |
||||
unsigned int uncpsize = READ_32(header + 22); /* uncompressed sz */ |
||||
unsigned int fnsize = READ_16(header + 26); /* file name length */ |
||||
unsigned int extsize = READ_16(header + 28); /* extra field length */ |
||||
filename[0] = extra[0] = '\0'; |
||||
|
||||
/* Header */ |
||||
if (fwrite(header, 1, 30, fpOut) == 30) { |
||||
offset += 30; |
||||
} else { |
||||
err = Z_ERRNO; |
||||
break; |
||||
} |
||||
|
||||
/* Filename */ |
||||
if (fnsize > 0) { |
||||
if (fread(filename, 1, fnsize, fpZip) == fnsize) { |
||||
if (fwrite(filename, 1, fnsize, fpOut) == fnsize) { |
||||
offset += fnsize; |
||||
} else { |
||||
err = Z_ERRNO; |
||||
break; |
||||
} |
||||
} else { |
||||
err = Z_ERRNO; |
||||
break; |
||||
} |
||||
} else { |
||||
err = Z_STREAM_ERROR; |
||||
break; |
||||
} |
||||
|
||||
/* Extra field */ |
||||
if (extsize > 0) { |
||||
if (fread(extra, 1, extsize, fpZip) == extsize) { |
||||
if (fwrite(extra, 1, extsize, fpOut) == extsize) { |
||||
offset += extsize; |
||||
} else { |
||||
err = Z_ERRNO; |
||||
break; |
||||
} |
||||
} else { |
||||
err = Z_ERRNO; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
/* Data */ |
||||
{ |
||||
int dataSize = cpsize; |
||||
if (dataSize == 0) { |
||||
dataSize = uncpsize; |
||||
} |
||||
if (dataSize > 0) { |
||||
char* data = malloc(dataSize); |
||||
if (data != NULL) { |
||||
if ((int)fread(data, 1, dataSize, fpZip) == dataSize) { |
||||
if ((int)fwrite(data, 1, dataSize, fpOut) == dataSize) { |
||||
offset += dataSize; |
||||
totalBytes += dataSize; |
||||
} else { |
||||
err = Z_ERRNO; |
||||
} |
||||
} else { |
||||
err = Z_ERRNO; |
||||
} |
||||
free(data); |
||||
if (err != Z_OK) { |
||||
break; |
||||
} |
||||
} else { |
||||
err = Z_MEM_ERROR; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/* Central directory entry */ |
||||
{ |
||||
char header[46]; |
||||
char* comment = ""; |
||||
int comsize = (int) strlen(comment); |
||||
WRITE_32(header, 0x02014b50); |
||||
WRITE_16(header + 4, version); |
||||
WRITE_16(header + 6, version); |
||||
WRITE_16(header + 8, gpflag); |
||||
WRITE_16(header + 10, method); |
||||
WRITE_16(header + 12, filetime); |
||||
WRITE_16(header + 14, filedate); |
||||
WRITE_32(header + 16, crc); |
||||
WRITE_32(header + 20, cpsize); |
||||
WRITE_32(header + 24, uncpsize); |
||||
WRITE_16(header + 28, fnsize); |
||||
WRITE_16(header + 30, extsize); |
||||
WRITE_16(header + 32, comsize); |
||||
WRITE_16(header + 34, 0); /* disk # */ |
||||
WRITE_16(header + 36, 0); /* int attrb */ |
||||
WRITE_32(header + 38, 0); /* ext attrb */ |
||||
WRITE_32(header + 42, currentOffset); |
||||
/* Header */ |
||||
if (fwrite(header, 1, 46, fpOutCD) == 46) { |
||||
offsetCD += 46; |
||||
|
||||
/* Filename */ |
||||
if (fnsize > 0) { |
||||
if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) { |
||||
offsetCD += fnsize; |
||||
} else { |
||||
err = Z_ERRNO; |
||||
break; |
||||
} |
||||
} else { |
||||
err = Z_STREAM_ERROR; |
||||
break; |
||||
} |
||||
|
||||
/* Extra field */ |
||||
if (extsize > 0) { |
||||
if (fwrite(extra, 1, extsize, fpOutCD) == extsize) { |
||||
offsetCD += extsize; |
||||
} else { |
||||
err = Z_ERRNO; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
/* Comment field */ |
||||
if (comsize > 0) { |
||||
if ((int)fwrite(comment, 1, comsize, fpOutCD) == comsize) { |
||||
offsetCD += comsize; |
||||
} else { |
||||
err = Z_ERRNO; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
|
||||
} else { |
||||
err = Z_ERRNO; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
/* Success */ |
||||
entries++; |
||||
|
||||
} else { |
||||
break; |
||||
} |
||||
} |
||||
|
||||
/* Final central directory */ |
||||
{ |
||||
int entriesZip = entries; |
||||
char header[22]; |
||||
char* comment = ""; // "ZIP File recovered by zlib/minizip/mztools";
|
||||
int comsize = (int) strlen(comment); |
||||
if (entriesZip > 0xffff) { |
||||
entriesZip = 0xffff; |
||||
} |
||||
WRITE_32(header, 0x06054b50); |
||||
WRITE_16(header + 4, 0); /* disk # */ |
||||
WRITE_16(header + 6, 0); /* disk # */ |
||||
WRITE_16(header + 8, entriesZip); /* hack */ |
||||
WRITE_16(header + 10, entriesZip); /* hack */ |
||||
WRITE_32(header + 12, offsetCD); /* size of CD */ |
||||
WRITE_32(header + 16, offset); /* offset to CD */ |
||||
WRITE_16(header + 20, comsize); /* comment */ |
||||
|
||||
/* Header */ |
||||
if (fwrite(header, 1, 22, fpOutCD) == 22) { |
||||
|
||||
/* Comment field */ |
||||
if (comsize > 0) { |
||||
if ((int)fwrite(comment, 1, comsize, fpOutCD) != comsize) { |
||||
err = Z_ERRNO; |
||||
} |
||||
} |
||||
|
||||
} else { |
||||
err = Z_ERRNO; |
||||
} |
||||
} |
||||
|
||||
/* Final merge (file + central directory) */ |
||||
fclose(fpOutCD); |
||||
if (err == Z_OK) { |
||||
fpOutCD = fopen(fileOutTmp, "rb"); |
||||
if (fpOutCD != NULL) { |
||||
int nRead; |
||||
char buffer[8192]; |
||||
while ( (nRead = (int)fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) { |
||||
if ((int)fwrite(buffer, 1, nRead, fpOut) != nRead) { |
||||
err = Z_ERRNO; |
||||
break; |
||||
} |
||||
} |
||||
fclose(fpOutCD); |
||||
} |
||||
} |
||||
|
||||
/* Close */ |
||||
fclose(fpZip); |
||||
fclose(fpOut); |
||||
|
||||
/* Wipe temporary file */ |
||||
(void)remove(fileOutTmp); |
||||
|
||||
/* Number of recovered entries */ |
||||
if (err == Z_OK) { |
||||
if (nRecovered != NULL) { |
||||
*nRecovered = entries; |
||||
} |
||||
if (bytesRecovered != NULL) { |
||||
*bytesRecovered = totalBytes; |
||||
} |
||||
} |
||||
} else { |
||||
err = Z_STREAM_ERROR; |
||||
} |
||||
return err; |
||||
} |
||||
|
@ -1,31 +1,31 @@ |
||||
/*
|
||||
Additional tools for Minizip |
||||
Code: Xavier Roche '2004 |
||||
License: Same as ZLIB (www.gzip.org) |
||||
*/ |
||||
|
||||
#ifndef _zip_tools_H |
||||
#define _zip_tools_H |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
#ifndef _ZLIB_H |
||||
#include "zlib.h" |
||||
#endif |
||||
|
||||
#include "unzip.h" |
||||
|
||||
/* Repair a ZIP file (missing central directory)
|
||||
file: file to recover |
||||
fileOut: output file after recovery |
||||
fileOutTmp: temporary file name used for recovery |
||||
*/ |
||||
extern int ZEXPORT unzRepair(const char* file, |
||||
const char* fileOut, |
||||
const char* fileOutTmp, |
||||
uLong* nRecovered, |
||||
uLong* bytesRecovered); |
||||
|
||||
#endif |
||||
/*
|
||||
Additional tools for Minizip |
||||
Code: Xavier Roche '2004 |
||||
License: Same as ZLIB (www.gzip.org) |
||||
*/ |
||||
|
||||
#ifndef _zip_tools_H |
||||
#define _zip_tools_H |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
#ifndef _ZLIB_H |
||||
#include "zlib.h" |
||||
#endif |
||||
|
||||
#include "unzip.h" |
||||
|
||||
/* Repair a ZIP file (missing central directory)
|
||||
file: file to recover |
||||
fileOut: output file after recovery |
||||
fileOutTmp: temporary file name used for recovery |
||||
*/ |
||||
extern int ZEXPORT unzRepair(const char* file,
|
||||
const char* fileOut,
|
||||
const char* fileOutTmp,
|
||||
uLong* nRecovered, |
||||
uLong* bytesRecovered); |
||||
|
||||
#endif |
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,352 +1,354 @@ |
||||
/* unzip.h -- IO for uncompress .zip files using zlib
|
||||
Version 1.01, May 8th, 2004 |
||||
|
||||
Copyright (C) 1998-2004 Gilles Vollant |
||||
|
||||
This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g |
||||
WinZip, InfoZip tools and compatible. |
||||
Encryption and multi volume ZipFile (span) are not supported. |
||||
Old compressions used by old PKZip 1.x are not supported |
||||
|
||||
|
||||
I WAIT FEEDBACK at mail info@winimage.com |
||||
Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution
|
||||
|
||||
Condition of use and distribution are the same than zlib : |
||||
|
||||
This software is provided 'as-is', without any express or implied |
||||
warranty. In no event will the authors be held liable for any damages |
||||
arising from the use of this software. |
||||
|
||||
Permission is granted to anyone to use this software for any purpose, |
||||
including commercial applications, and to alter it and redistribute it |
||||
freely, subject to the following restrictions: |
||||
|
||||
1. The origin of this software must not be misrepresented; you must not |
||||
claim that you wrote the original software. If you use this software |
||||
in a product, an acknowledgment in the product documentation would be |
||||
appreciated but is not required. |
||||
2. Altered source versions must be plainly marked as such, and must not be |
||||
misrepresented as being the original software. |
||||
3. This notice may not be removed or altered from any source distribution. |
||||
|
||||
|
||||
*/ |
||||
|
||||
/* for more info about .ZIP format, see
|
||||
http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip
|
||||
http://www.info-zip.org/pub/infozip/doc/
|
||||
PkWare has also a specification at : |
||||
ftp://ftp.pkware.com/probdesc.zip
|
||||
*/ |
||||
|
||||
#ifndef _unz_H |
||||
#define _unz_H |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
#ifndef _ZLIB_H |
||||
#include "zlib.h" |
||||
#endif |
||||
|
||||
#ifndef _ZLIBIOAPI_H |
||||
#include "ioapi.h" |
||||
#endif |
||||
|
||||
#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) |
||||
/* like the STRICT of WIN32, we define a pointer that cannot be converted
|
||||
from (void*) without cast */ |
||||
typedef struct TagunzFile__ { int unused; } unzFile__; |
||||
typedef unzFile__ *unzFile; |
||||
#else |
||||
typedef voidp unzFile; |
||||
#endif |
||||
|
||||
|
||||
#define UNZ_OK (0) |
||||
#define UNZ_END_OF_LIST_OF_FILE (-100) |
||||
#define UNZ_ERRNO (Z_ERRNO) |
||||
#define UNZ_EOF (0) |
||||
#define UNZ_PARAMERROR (-102) |
||||
#define UNZ_BADZIPFILE (-103) |
||||
#define UNZ_INTERNALERROR (-104) |
||||
#define UNZ_CRCERROR (-105) |
||||
|
||||
/* tm_unz contain date/time info */ |
||||
typedef struct tm_unz_s |
||||
{ |
||||
uInt tm_sec; /* seconds after the minute - [0,59] */ |
||||
uInt tm_min; /* minutes after the hour - [0,59] */ |
||||
uInt tm_hour; /* hours since midnight - [0,23] */ |
||||
uInt tm_mday; /* day of the month - [1,31] */ |
||||
uInt tm_mon; /* months since January - [0,11] */ |
||||
uInt tm_year; /* years - [1980..2044] */ |
||||
} tm_unz; |
||||
|
||||
/* unz_global_info structure contain global data about the ZIPfile
|
||||
These data comes from the end of central dir */ |
||||
typedef struct unz_global_info_s |
||||
{ |
||||
uLong number_entry; /* total number of entries in
|
||||
the central dir on this disk */ |
||||
uLong size_comment; /* size of the global comment of the zipfile */ |
||||
} unz_global_info; |
||||
|
||||
|
||||
/* unz_file_info contain information about a file in the zipfile */ |
||||
typedef struct unz_file_info_s |
||||
{ |
||||
uLong version; /* version made by 2 bytes */ |
||||
uLong version_needed; /* version needed to extract 2 bytes */ |
||||
uLong flag; /* general purpose bit flag 2 bytes */ |
||||
uLong compression_method; /* compression method 2 bytes */ |
||||
uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ |
||||
uLong crc; /* crc-32 4 bytes */ |
||||
uLong compressed_size; /* compressed size 4 bytes */ |
||||
uLong uncompressed_size; /* uncompressed size 4 bytes */ |
||||
uLong size_filename; /* filename length 2 bytes */ |
||||
uLong size_file_extra; /* extra field length 2 bytes */ |
||||
uLong size_file_comment; /* file comment length 2 bytes */ |
||||
|
||||
uLong disk_num_start; /* disk number start 2 bytes */ |
||||
uLong internal_fa; /* internal file attributes 2 bytes */ |
||||
uLong external_fa; /* external file attributes 4 bytes */ |
||||
|
||||
tm_unz tmu_date; |
||||
} unz_file_info; |
||||
|
||||
extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, |
||||
const char* fileName2, |
||||
int iCaseSensitivity)); |
||||
/*
|
||||
Compare two filename (fileName1,fileName2). |
||||
If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) |
||||
If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi |
||||
or strcasecmp) |
||||
If iCaseSenisivity = 0, case sensitivity is defaut of your operating system |
||||
(like 1 on Unix, 2 on Windows) |
||||
*/ |
||||
|
||||
|
||||
extern unzFile ZEXPORT unzOpen OF((const char *path)); |
||||
/*
|
||||
Open a Zip file. path contain the full pathname (by example, |
||||
on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer |
||||
"zlib/zlib113.zip". |
||||
If the zipfile cannot be opened (file don't exist or in not valid), the |
||||
return value is NULL. |
||||
Else, the return value is a unzFile Handle, usable with other function |
||||
of this unzip package. |
||||
*/ |
||||
|
||||
extern unzFile ZEXPORT unzOpen2 OF((const char *path, |
||||
zlib_filefunc_def* pzlib_filefunc_def)); |
||||
/*
|
||||
Open a Zip file, like unzOpen, but provide a set of file low level API |
||||
for read/write the zip file (see ioapi.h) |
||||
*/ |
||||
|
||||
extern int ZEXPORT unzClose OF((unzFile file)); |
||||
/*
|
||||
Close a ZipFile opened with unzipOpen. |
||||
If there is files inside the .Zip opened with unzOpenCurrentFile (see later), |
||||
these files MUST be closed with unzipCloseCurrentFile before call unzipClose. |
||||
return UNZ_OK if there is no problem. */ |
||||
|
||||
extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, |
||||
unz_global_info *pglobal_info)); |
||||
/*
|
||||
Write info about the ZipFile in the *pglobal_info structure. |
||||
No preparation of the structure is needed |
||||
return UNZ_OK if there is no problem. */ |
||||
|
||||
|
||||
extern int ZEXPORT unzGetGlobalComment OF((unzFile file, |
||||
char *szComment, |
||||
uLong uSizeBuf)); |
||||
/*
|
||||
Get the global comment string of the ZipFile, in the szComment buffer. |
||||
uSizeBuf is the size of the szComment buffer. |
||||
return the number of byte copied or an error code <0 |
||||
*/ |
||||
|
||||
|
||||
/***************************************************************************/ |
||||
/* Unzip package allow you browse the directory of the zipfile */ |
||||
|
||||
extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); |
||||
/*
|
||||
Set the current file of the zipfile to the first file. |
||||
return UNZ_OK if there is no problem |
||||
*/ |
||||
|
||||
extern int ZEXPORT unzGoToNextFile OF((unzFile file)); |
||||
/*
|
||||
Set the current file of the zipfile to the next file. |
||||
return UNZ_OK if there is no problem |
||||
return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. |
||||
*/ |
||||
|
||||
extern int ZEXPORT unzLocateFile OF((unzFile file, |
||||
const char *szFileName, |
||||
int iCaseSensitivity)); |
||||
/*
|
||||
Try locate the file szFileName in the zipfile. |
||||
For the iCaseSensitivity signification, see unzStringFileNameCompare |
||||
|
||||
return value : |
||||
UNZ_OK if the file is found. It becomes the current file. |
||||
UNZ_END_OF_LIST_OF_FILE if the file is not found |
||||
*/ |
||||
|
||||
|
||||
/* ****************************************** */ |
||||
/* Ryan supplied functions */ |
||||
/* unz_file_info contain information about a file in the zipfile */ |
||||
typedef struct unz_file_pos_s |
||||
{ |
||||
uLong pos_in_zip_directory; /* offset in zip file directory */ |
||||
uLong num_of_file; /* # of file */ |
||||
} unz_file_pos; |
||||
|
||||
extern int ZEXPORT unzGetFilePos( |
||||
unzFile file, |
||||
unz_file_pos* file_pos); |
||||
|
||||
extern int ZEXPORT unzGoToFilePos( |
||||
unzFile file, |
||||
unz_file_pos* file_pos); |
||||
|
||||
/* ****************************************** */ |
||||
|
||||
extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, |
||||
unz_file_info *pfile_info, |
||||
char *szFileName, |
||||
uLong fileNameBufferSize, |
||||
void *extraField, |
||||
uLong extraFieldBufferSize, |
||||
char *szComment, |
||||
uLong commentBufferSize)); |
||||
/*
|
||||
Get Info about the current file |
||||
if pfile_info!=NULL, the *pfile_info structure will contain somes info about |
||||
the current file |
||||
if szFileName!=NULL, the filemane string will be copied in szFileName |
||||
(fileNameBufferSize is the size of the buffer) |
||||
if extraField!=NULL, the extra field information will be copied in extraField |
||||
(extraFieldBufferSize is the size of the buffer). |
||||
This is the Central-header version of the extra field |
||||
if szComment!=NULL, the comment string of the file will be copied in szComment |
||||
(commentBufferSize is the size of the buffer) |
||||
*/ |
||||
|
||||
/***************************************************************************/ |
||||
/* for reading the content of the current zipfile, you can open it, read data
|
||||
from it, and close it (you can close it before reading all the file) |
||||
*/ |
||||
|
||||
extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); |
||||
/*
|
||||
Open for reading data the current file in the zipfile. |
||||
If there is no error, the return value is UNZ_OK. |
||||
*/ |
||||
|
||||
extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, |
||||
const char* password)); |
||||
/*
|
||||
Open for reading data the current file in the zipfile. |
||||
password is a crypting password |
||||
If there is no error, the return value is UNZ_OK. |
||||
*/ |
||||
|
||||
extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, |
||||
int* method, |
||||
int* level, |
||||
int raw)); |
||||
/*
|
||||
Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) |
||||
if raw==1 |
||||
*method will receive method of compression, *level will receive level of |
||||
compression |
||||
note : you can set level parameter as NULL (if you did not want known level, |
||||
but you CANNOT set method parameter as NULL |
||||
*/ |
||||
|
||||
extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, |
||||
int* method, |
||||
int* level, |
||||
int raw, |
||||
const char* password)); |
||||
/*
|
||||
Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) |
||||
if raw==1 |
||||
*method will receive method of compression, *level will receive level of |
||||
compression |
||||
note : you can set level parameter as NULL (if you did not want known level, |
||||
but you CANNOT set method parameter as NULL |
||||
*/ |
||||
|
||||
|
||||
extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); |
||||
/*
|
||||
Close the file in zip opened with unzOpenCurrentFile |
||||
Return UNZ_CRCERROR if all the file was read but the CRC is not good |
||||
*/ |
||||
|
||||
extern int ZEXPORT unzReadCurrentFile OF((unzFile file, |
||||
voidp buf, |
||||
unsigned len)); |
||||
/*
|
||||
Read bytes from the current file (opened by unzOpenCurrentFile) |
||||
buf contain buffer where data must be copied |
||||
len the size of buf. |
||||
|
||||
return the number of byte copied if somes bytes are copied |
||||
return 0 if the end of file was reached |
||||
return <0 with error code if there is an error |
||||
(UNZ_ERRNO for IO error, or zLib error for uncompress error) |
||||
*/ |
||||
|
||||
extern z_off_t ZEXPORT unztell OF((unzFile file)); |
||||
/*
|
||||
Give the current position in uncompressed data |
||||
*/ |
||||
|
||||
extern int ZEXPORT unzeof OF((unzFile file)); |
||||
/*
|
||||
return 1 if the end of file was reached, 0 elsewhere |
||||
*/ |
||||
|
||||
extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, |
||||
voidp buf, |
||||
unsigned len)); |
||||
/*
|
||||
Read extra field from the current file (opened by unzOpenCurrentFile) |
||||
This is the local-header version of the extra field (sometimes, there is |
||||
more info in the local-header version than in the central-header) |
||||
|
||||
if buf==NULL, it return the size of the local extra field |
||||
|
||||
if buf!=NULL, len is the size of the buffer, the extra header is copied in |
||||
buf. |
||||
the return value is the number of bytes copied in buf, or (if <0) |
||||
the error code |
||||
*/ |
||||
|
||||
/***************************************************************************/ |
||||
|
||||
/* Get the current file offset */ |
||||
extern uLong ZEXPORT unzGetOffset (unzFile file); |
||||
|
||||
/* Set the current file offset */ |
||||
extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); |
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* _unz_H */ |
||||
/* unzip.h -- IO for uncompress .zip files using zlib
|
||||
Version 1.01e, February 12th, 2005 |
||||
|
||||
Copyright (C) 1998-2005 Gilles Vollant |
||||
|
||||
This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g |
||||
WinZip, InfoZip tools and compatible. |
||||
|
||||
Multi volume ZipFile (span) are not supported. |
||||
Encryption compatible with pkzip 2.04g only supported |
||||
Old compressions used by old PKZip 1.x are not supported |
||||
|
||||
|
||||
I WAIT FEEDBACK at mail info@winimage.com |
||||
Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution
|
||||
|
||||
Condition of use and distribution are the same than zlib : |
||||
|
||||
This software is provided 'as-is', without any express or implied |
||||
warranty. In no event will the authors be held liable for any damages |
||||
arising from the use of this software. |
||||
|
||||
Permission is granted to anyone to use this software for any purpose, |
||||
including commercial applications, and to alter it and redistribute it |
||||
freely, subject to the following restrictions: |
||||
|
||||
1. The origin of this software must not be misrepresented; you must not |
||||
claim that you wrote the original software. If you use this software |
||||
in a product, an acknowledgment in the product documentation would be |
||||
appreciated but is not required. |
||||
2. Altered source versions must be plainly marked as such, and must not be |
||||
misrepresented as being the original software. |
||||
3. This notice may not be removed or altered from any source distribution. |
||||
|
||||
|
||||
*/ |
||||
|
||||
/* for more info about .ZIP format, see
|
||||
http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip
|
||||
http://www.info-zip.org/pub/infozip/doc/
|
||||
PkWare has also a specification at : |
||||
ftp://ftp.pkware.com/probdesc.zip
|
||||
*/ |
||||
|
||||
#ifndef _unz_H |
||||
#define _unz_H |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
#ifndef _ZLIB_H |
||||
#include "zlib.h" |
||||
#endif |
||||
|
||||
#ifndef _ZLIBIOAPI_H |
||||
#include "ioapi.h" |
||||
#endif |
||||
|
||||
#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) |
||||
/* like the STRICT of WIN32, we define a pointer that cannot be converted
|
||||
from (void*) without cast */ |
||||
typedef struct TagunzFile__ { int unused; } unzFile__; |
||||
typedef unzFile__ *unzFile; |
||||
#else |
||||
typedef voidp unzFile; |
||||
#endif |
||||
|
||||
|
||||
#define UNZ_OK (0) |
||||
#define UNZ_END_OF_LIST_OF_FILE (-100) |
||||
#define UNZ_ERRNO (Z_ERRNO) |
||||
#define UNZ_EOF (0) |
||||
#define UNZ_PARAMERROR (-102) |
||||
#define UNZ_BADZIPFILE (-103) |
||||
#define UNZ_INTERNALERROR (-104) |
||||
#define UNZ_CRCERROR (-105) |
||||
|
||||
/* tm_unz contain date/time info */ |
||||
typedef struct tm_unz_s |
||||
{ |
||||
uInt tm_sec; /* seconds after the minute - [0,59] */ |
||||
uInt tm_min; /* minutes after the hour - [0,59] */ |
||||
uInt tm_hour; /* hours since midnight - [0,23] */ |
||||
uInt tm_mday; /* day of the month - [1,31] */ |
||||
uInt tm_mon; /* months since January - [0,11] */ |
||||
uInt tm_year; /* years - [1980..2044] */ |
||||
} tm_unz; |
||||
|
||||
/* unz_global_info structure contain global data about the ZIPfile
|
||||
These data comes from the end of central dir */ |
||||
typedef struct unz_global_info_s |
||||
{ |
||||
uLong number_entry; /* total number of entries in
|
||||
the central dir on this disk */ |
||||
uLong size_comment; /* size of the global comment of the zipfile */ |
||||
} unz_global_info; |
||||
|
||||
|
||||
/* unz_file_info contain information about a file in the zipfile */ |
||||
typedef struct unz_file_info_s |
||||
{ |
||||
uLong version; /* version made by 2 bytes */ |
||||
uLong version_needed; /* version needed to extract 2 bytes */ |
||||
uLong flag; /* general purpose bit flag 2 bytes */ |
||||
uLong compression_method; /* compression method 2 bytes */ |
||||
uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ |
||||
uLong crc; /* crc-32 4 bytes */ |
||||
uLong compressed_size; /* compressed size 4 bytes */ |
||||
uLong uncompressed_size; /* uncompressed size 4 bytes */ |
||||
uLong size_filename; /* filename length 2 bytes */ |
||||
uLong size_file_extra; /* extra field length 2 bytes */ |
||||
uLong size_file_comment; /* file comment length 2 bytes */ |
||||
|
||||
uLong disk_num_start; /* disk number start 2 bytes */ |
||||
uLong internal_fa; /* internal file attributes 2 bytes */ |
||||
uLong external_fa; /* external file attributes 4 bytes */ |
||||
|
||||
tm_unz tmu_date; |
||||
} unz_file_info; |
||||
|
||||
extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, |
||||
const char* fileName2, |
||||
int iCaseSensitivity)); |
||||
/*
|
||||
Compare two filename (fileName1,fileName2). |
||||
If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) |
||||
If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi |
||||
or strcasecmp) |
||||
If iCaseSenisivity = 0, case sensitivity is defaut of your operating system |
||||
(like 1 on Unix, 2 on Windows) |
||||
*/ |
||||
|
||||
|
||||
extern unzFile ZEXPORT unzOpen OF((const char *path)); |
||||
/*
|
||||
Open a Zip file. path contain the full pathname (by example, |
||||
on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer |
||||
"zlib/zlib113.zip". |
||||
If the zipfile cannot be opened (file don't exist or in not valid), the |
||||
return value is NULL. |
||||
Else, the return value is a unzFile Handle, usable with other function |
||||
of this unzip package. |
||||
*/ |
||||
|
||||
extern unzFile ZEXPORT unzOpen2 OF((const char *path, |
||||
zlib_filefunc_def* pzlib_filefunc_def)); |
||||
/*
|
||||
Open a Zip file, like unzOpen, but provide a set of file low level API |
||||
for read/write the zip file (see ioapi.h) |
||||
*/ |
||||
|
||||
extern int ZEXPORT unzClose OF((unzFile file)); |
||||
/*
|
||||
Close a ZipFile opened with unzipOpen. |
||||
If there is files inside the .Zip opened with unzOpenCurrentFile (see later), |
||||
these files MUST be closed with unzipCloseCurrentFile before call unzipClose. |
||||
return UNZ_OK if there is no problem. */ |
||||
|
||||
extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, |
||||
unz_global_info *pglobal_info)); |
||||
/*
|
||||
Write info about the ZipFile in the *pglobal_info structure. |
||||
No preparation of the structure is needed |
||||
return UNZ_OK if there is no problem. */ |
||||
|
||||
|
||||
extern int ZEXPORT unzGetGlobalComment OF((unzFile file, |
||||
char *szComment, |
||||
uLong uSizeBuf)); |
||||
/*
|
||||
Get the global comment string of the ZipFile, in the szComment buffer. |
||||
uSizeBuf is the size of the szComment buffer. |
||||
return the number of byte copied or an error code <0 |
||||
*/ |
||||
|
||||
|
||||
/***************************************************************************/ |
||||
/* Unzip package allow you browse the directory of the zipfile */ |
||||
|
||||
extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); |
||||
/*
|
||||
Set the current file of the zipfile to the first file. |
||||
return UNZ_OK if there is no problem |
||||
*/ |
||||
|
||||
extern int ZEXPORT unzGoToNextFile OF((unzFile file)); |
||||
/*
|
||||
Set the current file of the zipfile to the next file. |
||||
return UNZ_OK if there is no problem |
||||
return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. |
||||
*/ |
||||
|
||||
extern int ZEXPORT unzLocateFile OF((unzFile file, |
||||
const char *szFileName, |
||||
int iCaseSensitivity)); |
||||
/*
|
||||
Try locate the file szFileName in the zipfile. |
||||
For the iCaseSensitivity signification, see unzStringFileNameCompare |
||||
|
||||
return value : |
||||
UNZ_OK if the file is found. It becomes the current file. |
||||
UNZ_END_OF_LIST_OF_FILE if the file is not found |
||||
*/ |
||||
|
||||
|
||||
/* ****************************************** */ |
||||
/* Ryan supplied functions */ |
||||
/* unz_file_info contain information about a file in the zipfile */ |
||||
typedef struct unz_file_pos_s |
||||
{ |
||||
uLong pos_in_zip_directory; /* offset in zip file directory */ |
||||
uLong num_of_file; /* # of file */ |
||||
} unz_file_pos; |
||||
|
||||
extern int ZEXPORT unzGetFilePos( |
||||
unzFile file, |
||||
unz_file_pos* file_pos); |
||||
|
||||
extern int ZEXPORT unzGoToFilePos( |
||||
unzFile file, |
||||
unz_file_pos* file_pos); |
||||
|
||||
/* ****************************************** */ |
||||
|
||||
extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, |
||||
unz_file_info *pfile_info, |
||||
char *szFileName, |
||||
uLong fileNameBufferSize, |
||||
void *extraField, |
||||
uLong extraFieldBufferSize, |
||||
char *szComment, |
||||
uLong commentBufferSize)); |
||||
/*
|
||||
Get Info about the current file |
||||
if pfile_info!=NULL, the *pfile_info structure will contain somes info about |
||||
the current file |
||||
if szFileName!=NULL, the filemane string will be copied in szFileName |
||||
(fileNameBufferSize is the size of the buffer) |
||||
if extraField!=NULL, the extra field information will be copied in extraField |
||||
(extraFieldBufferSize is the size of the buffer). |
||||
This is the Central-header version of the extra field |
||||
if szComment!=NULL, the comment string of the file will be copied in szComment |
||||
(commentBufferSize is the size of the buffer) |
||||
*/ |
||||
|
||||
/***************************************************************************/ |
||||
/* for reading the content of the current zipfile, you can open it, read data
|
||||
from it, and close it (you can close it before reading all the file) |
||||
*/ |
||||
|
||||
extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); |
||||
/*
|
||||
Open for reading data the current file in the zipfile. |
||||
If there is no error, the return value is UNZ_OK. |
||||
*/ |
||||
|
||||
extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, |
||||
const char* password)); |
||||
/*
|
||||
Open for reading data the current file in the zipfile. |
||||
password is a crypting password |
||||
If there is no error, the return value is UNZ_OK. |
||||
*/ |
||||
|
||||
extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, |
||||
int* method, |
||||
int* level, |
||||
int raw)); |
||||
/*
|
||||
Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) |
||||
if raw==1 |
||||
*method will receive method of compression, *level will receive level of |
||||
compression |
||||
note : you can set level parameter as NULL (if you did not want known level, |
||||
but you CANNOT set method parameter as NULL |
||||
*/ |
||||
|
||||
extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, |
||||
int* method, |
||||
int* level, |
||||
int raw, |
||||
const char* password)); |
||||
/*
|
||||
Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) |
||||
if raw==1 |
||||
*method will receive method of compression, *level will receive level of |
||||
compression |
||||
note : you can set level parameter as NULL (if you did not want known level, |
||||
but you CANNOT set method parameter as NULL |
||||
*/ |
||||
|
||||
|
||||
extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); |
||||
/*
|
||||
Close the file in zip opened with unzOpenCurrentFile |
||||
Return UNZ_CRCERROR if all the file was read but the CRC is not good |
||||
*/ |
||||
|
||||
extern int ZEXPORT unzReadCurrentFile OF((unzFile file, |
||||
voidp buf, |
||||
unsigned len)); |
||||
/*
|
||||
Read bytes from the current file (opened by unzOpenCurrentFile) |
||||
buf contain buffer where data must be copied |
||||
len the size of buf. |
||||
|
||||
return the number of byte copied if somes bytes are copied |
||||
return 0 if the end of file was reached |
||||
return <0 with error code if there is an error |
||||
(UNZ_ERRNO for IO error, or zLib error for uncompress error) |
||||
*/ |
||||
|
||||
extern z_off_t ZEXPORT unztell OF((unzFile file)); |
||||
/*
|
||||
Give the current position in uncompressed data |
||||
*/ |
||||
|
||||
extern int ZEXPORT unzeof OF((unzFile file)); |
||||
/*
|
||||
return 1 if the end of file was reached, 0 elsewhere |
||||
*/ |
||||
|
||||
extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, |
||||
voidp buf, |
||||
unsigned len)); |
||||
/*
|
||||
Read extra field from the current file (opened by unzOpenCurrentFile) |
||||
This is the local-header version of the extra field (sometimes, there is |
||||
more info in the local-header version than in the central-header) |
||||
|
||||
if buf==NULL, it return the size of the local extra field |
||||
|
||||
if buf!=NULL, len is the size of the buffer, the extra header is copied in |
||||
buf. |
||||
the return value is the number of bytes copied in buf, or (if <0) |
||||
the error code |
||||
*/ |
||||
|
||||
/***************************************************************************/ |
||||
|
||||
/* Get the current file offset */ |
||||
extern uLong ZEXPORT unzGetOffset (unzFile file); |
||||
|
||||
/* Set the current file offset */ |
||||
extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); |
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* _unz_H */ |
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,234 +1,235 @@ |
||||
/* zip.h -- IO for compress .zip files using zlib
|
||||
Version 1.01, May 8th, 2004 |
||||
|
||||
Copyright (C) 1998-2004 Gilles Vollant |
||||
|
||||
This unzip package allow creates .ZIP file, compatible with PKZip 2.04g |
||||
WinZip, InfoZip tools and compatible. |
||||
Encryption and multi volume ZipFile (span) are not supported. |
||||
Old compressions used by old PKZip 1.x are not supported |
||||
|
||||
For uncompress .zip file, look at unzip.h |
||||
|
||||
|
||||
I WAIT FEEDBACK at mail info@winimage.com |
||||
Visit also http://www.winimage.com/zLibDll/unzip.html for evolution
|
||||
|
||||
Condition of use and distribution are the same than zlib : |
||||
|
||||
This software is provided 'as-is', without any express or implied |
||||
warranty. In no event will the authors be held liable for any damages |
||||
arising from the use of this software. |
||||
|
||||
Permission is granted to anyone to use this software for any purpose, |
||||
including commercial applications, and to alter it and redistribute it |
||||
freely, subject to the following restrictions: |
||||
|
||||
1. The origin of this software must not be misrepresented; you must not |
||||
claim that you wrote the original software. If you use this software |
||||
in a product, an acknowledgment in the product documentation would be |
||||
appreciated but is not required. |
||||
2. Altered source versions must be plainly marked as such, and must not be |
||||
misrepresented as being the original software. |
||||
3. This notice may not be removed or altered from any source distribution. |
||||
|
||||
|
||||
*/ |
||||
|
||||
/* for more info about .ZIP format, see
|
||||
http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip
|
||||
http://www.info-zip.org/pub/infozip/doc/
|
||||
PkWare has also a specification at : |
||||
ftp://ftp.pkware.com/probdesc.zip
|
||||
*/ |
||||
|
||||
#ifndef _zip_H |
||||
#define _zip_H |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
#ifndef _ZLIB_H |
||||
#include "zlib.h" |
||||
#endif |
||||
|
||||
#ifndef _ZLIBIOAPI_H |
||||
#include "ioapi.h" |
||||
#endif |
||||
|
||||
#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) |
||||
/* like the STRICT of WIN32, we define a pointer that cannot be converted
|
||||
from (void*) without cast */ |
||||
typedef struct TagzipFile__ { int unused; } zipFile__; |
||||
typedef zipFile__ *zipFile; |
||||
#else |
||||
typedef voidp zipFile; |
||||
#endif |
||||
|
||||
#define ZIP_OK (0) |
||||
#define ZIP_EOF (0) |
||||
#define ZIP_ERRNO (Z_ERRNO) |
||||
#define ZIP_PARAMERROR (-102) |
||||
#define ZIP_BADZIPFILE (-103) |
||||
#define ZIP_INTERNALERROR (-104) |
||||
|
||||
#ifndef DEF_MEM_LEVEL |
||||
# if MAX_MEM_LEVEL >= 8 |
||||
# define DEF_MEM_LEVEL 8 |
||||
# else |
||||
# define DEF_MEM_LEVEL MAX_MEM_LEVEL |
||||
# endif |
||||
#endif |
||||
/* default memLevel */ |
||||
|
||||
/* tm_zip contain date/time info */ |
||||
typedef struct tm_zip_s |
||||
{ |
||||
uInt tm_sec; /* seconds after the minute - [0,59] */ |
||||
uInt tm_min; /* minutes after the hour - [0,59] */ |
||||
uInt tm_hour; /* hours since midnight - [0,23] */ |
||||
uInt tm_mday; /* day of the month - [1,31] */ |
||||
uInt tm_mon; /* months since January - [0,11] */ |
||||
uInt tm_year; /* years - [1980..2044] */ |
||||
} tm_zip; |
||||
|
||||
typedef struct |
||||
{ |
||||
tm_zip tmz_date; /* date in understandable format */ |
||||
uLong dosDate; /* if dos_date == 0, tmu_date is used */ |
||||
/* uLong flag; */ /* general purpose bit flag 2 bytes */ |
||||
|
||||
uLong internal_fa; /* internal file attributes 2 bytes */ |
||||
uLong external_fa; /* external file attributes 4 bytes */ |
||||
} zip_fileinfo; |
||||
|
||||
typedef const char* zipcharpc; |
||||
|
||||
|
||||
#define APPEND_STATUS_CREATE (0) |
||||
#define APPEND_STATUS_CREATEAFTER (1) |
||||
#define APPEND_STATUS_ADDINZIP (2) |
||||
|
||||
extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); |
||||
/*
|
||||
Create a zipfile. |
||||
pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on |
||||
an Unix computer "zlib/zlib113.zip". |
||||
if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip |
||||
will be created at the end of the file. |
||||
(useful if the file contain a self extractor code) |
||||
if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will |
||||
add files in existing zip (be sure you don't add file that doesn't exist) |
||||
If the zipfile cannot be opened, the return value is NULL. |
||||
Else, the return value is a zipFile Handle, usable with other function |
||||
of this zip package. |
||||
*/ |
||||
|
||||
/* Note : there is no delete function into a zipfile.
|
||||
If you want delete file into a zipfile, you must open a zipfile, and create another |
||||
Of couse, you can use RAW reading and writing to copy the file you did not want delte |
||||
*/ |
||||
|
||||
extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, |
||||
int append, |
||||
zipcharpc* globalcomment, |
||||
zlib_filefunc_def* pzlib_filefunc_def)); |
||||
|
||||
extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, |
||||
const char* filename, |
||||
const zip_fileinfo* zipfi, |
||||
const void* extrafield_local, |
||||
uInt size_extrafield_local, |
||||
const void* extrafield_global, |
||||
uInt size_extrafield_global, |
||||
const char* comment, |
||||
int method, |
||||
int level)); |
||||
/*
|
||||
Open a file in the ZIP for writing. |
||||
filename : the filename in zip (if NULL, '-' without quote will be used |
||||
*zipfi contain supplemental information |
||||
if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local |
||||
contains the extrafield data the the local header |
||||
if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global |
||||
contains the extrafield data the the local header |
||||
if comment != NULL, comment contain the comment string |
||||
method contain the compression method (0 for store, Z_DEFLATED for deflate) |
||||
level contain the level of compression (can be Z_DEFAULT_COMPRESSION) |
||||
*/ |
||||
|
||||
|
||||
extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, |
||||
const char* filename, |
||||
const zip_fileinfo* zipfi, |
||||
const void* extrafield_local, |
||||
uInt size_extrafield_local, |
||||
const void* extrafield_global, |
||||
uInt size_extrafield_global, |
||||
const char* comment, |
||||
int method, |
||||
int level, |
||||
int raw)); |
||||
|
||||
/*
|
||||
Same than zipOpenNewFileInZip, except if raw=1, we write raw file |
||||
*/ |
||||
|
||||
extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, |
||||
const char* filename, |
||||
const zip_fileinfo* zipfi, |
||||
const void* extrafield_local, |
||||
uInt size_extrafield_local, |
||||
const void* extrafield_global, |
||||
uInt size_extrafield_global, |
||||
const char* comment, |
||||
int method, |
||||
int level, |
||||
int raw, |
||||
int windowBits, |
||||
int memLevel, |
||||
int strategy, |
||||
const char* password, |
||||
uLong crcForCtypting)); |
||||
|
||||
/*
|
||||
Same than zipOpenNewFileInZip2, except |
||||
windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 |
||||
password : crypting password (NULL for no crypting) |
||||
crcForCtypting : crc of file to compress (needed for crypting) |
||||
*/ |
||||
|
||||
|
||||
extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, |
||||
const void* buf, |
||||
unsigned len)); |
||||
/*
|
||||
Write data in the zipfile |
||||
*/ |
||||
|
||||
extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); |
||||
/*
|
||||
Close the current file in the zipfile |
||||
*/ |
||||
|
||||
extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, |
||||
uLong uncompressed_size, |
||||
uLong crc32)); |
||||
/*
|
||||
Close the current file in the zipfile, for fiel opened with |
||||
parameter raw=1 in zipOpenNewFileInZip2 |
||||
uncompressed_size and crc32 are value for the uncompressed size |
||||
*/ |
||||
|
||||
extern int ZEXPORT zipClose OF((zipFile file, |
||||
const char* global_comment)); |
||||
/*
|
||||
Close the zipfile |
||||
*/ |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* _zip_H */ |
||||
/* zip.h -- IO for compress .zip files using zlib
|
||||
Version 1.01e, February 12th, 2005 |
||||
|
||||
Copyright (C) 1998-2005 Gilles Vollant |
||||
|
||||
This unzip package allow creates .ZIP file, compatible with PKZip 2.04g |
||||
WinZip, InfoZip tools and compatible. |
||||
Multi volume ZipFile (span) are not supported. |
||||
Encryption compatible with pkzip 2.04g only supported |
||||
Old compressions used by old PKZip 1.x are not supported |
||||
|
||||
For uncompress .zip file, look at unzip.h |
||||
|
||||
|
||||
I WAIT FEEDBACK at mail info@winimage.com |
||||
Visit also http://www.winimage.com/zLibDll/unzip.html for evolution
|
||||
|
||||
Condition of use and distribution are the same than zlib : |
||||
|
||||
This software is provided 'as-is', without any express or implied |
||||
warranty. In no event will the authors be held liable for any damages |
||||
arising from the use of this software. |
||||
|
||||
Permission is granted to anyone to use this software for any purpose, |
||||
including commercial applications, and to alter it and redistribute it |
||||
freely, subject to the following restrictions: |
||||
|
||||
1. The origin of this software must not be misrepresented; you must not |
||||
claim that you wrote the original software. If you use this software |
||||
in a product, an acknowledgment in the product documentation would be |
||||
appreciated but is not required. |
||||
2. Altered source versions must be plainly marked as such, and must not be |
||||
misrepresented as being the original software. |
||||
3. This notice may not be removed or altered from any source distribution. |
||||
|
||||
|
||||
*/ |
||||
|
||||
/* for more info about .ZIP format, see
|
||||
http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip
|
||||
http://www.info-zip.org/pub/infozip/doc/
|
||||
PkWare has also a specification at : |
||||
ftp://ftp.pkware.com/probdesc.zip
|
||||
*/ |
||||
|
||||
#ifndef _zip_H |
||||
#define _zip_H |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
#ifndef _ZLIB_H |
||||
#include "zlib.h" |
||||
#endif |
||||
|
||||
#ifndef _ZLIBIOAPI_H |
||||
#include "ioapi.h" |
||||
#endif |
||||
|
||||
#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) |
||||
/* like the STRICT of WIN32, we define a pointer that cannot be converted
|
||||
from (void*) without cast */ |
||||
typedef struct TagzipFile__ { int unused; } zipFile__; |
||||
typedef zipFile__ *zipFile; |
||||
#else |
||||
typedef voidp zipFile; |
||||
#endif |
||||
|
||||
#define ZIP_OK (0) |
||||
#define ZIP_EOF (0) |
||||
#define ZIP_ERRNO (Z_ERRNO) |
||||
#define ZIP_PARAMERROR (-102) |
||||
#define ZIP_BADZIPFILE (-103) |
||||
#define ZIP_INTERNALERROR (-104) |
||||
|
||||
#ifndef DEF_MEM_LEVEL |
||||
# if MAX_MEM_LEVEL >= 8 |
||||
# define DEF_MEM_LEVEL 8 |
||||
# else |
||||
# define DEF_MEM_LEVEL MAX_MEM_LEVEL |
||||
# endif |
||||
#endif |
||||
/* default memLevel */ |
||||
|
||||
/* tm_zip contain date/time info */ |
||||
typedef struct tm_zip_s |
||||
{ |
||||
uInt tm_sec; /* seconds after the minute - [0,59] */ |
||||
uInt tm_min; /* minutes after the hour - [0,59] */ |
||||
uInt tm_hour; /* hours since midnight - [0,23] */ |
||||
uInt tm_mday; /* day of the month - [1,31] */ |
||||
uInt tm_mon; /* months since January - [0,11] */ |
||||
uInt tm_year; /* years - [1980..2044] */ |
||||
} tm_zip; |
||||
|
||||
typedef struct |
||||
{ |
||||
tm_zip tmz_date; /* date in understandable format */ |
||||
uLong dosDate; /* if dos_date == 0, tmu_date is used */ |
||||
/* uLong flag; */ /* general purpose bit flag 2 bytes */ |
||||
|
||||
uLong internal_fa; /* internal file attributes 2 bytes */ |
||||
uLong external_fa; /* external file attributes 4 bytes */ |
||||
} zip_fileinfo; |
||||
|
||||
typedef const char* zipcharpc; |
||||
|
||||
|
||||
#define APPEND_STATUS_CREATE (0) |
||||
#define APPEND_STATUS_CREATEAFTER (1) |
||||
#define APPEND_STATUS_ADDINZIP (2) |
||||
|
||||
extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); |
||||
/*
|
||||
Create a zipfile. |
||||
pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on |
||||
an Unix computer "zlib/zlib113.zip". |
||||
if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip |
||||
will be created at the end of the file. |
||||
(useful if the file contain a self extractor code) |
||||
if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will |
||||
add files in existing zip (be sure you don't add file that doesn't exist) |
||||
If the zipfile cannot be opened, the return value is NULL. |
||||
Else, the return value is a zipFile Handle, usable with other function |
||||
of this zip package. |
||||
*/ |
||||
|
||||
/* Note : there is no delete function into a zipfile.
|
||||
If you want delete file into a zipfile, you must open a zipfile, and create another |
||||
Of couse, you can use RAW reading and writing to copy the file you did not want delte |
||||
*/ |
||||
|
||||
extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, |
||||
int append, |
||||
zipcharpc* globalcomment, |
||||
zlib_filefunc_def* pzlib_filefunc_def)); |
||||
|
||||
extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, |
||||
const char* filename, |
||||
const zip_fileinfo* zipfi, |
||||
const void* extrafield_local, |
||||
uInt size_extrafield_local, |
||||
const void* extrafield_global, |
||||
uInt size_extrafield_global, |
||||
const char* comment, |
||||
int method, |
||||
int level)); |
||||
/*
|
||||
Open a file in the ZIP for writing. |
||||
filename : the filename in zip (if NULL, '-' without quote will be used |
||||
*zipfi contain supplemental information |
||||
if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local |
||||
contains the extrafield data the the local header |
||||
if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global |
||||
contains the extrafield data the the local header |
||||
if comment != NULL, comment contain the comment string |
||||
method contain the compression method (0 for store, Z_DEFLATED for deflate) |
||||
level contain the level of compression (can be Z_DEFAULT_COMPRESSION) |
||||
*/ |
||||
|
||||
|
||||
extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, |
||||
const char* filename, |
||||
const zip_fileinfo* zipfi, |
||||
const void* extrafield_local, |
||||
uInt size_extrafield_local, |
||||
const void* extrafield_global, |
||||
uInt size_extrafield_global, |
||||
const char* comment, |
||||
int method, |
||||
int level, |
||||
int raw)); |
||||
|
||||
/*
|
||||
Same than zipOpenNewFileInZip, except if raw=1, we write raw file |
||||
*/ |
||||
|
||||
extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, |
||||
const char* filename, |
||||
const zip_fileinfo* zipfi, |
||||
const void* extrafield_local, |
||||
uInt size_extrafield_local, |
||||
const void* extrafield_global, |
||||
uInt size_extrafield_global, |
||||
const char* comment, |
||||
int method, |
||||
int level, |
||||
int raw, |
||||
int windowBits, |
||||
int memLevel, |
||||
int strategy, |
||||
const char* password, |
||||
uLong crcForCtypting)); |
||||
|
||||
/*
|
||||
Same than zipOpenNewFileInZip2, except |
||||
windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 |
||||
password : crypting password (NULL for no crypting) |
||||
crcForCtypting : crc of file to compress (needed for crypting) |
||||
*/ |
||||
|
||||
|
||||
extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, |
||||
const void* buf, |
||||
unsigned len)); |
||||
/*
|
||||
Write data in the zipfile |
||||
*/ |
||||
|
||||
extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); |
||||
/*
|
||||
Close the current file in the zipfile |
||||
*/ |
||||
|
||||
extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, |
||||
uLong uncompressed_size, |
||||
uLong crc32)); |
||||
/*
|
||||
Close the current file in the zipfile, for fiel opened with |
||||
parameter raw=1 in zipOpenNewFileInZip2 |
||||
uncompressed_size and crc32 are value for the uncompressed size |
||||
*/ |
||||
|
||||
extern int ZEXPORT zipClose OF((zipFile file, |
||||
const char* global_comment)); |
||||
/*
|
||||
Close the zipfile |
||||
*/ |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* _zip_H */ |
||||
|
@ -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.
@ -1,149 +1,258 @@ |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <windows.h> |
||||
#include "zlib.h" |
||||
|
||||
int ReadFileMemory(const char* filename,long* plFileSize,void** pFilePtr) |
||||
{ |
||||
FILE* stream; |
||||
void* ptr; |
||||
int retVal=1; |
||||
stream=fopen(filename, "rb"); |
||||
if (stream==NULL) |
||||
return 0; |
||||
|
||||
fseek(stream,0,SEEK_END); |
||||
|
||||
*plFileSize=ftell(stream); |
||||
fseek(stream,0,SEEK_SET); |
||||
ptr=malloc((*plFileSize)+1); |
||||
if (ptr==NULL) |
||||
retVal=0; |
||||
else |
||||
{ |
||||
if (fread(ptr, 1, *plFileSize,stream) != (*plFileSize)) |
||||
retVal=0; |
||||
} |
||||
fclose(stream); |
||||
*pFilePtr=ptr; |
||||
return retVal; |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
int BlockSizeCompress=0x8000; |
||||
int BlockSizeUncompress=0x8000; |
||||
int cprLevel=Z_DEFAULT_COMPRESSION ; |
||||
long lFileSize; |
||||
unsigned char* FilePtr; |
||||
long lBufferSizeCpr; |
||||
long lBufferSizeUncpr; |
||||
long lCompressedSize=0; |
||||
unsigned char* CprPtr; |
||||
unsigned char* UncprPtr; |
||||
long lSizeCpr,lSizeUncpr; |
||||
DWORD dwGetTick; |
||||
|
||||
if (argc<=1) |
||||
{ |
||||
printf("run TestZlib <File> [BlockSizeCompress] [BlockSizeUncompress] [compres. level]\n"); |
||||
return 0; |
||||
} |
||||
|
||||
if (ReadFileMemory(argv[1],&lFileSize,&FilePtr)==0) |
||||
{ |
||||
printf("error reading %s\n",argv[1]); |
||||
return 1; |
||||
} |
||||
else printf("file %s read, %u bytes\n",argv[1],lFileSize); |
||||
|
||||
if (argc>=3) |
||||
BlockSizeCompress=atol(argv[2]); |
||||
|
||||
if (argc>=4) |
||||
BlockSizeUncompress=atol(argv[3]); |
||||
|
||||
if (argc>=5) |
||||
cprLevel=(int)atol(argv[4]); |
||||
|
||||
lBufferSizeCpr = lFileSize + (lFileSize/0x10) + 0x200; |
||||
lBufferSizeUncpr = lBufferSizeCpr; |
||||
|
||||
CprPtr=(unsigned char*)malloc(lBufferSizeCpr + BlockSizeCompress); |
||||
UncprPtr=(unsigned char*)malloc(lBufferSizeUncpr + BlockSizeUncompress); |
||||
|
||||
dwGetTick=GetTickCount(); |
||||
{ |
||||
z_stream zcpr; |
||||
int ret=Z_OK; |
||||
long lOrigToDo = lFileSize; |
||||
long lOrigDone = 0; |
||||
int step=0; |
||||
memset(&zcpr,0,sizeof(z_stream)); |
||||
deflateInit(&zcpr,cprLevel); |
||||
|
||||
zcpr.next_in = FilePtr; |
||||
zcpr.next_out = CprPtr; |
||||
|
||||
|
||||
do |
||||
{ |
||||
long all_read_before = zcpr.total_in; |
||||
zcpr.avail_in = min(lOrigToDo,BlockSizeCompress); |
||||
zcpr.avail_out = BlockSizeCompress; |
||||
ret=deflate(&zcpr,(zcpr.avail_in==lOrigToDo) ? Z_FINISH : Z_SYNC_FLUSH); |
||||
lOrigDone += (zcpr.total_in-all_read_before); |
||||
lOrigToDo -= (zcpr.total_in-all_read_before); |
||||
step++; |
||||
} while (ret==Z_OK); |
||||
|
||||
lSizeCpr=zcpr.total_out; |
||||
deflateEnd(&zcpr); |
||||
dwGetTick=GetTickCount()-dwGetTick; |
||||
printf("total compress size = %u, in %u step\n",lSizeCpr,step); |
||||
printf("time = %u msec = %f sec\n\n",dwGetTick,dwGetTick/(double)1000.); |
||||
} |
||||
|
||||
dwGetTick=GetTickCount(); |
||||
{ |
||||
z_stream zcpr; |
||||
int ret=Z_OK; |
||||
long lOrigToDo = lSizeCpr; |
||||
long lOrigDone = 0; |
||||
int step=0; |
||||
memset(&zcpr,0,sizeof(z_stream)); |
||||
inflateInit(&zcpr); |
||||
|
||||
zcpr.next_in = CprPtr; |
||||
zcpr.next_out = UncprPtr; |
||||
|
||||
|
||||
do |
||||
{ |
||||
long all_read_before = zcpr.total_in; |
||||
zcpr.avail_in = min(lOrigToDo,BlockSizeUncompress); |
||||
zcpr.avail_out = BlockSizeUncompress; |
||||
ret=inflate(&zcpr,Z_SYNC_FLUSH); |
||||
lOrigDone += (zcpr.total_in-all_read_before); |
||||
lOrigToDo -= (zcpr.total_in-all_read_before); |
||||
step++; |
||||
} while (ret==Z_OK); |
||||
|
||||
lSizeUncpr=zcpr.total_out; |
||||
inflateEnd(&zcpr); |
||||
dwGetTick=GetTickCount()-dwGetTick; |
||||
printf("total uncompress size = %u, in %u step\n",lSizeUncpr,step); |
||||
printf("time = %u msec = %f sec\n\n",dwGetTick,dwGetTick/(double)1000.); |
||||
} |
||||
|
||||
if (lSizeUncpr==lFileSize) |
||||
{ |
||||
if (memcmp(FilePtr,UncprPtr,lFileSize)==0) |
||||
printf("compare ok\n"); |
||||
|
||||
} |
||||
|
||||
return 0; |
||||
|
||||
} |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <windows.h> |
||||
#include "zlib.h" |
||||
|
||||
|
||||
void MyDoMinus64(LARGE_INTEGER *R,LARGE_INTEGER A,LARGE_INTEGER B) |
||||
{ |
||||
R->HighPart = A.HighPart - B.HighPart; |
||||
if (A.LowPart >= B.LowPart) |
||||
R->LowPart = A.LowPart - B.LowPart; |
||||
else |
||||
{ |
||||
R->LowPart = A.LowPart - B.LowPart; |
||||
R->HighPart --; |
||||
} |
||||
} |
||||
|
||||
#ifdef _AMD64_ |
||||
unsigned _int64 myrdtsc(); |
||||
void BeginCountRdtsc(LARGE_INTEGER * pbeginTime64) |
||||
{ |
||||
// printf("rdtsc = %I64x\n",myrdtsc());
|
||||
pbeginTime64->QuadPart=myrdtsc(); |
||||
} |
||||
|
||||
LARGE_INTEGER GetResRdtsc(LARGE_INTEGER beginTime64,BOOL fComputeTimeQueryPerf) |
||||
{ |
||||
LARGE_INTEGER LIres; |
||||
unsigned _int64 res=myrdtsc()-((unsigned _int64)(beginTime64.QuadPart)); |
||||
LIres.QuadPart=res; |
||||
// printf("rdtsc = %I64x\n",myrdtsc());
|
||||
return LIres; |
||||
} |
||||
#else |
||||
void myGetRDTSC32(LARGE_INTEGER * pbeginTime64) |
||||
{ |
||||
DWORD dwEdx,dwEax; |
||||
_asm |
||||
{ |
||||
rdtsc |
||||
mov dwEax,eax |
||||
mov dwEdx,edx |
||||
} |
||||
pbeginTime64->LowPart=dwEax; |
||||
pbeginTime64->HighPart=dwEdx; |
||||
} |
||||
|
||||
void BeginCountRdtsc(LARGE_INTEGER * pbeginTime64) |
||||
{ |
||||
myGetRDTSC32(pbeginTime64); |
||||
} |
||||
|
||||
LARGE_INTEGER GetResRdtsc(LARGE_INTEGER beginTime64,BOOL fComputeTimeQueryPerf) |
||||
{ |
||||
LARGE_INTEGER LIres,endTime64; |
||||
myGetRDTSC32(&endTime64); |
||||
|
||||
LIres.LowPart=LIres.HighPart=0; |
||||
MyDoMinus64(&LIres,endTime64,beginTime64); |
||||
return LIres; |
||||
} |
||||
#endif |
||||
|
||||
|
||||
void BeginCountPerfCounter(LARGE_INTEGER * pbeginTime64,BOOL fComputeTimeQueryPerf) |
||||
{ |
||||
if ((!fComputeTimeQueryPerf) || (!QueryPerformanceCounter(pbeginTime64))) |
||||
{ |
||||
pbeginTime64->LowPart = GetTickCount(); |
||||
pbeginTime64->HighPart = 0; |
||||
} |
||||
} |
||||
|
||||
DWORD GetMsecSincePerfCounter(LARGE_INTEGER beginTime64,BOOL fComputeTimeQueryPerf) |
||||
{ |
||||
LARGE_INTEGER endTime64,ticksPerSecond,ticks; |
||||
DWORDLONG ticksShifted,tickSecShifted; |
||||
DWORD dwLog=16+0; |
||||
DWORD dwRet; |
||||
if ((!fComputeTimeQueryPerf) || (!QueryPerformanceCounter(&endTime64))) |
||||
dwRet = (GetTickCount() - beginTime64.LowPart)*1; |
||||
else |
||||
{ |
||||
MyDoMinus64(&ticks,endTime64,beginTime64); |
||||
QueryPerformanceFrequency(&ticksPerSecond); |
||||
|
||||
|
||||
{ |
||||
ticksShifted = Int64ShrlMod32(*(DWORDLONG*)&ticks,dwLog); |
||||
tickSecShifted = Int64ShrlMod32(*(DWORDLONG*)&ticksPerSecond,dwLog); |
||||
|
||||
}
|
||||
|
||||
dwRet = (DWORD)((((DWORD)ticksShifted)*1000)/(DWORD)(tickSecShifted)); |
||||
dwRet *=1; |
||||
} |
||||
return dwRet; |
||||
} |
||||
|
||||
int ReadFileMemory(const char* filename,long* plFileSize,void** pFilePtr) |
||||
{ |
||||
FILE* stream; |
||||
void* ptr; |
||||
int retVal=1; |
||||
stream=fopen(filename, "rb"); |
||||
if (stream==NULL) |
||||
return 0; |
||||
|
||||
fseek(stream,0,SEEK_END); |
||||
|
||||
*plFileSize=ftell(stream); |
||||
fseek(stream,0,SEEK_SET); |
||||
ptr=malloc((*plFileSize)+1); |
||||
if (ptr==NULL) |
||||
retVal=0; |
||||
else |
||||
{ |
||||
if (fread(ptr, 1, *plFileSize,stream) != (*plFileSize)) |
||||
retVal=0; |
||||
} |
||||
fclose(stream); |
||||
*pFilePtr=ptr; |
||||
return retVal; |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
int BlockSizeCompress=0x8000; |
||||
int BlockSizeUncompress=0x8000; |
||||
int cprLevel=Z_DEFAULT_COMPRESSION ; |
||||
long lFileSize; |
||||
unsigned char* FilePtr; |
||||
long lBufferSizeCpr; |
||||
long lBufferSizeUncpr; |
||||
long lCompressedSize=0; |
||||
unsigned char* CprPtr; |
||||
unsigned char* UncprPtr; |
||||
long lSizeCpr,lSizeUncpr; |
||||
DWORD dwGetTick,dwMsecQP; |
||||
LARGE_INTEGER li_qp,li_rdtsc,dwResRdtsc; |
||||
|
||||
if (argc<=1) |
||||
{ |
||||
printf("run TestZlib <File> [BlockSizeCompress] [BlockSizeUncompress] [compres. level]\n"); |
||||
return 0; |
||||
} |
||||
|
||||
if (ReadFileMemory(argv[1],&lFileSize,&FilePtr)==0) |
||||
{ |
||||
printf("error reading %s\n",argv[1]); |
||||
return 1; |
||||
} |
||||
else printf("file %s read, %u bytes\n",argv[1],lFileSize); |
||||
|
||||
if (argc>=3) |
||||
BlockSizeCompress=atol(argv[2]); |
||||
|
||||
if (argc>=4) |
||||
BlockSizeUncompress=atol(argv[3]); |
||||
|
||||
if (argc>=5) |
||||
cprLevel=(int)atol(argv[4]); |
||||
|
||||
lBufferSizeCpr = lFileSize + (lFileSize/0x10) + 0x200; |
||||
lBufferSizeUncpr = lBufferSizeCpr; |
||||
|
||||
CprPtr=(unsigned char*)malloc(lBufferSizeCpr + BlockSizeCompress); |
||||
|
||||
BeginCountPerfCounter(&li_qp,TRUE); |
||||
dwGetTick=GetTickCount(); |
||||
BeginCountRdtsc(&li_rdtsc); |
||||
{ |
||||
z_stream zcpr; |
||||
int ret=Z_OK; |
||||
long lOrigToDo = lFileSize; |
||||
long lOrigDone = 0; |
||||
int step=0; |
||||
memset(&zcpr,0,sizeof(z_stream)); |
||||
deflateInit(&zcpr,cprLevel); |
||||
|
||||
zcpr.next_in = FilePtr; |
||||
zcpr.next_out = CprPtr; |
||||
|
||||
|
||||
do |
||||
{ |
||||
long all_read_before = zcpr.total_in; |
||||
zcpr.avail_in = min(lOrigToDo,BlockSizeCompress); |
||||
zcpr.avail_out = BlockSizeCompress; |
||||
ret=deflate(&zcpr,(zcpr.avail_in==lOrigToDo) ? Z_FINISH : Z_SYNC_FLUSH); |
||||
lOrigDone += (zcpr.total_in-all_read_before); |
||||
lOrigToDo -= (zcpr.total_in-all_read_before); |
||||
step++; |
||||
} while (ret==Z_OK); |
||||
|
||||
lSizeCpr=zcpr.total_out; |
||||
deflateEnd(&zcpr); |
||||
dwGetTick=GetTickCount()-dwGetTick; |
||||
dwMsecQP=GetMsecSincePerfCounter(li_qp,TRUE); |
||||
dwResRdtsc=GetResRdtsc(li_rdtsc,TRUE); |
||||
printf("total compress size = %u, in %u step\n",lSizeCpr,step); |
||||
printf("time = %u msec = %f sec\n",dwGetTick,dwGetTick/(double)1000.); |
||||
printf("defcpr time QP = %u msec = %f sec\n",dwMsecQP,dwMsecQP/(double)1000.); |
||||
printf("defcpr result rdtsc = %I64x\n\n",dwResRdtsc.QuadPart); |
||||
} |
||||
|
||||
CprPtr=(unsigned char*)realloc(CprPtr,lSizeCpr); |
||||
UncprPtr=(unsigned char*)malloc(lBufferSizeUncpr + BlockSizeUncompress); |
||||
|
||||
BeginCountPerfCounter(&li_qp,TRUE); |
||||
dwGetTick=GetTickCount(); |
||||
BeginCountRdtsc(&li_rdtsc); |
||||
{ |
||||
z_stream zcpr; |
||||
int ret=Z_OK; |
||||
long lOrigToDo = lSizeCpr; |
||||
long lOrigDone = 0; |
||||
int step=0; |
||||
memset(&zcpr,0,sizeof(z_stream)); |
||||
inflateInit(&zcpr); |
||||
|
||||
zcpr.next_in = CprPtr; |
||||
zcpr.next_out = UncprPtr; |
||||
|
||||
|
||||
do |
||||
{ |
||||
long all_read_before = zcpr.total_in; |
||||
zcpr.avail_in = min(lOrigToDo,BlockSizeUncompress); |
||||
zcpr.avail_out = BlockSizeUncompress; |
||||
ret=inflate(&zcpr,Z_SYNC_FLUSH); |
||||
lOrigDone += (zcpr.total_in-all_read_before); |
||||
lOrigToDo -= (zcpr.total_in-all_read_before); |
||||
step++; |
||||
} while (ret==Z_OK); |
||||
|
||||
lSizeUncpr=zcpr.total_out; |
||||
inflateEnd(&zcpr); |
||||
dwGetTick=GetTickCount()-dwGetTick; |
||||
dwMsecQP=GetMsecSincePerfCounter(li_qp,TRUE); |
||||
dwResRdtsc=GetResRdtsc(li_rdtsc,TRUE); |
||||
printf("total uncompress size = %u, in %u step\n",lSizeUncpr,step); |
||||
printf("time = %u msec = %f sec\n",dwGetTick,dwGetTick/(double)1000.); |
||||
printf("uncpr time QP = %u msec = %f sec\n",dwMsecQP,dwMsecQP/(double)1000.); |
||||
printf("uncpr result rdtsc = %I64x\n\n",dwResRdtsc.QuadPart); |
||||
} |
||||
|
||||
if (lSizeUncpr==lFileSize) |
||||
{ |
||||
if (memcmp(FilePtr,UncprPtr,lFileSize)==0) |
||||
printf("compare ok\n"); |
||||
|
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
@ -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