0

私は Lazarus でプロジェクトに取り組んでおり、(いくつかの制限のため) 当分の間 Delphi XE に移行することにしました。

何が起こっているかの簡単な概要:

実行時に、外部ファイルをロードしてストリームに追加しています。ストリームは、1 つのメイン オブジェクト (TObject) から派生した複数の異なるクラスに属します。これらのクラスは、メイン オブジェクトから TList に追加されます。基本的に、各クラスには独自のストリーム プロパティがあり、クラスはメイン オブジェクトの子です。

このメイン オブジェクトには、保存と読み込みの手順があります。

オブジェクトを保存すると、string to stream を使用して、他のクラスからのすべてのストリーム データもファイルに保存されます。ここでの出力文字列は、XML に保存しているため、base64 でエンコードする必要があります。

ファイルを開くとき、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;

ここでの問題は Unicode に関連していると 99% 確信しています。残念なことに、Lazarus/Freepascal は常に Unicode であり、Delphi ではなく、さまざまな文字列型を使用しているため、私のようなプロではないユーザーが解決することはほとんど不可能です!

正直なところ、上記のコードはすべて少しごちゃごちゃしていると思います。自分が何をしているのかわからないまま、文字列を何に変更すればよいかを推測しようとしているだけのように感じます。

私の最初の考えは、すべてを から に変更することStringでしたAnsiString。これはほぼ一度は機能しましたが、使用しようとするDecode64StringToStreamとデータが返されませんでした。また、データが base64 エンコード形式で適切に保存されず、TStream.Seek が実装されていないなどのエラーが発生することもありました。

PS、私はガイドを読みましたが、古い Delphi プロジェクトを新しい Unicode バージョンに移行する方法についてのホワイトペーパーなど、たくさんありますが、正直なところ、まだ途方に暮れています。に置き換えるだけで十分だと思っていましstringAnsiStringが、そうではないようです。

ヒント、ポインター、または一般的なアドバイスや手がかりをいただければ幸いです。

4

1 に答える 1

4

あなたがやりたいことは次のとおりだと思います:

  1. Unicode 文字列を UTF-8 エンコーディングに変換します。多くの場合、これは Unicode テキストの最もスペース効率の良い形式です。
  2. base64 を使用して文字列をエンコードします。

次に、デコードするには、手順を逆にします。

コードは次のようになります。

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;
于 2013-10-01T10:46:03.223 に答える