vms.c
来自「压缩算法的源代码」· C语言 代码 · 共 2,500 行 · 第 1/5 页
C
2,500 行
memcpy(block, init, needlen);
switch (cmptype)
{
case BC_STORED: /* The simplest case */
memcpy(block, &(p->body[0]), usiz);
break;
case BC_00:
decompress_bits(block, usiz, &(p->body[0]));
break;
case BC_DEFL:
memextract(block, usiz, &(p->body[0]), csiz);
break;
default:
free(block);
block = NULL;
}
return block;
}
/*
* Simple uncompression routine. The compression uses bit stream.
* Compression scheme:
*
* if(byte!=0)
* putbit(1),putbyte(byte)
* else
* putbit(0)
*/
static void decompress_bits(outptr, needlen, bitptr)
uch *bitptr; /* Pointer into compressed data */
uch *outptr; /* Pointer into output block */
int needlen; /* Size of uncompressed block */
{
ulg bitbuf = 0;
int bitcnt = 0;
#define _FILL if(bitcnt+8 <= 32) \
{ bitbuf |= (*bitptr++) << bitcnt;\
bitcnt += 8; \
}
while (needlen--)
{
if (bitcnt <= 0)
_FILL;
if (bitbuf & 1)
{
bitbuf >>= 1;
if ((bitcnt -= 1) < 8)
_FILL;
*outptr++ = (uch) bitbuf;
bitcnt -= 8;
bitbuf >>= 8;
}
else
{
*outptr++ = 0;
bitcnt -= 1;
bitbuf >>= 1;
}
}
}
static void UpdateCRC(s, len)
register uch *s;
register int len;
{
register ulg crcval = crc32val;
/* update running CRC calculation with contents of a buffer */
while (len--)
crcval = crc_32_tab[((uch)crcval ^ (*s++)) & 0xff] ^ (crcval >> 8);
crc32val = crcval;
}
/* flush contents of output buffer */
int flush(rawbuf, size, unshrink) /* return PK-type error code */
uch *rawbuf;
ulg size;
int unshrink;
{
UpdateCRC(rawbuf, size);
if (tflag)
return PK_COOL; /* Do not output. Update CRC only */
else
return (*_flush_routine)(rawbuf, size, 0);
}
static int _flush_blocks(rawbuf, size, final_flag) /* Asynchronous version */
uch *rawbuf;
unsigned size;
int final_flag; /* 1 if this is the final flushout */
{
int round;
int rest;
int off = 0;
int status;
while (size > 0)
{
if (curbuf->bufcnt < BUFS512)
{
int ncpy;
ncpy = size > (BUFS512 - curbuf->bufcnt) ?
BUFS512 - curbuf->bufcnt :
size;
memcpy(curbuf->buf + curbuf->bufcnt, rawbuf + off, ncpy);
size -= ncpy;
curbuf->bufcnt += ncpy;
off += ncpy;
}
if (curbuf->bufcnt == BUFS512)
{
status = WriteBuffer(curbuf->buf, curbuf->bufcnt);
if (status)
return status;
curbuf = curbuf->next;
curbuf->bufcnt = 0;
}
}
return (final_flag && (curbuf->bufcnt > 0)) ?
WriteBuffer(curbuf->buf, curbuf->bufcnt) :
PK_COOL;
}
static int _flush_qio(rawbuf, size, final_flag)
uch *rawbuf;
unsigned size;
int final_flag; /* 1 if this is the final flushout -- currently ignored */
{
int status;
uch *out_ptr=rawbuf;
if( final_flag )
{
if( loccnt > 0 )
{ status = sys$qiow(0, pka_devchn, IO$_WRITEVBLK,
&pka_io_sb, 0, 0,
locbuf, ((loccnt+1)/2)*2, /* Round to event byte count */
pka_vbn,
0, 0, 0);
if(!ERR(status))
status = pka_io_sb.status;
if(ERR(status))
{ message("[ Write QIO failed ]\n",status);
return PK_DISK;
}
}
return PK_COOL;
}
if( loccnt > 0 )
{ /*
* Fill local buffer upto 512 bytes then put it out
*/
int ncpy;
ncpy = 512-loccnt;
if( ncpy > size )
ncpy = size;
memcpy(locptr,rawbuf,ncpy);
locptr += ncpy;
loccnt += ncpy;
size -= ncpy;
out_ptr += ncpy;
if( loccnt == 512 )
{
status = sys$qiow(0, pka_devchn, IO$_WRITEVBLK,
&pka_io_sb, 0, 0,
locbuf, loccnt, pka_vbn,
0, 0, 0);
if(!ERR(status))
status = pka_io_sb.status;
if(ERR(status))
{ message("[ Write QIO failed ]\n",status);
return PK_DISK;
}
pka_vbn++;
loccnt = 0;
locptr = locbuf;
}
}
if( size >= 512 )
{ int nblk,put_cnt;
/*
* Put rest of buffer as a single VB
*/
put_cnt = (nblk = size>>9)<<9;
status = sys$qiow(0, pka_devchn, IO$_WRITEVBLK,
&pka_io_sb, 0, 0,
out_ptr, put_cnt, pka_vbn,
0, 0, 0);
if(!ERR(status))
status = pka_io_sb.status;
if(ERR(status))
{ message("[ Write QIO failed ]\n",status);
return PK_DISK;
}
pka_vbn += nblk;
out_ptr += put_cnt;
size -= put_cnt;
}
if( size > 0 )
{ memcpy(locptr,out_ptr,size);
loccnt += size;
locptr += size;
}
return PK_COOL;
}
static int _flush_varlen(rawbuf, size, final_flag)
uch *rawbuf;
unsigned size;
int final_flag;
{
ush nneed;
ush reclen;
uch *inptr=rawbuf;
/*
* Flush local buffer
*/
if( loccnt > 0 )
{ reclen = *(ush*)locbuf;
if( (nneed = reclen + 2 - loccnt) > 0 )
{ if( nneed > size )
{ if( size+loccnt > BUFS512 )
{ fprintf(stderr,"[ Record too long (%d bytes) ]\n",reclen );
return PK_DISK;
}
memcpy(locbuf+loccnt,rawbuf,size);
loccnt += size;
size = 0;
}
else
{ memcpy(locbuf+loccnt,rawbuf,nneed);
loccnt += nneed;
size -= nneed;
inptr += nneed;
if( reclen & 1 )
{ size--;
inptr++;
}
if( WriteRecord(locbuf+2,reclen) )
return PK_DISK;
loccnt = 0;
}
}
else
{ if(WriteRecord(locbuf+2,reclen))
return PK_DISK;
loccnt -= reclen+2;
}
}
/*
* Flush incoming records
*/
while(size > 0)
{ reclen = *(ush*)inptr;
if( reclen+2 <= size )
{ if(WriteRecord(inptr+2,reclen))
return PK_DISK;
size -= 2+reclen;
inptr += 2+reclen;
if( reclen & 1)
{ --size;
++inptr;
}
}
else
{ memcpy(locbuf,inptr,size);
loccnt = size;
size = 0;
}
}
/*
* Final flush rest of local buffer
*/
if( final_flag && loccnt > 0 )
{ fprintf(stderr,
"[ Warning, incomplete record of length %d ]\n",
*(ush*)locbuf);
if( WriteRecord(locbuf+2,loccnt-2) )
return PK_DISK;
}
return PK_COOL;
}
/*
* Routine _flush_stream breaks decompressed stream into records
* depending on format of the stream (fab->rfm, pInfo->textmode, etc.)
* and puts out these records. It also handles CR LF sequences.
* Should be used when extracting *text* files.
*/
#define VT 0x0B
#define FF 0x0C
/* The file is from MSDOS/OS2/NT -> handle CRLF as record end, throw out ^Z */
/* GRR NOTES: cannot depend on hostnum! May have "flip'd" file or re-zipped
* a Unix file, etc. */
#ifdef USE_ORIG_DOS
# define ORG_DOS (hostnum==FS_FAT_ || hostnum==FS_HPFS_ || hostnum==FS_NTFS_)
#else
# define ORG_DOS 1
#endif
/* Record delimiters */
#ifdef undef
#define RECORD_END(c,f) \
( ( ORG_DOS || pInfo->textmode ) && c==CTRLZ \
|| ( f == FAB$C_STMLF && c==LF ) \
|| ( f == FAB$C_STMCR || ORG_DOS || pInfo->textmode ) && c==CR \
|| ( f == FAB$C_STM && (c==CR || c==LF || c==FF || c==VT) ) \
)
#else
# define RECORD_END(c,f) ((c) == LF || (c) == (CR))
#endif
static int find_eol(p,n,l)
/*
* Find first CR,LF,CR-LF or LF-CR in string 'p' of length 'n'.
* Return offset of the sequence found or 'n' if not found.
* If found, return in '*l' length of the sequence (1 or 2) or
* zero if sequence end not seen, i.e. CR or LF is last char
* in the buffer.
*/
char *p;
int n;
int *l;
{ int off = n;
char *q;
*l = 0;
for(q=p ; n > 0 ; --n,++q)
if( RECORD_END(*q,rfm) )
{ off = q-p;
break;
}
if( n > 1 )
{
*l = 1;
if( ( q[0] == CR && q[1] == LF ) || ( q[0] == LF && q[1] == CR ) )
*l = 2;
}
return off;
}
/* Record delimiters that must be put out */
#define PRINT_SPEC(c) ( (c)==FF || (c)==VT )
static int _flush_stream(rawbuf, size, final_flag)
uch *rawbuf;
unsigned size;
int final_flag; /* 1 if this is the final flushout */
{
int rest;
int end = 0, start = 0;
int off = 0;
if (size == 0 && loccnt == 0)
return PK_COOL; /* Nothing to do ... */
if( final_flag )
{ int recsize;
/*
* This is flush only call. size must be zero now.
* Just eject everything we have in locbuf.
*/
recsize = loccnt - (got_eol ? 1:0);
/*
* If the last char of file was ^Z ( end-of-file in MSDOS ),
* we will see it now.
*/
if( recsize==1 && locbuf[0] == CTRLZ )
return PK_COOL;
return WriteRecord(locbuf, recsize) ? PK_DISK : PK_COOL;
}
if ( loccnt > 0 )
{ /* Find end of record partialy saved in locbuf */
int recsize;
int complete=0;
if( got_eol )
{ recsize = loccnt - 1;
complete = 1;
if( (got_eol == CR && rawbuf[0] == LF) || (got_eol == LF && rawbuf[0] == CR) )
end = 1;
got_eol = 0;
}
else
{ int eol_len;
int eol_off;
eol_off = find_eol(rawbuf,size,&eol_len);
if( loccnt+eol_off > BUFS512 )
{ /*
* No room in locbuf. Dump it and clear
*/
recsize = loccnt;
start = 0;
fprintf(stderr, "[ Warning: Record too long (%d) ]\n",
loccnt+eol_off);
complete = 1;
end = 0;
}
else
{ if( eol_off >= size )
{ end = size;
complete = 0;
}
else if( eol_len == 0 )
{ got_eol = rawbuf[eol_off];
end = size;
complete = 0;
}
else
{ memcpy(locptr, rawbuf, eol_off);
recsize = loccnt + eol_off;
locptr += eol_off;
loccnt += eol_off;
end = eol_off + eol_len;
complete = 1;
}
}
}
if( complete )
{ if (WriteRecord(locbuf, recsize))
return PK_DISK;
loccnt = 0;
locptr = locbuf;
}
} /* end if( loccnt ) */
for(start = end; start < size && end < size; )
{ int eol_off,eol_len;
got_eol = 0;
#ifdef undef
if (cflag)
/* skip CR's at the beginning of record */
while (start < size && rawbuf[start] == CR)
++start;
#endif
if( start >= size )
continue;
/* Find record end */
end = start+(eol_off = find_eol(rawbuf+start, size-start, &eol_len));
if( end >= size )
continue;
if( eol_len > 0 )
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?