]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - test/ipptool.c
Fix ASAN support on Linux, drop suppressions file and just disable leak tests.
[thirdparty/cups.git] / test / ipptool.c
index d6b7904cc2762846bffa646b71106963400f55dd..71a05cba9313018aa4f75b05eefaac5060c9eca1 100644 (file)
  * Include necessary headers...
  */
 
-#define _IPP_PRIVATE_STRUCTURES 0      /* Disable private IPP stuff */
 #include <cups/cups-private.h>
-#include <cups/file-private.h>
 #include <regex.h>
 #include <sys/stat.h>
-#ifdef WIN32
+#ifdef _WIN32
 #  include <windows.h>
 #  ifndef R_OK
 #    define R_OK 0
@@ -25,7 +23,7 @@
 #else
 #  include <signal.h>
 #  include <termios.h>
-#endif /* WIN32 */
+#endif /* _WIN32 */
 #ifndef O_BINARY
 #  define O_BINARY 0
 #endif /* !O_BINARY */
@@ -166,8 +164,9 @@ static int  Cancel = 0;             /* Cancel test? */
  * Local functions...
  */
 
-static void    add_stringf(cups_array_t *a, const char *s, ...) __attribute__ ((__format__ (__printf__, 2, 3)));
+static void    add_stringf(cups_array_t *a, const char *s, ...) _CUPS_FORMAT(2, 3);
 static int      compare_uris(const char *a, const char *b);
+static void    copy_hex_string(char *buffer, unsigned char *data, int datalen, size_t bufsize);
 static int     do_test(_ipp_file_t *f, _ipp_vars_t *vars, _cups_testdata_t *data);
 static int     do_tests(const char *testfile, _ipp_vars_t *vars, _cups_testdata_t *data);
 static int     error_cb(_ipp_file_t *f, _cups_testdata_t *data, const char *error);
@@ -179,19 +178,19 @@ static char       *iso_date(const ipp_uchar_t *date);
 static void    pause_message(const char *message);
 static void    print_attr(cups_file_t *outfile, int output, ipp_attribute_t *attr, ipp_tag_t *group);
 static void    print_csv(_cups_testdata_t *data, ipp_t *ipp, ipp_attribute_t *attr, int num_displayed, char **displayed, size_t *widths);
-static void    print_fatal_error(_cups_testdata_t *data, const char *s, ...) __attribute__ ((__format__ (__printf__, 2, 3)));
+static void    print_fatal_error(_cups_testdata_t *data, const char *s, ...) _CUPS_FORMAT(2, 3);
 static void    print_ippserver_attr(_cups_testdata_t *data, ipp_attribute_t *attr, int indent);
 static void    print_ippserver_string(_cups_testdata_t *data, const char *s, size_t len);
 static void    print_line(_cups_testdata_t *data, ipp_t *ipp, ipp_attribute_t *attr, int num_displayed, char **displayed, size_t *widths);
 static void    print_xml_header(_cups_testdata_t *data);
 static void    print_xml_string(cups_file_t *outfile, const char *element, const char *s);
 static void    print_xml_trailer(_cups_testdata_t *data, int success, const char *message);
-#ifndef WIN32
+#ifndef _WIN32
 static void    sigterm_handler(int sig);
-#endif /* WIN32 */
+#endif /* _WIN32 */
 static int     timeout_cb(http_t *http, void *user_data);
 static int     token_cb(_ipp_file_t *f, _ipp_vars_t *vars, _cups_testdata_t *data, const char *token);
-static void    usage(void) __attribute__((noreturn));
+static void    usage(void) _CUPS_NORETURN;
 static const char *with_flags_string(int flags);
 static int      with_value(_cups_testdata_t *data, cups_array_t *errors, char *value, int flags, ipp_attribute_t *attr, char *matchbuf, size_t matchlen);
 static int      with_value_from(cups_array_t *errors, ipp_attribute_t *fromattr, ipp_attribute_t *attr, char *matchbuf, size_t matchlen);
@@ -222,14 +221,14 @@ main(int  argc,                           /* I - Number of command-line args */
                                        /* Global data */
 
 
-#ifndef WIN32
+#ifndef _WIN32
  /*
   * Catch SIGINT and SIGTERM...
   */
 
   signal(SIGINT, sigterm_handler);
   signal(SIGTERM, sigterm_handler);
-#endif /* !WIN32 */
+#endif /* !_WIN32 */
 
  /*
   * Initialize the locale and variables...
@@ -239,7 +238,7 @@ main(int  argc,                             /* I - Number of command-line args */
 
   init_data(&data);
 
-  _ippVarsInit(&vars);
+  _ippVarsInit(&vars, NULL, (_ipp_ferror_cb_t)error_cb, (_ipp_ftoken_cb_t)token_cb);
 
  /*
   * We need at least:
@@ -464,9 +463,9 @@ main(int  argc,                             /* I - Number of command-line args */
 
                snprintf(filename, sizeof(filename), "%s.gz", argv[i]);
                 if (access(filename, 0) && filename[0] != '/'
-#ifdef WIN32
+#ifdef _WIN32
                     && (!isalpha(filename[0] & 255) || filename[1] != ':')
-#endif /* WIN32 */
+#endif /* _WIN32 */
                     )
                {
                  snprintf(filename, sizeof(filename), "%s/ipptool/%s", cg->cups_datadir, argv[i]);
@@ -651,9 +650,9 @@ main(int  argc,                             /* I - Number of command-line args */
       }
 
       if (access(argv[i], 0) && argv[i][0] != '/'
-#ifdef WIN32
+#ifdef _WIN32
           && (!isalpha(argv[i][0] & 255) || argv[i][1] != ':')
-#endif /* WIN32 */
+#endif /* _WIN32 */
           )
       {
         snprintf(testname, sizeof(testname), "%s/ipptool/%s", cg->cups_datadir, argv[i]);
@@ -817,6 +816,69 @@ compare_uris(const char *a,             /* I - First URI */
 }
 
 
+/*
+ * 'copy_hex_string()' - Copy an octetString to a C string and encode as hex if
+ *                       needed.
+ */
+
+static void
+copy_hex_string(char          *buffer, /* I - String buffer */
+               unsigned char *data,    /* I - octetString data */
+               int           datalen,  /* I - octetString length */
+               size_t        bufsize)  /* I - Size of string buffer */
+{
+  char         *bufptr,                /* Pointer into string buffer */
+               *bufend = buffer + bufsize - 2;
+                                       /* End of string buffer */
+  unsigned char        *dataptr,               /* Pointer into octetString data */
+               *dataend = data + datalen;
+                                       /* End of octetString data */
+  static const char *hexdigits = "0123456789ABCDEF";
+                                       /* Hex digits */
+
+
+ /*
+  * First see if there are any non-ASCII bytes in the octetString...
+  */
+
+  for (dataptr = data; dataptr < dataend; dataptr ++)
+    if (*dataptr < 0x20 || *dataptr >= 0x7f)
+      break;
+
+  if (*dataptr)
+  {
+   /*
+    * Yes, encode as hex...
+    */
+
+    *buffer = '<';
+
+    for (bufptr = buffer + 1, dataptr = data; bufptr < bufend && dataptr < dataend; dataptr ++)
+    {
+      *bufptr++ = hexdigits[*dataptr >> 4];
+      *bufptr++ = hexdigits[*dataptr & 15];
+    }
+
+    if (bufptr < bufend)
+      *bufptr++ = '>';
+
+    *bufptr = '\0';
+  }
+  else
+  {
+   /*
+    * No, copy as a string...
+    */
+
+    if ((size_t)datalen > bufsize)
+      datalen = (int)bufsize - 1;
+
+    memcpy(buffer, data, (size_t)datalen);
+    buffer[datalen] = '\0';
+  }
+}
+
+
 /*
  * 'do_test()' - Do a single test from the test file.
  */
@@ -1031,11 +1093,11 @@ do_test(_ipp_file_t      *f,            /* I - IPP data file */
        }
 
        if (!Cancel && status == HTTP_STATUS_ERROR && httpError(data->http) != EINVAL &&
-#ifdef WIN32
+#ifdef _WIN32
            httpError(data->http) != WSAETIMEDOUT)
 #else
            httpError(data->http) != ETIMEDOUT)
-#endif /* WIN32 */
+#endif /* _WIN32 */
        {
          if (httpReconnect2(data->http, 30000, NULL))
            data->prev_pass = 0;
@@ -1058,11 +1120,11 @@ do_test(_ipp_file_t      *f,            /* I - IPP data file */
     }
 
     if (!Cancel && status == HTTP_STATUS_ERROR && httpError(data->http) != EINVAL &&
-#ifdef WIN32
+#ifdef _WIN32
        httpError(data->http) != WSAETIMEDOUT)
 #else
        httpError(data->http) != ETIMEDOUT)
-#endif /* WIN32 */
+#endif /* _WIN32 */
     {
       if (httpReconnect2(data->http, 30000, NULL))
        data->prev_pass = 0;
@@ -1270,7 +1332,7 @@ do_test(_ipp_file_t      *f,              /* I - IPP data file */
 
        if (ippGetName(attrptr))
        {
-         if (cupsArrayFind(a, (void *)ippGetName(attrptr)))
+         if (cupsArrayFind(a, (void *)ippGetName(attrptr)) && data->output < _CUPS_OUTPUT_LIST)
            add_stringf(data->errors, "Duplicate \"%s\" attribute in %s group",
                        ippGetName(attrptr), ippTagString(group));
 
@@ -1343,6 +1405,8 @@ do_test(_ipp_file_t      *f,              /* I - IPP data file */
 
       for (i = data->num_expects, expect = data->expects; i > 0; i --, expect ++)
       {
+       ipp_attribute_t *group_found;   /* Found parent attribute for group tests */
+
        if (expect->if_defined && !_ippVarsGet(vars, expect->if_defined))
          continue;
 
@@ -1350,15 +1414,33 @@ do_test(_ipp_file_t      *f,            /* I - IPP data file */
            _ippVarsGet(vars, expect->if_not_defined))
          continue;
 
-       found = ippFindAttribute(response, expect->name, IPP_TAG_ZERO);
+       if ((found = ippFindAttribute(response, expect->name, IPP_TAG_ZERO)) != NULL && expect->in_group && expect->in_group != ippGetGroupTag(found))
+       {
+         while ((found = ippFindNextAttribute(response, expect->name, IPP_TAG_ZERO)) != NULL)
+           if (expect->in_group == ippGetGroupTag(found))
+             break;
+       }
 
        do
        {
+         group_found = found;
+
+          if (expect->in_group && strchr(expect->name, '/'))
+          {
+            char       group_name[256],/* Parent attribute name */
+                       *group_ptr;     /* Pointer into parent attribute name */
+
+           strlcpy(group_name, expect->name, sizeof(group_name));
+           if ((group_ptr = strchr(group_name, '/')) != NULL)
+             *group_ptr = '\0';
+
+           group_found = ippFindAttribute(response, group_name, IPP_TAG_ZERO);
+         }
+
          if ((found && expect->not_expect) ||
              (!found && !(expect->not_expect || expect->optional)) ||
              (found && !expect_matches(expect, ippGetValueTag(found))) ||
-             (found && expect->in_group &&
-              ippGetGroupTag(found) != expect->in_group))
+             (group_found && expect->in_group && ippGetGroupTag(group_found) != expect->in_group))
          {
            if (expect->define_no_match)
              _ippVarsSet(vars, expect->define_no_match, "1");
@@ -1375,10 +1457,10 @@ do_test(_ipp_file_t      *f,            /* I - IPP data file */
                              expect->name, expect->of_type,
                              ippTagString(ippGetValueTag(found)));
 
-               if (expect->in_group && ippGetGroupTag(found) != expect->in_group)
+               if (expect->in_group && ippGetGroupTag(group_found) != expect->in_group)
                  add_stringf(data->errors, "EXPECTED: %s IN-GROUP %s (got %s).",
                              expect->name, ippTagString(expect->in_group),
-                             ippTagString(ippGetGroupTag(found)));
+                             ippTagString(ippGetGroupTag(group_found)));
              }
            }
 
@@ -1819,7 +1901,7 @@ do_tests(const char       *testfile,      /* I - Test file to use */
   * Run tests...
   */
 
-  _ippFileParse(vars, testfile, (_ipp_ftoken_cb_t)token_cb, (_ipp_ferror_cb_t)error_cb, (void *)data);
+  _ippFileParse(vars, testfile, (void *)data);
 
  /*
   * Close connection and return...
@@ -1939,9 +2021,9 @@ get_filename(const char *testfile,        /* I - Current test file */
       *dstptr = '\0';
   }
   else if (!access(src, R_OK) || *src == '/'
-#ifdef WIN32
+#ifdef _WIN32
            || (isalpha(*src & 255) && src[1] == ':')
-#endif /* WIN32 */
+#endif /* _WIN32 */
            )
   {
    /*
@@ -2100,7 +2182,7 @@ iso_date(const ipp_uchar_t *date) /* I - IPP (RFC 1903) date/time value */
 static void
 pause_message(const char *message)     /* I - Message */
 {
-#ifdef WIN32
+#ifdef _WIN32
   HANDLE       tty;                    /* Console handle */
   DWORD                mode;                   /* Console mode */
   char         key;                    /* Key press */
@@ -2148,7 +2230,7 @@ pause_message(const char *message)        /* I - Message */
     close(tty);
     return;
   }
-#endif /* WIN32 */
+#endif /* _WIN32 */
 
  /*
   * Display the prompt...
@@ -2156,7 +2238,7 @@ pause_message(const char *message)        /* I - Message */
 
   cupsFilePrintf(cupsFileStdout(), "%s\n---- PRESS ANY KEY ----", message);
 
-#ifdef WIN32
+#ifdef _WIN32
  /*
   * Read a key...
   */
@@ -2182,7 +2264,7 @@ pause_message(const char *message)        /* I - Message */
 
   tcsetattr(tty, TCSAFLUSH, &original);
   close(tty);
-#endif /* WIN32 */
+#endif /* _WIN32 */
 
  /*
   * Erase the "press any key" prompt...
@@ -2579,7 +2661,7 @@ print_ippserver_attr(
        break;
 
     default :
-       cupsFilePuts(data->outfile, " \"\"");
+        /* Out-of-band value */
        break;
   }
 
@@ -2845,7 +2927,7 @@ print_xml_trailer(
 }
 
 
-#ifndef WIN32
+#ifndef _WIN32
 /*
  * 'sigterm_handler()' - Handle SIGINT and SIGTERM.
  */
@@ -2860,7 +2942,7 @@ sigterm_handler(int sig)          /* I - Signal number (unused) */
   signal(SIGINT, SIG_DFL);
   signal(SIGTERM, SIG_DFL);
 }
-#endif /* !WIN32 */
+#endif /* !_WIN32 */
 
 
 /*
@@ -3704,6 +3786,7 @@ token_cb(_ipp_file_t      *f,             /* I - IPP file data */
             !_cups_strcasecmp(token, "WITH-VALUE"))
     {
       off_t    lastpos;                /* Last file position */
+      int      lastline;               /* Last line number */
 
       if (data->last_expect)
       {
@@ -3733,8 +3816,9 @@ token_cb(_ipp_file_t      *f,             /* I - IPP file data */
 
       for (;;)
       {
-        lastpos = cupsFileTell(f->fp);
-        ptr     += strlen(ptr);
+        lastpos  = cupsFileTell(f->fp);
+        lastline = f->linenum;
+        ptr      += strlen(ptr);
 
        if (!_ippFileReadToken(f, ptr, (sizeof(temp) - (size_t)(ptr - temp))))
          break;
@@ -3757,6 +3841,7 @@ token_cb(_ipp_file_t      *f,             /* I - IPP file data */
           */
 
           cupsFileSeek(f->fp, lastpos);
+          f->linenum = lastline;
           *ptr = '\0';
           break;
        }
@@ -4687,6 +4772,99 @@ with_value(_cups_testdata_t *data,       /* I - Test data */
         }
        break;
 
+    case IPP_TAG_STRING :
+        {
+          unsigned char        withdata[1023], /* WITH-VALUE data */
+                       *adata;         /* Pointer to octetString data */
+         int           withlen,        /* Length of WITH-VALUE data */
+                       adatalen;       /* Length of octetString */
+
+          if (*value == '<')
+          {
+           /*
+            * Grab hex-encoded value...
+            */
+
+            if ((withlen = (int)strlen(value)) & 1 || withlen > (int)(2 * (sizeof(withdata) + 1)))
+            {
+             print_fatal_error(data, "Bad WITH-VALUE hex value.");
+              return (0);
+           }
+
+           withlen = withlen / 2 - 1;
+
+            for (valptr = value + 1, adata = withdata; *valptr; valptr += 2)
+            {
+              int ch;                  /* Current character/byte */
+
+             if (isdigit(valptr[0]))
+               ch = (valptr[0] - '0') << 4;
+             else if (isalpha(valptr[0]))
+               ch = (tolower(valptr[0]) - 'a' + 10) << 4;
+             else
+               break;
+
+             if (isdigit(valptr[1]))
+               ch |= valptr[1] - '0';
+             else if (isalpha(valptr[1]))
+               ch |= tolower(valptr[1]) - 'a' + 10;
+             else
+               break;
+
+             *adata++ = (unsigned char)ch;
+           }
+
+           if (*valptr)
+           {
+             print_fatal_error(data, "Bad WITH-VALUE hex value.");
+              return (0);
+           }
+          }
+          else
+          {
+           /*
+            * Copy literal string value...
+            */
+
+            withlen = (int)strlen(value);
+
+            memcpy(withdata, value, (size_t)withlen);
+         }
+
+         for (i = 0; i < count; i ++)
+         {
+           adata = ippGetOctetString(attr, i, &adatalen);
+
+           if (withlen == adatalen && !memcmp(withdata, adata, (size_t)withlen))
+           {
+             if (!matchbuf[0])
+               copy_hex_string(matchbuf, adata, adatalen, matchlen);
+
+             if (!(flags & _CUPS_WITH_ALL))
+             {
+               match = 1;
+               break;
+             }
+           }
+           else if (flags & _CUPS_WITH_ALL)
+           {
+             match = 0;
+             break;
+           }
+         }
+
+         if (!match && errors)
+         {
+           for (i = 0; i < count; i ++)
+           {
+             adata = ippGetOctetString(attr, i, &adatalen);
+             copy_hex_string(temp, adata, adatalen, sizeof(temp));
+             add_stringf(data->errors, "GOT: %s=\"%s\"", name, temp);
+           }
+         }
+        }
+        break;
+
     default :
         break;
   }