home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / UTILITY / FILE / FILTYP10.ZIP / FILETYPE.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1991-07-31  |  11.5 KB  |  352 lines

  1. Program filetype;
  2. { Partial Un*x 'file' clone: use magic sequences to guess at file type       }
  3. { Free Software by TapirSoft Gisbert W.Selke, Jul 1991                       }
  4.  
  5. { See the sample Magic.FT or the documentation for an explanation of the     }
  6. { format of the magic file. Call without parameters for a usage screen.      }
  7.  
  8. {$A+,B-,D+,E+,F-,I-,L+,N-,O-,R+,S+,V- }
  9. {$M 16384,0,16384 }
  10.  
  11.   Const progname = 'FileType';
  12.         version  = '1.0';
  13.         copyright= 'Free Software by TapirSoft Gisbert W.Selke, Jul 1991';
  14.  
  15.         magicname= 'Magic.ft';
  16.         magicid  = ';FTMagic1.0';
  17.         bufsize  = 40000;
  18.         examsize = 256;
  19.         Tab      = #9;
  20.  
  21.   Type iobuffer   = Array [0..bufsize] Of byte;
  22.        exambuffer = Array [0..examsize-1] Of byte;
  23.        transbuff  = Array [0..255] Of byte;
  24.        nocasebuff = Array [0..examsize] Of boolean;
  25.  
  26.   Var magicfile : text;
  27.       testfile : File;
  28.       exambuff : Array [0..1] Of exambuffer;
  29.       maskbuff, magic : exambuffer;
  30.       translat, transl, transu : transbuff;
  31.       magicbuff: iobuffer;
  32.       nocase : nocasebuff;
  33.       fname, mname, temp : string;
  34.       pos2, matchpos, testfsize : longint;
  35.       examlen, examstart : word;
  36.       translen : integer;
  37.       i, magiclen, masklen, buffno : byte;
  38.       match : boolean;
  39.  
  40.       ctemp : char;
  41.  
  42.   Procedure usage;
  43.   { show usage hints and die                                                 }
  44.   Begin                                                              { usage }
  45.     writeln(progname,' ',version,' -- ',copyright);
  46.     writeln('Using magic numbers, try to find out type of given file');
  47.     writeln('Usage: ',progname,' [/m<magicfile>] [/q] <filename>');
  48.     writeln('       Default for <magicfile> is ',magicname,'.');
  49.     writeln('       /q (quiet) suppresses vanity message.');
  50.     Halt(1);
  51.   End;                                                               { usage }
  52.  
  53.   Procedure strip(Var s : string);
  54.   { strip leading blanks and tabs from s                                     }
  55.   Begin                                                              { strip }
  56.     While (s <> '') And ((s[1] = ' ') Or (s[1] = Tab)) Do Delete(s,1,1);
  57.   End;                                                               { strip }
  58.  
  59.   Function hex2num(c : char): byte;
  60.   { convert a hex digit to a number value                                    }
  61.   Begin                                                            { hex2num }
  62.     Case UpCase(c) Of
  63.       '0'..'9' : hex2num := Ord(c) - Ord('0');
  64.       'A'..'Z' : hex2num := Ord(UpCase(c)) - Ord('A') + 10;
  65.       Else hex2num := 0;
  66.     End;
  67.   End;                                                             { hex2num }
  68.  
  69.   Procedure getargs;
  70.   { get command line arguments, init vars                                    }
  71.     Var i : byte;
  72.         quiet : boolean;
  73.   Begin                                                            { getargs }
  74.     mname := '';
  75.     fname := '';
  76.     quiet := False;
  77.     For i := 1 To ParamCount Do
  78.     Begin
  79.       temp:= ParamStr(i);
  80.       If (temp[1] = '/') Or (temp[1] = '-') Then
  81.       Begin
  82.         If Length(temp) <= 1 Then usage;
  83.         Case UpCase(temp[2]) Of
  84.           'Q' : quiet := True;
  85.           'M' : Begin
  86.                   If Length(temp) = 2 Then usage;
  87.                   mname := Copy(temp,3,255);
  88.                 End;
  89.           Else  usage;
  90.         End;
  91.       End
  92.       Else
  93.       Begin
  94.         If fname <> ''Then usage;
  95.         fname := temp;
  96.       End;
  97.     End;
  98.     If fname = '' Then usage;
  99.     If mname = '' Then mname := magicname;
  100.     translen := 0;
  101.     For i := 0 To 255 Do translat[i] := i;
  102.     For i := Ord('a') To Ord('z') Do translat[i] := byte(UpCase(char(i)));
  103.     If Not quiet Then writeln(progname,' ',version,' -- ',copyright);
  104.   End;                                                             { getargs }
  105.  
  106.   Procedure gettestfile;
  107.   { gets name of testfile, reads starting buffer                             }
  108.   Begin                                                        { gettestfile }
  109.     FileMode := 0;
  110.     Assign(testfile,fname);
  111.     Reset(testfile,1);
  112.     If IOResult <> 0 Then
  113.     Begin
  114.       writeln('Cannot find ',fname);
  115.       Halt(2);
  116.     End;
  117.     BlockRead(testfile,exambuff[0],examsize,examlen);
  118.     If IOResult <> 0 Then
  119.     Begin
  120.       writeln('Cannot read ',fname);
  121.       Halt(3);
  122.     End;
  123.     If examlen = 0 Then
  124.     Begin
  125.       writeln(fname,': empty file');
  126.       Halt(0);
  127.     End;
  128.     testfsize := FileSize(testfile);
  129.     pos2 := 0;
  130.   End;                                                         { gettestfile }
  131.  
  132.   Procedure openmagicfile;
  133.   { find and open magic file                                                 }
  134.   Begin                                                      { openmagicfile }
  135.     Assign(magicfile,mname);
  136.     Reset(magicfile);
  137.     If IOResult <> 0 Then
  138.     Begin
  139.       temp:= ParamStr(0);
  140.       While (temp <> '') And (Not (temp[Length(temp)] In ['\',':'])) Do
  141.                                                   Delete(temp,Length(temp),1);
  142.       Assign(magicfile,temp+mname);
  143.       Reset(magicfile);
  144.       If IOResult <> 0 Then
  145.       Begin
  146.         writeln('Cannot find magic file ',mname);
  147.         Halt(4);
  148.       End;
  149.       mname := temp + mname;
  150.     End;
  151.     SetTextBuf(magicfile,magicbuff);
  152.     readln(magicfile,temp);
  153.     If Copy(temp,1,Length(magicid)) <> magicid Then
  154.     Begin
  155.       writeln(mname,' is not a valid ',progname,' magic number file');
  156.       Halt(6);
  157.     End;
  158.   End;                                                       { openmagicfile }
  159.  
  160.   Procedure gettrans(Var s : string; Var trans : transbuff);
  161.   { get a case translation line                                              }
  162.     Var i : byte;
  163.   Begin                                                           { gettrans }
  164.     For i := 0 To 255 Do trans[i] := 0;
  165.     For i := 2 To Length(s) Do trans[i] := byte(s[i]);
  166.     translen := Pred(Length(s));
  167.     For i := 0 To 255 Do translat[i] := i;
  168.     For i := Ord('a') To Ord('z') Do translat[i] := byte(UpCase(char(i)));
  169.     For i := 0 To translen-1 Do translat[transl[i]] := transu[i];
  170.     s := '';
  171.   End;                                                            { gettrans }
  172.  
  173.   Procedure getsequence(Var s : string; Var buff : exambuffer; Var len : byte;
  174.                         updcase : boolean);
  175.   { extract a magic (or mask) sequence from an input line                    }
  176.  
  177.     Var quote : char;
  178.         ival, stuffit : byte;
  179.         escaped, ignocase : boolean;
  180.  
  181.   Begin                                                        { getsequence }
  182.     quote := #0;
  183.     len := 0;
  184.     stuffit := 0;
  185.     ival:= 0;
  186.     ignocase := False;
  187.     While (s <> '') And ((UpCase(s[1]) In ['0'..'9','A'..'F','''','"','?']) Or
  188.                          (quote <> #0)) Do
  189.     Begin
  190.       If quote = #0 Then
  191.       Begin
  192.         escaped := False;
  193.         Case UpCase(s[1]) Of
  194.           '''','"' : Begin
  195.                        quote := s[1];
  196.                        ignocase := s[1] = '"';
  197.                        stuffit := 0;
  198.                      End;
  199.           '?'      : stuffit := 3;
  200.           '0'..'9', 'A'..'Z' : Begin
  201.                        ival := (ival ShL 4) Or hex2num(s[1]);
  202.                        Inc(stuffit);
  203.                      End;
  204.         End;
  205.       End
  206.       Else
  207.       Begin
  208.         If escaped Then
  209.         Begin
  210.           Case s[1] Of
  211.             'b' : ival :=  8;
  212.             't' : ival :=  9;
  213.             'n' : ival := 10;
  214.             'v' : ival := 11;
  215.             'f' : ival := 12;
  216.             'r' : ival := 13;
  217.             Else ival := byte(s[1]);
  218.           End;
  219.           escaped := False;
  220.           stuffit := 2;
  221.         End
  222.         Else
  223.         Begin
  224.           Case s[1] Of
  225.             '\' : Begin
  226.                     escaped := True;
  227.                     stuffit := 0;
  228.                   End;
  229.             '?' : Begin
  230.                     ival := 0;
  231.                     stuffit := 3;
  232.                   End;
  233.             Else Begin
  234.                    If s[1] = quote Then
  235.                    Begin
  236.                      quote := #0;
  237.                      ignocase := False;
  238.                      stuffit := 0;
  239.                    End
  240.                    Else
  241.                    Begin
  242.                      ival := byte(s[1]);
  243.                      stuffit := 2;
  244.                    End;
  245.                  End;
  246.           End;
  247.         End;
  248.       End;
  249.       If stuffit >= 2 Then
  250.       Begin
  251.         buff[len] := ival;
  252.         If stuffit = 3 Then maskbuff[len] := $0;
  253.         nocase[len] := ignocase;
  254.         Inc(len);
  255.         ival := 0;
  256.         stuffit := 0;
  257.       End;
  258.       Delete(s,1,1);
  259.     End;
  260.   End;                                                         { getsequence }
  261.  
  262.   Function getmatchpos(Var s : string) : longint;
  263.   { extracts a file offset from an input line                                }
  264.     Var nega : boolean;
  265.   Begin                                                        { getmatchpos }
  266.     Delete(s,1,1);
  267.     nega := False;
  268.     If s[1] = '-' Then
  269.     Begin
  270.       nega := True;
  271.       Delete(s,1,1);
  272.     End;
  273.     While (s <> '') And (UpCase(s[1]) In ['0'..'9','A'..'F']) Do
  274.     Begin
  275.       matchpos := 16*matchpos + hex2num(s[1]);
  276.       Delete(s,1,1);
  277.     End;
  278.     If nega Then matchpos := testfsize - matchpos;
  279.     If matchpos < 0 Then matchpos := 0;
  280.     strip(s);
  281.   End;                                                         { getmatchpos }
  282.  
  283. Begin
  284.   getargs;
  285.   gettestfile;
  286.   openmagicfile;
  287.   match := False;
  288.   While Not (EoF(magicfile) Or match) Do
  289.   Begin
  290.     readln(magicfile,temp);
  291.     If IOResult <> 0 Then
  292.     Begin
  293.       writeln('Error reading magic number file ',mname);
  294.       Halt(5);
  295.     End;
  296.     strip(temp);
  297.     If (temp <> '') And (UpCase(temp[1]) = 'V') Then gettrans(temp,transl);
  298.     If (temp <> '') And (temp[1] = '^')         Then gettrans(temp,transu);
  299.     If (temp <> '') And (temp[1] <> '#') And (temp[1] <> ';') Then
  300.     Begin
  301.       matchpos := 0;
  302.       If temp[1] = '@' Then matchpos := getmatchpos(temp);
  303.       masklen := 0;
  304.       If temp[1] = '&' Then
  305.       Begin
  306.         Delete(temp,1,1);
  307.         getsequence(temp,maskbuff,masklen,False);
  308.         strip(temp);
  309.       End;
  310.       getsequence(temp,magic,magiclen,True);
  311.       strip(temp);
  312.       For i := masklen To Pred(magiclen) Do maskbuff[i] := $FF;
  313.       If matchpos+magiclen <= examlen Then
  314.       Begin
  315.         buffno := 0;
  316.         examstart := matchpos;
  317.       End
  318.       Else
  319.       Begin
  320.         buffno := 1;
  321.         If (matchpos < pos2) Or (matchpos+magiclen > pos2+examlen) Then
  322.         Begin
  323.           pos2 := matchpos;
  324.           If pos2+examsize > testfsize Then pos2 := testfsize - examsize;
  325.           If pos2 < 0 Then pos2 := 0;
  326.           Seek(testfile,pos2);
  327.           BlockRead(testfile,exambuff[1],examsize,examlen);
  328.         End;
  329.         examstart := matchpos - pos2;
  330.       End;
  331.       If examlen >= magiclen Then
  332.       Begin
  333.         match := True;
  334.         i := 0;
  335.         While match And (i < magiclen) Do
  336.         Begin
  337.           ctemp := char(translat[exambuff[buffno,i+examstart]]);
  338.           If nocase[i] Then match := (magic[i] =
  339.                      (translat[exambuff[buffno,i+examstart]] And maskbuff[i]))
  340.                        Else match := (magic[i] =
  341.                                (exambuff[buffno,i+examstart] And maskbuff[i]));
  342.           Inc(i);
  343.         End;
  344.       End;
  345.     End;
  346.   End;
  347.   Close(magicfile);
  348.   Close(testfile);
  349.   If Not match Then temp := 'unknown';
  350.   writeln(fname,': ',temp);
  351. End.
  352.