Recent

Author Topic: copy MemoryStream to StringStream  (Read 13496 times)

hosune7845

  • Full Member
  • ***
  • Posts: 159
copy MemoryStream to StringStream
« on: June 23, 2017, 04:01:28 am »
Hi.

I tried to copy memStream -> strStream -> Another memStream

but Another memStream doesn't math with memStream

Here's my code.
Code: Pascal  [Select][+][-]
  1. var
  2.   AMemStr, AMemStr2: TMemoryStream;
  3.   AStrStr: TStringStream;
  4. begin
  5.   //Load some file
  6.   AMemStr := TMemoryStream.Create;
  7.   AMemStr.LoadFromFile('C:\Users\RND_HP_64bit\Desktop\dot-etst.bmp');
  8.   AMemStr.Position := 0;
  9.  
  10.   //copy MemoryStream to StringStream
  11.   AStrStr := TStringStream.Create('');
  12.   AStrStr.Size := AMemStr.Size;
  13.   AStrStr.CopyFrom(AMemStr, AMemStr.Size);
  14.   AStrStr.Position := 0;
  15.  
  16.   //copy StringStream to MemoryStream and save
  17.   AMemStr2 := TMemoryStream.Create;
  18.   AMemStr2.SetSize(AStrStr.Size);
  19.   AMemSTr2.WriteAnsiString(AStrStr.DataString); //Data AStrStr.DataString is from RS232 receive.
  20.   AMemStr2.SaveToFile('C:\HSSON\program\lazarus\FileTransfer\test.bmp');  
  21.  

File dot-etst.bmp <> test.bmp. test.bmp

Any idea?
« Last Edit: June 23, 2017, 04:19:21 am by hosune7845 »

Handoko

  • Hero Member
  • *****
  • Posts: 5122
  • My goal: build my own game engine using Lazarus
Re: copy MemoryStream to StringStream
« Reply #1 on: June 23, 2017, 04:12:54 am »
Don't use TStringStream but only memStream > memStream > memStream.

TStringStream is for ansistring, it stores extra character for reference count and length. That's why the problem happened in your code.

https://www.freepascal.org/docs-html/rtl/classes/tstringstream.html
http://wiki.freepascal.org/Character_and_string_types#AnsiString

hosune7845

  • Full Member
  • ***
  • Posts: 159
Re: copy MemoryStream to StringStream
« Reply #2 on: June 23, 2017, 04:20:23 am »
Don't use TStringStream but only memStream > memStream > memStream.

TStringStream is for ansistring, it stores extra character for reference count and length. That's why the problem happened in your code.

https://www.freepascal.org/docs-html/rtl/classes/tstringstream.html
http://wiki.freepascal.org/Character_and_string_types#AnsiString

Thank you.

But I need to transfer the stream to RS232 as string. I updated my code

Handoko

  • Hero Member
  • *****
  • Posts: 5122
  • My goal: build my own game engine using Lazarus
Re: copy MemoryStream to StringStream
« Reply #3 on: June 23, 2017, 04:32:52 am »
The real problem is:
TMemoryStream.WriteAnsiString(const S)

The result will have the extra characters added. Maybe you can try something like this:

for i := 1 to anAnsiString.GetSize do
  aMemoryStream.WriteByte(Byte(anAnsiString.ReadStr(1)))

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: copy MemoryStream to StringStream
« Reply #4 on: June 23, 2017, 04:39:29 am »
The real problem is:
TMemoryStream.WriteAnsiString(const S)

The result will have the extra characters added. Maybe you can try something like this:

for i := 1 to anAnsiString.GetSize do
  aMemoryStream.WriteByte(Byte(anAnsiString.ReadStr(1)))
it has nothing to do with ansi/utf8 or even ascii strings the method writeansistring first writes the length of the string and then the string it self. To write to a stream raw content you use the write method everything else has its own translation. eg
Code: Pascal  [Select][+][-]
  1. amemoyStream.Write(anStr[1],Length(anStr));
will save the contents of a string as they are in memory may that be ansistring, utf8, utf16 etc they will be  dumped as they are to the stream.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

hosune7845

  • Full Member
  • ***
  • Posts: 159
Re: copy MemoryStream to StringStream
« Reply #5 on: June 23, 2017, 05:35:39 am »
Thanks for all replies.

I test without RS232(TLazSErial) and works find as below :

Code: Pascal  [Select][+][-]
  1. var
  2.   AMemStr, AMemStr2: TMemoryStream;
  3.   AStrStr: TStringStream;
  4.  
  5.   s: string;
  6. begin
  7.   //Load some file
  8.   AMemStr := TMemoryStream.Create;
  9.   AMemStr.LoadFromFile('C:\Users\RND_HP_64bit\Desktop\dot-etst.bmp');
  10.   AMemStr.Position := 0;
  11.  
  12.   //copy MemoryStream to StringStream
  13.   AStrStr := TStringStream.Create('');
  14.   AStrStr.Size := AMemStr.Size;
  15.   AStrStr.CopyFrom(AMemStr, AMemStr.Size);
  16.   AStrStr.Position := 0;
  17.  
  18.  
  19.   s := AStrStr.DataString;
  20.   AMemStr2 := TMemoryStream.Create;
  21.   AMemStr2.SetSize(AStrStr.Size);
  22.   AMemStr2.Write(s[1], length(s) * sizeof(s[1]));
  23.   AMemStr2.SaveToFile('C:\HSSON\program\lazarus\FileTransfer\test.bmp');
  24.  

But with TLazSerial, Two files don't math. Here's code

Send
Code: Pascal  [Select][+][-]
  1.   //memstrSend -> Some file. already loaded
  2.   memstrSend.Position := 0;
  3.   fmStringStream := TStringStream.Create('');
  4.   fmStringStream.Position := 0;
  5.   fmStringStream.Size := memstrSend.Size;
  6.   fmStringStream.CopyFrom(memstrSend, memstrSend.Size);
  7.   fmStringStream.Position := 0;
  8.  
  9.   comSend.WriteData('FLS' + formatfloat('000000', fmStringStream.Size) + chr(13)+chr(10)); //File size
  10.   comSend.WriteData('FLD' + chr(13)+chr(10)); //Start download
  11.   fmStringStream.Position := 0;
  12.   s := fmStringStream.DataString;
  13.  
  14.   comSend.WriteData(s);
  15.  

Receive
Code: Pascal  [Select][+][-]
  1.        //nSize -> Size of file
  2.  
  3.         sValue := '1';
  4.         AMemStream := TMemoryStream.Create;
  5.         AMemStream.SetSize(nSize);
  6.         AMemStream.Position := 0;
  7.         while sValue <> '' do
  8.         begin
  9.           sValue := comReceive.ReadData;
  10.           AMemStream.Write(sValue[1], length(sValue) * sizeof(sValue[1]));
  11.           sValue := '';
  12.         end;
  13.  
  14.         AMemStream.SaveToFile('C:\HSSON\program\lazarus\FileTransfer\test.bmp');
  15.         AMemStream.Free;
  16.  


Any idea?

« Last Edit: June 23, 2017, 07:15:43 am by hosune7845 »

Handoko

  • Hero Member
  • *****
  • Posts: 5122
  • My goal: build my own game engine using Lazarus
Re: copy MemoryStream to StringStream
« Reply #6 on: June 23, 2017, 10:09:02 am »
There are 2 things seem weird to me:
- Your while-end loop will have only 1 pass. See line #7 and #3
- Why you multiply the length with size? See line #6

Code: Pascal  [Select][+][-]
  1.         sValue := '1';
  2.         //...
  3.         while sValue <> '' do
  4.         begin
  5.           sValue := comReceive.ReadData;
  6.           AMemStream.Write(sValue[1], length(sValue) * sizeof(sValue[1]));
  7.           sValue := '';
  8.         end;
  9.  

Handoko

  • Hero Member
  • *****
  • Posts: 5122
  • My goal: build my own game engine using Lazarus
Re: copy MemoryStream to StringStream
« Reply #7 on: June 23, 2017, 10:17:39 am »
Maybe what you want is

Code: Pascal  [Select][+][-]
  1.   repeat
  2.     sValue := comReceive.ReadData;
  3.     AMemStream.Write(sValue[1], Length(sValue));
  4.   until (sValue = '');

BeniBela

  • Hero Member
  • *****
  • Posts: 905
    • homepage
Re: copy MemoryStream to StringStream
« Reply #8 on: June 23, 2017, 12:30:18 pm »
Maybe what you want is

Code: Pascal  [Select][+][-]
  1.   repeat
  2.     sValue := comReceive.ReadData;
  3.     AMemStream.Write(sValue[1], Length(sValue));
  4.   until (sValue = '');

Never use [1]

Must be something like

Code: [Select]
    AMemStream.Write(pchar(pointer(sValue)))^, Length(sValue));

or it crashes when range checking is enabled

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: copy MemoryStream to StringStream
« Reply #9 on: June 23, 2017, 02:55:53 pm »
Never use [1]

Must be something like

Code: [Select]
    AMemStream.Write(pchar(pointer(sValue)))^, Length(sValue));

or it crashes when range checking is enabled
Can you provide more info? in a fast and dirty test I wrote just now it seems to behave properly with or with out range checking (laz 1.4.4 fpc 2.6.4 I think) see attached project.
PS I will be testing it later on laza 1.6 as well.
PS2 It does not raise any problems on 1.6.4 also, full debug options enabled
« Last Edit: June 23, 2017, 03:37:41 pm by taazz »
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

BeniBela

  • Hero Member
  • *****
  • Posts: 905
    • homepage
Re: copy MemoryStream to StringStream
« Reply #10 on: June 23, 2017, 03:38:41 pm »
I meant a crash by range exception if sValue = ''

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: copy MemoryStream to StringStream
« Reply #11 on: June 23, 2017, 03:42:32 pm »
I meant a crash by range exception if sValue = ''
Oh! that makes sense and an expected behavior.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1311
    • Lebeau Software
Re: copy MemoryStream to StringStream
« Reply #12 on: June 24, 2017, 12:58:14 am »
Never use [1]

Must be something like

Code: [Select]
    AMemStream.Write(pchar(pointer(sValue)))^, Length(sValue));

The double-casting is not necessary:

Code: [Select]
AMemStream.Write(PChar(sValue)^, Length(sValue));
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

BeniBela

  • Hero Member
  • *****
  • Posts: 905
    • homepage
Re: copy MemoryStream to StringStream
« Reply #13 on: June 24, 2017, 02:03:07 am »
Never use [1]

Must be something like

Code: [Select]
    AMemStream.Write(pchar(pointer(sValue)))^, Length(sValue));

The double-casting is not necessary:

Code: [Select]
AMemStream.Write(PChar(sValue)^, Length(sValue));

But with a pointer the cast was almost three times faster

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1311
    • Lebeau Software
Re: copy MemoryStream to StringStream
« Reply #14 on: June 25, 2017, 04:29:32 am »
But with a pointer the cast was almost three times faster

Then use Pointer instead of PChar, but you still don't need to double cast:

Code: [Select]
AMemStream.Write(Pointer(sValue)^, Length(sValue));
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

 

TinyPortal © 2005-2018