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.
 
 
 
 
 
 

580 lines
13 KiB

/*==============================================================================
This code module handles T4 conversion instances.
DATE NAME COMMENTS
12-Apr-93 RajeevD Adapted to C++ from WFW.
20-Apr-93 RajeevD Overhauled buffer handling.
==============================================================================*/
#include <ifaxos.h>
#include <memory.h>
#include <faxcodec.h>
#include "context.hpp"
#define RTC_EOL 5
#define VALIDATE_CHANGE
typedef short FAR *LPSHORT;
//==============================================================================
#pragma warning(disable:4704)
#ifdef WIN32
UINT // size of change vector (0 if invalid)
ValidChangeVector
(
LPSHORT lpsChange, // change vector buffer
SHORT xExt // pixel width of line
)
{
SHORT sPrev = -1;
SHORT cChange = xExt;
while (cChange--)
{
// Check monotonicity.
if (*lpsChange <= sPrev)
return 0;
sPrev = *lpsChange++;
if (sPrev == xExt)
{
// Check EOL termination.
if
( *lpsChange++ == xExt
&& *lpsChange++ == xExt
&& *lpsChange++ == xExt
&& *lpsChange++ == -1
&& *lpsChange++ == -1
)
return sizeof(WORD) * (xExt - cChange) ;
else
return 0;
}
} // while (cChange--)
return 0; // Hit end of change vector buffer.
}
#else // ifndef WIN32
UINT // size of change vector (0 if invalid)
ValidChangeVector
(
LPSHORT lpsChange, // change vector buffer
SHORT xExt // pixel width of line
)
{
UINT uRet;
_asm
{
push ds
push si
lds si, DWORD PTR [lpsChange] ; lpsChange
mov dx, -1 ; sPrev
mov cx, xExt ; cChange
mov bx, cx ; xExt
jmp enterloop
fooie:
lodsw
cmp ax, dx
jle error ; need SIGNED compare
mov dx, ax
cmp dx, bx
je goteol
enterloop:
loop fooie
error:
xor ax, ax
jmp done
goteol:
lodsw
cmp ax, bx ; bx == xExt
jne error
lodsw
cmp ax, bx
jne error
lodsw
cmp ax, bx
jne error
xor bx, bx
not bx ; bx == -1
lodsw
cmp ax, bx
jne error
lodsw
cmp ax, bx
jne error
// uRet = sizeof(WORD) * (xExt - cChange) ;
mov ax, xExt
sub ax, cx
inc ax
shl ax, 1
done:
pop si
pop ds
mov uRet, ax
}
return uRet;
}
#endif // WIN32
//==============================================================================
void CODEC::ResetBad (void)
{
DEBUGMSG (1,("FAXCODEC: decoded %d bad line(s)\r\n", wBad));
if (fcCount.cMaxRunBad < wBad)
fcCount.cMaxRunBad = wBad;
wBad = 0;
}
//==============================================================================
void CODEC::SwapChange (void)
{
LPBYTE lpbTemp;
lpbTemp = lpbChange;
lpbChange = lpbRef;
lpbRef = lpbTemp;
}
//==============================================================================
void CODEC::EndLine (void)
{
if (f2D)
{
// Reset consumer and producer.
t4C.lpbRef = lpbRef;
t4C.lpbBegRef = lpbRef;
t4P.lpbRef = lpbRef;
t4P.lpbBegRef = lpbRef;
// Increment K Factor
t4P.iKFactor++;
if (t4P.iKFactor == nKFactor)
t4P.iKFactor = 0;
}
// Clear change vector buffer (debug only).
DEBUGSTMT (_fmemset (lpbChange, 0xCD, sizeof(WORD) * xExt + CHANGE_SLACK));
// Reset consumer.
t4C.wColumn = 0;
t4C.wColor = 0;
t4C.lpbOut = lpbChange;
t4C.wOffset = LOWORD(lpbChange);
t4C.wToggle = 0;
// Reset producer.
t4P.wColumn = 0;
t4P.wColor = 0;
t4P.lpbIn = lpbChange;
}
//==============================================================================
void CODEC::StartPage (void)
{
if (wBad) ResetBad();
cSpurious = 0;
EndLine ();
// Reset consumer.
t4C.wWord = 0;
t4C.wBit = 0;
t4C.wRet = RET_BEG_OF_PAGE;
// Reset producer.
t4P.wWord = 0;
t4P.wBit = 0;
t4P.wRet = RET_BEG_OF_PAGE;
// Blank buffered output line.
_fmemset (lpbLine, 0, cbLine);
if (f2D)
{
// Blank reference vector.
LPWORD lpwRef = (LPWORD) lpbRef;
*lpwRef++ = (WORD)xExt;
*lpwRef++ = (WORD)xExt;
*lpwRef++ = (WORD)xExt;
*lpwRef++ = (WORD)xExt;
*lpwRef++ = 0xFFFF;
*lpwRef++ = 0xFFFF;
t4C.wMode = 0;
t4P.wMode = 0;
t4P.iKFactor = 0;
}
}
//==============================================================================
void CODEC::EndPage (LPBUFFER lpbufOut)
{
// Flush last byte and end-of-block code.
switch (nTypeOut)
{
case LRAW_DATA:
case NULL_DATA:
return;
case MH_DATA:
case MR_DATA:
#ifndef WIN32
return;
#endif
case MMR_DATA:
{
LPBYTE lpbBeg = lpbufOut->EndData();
t4P.lpbOut = lpbBeg;
t4P.cbOut = (WORD)(lpbufOut->EndBuf() - t4P.lpbOut);
t4P.wRet = RET_END_OF_PAGE;
Producer (&t4P);
lpbufOut->wLengthData += (WORD)(t4P.lpbOut - lpbBeg);
return;
}
default: DEBUGCHK (FALSE);
}
}
/*==============================================================================
This method initializes a CODEC context.
==============================================================================*/
void CODEC::Init (LPFC_PARAM lpParam, BOOL f2DInit)
{
DEBUGMSG (1, ("FAXCODEC: nTypeIn = %lx\n\r", lpParam->nTypeIn));
DEBUGMSG (1, ("FAXCODEC: nTypeOut = %lx\n\r", lpParam->nTypeOut));
DEBUGMSG (1, ("FAXCODEC: cbLine = %d\n\r", lpParam->cbLine));
DEBUGMSG (1, ("FAXCODEC: nKFactor = %d\n\r", lpParam->nKFactor));
// Initialize constants.
_fmemcpy (this, lpParam, sizeof(FC_PARAM));
xExt = 8 * cbLine;
f2D = f2DInit;
switch (nTypeIn) // Determine the consumer.
{
case LRAW_DATA: Consumer = RawToChange; break;
case MH_DATA: Consumer = MHToChange; break;
case MR_DATA: Consumer = MRToChange; break;
case MMR_DATA: Consumer = MMRToChange; break;
default: DEBUGCHK (FALSE);
}
switch (nTypeOut) // Determine the producer.
{
case NULL_DATA: Producer = NULL; break;
case LRAW_DATA: Producer = ChangeToRaw; break;
case MH_DATA: Producer = ChangeToMH; break;
case MR_DATA: Producer = ChangeToMR; break;
case MMR_DATA: Producer = ChangeToMMR; break;
default: DEBUGCHK (FALSE);
}
// Initialize memory buffers.
lpbLine = (LPBYTE) (this + 1);
lpbChange = lpbLine + cbLine + RAWBUF_SLACK;
lpbRef = lpbChange;
if (f2D)
lpbRef += xExt * sizeof(USHORT) + CHANGE_SLACK;
// Initialize consumer state.
t4C.cbSlack = CHANGE_SLACK;
t4C.cbLine = (WORD)cbLine;
t4C.nType = nTypeIn;
// Initialize producer state.
t4P.cbSlack = OUTBUF_SLACK;
t4P.cbLine = (WORD)cbLine;
t4P.nType = nTypeOut;
// Initialize error counts.
_fmemset (&fcCount, 0, sizeof(fcCount));
wBad = 0;
// Reset for beginning of page.
StartPage();
}
/*==============================================================================
This method executes a CODEC conversion.
==============================================================================*/
FC_STATUS CODEC::Convert (LPBUFFER lpbufIn, LPBUFFER lpbufOut)
{
FC_STATUS ret;
// A null input buffer is flag for end of page.
if (!lpbufIn || lpbufIn->dwMetaData == END_OF_PAGE)
{
DEBUGMSG (1,("FAXCODEC: got EOP\r\n"));
EndPage (lpbufOut);
StartPage ();
return FC_INPUT_EMPTY;
}
// Ignore input after RTC but before end of page.
if (cSpurious == RTC_EOL)
{
DEBUGMSG (1,("FAXCODEC: ignoring input after RTC or EOFB\r\n"));
return FC_INPUT_EMPTY;
}
#ifndef WIN32
if (t4C.wRet == RET_BEG_OF_PAGE)
{
if (nTypeOut == MH_DATA || nTypeOut == MR_DATA)
{
// Start page with EOL.
if (lpbufOut->EndBuf() - lpbufOut->EndData() < OUTBUF_SLACK)
return FC_OUTPUT_FULL;
*((LPWORD) lpbufOut->EndData()) = 0x8000;
lpbufOut->wLengthData += 2;
}
}
#endif // WIN32
// Initialize input buffer of consumer.
t4C.lpbIn = lpbufIn->lpbBegData;
t4C.cbIn = lpbufIn->wLengthData;
// Dispatch to 2 or 3 phase conversion.
if (nTypeOut == LRAW_DATA || nTypeOut == NULL_DATA)
ret = ConvertToRaw (lpbufIn, lpbufOut);
else
ret = ConvertToT4 (lpbufIn, lpbufOut);
// Adjust input buffer header.
lpbufIn->lpbBegData = t4C.lpbIn;
lpbufIn->wLengthData = t4C.cbIn;
return ret;
}
//==============================================================================
FC_STATUS CODEC::ConvertToRaw (LPBUFFER lpbufIn, LPBUFFER lpbufOut)
{
LPBYTE lpbOut = lpbufOut->EndData();
UINT cbOut = (UINT)(lpbufOut->EndBuf() - lpbOut);
if (t4P.wRet == RET_OUTPUT_FULL)
goto copy_phase;
while (1)
{
Consumer (&t4C); // generate change vector
switch (t4C.wRet)
{
case RET_INPUT_EMPTY1:
case RET_INPUT_EMPTY2:
return FC_INPUT_EMPTY;
case RET_SPURIOUS_EOL:
if (++cSpurious == RTC_EOL)
return FC_INPUT_EMPTY;
EndLine();
continue;
case RET_DECODE_ERR:
break; // handle it later
case RET_END_OF_PAGE:
if (wBad) ResetBad();
cSpurious = RTC_EOL;
return FC_INPUT_EMPTY;
case RET_END_OF_LINE:
t4P.cbIn = (USHORT)ValidChangeVector ((LPSHORT) lpbChange, (SHORT)xExt);
if (!t4P.cbIn)
t4C.wRet = RET_DECODE_ERR; // consumer lied!
else
{
// Adjust counters.
fcCount.cTotalGood++;
if (wBad) ResetBad();
cSpurious = 0;
}
break;
default: DEBUGCHK (FALSE);
}
// Handle decode errors.
if (t4C.wRet == RET_DECODE_ERR)
{
if (nTypeIn == MMR_DATA)
return FC_DECODE_ERR;
wBad++;
fcCount.cTotalBad++;
#ifdef DEBUG
_fmemset (lpbLine, 0xFF, cbLine); // emit black line
#endif
if (f2D)
{
// Replicate change vector.
t4P.cbIn = (WORD)ValidChangeVector ((LPSHORT) lpbRef, (WORD)xExt);
DEBUGCHK (t4P.cbIn);
_fmemcpy (lpbChange, lpbRef, t4P.cbIn + CHANGE_SLACK);
}
if (nTypeOut == NULL_DATA)
goto EOL;
if (!f2D)
goto copy_phase;
}
// Optimize validation.
if (nTypeOut == NULL_DATA)
goto EOL;
// Run the producer.
t4P.lpbOut = lpbLine;
t4P.cbOut = (WORD)cbLine;
ChangeToRaw (&t4P);
copy_phase:
if (cbOut < cbLine)
{
t4P.wRet = RET_OUTPUT_FULL;
return FC_OUTPUT_FULL;
}
// Append buffered line to output.
t4P.wRet = RET_END_OF_LINE;
_fmemcpy (lpbOut, lpbLine, cbLine);
lpbufOut->wLengthData += (WORD)cbLine;
lpbOut += cbLine;
cbOut -= cbLine;
EOL:
SwapChange ();
EndLine ();
} // while (1)
// C8 thinks we can get here, but I know better.
DEBUGCHK (FALSE);
return FC_DECODE_ERR;
}
//==============================================================================
FC_STATUS CODEC::ConvertToT4 (LPBUFFER lpbufIn, LPBUFFER lpbufOut)
{
LPBYTE lpbBegOut;
t4P.lpbOut = lpbufOut->EndData();
t4P.cbOut = (WORD)(lpbufOut->EndBuf() - t4P.lpbOut);
if (t4P.wRet == RET_OUTPUT_FULL)
goto producer_phase;
while (1) // Loop until input is empty or output is full.
{
Consumer (&t4C);
switch (t4C.wRet)
{
case RET_INPUT_EMPTY1:
case RET_INPUT_EMPTY2:
return FC_INPUT_EMPTY;
case RET_SPURIOUS_EOL:
if (++cSpurious == RTC_EOL)
return FC_INPUT_EMPTY;
EndLine();
continue;
case RET_DECODE_ERR:
break; // handle it later
case RET_END_OF_PAGE:
if (wBad) ResetBad();
cSpurious = RTC_EOL;
return FC_INPUT_EMPTY;
case RET_END_OF_LINE:
t4P.cbIn = (WORD)ValidChangeVector ((LPSHORT) lpbChange, (WORD)xExt);
if (!t4P.cbIn)
t4C.wRet = RET_DECODE_ERR; // consumer lied!
else
{
// Adjust counters.
fcCount.cTotalGood++;
if (wBad) ResetBad();
cSpurious = 0;
}
break;
default: DEBUGCHK (FALSE);
}
if (t4C.wRet == RET_DECODE_ERR)
{
DEBUGCHK (f2D && nTypeIn != LRAW_DATA);
if (nTypeIn == MMR_DATA)
return FC_DECODE_ERR;
wBad++;
fcCount.cTotalBad++;
#ifdef DEBUG
{
// Substitute all black line.
LPWORD lpwChange = (LPWORD) lpbChange;
*lpwChange++ = 0;
*lpwChange++ = xExt;
*lpwChange++ = xExt;
*lpwChange++ = xExt;
*lpwChange++ = xExt;
*lpwChange++ = 0xFFFF;
*lpwChange++ = 0xFFFF;
t4P.cbIn = 4;
}
#else
// Replicate previous line
t4P.cbIn = (WORD)ValidChangeVector ((LPSHORT) lpbRef, (WORD)xExt);
DEBUGCHK (t4P.cbIn);
_fmemcpy (lpbChange, lpbRef, t4P.cbIn + CHANGE_SLACK);
#endif
}
producer_phase:
lpbBegOut = t4P.lpbOut;
Producer (&t4P);
lpbufOut->wLengthData += (WORD)(t4P.lpbOut - lpbBegOut);
// Check if output is full.
if (t4P.wRet == RET_OUTPUT_FULL)
return FC_OUTPUT_FULL;
// EOL:
SwapChange();
EndLine ();
} // while (1)
// C8 thinks we can get here, but I know better.
DEBUGCHK (FALSE);
return FC_DECODE_ERR;
}