TypeRules.c++
上传用户:weiyuanprp
上传日期:2020-05-20
资源大小:1169k
文件大小:13k
源码类别:

传真(Fax)编程

开发平台:

C/C++

  1. /* $Id: TypeRules.c++,v 1.7 2008/01/04 23:24:31 faxguy Exp $ */
  2. /*
  3.  * Copyright (c) 1990-1996 Sam Leffler
  4.  * Copyright (c) 1991-1996 Silicon Graphics, Inc.
  5.  * HylaFAX is a trademark of Silicon Graphics
  6.  *
  7.  * Permission to use, copy, modify, distribute, and sell this software and 
  8.  * its documentation for any purpose is hereby granted without fee, provided
  9.  * that (i) the above copyright notices and this permission notice appear in
  10.  * all copies of the software and related documentation, and (ii) the names of
  11.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  12.  * publicity relating to the software without the specific, prior written
  13.  * permission of Sam Leffler and Silicon Graphics.
  14.  * 
  15.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  16.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  17.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  18.  * 
  19.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  20.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  21.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  22.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  23.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  24.  * OF THIS SOFTWARE.
  25.  */
  26. #include <ctype.h>
  27. #include "Array.h"
  28. #include "TypeRules.h"
  29. #include "PageSize.h"
  30. #include "config.h"
  31. #include <string.h>
  32. #include <stdlib.h>
  33. #ifdef _XOPEN_SOURCE_EXTENDED
  34. #include <arpa/inet.h>
  35. #else
  36. extern "C" {
  37. #include <netinet/in.h>
  38. }
  39. #endif
  40. #ifndef TRUE
  41. #define TRUE 1
  42. #endif
  43. #ifndef FALSE
  44. #define FALSE 0
  45. #endif
  46. TypeRule::TypeRule() {}
  47. TypeRule::~TypeRule() {}
  48. TypeRule::TypeRule(const TypeRule& other)
  49.     : fxObj(other)
  50.     , cmd(other.cmd)
  51. {
  52.     off = other.off;
  53.     cont = other.cont;
  54.     type = other.type;
  55.     op = other.op;
  56.     value.v = other.value.v;
  57.     result = other.result;
  58. }
  59. static const char* typeNames[] =
  60.     { "ascii", "asciiesc", "string", "istring", "address", "byte", "short", "long" };
  61. static const char* opNames[] =
  62.     { "<any>", "=", "!=", "<", "<=", ">", ">=", "&", "^", "!" };
  63. static const char* resultNames[] = { "tiff", "postscript", "pdf", "pcl", "error" };
  64. fxStr
  65. quoted(const fxStr& s)
  66. {
  67.     fxStr q;
  68.     q.append(" '");
  69.     for (u_int i = 0; i < s.length(); i++) {
  70. if (s[i] == ''') q.append("'\'");
  71. q.append(s[i]);
  72.     }
  73.     q.append("'");
  74.     return (q);
  75. }
  76. bool
  77. TypeRule::match(const void* data, size_t size, bool verbose) const
  78. {
  79.     if (verbose) {
  80. printf("rule: %soffset %#lx %s %s",
  81.     cont ? ">" : "",
  82.     (u_long) off,
  83.     typeNames[type],
  84.     opNames[op]
  85. );
  86. if (type == STRING || type == ISTRING)
  87.     printf(" "%s"", value.s);
  88. else if (type != ASCII && type != ASCIIESC) {
  89.     if (op == ANY)
  90. printf(" <any value>");
  91.     else
  92. printf(" %#llx", (long long) value.v);
  93. }
  94. printf(" -- ");
  95.     }
  96.     if (off > (off_t)size) {
  97. if (verbose)
  98.     printf("failed (offset past data)n");
  99. return (false);
  100.     }
  101.     bool ok = false;
  102.     long v = 0;
  103.     const u_char* cp = (const u_char*) data;
  104.     switch (type) {
  105.     case ASCII:
  106. {
  107. u_int i;
  108. for (i = 0; i < size; i++)
  109.     if (!isprint(cp[i]) && !isspace(cp[i])) {
  110. if (verbose)
  111.     printf("failed (unprintable char %#x)n", cp[i]);
  112. return (false);
  113.     }
  114. ok = true;
  115. goto done;
  116. }
  117.     case ASCIIESC:
  118. {
  119. u_int i;
  120. for (i = 0; i < size; i++)
  121.     if (!isprint(cp[i]) && !isspace(cp[i]) && cp[i] != '33') {
  122. if (verbose)
  123.     printf("failed (unprintable char %#x)n", cp[i]);
  124. return (FALSE);
  125.     }
  126. ok = TRUE;
  127. goto done;
  128. }
  129.     case STRING:
  130. ok = (strncmp((const char*)(cp+off), value.s,
  131.     fxmin((u_int) strlen(value.s), (u_int)(size-off))) == 0);
  132. goto done;
  133.     case ISTRING:
  134. ok = (strncasecmp((const char*)(cp+off), value.s,
  135.     fxmin((u_int) strlen(value.s), (u_int)(size-off))) == 0);
  136. goto done;
  137.     case ADDR:
  138. v = (u_long) off;
  139. break;
  140.     case BYTE:
  141. v = *cp;
  142. break;
  143.     case SHORT:
  144. if (off + 2 < (off_t)size) {
  145.     u_short w;
  146.     memcpy(&w, cp+off, 2);
  147.     v = ntohs(w);
  148.     break;
  149. }
  150. if (verbose)
  151.     printf("failed (insufficient data)n");
  152. return (false);
  153.     case LONG:
  154. if (off + 4 < (off_t)size) {
  155.     memcpy(&v, cp+off, 4);
  156.     v = ntohl(v);
  157.     break;
  158. }
  159. if (verbose)
  160.     printf("failed (insufficient data)n");
  161. return (false);
  162.     }
  163.     /*
  164.      * Numeric value, use operation.
  165.      */
  166.     switch (op) {
  167.     case ANY: ok = true; break;
  168.     case EQ: ok = (v == value.v); break;
  169.     case NE: ok = (v != value.v); break;
  170.     case LT: ok = (v  < value.v); break;
  171.     case LE: ok = (v <= value.v); break;
  172.     case GT: ok = (v  > value.v); break;
  173.     case GE: ok = (v >= value.v); break;
  174.     case AND: ok = ((v&value.v) == value.v); break;
  175.     case NOT: ok = ((v&value.v) != value.v); break;
  176.     case XOR: ok = ((v^value.v) != 0); break;
  177.     }
  178. done:
  179.     if (verbose) {
  180. if (ok)
  181.     printf("success (result %s, rule "%s")n",
  182. resultNames[result], (const char*) cmd);
  183. else
  184.     printf("failed (comparison)n");
  185.     }
  186.     return (ok);
  187. }
  188. /*
  189.  * rule:  a string passed to the shell to convert the input file
  190.  *   to the result format (suitable for sending as facsimile).
  191.  *   The rule string is a printf-like string that should use the
  192.  *   following "%" escapes:
  193.  * %i input file name
  194.  * %o output file name
  195.  * %r output horizontal resolution in pixels/mm
  196.  * %R output horizontal resolution in pixels/inch
  197.  * %v output vertical resolution in lines/mm
  198.  * %V output vertical resolution in lines/inch
  199.  * %f data format, 1 for 1-d encoding or 2 for 2-d encoding
  200.  * %w page width in pixels
  201.  * %W page width in mm
  202.  * %l page length in pixels
  203.  * %L page length in mm
  204.  * %s page size by name
  205.  * %F the pathname of the fax library (e.g./usr/local/lib/fax)
  206.  * %<x> the <x> character (e.g. ``%%'' results in ``%''
  207.  */
  208. fxStr
  209. TypeRule::getFmtdCmd(
  210.     const fxStr& input, const fxStr& output,
  211.     float hr, float vr, const fxStr& df, const fxStr& pname) const
  212. {
  213.     fxStr fmtd;
  214.     const PageSizeInfo* info = PageSizeInfo::getPageSizeByName(pname);
  215.     float pw = info->width();
  216.     float pl = info->height();
  217.     for (u_int i = 0, n = cmd.length(); i < n; i++) {
  218. char c = cmd[i];
  219. if (c == '%' && i+1 < n) {
  220.     i++;
  221.     switch (c = cmd[i]) {
  222.     case 'i': fmtd.append(quoted(input));   continue;
  223.     case 'o': fmtd.append(quoted(output));   continue;
  224.     case 'R': fmtd.append(fxStr(hr, "%.2f"));   continue;
  225.     case 'r': fmtd.append(fxStr(hr/25.4, "%.2g"));   continue;
  226.     case 'V': fmtd.append(fxStr(vr, "%.2f"));   continue;
  227.     case 'v': fmtd.append(fxStr(vr/25.4, "%.2g"));   continue;
  228.     case 'f': fmtd.append(df);   continue;
  229.     case 'W': fmtd.append(fxStr(pw, "%.4g"));   continue;
  230.     case 'w': fmtd.append(fxStr(pw*hr/25.4, "%.0f"));   continue;
  231.     case 'L': fmtd.append(fxStr(pl, "%.4g"));   continue;
  232.     case 'l': fmtd.append(fxStr(pl*vr/25.4, "%.0f"));   continue;
  233.     case 'F': fmtd.append(fxStr(FAX_LIBEXEC));   continue;
  234.     case 's': fmtd.append(pname);   continue;
  235.     }
  236. }
  237. fmtd.append(c);
  238.     }
  239.     return fmtd;
  240. }
  241. fxDECLARE_ObjArray(TypeRuleArray, TypeRule)
  242. fxIMPLEMENT_ObjArray(TypeRuleArray, TypeRule)
  243. TypeRules::TypeRules()
  244. {
  245.     verbose = false;
  246.     rules = new TypeRuleArray;
  247. }
  248. TypeRules::~TypeRules()
  249. {
  250.     delete rules;
  251. }
  252. void
  253. TypeRules::setVerbose(bool b)
  254. {
  255.     verbose = b;
  256. }
  257. #include <ctype.h>
  258. static bool
  259. appendLine(fxStr& s, const char* line)
  260. {
  261.     const char* cp = line;
  262.     for (; isspace(*cp); cp++)
  263. ;
  264.     if (cp > line) // put back one bit of white space
  265. cp--;
  266.     const char* cmd = cp;
  267.     if (*cp != '' && *cp != 'n' && *cp != '#') {
  268. do {
  269.     cp++;
  270.     if (cp[-1] == '\') {
  271. if (*cp == 'n') { // continue cmd string on next line
  272.     s.append(cmd, cp-1 - cmd);
  273.     return (true);
  274. } else if (*cp) // accept anything but \0
  275.     cp++;
  276.     }
  277. } while (*cp != '' && *cp != 'n' && *cp != '#');
  278. s.append(fxStr(cmd, cp-cmd));
  279.     }
  280.     return (false);
  281. }
  282. #include <stdarg.h>
  283. static void
  284. parseError(const char* file, u_int lineno, const char* fmt ...)
  285. {
  286.     va_list ap;
  287.     va_start(ap, fmt);
  288.     fprintf(stderr, "%s: line %u: ", file, lineno); 
  289.     vfprintf(stderr, fmt, ap);
  290.     va_end(ap);
  291. }
  292. TypeRules*
  293. TypeRules::read(const fxStr& file)
  294. {
  295.     FILE* fp;
  296.     fp = fopen(file, "r");
  297.     if (fp == NULL) {
  298. fprintf(stderr, "%s: Can not open type rules file.n",
  299.     (const char*) file);
  300. return NULL;
  301.     }
  302.     TypeRules* tr = new TypeRules;
  303.     char line[256];
  304.     u_int lineno = 0;
  305.     while (fgets(line, sizeof (line), fp) != NULL) {
  306. lineno++;
  307. char* cp = line;
  308. if (*cp == 'n' || *cp == '#')
  309.     continue;
  310. TypeRule rule;
  311. if (*cp == '>') { // continuation
  312.     rule.cont = true;
  313.     cp++;
  314. } else
  315.     rule.cont = false;
  316. const char *op = cp;
  317. rule.off = strtoul(op, &cp, 0); // file offset
  318. if (cp == op) {
  319.     parseError(file, lineno, "Missing file offset");
  320.     continue;
  321. }
  322. while (isspace(*cp))
  323.     cp++;
  324. const char* tp = cp;
  325. while (*cp && !isspace(*cp)) // data type
  326.     cp++;
  327. if (strncasecmp(tp, "byte", cp-tp) == 0)
  328.     rule.type = TypeRule::BYTE;
  329. else if (strncasecmp(tp, "short", cp-tp) == 0)
  330.     rule.type = TypeRule::SHORT;
  331. else if (strncasecmp(tp, "long", cp-tp) == 0)
  332.     rule.type = TypeRule::LONG;
  333. else if (strncasecmp(tp, "string", cp-tp) == 0)
  334.     rule.type = TypeRule::STRING;
  335. else if (strncasecmp(tp, "istring", cp-tp) == 0)
  336.     rule.type = TypeRule::ISTRING;
  337. else if (strncasecmp(tp, "ascii", cp-tp) == 0)
  338.     rule.type = TypeRule::ASCII;
  339. else if (strncasecmp(tp, "asciiesc", cp-tp) == 0)
  340.     rule.type = TypeRule::ASCIIESC;
  341. else if (strncasecmp(tp, "addr", cp-tp) == 0)
  342.     rule.type = TypeRule::ADDR;
  343. else {
  344.     parseError(file, lineno, "Unknown datatype "%.*s"", cp-tp, tp);
  345.     continue; // bad type
  346. }
  347. while (isspace(*cp))
  348.     cp++;
  349. rule.op = TypeRule::EQ; // default is '='
  350. const char* vp = cp;
  351. if (rule.type != TypeRule::STRING && rule.type != TypeRule::ISTRING
  352. && rule.type != TypeRule::ASCII && rule.type != TypeRule::ASCIIESC) {
  353.     // numeric value
  354.     switch (*vp) {
  355.     case '=': rule.op = TypeRule::EQ; cp++; break;
  356.     case '^': rule.op = TypeRule::XOR; cp++; break;
  357.     case '&': rule.op = TypeRule::AND; cp++; break;
  358.     case 'x': rule.op = TypeRule::ANY; cp++; break;
  359.     case '>':
  360. if (cp[1] == '=') {
  361.     rule.op = TypeRule::GE; cp++;
  362. } else
  363.     rule.op = TypeRule::GT;
  364. cp++;
  365. break;
  366.     case '<':
  367. if (cp[1] == '=') {
  368.     rule.op = TypeRule::LE; cp++;
  369. } else
  370.     rule.op = TypeRule::LT;
  371. cp++;
  372. break;
  373.     case '!':
  374. if (cp[1] == '=') {
  375.     rule.op = TypeRule::NE; cp++;
  376. } else
  377.     rule.op = TypeRule::NOT;
  378. cp++;
  379. break;
  380.     }
  381.     if (rule.op != TypeRule::ANY) {
  382. const char* vp = cp;
  383. rule.value.v = strtol(vp, &cp, 0);
  384. if (vp == cp) {
  385.     parseError(file, lineno, "Missing match value");
  386.     continue;
  387. }
  388.     }
  389. } else { // string value
  390.     while (*cp != '' && *cp != 't') // NB: accept blanks
  391. cp++;
  392.     if (*cp != 't')
  393. continue;
  394.     u_int len = cp-vp;
  395.     rule.value.s = (char*) malloc(len+1); // +1 for 
  396.     memcpy(rule.value.s, vp, len);
  397.     rule.value.s[len] = '';
  398. }
  399. while (isspace(*cp))
  400.     cp++;
  401. const char* rp = cp;
  402. while (isalpha(*cp))
  403.     cp++;
  404. if (strncasecmp(rp, "tiff", cp-rp) == 0)
  405.     rule.result = TypeRule::TIFF;
  406. else if (strncasecmp(rp, "ps", cp-rp) == 0)
  407.     rule.result = TypeRule::POSTSCRIPT;
  408. else if (strncasecmp(rp, "pdf", cp-rp) == 0)
  409.     rule.result = TypeRule::PDF;
  410. else if (strncasecmp(rp, "pcl", cp-rp) == 0)
  411.     rule.result = TypeRule::PCL;
  412. else if (strncasecmp(rp, "error", cp-rp) == 0)
  413.     rule.result = TypeRule::ERROR;
  414. else {
  415.     parseError(file, lineno, "Unknown result "%.*s"", cp-rp, rp);
  416.     continue;
  417. }
  418. while (isspace(*cp))
  419.     cp++;
  420. const char* cmd = cp; // collect cmd string
  421. if (*cp != '' && *cp != 'n' && *cp != '#') {
  422.     bool done = false; // XXX workaround compiler limitation
  423.     do {
  424. cp++;
  425. if (cp[-1] == '\') {
  426.     if (*cp == 'n') { // continue cmd string on next line
  427. rule.cmd = fxStr(cmd, cp-1 - cmd);
  428. while (fgets(line, sizeof (line), fp) != NULL &&
  429.   appendLine(rule.cmd, line))
  430.     ;
  431. done = true;
  432.     } else if (*cp) // accept anything but \0
  433. cp++;
  434. }
  435.     } while (!done && *cp != '' && *cp != 'n' && *cp != '#');
  436.     if (!done)
  437. rule.cmd = fxStr(cmd, cp-cmd);
  438. }
  439. tr->rules->append(rule);
  440.     }
  441.     (void) fclose(fp);
  442.     return (tr);
  443. }
  444. /*
  445.  * Check secondary matching rules after a primary match.
  446.  */
  447. u_int
  448. TypeRules::match2(u_int base, const void* data, u_int size, bool verb) const
  449. {
  450.     for (u_int i = 1, n = (*rules).length() - base; i < n; i++) {
  451. TypeRule& rule = (*rules)[base+i];
  452. if (!rule.isContinuation())
  453.     break;
  454. if (rule.match(data, size, verb))
  455.     return (i);
  456.     }
  457.     return 0;
  458. }
  459. const TypeRule*
  460. TypeRules::match(const void* data, u_int size) const
  461. {
  462.     if (verbose)
  463. printf("match against (..., %u)n", size);
  464.     for (u_int i = 0, n = (*rules).length(); i < n; i++) {
  465. TypeRule& rule = (*rules)[i];
  466. if (!rule.isContinuation() && rule.match(data, size, verbose))
  467.     return (&(*rules)[i + match2(i, data, size, verbose)]);
  468.     }
  469.     if (verbose)
  470. printf("no matchn");
  471.     return (NULL);
  472. }