📄 unitclasspush.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 + -