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 + -
显示快捷键?