1 /*
2  * Generate PPM files from printer output
3  *
4  * Copyright 2000-2001 Eric Sharkey <sharkey@superk.physics.sunysb.edu>
5  *                     Andy Thaller <thaller@ph.tum.de>
6  *                     Robert Krawitz <rlk@alum.mit.edu>
7  *
8  *   This program is free software; you can redistribute it and/or modify it
9  *   under the terms of the GNU General Public License as published by the Free
10  *   Software Foundation; either version 2 of the License, or (at your option)
11  *   any later version.
12  *
13  *   This program is distributed in the hope that it will be useful, but
14  *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15  *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16  *   for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <gutenprint/util.h>
26 #include<stdio.h>
27 #include<stdlib.h>
28 #ifdef HAVE_LIMITS_H
29 #include<limits.h>
30 #endif
31 #include<string.h>
32 
33 #ifdef __GNUC__
34 #define inline __inline__
35 #endif
36 
37 typedef enum {
38   QT_NONE,
39   QT_QUAD,
40   QT_MIS
41 } quadtone_t;
42 
43 /*
44  * Printer state variable.
45  */
46 typedef struct {
47   unsigned char unidirectional;
48   unsigned char printer_weave;
49   int page_management_units; /* dpi */
50   int relative_horizontal_units; /* dpi */
51   int absolute_horizontal_units; /* dpi, assumed to be >= relative */
52   int relative_vertical_units; /* dpi */
53   int absolute_vertical_units; /* dpi, assumed to be >= relative */
54   int horizontal_spacing;	/* Horizontal dot spacing */
55   int top_margin; /* dots */
56   int bottom_margin; /* dots */
57   int page_height; /* dots */
58   int dotsize;
59   int bpp; /* bits per pixel */
60   int current_color;
61   int xposition; /* dots */
62   int yposition; /* dots */
63   int monomode;
64   int nozzle_separation;
65   int nozzles;
66   int extraskip;
67   int got_graphics;
68   int left_edge;
69   int right_edge;
70   int top_edge;
71   int bottom_edge;
72   quadtone_t quadtone;
73 } pstate_t;
74 
75 /* We'd need about a gigabyte of ram to hold a ppm file of an 8.5 x 11
76  * 1440 x 720 dpi page.  That's more than I have in my laptop, so, let's
77  * play some games to reduce memory.  Allocate each scan line separately,
78  * and don't require that the allocated height be full page width.  This
79  * way, if we only want to print a 2x2 image, we only need to allocate the
80  * ram that we need.  We'll build up the printed image in ram at low
81  * color depth, KCMYcm color basis, and then write out the RGB ppm file
82  * as output.  This way we never need to have the full data in RAM at any
83  * time.  2 bits per color of KCMYcm is half the size of 8 bits per color
84  * of RGB.
85  *
86  * We would like to be able to print in bands, so that we don't have to
87  * read the entire page into memory in order to print it.  Unfortunately,
88  * we may not know what the left and right margins are until we've read the
89  * entire file.  If we can read it in two passes we could do it; use one
90  * pass to scan the file looking at the margins, and another pass to
91  * actually read in the data.  This optimization may be worthwhile.
92  */
93 
94 #define MAX_INKS 20
95 typedef struct {
96    unsigned char *line[MAX_INKS];
97    int startx[MAX_INKS];
98    int stopx[MAX_INKS];
99 } line_type;
100 
101 typedef unsigned char ppmpixel[3];
102 
103 unsigned char *buf;
104 unsigned valid_bufsize;
105 unsigned char minibuf[256];
106 unsigned bufsize;
107 unsigned save_bufsize;
108 unsigned char ch;
109 unsigned short sh;
110 int eject = 0;
111 int global_counter = 0;
112 int global_count = 0;
113 unsigned color_mask = 0xffffffff;
114 
115 pstate_t pstate;
116 int unweave;
117 
118 line_type **page=NULL;
119 
120 /* Color Codes:
121    color    Epson1  Epson2   Sequential
122    Black    0       0        0/16
123    Magenta  1       1        1/17
124    Cyan     2       2        2/18
125    Yellow   4       4        3/19
126    L.Mag.   17      257      4
127    L.Cyan   18      258      5
128    L.Black  16      256      6
129    D.Yellow 36      516      7
130    Red      7       N/A      8
131    Blue     8       N/A      9
132    P.Black  64      N/A      0
133    Gloss    9       N/A      10
134    LL.Black 48      768      11
135    Orange   10       N/A     12
136  */
137 
138 /* convert either Epson1 or Epson2 color encoding into a sequential encoding */
139 static int
seqcolor(int c)140 seqcolor(int c)
141 {
142   switch (c)
143     {
144     case 0:
145       return 0;
146     case 1:
147       return 1;
148     case 2:
149       return 2;
150     case 4:
151       return 3;
152     case 17:
153     case 257:
154       return 4;
155     case 18:
156     case 258:
157       return 5;
158     case 16:
159     case 256:
160       return 6;
161     case 36:
162     case 516:
163       return 7;
164     case 7:
165       return 8;
166     case 8:
167       return 9;
168     case 9:
169       return 10;
170     case 48:
171     case 768:
172       return 11;
173     case 10:
174       return 12;
175     case 64:
176       return 16;
177     case 65:
178       return 17;
179     case 66:
180       return 18;
181     case 68:
182       return 19;
183     default:
184       return 0;
185     }
186 }
187 
188 extern void merge_line(line_type *p, unsigned char *l, int startl, int stopl,
189 		       int color);
190 extern void expand_line (unsigned char *src, unsigned char *dst, int height,
191 			 int skip, int left_ignore);
192 extern void write_output (FILE *fp_w, int dontwrite, int allblack);
193 extern void find_white (unsigned char *buff,int npix, int *left, int *right);
194 extern int update_page (unsigned char *buff, int buffsize, int m, int n,
195 			int color, int density);
196 extern void parse_escp2 (FILE *fp_r);
197 extern void reverse_bit_order (unsigned char *buff, int n);
198 extern int rle_decode (unsigned char *inbuf, int n, int max);
199 extern void parse_canon (FILE *fp_r);
200 
201 unsigned get_mask_1[] = { 7, 6, 5, 4, 3, 2, 1, 0 };
202 unsigned get_mask_2[] = { 6, 4, 2, 0 };
203 unsigned get_mask_4[] = { 4, 0 };
204 
205 static inline int
get_bits(unsigned char * p,int idx)206 get_bits(unsigned char *p, int idx)
207 {
208   /*
209    * p is a pointer to a bit stream, ordered MSb first.  Extract the
210    * indexth bpp bit width field and return that value.  Ignore byte
211    * boundaries.
212    */
213   int value, b;
214   unsigned addr;
215   switch (pstate.bpp)
216     {
217     case 1:
218       return (p[idx >> 3] >> (7 - (idx & 7))) & 1;
219     case 2:
220       b = get_mask_2[idx & 3];
221       return (p[idx >> 2] >> b) & 3;
222     case 4:
223       b = get_mask_4[idx & 1];
224       return (p[idx >> 1] >> b) & 0xf;
225     case 8:
226       return p[idx];
227     default:
228       addr = (idx * pstate.bpp);
229       value = 0;
230       for (b = 0; b < pstate.bpp; b++)
231 	{
232 	  value += value;
233 	  value |= (p[(addr + b) >> 3] >> (7 - ((addr + b) & 7))) & 1;
234 	}
235       return(value);
236     }
237 }
238 
239 static unsigned clr_mask_1[] = { 0xfe, 0xfd, 0xfb, 0xf7,
240 				 0xef, 0xdf, 0xbf, 0x7f };
241 static unsigned clr_mask_2[] = { 0xfc, 0, 0xf3, 0, 0xcf, 0, 0x3f, 0 };
242 static unsigned clr_mask_4[] = { 0xf0, 0, 0, 0, 0xf, 0, 0, 0 };
243 
244 static inline void
set_bits(unsigned char * p,int idx,int value)245 set_bits(unsigned char *p,int idx,int value)
246 {
247 
248   /*
249    * p is a pointer to a bit stream, ordered MSb first.  Set the
250    * indexth bpp bit width field to value value.  Ignore byte
251    * boundaries.
252    */
253 
254   int b;
255   switch (pstate.bpp)
256     {
257     case 1:
258       b = (7 - (idx & 7));
259       p[idx >> 3] &= clr_mask_1[b];
260       p[idx >> 3] |= value << b;
261       break;
262     case 2:
263       b = get_mask_2[idx & 3];
264       p[idx >> 2] &= clr_mask_2[b];
265       p[idx >> 2] |= value << b;
266       break;
267     case 4:
268       b = get_mask_4[idx & 1];
269       p[idx >> 1] &= clr_mask_4[b];
270       p[idx >> 1] |= value << b;
271       break;
272     case 8:
273       p[idx] = value;
274       break;
275     default:
276       for (b = pstate.bpp - 1; b >= 0; b--)
277 	{
278 	  if (value & 1)
279 	    p[(idx * pstate.bpp + b) / 8] |=
280 	      1 << (7 - ((idx * pstate.bpp + b) % 8));
281 	  else
282 	    p[(idx * pstate.bpp + b) / 8] &=
283 	      ~(1 << (7 - ((idx * pstate.bpp + b) % 8)));
284 	  value/=2;
285 	}
286     }
287 }
288 
289 static float ink_colors[MAX_INKS][4] =
290 /* C(R) M(G) Y(B) K(W) */
291 {{ 0,   0,   0,   1 },		/* 0  K */
292  { 1,    .1, 1,   1 },		/* 1  M */
293  {  .1, 1,   1,   1 },		/* 2  C */
294  { 1,   1,    .1, 1 },		/* 3  Y */
295  { 1,    .7, 1,   1 },		/* 4  m */
296  {  .7, 1,   1,   1 },		/* 5  c */
297  {  .7,  .7,  .7, 1 },		/* 6  k */
298  {  .7,  .7, 0,   1 },		/* 7  dY */
299  { 1,   0,   0,   1 },		/* 8  R */
300  { 0,   0,   1,   1 },		/* 8  B */
301  { 1,   1,   1,   1 },		/* 10 Gloss */
302  {  .8,  .8,  .8, 1 },		/* 11 llk */
303  {  .9,  .3, 0,   1 },		/* 12 Orange */
304  { 0,   0,   0,   1 },		/* 13 K */
305  { 0,   0,   0,   1 },		/* 14 K */
306  { 0,   0,   0,   1 },		/* 15 K */
307  { 0,   0,   0,   1 },		/* 16 K */
308  { 1,    .1, 1,   1 },		/* 17 M */
309  {  .1, 1,   1,   1 },		/* 18 C */
310  { 1,   1,    .1, 1 },		/* 19 Y */
311 };
312 
313 static float quadtone_inks[] = { 0.0, .5, .25, .75, .9, .8 };
314 
315 static float mis_quadtone_inks[] = { 0.0, .25, .75, .5, .55, .85 };
316 
317 static float bpp_shift[] = { 0, 1, 3, 7, 15, 31, 63, 127, 255 };
318 
319 static inline void
mix_ink(ppmpixel p,int color,unsigned int amount,float * ink,quadtone_t quadtone)320 mix_ink(ppmpixel p, int color, unsigned int amount, float *ink, quadtone_t quadtone)
321 {
322   /* this is pretty crude */
323 
324   if (((1 << color) & color_mask) && amount)
325     {
326       int i;
327       float size;
328 
329       size = (float) amount / bpp_shift[pstate.bpp];
330       switch (quadtone)
331 	{
332 	case QT_QUAD:
333 	  for (i = 0; i < 3; i++)
334 	    p[i] *= (1 - size) + size * quadtone_inks[color];
335 	  break;
336 	case QT_MIS:
337 	  for (i = 0; i < 3; i++)
338 	    p[i] *= (1 - size) + size * mis_quadtone_inks[color];
339 	  break;
340 	default:
341 	  for (i = 0; i < 3; i++)
342 	    p[i] *= (1 - size) + size * ink[i];
343 	}
344     }
345 }
346 
347 void
merge_line(line_type * p,unsigned char * l,int startl,int stopl,int color)348 merge_line(line_type *p, unsigned char *l, int startl, int stopl, int color)
349 {
350 
351   int i;
352   int temp, shift, height, lvalue, pvalue, oldstop;
353   int width, owidth;
354   unsigned char *tempp;
355   int reversed = 0;
356   int need_realloc = 0;
357 
358   /*
359    * If we have a pixel to the left of anything previously printed,
360    * we need to expand our margins to the left.  This is a bit tricky...
361    */
362   if (startl < p->startx[color])
363     {
364       temp = p->startx[color];
365       p->startx[color] = startl;
366       startl = temp;
367 
368       temp = p->stopx[color];
369       p->stopx[color] = stopl;
370       stopl = temp;
371 
372       tempp = p->line[color];
373       p->line[color] = l;
374       l = tempp;
375       reversed = 1;
376     }
377   shift = startl - p->startx[color];
378   height = stopl - startl + 1;
379 
380   oldstop = p->stopx[color];
381   if (stopl > p->stopx[color])
382     {
383       p->stopx[color] = stopl;
384       need_realloc = 1;
385     }
386   if (need_realloc || reversed)
387     {
388       width = ((p->stopx[color] - p->startx[color] + 1) * pstate.bpp + 7) / 8;
389       owidth = ((oldstop - p->startx[color] + 1) * pstate.bpp + 7) / 8;
390       p->line[color] = stp_realloc(p->line[color], width);
391       memset((p->line[color] + owidth), 0, (width - owidth));
392     }
393   /*
394    * Can we do an empty line optimization?
395    */
396   for (i = 0; i < height; i++)
397     {
398       lvalue = get_bits(l, i);
399       if (lvalue)
400 	{
401 	  pvalue = get_bits(p->line[color], i + shift);
402 	  pvalue += lvalue;
403 	  if (pvalue > (1 << pstate.bpp) - 1)
404 	    pvalue = (1 << pstate.bpp) - 1;
405 	  set_bits(p->line[color], i + shift, pvalue);
406 	}
407     }
408   stp_free(l);
409 }
410 
411 void
expand_line(unsigned char * src,unsigned char * dst,int height,int skip,int left_ignore)412 expand_line (unsigned char *src, unsigned char *dst, int height, int skip,
413 	     int left_ignore)
414 {
415 
416   /*
417    * src is a pointer to a bit stream which is composed of fields of height
418    * bpp starting with the most significant bit of the first byte and
419    * proceeding from there with no regard to byte boundaries.  For the
420    * existing Epson printers, bpp is 1 or 2, which means fields will never
421    * cross byte boundaries.  However, if bpp were 3, this would undoubtedly
422    * happen.  This routine will make no assumptions about bpp, and handle each
423    * bit individually.  It's slow, but, it's the only way that will work in
424    * the general case of arbitrary bpp.
425    *
426    * We want to copy each field from the src to the dst, spacing the fields
427    * out every skip fields.  We should ignore the first left_ignore fields
428    * pointed to by src, though.
429    */
430 
431   int i;
432 
433   if ((skip == 1) && !(left_ignore * pstate.bpp % 8))
434     {
435       /* the trivial case, this should be faster */
436       memcpy(dst, src + left_ignore * pstate.bpp / 8,
437 	     (height * pstate.bpp + 7) / 8);
438     }
439   else
440     {
441       for (i = 0; i < height; i++)
442 	set_bits(dst, i * skip, get_bits(src, i + left_ignore));
443     }
444 }
445 
446 int donothing;
447 
448 void
write_output(FILE * fp_w,int dontwrite,int allblack)449 write_output(FILE *fp_w, int dontwrite, int allblack)
450 {
451   int c, l, p, left, right, first, last, width, height, i;
452   unsigned int amount;
453   ppmpixel *out_row;
454   int oversample = pstate.absolute_horizontal_units /
455     pstate.absolute_vertical_units;
456   if (oversample == 0)
457     oversample = 1;
458 
459   fprintf(stderr, "Margins: top: %d bottom: top+%d\n", pstate.top_margin,
460           pstate.bottom_margin);
461 
462   first = pstate.top_edge;
463   last = pstate.bottom_edge;
464   left = pstate.left_edge;
465   right = pstate.right_edge;
466   height = oversample * (last - first + 1);
467 
468   fprintf(stderr, "Image from (%d,%d) (%.3fx%.3f) to (%d,%d) (%.3fx%.3f) size (%dx%d) (%.3fx%.3f)\n",
469 	  left, first - pstate.top_margin,
470 	  (left / (double) pstate.page_management_units),
471 	  (first / (double) pstate.page_management_units),
472 	  right, last - pstate.top_margin,
473 	  (right / (double) pstate.page_management_units),
474 	  (last / (double) pstate.page_management_units),
475 	  right - left + 1, last - first + 1,
476 	  (right - left + 1) / (double) pstate.page_management_units,
477 	  (last - first + 1) / (double) pstate.page_management_units);
478 
479   width = right - left + 1;
480   if (width < 0)
481     width=0;
482 
483   out_row = stp_malloc(sizeof(ppmpixel) * width);
484   fprintf(stderr, "Writing output...\n");
485 
486   if (dontwrite)
487     return;
488   /* write out the PPM header */
489   fprintf(fp_w, "P6\n");
490   fprintf(fp_w, "%d %d\n", width, height);
491   fprintf(fp_w, "255\n");
492   for (l = first; l <= last; l++)
493     {
494       line_type *lt = page[l];
495       memset(out_row, ~0, (sizeof(ppmpixel) * width));
496       if (lt)
497 	{
498 	  for (c = 0; c < MAX_INKS; c++)
499 	    {
500 	      int inknum = allblack ? 0 : c;
501 	      float *ink = ink_colors[inknum];
502 	      if (lt->line[c])
503 		{
504 		  for (p = lt->startx[c]; p <= lt->stopx[c]; p++)
505 		    {
506 		      amount = get_bits(lt->line[c], p - lt->startx[c]);
507 		      mix_ink(out_row[p - left], c, amount, ink,
508 			      pstate.quadtone);
509 		    }
510 		}
511 	    }
512 	}
513       for (i = 0; i < oversample; i++)
514 	fwrite(out_row, sizeof(ppmpixel), width, fp_w);
515     }
516   stp_free(out_row);
517 }
518 
519 void
find_white(unsigned char * buff,int npix,int * left,int * right)520 find_white(unsigned char *buff,int npix, int *left, int *right)
521 {
522 
523   /*
524    * If a line has white borders on either side, count the number of
525    * pixels and fill that info into left and right.
526    */
527 
528   int i, j, max;
529   int words, bytes, bits, extra;
530 
531   *left = *right = 0;
532   bits = npix * pstate.bpp;
533   bytes = bits / 8;
534   extra = bits % 8;
535   words = bytes / sizeof(int);
536 
537   /*
538    * First, find the leftmost pixel.  We first identify the word
539    * containing the byte, then the byte, and finally the pixel within
540    * the byte.  It does seem like this is unnecessarily complex, perhaps?
541    */
542   max = words;
543   for (i = 0; (i < max) && (((int *)buff)[i] == 0); i++)
544     ;
545   max = (i < words) ? (i + 1) * sizeof(int) : bytes;
546 
547   i *= sizeof(int);		/* Convert from ints to bytes */
548   for (; (i < max) && (buff[i] == 0); i++)
549     ;
550   max = (i < bytes) ? 8 : extra;
551   for (j = 0; (j < max) && !(buff[i] & (1 << (7 - j))); j++)
552     ;
553   *left = (i * 8 + j) / pstate.bpp;
554   *right = 0;
555 
556   /* if left is everything, then right is nothing */
557   if (*left == npix)
558     return;
559 
560   /* right side, this is a little trickier */
561   for (i = 0; (i < extra) && !(buff[bytes] & (1 << (i + 8 - extra))); i++)
562     ;
563   if (i < extra)
564     {
565       *right = i / pstate.bpp;
566       return;
567     }
568   *right = extra;  /*temporarily store right in bits to avoid rounding error*/
569 
570   for (i = 0; (i < bytes % sizeof(int)) && !(buff[bytes - 1 - i]); i++)
571     ;
572   if (i < bytes % sizeof(int))
573     {
574       for (j = 0; (j < 8) && !(buff[bytes - 1 - i] & (1 << j)); j++)
575 	;
576       *right = (*right + i * 8 + j) / pstate.bpp;
577       return;
578     }
579   *right += i * 8;
580 
581   for (i = 0; (i < words) && !(((int *)buff)[words - 1 - i]); i++)
582     ;
583 
584   if (i < words)
585     {
586       *right += i * sizeof(int) * 8;
587       for (j = 0;
588 	   (j < sizeof(int)) && !(buff[(words - i) * sizeof(int) - 1 - j]);
589 	   j++)
590 	;
591       if (j < sizeof(int))
592 	{
593 	  *right += j * 8;
594 	  max = (words - i) * sizeof(int) - 1 - j;
595 	  for (j = 0; (j < 8) && !(buff[max] & (1 << j)); j++)
596 	    ;
597 	  if (j < 8)
598 	    {
599 	      *right = (*right + j) / pstate.bpp;
600 	      return;
601 	    }
602 	}
603     }
604   fprintf(stderr, "Warning: Reality failure.  The impossible happened.\n");
605 }
606 
607 int
update_page(unsigned char * buff,int buffsize,int m,int n,int color,int density)608 update_page(unsigned char *buff, /* I - pixel data               */
609 	    int buffsize,        /* I - size of buff in bytes     */
610 	    int m,              /* I - height of area in pixels */
611 	    int n,              /* I - width of area in pixels  */
612 	    int color,          /* I - color of pixel data      */
613 	    int density         /* I - horizontal density in dpi  */
614 	    )
615 {
616   int y, skip, oldstart, oldstop, mi = 0;
617   int left_white, right_white, width;
618   unsigned char *oldline;
619   int sep;
620 
621   if ((n == 0) || (m == 0))
622     return(0);  /* shouldn't happen */
623 
624   skip = pstate.relative_horizontal_units / density;
625   skip *= pstate.extraskip;
626 
627   if (skip == 0)
628     {
629       fprintf(stderr, "Warning!  Attempting to print at %d DPI but units are "
630 	      "set to %d DPI.\n", density, pstate.relative_horizontal_units);
631       return(0);
632     }
633 
634   if (!page)
635     {
636       fprintf(stderr,
637 	      "Warning! Attempting to print before setting up page!\n");
638       /*
639        * Let's hope that we've at least initialized the printer with
640        * with an ESC @ and allocate the default page.  Otherwise, we'll
641        * have unpredictable results.  But, that's a pretty acurate statement
642        * for a real printer, too!
643        */
644       page = (line_type **)
645 	stp_zalloc((pstate.bottom_margin - pstate.top_margin) *
646 		   sizeof(line_type *));
647     }
648   if (pstate.printer_weave)
649     sep = 1;
650   else
651     sep = pstate.nozzle_separation;
652   for (y=pstate.yposition; y < pstate.yposition + m * sep; y += sep, mi++)
653     {
654       if (y >= pstate.bottom_margin - pstate.top_margin)
655 	{
656 	  fprintf(stderr,
657 		  "Warning: Unprinter out of unpaper (limit %d, pos %d).\n",
658 		  pstate.bottom_margin, y);
659 	  return(1);
660 	}
661       find_white(buff + mi * ((n * pstate.bpp + 7) / 8), n,
662 		 &left_white, &right_white);
663       if (left_white == n)
664 	continue; /* ignore blank lines */
665       if (!(page[y]))
666 	{
667 	  page[y] = (line_type *) stp_zalloc(sizeof(line_type));
668 	  if (y < pstate.top_edge)
669 	    pstate.top_edge = y;
670 	  if (y > pstate.bottom_edge)
671 	    pstate.bottom_edge = y;
672 	}
673       if ((left_white * pstate.bpp < 8) && (skip == 1))
674 	{
675 	  left_white=0; /* if it's just a few bits, don't bother cropping */
676 	}               /* unless we need to expand the line anyway       */
677       if (page[y]->line[color])
678 	{
679 	  oldline = page[y]->line[color];
680 	  oldstart = page[y]->startx[color];
681 	  oldstop = page[y]->stopx[color];
682 	}
683       else
684 	{
685 	  oldline = NULL;
686 	  oldstart = -1;
687 	  oldstop = -1;
688 	}
689       page[y]->startx[color] = pstate.xposition + left_white * skip;
690       page[y]->stopx[color] =pstate.xposition + ((n - 1 - right_white) * skip);
691       if (page[y]->startx[color] < pstate.left_edge)
692 	pstate.left_edge = page[y]->startx[color];
693       if (page[y]->stopx[color] > pstate.right_edge)
694 	pstate.right_edge = page[y]->stopx[color];
695       width = page[y]->stopx[color] - page[y]->startx[color];
696       page[y]->line[color] =
697 	stp_zalloc(((width * skip + 1) * pstate.bpp + 7) / 8);
698       expand_line(buff + mi * ((n * pstate.bpp + 7) / 8), page[y]->line[color],
699 		  width+1, skip, left_white);
700       if (oldline)
701 	merge_line(page[y], oldline, oldstart, oldstop, color);
702     }
703   if (n)
704     pstate.xposition += (n - 1) * skip + 1;
705   return(0);
706 }
707 
708 #define get1(error)							\
709 do									\
710 {									\
711   if (!(global_count = fread(&ch, 1, 1, fp_r)))				\
712     {									\
713       fprintf(stderr, "%s at %d (%x), read %d",				\
714 	      error, global_counter, global_counter, global_count);	\
715       eject = 1;							\
716       continue;								\
717     }									\
718   else									\
719     global_counter += global_count;					\
720 } while (0)
721 
722 #define get2(error)							\
723 do									\
724 {									\
725   if (!(global_count = fread(minibuf, 1, 2, fp_r)))			\
726     {									\
727       fprintf(stderr, "%s at %d (%x), read %d",				\
728 	      error, global_counter, global_counter, global_count);	\
729       eject = 1;							\
730       continue;								\
731     }									\
732   else									\
733     {									\
734       global_counter += global_count;					\
735       sh = minibuf[0] + minibuf[1] * 256;				\
736     }									\
737 } while (0)
738 
739 #define getn(n,error)							\
740 do									\
741 {									\
742   if (!(global_count = fread(buf, 1, n, fp_r)))				\
743     {									\
744       fprintf(stderr, "%s at %d (%x), read %d",				\
745 	      error, global_counter, global_counter, global_count);	\
746       eject = 1;							\
747       continue;								\
748     }									\
749   else									\
750     global_counter += global_count;					\
751 } while (0)
752 
753 #define getnoff(n,offset,error)						\
754 do									\
755 {									\
756   if (!(global_count = fread(buf + offset, 1, n, fp_r)))		\
757     {									\
758       fprintf(stderr, "%s at %d (%x), read %d",				\
759 	      error, global_counter, global_counter, global_count);	\
760       eject = 1;							\
761       continue;								\
762     }									\
763   else									\
764     global_counter += global_count;					\
765 } while (0)
766 
767 static void
parse_escp2_data(FILE * fp_r)768 parse_escp2_data(FILE *fp_r)
769 {
770   int i, m = 0, n = 0, c = 0;
771   int currentcolor = 0;
772   int density = 0;
773   int bandsize;
774   switch (ch)
775     {
776     case 'i':
777       get1("Error reading color.\n");
778       currentcolor = seqcolor(ch);
779       get1("Error reading compression mode!\n");
780       c = ch;
781       get1("Error reading bpp!\n");
782       if (ch != pstate.bpp)
783 	{
784 	  fprintf(stderr, "Warning! Color depth altered by ESC i.\n");
785 	  pstate.bpp=ch;
786 	}
787       if (pstate.bpp > 2)
788 	fprintf(stderr, "Warning! Excessively deep color detected.\n");
789       if (pstate.bpp == 0)
790 	fprintf(stderr, "Warning! Zero bit pixel depth detected.\n");
791       get2("Error reading number of horizontal dots!\n");
792       n = (unsigned) sh * 8 / pstate.bpp;
793       get2("Error reading number of vertical dots!\n");
794       m = (unsigned) sh;
795       density = pstate.horizontal_spacing;
796       break;
797     case '.':
798       get1("Error reading compression mode!\n");
799       c=ch;
800       if (c > 2)
801 	{
802 	  fprintf(stderr,"Warning!  Unknown compression mode.\n");
803 	  break;
804 	}
805       get1("Error reading vertical density!\n");
806       /* What should we do with the vertical density here??? */
807       get1("Error reading horizontal density!\n");
808       density=3600/ch;
809       get1("Error reading number of vertical dots!\n");
810       m=ch;
811       get2("Error reading number of horizontal dots!\n");
812       n=sh;
813       currentcolor=pstate.current_color;
814       break;
815     }
816   bandsize = m * ((n * pstate.bpp + 7) / 8);
817   if (valid_bufsize < bandsize)
818     {
819       buf = stp_realloc(buf, bandsize);
820       valid_bufsize = bandsize;
821     }
822   switch (c)
823     {
824     case 0:  /* uncompressed */
825       bufsize = bandsize;
826       getn(bufsize,"Error reading raster data!\n");
827       update_page(buf, bufsize, m, n, currentcolor, density);
828       break;
829     case 1:  /* run length encoding */
830       i = 0;
831       while (!eject && (i < bandsize))
832 	{
833 	  get1("Error reading global_counter!\n");
834 	  if (ch < 128)
835 	    {
836 	      bufsize = ch + 1;
837 	      getnoff(bufsize, i, "Error reading RLE raster data!\n");
838 	    }
839 	  else
840 	    {
841 	      bufsize = 257 - (unsigned int) ch;
842 	      get1("Error reading compressed RLE raster data!\n");
843 	      memset(buf + i, ch, bufsize);
844 	    }
845 	  i += bufsize;
846 	}
847       if (i != bandsize)
848 	{
849 	  fprintf(stderr, "Error decoding RLE data.\n");
850 	  fprintf(stderr, "Total bufsize %d, expected %d\n",
851 		  i, bandsize);
852 	  eject = 1;
853 	}
854       else
855 	update_page(buf, i, m, n, currentcolor, density);
856       break;
857     case 2: /* TIFF compression */
858       fprintf(stderr, "TIFF mode not yet supported!\n");
859       /* FIXME: write TIFF stuff */
860       break;
861     default: /* unknown */
862       fprintf(stderr, "Unknown compression mode %d.\n", c);
863       break;
864     }
865 }
866 
867 static void
parse_escp2_extended(FILE * fp_r)868 parse_escp2_extended(FILE *fp_r)
869 {
870   int unit_base;
871   int i;
872 
873   get1("Corrupt file.  Incomplete extended command.\n");
874   if (eject)
875     return;
876   get2("Corrupt file.  Error reading buffer size.\n");
877   bufsize = sh;
878   getn(bufsize, "Corrupt file.  Error reading command payload.\n");
879   /* fprintf(stderr,"Command %X bufsize %d.\n",ch,bufsize); */
880   switch (ch)
881     {
882     case 'R':
883       if (bufsize == 8 && memcmp(buf, "\0REMOTE1", 8) == 0)
884 	{
885 	  int rc1 = 0, rc2 = 0;
886 	  /* Remote mode 1 */
887 	  do
888 	    {
889 	      get1("Corrupt file.  Error in remote mode.\n");
890 	      rc1 = ch;
891 	      get1("Corrupt file.  Error reading remote mode command.\n");
892 	      rc2 = ch;
893 	      get2("Corrupt file.  Error reading remote mode command size.\n");
894 	      bufsize = sh;
895 	      if (bufsize)
896 		getn(bufsize, "Corrupt file.  Error reading remote mode command parameters.\n");
897 	      if (rc1 == 0x1b && rc2 == 0) /* ignore quietly */
898 		;
899 	      else
900 		fprintf(stderr,
901 			"Remote mode command `%c%c' ignored.\n",
902 			rc1,rc2);
903 	    }
904 	  while (!eject && !(rc1 == 0x1b && rc2 == 0));
905 	}
906       else
907 	{
908 /*
909 	  fprintf(stderr,"Warning!  Commands in unrecognised remote mode %s ignored.\n", buf);
910 */
911 	  do
912 	    {
913 	      while((!eject) && (ch!=0x1b))
914 		get1("Error in remote mode.\n");
915 	      get1("Error reading remote mode terminator\n");
916 	    }
917 	  while ((!eject) && (ch != 0));
918 	}
919       break;
920     case 'G': /* select graphics mode */
921       /* FIXME: this is supposed to have more side effects */
922       pstate.printer_weave = 0;
923       pstate.dotsize = 0;
924       pstate.bpp = 1;
925       break;
926     case 'U': /* set page units */
927       switch (bufsize)
928 	{
929 	case 1:
930 	  pstate.page_management_units =
931 	    pstate.absolute_horizontal_units =
932 	    pstate.relative_horizontal_units =
933 	    pstate.relative_vertical_units =
934 	    pstate.horizontal_spacing =
935 	    pstate.absolute_vertical_units = 3600 / buf[0];
936 	  if (pstate.page_management_units < 720)
937 	    pstate.extraskip = 1;
938 	  fprintf(stderr, "Setting units to 1/%d\n",
939 		  pstate.absolute_horizontal_units);
940 	  break;
941 	case 5:
942 	  unit_base = buf[4] * 256 + buf[3];
943 	  pstate.extraskip=1;
944 	  pstate.page_management_units= unit_base / buf[0];
945 	  pstate.relative_vertical_units =
946 	    pstate.absolute_vertical_units = unit_base/buf[1];
947 	  pstate.relative_horizontal_units =
948 	    pstate.horizontal_spacing =
949 	    pstate.absolute_horizontal_units = unit_base / buf[2];
950 	  fprintf(stderr, "Setting page management units to 1/%d\n",
951 		  pstate.page_management_units);
952 	  fprintf(stderr, "Setting vertical units to 1/%d\n",
953 		  pstate.relative_vertical_units);
954 	  fprintf(stderr, "Setting horizontal units to 1/%d\n",
955 		  pstate.relative_horizontal_units);
956 	  break;
957 	}
958       break;
959     case 'i': /* set printer weave mode */
960       if (bufsize != 1)
961 	fprintf(stderr,"Malformed printer weave setting command.\n");
962       else
963 	pstate.printer_weave = buf[0] % 0x30;
964       break;
965     case 'e': /* set dot size */
966       if ((bufsize != 2) || (buf[0] != 0))
967 	fprintf(stderr,"Malformed dotsize setting command.\n");
968       else if (pstate.got_graphics)
969 	fprintf(stderr,"Changing dotsize while printing not supported.\n");
970       else
971 	{
972 	  pstate.dotsize = buf[1];
973 	  if (pstate.dotsize > 0x10)
974 	    pstate.bpp = 2;
975 	  else
976 	    pstate.bpp = 1;
977 	}
978       fprintf(stderr, "Setting dot size to 0x%x (bits %d)\n",
979 	      pstate.dotsize, pstate.bpp);
980       break;
981     case 'c': /* set page format */
982       if (page)
983 	{
984 	  fprintf(stderr,"Setting the page format in the middle of printing a page is not supported.\n");
985 	  break;
986 	}
987       switch (bufsize)
988 	{
989 	case 4:
990 	  pstate.top_margin = buf[1] * 256 + buf[0];
991 	  pstate.bottom_margin = buf[3] * 256 + buf[2];
992 	  break;
993 	case 8:
994 	  pstate.top_margin = (buf[3] << 24) +
995 	    (buf[2] << 16) + (buf[1] << 8) + buf[0];
996 	  pstate.bottom_margin = (buf[7] << 24) +
997 	    (buf[6] << 16) + (buf[5] << 8) + buf[4];
998 	  break;
999 	default:
1000 	  fprintf(stderr,"Malformed page format.  Ignored.\n");
1001 	}
1002       pstate.yposition = 0;
1003       if (pstate.top_margin + pstate.bottom_margin > pstate.page_height)
1004 	pstate.page_height = pstate.top_margin + pstate.bottom_margin;
1005       fprintf(stderr, "Setting top margin to %d (%.3f)\n",
1006 	      pstate.top_margin,
1007 	      (double) pstate.top_margin / pstate.page_management_units);
1008       fprintf(stderr, "Setting bottom margin to %d (%.3f)\n",
1009 	      pstate.bottom_margin,
1010 	      (double) pstate.bottom_margin / pstate.page_management_units);
1011       page = (line_type **)
1012 	stp_zalloc((pstate.bottom_margin - pstate.top_margin) *
1013 		   sizeof(line_type *));
1014       break;
1015     case 'V': /* set absolute vertical position */
1016       i = 0;
1017       switch (bufsize)
1018 	{
1019 	case 4:
1020 	  i = (buf[2] << 16) + (buf[3]<<24);
1021 	  /* FALLTHROUGH */
1022 	case 2:
1023 	  i += (buf[0]) + (256 * buf[1]);
1024 	  if (pstate.top_margin + i * (pstate.relative_vertical_units /
1025 				       pstate.absolute_vertical_units) >=
1026 	      pstate.yposition)
1027 	    pstate.yposition = i * (pstate.relative_vertical_units /
1028 				    pstate.absolute_vertical_units) +
1029 	      pstate.top_margin;
1030 	  else
1031 	    fprintf(stderr, "Warning: Setting Y position in negative direction ignored\n");
1032 	  break;
1033 	default:
1034 	  fprintf(stderr, "Malformed absolute vertical position set.\n");
1035 	}
1036       if (pstate.yposition > pstate.bottom_margin - pstate.top_margin)
1037 	{
1038 	  fprintf(stderr,
1039 		  "Warning! Printer head moved past bottom margin.  Dumping output and exiting.\n");
1040 	  eject = 1;
1041 	}
1042       break;
1043     case 'v': /* set relative vertical position */
1044       i = 0;
1045       switch (bufsize)
1046 	{
1047 	case 4:
1048 	  i = (buf[2] << 16) + (buf[3] << 24);
1049 	  /* FALLTHROUGH */
1050 	case 2:
1051 	  i += (buf[0]) + (256 * buf[1]);
1052 	  if (unweave)
1053 	    i = pstate.nozzles;
1054 	  pstate.yposition+=i;
1055 	  break;
1056 	default:
1057 	  fprintf(stderr,"Malformed relative vertical position set.\n");
1058 	}
1059       if (pstate.yposition > pstate.bottom_margin - pstate.top_margin)
1060 	{
1061 	  fprintf(stderr,"Warning! Printer head moved past bottom margin.  Dumping output and exiting.\n");
1062 	  eject = 1;
1063 	}
1064       break;
1065     case 'K':
1066       if (bufsize!=2)
1067 	fprintf(stderr,"Malformed monochrome/color mode selection.\n");
1068       else if (buf[0])
1069 	fprintf(stderr,"Non-zero first byte in monochrome selection command. Ignored.\n");
1070       else if (buf[0] > 0x02)
1071 	fprintf(stderr,"Unknown color mode 0x%X.\n",buf[1]);
1072       else
1073 	pstate.monomode = buf[1];
1074 
1075       break;
1076     case 's':		/* Set print speed */
1077     case 'm':		/* Set paper type */
1078       break;
1079     case 'S': /* set paper dimensions */
1080       switch (bufsize)
1081 	{
1082 	case 4:
1083 	  i = (buf[1] << 16) + buf[0];
1084 	  fprintf(stderr, "Setting paper width to %d (%.3f)\n", i,
1085 		  (double) i / pstate.page_management_units);
1086 	  i = (buf[3] << 16) + buf[2];
1087 	  fprintf(stderr, "Setting paper height to %d (%.3f)\n", i,
1088 		  (double) i / pstate.page_management_units);
1089 	  break;
1090 	case 8:
1091 	  i = (buf[3] << 24) + (buf[2] << 16) + (buf[1] << 8) + buf[0];
1092 	  fprintf(stderr, "Setting paper width to %d (%.3f)\n", i,
1093 		  (double) i / pstate.page_management_units);
1094 	  i = (buf[7] << 24) + (buf[6] << 16) + (buf[5] << 8) + buf[4];
1095 	  fprintf(stderr, "Setting paper height to %d (%.3f)\n", i,
1096 		  (double) i / pstate.page_management_units);
1097 	  break;
1098 	default:
1099 	  fprintf(stderr, "Invalid set paper dimensions command.\n");
1100 	}
1101       break;
1102     case 'D':
1103       if (bufsize != 4)
1104 	fprintf(stderr, "Malformed set resolution request.\n");
1105       else
1106 	{
1107 	  int res_base = (256 * buf[1]) + buf[0];
1108 	  pstate.nozzle_separation =
1109 	    pstate.absolute_vertical_units / (res_base / buf[2]);
1110 	  pstate.horizontal_spacing = res_base / buf[3];
1111 	  fprintf(stderr, "Setting nozzle separation to %d\n",
1112 		  pstate.nozzle_separation);
1113 	  fprintf(stderr, "Setting vertical spacing to 1/%d\n",
1114 		  res_base / buf[2]);
1115 	  fprintf(stderr, "Setting horizontal spacing to 1/%d\n",
1116 		  pstate.horizontal_spacing);
1117 	}
1118       break;
1119     case 'r': /* select color */
1120       if (bufsize!=2)
1121 	fprintf(stderr,"Malformed color selection request.\n");
1122       else
1123 	{
1124 	  sh = 256 * buf[0] + buf[1];
1125 	  if ((buf[1] > 4) || (buf[1] == 3) || (buf[0] > 1) ||
1126 	      (buf[0] && (buf[1]==0)))
1127 	    fprintf(stderr,"Invalid color 0x%X.\n",sh);
1128 	  else
1129 	    pstate.current_color = seqcolor(sh);
1130 	}
1131       break;
1132     case '\\': /* set relative horizontal position */
1133     case '/':
1134       i = (buf[3] << 8) + buf[2];
1135       if (pstate.xposition + i < 0)
1136 	{
1137 	  fprintf(stderr,"Warning! Attempt to move to -X region ignored.\n");
1138 	  fprintf(stderr,"   Command:  ESC ( %c %X %X %X %X  Original "
1139 		  "position: %d\n",
1140 		  ch, buf[0], buf[1], buf[2], buf[3], pstate.xposition);
1141 	}
1142       else  /* FIXME: Where is the right margin??? */
1143 	pstate.xposition+=i;
1144       break;
1145     case '$': /* set absolute horizontal position */
1146       i = (buf[3] << 24) + (buf[2] << 16) + (buf[1] << 8) + buf[0];
1147       pstate.xposition = i * (pstate.relative_horizontal_units /
1148 			      pstate.absolute_horizontal_units);
1149       break;
1150     case 'C': /* set page height */
1151       switch (bufsize)
1152 	{
1153 	case 2:
1154 	  i = (buf[1] << 8) | buf[0];
1155 	  fprintf(stderr, "Setting page height to %d (%.3f)\n", i,
1156 		  (double) i / pstate.page_management_units);
1157 	  break;
1158 	case 4:
1159 	  i = (buf[3] << 24) + (buf[2] << 16) + (buf[1] << 8) + buf[0];
1160 	  fprintf(stderr, "Setting page height to %d (%.3f)\n", i,
1161 		  (double) i / pstate.page_management_units);
1162 	  break;
1163 	default:
1164 	  fprintf(stderr, "Invalid set page height command.\n");
1165 	}
1166       break;
1167     default:
1168       fprintf(stderr,"Warning: Unknown command ESC ( 0x%X at 0x%08X.\n",
1169 	      ch, global_counter - 5 - bufsize);
1170     }
1171 }
1172 
1173 static void
parse_escp2_command(FILE * fp_r)1174 parse_escp2_command(FILE *fp_r)
1175 {
1176   get1("Corrupt file.  No command found.\n");
1177   switch (ch)
1178     {
1179     case 1: /* Magic EJL stuff to get USB port working */
1180       fprintf(stderr,"Ignoring EJL commands.\n");
1181       do
1182 	{
1183 	  get1("Error reading EJL commands.\n");
1184 	}
1185       while (!eject && ch != 0x1b);
1186       if (eject)
1187 	break;
1188       get1("Expect esc-NULL to close EJL command.\n");
1189       if (ch != 0x40)
1190 	fprintf(stderr, "Expect esc-NULL to close EJL command.\n");
1191       break;
1192     case '@': /* initialize printer */
1193       if (page)
1194 	eject = 1;
1195       else
1196 	{
1197 	  pstate.unidirectional = 0;
1198 	  pstate.printer_weave = 0;
1199 	  pstate.dotsize = 0;
1200 	  pstate.bpp = 1;
1201 	  pstate.page_management_units = 360;
1202 	  pstate.relative_horizontal_units = 180;
1203 	  pstate.absolute_horizontal_units = 60;
1204 	  pstate.relative_vertical_units = 360;
1205 	  pstate.absolute_vertical_units = 360;
1206 	  pstate.top_margin = 120;
1207 	  pstate.bottom_margin =
1208 	    pstate.page_height = 22 * 360; /* 22 inches is default ??? */
1209 	  pstate.monomode = 0;
1210 	  pstate.left_edge = INT_MAX;
1211 	  pstate.right_edge = 0;
1212 	  pstate.top_edge = INT_MAX;
1213 	  pstate.bottom_edge = 0;
1214 	}
1215       break;
1216     case 'U': /* turn unidirectional mode on/off */
1217       get1("Error reading unidirectionality.\n");
1218       if ((ch <= 2) || ((ch >= 0x30) && (ch <= 0x32)))
1219 	pstate.unidirectional=ch;
1220       break;
1221     case 'i': /* transfer raster image */
1222     case '.':
1223       pstate.got_graphics = 1;
1224       parse_escp2_data(fp_r);
1225       break;
1226     case '\\': /* set relative horizontal position */
1227       get2("Error reading relative horizontal position.\n");
1228       if (pstate.xposition + (signed short)sh < 0)
1229 	{
1230 	  fprintf(stderr, "Warning! Move off left of region ignored.\n");
1231 	  fprintf(stderr, "   Command:  ESC %c %X %X   "
1232 		  "Original Position: %d\n",
1233 		  ch, minibuf[0], minibuf[1], pstate.xposition);
1234 	}
1235       else  /* FIXME: Where is the right margin??? */
1236 	pstate.xposition += (signed short)sh;
1237       break;
1238     case '$': /* set absolute horizontal position */
1239       get2("Error reading absolute horizontal position.\n");
1240       pstate.xposition = sh * (pstate.relative_horizontal_units /
1241 			       pstate.absolute_horizontal_units);
1242       break;
1243     case 0x0:			/* Exit remote mode */
1244       get2("Error exiting remote mode.\n");
1245       break;
1246     case 0x6: /* flush buffers */
1247       /* Woosh.  Consider them flushed. */
1248       break;
1249     case 0x19: /* control paper loading */
1250       get1("Error reading paper control byte.\n");
1251       /* paper? */
1252       break;
1253     case 'r': /* select printing color */
1254       get1("Error reading color.\n");
1255       if ((ch <= 4) && (ch != 3))
1256 	pstate.current_color = seqcolor(ch);
1257       else
1258 	fprintf(stderr, "Invalid color %d.\n", ch);
1259       break;
1260     case '(': /* commands with a payload */
1261       parse_escp2_extended(fp_r);
1262       break;
1263     default:
1264       fprintf(stderr,"Warning: Unknown command ESC 0x%X at 0x%08X.\n",ch,global_counter-2);
1265     }
1266 }
1267 
1268 void
parse_escp2(FILE * fp_r)1269 parse_escp2(FILE *fp_r)
1270 {
1271   global_counter = 0;
1272 
1273   while ((!eject) && (fread(&ch, 1, 1, fp_r)))
1274     {
1275       global_counter++;
1276       switch (ch)
1277 	{
1278 	case 0xd:		/* carriage return */
1279 	  pstate.xposition = 0;
1280 	  break;
1281 	case 0xc:		/* form feed */
1282 	  eject = 1;
1283 	  break;
1284 	case 0x0:
1285 	  break;
1286 	case 0x1b:		/* Command! */
1287 	  parse_escp2_command(fp_r);
1288 	  break;
1289 	default:
1290 	  fprintf(stderr,
1291 		  "Corrupt file?  No ESC found.  Found: %02X at 0x%08X\n",
1292 		  ch, global_counter-1);
1293 	  break;
1294 	}
1295     }
1296 }
1297 
1298 
1299 /* 'reverse_bit_order'
1300  *
1301  * reverse the bit order in an array of bytes - does not reverse byte order!
1302  */
1303 void
reverse_bit_order(unsigned char * buff,int n)1304 reverse_bit_order(unsigned char *buff, int n)
1305 {
1306   int i;
1307   unsigned char a;
1308   if (!n) return; /* nothing to do */
1309 
1310   for (i= 0; i<n; i++) {
1311     a= buff[i];
1312     buff[i]=
1313       (a & 0x01) << 7 |
1314       (a & 0x02) << 5 |
1315       (a & 0x04) << 3 |
1316       (a & 0x08) << 1 |
1317       (a & 0x10) >> 1 |
1318       (a & 0x20) >> 3 |
1319       (a & 0x40) >> 5 |
1320       (a & 0x80) >> 7;
1321   }
1322 }
1323 
1324 /* 'rle_decode'
1325  *
1326  * run-length-decodes a given buffer of height "n"
1327  * and stores the result in the same buffer
1328  * not exceeding a size of "max" bytes.
1329  */
1330 int
rle_decode(unsigned char * inbuf,int n,int max)1331 rle_decode(unsigned char *inbuf, int n, int max)
1332 {
1333   unsigned char outbuf[1440*3];
1334   signed char *ib= (signed char *)inbuf;
1335   signed char cnt;
1336   int num;
1337   int i= 0, j;
1338   int o= 0;
1339 
1340 #ifdef DEBUG_RLE
1341   fprintf(stderr,"input: %d\n",n);
1342 #endif
1343   if (n<=0) return 0;
1344   if (max>1440*3) max= 1440*3; /* FIXME: this can be done much better! */
1345 
1346   while (i<n && o<max) {
1347     cnt= ib[i];
1348     if (cnt<0) {
1349       /* cnt identical bytes */
1350       /* fprintf(stderr,"rle 0x%02x = %4d = %4d\n",cnt&0xff,cnt,1-cnt); */
1351       num= 1-cnt;
1352       /* fprintf (stderr,"+%6d ",num); */
1353       for (j=0; j<num && o+j<max; j++) outbuf[o+j]= inbuf[i+1];
1354       o+= num;
1355       i+= 2;
1356     } else {
1357       /* cnt individual bytes */
1358       /* fprintf(stderr,"raw 0x%02x = %4d = %4d\n",cnt&0xff,cnt,cnt + 1); */
1359       num= cnt+1;
1360       /* fprintf (stderr,"*%6d ",num); */
1361       for (j=0; j<num && o+j<max; j++) outbuf[o+j]= inbuf[i+j+1];
1362       o+= num;
1363       i+= num+1;
1364     }
1365   }
1366   if (o>=max) {
1367     fprintf(stderr,"Warning: rle decompression exceeds output buffer.\n");
1368     return 0;
1369   }
1370   /* copy decompressed data to inbuf: */
1371   memset(inbuf,0,max-1);
1372   memcpy(inbuf,outbuf,o);
1373 #ifdef DEBUG_RLE
1374    fprintf(stderr,"output: %d\n",o);
1375 #endif
1376   return o;
1377 }
1378 
1379 void
parse_canon(FILE * fp_r)1380 parse_canon(FILE *fp_r)
1381 {
1382 
1383   int m=0;
1384   int currentcolor,currentbpp,density,l_eject;
1385   int cmdcounter;
1386   int delay_c=0, delay_m=0, delay_y=0, delay_C=0,
1387     delay_M=0, delay_Y=0, delay_K=0, currentdelay=0;
1388 
1389   global_counter=0;
1390 
1391   page= 0;
1392   l_eject=pstate.got_graphics=currentbpp=currentcolor=density=0;
1393   while ((!l_eject)&&(fread(&ch,1,1,fp_r))){
1394     global_counter++;
1395    if (ch==0xd) { /* carriage return */
1396      pstate.xposition=0;
1397 #ifdef DEBUG_CANON
1398      fprintf(stderr,"<  ");
1399 #endif
1400      continue;
1401    }
1402    if (ch==0xc) { /* form feed */
1403      l_eject=1;
1404      continue;
1405    }
1406    if (ch=='B') {
1407      fgets((char *)buf,sizeof(buf),fp_r);
1408      global_counter+= strlen((char *)buf);
1409      if (!strncmp((char *)buf,"JLSTART",7)) {
1410        while (strncmp((char *)buf,"BJLEND",6)) {
1411 	 fgets((char *)buf,sizeof(buf),fp_r);
1412 	 global_counter+= strlen((char *)buf);
1413 	 fprintf(stderr,"got BJL-plaintext-command %s",buf);
1414        }
1415      } else {
1416        fprintf(stderr,"Error: expected BJLSTART but got B%s",buf);
1417      }
1418      global_counter= ftell(fp_r);
1419      continue;
1420    }
1421    if (ch!=0x1b) {
1422      fprintf(stderr,"Corrupt file?  No ESC found.  Found: %02X at 0x%08X\n",
1423 	     ch,global_counter-1);
1424      continue;
1425    }
1426    get1("Corrupt file.  No command found.\n");
1427    /* fprintf(stderr,"Got a %X.\n",ch); */
1428    switch (ch) {
1429    case '[': /* 0x5b initialize printer */
1430      get1("Error reading CEM-code.\n");
1431      cmdcounter= global_counter;
1432      get2("Error reading CEM-data size.\n");
1433      getn(sh,"Error reading CEM-data.\n");
1434 
1435      if (ch=='K') /* 0x4b */ {
1436        if (sh!=2 || buf[0]!=0x00 ) {
1437 	 fprintf(stderr,"Error initializing printer with ESC [ K\n");
1438 	 l_eject=1;
1439 	 continue;
1440        }
1441        if (page) {
1442 	 l_eject=1;
1443 	 continue;
1444        } else {
1445 	 pstate.unidirectional=0;
1446 	 pstate.printer_weave=0;
1447 	 pstate.dotsize=0;
1448 	 pstate.bpp=1;
1449 	 pstate.page_management_units=360;
1450 	 pstate.relative_horizontal_units=180;
1451 	 pstate.absolute_horizontal_units=60;
1452 	 pstate.relative_vertical_units=360;
1453 	 pstate.absolute_vertical_units=360;
1454 	 pstate.top_margin=120;
1455 	 pstate.bottom_margin=
1456 	   pstate.page_height=22*360; /* 22 inches is default ??? */
1457 	 pstate.monomode=0;
1458 	 pstate.xposition= 0;
1459 	 pstate.yposition= 0;
1460 	 pstate.left_edge = INT_MAX;
1461 	 pstate.right_edge = 0;
1462 	 pstate.top_edge = INT_MAX;
1463 	 pstate.bottom_edge = 0;
1464 	 fprintf(stderr,"canon: init printer\n");
1465        }
1466      } else {
1467        fprintf(stderr,"Warning: Unknown command ESC %c 0x%X at 0x%08X.\n",
1468 	       0x5b,ch,global_counter);
1469      }
1470      break;
1471 
1472    case '@': /* 0x40 */
1473      l_eject=1;
1474      break;
1475 
1476    case '(': /* 0x28 */
1477      get1("Corrupt file.  Incomplete extended command.\n");
1478      cmdcounter= global_counter;
1479      get2("Corrupt file.  Error reading buffer size.\n");
1480      bufsize=sh;
1481      getn(bufsize,"Corrupt file.  Error reading data buffer.\n");
1482 
1483      switch(ch) {
1484 /* Color Codes:
1485    color    Epson1  Epson2   Sequential
1486    Black    0       0        0 K
1487    Magenta  1       1        1 M
1488    Cyan     2       2        2 C
1489    Yellow   4       4        3 Y
1490    L.Mag.   17      257      4 m
1491    L.Cyan   18      258      5 c
1492    L.Yellow NA      NA       6 y
1493  */
1494      case 'A': /* 0x41 - transfer graphics data */
1495        switch (*buf) {
1496        case 'K': currentcolor= 0; currentdelay= delay_K; break;
1497        case 'M': currentcolor= 1; currentdelay= delay_M; break;
1498        case 'C': currentcolor= 2; currentdelay= delay_C; break;
1499        case 'Y': currentcolor= 3; currentdelay= delay_Y; break;
1500        case 'm': currentcolor= 4; currentdelay= delay_m; break;
1501        case 'c': currentcolor= 5; currentdelay= delay_c; break;
1502        case 'y': currentcolor= 6; currentdelay= delay_y; break;
1503        default:
1504 	 fprintf(stderr,"Error: unsupported color type 0x%02x.\n",*buf);
1505 	 /* exit(-1); */
1506        }
1507        pstate.current_color= currentcolor;
1508        m= rle_decode(buf+1,bufsize-1,sizeof(buf)-1);
1509        /* reverse_bit_order(buf+1,m); */
1510        pstate.yposition+= currentdelay;
1511        if (m) update_page(buf+1,m,1,(m*8)/pstate.bpp,currentcolor,
1512 			  pstate.absolute_horizontal_units);
1513        pstate.yposition-= currentdelay;
1514 #ifdef DEBUG_CANON
1515        fprintf(stderr,"%c:%d>%d  ",*buf,sh-1,m);
1516 #endif
1517        break;
1518      case 'a': /* 0x61 - turn something on/off */
1519        break;
1520      case 'b': /* 0x62 - turn something else on/off */
1521        break;
1522      case 'c': /* 0x63 - some information about the print job */
1523        break;
1524      case 'd': /* 0x64 - set resolution */
1525        if (page) {
1526 	 fprintf(stderr,"Setting the page format in the middle of printing "
1527 		 "a page is not supported.\n");
1528 	 exit(-1);
1529        }
1530        pstate.relative_vertical_units=
1531 	 pstate.absolute_vertical_units=
1532 	 buf[1]+256*buf[0];
1533        pstate.relative_horizontal_units=
1534 	 pstate.absolute_horizontal_units=
1535 	 buf[3]+256*buf[2];
1536        pstate.bottom_margin= pstate.relative_vertical_units* 22;
1537        /* FIXME: replace with real page height */
1538        fprintf(stderr,"canon: res is %d x %d dpi\n",
1539 	       pstate.relative_horizontal_units,
1540 	       pstate.relative_vertical_units);
1541 
1542        page= (line_type **) stp_zalloc(pstate.bottom_margin *
1543 				       sizeof(line_type *));
1544        break;
1545      case 'e': /* 0x65 - vertical head movement */
1546        pstate.yposition+= (buf[1]+256*buf[0]);
1547 #ifdef DEBUG_CANON
1548        fprintf(stderr,"\n");
1549 #endif
1550        break;
1551      case 'l': /* 0x6c - some more information about the print job*/
1552        break;
1553      case 'm': /* 0x6d - used printheads and other things */
1554        break;
1555      case 'p': /* 0x70 - set printable area */
1556        break;
1557      case 'q': /* 0x71 - turn yet something else on/off */
1558        break;
1559      case 't': /* 0x74 - contains bpp and line delaying*/
1560        pstate.bpp= buf[0];
1561        fprintf(stderr,"canon: using %d bpp\n",pstate.bpp);
1562        if (buf[1]&0x04) {
1563 	 delay_y= 0;
1564 	 delay_m= 0;
1565 	 delay_c= 0;
1566 	 delay_Y= 0;
1567 	 delay_M= delay_Y+112;
1568 	 delay_C= delay_M+112;
1569 	 delay_K= delay_C+112;
1570 	 fprintf(stderr,"canon: using line delay code\n");
1571        }
1572        break;
1573 
1574      default:
1575        fprintf(stderr,"Warning: Unknown command ESC ( 0x%X at 0x%08X.\n",
1576 	       ch,global_counter);
1577      }
1578      break;
1579 
1580    default:
1581      fprintf(stderr,"Warning: Unknown command ESC 0x%X at 0x%08X.\n",
1582 	     ch,global_counter-2);
1583    }
1584  }
1585 }
1586 
1587 int
main(int argc,char * argv[])1588 main(int argc,char *argv[])
1589 {
1590 
1591   int arg;
1592   char *s;
1593   char *UNPRINT;
1594   FILE *fp_r, *fp_w;
1595   int force_extraskip = -1;
1596   int no_output = 0;
1597   int all_black = 0;
1598 
1599   unweave = 0;
1600   pstate.nozzle_separation = 6;
1601   fp_r = fp_w = NULL;
1602   for (arg = 1; arg < argc; arg++)
1603     {
1604       if (argv[arg][0] == '-')
1605 	{
1606 	  switch (argv[arg][1])
1607 	    {
1608 	    case 0:
1609 	      if (fp_r)
1610 		fp_w = stdout;
1611 	      else
1612 		fp_r = stdin;
1613 	      break;
1614 	    case 'h':
1615 	      fprintf(stderr, "Usage: %s [-m mask] [-n nozzle_sep] [-s extra] [-b] [-q] [-Q] [-M] [-u] [in [out]]\n", argv[0]);
1616 	      fprintf(stderr, "        -m mask       Color mask to unprint\n");
1617 	      fprintf(stderr, "        -n nozzle_sep Nozzle separation in vertical units for old printers\n");
1618 	      fprintf(stderr, "        -s extra      Extra feed requirement for old printers (typically 1)\n");
1619 	      fprintf(stderr, "        -b            Unprint everything in black\n");
1620 	      fprintf(stderr, "        -q            Don't produce output\n");
1621 	      fprintf(stderr, "        -Q            Assume quadtone inks\n");
1622 	      fprintf(stderr, "        -M            Assume MIS quadtone inks\n");
1623 	      fprintf(stderr, "        -u            Unweave\n");
1624 	      return 1;
1625 	    case 'm':
1626 	      if (argv[arg][2])
1627 		{
1628 		  s = argv[arg] + 2;
1629 		}
1630 	      else
1631 		{
1632 		  if (argc <= arg + 1)
1633 		    {
1634 		      fprintf(stderr, "Missing color mask\n");
1635 		      exit(-1);
1636 		    }
1637 		  else
1638 		    {
1639 		      s = argv[++arg];
1640 		    }
1641 		}
1642 	      if (!sscanf(s, "%x", &color_mask))
1643 		{
1644 		  fprintf(stderr,"Error parsing mask\n");
1645 		  exit(-1);
1646 		}
1647 	      break;
1648 	    case 'n':
1649 	      if (argv[arg][2])
1650 		{
1651 		  s = argv[arg] + 2;
1652 		}
1653 	      else
1654 		{
1655 		  if (argc <= arg + 1)
1656 		    {
1657 		      fprintf(stderr, "Missing nozzle separation\n");
1658 		      exit(-1);
1659 		    }
1660 		  else
1661 		    {
1662 		      s = argv[++arg];
1663 		    }
1664 		}
1665 	      if (!sscanf(s, "%d", &pstate.nozzle_separation))
1666 		{
1667 		  fprintf(stderr,"Error parsing nozzle separation\n");
1668 		  exit(-1);
1669 		}
1670 	      break;
1671 	    case 's':
1672 	      if (argv[arg][2])
1673 		{
1674 		  s = argv[arg] + 2;
1675 		}
1676 	      else
1677 		{
1678 		  if (argc <= arg + 1)
1679 		    {
1680 		      fprintf(stderr,"Missing extra skip\n");
1681 		      exit(-1);
1682 		    }
1683 		  else
1684 		    {
1685 		      s = argv[++arg];
1686 		    }
1687 		}
1688 	      if (!sscanf(s, "%d", &force_extraskip))
1689 		{
1690 		  fprintf(stderr, "Error parsing extra skip\n");
1691 		  exit(-1);
1692 		}
1693 	      break;
1694 	    case 'b':
1695 	      all_black = 1;
1696 	      break;
1697 	    case 'q':
1698 	      no_output = 1;
1699 	      break;
1700 	    case 'Q':
1701 	      pstate.quadtone = QT_QUAD;
1702 	      break;
1703 	    case 'M':
1704 	      pstate.quadtone = QT_MIS;
1705 	      break;
1706 	    case 'u':
1707 	      unweave = 1;
1708 	      break;
1709 	    }
1710 	}
1711       else
1712 	{
1713 	  if (fp_r)
1714 	    {
1715 	      if (!(fp_w = fopen(argv[arg],"w")))
1716 		{
1717 		  perror("Error opening output file");
1718 		  exit(-1);
1719 		}
1720 	    }
1721 	  else
1722 	    {
1723 	      if (!(fp_r = fopen(argv[arg],"r")))
1724 		{
1725 		  perror("Error opening input file");
1726 		  exit(-1);
1727 		}
1728 	    }
1729 	}
1730     }
1731   if (!fp_r)
1732     fp_r = stdin;
1733   if (!fp_w)
1734     fp_w = stdout;
1735 
1736   if (unweave) {
1737     pstate.nozzle_separation = 1;
1738   }
1739   pstate.nozzles = 96;
1740   buf = stp_malloc(256 * 256);
1741   valid_bufsize = 256 * 256;
1742 
1743   UNPRINT = getenv("UNPRINT");
1744   if ((UNPRINT)&&(!strcmp(UNPRINT,"canon")))
1745     {
1746       if (force_extraskip > 0)
1747 	pstate.extraskip = force_extraskip;
1748       else
1749 	pstate.extraskip = 1;
1750       parse_canon(fp_r);
1751     }
1752   else
1753     {
1754       if (force_extraskip > 0)
1755 	pstate.extraskip = force_extraskip;
1756       else
1757 	pstate.extraskip = 2;
1758       parse_escp2(fp_r);
1759     }
1760   fprintf(stderr,"Done reading.\n");
1761   write_output(fp_w, no_output, all_black);
1762   fclose(fp_w);
1763   fprintf(stderr,"Image dump complete.\n");
1764 
1765   return(0);
1766 }
1767