Tuesday, May 29, 2007

Stream Me a River

Recently, I have uploaded new open source unit to my web pages - GpStreams. It contains a mix of TStream descendants, enhancers and helpers I have written over the last few years.

Stream Window

TGpStreamWindow is a TStream descendant which provides a window into another stream.

Sometimes you want to pass just a part of a stream to some method. For example, you have a stream containing a header and data and you want to pass it to a method that expects only data. If you can't change the method in question to ignore the header (maybe it's not a method you have written), then you would normally have to copy the data part to another stream and pass the copy to that method.

Alternatively, you can wrap the stream into TGpStreamWindow and set limits to exclude the header, then pass the TGpStreamWindow instance to the method. TGpStreamWindow doesn't copy data but overrides Read, Write, and Seek methods.

Relevant part of the interface:

  TGpStreamWindow = class(TStream)
constructor Create(baseStream: TStream); overload;
constructor Create(baseStream: TStream; firstPos, lastPos: int64); overload;
procedure SetWindow(firstPos, lastPos: int64);
property FirstPos: int64 read srFirstPos;
property LastPos: int64 read srLastPos;
end; { TGpStreamWindow }


procedure DoSomethingWithData(dataStream: TStream);

procedure ProcessStream(headerAndData: TStream);
dataStream: TGpStreamWindow;
// first 512 bytes contain the header - ignore!
dataStream := TGpStreamWindow.Create(headerAndData, 513, headerAndData.Size - 1);
finally FreeAndNil(dataStream); end;

Streamed Memory Buffer

TGpFixedMemoryStream is a TStream descendant which provides  streamed access to a memory buffer. In a way, it is similar to the TStringStream except that the underlying data is stored in a constant-size memory buffer.


  TGpFixedMemoryStream = class(TStream)
constructor Create; overload;
constructor Create(const data; size: integer); overload;
constructor Create(const data: string); overload;
procedure SetBuffer(const data; size: integer);
property Memory: pointer read fmsBuffer;
end; { TGpFixedMemoryStream }

Stream enhancers

TGpStreamEnhancer class contains various small helpers for the TStream class. Because of the technology used (class helpers), it can only be used in D2005 and newer. Also because of the technology used, TGpStreamEnhancer extends functionality of TStream and all descendant classes.

TGpStreamEnhancer contains:

  • Big endian (Motorola) readers/writers - Methods to read/write numbers in Motorola (big endian) format.
  • Little endian (Intel) readers/writers - Methods to read/write numbers in Intel (little endian) format.
  • Tagged readers/writers - Methods to read/write tagged data.
  • Text file emulator - Write(string) and Writeln.
  • Other helpers - Save/load stream to/from file, format stream as string or hex string, empty the stream.

Stream Wrappers

Two stream wrappers are included. Both are implemented with interfaces and use the fact that Delphi automatically destroy interfaces when they go out of scope to achieve some 'automagic' functionality.

AutoDestroyStream automatically destroys a stream, when the wrapper goes out of scope.

For example, ProcessStream example above could be rewritten with AutoDestroyStream to:

procedure ProcessStream(headerAndData: TStream);
// first 512 bytes contain the header - ignore!
TGpStreamWindow.Create(headerAndData, 513, headerAndData.Size)).Stream);

KeepStreamPosition wrapper automatically resets stream position to the original value when wrapper is destroyed.

Other Utilities

Few 'unclassified' utilities are also included in the GpStreams unit.

SafeCreateFileStream is a wrapper around TFileStream.Create that maps exception into function result.

DestroyFileStreamAndDeleteFile destroys TFileStream and deletes the file that was used as a stream source.

Technorati tags: , , , ,


  1. When I click the "source and documentation, zipped" link, I get a 404 Not Found error.

  2. Oooops! Fixed.

    Thanks for the warning!