From dea5d26668844636511f003ec0f5cc797482f7ec Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Thu, 1 Apr 2021 13:57:16 -0400 Subject: [PATCH] Add support for limits in OF-TYPE syntax strings (Issue #153) --- doc/help/man-ipptoolfile.html | 3 +- man/ipptoolfile.5 | 3 +- tools/ipptool.c | 171 +++++++++++++++++++++++++++++++--- 3 files changed, 161 insertions(+), 16 deletions(-) diff --git a/doc/help/man-ipptoolfile.html b/doc/help/man-ipptoolfile.html index 1ab401691b..35ad6f8735 100644 --- a/doc/help/man-ipptoolfile.html +++ b/doc/help/man-ipptoolfile.html @@ -233,8 +233,9 @@ The following predicates are understood following the EXPECT test directi
Makes the EXPECT conditions apply only if the specified variable is not defined.
IN-GROUP tag
Requires the EXPECT attribute to be in the specified group tag. -
OF-TYPE tag[|tag,...] +
OF-TYPE tag[(limits)|tag|...]
Requires the EXPECT attribute to use one of the specified value tag(s). +Most value tags also support the specification of limits in parenthesis, for example "name(42)" would allow nameWith/WithoutLanguage strings up to 42 octets in length, "name(4:MAX)" would allow nameWith/WithoutLanguage strings between 4 and 255 octets in length, and "integer(-273:MAX)" would allow integers between -273 and 2147483647.
REPEAT-LIMIT number

Specifies the maximum number of times to repeat if the REPEAT-MATCH or REPEAT-NO-MATCH predicate is specified. The default value is 1000. diff --git a/man/ipptoolfile.5 b/man/ipptoolfile.5 index 76496b4838..000eaa5323 100644 --- a/man/ipptoolfile.5 +++ b/man/ipptoolfile.5 @@ -299,8 +299,9 @@ Makes the \fBEXPECT\fR conditions apply only if the specified variable is not de \fBIN\-GROUP \fItag\fR Requires the \fBEXPECT\fR attribute to be in the specified group tag. .TP 5 -\fBOF\-TYPE \fItag[|tag,...]\fR +\fBOF\-TYPE \fItag[(limits)|tag|...]\fR Requires the \fBEXPECT\fR attribute to use one of the specified value tag(s). +Most value tags also support the specification of limits in parenthesis, for example "name(42)" would allow nameWith/WithoutLanguage strings up to 42 octets in length, "name(4:MAX)" would allow nameWith/WithoutLanguage strings between 4 and 255 octets in length, and "integer(-273:MAX)" would allow integers between -273 and 2147483647. .TP 5 \fBREPEAT\-LIMIT \fInumber\fR .br diff --git a/tools/ipptool.c b/tools/ipptool.c index 6820fd460c..7de51e6c11 100644 --- a/tools/ipptool.c +++ b/tools/ipptool.c @@ -184,7 +184,7 @@ static void *do_monitor_printer_state(ipptool_test_t *data); static int do_test(_ipp_file_t *f, ipptool_test_t *data); static int do_tests(const char *testfile, ipptool_test_t *data); static int error_cb(_ipp_file_t *f, ipptool_test_t *data, const char *error); -static int expect_matches(ipptool_expect_t *expect, ipp_tag_t value_tag); +static int expect_matches(ipptool_expect_t *expect, ipp_attribute_t *attr); static char *get_filename(const char *testfile, char *dst, const char *src, size_t dstsize); static const char *get_string(ipp_attribute_t *attr, int element, int flags, char *buffer, size_t bufsize); static void init_data(ipptool_test_t *data); @@ -1044,7 +1044,7 @@ do_monitor_printer_state( if ((found && expect->not_expect) || (!found && !(expect->not_expect || expect->optional)) || - (found && !expect_matches(expect, ippGetValueTag(found))) || + (found && !expect_matches(expect, found)) || (expect->in_group && ippGetGroupTag(found) != expect->in_group) || (expect->with_distinct && !with_distinct_values(NULL, found))) { @@ -1737,7 +1737,7 @@ do_test(_ipp_file_t *f, /* I - IPP data file */ if ((found && expect->not_expect) || (!found && !(expect->not_expect || expect->optional)) || - (found && !expect_matches(expect, ippGetValueTag(found))) || + (found && !expect_matches(expect, found)) || (group_found && expect->in_group && ippGetGroupTag(group_found) != expect->in_group) || (expect->with_distinct && !with_distinct_values(NULL, found))) { @@ -1751,7 +1751,7 @@ do_test(_ipp_file_t *f, /* I - IPP data file */ add_stringf(data->errors, "EXPECTED: %s", expect->name); else if (found) { - if (!expect_matches(expect, ippGetValueTag(found))) + if (!expect_matches(expect, found)) add_stringf(data->errors, "EXPECTED: %s OF-TYPE %s (got %s)", expect->name, expect->of_type, ippTagString(ippGetValueTag(found))); @@ -2271,12 +2271,17 @@ error_cb(_ipp_file_t *f, /* I - IPP file data */ static int /* O - 1 if matches, 0 otherwise */ expect_matches( ipptool_expect_t *expect, /* I - Expected attribute */ - ipp_tag_t value_tag) /* I - Value tag for attribute */ + ipp_attribute_t *attr) /* I - Attribute */ { - int match; /* Match? */ - char *of_type, /* Type name to match */ - *next, /* Next name to match */ - sep; /* Separator character */ + int i, /* Looping var */ + count, /* Number of values */ + match; /* Match? */ + char *of_type, /* Type name to match */ + *paren, /* Pointer to opening parenthesis */ + *next, /* Next name to match */ + sep; /* Separator character */ + ipp_tag_t value_tag; /* Syntax/value tag */ + int lower, upper; /* Lower and upper bounds for syntax */ /* @@ -2291,6 +2296,9 @@ expect_matches( * types separated by "," or "|"... */ + value_tag = ippGetValueTag(attr); + count = ippGetCount(attr); + for (of_type = expect->of_type, match = 0; !match && *of_type; of_type = next) { /* @@ -2306,19 +2314,154 @@ expect_matches( * Support some meta-types to make it easier to write the test file. */ + if ((paren = strchr(of_type, '(')) != NULL) + { + char *ptr; // Pointer into syntax string + + *paren = '\0'; + + if (!strncmp(paren + 1, "MIN:", 4)) + { + lower = INT_MIN; + ptr = paren + 5; + } + else if ((ptr = strchr(paren + 1, ':')) != NULL) + { + lower = atoi(paren + 1); + } + else + { + lower = 0; + ptr = paren + 1; + } + + if (!strcmp(ptr, "MAX)")) + upper = INT_MAX; + else + upper = atoi(ptr); + } + else + { + lower = INT_MIN; + upper = INT_MAX; + } + if (!strcmp(of_type, "text")) - match = value_tag == IPP_TAG_TEXTLANG || value_tag == IPP_TAG_TEXT; + { + if (upper == INT_MAX) + upper = 1023; + + if (value_tag == IPP_TAG_TEXTLANG || value_tag == IPP_TAG_TEXT) + { + for (i = 0; i < count; i ++) + { + if (strlen(ippGetString(attr, i, NULL)) > (size_t)upper) + break; + } + + match = (i == count); + } + } else if (!strcmp(of_type, "name")) - match = value_tag == IPP_TAG_NAMELANG || value_tag == IPP_TAG_NAME; + { + if (upper == INT_MAX) + upper = 255; + + if (value_tag == IPP_TAG_NAMELANG || value_tag == IPP_TAG_NAME) + { + for (i = 0; i < count; i ++) + { + if (strlen(ippGetString(attr, i, NULL)) > (size_t)upper) + break; + } + + match = (i == count); + } + } else if (!strcmp(of_type, "collection")) + { match = value_tag == IPP_TAG_BEGIN_COLLECTION; - else - match = value_tag == ippTagValue(of_type); + } + else if (value_tag == ippTagValue(of_type)) + { + switch (value_tag) + { + case IPP_TAG_KEYWORD : + case IPP_TAG_URI : + if (upper == INT_MAX) + { + if (value_tag == IPP_TAG_KEYWORD) + upper = 255; + else + upper = 1023; + } + + for (i = 0; i < count; i ++) + { + if (strlen(ippGetString(attr, i, NULL)) > (size_t)upper) + break; + } + + match = (i == count); + break; + + case IPP_TAG_STRING : + if (upper == INT_MAX) + upper = 1023; + + for (i = 0; i < count; i ++) + { + int datalen; // Length of octetString value + + ippGetOctetString(attr, i, &datalen); + + if (datalen > upper) + break; + } + + match = (i == count); + break; + + case IPP_TAG_INTEGER : + for (i = 0; i < count; i ++) + { + int value = ippGetInteger(attr, i); + // Integer value + + if (value < lower || value > upper) + break; + } + + match = (i == count); + break; + + case IPP_TAG_RANGE : + for (i = 0; i < count; i ++) + { + int vupper, vlower = ippGetRange(attr, i, &vupper); + // Range value + + if (vlower < lower || vlower > upper || vupper < lower || vupper > upper) + break; + } + + match = (i == count); + break; + + default : + // No other constraints, so this is a match + match = 1; + break; + } + } /* - * Restore the separator if we have one... + * Restore the separators if we have them... */ + if (paren) + *paren = '('; + if (sep) *next++ = sep; } -- 2.47.2