⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unitclasspush.pas

📁 本代码实现在bmp中隐藏文件的功能
💻 PAS
字号:

{*******************************************************}
{                                                       }
{       eulB's 魔法BMP                                  }
{                                                       }
{       隐藏文件类                                      }
{                                                       }
{       2001年10月20日                                  }
{                                                       }
{*******************************************************}

unit unitClassPush;

interface

uses
  windows,Gauges,unitClass,SysUtils;

const
  NONE_MOD=0;  //没有余数,即3 bytes->  bits
  ONE_MOD=1;   //余数为1,即1 bytes->  bits
  TWO_MOD=2;   //余数为2,即2 bytes-> bits
  PUSH_HI=0;
  PUSH_NORMAL=1;

//隐藏文件类
type
  TPush=class(Tprocfunc)
    private
      FPsw,
      FBMPName,
      FFileName: string;
      FGauge:TGauge;
      procedure FPush(filename:pchar;bmpname:pchar;pb:TGauge);
      procedure FPush_Hi(filename:pchar;bmpname:pchar;pb:TGauge);
      procedure FBytes2Bits(bytes: array of byte;var bits: array of byte;Flag:integer);
      procedure FPush2RGB(var p_byte_bufs: array of byte;f_bit_buf:byte;Flag:integer);
      procedure FAddPassword(bmpfile:string;Password:string);
      procedure FSetBMPName(value: string);
      procedure FSetFileName(value:string);
      procedure FSetPsw(value: string);
      procedure FSetGauge(value:TGauge);
    public
      constructor create;
      procedure Push;
      procedure BMPBackup;          //文件备份
      procedure DelHidedFile;       //隐藏后删除文件
      function FileHided: Boolean;  //是否已有隐藏文件
      function BMPSize:integer;
      function MaxHideFileSize:integer;
      function Validate: Boolean;   //检查选择BMP文件的合法性
      function IsFileCanBePushed(Flag: Integer) :Boolean;
    published
      property BMPName: string write FSetBMPName;
      property FileName: string write FSetFileName;
      property Password: string write FSetPsw;
      property GaugeInstance: TGauge write FSetGauge;
  end;

implementation

uses
  Dialogs;
constructor TPush.create;
begin
  FPsw:='no password';
end;

procedure TPush.FSetBMPName(value: string);
begin
  FBMPName:=value;
end;

procedure TPush.FSetFileName(value:string);
begin
  FFileName:=value;
end;

procedure TPush.FSetPsw(value: string);
begin
  FPsw:=value;
end;

procedure TPush.FSetGauge(value:TGauge);
begin
  FGauge:=value;
end;

function TPush.FileHided: Boolean;
begin
  result:=false;
  if GetBMPInfo(FBMPName,BMPFilePushed) = 'J' then
  begin
    result:=true;
  end;
end;

procedure TPush.FPush(filename:pchar;bmpname:pchar;pb:TGauge);
var
  f,b:hfile;
  i:integer;
  file_len,len:longint;
  byte_buf:byte;
  byte_bufs:array[0..7] of byte;
begin
  pb.MinValue :=0;
  pb.Visible :=true;
  b:=_lopen(bmpname,OF_READWRITE);
  f:=_lopen(filename,OF_READ);
  len:=0;  // 一定要初始化,否则会莫名其妙的出错!!!

  //将被隐藏文件长度写入图像头部偏移2处
  file_len:=GetFileSize(filename);
  pb.MaxValue :=file_len;
  _llseek(b,2,0);
  _lwrite(b,@file_len,4); //@file_len即可,不必@(pchar(file_len))

  //定位读写指针到图像的位图阵列开始处
  _llseek(b,strtoint(GetBMPInfo(bmpname,BMPDataOffset))+24,0);

  //开始拆分并覆盖bmp
  while(len<file_len) do
  begin
    _lread(f,@byte_buf,1);
    inc(len);
    pb.Progress :=len;
    _lread(b,@byte_bufs,8);
    for i:=0 to 7 do
      if (byte_buf and mask[i]) >i then
        byte_bufs[i]:=byte_bufs[i] or 1      //说明byte_buf的第i+1位是1
      else
        byte_bufs[i]:=byte_bufs[i] and $FE;  //说明byte_buf的第i+1位是0
    _llseek(b,-8,FILE_CURRENT);
    for i:=0 to 7 do _lwrite(b,@byte_bufs[i],1);
  end;
  _lclose(f);
  _lclose(b);
  pb.Visible :=false;
end;

procedure TPush.FBytes2Bits(bytes: array of byte;var bits: array of byte;Flag: integer);
begin
  case Flag of
    NONE_MOD:
    begin
      bits[0]:= bytes[0] shr 2;
      bits[1]:=(bytes[0] and 3)  shl 4;
      bits[1]:= bits[1]  or (bytes[1] shr 4);
      bits[2]:=(bytes[1] and 15) shl 2;      //15-00001111
      bits[2]:= bits[2]  or (bytes[2] shr 6);
      bits[3]:= bytes[2] and 63;             //63-00111111
    end;
    ONE_MOD:
    begin
      bits[0]:= bytes[0] shr 2;
      bits[1]:= bytes[0] and 3;             
    end;
    TWO_MOD:
    begin
      bits[0]:= bytes[0] shr 2;
      bits[1]:=(bytes[0] and 3) shl 4;
      bits[1]:= bits[1]  or (bytes[1] shr 4);
      bits[2]:= bytes[1] and $0F;             
    end;
  end;
end;

procedure TPush.FPush2RGB(var p_byte_bufs: array of byte;f_bit_buf: byte;Flag:integer);
const
  R=0;
  G=1;
  B=2;
begin
  case Flag of
  NONE_MOD:
  begin
    //R分量    可改变两个分量
    p_byte_bufs[R]:=p_byte_bufs[R] and $FC;    //D0、D1
    p_byte_bufs[R]:=p_byte_bufs[R] or  (f_bit_buf and 3);

    //G分量    可改变一个分量
    p_byte_bufs[G]:=p_byte_bufs[G] and $FE;    //D2
    p_byte_bufs[G]:=p_byte_bufs[G] or  ((f_bit_buf and 4) shr 2);

    //B分量    可改变三个分量
    p_byte_bufs[B]:=p_byte_bufs[B] and $F8;
    p_byte_bufs[B]:=p_byte_bufs[B] or  ((f_bit_buf and $38) shr 3);
  end;
  ONE_MOD:   //f_bit_buf只有低2位有效 000000xx,所以正好放入R分量
    begin
      p_byte_bufs[R]:=p_byte_bufs[R] and $FC;    //D0、D1
      p_byte_bufs[R]:=p_byte_bufs[R] or  f_bit_buf;
    end;
  TWO_MOD:   //f_bit_buf低4位有效
    begin
      //R
      p_byte_bufs[R]:=p_byte_bufs[R] and $FC;    //D0、D1
      p_byte_bufs[R]:=p_byte_bufs[R] or  (f_bit_buf and 3);
      //G分量
      p_byte_bufs[G]:=p_byte_bufs[G] and $FE;    //D2
      p_byte_bufs[G]:=p_byte_bufs[G] or  ((f_bit_buf and 4) shr 2);
      //B分量
      p_byte_bufs[B]:=p_byte_bufs[B] and $FE;
      p_byte_bufs[B]:=p_byte_bufs[B] or  (f_bit_buf and 8);
    end;
  end;
end;

procedure TPush.FPush_Hi(filename:pchar;bmpname:pchar;pb:TGauge);
var
  f,p: hfile;
  i: integer;
  file_len,len: integer;
  f_byte_bufs: array[0..2] of byte;
  f_bit_bufs:  array[0..3] of byte;
  p_byte_bufs: array[0..2] of byte;
begin
  pb.MinValue :=0;
  pb.Visible :=true;
  p:=_lopen(bmpname,OF_READWRITE);
  f:=_lopen(filename,OF_READ);
  len:=0;

  //将被隐藏文件长度写入图像头部偏移2处
  file_len:=GetFileSize(filename);
  pb.MaxValue :=file_len div 3;
  _llseek(p,2,0);
  _lwrite(p,@file_len,4);

  //定位读写指针到图像的位图阵列+28处
  _llseek(p,strtoint(GetBMPInfo(bmpname,BMPDataOffset))+24,0);

  //开始拆分并覆盖bmp
  file_len:=file_len div 3;
  while (len<file_len ) do
  begin
    inc(len);
    pb.Progress :=len;
    _lread(f,@f_byte_bufs,3);
    FBytes2bits(f_byte_bufs,f_bit_bufs,NONE_MOD);
    for i:=0 to 3 do
    begin
      _lread(p,@p_byte_bufs,3);
      FPush2RGB(p_byte_bufs,f_bit_bufs[i],NONE_MOD);
      //操作完毕,写入BMP图像文件中去
      _llseek(p,-3,FILE_CURRENT);
      _lwrite(p,@p_byte_bufs,3);
    end;
  end;

  case (GetFileSize(filename) mod 3) of
  1:
  begin
    _lread(f,@f_byte_bufs,1);                       //余1,所以f_bit_bufs[0]、f_bit_bufs[1]有效
    FBytes2bits(f_byte_bufs,f_bit_bufs,ONE_MOD);
    _lread(p,@p_byte_bufs,3);
    FPush2RGB(p_byte_bufs,f_bit_bufs[0],NONE_MOD);
    _llseek(p,-3,FILE_CURRENT);
    _lwrite(p,@p_byte_bufs,3);

    _lread(p,@p_byte_bufs,1);                       //只要读入1byte就够了
    FPush2RGB(p_byte_bufs,f_bit_bufs[1],ONE_MOD); //因为f_bit_bufs[1]只有低二位有效
    _llseek(p,-1,FILE_CURRENT);
    _lwrite(p,@p_byte_bufs,1);
  end;
  2:
    begin
      _lread(f,@f_byte_bufs,2);
      FBytes2bits(f_byte_bufs,f_bit_bufs,TWO_MOD);
      for i:=0 to 1 do                            //因为f_bit_bufs[0]、f_bit_bufs[1]都有效
      begin
        _lread(p,@p_byte_bufs,3);
        FPush2RGB(p_byte_bufs,f_bit_bufs[i],NONE_MOD);
        _llseek(p,-3,FILE_CURRENT);
        _lwrite(p,@p_byte_bufs,3);
      end;
        _lread(p,@p_byte_bufs,3);
        FPush2RGB(p_byte_bufs,f_bit_bufs[2],TWO_MOD);
        _llseek(p,-3,FILE_CURRENT);
        _lwrite(p,@p_byte_bufs,3);  //f_bit_bufs[2]只有低4位有效
    end;
  end;
  _lclose(f);
  _lclose(p);
  pb.Visible :=false;
end;

procedure TPush.FAddPassword(bmpfile:string;Password:string);
var
  p: hfile;
  i: integer;
  psw_bit_bufs:  array[0..4] of byte;
  psw_byte_bufs,p_byte_bufs: array[0..3] of byte;
begin
  if Length(Password) <> 6 then      //不满6位,用space补足
    for i:=1 to 6-Length(Password) do
      Password:=Password+chr($20);
  p:=_lopen(pchar(bmpfile),OF_READWRITE);
  //定位致图像阵列开始处
  _llseek(p,strtoint(GetBMPInfo(bmpfile,BMPDataOffset)),0);
  for i:=0 to 2 do psw_byte_bufs[i]:=ord(password[i+1]);
  FBytes2bits(psw_byte_bufs,psw_bit_bufs,NONE_MOD);
  for i:=0 to 3 do
  begin
    _lread(p,@p_byte_bufs,3);
    FPush2RGB(p_byte_bufs,psw_bit_bufs[i],NONE_MOD);
    //写入BMP
    _llseek(p,-3,FILE_CURRENT);
    _lwrite(p,@p_byte_bufs,3);
  end;
  for i:=0 to 2 do psw_byte_bufs[i]:=ord(password[i+4]);
  FBytes2bits(psw_byte_bufs,psw_bit_bufs,NONE_MOD);
  for i:=0 to 3 do
  begin
    _lread(p,@p_byte_bufs,3);
    FPush2RGB(p_byte_bufs,psw_bit_bufs[i],NONE_MOD);
    //写入BMP
    _llseek(p,-3,FILE_CURRENT);
    _lwrite(p,@p_byte_bufs,3);
  end;
  _lclose(p);
end;

procedure TPush.DelHidedFile;
begin
  DeleteFile(FFileName);
end;

procedure TPush.BMPBackup;
begin
  //文件的备份,注:ChangeFileExt()并不真正改变文件的扩展名,只是生成一个string
  CopyFile(pchar(FBMPName),pchar(ChangeFileExt(FBMPName,'.bak')+'.bmp'),true);
end;

function TPush.BMPSize:integer;
begin
  result:=GetFileSize(FBMPName) div 1024;
end;

function TPush.MaxHideFileSize:integer;
begin
  result:=((GetFileSize(FBMPName)-strtoint(GetBMPInfo(FBMPName,BMPDataOffset))-
      length(ExtractFileName(FBMPName))*8-48) div 8) div 1024
end;

function TPush.Validate: Boolean;
begin
  result:=true;
  //是24位真彩色的BMP吗?
  if strtoint(GetBMPInfo(FBMPName,BMPBitsperPixel))<> 24 then
  begin
    result:=false;
  end;
end;

function TPush.IsFileCanBePushed(Flag: Integer):Boolean;
begin
  case Flag of
  PUSH_HI:
    begin
      result:=true;
      if (GetFileSize(FFileName) div 3)*12 > (GetFileSize(FBMPName)-
        strtoint(GetBMPInfo(FBMPName,BMPDataOffset))-
        length(ExtractFileName(FFileName))*8 -
        24 - 9)            //24-密码占有字节数  9-若 file_len Mod 3=2,则还须额外
      then result:=false;  //占用9个字节
    end;
  PUSH_NORMAL:  
    begin
      result:=true;
      if GetFileSize(FFileName)*8 > (GetFileSize(FBMPName)-
        strtoint(GetBMPInfo(FBMPName,BMPDataOffset))-
        length(ExtractFileName(FFileName))*8-48) then
        result:=false;
    end;
  end;
end;

procedure TPush.Push;
begin
  try
    //由于可能要覆盖曾经有过隐藏文件的BMP,所以不管如何,
    //总要先置密码保护为"否",即消除7H的'P'标志
    SetBMPFlag(FBMPName,UN_BMPFilePswAdded);

    //标志bmp文件为已有隐藏文件在内
    SetBMPFlag(FBMPName,BMPFilePushed);

    //开始压入
    FPush_Hi(pchar(FFileName),pchar(FBMPName),FGauge);

    //写人文件名
    AddFileName(FBMPName,ExtractFileName(FFileName));

   //写入密码
    if FPsw <> 'no password' then
    begin
      SetBMPFlag(FBMPName,BMPFilePswAdded);//置有密码设置标志
      FAddPassword(FBMPName,FPsw);
    end;
except
  on E:Exception do raise e.Create(e.Message);
end;
end;

end.


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -