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.
1569 lines
32 KiB
1569 lines
32 KiB
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// MacPrint - Windows NT Print Server for Macintosh Clients
|
|
// Copyright (c) Microsoft Corp., 1991, 1992, 1993
|
|
//
|
|
// psp.c - Macintosh Print Service Postscript Parsing Routines
|
|
//
|
|
// Author: Frank D. Byrum
|
|
// adapted from MacPrint from LAN Manager Services for Macintosh
|
|
//
|
|
// DESCRIPTION:
|
|
// This module provides the routines to parse the Adobe DSC 2.0
|
|
// comments in a PostScript stream.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <windows.h>
|
|
#include <macpsmsg.h>
|
|
#include <macps.h>
|
|
#include <pskey.h>
|
|
#include <debug.h>
|
|
|
|
// function prototypes
|
|
DWORD HandleTitle(PJR pjr);
|
|
DWORD HandleBeginExitServer(PJR pjr);
|
|
DWORD HandleCreationDate(PJR pjr);
|
|
DWORD HandleCreator(PJR pjr);
|
|
DWORD HandleEndExitServer(PJR pjr);
|
|
DWORD HandleEOF(PJR pjr);
|
|
DWORD HandleFor(PJR pjr);
|
|
DWORD HandleLogin(PJR pjr);
|
|
DWORD HandleBeginProcSet(PJR pjr);
|
|
DWORD HandleEndProcSet(PJR pjr);
|
|
DWORD HandleIncludeProcSet(PJR pjr);
|
|
DWORD HandleComment(PJR, PBYTE);
|
|
DWORD HandleBeginBinary(PJR pjr);
|
|
DWORD HandleEndBinary(PJR pjr);
|
|
DWORD HandlePages(PJR pjr);
|
|
void HandleJobComment (PJR, PBYTE);
|
|
PFR ReAllocateFontList (PFR pfrOld, DWORD cOldFonts, DWORD cNewFonts);
|
|
|
|
#if DBG_SPOOL_LOCALLY
|
|
HANDLE DbgSpoolFile = INVALID_HANDLE_VALUE;
|
|
#endif
|
|
|
|
char * deffonts[DEFAULTFONTS] =
|
|
{
|
|
FONT00, FONT01, FONT02, FONT03, FONT04, FONT05, FONT06, FONT07,
|
|
FONT08, FONT09, FONT10, FONT11, FONT12, FONT13, FONT14, FONT15,
|
|
FONT16, FONT17, FONT18, FONT19, FONT20, FONT21, FONT22, FONT23,
|
|
FONT24, FONT25, FONT26, FONT27, FONT28, FONT29, FONT30, FONT31,
|
|
FONT32, FONT33, FONT34
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SetDefaultPPDInfo() - Initialize to LaserWriter Plus configuration
|
|
//
|
|
// DESCRIPTION:
|
|
// This routine is used to set the default parameters of our
|
|
// printer to LaserWriter Plus characteristics. This is used
|
|
// in the event there is no PPD file associated with the given
|
|
// NT Printer Object (as in the case of non Postscript printers)
|
|
//
|
|
// returns true if queue structure initialized OK.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOLEAN
|
|
SetDefaultPPDInfo(
|
|
PQR pqr
|
|
)
|
|
{
|
|
DWORD i;
|
|
|
|
//
|
|
// initialize Postscript keywords
|
|
//
|
|
strcpy(pqr->LanguageVersion, ENGLISH);
|
|
strcpy(pqr->Product, DEFAULTPRODUCTRESPONSE);
|
|
strcpy(pqr->Version, DEFAULTPSVERSION);
|
|
strcpy(pqr->Revision, DEFAULTPSREVISION);
|
|
strcpy(pqr->DeviceNickName, UNKNOWNPRINTER);
|
|
strcpy(pqr->pszColorDevice, COLORDEVICEDEFAULT);
|
|
strcpy(pqr->pszResolution, RESOLUTIONDEFAULT);
|
|
strcpy(pqr->pszLanguageLevel, DEFAULTLANGUAGELEVEL);
|
|
pqr->FreeVM = VMDEFAULT;
|
|
pqr->SupportsBinary = FALSE;
|
|
|
|
pqr->fonts = NULL;
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SetDefaultFonts() - Initialize to LaserWriter Plus configuration
|
|
//
|
|
// DESCRIPTION:
|
|
// This routine is used to set the default parameters of our
|
|
// printer to LaserWriter Plus characteristics. This is used
|
|
// in the event there is no PPD file associated with the given
|
|
// NT Printer Object (as in the case of non Postscript printers)
|
|
//
|
|
// returns true if queue structure initialized OK.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOLEAN
|
|
SetDefaultFonts(
|
|
PQR pqr
|
|
)
|
|
{
|
|
DWORD i;
|
|
|
|
|
|
if (pqr->fonts != NULL)
|
|
{
|
|
DBGPRINT(("ERROR: pqr->fonts is nonnull!\n"));
|
|
}
|
|
|
|
pqr->fonts = (PFR)LocalAlloc(LPTR, DEFAULTFONTS * sizeof (FONT_RECORD));
|
|
if (pqr->fonts == NULL)
|
|
{
|
|
DBGPRINT(("ERROR: unable to allocate font data\n"));
|
|
ReportEvent(
|
|
hEventLog,
|
|
EVENTLOG_ERROR_TYPE,
|
|
EVENT_CATEGORY_INTERNAL,
|
|
EVENT_SERVICE_OUT_OF_MEMORY,
|
|
NULL, 0, 0, NULL, NULL);
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// copy font names
|
|
//
|
|
|
|
for (i = 0; i < DEFAULTFONTS; i++)
|
|
{
|
|
strcpy(pqr->fonts[i].name, deffonts[i]);
|
|
}
|
|
pqr->MaxFontIndex = DEFAULTFONTS-1;
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetPPDInfo() - Initialize to LaserWriter Plus configuration
|
|
//
|
|
// DESCRIPTION:
|
|
// This routine is used to set the parameters of our
|
|
// printer to the characteristics specified in the PPD
|
|
// file for the printer.
|
|
//
|
|
// returns true if queue structure initialized OK.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOLEAN
|
|
GetPPDInfo(
|
|
PQR pqr
|
|
)
|
|
{
|
|
FILE * ppdfile = NULL;
|
|
char * result = NULL;
|
|
char * token = NULL;
|
|
char line[PSLEN];
|
|
PFR fontPtr=NULL;
|
|
USHORT MaxFonts = 100;
|
|
USHORT fontindex = 0;
|
|
LPDRIVER_INFO_2 pdiThis = NULL;
|
|
DWORD cbpdiThis = sizeof(DRIVER_INFO_2) + 256;
|
|
LPSTR pszPPDFile = NULL;
|
|
BOOLEAN ReturnStatus = TRUE;
|
|
HANDLE hPrinter = INVALID_HANDLE_VALUE;
|
|
int toklen;
|
|
|
|
do
|
|
{
|
|
// get the path of the ppdfile
|
|
if (!OpenPrinter(pqr->pPrinterName, &hPrinter, NULL))
|
|
{
|
|
hPrinter = INVALID_HANDLE_VALUE;
|
|
DBGPRINT(("ERROR: unable to get printer handle, error=%d\n", GetLastError()));
|
|
ReturnStatus = FALSE;
|
|
break;
|
|
}
|
|
|
|
pdiThis = (LPDRIVER_INFO_2) LocalAlloc(LPTR, cbpdiThis);
|
|
if (pdiThis == NULL)
|
|
{
|
|
DBGPRINT(("ERROR: unable to allocate new driverinfo buffer\n"));
|
|
ReturnStatus = FALSE;
|
|
break;
|
|
}
|
|
if (!GetPrinterDriver(hPrinter,
|
|
NULL,
|
|
2,
|
|
(LPBYTE) pdiThis,
|
|
cbpdiThis,
|
|
&cbpdiThis))
|
|
{
|
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
DBGPRINT(("ERROR: unable to get printer driver info\n"));
|
|
ReturnStatus = FALSE;
|
|
break;
|
|
}
|
|
|
|
LocalFree(pdiThis);
|
|
pdiThis = (LPDRIVER_INFO_2) LocalAlloc(LPTR, cbpdiThis);
|
|
if (pdiThis == NULL)
|
|
{
|
|
DBGPRINT(("ERROR: unable to allocte new driverinfo buffer\n"));
|
|
ReturnStatus = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (!GetPrinterDriver(hPrinter,
|
|
NULL,
|
|
2,
|
|
(LPBYTE) pdiThis,
|
|
cbpdiThis,
|
|
&cbpdiThis))
|
|
{
|
|
DBGPRINT(("ERROR: unable to get printer driver info\n"));
|
|
ReturnStatus = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
#ifdef DBCS
|
|
pszPPDFile = (LPSTR)LocalAlloc(LPTR, (wcslen(pdiThis->pDataFile)+1) * sizeof(WCHAR));
|
|
#else
|
|
pszPPDFile = (LPSTR)LocalAlloc(LPTR, wcslen(pdiThis->pDataFile)+1);
|
|
#endif
|
|
DBGPRINT(("pDataFile name length = %d\n", wcslen(pdiThis->pDataFile)));
|
|
if (pszPPDFile == NULL)
|
|
{
|
|
DBGPRINT(("out of memory for pszPPDFile\n"));
|
|
ReturnStatus = FALSE;
|
|
break;
|
|
}
|
|
CharToOem(pdiThis->pDataFile, pszPPDFile);
|
|
DBGPRINT(("pDataFile = %ws, pszPPDFile = %s\n", pdiThis->pDataFile, pszPPDFile));
|
|
|
|
if ((ppdfile = fopen(pszPPDFile, "rt")) == NULL)
|
|
{
|
|
DBGPRINT(("File open error %s", pszPPDFile));
|
|
ReturnStatus = FALSE;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Allocate a buffer for fonts. We don't know yet what size we need.
|
|
* We make a guess and increase the size as we go. The incremental
|
|
* size is 10 fonts. We start off with 100. We shrink the segment size
|
|
* to the final size.
|
|
*/
|
|
fontPtr = (PFR) LocalAlloc (LPTR, sizeof(FONT_RECORD)*MaxFonts);
|
|
if (fontPtr == NULL)
|
|
{
|
|
DBGPRINT(("ERROR: cannot allocate font list buffer, error=%d\n", GetLastError()));
|
|
ReturnStatus = FALSE;
|
|
break;
|
|
}
|
|
|
|
pqr->SupportsBinary = FALSE; // Default
|
|
while (result = fgets(line, PSLEN, ppdfile))
|
|
{
|
|
if (line[0] != ASTERISK || (token= strtok(line, " \011")) == NULL)
|
|
continue;
|
|
|
|
// PPD Font Entry?
|
|
if (!_stricmp(line, ppdFONT))
|
|
{
|
|
/* This should be the fontname */
|
|
if ((token= strtok(NULL, " \011:")) != NULL)
|
|
{
|
|
if (strlen(token) <= FONTNAMELEN)
|
|
{
|
|
strcpy(fontPtr[fontindex].name, token);
|
|
DBGPRINT(("Font: %s\n", token));
|
|
fontindex++;
|
|
if (fontindex >= MaxFonts)
|
|
{
|
|
fontPtr = ReAllocateFontList (fontPtr, MaxFonts, MaxFonts + 10);
|
|
if (fontPtr == NULL)
|
|
{
|
|
DBGPRINT(("ERROR: unable to grow font buffer, error=%d\n", GetLastError()));
|
|
ReturnStatus = FALSE;
|
|
break;
|
|
}
|
|
MaxFonts += 10;
|
|
}
|
|
}
|
|
else DBGPRINT(("Fontname > PPDLEN ???\n"));
|
|
}
|
|
}
|
|
else if (!_stricmp(token, ppdPSVERSION))
|
|
{
|
|
// PPD Postscript Version Entry?
|
|
/* Get the PostScript version */
|
|
token= strtok(NULL, "\011()\""); /* This should be the version */
|
|
if (token != NULL)
|
|
{
|
|
toklen = strlen(token);
|
|
/* Get the PostScript revision */
|
|
if ((toklen <= PPDLEN) && (toklen > 0))
|
|
{
|
|
strcpy(pqr->Version, token);
|
|
DBGPRINT(("Version: %s\n", pqr->Version));
|
|
}
|
|
else
|
|
{
|
|
strcpy(pqr->Version, "1.0"); // Default
|
|
DBGPRINT(("Version > PPDLEN ???\n"));
|
|
}
|
|
|
|
token= strtok(NULL, "()\""); /* This should be the revision */
|
|
if (token != NULL)
|
|
{
|
|
while ((*token != '\0') && (*token == ' '))
|
|
token ++;
|
|
toklen = strlen(token);
|
|
if ((toklen <= PPDLEN) && (toklen > 0))
|
|
{
|
|
strcpy(pqr->Revision, token);
|
|
DBGPRINT(("Revision: %s\n", pqr->Revision));
|
|
}
|
|
else
|
|
{
|
|
strcpy(pqr->Revision, "1.0"); // Some bogus token
|
|
DBGPRINT(("Revision > PPDLEN ???\n"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
strcpy(pqr->Version, "1.0"); // Defaults
|
|
strcpy(pqr->Revision, "1.0");
|
|
}
|
|
}
|
|
}
|
|
else if (!_stricmp(token, ppdNICKNAME))
|
|
{
|
|
// PPD NickName?
|
|
/* Get the NICKNAME */
|
|
token= strtok(NULL, "\011()\""); /* This should be the nickname */
|
|
if ((token != NULL) && (strlen(token) <= PPDLEN))
|
|
{
|
|
strcpy(pqr->DeviceNickName, token);
|
|
DBGPRINT(("DeviceNickName: %s\n", pqr->DeviceNickName));
|
|
}
|
|
else DBGPRINT(("DeviceNickName > PPDLEN ???\n"));
|
|
}
|
|
else if (!_stricmp(token, ppdLANGUAGEVERSION))
|
|
{
|
|
// PPD Postscript Language Version?
|
|
/* Get the LANGUAGEVERSION */
|
|
token= strtok(NULL, " \011:"); /* This should be the language */
|
|
if ((token != NULL) && (strlen(token) <= PPDLEN))
|
|
{
|
|
strcpy(pqr->LanguageVersion, token);
|
|
DBGPRINT(("LanguageVersion: %s\n", pqr->LanguageVersion));
|
|
}
|
|
else DBGPRINT(("LanguageVersion > PPDLEN ???\n"));
|
|
}
|
|
else if (!_stricmp(token, ppdPRODUCT))
|
|
{
|
|
// PPD Product ?
|
|
/* Get the PRODUCT */
|
|
token = strtok(NULL, "\011()\""); /* This should be the product */
|
|
if ((token != NULL) && (strlen(token) <= PPDLEN))
|
|
{
|
|
strcpy(pqr->Product, token);
|
|
DBGPRINT(("Product: %s\n", pqr->Product));
|
|
}
|
|
else DBGPRINT(("Product > PPDLEN ???\n"));
|
|
}
|
|
else if (!_stricmp(token, ppdFREEVM))
|
|
{
|
|
token= strtok(NULL, "\011()\""); /* This should be the product */
|
|
if (token != NULL)
|
|
sscanf(token, "%ld", &pqr->FreeVM);
|
|
DBGPRINT(("Free VM: %ld\n", pqr->FreeVM));
|
|
}
|
|
else if (!_stricmp(token, ppdCOLORDEVICE))
|
|
{
|
|
// this should be a string indicating color support or not
|
|
// in the form of <True> or <False> (brackets not included)
|
|
token = strtok(NULL, " \011:\x0d\x0a");
|
|
if ((token != NULL) && (strlen(token) < COLORDEVICEBUFFLEN))
|
|
{
|
|
strcpy (pqr->pszColorDevice, token);
|
|
}
|
|
else
|
|
{
|
|
strcpy (pqr->pszColorDevice, COLORDEVICEDEFAULT);
|
|
}
|
|
DBGPRINT(("Color device: %s\n", pqr->pszColorDevice));
|
|
}
|
|
else if (!_stricmp(token, ppdDEFAULTRESOLUTION))
|
|
{
|
|
// this should be a string indicating the default
|
|
// resolution of the printer in the form <xxxxdpi>
|
|
// where xxxx is a number
|
|
token = strtok(NULL, " \011:\x0d\x0a");
|
|
if ((token != NULL) && (strlen(token) < RESOLUTIONBUFFLEN))
|
|
{
|
|
strcpy (pqr->pszResolution, token);
|
|
}
|
|
else
|
|
{
|
|
strcpy (pqr->pszResolution, RESOLUTIONDEFAULT);
|
|
}
|
|
DBGPRINT(("Resolution: %s\n", pqr->pszResolution));
|
|
}
|
|
else if (!_stricmp(token, ppdLANGUAGELEVEL))
|
|
{
|
|
// this should be the PostScript level ("1" or "2")
|
|
// implemented in this printer
|
|
token = strtok(NULL, " \011\"");
|
|
if ((token != NULL) && (PPDLEN >= strlen(token)))
|
|
{
|
|
strcpy (pqr->pszLanguageLevel, token);
|
|
}
|
|
else
|
|
{
|
|
strcpy (pqr->pszLanguageLevel, DEFAULTLANGUAGELEVEL);
|
|
}
|
|
DBGPRINT(("Language Level: %s\n", pqr->pszLanguageLevel));
|
|
}
|
|
else if (!_stricmp(line, ppdPROTOCOL))
|
|
{
|
|
/* Get the string following and see if it is BCP or TBCP ? */
|
|
if ((token= strtok(NULL, " \011:")) != NULL)
|
|
{
|
|
if (strstr(token, PROTOCOL_BCP) != NULL)
|
|
{
|
|
pqr->SupportsBinary = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!ReturnStatus)
|
|
{
|
|
pqr->fonts = NULL;
|
|
pqr->MaxFontIndex = 0;
|
|
}
|
|
else
|
|
{
|
|
pqr->fonts = fontPtr;
|
|
pqr->MaxFontIndex = fontindex-1;
|
|
}
|
|
} while (FALSE);
|
|
|
|
if (pszPPDFile != NULL)
|
|
{
|
|
LocalFree(pszPPDFile);
|
|
}
|
|
|
|
if (ppdfile != NULL)
|
|
{
|
|
fclose(ppdfile);
|
|
}
|
|
|
|
if (hPrinter != INVALID_HANDLE_VALUE)
|
|
{
|
|
ClosePrinter(hPrinter);
|
|
}
|
|
|
|
if (pdiThis != NULL)
|
|
{
|
|
LocalFree(pdiThis);
|
|
}
|
|
|
|
if (!ReturnStatus)
|
|
{
|
|
if (fontPtr != NULL)
|
|
{
|
|
LocalFree(fontPtr);
|
|
}
|
|
}
|
|
|
|
return (ReturnStatus);
|
|
}
|
|
|
|
|
|
|
|
|
|
PFR
|
|
ReAllocateFontList(
|
|
PFR pfrOld,
|
|
DWORD cOldFonts,
|
|
DWORD cNewFonts
|
|
)
|
|
{
|
|
PFR pfrNew = NULL;
|
|
|
|
DBGPRINT(("enter ReAllocateFontList()\n"));
|
|
|
|
do
|
|
{
|
|
// allocate new font record
|
|
pfrNew = LocalAlloc(LPTR, cNewFonts * sizeof(FONT_RECORD));
|
|
if (pfrNew == NULL)
|
|
{
|
|
DBGPRINT(("LocalAlloc fails with %d\n", GetLastError()));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// copy old font record
|
|
//
|
|
CopyMemory(pfrNew, pfrOld, cOldFonts * sizeof(FONT_RECORD));
|
|
} while (FALSE);
|
|
|
|
LocalFree(pfrOld);
|
|
|
|
return pfrNew;
|
|
}
|
|
|
|
|
|
/*
|
|
**
|
|
** WriteToSpool()
|
|
**
|
|
** Purpose: Determines if job stream is currently being written to
|
|
** the spooler, then writes it to the file if it is being written.
|
|
**
|
|
** Returns: fwrite return codes.
|
|
**
|
|
*/
|
|
DWORD
|
|
WriteToSpool(
|
|
PJR pjr,
|
|
PBYTE pchbuf,
|
|
int cchlen
|
|
)
|
|
{
|
|
BOOL SpoolIt=FALSE;
|
|
DWORD cbWritten;
|
|
DWORD dwError = NO_ERROR;
|
|
|
|
|
|
if ((cchlen !=0) && (pchbuf != NULL) &&
|
|
((pjr->psJobState==psExitServerJob) || (pjr->psJobState==psStandardJob)))
|
|
{
|
|
/* determine the data stream mode to know whether to write */
|
|
switch (pjr->JSState)
|
|
{
|
|
case JSStripEOL:
|
|
case JSStripKW:
|
|
case JSStripTok:
|
|
DBGPRINT(("POP - strip\n"));
|
|
PopJSState(pjr);
|
|
break;
|
|
|
|
case JSWriteEOL:
|
|
case JSWriteKW:
|
|
case JSWriteTok:
|
|
DBGPRINT(("POP - write\n"));
|
|
PopJSState(pjr);
|
|
case JSWrite:
|
|
SpoolIt=TRUE;
|
|
break;
|
|
}
|
|
|
|
// Do we write this Data to the Output Stream ?
|
|
if (SpoolIt)
|
|
{
|
|
// retry on disk full conditions.
|
|
LONG RetryCount = 0;
|
|
|
|
do
|
|
{
|
|
dwError = NO_ERROR;
|
|
do
|
|
{
|
|
if (pjr->FirstWrite)
|
|
{
|
|
// don't need that filter string anymore
|
|
#if 0
|
|
//
|
|
// place comment in job to signal AppleTalk monitor not to filter control characters
|
|
//
|
|
if (!WritePrinter(pjr->hPrinter, FILTERCONTROL, SIZE_FC, &cbWritten))
|
|
{
|
|
dwError = GetLastError();
|
|
DBGPRINT(("WritePrinter() failed with %d\n", dwError));
|
|
RetryCount++;
|
|
break;
|
|
}
|
|
#endif
|
|
pjr->FirstWrite = FALSE;
|
|
}
|
|
|
|
#if DBG_SPOOL_LOCALLY
|
|
if (DbgSpoolFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
WriteFile( DbgSpoolFile, pchbuf, cchlen, &cbWritten, NULL );
|
|
}
|
|
#endif
|
|
|
|
if (!WritePrinter(pjr->hPrinter, pchbuf, cchlen, &cbWritten))
|
|
{
|
|
dwError = GetLastError();
|
|
DBGPRINT(("ERROR: cannot write to printer, error = %x\n", dwError));
|
|
RetryCount++;
|
|
break;
|
|
}
|
|
} while (FALSE);
|
|
|
|
if (dwError == NO_ERROR)
|
|
break;
|
|
|
|
if ((dwError == ERROR_HANDLE_DISK_FULL) || (dwError == ERROR_DISK_FULL))
|
|
{
|
|
Sleep(180*1000); // 3 minutes. Its okay to block since we cannot
|
|
// service any other jobs either since the disk
|
|
// has no space anyway
|
|
}
|
|
} while (RetryCount <= 10);
|
|
}
|
|
}
|
|
return dwError;
|
|
}
|
|
|
|
|
|
/*
|
|
** MoveToPending()
|
|
**
|
|
** Purpose: Moves the buffer pointed at into the pending buffer.
|
|
**
|
|
** Returns: DosWrite error codes.
|
|
**
|
|
*/
|
|
DWORD
|
|
MoveToPending(
|
|
PJR pjr,
|
|
PBYTE pchbuf,
|
|
int cchlen
|
|
)
|
|
{
|
|
DBGPRINT(("Enter MoveToPending\n"));
|
|
if ((cchlen > PSLEN) || (*pchbuf != '%'))
|
|
{
|
|
/*
|
|
* input line is not a comment and is conforming PostScript line,
|
|
* so give it to WriteToSpool
|
|
*/
|
|
DBGPRINT(("not a DSC comment, so sending to spooler\n"));
|
|
return (WriteToSpool (pjr, pchbuf, cchlen));
|
|
}
|
|
|
|
pjr->PendingLen= cchlen;
|
|
memcpy(&pjr->bufPool[pjr->bufIndx].PendingBuffer[PENDLEN-cchlen], pchbuf, cchlen);
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
|
|
/*
|
|
** TellClient ()
|
|
**
|
|
** Purpose: Sends a message back to the client
|
|
**
|
|
** Returns: Any of the PAPWrite return codes.
|
|
**
|
|
*/
|
|
DWORD
|
|
TellClient(
|
|
PJR pjr,
|
|
BOOL fEof,
|
|
PBYTE BuffPtr,
|
|
int cchlen
|
|
)
|
|
{
|
|
DWORD rc = NO_ERROR;
|
|
fd_set writefds;
|
|
struct timeval timeout;
|
|
int sendflag;
|
|
int wsErr;
|
|
|
|
DBGPRINT(("enter TellClient()\n"));
|
|
|
|
do
|
|
{
|
|
FD_ZERO(&writefds);
|
|
FD_SET(pjr->sJob, &writefds);
|
|
|
|
//
|
|
// wait up to 30 seconds to be able to write
|
|
//
|
|
|
|
if (fEof)
|
|
{
|
|
sendflag = 0;
|
|
}
|
|
else
|
|
{
|
|
sendflag = MSG_PARTIAL;
|
|
}
|
|
|
|
timeout.tv_sec = 30;
|
|
timeout.tv_usec = 0;
|
|
|
|
DBGPRINT(("waiting for writeability\n"));
|
|
|
|
wsErr = select(0, NULL, &writefds, NULL, &timeout);
|
|
|
|
if (wsErr == 0)
|
|
{
|
|
DBGPRINT(("response to client times out\n"));
|
|
rc = ERROR_SEM_TIMEOUT;
|
|
break;
|
|
}
|
|
|
|
if (wsErr != 1)
|
|
{
|
|
rc = GetLastError();
|
|
DBGPRINT(("select(writefds) fails with %d\n"));
|
|
break;
|
|
}
|
|
|
|
if (send(pjr->sJob, BuffPtr, cchlen, sendflag) == SOCKET_ERROR)
|
|
{
|
|
rc = GetLastError();
|
|
DBGPRINT(("send() fails with %d\n", rc));
|
|
break;
|
|
}
|
|
} while (FALSE);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
**
|
|
** HandleBeginBinary()
|
|
**
|
|
** Purpose: Handles BeginBinary Comment Events.
|
|
**
|
|
*/
|
|
DWORD
|
|
HandleBeginBinary(
|
|
PJR pjr
|
|
)
|
|
{
|
|
DBGPRINT(("Enter HandleBeginBinary\n"));
|
|
|
|
/* Process the BeginBinary Comment */
|
|
pjr->InBinaryOp = TRUE;
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
**
|
|
** HandleEndBinary()
|
|
**
|
|
** Purpose: Handles BeginBinary Comment Events.
|
|
**
|
|
*/
|
|
DWORD
|
|
HandleEndBinary(
|
|
PJR pjr
|
|
)
|
|
{
|
|
DBGPRINT(("Enter HandleEndBinary\n"));
|
|
|
|
// Process the EndBinary Comment
|
|
pjr->InBinaryOp = FALSE;
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
**
|
|
** HandleBeginExitServer()
|
|
**
|
|
** Purpose: Handles BeginExitServer Comment Events.
|
|
**
|
|
*/
|
|
DWORD
|
|
HandleBeginExitServer(
|
|
PJR pjr
|
|
)
|
|
{
|
|
DBGPRINT(("Enter HandleBeginExitServer\n"));
|
|
switch (pjr->psJobState)
|
|
{
|
|
case psQueryJob:
|
|
case psExitServerJob:
|
|
PushJSState(pjr, JSStrip);
|
|
break;
|
|
|
|
case psStandardJob:
|
|
PushJSState(pjr, JSStripEOL);
|
|
break;
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
**
|
|
** HandleCreationDate()
|
|
**
|
|
** Purpose: Handles CreationDate Comment Events.
|
|
**
|
|
** Returns: Number of lines that should be skipped before scanning
|
|
** for another event starts again.
|
|
**
|
|
*/
|
|
DWORD
|
|
HandleCreationDate(
|
|
PJR pjr
|
|
)
|
|
{
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
**
|
|
** HandleCreator() -
|
|
**
|
|
** Purpose: Handles Creator Comment Events.
|
|
**
|
|
*/
|
|
DWORD
|
|
HandleCreator(
|
|
PJR pjr
|
|
)
|
|
{
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
**
|
|
** HandleEndExitServer()-
|
|
**
|
|
** Purpose: Handles EndExitServer Comment Events.
|
|
**
|
|
*/
|
|
DWORD
|
|
HandleEndExitServer(
|
|
PJR pjr
|
|
)
|
|
{
|
|
DBGPRINT(("Enter HandleEndExitServer\n"));
|
|
|
|
if (pjr->psJobState == psStandardJob)
|
|
PushJSState (pjr, JSStripEOL);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/*
|
|
** HandleEOF()
|
|
**
|
|
** Purpose: Handles EOF Comment Events.
|
|
**
|
|
*/
|
|
DWORD
|
|
HandleEOF(
|
|
PJR pjr
|
|
)
|
|
{
|
|
|
|
DBGPRINT(("Enter HandleEOF\n"));
|
|
|
|
if (pjr->psJobState == psQueryJob || pjr->psJobState == psExitServerJob)
|
|
{
|
|
pjr->psJobState = psStandardJob;
|
|
}
|
|
// pjr->JSState = JSStripKW;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
**
|
|
** HandleFor()
|
|
**
|
|
** Purpose: Handles For Comment Events.
|
|
**
|
|
*/
|
|
DWORD
|
|
HandleFor(
|
|
PJR pjr
|
|
)
|
|
{
|
|
|
|
LPSTR token;
|
|
BYTE pbBuffer[GENERIC_BUFFER_SIZE];
|
|
PJOB_INFO_1 pji1Job;
|
|
DWORD cbNeeded;
|
|
DWORD Status = NO_ERROR;
|
|
|
|
DBGPRINT(("Enter HandleFor\n"));
|
|
|
|
//
|
|
// only look for name in main part of print job
|
|
//
|
|
if (pjr->psJobState != psStandardJob)
|
|
{
|
|
DBGPRINT(("not in standard job, skipping username\n"));
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// make sure we haven't already set the title
|
|
//
|
|
|
|
if (pjr->dwFlags & JOB_FLAG_OWNERSET)
|
|
{
|
|
DBGPRINT(("owner already set, skipping username\n"));
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// mark the job as having an owner
|
|
//
|
|
pjr->dwFlags |= JOB_FLAG_OWNERSET;
|
|
|
|
//
|
|
// look for the client name in the comment and
|
|
// default if not found
|
|
//
|
|
if (((token = strtok(NULL, NULL_STR)) == NULL) ||
|
|
(strchr(token, '*') != NULL))
|
|
{
|
|
token = CLIENTNAME;
|
|
}
|
|
|
|
//
|
|
// get the current job info
|
|
//
|
|
pji1Job = (PJOB_INFO_1)pbBuffer;
|
|
if (!GetJob(pjr->hPrinter,
|
|
pjr->dwJobId,
|
|
1,
|
|
pbBuffer,
|
|
GENERIC_BUFFER_SIZE,
|
|
&cbNeeded))
|
|
{
|
|
//
|
|
// need more buffer? If so, try again with a larger one
|
|
//
|
|
|
|
if (cbNeeded > GENERIC_BUFFER_SIZE)
|
|
{
|
|
DBGPRINT(("GetJob needs larger buffer. Retrying\n"));
|
|
pji1Job = (PJOB_INFO_1)LocalAlloc(LPTR, cbNeeded);
|
|
if (pji1Job == NULL)
|
|
{
|
|
Status = GetLastError();
|
|
DBGPRINT(("ERROR: out of memory in HandleFor\n"));
|
|
return Status;
|
|
}
|
|
|
|
if (!GetJob(pjr->hPrinter,
|
|
pjr->dwJobId,
|
|
1,
|
|
(LPBYTE)pji1Job,
|
|
cbNeeded,
|
|
&cbNeeded))
|
|
{
|
|
Status = GetLastError();
|
|
DBGPRINT(("ERROR: second GetJob fails in HandleFor with %d\n",
|
|
Status));
|
|
return Status;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status = GetLastError();
|
|
DBGPRINT(("GetJob fails with %d\n", Status));
|
|
return Status ;
|
|
}
|
|
}
|
|
|
|
//
|
|
// change the username
|
|
//
|
|
OemToCharBuffW(token, pjr->pszUser, (TOKLEN > strlen(token))?(strlen(token)+1):(TOKLEN+1));
|
|
pji1Job->pUserName = pjr->pszUser;
|
|
DBGPRINT(("Setting user name to %ws\n", pjr->pszUser));
|
|
|
|
//
|
|
// set new job information (do not change job position)
|
|
//
|
|
pji1Job->Position = 0;
|
|
|
|
if (!SetJob(pjr->hPrinter,
|
|
pjr->dwJobId,
|
|
1,
|
|
(LPBYTE)pji1Job,
|
|
0))
|
|
{
|
|
Status = GetLastError();
|
|
DBGPRINT(("WARNING: tried to change user name and failed setjob with %d\n", Status));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/*
|
|
**
|
|
** HandleLogin()
|
|
**
|
|
** Purpose: Handles Login Comment Events.
|
|
**
|
|
** Returns: PAPWrite errors.
|
|
**
|
|
*/
|
|
DWORD
|
|
HandleLogin(
|
|
PJR pjr
|
|
)
|
|
{
|
|
DBGPRINT(("Enter HandleLogin\n"));
|
|
PushJSState(pjr,JSStripEOL);
|
|
return (TellClient(pjr, TRUE, LOGINRESPONSE, sizeof(LOGINRESPONSE)-1));
|
|
}
|
|
|
|
|
|
/*
|
|
**
|
|
** HandleTitle()
|
|
**
|
|
** Purpose: Handles Title Comment Events.
|
|
**
|
|
*/
|
|
DWORD
|
|
HandleTitle(
|
|
PJR pjr
|
|
)
|
|
{
|
|
LPSTR token;
|
|
LPWSTR pszTitle;
|
|
BYTE pbBuffer[GENERIC_BUFFER_SIZE];
|
|
PJOB_INFO_1 pji1Job;
|
|
PJOB_INFO_1 pji1JobAlloc=NULL;
|
|
DWORD cbNeeded;
|
|
DWORD Status = NO_ERROR;
|
|
|
|
DBGPRINT(("Enter HandleTitle\n"));
|
|
|
|
//
|
|
// only get title if we are in main part of job
|
|
//
|
|
if (pjr->psJobState != psStandardJob)
|
|
{
|
|
DBGPRINT(("skipping this title, not main job\n"));
|
|
return NO_ERROR ;
|
|
}
|
|
|
|
//
|
|
// make sure title not already set
|
|
//
|
|
if (JOB_FLAG_TITLESET & pjr->dwFlags)
|
|
{
|
|
DBGPRINT(("title already set. Skipping this title\n"));
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// marke the title as set
|
|
//
|
|
|
|
pjr->dwFlags |= JOB_FLAG_TITLESET;
|
|
|
|
//
|
|
// get the current job data
|
|
//
|
|
|
|
pji1Job = (PJOB_INFO_1)pbBuffer;
|
|
if (!GetJob(pjr->hPrinter,
|
|
pjr->dwJobId,
|
|
1,
|
|
pbBuffer,
|
|
GENERIC_BUFFER_SIZE,
|
|
&cbNeeded))
|
|
{
|
|
//
|
|
// need more buffer? If so, try again with a larger one
|
|
//
|
|
|
|
if (cbNeeded > GENERIC_BUFFER_SIZE)
|
|
{
|
|
DBGPRINT(("GetJob needs larger buffer. Retrying\n"));
|
|
pji1JobAlloc = (PJOB_INFO_1)LocalAlloc(LPTR, cbNeeded);
|
|
if (pji1JobAlloc == NULL)
|
|
{
|
|
Status = GetLastError();
|
|
DBGPRINT(("ERROR: out of memory\n"));
|
|
return Status;
|
|
}
|
|
|
|
pji1Job = pji1JobAlloc;
|
|
|
|
if (!GetJob(pjr->hPrinter,
|
|
pjr->dwJobId,
|
|
1,
|
|
(LPBYTE)pji1Job,
|
|
cbNeeded,
|
|
&cbNeeded))
|
|
{
|
|
Status = GetLastError();
|
|
DBGPRINT(("ERROR: second GetJob fails with %d\n", Status));
|
|
LocalFree(pji1JobAlloc);
|
|
return Status;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status = GetLastError();
|
|
DBGPRINT(("GetJob fails with %d\n", Status));
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
//
|
|
// get the title
|
|
//
|
|
if ((token = strtok(NULL, NULL_STR)) == NULL)
|
|
{
|
|
// Clear flag. No title.
|
|
pjr->dwFlags &= ~JOB_FLAG_TITLESET;
|
|
return NO_ERROR ;
|
|
}
|
|
|
|
pszTitle = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * (strlen(token)+1));
|
|
if (pszTitle == NULL)
|
|
{
|
|
Status = GetLastError();
|
|
DBGPRINT(("out of memory for pszTitle\n"));
|
|
return Status;
|
|
}
|
|
|
|
OemToCharBuffW(token, pszTitle, strlen(token)+1);
|
|
|
|
//
|
|
// change the title
|
|
//
|
|
pji1Job->Position = 0;
|
|
pji1Job->pDocument = pszTitle;
|
|
DBGPRINT(("changing title to %ws\n", pszTitle));
|
|
|
|
if (!SetJob(pjr->hPrinter,
|
|
pjr->dwJobId,
|
|
1,
|
|
(LPBYTE)pji1Job,
|
|
0))
|
|
{
|
|
|
|
Status = GetLastError();
|
|
DBGPRINT(("WARNING: tried to change title and failed setjob with %d\n", Status));
|
|
}
|
|
|
|
if (pji1JobAlloc)
|
|
{
|
|
LocalFree(pji1JobAlloc);
|
|
}
|
|
|
|
LocalFree(pszTitle);
|
|
return Status;
|
|
}
|
|
|
|
|
|
/*
|
|
**
|
|
** HandleBeginProcSet()
|
|
**
|
|
** Purpose: Handles Begining of a ProcSet Upload
|
|
**
|
|
*/
|
|
DWORD
|
|
HandleBeginProcSet(
|
|
PJR pjr
|
|
)
|
|
{
|
|
DBGPRINT(("Enter HandleBeginProcSet\n"));
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
** HandleEndProcSet()
|
|
**
|
|
** Purpose: Handles End of a procset inclusion.
|
|
**
|
|
*/
|
|
DWORD
|
|
HandleEndProcSet(
|
|
PJR pjr
|
|
)
|
|
{
|
|
DBGPRINT(("Enter HandleEndProcSet\n"));
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
** HandleIncludeProcSet()
|
|
**
|
|
** Purpose: Handles end of a procset inclusion.
|
|
**
|
|
** Entry:
|
|
** Pointer to Job Structure
|
|
**
|
|
** Exit:
|
|
**
|
|
** 0 if no error, otherwise error code.
|
|
*/
|
|
DWORD
|
|
HandleIncludeProcSet(
|
|
PJR pjr
|
|
)
|
|
{
|
|
DBGPRINT(("Enter HandleIncludeProcSet\n"));
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// HandlePages()
|
|
//
|
|
// This comment includes the total number of pages in the job and is
|
|
// used to set the jobinfo structure for the job with the total number
|
|
// of pages
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
DWORD
|
|
HandlePages(
|
|
PJR pjr
|
|
)
|
|
{
|
|
LPSTR token;
|
|
DWORD cPages = 0;
|
|
BYTE pbBuffer[GENERIC_BUFFER_SIZE];
|
|
PJOB_INFO_1 pji1Job;
|
|
DWORD cbNeeded;
|
|
DWORD Status = NO_ERROR;
|
|
|
|
DBGPRINT(("Enter HandlePages\n"));
|
|
|
|
//
|
|
// only get pages if we are in main part of job
|
|
//
|
|
if (pjr->psJobState != psStandardJob)
|
|
{
|
|
DBGPRINT(("skipping this comment, not main job\n"));
|
|
return NO_ERROR ;
|
|
}
|
|
|
|
//
|
|
// get the current job data
|
|
//
|
|
|
|
pji1Job = (PJOB_INFO_1)pbBuffer;
|
|
if (!GetJob(pjr->hPrinter,
|
|
pjr->dwJobId,
|
|
1,
|
|
pbBuffer,
|
|
GENERIC_BUFFER_SIZE,
|
|
&cbNeeded))
|
|
{
|
|
//
|
|
// GetJob failed, and buffer passed in is larger than the largest
|
|
// possible buffer for a job_info_1, so abort this ADSC comment
|
|
//
|
|
|
|
Status = GetLastError();
|
|
DBGPRINT(("GetJob() fails with %d\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// get the number of pages. The comment is of the form %%Pages xx nn
|
|
// where xx is the number of pages to display
|
|
//
|
|
|
|
token = strtok(NULL, " ");
|
|
if (token == NULL)
|
|
return(NO_ERROR);
|
|
|
|
cPages = atoi(token);
|
|
|
|
//
|
|
// change the number of pages
|
|
//
|
|
|
|
pji1Job->Position = 0;
|
|
pji1Job->TotalPages = cPages;
|
|
DBGPRINT(("changing page count to %d\n", cPages));
|
|
|
|
if (!SetJob(pjr->hPrinter,
|
|
pjr->dwJobId,
|
|
1,
|
|
(LPBYTE)pji1Job,
|
|
0))
|
|
{
|
|
Status = GetLastError();
|
|
DBGPRINT(("SetJob fails with %d\n",Status));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
struct commtable
|
|
{
|
|
PSZ commentstr;
|
|
DWORD (near *pfnHandle)(PJR);
|
|
} commtable [] =
|
|
{
|
|
{ FORCOMMENT, HandleFor },
|
|
{ TITLECOMMENT, HandleTitle },
|
|
{ BEXITSERVER, HandleBeginExitServer },
|
|
{ EEXITSERVER, HandleEndExitServer },
|
|
{ BPROCSET, HandleBeginProcSet },
|
|
{ EPROCSET, HandleEndProcSet },
|
|
{ INCLUDEPROCSET, HandleIncludeProcSet },
|
|
{ CREATIONDATE, HandleCreationDate },
|
|
{ CREATOR, HandleCreator },
|
|
{ EOFCOMMENT, HandleEOF },
|
|
{ LOGIN, HandleLogin },
|
|
{ LOGINCONT, HandleLogin },
|
|
{ BEGINBINARY, HandleBeginBinary },
|
|
{ ENDBINARY, HandleEndBinary },
|
|
{ PAGESCOMMENT, HandlePages },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/*
|
|
** HandleComment()
|
|
**
|
|
** Purpose: Handles Comment Events.
|
|
**
|
|
*/
|
|
DWORD
|
|
HandleComment(
|
|
PJR pjr,
|
|
PBYTE ps
|
|
)
|
|
{
|
|
PSZ token;
|
|
struct commtable *pct;
|
|
DWORD status = NO_ERROR;
|
|
|
|
DBGPRINT(("Enter HandleComment\n"));
|
|
|
|
if ((token = strtok(ps," :")) != NULL)
|
|
{
|
|
DBGPRINT(("Comment: %s\n", token));
|
|
for (pct = commtable; pct->pfnHandle; pct++)
|
|
{
|
|
if (!_stricmp(token, pct->commentstr))
|
|
{
|
|
status = pct->pfnHandle(pjr);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// No action on this keyword !!!
|
|
return status;
|
|
}
|
|
|
|
|
|
/*
|
|
** HandleJobComment()
|
|
**
|
|
** Purpose: This parses PostScript Job Comments
|
|
*/
|
|
void
|
|
HandleJobComment(
|
|
PJR pjr,
|
|
PBYTE ps
|
|
)
|
|
{
|
|
char *token;
|
|
|
|
DBGPRINT(("Enter HandleJobComment\n"));
|
|
|
|
token= strtok(ps, " ");
|
|
|
|
//
|
|
// it's a job statement
|
|
//
|
|
|
|
if ((token = strtok(NULL, " ")) != NULL)
|
|
{
|
|
/* standard job identification */
|
|
if (!strcmp(token, QUERYJOBID))
|
|
{
|
|
pjr->psJobState = psQueryJob;
|
|
pjr->JSState = JSStrip;
|
|
DBGPRINT(("This is a standard job\n"));
|
|
return;
|
|
}
|
|
|
|
if (!strcmp(token, EXITJOBID))
|
|
{
|
|
pjr->psJobState = psExitServerJob;
|
|
pjr->JSState = JSStrip;
|
|
DBGPRINT(("This is an exitjob\n"));
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Job identification not recognized, but some PostScript hackers
|
|
// put the program name in this comment, so we treat this as a standard
|
|
// job
|
|
//
|
|
|
|
DBGPRINT(("This is an unknown jobtype - processing as standard job\n"));
|
|
pjr->psJobState = psStandardJob;
|
|
pjr->JSState = JSWrite;
|
|
}
|
|
|
|
|
|
|
|
/* LineLength -
|
|
* Returns the number of bytes, including CR/LF to the next
|
|
* CR/LF in the buffer. If no CR/LF found, returns -1
|
|
*/
|
|
int
|
|
LineLength(PBYTE pBuf, int cbBuf)
|
|
{
|
|
|
|
int intLength = 0;
|
|
|
|
while (intLength < cbBuf)
|
|
{
|
|
//
|
|
// we are looking for a CR
|
|
//
|
|
if ((pBuf[intLength] != '\x0d') && (pBuf[intLength] != '\x0a'))
|
|
{
|
|
intLength++;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// we've found a CR. If it's followed by a LF, return that
|
|
// length too, otherwise, just return what we've found
|
|
//
|
|
if ((intLength + 1) < cbBuf)
|
|
{
|
|
if (pBuf[intLength + 1] == '\x0a')
|
|
{
|
|
return intLength + 2;
|
|
}
|
|
}
|
|
|
|
return intLength + 1;
|
|
}
|
|
|
|
return (-1);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
**
|
|
** PSParse()
|
|
**
|
|
** Purpose: This does the actual parsing of the PostScript Data Stream.
|
|
** This routine is always called pointing to the data stream at
|
|
** the beginning of a the Data Stream, or the beginning of a line.
|
|
**
|
|
** Returns: PAPWrite error codes.
|
|
**
|
|
*/
|
|
DWORD
|
|
PSParse(
|
|
PJR pjr,
|
|
PBYTE pchbuf,
|
|
int cchlen
|
|
)
|
|
{
|
|
int cbskip;
|
|
char ps[PENDLEN];
|
|
DWORD err = NO_ERROR;
|
|
|
|
DBGPRINT(("ENTER: PSParse()\n"));
|
|
|
|
while (cchlen > 0)
|
|
{
|
|
if ((cbskip = LineLength(pchbuf, cchlen)) == -1)
|
|
return (MoveToPending(pjr, pchbuf, cchlen));
|
|
|
|
/* Determine what the event is */
|
|
if ((cbskip < PSLEN) && (pchbuf[0] == '%'))
|
|
{
|
|
/* copy a comment into the ps string */
|
|
memcpy(ps, pchbuf, cbskip);
|
|
ps[cbskip-1] = 0; // OverWrite the CR/LF
|
|
|
|
if (ps[1] == '%')
|
|
{
|
|
/* Its a Query Comment */
|
|
if (ps[2] == '?'&& !pjr->InBinaryOp)
|
|
{
|
|
if (ps[3] == 'B')
|
|
{
|
|
/* Process the Begin Query Comment */
|
|
if ((err = HandleBQComment(pjr, ps)) != NO_ERROR)
|
|
{
|
|
DBGPRINT(("PSParse: HandleBQComment %ld\n", err));
|
|
return(err);
|
|
}
|
|
}
|
|
else if (ps[3] == 'E')
|
|
{
|
|
if (pjr->InProgress == QUERYDEFAULT)
|
|
{
|
|
if ((err = FinishDefaultQuery(pjr, ps)) != NO_ERROR)
|
|
{
|
|
DBGPRINT(("PSParse: FinishDefaultQuery %ld\n", err));
|
|
return(err);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Process the Comment */
|
|
if ((err = HandleComment(pjr, ps)) != NO_ERROR)
|
|
{
|
|
DBGPRINT(("PSParse: HandleComment %ld\n", err));
|
|
return(err);
|
|
}
|
|
}
|
|
}
|
|
else if (ps[1] == '!'&& !pjr->InBinaryOp)
|
|
{
|
|
/* Process Job ID Comment */
|
|
HandleJobComment(pjr, ps);
|
|
}
|
|
}
|
|
|
|
/* Write the lines to the spoolfile? */
|
|
if ((err = WriteToSpool (pjr, pchbuf, cbskip)) != NO_ERROR)
|
|
return (err);
|
|
|
|
pchbuf += cbskip;
|
|
cchlen -= cbskip;
|
|
}
|
|
return NO_ERROR;
|
|
}
|