我一直在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没有实现的错误。
string
替换为AnsiString
就足够了,但似乎不是。
非常感谢任何提示,指示或一般建议或线索。
答案 0 :(得分:4)
我认为你想要做的是:
然后解码你只需要反转步骤。
代码如下所示:
function Encode(const Input: string): AnsiString;
var
utf8: UTF8String;
begin
utf8 := UTF8String(Input);
Result := EncdDecd.EncodeBase64(PAnsiChar(utf8), Length(utf8));
end;
function Decode(const Input: AnsiString): string;
var
bytes: TBytes;
utf8: UTF8String;
begin
bytes := EncdDecd.DecodeBase64(Input);
SetLength(utf8, Length(bytes));
Move(Pointer(bytes)^, Pointer(utf8)^, Length(bytes));
Result := string(utf8);
end;