]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Fix printer-strings-uri support in _ppdCreateFromIPP.
authorMichael R Sweet <msweet@msweet.org>
Fri, 12 Apr 2024 23:26:24 +0000 (19:26 -0400)
committerMichael R Sweet <msweet@msweet.org>
Fri, 12 Apr 2024 23:26:24 +0000 (19:26 -0400)
Add PPD cache benchmarking program.

cups/Makefile
cups/cachebench.c [new file with mode: 0644]
cups/ppd-cache.c

index c79b93cb1c6bf81401c593a10d3ce343ecdc4485..2807053e0ecffe34a065635d5828746a063137c6 100644 (file)
@@ -90,6 +90,7 @@ IMAGEOBJS     = \
                raster-stubs.o
 
 TESTOBJS       = \
+               cachebench.o \
                fuzzipp.o \
                rasterbench.o \
                testadmin.o \
@@ -186,6 +187,7 @@ LIBTARGETS =        \
                libcupsimage.a
 
 UNITTARGETS =  \
+               cachebench \
                rasterbench \
                testadmin \
                testarray \
@@ -528,6 +530,16 @@ libcupsimage.a:    $(IMAGEOBJS)
        $(RANLIB) $@
 
 
+#
+# cachebench (dependency on static CUPS library is intentional)
+#
+
+cachebench:    cachebench.o $(LIBCUPSSTATIC)
+       echo Linking $@...
+       $(LD_CC) $(ALL_LDFLAGS) -o $@ cachebench.o $(LINKCUPSSTATIC)
+       $(CODE_SIGN) -s "$(CODE_SIGN_IDENTITY)" $@
+
+
 #
 # fuzzipp (dependency on static CUPS library is intentional)
 #
diff --git a/cups/cachebench.c b/cups/cachebench.c
new file mode 100644 (file)
index 0000000..410894d
--- /dev/null
@@ -0,0 +1,440 @@
+//
+// PPD cache benchmarking program for CUPS.
+//
+// Usage:
+//
+//   ./cachebench PRINTER-URI
+//
+// Copyright © 2024 by OpenPrinting.
+//
+// Licensed under Apache License v2.0.  See the file "LICENSE" for more
+// information.
+//
+
+#include "ppd-private.h"
+#include "file-private.h"
+#include <sys/time.h>
+
+
+//
+// Local functions...
+//
+
+static ipp_t   *create_attrs(_ppd_cache_t *pc);
+static ipp_t   *create_media_col(pwg_size_t *pwg, const char *source, const char *type);
+static ipp_t   *create_media_size(int min_width, int max_width, int min_length, int max_length);
+static double  get_elapsed(struct timeval *starttime, struct timeval *endtime);
+
+
+//
+// 'main()' - Main entry.
+//
+
+int                                    // O - Exit status
+main(int  argc,                                // I - Number of command-line args
+     char *argv[])                     // I - Command-line arguments
+{
+  cups_dest_t  *dest;                  // Destination
+  http_t       *http;                  // Connection to printer
+  char         resource[1024];         // Resource path for printer
+  ipp_t                *request,               // IPP request
+               *response;              // IPP response
+  char         ppd_file[1024],         // Generated PPD file
+               cache_file[1024];       // Generated PPD cache
+  ppd_file_t   *ppd;                   // PPD (loaded)
+  _ppd_cache_t *pc;                    // PPD cache
+  ipp_t                *pc_attrs;              // PPD cache attributes
+  int          i;                      // Looping var
+  struct timeval starttime,            // Start time
+               endtime;                // End time
+  double       ppd_secs,               // Average time to load PPD file
+               cache_secs;             // Average time to load cache file
+  static const char * const requested_attrs[] =
+  {                                    // "requested-attributes"
+    "all",
+    "media-col-database"
+  };
+
+
+  // Get the printer URI for the test...
+  if (argc != 2 || (strncmp(argv[1], "ipp://", 6) && strncmp(argv[1], "ipps://", 7)))
+  {
+    fputs("Usage: ./cachebench PRINTER-URI\n", stderr);
+    return (1);
+  }
+
+  dest = cupsGetDestWithURI("bench", argv[1]);
+
+  printf("Connecting to '%s'...\n", argv[1]);
+
+  if ((http = cupsConnectDest(dest, CUPS_DEST_FLAGS_DEVICE, /*msec*/30000, /*cancel*/NULL, resource, sizeof(resource), /*cb*/NULL, /*user_data*/NULL)) == NULL)
+  {
+    fprintf(stderr, "cachebench: Unable to connect to '%s': %s\n", argv[1], cupsGetErrorString());
+    return (1);
+  }
+
+  // Get printer attributes...
+  printf("Geting printer attributes for '%s'...\n", argv[1]);
+
+  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", 2, NULL, requested_attrs);
+
+  response = cupsDoRequest(http, request, resource);
+
+  if (cupsGetError() >= IPP_STATUS_ERROR_BAD_REQUEST)
+  {
+    fprintf(stderr, "cachebench: Unable to get attributes for '%s': %s\n", argv[1], cupsGetErrorString());
+    return (1);
+  }
+
+  // Generate a PPD file...
+  printf("Generating PPD file for '%s'...\n", argv[1]);
+
+  if (!_ppdCreateFromIPP(ppd_file, sizeof(ppd_file), response))
+  {
+    fprintf(stderr, "cachebench: Unable to create PPD file for '%s': %s\n", argv[1], cupsGetErrorString());
+    return (1);
+  }
+
+  printf("PPD file: %s\n", ppd_file);
+
+  ippDelete(response);
+
+  snprintf(cache_file, sizeof(cache_file), "%s.cache", ppd_file);
+
+  // Try doing the PPD and cache stuff multiple times...
+  for (i = 0, ppd_secs = cache_secs = 0.0; i < 1000; i ++)
+  {
+    // Generate the PPD cache file
+    gettimeofday(&starttime, NULL);
+
+    if ((ppd = ppdOpenFile(ppd_file)) == NULL)
+    {
+      int      linenum;                // Line number of error
+      ppd_status_t status;             // PPD status
+
+      status = ppdLastError(&linenum);
+      fprintf(stderr, "cachebench: Unable to open PPD file for '%s': %s on line %d.\n", argv[1], ppdErrorString(status), linenum);
+      return (1);
+    }
+
+    pc       = _ppdCacheCreateWithPPD(ppd);
+    pc_attrs = create_attrs(pc);
+
+    gettimeofday(&endtime, NULL);
+
+    ppd_secs += get_elapsed(&starttime, &endtime);
+
+    // Save it and free memory...
+    _ppdCacheWriteFile(pc, cache_file, pc_attrs);
+
+    _ppdCacheDestroy(pc);
+    ppdClose(ppd);
+    ippDelete(pc_attrs);
+
+    // Load the cache file
+    gettimeofday(&starttime, NULL);
+    pc = _ppdCacheCreateWithFile(cache_file, &pc_attrs);
+    gettimeofday(&endtime, NULL);
+
+    cache_secs += get_elapsed(&starttime, &endtime);
+
+    _ppdCacheDestroy(pc);
+    ippDelete(pc_attrs);
+  }
+
+  printf("Total raw PPD time: %.3fsecs\n", ppd_secs);
+  printf("Total cached PPD time: %.3fsecs\n", cache_secs);
+
+//  unlink(ppd_file);
+  unlink(cache_file);
+
+  return (0);
+}
+
+
+//
+// 'create_attrs()' - Create printer attributes from a PPD cache.
+//
+
+static ipp_t *                         // O - Printer attributes
+create_attrs(_ppd_cache_t *pc)         // I - PPD cache
+{
+  int          i, j;                   // Looping vars
+  ipp_t                *attrs;                 // Printer attributes
+//  ipp_attribute_t *attr;             // Current attribute
+  pwg_size_t   *size;                  // Current media size
+  int          num_values;             // Number of values
+  ipp_t                *cvalues[256];          // Collection values
+  int          ivalues[256];           // Integer values
+  const char   *svalues[256];          // String values
+  static const char * const media_col_supported[] =
+  {                                    // "media-col-supported" values
+    "media-bottom-margin",
+    "media-left-margin",
+    "media-right-margin",
+    "media-size",
+    "media-source",
+    "media-top-margin",
+    "media-type"
+  };
+  static const char * const sides_supported[] =
+  {                                    // "sides-supported" values
+    "one-sided",
+    "two-sided-long-edge",
+    "two-sided-short-edge"
+  };
+
+
+  attrs = ippNew();
+
+  // media-supported
+  for (i = 0, size = pc->sizes; i < pc->num_sizes && i < (int)(sizeof(svalues) / sizeof(svalues[0])); i ++)
+    svalues[i] = size->map.pwg;
+  num_values = i;
+
+  if (pc->custom_max_keyword && num_values < (int)(sizeof(svalues) / sizeof(svalues[0])))
+    svalues[num_values ++] = pc->custom_max_keyword;
+
+  if (pc->custom_min_keyword && num_values < (int)(sizeof(svalues) / sizeof(svalues[0])))
+    svalues[num_values ++] = pc->custom_min_keyword;
+
+  ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-supported", num_values, NULL, svalues);
+
+  // media-bottom-margin-supported
+  for (i = 0, size = pc->sizes, num_values = 0; i < pc->num_sizes; i ++)
+  {
+    for (j = 0; j < num_values; j ++)
+    {
+      if (size->bottom == ivalues[j])
+      {
+        break;
+      }
+      else if (size->bottom < ivalues[j])
+      {
+        memmove(ivalues + j + 1, ivalues + j, (size_t)(num_values - j) * sizeof(int));
+        ivalues[j] = size->bottom;
+        break;
+      }
+    }
+
+    if (j >= num_values && num_values < (int)(sizeof(ivalues) / sizeof(ivalues[0])))
+      ivalues[num_values ++] = size->bottom;
+  }
+
+  ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-bottom-margin-supported", num_values, ivalues);
+
+  // media-col-database
+  for (i = 0, size = pc->sizes; i < pc->num_sizes && i < (int)(sizeof(cvalues) / sizeof(cvalues[0])); i ++)
+    cvalues[i] = create_media_col(size, NULL, NULL);
+
+  num_values = i;
+
+  if ((pc->custom_max_width || pc->custom_max_length) && num_values < (int)(sizeof(cvalues) / sizeof(cvalues[0])))
+  {
+    ipp_t *media_col,                  // "media-col" value
+          *media_size;                 // "media-size" value
+
+    media_col = ippNew();
+    media_size = create_media_size(pc->custom_min_width, pc->custom_max_width, pc->custom_min_length, pc->custom_max_length);
+    ippAddCollection(media_col, IPP_TAG_ZERO, "media-size", media_size);
+    ippDelete(media_size);
+
+    cvalues[num_values ++] = media_col;
+  }
+
+  ippAddCollections(attrs, IPP_TAG_PRINTER, "media-col-database", num_values, (const ipp_t **)cvalues);
+  for (i = 0; i < num_values; i ++)
+    ippDelete(cvalues[i]);
+
+  // media-col-supported
+  ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-col-supported", (int)(sizeof(media_col_supported) / sizeof(media_col_supported[0])), NULL, media_col_supported);
+
+  // media-left-margin-supported
+  for (i = 0, size = pc->sizes, num_values = 0; i < pc->num_sizes; i ++)
+  {
+    for (j = 0; j < num_values; j ++)
+    {
+      if (size->left == ivalues[j])
+      {
+        break;
+      }
+      else if (size->left < ivalues[j])
+      {
+        memmove(ivalues + j + 1, ivalues + j, (size_t)(num_values - j) * sizeof(int));
+        ivalues[j] = size->left;
+        break;
+      }
+    }
+
+    if (j >= num_values && num_values < (int)(sizeof(ivalues) / sizeof(ivalues[0])))
+      ivalues[num_values ++] = size->left;
+  }
+
+  ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-left-margin-supported", num_values, ivalues);
+
+  // media-right-margin-supported
+  for (i = 0, size = pc->sizes, num_values = 0; i < pc->num_sizes; i ++)
+  {
+    for (j = 0; j < num_values; j ++)
+    {
+      if (size->right == ivalues[j])
+      {
+        break;
+      }
+      else if (size->right < ivalues[j])
+      {
+        memmove(ivalues + j + 1, ivalues + j, (size_t)(num_values - j) * sizeof(int));
+        ivalues[j] = size->right;
+        break;
+      }
+    }
+
+    if (j >= num_values && num_values < (int)(sizeof(ivalues) / sizeof(ivalues[0])))
+      ivalues[num_values ++] = size->right;
+  }
+
+  ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-right-margin-supported", num_values, ivalues);
+
+  // media-size-supported
+  for (i = 0, size = pc->sizes; i < pc->num_sizes && i < (int)(sizeof(cvalues) / sizeof(cvalues[0])); i ++)
+    cvalues[i] = create_media_size(size->width, 0, size->length, 0);
+
+  num_values = i;
+
+  if ((pc->custom_max_width || pc->custom_max_length) && num_values < (int)(sizeof(cvalues) / sizeof(cvalues[0])))
+    cvalues[num_values ++] = create_media_size(pc->custom_min_width, pc->custom_max_width, pc->custom_min_length, pc->custom_max_length);
+
+  ippAddCollections(attrs, IPP_TAG_PRINTER, "media-size-supported", num_values, (const ipp_t **)cvalues);
+  for (i = 0; i < num_values; i ++)
+    ippDelete(cvalues[i]);
+
+  // media-source-supported
+  for (i = 0; i < pc->num_sources && i < (int)(sizeof(svalues) / sizeof(svalues[0])); i ++)
+    svalues[i] = pc->sources[i].pwg;
+  num_values = i;
+
+  ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-source-supported", num_values, NULL, svalues);
+
+  // media-top-margin-supported
+  for (i = 0, size = pc->sizes, num_values = 0; i < pc->num_sizes; i ++)
+  {
+    for (j = 0; j < num_values; j ++)
+    {
+      if (size->top == ivalues[j])
+      {
+        break;
+      }
+      else if (size->top < ivalues[j])
+      {
+        memmove(ivalues + j + 1, ivalues + j, (size_t)(num_values - j) * sizeof(int));
+        ivalues[j] = size->top;
+        break;
+      }
+    }
+
+    if (j >= num_values && num_values < (int)(sizeof(ivalues) / sizeof(ivalues[0])))
+      ivalues[num_values ++] = size->top;
+  }
+
+  ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-top-margin-supported", num_values, ivalues);
+
+  // media-type-supported
+  for (i = 0; i < pc->num_types && i < (int)(sizeof(svalues) / sizeof(svalues[0])); i ++)
+    svalues[i] = pc->types[i].pwg;
+  num_values = i;
+
+  ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-type-supported", num_values, NULL, svalues);
+
+  // output-bin-supported
+  for (i = 0; i < pc->num_bins && i < (int)(sizeof(svalues) / sizeof(svalues[0])); i ++)
+    svalues[i] = pc->bins[i].pwg;
+  num_values = i;
+
+  if (num_values > 0)
+    ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "output-bin-supported", num_values, NULL, svalues);
+
+  // sides-supported
+  if (pc->sides_2sided_long)
+    ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "sides-supported", 3, NULL, sides_supported);
+  else
+    ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "sides-supported", NULL, sides_supported[0]);
+
+  return (attrs);
+}
+
+
+//
+// 'create_media_col()' - Create a media-col collection.
+//
+
+static ipp_t *                         // O - "media-col" collection
+create_media_col(pwg_size_t *pwg,      // I - PWG media size/margins
+                 const char *source,   // I - "media-source" value or `NULL` for none
+                 const char *type)     // I - "media-type" value or `NULL` for none
+{
+  ipp_t        *media_col,                     // "media-col" collection value
+       *media_size;                    // "media-size" sub-collection value
+
+
+  media_col = ippNew();
+
+  media_size = create_media_size(pwg->width, 0, pwg->length, 0);
+  ippAddCollection(media_col, IPP_TAG_ZERO, "media-size", media_size);
+  ippDelete(media_size);
+
+  if (source)
+    ippAddString(media_col, IPP_TAG_ZERO, IPP_TAG_KEYWORD, "media-source", NULL, source);
+
+  if (type)
+    ippAddString(media_col, IPP_TAG_ZERO, IPP_TAG_KEYWORD, "media-type", NULL, type);
+
+  ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, "media-bottom-margin", pwg->bottom);
+  ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, "media-left-margin", pwg->left);
+  ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, "media-right-margin", pwg->right);
+  ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, "media-top-margin", pwg->top);
+
+  return (media_col);
+}
+
+
+//
+// 'create_media_size()' - Create a media-size collection.
+//
+
+static ipp_t *                         // O - "media-size" collection
+create_media_size(int min_width,       // I - Minimum width
+                  int max_width,       // I - Maximum width
+                  int min_length,      // I - Minimum length
+                  int max_length)      // I - Maximum length
+{
+  ipp_t        *media_size;                    // "media-size" sub-collection value
+
+
+  media_size = ippNew();
+
+  if (max_width)
+    ippAddRange(media_size, IPP_TAG_ZERO, "x-dimension", min_width, max_width);
+  else
+    ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "x-dimension", min_width);
+
+  if (max_length)
+    ippAddRange(media_size, IPP_TAG_ZERO, "y-dimension", min_length, max_length);
+  else
+    ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "y-dimension", min_length);
+
+  return (media_size);
+}
+
+
+//
+// 'get_elapsed()' - Get the elapsed time in seconds.
+//
+
+static double                          // O - Elapsed time
+get_elapsed(struct timeval *starttime, // I - Start time
+            struct timeval *endtime)   // I - End time
+{
+  return ((double)(endtime->tv_sec - starttime->tv_sec) + 0.000001 * (double)(endtime->tv_usec - starttime->tv_usec));
+}
index ae88076cfb78bbfed78b027f6b86fcef50f385ad..617e6c7f1144b2ac7106c79ccd85ed00fbed59ec 100644 (file)
@@ -3141,7 +3141,6 @@ _ppdCreateFromIPP(char   *buffer, /* I - Filename buffer */
 {
   const char           *printer_uri;   /* Printer URI */
   http_t               *http = NULL;   /* HTTP connection */
-  cups_array_t         *languages;     /* List of languages */
   cups_lang_t          *lang,          /* Current language information */
                        *langs = NULL;  /* Language (strings) files */
   const char           *prefix;        /* Prefix string */
@@ -3222,12 +3221,6 @@ _ppdCreateFromIPP(char   *buffer,        /* I - Filename buffer */
     return (NULL);
   }
 
- /*
-  * Figure out the languages to load/generate...
-  */
-
-  languages = cups_get_languages();
-
  /*
   * Standard stuff for PPD file...
   */
@@ -3284,7 +3277,7 @@ _ppdCreateFromIPP(char   *buffer, /* I - Filename buffer */
     {
       keyword = ippGetString(lang_supp, i, NULL);
 
-      if (cupsArrayFind(languages, (void *)keyword) && (lang = cups_get_strings(&http, printer_uri, keyword)) != NULL)
+      if ((lang = cups_get_strings(&http, printer_uri, keyword)) != NULL)
       {
        /*
         * Add language...
@@ -3294,11 +3287,11 @@ _ppdCreateFromIPP(char   *buffer,       /* I - Filename buffer */
         langs      = lang;
 
         cupsFilePrintf(fp, "%s%s", prefix, keyword);
-        prefix = ",";
+        prefix = " ";
       }
     }
 
-    if (!strcmp(prefix, ","))
+    if (!strcmp(prefix, " "))
       cupsFilePuts(fp, "\"\n");
   }
 
@@ -3336,11 +3329,11 @@ _ppdCreateFromIPP(char   *buffer,       /* I - Filename buffer */
       if (strcmp(keyword, "attributes-charset") && strcmp(keyword, "attributes-natural-language") && strcmp(keyword, "printer-uri"))
       {
         cupsFilePrintf(fp, "%s%s", prefix, keyword);
-        prefix = ",";
+        prefix = " ";
       }
     }
 
-    if (!strcmp(prefix, ","))
+    if (!strcmp(prefix, " "))
       cupsFilePuts(fp, "\"\n");
   }
 
@@ -3353,11 +3346,11 @@ _ppdCreateFromIPP(char   *buffer,       /* I - Filename buffer */
       if (strcmp(keyword, "attributes-charset") && strcmp(keyword, "attributes-natural-language") && strcmp(keyword, "printer-uri"))
       {
         cupsFilePrintf(fp, "%s%s", prefix, keyword);
-        prefix = ",";
+        prefix = " ";
       }
     }
 
-    if (!strcmp(prefix, ","))
+    if (!strcmp(prefix, " "))
       cupsFilePuts(fp, "\"\n");
   }
 
@@ -5300,6 +5293,7 @@ cups_get_strings(
                *response = NULL;       /* IPP response */
   const char   *strings_uri;           /* "printer-strings-uri" value */
   char         strings_file[1024] = "";/* Strings filename */
+  static int   request_id = 1000;      // Request ID
 
 
  /*
@@ -5315,6 +5309,7 @@ cups_get_strings(
 
   request = ippNew();
   ippSetOperation(request, IPP_OP_GET_PRINTER_ATTRIBUTES);
+  ippSetRequestId(request, request_id ++);
   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, "attributes-charset", /*language*/NULL, "utf-8");
   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "attributes-natural-language", /*language*/NULL, language);
   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", /*language*/NULL, printer_uri);
@@ -5343,7 +5338,35 @@ cups_get_strings(
 
     cupsCopyString(lang->language, language, sizeof(lang->language));
     lang->strings = _cupsMessageLoad(strings_file, _CUPS_MESSAGE_STRINGS);
+    unlink(strings_file);
+  }
+#if 0
+  else
+  {
+    ipp_attribute_t *attr;
+    ipp_tag_t group_tag = IPP_TAG_ZERO, value_tag;
+    const char *name;
+    char value[2048];
+
+    puts("No printer-strings-uri in response.");
+    printf("Get-Printer-Attributes: %s\n", ippErrorString(ippGetStatusCode(response)));
+    for (attr = ippGetFirstAttribute(response); attr; attr = ippGetNextAttribute(response))
+    {
+      if (ippGetGroupTag(attr) != group_tag)
+      {
+        group_tag = ippGetGroupTag(attr);
+        puts(ippTagString(group_tag));
+      }
+
+      name      = ippGetName(attr);
+      value_tag = ippGetValueTag(attr);
+
+      ippAttributeString(attr, value, sizeof(value));
+
+      printf("  %s %s = %s\n", name, ippTagString(value_tag), value);
+    }
   }
+#endif // 0
 
   done: