home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / hexfindo.zip / HexFind.C < prev    next >
C/C++ Source or Header  |  2000-11-10  |  16KB  |  622 lines

  1. /*
  2.   hex pattern finder v2.1
  3.   additional features:
  4.   - file specification:
  5.     - wildcards in file spec
  6.     - recursive search in subdirectories
  7.     - optional also system or hidden files
  8.   - search pattern:
  9.     - wildcards allowed
  10.     - text strings, optional case insensitive
  11.  
  12.   (c) 1998 - 2000 Heinz Repp
  13. */
  14.  
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <ctype.h>
  18. #include <stdlib.h>
  19. #include <io.h>
  20. #include <fcntl.h>
  21. #include <sys\stat.h>
  22.  
  23. #if defined __OS2__ && defined __IBMC__
  24.   #define INCL_DOSFILEMGR
  25.   #define INCL_DOSERRORS
  26.   #include <os2.h>
  27. #elif defined __WIN32__ && defined __BORLANDC__
  28.   #include <dos.h>
  29.   #include <dir.h>
  30.   #define FALSE 0
  31.   #define TRUE 1
  32.   #define CCHMAXPATH MAXPATH
  33.   #define CCHMAXPATHCOMP MAXPATH
  34.   #define FILE_HIDDEN FA_HIDDEN
  35.   #define FILE_SYSTEM FA_SYSTEM
  36.   #define FILE_ARCHIVED FA_ARCH
  37.   #define FILE_READONLY FA_RDONLY
  38. #else
  39.   #error compiler not supported
  40. #endif
  41.  
  42. #define HF_STDIN 0
  43. #define BUFFERSIZE 49152  /* 48 kB */
  44.  
  45. short int     subdirs = FALSE, verbose = FALSE, no_case = FALSE,
  46.               p_length, p_signif, jumpm,  shift[256], jump[256],
  47.               p_posit[256], letter[256],
  48.          ch_prob [256] = {
  49. 14904, 1533, 1038, 865, 936, 615, 614, 643, 738, 450, 761, 389, 493, 602, 391, 528,
  50.  602, 339, 282, 251, 346, 262, 285, 217, 300, 212, 211, 218, 277, 209, 262, 227,
  51.  2663, 227, 320, 222, 532, 226, 342, 199, 314, 263, 301, 231, 344, 310, 366, 295,
  52.  638, 409, 357, 414, 323, 297, 297, 252, 311, 293, 257, 248, 233, 272, 215, 416,
  53.  567, 516, 313, 442, 587, 725, 513, 300, 296, 368, 171, 187, 373, 399, 351, 387,
  54.  673, 235, 387, 442, 414, 362, 349, 301, 233, 172, 184, 184, 256, 208, 256, 444,
  55.  247, 778, 317, 472, 558, 1365, 630, 349, 486, 783, 319, 210, 618, 397, 804, 722,
  56.  501, 158, 810, 692, 1156, 583, 354, 692, 286, 253, 202, 162, 230, 239, 307, 275,
  57.  722, 326, 244, 578, 254, 306, 200, 186, 685, 486, 201, 1045, 191, 366, 205, 171,
  58.  253, 164, 167, 166, 154, 130, 140, 127, 163, 197, 234, 144, 144, 127, 130, 142,
  59.  203, 188, 131, 140, 144, 136, 124, 120, 146, 117, 148, 117, 139, 119, 127, 127,
  60.  193, 133, 129, 118, 146, 124, 135, 131, 228, 141, 140, 211, 142, 126, 139, 198,
  61.  509, 292, 217, 229, 356, 126, 181, 283, 183, 178, 142, 136, 352, 133, 139, 138,
  62.  202, 152, 158, 135, 140, 118, 131, 153, 188, 138, 133, 144, 159, 155, 127, 141,
  63.  234, 149, 142, 136, 171, 137, 130, 127, 477, 263, 134, 221, 256, 127, 180, 175,
  64.  371, 188, 181, 163, 206, 154, 212, 273, 355, 184, 230, 218, 384, 216, 364, 3928
  65.  }; /* character probability in 1/100000 */
  66. unsigned long filecount = 0L, bytecount = 0L, matchcount = 0L,
  67.               fileopt = FILE_ARCHIVED | FILE_READONLY;
  68. unsigned char buffer[BUFFERSIZE + 511], poschar[256];
  69.  
  70. char nibble (char c)
  71. {
  72.   c = tolower (c);
  73.   if (c < '0' || c > '9' && c < 'a' || c > 'f')
  74.   {
  75.     fputs ("Hexadecimal pattern is not valid.\n", stderr);
  76.     exit (2);
  77.   }
  78.  
  79.   return c < 'a' ? c - '0' : c - ('a' - 10);
  80. } /* nibble */
  81.  
  82.  
  83. void ParseOption (char *option)
  84. {
  85.   do
  86.   {
  87.     switch (tolower (*option))
  88.     {
  89.       case 'i':
  90.         switch (*++option)
  91.         {
  92.           case '-':
  93.             option++;
  94.             no_case = FALSE;
  95.             break;
  96.           case '+':
  97.             option++;
  98.           default:
  99.             no_case = TRUE;
  100.         } /* endswitch r */
  101.         break;
  102.  
  103.       case 'h':
  104.         switch (*++option)
  105.         {
  106.           case '-':
  107.             option++;
  108.             fileopt &= ~FILE_HIDDEN;
  109.             break;
  110.           case '+':
  111.             option++;
  112.           default:
  113.             fileopt |= FILE_HIDDEN;
  114.         } /* endswitch h */
  115.         break;
  116.  
  117.       case 's':
  118.         switch (*++option)
  119.         {
  120.           case '-':
  121.             option++;
  122.             fileopt &= ~FILE_SYSTEM;
  123.             break;
  124.           case '+':
  125.             option++;
  126.           default:
  127.             fileopt |= FILE_SYSTEM;
  128.         } /* endswitch s */
  129.         break;
  130.  
  131.       case 'r':
  132.         switch (*++option)
  133.         {
  134.           case '-':
  135.             option++;
  136.             subdirs = FALSE;
  137.             break;
  138.           case '+':
  139.             option++;
  140.           default:
  141.             subdirs = TRUE;
  142.         } /* endswitch r */
  143.         break;
  144.  
  145.       case 'v':
  146.         switch (*++option)
  147.         {
  148.           case '-':
  149.             option++;
  150.             verbose = FALSE;
  151.             break;
  152.           case '+':
  153.             option++;
  154.           default:
  155.             verbose = TRUE;
  156.         } /* endswitch r */
  157.         break;
  158.  
  159.       default:
  160.         fprintf (stderr, "Unknown option \"%s\".\n", option);
  161.         exit (3);
  162.  
  163.     } /* endswitch */
  164.   } while (*option);
  165.  
  166. } /* ParseOption */
  167.  
  168.  
  169. void ParsePattern (char *hexarg)
  170. {
  171.   register int i, j;
  172.   int          state, lastw;
  173.   short int    pattern[256], p_lttr[256];
  174.  
  175.   p_length = 0;
  176.   p_signif = 0;
  177.   lastw = 0;
  178.   state = 0;
  179.  
  180.   do
  181.   {
  182.     switch (state)
  183.     {
  184.       case 0:
  185.         switch (*hexarg)
  186.         {
  187.           case '"':        /* double quoted string */
  188.           case '\'':       /* single quoted string */
  189.             state = *hexarg++;
  190.             break;
  191.           case ' ':
  192.             hexarg++;      /* ignore blanks */
  193.             break;
  194.           case '?':        /* wildcard */
  195.             hexarg++;
  196.             pattern[p_length] = -1;
  197.             lastw = ++p_length;
  198.             break;
  199.           default:
  200.             pattern[p_length] = nibble (*hexarg++) << 4;
  201.             state = 1;
  202.         }
  203.         break;
  204.       case 1:
  205.         pattern[p_length] |= nibble (*hexarg++);
  206.         if (no_case)
  207.           p_lttr[p_length] = FALSE;
  208.         p_posit[p_signif++] = p_length++;
  209.         state = 0;
  210.         break;
  211.       default:
  212.         if (*hexarg == state)
  213.         {
  214.           hexarg++;
  215.           state = 0;
  216.         }
  217.         else
  218.         {
  219.           pattern[p_length] = *hexarg++;
  220.           if (no_case)
  221.           {
  222.             if (pattern[p_length] >= 'A' && pattern[p_length] <= 'Z')
  223.             {
  224.               pattern[p_length] |= 0x20;
  225.               p_lttr[p_length] = TRUE;
  226.             }
  227.             else if (pattern[p_length] >= 'a' && pattern[p_length] <= 'z')
  228.               p_lttr[p_length] = TRUE;
  229.             else
  230.               p_lttr[p_length] = FALSE;
  231.           }
  232.           p_posit[p_signif++] = p_length++;
  233.         }
  234.     } /* endswitch state */
  235.  
  236.   } while (*hexarg && p_length < 256); /* enddo */
  237.  
  238.   if (state == 1)
  239.     nibble ('?');    /* causes appropriate error exit */
  240.   if (lastw == p_length)
  241.   {
  242.     fputs ("Trailing wildcard is not allowed.\n", stderr);
  243.     exit (4);
  244.   }
  245.  
  246.   /* insertion sort p_posit up to p_signif-2 in ch_prob order */
  247.   if (no_case)
  248.     for (i = 'a'; i <= 'z'; i++)
  249.       ch_prob[i] += ch_prob[i & ~0x20];
  250.  
  251.   for (i = 1; i < p_signif - 1; i++)
  252.   {
  253.     state = p_posit[i];
  254.     for (j = i;
  255.          j > 0 && ch_prob[pattern[p_posit[j - 1]]] < ch_prob[pattern[state]];
  256.          j--) p_posit[j] = p_posit[j - 1];
  257.     p_posit[j] = state;
  258.   }
  259.  
  260.   /* make shift and jump tables */
  261.   for (i = 0; i < 256; i++)
  262.      shift[i] = p_length - lastw;
  263.   for (i = 0; i < p_signif; i++)
  264.   {
  265.     poschar[i] = pattern[p_posit[i]];
  266.     if (no_case) letter[i] = p_lttr[p_posit[i]];
  267.  
  268.     if (p_posit[i] >= lastw)
  269.     {
  270.       shift[poschar[i]] = p_length - 1 - p_posit[i];
  271.       if (no_case && letter[i])
  272.         shift[poschar[i] & ~0x20] = shift[poschar[i]];
  273.     }
  274.     jump[i] = p_length;
  275.   }
  276.   jumpm = p_length;
  277.   /* try decreasing jumps after (partial) match */
  278.   for (j = p_length - 1; j > 0; j--)
  279.   {
  280.     /* check decreasing char positions:
  281.       if match is possible on shifted pattern after:
  282.       - mismatch, note shift distance as possible
  283.       - match before, try next position           */
  284.     for (i = p_signif - 1; i >= 0; i--)
  285.     {
  286.       if (p_posit[i] < j || pattern[p_posit[i] - j] < 0)
  287.         jump[i] = j;
  288.       else if (no_case && letter[i] != p_lttr[p_posit[i] - j])
  289.       {
  290.         if (letter[i])
  291.         {
  292.           if (poschar[i] != pattern[p_posit[i] - j] | 0x20)
  293.           {
  294.             jump[i] = j;
  295.             break;
  296.           }
  297.         }
  298.         else
  299.         {
  300.           jump[i] = j;
  301.           if ((poschar[i] | 0x20) != pattern[p_posit[i] - j])
  302.             break;
  303.         }
  304.       }
  305.       else if (poschar[i] != pattern[p_posit[i] - j])
  306.       {
  307.         jump[i] = j;
  308.         break;
  309.       }
  310.     }
  311.     if (i < 0)
  312.       jumpm = j;
  313.   }
  314.  
  315.   if (verbose)
  316.   {
  317.     printf ("Searching for HEX pattern ");
  318.     for (i = 0; i < p_length; i++)
  319.       if (pattern[i] < 0)
  320.         printf ("?? ");
  321.       else
  322.         printf ("%02X ", pattern[i]);
  323.     printf ("...\n");
  324.   }
  325.  
  326. } /* ParsePattern */
  327.  
  328.  
  329. unsigned char *FastSearch (register unsigned char *where)
  330. {
  331.   register int i;
  332.  
  333.   /* outer loop */
  334.   for ( ; ; )
  335.   {
  336.     where += p_length - 1;
  337.  
  338.     /* inner loop */
  339.     while (i = shift[*where])
  340.       where += i;
  341.     /* inner loop */
  342.  
  343.     where -= p_length - 1;
  344.  
  345.     i = p_signif - 1;
  346.     do
  347.       if (--i < 0)
  348.         return where;
  349.     while (no_case && letter[i] ?
  350.            (where[p_posit[i]] | 0x20) == poschar[i] :
  351.            where[p_posit[i]] == poschar[i]);
  352.  
  353.     where += jump[i];
  354.   } /* outer loop */
  355.  
  356. } /* FastSearch */
  357.  
  358.  
  359. void SearchFile (char *filename, int handle)
  360. {
  361.   unsigned long result, f_offset;
  362.   unsigned char *fill, *found, pdc[12];
  363.   int i;
  364.  
  365.   if (verbose)
  366.     printf ("Searching %s ...\n", filename);
  367.  
  368.   f_offset = 0;
  369.   fill = buffer;
  370.   pdc[0] = '(';
  371.  
  372.   while ((result = read (handle, fill, BUFFERSIZE)) > 0)
  373.   {
  374.     /* statistics */
  375.     bytecount += result;
  376.  
  377.     /* append pattern after end */
  378.     fill += result;
  379.     for (i = 0; i < p_signif; i++)
  380.       fill[p_posit[i]] = poschar[i];
  381.  
  382.     found = FastSearch (buffer);
  383.  
  384.     while (found <= fill - p_length)
  385.     {
  386.       /* it's a real match - print and count it */
  387.       sprintf (&pdc[1], "%lu", f_offset + (found - buffer));
  388.       printf ("offset 0x%08lX%11s) in %s\n",
  389.               f_offset + (found - buffer), pdc, filename);
  390.       matchcount++;
  391.  
  392.       found = FastSearch (found + jumpm);
  393.     }
  394.  
  395.     if (result < BUFFERSIZE)
  396.     {
  397.       break;
  398.     }
  399.     else
  400.     {
  401.       result = p_length - 1;
  402.       memcpy (buffer, fill - result, result);
  403.       f_offset += fill - buffer - result;
  404.       fill = buffer + result;
  405.     }
  406.   }
  407.  
  408.   /* statistics */
  409.   filecount++;
  410.  
  411. } /* SearchFile */
  412.  
  413.  
  414. int SearchPath (char *path, char *mask)
  415. {
  416.   int rc, fhandle;
  417. #if defined __OS2__ && defined __IBMC__
  418.   ULONG count;
  419.   HDIR dhandle;
  420.   FILEFINDBUF3 finfo;
  421. #elif defined __WIN32__ && defined __BORLANDC__
  422.   struct ffblk finfo;
  423.   #define achName ff_name
  424. #endif
  425.   char FullPathName[CCHMAXPATH];
  426.  
  427.   /* 1. search files */
  428.   strcpy (FullPathName, path);
  429.   strcat (FullPathName, mask);
  430.  
  431. #if defined __OS2__ && defined __IBMC__
  432.   dhandle = HDIR_CREATE;
  433.   count = 1;
  434.   if (DosFindFirst (FullPathName,
  435.                     &dhandle,
  436.                     fileopt,
  437.                     &finfo,
  438.                     sizeof (finfo),
  439.                     &count,
  440.                     FIL_STANDARD) == NO_ERROR)
  441. #elif defined __WIN32__ && defined __BORLANDC__
  442.   if (findfirst (FullPathName, &finfo, fileopt) == 0)
  443. #endif
  444.   {
  445.     do
  446.     {
  447.       strcpy (FullPathName, path);
  448.       strcat (FullPathName, finfo.achName);
  449.  
  450.       if ((fhandle = open (FullPathName, O_RDONLY | O_BINARY, 0)) == -1)
  451.       {
  452.         fprintf (stderr, "Error opening file %s.\n", FullPathName);
  453.       }
  454.       else
  455.       {
  456.         SearchFile (FullPathName, fhandle);
  457.         close (fhandle);
  458.       }
  459. #if defined __OS2__ && defined __IBMC__
  460.     } while (DosFindNext (dhandle,
  461.                           &finfo,
  462.                           sizeof (finfo),
  463.                           &count) == NO_ERROR); /* enddo */
  464. #elif defined __WIN32__ && defined __BORLANDC__
  465.     } while (findnext (&finfo) == 0);
  466. #endif
  467.  
  468. #if defined __OS2__ && defined __IBMC__
  469.     DosFindClose (dhandle);
  470. #elif defined __WIN32__ && defined __BORLANDC__
  471.     findclose (&finfo);
  472. #endif
  473.     rc = 0;
  474.   }
  475.   else
  476.   {
  477.     rc = 1;  /* no files found */
  478.   } /* endif DosFindFirst */
  479.  
  480.   /* 2. if recursive search subdirectories */
  481.   if (subdirs)
  482.   {
  483.     strcpy (FullPathName, path);
  484.     strcat (FullPathName, "*");
  485.  
  486. #if defined __OS2__ && defined __IBMC__
  487.     dhandle = HDIR_CREATE;
  488.     count = 1;
  489.     if (DosFindFirst (FullPathName,
  490.                       &dhandle,
  491.                       fileopt | MUST_HAVE_DIRECTORY,
  492.                       &finfo,
  493.                       sizeof (FILEFINDBUF3),
  494.                       &count,
  495.                       FIL_STANDARD) == NO_ERROR)
  496. #elif defined __WIN32__ && defined __BORLANDC__
  497.     if (findfirst (FullPathName, &finfo, fileopt | FA_DIREC) == 0)
  498. #endif
  499.     {
  500.       do
  501.       {
  502.         if (strcmp (finfo.achName, ".") && strcmp (finfo.achName, ".."))
  503.         {
  504.           strcpy (FullPathName, path);
  505.           strcat (FullPathName, finfo.achName);
  506.           strcat (FullPathName, "\\");
  507.  
  508.           rc &= SearchPath (FullPathName, mask);
  509.         }
  510. #if defined __OS2__ && defined __IBMC__
  511.       } while (DosFindNext (dhandle,
  512.                             &finfo,
  513.                             sizeof (finfo),
  514.                             &count) == NO_ERROR); /* enddo */
  515. #elif defined __WIN32__ && defined __BORLANDC__
  516.       } while (findnext (&finfo) == 0);
  517. #endif
  518.  
  519. #if defined __OS2__ && defined __IBMC__
  520.       DosFindClose (dhandle);
  521. #elif defined __WIN32__ && defined __BORLANDC__
  522.       findclose (&finfo);
  523. #endif
  524.     } /* endif DosFindFirst */
  525.   } /* endif */
  526.  
  527.   return rc;
  528. } /* SearchPath */
  529.  
  530.  
  531. int main (int argc, char *argv[])
  532. {
  533.   int i;
  534.   char rootpath[CCHMAXPATH], filemask[CCHMAXPATHCOMP], *filename = NULL;
  535.  
  536.   printf ("HexFind 2.1 (c) 1998-2000 by Heinz Repp\n");
  537.  
  538.   /* parse command line: */
  539.  
  540.   /* 1. leading options */
  541.   i = 1;
  542.   while (i < argc && (*argv[i] == '/' || *argv[i] == '-'))
  543.     ParseOption (++argv[i++]);
  544.  
  545.   /* 2. pattern */
  546.   if (i < argc)
  547.   {
  548.     ParsePattern (argv[i]);
  549.   }
  550.   else
  551.   {
  552.     fputs ("\n"
  553. "Usage:   HexFind [-options] [\"]<pattern>[\"] files ...\n"
  554. "\n"
  555. "   options:  <i>gnore case, <r>ecurse into subdirectories,\n"
  556. "             include <h>idden or <s>ystem files, be <v>erbose\n"
  557. " <pattern>:  one or more of [ HEX-pair | 'string' | ? ]\n"
  558. "             (? = wildcard, pattern must be contiguous or quoted!)\n",
  559.            stderr);
  560.     exit (1);
  561.   }
  562.  
  563.   /* 3. trailing options and file specs */
  564.   while (++i < argc)
  565.   {
  566.     if (*argv[i] == '/' || *argv[i] == '-')
  567.       ParseOption (++argv[i]);
  568.     else
  569.     {
  570.       strcpy (rootpath, argv[i]);
  571.       /* replace slashes by backslashes */
  572.       for (filename = rootpath;
  573.            filename = strchr (filename, '/');
  574.            *filename++ = '\\');
  575.       /* split into path and filename */
  576.       if (filename = strrchr (rootpath, '\\'))
  577.         filename++;   /* skip path delimiter */
  578.       else
  579.         filename = rootpath;      /* no path */
  580.  
  581.       if (*filename == '\0')      /* only path given */
  582.       {
  583.         strcpy (filemask, "*");
  584.       }
  585.       else
  586.       {
  587.         struct stat stbuff;
  588.  
  589.         if (strpbrk (filename, "?*") == NULL &&
  590.                  stat (rootpath, &stbuff) == 0 &&
  591.                  stbuff.st_mode & S_IFDIR)
  592.         /* no wildcards, name exists and is a directory */
  593.         {
  594.           strcat (rootpath, "\\");
  595.           strcpy (filemask, "*");
  596.         }
  597.         else
  598.         {
  599.           strcpy (filemask, filename);
  600.           *filename = '\0';
  601.         }
  602.       }
  603.  
  604.       if (SearchPath (rootpath, filemask))
  605.         fprintf (stderr, "Found no files matching '%s%s'.\n", rootpath, filemask);
  606.     } /* endif */
  607.   } /* endwhile all arguments */
  608.  
  609.   /* if no file spec until now */
  610.   if (filename == NULL)
  611.   {
  612.     setmode (HF_STDIN, O_BINARY);
  613.     SearchFile ("StdIn", HF_STDIN);
  614.   }
  615.  
  616.   if (verbose)
  617.     printf ("Found %lu occurence(s) in %lu file(s) (%lu bytes searched).\n",
  618.              matchcount, filecount, bytecount);
  619.  
  620.   exit (0);
  621. } /* main */
  622.