]> git.ipfire.org Git - thirdparty/cups-filters.git/commitdiff
libcupsfilters: Let filter functions not load or modify PPD file data
authorTill Kamppeter <till.kamppeter@gmail.com>
Fri, 8 Apr 2022 19:23:26 +0000 (21:23 +0200)
committerTill Kamppeter <till.kamppeter@gmail.com>
Fri, 8 Apr 2022 19:23:26 +0000 (21:23 +0200)
Let the filter functions not load the PPD file data and not mark
options in the PPD file data to make them better usable with Printer
Applications and to avoid race conditions in filter chains.

To keep the behavior of CUPS filters, changed the
cfFilterCUPSWrapper() function and the implicitclass CUPS backend
appropriately.

Also added support for direct Apple Raster output to the
cfFilterPDFToRaster() (Poppler) filter function and fixed a bug in the
output format selection in the cfFilterRasterToPWG() filter function.

backend/implicitclass.c
cupsfilters/bannertopdf.c
cupsfilters/filter.c
cupsfilters/filter.h
cupsfilters/pclmtoraster.cxx
cupsfilters/pdftoraster.cxx
cupsfilters/pwgtoraster.c
cupsfilters/rastertopwg.c
cupsfilters/universal.c
mime/cupsfilters-poppler.convs

index 090460ccd0767f9829fb89b55fff6fb57f3e2398..d3b7f10fec4a4460fae5d8c60c1590e5e45e137b 100644 (file)
@@ -330,17 +330,6 @@ main(int  argc,                            /* I - Number of command-line args */
                                              PPD file here which contains
                                              some info from the printer's
                                              DNS-SD record. */
-      if (filter_data.ppdfile)
-       filter_data.ppd = ppdOpenFile(filter_data.ppdfile);
-      else
-       filter_data.ppd = NULL;
-      if (filter_data.printer_attrs == NULL && filter_data.ppd == NULL)
-      {
-       ippDelete(response);
-       fprintf(stderr, "ERROR: Unable to get sufficient capability info of the destination printer.\n");
-       return (CUPS_BACKEND_FAILED);
-      }
-
       filter_data.num_options = num_options;
       filter_data.options = options;       /* Command line options from 5th
                                              arg */
@@ -353,6 +342,15 @@ main(int  argc,                            /* I - Number of command-line args */
       filter_data.iscanceledfunc = cfCUPSIsCanceledFunc; /* Job-is-canceled
                                                           function */
       filter_data.iscanceleddata = &job_canceled;
+
+      cfFilterLoadPPD(&filter_data);
+      if (filter_data.printer_attrs == NULL && filter_data.ppd == NULL)
+      {
+       ippDelete(response);
+       fprintf(stderr, "ERROR: Unable to get sufficient capability info of the destination printer.\n");
+       return (CUPS_BACKEND_FAILED);
+      }
+
       cfFilterOpenBackAndSidePipes(&filter_data);
 
       /* Parameters (input/output MIME types) for cfFilterUniversal() call */
@@ -389,13 +387,6 @@ main(int  argc,                            /* I - Number of command-line args */
       /* FINAL_CONTENT_TYPE environment variable */
       setenv("FINAL_CONTENT_TYPE", document_format, 1);
 
-      /* Mark the defaults and option settings in the PPD file */
-      if (filter_data.ppd)
-      {
-       ppdMarkDefaults(filter_data.ppd);
-       ppdMarkOptions(filter_data.ppd, num_options, options);
-      }
-
       /* We call the IPP CUPS backend at the end of the chain, so we have
         no output */
       nullfd = open("/dev/null", O_WRONLY);
@@ -409,6 +400,7 @@ main(int  argc,                             /* I - Number of command-line args */
       /* Clean up */
       cupsArrayDelete(filter_chain);
       ippDelete(response);
+      cfFilterFreePPD(&filter_data);
 
       if (retval) {
        fprintf(stderr, "ERROR: Job processing failed.\n");
index 5fdcff0abcfb95b05eef91148a5f60db6b284a81..ae7b7e1aedcc57d3aadd6f2e441de2a107d12b30 100644 (file)
@@ -1011,7 +1011,6 @@ int cfFilterBannerToPDF(int inputfd,         /* I - File descriptor input stream
 {
     banner_t *banner;
     int num_options = 0;
-    ppd_file_t *ppd = NULL;
     int ret;
     FILE *inputfp;
     FILE *outputfp;
@@ -1087,18 +1086,6 @@ int cfFilterBannerToPDF(int inputfd,         /* I - File descriptor input stream
         return (1);
     }
 
-    if (data->ppd)
-        ppd = data->ppd;
-    else if (data->ppdfile)
-        ppd = ppdOpenFile(data->ppdfile);
-
-
-    if (!ppd)
-    {
-        if (log)
-            log(ld, CF_LOGLEVEL_DEBUG, "cfFilterBannerToPDF: Could not open PPD file '%s'", ppd);
-    }
-
    /*
     * Parse the instructions...
     */
index 852998ba65770a8fdc2c983b6f61b2b2f204b086..5882fcf9133a755e87e9cffc18a24e15d5412ffc 100644 (file)
@@ -216,9 +216,6 @@ cfFilterCUPSWrapper(
   filter_data.options = options;       /* Command line options from 5th arg */
   filter_data.ppdfile = getenv("PPD"); /* PPD file name in the "PPD"
                                          environment variable. */
-  filter_data.ppd = filter_data.ppdfile ?
-                    ppdOpenFile(filter_data.ppdfile) : NULL;
-                                       /* Load PPD file */
   filter_data.back_pipe[0] = 3;        /* CUPS uses file descriptor 3 for */
   filter_data.back_pipe[1] = 3;        /* the back channel */
   filter_data.side_pipe[0] = 4;        /* CUPS uses file descriptor 4 for */
@@ -230,30 +227,86 @@ cfFilterCUPSWrapper(
   filter_data.iscanceleddata = JobCanceled;
 
  /*
-  * Prepare PPD file
+  * Load and prepare the PPD file
   */
 
-  ppdMarkDefaults(filter_data.ppd);
-  ppdMarkOptions(filter_data.ppd, filter_data.num_options, filter_data.options);
+  retval = cfFilterLoadPPD(&filter_data);
 
  /*
   * Fire up the filter function (output to stdout, file descriptor 1)
   */
 
-  retval = filter(inputfd, 1, inputseekable, &filter_data, parameters);
+  if (!retval)
+    retval = filter(inputfd, 1, inputseekable, &filter_data, parameters);
 
  /*
   * Clean up
   */
 
   cupsFreeOptions(num_options, options);
-  if (filter_data.ppd)
-    ppdClose(filter_data.ppd);
+  cfFilterFreePPD(&filter_data);
 
   return retval;
 }
 
 
+/*
+ * 'cfFilterLoadPPD()' - When preparing the data structure for calling
+ *                       one or more filter functions. Load the PPD
+ *                       file specified by the file name in the
+ *                       "ppdfile" field of the data structure. If the
+ *                       file name is NULL do nothing. If the PPD got
+ *                       successfully loaded also set up its cache,
+ *                       and mark default settings and if supplied in
+ *                       the data structure, also option settings.
+ */
+
+int                                      /* O - Error status */
+cfFilterLoadPPD(cf_filter_data_t *data)   /* I - Job and printer data */
+{
+  cf_logfunc_t     log = data->logfunc;   /* Log function */
+  void             *ld = data->logdata;   /* log function data */
+
+  if (data->ppdfile == NULL)
+  {
+    data->ppd = NULL;
+    return (0);
+  }
+
+  if ((data->ppd = ppdOpenFile(data->ppdfile)) == NULL)
+  {
+    if (log) log(ld, CF_LOGLEVEL_ERROR,
+                "cfFilterLoadPPD: Could not load PPD file %s: %s",
+                data->ppdfile, strerror(errno));
+    return (1);
+  }
+
+  data->ppd->cache = ppdCacheCreateWithPPD(data->ppd);
+  ppdMarkDefaults(data->ppd);
+  ppdMarkOptions(data->ppd, data->num_options, data->options);
+
+  return (0);
+}
+
+
+/*
+ * 'cfFilterFreePPD()' - After being done with the filter functions
+ *                       Free the memory used by the PPD file data in
+ *                       the data structure. If the pomiter to the PPD
+ *                       file data "ppd" is NULL, do nothing.
+ */
+
+void
+cfFilterFreePPD(cf_filter_data_t *data) /* I - Job and printer data */
+{
+  if (data->ppd == NULL)
+    return;
+
+  /* ppdClose() frees not only the main data structure but also the cache */
+  ppdClose(data->ppd);
+}
+
+
 /*
  * 'cfFilterTee()' - This filter function is mainly for debugging. it
  *                 resembles the "tee" utility, passing through the
index e9f517115afc8d11f246b1f3220246cd0ca329b1..baf3157b4e5b33ef87e6ed295583c1951fa6f587 100644 (file)
@@ -153,6 +153,12 @@ extern int cfFilterCUPSWrapper(int argc,
                               int *JobCanceled);
 
 
+extern int cfFilterLoadPPD(cf_filter_data_t *data);
+
+
+extern void cfFilterFreePPD(cf_filter_data_t *data);
+
+
 extern int cfFilterTee(int inputfd,
                       int outputfd,
                       int inputseekable,
@@ -325,13 +331,10 @@ extern int cfFilterPDFToRaster(int inputfd,
 
 /* Parameters: cf_filter_out_format_t*
    Ouput format: CUPS Raster, PWG Raster, Apple Raster, PCLm
-   Note: With Apple Raster or PCLm selections the output is actually
-   CUPS Raster but information about available color spaces and depths
-   is taken from the urf-supported printer IPP attribute or the
-   appropriate PPD file attribute (PCLM is always sRGB 8-bit). These
-   modes are for further processing with rastertopwg or
-   rastertopclm. This can change in the future when we add Apple
-   Raster output support to this filter. */
+   Note: With PCLm selection the output is actually CUPS Raster but
+   color space and depth will be 8-bit sRGB or SGray, the only color
+   spaces supported by PCLm. This mode is for further processing with
+   rastertopclm. */
 
 
 extern int cfFilterPSToPS(int inputfd,
index 8498b8cd84dfe2b3c27c14c0c5ac1b5913a68d01..7bf0b6789b2e517e87e3247bf96b77af9cf8ab83 100644 (file)
@@ -103,17 +103,11 @@ parseOpts(cf_filter_data_t *data, cf_filter_out_format_t outformat,
 
   num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
 
-  if (data->ppd)
-    ppd = data->ppd;
-  else if (data->ppdfile)
-    ppd = data->ppd = ppdOpenFile(data->ppdfile);
-
   if (ppd)
   {
-    ppdMarkOptions(ppd, num_options, options);
     if ((attr = ppdFindAttr(ppd,"PWGRaster",0)) != 0 &&
-        (!strcasecmp(attr->value, "true")
-         || !strcasecmp(attr->value, "on") ||
+       (!strcasecmp(attr->value, "true")
+        || !strcasecmp(attr->value, "on") ||
          !strcasecmp(attr->value, "yes")))
       pclmtoraster_data->outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
   }
index 3e89fd157bbc4eef185a4a1f0b01287ba1464ff1..1fc9d1d885caa74ee2939e8bdf5492bc50a501ea 100644 (file)
@@ -297,12 +297,9 @@ static void  handleRqeuiresPageRegion(pdftoraster_doc_t*doc) {
 }
 
 static int parseOpts(cf_filter_data_t *data,
-                    void *parameters,
+                    cf_filter_out_format_t outformat,
                     pdftoraster_doc_t *doc)
 {
-#ifdef HAVE_CUPS_1_7
-  cf_filter_out_format_t outformat;
-#endif /* HAVE_CUPS_1_7 */
   int num_options = 0;
   cups_option_t *options = NULL;
   char *profile = NULL;
@@ -314,49 +311,23 @@ static int parseOpts(cf_filter_data_t *data,
   ipp_t *printer_attrs = data->printer_attrs;
   cups_cspace_t cspace = (cups_cspace_t)(-1);
 
-  /* Note: With the CF_FILTER_OUT_FORMAT_APPLE_RASTER or CF_FILTER_OUT_FORMAT_PCLM
-     selections the output is actually CUPS Raster but information
-     about available color spaces and depths is taken from the
-     urf-supported printer IPP attribute or the appropriate PPD file
-     attribute (PCLM is always sRGB 8-bit). These modes are for
-     further processing with rastertopwg or rastertopclm. This can
-     change in the future when we add Apple Raster output support to
-     this filter. */
-
-  if (parameters) {
-    outformat = *(cf_filter_out_format_t *)parameters;
-    if (outformat != CF_FILTER_OUT_FORMAT_CUPS_RASTER &&
-       outformat != CF_FILTER_OUT_FORMAT_PWG_RASTER &&
-       outformat != CF_FILTER_OUT_FORMAT_APPLE_RASTER &&
-       outformat != CF_FILTER_OUT_FORMAT_PCLM)
-      outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
-  } else
-    outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
-
-  if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "cfFilterPDFToRaster: Output format: %s",
-              (outformat == CF_FILTER_OUT_FORMAT_CUPS_RASTER ? "CUPS Raster" :
-               "PWG Raster"));
-
-  if (outformat == CF_FILTER_OUT_FORMAT_PWG_RASTER)
+  if (outformat == CF_FILTER_OUT_FORMAT_PWG_RASTER ||
+      outformat == CF_FILTER_OUT_FORMAT_APPLE_RASTER)
     doc->pwgraster = 1;
 
   num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
 
-  if (data->ppd)
-    doc->ppd = data->ppd;
-  else if (data->ppdfile)
-    doc->ppd = ppdOpenFile(data->ppdfile);
+  doc->ppd = data->ppd;
 
-  if (doc->ppd) {
-    ppdMarkOptions(doc->ppd,num_options,options);
+  if (doc->ppd)
     handleRqeuiresPageRegion(doc);
-  else
+  else
     if (log) log(ld, CF_LOGLEVEL_DEBUG,
       "cfFilterPDFToRaster: PPD file is not specified.");
 
   cfRasterPrepareHeader(&(doc->header), data, outformat,
-                         (outformat == CF_FILTER_OUT_FORMAT_PWG_RASTER ?
+                         (outformat == CF_FILTER_OUT_FORMAT_PWG_RASTER ||
+                          outformat == CF_FILTER_OUT_FORMAT_APPLE_RASTER ?
                           outformat : CF_FILTER_OUT_FORMAT_CUPS_RASTER), 0,
                          &cspace);
 
@@ -1596,6 +1567,7 @@ int cfFilterPDFToRaster(int inputfd,         /* I - File descriptor input stream
        cf_filter_data_t *data,          /* I - Job and printer data */
        void *parameters)             /* I - Filter-specific parameters */
 {
+  cf_filter_out_format_t outformat;
   pdftoraster_doc_t doc;
   int i;
   int npages = 0;
@@ -1613,6 +1585,29 @@ int cfFilterPDFToRaster(int inputfd,         /* I - File descriptor input stream
   (void)inputseekable;
   cmsSetLogErrorHandler(lcmsErrorHandler);
 
+  /* Note: With the CF_FILTER_OUT_FORMAT_PCLM selection the output is
+     actually CUPS Raster but color spaces and depth are always
+     assumed to be 8-bit sRGB or sGray, the only color spaces in
+     PCLm. This mode is for further processing with rastertopclm. */
+
+  if (parameters) {
+    outformat = *(cf_filter_out_format_t *)parameters;
+    if (outformat != CF_FILTER_OUT_FORMAT_CUPS_RASTER &&
+       outformat != CF_FILTER_OUT_FORMAT_PWG_RASTER &&
+       outformat != CF_FILTER_OUT_FORMAT_APPLE_RASTER &&
+       outformat != CF_FILTER_OUT_FORMAT_PCLM)
+      outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
+  } else
+    outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
+
+  if (log) log(ld, CF_LOGLEVEL_DEBUG,
+              "cfFilterPDFToRaster: Final output format: %s",
+              (outformat == CF_FILTER_OUT_FORMAT_CUPS_RASTER ? "CUPS Raster" :
+               (outformat == CF_FILTER_OUT_FORMAT_PWG_RASTER ? "PWG Raster" :
+                (outformat == CF_FILTER_OUT_FORMAT_APPLE_RASTER ?
+                 "Apple Raster" :
+                 "PCLm"))));
+
  /*
   * Open the input data stream specified by inputfd ...
   */
@@ -1657,7 +1652,7 @@ int cfFilterPDFToRaster(int inputfd,         /* I - File descriptor input stream
   }
   close(fd);
 
-  if (parseOpts(data, parameters, &doc) == 1)
+  if (parseOpts(data, outformat, &doc) == 1)
   {
     unlink(name);
     return (1);
@@ -1774,8 +1769,17 @@ int cfFilterPDFToRaster(int inputfd,         /* I - File descriptor input stream
     }
   }
 
-  if ((raster = cupsRasterOpen(outputfd, doc.pwgraster ? CUPS_RASTER_WRITE_PWG :
-                              CUPS_RASTER_WRITE)) == 0) {
+  if ((raster = cupsRasterOpen(outputfd, (outformat ==
+                                         CF_FILTER_OUT_FORMAT_CUPS_RASTER ?
+                                         CUPS_RASTER_WRITE :
+                                         (outformat ==
+                                          CF_FILTER_OUT_FORMAT_PWG_RASTER ?
+                                          CUPS_RASTER_WRITE_PWG :
+                                          (outformat ==
+                                           CF_FILTER_OUT_FORMAT_APPLE_RASTER ?
+                                           CUPS_RASTER_WRITE_APPLE :
+                                           CUPS_RASTER_WRITE))))) == 0)
+  {
     if (log) log(ld, CF_LOGLEVEL_ERROR,
                 "cfFilterPDFToRaster: Cannot open raster stream.");
     ret = 1;
index 1e4dea172d84b6f917dcfc5ec2e03dacdeb38ba7..da1666d3827c0353929006e3526b10193865332a 100644 (file)
@@ -301,10 +301,7 @@ static int parseOpts(cf_filter_data_t *data,
 
   num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
   
-  if (data->ppd)
-    doc->ppd = data->ppd;
-  else if (data->ppdfile)
-    doc->ppd = data->ppd = ppdOpenFile(data->ppdfile);
+  doc->ppd = data->ppd;
 
   // Did the user explicitly request a certain page size? If not, overtake
   // the page size(s) from the input pages
index fc96d5c64d1d0e99358c156adc66ed703c517f6b..ccb40093837363744445a9577d509717040aa95b 100644 (file)
@@ -48,8 +48,8 @@ cfFilterRasterToPWG(int inputfd,         /* I - File descriptor input stream */
   int                  tmp;
   unsigned char                white;          /* White pixel */
        /* PPD file */
-  ppd_attr_t           *back;          /* cupsBackSide attribute */
-  ppd_cache_t          *cache;         /* PPD cache */
+  ppd_attr_t           *back = NULL;   /* cupsBackSide attribute */
+  ppd_cache_t          *cache = NULL;  /* PPD cache */
   pwg_size_t           *pwg_size;      /* PWG media size */
   pwg_media_t          *pwg_media;     /* PWG media name */
        /* Number of options */
@@ -67,7 +67,7 @@ cfFilterRasterToPWG(int inputfd,         /* I - File descriptor input stream */
     output_format = *(cf_filter_out_format_t *)parameters;
     if (output_format == CF_FILTER_OUT_FORMAT_PWG_RASTER)
       outras = cupsRasterOpen(outputfd, CUPS_RASTER_WRITE_PWG);
-    if (output_format == CF_FILTER_OUT_FORMAT_APPLE_RASTER)
+    else if (output_format == CF_FILTER_OUT_FORMAT_APPLE_RASTER)
       outras = cupsRasterOpen(outputfd, CUPS_RASTER_WRITE_APPLE);
     else
     {
@@ -85,18 +85,16 @@ cfFilterRasterToPWG(int inputfd,         /* I - File descriptor input stream */
 
   inras  = cupsRasterOpen(inputfd, CUPS_RASTER_READ);
 
-  if (data->ppd == NULL && data->ppdfile)
-    data->ppd = ppdOpenFile(data->ppdfile);
-
-  back = ppdFindAttr(data->ppd, "cupsBackSide", NULL);
-
   if (!data->ppd)
   {
     if (log) log(ld, CF_LOGLEVEL_DEBUG,
      "cfFilterRasterToPWG: PPD file is not specified.");
   }
-
-  cache = data->ppd ? data->ppd->cache : NULL;
+  else
+  {
+    back = ppdFindAttr(data->ppd, "cupsBackSide", NULL);
+    cache = data->ppd->cache;
+  }
 
   while (cupsRasterReadHeader2(inras, &inheader))
   {
index d9129067b9819957381e2edccc75c5db08f56892..80513ae6934829e7c7a3859975217eea7390d3ec 100644 (file)
@@ -54,13 +54,7 @@ cfFilterUniversal(int inputfd,         /* I - File descriptor input stream */
   }
   strncpy(output, final_output, sizeof(output) - 1);
 
-  /* If we have a PPD, load it and its cache, so that we can access the
-     "*cupsFilter(2): ..." lines */
-  if (data->ppd == NULL && data->ppdfile)
-    data->ppd = ppdOpenFile(data->ppdfile);
   ppd = data->ppd;
-  if (ppd && !ppd->cache)
-    ppd->cache = ppdCacheCreateWithPPD(ppd);
   cache = ppd ? ppd->cache : NULL;
 
   /* Check whether our output format (under CUPS it is taken from the
index 4fd91c1e715513a9fa9aec0b90b226c5cb052370..2796f002c6e1db869d033329f22d24bbc39b53e6 100644 (file)
@@ -17,3 +17,4 @@
 
 application/vnd.cups-pdf       application/vnd.cups-raster     100     pdftoraster
 application/vnd.cups-pdf       image/pwg-raster                100     pdftoraster
+application/vnd.cups-pdf       image/urf                       100     pdftoraster