Dec 232017
Turbo Pascal 6.0/TPW stream objects. Included compression and encryption.
File STREAM13.ZIP from The Programmer’s Corner in
Category Pascal Source Code
Turbo Pascal 6.0/TPW stream objects. Included compression and encryption.
File Name File Size Zip Size Zip Type
COMPRESS.PAS 3672 924 deflated
CRC16.ASM 5086 2147 deflated
CRC16.OBJ 722 718 deflated
CRC32.ASM 8310 3383 deflated
CRC32.OBJ 1259 1258 deflated
CRCARC.ASM 4326 1493 deflated
CRCARC.OBJ 729 646 deflated
ENCRYPT.PAS 2074 763 deflated
HUFFCOMP.PAS 4138 1081 deflated
HUFFMAN.PAS 9537 2854 deflated
LOGDEMO.PAS 1206 514 deflated
LZWSTREA.ASM 19245 4572 deflated
LZWSTREA.OBJ 2506 1861 deflated
OVR1.PAS 178 131 deflated
OVR2.PAS 178 131 deflated
OVRDEMO.PAS 1476 612 deflated
STREAMS.DOC 39546 11382 deflated
STREAMS.PAS 68302 14939 deflated
XMSSTRM.INC 9525 1978 deflated

Download File STREAM13.ZIP Here

Contents of the STREAMS.DOC file

STREAMS - TP 6.0/TPW 1.0 unit to supplement TurboVision/ObjectWindows streams

Version 1.3. Copyright D.J. Murdoch (1992).


"Wierd Stream Tricks" might be a good name for this unit. It
contains a miscellaneous collection of objects and procedures, all
on a theme of adding functionality to the streams in Borland's
Turbo Pascal libraries TurboVision and ObjectWindows.


This unit is *not* public domain code. You may use it for
non-profit purposes at no charge if credit is granted, but
written permission must be obtained from me for use of this unit in
commercial products.

A lot of the code in this unit is code that's been made freely
available by others, some of it under their copyright, other parts
public domain. As far as I know, all code included here may be
used under non-commercially for free. See the list of credits at
the end for all the (known) authors.

This is the second release of the STREAMS unit. There are probably
still bugs; I would really appreciate reports of any, or other
suggestions for improvement. Please send either one to me at one
of the following addresses:

[email protected] (Internet)
71631,122 (Compuserve)
DJ Murdoch at Fidonet node 1:221/177.40

D. J. Murdoch
79 John St. W.
Waterloo, Ontario, Canada
N2L 1B7



TStream (from Objects)
TFilter Base type for filters
TEncryptFilter Encrypts as it writes; decrypts as it reads
TLZWFilter Compresses as it writes; expands as it reads
TTextFilter Provides text file interface to stream
TLogFilter Provides logging of text file activity
TBitFilter Allows bit-oriented I/O
TDupFilter Duplicates output, checks for matching input
TSequential Filter that doesn't allow Seek
TChksumFilter Calculates 8 or 16 bit checksum for reads/writes
TCRC16Filter Calculates XMODEM style 16 bit CRC
TCRCARCFilter Calculates ARC style 16 bit CRC
TCRC32Filter Calculates ZIP & Zmodem style 32 bit CRC
TNulStream Eats writes, returns constant on reads
TRAMStream Stream in memory
TXMSStream Stream in XMS (extended) memory
TDOSStream (from Objects)
TBufStream (from Objects)
TNamedBufStream Buffered file stream that knows its name
TTempBufStream Buffered file stream that erases itself when done

Procedures & functions:

TempStream allocates a temporary stream
OvrInitStream like OvrInitEMS, but buffers overlays on a stream
May be called several times to buffer different
segments on different streams.
OvrDetachStream detaches stream from overlay system
OvrDisposeStreams detaches all streams from overlay system and disposes of
OvrSizeNeeded Calculates the size needed to load the rest of the segments
to a stream
OvrLoadAll immediately copies as many overlay segments to the stream
as will fit
xms_MemAvail returns the number of 1K blocks of XMS memory available
xms_MaxAvail returns size in Kb of the largest block of XMS memory

0. Files in archive
a list of the files that should accompany this one
1. TFilter
a generic object to act as a filter to a stream
2. TEncryptFilter
a filter which does simple encryption/decryption
3. TLZWFilter
a filter which does LZW compression/decompression
4. TTextFilter
a filter to provide the Read/ReadLn/Write/WriteLn
interface to a stream
5. TLogFilter
a filter to allow logging of activity on text files
6. TBitFilter
a filter to allow bit level I/O to a stream
7. TDupFilter
a filter to duplicate output, check for duplicate input
8. TSequential
a generic filter that can't Seek
9. Checksum/CRC filters:
a collection of filters which calculate checksums and CRC
values as the data goes by
10. TNulStream
a stream which counts data written to it, and which
returns a constant if you read
11. TRAMStream
a stream which resides entirely in RAM
12. TXMSStream
a stream which keeps its data in XMS memory
13. xms_MemAvail and xms_MaxAvail
procedures to show how much XMS memory is free
14. TNamedBufStream
a buffered file stream which knows its own name
15. TTempBufStream
a temporary buffered file stream, which deletes itself when
16. TempStream
a procedure to allocate a temporary stream, in RAM, EMS, or
on disk, according to a specified preference
17. OvrInitStream and related procedures
procedures to allow overlays to be buffered on any
stream or combination of streams
18. Miscellaneous constants and types

19. Release history and credits


Streams.doc - this file
Streams.pas - main source file for unit
Lzwstrea.asm - source for LZW compression - source for XMS stream
Crc16.asm - source for 16 bit CRC
Crc32.asm - source for 32 bit CRC
Crcarc.asm - source for ARC-style 16 bit CRC
Lzwstrea.obj - assembled code for external linking
Crc16.obj - " " " " "
Crcarc.obj - " " " " "
Crc32.obj - " " " " "

Demo programs:

Encrypt.pas - encryption program, using TEncryptFilter
Compress.pas - file compressor, using TLZWFilter
Huffman.pas - defines a Huffman encoding filter, using TBitFilter
HuffComp.pas - file compressor using THuffmanFilter
Logdemo.pas - simple demo of TLogFilter
Ovrdemo.pas - simple demo of multiple overlay files
ovr1.pas - one overlaid unit
ovr2.pas - a second overlaid unit

1. TFilter = object(TStream)

"Filters" are programs which take a file as input and produce a new
file as output. TFilter is an adaptation of this idea to streams.
Every TFilter has a base stream, which can be any kind of stream.
Every TFilter is itself a stream, which means you can read and
write to it. When you do, it just relays your request to the base

One use of this is in the fact that you can make descendants
of TFilter which massage the data on the way to and from the Base.
Just override the Read and Write (and possibly other) methods, and
you can make changes to the data flowing to or from *any* kind of
stream. No need for special coding for an TEMSStream, or for a
TDOSStream, or whatever. Your code can act on any of them.
Examples of things to do are in the Streams unit: encryption
(TEncryptFilter) and LZW compression (TLZWFilter).

The other main use is to add other kinds of functionality to a
stream. You can't use the formatting capabilities of ReadLn and
WriteLn with standard streams, but if you use a TTextFilter (see
below) you can.


Base : PStream;

TFilter.Base holds the pointer to the base stream.

StartOfs : longint;

TFilter.StartOfs holds the offset in the base stream of offset 0
in the filter. This allows multiple filters to work on the same
stream; one could work at offset 0, another at offset 1000, etc.
Just position the base to the desired starting offset before
initializing the filter.


Constructor Init(ABase: PStream);

TFilter.Init sets Base to point to ABase^, and sets StartOfs to
the current position of the base stream.

Destructor Done; virtual;

If Base is not nil, then TFilter.Done calls Flush, then disposes
of the base stream before calling TStream.Done for itself.

Function CheckStatus : boolean; virtual;

Returns true if status is stOK. If it is, but the base status is
not stOK, then it assumes that someone has called a Reset for the
filter, so it calls Reset for the base stream. Borland should
have made Reset virtual, and this kludge wouldn't have been

Procedure CheckBase;

Checks the base stream for an error. If Base^.status is not
stOK, then it calls Error with Code=stBaseError and

Function GetPos : longint; virtual;
Function GetSize : longint; virtual;
Procedure Read(var buf; count : word); virtual;
Procedure Seek(pos: longint); virtual;
Procedure Truncate; virtual;
Procedure Write(var buf; count: word); virtual;
Procedure Flush; virtual;

These methods all call the corresponding method in the base
stream. Offsets are translated using StartOfs. Before the call,
CheckStatus is called to propagate any Reset to the base; after
the call, CheckBase is called to propagate any errors to the
filter from the base.

2. TEncryptFilter = object(TFilter)

This is a filter which does simple encryption/decryption on the
base stream. The encryption method is to XOR each byte with a
Random(256) value; the starting RandSeed is the key for the


key : longint;

The key is used as a Randseed replacement value. Randseed itself
is left unmodified by Read and Write.


Constructor Init(Akey:longint; ABase:PStream);

The value AKey is used as the starting key for byte 0 of the
filter. Anything read from ABase is decrypted using this key;
anything written to it is encrypted.

Procedure Read(var buf; count : word); virtual;
Procedure Seek(pos : longint); virtual;
Procedure Write(var buf; count: word); virtual;

These methods all encrypt/decrypt and update the value of Key to
correspond to the new position in the stream. The encryption
method uses the same algorithm for encryption as for decryption.
TEncryptFilter.Seek is fairly slow, because it updates the Key
once for every byte difference between the current position and
the new position. Moving backwards is slower, because the update
algorithm is written in Pascal, not assembler as is the forward

3. TLZWFilter = object(TFilter)

This is a filter which does LZW compression as it writes to and
decompression as it reads from the base stream. The LZW code is
an adaptation of Wilbert van Leijen's implementation of the 12
bit LZW algorithm. It's quite fast, though not as fast as
Wilbert's version; it gets slowed down a lot by having to save
its state after every Read and Write operation. You're best off
writing large chunks to it to take advantage of Wilbert's
excellent code. (Historical note: Trying to rewrite this was
what inspired me to write FULLDB, a program which allows source
level debugging of external .ASM files. -djm)

Each TLZWFilter takes over 28700 bytes of memory, because it
keeps extensive tables to record the current state.

One limitation of the TLZWFilter is that it can only be opened in
read or write mode, and Seek cannot be used in write mode. If
this doesn't suit your application, you might want to flesh out
the demo Huffman encoder (HUFFMAN.PAS), since it does allow
random access.


Mode : word;

One of stOpenRead or stOpenWrite; the mode under which this
filter was opened.

Size : longint;

The size of the expanded stream. This is the size that users of
the filter will see; if compression is working, it will generally
be bigger than Base^.GetSize.

Position : longint;

This is the position in the expanded stream.

Tables : PLZWTables;

This is a pointer to the tables used by the compression engine.
They're automatically allocated on the heap.


Constructor Init(ABase:PStream; AMode:TOpenMode);

Allocates Tables from the heap, and opens the compressor in
a mode of either stOpenRead or stOpenWrite. If reading, a
signature and record of the uncompressed filesize is read from
the base to confirm that it is compressed by LZW, and to prime
the Tables. If writing, the signature is written to the stream.

Destructor Done; virtual;

Flushes all data to the stream, and writes the uncompressed
filesize to the head of it before calling TFilter.done.

Procedure Flush; virtual;
Function GetPos: longint; virtual;
Function GetSize:longint; virtual;
Procedure Read(var buf; count:word); virtual;
Procedure Seek(pos:longint); virtual;
Procedure Truncate; virtual;
Procedure Write(var buf; count: word); virtual;

These methods all override the basic filter methods and
compress/decompress the data. They check whether the operation
requested can be performed in the current mode, and call Error
with Code=stBadMode and Info=Mode if the operation is not

Seek is not supported at all in Write mode. In Read mode, it is
slow for seeking forwards, and very slow for seeking backwards:
it rewinds the file to the start and seeks forward from there by
expanding everything.

Truncate is not supported in either mode, and always causes a
call to Error.

Flush may only be called once; it changes Mode to 0, so any
further operations will fail.

4. TTextFilter = object(TFilter)

This is a filter which provides a Read/ReadLn/Write/WriteLn
interface to a stream through its Textfile field. Once the
filter is initialized, Textfile acts exactly like a text file in
the standard I/O procedures, but reads come from the stream, and
writes go to it. All of the standard stream methods work as
well, by flushing the Textfile variable first.


Textfile : Text;

This is the dummy text file to use in Read/ReadLn/Write/WriteLn.


Constructor Init(ABase:PStream; AName:String);

Initializes the filter with base ABase. The name AName is stored
as the name in the Textfile variable.

Destructor Done; virtual;

Closes the TextFile variable to flush any remaining data to the

function GetPos : LongInt; virtual;
function GetSize : LongInt; virtual;
procedure Read(var Buf; Count : Word); virtual;
procedure Seek(Pos : LongInt); virtual;
procedure Truncate; virtual;
procedure Write(var Buf; Count : Word); virtual;

Versions of the standard filter functions.

5. TLogFilter = object(TFilter)

This filter allows logging of activity on text files to a stream.
Logging is done very transparently. Once the TTextFilter is
initialized, you call the Log method to start logging a
particular text file, and the UnLog method to stop. When logging
is in effect, any data read from or written to the text file is
copied to the stream.

Multiple files may be logged to the same stream. For example,
you can log both Input and Output, and keep a record of an
interactive session on the stream.

It's also possible to log the same file to multiple streams.
Just create the different TLogFilter objects, and call their Log
methods with the same file as an argument. If you then call
Unlog, you must do it in the *reverse* order to the order you
called Log, e.g.
is the correct order to log and unlog.

One detail of the implementation may cause some trouble. The
data is logged to the stream at the time it is written to disk by
the text file. Since text files are buffered, this may not be
the time at which you write to the text file, and multiple text
files logged to the same stream may not have all data appearing
in the correct order.


LogList : ^Text;

This is a pointer to the first text file currently being logged.


Constructor Init(ABase:PStream);

Initializes the filter with a LogList of nil.

Destructor done; virtual;

Stops logging all text files by calling UnLog for each, and
closes and disposes of the base stream.

Procedure Log(var F:text);

Starts logging the text file F. Continues until the UnLog method
is called or the file is closed or Assign'd.

Function UnLog(var F:text):boolean;

Stops logging the text file F. Returns true if successful, false
if not. Will fail if an Assign has been done to F, or F has been
closed, or F has already been Unlogged, or another stream has
started logging F and hasn't been UnLog'd yet.

6. TBitFilter = object(TFilter)

This filter allows you to do bit-oriented I/O to a stream,
instead of the usual byte-oriented I/O. A typical use might be
for a compression scheme: if a word only takes the values 0 or
1, you can use a TBitFilter to be sure that it only takes up one
bit of the output file.

If you use this filter, you can mix standard byte-oriented I/O
(Read, Write) with bit-oriented I/O (GetBit, GetBits, ReadBits,
PutBit, PutBits, WriteBits). There's a substantial performance
penalty however, if the bytes you write to the stream aren't
aligned with the actual bytes in the base stream.

One arbitrary choice was made: the order of bits in a byte.
This object follows the 80x86 convention of least significant
part first, and considers the least significant bit (low bit) to
come before the most significant bit (high bit) within a byte.


BitPos : shortint;

Position of stream relative to base file. Negative values signal
that the buffer is unchanged from the file, positive values signal
that the file needs to be updated. Zero signals an empty buffer.

Mask : byte;

The mask to use to extract the next bit from the buffer.

Buffer : byte;

A buffer to hold 8 bits.

AtEnd : boolean;

This flag is an efficiency hack. A TBitFilter can write a single
bit anywhere in a file; this means that it has to read the
existing byte before writing a new one. If it's doing a lot of
small writes at the end of the file, this can be incredibly slow,
because every one of those reads will fail. The AtEnd flag
signals that the current position of the stream is the end of the
file, and a read isn't necessary.

Normally, AtEnd is maintained internally, and you don't need to
worry about it. However, if you increase the length of the base
stream other than by writes through the TBitFilter, you
*must* set AtEnd to false, so that the bit buffer is properly
initialized. Calling Flush on the TBitFilter is sufficient to do
this, and would probably be a good idea before you fiddled with
the base anyways.


Function GetBit : TBit;

Type TBit is a 0 or a 1. This function reads a single bit from
the stream.

Function GetBits(count : byte): longint;

This function reads up to 32 bits, and returns them in the
longint value. The first bit read ends up in the least
significant bit of the result, and bits higher than the count
are zeroed.

Procedure ReadBits(var buf; count : longint);

This procedure reads up to 524288 bits (64K bytes) from the
stream into the buffer. Reads are faster when they start on a
byte boundary. Only the bytes that are affected by the
read will be modified, with the high bits of the last byte zeroed
if necessary. For example, if you read fewer than 9 bits into a
word variable, the high byte of the word will be left untouched.

Procedure PutBit(ABit : TBit);

Write one bit to the stream.

Procedure PutBits(Abits : longint; count : byte);

Writes up to 32 bits to the stream. Since ABits is a value
parameter, you can write the value of an expression directly to
the stream without storing it in an intermediate variable.

Procedure WriteBits(var buf; count : longint);

This procedure writes up to 524288 bits (64K bytes) to the
stream. Writes are *much* faster if the starting bit is byte

Procedure SeekBit(bitpos:longint);

Seek to a particular bit in the stream.

Function GetBitPos : longint;

Get the current stream position accurate to the nearest bit.

Procedure CopyBits(var S:TBitFilter; Count:longint);

Like CopyFrom, but for bits: copies Count bits from S.

Procedure ByteAlign;

Seeks forward to the next byte boundary. If the last byte
of the stream is only partially filled, it will be padded with
zero bits.

Procedure Read(var Buf; Count : Word); virtual;
Procedure Write(var Buf; Count : Word); virtual;
Procedure Seek(Pos : LongInt); virtual;
Procedure Flush; virtual;

Implement the standard byte-oriented functions. Note that if the
base stream is not byte-aligned at the start or a read/write,
they will split each byte between two in the output stream.

Procedure PrepareBuffer(ForRead:boolean);

Internal method to prepare the buffer for a read or a write.

7. TDupFilter = object(TFilter)

A filter which duplicates writes to two base streams, and checks
that data read from the two base streams matches. The match test
is a virtual method, so a descendant could implement a different
test if desired.


Base2 : PStream;

This is a pointer to the second base stream. I/O is done first
to Base^, then to Base2^.

Startofs2 : Longint;

Corresponds to TFilter.StartOfs, but applies to Base2^: gives
the offset corresponding to the filter's offset of 0.


constructor Init(ABase, Abase2 : PStream);

Sets the two base streams and the start offset variables.

destructor Done; virtual;

Flushes the filter, then disposes of both bases if they're not

function MisMatch(var buf1,buf2; count:word):word; virtual;

Checks for a mismatch between the two buffers. Returns
the byte number of the mismatch (1 based), or 0 if they
test equal. This default method checks for an exact match.

procedure Read(var Buf; Count : Word); virtual;

Reads from Base into the buffer, then does a corresponding read
from Base2 into a local buffer calling MisMatch to check for a
mismatch. If one is found, calls the Error method to signal an
stMisMatch error, with the Info word equal to the position of
the mismatch in the current buffer.

Unless a base error occurs, the two bases will be left
synchronized at the position following the data just read.

procedure Seek(Pos : LongInt); virtual;
procedure Truncate; virtual;
procedure Write(var Buf; Count : Word); virtual;
procedure Flush; virtual;

Standard methods applied to both bases.

function CheckStatus : Boolean; virtual;

Checks the status of the filter, and assures that both bases are
okay if status is stOK.

procedure CheckBase2;

Like TFilter.CheckBase, but operates on base2 and signals

8. TSequential

This is a very simple descendant of TFilter: the only
difference is that it signals stUnsupported if the Seek method
is called. It's used as a base for the filters below, which can
only work sequentially.


procedure Seek(pos:longint); virtual;

Signals stUnsupported by calling Error if ever called.

9. Checksum/CRC filters

These are four filters, TChkSumFilter, TCRC16Filter,
TCRCARCFilter, and TCRC32Filter, which can be used to calculate
checksums and cyclic redundancy checks (CRCs) on the stream of
data passing through the filter in either reads or writes.

All three CRC filters are based on code by a collection of
authors: Stephen Satchell, Chuck Forsberg, Mark G. Mendel, R.
P. Byrne, J. R. Louvau and probably others. Edwin T. Floyd
collected them together and translated them to TASM. The
CRC*.ASM files include more comments about sources and usage.

The basic calculations are also available in the interfaced
procedures UpdateChksum, UpdateCRC16, UpdateCRCARC, UpdateCRC32.
See the source code for the calling details.

TChkSumFilter = object(TSequential)

TChkSumFilter calculates a 16 bit sum of all the bytes read from
or written to the stream.

TCRC16Filter = object(TSequential)

This filter calculates the same 16 bit CRC as used in XModem and
its descendants.

TCRCARCFilter = object(TSequential)

This filter calculates the 16 bit CRC used by ARC.

TCRC32Filter = object(TSequential)

This filter calculates the 32 bit CRC used by PKZIP and ZModem.


TChkSumFilter.Chksum : word;

The 16 bit sum of all bytes passing through the filter. If an 8
bit checksum is required, get the low byte of Chksum by using

TCRC16Filter.CRC16 : word;

The XModem-style 16 bit CRC of all bytes passing through the

TCRCARCFilter.CRCARC : word;

The ARC-style 16 bit CRC of all bytes passing through the

TCRC32Filter.CRC32 : longint;

The PKZIP and ZModem-style 32 bit CRC of all bytes passing
through the filter. Note that the value should be inverted
before use (i.e. use "not CRC32" rather than "CRC32") for
compatibility with those programs.


constructor TChkSumFilter.Init(ABase : PStream;AChksum:word);
constructor TCRC16Filter.Init(ABase : PStream;ACRC16:word);
constructor TCRCARCFilter.Init(ABase : PStream;ACRCARC:word);
constructor TCRC32Filter.Init(ABase : PStream;ACRC32:word);

These constructors all initialize the filter, and set the
sum or CRC to the given value. Typically the first three would
start with a value of 0; PKZIP and ZModem start the 32 bit CRC
with a value of $FFFFFFFF.

procedure Read(var Buf; Count : Word); virtual;
procedure Write(var Buf; Count : Word); virtual;

All four filters override just these two methods. Both update
the sum or CRC if the Read/Write is successful.

10. TNulStream = object(TStream)

A stream which eats your writes, and returns a constant if you
read from it. (Suggested by Stefan Boether.)

I can see two uses for this stream. Stefan suggested using it to
count bytes: if you're not sure how much space something will
take when written out, write it to a TNulStream, and then read
the size to find out. I use it differently in the TempStream
code: there, it's used to initialize another stream to a fixed
value. I just copy as many bytes as I need from a TNulStream.


position : longint;

The current position of the stream. This is increased by both
reads and writes. It's also used as the current size of the

value : byte;

The value which will be used to fill any read request.


Constructor init(Avalue : byte);

Initialize the stream with value=Avalue.

Destructor done; virtual;

Dispose of the stream.

Function getpos : longint; virtual;
Function getsize : longint; virtual;
Procedure read(var buf; count : word); virtual;
Procedure seek(pos: longint); virtual;
Procedure write(var buf; count: word); virtual;

Implement the basic stream functions.

11. TRAMStream = object(TStream)

A stream which resides entirely in RAM, either maintaining its
own buffer, or using a predefined buffer. The maximum length
is 65520 bytes.


cp : word;

The current pointer for the stream.

size : word;

The current size of the stream.

alloc : word;

The size of the allocated block of memory.

buffer : Pbyte_array;

A pointer to the block of memory holding the stream data.

OwnMem : Boolean;

Indicates whether the stream "owns" the buffer, and should dispose
of it in the Done destructor.


Constructor init(Asize : word);

Attempt to initialize the stream to a block size of Asize;
initial stream size and position are 0.

Constructor UseBuf(Abuffer : pointer; Asize : word);

Set up the stream using the given buffer; OwnMem is set to false,
so that the memory will not be disposed when done.

Destructor done; virtual;

Dispose of the stream, and if OwnMem is true, the data buffer.

Function getpos : longint; virtual;
Function getsize : longint; virtual;
Procedure read(var buf; count : word); virtual;
Procedure seek(pos: longint); virtual;
Procedure truncate; virtual;
Procedure write(var buf; count: word); virtual;

Implement the basic stream functions.

12. TXMSStream = object(TStream)

A stream which keeps its data in XMS (extended) memory.


Handle : word;

The handle used by the XMS memory manager for the stream's block
of data.

MaxBlocks : word;

The maximum number of 1K blocks of memory to allocate.

BlocksUsed : word;

The number of 1K blocks of memory currently allocated. Always
allocates at least 1 byte more than Size.

Size : longint;

The current size of the stream.

Position : longint;

The current position of the stream.


Constructor init(AMaxBlocks : word);

Attempt to initialize the stream to a block size of with the
given value for MaxBlocks. The initial stream size and position
are 0, and one block is allocated.

Destructor done; virtual;

Dispose of the stream, and release the XMS memory.

Function getpos : longint; virtual;
Function getsize : longint; virtual;
Procedure read(var buf; count : word); virtual;
Procedure seek(pos: longint); virtual;
Procedure truncate; virtual;
Procedure write(var buf; count: word); virtual;

Implement the basic stream functions.

Procedure NewBlock;

Internal method to increase the stream's allocation by one block.

Procedure FreeBlock;

Internal method to decrease the stream's allocation by one block.
Doesn't check if the allocated size falls below Size.

13. xms_MemAvail and xms_MaxAvail

These procedures are analogous to the MemAvail and MaxAvail
procedures in the System unit. They report on available XMS
memory, in units of 1K blocks.

14. TNamedBufStream = object(TBufStream)

A simple descendant of TBufStream which knows its own name.


filename : PString { PChar in TPW };

The name of the stream.


Constructor Init(name:FNameStr;mode:TOpenMode;abufsize:word);

Open the file with the given name, and save the name.

Destructor Done; virtual;

Close the file.

15. TTempBufStream = object(TNamedBufStream)

A temporary buffered file stream, which deletes itself when done.


Constructor init(abufsize:word);

Create a temporary file with a unique name, in the directory
pointed to by the environment varable TEMP or in the current
directory, and open it in read/write mode.

Destructor done; virtual;

Close and delete the temporary file.

16. Function TempStream(InitSize,MaxSize : longint;

This procedure returns a pointer to a temporary stream from a
choice of 4, specified in the Preference array. The first stream
type listed in the Preference array which can be successfully
created with the given sizes will be returned, or Nil if none can
be made.


Initsize : longint;

The initial size to allocate to the stream. This many nulls will
be written to the stream, and then the position will be set to
byte 0.

MaxSize : longint;

The maximum size to which the stream should be allowed to grow.

Preference : TStreamRanking;

An array of 4 entries specifying what sort of temporary stream is
desired. Supplied constants include:

ForSpeed = (RAMStream, EMSStream, XMSStream, FileStream);
ForSize = (FileStream,EMSStream, XMSStream, RAMStream);
ForSizeInMem = (EMSStream, XMSStream, RAMStream, NoStream);
ForOverlays = (EMSStream, XMSStream, FileStream, NoStream);

17. Stream overlay procedures

These procedures allow overlays to be buffered on any stream or
combination of streams. Some overlays can be loaded into EMS,
others kept on disk, and others can be put onto any other
available stream.


Procedure OvrInitStream(S:PStream);

Copies overlay segment code to S as new segments are loaded, and
does reloads from there. You may call OvrInitStream multiple
times, and different segments will be buffered on different
streams, depending on the order in which they are loaded by the
overlay loader.

On the first call, an exit handler is installed which will call
OvrDisposeStreams upon program termination.

Procedure OvrDetachStream(BadS:PStream);

Makes sure that the overlay system makes no references to BadS.
Call this before disposing of a stream which has been passed to
OvrInitStream, or you're very likely to crash.

Procedure OvrDisposeStreams;

Detaches and disposes of all streams being used by the overlay

Function OvrSizeNeeded:longint;

Returns the additional size required to load any segments which
still haven't been loaded to a stream.

Function OvrLoadAll:boolean;

Forces all overlay segments to be copied into the stream; if
successful (true) then no more references to the overlay file
will be made.

Warning: This function calls OvrClearBuf, so that any overlay
files which are already in the regular overlay buffer will need
to be reloaded.

18. Miscellaneous constants and types


stBadMode = 1;

Error signalled when an operation is not permitted in the current

stStreamFail = 2;

Error signalled when a stream Init failed.

stBaseError = 3;

Error signalled by a TFilter when the base stream has an error;
the base stream's error number is put in the Info field.

stMemError = 4;

Not enough memory for operation.

stSigError = 5;

Problem with LZW file signature.

stUsedAll = 6;

XMS stream has used all of its allowed blocks.

stUnsupported = 7;

Operation unsupported in this stream. TSequential signals this
error if Seek is called.

stBase2Error = 8;

Error in second base in a TDupFilter; Info gets the Base2^.Error

stMisMatch = 9;

The two bases don't match on a read. The Info field is set to
the position of the mismatch in the current read buffer.

BufSize : word = 2048;

Buffer size to use when creating a buffered file stream in


TOpenMode = $3C00..$3DFF;

This is the widest possible range of open modes for a TDOSStream
descendant. Values outside this range can cause very serious bugs in
programs, since the high byte is used as the DOS service number
when the file is opened.

PLZWTables = ^TLZWTables;
TLZWTables = record ...

These tables are used internally to maintain the state of a

PByte_Array = ^TByte_Array;
TByte_Array = array[0..65520] of byte;

An array type used as a buffer in several places.

TStreamType = (NoStream, RAMStream, EMSStream, XMSStream, FileStream);

The types of streams that TempStream can create.

TStreamRanking = array[1..NumTypes] of TStreamType;

An array giving the order from most preferred to least preferred
for a temporary stream.

15. Release history and credits

1.0 - First release, missing LZW. Immediately replaced by
1.1 - First correct release: TFilter, TEncryptFilter, TTextFilter,
TLogFilter, TRAMStream, TNamedBufStream, TTempBufStream,
TempStream, overlay procedures (my ideas), TLZWFilter
(from code by Wilbert van Leijen)
1.2 - TNulStream, TXMSStream added (from Stefan Boether)
TBitFilter added (suggestion of Rene Seguin)
TFilter.Done calls Flush
TRAMStream.UseBuf and OwnMem added.
1.3 - TDupFilter, TSequential, TChksumFilter added (my ideas),
TCRC16Filter, TCRCARCFilter, TCRC32Filter and related procedures
added (from code by Edwin T. Floyd, Stephen Satchell, Chuck
Forsberg, Mark G. Mendel, R. P. Byrne, J. R. Louvau and
probably others); TFilter.Flush added; HUFFMAN demo added.

 December 23, 2017  Add comments

Leave a Reply