1 /* Copyright (C) 2001-2019 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied,
8    modified or distributed except as expressly authorized under the terms
9    of the license contained in the file LICENSE in this distribution.
10 
11    Refer to licensing information at http://www.artifex.com or contact
12    Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13    CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 
17 /* Get/put parameters for PDF-writing driver */
18 #include "memory_.h"
19 #include "gx.h"
20 #include "gserrors.h"
21 #include "gdevpdfx.h"
22 #include "gdevpdfo.h"
23 #include "gdevpdfg.h"
24 #include "gdevpsdf.h"
25 #include "gsparamx.h"
26 #include "gsicc_manage.h"
27 
28 /*
29  * The pdfwrite device supports the following "real" parameters:
30  *      OutputFile <string>
31  *      all the Distiller parameters (also see gdevpsdp.c)
32  * Only some of the Distiller parameters actually have any effect.
33  *
34  * The device also supports the following write-only pseudo-parameters that
35  * serve only to communicate other information from the PostScript file.
36  * Their "value" is an array of strings, some of which may be the result
37  * of converting arbitrary PostScript objects to string form.
38  *      pdfmark - see gdevpdfm.c
39  *	DSC - processed in this file
40  */
41 static int pdf_dsc_process(gx_device_pdf * pdev,
42                             const gs_param_string_array * pma);
43 
44 static const int CoreDistVersion = 5000;	/* Distiller 5.0 */
45 static const gs_param_item_t pdf_param_items[] = {
46 #define pi(key, type, memb) { key, type, offset_of(gx_device_pdf, memb) }
47 
48         /* Acrobat Distiller 4 parameters */
49 
50     /*
51      * EndPage and StartPage are renamed because EndPage collides with
52      * a page device parameter.
53      */
54     pi("PDFEndPage", gs_param_type_int, EndPage),
55     pi("PDFStartPage", gs_param_type_int, StartPage),
56     pi("Optimize", gs_param_type_bool, Optimize),
57     pi("ParseDSCCommentsForDocInfo", gs_param_type_bool,
58        ParseDSCCommentsForDocInfo),
59     pi("ParseDSCComments", gs_param_type_bool, ParseDSCComments),
60     pi("EmitDSCWarnings", gs_param_type_bool, EmitDSCWarnings),
61     pi("CreateJobTicket", gs_param_type_bool, CreateJobTicket),
62     pi("PreserveEPSInfo", gs_param_type_bool, PreserveEPSInfo),
63     pi("AutoPositionEPSFiles", gs_param_type_bool, AutoPositionEPSFiles),
64     pi("PreserveCopyPage", gs_param_type_bool, PreserveCopyPage),
65     pi("UsePrologue", gs_param_type_bool, UsePrologue),
66 
67         /* Acrobat Distiller 5 parameters */
68 
69     pi("OffOptimizations", gs_param_type_int, OffOptimizations),
70 
71         /* Ghostscript-specific parameters */
72 
73     pi("ReAssignCharacters", gs_param_type_bool, ReAssignCharacters),
74     pi("ReEncodeCharacters", gs_param_type_bool, ReEncodeCharacters),
75     pi("FirstObjectNumber", gs_param_type_long, FirstObjectNumber),
76     pi("CompressFonts", gs_param_type_bool, CompressFonts),
77     pi("CompressStreams", gs_param_type_bool, CompressStreams),
78     pi("PrintStatistics", gs_param_type_bool, PrintStatistics),
79     pi("MaxInlineImageSize", gs_param_type_long, MaxInlineImageSize),
80 
81         /* PDF Encryption */
82     pi("OwnerPassword", gs_param_type_string, OwnerPassword),
83     pi("UserPassword", gs_param_type_string, UserPassword),
84     pi("KeyLength", gs_param_type_int, KeyLength),
85     pi("Permissions", gs_param_type_int, Permissions),
86     pi("EncryptionR", gs_param_type_int, EncryptionR),
87     pi("NoEncrypt", gs_param_type_string, NoEncrypt),
88 
89         /* Target viewer capabilities (Ghostscript-specific)  */
90  /* pi("ForOPDFRead", gs_param_type_bool, ForOPDFRead),			    pdfwrite-only */
91     pi("ProduceDSC", gs_param_type_bool, ProduceDSC),
92     pi("PatternImagemask", gs_param_type_bool, PatternImagemask),
93     pi("MaxClipPathSize", gs_param_type_int, MaxClipPathSize),
94     pi("MaxShadingBitmapSize", gs_param_type_int, MaxShadingBitmapSize),
95     pi("HaveTrueTypes", gs_param_type_bool, HaveTrueTypes),
96     pi("HaveCIDSystem", gs_param_type_bool, HaveCIDSystem),
97     pi("HaveTransparency", gs_param_type_bool, HaveTransparency),
98     pi("CompressEntireFile", gs_param_type_bool, CompressEntireFile),
99     pi("PDFX", gs_param_type_bool, PDFX),
100     pi("PDFA", gs_param_type_int, PDFA),
101     pi("DocumentUUID", gs_param_type_string, DocumentUUID),
102     pi("InstanceUUID", gs_param_type_string, InstanceUUID),
103     pi("DocumentTimeSeq", gs_param_type_int, DocumentTimeSeq),
104 
105     /* PDF/X parameters */
106     pi("PDFXTrimBoxToMediaBoxOffset", gs_param_type_float_array, PDFXTrimBoxToMediaBoxOffset),
107     pi("PDFXSetBleedBoxToMediaBox", gs_param_type_bool, PDFXSetBleedBoxToMediaBox),
108     pi("PDFXBleedBoxToTrimBoxOffset", gs_param_type_float_array, PDFXBleedBoxToTrimBoxOffset),
109 
110     /* media selection parameters */
111     pi("SetPageSize", gs_param_type_bool, SetPageSize),
112     pi("RotatePages", gs_param_type_bool, RotatePages),
113     pi("FitPages", gs_param_type_bool, FitPages),
114     pi("CenterPages", gs_param_type_bool, CenterPages),
115     pi("DoNumCopies", gs_param_type_bool, DoNumCopies),
116     pi("PreserveSeparation", gs_param_type_bool, PreserveSeparation),
117     pi("PreserveDeviceN", gs_param_type_bool, PreserveDeviceN),
118     pi("PDFACompatibilityPolicy", gs_param_type_int, PDFACompatibilityPolicy),
119     pi("DetectDuplicateImages", gs_param_type_bool, DetectDuplicateImages),
120     pi("AllowIncrementalCFF", gs_param_type_bool, AllowIncrementalCFF),
121     pi("WantsToUnicode", gs_param_type_bool, WantsToUnicode),
122     pi("AllowPSRepeatFunctions", gs_param_type_bool, AllowPSRepeatFunctions),
123     pi("IsDistiller", gs_param_type_bool, IsDistiller),
124     pi("PreserveSMask", gs_param_type_bool, PreserveSMask),
125     pi("PreserveTrMode", gs_param_type_bool, PreserveTrMode),
126     pi("NoT3CCITT", gs_param_type_bool, NoT3CCITT),
127     pi("FastWebView", gs_param_type_bool, Linearise),
128     pi("NoOutputFonts", gs_param_type_bool, FlattenFonts),
129     pi("WantsPageLabels", gs_param_type_bool, WantsPageLabels),
130     pi("UserUnit", gs_param_type_float, UserUnit),
131 #undef pi
132     gs_param_item_end
133 };
134 
135 /*
136   Notes on implementing the remaining Distiller functionality
137   ===========================================================
138 
139   Architectural issues
140   --------------------
141 
142   Must optionally disable application of TR, BG, UCR similarly.  Affects:
143     PreserveHalftoneInfo
144     PreserveOverprintSettings
145     TransferFunctionInfo
146     UCRandBGInfo
147 
148   Current limitations
149   -------------------
150 
151   Non-primary elements in HalftoneType 5 are not written correctly
152 
153   Acrobat Distiller 3
154   -------------------
155 
156   ---- Image parameters ----
157 
158   AntiAlias{Color,Gray,Mono}Images
159 
160   ---- Other parameters ----
161 
162   CompressPages
163     Compress things other than page contents
164   * PreserveHalftoneInfo
165   PreserveOPIComments
166     ? see OPI spec?
167   * PreserveOverprintSettings
168   * TransferFunctionInfo
169   * UCRandBGInfo
170   ColorConversionStrategy
171     Select color space for drawing commands
172   ConvertImagesToIndexed
173     Postprocess image data *after* downsampling (requires an extra pass)
174 
175   Acrobat Distiller 4
176   -------------------
177 
178   ---- Other functionality ----
179 
180   Document structure pdfmarks
181 
182   ---- Parameters ----
183 
184   xxxDownsampleType = /Bicubic
185     Add new filter (or use siscale?) & to setup (gdevpsdi.c)
186   DetectBlends
187     Idiom recognition?  PatternType 2 patterns / shfill?  (see AD4)
188   DoThumbnails
189     Also output to memory device -- resolution issue
190 
191   ---- Job-level control ----
192 
193   EmitDSCWarnings
194     Require DSC parser / interceptor
195   CreateJobTicket
196     ?
197   AutoPositionEPSFiles
198     Require DSC parsing
199   PreserveCopyPage
200     Concatenate Contents streams
201   UsePrologue
202     Needs hack in top-level control?
203 
204 */
205 
206 /* Transfer a collection of parameters. */
207 static const byte xfer_item_sizes[] = {
208     GS_PARAM_TYPE_SIZES(0)
209 };
210 int
gdev_pdf_get_param(gx_device * dev,char * Param,void * list)211 gdev_pdf_get_param(gx_device *dev, char *Param, void *list)
212 {
213     gx_device_pdf *pdev = (gx_device_pdf *)dev;
214     const gs_param_item_t *pi;
215     gs_param_list * plist = (gs_param_list *)list;
216     int code = 0;
217 
218     for (pi = pdf_param_items; pi->key != 0; ++pi) {
219         if (strcmp(pi->key, Param) == 0) {
220             const char *key = pi->key;
221             const void *pvalue = (const void *)((const char *)pdev + pi->offset);
222             int size = xfer_item_sizes[pi->type];
223             gs_param_typed_value typed;
224 
225             memcpy(&typed.value, pvalue, size);
226             typed.type = pi->type;
227             code = (*plist->procs->xmit_typed) (plist, key, &typed);
228             return code;
229         }
230     }
231     if (strcmp(Param, "CoreDistVersion") == 0) {
232         return(param_write_int(plist, "CoreDistVersion", &CoreDistVersion));
233     }
234     if (strcmp(Param, "CompatibilityLevel") == 0) {
235         float f = pdev->CompatibilityLevel;
236         return(param_write_float(plist, "CompatibilityLevel", &f));
237     }
238     if (strcmp(Param, "ForOPDFRead") == 0) {
239         return(param_write_bool(plist, "ForOPDFRead", &pdev->ForOPDFRead));
240     }
241     if (strcmp(Param, "PassUserUnit") == 0) {
242         bool dummy;
243         if (pdev->CompatibilityLevel > 1.5)
244             dummy = true;
245         else
246             dummy = false;
247         return(param_write_bool(plist, "PassUserUnit", &dummy));
248     }
249     if (!pdev->is_ps2write) {
250         if (strcmp(Param, "pdfmark")  == 0){
251             return(param_write_null(plist, "pdfmark"));
252         }
253         if (strcmp(Param, "DSC") == 0){
254             return(param_write_null(plist, "DSC"));
255         }
256     }
257     return gdev_psdf_get_param(dev, Param, list);
258 }
259 
260 /* ---------------- Get parameters ---------------- */
261 
262 /* Get parameters. */
263 int
gdev_pdf_get_params(gx_device * dev,gs_param_list * plist)264 gdev_pdf_get_params(gx_device * dev, gs_param_list * plist)
265 {
266     gx_device_pdf *pdev = (gx_device_pdf *) dev;
267     float cl = (float)pdev->CompatibilityLevel;
268     int code;
269     int cdv = CoreDistVersion;
270 
271     pdev->ParamCompatibilityLevel = cl;
272     code = gdev_psdf_get_params(dev, plist);
273     if (code < 0 ||
274         (code = param_write_int(plist, "CoreDistVersion", &cdv)) < 0 ||
275         (code = param_write_float(plist, "CompatibilityLevel", &cl)) < 0 ||
276         (!pdev->is_ps2write && (code = param_write_bool(plist, "ForOPDFRead", &pdev->ForOPDFRead)) < 0) ||
277         /* Indicate that we can process pdfmark and DSC. */
278         (param_requested(plist, "pdfmark") > 0 &&
279          (code = param_write_null(plist, "pdfmark")) < 0) ||
280         (param_requested(plist, "DSC") > 0 &&
281          (code = param_write_null(plist, "DSC")) < 0) ||
282         (code = gs_param_write_items(plist, pdev, NULL, pdf_param_items)) < 0
283         )
284     {}
285     return code;
286 }
287 
288 /* ---------------- Put parameters ---------------- */
289 
290 /* Put parameters, implementation */
291 static int
gdev_pdf_put_params_impl(gx_device * dev,const gx_device_pdf * save_dev,gs_param_list * plist)292 gdev_pdf_put_params_impl(gx_device * dev, const gx_device_pdf * save_dev, gs_param_list * plist)
293 {
294     int ecode, code;
295     gx_device_pdf *pdev = (gx_device_pdf *) dev;
296     float cl = (float)pdev->CompatibilityLevel;
297     bool locked = pdev->params.LockDistillerParams, ForOPDFRead;
298     gs_param_name param_name;
299 
300     pdev->pdf_memory = gs_memory_stable(pdev->memory);
301     /*
302      * If this is a pseudo-parameter (pdfmark or DSC),
303      * don't bother checking for any real ones.
304      */
305 
306     {
307         gs_param_string_array ppa;
308         gs_param_string pps;
309 
310         code = param_read_string_array(plist, (param_name = "pdfmark"), &ppa);
311         switch (code) {
312             case 0:
313                 code = pdfwrite_pdf_open_document(pdev);
314                 if (code < 0)
315                     return code;
316                 code = pdfmark_process(pdev, &ppa);
317                 if (code >= 0)
318                     return code;
319                 /* falls through for errors */
320             default:
321                 param_signal_error(plist, param_name, code);
322                 return code;
323             case 1:
324                 break;
325         }
326 
327         code = param_read_string_array(plist, (param_name = "DSC"), &ppa);
328         switch (code) {
329             case 0:
330                 code = pdfwrite_pdf_open_document(pdev);
331                 if (code < 0)
332                     return code;
333                 code = pdf_dsc_process(pdev, &ppa);
334                 if (code >= 0)
335                     return code;
336                 /* falls through for errors */
337             default:
338                 param_signal_error(plist, param_name, code);
339                 return code;
340             case 1:
341                 break;
342         }
343 
344         code = param_read_string(plist, (param_name = "pdfpagelabels"), &pps);
345         switch (code) {
346             case 0:
347                 {
348                     if (!pdev->ForOPDFRead) {
349                         cos_dict_t *const pcd = pdev->Catalog;
350                         code = pdfwrite_pdf_open_document(pdev);
351                         if (code < 0)
352                             return code;
353                         code = cos_dict_put_string(pcd, (const byte *)"/PageLabels", 11,
354                                    pps.data, pps.size);
355                         if (code >= 0)
356                             return code;
357                     } else
358                         return 0;
359                  }
360                 /* falls through for errors */
361             default:
362                 param_signal_error(plist, param_name, code);
363                 return code;
364             case 1:
365                 break;
366         }
367     }
368 
369     /*
370      * Check for LockDistillerParams before doing anything else.
371      * If LockDistillerParams is true and is not being set to false,
372      * ignore all resettings of PDF-specific parameters.  Note that
373      * LockDistillerParams is read again, and reset if necessary, in
374      * psdf_put_params.
375      */
376     ecode = param_read_bool(plist, (param_name = "LockDistillerParams"), &locked);
377     if (ecode < 0)
378         param_signal_error(plist, param_name, ecode);
379 
380     /* General parameters. */
381 
382     {
383         int efo = 1;
384 
385         ecode = param_put_int(plist, (param_name = ".EmbedFontObjects"), &efo, ecode);
386         if (ecode < 0)
387             param_signal_error(plist, param_name, ecode);
388         if (efo != 1)
389             param_signal_error(plist, param_name, ecode = gs_error_rangecheck);
390     }
391     {
392         int cdv = CoreDistVersion;
393 
394         ecode = param_put_int(plist, (param_name = "CoreDistVersion"), &cdv, ecode);
395         if (ecode < 0)
396             return gs_note_error(ecode);
397         if (cdv != CoreDistVersion)
398             param_signal_error(plist, param_name, ecode = gs_error_rangecheck);
399     }
400 
401     switch (code = param_read_float(plist, (param_name = "CompatibilityLevel"), &cl)) {
402         default:
403             ecode = code;
404             param_signal_error(plist, param_name, ecode);
405             break;
406         case 0:
407             if (!(locked && pdev->params.LockDistillerParams)) {
408                 /*
409                  * Must be 1.2, 1.3, 1.4, or 1.5.  Per Adobe documentation, substitute
410                  * the nearest achievable value.
411                  */
412                 if (cl < (float)1.15)
413                     cl = (float)1.1;
414                 else if (cl < (float)1.25)
415                     cl = (float)1.2;
416                 else if (cl < (float)1.35)
417                     cl = (float)1.3;
418                 else if (cl < (float)1.45)
419                     cl = (float)1.4;
420                 else if (cl < (float)1.55)
421                     cl = (float)1.5;
422                 else if (cl < (float)1.65)
423                     cl = (float)1.6;
424                 else if (cl < (float)1.75)
425                     cl = (float)1.7;
426                 else {
427                     cl = (float)2.0;
428                     if (pdev->params.TransferFunctionInfo == tfi_Preserve)
429                         pdev->params.TransferFunctionInfo = tfi_Apply;
430                 }
431             }
432         case 1:
433             break;
434     }
435     {   /* HACK : gs_param_list_s::memory is documented in gsparam.h as
436            "for allocating coerced arrays". Not sure why zputdeviceparams
437            sets it to the current memory space, while the device
438            assumes to store them in the device's memory space.
439            As a hackish workaround we temporary replace it here.
440            Doing so because we don't want to change the global code now
441            because we're unable to test it with all devices.
442            Bug 688531 "Segmentation fault running pdfwrite from 219-01.ps".
443 
444            This solution to be reconsidered after fixing
445            the bug 688533 "zputdeviceparams specifies a wrong memory space.".
446         */
447         gs_memory_t *mem = plist->memory;
448 
449         plist->memory = pdev->pdf_memory;
450         code = gs_param_read_items(plist, pdev, pdf_param_items);
451         if (code < 0 || (code = param_read_bool(plist, "ForOPDFRead", &ForOPDFRead)) < 0)
452         {
453         }
454         if (code == 0 && !pdev->is_ps2write && !(locked && pdev->params.LockDistillerParams))
455             pdev->ForOPDFRead = ForOPDFRead;
456         plist->memory = mem;
457     }
458     if (code < 0)
459         ecode = code;
460     {
461         /*
462          * Setting FirstObjectNumber is only legal if the file
463          * has just been opened and nothing has been written,
464          * or if we are setting it to the same value.
465          */
466         long fon = pdev->FirstObjectNumber;
467 
468         if (fon != save_dev->FirstObjectNumber) {
469             if (fon <= 0 || fon > 0x7fff0000 ||
470                 (pdev->next_id != 0 &&
471                  pdev->next_id !=
472                  save_dev->FirstObjectNumber + pdf_num_initial_ids)
473                 ) {
474                 ecode = gs_error_rangecheck;
475                 param_signal_error(plist, "FirstObjectNumber", ecode);
476             }
477         }
478     }
479     {
480         /*
481          * Set ProcessColorModel now, because gx_default_put_params checks
482          * it.
483          */
484         static const char *const pcm_names[] = {
485             "DeviceGray", "DeviceRGB", "DeviceCMYK", "DeviceN", 0
486         };
487         int pcm = -1;
488 
489         ecode = param_put_enum(plist, "ProcessColorModel", &pcm,
490                                pcm_names, ecode);
491         if (ecode < 0)
492             goto fail;
493         if (pcm >= 0) {
494             pdf_set_process_color_model(pdev, pcm);
495             rc_decrement(pdev->icc_struct, "gdev_pdf_put_params_impl, ProcessColorModel changed");
496             pdev->icc_struct = 0;
497         }
498     }
499 
500     if (pdev->is_ps2write && (code = param_read_bool(plist, "ProduceDSC", &pdev->ProduceDSC)) < 0) {
501         param_signal_error(plist, param_name, code);
502     }
503 
504     /* PDFA and PDFX are stored in the page device dictionary and therefore
505      * set on every setpagedevice. However, if we have encountered a file which
506      * can't be made this way, and the PDFACompatibilityPolicy is 1, we want to
507      * continue producing the file, but not as a PDF/A or PDF/X file. Its more
508      * or less impossible to alter the setting in the (potentially saved) page
509      * device dictionary, so we use this rather clunky method.
510      */
511     if (pdev->PDFA < 0 || pdev->PDFA > 3){
512         ecode = gs_note_error(gs_error_rangecheck);
513         param_signal_error(plist, "PDFA", ecode);
514         goto fail;
515     }
516     if(pdev->PDFA != 0 && pdev->AbortPDFAX)
517         pdev->PDFA = 0;
518     if(pdev->PDFX && pdev->AbortPDFAX)
519         pdev->PDFX = 0;
520     if (pdev->PDFX && pdev->PDFA != 0) {
521         ecode = gs_note_error(gs_error_rangecheck);
522         param_signal_error(plist, "PDFA", ecode);
523         goto fail;
524     }
525     if (pdev->PDFX && pdev->ForOPDFRead) {
526         ecode = gs_note_error(gs_error_rangecheck);
527         param_signal_error(plist, "PDFX", ecode);
528         goto fail;
529     }
530     if (pdev->PDFA != 0 && pdev->ForOPDFRead) {
531         ecode = gs_note_error(gs_error_rangecheck);
532         param_signal_error(plist, "PDFA", ecode);
533         goto fail;
534     }
535     if (pdev->PDFA == 1 || pdev->PDFX || pdev->CompatibilityLevel < 1.4) {
536          pdev->HaveTransparency = false;
537          pdev->PreserveSMask = false;
538     }
539 
540     /*
541      * We have to set version to the new value, because the set of
542      * legal parameter values for psdf_put_params varies according to
543      * the version.
544      */
545     if (pdev->PDFX)
546         cl = (float)1.3; /* Instead pdev->CompatibilityLevel = 1.2; - see below. */
547     if (pdev->PDFA == 1 && cl != 1.4)
548         cl = (float)1.4;
549     if (pdev->PDFA == 2 && cl < 1.7)
550         cl = (float)1.7;
551     pdev->version = (cl < 1.2 ? psdf_version_level2 : psdf_version_ll3);
552     if (pdev->ForOPDFRead) {
553         pdev->ResourcesBeforeUsage = true;
554         pdev->HaveCFF = false;
555         pdev->HavePDFWidths = false;
556         pdev->HaveStrokeColor = false;
557         cl = (float)1.2; /* Instead pdev->CompatibilityLevel = 1.2; - see below. */
558         pdev->MaxInlineImageSize = max_long; /* Save printer's RAM from saving temporary image data.
559                                                 Immediate images doen't need buffering. */
560         pdev->version = psdf_version_level2;
561     } else {
562         pdev->ResourcesBeforeUsage = false;
563         pdev->HaveCFF = true;
564         pdev->HavePDFWidths = true;
565         pdev->HaveStrokeColor = true;
566     }
567     pdev->ParamCompatibilityLevel = cl;
568     if (cl < 1.2) {
569         pdev->HaveCFF = false;
570     }
571 
572     ecode = param_read_float(plist, "UserUnit", &pdev->UserUnit);
573     if (ecode < 0)
574         goto fail;
575     if (pdev->UserUnit == 0 || (pdev->UserUnit != 1 && pdev->CompatibilityLevel < 1.6)) {
576         ecode = gs_note_error(gs_error_rangecheck);
577         param_signal_error(plist, "UserUnit", ecode);
578         goto fail;
579     }
580 
581     ecode = gdev_psdf_put_params(dev, plist);
582     if (ecode < 0)
583         goto fail;
584 
585     if (pdev->CompatibilityLevel > 1.7 && pdev->params.TransferFunctionInfo == tfi_Preserve) {
586         pdev->params.TransferFunctionInfo = tfi_Apply;
587         emprintf(pdev->memory, "\nIt is not possible to preserve transfer functions in PDF 2.0\ntransfer functions will be applied instead\n");
588     }
589 
590     if (pdev->params.ConvertCMYKImagesToRGB) {
591         if (pdev->params.ColorConversionStrategy == ccs_CMYK) {
592             emprintf(pdev->memory, "ConvertCMYKImagesToRGB is not compatible with ColorConversionStrategy of CMYK\n");
593         } else {
594             if (pdev->params.ColorConversionStrategy == ccs_Gray) {
595                 emprintf(pdev->memory, "ConvertCMYKImagesToRGB is not compatible with ColorConversionStrategy of Gray\n");
596             } else {
597                 if (pdev->icc_struct)
598                     rc_decrement(pdev->icc_struct,
599                                  "reset default profile\n");
600                 pdf_set_process_color_model(pdev,1);
601                 ecode = gsicc_init_device_profile_struct((gx_device *)pdev, NULL, 0);
602                 if (ecode < 0)
603                     goto fail;
604             }
605         }
606     }
607     switch (pdev->params.ColorConversionStrategy) {
608         case ccs_ByObjectType:
609         case ccs_LeaveColorUnchanged:
610             break;
611         case ccs_UseDeviceIndependentColor:
612         case ccs_UseDeviceIndependentColorForImages:
613             pdev->params.TransferFunctionInfo = tfi_Apply;
614             break;
615         case ccs_CMYK:
616             if (pdev->icc_struct)
617                 rc_decrement(pdev->icc_struct,
618                              "reset default profile\n");
619             pdf_set_process_color_model(pdev, 2);
620             ecode = gsicc_init_device_profile_struct((gx_device *)pdev, NULL, 0);
621             if (ecode < 0)
622                 goto fail;
623             break;
624         case ccs_Gray:
625             if (pdev->icc_struct)
626                 rc_decrement(pdev->icc_struct,
627                              "reset default profile\n");
628             pdf_set_process_color_model(pdev,0);
629             ecode = gsicc_init_device_profile_struct((gx_device *)pdev, NULL, 0);
630             if (ecode < 0)
631                 goto fail;
632             break;
633         case ccs_sRGB:
634         case ccs_RGB:
635             /* Only bother to do this if we didn't handle it above */
636             if (!pdev->params.ConvertCMYKImagesToRGB) {
637                 if (pdev->icc_struct)
638                     rc_decrement(pdev->icc_struct,
639                                  "reset default profile\n");
640                 pdf_set_process_color_model(pdev,1);
641                 ecode = gsicc_init_device_profile_struct((gx_device *)pdev, NULL, 0);
642                 if (ecode < 0)
643                     goto fail;
644             }
645             break;
646         default:
647             break;
648     }
649     if (cl < 1.5f && pdev->params.ColorImage.Filter != NULL &&
650             !strcmp(pdev->params.ColorImage.Filter, "JPXEncode")) {
651         emprintf(pdev->memory,
652                  "JPXEncode requires CompatibilityLevel >= 1.5 .\n");
653         ecode = gs_note_error(gs_error_rangecheck);
654     }
655     if (cl < 1.5f && pdev->params.GrayImage.Filter != NULL &&
656             !strcmp(pdev->params.GrayImage.Filter, "JPXEncode")) {
657         emprintf(pdev->memory,
658                  "JPXEncode requires CompatibilityLevel >= 1.5 .\n");
659         ecode = gs_note_error(gs_error_rangecheck);
660     }
661     if (cl < 1.4f && pdev->params.MonoImage.Filter != NULL &&
662             !strcmp(pdev->params.MonoImage.Filter, "JBIG2Encode")) {
663         emprintf(pdev->memory,
664                  "JBIG2Encode requires CompatibilityLevel >= 1.4 .\n");
665         ecode = gs_note_error(gs_error_rangecheck);
666     }
667     if (pdev->HaveTrueTypes && pdev->version == psdf_version_level2) {
668         pdev->version = psdf_version_level2_with_TT ;
669     }
670     if (ecode < 0)
671         goto fail;
672 
673     if (pdev->FirstObjectNumber != save_dev->FirstObjectNumber) {
674         if (pdev->xref.file != 0) {
675             if (gp_fseek(pdev->xref.file, 0L, SEEK_SET) != 0) {
676                 ecode = gs_error_ioerror;
677                 goto fail;
678             }
679             pdf_initialize_ids(pdev);
680         }
681     }
682     /* Handle the float/double mismatch. */
683     pdev->CompatibilityLevel = (int)(cl * 10 + 0.5) / 10.0;
684 
685     if (pdev->ForOPDFRead && pdev->OwnerPassword.size != 0) {
686         emprintf(pdev->memory, "\n\tSetting OwnerPassword for PostScript output would result in an encrypted\n\tunusable PostScript file, ignoring.\n");
687         pdev->OwnerPassword.size = 0;
688     }
689 
690     if(pdev->OwnerPassword.size != save_dev->OwnerPassword.size ||
691         (pdev->OwnerPassword.size != 0 &&
692          memcmp(pdev->OwnerPassword.data, save_dev->OwnerPassword.data,
693          pdev->OwnerPassword.size) != 0)) {
694         if (pdev->is_open) {
695             if (pdev->PageCount == 0) {
696                 gs_closedevice((gx_device *)save_dev);
697                 return 0;
698             }
699             else
700                 emprintf(pdev->memory, "Owner Password changed mid-job, ignoring.\n");
701         }
702     }
703 
704     if (pdev->Linearise && pdev->is_ps2write) {
705         emprintf(pdev->memory, "Can't linearise PostScript output, ignoring\n");
706         pdev->Linearise = false;
707     }
708 
709     if (pdev->Linearise && pdev->OwnerPassword.size != 0) {
710         emprintf(pdev->memory, "Can't linearise encrypted PDF, ignoring\n");
711         pdev->Linearise = false;
712     }
713 
714     if (pdev->FlattenFonts)
715         pdev->PreserveTrMode = false;
716     return 0;
717  fail:
718     /* Restore all the parameters to their original state. */
719     pdev->version = save_dev->version;
720     pdf_set_process_color_model(pdev, save_dev->pcm_color_info_index);
721     pdev->saved_fill_color = save_dev->saved_fill_color;
722     pdev->saved_stroke_color = save_dev->saved_fill_color;
723     {
724         const gs_param_item_t *ppi = pdf_param_items;
725 
726         for (; ppi->key; ++ppi)
727             memcpy((char *)pdev + ppi->offset,
728                    (char *)save_dev + ppi->offset,
729                    gs_param_type_sizes[ppi->type]);
730         pdev->ForOPDFRead = save_dev->ForOPDFRead;
731     }
732     return ecode;
733 }
734 
735 /* Put parameters */
736 int
gdev_pdf_put_params(gx_device * dev,gs_param_list * plist)737 gdev_pdf_put_params(gx_device * dev, gs_param_list * plist)
738 {
739     int code;
740     gx_device_pdf *pdev = (gx_device_pdf *) dev;
741     gs_memory_t *mem = gs_memory_stable(pdev->memory);
742     gx_device_pdf *save_dev = gs_malloc(mem, sizeof(gx_device_pdf), 1,
743         "saved gx_device_pdf");
744 
745     if (!save_dev)
746         return_error(gs_error_VMerror);
747     memcpy(save_dev, pdev, sizeof(gx_device_pdf));
748     code = gdev_pdf_put_params_impl(dev, save_dev, plist);
749     gs_free(mem, save_dev, sizeof(gx_device_pdf), 1, "saved gx_device_pdf");
750     return code;
751 }
752 
753 /* ---------------- Process DSC comments ---------------- */
754 
755 /* Bug #695850 DSC comments are not actually encoded, nor are they PostScript strings
756  * they are simply a sequence of bytes. SO it would seem we should just preserve that
757  * byte sequence. Bizarrely, Distiller treats the comment as 'almost' a PostScript
758  * string. In particular it converts octal codes into an equivalent binary byte. It
759  * also converts (eg) '\n' and '\r' into 'n' and 'r' and invalid octal escapes
760  * (eg \11) simply have the '\' turned into a '?'.
761  * We think this is nuts and have no intention of trying to mimic it precisely. This
762  * routine will find octal escapes and convert them into binary. The way this works is
763  * a little obscure. The DSC parser does convert the comment into a PostScript string
764  * and so has to escape any unusual characters. This means our octal escaped values in
765  * the original DSC comment have had the escape character ('\') escaped to become '\\'.
766  * All we need to do is remove the escape of the escape and we will end up with a
767  * properly escaped PostScript string.
768  */
unescape_octals(gx_device_pdf * pdev,char * src,int size)769 static int unescape_octals(gx_device_pdf * pdev, char *src, int size)
770 {
771     char *start, *dest;
772 
773     start = src;
774     dest = src;
775 
776     while(size) {
777         if (size > 4 && src[0] == '\\' && src[1] == '\\' &&
778                 src[2] > 0x29 && src[2] < 0x35 &&
779                 src[3] > 0x29 &&src[3] < 0x38 &&
780                 src[4] > 0x29 && src[4] < 0x38) {
781             src++;
782             size--;
783         } else {
784             *dest++ = *src++;
785             size--;
786         }
787     }
788     return (dest - start);
789 }
790 
791 static int
pdf_dsc_process(gx_device_pdf * pdev,const gs_param_string_array * pma)792 pdf_dsc_process(gx_device_pdf * pdev, const gs_param_string_array * pma)
793 {
794     /*
795      * The Adobe "Distiller Parameters" documentation says that Distiller
796      * looks at DSC comments, but it doesn't say which ones.  We look at
797      * the ones that we see how to map directly to obvious PDF constructs.
798      */
799     int code = 0;
800     uint i;
801 
802     /*
803      * If ParseDSCComments is false, all DSC comments are ignored, even if
804      * ParseDSCComentsForDocInfo or PreserveEPSInfo is true.
805      */
806     if (!pdev->ParseDSCComments)
807         return 0;
808 
809     for (i = 0; i + 1 < pma->size && code >= 0; i += 2) {
810         const gs_param_string *pkey = &pma->data[i];
811         gs_param_string *pvalue = (gs_param_string *)&pma->data[i + 1];
812         const char *key;
813         int newsize;
814 
815         /*
816          * %%For, %%Creator, and %%Title are recognized only if either
817          * ParseDSCCommentsForDocInfo or PreserveEPSInfo is true.
818          * The other DSC comments are always recognized.
819          *
820          * Acrobat Distiller sets CreationDate and ModDate to the current
821          * time, not the value of %%CreationDate.  We think this is wrong,
822          * but we do the same -- we ignore %%CreationDate here.
823          */
824 
825         if (pdf_key_eq(pkey, "Creator") && pdev->CompatibilityLevel <= 1.7) {
826             key = "/Creator";
827             newsize = unescape_octals(pdev, (char *)pvalue->data, pvalue->size);
828             code = cos_dict_put_c_key_string(pdev->Info, key,
829                                              pvalue->data, newsize);
830             continue;
831         } else if (pdf_key_eq(pkey, "Title") && pdev->CompatibilityLevel <= 1.7) {
832             key = "/Title";
833             newsize = unescape_octals(pdev, (char *)pvalue->data, pvalue->size);
834             code = cos_dict_put_c_key_string(pdev->Info, key,
835                                              pvalue->data, newsize);
836             continue;
837         } else if (pdf_key_eq(pkey, "For") && pdev->CompatibilityLevel <= 1.7) {
838             key = "/Author";
839             newsize = unescape_octals(pdev, (char *)pvalue->data, pvalue->size);
840             code = cos_dict_put_c_key_string(pdev->Info, key,
841                                              pvalue->data, newsize);
842             continue;
843         } else {
844             pdf_page_dsc_info_t *ppdi;
845             char scan_buf[200]; /* arbitrary */
846 
847             if ((ppdi = &pdev->doc_dsc_info,
848                  pdf_key_eq(pkey, "Orientation")) ||
849                 (ppdi = &pdev->page_dsc_info,
850                  pdf_key_eq(pkey, "PageOrientation"))
851                 ) {
852                 if (pvalue->size == 1 && pvalue->data[0] >= '0' &&
853                     pvalue->data[0] <= '3'
854                     )
855                     ppdi->orientation = pvalue->data[0] - '0';
856                 else
857                     ppdi->orientation = -1;
858             } else if ((ppdi = &pdev->doc_dsc_info,
859                         pdf_key_eq(pkey, "ViewingOrientation")) ||
860                        (ppdi = &pdev->page_dsc_info,
861                         pdf_key_eq(pkey, "PageViewingOrientation"))
862                        ) {
863                 gs_matrix mat;
864                 int orient;
865 
866                 if(pvalue->size >= sizeof(scan_buf) - 1)
867                     continue;	/* error */
868                 memcpy(scan_buf, pvalue->data, pvalue->size);
869                 scan_buf[pvalue->size] = 0;
870                 if (sscanf(scan_buf, "[%g %g %g %g]",
871                            &mat.xx, &mat.xy, &mat.yx, &mat.yy) != 4
872                     )
873                     continue;	/* error */
874                 for (orient = 0; orient < 4; ++orient) {
875                     if (mat.xx == 1 && mat.xy == 0 && mat.yx == 0 && mat.yy == 1)
876                         break;
877                     gs_matrix_rotate(&mat, -90.0, &mat);
878                 }
879                 if (orient == 4) /* error */
880                     orient = -1;
881                 ppdi->viewing_orientation = orient;
882             } else {
883                 gs_rect box;
884 
885                 if (pdf_key_eq(pkey, "EPSF")) {
886                     pdev->is_EPS = (pvalue->size >= 1 && pvalue->data[0] != '0');
887                     continue;
888                 }
889                 /*
890                  * We only parse the BoundingBox for the sake of
891                  * AutoPositionEPSFiles.
892                  */
893                 if (pdf_key_eq(pkey, "BoundingBox"))
894                     ppdi = &pdev->doc_dsc_info;
895                 else if (pdf_key_eq(pkey, "PageBoundingBox"))
896                     ppdi = &pdev->page_dsc_info;
897                 else
898                     continue;
899                 if(pvalue->size >= sizeof(scan_buf) - 1)
900                     continue;	/* error */
901                 memcpy(scan_buf, pvalue->data, pvalue->size);
902                 scan_buf[pvalue->size] = 0;
903                 if (sscanf(scan_buf, "[%lg %lg %lg %lg]",
904                            &box.p.x, &box.p.y, &box.q.x, &box.q.y) != 4
905                     )
906                     continue;	/* error */
907                 ppdi->bounding_box = box;
908             }
909             continue;
910         }
911     }
912     return code;
913 }
914