-1

I'm downloading a file from the web using IdHttp, like this:

var
 MS: TMemoryStream;

procedure Test1;
var
 Http: TIdHTTP;
begin
Http := TIdHTTP.Create(nil);
  try
    MS := TMemoryStream.Create;
    try
      Http.Get('http://www.test.com/test.exe', MS);
    finally
      MS.Free;
    end;
  finally
    Http.Free;
  end;
end;

Consequently, the downloaded file/stream (don't know how to pronounce it) will be in MS.Memory.

Well, I want to get or convert the MS.Memory to a string, and vice-versa.

I've tried the functions posted by Rob Kennedy in this question: Converting TMemoryStream to 'String' in Delphi 2009

But I just got the string: "MZP"

Can anyone help-me?

Community
  • 1
  • 1
paulohr
  • 576
  • 1
  • 9
  • 24
  • 3
    Why do you need to convert a `binary` data to string? It dose not make any sense with your code purpose. – kobik May 05 '12 at 13:59
  • @kobik, My program load a dll in memory that my 'competitors' CAN'T NOWAY obtain. Unfortunately, someone has obtained... So, I want to write the dll in a string, that can be converted to MemoryStream and load it. – paulohr May 05 '12 at 14:06
  • @TLama, if I use the `Get` function that has a string result, will be the same data contained in MS.Memory? – paulohr May 05 '12 at 14:11
  • 2
    still trying to hack the world? ;) – kobik May 05 '12 at 14:14
  • Well, it depends on content's encoding. The overload with the string result uses `TMemoryStream` internally. Then it converts it to a string by the content encoding. – TLama May 05 '12 at 14:14
  • @TLama, alright.. now, how convert the string to memorystream? – paulohr May 05 '12 at 14:21
  • 3
    A DLL is not a string. What are you really trying to do? Do you think your competitors will really find it so hard to do an HTTP GET? – David Heffernan May 05 '12 at 14:29
  • if you want transfer binary data as string format . you must use [base64](http://stackoverflow.com/questions/5795263/binary-to-base64-delphi),HEX data format for this purpose. – MajidTaheri May 05 '12 at 14:30

7 Answers7

4

Check the Length of resulting string. I suppose that string contains all binary file, but you can't see it as ASCII string due to zeroes in string body. Signature of executable (first bytes): 4D 5A 90 00. ASCII symbols: MZP#0 (P is ANSI Cyrillic in my case, symbol depends on code page).

MBo
  • 77,366
  • 5
  • 53
  • 86
2

I used from: Converting TMemoryStream to 'String' in Delphi 2009 the following function:

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;

After Http.Get('http://www.test.com/test.exe', MS); you can use: s:=StreamToString(MS);

s is string. For me it worked on Delphi 10.2 for reading pdf files from internet. It took me an hour to find this solution. All the functions of transforming memory stream into strings, found on the internet did not work for me. This is the only one that worked. Normal solution is: s:=Http.Get('http://www.test.com/test.exe'); without using the memory stream as an intermediary.

Petrus
  • 59
  • 5
1

All exe, dll file conatin an signature MZP#0 ... For pchar strings (huge string in delphi) #0 means end of the string and your debug inspector show MZP.

If you preserve original length of the stream you can access all the data.

tico
  • 124
  • 1
  • 6
1

just like others suggested, it's not sense to convert a binary dll to string without encoding. but if this is really needed, you can use: TStringStream class instead of TMemoryStream. and TStringStream.DataString property will get the string. please note again, directly converting binary data to string will perhaps lead to unspecified reuslt. use a encoding schema: e.g: base64, hex string

chenzero
  • 57
  • 1
  • 8
0

You can use LoadFromStream method of TStringList class .

Mojtaba Tajik
  • 1,725
  • 16
  • 34
0

The method using an intermediary TStrinStream is slow, because it copies the memory from one place to another 2 times:

  1. at the invokation of TStringStream.CopyFrom method,
  2. and at the final assignment Result := TStringStream.DataString

I suggest using no intermediary object and just copy the memory 1 time over to the result directly. Here is my function:



    Function TryMemoryStreamToString(const MS: TMemoryStream; var s: string): Boolean;
      begin
        Result := False; if(MS=nil)then exit;
        try
          SetLength(s, MS.Size - MS.Position);
          MS.Read(s[1], Length(s));
          Result := True;
        except
          Result := False;
        end;
      end;

off course you could return the string as the Result directly as well:



    Function MemoryStreamToStringDef(const MS: TMemoryStream; const ADefault: string = ''): string;
      begin
        if Assigned(MS)
           then try
                  SetLength(Result, MS.Size - MS.Position);
                  MS.Read(Result[1], Length(Result));
                except
                  Result := ADefault;
                end
           else Result := ADefault;
      end;

Just remember that the reading from the MemoryStream will start at wherever the TMemoryStream.Position points to. So be mindful of that and make sure it's where you want it to be, for example, if you want the entire content t all times, before calling the function set it to the beginning of the stream:



    var
      MS : TMemorySTream;
      s  : string;

    //(...)
      MS.Position := 0; 
      s := MemoryStreamToStringDef(MS);
    //(...)

Kris Jace
  • 69
  • 1
  • 5
0

Just for the record, in recent Delphi you can use a TStreamReader/TStreamWriter to read/write a string from/to a TStream descendent, like in the code below (where the LoadFromString/SaveToString are your own methods to do something with the string you read from the stream and to get a string from some object of yours respectively in order to write it to the stream):

procedure TStoryItem.LoadReadCom(const Stream: TStream);

begin
  var reader := TStreamReader.Create(Stream);
  LoadFromString(reader.ReadToEnd);
  FreeAndNil(reader); //the reader doesn't own the stream by default, so this won't close the stream
end;

procedure TStoryItem.SaveReadCom(const Stream: TStream);
begin
  var writer := TStreamWriter.Create(Stream);
  writer.Write(SaveToString);
  FreeAndNil(writer); //the writer doesn't own the stream by default, so this won't close the stream
end;
George Birbilis
  • 2,782
  • 2
  • 33
  • 35