Converting TMemoryStream to 'String' in Delphi 2009

We had the following code prior to Delphi 2009:

function MemoryStreamToString(M : TMemoryStream): String;
var
    NewCapacity: Longint;
begin
    if (M.Size = > 0) or (M.Memory = nil) then
       Result:= '' 
    else
    begin
       if TMemoryStreamProtected(M).Capacity = M.Size then
       begin
           NewCapacity:= M.Size+1;
           TMemoryStreamProtected(M).Realloc(NewCapacity);
       end;
       NullString(M.Memory^)[M.Size]:= #0;
       Result:= StrPas(M.Memory);
    end;
end;

How might we convert this code to support Unicode now with Delphi 2009?


The code you have is unnecessarily complex, even for older Delphi versions. Why should fetching the string version of a stream force the stream's memory to be reallocated, after all?

function MemoryStreamToString(M: TMemoryStream): string;
begin
  SetString(Result, PChar(M.Memory), M.Size div SizeOf(Char));
end;

That works in all Delphi versions, not just Delphi 2009. It works when the stream is empty without any special case. SetString is an under-appreciated function.

If the contents of your stream aren't changing to Unicode with your switch to Delphi 2009, then you should use this function instead:

function MemoryStreamToString(M: TMemoryStream): AnsiString;
begin
  SetString(Result, PAnsiChar(M.Memory), M.Size);
end;

That's equivalent to your original code, but skips the special cases.


Or perhaps you can refactor your code to use directly a TStringStream directly? You can use it instead of TMemoryStream (they have the same interface) and you can 'convert' it to a string by simply calling myString := myStringStream.DataString;


A "cleaner" way might be:

function StreamToString(aStream: TStream): string;
var
  SS: TStringStream;
begin
  if aStream <> nil then
  begin
    SS := TStringStream.Create('');
    try
      SS.CopyFrom(aStream, 0);  // No need to position at 0 nor provide size
      Result := SS.DataString;
    finally
      SS.Free;
    end;
  end else
  begin
    Result := '';
  end;
end;

I use:

function StreamToString(const Stream: TStream; const Encoding: TEncoding): string;
var
  StringBytes: TBytes;
begin
  Stream.Position := 0;
  SetLength(StringBytes, Stream.Size);
  Stream.ReadBuffer(StringBytes, Stream.Size);
  Result := Encoding.GetString(StringBytes);
end;

It has been tested with Delphi XE7 only.


I have not upgraded yet, but my understanding is:

NewCapacity := (M.Size + 1) * SizeOf(Char);