?
Solved

Copy a memory stream into a byte array

Posted on 2005-03-09
9
Medium Priority
?
16,876 Views
Last Modified: 2011-09-20
Ok here is a very simple one, but I need an answer quick please.

I have a memory stream (tmemorystream) and I need to put the contents of the memory stream into a byte array.

Here is what i tried to do but I've obviously done something wrong as it doesnt work

function TMainForm.convertTobytearray;

var
  TEncoded : String;
  SomeStream : tmemorystream;
  bufs : array of byte;

begin

//SNIP unimportant code//

  SomeStream := TMemoryStream.Create;
  SomeStream := HTTPSend(Tencoded);
  setlength(bufs,somestream.size);
  somestream.Read(bufs,somestream.size);
  showmessage(pchar(somestream.memory));
end;

If I step through the code, I see that a byte array of 6 bytes is allocated (the same as the size of the tmemorystream) but the bytes are all 00's but the memorystream contains actual binary data

I'm sure I have just missed something simple

Thanks in advance for any help

Luke
0
Comment
Question by:lukeMH
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
9 Comments
 
LVL 6

Expert Comment

by:pritaeas
ID: 13496478
A TMemoryStream has a Buffer property which is what need. But you'll have to look at the source to see how to access it. I don't have access to Delphi for the time being.

hth, pritaeas
0
 
LVL 26

Accepted Solution

by:
Russell Libby earned 1000 total points
ID: 13496635

Simple example. Notice the use of the first element of the byte array, otherwise the dynamic array will get clobbered.

Regards,
Russell

type
  TByteArray  =  Array of Byte;

function StreamToByteArray(Stream: TStream): TByteArray;
begin

  // Check stream
  if Assigned(Stream) then
  begin
     // Reset stream position
     Stream.Position:=0;
     // Allocate size
     SetLength(result, Stream.Size);
     // Read contents of stream
     Stream.Read(result[0], Stream.Size);
  end
  else
     // Clear result
     SetLength(result, 0);

end;

procedure TForm1.Button1Click(Sender: TObject);
var  bytes:      TByteArray;
     strmMem:    TMemoryStream;
     lpBytes:    Array [0..100] of Byte;
     dwIndex:    Integer;
begin

  for dwIndex:=0 to 100 do lpBytes[dwIndex]:=dwIndex;

  strmMem:=TMemoryStream.Create;
  strmMem.Write(lpBytes, SizeOf(lpBytes));

  bytes:=StreamToByteArray(strmMem);

  if CompareMem(bytes, @lpBytes, 100) then
     ShowMessage('Success')
  else
     ShowMessage('Failure');

  strmMem.Free;

end;

0
 

Author Comment

by:lukeMH
ID: 13496807
Where do i put

type
  TByteArray  =  Array of Byte;

?

Thanks

Luke
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 26

Expert Comment

by:Russell Libby
ID: 13496926

Define it pretty much anywhere..... just so long as it appears before usage. But please note, I only defined it so I could demo a function that returned that data type. You could just put the code inline, as in your example, and not have to define it at all, eg:

var
  TEncoded : String;
  SomeStream : tmemorystream;
  bufs : array of byte;

begin

//SNIP unimportant code//

  SomeStream := TMemoryStream.Create;
  SomeStream := HTTPSend(Tencoded);
  setlength(bufs,somestream.size);
  somestream.Read(bufs[0],somestream.size); // <- change
  showmessage(pchar(somestream.memory));
end;

The ** ONLY ** purpose of the demo was to illustrate the real problem. By passing the zero element, you are really passing the address of the first element of the array, vs the array itself. For dynamic arrays this does make a difference.


Russell


0
 

Author Comment

by:lukeMH
ID: 13497234
Hi,

I changed the line in my code like you suggested, but this didn't seem to do anything as buf is still an array or 0's

Kind Regards

Luke
0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 13497381

Luke,

Did you check to make sure that the stream was reset (position:=0) before attempting the Read? A Stream.Read will read from the current position, which if at the end of the stream will read nothing.

var
  TEncoded : String;
  SomeStream : tmemorystream;
  bufs : array of byte;
  dwRead:     Integer;
begin

  SomeStream:=TMemoryStream.Create;
  SomeStream:=HTTPSend(Tencoded);
  MessageBox(0, PChar(Format('Stream size = %d, Steam Position = %d', [SomeStream.Size, SomeStream.Position])), nil, MB_OK);

  SetLength(bufs, SomeStream.size);
  SomeStream.Position:=0;
  dwRead:=SomeStream.Read(bufs[0], SomeStream.size);
  MessageBox(0, PChar(Format('Number of bytes read = %d', [dwRead])), nil, MB_OK);

  MessageBox(0, SomeStream.Memory, nil, MB_OK);

end;


Regards,
Russell

0
 

Author Comment

by:lukeMH
ID: 13497407
doh!

I think you may well be right there, just going to check it out and if all is well points shall be awarded to you

Thanks and regards

Luke
0
 
LVL 13

Expert Comment

by:BlackTigerX
ID: 13497606
you can use
TByteDynArray

which is defined in the unit: Types

also beaware that TByteArray is already defined in the SysUtils unit, you wouldn't want to use that name as to not cause conflicts
0
 

Author Comment

by:lukeMH
ID: 13497962
rllibby you've got it,

Thanks everyone else for your comments

Kind Regards

Luke
0

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Michael from AdRem Software explains how to view the most utilized and worst performing nodes in your network, by accessing the Top Charts view in NetCrunch network monitor (https://www.adremsoft.com/). Top Charts is a view in which you can set seve…
Sometimes it takes a new vantage point, apart from our everyday security practices, to truly see our Active Directory (AD) vulnerabilities. We get used to implementing the same techniques and checking the same areas for a breach. This pattern can re…
Suggested Courses

770 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question