/*++ Copyright (c) 1990-1994 Microsoft Corporation All rights reserved Module Name: MsNull.c Abstract: Implements lanman's msnull type parsing for FFs. Author: Environment: User Mode -Win32 Revision History: --*/ #include #include "winprint.h" #include "msnull.h" #define sgn(x) (((x)>0) ? 1:-1) struct EscapeSequence EscapeStrings[] = { { "-",prdg_ActConstIgnore, 1}, { "0",prdg_ActNull,0}, { "1",prdg_ActNull,0}, { "2",prdg_ActNull,0}, { "3",prdg_ActConstIgnore, 1}, { "4",prdg_ActNull,0}, { "5",prdg_ActConstIgnore, 1}, { "6",prdg_ActNull,0}, { "7",prdg_ActNull,0}, { ":",prdg_ActNull,0}, { "=",prdg_ActNull,0}, { "A",prdg_ActConstIgnore, 1}, { "B",prdg_ActDelimited, '\0'}, { "C\0",prdg_ActConstIgnore, 1}, { "D",prdg_ActDelimited, '\0'}, { "E",prdg_ActReset,0}, { "F",prdg_ActNull,0}, { "G",prdg_ActNull,0}, { "H",prdg_ActNull,0}, { "I",prdg_ActConstIgnore, 1}, { "J",prdg_ActConstIgnore, 1}, { "K",prdg_ActCountIgnore, 0}, { "L",prdg_ActCountIgnore, 0}, { "N",prdg_ActConstIgnore, 1}, { "O",prdg_ActNull,0}, { "P",prdg_ActConstIgnore, 1}, { "Q",prdg_ActConstIgnore, 1}, { "R",prdg_ActNull,0}, { "S",prdg_ActConstIgnore, 1}, { "T",prdg_ActNull,0}, { "U",prdg_ActConstIgnore, 1}, { "W",prdg_ActConstIgnore, 1}, { "X",prdg_ActConstIgnore, 2}, { "Y",prdg_ActCountIgnore, 0}, { "Z",prdg_ActCountIgnore, 0}, { "[@",prdg_ActCountIgnore, 0}, { "[C",prdg_ActCountIgnore, 0}, { "[F",prdg_ActCountIgnore, 0}, { "[I",prdg_ActCountIgnore, 0}, { "[S",prdg_ActCountIgnore, 0}, { "[T",prdg_ActCountIgnore, 0}, { "[\\",prdg_ActCountIgnore, 0}, { "[g",prdg_ActCountIgnore, 0}, { "\\",prdg_ActCountIgnore, 0}, { "]",prdg_ActNull,0}, { "^",prdg_ActNull,0}, { "_",prdg_ActConstIgnore, 1}, { "d",prdg_ActConstIgnore, 2}, { "e",prdg_ActConstIgnore, 2}, { "j",prdg_ActNull,0}, { "n",prdg_ActNull,0}, { "\x6f", prdg_ActFF, 0} }; VOID CheckFormFeedStream( lpDCI pDCIData, unsigned char inch) /**********************************************************************/ /* */ /* FUNCTION: prdg_ParseRawData */ /* */ /* PARAMETERS: */ /* */ /* lpDCI pDCIData; Pointer to DC instance data */ /* unsigned char inch; The next byte in data stream */ /* */ /* DESCRIPTION: */ /* */ /* This function parses the stream of raw data which is being */ /* passed to the printer so that the driver can handle form feeds */ /* correctly. The function must follow all the escape sequences */ /* which occur in the sequence of raw data. */ /* */ /* CHANGES: */ /* */ /* This function is table driven (from the table in in the ddata */ /* module) so it should hopefully only require this to be changed */ /* to reflect the escape sequences for a different printer. If */ /* however there are escape sequneces which don't fall into the */ /* categories this parser can handle then extra code will have */ /* to be written to handle them. The parser can handle escape */ /* sequences with any number of unique identifying characters */ /* possibly followed by: a count then the number of charcters given */ /* in the count; a fixed number of characters; a stream of */ /* characters followed by a delimeter. */ /* */ /**********************************************************************/ { /******************************************************************/ /* Local Variables */ /******************************************************************/ INT Direction; /* Variables used in the */ UINT HiIndex; /* binary chop routine for */ UINT LoIndex; /* searching for a matching */ UINT Index; /* escape sequence */ UINT PrevIndex; char * optr; /* Pointers to access the */ char * nptr; /* escape sequence strings */ struct EscapeSequence *NewSequence; /* Pointer to an escape */ /* sequence */ /******************************************************************/ /* Process the input character through the parsing function. */ /* Switch depending on which state we are currently in. One of */ /* prdg_Text, prdg_ESC_match, prdg_ESC_n_ignore, prdg_ESC_d_ignore*/ /* prdg_ESC_read_lo_count, prdg_ESC_read_hi_count. */ /******************************************************************/ switch (pDCIData->ParserState) { case prdg_Text: /**********************************************************/ /* Text state. Usual state, handled in line by a macro. */ /* The code is included here for completeness only. */ /* The FFaction (Form Feed action) state is maintained - */ /* if the character is text (ie >= 0x20) then set it to */ /* prdg_FFstate, if the character is a FF then set it to */ /* prdg_FFx0c. If the input character is an escape then */ /* start up the sequence matching mode. */ /**********************************************************/ if (inch >= 0x20) pDCIData->FFstate = prdg_FFtext; else if (inch == 0x0c) pDCIData->FFstate = prdg_FFx0c; else if (inch == 0x1b) { /******************************************************/ /* The character is an escape so set ParserState and */ /* indicate we have not matched a sequence yet by */ /* setting ParserSequence to NULL. */ /******************************************************/ pDCIData->ParserState = prdg_ESC_match; pDCIData->ParserSequence = NULL; } break; case prdg_ESC_match: /**********************************************************/ /* Matching an escape sequence so try to match a new */ /* character. */ /**********************************************************/ if (!pDCIData->ParserSequence) { /******************************************************/ /* ParserSequence is NULL indicating that this is the */ /* first character of an escape sequence so use a */ /* binary chop to get to the correct area of the */ /* table of escape sequences (based on the first */ /* character of the escape sequence which is the */ /* cuurent input character). */ /******************************************************/ HiIndex = MaxEscapeStrings; LoIndex = 0; Index = (LoIndex + HiIndex)/2; PrevIndex = MaxEscapeStrings; /******************************************************/ /* while inch does not match the first character of */ /* the sequence indicated by Index move up or down */ /* the table depending on whether inch is < or > the */ /* first character of the escape sequence at Index. */ /******************************************************/ while (Direction = (inch - *EscapeStrings[Index].ESCString)) { if (Direction > 0) { LoIndex = Index; } else { HiIndex = Index; }; PrevIndex = Index; if (PrevIndex == (Index = (LoIndex + HiIndex)/2)) { /**********************************************/ /* There is no escape sequence with a first */ /* character matching the current input */ /* character so resume text mode. */ /**********************************************/ pDCIData->ParserState = prdg_Text; return; } } /*.. while (Direction = ...no match yet...............*/ /******************************************************/ /* Set up the ParserSequence and ParserString for the */ /* first match found. */ /******************************************************/ pDCIData->ParserSequence = &EscapeStrings[Index]; pDCIData->ParserString = EscapeStrings[Index].ESCString; }; /*.. if (!pDCIData->ParserSequence) .......................*/ /**********************************************************/ /* Loop forever trying to match escape sequences. */ /* First, try the new character against the current */ /* escape sequence and if it matches then check if it is */ /* the end of the sequence and if it is switch to the */ /* appropriate matching mode. If the new character does */ /* not match try the next escape sequence (in either */ /* ascending or descending order depending on whether the */ /* current character was < or > the character we were */ /* trying to match it to). If the new sequence we are */ /* trying to match against does not exist (ie we are at */ /* one end of the table) or it does not match upto (but */ /* not including) the position we are currently at then */ /* the escape sequence in the raw data we are trying to */ /* match is invalid so revert to prdg_Text mode. If it */ /* does match upto (but not including) the position we */ /* are currently trying to match then go back to try and */ /* match. */ /**********************************************************/ for (Direction = sgn(inch - *pDCIData->ParserString);;) { /******************************************************/ /* Partway along a sequence, try the new character and*/ /* if it matches then check for end of string. */ /******************************************************/ if (!(inch - *pDCIData->ParserString)) { if (*++pDCIData->ParserString != '\0') /**********************************************/ /* Escape sequence not finished yet so return */ /* and wait for the next character. Note that*/ /* this is where the pointer to the position */ /* in the escape sequence we are checking is */ /* updated. */ /**********************************************/ return; else /**********************************************/ /* The escape sequence has matched till the */ /* end so break to the next section which will*/ /* take the appropriate action. */ /**********************************************/ break; } /*.. if (!(inch - *pDCIData->ParserString)) ...match...*/ else { /**************************************************/ /* The current sequence does not match so we must */ /* try another sequence. Direction determines */ /* which way in the table we should go. */ /**************************************************/ NewSequence = pDCIData->ParserSequence + Direction; if (NewSequence < EscapeStrings || NewSequence> &EscapeStrings[MaxEscapeStrings-1]) { /**********************************************/ /* The new sequence is beyond one end of the */ /* table so revert to prdg_Text mode because */ /* we will not be able to find a match. */ /**********************************************/ pDCIData->ParserState = prdg_Text; return; } /**************************************************/ /* Check that all the characters in the new */ /* escape sequence upto (but not including) the */ /* current one match the old escape sequence */ /* (because those characters from the old escape */ /* sequence have already been matched to the */ /* raw data). */ /**************************************************/ for (optr=pDCIData->ParserSequence->ESCString, nptr=NewSequence->ESCString; optrParserString; ++optr,++nptr) if (*nptr != *optr) { /*****************************************/ /* If the new sequence does not match the*/ /* old then a match is not possible so */ /* return. */ /*****************************************/ pDCIData->ParserState = prdg_Text; return; } /**************************************************/ /* The new sequence is correct upto the character */ /* before the current character so loop back and */ /* check the current character. */ /**************************************************/ pDCIData->ParserSequence = NewSequence; pDCIData->ParserString = nptr; } /*.. else ! (!(inch - *pDCIData->ParserString.no match.*/ } /*.. for ( ... ;;) ....for ever...........................*/ /**********************************************************/ /* The escape sequence has been matched from our table of */ /* escape sequences so take the appropriate action for */ /* the particular sequence. */ /**********************************************************/ switch (pDCIData->ParserSequence->ESCAction) { case prdg_ActNull: /**************************************************/ /* No further action so revert to prdg_Text mode */ /**************************************************/ pDCIData->ParserState = prdg_Text; break; case prdg_ActDelimited: /**************************************************/ /* Ignore subsequent characters upto a specified */ /* delimeter. */ /**************************************************/ pDCIData->ParserState = prdg_ESC_d_ignore; pDCIData->ParserDelimiter = (char)pDCIData->ParserSequence->ESCValue; break; case prdg_ActConstIgnore: /**************************************************/ /* Ignore a specified number of characters. */ /**************************************************/ pDCIData->ParserState = prdg_ESC_n_ignore; pDCIData->ParserCount = pDCIData->ParserSequence->ESCValue; break; case prdg_ActCountIgnore: /**************************************************/ /* A two byte count follows so prepare to read it */ /* in. */ /**************************************************/ pDCIData->ParserState = prdg_ESC_read_lo_count; break; case prdg_ActFF: /**************************************************/ /* A special action for recognising the 0x1b6f */ /* "No Formfeed" sequence */ /**************************************************/ pDCIData->ParserState = prdg_Text; pDCIData->FFstate = prdg_FFx1b6f; break; case prdg_ActReset: /**************************************************/ /* On Esc-E (reset) don't eject a page if this is */ /* the last sequence in the stream. */ /**************************************************/ pDCIData->ParserState = prdg_Text; pDCIData->FFstate = prdg_FFx1b45; break; } /*.. switch (pDCIData->ParserSequence->ESCAction) .........*/ break; case prdg_ESC_n_ignore: /**********************************************************/ /* Ignoring n characters. Decrement the count, move back */ /* to text state if all ignored. */ /**********************************************************/ if (!(--pDCIData->ParserCount)) pDCIData->ParserState = prdg_Text; break; case prdg_ESC_d_ignore: /**********************************************************/ /* Ignoring up to a delimiter. If this is it, then stop */ /* ignoring. */ /**********************************************************/ if (inch == pDCIData->ParserDelimiter) pDCIData->ParserState = prdg_Text; break; case prdg_ESC_read_lo_count: /**********************************************************/ /* Reading first byte of count. Save it, advance state. */ /**********************************************************/ pDCIData->ParserCount = (UINT)inch; pDCIData->ParserState = prdg_ESC_read_hi_count; break; case prdg_ESC_read_hi_count: /**********************************************************/ /* Reading second byte of count. Save it, move to ignore */ /* a specified number of characters if there are any. */ /**********************************************************/ pDCIData->ParserCount += 256*(UINT)inch; if (pDCIData->ParserCount) pDCIData->ParserState = prdg_ESC_n_ignore; else pDCIData->ParserState = prdg_Text; break; }; /*.. switch (pDCIData->ParserState) ...............................*/ return; } BOOL CheckFormFeed( lpDCI pDCIData) { if (pDCIData->FFstate != prdg_FFx1b6f && pDCIData->FFstate != prdg_FFx1b45) { if (pDCIData->uType == PRINTPROCESSOR_TYPE_RAW_FF || (pDCIData->uType == PRINTPROCESSOR_TYPE_RAW_FF_AUTO && pDCIData->FFstate == prdg_FFtext)) { return TRUE; } } return FALSE; }