]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cups/testppd.c
Merge pull request #5621 from zdohnal/cgigetarray-sigsegv
[thirdparty/cups.git] / cups / testppd.c
index 6d5065c66eeb30ea97caf35a02622c911421f968..36707f29a65588782b4abf6914638b11fc2673b4 100644 (file)
@@ -1,16 +1,11 @@
 /*
  * PPD test program for CUPS.
  *
- * Copyright 2007-2015 by Apple Inc.
- * Copyright 1997-2006 by Easy Software Products.
+ * Copyright © 2007-2018 by Apple Inc.
+ * Copyright © 1997-2006 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 "LICENSE.txt"
- * which should have been included with this file.  If this file is
- * file is missing or damaged, see the license at "http://www.cups.org/".
- *
- * This file is subject to the Apple OS-Developed Software exception.
+ * Licensed under Apache License v2.0.  See the file "LICENSE" for more
+ * information.
  */
 
 /*
 #undef _CUPS_NO_DEPRECATED
 #include "cups-private.h"
 #include "ppd-private.h"
+#include "raster-private.h"
 #include <sys/stat.h>
-#ifdef WIN32
+#ifdef _WIN32
 #  include <io.h>
 #else
 #  include <unistd.h>
 #  include <fcntl.h>
-#endif /* WIN32 */
+#endif /* _WIN32 */
 #include <math.h>
 
 
+/*
+ * Local functions...
+ */
+
+static int     do_ppd_tests(const char *filename, int num_options, cups_option_t *options);
+static int     do_ps_tests(void);
+static void    print_changes(cups_page_header2_t *header, cups_page_header2_t *expected);
+
+
 /*
  * Test data...
  */
 
+static const char *dsc_code =
+"[{\n"
+"%%BeginFeature: *PageSize Tabloid\n"
+"<</PageSize[792 1224]>>setpagedevice\n"
+"%%EndFeature\n"
+"} stopped cleartomark\n";
+static const char *setpagedevice_code =
+"<<"
+"/MediaClass(Media Class)"
+"/MediaColor((Media Color))"
+"/MediaType(Media\\\\Type)"
+"/OutputType<416263>"
+"/AdvanceDistance 1000"
+"/AdvanceMedia 1"
+"/Collate false"
+"/CutMedia 2"
+"/Duplex true"
+"/HWResolution[100 200]"
+"/InsertSheet true"
+"/Jog 3"
+"/LeadingEdge 1"
+"/ManualFeed true"
+"/MediaPosition 8#777"
+"/MediaWeight 16#fe01"
+"/MirrorPrint true"
+"/NegativePrint true"
+"/NumCopies 1"
+"/Orientation 1"
+"/OutputFaceUp true"
+"/PageSize[612 792.1]"
+"/Separations true"
+"/TraySwitch true"
+"/Tumble true"
+"/cupsMediaType 2"
+"/cupsColorOrder 1"
+"/cupsColorSpace 1"
+"/cupsCompression 1"
+"/cupsRowCount 1"
+"/cupsRowFeed 1"
+"/cupsRowStep 1"
+"/cupsBorderlessScalingFactor 1.001"
+"/cupsInteger0 1"
+"/cupsInteger1 2"
+"/cupsInteger2 3"
+"/cupsInteger3 4"
+"/cupsInteger4 5"
+"/cupsInteger5 6"
+"/cupsInteger6 7"
+"/cupsInteger7 8"
+"/cupsInteger8 9"
+"/cupsInteger9 10"
+"/cupsInteger10 11"
+"/cupsInteger11 12"
+"/cupsInteger12 13"
+"/cupsInteger13 14"
+"/cupsInteger14 15"
+"/cupsInteger15 16"
+"/cupsReal0 1.1"
+"/cupsReal1 2.1"
+"/cupsReal2 3.1"
+"/cupsReal3 4.1"
+"/cupsReal4 5.1"
+"/cupsReal5 6.1"
+"/cupsReal6 7.1"
+"/cupsReal7 8.1"
+"/cupsReal8 9.1"
+"/cupsReal9 10.1"
+"/cupsReal10 11.1"
+"/cupsReal11 12.1"
+"/cupsReal12 13.1"
+"/cupsReal13 14.1"
+"/cupsReal14 15.1"
+"/cupsReal15 16.1"
+"/cupsString0(1)"
+"/cupsString1(2)"
+"/cupsString2(3)"
+"/cupsString3(4)"
+"/cupsString4(5)"
+"/cupsString5(6)"
+"/cupsString6(7)"
+"/cupsString7(8)"
+"/cupsString8(9)"
+"/cupsString9(10)"
+"/cupsString10(11)"
+"/cupsString11(12)"
+"/cupsString12(13)"
+"/cupsString13(14)"
+"/cupsString14(15)"
+"/cupsString15(16)"
+"/cupsMarkerType(Marker Type)"
+"/cupsRenderingIntent(Rendering Intent)"
+"/cupsPageSizeName(Letter)"
+"/cupsPreferredBitsPerColor 17"
+">> setpagedevice";
+
+static cups_page_header2_t setpagedevice_header =
+{
+  "Media Class",                       /* MediaClass */
+  "(Media Color)",                     /* MediaColor */
+  "Media\\Type",                       /* MediaType */
+  "Abc",                               /* OutputType */
+  1000,                                        /* AdvanceDistance */
+  CUPS_ADVANCE_FILE,                   /* AdvanceMedia */
+  CUPS_FALSE,                          /* Collate */
+  CUPS_CUT_JOB,                                /* CutMedia */
+  CUPS_TRUE,                           /* Duplex */
+  { 100, 200 },                                /* HWResolution */
+  { 0, 0, 0, 0 },                      /* ImagingBoundingBox */
+  CUPS_TRUE,                           /* InsertSheet */
+  CUPS_JOG_SET,                                /* Jog */
+  CUPS_EDGE_RIGHT,                     /* LeadingEdge */
+  { 0, 0 },                            /* Margins */
+  CUPS_TRUE,                           /* ManualFeed */
+  0777,                                        /* MediaPosition */
+  0xfe01,                              /* MediaWeight */
+  CUPS_TRUE,                           /* MirrorPrint */
+  CUPS_TRUE,                           /* NegativePrint */
+  1,                                   /* NumCopies */
+  CUPS_ORIENT_90,                      /* Orientation */
+  CUPS_TRUE,                           /* OutputFaceUp */
+  { 612, 792 },                                /* PageSize */
+  CUPS_TRUE,                           /* Separations */
+  CUPS_TRUE,                           /* TraySwitch */
+  CUPS_TRUE,                           /* Tumble */
+  0,                                   /* cupsWidth */
+  0,                                   /* cupsHeight */
+  2,                                   /* cupsMediaType */
+  0,                                   /* cupsBitsPerColor */
+  0,                                   /* cupsBitsPerPixel */
+  0,                                   /* cupsBytesPerLine */
+  CUPS_ORDER_BANDED,                   /* cupsColorOrder */
+  CUPS_CSPACE_RGB,                     /* cupsColorSpace */
+  1,                                   /* cupsCompression */
+  1,                                   /* cupsRowCount */
+  1,                                   /* cupsRowFeed */
+  1,                                   /* cupsRowStep */
+  0,                                   /* cupsNumColors */
+  1.001f,                              /* cupsBorderlessScalingFactor */
+  { 612.0f, 792.1f },                  /* cupsPageSize */
+  { 0.0f, 0.0f, 0.0f, 0.0f },          /* cupsImagingBBox */
+  { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 },
+                                       /* cupsInteger[16] */
+  { 1.1f, 2.1f, 3.1f, 4.1f, 5.1f, 6.1f, 7.1f, 8.1f, 9.1f, 10.1f, 11.1f, 12.1f, 13.1f, 14.1f, 15.1f, 16.1f },                   /* cupsReal[16] */
+  { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13",
+    "14", "15", "16" },                        /* cupsString[16] */
+  "Marker Type",                       /* cupsMarkerType */
+  "Rendering Intent",                  /* cupsRenderingIntent */
+  "Letter"                             /* cupsPageSizeName */
+};
+
 static const char      *default_code =
                        "[{\n"
                        "%%BeginFeature: *InstalledDuplexer False\n"
@@ -144,7 +299,7 @@ main(int  argc,                             /* I - Number of command-line arguments */
      char *argv[])                     /* I - Command-line arguments */
 {
   int          i;                      /* Looping var */
-  ppd_file_t   *ppd;                   /* PPD file loaded from disk */
+  ppd_file_t   *ppd = NULL;            /* PPD file loaded from disk */
   int          status;                 /* Status of tests (0 = success, 1 = fail) */
   int          conflicts;              /* Number of conflicts */
   char         *s;                     /* String */
@@ -861,6 +1016,42 @@ main(int  argc,                           /* I - Number of command-line arguments */
       puts("FAIL (returned 0)");
       status ++;
     }
+
+    status += do_ps_tests();
+  }
+  else if (!strcmp(argv[1], "--raster"))
+  {
+    for (status = 0, num_options = 0, options = NULL, i = 1; i < argc; i ++)
+    {
+      if (argv[i][0] == '-')
+      {
+        if (argv[i][1] == 'o')
+        {
+          if (argv[i][2])
+            num_options = cupsParseOptions(argv[i] + 2, num_options, &options);
+          else
+          {
+            i ++;
+            if (i < argc)
+              num_options = cupsParseOptions(argv[i], num_options, &options);
+            else
+            {
+              puts("Usage: testppd --raster [-o name=value ...] [filename.ppd ...]");
+              return (1);
+            }
+          }
+        }
+        else
+        {
+         puts("Usage: testppd --raster [-o name=value ...] [filename.ppd ...]");
+         return (1);
+        }
+      }
+      else
+       status += do_ppd_tests(argv[i], num_options, options);
+    }
+
+    cupsFreeOptions(num_options, options);
   }
   else if (!strncmp(argv[1], "ipp://", 6) || !strncmp(argv[1], "ipps://", 7))
   {
@@ -876,6 +1067,13 @@ main(int  argc,                           /* I - Number of command-line arguments */
                host[256],              /* Hostname */
                resource[256];          /* Resource path */
     int                port;                   /* Port number */
+    static const char * const pattrs[] =/* Requested printer attributes */
+    {
+      "job-template",
+      "printer-defaults",
+      "printer-description",
+      "media-col-database"
+    };
 
     if (httpSeparateURI(HTTP_URI_CODING_ALL, argv[1], scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
     {
@@ -892,6 +1090,7 @@ main(int  argc,                            /* I - Number of command-line arguments */
 
     request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, argv[1]);
+    ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]), NULL, pattrs);
     response = cupsDoRequest(http, request, resource);
 
     if (_ppdCreateFromIPP(buffer, sizeof(buffer), response))
@@ -1046,6 +1245,10 @@ main(int  argc,                          /* I - Number of command-line arguments */
             {
              switch (cparam->type)
              {
+               case PPD_CUSTOM_UNKNOWN :
+                   printf("              %s(%s): PPD_CUSTOM_UNKNOWN (error)\n", cparam->name, cparam->text);
+                   break;
+
                case PPD_CUSTOM_CURVE :
                    printf("              %s(%s): PPD_CUSTOM_CURVE (%g to %g)\n",
                           cparam->name, cparam->text,
@@ -1166,3 +1369,418 @@ main(int  argc,                         /* I - Number of command-line arguments */
 
   return (status);
 }
+
+
+/*
+ * 'do_ppd_tests()' - Test the default option commands in a PPD file.
+ */
+
+static int                             /* O - Number of errors */
+do_ppd_tests(const char    *filename,  /* I - PPD file */
+             int           num_options,        /* I - Number of options */
+             cups_option_t *options)   /* I - Options */
+{
+  ppd_file_t           *ppd;           /* PPD file data */
+  cups_page_header2_t  header;         /* Page header */
+
+
+  printf("\"%s\": ", filename);
+  fflush(stdout);
+
+  if ((ppd = ppdOpenFile(filename)) == NULL)
+  {
+    ppd_status_t       status;         /* Status from PPD loader */
+    int                        line;           /* Line number containing error */
+
+
+    status = ppdLastError(&line);
+
+    puts("FAIL (bad PPD file)");
+    printf("    %s on line %d\n", ppdErrorString(status), line);
+
+    return (1);
+  }
+
+  ppdMarkDefaults(ppd);
+  cupsMarkOptions(ppd, num_options, options);
+
+  if (cupsRasterInterpretPPD(&header, ppd, 0, NULL, NULL))
+  {
+    puts("FAIL (error from function)");
+    puts(cupsRasterErrorString());
+
+    return (1);
+  }
+  else
+  {
+    puts("PASS");
+
+    return (0);
+  }
+}
+
+
+/*
+ * 'do_ps_tests()' - Test standard PostScript commands.
+ */
+
+static int
+do_ps_tests(void)
+{
+  cups_page_header2_t  header;         /* Page header */
+  int                  preferred_bits; /* Preferred bits */
+  int                  errors = 0;     /* Number of errors */
+
+
+ /*
+  * Test PS exec code...
+  */
+
+  fputs("_cupsRasterExecPS(\"setpagedevice\"): ", stdout);
+  fflush(stdout);
+
+  memset(&header, 0, sizeof(header));
+  header.Collate = CUPS_TRUE;
+  preferred_bits = 0;
+
+  if (_cupsRasterExecPS(&header, &preferred_bits, setpagedevice_code))
+  {
+    puts("FAIL (error from function)");
+    puts(cupsRasterErrorString());
+    errors ++;
+  }
+  else if (preferred_bits != 17 ||
+           memcmp(&header, &setpagedevice_header, sizeof(header)))
+  {
+    puts("FAIL (bad header)");
+
+    if (preferred_bits != 17)
+      printf("    cupsPreferredBitsPerColor %d, expected 17\n",
+             preferred_bits);
+
+    print_changes(&setpagedevice_header, &header);
+    errors ++;
+  }
+  else
+    puts("PASS");
+
+  fputs("_cupsRasterExecPS(\"roll\"): ", stdout);
+  fflush(stdout);
+
+  if (_cupsRasterExecPS(&header, &preferred_bits,
+                        "792 612 0 0 0\n"
+                       "pop pop pop\n"
+                       "<</PageSize[5 -2 roll]/ImagingBBox null>>"
+                       "setpagedevice\n"))
+  {
+    puts("FAIL (error from function)");
+    puts(cupsRasterErrorString());
+    errors ++;
+  }
+  else if (header.PageSize[0] != 792 || header.PageSize[1] != 612)
+  {
+    printf("FAIL (PageSize [%d %d], expected [792 612])\n", header.PageSize[0],
+           header.PageSize[1]);
+    errors ++;
+  }
+  else
+    puts("PASS");
+
+  fputs("_cupsRasterExecPS(\"dup index\"): ", stdout);
+  fflush(stdout);
+
+  if (_cupsRasterExecPS(&header, &preferred_bits,
+                        "true false dup\n"
+                       "<</Collate 4 index"
+                       "/Duplex 5 index"
+                       "/Tumble 6 index>>setpagedevice\n"
+                       "pop pop pop"))
+  {
+    puts("FAIL (error from function)");
+    puts(cupsRasterErrorString());
+    errors ++;
+  }
+  else
+  {
+    if (!header.Collate)
+    {
+      printf("FAIL (Collate false, expected true)\n");
+      errors ++;
+    }
+
+    if (header.Duplex)
+    {
+      printf("FAIL (Duplex true, expected false)\n");
+      errors ++;
+    }
+
+    if (header.Tumble)
+    {
+      printf("FAIL (Tumble true, expected false)\n");
+      errors ++;
+    }
+
+    if(header.Collate && !header.Duplex && !header.Tumble)
+      puts("PASS");
+  }
+
+  fputs("_cupsRasterExecPS(\"%%Begin/EndFeature code\"): ", stdout);
+  fflush(stdout);
+
+  if (_cupsRasterExecPS(&header, &preferred_bits, dsc_code))
+  {
+    puts("FAIL (error from function)");
+    puts(cupsRasterErrorString());
+    errors ++;
+  }
+  else if (header.PageSize[0] != 792 || header.PageSize[1] != 1224)
+  {
+    printf("FAIL (bad PageSize [%d %d], expected [792 1224])\n",
+           header.PageSize[0], header.PageSize[1]);
+    errors ++;
+  }
+  else
+    puts("PASS");
+
+  return (errors);
+}
+
+
+
+
+/*
+ * 'print_changes()' - Print differences in the page header.
+ */
+
+static void
+print_changes(
+    cups_page_header2_t *header,       /* I - Actual page header */
+    cups_page_header2_t *expected)     /* I - Expected page header */
+{
+  int  i;                              /* Looping var */
+
+
+  if (strcmp(header->MediaClass, expected->MediaClass))
+    printf("    MediaClass (%s), expected (%s)\n", header->MediaClass,
+           expected->MediaClass);
+
+  if (strcmp(header->MediaColor, expected->MediaColor))
+    printf("    MediaColor (%s), expected (%s)\n", header->MediaColor,
+           expected->MediaColor);
+
+  if (strcmp(header->MediaType, expected->MediaType))
+    printf("    MediaType (%s), expected (%s)\n", header->MediaType,
+           expected->MediaType);
+
+  if (strcmp(header->OutputType, expected->OutputType))
+    printf("    OutputType (%s), expected (%s)\n", header->OutputType,
+           expected->OutputType);
+
+  if (header->AdvanceDistance != expected->AdvanceDistance)
+    printf("    AdvanceDistance %d, expected %d\n", header->AdvanceDistance,
+           expected->AdvanceDistance);
+
+  if (header->AdvanceMedia != expected->AdvanceMedia)
+    printf("    AdvanceMedia %d, expected %d\n", header->AdvanceMedia,
+           expected->AdvanceMedia);
+
+  if (header->Collate != expected->Collate)
+    printf("    Collate %d, expected %d\n", header->Collate,
+           expected->Collate);
+
+  if (header->CutMedia != expected->CutMedia)
+    printf("    CutMedia %d, expected %d\n", header->CutMedia,
+           expected->CutMedia);
+
+  if (header->Duplex != expected->Duplex)
+    printf("    Duplex %d, expected %d\n", header->Duplex,
+           expected->Duplex);
+
+  if (header->HWResolution[0] != expected->HWResolution[0] ||
+      header->HWResolution[1] != expected->HWResolution[1])
+    printf("    HWResolution [%d %d], expected [%d %d]\n",
+           header->HWResolution[0], header->HWResolution[1],
+           expected->HWResolution[0], expected->HWResolution[1]);
+
+  if (memcmp(header->ImagingBoundingBox, expected->ImagingBoundingBox,
+             sizeof(header->ImagingBoundingBox)))
+    printf("    ImagingBoundingBox [%d %d %d %d], expected [%d %d %d %d]\n",
+           header->ImagingBoundingBox[0],
+           header->ImagingBoundingBox[1],
+           header->ImagingBoundingBox[2],
+           header->ImagingBoundingBox[3],
+           expected->ImagingBoundingBox[0],
+           expected->ImagingBoundingBox[1],
+           expected->ImagingBoundingBox[2],
+           expected->ImagingBoundingBox[3]);
+
+  if (header->InsertSheet != expected->InsertSheet)
+    printf("    InsertSheet %d, expected %d\n", header->InsertSheet,
+           expected->InsertSheet);
+
+  if (header->Jog != expected->Jog)
+    printf("    Jog %d, expected %d\n", header->Jog,
+           expected->Jog);
+
+  if (header->LeadingEdge != expected->LeadingEdge)
+    printf("    LeadingEdge %d, expected %d\n", header->LeadingEdge,
+           expected->LeadingEdge);
+
+  if (header->Margins[0] != expected->Margins[0] ||
+      header->Margins[1] != expected->Margins[1])
+    printf("    Margins [%d %d], expected [%d %d]\n",
+           header->Margins[0], header->Margins[1],
+           expected->Margins[0], expected->Margins[1]);
+
+  if (header->ManualFeed != expected->ManualFeed)
+    printf("    ManualFeed %d, expected %d\n", header->ManualFeed,
+           expected->ManualFeed);
+
+  if (header->MediaPosition != expected->MediaPosition)
+    printf("    MediaPosition %d, expected %d\n", header->MediaPosition,
+           expected->MediaPosition);
+
+  if (header->MediaWeight != expected->MediaWeight)
+    printf("    MediaWeight %d, expected %d\n", header->MediaWeight,
+           expected->MediaWeight);
+
+  if (header->MirrorPrint != expected->MirrorPrint)
+    printf("    MirrorPrint %d, expected %d\n", header->MirrorPrint,
+           expected->MirrorPrint);
+
+  if (header->NegativePrint != expected->NegativePrint)
+    printf("    NegativePrint %d, expected %d\n", header->NegativePrint,
+           expected->NegativePrint);
+
+  if (header->NumCopies != expected->NumCopies)
+    printf("    NumCopies %d, expected %d\n", header->NumCopies,
+           expected->NumCopies);
+
+  if (header->Orientation != expected->Orientation)
+    printf("    Orientation %d, expected %d\n", header->Orientation,
+           expected->Orientation);
+
+  if (header->OutputFaceUp != expected->OutputFaceUp)
+    printf("    OutputFaceUp %d, expected %d\n", header->OutputFaceUp,
+           expected->OutputFaceUp);
+
+  if (header->PageSize[0] != expected->PageSize[0] ||
+      header->PageSize[1] != expected->PageSize[1])
+    printf("    PageSize [%d %d], expected [%d %d]\n",
+           header->PageSize[0], header->PageSize[1],
+           expected->PageSize[0], expected->PageSize[1]);
+
+  if (header->Separations != expected->Separations)
+    printf("    Separations %d, expected %d\n", header->Separations,
+           expected->Separations);
+
+  if (header->TraySwitch != expected->TraySwitch)
+    printf("    TraySwitch %d, expected %d\n", header->TraySwitch,
+           expected->TraySwitch);
+
+  if (header->Tumble != expected->Tumble)
+    printf("    Tumble %d, expected %d\n", header->Tumble,
+           expected->Tumble);
+
+  if (header->cupsWidth != expected->cupsWidth)
+    printf("    cupsWidth %d, expected %d\n", header->cupsWidth,
+           expected->cupsWidth);
+
+  if (header->cupsHeight != expected->cupsHeight)
+    printf("    cupsHeight %d, expected %d\n", header->cupsHeight,
+           expected->cupsHeight);
+
+  if (header->cupsMediaType != expected->cupsMediaType)
+    printf("    cupsMediaType %d, expected %d\n", header->cupsMediaType,
+           expected->cupsMediaType);
+
+  if (header->cupsBitsPerColor != expected->cupsBitsPerColor)
+    printf("    cupsBitsPerColor %d, expected %d\n", header->cupsBitsPerColor,
+           expected->cupsBitsPerColor);
+
+  if (header->cupsBitsPerPixel != expected->cupsBitsPerPixel)
+    printf("    cupsBitsPerPixel %d, expected %d\n", header->cupsBitsPerPixel,
+           expected->cupsBitsPerPixel);
+
+  if (header->cupsBytesPerLine != expected->cupsBytesPerLine)
+    printf("    cupsBytesPerLine %d, expected %d\n", header->cupsBytesPerLine,
+           expected->cupsBytesPerLine);
+
+  if (header->cupsColorOrder != expected->cupsColorOrder)
+    printf("    cupsColorOrder %d, expected %d\n", header->cupsColorOrder,
+           expected->cupsColorOrder);
+
+  if (header->cupsColorSpace != expected->cupsColorSpace)
+    printf("    cupsColorSpace %s, expected %s\n", _cupsRasterColorSpaceString(header->cupsColorSpace),
+           _cupsRasterColorSpaceString(expected->cupsColorSpace));
+
+  if (header->cupsCompression != expected->cupsCompression)
+    printf("    cupsCompression %d, expected %d\n", header->cupsCompression,
+           expected->cupsCompression);
+
+  if (header->cupsRowCount != expected->cupsRowCount)
+    printf("    cupsRowCount %d, expected %d\n", header->cupsRowCount,
+           expected->cupsRowCount);
+
+  if (header->cupsRowFeed != expected->cupsRowFeed)
+    printf("    cupsRowFeed %d, expected %d\n", header->cupsRowFeed,
+           expected->cupsRowFeed);
+
+  if (header->cupsRowStep != expected->cupsRowStep)
+    printf("    cupsRowStep %d, expected %d\n", header->cupsRowStep,
+           expected->cupsRowStep);
+
+  if (header->cupsNumColors != expected->cupsNumColors)
+    printf("    cupsNumColors %d, expected %d\n", header->cupsNumColors,
+           expected->cupsNumColors);
+
+  if (fabs(header->cupsBorderlessScalingFactor - expected->cupsBorderlessScalingFactor) > 0.001)
+    printf("    cupsBorderlessScalingFactor %g, expected %g\n",
+           header->cupsBorderlessScalingFactor,
+           expected->cupsBorderlessScalingFactor);
+
+  if (fabs(header->cupsPageSize[0] - expected->cupsPageSize[0]) > 0.001 ||
+      fabs(header->cupsPageSize[1] - expected->cupsPageSize[1]) > 0.001)
+    printf("    cupsPageSize [%g %g], expected [%g %g]\n",
+           header->cupsPageSize[0], header->cupsPageSize[1],
+           expected->cupsPageSize[0], expected->cupsPageSize[1]);
+
+  if (fabs(header->cupsImagingBBox[0] - expected->cupsImagingBBox[0]) > 0.001 ||
+      fabs(header->cupsImagingBBox[1] - expected->cupsImagingBBox[1]) > 0.001 ||
+      fabs(header->cupsImagingBBox[2] - expected->cupsImagingBBox[2]) > 0.001 ||
+      fabs(header->cupsImagingBBox[3] - expected->cupsImagingBBox[3]) > 0.001)
+    printf("    cupsImagingBBox [%g %g %g %g], expected [%g %g %g %g]\n",
+           header->cupsImagingBBox[0], header->cupsImagingBBox[1],
+           header->cupsImagingBBox[2], header->cupsImagingBBox[3],
+           expected->cupsImagingBBox[0], expected->cupsImagingBBox[1],
+           expected->cupsImagingBBox[2], expected->cupsImagingBBox[3]);
+
+  for (i = 0; i < 16; i ++)
+    if (header->cupsInteger[i] != expected->cupsInteger[i])
+      printf("    cupsInteger%d %d, expected %d\n", i, header->cupsInteger[i],
+             expected->cupsInteger[i]);
+
+  for (i = 0; i < 16; i ++)
+    if (fabs(header->cupsReal[i] - expected->cupsReal[i]) > 0.001)
+      printf("    cupsReal%d %g, expected %g\n", i, header->cupsReal[i],
+             expected->cupsReal[i]);
+
+  for (i = 0; i < 16; i ++)
+    if (strcmp(header->cupsString[i], expected->cupsString[i]))
+      printf("    cupsString%d (%s), expected (%s)\n", i,
+            header->cupsString[i], expected->cupsString[i]);
+
+  if (strcmp(header->cupsMarkerType, expected->cupsMarkerType))
+    printf("    cupsMarkerType (%s), expected (%s)\n", header->cupsMarkerType,
+           expected->cupsMarkerType);
+
+  if (strcmp(header->cupsRenderingIntent, expected->cupsRenderingIntent))
+    printf("    cupsRenderingIntent (%s), expected (%s)\n",
+           header->cupsRenderingIntent,
+           expected->cupsRenderingIntent);
+
+  if (strcmp(header->cupsPageSizeName, expected->cupsPageSizeName))
+    printf("    cupsPageSizeName (%s), expected (%s)\n",
+           header->cupsPageSizeName,
+           expected->cupsPageSizeName);
+}