我一直在 Lazarus 从事一个项目,并决定暂时将其移至 Delphi XE(由于一些限制)。
简要概述正在发生的事情:
在运行时,我正在加载外部文件并将它们添加到流中。流属于从一个主要对象(TObject)派生的几个不同的类。这些类从主对象添加到 TList 中,基本上每个类都有自己的流属性,并且该类是主对象的子对象。
在这个主要对象中,我有一个保存和加载过程:
保存对象时,它还通过使用字符串流将所有来自其他类的流数据保存到文件中。此处的输出字符串必须是 base64 编码,因为我要保存到 XML。
打开文件时,想法是解码 base64 字符串并将其移回流中,就好像它是 base64 编码之前的原始文件一样。
在 Lazarus 中它可以工作,这里是重要的代码(注意,其中一些不是我写的)。
const
Keys64 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/';
function Encode64String(S: string): string;
function Decode64String(S: string): string;
function Encode64StringToStream(const Input: TStream; var Output: string): Boolean;
procedure Decode64StringToStream(const Input: string; Output: TStream);
procedure StringToStream(Stream: TStream; const S: string);
function StreamToString(MS: TMemoryStream): string;
implementation
function Encode64String(S: string): string;
var
i: Integer;
a: Integer;
x: Integer;
b: Integer;
begin
Result := '';
a := 0;
b := 0;
for i := 1 to Length(s) do
begin
x := Ord(s[i]);
b := b * 256 + x;
a := a + 8;
while a >= 6 do
begin
a := a - 6;
x := b div (1 shl a);
b := b mod (1 shl a);
Result := Result + Keys64[x + 1];
end;
end;
if a > 0 then
begin
x := b shl (6 - a);
Result := Result + Keys64[x + 1];
end;
end;
function Decode64String(S: string): string;
var
i: Integer;
a: Integer;
x: Integer;
b: Integer;
begin
Result := '';
a := 0;
b := 0;
for i := 1 to Length(s) do
begin
x := Pos(s[i], Keys64) - 1;
if x >= 0 then
begin
b := b * 64 + x;
a := a + 6;
if a >= 8 then
begin
a := a - 8;
x := b shr a;
b := b mod (1 shl a);
x := x mod 256;
Result := Result + chr(x);
end;
end
else
Exit;
end;
end;
function Encode64StringToStream(const Input: TStream; var Output: string): Boolean;
var
MS: TMemoryStream;
begin
Result := False;
MS := TMemoryStream.Create;
try
Input.Seek(0, soFromBeginning);
MS.CopyFrom(Input, Input.Size);
MS.Seek(0, soFromBeginning);
Output := Encode64String(StreamToString(MS));
finally
MS.Free;
end;
Result := True;
end;
procedure Decode64StringToStream(const Input: string; Output: TStream);
var
MS: TMemoryStream;
begin
try
MS := TMemoryStream.Create;
try
StringToStream(MS, Decode64String(Input));
MS.Seek(0, soFromBeginning);
Output.CopyFrom(MS, MS.Size);
Output.Position := 0;
finally
MS.Free;
end;
except on E: Exception do
raise Exception.Create('stream decode error - ' + E.Message);
end;
end;
procedure StringToStream(Stream: TStream; const S: string);
begin
Stream.Write(Pointer(S)^, Length(S));
end;
function StreamToString(MS: TMemoryStream): string;
begin
SetString(Result, PChar(MS.Memory), MS.Size div SizeOf(Char));
end;
我 99% 确定这里的问题与 Unicode 相关。很遗憾,因为我相信 Lazarus/Freepascal 一直是 unicode 而不是 Delphi,因此使用了不同的字符串类型,这使得像我这样不太专业的用户几乎不可能解决!
老实说,我认为上面的所有代码都有些混乱,感觉就像我只是在猜测要将字符串更改为什么,而并不真正知道自己在做什么。
我的第一个想法是将所有内容从 更改String
为AnsiString
. 这几乎成功了一次,但是在尝试使用时,Decode64StringToStream
我得到了零数据。其他时候,数据没有正确保存为 base64 编码格式,有时我什至遇到诸如 TStream.Seek 未实现之类的错误。
PS,我已经阅读了指南,并且有很多关于如何将旧的 Delphi 项目迁移到更新的 unicode 版本的白皮书等,老实说,我仍然对它一无所知。我认为替换string
到AnsiString
就足够了,但似乎不是。
任何提示、指示或一般建议或线索将不胜感激。