I guess that you all already worked with a TBytesStream. It is derived from a TMemoryStream and offers direct access to the underlying TBytes:
... TBytesStream = class(TMemoryStream) private ... property Bytes: TBytes read FBytes; end; ...
So far so good, the problem is that a TMemoryStream allocates more memory than the current Size. The reason is that not necessary to realloc memory for every write operation. You can see this in the Realloc method
... const MemoryDelta = $2000; { Must be a power of 2 } ... function TBytesStream.Realloc(var NewCapacity: Longint): Pointer; begin if (NewCapacity > 0) and (NewCapacity <> FSize) then NewCapacity := (NewCapacity + (MemoryDelta - 1)) and not (MemoryDelta - 1); Result := Pointer(FBytes); if NewCapacity <> FCapacity then begin SetLength(FBytes, NewCapacity); Result := Pointer(FBytes); ... end; end; ...
As you can see the NewCapacity is larger than the Size of the Stream. If you look deeper at the code you can see that the NewCapacity is of power of 2.
But anyway, the point is that the property Bytes can include more bytes than the Size of the Stream. That’s why you must be very careful if you want to access directly to the Bytes property.
In order to avoid any issues I created a record helper for TBytes with the property BytesReal that includes the used bytes:
... TBytesStreamHelper = class helper for TBytesStream strict private function get_BytesReal: TBytes; public property BytesReal: TBytes read get_BytesReal; end; ... function TBytesStreamHelper.get_BytesReal: TBytes; begin if Capacity > Size then Result := Copy(Bytes, 0, Size) else Result := Bytes; end; ...
If you like than add the TBytesStreamHelper to your project and use the new property BytesReal.