]> git.ipfire.org Git - thirdparty/cups-filters.git/commitdiff
libcupsfilters, libppd: Separated PPD file support from libcupsfilters
authorTill Kamppeter <till.kamppeter@gmail.com>
Thu, 11 Aug 2022 12:51:35 +0000 (14:51 +0200)
committerTill Kamppeter <till.kamppeter@gmail.com>
Thu, 11 Aug 2022 12:51:35 +0000 (14:51 +0200)
This commit reverses the dependencies of the libcupsfilters and libppd
libraries. Instead of libcupsfilters depending on libppd no libppd
depends on libcupsfilters.

This is important for removing PPD file support from OS distributions
and so allow discontinuing the maintenance of PPD-file-supporting code
in the future. In a later step libppd and the filter executables for
CUPS will get separated from the cups-filters project/repository into
their own projects/repositories.

CUPS will not use PPD files any more from version 3.0.0 on, but go
all-IPP instead. CUPS iteself will only support driverless IPP
printers (IPP Everywhere, AirPrint, Mopria) and no classic printer
drivers which consist of PPD files and filter/backend executables any
more. For printers which still need drivers Printer Applications ar
the new driver format. A Printer Application is a software emulation
of a driverless IPP printer which on the other end talks with the
physical printer.

These modifications introduce several changes on the APIs of
libcupsfilters and libppd. Software depending on these libraries (like
pappl-retrofit) needs to get adapted. All filter executables,
backends, and utilities included in cups-filters got already adapted
with this commit.

The following changes have been done:

- cf_filter_data_t gets support for an array of named extension data
  structures and does not support field for the PPD name and data any
  more. libppd defines an extension named "libppd" to hold PPD name
  and data.  Filter functions (of libppd) which explicitly use/support
  PPD files access the PPD file through this extension, others simply
  ignore the extension if present.

- All filter functions in libcupsfilters drop PPD support completely.
  They get printer-specific data only by the printer IPP attributes
  and by option settings in the option list of the cf_filter_data_t
  structure. The full functionality of each filter function is
  conserved.

- Filter functions which process or generate raster data can also get
  the parameters for the raster data as a CUPS Raster sample header.

- To continue offering PPD-supporting CUPS filters libppd provides the
  ppdLoadAttributes() to convert a PPD file into printer IPP
  attributes, the ppdFilterLoadPPD() to convert further PPD attributes
  which have no IPP equivalent into option settings and a CUPS Raster
  sample header, and the wrapper function ppdFilterCUPSWrapper()
  called by the CUPS filter executable, making the mentioned two
  functions be called before the filter function itself (in most cases
  from libcupsfilters) gets called.

- Filter functions which need PPD file support, especially those which
  output PostScript, and also the former cfFilterExternalCUPS() (now
  ppdFilterExternalCUPS()) filter function have moved to libppd.

- The support for PostScript output has also been removed. Nowadays it
  only serves for printing on PostScript printers (where one usually
  also has a PPD file), as document exchange format PostScript got
  fully replaced by PDF.

- If PPD file support cannot be added to a filter function by only
  extracting the printer's properties from the PPD via printer IPP
  attributes and option settings, a wrapper filter function is created
  in libppd. This we do for cfFilterUniversal() (to correct the output
  format according to "*cupsFilters2: ..." lines in the PPD) and for
  cfFilterPDFToPDF()/cfFilterImageToPDF() (to add JCL/PJL commands
  from the PPD file for "classic" PDF printers).

- In raster driver support code moved the functions to read parameters
  from the PPD file to libppd.

- Moved the PPD file generator used by cups-browsed and by the
  driverless utility to libppd.

- Moved the handling of common parameters, like page size, duplex,
  backside orientation, color spaces and depths, Raster headers, ...,
  by the filter functions into separate functions to not duplicate the
  code in each filter function.

- Improved the page size handling, especially accepting all types of
  parameter supply (options, job attributes, printer attributes,
  Raster headers, handling borderless printing and overspray,
  specification of size by dimensions or by name, custom size,
  margins, recognition whether user explicitly requested a page size
  (if not, use input page size if possible) ...

- Made functions for handling human-readable/translation strings (of
  the PPD generator) API functions of libcupsfilters.

I addition, fixed several minor bugs.

87 files changed:
Makefile.am
backend/implicitclass.c
backend/parallel.c
cupsfilters/attr.c [deleted file]
cupsfilters/bannertopdf.c
cupsfilters/catalog.c [new file with mode: 0644]
cupsfilters/catalog.h [new file with mode: 0644]
cupsfilters/cmyk.c
cupsfilters/colord.c
cupsfilters/colord.h
cupsfilters/colormanager.c
cupsfilters/colormanager.h
cupsfilters/driver.h
cupsfilters/filter.c
cupsfilters/filter.h
cupsfilters/ghostscript.c
cupsfilters/ieee1284.c
cupsfilters/ieee1284.h
cupsfilters/imagetopdf.c
cupsfilters/imagetoraster.c
cupsfilters/ipp.c
cupsfilters/ipp.h
cupsfilters/lut.c
cupsfilters/mupdftopwg.c
cupsfilters/pclmtoraster.cxx
cupsfilters/pdftopdf/pdftopdf-jcl-private.h [deleted file]
cupsfilters/pdftopdf/pdftopdf-jcl.cxx [deleted file]
cupsfilters/pdftopdf/pdftopdf-processor-private.h
cupsfilters/pdftopdf/pdftopdf-processor.cxx
cupsfilters/pdftopdf/pdftopdf.cxx
cupsfilters/pdftoraster.cxx
cupsfilters/ppdgenerator.h [deleted file]
cupsfilters/pwgtoraster.c
cupsfilters/raster.c
cupsfilters/raster.h
cupsfilters/rastertopdf.cxx
cupsfilters/rastertopwg.c
cupsfilters/rgb.c
cupsfilters/test1284.c
cupsfilters/texttopdf.c
cupsfilters/texttotext.c
cupsfilters/universal.c
filter/bannertopdf.c
filter/commandtoescpx.c
filter/commandtopclx.c
filter/foomatic-rip/foomaticrip.c
filter/gstopdf.c
filter/gstopxl.c
filter/gstoraster.c
filter/imagetopdf.c
filter/imagetops.c
filter/imagetoraster.c
filter/mupdftopwg.c
filter/pcl-common.c
filter/pcl-common.h
filter/pclmtoraster.c
filter/pdftopdf.c
filter/pdftops.c
filter/pdftoraster.c
filter/pstops.c
filter/pwgtoraster.c
filter/rastertoescpx.c
filter/rastertopclm.c
filter/rastertopclx.c
filter/rastertopdf.c
filter/rastertops.c
filter/rastertopwg.c
filter/test_pdf1.c
filter/test_pdf2.c
filter/texttopdf.c
filter/texttotext.c
filter/universal.c
libppd.pc.in
ppd/imagetops-pstops.c [moved from cupsfilters/imagetops-pstops.c with 95% similarity]
ppd/pdftops.c [moved from cupsfilters/pdftops.c with 91% similarity]
ppd/ppd-emit.c
ppd/ppd-filter.c [new file with mode: 0644]
ppd/ppd-filter.h [new file with mode: 0644]
ppd/ppd-generator.c [moved from cupsfilters/ppdgenerator.c with 62% similarity]
ppd/ppd-ipp.c
ppd/ppd-load-profile.c [new file with mode: 0644]
ppd/ppd.c
ppd/ppd.h
ppd/rastertops.c [moved from cupsfilters/rastertops.c with 93% similarity]
ppd/testdriver.c [moved from cupsfilters/testdriver.c with 97% similarity]
utils/cups-browsed.c
utils/driverless.c

index c13c293b992bab3909e84cf593f953c8ff16e689..0ab85fc8a3ff525a7c95e11fbd211aea902cfe6e 100644 (file)
@@ -29,7 +29,7 @@ EXTRA_DIST = \
        filter/braille/filters/TODO.txt
 
 EXTRA_DIST += \
-       cupsfilters/testdriver.c \
+       ppd/testdriver.c \
        data/makePDFfromPS.sh \
        data/classified.ps \
        data/confidential.ps \
@@ -168,7 +168,7 @@ pkgppdincludedir = $(includedir)/ppd
 pkgppdinclude_DATA = \
        ppd/ppd.h \
        ppd/ppdc.h \
-       cupsfilters/log.h
+       ppd/ppd-filter.h
 
 pkgppddefsdir = $(datadir)/ppdc
 pkgppddefs_DATA = \
@@ -194,6 +194,9 @@ libppd_la_SOURCES = \
        ppd/ppd-conflicts.c \
        ppd/ppd-custom.c \
        ppd/ppd-emit.c \
+       ppd/ppd-filter.c \
+       ppd/ppd-generator.c \
+       ppd/ppd-load-profile.c \
        ppd/ppd-localize.c \
        ppd/ppd-mark.c \
        ppd/ppd-page.c \
@@ -206,12 +209,15 @@ libppd_la_SOURCES = \
        ppd/encode.c \
        ppd/file.c \
        ppd/file-private.h \
+       ppd/imagetops-pstops.c \
        ppd/ipp-private.h \
        ppd/language.c \
        ppd/language-private.h \
+       ppd/pdftops.c \
        ppd/raster-interpret.c \
        ppd/raster-error.c \
        ppd/raster-private.h \
+       ppd/rastertops.c \
        ppd/string.c \
        ppd/snprintf.c \
        ppd/string-private.h \
@@ -240,12 +246,16 @@ libppd_la_SOURCES = \
        $(pkgppdinclude_DATA) \
        $(pkgppddefs_DATA)
 libppd_la_LIBADD = \
+       libcupsfilters.la \
        $(CUPS_LIBS)
 libppd_la_CFLAGS = \
+       -I$(srcdir)/cupsfilters/ \
        $(CUPS_CFLAGS)
 libppd_la_LDFLAGS = \
        -no-undefined \
        -version-info 1
+libppd_la_DEPENDENCIES = \
+       libcupsfilters.la
 
 testppd_SOURCES = ppd/testppd.c
 testppd_LDADD = libppd.la \
@@ -392,6 +402,7 @@ pkgfilterdir = $(CUPS_SERVERBIN)/filter
 pkgfiltersincludedir = $(includedir)/cupsfilters
 pkgfiltersinclude_DATA = \
        cupsfilters/bitmap.h \
+       cupsfilters/catalog.h \
        cupsfilters/colord.h \
        cupsfilters/colormanager.h \
        cupsfilters/driver.h \
@@ -402,7 +413,6 @@ pkgfiltersinclude_DATA = \
        cupsfilters/log.h \
        cupsfilters/pdf.h \
        cupsfilters/pdfutils.h \
-       cupsfilters/ppdgenerator.h \
        cupsfilters/raster.h
 
 lib_LTLIBRARIES += libcupsfilters.la
@@ -433,9 +443,9 @@ TESTS += \
 #TESTS += test1284
 
 libcupsfilters_la_SOURCES = \
-       cupsfilters/attr.c \
        cupsfilters/bannertopdf.c \
        cupsfilters/bitmap.c \
+       cupsfilters/catalog.c \
        cupsfilters/check.c \
        cupsfilters/cmyk.c \
        cupsfilters/colord.c \
@@ -468,8 +478,6 @@ libcupsfilters_la_SOURCES = \
        cupsfilters/pdf.cxx \
        cupsfilters/pdftopdf/pdftopdf.cxx \
        cupsfilters/pdftopdf/pdftopdf-private.h \
-       cupsfilters/pdftopdf/pdftopdf-jcl.cxx \
-       cupsfilters/pdftopdf/pdftopdf-jcl-private.h \
        cupsfilters/pdftopdf/pdftopdf-processor.cxx \
        cupsfilters/pdftopdf/pdftopdf-processor-private.h \
        cupsfilters/pdftopdf/qpdf-pdftopdf-processor.cxx \
@@ -488,14 +496,10 @@ libcupsfilters_la_SOURCES = \
        cupsfilters/pdftopdf/qpdf-pdftopdf-private.h \
        cupsfilters/pdftopdf/qpdf-cm.cxx \
        cupsfilters/pdftopdf/qpdf-cm-private.h \
-       cupsfilters/pdftops.c \
        cupsfilters/pdftoraster.cxx \
        cupsfilters/pdfutils.c \
-       cupsfilters/ppdgenerator.c \
-       cupsfilters/imagetops-pstops.c \
        cupsfilters/pwgtoraster.c \
        cupsfilters/raster.c \
-       cupsfilters/rastertops.c \
        cupsfilters/rastertopdf.cxx \
        cupsfilters/rastertopwg.c \
        cupsfilters/rgb.c \
@@ -508,7 +512,6 @@ EXTRA_libcupsfilters_la_SOURCES = \
        cupsfilters/getline.c \
        cupsfilters/strcasestr.c
 libcupsfilters_la_LIBADD = \
-       libppd.la \
        libfontembed.la \
        $(FONTCONFIG_LIBS) \
        $(GETLINE) \
@@ -523,7 +526,6 @@ libcupsfilters_la_LIBADD = \
        $(POPPLER_LIBS) \
        -lm
 libcupsfilters_la_CFLAGS = \
-       -I$(srcdir)/ppd/ \
        -I$(srcdir)/fontembed/ \
        $(FONTCONFIG_CFLAGS) \
        $(CUPS_CFLAGS) \
@@ -542,7 +544,6 @@ libcupsfilters_CXXFLAGS = -std=c++0x $(libcupsfilters_CFLAGS)   # -std=c++11
 libcupsfilters_la_LIBADD += $(DBUS_LIBS)
 endif
 libcupsfilters_la_DEPENDENCIES = \
-       libppd.la \
        libfontembed.la \
        $(GETLINE) \
        $(STRCASESTR)
@@ -885,10 +886,12 @@ bannertopdf_SOURCES = \
        filter/bannertopdf.c
 bannertopdf_CFLAGS = \
        $(CUPS_CFLAGS) \
-       -I$(srcdir)/cupsfilters/
+       -I$(srcdir)/cupsfilters/ \
+       -I$(srcdir)/ppd/
 bannertopdf_LDADD = \
        $(CUPS_LIBS) \
-       libcupsfilters.la
+       libcupsfilters.la \
+       libppd.la
 
 commandtoescpx_SOURCES = \
        cupsfilters/driver.h \
@@ -937,92 +940,112 @@ foomatic_rip_SOURCES = \
 foomatic_rip_CFLAGS = \
        -DCONFIG_PATH='"$(sysconfdir)/foomatic"' \
        $(CUPS_CFLAGS) \
-       -I$(srcdir)/cupsfilters/
+       -I$(srcdir)/cupsfilters/ \
+       -I$(srcdir)/ppd/
 foomatic_rip_LDADD = \
        $(CUPS_LIBS) \
        -lm \
-       libcupsfilters.la
+       libcupsfilters.la \
+       libppd.la
 
 gstoraster_SOURCES = \
        filter/gstoraster.c
 gstoraster_CFLAGS = \
        $(CUPS_CFLAGS) \
-       -I$(srcdir)/cupsfilters/
+       -I$(srcdir)/cupsfilters/ \
+       -I$(srcdir)/ppd/
 gstoraster_LDADD = \
        $(CUPS_LIBS) \
-       libcupsfilters.la
+       libcupsfilters.la \
+       libppd.la
 
 gstopdf_SOURCES = \
        filter/gstopdf.c
 gstopdf_CFLAGS = \
        $(CUPS_CFLAGS) \
-       -I$(srcdir)/cupsfilters/
+       -I$(srcdir)/cupsfilters/ \
+       -I$(srcdir)/ppd/
 gstopdf_LDADD = \
        $(CUPS_LIBS) \
-       libcupsfilters.la
+       libcupsfilters.la \
+       libppd.la
 
 gstopxl_SOURCES = \
        filter/gstopxl.c
 gstopxl_CFLAGS = \
        $(CUPS_CFLAGS) \
-       -I$(srcdir)/cupsfilters/
+       -I$(srcdir)/cupsfilters/ \
+       -I$(srcdir)/ppd/
 gstopxl_LDADD = \
        $(CUPS_LIBS) \
-       libcupsfilters.la
+       libcupsfilters.la \
+       libppd.la
 
 imagetopdf_SOURCES = \
        filter/imagetopdf.c
 imagetopdf_CFLAGS = \
        $(CUPS_CFLAGS) \
-       -I$(srcdir)/cupsfilters/
+       -I$(srcdir)/cupsfilters/ \
+       -I$(srcdir)/ppd/
 imagetopdf_LDADD = \
        $(CUPS_LIBS) \
-       libcupsfilters.la
+       libcupsfilters.la \
+       libppd.la
 
 imagetops_SOURCES = \
        filter/imagetops.c
 imagetops_CFLAGS = \
        $(CUPS_CFLAGS) \
-       -I$(srcdir)/cupsfilters/
+       -I$(srcdir)/cupsfilters/ \
+       -I$(srcdir)/ppd/
 imagetops_LDADD = \
        $(CUPS_LIBS) \
-       libcupsfilters.la
+       libcupsfilters.la \
+       libppd.la
 
 imagetoraster_SOURCES = \
        filter/imagetoraster.c
 imagetoraster_CFLAGS = \
        $(CUPS_CFLAGS) \
-       -I$(srcdir)/cupsfilters/
+       -I$(srcdir)/cupsfilters/ \
+       -I$(srcdir)/ppd/
 imagetoraster_LDADD = \
        $(CUPS_LIBS) \
-       libcupsfilters.la
+       libcupsfilters.la \
+       libppd.la
 
 pclmtoraster_SOURCES = \
        filter/pclmtoraster.c
 pclmtoraster_CXXFLAGS = \
        -I$(srcdir)/cupsfilters/ \
+       -I$(srcdir)/ppd/ \
        $(CUPS_CFLAGS)
 pclmtoraster_LDADD = \
        libcupsfilters.la \
+       libppd.la \
        $(CUPS_LIBS)
 
 rastertopclm_SOURCES = \
        filter/rastertopclm.c
 rastertopclm_CFLAGS = \
        $(CUPS_CFLAGS) \
-       -I$(srcdir)/cupsfilters/
+       -I$(srcdir)/cupsfilters/ \
+       -I$(srcdir)/ppd/
 rastertopclm_LDADD = \
        $(CUPS_LIBS) \
-       libcupsfilters.la
+       libcupsfilters.la \
+       libppd.la
 
 rastertopdf_SOURCES = \
        filter/rastertopdf.c
 rastertopdf_CFLAGS = \
        $(CUPS_CFLAGS) \
-       -I$(srcdir)/cupsfilters/
+       -I$(srcdir)/cupsfilters/ \
+       -I$(srcdir)/ppd/
 rastertopdf_LDADD = \
        $(CUPS_LIBS) \
-       libcupsfilters.la
+       libcupsfilters.la \
+       libppd.la
 
 mupdftopwg_SOURCES = \
        filter/mupdftopwg.c
@@ -1039,72 +1062,88 @@ pwgtoraster_SOURCES = \
        filter/pwgtoraster.c
 pwgtoraster_CFLAGS = \
        $(CUPS_CFLAGS) \
-       -I$(srcdir)/cupsfilters/
+       -I$(srcdir)/cupsfilters/ \
+       -I$(srcdir)/ppd/
 pwgtoraster_LDADD = \
        $(CUPS_LIBS) \
-       libcupsfilters.la
+       libcupsfilters.la \
+       libppd.la
 
 rastertops_SOURCES = \
        filter/rastertops.c
 rastertops_CFLAGS = \
        $(CUPS_CFLAGS) \
-       -I$(srcdir)/cupsfilters/
+       -I$(srcdir)/cupsfilters/ \
+       -I$(srcdir)/ppd/
 rastertops_LDADD = \
        $(CUPS_LIBS) \
-       libcupsfilters.la
+       libcupsfilters.la \
+       libppd.la
 
 rastertopwg_SOURCES = \
        filter/rastertopwg.c
 rastertopwg_CFLAGS = \
        $(CUPS_CFLAGS) \
-       -I$(srcdir)/cupsfilters/
+       -I$(srcdir)/cupsfilters/ \
+       -I$(srcdir)/ppd/
 rastertopwg_LDADD = \
        $(CUPS_LIBS) \
-       libcupsfilters.la
+       libcupsfilters.la \
+       libppd.la
 
 texttotext_SOURCES = \
        filter/texttotext.c
 texttotext_CFLAGS = \
        -I$(srcdir)/cupsfilters/ \
+       -I$(srcdir)/ppd/ \
        $(CUPS_CFLAGS)
 texttotext_LDADD = \
        libcupsfilters.la \
+       libppd.la \
        $(CUPS_LIBS)
 
 texttopdf_SOURCES = \
        filter/texttopdf.c
 texttopdf_CFLAGS = \
        -I$(srcdir)/cupsfilters/ \
+       -I$(srcdir)/ppd/ \
        $(CUPS_CFLAGS)
 texttopdf_LDADD = \
        libcupsfilters.la \
+       libppd.la \
        $(CUPS_LIBS)
 
 pdftops_SOURCES = \
        filter/pdftops.c
 pdftops_CFLAGS = \
        -I$(srcdir)/cupsfilters/ \
+       -I$(srcdir)/ppd/ \
        $(CUPS_CFLAGS)
 pdftops_LDADD = \
        libcupsfilters.la \
+       libppd.la \
        $(CUPS_LIBS)
 
 pstops_SOURCES = \
        filter/pstops.c
 pstops_CFLAGS = \
        -I$(srcdir)/cupsfilters/ \
+       -I$(srcdir)/ppd/ \
        $(CUPS_CFLAGS)
 pstops_LDADD = \
        libcupsfilters.la \
+       libppd.la \
        $(CUPS_LIBS)
 
 pdftoraster_SOURCES = \
        filter/pdftoraster.c
 pdftoraster_CFLAGS = \
        -I$(srcdir)/cupsfilters/ \
+       -I$(srcdir)/ppd/ \
        $(CUPS_CFLAGS)
 pdftoraster_LDADD = \
        libcupsfilters.la \
+       libppd.la \
        $(CUPS_LIBS)
 
 rastertoescpx_SOURCES = \
@@ -1162,6 +1201,7 @@ universal_CFLAGS = \
        $(CUPS_CFLAGS)
 universal_LDADD = \
        libcupsfilters.la \
+       libppd.la \
        $(CUPS_LIBS)
 
 # =====
index d3b7f10fec4a4460fae5d8c60c1590e5e45e137b..8ee4e10517f3565d6925437103cdce48870cb2a2 100644 (file)
@@ -31,7 +31,7 @@
 #include <signal.h>
 #include <sys/types.h>
 #include <sys/wait.h>
-#include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
 #include <cupsfilters/ipp.h>
 
 /*
@@ -241,7 +241,7 @@ main(int  argc,                             /* I - Number of command-line args */
       int fd, nullfd;
       cf_filter_data_t filter_data;
       cf_filter_universal_parameter_t universal_parameters;
-      cf_filter_external_cups_t ipp_backend_params;
+      ppd_filter_external_cups_t ipp_backend_params;
       cf_filter_filter_in_chain_t universal_in_chain,
                               ipp_in_chain;
       cups_array_t *filter_chain;
@@ -305,34 +305,17 @@ main(int  argc,                           /* I - Number of command-line args */
       filter_data.job_user = argv[2];
       filter_data.job_title = title;
       filter_data.copies = atoi(argv[4]);
+      filter_data.content_type = "application/vnd.cups-pdf";
+      filter_data.final_content_type = document_format;
       filter_data.job_attrs = NULL;        /* We use command line options */
-      if ((filter_data.printer_attrs =
-          cfGetPrinterAttributes4(printer_uri, NULL, 0, NULL, 0, 1, 0)) !=
-         NULL)
+      filter_data.printer_attrs =
+       cfGetPrinterAttributes4(printer_uri, NULL, 0, NULL, 0, 1, 0);
                                            /* Poll the printer attributes from
                                              the printer */
-       filter_data.ppdfile = NULL;        /* We have successfully polled
-                                             the IPP attributes from the
-                                             printer. This is the most
-                                             precise printer capability info.
-                                             As the queue's PPD is only
-                                             for the cluster we prefer the
-                                             IPP attributes */
-      else
-       filter_data.ppdfile = getenv("PPD");/*The polling of the printer's
-                                             IPP attribute failed, meaning
-                                             that it is most probably not a
-                                             driverless IPP printers (IPP 2.x)
-                                             but a legacy IPP printer (IPP
-                                             1.x) which usually has
-                                             unsufficient capability info.
-                                             Therefore we fall back to the
-                                             PPD file here which contains
-                                             some info from the printer's
-                                             DNS-SD record. */
       filter_data.num_options = num_options;
       filter_data.options = options;       /* Command line options from 5th
                                              arg */
+      filter_data.extension = NULL;
       filter_data.back_pipe[0] = -1;
       filter_data.back_pipe[1] = -1;
       filter_data.side_pipe[0] = -1;
@@ -343,8 +326,19 @@ main(int  argc,                            /* I - Number of command-line args */
                                                           function */
       filter_data.iscanceleddata = &job_canceled;
 
-      cfFilterLoadPPD(&filter_data);
-      if (filter_data.printer_attrs == NULL && filter_data.ppd == NULL)
+      /* If the polling of the printer's IPP attributes has failed, it
+        means most probably that it is not a driverless IPP printer
+        (IPP 2.x) but a legacy IPP printer (IPP 1.x) which usually
+        has unsufficient capability info. Therefore we fall back to
+        the PPD file here which contains some info from the printer's
+        DNS-SD record.
+
+         If we have successfully polled the IPP attributes from the
+        printer, these attributes are the most precise printer
+        capability info and as the queue's PPD is only for the
+        cluster we prefer the IPP attributes. */
+      if (filter_data.printer_attrs == NULL &&
+         ppdFilterLoadPPDFile(&filter_data, getenv("PPD")) < 0)
       {
        ippDelete(response);
        fprintf(stderr, "ERROR: Unable to get sufficient capability info of the destination printer.\n");
@@ -353,9 +347,8 @@ main(int  argc,                             /* I - Number of command-line args */
 
       cfFilterOpenBackAndSidePipes(&filter_data);
 
-      /* Parameters (input/output MIME types) for cfFilterUniversal() call */
-      universal_parameters.input_format = "application/vnd.cups-pdf";
-      universal_parameters.output_format = document_format;
+      /* Parameters for cfFilterUniversal() call */
+      universal_parameters.actual_output_type = NULL;
       memset(&(universal_parameters.texttopdf_params), 0,
             sizeof(cf_filter_texttopdf_parameter_t));
 
@@ -367,13 +360,13 @@ main(int  argc,                           /* I - Number of command-line args */
       ipp_backend_params.options = NULL;
       ipp_backend_params.envp = NULL;
 
-      /* Filter chain entry for the cfFilterUniversal() filter function call */
-      universal_in_chain.function = cfFilterUniversal;
+      /* Filter chain entry for the ppdFilterUniversal() filter function call */
+      universal_in_chain.function = ppdFilterUniversal;
       universal_in_chain.parameters = &universal_parameters;
       universal_in_chain.name = "Filters";
 
       /* Filter chain entry for the IPP CUPS backend call */
-      ipp_in_chain.function = cfFilterExternalCUPS;
+      ipp_in_chain.function = ppdFilterExternalCUPS;
       ipp_in_chain.parameters = &ipp_backend_params;
       ipp_in_chain.name = "Backend";
 
@@ -393,14 +386,15 @@ main(int  argc,                           /* I - Number of command-line args */
 
       /* Call the filter chain to run the needed filters and the backend */
       retval = cfFilterChain(fd, nullfd, fd != 0 ? 1 : 0, &filter_data,
-                          filter_chain);
+                            filter_chain);
 
       cfFilterCloseBackAndSidePipes(&filter_data);
 
       /* Clean up */
       cupsArrayDelete(filter_chain);
       ippDelete(response);
-      cfFilterFreePPD(&filter_data);
+
+      ppdFilterFreePPDFile(&filter_data);
 
       if (retval) {
        fprintf(stderr, "ERROR: Job processing failed.\n");
index 74b935ec0c2572060c0cb11564fa903b00a724fb..6fc76211933e65659e6cb79426f58b0346c29da9 100644 (file)
@@ -26,6 +26,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <termios.h>
+#include <stdio.h>
 #include <sys/socket.h>
 
 
diff --git a/cupsfilters/attr.c b/cupsfilters/attr.c
deleted file mode 100644 (file)
index 09eeff2..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- *   PPD attribute lookup routine for CUPS.
- *
- *   Copyright 2007-2011 by Apple Inc.
- *   Copyright 1993-2005 by Easy Software Products.
- *
- *   These coded instructions, statements, and computer programs are the
- *   property of Apple Inc. and are protected by Federal copyright
- *   law.  Distribution and use rights are outlined in the file "COPYING"
- *   which should have been included with this file.
- *
- * Contents:
- *
- *   cfFindAttr() - Find a PPD attribute based on the colormodel,
- *                    media, and resolution.
- */
-
-/*
- * Include necessary headers.
- */
-
-#include <config.h>
-#include "driver.h"
-#include <string.h>
-#include <ctype.h>
-
-
-/*
- * 'cfFindAttr()' - Find a PPD attribute based on the colormodel,
- *                    media, and resolution.
- */
-
-ppd_attr_t *                           /* O - Matching attribute or NULL */
-cfFindAttr(ppd_file_t *ppd,            /* I - PPD file */
-             const char *name,         /* I - Attribute name */
-             const char *colormodel,   /* I - Color model */
-             const char *media,                /* I - Media type */
-             const char *resolution,   /* I - Resolution */
-            char       *spec,          /* O - Final selection string */
-            int        specsize,       /* I - Size of string buffer */
-            cf_logfunc_t log,      /* I - Log function */
-            void       *ld)            /* I - Log function data */
-{
-  ppd_attr_t   *attr;                  /* Attribute */
-
-
- /*
-  * Range check input...
-  */
-
-  if (!ppd || !name || !colormodel || !media || !resolution || !spec ||
-      specsize < PPD_MAX_NAME)
-    return (NULL);
-
- /*
-  * Look for the attribute with the following keywords:
-  *
-  *     ColorModel.MediaType.Resolution
-  *     ColorModel.Resolution
-  *     ColorModel
-  *     MediaType.Resolution
-  *     MediaType
-  *     Resolution
-  *     ""
-  */
-
-  snprintf(spec, specsize, "%s.%s.%s", colormodel, media, resolution);
-  if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "Looking for \"*%s %s\"...", name, spec);
-  if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
-    return (attr);
-
-  snprintf(spec, specsize, "%s.%s", colormodel, resolution);
-  if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "Looking for \"*%s %s\"...", name, spec);
-  if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
-    return (attr);
-
-  snprintf(spec, specsize, "%s", colormodel);
-  if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "Looking for \"*%s %s\"...", name, spec);
-  if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
-    return (attr);
-
-  snprintf(spec, specsize, "%s.%s", media, resolution);
-  if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "Looking for \"*%s %s\"...", name, spec);
-  if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
-    return (attr);
-
-  snprintf(spec, specsize, "%s", media);
-  if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "Looking for \"*%s %s\"...", name, spec);
-  if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
-    return (attr);
-
-  snprintf(spec, specsize, "%s", resolution);
-  if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "Looking for \"*%s %s\"...", name, spec);
-  if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
-    return (attr);
-
-  spec[0] = '\0';
-  if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "Looking for \"*%s\"...", name);
-  if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
-    return (attr);
-
-  if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "No instance of \"*%s\" found...", name);
-
-  return (NULL);
-}
-
index e8ebde2fa645f19a945ae39e74e20f682698e006..2227096fce2c868ce5bc6828433d8ec9b54cfd5d 100644 (file)
@@ -22,7 +22,8 @@
 #include <stdarg.h>
 #include <math.h>
 #include <errno.h>
-#include <cupsfilters/ppdgenerator.h>
+#include "ipp.h"
+#include "ipp.h"
 #include "raster.h"
 
 #ifndef HAVE_OPEN_MEMSTREAM
 #endif
 
 #include <cups/cups.h>
-#include <ppd/ppd.h>
-#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 6)
-#define HAVE_CUPS_1_7 1
-#endif
-#ifdef HAVE_CUPS_1_7
 #include <cups/pwg.h>
-#endif /* HAVE_CUPS_1_7 */
 
 #include "filter.h"
 #include "pdf.h"
@@ -311,167 +306,31 @@ out:
     return banner;
 }
 
-static float get_float_option(const char *name,
-                              int noptions,
-                              cups_option_t *options,
-                              float def)
-{
-    const char *value = cupsGetOption(name, noptions, options);
-    return value ? atof(value) : def;
-}
-
 static int get_int_option(const char *name,
-                          int noptions,
+                          int num_options,
                           cups_option_t *options,
                           int def)
 {
-    const char *value = cupsGetOption(name, noptions, options);
+    const char *value = cupsGetOption(name, num_options, options);
     return value ? atoi(value) : def;
 }
 
-static void get_pagesize(cf_filter_data_t *data,
-                         int noptions,
-                         cups_option_t *options,
-                         float *width,
-                         float *length,
-                         float media_limits[4])
+static int duplex_marked(cf_filter_data_t *data)
 {
-    ppd_file_t *ppd = data->ppd;
-    ipp_t *printer_attrs = data->printer_attrs;
-    static ppd_size_t defaultsize = {
-        0,     /* marked */
-        "",    /* name */
-        612.0, /* width */
-        792.0, /* length */
-        18.0,  /* left */
-        36.0,  /* bottom */
-        594.0, /* right */
-        756.0, /* top */
-    };
-    ppd_size_t *pagesize = &defaultsize;
-#ifdef HAVE_CUPS_1_7
-    pwg_media_t *size_found; /* page size found for given name */
-    const char *val;         /* Pointer into value */
-    char *ptr1, *ptr2,       /* Pointer into string */
-        s[255];              /* Temporary string */
-#endif                       /* HAVE_CUPS_1_7 */
-
-    if (!ppd || !(pagesize = ppdPageSize(ppd, NULL))) {
-       pagesize = &defaultsize;
-       if(printer_attrs!=NULL){
-           int left,
-           right,
-           top,
-           bottom,
-           min_length = 2147483647,
-           min_width = 2147483647,
-           max_length = 0,
-           max_width = 0;
-           char defsize[41];
-           ipp_attribute_t *defattr;
-           cups_array_t *printer_sizes;
-           printer_sizes = cfGenerateSizes(printer_attrs, &defattr, &min_length, &min_width,
-                                           &max_length, &max_width, 
-                                           &bottom, &left, &right, &top, defsize);
-           for(cups_size_t *size = (cups_size_t*)cupsArrayFirst(printer_sizes); size;
-               size = (cups_size_t*)cupsArrayNext(printer_sizes)){
-                   if(!strcmp(size->media, defsize)){
-                       ppd_size_t temp;
-                       snprintf(temp.name, sizeof(temp.name),"%s", defsize);
-                       temp.top = size->top *72.0 / 2540.0;
-                       temp.bottom = size->bottom *72.0 / 2540.0;
-                       temp.left = size->left *72.0 / 2540.0;
-                       temp.right = size->right *72.0 / 2540.0;
-                       temp.width = size->width *72.0 / 2540.0;
-                       temp.length = size->length *72.0 / 2540.0;
-                       pagesize = &temp;
-                       break;
-                   }
-               }
-       }
-    }
-
-    *width = pagesize->width;
-    *length = pagesize->length;
-
-    media_limits[0] = get_float_option("page-left",
-                                       noptions, options,
-                                       pagesize->left);
-    media_limits[1] = get_float_option("page-bottom",
-                                       noptions, options,
-                                       pagesize->bottom);
-    media_limits[2] = get_float_option("page-right",
-                                       noptions, options,
-                                       fabs(pagesize->right));
-    media_limits[3] = get_float_option("page-top",
-                                       noptions, options,
-                                       fabs(pagesize->top));
-
-#ifdef HAVE_CUPS_1_7
-    if (!ppd)
-    {
-        if ((val = cupsGetOption("media-size", noptions, options)) != NULL ||
-            (val = cupsGetOption("MediaSize", noptions, options)) != NULL ||
-            (val = cupsGetOption("page-size", noptions, options)) != NULL ||
-            (val = cupsGetOption("PageSize", noptions, options)) != NULL ||
-            (val = cupsGetOption("media", noptions, options)) != NULL)
-        {
-            for (ptr1 = (char *)val; *ptr1;)
-            {
-                for (ptr2 = s; *ptr1 && *ptr1 != ',' && (ptr2 - s) < (sizeof(s) - 1);)
-                    *ptr2++ = *ptr1++;
-                *ptr2++ = '\0';
-                if (*ptr1 == ',')
-                    ptr1++;
-                size_found = NULL;
-                if ((size_found = pwgMediaForPWG(s)) == NULL)
-                    if ((size_found = pwgMediaForPPD(s)) == NULL)
-                        size_found = pwgMediaForLegacy(s);
-                if (size_found != NULL)
-                {
-                    *width = size_found->width * 72.0 / 2540.0;
-                    *length = size_found->length * 72.0 / 2540.0;
-                    media_limits[2] += (*width - 612.0);
-                    media_limits[3] += (*length - 792.0);
-                }
-            }
-        }
-        if ((val = cupsGetOption("media-left-margin", noptions, options)) != NULL)
-            media_limits[0] = atol(val) * 72.0 / 2540.0;
-        if ((val = cupsGetOption("media-bottom-margin", noptions, options)) != NULL)
-            media_limits[1] = atol(val) * 72.0 / 2540.0;
-        if ((val = cupsGetOption("media-right-margin", noptions, options)) != NULL)
-            media_limits[2] = *width - atol(val) * 72.0 / 2540.0;
-        if ((val = cupsGetOption("media-top-margin", noptions, options)) != NULL)
-            media_limits[3] = *length - atol(val) * 72.0 / 2540.0;
-    }
-#endif /* HAVE_CUPS_1_7 */
-}
-
-static int duplex_marked(ppd_file_t *ppd,
-                         int noptions,
-                         cups_option_t *options)
-{
-    const char *val; /* Pointer into value */
-    return (ppd &&
-            (ppdIsMarked(ppd, "Duplex", "DuplexNoTumble") ||
-             ppdIsMarked(ppd, "Duplex", "DuplexTumble") ||
-             ppdIsMarked(ppd, "JCLDuplex", "DuplexNoTumble") ||
-             ppdIsMarked(ppd, "JCLDuplex", "DuplexTumble") ||
-             ppdIsMarked(ppd, "EFDuplex", "DuplexNoTumble") ||
-             ppdIsMarked(ppd, "EFDuplex", "DuplexTumble") ||
-             ppdIsMarked(ppd, "EFDuplexing", "DuplexNoTumble") ||
-             ppdIsMarked(ppd, "EFDuplexing", "DuplexTumble") ||
-             ppdIsMarked(ppd, "ARDuplex", "DuplexNoTumble") ||
-             ppdIsMarked(ppd, "ARDuplex", "DuplexTumble") ||
-             ppdIsMarked(ppd, "KD03Duplex", "DuplexNoTumble") ||
-             ppdIsMarked(ppd, "KD03Duplex", "DuplexTumble"))) ||
-           ((val = cupsGetOption("Duplex", noptions, options)) != NULL &&
-            (!strcasecmp(val, "DuplexNoTumble") ||
-             !strcasecmp(val, "DuplexTumble"))) ||
-           ((val = cupsGetOption("sides", noptions, options)) != NULL &&
-            (!strcasecmp(val, "two-sided-long-edge") ||
-             !strcasecmp(val, "two-sided-short-edge")));
+  const char *val; /* Pointer into value */
+  if ((val = cupsGetOption("Duplex",
+                          data->num_options, data->options)) != NULL)
+    return (strncasecmp(val, "Duplex", 6) == 0);
+  else if ((val = cupsGetOption("sides",
+                               data->num_options, data->options)) != NULL)
+    return (strncasecmp(val, "two-sided-", 10) == 0);
+  else if ((val = cfIPPAttrEnumValForPrinter(data->printer_attrs,
+                                            data->job_attrs,
+                                            "sides")) != NULL)
+    return (strncasecmp(val, "two-sided-", 10) == 0);
+  else if (data->header)
+    return (data->header->Duplex);
+  return (0);
 }
 
 static void info_linef(FILE *s,
@@ -566,13 +425,11 @@ static cf_opt_t *get_known_opts(
     const char *jobid,
     const char *user,
     const char *jobtitle,
-    int noptions,
+    int num_options,
     
     cups_option_t *options)
 {
 
-    ppd_file_t *ppd = data->ppd;
-    ppd_attr_t *attr;
     cf_opt_t *opt = NULL;
     ipp_t *printer_attrs = data->printer_attrs;
     ipp_attribute_t *ipp_attr;
@@ -593,48 +450,48 @@ static cf_opt_t *get_known_opts(
 
     /* Printer info */
     if ((value = cupsGetOption("printer-info",
-                               noptions, options)) == NULL || !value[0])
+                               num_options, options)) == NULL || !value[0])
       value =  getenv("PRINTER_INFO");
     opt = add_opt(opt, "printer-info", value);
 
     /* Time at creation */
     opt = add_opt(opt, "time-at-creation",
-                  human_time(cupsGetOption("time-at-creation", noptions, options)));
+                  human_time(cupsGetOption("time-at-creation", num_options, options)));
 
     /* Processing time */
     opt = add_opt(opt, "time-at-processing",
-                  human_time(cupsGetOption("time-at-processing", noptions, options)));
+                  human_time(cupsGetOption("time-at-processing", num_options, options)));
 
     /* Billing information */
     opt = add_opt(opt, "job-billing",
-                  cupsGetOption("job-billing", noptions, options));
+                  cupsGetOption("job-billing", num_options, options));
 
     /* Source hostname */
     opt = add_opt(opt, "job-originating-host-name",
-                  cupsGetOption("job-originating-host-name", noptions, options));
+                  cupsGetOption("job-originating-host-name", num_options, options));
 
     /* Banner font */
     opt = add_opt(opt, "banner-font",
-                  cupsGetOption("banner-font", noptions, options));
+                  cupsGetOption("banner-font", num_options, options));
 
     /* Banner font size */
     opt = add_opt(opt, "banner-font-size",
-                  cupsGetOption("banner-font-size", noptions, options));
+                  cupsGetOption("banner-font-size", num_options, options));
 
     /* Job UUID */
     opt = add_opt(opt, "job-uuid",
-                  cupsGetOption("job-uuid", noptions, options));
+                  cupsGetOption("job-uuid", num_options, options));
 
     /* Security context */
     opt = add_opt(opt, "security-context",
-                  cupsGetOption("security-context", noptions, options));
+                  cupsGetOption("security-context", num_options, options));
 
     /* Security context range part */
     opt = add_opt(opt, "security-context-range",
-                  cupsGetOption("security-context-range", noptions, options));
+                  cupsGetOption("security-context-range", num_options, options));
 
     /* Security context current range part */
-    const char *full_range = cupsGetOption("security-context-range", noptions, options);
+    const char *full_range = cupsGetOption("security-context-range", num_options, options);
     if (full_range)
     {
         size_t cur_size = strcspn(full_range, "-");
@@ -644,74 +501,62 @@ static cf_opt_t *get_known_opts(
 
     /* Security context type part */
     opt = add_opt(opt, "security-context-type",
-                  cupsGetOption("security-context-type", noptions, options));
+                  cupsGetOption("security-context-type", num_options, options));
 
     /* Security context role part */
     opt = add_opt(opt, "security-context-role",
-                  cupsGetOption("security-context-role", noptions, options));
+                  cupsGetOption("security-context-role", num_options, options));
 
     /* Security context user part */
     opt = add_opt(opt, "security-context-user",
-                  cupsGetOption("security-context-user", noptions, options));
+                  cupsGetOption("security-context-user", num_options, options));
 
-    if (ppd)
-    {
-        /* Driver */
-        opt = add_opt(opt, "driver", ppd->pcfilename);
-
-        /* Driver version */
-        opt = add_opt(opt, "driver-version",
-                      (attr = ppdFindAttr(ppd, "FileVersion", NULL)) ? attr->value : "");
+#if 0
+    /* Driver */
+    opt = add_opt(opt, "driver", "driverless");
 
-        /* Make and model */
-        opt = add_opt(opt, "make-and-model", ppd->nickname);
-    }
-    else
-    {
-       /* Driver */
-       opt = add_opt(opt, "driver", "drvless.ppd");
-
-       /* Driver version */
-        opt = add_opt(opt, "driver-version", VERSION);
-
-       /* Make and model */
-       int is_fax = 0;
-       char make[256];
-       char *model;
-       if ((ipp_attr = ippFindAttribute(printer_attrs, "ipp-features-supported",
-                               IPP_TAG_ZERO)) != NULL &&
-               ippContainsString(ipp_attr, "faxout"))
-       {
-           ipp_attr = ippFindAttribute(printer_attrs, "printer-uri-supported",
-               IPP_TAG_ZERO);
-           if (ipp_attr)
-           {
-               ippAttributeString(ipp_attr, buf, sizeof(buf));
-               if (strcasestr(buf, "faxout"))
-                   is_fax = 1;
-           }
-       }
+    /* Driver version */
+    opt = add_opt(opt, "driver-version", VERSION);
+#endif
 
-       if ((ipp_attr = ippFindAttribute(printer_attrs, "printer-make-and-model",
-                               IPP_TAG_ZERO)) != NULL)
-           snprintf(make, sizeof(make), "%s", ippGetString(ipp_attr, 0, NULL));
-       else
-           snprintf(make, sizeof(make), "%s", "Unknown Printer");
-       if (!strncasecmp(make, "Hewlett Packard ", 16) ||
-           !strncasecmp(make, "Hewlett-Packard ", 16)) {
-               model = make + 16;
-               snprintf(make, sizeof(make), "%s", "HP");
-       }
-       else if ((model = strchr(make, ' ')) != NULL)
-           *model++ = '\0';
-       else
-           model = make;
-       snprintf(buf, sizeof(buf), "%s %s, %sdriverless, cups-filters %s",
-               make, model, (is_fax ? "Fax, " : ""), VERSION);
-       char *nickname = buf;
-       opt = add_opt(opt, "make-and-model", nickname);
+    /* Make and model */
+    int is_fax = 0;
+    char make[256];
+    char *model;
+    if ((ipp_attr = ippFindAttribute(printer_attrs, "ipp-features-supported",
+                                    IPP_TAG_ZERO)) != NULL &&
+       ippContainsString(ipp_attr, "faxout"))
+    {
+      ipp_attr = ippFindAttribute(printer_attrs, "printer-uri-supported",
+                                 IPP_TAG_ZERO);
+      if (ipp_attr)
+      {
+       ippAttributeString(ipp_attr, buf, sizeof(buf));
+       if (strcasestr(buf, "faxout"))
+         is_fax = 1;
+      }
     }
 
+    if ((ipp_attr = ippFindAttribute(printer_attrs, "printer-info",
+                                    IPP_TAG_ZERO)) != NULL || 
+       (ipp_attr = ippFindAttribute(printer_attrs, "printer-make-and-model",
+                                    IPP_TAG_ZERO)) != NULL)
+      snprintf(make, sizeof(make), "%s", ippGetString(ipp_attr, 0, NULL));
+    else
+      snprintf(make, sizeof(make), "%s", "Unknown Printer");
+    if (!strncasecmp(make, "Hewlett Packard ", 16) ||
+       !strncasecmp(make, "Hewlett-Packard ", 16)) {
+      model = make + 16;
+      snprintf(make, sizeof(make), "%s", "HP");
+    }
+    else if ((model = strchr(make, ' ')) != NULL)
+      *model++ = '\0';
+    else
+      model = make;
+    snprintf(buf, sizeof(buf), "%s %s%s",
+            make, model, (is_fax ? ", Fax" : ""));
+    char *nickname = buf;
+    opt = add_opt(opt, "make-and-model", nickname);
 
     return opt;
 }
@@ -721,7 +566,7 @@ static int generate_banner_pdf(banner_t *banner,
                                const char *jobid,
                                const char *user,
                                const char *jobtitle,
-                               int noptions,
+                               int num_options,
                                cups_option_t *options,
                                cf_logfunc_t log,
                                void *ld,
@@ -731,14 +576,12 @@ static int generate_banner_pdf(banner_t *banner,
     size_t len;
     FILE *s;
     cf_pdf_t *doc;
-    float page_width, page_length;
+    float page_width = 0.0, page_length = 0.0;
     float media_limits[4];
     float page_scale;
-    ppd_attr_t *attr;
     unsigned copies;
     ipp_t *printer_attrs = data->printer_attrs;
     ipp_attribute_t *ipp_attr;
-    ppd_file_t *ppd = data->ppd;
     char buf2[1024];
     const char *value;
 #ifndef HAVE_OPEN_MEMSTREAM
@@ -753,8 +596,19 @@ static int generate_banner_pdf(banner_t *banner,
       return (1);
     }
 
-    get_pagesize(data, noptions, options,
-                 &page_width, &page_length, media_limits);
+    memset(media_limits, 0, sizeof(media_limits));
+    if (data != NULL && (data->printer_attrs) != NULL)
+    {
+      cfGetPageDimensions(data->printer_attrs, data->job_attrs,
+                         num_options, options,
+                         data->header, 0,
+                         &(page_width), &(page_length),
+                         &(media_limits[0]), &(media_limits[1]),
+                         &(media_limits[2]), &(media_limits[3]),
+                         NULL, NULL);
+      media_limits[2] = page_width - media_limits[2];
+      media_limits[3] = page_length - media_limits[3];
+    }
 
     if (cfPDFResizePage(doc, 1, page_width, page_length, &page_scale) != 0)
     {
@@ -804,23 +658,24 @@ static int generate_banner_pdf(banner_t *banner,
     fprintf(s, "17 TL\n");
 
     if ((banner->infos & INFO_PRINTER_NAME) &&
-       data->printer && data->printer[0])
+       data->printer && data->printer[0] && data->printer[0] != '/')
         info_line(s, "Printer", data->printer);
 
     if ((banner->infos & INFO_PRINTER_INFO) &&
        (((value = cupsGetOption("printer-info",
-                                noptions, options)) != NULL && value[0]) ||
+                                num_options, options)) != NULL && value[0]) ||
         ((value = getenv("PRINTER_INFO")) != NULL && value[0])))
         info_line(s, "Description", value);
 
     if ((banner->infos & INFO_PRINTER_LOCATION) &&
        (((value = cupsGetOption("printer-location",
-                                noptions, options)) != NULL && value[0]) ||
+                                num_options, options)) != NULL && value[0]) ||
         ((value = getenv("PRINTER_LOCATION")) != NULL && value[0])))
         info_line(s, "Location", value);
 
     if ((banner->infos & INFO_JOB_ID) &&
-       data->printer && data->printer[0] && jobid && jobid[0])
+       data->printer && data->printer[0] && data->printer[0] != '/' &&
+       jobid && jobid[0])
         info_linef(s, "Job ID", "%s-%s", data->printer, jobid);
 
     if ((banner->infos & INFO_JOB_NAME) && jobtitle && jobtitle[0])
@@ -828,7 +683,7 @@ static int generate_banner_pdf(banner_t *banner,
 
     if ((banner->infos & INFO_JOB_ORIGINATING_HOST_NAME) &&
        (value = cupsGetOption("job-originating-host-name",
-                             noptions, options)) != NULL && value[0])
+                             num_options, options)) != NULL && value[0])
         info_line(s, "Printed from", value);
 
     if ((banner->infos & INFO_JOB_ORIGINATING_USER_NAME) && user && user[0])
@@ -836,39 +691,28 @@ static int generate_banner_pdf(banner_t *banner,
 
     if ((banner->infos & INFO_TIME_AT_CREATION) &&
        (value =
-        cupsGetOption("time-at-creation", noptions, options)) != NULL &&
+        cupsGetOption("time-at-creation", num_options, options)) != NULL &&
        value[0])
         info_line_time(s, "Created at", value);
 
     if ((banner->infos & INFO_TIME_AT_PROCESSING) &&
        (value =
-        cupsGetOption("time-at-processing", noptions, options)) != NULL &&
+        cupsGetOption("time-at-processing", num_options, options)) != NULL &&
        value[0])
         info_line_time(s, "Printed at", value);
 
     if ((banner->infos & INFO_JOB_BILLING) &&
-       (value = cupsGetOption("job-billing", noptions, options)) != NULL &&
+       (value = cupsGetOption("job-billing", num_options, options)) != NULL &&
        value[0])
         info_line(s, "Billing Information\n", value);
 
     if ((banner->infos & INFO_JOB_UUID) &&
-       (value = cupsGetOption("job-uuid", noptions, options)) != NULL &&
+       (value = cupsGetOption("job-uuid", num_options, options)) != NULL &&
        value[0])
         info_line(s, "Job UUID", value);
 
-    if (ppd)
-    {
-      if ((banner->infos & INFO_PRINTER_DRIVER_NAME) ||
-         (banner->infos & INFO_PRINTER_MAKE_AND_MODEL))
-            info_line(s, "Driver/Model", ppd->nickname);
-
-       if ((banner->infos & INFO_PRINTER_DRIVER_VERSION) &&
-           (attr = ppdFindAttr(ppd, "FileVersion", NULL)) != NULL &&
-           attr->value && attr->value[0])
-         info_line(s, "Driver Version", attr->value);
-    }
-    else if ((banner->infos & INFO_PRINTER_DRIVER_NAME) ||
-            (banner->infos & INFO_PRINTER_MAKE_AND_MODEL))
+    if ((banner->infos & INFO_PRINTER_DRIVER_NAME) ||
+       (banner->infos & INFO_PRINTER_MAKE_AND_MODEL))
 
     {
        int is_fax = 0;
@@ -890,6 +734,9 @@ static int generate_banner_pdf(banner_t *banner,
        }
 
        if ((ipp_attr = ippFindAttribute(printer_attrs,
+                                        "printer-info",
+                                        IPP_TAG_ZERO)) != NULL ||
+           (ipp_attr = ippFindAttribute(printer_attrs,
                                         "printer-make-and-model",
                                         IPP_TAG_ZERO)) != NULL)
        {
@@ -952,7 +799,7 @@ static int generate_banner_pdf(banner_t *banner,
                                        jobid,
                                        user,
                                        jobtitle,
-                                       noptions,
+                                       num_options,
                                        options);
 
    /*
@@ -972,9 +819,9 @@ static int generate_banner_pdf(banner_t *banner,
       }
     }
 
-    copies = get_int_option("number-up", noptions, options, 1);
+    copies = get_int_option("number-up", num_options, options, 1);
 
-    if (duplex_marked(ppd, noptions, options))
+    if (duplex_marked(data))
         copies *= 2;
 
     if (copies > 1)
diff --git a/cupsfilters/catalog.c b/cupsfilters/catalog.c
new file mode 100644 (file)
index 0000000..2241ccf
--- /dev/null
@@ -0,0 +1,633 @@
+ /***
+  This file is part of cups-filters.
+
+  This file is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as
+  published by the Free Software Foundation; either version 2.1 of the
+  License, or (at your option) any later version.
+
+  This file is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
+  Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with avahi; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+  USA.
+***/
+
+/*
+ * Include necessary headers.
+ */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <cups/cups.h>
+#include <cups/backend.h>
+#include <cups/dir.h>
+#include <cups/pwg.h>
+#include <cupsfilters/catalog.h>
+
+
+int                            /* O  - 1 on success, 0 on failure */
+cfGetURI(const char *url,              /* I  - URL to get */
+       char       *name,               /* I  - Temporary filename */
+       size_t     namesize)            /* I  - Size of temporary filename
+                                               buffer */
+{
+  http_t               *http = NULL;
+  char                 scheme[32],     /* URL scheme */
+                       userpass[256],  /* URL username:password */
+                       host[256],      /* URL host */
+                       resource[256];  /* URL resource */
+  int                  port;           /* URL port */
+  http_encryption_t    encryption;     /* Type of encryption to use */
+  http_status_t                status;         /* Status of GET request */
+  int                  fd;             /* Temporary file */
+
+
+  if (httpSeparateURI(HTTP_URI_CODING_ALL, url, scheme, sizeof(scheme),
+                     userpass, sizeof(userpass), host, sizeof(host), &port,
+                     resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
+    return (0);
+
+  if (port == 443 || !strcmp(scheme, "https"))
+    encryption = HTTP_ENCRYPTION_ALWAYS;
+  else
+    encryption = HTTP_ENCRYPTION_IF_REQUESTED;
+
+  http = httpConnect2(host, port, NULL, AF_UNSPEC, encryption, 1, 5000, NULL);
+
+  if (!http)
+    return (0);
+
+  if ((fd = cupsTempFd(name, (int)namesize)) < 0)
+    return (0);
+
+  status = cupsGetFd(http, resource, fd);
+
+  close(fd);
+  httpClose(http);
+
+  if (status != HTTP_STATUS_OK) {
+    unlink(name);
+    *name = '\0';
+    return (0);
+  }
+
+  return (1);
+}
+
+
+/*
+ * 'cfCatalogFind()' - Find a CUPS message catalog file containing
+ *                     human-readable standard option and choice names
+ *                     for IPP printers
+ */
+
+const char *
+cfCatalogSearchDir(const char *dirname)
+{
+  const char *catalog = NULL, *c1, *c2;
+  cups_dir_t *dir = NULL, *subdir;
+  cups_dentry_t *subdirentry, *catalogentry;
+  char subdirpath[1024], catalogpath[2048], lang[8];
+  int i;
+
+  if (dirname == NULL)
+    return NULL;
+
+  /* Check first whether we have an English file and prefer this */
+  snprintf(catalogpath, sizeof(catalogpath), "%s/en/cups_en.po", dirname);
+  if (access(catalogpath, R_OK) == 0) {
+    /* Found */
+    catalog = strdup(catalogpath);
+    return catalog;
+  }
+
+  if ((dir = cupsDirOpen(dirname)) == NULL)
+    return NULL;
+
+  while ((subdirentry = cupsDirRead(dir)) != NULL) {
+    /* Do we actually have a subdir? */
+    if (!S_ISDIR(subdirentry->fileinfo.st_mode))
+      continue;
+    /* Check format of subdir name */
+    c1 = subdirentry->filename;
+    if (c1[0] < 'a' || c1[0] > 'z' || c1[1] < 'a' || c1[1] > 'z')
+      continue;
+    if (c1[2] >= 'a' && c1[2] <= 'z')
+      i = 3;
+    else
+      i = 2;
+    if (c1[i] == '_') {
+      i ++;
+      if (c1[i] < 'A' || c1[i] > 'Z' || c1[i+1] < 'A' || c1[i+1] > 'Z')
+       continue;
+      i += 2;
+      if (c1[i] >= 'A' && c1[i] <= 'Z')
+       i ++;
+    }
+    if (c1[i] != '\0' && c1[i] != '@')
+      continue;
+    strncpy(lang, c1, i);
+    lang[i] = '\0';
+    snprintf(subdirpath, sizeof(subdirpath), "%s/%s", dirname, c1);
+    if ((subdir = cupsDirOpen(subdirpath)) != NULL) {
+      while ((catalogentry = cupsDirRead(subdir)) != NULL) {
+       /* Do we actually have a regular file? */
+       if (!S_ISREG(catalogentry->fileinfo.st_mode))
+         continue;
+       /* Check format of catalog name */
+       c2 = catalogentry->filename;
+       if (strlen(c2) < 10 || strncmp(c2, "cups_", 5) != 0 ||
+           strncmp(c2 + 5, lang, i) != 0 ||
+           strcmp(c2 + strlen(c2) - 3, ".po"))
+         continue;
+       /* Is catalog readable ? */
+       snprintf(catalogpath, sizeof(catalogpath), "%s/%s", subdirpath, c2);
+       if (access(catalogpath, R_OK) != 0)
+         continue;
+       /* Found */
+       catalog = strdup(catalogpath);
+       break;
+      }
+      cupsDirClose(subdir);
+      subdir = NULL;
+      if (catalog != NULL)
+       break;
+    }
+  }
+
+  cupsDirClose(dir);
+  return catalog;
+}
+
+
+const char *
+cfCatalogFind(const char *preferreddir)
+{
+  const char *catalog = NULL, *c;
+  char buf[1024];
+
+  /* Directory supplied by calling program, from config file,
+     environment variable, ... */
+  if ((catalog = cfCatalogSearchDir(preferreddir)) != NULL)
+    goto found;
+
+  /* Directory supplied by environment variable CUPS_LOCALEDIR */
+  if ((catalog = cfCatalogSearchDir(getenv("CUPS_LOCALEDIR"))) != NULL)
+    goto found;
+
+  /* Determine CUPS datadir (usually /usr/share/cups) */
+  if ((c = getenv("CUPS_DATADIR")) == NULL)
+    c = CUPS_DATADIR;
+
+  /* Search /usr/share/cups/locale/ (location which
+     Debian/Ubuntu package of CUPS is using) */
+  snprintf(buf, sizeof(buf), "%s/locale", c);
+  if ((catalog = cfCatalogSearchDir(buf)) != NULL)
+    goto found;
+
+  /* Search /usr/(local/)share/locale/ (standard location
+     which CUPS is using on Linux) */
+  snprintf(buf, sizeof(buf), "%s/../locale", c);
+  if ((catalog = cfCatalogSearchDir(buf)) != NULL)
+    goto found;
+
+  /* Search /usr/(local/)lib/locale/ (standard location
+     which CUPS is using on many non-Linux systems) */
+  snprintf(buf, sizeof(buf), "%s/../../lib/locale", c);
+  if ((catalog = cfCatalogSearchDir(buf)) != NULL)
+    goto found;
+
+ found:
+  return catalog;
+}
+
+
+static int
+compare_choices(void *a,
+               void *b,
+               void *user_data)
+{
+  return strcasecmp(((catalog_choice_strings_t *)a)->name,
+                   ((catalog_choice_strings_t *)b)->name);
+}
+
+
+static int
+compare_options(void *a,
+               void *b,
+               void *user_data)
+{
+  return strcasecmp(((catalog_opt_strings_t *)a)->name,
+                   ((catalog_opt_strings_t *)b)->name);
+}
+
+
+void
+cfCatalogFreeChoiceStrings(void* entry,
+                          void* user_data)
+{
+  catalog_choice_strings_t *entry_rec = (catalog_choice_strings_t *)entry;
+
+  if (entry_rec) {
+    if (entry_rec->name) free(entry_rec->name);
+    if (entry_rec->human_readable) free(entry_rec->human_readable);
+    free(entry_rec);
+  }
+}
+
+
+void
+cfCatalogFreeOptionStrings(void* entry,
+                          void* user_data)
+{
+  catalog_opt_strings_t *entry_rec = (catalog_opt_strings_t *)entry;
+
+  if (entry_rec) {
+    if (entry_rec->name) free(entry_rec->name);
+    if (entry_rec->human_readable) free(entry_rec->human_readable);
+    if (entry_rec->choices) cupsArrayDelete(entry_rec->choices);
+    free(entry_rec);
+  }
+}
+
+
+cups_array_t *
+cfCatalogOptionArrayNew()
+{
+  return cupsArrayNew3(compare_options, NULL, NULL, 0,
+                      NULL, cfCatalogFreeOptionStrings);
+}
+
+
+catalog_opt_strings_t *
+cfCatalogFindOption(cups_array_t *options,
+                   char *name)
+{
+  catalog_opt_strings_t opt;
+
+  if (!name || !options)
+    return NULL;
+
+  opt.name = name;
+  return cupsArrayFind(options, &opt);
+}
+
+
+catalog_choice_strings_t *
+cfCatalogFindChoice(cups_array_t *choices,
+                   char *name)
+{
+  catalog_choice_strings_t choice;
+
+  if (!name || !choices)
+    return NULL;
+
+  choice.name = name;
+  return cupsArrayFind(choices, &choice);
+}
+
+
+catalog_opt_strings_t *
+cfCatalogAddOption(char *name,
+                  char *human_readable,
+                  cups_array_t *options)
+{
+  catalog_opt_strings_t *opt = NULL;
+
+  if (!name || !options)
+    return NULL;
+
+  if ((opt = cfCatalogFindOption(options, name)) == NULL) {
+    opt = calloc(1, sizeof(catalog_opt_strings_t));
+    if (!opt) return NULL;
+    opt->human_readable = NULL;
+    opt->choices = cupsArrayNew3(compare_choices, NULL, NULL, 0,
+                                NULL, cfCatalogFreeChoiceStrings);
+    if (!opt->choices) {
+      free(opt);
+      return NULL;
+    }
+    opt->name = strdup(name);
+    if (!cupsArrayAdd(options, opt)) {
+      cfCatalogFreeOptionStrings(opt, NULL);
+      return NULL;
+    }
+  }
+
+  if (human_readable)
+    opt->human_readable = strdup(human_readable);
+
+  return opt;
+}
+
+
+catalog_choice_strings_t *
+cfCatalogAddChoice(char *name,
+                   char *human_readable,
+                   char *opt_name,
+                   cups_array_t *options)
+{
+  catalog_choice_strings_t *choice = NULL;
+  catalog_opt_strings_t *opt;
+
+  if (!name || !human_readable || !opt_name || !options)
+    return NULL;
+
+  opt = cfCatalogAddOption(opt_name, NULL, options);
+  if (!opt) return NULL;
+
+  if ((choice = cfCatalogFindChoice(opt->choices, name)) == NULL) {
+    choice = calloc(1, sizeof(catalog_choice_strings_t));
+    if (!choice) return NULL;
+    choice->human_readable = NULL;
+    choice->name = strdup(name);
+    if (!cupsArrayAdd(opt->choices, choice)) {
+      cfCatalogFreeChoiceStrings(choice, NULL);
+      return NULL;
+    }
+  }
+
+  if (human_readable)
+    choice->human_readable = strdup(human_readable);
+
+  return choice;
+
+}
+
+
+char *
+cfCatalogLookUpOption(char *name,
+                     cups_array_t *options,
+                     cups_array_t *printer_options)
+{
+  catalog_opt_strings_t *opt = NULL;
+
+  if (!name || !options)
+    return NULL;
+
+  if (printer_options &&
+      (opt = cfCatalogFindOption(printer_options, name)) != NULL)
+    return opt->human_readable;
+  if ((opt = cfCatalogFindOption(options, name)) != NULL)
+    return opt->human_readable;
+  else
+    return NULL;
+}
+
+
+char *
+cfCatalogLookUpChoice(char *name,
+                     char *opt_name,
+                     cups_array_t *options,
+                     cups_array_t *printer_options)
+{
+  catalog_opt_strings_t *opt = NULL;
+  catalog_choice_strings_t *choice = NULL;
+
+  if (!name || !opt_name || !options)
+    return NULL;
+
+  if (printer_options &&
+      (opt = cfCatalogFindOption(printer_options, opt_name)) != NULL &&
+      (choice = cfCatalogFindChoice(opt->choices, name)) != NULL)
+    return choice->human_readable;
+  else if ((opt = cfCatalogFindOption(options, opt_name)) != NULL &&
+          (choice = cfCatalogFindChoice(opt->choices, name)) != NULL)
+    return choice->human_readable;
+  else
+    return NULL;
+}
+
+
+void
+cfCatalogLoad(const char *location,
+             cups_array_t *options)
+{
+  char tmpfile[1024];
+  const char *filename = NULL;
+  struct stat statbuf;
+  cups_file_t *fp;
+  char line[65536];
+  char *ptr, *start, *start2, *end, *end2, *sep;
+  char *opt_name = NULL, *choice_name = NULL,
+       *human_readable = NULL;
+  int part = -1; /* -1: before first "msgid" or invalid
+                       line
+                    0: "msgid"
+                    1: "msgstr"
+                    2: "..." = "..."
+                   10: EOF, save last entry */
+  int digit;
+  int found_in_catalog = 0;
+
+  if (location == NULL || (strncasecmp(location, "http:", 5) &&
+                          strncasecmp(location, "https:", 6))) {
+    if (location == NULL ||
+       (stat(location, &statbuf) == 0 &&
+        S_ISDIR(statbuf.st_mode))) /* directory? */
+    {
+      filename = cfCatalogFind(location);
+      if (filename)
+        found_in_catalog = 1;
+    }
+    else
+      filename = location;
+  } else {
+    if (cfGetURI(location, tmpfile, sizeof(tmpfile)))
+      filename = tmpfile;
+  }
+  if (!filename)
+    return;
+
+  if ((fp = cupsFileOpen(filename, "r")) == NULL)
+  {
+    if (filename == tmpfile)
+      unlink(filename);
+    return;
+  }
+
+  while (cupsFileGets(fp, line, sizeof(line)) || (part = 10)) {
+    /* Find a pair of quotes delimiting a string in each line
+       and optional "msgid" or "msgstr" keywords, or a
+       "..." = "..." pair. Skip comments ('#') and empty lines. */
+    if (part < 10) {
+      ptr = line;
+      while (isspace(*ptr)) ptr ++;
+      if (*ptr == '#' || *ptr == '\0') continue;
+      if ((start = strchr(ptr, '\"')) == NULL) continue;
+      if ((end = strrchr(ptr, '\"')) == start) continue;
+      if (*(end - 1) == '\\') continue;
+      start2 = NULL;
+      end2 = NULL;
+      if (start > ptr) {
+       if (*(start - 1) == '\\') continue;
+       if (strncasecmp(ptr, "msgid", 5) == 0) part = 0;
+       if (strncasecmp(ptr, "msgstr", 6) == 0) part = 1;
+      } else {
+       start2 = ptr;
+       while ((start2 = strchr(start2 + 1, '\"')) < end &&
+              *(start2 - 1) == '\\');
+       if (start2 < end) {
+         /* Line with "..." = "..." of text/strings format */
+         end2 = end;
+         end = start2;
+         start2 ++;
+         while (isspace(*start2)) start2 ++;
+         if (*start2 != '=') continue;
+         start2 ++;
+         while (isspace(*start2)) start2 ++;
+         if (*start2 != '\"') continue;
+         start2 ++;
+         *end2 = '\0';
+         part = 2;
+       } else
+         /* Continuation line in message catalog file */
+         start2 = NULL;
+      }
+      start ++;
+      *end = '\0';
+    }
+    /* Read out the strings between the quotes and save entries */
+    if (part == 0 || part == 2 || part == 10) {
+      /* Save previous attribute */
+      if (human_readable) {
+       if (opt_name) {
+         if (choice_name) {
+           cfCatalogAddChoice(choice_name, human_readable,
+                              opt_name, options);
+           free(choice_name);
+         } else
+           cfCatalogAddOption(opt_name, human_readable, options);
+         free(opt_name);
+       }
+       free(human_readable);
+       opt_name = NULL;
+       choice_name = NULL;
+       human_readable = NULL;
+      }
+      /* Stop the loop after saving the last entry */
+      if (part == 10)
+       break;
+      /* IPP attribute has to be defined with a single msgid line,
+        no continuation lines */
+      if (opt_name) {
+       free (opt_name);
+       opt_name = NULL;
+       if (choice_name) {
+         free (choice_name);
+         choice_name = NULL;
+       }
+       part = -1;
+       continue;
+      }
+      /* No continuation line in text/strings format */
+      if (part == 2 && (start2 == NULL || end2 == NULL)) {
+       part = -1;
+       continue;
+      }
+      /* Check line if it is a valid IPP attribute:
+        No spaces, only lowercase letters, digits, '-', '_',
+        "option" or "option.choice" */
+      for (ptr = start, sep = NULL; ptr < end; ptr ++)
+       if (*ptr == '.') { /* Separator between option and choice */
+         if (!sep) { /* Only the first '.' counts */
+           sep = ptr + 1;
+           *ptr = '\0';
+         }
+       } else if (!((*ptr >= 'a' && *ptr <= 'z') ||
+                    (*ptr >= '0' && *ptr <= '9') ||
+                    *ptr == '-' || *ptr == '_'))
+         break;
+      if (ptr < end) { /* Illegal character found */
+       part = -1;
+       continue;
+      }
+      if (strlen(start) > 0) /* Option name found */
+       opt_name = strdup(start);
+      else { /* Empty option name */
+       part = -1;
+       continue;
+      }
+      if (sep && strlen(sep) > 0) /* Choice name found */
+       choice_name = strdup(sep);
+      else /* Empty choice name */
+       choice_name = NULL;
+      if (part == 2) { /* Human-readable string in the same line */
+       start = start2;
+       end = end2;
+      }
+    }
+    if (part == 1 || part == 2) {
+      /* msgid was not for an IPP attribute, ignore this msgstr */
+      if (!opt_name) continue;
+      /* Empty string */
+      if (start == end) continue;
+      /* Unquote string */
+      ptr = start;
+      end = start;
+      while (*ptr) {
+       if (*ptr == '\\') {
+         ptr ++;
+         if (isdigit(*ptr)) {
+           digit = 0;
+           *end = 0;
+           while (isdigit(*ptr) && digit < 3) {
+             *end = *end * 8 + *ptr - '0';
+             digit ++;
+             ptr ++;
+           }
+           end ++;
+         } else {
+           if (*ptr == 'n')
+             *end ++ = '\n';
+           else if (*ptr == 'r')
+             *end ++ = '\r';
+           else if (*ptr == 't')
+             *end ++ = '\t';
+           else
+             *end ++ = *ptr;
+           ptr ++;
+         }
+       } else
+         *end ++ = *ptr ++;
+      }
+      *end = '\0';
+      /* Did the unquoting make the string empty? */
+      if (strlen(start) == 0) continue;
+      /* Add the string to our human-readable string */
+      if (human_readable) { /* Continuation line */
+       human_readable = realloc(human_readable,
+                                sizeof(char) *
+                                (strlen(human_readable) +
+                                 strlen(start) + 2));
+       ptr = human_readable + strlen(human_readable);
+       *ptr = ' ';
+       strncpy(ptr + 1, start,
+               sizeof(human_readable) - (ptr - human_readable) - 1);
+      } else /* First line */
+       human_readable = strdup(start);
+    }
+  }
+  cupsFileClose(fp);
+  if (choice_name != NULL)
+    free(choice_name);
+  if (opt_name != NULL)
+    free(opt_name);
+  if (filename == tmpfile)
+    unlink(filename);
+  if (found_in_catalog)
+    free((char *)filename);
+}
diff --git a/cupsfilters/catalog.h b/cupsfilters/catalog.h
new file mode 100644 (file)
index 0000000..cfd95f1
--- /dev/null
@@ -0,0 +1,92 @@
+ /***
+  This file is part of cups-filters.
+
+  This file is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as
+  published by the Free Software Foundation; either version 2.1 of the
+  License, or (at your option) any later version.
+
+  This file is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
+  Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with avahi; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+  USA.
+***/
+
+#ifndef _CUPS_FILTERS_CATALOG_H_
+#  define _CUPS_FILTERS_CATALOG_H_
+
+#  ifdef __cplusplus
+extern "C" {
+#  endif /* __cplusplus */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <math.h>
+
+#if defined(WIN32) || defined(__EMX__)
+#  include <io.h>
+#else
+#  include <unistd.h>
+#  include <fcntl.h>
+#endif /* WIN32 || __EMX__ */
+
+#include <cups/cups.h>
+#include <cups/backend.h>
+#include <cups/raster.h>
+
+/* Data structure for IPP choice name and human-readable string */
+typedef struct catalog_choice_strings_s {
+  char *name, *human_readable;
+} catalog_choice_strings_t;
+
+/* Data structure for IPP option name, human-readable string, and choice list */
+typedef struct catalog_opt_strings_s {
+  char *name, *human_readable;
+  cups_array_t *choices;
+} catalog_opt_strings_t;
+
+
+/*
+ * Prototypes...
+ */
+
+int             cfGetURI(const char *url, char *name, size_t namesize);
+const char      *cfCatalogSearchDir(const char *dirname);
+const char      *cfCatalogFind(const char *preferreddir);
+void            cfCatalogFreeChoiceStrings(void* entry, void* user_data);
+void            cfCatalogFreeOptionStrings(void* entry, void* user_data);
+cups_array_t    *cfCatalogOptionArrayNew();
+catalog_opt_strings_t *cfCatalogFindOption(cups_array_t *options, char *name);
+catalog_choice_strings_t *cfCatalogFindChoice(cups_array_t *choices,
+                                             char *name);
+catalog_opt_strings_t *cfCatalogAddOption(char *name, char *human_readable,
+                                         cups_array_t *options);
+catalog_choice_strings_t *cfCatalogAddChoice(char *name, char *human_readable,
+                                            char *opt_name,
+                                            cups_array_t *options);
+char            *cfCatalogLookUpOption(char *name, cups_array_t *options,
+                                      cups_array_t *printer_options);
+char            *cfCatalogLookUpChoice(char *name, char *opt_name,
+                                      cups_array_t *options,
+                                      cups_array_t *printer_options);
+void            cfCatalogLoad(const char *location, cups_array_t *options);
+
+
+#  ifdef __cplusplus
+}
+#  endif /* __cplusplus */
+
+#endif /* !_CUPS_FILTERS_CATALOG_H_ */
index 3dcaa6882cf3fbcca344096d6b0b08584fc2c000..448d93586f34ead2165c9558c73f83454fc62fde 100644 (file)
@@ -16,7 +16,6 @@
  *   cfCMYKDoCMYK()      - Do a CMYK separation...
  *   cfCMYKDoGray()      - Do a grayscale separation...
  *   cfCMYKDoRGB()       - Do an sRGB separation...
- *   cfCMYKLoad()        - Load a CMYK color profile from PPD attributes.
  *   cfCMYKNew()         - Create a new CMYK color separation.
  *   cfCMYKSetBlack()    - Set the transition range for CMY to black.
  *   cfCMYKSetCurve()    - Set a color transform curve using points.
@@ -1016,603 +1015,6 @@ cfCMYKDoRGB(const cf_cmyk_t   *cmyk,
 }
 
 
-/*
- * 'cfCMYKLoad()' - Load a CMYK color profile from PPD attributes.
- */
-
-cf_cmyk_t *                            /* O - CMYK color separation */
-cfCMYKLoad(ppd_file_t *ppd,            /* I - PPD file */
-            const char *colormodel,    /* I - ColorModel value */
-            const char *media,         /* I - MediaType value */
-            const char *resolution,    /* I - Resolution value */
-            cf_logfunc_t log,      /* I - Log function */
-            void       *ld)            /* I - Log function data */
-{
-  cf_cmyk_t    *cmyk;                  /* CMYK color separation */
-  char         spec[PPD_MAX_NAME];     /* Profile name */
-  ppd_attr_t   *attr;                  /* Attribute from PPD file */
-  int          num_channels;           /* Number of color components */
-  float                gamval,                 /* Gamma correction value */
-               density,                /* Density value */
-               light,                  /* Light ink limit */
-               dark,                   /* Light ink cut-off */
-               lower,                  /* Start of black ink */
-               upper;                  /* End of color ink */
-  int          num_xypoints;           /* Number of X,Y points */
-  float                xypoints[100 * 2],      /* X,Y points */
-               *xyptr;                 /* Current X,Y point */
-
-
- /*
-  * Range check input...
-  */
-
-  if (ppd == NULL || colormodel == NULL || resolution == NULL || media == NULL)
-    return (NULL);
-
- /*
-  * Find the following attributes:
-  *
-  *     cupsAllGamma          - Set default curve using gamma + density
-  *     cupsAllXY             - Set default curve using XY points
-  *     cupsBlackGamma        - Set black curve using gamma + density
-  *     cupsBlackGeneration   - Set black generation
-  *     cupsBlackLightDark    - Set black light/dark transition
-  *     cupsBlackXY           - Set black curve using XY points
-  *     cupsCyanGamma         - Set cyan curve using gamma + density
-  *     cupsCyanLightDark     - Set cyan light/dark transition
-  *     cupsCyanXY            - Set cyan curve using XY points
-  *     cupsInkChannels       - Set number of color channels
-  *     cupsInkLimit          - Set total ink limit
-  *     cupsLightBlackGamma   - Set light black curve using gamma + density
-  *     cupsLightBlackXY      - Set light black curve using XY points
-  *     cupsLightCyanGamma    - Set light cyan curve using gamma + density
-  *     cupsLightCyanXY       - Set light cyan curve using XY points
-  *     cupsLightMagentaGamma - Set light magenta curve using gamma + density
-  *     cupsLightMagentaXY    - Set light magenta curve using XY points
-  *     cupsMagentaGamma      - Set magenta curve using gamma + density
-  *     cupsMagentaLightDark  - Set magenta light/dark transition
-  *     cupsMagentaXY         - Set magenta curve using XY points
-  *     cupsYellowGamma       - Set yellow curve using gamma + density
-  *     cupsYellowXY          - Set yellow curve using XY points
-  *
-  * The only required attribute is cupsInkChannels.
-  *
-  * The *XY attributes have precedence over the *Gamma attributes, and
-  * the *Light* attributes have precedence over the corresponding
-  * *LightDark* attributes.
-  */
-
- /*
-  * Get the required cupsInkChannels attribute...
-  */
-
-  if ((attr = cfFindAttr(ppd, "cupsInkChannels", colormodel, media,
-                           resolution, spec, sizeof(spec), log, ld)) == NULL)
-    return (NULL);
-
-  num_channels = atoi(attr->value);
-
-  if (num_channels < 1 || num_channels > 7 || num_channels == 5)
-    return (NULL);
-
-  if ((cmyk = cfCMYKNew(num_channels)) == NULL)
-    return (NULL);
-
- /*
-  * Get the optional cupsInkLimit attribute...
-  */
-
-  if ((attr = cfFindAttr(ppd, "cupsInkLimit", colormodel, media,
-                           resolution, spec, sizeof(spec), log, ld)) != NULL)
-    cfCMYKSetInkLimit(cmyk, atof(attr->value));
-
- /*
-  * Get the optional cupsBlackGeneration attribute...
-  */
-
-  if ((attr = cfFindAttr(ppd, "cupsBlackGeneration", colormodel, media,
-                           resolution, spec, sizeof(spec), log, ld)) != NULL)
-  {
-    if (sscanf(attr->value, "%f%f", &lower, &upper) == 2)
-      cfCMYKSetBlack(cmyk, lower, upper, log, ld);
-  }
-
- /*
-  * Get the optional cupsBlackXY or cupsBlackGamma attributes...
-  */
-
-  if (num_channels != 3)
-  {
-    if ((attr = cfFindAttr(ppd, "cupsBlackXY", colormodel, media,
-                             resolution, spec, sizeof(spec), log, ld)) != NULL)
-    {
-      for (num_xypoints = 0, xyptr = xypoints;
-           attr != NULL && attr->value != NULL && num_xypoints < 100;
-          attr = ppdFindNextAttr(ppd, "cupsBlackXY", spec))
-       if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
-       {
-          num_xypoints ++;
-         xyptr += 2;
-       }
-
-      switch (num_channels)
-      {
-       case 1 :
-       case 2 :
-            cfCMYKSetCurve(cmyk, 0, num_xypoints, xypoints, log, ld);
-           break;
-       case 4 :
-            cfCMYKSetCurve(cmyk, 3, num_xypoints, xypoints, log, ld);
-           break;
-       case 6 :
-       case 7 :
-            cfCMYKSetCurve(cmyk, 5, num_xypoints, xypoints, log, ld);
-           break;
-      }
-    }
-    else if ((attr = cfFindAttr(ppd, "cupsBlackGamma", colormodel,
-                                  media, resolution, spec,
-                                 sizeof(spec), log, ld)) != NULL)
-    {
-      if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
-       switch (num_channels)
-       {
-         case 1 :
-         case 2 :
-              cfCMYKSetGamma(cmyk, 0, gamval, density, log, ld);
-             break;
-         case 4 :
-              cfCMYKSetGamma(cmyk, 3, gamval, density, log, ld);
-             break;
-         case 6 :
-         case 7 :
-              cfCMYKSetGamma(cmyk, 5, gamval, density, log, ld);
-             break;
-       }
-    }
-    else if ((attr = cfFindAttr(ppd, "cupsAllXY", colormodel, media,
-                                  resolution, spec, sizeof(spec), log, ld)) !=
-            NULL)
-    {
-      for (num_xypoints = 0, xyptr = xypoints;
-           attr != NULL && attr->value != NULL && num_xypoints < 100;
-          attr = ppdFindNextAttr(ppd, "cupsAllXY", spec))
-       if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
-       {
-          num_xypoints ++;
-         xyptr += 2;
-       }
-
-      switch (num_channels)
-      {
-       case 1 :
-       case 2 :
-            cfCMYKSetCurve(cmyk, 0, num_xypoints, xypoints, log, ld);
-           break;
-       case 4 :
-            cfCMYKSetCurve(cmyk, 3, num_xypoints, xypoints, log, ld);
-           break;
-       case 6 :
-       case 7 :
-            cfCMYKSetCurve(cmyk, 5, num_xypoints, xypoints, log, ld);
-           break;
-      }
-    }
-    else if ((attr = cfFindAttr(ppd, "cupsAllGamma", colormodel,
-                                  media, resolution, spec,
-                                 sizeof(spec), log, ld)) != NULL &&
-             num_channels != 3)
-    {
-      if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
-       switch (num_channels)
-       {
-         case 1 :
-         case 2 :
-              cfCMYKSetGamma(cmyk, 0, gamval, density, log, ld);
-             break;
-         case 4 :
-              cfCMYKSetGamma(cmyk, 3, gamval, density, log, ld);
-             break;
-         case 6 :
-         case 7 :
-              cfCMYKSetGamma(cmyk, 5, gamval, density, log, ld);
-             break;
-       }
-    }
-  }
-
-  if (num_channels > 2)
-  {
-   /*
-    * Get the optional cupsCyanXY or cupsCyanGamma attributes...
-    */
-
-    if ((attr = cfFindAttr(ppd, "cupsCyanXY", colormodel, media,
-                             resolution, spec, sizeof(spec), log, ld)) != NULL)
-    {
-      for (num_xypoints = 0, xyptr = xypoints;
-           attr != NULL && attr->value != NULL && num_xypoints < 100;
-          attr = ppdFindNextAttr(ppd, "cupsCyanXY", spec))
-       if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
-       {
-          num_xypoints ++;
-         xyptr += 2;
-       }
-
-      cfCMYKSetCurve(cmyk, 0, num_xypoints, xypoints, log, ld);
-    }
-    else if ((attr = cfFindAttr(ppd, "cupsCyanGamma", colormodel, media,
-                                  resolution, spec, sizeof(spec), log, ld)) !=
-            NULL)
-    {
-      if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
-       cfCMYKSetGamma(cmyk, 0, gamval, density, log, ld);
-    }
-    else if ((attr = cfFindAttr(ppd, "cupsAllXY", colormodel, media,
-                                  resolution, spec, sizeof(spec), log, ld)) !=
-            NULL)
-    {
-      for (num_xypoints = 0, xyptr = xypoints;
-           attr != NULL && attr->value != NULL && num_xypoints < 100;
-          attr = ppdFindNextAttr(ppd, "cupsAllXY", spec))
-       if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
-       {
-          num_xypoints ++;
-         xyptr += 2;
-       }
-
-      cfCMYKSetCurve(cmyk, 0, num_xypoints, xypoints, log, ld);
-    }
-    else if ((attr = cfFindAttr(ppd, "cupsAllGamma", colormodel, media,
-                                  resolution, spec, sizeof(spec), log, ld)) !=
-            NULL)
-    {
-      if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
-       cfCMYKSetGamma(cmyk, 0, gamval, density, log, ld);
-    }
-
-   /*
-    * Get the optional cupsMagentaXY or cupsMagentaGamma attributes...
-    */
-
-    if ((attr = cfFindAttr(ppd, "cupsMagentaXY", colormodel, media,
-                             resolution, spec, sizeof(spec), log, ld)) != NULL)
-    {
-      for (num_xypoints = 0, xyptr = xypoints;
-           attr != NULL && attr->value != NULL && num_xypoints < 100;
-          attr = ppdFindNextAttr(ppd, "cupsMagentaXY", spec))
-       if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
-       {
-          num_xypoints ++;
-         xyptr += 2;
-       }
-
-      switch (num_channels)
-      {
-       case 3 :
-       case 4 :
-            cfCMYKSetCurve(cmyk, 1, num_xypoints, xypoints, log, ld);
-           break;
-       case 6 :
-       case 7 :
-            cfCMYKSetCurve(cmyk, 2, num_xypoints, xypoints, log, ld);
-           break;
-      }
-    }
-    else if ((attr = cfFindAttr(ppd, "cupsMagentaGamma", colormodel, media,
-                                  resolution, spec, sizeof(spec), log, ld)) !=
-            NULL)
-    {
-      if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
-       switch (num_channels)
-       {
-         case 3 :
-         case 4 :
-              cfCMYKSetGamma(cmyk, 1, gamval, density, log, ld);
-             break;
-         case 6 :
-         case 7 :
-              cfCMYKSetGamma(cmyk, 2, gamval, density, log, ld);
-             break;
-       }
-    }
-    else if ((attr = cfFindAttr(ppd, "cupsAllXY", colormodel, media,
-                                  resolution, spec, sizeof(spec), log, ld)) !=
-            NULL)
-    {
-      for (num_xypoints = 0, xyptr = xypoints;
-           attr != NULL && attr->value != NULL && num_xypoints < 100;
-          attr = ppdFindNextAttr(ppd, "cupsAllXY", spec))
-       if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
-       {
-          num_xypoints ++;
-         xyptr += 2;
-       }
-
-      switch (num_channels)
-      {
-       case 3 :
-       case 4 :
-            cfCMYKSetCurve(cmyk, 1, num_xypoints, xypoints, log, ld);
-           break;
-       case 6 :
-       case 7 :
-            cfCMYKSetCurve(cmyk, 2, num_xypoints, xypoints, log, ld);
-           break;
-      }
-    }
-    else if ((attr = cfFindAttr(ppd, "cupsAllGamma", colormodel, media,
-                                  resolution, spec, sizeof(spec), log, ld)) !=
-            NULL)
-    {
-      if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
-       switch (num_channels)
-       {
-         case 3 :
-         case 4 :
-              cfCMYKSetGamma(cmyk, 1, gamval, density, log, ld);
-             break;
-         case 6 :
-         case 7 :
-              cfCMYKSetGamma(cmyk, 2, gamval, density, log, ld);
-             break;
-       }
-    }
-
-   /*
-    * Get the optional cupsYellowXY or cupsYellowGamma attributes...
-    */
-
-    if ((attr = cfFindAttr(ppd, "cupsYellowXY", colormodel, media,
-                             resolution, spec, sizeof(spec), log, ld)) != NULL)
-    {
-      for (num_xypoints = 0, xyptr = xypoints;
-           attr != NULL && attr->value != NULL && num_xypoints < 100;
-          attr = ppdFindNextAttr(ppd, "cupsYellowXY", spec))
-       if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
-       {
-          num_xypoints ++;
-         xyptr += 2;
-       }
-
-      switch (num_channels)
-      {
-       case 3 :
-       case 4 :
-            cfCMYKSetCurve(cmyk, 2, num_xypoints, xypoints, log, ld);
-           break;
-       case 6 :
-       case 7 :
-            cfCMYKSetCurve(cmyk, 4, num_xypoints, xypoints, log, ld);
-           break;
-      }
-    }
-    else if ((attr = cfFindAttr(ppd, "cupsYellowGamma", colormodel, media,
-                                  resolution, spec, sizeof(spec), log, ld)) !=
-            NULL)
-    {
-      if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
-       switch (num_channels)
-       {
-         case 3 :
-         case 4 :
-              cfCMYKSetGamma(cmyk, 2, gamval, density, log, ld);
-             break;
-         case 6 :
-         case 7 :
-              cfCMYKSetGamma(cmyk, 4, gamval, density, log, ld);
-             break;
-       }
-    }
-    else if ((attr = cfFindAttr(ppd, "cupsAllXY", colormodel, media,
-                                  resolution, spec, sizeof(spec), log, ld)) !=
-            NULL)
-    {
-      for (num_xypoints = 0, xyptr = xypoints;
-           attr != NULL && attr->value != NULL && num_xypoints < 100;
-          attr = ppdFindNextAttr(ppd, "cupsAllXY", spec))
-       if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
-       {
-          num_xypoints ++;
-         xyptr += 2;
-       }
-
-      switch (num_channels)
-      {
-       case 3 :
-       case 4 :
-            cfCMYKSetCurve(cmyk, 2, num_xypoints, xypoints, log, ld);
-           break;
-       case 6 :
-       case 7 :
-            cfCMYKSetCurve(cmyk, 4, num_xypoints, xypoints, log, ld);
-           break;
-      }
-    }
-    else if ((attr = cfFindAttr(ppd, "cupsAllGamma", colormodel, media,
-                                  resolution, spec, sizeof(spec), log, ld)) !=
-            NULL)
-    {
-      if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
-       switch (num_channels)
-       {
-         case 3 :
-         case 4 :
-              cfCMYKSetGamma(cmyk, 2, gamval, density, log, ld);
-             break;
-         case 6 :
-         case 7 :
-              cfCMYKSetGamma(cmyk, 4, gamval, density, log, ld);
-             break;
-       }
-    }
-  }
-
- /*
-  * Get the optional cupsLightBlackXY, cupsLightBlackGamma, or
-  * cupsBlackLtDk attributes...
-  */
-
-  if (num_channels == 2 || num_channels == 7)
-  {
-    if ((attr = cfFindAttr(ppd, "cupsLightBlackXY", colormodel, media,
-                             resolution, spec, sizeof(spec), log, ld)) != NULL)
-    {
-      for (num_xypoints = 0, xyptr = xypoints;
-           attr != NULL && attr->value != NULL && num_xypoints < 100;
-          attr = ppdFindNextAttr(ppd, "cupsLightBlackXY", spec))
-       if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
-       {
-          num_xypoints ++;
-         xyptr += 2;
-       }
-
-      switch (num_channels)
-      {
-       case 2 :
-            cfCMYKSetCurve(cmyk, 1, num_xypoints, xypoints, log, ld);
-           break;
-       case 7 :
-            cfCMYKSetCurve(cmyk, 6, num_xypoints, xypoints, log, ld);
-           break;
-      }
-    }
-    else if ((attr = cfFindAttr(ppd, "cupsLightBlackGamma", colormodel,
-                                  media, resolution, spec,
-                                 sizeof(spec), log, ld)) != NULL)
-    {
-      if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
-       switch (num_channels)
-       {
-         case 2 :
-              cfCMYKSetGamma(cmyk, 1, gamval, density, log, ld);
-             break;
-         case 7 :
-              cfCMYKSetGamma(cmyk, 6, gamval, density, log, ld);
-             break;
-       }
-    }
-    else if ((attr = cfFindAttr(ppd, "cupsBlackLtDk", colormodel, media,
-                                  resolution, spec, sizeof(spec), log, ld)) !=
-            NULL)
-    {
-      if (sscanf(attr->value, "%f%f", &light, &dark) == 2)
-       switch (num_channels)
-       {
-         case 2 :
-              cfCMYKSetLtDk(cmyk, 0, light, dark, log, ld);
-             break;
-         case 7 :
-              cfCMYKSetLtDk(cmyk, 5, light, dark, log, ld);
-             break;
-       }
-      else
-       if (log) log(ld, CF_LOGLEVEL_ERROR,
-                    "Bad cupsBlackLtDk value \"%s\"!",
-                    attr->value);
-    }
-    else
-      if (log) log(ld, CF_LOGLEVEL_WARN,
-                  "No light black attribute found for %s!",
-                  spec);
-  }
-
-  if (num_channels >= 6)
-  {
-   /*
-    * Get the optional cupsLightCyanXY, cupsLightCyanGamma, or
-    * cupsCyanLtDk attributes...
-    */
-
-    if ((attr = cfFindAttr(ppd, "cupsLightCyanXY", colormodel, media,
-                             resolution, spec, sizeof(spec), log, ld)) != NULL)
-    {
-      for (num_xypoints = 0, xyptr = xypoints;
-           attr != NULL && attr->value != NULL && num_xypoints < 100;
-          attr = ppdFindNextAttr(ppd, "cupsLightCyanXY", spec))
-       if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
-       {
-          num_xypoints ++;
-         xyptr += 2;
-       }
-
-      cfCMYKSetCurve(cmyk, 1, num_xypoints, xypoints, log, ld);
-    }
-    else if ((attr = cfFindAttr(ppd, "cupsLightCyanGamma", colormodel,
-                                  media, resolution, spec,
-                                 sizeof(spec), log, ld)) != NULL)
-    {
-      if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
-       cfCMYKSetGamma(cmyk, 1, gamval, density, log, ld);
-    }
-    else if ((attr = cfFindAttr(ppd, "cupsCyanLtDk", colormodel, media,
-                                  resolution, spec, sizeof(spec), log, ld)) !=
-            NULL)
-    {
-      if (sscanf(attr->value, "%f%f", &light, &dark) == 2)
-       cfCMYKSetLtDk(cmyk, 0, light, dark, log, ld);
-      else
-       if (log) log(ld, CF_LOGLEVEL_ERROR,
-                    "Bad cupsCyanLtDk value \"%s\"!",
-                    attr->value);
-    }
-    else
-      if (log) log(ld, CF_LOGLEVEL_WARN,
-                  "No light cyan attribute found for %s!",
-                  spec);
-
-   /*
-    * Get the optional cupsLightMagentaXY, cupsLightMagentaGamma, or
-    * cupsMagentaLtDk attributes...
-    */
-
-    if ((attr = cfFindAttr(ppd, "cupsLightMagentaXY", colormodel, media,
-                             resolution, spec, sizeof(spec), log, ld)) != NULL)
-    {
-      for (num_xypoints = 0, xyptr = xypoints;
-           attr != NULL && attr->value != NULL && num_xypoints < 100;
-          attr = ppdFindNextAttr(ppd, "cupsLightMagentaXY", spec))
-       if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
-       {
-          num_xypoints ++;
-         xyptr += 2;
-       }
-
-      cfCMYKSetCurve(cmyk, 3, num_xypoints, xypoints, log, ld);
-    }
-    else if ((attr = cfFindAttr(ppd, "cupsLightMagentaGamma", colormodel,
-                                  media, resolution, spec,
-                                 sizeof(spec), log, ld)) != NULL)
-    {
-      if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
-       cfCMYKSetGamma(cmyk, 3, gamval, density, log, ld);
-    }
-    else if ((attr = cfFindAttr(ppd, "cupsMagentaLtDk", colormodel, media,
-                                  resolution, spec, sizeof(spec), log, ld)) !=
-            NULL)
-    {
-      if (sscanf(attr->value, "%f%f", &light, &dark) == 2)
-       cfCMYKSetLtDk(cmyk, 2, light, dark, log, ld);
-      else
-       if (log) log(ld, CF_LOGLEVEL_ERROR,
-                    "Bad cupsMagentaLtDk value \"%s\"!",
-                    attr->value);
-    }
-    else
-      if (log) log(ld, CF_LOGLEVEL_WARN,
-                  "No light magenta attribute found for %s!",
-                  spec);
-  }
-
- /*
-  * Return the new profile...
-  */
-
-  return (cmyk);
-}
-
-
 /*
  * 'cfCMYKNew()' - Create a new CMYK color separation.
  */
index 1cb2ad85be52284f0c2ae8c4ead4809b1f3c9928..5ebedacfe6bb6c917d05abe9292c1abd2f5f84ec 100644 (file)
@@ -32,6 +32,7 @@ MIT Open Source License  -  http://www.opensource.org/
 #include <stdio.h>
 #include <sys/types.h>
 #include <cupsfilters/filter.h>
+#include <cupsfilters/raster.h>
 #ifdef HAVE_DBUS
   #include <dbus/dbus.h>
 #endif
@@ -44,76 +45,70 @@ MIT Open Source License  -  http://www.opensource.org/
 #define QUAL_SIZE         3
 
 char **
-cfColordGetQualifierForPPD (ppd_file_t *ppd)
+cfColordGetQualifier(cf_filter_data_t *data,
+                    const char *color_space,
+                    const char *media_type,
+                    int x_res,
+                    int y_res)
 {
-  char q_keyword[PPD_MAX_NAME];
+  int i, len;
+  const char *val;
+  const char *ptr1, *ptr2;
+  char buf[64];
   char **tuple = NULL;
-  const char *q1_choice;
-  const char *q2_choice;
-  const char *q3_choice;
-  ppd_attr_t *attr;
-  ppd_attr_t *q1_attr;
-  ppd_attr_t *q2_attr;
-  ppd_attr_t *q3_attr;
-
-  /* get colorspace */
-  if ((attr = ppdFindAttr (ppd, "cupsICCQualifier1", NULL)) != NULL &&
-      attr->value && attr->value[0])
-  {
-    snprintf (q_keyword, sizeof (q_keyword), "Default%s", attr->value);
-    q1_attr = ppdFindAttr (ppd, q_keyword, NULL);
-  }
-  else if ((q1_attr = ppdFindAttr (ppd, "DefaultColorModel", NULL)) == NULL)
-    q1_attr = ppdFindAttr (ppd, "DefaultColorSpace", NULL);
+  int                  num_options = 0;
+  cups_option_t        *options = NULL;
 
-  if (q1_attr && q1_attr->value && q1_attr->value[0])
-    q1_choice = q1_attr->value;
-  else
-    q1_choice = "";
 
-  /* get media */
-  if ((attr = ppdFindAttr(ppd, "cupsICCQualifier2", NULL)) != NULL &&
-      attr->value && attr->value[0])
+  num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
+
+  /* Get data from "cm-profile-qualifier" option */
+  if ((val =
+       cupsGetOption("cm-profile-qualifier",
+                    data->num_options, data->options)) != NULL &&
+      val[0] != '\0')
   {
-    snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value);
-    q2_attr = ppdFindAttr(ppd, q_keyword, NULL);
+    tuple = calloc(QUAL_SIZE + 1, sizeof(char*));
+    ptr1 = ptr2 = val;
+    for (i = 0; i < QUAL_SIZE; i ++)
+    {
+      while (*ptr2 && *ptr2 != '.') ptr2 ++;
+      len = ptr2 - ptr1;
+      tuple[i] = malloc((len + 1) * sizeof(char));
+      memcpy(tuple[i], ptr1, len);
+      tuple[i][len] = '\0';
+      if (*ptr2)
+       ptr2 ++;
+      ptr1 = ptr2; 
+    }
   }
   else
-    q2_attr = ppdFindAttr(ppd, "DefaultMediaType", NULL);
-
-  if (q2_attr && q2_attr->value && q2_attr->value[0])
-    q2_choice = q2_attr->value;
-  else
-    q2_choice = "";
-
-  /* get resolution */
-  if ((attr = ppdFindAttr(ppd, "cupsICCQualifier3", NULL)) != NULL &&
-      attr->value && attr->value[0])
   {
-    snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value);
-    q3_attr = ppdFindAttr(ppd, q_keyword, NULL);
+    /* String for resolution */
+    if (x_res <= 0)
+      buf[0] = '\0';
+    else if (y_res <= 0 || y_res == x_res)
+      snprintf(buf, sizeof(buf), "%ddpi", x_res);
+    else
+      snprintf(buf, sizeof(buf), "%dx%ddpi", x_res, y_res);
+
+    /* return a NULL terminated array so we don't have to break it up later */
+    tuple = calloc(QUAL_SIZE + 1, sizeof(char*));
+    tuple[QUAL_COLORSPACE] = strdup(color_space ? color_space : "");
+    tuple[QUAL_MEDIA]      = strdup(media_type ? media_type : "");
+    tuple[QUAL_RESOLUTION] = strdup(buf);
   }
-  else
-    q3_attr = ppdFindAttr(ppd, "DefaultResolution", NULL);
-
-  if (q3_attr && q3_attr->value && q3_attr->value[0])
-    q3_choice = q3_attr->value;
-  else
-    q3_choice = "";
+  
+  cupsFreeOptions(num_options, options);
 
-  /* return a NULL terminated array so we don't have to break it up later */
-  tuple = calloc(QUAL_SIZE + 1, sizeof(char*));
-  tuple[QUAL_COLORSPACE] = strdup(q1_choice);
-  tuple[QUAL_MEDIA]      = strdup(q2_choice);
-  tuple[QUAL_RESOLUTION] = strdup(q3_choice);
   return tuple;
 }
 
 #ifdef HAVE_DBUS
 
 static char *
-get_filename_for_profile_path ( cf_filter_data_t *data,
-                               DBusConnection *con,
+get_filename_for_profile_path (cf_filter_data_t *data,
+                              DBusConnection *con,
                                const char *object_path)
 {
   cf_logfunc_t log = data->logfunc;
index 02072b37f487cd87b7a1205b7ada42e85499a834..b37287c32f11aa04534e5733d4ba1c89d8179191 100644 (file)
@@ -35,10 +35,13 @@ extern "C" {
 /* Common routines for accessing the colord CMS framework */
 
 #include <cups/raster.h>
-#include <ppd/ppd.h>
 #include <cupsfilters/filter.h>
 
-char **cfColordGetQualifierForPPD(ppd_file_t *ppd);
+char **cfColordGetQualifier(cf_filter_data_t *data,
+                           const char *color_space,
+                           const char *media_type,
+                           int x_res,
+                           int y_res);
 char *cfColordGetProfileForDeviceID(cf_filter_data_t *data,
                                    const char *device_id,
                                    const char **qualifier_tuple);
index f59926315007422f042c6cc5a54f766ecc019977..90acdb04594584ef12d3f6ad8ade21c123c13000 100644 (file)
@@ -29,23 +29,12 @@ MIT Open Source License  -  http://www.opensource.org/
 #include "colormanager.h"
 #include <cupsfilters/colord.h>
 #include <cupsfilters/filter.h>
+#include <cupsfilters/raster.h>
 
 
 #define CM_MAX_FILE_LENGTH 1024
 
 
-/* Private function prototypes */
-static int      get_colord_printer_cm_status   (cf_filter_data_t *data);
-static char    *get_colord_printer_id          (cf_filter_data_t *data);
-static int      get_colord_profile             (cf_filter_data_t *data,
-                                                 char **profile,
-                                                 ppd_file_t *ppd);
-static char    *get_ppd_icc_fallback           (cf_filter_data_t *data, 
-                                                ppd_file_t *ppd, 
-                                                 char **qualifier);
-
-
-
 /* Commonly-used calibration numbers */
 
 double           adobergb_wp[3] = {0.95045471, 1.0, 1.08905029};
@@ -71,55 +60,118 @@ cfCmIsPrinterCmDisabled(cf_filter_data_t *data)
 {
     cf_logfunc_t log = data->logfunc;
     void *ld = data->logdata;
-    int is_cm_off = 0;          /* color management status flag */
+    int is_printer_cm_disabled = 0;   /* color management status flag */
+    char printer_id[CM_MAX_FILE_LENGTH] = ""; /* colord printer id */ 
+
+
+    /* If invalid input, we leave color management alone */
+    if (data->printer == NULL) {
+      if(log) log(ld, CF_LOGLEVEL_DEBUG,
+               "Color Manager: Invalid printer name.");
+      return 0;
+    }
 
+    /* Create printer id string for colord */
+    snprintf(printer_id, CM_MAX_FILE_LENGTH, "cups-%s", data->printer);
 
-    /* Request color management status from colord */
-    is_cm_off = get_colord_printer_cm_status(data);
+    /* Check if device is inhibited/disabled in colord  */
+    is_printer_cm_disabled = cfColordGetInhibitForDeviceID (data, printer_id);
 
-    if (is_cm_off)
+    if (is_printer_cm_disabled)
        if(log) log(ld, CF_LOGLEVEL_DEBUG,
                "Color Manager: Color management disabled by OS.");
 
-    return is_cm_off;      
-
+    return is_printer_cm_disabled;
 }
 
 
 /* Get printer ICC profile from the system's color manager */
 int 
 cfCmGetPrinterIccProfile(cf_filter_data_t *data,
-                       char **icc_profile,        /* ICC Profile Path */
-                       ppd_file_t *ppd)           /* Optional PPD file for fallback profile */
+                        const char *color_space,
+                        const char *media_type,
+                        int x_res,
+                        int y_res,
+                        char **profile)      /* ICC Profile Path */
 {
     cf_logfunc_t log = data->logfunc;
     void *ld = data->logdata;
-    int profile_set = 0;        /* 'is profile found' flag */
+    const char *val;
+    int   is_profile_set = 0;        /* profile-is-found flag */
+    char  **qualifier = NULL;        /* color qualifier strings */
+    char  *icc_profile = NULL;       /* icc profile path */
+    char  printer_id[CM_MAX_FILE_LENGTH] = ""; /* colord printer id */ 
 
+    if (data->printer == NULL || profile == NULL) {
+      if(log) log(ld, CF_LOGLEVEL_DEBUG,
+                 "Color Manager: Invalid input - Unable to find profile."); 
+      return -1;
+    }
+    /* Get color qualifier triple */
+    qualifier = cfColordGetQualifier(data, color_space, media_type,
+                                    x_res, y_res);
 
-    /* Request a profile from colord */
-    profile_set = get_colord_profile(data, icc_profile, ppd);
-    if(log) log(ld, CF_LOGLEVEL_DEBUG,
-               "Color Manager: ICC Profile: %s", *icc_profile ?
-        *icc_profile : "None");
+    if (qualifier != NULL) {
+      /* Create printer id string for colord */
+      snprintf(printer_id, CM_MAX_FILE_LENGTH, "cups-%s", data->printer);
 
-    return profile_set;
+      /* Get profile from colord using qualifiers */
+      icc_profile = cfColordGetProfileForDeviceID(data,
+                                                 (const char *)printer_id,
+                                                 (const char **)qualifier);
+    }
 
+    /* Do we have a profile? */
+    if (icc_profile)
+      is_profile_set = 1;
+    /* If not, get fallback profile from option */
+    else if ((val = cupsGetOption("cm-fallback-profile",
+                                 data->num_options, data->options)) != NULL &&
+            val[0] != '\0')
+    {
+      is_profile_set = 1;
+      icc_profile = strdup(val);
+    }
+    else
+      icc_profile = NULL;
+
+    /* If a profile is found, we give it to the caller */    
+    if (is_profile_set)
+      *profile = strdup(icc_profile);
+    else 
+      *profile = NULL;
+
+    if (qualifier != NULL) {
+      for (int i=0; qualifier[i] != NULL; i++)
+        free(qualifier[i]);
+      free(qualifier);
+    }
+
+    if (icc_profile != NULL)
+      free(icc_profile);
+
+    if(log) log(ld, CF_LOGLEVEL_DEBUG,
+               "Color Manager: ICC Profile: %s",
+               *profile ? *profile : "None");
+
+    return is_profile_set;
 }
 
 
 /* Find the "cm-calibration" CUPS option */
 cf_cm_calibration_t    
-cfCmGetCupsColorCalibrateMode(cf_filter_data_t *data,
-                           cups_option_t *options,    /* Options from CUPS */
-                            int num_options)           /* Options from CUPS */
+cfCmGetCupsColorCalibrateMode(cf_filter_data_t *data)
 {
-
-    cf_logfunc_t log = data->logfunc;
-    void *ld = data->logdata;
+    int                num_options = 0;
+    cups_option_t      *options = NULL;
+    cf_logfunc_t        log = data->logfunc;
+    void                *ld = data->logdata;
     cf_cm_calibration_t status;     /* color management status */
 
 
+    num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
+
     /* Find the string in CUPS options and */
     if (cupsGetOption(CF_CM_CALIBRATION_STRING, num_options, options) != NULL)
       status = CF_CM_CALIBRATION_ENABLED;
@@ -128,10 +180,11 @@ cfCmGetCupsColorCalibrateMode(cf_filter_data_t *data,
 
     if(log) log(ld, CF_LOGLEVEL_DEBUG,
                "Color Manager: %s", status ?
-           "Calibration Mode/Enabled" : "Calibration Mode/Off");
+               "Calibration Mode/Enabled" : "Calibration Mode/Off");
 
+    cupsFreeOptions(num_options, options);
+    
     return status;
-
 }
 
 
@@ -176,214 +229,3 @@ double *cfCmBlackPointDefault(void)
 {
     return blackpoint_default;
 }
-
-
-
-
-/*
- * Private functions
- */
-
-
-static char * 
-get_colord_printer_id( cf_filter_data_t *data)
-{
-
-    cf_logfunc_t log = data->logfunc;
-    void *ld = data->logdata;
-    if (data->printer == NULL) {
-      if(log) log(ld, CF_LOGLEVEL_DEBUG,
-               "Color Manager: Invalid printer name.");
-      return 0;
-    }
-
-    /* Create printer id string for colord */
-    char* printer_id = (char*)malloc(CM_MAX_FILE_LENGTH);
-    snprintf (printer_id, CM_MAX_FILE_LENGTH, "cups-%s", data->printer);
-
-    return printer_id;    
-
-}
-
-
-static int 
-get_colord_printer_cm_status( cf_filter_data_t *data)
-{
-
-    cf_logfunc_t log = data->logfunc;
-    void *ld = data->logdata;
-
-    /* If invalid input, we leave color management alone */
-    if (data->printer == NULL) {
-      if(log) log(ld, CF_LOGLEVEL_DEBUG,
-               "Color Manager: Invalid printer name.");
-      return 0;
-    } else if (!strcmp(data->printer, "(null)"))
-      return 0;
-    int is_printer_cm_disabled = 0;   /* color management status flag */
-    char *printer_id = 0;             /* colord printer id string */
-
-
-    /* Check if device is inhibited/disabled in colord  */
-    printer_id = get_colord_printer_id(data);
-    is_printer_cm_disabled = cfColordGetInhibitForDeviceID (data, printer_id);
-
-    if (printer_id != NULL)
-      free(printer_id);
-
-    return is_printer_cm_disabled;
-
-}
-
-static int 
-get_colord_profile(cf_filter_data_t *data,
-                    char         **profile,         /* Requested icc profile path */      
-                    ppd_file_t   *ppd)              /* PPD file */
-{
-
-    cf_logfunc_t log = data->logfunc;
-    void *ld = data->logdata;
-
-    if (data->printer == NULL || profile == 0) {
-      if(log) log(ld, CF_LOGLEVEL_DEBUG,
-               "Color Manager: Invalid input - Unable to find profile."); 
-      return -1;
-    }
-    int   is_profile_set = 0;        /* profile-is-found flag */
-    char  **qualifier = NULL;        /* color qualifier strings */
-    char  *icc_profile = NULL;       /* icc profile path */
-    char  *printer_id = NULL;        /* colord printer id */ 
-
-
-    /* Get color qualifier triple */
-    qualifier = cfColordGetQualifierForPPD(ppd);
-
-    if (qualifier != NULL) {
-      printer_id = get_colord_printer_id(data);
-      /* Get profile from colord using qualifiers */
-      icc_profile = cfColordGetProfileForDeviceID (data,
-                                                     (const char *)printer_id,
-                                                     (const char **)qualifier);
-    }
-
-    if (icc_profile) 
-      is_profile_set = 1; 
-    else if (ppd) {
-    /* Get optional fallback PPD profile */
-      icc_profile = get_ppd_icc_fallback(data, ppd, qualifier);
-      if (icc_profile)
-        is_profile_set = 1;
-    }
-
-    /* If a profile is found, we give it to the caller */    
-    if (is_profile_set)
-      *profile = strdup(icc_profile);
-    else 
-      *profile = 0;
-
-    if (printer_id != NULL)
-      free(printer_id);
-
-    if (qualifier != NULL) {
-      for (int i=0; qualifier[i] != NULL; i++)
-        free(qualifier[i]);
-      free(qualifier);
-    }
-
-    if (icc_profile != NULL)
-      free(icc_profile);
-
-    return is_profile_set;
-
-}
-
-
-#ifndef CUPSDATA
-#define CUPSDATA "/usr/share/cups"
-#endif
-
-/* From gstoraster */
-static char *
-get_ppd_icc_fallback (cf_filter_data_t *data, ppd_file_t *ppd, char **qualifier)
-{
-
-  cf_logfunc_t log = data->logfunc;
-  void *ld = data->logdata;
-  char full_path[1024];
-  char *icc_profile = NULL;
-  char qualifer_tmp[1024];
-  const char *profile_key;
-  ppd_attr_t *attr;
-
-  /* get profile attr, falling back to CUPS */
-  profile_key = "APTiogaProfile";
-  attr = ppdFindAttr(ppd, profile_key, NULL);
-  if (attr == NULL) {
-    profile_key = "cupsICCProfile";
-    attr = ppdFindAttr(ppd, profile_key, NULL);
-  }
-
-  /* create a string for a quick comparion */
-  snprintf(qualifer_tmp, sizeof(qualifer_tmp),
-           "%s.%s.%s",
-           qualifier[0],
-           qualifier[1],
-           qualifier[2]);
-
-  /* neither */
-  if (attr == NULL) {
-    if(log) log(ld, CF_LOGLEVEL_INFO,
-               "Color Manager: no profiles specified in PPD");
-               
-    goto out;
-  }
-
-  /* try to find a profile that matches the qualifier exactly */
-  for (;attr != NULL; attr = ppdFindNextAttr(ppd, profile_key, NULL)) {
-    if(log) log(ld, CF_LOGLEVEL_INFO,
-               "Color Manager: found profile %s in PPD with qualifier '%s'",
-                       attr->value, attr->spec);
-
-    /* invalid entry */
-    if (attr->spec == NULL || attr->value == NULL)
-      continue;
-
-    /* expand to a full path if not already specified */
-    if (attr->value[0] != '/')
-      snprintf(full_path, sizeof(full_path),
-               "%s/profiles/%s", CUPSDATA, attr->value);
-    else {
-      strncpy(full_path, attr->value, sizeof(full_path) - 1);
-      if (strlen(attr->value) > 1023)
-        full_path[1023] = '\0';
-    }
-
-    /* check the file exists */
-    if (access(full_path, 0)) {
-      if(log) log(ld, CF_LOGLEVEL_INFO,
-               "Color Manager: found profile %s in PPD that does not exist",
-              full_path);
-      continue;
-    }
-
-    /* matches the qualifier */
-    if (strcmp(qualifer_tmp, attr->spec) == 0) {
-      icc_profile = strdup(full_path);
-      goto out;
-    }
-  }
-
-  /* no match */
-  if (attr == NULL) {
-    if(log) log(ld, CF_LOGLEVEL_INFO,
-               "Color Manager: no profiles in PPD for qualifier '%s'",
-            qualifer_tmp);
-    goto out;
-  }
-
-out:
-  return icc_profile;
-}
-
index 30d3f07cee0950681c9224631a3ed806911ce552..020d8ab6b886a79f08e316bd8b9565646da4959a 100644 (file)
@@ -38,7 +38,6 @@ extern "C" {
 
 
 #include <cups/raster.h>
-#include <ppd/ppd.h>
 #include <cupsfilters/filter.h>
 
 
@@ -62,13 +61,14 @@ typedef enum cf_cm_calibration_e
 
 
 extern 
-cf_cm_calibration_t cfCmGetCupsColorCalibrateMode(cf_filter_data_t *data,
-                                                 cups_option_t *options,
-                                                 int num_options);
+cf_cm_calibration_t cfCmGetCupsColorCalibrateMode(cf_filter_data_t *data);
 
 extern int cfCmGetPrinterIccProfile(cf_filter_data_t *data,
-                                   char **icc_profile,
-                                   ppd_file_t *ppd);
+                                   const char *color_space,
+                                   const char *media_type,
+                                   int x_res,
+                                   int y_res,
+                                   char **icc_profile);
 
 extern int cfCmIsPrinterCmDisabled(cf_filter_data_t *data);
 
index 753d2fa9aca6c63f763004b3ee8ba7832af1ed97..c3e55fa656b3a22351ef65c99d39ecf83056b293 100644 (file)
@@ -26,7 +26,6 @@ extern "C" {
 #  include <time.h>
 #  include <math.h>
 #  include "filter.h"
-#  include <ppd/ppd.h>
 
 #  if defined(WIN32) || defined(__EMX__)
 #    include <io.h>
@@ -121,18 +120,6 @@ extern const unsigned char
  * Prototypes...
  */
 
-/*
- * Attribute function...
- */
-
-extern ppd_attr_t      *cfFindAttr(ppd_file_t *ppd, const char *name,
-                                   const char *colormodel,
-                                   const char *media,
-                                   const char *resolution,
-                                   char *spec, int specsize,
-                                   cf_logfunc_t log,
-                                   void *ld);
-                              
 /*
  * Byte checking functions...
  */
@@ -158,13 +145,6 @@ extern void                cfDitherDelete(cf_dither_t *);
 extern cf_lut_t                *cfLutNew(int num_vals, const float *vals,
                                  cf_logfunc_t log, void *ld);
 extern void            cfLutDelete(cf_lut_t *lut);
-extern cf_lut_t                *cfLutLoad(ppd_file_t *ppd,
-                                  const char *colormodel,
-                                  const char *media,
-                                  const char *resolution,
-                                  const char *ink,
-                                  cf_logfunc_t log,
-                                  void *ld);
 
 
 /*
@@ -194,12 +174,6 @@ extern void                cfRGBDoGray(cf_rgb_t *rgb,
 extern void            cfRGBDoRGB(cf_rgb_t *rgb,
                                   const unsigned char *input,
                                   unsigned char *output, int num_pixels);
-extern cf_rgb_t                *cfRGBLoad(ppd_file_t *ppd,
-                                  const char *colormodel,
-                                  const char *media,
-                                  const char *resolution,
-                                  cf_logfunc_t log,
-                                  void *ld);
 extern cf_rgb_t                *cfRGBNew(int num_samples, cf_sample_t *samples,
                                  int cube_size, int num_channels);
 
@@ -221,13 +195,7 @@ extern void                cfCMYKDoGray(const cf_cmyk_t *cmyk,
 extern void            cfCMYKDoRGB(const cf_cmyk_t *cmyk,
                                    const unsigned char *input,
                                    short *output, int num_pixels);
-extern cf_cmyk_t       *cfCMYKLoad(ppd_file_t *ppd,
-                                   const char *colormodel,
-                                   const char *media,
-                                   const char *resolution,
-                                   cf_logfunc_t log,
-                                   void *ld);
-  extern void          cfCMYKSetBlack(cf_cmyk_t *cmyk,
+extern void            cfCMYKSetBlack(cf_cmyk_t *cmyk,
                                       float lower, float upper,
                                       cf_logfunc_t log, void *ld);
 extern void            cfCMYKSetCurve(cf_cmyk_t *cmyk, int channel,
@@ -238,7 +206,7 @@ extern void         cfCMYKSetGamma(cf_cmyk_t *cmyk, int channel,
                                       float gamval, float density,
                                       cf_logfunc_t log, void *ld);
 extern void            cfCMYKSetInkLimit(cf_cmyk_t *cmyk, float limit);
-  extern void          cfCMYKSetLtDk(cf_cmyk_t *cmyk, int channel,
+extern void            cfCMYKSetLtDk(cf_cmyk_t *cmyk, int channel,
                                      float light, float dark,
                                      cf_logfunc_t log, void *ld);
 
index 0d9fc57cded4038d39c4328893a494008d324dc2..3b46db6c53511cedbece1d39d3a74f7dc1ec29c7 100644 (file)
@@ -20,7 +20,6 @@
 #include <sys/wait.h>
 #include <cups/file.h>
 #include <cups/array.h>
-#include <ppd/ppd.h>
 
 extern char **environ;
 
@@ -117,193 +116,110 @@ cfCUPSIsCanceledFunc(void *data)
 }
 
 
-/*
- * 'cfFilterCUPSWrapper()' - Wrapper function to use a filter function as
- *                         classic CUPS filter
- */
-
-int                                    /* O - Exit status */
-cfFilterCUPSWrapper(
-     int  argc,                                /* I - Number of command-line args */
-     char *argv[],                     /* I - Command-line arguments */
-     cf_filter_function_t filter,          /* I - Filter function */
-     void *parameters,                  /* I - Filter function parameters */
-     int *JobCanceled)                  /* I - Var set to 1 when job canceled */
+static cf_filter_data_ext_t *
+get_filter_data_ext_entry(cups_array_t *ext_array,
+                         const char *name)
 {
-  int          inputfd;                /* Print file descriptor*/
-  int           inputseekable;          /* Is the input seekable (actual file
-                                          not stdin)? */
-  int          num_options;            /* Number of print options */
-  cups_option_t        *options;               /* Print options */
-  cf_filter_data_t filter_data;
-  int           retval = 0;
+  cf_filter_data_ext_t *entry;
 
+  if (!ext_array || !name)
+    return (NULL);
 
- /*
-  * Make sure status messages are not buffered...
-  */
+  for (entry = (cf_filter_data_ext_t *)cupsArrayFirst(ext_array);
+       entry;
+       entry = (cf_filter_data_ext_t *)cupsArrayNext(ext_array))
+    if (strcmp(entry->name, name) == 0)
+      break;
 
-  setbuf(stderr, NULL);
+  return (entry);
+}
 
- /*
-  * Ignore broken pipe signals...
-  */
 
-  signal(SIGPIPE, SIG_IGN);
+void *                                     /* O - Extension record which got
+                                                 replaced, NULL if there was
+                                                 no record under this name,
+                                                 the added record is the one
+                                                 there, or no record was
+                                                 added. If not NULL the
+                                                 returned record should usually
+                                                 be deleted or freed. */
+cfFilterDataAddExt(cf_filter_data_t *data, /* I - Filter data record */
+                  const char *name,       /* I - Name of extension */
+                  void *ext)              /* I - Extension record to be added*/
+{
+  cf_filter_data_ext_t *entry;
+  void *old_ext = NULL;
 
- /*
-  * Check command-line...
-  */
+  if (!data || !name || !ext)
+    return (NULL);
 
-  if (argc < 6 || argc > 7)
-  {
-    fprintf(stderr, "Usage: %s job-id user title copies options [file]\n",
-           argv[0]);
-    return (1);
-  }
+  if (data->extension == NULL)
+    data->extension = cupsArrayNew(NULL, NULL);
 
- /*
-  * If we have 7 arguments, print the file named on the command-line.
-  * Otherwise, send stdin instead...
-  */
+  if (data->extension == NULL)
+    return (NULL);
 
-  if (argc == 6)
+  if ((entry = get_filter_data_ext_entry(data->extension, name)) != NULL)
   {
-    inputfd = 0; /* stdin */
-    inputseekable = 0;
+    old_ext = entry->ext;
+    entry->ext = ext;
   }
   else
   {
-   /*
-    * Try to open the print file...
-    */
-
-    if ((inputfd = open(argv[6], O_RDONLY)) < 0)
+    entry = (cf_filter_data_ext_t *)calloc(1, sizeof(cf_filter_data_ext_t));
+    if (entry)
     {
-      if (!JobCanceled)
-      {
-        fprintf(stderr, "DEBUG: Unable to open \"%s\": %s\n", argv[6],
-               strerror(errno));
-       fprintf(stderr, "ERROR: Unable to open print file");
-      }
-
-      return (1);
+      entry->name = strdup(name);
+      entry->ext = ext;
+      cupsArrayAdd(data->extension, entry);
     }
-
-    inputseekable = 1;
   }
 
- /*
-  * Process command-line options...
-  */
-
-  options     = NULL;
-  num_options = cupsParseOptions(argv[5], 0, &options);
-
- /*
-  * Create data record to call filter function and load PPD file
-  */
-
-  if ((filter_data.printer = getenv("PRINTER")) == NULL)
-    filter_data.printer = argv[0];
-  filter_data.job_id = atoi(argv[1]);
-  filter_data.job_user = argv[2];
-  filter_data.job_title = argv[3];
-  filter_data.copies = atoi(argv[4]);
-  filter_data.job_attrs = NULL;        /* We use command line options */
-  filter_data.printer_attrs = NULL;    /* We use the queue's PPD file */
-  filter_data.num_options = num_options;
-  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.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 */
-  filter_data.side_pipe[1] = 4;        /* the side channel */
-  filter_data.logfunc = cfCUPSLogFunc;  /* Logging scheme of CUPS */
-  filter_data.logdata = NULL;
-  filter_data.iscanceledfunc = cfCUPSIsCanceledFunc; /* Job-is-canceled
-                                                      function */
-  filter_data.iscanceleddata = JobCanceled;
-
- /*
-  * Load and prepare the PPD file
-  */
-
-  retval = cfFilterLoadPPD(&filter_data);
-
- /*
-  * Fire up the filter function (output to stdout, file descriptor 1)
-  */
+  return (old_ext);
+}
 
-  if (!retval)
-    retval = filter(inputfd, 1, inputseekable, &filter_data, parameters);
 
- /*
-  * Clean up
-  */
+void *
+cfFilterDataGetExt(cf_filter_data_t *data,
+                  const char *name)
+{
+  cf_filter_data_ext_t *entry;
 
-  cupsFreeOptions(num_options, options);
-  cfFilterFreePPD(&filter_data);
+  if (!data || !name || data->extension == NULL)
+    return (NULL);
 
-  return retval;
+  if ((entry = get_filter_data_ext_entry(data->extension, name)) != NULL)
+    return (entry->ext);
+  else
+    return NULL;
 }
 
 
-/*
- * '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 */
+void *
+cfFilterDataRemoveExt(cf_filter_data_t *data,
+                     const char *name)
 {
-  cf_logfunc_t     log = data->logfunc;   /* Log function */
-  void             *ld = data->logdata;   /* log function data */
+  cf_filter_data_ext_t *entry;
+  void *ext = NULL;
 
-  if (data->ppdfile == NULL)
-  {
-    data->ppd = NULL;
-    return (0);
-  }
+  if (!data || !name || data->extension == NULL)
+    return (NULL);
 
-  if ((data->ppd = ppdOpenFile(data->ppdfile)) == NULL)
+  if ((entry = get_filter_data_ext_entry(data->extension, name)) != NULL)
   {
-    if (log) log(ld, CF_LOGLEVEL_ERROR,
-                "cfFilterLoadPPD: Could not load PPD file %s: %s",
-                data->ppdfile, strerror(errno));
-    return (1);
+    ext = entry->ext;
+    cupsArrayRemove(data->extension, entry);
+    free(entry->name);
+    free(entry);
+    if (cupsArrayCount(data->extension) == 0)
+    {
+      cupsArrayDelete(data->extension);
+      data->extension = NULL;
+    }
+    return (ext);
   }
-
-  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);
+  else
+    return NULL;
 }
 
 
@@ -831,668 +747,6 @@ cfFilterChain(int inputfd,         /* I - File descriptor input stream */
 }
 
 
-/*
- * 'get_env_var()' - Auxiliary function for cfFilterExternalCUPS(), gets value of
- *                   an environment variable in a list of environment variables
- *                   as used by the execve() function
- */
-
-static char *             /* O - The value, NULL if variable is not in list */
-get_env_var(char *name,   /* I - Name of environment variable to read */
-           char **env)   /* I - List of environment variable serttings */
-{
-  int i = 0;
-
-
-  if (env)
-    for (i = 0; env[i]; i ++)
-      if (strncmp(env[i], name, strlen(name)) == 0 &&
-         strlen(env[i]) > strlen(name) &&
-         env[i][strlen(name)] == '=')
-       return (env[i] + strlen(name) + 1);
-
-  return (NULL);
-}
-
-
-/*
- * 'add_env_var()' - Auxiliary function for cfFilterExternalCUPS(), adds/sets
- *                   an environment variable in a list of environment variables
- *                   as used by the execve() function
- */
-
-static int                /* O - Index of where the new value got inserted in
-                                the list */
-add_env_var(char *name,   /* I - Name of environment variable to set */
-           char *value,  /* I - Value of environment variable to set */
-           char ***env)  /* I - List of environment variable serttings */
-{
-  char *p;
-  int i = 0,
-      name_len;
-
-
-  if (!name || !env || !name[0])
-    return (-1);
-
-  /* Assemble a "VAR=VALUE" string and the string length of "VAR" */
-  if ((p = strchr(name, '=')) != NULL)
-  {
-    /* User supplied "VAR=VALUE" as name and NULL as value */
-    if (value)
-      return (-1);
-    name_len = p - name;
-    p = strdup(name);
-  }
-  else
-  {
-    /* User supplied variable name and value as the name and as the value */
-    name_len = strlen(name);
-    p = (char *)calloc(strlen(name) + (value ? strlen(value) : 0) + 2,
-                      sizeof(char));
-    sprintf(p, "%s=%s", name, (value ? value : ""));
-  }
-
-  /* Check whether we already have this variable in the list and update its
-     value if it is there */
-  if (*env)
-    for (i = 0; (*env)[i]; i ++)
-      if (strncmp((*env)[i], p, name_len) == 0 && (*env)[i][name_len] == '=')
-      {
-       free((*env)[i]);
-       (*env)[i] = p;
-       return (i);
-      }
-
-  /* Add the variable as new item to the list */
-  *env = (char **)realloc(*env, (i + 2) * sizeof(char *));
-  (*env)[i] = p;
-  (*env)[i + 1] = NULL;
-  return (i);
-}
-
-
-/*
- * 'sanitize_device_uri()' - Remove authentication info from a device URI
- */
-
-static char *                           /* O - Sanitized URI */
-sanitize_device_uri(const char *uri,   /* I - Device URI */
-                   char *buf,          /* I - Buffer for output */
-                   size_t bufsize)     /* I - Size of buffer */
-{
-  char *start,                         /* Start of data after scheme */
-       *slash,                         /* First slash after scheme:// */
-       *ptr;                           /* Pointer into user@host:port part */
-
-
-  /* URI not supplied */
-  if (!uri)
-    return (NULL);
-
-  /* Copy the device URI to a temporary buffer so we can sanitize any auth
-   * info in it... */
-  strncpy(buf, uri, bufsize);
-
-  /* Find the end of the scheme:// part... */
-  if ((ptr = strchr(buf, ':')) != NULL)
-  {
-    for (start = ptr + 1; *start; start ++)
-      if (*start != '/')
-        break;
-
-    /* Find the next slash (/) in the URI... */
-    if ((slash = strchr(start, '/')) == NULL)
-      slash = start + strlen(start);   /* No slash, point to the end */
-
-    /* Check for an @ sign before the slash... */
-    if ((ptr = strchr(start, '@')) != NULL && ptr < slash)
-    {
-      /* Found an @ sign and it is before the resource part, so we have
-        an authentication string.  Copy the remaining URI over the
-        authentication string... */
-      memmove(start, ptr + 1, strlen(ptr + 1) + 1);
-    }
-  }
-
-  /* Return the sanitized URI... */
-  return (buf);
-}
-
-
-/*
- * 'cfFilterExternalCUPS()' - Filter function which calls an external,
- *                          classic CUPS filter, for example a
- *                          (proprietary) printer driver which cannot
- *                          be converted to a filter function or is to
- *                          awkward or risky to convert for example
- *                          when the printer hardware is not available
- *                          for testing
- */
-
-int                                     /* O - Error status */
-cfFilterExternalCUPS(int inputfd,         /* I - File descriptor input stream */
-                  int outputfd,        /* I - File descriptor output stream */
-                  int inputseekable,   /* I - Is input stream seekable? */
-                  cf_filter_data_t *data, /* I - Job and printer data */
-                  void *parameters)    /* I - Filter-specific parameters */
-{
-  cf_filter_external_cups_t *params = (cf_filter_external_cups_t *)parameters;
-  int           i;
-  int           is_backend = 0;      /* Do we call a CUPS backend? */
-  int          pid,                 /* Process ID of filter */
-                stderrpid,           /* Process ID for stderr logging process */
-                wpid;                /* PID reported as terminated */
-  int          fd;                  /* Temporary file descriptor */
-  int           backfd, sidefd;      /* file descriptors for back and side
-                                        channels */
-  int           stderrpipe[2];       /* Pipe to log stderr */
-  cups_file_t   *fp;                 /* File pointer to read log lines */
-  char          buf[2048];           /* Log line buffer */
-  cf_loglevel_t log_level;       /* Log level of filter's log message */
-  char          *ptr1, *ptr2,
-                *msg,                /* Filter log message */
-                *filter_name;        /* Filter name for logging */
-  char          filter_path[1024];   /* Full path of the filter */
-  char          **argv,                     /* Command line args for filter */
-                **envp = NULL;       /* Environment variables for filter */
-  int           num_all_options = 0;
-  cups_option_t *all_options = NULL;
-  char          job_id_str[16],
-                copies_str[16],
-                *options_str = NULL;
-  cups_option_t *opt;
-  int status = 65536;
-  int wstatus;
-  cf_logfunc_t log = data->logfunc;
-  void          *ld = data->logdata;
-  cf_filter_iscanceledfunc_t iscanceled = data->iscanceledfunc;
-  void          *icd = data->iscanceleddata;
-
-
-  if (!params->filter || !params->filter[0]) {
-    if (log) log(ld, CF_LOGLEVEL_ERROR,
-                "cfFilterExternalCUPS: Filter executable path/command not specified");
-    return (1);
-  }
-
-  /* Check whether back/side channel FDs are valid and not all-zero
-     from calloc'ed filter_data */
-  if (data->back_pipe[0] == 0 && data->back_pipe[1] == 0)
-    data->back_pipe[0] = data->back_pipe[1] = -1;
-  if (data->side_pipe[0] == 0 && data->side_pipe[1] == 0)
-    data->side_pipe[0] = data->side_pipe[1] = -1;
-
-  /* Select the correct end of the back/side channel pipes:
-     [0] for filters, [1] for backends */
-  is_backend = (params->is_backend ? 1 : 0);
-  backfd = data->back_pipe[is_backend];
-  sidefd = data->side_pipe[is_backend];
-
-  /* Filter name for logging */
-  if ((filter_name = strrchr(params->filter, '/')) != NULL)
-    filter_name ++;
-  else
-    filter_name = (char *)params->filter;
-
- /*
-  * Ignore broken pipe signals...
-  */
-
-  signal(SIGPIPE, SIG_IGN);
-
- /*
-  * Copy the current environment variables and add some important ones
-  * needed for correct execution of the CUPS filter (which is not running
-  * out of CUPS here)
-  */
-
-  /* Some default environment variables from CUPS, will get overwritten
-     if also defined in the environment in which the caller is started
-     or in the parameters */
-  add_env_var("CUPS_DATADIR", CUPS_DATADIR, &envp);
-  add_env_var("CUPS_SERVERBIN", CUPS_SERVERBIN, &envp);
-  add_env_var("CUPS_SERVERROOT", CUPS_SERVERROOT, &envp);
-  add_env_var("CUPS_STATEDIR", CUPS_STATEDIR, &envp);
-  add_env_var("SOFTWARE", "CUPS/2.5.99", &envp); /* Last CUPS with PPDs */
-
-  /* Copy the environment in which the caller got started */
-  if (environ)
-    for (i = 0; environ[i]; i ++)
-      add_env_var(environ[i], NULL, &envp);
-
-  /* Set the environment variables given by the parameters */
-  if (params->envp)
-    for (i = 0; params->envp[i]; i ++)
-      add_env_var(params->envp[i], NULL, &envp);
-
-  /* Add CUPS_SERVERBIN to the beginning of PATH */
-  ptr1 = get_env_var("PATH", envp);
-  ptr2 = get_env_var("CUPS_SERVERBIN", envp);
-  if (ptr2 && ptr2[0])
-  {
-    if (ptr1 && ptr1[0])
-    {
-      snprintf(buf, sizeof(buf), "%s/%s:%s",
-              ptr2, params->is_backend ? "backend" : "filter", ptr1);
-      ptr1 = buf;
-    }
-    else
-      ptr1 = ptr2;
-    add_env_var("PATH", ptr1, &envp);
-  }
-
-  if (params->is_backend < 2) /* Not needed in discovery mode of backend */
-  {
-    /* Print queue name from filter data */
-    if (data->printer)
-      add_env_var("PRINTER", data->printer, &envp);
-    else
-      add_env_var("PRINTER", "Unknown", &envp);
-
-    /* PPD file path/name from filter data, required for most CUPS filters */
-    if (data->ppdfile)
-      add_env_var("PPD", data->ppdfile, &envp);
-
-    /* Device URI from parameters */
-    if (params->is_backend && params->device_uri)
-      add_env_var("DEVICE_URI", (char *)params->device_uri, &envp);
-  }
-
-  /* Determine full path for the filter */
-  if (params->filter[0] == '/' ||
-      (ptr1 = get_env_var("CUPS_SERVERBIN", envp)) == NULL || !ptr1[0])
-    strncpy(filter_path, params->filter, sizeof(filter_path) - 1);
-  else
-    snprintf(filter_path, sizeof(filter_path), "%s/%s/%s", ptr1,
-            params->is_backend ? "backend" : "filter", params->filter);
-
-  /* Log the resulting list of environment variable settings
-     (with any authentication info removed)*/
-  if (log)
-  {
-    for (i = 0; envp[i]; i ++)
-      if (!strncmp(envp[i], "AUTH_", 5))
-       log(ld, CF_LOGLEVEL_DEBUG, "cfFilterExternalCUPS (%s): envp[%d]: AUTH_%c****",
-           filter_name, i, envp[i][5]);
-      else if (!strncmp(envp[i], "DEVICE_URI=", 11))
-       log(ld, CF_LOGLEVEL_DEBUG, "cfFilterExternalCUPS (%s): envp[%d]: DEVICE_URI=%s",
-           filter_name, i, sanitize_device_uri(envp[i] + 11,
-                                               buf, sizeof(buf)));
-      else
-       log(ld, CF_LOGLEVEL_DEBUG, "cfFilterExternalCUPS (%s): envp[%d]: %s",
-           filter_name, i, envp[i]);
-  }
-
-  if (params->is_backend < 2) {
-   /*
-    * Filter or backend for job execution
-    */
-
-   /*
-    * Join the options from the filter data and from the parameters
-    * If an option is present in both filter data and parameters, the
-    * value in the filter data has priority
-    */
-
-    for (i = 0, opt = params->options; i < params->num_options; i ++, opt ++)
-      num_all_options = cupsAddOption(opt->name, opt->value, num_all_options,
-                                     &all_options);
-    for (i = 0, opt = data->options; i < data->num_options; i ++, opt ++)
-      num_all_options = cupsAddOption(opt->name, opt->value, num_all_options,
-                                     &all_options);
-
-   /*
-    * Create command line arguments for the CUPS filter
-    */
-
-    argv = (char **)calloc(7, sizeof(char *));
-
-    /* Numeric parameters */
-    snprintf(job_id_str, sizeof(job_id_str) - 1, "%d",
-            data->job_id > 0 ? data->job_id : 1);
-    snprintf(copies_str, sizeof(copies_str) - 1, "%d",
-            data->copies > 0 ? data->copies : 1);
-
-    /* Options, build string of "Name1=Value1 Name2=Value2 ..." but use
-       "Name" and "noName" instead for boolean options */
-    for (i = 0, opt = all_options; i < num_all_options; i ++, opt ++) {
-      if (strcasecmp(opt->value, "true") == 0 ||
-         strcasecmp(opt->value, "false") == 0) {
-       options_str =
-         (char *)realloc(options_str,
-                         ((options_str ? strlen(options_str) : 0) +
-                          strlen(opt->name) +
-                          (strcasecmp(opt->value, "false") == 0 ? 2 : 0) + 2) *
-                         sizeof(char));
-       if (i == 0)
-         options_str[0] = '\0';
-       sprintf(options_str + strlen(options_str), " %s%s",
-               (strcasecmp(opt->value, "false") == 0 ? "no" : ""), opt->name);
-      } else {
-       options_str =
-         (char *)realloc(options_str,
-                         ((options_str ? strlen(options_str) : 0) +
-                          strlen(opt->name) + strlen(opt->value) + 3) *
-                         sizeof(char));
-       if (i == 0)
-         options_str[0] = '\0';
-       sprintf(options_str + strlen(options_str), " %s=%s", opt->name, opt->value);
-      }
-    }
-
-    /* Find DEVICE_URI environment variable */
-    if (params->is_backend && !params->device_uri)
-      for (i = 0; envp[i]; i ++)
-       if (strncmp(envp[i], "DEVICE_URI=", 11) == 0)
-         break;
-
-    /* Add items to array */
-    argv[0] = strdup((params->is_backend && params->device_uri ?
-                     (char *)sanitize_device_uri(params->device_uri,
-                                                 buf, sizeof(buf)) :
-                     (params->is_backend && envp[i] ?
-                      (char *)sanitize_device_uri(envp[i] + 11,
-                                                  buf, sizeof(buf)) :
-                      (data->printer ? data->printer :
-                       (char *)params->filter))));
-    argv[1] = job_id_str;
-    argv[2] = data->job_user ? data->job_user : "Unknown";
-    argv[3] = data->job_title ? data->job_title : "Untitled";
-    argv[4] = copies_str;
-    argv[5] = options_str ? options_str + 1 : "";
-    argv[6] = NULL;
-
-    /* Log the arguments */
-    if (log)
-      for (i = 0; argv[i]; i ++)
-       log(ld, CF_LOGLEVEL_DEBUG, "cfFilterExternalCUPS (%s): argv[%d]: %s",
-           filter_name, i, argv[i]);
-  } else {
-   /*
-    * Backend in device discovery mode
-    */
-
-    argv = (char **)calloc(2, sizeof(char *));
-    argv[0] = strdup((char *)params->filter);
-    argv[1] = NULL;
-  }
-
- /*
-  * Execute the filter
-  */
-
-  if (pipe(stderrpipe) < 0) {
-    if (log) log(ld, CF_LOGLEVEL_ERROR,
-                "cfFilterExternalCUPS (%s): Could not create pipe for stderr: %s",
-                filter_name, strerror(errno));
-    return (1);
-  }
-
-  if ((pid = fork()) == 0) {
-   /*
-    * Child process goes here...
-    *
-    * Update stdin/stdout/stderr as needed...
-    */
-
-    if (inputfd != 0) {
-      if (inputfd < 0) {
-        inputfd = open("/dev/null", O_RDONLY);
-       if (log) log(ld, CF_LOGLEVEL_ERROR,
-                    "cfFilterExternalCUPS (%s): No input file descriptor supplied for CUPS filter - %s",
-                  filter_name, strerror(errno));
-      }
-
-      if (inputfd > 0) {
-       fcntl_add_cloexec(inputfd);
-        if (dup2(inputfd, 0) < 0) {
-         if (log) log(ld, CF_LOGLEVEL_ERROR,
-                      "cfFilterExternalCUPS (%s): Failed to connect input file descriptor with CUPS filter's stdin - %s",
-                      filter_name, strerror(errno));
-         goto fd_error;
-       } else
-         if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                      "cfFilterExternalCUPS (%s): Connected input file descriptor %d to CUPS filter's stdin.",
-                      filter_name, inputfd);
-       close(inputfd);
-      }
-    } else
-      if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterExternalCUPS (%s): Input comes from stdin, letting the filter grab stdin directly",
-                  filter_name);
-
-    if (outputfd != 1) {
-      if (outputfd < 0)
-        outputfd = open("/dev/null", O_WRONLY);
-
-      if (outputfd > 1) {
-       fcntl_add_cloexec(outputfd);
-       dup2(outputfd, 1);
-       close(outputfd);
-      }
-    }
-
-    if (strcasestr(params->filter, "gziptoany")) {
-      /* Send stderr to the Nirwana if we are running gziptoany, as
-        gziptoany emits a false "PAGE: 1 1" */
-      if ((fd = open("/dev/null", O_RDWR)) > 2) {
-       fcntl_add_cloexec(fd);
-       dup2(fd, 2);
-       close(fd);
-      } else
-        close(fd);
-    } else {
-      /* Send stderr into pipe for logging */
-      fcntl_add_cloexec(stderrpipe[1]);
-      dup2(stderrpipe[1], 2);
-      fcntl_add_nonblock(2);
-    }
-    close(stderrpipe[0]);
-    close(stderrpipe[1]);
-
-    if (params->is_backend < 2) { /* Not needed in discovery mode of backend */
-      /* Back channel */
-      if (backfd != 3 && backfd >= 0) {
-       dup2(backfd, 3);
-       close(backfd);
-       fcntl_add_nonblock(3);
-      } else if (backfd < 0) {
-       if ((backfd = open("/dev/null", O_RDWR)) > 3) {
-         dup2(backfd, 3);
-         close(backfd);
-       } else
-         close(backfd);
-       fcntl_add_nonblock(3);
-      }
-
-      /* Side channel */
-      if (sidefd != 4 && sidefd >= 0) {
-       dup2(sidefd, 4);
-       close(sidefd);
-       fcntl_add_nonblock(4);
-      } else if (sidefd < 0) {
-       if ((sidefd = open("/dev/null", O_RDWR)) > 4) {
-         dup2(sidefd, 4);
-         close(sidefd);
-       } else
-         close(sidefd);
-       fcntl_add_nonblock(4);
-      }
-    }
-
-   /*
-    * Execute command...
-    */
-
-    execve(filter_path, argv, envp);
-
-    if (log) log(ld, CF_LOGLEVEL_ERROR,
-                "cfFilterExternalCUPS (%s): Execution of %s %s failed - %s",
-                filter_name, params->is_backend ? "backend" : "filter",
-                filter_path, strerror(errno));
-
-  fd_error:
-    exit(errno);
-  } else if (pid > 0) {
-    if (log) log(ld, CF_LOGLEVEL_INFO,
-                "cfFilterExternalCUPS (%s): %s (PID %d) started.",
-                filter_name, filter_path, pid);
-  } else {
-    if (log) log(ld, CF_LOGLEVEL_ERROR,
-                "cfFilterExternalCUPS (%s): Unable to fork process for %s %s",
-                filter_name, params->is_backend ? "backend" : "filter",
-                filter_path);
-    close(stderrpipe[0]);
-    close(stderrpipe[1]);
-    status = 1;
-    goto out;
-  }
-  if (inputfd >= 0)
-    close(inputfd);
-  if (outputfd >= 0)
-    close(outputfd);
-
- /*
-  * Log the filter's stderr
-  */
-
-  if ((stderrpid = fork()) == 0) {
-   /*
-    * Child process goes here...
-    */
-
-    close(stderrpipe[1]);
-    fp = cupsFileOpenFd(stderrpipe[0], "r");
-    while (cupsFileGets(fp, buf, sizeof(buf)))
-      if (log) {
-       if (strncmp(buf, "DEBUG: ", 7) == 0) {
-         log_level = CF_LOGLEVEL_DEBUG;
-         msg = buf + 7;
-       } else if (strncmp(buf, "DEBUG2: ", 8) == 0) {
-         log_level = CF_LOGLEVEL_DEBUG;
-         msg = buf + 8;
-       } else if (strncmp(buf, "INFO: ", 6) == 0) {
-         log_level = CF_LOGLEVEL_INFO;
-         msg = buf + 6;
-       } else if (strncmp(buf, "WARNING: ", 9) == 0) {
-         log_level = CF_LOGLEVEL_WARN;
-         msg = buf + 9;
-       } else if (strncmp(buf, "ERROR: ", 7) == 0) {
-         log_level = CF_LOGLEVEL_ERROR;
-         msg = buf + 7;
-       } else if (strncmp(buf, "PAGE: ", 6) == 0 ||
-                  strncmp(buf, "ATTR: ", 6) == 0 ||
-                  strncmp(buf, "STATE: ", 7) == 0 ||
-                  strncmp(buf, "PPD: ", 5) == 0) {
-         log_level = CF_LOGLEVEL_CONTROL;
-         msg = buf;
-       } else {
-         log_level = CF_LOGLEVEL_DEBUG;
-         msg = buf;
-       }
-       if (log_level == CF_LOGLEVEL_CONTROL)
-         log(ld, log_level, msg);
-       else
-         log(ld, log_level, "cfFilterExternalCUPS (%s): %s", filter_name, msg);
-      }
-    cupsFileClose(fp);
-    /* No need to close the fd stderrpipe[0], as cupsFileClose(fp) does this
-       already */
-    /* Ignore errors of the logging process */
-    exit(0);
-  } else if (stderrpid > 0) {
-    if (log) log(ld, CF_LOGLEVEL_INFO,
-                "cfFilterExternalCUPS (%s): Logging (PID %d) started.",
-                filter_name, stderrpid);
-  } else {
-    if (log) log(ld, CF_LOGLEVEL_ERROR,
-                "cfFilterExternalCUPS (%s): Unable to fork process for logging",
-                filter_name);
-    close(stderrpipe[0]);
-    close(stderrpipe[1]);
-    status = 1;
-    goto out;
-  }
-
-  close(stderrpipe[0]);
-  close(stderrpipe[1]);
-
- /*
-  * Wait for filter and logging processes to finish
-  */
-
-  status = 0;
-
-  while (pid > 0 || stderrpid > 0) {
-    if ((wpid = wait(&wstatus)) < 0) {
-      if (errno == EINTR && iscanceled && iscanceled(icd)) {
-       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                    "cfFilterExternalCUPS (%s): Job canceled, killing %s ...",
-                    filter_name, params->is_backend ? "backend" : "filter");
-       kill(pid, SIGTERM);
-       pid = -1;
-       kill(stderrpid, SIGTERM);
-       stderrpid = -1;
-       break;
-      } else
-       continue;
-    }
-
-    /* How did the filter terminate */
-    if (wstatus) {
-      if (WIFEXITED(wstatus)) {
-       /* Via exit() anywhere or return() in the main() function */
-       if (log) log(ld, CF_LOGLEVEL_ERROR,
-                    "cfFilterExternalCUPS (%s): %s (PID %d) stopped with status %d",
-                    filter_name,
-                    (wpid == pid ?
-                     (params->is_backend ? "Backend" : "Filter") :
-                     "Logging"),
-                    wpid, WEXITSTATUS(wstatus));
-      } else {
-       /* Via signal */
-       if (log) log(ld, CF_LOGLEVEL_ERROR,
-                    "cfFilterExternalCUPS (%s): %s (PID %d) crashed on signal %d",
-                    filter_name,
-                    (wpid == pid ?
-                     (params->is_backend ? "Backend" : "Filter") :
-                     "Logging"),
-                    wpid, WTERMSIG(wstatus));
-      }
-      status = 1;
-    } else {
-      if (log) log(ld, CF_LOGLEVEL_INFO,
-                  "cfFilterExternalCUPS (%s): %s (PID %d) exited with no errors.",
-                  filter_name,
-                  (wpid == pid ?
-                   (params->is_backend ? "Backend" : "Filter") : "Logging"),
-                  wpid);
-    }
-    if (wpid == pid)
-      pid = -1;
-    else  if (wpid == stderrpid)
-      stderrpid = -1;
-  }
-
- /*
-  * Clean up
-  */
-
- out:
-  cupsFreeOptions(num_all_options, all_options);
-  if (options_str)
-    free(options_str);
-  free(argv[0]);
-  free(argv);
-  for (i = 0; envp[i]; i ++)
-    free(envp[i]);
-  free(envp);
-
-  return (status);
-}
-
-
 /*
  * 'cfFilterOpenBackAndSidePipes()' - Open the pipes for the back
  *                                  channel and the side channel, so
@@ -1626,378 +880,3 @@ cfFilterCloseBackAndSidePipes(
   if (log) log(ld, CF_LOGLEVEL_DEBUG,
               "Closed the pipes for back and side channels");
 }
-
-
-/*
- * 'cfFilterSetCommonOptions()' - Set common filter options for media size, etc.
- *                              based on PPD file
- */
-
-void
-cfFilterSetCommonOptions(
-    ppd_file_t    *ppd,                        /* I - PPD file */
-    int           num_options,          /* I - Number of options */
-    cups_option_t *options,             /* I - Options */
-    int           change_size,         /* I - Change page size? */
-    int           *Orientation,         /* I/O - Basic page parameters */
-    int           *Duplex,
-    int           *LanguageLevel,
-    int           *ColorDevice,
-    float         *PageLeft,
-    float         *PageRight,
-    float         *PageTop,
-    float         *PageBottom,
-    float         *PageWidth,
-    float         *PageLength,
-    cf_logfunc_t log,               /* I - Logging function,
-                                              NULL for no logging */
-    void *ld)                           /* I - User data for logging function,
-                                              can be NULL */
-{
-  ppd_size_t   *pagesize;              /* Current page size */
-  const char   *val;                   /* Option value */
-
-
-  *Orientation = 0;            /* 0 = portrait, 1 = landscape, etc. */
-  *Duplex = 0;                 /* Duplexed? */
-  *LanguageLevel = 1;          /* Language level of printer */
-  *ColorDevice = 1;            /* Color printer? */
-  *PageLeft = 18.0f;           /* Left margin */
-  *PageRight = 594.0f;         /* Right margin */
-  *PageBottom = 36.0f;         /* Bottom margin */
-  *PageTop = 756.0f;           /* Top margin */
-  *PageWidth = 612.0f;         /* Total page width */
-  *PageLength = 792.0f;                /* Total page length */
-
-  if ((pagesize = ppdPageSize(ppd, NULL)) != NULL)
-  {
-    int corrected = 0;
-    if (pagesize->width > 0) 
-      *PageWidth = pagesize->width;
-    else
-    {
-      if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "Invalid value for page width: %.0f",
-                  pagesize->width);
-      corrected = 1;
-    }
-    if (pagesize->length > 0) 
-      *PageLength = pagesize->length;
-    else
-    {
-      if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "Invalid value for page length: %.0f",
-                  pagesize->length);
-      corrected = 1;
-    }
-    if (pagesize->top >= 0 && pagesize->top <= *PageLength) 
-      *PageTop = pagesize->top;
-    else
-    {
-      if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "Invalid value for page top margin: %.0f",
-                  pagesize->top);
-      if (*PageLength >= *PageBottom)
-       *PageTop = *PageLength - *PageBottom;
-      else
-       *PageTop = *PageLength;
-      corrected = 1;
-    }
-    if (pagesize->bottom >= 0 && pagesize->bottom <= *PageLength) 
-      *PageBottom = pagesize->bottom;
-    else
-    {
-      if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "Invalid value for page bottom margin: %.0f",
-                  pagesize->bottom);
-      if (*PageLength <= *PageBottom)
-       *PageBottom = 0.0f;
-      corrected = 1;
-    }
-    if (*PageBottom == *PageTop)
-    {
-      if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "Invalid values for page margins: Bottom: %.0f; Top: %.0f",
-                  *PageBottom, *PageTop);
-      *PageTop = *PageLength - *PageBottom;
-      if (*PageBottom == *PageTop)
-      {
-       *PageBottom = 0.0f;
-       *PageTop = *PageLength;
-      }
-      corrected = 1;
-    }
-    if (*PageBottom > *PageTop)
-    {
-      if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "Invalid values for page margins: Bottom: %.0f; Top: %.0f",
-                  *PageBottom, *PageTop);
-      float swap = *PageBottom;
-      *PageBottom = *PageTop;
-      *PageTop = swap;
-      corrected = 1;
-    }
-
-    if (pagesize->left >= 0 && pagesize->left <= *PageWidth) 
-      *PageLeft = pagesize->left;
-    else
-    {
-      if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "Invalid value for page left margin: %.0f",
-                  pagesize->left);
-      if (*PageWidth <= *PageLeft)
-       *PageLeft = 0.0f;
-      corrected = 1;
-    }
-    if (pagesize->right >= 0 && pagesize->right <= *PageWidth) 
-      *PageRight = pagesize->right;
-    else
-    {
-      if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "Invalid value for page right margin: %.0f",
-                  pagesize->right);
-      if (*PageWidth >= *PageLeft)
-       *PageRight = *PageWidth - *PageLeft;
-      else
-       *PageRight = *PageWidth;
-      corrected = 1;
-    }
-    if (*PageLeft == *PageRight)
-    {
-      if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "Invalid values for page margins: Left: %.0f; Right: %.0f",
-                  *PageLeft, *PageRight);
-      *PageRight = *PageWidth - *PageLeft;
-      if (*PageLeft == *PageRight)
-      {
-       *PageLeft = 0.0f;
-       *PageRight = *PageWidth;
-      }
-      corrected = 1;
-    }
-    if (*PageLeft > *PageRight)
-    {
-      if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "Invalid values for page margins: Left: %.0f; Right: %.0f",
-                  *PageLeft, *PageRight);
-      float swap = *PageLeft;
-      *PageLeft = *PageRight;
-      *PageRight = swap;
-      corrected = 1;
-    }
-
-    if (corrected)
-    {
-      if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "PPD Page = %.0fx%.0f; %.0f,%.0f to %.0f,%.0f",
-                  pagesize->width, pagesize->length, pagesize->left,
-                  pagesize->bottom, pagesize->right, pagesize->top);
-      if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "Corrected Page = %.0fx%.0f; %.0f,%.0f to %.0f,%.0f",
-                  *PageWidth, *PageLength, *PageLeft,
-                  *PageBottom, *PageRight, *PageTop);
-    }
-    else
-      if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "Page = %.0fx%.0f; %.0f,%.0f to %.0f,%.0f",
-                  pagesize->width, pagesize->length, pagesize->left,
-                  pagesize->bottom, pagesize->right, pagesize->top);
-  }
-
-  if (ppd != NULL)
-  {
-    *ColorDevice   = ppd->color_device;
-    *LanguageLevel = ppd->language_level;
-  }
-
-  if ((val = cupsGetOption("landscape", num_options, options)) != NULL)
-  {
-    if (strcasecmp(val, "no") != 0 && strcasecmp(val, "off") != 0 &&
-        strcasecmp(val, "false") != 0)
-    {
-      if (ppd && ppd->landscape > 0)
-        *Orientation = 1;
-      else
-        *Orientation = 3;
-    }
-  }
-  else if ((val = cupsGetOption("orientation-requested",
-                               num_options, options)) != NULL)
-  {
-   /*
-    * Map IPP orientation values to 0 to 3:
-    *
-    *   3 = 0 degrees   = 0
-    *   4 = 90 degrees  = 1
-    *   5 = -90 degrees = 3
-    *   6 = 180 degrees = 2
-    */
-
-    *Orientation = atoi(val) - 3;
-    if (*Orientation >= 2)
-      *Orientation ^= 1;
-  }
-
-  if ((val = cupsGetOption("page-left", num_options, options)) != NULL)
-  {
-    switch (*Orientation & 3)
-    {
-      case 0 :
-          *PageLeft = (float)atof(val);
-         break;
-      case 1 :
-          *PageBottom = (float)atof(val);
-         break;
-      case 2 :
-          *PageRight = *PageWidth - (float)atof(val);
-         break;
-      case 3 :
-          *PageTop = *PageLength - (float)atof(val);
-         break;
-    }
-  }
-
-  if ((val = cupsGetOption("page-right", num_options, options)) != NULL)
-  {
-    switch (*Orientation & 3)
-    {
-      case 0 :
-          *PageRight = *PageWidth - (float)atof(val);
-         break;
-      case 1 :
-          *PageTop = *PageLength - (float)atof(val);
-         break;
-      case 2 :
-          *PageLeft = (float)atof(val);
-         break;
-      case 3 :
-          *PageBottom = (float)atof(val);
-         break;
-    }
-  }
-
-  if ((val = cupsGetOption("page-bottom", num_options, options)) != NULL)
-  {
-    switch (*Orientation & 3)
-    {
-      case 0 :
-          *PageBottom = (float)atof(val);
-         break;
-      case 1 :
-          *PageLeft = (float)atof(val);
-         break;
-      case 2 :
-          *PageTop = *PageLength - (float)atof(val);
-         break;
-      case 3 :
-          *PageRight = *PageWidth - (float)atof(val);
-         break;
-    }
-  }
-
-  if ((val = cupsGetOption("page-top", num_options, options)) != NULL)
-  {
-    switch (*Orientation & 3)
-    {
-      case 0 :
-          *PageTop = *PageLength - (float)atof(val);
-         break;
-      case 1 :
-          *PageRight = *PageWidth - (float)atof(val);
-         break;
-      case 2 :
-          *PageBottom = (float)atof(val);
-         break;
-      case 3 :
-          *PageLeft = (float)atof(val);
-         break;
-    }
-  }
-
-  if (change_size)
-    cfFilterUpdatePageVars(*Orientation, PageLeft, PageRight,
-                        PageTop, PageBottom, PageWidth, PageLength);
-
-  if (ppdIsMarked(ppd, "Duplex", "DuplexNoTumble") ||
-      ppdIsMarked(ppd, "Duplex", "DuplexTumble") ||
-      ppdIsMarked(ppd, "JCLDuplex", "DuplexNoTumble") ||
-      ppdIsMarked(ppd, "JCLDuplex", "DuplexTumble") ||
-      ppdIsMarked(ppd, "EFDuplex", "DuplexNoTumble") ||
-      ppdIsMarked(ppd, "EFDuplex", "DuplexTumble") ||
-      ppdIsMarked(ppd, "EFDuplexing", "DuplexNoTumble") ||
-      ppdIsMarked(ppd, "EFDuplexing", "DuplexTumble") ||
-      ppdIsMarked(ppd, "ARDuplex", "DuplexNoTumble") ||
-      ppdIsMarked(ppd, "ARDuplex", "DuplexTumble") ||
-      ppdIsMarked(ppd, "KD03Duplex", "DuplexNoTumble") ||
-      ppdIsMarked(ppd, "KD03Duplex", "DuplexTumble"))
-    *Duplex = 1;
-
-  return;
-}
-
-
-/*
- * 'cfFilterUpdatePageVars()' - Update the page variables for the orientation.
- */
-
-void
-cfFilterUpdatePageVars(int Orientation,
-                    float *PageLeft, float *PageRight,
-                    float *PageTop, float *PageBottom,
-                    float *PageWidth, float *PageLength)
-{
-  float                temp;                   /* Swapping variable */
-
-
-  switch (Orientation & 3)
-  {
-    case 0 : /* Portait */
-        break;
-
-    case 1 : /* Landscape */
-       temp        = *PageLeft;
-       *PageLeft   = *PageBottom;
-       *PageBottom = temp;
-
-       temp        = *PageRight;
-       *PageRight  = *PageTop;
-       *PageTop    = temp;
-
-       temp        = *PageWidth;
-       *PageWidth  = *PageLength;
-       *PageLength = temp;
-       break;
-
-    case 2 : /* Reverse Portrait */
-       temp        = *PageWidth - *PageLeft;
-       *PageLeft   = *PageWidth - *PageRight;
-       *PageRight  = temp;
-
-       temp        = *PageLength - *PageBottom;
-       *PageBottom = *PageLength - *PageTop;
-       *PageTop    = temp;
-        break;
-
-    case 3 : /* Reverse Landscape */
-       temp        = *PageWidth - *PageLeft;
-       *PageLeft   = *PageWidth - *PageRight;
-       *PageRight  = temp;
-
-       temp        = *PageLength - *PageBottom;
-       *PageBottom = *PageLength - *PageTop;
-       *PageTop    = temp;
-
-       temp        = *PageLeft;
-       *PageLeft   = *PageBottom;
-       *PageBottom = temp;
-
-       temp        = *PageRight;
-       *PageRight  = *PageTop;
-       *PageTop    = temp;
-
-       temp        = *PageWidth;
-       *PageWidth  = *PageLength;
-       *PageLength = temp;
-       break;
-  }
-}
index e9bcd2f2f0da001bd1cfbe2cefa6224348418f15..2e37801a181d1b4f32768aa659e7f318064fd26f 100644 (file)
@@ -35,7 +35,6 @@ extern "C" {
 
 #  include <cups/cups.h>
 #  include <cups/raster.h>
-#  include <ppd/ppd.h>
 
 
 /*
@@ -51,15 +50,19 @@ typedef struct cf_filter_data_s {
   char *job_title;           /* Job title or NULL */
   int copies;                /* Number of copies
                                (1 if filter(s) should not treat it) */
+  char *content_type;        /* Input MIME type (CUPS env variable
+                               CONTENT_TYPE) or NULL */
+  char *final_content_type;  /* Output MIME type (CUPS env variable
+                               FINAL_CONTENT_TYPE) or NULL */
   ipp_t *job_attrs;          /* IPP attributes passed along with the job */
   ipp_t *printer_attrs;      /* Printer capabilities in IPP format
                                (what is answered to get-printer-attributes */
+  cups_page_header2_t *header; /* CUPS/PWG Raster header (optional) */
   int           num_options;
   cups_option_t *options;    /* Job options as key/value pairs */
-  char *ppdfile;             /* PPD file name */
-  ppd_file_t *ppd;           /* PPD file data */
   int back_pipe[2];          /* File descriptors of backchannel pipe */
   int side_pipe[2];          /* File descriptors of sidechannel pipe */
+  cups_array_t *extension;   /* Extension data */
   cf_logfunc_t logfunc;  /* Logging function, NULL for no logging */
   void *logdata;             /* User data for logging function, can be NULL */
   cf_filter_iscanceledfunc_t iscanceledfunc; /* Function returning 1 when
@@ -69,6 +72,11 @@ typedef struct cf_filter_data_s {
                                NULL */
 } cf_filter_data_t;
 
+typedef struct cf_filter_data_ext_s {
+  char* name;
+  void *ext;
+} cf_filter_data_ext_t;
+
 typedef int (*cf_filter_function_t)(int inputfd, int outputfd,
                                    int inputseekable, cf_filter_data_t *data,
                                    void *parameters);
@@ -84,26 +92,6 @@ typedef enum cf_filter_out_format_e { /* Possible output formats for filter
   CF_FILTER_OUT_FORMAT_PXL            /* PCL-XL */
 } cf_filter_out_format_t;
 
-typedef struct cf_filter_external_cups_s { /* Parameters for the
-                                          cfFilterExternalCUPS() filter
-                                          function */
-  const char *filter;        /* Path/Name of the CUPS filter to be called by
-                               this filter function, required */
-  int is_backend;            /* 0 if we call a filter, 1 if we call a CUPS
-                               backend, 2 if we call a CUPS backend in
-                               device discovery mode */
-  const char *device_uri;    /* Device URI when calling a CUPS Backend for
-                               processing a job, optional, alternatively
-                               DEVICE_URI environment variable can get set
-                               in envp */
-  int num_options;           /* Extra options for the 5th command line */
-  cups_option_t *options;    /* argument, options of filter_data have
-                                priority, 0/NULL if none */
-  char **envp;               /* Additional environment variables, the already
-                                defined ones stay valid but can be overwritten
-                                by these ones, NULL if none */
-} cf_filter_external_cups_t;
-
 typedef struct cf_filter_filter_in_chain_s { /* filter entry for CUPS array to
                                                be supplied to cfFilterChain()
                                                filter function */
@@ -127,8 +115,7 @@ typedef struct cf_filter_universal_parameter_s { /* Contains input and output
                                                    universal function, and also
                                                    parameters for
                                                    cfFilterTextToPDF() */
-  char *input_format;                 
-  char *output_format;
+  char *actual_output_type;
   cf_filter_texttopdf_parameter_t texttopdf_params;
 } cf_filter_universal_parameter_t;
 
@@ -146,17 +133,14 @@ extern void cfCUPSLogFunc(void *data,
 extern int cfCUPSIsCanceledFunc(void *data);
 
 
-extern int cfFilterCUPSWrapper(int argc,
-                              char *argv[],
-                              cf_filter_function_t filter,
-                              void *parameters,
-                              int *JobCanceled);
+extern void *cfFilterDataAddExt(cf_filter_data_t *data, const char *name,
+                               void *ext);
 
 
-extern int cfFilterLoadPPD(cf_filter_data_t *data);
+extern void *cfFilterDataGetExt(cf_filter_data_t *data, const char *name);
 
 
-extern void cfFilterFreePPD(cf_filter_data_t *data);
+extern void *cfFilterDataRemoveExt(cf_filter_data_t *data, const char *name);
 
 
 extern int cfFilterTee(int inputfd,
@@ -192,19 +176,7 @@ extern int cfFilterChain(int inputfd,
 /* Parameters: Unsorted (!) CUPS array of cf_filter_filter_in_chain_t*
    List of filters to execute in a chain, next filter takes output of
    previous filter as input, all get the same filter data, parameters
-   from the array */
-
-
-extern int cfFilterExternalCUPS(int inputfd,
-                               int outputfd,
-                               int inputseekable,
-                               cf_filter_data_t *data,
-                               void *parameters);
-
-/* Parameters: cf_filter_external_cups_t*
-   Path/Name of the CUPS filter to be called by this filter function,
-   extra options for the 5th command line argument, and extra environment
-   variables */
+   are supplied individually in the array */
 
 
 extern int cfFilterOpenBackAndSidePipes(cf_filter_data_t *data);
@@ -219,17 +191,19 @@ extern int cfFilterGhostscript(int inputfd,
                               cf_filter_data_t *data,
                               void *parameters);
 
-/* Parameters: cf_filter_out_format_t*
-   Ouput format: PDF, raster-only PDF, PCLm, PostScript, CUPS Raster,
+/* Requires specification of output format via data->final_content_type
+
+   Output formats: PDF, raster-only PDF, PCLm, PostScript, CUPS Raster,
    PWG Raster, Apple Raster, PCL-XL
-   Note: With the CF_FILTER_OUT_FORMAT_APPLE_RASTER selection and a
-   Ghostscript version without "appleraster" output device (9.55.x and
-   older) the output is actually CUPS Raster but information about
-   available color spaces and depths is taken from the urf-supported
-   printer IPP attribute or appropriate PPD file attribute. This mode
-   is for further processing with rastertopwg. With Ghostscript
-   supporting Apple Raster output (9.56.0 and newer), we actually
-   produce Apple Raster and no further filter is required. */
+
+   Note: With the Apple Raster selection and a Ghostscript version
+   without "appleraster" output device (9.55.x and older) the output
+   is actually CUPS Raster but information about available color
+   spaces and depths is taken from the urf-supported printer IPP
+   attribute. This mode is for further processing with
+   rastertopwg. With Ghostscript supporting Apple Raster output
+   (9.56.0 and newer), we actually produce Apple Raster and no further
+   filter is required. */
 
 
 extern int cfFilterBannerToPDF(int inputfd,
@@ -253,26 +227,21 @@ extern int cfFilterImageToPDF(int inputfd,
                              void *parameters);
 
 
-extern int cfFilterImageToPS(int inputfd,
-                            int outputfd,
-                            int inputseekable,
-                            cf_filter_data_t *data,
-                            void *parameters);
-
-
 extern int cfFilterImageToRaster(int inputfd,
                                 int outputfd,
                                 int inputseekable,
                                 cf_filter_data_t *data,
                                 void *parameters);
 
-/* Parameters: cf_filter_out_format_t* Ouput format: CUPS Raster, PWG
-   Raster, Apple Raster, PCLM
+/* Requires specification of output format via data->final_content_type
+
+   Output formats: CUPS Raster, PWG Raster, Apple Raster, PCLM
+
    Note: On the Apple Raster, PWG Raster, and PCLm selection the
    output is actually CUPS Raster but information about available
    color spaces and depths is taken from the urf-supported or
-   pwg-raster-document-type-supported printer IPP attributes or
-   appropriate PPD file attributes. This mode is for further
+   pwg-raster-document-type-supported printer IPP attributes or from a
+   supplied CUPS Raster sample header. This mode is for further
    processing with rastertopwg or rastertopclm. This can change in the
    future when we add Apple Raster and PWG Raster output support to
    this filter function. */
@@ -284,13 +253,15 @@ extern int cfFilterMuPDFToPWG(int inputfd,
                              cf_filter_data_t *data,
                              void *parameters);
 
-/* Parameters: cf_filter_out_format_t*
-   Ouput format: CUPS Raster, PWG Raster, Apple Raster, PCLm
+/* Requires specification of output format via data->final_content_type
+
+   Output formats: CUPS Raster, PWG Raster, Apple Raster, PCLm
+
    Note: With CUPS Raster, Apple Raster, or PCLm selections the output
    is actually PWG Raster but information about available color spaces
-   and depths is taken from the pseudo-PostScript in the PPDs options,
-   urf-supported printer IPP attribute or the appropriate PPD file
-   attribute (PCLM is always sRGB 8-bit). These modes are for further
+   and depths is taken from the urf-supported printer IPP attribute,
+   the pclm- attributes, or from a supplied CUPS Raster sample header
+   (PCLM is always sGray/sRGB 8-bit). These modes are for further
    processing with pwgtoraster or rastertopclm. This can change in the
    future when MuPDF adds further output formats. */
 
@@ -301,8 +272,9 @@ extern int cfFilterPCLmToRaster(int inputfd,
                                cf_filter_data_t *data,
                                void *parameters);
 
-/* Parameters: cf_filter_out_format_t*
-   Ouput format: CUPS Raster, Apple Raster, or PWG Raster */
+/* Requires specification of output format via data->final_content_type
+
+   Output formats: CUPS Raster, Apple Raster, or PWG Raster */
 
 
 extern int cfFilterPDFToPDF(int inputfd,
@@ -311,17 +283,16 @@ extern int cfFilterPDFToPDF(int inputfd,
                            cf_filter_data_t *data,
                            void *parameters);
 
-/* Parameters: const char*
-   For CUPS value of FINAL_CONTENT_TYPE environment variable, generally
-   MIME type of the final output format of the filter chain for this job
-   (not the output of the cfFilterPDFToPDF() filter function) */
+/* (Optional) Specification of output format via
+   data->final_content_type is used for determining whether this
+   filter function does page logging for CUPS (output of "PAGE: XX YY"
+   log messages) or not and also to determine whether the printer or
+   driver generates copies or whether we have to send the pages
+   repeatedly.
 
-
-extern int cfFilterPDFToPS(int inputfd,
-                          int outputfd,
-                          int inputseekable,
-                          cf_filter_data_t *data,
-                          void *parameters);
+   Alternatively, the options "pdf-filter-page-logging",
+   "hardware-copies", and "hardware-collate" can be used to manually
+   do these selections. */
 
 
 extern int cfFilterPDFToRaster(int inputfd,
@@ -330,33 +301,30 @@ extern int cfFilterPDFToRaster(int inputfd,
                               cf_filter_data_t *data,
                               void* parameters);
 
-/* Parameters: cf_filter_out_format_t*
-   Ouput format: CUPS Raster, PWG Raster, Apple Raster, PCLm
+/* Requires specification of output format via data->final_content_type
+
+   Output formats: CUPS Raster, PWG Raster, Apple Raster, PCLm
+
    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,
-                         int outputfd,
-                         int inputseekable,
-                         cf_filter_data_t *data,
-                         void *parameters);
-
-
 extern int cfFilterPWGToRaster(int inputfd,
                               int outputfd,
                               int inputseekable,
                               cf_filter_data_t *data,
                               void *parameters);
 
-/* Parameters: cf_filter_out_format_t*
-   Ouput format: CUPS Raster, PWG Raster, Apple Raster, PCLm
-   Note: On the PCLM selection the output is actually CUPS Raster
-   but information about available color spaces and depths is taken from
-   the pclm-... printer IPP attributes or appropriate PPD file
-   attribute. This mode is for further processing with rastertopclm. */
+/* Requires specification of output format via data->final_content_type
+
+   Output formats: CUPS Raster, PWG Raster, Apple Raster, PCLm
+
+   Note: On the PCLM selection the output is actually CUPS Raster but
+   information about available color spaces and depths is taken from
+   the pclm-... printer IPP attributes. This mode is for further
+   processing with rastertopclm. */
 
 
 extern int cfFilterRasterToPDF(int inputfd,
@@ -365,15 +333,9 @@ extern int cfFilterRasterToPDF(int inputfd,
                               cf_filter_data_t *data,
                               void *parameters);
 
-/* Parameters: cf_filter_out_format_t*
-   Ouput format: PDF, PCLm */
+/* Requires specification of output format via data->final_content_type
 
-
-extern int cfFilterRasterToPS(int inputfd,
-                             int outputfd,
-                             int inputseekable,
-                             cf_filter_data_t *data,
-                             void *parameters);
+   Output formats: PDF, PCLm */
 
 
 extern int cfFilterRasterToPWG(int inputfd,
@@ -382,8 +344,9 @@ extern int cfFilterRasterToPWG(int inputfd,
                               cf_filter_data_t *data,
                               void *parameters);
 
-/* Parameters: cf_filter_out_format_t*
-   Ouput format: Apple Raster or PWG Raster */
+/* Requires specification of output format via data->final_content_type
+
+   Output formats: Apple Raster or PWG Raster */
 
 
 extern int cfFilterTextToPDF(int inputfd,
@@ -393,6 +356,7 @@ extern int cfFilterTextToPDF(int inputfd,
                             void *parameters);
 
 /* Parameters: cf_filter_texttopdf_parameter_t*
+
    Data directory (fonts, charsets), charset, content type (for prettyprint),
    classification (for overprint/watermark) */
 
@@ -409,34 +373,16 @@ extern int cfFilterUniversal(int inputfd,
                             cf_filter_data_t *data,
                             void *parameters);
 
-/* Parameters: cf_filter_universal_parameter_t
-   Contains : Input_type: CONTENT_TYPE environment variable of CUPS
-              Output type: FINAL_CONTENT TYPE environment variable of CUPS
-              texttopdf_params: parameters for texttopdf */
-
-
-extern void cfFilterSetCommonOptions(ppd_file_t *ppd,
-                                    int num_options,
-                                    cups_option_t *options,
-                                    int change_size,
-                                    int *Orientation,
-                                    int *Duplex,
-                                    int *LanguageLevel,
-                                    int *ColorDevice,
-                                    float *PageLeft,
-                                    float *PageRight,
-                                    float *PageTop,
-                                    float *PageBottom,
-                                    float *PageWidth,
-                                    float *PageLength,
-                                    cf_logfunc_t log,
-                                    void *ld);
-
-
-extern void cfFilterUpdatePageVars(int Orientation,
-                                  float *PageLeft, float *PageRight,
-                                  float *PageTop, float *PageBottom,
-                                  float *PageWidth, float *PageLength);
+/* Requires specification of input format via data->content_type and 
+   job's final output format via data->final_content_type
+
+   Parameters: cf_filter_universal_parameter_t
+
+   Contains: actual_output_type: Format which the filter should
+             actually produce if different from job's final output
+             format, otherwise NULL to produce the job's final output
+             format
+            texttopdf_params: parameters for texttopdf */
 
 
 #  ifdef __cplusplus
index 3fe9a0862f35d05a68b3d03b74ce5eda73990237..6f1e9a5a86c5922f220e68a3efa5cb55d92bb96d 100644 (file)
@@ -59,6 +59,7 @@ parse_doc_type(FILE *fp)
     if (is_empty && buf[0] != '\n') is_empty = 0;
     if (strncmp(buf,"%PDF",4) == 0) type = GS_DOC_TYPE_PDF;
     if (strncmp(buf,"%!",2) == 0) type = GS_DOC_TYPE_PS;
+    if (type != GS_DOC_TYPE_UNKNOWN) break;
   }
   if (is_empty) type = GS_DOC_TYPE_EMPTY;
   rewind(fp);
@@ -100,8 +101,8 @@ parse_pdf_header_options(FILE *fp, gs_page_header *h)
 }
 
 static void
-add_pdf_header_options(gs_page_header *h, cups_array_t *gs_args,
-                      cf_filter_out_format_t outformat, int pxlcolor)
+header_to_gs_args(gs_page_header *h, cups_array_t *gs_args,
+                 cf_filter_out_format_t outformat, int pxlcolor)
 {
   int i;
   char tmpstr[1024];
@@ -702,17 +703,15 @@ cfFilterGhostscript(int inputfd,            /* I - File descriptor input
   cups_cspace_t cspace = -1;
   int bytes;
   int fd;
-  int cm_disabled;
+  int cm_disabled = 0;
   int i;
   int num_options;
   int status = 1;
-  ppd_file_t *ppd = NULL;
   ipp_t *printer_attrs = data->printer_attrs;
   ipp_t *job_attrs = data->job_attrs;
   struct sigaction sa;
   cf_cm_calibration_t cm_calibrate;
   int pxlcolor = 0; /* 1 if printer is color printer otherwise 0. */
-  ppd_attr_t *attr;
   ipp_attribute_t *ipp_attr;
   cf_logfunc_t log = data->logfunc;
   void          *ld = data->logdata;
@@ -720,17 +719,8 @@ cfFilterGhostscript(int inputfd,            /* I - File descriptor input
   void          *icd = data->iscanceleddata;
 
 
-  /* Note: With the CF_FILTER_OUT_FORMAT_APPLE_RASTER selection and a
-     Ghostscript version without "appleraster" output device (9.55.x
-     and older) the output is actually CUPS Raster but information
-     about available color spaces and depths is taken from the
-     urf-supported printer IPP attribute or appropriate PPD file
-     attribute. This mode is for further processing with
-     rastertopwg. With Ghostscript supporting Apple Raster output
-     (9.56.0 and newer), we actually produce Apple Raster and no
-     further filter is required. */
-
-  if (parameters) {
+  if (parameters)
+  {
     outformat = *(cf_filter_out_format_t *)parameters;
     if (outformat != CF_FILTER_OUT_FORMAT_PDF &&
        outformat != CF_FILTER_OUT_FORMAT_PDF_IMAGE &&
@@ -740,8 +730,37 @@ cfFilterGhostscript(int inputfd,            /* I - File descriptor input
        outformat != CF_FILTER_OUT_FORMAT_APPLE_RASTER &&
        outformat != CF_FILTER_OUT_FORMAT_PXL)
       outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
-  } else
-    outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
+  }
+  else
+  {
+    t = data->final_content_type;
+    if (t)
+    {
+      if (strcasestr(t, "pwg"))
+       outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
+      else if (strcasestr(t, "urf"))
+       outformat = CF_FILTER_OUT_FORMAT_APPLE_RASTER;
+      else if (strcasestr(t, "pclm"))
+       outformat = CF_FILTER_OUT_FORMAT_PCLM;
+      else if (strcasestr(t, "pcl-xl"))
+       outformat = CF_FILTER_OUT_FORMAT_PXL;
+      else if (strcasestr(t, "pdf"))
+       outformat = CF_FILTER_OUT_FORMAT_PDF;
+      else
+       outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
+    }
+    else
+      outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
+  }
+
+  /* Note: With the CF_FILTER_OUT_FORMAT_APPLE_RASTER selection and a
+     Ghostscript version without "appleraster" output device (9.55.x
+     and older) the output is actually CUPS Raster but information
+     about available color spaces and depths is taken from the
+     urf-supported printer IPP attribute. This mode is for further
+     processing with rastertopwg. With Ghostscript supporting Apple
+     Raster output (9.56.0 and newer), we actually produce Apple
+     Raster and no further filter is required. */
 
   if (log) log(ld, CF_LOGLEVEL_DEBUG,
               "cfFilterGhostscript: Output format: %s",
@@ -767,8 +786,6 @@ cfFilterGhostscript(int inputfd,            /* I - File descriptor input
   num_options = data->num_options;
   options = data->options;
 
-  ppd = data->ppd;
-
  /*
   * Environment variables for Ghostscript call ...
   */
@@ -780,13 +797,6 @@ cfFilterGhostscript(int inputfd,            /* I - File descriptor input
     num_env ++;
   }
 
-  if (data->ppdfile)
-  {
-    snprintf(tmpstr, sizeof(tmpstr), "PPD=%s", data->ppdfile);
-    envp[num_env] = strdup(tmpstr);
-    num_env ++;
-  }
-
   if ((t = getenv("RIP_MAX_CACHE")) != NULL)
   {
     snprintf(tmpstr, sizeof(tmpstr), "RIP_MAX_CACHE=%s", t);
@@ -972,22 +982,6 @@ cfFilterGhostscript(int inputfd,            /* I - File descriptor input
                 "cfFilterGhostscript: Streaming mode, no checks for input format, zero-page input, instructions from previous filter");
   }
 
-  /* Find print-rendering-intent */
-  cfGetPrintRenderIntent(data, &h);
-  if(log) log(ld, CF_LOGLEVEL_DEBUG,
-             "Print rendering intent = %s", h.cupsRenderingIntent);
-
-  /*  Check status of color management in CUPS */
-  cm_calibrate = cfCmGetCupsColorCalibrateMode(data, options, num_options);
-
-  if (cm_calibrate == CF_CM_CALIBRATION_ENABLED)
-    cm_disabled = 1;
-  else 
-    cm_disabled = cfCmIsPrinterCmDisabled(data);
-
-  if (!cm_disabled)
-    cfCmGetPrinterIccProfile(data, &icc_profile, ppd);
-
   /* Ghostscript parameters */
   gs_args = cupsArrayNew(NULL, NULL);
   if (!gs_args) {
@@ -1069,9 +1063,44 @@ cfFilterGhostscript(int inputfd,            /* I - File descriptor input
                 strdup("-dColorConversionStrategy=/LeaveColorUnchanged"));
   }
 
-  cspace = icc_profile ? CUPS_CSPACE_RGB : -1;
+  /* Generate a pseudo Raster header to collect all data from the
+     printer and job attributes and also from the options which is
+     relevant for the Raster output. The header is not actually
+     inserted into the output Raster stream, but instead, converted to
+     command line options for Ghostscript by the header_to_gs_args()
+     function. Then Ghostscript generates the actual headers by
+     itself.
+
+     Ghostscript especially uses the sizes of each input page as
+     output page sizes and not the page size requested on the call of
+     this filter function. This means, for avoiding to send pages of
+     unsupported size to the printer, to pass the input data through
+     cfFilterPDFToPDF() before applying the cfFilterGhostscript()
+     filter function. */
+
+  cspace = -1;
   cfRasterPrepareHeader(&h, data, outformat, outformat, 0, &cspace);
 
+  /* Find print-rendering-intent */
+  h.cupsRenderingIntent[0] = '\0';
+  cfGetPrintRenderIntent(data, h.cupsRenderingIntent,
+                        sizeof(h.cupsRenderingIntent));
+  if(log) log(ld, CF_LOGLEVEL_DEBUG,
+             "Print rendering intent = %s", h.cupsRenderingIntent);
+
+  /* Check status of color management in CUPS */
+  cm_calibrate = cfCmGetCupsColorCalibrateMode(data);
+
+  if (cm_calibrate == CF_CM_CALIBRATION_ENABLED)
+    cm_disabled = 1;
+  else
+    cm_disabled = cfCmIsPrinterCmDisabled(data);
+
+  if (!cm_disabled)
+    cfCmGetPrinterIccProfile(data, cfRasterColorSpaceString(h.cupsColorSpace),
+                            h.MediaType, h.HWResolution[0], h.HWResolution[1],
+                            &icc_profile);
+
   /* Special Ghostscript options for raster-only PDF output */
 
   /* We use PCLm instead of general raster PDF here if the printer
@@ -1091,17 +1120,12 @@ cfFilterGhostscript(int inputfd,            /* I - File descriptor input
     char c;
 
     ipp_attr = NULL;
-    attr = NULL;
     if (outformat == CF_FILTER_OUT_FORMAT_PCLM || /* PCLm forced */
        /* PCLm supported according to printer IPP attributes */
        (printer_attrs &&
         (ipp_attr =
          ippFindAttribute(printer_attrs, "pclm-source-resolution-supported",
-                          IPP_TAG_ZERO)) != NULL) ||
-       /* PCLm supported according to PPD file */
-       (ppd &&
-        (attr =
-         ppdFindAttr(ppd, "cupsPclmSourceResolutionSupported", 0)) != NULL)) {
+                          IPP_TAG_ZERO)) != NULL)) {
 
       outformat = CF_FILTER_OUT_FORMAT_PCLM;
 
@@ -1111,9 +1135,7 @@ cfFilterGhostscript(int inputfd,            /* I - File descriptor input
          correct if needed */
       res_x = h.HWResolution[0];
       res_y = h.HWResolution[1];
-      if (attr)
-       res_str = attr->value;
-      else if (ipp_attr) {
+      if (ipp_attr) {
        ippAttributeString(ipp_attr, tmpstr, sizeof(tmpstr));
        res_str = tmpstr;
       }
@@ -1144,32 +1166,22 @@ cfFilterGhostscript(int inputfd,            /* I - File descriptor input
       if (best_res_x > 0 && best_res_y > 0) {
        snprintf(tmpstr, sizeof(tmpstr), "-r%dx%d", best_res_x, best_res_y);
        cupsArrayAdd(gs_args, strdup(tmpstr));
-      } else if ((printer_attrs &&
-                 (ipp_attr =
-                  ippFindAttribute(printer_attrs,
-                                   "pclm-source-resolution-default",
-                                   IPP_TAG_ZERO)) != NULL) ||
-                (ppd &&
-                 (attr =
-                  ppdFindAttr(ppd,
-                              "cupsPclmSourceResolutionDefault", 0)) != NULL)){
-       if (attr)
-         res_str = attr->value;
-       else if (ipp_attr) {
-         ippAttributeString(ipp_attr, tmpstr, sizeof(tmpstr));
-         res_str = tmpstr;
-       }
-       if (res_str)
-         if ((n = sscanf(res_str, "%d%c%d",
-                         &best_res_x, &c, &best_res_y)) > 0) {
-           if (n < 3 || (c != 'x' && c != 'X'))
-             best_res_y = best_res_x;
-           if (best_res_x > 0 && best_res_y > 0) {
-             snprintf(tmpstr, sizeof(tmpstr), "-r%dx%d",
-                      best_res_x, best_res_y);
-             cupsArrayAdd(gs_args, strdup(tmpstr));
-           }
+      } else if (printer_attrs &&
+                (ipp_attr =
+                 ippFindAttribute(printer_attrs,
+                                  "pclm-source-resolution-default",
+                                  IPP_TAG_ZERO)) != NULL) {
+       ippAttributeString(ipp_attr, tmpstr, sizeof(tmpstr));
+       if ((n = sscanf(tmpstr, "%d%c%d",
+                       &best_res_x, &c, &best_res_y)) > 0) {
+         if (n < 3 || (c != 'x' && c != 'X'))
+           best_res_y = best_res_x;
+         if (best_res_x > 0 && best_res_y > 0) {
+           snprintf(tmpstr, sizeof(tmpstr), "-r%dx%d",
+                    best_res_x, best_res_y);
+           cupsArrayAdd(gs_args, strdup(tmpstr));
          }
+       }
       }
       if (best_res_x <= 0 || best_res_y <= 0) {
        snprintf(tmpstr, sizeof(tmpstr), "-r%dx%d", res_x, res_y);
@@ -1186,20 +1198,12 @@ cfFilterGhostscript(int inputfd,            /* I - File descriptor input
       /* Strip/Band Height */
 
       n = 0;
-      if ((printer_attrs &&
-          (ipp_attr =
-           ippFindAttribute(printer_attrs,
-                            "pclm-strip-height-preferred",
-                            IPP_TAG_ZERO)) != NULL) ||
-         (ppd &&
-          (attr =
-           ppdFindAttr(ppd,
-                       "cupsPclmStripHeightPreferred", 0)) != NULL)) {
-       if (attr)
-         n = atoi(attr->value);
-       else if (ipp_attr)
-         n = ippGetInteger(ipp_attr, 0);
-      }
+      if (printer_attrs &&
+         (ipp_attr =
+          ippFindAttribute(printer_attrs,
+                           "pclm-strip-height-preferred",
+                           IPP_TAG_ZERO)) != NULL)
+       n = ippGetInteger(ipp_attr, 0);
       if (n <= 0) n = 16;
       snprintf(tmpstr, sizeof(tmpstr), "-dStripHeight=%d", n);
       cupsArrayAdd(gs_args, strdup(tmpstr));
@@ -1208,31 +1212,19 @@ cfFilterGhostscript(int inputfd,            /* I - File descriptor input
 
       /* Compression method */
 
-      if ((printer_attrs &&
-          (ipp_attr =
-           ippFindAttribute(printer_attrs,
-                            "pclm-compression-method-preferred",
-                            IPP_TAG_ZERO)) != NULL) ||
-         (ppd &&
-          (attr =
-           ppdFindAttr(ppd,
-                       "cupsPclmCompressionMethodPreferred", 0)) != NULL)) {
-       if (attr)
-         res_str = attr->value;
-       else if (ipp_attr) {
-         ippAttributeString(ipp_attr, tmpstr, sizeof(tmpstr));
-         res_str = tmpstr;
-       }
-       if (res_str) {
-         if (strcasestr(res_str, "flate"))
-           cupsArrayAdd(gs_args, strdup("-sCompression=Flate"));
-         else if (strcasestr(res_str, "rle"))
-           cupsArrayAdd(gs_args, strdup("-sCompression=RLE"));
-         else if (strcasestr(res_str, "jpeg"))
-           cupsArrayAdd(gs_args, strdup("-sCompression=JPEG"));
-         else
-           cupsArrayAdd(gs_args, strdup("-sCompression=Flate"));
-       } else
+      if (printer_attrs &&
+         (ipp_attr =
+          ippFindAttribute(printer_attrs,
+                           "pclm-compression-method-preferred",
+                           IPP_TAG_ZERO)) != NULL) {
+       ippAttributeString(ipp_attr, tmpstr, sizeof(tmpstr));
+       if (strcasestr(tmpstr, "flate"))
+         cupsArrayAdd(gs_args, strdup("-sCompression=Flate"));
+       else if (strcasestr(tmpstr, "rle"))
+         cupsArrayAdd(gs_args, strdup("-sCompression=RLE"));
+       else if (strcasestr(tmpstr, "jpeg"))
+         cupsArrayAdd(gs_args, strdup("-sCompression=JPEG"));
+       else
          cupsArrayAdd(gs_args, strdup("-sCompression=Flate"));
       } else
        cupsArrayAdd(gs_args, strdup("-sCompression=Flate"));
@@ -1242,18 +1234,11 @@ cfFilterGhostscript(int inputfd,            /* I - File descriptor input
       /* Ghostscript output device and color/gray */
 
       n = 0;
-      if (ppd) {
-        if ((attr = ppdFindAttr(ppd,"ColorDevice", 0)) != 0 &&
-           (!strcasecmp(attr->value, "true") ||
-            !strcasecmp(attr->value, "on") ||
-            !strcasecmp(attr->value, "yes")))
-          /* Color printer, according to PPD */
-         n = 1;
-      } else if (printer_attrs) {
-       if (((ipp_attr =
-             ippFindAttribute(printer_attrs,
-                              "color-supported", IPP_TAG_ZERO)) != NULL &&
-            ippGetBoolean(ipp_attr, 0))) {
+      if (printer_attrs) {
+       if ((ipp_attr =
+            ippFindAttribute(printer_attrs,
+                             "color-supported", IPP_TAG_ZERO)) != NULL &&
+           ippGetBoolean(ipp_attr, 0)) {
          /* Color printer, according to printer attributes */
          n = 1;
        }
@@ -1275,23 +1260,12 @@ cfFilterGhostscript(int inputfd,            /* I - File descriptor input
 
   if (outformat == CF_FILTER_OUT_FORMAT_PXL)
   {
-    if (ppd)
-    {
-      {
-        if ((attr = ppdFindAttr(ppd,"ColorDevice", 0)) != 0 &&
-           (!strcasecmp(attr->value, "true") ||
-            !strcasecmp(attr->value, "on") ||
-            !strcasecmp(attr->value, "yes")))
-          /* Color PCL XL printer, according to PPD */
-         pxlcolor = 1;
-      }  
-    }
-    else if (printer_attrs)
+    if (printer_attrs)
     {
-      if (((ipp_attr =
-           ippFindAttribute(printer_attrs,
-                            "color-supported", IPP_TAG_BOOLEAN)) != NULL &&
-          ippGetBoolean(ipp_attr, 0))) {
+      if ((ipp_attr =
+          ippFindAttribute(printer_attrs,
+                           "color-supported", IPP_TAG_BOOLEAN)) != NULL &&
+         ippGetBoolean(ipp_attr, 0)) {
         /* Color PCL XL printer, according to printer attributes */
         pxlcolor = 1;
       }
@@ -1361,17 +1335,13 @@ cfFilterGhostscript(int inputfd,            /* I - File descriptor input
           !strncasecmp(val, "Rgbw", 4)      ||
           !strncasecmp(val, "Rgb", 3)       ||
           !strcasecmp(val, "auto"))
-        {
           pxlcolor = 1;
-        }
         else if(!strncasecmp(val, "Device", 6))
         {
           const char *ptr = val + 6;
           if(strtol(ptr, (char **)&ptr, 10)>1)  /* Printer seems to support
                                                   more then 1 color  */
-          {
             pxlcolor = 1;
-          }
         }
       }
     } 
@@ -1387,13 +1357,82 @@ cfFilterGhostscript(int inputfd,            /* I - File descriptor input
   h.Orientation = CUPS_ORIENT_0;
 
   /* get all the data from the header and pass it to ghostscript */
-  add_pdf_header_options (&h, gs_args, outformat, pxlcolor);
+  header_to_gs_args(&h, gs_args, outformat, pxlcolor);
+
+  /* CUPS Raster versions: 2 = compressed; 3 = uncompressed */
+  /* Requires Ghostscript 9.57 or later */
+  if (outformat == CF_FILTER_OUT_FORMAT_CUPS_RASTER &&
+      (t = cupsGetOption("cups-raster-version",
+                          num_options, options)) != NULL &&
+      (!strcmp(t, "2") || !strcmp(t, "3")))
+  {
+    snprintf(tmpstr, sizeof(tmpstr), "-dcupsRasterVersion=%s", t);
+    cupsArrayAdd(gs_args, strdup(tmpstr));
+  }
+
+  /* Back side orientation for duplex printing: Normal, ManualTumble,
+     Rotated, Flipped */
+  /* When printing duplex, margins on the back side meeds to get swapped? */
+  /* Requires Ghostscript 9.57 or later */
+  if (h.Duplex)
+  {
+    int backside;
+    /* analyze options relevant to Duplex */
+    /* APDuplexRequiresFlippedMargin */
+    enum {
+      FM_NO,
+      FM_FALSE,
+      FM_TRUE
+    } flippedMargin;
+
+    backside = cfGetBackSideOrientation(data);
+
+    t = NULL;
+    flippedMargin = FM_NO;
+
+    if (backside >= 0)
+    {
+      flippedMargin = (backside & 16 ? FM_TRUE :
+                      (backside & 8 ? FM_FALSE :
+                       FM_NO));
+      backside &= 7;
+
+      if (backside == CF_BACKSIDE_MANUAL_TUMBLE)
+       t = "ManualTumble";
+      else if (backside == CF_BACKSIDE_ROTATED)
+       t = "Rotated";
+      else if (backside == CF_BACKSIDE_FLIPPED)
+       t = "Flipped";
+      else
+       t = "Normal";
+    }
+
+    if (t != NULL)
+    {
+      snprintf(tmpstr, sizeof(tmpstr), "-scupsBackSideOrientation=%s", t);
+      cupsArrayAdd(gs_args, strdup(tmpstr));
+    }
+
+    if (flippedMargin == FM_TRUE)
+      cupsArrayAdd(gs_args, strdup("-dcupsBackSideFlipMargins"));
+  }
+
+  /* Manual Copies needed (no device copies functionality available) */
+  /* Requires Ghostscript 9.57 or later */
+  if ((t = cupsGetOption("hardware-copies",
+                        num_options, options)) != NULL &&
+      (!strcasecmp(t, "false") || !strcasecmp(t, "off") ||
+       !strcasecmp(t, "no")))
+    cupsArrayAdd(gs_args, strdup("-dcupsManualCopies"));
 
   /* CUPS font path */
-  if ((t = getenv("CUPS_FONTPATH")) == NULL)
-    t = CUPS_FONTPATH;
-  snprintf(tmpstr, sizeof(tmpstr), "-I%s", t);
-  cupsArrayAdd(gs_args, strdup(tmpstr));
+  if ((t = cupsGetOption("cups-fontpath",
+                        num_options, options)) != NULL &&
+      t[0] != '\0')
+  {
+    snprintf(tmpstr, sizeof(tmpstr), "-I%s", t);
+    cupsArrayAdd(gs_args, strdup(tmpstr));
+  }
 
   /* Set the device output ICC profile */
   if (icc_profile != NULL && icc_profile[0] != '\0') {
@@ -1442,27 +1481,24 @@ cfFilterGhostscript(int inputfd,            /* I - File descriptor input
     cupsArrayAdd(gs_args, strdup(tmpstr));
   }
 
-  if ((t = cupsGetOption("profile", num_options, options)) != NULL) {
+  if (!cm_disabled &&
+      (t = cupsGetOption("profile", num_options, options)) != NULL) {
     snprintf(tmpstr, sizeof(tmpstr), "<</cupsProfile(%s)>>setpagedevice", t);
     cupsArrayAdd(gs_args, strdup(tmpstr));
   }
 
-  /* Do we have a "center-of-pixel" command line option or
-     "CenterOfPixel" PPD option set to "true"? In this case let
-     Ghostscript use the center-of-pixel rule instead of the
-     PostScript-standard any-part-of-pixel rule when filling a
-     path. This improves the accuracy of graphics (like bar codes for
-     example) on low-resolution printers (like label printers with
-     typically 203 dpi). See
+  /* Do we have a "center-of-pixel" or "CenterOfPixel" command line
+     option set to "true"? In this case let Ghostscript use the
+     center-of-pixel rule instead of the PostScript-standard
+     any-part-of-pixel rule when filling a path. This improves the
+     accuracy of graphics (like bar codes for example) on
+     low-resolution printers (like label printers with typically 203
+     dpi). See
      https://bugs.linuxfoundation.org/show_bug.cgi?id=1373 */
-  if (((t = cupsGetOption("CenterOfPixel", num_options, options)) == NULL &&
-       (t = cupsGetOption("center-of-pixel", num_options, options)) == NULL &&
-       ppd && (attr = ppdFindAttr(ppd,"DefaultCenterOfPixel", NULL)) != NULL &&
-       (!strcasecmp(attr->value, "true") ||
-       !strcasecmp(attr->value, "on") ||
-       !strcasecmp(attr->value, "yes"))) ||
-      (t && (!strcasecmp(t, "true") || !strcasecmp(t, "on") ||
-            !strcasecmp(t, "yes")))) {
+  if (((t = cupsGetOption("CenterOfPixel", num_options, options)) != NULL ||
+       (t = cupsGetOption("center-of-pixel", num_options, options)) != NULL) &&
+      (!strcasecmp(t, "true") || !strcasecmp(t, "on") ||
+       !strcasecmp(t, "yes"))) {
     if (log) log(ld, CF_LOGLEVEL_DEBUG,
                 "cfFilterGhostscript: Ghostscript using Center-of-Pixel method to "
                 "fill paths.");
index 26e084dda943f81d299507e6608060c0f8d29a70..14eb4a3e620aaae86bcb874a428bb6f6023a21b8 100644 (file)
@@ -29,6 +29,7 @@
 #include <cups/cups.h>
 #include <string.h>
 #include <ctype.h>
+#include <stdio.h>
 #define DEBUG_printf(x)
 #define DEBUG_puts(x)
 
index 93e32cd2b921d195765199d6dc3a3c01e27cca30..6a56b27b52599a15b87b56d38bb669d2b383f9fe 100644 (file)
@@ -19,7 +19,6 @@
  */
 
 #  include <cups/cups.h>
-#  include <ppd/ppd.h>
 #  include <cups/backend.h>
 #  include <cups/sidechannel.h>
 #  include <string.h>
index 63bbdd7b3944015a14c456755067e2772ff3d8bd..22a264d316c98dd5238cc817dd4251a80e9b6ae1 100644 (file)
@@ -21,8 +21,9 @@
 #include "config.h"
 #include <cupsfilters/filter.h>
 #include <cupsfilters/image.h>
-#include <cupsfilters/ppdgenerator.h>
+#include <cupsfilters/ipp.h>
 #include <cupsfilters/raster.h>
+#include <cupsfilters/ipp.h>
 #include <cupsfilters/image-private.h>
 #include <math.h>
 #include <ctype.h>
@@ -46,10 +47,9 @@ typedef struct imagetopdf_doc_s {       /**** Document information ****/
                Collate,                /* Collate copies? */
                Copies,                 /* Number of copies */
                Reverse,                /* Output order */
-               EvenDuplex;             /* cupsEvenDuplex */
+               EvenDuplex;             /* Duplex needs even number of pages? */
   int          Orientation,            /* 0 = portrait, 1 = landscape, etc. */
                Duplex,                 /* Duplexed? */
-               LanguageLevel,          /* Language level of printer */
                Color;                  /* Print in color? */
   float        PageLeft,               /* Left margin */
                PageRight,              /* Right margin */
@@ -88,7 +88,6 @@ typedef struct imagetopdf_doc_s {       /**** Document information ****/
   cf_ib_t      *row;                   /* Current row */
   float                gammaval;               /* Gamma correction value */
   float                brightness;             /* Gamma correction value */
-  ppd_file_t   *ppd;                   /* PPD file */
   char         linebuf[LINEBUFSIZE];
   FILE         *outputfp;
 } imagetopdf_doc_t;
@@ -97,7 +96,6 @@ typedef struct imagetopdf_doc_s {       /**** Document information ****/
  * Local functions...
  */
 
-static void    emit_jcl_options(imagetopdf_doc_t *doc, FILE *fp, int copies);
 #ifdef OUT_AS_HEX
 static void    out_hex(imagetopdf_doc_t *doc, cf_ib_t *, int, int);
 #else
@@ -122,64 +120,6 @@ static int out_page_object(imagetopdf_doc_t *doc, int pageObj,
 static int     out_page_contents(imagetopdf_doc_t *doc, int contentsObj);
 static int     out_image(imagetopdf_doc_t *doc, int imgObj);
 
-static void emit_jcl_options(imagetopdf_doc_t *doc, FILE *fp, int copies)
-{
-  int section;
-  ppd_choice_t **choices;
-  int i;
-  char buf[1024];
-  ppd_attr_t *attr;
-  int pdftopdfjcl = 0;
-  int datawritten = 0;
-
-  if (doc->ppd == 0) return;
-  if ((attr = ppdFindAttr(doc->ppd,"pdftopdfJCLBegin",NULL)) != NULL) {
-    int n = strlen(attr->value);
-    pdftopdfjcl = 1;
-    for (i = 0;i < n;i++) {
-       if (attr->value[i] == '\r' || attr->value[i] == '\n') {
-           /* skip new line */
-           continue;
-       }
-       fputc(attr->value[i],fp);
-       datawritten = 1;
-    }
-  }
-
-  snprintf(buf,sizeof(buf),"%d",copies);
-  if (ppdFindOption(doc->ppd,"Copies") != NULL) {
-    ppdMarkOption(doc->ppd,"Copies",buf);
-  } else {
-    if ((attr = ppdFindAttr(doc->ppd,"pdftopdfJCLCopies",buf)) != NULL) {
-      fputs(attr->value,fp);
-      datawritten = 1;
-    } else if (pdftopdfjcl) {
-      fprintf(fp,"Copies=%d;",copies);
-      datawritten = 1;
-    }
-  }
-  for (section = (int)PPD_ORDER_ANY;
-      section <= (int)PPD_ORDER_PROLOG;section++) {
-    int n;
-
-    n = ppdCollect(doc->ppd,(ppd_section_t)section,&choices);
-    for (i = 0;i < n;i++) {
-      snprintf(buf,sizeof(buf),"pdftopdfJCL%s",
-        ((ppd_option_t *)(choices[i]->option))->keyword);
-      if ((attr = ppdFindAttr(doc->ppd,buf,choices[i]->choice)) != NULL) {
-        fputs(attr->value,fp);
-       datawritten = 1;
-      } else if (pdftopdfjcl) {
-        fprintf(fp,"%s=%s;",
-          ((ppd_option_t *)(choices[i]->option))->keyword,
-          choices[i]->choice);
-       datawritten = 1;
-      }
-    }
-  }
-  if (datawritten) fputc('\n',fp);
-}
-
 static void set_offset(imagetopdf_doc_t *doc, int obj)
 {
   doc->objects[obj].offset = doc->currentOffset;
@@ -599,62 +539,6 @@ static int out_image(imagetopdf_doc_t *doc, int imgObj)
   return (0);
 }
 
-/*
- * Copied ppd_decode() from CUPS which is not exported to the API
- */
-
-static int                             /* O - Length of decoded string */
-ppd_decode(char *string)               /* I - String to decode */
-{
-  char *inptr,                         /* Input pointer */
-       *outptr;                        /* Output pointer */
-
-
-  inptr  = string;
-  outptr = string;
-
-  while (*inptr != '\0')
-    if (*inptr == '<' && isxdigit(inptr[1] & 255))
-    {
-     /*
-      * Convert hex to 8-bit values...
-      */
-
-      inptr ++;
-      while (isxdigit(*inptr & 255))
-      {
-       if (isalpha(*inptr))
-         *outptr = (tolower(*inptr) - 'a' + 10) << 4;
-       else
-         *outptr = (*inptr - '0') << 4;
-
-       inptr ++;
-
-        if (!isxdigit(*inptr & 255))
-         break;
-
-       if (isalpha(*inptr))
-         *outptr |= tolower(*inptr) - 'a' + 10;
-       else
-         *outptr |= *inptr - '0';
-
-       inptr ++;
-       outptr ++;
-      }
-
-      while (*inptr != '>' && *inptr != '\0')
-       inptr ++;
-      while (*inptr == '>')
-       inptr ++;
-    }
-    else
-      *outptr++ = *inptr++;
-
-  *outptr = '\0';
-
-  return ((int)(outptr - string));
-}
-
 /*
  * 'cfFilterImageToPDF()' - Filter function to convert many common image file
  *                  formats into PDF
@@ -670,15 +554,13 @@ cfFilterImageToPDF(int inputfd,         /* I - File descriptor input stream */
   imagetopdf_doc_t     doc;            /* Document information */
   cups_page_header2_t h;                /* CUPS Raster page header, to */
                                         /* accommodate results of command */
-                                        /* line parsing for PPD-less queue */
-  ppd_choice_t *choice;                /* PPD option choice */
-  int          num_options = 0;                /* Number of print options */
-  cups_option_t        *options = NULL;                /* Print options */
+                                        /* line and IPP parsing */
+  int          num_options = 0;        /* Number of print options */
+  cups_option_t        *options = NULL;        /* Print options */
   const char   *val;                   /* Option value */
   float                zoom;                   /* Zoom facter */
   int          xppi, yppi;             /* Pixels-per-inch */
   int          hue, sat;               /* Hue and saturation adjustment */
-  int          emit_jcl;
   int           pdf_printer = 0;
   char         tempfile[1024];         /* Name of file to print */
   FILE          *fp;                   /* Input file */
@@ -688,7 +570,6 @@ cfFilterImageToPDF(int inputfd,         /* I - File descriptor input stream */
   int          deviceCopies = 1;
   int          deviceCollate = 0;
   int          deviceReverse = 0;
-  ppd_attr_t   *attr;
   int          pl, pr;
   int          fillprint = 0;          /* print-scaling = fill */
   int          cropfit = 0;            /* -o crop-to-fit = true */
@@ -699,14 +580,15 @@ cfFilterImageToPDF(int inputfd,         /* I - File descriptor input stream */
   ipp_t *printer_attrs = data->printer_attrs;
   ipp_t *job_attrs = data->job_attrs;
   ipp_attribute_t *ipp;
-  int                  min_length = __INT32_MAX__,       /*  ppd->custom_min[1]        */
-                       min_width = __INT32_MAX__,        /*  ppd->custom_min[0]        */
-                       max_length = 0,                   /*  ppd->custom_max[1]        */
-                       max_width=0;                      /*  ppd->custom_max[0]        */
-  float                customLeft = 0.0,               /*  ppd->custom_margin[0]  */
-                       customBottom = 0.0,             /*  ppd->custom_margin[1]  */
-                       customRight = 0.0,              /*  ppd->custom_margin[2]  */
-                       customTop = 0.0;                /*  ppd->custom_margin[3]  */
+  cups_cspace_t cspace = (cups_cspace_t)(-1);
+  int                  min_length = __INT32_MAX__,
+                       min_width = __INT32_MAX__,
+                       max_length = 0,
+                       max_width = 0;
+  float                customLeft = 0.0,
+                       customBottom = 0.0,
+                       customRight = 0.0,
+                       customTop = 0.0;
   char                         defSize[41];
 
 
@@ -835,14 +717,15 @@ cfFilterImageToPDF(int inputfd,         /* I - File descriptor input stream */
   */
 
   if (printer_attrs != NULL) {
-    int left, right, top, bottom;
-    cfGenerateSizes(printer_attrs, &ipp, &min_length, &min_width,
-                   &max_length, &max_width, &bottom, &left, &right, &top,
-                   defSize);
+    int left, bottom, right, top;
+    cfGenerateSizes(printer_attrs, CF_GEN_SIZES_DEFAULT, NULL, &ipp,
+                   NULL, NULL, NULL, NULL, NULL, NULL,
+                   &min_width, &min_length, &max_width, &max_length,
+                   &left, &bottom, &right, &top, defSize, NULL);
     customLeft = left*72.0/2540.0;
+    customBottom = bottom*72.0/2540.0;
     customRight = right*72.0/2540.0;
     customTop = top*72.0/2540.0;
-    customBottom = bottom*72.0/2540.0;
   }
 
 
@@ -850,202 +733,78 @@ cfFilterImageToPDF(int inputfd,         /* I - File descriptor input stream */
   * Process job options...
   */
 
-  doc.ppd = data->ppd;
-  cfFilterSetCommonOptions(doc.ppd, num_options, options, 0,
-                        &doc.Orientation, &doc.Duplex,
-                        &doc.LanguageLevel, &doc.Color,
-                        &doc.PageLeft, &doc.PageRight,
-                        &doc.PageTop, &doc.PageBottom,
-                        &doc.PageWidth, &doc.PageLength,
-                        log, ld);
-
-  /* The cfFilterSetCommonOptions() does not set doc.Color
-     according to option settings (user's demand for color/gray),
-     so we parse the options and set the mode here */
-  cfRasterParseIPPOptions(&h, data, 0, 1);
-  if (doc.Color)
-    doc.Color = h.cupsNumColors <= 1 ? 0 : 1;
-  if (!doc.ppd) {
-    /* Without PPD use also the other findings of cfRasterParseIPPOptions() */
-    doc.Orientation = h.Orientation;
-    doc.Duplex = h.Duplex;
-    doc.PageWidth = h.cupsPageSize[0] != 0.0 ? h.cupsPageSize[0] :
-      (float)h.PageSize[0];
-    doc.PageLength = h.cupsPageSize[1] != 0.0 ? h.cupsPageSize[1] :
-      (float)h.PageSize[1];
-    doc.PageLeft = h.cupsImagingBBox[0] != 0.0 ? h.cupsImagingBBox[0] :
-      (float)h.ImagingBoundingBox[0];
-    doc.PageBottom = h.cupsImagingBBox[1] != 0.0 ? h.cupsImagingBBox[1] :
-      (float)h.ImagingBoundingBox[1];
-    doc.PageRight = h.cupsImagingBBox[2] != 0.0 ? h.cupsImagingBBox[2] :
-      (float)h.ImagingBoundingBox[2];
-    doc.PageTop = h.cupsImagingBBox[3] != 0.0 ? h.cupsImagingBBox[3] :
-      (float)h.ImagingBoundingBox[3];
-    doc.Flip = h.MirrorPrint ? 1 : 0;
-    doc.Collate = h.Collate ? 1 : 0;
-    doc.Copies = h.NumCopies;
-  }
+  /* To find the correct output color space, resolution page size, ...
+     and to parse all releveant command line options we run 
+     cfRasterPrepareHeader() here and afterwards we simply take the
+     needed parameters from the header. */
+  cfRasterPrepareHeader(&h, data, CF_FILTER_OUT_FORMAT_CUPS_RASTER,
+                       CF_FILTER_OUT_FORMAT_CUPS_RASTER, 0, &cspace);
+  doc.Color = h.cupsNumColors <= 1 ? 0 : 1;
+  doc.Orientation = h.Orientation;
+  doc.Duplex = h.Duplex;
+  doc.PageWidth = h.cupsPageSize[0] != 0.0 ? h.cupsPageSize[0] :
+    (float)h.PageSize[0];
+  doc.PageLength = h.cupsPageSize[1] != 0.0 ? h.cupsPageSize[1] :
+    (float)h.PageSize[1];
+  doc.PageLeft = h.cupsImagingBBox[0] != 0.0 ? h.cupsImagingBBox[0] :
+    (float)h.ImagingBoundingBox[0];
+  doc.PageBottom = h.cupsImagingBBox[1] != 0.0 ? h.cupsImagingBBox[1] :
+    (float)h.ImagingBoundingBox[1];
+  doc.PageRight = h.cupsImagingBBox[2] != 0.0 ? h.cupsImagingBBox[2] :
+    (float)h.ImagingBoundingBox[2];
+  doc.PageTop = h.cupsImagingBBox[3] != 0.0 ? h.cupsImagingBBox[3] :
+    (float)h.ImagingBoundingBox[3];
+  doc.Flip = h.MirrorPrint ? 1 : 0;
+  doc.Collate = h.Collate ? 1 : 0;
+  doc.Copies = data->copies;
 
-  if (doc.Copies == 1
-      && (choice = ppdFindMarkedChoice(doc.ppd,"Copies")) != NULL) {
-    doc.Copies = atoi(choice->choice);
-  }
   if (doc.Copies == 0) doc.Copies = 1;
-  if ((val = cupsGetOption("Duplex",num_options,options)) != 0 &&
-      (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
-       !strcasecmp(val, "yes"))) {
-      /* for compatiblity */
-      if (ppdFindOption(doc.ppd,"Duplex") != NULL) {
-        ppdMarkOption(doc.ppd,"Duplex","True");
-        ppdMarkOption(doc.ppd,"Duplex","On");
-        doc.Duplex = 1;
-      }
-  } else if ((val = cupsGetOption("sides",num_options,options)) != 0 &&
-      (!strcasecmp(val, "two-sided-long-edge") ||
-       !strcasecmp(val, "two-sided-short-edge"))) {
-      /* for compatiblity */
-      if (ppdFindOption(doc.ppd,"Duplex") != NULL) {
-        ppdMarkOption(doc.ppd,"Duplex","True");
-        ppdMarkOption(doc.ppd,"Duplex","On");
-        doc.Duplex = 1;
-      }
-  }
 
-  if ((val = cupsGetOption("OutputOrder",num_options,options)) != 0    ||
-       (val = cupsGetOption("outputorder", num_options, options))!=NULL) {
-    if (!strcasecmp(val, "Reverse")) {
-      doc.Reverse = 1;
-    }
-  } else if (doc.ppd) {
-   /*
-    * Figure out the right default output order from the PPD file...
-    */
-
-    if ((choice = ppdFindMarkedChoice(doc.ppd,"OutputOrder")) != 0) {
-      doc.Reverse = !strcasecmp(choice->choice,"Reverse");
-    } else if ((choice = ppdFindMarkedChoice(doc.ppd,"OutputBin")) != 0 &&
-        (attr = ppdFindAttr(doc.ppd,"PageStackOrder",choice->choice)) != 0 &&
-        attr->value) {
-      doc.Reverse = !strcasecmp(attr->value,"Reverse");
-    } else if ((attr = ppdFindAttr(doc.ppd,"DefaultOutputOrder",0)) != 0 &&
-             attr->value) {
-      doc.Reverse = !strcasecmp(attr->value,"Reverse");
-    }
+  /* Do we need to print the pages in reverse order? */
+  if ((val = cupsGetOption("OutputOrder", num_options, options)) != NULL ||
+      (val = cupsGetOption("output-order", num_options, options)) != NULL ||
+      (val = cupsGetOption("page-delivery", num_options, options)) != NULL)
+  {
+    doc.Reverse = (strcasecmp(val, "Reverse") == 0 ||
+                  strcasecmp(val, "reverse-order") == 0);
   }
-    else if(printer_attrs){
-       /*      If PPD file is NULL, we use printer attrs to determine if we need to print in reverse order */
-       char *defaultoutbin = strdup("");
-       const char* outbin;
-       if ((ipp = ippFindAttribute(printer_attrs, "output-bin-default", IPP_TAG_ZERO))
-       != NULL)
-               defaultoutbin = strdup(ippGetString(ipp, 0, NULL));
-       /* Find out on which position of the list of output bins the default one is,
-       if there is no default bin, take the first of this list */
-       int i = 0;
-       if ((ipp = ippFindAttribute(printer_attrs, "output-bin-supported",
-                               IPP_TAG_ZERO)) != NULL) {
-           int count = ippGetCount(ipp);
-               for (i = 0; i < count; i ++) {
-                   outbin = ippGetString(ipp, i, NULL);
-                       if (outbin == NULL)
-                           continue;
-                       if (defaultoutbin == NULL) {
-                           defaultoutbin = strdup(outbin);
-                           break;
-                       } else if (strcasecmp(outbin, defaultoutbin) == 0)
-                       break;
-               }
-       }
-       void *outbin_properties_octet;
-       int octet_str_len;
-       char outbin_properties[1024];
-       int outputorderinfofound = 0;
-       int faceupdown = 0;
-       int firsttolast = 0;
-       if ((ipp = ippFindAttribute(printer_attrs, "printer-output-tray",
-               IPP_TAG_STRING)) != NULL &&
-                       i < ippGetCount(ipp)) {
-           outbin_properties_octet = ippGetOctetString(ipp, i, &octet_str_len);
-           memset(outbin_properties, 0, sizeof(outbin_properties));
-           memcpy(outbin_properties, outbin_properties_octet,
-               ((size_t)octet_str_len < sizeof(outbin_properties) - 1 ?
-               (size_t)octet_str_len : sizeof(outbin_properties) - 1));
-               if (strcasestr(outbin_properties, "pagedelivery=faceUp")) {
-                   outputorderinfofound = 1;
-                   faceupdown = -1;
-               }
-               if (strcasestr(outbin_properties, "stackingorder=lastToFirst"))
-               firsttolast = -1;
-       }
-       if (outputorderinfofound == 0 && defaultoutbin &&
-       strcasestr(defaultoutbin, "face-up"))
-           faceupdown = -1;
-       if (defaultoutbin)
-           free (defaultoutbin);
-       if (firsttolast * faceupdown < 0)
-           doc.Reverse = 1;;
-    }
+  else
+    doc.Reverse = cfIPPReverseOutput(printer_attrs, job_attrs);
 
   /* adjust to even page when duplex */
-  if (((val = cupsGetOption("cupsEvenDuplex",num_options,options)) != 0 &&
-             (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
-               !strcasecmp(val, "yes"))) ||
-         ((attr = ppdFindAttr(doc.ppd,"cupsEvenDuplex",0)) != 0 &&
-             (!strcasecmp(attr->value, "true")
-               || !strcasecmp(attr->value, "on") ||
-               !strcasecmp(attr->value, "yes")))) {
+  if ((val = cupsGetOption("even-duplex", num_options, options)) != 0 &&
+      (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
+       !strcasecmp(val, "yes")))
     doc.EvenDuplex = 1;
-  }
 
-  if ((val = cupsGetOption("multiple-document-handling",
-                          num_options, options)) != NULL)
-  {
+  // Collate
+  if ((val = cupsGetOption("Collate", num_options, options)) != NULL &&
+      (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
+       !strcasecmp(val, "yes")))
+    doc.Collate = 1;
+  else if ((val = cupsGetOption("sheet-collate", num_options, options)) != NULL)
+    doc.Collate = (strcasecmp(val, "uncollated") != 0);
+  else if (((val = cupsGetOption("multiple-document-handling",
+                                num_options, options)) != NULL &&
+           (strcasecmp(val, "separate-documents-collated-copies") == 0 ||
+            strcasecmp(val, "separate-documents-uncollated-copies") == 0 ||
+            strcasecmp(val, "single-document") == 0 ||
+            strcasecmp(val, "single-document-new-sheet") == 0)) ||
+          (val = cfIPPAttrEnumValForPrinter(printer_attrs, job_attrs,
+                                            "multiple-document-handling")) !=
+          NULL)
    /*
-    * This IPP attribute is unnecessarily complicated...
+    * This IPP attribute is unnecessarily complicated:
     *
-    *   single-document, separate-documents-collated-copies, and
-    *   single-document-new-sheet all require collated copies.
+    *   single-document, separate-documents-collated-copies,
+    *   single-document-new-sheet:
+    *      -> collate (true)
     *
-    *   separate-documents-uncollated-copies allows for uncollated copies.
+    *   separate-documents-uncollated-copies:
+    *      -> can be uncollated (false)
     */
-
-    doc.Collate = strcasecmp(val, "separate-documents-uncollated-copies") != 0;
-  }
-
-  if ((val = cupsGetOption("Collate", num_options, options)) != NULL  ||
-       (val = cupsGetOption("collate", num_options, options))) {
-    if (strcasecmp(val, "True") == 0) {
-      doc.Collate = 1;
-    }
-  } else {
-    if ((choice = ppdFindMarkedChoice(doc.ppd,"Collate")) != NULL
-      && (!strcasecmp(choice->choice,"true")
-        || !strcasecmp(choice->choice, "on")
-       || !strcasecmp(choice->choice, "yes"))) {
-      doc.Collate = 1;
-    }
-    else if((ipp = ippFindAttribute(printer_attrs, "multiple-document-handling-default", 
-               IPP_TAG_ZERO))!=NULL){
-       ippAttributeString(ipp, buf, sizeof(buf));
-       val = buf;
-       doc.Collate = strcasecmp(val, "separate-documents-uncollated-copies") != 0;
-    }
-    /* Still if we are having no clue about collate, pick any random value(1st in this case)
-       from supported options  */
-    else if((ipp = ippFindAttribute(printer_attrs, "multiple-document-handling-supported", 
-                       IPP_TAG_ZERO))!=NULL){
-       ippAttributeString(ipp, buf, sizeof(buf));
-       int i=0;
-       for(i=0; buf[i]!='\0';i++){
-           if(buf[i]==' ' || buf[i]==','){
-               buf[i] = '\0';
-               break;
-           }
-       }
-       val = buf;
-       doc.Collate = strcasecmp(val, "separate-documents-uncollated-copies") != 0;
-    }
-  }
+    doc.Collate =
+      (strcasecmp(val, "separate-documents-uncollated-copies") != 0);
 
   if ((val = cupsGetOption("gamma", num_options, options)) != NULL)
       doc.gammaval = atoi(val) * 0.001f;
@@ -1119,14 +878,6 @@ cfFilterImageToPDF(int inputfd,         /* I - File descriptor input stream */
       strcasecmp(val, "True") == 0)
     doc.Flip = 1;
 
-  if ((val = cupsGetOption("emit-jcl", num_options, options)) != NULL &&
-      (!strcasecmp(val, "false") || !strcasecmp(val, "off") ||
-       !strcasecmp(val, "no") || !strcmp(val, "0")))
-    emit_jcl = 0;
-  else
-    emit_jcl = 1;
-
-
 
  /*
   * Open the input image to print...
@@ -1142,13 +893,9 @@ cfFilterImageToPDF(int inputfd,         /* I - File descriptor input stream */
   int fidelity = 0;
   int document_large = 0;
 
-  if (doc.ppd && (doc.ppd->custom_margins[0] || doc.ppd->custom_margins[1] ||
-                 doc.ppd->custom_margins[2] || doc.ppd->custom_margins[3]))
-                                            // In case of custom margins
-    margin_defined = 1;
-  else if(customBottom!=0 || customLeft!=0 || customRight!=0 || customTop!=0)
-       margin_defined = 1;
-  if (doc.PageLength != doc.PageTop - doc.PageBottom ||
+  if (customLeft != 0 || customRight != 0 ||
+      customBottom != 0 || customTop != 0 ||
+      doc.PageLength != doc.PageTop - doc.PageBottom ||
       doc.PageWidth != doc.PageRight - doc.PageLeft)
     margin_defined = 1;
 
@@ -1567,29 +1314,13 @@ cfFilterImageToPDF(int inputfd,         /* I - File descriptor input stream */
   * Update the page size for custom sizes...
   */
 
-  /* If size if specified by user, use it, else default size from
-     printer_attrs*/
-  if ((ipp = ippFindAttribute(job_attrs, "media-size", IPP_TAG_ZERO)) != NULL ||
-      (val = cupsGetOption("MediaSize", num_options, options)) != NULL ||
-      (ipp = ippFindAttribute(job_attrs, "page-size", IPP_TAG_ZERO)) != NULL ||
-      (val = cupsGetOption("PageSize", num_options, options)) != NULL ) {
-    if (val == NULL) {
-      ippAttributeString(ipp, buf, sizeof(buf));
-      strcpy(defSize, buf);
-    }
-    else
-       snprintf(defSize, sizeof(defSize), "%s", val);
-  }
-
-
+  strcpy(defSize, h.cupsPageSizeName);
 
-  if (((choice = ppdFindMarkedChoice(doc.ppd, "PageSize")) != NULL &&
-      strcasecmp(choice->choice, "Custom") == 0) ||
-       strncasecmp(defSize, "custom", 6)==0)
+  if ((strncasecmp(defSize, "Custom", 6)) == 0 ||
+      strcasestr(defSize, "_custom_"))
   {
     float      width,          /* New width in points */
                length;         /* New length in points */
-    char       s[255];         /* New custom page size... */
 
 
    /*
@@ -1610,31 +1341,18 @@ cfFilterImageToPDF(int inputfd,         /* I - File descriptor input stream */
    /*
     * Add margins to page size...
     */
-    if(doc.ppd!=NULL){
-       width  += doc.ppd->custom_margins[0] + doc.ppd->custom_margins[2];
-       length += doc.ppd->custom_margins[1] + doc.ppd->custom_margins[3];
-    }
-    else{
-       width += customLeft + customRight;
-       length += customTop + customBottom;
-    }
+
+    width += customLeft + customRight;
+    length += customTop + customBottom;
+
    /*
     * Enforce minimums...
     */
 
-    if(doc.ppd!=NULL)
-    {
-       if(width<doc.ppd->custom_min[0])
-         width = doc.ppd->custom_min[0];
-       if(length<doc.ppd->custom_min[1])
-         length = doc.ppd->custom_min[1];
-    }
-    else{
-       if(width<min_width)
-         width = min_width;
-       if(length<min_length)
-         length = min_length;
-    }
+    if (width < min_width)
+      width = min_width;
+    if (length < min_length)
+      length = min_length;
 
     if (log) log(ld, CF_LOGLEVEL_DEBUG,
                 "cfFilterImageToPDF: Updated custom page size to %.2f x %.2f "
@@ -1645,8 +1363,12 @@ cfFilterImageToPDF(int inputfd,         /* I - File descriptor input stream */
     * Set the new custom size...
     */
 
-    sprintf(s, "Custom.%.0fx%.0f", width, length);
-    ppdMarkOption(doc.ppd, "PageSize", s);
+    strcpy(h.cupsPageSizeName, "Custom");
+
+    h.cupsPageSize[0] = width + 0.5;
+    h.cupsPageSize[1] = length + 0.5;
+    h.PageSize[0]     = width + 0.5;
+    h.PageSize[1]     = length + 0.5;
 
    /*
     * Update page variables...
@@ -1654,96 +1376,101 @@ cfFilterImageToPDF(int inputfd,         /* I - File descriptor input stream */
 
     doc.PageWidth  = width;
     doc.PageLength = length;
-    if (doc.ppd != NULL)
-      doc.PageLeft   = doc.ppd->custom_margins[0];
-    else
-      doc.PageLeft = customLeft;
-    if (doc.ppd != NULL)
-      doc.PageRight  = width - doc.ppd->custom_margins[2];
-    else
-      doc.PageRight = width - customRight;
-    if (doc.ppd != NULL)
-      doc.PageBottom = doc.ppd->custom_margins[1];
-    else
-      doc.PageBottom = customBottom;
-    if (doc.ppd != NULL)
-      doc.PageTop    = length - doc.ppd->custom_margins[3];
-    else
-      doc.PageTop = length - customTop;
+    doc.PageLeft = customLeft;
+    doc.PageRight = width - customRight;
+    doc.PageBottom = customBottom;
+    doc.PageTop = length - customTop;
   }
 
   if (doc.Copies == 1) {
     /* collate is not needed */
     doc.Collate = 0;
-    ppdMarkOption(doc.ppd,"Collate","False");
   }
+
   if (!doc.Duplex) {
     /* evenDuplex is not needed */
     doc.EvenDuplex = 0;
   }
 
-  /* check collate device */
-  if (doc.Collate) {
-    if ((choice = ppdFindMarkedChoice(doc.ppd,"Collate")) != NULL &&
-       !strcasecmp(choice->choice,"true")) {
-      ppd_option_t *opt;
-
-      if ((opt = ppdFindOption(doc.ppd,"Collate")) != NULL &&
-        !opt->conflicted) {
-        deviceCollate = 1;
-      } else {
-        ppdMarkOption(doc.ppd,"Collate","False");
-      }
+  // Check options for caller's instructions about hardware copies/collate
+  if ((val = cupsGetOption("hardware-copies",
+                          num_options, options)) != NULL)
+  {
+    if (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
+       !strcasecmp(val, "yes"))
+    {
+      // Use hardware copies according to the caller's instructions
+      deviceCopies = doc.Copies;
+      doc.Copies = 1;
     }
   }
-  /* check OutputOrder device */
-  if (doc.Reverse) {
-    if (ppdFindOption(doc.ppd,"OutputOrder") != NULL) {
-      deviceReverse = 1;
-    }
+  else if (data->final_content_type &&
+          (strcasestr(data->final_content_type, "/pdf") ||
+           strcasestr(data->final_content_type, "/vnd.cups-pdf")))
+  {
+    // Caller did not tell us whether the printer does Hardware copies
+    // or not, so we assume hardware copies on PDF printers, and software
+    // copies on other (usually raster) printers or if we do not know the
+    // final output format.
+    deviceCopies = doc.Copies;
+    doc.Copies = 1;
   }
-  if (doc.ppd != NULL &&
-       !doc.ppd->manual_copies && doc.Collate && !deviceCollate) {
+
+  if (deviceCopies > 1 && doc.Collate)
+  {
+    if ((val = cupsGetOption("hardware-collate",
+                           num_options, options)) != NULL)
+    {
+      // Use hardware collate according to the caller's instructions
+      if (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
+         !strcasecmp(val, "yes"))
+       deviceCollate = 1;
+    }
+    else
+      // Check output format MIME type whether it is
+      // of a driverless IPP printer (PDF, Apple Raster, PWG Raster, PCLm).
+      // These printers do always hardware collate if they do hardware copies.
+      // https://github.com/apple/cups/issues/5433
+      deviceCollate = (data->final_content_type &&
+                      (strcasestr(data->final_content_type, "/pdf") ||
+                       strcasestr(data->final_content_type, "/vnd.cups-pdf") ||
+                       strcasestr(data->final_content_type, "/pwg-raster") ||
+                       strcasestr(data->final_content_type, "/urf") ||
+                       strcasestr(data->final_content_type, "/PCLm")));
+  }
+
+  if (deviceCopies && doc.Collate && !deviceCollate)
+  {
     /* Copying by device , software collate is impossible */
     /* Enable software copying */
-    doc.ppd->manual_copies = 1;
+    doc.Copies = deviceCopies;
+    deviceCopies = 1;
   }
-  if (doc.Copies > 1 && (doc.ppd == NULL || doc.ppd->manual_copies)
-      && doc.Duplex) {
-    /* Enable software collate , or same pages are printed in both sides */
-      doc.Collate = 1;
-      if (deviceCollate) {
-        deviceCollate = 0;
-        ppdMarkOption(doc.ppd,"Collate","False");
-      }
+
+  if (doc.Copies > 1 && deviceCopies == 1 && doc.Duplex)
+  {
+    /* Enable software collate, or same pages are printed in both sides */
+    doc.Collate = 1;
+    if (deviceCollate)
+      deviceCollate = 0;
   }
-  if (doc.Duplex && doc.Collate && !deviceCollate) {
-    /* Enable evenDuplex or the first page may be printed other side of the
-      end of precedings */
+
+  if (doc.Duplex && doc.Collate && !deviceCollate)
+    /* Enable evenDuplex or the first page of the second copy may be
+      printed on the back side of the end of the first copy */
     doc.EvenDuplex = 1;
-  }
-  if (doc.Duplex && doc.Reverse && !deviceReverse) {
+
+  if (doc.Duplex && doc.Reverse && !deviceReverse)
     /* Enable evenDuplex or the first page may be empty. */
     doc.EvenDuplex = 1;
-  }
+
   /* change feature for software */
-  if (deviceCollate) {
+  if (deviceCollate)
     doc.Collate = 0;
-  }
+
   if (deviceReverse) {
     doc.Reverse = 0;
   }
-  if (doc.ppd != NULL) {
-    if (doc.ppd->manual_copies) {
-      /* sure disable hardware copying */
-      ppdMarkOption(doc.ppd,"Copies","1");
-      ppdMarkOption(doc.ppd,"JCLCopies","1");
-    } else {
-      /* change for hardware copying */
-      deviceCopies = doc.Copies;
-      doc.Copies = 1;
-    }
-  }
 
  /*
   * See if we need to collate, and if so how we need to do it...
@@ -1754,7 +1481,6 @@ cfFilterImageToPDF(int inputfd,         /* I - File descriptor input stream */
     /* collate is not needed, disable it */
     deviceCollate = 0;
     doc.Collate = 0;
-    ppdMarkOption(doc.ppd,"Collate","False");
   }
 
   if (((doc.xpages*doc.ypages) % 2) == 0) {
@@ -1762,71 +1488,6 @@ cfFilterImageToPDF(int inputfd,         /* I - File descriptor input stream */
     doc.EvenDuplex = 0;
   }
 
- /*
-  * Write any "exit server" options that have been selected...
-  */
-
-  ppdEmit(doc.ppd, doc.outputfp, PPD_ORDER_EXIT);
-
- /*
-  * Write any JCL commands that are needed to print PostScript code...
-  */
-
-  if (doc.ppd && emit_jcl) {
-    /* pdftopdf only adds JCL to the job if the printer is a native PDF
-       printer and the PPD is for this mode, having the "*JCLToPDFInterpreter:"
-       keyword. We need to read this keyword manually from the PPD and replace
-       the content of ppd->jcl_ps by the value of this keyword, so that
-       ppdEmitJCL() actalually adds JCL based on the presence on
-       "*JCLToPDFInterpreter:". */
-    ppd_attr_t *attr;
-    char buf[1024];
-    int devicecopies_done = 0;
-    char *old_jcl_ps = doc.ppd->jcl_ps;
-    /* If there is a "Copies" option in the PPD file, assure that hardware
-       copies are implemented as described by this option */
-    if (ppdFindOption(doc.ppd,"Copies") != NULL && deviceCopies > 1)
-    {
-      snprintf(buf,sizeof(buf),"%d",deviceCopies);
-      ppdMarkOption(doc.ppd,"Copies",buf);
-      devicecopies_done = 1;
-    }
-    if ((attr = ppdFindAttr(doc.ppd,"JCLToPDFInterpreter",NULL)) != NULL)
-    {
-      if (deviceCopies > 1 && devicecopies_done == 0 && /* HW copies */
-         strncmp(doc.ppd->jcl_begin, "\033%-12345X@", 10) == 0) /* PJL */
-      {
-       /* Add a PJL command to implement the hardware copies */
-        const size_t size = strlen(attr->value) + 1 + 30;
-        doc.ppd->jcl_ps = (char *)malloc(size * sizeof(char));
-        if (deviceCollate)
-       {
-          snprintf(doc.ppd->jcl_ps, size, "@PJL SET QTY=%d\n%s",
-                   deviceCopies, attr->value);
-        }
-       else
-       {
-          snprintf(doc.ppd->jcl_ps, size, "@PJL SET COPIES=%d\n%s",
-                   deviceCopies, attr->value);
-        }
-      }
-      else
-       doc.ppd->jcl_ps = strdup(attr->value);
-      ppd_decode(doc.ppd->jcl_ps);
-      pdf_printer = 1;
-    }
-    else
-    {
-      doc.ppd->jcl_ps = NULL;
-      pdf_printer = 0;
-    }
-    ppdEmitJCL(doc.ppd, doc.outputfp, data->job_id, data->job_user,
-              data->job_title);
-    emit_jcl_options(&doc, doc.outputfp, deviceCopies);
-    free(doc.ppd->jcl_ps);
-    doc.ppd->jcl_ps = old_jcl_ps; /* cups uses pool allocator, not free() */
-  }
-
  /*
   * Start sending the document with any commands needed...
   */
@@ -2135,12 +1796,6 @@ cfFilterImageToPDF(int inputfd,         /* I - File descriptor input stream */
   * Close files...
   */
 
-  if (emit_jcl)
-  {
-    if (doc.ppd && doc.ppd->jcl_end)
-      ppdEmitJCLEnd(doc.ppd, doc.outputfp);
-  }
-
   cfImageClose(doc.img);
   fclose(doc.outputfp);
   close(outputfd);
index 0d2109a0f9124afdf779a82cc22c0a4b69c3466e..66f8079239bb51025a5cf027d0fa5e34ec3051a5 100644 (file)
@@ -33,7 +33,7 @@
 #include <cupsfilters/filter.h>
 #include <cupsfilters/raster.h>
 #include <cupsfilters/colormanager.h>
-#include <cupsfilters/ppdgenerator.h>
+#include <cupsfilters/ipp.h>
 #include <cupsfilters/image-private.h>
 #include <unistd.h>
 #include <math.h>
@@ -53,7 +53,6 @@ typedef struct {                /**** Document information ****/
        Copies;                 /* Number of copies */
   int   Orientation,           /* 0 = portrait, 1 = landscape, etc. */
         Duplex,                /* Duplexed? */
-        LanguageLevel,         /* Language level of printer */
         Color;                 /* Print in color? */
   float PageLeft,              /* Left margin */
         PageRight,             /* Right margin */
@@ -208,13 +207,8 @@ cfFilterImageToRaster(int inputfd,         /* I - File descriptor input stream *
   int                  xc0, yc0,       /* Corners of the page in image
                                           coords */
                        xc1, yc1;
-  ppd_file_t           *ppd;           /* PPD file */
-  ppd_choice_t         *choice;        /* PPD option choice */
   cups_cspace_t         cspace = -1;    /* CUPS color space */
-  char                 *resolution,    /* Output resolution */
-                       *media_type;    /* Media type */
-  ppd_profile_t                *profile;       /* Color profile */
-  ppd_profile_t                userprofile;    /* User-specified profile */
+  char                 *media_type;    /* Media type */
   cups_raster_t                *ras;           /* Raster stream */
   cups_page_header2_t  header;         /* Page header */
   int                  num_options = 0;        /* Number of print options */
@@ -247,9 +241,9 @@ cfFilterImageToRaster(int inputfd,         /* I - File descriptor input stream *
   int                   fd;            /* File descriptor for temp file */
   char                  buf[BUFSIZ];
   int                   bytes;
-  cf_cm_calibration_t      cm_calibrate;   /* Are we color calibrating the
+  cf_cm_calibration_t   cm_calibrate;   /* Are we color calibrating the
                                           device? */
-  int                   cm_disabled;    /* Color management disabled? */
+  int                   cm_disabled = 0;/* Color management disabled? */
   int                   fillprint = 0; /* print-scaling = fill */
   int                   cropfit = 0;   /* -o crop-to-fit */
   cf_logfunc_t      log = data->logfunc;
@@ -259,36 +253,35 @@ cfFilterImageToRaster(int inputfd,         /* I - File descriptor input stream *
   ipp_t                 *printer_attrs = data->printer_attrs;
   ipp_t                 *job_attrs = data->job_attrs;
   ipp_attribute_t *ipp;
-  int                  min_length = __INT32_MAX__,       /*  ppd->custom_min[1]        */
-                       min_width = __INT32_MAX__,        /*  ppd->custom_min[0]        */
-                       max_length = 0,                   /*  ppd->custom_max[1]        */
-                       max_width=0;                    /*  ppd->custom_max[0]  */
-  float                customLeft = 0.0,               /*  ppd->custom_margin[0]  */
-                       customBottom = 0.0,             /*  ppd->custom_margin[1]  */
-                       customRight = 0.0,              /*  ppd->custom_margin[2]  */
-                       customTop = 0.0;                /*  ppd->custom_margin[3]  */
+  int                  min_length = __INT32_MAX__,
+                       min_width = __INT32_MAX__;
+  float                customLeft = 0.0,
+                       customBottom = 0.0,
+                       customRight = 0.0,
+                       customTop = 0.0;
   char                         defSize[41];
   cf_filter_out_format_t   outformat;
 
   /* Note: With the CF_FILTER_OUT_FORMAT_APPLE_RASTER,
-     CF_FILTER_OUT_FORMAT_PWG_RASTER, or CF_FILTER_OUT_FORMAT_PCLM selections the
-     output is actually CUPS Raster but information about available
-     color spaces and depths are taken from the urf-supported or
-     pwg-raster-document-type-supported printer IPP attributes or
-     appropriate PPD file attributes (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 and PWG Raster output support to this filter. */
-
-  if (parameters) {
-    outformat = *(cf_filter_out_format_t *)parameters;
-    if (outformat != CF_FILTER_OUT_FORMAT_PCLM &&
-       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_CUPS_RASTER;
-  } else
-    outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
+     CF_FILTER_OUT_FORMAT_PWG_RASTER, or CF_FILTER_OUT_FORMAT_PCLM
+     selections the output is actually CUPS Raster but information
+     about available color spaces and depths are taken from the
+     urf-supported or pwg-raster-document-type-supported printer IPP
+     attributes (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 and PWG Raster
+     output support to this filter. */
+
+  outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
+  val = data->final_content_type;
+  if (val) {
+    if (strcasestr(val, "pwg"))
+      outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
+    else if (strcasestr(val, "urf"))
+      outformat = CF_FILTER_OUT_FORMAT_APPLE_RASTER;
+    else if (strcasestr(val, "pclm"))
+      outformat = CF_FILTER_OUT_FORMAT_PCLM;
+  }
 
   if (log) log(ld, CF_LOGLEVEL_DEBUG,
               "cfFilterImageToRaster: Final output format: %s",
@@ -297,17 +290,6 @@ cfFilterImageToRaster(int inputfd,         /* I - File descriptor input stream *
                 (outformat == CF_FILTER_OUT_FORMAT_APPLE_RASTER ? "Apple Raster" :
                  "PCLm"))));
 
-  if (printer_attrs != NULL) {
-    int left, right, top, bottom;
-    cfGenerateSizes(printer_attrs, &ipp, &min_length, &min_width,
-                   &max_length, &max_width, &bottom, &left, &right, &top,
-                   defSize);
-    customLeft = left*72.0/2540.0;
-    customRight = right*72.0/2540.0;
-    customTop = top*72.0/2540.0;
-    customBottom = bottom*72.0/2540.0;
-  }
-
  /*
   * Make sure status messages are not buffered...
   */
@@ -320,6 +302,22 @@ cfFilterImageToRaster(int inputfd,         /* I - File descriptor input stream *
 
   signal(SIGPIPE, SIG_IGN);
 
+  if (printer_attrs != NULL) {
+    int minw, minl, maxw, maxl;
+    int left, bottom, right, top;
+    cfGenerateSizes(printer_attrs, CF_GEN_SIZES_DEFAULT, NULL, &ipp,
+                   NULL, NULL, NULL, NULL, NULL, NULL,
+                   &minw, &minl, &maxw, &maxl,
+                   &left, &bottom, &right, &top,
+                   defSize, NULL);
+    min_width = minw * 72 / 2540;
+    min_length = minl * 72 / 2540;
+    customLeft = left * 72.0 / 2540.0;
+    customBottom = bottom * 72.0 / 2540.0;
+    customRight = right * 72.0 / 2540.0;
+    customTop = top * 72.0 / 2540.0;
+  }
+
  /*
   * Initialize data structure
   */
@@ -413,11 +411,9 @@ cfFilterImageToRaster(int inputfd,         /* I - File descriptor input stream *
   */
 
   cfRasterPrepareHeader(&header, data, outformat,
-                         CF_FILTER_OUT_FORMAT_CUPS_RASTER, 1, &cspace);
-  ppd = data->ppd;
+                       CF_FILTER_OUT_FORMAT_CUPS_RASTER, 1, &cspace);
   doc.Orientation = header.Orientation;
   doc.Duplex = header.Duplex;
-  doc.LanguageLevel = 1;
   doc.Color = header.cupsNumColors>1?1:0;
   doc.PageLeft = header.cupsImagingBBox[0] != 0.0 ?
     header.cupsImagingBBox[0] :
@@ -462,7 +458,9 @@ cfFilterImageToRaster(int inputfd,         /* I - File descriptor input stream *
 
   /*  Find print-rendering-intent */
 
-  cfGetPrintRenderIntent(data, &header);
+  header.cupsRenderingIntent[0] = '\0';
+  cfGetPrintRenderIntent(data, header.cupsRenderingIntent,
+                        sizeof(header.cupsRenderingIntent));
   if(log) log(ld, CF_LOGLEVEL_DEBUG,
              "cfFilterImageToRaster: Print rendering intent = %s",
              header.cupsRenderingIntent);
@@ -576,100 +574,44 @@ cfFilterImageToRaster(int inputfd,         /* I - File descriptor input stream *
   if ((val = cupsGetOption("hue", num_options, options)) != NULL)
     hue = atoi(val);
 
-  if ((choice = ppdFindMarkedChoice(ppd, "MirrorPrint")) != NULL ||
-      ((val = cupsGetOption("MirrorPrint", num_options, options)) != NULL) ||
-      (ipp = ippFindAttribute(job_attrs, "mirror-print", IPP_TAG_ZERO)) !=
-      NULL ||
+  if ((val = cupsGetOption("MirrorPrint", num_options, options)) != NULL ||
+      (val = cupsGetOption("mirror-print", num_options, options)) != NULL ||
+      (val = cupsGetOption("mirror", num_options, options)) != NULL ||
+      (ipp = ippFindAttribute(job_attrs, "mirror-print",
+                             IPP_TAG_ZERO)) != NULL ||
       (ipp = ippFindAttribute(printer_attrs, "mirror-print-default",
-                             IPP_TAG_ZERO))!=NULL)
+                             IPP_TAG_ZERO)) != NULL)
   {
-    if (val != NULL)
-    {
-      /*  We already found the value  */
-    }
-    else if (ipp != NULL) {
+    if (val == NULL && ipp != NULL) {
       ippAttributeString(ipp, buf, sizeof(buf));
       val = buf;
     }
-    else
-    {
-      val = choice->choice;
-      choice->marked = 0;
-    }
   }
-  else
-    val = cupsGetOption("mirror", num_options, options);
 
   if (val && (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
               !strcasecmp(val, "yes")))
     doc.Flip = 1;
 
  /*
-  * Get the media type and resolution that have been chosen...
+  * Get the media type that have been chosen...
   */
 
-  if ((choice = ppdFindMarkedChoice(ppd, "MediaType")) != NULL ||
-      (val = cupsGetOption("MediaType", num_options, options)) != NULL ||
+  if ((val = cupsGetOption("MediaType", num_options, options)) != NULL ||
+      (val = cupsGetOption("media-type", num_options, options)) != NULL ||
       (ipp = ippFindAttribute(job_attrs, "media-type", IPP_TAG_ZERO)) != NULL ||
       (ipp = ippFindAttribute(printer_attrs, "media-type-supported",
-                             IPP_TAG_ZERO))!=NULL)
+                             IPP_TAG_ZERO)) != NULL)
   {
     if (val != NULL)
-    {
       media_type = strdup(val);
-    }
-    else if(choice!=NULL)
-      media_type = strdup(choice->choice);
-    else if(ipp!=NULL){
+    else if (ipp != NULL)
       media_type = strdup(ippGetString(ipp, 0, NULL));
-    }
   }
   else
     media_type = strdup("");
 
-  if ((choice = ppdFindMarkedChoice(ppd, "Resolution")) != NULL)
-    resolution = strdup(choice->choice);
-  else if ((val = cupsGetOption("Resolution", num_options, options)) != NULL ||
-          (ipp = ippFindAttribute(job_attrs, "printer-resolution",
-                                  IPP_TAG_ZERO))!=NULL)
-  {
-    if (val == NULL) {
-      ippAttributeString(ipp, buf, sizeof(buf));
-      resolution = strdup(buf);
-    }
-    else
-    {
-      resolution = strdup(val);
-    }
-  }
-  else if ((ipp = ippFindAttribute(printer_attrs, "printer-resolution-default",
-                                  IPP_TAG_ZERO)) != NULL)
-  {
-    ippAttributeString(ipp, buf, sizeof(buf));
-    resolution = strdup(buf);
-  }
-  else if((ipp = ippFindAttribute(printer_attrs,
-                                 "printer-resolution-supported",
-                                 IPP_TAG_ZERO)) != NULL)
-  {
-    ippAttributeString(ipp, buf, sizeof(buf));
-    resolution = strdup(buf);
-    for (i = 0; resolution[i] != '\0'; i++)
-    {
-      if (resolution[i]==' ' ||
-         resolution[i]==',')
-      {
-       resolution[i] = '\0';
-       break;
-      }
-    }
-  }
-  else
-    resolution = strdup("300dpi");
-  if(log) log(ld, CF_LOGLEVEL_DEBUG, "Resolution = %s", resolution);
-
   /* support the "cm-calibration" option */
-  cm_calibrate = cfCmGetCupsColorCalibrateMode(data, options, num_options);
+  cm_calibrate = cfCmGetCupsColorCalibrateMode(data);
 
   if (cm_calibrate == CF_CM_CALIBRATION_ENABLED)
     cm_disabled = 1;
@@ -788,73 +730,37 @@ cfFilterImageToRaster(int inputfd,         /* I - File descriptor input stream *
   }
 
  /*
-  * Find a color profile matching the current options...
+  * Apply a color profile...
   */
    
   if ((val = cupsGetOption("profile", num_options, options)) != NULL &&
       !cm_disabled)
   {
-    profile = &userprofile;
-    sscanf(val, "%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f",
-           &(userprofile.density), &(userprofile.gamma),
-          userprofile.matrix[0] + 0, userprofile.matrix[0] + 1,
-          userprofile.matrix[0] + 2,
-          userprofile.matrix[1] + 0, userprofile.matrix[1] + 1,
-          userprofile.matrix[1] + 2,
-          userprofile.matrix[2] + 0, userprofile.matrix[2] + 1,
-          userprofile.matrix[2] + 2);
-
-    userprofile.density      *= 0.001f;
-    userprofile.gamma        *= 0.001f;
-    userprofile.matrix[0][0] *= 0.001f;
-    userprofile.matrix[0][1] *= 0.001f;
-    userprofile.matrix[0][2] *= 0.001f;
-    userprofile.matrix[1][0] *= 0.001f;
-    userprofile.matrix[1][1] *= 0.001f;
-    userprofile.matrix[1][2] *= 0.001f;
-    userprofile.matrix[2][0] *= 0.001f;
-    userprofile.matrix[2][1] *= 0.001f;
-    userprofile.matrix[2][2] *= 0.001f;
-  }
-  else if (ppd != NULL && !cm_disabled)
-  {
-    if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "cfFilterImageToRaster: Searching for profile \"%s/%s\"...",
-                resolution, media_type);
+    float         density;                /* Ink density to use */
+    float         gamma;                  /* Gamma correction to use */
+    float         matrix[3][3];           /* Transform matrix */
 
-    for (i = 0, profile = ppd->profiles; i < ppd->num_profiles;
-        i ++, profile ++)
-    {
-      if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterImageToRaster: \"%s/%s\" = ", profile->resolution,
-                  profile->media_type);
-
-      if ((strcmp(profile->resolution, resolution) == 0 ||
-           profile->resolution[0] == '-') &&
-          (strcmp(profile->media_type, media_type) == 0 ||
-           profile->media_type[0] == '-'))
-      {
-       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                    "cfFilterImageToRaster:    MATCH");
-       break;
-      }
-      else
-       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                    "cfFilterImageToRaster:    no.");
-    }
-
-   /*
-    * If we found a color profile, use it!
-    */
-
-    if (i >= ppd->num_profiles)
-      profile = NULL;
+    sscanf(val, "%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f",
+           &(density), &(gamma),
+          matrix[0] + 0, matrix[0] + 1, matrix[0] + 2,
+          matrix[1] + 0, matrix[1] + 1, matrix[1] + 2,
+          matrix[2] + 0, matrix[2] + 1, matrix[2] + 2);
+
+    density      *= 0.001f;
+    gamma        *= 0.001f;
+
+    matrix[0][0] *= 0.001f;
+    matrix[0][1] *= 0.001f;
+    matrix[0][2] *= 0.001f;
+    matrix[1][0] *= 0.001f;
+    matrix[1][1] *= 0.001f;
+    matrix[1][2] *= 0.001f;
+    matrix[2][0] *= 0.001f;
+    matrix[2][1] *= 0.001f;
+    matrix[2][2] *= 0.001f;
+
+    cfImageSetProfile(density, gamma, matrix);
   }
-  else
-    profile = NULL;
-
-  if (profile)
-    cfImageSetProfile(profile->density, profile->gamma, profile->matrix);
 
   cfImageSetRasterColorSpace(header.cupsColorSpace);
 
@@ -884,19 +790,11 @@ cfFilterImageToRaster(int inputfd,         /* I - File descriptor input stream *
   int fidelity = 0;
   int document_large = 0;
 
-  if (ppd != NULL && (ppd->custom_margins[0] || ppd->custom_margins[1] ||
-                      ppd->custom_margins[2] || ppd->custom_margins[3]))
-    margin_defined = 1;
-       else{
-               if(customLeft!=0 || customRight!=0 || customBottom!=0 || customTop!=0)
-                       margin_defined = 1;
-       }
-
-  if (doc.PageLength != doc.PageTop - doc.PageBottom ||
+  if (customLeft != 0 || customRight != 0 ||
+      customBottom != 0 || customTop != 0 ||
+      doc.PageLength != doc.PageTop - doc.PageBottom ||
       doc.PageWidth != doc.PageRight - doc.PageLeft)
-  {
     margin_defined = 1;
-  }
 
   if ((val = cupsGetOption("ipp-attribute-fidelity",
                           num_options, options)) != NULL)
@@ -1361,22 +1259,11 @@ cfFilterImageToRaster(int inputfd,         /* I - File descriptor input stream *
   */
 
   /* If size if specified by user, use it, else default size from
-     printer_attrs*/
-  if ((ipp = ippFindAttribute(job_attrs, "media-size", IPP_TAG_ZERO)) != NULL ||
-      (val = cupsGetOption("MediaSize", num_options, options)) != NULL ||
-      (ipp = ippFindAttribute(job_attrs, "page-size", IPP_TAG_ZERO)) != NULL ||
-      (val = cupsGetOption("PageSize", num_options, options)) != NULL ) {
-    if (val == NULL) {
-      ippAttributeString(ipp, buf, sizeof(buf));
-      strcpy(defSize, buf);
-    }
-    else
-       snprintf(defSize, sizeof(defSize), "%s", val);
-  }
+     printer_attrs */
+  strcpy(defSize, header.cupsPageSizeName);
 
-  if (((choice = ppdFindMarkedChoice(ppd, "PageSize")) != NULL &&
-       strcasecmp(choice->choice, "Custom") == 0) ||
-      (strncasecmp(defSize, "Custom", 6)) == 0)
+  if ((strncasecmp(defSize, "Custom", 6)) == 0 ||
+      strcasestr(defSize, "_custom_"))
   {
     float      width,          /* New width in points */
                length;         /* New length in points */
@@ -1400,41 +1287,23 @@ cfFilterImageToRaster(int inputfd,         /* I - File descriptor input stream *
    /*
     * Add margins to page size...
     */
-   if(ppd!=NULL){
-       width  += ppd->custom_margins[0] + ppd->custom_margins[2];
-       length += ppd->custom_margins[1] + ppd->custom_margins[3];
-       }
-       else{
-         width  += customLeft + customRight;
-         length += customBottom + customTop;
-       }
+
+    width  += customLeft + customRight;
+    length += customBottom + customTop;
+
    /*
     * Enforce minimums...
     */
-   if (ppd != NULL)
-   {
-     if (width < ppd->custom_min[0])
-       width = ppd->custom_min[0];
-   }
-   else
-   {
-     if (width < min_width)
-       width = min_width;
-   }
-   if (ppd != NULL) {
-     if (length < ppd->custom_min[1])
-       length = ppd->custom_min[1];
-   }
-   else
-   {
-     if(length < min_length)
-       length = min_length;
-   }
-
-   if (log) log(ld, CF_LOGLEVEL_DEBUG,
-               "cfFilterImageToRaster: Updated custom page size to %.2f x %.2f "
-               "inches...",
-               width / 72.0, length / 72.0);
+
+    if (width < min_width)
+      width = min_width;
+    if(length < min_length)
+      length = min_length;
+
+    if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                "cfFilterImageToRaster: Updated custom page size to %.2f x %.2f "
+                "inches...",
+                width / 72.0, length / 72.0);
 
    /*
     * Set the new custom size...
@@ -1453,36 +1322,17 @@ cfFilterImageToRaster(int inputfd,         /* I - File descriptor input stream *
 
     doc.PageWidth  = width;
     doc.PageLength = length;
-    if (ppd != NULL)
-      doc.PageLeft   = ppd->custom_margins[0];
-    else
-      doc.PageLeft = customLeft;
-    if (ppd != NULL)
-      doc.PageRight  = width - ppd->custom_margins[2];
-    else
-      doc.PageRight = width - customRight;
-    if (ppd != NULL)
-      doc.PageBottom = ppd->custom_margins[1];
-    else
-      doc.PageBottom = customBottom;
-    if (ppd != NULL)
-      doc.PageTop    = length - ppd->custom_margins[3];
-    else
-      doc.PageTop = length - customTop;
+    doc.PageLeft = customLeft;
+    doc.PageRight = width - customRight;
+    doc.PageBottom = customBottom;
+    doc.PageTop = length - customTop;
 
    /*
     * Remove margins from page size...
     */
-   if (ppd != NULL)
-   {
-     width  -= ppd->custom_margins[0] + ppd->custom_margins[2];
-     length -= ppd->custom_margins[1] + ppd->custom_margins[3];
-   }
-   else
-   {
-     width -= customLeft + customRight;
-     length -= customTop + customBottom;
-   }
+
+    width -= customLeft + customRight;
+    length -= customTop + customBottom;
 
    /*
     * Set the bitmap size...
@@ -1490,6 +1340,7 @@ cfFilterImageToRaster(int inputfd,         /* I - File descriptor input stream *
 
     header.cupsWidth  = width * header.HWResolution[0] / 72.0;
     header.cupsHeight = length * header.HWResolution[1] / 72.0;
+
   } else {
    /*
     * Set the bitmap size...
@@ -1701,11 +1552,20 @@ cfFilterImageToRaster(int inputfd,         /* I - File descriptor input stream *
   if (xpages == 1 && ypages == 1)
     doc.Collate = 0;
 
-  slowcollate = doc.Collate && ppdFindOption(ppd, "Collate") == NULL;
-  if (ppd != NULL)
-    slowcopies = ppd->manual_copies;
-  else
-    slowcopies = 1;
+  /* We should also check printer-attrs here, but printer-attrs shows
+     hardware copies ("copies-supported = 1-99") and hardware collate
+     ("multiple-document-handling-supported =
+     separate-documents-uncollated-copies,
+     separate-documents-collated-copies") even on cheapest raster
+     printers */
+  slowcollate = doc.Collate &&
+    ((val = cupsGetOption("hardware-collate", num_options, options)) == NULL ||
+     !strcasecmp(val, "false") || !strcasecmp(val, "off") ||
+     !strcasecmp(val, "no"));
+  slowcopies =
+    ((val = cupsGetOption("hardware-copies", num_options, options)) == NULL ||
+     !strcasecmp(val, "false") || !strcasecmp(val, "off") ||
+     !strcasecmp(val, "no"));
 
   if (doc.Copies > 1 && !slowcollate && !slowcopies)
   {
@@ -2001,7 +1861,6 @@ cfFilterImageToRaster(int inputfd,         /* I - File descriptor input stream *
   */
 
  canceled:
-  free(resolution);
   free(media_type);
   free(row);
   cupsRasterClose(ras);
index 68465ca47a62f7ca1dd186efbb0c6e9b8e22a582..599f3bde6f15ea8c017c13e89f811a5f5d5de6ca 100644 (file)
   USA.
 ***/
 
-#ifdef HAVE_CONFIG_H
+/*
+ * Include necessary headers.
+ */
+
 #include <config.h>
-#endif
 
 #include <ctype.h>
+#include <limits.h>
 #include <stdlib.h>
-#include <cups/cups.h>
-#include <cups/backend.h>
-#include <cupsfilters/ipp.h>
-#include <cupsfilters/ppdgenerator.h>
 #include <errno.h>
 #include <stdio.h>
 #include <signal.h>
 #include <sys/wait.h>
 #include <sys/types.h>
-
-#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5)
-#define HAVE_CUPS_1_6 1
-#endif
+#include <cups/cups.h>
+#include <cups/backend.h>
+#include <cups/dir.h>
+#include <cups/pwg.h>
+#include <cupsfilters/ipp.h>
 
 enum resolve_uri_converter_type        /**** Resolving DNS-SD based URI ****/
 {
@@ -113,7 +113,6 @@ cfResolveURI(const char *raw_uri)
   return (uri ? strdup(uri) : NULL);
 }
 
-#ifdef HAVE_CUPS_1_6
 /* Check how the driverless support is provided */
 int
 cfCheckDriverlessSupport(const char* uri)
@@ -256,10 +255,10 @@ cfGetPrinterAttributes5(http_t *http_printer,
     *driverless_info = CF_DRVLESS_FULL;
 
   /* Request printer properties via IPP, for example to
-      - generate a PPD file for the printer
-        (mainly driverless-capable printers)
-      - generally find capabilities, options, and default settinngs,
-      - printers status: Accepting jobs? Busy? With how many jobs? */
+      - Find capabilities, options, and default settings
+      - Printer's status: Accepting jobs? Busy? With how many jobs?
+      - Generate a PPD file for the printer
+        (mainly driverless-capable printers with CUPS 2.x) */
 
   cf_get_printer_attributes_log[0] = '\0';
 
@@ -662,8 +661,6 @@ cfippfindBasedURIConverter (const char *uri, int is_fax)
 }
 
 
-#endif /* HAVE_CUPS_1_6 */
-
 const char* /* O - Attribute value as string */
 cfIPPAttrEnumValForPrinter(ipp_t *printer_attrs, /* I - Printer attributes, same
                                                      as to respond
@@ -673,9 +670,10 @@ cfIPPAttrEnumValForPrinter(ipp_t *printer_attrs, /* I - Printer attributes, same
                         const char *attr_name)/* I - Attribute name */
 {
   ipp_attribute_t *attr;
-  char valuebuffer[65536],
-       printer_attr_name[256];
+  char printer_attr_name[256];
   int  i;
+  const char *res;
+
 
   if ((printer_attrs == NULL && job_attrs == NULL) || attr_name == NULL)
     return NULL;
@@ -684,42 +682,46 @@ cfIPPAttrEnumValForPrinter(ipp_t *printer_attrs, /* I - Printer attributes, same
      as string */
   if (job_attrs == NULL ||
       (attr = ippFindAttribute(job_attrs, attr_name, IPP_TAG_ZERO)) == NULL)
-    valuebuffer[0] = '\0';
+    res = NULL;
   else
-    ippAttributeString(attr, valuebuffer, sizeof(valuebuffer));
+    res = ippGetString(attr, 0, NULL);
 
   /* Check the printer properties if supplied to see whether the job attribute
      value is valid or if the job attribute was not supplied. Use printer
      default value of job attribute is invalid or not supplied 
      If no printer attributes are supplied (NULL), simply accept the job
      attribute value */
-  if (printer_attrs) {
-    if (valuebuffer[0]) {
+  if (printer_attrs)
+  {
+    if (res && res[0])
+    {
       /* Check whether value is valid according to printer attributes */
       snprintf(printer_attr_name, sizeof(printer_attr_name) - 1,
               "%s-supported", attr_name);
       if ((attr = ippFindAttribute(printer_attrs, printer_attr_name,
                                   IPP_TAG_ZERO)) != NULL) {
        for (i = 0; i < ippGetCount(attr); i ++)
-         if (strcasecmp(valuebuffer, ippGetString(attr, i, NULL)) == 0)
+         if (strcasecmp(res, ippGetString(attr, i, NULL)) == 0)
            break; /* Job attribute value is valid */
-       if (i ==  ippGetCount(attr))
-         valuebuffer[0] = '\0'; /* Job attribute value is not valid */
+       if (i == ippGetCount(attr))
+         res = NULL; /* Job attribute value is not valid */
       }
     }
-    if (!valuebuffer[0]) {
+    if (!res || !res[0])
+    {
       /* Use default value from printer attributes */
       snprintf(printer_attr_name, sizeof(printer_attr_name) - 1,
               "%s-default", attr_name);
       if ((attr = ippFindAttribute(printer_attrs, printer_attr_name,
                                   IPP_TAG_ZERO)) != NULL)
-       ippAttributeString(attr, valuebuffer, sizeof(valuebuffer));
+       res = ippGetString(attr, 0, NULL);
     }
   }
 
-  return (valuebuffer[0] ? strdup(valuebuffer) : NULL);
+  return (res);
 }
 
+
 int                 /* O - 1: Success; 0: Error */
 cfIPPAttrIntValForPrinter(ipp_t *printer_attrs, /* I - Printer attributes, same
                                                     as to respond
@@ -780,3 +782,1552 @@ cfIPPAttrIntValForPrinter(ipp_t *printer_attrs, /* I - Printer attributes, same
     *value = val;
   return retval;
 }
+
+
+int                 /* O - 1: Success; 0: Error */
+cfIPPAttrResolutionForPrinter(ipp_t *printer_attrs,/* I - Printer attributes */
+                             ipp_t *job_attrs,    /* I - Job attributes */
+                             const char *attr_name,/* I - Attribute name */
+                             int   *xres,         /* O - X resolution (dpi) */
+                             int   *yres)         /* O - Y resolution (dpi) */
+                             
+{
+  int i;
+  ipp_attribute_t *attr;
+  char printer_attr_name[256];
+  int  retval, x, y;
+  ipp_res_t units;
+
+  if ((printer_attrs == NULL && job_attrs == NULL))
+    return 0;
+
+  if (attr_name == NULL)
+    attr_name = "printer-resolution";
+
+  /* Check whether job got supplied the named attribute and read out its value
+     as integer */
+  if (job_attrs == NULL ||
+      (attr = ippFindAttribute(job_attrs, attr_name, IPP_TAG_ZERO)) == NULL)
+    retval = 0;
+  else
+  {
+    retval = 1;
+    x = ippGetResolution(attr, 0, &y, &units);
+    if (units == IPP_RES_PER_CM)
+    {
+      /* Get resolutions in dpi */
+      x = (int)((float)x * 2.54);
+      y = (int)((float)y * 2.54);
+    }
+  }
+
+  /* Check the printer properties if supplied to see whether the job attribute
+     value is valid or if the job attribute was not supplied. Use printer
+     default value of job attribute is invalid or not supplied 
+     If no printer attributes are supplied (NULL), simply accept the job
+     attribute value */
+  if (printer_attrs) {
+    if (retval == 1) {
+      /* Check whether value is valid according to printer attributes */
+      snprintf(printer_attr_name, sizeof(printer_attr_name) - 1,
+              "%s-supported", attr_name);
+      if ((attr = ippFindAttribute(printer_attrs, printer_attr_name,
+                                  IPP_TAG_RANGE)) != NULL)
+      {
+       for (i = 0; i < ippGetCount(attr); i ++)
+       {
+         int sx, sy;
+         ipp_res_t su;
+         sx = ippGetResolution(attr, i, &sy, &su);
+         if (su == IPP_RES_PER_CM)
+         {
+           /* Get resolutions in dpi */
+           sx = (int)((float)sx * 2.54);
+           sy = (int)((float)sy * 2.54);
+         }
+         if ((x - sx) * (x - sx) < 10 &&
+             (y - sy) * (y - sy) < 10)
+           break; /* Job attribute value is valid */
+       }
+       if (i == ippGetCount(attr))
+         retval = 0; /* Job attribute value is not valid */
+      }
+    }
+    if (retval == 0) {
+      /* Use default value from printer attributes */
+      snprintf(printer_attr_name, sizeof(printer_attr_name) - 1,
+              "%s-default", attr_name);
+      if ((attr = ippFindAttribute(printer_attrs, printer_attr_name,
+                                  IPP_TAG_ZERO)) != NULL) {
+       retval = 1;
+       x = ippGetResolution(attr, 0, &y, &units);
+       if (units == IPP_RES_PER_CM)
+       {
+         /* Get resolutions in dpi */
+         x = (int)((float)x * 2.54);
+         y = (int)((float)y * 2.54);
+       }
+      }
+    }
+  }
+
+  if (retval == 1)
+  {
+    *xres = x;
+    *yres = y;
+  }
+  return retval;
+}
+
+
+int
+cfIPPReverseOutput(ipp_t *printer_attrs,
+                  ipp_t *job_attrs)
+{
+  int i;
+  ipp_attribute_t *attr1, *attr2;
+  const char *val1, *val2;
+  char buf[1024];
+  int length;
+
+  // Figure out the right default output order from the IPP attributes...
+  if ((val1 = cfIPPAttrEnumValForPrinter(printer_attrs, job_attrs,
+                                        "output-bin")) != NULL)
+  {
+    // Find corresponding "printer-output-tray" entry
+    if ((attr1 = ippFindAttribute(printer_attrs, "output-bin-supported",
+                                 IPP_TAG_ZERO)) != NULL &&
+       (attr2 = ippFindAttribute(printer_attrs, "printer-output-tray",
+                                 IPP_TAG_ZERO)) != NULL)
+    {
+      for (i = 0; i < ippGetCount(attr1) && i < ippGetCount(attr2); i ++)
+      {
+       if ((val2 = ippGetString(attr1, i, 0)) != NULL &&
+           strcmp(val1, val2) == 0)
+       {
+         if ((val2 =
+              (const char *)ippGetOctetString(attr2, i, &length)) != NULL)
+         {
+           if (length > (int)(sizeof(buf) - 1))
+             length = (int)(sizeof(buf) - 1);
+           memcpy(buf, val2, length);
+           buf[length] = '\0';
+           if (strcasestr(buf, "stackingorder=firstToLast"))
+             return (0);
+           if (strcasestr(buf, "stackingorder=lastToFirst"))
+             return (1);
+           if (strcasestr(buf, "pagedelivery=faceDown"))
+             return (0);
+           if (strcasestr(buf, "pagedelivery=faceUp"))
+             return (1);
+         }
+         break;
+       }
+      }
+    }
+    // Check whether output bin name is "face-down" or "face-up"
+    if (strcasestr(val1, "face-down"))
+      return (0);
+    if (strcasestr(val1, "face-up"))
+      return (1);
+  }
+
+  // No hint of whether to print in original or reverse order. Usually this
+  // happens for a fax-out queue, where one has no output bin. Use original
+  // order then.
+  return (0);
+}
+
+
+#ifndef HAVE_STRLCPY
+/*
+ * 'strlcpy()' - Safely copy two strings.
+ */
+
+size_t                                 /* O - Length of string */
+strlcpy(char       *dst,               /* O - Destination string */
+       const char *src,                /* I - Source string */
+       size_t      size)               /* I - Size of destination string buffer */
+{
+  size_t       srclen;                 /* Length of source string */
+
+
+ /*
+  * Figure out how much room is needed...
+  */
+
+  size --;
+
+  srclen = strlen(src);
+
+ /*
+  * Copy the appropriate amount...
+  */
+
+  if (srclen > size)
+    srclen = size;
+
+  memmove(dst, src, srclen);
+  dst[srclen] = '\0';
+
+  return (srclen);
+}
+#endif /* !HAVE_STRLCPY */
+
+/*
+ * 'cfStrFormatd()' - Format a floating-point number.
+ */
+
+char *                                 /* O - Pointer to end of string */
+cfStrFormatd(char         *buf,        /* I - String */
+            char         *bufend,      /* I - End of string buffer */
+            double       number,       /* I - Number to format */
+            struct lconv *loc) /* I - Locale data */
+{
+  char         *bufptr,                /* Pointer into buffer */
+               temp[1024],             /* Temporary string */
+               *tempdec,               /* Pointer to decimal point */
+               *tempptr;               /* Pointer into temporary string */
+  const char   *dec;                   /* Decimal point */
+  int          declen;                 /* Length of decimal point */
+
+
+ /*
+  * Format the number using the "%.12f" format and then eliminate
+  * unnecessary trailing 0's.
+  */
+
+  snprintf(temp, sizeof(temp), "%.12f", number);
+  for (tempptr = temp + strlen(temp) - 1;
+       tempptr > temp && *tempptr == '0';
+       *tempptr-- = '\0');
+
+ /*
+  * Next, find the decimal point...
+  */
+
+  if (loc && loc->decimal_point) {
+    dec    = loc->decimal_point;
+    declen = (int)strlen(dec);
+  } else {
+    dec    = ".";
+    declen = 1;
+  }
+
+  if (declen == 1)
+    tempdec = strchr(temp, *dec);
+  else
+    tempdec = strstr(temp, dec);
+
+ /*
+  * Copy everything up to the decimal point...
+  */
+
+  if (tempdec) {
+    for (tempptr = temp, bufptr = buf;
+         tempptr < tempdec && bufptr < bufend;
+        *bufptr++ = *tempptr++);
+
+    tempptr += declen;
+
+    if (*tempptr && bufptr < bufend) {
+      *bufptr++ = '.';
+
+      while (*tempptr && bufptr < bufend)
+        *bufptr++ = *tempptr++;
+    }
+
+    *bufptr = '\0';
+  } else {
+    strlcpy(buf, temp, (size_t)(bufend - buf + 1));
+    bufptr = buf + strlen(buf);
+  }
+
+  return (bufptr);
+}
+
+
+int
+cfCompareResolutions(void *resolution_a,
+                    void *resolution_b,
+                    void *user_data)
+{
+  cf_res_t *res_a = (cf_res_t *)resolution_a;
+  cf_res_t *res_b = (cf_res_t *)resolution_b;
+  int i, a, b;
+
+  /* Compare the pixels per square inch */
+  a = res_a->x * res_a->y;
+  b = res_b->x * res_b->y;
+  i = (a > b) - (a < b);
+  if (i) return i;
+
+  /* Compare how much the pixel shape deviates from a square, the
+     more, the worse */
+  a = 100 * res_a->y / res_a->x;
+  if (a > 100) a = 10000 / a; 
+  b = 100 * res_b->y / res_b->x;
+  if (b > 100) b = 10000 / b; 
+  return (a > b) - (a < b);
+}
+
+void *
+cfCopyResolution(void *resolution,
+               void *user_data)
+{
+  cf_res_t *res = (cf_res_t *)resolution;
+  cf_res_t *copy;
+
+  copy = (cf_res_t *)calloc(1, sizeof(cf_res_t));
+  if (copy) {
+    copy->x = res->x;
+    copy->y = res->y;
+  }
+
+  return copy;
+}
+
+void
+cfFreeResolution(void *resolution,
+               void *user_data)
+{
+  cf_res_t *res = (cf_res_t *)resolution;
+
+  if (res) free(res);
+}
+
+cups_array_t *
+cfNewResolutionArray()
+{
+  return cupsArrayNew3(cfCompareResolutions, NULL, NULL, 0,
+                      cfCopyResolution, cfFreeResolution);
+}
+
+cf_res_t *
+cfNewResolution(int x,
+               int y)
+{
+  cf_res_t *res = (cf_res_t *)calloc(1, sizeof(cf_res_t));
+  if (res) {
+    res->x = x;
+    res->y = y;
+  }
+  return res;
+}
+
+/* Read a single resolution from an IPP attribute, take care of
+   obviously wrong entries (printer firmware bugs), ignoring
+   resolutions of less than 60 dpi in at least one dimension and
+   fixing Brother's "600x2dpi" resolutions. */
+cf_res_t *
+cfIPPResToResolution(ipp_attribute_t *attr,
+                    int index)
+{
+  cf_res_t *res = NULL;
+  int x = 0, y = 0;
+  ipp_res_t units;
+
+  if (attr) {
+    ipp_tag_t tag = ippGetValueTag(attr);
+    int count = ippGetCount(attr);
+
+    if (tag == IPP_TAG_RESOLUTION && index < count) {
+      x = ippGetResolution(attr, index, &y, &units);
+      if (units == IPP_RES_PER_CM)
+      {
+       x = (int)(x * 2.54);
+       y = (int)(y * 2.54);
+      }
+      if (y == 2) y = x; /* Brother quirk ("600x2dpi") */
+      if (x >= 60 && y >= 60)
+       res = cfNewResolution(x, y);
+    }
+  }
+
+  return res;
+}
+
+cups_array_t *
+cfIPPAttrToResolutionArray(ipp_attribute_t *attr)
+{
+  cups_array_t *res_array = NULL;
+  cf_res_t *res;
+  int i;
+
+  if (attr) {
+    ipp_tag_t tag = ippGetValueTag(attr);
+    int count = ippGetCount(attr);
+
+    if (tag == IPP_TAG_RESOLUTION && count > 0) {
+      res_array = cfNewResolutionArray();
+      if (res_array) {
+       for (i = 0; i < count; i ++)
+         if ((res = cfIPPResToResolution(attr, i)) != NULL) {
+           if (cupsArrayFind(res_array, res) == NULL)
+             cupsArrayAdd(res_array, res);
+           cfFreeResolution(res, NULL);
+         }
+      }
+      if (cupsArrayCount(res_array) == 0) {
+       cupsArrayDelete(res_array);
+       res_array = NULL;
+      }
+    }
+  }
+
+  return res_array;
+}
+
+/* Build up an array of common resolutions and most desirable default
+   resolution from multiple arrays of resolutions with an optional
+   default resolution.
+   Call this function with each resolution array you find as "new", and
+   in "current" an array of the common resolutions will be built up.
+   You do not need to create an empty array for "current" before
+   starting. Initialize it with NULL.
+   "current_default" holds the default resolution of the array "current".
+   It will get replaced by "new_default" if "current_default" is either
+   NULL or a resolution which is not in "current" any more.
+   "new" and "new_default" will be deleted/freed and set to NULL after
+   each, successful or unsuccssful operation.
+   Note that when calling this function the addresses of the pointers
+   to the resolution arrays and default resolutions have to be given
+   (call by reference) as all will get modified by the function. */
+
+int /* 1 on success, 0 on failure */
+cfJoinResolutionArrays(cups_array_t **current,
+                      cups_array_t **new_arr,
+                      cf_res_t **current_default,
+                      cf_res_t **new_default)
+{
+  cf_res_t *res;
+  int retval;
+
+  if (current == NULL || new_arr == NULL || *new_arr == NULL ||
+      cupsArrayCount(*new_arr) == 0) {
+    retval = 0;
+    goto finish;
+  }
+
+  if (*current == NULL) {
+    /* We are adding the very first resolution array, simply make it
+       our common resolutions array */
+    *current = *new_arr;
+    if (current_default) {
+      if (*current_default)
+       free(*current_default);
+      *current_default = (new_default ? *new_default : NULL);
+    }
+    return 1;
+  } else if (cupsArrayCount(*current) == 0) {
+    retval = 1;
+    goto finish;
+  }
+
+  /* Dry run: Check whether the two arrays have at least one resolution
+     in common, if not, do not touch the original array */
+  for (res = cupsArrayFirst(*current);
+       res; res = cupsArrayNext(*current))
+    if (cupsArrayFind(*new_arr, res))
+      break;
+
+  if (res) {
+    /* Reduce the original array to the resolutions which are in both
+       the original and the new array, at least one resolution will
+       remain. */
+    for (res = cupsArrayFirst(*current);
+        res; res = cupsArrayNext(*current))
+      if (!cupsArrayFind(*new_arr, res))
+       cupsArrayRemove(*current, res);
+    if (current_default) {
+      /* Replace the current default by the new one if the current default
+        is not in the array any more or if it is NULL. If the new default
+        is not in the list or NULL in such a case, set the current default
+        to NULL */
+      if (*current_default && !cupsArrayFind(*current, *current_default)) {
+       free(*current_default);
+       *current_default = NULL;
+      }
+      if (*current_default == NULL && new_default && *new_default &&
+         cupsArrayFind(*current, *new_default))
+       *current_default = cfCopyResolution(*new_default, NULL);
+    }
+    retval = 1;
+  } else
+    retval = 0;
+
+ finish:
+  if (new_arr && *new_arr) {
+    cupsArrayDelete(*new_arr);
+    *new_arr = NULL;
+  }
+  if (new_default && *new_default) {
+    free(*new_default);
+    *new_default = NULL;
+  }
+  return retval;
+}
+
+
+/*
+ * 'pwg_compare_sizes()' - Compare two media sizes...
+ */
+
+static int                             /* O - Result of comparison */
+pwg_compare_sizes(cups_size_t *a,      /* I - First media size */
+                  cups_size_t *b)      /* I - Second media size */
+{
+  return (strcmp(a->media, b->media));
+}
+
+
+/*
+ * 'pwg_copy_size()' - Copy a media size.
+ */
+
+static cups_size_t *                   /* O - New media size */
+pwg_copy_size(cups_size_t *size)       /* I - Media size to copy */
+{
+  cups_size_t  *newsize = (cups_size_t *)calloc(1, sizeof(cups_size_t));
+                                       /* New media size */
+
+  if (newsize)
+    memcpy(newsize, size, sizeof(cups_size_t));
+
+  return (newsize);
+}
+
+
+int                                    /* O -  1: Requested page size supported
+                                               2: Requested page size supported
+                                                  when rotated by 90 degrees
+                                               0: No page size requested
+                                              -1: Requested size unsupported */
+cfGetPageDimensions(ipp_t *printer_attrs,   /* I - Printer attributes */
+                   ipp_t *job_attrs,       /* I - Job attributes */
+                   int num_options,        /* I - Number of options */
+                   cups_option_t *options, /* I - Options */
+                   cups_page_header2_t *header, /* I - Raster page header */
+                   int transverse_fit,     /* I - Accept transverse fit? */
+                   float *width,           /* O - Width (in pt, 1/72 inches) */
+                   float *height,          /* O - Height */
+                   float *left,            /* O - Left margin */
+                   float *bottom,          /* O - Bottom margin */
+                   float *right,           /* O - Right margin */
+                   float *top,             /* O - Top margin */
+                   char *name,             /* O - Page size name */
+                   ipp_t **media_col_entry)/* O - media-col-database record of
+                                                  match */
+{
+  int           i;
+  const char    *attr_name;
+  char          size_name_buf[IPP_MAX_NAME + 1];
+  int           size_requested = 0;
+  const char * const media_size_attr_names[] = {
+    "Jmedia-col",
+    "Jmedia-size",
+    "Jmedia",
+    "JPageSize",
+    "JMediaSize",
+    "J", /* A raster header with media dimensions */
+    "jmedia-col",
+    "jmedia-size",
+    "jmedia",
+    "jPageSize",
+    "jMediaSize",
+    "j", /* A raster header with media dimensions */
+    "Dmedia-col-default",
+    "Dmedia-default",
+  };
+
+
+  if (name == NULL)
+    name = size_name_buf;
+  name[0] = '\0';
+
+  if (media_col_entry)
+    *media_col_entry = NULL;
+
+ /*
+  * Media from job_attrs and options, defaults from printer_attrs...
+  */
+
+  /* Go through all job attributes and options which could contain the
+     page size, afterwards go through the page size defaults in the
+     printer attributes */
+  for (i = 0;
+       i < sizeof(media_size_attr_names) / sizeof(media_size_attr_names[0]);
+       i ++)
+  {
+    ipp_attribute_t *attr = NULL;      /* Job attribute */
+    char       valstr[8192];           /* Attribute value string */
+    const char *value = NULL;          /* Option value */
+    const char *name_ptr = NULL;       /* Pointer to page size name */
+    int                num_media_col = 0;      /* Number of media-col values */
+    cups_option_t *media_col = NULL;   /* media-col values */
+    int         ipp_width = 0,
+                ipp_height = 0,
+                ipp_left = -1,
+                ipp_bottom = -1,
+                ipp_right = -1,
+                ipp_top = -1;
+
+    attr_name = media_size_attr_names[i];
+    if (*attr_name == 'J' ||
+       (transverse_fit && *attr_name == 'j')) /* Job attribute/option */
+    {
+      if (*(attr_name + 1) == '\0')
+      {
+       if (header)
+       {
+         /* Raster header */
+         if (header->cupsPageSize[0] > 0.0)
+           ipp_width = (int)(header->cupsPageSize[0] * 2540.0 / 72.0);
+         else if (header->PageSize[0] > 0)
+           ipp_width = (int)(header->PageSize[0] * 2540 / 72);
+         if (header->cupsPageSize[1] > 0.0)
+           ipp_height = (int)(header->cupsPageSize[1] * 2540.0 / 72.0);
+         else if (header->PageSize[1] > 0)
+           ipp_height = (int)(header->PageSize[1] * 2540 / 72);
+         if (header->ImagingBoundingBox[3] > 0)
+         {
+           if (header->cupsImagingBBox[0] >= 0.0)
+             ipp_left = (int)(header->cupsImagingBBox[0] * 2540.0 / 72.0);
+           else if (header->ImagingBoundingBox[0] >= 0)
+             ipp_left = (int)(header->ImagingBoundingBox[0] * 2540 / 72);
+           if (header->cupsImagingBBox[1] >= 0.0)
+             ipp_bottom = (int)(header->cupsImagingBBox[1] * 2540.0 / 72.0);
+           else if (header->ImagingBoundingBox[1] >= 0)
+             ipp_bottom = (int)(header->ImagingBoundingBox[1] * 2540 / 72);
+           if (header->cupsImagingBBox[2] > 0.0)
+             ipp_right = ipp_width -
+             (int)(header->cupsImagingBBox[2] * 2540.0 / 72.0);
+           else if (header->ImagingBoundingBox[2] > 0)
+             ipp_right = ipp_width -
+               (int)(header->ImagingBoundingBox[2] * 2540 / 72);
+           if (header->cupsImagingBBox[3] > 0.0)
+           ipp_top = ipp_height -
+             (int)(header->cupsImagingBBox[3] * 2540.0 / 72.0);
+           else if (header->ImagingBoundingBox[3] > 0)
+             ipp_top = ipp_height -
+               (int)(header->ImagingBoundingBox[3] * 2540 / 72);
+         }
+         else
+           ipp_left = ipp_bottom = ipp_right = ipp_top = 0;
+       }
+       else
+         continue;
+      }
+      else if ((attr = ippFindAttribute(job_attrs, attr_name + 1,
+                                       IPP_TAG_ZERO)) != NULL)
+      {
+       /* String from IPP attribute */
+       ippAttributeString(attr, valstr, sizeof(valstr));
+       value = valstr;
+      }
+      else if ((value = cupsGetOption(attr_name + 1, num_options,
+                                     options)) == NULL)
+       continue;
+    }
+    else if (*attr_name == 'D') /* Printer default */
+    {
+      if (*(attr_name + 1))
+      {
+       if ((attr = ippFindAttribute(printer_attrs, attr_name + 1,
+                                  IPP_TAG_ZERO)) != NULL)
+        {
+         /* String from IPP attribute */
+         ippAttributeString(attr, valstr, sizeof(valstr));
+         value = valstr;
+       }
+       else
+         continue;
+      }
+      else
+       continue;
+    }
+    else
+      continue;
+
+    if (value)
+    {
+      if (*value == '{')
+      {
+       /*
+       * String is a dictionary -> "media-col" value...
+       */
+
+       num_media_col = cupsParseOptions(value, 0, &media_col);
+
+       /* Actual size in dictionary? */
+       if ((value = cupsGetOption("media-size", num_media_col, media_col))
+           != NULL)
+       {
+         int           num_media_size; /* Number of media-size values */
+         cups_option_t *media_size;    /* media-size values */
+         const char    *x_dimension,   /* x-dimension value */
+                       *y_dimension;   /* y-dimension value */
+
+         num_media_size = cupsParseOptions(value, 0, &media_size);
+
+         if ((x_dimension = cupsGetOption("x-dimension", num_media_size, media_size)) != NULL && (y_dimension = cupsGetOption("y-dimension", num_media_size, media_size)) != NULL)
+         {
+           ipp_width = atoi(x_dimension);
+           ipp_height = atoi(y_dimension);
+         }
+
+         cupsFreeOptions(num_media_size, media_size);
+       }
+       /* Name in dictionary? Use only if actual dimensions are not supplied */
+       if ((ipp_width <= 0 || ipp_height <= 0) &&
+           (name_ptr = cupsGetOption("media-size-name",
+                                   num_media_col, media_col)) == NULL)
+       {
+         cupsFreeOptions(num_media_col, media_col);
+         continue;
+       }
+
+       /* Grab margins from media-col */
+       if ((value = cupsGetOption("media-left-margin",
+                                  num_media_col, media_col))
+           != NULL)
+         ipp_left = atoi(value);
+       if ((value = cupsGetOption("media-bottom-margin",
+                                  num_media_col, media_col))
+           != NULL)
+         ipp_bottom = atoi(value);
+       if ((value = cupsGetOption("media-right-margin",
+                                  num_media_col, media_col))
+           != NULL)
+         ipp_right = atoi(value);
+       if ((value = cupsGetOption("media-top-margin",
+                                  num_media_col, media_col))
+           != NULL)
+         ipp_top = atoi(value);
+      }
+      else
+      {
+       /*
+       * String is not dictionary, check also if it contains commas (list
+       * of media properties supplied via "media" CUPS option
+       */
+
+       char *ptr;
+       name_ptr = value;
+       if (strchr(value, ','))
+       {
+         /* Comma-separated list of media properties, supplied with "media"
+            CUPS option */
+         if (value != valstr)
+         {
+           /* Copy string for further manipulation */
+           strlcpy(valstr, value, sizeof(valstr));
+           value = valstr;
+           name_ptr = value;
+         }
+         for (ptr = (char *)value; *ptr;)
+         {
+           ptr ++;
+           if (*ptr == ',' || *ptr == '\0')
+           {
+             /* End of item name */
+             if (*ptr == ',')
+             {
+               *ptr = '\0';
+               ptr ++;
+             }
+             /* Find PWG media entry for the name, if we find one, the name
+                is actually a page size name */
+             if (pwgMediaForPWG(name_ptr) ||
+                 pwgMediaForPPD(name_ptr) ||
+                 pwgMediaForLegacy(name_ptr))
+               /* This is a page size name */
+               break;
+             else if (*ptr)
+               /* Next item */
+               name_ptr = ptr;
+             else
+               /* No further item */
+               name_ptr = NULL;
+           }
+         }
+       }
+      }
+    }
+
+    /* Get name from media */
+    if (name_ptr)
+    {
+      if (ipp_left == 0 && ipp_bottom == 0 &&
+         ipp_right == 0 && ipp_top == 0)
+       snprintf(name, IPP_MAX_NAME, "%.29s.Borderless", name_ptr);
+      else
+       strlcpy(name, name_ptr, IPP_MAX_NAME);
+    }
+
+    /* Landscape/Transverse fit */
+    if (*attr_name == 'j') /* Only job attributes/options */
+    {
+      int swap;
+
+      swap = ipp_width;
+      ipp_width = ipp_height;
+      ipp_height = swap;
+
+      swap = ipp_left;
+      ipp_left = ipp_top;
+      ipp_top = ipp_right;
+      ipp_right = ipp_bottom;
+      ipp_bottom = swap;       
+    }
+    
+    cupsFreeOptions(num_media_col, media_col);
+
+    /* We have a valid request for a page size */
+    if (*attr_name == 'J' || *attr_name == 'j')
+      size_requested = 1;
+
+    /* Validate collected information */
+    /* If we have a size, we use the size as search term (name = "" then),
+       if we have no size but a name, use the name, always pass in margins
+       if available */
+    cfGenerateSizes(printer_attrs, CF_GEN_SIZES_SEARCH, NULL, NULL,
+                   &ipp_width, &ipp_height,
+                   &ipp_left, &ipp_bottom, &ipp_right, &ipp_top,
+                   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, name,
+                   media_col_entry);
+
+    /* Return resulting numbers */
+    if (ipp_width > 0 && ipp_height > 0 &&
+       ipp_left >= 0 && ipp_bottom >= 0 &&
+       ipp_right >= 0 && ipp_top >= 0)
+    {
+      if (width)
+       *width = ipp_width * 72.0 / 2540.0;
+      if (height)
+       *height = ipp_height * 72.0 / 2540.0;
+
+      if (left)
+       *left = ipp_left * 72.0 / 2540.0;
+      if (bottom)
+       *bottom = ipp_bottom * 72.0 / 2540.0;
+      if (right)
+       *right = ipp_right * 72.0 / 2540.0;
+      if (top)
+       *top = ipp_top * 72.0 / 2540.0;
+
+      return (*attr_name == 'J' ? 1 :
+             (*attr_name == 'j' ? 2 :
+              (size_requested ? -1 : 0)));
+    }
+    else if (media_col_entry)
+      *media_col_entry = NULL;
+  }
+  return (size_requested ? -1 : 0);
+}
+
+
+void
+cfGenerateSizes(ipp_t *response,
+               cf_gen_sizes_mode_t mode,
+               cups_array_t **sizes,
+               ipp_attribute_t **defattr,
+               int *width,
+               int *length,
+               int *left,
+               int *bottom,
+               int *right,
+               int *top,
+               int *min_width,
+               int *min_length,
+               int *max_width,
+               int *max_length,
+               int *custom_left,
+               int *custom_bottom,
+               int *custom_right,
+               int *custom_top,
+               char *size_name,
+               ipp_t **media_col_entry)
+{
+  ipp_attribute_t          *default_attr,
+                           *attr,                /* xxx-supported */
+                           *x_dim, *y_dim,       /* Media dimensions */
+                           *name;                /* Media size name */ 
+  ipp_t                    *media_col,           /* Media collection */
+                           *media_size;          /* Media size collection */
+  int                      i, x = 0, y = 0, count = 0;
+  pwg_media_t              *pwg, *pwg_by_name;   /* PWG media size */
+  int                      local_min_width, local_min_length,
+                           local_max_width, local_max_length;
+  int                      local_left, local_right, local_bottom, local_top;
+  ipp_attribute_t          *margin;  /* media-xxx-margin attribute */
+  const char               *psname;
+  const char               *entry_name;
+  char                     size_name_buf[IPP_MAX_NAME + 1] = "";
+  pwg_media_t              *search = NULL;
+  int                      search_width = 0,
+                           search_length = 0,
+                           search_left = -1,
+                           search_bottom = -1,
+                           search_right = -1,
+                           search_top = -1,
+                           borderless = 0;
+  long long                min_border_mismatch = LLONG_MAX,
+                           border_mismatch;
+
+
+  if (media_col_entry)
+    *media_col_entry = NULL;
+
+  if (custom_left == NULL)
+    custom_left = &local_left;
+  if ((attr = ippFindAttribute(response, "media-left-margin-supported",
+                              IPP_TAG_INTEGER)) != NULL) {
+    for (i = 1, *custom_left = ippGetInteger(attr, 0), count = ippGetCount(attr);
+        i < count; i ++)
+      if (ippGetInteger(attr, i) < *custom_left)
+        *custom_left = ippGetInteger(attr, i);
+  } else
+    *custom_left = 635;
+
+  if (custom_bottom == NULL)
+    custom_bottom = &local_bottom;
+  if ((attr = ippFindAttribute(response, "media-bottom-margin-supported",
+                              IPP_TAG_INTEGER)) != NULL) {
+    for (i = 1, *custom_bottom = ippGetInteger(attr, 0), count = ippGetCount(attr);
+        i < count; i ++)
+      if (ippGetInteger(attr, i) < *custom_bottom)
+        *custom_bottom = ippGetInteger(attr, i);
+  } else
+    *custom_bottom = 1270;
+
+  if (custom_right == NULL)
+    custom_right = &local_right;
+  if ((attr = ippFindAttribute(response, "media-right-margin-supported",
+                              IPP_TAG_INTEGER)) != NULL) {
+    for (i = 1, *custom_right = ippGetInteger(attr, 0), count = ippGetCount(attr);
+        i < count; i ++)
+      if (ippGetInteger(attr, i) < *custom_right)
+        *custom_right = ippGetInteger(attr, i);
+  } else
+    *custom_right = 635;
+
+  if (custom_top == NULL)
+    custom_top = &local_top;
+  if ((attr = ippFindAttribute(response, "media-top-margin-supported",
+                              IPP_TAG_INTEGER)) != NULL) {
+    for (i = 1, *custom_top = ippGetInteger(attr, 0), count = ippGetCount(attr);
+        i < count; i ++)
+      if (ippGetInteger(attr, i) < *custom_top)
+        *custom_top = ippGetInteger(attr, i);
+  } else
+    *custom_top = 1270;
+
+  if (mode != CF_GEN_SIZES_DEFAULT)
+  {
+    if (min_width == NULL)
+      min_width = &local_min_width;
+    *min_width = 0;
+    if (min_length == NULL)
+      min_length = &local_min_length;
+    *min_length = 0;
+    if (max_width == NULL)
+      max_width = &local_max_width;
+    *max_width = 0;
+    if (max_length == NULL)
+      max_length = &local_max_length;
+    *max_length = 0;
+  }
+
+  if (size_name == NULL)
+  {
+    size_name = size_name_buf;
+    size_name[0] = '\0';
+  }
+  if (mode == CF_GEN_SIZES_DEFAULT)
+    size_name[0] = '\0';
+  if (defattr == NULL && mode == CF_GEN_SIZES_DEFAULT)
+    defattr = &default_attr;
+  if (defattr &&
+      (*defattr = ippFindAttribute(response, "media-col-default",
+                                  IPP_TAG_BEGIN_COLLECTION)) != NULL) {
+    if (mode == CF_GEN_SIZES_DEFAULT &&
+       (attr = ippFindAttribute(ippGetCollection(*defattr, 0), "media-size",
+                                IPP_TAG_BEGIN_COLLECTION)) != NULL) {
+      media_size = ippGetCollection(attr, 0);
+      x_dim      = ippFindAttribute(media_size, "x-dimension", IPP_TAG_INTEGER);
+      y_dim      = ippFindAttribute(media_size, "y-dimension", IPP_TAG_INTEGER);
+  
+      if ((margin = ippFindAttribute(ippGetCollection(*defattr, 0),
+                                    "media-bottom-margin", IPP_TAG_INTEGER))
+         != NULL)
+       local_bottom = ippGetInteger(margin, 0);
+      else
+       local_bottom = *custom_bottom;
+      if (bottom)
+       *bottom = local_bottom;
+
+      if ((margin = ippFindAttribute(ippGetCollection(*defattr, 0),
+                                    "media-left-margin", IPP_TAG_INTEGER))
+         != NULL)
+       local_left = ippGetInteger(margin, 0);
+      else
+       local_left = *custom_left;
+      if (left)
+       *left = local_left;
+
+      if ((margin = ippFindAttribute(ippGetCollection(*defattr, 0),
+                                    "media-right-margin", IPP_TAG_INTEGER))
+         != NULL)
+       local_right = ippGetInteger(margin, 0);
+      else
+       local_right = *custom_right;
+      if (right)
+       *right = local_right;
+
+      if ((margin = ippFindAttribute(ippGetCollection(*defattr, 0),
+                                    "media-top-margin", IPP_TAG_INTEGER))
+         != NULL)
+       local_top = ippGetInteger(margin, 0);
+      else
+       local_top = *custom_top;
+      if (top)
+       *top = local_top;
+
+      if (x_dim && y_dim) {
+       x = ippGetInteger(x_dim, 0);
+       y = ippGetInteger(y_dim, 0);
+       if (x > 0 && y > 0 &&
+           (pwg = pwgMediaForSize(x, y)) != NULL) {
+         psname = (pwg->ppd != NULL ? pwg->ppd : pwg->pwg);
+         if (local_bottom == 0 && local_left == 0 &&
+             local_right == 0 && local_top == 0)
+           snprintf(size_name, IPP_MAX_NAME, "%s.Borderless", psname);
+         else
+           strlcpy(size_name, psname, IPP_MAX_NAME);
+       }
+      }
+    }
+  }
+  if (mode == CF_GEN_SIZES_DEFAULT &&
+      (pwg =
+       pwgMediaForPWG(ippGetString(ippFindAttribute(response,
+                                                   "media-default",
+                                                   IPP_TAG_ZERO), 0,
+                                  NULL))) != NULL) {
+    psname = (pwg->ppd != NULL ? pwg->ppd : pwg->pwg);
+    strlcpy(size_name, psname, IPP_MAX_NAME);
+    if (x <= 0 || y <= 0) {
+      x = pwg->width;
+      y = pwg->length;
+    }
+  }
+
+  if (mode == CF_GEN_SIZES_DEFAULT)
+  {
+    /* Output the default page size dimensions, 0 if no valid size found */
+    if (!size_name[0])
+      strlcpy(size_name, "Unknown", IPP_MAX_NAME);
+    if (width)
+    {
+      if (x > 0)
+       *width = x;
+      else
+       *width = 0;
+    }
+    if (length)
+    {
+      if (y > 0)
+       *length = y;
+      else
+       *length = 0;
+    }
+  }
+  else
+  {
+    /* Find the dimensions for the page size name we got as search term */
+    char *ptr;
+    int is_transverse = (strcasestr(size_name, ".Transverse") ? 1 : 0);
+    if (strcasestr(size_name, ".Fullbleed") ||
+       strcasestr(size_name, ".Borderless") ||
+       strcasestr(size_name, ".FB"))
+      mode = CF_GEN_SIZES_SEARCH_BORDERLESS_ONLY;
+    if (size_name != size_name_buf)
+      strlcpy(size_name_buf, size_name, IPP_MAX_NAME);
+    if ((ptr = strchr(size_name_buf, '.')) != NULL &&
+       strncasecmp(size_name_buf, "Custom.", 7) != 0)
+      *ptr = '\0';
+    if ((search = pwgMediaForPWG(size_name_buf)) == NULL)
+      if ((search = pwgMediaForPPD(size_name_buf)) == NULL)
+       search = pwgMediaForLegacy(size_name_buf);
+    if (search != NULL) {
+      /* Set the appropriate dimensions */
+      if (is_transverse)
+      {
+       search_width = search->length;
+       search_length = search->width;
+      }
+      else
+      {
+       search_width = search->width;
+       search_length = search->length;
+      }
+    }
+    else
+    {
+      /* Set the dimensions if we search by dimensions */
+      if (width)
+       search_width = *width;
+      if (length)
+       search_length = *length;
+    }
+    if (search_width <= 0 || search_length <= 0)
+    {
+      /* No valid search dimensions, de-activate searching and set 0 as
+        result */
+      mode = CF_GEN_SIZES_DEFAULT;
+      if (width)
+       *width = 0;
+      if (length)
+       *length = 0;
+    }
+    else
+    {
+      /* Check whether we have margin info so that we can search for a
+        size with similar/the same margins, otherwise set the margins
+        -1 to pick the first entry from the list which fits the size
+        dimensions (if there are variants of a size, the first entry
+        is usually the standard size) */
+      if (left && *left >= 0)
+       search_left = *left;
+      else
+       search_left = -1;
+      if (bottom && *bottom >= 0)
+       search_bottom = *bottom;
+      else
+       search_bottom = -1;
+      if (right && *right >= 0)
+       search_right = *right;
+      else
+       search_right = -1;
+      if (top && *top >= 0)
+       search_top = *top;
+      else
+       search_top = -1;
+    }
+  }
+
+  if (mode == CF_GEN_SIZES_DEFAULT &&
+      !sizes && !min_width && !max_width && !min_length && !max_length)
+    return;
+
+  if (sizes)
+    *sizes = cupsArrayNew3((cups_array_func_t)pwg_compare_sizes, NULL, NULL, 0,
+                          (cups_acopy_func_t)pwg_copy_size,
+                          (cups_afree_func_t)free);
+
+  if ((attr = ippFindAttribute(response, "media-col-database",
+                              IPP_TAG_BEGIN_COLLECTION)) != NULL) {
+    for (i = 0, count = ippGetCount(attr); i < count; i ++) {
+      cups_size_t temp, temp_by_name;   /* Current size */
+
+      media_col   = ippGetCollection(attr, i);
+      media_size  =
+       ippGetCollection(ippFindAttribute(media_col, "media-size",
+                                         IPP_TAG_BEGIN_COLLECTION), 0);
+      /* These are the numeric paper dimensions explicitly mentioned
+        in this media entry. if we were called in a retro-fitting
+        setup via a ppdFilter...() wrapper filter function of libppd,
+        these dimensions can deviate from the paper dimensions which
+        the PWG-style page size name in the same entry suggests. In
+        this case we match both sizes against the size requested for
+        the job and consider the entry as matching if one of the two
+        sizes matches. In this case the entry gets included in all
+        entries which are selected by the closest fit of the margins.
+
+        We do this as some PPD files (especially of HPLIP) contain
+        page size entries which are variants of a standard size with
+        the base name of a standard size (like "A4.Borderless", base
+        name "A4") but different dimensions.
+
+        Especially there are larger dimensions for borderless, for
+        overspraying over the borders of the sheet so that there will
+        be no faint white borders if the sheet is a little
+        mis-aligned.
+
+        So if such overspraying borderless size entry is present and
+        has zero margins while the standard size entry has regular
+        margins, this entry will get automatically selected if
+        borderless printing (standard size name or dimensions plus
+        zero margins) is selected.
+      */
+      x_dim       = ippFindAttribute(media_size, "x-dimension", IPP_TAG_ZERO);
+      y_dim       = ippFindAttribute(media_size, "y-dimension", IPP_TAG_ZERO);
+      // Move "if" for custom size parameters here 
+      //if (ippGetValueTag(x_dim) == IPP_TAG_RANGE ||
+      //        ippGetValueTag(y_dim) == IPP_TAG_RANGE) {
+      pwg         = pwgMediaForSize(ippGetInteger(x_dim, 0),
+                                   ippGetInteger(y_dim, 0));
+      name        = ippFindAttribute(media_col, "media-size-name",
+                                    IPP_TAG_ZERO);
+      pwg_by_name = NULL;
+      if (name)
+      {
+       entry_name = ippGetString(name, 0, NULL);
+       if (entry_name)
+         pwg_by_name = pwgMediaForPWG(entry_name);
+      }
+
+      if (pwg || pwg_by_name) {
+       if (!sizes && mode == CF_GEN_SIZES_DEFAULT)
+         continue;
+
+       if (pwg)
+       {
+         temp.width  = pwg->width;
+         temp.length = pwg->length;
+       }
+       else
+         temp.width = temp.length = 0;
+
+       if (pwg_by_name)
+       {
+         temp_by_name.width  = pwg_by_name->width;
+         temp_by_name.length = pwg_by_name->length;
+       }
+       else
+         temp_by_name.width = temp_by_name.length = 0;
+
+       if ((margin = ippFindAttribute(media_col, "media-bottom-margin",
+                                      IPP_TAG_INTEGER)) != NULL)
+         temp.bottom = ippGetInteger(margin, 0);
+       else
+         temp.bottom = *custom_bottom;
+
+       if ((margin = ippFindAttribute(media_col, "media-left-margin",
+                                      IPP_TAG_INTEGER)) != NULL)
+         temp.left = ippGetInteger(margin, 0);
+       else
+         temp.left = *custom_left;
+
+       if ((margin = ippFindAttribute(media_col, "media-right-margin",
+                                      IPP_TAG_INTEGER)) != NULL)
+         temp.right = ippGetInteger(margin, 0);
+       else
+         temp.right = *custom_right;
+
+       if ((margin = ippFindAttribute(media_col, "media-top-margin",
+                                      IPP_TAG_INTEGER)) != NULL)
+         temp.top = ippGetInteger(margin, 0);
+       else
+         temp.top = *custom_top;
+
+       psname = (pwg_by_name ?
+                 (pwg_by_name->ppd != NULL ?
+                  pwg_by_name->ppd : pwg_by_name->pwg) :
+                 (pwg->ppd != NULL ? pwg->ppd : pwg->pwg));
+       if (temp.bottom == 0 && temp.left == 0 && temp.right == 0 &&
+           temp.top == 0)
+       {
+         snprintf(temp.media, sizeof(temp.media), "%s.Borderless", psname);
+         borderless = 1;
+       }
+       else
+       {
+         strlcpy(temp.media, psname, sizeof(temp.media));
+         borderless = 0;
+       }
+
+       /* Check whether this size matches our search criteria */
+       if (mode != CF_GEN_SIZES_DEFAULT &&
+           min_border_mismatch > 0 &&
+           search_width > 0 && search_length > 0 &&
+           ((abs(search_width - temp_by_name.width) < 70 /* 2pt */ &&
+             abs(search_length - temp_by_name.length) < 70) /* 2pt */ ||
+            (abs(search_width - temp.width) < 70 /* 2pt */ &&
+             abs(search_length - temp.length) < 70) /* 2pt */))
+       {
+         /* Found size with the correct dimensions */
+         int match = 0;
+         if (mode == CF_GEN_SIZES_SEARCH_BORDERLESS_ONLY &&
+             borderless == 1)
+         {
+           /* We search only for borderless sizes and have found a match */
+           border_mismatch = 0;
+           min_border_mismatch = 0;
+           if (media_col_entry)
+             *media_col_entry = media_col;
+           match = 1;
+         }
+         else if (mode == CF_GEN_SIZES_SEARCH)
+         {
+           /* We search a size in general, borders are accepted. find the
+              best match in terms of border size */
+           border_mismatch =
+             (long long)(search_left < 0 ? 1 :
+                         (abs(search_left - temp.left) + 1)) *
+             (long long)(search_bottom < 0 ? 1 :
+                         (abs(search_bottom - temp.bottom) + 1)) *
+             (long long)(search_right < 0 ? 1 :
+                         (abs(search_right - temp.right) + 1)) *
+             (long long)(search_top < 0 ? 1 :
+                         (abs(search_top - temp.top) + 1));
+           if (border_mismatch < min_border_mismatch)
+           {
+             min_border_mismatch = border_mismatch;
+             if (media_col_entry)
+               *media_col_entry = media_col;
+             match = 1;
+           }
+         }
+         if (match)
+         {
+           if (width)
+             *width = temp.width;
+           if (length)
+             *length = temp.length;
+           if (left)
+             *left = temp.left;
+           if (bottom)
+             *bottom = temp.bottom;
+           if (right)
+             *right = temp.right;
+           if (top)
+             *top = temp.top;
+           strlcpy(size_name, temp.media, IPP_MAX_NAME);
+         }
+       }
+
+       /* Add size to list */
+       if (sizes && !cupsArrayFind(*sizes, &temp))
+         cupsArrayAdd(*sizes, &temp);
+
+      } else if (ippGetValueTag(x_dim) == IPP_TAG_RANGE ||
+                ippGetValueTag(y_dim) == IPP_TAG_RANGE) {
+       /*
+        * Custom size - record the min/max values...
+        */
+
+       int lower, upper;   /* Range values */
+
+       if (ippGetValueTag(x_dim) == IPP_TAG_RANGE)
+         lower = ippGetRange(x_dim, 0, &upper);
+       else
+         lower = upper = ippGetInteger(x_dim, 0);
+
+       if (min_width && lower < *min_width)
+         *min_width = lower;
+       if (max_width && upper > *max_width)
+         *max_width = upper;
+
+       if (ippGetValueTag(y_dim) == IPP_TAG_RANGE)
+         lower = ippGetRange(y_dim, 0, &upper);
+       else
+         lower = upper = ippGetInteger(y_dim, 0);
+
+       if (min_length && lower < *min_length)
+         *min_length = lower;
+       if (max_length && upper > *max_length)
+         *max_length = upper;
+      }
+    }
+    if (min_border_mismatch < LLONG_MAX)
+    {
+      /* If we have found a matching page size in the media-col-database
+        we stop searching */
+      min_border_mismatch = 0;
+    }
+  }
+  if ((attr = ippFindAttribute(response, "media-size-supported",
+                              IPP_TAG_BEGIN_COLLECTION)) != NULL) {
+    for (i = 0, count = ippGetCount(attr); i < count; i ++) {
+      cups_size_t temp;   /* Current size */
+
+      media_size  = ippGetCollection(attr, i);
+      x_dim       = ippFindAttribute(media_size, "x-dimension", IPP_TAG_ZERO);
+      y_dim       = ippFindAttribute(media_size, "y-dimension", IPP_TAG_ZERO);
+      pwg         = pwgMediaForSize(ippGetInteger(x_dim, 0),
+                                   ippGetInteger(y_dim, 0));
+
+      if (pwg) {
+       if (!sizes && mode == CF_GEN_SIZES_DEFAULT)
+         continue;
+
+       temp.width  = pwg->width;
+       temp.length = pwg->length;
+       temp.left   = *custom_left;
+       temp.bottom = *custom_bottom;
+       temp.right  = *custom_right;
+       temp.top    = *custom_top;
+
+       psname = (pwg->ppd != NULL ? pwg->ppd : pwg->pwg);
+       if (temp.bottom == 0 && temp.left == 0 && temp.right == 0 &&
+           temp.top == 0)
+       {
+         snprintf(temp.media, sizeof(temp.media), "%s.Borderless", psname);
+         borderless = 1;
+       }
+       else
+       {
+         strlcpy(temp.media, psname, sizeof(temp.media));
+         borderless = 0;
+       }
+
+       /* Check whether this size matches our search criteria */
+       if (mode != CF_GEN_SIZES_DEFAULT &&
+           min_border_mismatch > 0 &&
+           search_width > 0 && search_length > 0 &&
+           abs(search_width - temp.width) < 70 /* 2pt */ &&
+           abs(search_length - temp.length) < 70 /* 2pt */)
+       {
+         /* Found size with the correct dimensions */
+         if (mode != CF_GEN_SIZES_SEARCH_BORDERLESS_ONLY ||
+             borderless == 1)
+         {
+           /* We accept the entry just by the size dimensions as
+              "media-size-supported" has no per-size margin info */
+           if (width)
+             *width = temp.width;
+           if (length)
+             *length = temp.length;
+           if (left)
+             *left = temp.left;
+           if (bottom)
+             *bottom = temp.bottom;
+           if (right)
+             *right = temp.right;
+           if (top)
+             *top = temp.top;
+           strlcpy(size_name, temp.media, IPP_MAX_NAME);
+           /* Found it, stop searching */
+           min_border_mismatch = 0;
+         }
+       }
+
+       if (sizes && !cupsArrayFind(*sizes, &temp))
+         cupsArrayAdd(*sizes, &temp);
+      } else if (ippGetValueTag(x_dim) == IPP_TAG_RANGE ||
+                ippGetValueTag(y_dim) == IPP_TAG_RANGE) {
+       /*
+        * Custom size - record the min/max values...
+        */
+
+       int lower, upper;   /* Range values */
+
+       if (ippGetValueTag(x_dim) == IPP_TAG_RANGE)
+         lower = ippGetRange(x_dim, 0, &upper);
+       else
+         lower = upper = ippGetInteger(x_dim, 0);
+
+       if (min_width && lower < *min_width)
+         *min_width = lower;
+       if (max_width && upper > *max_width)
+         *max_width = upper;
+
+       if (ippGetValueTag(y_dim) == IPP_TAG_RANGE)
+         lower = ippGetRange(y_dim, 0, &upper);
+       else
+         lower = upper = ippGetInteger(y_dim, 0);
+
+       if (min_length && lower < *min_length)
+         *min_length = lower;
+       if (max_length && upper > *max_length)
+         *max_length = upper;
+      }
+    }
+  }
+  if ((attr = ippFindAttribute(response, "media-supported", IPP_TAG_ZERO))
+      != NULL) {
+    for (i = 0, count = ippGetCount(attr); i < count; i ++) {
+      const char  *pwg_size = ippGetString(attr, i, NULL);
+      /* PWG size name */
+      cups_size_t temp, *temp2; /* Current size, found size */
+
+      if ((pwg = pwgMediaForPWG(pwg_size)) != NULL) {
+        if (strstr(pwg_size, "_max_") || strstr(pwg_size, "_max.")) {
+          if (max_width && pwg->width > *max_width)
+            *max_width = pwg->width;
+          if (max_length && pwg->length > *max_length)
+            *max_length = pwg->length;
+        } else if (strstr(pwg_size, "_min_") || strstr(pwg_size, "_min.")) {
+          if (min_width && pwg->width < *min_width)
+            *min_width = pwg->width;
+          if (min_length && pwg->length < *min_length)
+            *min_length = pwg->length;
+        } else {
+         if (!sizes && mode == CF_GEN_SIZES_DEFAULT)
+           continue;
+
+         temp.width  = pwg->width;
+         temp.length = pwg->length;
+         temp.left   = *custom_left;
+         temp.bottom = *custom_bottom;
+         temp.right  = *custom_right;
+         temp.top    = *custom_top;
+
+         psname = (pwg->ppd != NULL ? pwg->ppd : pwg->pwg);
+         if (temp.bottom == 0 && temp.left == 0 && temp.right == 0 &&
+             temp.top == 0)
+           snprintf(temp.media, sizeof(temp.media), "%s.Borderless", psname);
+         else
+           strlcpy(temp.media, psname, sizeof(temp.media));
+
+         /* Add the printer's original IPP name to an already found size */
+         if (sizes)
+         {
+           if ((temp2 = cupsArrayFind(*sizes, &temp)) != NULL) {
+             snprintf(temp2->media + strlen(temp2->media),
+                      sizeof(temp2->media) - strlen(temp2->media),
+                      " %s", pwg_size);
+             /* Check if we have also a borderless version of the size and add
+                the original IPP name also there */
+             snprintf(temp.media, sizeof(temp.media), "%s.Borderless", psname);
+             if ((temp2 = cupsArrayFind(*sizes, &temp)) != NULL)
+               snprintf(temp2->media + strlen(temp2->media),
+                        sizeof(temp2->media) - strlen(temp2->media),
+                        " %s", pwg_size);
+           } else
+             cupsArrayAdd(*sizes, &temp);
+         }
+       }
+      }
+    }
+  }
+  if (mode != CF_GEN_SIZES_DEFAULT && min_border_mismatch > 0 &&
+      search_width > 0 && search_length > 0 &&
+      *min_width >= 0 && *min_length >= 0 &&
+      *max_width >= *min_width && *max_length >= *min_length &&
+      *custom_left >= 0 && *custom_bottom >= 0 &&
+      *custom_right >= 0 && *custom_top >= 0)
+  {
+    /* Do we have support for a custom page size and have valid size ranges for
+       it? Check whether the size we are searching for can go as custom size */
+    if (search_width >= *min_width - 70 /* 2pt */ &&
+       search_width <= *max_width + 70 /* 2pt */ &&
+       search_length >= *min_length - 70 /* 2pt */ &&
+       search_length <= *max_length + 70 /* 2pt */)
+    {
+      if (width)
+       *width = (search_width < *min_width ? *min_width :
+                 (search_width > *max_width ? *max_width : search_width));
+      if (length)
+       *length = (search_length < *min_length ? *min_length :
+                  (search_length > *max_length ? *max_length : search_length));
+      if (left) *left = *custom_left;
+      if (bottom) *bottom = *custom_bottom;
+      if (right) *right = *custom_right;
+      if (top) *top = *custom_top;
+      min_border_mismatch = 0;
+    }
+  }
+  if (mode != CF_GEN_SIZES_DEFAULT && min_border_mismatch > 0)
+  {
+    /* Size not found */
+    if (width) *width = 0;
+    if (length) *length = 0;
+    if (left) *left = -1;
+    if (bottom) *bottom = -1;
+    if (right) *right = -1;
+    if (top) *top = -1;
+  }
+}
index 899e38cabe874d49d2cf6b23bc880ec9f3f67065..d62a1eda0ab0e590625b24e7a44ead148ef71b56 100644 (file)
 extern "C" {
 #  endif /* __cplusplus */
 
-#ifdef HAVE_CONFIG_H
+/*
+ * Include necessary headers...
+ */
+
 #include <config.h>
-#endif
 
 #include <ctype.h>
+#include <stdio.h>
 #include <stdlib.h>
+#include <time.h>
+#include <math.h>
+
+#if defined(WIN32) || defined(__EMX__)
+#  include <io.h>
+#else
+#  include <unistd.h>
+#  include <fcntl.h>
+#endif /* WIN32 || __EMX__ */
+
 #include <cups/cups.h>
 #include <cups/backend.h>
+#include <cups/raster.h>
 
 #define CF_GET_PRINTER_ATTRIBUTES_LOGSIZE 4 * 65536
 #define CF_GET_PRINTER_ATTRIBUTES_MAX_OUTPUT_LEN 8192
@@ -39,6 +53,11 @@ extern "C" {
 
 extern char cf_get_printer_attributes_log[CF_GET_PRINTER_ATTRIBUTES_LOGSIZE];
 
+
+/*
+ * Types...
+ */
+
 /* Enum of possible driverless options */
 enum cf_driverless_support_modes_e {
   CF_DRVLESS_CHECKERR,      /* Unable to get get-printer-attributes response*/
@@ -49,6 +68,22 @@ enum cf_driverless_support_modes_e {
                               attribute */
 };
 
+/* Data structure for resolution (X x Y dpi) */
+typedef struct cf_res_s {
+  int x, y;
+} cf_res_t;
+
+typedef enum cf_gen_sizes_mode_e {
+  CF_GEN_SIZES_DEFAULT = 0,
+  CF_GEN_SIZES_SEARCH,
+  CF_GEN_SIZES_SEARCH_BORDERLESS_ONLY
+} cf_gen_sizes_mode_t;
+
+
+/*
+ * Prototypes...
+ */
+
 char    *cfResolveURI(const char *raw_uri);
 char    *cfippfindBasedURIConverter(const char *uri ,int is_fax);
 int     cfCheckDriverlessSupport(const char* uri);
@@ -97,6 +132,59 @@ int cfIPPAttrIntValForPrinter(ipp_t *printer_attrs,
                              ipp_t *job_attrs,
                              const char *attr_name,
                              int   *value);
+int cfIPPAttrResolutionForPrinter(ipp_t *printer_attrs, ipp_t *job_attrs,
+                                 const char *attr_name, int *xres, int *yres);
+int cfIPPReverseOutput(ipp_t *printer_attrs, ipp_t *job_attrs);
+
+char            *cfStrFormatd(char *buf, char *bufend, double number,
+                             struct lconv *loc);
+int             cfCompareResolutions(void *resolution_a, void *resolution_b,
+                                    void *user_data);
+void            *cfCopyResolution(void *resolution, void *user_data);
+void            cfFreeResolution(void *resolution, void *user_data);
+cf_res_t        *cfNewResolution(int x, int y);
+cups_array_t    *cfNewResolutionArray();
+cf_res_t        *cfIPPResToResolution(ipp_attribute_t *attr, int index);
+cups_array_t    *cfIPPAttrToResolutionArray(ipp_attribute_t *attr);
+int             cfJoinResolutionArrays(cups_array_t **current,
+                                      cups_array_t **new_arr,
+                                      cf_res_t **current_default,
+                                      cf_res_t **new_default);
+int             cfGetPageDimensions(ipp_t *printer_attrs,
+                                   ipp_t *job_attrs,
+                                   int num_options,
+                                   cups_option_t *options,
+                                   cups_page_header2_t *header,
+                                   int transverse_fit,
+                                   float *width,
+                                   float *height,
+                                   float *left,
+                                   float *bottom,
+                                   float *right,
+                                   float *top,
+                                   char *name,
+                                   ipp_t **media_col_entry);
+void            cfGenerateSizes(ipp_t *response,
+                               cf_gen_sizes_mode_t mode,
+                               cups_array_t **sizes,
+                               ipp_attribute_t **defattr,
+                               int *width,
+                               int *length,
+                               int *left,
+                               int *bottom,
+                               int *right,
+                               int *top,
+                               int *min_width,
+                               int *min_length,
+                               int *max_width,
+                               int *max_length,
+                               int *custom_left,
+                               int *custom_bottom,
+                               int *custom_right,
+                               int *custom_top,
+                               char *size_name,
+                               ipp_t **media_col_entry);
+
 
 #  ifdef __cplusplus
 }
index f8114d2863d91619d9e9499584d571b86c894443..3e60298f7f90ae9aace6e805961bc1bdc2bd0b53 100644 (file)
@@ -12,7 +12,6 @@
  * Contents:
  *
  *   cfLutDelete() - Free the memory used by a lookup table.
- *   cfLutLoad()   - Load a LUT from a PPD file.
  *   cfLutNew()    - Make a lookup table from a list of pixel values.
  */
 
@@ -36,61 +35,6 @@ cfLutDelete(cf_lut_t *lut)           /* I - Lookup table to free */
 }
 
 
-/*
- * 'cfLutLoad()' - Load a LUT from a PPD file.
- */
-
-cf_lut_t *                             /* O - New lookup table */
-cfLutLoad(ppd_file_t *ppd,             /* I - PPD file */
-            const char *colormodel,    /* I - Color model */
-            const char *media,         /* I - Media type */
-            const char *resolution,    /* I - Resolution */
-           const char *ink,            /* I - Ink name */
-           cf_logfunc_t log,       /* I - Log function */
-           void       *ld)             /* I - Log function data */
-{
-  char         name[PPD_MAX_NAME],     /* Attribute name */
-               spec[PPD_MAX_NAME];     /* Attribute spec */
-  ppd_attr_t   *attr;                  /* Attribute */
-  int          nvals;                  /* Number of values */
-  float                vals[4];                /* Values */
-
-
- /*
-  * Range check input...
-  */
-
-  if (!ppd || !colormodel || !media || !resolution || !ink)
-    return (NULL);
-
- /*
-  * Try to find the LUT values...
-  */
-
-  snprintf(name, sizeof(name), "cups%sDither", ink);
-
-  if ((attr = cfFindAttr(ppd, name, colormodel, media, resolution, spec,
-                           sizeof(spec), log, ld)) == NULL)
-    attr = cfFindAttr(ppd, "cupsAllDither", colormodel, media,
-                        resolution, spec, sizeof(spec), log, ld);
-
-  if (!attr)
-    return (NULL);
-
-  vals[0] = 0.0;
-  vals[1] = 0.0;
-  vals[2] = 0.0;
-  vals[3] = 0.0;
-  nvals   = sscanf(attr->value, "%f%f%f", vals + 1, vals + 2, vals + 3) + 1;
-
-  if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "Loaded LUT %s from PPD with values [%.3f %.3f %.3f %.3f]",
-              name, vals[0], vals[1], vals[2], vals[3]);
-
-  return (cfLutNew(nvals, vals, log, ld));
-}
-
-
 /*
  * 'cfLutNew()' - Make a lookup table from a list of pixel values.
  *
index fcfe86ce10334b8ab411e4a265104304df1f5a89..4ecb173e09adf60fceb678204760bc6dc1130e9c 100644 (file)
@@ -33,9 +33,6 @@ MIT Open Source License  -  http://www.opensource.org/
 
 #include <config.h>
 #include <cups/cups.h>
-#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 6)
-#define HAVE_CUPS_1_7 1
-#endif
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -118,9 +115,9 @@ parse_pdf_header_options(FILE *fp, mupdf_page_header *h)
 }
 
 static void
-add_pdf_header_options(mupdf_page_header   *h,
-                      cf_filter_out_format_t outformat,
-                      cups_array_t        *mupdf_args)
+header_to_gs_args(mupdf_page_header *h,
+                 cf_filter_out_format_t outformat,
+                 cups_array_t *mupdf_args)
 {
   char tmpstr[1024];
 
@@ -391,26 +388,25 @@ int
 cfFilterMuPDFToPWG(int inputfd,         /* I - File descriptor input stream */
                   int outputfd,        /* I - File descriptor output stream */
                   int inputseekable,   /* I - Is input stream seekable?
-                                              (unused)*/
+                                              (unused) */
                   cf_filter_data_t *data, /* I - Job and printer data */
-                  void *parameters)    /* I - Filter-specific parameters */
+                  void *parameters)    /* I - Filter-specific parameters
+                                              (unused) */
 {
   cf_filter_out_format_t outformat;
+  char *val;
   char buf[BUFSIZ];
   char *icc_profile = NULL;
   char tmpstr[1024];
   cups_array_t *mupdf_args = NULL;
-  cups_option_t *options = NULL;
   FILE *fp = NULL;
   char infilename[1024];
   mupdf_page_header h;
   int fd = -1;
-  int cm_disabled;
+  int cm_disabled = 0;
   int n;
-  int num_options;
   int empty = 0;
   int status = 1;
-  ppd_file_t *ppd = NULL;
   struct sigaction sa;
   cf_cm_calibration_t cm_calibrate;
   cf_logfunc_t log = data->logfunc;
@@ -419,20 +415,24 @@ cfFilterMuPDFToPWG(int inputfd,         /* I - File descriptor input stream */
   void *icd = data->iscanceleddata;
   cups_cspace_t cspace = -1;
 
-#ifdef HAVE_CUPS_1_7
-  ppd_attr_t *attr;
-#endif /* HAVE_CUPS_1_7 */
-
   (void)inputseekable;
+  (void)parameters;
 
-  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)
+  val = data->final_content_type;
+  if (val)
+  {
+    if (strcasestr(val, "pwg"))
+      outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
+    else if (strcasestr(val, "urf"))
+      outformat = CF_FILTER_OUT_FORMAT_APPLE_RASTER;
+    else if (strcasestr(val, "pclm"))
+      outformat = CF_FILTER_OUT_FORMAT_PCLM;
+    else if (strcasestr(val, "cups"))
+      outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
+    else
       outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
-  } else
+  }
+  else
     outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
 
   if (log) log(ld, CF_LOGLEVEL_DEBUG,
@@ -447,13 +447,6 @@ cfFilterMuPDFToPWG(int inputfd,         /* I - File descriptor input stream */
   sa.sa_handler = SIG_IGN;
   sigaction(SIGPIPE, &sa, NULL);
 
-  num_options = data->num_options;
-
-  ppd = data->ppd;
-  if (ppd) {
-    ppdMarkOptions (ppd, num_options, options);
-  }
-
   fd = cupsTempFd(infilename, 1024);
     if (fd < 0) {
       if(log) log(ld, CF_LOGLEVEL_ERROR, "cfFilterMuPDFToPWG: Can't create temporary file");
@@ -496,24 +489,6 @@ cfFilterMuPDFToPWG(int inputfd,         /* I - File descriptor input stream */
   if (empty == -1)
     goto out;
 
-  /*  Check status of color management in CUPS */
-  cm_calibrate = cfCmGetCupsColorCalibrateMode(data, options, num_options);
-
-  if (cm_calibrate == CF_CM_CALIBRATION_ENABLED)
-    cm_disabled = 1;
-  else 
-    cm_disabled = cfCmIsPrinterCmDisabled(data);
-
-  if (!cm_disabled)
-    cfCmGetPrinterIccProfile(data, &icc_profile, ppd);
-
-/*  Find print-rendering-intent */
-
-    cfGetPrintRenderIntent(data, &h);
-    if(log) log(ld, CF_LOGLEVEL_DEBUG,
-       "Print rendering intent = %s", h.cupsRenderingIntent);
-
-
   /* mutool parameters */
   mupdf_args = cupsArrayNew(NULL, NULL);
   if (!mupdf_args) {
@@ -533,36 +508,13 @@ cfFilterMuPDFToPWG(int inputfd,         /* I - File descriptor input stream */
   /* mutool output parameters */
   cupsArrayAdd(mupdf_args, strdup("-Fpwg"));
 
-  /* Note that MuPDF only creates PWG Raster and never CUPS Raster,
-     so we set the PWG Raster flag in the  cfRasterPrepareHeader() call.
-     This function takes care of generating a completely consistent PWG
-     Raster header then, no extra manipulation needed.
+  /* Note that MuPDF only creates PWG Raster so we select this as header format,
+     We also supply the final output format (to which will be converted with
+     further filters) to determine the correct color space and depth.
      From the header h only cupsWidth/cupsHeight (dimensions in pixels),
      resolution, and color space are used here. */
   cfRasterPrepareHeader(&h, data, outformat,
-                         CF_FILTER_OUT_FORMAT_PWG_RASTER, 1, &cspace);
-
-  if ((h.HWResolution[0] == 100) && (h.HWResolution[1] == 100)) {
-    /* No "Resolution" option */
-    if (ppd && (attr = ppdFindAttr(ppd, "DefaultResolution", 0)) != NULL) {
-      /* "*DefaultResolution" keyword in the PPD */
-      const char *p = attr->value;
-      h.HWResolution[0] = atoi(p);
-      if ((p = strchr(p, 'x')) != NULL)
-       h.HWResolution[1] = atoi(p);
-      else
-       h.HWResolution[1] = h.HWResolution[0];
-      if (h.HWResolution[0] <= 0)
-       h.HWResolution[0] = 300;
-      if (h.HWResolution[1] <= 0)
-       h.HWResolution[1] = h.HWResolution[0];
-    } else {
-      h.HWResolution[0] = 300;
-      h.HWResolution[1] = 300;
-    }
-    h.cupsWidth = h.HWResolution[0] * h.PageSize[0] / 72;
-    h.cupsHeight = h.HWResolution[1] * h.PageSize[1] / 72;
-  }
+                       CF_FILTER_OUT_FORMAT_PWG_RASTER, 1, &cspace);
 
   /* set PDF-specific options */
   parse_pdf_header_options(fp, &h);
@@ -571,8 +523,30 @@ cfFilterMuPDFToPWG(int inputfd,         /* I - File descriptor input stream */
   h.MirrorPrint = CUPS_FALSE;
   h.Orientation = CUPS_ORIENT_0;
 
+  /* Check status of color management in CUPS */
+  cm_calibrate = cfCmGetCupsColorCalibrateMode(data);
+
+  if (cm_calibrate == CF_CM_CALIBRATION_ENABLED)
+    cm_disabled = 1;
+  else
+    cm_disabled = cfCmIsPrinterCmDisabled(data);
+
+  if (!cm_disabled)
+    cfCmGetPrinterIccProfile(data, cfRasterColorSpaceString(h.cupsColorSpace),
+                            h.MediaType, h.HWResolution[0], h.HWResolution[1],
+                            &icc_profile);
+
+  /* Note: No ICC profile support in mutool! */
+
+  /*  Find print-rendering-intent */
+  h.cupsRenderingIntent[0] = '\0';
+  cfGetPrintRenderIntent(data, h.cupsRenderingIntent,
+                        sizeof(h.cupsRenderingIntent));
+  if(log) log(ld, CF_LOGLEVEL_DEBUG,
+             "Print rendering intent = %s", h.cupsRenderingIntent);
+
   /* get all the data from the header and pass it to mutool */
-  add_pdf_header_options (&h, outformat, mupdf_args);
+  header_to_gs_args(&h, outformat, mupdf_args);
 
   snprintf(tmpstr, sizeof(tmpstr), "%s", infilename);
   cupsArrayAdd(mupdf_args, strdup(tmpstr));
index 06fd216b5b4ea3263ca3dcad07062d4f8cc86845..50f9d9b9ffcce4c78be7334b4b6dd262ba41d8c2 100644 (file)
 #include "filter.h"
 #include <cups/raster.h>
 #include <cups/cups.h>
-#include <ppd/ppd.h>
 #include <errno.h>
 #include <qpdf/QPDF.hh>
 #include <qpdf/QPDFObjectHandle.hh>
 #include "image.h"
 #include "bitmap.h"
 #include "raster.h"
-#include <cupsfilters/filter.h>
+#include "filter.h"
+#include "ipp.h"
+
 
 
 #if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 6)
@@ -45,7 +46,6 @@ typedef struct pclmtoraster_data_s
   int numcolors = 0;
   int rowsize = 0;
   cups_page_header2_t header;
-  ppd_file_t *ppd = 0;
   char pageSizeRequested[64];
   int bi_level = 0;
   /* image swapping */
@@ -85,13 +85,10 @@ parse_opts(cf_filter_data_t *data, cf_filter_out_format_t outformat,
   int                  num_options = 0;
   cups_option_t*       options = NULL;
   const char*          t = NULL;
-  ppd_attr_t*          attr;
   const char           *val;
   cf_logfunc_t log = data->logfunc;
   void                 *ld = data->logdata;
-  ppd_file_t           *ppd = pclmtoraster_data->ppd;
   cups_page_header2_t  *header = &(pclmtoraster_data->header);
-  ipp_t                 *printer_attrs = data->printer_attrs;
   cups_cspace_t         cspace = (cups_cspace_t)(-1);
 
 
@@ -103,157 +100,72 @@ parse_opts(cf_filter_data_t *data, cf_filter_out_format_t outformat,
 
   num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
 
-  if (ppd)
+  t = cupsGetOption("media-class", num_options, options);
+  if (t == NULL)
+    t = cupsGetOption("MediaClass", num_options, options);
+  if (t != NULL)
   {
-    if ((attr = ppdFindAttr(ppd,"PWGRaster",0)) != 0 &&
-       (!strcasecmp(attr->value, "true")
-        || !strcasecmp(attr->value, "on") ||
-         !strcasecmp(attr->value, "yes")))
+    if (strcasestr(t, "pwg"))
       pclmtoraster_data->outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
   }
-  else
-  {
-    if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "cfFilterPCLmToRaster: PPD file is not specified.");
-
-    t = cupsGetOption("media-class", num_options, options);
-    if (t == NULL)
-      t = cupsGetOption("MediaClass", num_options, options);
-    if (t != NULL)
-    {
-      if (strcasestr(t, "pwg"))
-       pclmtoraster_data->outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
-    }
-  }
 
   cfRasterPrepareHeader(header, data, outformat, outformat, 0, &cspace);
 
-  if (ppd)
+  if (header->Duplex)
   {
-    if (header->Duplex)
+    int backside;
+    /* analyze options relevant to Duplex */
+    /* APDuplexRequiresFlippedMargin */
+    enum {
+      FM_NO,
+      FM_FALSE,
+      FM_TRUE
+    } flippedMargin = FM_NO;
+
+    backside = cfGetBackSideOrientation(data);
+
+    if (backside >= 0)
     {
-      /* analyze options relevant to Duplex */
-      const char *backside = "";
-      /* APDuplexRequiresFlippedMargin */
-      enum {
-        FM_NO, FM_FALSE, FM_TRUE
-      } flippedMargin = FM_NO;
-
-      attr = ppdFindAttr(ppd,"cupsBackSide",NULL);
-      if (attr != NULL && attr->value != NULL)
-      {
-        ppd->flip_duplex = 0;
-        backside = attr->value;
-      }
-      else if (ppd->flip_duplex)
-      {
-        backside = "Rotated"; /* compatible with Max OS and GS 8.71 */
-      }
-
-      attr = ppdFindAttr(ppd,"APDuplexRequiresFlippedMargin",NULL);
-      if (attr != NULL && attr->value != NULL)
-      {
-        if (strcasecmp(attr->value,"true") == 0)
-       {
-          flippedMargin = FM_TRUE;
-        }
-       else
-       {
-          flippedMargin = FM_FALSE;
-        }
-      }
-      if (strcasecmp(backside,"ManualTumble") == 0 && header->Tumble)
-      {
-        pclmtoraster_data->swap_image_x = pclmtoraster_data->swap_image_y =
-         true;
-        pclmtoraster_data->swap_margin_x = pclmtoraster_data->swap_margin_y =
-         true;
-        if (flippedMargin == FM_TRUE)
-       {
-          pclmtoraster_data->swap_margin_y = false;
-        }
-      }
-      else if (strcasecmp(backside,"Rotated") == 0 && !header->Tumble)
-      {
-        pclmtoraster_data->swap_image_x = pclmtoraster_data->swap_image_y =
-         true;
-        pclmtoraster_data->swap_margin_x = pclmtoraster_data->swap_margin_y =
-         true;
-        if (flippedMargin == FM_TRUE)
-       {
-          pclmtoraster_data->swap_margin_y = false;
-        }
-      }
-      else if (strcasecmp(backside,"Flipped") == 0)
-      {
-        if (header->Tumble)
-       {
-          pclmtoraster_data->swap_image_x = true;
-          pclmtoraster_data->swap_margin_x = pclmtoraster_data->swap_margin_y =
-           true;
-        }
-       else
-       {
-          pclmtoraster_data->swap_image_y = true;
-        }
-        if (flippedMargin == FM_FALSE)
-       {
-          pclmtoraster_data->swap_margin_y =
-           !(pclmtoraster_data->swap_margin_y);
-        }
-      }
-    }
-  } else {
-    int backside = cfGetBackSideAndHeaderDuplex(printer_attrs, header);
-    if(header->Duplex){
-      /* analyze options relevant to Duplex */
-      /* APDuplexRequiresFlippedMargin */
-      enum {
-        FM_NO, FM_FALSE, FM_TRUE
-      } flippedMargin = FM_NO;
+      flippedMargin = (backside & 16 ? FM_TRUE :
+                      (backside & 8 ? FM_FALSE :
+                       FM_NO));
+      backside &= 7;
 
       if (backside==CF_BACKSIDE_MANUAL_TUMBLE && header->Tumble)
       {
-        pclmtoraster_data->swap_image_x = pclmtoraster_data->swap_image_y =
+       pclmtoraster_data->swap_image_x = pclmtoraster_data->swap_image_y =
          true;
-        pclmtoraster_data->swap_margin_x = pclmtoraster_data->swap_margin_y =
+       pclmtoraster_data->swap_margin_x = pclmtoraster_data->swap_margin_y =
          true;
-        if (flippedMargin == FM_TRUE)
-       {
-          pclmtoraster_data->swap_margin_y = false;
-        }
+       if (flippedMargin == FM_TRUE)
+         pclmtoraster_data->swap_margin_y = false;
       }
       else if (backside==CF_BACKSIDE_ROTATED && !header->Tumble)
       {
-        pclmtoraster_data->swap_image_x = pclmtoraster_data->swap_image_y =
+       pclmtoraster_data->swap_image_x = pclmtoraster_data->swap_image_y =
          true;
-        pclmtoraster_data->swap_margin_x = pclmtoraster_data->swap_margin_y =
+       pclmtoraster_data->swap_margin_x = pclmtoraster_data->swap_margin_y =
          true;
-        if (flippedMargin == FM_TRUE)
-       {
-          pclmtoraster_data->swap_margin_y = false;
-        }
+       if (flippedMargin == FM_TRUE)
+         pclmtoraster_data->swap_margin_y = false;
       }
       else if (backside==CF_BACKSIDE_FLIPPED)
       {
-        if (header->Tumble)
+       if (header->Tumble)
        {
-          pclmtoraster_data->swap_image_x = true;
-          pclmtoraster_data->swap_margin_x = pclmtoraster_data->swap_margin_y =
-           true;
-        }
+         pclmtoraster_data->swap_image_x = true;
+         pclmtoraster_data->swap_margin_x =
+           pclmtoraster_data->swap_margin_y = true;
+       }
        else
-       {
-          pclmtoraster_data->swap_image_y = true;
-        }
-        if (flippedMargin == FM_FALSE)
-       {
-          pclmtoraster_data->swap_margin_y =
+         pclmtoraster_data->swap_image_y = true;
+       if (flippedMargin == FM_FALSE)
+         pclmtoraster_data->swap_margin_y =
            !(pclmtoraster_data->swap_margin_y);
-        }
       }
     }
   }
+
   if ((val = cupsGetOption("print-color-mode", num_options, options)) != NULL
                            && !strncasecmp(val, "bi-level", 8))
     pclmtoraster_data->bi_level = 1;
@@ -834,7 +746,7 @@ out_page(cups_raster_t*      raster,        /* I - Raster stream */
   long long            rotate = 0,
                        height,
                        width;
-  double               paperdimensions[2], margins[4], l, swap;
+  float                        paperdimensions[2], margins[4], l, swap;
   int                  bufsize = 0, pixel_count = 0,
                        temp = 0;
   float                mediaBox[4];
@@ -846,7 +758,6 @@ out_page(cups_raster_t*      raster,        /* I - Raster stream */
   QPDFObjectHandle     image;
   QPDFObjectHandle     imgdict;
   QPDFObjectHandle     colorspace_obj;
-  ppd_file_t           *ppd = data->ppd;
 
   // Check if page is rotated.
   if (page.getKey("/Rotate").isInteger())
@@ -879,18 +790,17 @@ out_page(cups_raster_t*    raster,        /* I - Raster stream */
       data->header.PageSize[1] = (unsigned)l;
   }
 
-  // Adjust header page size and margins according to the ppd file.
-  if (ppd)
-  {
-    ppdRasterMatchPPDSize(&(data->header), ppd, margins, paperdimensions, NULL,
-                         NULL);
-    if (data->outformat != CF_FILTER_OUT_FORMAT_CUPS_RASTER)
-      memset(margins, 0, sizeof(margins));
-  }
-  else if(filter_data!=NULL &&(filter_data->printer_attrs)!=NULL)
+  memset(paperdimensions, 0, sizeof(paperdimensions));
+  memset(margins, 0, sizeof(margins));
+  if (filter_data != NULL && (filter_data->printer_attrs) != NULL)
   {
-    cfRasterMatchIPPSize(&(data->header), filter_data, margins, paperdimensions, NULL, NULL);
-    if (data->outformat != CF_FILTER_OUT_FORMAT_CUPS_RASTER)
+    cfGetPageDimensions(filter_data->printer_attrs, filter_data->job_attrs,
+                       filter_data->num_options, filter_data->options,
+                       &(data->header), 0,
+                       &(paperdimensions[0]), &(paperdimensions[1]),
+                       &(margins[0]), &(margins[1]),
+                       &(margins[2]), &(margins[3]), NULL, NULL);
+    if (data->outformat == CF_FILTER_OUT_FORMAT_PWG_RASTER)
       memset(margins, 0, sizeof(margins));
   }
   else
diff --git a/cupsfilters/pdftopdf/pdftopdf-jcl-private.h b/cupsfilters/pdftopdf/pdftopdf-jcl-private.h
deleted file mode 100644 (file)
index 373d3c5..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef _CUPS_FILTERS_PDFTOPDF_PDFTOPDF_JCL_H
-#define _CUPS_FILTERS_PDFTOPDF_PDFTOPDF_JCL_H
-
-struct _cfPDFToPDFProcessingParameters;
-class _cfPDFToPDFProcessor;
-
-void _cfPDFToPDFEmitPreamble(FILE *fp, ppd_file_t *ppd,
-                            const _cfPDFToPDFProcessingParameters &param);
-void _cfPDFToPDFEmitPostamble(FILE *fp, ppd_file_t *ppd,
-                             const _cfPDFToPDFProcessingParameters &param);
-
-void _cfPDFToPDFEmitComment(_cfPDFToPDFProcessor &proc,
-                           const _cfPDFToPDFProcessingParameters &param);
-
-#endif
diff --git a/cupsfilters/pdftopdf/pdftopdf-jcl.cxx b/cupsfilters/pdftopdf/pdftopdf-jcl.cxx
deleted file mode 100644 (file)
index 9d64ea1..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-#include <ctype.h>
-#include "pdftopdf-processor-private.h"
-#include <ppd/ppd.h>
-
-#include <string.h>
-
-// TODO: -currently changes ppd.  (Copies)
-//
-static void emitJCLOptions(FILE *fp, ppd_file_t *ppd, int device_copies) // {{{
-{
-  int section;
-  ppd_choice_t **choices;
-  int i;
-  char buf[1024];
-  ppd_attr_t *attr;
-  bool withJCL=false,
-    datawritten=false;
-
-  if (!ppd) return;
-
-  if ((attr = ppdFindAttr(ppd,"pdftopdfJCLBegin",NULL)) != NULL) {
-    withJCL=true;
-    const int n=strlen(attr->value);
-    for (i = 0;i < n;i++) {
-      if (attr->value[i] == '\r' || attr->value[i] == '\n') {
-        // skip new line
-        continue;
-      }
-      fputc(attr->value[i],fp);
-      datawritten=true;
-    }
-  }
-         
-  snprintf(buf,sizeof(buf),"%d",device_copies);
-  if (ppdFindOption(ppd,"Copies") != NULL) {
-    ppdMarkOption(ppd,"Copies",buf);
-  } else {
-    if ((attr = ppdFindAttr(ppd,"pdftopdfJCLCopies",buf)) != NULL) {
-      fputs(attr->value,fp);
-      datawritten=true;
-    } else if (withJCL) {
-      fprintf(fp,"Copies=%d;",device_copies);
-      datawritten=true;
-    }
-  }
-  for (section = (int)PPD_ORDER_ANY;
-       section <= (int)PPD_ORDER_PROLOG;section++) {
-    int n = ppdCollect(ppd,(ppd_section_t)section,&choices);
-    for (i = 0;i < n;i++) {
-      snprintf(buf,sizeof(buf),"pdftopdfJCL%s",
-              ((ppd_option_t *)(choices[i]->option))->keyword);
-      if ((attr = ppdFindAttr(ppd,buf,choices[i]->choice)) != NULL) {
-        fputs(attr->value,fp);
-        datawritten=true;
-      } else if (withJCL) {
-        fprintf(fp,"%s=%s;",
-               ((ppd_option_t *)(choices[i]->option))->keyword,
-               choices[i]->choice);
-        datawritten=true;
-      }
-    }
-  }
-  if (datawritten) {
-    fputc('\n',fp);
-  }
-}
-// }}}
-
-/* Copied ppd_decode() from CUPS which is not exported to the API; needed in _cfPDFToPDFEmitPreamble() */
-// {{{ static int ppd_decode(char *string) 
-static int                             /* O - Length of decoded string */
-ppd_decode(char *string)               /* I - String to decode */
-{
-  char *inptr,                         /* Input pointer */
-    *outptr;                   /* Output pointer */
-
-  inptr  = string;
-  outptr = string;
-
-  while (*inptr != '\0')
-    if (*inptr == '<' && isxdigit(inptr[1] & 255)) {
-      /*
-       * Convert hex to 8-bit values...
-       */
-
-      inptr ++;
-      while (isxdigit(*inptr & 255)) {
-       if (isalpha(*inptr))
-         *outptr = (tolower(*inptr) - 'a' + 10) << 4;
-       else
-         *outptr = (*inptr - '0') << 4;
-
-       inptr ++;
-
-        if (!isxdigit(*inptr & 255))
-         break;
-
-       if (isalpha(*inptr))
-         *outptr |= tolower(*inptr) - 'a' + 10;
-       else
-         *outptr |= *inptr - '0';
-
-       inptr ++;
-       outptr ++;
-      }
-
-      while (*inptr != '>' && *inptr != '\0')
-       inptr ++;
-      while (*inptr == '>')
-       inptr ++;
-    } else
-      *outptr++ = *inptr++;
-
-  *outptr = '\0';
-
-  return ((int)(outptr - string));
-}
-// }}}
-
-void _cfPDFToPDFEmitPreamble(FILE *fp, ppd_file_t *ppd,
-                 const _cfPDFToPDFProcessingParameters &param) // {{{
-{
-  if (ppd == 0) return;
-
-  ppdEmit(ppd, fp, PPD_ORDER_EXIT);
-
-  if (param.emit_jcl) {
-    /* pdftopdf only adds JCL to the job if the printer is a native PDF
-       printer and the PPD is for this mode, having the "*JCLToPDFInterpreter:"
-       keyword. We need to read this keyword manually from the PPD and replace
-       the content of ppd->jcl_ps by the value of this keyword, so that
-       ppdEmitJCL() actually adds JCL based on the presence on 
-       "*JCLToPDFInterpreter:". */
-    ppd_attr_t *attr;
-    char buf[1024];
-    int devicecopies_done = 0;
-    char *old_jcl_ps = ppd->jcl_ps;
-    /* If there is a "Copies" option in the PPD file, assure that hardware
-       copies are implemented as described by this option */
-    if (ppdFindOption(ppd,"Copies") != NULL &&
-       param.device_copies > 1) {
-      snprintf(buf,sizeof(buf),"%d",param.device_copies);
-      ppdMarkOption(ppd,"Copies",buf);
-      devicecopies_done = 1;
-    }
-    if ((attr=ppdFindAttr(ppd,"JCLToPDFInterpreter",NULL)) != NULL) {
-      if (param.device_copies > 1 && devicecopies_done == 0 && // HW copies
-         strncmp(ppd->jcl_begin, "\033%-12345X@", 10) == 0) { // PJL
-       /* Add a PJL command to implement the hardware copies */
-        const size_t size=strlen(attr->value)+1+30;
-        ppd->jcl_ps=(char *)malloc(size*sizeof(char));
-        if (param.device_collate) {
-          snprintf(ppd->jcl_ps, size, "@PJL SET QTY=%d\n%s",
-                   param.device_copies, attr->value);
-        } else {
-          snprintf(ppd->jcl_ps, size, "@PJL SET COPIES=%d\n%s",
-                   param.device_copies, attr->value);
-        }
-      } else
-       ppd->jcl_ps=strdup(attr->value);
-      ppd_decode(ppd->jcl_ps);
-    } else {
-      ppd->jcl_ps=NULL;
-    }
-    ppdEmitJCL(ppd, fp, param.job_id, param.user, param.title);
-    emitJCLOptions(fp, ppd, param.device_copies);
-    free(ppd->jcl_ps);
-    ppd->jcl_ps = old_jcl_ps; // cups uses pool allocator, not free()
-  }
-}
-// }}}
-
-void _cfPDFToPDFEmitPostamble(FILE *fp, ppd_file_t *ppd,
-                  const _cfPDFToPDFProcessingParameters &param) // {{{
-{
-  if (param.emit_jcl) { 
-    ppdEmitJCLEnd(ppd, fp);
-  }
-}
-// }}}
-
-// pass information to subsequent filters via PDF comments
-void _cfPDFToPDFEmitComment(_cfPDFToPDFProcessor &proc,const _cfPDFToPDFProcessingParameters &param) // {{{
-{
-  std::vector<std::string> output;
-
-  output.push_back("% This file was generated by pdftopdf");
-
-  // This is not standard, but like PostScript. 
-  if (param.device_copies>0) {
-    char buf[256];
-    snprintf(buf,sizeof(buf),"%d",param.device_copies);
-    output.push_back(std::string("%%PDFTOPDFNumCopies : ")+buf);
-
-    if (param.device_collate) {
-      output.push_back("%%PDFTOPDFCollate : true");
-    } else {
-      output.push_back("%%PDFTOPDFCollate : false");
-    }
-  }
-
-  proc.set_comments(output);
-}
-// }}}
index dcd594f56c7a7e69db058e32a97dae3d2ad6771e..6283ffe0d8feb46492fd2adc58d992380e19afb1 100644 (file)
@@ -20,6 +20,7 @@ struct _cfPDFToPDFProcessingParameters {
 _cfPDFToPDFProcessingParameters()
 : job_id(0),num_copies(1),
     user(0),title(0),
+    pagesize_requested(false),
     fitplot(false),
     fillprint(false),  //print-scaling = fill
     cropfit(false),
@@ -47,8 +48,9 @@ _cfPDFToPDFProcessingParameters()
 
     auto_rotate(false),
 
-    emit_jcl(true),device_copies(1),
-    device_collate(false),set_duplex(false),
+    device_copies(1),
+    device_collate(false),
+    set_duplex(false),
 
     page_logging(-1)
   {
@@ -68,6 +70,7 @@ _cfPDFToPDFProcessingParameters()
 
   int job_id, num_copies;
   const char *user, *title; // will stay around
+  bool pagesize_requested;
   bool fitplot;
   bool fillprint;   //print-scaling = fill
   bool cropfit;     // -o crop-to-fit
@@ -101,8 +104,6 @@ _cfPDFToPDFProcessingParameters()
 
   bool auto_rotate;
 
-  // ppd/jcl changes
-  bool emit_jcl;
   int device_copies;
   bool device_collate;
   bool set_duplex;
index fd3343eb93b41eb0d1c7ae22f652053ff65ee91a..2a801469cbb9bc4f03f5f0470fb925c16c28c9b8 100644 (file)
@@ -111,9 +111,6 @@ void _cfPDFToPDFProcessingParameters::dump(pdftopdf_doc_t *doc) const // {{{
                                 "cfFilterPDFToPDF: auto_rotate: %s",
                                 (auto_rotate)?"true":"false");
 
-  if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
-                                "cfFilterPDFToPDF: emit_jcl: %s",
-                                (emit_jcl)?"true":"false");
   if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
                                 "cfFilterPDFToPDF: device_copies: %d",
                                 device_copies);
@@ -174,6 +171,15 @@ bool _cfProcessPDFToPDF(_cfPDFToPDFProcessor &proc,_cfPDFToPDFProcessingParamete
     return false;
   }
 
+  // Certain features require a given page size for the page to be
+  // printed or all pages of the document being the same size. Here we
+  // set param.pagesize_requested so that the default pag size is used
+  // when no size got specified by the user.
+  if (param.fitplot || param.fillprint || param.autoprint || param.autofit ||
+      param.booklet != CF_PDFTOPDF_BOOKLET_OFF ||
+      param.nup.nupX > 1 || param.nup.nupY > 1)
+    param.pagesize_requested = true;
+      
   const bool dst_lscape =
     (param.paper_is_landscape ==
      ((param.orientation == ROT_0) || (param.orientation == ROT_180)));
@@ -199,9 +205,10 @@ bool _cfProcessPDFToPDF(_cfPDFToPDFProcessor &proc,_cfPDFToPDFProcessingParamete
   if (param.booklet!=CF_PDFTOPDF_BOOKLET_OFF) {
     shuffle=_cfPDFToPDFBookletShuffle(numOrigPages,param.book_signature);
     if (param.booklet==CF_PDFTOPDF_BOOKLET_ON) { // override options
-      // TODO? specifically "sides=two-sided-short-edge" / DuplexTumble
+      // We do not "sides=two-sided-short-edge" / DuplexTumble here.
+      // We assume it done by caller, for example ppdFilterLoadPPD() of libppd
       // param.duplex=true;
-      // param.set_duplex=true;  ?    currently done in setFinalPPD()
+      // param.set_duplex=true;
       _cfPDFToPDFNupParameters::preset(2,param.nup); // TODO?! better
     }
   } else { // 0 1 2 3 ...
@@ -291,7 +298,7 @@ bool _cfProcessPDFToPDF(_cfPDFToPDFProcessor &proc,_cfPDFToPDFProcessingParamete
     param.page.top = param.page.height;
   }
 
-  if (param.fillprint || param.cropfit)
+  if (param.pagesize_requested && (param.fillprint || param.cropfit))
   {
     for (int i = 0; i < (int)input_page_range_list.size(); i ++)
     {
@@ -367,6 +374,11 @@ bool _cfProcessPDFToPDF(_cfPDFToPDFProcessor &proc,_cfPDFToPDFProcessingParamete
     _cfPDFToPDFPageRect rect;
     rect = page->get_rect();
     //rect.dump(doc);
+    if (!param.pagesize_requested)
+    {
+      param.page.width = param.page.right = rect.width;
+      param.page.height = param.page.top = rect.height;
+    }
 
     bool newPage = nupstate.mext_page(rect.width, rect.height, pgedit);
     if (newPage)
index 25faf0a40bad2508006527da8b1cfd0ab0a9909f..c8678efe778c9bc4aff392c01e341b17ac4ae0e9 100644 (file)
@@ -7,7 +7,6 @@
 #include <stdio.h>
 #include <assert.h>
 #include <cups/cups.h>
-#include <ppd/ppd.h>
 #if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 6)
 #define HAVE_CUPS_1_7 1
 #endif
 #include <sys/wait.h>
 #include "pdftopdf-private.h"
 #include "cupsfilters/raster.h"
-#include "cupsfilters/ppdgenerator.h"
+#include "cupsfilters/ipp.h"
+#include "cupsfilters/ipp.h"
 #include "pdftopdf-processor-private.h"
-#include "pdftopdf-jcl-private.h"
 
 #include <stdarg.h>
 
 
 // namespace {}
 
-void setFinalPPD(ppd_file_t *ppd,const _cfPDFToPDFProcessingParameters &param)
-{
-  if ((param.booklet==CF_PDFTOPDF_BOOKLET_ON)&&(ppdFindOption(ppd,"Duplex"))) {
-    // TODO: elsewhere, better
-    ppdMarkOption(ppd,"Duplex","DuplexTumble");
-    // TODO? sides=two-sided-short-edge
-  }
-
-  // for compatibility
-  if ((param.set_duplex)&&(ppdFindOption(ppd,"Duplex")!=NULL)) {
-    ppdMarkOption(ppd,"Duplex","True");
-    ppdMarkOption(ppd,"Duplex","On");
-  }
-
-  // we do it, printer should not
-  ppd_choice_t *choice;
-  if ((choice=ppdFindMarkedChoice(ppd,"MirrorPrint")) != NULL) {
-    choice->marked=0;
-  }
-}
-
-// for choice, only overwrites ret if found in ppd
-static bool ppdGetInt(ppd_file_t *ppd,const char *name,int *ret) // {{{
-{
-  assert(ret);
-  ppd_choice_t *choice=ppdFindMarkedChoice(ppd,name); // !ppd is ok.
-  if (choice) {
-    *ret=atoi(choice->choice);
-    return true;
-  }
-  return false;
-}
-// }}}
-
 static bool optGetInt(const char *name,int num_options,cups_option_t *options,int *ret) // {{{
 {
   assert(ret);
@@ -112,87 +77,6 @@ static bool is_true(const char *value) // {{{
 }
 // }}}
 
-static bool ppdGetDuplex(ppd_file_t *ppd) // {{{
-{
-  const char **option, **choice;
-  const char *option_names[] = {
-    "Duplex",
-    "JCLDuplex",
-    "EFDuplex",
-    "KD03Duplex",
-    NULL
-  };
-  const char *choice_names[] = {
-    "DuplexNoTumble",
-    "DuplexTumble",
-    "LongEdge",
-    "ShortEdge",
-    "Top",
-    "Bottom",
-    NULL
-  };
-  for (option = option_names; *option; option ++)
-    for (choice = choice_names; *choice; choice ++)
-      if (ppdIsMarked(ppd, *option, *choice))
-       return 1;
-  return 0;
-}
-// }}}
-
-// TODO: enum
-static bool ppdDefaultOrder(ppd_file_t *ppd, pdftopdf_doc_t *doc) // {{{  -- is reverse?
-{
-  ppd_choice_t *choice;
-  ppd_attr_t *attr;
-  const char *val=NULL;
-
-  // Figure out the right default output order from the PPD file...
-  if ((choice=ppdFindMarkedChoice(ppd,"OutputOrder")) != NULL) {
-    val=choice->choice;
-  } else if (((choice=ppdFindMarkedChoice(ppd,"OutputBin")) != NULL)&&
-            ((attr=ppdFindAttr(ppd,"PageStackOrder",choice->choice)) != NULL)) {
-    val=attr->value;
-  } else if ((attr=ppdFindAttr(ppd,"DefaultOutputOrder",0)) != NULL) {
-    val=attr->value;
-  }
-  if ((!val)||(strcasecmp(val,"Normal")==0)||(strcasecmp(val,"same-order")==0)) {
-    return false;
-  } else if (strcasecmp(val,"Reverse")==0||(strcasecmp(val,"reverse-order")==0)) {
-    return true;
-  }
-
-  if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_ERROR,
-                                "cfFilterPDFToPDF: Unsupported output-order "
-                                "value %s, using 'normal'!",
-                                val);
-  return false;
-}
-// }}}
-
-static bool optGetCollate(int num_options,cups_option_t *options) // {{{
-{
-  if (is_true(cupsGetOption("Collate",num_options,options))) {
-    return true;
-  }
-
-  const char *val=NULL;
-  if ((val=cupsGetOption("multiple-document-handling",num_options,options)) != NULL) {
-   /* This IPP attribute is unnecessarily complicated:
-    *   single-document, separate-documents-collated-copies, single-document-new-sheet:
-    *      -> collate (true)
-    *   separate-documents-uncollated-copies:
-    *      -> can be uncollated (false)
-    */
-    return (strcasecmp(val,"separate-documents-uncollated-copies")!=0);
-  }
-
-  if ((val=cupsGetOption("sheet-collate",num_options,options)) != NULL) {
-    return (strcasecmp(val,"uncollated")!=0);
-  }
-
-  return false;
-}
-// }}}
 
 static bool parsePosition(const char *value,pdftopdf_position_e &xpos,pdftopdf_position_e &ypos) // {{{
 {
@@ -296,26 +180,24 @@ static bool _cfPDFToPDFParseBorder(const char *val,pdftopdf_border_type_e &ret)
 }
 // }}}
 
-void getParameters(cf_filter_data_t *data,int num_options,cups_option_t *options,_cfPDFToPDFProcessingParameters &param,char *final_content_type,pdftopdf_doc_t *doc) // {{{
+void getParameters(cf_filter_data_t *data,int num_options,cups_option_t *options,_cfPDFToPDFProcessingParameters &param,pdftopdf_doc_t *doc) // {{{
 {
-
-  ppd_file_t *ppd = data->ppd;
+  char *final_content_type = data->final_content_type;
   ipp_t *printer_attrs = data->printer_attrs;
-  ipp_attribute_t *ipp;
+  ipp_t *job_attrs = data->job_attrs;
+  ipp_attribute_t *attr;
   const char *val;
    
-  if ((val = cupsGetOption("copies",num_options,options)) != NULL      ||
-       (val = cupsGetOption("Copies", num_options, options))!=NULL     ||
-       (val = cupsGetOption("num-copies", num_options, options))!=NULL ||
-       (val = cupsGetOption("NumCopies", num_options, options))!=NULL) {
+  if ((val = cupsGetOption("copies",num_options, options)) != NULL ||
+      (val = cupsGetOption("Copies", num_options, options)) != NULL ||
+      (val = cupsGetOption("num-copies", num_options, options)) != NULL ||
+      (val = cupsGetOption("NumCopies", num_options, options)) != NULL)
+  {
     int copies = atoi(val);
     if (copies > 0)
       param.num_copies = copies;
   }
-  // param.num_copies initially from commandline
-  if (param.num_copies==1) {
-    ppdGetInt(ppd,"Copies",&param.num_copies);
-  }
+
   if (param.num_copies==0) {
     param.num_copies=1;
   }
@@ -364,11 +246,14 @@ void getParameters(cf_filter_data_t *data,int num_options,cups_option_t *options
     param.autoprint = true;
   }
 
-  if (ppd && (ppd->landscape < 0)) { // direction the printer rotates landscape (90 or -90)
+  // direction the printer rotates landscape
+  // (landscape-orientation-requested-preferred: 4: 90 or 5: -90)
+  if (printer_attrs != NULL &&
+      (attr = ippFindAttribute(printer_attrs, "landscape-orientation-requested-preferred", IPP_TAG_ZERO)) != NULL &&
+      ippGetInteger(attr, 0) == 5)
     param.normal_landscape=ROT_270;
-  } else {
+  else
     param.normal_landscape=ROT_90;
-  }
 
   int ipprot;
   param.orientation=ROT_0;
@@ -395,67 +280,51 @@ void getParameters(cf_filter_data_t *data,int num_options,cups_option_t *options
     param.no_orientation = true;
   }
 
-  ppd_size_t *pagesize;
-  // param.page default is letter, border 36,18
-  if ((pagesize=ppdPageSize(ppd,0)) != NULL) { // "already rotated"
-    param.page.top=pagesize->top;
-    param.page.left=pagesize->left;
-    param.page.right=pagesize->right;
-    param.page.bottom=pagesize->bottom;
-    param.page.width=pagesize->width;
-    param.page.height=pagesize->length;
+  if (printer_attrs != NULL)
+    param.pagesize_requested =
+      (cfGetPageDimensions(printer_attrs, job_attrs, num_options, options, NULL,
+                          0,
+                          &(param.page.width), &(param.page.height),
+                          &(param.page.left), &(param.page.bottom),
+                          &(param.page.right), &(param.page.top),
+                          NULL, NULL) == 1);
+
+  if (param.page.width <= 0 || param.page.height <= 0)
+  {
+    if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_WARN,
+                                  "cfFilterPDFToPDF: Could not determine the output page dimensions, falling back to US Letter format");
+    param.page.width = 612;
+    param.page.height = 792;
   }
-  else 
+  if (param.page.left < 0)
   {
-       if(printer_attrs!=NULL){
-           char defSize[41];
-           int min_length = 99999,
-               max_length = 0,
-               min_width = 99999,
-               max_width = 0,
-               left, right,
-               top, bottom; 
-           cfGenerateSizes(printer_attrs, &ipp, &min_length, &min_width,
-                       &max_length, &max_width, &bottom, &left, &right, &top,
-                       defSize);
-           param.page.top = top* 72.0/2540.0;
-           param.page.bottom = bottom* 72.0/2540.0;
-           param.page.right = right * 72.0/2540.0;
-           param.page.left = left* 72.0/2540.0;
-           param.page.width = min_width*72.0/2540.0;
-           param.page.height = min_length*72.0/2540.0;
-       }
-
-    #ifdef HAVE_CUPS_1_7
-       if ((val = cupsGetOption("media-size", num_options, options)) != NULL ||
-               (val = cupsGetOption("MediaSize", num_options, options)) != NULL ||
-               (val = cupsGetOption("page-size", num_options, options)) != NULL ||
-               (val = cupsGetOption("PageSize", num_options, options)) != NULL) {
-       pwg_media_t *size_found = NULL;
-       if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
-                                       "cfFilterPDFToPDF: Page size from command "
-                                       "line: %s", val);
-       if ((size_found = pwgMediaForPWG(val)) == NULL)
-               if ((size_found = pwgMediaForPPD(val)) == NULL)
-               size_found = pwgMediaForLegacy(val);
-       if (size_found != NULL) {
-               param.page.width = size_found->width * 72.0 / 2540.0;
-               param.page.height = size_found->length * 72.0 / 2540.0;
-               param.page.top=param.page.bottom=36.0;
-               param.page.right=param.page.left=18.0;
-               param.page.right=param.page.width-param.page.right;
-               param.page.top=param.page.height-param.page.top;
-               if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
-                                       "cfFilterPDFToPDF: Width: %f, Length: %f",
-                                       param.page.width, param.page.height);
-       }
-       else
-               if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
-                                       "cfFilterPDFToPDF: Unsupported page size %s.",
-                                       val);
-       }
-    #endif /* HAVE_CUPS_1_7 */
+    if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_WARN,
+                                  "cfFilterPDFToPDF: Could not determine the width of the left margin, falling back to 18 pt/6.35 mm");
+    param.page.left = 18.0;
   }
+  if (param.page.bottom < 0)
+  {
+    if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_WARN,
+                                  "cfFilterPDFToPDF: Could not determine the width of the bottom margin, falling back to 36 pt/12.7 mm");
+    param.page.bottom = 36.0;
+  }
+  if (param.page.right < 0)
+  {
+    if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_WARN,
+                                  "cfFilterPDFToPDF: Could not determine the width of the right margin, falling back to 18 pt/6.35 mm");
+    param.page.right = param.page.width - 18.0;
+  }
+  else
+    param.page.right = param.page.width - param.page.right;
+  if (param.page.top < 0)
+  {
+    if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_WARN,
+                                  "cfFilterPDFToPDF: Could not determine the width of the top margin, falling back to 36 pt/12.7 mm");
+    param.page.top = param.page.height - 36.0;
+  }
+  else
+    param.page.top = param.page.height - param.page.top;
+
   param.paper_is_landscape=(param.page.width>param.page.height);
 
   _cfPDFToPDFPageRect tmp; // borders (before rotation)
@@ -491,9 +360,11 @@ void getParameters(cf_filter_data_t *data,int num_options,cups_option_t *options
 
   param.page.set(tmp); // replace values, where tmp.* != NaN  (because tmp needed rotation, param.page not!)
 
-  if (ppdGetDuplex(ppd)) {
+  if ((val = cfIPPAttrEnumValForPrinter(printer_attrs, job_attrs, "sides")) !=
+      NULL &&
+      strncmp(val, "two-sided-", 10) == 0) {
     param.duplex=true;
-  } else if (is_true(cupsGetOption("Duplex",num_options,options))) {
+  } else if (is_true(cupsGetOption("Duplex", num_options, options))) {
     param.duplex=true;
     param.set_duplex=true;
   } else if ((val=cupsGetOption("sides",num_options,options)) != NULL) {
@@ -544,12 +415,13 @@ void getParameters(cf_filter_data_t *data,int num_options,cups_option_t *options
 
   if ((val=cupsGetOption("OutputOrder",num_options,options)) != NULL ||
       (val=cupsGetOption("output-order",num_options,options)) != NULL ||
-      (val=cupsGetOption("page-delivery",num_options,options)) != NULL) {
+      (val=cupsGetOption("page-delivery",num_options,options)) != NULL)
+  {
     param.reverse = (strcasecmp(val, "Reverse") == 0 ||
                     strcasecmp(val, "reverse-order") == 0);
-  } else if (ppd) {
-    param.reverse=ppdDefaultOrder(ppd, doc);
   }
+  else
+    param.reverse = cfIPPReverseOutput(printer_attrs, job_attrs);
 
   std::string rawlabel;
   char *classification = getenv("CLASSIFICATION");
@@ -593,20 +465,9 @@ void getParameters(cf_filter_data_t *data,int num_options,cups_option_t *options
     parseRanges(val,param.input_page_ranges);
   }
 
-  ppd_choice_t *choice;
-  if ((choice=ppdFindMarkedChoice(ppd,"MirrorPrint")) != NULL) {
-    val=choice->choice;
-  } else {
-    if((val = cupsGetOption("mirror", num_options, options))!=NULL  ||
-       (val = cupsGetOption("mirror-print", num_options, options))!=NULL       ||
-       (val = cupsGetOption("MirrorPrint", num_options, options))!=NULL)
+  if((val = cupsGetOption("mirror", num_options, options)) != NULL ||
+     (val = cupsGetOption("mirror-print", num_options, options)) != NULL)
     param.mirror=is_true(val);
-  }
-  
-
-  if ((val=cupsGetOption("emit-jcl",num_options,options)) != NULL) {
-    param.emit_jcl=!is_false(val)&&(strcmp(val,"0")!=0);
-  }
 
   param.booklet=pdftopdf_booklet_mode_e::CF_PDFTOPDF_BOOKLET_OFF;
   if ((val=cupsGetOption("booklet",num_options,options)) != NULL) {
@@ -641,10 +502,30 @@ void getParameters(cf_filter_data_t *data,int num_options,cups_option_t *options
     }
   }
 
-  param.collate=optGetCollate(num_options,options);
-  // FIXME? pdftopdf also considers if ppdCollate is set (only when cupsGetOption is /not/ given) [and if is_true overrides param.collate=true]  -- pstops does not
+  // Collate
+  if (is_true(cupsGetOption("Collate", num_options, options)))
+    param.collate = true;
+  else if ((val = cupsGetOption("sheet-collate", num_options, options)) != NULL)
+    param.collate = (strcasecmp(val, "uncollated") != 0);
+  else if (((val = cupsGetOption("multiple-document-handling",
+                                num_options, options)) != NULL &&
+           (strcasecmp(val, "separate-documents-collated-copies") == 0 ||
+            strcasecmp(val, "separate-documents-uncollated-copies") == 0 ||
+            strcasecmp(val, "single-document") == 0 ||
+            strcasecmp(val, "single-document-new-sheet") == 0)) ||
+          (val = cfIPPAttrEnumValForPrinter(printer_attrs, job_attrs,
+                                            "multiple-document-handling")) !=
+          NULL)
+   /* This IPP attribute is unnecessarily complicated:
+    *   single-document, separate-documents-collated-copies, single-document-new-sheet:
+    *      -> collate (true)
+    *   separate-documents-uncollated-copies:
+    *      -> can be uncollated (false)
+    */
+    param.collate =
+      (strcasecmp(val, "separate-documents-uncollated-copies") != 0);
 
-/*
+  /*
   // TODO: scaling
   // TODO: natural-scaling
 
@@ -661,24 +542,14 @@ void getParameters(cf_filter_data_t *data,int num_options,cups_option_t *options
     naturalScaling = atoi(val) * 0.01;
   }
 
-bool checkFeature(const char *feature, int num_options, cups_option_t *options) // {{{
-{
-  const char *val;
-  ppd_attr_t *attr;
-
-  return ((val=cupsGetOption(feature,num_options,options)) != NULL && is_true(val)) ||
-         ((attr=ppdFindAttr(ppd,feature,0)) != NULL && is_true(attr->val));
-}
-// }}}
-*/
+  */
 
   // make pages a multiple of two (only considered when duplex is on).
   // i.e. printer has hardware-duplex, but needs pre-inserted filler pages
   // FIXME? pdftopdf also supports it as cmdline option (via checkFeature())
-  ppd_attr_t *attr;
-  if ((attr=ppdFindAttr(ppd,"cupsEvenDuplex",0)) != NULL) {
-    param.even_duplex=is_true(attr->value);
-  }
+  param.even_duplex =
+    (param.duplex &&
+     is_true(cupsGetOption("even-duplex", num_options, options)));
 
   // TODO? pdftopdf* ?
   // TODO?! pdftopdfAutoRotate
@@ -693,258 +564,136 @@ bool checkFeature(const char *feature, int num_options, cups_option_t *options)
   // printer driver) does page logging in the /var/log/cups/page_log file
   // by outputting "PAGE: <# of current page> <# of copies>" to stderr.
 
-  // pdftopdf would have to do this only for PDF printers as in this case
-  // pdftopdf is the last filter, but some of the other filters are not
-  // able to do the logging because they do not have access to the number
-  // of pages of the file to be printed, so pdftopdf overtakes their logging
-  // duty.
-
-  // The filters currently are:
-  // - foomatic-rip (lets Ghostscript convert PDF to printer's format via
-  //   built-in drivers, no access to the PDF content)
-  // - gstopxl (uses Ghostscript, like foomatic-rip)
-  // - *toraster on IPP Everywhere printers (then *toraster gets the last
-  //   filter, the case if FINAL_CONTENT_TYPE env var is "image/pwg-raster")
-  // - hpps (bug)
-
-  // Check whether page logging is forced or suppressed by the command line
-  if ((val=cupsGetOption("page-logging",num_options,options)) != NULL) {
+  // cfFilterPDFToPDF() would have to do this only for PDF printers as
+  // in this case cfFilterPDFToPDF() is the last filter, but some of
+  // the other filters are not able to do the logging because they do
+  // not have access to the number of pages of the file to be printed,
+  // so cfFilterPDFToPDF() overtakes their logging duty.
+
+  // Check whether page logging is forced or suppressed by the options
+  if ((val = cupsGetOption("pdf-filter-page-logging",
+                          num_options, options)) != NULL) {
     if (strcasecmp(val,"auto") == 0) {
       param.page_logging = -1;
       if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
                                     "cfFilterPDFToPDF: Automatic page logging "
-                                    "selected by command line.");
+                                    "selected by options.");
     } else if (is_true(val)) {
       param.page_logging = 1;
       if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
-                                    "cfFilterPDFToPDF: Forced page logging selected "
-                                    "by command line.");
+                                    "cfFilterPDFToPDF: Forced page logging "
+                                    "selected by options.");
     } else if (is_false(val)) {
       param.page_logging = 0;
       if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
-                                    "cfFilterPDFToPDF: Suppressed page logging "
-                                    "selected by command line.");
+                                    "cfFilterPDFToPDF: Suppressed page "
+                                    "logging selected by options.");
     } else {
       if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_ERROR,
-                                    "cfFilterPDFToPDF: Unsupported page-logging "
-                                    "value %s, using page-logging=auto!",val);
+                                    "cfFilterPDFToPDF: Unsupported page "
+                                    "logging setting "
+                                    "\"pdf-filter-page-logging=%s\", "
+                                    "using \"auto\"!", val);
       param.page_logging = -1;
     }
   }
 
   if (param.page_logging == -1) {
-    // Determine the last filter in the chain via cupsFilter(2) lines of the
-    // PPD file and FINAL_CONTENT_TYPE
-    if (!ppd) {
-      // If PPD file is not specified, we determine whether to log pages or not
-      // using FINAL_CONTENT_TYPE env variable. log pages only when FINAL_CONTENT_TYPE is
-      // either pdf or raster
-       
-        if (final_content_type && (strcasestr(final_content_type, "/pdf") ||
-       strcasestr(final_content_type, "/vnd.cups-pdf") ||
-       strcasestr(final_content_type, "/pwg-raster")))
-             param.page_logging = 1;
-       else
-             param.page_logging = 0;   
-       // If final_content_type is not clearly available we are not sure whether to log pages or not
-       if((char*)final_content_type==NULL || 
-               sizeof(final_content_type)==0 || 
-               final_content_type[0]=='\0'){
-           param.page_logging = -1;     
-       }
-       if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
-               "cfFilterPDFToPDF: No PPD file specified,  "
-               "determined whether to log pages or "
-               "not using final_content_type env variable.");
-               doc->logfunc(doc->logdata,CF_LOGLEVEL_DEBUG,"final_content_type = %s page_logging=%d",final_content_type?final_content_type:"NULL",param.page_logging);
-    } else {
-      char *lastfilter = NULL;
-      if (final_content_type == NULL) {
-       // No FINAL_CONTENT_TYPE env variable set, we cannot determine
-       // whether we have to log pages, so do not log.
-       param.page_logging = 0;
-       if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
-                                      "cfFilterPDFToPDF: No FINAL_CONTENT_TYPE "
-                                      "environment variable, could not "
-                                      "determine whether to log pages or "
-                                      "not, so turned off page logging.");
-      // Proceed depending on number of cupsFilter(2) lines in PPD
-      } else if (ppd->num_filters == 0) {
-       // No filter line, manufacturer-supplied PostScript PPD
-       // In this case cfFilterPSToPS, called by cfFilterPDFToPS, does the logging
-       param.page_logging = 0;
-      } else if (ppd->num_filters == 1) {
-       // One filter line, so this one filter is the last filter
-       lastfilter = ppd->filters[0];
-      } else {
-       // More than one filter line, determine the one which got
-       // actually used via FINAL_CONTENT_TYPE
-       ppd_attr_t *ppd_attr;
-       if ((ppd_attr = ppdFindAttr(ppd, "cupsFilter2", NULL)) != NULL) {
-         // We have cupsFilter2 lines, use only these
-         do {
-           // Go to the second work, which is the destination MIME type
-           char *p = ppd_attr->value;
-           while (!isspace(*p)) p ++;
-           while (isspace(*p)) p ++;
-           // Compare with FINAL_CONTEN_TYPE
-           if (!strncasecmp(final_content_type, p,
-                            strlen(final_content_type))) {
-             lastfilter = ppd_attr->value;
-             break;
-           }
-         } while ((ppd_attr = ppdFindNextAttr(ppd, "cupsFilter2", NULL))
-                  != NULL);
-       } else {
-         // We do not have cupsFilter2 lines, use the cupsFilter lines
-         int i;
-         for (i = 0; i < ppd->num_filters; i ++) {
-           // Compare source MIME type (first word) with FINAL_CONTENT_TYPE
-           if (!strncasecmp(final_content_type, ppd->filters[i],
-                            strlen(final_content_type))) {
-             lastfilter = ppd->filters[i];
-             break;
-           }
-         }
-       }
-      }
-      if (param.page_logging == -1) {
-       if (lastfilter) {
-         // Get the name of the last filter, without mime type and cost
-         char *p = lastfilter;
-         char *q = p + strlen(p) - 1;
-         while(!isspace(*q) && *q != '/') q --;
-         lastfilter = q + 1;
-         // Check whether we have to log
-         if (!strcasecmp(lastfilter, "-")) {
-           // No filter defined in the PPD
-           // If output data (FINAL_CONTENT_TYPE) is PDF, pdftopdf is last
-           // filter (PDF printer) and has to log
-           // If output data (FINAL_CONTENT_TYPE) is PWG Raster, *toraster is
-           // last filter (IPP Everywhere printer) and pdftopdf has to log
-           if (strcasestr(final_content_type, "/pdf") ||
-               strcasestr(final_content_type, "/vnd.cups-pdf") ||
-               strcasestr(final_content_type, "/pwg-raster"))
-             param.page_logging = 1;
-           else
-             param.page_logging = 0;
-         } else if (!strcasecmp(lastfilter, "pdftopdf")) {
-           // pdftopdf is last filter (PDF printer)
-           param.page_logging = 1;
-         } else if (!strcasecmp(lastfilter, "gstopxl")) {
-           // gstopxl is last filter, this is a Ghostscript-based filter
-           // without access to the pages of the file to be printed, so we
-           // log the pages
-           param.page_logging = 1;
-         } else if (!strcasecmp(lastfilter + strlen(lastfilter) - 8,
-                                "toraster") ||
-                    !strcasecmp(lastfilter + strlen(lastfilter) - 5,
-                                "topwg")) {
-           // On IPP Everywhere printers which accept PWG Raster data one
-           // of gstoraster, cfFilterPDFToRaster, or mupdftopwg is the last
-           // filter. These filters do not log pages so pdftopdf has to
-           // do it
-           param.page_logging = 1;
-         } else if (!strcasecmp(lastfilter, "foomatic-rip")) {
-           // foomatic-rip is last filter, foomatic-rip is mainly used as
-           // Ghostscript wrapper to use Ghostscript's built-in printer
-           // drivers. Here there is also no access to the pages so that we
-           // delegate the logging to pdftopdf
-           param.page_logging = 1;
-         } else if (!strcasecmp(lastfilter, "hpps")) {
-           // hpps is last filter, hpps is part of HPLIP and it is a bug that
-           // it does not do the page logging.
-           param.page_logging = 1;
-         } else {
-           // All the other filters log pages as expected.
-           param.page_logging = 0;
-         }
-       } else {
-         if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_ERROR,
-                                        "cfFilterPDFToPDF: Last filter could not "
-                                        "get determined, page logging turned "
-                                        "off.");
-         param.page_logging = 0;
-       }
-      }
-      if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
-                                    "cfFilterPDFToPDF: Last filter determined by the "
-                                    "PPD: %s; FINAL_CONTENT_TYPE: "
-                                    "%s => pdftopdf will %slog pages in "
-                                    "page_log.",
-                                    (lastfilter ? lastfilter : "None"),
-                                    (final_content_type ? final_content_type :
-                                     "(not supplied)"),
-                                    (param.page_logging == 0 ? "not " : ""));
+    // We determine whether to log pages or not
+    // using the output data MIME type. log pages only when the output is
+    // either pdf or PWG Raster
+    if (final_content_type &&
+       (strcasestr(final_content_type, "/pdf") ||
+        strcasestr(final_content_type, "/vnd.cups-pdf") ||
+        strcasestr(final_content_type, "/pwg-raster")))
+      param.page_logging = 1;
+    else
+      param.page_logging = 0;
+
+    // If final_content_type is not clearly available we are not sure whether
+    // to log pages or not
+    if((char*)final_content_type==NULL ||
+       sizeof(final_content_type)==0 ||
+       final_content_type[0]=='\0'){
+      param.page_logging = -1;
+    }
+    if (doc->logfunc)
+    {
+      doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
+                  "cfFilterPDFToPDF: Determined whether to "
+                  "log pages or not using output data type.");
+      doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
+                  "final_content_type = %s => page_logging = %d",
+                  final_content_type ? final_content_type : "NULL",
+                  param.page_logging);
     }
+    if (param.page_logging == -1)
+      param.page_logging = 0;
   }
 }
 // }}}
 
-static bool printerWillCollate(ppd_file_t *ppd) // {{{
+void calculate(int num_options,
+              cups_option_t *options,
+              _cfPDFToPDFProcessingParameters &param,
+              char *final_content_type) // {{{
 {
-  ppd_choice_t *choice;
-
-  if (((choice=ppdFindMarkedChoice(ppd,"Collate")) != NULL)&&
-      (is_true(choice->choice))) {
-
-    // printer can collate, but also for the currently marked ppd features?
-    ppd_option_t *opt=ppdFindOption(ppd,"Collate");
-    return (opt)&&(!opt->conflicted);
+  const char       *val;
+  bool             hw_copies = false,
+                   hw_collate = false;
+
+
+  // Check options for caller's instructions about hardware copies/collate
+  if ((val = cupsGetOption("hardware-copies",
+                          num_options, options)) != NULL)
+    // Use hardware copies according to the caller's instructions
+    hw_copies = is_true(val);
+  else
+    // Caller did not tell us whether the printer does Hardware copies
+    // or not, so we assume hardware copies on PDF printers, and software
+    // copies on other (usually raster) printers or if we do not know the
+    // final output format.
+    hw_copies = (final_content_type &&
+                (strcasestr(final_content_type, "/pdf") ||
+                 strcasestr(final_content_type, "/vnd.cups-pdf")));
+  if (hw_copies)
+  {
+    if ((val = cupsGetOption("hardware-collate",
+                           num_options, options)) != NULL)
+      // Use hardware collate according to the caller's instructions
+      hw_collate = is_true(val);
+    else
+      // Check output format MIME type whether it is
+      // of a driverless IPP printer (PDF, Apple Raster, PWG Raster, PCLm).
+      // These printers do always hardware collate if they do hardware copies.
+      // https://github.com/apple/cups/issues/5433
+      hw_collate = (final_content_type &&
+                   (strcasestr(final_content_type, "/pdf") ||
+                    strcasestr(final_content_type, "/vnd.cups-pdf") ||
+                    strcasestr(final_content_type, "/pwg-raster") ||
+                    strcasestr(final_content_type, "/urf") ||
+                    strcasestr(final_content_type, "/PCLm")));
   }
-  return false;
-}
-// }}}
-
-void calculate(cf_filter_data_t *data,_cfPDFToPDFProcessingParameters &param,char *final_content_type) // {{{
-{
-  ppd_file_t *ppd = data->ppd;
-  int num_options = 0;
-  cups_option_t *options = NULL;
-  num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
-  if (param.reverse)
+  
+  if (param.reverse && param.duplex)
     // Enable even_duplex or the first page may be empty.
     param.even_duplex=true; // disabled later, if non-duplex
 
-  setFinalPPD(ppd,param);
-
   if (param.num_copies==1) {
     param.device_copies=1;
     // collate is never needed for a single copy
     param.collate=false; // (does not make a big difference for us)
-  } else if ((ppd)&&(!ppd->manual_copies)) { // hw copy generation available
+  } else if (hw_copies) { // hw copy generation available
     param.device_copies=param.num_copies;
     if (param.collate) { // collate requested by user
-      // Check output format (FINAL_CONTENT_TYPE env variable) whether it is
-      // of a driverless IPP printer (PDF, Apple Raster, PWG Raster, PCLm).
-      // These printers do always hardware collate if they do hardware copies.
-      // https://github.com/apple/cups/issues/5433
-      if (final_content_type &&
-         (strcasestr(final_content_type, "/pdf") ||
-          strcasestr(final_content_type, "/vnd.cups-pdf") ||
-          strcasestr(final_content_type, "/pwg-raster") ||
-          strcasestr(final_content_type, "/urf") ||
-          strcasestr(final_content_type, "/PCLm"))) {
-       param.device_collate = true;
-      } else {
-       // check collate device, with current/final(!) ppd settings
-       param.device_collate=printerWillCollate(ppd);
-       if (!param.device_collate) {
-         // printer can't hw collate -> we must copy collated in sw
-         param.device_copies=1;
-       }
+      param.device_collate = hw_collate;
+      if (!param.device_collate) {
+       // printer can't hw collate -> we must copy collated in sw
+       param.device_copies=1;
       }
     } // else: printer copies w/o collate and takes care of duplex/even_duplex
   }
-  else if(final_content_type &&
-       ((strcasestr(final_content_type, "/pdf"))  ||
-       (strcasestr(final_content_type, "/vnd.cups-pdf")))){
-    param.device_copies = param.num_copies;
-    if(param.collate){
-       param.device_collate = true;
-    }
-  }
- else { // sw copies
+  else { // sw copies
     param.device_copies=1;
     if (param.duplex) { // &&(num_copies>1)
       // sw collate + even_duplex must be forced to prevent copies on the backsides
@@ -953,23 +702,15 @@ void calculate(cf_filter_data_t *data,_cfPDFToPDFProcessingParameters &param,cha
     }
   }
 
-  // TODO? FIXME:  unify code with emitJCLOptions, which does this "by-hand" now (and makes this code superfluous)
-  if (param.device_copies==1) {
-    // make sure any hardware copying is disabled
-    ppdMarkOption(ppd,"Copies","1");
-    ppdMarkOption(ppd,"JCLCopies","1");
-  } else { // hw copy
+  if (param.device_copies != 1) //hw copy
     param.num_copies=1; // disable sw copy
-  }
 
-  if ((param.collate)&&(!param.device_collate)) { // software collate
-    ppdMarkOption(ppd,"Collate","False"); // disable any hardware-collate (in JCL)
+  if (param.duplex &&
+      param.collate && !param.device_collate) // software collate
     param.even_duplex=true; // fillers always needed
-  }
 
-  if (!param.duplex) {
+  if (!param.duplex)
     param.even_duplex=false;
-  }
 }
 // }}}
 
@@ -1038,10 +779,10 @@ cfFilterPDFToPDF(int inputfd,         /* I - File descriptor input stream */
         int outputfd,        /* I - File descriptor output stream */
         int inputseekable,   /* I - Is input stream seekable? */
         cf_filter_data_t *data, /* I - Job and printer data */
-        void *parameters)    /* I - Filter-specific parameters */
+        void *parameters)    /* I - Filter-specific parameters (unused) */
 {
   pdftopdf_doc_t     doc;         /* Document information */
-  char               *final_content_type = NULL;
+  char               *final_content_type = data->final_content_type;
   FILE               *inputfp,
                      *outputfp;
   const char         *t;
@@ -1054,10 +795,7 @@ cfFilterPDFToPDF(int inputfd,         /* I - File descriptor input stream */
   void               *icd = data->iscanceleddata;
   int num_options = 0;
   cups_option_t *options = NULL;
-  num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
 
-  if (parameters)
-    final_content_type = (char *)parameters;
 
   try {
     _cfPDFToPDFProcessingParameters param;
@@ -1075,9 +813,11 @@ cfFilterPDFToPDF(int inputfd,         /* I - File descriptor input stream */
     doc.iscanceledfunc = iscanceled;
     doc.iscanceleddata = icd;
 
-    getParameters(data, num_options, options, param, final_content_type, &doc);
+    num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
 
-    calculate(data, param, final_content_type);
+    getParameters(data, num_options, options, param, &doc);
+
+    calculate(num_options, options, param, final_content_type);
 
 #ifdef DEBUG
     param.dump(&doc);
@@ -1096,6 +836,8 @@ cfFilterPDFToPDF(int inputfd,         /* I - File descriptor input stream */
                     "cfFilterPDFToPDF: Streaming mode: No PDF processing, only adding of JCL");
     }
 
+    cupsFreeOptions(num_options, options);
+
     std::unique_ptr<_cfPDFToPDFProcessor> proc(_cfPDFToPDFFactory::processor());
 
     if ((inputseekable && inputfd > 0) || streaming) {
@@ -1128,28 +870,30 @@ cfFilterPDFToPDF(int inputfd,         /* I - File descriptor input stream */
        return 2;
 
       // Pass information to subsequent filters via PDF comments
-      _cfPDFToPDFEmitComment(*proc, param);
-    }
+      std::vector<std::string> output;
+
+      output.push_back("% This file was generated by pdftopdf");
+
+      // This is not standard, but like PostScript. 
+      if (param.device_copies > 0)
+      {
+       char buf[256];
+       snprintf(buf, sizeof(buf), "%d", param.device_copies);
+       output.push_back(std::string("%%PDFTOPDFNumCopies : ")+buf);
+
+       if (param.device_collate)
+         output.push_back("%%PDFTOPDFCollate : true");
+       else
+         output.push_back("%%PDFTOPDFCollate : false");
+      }
 
-    /* TODO
-    // color management
-    --- PPD:
-      copyPPDLine_(fp_dest, fp_src, "*PPD-Adobe: ");
-      copyPPDLine_(fp_dest, fp_src, "*cupsICCProfile ");
-      copyPPDLine_(fp_dest, fp_src, "*Manufacturer:");
-      copyPPDLine_(fp_dest, fp_src, "*ColorDevice:");
-      copyPPDLine_(fp_dest, fp_src, "*DefaultColorSpace:");
-    if (cupsICCProfile) {
-      proc.add_cm(...,...);
+      proc->set_comments(output);
     }
-    */
 
     outputfp = fdopen(outputfd, "w");
     if (outputfp == NULL)
       return 1;
 
-    _cfPDFToPDFEmitPreamble(outputfp, data->ppd, param); // ppdEmit, JCL stuff
-
     if (!streaming) {
       // Pass on the processed input data
       proc->emit_file(outputfp, &doc, CF_PDFTOPDF_WILL_STAY_ALIVE);
@@ -1164,7 +908,6 @@ cfFilterPDFToPDF(int inputfd,         /* I - File descriptor input stream */
       fclose(inputfp);
     }
 
-    _cfPDFToPDFEmitPostamble(outputfp, data->ppd,param);
     fclose(outputfp);
   } catch (std::exception &e) {
     // TODO? exception type
index 089d8e1dbc93edba8f8bd55111c32b09d656974d..1f8601305633d02373f9ce77ee30176f0d0a2bef 100644 (file)
@@ -32,6 +32,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include "colormanager.h"
 #include "image.h"
 #include "filter.h"
+#include "ipp.h"
 #include <config.h>
 #include <cups/cups.h>
 #if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 6)
@@ -46,7 +47,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #ifdef HAVE_CPP_POPPLER_VERSION_H
 #include <poppler/cpp/poppler-version.h>
 #endif
-#include <ppd/ppd.h>
 #include <stdarg.h>
 #include <cups/raster.h>
 #include <cupsfilters/image.h>
@@ -118,7 +118,6 @@ typedef struct pdftoraster_doc_s
   unsigned int bitspercolor;
   unsigned int popplerNumColors; 
   unsigned int bitmapoffset[2];
-  ppd_file_t *ppd = 0;
   poppler::document *poppler_doc;
   cups_page_header2_t header;
   cf_logfunc_t logfunc;             /* Logging function, NULL for no
@@ -260,55 +259,17 @@ static void lcms_error_handler(cmsContext contextId, cmsUInt32Number ErrorCode,
 }
 #endif
 
-static void handle_requires_page_region(pdftoraster_doc_t*doc) {
-  ppd_choice_t *mf;
-  ppd_choice_t *is;
-  ppd_attr_t *rregions = NULL;
-  ppd_size_t *size;
-
-  if ((size = ppdPageSize(doc->ppd,NULL)) == NULL) return;
-  mf = ppdFindMarkedChoice(doc->ppd,"ManualFeed");
-  if ((is = ppdFindMarkedChoice(doc->ppd,"InputSlot")) != NULL) {
-    rregions = ppdFindAttr(doc->ppd,"RequiresPageRegion",is->choice);
-  }
-  if (rregions == NULL) {
-    rregions = ppdFindAttr(doc->ppd,"RequiresPageRegion","All");
-  }
-  if (!strcasecmp(size->name,"Custom") || (!mf && !is) ||
-      (mf && !strcasecmp(mf->choice,"False") &&
-       (!is || (is->code && !is->code[0]))) ||
-      (!rregions && doc->ppd->num_filters > 0)) {
-    ppdMarkOption(doc->ppd,"PageSize",size->name);
-  } else if (rregions && rregions->value
-      && !strcasecmp(rregions->value,"True")) {
-    ppdMarkOption(doc->ppd,"PageRegion",size->name);
-  } else {
-    ppd_choice_t *page;
-
-    if ((page = ppdFindMarkedChoice(doc->ppd,"PageSize")) != NULL) {
-      page->marked = 0;
-      cupsArrayRemove(doc->ppd->marked,page);
-    }
-    if ((page = ppdFindMarkedChoice(doc->ppd,"PageRegion")) != NULL) {
-      page->marked = 0;
-      cupsArrayRemove(doc->ppd->marked, page);
-    }
-  }
-}
-
 static int parse_opts(cf_filter_data_t *data,
-                    cf_filter_out_format_t outformat,
-                    pdftoraster_doc_t *doc)
+                     cf_filter_out_format_t outformat,
+                     pdftoraster_doc_t *doc)
 {
   int num_options = 0;
   cups_option_t *options = NULL;
   char *profile = NULL;
   const char *t = NULL;
-  ppd_attr_t *attr;
   const char *val;
   cf_logfunc_t log = data->logfunc;
   void *ld = data ->logdata;
-  ipp_t *printer_attrs = data->printer_attrs;
   cups_cspace_t cspace = (cups_cspace_t)(-1);
 
   if (outformat == CF_FILTER_OUT_FORMAT_PWG_RASTER ||
@@ -317,185 +278,115 @@ static int parse_opts(cf_filter_data_t *data,
 
   num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
 
-  doc->ppd = data->ppd;
-
-  if (doc->ppd)
-    handle_requires_page_region(doc);
-  else
-    if (log) log(ld, CF_LOGLEVEL_DEBUG,
-      "cfFilterPDFToRaster: PPD file is not specified.");
-
+  memset(&(doc->header), 0, sizeof(doc->header));
   cfRasterPrepareHeader(&(doc->header), data, outformat,
                          (outformat == CF_FILTER_OUT_FORMAT_PWG_RASTER ||
                           outformat == CF_FILTER_OUT_FORMAT_APPLE_RASTER ?
                           outformat : CF_FILTER_OUT_FORMAT_CUPS_RASTER), 0,
                          &cspace);
 
-  if (doc->ppd) {
-    attr = ppdFindAttr(doc->ppd,"pdftorasterRenderingIntent",NULL);
-    if (attr != NULL && attr->value != NULL) {
-      if (strcasecmp(attr->value,"PERCEPTUAL") == 0) {
-       doc->colour_profile.renderingIntent = INTENT_PERCEPTUAL;
-      } else if (strcasecmp(attr->value,"RELATIVE_COLORIMETRIC") == 0) {
-       doc->colour_profile.renderingIntent = INTENT_RELATIVE_COLORIMETRIC;
-      } else if (strcasecmp(attr->value,"SATURATION") == 0) {
-       doc->colour_profile.renderingIntent = INTENT_SATURATION;
-      } else if (strcasecmp(attr->value,"ABSOLUTE_COLORIMETRIC") == 0) {
-       doc->colour_profile.renderingIntent = INTENT_ABSOLUTE_COLORIMETRIC;
-      }
-    }
-    if (doc->header.Duplex) {
-      /* analyze options relevant to Duplex */
-      const char *backside = "";
-      /* APDuplexRequiresFlippedMargin */
-      enum {
-       FM_NO, FM_FALSE, FM_TRUE
-      } flippedMargin = FM_NO;
-
-      attr = ppdFindAttr(doc->ppd,"cupsBackSide",NULL);
-      if (attr != NULL && attr->value != NULL) {
-       doc->ppd->flip_duplex = 0;
-       backside = attr->value;
-      } else if (doc->ppd->flip_duplex) {
-       backside = "Rotated"; /* compatible with Max OS and GS 8.71 */
-      }
-
-      attr = ppdFindAttr(doc->ppd,"APDuplexRequiresFlippedMargin",NULL);
-      if (attr != NULL && attr->value != NULL) {
-       if (strcasecmp(attr->value,"true") == 0) {
-         flippedMargin = FM_TRUE;
-       } else {
-         flippedMargin = FM_FALSE;
-       }
-      }
-      if (strcasecmp(backside,"ManualTumble") == 0 && doc->header.Tumble) {
-       doc->swap_image_x = doc->swap_image_y = true;
-       doc->swap_margin_x = doc->swap_margin_y = true;
-       if (flippedMargin == FM_TRUE) {
-         doc->swap_margin_y = false;
-       }
-      } else if (strcasecmp(backside,"Rotated") == 0 && !doc->header.Tumble) {
-       doc->swap_image_x = doc->swap_image_y = true;
-       doc->swap_margin_x = doc->swap_margin_y = true;
-       if (flippedMargin == FM_TRUE) {
-         doc->swap_margin_y = false;
-       }
-      } else if (strcasecmp(backside,"Flipped") == 0) {
-       if (doc->header.Tumble) {
-         doc->swap_image_x = true;
-         doc->swap_margin_x = doc->swap_margin_y = true;
-       } else {
-         doc->swap_image_y = true;
-       }
-       if (flippedMargin == FM_FALSE) {
-         doc->swap_margin_y = !doc->swap_margin_y;
-       }
-      }
-    }
-
-    /* support the CUPS "cm-calibration" option */
-    doc->colour_profile.cm_calibrate = cfCmGetCupsColorCalibrateMode(data, options, num_options);
-
-    if (doc->colour_profile.cm_calibrate == CF_CM_CALIBRATION_ENABLED)
-      doc->colour_profile.cm_disabled = 1;
-    else
-      doc->colour_profile.cm_disabled = cfCmIsPrinterCmDisabled(data);
-
-    if (!doc->colour_profile.cm_disabled)
-      cfCmGetPrinterIccProfile(data, &profile, doc->ppd);
-
-    if (profile != NULL) {
-      doc->colour_profile.colorProfile = cmsOpenProfileFromFile(profile,"r");
-      free(profile);
-    }
-
-    if ((attr = ppdFindAttr(doc->ppd,"PWGRaster",0)) != 0 &&
-       (!strcasecmp(attr->value, "true")
-        || !strcasecmp(attr->value, "on") ||
-        !strcasecmp(attr->value, "yes")))
-      doc->pwgraster = 1;
-  } else {
+  t = cupsGetOption("media-class", num_options, options);
+  if (t == NULL)
+    t = cupsGetOption("MediaClass", num_options, options);
+  if (t != NULL && strcasestr(t, "pwg"))
     doc->pwgraster = 1;
-    t = cupsGetOption("media-class", num_options, options);
-    if (t == NULL)
-      t = cupsGetOption("MediaClass", num_options, options);
-    if (t != NULL)
+  else
+    doc->pwgraster = 0;
+
+  doc->header.cupsRenderingIntent[0] = '\0';
+  cfGetPrintRenderIntent(data, doc->header.cupsRenderingIntent,
+                        sizeof(doc->header.cupsRenderingIntent));
+  if (strcasecmp(doc->header.cupsRenderingIntent, "PERCEPTUAL") == 0)
+    doc->colour_profile.renderingIntent = INTENT_PERCEPTUAL;
+  else if (strcasecmp(doc->header.cupsRenderingIntent, "RELATIVE") == 0)
+    doc->colour_profile.renderingIntent = INTENT_RELATIVE_COLORIMETRIC;
+  else if (strcasecmp(doc->header.cupsRenderingIntent, "SATURATION") == 0)
+    doc->colour_profile.renderingIntent = INTENT_SATURATION;
+  else if (strcasecmp(doc->header.cupsRenderingIntent, "ABSOLUTE") == 0)
+    doc->colour_profile.renderingIntent = INTENT_ABSOLUTE_COLORIMETRIC;
+    // XXX relative-bpc ???
+
+  if(log) log(ld, CF_LOGLEVEL_DEBUG,
+             "Print rendering intent = %s", doc->header.cupsRenderingIntent);
+
+  if (doc->header.Duplex)
+  {
+    int backside;
+    /* analyze options relevant to Duplex */
+    /* APDuplexRequiresFlippedMargin */
+    enum {
+      FM_NO,
+      FM_FALSE,
+      FM_TRUE
+    } flippedMargin;
+
+    backside = cfGetBackSideOrientation(data);
+
+    if (backside >= 0)
     {
-      if (strcasestr(t, "pwg"))
-       doc->pwgraster = 1;
-      else
-       doc->pwgraster = 0;
-    }
-    cfGetPrintRenderIntent(data, &(doc->header));
-    if(strcasecmp(doc->header.cupsRenderingIntent, "PERCEPTUAL")==0){
-       doc->colour_profile.renderingIntent = INTENT_PERCEPTUAL;
-    } else if (strcasecmp(doc->header.cupsRenderingIntent,"RELATIVE") == 0) {
-       doc->colour_profile.renderingIntent = INTENT_RELATIVE_COLORIMETRIC;
-    } else if (strcasecmp(doc->header.cupsRenderingIntent,"SATURATION") == 0) {
-       doc->colour_profile.renderingIntent = INTENT_SATURATION;
-    } else if (strcasecmp(doc->header.cupsRenderingIntent,"ABSOLUTE") == 0) {
-       doc->colour_profile.renderingIntent = INTENT_ABSOLUTE_COLORIMETRIC;
-    }
-    if(log) log(ld, CF_LOGLEVEL_DEBUG,
-       "Print rendering intent = %s", doc->header.cupsRenderingIntent);
-    
-    int backside = cfGetBackSideAndHeaderDuplex(printer_attrs, &(doc->header));
-    if (doc->header.Duplex) {
-      /* analyze options relevant to Duplex */
-      /* APDuplexRequiresFlippedMargin */
-      enum {
-       FM_NO, FM_FALSE, FM_TRUE
-      } flippedMargin = FM_NO;
-
-      if (backside == CF_BACKSIDE_MANUAL_TUMBLE && doc->header.Tumble) {
+      flippedMargin = (backside & 16 ? FM_TRUE :
+                      (backside & 8 ? FM_FALSE :
+                       FM_NO));
+      backside &= 7;
+
+      if (backside == CF_BACKSIDE_MANUAL_TUMBLE && doc->header.Tumble)
+      {
        doc->swap_image_x = doc->swap_image_y = true;
        doc->swap_margin_x = doc->swap_margin_y = true;
-       if (flippedMargin == FM_TRUE) {
+       if (flippedMargin == FM_TRUE)
          doc->swap_margin_y = false;
-       }
-      } else if (backside==CF_BACKSIDE_ROTATED && !doc->header.Tumble) {
+      }
+      else if (backside==CF_BACKSIDE_ROTATED && !doc->header.Tumble)
+      {
        doc->swap_image_x = doc->swap_image_y = true;
        doc->swap_margin_x = doc->swap_margin_y = true;
-       if (flippedMargin == FM_TRUE) {
+       if (flippedMargin == FM_TRUE)
          doc->swap_margin_y = false;
-       }
-      } else if (backside==CF_BACKSIDE_FLIPPED) {
-       if (doc->header.Tumble) {
+      }
+      else if (backside==CF_BACKSIDE_FLIPPED)
+      {
+       if (doc->header.Tumble)
+       {
          doc->swap_image_x = true;
          doc->swap_margin_x = doc->swap_margin_y = true;
-       } else {
-         doc->swap_image_y = true;
        }
-       if (flippedMargin == FM_FALSE) {
+       else
+         doc->swap_image_y = true;
+       if (flippedMargin == FM_FALSE)
          doc->swap_margin_y = !doc->swap_margin_y;
-       }
       }
     }
+  }
 
-    /* support the CUPS "cm-calibration" option */
-    doc->colour_profile.cm_calibrate = cfCmGetCupsColorCalibrateMode(data, options, num_options);
+  /* support the CUPS "cm-calibration" option */
+  doc->colour_profile.cm_calibrate = cfCmGetCupsColorCalibrateMode(data);
 
-    if (doc->colour_profile.cm_calibrate == CF_CM_CALIBRATION_ENABLED)
-      doc->colour_profile.cm_disabled = 1;
-    else
-      doc->colour_profile.cm_disabled = cfCmIsPrinterCmDisabled(data);
+  if (doc->colour_profile.cm_calibrate == CF_CM_CALIBRATION_ENABLED)
+    doc->colour_profile.cm_disabled = 1;
+  else
+    doc->colour_profile.cm_disabled = cfCmIsPrinterCmDisabled(data);
 
-    if (!doc->colour_profile.cm_disabled)
-      cfCmGetPrinterIccProfile(data, &profile, doc->ppd);
+  if (!doc->colour_profile.cm_disabled)
+    cfCmGetPrinterIccProfile
+      (data,
+       cfRasterColorSpaceString(doc->header.cupsColorSpace),
+       doc->header.MediaType,
+       doc->header.HWResolution[0], doc->header.HWResolution[1],
+       &profile);
 
-    if (profile != NULL) {
-      doc->colour_profile.colorProfile = cmsOpenProfileFromFile(profile,"r");
-      free(profile);
-    }
+  if (profile != NULL)
+  {
+    doc->colour_profile.colorProfile = cmsOpenProfileFromFile(profile,"r");
+    free(profile);
   }
+
   if ((val = cupsGetOption("print-color-mode", num_options, options)) != NULL
                            && !strncasecmp(val, "bi-level", 8))
     doc->bi_level = 1;
   if (log) log(ld, CF_LOGLEVEL_DEBUG,
     "cfFilterPDFToRaster: Page size requested: %s", doc->header.cupsPageSizeName);
 
-  if (num_options)
-    cupsFreeOptions(num_options, options);
+  cupsFreeOptions(num_options, options);
 
   return (0);
 }
@@ -954,7 +845,7 @@ static unsigned char *convert_line_plane_swap(unsigned char *src,
   return dst;
 }
 
-/* Handle special cases which appear in Gutenprint's PPDs */
+/* Handle special cases which appear in the Gutenprint driver */
 static bool select_special_case(pdftoraster_doc_t* doc, conversion_function_t* convert)
 {
   int i;
@@ -1231,12 +1122,14 @@ static unsigned char *remove_alpha(unsigned char *src, unsigned char *dst, unsig
 }
 
 static void write_page_image(cups_raster_t *raster, pdftoraster_doc_t *doc,
-  int pageNo, conversion_function_t* convert, cf_filter_iscanceledfunc_t iscanceled, void *icd)
+                            int pageNo, conversion_function_t* convert, float overspray_factor, cf_filter_iscanceledfunc_t iscanceled, void *icd)
 {
+  int i;
   convert_line_func convertLine;
   unsigned char *lineBuf = NULL;
   unsigned char *dp;
   unsigned int rowsize;
+  int fakeres[2];
 
   if (iscanceled && iscanceled(icd))
     return;
@@ -1246,6 +1139,18 @@ static void write_page_image(cups_raster_t *raster, pdftoraster_doc_t *doc,
   pr.set_render_hint(poppler::page_renderer::antialiasing, true);
   pr.set_render_hint(poppler::page_renderer::text_antialiasing, true);
 
+  // Overspray borderless page size: If the dimensions of the page
+  // size are up to 10% larger than the ones of the input page, zoom
+  // the image by rendering with an appropriately larger fake
+  // resolution.
+  poppler::page_box_enum box = poppler::page_box_enum::crop_box;
+  poppler::rectf inputPageBox = current_page->page_rect(box);
+  for (i = 0; i < 2; i ++)
+    fakeres[i] = doc->header.HWResolution[i];
+  if (overspray_factor != 1.0)
+    for (i = 0; i < 2; i ++)
+      fakeres[i] = (int)(fakeres[i] * overspray_factor);
+
   unsigned char *colordata,*newdata,*graydata,*onebitdata;
   unsigned int pixel_count;
   poppler::image im;
@@ -1255,7 +1160,7 @@ static void write_page_image(cups_raster_t *raster, pdftoraster_doc_t *doc,
    case CUPS_CSPACE_K:  // Black
    case CUPS_CSPACE_SW: // sGray
     if(doc->header.cupsBitsPerColor==1){ // Special case for 1-bit colorspaces
-      im = pr.render_page(current_page,doc->header.HWResolution[0],doc->header.HWResolution[1],doc->bitmapoffset[0],doc->bitmapoffset[1],(doc->bytesPerLine)*8,doc->header.cupsHeight);
+      im = pr.render_page(current_page,fakeres[0],fakeres[1],doc->bitmapoffset[0],doc->bitmapoffset[1],(doc->bytesPerLine)*8,doc->header.cupsHeight);
     newdata = (unsigned char *)malloc(sizeof(char)*3*im.width()*im.height());
     newdata = remove_alpha((unsigned char *)im.const_data(),newdata,im.width(),im.height());
     graydata=(unsigned char *)malloc(sizeof(char)*im.width()*im.height());
@@ -1266,7 +1171,8 @@ static void write_page_image(cups_raster_t *raster, pdftoraster_doc_t *doc,
     rowsize=doc->bytesPerLine;
     }
     else{
-      im = pr.render_page(current_page,doc->header.HWResolution[0],doc->header.HWResolution[1],doc->bitmapoffset[0],doc->bitmapoffset[1],doc->header.cupsWidth,doc->header.cupsHeight);
+      
+      im = pr.render_page(current_page,fakeres[0],fakeres[1],doc->bitmapoffset[0],doc->bitmapoffset[1],doc->header.cupsWidth,doc->header.cupsHeight);
       newdata = (unsigned char *)malloc(sizeof(char)*3*im.width()*im.height());
       newdata = remove_alpha((unsigned char *)im.const_data(),newdata,im.width(),im.height());
       pixel_count=im.width()*im.height();
@@ -1284,7 +1190,7 @@ static void write_page_image(cups_raster_t *raster, pdftoraster_doc_t *doc,
    case CUPS_CSPACE_CMY:
    case CUPS_CSPACE_RGBW:
    default:
-   im = pr.render_page(current_page,doc->header.HWResolution[0],doc->header.HWResolution[1],doc->bitmapoffset[0],doc->bitmapoffset[1],doc->header.cupsWidth,doc->header.cupsHeight);
+   im = pr.render_page(current_page,fakeres[0],fakeres[1],doc->bitmapoffset[0],doc->bitmapoffset[1],doc->header.cupsWidth,doc->header.cupsHeight);
    newdata = (unsigned char *)malloc(sizeof(char)*3*im.width()*im.height());
    newdata = remove_alpha((unsigned char *)im.const_data(),newdata,im.width(),im.height());
    pixel_count=im.width()*im.height();
@@ -1335,18 +1241,19 @@ static int out_page(pdftoraster_doc_t *doc, int pageNo, cf_filter_data_t *data,
   cups_raster_t *raster, conversion_function_t *convert, cf_logfunc_t log, void* ld, cf_filter_iscanceledfunc_t iscanceled, void *icd)
 {
   int rotate = 0;
-  double paperdimensions[2], /* Physical size of the paper */
+  float paperdimensions[2], /* Physical size of the paper */
     margins[4];        /* Physical margins of print */
   double l, swap;
   int imageable_area_fit = 0;
+  float overspray_factor = 1.0;
   int i;
 
   if (iscanceled && iscanceled(icd))
     return (0);
 
   poppler::page *current_page =doc->poppler_doc->create_page(pageNo-1);
-  poppler::page_box_enum box = poppler::page_box_enum::media_box;
-  poppler::rectf mediaBox = current_page->page_rect(box);
+  poppler::page_box_enum box = poppler::page_box_enum::crop_box;
+  poppler::rectf inputPageBox = current_page->page_rect(box);
   poppler::page::orientation_enum orient = current_page->orientation();
   switch (orient) {
     case poppler::page::landscape: rotate=90;
@@ -1358,35 +1265,84 @@ static int out_page(pdftoraster_doc_t *doc, int pageNo, cf_filter_data_t *data,
      default:rotate=0;
   }
   if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "cfFilterPDFToRaster: mediabox = [ %f %f %f %f ]; rotate = %d",
-              mediaBox.left(), mediaBox.top(), mediaBox.right(),
-              mediaBox.bottom(), rotate);
-  l = mediaBox.width();
+              "cfFilterPDFToRaster: cropbox = [ %f %f %f %f ]; rotate = %d",
+              inputPageBox.left(), inputPageBox.top(), inputPageBox.right(),
+              inputPageBox.bottom(), rotate);
+  // Enter input page dimensions in header, so that if no page size got
+  // specified for the job, the input size gets used via the header
+  l = inputPageBox.width();
   if (l < 0) l = -l;
   if (rotate == 90 || rotate == 270)
-    doc->header.PageSize[1] = (unsigned)l;
+    doc->header.cupsPageSize[1] = l;
   else
-    doc->header.PageSize[0] = (unsigned)l;
-  l = mediaBox.height();
+    doc->header.cupsPageSize[0] = l;
+  l = inputPageBox.height();
   if (l < 0) l = -l;
   if (rotate == 90 || rotate == 270)
-    doc->header.PageSize[0] = (unsigned)l;
+    doc->header.cupsPageSize[0] = l;
+  else
+    doc->header.cupsPageSize[1] = l;
+  if (rotate == 90 || rotate == 270)
+  {
+    doc->header.cupsImagingBBox[0] =
+      doc->header.cupsPageSize[0] - inputPageBox.bottom();
+    doc->header.cupsImagingBBox[1] = inputPageBox.right();
+    doc->header.cupsImagingBBox[2] =
+      doc->header.cupsPageSize[0] - inputPageBox.top();
+    doc->header.cupsImagingBBox[3] = inputPageBox.left();
+  }
   else
-    doc->header.PageSize[1] = (unsigned)l;
+  {
+    doc->header.cupsImagingBBox[0] = inputPageBox.left();
+    doc->header.cupsImagingBBox[1] =
+      doc->header.cupsPageSize[1] - inputPageBox.bottom();
+    doc->header.cupsImagingBBox[2] = inputPageBox.right();
+    doc->header.cupsImagingBBox[3] =
+      doc->header.cupsPageSize[1] - inputPageBox.top();
+  }
+  for (i = 0; i < 2; i ++)
+    doc->header.PageSize[i] = (unsigned)(doc->header.cupsPageSize[i]);
+  for (i = 0; i < 4; i ++)
+    doc->header.ImagingBoundingBox[i] =
+      (unsigned)(doc->header.cupsImagingBBox[i]);
 
   memset(paperdimensions, 0, sizeof(paperdimensions));
   memset(margins, 0, sizeof(margins));
-  if (doc->ppd) {
-    ppdRasterMatchPPDSize(&(doc->header), doc->ppd, margins, paperdimensions, &imageable_area_fit, NULL);
+  if (data != NULL && (data->printer_attrs) != NULL)
+  {
+    i = cfGetPageDimensions(data->printer_attrs, data->job_attrs,
+                           data->num_options, data->options,
+                           &(doc->header), 0,
+                           &(paperdimensions[0]), &(paperdimensions[1]),
+                           &(margins[0]), &(margins[1]),
+                           &(margins[2]), &(margins[3]), NULL, NULL);
+    // Overspray borderless page size: If the dimensions of the page
+    // size are up to 10% larger than the ones of the input page, zoom
+    // the image by rendering with an appropriately larger fake
+    // resolution.
+    if (i == 1 && // User-requested page size or size of the input
+                 // page (if user did not request a page size) was
+                 // fitting one of the printer
+       margins[0] == 0 && margins[1] == 0 &&
+       margins[2] == 0 && margins[3] == 0 && // Borderless only
+       paperdimensions[0] > (int)(doc->header.cupsPageSize[0]) &&
+       paperdimensions[0] <= (int)(doc->header.cupsPageSize[0] * 1.10) &&
+       paperdimensions[1] > (int)(doc->header.cupsPageSize[1]) &&
+       paperdimensions[1] <= (int)(doc->header.cupsPageSize[1] * 1.10))
+    {
+      float factor0, factor1;
+      factor0 = paperdimensions[0] / doc->header.cupsPageSize[0];
+      factor1 = paperdimensions[1] / doc->header.cupsPageSize[1];
+      overspray_factor = (factor0 > factor1 ? factor0 : factor1);
+      if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                  "cfFilterPDFToRaster: Zoom factor for borderless printing with overspray: %f",
+                  overspray_factor);
+    }
     if (doc->pwgraster == 1)
       memset(margins, 0, sizeof(margins));
-  } else if(data!=NULL && (data->printer_attrs)!=NULL) {
-       cfRasterMatchIPPSize(&(doc->header), data, margins, paperdimensions, &imageable_area_fit, NULL);
-       if(doc->pwgraster==1){
-         memset(margins, 0, sizeof(margins));
-       }
   }
-  else {
+  else
+  {
     for (i = 0; i < 2; i ++)
       paperdimensions[i] = doc->header.PageSize[i];
     if (doc->header.cupsImagingBBox[3] > 0.0) {
@@ -1463,6 +1419,20 @@ static int out_page(pdftoraster_doc_t *doc, int pageNo, cf_filter_data_t *data,
   if (doc->header.cupsColorOrder == CUPS_ORDER_BANDED) {
     doc->header.cupsBytesPerLine *= doc->header.cupsNumColors;
   }
+
+  if (log) log(ld,CF_LOGLEVEL_DEBUG,
+              "cfFilterPDFToRaster: Page %d: Dimensions: %fx%f; Bounding box: %f %f %f %f",
+              pageNo,
+              doc->header.cupsPageSize[0], doc->header.cupsPageSize[1],
+              doc->header.cupsImagingBBox[0],
+              doc->header.cupsImagingBBox[1],
+              doc->header.cupsImagingBBox[2],
+              doc->header.cupsImagingBBox[3]);
+  if (log) log(ld,CF_LOGLEVEL_DEBUG,
+              "cfFilterPDFToRaster: Page %d: Pixel dimensions: %dx%d; Bitmap offsets: %d %d",
+              pageNo, doc->header.cupsWidth, doc->header.cupsHeight,
+              doc->bitmapoffset[0], doc->bitmapoffset[1]);
+
   if (!cupsRasterWriteHeader2(raster,&(doc->header))) {
     if (log) log(ld,CF_LOGLEVEL_ERROR,
                 "cfFilterPDFToRaster: Cannot write page %d header", pageNo);
@@ -1470,7 +1440,7 @@ static int out_page(pdftoraster_doc_t *doc, int pageNo, cf_filter_data_t *data,
   }
 
   /* write page image */
-  write_page_image(raster,doc,pageNo, convert, iscanceled, icd);
+  write_page_image(raster,doc,pageNo, convert, overspray_factor, iscanceled, icd);
   return (0);
 }
 
@@ -1565,8 +1535,9 @@ int cfFilterPDFToRaster(int inputfd,         /* I - File descriptor input stream
        int outputfd,                 /* I - File descriptor output stream */
        int inputseekable,            /* I - Is input stream seekable? (unused)*/
        cf_filter_data_t *data,          /* I - Job and printer data */
-       void *parameters)             /* I - Filter-specific parameters */
+       void *parameters)             /* I - Filter-specific parameters(unused)*/
 {
+  const char *val;
   cf_filter_out_format_t outformat;
   pdftoraster_doc_t doc;
   int i;
@@ -1583,23 +1554,30 @@ int cfFilterPDFToRaster(int inputfd,         /* I - File descriptor input stream
   int ret = 0;
 
   (void)inputseekable;
+  (void)parameters;
+
   cmsSetLogErrorHandler(lcms_error_handler);
 
+  val = data->final_content_type;
+  if (val)
+  {
+    if (strcasestr(val, "pwg"))
+      outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
+    else if (strcasestr(val, "urf"))
+      outformat = CF_FILTER_OUT_FORMAT_APPLE_RASTER;
+    else if (strcasestr(val, "pclm"))
+      outformat = CF_FILTER_OUT_FORMAT_PCLM;
+    else
+      outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
+  }
+  else
+    outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
+
   /* 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" :
@@ -1805,7 +1783,7 @@ int cfFilterPDFToRaster(int inputfd,         /* I - File descriptor input stream
     }
   } else
     if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "cfFilterPDFToRaster: Input is empty outputting empty file.");
+                "cfFilterPDFToRaster: Input is empty, outputting empty file.");
 
  out:
   if (raster)
diff --git a/cupsfilters/ppdgenerator.h b/cupsfilters/ppdgenerator.h
deleted file mode 100644 (file)
index f163c46..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- *   IPP Everywhere/Apple Raster/IPP legacy PPD generator header file
- *
- *   Copyright 2016 by Till Kamppeter.
- *
- *   The PPD generator is based on the PPD generator for the CUPS
- *   "lpadmin -m everywhere" functionality in the cups/ppd-cache.c
- *   file. The copyright of this file is:
- *
- *   Copyright 2010-2016 by Apple Inc.
- *
- *   These coded instructions, statements, and computer programs are the
- *   property of Apple Inc. and are protected by Federal copyright
- *   law.  Distribution and use rights are outlined in the file "COPYING"
- *   which should have been included with this file. 
- */
-
-#ifndef _CUPS_FILTERS_PPDGENERATOR_H_
-#  define _CUPS_FILTERS_PPDGENERATOR_H_
-
-#  ifdef __cplusplus
-extern "C" {
-#  endif /* __cplusplus */
-
-/*
- * Include necessary headers...
- */
-
-#  include <stdio.h>
-#  include <stdlib.h>
-#  include <time.h>
-#  include <math.h>
-
-#  if defined(WIN32) || defined(__EMX__)
-#    include <io.h>
-#  else
-#    include <unistd.h>
-#    include <fcntl.h>
-#  endif /* WIN32 || __EMX__ */
-
-#  include <cups/cups.h>
-#  include <cups/raster.h>
-
-#include <config.h>
-#include <cups/cups.h>
-#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5)
-#define HAVE_CUPS_1_6 1
-#endif
-
-/*
- * Prototypes...
- */
-
-#ifdef HAVE_CUPS_1_6
-
-/* Data structure for resolution (X x Y dpi) */
-typedef struct cf_res_s {
-  int x, y;
-} cf_res_t;
-
-char            *cfCreatePPDFromIPP(char *buffer, size_t bufsize,
-                                   ipp_t *response, const char *make_model,
-                                   const char *pdl, int color, int duplex,
-                                   char *status_msg, size_t status_msg_size);
-char            *cfCreatePPDFromIPP2(char *buffer, size_t bufsize,
-                                    ipp_t *response, const char *make_model,
-                                    const char *pdl, int color, int duplex,
-                                    cups_array_t* conflicts,
-                                    cups_array_t *sizes,char* default_pagesize,
-                                    const char *default_cluster_color,
-                                    char *status_msg, size_t status_msg_size);
-char            *cfStrFormatd(char *buf, char *bufend, double number,
-                             struct lconv *loc);
-int             cfCompareResolutions(void *resolution_a, void *resolution_b,
-                                    void *user_data);
-void            *cfCopyResolution(void *resolution, void *user_data);
-void            cfFreeResolution(void *resolution, void *user_data);
-cf_res_t        *cfNewResolution(int x, int y);
-cups_array_t    *cfNewResolutionArray();
-cf_res_t        *cfIPPResToResolution(ipp_attribute_t *attr, int index);
-cups_array_t    *cfIPPAttrToResolutionArray(ipp_attribute_t *attr);
-int             cfJoinResolutionArrays(cups_array_t **current,
-                                      cups_array_t **new_arr,
-                                      cf_res_t **current_default,
-                                      cf_res_t **new_default);
-cups_array_t    *cfGenerateSizes(ipp_t *response,
-                               ipp_attribute_t **defattr,
-                               int *min_length,
-                               int* min_width,
-                               int* max_length,
-                               int* max_width,
-                               int* bottom,
-                               int* left,
-                               int* right,
-                               int* top,
-                               char* ppdname);
-#endif /* HAVE_CUPS_1_6 */
-
-#  ifdef __cplusplus
-}
-#  endif /* __cplusplus */
-
-#endif /* !_CUPS_FILTERS_PPDGENERATOR_H_ */
index e7a4d2b087bbe94d359532016958378ab73266fd..e10e8e26be2539d47db0fbf0ec7c1bbf6fcdb7f7 100644 (file)
@@ -33,6 +33,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include "image.h"
 #include "bitmap.h"
 #include "filter.h"
+#include "ipp.h"
 #include <config.h>
 #include <cups/cups.h>
 #if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 6)
@@ -45,7 +46,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include <stdlib.h>
 #include <stdbool.h>
 #include <string.h>
-#include <ppd/ppd.h>
 #include <stdarg.h>
 #include <cups/raster.h>
 #include <cupsfilters/image.h>
@@ -104,19 +104,15 @@ typedef struct cms_profile_s
 
 typedef struct pwgtoraster_doc_s
 {                /**** Document information ****/
+  cf_filter_data_t *data;
   bool page_size_requested;
   int bi_level;
   bool allocLineBuf;
   unsigned int bitspercolor;
   unsigned int outputNumColors; 
   unsigned int bitmapoffset[2];
-  ppd_file_t *ppd;
   cups_page_header2_t inheader;
   cups_page_header2_t outheader;
-  cf_logfunc_t logfunc;             /* Logging function, NULL for no
-                                          logging */
-  void          *logdata;               /* User data for logging function, can
-                                          be NULL */
   cups_file_t  *inputfp;               /* Temporary file, if any */
   FILE         *outputfp;              /* Temporary file, if any */
   /* margin swapping */
@@ -250,59 +246,20 @@ static void lcms_error_handler(cmsContext contextId, cmsUInt32Number ErrorCode,
 }
 #endif
 
-static void handle_requires_page_region(pwgtoraster_doc_t*doc) {
-  ppd_choice_t *mf;
-  ppd_choice_t *is;
-  ppd_attr_t *rregions = NULL;
-  ppd_size_t *size;
-
-  if ((size = ppdPageSize(doc->ppd,NULL)) == NULL) return;
-  mf = ppdFindMarkedChoice(doc->ppd,"ManualFeed");
-  if ((is = ppdFindMarkedChoice(doc->ppd,"InputSlot")) != NULL) {
-    rregions = ppdFindAttr(doc->ppd,"RequiresPageRegion",is->choice);
-  }
-  if (rregions == NULL) {
-    rregions = ppdFindAttr(doc->ppd,"RequiresPageRegion","All");
-  }
-  if (!strcasecmp(size->name,"Custom") || (!mf && !is) ||
-      (mf && !strcasecmp(mf->choice,"False") &&
-       (!is || (is->code && !is->code[0]))) ||
-      (!rregions && doc->ppd->num_filters > 0)) {
-    ppdMarkOption(doc->ppd,"PageSize",size->name);
-  } else if (rregions && rregions->value
-      && !strcasecmp(rregions->value,"True")) {
-    ppdMarkOption(doc->ppd,"PageRegion",size->name);
-  } else {
-    ppd_choice_t *page;
-
-    if ((page = ppdFindMarkedChoice(doc->ppd,"PageSize")) != NULL) {
-      page->marked = 0;
-      cupsArrayRemove(doc->ppd->marked,page);
-    }
-    if ((page = ppdFindMarkedChoice(doc->ppd,"PageRegion")) != NULL) {
-      page->marked = 0;
-      cupsArrayRemove(doc->ppd->marked, page);
-    }
-  }
-}
-
-static int parse_opts(cf_filter_data_t *data,
-                    cf_filter_out_format_t outformat,
-                    pwgtoraster_doc_t *doc)
+static int parse_opts(cf_filter_out_format_t outformat,
+                     pwgtoraster_doc_t *doc)
 {
   int num_options = 0;
   cups_option_t *options = NULL;
   char *profile = NULL;
-  ppd_attr_t *attr;
   const char *val;
+  cf_filter_data_t *data = doc->data;
   cf_logfunc_t log = data->logfunc;
   void *ld = data ->logdata;
   cups_cspace_t         cspace = (cups_cspace_t)(-1);
 
   num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
   
-  doc->ppd = data->ppd;
-
   // Did the user explicitly request a certain page size? If not, overtake
   // the page size(s) from the input pages
   doc->page_size_requested =
@@ -317,95 +274,83 @@ static int parse_opts(cf_filter_data_t *data,
                          outformat == CF_FILTER_OUT_FORMAT_PCLM ?
                          CF_FILTER_OUT_FORMAT_CUPS_RASTER : outformat, 0, &cspace);
 
-  if (doc->ppd) {
-    if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "cfFilterPWGToRaster: Using PPD file: %s", doc->ppd->nickname);
-    ppdMarkOptions(doc->ppd,num_options,options);
-    handle_requires_page_region(doc);
-    attr = ppdFindAttr(doc->ppd,"pwgtorasterRenderingIntent",NULL);
-    if (attr != NULL && attr->value != NULL) {
-      if (strcasecmp(attr->value,"PERCEPTUAL") == 0) {
-       doc->color_profile.renderingIntent = INTENT_PERCEPTUAL;
-      } else if (strcasecmp(attr->value,"RELATIVE_COLORIMETRIC") == 0) {
-       doc->color_profile.renderingIntent = INTENT_RELATIVE_COLORIMETRIC;
-      } else if (strcasecmp(attr->value,"SATURATION") == 0) {
-       doc->color_profile.renderingIntent = INTENT_SATURATION;
-      } else if (strcasecmp(attr->value,"ABSOLUTE_COLORIMETRIC") == 0) {
-       doc->color_profile.renderingIntent = INTENT_ABSOLUTE_COLORIMETRIC;
-      }
-    }
-    if (doc->outheader.Duplex) {
-      /* analyze options relevant to Duplex */
-      const char *backside = "";
-      /* APDuplexRequiresFlippedMargin */
-      enum {
-       FM_NO, FM_FALSE, FM_TRUE
-      } flippedMargin = FM_NO;
-
-      attr = ppdFindAttr(doc->ppd,"cupsBackSide",NULL);
-      if (attr != NULL && attr->value != NULL) {
-       doc->ppd->flip_duplex = 0;
-       backside = attr->value;
-      } else if (doc->ppd->flip_duplex) {
-       backside = "Rotated"; /* compatible with Max OS and GS 8.71 */
-      }
+  if (doc->outheader.Duplex)
+  {
+    int backside;
+    /* analyze options relevant to Duplex */
+    /* APDuplexRequiresFlippedMargin */
+    enum {
+      FM_NO,
+      FM_FALSE,
+      FM_TRUE
+    } flippedMargin;
+
+    backside = cfGetBackSideOrientation(data);
+
+    if (backside >= 0)
+    {
+      flippedMargin = (backside & 16 ? FM_TRUE :
+                      (backside & 8 ? FM_FALSE :
+                       FM_NO));
+      backside &= 7;
 
-      attr = ppdFindAttr(doc->ppd,"APDuplexRequiresFlippedMargin",NULL);
-      if (attr != NULL && attr->value != NULL) {
-       if (strcasecmp(attr->value,"true") == 0) {
-         flippedMargin = FM_TRUE;
-       } else {
-         flippedMargin = FM_FALSE;
-       }
-      }
-      if (strcasecmp(backside,"ManualTumble") == 0 && doc->outheader.Tumble) {
+      if (backside == CF_BACKSIDE_MANUAL_TUMBLE && doc->outheader.Tumble)
+      {
        doc->swap_margin_x = doc->swap_margin_y = true;
-       if (flippedMargin == FM_TRUE) {
+       if (flippedMargin == FM_TRUE)
          doc->swap_margin_y = false;
-       }
-      } else if (strcasecmp(backside,"Rotated") == 0 && !doc->outheader.Tumble) {
+      }
+      else if (backside==CF_BACKSIDE_ROTATED && !doc->outheader.Tumble)
+      {
        doc->swap_margin_x = doc->swap_margin_y = true;
-       if (flippedMargin == FM_TRUE) {
+       if (flippedMargin == FM_TRUE)
          doc->swap_margin_y = false;
-       }
-      } else if (strcasecmp(backside,"Flipped") == 0) {
-       if (doc->outheader.Tumble) {
+      }
+      else if (backside==CF_BACKSIDE_FLIPPED)
+      {
+       if (doc->outheader.Tumble)
          doc->swap_margin_x = doc->swap_margin_y = true;
-       }
-       if (flippedMargin == FM_FALSE) {
+       if (flippedMargin == FM_FALSE)
          doc->swap_margin_y = !doc->swap_margin_y;
-       }
       }
     }
+  }
 
-    /* support the CUPS "cm-calibration" option */
-    doc->color_profile.cm_calibrate = cfCmGetCupsColorCalibrateMode(data, options, num_options);
+  /* support the CUPS "cm-calibration" option */
+  doc->color_profile.cm_calibrate = cfCmGetCupsColorCalibrateMode(data);
 
-    if (doc->color_profile.cm_calibrate == CF_CM_CALIBRATION_ENABLED)
-      doc->color_profile.cm_disabled = 1;
-    else
-      doc->color_profile.cm_disabled = cfCmIsPrinterCmDisabled(data);
+  if (doc->color_profile.cm_calibrate == CF_CM_CALIBRATION_ENABLED)
+    doc->color_profile.cm_disabled = 1;
+  else
+    doc->color_profile.cm_disabled = cfCmIsPrinterCmDisabled(data);
 
-    if (!doc->color_profile.cm_disabled)
-      cfCmGetPrinterIccProfile(data, &profile, doc->ppd);
+  if (!doc->color_profile.cm_disabled)
+    cfCmGetPrinterIccProfile
+      (data,
+       cfRasterColorSpaceString(doc->outheader.cupsColorSpace),
+       doc->outheader.MediaType,
+       doc->outheader.HWResolution[0], doc->outheader.HWResolution[1],
+       &profile);
 
-    if (profile != NULL) {
-      doc->color_profile.colorProfile = cmsOpenProfileFromFile(profile,"r");
-      free(profile);
-    }
-  } else {
-    if (log) log(ld, CF_LOGLEVEL_DEBUG,
-      "cfFilterPWGToRaster: No PPD file is specified.");
-    if (strcasecmp(doc->outheader.cupsRenderingIntent, "Perceptual") == 0) {
-      doc->color_profile.renderingIntent = INTENT_PERCEPTUAL;
-    } else if (strcasecmp(doc->outheader.cupsRenderingIntent, "Relative") == 0) {
-      doc->color_profile.renderingIntent = INTENT_RELATIVE_COLORIMETRIC;
-    } else if (strcasecmp(doc->outheader.cupsRenderingIntent, "Saturation") == 0) {
-      doc->color_profile.renderingIntent = INTENT_SATURATION;
-    } else if (strcasecmp(doc->outheader.cupsRenderingIntent, "Absolute") == 0) {
-      doc->color_profile.renderingIntent = INTENT_ABSOLUTE_COLORIMETRIC;
-    }
+  if (profile != NULL)
+  {
+    doc->color_profile.colorProfile = cmsOpenProfileFromFile(profile,"r");
+    free(profile);
+  }
+
+  doc->outheader.cupsRenderingIntent[0] = '\0';
+  cfGetPrintRenderIntent(data, doc->outheader.cupsRenderingIntent,
+                        sizeof(doc->outheader.cupsRenderingIntent));
+  if (strcasecmp(doc->outheader.cupsRenderingIntent, "Perceptual") == 0) {
+    doc->color_profile.renderingIntent = INTENT_PERCEPTUAL;
+  } else if (strcasecmp(doc->outheader.cupsRenderingIntent, "Relative") == 0) {
+    doc->color_profile.renderingIntent = INTENT_RELATIVE_COLORIMETRIC;
+  } else if (strcasecmp(doc->outheader.cupsRenderingIntent, "Saturation") == 0) {
+    doc->color_profile.renderingIntent = INTENT_SATURATION;
+  } else if (strcasecmp(doc->outheader.cupsRenderingIntent, "Absolute") == 0) {
+    doc->color_profile.renderingIntent = INTENT_ABSOLUTE_COLORIMETRIC;
   }
+
   if ((val = cupsGetOption("print-color-mode", num_options, options)) != NULL
                            && !strncasecmp(val, "bi-level", 8))
     doc->bi_level = 1;
@@ -843,7 +788,7 @@ static unsigned char *convert_line_plane_swap(unsigned char *src,
   return dst;
 }
 
-/* Handle special cases which appear in Gutenprint's PPDs */
+/* Handle special cases which appear in the Gutenprint driver */
 static bool select_special_case(pwgtoraster_doc_t* doc, conversion_function_t* convert)
 {
   int i;
@@ -919,11 +864,12 @@ static unsigned int get_cms_color_space_type(cmsColorSpaceSignature cs)
 
 /* select convertLine function */
 static int select_convert_func(cups_raster_t *raster,
-                            pwgtoraster_doc_t* doc,
-                            conversion_function_t *convert,
-                            cf_logfunc_t log,
-                            void* ld)
+                              pwgtoraster_doc_t* doc,
+                              conversion_function_t *convert)
 {
+  cf_logfunc_t log = doc->data->logfunc;
+  void* ld = doc->data->logdata;
+
   doc->bitspercolor = doc->outheader.cupsBitsPerColor;
 
   if ((doc->color_profile.colorProfile == NULL || doc->color_profile.outputColorProfile == doc->color_profile.colorProfile)
@@ -1094,21 +1040,17 @@ static int select_convert_func(cups_raster_t *raster,
 }
 
 static bool out_page(pwgtoraster_doc_t *doc,
-                   int pageNo,
-                   cups_raster_t *inras,
-                   cups_raster_t *outras,
-                   conversion_function_t *convert,
-                   cf_logfunc_t log,
-                   void *ld,
-                   cf_filter_iscanceledfunc_t iscanceled,
-                   void *icd)
+                    int pageNo,
+                    cups_raster_t *inras,
+                    cups_raster_t *outras,
+                    conversion_function_t *convert)
 {
   int i, j;
-  double paperdimensions[2], /* Physical size of the paper */
+  cf_filter_data_t *data = doc->data;
+  float paperdimensions[2], /* Physical size of the paper */
     margins[4];        /* Physical margins of print */
-  double swap;
+  float swap;
   int imageable_area_fit = 0;
-  int landscape_fit = 0;
   int overspray_duplicate_after_pixels = INT_MAX;
   int next_overspray_duplicate = 0;
   int next_line_read = 0;
@@ -1127,7 +1069,10 @@ static bool out_page(pwgtoraster_doc_t *doc,
   unsigned char *pagebuf = NULL;
   unsigned int res_down_factor[2];
   unsigned int res_up_factor[2];
-
+  cf_logfunc_t log = data->logfunc;
+  void *ld = data->logdata;
+  cf_filter_iscanceledfunc_t iscanceled = data->iscanceledfunc;
+  void *icd = data->iscanceleddata;
 
   if (iscanceled && iscanceled(icd))
   {
@@ -1145,21 +1090,6 @@ static bool out_page(pwgtoraster_doc_t *doc,
     return (false);
   }
 
-  if (doc->inheader.ImagingBoundingBox[0] ||
-      doc->inheader.ImagingBoundingBox[1] ||
-      doc->inheader.ImagingBoundingBox[2] ||
-      doc->inheader.ImagingBoundingBox[3])
-  {
-    // Only CUPS Raster (not supported as input format by this filter
-    // function) defines margins and so an ImagingBoundingBox, for PWG
-    // Raster and Apple Raster (the input formats supported by this
-    // filter function) these values are all zero. With at least one not
-    // zero we consider the input not supported.
-    log(ld, CF_LOGLEVEL_ERROR,
-       "cfFilterPWGToRaster: Input page %d is not PWG or Apple Raster", pageNo);
-    return (false);
-  }
-  
   if (log) {
     log(ld, CF_LOGLEVEL_DEBUG,
        "cfFilterPWGToRaster: Input page %d", pageNo);
@@ -1197,10 +1127,23 @@ static bool out_page(pwgtoraster_doc_t *doc,
 
   memset(paperdimensions, 0, sizeof(paperdimensions));
   memset(margins, 0, sizeof(margins));
-  if (doc->ppd)
+  if (data->printer_attrs)
   {
-    ppdRasterMatchPPDSize(&(doc->outheader), doc->ppd, margins,
-                         paperdimensions, &imageable_area_fit, &landscape_fit);
+    /* Find dimensions/margins of requested page size */
+    if (cfGetPageDimensions(data->printer_attrs, data->job_attrs,
+                           data->num_options, data->options,
+                           &(doc->outheader), 0,
+                           &(paperdimensions[0]), &(paperdimensions[1]),
+                           &(margins[0]), &(margins[1]),
+                           &(margins[2]), &(margins[3]), NULL, NULL) == 0)
+    {
+      /* Find dimensions/margins for input page size */
+      cfGetPageDimensions(data->printer_attrs, NULL, 0, NULL,
+                         &(doc->inheader), 0,
+                         &(paperdimensions[0]), &(paperdimensions[1]),
+                         &(margins[0]), &(margins[1]),
+                         &(margins[2]), &(margins[3]), NULL, NULL);
+    }
     if (doc->outheader.ImagingBoundingBox[3] == 0)
       for (i = 0; i < 4; i ++)
        margins[i] = 0.0;
@@ -1344,6 +1287,19 @@ static bool out_page(pwgtoraster_doc_t *doc,
 
   // Pre-conversion of resolution and color space
   //
+  // This is needed if we work with a driver (especially Gutenprint)
+  // handling very high resolutions due to the high resolution (high
+  // ink nozzle density of printer) used for dithering but do not want
+  // to overload clients be requiring them sending high-resolution job
+  // data. So we can tell the client to send a lower resolution while
+  // we let the driver use a higher resolution. Also color spaces
+  // clients can produce are usually more limited than what drivers
+  // work with.
+  //
+  // We also need this feature for retro-fitting CUPS Raster drivers
+  // which have the driver's/the printers's capabilities defined in
+  // PPD files (handled by ppdFilterCUPSWrapper() in libppd):
+  //
   // The resolution and color space/depth/order for the CUPS Raster
   // data to be fed into the filter is not simply defined by options
   // and choices with intuitive names, but by the PostScript code
@@ -1508,7 +1464,7 @@ static bool out_page(pwgtoraster_doc_t *doc,
   // Input line buffer (with space for raising horizontal resolution
   // and overspray stretch if needed)
   //
-  // Note that the input lines can get stretched when the PPD defines
+  // Note that the input lines can get stretched when the driver defines
   // paper dimensions larger than the physical paper size for
   // overspraying on borderless printouts. Therefore we allocate the
   // maximum of the input line size (multiplied by a resolution
@@ -1534,7 +1490,7 @@ static bool out_page(pwgtoraster_doc_t *doc,
 
   // Overspray stretch of the input image If the output page
   // dimensions are larger than the input page dimensions we have most
-  // probably a page size from the PPD where the page dimensions are
+  // probably a page size from the driver where the page dimensions are
   // defined larger than the physical paper to do an overspray when
   // printing borderless, to avoid narrow white margins on one side if
   // the paper is not exactly aligned in the printer. The HPLIP driver
@@ -2093,11 +2049,12 @@ int cfFilterPWGToRaster(int inputfd,        /* I - File descriptor input stream
                 int outputfd,       /* I - File descriptor output stream */
                 int inputseekable,  /* I - Is input stream seekable? (unused) */
                 cf_filter_data_t *data,/* I - Job and printer data */
-                void *parameters)   /* I - Filter-specific parameters */
+                void *parameters)   /* I - Filter-specific parameters (unused)*/
 {
   cf_filter_out_format_t outformat;
   pwgtoraster_doc_t doc;
   int i;
+  const char           *val;
   cups_raster_t *inras = NULL,
                 *outras = NULL;
   cf_logfunc_t     log = data->logfunc;
@@ -2109,15 +2066,21 @@ int cfFilterPWGToRaster(int inputfd,        /* I - File descriptor input stream
 
 
   (void)inputseekable;
+  (void)parameters;
 
-  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)
+  val = data->final_content_type;
+  if (val)
+  {
+    if (strcasestr(val, "pwg"))
+      outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
+    else if (strcasestr(val, "urf"))
+      outformat = CF_FILTER_OUT_FORMAT_APPLE_RASTER;
+    else if (strcasestr(val, "pclm"))
+      outformat = CF_FILTER_OUT_FORMAT_PCLM;
+    else
       outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
-  } else
+  }
+  else
     outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
 
   if (log) log(ld, CF_LOGLEVEL_DEBUG,
@@ -2150,10 +2113,11 @@ int cfFilterPWGToRaster(int inputfd,        /* I - File descriptor input stream
 
   // Initialize data structure
   memset(&doc, 0, sizeof(doc));
+  doc.data = data;
   doc.color_profile.renderingIntent = INTENT_PERCEPTUAL;
 
   // Parse the options
-  if (parse_opts(data, outformat, &doc) == 1)
+  if (parse_opts(outformat, &doc) == 1)
     return (1);
 
   doc.outheader.NumCopies = data->copies;
@@ -2277,7 +2241,7 @@ int cfFilterPWGToRaster(int inputfd,        /* I - File descriptor input stream
   */
 
   memset(&convert, 0, sizeof(conversion_function_t));
-  if (select_convert_func(outras, &doc, &convert, log, ld) == 1)
+  if (select_convert_func(outras, &doc, &convert) == 1)
   {
     if (log) log(ld, CF_LOGLEVEL_ERROR,
                 "cfFilterPWGToRaster: Unable to select color conversion function.");
@@ -2348,8 +2312,7 @@ int cfFilterPWGToRaster(int inputfd,        /* I - File descriptor input stream
   */
 
   i = 0;
-  while (out_page(&doc, i + 1, inras, outras, &convert, log, ld, iscanceled,
-                icd))
+  while (out_page(&doc, i + 1, inras, outras, &convert))
     i ++;
   if (i == 0)
     if (log) log(ld, CF_LOGLEVEL_DEBUG,
index e6442771dffe587b79696e92c9e5fe9a2680b84e..de39c89e2d01c037da5be291032475ba9b40ff22 100644 (file)
@@ -1,37 +1,37 @@
 /*
  *   Function to apply IPP options to a CUPS/PWG Raster header.
  *
- *   Copyright 2013 by Till Kamppeter.
+ *   Copyright 2013-2022 by Till Kamppeter.
  *
  *   Distribution and use rights are outlined in the file "COPYING"
  *   which should have been included with this file.
  *
  * Contents:
  *
- *   cfRasterParseIPPOptions() - Parse IPP options from the command line
- *                                 and apply them to the CUPS Raster header.
  */
 
-#include <config.h>
-#include <cups/cups.h>
-#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 6)
-#define HAVE_CUPS_1_7 1
-#endif
 
 /*
  * Include necessary headers.
  */
 
+#include <config.h>
+#include <cups/cups.h>
 #include "raster.h"
 #include "filter.h"
 #include "driver.h"
 #include "ipp.h"
 #include <string.h>
 #include <ctype.h>
-#include <cupsfilters/ppdgenerator.h>
-#ifdef HAVE_CUPS_1_7
+#include <cupsfilters/ipp.h>
 #include <cups/pwg.h>
-#endif /* HAVE_CUPS_1_7 */
+
+/*
+ * Local functions
+ */
+
+int raster_base_header(cups_page_header2_t *h, cf_filter_data_t *data,
+                      int pwg_raster);
 
 /*
  * '_strlcpy()' - Safely copy two strings.
@@ -67,6 +67,88 @@ _strlcpy(char       *dst,            /* O - Destination string */
 }
 
 
+/*
+ * 'cfRasterColorSpaceString()' - Return the color space name for a
+ *                                cupsColorSpace value.
+ */
+
+const char *
+cfRasterColorSpaceString(cups_cspace_t cspace) /* I - cupsColorSpace value */
+{
+  static const char * const cups_color_spaces[] =
+  {                                    /* Color spaces */
+    "W",
+    "RGB",
+    "RGBA",
+    "K",
+    "CMY",
+    "YMC",
+    "CMYK",
+    "YMCK",
+    "KCMY",
+    "KCMYcm",
+    "GMCK",
+    "GMCS",
+    "WHITE",
+    "GOLD",
+    "SILVER",
+    "CIEXYZ",
+    "CIELab",
+    "RGBW",
+    "SW",
+    "SRGB",
+    "ADOBERGB",
+    "21",
+    "22",
+    "23",
+    "24",
+    "25",
+    "26",
+    "27",
+    "28",
+    "29",
+    "30",
+    "31",
+    "ICC1",
+    "ICC2",
+    "ICC3",
+    "ICC4",
+    "ICC5",
+    "ICC6",
+    "ICC7",
+    "ICC8",
+    "ICC9",
+    "ICCA",
+    "ICCB",
+    "ICCC",
+    "ICCD",
+    "ICCE",
+    "ICCF",
+    "47",
+    "DEVICE1",
+    "DEVICE2",
+    "DEVICE3",
+    "DEVICE4",
+    "DEVICE5",
+    "DEVICE6",
+    "DEVICE7",
+    "DEVICE8",
+    "DEVICE9",
+    "DEVICEA",
+    "DEVICEB",
+    "DEVICEC",
+    "DEVICED",
+    "DEVICEE",
+    "DEVICEF"
+  };
+
+  if (cspace < CUPS_CSPACE_W || cspace > CUPS_CSPACE_DEVICEF)
+    return ("Unknown");
+  else
+    return (cups_color_spaces[cspace]);
+}
+
+
 /*
  * 'cfRasterMatchIPPSize()' - Match IPP page size to header page size.
  */
@@ -74,7 +156,7 @@ _strlcpy(char       *dst,            /* O - Destination string */
 int 
 cfRasterMatchIPPSize(
     cups_page_header2_t *header,       /* I - Page header to match */
-    cf_filter_data_t   *data,          /* I - printer-data file */
+    cf_filter_data_t   *data,          /* I - Filter data */
     double             margins[4],     /* O - Margins of media in points */
     double             dimensions[2],  /* O - Width and Length of media in points */
     int                *image_fit,     /* O - Imageable Area Fit */
@@ -108,26 +190,32 @@ cfRasterMatchIPPSize(
                                        /* Requested PageSize */
 
   printer_attrs = data->printer_attrs;
-  printer_sizes = cfGenerateSizes(printer_attrs, &defattr, &min_length, &min_width,
-                                 &max_length, &max_width,
-                                 &bottom, &left, &right, &top, defsize);
 
   if (!header)
   {
-    if(log) log(ld, CF_LOGLEVEL_ERROR, "Page header cannot be NULL!\n");
+    if(log) log(ld, CF_LOGLEVEL_ERROR, "Page header cannot be NULL!");
     return (-1);
   }
+
   if (!printer_attrs)
   {
-    if(log) log(ld, CF_LOGLEVEL_ERROR, "Printer-attributes info not supplied!\n");
+    if(log) log(ld, CF_LOGLEVEL_ERROR, "Printer-attributes info not supplied!");
     return (-1);
   }
 
-  strncpy(pageSizeRequested, header->cupsPageSizeName, 64); /* Prefer user-selected page size. */
+  cfGenerateSizes(printer_attrs, CF_GEN_SIZES_DEFAULT, &printer_sizes, &defattr,
+                 NULL, NULL, NULL, NULL, NULL, NULL,
+                 &min_width, &min_length,
+                 &max_width, &max_length,
+                 &left, &bottom, &right, &top, defsize, NULL);
+
+  strncpy(pageSizeRequested, header->cupsPageSizeName, 64);
+    /* Prefer user-selected page size. */
   memset(dimensions, 0, sizeof(double)*2);
   memset(margins, 0, sizeof(double)*4);
   size_matched = NULL;
 
+  /* XXX FullBleed? FB? */
     /* Find a page size without ".Borderless" suffix */
     /* (if all are ".Borderless" we drop the suffix in the size's names) */
     for (size = (cups_size_t *)cupsArrayFirst(printer_sizes); size;
@@ -201,7 +289,7 @@ cfRasterMatchIPPSize(
        if(fabs(header->PageSize[1] - temptop + tempbottom) / templength < 0.01 &&
           fabs(header->PageSize[0] - tempright + templeft) / tempwidth < 0.01  &&
           (size_matched==NULL || !strcasecmp(pageSizeRequested, ippsizename))){
-               if(log)log(ld,CF_LOGLEVEL_DEBUG,"Imageable area fit\n");
+               if(log)log(ld,CF_LOGLEVEL_DEBUG,"Imageable area fit");
                size_matched = size;
                if (landscape) *landscape = 0;
                if (image_fit) *image_fit = 1;
@@ -213,14 +301,14 @@ cfRasterMatchIPPSize(
    /*
     * Standard size...
     */
-    if(log)log(ld,CF_LOGLEVEL_DEBUG,"IPP matched size = %s\n", size_matched->media);
+    if(log)log(ld,CF_LOGLEVEL_DEBUG,"IPP matched size = %s", size_matched->media);
     size = size_matched;
     dimensions[0] = size->width * 72.0 / 2540.0;
     dimensions[1] = size->length * 72.0 / 2540.0;
     margins[0] = size->left * 72.0 / 2540.0;
     margins[1] = size->bottom * 72.0 / 2540.0;
-    margins[2] = (size->width - size->right) * 72.0 / 2540.0;
-    margins[3] = (size->length - size->top) * 72.0 / 2540.0;
+    margins[2] = size->right * 72.0 / 2540.0;
+    margins[3] = size->top * 72.0 / 2540.0;
     snprintf(header->cupsPageSizeName, sizeof(header->cupsPageSizeName),
             "%.63s", size->media);
   }
@@ -288,42 +376,42 @@ cfRasterMatchIPPSize(
                if(fabs(header->PageSize[0] - temptop + tempbottom) / templength < 0.01 &&
                fabs(header->PageSize[1] - tempright + templeft) / tempwidth < 0.01     &&
                (size_matched==NULL || !strcasecmp(pageSizeRequested, ippsizename))){
-                       if(log) log(ld, CF_LOGLEVEL_DEBUG, "Imageable area fit\n");
+                       if(log) log(ld, CF_LOGLEVEL_DEBUG, "Imageable area fit");
                        size_matched = size;
                        if (landscape) *landscape = 1;
                        if (image_fit) *image_fit = 1;
                }
        }       
-  }
-  if (size_matched)
-  {
-    /*
-     * Standard size in landscape orientation...
-     */
-    size = size_matched;
-    if(log) log(ld, CF_LOGLEVEL_DEBUG, "landscape size = %s\n", size->media);
-    dimensions[0] = size->width * 72.0 / 2540.0;
-    dimensions[1] = size->length * 72.0 / 2540.0;
-    margins[0] = size->left * 72.0 / 2540.0;
-    margins[1] = size->bottom * 72.0 / 2540.0;
-    margins[2] = (size->width - size->right) * 72.0 / 2540.0;
-    margins[3] = (size->length - size->top) * 72.0 / 2540.0;
-    snprintf(header->cupsPageSizeName, sizeof(header->cupsPageSizeName),
-            "%.63s", size->media);
-  }
-  else
-  {
-    /*
-     * Custom size...
-     */
-    if(log) log(ld, CF_LOGLEVEL_DEBUG, "size = custom\n");
-    for (i = 0; i < 2; i ++)
-      dimensions[i] = header->PageSize[i];
-    margins[0] = left * 72.0 / 2540.0;
-    margins[1] = bottom * 72.0 / 2540.0;
-    margins[2] = right * 72.0 / 2540.0;
-    margins[3] = bottom * 72.0 / 2540.0;
-    snprintf(header->cupsPageSizeName, 64, "Custom.%dx%d", header->PageSize[0], header->PageSize[1]);
+       if (size_matched)
+       {
+        /*
+         * Standard size in landscape orientation...
+         */
+         size = size_matched;
+         if(log) log(ld, CF_LOGLEVEL_DEBUG, "landscape size = %s", size->media);
+         dimensions[0] = size->width * 72.0 / 2540.0;
+         dimensions[1] = size->length * 72.0 / 2540.0;
+         margins[0] = size->left * 72.0 / 2540.0;
+         margins[1] = size->bottom * 72.0 / 2540.0;
+         margins[2] = size->right * 72.0 / 2540.0;
+         margins[3] = size->top * 72.0 / 2540.0;
+         snprintf(header->cupsPageSizeName, sizeof(header->cupsPageSizeName),
+                  "%.63s", size->media);
+       }
+       else
+       {
+        /*
+         * Custom size...
+         */
+         if(log) log(ld, CF_LOGLEVEL_DEBUG, "size = custom");
+         for (i = 0; i < 2; i ++)
+           dimensions[i] = header->PageSize[i];
+         margins[0] = left * 72.0 / 2540.0;
+         margins[1] = bottom * 72.0 / 2540.0;
+         margins[2] = right * 72.0 / 2540.0;
+         margins[3] = top * 72.0 / 2540.0;
+         snprintf(header->cupsPageSizeName, 64, "Custom.%dx%d", header->PageSize[0], header->PageSize[1]);
+       }
   }
 
   return 0;
@@ -331,110 +419,160 @@ cfRasterMatchIPPSize(
 }
 
 /*
- *  'cfGetBackSideAndHeaderDuplex()' - 
- *                             This functions returns the cupsBackSide using 
- *                             printer attributes.
- *                             meaning and reason for backside orientation:-
- *                             It only makes sense if printer supports duplex,
- *                             so, if printer reports that it supports duplex 
- *                             printing via sides-supported IPP attribute, then
- *                             it also reports back-side orientation for each 
- *                             PDL in PDL specific IPP attributes. Backside 
- *                             orientation is specially needed for raster
- *                             PDLs as raster PDLs are specially made for 
- *                             raster printers which do not have sufficient memory 
- *                             to hold a full page bitmap(raster page). 
- *                             So they cannot build the whole page in memory 
- *                             before starting to print it. For one sided printing 
- *                             it is easy to manage. The printer's mechanism pulls 
- *                             the page in on its upper edge and starts to print,  
- *                             from top to bottom, after that it ejects the page.  
- *                             For double-sided printing it does the same for the  
- *                             front side, but for the back side the mechanics of  
- *                             the printer has to turn over the sheet, and now,  
- *                             depending on how the sheet is turned over it happens  
- *                             that the edge arriving in the printing mechanism is 
- *                             the lower edge of the back side. And if the printer  
- *                             simply prints then, the back side is the wrong way  
- *                             around. The printer reports its need via back side  
- *                             orientation in such a case, so that the client knows  
- *                             to send the back side upside down for example.  
- *                             In vector PDL, PDF and PostScript, always the full  
- *                             page's raster image is completely generated in the  
- *                             printer before the page is started, and therefore the  
- *                             printer can start to take the pixels from the lower  
- *                             edge of the raster image if needed, so back side  
- *                             orientation is always "normal" for these PDLs. 
- *                             And if a printer does not support duplex, back side 
- *                             orientation is not needed.
+ *  'cfGetBackSideOrientation()' - This functions returns the back
+ *                                side orientation using printer
+ *                                attributes.  Meaning and reason for
+ *                                backside orientation: It only
+ *                                makes sense if printer supports
+ *                                duplex, so, if printer reports that
+ *                                it supports duplex printing via
+ *                                sides-supported IPP attribute, then
+ *                                it also reports back-side
+ *                                orientation for each PDL in PDL
+ *                                specific IPP attributes. Backside
+ *                                orientation is specially needed for
+ *                                raster PDLs as raster PDLs are
+ *                                specially made for raster printers
+ *                                which do not have sufficient memory
+ *                                to hold a full page bitmap(raster
+ *                                page).  So they cannot build the
+ *                                whole page in memory before
+ *                                starting to print it. For one sided
+ *                                printing it is easy to manage. The
+ *                                printer's mechanism pulls the page
+ *                                in on its upper edge and starts to
+ *                                print, from top to bottom, after
+ *                                that it ejects the page.  For
+ *                                double-sided printing it does the
+ *                                same for the front side, but for
+ *                                the back side the mechanics of the
+ *                                printer has to turn over the sheet,
+ *                                and now, depending on how the sheet
+ *                                is turned over it happens that the
+ *                                edge arriving in the printing
+ *                                mechanism is the lower edge of the
+ *                                back side. And if the printer
+ *                                simply prints then, the back side
+ *                                is the wrong way around. The
+ *                                printer reports its need via back
+ *                                side orientation in such a case, so
+ *                                that the client knows to send the
+ *                                back side upside down for example.
+ *                                In vector PDL, PDF and PostScript,
+ *                                always the full page's raster image
+ *                                is completely generated in the
+ *                                printer before the page is started,
+ *                                and therefore the printer can start
+ *                                to take the pixels from the lower
+ *                                edge of the raster image if needed,
+ *                                so back side orientation is always
+ *                                "normal" for these PDLs.  And if a
+ *                                printer does not support duplex,
+ *                                back side orientation is not
+ *                                needed.
  */
 
-int                                                    /* O - Backside obtained using printer attributes */
-cfGetBackSideAndHeaderDuplex(ipp_t *printer_attrs,     /* I - printer attributes using filter data */
-                       cups_page_header2_t *header)    /* O - header */
+int                                   /* O - Backside orientation (bit 0-2)
+                                             Requires flipped margin?
+                                             Yes: bit 4 set; No: bit 3 set */
+cfGetBackSideOrientation(cf_filter_data_t *data) /* I - Filter data */
 {
-    ipp_attribute_t *ipp_attr; /* IPP attribute */
-    int i,                     /* Looping variable */
-       count;                  
-    int backside = -1; /* backside obtained using printer attributes */
-    if((ipp_attr = ippFindAttribute(printer_attrs, "sides-supported", IPP_TAG_ZERO))!=NULL){
-       if(ippContainsString(ipp_attr, "two-sided-long-edge")){
-           if(header) header->Duplex = CUPS_TRUE;
-           if((ipp_attr = ippFindAttribute(printer_attrs, "urf-supported",
-               IPP_TAG_ZERO))!=NULL){
-               for(i = 0, count = ippGetCount(ipp_attr); i<count;i++){
-                   const char *dm = ippGetString(ipp_attr, i, NULL); /* DM value */
-                   if(!strcasecmp(dm, "DM1")){
-                       backside = CF_BACKSIDE_NORMAL;
-                       break;
-                   }
-                   if(!strcasecmp(dm, "DM2")){
-                       backside = CF_BACKSIDE_FLIPPED;
-                       break;
-                   }
-                   if(!strcasecmp(dm, "DM3")){
-                       backside = CF_BACKSIDE_ROTATED;
-                       break;
-                   }
-                   if(!strcasecmp(dm, "DM4")){
-                       backside = CF_BACKSIDE_MANUAL_TUMBLE;
-                       break;
-                   }
-               }
-           }
-           if((ipp_attr = ippFindAttribute(printer_attrs, "pwg-raster-document-sheet-back",
-               IPP_TAG_ZERO))!=NULL){
-               const char *keyword;
-               keyword = ippGetString(ipp_attr, 0, NULL);
-               if (!strcmp(keyword, "flipped"))
-                   backside = CF_BACKSIDE_FLIPPED;
-               else if (!strcmp(keyword, "manual-tumble"))
-                   backside = CF_BACKSIDE_MANUAL_TUMBLE;
-               else if (!strcmp(keyword, "normal"))
-                   backside = CF_BACKSIDE_NORMAL;
-               else
-                   backside = CF_BACKSIDE_ROTATED;             
-           }
+  ipp_t *printer_attrs = data->printer_attrs;
+  int num_options = data->num_options;
+  cups_option_t *options = data->options;
+  char *final_content_type = data->final_content_type;
+  ipp_attribute_t *ipp_attr = NULL; /* IPP attribute */
+  int i,                       /* Looping variable */
+      count;                   
+  const char *keyword;
+  int backside = -1;   /* backside obtained using printer attributes */
+  // also check options
+  if ((ipp_attr = ippFindAttribute(printer_attrs, "sides-supported",
+                                    IPP_TAG_ZERO)) != NULL)
+  {
+    if (ippContainsString(ipp_attr, "two-sided-long-edge"))
+    {
+      if (final_content_type &&
+         strcasestr(final_content_type, "/urf") &&
+         (ipp_attr = ippFindAttribute(printer_attrs, "urf-supported",
+                                      IPP_TAG_ZERO)) != NULL)
+      {
+       for (i = 0, count = ippGetCount(ipp_attr); i < count; i ++)
+       {
+         const char *dm = ippGetString(ipp_attr, i, NULL); /* DM value */
+         if(!strcasecmp(dm, "DM1")){
+           backside = CF_BACKSIDE_NORMAL;
+           break;
+         }
+         if(!strcasecmp(dm, "DM2")){
+           backside = CF_BACKSIDE_FLIPPED;
+           break;
+         }
+         if(!strcasecmp(dm, "DM3")){
+           backside = CF_BACKSIDE_ROTATED;
+           break;
+         }
+         if(!strcasecmp(dm, "DM4")){
+           backside = CF_BACKSIDE_MANUAL_TUMBLE;
+           break;
+         }
        }
+      }
+      else if ((final_content_type &&
+               strcasestr(final_content_type, "/vnd.pwg-raster") &&
+               (ipp_attr = ippFindAttribute(printer_attrs,
+                                            "pwg-raster-document-sheet-back",
+                                            IPP_TAG_ZERO)) != NULL) ||
+              (final_content_type &&
+               strcasestr(final_content_type, "/pclm") &&
+               (ipp_attr = ippFindAttribute(printer_attrs,
+                                            "pclm-raster-back-side",
+                                            IPP_TAG_ZERO)) != NULL) ||
+              ((ipp_attr = NULL) ||
+               (keyword = cupsGetOption("back-side-orientation",
+                                        num_options, options)) != NULL))
+      {
+       if (ipp_attr)
+         keyword = ippGetString(ipp_attr, 0, NULL);
+       if (!strcasecmp(keyword, "flipped"))
+         backside = CF_BACKSIDE_FLIPPED;
+       else if (!strncasecmp(keyword, "manual", 6))
+         backside = CF_BACKSIDE_MANUAL_TUMBLE;
+       else if (!strcasecmp(keyword, "normal"))
+         backside = CF_BACKSIDE_NORMAL;
+       else if (!strcasecmp(keyword, "rotated"))
+         backside = CF_BACKSIDE_ROTATED;               
+      }
+      
+      if (backside == -1)
+       backside = CF_BACKSIDE_NORMAL;
+      else if ((keyword = cupsGetOption("duplex-requires-flipped-margin",
+                                       num_options, options)) != NULL)
+      {
+       if (strcasecmp(keyword, "true") == 0)
+         backside |= 16;
+       else
+         backside |= 8;
+      }
     }
-    
-    if(header && header->Duplex==1 && backside==-1) backside = CF_BACKSIDE_NORMAL;
-    return backside;
-    
+  }
+
+  return backside;
 }
 
-int 
-cfGetPrintRenderIntent(cf_filter_data_t *data,
-                       cups_page_header2_t *header)
+const char *
+cfGetPrintRenderIntent(cf_filter_data_t *data, char *ri, int ri_len)
 {
   const char           *val;
   int                  num_options = 0;
   cups_option_t        *options = NULL;
   ipp_t                *printer_attrs = data->printer_attrs;
   ipp_attribute_t      *ipp_attr;
-  cf_logfunc_t         log = data->logfunc;
+  cf_logfunc_t                 log = data->logfunc;
   void                  *ld = data->logdata;
   int                  i;
+
+
   num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
 
   if ((val = cupsGetOption("print-rendering-intent", num_options,
@@ -444,89 +582,80 @@ cfGetPrintRenderIntent(cf_filter_data_t *data,
       (val = cupsGetOption("RenderingIntent", num_options,
                           options)) != NULL)
   {
-    if (!strcmp(val, "absolute"))
-      snprintf(header->cupsRenderingIntent, sizeof(header->cupsRenderingIntent),
-       "%s","Absolute");
-    else if (!strcmp(val, "automatic"))
-      snprintf(header->cupsRenderingIntent,sizeof(header->cupsRenderingIntent),
-             "%s", "Automatic");
-    else if (!strcmp(val, "perceptual"))
-      snprintf(header->cupsRenderingIntent, sizeof(header->cupsRenderingIntent),
-               "%s", "Perceptual");
-    else if (!strcmp(val, "relative"))
-      snprintf(header->cupsRenderingIntent, sizeof(header->cupsRenderingIntent),
-             "%s",  "Relative");
-    else if (!strcmp(val, "relative-bpc"))
-      snprintf(header->cupsRenderingIntent, sizeof(header->cupsRenderingIntent),
-               "%s", "RelativeBpc");
-    else if (!strcmp(val, "saturation"))
-      snprintf(header->cupsRenderingIntent, sizeof(header->cupsRenderingIntent),
-             "%s",  "Saturation");
+    if (!strcasecmp(val, "absolute"))
+      snprintf(ri, ri_len, "%s", "Absolute");
+    else if (!strcasecmp(val, "auto") || !strcasecmp(val, "automatic"))
+      snprintf(ri, ri_len, "%s", "Automatic");
+    else if (!strcasecmp(val, "perceptual"))
+      snprintf(ri, ri_len, "%s", "Perceptual");
+    else if (!strcasecmp(val, "relative"))
+      snprintf(ri, ri_len, "%s",  "Relative");
+    else if (!strcasecmp(val, "relative-bpc") ||
+            !strcasecmp(val, "relativebpc"))
+      snprintf(ri, ri_len, "%s", "RelativeBpc");
+    else if (!strcasecmp(val, "saturation"))
+      snprintf(ri, ri_len, "%s",  "Saturation");
   }
-  else 
+
+  if ((ipp_attr = ippFindAttribute(printer_attrs,
+                                  "print-rendering-intent-supported",
+                                  IPP_TAG_ZERO)) != NULL)
   {
-       header->cupsRenderingIntent[0] = '\0';
-  }
-    if((ipp_attr = ippFindAttribute(printer_attrs, "print-rendering-intent-supported",
-                                                       IPP_TAG_ZERO))!=NULL){
-       int autoRender = 0;int count;
-        if((count = ippGetCount(ipp_attr))>0){
-           char temp[41] = "auto";
-           if(header->cupsRenderingIntent[0]!='\0'){           /* User is willing to supply some option */
-               for(i=0; i<count; i++){
-                   const char *temp2 = ippGetString(ipp_attr, i, NULL);
-                   if(!strcasecmp(temp2, "auto")) autoRender = 1;
-                   if(!strcasecmp(header->cupsRenderingIntent, temp2)){
-                       break;
-                   }
-               }
-               if(i==count){
-                   if(log) log(ld, CF_LOGLEVEL_DEBUG,
-                               "User specified print-rendering-intent not supported by printer,"
-                                       "using default print rendering intent.");
-                   header->cupsRenderingIntent[0] = '\0';
-               }
-           }
-           if(header->cupsRenderingIntent[0]=='\0'){           /* Either user has not supplied any option
-                                                                  or user supplied value is not supported by printer */
-               if((ipp_attr = ippFindAttribute(printer_attrs, "print-rendering-intent-default",
-                                                       IPP_TAG_ZERO))!=NULL){
-                   snprintf(temp,sizeof(temp),"%s",ippGetString(ipp_attr, 0, NULL));
-                   snprintf(header->cupsRenderingIntent, sizeof(header->cupsRenderingIntent),
-                               "%s",ippGetString(ipp_attr, 0, NULL));
-               }
-               else if(autoRender==1){
-                   snprintf(temp,sizeof(temp),"%s","auto");
-                   snprintf(header->cupsRenderingIntent, sizeof(header->cupsRenderingIntent),
-                               "%s","auto");
+    int autoRender = 0;
+    int count;
 
-               }
-           }
-        }
+    if ((count = ippGetCount(ipp_attr)) > 0)
+    {
+      for (i = 0; i < count; i ++)
+      {
+       const char *temp = ippGetString(ipp_attr, i, NULL);
+       if (!strcasecmp(temp, "auto")) autoRender = 1;
+       if (ri[0] != '\0')
+         /* User has supplied a setting */
+         if (!strcasecmp(ri, temp))
+           break;
+      }
+      if (ri[0] != '\0' && i == count)
+      {
+       if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                    "User specified print-rendering-intent not supported "
+                    "by printer, using default print rendering intent.");
+       ri[0] = '\0';
+      }
+      if (ri[0] == '\0')
+      {        /* Either user has not supplied any setting
+          or user supplied value is not supported by printer */
+       if ((ipp_attr = ippFindAttribute(printer_attrs,
+                                        "print-rendering-intent-default",
+                                        IPP_TAG_ZERO)) != NULL)
+         snprintf(ri, ri_len, "%s", ippGetString(ipp_attr, 0, NULL));
+       else if (autoRender == 1)
+         snprintf(ri, ri_len, "%s", "auto");
+      }
     }
-    return 0;
+  }
+
+  cupsFreeOptions(num_options, options);
+  return (ri);
 }
 
 /*
- * 'cfRasterPrepareHeader() - This function creates a CUPS/PWG
- *                              Raster header for Raster output based
- *                              on the printer and job properties
- *                              supplied to the calling filter
- *                              functions, printer properties via PPD
- *                              file or printer IPP attributes and job
- *                              properties via CUPS option list and
- *                              job IPP attributes. For PWG and Apple
- *                              Raster output the color space and
- *                              depth is auto-selected based on
- *                              available options listed in the
- *                              urf-supported and
- *                              pwg-raster-document-type-supported
- *                              printer IPP attributes (PPD generator
- *                              adds those also to the PPD) and the
- *                              settings of print-color-mode
- *                              ("ColorModel") and print-quality
- *                              ("cupsPrintQuality") job
- *                              attributes/options.
+ * 'cfRasterPrepareHeader() - This function creates a CUPS/PWG Raster
+ *                            header for Raster output based on the
+ *                            printer and job properties supplied to
+ *                            the calling filter functions, printer
+ *                            properties via printer IPP attributes
+ *                            and job properties via CUPS option list
+ *                            and job IPP attributesor optionally a
+ *                            sample header. For PWG and Apple Raster
+ *                            output the color space and depth is
+ *                            auto-selected based on available options
+ *                            listed in the urf-supported and
+ *                            pwg-raster-document-type-supported
+ *                            printer IPP attributes and the settings
+ *                            of print-color-mode ("ColorModel") and
+ *                            print-quality ("cupsPrintQuality") job
+ *                            attributes/options.
  */
 
 int                                             /* O  - 0 on success,
@@ -551,7 +680,6 @@ cfRasterPrepareHeader(cups_page_header2_t *h, /* I  - Raster header */
                                                        found. */
 {
   int i;
-  ppd_file_t *ppd;
   ipp_t *printer_attrs, *job_attrs;
   int num_options = 0;
   cups_option_t *options = NULL;
@@ -563,16 +691,16 @@ cfRasterPrepareHeader(cups_page_header2_t *h, /* I  - Raster header */
       pclm = 0;
   int cupsrasterheader = 1;
   const char *p;
-  ppd_attr_t *ppd_attr;
   ipp_attribute_t *attr;
-  const char *cspaces_available, *color_mode, *quality;
+  const char *cspaces_available = NULL, *color_mode = NULL, *quality = NULL;
   int hi_depth;
-  ppd_choice_t *choice;
   char valuebuffer[2048];
   int res = 1;
   int xres = -1; int yres = -1;
-  double margins[4];
-  double dimensions[2];
+  float margins[4];
+  float dimensions[2];
+  char size_name_buf[IPP_MAX_NAME + 1];
+  
 
   if (final_outformat == CF_FILTER_OUT_FORMAT_PWG_RASTER)
     pwgraster = 1;
@@ -583,6 +711,25 @@ cfRasterPrepareHeader(cups_page_header2_t *h, /* I  - Raster header */
   else
     cupsraster = 1;
 
+  if (cupsraster)
+  {
+    pwgraster = 0;
+    p = cupsGetOption("media-class", num_options, options);
+    if (p == NULL)
+      p = cupsGetOption("MediaClass", num_options, options);
+    if (p != NULL)
+    {
+      if (strcasestr(p, "pwg")) {
+       pwgraster = 1;
+       cupsraster = 0;
+       if (log)
+         log(ld, CF_LOGLEVEL_DEBUG,
+             "PWG Raster output requested (via \"MediaClass\"/\"media-class\" option)");
+      } else
+       pwgraster = 0;
+    }
+  }
+
   if (header_outformat == CF_FILTER_OUT_FORMAT_PWG_RASTER ||
       header_outformat == CF_FILTER_OUT_FORMAT_APPLE_RASTER)
     cupsrasterheader = 0;
@@ -591,7 +738,6 @@ cfRasterPrepareHeader(cups_page_header2_t *h, /* I  - Raster header */
   job_attrs = data->job_attrs;
 
   num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
-  ppd = data->ppd;
   printer_attrs = data->printer_attrs;
   job_attrs = data->job_attrs;
 
@@ -615,8 +761,7 @@ cfRasterPrepareHeader(cups_page_header2_t *h, /* I  - Raster header */
                                 "pwg-raster-document-resolution-supported",
                                 IPP_TAG_RESOLUTION)) != NULL)
     {
-      strncpy(valuebuffer, ippGetString(attr, 0, NULL),
-             sizeof(valuebuffer) - 1);
+      ippAttributeString(attr, valuebuffer, sizeof(valuebuffer));
       const char *p = valuebuffer;
       xres = atoi(p);
       if ((p = strchr(p, 'x')) != NULL)
@@ -655,8 +800,7 @@ cfRasterPrepareHeader(cups_page_header2_t *h, /* I  - Raster header */
                                 "pclm-source-resolution-default",
                                 IPP_TAG_RESOLUTION)) != NULL)
     {
-      strncpy(valuebuffer, ippGetString(attr, 0, NULL),
-             sizeof(valuebuffer) - 1);
+      ippAttributeString(attr, valuebuffer, sizeof(valuebuffer));
       const char *p = valuebuffer;
       xres = atoi(p);
       if ((p = strchr(p, 'x')) != NULL)
@@ -680,173 +824,87 @@ cfRasterPrepareHeader(cups_page_header2_t *h, /* I  - Raster header */
         (pclm ? "PCLm" : "CUPS Raster")));
   }
 
-  if (ppd)
-  {
-    if (log)
-      log(ld, CF_LOGLEVEL_DEBUG, "PPD file present");
-    ppdRasterInterpretPPD(h, ppd, num_options, options, NULL);
-    if ((ppd_attr = ppdFindAttr(ppd,"PWGRaster",0)) != 0 &&
-       (!strcasecmp(ppd_attr->value, "true") ||
-        !strcasecmp(ppd_attr->value, "on") ||
-        !strcasecmp(ppd_attr->value, "yes"))) {
-      pwgraster = 1;
-      cupsraster = 0;
-      appleraster = 0;
-      pclm = 0;
-      if (log)
-       log(ld, CF_LOGLEVEL_DEBUG,
-           "PWG Raster output requested (via \"PWGRaster\" PPD attribute)");
-    }
-
-    if (pwgraster || appleraster || pclm) {
-      if ((pwgraster &&
-          (ppd_attr = ppdFindAttr(ppd, "cupsPwgRasterDocumentTypeSupported",
-                                  NULL)) != NULL) ||
-         (appleraster &&
-          (ppd_attr = ppdFindAttr(ppd, "cupsUrfSupported", NULL)) != NULL)) {
-       cspaces_available = ppd_attr->value;
-       if (cspaces_available && cspaces_available[0]) {
-         /* PPD is from the PPD generator (cfCreatePPDFromIPP()) of
-            cups-filters, so we auto-select color space and depth */
-         if ((color_mode = cupsGetOption("print-color-mode", num_options,
-                                         options)) == NULL) {
-           choice = ppdFindMarkedChoice(ppd, "ColorModel");
-           if (choice)
-             color_mode = choice->choice;
-           else
-             color_mode = "auto";
-         }
-         if ((quality = cupsGetOption("print-quality", num_options,
-                                      options)) == NULL) {
-           choice = ppdFindMarkedChoice(ppd, "cupsPrintQuality");
-           if (choice)
-             quality = choice->choice;
-           else
-             quality = "Normal";
-         }
-         hi_depth = (!no_high_depth &&
-                     (!strcasecmp(quality, "High") || !strcmp(quality, "5"))) ?
-           1 : 0;
-         if (log) {
-           log(ld, CF_LOGLEVEL_DEBUG,
-               "Color mode requested: %s; color depth requested: %s",
-               color_mode, hi_depth ? "High" : "Standard");
-           log(ld, CF_LOGLEVEL_DEBUG,
-               "Determining best color space/depth ...");
-         }
-         res = cfRasterSetColorSpace(h, cspaces_available, color_mode,
-                                       cspace, &hi_depth);
-       }
-      }
-      else if (pclm)
-      {
-       /* Available color spaces are always SRGB 8 and SGray 8 */
-       cspaces_available = "srgb_8,sgray_8";
-       if ((color_mode = cupsGetOption("print-color-mode", num_options,
-                                       options)) == NULL) {
-         choice = ppdFindMarkedChoice(ppd, "ColorModel");
-         if (choice)
-           color_mode = choice->choice;
-         else
-           color_mode = "auto";
-       }
-       hi_depth = 0;
-       if (log)
-         log(ld, CF_LOGLEVEL_DEBUG,
-             "For PCLm color mode is always SRGB/SGray 8-bit.");
-       res = cfRasterSetColorSpace(h, cspaces_available, color_mode,
-                                     cspace, &hi_depth);
-      }
-    }
-
-    for (i = 0; i < 2; i ++)
-      dimensions[i] = h->PageSize[i];
-    if (cupsrasterheader) {
-      margins[0] = h->cupsImagingBBox[0];
-      margins[1] = h->cupsImagingBBox[1];
-      margins[2] = dimensions[0] - h->cupsImagingBBox[2];
-      margins[3] = dimensions[1] - h->cupsImagingBBox[3];
-    } else
-      memset(margins, 0, sizeof(margins));
-  }
+  if (data->header)
+    *h = *(data->header); /* Copy sample header */
   else
+    raster_base_header(h, data, 1 - cupsrasterheader);
+  if (cfGetPageDimensions(data->printer_attrs, data->job_attrs,
+                         data->num_options, data->options, h, 0,
+                         &(dimensions[0]), &(dimensions[1]),
+                         &(margins[0]), &(margins[1]),
+                         &(margins[2]), &(margins[3]), size_name_buf,
+                         NULL) < 0)
   {
-    if (log)
-      log(ld, CF_LOGLEVEL_DEBUG, "No PPD file present");
-    if (cupsraster)
+    pwg_media_t *pwg_media;
+    
+    for (i = 0; i < 2; i ++)
+      dimensions[i] = h->cupsPageSize[i];
+    margins[0] = h->cupsImagingBBox[0];
+    margins[1] = h->cupsImagingBBox[1];
+    margins[2] = dimensions[0] - h->cupsImagingBBox[2];
+    margins[3] = dimensions[1] - h->cupsImagingBBox[3];
+    pwg_media = pwgMediaForSize(dimensions[0] / 72 * 2540,
+                               dimensions[1] / 72 * 2540);
+    if (pwg_media)
     {
-      pwgraster = 0;
-      p = cupsGetOption("media-class", num_options, options);
-      if (p == NULL)
-       p = cupsGetOption("MediaClass", num_options, options);
-      if (p != NULL)
-      {
-       if (strcasestr(p, "pwg")) {
-         pwgraster = 1;
-         cupsraster = 0;
-         if (log)
-           log(ld, CF_LOGLEVEL_DEBUG,
-               "PWG Raster output requested (via \"MediaClass\"/\"media-class\" option)");
-       } else
-         pwgraster = 0;
-      }
-    }
-    cfRasterParseIPPOptions(h, data, 1 - cupsrasterheader, 1);
-    if (cfRasterMatchIPPSize(h, data, margins, dimensions, NULL, NULL) < 0) {
-      for (i = 0; i < 2; i ++)
-       dimensions[i] = h->PageSize[i];
-      memset(margins, 0, sizeof(margins));
+      p = (pwg_media->ppd ? pwg_media->ppd :
+          (pwg_media->legacy ? pwg_media->legacy : pwg_media->pwg));
+      if (p)
+       _strlcpy(h->cupsPageSizeName, p, sizeof(h->cupsPageSizeName));
     }
-    if (!cupsrasterheader)
-      memset(margins, 0, sizeof(margins));
-
-    if (printer_attrs &&
-       ((pwgraster &&
-         (attr = ippFindAttribute(printer_attrs,
-                                  "pwg-raster-document-type-supported",
-                                  IPP_TAG_ZERO)) != NULL) ||
-        (appleraster &&
-         (attr = ippFindAttribute(printer_attrs,
-                                  "urf-supported",
-                                  IPP_TAG_ZERO)) != NULL))) {
-      ippAttributeString(attr, valuebuffer, sizeof(valuebuffer));
-      cspaces_available = valuebuffer;
-      if ((color_mode = cupsGetOption("print-color-mode", num_options,
-                                     options)) == NULL)
-       color_mode = cfIPPAttrEnumValForPrinter(printer_attrs, job_attrs,
+  }
+  else if (size_name_buf[0])
+    _strlcpy(h->cupsPageSizeName, size_name_buf, sizeof(h->cupsPageSizeName));
+
+  if (!cupsrasterheader)
+    memset(margins, 0, sizeof(margins)); 
+
+  if (printer_attrs &&
+      ((pwgraster &&
+       (attr = ippFindAttribute(printer_attrs,
+                                "pwg-raster-document-type-supported",
+                                IPP_TAG_ZERO)) != NULL) ||
+       (appleraster &&
+       (attr = ippFindAttribute(printer_attrs,
+                                "urf-supported",
+                                IPP_TAG_ZERO)) != NULL))) {
+    ippAttributeString(attr, valuebuffer, sizeof(valuebuffer));
+    cspaces_available = valuebuffer;
+    if ((color_mode = cupsGetOption("print-color-mode", num_options,
+                                   options)) == NULL)
+      color_mode = cfIPPAttrEnumValForPrinter(printer_attrs, job_attrs,
                                              "print-color-mode");
-      if ((quality = cupsGetOption("print-quality", num_options,
-                                  options)) == NULL)
-       quality = cfIPPAttrEnumValForPrinter(printer_attrs, job_attrs,
+    if ((quality = cupsGetOption("print-quality", num_options,
+                                options)) == NULL)
+      quality = cfIPPAttrEnumValForPrinter(printer_attrs, job_attrs,
                                           "print-quality");
-      hi_depth = (!no_high_depth &&
-                 (!strcasecmp(quality, "high") || !strcmp(quality, "5"))) ?
-       1 : 0;
-      if (log) {
-       log(ld, CF_LOGLEVEL_DEBUG,
-           "Color mode requested: %s; color depth requested: %s",
-           color_mode, hi_depth ? "High" : "Standard");
-       log(ld, CF_LOGLEVEL_DEBUG,
-           "Determining best color space/depth ...");
-      }
-      res = cfRasterSetColorSpace(h, cspaces_available, color_mode,
-                                   cspace, &hi_depth);
+    hi_depth = (!no_high_depth && quality &&
+               (!strcasecmp(quality, "high") || !strcmp(quality, "5"))) ?
+      1 : 0;
+    if (log) {
+      log(ld, CF_LOGLEVEL_DEBUG,
+         "Color mode requested: %s; color depth requested: %s",
+         color_mode, hi_depth ? "High" : "Standard");
+      log(ld, CF_LOGLEVEL_DEBUG,
+         "Determining best color space/depth ...");
     }
-    else if (pclm)
-    {
-      /* Available color spaces are always SRGB 8 and SGray 8 */
-      cspaces_available = "srgb_8,sgray_8";
-      if ((color_mode = cupsGetOption("print-color-mode", num_options,
-                                     options)) == NULL)
-       color_mode = cfIPPAttrEnumValForPrinter(printer_attrs, job_attrs,
+    res = cfRasterSetColorSpace(h, cspaces_available, color_mode,
+                               cspace, &hi_depth);
+  }
+  else if (pclm)
+  {
+    /* Available color spaces are always SRGB 8 and SGray 8 */
+    cspaces_available = "srgb_8,sgray_8";
+    if ((color_mode = cupsGetOption("print-color-mode", num_options,
+                                   options)) == NULL)
+      color_mode = cfIPPAttrEnumValForPrinter(printer_attrs, job_attrs,
                                              "print-color-mode");
-      hi_depth = 0;
-      if (log)
-       log(ld, CF_LOGLEVEL_DEBUG,
-           "For PCLm color mode is always SRGB/SGray 8-bit.");
-      res = cfRasterSetColorSpace(h, cspaces_available, color_mode,
-                                   cspace, &hi_depth);
-    }
+    hi_depth = 0;
+    if (log)
+      log(ld, CF_LOGLEVEL_DEBUG,
+         "For PCLm color mode is always SRGB/SGray 8-bit.");
+    res = cfRasterSetColorSpace(h, cspaces_available, color_mode,
+                               cspace, &hi_depth);
   }
 
   if (res != 1) {
@@ -874,30 +932,17 @@ cfRasterPrepareHeader(cups_page_header2_t *h, /* I  - Raster header */
   }
 
   if ((h->HWResolution[0] == 100) && (h->HWResolution[1] == 100)) {
-    /* No "Resolution" option */
-    if (ppd && (ppd_attr = ppdFindAttr(ppd, "DefaultResolution", 0)) != NULL) {
-      /* "*DefaultResolution" keyword in the PPD */
-      const char *p = ppd_attr->value;
-      h->HWResolution[0] = atoi(p);
-      if ((p = strchr(p, 'x')) != NULL)
-       h->HWResolution[1] = atoi(p+1);   /*  Since p now points to a pointer such that *p = 'x', 
-                                        therefore using p+1, cause p+1 points to a numeric value  */
-      else
-       h->HWResolution[1] = h->HWResolution[0];
-      if (h->HWResolution[0] <= 0)
-       h->HWResolution[0] = 300;
-      if (h->HWResolution[1] <= 0)
-       h->HWResolution[1] = h->HWResolution[0];
-  } else {
-    if(xres!=-1){
+    /* No resolution set in header */
+    if (xres != -1)
+    {
       h->HWResolution[0] = xres;
       h->HWResolution[1] = yres;  
     }
-    else{
+    else
+    {
       h->HWResolution[0] = 300;
       h->HWResolution[1] = 300;
     }
-  }
     h->cupsWidth = h->HWResolution[0] * h->PageSize[0] / 72;
     h->cupsHeight = h->HWResolution[1] * h->PageSize[1] / 72;
   }
@@ -1017,7 +1062,7 @@ cfRasterSetColorSpace(cups_page_header2_t *h, /* I  - Raster header */
      only */
   if (islower(available[0]) &&
       (p = strstr(available, "black_1")) != NULL &&
-      !isdigit(p + 7) &&
+      !isdigit(*(p + 7)) &&
       (!strcmp(color_mode, "bi-level") ||
        !strcmp(color_mode, "process-bi-level"))) {
     /* Set parameters for bi-level, there is only one color space and color
@@ -1192,34 +1237,22 @@ cfRasterSetColorSpace(cups_page_header2_t *h, /* I  - Raster header */
 }
 
 
-/*
- * 'cfRasterParseIPPOptions()' - Parse IPP options from the command line
- *                                 and apply them to the CUPS Raster header.
- */
-
-int                                          /* O - -1 on error, 0 on success */
-cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
-                         cf_filter_data_t *data,
-                         int pwg_raster,         /* I - 1 if PWG Raster */
-                         int set_defaults)       /* I - If 1, set default
-                                                    values for all fields for
-                                                    which we did not get an
-                                                    option */
+int                                        /* O - -1 on error, 0 on success */
+raster_base_header(cups_page_header2_t *h, /* O - Raster header */
+                  cf_filter_data_t *data, /* I - Filter data */
+                  int pwg_raster)         /* I - 1 if PWG/Apple Raster */
 {
-#ifdef HAVE_CUPS_1_7
   int          i;                      /* Looping var */
   char         *ptr,                   /* Pointer into string */
                s[255];                 /* Temporary string */
   const char   *val,                   /* Pointer into value */
                 *media;                        /* media option */
-  char         *page_size,             /* PageSize option */
-                *media_source,          /* Media source */
+  char         *media_source,          /* Media source */
                 *media_type;           /* Media type */
   pwg_media_t   *size_found;            /* page size found for given name */
-  float         size;                   /* page size dimension */
-  int num_options = 0;          /*  number of options */
-  cups_option_t *options = NULL;  /*  Options */
-  ppd_option_t  *option;
+  int           num_options = 0;        /* Number of options */
+  cups_option_t *options = NULL;        /* Options */
+  ipp_attribute_t *attr;
 
 
  /*
@@ -1232,53 +1265,23 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
  /*
   * Join the IPP attributes and the CUPS options in a single list
   */
-  num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
-
- /*
-  * If we have a PPD file in the filter data, take it into account, by
-  * not parsing options which are in the PPD file here.
-  *
-  * They should get parsed and applied separately via the
-  * ppdRasterInterpretPPD() as that function parses the embedded
-  * PostScript code. This way weird things like Gutenprint's
-  * "Resolution" option (choice name is something odd, like
-  * 301x300dpi, and actual resolution can be completely different)
-  * will get treated correctly.
-  *
-  * We mark the option settings in the PPD and call ppdRasterInterpretPPD()
-  * only when we are called with set_defaults = 1. In any case we remove
-  * the options of the PPD from our option list before we start parsing. 
-  */
 
-  if (data->ppd)
-  {
-    if (set_defaults)
-    {
-      ppdMarkOptions(data->ppd, num_options, options);
-      ppdRasterInterpretPPD(h, data->ppd, num_options, options, NULL);
-    }
-    for (option = ppdFirstOption(data->ppd); option;
-        option = ppdNextOption(data->ppd))
-      num_options = cupsRemoveOption(option->keyword, num_options, &options);
-  } else if (set_defaults)
-    memset(h, 0, sizeof(cups_page_header2_t));
+  num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
 
  /*
   * Check if the supplied "media" option is a comma-separated list of any
   * combination of page size ("media"), media source ("media-position"),
-  * and media type ("media-type") and if so, put these list elements into
-  * their dedicated options.
+  * and media type ("media-type") and if so, extract media type and source.
+  * Media size will be handled separately.
   */
 
-  page_size = NULL;
   media_source = NULL;
   media_type = NULL;
   if ((media = cupsGetOption("media", num_options, options)) != NULL)
   {
    /*
-    * Loop through the option string, separating it at commas and marking each
-    * individual option as long as the corresponding PPD option (PageSize,
-    * InputSlot, etc.) is not also set.
+    * Loop through the option string, separating it at commas and setting each
+    * individual option.
     *
     * For PageSize, we also check for an empty option value since some versions
     * of MacOS X use it to specify auto-selection of the media based solely on
@@ -1305,7 +1308,7 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
       size_found = NULL;
       if ((size_found = pwgMediaForPWG(s)) == NULL)
        if ((size_found = pwgMediaForPPD(s)) == NULL)
-         if ((size_found = pwgMediaForPPD(s)) == NULL)
+         if ((size_found = pwgMediaForLegacy(s)) == NULL)
          {
            if (strcasestr(s, "tray") ||
                strcasestr(s, "feed") ||
@@ -1318,6 +1321,7 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
                strcasestr(s, "left") ||
                strcasestr(s, "right") ||
                strcasestr(s, "side") ||
+               strcasestr(s, "roll") ||
                strcasestr(s, "main"))
             { 
               if (media_source == NULL)
@@ -1326,58 +1330,74 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
            else
              media_type = strdup(s);
          }
-      if (page_size == NULL && size_found)
-       page_size = strdup(size_found->pwg);
     }
   }
 
+ /*
+  * Initialize header
+  */
+
+  memset(h, 0, sizeof(cups_page_header2_t));
+
+ /*
+  * Fill in the items using printer and job IPP attributes and options
+  */
+
   if (pwg_raster)
     strcpy(h->MediaClass, "PwgRaster");
   else if ((val = cupsGetOption("media-class", num_options, options)) != NULL ||
           (val = cupsGetOption("MediaClass", num_options, options)) != NULL)
     _strlcpy(h->MediaClass, val, sizeof(h->MediaClass));
-  else if (set_defaults)
+  else
     strcpy(h->MediaClass, "");
+  if (strcasecmp(h->MediaClass, "PwgRaster") == 0)
+    pwg_raster = 1;
 
   if ((val = cupsGetOption("media-color", num_options, options)) != NULL ||
       (val = cupsGetOption("MediaColor", num_options, options)) != NULL)
     _strlcpy(h->MediaColor, val, sizeof(h->MediaColor));
-  else if (set_defaults)
+  else
     h->MediaColor[0] = '\0';
 
   if ((val = cupsGetOption("media-type", num_options, options)) != NULL ||
       (val = cupsGetOption("MediaType", num_options, options)) != NULL ||
-      (val = media_type) != NULL)
+      (val = media_type) != NULL ||
+      (val = cfIPPAttrEnumValForPrinter(data->printer_attrs,
+                                       data->job_attrs,
+                                       "media-type")) != NULL)
     _strlcpy(h->MediaType, val, sizeof(h->MediaType));
-  else if (set_defaults)
+  else
     h->MediaType[0] = '\0';
 
   if ((val = cupsGetOption("print-content-optimize", num_options,
                           options)) != NULL ||
       (val = cupsGetOption("output-type", num_options, options)) != NULL ||
-      (val = cupsGetOption("OutputType", num_options, options)) != NULL)
+      (val = cupsGetOption("OutputType", num_options, options)) != NULL ||
+      (val = cfIPPAttrEnumValForPrinter(data->printer_attrs,
+                                        data->job_attrs,
+                                       "print-content-optimize")) != NULL)
   {
-    if (!strcasecmp(val, "automatic"))
-      _strlcpy(h->OutputType, "Automatic",
+    if (!strncasecmp(val, "auto", 4))
+      _strlcpy(h->OutputType, "automatic",
              sizeof(h->OutputType));
     else if (!strcasecmp(val, "graphics") ||
             !strcasecmp(val, "graphic"))
-      _strlcpy(h->OutputType, "Graphics", sizeof(h->OutputType));
+      _strlcpy(h->OutputType, "graphics", sizeof(h->OutputType));
     else if (!strcasecmp(val, "photo"))
-      _strlcpy(h->OutputType, "Photo", sizeof(h->OutputType));
+      _strlcpy(h->OutputType, "photo", sizeof(h->OutputType));
     else if (!strcasecmp(val, "text"))
-      _strlcpy(h->OutputType, "Text", sizeof(h->OutputType));
+      _strlcpy(h->OutputType, "text", sizeof(h->OutputType));
     else if (!strcasecmp(val, "text-and-graphics") ||
             !strcasecmp(val, "text-and-graphic") ||
             !strcasecmp(val, "TextAndGraphics") ||
             !strcasecmp(val, "TextAndGraphic"))
-      _strlcpy(h->OutputType, "TextAndGraphics",
+      _strlcpy(h->OutputType, "text-and-graphics",
              sizeof(h->OutputType));
     else if (!pwg_raster)
       _strlcpy(h->OutputType, val, sizeof(h->OutputType));
   }
-  else if (set_defaults)
-    _strlcpy(h->OutputType, "Automatic", sizeof(h->OutputType));
+  else
+    _strlcpy(h->OutputType, "automatic", sizeof(h->OutputType));
 
   if (pwg_raster)
   {
@@ -1389,30 +1409,35 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
   else
   {
     /* TODO - Support for advance distance and advance media */
-    if (set_defaults)
+    h->AdvanceDistance = 0;
+    h->AdvanceMedia = CUPS_ADVANCE_NONE;
+    if ((val = cupsGetOption("Collate", num_options, options)) != NULL ||
+       (val = cupsGetOption("multiple-document-handling",
+                            num_options, options)) != NULL ||
+       (val = cfIPPAttrEnumValForPrinter(data->printer_attrs,
+                                         data->job_attrs,
+                                         "multiple-document-handling")) !=
+        NULL)
     {
-      h->AdvanceDistance = 0;
-      h->AdvanceMedia = CUPS_ADVANCE_NONE;
+      if (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
+         !strcasecmp(val, "yes") ||
+         !strcasecmp(val, "separate-documents-collated-copies"))
+       h->Collate = CUPS_TRUE;
+      else
+       h->Collate = CUPS_FALSE;
     }
-    if ((val = cupsGetOption("Collate", num_options, options)) != NULL &&
-       (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
-        !strcasecmp(val, "yes")))
-      h->Collate = CUPS_TRUE;
-    else if ((val = cupsGetOption("Collate", num_options, options)) != NULL &&
-            (!strcasecmp(val, "false") || !strcasecmp(val, "off") ||
-             !strcasecmp(val, "no")))
-      h->Collate = CUPS_FALSE;
-    else if (set_defaults)
+    else
       h->Collate = CUPS_FALSE;
   }
 
-  if (set_defaults)
-    h->CutMedia = CUPS_CUT_NONE;
+  h->CutMedia = CUPS_CUT_NONE;
 
-  if (set_defaults)
-    h->Tumble = CUPS_FALSE;
+  h->Tumble = CUPS_FALSE;
   if ((val = cupsGetOption("sides", num_options, options)) != NULL ||
-      (val = cupsGetOption("Duplex", num_options, options)) != NULL)
+      (val = cupsGetOption("Duplex", num_options, options)) != NULL ||
+      (val = cfIPPAttrEnumValForPrinter(data->printer_attrs,
+                                       data->job_attrs,
+                                       "sides")) != NULL)
   {
     if (!strcasecmp(val, "None") || !strcasecmp(val, "Off") ||
        !strcasecmp(val, "False") || !strcasecmp(val, "No") ||
@@ -1425,15 +1450,17 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
             !strncasecmp(val, "Duplex", 6))
     {
       h->Duplex = CUPS_TRUE;
-      if (!strncasecmp(val, "DuplexTumble", 12))
+      if (!strncasecmp(val, "DuplexTumble", 12) ||
+         strcasestr(val, "short-edge"))
        h->Tumble = CUPS_TRUE;
-      if (!strncasecmp(val, "DuplexNoTumble", 12))
+      if (!strncasecmp(val, "DuplexNoTumble", 14) ||
+         strcasestr(val, "long-edge"))
        h->Tumble = CUPS_FALSE;
     }
-    else if (set_defaults)
+    else
       h->Duplex = CUPS_FALSE;
   }
-  else if (set_defaults)
+  else
     h->Duplex = CUPS_FALSE;
 
   if ((val = cupsGetOption("printer-resolution", num_options,
@@ -1451,19 +1478,11 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
        yres = strtol(ptr + 1, (char **)&ptr, 10);
     }
 
-    if (ptr <= val || xres <= 0 || yres <= 0 || !ptr ||
-       (*ptr != '\0' &&
-        strcasecmp(ptr, "dpi") &&
-        strcasecmp(ptr, "dpc") &&
-        strcasecmp(ptr, "dpcm")))
-    {
-      if (set_defaults)
-      {
-       h->HWResolution[0] = 600;
-       h->HWResolution[1] = 600;
-      }
-    }
-    else
+    if (ptr > val && xres > 0 && yres > 0 && ptr &&
+       (*ptr == '\0' ||
+        !strcasecmp(ptr, "dpi") ||
+        !strcasecmp(ptr, "dpc") ||
+        !strcasecmp(ptr, "dpcm")))
     {
       if (!strcasecmp(ptr, "dpc") ||
          !strcasecmp(ptr, "dpcm"))
@@ -1474,24 +1493,36 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
       h->HWResolution[0] = xres;
       h->HWResolution[1] = yres;
     }
+    else
+    {
+      h->HWResolution[0] = 100; /* Resolution invalid */
+      h->HWResolution[1] = 100;
+    }
   }
-  else if (set_defaults)
-  {
-    h->HWResolution[0] = 600;
-    h->HWResolution[1] = 600;
-  }
-  
-  if (set_defaults)
+  else
   {
-    /* TODO - Support for insert sheets */
-    h->InsertSheet = CUPS_FALSE;
+    h->HWResolution[0] = 100; /* Resolution invalid */
+    h->HWResolution[1] = 100;
   }
 
-  if (set_defaults)
+  // Resolution from IPP attrs
+  if (h->HWResolution[0] == 100 && h->HWResolution[1] == 100)
   {
-    /* TODO - Support for jog */
-    h->Jog = CUPS_JOG_NONE;
+    int x = 0, y = 0;
+    cfIPPAttrResolutionForPrinter(data->printer_attrs, data->job_attrs,
+                                 NULL, &x, &y);
+    if (x && y)
+    {
+      h->HWResolution[0] = x;
+      h->HWResolution[1] = y;
+    }
   }
+  
+  /* TODO - Support for insert sheets */
+  h->InsertSheet = CUPS_FALSE;
+
+  /* TODO - Support for jog */
+  h->Jog = CUPS_JOG_NONE;
 
   if ((val = cupsGetOption("feed-orientation", num_options,
                           options)) != NULL ||
@@ -1503,21 +1534,21 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
     else if (!strcasecmp(val, "LongEdgeFirst"))
       h->LeadingEdge = CUPS_EDGE_RIGHT;
   }
-  else if (set_defaults)
+  else
     h->LeadingEdge = CUPS_EDGE_TOP;
 
-  if (pwg_raster || set_defaults)
-  {
-    /* TODO - Support for manual feed */
-    h->ManualFeed = CUPS_FALSE;
-  }
+  /* TODO - Support for manual feed */
+  h->ManualFeed = CUPS_FALSE;
 
   if ((val = cupsGetOption("media-position", num_options, options)) != NULL ||
       (val = cupsGetOption("MediaPosition", num_options, options)) != NULL ||
       (val = cupsGetOption("media-source", num_options, options)) != NULL ||
       (val = cupsGetOption("MediaSource", num_options, options)) != NULL ||
       (val = cupsGetOption("InputSlot", num_options, options)) != NULL ||
-      (val = media_source) != NULL)
+      (val = media_source) != NULL ||
+      (val = cfIPPAttrEnumValForPrinter(data->printer_attrs,
+                                       data->job_attrs,
+                                       "media-source")) != NULL)
   {
     if (!strncasecmp(val, "Auto", 4) ||
        !strncasecmp(val, "Default", 7))
@@ -1526,7 +1557,8 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
       h->MediaPosition = 1;
     else if (!strcasecmp(val, "Alternate"))
       h->MediaPosition = 2;
-    else if (!strcasecmp(val, "LargeCapacity"))
+    else if (!strcasecmp(val, "LargeCapacity") ||
+            !strcasecmp(val, "large-capacity"))
       h->MediaPosition = 3;
     else if (!strcasecmp(val, "Manual"))
       h->MediaPosition = 4;
@@ -1538,9 +1570,11 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
       h->MediaPosition = 7;
     else if (!strcasecmp(val, "Hagaki"))
       h->MediaPosition = 8;
-    else if (!strcasecmp(val, "MainRoll"))
+    else if (!strcasecmp(val, "MainRoll") ||
+            !strcasecmp(val, "main-roll"))
       h->MediaPosition = 9;
-    else if (!strcasecmp(val, "AlternateRoll"))
+    else if (!strcasecmp(val, "AlternateRoll") ||
+            !strcasecmp(val, "alternate-roll"))
       h->MediaPosition = 10;
     else if (!strcasecmp(val, "Top"))
       h->MediaPosition = 11;
@@ -1558,70 +1592,101 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
       h->MediaPosition = 17;
     else if (!strcasecmp(val, "Rear"))
       h->MediaPosition = 18;
-    else if (!strcasecmp(val, "ByPassTray"))
+    else if (!strcasecmp(val, "ByPassTray") ||
+            !strcasecmp(val, "bypass-tray"))
       h->MediaPosition = 19;
-    else if (!strcasecmp(val, "Tray1"))
+    else if (!strcasecmp(val, "Tray1") ||
+            !strcasecmp(val, "tray-1"))
       h->MediaPosition = 20;
-    else if (!strcasecmp(val, "Tray2"))
+    else if (!strcasecmp(val, "Tray2") ||
+            !strcasecmp(val, "tray-2"))
       h->MediaPosition = 21;
-    else if (!strcasecmp(val, "Tray3"))
+    else if (!strcasecmp(val, "Tray3") ||
+            !strcasecmp(val, "tray-3"))
       h->MediaPosition = 22;
-    else if (!strcasecmp(val, "Tray4"))
+    else if (!strcasecmp(val, "Tray4") ||
+            !strcasecmp(val, "tray-4"))
       h->MediaPosition = 23;
-    else if (!strcasecmp(val, "Tray5"))
+    else if (!strcasecmp(val, "Tray5") ||
+            !strcasecmp(val, "tray-5"))
       h->MediaPosition = 24;
-    else if (!strcasecmp(val, "Tray6"))
+    else if (!strcasecmp(val, "Tray6") ||
+            !strcasecmp(val, "tray-6"))
       h->MediaPosition = 25;
-    else if (!strcasecmp(val, "Tray7"))
+    else if (!strcasecmp(val, "Tray7") ||
+            !strcasecmp(val, "tray-7"))
       h->MediaPosition = 26;
-    else if (!strcasecmp(val, "Tray8"))
+    else if (!strcasecmp(val, "Tray8") ||
+            !strcasecmp(val, "tray-8"))
       h->MediaPosition = 27;
-    else if (!strcasecmp(val, "Tray9"))
+    else if (!strcasecmp(val, "Tray9") ||
+            !strcasecmp(val, "tray-9"))
       h->MediaPosition = 28;
-    else if (!strcasecmp(val, "Tray10"))
+    else if (!strcasecmp(val, "Tray10") ||
+            !strcasecmp(val, "tray-10"))
       h->MediaPosition = 29;
-    else if (!strcasecmp(val, "Tray11"))
+    else if (!strcasecmp(val, "Tray11") ||
+            !strcasecmp(val, "tray-11"))
       h->MediaPosition = 30;
-    else if (!strcasecmp(val, "Tray12"))
+    else if (!strcasecmp(val, "Tray12") ||
+            !strcasecmp(val, "tray-12"))
       h->MediaPosition = 31;
-    else if (!strcasecmp(val, "Tray13"))
+    else if (!strcasecmp(val, "Tray13") ||
+            !strcasecmp(val, "tray-13"))
       h->MediaPosition = 32;
-    else if (!strcasecmp(val, "Tray14"))
+    else if (!strcasecmp(val, "Tray14") ||
+            !strcasecmp(val, "tray-14"))
       h->MediaPosition = 33;
-    else if (!strcasecmp(val, "Tray15"))
+    else if (!strcasecmp(val, "Tray15") ||
+            !strcasecmp(val, "tray-15"))
       h->MediaPosition = 34;
-    else if (!strcasecmp(val, "Tray16"))
+    else if (!strcasecmp(val, "Tray16") ||
+            !strcasecmp(val, "tray-16"))
       h->MediaPosition = 35;
-    else if (!strcasecmp(val, "Tray17"))
+    else if (!strcasecmp(val, "Tray17") ||
+            !strcasecmp(val, "tray-17"))
       h->MediaPosition = 36;
-    else if (!strcasecmp(val, "Tray18"))
+    else if (!strcasecmp(val, "Tray18") ||
+            !strcasecmp(val, "tray-18"))
       h->MediaPosition = 37;
-    else if (!strcasecmp(val, "Tray19"))
+    else if (!strcasecmp(val, "Tray19") ||
+            !strcasecmp(val, "tray-19"))
       h->MediaPosition = 38;
-    else if (!strcasecmp(val, "Tray20"))
+    else if (!strcasecmp(val, "Tray20") ||
+            !strcasecmp(val, "tray-20"))
       h->MediaPosition = 39;
-    else if (!strcasecmp(val, "Roll1"))
+    else if (!strcasecmp(val, "Roll1") ||
+            !strcasecmp(val, "roll-1"))
       h->MediaPosition = 40;
-    else if (!strcasecmp(val, "Roll2"))
+    else if (!strcasecmp(val, "Roll2") ||
+            !strcasecmp(val, "roll-2"))
       h->MediaPosition = 41;
-    else if (!strcasecmp(val, "Roll3"))
+    else if (!strcasecmp(val, "Roll3") ||
+            !strcasecmp(val, "roll-3"))
       h->MediaPosition = 42;
-    else if (!strcasecmp(val, "Roll4"))
+    else if (!strcasecmp(val, "Roll4") ||
+            !strcasecmp(val, "roll-4"))
       h->MediaPosition = 43;
-    else if (!strcasecmp(val, "Roll5"))
+    else if (!strcasecmp(val, "Roll5") ||
+            !strcasecmp(val, "roll-5"))
       h->MediaPosition = 44;
-    else if (!strcasecmp(val, "Roll6"))
+    else if (!strcasecmp(val, "Roll6") ||
+            !strcasecmp(val, "roll-6"))
       h->MediaPosition = 45;
-    else if (!strcasecmp(val, "Roll7"))
+    else if (!strcasecmp(val, "Roll7") ||
+            !strcasecmp(val, "roll-7"))
       h->MediaPosition = 46;
-    else if (!strcasecmp(val, "Roll8"))
+    else if (!strcasecmp(val, "Roll8") ||
+            !strcasecmp(val, "roll-8"))
       h->MediaPosition = 47;
-    else if (!strcasecmp(val, "Roll9"))
+    else if (!strcasecmp(val, "Roll9") ||
+            !strcasecmp(val, "roll-9"))
       h->MediaPosition = 48;
-    else if (!strcasecmp(val, "Roll10"))
+    else if (!strcasecmp(val, "Roll10") ||
+            !strcasecmp(val, "roll-10"))
       h->MediaPosition = 49;
   }
-  else if (set_defaults)
+  else
     h->MediaPosition = 0; /* Auto */
 
   if ((val = cupsGetOption("media-weight", num_options, options)) != NULL ||
@@ -1630,7 +1695,7 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
                           options)) != NULL ||
       (val = cupsGetOption("MediaWeightMetric", num_options, options)) != NULL)
     h->MediaWeight = atol(val);
-  else if (set_defaults)
+  else
     h->MediaWeight = 0;
 
   if (pwg_raster)
@@ -1651,7 +1716,7 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
               !strcasecmp(val, "off") ||
               !strcasecmp(val, "no"))
        h->MirrorPrint = CUPS_FALSE;
-      else if (set_defaults)
+      else
        h->MirrorPrint = CUPS_FALSE;
     }
     if ((val = cupsGetOption("negative-print", num_options, options)) != NULL ||
@@ -1664,24 +1729,35 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
               !strcasecmp(val, "off") ||
               !strcasecmp(val, "no"))
        h->NegativePrint = CUPS_FALSE;
-      else if (set_defaults)
+      else
        h->NegativePrint = CUPS_FALSE;
     }
   }
 
+  i = 0;
   if ((val = cupsGetOption("copies", num_options, options)) != NULL ||
       (val = cupsGetOption("Copies", num_options, options)) != NULL ||
       (val = cupsGetOption("num-copies", num_options, options)) != NULL ||
-      (val = cupsGetOption("NumCopies", num_options, options)) != NULL)
-    h->NumCopies = atol(val);
-  else if (set_defaults)
+      (val = cupsGetOption("NumCopies", num_options, options)) != NULL ||
+      cfIPPAttrIntValForPrinter(data->printer_attrs, data->job_attrs,
+                               "copies", &i) == 1)
+  {
+    if (val)
+      h->NumCopies = atol(val);
+    else if (i)
+      h->NumCopies = i;
+  }
+  else
     h->NumCopies = 1; /* 0 = Printer default */
 
   if ((val = cupsGetOption("orientation-requested", num_options,
                           options)) != NULL ||
       (val = cupsGetOption("OrientationRequested", num_options,
                           options)) != NULL ||
-      (val = cupsGetOption("Orientation", num_options, options)) != NULL)
+      (val = cupsGetOption("Orientation", num_options, options)) != NULL ||
+      (val = cfIPPAttrEnumValForPrinter(data->printer_attrs,
+                                       data->job_attrs,
+                                       "orientation-requested")) != NULL)
   {
     if (!strcasecmp(val, "Portrait") ||
        !strcasecmp(val, "3") ||
@@ -1698,10 +1774,10 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
             !strcasecmp(val, "ReverseLandscape") ||
             !strcasecmp(val, "6"))
       h->Orientation = CUPS_ORIENT_270;
-    else if (set_defaults)
+    else
       h->Orientation = CUPS_ORIENT_0;
   }
-  else if (set_defaults)
+  else
     h->Orientation = CUPS_ORIENT_0;
 
   if (pwg_raster)
@@ -1712,137 +1788,23 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
   else
   {
     if ((val = cupsGetOption("OutputFaceUp", num_options, options)) != NULL ||
-       (val = cupsGetOption("output-face-up", num_options, options)) != NULL)
+       (val = cupsGetOption("output-face-up", num_options, options)) != NULL ||
+       (val = cupsGetOption("OutputBin", num_options, options)) != NULL ||
+       (val = cupsGetOption("output-bin", num_options, options)) != NULL ||
+       (val = cfIPPAttrEnumValForPrinter(data->printer_attrs,
+                                         data->job_attrs,
+                                         "output-bin")) != NULL)
     {
       if (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
-         !strcasecmp(val, "yes"))
+         !strcasecmp(val, "yes") || !strcasecmp(val, "face-up") ||
+         !strcasecmp(val, "FaceUp"))
        h->OutputFaceUp = CUPS_TRUE;
-      else if (!strcasecmp(val, "false") ||
-              !strcasecmp(val, "off") ||
-              !strcasecmp(val, "no"))
+      else if (!strcasecmp(val, "false") || !strcasecmp(val, "off") ||
+              !strcasecmp(val, "no") || !strcasecmp(val, "face-down") ||
+              !strcasecmp(val, "FaceDown"))
        h->OutputFaceUp = CUPS_FALSE;
-      else if (set_defaults)
-       h->OutputFaceUp = CUPS_FALSE;
-    }
-  }
-
-  if ((val = cupsGetOption("media-size", num_options, options)) != NULL ||
-      (val = cupsGetOption("MediaSize", num_options, options)) != NULL ||
-      (val = cupsGetOption("page-size", num_options, options)) != NULL ||
-      (val = cupsGetOption("PageSize", num_options, options)) != NULL ||
-      (val = page_size) != NULL)
-  {
-    size_found = NULL;
-    if ((size_found = pwgMediaForPWG(val)) == NULL)
-      if ((size_found = pwgMediaForPPD(val)) == NULL)
-       size_found = pwgMediaForLegacy(val);
-    if (size_found != NULL)
-    {
-      h->PageSize[0] = size_found->width * 72 / 2540;
-      h->PageSize[1] = size_found->length * 72 / 2540;
-      _strlcpy(h->cupsPageSizeName, size_found->pwg,
-             sizeof(h->cupsPageSizeName));
-      if (pwg_raster)
-      {
-       h->cupsPageSize[0] = 0.0;
-       h->cupsPageSize[1] = 0.0;
-      }
       else
-      {
-       h->cupsPageSize[0] = size_found->width * 72.0 / 2540.0;
-       h->cupsPageSize[1] = size_found->length * 72.0 / 2540.0;
-      }
-    }
-  }
-  else if (set_defaults)
-  {
-    /* TODO: Automatic A4/Letter, like in scheduler/conf.c in CUPS. */
-    h->cupsPageSize[0] = 612.0f;
-    h->cupsPageSize[1] = 792.0f;
-    
-    h->PageSize[0] = 612;
-    h->PageSize[1] = 792;
-    _strlcpy(h->cupsPageSizeName, "na_letter_8.5x11in",
-           sizeof(h->cupsPageSizeName));
-    if (pwg_raster)
-    {
-      h->cupsPageSize[0] = 0.0;
-      h->cupsPageSize[1] = 0.0;
-    }
-  }
-  else if (pwg_raster)
-  {
-    h->cupsPageSize[0] = 0.0;
-    h->cupsPageSize[1] = 0.0;
-  }
-
-  if (pwg_raster)
-  {
-    /* Set "reserved" fields to 0 */
-    h->Margins[0] = 0;
-    h->Margins[1] = 0;
-    h->ImagingBoundingBox[0] = 0;
-    h->ImagingBoundingBox[1] = 0;
-    h->ImagingBoundingBox[2] = 0;
-    h->ImagingBoundingBox[3] = 0;
-    h->cupsImagingBBox[0] = 0.0;
-    h->cupsImagingBBox[1] = 0.0;
-    h->cupsImagingBBox[2] = 0.0;
-    h->cupsImagingBBox[3] = 0.0;
-  }
-  else
-  {
-    if ((val = cupsGetOption("media-left-margin", num_options, options))
-       != NULL)
-    {
-      size = atol(val) * 72.0 / 2540.0; 
-      h->Margins[0] = (int)size;
-      h->ImagingBoundingBox[0] = (int)size;
-      h->cupsImagingBBox[0] = size;
-    }
-    else if (set_defaults)
-    {
-      h->Margins[0] = 0;
-      h->ImagingBoundingBox[0] = 0;
-      h->cupsImagingBBox[0] = 18.0f;
-    }
-    if ((val = cupsGetOption("media-bottom-margin", num_options, options))
-       != NULL)
-    {
-      size = atol(val) * 72.0 / 2540.0; 
-      h->Margins[1] = (int)size;
-      h->ImagingBoundingBox[1] = (int)size;
-      h->cupsImagingBBox[1] = size;
-    }
-    else if (set_defaults)
-    {
-      h->Margins[1] = 0;
-      h->ImagingBoundingBox[1] = 0;
-      h->cupsImagingBBox[1] = 36.0f;
-    }
-    if ((val = cupsGetOption("media-right-margin", num_options, options))
-       != NULL)
-    {
-      size = atol(val) * 72.0 / 2540.0; 
-      h->ImagingBoundingBox[2] = h->PageSize[0] - (int)size;
-      h->cupsImagingBBox[2] = h->cupsPageSize[0] - size;
-    }
-    else if (set_defaults)
-    {
-      h->ImagingBoundingBox[2] = h->PageSize[0];
-      h->cupsImagingBBox[2] = 594.0f;
-    }
-    if ((val = cupsGetOption("media-top-margin", num_options, options))
-       != NULL)
-    {
-      size = atol(val) * 72.0 / 2540.0; 
-      h->ImagingBoundingBox[3] = h->PageSize[1] - (int)size;
-      h->cupsImagingBBox[3] = h->cupsPageSize[1] - size;
-    }
-    else if (set_defaults)
-    {
-      h->ImagingBoundingBox[3] = h->PageSize[1];
-      h->cupsImagingBBox[3] = 756.0f;
+       h->OutputFaceUp = CUPS_FALSE;
     }
   }
 
@@ -1864,7 +1826,7 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
               !strcasecmp(val, "off") ||
               !strcasecmp(val, "no"))
        h->Separations = CUPS_FALSE;
-      else if (set_defaults)
+      else
        h->Separations = CUPS_FALSE;
     }
     if ((val = cupsGetOption("tray-switch", num_options, options)) != NULL ||
@@ -1877,49 +1839,41 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
               !strcasecmp(val, "off") ||
               !strcasecmp(val, "no"))
        h->TraySwitch = CUPS_FALSE;
-      else if (set_defaults)
+      else
        h->TraySwitch = CUPS_FALSE;
     }
   }
 
-  if ((val = cupsGetOption("sides", num_options, options)) != NULL ||
-      (val = cupsGetOption("Tumble", num_options, options)) != NULL)
+  if ((val = cupsGetOption("Tumble", num_options, options)) != NULL)
   {
-    if (!strcasecmp(val, "None") || !strcasecmp(val, "Off") ||
-       !strcasecmp(val, "False") || !strcasecmp(val, "No") ||
-       !strcasecmp(val, "one-sided") || !strcasecmp(val, "OneSided") ||
-       !strcasecmp(val, "two-sided-long-edge") ||
-       !strcasecmp(val, "TwoSidedLongEdge") ||
-       !strcasecmp(val, "DuplexNoTumble"))
+    if (!strcasecmp(val, "Off") || !strcasecmp(val, "False") ||
+       !strcasecmp(val, "No"))
       h->Tumble = CUPS_FALSE;
-    else if (!strcasecmp(val, "On") ||
-            !strcasecmp(val, "True") || !strcasecmp(val, "Yes") ||
-            !strcasecmp(val, "two-sided-short-edge") ||
-            !strcasecmp(val, "TwoSidedShortEdge") ||
-            !strcasecmp(val, "DuplexTumble"))
+    else if (!strcasecmp(val, "On") || !strcasecmp(val, "True") ||
+            !strcasecmp(val, "Yes"))
       h->Tumble = CUPS_TRUE;
   }
 
-  h->cupsWidth = h->HWResolution[0] * h->PageSize[0] / 72;
-  h->cupsHeight = h->HWResolution[1] * h->PageSize[1] / 72;
-
-  if (pwg_raster || set_defaults)
-  {
-    /* TODO - Support for MediaType number */
-    h->cupsMediaType = 0;
-  }
-
-  if ((val = cupsGetOption("pwg-raster-document-type", num_options,
-                          options)) != NULL ||
-      (val = cupsGetOption("PwgRasterDocumentType", num_options,
-                          options)) != NULL ||
-      (val = cupsGetOption("color-space", num_options, options)) != NULL ||
-      (val = cupsGetOption("ColorSpace", num_options, options)) != NULL ||
-      (val = cupsGetOption("color-model", num_options, options)) != NULL ||
-      (val = cupsGetOption("ColorModel", num_options, options)) != NULL ||
-      (val = cupsGetOption("print-color-mode", num_options, options)) != NULL ||
-      (val = cupsGetOption("output-mode", num_options, options)) != NULL ||
-      (val = cupsGetOption("OutputMode", num_options, options)) != NULL)
+  /* TODO - Support for MediaType number */
+  h->cupsMediaType = 0;
+
+  /* Only for CUPS Raster, if we do not have a sample header from a PPD file */
+  if (pwg_raster == 0 &&
+      ((val = cupsGetOption("pwg-raster-document-type", num_options,
+                           options)) != NULL ||
+       (val = cupsGetOption("PwgRasterDocumentType", num_options,
+                           options)) != NULL ||
+       (val = cupsGetOption("color-space", num_options, options)) != NULL ||
+       (val = cupsGetOption("ColorSpace", num_options, options)) != NULL ||
+       (val = cupsGetOption("color-model", num_options, options)) != NULL ||
+       (val = cupsGetOption("ColorModel", num_options, options)) != NULL ||
+       (val = cupsGetOption("print-color-mode", num_options, options)) !=
+       NULL ||
+       (val = cupsGetOption("output-mode", num_options, options)) != NULL ||
+       (val = cupsGetOption("OutputMode", num_options, options)) != NULL ||
+       (val = cfIPPAttrEnumValForPrinter(data->printer_attrs,
+                                        data->job_attrs,
+                                        "print-color-mode")) != NULL))
   {
     int                bitspercolor,   /* Bits per color */
                 bitsperpixel,   /* Bits per pixel */
@@ -2055,11 +2009,8 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
     else if (!strcasecmp(val, "auto"))
     {
       /* Let "auto" not look like an error */
-      if (set_defaults)
-      {
-       colorspace = 19;
-       numcolors = 3;
-      }
+      colorspace = 19;
+      numcolors = 3;
     }
     if (numcolors > 0)
     {
@@ -2078,16 +2029,13 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
     }
     else
     {
-      if (set_defaults)
-      {
-       h->cupsBitsPerColor = 8;
-       h->cupsBitsPerPixel = 24;
-       h->cupsColorSpace = 19;
-       h->cupsNumColors = 3;
-      }
+      h->cupsBitsPerColor = 8;
+      h->cupsBitsPerPixel = 24;
+      h->cupsColorSpace = 19;
+      h->cupsNumColors = 3;
     }
   }
-  else if (set_defaults)
+  else
   {
     h->cupsBitsPerColor = 8;
     h->cupsBitsPerPixel = 24;
@@ -2095,38 +2043,24 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
     h->cupsNumColors = 3;
   }
 
-  h->cupsBytesPerLine = (h->cupsWidth * h->cupsBitsPerPixel + 7) / 8;
+  /* TODO - Support for color orders 1 (banded) and 2 (planar) */
+  h->cupsColorOrder = 0;
   
-  if (pwg_raster || set_defaults)
-  {
-    /* TODO - Support for color orders 1 (banded) and 2 (planar) */
-    h->cupsColorOrder = 0;
-  }
-  
-  if (pwg_raster || set_defaults)
-  {
-    /* TODO - Support for these parameters */
-    h->cupsCompression = 0;
-    h->cupsRowCount = 0;
-    h->cupsRowFeed = 0;
-    h->cupsRowStep = 0;
-  }
+  /* TODO - Support for these parameters */
+  h->cupsCompression = 0;
+  h->cupsRowCount = 0;
+  h->cupsRowFeed = 0;
+  h->cupsRowStep = 0;
 
-  if (pwg_raster || set_defaults)
-  {
-    /* TODO - Support for cupsBorderlessScalingFactor */
-    h->cupsBorderlessScalingFactor = 0.0;
-  }
+  /* TODO - Support for cupsBorderlessScalingFactor */
+  h->cupsBorderlessScalingFactor = 0.0;
 
-  if (pwg_raster || set_defaults)
+  /* TODO - Support for custom values in CUPS Raster mode */
+  for (i = 0; i < 16; i ++)
   {
-    /* TODO - Support for custom values in CUPS Raster mode */
-    for (i = 0; i < 16; i ++)
-    {
-      h->cupsInteger[i] = 0;
-      h->cupsReal[i] = 0.0;
-      memset(h->cupsString[i], 0, 64);
-    }
+    h->cupsInteger[i] = 0;
+    h->cupsReal[i] = 0.0;
+    memset(h->cupsString[i], 0, 64);
   }
 
   if (pwg_raster)
@@ -2142,11 +2076,38 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
        h->cupsInteger[0] = impressions;
     }
 
+    /* Printer property, command line options only for development and
+       debugging */
     if ((val = cupsGetOption("pwg-raster-document-sheet-back", num_options,
                             options)) != NULL ||
-       (val = cupsGetOption("PwgRasterDocumentSheetBack", num_options,
-                            options)) != NULL)
+       (val = cupsGetOption("back-side-orientation", num_options,
+                            options)) != NULL ||
+       (data->printer_attrs &&
+        ((attr = ippFindAttribute(data->printer_attrs, "urf-supported",
+                                  IPP_TAG_ZERO)) != NULL ||
+         (attr = ippFindAttribute(data->printer_attrs,
+                                  "pwg-raster-document-sheet-back",
+                                  IPP_TAG_ZERO)) != NULL ||
+         (attr = ippFindAttribute(data->printer_attrs,
+                                  "pclm-raster-back-side",
+                                  IPP_TAG_ZERO)) != NULL)))
     {
+      if (val == NULL)
+      {
+       if (ippGetCount(attr) > 1) // urf-supported
+       {
+         for (i = 0; i < ippGetCount(attr); i ++)
+         {
+           val = ippGetString(attr, i, NULL);
+           if (strncmp(val, "DM", 2) == 0) // Duplex mode field
+             break;
+         }
+         if (i == ippGetCount(attr)) // Not found, no duplex
+           val = "DM1";
+       }
+       else // pwg-raster-document-sheet-back/pclm-raster-back-side
+         val = ippGetString(attr, 0, NULL);
+      }
       /* Set CrossFeedTransform and FeedTransform */
       if (h->Duplex == CUPS_FALSE)
       {
@@ -2157,22 +2118,26 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
       {
        if (h->Tumble == CUPS_FALSE)
        {
-         if (!strcasecmp(val, "Flipped"))
+         if (!strcasecmp(val, "Flipped") ||
+             !strcasecmp(val, "DM2"))
          {
            h->cupsInteger[1] =  1;
            h->cupsInteger[2] = -1;
          }
-         else if (!strncasecmp(val, "Manual", 6))
+         else if (!strncasecmp(val, "Manual", 6) ||
+                  !strcasecmp(val, "DM4"))
          {
            h->cupsInteger[1] =  1;
            h->cupsInteger[2] =  1;
          }
-         else if (!strcasecmp(val, "Normal"))
+         else if (!strcasecmp(val, "Normal") ||
+                  !strcasecmp(val, "DM1"))
          {
            h->cupsInteger[1] =  1;
            h->cupsInteger[2] =  1;
          }
-         else if (!strcasecmp(val, "Rotated"))
+         else if (!strcasecmp(val, "Rotated") ||
+                  !strcasecmp(val, "DM3"))
          {
            h->cupsInteger[1] = -1;
            h->cupsInteger[2] = -1;
@@ -2185,22 +2150,26 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
        }
        else
        {
-         if (!strcasecmp(val, "Flipped"))
+         if (!strcasecmp(val, "Flipped") ||
+             !strcasecmp(val, "DM2"))
          {
            h->cupsInteger[1] = -1;
            h->cupsInteger[2] =  1;
          }
-         else if (!strncasecmp(val, "Manual", 6))
+         else if (!strncasecmp(val, "Manual", 6) ||
+                  !strcasecmp(val, "DM4"))
          {
            h->cupsInteger[1] = -1;
            h->cupsInteger[2] = -1;
          }
-         else if (!strcasecmp(val, "Normal"))
+         else if (!strcasecmp(val, "Normal") ||
+                  !strcasecmp(val, "DM1"))
          {
            h->cupsInteger[1] =  1;
            h->cupsInteger[2] =  1;
          }
-         else if (!strcasecmp(val, "Rotated"))
+         else if (!strcasecmp(val, "Rotated") ||
+                  !strcasecmp(val, "DM3"))
          {
            h->cupsInteger[1] =  1;
            h->cupsInteger[2] =  1;
@@ -2266,7 +2235,7 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
     {
       int vendorlength = atoi(val);            /* How many bytes of vendor
                                                   data? */
-      if (vendorlength <= 1088)
+      if (vendorlength > 0 && vendorlength <= 1088)
       {
        h->cupsInteger[15] = vendorlength;
        if ((val = cupsGetOption("vendor-data", num_options,
@@ -2279,18 +2248,18 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
     }
   }
 
-  if (pwg_raster || set_defaults)
-  {
-    /* Set "reserved" fields to 0 */
-    memset(h->cupsMarkerType, 0, 64);
-  }
+  /* Set "reserved" fields to 0 */
+  memset(h->cupsMarkerType, 0, 64);
 
   if ((val = cupsGetOption("print-rendering-intent", num_options,
                           options)) != NULL ||
       (val = cupsGetOption("PrintRenderingIntent", num_options,
                           options)) != NULL ||
       (val = cupsGetOption("RenderingIntent", num_options,
-                          options)) != NULL)
+                          options)) != NULL ||
+      (val = cfIPPAttrEnumValForPrinter(data->printer_attrs,
+                                       data->job_attrs,
+                                       "print-rendering-intent")) != NULL)
   {
     if (!strcmp(val, "absolute"))
       _strlcpy(h->cupsRenderingIntent, "Absolute",
@@ -2304,24 +2273,22 @@ cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
     else if (!strcmp(val, "relative"))
       _strlcpy(h->cupsRenderingIntent, "Relative",
              sizeof(h->cupsRenderingIntent));
-    else if (!strcmp(val, "relative-bpc"))
+    else if (!strcmp(val, "relative-bpc") ||
+            !strcmp(val, "RelativeBpc"))
       _strlcpy(h->cupsRenderingIntent, "RelativeBpc",
              sizeof(h->cupsRenderingIntent));
     else if (!strcmp(val, "saturation"))
       _strlcpy(h->cupsRenderingIntent, "Saturation",
              sizeof(h->cupsRenderingIntent));
   }
-  else if (set_defaults)
+  else
     h->cupsRenderingIntent[0] = '\0';
 
   if (media_source != NULL)
     free(media_source);
   if (media_type != NULL)
     free(media_type);
-  if (page_size != NULL)
-    free(page_size);
   cupsFreeOptions(num_options, options);
-#endif /* HAVE_CUPS_1_7 */
 
   return (0);
 }
index 2122dfaf34c2fe1cb5c13b29268a81723e30dbb1..f866dafa559b3c6052f592b9486c63dcf918bd8e 100644 (file)
@@ -51,6 +51,7 @@ typedef enum cf_backside_orient_e
  * Prototypes...
  */
 
+extern const char *     cfRasterColorSpaceString(cups_cspace_t cspace);
 extern int              cfRasterPrepareHeader(cups_page_header2_t *h,
                                              cf_filter_data_t *data,
                                              cf_filter_out_format_t
@@ -64,10 +65,6 @@ extern int              cfRasterSetColorSpace(cups_page_header2_t *h,
                                              const char *color_mode,
                                              cups_cspace_t *cspace,
                                              int *high_depth);
-extern int              cfRasterParseIPPOptions(cups_page_header2_t *h,
-                                               cf_filter_data_t *data,
-                                               int pwg_raster,
-                                               int set_defaults);
 extern int             cfJoinJobOptionsAndAttrs(cf_filter_data_t *data,
                                                 int num_options,
                                                 cups_option_t **options);
@@ -77,11 +74,9 @@ extern int           cfRasterMatchIPPSize(cups_page_header2_t *header,
                                             double dimensions[2],
                                             int *image_fit,
                                             int *landscape);
-extern int             cfGetBackSideAndHeaderDuplex(ipp_t *printer_attrs,
-                                                    cups_page_header2_t
-                                                    *header);
-extern int             cfGetPrintRenderIntent(cf_filter_data_t *data,
-                                              cups_page_header2_t *header);
+extern int             cfGetBackSideOrientation(cf_filter_data_t *data);
+extern const char      *cfGetPrintRenderIntent(cf_filter_data_t *data,
+                                               char *ri, int ri_len);
 
 #  ifdef __cplusplus
 }
index 9c32599b27cf988a9c03d46da4c84c3f66c33ab3..29702bee89d5d9d822b10bd9a109f21c348cb8d2 100644 (file)
@@ -36,6 +36,7 @@
 #include <cups/raster.h>
 #include <cupsfilters/colormanager.h>
 #include <cupsfilters/image.h>
+#include <cupsfilters/raster.h>
 
 #include <arpa/inet.h>   // ntohl
 
@@ -1331,6 +1332,7 @@ cfFilterRasterToPDF(int inputfd,    /* I - File descriptor input stream */
        void *parameters)    /* I - Filter-specific parameters (outformat) */
 {
   int i;
+  char *t;
   rastertopdf_doc_t    doc;            /* Document information */
   FILE          *outputfp;              /* Output data stream */
   cf_filter_out_format_t outformat; /* Output format */
@@ -1340,7 +1342,6 @@ cfFilterRasterToPDF(int inputfd,    /* I - File descriptor input stream */
   struct pdf_info pdf;
   cups_raster_t        *ras;           /* Raster stream for printing */
   cups_page_header2_t  header;         /* Page header from file */
-  ppd_attr_t    *attr;  /* PPD attribute */
   ipp_t *printer_attrs = data->printer_attrs; /* Printer attributes from printer data*/
   ipp_attribute_t *ipp_attr; /* Printer attribute*/
   const char*         profile_name = NULL;     /* IPP Profile Name */
@@ -1362,7 +1363,21 @@ cfFilterRasterToPDF(int inputfd,    /* I - File descriptor input stream */
       outformat = CF_FILTER_OUT_FORMAT_PDF;
   }
   else
-    outformat = CF_FILTER_OUT_FORMAT_PDF;
+  {
+    t = data->final_content_type;
+    if (t)
+    {
+      if (strcasestr(t, "pclm"))
+       outformat = CF_FILTER_OUT_FORMAT_PCLM;
+      else if (strcasestr(t, "pdf"))
+       outformat = CF_FILTER_OUT_FORMAT_PDF;
+      else
+       outformat = CF_FILTER_OUT_FORMAT_PDF;
+    }
+    else
+      outformat = CF_FILTER_OUT_FORMAT_PDF;
+  }
+
   if (log) log(ld, CF_LOGLEVEL_DEBUG,
               "cfFilterRasterToPDF: OUTFORMAT=\"%s\"",
               outformat == CF_FILTER_OUT_FORMAT_PDF ? "PDF" : "PCLM");
@@ -1391,7 +1406,7 @@ cfFilterRasterToPDF(int inputfd,    /* I - File descriptor input stream */
   doc.iscanceleddata = icd;
 
   /* support the CUPS "cm-calibration" option */ 
-  cm_calibrate = cfCmGetCupsColorCalibrateMode(data, data->options, data->num_options);
+  cm_calibrate = cfCmGetCupsColorCalibrateMode(data);
 
   if (outformat == CF_FILTER_OUT_FORMAT_PCLM ||
       cm_calibrate == CF_CM_CALIBRATION_ENABLED)
@@ -1399,11 +1414,10 @@ cfFilterRasterToPDF(int inputfd,    /* I - File descriptor input stream */
   else
     doc.cm_disabled = cfCmIsPrinterCmDisabled(data);
 
-  if (outformat == CF_FILTER_OUT_FORMAT_PCLM && data->ppd == NULL
-        && printer_attrs == NULL )
+  if (outformat == CF_FILTER_OUT_FORMAT_PCLM && printer_attrs == NULL)
   {
     if (log) log(ld, CF_LOGLEVEL_ERROR,
-      "cfFilterRasterToPDF: PCLm output:  Neither a PPD file nor printer IPP attributes are supplied, PCLm output not possible.");
+      "cfFilterRasterToPDF: PCLm output: No printer IPP attributes are supplied, PCLm output not possible.");
     return 1;
   }
 
@@ -1413,109 +1427,8 @@ cfFilterRasterToPDF(int inputfd,    /* I - File descriptor input stream */
   // Process pages as needed...
   Page = 0;
 
-  /* Get PCLm attributes from PPD */
-  if (data->ppd && outformat == CF_FILTER_OUT_FORMAT_PCLM)
-  {
-    char *attr_name = (char *)"cupsPclmStripHeightPreferred";
-    if ((attr = ppdFindAttr(data->ppd, attr_name, NULL)) != NULL)
-    {
-      if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterRasterToPDF: PPD PCLm attribute \"%s\" with value \"%s\"",
-                  attr_name, attr->value);
-      pdf.pclm_strip_height_preferred = atoi(attr->value);
-    }
-    else
-      pdf.pclm_strip_height_preferred = 16; /* default strip height */
-
-    attr_name = (char *)"cupsPclmStripHeightSupported";
-    if ((attr = ppdFindAttr(data->ppd, attr_name, NULL)) != NULL)
-    {
-      if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterRasterToPDF: PPD PCLm attribute \"%s\" with value \"%s\"",
-                  attr_name, attr->value);
-      pdf.pclm_strip_height_supported.clear();  // remove default value = 16
-      std::vector<std::string> vec = split_strings(attr->value, ",");
-      for (size_t i = 0; i < vec.size(); i ++)
-        pdf.pclm_strip_height_supported.push_back(atoi(vec[i].c_str()));
-      vec.clear();
-    }
-
-    attr_name = (char *)"cupsPclmRasterBackSide";
-    if ((attr = ppdFindAttr(data->ppd, attr_name, NULL)) != NULL)
-    {
-      if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterRasterToPDF: PPD PCLm attribute \"%s\" with value \"%s\"",
-                  attr_name, attr->value);
-      pdf.pclm_raster_back_side = attr->value;
-    }
-
-    attr_name = (char *)"cupsPclmSourceResolutionSupported";
-    if ((attr = ppdFindAttr(data->ppd, attr_name, NULL)) != NULL)
-    {
-      if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterRasterToPDF: PPD PCLm attribute \"%s\" with value \"%s\"",
-                  attr_name, attr->value);
-      pdf.pclm_source_resolution_supported = split_strings(attr->value, ",");
-    }
-
-    attr_name = (char *)"cupsPclmSourceResolutionDefault";
-    if ((attr = ppdFindAttr(data->ppd, attr_name, NULL)) != NULL)
-    {
-      if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterRasterToPDF: PPD PCLm attribute \"%s\" with value \"%s\"",
-                  attr_name, attr->value);
-      pdf.pclm_source_resolution_default = attr->value;
-    }
-    else if (pdf.pclm_source_resolution_supported.size() > 0)
-    {
-      pdf.pclm_source_resolution_default =
-       pdf.pclm_source_resolution_supported[0];
-      if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterRasterToPDF: PPD PCLm attribute \"%s\" missing, taking first item of \"cupsPclmSourceResolutionSupported\" as default resolution",
-                  attr_name);
-    }
-    else
-    {
-      if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "cfFilterRasterToPDF: PCLm output: PPD file does not contain printer resolution information for PCLm.");
-      return 1;
-    }
-
-    attr_name = (char *)"cupsPclmCompressionMethodPreferred";
-    if ((attr = ppdFindAttr(data->ppd, attr_name, NULL)) != NULL)
-    {
-      if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterRasterToPDF: PPD PCLm attribute \"%s\" with value \"%s\"",
-                  attr_name, attr->value);
-      std::vector<std::string> vec = split_strings(attr->value, ",");
-
-      // get all compression methods supported by the printer
-      for (std::vector<std::string>::iterator it = vec.begin();
-            it != vec.end(); ++it)
-      {
-        std::string compression_method = *it;
-        for (char& x: compression_method)
-          x = tolower(x);
-        if (compression_method == "flate")
-          pdf.pclm_compression_method_preferred.push_back(FLATE_DECODE);
-        else if (compression_method == "rle")
-          pdf.pclm_compression_method_preferred.push_back(RLE_DECODE);
-        else if (compression_method == "jpeg")
-          pdf.pclm_compression_method_preferred.push_back(DCT_DECODE);
-      }
-
-    }
-    // If the compression methods is none of the above or is erreneous
-    // use FLATE as compression method and show a warning.
-    if (pdf.pclm_compression_method_preferred.empty())
-    {
-      if (log) log(ld, CF_LOGLEVEL_WARN,
-                  "(rastertopclm) Unable parse PPD attribute \"%s\". "
-                  "Using FLATE for encoding image streams.", attr_name);
-      pdf.pclm_compression_method_preferred.push_back(FLATE_DECODE);
-    }
-  }
-  else if(outformat == CF_FILTER_OUT_FORMAT_PCLM && printer_attrs)
+  /* Get PCLm parameters from printer IPP attributes */
+  if (outformat == CF_FILTER_OUT_FORMAT_PCLM)
   {
     if (log)
     {
@@ -1666,6 +1579,10 @@ cfFilterRasterToPDF(int inputfd,    /* I - File descriptor input stream */
     if (log) log(ld, CF_LOGLEVEL_INFO,
                 "cfFilterRasterToPDF: Starting page %d.", Page);
 
+    // Update rendering intent with user settings or the default
+    cfGetPrintRenderIntent(data, header.cupsRenderingIntent,
+                          sizeof(header.cupsRenderingIntent));
+
     // Use "profile=profile_name.icc" to embed 'profile_name.icc' into the PDF
     // for testing. Forces color management to enable.
     if (outformat == CF_FILTER_OUT_FORMAT_PDF &&
index a92cdfa0b781d547046a17a08bdac81c07acf725..30a7ee4c141a63f5cee16c52ee75c8381ea7db12 100644 (file)
@@ -12,7 +12,8 @@
  */
 
 #include "filter.h"
-#include <ppd/ppd.h>
+#include "raster.h"
+#include "ipp.h"
 #include <cups/raster.h>
 #include <unistd.h>
 #include <fcntl.h>
@@ -48,54 +49,51 @@ cfFilterRasterToPWG(int inputfd,         /* I - File descriptor input stream */
                        lineoffset;     /* Offset into line */
   int                  tmp;
   unsigned char                white;          /* White pixel */
-       /* PPD file */
-  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 */
+  int                  back;           /* Back side orientation */
+  char                  buf[64];
+  int                   width,
+                        height,
+                        left,
+                        right,
+                        bottom,
+                        top;
+  int                  num_options = 0;/* Number of options */
   cups_option_t                *options = NULL;/* Options */
   const char           *val;           /* Option value */
   cf_filter_iscanceledfunc_t iscanceled = data->iscanceledfunc;
   void                 *icd = data->iscanceleddata;
   cf_logfunc_t     log = data->logfunc;
   void          *ld = data->logdata;
-  cf_filter_out_format_t output_format;
+  int                   res = 0;
 
 
-  if (parameters)
-  {
-    output_format = *(cf_filter_out_format_t *)parameters;
-    if (output_format == CF_FILTER_OUT_FORMAT_PWG_RASTER)
+  val = data->final_content_type;
+  if (val) {
+    if (strcasestr(val, "pwg"))
       outras = cupsRasterOpen(outputfd, CUPS_RASTER_WRITE_PWG);
-    else if (output_format == CF_FILTER_OUT_FORMAT_APPLE_RASTER)
+    else if (strcasestr(val, "urf"))
       outras = cupsRasterOpen(outputfd, CUPS_RASTER_WRITE_APPLE);
     else
     {
       if (log) log(ld, CF_LOGLEVEL_ERROR,
                   "cfFilterRasterToPWG: Invalid output format specified. Only PWG Raster and Apple Raster/URF are supported.");
+
+      close(inputfd);
+      close(outputfd);
       return (1);
     }
   }
   else
   {
-    if (log) log(ld, CF_LOGLEVEL_ERROR,
-                "cfFilterRasterToPWG: Output format not specified.");
-    return (1);
+    if (log) log(ld, CF_LOGLEVEL_WARN,
+                "cfFilterRasterToPWG: Output format not specified, defaulting to PWG Raster.");
+    
+    outras = cupsRasterOpen(outputfd, CUPS_RASTER_WRITE_PWG);
   }
 
-  inras  = cupsRasterOpen(inputfd, CUPS_RASTER_READ);
+  num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
 
-  if (!data->ppd)
-  {
-    if (log) log(ld, CF_LOGLEVEL_DEBUG,
-     "cfFilterRasterToPWG: PPD file is not specified.");
-  }
-  else
-  {
-    back = ppdFindAttr(data->ppd, "cupsBackSide", NULL);
-    cache = data->ppd->cache;
-  }
+  inras  = cupsRasterOpen(inputfd, CUPS_RASTER_READ);
 
   while (cupsRasterReadHeader2(inras, &inheader))
   {
@@ -203,7 +201,8 @@ cfFilterRasterToPWG(int inputfd,         /* I - File descriptor input stream */
                   "cfFilterRasterToPWG: Unsupported raster data.");
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
                   "cfFilterRasterToPWG: Bad bottom/left/top margin on page %d.", page);
-      return (1);
+      res = 1;
+      goto fail;
     }
 
     switch (inheader.cupsColorSpace)
@@ -242,7 +241,8 @@ cfFilterRasterToPWG(int inputfd,         /* I - File descriptor input stream */
        if (log) log(ld,CF_LOGLEVEL_DEBUG,
                     "cfFilterRasterToPWG: Unsupported cupsColorSpace %d on page %d.",
                     inheader.cupsColorSpace, page);
-       return (1);
+       res = 1;
+       goto fail;
     }
 
     if (inheader.cupsColorOrder != CUPS_ORDER_CHUNKED)
@@ -252,7 +252,8 @@ cfFilterRasterToPWG(int inputfd,         /* I - File descriptor input stream */
       if (log) log(ld,CF_LOGLEVEL_DEBUG,
                   "cfFilterRasterToPWG: Unsupported cupsColorOrder %d on page %d.",
                   inheader.cupsColorOrder, page);
-      return (1);
+      res = 1;
+      goto fail;
     }
 
     if (inheader.cupsBitsPerPixel != 1 &&
@@ -263,7 +264,8 @@ cfFilterRasterToPWG(int inputfd,         /* I - File descriptor input stream */
       if (log) log(ld,CF_LOGLEVEL_DEBUG,
                   "cfFilterRasterToPWG: Unsupported cupsBitsPerColor %d on page %d.",
                   inheader.cupsBitsPerColor, page);
-      return (1);
+      res = 1;
+      goto fail;
     }
 
     memcpy(&outheader, &inheader, sizeof(outheader));
@@ -274,7 +276,7 @@ cfFilterRasterToPWG(int inputfd,         /* I - File descriptor input stream */
     outheader.cupsInteger[14]  = 0;    /* VendorIdentifier */
     outheader.cupsInteger[15]  = 0;    /* VendorLength */
 
-    if ((val = cupsGetOption("print-content-optimize", data->num_options,
+    if ((val = cupsGetOption("print-content-optimize", num_options,
                              options)) != NULL)
     {
       if (!strcmp(val, "automatic"))
@@ -300,7 +302,7 @@ cfFilterRasterToPWG(int inputfd,         /* I - File descriptor input stream */
     }
 
     if ((val = cupsGetOption("print-quality",
-                            data->num_options, options)) != NULL)
+                            num_options, options)) != NULL)
     {
       unsigned quality = (unsigned)atoi(val); /* print-quality value */
 
@@ -314,65 +316,63 @@ cfFilterRasterToPWG(int inputfd,         /* I - File descriptor input stream */
       }
     }
 
-    if ((val = cupsGetOption("print-rendering-intent", data->num_options,
-                             options)) != NULL)
-    {
-      if (!strcmp(val, "absolute"))
-        strncpy(outheader.cupsRenderingIntent, "Absolute",
-                sizeof(outheader.cupsRenderingIntent));
-      else if (!strcmp(val, "automatic"))
-        strncpy(outheader.cupsRenderingIntent, "Automatic",
-                sizeof(outheader.cupsRenderingIntent));
-      else if (!strcmp(val, "perceptual"))
-        strncpy(outheader.cupsRenderingIntent, "Perceptual",
-                sizeof(outheader.cupsRenderingIntent));
-      else if (!strcmp(val, "relative"))
-        strncpy(outheader.cupsRenderingIntent, "Relative",
-                sizeof(outheader.cupsRenderingIntent));
-      else if (!strcmp(val, "relative-bpc"))
-        strncpy(outheader.cupsRenderingIntent, "RelativeBpc",
-                sizeof(outheader.cupsRenderingIntent));
-      else if (!strcmp(val, "saturation"))
-        strncpy(outheader.cupsRenderingIntent, "Saturation",
-                sizeof(outheader.cupsRenderingIntent));
-      else
-      {
-        if (log) log(ld,CF_LOGLEVEL_DEBUG,
-                    "cfFilterRasterToPWG: Unsupported print-rendering-intent value.");
-        outheader.cupsRenderingIntent[0] = '\0';
-      }
-    }
+    /* Update rendering intent with user settings or the default */
+    outheader.cupsRenderingIntent[0] = '\0';
+    cfGetPrintRenderIntent(data, outheader.cupsRenderingIntent,
+                          sizeof(outheader.cupsRenderingIntent));
 
-    if (inheader.cupsPageSizeName[0] &&
-       (pwg_size = ppdCacheGetSize(cache,
-                                   inheader.cupsPageSizeName)) != NULL &&
-       pwg_size->map.pwg)
+    /* First try to use the input page size name for the output page,
+       check whether this size is supported by theprinter */
+    buf[0] = '\0';
+    if (inheader.cupsPageSizeName[0])
     {
-      strncpy(outheader.cupsPageSizeName, pwg_size->map.pwg,
-             sizeof(outheader.cupsPageSizeName) - 1);
+      /* Take only a page size name for a page size the printer actually
+        supports */
+      snprintf(buf, sizeof(buf), "%.63s", inheader.cupsPageSizeName);
+      cfGenerateSizes(data->printer_attrs, CF_GEN_SIZES_SEARCH, NULL, NULL,
+                     NULL, NULL, NULL, NULL, NULL, NULL,
+                     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                     buf, NULL);
     }
+    if (buf[0])
+      snprintf(outheader.cupsPageSizeName,
+              sizeof(outheader.cupsPageSizeName),
+              "%.63s", buf);
     else
     {
-      pwg_media =
-       pwgMediaForSize((int)(2540.0 * inheader.cupsPageSize[0] / 72.0),
-                       (int)(2540.0 * inheader.cupsPageSize[1] / 72.0));
-
-      if (pwg_media)
-        strncpy(outheader.cupsPageSizeName, pwg_media->pwg,
-                sizeof(outheader.cupsPageSizeName) - 1);
+      /* No name found, find the printer's page size by the size dimensions
+         and margins */
+      width = (int)(2540.0 * inheader.cupsPageSize[0] / 72.0);
+      height = (int)(2540.0 * inheader.cupsPageSize[1] / 72.0);
+      left = (int)(2540.0 * inheader.ImagingBoundingBox[0] / 72.0);
+      bottom = (int)(2540.0 * inheader.ImagingBoundingBox[1] / 72.0);
+      right = width - (int)(2540.0 * inheader.ImagingBoundingBox[2] / 72.0);
+      top = height - (int)(2540.0 * inheader.ImagingBoundingBox[3] / 72.0);
+      cfGenerateSizes(data->printer_attrs, CF_GEN_SIZES_SEARCH, NULL, NULL,
+                     &width, &height, &left, &bottom, &right, &top,
+                     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                     buf, NULL);
+      if (buf[0])
+       snprintf(outheader.cupsPageSizeName,
+                sizeof(outheader.cupsPageSizeName),
+                "%.63s", buf);
       else
       {
         if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                    "cfFilterRasterToPWG: Unsupported PageSize %.2fx%.2f.",
+                    "cfFilterRasterToPWG: Page size %.2fx%.2f not supported by printer.",
                     inheader.cupsPageSize[0], inheader.cupsPageSize[1]);
         outheader.cupsPageSizeName[0] = '\0';
       }
     }
 
     if (inheader.Duplex && !(page & 1) &&
-        back && strcasecmp(back->value, "Normal"))
+       (back = cfGetBackSideOrientation(data)) > 0 &&
+        (back &= 7) != CF_BACKSIDE_NORMAL)
     {
-      if (strcasecmp(back->value, "Flipped"))
+      outheader.Duplex = CUPS_TRUE;
+      outheader.Tumble = inheader.Tumble;
+
+      if (back == CF_BACKSIDE_FLIPPED)
       {
         if (inheader.Tumble)
         {
@@ -403,7 +403,7 @@ cfFilterRasterToPWG(int inputfd,         /* I - File descriptor input stream */
                                        /* ImageBoxBottom */
         }
       }
-      else if (strcasecmp(back->value, "ManualTumble"))
+      else if (back == CF_BACKSIDE_MANUAL_TUMBLE)
       {
         if (inheader.Tumble)
         {
@@ -435,7 +435,7 @@ cfFilterRasterToPWG(int inputfd,         /* I - File descriptor input stream */
                                        /* ImageBoxBottom */
         }
       }
-      else if (strcasecmp(back->value, "Rotated"))
+      else if (back == CF_BACKSIDE_ROTATED)
       {
         if (inheader.Tumble)
         {
@@ -473,7 +473,7 @@ cfFilterRasterToPWG(int inputfd,         /* I - File descriptor input stream */
         */
 
         if (log) log(ld,CF_LOGLEVEL_DEBUG,
-                    "cfFilterRasterToPWG: Unsupported cupsBackSide value.");
+                    "cfFilterRasterToPWG: Unsupported back side orientation value.");
 
        outheader.cupsInteger[1] = 1;   /* CrossFeedTransform */
        outheader.cupsInteger[2] = 1;   /* FeedTransform */
@@ -490,6 +490,9 @@ cfFilterRasterToPWG(int inputfd,         /* I - File descriptor input stream */
     }
     else
     {
+      outheader.Duplex = inheader.Duplex;
+      outheader.Tumble = inheader.Tumble;
+
       outheader.cupsInteger[1] = 1;    /* CrossFeedTransform */
       outheader.cupsInteger[2] = 1;    /* FeedTransform */
 
@@ -509,7 +512,8 @@ cfFilterRasterToPWG(int inputfd,         /* I - File descriptor input stream */
                   "cfFilterRasterToPWG: Error sending raster data.");
       if (log) log(ld,CF_LOGLEVEL_DEBUG,
                   "cfFilterRasterToPWG: Unable to write header for page %d.", page);
-      return (1);
+      res = 1;
+      goto fail;
     }
 
    /*
@@ -533,7 +537,8 @@ cfFilterRasterToPWG(int inputfd,         /* I - File descriptor input stream */
        if (log) log(ld,CF_LOGLEVEL_DEBUG,
                     "cfFilterRasterToPWG: Unable to write line %d for page %d.",
                     page_top - y + 1, page);
-       return (1);
+       res = 1;
+       goto fail;
       }
 
     for (y = inheader.cupsHeight; y > 0; y --)
@@ -547,7 +552,8 @@ cfFilterRasterToPWG(int inputfd,         /* I - File descriptor input stream */
        if (log) log(ld,CF_LOGLEVEL_DEBUG,
                     "cfFilterRasterToPWG: Unable to read line %d for page %d.",
                     inheader.cupsHeight - y + page_top + 1, page);
-       return (1);
+       res = 1;
+       goto fail;
       }
 
       if (!cupsRasterWritePixels(outras, line, outheader.cupsBytesPerLine))
@@ -557,7 +563,8 @@ cfFilterRasterToPWG(int inputfd,         /* I - File descriptor input stream */
        if (log) log(ld,CF_LOGLEVEL_DEBUG,
                     "cfFilterRasterToPWG: Unable to write line %d for page %d.",
                     inheader.cupsHeight - y + page_top + 1, page);
-       return (1);
+       res = 1;
+       goto fail;
       }
     }
 
@@ -571,17 +578,22 @@ cfFilterRasterToPWG(int inputfd,         /* I - File descriptor input stream */
                     "cfFilterRasterToPWG: Unable to write line %d for page %d.",
                     page_bottom - y + page_top + inheader.cupsHeight + 1,
                     page);
-       return (1);
+       res = 1;
+       goto fail;
       }
 
     free(line);
   }
 
+ fail:
+
   cupsRasterClose(inras);
   close(inputfd);
 
   cupsRasterClose(outras);
   close(outputfd);
 
-  return (0);
+  cupsFreeOptions(num_options, options);
+
+  return (res);
 }
index e34431dac44222bcdf66cafc709a5d112b9fdb2d..440f601cf3127151a0ededeffdd4e799baaa9060 100644 (file)
@@ -14,7 +14,6 @@
  *   cfRGBDelete() - Delete a color separation.
  *   cfRGBDoGray() - Do a grayscale separation...
  *   cfRGBDoRGB()  - Do a RGB separation...
- *   cfRGBLoad()   - Load a RGB color profile from a PPD file.
  *   cfRGBNew()    - Create a new RGB color separation.
  */
 
@@ -299,129 +298,6 @@ cfRGBDoRGB(cf_rgb_t          *rgbptr,
 }
 
 
-/*
- * 'cfRGBLoad()' - Load a RGB color profile from a PPD file.
- */
-
-cf_rgb_t *                             /* O - New color profile */
-cfRGBLoad(ppd_file_t *ppd,             /* I - PPD file */
-            const char *colormodel,    /* I - Color model */
-            const char *media,         /* I - Media type */
-            const char *resolution,    /* I - Resolution */
-           cf_logfunc_t log,       /* I - Log function */
-           void       *ld)             /* I - Log function data */
-{
-  int          i,                      /* Looping var */
-               cube_size,              /* Size of color lookup cube */
-               num_channels,           /* Number of color channels */
-               num_samples;            /* Number of color samples */
-  cf_sample_t  *samples;               /* Color samples */
-  float                values[7];              /* Color sample values */
-  char         spec[PPD_MAX_NAME];     /* Profile name */
-  ppd_attr_t   *attr;                  /* Attribute from PPD file */
-  cf_rgb_t     *rgbptr;                /* RGB color profile */
-
-
- /*
-  * Find the following attributes:
-  *
-  *    cupsRGBProfile  - Specifies the cube size, number of channels, and
-  *                      number of samples
-  *    cupsRGBSample   - Specifies an RGB to CMYK color sample
-  */
-
-  if ((attr = cfFindAttr(ppd, "cupsRGBProfile", colormodel, media,
-                           resolution, spec, sizeof(spec), log, ld)) == NULL)
-  {
-    if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "No cupsRGBProfile attribute found for the current settings!");
-    return (NULL);
-  }
-
-  if (!attr->value || sscanf(attr->value, "%d%d%d", &cube_size, &num_channels,
-                             &num_samples) != 3)
-  {
-    if (log) log(ld, CF_LOGLEVEL_ERROR,
-                "Bad cupsRGBProfile attribute \'%s\'!",
-                attr->value ? attr->value : "(null)");
-    return (NULL);
-  }
-
-  if (cube_size < 2 || cube_size > 16 ||
-      num_channels < 1 || num_channels > CF_MAX_RGB ||
-      num_samples != (cube_size * cube_size * cube_size))
-  {
-    if (log) log(ld, CF_LOGLEVEL_ERROR,
-                "Bad cupsRGBProfile attribute \'%s\'!",
-                attr->value);
-    return (NULL);
-  }
-
- /*
-  * Allocate memory for the samples and read them...
-  */
-
-  if ((samples = calloc(num_samples, sizeof(cf_sample_t))) == NULL)
-  {
-    if (log) log(ld, CF_LOGLEVEL_ERROR,
-                "Unable to allocate memory for RGB profile!");
-    return (NULL);
-  }
-
- /*
-  * Read all of the samples...
-  */
-
-  for (i = 0; i < num_samples; i ++)
-    if ((attr = ppdFindNextAttr(ppd, "cupsRGBSample", spec)) == NULL)
-      break;
-    else if (!attr->value)
-    {
-      if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "Bad cupsRGBSample value!");
-      break;
-    }
-    else if (sscanf(attr->value, "%f%f%f%f%f%f%f", values + 0,
-                    values + 1, values + 2, values + 3, values + 4, values + 5,
-                    values + 6) != (3 + num_channels))
-    {
-      if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "Bad cupsRGBSample value!");
-      break;
-    }
-    else
-    {
-      samples[i].rgb[0]    = (int)(255.0 * values[0] + 0.5);
-      samples[i].rgb[1]    = (int)(255.0 * values[1] + 0.5);
-      samples[i].rgb[2]    = (int)(255.0 * values[2] + 0.5);
-      samples[i].colors[0] = (int)(255.0 * values[3] + 0.5);
-      if (num_channels > 1)
-       samples[i].colors[1] = (int)(255.0 * values[4] + 0.5);
-      if (num_channels > 2)
-       samples[i].colors[2] = (int)(255.0 * values[5] + 0.5);
-      if (num_channels > 3)
-       samples[i].colors[3] = (int)(255.0 * values[6] + 0.5);
-    }
-
- /*
-  * If everything went OK, create the color profile...
-  */
-
-  if (i == num_samples)
-    rgbptr = cfRGBNew(num_samples, samples, cube_size, num_channels);
-  else
-    rgbptr = NULL;
-
- /*
-  * Free the temporary sample array and return...
-  */
-
-  free(samples);
-
-  return (rgbptr);
-}
-
-
 /*
  * 'cfRGBNew()' - Create a new RGB color separation.
  */
index d96e3ba4bbaccce60ae04d09033c003ed6d3163c..6568f7f23cd4bac10c038e7aefd46b85dbd5d502 100644 (file)
@@ -21,6 +21,7 @@
 #include <config.h>
 #include <string.h>
 #include <ctype.h>
+#include <stdio.h>
 #ifdef WIN32
 #  include <io.h>
 #else
index f5416cffc2351704c67d92a075304890c4463bb5..9f610020624402ea0a61f18136515c92379f62b3 100644 (file)
@@ -492,7 +492,7 @@ typedef struct texttopdf_doc_s
 
   cups_page_header2_t h;        /* CUPS Raster page header, to */
                                 /* accommodate results of command */
-                                /* line parsing for PPD-less queue */
+                                /* line/IPP attribute parsing */
   cf_filter_texttopdf_parameter_t env_vars;
   int          NumKeywords;
   float                PageLeft,       /* Left margin */
@@ -541,7 +541,7 @@ static void     write_font_str(float x,float y,int fontid, lchar_t *str,
 static void     write_pretty_header();
 static int      write_prolog(const char *title, const char *user,
                            const char *classification, const char *label, 
-                           ppd_file_t *ppd, texttopdf_doc_t *doc,
+                           texttopdf_doc_t *doc,
                            cf_logfunc_t log, void *ld);
 static void     write_page(texttopdf_doc_t *doc);
 static void     write_epilogue(texttopdf_doc_t *doc);
@@ -585,6 +585,7 @@ cfFilterTextToPDF(int inputfd,      /* I - File descriptor input stream */
   int          stdoutbackupfd; /* The "real" stdout is backupped here while */
                                /* stdout is redirected */
   int          ret = 0;        /* Return value */
+  cups_cspace_t cspace = (cups_cspace_t)(-1);
 
 
  /*
@@ -661,11 +662,6 @@ cfFilterTextToPDF(int inputfd,     /* I - File descriptor input stream */
   * Process command-line options and write the prolog...
   */
 
-  if (data->ppd)
-  {
-    ppdMarkOptions(data->ppd, data->num_options, data->options);
-  }
-
   if ((val = cupsGetOption("prettyprint",
                           data->num_options, data->options)) != NULL &&
       strcasecmp(val, "no") && strcasecmp(val, "off") &&
@@ -716,31 +712,69 @@ cfFilterTextToPDF(int inputfd,    /* I - File descriptor input stream */
     }
   }
 
-  cfFilterSetCommonOptions(data->ppd, data->num_options, data->options, 1,
-                        &(doc.Orientation), &(doc.Duplex),
-                        &(doc.LanguageLevel), &(doc.ColorDevice),
-                        &(doc.PageLeft), &(doc.PageRight), &(doc.PageTop),
-                        &(doc.PageBottom), &(doc.PageWidth), &(doc.PageLength),
-                        log, ld);
-
-  if (!data->ppd) {
-    cfRasterParseIPPOptions(&(doc.h), data, 0, 1);
-    doc.Orientation = doc.h.Orientation;
-    doc.Duplex = doc.h.Duplex;
-    doc.ColorDevice = doc.h.cupsNumColors <= 1 ? 0 : 1;
-    doc.PageWidth = doc.h.cupsPageSize[0] != 0.0 ? doc.h.cupsPageSize[0] :
-      (float)doc.h.PageSize[0];
-    doc.PageLength = doc.h.cupsPageSize[1] != 0.0 ? doc.h.cupsPageSize[1] :
-      (float)doc.h.PageSize[1];
-    doc.PageLeft = doc.h.cupsImagingBBox[0] != 0.0 ? doc.h.cupsImagingBBox[0] :
-      (float)doc.h.ImagingBoundingBox[0];
-    doc.PageBottom = doc.h.cupsImagingBBox[1] != 0.0 ?
-      doc.h.cupsImagingBBox[1] : (float)doc.h.ImagingBoundingBox[1];
-    doc.PageRight = doc.h.cupsImagingBBox[2] != 0.0 ? doc.h.cupsImagingBBox[2] :
-      (float)doc.h.ImagingBoundingBox[2];
-    doc.PageTop = doc.h.cupsImagingBBox[3] != 0.0 ? doc.h.cupsImagingBBox[3] :
-      (float)doc.h.ImagingBoundingBox[3];
-    doc.Copies = doc.h.NumCopies;
+  cfRasterPrepareHeader(&(doc.h), data, CF_FILTER_OUT_FORMAT_CUPS_RASTER,
+                       CF_FILTER_OUT_FORMAT_CUPS_RASTER, 0, &cspace);
+  doc.Orientation = doc.h.Orientation;
+  doc.Duplex = doc.h.Duplex;
+  doc.ColorDevice = doc.h.cupsNumColors <= 1 ? 0 : 1;
+  doc.PageWidth = doc.h.cupsPageSize[0] != 0.0 ? doc.h.cupsPageSize[0] :
+    (float)doc.h.PageSize[0];
+  doc.PageLength = doc.h.cupsPageSize[1] != 0.0 ? doc.h.cupsPageSize[1] :
+    (float)doc.h.PageSize[1];
+  doc.PageLeft = doc.h.cupsImagingBBox[0] != 0.0 ? doc.h.cupsImagingBBox[0] :
+    (float)doc.h.ImagingBoundingBox[0];
+  doc.PageBottom = doc.h.cupsImagingBBox[1] != 0.0 ?
+    doc.h.cupsImagingBBox[1] : (float)doc.h.ImagingBoundingBox[1];
+  doc.PageRight = doc.h.cupsImagingBBox[2] != 0.0 ? doc.h.cupsImagingBBox[2] :
+    (float)doc.h.ImagingBoundingBox[2];
+  doc.PageTop = doc.h.cupsImagingBBox[3] != 0.0 ? doc.h.cupsImagingBBox[3] :
+    (float)doc.h.ImagingBoundingBox[3];
+  doc.Copies = doc.h.NumCopies;
+
+  /* Check whether we do borderless printing with overspray and let text only
+     get printed on the actual media size */
+  if (doc.h.cupsPageSizeName[0] != '\0')
+  {
+    /* The page size name in te header corresponds to the actual size of
+       the media, so find the size dimensions */
+    pwg_media_t *size_found = NULL;
+    strncpy(keyword, doc.h.cupsPageSizeName, sizeof(keyword));
+    if ((keyptr = strchr(keyword, '.')) != NULL)
+      *keyptr = '\0';
+    if ((size_found = pwgMediaForPPD(keyword)) != NULL ||
+       (size_found = pwgMediaForLegacy(keyword)) != NULL ||
+       (size_found = pwgMediaForPWG(keyword)) != NULL)
+    {
+      /* Dimensions in PostScript points */
+      float w = size_found->width / 2540.0 * 72.0;
+      float l = size_found->length / 2540.0 * 72.0;
+      if (w < doc.PageWidth)
+      {
+       /* Width in header > actual media width => overspray */
+       /* As the overspray is to cover tolerances in paper traction
+          and the paper can be mis-aligned to any size, we let
+          margins be at least double the overspray width on each
+          side (not dividing by 2) */
+       float margin_needed = doc.PageWidth - w;
+       if (doc.PageLeft < margin_needed)
+         doc.PageLeft = margin_needed;
+       if (doc.PageWidth - doc.PageRight < margin_needed)
+         doc.PageRight = doc.PageWidth - margin_needed;
+      }
+      if (l < doc.PageLength)
+      {
+       /* Length in header > actual media length => overspray */
+       /* As the overspray is to cover tolerances in paper traction
+          and the paper can be mis-aligned to any size, we let
+          margins be at least double the overspray width on each
+          side (not dividing by 2) */
+       float margin_needed = doc.PageLength - l;
+       if (doc.PageBottom < margin_needed)
+         doc.PageBottom = margin_needed;
+       if (doc.PageLength - doc.PageTop < margin_needed)
+         doc.PageTop = doc.PageLength - margin_needed;
+      }
+    }
   }
 
   if ((val = cupsGetOption("wrap", data->num_options, data->options)) == NULL)
@@ -863,7 +897,7 @@ cfFilterTextToPDF(int inputfd,      /* I - File descriptor input stream */
                        doc.env_vars.classification,
                        cupsGetOption("page-label", data->num_options,
                                      data->options),
-                       data->ppd, &doc, log, ld);
+                       &doc, log, ld);
       if (ret)
        goto out;
     }
@@ -1658,7 +1692,7 @@ write_page(texttopdf_doc_t *doc)
 
   (doc->NumPages)++;
   if (doc->PrettyPrint)
-    write_pretty_header(doc->pdf);
+    write_pretty_header(doc);
 
   for (line = 0; line < doc->SizeLines; line ++)
     write_line(line, doc->Page[line], doc);
@@ -1702,7 +1736,6 @@ write_prolog(const char *title,           /* I - Title of job */
            const char *user,           /* I - Username */
             const char *classification,        /* I - Classification */
            const char *label,          /* I - Page label */
-            ppd_file_t *ppd,           /* I - PPD file info */
             texttopdf_doc_t *doc,
             cf_logfunc_t log,
             void *ld)
index 622a305b51be57a331a17005c599ad6ae35bb5bf..9281312b509fbb6c2c2f3a143c82c0cb6799a08b 100644 (file)
@@ -2,8 +2,8 @@
  *   texttotext
  *
  *   Filter to print text files on text-only printers. The filter has
- *   several configuration options controlled by a PPD file so that it
- *   should work with most printer models.
+ *   several configuration options so that it should work with most
+ *   printer models.
  *
  *   Copyright 2007-2011 by Apple Inc.
  *   Copyright 1997-2006 by Easy Software Products.
@@ -19,7 +19,6 @@
 
 #include <config.h>
 #include <cups/cups.h>
-#include <ppd/ppd.h>
 #include <cups/file.h>
 #include <signal.h>
 #include <sys/wait.h>
@@ -31,6 +30,7 @@
 #include <ctype.h>
 #include <iconv.h>
 #include <cupsfilters/image-private.h>
+#include "ipp.h"
 #include "filter.h"
 
 /*
@@ -70,21 +70,18 @@ int cfFilterTextToText(int inputfd,         /* I - File descriptor input stream
   int          exit_status = 0;        /* Exit status */
   int          fd;                     /* Copy file descriptor */
 
-  char         buffer[8192];           /* Copy buffer */
   int           num_copies;             /* Number of copies */
-  ppd_file_t   *ppd;                   /* PPD file */
   int          num_options;            /* Number of options */
   cups_option_t        *options;               /* Options */
-  const char   *val, *val2;                    /* Option value */
-  ppd_attr_t    *ppd_attr;              /* Attribute taken from the PPD */
+  const char   *val;                   /* Option value */
   int           num_lines = 66,         /* Lines per page */
                 num_columns = 80;       /* Characters per line */
   int           page_left = 0,          /* Page margins */
                 page_right = 0,
                 page_top = 0,
                 page_bottom = 0,
-                num_lines_per_inch = 6,
-                num_chars_per_inch = 10;
+                num_lines_per_inch = 0,
+                num_chars_per_inch = 0;
   int           text_width,             /* Width of the text area on the page */
                 text_height;            /* Height of the text area on the
                                           page */
@@ -142,6 +139,10 @@ int cfFilterTextToText(int inputfd,         /* I - File descriptor input stream
                                           empty (no visible characters)? */
   int           previous_is_cr;         /* Is the previous character processed
                                           a Carriage Return? */
+  int           new_line_started = 0;   /* Is the proceeding of starting a
+                                          new line (left margin, new page's
+                                          top margin, wrapped word) already
+                                          done for this line? */
   int           skip_rest_of_line = 0;  /* Are we truncating an overlong
                                           line? */
   int           skip_spaces = 0;        /* Are we skipping spaces at a line
@@ -151,10 +152,11 @@ int cfFilterTextToText(int inputfd,         /* I - File descriptor input stream
   int           num_pages = 0;          /* Number of pages which get actually
                                           printed */
  
-  ipp_t *printer_attrs = NULL;
-  ipp_t *job_attrs = NULL;
+  ipp_t *printer_attrs = data->printer_attrs;
+  ipp_t *job_attrs = data->job_attrs;
   ipp_attribute_t *ipp;
-  ipp_t *defsize;
+  ipp_t *media_col_entry;
+  float paperdimensions[2];
   char buf[2048];
 
   cf_logfunc_t     log = data->logfunc;
@@ -190,135 +192,98 @@ int cfFilterTextToText(int inputfd,         /* I - File descriptor input stream
     num_copies = 1;
 
  /*
-  * Get the options from the fifth command line argument
+  * Parse the options and IPP attributes
   */
 
   num_options = data->num_options;
-
- /*
-  * Load the PPD file and mark options...
-  */
-
-  ppd = data->ppd;
   options = data->options;
-  if (ppd)
-  {
-    ppdMarkOptions(ppd, num_options, options);
-  }
 
- /*
-  * Parse the options
-  */
-
-  /*  Default page size attributes as per printer attributes  */
-  defsize = ippGetCollection(ippFindAttribute(printer_attrs,       
-                          "media-col-default", IPP_TAG_ZERO), 0);
-  
-  if((val = cupsGetOption("NumLinesPerInch", num_options, options))!= NULL         ||
-    (ipp = ippFindAttribute(job_attrs,"num-lines-per-inch", IPP_TAG_INTEGER)) != NULL ||
-    (ipp = ippFindAttribute(printer_attrs,"num-lines-per-inch-default", IPP_TAG_INTEGER)) != NULL ||
-    (ppd_attr = ppdFindAttr(ppd, "DefaultNumLinesPerInch",NULL))!=NULL){
-      if(val == NULL && ipp!=NULL){
-        ippAttributeString(ipp, buf, sizeof(buf));
-        val = buf;
-      }
-      if(val == NULL){
-        val = ppd_attr->value;
-      }
+  /* Number of lines and columns per inch This is mainly for
+     development and debugging. With these set and the page size given
+     as width and length dimension, the number of lines and columns on
+     the page gets calculated. A way for using custom sizes.  With
+     these not set, the media-col-database entry for the page size is
+     looked up and if it has the extra integer entries "num-lines" and
+     "num-columns", the numbers here are used. */
+  if ((val = cupsGetOption("NumLinesPerInch",
+                          num_options, options)) != NULL ||
+      (val = cupsGetOption("num-lines-per-inch",
+                          num_options, options)) != NULL ||
+      (ipp = ippFindAttribute(job_attrs, "num-lines-per-inch",
+                             IPP_TAG_INTEGER)) != NULL ||
+      (ipp = ippFindAttribute(printer_attrs, "num-lines-per-inch-default",
+                             IPP_TAG_INTEGER)) != NULL)
+  {
+    if (val == NULL)
+    {
+      ippAttributeString(ipp, buf, sizeof(buf));
+      val = buf;
+    }
+    if (val && val[0])
       num_lines_per_inch = atoi(val);
+    if (log)
+    {
+      if (num_lines_per_inch <= 0)
+       log(ld, CF_LOGLEVEL_DEBUG,
+           "cfFilterTextToText: Number of lines per inch not set, if page dimensions are given, find number of lines per page via pre-defined page sizes");
+      else
+       log(ld, CF_LOGLEVEL_DEBUG,
+           "cfFilterTextToText: Number of lines per inch: %d",
+           num_lines_per_inch);
     }
+  }
 
-  if((val = cupsGetOption("NumCharsPerInch", num_options, options))!= NULL          ||
-    (ipp = ippFindAttribute(job_attrs,"num-chars-per-inch", IPP_TAG_INTEGER)) != NULL  ||
-    (ipp = ippFindAttribute(printer_attrs,"num-chars-per-inch-default", IPP_TAG_INTEGER)) != NULL  ||
-    (ppd_attr = ppdFindAttr(ppd, "DefautlNumCharsPerInch", NULL))!=NULL){
-      if(val == NULL && ipp!=NULL){
-        ippAttributeString(ipp, buf, sizeof(buf));
-        val = buf;
-      }
-      if(val == NULL){
-        val = ppd_attr->value;
-      }
-      num_chars_per_inch = atoi(val);
-    }
-    if(log) log(ld, CF_LOGLEVEL_DEBUG,"cfFilterTextToText: num of lines per inch = %d",num_lines_per_inch);
-    if(log) log(ld, CF_LOGLEVEL_DEBUG,"cfFilterTextToText: num of chars per inch = %d",num_chars_per_inch);
-
-  /* With the "PageSize"/"PageRegion" options we only determine the number
-     of lines and columns of a page, we do not use the geometry defined by
-     "PaperDimension" and "ImageableArea" in the PPD */
-  if ((val = cupsGetOption("PageSize", num_options, options)) != NULL       ||
-      (val = cupsGetOption("PageRegion", num_options, options)) != NULL     ||
-      (ipp = ippFindAttribute(job_attrs, "page-size", IPP_TAG_ZERO ))!=NULL ||
-      (ipp = ippFindAttribute(job_attrs, "page-region", IPP_TAG_ZERO))!=NULL||
-      (ppd_attr = ppdFindAttr(ppd, "DefaultPageSize", NULL)) != NULL        ||
-      (ppd_attr = ppdFindAttr(ppd, "DefaultPageRegion", NULL)) != NULL) {
-    if (val == NULL && ipp!=NULL){
+  if ((val = cupsGetOption("NumCharsPerInch",
+                          num_options, options)) != NULL ||
+      (val = cupsGetOption("num-chars-per-inch",
+                          num_options, options)) != NULL ||
+      (ipp = ippFindAttribute(job_attrs,"num-chars-per-inch",
+                             IPP_TAG_INTEGER)) != NULL ||
+      (ipp = ippFindAttribute(printer_attrs, "num-chars-per-inch-default",
+                             IPP_TAG_INTEGER)) != NULL)
+  {
+    if (val == NULL)
+    {
       ippAttributeString(ipp, buf, sizeof(buf));
       val = buf;
     }
-    if(val==NULL)
-      val = ppd_attr->value;
-
-    if(log) log(ld, CF_LOGLEVEL_DEBUG,"cfFilterTextToText: PageSize: %s", val);
-    snprintf(buffer, sizeof(buffer), "Default%sNumLines", val);
-    if ((val2 = cupsGetOption(buffer + 7, num_options, options)) != NULL ||
-  (ipp = ippFindAttribute(job_attrs, buffer+7, IPP_TAG_ZERO))!= NULL   ||
-  (ipp = ippFindAttribute(printer_attrs, buffer, IPP_TAG_ZERO))!=NULL ||
-  (ppd_attr = ppdFindAttr(ppd, buffer, NULL)) != NULL) {
-    char buf2[2048];
-      if (val2 == NULL && ipp!=NULL){
-        ippAttributeString(ipp, buf2, sizeof(buf2));
-        val2 = buf2;
-      }
-      if(val2==NULL)
-             val2 = ppd_attr->value;
-      if (!strncasecmp(val2, "Custom.", 7))
-       val2 += 7;
-      num_lines = atoi(val2);
-    }
-    snprintf(buffer, sizeof(buffer), "Default%sNumColumns", val);
-    if ((val2 = cupsGetOption(buffer + 7, num_options, options)) != NULL ||
-      (ipp = ippFindAttribute(job_attrs, buffer+7, IPP_TAG_ZERO))!=NULL  ||
-      (ipp = ippFindAttribute(printer_attrs, buffer, IPP_TAG_ZERO))!=NULL ||
-      (ppd_attr = ppdFindAttr(ppd, buffer, NULL))!=NULL) {
-    char buf2[2048];
-      if (val2 == NULL && ipp!=NULL){
-        ippAttributeString(ipp, buf2, sizeof(buf2));
-        val2 = buf2;
-      }
-if(val2==NULL)
-       val2 = ppd_attr->value;
-      if (!strncasecmp(val2, "Custom.", 7))
-       val2 += 7;
-      num_columns = atoi(val2);
-    }
-    if (num_lines <= 0) {
-      if(log) log(ld, CF_LOGLEVEL_DEBUG,"cfFilterTextToText: Invalid number of lines %d, using default: 66",
-             num_lines);
-      num_lines = 66;
-    }
-    if (num_columns <= 0) {
-      if(log) log(ld, CF_LOGLEVEL_DEBUG,"cfFilterTextToText: Invalid number of columns %d, using default: 80",
-             num_columns);
-      num_columns = 80;
+    if (val && val[0])
+      num_chars_per_inch = atoi(val);
+    if (log)
+    {
+      if (num_chars_per_inch <= 0)
+       log(ld, CF_LOGLEVEL_DEBUG,
+           "cfFilterTextToText: Number of charcters per inch not set, if page dimensions are given, find number of characters per line via pre-defined page sizes");
+      else
+       if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                    "cfFilterTextToText: Number of characters per inch = %d",
+                    num_chars_per_inch);
     }
   }
-  else if((ipp = ippFindAttribute(defsize, "media-size", IPP_TAG_ZERO))!= NULL){
-    ipp_t *media_size = ippGetCollection(ipp, 0);
-    int x_dim = ippGetInteger(ippFindAttribute(media_size, "x-dimension", IPP_TAG_ZERO),0);
-    int y_dim = ippGetInteger(ippFindAttribute(media_size, "y-dimension", IPP_TAG_ZERO),0);
-    num_lines = (int)((y_dim/72.0)*(num_lines_per_inch));         /*  Since y_dim and x_dim are in points, 
-                                                                      divide them by 72 to convert in inch  */
-    num_columns = (int)((x_dim/72.0)*(num_chars_per_inch));
-  }
-  else if((ipp = ippFindAttribute(printer_attrs, "media-default", IPP_TAG_ZERO))!=NULL){
-    pwg_media_t *pwg = pwgMediaForPWG(ippGetString(ipp, 0, NULL));
-    int x_dim = pwg->width;
-    int y_dim = pwg->length;
-    num_lines = (int)((y_dim/72.0)*(num_lines_per_inch));
-    num_columns = (int)((x_dim/72.0)*(num_chars_per_inch));
+
+  cfGetPageDimensions(printer_attrs, job_attrs, num_options, options,
+                     NULL, 0,
+                     &(paperdimensions[0]), &(paperdimensions[1]),
+                     NULL, NULL, NULL, NULL, NULL, &media_col_entry);
+  if (media_col_entry)
+  {
+    /* We have a media-col-database and the requested/default page size
+       is contained in it (= size is supported), check whether we have
+       a number of lines/columns registered via extra interger entries
+       "num-columns" and "num-lines". */
+    num_columns = ippGetInteger(ippFindAttribute(media_col_entry,
+                                                "num-columns",
+                                                IPP_TAG_ZERO), 0);
+    num_lines = ippGetInteger(ippFindAttribute(media_col_entry,
+                                              "num-lines",
+                                              IPP_TAG_ZERO), 0);
   }
+
+  if (num_chars_per_inch > 0 && paperdimensions[0] > 0)
+    num_columns = (int)((paperdimensions[0] / 72.0) * (num_chars_per_inch));
+  if (num_lines_per_inch > 0 && paperdimensions[1] > 0)
+    num_lines = (int)((paperdimensions[1] / 72.0) * (num_lines_per_inch));
+
   if (num_lines <= 0) {
     if(log) log(ld, CF_LOGLEVEL_DEBUG,"cfFilterTextToText: Invalid number of lines %d, using default: 66",
              num_lines);
@@ -332,7 +297,8 @@ if(val2==NULL)
 
   /* Direct specification of number of lines/columns, mainly for debugging
      and development */
-  if ((val = cupsGetOption("page-height", num_options, options)) != NULL  ||
+  if ((val = cupsGetOption("PageHeight", num_options, options)) != NULL ||
+      (val = cupsGetOption("page-height", num_options, options)) != NULL ||
       (ipp = ippFindAttribute(job_attrs, "page-height", IPP_TAG_INTEGER))!=NULL) {
         if(val == NULL){
           ippAttributeString(ipp, buf, sizeof(buf));
@@ -345,7 +311,8 @@ if(val2==NULL)
       if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Invalid number of lines %d, using default value: %d",
              i, num_lines);
   }
-  if ((val = cupsGetOption("page-width", num_options, options)) != NULL ||
+  if ((val = cupsGetOption("PageWidth", num_options, options)) != NULL ||
+      (val = cupsGetOption("page-width", num_options, options)) != NULL ||
       (ipp = ippFindAttribute(job_attrs, "page-width", IPP_TAG_INTEGER))!=NULL) {
     if(val == NULL){
       ippAttributeString(ipp, buf, sizeof(buf));
@@ -362,85 +329,149 @@ if(val2==NULL)
   if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Lines per page: %d; Characters per line: %d",
          num_lines, num_columns);
   
-  if ((val = cupsGetOption("page-left", num_options, options)) != NULL ||
-      (ipp = ippFindAttribute(job_attrs, "page-left", IPP_TAG_INTEGER))!=NULL ||
-      (ppd_attr = ppdFindAttr(ppd, "Defaultpage-left", NULL)) != NULL ||
-      (ipp = ippFindAttribute(defsize, "media-left-margin", IPP_TAG_INTEGER))!=NULL) {
-    if (val == NULL && ipp!=NULL){
+  if ((val = cupsGetOption("PageLeft",
+                          num_options, options)) != NULL ||
+      (val = cupsGetOption("page-left",
+                          num_options, options)) != NULL ||
+      (ipp = ippFindAttribute(job_attrs, "page-left",
+                             IPP_TAG_INTEGER)) != NULL ||
+      (ipp = ippFindAttribute(printer_attrs, "page-left-default",
+                             IPP_TAG_INTEGER)) != NULL)
+  {
+    if (val == NULL)
+    {
       ippAttributeString(ipp, buf, sizeof(buf));
       val = buf;
     }
-    if(val == NULL && ppd_attr!=NULL)
-      val = ppd_attr->value;
-    if (!strncasecmp(val, "Custom.", 7))
-      val += 7;
-    page_left = atoi(val);
-    if (page_left < 0 || page_left > num_columns - 1) {
-      if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Invalid left margin %d, setting to 0",
-             page_left);
-      page_left = 0;
+    if (val && val[0])
+    {
+      if (!strncasecmp(val, "Custom", 6))
+       val += 7;
+      page_left = atoi(val);
+    }
+    if (log)
+    {
+      if (page_left < 0 || page_left > num_columns - 1)
+      {
+       log(ld, CF_LOGLEVEL_DEBUG,
+           "cfFilterTextToText: Left margin not set or invalid, use 0 columns");
+       page_left = 0;
+      }
+      else
+       if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                    "cfFilterTextToText: Left margin: %d columns",
+                    page_left);
     }
   }
-  if ((val = cupsGetOption("page-right", num_options, options)) != NULL ||
-      (ipp = ippFindAttribute(job_attrs, "page-right", IPP_TAG_INTEGER))!=NULL ||
-      (ppd_attr = ppdFindAttr(ppd, "Defaultpage-right", NULL)) != NULL  ||
-        (ipp = ippFindAttribute(defsize, "media-right-margin", IPP_TAG_INTEGER))!=NULL) {
-    if (val == NULL && ipp!=NULL){
+
+  if ((val = cupsGetOption("PageRight",
+                          num_options, options)) != NULL ||
+      (val = cupsGetOption("page-right",
+                          num_options, options)) != NULL ||
+      (ipp = ippFindAttribute(job_attrs, "page-right",
+                             IPP_TAG_INTEGER)) != NULL ||
+      (ipp = ippFindAttribute(printer_attrs, "page-right-default",
+                             IPP_TAG_INTEGER)) != NULL)
+  {
+    if (val == NULL)
+    {
       ippAttributeString(ipp, buf, sizeof(buf));
       val = buf;
     }
-    if(val == NULL && ppd_attr!=NULL)
-      val = ppd_attr->value;
-    if (!strncasecmp(val, "Custom.", 7))
-      val += 7;
-    page_right = atoi(val);
-    if (page_right < 0 || page_right > num_columns - page_left - 1) {
-      if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Invalid right margin %d, setting to 0",
-             page_right);
-      page_right = 0;
+    if (val && val[0])
+    {
+      if (!strncasecmp(val, "Custom", 6))
+       val += 7;
+      page_right = atoi(val);
+    }
+    if (log)
+    {
+      if (page_right < 0 || page_right > num_columns - 1)
+      {
+       log(ld, CF_LOGLEVEL_DEBUG,
+           "cfFilterTextToText: Right margin not set or invalid, use 0 columns");
+       page_right = 0;
+      }
+      else
+       if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                    "cfFilterTextToText: Right margin: %d columns",
+                    page_right);
     }
   }
-  if ((val = cupsGetOption("page-top", num_options, options)) != NULL ||
-      (ipp = ippFindAttribute(job_attrs,"page-top", IPP_TAG_INTEGER))!=NULL ||
-      (ppd_attr = ppdFindAttr(ppd, "Defaultpage-top", NULL)) != NULL  ||
-      (ipp = ippFindAttribute(defsize, "media-top-margin", IPP_TAG_INTEGER))!=NULL) {
-    if (val == NULL && ipp!=NULL){
+
+  if ((val = cupsGetOption("PageTop",
+                          num_options, options)) != NULL ||
+      (val = cupsGetOption("page-top",
+                          num_options, options)) != NULL ||
+      (ipp = ippFindAttribute(job_attrs, "page-top",
+                             IPP_TAG_INTEGER)) != NULL ||
+      (ipp = ippFindAttribute(printer_attrs, "page-top-default",
+                             IPP_TAG_INTEGER)) != NULL)
+  {
+    if (val == NULL)
+    {
       ippAttributeString(ipp, buf, sizeof(buf));
       val = buf;
     }
-    if(val == NULL && ppd_attr!=NULL)
-      val = ppd_attr->value;
-    
-    if (!strncasecmp(val, "Custom.", 7))
-      val += 7;
-    page_top = atoi(val);
-    if (page_top < 0 || page_top > num_lines - 1) {
-      if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Invalid top margin %d, setting to 0",
-             page_top);
-      page_top = 0;
+    if (val && val[0])
+    {
+      if (!strncasecmp(val, "Custom", 6))
+       val += 7;
+      page_top = atoi(val);
+    }
+    if (log)
+    {
+      if (page_top < 0 || page_top > num_lines - 1)
+      {
+       log(ld, CF_LOGLEVEL_DEBUG,
+           "cfFilterTextToText: Top margin not set or invalid, use 0 lines");
+       page_top = 0;
+      }
+      else
+       if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                    "cfFilterTextToText: Top margin: %d lines",
+                    page_top);
     }
   }
-  if ((val = cupsGetOption("page-bottom", num_options, options)) != NULL ||
-      (ipp = ippFindAttribute(job_attrs,"page-bottom",IPP_TAG_INTEGER))!=NULL ||
-      (ppd_attr = ppdFindAttr(ppd, "Defaultpage-bottom", NULL)) != NULL ||
-      (ipp = ippFindAttribute(defsize, "media-bottom-margin", IPP_TAG_INTEGER))!=NULL) {
-    if (val == NULL && ipp!=NULL){
+
+  if ((val = cupsGetOption("PageBottom",
+                          num_options, options)) != NULL ||
+      (val = cupsGetOption("page-bottom",
+                          num_options, options)) != NULL ||
+      (ipp = ippFindAttribute(job_attrs, "page-bottom",
+                             IPP_TAG_INTEGER)) != NULL ||
+      (ipp = ippFindAttribute(printer_attrs, "page-bottom-default",
+                             IPP_TAG_INTEGER)) != NULL)
+  {
+    if (val == NULL)
+    {
       ippAttributeString(ipp, buf, sizeof(buf));
       val = buf;
     }
-    if(val==NULL && ppd_attr!=NULL)
-      val = ppd_attr->value;
-    if (!strncasecmp(val, "Custom.", 7))
-      val += 7;
-    page_bottom = atoi(val);
-    if (page_bottom < 0 || page_bottom > num_lines - page_top - 1) {
-      if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Invalid bottom margin %d, setting to 0",
-             page_bottom);
-      page_bottom = 0;
+    if (val && val[0])
+    {
+      if (!strncasecmp(val, "Custom", 6))
+       val += 7;
+      page_bottom = atoi(val);
+    }
+    if (log)
+    {
+      if (page_bottom < 0 || page_bottom > num_lines - 1)
+      {
+       log(ld, CF_LOGLEVEL_DEBUG,
+           "cfFilterTextToText: Bottom margin not set or invalid, use 0 lines");
+       page_bottom = 0;
+      }
+      else
+       if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                    "cfFilterTextToText: Bottom margin: %d lines",
+                    page_bottom);
     }
   }
-  if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Margins: Left (Columns): %d; Right (Columns): %d; Top (Lines): %d; Bottom (Lines): %d",
-         page_left, page_right, page_top, page_bottom);
+
+  if (log) log(ld, CF_LOGLEVEL_DEBUG,
+              "cfFilterTextToText: Margins: Left (Columns): %d; Right (Columns): %d; Top (Lines): %d; Bottom (Lines): %d",
+              page_left, page_right, page_top, page_bottom);
 
   text_width = num_columns - page_left - page_right;
   text_height = num_lines - page_top - page_bottom;
@@ -448,139 +479,186 @@ if(val2==NULL)
          text_height, text_width);
 
   strcpy(encoding, "ASCII//IGNORE");
-  if ((val = cupsGetOption("PrinterEncoding", num_options, options)) != NULL ||
-      (ipp = ippFindAttribute(job_attrs, "printer-encoding", IPP_TAG_ZERO))!=NULL ||
-      (ppd_attr = ppdFindAttr(ppd, "DefaultPrinterEncoding", NULL)) != NULL ||
-      (ipp = ippFindAttribute(printer_attrs, "printer-encoding-default", IPP_TAG_ZERO))!= NULL) {
-    if (val == NULL && ipp!=NULL){
+  if ((val = cupsGetOption("PrinterEncoding",
+                          num_options, options)) != NULL ||
+      (val = cupsGetOption("printer-encoding",
+                          num_options, options)) != NULL ||
+      (ipp = ippFindAttribute(job_attrs, "printer-encoding",
+                             IPP_TAG_ZERO)) != NULL ||
+      (ipp = ippFindAttribute(printer_attrs, "printer-encoding-default",
+                             IPP_TAG_ZERO)) != NULL)
+  {
+    if (val == NULL)
+    {
       ippAttributeString(ipp, buf, sizeof(buf));
       val = buf;
     }
-    if(val == NULL && ppd_attr!=NULL)
-      val = ppd_attr->value;
-    if (!strncasecmp(val, "Custom.", 7))
-      val += 7;
-    if (val[0] != '\0') {
-      snprintf(encoding, sizeof(encoding), "%.55s//IGNORE", val);
-      for (p = encoding; *p; p ++)
-       *p = toupper(*p);
+    if (val && val[0])
+    {
+      if (!strncasecmp(val, "Custom", 6))
+       val += 7;
+      if (val[0] != '\0')
+      {
+       snprintf(encoding, sizeof(encoding), "%.55s//IGNORE", val);
+       for (p = encoding; *p; p ++)
+         *p = toupper(*p);
+      }
     }
   }
-  if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Output encoding: %s", encoding);
-  
-  if ((val = cupsGetOption("OverlongLines", num_options, options)) != NULL ||
-      (ipp = ippFindAttribute(job_attrs, "overlong-lines", IPP_TAG_ENUM))!=NULL ||
-      (ipp = ippFindAttribute(printer_attrs, "overlong-lines-default", IPP_TAG_ENUM))!=NULL ||
-      (ppd_attr = ppdFindAttr(ppd, "DefaultOverlongLines", NULL)) != NULL) {
-    if (val == NULL && ipp!=NULL){
+  if (log) log(ld, CF_LOGLEVEL_DEBUG,
+              "cfFilterTextToText: Output encoding: %s", encoding);
+
+  if ((val = cupsGetOption("OverLongLines",
+                          num_options, options)) != NULL ||
+      (val = cupsGetOption("over-long-lines",
+                          num_options, options)) != NULL ||
+      (ipp = ippFindAttribute(job_attrs, "over-long-lines",
+                             IPP_TAG_ZERO)) != NULL ||
+      (ipp = ippFindAttribute(printer_attrs, "over-long-lines-default",
+                             IPP_TAG_ZERO)) != NULL)
+  {
+    if (val == NULL)
+    {
       ippAttributeString(ipp, buf, sizeof(buf));
       val = buf;
     }
-    if(val == NULL)
-      val = ppd_attr->value;
-    if (!strcasecmp(val, "Truncate"))
+    if (!strcasecmp(val, "truncate"))
       overlong_lines = TRUNCATE;
-    else if (!strcasecmp(val, "WordWrap"))
+    else if (!strcasecmp(val, "word-wrap") ||
+            !strcasecmp(val, "WordWrap"))
       overlong_lines = WORDWRAP;
-    else if (!strcasecmp(val, "WrapAtWidth"))
+    else if (!strcasecmp(val, "wrap-at-width") ||
+            !strcasecmp(val, "WrapAtWidth"))
       overlong_lines = WRAPATWIDTH;
     else
-      if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Invalid value for OverlongLines: %s, using default value",
-             val);
+      if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                  "cfFilterTextToText: Invalid value for over-long-lines: %s, using default value",
+                  val);
   }
-  if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Handling of overlong lines: %s",
-         (overlong_lines == TRUNCATE ? "Truncate at maximum width" :
-          (overlong_lines == WORDWRAP ? "Word-wrap" :
-           "Wrap exactly at maximum width")));
-
-  if ((val = cupsGetOption("TabWidth", num_options, options)) != NULL ||
-      (ipp = ippFindAttribute(job_attrs,"tab-width", IPP_TAG_INTEGER))!=NULL ||
-      (ipp = ippFindAttribute(printer_attrs,"tab-width-default",  IPP_TAG_INTEGER ))!=NULL  ||
-      (ppd_attr = ppdFindAttr(ppd, "DefaultTabWidth", NULL)) != NULL) {
-    if (val == NULL && ipp!=NULL){
+  if (log) log(ld, CF_LOGLEVEL_DEBUG,
+              "cfFilterTextToText: Handling of overlong lines: %s",
+              (overlong_lines == TRUNCATE ? "Truncate at maximum width" :
+               (overlong_lines == WORDWRAP ? "Word-wrap" :
+                "Wrap exactly at maximum width")));
+
+  if ((val = cupsGetOption("TabWidth",
+                          num_options, options)) != NULL ||
+      (val = cupsGetOption("tab-width",
+                          num_options, options)) != NULL ||
+      (ipp = ippFindAttribute(job_attrs, "tab-width",
+                             IPP_TAG_INTEGER)) != NULL ||
+      (ipp = ippFindAttribute(printer_attrs, "tab-width-default",
+                             IPP_TAG_INTEGER)) != NULL)
+  {
+    if (val == NULL)
+    {
       ippAttributeString(ipp, buf, sizeof(buf));
       val = buf;
     }
-    if(val == NULL && ppd_attr!=NULL)
-      val = ppd_attr->value;
-    if (!strncasecmp(val, "Custom.", 7))
-      val += 7;
-    i = atoi(val);
-    if (i > 0)
-      tab_width = i;
-    else
-      if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Invalid tab width %d, using default value: %d",
-             i, tab_width);
+    if (val && val[0])
+    {
+      if (!strncasecmp(val, "Custom", 6))
+       val += 7;
+      tab_width = atoi(val);
+    }
+    if (log)
+    {
+      if (tab_width <= 0 || tab_width > num_columns - 1)
+       log(ld, CF_LOGLEVEL_DEBUG,
+           "cfFilterTextToText: Tab width not set or invalid, use default");
+      else
+       if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                    "cfFilterTextToText: Tab width: %d columns",
+                    tab_width);
+    }
   }
-  if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Tab width: %d", tab_width);
-
-  if ((val = cupsGetOption("Pagination", num_options, options)) != NULL ||
-      (ipp = ippFindAttribute(job_attrs, "pagination", IPP_TAG_BOOLEAN))!=NULL  ||
-      (ipp = ippFindAttribute(printer_attrs, "pagination-default", IPP_TAG_BOOLEAN))!=NULL  ||
-      (ppd_attr = ppdFindAttr(ppd, "DefaultPagination", NULL)) != NULL) {
-    if (val == NULL && ipp!=NULL){
-      ippAttributeString(ipp, buf,sizeof(buf));
+  if (log) log(ld, CF_LOGLEVEL_DEBUG,
+              "cfFilterTextToText: Tab width: %d", tab_width);
+
+  if ((val = cupsGetOption("Pagination",
+                          num_options, options)) != NULL ||
+      (val = cupsGetOption("pagination",
+                          num_options, options)) != NULL ||
+      (ipp = ippFindAttribute(job_attrs, "pagination",
+                             IPP_TAG_ZERO)) != NULL ||
+      (ipp = ippFindAttribute(printer_attrs, "pagination-default",
+                             IPP_TAG_ZERO)) != NULL)
+  {
+    if (val == NULL)
+    {
+      ippAttributeString(ipp, buf, sizeof(buf));
       val = buf;
     }
-    if(val == NULL && ppd_attr!=NULL)
-      val = ppd_attr->value;
     if (is_true(val))
       pagination = 1;
     else if (is_false(val))
       pagination = 0;
     else
-      if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Invalid value for Pagination: %s, using default value",
-             val);
+      if(log) log(ld, CF_LOGLEVEL_DEBUG,
+                 "cfFilterTextToText: Invalid value for pagination: %s, using default value",
+                 val);
   }
-  if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Pagination (Print in defined pages): %s",
-         (pagination ? "Yes" : "No"));
-
-  if ((val = cupsGetOption("SendFF", num_options, options)) != NULL ||
-      (ipp = ippFindAttribute(job_attrs, "sendff", IPP_TAG_BOOLEAN))!=NULL ||
-      (ipp = ippFindAttribute(printer_attrs, "sendff-default", IPP_TAG_BOOLEAN))!=NULL ||
-      (ppd_attr = ppdFindAttr(ppd, "DefaultSendFF", NULL)) != NULL) {
-    if (val == NULL && ipp!=NULL){
+  if(log) log(ld, CF_LOGLEVEL_DEBUG,
+             "cfFilterTextToText: Pagination (Print in defined pages): %s",
+             (pagination ? "Yes" : "No"));
+
+  if ((val = cupsGetOption("SendFF",
+                          num_options, options)) != NULL ||
+      (val = cupsGetOption("send-ff",
+                          num_options, options)) != NULL ||
+      (ipp = ippFindAttribute(job_attrs, "send-ff",
+                             IPP_TAG_ZERO)) != NULL ||
+      (ipp = ippFindAttribute(printer_attrs, "send-ff-default",
+                             IPP_TAG_ZERO)) != NULL)
+  {
+    if (val == NULL)
+    {
       ippAttributeString(ipp, buf, sizeof(buf));
       val = buf;
     }
-    if(val==NULL && ppd_attr!=NULL)
-      val = ppd_attr->value;
     if (is_true(val))
       send_ff = 1;
     else if (is_false(val))
       send_ff = 0;
     else
-      if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Invalid value for SendFF: %s, using default value",
-             val);
+      if(log) log(ld, CF_LOGLEVEL_DEBUG,
+                 "cfFilterTextToText: Invalid value for send-ff: %s, using default value",
+                 val);
   }
-  if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Send Form Feed character at end of page: %s",
-         (send_ff ? "Yes" : "No"));
-
-  if ((val = cupsGetOption("NewlineCharacters", num_options, options)) !=
-      NULL ||
-      (ipp = ippFindAttribute(job_attrs, "newline-characters", IPP_TAG_ENUM))!=NULL ||
-      (ipp = ippFindAttribute(printer_attrs, "newline-characters-default", IPP_TAG_ENUM))!=NULL ||
-      (ppd_attr = ppdFindAttr(ppd, "DefaultNewlineCharacters", NULL)) != NULL) {
-    if (val == NULL && ipp!=NULL){
+  if(log) log(ld, CF_LOGLEVEL_DEBUG,
+             "cfFilterTextToText: Send Form Feed character at end of page: %s",
+             (send_ff ? "Yes" : "No"));
+
+  if ((val = cupsGetOption("NewlineCharacters",
+                          num_options, options)) != NULL ||
+      (val = cupsGetOption("newline-characters",
+                          num_options, options)) != NULL ||
+      (ipp = ippFindAttribute(job_attrs, "newline-characters",
+                             IPP_TAG_ZERO)) != NULL ||
+      (ipp = ippFindAttribute(printer_attrs, "newline-characters-default",
+                             IPP_TAG_ZERO)) != NULL)
+  {
+    if (val == NULL)
+    {
       ippAttributeString(ipp, buf, sizeof(buf));
       val = buf;
     }
-    if(val == NULL && ppd_attr!=NULL)
-      val = ppd_attr->value;
-    if (!strcasecmp(val, "LF"))
+    if (!strcasecmp(val, "lf"))
       newline_char = LF;
-    else if (!strcasecmp(val, "CR"))
+    else if (!strcasecmp(val, "cr"))
       newline_char = CR;
-    else if (!strcasecmp(val, "CRLF"))
+    else if (!strcasecmp(val, "crlf"))
       newline_char = CRLF;
     else
-      if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Invalid value for NewlineCharacters: %s, using default value",
-             val);
+      if(log) log(ld, CF_LOGLEVEL_DEBUG,
+                 "cfFilterTextToText: Invalid value for newline-characters: %s, using default value",
+                 val);
   }
-  if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Characters sent to make printer start a new line: %s",
-         (newline_char == LF ? "Line Feed (LF)" :
-          (newline_char == CR ? "Carriage Return (CR)" :
-           "Carriage Return (CR) and Line Feed (LF)")));
+  if(log) log(ld, CF_LOGLEVEL_DEBUG,
+             "cfFilterTextToText: Characters sent to make printer start a new line: %s",
+             (newline_char == LF ? "Line Feed (LF)" :
+              (newline_char == CR ? "Carriage Return (CR)" :
+               "Carriage Return (CR) and Line Feed (LF)")));
 
   if ((val = cupsGetOption("page-ranges", num_options, options)) !=
       NULL  ||
@@ -621,7 +699,9 @@ if(val2==NULL)
             (odd_pages ? "only the odd pages" :
              "no pages")));
   
-  if ((val = cupsGetOption("output-order", num_options, options)) !=
+  if ((val = cupsGetOption("OutputOrder", num_options, options)) !=
+      NULL  ||
+      (val = cupsGetOption("output-order", num_options, options)) !=
       NULL  ||
       (ipp = ippFindAttribute(job_attrs,"output-order", IPP_TAG_ZERO))!=NULL) {
         if(val == NULL){
@@ -662,11 +742,11 @@ if(val2==NULL)
   else if (newline_char == CRLF)
     newline_char_str = "\r\n";
 
-  /* Size of the output page in bytes (only 1-byte-per-character supported)
+  /* Size of the output page in bytes (up to 4-byte-per-character)
      in the worst case, no blank lines at top and bottom, no blank right
      margin, 2 characters for newline (CR + LF) plus form feed plus closing
      zero */
-  page_size = (num_columns + 2) * num_lines + 2;
+  page_size = ((num_columns + 2) * num_lines + 2) * 4;
 
   /* Allocate output page buffer */
   out_page = calloc(page_size, sizeof(char));
@@ -702,7 +782,7 @@ if(val2==NULL)
     page_array = cupsArrayNew(NULL, NULL);
   }
 
-  /* Main loop for readin the input file, converting the encoding, formatting
+  /* Main loop for reading the input file, converting the encoding, formatting
      the output, and printing the pages */
   destptr = out_page;
   page_empty = 1;
@@ -711,6 +791,7 @@ if(val2==NULL)
   column = 0;
   previous_is_cr = 0;
   insize = 0;
+  new_line_started = 0;
   do {
     /* Reset input pointer */
     inptr = inbuf;
@@ -742,10 +823,13 @@ if(val2==NULL)
     if (insize > 0) { /* Do we have data to convert? */
       /* Do the conversion.  */
       nconv = iconv (cd, &inptr, &insize, &outptr, &outsize);
-      if (nconv == (size_t) -1) {
+      if (log && nconv == (size_t) -1)
+       log(ld, CF_LOGLEVEL_DEBUG,
+           "cfFilterTextToText: iconv() message: %s", strerror(errno));
+      if (nconv == (size_t) -1 && insize > 0) {
        /* Not everything went right. It might only be
           an unfinished byte sequence at the end of the
-          buffer. Or it is a real problem. */
+          output buffer. Or it is a real problem. */
        if (errno == EINVAL || errno == E2BIG) {
          /* This is harmless.  Simply move the unused
             bytes to the beginning of the buffer so that
@@ -802,6 +886,7 @@ if(val2==NULL)
          /* Position cursor in next line */
          line ++;
          column = 0;
+         new_line_started = 0;
        }
       }
       if ((line >= text_height && /* Current page is full */
@@ -832,13 +917,15 @@ if(val2==NULL)
            /* Log the page output (only once, when printing the first buffer
               load) */
            if (num_pages == 1)
-      {
-            if(log) log(ld, CF_LOGLEVEL_INFO, "cfFilterTextToText: 1 1");
-      }
+           {
+             if(log) log(ld, CF_LOGLEVEL_CONTROL, "PAGE: 1 1");
+           }
+           cupsFilePuts(outputfp, out_page);
          } else if ((num_copies == 1 || !collate) && !reverse_order) {
       
            /* Log the page output */
-           if(log) log(ld, CF_LOGLEVEL_INFO, "cfFilterTextToText: %d %d", num_pages, num_copies);
+           if(log) log(ld, CF_LOGLEVEL_CONTROL, "PAGE: %d %d", num_pages, num_copies);
+           cupsFilePuts(outputfp, out_page);
          } else {
            /* Save the page in the page array */
            cupsArrayAdd(page_array, strdup(out_page));
@@ -849,11 +936,13 @@ if(val2==NULL)
        page_empty = 1;
        line = 0;
        column = 0;
+       new_line_started = 0;
        page ++;
       }
       if (outbuf[0] == '\0') /* End of input file */
        break;
-      if (column == 0) { /* Start of new line */ 
+      if (column == 0 && !new_line_started) { /* Start of new line */
+       new_line_started = 1;
        if (line == 0 && pagination)   /* Start of new page */
          for (i = 0; i < page_top; i ++)
            for (j = 0; newline_char_str[j]; j ++)
@@ -882,6 +971,7 @@ if(val2==NULL)
          /* Position cursor in next line */
          line ++;
          column = 0;
+         new_line_started = 0;
          /* Finished truncating an overlong line */
          skip_rest_of_line = 0;
          skip_spaces = 0;
@@ -911,6 +1001,7 @@ if(val2==NULL)
              for (j = 0; newline_char_str[j]; j ++)
                *(destptr ++) = newline_char_str[j];
          column = 0;
+         new_line_started = 0;
          /* Finished truncating an overlong line */
          skip_rest_of_line = 0;
          skip_spaces = 0;
@@ -929,7 +1020,6 @@ if(val2==NULL)
        }
       }
     }
-    cupsFilePuts(outputfp, out_page);
   } while (outbuf[0] != '\0'); /* End of input file */
 
   close(fd);
index 41fb5e652795115f2e5ccacc355a4a55b125bc75..0617156f0267fc53e06a03a6d5566c31c12ffe60 100644 (file)
@@ -12,7 +12,6 @@
 #include <ctype.h>
 #include <limits.h>
 #include <cups/cups.h>
-#include <ppd/ppd.h>
 
 int                            /* O - Error status */
 cfFilterUniversal(int inputfd,         /* I - File descriptor input stream */
@@ -31,162 +30,43 @@ cfFilterUniversal(int inputfd,         /* I - File descriptor input stream */
   char output_type[256];
   cf_filter_out_format_t *outformat;
   cf_filter_filter_in_chain_t *filter, *next;
-  cf_filter_universal_parameter_t universal_parameters;
-  ppd_file_t *ppd;
-  ppd_cache_t *cache;
+  cf_filter_universal_parameter_t *universal_parameters;
   cf_logfunc_t log = data->logfunc;
   void *ld = data->logdata;
   int ret = 0;
 
-  universal_parameters = *(cf_filter_universal_parameter_t *)parameters;
-  input = universal_parameters.input_format;
+  universal_parameters = (cf_filter_universal_parameter_t *)parameters;
+  input = data->content_type;
   if (input == NULL)
   {
     if (log) log(ld, CF_LOGLEVEL_ERROR,
                 "cfFilterUniversal: No input data format supplied.");
     return (1);
   }
-  final_output = universal_parameters.output_format;
-  if (final_output == NULL)
-  {
-    if (log) log(ld, CF_LOGLEVEL_ERROR,
-                "cfFilterUniversal: No output data format supplied.");
-    return (1);
-  }
-  strncpy(output, final_output, sizeof(output) - 1);
 
-  ppd = data->ppd;
-  cache = ppd ? ppd->cache : NULL;
-
-  /* Check whether our output format (under CUPS it is taken from the
-     FINAL_CONTENT_TYPE env variable) is the destination format (2nd
-     word) of a "*cupsFilter2: ..." line (string has 4 words), in this
-     case the specified filter (4th word) does the last step,
-     converting from the input format (1st word) of the line to the
-     destination format and so we only need to convert to the input
-     format. In this case we need to correct our output format.
-
-     If there is more than one line with the given output format and
-     an inpout format we can produce, we select the one with the
-     lowest cost value (3rd word) as this is the one which CUPS should have
-     chosen for this job.
-
-     If we have "*cupsFilter: ..." lines (without "2", string with 3
-     words) we do not need to do anything special, as the input format
-     specified is the FIMAL_CONTENT_TYPE which CUPS supplies to us and
-     into which we have to convert. So we quit parsing if the first
-     line has only 3 words, as if CUPS uses the "*cupsFilter: ..."
-     lines only if there is no "*cupsFilter2: ..." line min the PPD,
-     so if we encounter a line with only 3 words the other lines will
-     have only 3 words, too and nothing has to be done. */
-
-  if (ppd && ppd->num_filters && cache)
+  final_output = data->final_content_type;
+  if (final_output == NULL)
   {
-    int lowest_cost = INT_MAX;
-    char *filter;
-
-    if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "cfFilterUniversal: \"*cupsFilter(2): ...\" lines in the PPD file:");
-
-    for (filter = (char *)cupsArrayFirst(cache->filters);
-        filter;
-        filter = (char *)cupsArrayNext(cache->filters))
+    final_output = universal_parameters->actual_output_type;
+    if (final_output == NULL)
     {
-      char buf[256];
-      char *ptr,
-          *in = NULL,
-          *out = NULL,
-          *coststr = NULL;
-      int cost;
-
-      if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterUniversal:    %s", filter);
-
-      /* String of the "*cupsfilter:" or "*cupsfilter2:" line */
-      strncpy(buf, filter, sizeof(buf) - 1);
-
-      /* Separate the words */
-      in = ptr = buf;
-      while (*ptr && !isspace(*ptr)) ptr ++;
-      if (!*ptr) goto error;
-      *ptr = '\0';
-      ptr ++;
-      while (*ptr && isspace(*ptr)) ptr ++;
-      if (!*ptr) goto error;
-      out = ptr;
-      while (*ptr && !isspace(*ptr)) ptr ++;
-      if (!*ptr) goto error;
-      *ptr = '\0';
-      ptr ++;
-      while (*ptr && isspace(*ptr)) ptr ++;
-      if (!*ptr) goto error;
-      coststr = ptr;
-      if (!isdigit(*ptr)) goto error;
-      while (*ptr && !isspace(*ptr)) ptr ++;
-      if (!*ptr) goto error;
-      *ptr = '\0';
-      ptr ++;
-      while (*ptr && isspace(*ptr)) ptr ++;
-      if (!*ptr) goto error;
-      cost = atoi(coststr);
-
-      /* Valid "*cupsFilter2: ..." line ... */
-      if (/* Must be of lower cost than what we selected before */
-         cost < lowest_cost &&
-         /* Must have our FINAL_CONTENT_TYPE as output */
-         strcasecmp(out, final_output) == 0 &&
-         /* Must have as input a format we are able to produce */
-         (strcasecmp(in, "application/vnd.cups-raster") == 0 ||
-          strcasecmp(in, "application/vnd.cups-pdf") == 0 ||
-          strcasecmp(in, "application/vnd.cups-postscript") == 0 ||
-          strcasecmp(in, "application/pdf") == 0 ||
-          strcasecmp(in, "image/pwg-raster") == 0 ||
-          strcasecmp(in, "image/urf") == 0 ||
-          strcasecmp(in, "application/PCLm") == 0 ||
-          strcasecmp(in, "application/postscript") == 0))
-      {
-       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                    "cfFilterUniversal:       --> Selecting this line");
-       /* Take the input format of the line as output format for us */
-       strncpy(output, in, sizeof(output));
-       /* Update the minimum cost found */
-       lowest_cost = cost;
-       /* We cannot find a "better" solution ... */
-       if (lowest_cost == 0)
-       {
-         if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                      "cfFilterUniversal:    Cost value is down to zero, stopping reading further lines");
-         break;
-       }
-      }
-
-      continue;
-
-    error:
-      if (lowest_cost == INT_MAX && coststr)
-      {
-       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                    "cfFilterUniversal: PPD uses \"*cupsFilter: ...\" lines, so we always convert to format given by FINAL_CONTENT_TYPE");
-       break;
-      }
       if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "cfFilterUniversal: Invalid \"*cupsFilter2: ...\" line in PPD: %s",
-                  filter);
+                  "cfFilterUniversal: No output data format supplied.");
+      return (1);
     }
-
   }
 
-  if (strcasecmp(output, final_output) != 0)
-  {
-    if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "cfFilterUniversal: Converting from %s to %s, final output will be %s",
-                input, output, final_output);
-  }
+  if (universal_parameters->actual_output_type)
+    strncpy(output, universal_parameters->actual_output_type,
+           sizeof(output) - 1);
   else
-  {
-    if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "cfFilterUniversal: Converting from %s to %s", input, output);
-  }
+    strncpy(output, data->final_content_type, sizeof(output) - 1);
+
+  if (log) log(ld, CF_LOGLEVEL_DEBUG,
+              "cfFilterUniversal: Converting from %s to %s", input, output);
+  if (log) log(ld, CF_LOGLEVEL_DEBUG,
+              "cfFilterUniversal: Final output format for job: %s",
+              final_output);
 
   sscanf(input, "%15[^/]/%255s", input_super, input_type);
   sscanf(output, "%15[^/]/%255s", output_super, output_type);
@@ -290,11 +170,11 @@ cfFilterUniversal(int inputfd,         /* I - File descriptor input stream */
             (!strcmp(input_super, "application") && input_type[0] == 'x'))
     {
       filter = malloc(sizeof(cf_filter_filter_in_chain_t));
-      cf_filter_texttopdf_parameter_t* parameters =
+      cf_filter_texttopdf_parameter_t* tparameters =
        (cf_filter_texttopdf_parameter_t *) malloc(sizeof(cf_filter_texttopdf_parameter_t));
-      *parameters = universal_parameters.texttopdf_params;
+      *tparameters = universal_parameters->texttopdf_params;
       filter->function = cfFilterTextToPDF;
-      filter->parameters = parameters;
+      filter->parameters = tparameters;
       filter->name = "texttopdf";
       cupsArrayAdd(filter_chain, filter);
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
@@ -409,17 +289,6 @@ cfFilterUniversal(int inputfd,         /* I - File descriptor input stream */
                       "cfFilterUniversal: Adding %s to chain",
                       filter->name);
        }
-       else if(!strcmp(output, "application/postscript") ||
-               !strcmp(output, "application/vnd.cups-postscript"))
-       {
-         filter = malloc(sizeof(cf_filter_filter_in_chain_t));
-         filter->function = cfFilterPDFToPS;
-         filter->parameters = NULL;
-         filter->name = "pdftops";
-         if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                      "cfFilterUniversal: Adding %s to chain", filter->name);
-         cupsArrayAdd(filter_chain, filter);
-       }
        else
        {
          // Output format is not PDF and unknown -> Error
index d5cb23f7fe9aa8827ccb54568e1fbfcea6838f78..8b70830a0313a94417a6420cd9f70524858b06b2 100644 (file)
@@ -3,6 +3,7 @@
  */
 
 #include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
 #include <config.h>
 #include <signal.h>
 
@@ -50,7 +51,7 @@ main(int  argc,          /* I - Number of command-line arguments */
 #endif /* HAVE_SIGSET */
 
  /*
-  * Fire up the cfFilterPDFToRaster() filter function
+  * Fire up the ppdFilterPDFToRaster() filter function
   */
 
   char buf[1024];
@@ -59,7 +60,8 @@ main(int  argc,          /* I - Number of command-line arguments */
     datadir = CUPS_DATADIR;
   snprintf(buf, sizeof(buf), "%s/data", datadir);
 
-  ret = cfFilterCUPSWrapper(argc, argv, cfFilterBannerToPDF, buf, &JobCanceled);
+  ret = ppdFilterCUPSWrapper(argc, argv, cfFilterBannerToPDF, buf,
+                            &JobCanceled);
 
   if (ret)
     fprintf(stderr, "ERROR: bannertopdf filter function failed.\n");
index 128081763e55142e293b560e18a93c73d6fcfc77..7544c3b3ebfbedc96fe296ace1305f2767972c68 100644 (file)
 #include <cups/cups.h>
 #include <ppd/ppd.h>
 #include <cupsfilters/driver.h>
+#include <cupsfilters/image.h>
+#include "escp.h"
 #include <string.h>
 #include <ctype.h>
-#include "escp.h"
 
 
 /*
index 096b144528dcb5d846cf6b2f17ff2a86618f8515..d4a03528595f633dabfa4afd55e9ba66c2302d2b 100644 (file)
 #include <cups/cups.h>
 #include <ppd/ppd.h>
 #include <cupsfilters/driver.h>
+#include <cupsfilters/image.h>
+#include "pcl.h"
 #include <string.h>
 #include <ctype.h>
-#include "pcl.h"
 
 
 /*
index 9fed656a553dcc49fdfbc5eff9d816838cd75ef9..87c0561d5f5b2c6999be92746fb66991600efd8f 100644 (file)
@@ -1042,8 +1042,6 @@ int main(int argc, char** argv)
                   _log("INFO: Using qualifer: '%s.%s.%s'\n",
                         qualifier[0], qualifier[1], qualifier[2]);
 
-                  cfCmGetPrinterIccProfile(data, (char **)&icc_profile, 0);
-
                   /* fall back to PPD */
                   if (icc_profile == NULL) {
                     _log("INFO: need to look in PPD for matching qualifer\n");
index 57d118f1596cb24260a14462747464de0e80da73..ce6d63588bdc7f495b76e0949fdcf70af34431ba 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
 #include <signal.h>
 
 
@@ -54,12 +55,12 @@ main(int  argc,                             /* I - Number of command-line args */
 #endif /* HAVE_SIGSET */
 
   /*
-   * Fire up the cfFilterGhostscript() filter function.
+   * Fire up the ppdFilterGhostscript() filter function.
    */
 
   cf_filter_out_format_t outformat = CF_FILTER_OUT_FORMAT_PDF;
-  ret = cfFilterCUPSWrapper(argc, argv, cfFilterGhostscript, &outformat,
-                           &JobCanceled);
+  ret = ppdFilterCUPSWrapper(argc, argv, cfFilterGhostscript, &outformat,
+                            &JobCanceled);
 
   if (ret)
     fprintf(stderr, "ERROR: gstopdf filter failed.\n");
index cdbecf55ada0dfc5227c72fd23f042b69c88a185..94954da913df79f15a11cd961f4532c7950185ab 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
 #include <signal.h>
 
 
@@ -55,12 +56,12 @@ main(int  argc,                             /* I - Number of command-line args */
 #endif /* HAVE_SIGSET */
 
   /*
-   * Fire up the cfFilterGhostscript() filter function.
+   * Fire up the ppdFilterGhostscript() filter function.
    */
 
   cf_filter_out_format_t outformat = CF_FILTER_OUT_FORMAT_PXL;
-  ret = cfFilterCUPSWrapper(argc, argv, cfFilterGhostscript, &outformat,
-                           &JobCanceled);
+  ret = ppdFilterCUPSWrapper(argc, argv, cfFilterGhostscript, &outformat,
+                            &JobCanceled);
 
   if (ret)
     fprintf(stderr, "ERROR: gstopxl filter failed.\n");
index 46322a0b7ee270fafd4b00167c44874d6c23dc0d..0aa5e70665a88f63d3ec1bba9b91d7874933df92 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
 #include <signal.h>
 
 
@@ -55,22 +56,11 @@ main(int  argc,                             /* I - Number of command-line args */
 #endif /* HAVE_SIGSET */
 
   /*
-   * Fire up the cfFilterGhostscript() filter function.
+   * Fire up the ppdFilterGhostscript() filter function.
    */
 
-  cf_filter_out_format_t outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
-  char *t = getenv("FINAL_CONTENT_TYPE");
-  if (t) {
-    if (strcasestr(t, "pwg"))
-      outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
-    else if (strcasestr(t, "urf"))
-      outformat = CF_FILTER_OUT_FORMAT_APPLE_RASTER;
-    else if (strcasestr(t, "pclm"))
-      outformat = CF_FILTER_OUT_FORMAT_PCLM;
-  }
-
-  ret = cfFilterCUPSWrapper(argc, argv, cfFilterGhostscript, &outformat,
-                           &JobCanceled);
+  ret = ppdFilterCUPSWrapper(argc, argv, cfFilterGhostscript, NULL,
+                            &JobCanceled);
 
   if (ret)
     fprintf(stderr, "ERROR: gstoraster filter failed.\n");
index a208f63b17a3d6f837e37b60c2d3ce81d55ba268..88b3d3aea36740a582be317be79037105c08962b 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
 #include <signal.h>
 
 
@@ -61,10 +62,11 @@ main(int  argc,                             /* I - Number of command-line args */
 #endif /* HAVE_SIGSET */
 
  /*
-  * Fire up the cfFilterImageToPDF() filter function
+  * Fire up the ppdFilterImageToPDF() filter function
   */
 
-  ret = cfFilterCUPSWrapper(argc, argv, cfFilterImageToPDF, NULL, &JobCanceled);
+  ret = ppdFilterCUPSWrapper(argc, argv, ppdFilterImageToPDF, NULL,
+                            &JobCanceled);
 
   if (ret)
     fprintf(stderr, "ERROR: imagetopdf filter function failed.\n");
index e373b4f56b9c22c50fe3824e4cf9465237cd6198..9ad54b12a377b44bad623c367463b005da7c44cd 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
 #include <signal.h>
 
 
@@ -64,7 +65,7 @@ main(int  argc,                               /* I - Number of command-line args */
   * Fire up the cfFilterImageToPS() filter function
   */
 
-  ret = cfFilterCUPSWrapper(argc, argv, cfFilterImageToPS, NULL, &JobCanceled);
+  ret = ppdFilterCUPSWrapper(argc, argv, ppdFilterImageToPS, NULL, &JobCanceled);
 
   if (ret)
     fprintf(stderr, "ERROR: imagetops filter function failed.\n");
index 9e60fb901dbd3dfcecef90cd8e9a805349e33887..86c7b8c54385d0aa4bb0409ec060f5e9aa74ca98 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
 #include <signal.h>
 
 
@@ -61,21 +62,10 @@ main(int  argc,                             /* I - Number of command-line args */
 #endif /* HAVE_SIGSET */
 
  /*
-  * Fire up the cfFilterImageToRaster() filter function
+  * Fire up the ppdFilterImageToRaster() filter function
   */
 
-  cf_filter_out_format_t outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
-  char *t = getenv("FINAL_CONTENT_TYPE");
-  if (t) {
-    if (strcasestr(t, "pwg"))
-      outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
-    else if (strcasestr(t, "urf"))
-      outformat = CF_FILTER_OUT_FORMAT_APPLE_RASTER;
-    else if (strcasestr(t, "pclm"))
-      outformat = CF_FILTER_OUT_FORMAT_PCLM;
-  }
-
-  ret = cfFilterCUPSWrapper(argc, argv, cfFilterImageToRaster, &outformat, &JobCanceled);
+  ret = ppdFilterCUPSWrapper(argc, argv, cfFilterImageToRaster, NULL, &JobCanceled);
 
   if (ret)
     fprintf(stderr, "ERROR: imagetoraster filter function failed.\n");
index eff52b3a65cdbf09de9835af6900767142ddfd6b..eeac5f19fbf538ac460a827f55fd8013baf30af0 100644 (file)
@@ -3,6 +3,7 @@
  */
 
 #include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
 #include <signal.h>
 
 /*
@@ -50,21 +51,10 @@ main(int  argc,        /* I - Number of command-line arguments */
 #endif /* HAVE_SIGSET */
 
  /*
-  * Fire up the cfFilterMuPDFToPWG() filter function
+  * Fire up the ppdFilterMuPDFToPWG() filter function
   */
   
-  cf_filter_out_format_t outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
-  char *t = getenv("FINAL_CONTENT_TYPE");
-  if (t) {
-    if (strcasestr(t, "pwg"))
-      outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
-    else if (strcasestr(t, "urf"))
-      outformat = CF_FILTER_OUT_FORMAT_APPLE_RASTER;
-    else if (strcasestr(t, "pclm"))
-      outformat = CF_FILTER_OUT_FORMAT_PCLM;
-  }
-
-  ret = cfFilterCUPSWrapper(argc, argv, cfFilterMuPDFToPWG, &outformat, &JobCanceled);
+  ret = ppdFilterCUPSWrapper(argc, argv, cfFilterMuPDFToPWG, NULL, &JobCanceled);
 
   if (ret)
     fprintf(stderr, "ERROR: mupdftopwg filter function failed.\n");
index 2488d2514e5076293b4d8acc28d44f1afff24ae5..fd0ae934a37358831642bac4c22eacd2d04f2611 100644 (file)
@@ -21,6 +21,8 @@
  */
 
 #include <cupsfilters/driver.h>
+#include <ppd/ppd.h>
+#include <ppd/ppd-filter.h>
 #include "pcl-common.h"
 #include <math.h>
 
index 9249aaf1b1ec99416ce5b527df74535afb5ba996..42d8ab0c56aa65ee185b1bdbaf1e40234ac854b2 100644 (file)
@@ -14,6 +14,7 @@
  * Include necessary headers...
  */
 
+#include <ppd/ppd.h>
 #include <string.h>
 #include <ctype.h>
 #include "pcl.h"
index f773a50bd036e47691347d9034811280c6c6f8e7..a34cc1a64dd7b733b458880f624e1505d9b92b61 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
 
 /*
  * Local globals...
@@ -46,7 +47,7 @@ int main(int argc, char **argv)
       outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
   }
 
-  ret = cfFilterCUPSWrapper(argc, argv, cfFilterPCLmToRaster, &outformat, &JobCanceled);
+  ret = ppdFilterCUPSWrapper(argc, argv, cfFilterPCLmToRaster, &outformat, &JobCanceled);
 
   if (ret)
     fprintf(stderr, "ERROR: pclmtoraster filter function failed.\n");
index b84e41c8c917e04d39707493a831623165d22d4a..1e08b1be9383adcbdc55b878d250a43e186e4cc1 100644 (file)
@@ -6,7 +6,9 @@
 /*
  * Include necessary headers...
  */
+
 #include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
 #include <signal.h>
 
 
@@ -52,8 +54,13 @@ main(int  argc,                              /* I - Number of command-line args */
 #else
   signal(SIGTERM, cancel_job);
 #endif /* HAVE_SIGSET */
-  char *t = getenv("FINAL_CONTENT_TYPE");
-  ret = cfFilterCUPSWrapper(argc, argv, cfFilterPDFToPDF, t, &JobCanceled);
+
+ /*
+  * Fire up the ppdFilterPDFToPDF() filter function
+  */
+
+  ret = ppdFilterCUPSWrapper(argc, argv, ppdFilterPDFToPDF, NULL, &JobCanceled);
+
   if (ret)
     fprintf(stderr, "ERROR: pdftopdf filter function failed.\n");
 
index 2774d346f3c5aae19377c9b34eba4b2465a8181e..28e0e9911ceb6e91573928d4ea19da95da2bd07b 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
 #include <signal.h>
 
 
@@ -64,7 +65,7 @@ main(int  argc,                               /* I - Number of command-line args */
   * Fire up the cfFilterPSToPS() filter function
   */
 
-  ret = cfFilterCUPSWrapper(argc, argv, cfFilterPDFToPS, NULL, &JobCanceled);
+  ret = ppdFilterCUPSWrapper(argc, argv, ppdFilterPDFToPS, NULL, &JobCanceled);
 
   if (ret)
     fprintf(stderr, "ERROR: pdftops filter function failed.\n");
index a059460e1e4a3707955722df72065d725c0487d4..c30bb9220e6c26984feb3d81b6db078fb7581fa2 100644 (file)
@@ -3,6 +3,7 @@
  */
 
 #include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
 #include <signal.h>
 
 /*
@@ -49,23 +50,10 @@ main(int  argc,        /* I - Number of command-line arguments */
 #endif /* HAVE_SIGSET */
 
  /*
-  * Fire up the cfFilterPDFToRaster() filter function
+  * Fire up the ppdFilterPDFToRaster() filter function
   */
 
-  cf_filter_out_format_t outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
-  char *t = getenv("FINAL_CONTENT_TYPE");
-  if (t) {
-    if (strcasestr(t, "pwg"))
-      outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
-    else if (strcasestr(t, "cups"))
-      outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
-    else if (strcasestr(t, "urf"))
-      outformat = CF_FILTER_OUT_FORMAT_APPLE_RASTER;
-    else if (strcasestr(t, "pclm"))
-      outformat = CF_FILTER_OUT_FORMAT_PCLM;
-  }
-
-  ret = cfFilterCUPSWrapper(argc, argv, cfFilterPDFToRaster, &outformat, &JobCanceled);
+  ret = ppdFilterCUPSWrapper(argc, argv, cfFilterPDFToRaster, NULL, &JobCanceled);
 
   if (ret)
     fprintf(stderr, "ERROR: pdftoraster filter function failed.\n");
index 8c42eb7934793d0ba39240f547c9458551fb2e18..06837c4b05c629107fc14e2e9a35e66b40ec98b0 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
 #include <signal.h>
 
 
@@ -64,7 +65,7 @@ main(int  argc,                               /* I - Number of command-line args */
   * Fire up the cfFilterPSToPS() filter function
   */
 
-  ret = cfFilterCUPSWrapper(argc, argv, cfFilterPSToPS, NULL, &JobCanceled);
+  ret = ppdFilterCUPSWrapper(argc, argv, ppdFilterPSToPS, NULL, &JobCanceled);
 
   if (ret)
     fprintf(stderr, "ERROR: pstops filter function failed.\n");
index c630ec06f72e2ca9bbe0b6d214ab8ff9f6a8faa2..355567af6e0c702dbb276e7ab675ad665b377c26 100644 (file)
@@ -3,6 +3,7 @@
  */
 
 #include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
 #include <signal.h>
 
 /*
@@ -49,21 +50,10 @@ main(int  argc,        /* I - Number of command-line arguments */
 #endif /* HAVE_SIGSET */
 
  /*
-  * Fire up the cfFilterPDFToRaster() filter function
+  * Fire up the ppdFilterPWGToRaster() filter function
   */
 
-  cf_filter_out_format_t outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
-  char *t = getenv("FINAL_CONTENT_TYPE");
-  if (t) {
-    if (strcasestr(t, "pwg"))
-      outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
-    else if (strcasestr(t, "urf"))
-      outformat = CF_FILTER_OUT_FORMAT_APPLE_RASTER;
-    else if (strcasestr(t, "pclm"))
-      outformat = CF_FILTER_OUT_FORMAT_PCLM;
-  }
-
-  ret = cfFilterCUPSWrapper(argc, argv, cfFilterPWGToRaster, &outformat, &JobCanceled);
+  ret = ppdFilterCUPSWrapper(argc, argv, cfFilterPWGToRaster, NULL, &JobCanceled);
 
   if (ret)
     fprintf(stderr, "ERROR: pwgtoraster filter function failed.\n");
index 8c851afece8b310121a368c407674df506550a29..a9e6e7556c7dd493fe83abe294b5343851469a22 100644 (file)
@@ -28,6 +28,7 @@
  */
 
 #include <cupsfilters/driver.h>
+#include <ppd/ppd.h>
 #include "escp.h"
 #include <signal.h>
 #include <string.h>
@@ -244,13 +245,13 @@ StartPage(ppd_file_t         *ppd,        /* I - PPD file */
 
   if (header->cupsColorSpace == CUPS_CSPACE_RGB ||
       header->cupsColorSpace == CUPS_CSPACE_W)
-    RGB = cfRGBLoad(ppd, colormodel, header->MediaType, resolution,
-                     logfunc, ld);
+    RGB = ppdRGBLoad(ppd, colormodel, header->MediaType, resolution,
+                    logfunc, ld);
   else
     RGB = NULL;
 
-  CMYK = cfCMYKLoad(ppd, colormodel, header->MediaType, resolution,
-                     logfunc, ld);
+  CMYK = ppdCMYKLoad(ppd, colormodel, header->MediaType, resolution,
+                    logfunc, ld);
 
   if (RGB)
     fputs("DEBUG: Loaded RGB separation from PPD.\n", stderr);
@@ -274,66 +275,66 @@ StartPage(ppd_file_t         *ppd,        /* I - PPD file */
   switch (PrinterPlanes)
   {
     case 1 : /* K */
-        DitherLuts[0] = cfLutLoad(ppd, colormodel, header->MediaType,
+        DitherLuts[0] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                    resolution, "Black", logfunc, ld);
         break;
 
     case 2 : /* Kk */
-        DitherLuts[0] = cfLutLoad(ppd, colormodel, header->MediaType,
+        DitherLuts[0] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                    resolution, "Black", logfunc, ld);
-        DitherLuts[1] = cfLutLoad(ppd, colormodel, header->MediaType,
+        DitherLuts[1] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                    resolution, "LightBlack", logfunc, ld);
         break;
 
     case 3 : /* CMY */
-        DitherLuts[0] = cfLutLoad(ppd, colormodel, header->MediaType,
+        DitherLuts[0] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                    resolution, "Cyan", logfunc, ld);
-        DitherLuts[1] = cfLutLoad(ppd, colormodel, header->MediaType,
+        DitherLuts[1] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                    resolution, "Magenta", logfunc, ld);
-        DitherLuts[2] = cfLutLoad(ppd, colormodel, header->MediaType,
+        DitherLuts[2] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                    resolution, "Yellow", logfunc, ld);
         break;
 
     case 4 : /* CMYK */
-        DitherLuts[0] = cfLutLoad(ppd, colormodel, header->MediaType,
+        DitherLuts[0] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                    resolution, "Cyan", logfunc, ld);
-        DitherLuts[1] = cfLutLoad(ppd, colormodel, header->MediaType,
+        DitherLuts[1] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                    resolution, "Magenta", logfunc, ld);
-        DitherLuts[2] = cfLutLoad(ppd, colormodel, header->MediaType,
+        DitherLuts[2] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                    resolution, "Yellow", logfunc, ld);
-        DitherLuts[3] = cfLutLoad(ppd, colormodel, header->MediaType,
+        DitherLuts[3] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                    resolution, "Black", logfunc, ld);
         break;
 
     case 6 : /* CcMmYK */
-        DitherLuts[0] = cfLutLoad(ppd, colormodel, header->MediaType,
+        DitherLuts[0] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                    resolution, "Cyan", logfunc, ld);
-        DitherLuts[1] = cfLutLoad(ppd, colormodel, header->MediaType,
+        DitherLuts[1] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                    resolution, "LightCyan", logfunc, ld);
-        DitherLuts[2] = cfLutLoad(ppd, colormodel, header->MediaType,
+        DitherLuts[2] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                    resolution, "Magenta", logfunc, ld);
-        DitherLuts[3] = cfLutLoad(ppd, colormodel, header->MediaType,
+        DitherLuts[3] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                    resolution, "LightMagenta", logfunc, ld);
-        DitherLuts[4] = cfLutLoad(ppd, colormodel, header->MediaType,
+        DitherLuts[4] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                    resolution, "Yellow", logfunc, ld);
-        DitherLuts[5] = cfLutLoad(ppd, colormodel, header->MediaType,
+        DitherLuts[5] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                    resolution, "Black", logfunc, ld);
         break;
 
     case 7 : /* CcMmYKk */
-        DitherLuts[0] = cfLutLoad(ppd, colormodel, header->MediaType,
+        DitherLuts[0] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                    resolution, "Cyan", logfunc, ld);
-        DitherLuts[1] = cfLutLoad(ppd, colormodel, header->MediaType,
+        DitherLuts[1] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                    resolution, "LightCyan", logfunc, ld);
-        DitherLuts[2] = cfLutLoad(ppd, colormodel, header->MediaType,
+        DitherLuts[2] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                    resolution, "Magenta", logfunc, ld);
-        DitherLuts[3] = cfLutLoad(ppd, colormodel, header->MediaType,
+        DitherLuts[3] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                    resolution, "LightMagenta", logfunc, ld);
-        DitherLuts[4] = cfLutLoad(ppd, colormodel, header->MediaType,
+        DitherLuts[4] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                    resolution, "Yellow", logfunc, ld);
-        DitherLuts[5] = cfLutLoad(ppd, colormodel, header->MediaType,
+        DitherLuts[5] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                    resolution, "Black", logfunc, ld);
-        DitherLuts[6] = cfLutLoad(ppd, colormodel, header->MediaType,
+        DitherLuts[6] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                    resolution, "LightBlack", logfunc, ld);
         break;
   }
@@ -763,7 +764,7 @@ StartPage(ppd_file_t         *ppd,  /* I - PPD file */
   * Enable unidirectional printing depending on the mode...
   */
 
-  if ((attr = cfFindAttr(ppd, "cupsESCPDirection", colormodel,
+  if ((attr = ppdFindColorAttr(ppd, "cupsESCPDirection", colormodel,
                            header->MediaType, resolution, spec,
                           sizeof(spec), logfunc, ld)) != NULL)
     printf("\033U%c", atoi(attr->value));
@@ -772,7 +773,7 @@ StartPage(ppd_file_t         *ppd,  /* I - PPD file */
   * Enable/disable microweaving as needed...
   */
 
-  if ((attr = cfFindAttr(ppd, "cupsESCPMicroWeave", colormodel,
+  if ((attr = ppdFindColorAttr(ppd, "cupsESCPMicroWeave", colormodel,
                            header->MediaType, resolution, spec,
                           sizeof(spec), logfunc, ld)) != NULL)
     printf("\033(i\001%c%c", 0, atoi(attr->value));
@@ -781,7 +782,7 @@ StartPage(ppd_file_t         *ppd,  /* I - PPD file */
   * Set the dot size and print speed as needed...
   */
 
-  if ((attr = cfFindAttr(ppd, "cupsESCPDotSize", colormodel,
+  if ((attr = ppdFindColorAttr(ppd, "cupsESCPDotSize", colormodel,
                            header->MediaType, resolution, spec,
                           sizeof(spec), logfunc, ld)) != NULL)
     printf("\033(e\002%c%c%c", 0, 0, atoi(attr->value));
@@ -1204,7 +1205,7 @@ Shutdown(ppd_file_t *ppd)         /* I - PPD file */
     cfWritePrintData("\033(R\010\000\000REMOTE1", 13);
 
    /*
-    * Load defaults...
+    * LoadXS defaults...
     */
 
     cfWritePrintData("LD\000\000", 4);
index 8174149d64f152d58989564a5dc00864f1cc0a30..fb07c778e1f0485661e0a935953581a9f817a68c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Raster to pclm filter(based on cfFilterRasterToPDF() filter function).
+ * Raster to PCLm filter (based on cfFilterRasterToPDF() filter function).
  */
 
 
@@ -8,6 +8,7 @@
  */
 
 #include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
 #include <signal.h>
 
 
@@ -54,11 +55,11 @@ main(int  argc,                             /* I - Number of command-line args */
 #endif /* HAVE_SIGSET */
 
   /*
-   * Fire up the cfFilterRasterToPDF() filter function.
+   * Fire up the ppdFilterRasterToPDF() filter function.
    */
 
   cf_filter_out_format_t outformat = CF_FILTER_OUT_FORMAT_PCLM;
-  ret = cfFilterCUPSWrapper(argc, argv, cfFilterRasterToPDF, &outformat, &JobCanceled);
+  ret = ppdFilterCUPSWrapper(argc, argv, cfFilterRasterToPDF, &outformat, &JobCanceled);
 
   if (ret)
     fprintf(stderr, "ERROR: rastertopclm filter failed.\n");
index 8ba022854d928f236412df2b6b343b6bee8a9855..07f6b42edfa4d9e74312e461e4b3740e90087355 100644 (file)
  * Include necessary headers...
  */
 
+#include "pcl-common.h"
 #include <cupsfilters/colormanager.h>
 #include <cupsfilters/driver.h>
-#include "pcl-common.h"
-#include <signal.h>
 #include <cupsfilters/filter.h>
+#include <ppd/ppd.h>
+#include <ppd/ppd-filter.h>
+#include <signal.h>
 
 /*
  * Output modes...
@@ -347,7 +349,7 @@ StartPage(cf_filter_data_t      *data,      /* I - filter data */
     fprintf(stderr, "DEBUG: Resolution = %s\n", resolution);
 
     /* support the "cm-calibration" option */
-    cm_calibrate = cfCmGetCupsColorCalibrateMode(data, options, num_options);
+    cm_calibrate = cfCmGetCupsColorCalibrateMode(data);
 
     if (cm_calibrate == CF_CM_CALIBRATION_ENABLED)
       cm_disabled = 1;
@@ -358,10 +360,10 @@ StartPage(cf_filter_data_t      *data,    /* I - filter data */
     {
       if (header->cupsColorSpace == CUPS_CSPACE_RGB ||
          header->cupsColorSpace == CUPS_CSPACE_W)
-       RGB = cfRGBLoad(ppd, colormodel, header->MediaType, resolution,
+       RGB = ppdRGBLoad(ppd, colormodel, header->MediaType, resolution,
                          logfunc, ld);
 
-      CMYK = cfCMYKLoad(ppd, colormodel, header->MediaType, resolution,
+      CMYK = ppdCMYKLoad(ppd, colormodel, header->MediaType, resolution,
                          logfunc, ld);
     }
 
@@ -393,42 +395,42 @@ StartPage(cf_filter_data_t      *data,    /* I - filter data */
     switch (PrinterPlanes)
     {
       case 1 : /* K */
-          DitherLuts[0] = cfLutLoad(ppd, colormodel, header->MediaType,
+          DitherLuts[0] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                      resolution, "Black", logfunc, ld);
           break;
 
       case 3 : /* CMY */
-          DitherLuts[0] = cfLutLoad(ppd, colormodel, header->MediaType,
+          DitherLuts[0] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                      resolution, "Cyan", logfunc, ld);
-          DitherLuts[1] = cfLutLoad(ppd, colormodel, header->MediaType,
+          DitherLuts[1] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                      resolution, "Magenta", logfunc, ld);
-          DitherLuts[2] = cfLutLoad(ppd, colormodel, header->MediaType,
+          DitherLuts[2] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                      resolution, "Yellow", logfunc, ld);
           break;
 
       case 4 : /* CMYK */
-          DitherLuts[0] = cfLutLoad(ppd, colormodel, header->MediaType,
+          DitherLuts[0] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                      resolution, "Cyan", logfunc, ld);
-          DitherLuts[1] = cfLutLoad(ppd, colormodel, header->MediaType,
+          DitherLuts[1] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                      resolution, "Magenta", logfunc, ld);
-          DitherLuts[2] = cfLutLoad(ppd, colormodel, header->MediaType,
+          DitherLuts[2] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                      resolution, "Yellow", logfunc, ld);
-          DitherLuts[3] = cfLutLoad(ppd, colormodel, header->MediaType,
+          DitherLuts[3] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                      resolution, "Black", logfunc, ld);
           break;
 
       case 6 : /* CcMmYK */
-          DitherLuts[0] = cfLutLoad(ppd, colormodel, header->MediaType,
+          DitherLuts[0] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                      resolution, "Cyan", logfunc, ld);
-          DitherLuts[1] = cfLutLoad(ppd, colormodel, header->MediaType,
+          DitherLuts[1] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                      resolution, "LightCyan", logfunc, ld);
-          DitherLuts[2] = cfLutLoad(ppd, colormodel, header->MediaType,
+          DitherLuts[2] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                      resolution, "Magenta", logfunc, ld);
-          DitherLuts[3] = cfLutLoad(ppd, colormodel, header->MediaType,
+          DitherLuts[3] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                      resolution, "LightMagenta", logfunc, ld);
-          DitherLuts[4] = cfLutLoad(ppd, colormodel, header->MediaType,
+          DitherLuts[4] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                      resolution, "Yellow", logfunc, ld);
-          DitherLuts[5] = cfLutLoad(ppd, colormodel, header->MediaType,
+          DitherLuts[5] = ppdLutLoad(ppd, colormodel, header->MediaType,
                                      resolution, "Black", logfunc, ld);
           break;
     }
@@ -666,7 +668,7 @@ StartPage(cf_filter_data_t      *data,      /* I - filter data */
     printf("\033*p0Y\033*p0X");
   }
 
-  if (ppd && ((attr = cfFindAttr(ppd, "cupsPCLQuality", colormodel,
+  if (ppd && ((attr = ppdFindColorAttr(ppd, "cupsPCLQuality", colormodel,
                                   header->MediaType, resolution, spec,
                                   sizeof(spec), logfunc, ld)) != NULL))
   {
@@ -697,7 +699,7 @@ StartPage(cf_filter_data_t      *data,      /* I - filter data */
       * vertical resolutions as well as a color count...
       */
 
-      if (ppd && ((attr = cfFindAttr(ppd, "cupsPCLCRDMode", colormodel,
+      if (ppd && ((attr = ppdFindColorAttr(ppd, "cupsPCLCRDMode", colormodel,
                                       header->MediaType, resolution, spec,
                                       sizeof(spec), logfunc, ld)) != NULL))
         i = atoi(attr->value);
index 12cde08f9e4c00bb22c9dca2deb46fa6f10ff2e3..76065b9a900c1be9459f181158e8c441d41278c7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Raster to pdf filter(based on cfFilterRasterToPDF() filter function).
+ * Raster to PDF filter (based on cfFilterRasterToPDF() filter function).
  */
 
 
@@ -8,6 +8,7 @@
  */
 
 #include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
 #include <signal.h>
 
 
@@ -54,11 +55,11 @@ main(int  argc,                             /* I - Number of command-line args */
 #endif /* HAVE_SIGSET */
 
   /*
-   * Fire up the cfFilterRasterToPDF() filter function.
+   * Fire up the ppdFilterRasterToPDF() filter function.
    */
 
   cf_filter_out_format_t outformat = CF_FILTER_OUT_FORMAT_PDF;
-  ret = cfFilterCUPSWrapper(argc, argv, cfFilterRasterToPDF, &outformat, &JobCanceled);
+  ret = ppdFilterCUPSWrapper(argc, argv, cfFilterRasterToPDF, &outformat, &JobCanceled);
 
   if (ret)
     fprintf(stderr, "ERROR: rastertopdf filter failed.\n");
index a72553a8e780f1c6469c3e27796999cfd7df9efe..f6065bb43e4d81908bd43e4abf57fe8e0ef78a06 100644 (file)
@@ -25,6 +25,7 @@
  */
 
 #include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
 #include <signal.h>
 
 /*
@@ -74,7 +75,8 @@ main(int  argc,          /* I - Number of command-line arguments */
   * Fire up the cfFilterRasterToPS() filter function
   */
 
-  ret = cfFilterCUPSWrapper(argc, argv, cfFilterRasterToPS, NULL, &JobCanceled);
+  ret = ppdFilterCUPSWrapper(argc, argv, ppdFilterRasterToPS, NULL,
+                            &JobCanceled);
 
   if (ret)
     fprintf(stderr, "ERROR: rastertops filter function failed.\n");
index 125ce97440a53e4f18108ef2f48cb5ccd65fac71..e4ae895444843f5a8615e3a97efdb25e3e40e686 100644 (file)
@@ -3,6 +3,7 @@
  */
 
 #include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
 #include <signal.h>
 
 /*
@@ -49,17 +50,10 @@ main(int  argc,        /* I - Number of command-line arguments */
 #endif /* HAVE_SIGSET */
 
  /*
-  * Fire up the cfFilterPDFToRaster() filter function
+  * Fire up the ppdFilterRasterToPWG() filter function
   */
-  cf_filter_out_format_t outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
-  char *t = getenv("FINAL_CONTENT_TYPE");
-  if (t) {
-    if (strcasestr(t, "pwg"))
-      outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
-    else if (strcasestr(t, "urf"))
-      outformat = CF_FILTER_OUT_FORMAT_APPLE_RASTER;
-  }
-  ret = cfFilterCUPSWrapper(argc, argv, cfFilterRasterToPWG, &outformat, &JobCanceled);
+
+  ret = ppdFilterCUPSWrapper(argc, argv, cfFilterRasterToPWG, NULL, &JobCanceled);
 
   if (ret)
     fprintf(stderr, "ERROR: rastertopwg filter function failed.\n");
index 1ed6f29e3912cd9d18985aa3cef88b4129860771..6781ef15ae2eeb4813cd66a079724132340fe584 100644 (file)
@@ -25,7 +25,7 @@ int main()
   int cobj=cfPDFOutAddXRef(pdf);
   const char buf[]="BT /a 10 Tf (abc) Tj ET";
   cfPDFOutPrintF(pdf,"%d 0 obj\n"
-                    "<</Length %d\n"
+                    "<</Length %ld\n"
                     ">>\n"
                     "stream\n"
                     "%s\n"
index 85524ba4774dc624c41c73aacf16040a10641824..3fd4baadb1aff224f2a7da8c35d46106eb94bafa 100644 (file)
@@ -79,7 +79,7 @@ int main()
   const int clobj=cfPDFOutAddXRef(pdf);
   assert(clobj==cobj+1);
   cfPDFOutPrintF(pdf,"%d 0 obj\n"
-                    "%d\n"
+                    "%ld\n"
                     "endobj\n"
                     ,clobj,streamlen);
 
index 4c3ac47c2414855da72b28cb139c6152831d61d4..43b56179c290871e9068972832f3b8cf24756f58 100644 (file)
@@ -3,6 +3,7 @@
  */
 
 #include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
 #include <signal.h>
 #include <fontconfig/fontconfig.h>
 #include <config.h>
@@ -50,7 +51,7 @@ main(int  argc,          /* I - Number of command-line arguments */
 #endif /* HAVE_SIGSET */
 
  /*
-  * Fire up the cfFilterTextToPDF() filter function
+  * Fire up the ppdFilterTextToPDF() filter function
   */
  cf_filter_texttopdf_parameter_t parameters;
  char *p;
@@ -72,7 +73,7 @@ main(int  argc,          /* I - Number of command-line arguments */
  else
    parameters.classification = NULL;
 
-  ret = cfFilterCUPSWrapper(argc, argv, cfFilterTextToPDF, &parameters, &JobCanceled);
+  ret = ppdFilterCUPSWrapper(argc, argv, cfFilterTextToPDF, &parameters, &JobCanceled);
 
   if (ret)
     fprintf(stderr, "ERROR: texttopdf filter function failed.\n");
index 72a8ff86cc9c7087d88ff4e0dd53ca7880943175..d27ab7f14a29df0bc00df0fde63498cf7b19194c 100644 (file)
@@ -3,6 +3,7 @@
  */
 
 #include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
 #include <signal.h>
 
 /*
@@ -49,11 +50,12 @@ main(int  argc,        /* I - Number of command-line arguments */
 #endif /* HAVE_SIGSET */
 
  /*
-  * Fire up the cfFilterTextToText() filter function
+  * Fire up the ppdFilterTextToText() filter function
   */
 
 
-  ret = cfFilterCUPSWrapper(argc, argv, cfFilterTextToText, NULL, &JobCanceled);
+  ret = ppdFilterCUPSWrapper(argc, argv, cfFilterTextToText, NULL,
+                            &JobCanceled);
 
   if (ret)
     fprintf(stderr, "ERROR: texttotext filter function failed.\n");
index 44ace59847711c6454814074eef0710bdedda076..6dfedd34e9358cf649bd8d860c48adacd22916d3 100644 (file)
@@ -3,6 +3,7 @@
  */
 
 #include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
 #include <config.h>
 #include <signal.h>
 
@@ -52,16 +53,8 @@ main(int  argc,                              /* I - Number of command-line args */
   signal(SIGTERM, cancel_job);
 #endif /* HAVE_SIGSET */
 
-  if ((p = getenv("CONTENT_TYPE")) != NULL)
-    universal_parameters.input_format = strdup(p);
-  else
-    universal_parameters.input_format = NULL;
-
-  if ((p = getenv("FINAL_CONTENT_TYPE")) != NULL)
-    universal_parameters.output_format = strdup(p);
-  else
-    universal_parameters.output_format = NULL;
-
+  universal_parameters.actual_output_type = NULL; /* Determined by PPD file */
+  
   if ((p = getenv("CUPS_DATADIR")) != NULL)
     universal_parameters.texttopdf_params.data_dir = strdup(p);
   else
@@ -72,24 +65,25 @@ main(int  argc,                             /* I - Number of command-line args */
   else
     universal_parameters.texttopdf_params.char_set = NULL;
 
-  universal_parameters.texttopdf_params.content_type =
-    universal_parameters.input_format;
+  if ((p = getenv("CONTENT_TYPE")) != NULL)
+    universal_parameters.texttopdf_params.content_type = strdup(p);
+  else
+    universal_parameters.texttopdf_params.content_type = NULL;
 
   if ((p = getenv("CLASSIFICATION")) != NULL)
     universal_parameters.texttopdf_params.classification = strdup(p);
   else
     universal_parameters.texttopdf_params.classification = NULL;
 
-  ret = cfFilterCUPSWrapper(argc, argv, cfFilterUniversal, &universal_parameters,
-                         &JobCanceled);
+  ret = ppdFilterCUPSWrapper(argc, argv, ppdFilterUniversal,
+                            &universal_parameters, &JobCanceled);
 
   if (ret)
     fprintf(stderr, "ERROR: universal filter failed.\n");
 
-  free(universal_parameters.input_format);
-  free(universal_parameters.output_format);
   free(universal_parameters.texttopdf_params.data_dir);
   free(universal_parameters.texttopdf_params.char_set);
+  free(universal_parameters.texttopdf_params.content_type);
   free(universal_parameters.texttopdf_params.classification);
 
   return (ret);
index dc7ea1ef40b8d61b4ede438cdd327ca4c5a767c2..481a293ffc5b744d3d794dc388f09722d71a4bd1 100644 (file)
@@ -4,7 +4,7 @@ libdir=@libdir@
 includedir=@includedir@
                                                                        
 Name: libppd
-Description: Library for handling PPD files
+Description: Library for handling PPD files and PostScript output
 Version: @VERSION@
 
 Libs: -L${libdir} -lppd
similarity index 95%
rename from cupsfilters/imagetops-pstops.c
rename to ppd/imagetops-pstops.c
index fbc0ac89085f02822ada7b4806cb60b484cf230b..6232ce5decde07e231f29c13619b8c860a67d6ca 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * PostScript filter function and image file to PostScript filter function
- * for cups-filters.
+ * for libppd.
  *
  * Copyright Â©Â 2020 by Till Kamppeter
  * Copyright Â©Â 2007-2018 by Apple Inc.
@@ -19,6 +19,7 @@
 #include <cupsfilters/raster.h>
 #include <cupsfilters/image-private.h>
 #include <ppd/ppd.h>
+#include <ppd/ppd-filter.h>
 #include <cups/file.h>
 #include <cups/array.h>
 #include <limits.h>
@@ -223,18 +224,21 @@ static void               write_text_comment(pstops_doc_t *doc,
                                           const char *name, const char *value);
 
 /*
- * 'cfFilterPSToPS()' - Filter function to insert PostScript code from
+ * 'ppdFilterPSToPS()' - Filter function to insert PostScript code from
  *              PPD file (PostScript printer driver) into a 
  *              PostScript data stream
  */
 
 int                         /* O - Error status */
-cfFilterPSToPS(int inputfd,         /* I - File descriptor input stream */
+ppdFilterPSToPS(int inputfd,         /* I - File descriptor input stream */
        int outputfd,        /* I - File descriptor output stream */
        int inputseekable,   /* I - Is input stream seekable? (unused) */
        cf_filter_data_t *data, /* I - Job and printer data */
        void *parameters)    /* I - Filter-specific parameters (unused) */
 {
+  ppd_filter_data_ext_t *filter_data_ext =
+    (ppd_filter_data_ext_t *)cfFilterDataGetExt(data,
+                                               PPD_FILTER_DATA_EXT);
   pstops_doc_t doc;                    /* Document information */
   cups_file_t  *inputfp,*fp;           /* Print file */
   FILE          *outputfp;              /* Output data stream */
@@ -264,7 +268,8 @@ cfFilterPSToPS(int inputfd,         /* I - File descriptor input stream */
   * Process job options...
   */
 
-  if (set_pstops_options(&doc, data->ppd, data->job_id, data->job_user,
+  if (set_pstops_options(&doc, filter_data_ext->ppd,
+                        data->job_id, data->job_user,
                         data->job_title, data->copies,
                         data->num_options, data->options,
                         log, ld, iscanceled, icd) == 1)
@@ -280,7 +285,7 @@ cfFilterPSToPS(int inputfd,         /* I - File descriptor input stream */
      if(pipe(proc_pipe))
      {
         if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "cfFilterPSToPS: Unable to create pipe for input-page-ranges");
+                  "ppdFilterPSToPS: Unable to create pipe for input-page-ranges");
                   return (1);
      }
     if ((pstops_pid = fork()) == 0)
@@ -292,7 +297,7 @@ cfFilterPSToPS(int inputfd,         /* I - File descriptor input stream */
         if (!iscanceled || !iscanceled(icd))
         {
         if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                    "cfFilterPSToPS: Unable to open input data stream.");
+                    "ppdFilterPSToPS: Unable to open input data stream.");
         }
 
      exit (1);
@@ -356,7 +361,7 @@ cfFilterPSToPS(int inputfd,         /* I - File descriptor input stream */
     if (!iscanceled || !iscanceled(icd))
     {
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterPSToPS: Unable to open input data stream.");
+                  "ppdFilterPSToPS: Unable to open input data stream.");
     }
 
     return (1);
@@ -371,7 +376,7 @@ cfFilterPSToPS(int inputfd,         /* I - File descriptor input stream */
     if (!iscanceled || !iscanceled(icd))
     {
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterPSToPS: Unable to open output data stream.");
+                  "ppdFilterPSToPS: Unable to open output data stream.");
     }
 
     cupsFileClose(inputfp);
@@ -386,7 +391,7 @@ cfFilterPSToPS(int inputfd,         /* I - File descriptor input stream */
   if ((len = (ssize_t)cupsFileGetLine(inputfp, line, sizeof(line))) == 0)
   {
     if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "cfFilterPSToPS: The print file is empty.");
+                "ppdFilterPSToPS: The print file is empty.");
     /* Do not treat this an error, if a previous filter eliminated all
        pages the job should get dequeued without anything printed. */
     return (0);
@@ -399,14 +404,14 @@ cfFilterPSToPS(int inputfd,         /* I - File descriptor input stream */
   * Write any "exit server" options that have been selected...
   */
 
-  ppdEmit(data->ppd, outputfp, PPD_ORDER_EXIT);
+  ppdEmit(filter_data_ext->ppd, outputfp, PPD_ORDER_EXIT);
 
  /*
   * Write any JCL commands that are needed to print PostScript code...
   */
 
   if (doc.emit_jcl)
-    ppdEmitJCL(data->ppd, outputfp, doc.job_id, doc.user, doc.title);
+    ppdEmitJCL(filter_data_ext->ppd, outputfp, doc.job_id, doc.user, doc.title);
 
  /*
   * Start with a DSC header...
@@ -426,7 +431,7 @@ cfFilterPSToPS(int inputfd,         /* I - File descriptor input stream */
     */
 
     if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "cfFilterPSToPS: Skipping PJL header...");
+                "ppdFilterPSToPS: Skipping PJL header...");
 
     while (strstr(line, "ENTER LANGUAGE") == NULL && strncmp(line, "%!", 2))
       if ((len = (ssize_t)cupsFileGetLine(inputfp, line, sizeof(line))) == 0)
@@ -450,7 +455,7 @@ cfFilterPSToPS(int inputfd,         /* I - File descriptor input stream */
     * Yes, filter the document...
     */
 
-    copy_dsc(&doc, data->ppd, line, len, sizeof(line));
+    copy_dsc(&doc, filter_data_ext->ppd, line, len, sizeof(line));
   }
   else
   {
@@ -459,7 +464,7 @@ cfFilterPSToPS(int inputfd,         /* I - File descriptor input stream */
     * a single page...
     */
 
-    copy_non_dsc(&doc, data->ppd, line, len, sizeof(line));
+    copy_non_dsc(&doc, filter_data_ext->ppd, line, len, sizeof(line));
   }
 
  /*
@@ -475,8 +480,8 @@ cfFilterPSToPS(int inputfd,         /* I - File descriptor input stream */
 
   if (doc.emit_jcl)
   {
-    if (data->ppd && data->ppd->jcl_end)
-      ppdEmitJCLEnd(data->ppd, doc.outputfp);
+    if (filter_data_ext->ppd && filter_data_ext->ppd->jcl_end)
+      ppdEmitJCLEnd(filter_data_ext->ppd, doc.outputfp);
     else
       doc_putc(&doc, 0x04);
   }
@@ -513,7 +518,7 @@ cfFilterPSToPS(int inputfd,         /* I - File descriptor input stream */
           if (errno == EINTR)
             goto retry_wait;
           if (log) log(ld, CF_LOGLEVEL_ERROR,
-          "cfFilterPSToPS: Error while waiting for input_page_ranges to finish - %s.",
+          "ppdFilterPSToPS: Error while waiting for input_page_ranges to finish - %s.",
           strerror(errno));
         }
         /* How did the sub-process terminate */
@@ -521,18 +526,18 @@ cfFilterPSToPS(int inputfd,         /* I - File descriptor input stream */
       if (WIFEXITED(childStatus)) {
        /* Via exit() anywhere or return() in the main() function */
        if (log) log(ld, CF_LOGLEVEL_ERROR,
-                    "cfFilterPSToPS: input-page-ranges filter (PID %d) stopped with status %d",
+                    "ppdFilterPSToPS: input-page-ranges filter (PID %d) stopped with status %d",
                     pstops_pid, WEXITSTATUS(childStatus));
       } else {
        /* Via signal */
        if (log) log(ld, CF_LOGLEVEL_ERROR,
-                    "cfFilterPSToPS: imput-page-ranges filter (PID %d) crashed on signal %d",
+                    "ppdFilterPSToPS: imput-page-ranges filter (PID %d) crashed on signal %d",
                     pstops_pid, WTERMSIG(childStatus));
       }
       status=1;
     } else {
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterPSToPS: input-page-ranges-filter (PID %d) exited with no errors.",
+                  "ppdFilterPSToPS: input-page-ranges-filter (PID %d) exited with no errors.",
                   pstops_pid);
     }
   }
@@ -548,12 +553,12 @@ cfFilterPSToPS(int inputfd,         /* I - File descriptor input stream */
 
 
 /*
- * 'cfFilterImageToPS()' - Filter function to convert many common image file
+ * 'ppdFilterImageToPS()' - Filter function to convert many common image file
  *                 formats into PostScript
  */
 
 int                                       /* O - Error status */
-cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
+ppdFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
                  int outputfd,           /* I - File descriptor output stream*/
                  int inputseekable,      /* I - Is input stream seekable?
                                             (unused) */
@@ -561,6 +566,9 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
                  void *parameters)       /* I - Filter-specific parameters
                                             (unused) */
 {
+  ppd_filter_data_ext_t *filter_data_ext =
+    (ppd_filter_data_ext_t *)cfFilterDataGetExt(data,
+                                               PPD_FILTER_DATA_EXT);
   pstops_doc_t doc;                    /* Document information */
   cf_image_t   *img;                   /* Image to print */
   float                xprint,                 /* Printable area */
@@ -616,6 +624,7 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
   int           fd;                    /* File descriptor for temp file */
   char          buf[BUFSIZ];
   int           bytes;
+  cups_cspace_t cspace = (cups_cspace_t)(-1);
   cf_logfunc_t log = data->logfunc;
   void          *ld = data->logdata;
   cf_filter_iscanceledfunc_t iscanceled = data->iscanceledfunc;
@@ -659,7 +668,7 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
     if (!iscanceled || !iscanceled(icd))
     {
       if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "cfFilterImageToPS: Unable to open input data stream.");
+                  "ppdFilterImageToPS: Unable to open input data stream.");
     }
 
     return (1);
@@ -673,13 +682,13 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
     if ((fd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
     {
       if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "cfFilterImageToPS: Unable to copy input: %s",
+                  "ppdFilterImageToPS: Unable to copy input: %s",
                   strerror(errno));
       return (1);
     }
 
     if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "cfFilterImageToPS: Copying input to temp file \"%s\"",
+                "ppdFilterImageToPS: Copying input to temp file \"%s\"",
                 tempfile);
 
     while ((bytes = fread(buf, 1, sizeof(buf), inputfp)) > 0)
@@ -697,7 +706,7 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
       if (!iscanceled || !iscanceled(icd))
       {
        if (log) log(ld, CF_LOGLEVEL_ERROR,
-                    "cfFilterImageToPS: Unable to open temporary file.");
+                    "ppdFilterImageToPS: Unable to open temporary file.");
       }
 
       unlink(tempfile);
@@ -714,7 +723,7 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
     if (!iscanceled || !iscanceled(icd))
     {
       if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "cfFilterImageToPS: Unable to open output data stream.");
+                  "ppdFilterImageToPS: Unable to open output data stream.");
     }
 
     fclose(inputfp);
@@ -749,8 +758,8 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
   * Process job options...
   */
 
-  ppd = data->ppd;
-  cfFilterSetCommonOptions(ppd, num_options, options, 0,
+  ppd = filter_data_ext->ppd;
+  ppdFilterSetCommonOptions(ppd, num_options, options, 0,
                         &doc.Orientation, &doc.Duplex,
                         &doc.LanguageLevel, &doc.Color,
                         &doc.PageLeft, &doc.PageRight,
@@ -758,10 +767,11 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
                         &doc.PageWidth, &doc.PageLength,
                         log, ld);
 
-  /* The cfFilterSetCommonOptions() does not set doc.Color
+  /* The ppdFilterSetCommonOptions() does not set doc.Color
      according to option settings (user's demand for color/gray),
      so we parse the options and set the mode here */
-  cfRasterParseIPPOptions(&h, data, 0, 1);
+  cfRasterPrepareHeader(&h, data, CF_FILTER_OUT_FORMAT_CUPS_RASTER,
+                       CF_FILTER_OUT_FORMAT_CUPS_RASTER, 0, &cspace);
   if (doc.Color)
     doc.Color = h.cupsNumColors <= 1 ? 0 : 1;
   if (!ppd) {
@@ -1126,7 +1136,7 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
   if (img == NULL)
   {
     if (log) log(ld, CF_LOGLEVEL_ERROR,
-                "cfFilterImageToPS: The print file could not be opened - %s",
+                "ppdFilterImageToPS: The print file could not be opened - %s",
                 strerror(errno));
     return (1);
   }
@@ -1147,7 +1157,7 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
     yppi = xppi;
 
   if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "cfFilterImageToPS: Before scaling: xppi=%d, yppi=%d, zoom=%.2f",
+              "ppdFilterImageToPS: Before scaling: xppi=%d, yppi=%d, zoom=%.2f",
               xppi, yppi, zoom);
 
   if (xppi > 0)
@@ -1168,14 +1178,14 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
     }
 
     if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "cfFilterImageToPS: Before scaling: xprint=%.1f, yprint=%.1f",
+                "ppdFilterImageToPS: Before scaling: xprint=%.1f, yprint=%.1f",
                 xprint, yprint);
 
     xinches = (float)cfImageGetWidth(img) / (float)xppi;
     yinches = (float)cfImageGetHeight(img) / (float)yppi;
 
     if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "cfFilterImageToPS: Image size is %.1f x %.1f inches...",
+                "ppdFilterImageToPS: Image size is %.1f x %.1f inches...",
                 xinches, yinches);
 
     if ((val = cupsGetOption("natural-scaling", num_options, options)) != NULL)
@@ -1192,7 +1202,7 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
       */
 
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterImageToPS: Auto orientation...");
+                  "ppdFilterImageToPS: Auto orientation...");
 
       if ((xinches > xprint || yinches > yprint) &&
           xinches <= yprint && yinches <= xprint)
@@ -1202,7 +1212,7 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
        */
 
        if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                    "cfFilterImageToPS: Using landscape orientation...");
+                    "ppdFilterImageToPS: Using landscape orientation...");
 
        doc.Orientation = (doc.Orientation + 1) & 3;
        xsize       = yprint;
@@ -1222,11 +1232,11 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
     aspect = (float)cfImageGetYPPI(img) / (float)cfImageGetXPPI(img);
 
     if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "cfFilterImageToPS: Before scaling: xprint=%.1f, yprint=%.1f",
+                "ppdFilterImageToPS: Before scaling: xprint=%.1f, yprint=%.1f",
                 xprint, yprint);
 
     if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "cfFilterImageToPS: cfImageGetXPPI(img) = %d, "
+                "ppdFilterImageToPS: cfImageGetXPPI(img) = %d, "
                 "cfImageGetYPPI(img) = %d, aspect = %f",
                 cfImageGetXPPI(img), cfImageGetYPPI(img), aspect);
 
@@ -1252,10 +1262,10 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
     }
 
     if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "cfFilterImageToPS: Portrait size is %.2f x %.2f inches",
+                "ppdFilterImageToPS: Portrait size is %.2f x %.2f inches",
                 xsize, ysize);
     if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "cfFilterImageToPS: Landscape size is %.2f x %.2f inches",
+                "ppdFilterImageToPS: Landscape size is %.2f x %.2f inches",
                 xsize2, ysize2);
 
     if (cupsGetOption("orientation-requested", num_options, options) == NULL &&
@@ -1267,7 +1277,7 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
       */
 
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterImageToPS: Auto orientation...");
+                  "ppdFilterImageToPS: Auto orientation...");
 
       if ((xsize * ysize) < (xsize2 * xsize2))
       {
@@ -1276,7 +1286,7 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
        */
 
        if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                    "cfFilterImageToPS: Using landscape orientation...");
+                    "ppdFilterImageToPS: Using landscape orientation...");
 
        doc.Orientation = 1;
        xinches     = xsize2;
@@ -1291,7 +1301,7 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
        */
 
        if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                    "cfFilterImageToPS: Using portrait orientation...");
+                    "ppdFilterImageToPS: Using portrait orientation...");
 
        doc.Orientation = 0;
        xinches     = xsize;
@@ -1301,7 +1311,7 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
     else if (doc.Orientation & 1)
     {
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterImageToPS: Using landscape orientation...");
+                  "ppdFilterImageToPS: Using landscape orientation...");
 
       xinches     = xsize2;
       yinches     = ysize2;
@@ -1311,7 +1321,7 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
     else
     {
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterImageToPS: Using portrait orientation...");
+                  "ppdFilterImageToPS: Using portrait orientation...");
 
       xinches     = xsize;
       yinches     = ysize;
@@ -1332,7 +1342,7 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
   yprint = yinches / ypages;
 
   if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "cfFilterImageToPS: xpages = %dx%.2fin, ypages = %dx%.2fin",
+              "ppdFilterImageToPS: xpages = %dx%.2fin, ypages = %dx%.2fin",
               xpages, xprint, ypages, yprint);
 
  /*
@@ -1380,7 +1390,7 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
       length = ppd->custom_min[1];
 
     if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "cfFilterImageToPS: Updated custom page size to %.2f x %.2f inches...",
+                "ppdFilterImageToPS: Updated custom page size to %.2f x %.2f inches...",
                 width / 72.0, length / 72.0);
 
    /*
@@ -1524,7 +1534,7 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
   if (row == NULL)
   {
     log(ld, CF_LOGLEVEL_ERROR,
-       "cfFilterImageToPS: Could not allocate memory.");
+       "ppdFilterImageToPS: Could not allocate memory.");
     cfImageClose(img);
     return (2);
   }
@@ -1532,15 +1542,15 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
   if (log)
   {
     log(ld, CF_LOGLEVEL_DEBUG,
-       "cfFilterImageToPS: XPosition=%d, YPosition=%d, Orientation=%d",
+       "ppdFilterImageToPS: XPosition=%d, YPosition=%d, Orientation=%d",
        XPosition, YPosition, doc.Orientation);
     log(ld, CF_LOGLEVEL_DEBUG,
-       "cfFilterImageToPS: xprint=%.1f, yprint=%.1f", xprint, yprint);
+       "ppdFilterImageToPS: xprint=%.1f, yprint=%.1f", xprint, yprint);
     log(ld, CF_LOGLEVEL_DEBUG,
-       "cfFilterImageToPS: PageLeft=%.0f, PageRight=%.0f, PageWidth=%.0f",
+       "ppdFilterImageToPS: PageLeft=%.0f, PageRight=%.0f, PageWidth=%.0f",
        doc.PageLeft, doc.PageRight, doc.PageWidth);
     log(ld, CF_LOGLEVEL_DEBUG,
-       "cfFilterImageToPS: PageBottom=%.0f, PageTop=%.0f, PageLength=%.0f",
+       "ppdFilterImageToPS: PageBottom=%.0f, PageTop=%.0f, PageLength=%.0f",
        doc.PageBottom, doc.PageTop, doc.PageLength);
   }
 
@@ -1660,7 +1670,7 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
   }
 
   if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "cfFilterImageToPS: left=%.2f, top=%.2f", left, top);
+              "ppdFilterImageToPS: left=%.2f, top=%.2f", left, top);
 
   for (page = 1; Copies > 0; Copies --)
     for (xpage = 0; xpage < xpages; xpage ++)
@@ -1669,7 +1679,7 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
        if (iscanceled && iscanceled(icd))
        {
          if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                      "cfFilterImageToPS: Job canceled");
+                      "ppdFilterImageToPS: Job canceled");
          goto canceled;
        }
 
@@ -1678,7 +1688,7 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
              "PAGE: %d %d", page, realcopies);
 
        if (log) log(ld, CF_LOGLEVEL_INFO,
-                    "cfFilterImageToPS: Printing page %d.", page);
+                    "ppdFilterImageToPS: Printing page %d.", page);
 
         doc_printf(&doc, "%%%%Page: %d %d\n", page, page);
 
@@ -1821,7 +1831,7 @@ cfFilterImageToPS(int inputfd,            /* I - File descriptor input stream */
   }
 
   if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "cfFilterImageToPS: Printing completed.", page);
+              "ppdFilterImageToPS: Printing completed.", page);
 
  /*
   * Close files...
@@ -1854,14 +1864,14 @@ add_page(pstops_doc_t *doc,             /* I - Document information */
   if (!doc->pages)
   {
     if (log) log(ld, CF_LOGLEVEL_ERROR,
-                "cfFilterPSToPS: Unable to allocate memory for pages array");
+                "ppdFilterPSToPS: Unable to allocate memory for pages array");
     return (NULL);
   }
 
   if ((pageinfo = calloc(1, sizeof(pstops_page_t))) == NULL)
   {
     if (log) log(ld, CF_LOGLEVEL_ERROR,
-                "cfFilterPSToPS: Unable to allocate memory for page info");
+                "ppdFilterPSToPS: Unable to allocate memory for page info");
     return (NULL);
   }
 
@@ -2037,7 +2047,7 @@ copy_comments(pstops_doc_t *doc,  /* I - Document info */
     */
 
     if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "cfFilterPSToPS: %s", line);
+                "ppdFilterPSToPS: %s", line);
 
    /*
     * Pull the headers out...
@@ -2049,7 +2059,7 @@ copy_comments(pstops_doc_t *doc,  /* I - Document info */
 
       if (saw_pages && log)
        log(ld, CF_LOGLEVEL_DEBUG,
-           "cfFilterPSToPS: A duplicate %%Pages: comment was seen.");
+           "ppdFilterPSToPS: A duplicate %%Pages: comment was seen.");
 
       saw_pages = 1;
 
@@ -2104,7 +2114,7 @@ copy_comments(pstops_doc_t *doc,  /* I - Document info */
       if (saw_bounding_box)
       {
        if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                    "cfFilterPSToPS: A duplicate %%BoundingBox: comment was seen.");
+                    "ppdFilterPSToPS: A duplicate %%BoundingBox: comment was seen.");
       }
       else if (strstr(line + 14, "(atend)"))
       {
@@ -2117,7 +2127,7 @@ copy_comments(pstops_doc_t *doc,  /* I - Document info */
                      doc->bounding_box + 3) != 4)
       {
        if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                    "cfFilterPSToPS: A bad %%BoundingBox: comment was seen.");
+                    "ppdFilterPSToPS: A bad %%BoundingBox: comment was seen.");
 
        doc->bounding_box[0] = (int)(doc->PageLeft);
        doc->bounding_box[1] = (int)(doc->PageBottom);
@@ -2152,7 +2162,7 @@ copy_comments(pstops_doc_t *doc,  /* I - Document info */
        */
 
        doc->Orientation = (4 - doc->Orientation + orient) & 3;
-       cfFilterUpdatePageVars(doc->Orientation,
+       ppdFilterUpdatePageVars(doc->Orientation,
                             &doc->PageLeft, &doc->PageRight,
                             &doc->PageTop, &doc->PageBottom,
                             &doc->PageWidth, &doc->PageLength);
@@ -2173,11 +2183,11 @@ copy_comments(pstops_doc_t *doc,        /* I - Document info */
 
   if (!saw_bounding_box && log)
     log(ld, CF_LOGLEVEL_DEBUG,
-       "cfFilterPSToPS: There wasn't a %%BoundingBox: comment in the header.");
+       "ppdFilterPSToPS: There wasn't a %%BoundingBox: comment in the header.");
 
   if (!saw_pages && log)
     log(ld, CF_LOGLEVEL_DEBUG,
-       "cfFilterPSToPS: There wasn't a %%Pages: comment in the header.");
+       "ppdFilterPSToPS: There wasn't a %%Pages: comment in the header.");
 
   if (!saw_for)
     write_text_comment(doc, "For", doc->user);
@@ -2262,7 +2272,7 @@ copy_dsc(pstops_doc_t *doc,               /* I - Document info */
   */
 
   if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "cfFilterPSToPS: Before copy_comments - %s", line);
+              "ppdFilterPSToPS: Before copy_comments - %s", line);
   linelen = copy_comments(doc, ppd, line, linelen, linesize);
 
  /*
@@ -2270,7 +2280,7 @@ copy_dsc(pstops_doc_t *doc,               /* I - Document info */
   */
 
   if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "cfFilterPSToPS: Before copy_prolog - %s", line);
+              "ppdFilterPSToPS: Before copy_prolog - %s", line);
   linelen = copy_prolog(doc, ppd, line, linelen, linesize);
 
  /*
@@ -2278,7 +2288,7 @@ copy_dsc(pstops_doc_t *doc,               /* I - Document info */
   */
 
   if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "cfFilterPSToPS: Before copy_setup - %s", line);
+              "ppdFilterPSToPS: Before copy_setup - %s", line);
   linelen = copy_setup(doc, ppd, line, linelen, linesize);
 
  /*
@@ -2300,13 +2310,13 @@ copy_dsc(pstops_doc_t *doc,             /* I - Document info */
   number = 0;
 
   if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "cfFilterPSToPS: Before page loop - %s", line);
+              "ppdFilterPSToPS: Before page loop - %s", line);
   while (!strncmp(line, "%%Page:", 7))
   {
     if (iscanceled && iscanceled(icd))
     {
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterPSToPS: Job canceled");
+                  "ppdFilterPSToPS: Job canceled");
       break;
     }
 
@@ -2315,13 +2325,13 @@ copy_dsc(pstops_doc_t *doc,             /* I - Document info */
     if (check_range((number - 1) / doc->number_up + 1,doc->page_ranges,doc->page_set))
     {
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterPSToPS: Copying page %d...", number);
+                  "ppdFilterPSToPS: Copying page %d...", number);
       linelen = copy_page(doc, ppd, number, line, linelen, linesize);
     }
     else
     {
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterPSToPS: Skipping page %d...", number);
+                  "ppdFilterPSToPS: Skipping page %d...", number);
       linelen = skip_page(doc, line, linelen, linesize);
     }
   }
@@ -2403,7 +2413,7 @@ copy_dsc(pstops_doc_t *doc,               /* I - Document info */
       if (iscanceled && iscanceled(icd))
       {
        if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                    "cfFilterPSToPS: Job canceled");
+                    "ppdFilterPSToPS: Job canceled");
        break;
       }
 
@@ -2464,7 +2474,7 @@ copy_dsc(pstops_doc_t *doc,               /* I - Document info */
        if (iscanceled && iscanceled(icd))
          {
            if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                        "cfFilterPSToPS: Job canceled");
+                        "ppdFilterPSToPS: Job canceled");
            break;
          }
 
@@ -2544,7 +2554,7 @@ copy_non_dsc(pstops_doc_t *doc,           /* I - Document info */
   */
 
   if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "cfFilterPSToPS: This document does not conform to the Adobe Document "
+              "ppdFilterPSToPS: This document does not conform to the Adobe Document "
               "Structuring Conventions and may not print correctly.");
 
  /*
@@ -2671,7 +2681,7 @@ copy_non_dsc(pstops_doc_t *doc,           /* I - Document info */
       if (iscanceled && iscanceled(icd))
       {
        if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                    "cfFilterPSToPS: Job canceled");
+                    "ppdFilterPSToPS: Job canceled");
        break;
       }
 
@@ -2742,14 +2752,14 @@ copy_page(pstops_doc_t *doc,            /* I - Document info */
   if (!parse_text(line + 7, &ptr, label, sizeof(label)))
   {
     if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "cfFilterPSToPS: There was a bad %%Page: comment in the file.");
+                "ppdFilterPSToPS: There was a bad %%Page: comment in the file.");
     label[0] = '\0';
     number   = doc->page;
   }
   else if (strtol(ptr, &ptr, 10) == LONG_MAX || !isspace(*ptr & 255))
   {
     if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "cfFilterPSToPS: There was a bad %%Page: comment in the file.");
+                "ppdFilterPSToPS: There was a bad %%Page: comment in the file.");
     number = doc->page;
   }
 
@@ -2850,7 +2860,7 @@ copy_page(pstops_doc_t *doc,              /* I - Document info */
       {
        if (log)
          log(ld, CF_LOGLEVEL_DEBUG,
-             "cfFilterPSToPS: There was a bad %%PageBoundingBox: comment in the "
+             "ppdFilterPSToPS: There was a bad %%PageBoundingBox: comment in the "
              "file.");
         memcpy(bounding_box, doc->bounding_box,
               sizeof(bounding_box));
@@ -2865,13 +2875,13 @@ copy_page(pstops_doc_t *doc,            /* I - Document info */
        if (log)
        {
          log(ld, CF_LOGLEVEL_DEBUG,
-             "cfFilterPSToPS: Orientation = %d", doc->Orientation);
+             "ppdFilterPSToPS: Orientation = %d", doc->Orientation);
          log(ld, CF_LOGLEVEL_DEBUG,
-             "cfFilterPSToPS: original bounding_box = [ %d %d %d %d ]",
+             "ppdFilterPSToPS: original bounding_box = [ %d %d %d %d ]",
              bounding_box[0], bounding_box[1],
              bounding_box[2], bounding_box[3]);
          log(ld, CF_LOGLEVEL_DEBUG,
-             "cfFilterPSToPS: PageWidth = %.1f, PageLength = %.1f",
+             "ppdFilterPSToPS: PageWidth = %.1f, PageLength = %.1f",
              doc->PageWidth, doc->PageLength);
        }
 
@@ -2900,7 +2910,7 @@ copy_page(pstops_doc_t *doc,              /* I - Document info */
        }
 
        if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                    "cfFilterPSToPS: updated bounding_box = [ %d %d %d %d ]",
+                    "ppdFilterPSToPS: updated bounding_box = [ %d %d %d %d ]",
                     bounding_box[0], bounding_box[1],
                     bounding_box[2], bounding_box[3]);
       }
@@ -3158,7 +3168,7 @@ copy_page(pstops_doc_t *doc,              /* I - Document info */
          line[0] = '\0';
          if (log)
            log(ld, CF_LOGLEVEL_ERROR,
-               "cfFilterPSToPS: Early end-of-file while reading binary data: %s",
+               "ppdFilterPSToPS: Early end-of-file while reading binary data: %s",
                strerror(errno));
          return (0);
        }
@@ -3236,7 +3246,7 @@ copy_prolog(pstops_doc_t *doc,            /* I - Document info */
       linelen = (ssize_t)cupsFileGetLine(doc->inputfp, line, linesize);
     else
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterPSToPS: The %%EndProlog comment is missing.");
+                  "ppdFilterPSToPS: The %%EndProlog comment is missing.");
   }
 
   doc_puts(doc, "%%EndProlog\n");
@@ -3310,7 +3320,7 @@ copy_setup(pstops_doc_t *doc,             /* I - Document info */
       linelen = (ssize_t)cupsFileGetLine(doc->inputfp, line, linesize);
     else
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterPSToPS: The %%EndSetup comment is missing.");
+                  "ppdFilterPSToPS: The %%EndSetup comment is missing.");
   }
 
   if (num_options > 0)
@@ -3365,7 +3375,7 @@ copy_trailer(pstops_doc_t *doc,           /* I - Document info */
   }
 
   if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "cfFilterPSToPS: Wrote %d pages...", number);
+              "ppdFilterPSToPS: Wrote %d pages...", number);
 
   doc_printf(doc, "%%%%Pages: %d\n", number);
   if (doc->number_up > 1 || doc->fit_to_page)
@@ -3537,7 +3547,7 @@ doc_printf(pstops_doc_t *doc,             /* I - Document information */
   if ((size_t)bytes > sizeof(buffer))
   {
     if (log) log(ld, CF_LOGLEVEL_ERROR,
-                "cfFilterPSToPS: Buffer overflow detected, truncating.");
+                "ppdFilterPSToPS: Buffer overflow detected, truncating.");
     bytes = sizeof(buffer);
   }
 
@@ -3687,7 +3697,7 @@ include_feature(
   if (sscanf(line + 17, "%254s%254s", name, value) != 2)
   {
     if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "cfFilterPSToPS: The %%IncludeFeature: comment is not valid.");
+                "ppdFilterPSToPS: The %%IncludeFeature: comment is not valid.");
     return (num_options);
   }
 
@@ -3698,7 +3708,7 @@ include_feature(
   if ((option = ppdFindOption(ppd, name + 1)) == NULL)
   {
     if (log) log(ld, CF_LOGLEVEL_WARN,
-                "cfFilterPSToPS: Unknown option \"%s\".", name + 1);
+                "ppdFilterPSToPS: Unknown option \"%s\".", name + 1);
     return (num_options);
   }
 
@@ -3706,7 +3716,7 @@ include_feature(
       option->section == PPD_ORDER_JCL)
   {
     if (log) log(ld, CF_LOGLEVEL_WARN,
-                "cfFilterPSToPS: Option \"%s\" cannot be included via "
+                "ppdFilterPSToPS: Option \"%s\" cannot be included via "
                 "%%%%IncludeFeature.", name + 1);
     return (num_options);
   }
@@ -3714,7 +3724,7 @@ include_feature(
   if (!ppdFindChoice(option, value))
   {
     if (log) log(ld, CF_LOGLEVEL_WARN,
-                "cfFilterPSToPS: Unknown choice \"%s\" for option \"%s\".",
+                "ppdFilterPSToPS: Unknown choice \"%s\" for option \"%s\".",
                 value, name + 1);
     return (num_options);
   }
@@ -3996,7 +4006,7 @@ set_pstops_options(
   doc->iscanceleddata = icd;
 
   /* Set some common values */
-  cfFilterSetCommonOptions(ppd, num_options, options, 1,
+  ppdFilterSetCommonOptions(ppd, num_options, options, 1,
                         &doc->Orientation, &doc->Duplex,
                         &doc->LanguageLevel, &doc->Color,
                         &doc->PageLeft, &doc->PageRight,
@@ -4136,7 +4146,7 @@ set_pstops_options(
          break;
       default :
          if (log) log(ld, CF_LOGLEVEL_ERROR,
-                      "cfFilterPSToPS: Unsupported number-up value %d, using "
+                      "ppdFilterPSToPS: Unsupported number-up value %d, using "
                       "number-up=1.", intval);
           doc->number_up = 1;
          break;
@@ -4170,7 +4180,7 @@ set_pstops_options(
     else
     {
       if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "cfFilterPSToPS: Unsupported number-up-layout value %s, using "
+                  "ppdFilterPSToPS: Unsupported number-up-layout value %s, using "
                   "number-up-layout=lrtb.", val);
       doc->number_up_layout = PSTOPS_LAYOUT_LRTB;
     }
@@ -4221,7 +4231,7 @@ set_pstops_options(
     else
     {
       if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "cfFilterPSToPS: Unsupported page-border value %s, using "
+                  "ppdFilterPSToPS: Unsupported page-border value %s, using "
                   "page-border=none.", val);
       doc->page_border = PSTOPS_BORDERNONE;
     }
@@ -4333,7 +4343,7 @@ set_pstops_options(
                                    sizeof(doc->tempfile))) == NULL)
     {
       if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "cfFilterPSToPS: Unable to create temporary file: %s",
+                  "ppdFilterPSToPS: Unable to create temporary file: %s",
                   strerror(errno));
       return (1);
     }
@@ -4354,7 +4364,7 @@ set_pstops_options(
   }
 
   if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "cfFilterPSToPS: slow_collate=%d, slow_duplex=%d, slow_order=%d",
+              "ppdFilterPSToPS: slow_collate=%d, slow_duplex=%d, slow_order=%d",
               doc->slow_collate, doc->slow_duplex, doc->slow_order);
 
   return(0);
@@ -4413,7 +4423,7 @@ skip_page(pstops_doc_t *doc,              /* I - Document information */
          line[0] = '\0';
          if (log)
            log(ld, CF_LOGLEVEL_ERROR,
-               "cfFilterPSToPS: Early end-of-file while reading binary data: %s",
+               "ppdFilterPSToPS: Early end-of-file while reading binary data: %s",
                strerror(errno));
          return (0);
        }
@@ -4477,18 +4487,18 @@ start_nup(pstops_doc_t *doc,            /* I - Document information */
   if (log)
   {
     log(ld, CF_LOGLEVEL_DEBUG,
-       "cfFilterPSToPS: pagew = %.1f, pagel = %.1f", pagew, pagel);
+       "ppdFilterPSToPS: pagew = %.1f, pagel = %.1f", pagew, pagel);
     log(ld, CF_LOGLEVEL_DEBUG,
-       "cfFilterPSToPS: bboxx = %d, bboxy = %d, bboxw = %d, bboxl = %d",
+       "ppdFilterPSToPS: bboxx = %d, bboxy = %d, bboxw = %d, bboxl = %d",
        bboxx, bboxy, bboxw, bboxl);
     log(ld, CF_LOGLEVEL_DEBUG,
-       "cfFilterPSToPS: PageLeft = %.1f, PageRight = %.1f",
+       "ppdFilterPSToPS: PageLeft = %.1f, PageRight = %.1f",
        doc->PageLeft, doc->PageRight);
     log(ld, CF_LOGLEVEL_DEBUG,
-       "cfFilterPSToPS: PageTop = %.1f, PageBottom = %.1f",
+       "ppdFilterPSToPS: PageTop = %.1f, PageBottom = %.1f",
        doc->PageTop, doc->PageBottom);
     log(ld, CF_LOGLEVEL_DEBUG,
-       "cfFilterPSToPS: PageWidth = %.1f, PageLength = %.1f",
+       "ppdFilterPSToPS: PageWidth = %.1f, PageLength = %.1f",
        doc->PageWidth, doc->PageLength);
   }
 
similarity index 91%
rename from cupsfilters/pdftops.c
rename to ppd/pdftops.c
index 55497be63e18cabd43b18bdd89924deddc242f7f..afdf81c534332f1a0002c89acb6d31b7419e09af 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * PDF-to-PostScript filter function for cups-filters.
+ * PDF-to-PostScript filter function for libppd.
  *
  * Copyright 2011-2020 by Till Kamppeter
  * Copyright 2007-2011 by Apple Inc.
  *   parsePDFTOPDFComment() - Check whether we are executed after pdftopdf
  *   remove_options()       - Remove unwished entries from an option list
  *   log_command_line()     - Log the command line of a program which we call
- *   cfFilterPDFToPS()              - pdftops filter function
+ *   ppdFilterPDFToPS()              - pdftops filter function
  */
 
 /*
  * Include necessary headers...
  */
 
-#include "filter.h"
-#include "raster.h"
-#include "pdf.h"
 #include <config.h>
 #include <cups/cups.h>
-#include <ppd/ppd.h>
 #include <cups/file.h>
 #include <signal.h>
 #include <sys/wait.h>
 #include <string.h>
 #include <ctype.h>
 #include <cupsfilters/filter.h>
+#include <cupsfilters/raster.h>
+#include <cupsfilters/pdf.h>
 #include <cupsfilters/image-private.h>
+#include "ppd.h"
+#include "ppd-filter.h"
 
 #define MAX_CHECK_COMMENT_LINES        20
 
@@ -67,7 +67,7 @@ const char *pstops_exclude_general[] = {
 const char *pstops_exclude_page_management[] = {
   "brightness",
   "Collate",
-  "cupsEvenDuplex",
+  "even-duplex",
   "gamma",
   "hue",
   "ipp-attribute-fidelity",
@@ -118,7 +118,7 @@ parse_pdftopdf_comment(char *filename,       /* I - Input file */
 
   if ((fp = fopen(filename,"rb")) == NULL) {
     if (log) log(ld, CF_LOGLEVEL_ERROR,
-                "cfFilterPDFToPS: Cannot open input file \"%s\"",
+                "ppdFilterPDFToPS: Cannot open input file \"%s\"",
                 filename);
     return;
   }
@@ -176,7 +176,7 @@ is_empty(char *filename,       /* I - Input file */
   if (fp == NULL)
   {
     if (log) log(ld, CF_LOGLEVEL_ERROR,
-                "cfFilterPDFToPS: Cannot open input file \"%s\"",
+                "ppdFilterPDFToPS: Cannot open input file \"%s\"",
                 filename);
     return 1;
   }
@@ -187,14 +187,14 @@ is_empty(char *filename,       /* I - Input file */
     if (fread(buf, 1, 1, fp) == 0) {
       fclose(fp);
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterPDFToPS: Input is empty, outputting empty file.");
+                  "ppdFilterPDFToPS: Input is empty, outputting empty file.");
       return 1;
     }
     fclose(fp);
     int pages = cfPDFPages(filename);
     if (pages == 0) {
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterPDFToPS: No pages left, outputting empty file.");
+                  "ppdFilterPDFToPS: No pages left, outputting empty file.");
       return 1;
     }
     if (pages > 0)
@@ -223,7 +223,7 @@ log_command_line(const char* file,     /* I - Program to be executed */
     return;
 
   /* Debug output: Full command line of program to be called */
-  snprintf(buf, sizeof(buf) - 1, "cfFilterPDFToPS: Running command line for %s:",
+  snprintf(buf, sizeof(buf) - 1, "ppdFilterPDFToPS: Running command line for %s:",
           (file ? file : argv[0]));
   if (file)
     snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf) - 1,
@@ -243,17 +243,20 @@ log_command_line(const char* file,     /* I - Program to be executed */
 
 
 /*
- * 'cfFilterPDFToPS()' - Filter function to convert PDF input into
+ * 'ppdFilterPDFToPS()' - Filter function to convert PDF input into
  *               PostScript to be printed on PostScript printers
  */
 
 int                          /* O - Error status */
-cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
+ppdFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
        int outputfd,        /* I - File descriptor output stream */
        int inputseekable,   /* I - Is input stream seekable? (unused) */
        cf_filter_data_t *data, /* I - Job and printer data */
        void *parameters)    /* I - Filter-specific parameters (unused) */
 {
+  ppd_filter_data_ext_t *filter_data_ext =
+    (ppd_filter_data_ext_t *)cfFilterDataGetExt(data,
+                                               PPD_FILTER_DATA_EXT);
   renderer_t    renderer = CUPS_PDFTOPS_RENDERER; /* Renderer: gs or pdftops
                                                     or acroread or pdftocairo
                                                     or hybrid */
@@ -304,6 +307,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
                *ptr;                   /* Pointer into value */
   int          duplex, tumble;         /* Duplex settings for PPD-less
                                           printing */
+  cups_cspace_t cspace = (cups_cspace_t)(-1);
   cf_logfunc_t log = data->logfunc;
   void          *ld = data->logdata;
   cf_filter_iscanceledfunc_t iscanceled = data->iscanceledfunc;
@@ -331,7 +335,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
     if (!iscanceled || !iscanceled(icd))
     {
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterPDFToPS: Unable to open input data stream.");
+                  "ppdFilterPDFToPS: Unable to open input data stream.");
     }
 
     return (1);
@@ -344,12 +348,12 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
   if ((fd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
   {
     if (log) log(ld, CF_LOGLEVEL_ERROR,
-                "cfFilterPDFToPS: Unable to copy PDF file: %s", strerror(errno));
+                "ppdFilterPDFToPS: Unable to copy PDF file: %s", strerror(errno));
     return (1);
   }
 
   if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "cfFilterPDFToPS: Copying input to temp file \"%s\"",
+              "ppdFilterPDFToPS: Copying input to temp file \"%s\"",
               tempfile);
 
   while ((bytes = fread(buffer, 1, sizeof(buffer), inputfp)) > 0)
@@ -389,7 +393,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
   num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
   
 
-  ppd = data->ppd;
+  ppd = filter_data_ext->ppd;
 
  /*
   * Process job options...
@@ -427,7 +431,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
     make_model[strlen(make_model) - 1] = '\0';
   }
   if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "cfFilterPDFToPS: Printer make and model: %s", make_model);
+              "ppdFilterPDFToPS: Printer make and model: %s", make_model);
 
  /*
   * Select the PDF renderer: Ghostscript (gs), Poppler (pdftops),
@@ -452,7 +456,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
       renderer = HYBRID;
     else
       if (log) log(ld, CF_LOGLEVEL_WARN,
-                  "cfFilterPDFToPS: Invalid value for \"pdftops-renderer\": \"%s\"",
+                  "ppdFilterPDFToPS: Invalid value for \"pdftops-renderer\": \"%s\"",
                   val);
   }
 
@@ -466,7 +470,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
          (ptr = strcasestr(make_model, "LaserWriter")))))
     {
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterPDFToPS: Switching to Poppler's pdftops instead of "
+                  "ppdFilterPDFToPS: Switching to Poppler's pdftops instead of "
                   "Ghostscript for Brother, Minolta, Konica Minolta, Dell, "
                   "and Apple LaserWriter printers to work around bugs in the "
                   "printer's PS interpreters");
@@ -496,7 +500,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
          if (!*ptr) /* End of string, no further word */
          {
            if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                        "cfFilterPDFToPS: Switching to Poppler's pdftops instead of "
+                        "ppdFilterPDFToPS: Switching to Poppler's pdftops instead of "
                         "Ghostscript for old HP LaserJet (\"LaserJet "
                         "<number>\", no letters before <number>, no "
                         "additional words after <number>) printers to "
@@ -561,8 +565,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
   pstops_filter_data.printer_attrs = NULL;
   pstops_filter_data.num_options = num_pstops_options;
   pstops_filter_data.options = pstops_options;
-  pstops_filter_data.ppdfile = NULL;
-  pstops_filter_data.ppd = ppd;
+  pstops_filter_data.extension = data->extension;
   pstops_filter_data.logfunc = log;
   pstops_filter_data.logdata = ld;
   pstops_filter_data.iscanceledfunc = iscanceled;
@@ -621,7 +624,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
   }
 
  /*
-  * Build the command-line for the cfFilterPDFToPS, gs, mutool, pdftocairo, or
+  * Build the command-line for the ppdFilterPDFToPS, gs, mutool, pdftocairo, or
   * acroread filter...
   */
 
@@ -702,18 +705,18 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
       else if (renderer == PDFTOCAIRO)
       {
        if (log) log(ld, CF_LOGLEVEL_WARN,
-                    "cfFilterPDFToPS: Level 1 PostScript not supported by "
+                    "ppdFilterPDFToPS: Level 1 PostScript not supported by "
                     "pdftocairo.");
       }
       else if (renderer == ACROREAD)
       {
        if (log) log(ld, CF_LOGLEVEL_WARN,
-                    "cfFilterPDFToPS: Level 1 PostScript not supported by acroread.");
+                    "ppdFilterPDFToPS: Level 1 PostScript not supported by acroread.");
       }
       else if (renderer == MUPDF)
       {
        if (log) log(ld, CF_LOGLEVEL_WARN,
-                    "cfFilterPDFToPS: Level 1 PostScript not supported by mutool.");
+                    "ppdFilterPDFToPS: Level 1 PostScript not supported by mutool.");
       }
     }
     else if (ppd->language_level == 2)
@@ -762,7 +765,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
       else if (renderer == MUPDF)
       {
        if (log) log(ld, CF_LOGLEVEL_WARN,
-                    "cfFilterPDFToPS: Level 3 PostScript not supported by mutool.");
+                    "ppdFilterPDFToPS: Level 3 PostScript not supported by mutool.");
       }
       else /* PDFTOCAIRO || ACROREAD */
         pdf_argv[pdf_argc++] = (char *)"-level3";
@@ -838,10 +841,11 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
     if ((xres == 0) && (yres == 0) &&
        ((numvalues = sscanf(resolution, "%dx%d", &xres, &yres)) <= 0))
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterPDFToPS: No resolution information found in the PPD file.");
+                  "ppdFilterPDFToPS: No resolution information found in the PPD file.");
   }
   else{
-    cfRasterParseIPPOptions(&header, data, 0, 1);
+    cfRasterPrepareHeader(&header, data, CF_FILTER_OUT_FORMAT_CUPS_RASTER,
+                         CF_FILTER_OUT_FORMAT_CUPS_RASTER, 0, &cspace);
     if (header.HWResolution[0] > 100 && header.HWResolution[1] > 100)
     {
       xres = header.HWResolution[0];
@@ -893,7 +897,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
           strcasecmp(ptr, "dpcm")))
       {
        if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                    "cfFilterPDFToPS: Bad resolution value \"%s\".", val);
+                    "ppdFilterPDFToPS: Bad resolution value \"%s\".", val);
       }
       else
       {
@@ -929,7 +933,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
       maxres = mres;
     else
       if (log) log(ld, CF_LOGLEVEL_WARN,
-                  "cfFilterPDFToPS: Invalid value for "
+                  "ppdFilterPDFToPS: Invalid value for "
                   "\"pdftops-max-image-resolution\": \"%s\"",
                   val);
   }
@@ -956,7 +960,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
     snprintf(resolution, sizeof(resolution), "%d", res);
     pdf_argv[pdf_argc++] = resolution;
     if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "cfFilterPDFToPS: Using image rendering resolution %d dpi", res);
+                "ppdFilterPDFToPS: Using image rendering resolution %d dpi", res);
 #endif /* HAVE_POPPLER_PDFTOPS_WITH_RESOLUTION */
     if (gray_output == 1) /* Checking for monochrome/grayscale PostScript
                             output */
@@ -975,11 +979,11 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
         pdf_argv[pdf_argc++] = (char *)"-optimizecolorspace"; */
       /* Issue a warning message when printing a grayscale job with Poppler */
       if (log) log(ld, CF_LOGLEVEL_WARN,
-                  "cfFilterPDFToPS: Grayscale/monochrome printing requested for this "
+                  "ppdFilterPDFToPS: Grayscale/monochrome printing requested for this "
                   "job but Poppler is not able to convert to "
                   "grayscale/monochrome PostScript.");
       if (log) log(ld, CF_LOGLEVEL_WARN,
-                  "cfFilterPDFToPS: Use \"pdftops-renderer\" option (see "
+                  "ppdFilterPDFToPS: Use \"pdftops-renderer\" option (see "
                   "cups-filters README file) to use Ghostscript or MuPDF for "
                   "the PDF -> PostScript conversion.");
     }
@@ -995,7 +999,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
     snprintf(resolution, 127, "-r%d", res);
     pdf_argv[pdf_argc++] = resolution;
     if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "cfFilterPDFToPS: Using image rendering resolution %d dpi", res);
+                "ppdFilterPDFToPS: Using image rendering resolution %d dpi", res);
    /*
     * PostScript debug mode: If you send a job with "lpr -o psdebug" Ghostscript
     * will not compress the pages, so that the PostScript code can get
@@ -1012,7 +1016,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
          !strncasecmp(make_model, "Utax", 4))))
     {
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterPDFToPS: Deactivated compression of pages in "
+                  "ppdFilterPDFToPS: Deactivated compression of pages in "
                   "Ghostscript's PostScript output (\"psdebug\" debug mode "
                   "or Kyocera/Utax printer)");
       pdf_argv[pdf_argc++] = (char *)"-dCompressPages=false";
@@ -1029,7 +1033,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
        !strncasecmp(make_model, "Brother", 7))
     {
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterPDFToPS: Deactivation of Ghostscript's image compression "
+                  "ppdFilterPDFToPS: Deactivation of Ghostscript's image compression "
                   "for Brother printers to workarounmd PS interpreter bug");
       pdf_argv[pdf_argc++] = (char *)"-dEncodeMonoImages=false";
       pdf_argv[pdf_argc++] = (char *)"-dEncodeColorImages=false";
@@ -1045,7 +1049,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
        !strncasecmp(make_model, "Toshiba", 7))
     {
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterPDFToPS: To work around a bug in Toshiba's PS "
+                  "ppdFilterPDFToPS: To work around a bug in Toshiba's PS "
                   "interpreters turn TTF font glyphs into bitmaps, usually "
                   "Type 3 PS fonts, or images for large characters");
       pdf_argv[pdf_argc++] = (char *)"-dHaveTrueTypes=false";
@@ -1117,7 +1121,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
     if (pipe(pstops_pipe))
     {
       if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "cfFilterPDFToPS: Unable to create pipe for cfFilterPSToPS: %s",
+                  "ppdFilterPDFToPS: Unable to create pipe for ppdFilterPSToPS: %s",
                   strerror(errno));
 
       exit_status = 1;
@@ -1130,7 +1134,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
     if (pipe(post_proc_pipe))
     {
       if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "cfFilterPDFToPS: Unable to create pipe for post-processing: %s",
+                  "ppdFilterPDFToPS: Unable to create pipe for post-processing: %s",
                   strerror(errno));
 
       exit_status = 1;
@@ -1163,21 +1167,21 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
     {
       execvp(CUPS_POPPLER_PDFTOPS, pdf_argv);
       if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "cfFilterPDFToPS: Unable to execute pdftops program: %s",
+                  "ppdFilterPDFToPS: Unable to execute pdftops program: %s",
                   strerror(errno));
     }
     else if (renderer == GS)
     {
       execvp(CUPS_GHOSTSCRIPT, pdf_argv);
       if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "cfFilterPDFToPS: Unable to execute gs program: %s",
+                  "ppdFilterPDFToPS: Unable to execute gs program: %s",
                   strerror(errno));
     }
     else if (renderer == PDFTOCAIRO)
     {
       execvp(CUPS_POPPLER_PDFTOCAIRO, pdf_argv);
       if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "cfFilterPDFToPS: Unable to execute pdftocairo program: %s",
+                  "ppdFilterPDFToPS: Unable to execute pdftocairo program: %s",
                   strerror(errno));
     }
     else if (renderer == ACROREAD)
@@ -1194,14 +1198,14 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
      
       execvp(CUPS_ACROREAD, pdf_argv);
       if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "cfFilterPDFToPS: Unable to execute acroread program: %s",
+                  "ppdFilterPDFToPS: Unable to execute acroread program: %s",
                   strerror(errno));
     }
     else if (renderer == MUPDF)
     {
       execvp(CUPS_MUTOOL, pdf_argv);
       if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "cfFilterPDFToPS: Unable to execute mutool program: %s",
+                  "ppdFilterPDFToPS: Unable to execute mutool program: %s",
                   strerror(errno));
     }
 
@@ -1217,23 +1221,23 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
     {
       if (renderer == PDFTOPS)
        log(ld, CF_LOGLEVEL_ERROR,
-           "cfFilterPDFToPS: Unable to execute pdftops program: %s",
+           "ppdFilterPDFToPS: Unable to execute pdftops program: %s",
            strerror(errno));
       else if (renderer == GS)
        log(ld, CF_LOGLEVEL_ERROR,
-           "cfFilterPDFToPS: Unable to execute gs program: %s",
+           "ppdFilterPDFToPS: Unable to execute gs program: %s",
            strerror(errno));
       else if (renderer == PDFTOCAIRO)
        log(ld, CF_LOGLEVEL_ERROR,
-           "cfFilterPDFToPS: Unable to execute pdftocairo program: %s",
+           "ppdFilterPDFToPS: Unable to execute pdftocairo program: %s",
            strerror(errno));
       else if (renderer == ACROREAD)
        log(ld, CF_LOGLEVEL_ERROR,
-           "cfFilterPDFToPS: Unable to execute acroread program: %s",
+           "ppdFilterPDFToPS: Unable to execute acroread program: %s",
            strerror(errno));
       else if (renderer == MUPDF)
        log(ld, CF_LOGLEVEL_ERROR,
-           "cfFilterPDFToPS: Unable to execute mutool program: %s",
+           "ppdFilterPDFToPS: Unable to execute mutool program: %s",
            strerror(errno));
     }
 
@@ -1242,7 +1246,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
   }
 
   if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "cfFilterPDFToPS: Started filter %s (PID %d)", pdf_argv[0], pdf_pid);
+              "ppdFilterPDFToPS: Started filter %s (PID %d)", pdf_argv[0], pdf_pid);
 
   if (need_post_proc)
   {
@@ -1311,7 +1315,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
          {
            /* No Prolog section, create one */
            if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                        "cfFilterPDFToPS: Adding Prolog section for workaround "
+                        "ppdFilterPDFToPS: Adding Prolog section for workaround "
                         "PostScript code");
            puts("%%BeginProlog");
          }
@@ -1342,7 +1346,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
                !strncasecmp(make_model, "Utax", 4))
            {
              if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                          "cfFilterPDFToPS: Inserted workaround PostScript code for "
+                          "ppdFilterPDFToPS: Inserted workaround PostScript code for "
                           "Kyocera and Utax printers");
              puts("% ===== Workaround insertion by pdftops CUPS filter =====");
              puts("% Kyocera's/Utax's PostScript interpreter crashes on "
@@ -1378,7 +1382,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
            else if (!strncasecmp(make_model, "Brother", 7))
            {
              if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                          "cfFilterPDFToPS: Inserted workaround PostScript code for "
+                          "ppdFilterPDFToPS: Inserted workaround PostScript code for "
                           "Brother printers");
              puts("% ===== Workaround insertion by pdftops CUPS filter =====");
              puts("% Brother's PostScript interpreter spits out the current "
@@ -1427,7 +1431,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
              {
                /* No Setup section, create one */
                if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                            "cfFilterPDFToPS: Adding Setup section for option "
+                            "ppdFilterPDFToPS: Adding Setup section for option "
                             "PostScript code");
                puts("%%BeginSetup");
              }
@@ -1588,7 +1592,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
       */
 
       if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "cfFilterPDFToPS: Unable to execute post-processing process: %s",
+                  "ppdFilterPDFToPS: Unable to execute post-processing process: %s",
                   strerror(errno));
 
       exit_status = 1;
@@ -1596,7 +1600,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
     }
 
     if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "cfFilterPDFToPS: Started post-processing (PID %d)", post_proc_pid);
+                "ppdFilterPDFToPS: Started post-processing (PID %d)", post_proc_pid);
   }
 
   if (ppd)
@@ -1614,11 +1618,11 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
        close(post_proc_pipe[1]);
       }
 
-      ret = cfFilterPSToPS(pstops_pipe[0], outputfd, 0, &pstops_filter_data, NULL);
+      ret = ppdFilterPSToPS(pstops_pipe[0], outputfd, 0, &pstops_filter_data, NULL);
       close(pstops_pipe[0]);
 
       if (ret && log) log(ld, CF_LOGLEVEL_ERROR,
-                         "cfFilterPDFToPS: pstops filter function failed.");
+                         "ppdFilterPDFToPS: pstops filter function failed.");
 
       close(outputfd);
       exit(ret);
@@ -1630,7 +1634,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
       */
 
       if (log) log(ld, CF_LOGLEVEL_ERROR,
-                  "cfFilterPDFToPS: Unable to execute pstops program: %s",
+                  "ppdFilterPDFToPS: Unable to execute pstops program: %s",
                   strerror(errno));
 
       exit_status = 1;
@@ -1638,7 +1642,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
     }
 
     if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                "cfFilterPDFToPS: Started filter pstops (PID %d)", pstops_pid);
+                "ppdFilterPDFToPS: Started filter pstops (PID %d)", pstops_pid);
 
     close(pstops_pipe[0]);
     close(pstops_pipe[1]);
@@ -1689,7 +1693,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
        exit_status = WEXITSTATUS(wait_status);
 
        if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                    "cfFilterPDFToPS: PID %d (%s) stopped with status %d!",
+                    "ppdFilterPDFToPS: PID %d (%s) stopped with status %d!",
                     wait_pid,
                     wait_pid == pdf_pid ?
                     (renderer == PDFTOPS ? "pdftops" :
@@ -1706,7 +1710,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
       else if (WTERMSIG(wait_status) == SIGTERM)
       {
        if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                    "cfFilterPDFToPS: PID %d (%s) was terminated normally with "
+                    "ppdFilterPDFToPS: PID %d (%s) was terminated normally with "
                     "signal %d!",
                     wait_pid,
                     wait_pid == pdf_pid ?
@@ -1726,7 +1730,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
        exit_status = WTERMSIG(wait_status);
 
        if (log) log(ld, CF_LOGLEVEL_ERROR,
-                    "cfFilterPDFToPS: PID %d (%s) crashed on signal %d!",
+                    "ppdFilterPDFToPS: PID %d (%s) crashed on signal %d!",
                     wait_pid,
                     wait_pid == pdf_pid ?
                     (renderer == PDFTOPS ? "pdftops" :
@@ -1744,7 +1748,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
     else
     {
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterPDFToPS: PID %d (%s) exited with no errors.",
+                  "ppdFilterPDFToPS: PID %d (%s) exited with no errors.",
                   wait_pid,
                   wait_pid == pdf_pid ?
                   (renderer == PDFTOPS ? "pdftops" :
@@ -1766,7 +1770,7 @@ cfFilterPDFToPS(int inputfd,         /* I - File descriptor input stream */
   error:
 
   if (log) log(ld, CF_LOGLEVEL_DEBUG,
-              "cfFilterPDFToPS: Closing files ...");
+              "ppdFilterPDFToPS: Closing files ...");
 
   close(outputfd);
 
index ba96e9ec82330d073fc48fdbbedd36073f12e0b9..cf9afd632e0fb397107700f92d38a3fc8f6118f4 100644 (file)
@@ -23,6 +23,8 @@
 #  include <unistd.h>
 #endif /* _WIN32 || __EMX__ */
 #include <errno.h>
+#include <ctype.h>
+#include <string.h>
 
 
 /*
@@ -30,7 +32,6 @@
  */
 
 static int     ppd_compare_cparams(ppd_cparam_t *a, ppd_cparam_t *b);
-static void    ppd_handle_media(ppd_file_t *ppd);
 
 
 /*
@@ -353,7 +354,8 @@ ppdEmitFd(ppd_file_t    *ppd,               /* I - PPD file record */
 
 
 /*
- * 'ppdEmitJCL()' - Emit code for JCL options to a file.
+ * 'ppdEmitJCL()' - Emit code for JCL options to a file (for PostScript
+ *                  output).
  */
 
 int                                    /* O - 0 on success, -1 on failure */
@@ -363,6 +365,27 @@ ppdEmitJCL(ppd_file_t *ppd,                /* I - PPD file record */
           const char *user,            /* I - Username */
           const char *title)           /* I - Title */
 {
+  return ppdEmitJCLPDF(ppd, fp, job_id, user, title, -1, false);
+}
+
+
+/*
+ * 'ppdEmitJCLPDF()' - Emit code for JCL options to a file (for PDF output).
+ */
+
+int                                    /* O - 0 on success, -1 on failure */
+ppdEmitJCLPDF(ppd_file_t *ppd,         /* I - PPD file record */
+             FILE       *fp,           /* I - File to write to */
+             int        job_id,        /* I - Job ID */
+             const char *user,         /* I - Username */
+             const char *title,        /* I - Title */
+             int hw_copies,            /* I - Number of hardware (device)
+                                              copies, -1: PS mode */
+             bool hw_collate)          /* I - Do we have hardware (device)
+                                              collate? */
+{
+  ppd_attr_t    *attr;                  /* PPD attribute */
+  const char    *jcl_pdf = NULL;
   char         *ptr;                   /* Pointer into JCL string */
   char         temp[65],               /* Local title string */
                displaymsg[33];         /* Local display string */
@@ -372,7 +395,19 @@ ppdEmitJCL(ppd_file_t *ppd,                /* I - PPD file record */
   * Range check the input...
   */
 
-  if (!ppd || !ppd->jcl_begin || !ppd->jcl_ps)
+
+  if (!ppd || !ppd->jcl_begin)
+    return (0);
+
+#if HAVE_CUPS_3_X
+  jcl_pdf = ppd->jcl_pdf;
+#else
+  if ((attr = ppdFindAttr(ppd, "JCLToPDFInterpreter", NULL)) != NULL)
+    jcl_pdf = attr->value;
+#endif
+  
+  if ((!ppd->jcl_ps && hw_copies < 0) ||
+      (!jcl_pdf && hw_copies >= 0))
     return (0);
 
  /*
@@ -530,7 +565,30 @@ ppdEmitJCL(ppd_file_t *ppd,                /* I - PPD file record */
     fputs(ppd->jcl_begin, fp);
 
   ppdEmit(ppd, fp, PPD_ORDER_JCL);
-  fputs(ppd->jcl_ps, fp);
+
+  if (hw_copies < 0)
+    /* PostScript output */
+    fputs(ppd->jcl_ps, fp);
+  else
+  {
+    /* PDF output */
+
+    int hw_copies_done = 0;
+
+    /* There is a "Copies" option in the PPD file, so this option setting
+       always takes care of correct implementation of the copies */
+    if (ppdFindOption(ppd,"Copies") != NULL &&
+       hw_copies > 1)
+      hw_copies_done = 1;
+
+    if (hw_copies > 1 && hw_copies_done == 0 && // HW copies
+       strncmp(ppd->jcl_begin, "\033%-12345X@", 10) == 0) // PJL
+      /* Add a PJL command to implement the hardware copies */
+      fprintf(fp, "@PJL SET %s=%d\n", hw_collate ? "QTY" : "COPIES",
+             hw_copies);
+
+    fputs(jcl_pdf, fp);
+  }
 
   return (0);
 }
@@ -633,7 +691,7 @@ ppdEmitString(ppd_file_t    *ppd,   /* I - PPD file record */
   * Use PageSize or PageRegion as required...
   */
 
-  ppd_handle_media(ppd);
+  ppdHandleMedia(ppd);
 
  /*
   * Collect the options we need to emit...
@@ -1103,23 +1161,11 @@ ppdEmitString(ppd_file_t    *ppd,       /* I - PPD file record */
 
 
 /*
- * 'ppd_compare_cparams()' - Compare the order of two custom parameters.
- */
-
-static int                             /* O - Result of comparison */
-ppd_compare_cparams(ppd_cparam_t *a,   /* I - First parameter */
-                    ppd_cparam_t *b)   /* I - Second parameter */
-{
-  return (a->order - b->order);
-}
-
-
-/*
- * 'ppd_handle_media()' - Handle media selection...
+ * 'ppdHandleMedia()' - Handle media selection...
  */
 
-static void
-ppd_handle_media(ppd_file_t *ppd)      /* I - PPD file */
+void
+ppdHandleMedia(ppd_file_t *ppd)        /* I - PPD file */
 {
   ppd_choice_t *manual_feed,           /* ManualFeed choice, if any */
                *input_slot;            /* InputSlot choice, if any */
@@ -1213,3 +1259,15 @@ ppd_handle_media(ppd_file_t *ppd)        /* I - PPD file */
     }
   }
 }
+
+
+/*
+ * 'ppd_compare_cparams()' - Compare the order of two custom parameters.
+ */
+
+static int                             /* O - Result of comparison */
+ppd_compare_cparams(ppd_cparam_t *a,   /* I - First parameter */
+                    ppd_cparam_t *b)   /* I - Second parameter */
+{
+  return (a->order - b->order);
+}
diff --git a/ppd/ppd-filter.c b/ppd/ppd-filter.c
new file mode 100644 (file)
index 0000000..25549e8
--- /dev/null
@@ -0,0 +1,2553 @@
+/*
+ * Filter functions support for libppd.
+ *
+ * Copyright Â© 2020-2022 by Till Kamppeter.
+ *
+ * Licensed under Apache License v2.0.  See the file "LICENSE" for more
+ * information.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "config.h"
+#include "ppd-filter.h"
+#include "ppd.h"
+#include <limits.h>
+#include <math.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <ctype.h>
+#include <sys/wait.h>
+#include <cups/file.h>
+#include <cups/array.h>
+
+extern char **environ;
+
+/*
+ * 'ppdFilterCUPSWrapper()' - Wrapper function to use a filter function as
+ *                            classic CUPS filter
+ */
+
+int                                    /* O - Exit status */
+ppdFilterCUPSWrapper(
+     int  argc,                                /* I - Number of command-line args */
+     char *argv[],                     /* I - Command-line arguments */
+     cf_filter_function_t filter,       /* I - Filter function */
+     void *parameters,                  /* I - Filter function parameters */
+     int *JobCanceled)                  /* I - Var set to 1 when job canceled */
+{
+  int          inputfd;                /* Print file descriptor*/
+  int           inputseekable;          /* Is the input seekable (actual file
+                                          not stdin)? */
+  int          num_options;            /* Number of print options */
+  cups_option_t        *options;               /* Print options */
+  cf_filter_data_t filter_data;
+  const char    *val;
+  char          buf[256];
+  int           retval = 0;
+
+
+ /*
+  * Make sure status messages are not buffered...
+  */
+
+  setbuf(stderr, NULL);
+
+ /*
+  * Ignore broken pipe signals...
+  */
+
+  signal(SIGPIPE, SIG_IGN);
+
+ /*
+  * Check command-line...
+  */
+
+  if (argc < 6 || argc > 7)
+  {
+    fprintf(stderr, "Usage: %s job-id user title copies options [file]\n",
+           argv[0]);
+    return (1);
+  }
+
+ /*
+  * If we have 7 arguments, print the file named on the command-line.
+  * Otherwise, send stdin instead...
+  */
+
+  if (argc == 6)
+  {
+    inputfd = 0; /* stdin */
+    inputseekable = 0;
+  }
+  else
+  {
+   /*
+    * Try to open the print file...
+    */
+
+    if ((inputfd = open(argv[6], O_RDONLY)) < 0)
+    {
+      if (!JobCanceled)
+      {
+        fprintf(stderr, "DEBUG: Unable to open \"%s\": %s\n", argv[6],
+               strerror(errno));
+       fprintf(stderr, "ERROR: Unable to open print file");
+      }
+
+      return (1);
+    }
+
+    inputseekable = 1;
+  }
+
+ /*
+  * Process command-line options...
+  */
+
+  options     = NULL;
+  num_options = cupsParseOptions(argv[5], 0, &options);
+
+  if ((filter_data.printer = getenv("PRINTER")) == NULL)
+    filter_data.printer = argv[0];
+  filter_data.job_id = atoi(argv[1]);
+  filter_data.job_user = argv[2];
+  filter_data.job_title = argv[3];
+  filter_data.copies = atoi(argv[4]);
+  filter_data.content_type = getenv("CONTENT_TYPE");
+  filter_data.final_content_type = getenv("FINAL_CONTENT_TYPE");
+  filter_data.job_attrs = NULL;        /* We use command line options */
+  /* The following two will get populated by ppdFilterLoadPPD() */
+  filter_data.printer_attrs = NULL;    /* We use the queue's PPD file */
+  filter_data.header = NULL;           /* CUPS Raster header of queue's PPD */
+  filter_data.num_options = num_options;
+  filter_data.options = options;       /* Command line options from 5th arg */
+  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 */
+  filter_data.side_pipe[1] = 4;        /* the side channel */
+  filter_data.extension = NULL;
+  filter_data.logfunc = cfCUPSLogFunc;  /* Logging scheme of CUPS */
+  filter_data.logdata = NULL;
+  filter_data.iscanceledfunc = cfCUPSIsCanceledFunc; /* Job-is-canceled
+                                                      function */
+  filter_data.iscanceleddata = JobCanceled;
+
+ /*
+  * CUPS_FONTPATH (Usually /usr/share/cups/fonts)
+  */
+
+  if (cupsGetOption("cups-fontpath",
+                   filter_data.num_options, filter_data.options) == NULL)
+  {
+    if ((val = getenv("CUPS_FONTPATH")) == NULL)
+    {
+      val = CUPS_DATADIR;
+      snprintf(buf, sizeof(buf), "%s/fonts", val);
+      val = buf;
+    }
+    if (val[0] != '\0')
+      filter_data.num_options =
+       cupsAddOption("cups-fontpath", val,
+                     filter_data.num_options, &(filter_data.options));
+  }
+
+ /*
+  * Load and prepare the PPD file, also attach it as extension "libppd"
+  * to the filter_data structure
+  */
+
+  retval = ppdFilterLoadPPDFile(&filter_data, getenv("PPD"));
+
+ /*
+  * Fire up the filter function (output to stdout, file descriptor 1)
+  */
+
+  if (!retval)
+    retval = filter(inputfd, 1, inputseekable, &filter_data, parameters);
+
+ /*
+  * Clean up
+  */
+
+  cupsFreeOptions(filter_data.num_options, filter_data.options);
+  ppdFilterFreePPDFile(&filter_data);
+
+  return retval;
+}
+
+
+/*
+ * 'ppdFilterLoadPPDFile()' - When preparing the filter data structure
+ *                            for calling one or more filter
+ *                            functions, load the PPD file specified
+ *                            by its file name.  If the file name is
+ *                            NULL or empty, do nothing. If the PPD
+ *                            got successfully loaded add its data to
+ *                            the filter data structure as extension
+ *                            named "libppd", so that filters
+ *                            functions designed for using PPDs can
+ *                            access it. Then read out all the
+ *                            relevant data with the
+ *                            ppdFilterLoadPPD() function.
+ */
+
+int                                         /* O   - Error status */
+ppdFilterLoadPPDFile(cf_filter_data_t *data, /* I/O - Job and printer data */
+                    const char *ppdfile)    /* I   - PPD file name */
+{
+  ppd_filter_data_ext_t *filter_data_ext; /* Record for "libppd" extension */
+  ppd_file_t       *ppd;                  /* PPD data */
+  cf_logfunc_t     log = data->logfunc;   /* Log function */
+  void             *ld = data->logdata;   /* log function data */
+
+  if (!ppdfile || !ppdfile[0])
+    return (-1);
+
+  if ((ppd = ppdOpenFile(ppdfile)) == NULL)
+  {
+    if (log) log(ld, CF_LOGLEVEL_ERROR,
+                "ppdFilterLoadPPDFile: Could not load PPD file %s: %s",
+                ppdfile, strerror(errno));
+    return (-1);
+  }
+
+  filter_data_ext =
+    (ppd_filter_data_ext_t *)calloc(1, sizeof(ppd_filter_data_ext_t));
+
+  filter_data_ext->ppdfile = strdup(ppdfile); /* PPD file name */
+  filter_data_ext->ppd = ppd;                 /* PPD data */
+  cfFilterDataAddExt(data, PPD_FILTER_DATA_EXT, filter_data_ext);
+
+  return ppdFilterLoadPPD(data);
+}
+
+
+/*
+ * 'ppdFilterLoadPPD()' - When preparing the filter data structure for
+ *                        calling one or more filter functions, and a
+ *                        PPD file is attached as "libppd" extension,
+ *                        set up the PPD's cache, mark default
+ *                        settings and if supplied in the data
+ *                        structure, also option settings. Then
+ *                        convert the capability and option info in
+ *                        the PPD file into printer IPP attributes and
+ *                        what cannot be represented in IPP as option
+ *                        settings and add these results to the filter
+ *                        data structure. This allows to use the (by
+ *                        itself not PPD-supporting) filter function
+ *                        to do its work for the printer represented
+ *                        by the PPD file. Add the CUPS PPD file data
+ *                        structure with embedded CUPS PPD cache data
+ *                        structure (including PPD option setting
+ *                        presets for all possible print-color-mode,
+ *                        print-quality, and print-content-optimize
+ *                        settings) to the filter data structure for
+ *                        use by libppd's PPD-requiring filter
+ *                        functions.
+ */
+
+int                                     /* O   - Error status */
+ppdFilterLoadPPD(cf_filter_data_t *data) /* I/O - Job and printer data */
+{
+  int              i;
+  ppd_filter_data_ext_t *filter_data_ext =
+    (ppd_filter_data_ext_t *)cfFilterDataGetExt(data,
+                                               PPD_FILTER_DATA_EXT);
+  ppd_file_t       *ppd;
+  int              num_job_attr_options = 0;
+  cups_option_t    *job_attr_options = NULL;
+  cups_option_t    *opt;
+  ppd_attr_t       *ppd_attr;
+  ppd_choice_t     *choice;
+  ipp_attribute_t  *attr;
+  ipp_t            *col;
+  const char       *val;
+  char             *lastfilter = NULL;
+  bool             hw_copies = false,
+                   hw_collate = false;
+  const char       *page_size, *media;
+  const char       *q1_choice, *q2_choice, *q3_choice;
+  char             buf[1024];
+  char             cm_qualifier_tmp[1024];
+  const char       *cm_profile_key;
+  char            *resolution,           /* Output resolution */
+                  *media_type;           /* Media type */
+  ppd_profile_t           *profile;              /* Color profile */
+  cf_logfunc_t     log = data->logfunc;   /* Log function */
+  void             *ld = data->logdata;   /* log function data */
+
+  if (!filter_data_ext || !filter_data_ext->ppd)
+    return (-1);
+
+ /*
+  * Prepare PPD file and mark options
+  */
+
+  ppd = filter_data_ext->ppd;
+  ppd->cache = ppdCacheCreateWithPPD(ppd);
+  ppdMarkDefaults(ppd);
+  ppdMarkOptions(ppd, data->num_options, data->options);
+  num_job_attr_options = ppdGetOptions(&job_attr_options, data->printer_attrs,
+                                      data->job_attrs, ppd);
+  for(i = 0, opt = job_attr_options; i < num_job_attr_options; i++, opt++)
+    data->num_options = cupsAddOption(opt->name, opt->value,
+                                     data->num_options, &(data->options));
+  cupsFreeOptions(num_job_attr_options, job_attr_options);
+  ppdMarkOptions(ppd, data->num_options, data->options);
+  ppdHandleMedia(ppd);
+
+ /*
+  * Pass on PPD attributes
+  */
+
+  /* Pass on "PWGRaster" PPD attribute (for PWG Raster output) */
+  if ((ppd_attr = ppdFindAttr(ppd, "PWGRaster", 0)) != 0 &&
+      (!strcasecmp(ppd_attr->value, "true") ||
+       !strcasecmp(ppd_attr->value, "on") ||
+       !strcasecmp(ppd_attr->value, "yes")))
+    data->num_options = cupsAddOption("media-class", "PwgRaster",
+                                     data->num_options, &(data->options));
+
+  /* Pass on "cupsEvenDuplex" PPD attribute */
+  if ((ppd_attr = ppdFindAttr(ppd, "cupsEvenDuplex", 0)) != NULL)
+    data->num_options = cupsAddOption("even-duplex", ppd_attr->value,
+                                     data->num_options, &(data->options));
+
+  /* Pass on "cupsBackSide" (or "cupsFlipDuplex") PPD attribute */
+  if ((ppd_attr = ppdFindAttr(ppd, "cupsBackSide", 0)) != NULL)
+  {
+    ppd->flip_duplex = 0; /* "cupsBackSide" has priority */
+    data->num_options = cupsAddOption("back-side-orientation", ppd_attr->value,
+                                     data->num_options, &(data->options));
+  }
+  else if (ppd->flip_duplex) /* "cupsFlipDuplex" same as "Rotated" */
+    data->num_options = cupsAddOption("back-side-orientation", "Rotated",
+                                     data->num_options, &(data->options));
+
+  /* Pass on "APDuplexRequiresFlippedMargin" PPD attribute */
+  if ((ppd_attr = ppdFindAttr(ppd, "APDuplexRequiresFlippedMargin", 0)) != NULL)
+    data->num_options = cupsAddOption("duplex-requires-flipped-margin",
+                                     ppd_attr->value,
+                                     data->num_options, &(data->options));
+
+  /* Pass on "cupsRasterVersion" PPD attribute */
+  if ((ppd_attr = ppdFindAttr(ppd,"cupsRasterVersion", 0)) != NULL)
+    data->num_options = cupsAddOption("cups-raster-version",
+                                     ppd_attr->value,
+                                     data->num_options, &(data->options));
+
+  /* Pass on "DefaultCenterOfPixel" PPD attribute (for Ghostscript) */
+  if ((ppd_attr = ppdFindAttr(ppd,"DefaultCenterOfPixel", 0)) != NULL)
+    data->num_options = cupsAddOption("center-of-pixel",
+                                     ppd_attr->value,
+                                     data->num_options, &(data->options));
+
+  /* Set short-edge Duplex when booklet printing is selected */
+  if ((val = cupsGetOption("booklet",
+                          data->num_options, data->options)) != NULL &&
+      (!strcasecmp(val, "on") || !strcasecmp(val, "yes") ||
+       !strcasecmp(val, "true")) &&
+      ppd->cache->sides_option &&
+      ppd->cache->sides_2sided_short &&
+      ppdFindOption(ppd, ppd->cache->sides_option))
+    ppdMarkOption(ppd, ppd->cache->sides_option,
+                 ppd->cache->sides_2sided_short);
+
+  /* Let the PDF filter do mirrored printing */
+  if ((choice = ppdFindMarkedChoice(ppd, "MirrorPrint")) != NULL)
+  {
+    choice->marked = 0;
+    data->num_options = cupsAddOption("mirror", "true",
+                                     data->num_options, &(data->options));
+  }
+
+ /*
+  * Find out whether we can do hardware copies/collate
+  */
+
+  if (data->copies == 1)
+  {
+    /* 1 copy, hardware copies/collate do not make difference */
+    hw_copies = false;
+    hw_collate = false;
+  }
+  else if (!ppd->manual_copies)
+  {
+    /* Hardware copy generation available */
+    hw_copies = true;
+    /* Check output format (FINAL_CONTENT_TYPE env variable) whether it is
+       of a driverless IPP printer (PDF, Apple Raster, PWG Raster, PCLm).
+       These printers do always hardware collate if they do hardware copies.
+       https://github.com/apple/cups/issues/5433
+       This also assumes that if a classic PDF printer (non-IPP printer printing
+       with JCL/PJL-controlled PDF) supports hardware copies that it also does
+       hardware collate */
+    if (data->final_content_type &&
+       (strcasestr(data->final_content_type, "/pdf") ||
+        strcasestr(data->final_content_type, "/vnd.cups-pdf") ||
+        strcasestr(data->final_content_type, "/pwg-raster") ||
+        strcasestr(data->final_content_type, "/urf") ||
+        strcasestr(data->final_content_type, "/PCLm")))
+    {
+      /* If PPD has "Collate" option set to not collate, do not set
+        hw_collate, especially important to set correct JCL/PJL on
+        "classic" PDF printers (they will always collate otherwise) */
+      if ((choice = ppdFindMarkedChoice(ppd, "Collate")) != NULL &&
+         (!strcasecmp(choice->choice, "off") ||
+          !strcasecmp(choice->choice, "no") ||
+          !strcasecmp(choice->choice, "false")))
+       hw_collate = false;
+      else
+       hw_collate = true;
+    }
+    else
+    {
+      /* Check whether printer hardware-collates with current PPD settings */
+      if ((choice = ppdFindMarkedChoice(ppd, "Collate")) != NULL &&
+         (!strcasecmp(choice->choice, "on") ||
+          !strcasecmp(choice->choice, "yes") ||
+          !strcasecmp(choice->choice, "true")))
+      {
+       /* Printer can collate, but also for the currently marked PPD
+          features? */
+       ppd_option_t *opt = ppdFindOption(ppd, "Collate");
+       hw_collate = (opt && !opt->conflicted);
+      }
+      else
+       hw_collate = false;
+    }
+  }
+  else
+  {
+    /* We have "*cupsManualCopies: True" =>
+       Software copies/collate */
+    hw_copies = false;
+    hw_collate = false;
+  }
+
+  if (!hw_copies)
+  {
+    /* Software copies */
+    /* Make sure any hardware copying is disabled */
+    ppdMarkOption(ppd, "Copies", "1");
+    ppdMarkOption(ppd, "JCLCopies", "1");
+  }
+  else
+  {
+    /* Hardware copies */
+    /* If there is a "Copies" option in the PPD file, assure that hardware
+       copies are implemented as described by this option */
+    snprintf(buf, sizeof(buf), "%d", hw_copies);
+    ppdMarkOption(ppd, "Copies", buf);
+  }
+
+  /* Software collate */
+  if (!hw_collate)
+    /* Disable any hardware collate (in JCL) */
+    ppdMarkOption(ppd, "Collate", "False");
+
+  /* Add options telling whether we want hardware copies/collate or not */
+  data->num_options = cupsAddOption("hardware-copies",
+                                   (hw_copies ? "true" : "false"),
+                                   data->num_options, &(data->options));
+  data->num_options = cupsAddOption("hardware-collate",
+                                   (hw_collate ? "true" : "false"),
+                                   data->num_options, &(data->options));
+
+ /*
+  * Pass on color management attributes
+  */
+
+  /* Get color space */
+  if ((ppd_attr = ppdFindAttr (ppd, "cupsICCQualifier1", NULL)) != NULL &&
+      ppd_attr->value && ppd_attr->value[0])
+    choice = ppdFindMarkedChoice(ppd, ppd_attr->value);
+  else if ((choice = ppdFindMarkedChoice(ppd, "ColorModel")) == NULL)
+    choice = ppdFindMarkedChoice(ppd, "ColorSpace");
+  if (choice && choice->choice && choice->choice[0])
+    q1_choice = choice->choice;
+  else
+    q1_choice = "";
+
+  /* Get media type */
+  if ((ppd_attr = ppdFindAttr(ppd, "cupsICCQualifier2", NULL)) != NULL &&
+      ppd_attr->value && ppd_attr->value[0])
+    choice = ppdFindMarkedChoice(ppd, ppd_attr->value);
+  else
+    choice = ppdFindMarkedChoice(ppd, "MediaType");
+  if (choice && choice->choice && choice->choice[0])
+    q2_choice = choice->choice;
+  else
+    q2_choice = "";
+
+  /* Get resolution */
+  if ((ppd_attr = ppdFindAttr(ppd, "cupsICCQualifier3", NULL)) != NULL &&
+      ppd_attr->value && ppd_attr->value[0])
+    choice = ppdFindMarkedChoice(ppd, ppd_attr->value);
+  else
+    choice = ppdFindMarkedChoice(ppd, "Resolution");
+  if (choice && choice->choice && choice->choice[0])
+    q3_choice = choice->choice;
+  else
+  {
+    ppd_attr = ppdFindAttr(ppd, "DefaultResolution", NULL);
+    if (ppd_attr && ppd_attr->value && ppd_attr->value[0])
+      q3_choice = ppd_attr->value;
+    else
+      q3_choice = "";
+  }
+
+  /* create a string for the option */
+  snprintf(cm_qualifier_tmp, sizeof(cm_qualifier_tmp),
+           "%s.%s.%s", q1_choice, q2_choice, q3_choice);
+  if (log) log(ld, CF_LOGLEVEL_DEBUG,
+              "ppdFilterLoadPPD: Color profile qualifier determined from job and PPD data '%s'",
+              cm_qualifier_tmp);
+
+  /* Supply qualifier as option */
+  data->num_options = cupsAddOption("cm-profile-qualifier", cm_qualifier_tmp,
+                                   data->num_options, &(data->options));
+
+  /* get profile attr, falling back to CUPS */
+  cm_profile_key = "APTiogaProfile";
+  ppd_attr = ppdFindAttr(ppd, cm_profile_key, NULL);
+  if (ppd_attr == NULL)
+  {
+    cm_profile_key = "cupsICCProfile";
+    ppd_attr = ppdFindAttr(ppd, cm_profile_key, NULL);
+  }
+
+  if (ppd_attr == NULL)
+  {
+    /* neither */
+    if (log) log(ld, CF_LOGLEVEL_DEBUG,
+               "ppdFilterLoadPPD: No ICC profiles specified in PPD");
+  }
+  else
+  {
+    /* Try to find a profile that matches the qualifier exactly */
+    for (;ppd_attr != NULL;
+        ppd_attr = ppdFindNextAttr(ppd, cm_profile_key, NULL))
+    {
+      /* Invalid entry */
+      if (ppd_attr->spec == NULL || ppd_attr->value == NULL)
+       continue;
+
+      /* Matches the qualifier */
+      if (strcmp(cm_qualifier_tmp, ppd_attr->spec) == 0)
+      {
+       if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                    "ppdFilterLoadPPD: Found ICC profile %s in PPD for qualifier '%s'",
+                    ppd_attr->value, ppd_attr->spec);
+       break;
+      }
+    }
+
+    /* No match */
+    if (ppd_attr == NULL)
+    {
+      if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                  "ppdFilterLoadPPD: No ICC profile in PPD for qualifier '%s'",
+                  cm_qualifier_tmp);
+    }
+    else
+    {
+      /* expand to a full path if not already specified */
+      if (ppd_attr->value[0] != '/')
+      {
+       if ((val = getenv("CUPS_DATADIR")) == NULL)
+         val = CUPS_DATADIR;
+       snprintf(buf, sizeof(buf),
+                "%s/profiles/%s", val, ppd_attr->value);
+      }
+      else
+      {
+       strncpy(buf, ppd_attr->value, sizeof(buf) - 1);
+       if (strlen(ppd_attr->value) > 1023)
+         buf[1023] = '\0';
+      }
+
+      /* check the file exists */
+      if (access(buf, 0))
+      {
+       if (log) log(ld, CF_LOGLEVEL_ERROR,
+                    "ppdFilterLoadPPD: ICC profile %s in PPD does not exist",
+                    buf);
+      }
+      else
+      {
+       /* Supply path as fallback profile option */
+       if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                    "ppdFilterLoadPPD: Using ICC profile %s as fallback if colord does not supply another one",
+                    buf);
+       data->num_options =
+         cupsAddOption("cm-fallback-profile", buf,
+                       data->num_options, &(data->options));
+      }
+    }
+  }
+
+ /*
+  * Find a color profile matching the current options...
+  */
+
+  if (cupsGetOption("profile", data->num_options, data->options) == NULL)
+  {
+    if ((choice = ppdFindMarkedChoice(ppd, "Resolution")) != NULL)
+      resolution = choice->choice;
+    else
+      resolution = "-";
+    if ((choice = ppdFindMarkedChoice(ppd, "MediaType")) != NULL)
+      media_type = choice->choice;
+    else
+      media_type = "-";
+
+    if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                "ppdFilterLoadPPD: Searching for profile \"%s/%s\"...",
+                resolution, media_type);
+
+    for (i = 0, profile = ppd->profiles; i < ppd->num_profiles;
+        i ++, profile ++)
+    {
+      if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                  "ppdFilterLoadPPD: \"%s/%s\" = ", profile->resolution,
+                  profile->media_type);
+
+      if ((strcmp(profile->resolution, resolution) == 0 ||
+           profile->resolution[0] == '-') &&
+          (strcmp(profile->media_type, media_type) == 0 ||
+           profile->media_type[0] == '-'))
+      {
+       if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                    "ppdFilterLoadPPD:    MATCH");
+       break;
+      }
+      else
+       if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                    "ppdFilterLoadPPD:    no.");
+    }
+
+   /*
+    * If we found a color profile, use it!
+    */
+
+    if (i >= ppd->num_profiles)
+      profile = NULL;
+  }
+  else
+    profile = NULL;
+
+  if (profile)
+  {
+    snprintf(buf, sizeof(buf),
+            "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
+            (int)(profile->density * 1000.0),
+            (int)(profile->gamma * 1000.0),
+            (int)(profile->matrix[0][0] * 1000.0),
+            (int)(profile->matrix[0][1] * 1000.0),
+            (int)(profile->matrix[0][2] * 1000.0),
+            (int)(profile->matrix[1][0] * 1000.0),
+            (int)(profile->matrix[1][1] * 1000.0),
+            (int)(profile->matrix[1][2] * 1000.0),
+            (int)(profile->matrix[2][0] * 1000.0),
+            (int)(profile->matrix[2][1] * 1000.0),
+            (int)(profile->matrix[2][2] * 1000.0));
+    data->num_options = cupsAddOption("profile", buf,
+                                     data->num_options, &(data->options));
+  }
+
+ /*
+  * Convert the settings and properties in the PPD into printer IPP
+  * attributes
+  */
+
+  data->printer_attrs = ppdLoadAttributes(ppd);
+
+ /*
+  * Generate a CUPS Raster sample header, some filters can easily take
+  * data from it or make it the base for actual Raster headers. The
+  * header is based on the pseudo-PostScript code at the option
+  * settings in the PPD file, this is especially a more reliable way
+  * to obtain the correct resolution.
+  *
+  * This only works if the PPD file is actually for a CUPS Raster
+  * driver, as other PPD files do not contain all resolution, page
+  * geometry and color space/depth info in pseudo-PostScript code and
+  * the ppdRasterInterpretPPD() function only parses the
+  * pseudo-PostScript code not the names of the options and choices.
+  *
+  * Therefore we create the sample header only if the PPD is actually
+  * for a CUPS Raster driver.
+  */
+
+  data->header = NULL;
+  for (i = 0; i < ppd->num_filters; i ++)
+  {
+    if (!strncasecmp(ppd->filters[i], "application/vnd.cups-raster", 27))
+    {
+      // We have a CUPS Raster driver PPD file
+      data->header =
+       (cups_page_header2_t *)calloc(1, sizeof(cups_page_header2_t));
+      if (ppdRasterInterpretPPD(data->header, ppd,
+                               data->num_options, data->options, NULL) < 0)
+      {
+       if (log) log(ld, CF_LOGLEVEL_ERROR,
+                    "ppdFilterLoadPPD: Unable to generate CUPS Raster sample header.");
+       free(data->header);
+       data->header = NULL;
+      }
+      break;
+    }
+  }
+
+ /*
+  * Replace the "PageSize" option by a media-col attribute, as this
+  * one selects the media much more reliably by numeric size
+  * dimensions and margins and not by name.
+  *
+  * PPDs have special page size names for page size variants (A4,
+  * A4.Borderless, A4.Duplex, A4.Transverse) which cannot get mapped
+  * into the printer IPP attributes (media-col-database) and so cannot
+  * get easily selected by the PPD-support-free core filter functions
+  * in libcupsfilters.
+  *
+  * Usually, the media-col attribute does not need to get copied from
+  * printer attributes to job attributes, but having it in the job
+  * attributes tells the filters that the user has requested a page
+  * size, as at least some filters overtake the sizes of the input
+  * pages when the user does not request a page size.
+  */
+
+  page_size = cupsGetOption("PageSize", data->num_options, data->options);
+  media = cupsGetOption("media", data->num_options, data->options);
+  if ((page_size || media) &&
+      (attr = ippFindAttribute(data->printer_attrs, "media-col-default",
+                              IPP_TAG_ZERO)) != NULL)
+  {
+    /* We have already applied the settings of these options to the
+       PPD file and converted the PPD option settings into the printer
+       IPP attributes. The media size and margins corresponding to the
+       name supplied with these options is now included in the printer
+       IPP attributes as "media-col-default". Here we remove the
+       "PageSize" and "media" options and add "media-col" to the job
+       attributes as a copy of "media-col-default" in the printer
+       attributes. We do this only if the size specified by "PageSize"
+       or "media" is not a custom size ("Custom.XXxYYunit") as a
+       custom size cannot get marked in the PPD file and so not set as
+       default page size, so it does not make it into
+       media-col-default. In this case we only remove "media-col". */
+
+    int is_custom = 0;
+
+    if (page_size)
+    {
+      if (strncasecmp(page_size, "Custom.", 7) != 0)
+       data->num_options = cupsRemoveOption("PageSize", data->num_options,
+                                            &(data->options));
+      else
+       is_custom = 1;
+    }
+
+    if (media)
+    {
+      if ((val = strcasestr(media, "Custom.")) == NULL ||
+         (val != media && *(val - 1) != ','))
+       data->num_options = cupsRemoveOption("media", data->num_options,
+                                            &(data->options));
+      else
+       is_custom = 1;
+    }
+
+    data->num_options = cupsRemoveOption("media-col", data->num_options,
+                                         &(data->options));
+    ippDeleteAttribute(data->job_attrs,
+                      ippFindAttribute(data->job_attrs, "media-col",
+                                       IPP_TAG_ZERO));
+
+    if (!is_custom)
+    {
+      /* String from IPP attribute for option list */
+      ippAttributeString(attr, buf, sizeof(buf));
+      data->num_options = cupsAddOption("media-col", buf,
+                                       data->num_options, &(data->options));
+
+      /* Copy the default media-col */
+      col = ippGetCollection(attr, 0);
+      ippAddCollection(data->job_attrs, IPP_TAG_PRINTER, "media-col", col);
+    }
+  }
+
+ /*
+  * Find out whether the PDF filter (cfFilterPDFToPDF() or
+  * cfFilterImageToPDF()) should log the pages or whether the last
+  * filter (usually the printer driver) should do it.
+  */
+
+  if ((val = cupsGetOption("pdf-filter-page-logging",
+                          data->num_options, data->options)) == NULL ||
+      strcasecmp(val, "auto") == 0)
+  {
+    int page_logging = -1;
+    if (data->final_content_type == NULL)
+    {
+      /* Final data MIME type not known, we cannot determine
+        whether we have to log pages, so do not log. */
+      page_logging = 0;
+      if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                  "ppdFilterLoadPPD: No final data MIME type known, so we "
+                  "cannot determine whether the PDF filter has to log pages "
+                  "or not, so turning off page logging for the PDF filter.");
+    }
+    /* Proceed depending on number of cupsFilter(2) lines in PPD */
+    else if (ppd->num_filters == 0)
+    {
+      /* No filter line, manufacturer-supplied PostScript PPD
+        In this case cfFilterPSToPS, called by cfFilterPDFToPS, does the
+        logging */
+      page_logging = 0;
+    }
+    else
+    {
+      /* Filter(s) specified by filter line(s), determine the one which got
+        actually used via final data MIME type */
+      bool cupsfilter2 = (ppdFindAttr(ppd, "cupsFilter2", NULL) != NULL);
+      for (lastfilter = (char *)cupsArrayFirst(ppd->cache->filters);
+          lastfilter;
+          lastfilter = (char *)cupsArrayNext(ppd->cache->filters))
+      {
+       char *p = lastfilter;
+       if (cupsfilter2)
+       {
+         /* Skip first word as the final content type is the second */
+         while (!isspace(*p)) p ++;
+         while (isspace(*p)) p ++;
+       }
+       if (!strncasecmp(data->final_content_type, p,
+                        strlen(data->final_content_type))) {
+         break;
+       }
+      }
+    }
+    if (page_logging == -1)
+    {
+      if (lastfilter)
+      {
+       /* Get the name of the last filter, without mime type and cost */
+       char *p = lastfilter;
+       char *q = p + strlen(p) - 1;
+       while (!isspace(*q) && *q != '/') q --;
+       lastfilter = q + 1;
+       /* Check whether the PDF filter has to log */
+       if (!strcasecmp(lastfilter, "-"))
+       {
+         /* No filter defined in the PPD
+            If output data is PDF, cfFilterPDFToPDF() is last
+            filter (PDF printer) and has to log
+            If output data is Apple/PWG Raster or PCLm, cfFilter*ToRaster() is
+            last filter (Driverless IPP printer) and cfFilterPDFToPDF()
+            also has to log */
+         if (strcasestr(data->final_content_type, "/pdf") ||
+             strcasestr(data->final_content_type, "/vnd.cups-pdf") ||
+             strcasestr(data->final_content_type, "/pwg-raster") ||
+             strcasestr(data->final_content_type, "/urf") ||
+             strcasestr(data->final_content_type, "/pclm"))
+           page_logging = 1;
+         else
+           page_logging = 0;
+       }
+       else if (!strcasecmp(lastfilter, "pdftopdf") ||
+                !strcasecmp(lastfilter, "imagetopdf"))
+       {
+         /* cfFilterPDFToPDF() is last filter (PDF printer) */
+         page_logging = 1;
+       }
+       else if (!strcasecmp(lastfilter, "gstopxl"))
+       {
+         /* cfFilterGhostscript() with PCL-XL output is last filter,
+            this is a Ghostscript-based filter without access to the
+            pages of the file to be printed, so the PDF filter has to
+            log the pages */
+         page_logging = 1;
+       }
+       else if (!strcasecmp(lastfilter + strlen(lastfilter) - 8,
+                            "toraster") ||
+                !strcasecmp(lastfilter + strlen(lastfilter) - 5,
+                            "topwg"))
+       {
+         /* On IPP Everywhere printers which accept PWG Raster data one
+            of cfFilterGhostscript(), cfFilterPDFToRaster(), or
+            cfFilterMuPDFToPWG() is the last filter. These filters do not
+            log pages so the PDF filter has to do it */
+         page_logging = 1;
+       }
+       else if (!strcasecmp(lastfilter, "foomatic-rip"))
+       {
+         /* foomatic-rip is last filter, foomatic-rip is mainly used as
+            Ghostscript wrapper to use Ghostscript's built-in printer
+            drivers. Here there is also no access to the pages so that we
+            delegate the logging to the PDF filter */
+         page_logging = 1;
+       }
+       else if (!strcasecmp(lastfilter, "hpps"))
+       {
+         /* hpps is last filter, hpps is part of HPLIP and it is a bug that
+            it does not do the page logging. */
+         page_logging = 1;
+       }
+       else
+       {
+         /* All the other filters (printer drivers) log pages as expected. */
+         page_logging = 0;
+       }
+      }
+      else
+      {
+       if (log) log(ld, CF_LOGLEVEL_ERROR,
+                    "ppdFilterLoadPPD: Last filter could not get determined, "
+                    "page logging by the PDF filter turned off.");
+         page_logging = 0;
+      }
+      if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                  "ppdFilterLoadPPD: Last filter determined by the PPD: %s; "
+                  "Final data MIME type: %s => PDF filter will %slog pages in "
+                  "page_log.",
+                  (lastfilter ? lastfilter : "None"),
+                  (data->final_content_type ? data->final_content_type :
+                   "(not supplied)"),
+                  (page_logging == 0 ? "not " : ""));
+    }
+
+    /* Pass on the result as "pdf-filter-page-logging" option */
+    data->num_options = cupsAddOption("pdf-filter-page-logging",
+                                     (page_logging == 1 ? "On" : "Off"),
+                                     data->num_options, &(data->options));
+  }
+
+  return (0);
+}
+
+
+/*
+ * 'ppdFilterFreePPDFile()' - After being done with the filter
+ *                            functions free the memory used by the
+ *                            PPD file data in the data structure. If
+ *                            the pointer to the "libppd" is NULL, do
+ *                            nothing.
+ */
+
+void
+ppdFilterFreePPDFile(cf_filter_data_t *data) /* I - Job and printer data */
+{
+  ppd_filter_data_ext_t *filter_data_ext =
+    (ppd_filter_data_ext_t *)cfFilterDataRemoveExt(data,
+                                                  PPD_FILTER_DATA_EXT);
+
+  if (filter_data_ext)
+  {
+    if (filter_data_ext->ppd)
+      /* ppdClose() frees not only the main data structure but also the cache */
+      ppdClose(filter_data_ext->ppd);
+
+    if (filter_data_ext->ppdfile)
+      free(filter_data_ext->ppdfile);
+
+    free(filter_data_ext);
+
+    ppdFilterFreePPD(data);
+  }
+}
+
+
+/*
+ * 'ppdFilterFreePPD()' - After being done with the filter functions
+ *                        free the memory used by the PPD file data in
+ *                        the data structure. If the pointers to the
+ *                        data extracted from the PPD are NULL, do
+ *                        nothing.
+ */
+
+void
+ppdFilterFreePPD(cf_filter_data_t *data) /* I - Job and printer data */
+{
+  if (data->printer_attrs)
+  {
+    ippDelete(data->printer_attrs);
+    data->printer_attrs = NULL;
+  }
+
+  if (data->header)
+  {
+    free(data->header);
+    data->header = NULL;
+  }
+}
+
+
+/*
+ * 'get_env_var()' - Auxiliary function for ppdFilterExternalCUPS(), gets value of
+ *                   an environment variable in a list of environment variables
+ *                   as used by the execve() function
+ */
+
+static char *             /* O - The value, NULL if variable is not in list */
+get_env_var(char *name,   /* I - Name of environment variable to read */
+           char **env)   /* I - List of environment variable serttings */
+{
+  int i = 0;
+
+
+  if (env)
+    for (i = 0; env[i]; i ++)
+      if (strncmp(env[i], name, strlen(name)) == 0 &&
+         strlen(env[i]) > strlen(name) &&
+         env[i][strlen(name)] == '=')
+       return (env[i] + strlen(name) + 1);
+
+  return (NULL);
+}
+
+
+/*
+ * 'add_env_var()' - Auxiliary function for ppdFilterExternalCUPS(), adds/sets
+ *                   an environment variable in a list of environment variables
+ *                   as used by the execve() function
+ */
+
+static int                /* O - Index of where the new value got inserted in
+                                the list */
+add_env_var(char *name,   /* I - Name of environment variable to set */
+           char *value,  /* I - Value of environment variable to set */
+           char ***env)  /* I - List of environment variable serttings */
+{
+  char *p;
+  int i = 0,
+      name_len;
+
+
+  if (!name || !env || !name[0])
+    return (-1);
+
+  /* Assemble a "VAR=VALUE" string and the string length of "VAR" */
+  if ((p = strchr(name, '=')) != NULL)
+  {
+    /* User supplied "VAR=VALUE" as name and NULL as value */
+    if (value)
+      return (-1);
+    name_len = p - name;
+    p = strdup(name);
+  }
+  else
+  {
+    /* User supplied variable name and value as the name and as the value */
+    name_len = strlen(name);
+    p = (char *)calloc(strlen(name) + (value ? strlen(value) : 0) + 2,
+                      sizeof(char));
+    sprintf(p, "%s=%s", name, (value ? value : ""));
+  }
+
+  /* Check whether we already have this variable in the list and update its
+     value if it is there */
+  if (*env)
+    for (i = 0; (*env)[i]; i ++)
+      if (strncmp((*env)[i], p, name_len) == 0 && (*env)[i][name_len] == '=')
+      {
+       free((*env)[i]);
+       (*env)[i] = p;
+       return (i);
+      }
+
+  /* Add the variable as new item to the list */
+  *env = (char **)realloc(*env, (i + 2) * sizeof(char *));
+  (*env)[i] = p;
+  (*env)[i + 1] = NULL;
+  return (i);
+}
+
+
+/*
+ * 'sanitize_device_uri()' - Remove authentication info from a device URI
+ */
+
+static char *                           /* O - Sanitized URI */
+sanitize_device_uri(const char *uri,   /* I - Device URI */
+                   char *buf,          /* I - Buffer for output */
+                   size_t bufsize)     /* I - Size of buffer */
+{
+  char *start,                         /* Start of data after scheme */
+       *slash,                         /* First slash after scheme:// */
+       *ptr;                           /* Pointer into user@host:port part */
+
+
+  /* URI not supplied */
+  if (!uri)
+    return (NULL);
+
+  /* Copy the device URI to a temporary buffer so we can sanitize any auth
+   * info in it... */
+  strncpy(buf, uri, bufsize);
+
+  /* Find the end of the scheme:// part... */
+  if ((ptr = strchr(buf, ':')) != NULL)
+  {
+    for (start = ptr + 1; *start; start ++)
+      if (*start != '/')
+        break;
+
+    /* Find the next slash (/) in the URI... */
+    if ((slash = strchr(start, '/')) == NULL)
+      slash = start + strlen(start);   /* No slash, point to the end */
+
+    /* Check for an @ sign before the slash... */
+    if ((ptr = strchr(start, '@')) != NULL && ptr < slash)
+    {
+      /* Found an @ sign and it is before the resource part, so we have
+        an authentication string.  Copy the remaining URI over the
+        authentication string... */
+      memmove(start, ptr + 1, strlen(ptr + 1) + 1);
+    }
+  }
+
+  /* Return the sanitized URI... */
+  return (buf);
+}
+
+
+/*
+ * 'fcntl_add_cloexec()' - Add FD_CLOEXEC flag to the flags
+ *                         of a given file descriptor.
+ */
+
+static int                /* Return value of fcntl() */
+fcntl_add_cloexec(int fd) /* File descriptor to add FD_CLOEXEC to */
+{
+  return fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
+}
+
+
+/*
+ * 'fcntl_add_nonblock()' - Add O_NONBLOCK flag to the flags
+ *                          of a given file descriptor.
+ */
+
+static int                 /* Return value of fcntl() */
+fcntl_add_nonblock(int fd) /* File descriptor to add O_NONBLOCK to */
+{
+  return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
+}
+
+
+/*
+ * 'ppdFilterExternalCUPS()' - Filter function which calls an external,
+ *                          classic CUPS filter, for example a
+ *                          (proprietary) printer driver which cannot
+ *                          be converted to a filter function or is to
+ *                          awkward or risky to convert for example
+ *                          when the printer hardware is not available
+ *                          for testing
+ */
+
+int                                     /* O - Error status */
+ppdFilterExternalCUPS(int inputfd,      /* I - File descriptor input stream */
+                  int outputfd,        /* I - File descriptor output stream */
+                  int inputseekable,   /* I - Is input stream seekable? */
+                  cf_filter_data_t *data, /* I - Job and printer data */
+                  void *parameters)    /* I - Filter-specific parameters */
+{
+  ppd_filter_data_ext_t *filter_data_ext =
+    (ppd_filter_data_ext_t *)cfFilterDataGetExt(data,
+                                               PPD_FILTER_DATA_EXT);
+  ppd_filter_external_cups_t *params = (ppd_filter_external_cups_t *)parameters;
+  int           i;
+  int           is_backend = 0;      /* Do we call a CUPS backend? */
+  int          pid,                 /* Process ID of filter */
+                stderrpid,           /* Process ID for stderr logging process */
+                wpid;                /* PID reported as terminated */
+  int          fd;                  /* Temporary file descriptor */
+  int           backfd, sidefd;      /* file descriptors for back and side
+                                        channels */
+  int           stderrpipe[2];       /* Pipe to log stderr */
+  cups_file_t   *fp;                 /* File pointer to read log lines */
+  char          buf[2048];           /* Log line buffer */
+  cf_loglevel_t log_level;           /* Log level of filter's log message */
+  char          *ptr1, *ptr2,
+                *msg,                /* Filter log message */
+                *filter_name;        /* Filter name for logging */
+  char          filter_path[1024];   /* Full path of the filter */
+  char          **argv,                     /* Command line args for filter */
+                **envp = NULL;       /* Environment variables for filter */
+  int           num_all_options = 0;
+  cups_option_t *all_options = NULL;
+  char          job_id_str[16],
+                copies_str[16],
+                *options_str = NULL;
+  cups_option_t *opt;
+  int status = 65536;
+  int wstatus;
+  cf_logfunc_t log = data->logfunc;
+  void          *ld = data->logdata;
+  cf_filter_iscanceledfunc_t iscanceled = data->iscanceledfunc;
+  void          *icd = data->iscanceleddata;
+
+
+  if (!params->filter || !params->filter[0]) {
+    if (log) log(ld, CF_LOGLEVEL_ERROR,
+                "ppdFilterExternalCUPS: Filter executable path/command not specified");
+    return (1);
+  }
+
+  /* Check whether back/side channel FDs are valid and not all-zero
+     from calloc'ed filter_data */
+  if (data->back_pipe[0] == 0 && data->back_pipe[1] == 0)
+    data->back_pipe[0] = data->back_pipe[1] = -1;
+  if (data->side_pipe[0] == 0 && data->side_pipe[1] == 0)
+    data->side_pipe[0] = data->side_pipe[1] = -1;
+
+  /* Select the correct end of the back/side channel pipes:
+     [0] for filters, [1] for backends */
+  is_backend = (params->is_backend ? 1 : 0);
+  backfd = data->back_pipe[is_backend];
+  sidefd = data->side_pipe[is_backend];
+
+  /* Filter name for logging */
+  if ((filter_name = strrchr(params->filter, '/')) != NULL)
+    filter_name ++;
+  else
+    filter_name = (char *)params->filter;
+
+ /*
+  * Ignore broken pipe signals...
+  */
+
+  signal(SIGPIPE, SIG_IGN);
+
+ /*
+  * Copy the current environment variables and add some important ones
+  * needed for correct execution of the CUPS filter (which is not running
+  * out of CUPS here)
+  */
+
+  /* Some default environment variables from CUPS, will get overwritten
+     if also defined in the environment in which the caller is started
+     or in the parameters */
+  add_env_var("CUPS_DATADIR", CUPS_DATADIR, &envp);
+  add_env_var("CUPS_SERVERBIN", CUPS_SERVERBIN, &envp);
+  add_env_var("CUPS_SERVERROOT", CUPS_SERVERROOT, &envp);
+  add_env_var("CUPS_STATEDIR", CUPS_STATEDIR, &envp);
+  add_env_var("SOFTWARE", "CUPS/2.5.99", &envp); /* Last CUPS with PPDs */
+  if (data->content_type)
+    add_env_var("CONTENT_TYPE", data->content_type, &envp);
+  if (data->final_content_type)
+    add_env_var("FINAL_CONTENT_TYPE", data->final_content_type, &envp);
+
+  /* Copy the environment in which the caller got started */
+  if (environ)
+    for (i = 0; environ[i]; i ++)
+      add_env_var(environ[i], NULL, &envp);
+
+  /* Set the environment variables given by the parameters */
+  if (params->envp)
+    for (i = 0; params->envp[i]; i ++)
+      add_env_var(params->envp[i], NULL, &envp);
+
+  /* Add CUPS_SERVERBIN to the beginning of PATH */
+  ptr1 = get_env_var("PATH", envp);
+  ptr2 = get_env_var("CUPS_SERVERBIN", envp);
+  if (ptr2 && ptr2[0])
+  {
+    if (ptr1 && ptr1[0])
+    {
+      snprintf(buf, sizeof(buf), "%s/%s:%s",
+              ptr2, params->is_backend ? "backend" : "filter", ptr1);
+      ptr1 = buf;
+    }
+    else
+      ptr1 = ptr2;
+    add_env_var("PATH", ptr1, &envp);
+  }
+
+  if (params->is_backend < 2) /* Not needed in discovery mode of backend */
+  {
+    /* Print queue name from filter data */
+    if (data->printer)
+      add_env_var("PRINTER", data->printer, &envp);
+    else
+      add_env_var("PRINTER", "Unknown", &envp);
+
+    /* PPD file path/name from filter data, required for most CUPS filters */
+    if (filter_data_ext->ppdfile)
+      add_env_var("PPD", filter_data_ext->ppdfile, &envp);
+
+    /* Device URI from parameters */
+    if (params->is_backend && params->device_uri)
+      add_env_var("DEVICE_URI", (char *)params->device_uri, &envp);
+  }
+
+  /* Determine full path for the filter */
+  if (params->filter[0] == '/' ||
+      (ptr1 = get_env_var("CUPS_SERVERBIN", envp)) == NULL || !ptr1[0])
+    strncpy(filter_path, params->filter, sizeof(filter_path) - 1);
+  else
+    snprintf(filter_path, sizeof(filter_path), "%s/%s/%s", ptr1,
+            params->is_backend ? "backend" : "filter", params->filter);
+
+  /* Log the resulting list of environment variable settings
+     (with any authentication info removed)*/
+  if (log)
+  {
+    for (i = 0; envp[i]; i ++)
+      if (!strncmp(envp[i], "AUTH_", 5))
+       log(ld, CF_LOGLEVEL_DEBUG, "ppdFilterExternalCUPS (%s): envp[%d]: AUTH_%c****",
+           filter_name, i, envp[i][5]);
+      else if (!strncmp(envp[i], "DEVICE_URI=", 11))
+       log(ld, CF_LOGLEVEL_DEBUG, "ppdFilterExternalCUPS (%s): envp[%d]: DEVICE_URI=%s",
+           filter_name, i, sanitize_device_uri(envp[i] + 11,
+                                               buf, sizeof(buf)));
+      else
+       log(ld, CF_LOGLEVEL_DEBUG, "ppdFilterExternalCUPS (%s): envp[%d]: %s",
+           filter_name, i, envp[i]);
+  }
+
+  if (params->is_backend < 2) {
+   /*
+    * Filter or backend for job execution
+    */
+
+   /*
+    * Join the options from the filter data and from the parameters
+    * If an option is present in both filter data and parameters, the
+    * value in the filter data has priority
+    */
+
+    for (i = 0, opt = params->options; i < params->num_options; i ++, opt ++)
+      num_all_options = cupsAddOption(opt->name, opt->value, num_all_options,
+                                     &all_options);
+    for (i = 0, opt = data->options; i < data->num_options; i ++, opt ++)
+      num_all_options = cupsAddOption(opt->name, opt->value, num_all_options,
+                                     &all_options);
+
+   /*
+    * Create command line arguments for the CUPS filter
+    */
+
+    argv = (char **)calloc(7, sizeof(char *));
+
+    /* Numeric parameters */
+    snprintf(job_id_str, sizeof(job_id_str) - 1, "%d",
+            data->job_id > 0 ? data->job_id : 1);
+    snprintf(copies_str, sizeof(copies_str) - 1, "%d",
+            data->copies > 0 ? data->copies : 1);
+
+    /* Options, build string of "Name1=Value1 Name2=Value2 ..." but use
+       "Name" and "noName" instead for boolean options */
+    for (i = 0, opt = all_options; i < num_all_options; i ++, opt ++) {
+      if (strcasecmp(opt->value, "true") == 0 ||
+         strcasecmp(opt->value, "false") == 0) {
+       options_str =
+         (char *)realloc(options_str,
+                         ((options_str ? strlen(options_str) : 0) +
+                          strlen(opt->name) +
+                          (strcasecmp(opt->value, "false") == 0 ? 2 : 0) + 2) *
+                         sizeof(char));
+       if (i == 0)
+         options_str[0] = '\0';
+       sprintf(options_str + strlen(options_str), " %s%s",
+               (strcasecmp(opt->value, "false") == 0 ? "no" : ""), opt->name);
+      } else {
+       options_str =
+         (char *)realloc(options_str,
+                         ((options_str ? strlen(options_str) : 0) +
+                          strlen(opt->name) + strlen(opt->value) + 3) *
+                         sizeof(char));
+       if (i == 0)
+         options_str[0] = '\0';
+       sprintf(options_str + strlen(options_str), " %s=%s", opt->name, opt->value);
+      }
+    }
+
+    /* Find DEVICE_URI environment variable */
+    if (params->is_backend && !params->device_uri)
+      for (i = 0; envp[i]; i ++)
+       if (strncmp(envp[i], "DEVICE_URI=", 11) == 0)
+         break;
+
+    /* Add items to array */
+    argv[0] = strdup((params->is_backend && params->device_uri ?
+                     (char *)sanitize_device_uri(params->device_uri,
+                                                 buf, sizeof(buf)) :
+                     (params->is_backend && envp[i] ?
+                      (char *)sanitize_device_uri(envp[i] + 11,
+                                                  buf, sizeof(buf)) :
+                      (data->printer ? data->printer :
+                       (char *)params->filter))));
+    argv[1] = job_id_str;
+    argv[2] = data->job_user ? data->job_user : "Unknown";
+    argv[3] = data->job_title ? data->job_title : "Untitled";
+    argv[4] = copies_str;
+    argv[5] = options_str ? options_str + 1 : "";
+    argv[6] = NULL;
+
+    /* Log the arguments */
+    if (log)
+      for (i = 0; argv[i]; i ++)
+       log(ld, CF_LOGLEVEL_DEBUG, "ppdFilterExternalCUPS (%s): argv[%d]: %s",
+           filter_name, i, argv[i]);
+  } else {
+   /*
+    * Backend in device discovery mode
+    */
+
+    argv = (char **)calloc(2, sizeof(char *));
+    argv[0] = strdup((char *)params->filter);
+    argv[1] = NULL;
+  }
+
+ /*
+  * Execute the filter
+  */
+
+  if (pipe(stderrpipe) < 0) {
+    if (log) log(ld, CF_LOGLEVEL_ERROR,
+                "ppdFilterExternalCUPS (%s): Could not create pipe for stderr: %s",
+                filter_name, strerror(errno));
+    return (1);
+  }
+
+  if ((pid = fork()) == 0) {
+   /*
+    * Child process goes here...
+    *
+    * Update stdin/stdout/stderr as needed...
+    */
+
+    if (inputfd != 0) {
+      if (inputfd < 0) {
+        inputfd = open("/dev/null", O_RDONLY);
+       if (log) log(ld, CF_LOGLEVEL_ERROR,
+                    "ppdFilterExternalCUPS (%s): No input file descriptor supplied for CUPS filter - %s",
+                  filter_name, strerror(errno));
+      }
+
+      if (inputfd > 0) {
+       fcntl_add_cloexec(inputfd);
+        if (dup2(inputfd, 0) < 0) {
+         if (log) log(ld, CF_LOGLEVEL_ERROR,
+                      "ppdFilterExternalCUPS (%s): Failed to connect input file descriptor with CUPS filter's stdin - %s",
+                      filter_name, strerror(errno));
+         goto fd_error;
+       } else
+         if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                      "ppdFilterExternalCUPS (%s): Connected input file descriptor %d to CUPS filter's stdin.",
+                      filter_name, inputfd);
+       close(inputfd);
+      }
+    } else
+      if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                  "ppdFilterExternalCUPS (%s): Input comes from stdin, letting the filter grab stdin directly",
+                  filter_name);
+
+    if (outputfd != 1) {
+      if (outputfd < 0)
+        outputfd = open("/dev/null", O_WRONLY);
+
+      if (outputfd > 1) {
+       fcntl_add_cloexec(outputfd);
+       dup2(outputfd, 1);
+       close(outputfd);
+      }
+    }
+
+    if (strcasestr(params->filter, "gziptoany")) {
+      /* Send stderr to the Nirwana if we are running gziptoany, as
+        gziptoany emits a false "PAGE: 1 1" */
+      if ((fd = open("/dev/null", O_RDWR)) > 2) {
+       fcntl_add_cloexec(fd);
+       dup2(fd, 2);
+       close(fd);
+      } else
+        close(fd);
+    } else {
+      /* Send stderr into pipe for logging */
+      fcntl_add_cloexec(stderrpipe[1]);
+      dup2(stderrpipe[1], 2);
+      fcntl_add_nonblock(2);
+    }
+    close(stderrpipe[0]);
+    close(stderrpipe[1]);
+
+    if (params->is_backend < 2) { /* Not needed in discovery mode of backend */
+      /* Back channel */
+      if (backfd != 3 && backfd >= 0) {
+       dup2(backfd, 3);
+       close(backfd);
+       fcntl_add_nonblock(3);
+      } else if (backfd < 0) {
+       if ((backfd = open("/dev/null", O_RDWR)) > 3) {
+         dup2(backfd, 3);
+         close(backfd);
+       } else
+         close(backfd);
+       fcntl_add_nonblock(3);
+      }
+
+      /* Side channel */
+      if (sidefd != 4 && sidefd >= 0) {
+       dup2(sidefd, 4);
+       close(sidefd);
+       fcntl_add_nonblock(4);
+      } else if (sidefd < 0) {
+       if ((sidefd = open("/dev/null", O_RDWR)) > 4) {
+         dup2(sidefd, 4);
+         close(sidefd);
+       } else
+         close(sidefd);
+       fcntl_add_nonblock(4);
+      }
+    }
+
+   /*
+    * Execute command...
+    */
+
+    execve(filter_path, argv, envp);
+
+    if (log) log(ld, CF_LOGLEVEL_ERROR,
+                "ppdFilterExternalCUPS (%s): Execution of %s %s failed - %s",
+                filter_name, params->is_backend ? "backend" : "filter",
+                filter_path, strerror(errno));
+
+  fd_error:
+    exit(errno);
+  } else if (pid > 0) {
+    if (log) log(ld, CF_LOGLEVEL_INFO,
+                "ppdFilterExternalCUPS (%s): %s (PID %d) started.",
+                filter_name, filter_path, pid);
+  } else {
+    if (log) log(ld, CF_LOGLEVEL_ERROR,
+                "ppdFilterExternalCUPS (%s): Unable to fork process for %s %s",
+                filter_name, params->is_backend ? "backend" : "filter",
+                filter_path);
+    close(stderrpipe[0]);
+    close(stderrpipe[1]);
+    status = 1;
+    goto out;
+  }
+  if (inputfd >= 0)
+    close(inputfd);
+  if (outputfd >= 0)
+    close(outputfd);
+
+ /*
+  * Log the filter's stderr
+  */
+
+  if ((stderrpid = fork()) == 0) {
+   /*
+    * Child process goes here...
+    */
+
+    close(stderrpipe[1]);
+    fp = cupsFileOpenFd(stderrpipe[0], "r");
+    while (cupsFileGets(fp, buf, sizeof(buf)))
+      if (log) {
+       if (strncmp(buf, "DEBUG: ", 7) == 0) {
+         log_level = CF_LOGLEVEL_DEBUG;
+         msg = buf + 7;
+       } else if (strncmp(buf, "DEBUG2: ", 8) == 0) {
+         log_level = CF_LOGLEVEL_DEBUG;
+         msg = buf + 8;
+       } else if (strncmp(buf, "INFO: ", 6) == 0) {
+         log_level = CF_LOGLEVEL_INFO;
+         msg = buf + 6;
+       } else if (strncmp(buf, "WARNING: ", 9) == 0) {
+         log_level = CF_LOGLEVEL_WARN;
+         msg = buf + 9;
+       } else if (strncmp(buf, "ERROR: ", 7) == 0) {
+         log_level = CF_LOGLEVEL_ERROR;
+         msg = buf + 7;
+       } else if (strncmp(buf, "PAGE: ", 6) == 0 ||
+                  strncmp(buf, "ATTR: ", 6) == 0 ||
+                  strncmp(buf, "STATE: ", 7) == 0 ||
+                  strncmp(buf, "PPD: ", 5) == 0) {
+         log_level = CF_LOGLEVEL_CONTROL;
+         msg = buf;
+       } else {
+         log_level = CF_LOGLEVEL_DEBUG;
+         msg = buf;
+       }
+       if (log_level == CF_LOGLEVEL_CONTROL)
+         log(ld, log_level, msg);
+       else
+         log(ld, log_level, "ppdFilterExternalCUPS (%s): %s", filter_name, msg);
+      }
+    cupsFileClose(fp);
+    /* No need to close the fd stderrpipe[0], as cupsFileClose(fp) does this
+       already */
+    /* Ignore errors of the logging process */
+    exit(0);
+  } else if (stderrpid > 0) {
+    if (log) log(ld, CF_LOGLEVEL_INFO,
+                "ppdFilterExternalCUPS (%s): Logging (PID %d) started.",
+                filter_name, stderrpid);
+  } else {
+    if (log) log(ld, CF_LOGLEVEL_ERROR,
+                "ppdFilterExternalCUPS (%s): Unable to fork process for logging",
+                filter_name);
+    close(stderrpipe[0]);
+    close(stderrpipe[1]);
+    status = 1;
+    goto out;
+  }
+
+  close(stderrpipe[0]);
+  close(stderrpipe[1]);
+
+ /*
+  * Wait for filter and logging processes to finish
+  */
+
+  status = 0;
+
+  while (pid > 0 || stderrpid > 0) {
+    if ((wpid = wait(&wstatus)) < 0) {
+      if (errno == EINTR && iscanceled && iscanceled(icd)) {
+       if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                    "ppdFilterExternalCUPS (%s): Job canceled, killing %s ...",
+                    filter_name, params->is_backend ? "backend" : "filter");
+       kill(pid, SIGTERM);
+       pid = -1;
+       kill(stderrpid, SIGTERM);
+       stderrpid = -1;
+       break;
+      } else
+       continue;
+    }
+
+    /* How did the filter terminate */
+    if (wstatus) {
+      if (WIFEXITED(wstatus)) {
+       /* Via exit() anywhere or return() in the main() function */
+       if (log) log(ld, CF_LOGLEVEL_ERROR,
+                    "ppdFilterExternalCUPS (%s): %s (PID %d) stopped with status %d",
+                    filter_name,
+                    (wpid == pid ?
+                     (params->is_backend ? "Backend" : "Filter") :
+                     "Logging"),
+                    wpid, WEXITSTATUS(wstatus));
+      } else {
+       /* Via signal */
+       if (log) log(ld, CF_LOGLEVEL_ERROR,
+                    "ppdFilterExternalCUPS (%s): %s (PID %d) crashed on signal %d",
+                    filter_name,
+                    (wpid == pid ?
+                     (params->is_backend ? "Backend" : "Filter") :
+                     "Logging"),
+                    wpid, WTERMSIG(wstatus));
+      }
+      status = 1;
+    } else {
+      if (log) log(ld, CF_LOGLEVEL_INFO,
+                  "ppdFilterExternalCUPS (%s): %s (PID %d) exited with no errors.",
+                  filter_name,
+                  (wpid == pid ?
+                   (params->is_backend ? "Backend" : "Filter") : "Logging"),
+                  wpid);
+    }
+    if (wpid == pid)
+      pid = -1;
+    else  if (wpid == stderrpid)
+      stderrpid = -1;
+  }
+
+ /*
+  * Clean up
+  */
+
+ out:
+  cupsFreeOptions(num_all_options, all_options);
+  if (options_str)
+    free(options_str);
+  free(argv[0]);
+  free(argv);
+  for (i = 0; envp[i]; i ++)
+    free(envp[i]);
+  free(envp);
+
+  return (status);
+}
+
+
+/*
+ * 'ppdFilterEmitJCL()' - Wrapper for the PDF-generating filter
+ *                        functions to emit JCL (PJL) before and after
+ *                        the PDF output.
+ */
+
+int                                   /* O - Error status */
+ppdFilterEmitJCL(int inputfd,         /* I - File descriptor input stream */
+                int outputfd,        /* I - File descriptor output stream */
+                int inputseekable,   /* I - Is input stream seekable? */
+                cf_filter_data_t *data, /* I - Job and printer data */
+                void *parameters,    /* I - Filter-specific parameters */
+                cf_filter_function_t orig_filter)
+{
+  ppd_filter_data_ext_t *filter_data_ext =
+    (ppd_filter_data_ext_t *)cfFilterDataGetExt(data,
+                                               PPD_FILTER_DATA_EXT);
+  const char    *val;
+  int           streaming = 0;
+  int           ret = 1;
+  size_t        bytes;
+  char          buf[8192];
+  int           outfds[2], pid = -1;
+  FILE          *fp;
+  int           hw_copies = 1;
+  bool          hw_collate = false;
+  int          status,          /* Exit status */
+                retval = 1;     /* Return value */
+  cf_logfunc_t  log = data->logfunc;
+  void          *ld = data->logdata;
+
+
+ /*
+  * Check whether we are in streaming mode (cfFilterPDFToPDF() only)
+  *
+  * If we are in streaming mode of cfFilterPDFToPDF() we only apply
+  * JCL and do not run the job through cfFilterPDFToPDF() itself (so
+  * no page management, form flattening, page size/orientation
+  * adjustment, ...)
+  */
+
+  if (orig_filter == cfFilterPDFToPDF &&
+      (val = cupsGetOption("filter-streaming-mode",
+                          data->num_options, data->options)) != NULL &&
+      (strcasecmp(val, "false") && strcasecmp(val, "off") &
+       strcasecmp(val, "no")))
+  {
+    streaming = 1;
+    if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                "ppdFilterEmitJCL: Streaming mode: No PDF processing, only adding of JCL");
+  }
+
+ /*
+  * Call the original filter function without forking if we suppress
+  * JCL output via option...
+  */
+
+  if ((val = cupsGetOption("emit-jcl",
+                          data->num_options, data->options)) != NULL &&
+      (strcasecmp(val, "false") == 0 || strcasecmp(val, "off") == 0 ||
+       strcasecmp(val, "no") == 0))
+  {
+    if (!streaming)
+      /* Call actual filter function from libcupsfilters */
+      ret = orig_filter(inputfd, outputfd, inputseekable, data, parameters);
+    else
+    {
+      /* Just pass through the data unchanged... */
+      fp = fdopen(outputfd, "w");
+      while ((bytes = read(inputfd, buf, sizeof(buf))) > 0)
+       fwrite(buf, 1, bytes, fp);
+      close(inputfd);
+      fclose(fp);
+      ret = 0;
+    }
+    return (ret);
+  }
+
+  if (!streaming)
+  {
+   /*
+    * Create pipe for output of original filter function...
+    */
+
+    if (pipe(outfds) < 0)
+    {
+      if (log) log(ld, CF_LOGLEVEL_ERROR,
+                  "ppdFilterEmitJCL: Could not create pipe for ouput: %s",
+                  strerror(errno));
+      return (1);
+    }
+
+   /*
+    * Fork child process for original filter function...
+    */
+
+    if ((pid = fork()) == 0)
+    {
+      /* Send output into pipe for adding JCL */
+      fcntl_add_cloexec(outfds[1]);
+      close(outfds[0]);
+
+      /* Call actual filter function from libcupsfilters */
+      ret = orig_filter(inputfd, outfds[1], inputseekable, data, parameters);
+
+      exit(ret);
+    }
+    else if (pid > 0)
+    {
+      if (log) log(ld, CF_LOGLEVEL_INFO,
+                  "ppdFilterEmitJCL: Filter function (PID %d) started.",
+                  pid);
+    }
+    else
+    {
+      if (log) log(ld, CF_LOGLEVEL_ERROR,
+                "ppdFilterEmitJCL: Unable to fork process for filter function.");
+      close(outfds[0]);
+      close(outfds[1]);
+      retval = 1;
+      goto out;
+    }
+
+    if (inputfd >= 0)
+      close(inputfd);
+    close(outfds[1]);
+  }
+  else
+
+   /*
+    * In Streaming mode we simply copy the input
+    */
+
+    outfds[0] = inputfd;
+
+ /*
+  * Check options for caller's instructions about hardware copies/collate
+  */
+
+  hw_copies =
+    ((val = cupsGetOption("hardware-copies",
+                         data->num_options, data->options)) != NULL &&
+     (strcasecmp(val, "true") == 0 || strcasecmp(val, "on") == 0 ||
+      strcasecmp(val, "yes") == 0)) ?
+    data->copies : 1;
+
+  hw_collate =
+    (hw_copies > 1 &&
+     (val = cupsGetOption("hardware-collate",
+                         data->num_options, data->options)) != NULL &&
+     (strcasecmp(val, "true") == 0 || strcasecmp(val, "on") == 0 ||
+      strcasecmp(val, "yes") == 0));
+
+ /*
+  * Assemble the output: Exit server, JCL preamble, PDF output, JCL postamble
+  */
+
+  fp = fdopen(outputfd, "w");
+  ppdEmit(filter_data_ext->ppd, fp, PPD_ORDER_EXIT);
+  ppdEmitJCLPDF(filter_data_ext->ppd, fp,
+               data->job_id, data->job_user, data->job_title,
+               hw_copies, hw_collate);
+  while ((bytes = read(outfds[0], buf, sizeof(buf))) > 0)
+    fwrite(buf, 1, bytes, fp);
+  close(outfds[0]);
+  ppdEmitJCLEnd(filter_data_ext->ppd, fp);
+  fclose(fp);
+
+  if (!streaming)
+  {
+   /*
+    * Wait for filter process to finish
+    */
+
+  retry_wait:
+    if (waitpid (pid, &status, 0) == -1)
+    {
+      if (errno == EINTR)
+       goto retry_wait;
+      if (log)
+       log(ld, CF_LOGLEVEL_DEBUG,
+           "ppdFilterEmitJCL: Filter function (PID %d) stopped with an error: %s!",
+           pid, strerror(errno));
+      goto out;
+    }
+
+    if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                "ppdFilterEmitJCL: Filter function (PID %d) exited with no errors.",
+                pid);
+
+    /* How did the filter function terminate */
+    if (WIFEXITED(status))
+      /* Via exit() anywhere or return() in the main() function */
+      retval = WEXITSTATUS(status);
+    else if (WIFSIGNALED(status))
+      /* Via signal */
+      retval = 256 * WTERMSIG(status);
+  }
+  else
+    retval = 0;
+
+ out:
+  return (retval);
+}
+
+
+/*
+ * 'ppdFilterImageToPDF()' - Wrapper for the filter function
+ *                           cfFilterImageToPDF() to add PPD file
+ *                           support to it.
+ */
+
+int                                       /* O - Error status */
+ppdFilterImageToPDF(int inputfd,          /* I - File descriptor input stream */
+                   int outputfd,         /* I - File descriptor output stream*/
+                   int inputseekable,    /* I - Is input stream seekable? */
+                   cf_filter_data_t *data, /* I - Job and printer data */
+                   void *parameters)     /* I - Filter-specific parameters */
+{
+  return ppdFilterEmitJCL(inputfd, outputfd, inputseekable, data,
+                         parameters, cfFilterImageToPDF);
+}
+
+
+/*
+ * 'ppdFilterPDFtoPDF()' - Wrapper for the filter function 
+ *                         cfFilterPDFtoPDF() to add PPD file
+ *                         support to it.
+ */
+
+int                                    /* O - Error status */
+ppdFilterPDFToPDF(int inputfd,         /* I - File descriptor input stream */
+                 int outputfd,        /* I - File descriptor output stream */
+                 int inputseekable,   /* I - Is input stream seekable? */
+                 cf_filter_data_t *data, /* I - Job and printer data */
+                 void *parameters)    /* I - Filter-specific parameters */
+{
+  return ppdFilterEmitJCL(inputfd, outputfd, inputseekable, data,
+                         parameters, cfFilterPDFToPDF);
+}
+
+
+/*
+ * 'ppdFilterUniversal()' - Wrapper for the filter function
+ *                          cfFilterUniversal() to add PPD file
+ *                          support to it.
+ */
+
+int                                     /* O - Error status */
+ppdFilterUniversal(int inputfd,         /* I - File descriptor input stream */
+                  int outputfd,        /* I - File descriptor output stream*/
+                  int inputseekable,   /* I - Is input stream seekable? */
+                  cf_filter_data_t *data, /* I - Job and printer data */
+                  void *parameters)    /* I - Filter-specific parameters */
+{
+  ppd_filter_data_ext_t *filter_data_ext =
+    (ppd_filter_data_ext_t *)cfFilterDataGetExt(data,
+                                               PPD_FILTER_DATA_EXT);
+  char *input;
+  char *final_output;
+  char output[256];
+  cf_filter_universal_parameter_t universal_parameters;
+  ppd_file_t *ppd;
+  ppd_cache_t *cache;
+  cups_array_t *filter_chain;
+  cf_filter_filter_in_chain_t extra_filter, universal_filter;
+  int ret;
+  cf_logfunc_t log = data->logfunc;
+  void *ld = data->logdata;
+
+
+  universal_parameters = *(cf_filter_universal_parameter_t *)parameters;
+  input = data->content_type;
+  if (input == NULL)
+  {
+    if (log) log(ld, CF_LOGLEVEL_ERROR,
+                "ppdFilterUniversal: No input data format supplied.");
+    return (1);
+  }
+
+  final_output = data->final_content_type;
+  if (final_output == NULL)
+  {
+    final_output = universal_parameters.actual_output_type;
+    if (final_output == NULL)
+    {
+      if (log) log(ld, CF_LOGLEVEL_ERROR,
+                  "ppdFilterUniversal: No output data format supplied.");
+      return (1);
+    }
+  }
+
+  ppd = filter_data_ext->ppd;
+
+  if (universal_parameters.actual_output_type)
+    strncpy(output, universal_parameters.actual_output_type,
+           sizeof(output) - 1);
+  else if(ppd)
+  {
+    strncpy(output, data->final_content_type, sizeof(output) - 1);
+
+    cache = ppd ? ppd->cache : NULL;
+
+    /* Check whether our output format (under CUPS it is taken from
+       the FINAL_CONTENT_TYPE env variable) is the destination format
+       (2nd word) of a "*cupsFilter2: ..." line (string has 4 words),
+       in this case the specified filter (4th word) does the last
+       step, converting from the input format (1st word) of the line
+       to the destination format and so we only need to convert to the
+       input format. In this case we need to correct our output
+       format.
+
+       If there is more than one line with the given output format and
+       an inpout format we can produce, we select the one with the
+       lowest cost value (3rd word) as this is the one which CUPS
+       should have chosen for this job.
+
+       If we have "*cupsFilter: ..." lines (without "2", string with 3
+       words) we do not need to do anything special, as the input
+       format specified is the FIMAL_CONTENT_TYPE which CUPS supplies
+       to us and into which we have to convert. So we quit parsing if
+       the first line has only 3 words, as if CUPS uses the
+       "*cupsFilter: ..."  lines only if there is no "*cupsFilter2:
+       ..." line min the PPD, so if we encounter a line with only 3
+       words the other lines will have only 3 words, too and nothing
+       has to be done. */
+
+    if (ppd && ppd->num_filters && cache)
+    {
+      int lowest_cost = INT_MAX;
+      char *filter;
+
+      if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                  "ppdFilterUniversal: \"*cupsFilter(2): ...\" lines in the PPD file:");
+
+      for (filter = (char *)cupsArrayFirst(cache->filters);
+          filter;
+          filter = (char *)cupsArrayNext(cache->filters))
+      {
+       char buf[256];
+       char *ptr,
+         *in = NULL,
+          *out = NULL,
+         *coststr = NULL;
+       int cost;
+
+       if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                    "ppdFilterUniversal:    %s", filter);
+
+       /* String of the "*cupsfilter:" or "*cupsfilter2:" line */
+       strncpy(buf, filter, sizeof(buf) - 1);
+
+       /* Separate the words */
+       in = ptr = buf;
+       while (*ptr && !isspace(*ptr)) ptr ++;
+       if (!*ptr) goto error;
+       *ptr = '\0';
+       ptr ++;
+       while (*ptr && isspace(*ptr)) ptr ++;
+       if (!*ptr) goto error;
+       out = ptr;
+       while (*ptr && !isspace(*ptr)) ptr ++;
+       if (!*ptr) goto error;
+       *ptr = '\0';
+       ptr ++;
+       while (*ptr && isspace(*ptr)) ptr ++;
+       if (!*ptr) goto error;
+       coststr = ptr;
+       if (!isdigit(*ptr)) goto error;
+       while (*ptr && !isspace(*ptr)) ptr ++;
+       if (!*ptr) goto error;
+       *ptr = '\0';
+       ptr ++;
+       while (*ptr && isspace(*ptr)) ptr ++;
+       if (!*ptr) goto error;
+       cost = atoi(coststr);
+
+       /* Valid "*cupsFilter2: ..." line ... */
+       if (/* Must be of lower cost than what we selected before */
+           cost < lowest_cost &&
+           /* Must have our FINAL_CONTENT_TYPE as output */
+           strcasecmp(out, final_output) == 0 &&
+           /* Must have as input a format we are able to produce */
+           (strcasecmp(in, "application/vnd.cups-raster") == 0 ||
+            strcasecmp(in, "application/vnd.cups-pdf") == 0 ||
+            strcasecmp(in, "application/vnd.cups-postscript") == 0 ||
+            strcasecmp(in, "application/pdf") == 0 ||
+            strcasecmp(in, "image/pwg-raster") == 0 ||
+            strcasecmp(in, "image/urf") == 0 ||
+            strcasecmp(in, "application/PCLm") == 0 ||
+            strcasecmp(in, "application/postscript") == 0))
+       {
+         if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                      "ppdFilterUniversal:       --> Selecting this line");
+         /* Take the input format of the line as output format for us */
+         strncpy(output, in, sizeof(output));
+         /* Update the minimum cost found */
+         lowest_cost = cost;
+         /* We cannot find a "better" solution ... */
+         if (lowest_cost == 0)
+         {
+           if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                        "ppdFilterUniversal:    Cost value is down to zero, stopping reading further lines");
+           break;
+         }
+       }
+
+       continue;
+
+      error:
+       if (lowest_cost == INT_MAX && coststr)
+       {
+         if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                      "ppdFilterUniversal: PPD uses \"*cupsFilter: ...\" lines, so we always convert to format given by FINAL_CONTENT_TYPE");
+         break;
+       }
+       if (log) log(ld, CF_LOGLEVEL_ERROR,
+                    "ppdFilterUniversal: Invalid \"*cupsFilter2: ...\" line in PPD: %s",
+                    filter);
+      }
+
+    }
+  }
+
+  if (strcasecmp(output, final_output) != 0)
+  {
+    if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                "ppdFilterUniversal: Converting from %s to %s, final output will be %s",
+                input, output, final_output);
+    universal_parameters.actual_output_type = output;
+  }
+  else
+  {
+    if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                "ppdFilterUniversal: Converting from %s to %s", input, output);
+  }
+
+  if (strstr(output, "postscript"))
+  {
+    /* PostScript output, we need to add libppd's ppdFilterPDFToPS() to
+       the end of the chain */
+    universal_parameters.actual_output_type = "application/vnd.cups-pdf";
+    extra_filter.function = ppdFilterPDFToPS;
+    extra_filter.parameters = NULL;
+    extra_filter.name = "pdftops";
+  }
+#if HAVE_CUPS_3_X
+  else if (ppd && ppd->jcl_pdf && strstr(output, "pdf"))
+#else
+  else if (ppd && ppdFindAttr(ppd, "JCLToPDFInterpreter", NULL) &&
+          strstr(output, "pdf"))
+#endif
+  {
+    /* Classic PDF printer, with job control via JCL/PJL, needs
+       libppd's ppdFilterPDFToPDF() filter function which adds PPD's JCL/PJL*/
+    if (!strncmp(input, "image/", 6) &&
+       strcmp(input + 6, "urf") && strcmp(input + 6, "pwg-raster"))
+      /* Input is an image file: call only ppdFilterImageToPDF() as
+        cfFilterImageToPDF() + ppdFilterPDFToPDF() would apply the margins
+        twice */
+      return ppdFilterImageToPDF(inputfd, outputfd, inputseekable, data, NULL);
+    else
+    {
+      /* Any other input format: Replace the cfFilterPDFToPDF() call by
+        cfFilterUniversal() with a call of ppdFilterPDFToPDF(), so that
+        JCL/PJL from the PPD gets added. */
+      universal_parameters.actual_output_type = "application/pdf";
+      extra_filter.function = ppdFilterPDFToPDF;
+      extra_filter.parameters = NULL;
+      extra_filter.name = "pdftopdf+JCL";
+    }
+  }
+  else
+    /* No extra filter needed, cfFilterUniversal() does the job
+       correctly with only the filter functions of libcupsfilters */
+    extra_filter.function = NULL;
+
+  if (extra_filter.function)
+  {
+    /* Chain cfFilterUniversal() with the extra filter function */
+    universal_filter.function = cfFilterUniversal;
+    universal_filter.parameters = &universal_parameters;
+    universal_filter.name = "universal";
+    filter_chain = cupsArrayNew(NULL, NULL);
+    cupsArrayAdd(filter_chain, &universal_filter);
+    cupsArrayAdd(filter_chain, &extra_filter);
+    ret = cfFilterChain(inputfd, outputfd, inputseekable, data,
+                       filter_chain);
+    cupsArrayDelete(filter_chain);
+  }
+  else
+    ret = cfFilterUniversal(inputfd, outputfd, inputseekable, data,
+                           &universal_parameters);
+
+  return (ret);
+}
+
+
+/*
+ * 'ppdFilterSetCommonOptions()' - Set common filter options for media size,
+ *                                 etc. based on PPD file
+ */
+
+void
+ppdFilterSetCommonOptions(
+    ppd_file_t    *ppd,                        /* I - PPD file */
+    int           num_options,          /* I - Number of options */
+    cups_option_t *options,             /* I - Options */
+    int           change_size,         /* I - Change page size? */
+    int           *Orientation,         /* I/O - Basic page parameters */
+    int           *Duplex,
+    int           *LanguageLevel,
+    int           *ColorDevice,
+    float         *PageLeft,
+    float         *PageRight,
+    float         *PageTop,
+    float         *PageBottom,
+    float         *PageWidth,
+    float         *PageLength,
+    cf_logfunc_t log,                   /* I - Logging function,
+                                              NULL for no logging */
+    void *ld)                           /* I - User data for logging function,
+                                              can be NULL */
+{
+  ppd_size_t   *pagesize;              /* Current page size */
+  const char   *val;                   /* Option value */
+
+
+  *Orientation = 0;            /* 0 = portrait, 1 = landscape, etc. */
+  *Duplex = 0;                 /* Duplexed? */
+  *LanguageLevel = 1;          /* Language level of printer */
+  *ColorDevice = 1;            /* Color printer? */
+  *PageLeft = 18.0f;           /* Left margin */
+  *PageRight = 594.0f;         /* Right margin */
+  *PageBottom = 36.0f;         /* Bottom margin */
+  *PageTop = 756.0f;           /* Top margin */
+  *PageWidth = 612.0f;         /* Total page width */
+  *PageLength = 792.0f;                /* Total page length */
+
+  if ((pagesize = ppdPageSize(ppd, NULL)) != NULL)
+  {
+    int corrected = 0;
+    if (pagesize->width > 0) 
+      *PageWidth = pagesize->width;
+    else
+    {
+      if (log) log(ld, CF_LOGLEVEL_ERROR,
+                  "Invalid value for page width: %.0f",
+                  pagesize->width);
+      corrected = 1;
+    }
+    if (pagesize->length > 0) 
+      *PageLength = pagesize->length;
+    else
+    {
+      if (log) log(ld, CF_LOGLEVEL_ERROR,
+                  "Invalid value for page length: %.0f",
+                  pagesize->length);
+      corrected = 1;
+    }
+    if (pagesize->top >= 0 && pagesize->top <= *PageLength) 
+      *PageTop = pagesize->top;
+    else
+    {
+      if (log) log(ld, CF_LOGLEVEL_ERROR,
+                  "Invalid value for page top margin: %.0f",
+                  pagesize->top);
+      if (*PageLength >= *PageBottom)
+       *PageTop = *PageLength - *PageBottom;
+      else
+       *PageTop = *PageLength;
+      corrected = 1;
+    }
+    if (pagesize->bottom >= 0 && pagesize->bottom <= *PageLength) 
+      *PageBottom = pagesize->bottom;
+    else
+    {
+      if (log) log(ld, CF_LOGLEVEL_ERROR,
+                  "Invalid value for page bottom margin: %.0f",
+                  pagesize->bottom);
+      if (*PageLength <= *PageBottom)
+       *PageBottom = 0.0f;
+      corrected = 1;
+    }
+    if (*PageBottom == *PageTop)
+    {
+      if (log) log(ld, CF_LOGLEVEL_ERROR,
+                  "Invalid values for page margins: Bottom: %.0f; Top: %.0f",
+                  *PageBottom, *PageTop);
+      *PageTop = *PageLength - *PageBottom;
+      if (*PageBottom == *PageTop)
+      {
+       *PageBottom = 0.0f;
+       *PageTop = *PageLength;
+      }
+      corrected = 1;
+    }
+    if (*PageBottom > *PageTop)
+    {
+      if (log) log(ld, CF_LOGLEVEL_ERROR,
+                  "Invalid values for page margins: Bottom: %.0f; Top: %.0f",
+                  *PageBottom, *PageTop);
+      float swap = *PageBottom;
+      *PageBottom = *PageTop;
+      *PageTop = swap;
+      corrected = 1;
+    }
+
+    if (pagesize->left >= 0 && pagesize->left <= *PageWidth) 
+      *PageLeft = pagesize->left;
+    else
+    {
+      if (log) log(ld, CF_LOGLEVEL_ERROR,
+                  "Invalid value for page left margin: %.0f",
+                  pagesize->left);
+      if (*PageWidth <= *PageLeft)
+       *PageLeft = 0.0f;
+      corrected = 1;
+    }
+    if (pagesize->right >= 0 && pagesize->right <= *PageWidth) 
+      *PageRight = pagesize->right;
+    else
+    {
+      if (log) log(ld, CF_LOGLEVEL_ERROR,
+                  "Invalid value for page right margin: %.0f",
+                  pagesize->right);
+      if (*PageWidth >= *PageLeft)
+       *PageRight = *PageWidth - *PageLeft;
+      else
+       *PageRight = *PageWidth;
+      corrected = 1;
+    }
+    if (*PageLeft == *PageRight)
+    {
+      if (log) log(ld, CF_LOGLEVEL_ERROR,
+                  "Invalid values for page margins: Left: %.0f; Right: %.0f",
+                  *PageLeft, *PageRight);
+      *PageRight = *PageWidth - *PageLeft;
+      if (*PageLeft == *PageRight)
+      {
+       *PageLeft = 0.0f;
+       *PageRight = *PageWidth;
+      }
+      corrected = 1;
+    }
+    if (*PageLeft > *PageRight)
+    {
+      if (log) log(ld, CF_LOGLEVEL_ERROR,
+                  "Invalid values for page margins: Left: %.0f; Right: %.0f",
+                  *PageLeft, *PageRight);
+      float swap = *PageLeft;
+      *PageLeft = *PageRight;
+      *PageRight = swap;
+      corrected = 1;
+    }
+
+    if (corrected)
+    {
+      if (log) log(ld, CF_LOGLEVEL_ERROR,
+                  "PPD Page = %.0fx%.0f; %.0f,%.0f to %.0f,%.0f",
+                  pagesize->width, pagesize->length, pagesize->left,
+                  pagesize->bottom, pagesize->right, pagesize->top);
+      if (log) log(ld, CF_LOGLEVEL_ERROR,
+                  "Corrected Page = %.0fx%.0f; %.0f,%.0f to %.0f,%.0f",
+                  *PageWidth, *PageLength, *PageLeft,
+                  *PageBottom, *PageRight, *PageTop);
+    }
+    else
+      if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                  "Page = %.0fx%.0f; %.0f,%.0f to %.0f,%.0f",
+                  pagesize->width, pagesize->length, pagesize->left,
+                  pagesize->bottom, pagesize->right, pagesize->top);
+  }
+
+  if (ppd != NULL)
+  {
+    *ColorDevice   = ppd->color_device;
+    *LanguageLevel = ppd->language_level;
+  }
+
+  if ((val = cupsGetOption("landscape", num_options, options)) != NULL)
+  {
+    if (strcasecmp(val, "no") != 0 && strcasecmp(val, "off") != 0 &&
+        strcasecmp(val, "false") != 0)
+    {
+      if (ppd && ppd->landscape > 0)
+        *Orientation = 1;
+      else
+        *Orientation = 3;
+    }
+  }
+  else if ((val = cupsGetOption("orientation-requested",
+                               num_options, options)) != NULL)
+  {
+   /*
+    * Map IPP orientation values to 0 to 3:
+    *
+    *   3 = 0 degrees   = 0
+    *   4 = 90 degrees  = 1
+    *   5 = -90 degrees = 3
+    *   6 = 180 degrees = 2
+    */
+
+    *Orientation = atoi(val) - 3;
+    if (*Orientation >= 2)
+      *Orientation ^= 1;
+  }
+
+  if ((val = cupsGetOption("page-left", num_options, options)) != NULL)
+  {
+    switch (*Orientation & 3)
+    {
+      case 0 :
+          *PageLeft = (float)atof(val);
+         break;
+      case 1 :
+          *PageBottom = (float)atof(val);
+         break;
+      case 2 :
+          *PageRight = *PageWidth - (float)atof(val);
+         break;
+      case 3 :
+          *PageTop = *PageLength - (float)atof(val);
+         break;
+    }
+  }
+
+  if ((val = cupsGetOption("page-right", num_options, options)) != NULL)
+  {
+    switch (*Orientation & 3)
+    {
+      case 0 :
+          *PageRight = *PageWidth - (float)atof(val);
+         break;
+      case 1 :
+          *PageTop = *PageLength - (float)atof(val);
+         break;
+      case 2 :
+          *PageLeft = (float)atof(val);
+         break;
+      case 3 :
+          *PageBottom = (float)atof(val);
+         break;
+    }
+  }
+
+  if ((val = cupsGetOption("page-bottom", num_options, options)) != NULL)
+  {
+    switch (*Orientation & 3)
+    {
+      case 0 :
+          *PageBottom = (float)atof(val);
+         break;
+      case 1 :
+          *PageLeft = (float)atof(val);
+         break;
+      case 2 :
+          *PageTop = *PageLength - (float)atof(val);
+         break;
+      case 3 :
+          *PageRight = *PageWidth - (float)atof(val);
+         break;
+    }
+  }
+
+  if ((val = cupsGetOption("page-top", num_options, options)) != NULL)
+  {
+    switch (*Orientation & 3)
+    {
+      case 0 :
+          *PageTop = *PageLength - (float)atof(val);
+         break;
+      case 1 :
+          *PageRight = *PageWidth - (float)atof(val);
+         break;
+      case 2 :
+          *PageBottom = (float)atof(val);
+         break;
+      case 3 :
+          *PageLeft = (float)atof(val);
+         break;
+    }
+  }
+
+  if (change_size)
+    ppdFilterUpdatePageVars(*Orientation, PageLeft, PageRight,
+                        PageTop, PageBottom, PageWidth, PageLength);
+
+  if (ppdIsMarked(ppd, "Duplex", "DuplexNoTumble") ||
+      ppdIsMarked(ppd, "Duplex", "DuplexTumble") ||
+      ppdIsMarked(ppd, "JCLDuplex", "DuplexNoTumble") ||
+      ppdIsMarked(ppd, "JCLDuplex", "DuplexTumble") ||
+      ppdIsMarked(ppd, "EFDuplex", "DuplexNoTumble") ||
+      ppdIsMarked(ppd, "EFDuplex", "DuplexTumble") ||
+      ppdIsMarked(ppd, "EFDuplexing", "DuplexNoTumble") ||
+      ppdIsMarked(ppd, "EFDuplexing", "DuplexTumble") ||
+      ppdIsMarked(ppd, "ARDuplex", "DuplexNoTumble") ||
+      ppdIsMarked(ppd, "ARDuplex", "DuplexTumble") ||
+      ppdIsMarked(ppd, "KD03Duplex", "DuplexNoTumble") ||
+      ppdIsMarked(ppd, "KD03Duplex", "DuplexTumble"))
+    *Duplex = 1;
+
+  return;
+}
+
+
+/*
+ * 'ppdFilterUpdatePageVars()' - Update the page variables for the orientation.
+ */
+
+void
+ppdFilterUpdatePageVars(int Orientation,
+                    float *PageLeft, float *PageRight,
+                    float *PageTop, float *PageBottom,
+                    float *PageWidth, float *PageLength)
+{
+  float                temp;                   /* Swapping variable */
+
+
+  switch (Orientation & 3)
+  {
+    case 0 : /* Portait */
+        break;
+
+    case 1 : /* Landscape */
+       temp        = *PageLeft;
+       *PageLeft   = *PageBottom;
+       *PageBottom = temp;
+
+       temp        = *PageRight;
+       *PageRight  = *PageTop;
+       *PageTop    = temp;
+
+       temp        = *PageWidth;
+       *PageWidth  = *PageLength;
+       *PageLength = temp;
+       break;
+
+    case 2 : /* Reverse Portrait */
+       temp        = *PageWidth - *PageLeft;
+       *PageLeft   = *PageWidth - *PageRight;
+       *PageRight  = temp;
+
+       temp        = *PageLength - *PageBottom;
+       *PageBottom = *PageLength - *PageTop;
+       *PageTop    = temp;
+        break;
+
+    case 3 : /* Reverse Landscape */
+       temp        = *PageWidth - *PageLeft;
+       *PageLeft   = *PageWidth - *PageRight;
+       *PageRight  = temp;
+
+       temp        = *PageLength - *PageBottom;
+       *PageBottom = *PageLength - *PageTop;
+       *PageTop    = temp;
+
+       temp        = *PageLeft;
+       *PageLeft   = *PageBottom;
+       *PageBottom = temp;
+
+       temp        = *PageRight;
+       *PageRight  = *PageTop;
+       *PageTop    = temp;
+
+       temp        = *PageWidth;
+       *PageWidth  = *PageLength;
+       *PageLength = temp;
+       break;
+  }
+}
diff --git a/ppd/ppd-filter.h b/ppd/ppd-filter.h
new file mode 100644 (file)
index 0000000..156b27a
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ *   Filter functions header file for libppd.
+ *
+ *   Copyright Â© 2020-2022 by Till Kamppeter.
+ *
+ *   Licensed under Apache License v2.0.  See the file "LICENSE" for more
+ *   information.
+ */
+
+#ifndef _PPD_PPD_FILTER_H_
+#  define _PPD_PPD_FILTER_H_
+
+#  ifdef __cplusplus
+extern "C" {
+#  endif /* __cplusplus */
+
+
+/*
+ * Include necessary headers...
+ */
+
+#  include <cupsfilters/log.h>
+#  include <cupsfilters/filter.h>
+
+#  include <stdio.h>
+#  include <stdlib.h>
+#  include <time.h>
+#  include <math.h>
+
+#  if defined(WIN32) || defined(__EMX__)
+#    include <io.h>
+#  else
+#    include <unistd.h>
+#    include <fcntl.h>
+#  endif /* WIN32 || __EMX__ */
+
+#  include <cups/cups.h>
+#  include <cups/raster.h>
+#  include <ppd/ppd.h>
+
+#  define PPD_FILTER_DATA_EXT "libppd"
+
+
+/*
+ * Types and structures...
+ */
+
+typedef struct ppd_filter_data_ext_s {
+  char *ppdfile;             /* PPD file name */
+  ppd_file_t *ppd;           /* PPD file data */
+} ppd_filter_data_ext_t;
+
+typedef struct ppd_filter_external_cups_s { /* Parameters for the
+                                              ppdFilterExternalCUPS() filter
+                                              function */
+  const char *filter;        /* Path/Name of the CUPS filter to be called by
+                               this filter function, required */
+  int is_backend;            /* 0 if we call a filter, 1 if we call a CUPS
+                               backend, 2 if we call a CUPS backend in
+                               device discovery mode */
+  const char *device_uri;    /* Device URI when calling a CUPS Backend for
+                               processing a job, optional, alternatively
+                               DEVICE_URI environment variable can get set
+                               in envp */
+  int num_options;           /* Extra options for the 5th command line */
+  cups_option_t *options;    /* argument, options of filter_data have
+                                priority, 0/NULL if none */
+  char **envp;               /* Additional environment variables, the already
+                                defined ones stay valid but can be overwritten
+                                by these ones, NULL if none */
+} ppd_filter_external_cups_t;
+
+
+/*
+ * Prototypes...
+ */
+
+extern int ppdFilterCUPSWrapper(int argc,
+                               char *argv[],
+                               cf_filter_function_t filter,
+                               void *parameters,
+                               int *JobCanceled);
+
+
+extern int ppdFilterLoadPPDFile(cf_filter_data_t *data, const char *ppdfile);
+
+
+extern int ppdFilterLoadPPD(cf_filter_data_t *data);
+
+
+extern void ppdFilterFreePPDFile(cf_filter_data_t *data);
+
+
+extern void ppdFilterFreePPD(cf_filter_data_t *data);
+
+
+extern int ppdFilterExternalCUPS(int inputfd,
+                                int outputfd,
+                                int inputseekable,
+                                cf_filter_data_t *data,
+                                void *parameters);
+
+/* Parameters: ppd_filter_external_cups_t*
+   Path/Name of the CUPS filter to be called by this filter function,
+   specification whether we call a filter or a backend, an in case of
+   backend, whether in job processing or discovery mode, extra options
+   for the 5th command line argument, and extra environment
+   variables */
+
+
+extern int ppdFilterEmitJCL(int inputfd,
+                           int outputfd,
+                           int inputseekable,
+                           cf_filter_data_t *data,
+                           void *parameters,
+                           cf_filter_function_t orig_filter);
+
+
+extern int ppdFilterImageToPDF(int inputfd,
+                              int outputfd,
+                              int inputseekable,
+                              cf_filter_data_t *data,
+                              void *parameters);
+
+
+extern int ppdFilterImageToPS(int inputfd,
+                             int outputfd,
+                             int inputseekable,
+                             cf_filter_data_t *data,
+                             void *parameters);
+
+
+extern int ppdFilterPDFToPDF(int inputfd,
+                            int outputfd,
+                            int inputseekable,
+                            cf_filter_data_t *data,
+                            void *parameters);
+
+/* (Optional) Specification of output format via
+   data->final_content_type is used for determining whether this
+   filter function does page logging for CUPS (output of "PAGE: XX YY"
+   log messages) or not and also to determine whether the printer or
+   driver generates copies or whether we have to send the pages
+   repeatedly.
+
+   Alternatively, the options "pdf-filter-page-logging",
+   "hardware-copies", and "hardware-collate" can be used to manually
+   do these selections. */
+
+
+
+extern int ppdFilterPDFToPS(int inputfd,
+                           int outputfd,
+                           int inputseekable,
+                           cf_filter_data_t *data,
+                           void *parameters);
+
+
+extern int ppdFilterPSToPS(int inputfd,
+                          int outputfd,
+                          int inputseekable,
+                          cf_filter_data_t *data,
+                          void *parameters);
+
+
+extern int ppdFilterRasterToPS(int inputfd,
+                              int outputfd,
+                              int inputseekable,
+                              cf_filter_data_t *data,
+                              void *parameters);
+
+
+extern int ppdFilterUniversal(int inputfd,
+                             int outputfd,
+                             int inputseekable,
+                             cf_filter_data_t *data,
+                             void *parameters);
+
+/* Requires specification of input format via data->content_type and 
+   job's final output format via data->final_content_type
+
+   Parameters: cf_filter_universal_parameter_t
+
+   Contains: actual_output_type: Format which the filter should
+             actually produce if different from job's final output
+             format, or NULL to auto-determine the needed output
+            format from the PPDs "cupsFilter2: ..." lines. Default
+            is the job's final output format.
+            texttopdf_params: parameters for texttopdf */
+
+
+extern void ppdFilterSetCommonOptions(ppd_file_t *ppd,
+                                     int num_options,
+                                     cups_option_t *options,
+                                     int change_size,
+                                     int *Orientation,
+                                     int *Duplex,
+                                     int *LanguageLevel,
+                                     int *ColorDevice,
+                                     float *PageLeft,
+                                     float *PageRight,
+                                     float *PageTop,
+                                     float *PageBottom,
+                                     float *PageWidth,
+                                     float *PageLength,
+                                     cf_logfunc_t log,
+                                     void *ld);
+
+
+extern void ppdFilterUpdatePageVars(int Orientation,
+                                   float *PageLeft, float *PageRight,
+                                   float *PageTop, float *PageBottom,
+                                   float *PageWidth, float *PageLength);
+
+
+#  ifdef __cplusplus
+}
+#  endif /* __cplusplus */
+
+#endif /* !_PPD_PPD_FILTER_H_ */
similarity index 62%
rename from cupsfilters/ppdgenerator.c
rename to ppd/ppd-generator.c
index eaf4a603523c7a742dca47f99bc74a4cf4807ad5..3ea9694dc4adfd1b0b7b65913fc8298acda22098 100644 (file)
 #include <cups/cups.h>
 #include <cups/dir.h>
 #include <ppd/ppd.h>
-#include <cupsfilters/ppdgenerator.h>
-#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5)
-#define HAVE_CUPS_1_6 1
-#endif
-#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 6)
-#define HAVE_CUPS_1_7 1
-#endif
+#include <ppd/string-private.h>
+#include <cupsfilters/ipp.h>
+#include <cupsfilters/catalog.h>
 
 
 /*
@@ -38,9 +34,7 @@
 #include <errno.h>
 #include <string.h>
 #include <ctype.h>
-#ifdef HAVE_CUPS_1_7
 #include <cups/pwg.h>
-#endif /* HAVE_CUPS_1_7 */
 
 
 /*
 #endif
 
 
-#ifdef HAVE_CUPS_1_6
-/*
- * Local types...
- */
-
-/* Data structure for IPP choice name and human-readable string */
-typedef struct ipp_choice_strings_s {
-  char *name, *human_readable;
-} ipp_choice_strings_t;
-
-/* Data structure for IPP option name, human-readable string, and choice list */
-typedef struct ipp_opt_strings_s {
-  char *name, *human_readable;
-  cups_array_t *choices;
-} ipp_opt_strings_t;
-
-/* The following code uses a lot of CUPS >= 1.6 specific stuff.
-   It needed for create_local_queue() in cups-browsed
-   to set up local queues for non-CUPS printer broadcasts
-   that is disabled in create_local_queue() for older CUPS <= 1.5.4.
-   Accordingly the following code is also disabled here for CUPS < 1.6. */
-
 /*
  * The code below is borrowed from the CUPS 2.2.x upstream repository
  * (via patches attached to https://www.cups.org/str.php?L4258). This
@@ -92,1271 +64,8 @@ typedef struct ipp_opt_strings_s {
  */
 
 
-cups_array_t *opt_strings_catalog = NULL;
 char ppdgenerator_msg[1024];
 
-typedef struct _pwg_finishings_s       /**** PWG finishings mapping data ****/
-{
-  ipp_finishings_t     value;          /* finishings value */
-  int                  num_options;    /* Number of options to apply */
-  cups_option_t                *options;       /* Options to apply */
-} _pwg_finishings_t;
-
-#define _PWG_EQUIVALENT(x, y)  (abs((x)-(y)) < 2)
-
-#ifndef HAVE_STRLCPY
-/*
- * 'strlcpy()' - Safely copy two strings.
- */
-
-size_t                                 /* O - Length of string */
-strlcpy(char       *dst,               /* O - Destination string */
-       const char *src,                /* I - Source string */
-       size_t      size)               /* I - Size of destination string buffer */
-{
-  size_t       srclen;                 /* Length of source string */
-
-
- /*
-  * Figure out how much room is needed...
-  */
-
-  size --;
-
-  srclen = strlen(src);
-
- /*
-  * Copy the appropriate amount...
-  */
-
-  if (srclen > size)
-    srclen = size;
-
-  memmove(dst, src, srclen);
-  dst[srclen] = '\0';
-
-  return (srclen);
-}
-#endif /* !HAVE_STRLCPY */
-
-/*
- * 'cfStrFormatd()' - Format a floating-point number.
- */
-
-char *                                 /* O - Pointer to end of string */
-cfStrFormatd(char         *buf,        /* I - String */
-            char         *bufend,      /* I - End of string buffer */
-            double       number,       /* I - Number to format */
-            struct lconv *loc) /* I - Locale data */
-{
-  char         *bufptr,                /* Pointer into buffer */
-               temp[1024],             /* Temporary string */
-               *tempdec,               /* Pointer to decimal point */
-               *tempptr;               /* Pointer into temporary string */
-  const char   *dec;                   /* Decimal point */
-  int          declen;                 /* Length of decimal point */
-
-
- /*
-  * Format the number using the "%.12f" format and then eliminate
-  * unnecessary trailing 0's.
-  */
-
-  snprintf(temp, sizeof(temp), "%.12f", number);
-  for (tempptr = temp + strlen(temp) - 1;
-       tempptr > temp && *tempptr == '0';
-       *tempptr-- = '\0');
-
- /*
-  * Next, find the decimal point...
-  */
-
-  if (loc && loc->decimal_point) {
-    dec    = loc->decimal_point;
-    declen = (int)strlen(dec);
-  } else {
-    dec    = ".";
-    declen = 1;
-  }
-
-  if (declen == 1)
-    tempdec = strchr(temp, *dec);
-  else
-    tempdec = strstr(temp, dec);
-
- /*
-  * Copy everything up to the decimal point...
-  */
-
-  if (tempdec) {
-    for (tempptr = temp, bufptr = buf;
-         tempptr < tempdec && bufptr < bufend;
-        *bufptr++ = *tempptr++);
-
-    tempptr += declen;
-
-    if (*tempptr && bufptr < bufend) {
-      *bufptr++ = '.';
-
-      while (*tempptr && bufptr < bufend)
-        *bufptr++ = *tempptr++;
-    }
-
-    *bufptr = '\0';
-  } else {
-    strlcpy(buf, temp, (size_t)(bufend - buf + 1));
-    bufptr = buf + strlen(buf);
-  }
-
-  return (bufptr);
-}
-
-
-/*
- * 'pwg_compare_sizes()' - Compare two media sizes...
- */
-
-static int                             /* O - Result of comparison */
-pwg_compare_sizes(cups_size_t *a,      /* I - First media size */
-                  cups_size_t *b)      /* I - Second media size */
-{
-  return (strcmp(a->media, b->media));
-}
-
-
-/*
- * 'pwg_copy_size()' - Copy a media size.
- */
-
-static cups_size_t *                   /* O - New media size */
-pwg_copy_size(cups_size_t *size)       /* I - Media size to copy */
-{
-  cups_size_t  *newsize = (cups_size_t *)calloc(1, sizeof(cups_size_t));
-                                       /* New media size */
-
-  if (newsize)
-    memcpy(newsize, size, sizeof(cups_size_t));
-
-  return (newsize);
-}
-
-static int                             /* O  - 1 on success, 0 on failure */
-get_url(const char *url,               /* I  - URL to get */
-       char       *name,               /* I  - Temporary filename */
-       size_t     namesize)            /* I  - Size of temporary filename
-                                               buffer */
-{
-  http_t               *http = NULL;
-  char                 scheme[32],     /* URL scheme */
-                       userpass[256],  /* URL username:password */
-                       host[256],      /* URL host */
-                       resource[256];  /* URL resource */
-  int                  port;           /* URL port */
-  http_encryption_t    encryption;     /* Type of encryption to use */
-  http_status_t                status;         /* Status of GET request */
-  int                  fd;             /* Temporary file */
-
-
-  if (httpSeparateURI(HTTP_URI_CODING_ALL, url, scheme, sizeof(scheme),
-                     userpass, sizeof(userpass), host, sizeof(host), &port,
-                     resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
-    return (0);
-
-  if (port == 443 || !strcmp(scheme, "https"))
-    encryption = HTTP_ENCRYPTION_ALWAYS;
-  else
-    encryption = HTTP_ENCRYPTION_IF_REQUESTED;
-
-  http = httpConnect2(host, port, NULL, AF_UNSPEC, encryption, 1, 5000, NULL);
-
-  if (!http)
-    return (0);
-
-  if ((fd = cupsTempFd(name, (int)namesize)) < 0)
-    return (0);
-
-  status = cupsGetFd(http, resource, fd);
-
-  close(fd);
-  httpClose(http);
-
-  if (status != HTTP_STATUS_OK) {
-    unlink(name);
-    *name = '\0';
-    return (0);
-  }
-
-  return (1);
-}
-
-
-
-/*
- * 'find_cups_message_catalog()' - Find a CUPS message catalog file
- *                                 containing human-readable standard
- *                                 option and choice names for IPP
- *                                 printers
- */
-
-static const char *
-search_dir_for_catalog(const char *dirname)
-{
-  const char *catalog = NULL, *c1, *c2;
-  cups_dir_t *dir = NULL, *subdir;
-  cups_dentry_t *subdirentry, *catalogentry;
-  char subdirpath[1024], catalogpath[2048], lang[8];
-  int i;
-
-  if (dirname == NULL)
-    return NULL;
-
-  /* Check first whether we have an English file and prefer this */
-  snprintf(catalogpath, sizeof(catalogpath), "%s/en/cups_en.po", dirname);
-  if (access(catalogpath, R_OK) == 0) {
-    /* Found */
-    catalog = strdup(catalogpath);
-    return catalog;
-  }
-
-  if ((dir = cupsDirOpen(dirname)) == NULL)
-    return NULL;
-
-  while ((subdirentry = cupsDirRead(dir)) != NULL) {
-    /* Do we actually have a subdir? */
-    if (!S_ISDIR(subdirentry->fileinfo.st_mode))
-      continue;
-    /* Check format of subdir name */
-    c1 = subdirentry->filename;
-    if (c1[0] < 'a' || c1[0] > 'z' || c1[1] < 'a' || c1[1] > 'z')
-      continue;
-    if (c1[2] >= 'a' && c1[2] <= 'z')
-      i = 3;
-    else
-      i = 2;
-    if (c1[i] == '_') {
-      i ++;
-      if (c1[i] < 'A' || c1[i] > 'Z' || c1[i+1] < 'A' || c1[i+1] > 'Z')
-       continue;
-      i += 2;
-      if (c1[i] >= 'A' && c1[i] <= 'Z')
-       i ++;
-    }
-    if (c1[i] != '\0' && c1[i] != '@')
-      continue;
-    strncpy(lang, c1, i);
-    lang[i] = '\0';
-    snprintf(subdirpath, sizeof(subdirpath), "%s/%s", dirname, c1);
-    if ((subdir = cupsDirOpen(subdirpath)) != NULL) {
-      while ((catalogentry = cupsDirRead(subdir)) != NULL) {
-       /* Do we actually have a regular file? */
-       if (!S_ISREG(catalogentry->fileinfo.st_mode))
-         continue;
-       /* Check format of catalog name */
-       c2 = catalogentry->filename;
-       if (strlen(c2) < 10 || strncmp(c2, "cups_", 5) != 0 ||
-           strncmp(c2 + 5, lang, i) != 0 ||
-           strcmp(c2 + strlen(c2) - 3, ".po"))
-         continue;
-       /* Is catalog readable ? */
-       snprintf(catalogpath, sizeof(catalogpath), "%s/%s", subdirpath, c2);
-       if (access(catalogpath, R_OK) != 0)
-         continue;
-       /* Found */
-       catalog = strdup(catalogpath);
-       break;
-      }
-      cupsDirClose(subdir);
-      subdir = NULL;
-      if (catalog != NULL)
-       break;
-    }
-  }
-
-  cupsDirClose(dir);
-  return catalog;
-}
-
-static const char *
-find_cups_message_catalog(const char *preferreddir)
-{
-  const char *catalog = NULL, *c;
-  char buf[1024];
-
-  /* Directory supplied by calling program, from config file,
-     environment variable, ... */
-  if ((catalog = search_dir_for_catalog(preferreddir)) != NULL)
-    goto found;
-
-  /* Directory supplied by environment variable CUPS_LOCALEDIR */
-  if ((catalog = search_dir_for_catalog(getenv("CUPS_LOCALEDIR"))) != NULL)
-    goto found;
-
-  /* Determine CUPS datadir (usually /usr/share/cups) */
-  if ((c = getenv("CUPS_DATADIR")) == NULL)
-    c = CUPS_DATADIR;
-
-  /* Search /usr/share/cups/locale/ (location which
-     Debian/Ubuntu package of CUPS is using) */
-  snprintf(buf, sizeof(buf), "%s/locale", c);
-  if ((catalog = search_dir_for_catalog(buf)) != NULL)
-    goto found;
-
-  /* Search /usr/(local/)share/locale/ (standard location
-     which CUPS is using on Linux) */
-  snprintf(buf, sizeof(buf), "%s/../locale", c);
-  if ((catalog = search_dir_for_catalog(buf)) != NULL)
-    goto found;
-
-  /* Search /usr/(local/)lib/locale/ (standard location
-     which CUPS is using on many non-Linux systems) */
-  snprintf(buf, sizeof(buf), "%s/../../lib/locale", c);
-  if ((catalog = search_dir_for_catalog(buf)) != NULL)
-    goto found;
-
- found:
-  return catalog;
-}
-
-static int
-compare_choices(void *a,
-               void *b,
-               void *user_data)
-{
-  return strcasecmp(((ipp_choice_strings_t *)a)->name,
-                   ((ipp_choice_strings_t *)b)->name);
-}
-
-static int
-compare_options(void *a,
-               void *b,
-               void *user_data)
-{
-  return strcasecmp(((ipp_opt_strings_t *)a)->name,
-                   ((ipp_opt_strings_t *)b)->name);
-}
-
-static void
-free_choice_strings(void* entry, void* user_data)
-{
-  ipp_choice_strings_t *entry_rec = (ipp_choice_strings_t *)entry;
-
-  if (entry_rec) {
-    if (entry_rec->name) free(entry_rec->name);
-    if (entry_rec->human_readable) free(entry_rec->human_readable);
-    free(entry_rec);
-  }
-}
-
-static void
-free_opt_strings(void* entry,
-                void* user_data)
-{
-  ipp_opt_strings_t *entry_rec = (ipp_opt_strings_t *)entry;
-
-  if (entry_rec) {
-    if (entry_rec->name) free(entry_rec->name);
-    if (entry_rec->human_readable) free(entry_rec->human_readable);
-    if (entry_rec->choices) cupsArrayDelete(entry_rec->choices);
-    free(entry_rec);
-  }
-}
-
-static cups_array_t *
-opt_array_new()
-{
-  return cupsArrayNew3(compare_options, NULL, NULL, 0,
-                      NULL, free_opt_strings);
-}
-
-static ipp_opt_strings_t *
-find_opt_in_array(cups_array_t *options,
-                 char *name)
-{
-  ipp_opt_strings_t opt;
-
-  if (!name || !options)
-    return NULL;
-
-  opt.name = name;
-  return cupsArrayFind(options, &opt);
-}
-
-static ipp_choice_strings_t *
-find_choice_in_array(cups_array_t *choices,
-                    char *name)
-{
-  ipp_choice_strings_t choice;
-
-  if (!name || !choices)
-    return NULL;
-
-  choice.name = name;
-  return cupsArrayFind(choices, &choice);
-}
-
-static ipp_opt_strings_t *
-add_opt_to_array(char *name,
-                char *human_readable,
-                cups_array_t *options)
-{
-  ipp_opt_strings_t *opt = NULL;
-
-  if (!name || !options)
-    return NULL;
-
-  if ((opt = find_opt_in_array(options, name)) == NULL) {
-    opt = calloc(1, sizeof(ipp_opt_strings_t));
-    if (!opt) return NULL;
-    opt->human_readable = NULL;
-    opt->choices = cupsArrayNew3(compare_choices, NULL, NULL, 0,
-                                NULL, free_choice_strings);
-    if (!opt->choices) {
-      free(opt);
-      return NULL;
-    }
-    opt->name = strdup(name);
-    if (!cupsArrayAdd(options, opt)) {
-      free_opt_strings(opt, NULL);
-      return NULL;
-    }
-  }
-
-  if (human_readable)
-    opt->human_readable = strdup(human_readable);
-
-  return opt;
-}
-
-static ipp_choice_strings_t *
-add_choice_to_array(char *name,
-                   char *human_readable,
-                   char *opt_name,
-                   cups_array_t *options)
-{
-  ipp_choice_strings_t *choice = NULL;
-  ipp_opt_strings_t *opt;
-
-  if (!name || !human_readable || !opt_name || !options)
-    return NULL;
-
-  opt = add_opt_to_array(opt_name, NULL, options);
-  if (!opt) return NULL;
-
-  if ((choice = find_choice_in_array(opt->choices, name)) == NULL) {
-    choice = calloc(1, sizeof(ipp_choice_strings_t));
-    if (!choice) return NULL;
-    choice->human_readable = NULL;
-    choice->name = strdup(name);
-    if (!cupsArrayAdd(opt->choices, choice)) {
-      free_choice_strings(choice, NULL);
-      return NULL;
-    }
-  }
-
-  if (human_readable)
-    choice->human_readable = strdup(human_readable);
-
-  return choice;
-
-}
-
-static char *
-lookup_option(char *name,
-             cups_array_t *options,
-             cups_array_t *printer_options)
-{
-  ipp_opt_strings_t *opt = NULL;
-
-  if (!name || !options)
-    return NULL;
-
-  if (printer_options &&
-      (opt = find_opt_in_array(printer_options, name)) != NULL)
-    return opt->human_readable;
-  if ((opt = find_opt_in_array(options, name)) != NULL)
-    return opt->human_readable;
-  else
-    return NULL;
-}
-
-static char *
-lookup_choice(char *name,
-             char *opt_name,
-             cups_array_t *options,
-             cups_array_t *printer_options)
-{
-  ipp_opt_strings_t *opt = NULL;
-  ipp_choice_strings_t *choice = NULL;
-
-  if (!name || !opt_name || !options)
-    return NULL;
-
-  if (printer_options &&
-      (opt = find_opt_in_array(printer_options, opt_name)) != NULL &&
-      (choice = find_choice_in_array(opt->choices, name)) != NULL)
-    return choice->human_readable;
-  else if ((opt = find_opt_in_array(options, opt_name)) != NULL &&
-          (choice = find_choice_in_array(opt->choices, name)) != NULL)
-    return choice->human_readable;
-  else
-    return NULL;
-}
-
-
-static void
-load_opt_strings_catalog(const char *location,
-                        cups_array_t *options)
-{
-  char tmpfile[1024];
-  const char *filename = NULL;
-  struct stat statbuf;
-  cups_file_t *fp;
-  char line[65536];
-  char *ptr, *start, *start2, *end, *end2, *sep;
-  char *opt_name = NULL, *choice_name = NULL,
-       *human_readable = NULL;
-  int part = -1; /* -1: before first "msgid" or invalid
-                       line
-                    0: "msgid"
-                    1: "msgstr"
-                    2: "..." = "..."
-                   10: EOF, save last entry */
-  int digit;
-  int found_in_catalog = 0;
-
-  if (location == NULL || (strncasecmp(location, "http:", 5) &&
-                          strncasecmp(location, "https:", 6))) {
-    if (location == NULL ||
-       (stat(location, &statbuf) == 0 &&
-        S_ISDIR(statbuf.st_mode))) /* directory? */
-    {
-      filename = find_cups_message_catalog(location);
-      if (filename)
-        found_in_catalog = 1;
-    }
-    else
-      filename = location;
-  } else {
-    if (get_url(location, tmpfile, sizeof(tmpfile)))
-      filename = tmpfile;
-  }
-  if (!filename)
-    return;
-
-  if ((fp = cupsFileOpen(filename, "r")) == NULL)
-  {
-    if (filename == tmpfile)
-      unlink(filename);
-    return;
-  }
-
-  while (cupsFileGets(fp, line, sizeof(line)) || (part = 10)) {
-    /* Find a pair of quotes delimiting a string in each line
-       and optional "msgid" or "msgstr" keywords, or a
-       "..." = "..." pair. Skip comments ('#') and empty lines. */
-    if (part < 10) {
-      ptr = line;
-      while (isspace(*ptr)) ptr ++;
-      if (*ptr == '#' || *ptr == '\0') continue;
-      if ((start = strchr(ptr, '\"')) == NULL) continue;
-      if ((end = strrchr(ptr, '\"')) == start) continue;
-      if (*(end - 1) == '\\') continue;
-      start2 = NULL;
-      end2 = NULL;
-      if (start > ptr) {
-       if (*(start - 1) == '\\') continue;
-       if (strncasecmp(ptr, "msgid", 5) == 0) part = 0;
-       if (strncasecmp(ptr, "msgstr", 6) == 0) part = 1;
-      } else {
-       start2 = ptr;
-       while ((start2 = strchr(start2 + 1, '\"')) < end &&
-              *(start2 - 1) == '\\');
-       if (start2 < end) {
-         /* Line with "..." = "..." of text/strings format */
-         end2 = end;
-         end = start2;
-         start2 ++;
-         while (isspace(*start2)) start2 ++;
-         if (*start2 != '=') continue;
-         start2 ++;
-         while (isspace(*start2)) start2 ++;
-         if (*start2 != '\"') continue;
-         start2 ++;
-         *end2 = '\0';
-         part = 2;
-       } else
-         /* Continuation line in message catalog file */
-         start2 = NULL;
-      }
-      start ++;
-      *end = '\0';
-    }
-    /* Read out the strings between the quotes and save entries */
-    if (part == 0 || part == 2 || part == 10) {
-      /* Save previous attribute */
-      if (human_readable) {
-       if (opt_name) {
-         if (choice_name) {
-           add_choice_to_array(choice_name, human_readable,
-                               opt_name, options);
-           free(choice_name);
-         } else
-           add_opt_to_array(opt_name, human_readable, options);
-         free(opt_name);
-       }
-       free(human_readable);
-       opt_name = NULL;
-       choice_name = NULL;
-       human_readable = NULL;
-      }
-      /* Stop the loop after saving the last entry */
-      if (part == 10)
-       break;
-      /* IPP attribute has to be defined with a single msgid line,
-        no continuation lines */
-      if (opt_name) {
-       free (opt_name);
-       opt_name = NULL;
-       if (choice_name) {
-         free (choice_name);
-         choice_name = NULL;
-       }
-       part = -1;
-       continue;
-      }
-      /* No continuation line in text/strings format */
-      if (part == 2 && (start2 == NULL || end2 == NULL)) {
-       part = -1;
-       continue;
-      }
-      /* Check line if it is a valid IPP attribute:
-        No spaces, only lowercase letters, digits, '-', '_',
-        "option" or "option.choice" */
-      for (ptr = start, sep = NULL; ptr < end; ptr ++)
-       if (*ptr == '.') { /* Separator between option and choice */
-         if (!sep) { /* Only the first '.' counts */
-           sep = ptr + 1;
-           *ptr = '\0';
-         }
-       } else if (!((*ptr >= 'a' && *ptr <= 'z') ||
-                    (*ptr >= '0' && *ptr <= '9') ||
-                    *ptr == '-' || *ptr == '_'))
-         break;
-      if (ptr < end) { /* Illegal character found */
-       part = -1;
-       continue;
-      }
-      if (strlen(start) > 0) /* Option name found */
-       opt_name = strdup(start);
-      else { /* Empty option name */
-       part = -1;
-       continue;
-      }
-      if (sep && strlen(sep) > 0) /* Choice name found */
-       choice_name = strdup(sep);
-      else /* Empty choice name */
-       choice_name = NULL;
-      if (part == 2) { /* Human-readable string in the same line */
-       start = start2;
-       end = end2;
-      }
-    }
-    if (part == 1 || part == 2) {
-      /* msgid was not for an IPP attribute, ignore this msgstr */
-      if (!opt_name) continue;
-      /* Empty string */
-      if (start == end) continue;
-      /* Unquote string */
-      ptr = start;
-      end = start;
-      while (*ptr) {
-       if (*ptr == '\\') {
-         ptr ++;
-         if (isdigit(*ptr)) {
-           digit = 0;
-           *end = 0;
-           while (isdigit(*ptr) && digit < 3) {
-             *end = *end * 8 + *ptr - '0';
-             digit ++;
-             ptr ++;
-           }
-           end ++;
-         } else {
-           if (*ptr == 'n')
-             *end ++ = '\n';
-           else if (*ptr == 'r')
-             *end ++ = '\r';
-           else if (*ptr == 't')
-             *end ++ = '\t';
-           else
-             *end ++ = *ptr;
-           ptr ++;
-         }
-       } else
-         *end ++ = *ptr ++;
-      }
-      *end = '\0';
-      /* Did the unquoting make the string empty? */
-      if (strlen(start) == 0) continue;
-      /* Add the string to our human-readable string */
-      if (human_readable) { /* Continuation line */
-       human_readable = realloc(human_readable,
-                                sizeof(char) *
-                                (strlen(human_readable) +
-                                 strlen(start) + 2));
-       ptr = human_readable + strlen(human_readable);
-       *ptr = ' ';
-       strlcpy(ptr + 1, start, strlen(start) + 1);
-      } else { /* First line */
-       human_readable = malloc(sizeof(char) *
-                               (strlen(start) + 1));
-       strlcpy(human_readable, start, strlen(start) + 1);
-      }
-    }
-  }
-  cupsFileClose(fp);
-  if (choice_name != NULL)
-    free(choice_name);
-  if (opt_name != NULL)
-    free(opt_name);
-  if (filename == tmpfile)
-    unlink(filename);
-  if (found_in_catalog)
-    free((char *)filename);
-}
-
-
-int
-cfCompareResolutions(void *resolution_a,
-                    void *resolution_b,
-                    void *user_data)
-{
-  cf_res_t *res_a = (cf_res_t *)resolution_a;
-  cf_res_t *res_b = (cf_res_t *)resolution_b;
-  int i, a, b;
-
-  /* Compare the pixels per square inch */
-  a = res_a->x * res_a->y;
-  b = res_b->x * res_b->y;
-  i = (a > b) - (a < b);
-  if (i) return i;
-
-  /* Compare how much the pixel shape deviates from a square, the
-     more, the worse */
-  a = 100 * res_a->y / res_a->x;
-  if (a > 100) a = 10000 / a; 
-  b = 100 * res_b->y / res_b->x;
-  if (b > 100) b = 10000 / b; 
-  return (a > b) - (a < b);
-}
-
-void *
-cfCopyResolution(void *resolution,
-               void *user_data)
-{
-  cf_res_t *res = (cf_res_t *)resolution;
-  cf_res_t *copy;
-
-  copy = (cf_res_t *)calloc(1, sizeof(cf_res_t));
-  if (copy) {
-    copy->x = res->x;
-    copy->y = res->y;
-  }
-
-  return copy;
-}
-
-void
-cfFreeResolution(void *resolution,
-               void *user_data)
-{
-  cf_res_t *res = (cf_res_t *)resolution;
-
-  if (res) free(res);
-}
-
-cups_array_t *
-cfNewResolutionArray()
-{
-  return cupsArrayNew3(cfCompareResolutions, NULL, NULL, 0,
-                      cfCopyResolution, cfFreeResolution);
-}
-
-cf_res_t *
-cfNewResolution(int x,
-               int y)
-{
-  cf_res_t *res = (cf_res_t *)calloc(1, sizeof(cf_res_t));
-  if (res) {
-    res->x = x;
-    res->y = y;
-  }
-  return res;
-}
-
-/* Read a single resolution from an IPP attribute, take care of
-   obviously wrong entries (printer firmware bugs), ignoring
-   resolutions of less than 60 dpi in at least one dimension and
-   fixing Brother's "600x2dpi" resolutions. */
-cf_res_t *
-cfIPPResToResolution(ipp_attribute_t *attr,
-                    int index)
-{
-  cf_res_t *res = NULL;
-  int x = 0, y = 0;
-
-  if (attr) {
-    ipp_tag_t tag = ippGetValueTag(attr);
-    int count = ippGetCount(attr);
-
-    if (tag == IPP_TAG_RESOLUTION && index < count) {
-      ppdPwgPpdizeResolution(attr, index, &x, &y, NULL, 0);
-      if (y == 2) y = x; /* Brother quirk ("600x2dpi") */
-      if (x >= 60 && y >= 60)
-       res = cfNewResolution(x, y);
-    }
-  }
-
-  return res;
-}
-
-cups_array_t *
-cfIPPAttrToResolutionArray(ipp_attribute_t *attr)
-{
-  cups_array_t *res_array = NULL;
-  cf_res_t *res;
-  int i;
-
-  if (attr) {
-    ipp_tag_t tag = ippGetValueTag(attr);
-    int count = ippGetCount(attr);
-
-    if (tag == IPP_TAG_RESOLUTION && count > 0) {
-      res_array = cfNewResolutionArray();
-      if (res_array) {
-       for (i = 0; i < count; i ++)
-         if ((res = cfIPPResToResolution(attr, i)) != NULL) {
-           if (cupsArrayFind(res_array, res) == NULL)
-             cupsArrayAdd(res_array, res);
-           cfFreeResolution(res, NULL);
-         }
-      }
-      if (cupsArrayCount(res_array) == 0) {
-       cupsArrayDelete(res_array);
-       res_array = NULL;
-      }
-    }
-  }
-
-  return res_array;
-}
-
-/* Build up an array of common resolutions and most desirable default
-   resolution from multiple arrays of resolutions with an optional
-   default resolution.
-   Call this function with each resolution array you find as "new", and
-   in "current" an array of the common resolutions will be built up.
-   You do not need to create an empty array for "current" before
-   starting. Initialize it with NULL.
-   "current_default" holds the default resolution of the array "current".
-   It will get replaced by "new_default" if "current_default" is either
-   NULL or a resolution which is not in "current" any more.
-   "new" and "new_default" will be deleted/freed and set to NULL after
-   each, successful or unsuccssful operation.
-   Note that when calling this function the addresses of the pointers
-   to the resolution arrays and default resolutions have to be given
-   (call by reference) as all will get modified by the function. */
-
-int /* 1 on success, 0 on failure */
-cfJoinResolutionArrays(cups_array_t **current,
-                      cups_array_t **new_arr,
-                      cf_res_t **current_default,
-                      cf_res_t **new_default)
-{
-  cf_res_t *res;
-  int retval;
-
-  if (current == NULL || new_arr == NULL || *new_arr == NULL ||
-      cupsArrayCount(*new_arr) == 0) {
-    retval = 0;
-    goto finish;
-  }
-
-  if (*current == NULL) {
-    /* We are adding the very first resolution array, simply make it
-       our common resolutions array */
-    *current = *new_arr;
-    if (current_default) {
-      if (*current_default)
-       free(*current_default);
-      *current_default = (new_default ? *new_default : NULL);
-    }
-    return 1;
-  } else if (cupsArrayCount(*current) == 0) {
-    retval = 1;
-    goto finish;
-  }
-
-  /* Dry run: Check whether the two arrays have at least one resolution
-     in common, if not, do not touch the original array */
-  for (res = cupsArrayFirst(*current);
-       res; res = cupsArrayNext(*current))
-    if (cupsArrayFind(*new_arr, res))
-      break;
-
-  if (res) {
-    /* Reduce the original array to the resolutions which are in both
-       the original and the new array, at least one resolution will
-       remain. */
-    for (res = cupsArrayFirst(*current);
-        res; res = cupsArrayNext(*current))
-      if (!cupsArrayFind(*new_arr, res))
-       cupsArrayRemove(*current, res);
-    if (current_default) {
-      /* Replace the current default by the new one if the current default
-        is not in the array any more or if it is NULL. If the new default
-        is not in the list or NULL in such a case, set the current default
-        to NULL */
-      if (*current_default && !cupsArrayFind(*current, *current_default)) {
-       free(*current_default);
-       *current_default = NULL;
-      }
-      if (*current_default == NULL && new_default && *new_default &&
-         cupsArrayFind(*current, *new_default))
-       *current_default = cfCopyResolution(*new_default, NULL);
-    }
-    retval = 1;
-  } else
-    retval = 0;
-
- finish:
-  if (new_arr && *new_arr) {
-    cupsArrayDelete(*new_arr);
-    *new_arr = NULL;
-  }
-  if (new_default && *new_default) {
-    free(*new_default);
-    *new_default = NULL;
-  }
-  return retval;
-}
-
-cups_array_t*
-cfGenerateSizes(ipp_t *response,
-               ipp_attribute_t **defattr,
-               int* min_length,
-               int* min_width,
-               int* max_length,
-               int* max_width,
-               int* bottom,
-               int* left,
-               int* right,
-               int* top,
-               char* ppdname)
-{
-  cups_array_t             *sizes;               /* Media sizes we've added */
-  ipp_attribute_t          *attr,                /* xxx-supported */
-                           *x_dim, *y_dim;       /* Media dimensions */
-  ipp_t                    *media_col,           /* Media collection */
-                           *media_size;          /* Media size collection */
-  int                      i, count = 0;
-  pwg_media_t              *pwg;                 /* PWG media size */
-  int                      left_def, right_def, bottom_def, top_def;
-  ipp_attribute_t          *margin;  /* media-xxx-margin attribute */
-  const char               *psname;
-
-  if ((attr = ippFindAttribute(response, "media-bottom-margin-supported",
-                              IPP_TAG_INTEGER)) != NULL) {
-    for (i = 1, *bottom = ippGetInteger(attr, 0), count = ippGetCount(attr);
-        i < count; i ++)
-      if (i == 1 || ippGetInteger(attr, i) < *bottom)
-        *bottom = ippGetInteger(attr, i);
-  } else
-    *bottom = 1270;
-
-  if ((attr = ippFindAttribute(response, "media-left-margin-supported",
-                              IPP_TAG_INTEGER)) != NULL) {
-    for (i = 1, *left = ippGetInteger(attr, 0), count = ippGetCount(attr);
-        i < count; i ++)
-      if (i == 1 || ippGetInteger(attr, i) < *left)
-        *left = ippGetInteger(attr, i);
-  } else
-    *left = 635;
-
-  if ((attr = ippFindAttribute(response, "media-right-margin-supported",
-                              IPP_TAG_INTEGER)) != NULL) {
-    for (i = 1, *right = ippGetInteger(attr, 0), count = ippGetCount(attr);
-        i < count; i ++)
-      if (i == 1 || ippGetInteger(attr, i) < *right)
-        *right = ippGetInteger(attr, i);
-  } else
-    *right = 635;
-
-  if ((attr = ippFindAttribute(response, "media-top-margin-supported",
-                              IPP_TAG_INTEGER)) != NULL) {
-    for (i = 1, *top = ippGetInteger(attr, 0), count = ippGetCount(attr);
-        i < count; i ++)
-      if (i == 1 || ippGetInteger(attr, i) < *top)
-        *top = ippGetInteger(attr, i);
-  } else
-    *top = 1270;
-
-  if ((*defattr = ippFindAttribute(response, "media-col-default",
-                                  IPP_TAG_BEGIN_COLLECTION)) != NULL) {
-    if ((attr = ippFindAttribute(ippGetCollection(*defattr, 0), "media-size",
-                                IPP_TAG_BEGIN_COLLECTION)) != NULL) {
-      media_size = ippGetCollection(attr, 0);
-      x_dim      = ippFindAttribute(media_size, "x-dimension", IPP_TAG_INTEGER);
-      y_dim      = ippFindAttribute(media_size, "y-dimension", IPP_TAG_INTEGER);
-  
-      if ((margin = ippFindAttribute(ippGetCollection(*defattr, 0),
-                                    "media-bottom-margin", IPP_TAG_INTEGER))
-         != NULL)
-       bottom_def = ippGetInteger(margin, 0);
-      else
-       bottom_def = *bottom;
-
-      if ((margin = ippFindAttribute(ippGetCollection(*defattr, 0),
-                                    "media-left-margin", IPP_TAG_INTEGER))
-         != NULL)
-       left_def = ippGetInteger(margin, 0);
-      else
-       left_def = *left;
-
-      if ((margin = ippFindAttribute(ippGetCollection(*defattr, 0),
-                                    "media-right-margin", IPP_TAG_INTEGER))
-         != NULL)
-       right_def = ippGetInteger(margin, 0);
-      else
-       right_def = *right;
-
-      if ((margin = ippFindAttribute(ippGetCollection(*defattr, 0),
-                                    "media-top-margin", IPP_TAG_INTEGER))
-         != NULL)
-       top_def = ippGetInteger(margin, 0);
-      else
-       top_def = *top;
-
-      if (x_dim && y_dim &&
-         (pwg = pwgMediaForSize(ippGetInteger(x_dim, 0),
-                                ippGetInteger(y_dim, 0))) != NULL) {
-       psname = (pwg->ppd != NULL ? pwg->ppd : pwg->pwg);
-        if (bottom_def == 0 && left_def == 0 && right_def == 0 && top_def == 0)
-          snprintf(ppdname, PPD_MAX_NAME, "%s.Borderless", psname);
-        else
-          strlcpy(ppdname, psname, PPD_MAX_NAME);
-      } else
-       strlcpy(ppdname, "Unknown", PPD_MAX_NAME);
-    } else
-      strlcpy(ppdname, "Unknown", PPD_MAX_NAME);
-  } else if ((pwg =
-             pwgMediaForPWG(ippGetString(ippFindAttribute(response,
-                                                          "media-default",
-                                                          IPP_TAG_ZERO), 0,
-                                         NULL))) != NULL) {
-    psname = (pwg->ppd != NULL ? pwg->ppd : pwg->pwg);
-    strlcpy(ppdname, psname, PPD_MAX_NAME);
-  } else
-    strlcpy(ppdname, "Unknown", PPD_MAX_NAME);
-
-  sizes = cupsArrayNew3((cups_array_func_t)pwg_compare_sizes, NULL, NULL, 0,
-                       (cups_acopy_func_t)pwg_copy_size,
-                       (cups_afree_func_t)free);
-
-  if ((attr = ippFindAttribute(response, "media-col-database",
-                              IPP_TAG_BEGIN_COLLECTION)) != NULL) {
-    for (i = 0, count = ippGetCount(attr); i < count; i ++) {
-      cups_size_t temp;   /* Current size */
-
-      media_col   = ippGetCollection(attr, i);
-      media_size  =
-       ippGetCollection(ippFindAttribute(media_col, "media-size",
-                                         IPP_TAG_BEGIN_COLLECTION), 0);
-      x_dim       = ippFindAttribute(media_size, "x-dimension", IPP_TAG_ZERO);
-      y_dim       = ippFindAttribute(media_size, "y-dimension", IPP_TAG_ZERO);
-      pwg         = pwgMediaForSize(ippGetInteger(x_dim, 0),
-                                   ippGetInteger(y_dim, 0));
-
-      if (pwg) {
-       temp.width  = pwg->width;
-       temp.length = pwg->length;
-
-       if ((margin = ippFindAttribute(media_col, "media-bottom-margin",
-                                      IPP_TAG_INTEGER)) != NULL)
-         temp.bottom = ippGetInteger(margin, 0);
-       else
-         temp.bottom = *bottom;
-
-       if ((margin = ippFindAttribute(media_col, "media-left-margin",
-                                      IPP_TAG_INTEGER)) != NULL)
-         temp.left = ippGetInteger(margin, 0);
-       else
-         temp.left = *left;
-
-       if ((margin = ippFindAttribute(media_col, "media-right-margin",
-                                      IPP_TAG_INTEGER)) != NULL)
-         temp.right = ippGetInteger(margin, 0);
-       else
-         temp.right = *right;
-
-       if ((margin = ippFindAttribute(media_col, "media-top-margin",
-                                      IPP_TAG_INTEGER)) != NULL)
-         temp.top = ippGetInteger(margin, 0);
-       else
-         temp.top = *top;
-
-       psname = (pwg->ppd != NULL ? pwg->ppd : pwg->pwg);
-       if (temp.bottom == 0 && temp.left == 0 && temp.right == 0 &&
-           temp.top == 0)
-         snprintf(temp.media, sizeof(temp.media), "%s.Borderless", psname);
-       else
-         strlcpy(temp.media, psname, sizeof(temp.media));
-
-       if (!cupsArrayFind(sizes, &temp))
-         cupsArrayAdd(sizes, &temp);
-      } else if (ippGetValueTag(x_dim) == IPP_TAG_RANGE ||
-                ippGetValueTag(y_dim) == IPP_TAG_RANGE) {
-       /*
-        * Custom size - record the min/max values...
-        */
-
-       int lower, upper;   /* Range values */
-
-       if (ippGetValueTag(x_dim) == IPP_TAG_RANGE)
-         lower = ippGetRange(x_dim, 0, &upper);
-       else
-         lower = upper = ippGetInteger(x_dim, 0);
-
-       if (lower < *min_width)
-         *min_width = lower;
-       if (upper > *max_width)
-         *max_width = upper;
-
-       if (ippGetValueTag(y_dim) == IPP_TAG_RANGE)
-         lower = ippGetRange(y_dim, 0, &upper);
-       else
-         lower = upper = ippGetInteger(y_dim, 0);
-
-       if (lower < *min_length)
-         *min_length = lower;
-       if (upper > *max_length)
-         *max_length = upper;
-      }
-    }
-  }
-  if ((attr = ippFindAttribute(response, "media-size-supported",
-                              IPP_TAG_BEGIN_COLLECTION)) != NULL) {
-    for (i = 0, count = ippGetCount(attr); i < count; i ++) {
-      cups_size_t temp;   /* Current size */
-
-      media_size  = ippGetCollection(attr, i);
-      x_dim       = ippFindAttribute(media_size, "x-dimension", IPP_TAG_ZERO);
-      y_dim       = ippFindAttribute(media_size, "y-dimension", IPP_TAG_ZERO);
-      pwg         = pwgMediaForSize(ippGetInteger(x_dim, 0),
-                                   ippGetInteger(y_dim, 0));
-
-      if (pwg) {
-       temp.width  = pwg->width;
-       temp.length = pwg->length;
-       temp.bottom = *bottom;
-       temp.left   = *left;
-       temp.right  = *right;
-       temp.top    = *top;
-
-       psname = (pwg->ppd != NULL ? pwg->ppd : pwg->pwg);
-       if (temp.bottom == 0 && temp.left == 0 && temp.right == 0 &&
-           temp.top == 0)
-         snprintf(temp.media, sizeof(temp.media), "%s.Borderless", psname);
-       else
-         strlcpy(temp.media, psname, sizeof(temp.media));
-
-       if (!cupsArrayFind(sizes, &temp))
-         cupsArrayAdd(sizes, &temp);
-      } else if (ippGetValueTag(x_dim) == IPP_TAG_RANGE ||
-                ippGetValueTag(y_dim) == IPP_TAG_RANGE) {
-       /*
-        * Custom size - record the min/max values...
-        */
-
-       int lower, upper;   /* Range values */
-
-       if (ippGetValueTag(x_dim) == IPP_TAG_RANGE)
-         lower = ippGetRange(x_dim, 0, &upper);
-       else
-         lower = upper = ippGetInteger(x_dim, 0);
-
-       if (lower < *min_width)
-         *min_width = lower;
-       if (upper > *max_width)
-         *max_width = upper;
-
-       if (ippGetValueTag(y_dim) == IPP_TAG_RANGE)
-         lower = ippGetRange(y_dim, 0, &upper);
-       else
-         lower = upper = ippGetInteger(y_dim, 0);
-
-       if (lower < *min_length)
-         *min_length = lower;
-       if (upper > *max_length)
-         *max_length = upper;
-      }
-    }
-  }
-  if ((attr = ippFindAttribute(response, "media-supported", IPP_TAG_ZERO))
-      != NULL) {
-    for (i = 0, count = ippGetCount(attr); i < count; i ++) {
-      const char  *pwg_size = ippGetString(attr, i, NULL);
-      /* PWG size name */
-      cups_size_t temp, *temp2; /* Current size, found size */
-
-      if ((pwg = pwgMediaForPWG(pwg_size)) != NULL) {
-        if (strstr(pwg_size, "_max_") || strstr(pwg_size, "_max.")) {
-          if (pwg->width > *max_width)
-            *max_width = pwg->width;
-          if (pwg->length > *max_length)
-            *max_length = pwg->length;
-        } else if (strstr(pwg_size, "_min_") || strstr(pwg_size, "_min.")) {
-          if (pwg->width < *min_width)
-            *min_width = pwg->width;
-          if (pwg->length < *min_length)
-            *min_length = pwg->length;
-        } else {
-         temp.width  = pwg->width;
-         temp.length = pwg->length;
-         temp.bottom = *bottom;
-         temp.left   = *left;
-         temp.right  = *right;
-         temp.top    = *top;
-
-         psname = (pwg->ppd != NULL ? pwg->ppd : pwg->pwg);
-         if (temp.bottom == 0 && temp.left == 0 && temp.right == 0 &&
-             temp.top == 0)
-           snprintf(temp.media, sizeof(temp.media), "%s.Borderless", psname);
-         else
-           strlcpy(temp.media, psname, sizeof(temp.media));
-
-         /* Add the printer's original IPP name to an already found size */
-         if ((temp2 = cupsArrayFind(sizes, &temp)) != NULL) {
-           snprintf(temp2->media + strlen(temp2->media),
-                    sizeof(temp2->media) - strlen(temp2->media),
-                    " %s", pwg_size);
-           /* Check if we have also a borderless version of the size and add
-              the original IPP name also there */
-           snprintf(temp.media, sizeof(temp.media), "%s.Borderless", psname);
-           if ((temp2 = cupsArrayFind(sizes, &temp)) != NULL)
-             snprintf(temp2->media + strlen(temp2->media),
-                      sizeof(temp2->media) - strlen(temp2->media),
-                      " %s", pwg_size);
-         } else
-           cupsArrayAdd(sizes, &temp);
-       }
-      }
-    }
-  }
-  return sizes;
-}
-
-
 /*
  * Human-readable strings in the PPDs generated by the PPD generator for
  * using driverless IPP printers with CUPS
@@ -1401,15 +110,15 @@ cfGenerateSizes(ipp_t *response,
  */
 
 /*
- * 'cfCreatePPDFromIPP()' - Create a PPD file describing the capabilities
- *                          of an IPP printer, using info from DNS-SD record
- *                          as fallback (for poor IPP responses, especially
- *                          IPP 1.x legacy)
+ * 'ppdCreatePPDFromIPP()' - Create a PPD file describing the capabilities
+ *                           of an IPP printer, using info from DNS-SD record
+ *                           as fallback (for poor IPP responses, especially
+ *                           IPP 1.x legacy)
  */
 
-char *                                           /* O - PPD filename or NULL on
-                                                       error */
-cfCreatePPDFromIPP (char         *buffer,          /* I - Filename buffer */
+char *                                             /* O - PPD filename or NULL 
+                                                          on error */
+ppdCreatePPDFromIPP(char         *buffer,          /* I - Filename buffer */
                    size_t       bufsize,          /* I - Size of filename
                                                          buffer */
                    ipp_t        *response,        /* I - Get-Printer-Attributes
@@ -1428,46 +137,47 @@ cfCreatePPDFromIPP (char         *buffer,          /* I - Filename buffer */
                    size_t       status_msg_size)  /* I - Size of status message
                                                          buffer */
 {
-  return cfCreatePPDFromIPP2(buffer, bufsize, response, make_model, pdl,
-                            color, duplex, NULL, NULL, NULL, NULL,
-                            status_msg, status_msg_size);
+  return ppdCreatePPDFromIPP2(buffer, bufsize, response, make_model, pdl,
+                             color, duplex, NULL, NULL, NULL, NULL,
+                             status_msg, status_msg_size);
 }
 
 /*
- * 'cfCreatePPDFromIPP2()' - Create a PPD file describing the capabilities
- *                           of an IPP printer, with extra parameters for
- *                           PPDs from a merged IPP record for printer
- *                           clusters
+ * 'ppdCreatePPDFromIPP2()' - Create a PPD file describing the
+ *                            capabilities of an IPP printer, with
+ *                            extra parameters for PPDs from a merged
+ *                            IPP record for printer clusters
  */
 
-char *                                           /* O - PPD filename or NULL on
-                                                       error */
-cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
-                   size_t       bufsize,          /* I - Size of filename
-                                                         buffer */
-                   ipp_t        *response,        /* I - Get-Printer-Attributes
-                                                         response */
-                   const char   *make_model,      /* I - Make and model from
-                                                         DNS-SD */
-                   const char   *pdl,             /* I - List of PDLs from
-                                                         DNS-SD */
-                   int          color,            /* I - Color printer? (from
-                                                         DNS-SD) */
-                   int          duplex,           /* I - Duplex printer? (from
-                                                         DNS-SD) */
-                   cups_array_t *conflicts,       /* I - Array of constraints*/
-                   cups_array_t *sizes,           /* I - Media sizes we've
-                                                         added */ 
-                   char*        default_pagesize, /* I - Default page size*/
-                   const char   *default_cluster_color, /* I - cluster def
-                                                         color (if cluster's
-                                                         attributes are
-                                                         returned) */
-                   char         *status_msg,      /* I - Status message buffer,
-                                                         NULL to ignore
-                                                         message */
-                   size_t       status_msg_size)  /* I - Size of status message
-                                                         buffer */
+char *                                              /* O - PPD filename or NULL
+                                                          on error */
+ppdCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
+                    size_t       bufsize,          /* I - Size of filename
+                                                          buffer */
+                    ipp_t        *response,        /* I - Get-Printer-
+                                                          Attributes response*/
+                    const char   *make_model,      /* I - Make and model from
+                                                          DNS-SD */
+                    const char   *pdl,             /* I - List of PDLs from
+                                                          DNS-SD */
+                    int          color,            /* I - Color printer? (from
+                                                          DNS-SD) */
+                    int          duplex,           /* I - Duplex printer? (from
+                                                          DNS-SD) */
+                    cups_array_t *conflicts,       /* I - Array of
+                                                          constraints */
+                    cups_array_t *sizes,           /* I - Media sizes we've
+                                                          added */ 
+                    char*        default_pagesize, /* I - Default page size*/
+                    const char   *default_cluster_color, /* I - cluster def
+                                                          color (if cluster's
+                                                          attributes are
+                                                          returned) */
+                    char         *status_msg,      /* I - Status message
+                                                          buffer, NULL to
+                                                          ignore message */
+                    size_t       status_msg_size)  /* I - Size of status
+                                                          message buffer */
 {
   cups_file_t          *fp;            /* PPD file */
   cups_array_t         *printer_sizes; /* Media sizes we've added */
@@ -1684,15 +394,13 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
                                                                    NULL));
 
   /* Message catalogs for UI strings */
-  if (opt_strings_catalog == NULL) {
-    opt_strings_catalog = opt_array_new();
-    load_opt_strings_catalog(NULL, opt_strings_catalog);
-  }
+  opt_strings_catalog = cfCatalogOptionArrayNew();
+  cfCatalogLoad(NULL, opt_strings_catalog);
   if ((attr = ippFindAttribute(response, "printer-strings-uri",
                               IPP_TAG_URI)) != NULL) {
-    printer_opt_strings_catalog = opt_array_new();
-    load_opt_strings_catalog(ippGetString(attr, 0, NULL),
-                            printer_opt_strings_catalog);
+    printer_opt_strings_catalog = cfCatalogOptionArrayNew();
+    cfCatalogLoad(ippGetString(attr, 0, NULL),
+                 printer_opt_strings_catalog);
     if (cupsArrayCount(printer_opt_strings_catalog) > 0)
       cupsFilePrintf(fp, "*cupsStringsURI: \"%s\"\n", ippGetString(attr, 0,
                                                                   NULL));
@@ -2103,9 +811,11 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
  /*
   * PageSize/PageRegion/ImageableArea/PaperDimension
   */
-  printer_sizes = cfGenerateSizes(response, &defattr, &min_length, &min_width,
-                                 &max_length, &max_width,
-                                 &bottom, &left, &right, &top, ppdname);
+  cfGenerateSizes(response, CF_GEN_SIZES_DEFAULT, &printer_sizes, &defattr,
+                 NULL, NULL, NULL, NULL, NULL, NULL,
+                 &min_width, &min_length,
+                 &max_width, &max_length,
+                 &left, &bottom, &right, &top, ppdname, NULL);
   if (sizes==NULL) {
     sizes = printer_sizes;
   } else
@@ -2158,17 +868,17 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
       }
 
       if (ippsizename)
-       human_readable = lookup_choice(ippsizename, "media",
-                                      opt_strings_catalog,
-                                      printer_opt_strings_catalog);
+       human_readable = cfCatalogLookUpChoice(ippsizename, "media",
+                                              opt_strings_catalog,
+                                              printer_opt_strings_catalog);
       else
        human_readable = NULL;
       if (!human_readable) {
        pwg = pwgMediaForSize(size->width, size->length);
        if (pwg)
-         human_readable = lookup_choice((char *)pwg->pwg, "media",
-                                        opt_strings_catalog,
-                                        printer_opt_strings_catalog);
+         human_readable = cfCatalogLookUpChoice((char *)pwg->pwg, "media",
+                                                opt_strings_catalog,
+                                                printer_opt_strings_catalog);
       }
 
       if (all_borderless) {
@@ -2203,17 +913,17 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
       }
 
       if (ippsizename)
-       human_readable = lookup_choice(ippsizename, "media",
-                                      opt_strings_catalog,
-                                      printer_opt_strings_catalog);
+       human_readable = cfCatalogLookUpChoice(ippsizename, "media",
+                                              opt_strings_catalog,
+                                              printer_opt_strings_catalog);
       else
        human_readable = NULL;
       if (!human_readable) {
        pwg = pwgMediaForSize(size->width, size->length);
        if (pwg)
-         human_readable = lookup_choice((char *)pwg->pwg, "media",
-                                        opt_strings_catalog,
-                                        printer_opt_strings_catalog);
+         human_readable = cfCatalogLookUpChoice((char *)pwg->pwg, "media",
+                                                opt_strings_catalog,
+                                                printer_opt_strings_catalog);
       }
 
       if (all_borderless) {
@@ -2440,8 +1150,8 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
       "roll-10"
     };
 
-    human_readable = lookup_option("media-source", opt_strings_catalog,
-                                  printer_opt_strings_catalog);
+    human_readable = cfCatalogLookUpOption("media-source", opt_strings_catalog,
+                                          printer_opt_strings_catalog);
     cupsFilePrintf(fp, "*OpenUI *InputSlot/%s: PickOne\n"
                   "*OrderDependency: 10 AnySetup *InputSlot\n",
                   (human_readable ? human_readable : "Media Source"));
@@ -2455,9 +1165,9 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
       if (i == 0 && !have_default)
        cupsFilePrintf(fp, "*DefaultInputSlot: %s\n", ppdname);
 
-      human_readable = lookup_choice((char *)keyword, "media-source",
-                                    opt_strings_catalog,
-                                    printer_opt_strings_catalog);
+      human_readable = cfCatalogLookUpChoice((char *)keyword, "media-source",
+                                            opt_strings_catalog,
+                                            printer_opt_strings_catalog);
       for (j = (int)(sizeof(sources) / sizeof(sources[0])) - 1; j >= 0; j --)
         if (!strcmp(sources[j], keyword))
          break;
@@ -2488,8 +1198,8 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
   if ((attr = ippFindAttribute(response, "media-type-supported",
                               IPP_TAG_ZERO)) != NULL &&
       (count = ippGetCount(attr)) > 1) {
-    human_readable = lookup_option("media-type", opt_strings_catalog,
-                                  printer_opt_strings_catalog);
+    human_readable = cfCatalogLookUpOption("media-type", opt_strings_catalog,
+                                          printer_opt_strings_catalog);
     cupsFilePrintf(fp, "*OpenUI *MediaType/%s: PickOne\n"
                   "*OrderDependency: 10 AnySetup *MediaType\n"
                   "*DefaultMediaType: %s\n",
@@ -2500,9 +1210,9 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
 
       ppdPwgPpdizeName(keyword, ppdname, sizeof(ppdname));
 
-      human_readable = lookup_choice((char *)keyword, "media-type",
-                                    opt_strings_catalog,
-                                    printer_opt_strings_catalog);
+      human_readable = cfCatalogLookUpChoice((char *)keyword, "media-type",
+                                            opt_strings_catalog,
+                                            printer_opt_strings_catalog);
       cupsFilePrintf(fp, "*MediaType %s%s%s: \"<</MediaType(%s)>>setpagedevice\"\n",
                     ppdname,
                     (human_readable ? "/" : ""),
@@ -2525,8 +1235,9 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
     attr = ippFindAttribute(response, "output-mode-supported",
                            IPP_TAG_KEYWORD);
 
-  human_readable = lookup_option("print-color-mode", opt_strings_catalog,
-                                printer_opt_strings_catalog);
+  human_readable = cfCatalogLookUpOption("print-color-mode",
+                                        opt_strings_catalog,
+                                        printer_opt_strings_catalog);
   if (attr && ippGetCount(attr) > 0) {
     const char *default_color = NULL;  /* Default */
     int first_choice = 1;
@@ -2560,9 +1271,9 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
                         (human_readable ? human_readable : "Color Mode"));
        }
 
-       human_readable2 = lookup_choice("bi-level", "print-color-mode",
-                                       opt_strings_catalog,
-                                       printer_opt_strings_catalog);
+       human_readable2 = cfCatalogLookUpChoice("bi-level", "print-color-mode",
+                                               opt_strings_catalog,
+                                               printer_opt_strings_catalog);
         cupsFilePrintf(fp, "*ColorModel FastGray/%s: \"\"\n",
                       (human_readable2 ? human_readable2 : "Text"));
 
@@ -2576,9 +1287,10 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
                         (human_readable ? human_readable : "Color Mode"));
        }
 
-       human_readable2 = lookup_choice("process-bi-level", "print-color-mode",
-                                       opt_strings_catalog,
-                                       printer_opt_strings_catalog);
+       human_readable2 = cfCatalogLookUpChoice("process-bi-level",
+                                               "print-color-mode",
+                                               opt_strings_catalog,
+                                               printer_opt_strings_catalog);
         cupsFilePrintf(fp, "*ColorModel ProcessFastGray/%s: \"\"\n",
                       (human_readable2 ? human_readable2 : "Process Text"));
       } else if (!strcmp(keyword, "auto-monochrome")) {
@@ -2589,9 +1301,10 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
                         (human_readable ? human_readable : "Color Mode"));
        }
 
-       human_readable2 = lookup_choice("auto-monochrome", "print-color-mode",
-                                       opt_strings_catalog,
-                                       printer_opt_strings_catalog);
+       human_readable2 = cfCatalogLookUpChoice("auto-monochrome",
+                                               "print-color-mode",
+                                               opt_strings_catalog,
+                                               printer_opt_strings_catalog);
         cupsFilePrintf(fp, "*ColorModel AutoGray/%s: \"\"\n",
                       (human_readable2 ? human_readable2 : "Auto Monochrome"));
       } else if (!strcmp(keyword, "monochrome")) {
@@ -2602,9 +1315,10 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
                         (human_readable ? human_readable : "Color Mode"));
        }
 
-       human_readable2 = lookup_choice("monochrome", "print-color-mode",
-                                       opt_strings_catalog,
-                                       printer_opt_strings_catalog);
+       human_readable2 = cfCatalogLookUpChoice("monochrome",
+                                               "print-color-mode",
+                                               opt_strings_catalog,
+                                               printer_opt_strings_catalog);
         cupsFilePrintf(fp, "*ColorModel Gray/%s: \"\"\n",
                       (human_readable2 ? human_readable2 : "Monochrome"));
 
@@ -2618,10 +1332,10 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
                         (human_readable ? human_readable : "Color Mode"));
        }
 
-       human_readable2 = lookup_choice("process-monochrome",
-                                       "print-color-mode",
-                                       opt_strings_catalog,
-                                       printer_opt_strings_catalog);
+       human_readable2 = cfCatalogLookUpChoice("process-monochrome",
+                                               "print-color-mode",
+                                               opt_strings_catalog,
+                                               printer_opt_strings_catalog);
         cupsFilePrintf(fp, "*ColorModel ProcessGray/%s: \"\"\n",
                       (human_readable2 ? human_readable2 :
                        "Process Monochrome"));
@@ -2633,9 +1347,9 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
                         (human_readable ? human_readable : "Color Mode"));
        }
 
-       human_readable2 = lookup_choice("color", "print-color-mode",
-                                       opt_strings_catalog,
-                                       printer_opt_strings_catalog);
+       human_readable2 = cfCatalogLookUpChoice("color", "print-color-mode",
+                                               opt_strings_catalog,
+                                               printer_opt_strings_catalog);
         cupsFilePrintf(fp, "*ColorModel RGB/%s: \"\"\n",
                       (human_readable2 ? human_readable2 : "Color"));
 
@@ -2649,9 +1363,10 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
            !ippContainsString(attr, "process-monochrome") &&
            !ippContainsString(attr, "bi-level") &&
            !ippContainsString(attr, "process-bi-level")) {
-         human_readable2 = lookup_choice("monochrome", "print-color-mode",
-                                         opt_strings_catalog,
-                                         printer_opt_strings_catalog);
+         human_readable2 = cfCatalogLookUpChoice("monochrome",
+                                                 "print-color-mode",
+                                                 opt_strings_catalog,
+                                                 printer_opt_strings_catalog);
          cupsFilePrintf(fp, "*ColorModel Gray/%s: \"\"\n",
                         (human_readable2 ? human_readable2 : "Grayscale"));
        }
@@ -2695,24 +1410,25 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
                                IPP_TAG_KEYWORD)) != NULL &&
        ippContainsString(attr, "two-sided-long-edge")) ||
       (attr == NULL && duplex)) {
-    human_readable = lookup_option("sides", opt_strings_catalog,
-                                  printer_opt_strings_catalog);
+    human_readable = cfCatalogLookUpOption("sides", opt_strings_catalog,
+                                          printer_opt_strings_catalog);
     cupsFilePrintf(fp, "*OpenUI *Duplex/%s: PickOne\n"
                   "*OrderDependency: 10 AnySetup *Duplex\n"
                   "*DefaultDuplex: None\n",
                   (human_readable ? human_readable : "2-Sided Printing"));
-    human_readable = lookup_choice("one-sided", "sides", opt_strings_catalog,
-                                  printer_opt_strings_catalog);
+    human_readable = cfCatalogLookUpChoice("one-sided", "sides",
+                                          opt_strings_catalog,
+                                          printer_opt_strings_catalog);
     cupsFilePrintf(fp, "*Duplex None/%s: \"<</Duplex false>>setpagedevice\"\n",
                   (human_readable ? human_readable : "Off"));
-    human_readable = lookup_choice("two-sided-long-edge", "sides",
-                                  opt_strings_catalog,
-                                  printer_opt_strings_catalog);
+    human_readable = cfCatalogLookUpChoice("two-sided-long-edge", "sides",
+                                          opt_strings_catalog,
+                                          printer_opt_strings_catalog);
     cupsFilePrintf(fp, "*Duplex DuplexNoTumble/%s: \"<</Duplex true/Tumble false>>setpagedevice\"\n",
                   (human_readable ? human_readable : "On (Portrait)"));
-    human_readable = lookup_choice("two-sided-short-edge", "sides",
-                                  opt_strings_catalog,
-                                  printer_opt_strings_catalog);
+    human_readable = cfCatalogLookUpChoice("two-sided-short-edge", "sides",
+                                          opt_strings_catalog,
+                                          printer_opt_strings_catalog);
     cupsFilePrintf(fp, "*Duplex DuplexTumble/%s: \"<</Duplex true/Tumble true>>setpagedevice\"\n",
                   (human_readable ? human_readable : "On (Landscape)"));
     cupsFilePrintf(fp, "*CloseUI: *Duplex\n");
@@ -2765,8 +1481,8 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
   if ((attr = ippFindAttribute(response, "output-bin-supported",
                               IPP_TAG_ZERO)) != NULL &&
       (count = ippGetCount(attr)) > 0) {
-    human_readable = lookup_option("output-bin", opt_strings_catalog,
-                                  printer_opt_strings_catalog);
+    human_readable = cfCatalogLookUpOption("output-bin", opt_strings_catalog,
+                                          printer_opt_strings_catalog);
     cupsFilePrintf(fp, "*OpenUI *OutputBin/%s: PickOne\n"
                   "*OrderDependency: 10 AnySetup *OutputBin\n"
                   "*DefaultOutputBin: %s\n",
@@ -2778,9 +1494,9 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
 
       ppdPwgPpdizeName(keyword, ppdname, sizeof(ppdname));
 
-      human_readable = lookup_choice((char *)keyword, "output-bin",
-                                    opt_strings_catalog,
-                                    printer_opt_strings_catalog);
+      human_readable = cfCatalogLookUpChoice((char *)keyword, "output-bin",
+                                            opt_strings_catalog,
+                                            printer_opt_strings_catalog);
       cupsFilePrintf(fp, "*OutputBin %s%s%s: \"\"\n",
                     ppdname,
                     (human_readable ? "/" : ""),
@@ -2904,16 +1620,16 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
 
       cupsArrayAdd(fin_options, "*StapleLocation");
 
-      human_readable = lookup_choice("staple", "finishing-template",
-                                    opt_strings_catalog,
-                                    printer_opt_strings_catalog);
+      human_readable = cfCatalogLookUpChoice("staple", "finishing-template",
+                                            opt_strings_catalog,
+                                            printer_opt_strings_catalog);
       cupsFilePrintf(fp, "*OpenUI *StapleLocation/%s: PickOne\n",
                     (human_readable ? human_readable : "Staple"));
       cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *StapleLocation\n");
       cupsFilePuts(fp, "*DefaultStapleLocation: None\n");
-      human_readable = lookup_choice("3", "finishings",
-                                    opt_strings_catalog,
-                                    printer_opt_strings_catalog);
+      human_readable = cfCatalogLookUpChoice("3", "finishings",
+                                            opt_strings_catalog,
+                                            printer_opt_strings_catalog);
       cupsFilePrintf(fp, "*StapleLocation None/%s: \"\"\n",
                     (human_readable ? human_readable : "None"));
 
@@ -2947,8 +1663,9 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
           continue;
 
        snprintf(buf, sizeof(buf), "%d", value);
-       human_readable = lookup_choice(buf, "finishings", opt_strings_catalog,
-                                      printer_opt_strings_catalog);
+       human_readable = cfCatalogLookUpChoice(buf, "finishings",
+                                              opt_strings_catalog,
+                                              printer_opt_strings_catalog);
        cupsFilePrintf(fp, "*StapleLocation %s%s%s: \"\"\n", ppd_keyword,
                       (human_readable ? "/" : ""),
                       (human_readable ? human_readable : ""));
@@ -2992,16 +1709,16 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
 
       cupsArrayAdd(fin_options, "*FoldType");
 
-      human_readable = lookup_choice("fold", "finishing-template",
-                                    opt_strings_catalog,
-                                    printer_opt_strings_catalog);
+      human_readable = cfCatalogLookUpChoice("fold", "finishing-template",
+                                            opt_strings_catalog,
+                                            printer_opt_strings_catalog);
       cupsFilePrintf(fp, "*OpenUI *FoldType/%s: PickOne\n",
                     (human_readable ? human_readable : "Fold"));
       cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *FoldType\n");
       cupsFilePuts(fp, "*DefaultFoldType: None\n");
-      human_readable = lookup_choice("3", "finishings",
-                                    opt_strings_catalog,
-                                    printer_opt_strings_catalog);
+      human_readable = cfCatalogLookUpChoice("3", "finishings",
+                                            opt_strings_catalog,
+                                            printer_opt_strings_catalog);
       cupsFilePrintf(fp, "*FoldType None/%s: \"\"\n",
                     (human_readable ? human_readable : "None"));
 
@@ -3035,8 +1752,9 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
           continue;
 
        snprintf(buf, sizeof(buf), "%d", value);
-       human_readable = lookup_choice(buf, "finishings", opt_strings_catalog,
-                                      printer_opt_strings_catalog);
+       human_readable = cfCatalogLookUpChoice(buf, "finishings",
+                                              opt_strings_catalog,
+                                              printer_opt_strings_catalog);
        cupsFilePrintf(fp, "*FoldType %s%s%s: \"\"\n", ppd_keyword,
                       (human_readable ? "/" : ""),
                       (human_readable ? human_readable : ""));
@@ -3087,16 +1805,16 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
 
       cupsArrayAdd(fin_options, "*PunchMedia");
 
-      human_readable = lookup_choice("punch", "finishing-template",
-                                    opt_strings_catalog,
-                                    printer_opt_strings_catalog);
+      human_readable = cfCatalogLookUpChoice("punch", "finishing-template",
+                                            opt_strings_catalog,
+                                            printer_opt_strings_catalog);
       cupsFilePrintf(fp, "*OpenUI *PunchMedia/%s: PickOne\n",
                     (human_readable ? human_readable : "Punch"));
       cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *PunchMedia\n");
       cupsFilePuts(fp, "*DefaultPunchMedia: None\n");
-      human_readable = lookup_choice("3", "finishings",
-                                    opt_strings_catalog,
-                                    printer_opt_strings_catalog);
+      human_readable = cfCatalogLookUpChoice("3", "finishings",
+                                            opt_strings_catalog,
+                                            printer_opt_strings_catalog);
       cupsFilePrintf(fp, "*PunchMedia None/%s: \"\"\n",
                     (human_readable ? human_readable : "None"));
 
@@ -3130,8 +1848,9 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
           continue;
 
        snprintf(buf, sizeof(buf), "%d", value);
-       human_readable = lookup_choice(buf, "finishings", opt_strings_catalog,
-                                      printer_opt_strings_catalog);
+       human_readable = cfCatalogLookUpChoice(buf, "finishings",
+                                              opt_strings_catalog,
+                                              printer_opt_strings_catalog);
        cupsFilePrintf(fp, "*PunchMedia %s%s%s: \"\"\n", ppd_keyword,
                       (human_readable ? "/" : ""),
                       (human_readable ? human_readable : ""));
@@ -3149,9 +1868,10 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
     if (ippContainsInteger(attr, IPP_FINISHINGS_BOOKLET_MAKER)) {
       cupsArrayAdd(fin_options, "*Booklet");
 
-      human_readable = lookup_choice("booklet-maker", "finishing-template",
-                                    opt_strings_catalog,
-                                    printer_opt_strings_catalog);
+      human_readable = cfCatalogLookUpChoice("booklet-maker",
+                                            "finishing-template",
+                                            opt_strings_catalog,
+                                            printer_opt_strings_catalog);
       cupsFilePrintf(fp, "*OpenUI *Booklet/%s: Boolean\n",
                     (human_readable ? human_readable : "Booklet"));
       cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *Booklet\n");
@@ -3186,16 +1906,16 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
 
       cupsArrayAdd(fin_options, "*CutMedia");
 
-      human_readable = lookup_choice("trim", "finishing-template",
-                                    opt_strings_catalog,
-                                    printer_opt_strings_catalog);
+      human_readable = cfCatalogLookUpChoice("trim", "finishing-template",
+                                            opt_strings_catalog,
+                                            printer_opt_strings_catalog);
       cupsFilePrintf(fp, "*OpenUI *CutMedia/%s: PickOne\n",
                     (human_readable ? human_readable : "Cut"));
       cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *CutMedia\n");
       cupsFilePuts(fp, "*DefaultCutMedia: None\n");
-      human_readable = lookup_choice("3", "finishings",
-                                    opt_strings_catalog,
-                                    printer_opt_strings_catalog);
+      human_readable = cfCatalogLookUpChoice("3", "finishings",
+                                            opt_strings_catalog,
+                                            printer_opt_strings_catalog);
       cupsFilePrintf(fp, "*CutMedia None/%s: \"\"\n",
                     (human_readable ? human_readable : "None"));
 
@@ -3217,8 +1937,9 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
          ppd_keyword = trim_keywords[value - IPP_FINISHINGS_TRIM_AFTER_PAGES];
 
        snprintf(buf, sizeof(buf), "%d", value);
-       human_readable = lookup_choice(buf, "finishings", opt_strings_catalog,
-                                      printer_opt_strings_catalog);
+       human_readable = cfCatalogLookUpChoice(buf, "finishings",
+                                              opt_strings_catalog,
+                                              printer_opt_strings_catalog);
        cupsFilePrintf(fp, "*CutMedia %s%s%s: \"\"\n", ppd_keyword,
                       (human_readable ? "/" : ""),
                       (human_readable ? human_readable : ""));
@@ -3238,15 +1959,16 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
     ipp_attribute_t *finishing_attr;   /* Current finishing member attribute */
     cups_array_t *templates;           /* Finishing templates */
 
-    human_readable = lookup_option("finishing-template", opt_strings_catalog,
-                                  printer_opt_strings_catalog);
+    human_readable = cfCatalogLookUpOption("finishing-template",
+                                          opt_strings_catalog,
+                                          printer_opt_strings_catalog);
     cupsFilePrintf(fp, "*OpenUI *cupsFinishingTemplate/%s: PickOne\n",
                   (human_readable ? human_readable : "Finishing Template"));
     cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *cupsFinishingTemplate\n");
     cupsFilePuts(fp, "*DefaultcupsFinishingTemplate: none\n");
-    human_readable = lookup_choice("3", "finishings",
-                                  opt_strings_catalog,
-                                  printer_opt_strings_catalog);
+    human_readable = cfCatalogLookUpChoice("3", "finishings",
+                                          opt_strings_catalog,
+                                          printer_opt_strings_catalog);
     cupsFilePrintf(fp, "*cupsFinishingTemplate None/%s: \"\"\n",
                   (human_readable ? human_readable : "None"));
 
@@ -3267,9 +1989,10 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
 
       cupsArrayAdd(templates, (void *)keyword);
 
-      human_readable = lookup_choice((char *)keyword, "finishing-template",
-                                    opt_strings_catalog,
-                                    printer_opt_strings_catalog);
+      human_readable = cfCatalogLookUpChoice((char *)keyword,
+                                            "finishing-template",
+                                            opt_strings_catalog,
+                                            printer_opt_strings_catalog);
       if (human_readable == NULL)
        human_readable = (char *)keyword;
       cupsFilePrintf(fp, "*cupsFinishingTemplate %s/%s: \"\n", keyword,
@@ -3329,27 +2052,30 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
   if ((quality =
        ippFindAttribute(response, "print-quality-supported",
                        IPP_TAG_ENUM)) != NULL) {
-    human_readable = lookup_option("print-quality", opt_strings_catalog,
-                                  printer_opt_strings_catalog);
+    human_readable = cfCatalogLookUpOption("print-quality", opt_strings_catalog,
+                                          printer_opt_strings_catalog);
     cupsFilePrintf(fp, "*OpenUI *cupsPrintQuality/%s: PickOne\n"
                   "*OrderDependency: 10 AnySetup *cupsPrintQuality\n"
                   "*DefaultcupsPrintQuality: Normal\n",
                   (human_readable ? human_readable : "Print Quality"));
     if (ippContainsInteger(quality, IPP_QUALITY_DRAFT)) {
-      human_readable = lookup_choice("3", "print-quality", opt_strings_catalog,
-                                    printer_opt_strings_catalog);
+      human_readable = cfCatalogLookUpChoice("3", "print-quality",
+                                            opt_strings_catalog,
+                                            printer_opt_strings_catalog);
       cupsFilePrintf(fp, "*cupsPrintQuality Draft/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n",
                     (human_readable ? human_readable : "Draft"),
                     min_res->x, min_res->y);
     }
-    human_readable = lookup_choice("4", "print-quality", opt_strings_catalog,
-                                  printer_opt_strings_catalog);
+    human_readable = cfCatalogLookUpChoice("4", "print-quality",
+                                          opt_strings_catalog,
+                                          printer_opt_strings_catalog);
     cupsFilePrintf(fp, "*cupsPrintQuality Normal/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n",
                   (human_readable ? human_readable : "Normal"),
                   common_def->x, common_def->y);
     if (ippContainsInteger(quality, IPP_QUALITY_HIGH)) {
-      human_readable = lookup_choice("5", "print-quality", opt_strings_catalog,
-                                    printer_opt_strings_catalog);
+      human_readable = cfCatalogLookUpChoice("5", "print-quality",
+                                            opt_strings_catalog,
+                                            printer_opt_strings_catalog);
       cupsFilePrintf(fp, "*cupsPrintQuality High/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n",
                     (human_readable ? human_readable : "High"),
                     max_res->x, max_res->y);
@@ -3375,9 +2101,9 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
     if ((attr = ippFindAttribute(response, "print-content-optimize-supported",
                                 IPP_TAG_ZERO)) != NULL &&
        (count = ippGetCount(attr)) > 1) {
-      human_readable = lookup_option("print-content-optimize",
-                                    opt_strings_catalog,
-                                    printer_opt_strings_catalog);
+      human_readable = cfCatalogLookUpOption("print-content-optimize",
+                                            opt_strings_catalog,
+                                            printer_opt_strings_catalog);
       cupsFilePrintf(fp, "*OpenUI *print-content-optimize/%s: PickOne\n"
                     "*OrderDependency: 10 AnySetup *print-content-optimize\n"
                     "*Defaultprint-content-optimize: %s\n",
@@ -3386,10 +2112,10 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
       for (i = 0; i < count; i ++) {
        keyword = ippGetString(attr, i, NULL);
 
-       human_readable = lookup_choice((char *)keyword,
-                                      "print-content-optimize",
-                                      opt_strings_catalog,
-                                      printer_opt_strings_catalog);
+       human_readable = cfCatalogLookUpChoice((char *)keyword,
+                                              "print-content-optimize",
+                                              opt_strings_catalog,
+                                              printer_opt_strings_catalog);
        cupsFilePrintf(fp, "*print-content-optimize %s%s%s: \"\"\n",
                       keyword,
                       (human_readable ? "/" : ""),
@@ -3411,28 +2137,29 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
     if ((attr = ippFindAttribute(response, "print-rendering-intent-supported",
                                 IPP_TAG_ZERO)) != NULL &&
        (count = ippGetCount(attr)) > 1) {
-      human_readable = lookup_option("print-rendering-intent",
-                                    opt_strings_catalog,
-                                    printer_opt_strings_catalog);
-      cupsFilePrintf(fp, "*OpenUI *print-rendering-intent/%s: PickOne\n"
-                    "*OrderDependency: 10 AnySetup *print-rendering-intent\n"
-                    "*Defaultprint-rendering-intent: %s\n",
+      human_readable = cfCatalogLookUpOption("print-rendering-intent",
+                                            opt_strings_catalog,
+                                            printer_opt_strings_catalog);
+      cupsFilePrintf(fp, "*OpenUI *cupsRenderingIntent/%s: PickOne\n"
+                    "*OrderDependency: 10 AnySetup *cupsRenderingIntent\n"
+                    "*DefaultcupsRenderingIntent: %s\n",
                     (human_readable ? human_readable :
                      "Print Rendering Intent"),
                     ppdname);
       for (i = 0; i < count; i ++) {
        keyword = ippGetString(attr, i, NULL);
 
-       human_readable = lookup_choice((char *)keyword,
-                                      "print-rendering-intent",
-                                      opt_strings_catalog,
-                                      printer_opt_strings_catalog);
-       cupsFilePrintf(fp, "*print-rendering-intent %s%s%s: \"\"\n",
+       human_readable = cfCatalogLookUpChoice((char *)keyword,
+                                              "print-rendering-intent",
+                                              opt_strings_catalog,
+                                              printer_opt_strings_catalog);
+       cupsFilePrintf(fp, "*cupsRenderingIntent %s%s%s: \"<</cupsRenderingIntent (%s)>>setpagedevice\"\n",
                       keyword,
                       (human_readable ? "/" : ""),
-                      (human_readable ? human_readable : ""));
+                      (human_readable ? human_readable : ""),
+                      keyword);
       }
-      cupsFilePuts(fp, "*CloseUI: *print-rendering-intent\n");
+      cupsFilePuts(fp, "*CloseUI: *cupsRenderingIntent\n");
     }
 
     /*
@@ -3448,8 +2175,9 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
     if ((attr = ippFindAttribute(response, "print-scaling-supported",
                                 IPP_TAG_ZERO)) != NULL &&
        (count = ippGetCount(attr)) > 1) {
-      human_readable = lookup_option("print-scaling", opt_strings_catalog,
-                                    printer_opt_strings_catalog);
+      human_readable = cfCatalogLookUpOption("print-scaling",
+                                            opt_strings_catalog,
+                                            printer_opt_strings_catalog);
       cupsFilePrintf(fp, "*OpenUI *print-scaling/%s: PickOne\n"
                     "*OrderDependency: 10 AnySetup *print-scaling\n"
                     "*Defaultprint-scaling: %s\n",
@@ -3458,9 +2186,9 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
       for (i = 0; i < count; i ++) {
        keyword = ippGetString(attr, i, NULL);
 
-       human_readable = lookup_choice((char *)keyword, "print-scaling",
-                                      opt_strings_catalog,
-                                      printer_opt_strings_catalog);
+       human_readable = cfCatalogLookUpChoice((char *)keyword, "print-scaling",
+                                              opt_strings_catalog,
+                                              printer_opt_strings_catalog);
        cupsFilePrintf(fp, "*print-scaling %s%s%s: \"\"\n",
                       keyword,
                       (human_readable ? "/" : ""),
@@ -3475,8 +2203,8 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
   */
 
   if (is_fax) {
-    human_readable = lookup_option("Phone", opt_strings_catalog,
-                                  printer_opt_strings_catalog);
+    human_readable = cfCatalogLookUpOption("Phone", opt_strings_catalog,
+                                          printer_opt_strings_catalog);
 
     cupsFilePrintf(fp, "*OpenUI *phone/%s: PickOne\n"
                   "*OrderDependency: 10 AnySetup *phone\n"
@@ -3487,8 +2215,8 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
     cupsFilePrintf(fp,"*Customphone True: \"\"\n"
                   "*ParamCustomphone Text: 1 string 0 64\n");
 
-    human_readable = lookup_option("faxPrefix", opt_strings_catalog,
-                                  printer_opt_strings_catalog);
+    human_readable = cfCatalogLookUpOption("faxPrefix", opt_strings_catalog,
+                                          printer_opt_strings_catalog);
 
     cupsFilePrintf(fp, "*OpenUI *faxPrefix/%s: PickOne\n"
                   "*OrderDependency: 10 AnySetup *faxPrefix\n"
@@ -3519,9 +2247,10 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
       if (!preset || !preset_name)
         continue;
 
-      if ((localized_name = lookup_option((char *)preset_name,
-                                         opt_strings_catalog,
-                                         printer_opt_strings_catalog)) == NULL)
+      if ((localized_name =
+          cfCatalogLookUpOption((char *)preset_name,
+                                opt_strings_catalog,
+                                printer_opt_strings_catalog)) == NULL)
         cupsFilePrintf(fp, "*APPrinterPreset %s: \"\n", preset_name);
       else
         cupsFilePrintf(fp, "*APPrinterPreset %s/%s: \"\n", preset_name,
@@ -3677,6 +2406,8 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
             (is_fax ? "Fax " : ""));
 
   cupsFileClose(fp);
+  if (opt_strings_catalog)
+    cupsArrayDelete(opt_strings_catalog);
   if (printer_opt_strings_catalog)
     cupsArrayDelete(printer_opt_strings_catalog);
 
@@ -3705,5 +2436,3 @@ cfCreatePPDFromIPP2(char         *buffer,          /* I - Filename buffer */
 
   return (NULL);
 }
-
-#endif /* HAVE_CUPS_1_6 */
index 6d2aeb4ef763c5079a68471e93ab8beb0a7c5ee7..cd0243db36a73b8286ad27385ca5b0065184e5de 100644 (file)
@@ -16,6 +16,8 @@
 
 #include "ppd.h"
 #include "debug-internal.h"
+#include <ctype.h>
+#include <errno.h>
 
 
 /*
@@ -24,6 +26,7 @@
 
 static ipp_t           *create_media_col(const char *media, const char *source, const char *type, int width, int length, int bottom, int left, int right, int top);
 static ipp_t           *create_media_size(int width, int length);
+static ipp_t           *create_media_size_ranges(int min_width, int min_length, int max_width, int max_length);
 
 
 /*
@@ -254,23 +257,28 @@ ppdGetOptions(cups_option_t **options,    /* O - Options */
  */
 
 ipp_t *                                        /* O - IPP attributes or `NULL`
-                                          on error */
+                                              on error */
 ppdLoadAttributes(
-    ppd_file_t   *ppd,                 /* I - PPD file data */
-    cups_array_t *docformats)          /* I - document-format-supported
-                                          values */
+    ppd_file_t   *ppd)                 /* I - PPD file data */
 {
   int          i, j;                   /* Looping vars */
+  char          *ptr;
+  cups_array_t  *docformats;           /* document-format-supported
+                                          values */
   ipp_t                *attrs;                 /* Attributes */
   ipp_attribute_t *attr;               /* Current attribute */
+  ipp_attribute_t *aux_attr;           /* Auxiliary attribute */
   ipp_t                *col;                   /* Current collection value */
   ppd_attr_t   *ppd_attr;              /* PPD attribute */
+  ppd_option_t *ppd_option;            /* PPD option */
   ppd_choice_t *ppd_choice;            /* PPD choice */
   ppd_size_t   *ppd_size;              /* Default PPD size */
   pwg_size_t   *pwg_size,              /* Current PWG size */
                *default_size = NULL;   /* Default PWG size */
   const char   *default_source = NULL, /* Default media source */
-               *default_type = NULL;   /* Default media type */
+               *default_type = NULL,   /* Default media type */
+               *default_output_bin = NULL,     /* Default output bin */
+               *default_output_order = NULL;   /* Default output order */
   pwg_map_t    *pwg_map;               /* Mapping from PWG to PPD keywords */
   ppd_cache_t  *pc;                    /* PPD cache */
   ppd_pwg_finishings_t *finishings;    /* Current finishings value */
@@ -279,9 +287,19 @@ ppdLoadAttributes(
   int          margins[10];            /* media-xxx-margin-supported values */
   int          xres,                   /* Default horizontal resolution */
                yres;                   /* Default vertical resolution */
-  int          num_urf;                /* Number of urf-supported values */
-  const char   *urf[10];               /* urf-supported values */
-  char         urf_rs[32];             /* RS value */
+  int           urf_supported_found;
+  int           pwg_raster_found;
+  int           is_texttotext;
+  int          num_items;              /* Number of IPP attribute values */
+  const char   *items[20];             /* IPP attribute values */
+  char         item_buf[64];           /* RS value */
+  int           res_x[20], res_y[20], int_item[20];
+  char          *val,
+                *def_output_bin = NULL,
+                buf[1024];
+  int           def_found,
+                order,
+                face_up;
   static const int     orientation_requested_supported[4] =
   {                                    /* orientation-requested-supported values */
     IPP_ORIENT_PORTRAIT,
@@ -373,8 +391,6 @@ ppdLoadAttributes(
   if (ppd == NULL)
     return (NULL);
 
-  ppdMarkDefaults(ppd);
-
   if (ppd->cache == NULL)
   {
     if ((pc = ppdCacheCreateWithPPD(ppd)) != NULL)
@@ -426,6 +442,22 @@ ppdLoadAttributes(
   if ((ppd_choice = ppdFindMarkedChoice(ppd, "MediaType")) != NULL)
     default_type = ppdCacheGetType(pc, ppd_choice->choice);
 
+  if ((ppd_choice = ppdFindMarkedChoice(ppd, "OutputOrder")) != NULL)
+    default_output_order = ppd_choice->choice;
+  if ((ppd_choice = ppdFindMarkedChoice(ppd, "OutputBin")) != NULL)
+  {
+    default_output_bin = ppd_choice->choice;
+    if (default_output_order == NULL &&
+       (ppd_attr = ppdFindAttr(ppd, "PageStackOrder",
+                               ppd_choice->choice)) != NULL)
+      default_output_order = ppd_attr->value;
+  }
+  if (default_output_order == NULL &&
+      (ppd_attr = ppdFindAttr(ppd, "DefaultOutputOrder", 0)) != NULL)
+    default_output_order = ppd_attr->value;
+  if (default_output_order == NULL)
+    default_output_order = "Normal";
+
   if ((ppd_attr = ppdFindAttr(ppd, "DefaultResolution", NULL)) != NULL)
   {
    /*
@@ -446,26 +478,43 @@ ppdLoadAttributes(
     xres = yres = 300;
   }
 
-  snprintf(urf_rs, sizeof(urf_rs), "RS%d", yres < xres ? yres : xres);
-
-  num_urf = 0;
-  urf[num_urf ++] = "V1.4";
-  urf[num_urf ++] = "CP1";
-  urf[num_urf ++] = urf_rs;
-  urf[num_urf ++] = "W8";
-  if (pc->sides_2sided_long)
-    urf[num_urf ++] = "DM1";
-  if (ppd->color_device)
-    urf[num_urf ++] = "SRGB24";
-
  /*
-  * PostScript printers accept PDF via one of the CUPS PDF to PostScript
-  * filters, along with PostScript (of course) and JPEG...
+  * Data formats which the printer understands, if the PPD specifies
+  * a driver in a "*cupsFilter(2): ..." line, we add the input format
+  * of the driver, as this is what our filter need to produce.
   */
 
-  cupsArrayAdd(docformats, "application/pdf");
-  cupsArrayAdd(docformats, "application/postscript");
-  cupsArrayAdd(docformats, "image/jpeg");
+  docformats = cupsArrayNew3((cups_array_func_t)strcmp, NULL, NULL, 0, NULL,
+                            (cups_afree_func_t)free);
+  is_texttotext = 0;
+  if (ppd->num_filters)
+  {
+    char *filter;
+    for (filter = (char *)cupsArrayFirst(pc->filters);
+        filter;
+        filter = (char *)cupsArrayNext(pc->filters))
+    {
+      char buf[256];
+
+      /* String of the "*cupsfilter:" or "*cupsfilter2:" line */
+      strncpy(buf, filter, sizeof(buf) - 1);
+
+      /* Is the PPD file using the "texttotext" filter? */
+      if (strcmp(buf + strlen(buf) - 10, "texttotext") == 0)
+       is_texttotext = 1;
+
+      /* Separate the first word */
+      ptr = buf;
+      while (*ptr && !isspace(*ptr)) ptr ++;
+      if (*ptr)
+       *ptr = '\0';
+
+      /* Add it to the list of output formats */
+      cupsArrayAdd(docformats, strdup(buf));
+    }
+  }
+  else
+    cupsArrayAdd(docformats, strdup("application/vnd.cups-postscript"));
 
  /*
   * Create the attributes...
@@ -473,14 +522,146 @@ ppdLoadAttributes(
 
   attrs = ippNew();
 
+ /*
+  * Properties of supported Raster formats: Convert from strings
+  * in the PPD files (from driverless PPD auto-generator) into
+  * printer IPP attributes
+  */
+
+  urf_supported_found = 0;
+  pwg_raster_found = 0;
+  for (i = 0; i < ppd->num_attrs; i ++)
+  {
+    ppd_attr = ppd->attrs[i];
+    if ((cupsArrayFind(docformats, (void *)"image/urf") &&
+        strcasecmp(ppd_attr->name, "cupsUrfSupported") == 0) ||
+       (cupsArrayFind(docformats, (void *)"image/pwg-raster") &&
+        strncasecmp(ppd_attr->name, "cupsPwgRaster", 13) == 0) ||
+       (cupsArrayFind(docformats, (void *)"application/PCLm") &&
+        strncasecmp(ppd_attr->name, "cupsPclm", 8) == 0))
+    {
+      /* Convert PPD-style names into IPP-style names */
+      ppdPwgUnppdizeName(ppd_attr->name + 4, item_buf, sizeof(item_buf), NULL);
+      if (strcasecmp(item_buf, "urf-supported") == 0)
+       /* Explicit urf-supported string in the PPD, so we do not need to
+          generate one later */
+       urf_supported_found = 1;
+      if (strncasecmp(item_buf, "pwg-raster-", 11) == 0)
+       /* Explicit pwg-raster-... attributes in the PPD, so we do not need to
+          generate them later */
+       pwg_raster_found = 1;
+      /* Make array from comma-separated list */
+      strncpy(buf, ppd_attr->value, sizeof(buf) - 1);
+      num_items = 0;
+      char *p = buf;
+      do
+      {
+       items[num_items ++] = p;
+       if ((p = strchr(p, ',')) != NULL)
+       {
+         *p = '\0';
+         p ++;
+       }
+      }
+      while (p);
+      if (strlen(items[0]) > 3 &&
+         strncasecmp(items[0] + strlen(items[0]) - 3, "dpi", 3) == 0 &&
+         isdigit(*(items[0] + strlen(items[0]) - 4)))
+      {
+       /* Resolutions */
+       for (j = 0; j < num_items; j ++)
+         if (sscanf(items[j], "%dx%d", &res_x[j], &res_y[j]) == 1)
+           res_y[j] = res_x[j];
+       ippAddResolutions(attrs, IPP_TAG_PRINTER, item_buf, num_items, IPP_RES_PER_INCH, res_x, res_y);
+      }
+      else if (strlen(items[0]) > 0 &&
+              ((int)(strtol(items[0], &p, 10) * 0) || (errno == 0 && *p == '\0')))
+      {
+       /* Integer number(s) */
+       for (j = 0; j < num_items; j ++)
+         int_item[j] = (int)strtol(items[j], NULL, 10);
+       ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, item_buf, num_items, int_item);
+      }
+      else
+       /* General */
+       ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, item_buf, num_items, NULL, items);
+    }
+  }
+
+ /*
+  * Generate urf-supported entry for the printer IPP attributes, if there
+  * is no such entry in the PPD file (from driverless PPD auto-generator
+  */
+
+  if (urf_supported_found == 0 &&
+      cupsArrayFind(docformats, (void *)"image/urf"))
+  {
+    snprintf(item_buf, sizeof(item_buf), "RS%d", yres < xres ? yres : xres);
+
+    num_items = 0;
+    items[num_items ++] = "V1.4";
+    items[num_items ++] = "CP1";
+    items[num_items ++] = item_buf;
+    items[num_items ++] = "W8";
+    if (pc->sides_2sided_long)
+      items[num_items ++] = "DM1";
+    if (ppd->color_device)
+      items[num_items ++] = "SRGB24";
+
+    /* urf-supported IPP attribute */
+    ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "urf-supported", num_items, NULL, items);
+  }
+
+ /*
+  * Generate pwg-raster-document-xxx-supported entries for the printer
+  * IPP attributes, if there is no such entry in the PPD file (from
+  * driverless PPD auto-generator
+  */
+
+  if (pwg_raster_found == 0 &&
+      cupsArrayFind(docformats, (void *)"image/pwg-raster"))
+  {
+    ippAddResolution(attrs, IPP_TAG_PRINTER, "pwg-raster-document-resolution-supported", IPP_RES_PER_INCH, xres, yres);
+
+    if (pc->sides_2sided_long)
+      ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "pwg-raster-document-sheet-back", NULL, "normal");
+
+    if (ppd->color_device)
+      ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "pwg-raster-document-type-supported", (int)(sizeof(pwg_raster_document_type_supported_color) / sizeof(pwg_raster_document_type_supported_color[0])), NULL, pwg_raster_document_type_supported_color);
+    else
+      ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "pwg-raster-document-type-supported", (int)(sizeof(pwg_raster_document_type_supported) / sizeof(pwg_raster_document_type_supported[0])), NULL, pwg_raster_document_type_supported);
+  }
+
+  /* Fax out PPD? */
+  if (((ppd_attr = ppdFindAttr(ppd, "cupsFax", NULL)) != NULL &&
+       strcasecmp(ppd_attr->value, "True") == 0) ||
+      ((ppd_attr = ppdFindAttr(ppd, "cupsIPPFaxOut", NULL)) != NULL &&
+       strcasecmp(ppd_attr->value, "True") == 0))
+  {
+    ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "ipp-features-supported", NULL, "faxout");
+    ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_URI), "printer-uri-supported", NULL, "ipp://localhost/ipp/faxout");
+  }
+  
   /* color-supported */
   ippAddBoolean(attrs, IPP_TAG_PRINTER, "color-supported", (char)ppd->color_device);
 
   /* copies-default */
-  ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "copies-default", 1);
+  if (((ppd_choice = ppdFindMarkedChoice(ppd, "Copies")) == NULL ||
+       (i = atoi(ppd_choice->choice)) <= 0) &&
+      ((ppd_attr = ppdFindAttr(ppd, "DefaultCopies", NULL)) == NULL ||
+       (i = atoi(ppd_attr->value)) <= 0))
+    i = 1;
+  ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "copies-default", i);
 
   /* copies-supported */
-  ippAddRange(attrs, IPP_TAG_PRINTER, "copies-supported", 1, 999);
+  ippAddRange(attrs, IPP_TAG_PRINTER, "copies-supported", 1,
+             pc->max_copies > 0 ? pc->max_copies : 999);
+
+  /* document-format-supported */
+  attr = ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "document-format-supported", cupsArrayCount(docformats), NULL, NULL);
+  for (ptr = (char *)cupsArrayFirst(docformats), i = 0; ptr;
+       ptr = (char *)cupsArrayNext(docformats), i ++)
+    ippSetString(attrs, &attr, i, ptr);
 
   /* document-password-supported */
   ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "document-password-supported", 127);
@@ -576,20 +757,75 @@ ppdLoadAttributes(
 
   ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-bottom-margin-supported", num_margins, margins);
 
-  /* media-col-database */
+  /* landscape-orientation-requested-preferred */
+  if (ppd->landscape < 0)      /* Direction the printer rotates landscape
+                                 (-90) */
+  {
+    /* Rotate clockwise (reverse landscape)*/
+    ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "landscape-orientation-requested-preferred", 5);
+  }
+  else if (ppd->landscape > 0) /* (+90) */
+  {
+    /* Rotate counter-clockwise (landscape) */
+    ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "landscape-orientation-requested-preferred", 4);
+  }
+
+  /* media-col-database and media-col-default */
   attr = ippAddCollections(attrs, IPP_TAG_PRINTER, "media-col-database", pc->num_sizes, NULL);
   for (i = 0, pwg_size = pc->sizes; i < pc->num_sizes; i ++, pwg_size ++)
   {
-    col = create_media_col(pwg_size->map.pwg, NULL, NULL, pwg_size->width, pwg_size->length, pwg_size->bottom, pwg_size->left, pwg_size->right, pwg_size->top);
+    if ((ptr = strchr(pwg_size->map.ppd, '.')) != NULL)
+    {
+      /* Page size variant, use original size's PWG name but PPD's
+        dimensions and margins.
+
+        This way we can associate extra size for overspraying when
+         printing borderless with the original page size, for example
+         for cfFilterPWGToRaster() to correct original-sized PWG
+         Raster to overspray-sized CUPS Raster (for HPLIP for
+         example). Filters can also switch to overspray size if the
+         original size plus zero margins is requested for a job */
+      pwg_size_t *size;
+      memmove(buf, pwg_size->map.ppd, ptr - pwg_size->map.ppd);
+      buf[ptr - pwg_size->map.ppd] = '\0';
+      for (j = 0, size = pc->sizes; j < pc->num_sizes; j ++, size ++)
+       /* Find entry of original size */
+       if (strcasecmp(buf, size->map.ppd) == 0)
+       {
+         ptr = size->map.pwg;
+         break;
+       }
+      if (j == pc->num_sizes)
+       ptr = pwg_size->map.pwg;
+    }
+    else
+      ptr = pwg_size->map.pwg;
+    col = create_media_col(ptr, NULL, NULL, pwg_size->width, pwg_size->length, pwg_size->bottom, pwg_size->left, pwg_size->right, pwg_size->top);
+    if (is_texttotext)
+    {
+      /* Add info about the number of lines and number of columns defined in
+        the PPD for each page size to the appropriate media-col-database
+        entries */
+      snprintf(buf, sizeof(buf), "%sNumColumns", pwg_size->map.ppd);
+      if ((ppd_choice = ppdFindMarkedChoice(ppd, buf)) != NULL &&
+         (j = atoi(ppd_choice->choice)) > 0)
+       ippAddInteger(col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "num-columns", j);
+      snprintf(buf, sizeof(buf), "%sNumLines", pwg_size->map.ppd);
+      if ((ppd_choice = ppdFindMarkedChoice(ppd, buf)) != NULL &&
+         (j = atoi(ppd_choice->choice)) > 0)
+       ippAddInteger(col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "num-lines", j);
+    }
     ippSetCollection(attrs, &attr, i, col);
     ippDelete(col);
+    if (pwg_size == default_size)
+    {
+      /* media-col-default */
+      col = create_media_col(ptr, default_source, default_type, pwg_size->width, pwg_size->length, pwg_size->bottom, pwg_size->left, pwg_size->right, pwg_size->top);
+      ippAddCollection(attrs, IPP_TAG_PRINTER, "media-col-default", col);
+      ippDelete(col);
+    }
   }
 
-  /* media-col-default */
-  col = create_media_col(default_size->map.pwg, default_source, default_type, default_size->width, default_size->length, default_size->bottom, default_size->left, default_size->right, default_size->top);
-  ippAddCollection(attrs, IPP_TAG_PRINTER, "media-col-default", col);
-  ippDelete(col);
-
   /* media-col-ready */
   col = create_media_col(default_size->map.pwg, default_source, default_type, default_size->width, default_size->length, default_size->bottom, default_size->left, default_size->right, default_size->top);
   ippAddCollection(attrs, IPP_TAG_PRINTER, "media-col-ready", col);
@@ -665,13 +901,20 @@ ppdLoadAttributes(
     ippSetString(attrs, &attr, i, pwg_size->map.pwg);
 
   /* media-size-supported */
-  attr = ippAddCollections(attrs, IPP_TAG_PRINTER, "media-size-supported", pc->num_sizes, NULL);
+  attr = ippAddCollections(attrs, IPP_TAG_PRINTER, "media-size-supported", pc->num_sizes + (ppd->variable_sizes ? 1 : 0), NULL);
   for (i = 0, pwg_size = pc->sizes; i < pc->num_sizes; i ++, pwg_size ++)
   {
     col = create_media_size(pwg_size->width, pwg_size->length);
     ippSetCollection(attrs, &attr, i, col);
     ippDelete(col);
   }
+  if (ppd->variable_sizes)
+  {
+    col = create_media_size_ranges(pc->custom_min_width, pc->custom_min_length,
+                                  pc->custom_max_width, pc->custom_max_length);
+    ippSetCollection(attrs, &attr, pc->num_sizes, col);
+    ippDelete(col);
+  }
 
   /* media-source-supported */
   if (pc->num_sources > 0)
@@ -732,23 +975,79 @@ ppdLoadAttributes(
   /* orientation-requested-supported */
   ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "orientation-requested-supported", (int)(sizeof(orientation_requested_supported) / sizeof(orientation_requested_supported[0])), orientation_requested_supported);
 
-  /* output-bin-default */
-  if (pc->num_bins > 0)
-    ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "output-bin-default", NULL, pc->bins->pwg);
-  else
-    ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "output-bin-default", NULL, "face-down");
-
-  /* output-bin-supported */
+  /* output-bin-supported and output-bin-default */
+  def_found = 0;
   if (pc->num_bins > 0)
   {
     attr = ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "output-bin-supported", pc->num_bins, NULL,  NULL);
     for (i = 0, pwg_map = pc->bins; i < pc->num_bins; i ++, pwg_map ++)
+    {
       ippSetString(attrs, &attr, i, pwg_map->pwg);
+      if (default_output_bin && !strcmp(pwg_map->ppd, default_output_bin))
+      {
+       def_output_bin = pwg_map->pwg;
+       def_found = 1;
+      }
+      if ((ppd_attr = ppdFindAttr(ppd, "PageStackOrder",
+                                 pwg_map->ppd)) != NULL)
+       val = ppd_attr->value;
+      else
+       val = NULL;
+      order = (val && strcasecmp(val, "Normal") == 0 ? 1 :
+              (val && strcasecmp(val, "Reverse") == 0 ? -1 : 0));
+      if (i == 0 ||
+         (!def_found && ((order == 1 &&
+                          strcasecmp(default_output_order, "Normal")) ||
+                         (order == -1 &&
+                          strcasecmp(default_output_order, "Reverse")))))
+       def_output_bin = pwg_map->pwg;
+      face_up = (((strcasestr(pwg_map->pwg, "face") &&
+                  strcasestr(pwg_map->pwg, "up")) ||
+                 (strcasestr(pwg_map->ppd, "face") &&
+                  strcasestr(pwg_map->ppd, "up"))) ? 1 :
+                (((strcasestr(pwg_map->pwg, "face") &&
+                   strcasestr(pwg_map->pwg, "down")) ||
+                  (strcasestr(pwg_map->ppd, "face") &&
+                   strcasestr(pwg_map->ppd, "down"))) ? -1 : 0));
+      if (order == 0)
+      {
+       if (face_up != 0)
+         order = -face_up;
+       else
+         order = (strcasecmp(default_output_order, "Normal") == 0 ? 1 :
+                  (strcasecmp(default_output_order, "Reverse") == 0 ? -1 : 0));
+      }
+      if (face_up == 0 && order != 0)
+       face_up = -order;
+      snprintf(buf, sizeof(buf), "type=unknown;maxcapacity=-2;remaining=-2;status=5;stackingorder=%s;pagedelivery=%s;name=%s",
+             (order == -1 ? "lastToFirst" :
+              (order == 1 ? "firstToLast" :
+               "unknown")),
+             (face_up == -1 ? "faceDown" :
+              (face_up == -1 ? "faceUp" :
+               "unknown")),
+             pwg_map->ppd);
+      if (i == 0)
+       aux_attr = ippAddOctetString(attrs, IPP_TAG_PRINTER,
+                                    "printer-output-tray", buf, strlen(buf));
+      else
+       ippSetOctetString(attrs, &aux_attr, i, buf, strlen(buf)); 
+    }
   }
   else
   {
-    ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "output-bin-supported", NULL, "face-down");
+    order = (strcasecmp(default_output_order, "Normal") == 0 ? 1 :
+            (strcasecmp(default_output_order, "Reverse") == 0 ? -1 : 1));
+    def_output_bin = (order == 1 ? "face-down" : "face-up");
+    ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "output-bin-supported", NULL, def_output_bin);
+    snprintf(buf, sizeof(buf), "type=unknown;maxcapacity=-2;remaining=-2;status=5;stackingorder=%s;pagedelivery=%s;name=%s",
+            (order == -1 ? "lastToFirst" : "firstToLast"),
+            (order == -1 ? "faceUp" : "faceDown"),
+            def_output_bin);
+    ippAddOctetString(attrs, IPP_TAG_PRINTER,
+                     "printer-output-tray", buf, strlen(buf));
   }
+  ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "output-bin-default", NULL, def_output_bin);
 
   /* overrides-supported */
   ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "overrides-supported", (int)(sizeof(overrides_supported) / sizeof(overrides_supported[0])), NULL, overrides_supported);
@@ -764,7 +1063,21 @@ ppdLoadAttributes(
     ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "pages-per-minute-color", ppd->throughput);
 
   /* print-color-mode-default */
-  ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-color-mode-default", NULL, ppd->color_device ? "auto" : "monochrome");
+  bool mono =
+    (ppd->color_device &&
+     (((ppd_choice = ppdFindMarkedChoice(ppd, "ColorModel")) != NULL &&
+       (strcasestr(ppd_choice->choice, "mono") ||
+       strcasestr(ppd_choice->choice, "gray") ||
+       strcasestr(ppd_choice->choice, "bw") ||
+       strcasestr(ppd_choice->choice, "bi-level") ||
+       strcasestr(ppd_choice->choice, "bi_level"))) ||
+      ((ppd_choice = ppdFindMarkedChoice(ppd, "OutputMode")) != NULL &&
+       (strcasestr(ppd_choice->choice, "mono") ||
+       strcasestr(ppd_choice->choice, "gray") ||
+       strcasestr(ppd_choice->choice, "bw") ||
+       strcasestr(ppd_choice->choice, "bi-level") ||
+       strcasestr(ppd_choice->choice, "bi_level")))));
+  ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "print-color-mode-default", NULL, ppd->color_device && !mono ? "auto" : "monochrome");
 
   /* print-color-mode-supported */
   if (ppd->color_device)
@@ -785,10 +1098,25 @@ ppdLoadAttributes(
   ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "print-quality-supported", (int)(sizeof(print_quality_supported) / sizeof(print_quality_supported[0])), print_quality_supported);
 
   /* print-rendering-intent-default */
-  ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-rendering-intent-default", NULL, "auto");
+  if ((ppd_choice =
+       ppdFindMarkedChoice(ppd, "cupsRenderingIntent")) != NULL ||
+      (ppd_choice =
+       ppdFindMarkedChoice(ppd, "print-rendering-intent")) != NULL)
+    ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "print-rendering-intent-default", NULL, ppd_choice->choice);
+  else
+    ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-rendering-intent-default", NULL, "auto");
 
   /* print-rendering-intent-supported */
-  ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-rendering-intent-supported", NULL, "auto");
+  if (((ppd_option = ppdFindOption(ppd, "cupsRenderingIntent")) != NULL ||
+       (ppd_option = ppdFindOption(ppd, "print-rendering-intent")) != NULL) &&
+      ppd_option->num_choices > 0)
+  {
+    for (i = 0; i < ppd_option->num_choices && i < sizeof(items); i ++)
+      items[i] = ppd_option->choices[i].choice;
+    ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "print-rendering-intent-supported", i, NULL, items);
+  }
+  else
+    ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-rendering-intent-supported", NULL, "auto");
 
   /* printer-device-id */
   if ((ppd_attr = ppdFindAttr(ppd, "1284DeviceId", NULL)) != NULL)
@@ -807,11 +1135,15 @@ ppdLoadAttributes(
 
     char       device_id[1024];                /* Device ID string */
 
+    //XXX TODO: CMD:
     snprintf(device_id, sizeof(device_id), "MFG:%s;MDL:%s;CMD:PS;", ppd->manufacturer, ppd->modelname);
 
     ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-device-id", NULL, device_id);
   }
 
+  /* printer-info */
+  ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", NULL, ppd->nickname);
+
   /* printer-input-tray */
   if (pc->num_sources > 0)
   {
@@ -838,6 +1170,7 @@ ppdLoadAttributes(
   }
 
   /* printer-make-and-model */
+  // XXX TODO: Rip off driver info
   ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-make-and-model", NULL, ppd->nickname);
 
   /* printer-resolution-default */
@@ -864,33 +1197,91 @@ ppdLoadAttributes(
     ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_TEXT), "printer-supply-description", (int)(sizeof(printer_supply_description) / sizeof(printer_supply_description[0])), NULL, printer_supply_description);
   }
 
-  /* pwg-raster-document-xxx-supported */
-  if (cupsArrayFind(docformats, (void *)"image/pwg-raster"))
-  {
-    ippAddResolution(attrs, IPP_TAG_PRINTER, "pwg-raster-document-resolution-supported", IPP_RES_PER_INCH, xres, yres);
-
-    if (pc->sides_2sided_long)
-      ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "pwg-raster-document-sheet-back", NULL, "normal");
-
-    if (ppd->color_device)
-      ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "pwg-raster-document-type-supported", (int)(sizeof(pwg_raster_document_type_supported_color) / sizeof(pwg_raster_document_type_supported_color[0])), NULL, pwg_raster_document_type_supported_color);
-    else
-      ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "pwg-raster-document-type-supported", (int)(sizeof(pwg_raster_document_type_supported) / sizeof(pwg_raster_document_type_supported[0])), NULL, pwg_raster_document_type_supported);
-  }
-
   /* sides-default */
-  ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "sides-default", NULL, "one-sided");
+  if (pc->sides_option && pc->sides_2sided_long &&
+      ppdIsMarked(ppd, pc->sides_option, pc->sides_2sided_long))
+    ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "sides-default", NULL, "two-sided-long-edge");
+  else if (pc->sides_option && pc->sides_2sided_short &&
+          ppdIsMarked(ppd, pc->sides_option, pc->sides_2sided_short))
+    ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "sides-default", NULL, "two-sided-long-short");
+  else
+    ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "sides-default", NULL, "one-sided");
 
   /* sides-supported */
-  if (pc->sides_2sided_long)
+  if (pc->sides_option && pc->sides_2sided_long)
     ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "sides-supported", (int)(sizeof(sides_supported) / sizeof(sides_supported[0])), NULL, sides_supported);
   else
     ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "sides-supported", NULL, "one-sided");
 
-  /* urf-supported */
-  if (cupsArrayFind(docformats, (void *)"image/urf"))
-    ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "urf-supported", num_urf, NULL, urf);
+  /* Extra attributes for "texttotext" filter */ 
+  if (is_texttotext)
+  {
+    if ((ppd_choice = ppdFindMarkedChoice(ppd, "OverLongLines")) != NULL &&
+       ppd_choice->choice && ppd_choice->choice[0])
+    {
+      ppdPwgUnppdizeName(ppd_choice->choice, buf, sizeof(buf), NULL);
+      ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                  "over-long-lines-default", NULL, buf);
+    }
+
+    if ((ppd_choice = ppdFindMarkedChoice(ppd, "TabWidth")) != NULL &&
+       (i = atoi(ppd_choice->choice)) > 0)
+      ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                   "tab-width-default", i);
 
+    if ((ppd_choice = ppdFindMarkedChoice(ppd, "Pagination")) != NULL &&
+       ppd_choice->choice && ppd_choice->choice[0])
+    {
+      ppdPwgUnppdizeName(ppd_choice->choice, buf, sizeof(buf), NULL);
+      ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                  "pagination-default", NULL, buf);
+    }
+
+    if ((ppd_choice = ppdFindMarkedChoice(ppd, "page-left")) != NULL &&
+       (i = atoi(ppd_choice->choice)) > 0)
+      ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                   "page-left-default", i);
+
+    if ((ppd_choice = ppdFindMarkedChoice(ppd, "page-right")) != NULL &&
+       (i = atoi(ppd_choice->choice)) > 0)
+      ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                   "page-right-default", i);
+
+    if ((ppd_choice = ppdFindMarkedChoice(ppd, "page-top")) != NULL &&
+       (i = atoi(ppd_choice->choice)) > 0)
+      ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                   "page-top-default", i);
+
+    if ((ppd_choice = ppdFindMarkedChoice(ppd, "page-bottom")) != NULL &&
+       (i = atoi(ppd_choice->choice)) > 0)
+      ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                   "page-bottom-default", i);
+
+    if ((ppd_choice = ppdFindMarkedChoice(ppd, "PrinterEncoding")) != NULL &&
+       ppd_choice->choice && ppd_choice->choice[0])
+      ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+                  "printer-encoding-default", NULL, ppd_choice->choice);
+
+    if ((ppd_choice = ppdFindMarkedChoice(ppd, "NewlineCharacters")) != NULL &&
+       ppd_choice->choice && ppd_choice->choice[0])
+    {
+      ppdPwgUnppdizeName(ppd_choice->choice, buf, sizeof(buf), NULL);
+      ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                  "newline-characters-default", NULL, buf);
+    }
+
+    if ((ppd_choice = ppdFindMarkedChoice(ppd, "SendFF")) != NULL &&
+       ppd_choice->choice && ppd_choice->choice[0])
+    {
+      ppdPwgUnppdizeName(ppd_choice->choice, buf, sizeof(buf), NULL);
+      ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                  "send-ff-default", NULL, buf);
+    }
+
+  }
+
+  /* Clean up */
+  cupsArrayDelete(docformats);
   return (attrs);
 }
 
@@ -966,3 +1357,22 @@ create_media_size(int width,              /* I - x-dimension in 2540ths */
 
   return (media_size);
 }
+
+
+/*
+ * 'create_media_size_range()' - Create a media-size range for custom sizes.
+ */
+
+static ipp_t *                                 /* O - media-col collection */
+create_media_size_ranges(int min_width,                /* I - min x dim in 2540ths */
+                        int min_length,        /* I - nin y dim in 2540ths */
+                        int max_width,         /* I - max x dim in 2540ths */
+                        int max_length)        /* I - max y dim in 2540ths */
+{
+  ipp_t        *media_size_ranges = ippNew();          /* media-size value */
+
+  ippAddRange(media_size_ranges, IPP_TAG_PRINTER, "x-dimension", min_width, max_width);
+  ippAddRange(media_size_ranges, IPP_TAG_PRINTER, "y-dimension", min_length, max_length);
+
+  return (media_size_ranges);
+}
diff --git a/ppd/ppd-load-profile.c b/ppd/ppd-load-profile.c
new file mode 100644 (file)
index 0000000..9d44d48
--- /dev/null
@@ -0,0 +1,894 @@
+/*
+ *   PPD color profile attribute lookup functions for libppd.
+ *
+ *   Copyright 2007-2011 by Apple Inc.
+ *   Copyright 1993-2005 by Easy Software Products.
+ *
+ *   These coded instructions, statements, and computer programs are the
+ *   property of Apple Inc. and are protected by Federal copyright
+ *   law.  Distribution and use rights are outlined in the file "COPYING"
+ *   which should have been included with this file.
+ *
+ * Contents:
+ *
+ *   ppdFindColorAttr() - Find a PPD attribute based on the colormodel,
+ *                        media, and resolution.
+ *   ppdLutLoad()       - Load a LUT from a PPD file.
+ *   ppdRGBLoad()       - Load a RGB color profile from a PPD file.
+ *   ppdCMYKLoad()      - Load a CMYK color profile from PPD attributes.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include <config.h>
+#include "ppd.h"
+#include <cupsfilters/filter.h>
+#include <cupsfilters/driver.h>
+#include <string.h>
+#include <ctype.h>
+
+
+/*
+ * 'ppdFindColorAttr()' - Find a PPD attribute based on the colormodel,
+ *                        media, and resolution.
+ */
+
+ppd_attr_t *                                   /* O - Matching attribute or
+                                                      NULL */
+ppdFindColorAttr(ppd_file_t *ppd,              /* I - PPD file */
+                const char *name,              /* I - Attribute name */
+                const char *colormodel,        /* I - Color model */
+                const char *media,             /* I - Media type */
+                const char *resolution,        /* I - Resolution */
+                char       *spec,              /* O - Final selection string */
+                int        specsize,           /* I - Size of string buffer */
+                cf_logfunc_t log,              /* I - Log function */
+                void       *ld)                /* I - Log function data */
+{
+  ppd_attr_t   *attr;                  /* Attribute */
+
+
+ /*
+  * Range check input...
+  */
+
+  if (!ppd || !name || !colormodel || !media || !resolution || !spec ||
+      specsize < IPP_MAX_NAME)
+    return (NULL);
+
+ /*
+  * Look for the attribute with the following keywords:
+  *
+  *     ColorModel.MediaType.Resolution
+  *     ColorModel.Resolution
+  *     ColorModel
+  *     MediaType.Resolution
+  *     MediaType
+  *     Resolution
+  *     ""
+  */
+
+  snprintf(spec, specsize, "%s.%s.%s", colormodel, media, resolution);
+  if (log) log(ld, CF_LOGLEVEL_DEBUG,
+              "Looking for \"*%s %s\"...", name, spec);
+  if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
+    return (attr);
+
+  snprintf(spec, specsize, "%s.%s", colormodel, resolution);
+  if (log) log(ld, CF_LOGLEVEL_DEBUG,
+              "Looking for \"*%s %s\"...", name, spec);
+  if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
+    return (attr);
+
+  snprintf(spec, specsize, "%s", colormodel);
+  if (log) log(ld, CF_LOGLEVEL_DEBUG,
+              "Looking for \"*%s %s\"...", name, spec);
+  if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
+    return (attr);
+
+  snprintf(spec, specsize, "%s.%s", media, resolution);
+  if (log) log(ld, CF_LOGLEVEL_DEBUG,
+              "Looking for \"*%s %s\"...", name, spec);
+  if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
+    return (attr);
+
+  snprintf(spec, specsize, "%s", media);
+  if (log) log(ld, CF_LOGLEVEL_DEBUG,
+              "Looking for \"*%s %s\"...", name, spec);
+  if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
+    return (attr);
+
+  snprintf(spec, specsize, "%s", resolution);
+  if (log) log(ld, CF_LOGLEVEL_DEBUG,
+              "Looking for \"*%s %s\"...", name, spec);
+  if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
+    return (attr);
+
+  spec[0] = '\0';
+  if (log) log(ld, CF_LOGLEVEL_DEBUG,
+              "Looking for \"*%s\"...", name);
+  if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
+    return (attr);
+
+  if (log) log(ld, CF_LOGLEVEL_DEBUG,
+              "No instance of \"*%s\" found...", name);
+
+  return (NULL);
+}
+
+/*
+ * 'ppdLutLoad()' - Load a LUT from a PPD file.
+ */
+
+cf_lut_t *                             /* O - New lookup table */
+ppdLutLoad(ppd_file_t *ppd,            /* I - PPD file */
+            const char *colormodel,    /* I - Color model */
+            const char *media,         /* I - Media type */
+            const char *resolution,    /* I - Resolution */
+           const char *ink,            /* I - Ink name */
+           cf_logfunc_t log,       /* I - Log function */
+           void       *ld)             /* I - Log function data */
+{
+  char         name[PPD_MAX_NAME],     /* Attribute name */
+               spec[PPD_MAX_NAME];     /* Attribute spec */
+  ppd_attr_t   *attr;                  /* Attribute */
+  int          nvals;                  /* Number of values */
+  float                vals[4];                /* Values */
+
+
+ /*
+  * Range check input...
+  */
+
+  if (!ppd || !colormodel || !media || !resolution || !ink)
+    return (NULL);
+
+ /*
+  * Try to find the LUT values...
+  */
+
+  snprintf(name, sizeof(name), "cups%sDither", ink);
+
+  if ((attr = ppdFindColorAttr(ppd, name, colormodel, media, resolution, spec,
+                           sizeof(spec), log, ld)) == NULL)
+    attr = ppdFindColorAttr(ppd, "cupsAllDither", colormodel, media,
+                        resolution, spec, sizeof(spec), log, ld);
+
+  if (!attr)
+    return (NULL);
+
+  vals[0] = 0.0;
+  vals[1] = 0.0;
+  vals[2] = 0.0;
+  vals[3] = 0.0;
+  nvals   = sscanf(attr->value, "%f%f%f", vals + 1, vals + 2, vals + 3) + 1;
+
+  if (log) log(ld, CF_LOGLEVEL_DEBUG,
+              "Loaded LUT %s from PPD with values [%.3f %.3f %.3f %.3f]",
+              name, vals[0], vals[1], vals[2], vals[3]);
+
+  return (cfLutNew(nvals, vals, log, ld));
+}
+
+
+/*
+ * 'ppdRGBLoad()' - Load a RGB color profile from a PPD file.
+ */
+
+cf_rgb_t *                             /* O - New color profile */
+ppdRGBLoad(ppd_file_t *ppd,            /* I - PPD file */
+            const char *colormodel,    /* I - Color model */
+            const char *media,         /* I - Media type */
+            const char *resolution,    /* I - Resolution */
+           cf_logfunc_t log,       /* I - Log function */
+           void       *ld)             /* I - Log function data */
+{
+  int          i,                      /* Looping var */
+               cube_size,              /* Size of color lookup cube */
+               num_channels,           /* Number of color channels */
+               num_samples;            /* Number of color samples */
+  cf_sample_t  *samples;               /* Color samples */
+  float                values[7];              /* Color sample values */
+  char         spec[IPP_MAX_NAME];     /* Profile name */
+  ppd_attr_t   *attr;                  /* Attribute from PPD file */
+  cf_rgb_t     *rgbptr;                /* RGB color profile */
+
+
+ /*
+  * Find the following attributes:
+  *
+  *    cupsRGBProfile  - Specifies the cube size, number of channels, and
+  *                      number of samples
+  *    cupsRGBSample   - Specifies an RGB to CMYK color sample
+  */
+
+  if ((attr = ppdFindColorAttr(ppd, "cupsRGBProfile", colormodel, media,
+                           resolution, spec, sizeof(spec), log, ld)) == NULL)
+  {
+    if (log) log(ld, CF_LOGLEVEL_DEBUG,
+                "No cupsRGBProfile attribute found for the current settings!");
+    return (NULL);
+  }
+
+  if (!attr->value || sscanf(attr->value, "%d%d%d", &cube_size, &num_channels,
+                             &num_samples) != 3)
+  {
+    if (log) log(ld, CF_LOGLEVEL_ERROR,
+                "Bad cupsRGBProfile attribute \'%s\'!",
+                attr->value ? attr->value : "(null)");
+    return (NULL);
+  }
+
+  if (cube_size < 2 || cube_size > 16 ||
+      num_channels < 1 || num_channels > CF_MAX_RGB ||
+      num_samples != (cube_size * cube_size * cube_size))
+  {
+    if (log) log(ld, CF_LOGLEVEL_ERROR,
+                "Bad cupsRGBProfile attribute \'%s\'!",
+                attr->value);
+    return (NULL);
+  }
+
+ /*
+  * Allocate memory for the samples and read them...
+  */
+
+  if ((samples = calloc(num_samples, sizeof(cf_sample_t))) == NULL)
+  {
+    if (log) log(ld, CF_LOGLEVEL_ERROR,
+                "Unable to allocate memory for RGB profile!");
+    return (NULL);
+  }
+
+ /*
+  * Read all of the samples...
+  */
+
+  for (i = 0; i < num_samples; i ++)
+    if ((attr = ppdFindNextAttr(ppd, "cupsRGBSample", spec)) == NULL)
+      break;
+    else if (!attr->value)
+    {
+      if (log) log(ld, CF_LOGLEVEL_ERROR,
+                  "Bad cupsRGBSample value!");
+      break;
+    }
+    else if (sscanf(attr->value, "%f%f%f%f%f%f%f", values + 0,
+                    values + 1, values + 2, values + 3, values + 4, values + 5,
+                    values + 6) != (3 + num_channels))
+    {
+      if (log) log(ld, CF_LOGLEVEL_ERROR,
+                  "Bad cupsRGBSample value!");
+      break;
+    }
+    else
+    {
+      samples[i].rgb[0]    = (int)(255.0 * values[0] + 0.5);
+      samples[i].rgb[1]    = (int)(255.0 * values[1] + 0.5);
+      samples[i].rgb[2]    = (int)(255.0 * values[2] + 0.5);
+      samples[i].colors[0] = (int)(255.0 * values[3] + 0.5);
+      if (num_channels > 1)
+       samples[i].colors[1] = (int)(255.0 * values[4] + 0.5);
+      if (num_channels > 2)
+       samples[i].colors[2] = (int)(255.0 * values[5] + 0.5);
+      if (num_channels > 3)
+       samples[i].colors[3] = (int)(255.0 * values[6] + 0.5);
+    }
+
+ /*
+  * If everything went OK, create the color profile...
+  */
+
+  if (i == num_samples)
+    rgbptr = cfRGBNew(num_samples, samples, cube_size, num_channels);
+  else
+    rgbptr = NULL;
+
+ /*
+  * Free the temporary sample array and return...
+  */
+
+  free(samples);
+
+  return (rgbptr);
+}
+
+
+/*
+ * 'ppdCMYKLoad()' - Load a CMYK color profile from PPD attributes.
+ */
+
+cf_cmyk_t *                            /* O - CMYK color separation */
+ppdCMYKLoad(ppd_file_t *ppd,           /* I - PPD file */
+            const char *colormodel,    /* I - ColorModel value */
+            const char *media,         /* I - MediaType value */
+            const char *resolution,    /* I - Resolution value */
+            cf_logfunc_t log,      /* I - Log function */
+            void       *ld)            /* I - Log function data */
+{
+  cf_cmyk_t    *cmyk;                  /* CMYK color separation */
+  char         spec[IPP_MAX_NAME];     /* Profile name */
+  ppd_attr_t   *attr;                  /* Attribute from PPD file */
+  int          num_channels;           /* Number of color components */
+  float                gamval,                 /* Gamma correction value */
+               density,                /* Density value */
+               light,                  /* Light ink limit */
+               dark,                   /* Light ink cut-off */
+               lower,                  /* Start of black ink */
+               upper;                  /* End of color ink */
+  int          num_xypoints;           /* Number of X,Y points */
+  float                xypoints[100 * 2],      /* X,Y points */
+               *xyptr;                 /* Current X,Y point */
+
+
+ /*
+  * Range check input...
+  */
+
+  if (ppd == NULL || colormodel == NULL || resolution == NULL || media == NULL)
+    return (NULL);
+
+ /*
+  * Find the following attributes:
+  *
+  *     cupsAllGamma          - Set default curve using gamma + density
+  *     cupsAllXY             - Set default curve using XY points
+  *     cupsBlackGamma        - Set black curve using gamma + density
+  *     cupsBlackGeneration   - Set black generation
+  *     cupsBlackLightDark    - Set black light/dark transition
+  *     cupsBlackXY           - Set black curve using XY points
+  *     cupsCyanGamma         - Set cyan curve using gamma + density
+  *     cupsCyanLightDark     - Set cyan light/dark transition
+  *     cupsCyanXY            - Set cyan curve using XY points
+  *     cupsInkChannels       - Set number of color channels
+  *     cupsInkLimit          - Set total ink limit
+  *     cupsLightBlackGamma   - Set light black curve using gamma + density
+  *     cupsLightBlackXY      - Set light black curve using XY points
+  *     cupsLightCyanGamma    - Set light cyan curve using gamma + density
+  *     cupsLightCyanXY       - Set light cyan curve using XY points
+  *     cupsLightMagentaGamma - Set light magenta curve using gamma + density
+  *     cupsLightMagentaXY    - Set light magenta curve using XY points
+  *     cupsMagentaGamma      - Set magenta curve using gamma + density
+  *     cupsMagentaLightDark  - Set magenta light/dark transition
+  *     cupsMagentaXY         - Set magenta curve using XY points
+  *     cupsYellowGamma       - Set yellow curve using gamma + density
+  *     cupsYellowXY          - Set yellow curve using XY points
+  *
+  * The only required attribute is cupsInkChannels.
+  *
+  * The *XY attributes have precedence over the *Gamma attributes, and
+  * the *Light* attributes have precedence over the corresponding
+  * *LightDark* attributes.
+  */
+
+ /*
+  * Get the required cupsInkChannels attribute...
+  */
+
+  if ((attr = ppdFindColorAttr(ppd, "cupsInkChannels", colormodel, media,
+                           resolution, spec, sizeof(spec), log, ld)) == NULL)
+    return (NULL);
+
+  num_channels = atoi(attr->value);
+
+  if (num_channels < 1 || num_channels > 7 || num_channels == 5)
+    return (NULL);
+
+  if ((cmyk = cfCMYKNew(num_channels)) == NULL)
+    return (NULL);
+
+ /*
+  * Get the optional cupsInkLimit attribute...
+  */
+
+  if ((attr = ppdFindColorAttr(ppd, "cupsInkLimit", colormodel, media,
+                           resolution, spec, sizeof(spec), log, ld)) != NULL)
+    cfCMYKSetInkLimit(cmyk, atof(attr->value));
+
+ /*
+  * Get the optional cupsBlackGeneration attribute...
+  */
+
+  if ((attr = ppdFindColorAttr(ppd, "cupsBlackGeneration", colormodel, media,
+                           resolution, spec, sizeof(spec), log, ld)) != NULL)
+  {
+    if (sscanf(attr->value, "%f%f", &lower, &upper) == 2)
+      cfCMYKSetBlack(cmyk, lower, upper, log, ld);
+  }
+
+ /*
+  * Get the optional cupsBlackXY or cupsBlackGamma attributes...
+  */
+
+  if (num_channels != 3)
+  {
+    if ((attr = ppdFindColorAttr(ppd, "cupsBlackXY", colormodel, media,
+                             resolution, spec, sizeof(spec), log, ld)) != NULL)
+    {
+      for (num_xypoints = 0, xyptr = xypoints;
+           attr != NULL && attr->value != NULL && num_xypoints < 100;
+          attr = ppdFindNextAttr(ppd, "cupsBlackXY", spec))
+       if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+       {
+          num_xypoints ++;
+         xyptr += 2;
+       }
+
+      switch (num_channels)
+      {
+       case 1 :
+       case 2 :
+            cfCMYKSetCurve(cmyk, 0, num_xypoints, xypoints, log, ld);
+           break;
+       case 4 :
+            cfCMYKSetCurve(cmyk, 3, num_xypoints, xypoints, log, ld);
+           break;
+       case 6 :
+       case 7 :
+            cfCMYKSetCurve(cmyk, 5, num_xypoints, xypoints, log, ld);
+           break;
+      }
+    }
+    else if ((attr = ppdFindColorAttr(ppd, "cupsBlackGamma", colormodel,
+                                  media, resolution, spec,
+                                 sizeof(spec), log, ld)) != NULL)
+    {
+      if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+       switch (num_channels)
+       {
+         case 1 :
+         case 2 :
+              cfCMYKSetGamma(cmyk, 0, gamval, density, log, ld);
+             break;
+         case 4 :
+              cfCMYKSetGamma(cmyk, 3, gamval, density, log, ld);
+             break;
+         case 6 :
+         case 7 :
+              cfCMYKSetGamma(cmyk, 5, gamval, density, log, ld);
+             break;
+       }
+    }
+    else if ((attr = ppdFindColorAttr(ppd, "cupsAllXY", colormodel, media,
+                                  resolution, spec, sizeof(spec), log, ld)) !=
+            NULL)
+    {
+      for (num_xypoints = 0, xyptr = xypoints;
+           attr != NULL && attr->value != NULL && num_xypoints < 100;
+          attr = ppdFindNextAttr(ppd, "cupsAllXY", spec))
+       if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+       {
+          num_xypoints ++;
+         xyptr += 2;
+       }
+
+      switch (num_channels)
+      {
+       case 1 :
+       case 2 :
+            cfCMYKSetCurve(cmyk, 0, num_xypoints, xypoints, log, ld);
+           break;
+       case 4 :
+            cfCMYKSetCurve(cmyk, 3, num_xypoints, xypoints, log, ld);
+           break;
+       case 6 :
+       case 7 :
+            cfCMYKSetCurve(cmyk, 5, num_xypoints, xypoints, log, ld);
+           break;
+      }
+    }
+    else if ((attr = ppdFindColorAttr(ppd, "cupsAllGamma", colormodel,
+                                  media, resolution, spec,
+                                 sizeof(spec), log, ld)) != NULL &&
+             num_channels != 3)
+    {
+      if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+       switch (num_channels)
+       {
+         case 1 :
+         case 2 :
+              cfCMYKSetGamma(cmyk, 0, gamval, density, log, ld);
+             break;
+         case 4 :
+              cfCMYKSetGamma(cmyk, 3, gamval, density, log, ld);
+             break;
+         case 6 :
+         case 7 :
+              cfCMYKSetGamma(cmyk, 5, gamval, density, log, ld);
+             break;
+       }
+    }
+  }
+
+  if (num_channels > 2)
+  {
+   /*
+    * Get the optional cupsCyanXY or cupsCyanGamma attributes...
+    */
+
+    if ((attr = ppdFindColorAttr(ppd, "cupsCyanXY", colormodel, media,
+                             resolution, spec, sizeof(spec), log, ld)) != NULL)
+    {
+      for (num_xypoints = 0, xyptr = xypoints;
+           attr != NULL && attr->value != NULL && num_xypoints < 100;
+          attr = ppdFindNextAttr(ppd, "cupsCyanXY", spec))
+       if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+       {
+          num_xypoints ++;
+         xyptr += 2;
+       }
+
+      cfCMYKSetCurve(cmyk, 0, num_xypoints, xypoints, log, ld);
+    }
+    else if ((attr = ppdFindColorAttr(ppd, "cupsCyanGamma", colormodel, media,
+                                  resolution, spec, sizeof(spec), log, ld)) !=
+            NULL)
+    {
+      if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+       cfCMYKSetGamma(cmyk, 0, gamval, density, log, ld);
+    }
+    else if ((attr = ppdFindColorAttr(ppd, "cupsAllXY", colormodel, media,
+                                  resolution, spec, sizeof(spec), log, ld)) !=
+            NULL)
+    {
+      for (num_xypoints = 0, xyptr = xypoints;
+           attr != NULL && attr->value != NULL && num_xypoints < 100;
+          attr = ppdFindNextAttr(ppd, "cupsAllXY", spec))
+       if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+       {
+          num_xypoints ++;
+         xyptr += 2;
+       }
+
+      cfCMYKSetCurve(cmyk, 0, num_xypoints, xypoints, log, ld);
+    }
+    else if ((attr = ppdFindColorAttr(ppd, "cupsAllGamma", colormodel, media,
+                                  resolution, spec, sizeof(spec), log, ld)) !=
+            NULL)
+    {
+      if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+       cfCMYKSetGamma(cmyk, 0, gamval, density, log, ld);
+    }
+
+   /*
+    * Get the optional cupsMagentaXY or cupsMagentaGamma attributes...
+    */
+
+    if ((attr = ppdFindColorAttr(ppd, "cupsMagentaXY", colormodel, media,
+                             resolution, spec, sizeof(spec), log, ld)) != NULL)
+    {
+      for (num_xypoints = 0, xyptr = xypoints;
+           attr != NULL && attr->value != NULL && num_xypoints < 100;
+          attr = ppdFindNextAttr(ppd, "cupsMagentaXY", spec))
+       if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+       {
+          num_xypoints ++;
+         xyptr += 2;
+       }
+
+      switch (num_channels)
+      {
+       case 3 :
+       case 4 :
+            cfCMYKSetCurve(cmyk, 1, num_xypoints, xypoints, log, ld);
+           break;
+       case 6 :
+       case 7 :
+            cfCMYKSetCurve(cmyk, 2, num_xypoints, xypoints, log, ld);
+           break;
+      }
+    }
+    else if ((attr = ppdFindColorAttr(ppd, "cupsMagentaGamma", colormodel, media,
+                                  resolution, spec, sizeof(spec), log, ld)) !=
+            NULL)
+    {
+      if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+       switch (num_channels)
+       {
+         case 3 :
+         case 4 :
+              cfCMYKSetGamma(cmyk, 1, gamval, density, log, ld);
+             break;
+         case 6 :
+         case 7 :
+              cfCMYKSetGamma(cmyk, 2, gamval, density, log, ld);
+             break;
+       }
+    }
+    else if ((attr = ppdFindColorAttr(ppd, "cupsAllXY", colormodel, media,
+                                  resolution, spec, sizeof(spec), log, ld)) !=
+            NULL)
+    {
+      for (num_xypoints = 0, xyptr = xypoints;
+           attr != NULL && attr->value != NULL && num_xypoints < 100;
+          attr = ppdFindNextAttr(ppd, "cupsAllXY", spec))
+       if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+       {
+          num_xypoints ++;
+         xyptr += 2;
+       }
+
+      switch (num_channels)
+      {
+       case 3 :
+       case 4 :
+            cfCMYKSetCurve(cmyk, 1, num_xypoints, xypoints, log, ld);
+           break;
+       case 6 :
+       case 7 :
+            cfCMYKSetCurve(cmyk, 2, num_xypoints, xypoints, log, ld);
+           break;
+      }
+    }
+    else if ((attr = ppdFindColorAttr(ppd, "cupsAllGamma", colormodel, media,
+                                  resolution, spec, sizeof(spec), log, ld)) !=
+            NULL)
+    {
+      if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+       switch (num_channels)
+       {
+         case 3 :
+         case 4 :
+              cfCMYKSetGamma(cmyk, 1, gamval, density, log, ld);
+             break;
+         case 6 :
+         case 7 :
+              cfCMYKSetGamma(cmyk, 2, gamval, density, log, ld);
+             break;
+       }
+    }
+
+   /*
+    * Get the optional cupsYellowXY or cupsYellowGamma attributes...
+    */
+
+    if ((attr = ppdFindColorAttr(ppd, "cupsYellowXY", colormodel, media,
+                             resolution, spec, sizeof(spec), log, ld)) != NULL)
+    {
+      for (num_xypoints = 0, xyptr = xypoints;
+           attr != NULL && attr->value != NULL && num_xypoints < 100;
+          attr = ppdFindNextAttr(ppd, "cupsYellowXY", spec))
+       if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+       {
+          num_xypoints ++;
+         xyptr += 2;
+       }
+
+      switch (num_channels)
+      {
+       case 3 :
+       case 4 :
+            cfCMYKSetCurve(cmyk, 2, num_xypoints, xypoints, log, ld);
+           break;
+       case 6 :
+       case 7 :
+            cfCMYKSetCurve(cmyk, 4, num_xypoints, xypoints, log, ld);
+           break;
+      }
+    }
+    else if ((attr = ppdFindColorAttr(ppd, "cupsYellowGamma", colormodel, media,
+                                  resolution, spec, sizeof(spec), log, ld)) !=
+            NULL)
+    {
+      if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+       switch (num_channels)
+       {
+         case 3 :
+         case 4 :
+              cfCMYKSetGamma(cmyk, 2, gamval, density, log, ld);
+             break;
+         case 6 :
+         case 7 :
+              cfCMYKSetGamma(cmyk, 4, gamval, density, log, ld);
+             break;
+       }
+    }
+    else if ((attr = ppdFindColorAttr(ppd, "cupsAllXY", colormodel, media,
+                                  resolution, spec, sizeof(spec), log, ld)) !=
+            NULL)
+    {
+      for (num_xypoints = 0, xyptr = xypoints;
+           attr != NULL && attr->value != NULL && num_xypoints < 100;
+          attr = ppdFindNextAttr(ppd, "cupsAllXY", spec))
+       if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+       {
+          num_xypoints ++;
+         xyptr += 2;
+       }
+
+      switch (num_channels)
+      {
+       case 3 :
+       case 4 :
+            cfCMYKSetCurve(cmyk, 2, num_xypoints, xypoints, log, ld);
+           break;
+       case 6 :
+       case 7 :
+            cfCMYKSetCurve(cmyk, 4, num_xypoints, xypoints, log, ld);
+           break;
+      }
+    }
+    else if ((attr = ppdFindColorAttr(ppd, "cupsAllGamma", colormodel, media,
+                                  resolution, spec, sizeof(spec), log, ld)) !=
+            NULL)
+    {
+      if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+       switch (num_channels)
+       {
+         case 3 :
+         case 4 :
+              cfCMYKSetGamma(cmyk, 2, gamval, density, log, ld);
+             break;
+         case 6 :
+         case 7 :
+              cfCMYKSetGamma(cmyk, 4, gamval, density, log, ld);
+             break;
+       }
+    }
+  }
+
+ /*
+  * Get the optional cupsLightBlackXY, cupsLightBlackGamma, or
+  * cupsBlackLtDk attributes...
+  */
+
+  if (num_channels == 2 || num_channels == 7)
+  {
+    if ((attr = ppdFindColorAttr(ppd, "cupsLightBlackXY", colormodel, media,
+                             resolution, spec, sizeof(spec), log, ld)) != NULL)
+    {
+      for (num_xypoints = 0, xyptr = xypoints;
+           attr != NULL && attr->value != NULL && num_xypoints < 100;
+          attr = ppdFindNextAttr(ppd, "cupsLightBlackXY", spec))
+       if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+       {
+          num_xypoints ++;
+         xyptr += 2;
+       }
+
+      switch (num_channels)
+      {
+       case 2 :
+            cfCMYKSetCurve(cmyk, 1, num_xypoints, xypoints, log, ld);
+           break;
+       case 7 :
+            cfCMYKSetCurve(cmyk, 6, num_xypoints, xypoints, log, ld);
+           break;
+      }
+    }
+    else if ((attr = ppdFindColorAttr(ppd, "cupsLightBlackGamma", colormodel,
+                                  media, resolution, spec,
+                                 sizeof(spec), log, ld)) != NULL)
+    {
+      if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+       switch (num_channels)
+       {
+         case 2 :
+              cfCMYKSetGamma(cmyk, 1, gamval, density, log, ld);
+             break;
+         case 7 :
+              cfCMYKSetGamma(cmyk, 6, gamval, density, log, ld);
+             break;
+       }
+    }
+    else if ((attr = ppdFindColorAttr(ppd, "cupsBlackLtDk", colormodel, media,
+                                  resolution, spec, sizeof(spec), log, ld)) !=
+            NULL)
+    {
+      if (sscanf(attr->value, "%f%f", &light, &dark) == 2)
+       switch (num_channels)
+       {
+         case 2 :
+              cfCMYKSetLtDk(cmyk, 0, light, dark, log, ld);
+             break;
+         case 7 :
+              cfCMYKSetLtDk(cmyk, 5, light, dark, log, ld);
+             break;
+       }
+      else
+       if (log) log(ld, CF_LOGLEVEL_ERROR,
+                    "Bad cupsBlackLtDk value \"%s\"!",
+                    attr->value);
+    }
+    else
+      if (log) log(ld, CF_LOGLEVEL_WARN,
+                  "No light black attribute found for %s!",
+                  spec);
+  }
+
+  if (num_channels >= 6)
+  {
+   /*
+    * Get the optional cupsLightCyanXY, cupsLightCyanGamma, or
+    * cupsCyanLtDk attributes...
+    */
+
+    if ((attr = ppdFindColorAttr(ppd, "cupsLightCyanXY", colormodel, media,
+                             resolution, spec, sizeof(spec), log, ld)) != NULL)
+    {
+      for (num_xypoints = 0, xyptr = xypoints;
+           attr != NULL && attr->value != NULL && num_xypoints < 100;
+          attr = ppdFindNextAttr(ppd, "cupsLightCyanXY", spec))
+       if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+       {
+          num_xypoints ++;
+         xyptr += 2;
+       }
+
+      cfCMYKSetCurve(cmyk, 1, num_xypoints, xypoints, log, ld);
+    }
+    else if ((attr = ppdFindColorAttr(ppd, "cupsLightCyanGamma", colormodel,
+                                  media, resolution, spec,
+                                 sizeof(spec), log, ld)) != NULL)
+    {
+      if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+       cfCMYKSetGamma(cmyk, 1, gamval, density, log, ld);
+    }
+    else if ((attr = ppdFindColorAttr(ppd, "cupsCyanLtDk", colormodel, media,
+                                  resolution, spec, sizeof(spec), log, ld)) !=
+            NULL)
+    {
+      if (sscanf(attr->value, "%f%f", &light, &dark) == 2)
+       cfCMYKSetLtDk(cmyk, 0, light, dark, log, ld);
+      else
+       if (log) log(ld, CF_LOGLEVEL_ERROR,
+                    "Bad cupsCyanLtDk value \"%s\"!",
+                    attr->value);
+    }
+    else
+      if (log) log(ld, CF_LOGLEVEL_WARN,
+                  "No light cyan attribute found for %s!",
+                  spec);
+
+   /*
+    * Get the optional cupsLightMagentaXY, cupsLightMagentaGamma, or
+    * cupsMagentaLtDk attributes...
+    */
+
+    if ((attr = ppdFindColorAttr(ppd, "cupsLightMagentaXY", colormodel, media,
+                             resolution, spec, sizeof(spec), log, ld)) != NULL)
+    {
+      for (num_xypoints = 0, xyptr = xypoints;
+           attr != NULL && attr->value != NULL && num_xypoints < 100;
+          attr = ppdFindNextAttr(ppd, "cupsLightMagentaXY", spec))
+       if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+       {
+          num_xypoints ++;
+         xyptr += 2;
+       }
+
+      cfCMYKSetCurve(cmyk, 3, num_xypoints, xypoints, log, ld);
+    }
+    else if ((attr = ppdFindColorAttr(ppd, "cupsLightMagentaGamma", colormodel,
+                                  media, resolution, spec,
+                                 sizeof(spec), log, ld)) != NULL)
+    {
+      if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+       cfCMYKSetGamma(cmyk, 3, gamval, density, log, ld);
+    }
+    else if ((attr = ppdFindColorAttr(ppd, "cupsMagentaLtDk", colormodel, media,
+                                  resolution, spec, sizeof(spec), log, ld)) !=
+            NULL)
+    {
+      if (sscanf(attr->value, "%f%f", &light, &dark) == 2)
+       cfCMYKSetLtDk(cmyk, 2, light, dark, log, ld);
+      else
+       if (log) log(ld, CF_LOGLEVEL_ERROR,
+                    "Bad cupsMagentaLtDk value \"%s\"!",
+                    attr->value);
+    }
+    else
+      if (log) log(ld, CF_LOGLEVEL_WARN,
+                  "No light magenta attribute found for %s!",
+                  spec);
+  }
+
+ /*
+  * Return the new profile...
+  */
+
+  return (cmyk);
+}
index 11ad63243aa1dab37bb0898f7c8f4b04f28761fb..f1ea670930e5f893ec0ae2cce401bc17fdc4cfe7 100644 (file)
--- a/ppd/ppd.c
+++ b/ppd/ppd.c
@@ -131,6 +131,9 @@ ppdClose(ppd_file_t *ppd)           /* I - PPD file record */
   free(ppd->jcl_begin);
   free(ppd->jcl_end);
   free(ppd->jcl_ps);
+#if HAVE_CUPS_3_X
+  free(ppd->jcl_pdf);
+#endif
 
  /*
   * Free any UI groups, subgroups, and options...
@@ -873,6 +876,13 @@ ppdOpenWithLocalization(
       ppd->jcl_ps = strdup(string);
       ppd_decode(ppd->jcl_ps);         /* Decode quoted string */
     }
+#if HAVE_CUPS_3_X
+    else if (!strcmp(keyword, "JCLToPDFInterpreter"))
+    {
+      ppd->jcl_pdf = strdup(string);
+      ppd_decode(ppd->jcl_pdf);                /* Decode quoted string */
+    }
+#endif
     else if (!strcmp(keyword, "AccurateScreensSupport"))
       ppd->accurate_screens = !strcasecmp(string, "True");
     else if (!strcmp(keyword, "ColorDevice"))
index 81fc86a5534e82b9dff09602919bb29295dfc65c..e434b50cae3ffd89ae376a6013fc542b7d5a5ef7 100644 (file)
--- a/ppd/ppd.h
+++ b/ppd/ppd.h
@@ -26,7 +26,9 @@
 #  include <cupsfilters/log.h>
 
 #  include <stdio.h>
+#  include <stdbool.h>
 #  include <cups/raster.h>
+#  include <cupsfilters/driver.h>
 
 
 /*
@@ -472,6 +474,9 @@ typedef struct ppd_file_s           /**** PPD File ****/
                                           @private@ */
   char         *jcl_begin;             /* Start JCL commands */
   char         *jcl_ps;                /* Enter PostScript interpreter */
+#if HAVE_CUPS_3_X
+  char         *jcl_pdf;               /* Enter PDF interpreter */
+#endif
   char         *jcl_end;               /* End JCL commands */
   char         *lang_encoding;         /* Language encoding */
   char         *lang_version;          /* Language version (English, Spanish,
@@ -757,6 +762,7 @@ extern void         ppdFreeLanguages(cups_array_t *languages);
 extern cups_encoding_t ppdGetEncoding(const char *name);
 extern cups_array_t    *ppdGetLanguages(ppd_file_t *ppd);
 extern ppd_globals_t   *ppdGlobals(void);
+extern void            ppdHandleMedia(ppd_file_t *ppd);
 extern unsigned                ppdHashName(const char *name);
 extern ppd_attr_t      *ppdLocalizedAttr(ppd_file_t *ppd, const char *keyword,
                                          const char *spec, const char *ll_CC);
@@ -787,8 +793,7 @@ extern void         ppdPwgUnppdizeName(const char *ppd, char *name,
                                           const char *dashchars);
 
 /**** New in cups-filters 2.0.0: Overtaken from ippeveprinter ****/
-extern ipp_t           *ppdLoadAttributes(ppd_file_t   *ppd,
-                                          cups_array_t *docformats);
+extern ipp_t           *ppdLoadAttributes(ppd_file_t   *ppd);
 
 /**** New in cups-filters 2.0.0: Overtaken from ippeveps ****/
 extern int             ppdGetOptions(cups_option_t **options,
@@ -822,6 +827,59 @@ extern int         ppdCollectionDumpCache(const char *filename,
 /**** New in cups-filters 2.0.0: For PPD retro-fit Printer Applications ****/
 extern void             ppdCacheAssignPresets(ppd_file_t *ppd, ppd_cache_t *pc);
 
+/**** New in cups-filters 2.0.0: JCL for PDF printers, for
+      ppdFilterPDFToPDF() and ppdFilterImageToPDF() ****/
+extern int              ppdEmitJCLPDF(ppd_file_t *ppd, FILE *fp,
+                                     int job_id, const char *user,
+                                     const char *title,
+                                     int hw_copies, bool hw_collate);
+
+/**** New in cups-filters 2.0.0: PPD file generator for CUPS queues for
+      driverless printers, compared to the one of CUPS this one supports
+      also clusters composed of different printers as composed by
+      cups-browsed, was cfCreatePPDFromIPP(2)() in libcupsfilters before ****/
+char            *ppdCreatePPDFromIPP(char *buffer, size_t bufsize,
+                                    ipp_t *response, const char *make_model,
+                                    const char *pdl, int color, int duplex,
+                                    char *status_msg, size_t status_msg_size);
+char            *ppdCreatePPDFromIPP2(char *buffer, size_t bufsize,
+                                     ipp_t *response, const char *make_model,
+                                     const char *pdl, int color, int duplex,
+                                     cups_array_t* conflicts,
+                                     cups_array_t *sizes,
+                                     char* default_pagesize,
+                                     const char *default_cluster_color,
+                                     char *status_msg, size_t status_msg_size);
+
+/**** New in cups-filters 2.0.0: Functions to load color profile data from
+      PPD files, from driver.h ****/
+extern ppd_attr_t      *ppdFindColorAttr(ppd_file_t *ppd, const char *name,
+                                         const char *colormodel,
+                                         const char *media,
+                                         const char *resolution,
+                                         char *spec, int specsize,
+                                         cf_logfunc_t log,
+                                         void *ld);
+extern cf_lut_t                *ppdLutLoad(ppd_file_t *ppd,
+                                   const char *colormodel,
+                                   const char *media,
+                                   const char *resolution,
+                                   const char *ink,
+                                   cf_logfunc_t log,
+                                   void *ld);
+extern cf_rgb_t                *ppdRGBLoad(ppd_file_t *ppd,
+                                   const char *colormodel,
+                                   const char *media,
+                                   const char *resolution,
+                                   cf_logfunc_t log,
+                                   void *ld);
+extern cf_cmyk_t       *ppdCMYKLoad(ppd_file_t *ppd,
+                                   const char *colormodel,
+                                   const char *media,
+                                   const char *resolution,
+                                   cf_logfunc_t log,
+                                   void *ld);
+
 
 /*
  * C++ magic...
similarity index 93%
rename from cupsfilters/rastertops.c
rename to ppd/rastertops.c
index 03c86bb879f6ca8abbe62e240b95dfd1574262cf..bdb874c863125a7e3c559205cb722cd97e0c6444 100644 (file)
@@ -2,9 +2,9 @@
  * Include necessary headers...
  */
 
-#include "colormanager.h"
-#include "filter.h"
-#include "image.h"
+#include <cupsfilters/colormanager.h>
+#include <cupsfilters/filter.h>
+#include <cupsfilters/image.h>
 #include <config.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -319,23 +319,23 @@ z_error(int ret, /* I - Return status of deflate */
   switch (ret) {
   case Z_ERRNO:
     if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_ERROR,
-                 "cfFilterRasterToPS: zpipe - error in source data or output file");
+                 "ppdFilterRasterToPS: zpipe - error in source data or output file");
     break;
   case Z_STREAM_ERROR:
     if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_ERROR,
-                 "cfFilterRasterToPS: zpipe - invalid compression level");
+                 "ppdFilterRasterToPS: zpipe - invalid compression level");
     break;
   case Z_DATA_ERROR:
     if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_ERROR,
-                 "cfFilterRasterToPS: zpipe - invalid or incomplete deflate data");
+                 "ppdFilterRasterToPS: zpipe - invalid or incomplete deflate data");
     break;
   case Z_MEM_ERROR:
     if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_ERROR,
-                 "cfFilterRasterToPS: zpipe - out of memory");
+                 "ppdFilterRasterToPS: zpipe - out of memory");
     break;
   case Z_VERSION_ERROR:
     if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_ERROR,
-                 "cfFilterRasterToPS: zpipe - zlib version mismatch!");
+                 "ppdFilterRasterToPS: zpipe - zlib version mismatch!");
   }
 }
 
@@ -365,12 +365,12 @@ write_trailer(int  pages, /* I - Number of pages */
 }
 
 /*
- * 'cfFilterRasterToPS()' - Filter function to convert PWG raster input
+ * 'ppdFilterRasterToPS()' - Filter function to convert PWG raster input
  *                  to PostScript
  */
 
 int                         /* O - Error status */
-cfFilterRasterToPS(int inputfd,         /* I - File descriptor input stream */
+ppdFilterRasterToPS(int inputfd,         /* I - File descriptor input stream */
        int outputfd,        /* I - File descriptor output stream */
        int inputseekable,   /* I - Is input stream seekable? (unused) */
        cf_filter_data_t *data, /* I - Job and printer data */
@@ -402,7 +402,7 @@ cfFilterRasterToPS(int inputfd,         /* I - File descriptor input stream */
     if (!iscanceled || !iscanceled(icd))
     {
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterRasterToPS: Unable to open input data stream.");
+                  "ppdFilterRasterToPS: Unable to open input data stream.");
     }
 
     return (1);
@@ -417,7 +417,7 @@ cfFilterRasterToPS(int inputfd,         /* I - File descriptor input stream */
     if (!iscanceled || !iscanceled(icd))
     {
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterRasterToPS: Unable to open output data stream.");
+                  "ppdFilterRasterToPS: Unable to open output data stream.");
     }
 
     cupsFileClose(inputfp);
@@ -447,7 +447,7 @@ cfFilterRasterToPS(int inputfd,         /* I - File descriptor input stream */
     if (iscanceled && iscanceled(icd))
     {
       if (log) log(ld, CF_LOGLEVEL_DEBUG,
-                  "cfFilterRasterToPS: Job canceled");
+                  "ppdFilterRasterToPS: Job canceled");
       break;
     }
 
@@ -468,7 +468,7 @@ cfFilterRasterToPS(int inputfd,         /* I - File descriptor input stream */
     Page ++;
 
     if (log) log(ld, CF_LOGLEVEL_INFO,
-     "cfFilterRasterToPS: Starting page %d.", Page);
+     "ppdFilterRasterToPS: Starting page %d.", Page);
 
    /*
     *  Write the starting of the page
@@ -493,7 +493,7 @@ cfFilterRasterToPS(int inputfd,         /* I - File descriptor input stream */
   if (empty)
   {
      if (log) log(ld, CF_LOGLEVEL_DEBUG,
-      "cfFilterRasterToPS: Input is empty, outputting empty file.");
+      "ppdFilterRasterToPS: Input is empty, outputting empty file.");
      cupsRasterClose(ras);
      return 0;
   }
similarity index 97%
rename from cupsfilters/testdriver.c
rename to ppd/testdriver.c
index 13320fef62252fb7cb7d156f3b56bb8f92843386..1b233620b8a93b6e1901b3246e829f815eb34eb3 100644 (file)
  *   main()      - Enumerate or display PPD files.
  *   cat_ppd()   - Display a PPD file.
  *   list_ppds() - List PPDs.
+ *
+ * Compile with:gcc -o testdriver testdriver.c -I.. -lppd -lcups
  */
 
 /*
  * Include necessary headers...
  */
 
-#include <cups/string-private.h>
+#include <ppd/ppd.h>
+#include <ppd/string-private.h>
 #include <cups/cups.h>
 
 
index c050dd187496408b3667a6e8c97b7e4281513d95..056463c89f5041fd3792056351b0e553ce061138 100644 (file)
@@ -122,7 +122,7 @@ static int  ldap_rebind_proc(LDAP *RebindLDAPHandle,
 #include <cups/cups.h>
 #include <cups/raster.h>
 #include <cupsfilters/ipp.h>
-#include <cupsfilters/ppdgenerator.h>
+#include <cupsfilters/ipp.h>
 #include <ppd/ppd.h>
 
 #include "cups-notifier.h"
@@ -2097,17 +2097,13 @@ static cups_array_t* get_pagesize(ipp_t *printer_attributes)
 {
   cups_array_t            *sizes, *page_media;
   cups_size_t             *size;
-  ipp_attribute_t         *defattr;
-  char                    *ppdsizename, *temp;
-  int                     min_length = INT_MAX, min_width = INT_MAX,
-                          max_length = 0, max_width = 0,
-                          bottom, left, right, top;
-  char                    ppdname[41];
+  char                    *ppdsizename, *ptr;
 
   ppdsizename = (char *)malloc(sizeof(char) * 128);
-  sizes = cfGenerateSizes(printer_attributes, &defattr, &min_length, &min_width,
-                         &max_length, &max_width,
-                         &bottom, &left, &right, &top,ppdname);
+  cfGenerateSizes(printer_attributes, CF_GEN_SIZES_DEFAULT,
+                 &sizes, NULL, NULL, NULL, NULL,
+                 NULL, NULL, NULL, NULL, NULL, NULL,
+                 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
   if ((page_media = cupsArrayNew3((cups_array_func_t)strcasecmp, NULL, NULL, 0,
                                  (cups_acopy_func_t)strdup,
                                  (cups_afree_func_t)free)) == NULL)
@@ -2115,8 +2111,8 @@ static cups_array_t* get_pagesize(ipp_t *printer_attributes)
   for (size = (cups_size_t *)cupsArrayFirst(sizes); size;
        size = (cups_size_t *)cupsArrayNext(sizes)) {
     strcpy(ppdsizename, size->media);
-    if (( temp = strchr(ppdsizename, ' ')) != NULL)
-      *temp = '\0';
+    if (( ptr = strchr(ppdsizename, ' ')) != NULL)
+      *ptr = '\0';
     cupsArrayAdd(page_media, ppdsizename);
   }
   free(ppdsizename);
@@ -2714,11 +2710,8 @@ cups_array_t* get_cluster_sizes(char* cluster_name)
                        *sizes_ppdname;
   cups_size_t          *size;
   remote_printer_t     *p;
-  ipp_attribute_t      *defattr;
-  char                 ppdname[41], pagesize[128];
+  char                 pagesize[128];
   char*                first_space;
-  int                  min_length, min_width, max_length, max_width,
-                       bottom, left, right, top;
 
   cluster_sizes = cupsArrayNew3((cups_array_func_t)pwg_compare_sizes,
                                NULL, NULL, 0,
@@ -2733,18 +2726,10 @@ cups_array_t* get_cluster_sizes(char* cluster_name)
       if(p->status == STATUS_DISAPPEARED || p->status == STATUS_UNCONFIRMED ||
         p->status == STATUS_TO_BE_RELEASED )
        continue;
-      defattr = NULL;
-      min_length = INT_MAX;
-      min_width = INT_MAX;
-      max_length = 0;
-      max_width = 0;
-      bottom = 0;
-      left = 0;
-      right = 0;
-      top = 0;
-      sizes = cfGenerateSizes(p->prattrs, &defattr, &min_length, &min_width,
-                             &max_length, &max_width,
-                             &bottom, &left, &right, &top, ppdname);
+      cfGenerateSizes(p->prattrs, CF_GEN_SIZES_DEFAULT,
+                     &sizes, NULL, NULL, NULL, NULL,
+                     NULL, NULL, NULL, NULL, NULL, NULL,
+                     NULL, NULL, NULL, NULL, NULL, NULL, NULL);
       for (size = (cups_size_t *)cupsArrayFirst(sizes);
           size; size = (cups_size_t *)cupsArrayNext(sizes)) {
        if (!cupsArrayFind(cluster_sizes, size)) {
@@ -2893,7 +2878,7 @@ cups_array_t* generate_cluster_conflicts(char* cluster_name,
 
 /*get_cluster_attributes - Returns ipp_t* containing the options supplied by
                            all the printers in the cluster, which can be sent
-                           to cfCreatePPDFromIPP2() to generate the PPD file */
+                           to ppdCreatePPDFromIPP2() to generate the PPD file */
 ipp_t* get_cluster_attributes(char* cluster_name)
 {
   remote_printer_t     *p;
@@ -2983,7 +2968,7 @@ void get_cluster_default_attributes(ipp_t** merged_attributes,
   int                     max_pages_per_min = 0, pages_per_min;
   remote_printer_t        *p, *def_printer = NULL;
   int                     i, count;
-  ipp_attribute_t         *attr, *media_attr, *media_col_default, *defattr;
+  ipp_attribute_t         *attr, *media_attr, *media_col_default;
   ipp_t                   *media_col,
                           *media_size, *current_media=NULL;
   char                    media_source[32], media_type[32];
@@ -2992,11 +2977,7 @@ void get_cluster_default_attributes(ipp_t** merged_attributes,
   const char              *keyword;
   cf_res_t                *res;
   int                     xres, yres;
-  int                     min_length = INT_MAX, min_width = INT_MAX,
-                          max_length = 0, max_width = 0,
-                          bottom, left, right, top;
   char                    ppdname[41];
-  cups_array_t            *sizes;
 
   /*The printer with the maximum Throughtput(pages_per_min) is selected as 
     the default printer*/
@@ -3036,9 +3017,11 @@ void get_cluster_default_attributes(ipp_t** merged_attributes,
   debug_printf("Default Attributes of the cluster %s are : \n", cluster_name);
 
   /* Generating the default pagesize for the cluster*/
-  sizes = cfGenerateSizes(def_printer->prattrs, &defattr, &min_length,
-                         &min_width, &max_length, &max_width,
-                         &bottom, &left, &right, &top, ppdname);
+  cfGenerateSizes(def_printer->prattrs, CF_GEN_SIZES_DEFAULT,
+                 NULL, NULL, NULL, NULL,
+                 NULL, NULL, NULL, NULL, NULL, NULL,
+                 NULL, NULL, NULL, NULL, NULL, NULL,
+                 ppdname, NULL);
   strcpy(default_pagesize, ppdname);
   debug_printf("Default PageSize : %s\n", default_pagesize);
 
@@ -3257,8 +3240,6 @@ void get_cluster_default_attributes(ipp_t** merged_attributes,
       cfFreeResolution(res, NULL);
     }
   }
-
-  cupsArrayDelete(sizes);
 }
 
 /* Function to see which printer in the cluster supports the
@@ -8026,11 +8007,11 @@ void create_queue(void* arg) {
          ourselves */
       printer_ipp_response = (num_cluster_printers == 1) ? p->prattrs :
         printer_attributes;
-      if (!cfCreatePPDFromIPP2(ppdname, sizeof(ppdname), printer_ipp_response,
-                              make_model,
-                              pdl, color, duplex, conflicts, sizes,
-                              default_pagesize, default_color,
-                              ppdgenerator_msg, sizeof(ppdgenerator_msg))) {
+      if (!ppdCreatePPDFromIPP2(ppdname, sizeof(ppdname), printer_ipp_response,
+                               make_model,
+                               pdl, color, duplex, conflicts, sizes,
+                               default_pagesize, default_color,
+                               ppdgenerator_msg, sizeof(ppdgenerator_msg))) {
         if (errno != 0)
          debug_printf("Unable to create PPD file: %s\n",
                       strerror(errno));
@@ -8192,11 +8173,11 @@ void create_queue(void* arg) {
           ourselves */
        printer_ipp_response = (num_cluster_printers == 1) ? p->prattrs :
          printer_attributes;
-       if (!cfCreatePPDFromIPP2(ppdname, sizeof(ppdname), printer_ipp_response,
-                                make_model,
-                                pdl, color, duplex, conflicts, sizes,
-                                default_pagesize, default_color,
-                                ppdgenerator_msg, sizeof(ppdgenerator_msg))) {
+       if (!ppdCreatePPDFromIPP2(ppdname, sizeof(ppdname),
+                                 printer_ipp_response, make_model,
+                                 pdl, color, duplex, conflicts, sizes,
+                                 default_pagesize, default_color,
+                                 ppdgenerator_msg, sizeof(ppdgenerator_msg))) {
          if (errno != 0)
            debug_printf("Unable to create PPD file: %s\n",
                         strerror(errno));
index 4c1fc048e1f2dda48e317371b03bb8f52e260893..7ec3f5de37a8fb126ff11385436b92eed0478373 100644 (file)
@@ -36,7 +36,7 @@
 #include <ppd/ppd.h>
 #include <cups/raster.h>
 #include <cupsfilters/ipp.h>
-#include <cupsfilters/ppdgenerator.h>
+#include <cupsfilters/ipp.h>
 
 #define MAX_OUTPUT_LEN 8192
 
@@ -641,8 +641,8 @@ generate_ppd (const char *uri, int isFax)
   }
 
   /* Generate the PPD file */
-  if (!cfCreatePPDFromIPP(ppdname, sizeof(ppdname), response, NULL, NULL, 0,
-                         0, ppdgenerator_msg, sizeof(ppdgenerator_msg))) {
+  if (!ppdCreatePPDFromIPP(ppdname, sizeof(ppdname), response, NULL, NULL, 0,
+                          0, ppdgenerator_msg, sizeof(ppdgenerator_msg))) {
     if (strlen(ppdgenerator_msg) > 0)
       fprintf(stderr, "ERROR: Unable to create PPD file: %s\n",
              ppdgenerator_msg);