www.pudn.com > srmsrc.zip > SrmUnit.pas


//--------------------------------------------------------------------------- 
//(R)CopyRight KivenSoft International ,inc 1999 
//单元名称:数据库单元 
//程序名称:电子书库 
//作    者:李会文 
//开始时间:1998.07.28 
//最后修改:1999.07.22 
//备注:此单元定义了SRM文件的读写接口 
//--------------------------------------------------------------------------- 
unit SrmUnit; 
 
interface 
 
uses 
  Windows,SysUtils,Classes, SrmConst; 
 
 
type 
PCharArray=^TCharArray; 
TCharArray=array[0..0] of char; 
PDwordArray=^TDwordArray; 
TDwordArray=array[0..0] of DWORD; 
PIntArray=^TIntArray; 
TIntArray=array[0..0] of integer; 
 
PTreeData=^TTreeData; 
TTreeData=record        //索引信息 
  Pos: longint; 
  DataType: longint; 
end; 
PTdArray=^TTdArray; 
TTdArray=array[0..0] of TTreeData; 
 
PFileHead=^TFileHead; 
TFileHead=record 
  OpenFlag      :Longint;                      //数据库打开标志 
  LastViewPos   :longint;                   //关闭时的位置 
  IndexPos      :longint;                   //索引位置 
  EditDate      :TDateTime;                 //最后修改日期 
  Key           :DWORD;                     //密钥 
  Password      :array[0..11] of char;      //口令 
  Author        :array[0..15] of char;      //作者 
  BuildDate     :TDateTime;                 //建库日期 
  DataType      :longint;                   //数据库格式 
  DataFlag      :array[0..7] of char;       //数据库标志 
  Version       :longint;                   //数据库版本 
  BookMerg      :array[0..9] of longint;    //10个书签 
  Keep          :longint;                   //保留字段 
end; 
 
//DataType 0:Index    1:Normal Dir     2:Notmal TXT    3:Normal HTML 
PIndexHead=^TIndexHead; 
TIndexHead=record 
  DataType      :longint;                   //段类型 
  Key           :DWORD;                     //密钥 
  Count         :longint;                   //标题数量 
  Size          :longint;                   //标题长度 
  Keep          :longint;                   //保留字段 
end; 
 
PDataHead=^TDataHead; 
TDataHead=record 
  DataType      :longint;                   //段类型 
  Author        :array[0..15] of char;      //作者 
  PubDate       :TDateTime;                 //收录日期 
  Key           :DWORD;                     //密钥 
  Num           :longint;                   //附件数量 
  SearchKey     :array[0..51] of char;      //关键词 
  Password      :array[0..11] of char;      //口令 
  Keep          :longint;                   //保留字段 
end; 
 
//------------------------------------------------------------------------ 
TSrmObject=class 
  private 
    FChangeFlag         :boolean;   //在文件后有增加新信息的变量 
    FDbChanged          :boolean;   //数据库属性有变动 
    FIndexChanged       :boolean;   //索引有变动 
    FItemHeadChanged    :boolean;   //标题头有变动 
    FItemDataChanged    :boolean;   //标题内容有变动 
    FFileHead           :TFileHead; 
    FIndexHead          :TIndexHead; 
    FDataHead           :TDataHead; 
    FFileHandle         :integer;       //文件句柄 
    FFileName           :string; 
    FActivePos          :longint;       //当前读出内容的位置 
 
    procedure Encypher(Cypher:DWORD;var Buf;Count:integer); 
    procedure Decypher(Cypher:DWORD;var Buf;Count:integer); 
    procedure CreateSrmFile;            //建立一个空数据库 
    procedure SetDbChanged(Value:boolean); 
    procedure SetIndexChanged(Value:boolean); 
    procedure SetItemHeadChanged(Value:boolean); 
    procedure SetItemDataChanged(Value:boolean); 
  public 
    property FileName:string read FFileName; 
    property FileHead:TFileHead read FFileHead write FFileHead; 
    property IndexHead:TIndexHead read FIndexHead write FIndexHead; 
    property DataHead:TDataHead read FDataHead write FDataHead; 
    property ActivePos:longint read FActivePos write FActivePos; 
    property DbChanged:boolean read FDbChanged write SetDbChanged; 
    property IndexChanged:boolean read FIndexChanged write SetIndexChanged; 
    property ItemHeadChanged:boolean read FItemHeadChanged write SetItemHeadChanged; 
    property ItemDataChanged:boolean read FItemDataChanged write SetItemDataChanged; 
 
    constructor Create(Fn:string;Mode:Word); 
    destructor Destroy;override; 
    procedure Free; 
    procedure SaveSrmFile;          //不关闭文件情况下保存文件 
    procedure LoadIndex(Msh,Msd:TMemoryStream); //读索引 
    procedure SaveIndex(Msh,Msd:TMemoryStream);//写索引 
    class function IsSrmFile(var Fn:string):boolean;//判断是否是SRM格式数据库文件 
    procedure ReadItemHead(Ps:longint);  //读数据段头 
    procedure ReadItemData(DataStream:TMemoryStream);  //读数据段内容 
    procedure EditItemHead(Ps:longint);    //修改数据头 
    function AddItemHead:longint;          //写数据段头 
    procedure AddItemData(DataStream:TMemoryStream); //写数据段内容 
    function GetItemPassword(Ps:longint):string; //得某标题口令 
 end; 
//------------------------------------------------------------------------ 
 
 
implementation 
 
//------------------------------------------------------------------------ 
procedure TSrmObject.Encypher(Cypher:DWORD;var Buf;Count:integer); 
var 
  i:integer; 
begin 
  Cypher:=not Cypher; 
  Dec(Count); 
  for i:=0 to Count do 
    TDwordArray(Buf)[i]:=TDwordArray(Buf)[i] xor Cypher; 
end; 
 
procedure TSrmObject.Decypher(Cypher:DWORD;var Buf;Count:integer); 
var 
  i:integer; 
begin 
  Cypher:=not Cypher; 
  Dec(Count); 
  for i:=0 to Count do 
    TDwordArray(Buf)[i]:=TDwordArray(Buf)[i] xor Cypher; 
end; 
//------------------------------------------------------------------------ 
 
procedure TSrmObject.CreateSrmFile;    //建立一个空数据库 
var 
  i:integer; 
begin 
    FFileHandle:=FileCreate(FFileName); 
    if FFileHandle=-1 then raise Exception.Create(csCanNotCreate); 
    //添充缺省信息头 
    with FFileHead do 
    begin 
      OpenFlag:=0; 
      LastViewPos:=0; 
      IndexPos:=sizeof(TFileHead); 
      EditDate:=Now; 
      Key:=GetTickCount; 
      Password[0]:=#0; 
      Author[0]:=#0; 
      BuildDate:=EditDate; 
      DataType:=0; 
      Version:=3; 
      Keep:=0; 
      DataFlag[0]:='K'; 
      DataFlag[1]:='i'; 
      DataFlag[2]:='v'; 
      DataFlag[3]:='e'; 
      DataFlag[4]:='n'; 
      for i:=0 to 9 do BookMerg[i]:=-1; 
    end; 
    //添充缺省索引 
    with FIndexHead do 
    begin 
      DataType:=0; 
      Key:=GetTickCount; 
      Count:=0; 
      Size:=0; 
      Keep:=0; 
    end; 
    //加密写入文件后解密 
    with FFileHead do 
    begin 
      Encypher(Key,Author,4); 
      Encypher(Key,Password,3); 
      FileWrite(FFileHandle,FFileHead,sizeof(TFileHead)); 
      FileWrite(FFileHandle,FIndexHead,sizeof(TIndexHead)); 
      Decypher(Key,Author,4); 
      Decypher(Key,Password,3); 
    end; 
end; 
 
constructor TSrmObject.Create(Fn:string;Mode:Word); 
begin 
  FFileName:=Fn; 
  FChangeFlag:=false; 
  FDbChanged:=false; 
  FIndexChanged:=false; 
  FItemHeadChanged:=false; 
  FItemDataChanged:=false; 
  FDataHead.Keep:=0; 
  //打开文件时读文件头,否则建新文件 
  if Mode=fmOpenReadWrite then 
  begin 
    FFileHandle:=FileOpen(FFileName,fmOpenReadWrite); 
    FileRead(FFileHandle,FFileHead,sizeof(TFileHead)); 
    with FFileHead do 
    begin 
      Decypher(Key,Password,3); 
      Decypher(Key,Author,4); 
    end; 
  end 
  else if Mode=fmCreate then 
  begin 
    CreateSrmFile; 
  end; 
end; 
 
destructor TSrmObject.Destroy; 
begin 
  if FFileHandle<>-1 then 
  begin 
    FileClose(FFileHandle);  //关闭文件 
    FFileHandle:=-1; 
  end; 
  inherited; 
end; 
 
procedure TSrmObject.Free; 
begin 
  if Assigned(self) then Destroy; 
end; 
 
procedure TSrmObject.SaveSrmFile; 
begin 
  //写入更新后的文件头 
  with FFileHead do 
  begin 
    FileSeek(FFileHandle,0,0); 
    EditDate:=Now; 
    Key:=GetTickCount; 
    Encypher(Key,Password,3); 
    Encypher(Key,Author,4); 
    FileWrite(FFileHandle,FFileHead,sizeof(TFileHead)); 
    Decypher(Key,Password,3); 
    Decypher(Key,Author,4); 
  end; 
end; 
 
class function TSrmObject.IsSrmFile(var Fn:string):boolean; 
var 
  Fh: TFileHead; 
  Fs: TFileStream; 
begin 
  Result:=false; 
  Fs:=TFileStream.Create(Fn,fmOpenRead); 
  //根据文件长度判断 
  with Fs do 
  begin 
    if (Size<(sizeof(TFileHead)+sizeof(TIndexHead))) then 
    begin 
      Free; 
      Result:=false; 
      Exit; 
    end; 
    Read(Fh,sizeof(TFileHead)); 
    Free; 
  end; 
  //根据文件标志判断 
  with Fh do 
  begin 
    if ( (DataFlag[0]='K') and (DataFlag[1]='i') and 
        (DataFlag[2]='v') and (DataFlag[3]='e') and 
        (DataFlag[4]='n') ) then 
      Result:=true; 
  end; 
end; 
 
procedure TSrmObject.LoadIndex(Msh,Msd:TMemoryStream); 
begin 
  //读出索引头 
  FileSeek(FFileHandle,FFileHead.IndexPos,0); 
  FileRead(FFileHandle,FIndexHead,sizeof(TIndexHead)); 
  //处理索引长度为0的状况,否则读出具体索引 
  if (FIndexHead.Size=0) then 
  begin 
    Msh.SetSize(0); 
    Msd.SetSize(0); 
  end 
  else 
  begin 
    Msh.SetSize(FIndexHead.Size); 
    Msd.SetSize(FIndexHead.Count*sizeof(longint)*2); 
    FileRead(FFileHandle,Msh.Memory^,Msh.Size); 
    FileRead(FFileHandle,Msd.Memory^,Msd.Size); 
    Decypher(FIndexHead.Key,Msh.Memory^,Msh.Size div 4); 
  end; 
end; 
 
procedure TSrmObject.SaveIndex(Msh,Msd:TMemoryStream); 
begin 
  if FChangeFlag then  //增加过新内容时 
    FFileHead.IndexPos:=FileSeek(FFileHandle,0,2) 
  else                 //无新增内容 
    FileSeek(FFileHandle,FFileHead.IndexPos,0); 
  //设置数据头 
  with FIndexHead do 
  begin 
    Key:=GetTickCount; 
    Size:=Msh.Size; 
    Count:=Msd.Size div (sizeof(longint)*2); 
  end; 
  //加密标题内容 
  Encypher(FIndexHead.Key,Msh.Memory^,Msh.Size div 4); 
  //写入索引 
  FileWrite(FFileHandle,FIndexHead,sizeof(TIndexHead)); 
  FileWrite(FFileHandle,Msh.Memory^,Msh.Size); 
  FileWrite(FFileHandle,Msd.Memory^,Msd.Size); 
end; 
 
procedure TSrmObject.ReadItemHead(Ps:longint); 
begin 
  FActivePos:=Ps;  //保存当前数据位置 
  //读出并解密 
  with FDataHead do 
  begin 
    FileSeek(FFileHandle,Ps,0); 
    FileRead(FFileHandle,FDataHead,sizeof(TDataHead)); 
    Decypher(Key,SearchKey,13); 
    Decypher(Key,Author,4); 
    Decypher(Key,Password,3); 
  end; 
end; 
 
procedure TSrmObject.ReadItemData(DataStream:TMemoryStream); 
var 
  size:longint; 
begin 
  //读出具体内容 
  FileRead(FFileHandle,size,sizeof(longint)); 
  DataStream.SetSize(size); 
  FileRead(FFileHandle,DataStream.Memory^,size); 
  Decypher(FDataHead.Key,DataStream.Memory^,size div 4); 
end; 
 
procedure TSrmObject.EditItemHead(Ps:longint); 
begin 
  //修改数据头 
  FileSeek(FFileHandle,Ps,0); 
  with FDataHead do 
  begin 
    Encypher(Key,SearchKey,13); 
    Encypher(Key,Author,4); 
    Encypher(Key,Password,3); 
    FileWrite(FFileHandle,FDataHead,sizeof(TDataHead)); 
    Decypher(Key,SearchKey,13); 
    Decypher(Key,Author,4); 
    Decypher(Key,Password,3); 
  end; 
end; 
 
function TSrmObject.AddItemHead:longint; 
begin 
  //新内容增加时移到文件尾添加 
  FChangeFlag:=true; 
  with FDataHead do 
  begin 
    Result:=FileSeek(FFileHandle,0,2); 
    Key:=GetTickCount; 
    PubDate:=Now; 
    Encypher(Key,SearchKey,13); 
    Encypher(Key,Author,4); 
    Encypher(Key,Password,3); 
    FileWrite(FFileHandle,FDataHead,sizeof(TDataHead)); 
    Decypher(Key,SearchKey,13); 
    Decypher(Key,Author,4); 
    Decypher(Key,Password,3); 
  end; 
end; 
 
procedure TSrmObject.AddItemData(DataStream:TMemoryStream); 
var 
  size:longint; 
begin 
  size:=DataStream.Size; 
  FileWrite(FFileHandle,size,sizeof(longint)); 
  Encypher(FDataHead.Key,DataStream.Memory^,size div 4); 
  FileWrite(FFileHandle,DataStream.Memory^,size); 
end; 
 
function TSrmObject.GetItemPassword(Ps:longint):string; //得某标题口令 
var 
  Dh:TDataHead; 
begin 
  //读出并解密 
  with Dh do 
  begin 
    FileSeek(FFileHandle,Ps,0); 
    FileRead(FFileHandle,Dh,sizeof(TDataHead)); 
    Decypher(Key,Password,3); 
  end; 
  result:=string(Dh.Password); 
end; 
 
procedure TSrmObject.SetDbChanged(Value:boolean); 
begin 
  FDbChanged:=Value; 
end; 
 
procedure TSrmObject.SetIndexChanged(Value:boolean); 
begin 
  FIndexChanged:=Value; 
  if Value then FDbChanged:=Value; 
end; 
 
procedure TSrmObject.SetItemHeadChanged(Value:boolean); 
begin 
  FItemHeadChanged:=Value; 
  if Value then 
  begin 
    FIndexChanged:=Value; 
    FDbChanged:=Value; 
  end; 
end; 
 
procedure TSrmObject.SetItemDataChanged(Value:boolean); 
begin 
  FItemDataChanged:=Value; 
  if Value then 
  begin 
    FIndexChanged:=Value; 
    FDbChanged:=Value; 
  end; 
end; 
 
 
 
end.