1 /*****************************************************************************\
2   printer.cpp : Implimentation for the Printer class
3 
4   Copyright (c) 1996 - 2015, HP Co.
5   All rights reserved.
6 
7   Redistribution and use in source and binary forms, with or without
8   modification, are permitted provided that the following conditions
9   are met:
10   1. Redistributions of source code must retain the above copyright
11      notice, this list of conditions and the following disclaimer.
12   2. Redistributions in binary form must reproduce the above copyright
13      notice, this list of conditions and the following disclaimer in the
14      documentation and/or other materials provided with the distribution.
15   3. Neither the name of HP nor the names of its
16      contributors may be used to endorse or promote products derived
17      from this software without specific prior written permission.
18 
19   THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
20   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
22   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24   TO, PATENT INFRINGEMENT; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25   OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26   ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 \*****************************************************************************/
30 
31 
32 #include "header.h"
33 #include "io_defs.h"
34 #include "resources.h"
35 
36 
37 //
38 // ** Printer CLASS **
39 
40 APDK_BEGIN_NAMESPACE
41 extern BYTE* GetHTBinary();
42 APDK_END_NAMESPACE
43 
44 APDK_BEGIN_NAMESPACE
45 
Printer(SystemServices * pSys,int numfonts,BOOL proto)46 Printer::Printer
47 (
48     SystemServices* pSys,
49     int numfonts,
50     BOOL proto
51 ) :
52     constructor_error(NO_ERROR),
53     IOMode(pSys->IOMode),
54 #if defined(APDK_FONTS_NEEDED)
55     iNumFonts(numfonts),
56 #else
57     iNumFonts(0),
58 #endif
59     bCheckForCancelButton(FALSE),
60     ulBytesSentSinceCancelCheck(0),
61     ePen(NO_PEN),
62     CMYMap(NULL),
63     pSS(pSys),
64     InSlowPollMode(0),
65     iTotal_SLOW_POLL_Count(0),
66     iMax_SLOW_POLL_Count(DEFAULT_SLOW_POLL_COUNT),
67     ErrorTerminationState(FALSE),
68     iBuffSize(pSys->GetSendBufferSize()),
69     iCurrBuffSize(0),
70     EndJob(FALSE),
71     ModeCount(2),
72     m_bVIPPrinter(FALSE)
73 {
74 
75     int i = 0; // counter
76 
77 #ifdef  APDK_LINUX
78     m_iNumPages = 0;
79 #endif
80 
81     for (i = 0; i < MAX_PRINTMODES; i++)
82     {
83         pMode[i]=NULL;
84     }
85 
86     //CompatiblePens[0] = BOTH_PENS;
87     //for (i = 1; i < MAX_COMPATIBLE_PENS; i++)
88     //{
89     //    CompatiblePens[i] = DUMMY_PEN;
90     //}
91 
92     if (IOMode.bDevID)
93     {
94        iMax_SLOW_POLL_Count = DEFAULT_SLOW_POLL_BIDI;
95     }
96 
97     // Allocate memory for my send buffer
98     pSendBuffer = NULL;
99 #ifdef APDK_BUFFER_SEND
100     pSendBuffer = pSS->AllocMem(iBuffSize+2);
101     CNEWCHECK(pSendBuffer);
102 #endif
103 
104 #ifdef APDK_AUTODUPLEX
105     bDuplexCapable = FALSE;
106     m_bRotateBackPage = TRUE;
107 #endif
108 
109 /*
110  *  LaserJet printers do not send status via device id string. PJL is used to
111  *  get status.
112  *  REVISIT:    Do the same for Business Inkjets as well.
113  */
114 
115     m_bStatusByPJL = FALSE;
116     char    *tmpStr;
117     if ((strstr ((char *) pSS->strDevID, "LaserJet")) &&
118         (tmpStr = strstr ((char *) pSS->strDevID, "CMD:")) &&
119         (tmpStr = strstr (tmpStr+4, "PJL")))
120     {
121         m_bStatusByPJL = TRUE;
122     }
123 
124 #if defined(APDK_FONTS_NEEDED)
125     // create dummy font objects to be queried via EnumFont
126     // these fonts used by all except DJ400
127 
128     for (i = 0; i<=MAX_PRINTER_FONTS; i++)
129         fontarray[i] = NULL;
130 
131 
132 #ifdef APDK_COURIER
133     fontarray[COURIER_INDEX] = new Courier();
134     CNEWCHECK(fontarray[COURIER_INDEX]);
135 #endif
136 #ifdef APDK_CGTIMES
137     fontarray[CGTIMES_INDEX] = new CGTimes();
138     CNEWCHECK(fontarray[CGTIMES_INDEX]);
139 #endif
140 #ifdef APDK_LTRGOTHIC
141     fontarray[LETTERGOTHIC_INDEX] = new LetterGothic();
142     CNEWCHECK(fontarray[LETTERGOTHIC_INDEX]);
143 #endif
144 #ifdef APDK_UNIVERS
145     fontarray[UNIVERS_INDEX] = new Univers();
146     CNEWCHECK(fontarray[UNIVERS_INDEX]);
147 #endif
148 
149 #endif  //
150 } //Printer
151 
152 
~Printer()153 Printer::~Printer()
154 {
155     if (pMode[GRAYMODE_INDEX])
156     {
157         if (pMode[GRAYMODE_INDEX]->dyeCount==3) // only happens when compgray map used
158         {
159             pSS->FreeMem((BYTE*) pMode[GRAYMODE_INDEX]->cmap.ulMap1 );
160         }
161     }
162 
163     for (int i = 0; i < MAX_PRINTMODES; i++)
164     {
165         if (pMode[i])
166         {
167             delete pMode[i];
168         }
169     }
170 
171 #ifdef APDK_BUFFER_SEND
172     if (pSendBuffer != NULL)
173     {
174         pSS->FreeMem(pSendBuffer);
175     }
176 #endif
177 
178 #ifdef APDK_COURIER
179     delete fontarray[COURIER_INDEX];
180 #endif
181 #ifdef APDK_CGTIMES
182     delete fontarray[CGTIMES_INDEX];
183 #endif
184 #ifdef APDK_LTRGOTHIC
185     delete fontarray[LETTERGOTHIC_INDEX];
186 #endif
187 #ifdef APDK_UNIVERS
188     delete fontarray[UNIVERS_INDEX];
189 #endif
190 
191 } //~Printer
192 
193 
194 ////////////////////////////////////////////////////////////////////////////
CreateCompressor(unsigned int RasterSize)195 Compressor* Printer::CreateCompressor (unsigned int RasterSize)
196 {
197     return new Mode9 (pSS, RasterSize);   // most printers use mode 9
198 }
199 
200 ////////////////////////////////////////////////////////////////////////////
CreateBlackPlaneCompressor(unsigned int RasterSize,BOOL bVIPPrinter)201 Compressor* Printer::CreateBlackPlaneCompressor (unsigned int RasterSize,
202                                                  BOOL bVIPPrinter)
203 {
204     return new Mode9 (pSS, RasterSize, bVIPPrinter);   // most printers use mode 9
205 }
206 
207 ////////////////////////////////////////////////////////////////////////////
208 // ** API functions
209 //
210 
211 
Flush(int FlushSize)212 DRIVER_ERROR Printer::Flush
213 (
214     int FlushSize       // = MAX_RASTERSIZE
215 )
216 // flush possible leftover garbage --
217 // default call will send one (maximal) raster's worth of zeroes
218 {
219     ASSERT(FlushSize > 0);
220     ASSERT(FlushSize <= MAX_RASTERSIZE);
221 
222     DRIVER_ERROR err = NO_ERROR;
223     int iChunkSize = 1000;
224     BYTE *zero = NULL;
225 
226     // Try to allocate iChunkSize bytes of memory.  If we fail then cut size
227     // in half and try again.  If we can't allocate even 10 bytes then bail
228     // with a memory allocation error.  Flush is called at the beginning of
229     // the print job - if there is no memory allocate now then we won't be
230     // printing in any case.
231     while (iChunkSize > 10 && zero == NULL)
232     {
233         zero = pSS->AllocMem(iChunkSize);
234         if (zero == NULL)
235         {
236             iChunkSize /= 2;
237         }
238     }
239 
240     if (zero == NULL)
241     {
242         return ALLOCMEM_ERROR;
243     }
244 
245     memset(zero, 0, iChunkSize);
246     int iChunks = (FlushSize / iChunkSize) + 1;
247 
248     for (int i = 0; i < iChunks; i++)
249     {
250         if ((err = Send( zero, iChunkSize)) != NO_ERROR)
251         {
252             break;              // there was an error
253         }
254     }
255     pSS->FreeMem(zero);         //break to here
256     return err;
257 } //Flush
258 
259 
260 /*
261  *  Function name: ParseError
262  *
263  *  Owner: Darrell Walker
264  *
265  *  Purpose:  To determine what error state the printer is in.
266  *
267  *  Called by: Send()
268  *
269  *  Parameters on entry: status_reg is the contents of the centronics
270  *                      status register (at the time the error was
271  *                      detected)
272  *
273  *  Parameters on exit: unchanged
274  *
275  *  Return Values: The proper DISPLAY_STATUS to reflect the printer
276  *              error state.
277  *
278  */
279 
ParseError(BYTE status_reg)280 DISPLAY_STATUS Printer::ParseError
281 (
282     BYTE status_reg
283 )
284 {
285     DBG1("Printer: parsing error info\n");
286 
287     DRIVER_ERROR err = NO_ERROR;
288     BYTE DevIDBuffer[DevIDBuffSize];
289 
290     if(IOMode.bDevID)
291     {
292         // If a bi-di cable was plugged in and everything was OK, let's see if it's still
293         // plugged in and everything is OK
294         err = pSS->GetDeviceID(DevIDBuffer, DevIDBuffSize, TRUE);
295         if(err != NO_ERROR)
296         {
297             // job was bi-di but now something's messed up, probably cable unplugged
298             // or printer turned off during print job
299             return DISPLAY_COMM_PROBLEM;
300         }
301     }
302 
303     // check for errors we can detect from the status reg
304 
305     if (IOMode.bStatus)
306     {
307         if ( DEVICE_IS_OOP(status_reg) )
308         {
309             DBG1("Out Of Paper\n");
310             return DISPLAY_OUT_OF_PAPER;
311         }
312 
313 		if (DEVICE_PAPER_JAMMED(status_reg))
314 		{
315 			DBG1("Paper Jammed\n");
316 			return DISPLAY_PAPER_JAMMED;
317 		}
318 		if (DEVICE_IO_TRAP(status_reg))
319         {
320             DBG1("IO Trap\n");
321             return DISPLAY_ERROR_TRAP;
322         }
323     }
324 
325     if (IOMode.bDevID)
326     {
327         if ( TopCoverOpen(status_reg) )
328         {
329             DBG1("Top Cover Open\n");
330             return DISPLAY_TOP_COVER_OPEN;
331         }
332 
333         // VerifyPenInfo will handle prompting the user
334         //  if this is a problem
335         VerifyPenInfo();
336     }
337 
338     // don't know what the problem is-
339     //  Is the PrinterAlive?
340     if (pSS->PrinterIsAlive())  // <- This is only viable if bStatus is TRUE
341     {
342         iTotal_SLOW_POLL_Count += iMax_SLOW_POLL_Count;
343 
344         // -Note that iTotal_SLOW_POLL_Count is a multiple of
345         //  iMax_SLOW_POLL_Count allowing us to check this
346         //  on an absolute time limit - not relative to the number
347         //  of times we happen to have entered ParseError.
348         // -Also note that we have different thresholds for uni-di & bi-di.
349 
350         // REVISIT these counts - they are relative to the speed through
351         // the send loop aren't they?  They may be too long!
352         if(
353             ((IOMode.bDevID == FALSE) && (iTotal_SLOW_POLL_Count >= 60)) ||
354             ((IOMode.bDevID == TRUE)  && (iTotal_SLOW_POLL_Count >= 120))
355           )
356         {
357             return DISPLAY_BUSY;
358         }
359         else
360         {
361             return DISPLAY_PRINTING;
362         }
363     }
364     else
365     {
366         return DISPLAY_COMM_PROBLEM;
367     }
368 } //ParseError
369 
Encapsulate(const RASTERDATA * InputRaster,BOOL bLastPlane)370 DRIVER_ERROR Printer::Encapsulate
371 (
372     const RASTERDATA* InputRaster,
373     BOOL bLastPlane
374 )
375 {
376     DRIVER_ERROR    err;
377     char            scratch[20];
378     int             scratchLen;
379 
380     if (bLastPlane)
381     {
382 		if (VIPPrinter())
383 		{
384 			if (InputRaster->rastersize[COLORTYPE_BLACK] != 0)
385 			{
386 				if (InputRaster->rastersize[COLORTYPE_COLOR] != 0)
387 				{
388 					scratchLen = sprintf (scratch, "\033*b%uV", InputRaster->rastersize[COLORTYPE_BLACK]);
389 					err = Send ((const BYTE*) scratch, scratchLen);
390 					if (err == NO_ERROR)
391 					{
392 						err = Send (InputRaster->rasterdata[COLORTYPE_BLACK], InputRaster->rastersize[COLORTYPE_BLACK]);
393 					}
394 					if (err == NO_ERROR)
395 					{
396 						scratchLen = sprintf (scratch, "\033*b%uW", InputRaster->rastersize[COLORTYPE_COLOR]);
397 						err = Send ((const BYTE*) scratch, scratchLen);
398 						if (err == NO_ERROR)
399 						{
400 							err = Send (InputRaster->rasterdata[COLORTYPE_COLOR], InputRaster->rastersize[COLORTYPE_COLOR]);
401 						}
402 					}
403 				}
404 				else
405 				{
406 					scratchLen = sprintf (scratch, "\033*b%uV", InputRaster->rastersize[COLORTYPE_BLACK]);
407 					err = Send ((const BYTE*) scratch, scratchLen);
408 					if (err == NO_ERROR)
409 					{
410 						err = Send (InputRaster->rasterdata[COLORTYPE_BLACK], InputRaster->rastersize[COLORTYPE_BLACK]);
411 						if (err == NO_ERROR)
412 						{
413 							scratchLen = sprintf (scratch, "\033*b%uW", 0);
414 							err = Send ((const BYTE*) scratch, scratchLen);
415 						}
416 					}
417 				}
418 			}
419 			else
420 			{
421 				scratchLen = sprintf (scratch, "\033*b%uV", 0);
422 				err = Send ((const BYTE*) scratch, scratchLen);
423 				if (err == NO_ERROR)
424 				{
425 					scratchLen = sprintf (scratch, "\033*b%uW", InputRaster->rastersize[COLORTYPE_COLOR]);
426 					err = Send ((const BYTE*) scratch, scratchLen);
427 					if (err == NO_ERROR && InputRaster->rastersize[COLORTYPE_COLOR] != 0)
428 					{
429 						err = Send (InputRaster->rasterdata[COLORTYPE_COLOR], InputRaster->rastersize[COLORTYPE_COLOR]);
430 					}
431 				}
432 			}
433 		}
434 		else
435 		{
436 			scratchLen = sprintf (scratch, "\033*b%uW", InputRaster->rastersize[COLORTYPE_COLOR]);
437 			err = Send ((const BYTE*) scratch, scratchLen);
438 			if (err == NO_ERROR)
439 			{
440 				err = Send (InputRaster->rasterdata[COLORTYPE_COLOR], InputRaster->rastersize[COLORTYPE_COLOR]);
441 			}
442 		}
443     }
444     else
445     {
446         scratchLen = sprintf (scratch, "\033*b%uV", InputRaster->rastersize[COLORTYPE_COLOR]);
447 		err = Send ((const BYTE*) scratch, scratchLen);
448 		if (err == NO_ERROR)
449 		{
450 			err = Send (InputRaster->rasterdata[COLORTYPE_COLOR], InputRaster->rastersize[COLORTYPE_COLOR]);
451 		}
452     }
453     return err;
454 }
455 
456 
Send(const BYTE * pWriteBuff)457 DRIVER_ERROR Printer::Send
458 (
459     const BYTE* pWriteBuff
460 )
461 {
462     ASSERT(pWriteBuff);
463     int len = strlen((const char*)pWriteBuff);
464     return Send(pWriteBuff,len);
465 } //Send
466 
467 
468 /*
469  *  Function name: Printer::Send
470  *
471  *  Owner: Darrell Walker
472  *
473  *  Purpose:  Encapsulate error handling generated by performing I/O
474  *
475  *  Called by:
476  *
477  *  Calls made: WritePort(), GetStatus(), BusyWait(), ParseError(),
478  *              DisplayPrinterStatus(), YieldToSystem()
479  *
480  *  Parameters on entry: pJob is a pointer to the current JOBSTRUCT,
481  *                      pWriteBuff is a pointer to the data the
482  *                      caller wishes to send to the pritner,
483  *                      wWriteCount is the number of bytes of
484  *                      pWriteBuff to send
485  *
486  *  Parameters on exit: Unchanged
487  *
488  *  Side effects: Sends data to the printer, may update print dialog,
489  *              may change pJob->InSlowPollMode,
490  *              pJob->ErrorTerminationState
491  *
492  *  Return Values: NO_ERROR or JOB_CANCELED or IO_ERROR
493  *
494  *  Comments: (TJL) This routine now has functionality to attempt iterating
495  *      through wWriteCount bytes of data (until we hit slow poll mode)
496  *      before sending PCL cleanup code.  This still leaves the possibility of
497  *      prematurely exiting with an incomplete raster, but gives I/O a fighting chance
498  *      of completing the raster while also protecting from a bogged down slow poll phase
499  *      which would prevent a timely exit from CANCEL.  A JobCanceled flag is used
500  *      because JOB_CANCELED cannot be maintained by write_error through the while
501  *      loop since it will be overwritten by next ToDevice.
502  *
503  */
504 
Send(const BYTE * pWriteBuff,DWORD dwWriteCount)505 DRIVER_ERROR Printer::Send
506 (
507     const BYTE* pWriteBuff,
508     DWORD dwWriteCount
509 )
510 {
511     ASSERT(pWriteBuff);
512 
513     DRIVER_ERROR    write_error = NO_ERROR;
514     DWORD           residual = 0;
515     const BYTE *    pWritePos = NULL;
516     BOOL            error_displayed = FALSE;
517     BYTE            status_reg = 0;
518     DISPLAY_STATUS  eDisplayStatus = DISPLAY_PRINTING;
519     BOOL            JobCanceled = FALSE;  // see comments in function header
520 
521     // these are just an abstraction layer - buffered vs. non-buffered
522     const BYTE *    pBuffer = pWriteBuff;
523     DWORD           dwSendSize = dwWriteCount;
524 
525 ////////////////////////////////////////////////////////////////
526 #ifdef NULL_IO
527     // test imaging speed independent of printer I/O, will not
528     // send any data to the device
529     return NO_ERROR;
530 #endif
531 ////////////////////////////////////////////////////////////////
532 
533     if (ErrorTerminationState)  // don't try any more IO if we previously
534     {
535         return JOB_CANCELED;    // terminated in an error state
536     }
537 
538     if (EndJob == FALSE && dwWriteCount == 0)    // don't bother processing
539     {
540         return NO_ERROR;                         //  an empty Send call
541     }
542 
543 #ifdef APDK_BUFFER_SEND
544     DWORD BytesToWrite = dwWriteCount;
545 
546     do
547     {
548         // we should bypass the buffering for a large Send, but don't lose what may already be buffered
549         if ( (BytesToWrite >= iBuffSize) && (iCurrBuffSize == 0) )
550         {
551             pBuffer = pWriteBuff+(dwWriteCount-BytesToWrite);
552             dwSendSize = BytesToWrite;
553             BytesToWrite = 0;  // this is checked for at the end of the outer loop
554         }
555         else // we will buffer this data
556         {
557             // if it'll fit then just copy everything to the buffer
558             if (BytesToWrite <= DWORD(iBuffSize-iCurrBuffSize))
559             {
560                 memcpy((void*)(pSendBuffer+iCurrBuffSize),
561                     (void*)(pWriteBuff+(dwWriteCount-BytesToWrite)),BytesToWrite);
562                iCurrBuffSize += BytesToWrite;
563                BytesToWrite = 0;
564             }
565               else // copy what we can into the buffer, we'll get the rest later
566             {
567               memcpy((void*)(pSendBuffer+iCurrBuffSize),
568                 (void*)(pWriteBuff+(dwWriteCount-BytesToWrite)),
569                 iBuffSize-iCurrBuffSize);
570                 BytesToWrite -= (iBuffSize-iCurrBuffSize);
571                 iCurrBuffSize = iBuffSize;
572             }
573 
574             // if the buffer is now full (ready-to-send) or if we're at
575             // the end of the job, then send what we have in the buffer.
576             // otherwise just break (the buffer isn't ready to send)
577             if ( (EndJob == FALSE) && (iCurrBuffSize != iBuffSize) )
578             {
579                 break;  // we're not ready to send yet
580             }
581             else // send this buffered data
582             {
583                 pBuffer = pSendBuffer;
584                 dwSendSize = iCurrBuffSize;
585             }
586 		}
587 #endif
588 
589     // initialize our 'residual' to the full send size
590     residual = dwSendSize;
591 
592     if (bCheckForCancelButton &&
593         (ulBytesSentSinceCancelCheck >= CANCEL_BUTTON_CHECK_THRESHOLD) &&
594         (pSS->IOMode.bDevID))
595     {
596         ulBytesSentSinceCancelCheck = 0;
597         char* tmpStr;
598         BYTE DevIDBuffer[DevIDBuffSize];
599         DRIVER_ERROR tmpErr = pSS->GetDeviceID(DevIDBuffer, DevIDBuffSize, TRUE);
600         if(tmpErr)
601             return tmpErr;
602         BOOL cancelcheck=FALSE;
603 
604         if((tmpStr = strstr((char*)DevIDBuffer + 2,"CNCL")))
605         {
606             cancelcheck=TRUE;
607         }
608         else
609         {
610             int     iVersion = pSS->GetVIPVersion ();
611 
612             if((tmpStr = strstr((char*)DevIDBuffer + 2,";S:")) &&
613                 iVersion < 6)    // DJ990 devID style
614             {
615                 // point to PrinterState
616 /*
617  *				VIPVersion = DevID Version + 1 - DevID Version no is 2 bytes following ;S:
618  *				Version 00 and 01 report 12 bytes for status info
619  *				Version 02 and onwards, report two additional bytes before pen info
620  */
621 
622 				if (iVersion < 3)
623 				{
624 					tmpStr += 17;   // 3 for ";S:", 2 for version, 12 for features = 17
625 				}
626 				else if (iVersion < 5)
627 				{
628 					tmpStr += 19;	// 17 as above plus 1 for MaxPaperSize, 1 reserved = 19
629 				}
630                 else
631                 {
632                     tmpStr += 23;   // Crystal added 4 more nibbles
633                 }
634 
635                 BYTE b1=*tmpStr++;
636                 BYTE b2=*tmpStr++;
637                 if (((b1=='0') && (b2=='5')) && iVersion <= 5)     // 05 = cancel
638                 {
639                     cancelcheck=TRUE;
640                 }
641             }
642         }
643         if (cancelcheck)
644         {
645             // Since the printer is now just throwing data away, we can bail
646             // immediately w/o worrying about finishing the raster so the
647             // end-of-job FF will work.
648             ErrorTerminationState = TRUE;
649             pSS->DisplayPrinterStatus(DISPLAY_PRINTING_CANCELED);
650             return JOB_CANCELED;
651         }
652     }
653 
654     // If we have nothing to send, we need to bail to avoid spurious dialogs
655     //  at the end of the ::send function.  I'd prefer a solution where we don't
656     //  bail from a while loop but in practice this shouldn't have any ill effects.
657     if (residual <= 0)
658     {
659         return NO_ERROR;
660     }
661 
662     while (residual > 0)    // while still data to send in this request
663     {
664         DWORD prev_residual = residual;     // WritePort overwrites request
665                                             // count, need to save
666 
667         pWritePos = (const BYTE *) &(pBuffer[dwSendSize-residual]);
668         write_error = pSS->ToDevice(pWritePos, &residual);
669 
670         // The following error handling code is recommended, but is not supported
671         // on several current platforms for this reason:  when the printer buffer
672         // fills and declines more data, the O/S returns a BUSY error in one form
673         // or another.  The real solution is to allow the code below and have the
674         // derived pSS->ToDevice functions catch and ignore any BUSY error - only
675         // returning a real error to ::Send.  The current workaround here is that we
676         // literally ignore all errors returned from the I/O system and ultimately catch
677         // them after we've reached our slow poll limit via the slow poll logic below. -TL
678 //        if(write_error != NO_ERROR)
679 //        {
680 //            DBG1("IO_ERROR returned from ToDevice - ABORT!\n");
681 //            ErrorTerminationState = TRUE;
682 //            return write_error;
683 //        }
684 
685         write_error = NO_ERROR;
686         eDisplayStatus = DISPLAY_PRINTING;
687         if (residual == 0) // no more data to send this time
688         {
689             if (m_bStatusByPJL)
690             {
691                 status_reg = (BYTE) DISPLAY_PRINTING;
692                 if (IOMode.bStatus)
693                     eDisplayStatus = ParseError (status_reg);
694                 if (eDisplayStatus != DISPLAY_PRINTING)
695                     write_error = IO_ERROR;
696             }
697 
698             // did we want to transition out of slow poll?
699             if ( (InSlowPollMode != 0) &&
700                 (prev_residual > MIN_XFER_FOR_SLOW_POLL) )
701             {
702                 InSlowPollMode = 0;
703                 iTotal_SLOW_POLL_Count = 0;
704             }
705             if (write_error == NO_ERROR)
706                 break;  // out of while loop
707         }
708 
709 
710         // if we are here, WritePort() was not able to
711         // send the full request so start looking for errors
712 
713         // decide whether we've waited long enough to check for an error
714         if (InSlowPollMode > iMax_SLOW_POLL_Count )
715         {
716             if (JobCanceled == TRUE)
717             // Well, I/O didn't finish in time to meet the CANCEL request and avoid
718             // the SlowPoll threshold.  We have to bail for prompt cancel response.
719             {
720                 DBG1("Send(SlowPoll): Premature return w/ JOB_CANCELED\n");
721                 ErrorTerminationState = TRUE;
722                 return JOB_CANCELED;
723             }
724 
725             DBG1("Printer slow poll times exceeded\n");
726             // reset counter so we will not pop it next time
727             InSlowPollMode = 1;
728             write_error = IO_ERROR;
729         }
730         else
731         {
732             write_error = NO_ERROR;
733         }
734 
735         // are we in slow poll mode?  If so, track our count
736         if ( (prev_residual - residual) <= MIN_XFER_FOR_SLOW_POLL)
737         {
738             InSlowPollMode++;
739 
740 #if defined(DEBUG) && (DBG_MASK & DBG_LVL1)
741             if (InSlowPollMode == 1)
742             {
743                 printf("entering slow poll mode\n");
744             }
745             else
746             {
747                 printf("still in slow poll mode, count = %d\n",
748                                     InSlowPollMode);
749             }
750 #endif
751             // give the printer some time to process
752             if (pSS->BusyWait((DWORD)200) == JOB_CANCELED)
753             {
754                 DBG1("Send: JOB_CANCELED\n");
755                 JobCanceled = TRUE;
756                 pSS->DisplayPrinterStatus(DISPLAY_PRINTING_CANCELED);
757             }
758         }
759         else
760         {
761             // still busy, but taking enough data that
762             // we are not in slow poll mode
763             DBG1("Partial Send but not slow poll mode\n");
764             InSlowPollMode = 0;
765             iTotal_SLOW_POLL_Count = 0;
766         }
767 
768 
769         if (write_error != NO_ERROR || (m_bStatusByPJL && eDisplayStatus != DISPLAY_PRINTING))
770         // slow poll times exceeded
771         // the printer isn't taking data so let's see what's wrong...
772         {
773             DBG1("Parsing possible error state...\n");
774             error_displayed = TRUE;
775 
776             if (m_bStatusByPJL)
777             {
778                 status_reg = (BYTE) eDisplayStatus;
779             }
780             else
781             {
782                 // go get the status of the printer
783                 if (IOMode.bStatus)
784                 {
785                     pSS->GetStatusInfo(&status_reg);
786                 }
787 
788                 // determine the error
789                 eDisplayStatus = ParseError(status_reg);
790             }
791 
792             switch (eDisplayStatus)
793             {
794                 case DISPLAY_PRINTING_CANCELED:
795 
796                         // user canceled in an error state,
797                         // so we don't want to attempt any
798                         // further communication with the printer
799 
800                         ErrorTerminationState = TRUE;
801                         pSS->DisplayPrinterStatus(eDisplayStatus);
802                         return JOB_CANCELED;
803 
804                 case DISPLAY_ERROR_TRAP:
805                 case DISPLAY_COMM_PROBLEM:
806                         // these are unrecoverable cases
807                         // don't let any more of this job
808                         // be sent to the printer
809 
810                         ErrorTerminationState = TRUE;
811                         pSS->DisplayPrinterStatus(eDisplayStatus);
812 
813                         // wait for user to cancel the job,
814                         // otherwise they might miss the
815                         // error message
816                         while (pSS->BusyWait(500) != JOB_CANCELED)
817                         {
818                                 // nothing....
819                             ;
820                         }
821                         return IO_ERROR;
822 
823                 case DISPLAY_TOP_COVER_OPEN:
824 
825                     pSS->DisplayPrinterStatus(DISPLAY_TOP_COVER_OPEN);
826 
827                     // wait for top cover to close
828                     while ( eDisplayStatus == DISPLAY_TOP_COVER_OPEN)
829                     {
830                         if (pSS->BusyWait((DWORD)500) == JOB_CANCELED)
831                         // although we'll leave an incomplete job in the printer,
832                         // we really need to bail for proper CANCEL response.
833                         {
834                             ErrorTerminationState = TRUE;
835                             return JOB_CANCELED;
836                         }
837 
838                         if (m_bStatusByPJL)
839                         {
840                             status_reg = (BYTE) eDisplayStatus;
841                         }
842                         else
843                         {
844                             if (IOMode.bStatus)
845                             {
846                                 pSS->GetStatusInfo(&status_reg);
847                             }
848                         }
849 
850                         eDisplayStatus = ParseError(status_reg);
851                     }
852 
853                     pSS->DisplayPrinterStatus(DISPLAY_PRINTING);
854 
855                     // Wait for printer to come back online
856                     if (pSS->BusyWait((DWORD)1000) == JOB_CANCELED)
857                     // Since the top_cover error HAS been handled, we have
858                     // the opportunity to finish the raster before we hit
859                     // the next slowpoll threshold.
860                     {
861                         DBG1("Send: JOB_CANCELED\n");
862                         JobCanceled = TRUE;
863                         pSS->DisplayPrinterStatus(DISPLAY_PRINTING_CANCELED);
864                     }
865 
866                     break;
867 
868                 case DISPLAY_OUT_OF_PAPER:
869 				case DISPLAY_PHOTOTRAY_MISMATCH:
870 				{
871 					DISPLAY_STATUS	tmpStatus = eDisplayStatus;
872                     pSS->DisplayPrinterStatus(eDisplayStatus);
873 
874                     // wait for the user to add paper and
875                     // press resume
876                     while ( eDisplayStatus == tmpStatus)
877                     {
878                         if (pSS->BusyWait((DWORD)500) == JOB_CANCELED)
879                         // although we'll leave an incomplete job in the printer,
880                         // we really need to bail for proper CANCEL response.
881                         {
882                             ErrorTerminationState = TRUE;
883                             return JOB_CANCELED;
884                         }
885 
886                         if (m_bStatusByPJL)
887                         {
888                             status_reg = (BYTE) eDisplayStatus;
889                         }
890                         else
891                         {
892                             if (IOMode.bStatus)
893                             {
894                                 pSS->GetStatusInfo(&status_reg);
895                             }
896                         }
897 
898                         eDisplayStatus = ParseError(status_reg);
899                     }
900 
901                     pSS->DisplayPrinterStatus(DISPLAY_PRINTING);
902 
903                     break;
904 				}
905 
906                 case DISPLAY_BUSY:
907 
908                     if (pSS->BusyWait((DWORD)5000) == JOB_CANCELED)
909                     {
910                         ErrorTerminationState = TRUE;
911                         return JOB_CANCELED;
912                     }
913 
914                     pSS->DisplayPrinterStatus(DISPLAY_BUSY);
915 
916                     break;
917 
918                 // other cases need no special handling, display
919                 // the error and try to continue
920                 default:
921                     pSS->DisplayPrinterStatus(eDisplayStatus);
922                     break;
923             }// switch
924         } // if
925 
926         // give printer time to digest the data and check for 'cancel' before
927         // the next iteration of the loop
928         if (pSS->BusyWait((DWORD)100) == JOB_CANCELED)
929         {
930             DBG1("Send: JOB_CANCELED\n");
931             JobCanceled = TRUE;
932             pSS->DisplayPrinterStatus(DISPLAY_PRINTING_CANCELED);
933         }
934 
935     }   // while (residual > 0)
936 
937     // The above BusyWait's will not be checked if residual gets sent the first time, every time
938     // because we 'break' at that point for efficiency.  However, we want to make sure we check
939     // at least once for a CANCEL event for timely job-cancel response.
940     if (pSS->BusyWait((DWORD)0) == JOB_CANCELED)
941     {
942         JobCanceled = TRUE;
943         pSS->DisplayPrinterStatus(DISPLAY_PRINTING_CANCELED);
944     }
945 
946 #ifdef APDK_BUFFER_SEND
947     // Our buffer is now empty: reset the size so concurrent writes start at the beginning
948         iCurrBuffSize = 0;
949 
950     } while (BytesToWrite > 0);
951 #endif
952 
953     // restore my JOB_CANCELED error
954     if (JobCanceled == TRUE)
955     {
956         DBG1("Send: Clean return w/ JOB_CANCELED\n");
957         // ensure that display still says we're cancelling
958         pSS->DisplayPrinterStatus(DISPLAY_PRINTING_CANCELED);
959         return JOB_CANCELED;
960     }
961     else
962     {
963         // ensure any error message has been cleared
964         pSS->DisplayPrinterStatus(DISPLAY_PRINTING);
965         if (bCheckForCancelButton)
966         {
967             ulBytesSentSinceCancelCheck += dwWriteCount;
968         }
969         return NO_ERROR;
970     }
971 } //Send
972 
973 
TopCoverOpen(BYTE)974 BOOL Printer::TopCoverOpen
975 (
976     BYTE /*status_reg*/
977 )
978 {
979     char * pStr;
980     BYTE bDevIDBuff[DevIDBuffSize];
981 
982     if(IOMode.bDevID == FALSE)
983     {
984         return FALSE;
985     }
986 
987     DRIVER_ERROR err = pSS->GetDeviceID(bDevIDBuff, DevIDBuffSize, TRUE);
988     if (err != NO_ERROR)
989     {
990         return FALSE;
991     }
992 
993     if( (pStr=strstr((char*)bDevIDBuff+2,"VSTATUS:")) ) //  find the VSTATUS area
994     {
995         pStr+=8;
996         // now parse VSTATUS parameters
997         // looking for UP for open, DN for closed
998         if (strstr((char*)pStr,"UP"))
999         {
1000             return TRUE;
1001         }
1002         if (strstr((char*)pStr,"DN"))
1003         {
1004             return FALSE;
1005         }
1006 
1007         DBG1("didn't find UP or DN!!\n");
1008         return FALSE;
1009     }
1010     else
1011     if (( pStr = strstr ((char*) bDevIDBuff+2, ";S")))
1012     {
1013         if ( (*(pStr+5) == '9') )
1014         {
1015             return TRUE;
1016         }
1017         else
1018         {
1019             return FALSE;
1020         }
1021     }
1022     else
1023     {
1024         return FALSE;  // if we can't find VSTATUS or binary status field, assume top is not open
1025     }
1026 } //TopCoverOpen
1027 
1028 
CleanPen()1029 DRIVER_ERROR Printer::CleanPen()
1030 {
1031     DBG1("Printer::ClearPen() called\n");
1032 
1033     DWORD length=sizeof(PEN_CLEAN_PML);
1034     return pSS->ToDevice(PEN_CLEAN_PML,&length);
1035 } //CleanPen
1036 
1037 
GetMode(unsigned int index)1038 PrintMode* Printer::GetMode
1039 (
1040     unsigned int index
1041 )
1042 {
1043     if (index >= ModeCount)
1044     {
1045         return NULL;
1046     }
1047 
1048     return pMode[index];
1049 } //GetMode
1050 
1051 
PrintMode(uint32_t * map1,uint32_t * map2)1052 PrintMode::PrintMode
1053 (
1054     uint32_t *map1,
1055     uint32_t *map2
1056 )
1057 {
1058     pmQuality = QUALITY_NORMAL;
1059     pmMediaType = MEDIA_PLAIN;
1060     pmColor = COLOR;
1061     int iCount;
1062 
1063     cmap.ulMap1 = map1;
1064     cmap.ulMap2 = map2;
1065     cmap.ulMap3 = NULL;
1066 
1067     BaseResX = BaseResY = TextRes = 300;
1068     MixedRes= FALSE;
1069 
1070     // default setting
1071     for (iCount = 0; iCount < MAXCOLORPLANES; iCount++)
1072     {
1073         ResolutionX[iCount] = BaseResX;
1074         ResolutionY[iCount] = BaseResY;
1075         ColorDepth[iCount] = 1;
1076     }
1077 
1078     medium = mediaPlain;
1079     theQuality = qualityNormal;
1080     dyeCount=4;
1081 
1082     Config.bResSynth = TRUE;
1083 
1084 #if defined(APDK_VIP_COLORFILTERING)
1085     Config.bErnie = FALSE;
1086 #endif
1087 
1088     Config.bPixelReplicate = TRUE;
1089     Config.bColorImage = TRUE;
1090     Config.bCompress = TRUE;
1091     Config.eHT = FED;
1092     BlackFEDTable = GetHTBinary();
1093     ColorFEDTable = GetHTBinary();
1094 
1095 
1096     // set for most common cases
1097     bFontCapable = TRUE;
1098     CompatiblePens[0] = BOTH_PENS;
1099     for(iCount = 1; iCount < MAX_COMPATIBLE_PENS; iCount++)
1100     {
1101         CompatiblePens[iCount] = DUMMY_PEN;
1102     }
1103 
1104 #ifdef APDK_AUTODUPLEX
1105     bDuplexCapable = FALSE;
1106     DuplexMode = DUPLEXMODE_NONE;
1107 #endif
1108 
1109 } //PrintMode
1110 
1111 
GrayMode(uint32_t * map)1112 GrayMode::GrayMode
1113 (
1114     uint32_t *map
1115 ) :
1116     PrintMode(map)
1117 // grayscale uses econo, 300, 1 bit
1118 {
1119     ColorDepth[K] = 1;
1120     dyeCount = 1;
1121     CompatiblePens[1] = BLACK_PEN;  // accept either black or both
1122     pmColor = GREY_K;
1123 } //GrayMode
1124 
1125 
CMYGrayMode(uint32_t * map)1126 CMYGrayMode::CMYGrayMode
1127 (
1128     uint32_t *map
1129 ) :
1130     GrayMode(map)
1131 {
1132     CompatiblePens[1] = COLOR_PEN;  // accept either color or both
1133     dyeCount = 3;
1134     pmColor = GREY_CMY;
1135 } //CMYGrayMode
1136 
1137 
KCMYGrayMode(uint32_t * map)1138 KCMYGrayMode::KCMYGrayMode
1139 (
1140     uint32_t *map
1141 ) :
1142     GrayMode(map)
1143 {
1144     dyeCount = 4;
1145     pmColor = GREY_CMY;
1146 } //KCMYGrayMode
1147 
1148 
SetPenInfo(char * & pStr,BOOL QueryPrinter)1149 DRIVER_ERROR Printer::SetPenInfo
1150 (
1151     char*& pStr,
1152     BOOL QueryPrinter
1153 )
1154 {
1155     DRIVER_ERROR err;
1156 
1157     if (QueryPrinter)
1158     {
1159         // read the DevID into the stored strDevID
1160         err = pSS->GetDeviceID(pSS->strDevID, DevIDBuffSize, TRUE);
1161         ERRCHECK;
1162 
1163         // update the static values of the pens
1164         err = pSS->DR->ParseDevIDString((const char*)(pSS->strDevID),pSS->strModel,&(pSS->VIPVersion),pSS->strPens);
1165         ERRCHECK;
1166 
1167         if ((pStr = strstr((char*)pSS->strDevID,"VSTATUS:")))   //  find the VSTATUS area
1168         {
1169             pStr += 8;
1170         }
1171         else if ((pStr = strstr((char*)pSS->strDevID, ";S:00")))  // binary encoded device ID status (version 0)
1172         {
1173             pStr += 19;     // get to the number of pens field - 12 byte feature field
1174         }
1175         else if ((pStr = strstr ((char *) pSS->strDevID, ";S:01")))
1176         {
1177             pStr += 19;     // same as version 00
1178         }
1179         else if ((pStr = strstr((char*)pSS->strDevID, ";S:02")))  // binary encoded device ID status (version 2)
1180         {
1181 //            pStr += 21;     // get to the number of pens field - 14 byte feature field
1182             pStr += 19;     // same as version 00 - see registry.cpp
1183         }
1184         else if ((pStr = strstr((char*)pSS->strDevID, ";S:03")))  // binary encoded device ID status (version 3)
1185         {
1186             pStr += 21;     // get to the number of pens field - 14 byte feature field
1187         }
1188         else if ((pStr = strstr((char*)pSS->strDevID, ";S:04")))  // binary encoded device ID status (version 3)
1189         {
1190             pStr += 25;     // get to the number of pens field - 18 byte feature field
1191         }
1192         else if ((pSS->GetVIPVersion ()) > 5)
1193         {
1194             return NO_ERROR;
1195         }
1196         else
1197         {
1198             TRACE("Printer::SetPenInfo - Unsupported DeviceID %s.\n", pSS->strDevID);
1199 /*            ASSERT (0);  // you must have a printer with a new version that is not supported yet! */
1200             return BAD_DEVICE_ID;  // - code should never reach this point
1201         }
1202     }
1203     else
1204     {
1205         pStr = pSS->strPens;
1206     }
1207     return NO_ERROR;
1208 } //SetPenInfo
1209 
1210 
Compatible(PEN_TYPE pens)1211 BOOL PrintMode::Compatible
1212 (
1213     PEN_TYPE pens
1214 )
1215 {
1216     BOOL res = FALSE;
1217     for (int i=0; i < MAX_COMPATIBLE_PENS; i++)
1218     {
1219         if (CompatiblePens[i] == pens)
1220         {
1221             res = TRUE;
1222         }
1223     }
1224     return res;
1225 } //Compatible
1226 
1227 
1228 
SetPens(PEN_TYPE eNewPen)1229 DRIVER_ERROR Printer::SetPens
1230 (
1231     PEN_TYPE eNewPen
1232 )
1233 {
1234     ASSERT(eNewPen <= MAX_PEN_TYPE);
1235     // We are (probably)in unidi.  We have to trust they know what pens are
1236     // in the printer.  We'll let them set any pen set (even if this printer
1237     // doesn't support it.  We'll find out during SelectPrintMode
1238     if (eNewPen <= MAX_PEN_TYPE)
1239     {
1240         ePen = eNewPen;
1241         return NO_ERROR;
1242     }
1243     else
1244     {
1245         return UNSUPPORTED_PEN;
1246     }
1247 } //SetPens
1248 
GetValues(QUALITY_MODE & eQuality,MEDIATYPE & eMedia,COLORMODE & eColor,BOOL & bDeviceText)1249 void PrintMode::GetValues
1250 (
1251     QUALITY_MODE& eQuality,
1252     MEDIATYPE& eMedia,
1253     COLORMODE& eColor,
1254     BOOL& bDeviceText
1255 )
1256 {
1257     if (&eQuality != NULL)
1258     {
1259         eQuality = pmQuality;
1260     }
1261 
1262     if (&eMedia != NULL)
1263     {
1264         eMedia = pmMediaType;
1265     }
1266 
1267     if (&eColor != NULL)
1268     {
1269         eColor = pmColor;
1270     }
1271 
1272     if (&bDeviceText != NULL)
1273     {
1274         bDeviceText = bFontCapable;
1275     }
1276 } //GetValues
1277 
1278 
SetPMIndices()1279 void Printer::SetPMIndices()
1280 {
1281     for (unsigned int i=0; i < ModeCount; i++)
1282     {
1283         pMode[i]->myIndex = i;
1284     }
1285 } //SetPMIndices
1286 
1287 APDK_END_NAMESPACE
1288 
1289 
1290