I'm trying to write a wrapper class around TRichEdit that can encode and decode RTF to/from plaintext.

This is what I've written so far:

type
  TRTF = class
  private
    FRichEdit : TRichEdit;
    procedure SetText(const AText: string);
    function GetText: string;
    class function Convert(const AInput: string; AEncode: Boolean): string; inline; static;
  public
    constructor Create;
    destructor Destroy; override;
    class function Decode(const AInput: string): string; static;
    class function Encode(const AInput: string): string; static;
  end;

constructor TRTF.Create;
begin
  FRichEdit := TRichEdit.CreateParented(HWND_MESSAGE);
end;

destructor TRTF.Destroy;
begin
  FRichEdit.Free;
  inherited;
end;

function TRTF.GetText: string;
var
  Stream: TStringStream;
begin
  if FRichEdit.PlainText then begin
    Stream := TStringStream.Create('', TEncoding.ANSI);
  end else begin
    Stream := TStringStream.Create('', TEncoding.ASCII);
  end;
  try
    FRichEdit.Lines.SaveToStream(Stream, Stream.Encoding);
    Result := Stream.DataString;
  finally
    Stream.Free;
  end;
end;

procedure TRTF.SetText(const AText: string);
var
  Stream: TStringStream;
begin
  if FRichEdit.PlainText then begin
    Stream := TStringStream.Create(AText, TEncoding.ANSI);
  end else begin
    Stream := TStringStream.Create(AText, TEncoding.ASCII);
  end;
  try
    Stream.Seek(0, TSeekOrigin.soBeginning);
    FRichEdit.Lines.LoadFromStream(Stream);
  finally
    Stream.Free;
  end;
end;

class function TRTF.Convert(const AInput: string; AEncode: Boolean): string;
var
  RTF: TRTF;
begin
  RTF := TRTF.Create;
  try
    RTF.FRichEdit.PlainText := AEncode;
    RTF.SetText(AInput);
    RTF.FRichEdit.PlainText := not AEncode;
    Result := RTF.GetText;
  finally
    RTF.Free;
  end;
end;

class function TRTF.Encode(const AInput: string): string;
begin
  Result := Convert(AInput, True);
end;

class function TRTF.Decode(const AInput: string): string;
begin
  Result := Convert(AInput, False);
end;

This seems to be working reasonably well for everything that can be represented by the user default ANSI codepage.

It fails (converts them to ?) for other characters though.

Is there an easy way to enable correct Unicode handling in my code?

I tried to use TEncoding.Unicode and TEncoding.UTF8 as the encoding for the TStringStream when the TRichEdit is set to PlainText := True, but that doesn't work.

有帮助吗?

解决方案

I think you are over-complicating this. There's no need to use the PlainText property at all. Leave it at its default setting of True. Then, to read/write RTF use LoadFromStream and SaveToStream. And to read/write plain text use the Lines.Text property.

This is about as simple as I can make it:

type
  TRTF = class
  strict private
    class function CreateRichEdit: TRichEdit; static;
  public
    class function Decode(const AInput: string): string; static;
    class function Encode(const AInput: string): string; static;
  end;

class function TRTF.CreateRichEdit: TRichEdit;
begin
  Result := TRichEdit.CreateParented(HWND_MESSAGE);
end;

class function TRTF.Encode(const AInput: string): string;
var
  RichEdit: TRichEdit;
  Stream: TStringStream;
begin
  RichEdit := CreateRichEdit;
  try
    RichEdit.Lines.Text := AInput;
    Stream := TStringStream.Create;
    try
      RichEdit.Lines.SaveToStream(Stream);
      Result := Stream.DataString;
    finally
      Stream.Free;
    end;
  finally
    RichEdit.Free;
  end;
end;

class function TRTF.Decode(const AInput: string): string;
var
  RichEdit: TRichEdit;
  Stream: TStringStream;
begin
  RichEdit := CreateRichEdit;
  try
    Stream := TStringStream.Create(AInput);
    try
      RichEdit.Lines.LoadFromStream(Stream);
      Result := RichEdit.Lines.Text;
    finally
      Stream.Free;
    end;
  finally
    RichEdit.Free;
  end;
end;
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top