CnPack Forum » 技术板块灌水区 » 自己修改Zeos DBO使其支持加密的SQLite


2008-12-17 10:09 rarnu
自己修改Zeos DBO使其支持加密的SQLite

昨天提交了一些相关的代码去Source Forge,得到的结果是,对方毫不理睬,并且已经删除了我提交的代码
我尊重他们的协议,不自行发布修改后的Zeos,因此,只能将修改方法公开,以便各位自行修改。

要改的地方不是太多,大家看着我的改法,自己改一下就好了,不是很麻烦

[b]一、修改ZPlainSqLiteDriver.pas[/b]
这个文件位于\src\plain目录下

在接口IZSQLitePlainDriver内,修改Open()方法的定义
原始的定义为:[color=#0000ff]function [/color]Open([color=#0000ff]const [/color]filename: PChar; mode: Integer; [color=#0000ff]var [/color]errmsg: PChar): Psqlite;
修改为:[color=#0000ff]function [/color]Open([color=#0000ff]const [/color]filename: PChar; mode: Integer;password: PChar; [color=#0000ff]var [/color]errmsg: PChar): Psqlite;

在类TZSQLite28PlainDriver内,修改Open()方法的定义
修改方法同上,定义是一样的
在类TZSQLite3PlainDriver 内,做同样的修改

继续往下,找到 TZSQLite3PlainDriver.Open()方法,作如下修改:
原始的代码为:
[code]function TZSQLite3PlainDriver.Open(const filename: PChar; mode: Integer; var errmsg: PChar): Psqlite;

var

  Result0: Psqlite;

  Version: string;

  FileNameString: String;

begin

  Result0:= nil;

  Version := LibVersion;

  FileNameString := filename;

  {$IFNDEF VER130}

  if (Version > '3.2.5') then

    ZPlainSqLite3.sqlite_open(PAnsiChar(AnsiToUTF8(FileNameString)), Result0)

  else

  {$ENDIF}

  ZPlainSqLite3.sqlite_open(filename, Result0);

  Result := Result0;

end;[/code]

修改为:[code]function TZSQLite3PlainDriver.Open(const filename: PChar; mode: Integer; password: PChar; var errmsg: PChar): Psqlite;

var

  Result0: Psqlite;

  Version: string;

  FileNameString: String;

begin

  Result0:= nil;

  Version := LibVersion;

  FileNameString := filename;

  {$IFNDEF VER130}

  if (Version > '3.2.5') then

    ZPlainSqLite3.sqlite_open(PAnsiChar(AnsiToUTF8(FileNameString)), Result0)

  else

  {$ENDIF}

  ZPlainSqLite3.sqlite_open(filename, Result0);

  Result := Result0;

  if password <> EmptyStr then                                                     <--  此处修改

    ZPlainSqLite3.sqlite_key(Result0, password, Length(password));

end;[/code]

[b]二、修改ZDbcSqLite.pas[/b]
这个文件位于\src\dbc目录下

找到TZSQLiteConnection.Open()方法,作如下修改:
原始代码为:[code]procedure TZSQLiteConnection.Open;

var

  ErrorCode: Integer;

  ErrorMessage: PChar;

  LogMessage: string;

  SQL: string;

begin

  if not Closed then Exit;

  ErrorMessage := '';

  LogMessage := Format('CONNECT TO "%s" AS USER "%s"', [Database, User]);

  FHandle := FPlainDriver.Open(PChar(Database), 0, ErrorMessage);

  if FHandle = nil then

  begin

    CheckSQLiteError(FPlainDriver, SQLITE_ERROR, ErrorMessage,  lcConnect, LogMessage);

  end;

  DriverManager.LogMessage(lcConnect, FPlainDriver.GetProtocol, LogMessage);

  { Turn on encryption if requested }

  if StrToBoolEx(Info.Values['encrypted']) then

  begin

    ErrorCode := FPlainDriver.Key(FHandle, PChar(Password), StrLen(PChar(Password)));

    CheckSQLiteError(FPlainDriver, ErrorCode, ErrorMessage, lcConnect, 'SQLite.Key');

  end;

  try

    SQL := 'PRAGMA show_datatypes = ON';

    ErrorCode := FPlainDriver.Execute(FHandle, PChar(SQL),  nil, nil, ErrorMessage);

    CheckSQLiteError(FPlainDriver, ErrorCode, ErrorMessage, lcExecute, SQL);

{

         SQL := 'PRAGMA empty_result_callbacks = ON';

         ErrorCode := FPlainDriver.Execute(FHandle, PChar(SQL),

           nil, nil, ErrorMessage);

         CheckSQLiteError(FPlainDriver, ErrorCode, ErrorMessage, lcExecute, SQL);

}

    StartTransactionSupport;

  except

    FPlainDriver.Close(FHandle);

    FHandle := nil;

    raise;

  end;

  inherited Open;

end;[/code]

修改为:[code]procedure TZSQLiteConnection.Open;

var

  ErrorCode: Integer;

  ErrorMessage: PChar;

  LogMessage: string;

  SQL: string;

begin

  if not Closed then Exit;

  ErrorMessage := '';

  LogMessage := Format('CONNECT TO "%s" AS USER "%s"', [Database, User]);

  FHandle := FPlainDriver.Open(PChar(Database), 0, PChar(Password), ErrorMessage);           <--  此处修改

  if FHandle = nil then

  begin

    CheckSQLiteError(FPlainDriver, SQLITE_ERROR, ErrorMessage,  lcConnect, LogMessage);

  end;

  DriverManager.LogMessage(lcConnect, FPlainDriver.GetProtocol, LogMessage);

  { Turn on encryption if requested }

  if StrToBoolEx(Info.Values['encrypted']) then

  begin

    ErrorCode := FPlainDriver.Key(FHandle, PChar(Password), StrLen(PChar(Password)));

    CheckSQLiteError(FPlainDriver, ErrorCode, ErrorMessage, lcConnect, 'SQLite.Key');

  end;

  try

    SQL := 'PRAGMA show_datatypes = ON';

    ErrorCode := FPlainDriver.Execute(FHandle, PChar(SQL),  nil, nil, ErrorMessage);

    CheckSQLiteError(FPlainDriver, ErrorCode, ErrorMessage, lcExecute, SQL);



{

         SQL := 'PRAGMA empty_result_callbacks = ON';

         ErrorCode := FPlainDriver.Execute(FHandle, PChar(SQL),

           nil, nil, ErrorMessage);

         CheckSQLiteError(FPlainDriver, ErrorCode, ErrorMessage, lcExecute, SQL);

}



    StartTransactionSupport;

  except

    FPlainDriver.Close(FHandle);

    FHandle := nil;

    raise;

  end;

  inherited Open;

end;[/code[]



三、修改ZDbcSqliteUtils.pas

这个文件位于\src\dbc目录下



找到ConvertSQLiteTypeToSQLType()法,作如下修改:

原始代码为:[code]

function ConvertSQLiteTypeToSQLType(TypeName: string; var Precision: Integer;

  var Decimals: Integer): TZSQLType;

var

  P1, P2: Integer;

  Temp: string;

begin

  TypeName := UpperCase(TypeName);

  Result := stString;

  Precision := 0;

  Decimals := 0;



  P1 := Pos('(', TypeName);

  P2 := Pos(')', TypeName);

  if (P1 > 0) and (P2 > 0) then

  begin

    Temp := Copy(TypeName, P1 + 1, P2 - P1 - 1);

    TypeName := Copy(TypeName, 1, P1 - 1);

    P1 := Pos(',', Temp);

    if P1 > 0 then

    begin

      Precision := StrToIntDef(Copy(Temp, 1, P1 - 1), 0);

      Decimals := StrToIntDef(Copy(Temp, P1 + 1, Length(Temp) - P1), 0);

    end else

      Precision := StrToIntDef(Temp, 0);

  end;



  if StartsWith(TypeName, 'BOOL') then

    Result := stBoolean

  else if TypeName = 'TINYINT' then

    Result := stByte

  else if TypeName = 'SMALLINT' then

    Result := stShort

  else if TypeName = 'MEDIUMINT' then

    Result := stInteger

  else if StartsWith(TypeName, 'INT') then

    Result := stInteger

  else if TypeName = 'BIGINT' then

    Result := stLong

  else if StartsWith(TypeName, 'REAL') then

    Result := stDouble

  else if StartsWith(TypeName, 'FLOAT') then

    Result := stDouble

  else if (TypeName = 'NUMERIC') or (TypeName = 'DECIMAL')

    or (TypeName = 'NUMBER') then

  begin

   { if Decimals = 0 then

      Result := stInteger

    else} Result := stDouble;

  end

  else if StartsWith(TypeName, 'DOUB') then

    Result := stDouble

  else if TypeName = 'MONEY' then

    Result := stBigDecimal

  else if StartsWith(TypeName, 'CHAR') then

    Result := stString

  else if TypeName = 'VARCHAR' then

    Result := stString

  else if TypeName = 'VARBINARY' then

    Result := stBytes

  else if TypeName = 'BINARY' then

    Result := stBytes

  else if TypeName = 'DATE' then

    Result := stDate

  else if TypeName = 'TIME' then

    Result := stTime

  else if TypeName = 'TIMESTAMP' then

    Result := stTimestamp

  else if TypeName = 'DATETIME' then

    Result := stTimestamp

  else if Pos('BLOB', TypeName) > 0 then

    Result := stBinaryStream

  else if Pos('CLOB', TypeName) > 0 then

    Result := stAsciiStream

  else if Pos('TEXT', TypeName) > 0 then

    Result := stAsciiStream;



  if (Result = stInteger) and (Precision <> 0) then

  begin

    if Precision <= 2 then

      Result := stByte

    else if Precision <= 4 then

      Result := stShort

    else if Precision <= 9 then

      Result := stInteger

    else Result := stLong;

  end;



  if (Result = stString) and (Precision = 0) then

    Precision := 256;

end;[/code]

修改为:[code]function ConvertSQLiteTypeToSQLType(TypeName: string; var Precision: Integer;

  var Decimals: Integer): TZSQLType;

var

  P1, P2: Integer;

  Temp: string;

begin

  TypeName := UpperCase(TypeName);

  Result := stString;

  Precision := 0;

  Decimals := 0;



  P1 := Pos('(', TypeName);

  P2 := Pos(')', TypeName);

  if (P1 > 0) and (P2 > 0) then

  begin

    Temp := Copy(TypeName, P1 + 1, P2 - P1 - 1);

    TypeName := Copy(TypeName, 1, P1 - 1);

    P1 := Pos(',', Temp);

    if P1 > 0 then

    begin

      Precision := StrToIntDef(Copy(Temp, 1, P1 - 1), 0);

      Decimals := StrToIntDef(Copy(Temp, P1 + 1, Length(Temp) - P1), 0);

    end else

      Precision := StrToIntDef(Temp, 0);

  end;



  if StartsWith(TypeName, 'BOOL') then

    Result := stBoolean

  else if TypeName = 'TINYINT' then

    Result := stByte

  else if TypeName = 'SMALLINT' then

    Result := stShort

  else if TypeName = 'MEDIUMINT' then

    Result := stInteger

  else if StartsWith(TypeName, 'INT') then

    Result := stInteger

  else if TypeName = 'BIGINT' then

    Result := stLong

  else if StartsWith(TypeName, 'REAL') then

    Result := stDouble

  else if StartsWith(TypeName, 'FLOAT') then

    Result := stDouble

  else if (TypeName = 'NUMERIC') or (TypeName = 'DECIMAL')

    or (TypeName = 'NUMBER') then

  begin

   { if Decimals = 0 then

      Result := stInteger

    else} Result := stDouble;

  end

  else if StartsWith(TypeName, 'DOUB') then

    Result := stDouble

  else if TypeName = 'MONEY' then

    Result := stBigDecimal

  else if StartsWith(TypeName, 'CHAR') then

    Result := stString

  else if TypeName = 'VARCHAR' then

    Result := stString

  else if TypeName = 'VARBINARY' then

    Result := stBytes

  else if TypeName = 'BINARY' then

    Result := stBytes

  else if TypeName = 'DATE' then

    Result := stDate

  else if TypeName = 'TIME' then

    Result := stTime

  else if TypeName = 'TIMESTAMP' then

    Result := stTimestamp

  else if TypeName = 'DATETIME' then

    Result := stTimestamp

  else if Pos('BLOB', TypeName) > 0 then

    Result := stBinaryStream

  else if Pos('CLOB', TypeName) > 0 then

    Result := stAsciiStream

  else if Pos('TEXT', TypeName) > 0 then

    Result := stString;                                                 <--  此处修改



  if (Result = stInteger) and (Precision <> 0) then

  begin

    if Precision <= 2 then

      Result := stByte

    else if Precision <= 4 then

      Result := stShort

    else if Precision <= 9 then

      Result := stInteger

    else Result := stLong;

  end;



  if (Result = stString) and (Precision = 0) then

    Precision := 4096;                                               <--  此处修改

end;[/code]

四、保存修改,编译,安装
经过修改的Zeos即可支持加密的SQLite数据库,示例代码如下:[code]ZConnection1.Password := 'sa';

ZConnection1.Connect;

ZTable1.TableName := 'Employees';

ZTable1.Open;[/code]

[[i] 本帖最后由 rarnu 于 2008-12-17 10:22 编辑 [/i]]

2008-12-17 23:23 lixupeng
不懂纯支持下:victory:

2009-6-2 11:08 jAmEs_
好像有用~~~不過不是很理解為何SF不接受這個修改:)

[[i] 本帖最後由 jAmEs_ 於 2009-6-2 12:09 編輯 [/i]]

2009-6-2 14:03 kendling
发布协议的问题吧?

2009-6-3 09:38 jAmEs_
什麽概念?

2009-8-28 17:47 ouyongke
:loveliness:
橙子!   橙子大大的贴不顶就太不仗义啦!

2009-12-14 11:14 yinque
不用这么麻烦
在创建一个TZConnection时, 只要Properties属性置为"encrypted=true", 那么ZerosDBO会自动按加密方式去访问sqlite
但运行会出错: 'Access violation at address 00000000.read of address 00000000'
只要把  ZDbcSqiliteutils.pas 中的   PlainDriver.FreeMem(ErrorMessage);    注释掉即可

2009-12-14 11:20 yinque
上指 ZeosDBO 6.64
这个版本应该是几年前就有了
不过到现在也没更新的版本

页: [1]


Powered by Discuz! Archiver 5.0.0  © 2001-2006 Comsenz Inc.