1 #include <ctype.h>
2 #include "pdftopdf_processor.h"
3 #include <cups/ppd.h>
4
5 #include <string.h>
6
7 // TODO: -currently changes ppd. (Copies)
8 //
emitJCLOptions(FILE * fp,ppd_file_t * ppd,int deviceCopies)9 static void emitJCLOptions(FILE *fp, ppd_file_t *ppd, int deviceCopies) // {{{
10 {
11 int section;
12 ppd_choice_t **choices;
13 int i;
14 char buf[1024];
15 ppd_attr_t *attr;
16 bool withJCL=false,
17 datawritten=false;
18
19 if (!ppd) return;
20
21 if ((attr = ppdFindAttr(ppd,"pdftopdfJCLBegin",NULL)) != NULL) {
22 withJCL=true;
23 const int n=strlen(attr->value);
24 for (i = 0;i < n;i++) {
25 if (attr->value[i] == '\r' || attr->value[i] == '\n') {
26 // skip new line
27 continue;
28 }
29 fputc(attr->value[i],fp);
30 datawritten=true;
31 }
32 }
33
34 snprintf(buf,sizeof(buf),"%d",deviceCopies);
35 if (ppdFindOption(ppd,"Copies") != NULL) {
36 ppdMarkOption(ppd,"Copies",buf);
37 } else {
38 if ((attr = ppdFindAttr(ppd,"pdftopdfJCLCopies",buf)) != NULL) {
39 fputs(attr->value,fp);
40 datawritten=true;
41 } else if (withJCL) {
42 fprintf(fp,"Copies=%d;",deviceCopies);
43 datawritten=true;
44 }
45 }
46 for (section = (int)PPD_ORDER_ANY;
47 section <= (int)PPD_ORDER_PROLOG;section++) {
48 int n = ppdCollect(ppd,(ppd_section_t)section,&choices);
49 for (i = 0;i < n;i++) {
50 snprintf(buf,sizeof(buf),"pdftopdfJCL%s",
51 ((ppd_option_t *)(choices[i]->option))->keyword);
52 if ((attr = ppdFindAttr(ppd,buf,choices[i]->choice)) != NULL) {
53 fputs(attr->value,fp);
54 datawritten=true;
55 } else if (withJCL) {
56 fprintf(fp,"%s=%s;",
57 ((ppd_option_t *)(choices[i]->option))->keyword,
58 choices[i]->choice);
59 datawritten=true;
60 }
61 }
62 }
63 if (datawritten) {
64 fputc('\n',fp);
65 }
66 }
67 // }}}
68
69 /* Copied ppd_decode() from CUPS which is not exported to the API; needed in emitPreamble() */
70 // {{{ static int ppd_decode(char *string)
71 static int /* O - Length of decoded string */
ppd_decode(char * string)72 ppd_decode(char *string) /* I - String to decode */
73 {
74 char *inptr, /* Input pointer */
75 *outptr; /* Output pointer */
76
77 inptr = string;
78 outptr = string;
79
80 while (*inptr != '\0')
81 if (*inptr == '<' && isxdigit(inptr[1] & 255)) {
82 /*
83 * Convert hex to 8-bit values...
84 */
85
86 inptr ++;
87 while (isxdigit(*inptr & 255)) {
88 if (isalpha(*inptr))
89 *outptr = (tolower(*inptr) - 'a' + 10) << 4;
90 else
91 *outptr = (*inptr - '0') << 4;
92
93 inptr ++;
94
95 if (!isxdigit(*inptr & 255))
96 break;
97
98 if (isalpha(*inptr))
99 *outptr |= tolower(*inptr) - 'a' + 10;
100 else
101 *outptr |= *inptr - '0';
102
103 inptr ++;
104 outptr ++;
105 }
106
107 while (*inptr != '>' && *inptr != '\0')
108 inptr ++;
109 while (*inptr == '>')
110 inptr ++;
111 } else
112 *outptr++ = *inptr++;
113
114 *outptr = '\0';
115
116 return ((int)(outptr - string));
117 }
118 // }}}
119
emitPreamble(ppd_file_t * ppd,const ProcessingParameters & param)120 void emitPreamble(ppd_file_t *ppd,const ProcessingParameters ¶m) // {{{
121 {
122 if (ppd == 0) return;
123
124 ppdEmit(ppd,stdout,PPD_ORDER_EXIT);
125
126 if (param.emitJCL) {
127 /* pdftopdf only adds JCL to the job if the printer is a native PDF
128 printer and the PPD is for this mode, having the "*JCLToPDFInterpreter:"
129 keyword. We need to read this keyword manually from the PPD and replace
130 the content of ppd->jcl_ps by the value of this keyword, so that
131 ppdEmitJCL() actually adds JCL based on the presence on
132 "*JCLToPDFInterpreter:". */
133 ppd_attr_t *attr;
134 char buf[1024];
135 int devicecopies_done = 0;
136 char *old_jcl_ps = ppd->jcl_ps;
137 /* If there is a "Copies" option in the PPD file, assure that hardware
138 copies are implemented as described by this option */
139 if (ppdFindOption(ppd,"Copies") != NULL &&
140 param.deviceCopies > 1) {
141 snprintf(buf,sizeof(buf),"%d",param.deviceCopies);
142 ppdMarkOption(ppd,"Copies",buf);
143 devicecopies_done = 1;
144 }
145 if ((attr=ppdFindAttr(ppd,"JCLToPDFInterpreter",NULL)) != NULL) {
146 if (param.deviceCopies > 1 && devicecopies_done == 0 && // HW copies
147 strncmp(ppd->jcl_begin, "\033%-12345X@", 10) == 0) { // PJL
148 /* Add a PJL command to implement the hardware copies */
149 const size_t size=strlen(attr->value)+1+30;
150 ppd->jcl_ps=(char *)malloc(size*sizeof(char));
151 if (param.deviceCollate) {
152 snprintf(ppd->jcl_ps, size, "@PJL SET QTY=%d\n%s",
153 param.deviceCopies, attr->value);
154 } else {
155 snprintf(ppd->jcl_ps, size, "@PJL SET COPIES=%d\n%s",
156 param.deviceCopies, attr->value);
157 }
158 } else
159 ppd->jcl_ps=strdup(attr->value);
160 ppd_decode(ppd->jcl_ps);
161 } else {
162 ppd->jcl_ps=NULL;
163 }
164 ppdEmitJCL(ppd,stdout,param.jobId,param.user,param.title);
165 emitJCLOptions(stdout,ppd,param.deviceCopies);
166 free(ppd->jcl_ps);
167 ppd->jcl_ps = old_jcl_ps; // cups uses pool allocator, not free()
168 }
169 }
170 // }}}
171
emitPostamble(ppd_file_t * ppd,const ProcessingParameters & param)172 void emitPostamble(ppd_file_t *ppd,const ProcessingParameters ¶m) // {{{
173 {
174 if (param.emitJCL) {
175 ppdEmitJCLEnd(ppd,stdout);
176 }
177 }
178 // }}}
179
180 // pass information to subsequent filters via PDF comments
emitComment(PDFTOPDF_Processor & proc,const ProcessingParameters & param)181 void emitComment(PDFTOPDF_Processor &proc,const ProcessingParameters ¶m) // {{{
182 {
183 std::vector<std::string> output;
184
185 output.push_back("% This file was generated by pdftopdf");
186
187 // This is not standard, but like PostScript.
188 if (param.deviceCopies>0) {
189 char buf[256];
190 snprintf(buf,sizeof(buf),"%d",param.deviceCopies);
191 output.push_back(std::string("%%PDFTOPDFNumCopies : ")+buf);
192
193 if (param.deviceCollate) {
194 output.push_back("%%PDFTOPDFCollate : true");
195 } else {
196 output.push_back("%%PDFTOPDFCollate : false");
197 }
198 }
199
200 proc.setComments(output);
201 }
202 // }}}
203