Thursday, March 25, 2010

How to get archive type

Have you ever find yourself in need to get the type of a archive? I don't know about you but I found myself in this situation a few times, therefore last time I said: That's enough lemme write a unit which does just that, 169 lines of code does exactly what I need and it does very well, I can now detect 12 archive types of most used compression routines.
As most of you know, each file type has some signature in the header(first few bytes in the file). Without anymore chit-chat here's the source that makes it all happen:
uDGArchiveType.pas
{******************************************************************************}
{                                                                              }
{   Unit: uDGArchiveType.pas                                                   }
{                                                                              }
{   Scope: archive type detection                                              }
{                                                                              }
{   Copyright© Dorin Duminica                                                  }
{                                                                              }
{******************************************************************************}
unit uDGArchiveType;

interface

uses
  SysUtils,
  Classes;

type
  TDGArchiveSignature = type Cardinal;

const
  szDGArchiveSignature = SizeOf(TDGArchiveSignature);

type
  TDGArchiveType = (
    atUnknown,
    atZip,
    atGZip,
    atCab,
    atRar,
    at7Zip,
    atBZip2,
    atARC,
    atQuad,
    atTar,
    atPAQ,
    atPEA);

type
  TDGArchiveTypeRec = record
    ArchiveType: TDGArchiveType;
    Signature: TDGArchiveSignature;
    Name: string;
  end; // TDGArchiveTypeRec = record

const
  CARCHIVESIGNATURE_UNKNOWN = 0;
  CARCHIVESIGNATURE_ZIP = $04034B50; // 0x04034B50
  CARCHIVESIGNATURE_GZIP = $08088B1F; // 0x08088B1F
  CARCHIVESIGNATURE_CAB = $4643534D; // 0x4643534D
  CARCHIVESIGNATURE_RAR = $21726152; // 0x21726152
  CARCHIVESIGNATURE_7ZIP = 2948364855;
  CARCHIVESIGNATURE_BZIP2 = $39685A42; // 0x39685A42
  CARCHIVESIGNATURE_ARC = $01437241; // 0x01437241
  CARCHIVESIGNATURE_QUAD = $0002A1BA; // 0x0002A1BA
  CARCHIVESIGNATURE_TAR = $65706957; // 0x65706957
  CARCHIVESIGNATURE_PAQ = $38716170; // 0x38716170
  CARCHIVESIGNATURE_PEA = $130001EA; // 0x130001EA

const
  CARCHIVENAME_UNKNOWN = 'Unknown';
  CARCHIVENAME_ZIP = 'Zip';
  CARCHIVENAME_GZIP = 'GZip';
  CARCHIVENAME_CAB = 'Cabinet';
  CARCHIVENAME_RAR = 'Rar';
  CARCHIVENAME_7ZIP = '7Zip';
  CARCHIVENAME_BZIP2 = 'BZip2';
  CARCHIVENAME_ARC = 'Arc';
  CARCHIVENAME_QUAD = 'Quad/Balz';
  CARCHIVENAME_TAR = 'Tar';
  CARCHIVENAME_PAQ = 'PAQ';
  CARCHIVENAME_PEA = 'PEA';

const
  CARCHIVE_COUNT = 12;

const
  CARCHIVE_TYPES: array[0..CARCHIVE_COUNT -1] of TDGArchiveTypeRec = (
    (ArchiveType: atUnknown; Signature: 0; Name: CARCHIVENAME_UNKNOWN),
    (ArchiveType: atZip; Signature: CARCHIVESIGNATURE_ZIP; Name: CARCHIVENAME_ZIP),
    (ArchiveType: atGZip; Signature: CARCHIVESIGNATURE_GZIP; Name: CARCHIVENAME_GZIP),
    (ArchiveType: atCab; Signature: CARCHIVESIGNATURE_CAB; Name: CARCHIVENAME_CAB),
    (ArchiveType: atRar; Signature: CARCHIVESIGNATURE_RAR; Name: CARCHIVENAME_RAR),
    (ArchiveType: at7Zip; Signature: CARCHIVESIGNATURE_7ZIP; Name: CARCHIVENAME_7ZIP),
    (ArchiveType: atBZip2; Signature: CARCHIVESIGNATURE_BZIP2; Name: CARCHIVENAME_BZIP2),
    (ArchiveType: atARC; Signature: CARCHIVESIGNATURE_ARC; Name: CARCHIVENAME_ARC),
    (ArchiveType: atQuad; Signature: CARCHIVESIGNATURE_QUAD; Name: CARCHIVENAME_QUAD),
    (ArchiveType: atTar; Signature: CARCHIVESIGNATURE_TAR; Name: CARCHIVENAME_TAR),
    (ArchiveType: atPAQ; Signature: CARCHIVESIGNATURE_PAQ; Name: CARCHIVENAME_PAQ),
    (ArchiveType: atPEA; Signature: CARCHIVESIGNATURE_PEA; Name: CARCHIVENAME_PEA)
  ); // CARCHIVE_TYPES: array[0..CARCHIVE_COUNT -1] of TDGArchiveTypeRec = (

function GetArchiveSignature(const FileName: string): TDGArchiveSignature; OVERLOAD;
function GetArchiveSignature(Stream: TStream): TDGArchiveSignature; OVERLOAD;
function GetArchiveTypeRec(Signature: TDGArchiveSignature): TDGArchiveTypeRec;
function GetArchiveType(const FileName: string): TDGArchiveType; OVERLOAD;
function GetArchiveType(Strean: TStream): TDGArchiveType; OVERLOAD;
function GetArchiveName(const FileName: string): string; OVERLOAD;
function GetArchiveName(Stream: TStream): string; OVERLOAD;
function GetArchiveTypeSignature(ArchiveType: TDGArchiveType): TDGArchiveSignature;

implementation

function GetArchiveSignature(Stream: TStream): TDGArchiveSignature;
begin
  Result := CARCHIVESIGNATURE_UNKNOWN;
  if Stream.Size >= szDGArchiveSignature then begin
    Stream.Position := 0;
    Stream.ReadBuffer(Result, szDGArchiveSignature);
  end; // if Stream.Size >= szDGArchiveSignature then begin
end; // function GetArchiveSignature(Stream: TStream): TDGArchiveSignature;

function GetArchiveSignature(const FileName: string): TDGArchiveSignature;
var
  ArchiveStream: TFileStream;
begin
  try
    ArchiveStream := TFileStream.Create(FileName, fmOpenRead or fmShareExclusive);
    Result := GetArchiveSignature(ArchiveStream);
  finally
    FreeAndNil(ArchiveStream);
  end; // try ... finally
end; // function GetArchiveSignature(const FileName: string): TDGArchiveSignature;

function GetArchiveTypeRec(Signature: TDGArchiveSignature): TDGArchiveTypeRec;
var
  Index: Integer;
begin
  Result := CARCHIVE_TYPES[CARCHIVESIGNATURE_UNKNOWN];
  for Index := Low(CARCHIVE_TYPES) to High(CARCHIVE_TYPES) do
    if CARCHIVE_TYPES[Index].Signature = Signature then begin
      Result := CARCHIVE_TYPES[Index];
      Exit;
    end; // if CARCHIVE_TYPES[Index].Signature = Signature then begin
end; // function GetArchiveTypeRec(Signature: TDGArchiveSignature): TDGArchiveTypeRec;

function GetArchiveType(const FileName: string): TDGArchiveType;
begin
  Result := GetArchiveTypeRec(GetArchiveSignature(FileName)).ArchiveType;
end; // function GetArchiveType(const FileName: string): TDGArchiveType;

function GetArchiveType(Strean: TStream): TDGArchiveType;
begin
  Result := GetArchiveTypeRec(GetArchiveSignature(Strean)).ArchiveType;
end; // function GetArchiveType(Strean: TStream): TDGArchiveType;

function GetArchiveName(const FileName: string): string;
begin
  Result := GetArchiveTypeRec(GetArchiveSignature(FileName)).Name;
end; // function GetArchiveName(const FileName: string): string;

function GetArchiveName(Stream: TStream): string;
begin
  Result := GetArchiveTypeRec(GetArchiveSignature(Stream)).Name;
end; // function GetArchiveName(Stream: TStream): string;

function GetArchiveTypeSignature(ArchiveType: TDGArchiveType): TDGArchiveSignature;
var
  Index: Integer;
begin
  Result := CARCHIVESIGNATURE_UNKNOWN;
  for Index := Low(CARCHIVE_TYPES) to High(CARCHIVE_TYPES) do
    if CARCHIVE_TYPES[Index].ArchiveType = ArchiveType then begin
      Result := CARCHIVE_TYPES[Index].Signature;
      Exit;
    end; // if CARCHIVE_TYPES[Index].ArchiveType = ArchiveType then begin
end; // function GetArchiveTypeSignature(ArchiveType: TDGArchiveType): TDGArchiveSignature;

end. // unit uDGArchiveType;
Usage:
add a button and a OpenDialog on the form, rename OpenDialog1 to OpenDialog, double-click the button and add this code:
  if OpenDialog.Execute then
    ShowMessage(GetArchiveName(OpenDialog.FileName));
The rest is up to you, have fun!
P.S. If you know any other archive signatures please let me know, I will update this unit and make it available to other people.

2 comments:

Blogroll(General programming and Delphi feeds)