1 /* Copyright (C) 2001-2012 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.,  7 Mt. Lassen Drive - Suite A-134, San Rafael,
13    CA  94903, 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 "gsparamx.h"
25 
26 /*
27  * The pdfwrite device supports the following "real" parameters:
28  *      OutputFile <string>
29  *      all the Distiller parameters (also see gdevpsdp.c)
30  * Only some of the Distiller parameters actually have any effect.
31  *
32  * The device also supports the following write-only pseudo-parameters that
33  * serve only to communicate other information from the PostScript file.
34  * Their "value" is an array of strings, some of which may be the result
35  * of converting arbitrary PostScript objects to string form.
36  *      pdfmark - see gdevpdfm.c
37  *	DSC - processed in this file
38  */
39 static int pdf_dsc_process(gx_device_pdf * pdev,
40                             const gs_param_string_array * pma);
41 
42 static const int CoreDistVersion = 5000;	/* Distiller 5.0 */
43 static const gs_param_item_t pdf_param_items[] = {
44 #define pi(key, type, memb) { key, type, offset_of(gx_device_pdf, memb) }
45 
46         /* Acrobat Distiller 4 parameters */
47 
48     /*
49      * EndPage and StartPage are renamed because EndPage collides with
50      * a page device parameter.
51      */
52     pi("PDFEndPage", gs_param_type_int, EndPage),
53     pi("PDFStartPage", gs_param_type_int, StartPage),
54     pi("Optimize", gs_param_type_bool, Optimize),
55     pi("ParseDSCCommentsForDocInfo", gs_param_type_bool,
56        ParseDSCCommentsForDocInfo),
57     pi("ParseDSCComments", gs_param_type_bool, ParseDSCComments),
58     pi("EmitDSCWarnings", gs_param_type_bool, EmitDSCWarnings),
59     pi("CreateJobTicket", gs_param_type_bool, CreateJobTicket),
60     pi("PreserveEPSInfo", gs_param_type_bool, PreserveEPSInfo),
61     pi("AutoPositionEPSFiles", gs_param_type_bool, AutoPositionEPSFiles),
62     pi("PreserveCopyPage", gs_param_type_bool, PreserveCopyPage),
63     pi("UsePrologue", gs_param_type_bool, UsePrologue),
64 
65         /* Acrobat Distiller 5 parameters */
66 
67     pi("OffOptimizations", gs_param_type_int, OffOptimizations),
68 
69         /* Ghostscript-specific parameters */
70 
71     pi("ReAssignCharacters", gs_param_type_bool, ReAssignCharacters),
72     pi("ReEncodeCharacters", gs_param_type_bool, ReEncodeCharacters),
73     pi("FirstObjectNumber", gs_param_type_long, FirstObjectNumber),
74     pi("CompressFonts", gs_param_type_bool, CompressFonts),
75     pi("PrintStatistics", gs_param_type_bool, PrintStatistics),
76     pi("MaxInlineImageSize", gs_param_type_long, MaxInlineImageSize),
77     pi("DSCEncodingToUnicode", gs_param_type_int_array, DSCEncodingToUnicode),
78 
79         /* PDF Encryption */
80     pi("OwnerPassword", gs_param_type_string, OwnerPassword),
81     pi("UserPassword", gs_param_type_string, UserPassword),
82     pi("KeyLength", gs_param_type_int, KeyLength),
83     pi("Permissions", gs_param_type_int, Permissions),
84     pi("EncryptionR", gs_param_type_int, EncryptionR),
85     pi("NoEncrypt", gs_param_type_string, NoEncrypt),
86 
87         /* Target viewer capabilities (Ghostscript-specific)  */
88  /* pi("ForOPDFRead", gs_param_type_bool, ForOPDFRead),			    pdfwrite-only */
89     pi("ProduceDSC", gs_param_type_bool, ProduceDSC),
90     pi("PatternImagemask", gs_param_type_bool, PatternImagemask),
91     pi("MaxClipPathSize", gs_param_type_int, MaxClipPathSize),
92     pi("MaxShadingBitmapSize", gs_param_type_int, MaxShadingBitmapSize),
93 #ifdef DEPRECATED_906
94     pi("MaxViewerMemorySize", gs_param_type_int, MaxViewerMemorySize),
95 #endif
96     pi("HaveTrueTypes", gs_param_type_bool, HaveTrueTypes),
97     pi("HaveCIDSystem", gs_param_type_bool, HaveCIDSystem),
98     pi("HaveTransparency", gs_param_type_bool, HaveTransparency),
99     pi("CompressEntireFile", gs_param_type_bool, CompressEntireFile),
100     pi("PDFX", gs_param_type_bool, PDFX),
101     pi("PDFA", gs_param_type_int, PDFA),
102     pi("DocumentUUID", gs_param_type_string, DocumentUUID),
103     pi("InstanceUUID", gs_param_type_string, InstanceUUID),
104     pi("DocumentTimeSeq", gs_param_type_int, DocumentTimeSeq),
105 
106     /* PDF/X parameters */
107     pi("PDFXTrimBoxToMediaBoxOffset", gs_param_type_float_array, PDFXTrimBoxToMediaBoxOffset),
108     pi("PDFXSetBleedBoxToMediaBox", gs_param_type_bool, PDFXSetBleedBoxToMediaBox),
109     pi("PDFXBleedBoxToTrimBoxOffset", gs_param_type_float_array, PDFXBleedBoxToTrimBoxOffset),
110 
111     /* media selection parameters */
112     pi("SetPageSize", gs_param_type_bool, SetPageSize),
113     pi("RotatePages", gs_param_type_bool, RotatePages),
114     pi("FitPages", gs_param_type_bool, FitPages),
115     pi("CenterPages", gs_param_type_bool, CenterPages),
116     pi("DoNumCopies", gs_param_type_bool, DoNumCopies),
117     pi("PreserveSeparation", gs_param_type_bool, PreserveSeparation),
118     pi("PreserveDeviceN", gs_param_type_bool, PreserveDeviceN),
119     pi("PDFACompatibilityPolicy", gs_param_type_int, PDFACompatibilityPolicy),
120     pi("DetectDuplicateImages", gs_param_type_bool, DetectDuplicateImages),
121     pi("AllowIncrementalCFF", gs_param_type_bool, AllowIncrementalCFF),
122     pi("WantsToUnicode", gs_param_type_bool, WantsToUnicode),
123     pi("AllowPSRepeatFunctions", gs_param_type_bool, AllowPSRepeatFunctions),
124     pi("IsDistiller", gs_param_type_bool, IsDistiller),
125     pi("PreserveSMask", gs_param_type_bool, PreserveSMask),
126     pi("PreserveTrMode", gs_param_type_bool, PreserveTrMode),
127     pi("NoT3CCITT", gs_param_type_bool, NoT3CCITT),
128 #undef pi
129     gs_param_item_end
130 };
131 
132 /*
133   Notes on implementing the remaining Distiller functionality
134   ===========================================================
135 
136   Architectural issues
137   --------------------
138 
139   Must optionally disable application of TR, BG, UCR similarly.  Affects:
140     PreserveHalftoneInfo
141     PreserveOverprintSettings
142     TransferFunctionInfo
143     UCRandBGInfo
144 
145   Current limitations
146   -------------------
147 
148   Non-primary elements in HalftoneType 5 are not written correctly
149 
150   Acrobat Distiller 3
151   -------------------
152 
153   ---- Image parameters ----
154 
155   AntiAlias{Color,Gray,Mono}Images
156 
157   ---- Other parameters ----
158 
159   CompressPages
160     Compress things other than page contents
161   * PreserveHalftoneInfo
162   PreserveOPIComments
163     ? see OPI spec?
164   * PreserveOverprintSettings
165   * TransferFunctionInfo
166   * UCRandBGInfo
167   ColorConversionStrategy
168     Select color space for drawing commands
169   ConvertImagesToIndexed
170     Postprocess image data *after* downsampling (requires an extra pass)
171 
172   Acrobat Distiller 4
173   -------------------
174 
175   ---- Other functionality ----
176 
177   Document structure pdfmarks
178 
179   ---- Parameters ----
180 
181   xxxDownsampleType = /Bicubic
182     Add new filter (or use siscale?) & to setup (gdevpsdi.c)
183   DetectBlends
184     Idiom recognition?  PatternType 2 patterns / shfill?  (see AD4)
185   DoThumbnails
186     Also output to memory device -- resolution issue
187 
188   ---- Job-level control ----
189 
190   EmitDSCWarnings
191     Require DSC parser / interceptor
192   CreateJobTicket
193     ?
194   AutoPositionEPSFiles
195     Require DSC parsing
196   PreserveCopyPage
197     Concatenate Contents streams
198   UsePrologue
199     Needs hack in top-level control?
200 
201 */
202 
203 /* ---------------- Get parameters ---------------- */
204 
205 /* Get parameters. */
206 int
gdev_pdf_get_params(gx_device * dev,gs_param_list * plist)207 gdev_pdf_get_params(gx_device * dev, gs_param_list * plist)
208 {
209     gx_device_pdf *pdev = (gx_device_pdf *) dev;
210     float cl = (float)pdev->CompatibilityLevel;
211     int code;
212     int cdv = CoreDistVersion;
213 
214     pdev->ParamCompatibilityLevel = cl;
215     code = gdev_psdf_get_params(dev, plist);
216     if (code < 0 ||
217         (code = param_write_int(plist, "CoreDistVersion", &cdv)) < 0 ||
218         (code = param_write_float(plist, "CompatibilityLevel", &cl)) < 0 ||
219         (!pdev->is_ps2write && (code = param_write_bool(plist, "ForOPDFRead", &pdev->ForOPDFRead)) < 0) ||
220         /* Indicate that we can process pdfmark and DSC. */
221         (param_requested(plist, "pdfmark") > 0 &&
222          (code = param_write_null(plist, "pdfmark")) < 0) ||
223         (param_requested(plist, "DSC") > 0 &&
224          (code = param_write_null(plist, "DSC")) < 0) ||
225         (code = gs_param_write_items(plist, pdev, NULL, pdf_param_items)) < 0
226         )
227     {}
228     return code;
229 }
230 
231 /* ---------------- Put parameters ---------------- */
232 
233 /* Put parameters, implementation */
234 static int
gdev_pdf_put_params_impl(gx_device * dev,const gx_device_pdf * save_dev,gs_param_list * plist)235 gdev_pdf_put_params_impl(gx_device * dev, const gx_device_pdf * save_dev, gs_param_list * plist)
236 {
237     int ecode, code;
238     gx_device_pdf *pdev = (gx_device_pdf *) dev;
239     float cl = (float)pdev->CompatibilityLevel;
240     bool locked = pdev->params.LockDistillerParams;
241     gs_param_name param_name;
242     enum psdf_color_conversion_strategy save_ccs = pdev->params.ColorConversionStrategy;
243 
244     pdev->pdf_memory = gs_memory_stable(pdev->memory);
245     /*
246      * If this is a pseudo-parameter (pdfmark or DSC),
247      * don't bother checking for any real ones.
248      */
249 
250     {
251         gs_param_string_array ppa;
252 
253         code = param_read_string_array(plist, (param_name = "pdfmark"), &ppa);
254         switch (code) {
255             case 0:
256                 code = pdfwrite_pdf_open_document(pdev);
257                 if (code < 0)
258                     return code;
259                 code = pdfmark_process(pdev, &ppa);
260                 if (code >= 0)
261                     return code;
262                 /* falls through for errors */
263             default:
264                 param_signal_error(plist, param_name, code);
265                 return code;
266             case 1:
267                 break;
268         }
269 
270         code = param_read_string_array(plist, (param_name = "DSC"), &ppa);
271         switch (code) {
272             case 0:
273                 code = pdfwrite_pdf_open_document(pdev);
274                 if (code < 0)
275                     return code;
276                 code = pdf_dsc_process(pdev, &ppa);
277                 if (code >= 0)
278                     return code;
279                 /* falls through for errors */
280             default:
281                 param_signal_error(plist, param_name, code);
282                 return code;
283             case 1:
284                 break;
285         }
286     }
287 
288     /*
289      * Check for LockDistillerParams before doing anything else.
290      * If LockDistillerParams is true and is not being set to false,
291      * ignore all resettings of PDF-specific parameters.  Note that
292      * LockDistillerParams is read again, and reset if necessary, in
293      * psdf_put_params.
294      */
295     ecode = code = param_read_bool(plist, "LockDistillerParams", &locked);
296     if (ecode < 0)
297         param_signal_error(plist, param_name, ecode);
298 
299     if (!(locked && pdev->params.LockDistillerParams)) {
300         /* General parameters. */
301 
302         {
303             int efo = 1;
304 
305             ecode = param_put_int(plist, (param_name = ".EmbedFontObjects"), &efo, ecode);
306             if (ecode < 0)
307                 param_signal_error(plist, param_name, ecode);
308             if (efo != 1)
309                 param_signal_error(plist, param_name, ecode = gs_error_rangecheck);
310         }
311         {
312             int cdv = CoreDistVersion;
313 
314             ecode = param_put_int(plist, (param_name = "CoreDistVersion"), &cdv, ecode);
315             if (ecode < 0)
316                 return gs_note_error(ecode);
317             if (cdv != CoreDistVersion)
318                 param_signal_error(plist, param_name, ecode = gs_error_rangecheck);
319         }
320 
321         switch (code = param_read_float(plist, (param_name = "CompatibilityLevel"), &cl)) {
322             default:
323                 ecode = code;
324                 param_signal_error(plist, param_name, ecode);
325             case 0:
326                 /*
327                  * Must be 1.2, 1.3, 1.4, or 1.5.  Per Adobe documentation, substitute
328                  * the nearest achievable value.
329                  */
330                 if (cl < (float)1.15)
331                     cl = (float)1.1;
332                 else if (cl < (float)1.25)
333                     cl = (float)1.2;
334                 else if (cl < (float)1.35)
335                     cl = (float)1.3;
336                 else if (cl < (float)1.45)
337                     cl = (float)1.4;
338                 else if (cl < (float)1.55)
339                     cl = (float)1.5;
340                 else if (cl < (float)1.65)
341                     cl = (float)1.6;
342                 else
343                     cl = (float)1.7;
344             case 1:
345                 break;
346         }
347         {   /* HACK : gs_param_list_s::memory is documented in gsparam.h as
348                "for allocating coerced arrays". Not sure why zputdeviceparams
349                sets it to the current memory space, while the device
350                assumes to store them in the device's memory space.
351                As a hackish workaround we temporary replace it here.
352                Doing so because we don't want to change the global code now
353                because we're unable to test it with all devices.
354                Bug 688531 "Segmentation fault running pdfwrite from 219-01.ps".
355 
356                This solution to be reconsidered after fixing
357                the bug 688533 "zputdeviceparams specifies a wrong memory space.".
358             */
359             gs_memory_t *mem = plist->memory;
360 
361             plist->memory = pdev->pdf_memory;
362             code = gs_param_read_items(plist, pdev, pdf_param_items);
363             if (code < 0 ||
364                 (!pdev->is_ps2write && (code = param_read_bool(plist, "ForOPDFRead", &pdev->ForOPDFRead)) < 0)
365                 ){
366             }
367             plist->memory = mem;
368         }
369         if (code < 0)
370             ecode = code;
371         {
372             /*
373              * Setting FirstObjectNumber is only legal if the file
374              * has just been opened and nothing has been written,
375              * or if we are setting it to the same value.
376              */
377             long fon = pdev->FirstObjectNumber;
378 
379             if (fon != save_dev->FirstObjectNumber) {
380                 if (fon <= 0 || fon > 0x7fff0000 ||
381                     (pdev->next_id != 0 &&
382                      pdev->next_id !=
383                      save_dev->FirstObjectNumber + pdf_num_initial_ids)
384                     ) {
385                     ecode = gs_error_rangecheck;
386                     param_signal_error(plist, "FirstObjectNumber", ecode);
387                 }
388             }
389         }
390         {
391             /*
392              * Set ProcessColorModel now, because gx_default_put_params checks
393              * it.
394              */
395             static const char *const pcm_names[] = {
396                 "DeviceGray", "DeviceRGB", "DeviceCMYK", "DeviceN", 0
397             };
398             int pcm = -1;
399 
400             ecode = param_put_enum(plist, "ProcessColorModel", &pcm,
401                                    pcm_names, ecode);
402             if (pcm >= 0) {
403                 pdf_set_process_color_model(pdev, pcm);
404                 pdf_set_initial_color(pdev, &pdev->saved_fill_color, &pdev->saved_stroke_color,
405                                 &pdev->fill_used_process_color, &pdev->stroke_used_process_color);
406             }
407         }
408     }
409     if (ecode < 0)
410         goto fail;
411 
412     if (pdev->is_ps2write && (code = param_read_bool(plist, "ProduceDSC", &pdev->ProduceDSC)) < 0) {
413         param_signal_error(plist, param_name, code);
414     }
415 
416     /* PDFA and PDFX are stored in the page device dictionary and therefore
417      * set on every setpagedevice. However, if we have encountered a file which
418      * can't be made this way, and the PDFACompatibilityPolicy is 1, we want to
419      * continue producing the file, but not as a PDF/A or PDF/X file. Its more
420      * or less impossible to alter the setting in the (potentially saved) page
421      * device dictionary, so we use this rather clunky method.
422      */
423     if (pdev->PDFA < 0 || pdev->PDFA > 2){
424         ecode = gs_note_error(gs_error_rangecheck);
425         param_signal_error(plist, "PDFA", ecode);
426         goto fail;
427     }
428     if(pdev->PDFA != 0 && pdev->AbortPDFAX)
429         pdev->PDFA = 0;
430     if(pdev->PDFX && pdev->AbortPDFAX)
431         pdev->PDFX = 0;
432     if (pdev->PDFX && pdev->PDFA != 0) {
433         ecode = gs_note_error(gs_error_rangecheck);
434         param_signal_error(plist, "PDFA", ecode);
435         goto fail;
436     }
437     if (pdev->PDFX && pdev->ForOPDFRead) {
438         ecode = gs_note_error(gs_error_rangecheck);
439         param_signal_error(plist, "PDFX", ecode);
440         goto fail;
441     }
442     if (pdev->PDFA != 0 && pdev->ForOPDFRead) {
443         ecode = gs_note_error(gs_error_rangecheck);
444         param_signal_error(plist, "PDFA", ecode);
445         goto fail;
446     }
447     if (pdev->PDFA == 1)
448          pdev->HaveTransparency = false;
449     /*
450      * We have to set version to the new value, because the set of
451      * legal parameter values for psdf_put_params varies according to
452      * the version.
453      */
454     if (pdev->PDFX)
455         cl = (float)1.3; /* Instead pdev->CompatibilityLevel = 1.2; - see below. */
456     if (pdev->PDFA != 0 && cl < 1.4)
457         cl = (float)1.4;
458     pdev->version = (cl < 1.2 ? psdf_version_level2 : psdf_version_ll3);
459     if (pdev->ForOPDFRead) {
460         pdev->ResourcesBeforeUsage = true;
461         pdev->HaveCFF = false;
462         pdev->HavePDFWidths = false;
463         pdev->HaveStrokeColor = false;
464         cl = (float)1.2; /* Instead pdev->CompatibilityLevel = 1.2; - see below. */
465         pdev->MaxInlineImageSize = max_long; /* Save printer's RAM from saving temporary image data.
466                                                 Immediate images doen't need buffering. */
467         pdev->version = psdf_version_level2;
468     } else {
469         pdev->ResourcesBeforeUsage = false;
470         pdev->HaveCFF = true;
471         pdev->HavePDFWidths = true;
472         pdev->HaveStrokeColor = true;
473     }
474     pdev->ParamCompatibilityLevel = cl;
475     if (cl < 1.2) {
476         pdev->HaveCFF = false;
477     }
478     ecode = gdev_psdf_put_params(dev, plist);
479     if (ecode < 0)
480         goto fail;
481     if ((pdev->params.ColorConversionStrategy == ccs_CMYK &&
482          strcmp(pdev->color_info.cm_name, "DeviceCMYK")) ||
483         (pdev->params.ColorConversionStrategy == ccs_sRGB &&
484           strcmp(pdev->color_info.cm_name, "DeviceRGB")) ||
485         (pdev->params.ColorConversionStrategy == ccs_Gray &&
486           strcmp(pdev->color_info.cm_name, "DeviceGray"))) {
487         emprintf(pdev->memory,
488                  "ColorConversionStrategy is incompatible to ProcessColorModel.\n");
489         ecode = gs_note_error(gs_error_rangecheck);
490         pdev->params.ColorConversionStrategy = save_ccs;
491     }
492     if (pdev->params.ColorConversionStrategy == ccs_UseDeviceIndependentColor) {
493         if (!pdev->UseCIEColor) {
494             emprintf(pdev->memory,
495                      "Set UseCIEColor for UseDeviceIndependentColor to work properly.\n");
496             ecode = gs_note_error(gs_error_rangecheck);
497             pdev->UseCIEColor = true;
498         }
499     }
500     if (pdev->params.ColorConversionStrategy == ccs_UseDeviceIndependentColorForImages) {
501         if (!pdev->UseCIEColor) {
502             emprintf(pdev->memory,
503                      "UseDeviceDependentColorForImages is not supported. Use UseDeviceIndependentColor.\n");
504             pdev->params.ColorConversionStrategy = ccs_UseDeviceIndependentColor;
505             if (!pdev->UseCIEColor) {
506                 emprintf(pdev->memory,
507                          "Set UseCIEColor for UseDeviceIndependentColor to work properly.\n");
508                 ecode = gs_note_error(gs_error_rangecheck);
509                 pdev->UseCIEColor = true;
510             }
511         }
512     }
513     if (pdev->params.ColorConversionStrategy == ccs_UseDeviceDependentColor) {
514         if (!strcmp(pdev->color_info.cm_name, "DeviceCMYK")) {
515             emprintf(pdev->memory,
516                      "Replacing the deprecated device parameter value UseDeviceDependentColor with CMYK.\n");
517             pdev->params.ColorConversionStrategy = ccs_CMYK;
518         } else if (!strcmp(pdev->color_info.cm_name, "DeviceRGB")) {
519             emprintf(pdev->memory,
520                      "Replacing the deprecated device parameter value UseDeviceDependentColor with sRGB.\n");
521             pdev->params.ColorConversionStrategy = ccs_sRGB;
522         } else {
523             emprintf(pdev->memory,
524                      "Replacing the deprecated device parameter value UseDeviceDependentColor with Gray.\n");
525             pdev->params.ColorConversionStrategy = ccs_Gray;
526         }
527     }
528     if (cl < 1.5 && pdev->params.ColorImage.Filter != NULL &&
529             !strcmp(pdev->params.ColorImage.Filter, "JPXEncode")) {
530         emprintf(pdev->memory,
531                  "JPXEncode requires CompatibilityLevel >= 1.5 .\n");
532         ecode = gs_note_error(gs_error_rangecheck);
533     }
534     if (cl < 1.5 && pdev->params.GrayImage.Filter != NULL &&
535             !strcmp(pdev->params.GrayImage.Filter, "JPXEncode")) {
536         emprintf(pdev->memory,
537                  "JPXEncode requires CompatibilityLevel >= 1.5 .\n");
538         ecode = gs_note_error(gs_error_rangecheck);
539     }
540     if (cl < 1.4  && pdev->params.MonoImage.Filter != NULL &&
541             !strcmp(pdev->params.MonoImage.Filter, "JBIG2Encode")) {
542         emprintf(pdev->memory,
543                  "JBIG2Encode requires CompatibilityLevel >= 1.4 .\n");
544         ecode = gs_note_error(gs_error_rangecheck);
545     }
546     if (pdev->HaveTrueTypes && pdev->version == psdf_version_level2) {
547         pdev->version = psdf_version_level2_with_TT ;
548     }
549     /*
550      * Acrobat Reader doesn't handle user-space coordinates larger than
551      * MAX_USER_COORD.  To compensate for this, reduce the resolution so
552      * that the page size in device space (which we equate to user space) is
553      * significantly less than MAX_USER_COORD.  Note that this still does
554      * not protect us against input files that use coordinates far outside
555      * the page boundaries.
556      */
557 #define MAX_EXTENT ((int)(MAX_USER_COORD * 0.9))
558     /* Changing resolution or page size requires closing the device, */
559     if (dev->height > MAX_EXTENT || dev->width > MAX_EXTENT) {
560         double factor =
561             max(dev->height / (double)MAX_EXTENT,
562                 dev->width / (double)MAX_EXTENT);
563 
564         gx_device_set_resolution(dev, dev->HWResolution[0] / factor,
565                                  dev->HWResolution[1] / factor);
566     }
567 #undef MAX_EXTENT
568     if (pdev->FirstObjectNumber != save_dev->FirstObjectNumber) {
569         if (pdev->xref.file != 0) {
570             gp_fseek_64(pdev->xref.file, 0L, SEEK_SET);
571             pdf_initialize_ids(pdev);
572         }
573     }
574     /* Handle the float/double mismatch. */
575     pdev->CompatibilityLevel = (int)(cl * 10 + 0.5) / 10.0;
576     if(pdev->OwnerPassword.size != save_dev->OwnerPassword.size ||
577         (pdev->OwnerPassword.size != 0 &&
578          memcmp(pdev->OwnerPassword.data, save_dev->OwnerPassword.data,
579          pdev->OwnerPassword.size) != 0)) {
580         if (pdev->is_open) {
581             if (pdev->PageCount == 0) {
582                 gs_closedevice((gx_device *)save_dev);
583                 return 0;
584             }
585             else
586                 emprintf(pdev->memory, "Owner Password changed mid-job, ignoring.\n");
587         }
588     }
589     return 0;
590  fail:
591     /* Restore all the parameters to their original state. */
592     pdev->version = save_dev->version;
593     pdf_set_process_color_model(pdev, save_dev->pcm_color_info_index);
594     pdev->saved_fill_color = save_dev->saved_fill_color;
595     pdev->saved_stroke_color = save_dev->saved_fill_color;
596     {
597         const gs_param_item_t *ppi = pdf_param_items;
598 
599         for (; ppi->key; ++ppi)
600             memcpy((char *)pdev + ppi->offset,
601                    (char *)save_dev + ppi->offset,
602                    gs_param_type_sizes[ppi->type]);
603         pdev->ForOPDFRead = save_dev->ForOPDFRead;
604     }
605     return ecode;
606 }
607 
608 /* Put parameters */
609 int
gdev_pdf_put_params(gx_device * dev,gs_param_list * plist)610 gdev_pdf_put_params(gx_device * dev, gs_param_list * plist)
611 {
612     int code;
613     gx_device_pdf *pdev = (gx_device_pdf *) dev;
614     gs_memory_t *mem = gs_memory_stable(pdev->memory);
615     gx_device_pdf *save_dev = gs_malloc(mem, sizeof(gx_device_pdf), 1,
616         "saved gx_device_pdf");
617 
618     if (!save_dev)
619         return_error(gs_error_VMerror);
620     memcpy(save_dev, pdev, sizeof(gx_device_pdf));
621     code = gdev_pdf_put_params_impl(dev, save_dev, plist);
622     gs_free(mem, save_dev, sizeof(gx_device_pdf), 1, "saved gx_device_pdf");
623     return code;
624 }
625 
626 /* ---------------- Process DSC comments ---------------- */
627 
628 static int
pdf_dsc_process(gx_device_pdf * pdev,const gs_param_string_array * pma)629 pdf_dsc_process(gx_device_pdf * pdev, const gs_param_string_array * pma)
630 {
631     /*
632      * The Adobe "Distiller Parameters" documentation says that Distiller
633      * looks at DSC comments, but it doesn't say which ones.  We look at
634      * the ones that we see how to map directly to obvious PDF constructs.
635      */
636     int code = 0;
637     uint i;
638 
639     /*
640      * If ParseDSCComments is false, all DSC comments are ignored, even if
641      * ParseDSCComentsForDocInfo or PreserveEPSInfo is true.
642      */
643     if (!pdev->ParseDSCComments)
644         return 0;
645 
646     for (i = 0; i + 1 < pma->size && code >= 0; i += 2) {
647         const gs_param_string *pkey = &pma->data[i];
648         const gs_param_string *pvalue = &pma->data[i + 1];
649         const char *key;
650         int code;
651 
652         /*
653          * %%For, %%Creator, and %%Title are recognized only if either
654          * ParseDSCCommentsForDocInfo or PreserveEPSInfo is true.
655          * The other DSC comments are always recognized.
656          *
657          * Acrobat Distiller sets CreationDate and ModDate to the current
658          * time, not the value of %%CreationDate.  We think this is wrong,
659          * but we do the same -- we ignore %%CreationDate here.
660          */
661 
662         if (pdf_key_eq(pkey, "Creator"))
663             key = "/Creator";
664         else if (pdf_key_eq(pkey, "Title"))
665             key = "/Title";
666         else if (pdf_key_eq(pkey, "For"))
667             key = "/Author";
668         else {
669             pdf_page_dsc_info_t *ppdi;
670             char scan_buf[200]; /* arbitrary */
671 
672             if ((ppdi = &pdev->doc_dsc_info,
673                  pdf_key_eq(pkey, "Orientation")) ||
674                 (ppdi = &pdev->page_dsc_info,
675                  pdf_key_eq(pkey, "PageOrientation"))
676                 ) {
677                 if (pvalue->size == 1 && pvalue->data[0] >= '0' &&
678                     pvalue->data[0] <= '3'
679                     )
680                     ppdi->orientation = pvalue->data[0] - '0';
681                 else
682                     ppdi->orientation = -1;
683             } else if ((ppdi = &pdev->doc_dsc_info,
684                         pdf_key_eq(pkey, "ViewingOrientation")) ||
685                        (ppdi = &pdev->page_dsc_info,
686                         pdf_key_eq(pkey, "PageViewingOrientation"))
687                        ) {
688                 gs_matrix mat;
689                 int orient;
690 
691                 if(pvalue->size >= sizeof(scan_buf) - 1)
692                     continue;	/* error */
693                 memcpy(scan_buf, pvalue->data, pvalue->size);
694                 scan_buf[pvalue->size] = 0;
695                 if (sscanf(scan_buf, "[%g %g %g %g]",
696                            &mat.xx, &mat.xy, &mat.yx, &mat.yy) != 4
697                     )
698                     continue;	/* error */
699                 for (orient = 0; orient < 4; ++orient) {
700                     if (mat.xx == 1 && mat.xy == 0 && mat.yx == 0 && mat.yy == 1)
701                         break;
702                     gs_matrix_rotate(&mat, -90.0, &mat);
703                 }
704                 if (orient == 4) /* error */
705                     orient = -1;
706                 ppdi->viewing_orientation = orient;
707             } else {
708                 gs_rect box;
709 
710                 if (pdf_key_eq(pkey, "EPSF")) {
711                     pdev->is_EPS = (pvalue->size >= 1 && pvalue->data[0] != '0');
712                     continue;
713                 }
714                 /*
715                  * We only parse the BoundingBox for the sake of
716                  * AutoPositionEPSFiles.
717                  */
718                 if (pdf_key_eq(pkey, "BoundingBox"))
719                     ppdi = &pdev->doc_dsc_info;
720                 else if (pdf_key_eq(pkey, "PageBoundingBox"))
721                     ppdi = &pdev->page_dsc_info;
722                 else
723                     continue;
724                 if(pvalue->size >= sizeof(scan_buf) - 1)
725                     continue;	/* error */
726                 memcpy(scan_buf, pvalue->data, pvalue->size);
727                 scan_buf[pvalue->size] = 0;
728                 if (sscanf(scan_buf, "[%lg %lg %lg %lg]",
729                            &box.p.x, &box.p.y, &box.q.x, &box.q.y) != 4
730                     )
731                     continue;	/* error */
732                 ppdi->bounding_box = box;
733             }
734             continue;
735         }
736 
737         if (pdev->ParseDSCCommentsForDocInfo || pdev->PreserveEPSInfo)
738             code = cos_dict_put_c_key_string(pdev->Info, key,
739                                              pvalue->data, pvalue->size);
740     }
741     return code;
742 }
743