Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

595 lines
18 KiB

/*++
Copyright (c) 1996 - 1999 Microsoft Corporation
Module Name:
compress.c
Abstract:
Implementation of compression formats for sending data to devices.
Environment:
Windows NT Unidrv driver
Revision History:
12/15/96 -alvins-
Created
--*/
#include "raster.h"
#include "compress.h" /* Function prototypes */
//*************************************************************
int
iCompTIFF(
BYTE *pbOBuf,
BYTE *pbIBuf,
int iBCnt
)
/*++
Routine Description:
This function is called to compress a scan line of data using
TIFF v4 compression.
Arguments:
pbOBuf Pointer to output buffer PRESUMED LARGE ENOUGH
pbIBuf Pointer to data buffer to compress
iBCnt Number of bytes to compress
Return Value:
Number of compressed bytes
Note:
The output buffer is presumed large enough to hold the output.
In the worst case (NO REPETITIONS IN DATA) there is an extra
byte added every 128 bytes of input data. So, you should make
the output buffer at least 1% larger than the input buffer.
--*/
{
BYTE *pbOut; /* Output byte location */
BYTE *pbStart; /* Start of current input stream */
BYTE *pb; /* Miscellaneous usage */
BYTE *pbEnd; /* The last byte of input */
BYTE jLast; /* Last byte, for match purposes */
BYTE bLast;
int iSize; /* Bytes in the current length */
int iSend; /* Number to send in this command */
pbOut = pbOBuf;
pbStart = pbIBuf;
pbEnd = pbIBuf + iBCnt; /* The last byte */
#if (TIFF_MIN_RUN >= 4)
// this is a faster algorithm for calculating TIFF compression
// that assumes a minimum RUN of at least 4 bytes. If the
// third and fourth byte don't equal then the first/second bytes are
// irrelevant. This means we can determine non-run data three times
// as fast since we only check every third byte pair.
if (iBCnt > TIFF_MIN_RUN)
{
// make sure the last two bytes aren't equal so we don't have to check
// for the buffer end when looking for runs
bLast = pbEnd[-1];
pbEnd[-1] = ~pbEnd[-2];
while( (pbIBuf += 3) < pbEnd )
{
if (*pbIBuf == pbIBuf[-1])
{
// save the run start pointer, pb, and check whether the first
// bytes are also part of the run
//
pb = pbIBuf-1;
if (*pbIBuf == pbIBuf[-2])
{
pb--;
if (*pbIBuf == pbIBuf[-3])
pb--;
}
// Find out how long this run is
jLast = *pb;
do {
pbIBuf++;
} while (*pbIBuf == jLast);
// test whether last byte is also part of the run
//
if (jLast == bLast && pbIBuf == (pbEnd-1))
pbIBuf++;
// Determine if the run is longer that the required
// minimum run size.
//
if ((iSend = (int)(pbIBuf - pb)) >= (TIFF_MIN_RUN))
{
/*
* Worth recording as a run, so first set the literal
* data which may have already been scanned before recording
* this run.
*/
if( (iSize = (int)(pb - pbStart)) > 0 )
{
/* There is literal data, so record it now */
while (iSize > TIFF_MAX_LITERAL)
{
iSize -= TIFF_MAX_LITERAL;
*pbOut++ = TIFF_MAX_LITERAL-1;
CopyMemory(pbOut, pbStart, TIFF_MAX_LITERAL);
pbStart += TIFF_MAX_LITERAL;
pbOut += TIFF_MAX_LITERAL;
}
*pbOut++ = iSize - 1;
CopyMemory(pbOut, pbStart, iSize);
pbOut += iSize;
}
/*
* Now for the repeat pattern. Same logic, but only
* one byte is needed per entry.
*/
iSize = iSend;
while (iSize > TIFF_MAX_RUN)
{
*((char *)pbOut)++ = 1 - TIFF_MAX_RUN;
*pbOut++ = jLast;
iSize -= TIFF_MAX_RUN;
}
*pbOut++ = 1 - iSize;
*pbOut++ = jLast;
pbStart = pbIBuf; /* Ready for the next one! */
}
}
}
pbEnd[-1] = bLast;
}
#else
jLast = *pbIBuf++;
while( pbIBuf < pbEnd )
{
if( jLast == *pbIBuf )
{
/* Find out how long this run is. Then decide on using it */
pb = pbIBuf;
do {
pbIBuf++;
} while (pbIBuf < pbEnd && *pbIBuf == jLast);
/*
* Note that pb points at the SECOND byte of the pattern!
* AND also that pbIBuf points at the first byte AFTER the run.
*/
if ((iSend = pbIBuf - pb) >= (TIFF_MIN_RUN - 1))
{
/*
* Worth recording as a run, so first set the literal
* data which may have already been scanned before recording
* this run.
*/
if( (iSize = pb - pbStart - 1) > 0 )
{
/* There is literal data, so record it now */
while (iSize > TIFF_MAX_LITERAL)
{
iSize -= TIFF_MAX_LITERAL;
*pbOut++ = TIFF_MAX_LITERAL-1;
CopyMemory(pbOut, pbStart, TIFF_MAX_LITERAL);
pbStart += TIFF_MAX_LITERAL;
pbOut += TIFF_MAX_LITERAL;
}
*pbOut++ = iSize - 1;
CopyMemory(pbOut, pbStart, iSize);
pbOut += iSize;
}
/*
* Now for the repeat pattern. Same logic, but only
* one byte is needed per entry.
*/
iSize = iSend + 1;
while (iSize > TIFF_MAX_RUN)
{
*((char *)pbOut)++ = 1 - TIFF_MAX_RUN;
*pbOut++ = jLast;
iSize -= TIFF_MAX_RUN;
}
*pbOut++ = 1 - iSize;
*pbOut++ = jLast;
pbStart = pbIBuf; /* Ready for the next one! */
}
if (pbIBuf == pbEnd)
break;
}
jLast = *pbIBuf++; /* Onto the next byte */
}
#endif
if ((iSize = (int)(pbEnd - pbStart)) > 0)
{
/* Left some dangling. This can only be literal data. */
while( (iSend = min( iSize, TIFF_MAX_LITERAL )) > 0 )
{
*pbOut++ = iSend - 1;
CopyMemory( pbOut, pbStart, iSend );
pbOut += iSend;
pbStart += iSend;
iSize -= iSend;
}
}
return (int)(pbOut - pbOBuf);
}
//**********************************************************
int
iCompFERLE(
BYTE *pbOBuf,
BYTE *pbIBuf,
int iBCnt,
int iMaxCnt
)
/*++
Routine Description:
This function is called to compress a scan line of data using
Far East Run length encoding.
Arguments:
pbOBuf Pointer to output buffer PRESUMED LARGE ENOUGH
pbIBuf Pointer to data buffer to compress
iBCnt Number of bytes to compress
iMaxCnt Maximum number of bytes to create on output
Return Value:
Number of compressed bytes or -1 if too large for buffer
--*/
{
BYTE *pbO; /* Record output location */
BYTE *pbI; /* Scanning for runs */
BYTE *pbIEnd; /* First byte past end of input data */
BYTE *pbStart; /* Start of current data stream */
BYTE *pbTmp;
BYTE jLast; /* Previous byte */
int iSize; /* Number of bytes in the run */
if (iBCnt == 0)
return 0;
pbO = pbOBuf; /* Working copy */
pbIEnd = pbIBuf + iBCnt; /* Gone too far if we reach here */
/*
* Calculate the maximum amount of data we will generate
*/
pbStart = pbIBuf;
while (++pbIBuf < pbIEnd)
{
if (*pbIBuf == pbIBuf[-1])
{
// valid run but we will first output any literal data
if ((iSize = (int)(pbIBuf - pbStart) - 1) > 0)
{
if ((iMaxCnt -= iSize) < 0) // test for output overflow
return -1;
CopyMemory(pbO,pbStart,iSize);
pbO += iSize;
}
// determine the run length
jLast = *pbIBuf;
pbI = pbIBuf;
pbTmp = pbIBuf + FERLE_MAX_RUN - 1;
if (pbTmp > pbIEnd)
pbTmp = pbIEnd;
do {
pbIBuf++;
} while (pbIBuf < pbTmp && *pbIBuf == jLast);
iSize = (int)(pbIBuf - pbI) + 1; /* Number of times */
// output the RLE strings
if ((iMaxCnt -= 3) < 0) // test for output overflow
return -1;
*pbO++ = jLast; // copy data byte twice
*pbO++ = jLast;
*pbO++ = (BYTE)iSize;
// test if we are done
if( pbIBuf == pbIEnd )
return (int)(pbO - pbOBuf);
// setup for continuation of loop
pbStart = pbIBuf;
}
}
/*
* Since the data did not end in a run we must output the last
* literal data if we haven't overflowed the buffer.
*/
iSize = (int)(pbIBuf - pbStart);
if (iMaxCnt < iSize)
return -1;
CopyMemory(pbO,pbStart,iSize);
pbO += iSize;
return (int)(pbO - pbOBuf);
}
//****************************************************
int
iCompDeltaRow(
BYTE *pbOBuf,
BYTE *pbIBuf,
BYTE *pbPBuf,
int iBCnt,
int iLimit
)
/*++
Routine Description:
This function is called to compress a scan line of data using
delta row compression.
Arguments:
pbOBuf Pointer to output buffer
pbIBuf Pointer to data buffer to compress
pbPBuf Pointer to previous row data buffer
iBCnt Number of bytes in the above
iLimit Don't exceed this number of compressed bytes
Return Value:
Number of compressed bytes or -1 if too large for buffer
Note:
A return value of 0 is valid since it implies the two lines
are identical.
--*/
{
#ifdef _X86_
BYTE *pbO; /* Record output location */
BYTE *pbOEnd; /* As far as we will go in the output buffer */
BYTE *pbIEnd;
BYTE *pbStart;
BYTE *pb;
int iDelta;
int iOffset; // index of current data stream
int iSize; /* Number of bytes in the run */
/*
* Limit the amount of data we will generate. For performance
* reasons we will ignore the effects of an offset value
* greater than 30 since it implies we were able to already skip
* that many bytes. However, for safety sake we will reduce the
* max allowable size by 2 bytes.
*/
pbO = pbOBuf; /* Working copy */
pbOEnd = pbOBuf + iLimit - 2;
iDelta = pbPBuf - pbIBuf;
pbIEnd = pbIBuf + iBCnt;
pbStart = pbIBuf;
//
// this is the main loop for compressing the data
//
while (pbIBuf < pbIEnd)
{
// fast skip for matching dwords
//
if (!((ULONG_PTR)pbIBuf & 3))
{
while (pbIBuf <= (pbIEnd-4) && *(DWORD *)pbIBuf == *(DWORD *)&pbIBuf[iDelta])
pbIBuf += 4;
if (pbIBuf >= pbIEnd)
break;
}
// test for non-matching bytes and output the necessary compression string
//
if (*pbIBuf != pbIBuf[iDelta])
{
// determine the run length
pb = pbIBuf;
do {
pb++;
} while (pb < pbIEnd && *pb != pb[iDelta]);
iSize = (int)(pb - pbIBuf);
// Lets make sure we have room in the buffer before
// we continue this, this compression algorithm adds
// 1 byte for every 8 bytes of data worst case.
//
if (((iSize * 9 + 7) >> 3) > (pbOEnd - pbO)) // gives tighter code
return -1;
iOffset = (int)(pbIBuf - pbStart);
if (iOffset > 30)
{
if (iSize < 8)
*pbO++ = ((iSize-1) << 5) + 31;
else
*pbO++ = (7 << 5) + 31;
iOffset -= 31;
while (iOffset >= 255)
{
iOffset -= 255;
*pbO++ = 255;
}
*pbO++ = (BYTE)iOffset;
if (iSize > 8)
goto FastEightByteRun;
}
else if (iSize > 8)
{
*pbO++ = (7 << 5) + iOffset;
FastEightByteRun:
while (1)
{
CopyMemory(pbO,pbIBuf,8);
pbIBuf += 8;
pbO += 8;
if ((iSize -= 8) <= 8)
break;
*pbO++ = (7 << 5);
}
*pbO++ = (iSize-1) << 5;
}
else
*pbO++ = ((iSize-1) << 5) + iOffset;
CopyMemory (pbO,pbIBuf,iSize);
pbIBuf += iSize;
pbO += iSize;
pbStart = pbIBuf;
}
pbIBuf++;
}
return (int)(pbO - pbOBuf);
#else
BYTE *pbO; /* Record output location */
BYTE *pbOEnd; /* As far as we will go in the output buffer */
BYTE *pbIEnd;
BYTE *pbStart;
BYTE *pb;
int iOffset; // index of current data stream
int iSize; /* Number of bytes in the run */
/*
* Limit the amount of data we will generate. For performance
* reasons we will ignore the effects of an offset value
* greater than 30 since it implies we were able to already skip
* that many bytes. However, for safety sake we will reduce the
* max allowable size by 2 bytes.
*/
pbO = pbOBuf; /* Working copy */
pbOEnd = pbOBuf + iLimit - 2;
pbIEnd = pbIBuf + iBCnt;
pbStart = pbIBuf;
//
// this is the main loop for compressing the data
//
while (pbIBuf < pbIEnd)
{
// fast skip for matching dwords
//
if (!((ULONG_PTR)pbIBuf & 3))
{
while (pbIBuf <= (pbIEnd-4) && *(DWORD *)pbIBuf == *(DWORD *)pbPBuf)
{
pbIBuf += 4;
pbPBuf += 4;
}
if (pbIBuf >= pbIEnd)
break;
}
// test for non-matching bytes and output the necessary compression string
//
if (*pbIBuf != *pbPBuf)
{
// determine the run length
pb = pbIBuf;
do {
pb++;
pbPBuf++;
} while (pb < pbIEnd && *pb != *pbPBuf);
iSize = (int)(pb - pbIBuf);
// Lets make sure we have room in the buffer before
// we continue this, this compression algorithm adds
// 1 byte for every 8 bytes of data worst case.
//
if (((iSize * 9 + 7) >> 3) > (int)(pbOEnd - pbO))
return -1;
// special case the initial offset value since it
// occurs only once and may require extra bytes
//
if ((iOffset = (int)(pbIBuf - pbStart)))
{
int iSend = min (iSize,8);
if (iOffset > 30)
{
*pbO++ = ((iSend-1) << 5) + 31;
iOffset -= 31;
while (iOffset >= 255)
{
*pbO++ = 255;
iOffset -= 255;
}
*pbO++ = (BYTE)iOffset;
}
else
{
*pbO++ = ((iSend-1) << 5) + iOffset;
}
// output the initial changed bytes
CopyMemory(pbO,pbIBuf,iSend);
pbIBuf += iSend;
pbO += iSend;
iSize -= iSend;
}
// now output any remaining changed data
//
while (iSize)
{
if (iSize >= 8)
{
*pbO++ = (8 - 1) << 5;
CopyMemory(pbO,pbIBuf,8);
pbIBuf += 8;
pbO += 8;
iSize -= 8;
}
else
{
*pbO++ = (iSize-1) << 5;
CopyMemory(pbO,pbIBuf,iSize);
pbIBuf += iSize;
pbO += iSize;
break;
}
}
pbStart = pbIBuf;
}
pbIBuf++;
pbPBuf++;
}
return (int)(pbO - pbOBuf);
#endif
}