1 /*
2  *   Common filter routines for CUPS.
3  *
4  *   Copyright 2007-2011 by Apple Inc.
5  *   Copyright 1997-2006 by Easy Software Products.
6  *
7  *   These coded instructions, statements, and computer programs are the
8  *   property of Apple Inc. and are protected by Federal copyright
9  *   law.  Distribution and use rights are outlined in the file "COPYING"
10  *   which should have been included with this file.
11  *
12  * Contents:
13  *
14  *   SetCommonOptions() - Set common filter options for media size,
15  *                        etc.
16  *   UpdatePageVars()   - Update the page variables for the orientation.
17  *   WriteComment()     - Write a DSC comment.
18  *   WriteCommon()      - Write common procedures...
19  *   WriteLabelProlog() - Write the prolog with the classification
20  *                        and page label.
21  *   WriteLabels()      - Write the actual page labels.
22  */
23 
24 /*
25  * Include necessary headers...
26  */
27 
28 #include "common.h"
29 #include <locale.h>
30 
31 
32 /*
33  * Globals...
34  */
35 
36 int	Orientation = 0,		/* 0 = portrait, 1 = landscape, etc. */
37 	Duplex = 0,			/* Duplexed? */
38 	LanguageLevel = 1,		/* Language level of printer */
39 	ColorDevice = 1;		/* Do color text? */
40 float	PageLeft = 18.0f,		/* Left margin */
41 	PageRight = 594.0f,		/* Right margin */
42 	PageBottom = 36.0f,		/* Bottom margin */
43 	PageTop = 756.0f,		/* Top margin */
44 	PageWidth = 612.0f,		/* Total page width */
45 	PageLength = 792.0f;		/* Total page length */
46 
47 
48 /*
49  * 'SetCommonOptions()' - Set common filter options for media size, etc.
50  */
51 
52 ppd_file_t *				/* O - PPD file */
SetCommonOptions(int num_options,cups_option_t * options,int change_size)53 SetCommonOptions(
54     int           num_options,		/* I - Number of options */
55     cups_option_t *options,		/* I - Options */
56     int           change_size)		/* I - Change page size? */
57 {
58   ppd_file_t	*ppd;			/* PPD file */
59   ppd_size_t	*pagesize;		/* Current page size */
60   const char	*val;			/* Option value */
61 
62 
63 #ifdef LC_TIME
64   setlocale(LC_TIME, "");
65 #endif /* LC_TIME */
66 
67   ppd = ppdOpenFile(getenv("PPD"));
68 
69   ppdMarkDefaults(ppd);
70   cupsMarkOptions(ppd, num_options, options);
71 
72   if ((pagesize = ppdPageSize(ppd, NULL)) != NULL)
73   {
74     int corrected = 0;
75     if (pagesize->width > 0)
76       PageWidth = pagesize->width;
77     else
78     {
79       fprintf(stderr, "ERROR: Invalid value for page width: %.0f\n",
80 	      pagesize->width);
81       corrected = 1;
82     }
83     if (pagesize->length > 0)
84       PageLength = pagesize->length;
85     else
86     {
87       fprintf(stderr, "ERROR: Invalid value for page length: %.0f\n",
88 	      pagesize->length);
89       corrected = 1;
90     }
91     if (pagesize->top >= 0 && pagesize->top <= PageLength)
92       PageTop = pagesize->top;
93     else
94     {
95       fprintf(stderr, "ERROR: Invalid value for page top margin: %.0f\n",
96 	      pagesize->top);
97       if (PageLength >= PageBottom)
98 	PageTop = PageLength - PageBottom;
99       else
100 	PageTop = PageLength;
101       corrected = 1;
102     }
103     if (pagesize->bottom >= 0 && pagesize->bottom <= PageLength)
104       PageBottom = pagesize->bottom;
105     else
106     {
107       fprintf(stderr, "ERROR: Invalid value for page bottom margin: %.0f\n",
108 	      pagesize->bottom);
109       if (PageLength <= PageBottom)
110 	PageBottom = 0.0f;
111       corrected = 1;
112     }
113     if (PageBottom == PageTop)
114     {
115       fprintf(stderr, "ERROR: Invalid values for page margins: Bottom: %.0f; Top: %.0f\n",
116 	      PageBottom, PageTop);
117       PageTop = PageLength - PageBottom;
118       if (PageBottom == PageTop)
119       {
120 	PageBottom = 0.0f;
121 	PageTop = PageLength;
122       }
123       corrected = 1;
124     }
125     if (PageBottom > PageTop)
126     {
127       fprintf(stderr, "ERROR: Invalid values for page margins: Bottom: %.0f; Top: %.0f\n",
128 	      PageBottom, PageTop);
129       float swap = PageBottom;
130       PageBottom = PageTop;
131       PageTop = swap;
132       corrected = 1;
133     }
134 
135     if (pagesize->left >= 0 && pagesize->left <= PageWidth)
136       PageLeft = pagesize->left;
137     else
138     {
139       fprintf(stderr, "ERROR: Invalid value for page left margin: %.0f\n",
140 	      pagesize->left);
141       if (PageWidth <= PageLeft)
142 	PageLeft = 0.0f;
143       corrected = 1;
144     }
145     if (pagesize->right >= 0 && pagesize->right <= PageWidth)
146       PageRight = pagesize->right;
147     else
148     {
149       fprintf(stderr, "ERROR: Invalid value for page right margin: %.0f\n",
150 	      pagesize->right);
151       if (PageWidth >= PageLeft)
152 	PageRight = PageWidth - PageLeft;
153       else
154 	PageRight = PageWidth;
155       corrected = 1;
156     }
157     if (PageLeft == PageRight)
158     {
159       fprintf(stderr, "ERROR: Invalid values for page margins: Left: %.0f; Right: %.0f\n",
160 	      PageLeft, PageRight);
161       PageRight = PageWidth - PageLeft;
162       if (PageLeft == PageRight)
163       {
164 	PageLeft = 0.0f;
165 	PageRight = PageWidth;
166       }
167       corrected = 1;
168     }
169     if (PageLeft > PageRight)
170     {
171       fprintf(stderr, "ERROR: Invalid values for page margins: Left: %.0f; Right: %.0f\n",
172 	      PageLeft, PageRight);
173       float swap = PageLeft;
174       PageLeft = PageRight;
175       PageRight = swap;
176       corrected = 1;
177     }
178 
179     if (corrected)
180     {
181       fprintf(stderr, "ERROR: PPD Page = %.0fx%.0f; %.0f,%.0f to %.0f,%.0f\n",
182 	      pagesize->width, pagesize->length, pagesize->left, pagesize->bottom, pagesize->right, pagesize->top);
183       fprintf(stderr, "ERROR: Corrected Page = %.0fx%.0f; %.0f,%.0f to %.0f,%.0f\n",
184 	      PageWidth, PageLength, PageLeft, PageBottom, PageRight, PageTop);
185     }
186     else
187       fprintf(stderr, "DEBUG: Page = %.0fx%.0f; %.0f,%.0f to %.0f,%.0f\n",
188 	      pagesize->width, pagesize->length, pagesize->left, pagesize->bottom, pagesize->right, pagesize->top);
189   }
190 
191   if (ppd != NULL)
192   {
193     ColorDevice   = ppd->color_device;
194     LanguageLevel = ppd->language_level;
195   }
196 
197   if ((val = cupsGetOption("landscape", num_options, options)) != NULL)
198   {
199     if (strcasecmp(val, "no") != 0 && strcasecmp(val, "off") != 0 &&
200         strcasecmp(val, "false") != 0)
201     {
202       if (ppd && ppd->landscape > 0)
203         Orientation = 1;
204       else
205         Orientation = 3;
206     }
207   }
208   else if ((val = cupsGetOption("orientation-requested", num_options, options)) != NULL)
209   {
210    /*
211     * Map IPP orientation values to 0 to 3:
212     *
213     *   3 = 0 degrees   = 0
214     *   4 = 90 degrees  = 1
215     *   5 = -90 degrees = 3
216     *   6 = 180 degrees = 2
217     */
218 
219     Orientation = atoi(val) - 3;
220     if (Orientation >= 2)
221       Orientation ^= 1;
222   }
223 
224   if ((val = cupsGetOption("page-left", num_options, options)) != NULL)
225   {
226     switch (Orientation & 3)
227     {
228       case 0 :
229           PageLeft = (float)atof(val);
230 	  break;
231       case 1 :
232           PageBottom = (float)atof(val);
233 	  break;
234       case 2 :
235           PageRight = PageWidth - (float)atof(val);
236 	  break;
237       case 3 :
238           PageTop = PageLength - (float)atof(val);
239 	  break;
240     }
241   }
242 
243   if ((val = cupsGetOption("page-right", num_options, options)) != NULL)
244   {
245     switch (Orientation & 3)
246     {
247       case 0 :
248           PageRight = PageWidth - (float)atof(val);
249 	  break;
250       case 1 :
251           PageTop = PageLength - (float)atof(val);
252 	  break;
253       case 2 :
254           PageLeft = (float)atof(val);
255 	  break;
256       case 3 :
257           PageBottom = (float)atof(val);
258 	  break;
259     }
260   }
261 
262   if ((val = cupsGetOption("page-bottom", num_options, options)) != NULL)
263   {
264     switch (Orientation & 3)
265     {
266       case 0 :
267           PageBottom = (float)atof(val);
268 	  break;
269       case 1 :
270           PageLeft = (float)atof(val);
271 	  break;
272       case 2 :
273           PageTop = PageLength - (float)atof(val);
274 	  break;
275       case 3 :
276           PageRight = PageWidth - (float)atof(val);
277 	  break;
278     }
279   }
280 
281   if ((val = cupsGetOption("page-top", num_options, options)) != NULL)
282   {
283     switch (Orientation & 3)
284     {
285       case 0 :
286           PageTop = PageLength - (float)atof(val);
287 	  break;
288       case 1 :
289           PageRight = PageWidth - (float)atof(val);
290 	  break;
291       case 2 :
292           PageBottom = (float)atof(val);
293 	  break;
294       case 3 :
295           PageLeft = (float)atof(val);
296 	  break;
297     }
298   }
299 
300   if (change_size)
301     UpdatePageVars();
302 
303   if (ppdIsMarked(ppd, "Duplex", "DuplexNoTumble") ||
304       ppdIsMarked(ppd, "Duplex", "DuplexTumble") ||
305       ppdIsMarked(ppd, "JCLDuplex", "DuplexNoTumble") ||
306       ppdIsMarked(ppd, "JCLDuplex", "DuplexTumble") ||
307       ppdIsMarked(ppd, "EFDuplex", "DuplexNoTumble") ||
308       ppdIsMarked(ppd, "EFDuplex", "DuplexTumble") ||
309       ppdIsMarked(ppd, "KD03Duplex", "DuplexNoTumble") ||
310       ppdIsMarked(ppd, "KD03Duplex", "DuplexTumble"))
311     Duplex = 1;
312 
313   return (ppd);
314 }
315 
316 
317 /*
318  * 'UpdatePageVars()' - Update the page variables for the orientation.
319  */
320 
321 void
UpdatePageVars(void)322 UpdatePageVars(void)
323 {
324   float		temp;			/* Swapping variable */
325 
326 
327   switch (Orientation & 3)
328   {
329     case 0 : /* Portait */
330         break;
331 
332     case 1 : /* Landscape */
333 	temp       = PageLeft;
334 	PageLeft   = PageBottom;
335 	PageBottom = temp;
336 
337 	temp       = PageRight;
338 	PageRight  = PageTop;
339 	PageTop    = temp;
340 
341 	temp       = PageWidth;
342 	PageWidth  = PageLength;
343 	PageLength = temp;
344 	break;
345 
346     case 2 : /* Reverse Portrait */
347 	temp       = PageWidth - PageLeft;
348 	PageLeft   = PageWidth - PageRight;
349 	PageRight  = temp;
350 
351 	temp       = PageLength - PageBottom;
352 	PageBottom = PageLength - PageTop;
353 	PageTop    = temp;
354         break;
355 
356     case 3 : /* Reverse Landscape */
357 	temp       = PageWidth - PageLeft;
358 	PageLeft   = PageWidth - PageRight;
359 	PageRight  = temp;
360 
361 	temp       = PageLength - PageBottom;
362 	PageBottom = PageLength - PageTop;
363 	PageTop    = temp;
364 
365 	temp       = PageLeft;
366 	PageLeft   = PageBottom;
367 	PageBottom = temp;
368 
369 	temp       = PageRight;
370 	PageRight  = PageTop;
371 	PageTop    = temp;
372 
373 	temp       = PageWidth;
374 	PageWidth  = PageLength;
375 	PageLength = temp;
376 	break;
377   }
378 }
379 
380 
381 /*
382  * 'WriteCommon()' - Write common procedures...
383  */
384 
385 void
WriteCommon(void)386 WriteCommon(void)
387 {
388   puts("% x y w h ESPrc - Clip to a rectangle.\n"
389        "userdict/ESPrc/rectclip where{pop/rectclip load}\n"
390        "{{newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
391        "neg 0 rlineto closepath clip newpath}bind}ifelse put");
392   puts("% x y w h ESPrf - Fill a rectangle.\n"
393        "userdict/ESPrf/rectfill where{pop/rectfill load}\n"
394        "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
395        "neg 0 rlineto closepath fill grestore}bind}ifelse put");
396   puts("% x y w h ESPrs - Stroke a rectangle.\n"
397        "userdict/ESPrs/rectstroke where{pop/rectstroke load}\n"
398        "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
399        "neg 0 rlineto closepath stroke grestore}bind}ifelse put");
400 }
401 
402 
403 /*
404  * 'WriteLabelProlog()' - Write the prolog with the classification
405  *                        and page label.
406  */
407 
408 void
WriteLabelProlog(const char * label,float bottom,float top,float width)409 WriteLabelProlog(const char *label,	/* I - Page label */
410 		 float      bottom,	/* I - Bottom position in points */
411 		 float      top,	/* I - Top position in points */
412 		 float      width)	/* I - Width in points */
413 {
414   const char	*classification;	/* CLASSIFICATION environment variable */
415   const char	*ptr;			/* Temporary string pointer */
416 
417 
418  /*
419   * First get the current classification...
420   */
421 
422   if ((classification = getenv("CLASSIFICATION")) == NULL)
423     classification = "";
424   if (strcmp(classification, "none") == 0)
425     classification = "";
426 
427  /*
428   * If there is nothing to show, bind an empty 'write labels' procedure
429   * and return...
430   */
431 
432   if (!classification[0] && (label == NULL || !label[0]))
433   {
434     puts("userdict/ESPwl{}bind put");
435     return;
436   }
437 
438  /*
439   * Set the classification + page label string...
440   */
441 
442   printf("userdict");
443   if (strcmp(classification, "confidential") == 0)
444     printf("/ESPpl(CONFIDENTIAL");
445   else if (strcmp(classification, "classified") == 0)
446     printf("/ESPpl(CLASSIFIED");
447   else if (strcmp(classification, "secret") == 0)
448     printf("/ESPpl(SECRET");
449   else if (strcmp(classification, "topsecret") == 0)
450     printf("/ESPpl(TOP SECRET");
451   else if (strcmp(classification, "unclassified") == 0)
452     printf("/ESPpl(UNCLASSIFIED");
453   else
454   {
455     printf("/ESPpl(");
456 
457     for (ptr = classification; *ptr; ptr ++)
458       if (*ptr < 32 || *ptr > 126)
459         printf("\\%03o", *ptr);
460       else if (*ptr == '_')
461         putchar(' ');
462       else
463       {
464 	if (*ptr == '(' || *ptr == ')' || *ptr == '\\')
465 	  putchar('\\');
466 
467 	putchar(*ptr);
468       }
469   }
470 
471   if (label)
472   {
473     if (classification[0])
474       printf(" - ");
475 
476    /*
477     * Quote the label string as needed...
478     */
479 
480     for (ptr = label; *ptr; ptr ++)
481       if (*ptr < 32 || *ptr > 126)
482         printf("\\%03o", *ptr);
483       else
484       {
485 	if (*ptr == '(' || *ptr == ')' || *ptr == '\\')
486 	  putchar('\\');
487 
488 	putchar(*ptr);
489       }
490   }
491 
492   puts(")put");
493 
494  /*
495   * Then get a 14 point Helvetica-Bold font...
496   */
497 
498   puts("userdict/ESPpf /Helvetica-Bold findfont 14 scalefont put");
499 
500  /*
501   * Finally, the procedure to write the labels on the page...
502   */
503 
504   puts("userdict/ESPwl{");
505   puts("  ESPpf setfont");
506   printf("  ESPpl stringwidth pop dup 12 add exch -0.5 mul %.0f add\n",
507          width * 0.5f);
508   puts("  1 setgray");
509   printf("  dup 6 sub %.0f 3 index 20 ESPrf\n", bottom - 2.0);
510   printf("  dup 6 sub %.0f 3 index 20 ESPrf\n", top - 18.0);
511   puts("  0 setgray");
512   printf("  dup 6 sub %.0f 3 index 20 ESPrs\n", bottom - 2.0);
513   printf("  dup 6 sub %.0f 3 index 20 ESPrs\n", top - 18.0);
514   printf("  dup %.0f moveto ESPpl show\n", bottom + 2.0);
515   printf("  %.0f moveto ESPpl show\n", top - 14.0);
516   puts("pop");
517   puts("}bind put");
518 }
519 
520 
521 /*
522  * 'WriteLabels()' - Write the actual page labels.
523  */
524 
525 void
WriteLabels(int orient)526 WriteLabels(int orient)	/* I - Orientation of the page */
527 {
528   float	width,		/* Width of page */
529 	length;		/* Length of page */
530 
531 
532   puts("gsave");
533 
534   if ((orient ^ Orientation) & 1)
535   {
536     width  = PageLength;
537     length = PageWidth;
538   }
539   else
540   {
541     width  = PageWidth;
542     length = PageLength;
543   }
544 
545   switch (orient & 3)
546   {
547     case 1 : /* Landscape */
548         printf("%.1f 0.0 translate 90 rotate\n", length);
549         break;
550     case 2 : /* Reverse Portrait */
551         printf("%.1f %.1f translate 180 rotate\n", width, length);
552         break;
553     case 3 : /* Reverse Landscape */
554         printf("0.0 %.1f translate -90 rotate\n", width);
555         break;
556   }
557 
558   puts("ESPwl");
559   puts("grestore");
560 }
561 
562 
563 /*
564  * 'WriteTextComment()' - Write a DSC text comment.
565  */
566 
567 void
WriteTextComment(const char * name,const char * value)568 WriteTextComment(const char *name,	/* I - Comment name ("Title", etc.) */
569                  const char *value)	/* I - Comment value */
570 {
571   int	len;				/* Current line length */
572 
573 
574  /*
575   * DSC comments are of the form:
576   *
577   *   %%name: value
578   *
579   * The name and value must be limited to 7-bit ASCII for most printers,
580   * so we escape all non-ASCII and ASCII control characters as described
581   * in the Adobe Document Structuring Conventions specification.
582   */
583 
584   printf("%%%%%s: (", name);
585   len = 5 + strlen(name);
586 
587   while (*value)
588   {
589     if (*value < ' ' || *value >= 127)
590     {
591      /*
592       * Escape this character value...
593       */
594 
595       if (len >= 251)			/* Keep line < 254 chars */
596         break;
597 
598       printf("\\%03o", *value & 255);
599       len += 4;
600     }
601     else if (*value == '\\')
602     {
603      /*
604       * Escape the backslash...
605       */
606 
607       if (len >= 253)			/* Keep line < 254 chars */
608         break;
609 
610       putchar('\\');
611       putchar('\\');
612       len += 2;
613     }
614     else
615     {
616      /*
617       * Put this character literally...
618       */
619 
620       if (len >= 254)			/* Keep line < 254 chars */
621         break;
622 
623       putchar(*value);
624       len ++;
625     }
626 
627     value ++;
628   }
629 
630   puts(")");
631 }
632 
633