%
%   $Id$
%   This file is part of the FPC documentation.
%   Copyright (C) 1998, by Michael Van Canneyt
%
%   The FPC documentation is free text; you can redistribute it and/or
%   modify it under the terms of the GNU Library General Public License as
%   published by the Free Software Foundation; either version 2 of the
%   License, or (at your option) any later version.
%
%   The FPC Documentation is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
%   Library General Public License for more details.
%
%   You should have received a copy of the GNU Library General Public
%   License along with the FPC documentation; see the file COPYING.LIB.  If not,
%   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
%   Boston, MA 02111-1307, USA. 
%
\chapter{The Objects unit.}
This chapter documents the \file{objects} unit. The unit was implemented by
many people, and was mainly taken from the FreeVision sources.

The methods and fields that are in a \var{Private} part of an object
declaration have been left out of this documentation.

\section{Constants}
The following constants are error codes, returned by the various stream
objects.

\begin{verbatim}
CONST
   stOk         =  0; { No stream error }
   stError      = -1; { Access error }
   stInitError  = -2; { Initialize error }
   stReadError  = -3; { Stream read error }
   stWriteError = -4; { Stream write error }
   stGetError   = -5; { Get object error }
   stPutError   = -6; { Put object error }
   stSeekError  = -7; { Seek error in stream }
   stOpenError  = -8; { Error opening stream }
\end{verbatim}
These constants can be passed to constructors of file streams:
\begin{verbatim}
CONST
   stCreate    = $3C00; { Create new file }
   stOpenRead  = $3D00; { Read access only }
   stOpenWrite = $3D01; { Write access only }
   stOpen      = $3D02; { Read/write access }
\end{verbatim}

The following constants are error codes, returned by the collection list
objects:
\begin{verbatim}
CONST
   coIndexError = -1; { Index out of range }
   coOverflow   = -2; { Overflow }
\end{verbatim}

Maximum data sizes (used in determining how many data can be used.

\begin{verbatim}
CONST
   MaxBytes = 128*1024*1024;                          { Maximum data size }
   MaxWords = MaxBytes DIV SizeOf(Word);              { Max word data size }
   MaxPtrs = MaxBytes DIV SizeOf(Pointer);            { Max ptr data size }
   MaxCollectionSize = MaxBytes DIV SizeOf(Pointer);  { Max collection size }
\end{verbatim}

\section{Types}
The follwing auxiliary types are defined:
\begin{verbatim}
TYPE
   { Character set }
   TCharSet = SET Of Char;                            
   PCharSet = ^TCharSet;

   { Byte array }
   TByteArray = ARRAY [0..MaxBytes-1] Of Byte;        
   PByteArray = ^TByteArray;

   { Word array }
   TWordArray = ARRAY [0..MaxWords-1] Of Word;        
   PWordArray = ^TWordArray;

   { Pointer array }
   TPointerArray = Array [0..MaxPtrs-1] Of Pointer;   
   PPointerArray = ^TPointerArray; 

   { String pointer }
   PString = ^String;

   { Filename array }
   AsciiZ = Array [0..255] Of Char;

   Sw_Word    = Cardinal;
   Sw_Integer = LongInt;
\end{verbatim}
The following records are used internaly for easy type conversion:
\begin{verbatim}
TYPE
   { Word to bytes}
   WordRec = packed RECORD
     Lo, Hi: Byte;     
   END;

   { LongInt to words }
   LongRec = packed RECORD
     Lo, Hi: Word;
   END;

  { Pointer to words }
   PtrRec = packed RECORD
     Ofs, Seg: Word;
   END;
\end{verbatim}
The following record is used when streaming objects:

\begin{verbatim}
TYPE
   PStreamRec = ^TStreamRec;
   TStreamRec = Packed RECORD
      ObjType: Sw_Word;
      VmtLink: pointer;
      Load : Pointer;
      Store: Pointer;
      Next : PStreamRec;
   END;
\end{verbatim}

The \var{TPoint} basic object is used in the \var{TRect} object (see
\sees{TRect}):
\begin{verbatim}
TYPE
   PPoint = ^TPoint;
   TPoint = OBJECT
      X, Y: Sw_Integer;
   END;
\end{verbatim}

\section{TRect}
\label{se:TRect}

The \var{TRect} object is declared as follows:
\begin{verbatim}
   TRect = OBJECT
      A, B: TPoint;
      FUNCTION Empty: Boolean;
      FUNCTION Equals (R: TRect): Boolean;
      FUNCTION Contains (P: TPoint): Boolean;
      PROCEDURE Copy (R: TRect);
      PROCEDURE Union (R: TRect);
      PROCEDURE Intersect (R: TRect);
      PROCEDURE Move (ADX, ADY: Sw_Integer);
      PROCEDURE Grow (ADX, ADY: Sw_Integer);
      PROCEDURE Assign (XA, YA, XB, YB: Sw_Integer);
   END;
\end{verbatim}

\begin{function}{TRect.Empty}
\Declaration
Function TRect.Empty: Boolean;
\Description
\var{Empty} returns \var{True} if the rectangle defined by the corner points 
\var{A}, \var{B} has zero or negative surface.
\Errors
None.
\SeeAlso
\seef{TRect.Equals}, \seef{TRect.Contains}
\end{function}

\latex{\inputlisting{objectex/ex1.pp}}
\html{\input{objectex/ex1.tex}}

\begin{function}{TRect.Equals}      
\Declaration
Function TRect.Equals (R: TRect): Boolean;
\Description
\var{Equals} returns \var{True} if the rectangle has the 
same corner points \var{A,B} as the rectangle R, and \var{False}
otherwise.
\Errors
None.
\SeeAlso
\seefl{Empty}{TRect.Empty}, \seefl{Contains}{TRect.Contains}
\end{function}

For an example, see \seef{TRect.Empty}

\begin{function}{TRect.Contains}
\Declaration
Function TRect.Contains (P: TPoint): Boolean;
\Description
\var{Contains} returns \var{True} if the point \var{P} is contained
in the rectangle (including borders), \var{False} otherwise.
\Errors
None.
\SeeAlso
\seepl{Intersect}{TRect.Intersect}, \seefl{Equals}{TRect.Equals}
\end{function}

\begin{procedure}{TRect.Copy}
\Declaration     
Procedure TRect.Copy (R: TRect);
\Description
Assigns the rectangle R to the object. After the call to \var{Copy}, the
rectangle R has been copied to the object that invoked \var{Copy}.
\Errors
None.
\SeeAlso
\seepl{Assign}{TRect.Assign}
\end{procedure}

\latex{\inputlisting{objectex/ex2.pp}}
\html{\input{objectex/ex2.tex}}

\begin{procedure}{TRect.Union}
\Declaration
Procedure TRect.Union (R: TRect);
\Description
\var{Union} enlarges the current rectangle so that it becomes the union
of the current rectangle with the rectangle \var{R}.
\Errors
None.
\SeeAlso
\seepl{Intersect}{TRect.Intersect}
\end{procedure}

\latex{\inputlisting{objectex/ex3.pp}}
\html{\input{objectex/ex3.tex}}

\begin{procedure}{TRect.Intersect}
\Declaration
Procedure TRect.Intersect (R: TRect);
\Description
\var{Intersect} makes the intersection of the current rectangle with
\var{R}. If the intersection is empty, then the rectangle is set to the empty
rectangle at coordinate (0,0).
\Errors
None.
\SeeAlso
\seepl{Union}{TRect.Union}
\end{procedure}

\latex{\inputlisting{objectex/ex4.pp}}
\html{\input{objectex/ex4.tex}}

\begin{procedure}{TRect.Move}
\Declaration
Procedure TRect.Move (ADX, ADY: Sw\_Integer);
\Description
\var{Move} moves the current rectangle along a vector with components
\var{(ADX,ADY)}. It adds \var{ADX} to the X-coordinate of both corner
points, and \var{ADY} to both end points.
\Errors
None.
\SeeAlso
\seepl{Grow}{TRect.Grow}
\end{procedure}

\latex{\inputlisting{objectex/ex5.pp}}
\html{\input{objectex/ex5.tex}}

\begin{procedure}{TRect.Grow}
\Declaration
Procedure TRect.Grow (ADX, ADY: Sw\_Integer);
\Description
\var{Grow} expands the rectangle with an amount \var{ADX} in the \var{X}
direction (both on the left and right side of the rectangle, thus adding a 
length 2*ADX to the width of the rectangle), and an amount \var{ADY} in 
the \var{Y} direction (both on the top and the bottom side of the rectangle,
adding a length 2*ADY to the height of the rectangle. 

\var{ADX} and \var{ADY} can be negative. If the resulting rectangle is empty, it is set 
to the empty rectangle at \var{(0,0)}.
\Errors
None.
\SeeAlso
\seepl{Move}{TRect.Move}.
\end{procedure}


\latex{\inputlisting{objectex/ex6.pp}}
\html{\input{objectex/ex7.tex}}

\begin{procedure}{TRect.Assign}
\Declaration
Procedure Trect.Assign (XA, YA, XB, YB: Sw\_Integer);
\Description
\var{Assign} sets the corner points of the rectangle to \var{(XA,YA)} and 
\var{(Xb,Yb)}.
\Errors
None.
\SeeAlso
\seepl{Copy}{TRect.Copy}
\end{procedure}

For an example, see \seep{TRect.Copy}.

\section{TObject}
\label{se:TObject}

The full declaration of the \var{TObject} type is:
\begin{verbatim}
TYPE
   TObject = OBJECT
      CONSTRUCTOR Init;
      PROCEDURE Free;
      DESTRUCTOR Done;Virtual;
   END;
   PObject = ^TObject;
\end{verbatim}
\begin{procedure}{TObject.Init}
\Declaration
Constructor TObject.Init;
\Description
Instantiates a new object of type \var{TObject}. It fills the instance up
with Zero bytes.
\Errors
None.
\SeeAlso
\seepl{Free}{TObject.Free}, \seepl{Done}{TObject.Done}
\end{procedure}

For an example, see \seepl{Free}{TObject.Free}

\begin{procedure}{TObject.Free}
\Declaration
Procedure TObject.Free;
\Description
\var{Free} calls the destructor of the object, and releases the memory
occupied by the instance of the object.
\Errors
No checking is performed to see whether \var{self} is \var{nil} and whether
the object is indeed allocated on the heap.
\SeeAlso
\seepl{Init}{TObject.Init}, \seepl{Done}{TObject.Done}
\end{procedure}

\latex{\inputlisting{objectex/ex7.pp}}
\html{\input{objectex/ex7.tex}}

\begin{procedure}{TObject.Done}
\Declaration
Destructor TObject.Done;Virtual;
\Description
\var{Done}, the destructor of \var{TObject} does nothing. It is mainly
intended to be used in the \seep{TObject.Free} method.
\Errors
None.
\SeeAlso
\seepl{Free}{TObject.Free}, \seepl{Init}{TObject.Init}
\end{procedure}

\section{TStream}
\label{se:TStream}

The \var{TStream} object is the ancestor for all streaming objects, i.e.
objects that have the capability to store and retrieve data.

It defines a number of methods that are common to all objects that implement
streaming, many of them are virtual, and are only implemented in the
descendrnt types.

Programs should not instantiate objects of type TStream directly, but
instead instantiate a descendant type, such as \var{TDosStream},
\var{TMemoryStream}.

This is the full declaration of the \var{TStream} object:
\begin{verbatim}
TYPE
   TStream = OBJECT (TObject)
         Status    : Integer; { Stream status }
         ErrorInfo : Integer; { Stream error info }
         StreamSize: LongInt; { Stream current size }
         Position  : LongInt; { Current position }
      FUNCTION Get: PObject;
      FUNCTION StrRead: PChar;
      FUNCTION GetPos: Longint; Virtual;
      FUNCTION GetSize: Longint; Virtual;
      FUNCTION ReadStr: PString;
      PROCEDURE Open (OpenMode: Word); Virtual;
      PROCEDURE Close; Virtual;
      PROCEDURE Reset;
      PROCEDURE Flush; Virtual;
      PROCEDURE Truncate; Virtual;
      PROCEDURE Put (P: PObject);
      PROCEDURE StrWrite (P: PChar);
      PROCEDURE WriteStr (P: PString);
      PROCEDURE Seek (Pos: LongInt); Virtual;
      PROCEDURE Error (Code, Info: Integer); Virtual;
      PROCEDURE Read (Var Buf; Count: Sw_Word); Virtual;
      PROCEDURE Write (Var Buf; Count: Sw_Word); Virtual;
      PROCEDURE CopyFrom (Var S: TStream; Count: Longint);
   END;
   PStream = ^TStream;
\end{verbatim}

\begin{function}{TStream.Get}
\Declaration
Function TStream.Get : PObject;
\Description
\var{Get} reads an object definition  from a stream, and returns
a pointer to an instance of this object.
\Errors
On error, \var{TStream.Status} is set, and NIL is returned.
\SeeAlso 
\seepl{Put}{TStream.Put}
\end{function}

\begin{function}{TStream.StrRead}
\Declaration
Function TStream.StrRead: PChar;
\Description
\var{StrRead} reads a string from the stream, allocates memory
for it, and returns a pointer to a null-terminated copy of the string
on the heap.
\Errors
On error, \var{Nil} is returned.
\SeeAlso
\seepl{StrWrite}{TStream.StrWrite}, \seefl{ReadStr}{TStream.ReadStr}
\end{function}

\begin{function}{TStream.GetPos}
\Declaration 
TSTream.GetPos : Longint; Virtual;
\Description
If the stream's status is \var{stOk}, \var{GetPos} returns the current 
position in the stream. Otherwise it returns \var{-1}
\Errors
\var{-1} is returned if the status is an error condition.
\SeeAlso
\seepl{Seek}{TStream.Seek}, \seefl{GetSize}{TStream.GetSize}
\end{function}

\begin{function}{TStream.GetSize}
\Declaration
Function TStream.GetSize: Longint; Virtual;
\Description
If the stream's status is \var{stOk} then \var{GetSize} returns
the size of the stream, otherwise it returns \var{-1}.
\Errors
\var{-1} is returned if the status is an error condition.
\SeeAlso
\seepl{Seek}{TStream.Seek}, \seefl{GetPos}{TStream.GetPos}
\end{function}

\begin{function}{TStream.ReadStr}
\Declaration
Function TStream.ReadStr: PString;
\Description
\var{ReadStr} reads a string from the stream, copies it to the heap
and returns a pointer to this copy. The string is saved as a pascal
string, and hence is NOT null terminated.
\Errors
On error (e.g. not enough memory), \var{Nil} is returned.
\SeeAlso
\seefl{StrRead}{TStream.StrRead}
\end{function}

\begin{procedure}{TStream.Open}
\Declaration
Procedure TStream.Open (OpenMode: Word); Virtual;
\Description
\var{Open} is an abstract method, that should be overridden by descendent
objects. Since opening a stream depends on the stream's type this is not
surprising.
\Errors
None.
\SeeAlso
\seepl{Close}{TStream.Close}, \seepl{Reset}{TStream.Reset}
\end{procedure}

\begin{procedure}{TStream.Close}
\Declaration
Procedure TStream.Close; Virtual;
\Description
\var{Close} is an abstract method, that should be overridden by descendent
objects. Since Closing a stream depends on the stream's type this is not
surprising.
\Errors
None.
\SeeAlso
\seepl{Open}{TStream.Open}, \seepl{Reset}{TStream.Reset}
\end{procedure}

\begin{procedure}{TStream.Reset}
\Declaration
PROCEDURE TStream.Reset;
\Description
\var{Reset} sets the stream's status to \var{0}, as well as the ErrorInfo
\Errors
None.
\SeeAlso
\seepl{Open}{TStream.Open}, \seepl{Close}{TStream.Close}
\end{procedure}

\begin{procedure}{TStream.Flush}
\Declaration 
Procedure TStream.Flush; Virtual;
\Description
\var{Flush} is an abstract method that should be overridden by descendent
objects. It serves to enable the programmer to tell streams that implement 
a buffer to clear the buffer.
\Errors
None.
\SeeAlso
\seepl{Truncate}{TStream.Truncate}
\end{procedure}

\begin{procedure}{TStream.Truncate}
\Declaration
Procedure TStream.Truncate; Virtual;
\Description
\var{Truncate} is an abstract procedure that should be overridden by
descendent objects. It serves to enable the programmer to truncate the
size of the stream to the current file position.
\Errors
None.
\SeeAlso
\seepl{Seek}{TStream.Seek}
\end{procedure}

\begin{procedure}{TStream.Put}
\Declaration
Procedure TStream.Put (P: PObject);
\Description
\var{Put} writes the object pointed to by \var{P}. \var{P} should be
non-nil. The object type must have been registered with \seep{RegisterType}.

After the object has been written, it can be read again with \seefl{Get}{TStream.Get}.
\Errors
No check is done whether P is \var{Nil} or not. Passing \var{Nil} will cause
a run-time error 216 to be generated. If the object has not been registered,
the status of the stream will be set to \var{stPutError}.
\SeeAlso
\seefl{Get}{TStream.Get}
\end{procedure}

\begin{procedure}{TStream.StrWrite}
\Declaration
Procedure TStream.StrWrite (P: PChar);
\Description
\var{StrWrite} writes the null-terminated string \var{P} to the stream.
\var{P} can only be 65355 bytes long.
\Errors
None.
\SeeAlso
\seepl{WriteStr}{TStream.WriteStr}, \seefl{StrRead}{TStream.StrRead},
\seefl{ReadStr}{TStream.ReadStr}
\end{procedure}

\begin{procedure}{TStream.WriteStr}
\Declaration
Procedure TStream.WriteStr (P: PString);
\Description
\var{StrWrite} writes the pascal string pointed to by \var{P} to the stream.
\Errors
None.
\SeeAlso
\seepl{StrWrite}{TStream.StrWrite}, \seefl{StrRead}{TStream.StrRead},
\seefl{ReadStr}{TStream.ReadStr}
\end{procedure}

\begin{procedure}{TStream.Seek}
\Declaration      
PROCEDURE TStream.Seek (Pos: LongInt); Virtual;
\Description
Seek sets the position to \var{Pos}. This position is counted
from the beginning, and is zero based. (i.e. seeek(0) sets the position
pointer on the first byte of the stream)
\Errors
If \var{Pos} is larger than the stream size, \var{Status} is set to
\var{StSeekError}.
\SeeAlso
\seefl{GetPos}{TStream.GetPos}, \seefl{GetSize}{TStream.GetSize}
\end{procedure}

\begin{procedure}{TStream.Error}
\Declaration
Procedure TStream.Error (Code, Info: Integer); Virtual;
\Description
\var{Error} sets the stream's status to \var{Code} and \var{ErrorInfo}
to \var{Info}. If the \var{StreamError} procedural variable is set,
\var{Error} executes it, passing \var{Self} as an argument.

This method should not be called directly from a program. It is intended to
be used in descendent objects.
\Errors
None.
\SeeAlso
\end{procedure}

\begin{procedure}{TStream.Read}
\Declaration
Procedure TStream.Read (Var Buf; Count: Sw\_Word); Virtual;
\Description
\var{Read} is an abstract method that should be overridden by descendent
objects.

\var{Read} reads \var{Count} bytes from the stream into \var{Buf}.
It updates the position pointer, increasing it's value with \var{Count}. 
\var{Buf} must be large enough to contain \var{Count} bytes.
\Errors
No checking is done to see if \var{Buf} is large enough to contain
\var{Count} bytes. 
\SeeAlso
\seepl{Write}{TStream.Write}, \seefl{ReadStr}{TStream.ReadStr},
\seefl{StrRead}{TStream.StrRead}
\end{procedure}

\begin{procedure}{TStream.Write}
\Declaration
Procedure TStream.Write (Var Buf; Count: Sw\_Word); Virtual;
\Description
\var{Write} is an abstract method that should be overridden by descendent
objects.

\var{Write} writes \var{Count} bytes to the stream from \var{Buf}.
It updates the position pointer, increasing it's value with \var{Count}. 
\Errors
No checking is done to see if \var{Buf} actually contains \var{Count} bytes. 
\SeeAlso
\seepl{Read}{TStream.Read}, \seepl{WriteStr}{TStream.WriteStr},
\seepl{StrWrite}{TStream.StrWrite}
\end{procedure}

\begin{procedure}{TStream.CopyFrom}
\Declaration
Procedure TStream.CopyFrom (Var S: TStream; Count: Longint);
\Description
\var{CopyFrom} reads Count bytes from stream \var{S} and stores them
in the current stream. It uses the \seepl{Read}{TStream.Read} method
to read the data, and the \seepl{Write}{TStream.Write} method to
write in the current stream.
\Errors
None.
\SeeAlso
\seepl{Read}{TStream.Read}, \seepl{Write}{TStream.Write}
\end{procedure}

\section{TDosStream}
\label{se:TDosStream}

\var{TDosStream} is a steam that stores it's contents in a file.
it overrides a couple of methods of \var{TSteam} for this.

In addition to the fields inherited from \var{TStream} (see \sees{TStream}),
there are some extra fields, that describe the file. (mainly the name and
the OS file handle)

No buffering in memory is done when using \var{TDosStream}. 
All data are written directly to the file. For a stream that buffers 
in memory, see \sees{TBufStream}.

Here is the full declaration of the \var{TDosStream} object:
\begin{verbatim}
TYPE
   TDosStream = OBJECT (TStream)
         Handle: THandle; { DOS file handle }
         FName : AsciiZ;  { AsciiZ filename }
      CONSTRUCTOR Init (FileName: FNameStr; Mode: Word);
      DESTRUCTOR Done; Virtual;
      PROCEDURE Close; Virtual;
      PROCEDURE Truncate; Virtual;
      PROCEDURE Seek (Pos: LongInt); Virtual;
      PROCEDURE Open (OpenMode: Word); Virtual;
      PROCEDURE Read (Var Buf; Count: Sw_Word); Virtual;
      PROCEDURE Write (Var Buf; Count: Sw_Word); Virtual;
   END;
   PDosStream = ^TDosStream;
\end{verbatim}

\begin{procedure}{TDosStream.Init}
\Declaration
Constructor Init (FileName: FNameStr; Mode: Word);
\Description
\var{Init} instantiates an instance of \var{TDosStream}. The name of the 
file that contains (or will contain) the data of the stream is given in
\var{FileName}. The \var{Mode} parameter determines whether a new file 
should be created and what access rights you have on the file. 
It can be one of the following constants:
\begin{description}
\item[stCreate] Creates a new file.
\item[stOpenRead] Read access only.
\item[stOpenWrite] Write access only.
\item[stOpen] Read and write access.
\end{description}
\Errors
On error, \var{Status} is set to \var{stInitError}, and \var{ErrorInfo}
is set to the \dos error code.
\SeeAlso
\seepl{Done}{TDosStream.Done}
\end{procedure}

\begin{procedure}{TDosStream.Done}
\Declaration
Destructor TDosStream.Done; Virtual;
\Description
\var{Done} closes the file if it was open and cleans up the 
instance of \var{TDosStream}. 
\Errors
None.
\SeeAlso
\seepl{Init}{TDosStream.Init},
\seepl{Close}{TDosStream.Close}
\end{procedure}

\begin{procedure}{TDosStream.Close}
\Declaration
Pocedure TDosStream.Close; Virtual;
\Description
\var{Close} closes the file if it was open, and sets \var{Handle} to -1. 
Contrary to \seepl{Done}{TDosStream.Done} it does not clean up the instance
of \var{TDosStream}
\Errors
None.
\SeeAlso
\seep{TStream.Close}, \seepl{Init}{TDosStream.Init},
\seepl{Done}{TDosStream.Done}
\end{procedure}

\begin{procedure}{TDosStream.Truncate}
\Declaration
Procedure TDosStream.Truncate; Virtual;
\Description
If the status of the stream is \var{stOK}, then \var{Truncate} tries to
truncate the stream size to the current file position.
\Errors
If an error occurs, the stream's status is set to \var{stError} and
\var{ErrorInfo} is set to the OS error code.
\SeeAlso
\seep{TStream.Truncate}, \seefl{GetSize}{TStream.GetSize}
\end{procedure}

\begin{procedure}{TDosStream.Seek}
\Declaration
Procedure TDosStream.Seek (Pos: LongInt); Virtual;
\Description
If the stream's status is \var{stOK}, then \var{Seek} sets the 
file position to \var{Pos}. \var{Pos} is a zero-based offset, counted from
the beginning of the file.
\Errors
In case an error occurs, the stream's status is set to \var{stSeekError},
and the OS error code is stored in \var{ErrorInfo}.
\SeeAlso
\seep{TStream.Seek}, \seefl{GetPos}{TStream.GetPos}
\end{procedure}

\begin{procedure}{TDosStream.Open}
\Declaration
Procedure TDosStream.Open (OpenMode: Word); Virtual;
\Description
If the stream's status is \var{stOK}, and the stream is closed then
\var{Open} re-opens the file stream with mode \var{OpenMode}.
This call can be used after a \seepl{Close}{TDosStream.Close} call.
\Errors
If an error occurs when re-opening the file, then \var{Status} is set
to \var{stOpenError}, and the OS error code is stored in \var{ErrorInfo}
\SeeAlso
\seep{TStream.Open}, \seepl{Close}{TDosStream.Close}
\end{procedure}

\begin{procedure}{TDosStream.Read}
\Declaration
Procedure TDosStream.Read (Var Buf; Count: Sw\_Word); Virtual;
\Description
If the Stream is open and the stream status is \var{stOK} then 
\var{Read} will read \var{Count} bytes from the stream and place them
in  \var{Buf}.
\Errors
In case of an error, \var{Status} is set to \var{StReadError}, and
\var{ErrorInfo} gets the OS specific error, or 0 when an attempt was
made to read beyond the end of the stream.
\SeeAlso
\seep{TStream.Read}, \seepl{Write}{TDosStream.Write}
\end{procedure}

\begin{procedure}{TDosStream.Write}
\Declaration
Procedure TDosStream.Write (Var Buf; Count: Sw\_Word); Virtual;
\Description
If the Stream is open and the stream status is \var{stOK} then 
\var{Write} will write \var{Count} bytes from \var{Buf} and place them
in the stream.
\Errors
In case of an error, \var{Status} is set to \var{StWriteError}, and
\var{ErrorInfo} gets the OS specific error.
\SeeAlso
\seep{TStream.Write}, \seepl{Read}{TDosStream.Read}

\end{procedure}

\section{TBufStream}
\label{se:TBufStream}

\var{Bufstream} implements a buffered file stream. That is, all data written
to the stream is written to memory first. Only when the buffer is full, or
on explicit request, the data is written to disk.

Also, when reading from the stream, first the buffer is checked if there is
any unread data in it. If so, this is read first. If not the buffer is
filled again, and then the data is read from the buffer.

The size of the buffer is fixed and is set when constructing the file.

This is useful if you need heavy throughput for your stream, because it
speeds up operations.

\begin{verbatim}
TYPE
   TBufStream = OBJECT (TDosStream)
         LastMode: Byte;       { Last buffer mode }
         BufSize : Sw_Word;    { Buffer size }
         BufPtr  : Sw_Word;    { Buffer start }
         BufEnd  : Sw_Word;    { Buffer end }
         Buffer  : PByteArray; { Buffer allocated }
      CONSTRUCTOR Init (FileName: FNameStr; Mode, Size: Word);
      DESTRUCTOR Done; Virtual;
      PROCEDURE Close; Virtual;
      PROCEDURE Flush; Virtual;
      PROCEDURE Truncate; Virtual;
      PROCEDURE Seek (Pos: LongInt); Virtual;
      PROCEDURE Open (OpenMode: Word); Virtual;
      PROCEDURE Read (Var Buf; Count: Sw_Word); Virtual;
      PROCEDURE Write (Var Buf; Count: Sw_Word); Virtual;
   END;
   PBufStream = ^TBufStream;
\end{verbatim}

\begin{procedure}{TBufStream.Init}
\Declaration
Constructor Init (FileName: FNameStr; Mode,Size: Word);
\Description
\var{Init} instantiates an instance of \var{TBufStream}. The name of the 
file that contains (or will contain) the data of the stream is given in
\var{FileName}. The \var{Mode} parameter determines whether a new file 
should be created and what access rights you have on the file. 
It can be one of the following constants:
\begin{description}
\item[stCreate] Creates a new file.
\item[stOpenRead] Read access only.
\item[stOpenWrite] Write access only.
\item[stOpen] Read and write access.
\end{description}
The \var{Size} parameter determines the size of the buffer that will be
created. It should be different from zero.
\Errors
On error, \var{Status} is set to \var{stInitError}, and \var{ErrorInfo}
is set to the \dos error code.
\SeeAlso
\seep{TDosStream.Init}, \seepl{Done}{TBufStream.Done}
\end{procedure}

\begin{procedure}{TBufStream.Done}
\Declaration
Destructor TBufStream.Done; Virtual;
\Description
\var{Done} flushes and closes the file if it was open and cleans up the 
instance of \var{TBufStream}. 
\Errors
None.
\SeeAlso
\seep{TDosStream.Done}, \seepl{Init}{TBufStream.Init},
\seepl{Close}{TBufStream.Close}
\end{procedure}

\begin{procedure}{TBufStream.Close}
\Declaration
Pocedure TBufStream.Close; Virtual;
\Description
\var{Close} flushes and closes the file if it was open, and sets \var{Handle} to -1. 
Contrary to \seepl{Done}{TBufStream.Done} it does not clean up the instance
of \var{TBufStream}
\Errors
None.
\SeeAlso
\seep{TStream.Close}, \seepl{Init}{TBufStream.Init},
\seepl{Done}{TBufStream.Done}
\end{procedure}

\begin{procedure}{TBufStream.Flush}
\Declaration
Pocedure TBufStream.Flush; Virtual;
\Description
When the stream is in write mode, the contents of the buffer are written to
disk, and the buffer position is set to zero.

When the stream is in read mode, the buffer position is set to zero.
\Errors
Write errors may occur if the file was in write mode.
see \seepl{Write}{TBufStream.Write} for more info on the errors.
\SeeAlso
\seep{TStream.Close}, \seepl{Init}{TBufStream.Init},
\seepl{Done}{TBufStream.Done}
\end{procedure}

\begin{procedure}{TBufStream.Truncate}
\Declaration
Procedure TBufStream.Truncate; Virtual;
\Description
If the status of the stream is \var{stOK}, then \var{Truncate} tries to
flush the buffer, and then truncates the stream size to the current 
file position.
\Errors
Errors can be those of \seepl{Flush}{TBufStream.Flush} or
\seep{TDosStream.Truncate}.
\SeeAlso
\seep{TStream.Truncate}, \seep{TDosStream.Truncate},
\seefl{GetSize}{TStream.GetSize}
\end{procedure}

\begin{procedure}{TBufStream.Seek}
\Declaration
Procedure TBufStream.Seek (Pos: LongInt); Virtual;
\Description
If the stream's status is \var{stOK}, then \var{Seek} sets the 
file position to \var{Pos}. \var{Pos} is a zero-based offset, counted from
the beginning of the file.
\Errors
In case an error occurs, the stream's status is set to \var{stSeekError},
and the OS error code is stored in \var{ErrorInfo}.
\SeeAlso
\seep{TStream.Seek}, \seefl{GetPos}{TStream.GetPos}
\end{procedure}

\begin{procedure}{TBufStream.Open}
\Declaration
Procedure TBufStream.Open (OpenMode: Word); Virtual;
\Description
If the stream's status is \var{stOK}, and the stream is closed then
\var{Open} re-opens the file stream with mode \var{OpenMode}.
This call can be used after a \seepl{Close}{TBufStream.Close} call.
\Errors
If an error occurs when re-opening the file, then \var{Status} is set
to \var{stOpenError}, and the OS error code is stored in \var{ErrorInfo}
\SeeAlso
\seep{TStream.Open}, \seepl{Close}{TBufStream.Close}
\end{procedure}

\begin{procedure}{TBufStream.Read}
\Declaration
Procedure TBufStream.Read (Var Buf; Count: Sw\_Word); Virtual;
\Description
If the Stream is open and the stream status is \var{stOK} then 
\var{Read} will read \var{Count} bytes from the stream and place them
in  \var{Buf}.

\var{Read} will first try to read the data from the stream's internal
buffer. If insufficient data is available, the buffer will be filled before
contiunuing to read. This process is repeated until all needed data 
has been read.

\Errors
In case of an error, \var{Status} is set to \var{StReadError}, and
\var{ErrorInfo} gets the OS specific error, or 0 when an attempt was
made to read beyond the end of the stream.
\SeeAlso
\seep{TStream.Read}, \seepl{Write}{TBufStream.Write}
\end{procedure}

\begin{procedure}{TBufStream.Write}
\Declaration
Procedure TBufStream.Write (Var Buf; Count: Sw\_Word); Virtual;
\Description
If the Stream is open and the stream status is \var{stOK} then 
\var{Write} will write \var{Count} bytes from \var{Buf} and place them
in the stream.

\var{Write} will first try to write the data to the stream's internal
buffer. When the internal buffer is full, then the contents will be written 
to disk. This process is repeated until all data has been written.
\Errors
In case of an error, \var{Status} is set to \var{StWriteError}, and
\var{ErrorInfo} gets the OS specific error.
\SeeAlso
\seep{TStream.Write}, \seepl{Read}{TBufStream.Read}

\end{procedure}

\section{TMemoryStream}
\section{se:TMemoryStream}

\begin{verbatim}
TYPE
   TMemoryStream = OBJECT (TStream)
         BlkCount: Sw_Word;                           { Number of segments }
         BlkSize : Word;                              { Memory block size }
         MemSize : LongInt;                           { Memory alloc size }
         BlkList : PPointerArray;                     { Memory block list }
      CONSTRUCTOR Init (ALimit: Longint; ABlockSize: Word);
      DESTRUCTOR Done;                                               Virtual;
      PROCEDURE Truncate;                                            Virtual;
      PROCEDURE Read (Var Buf; Count: Sw_Word);                      Virtual;
      PROCEDURE Write (Var Buf; Count: Sw_Word);                     Virtual;
      PRIVATE
      FUNCTION ChangeListSize (ALimit: Sw_Word): Boolean;
   END;
   PMemoryStream = ^TMemoryStream;
\end{verbatim}

\section{TCollection}
\label{se:TCollection}

\begin{verbatim}
TYPE
   TItemList = Array [0..MaxCollectionSize - 1] Of Pointer;
   PItemList = ^TItemList;

   TCollection = OBJECT (TObject)
         Items: PItemList;  { Item list pointer }
         Count: Sw_Integer; { Item count }
         Limit: Sw_Integer; { Item limit count }
         Delta: Sw_Integer; { Inc delta size }
      CONSTRUCTOR Init (ALimit, ADelta: Sw_Integer);
      CONSTRUCTOR Load (Var S: TStream);
      DESTRUCTOR Done; Virtual;
      FUNCTION At (Index: Sw_Integer): Pointer;
      FUNCTION IndexOf (Item: Pointer): Sw_Integer; Virtual;
      FUNCTION GetItem (Var S: TStream): Pointer; Virtual;
      FUNCTION LastThat (Test: Pointer): Pointer;
      FUNCTION FirstThat (Test: Pointer): Pointer;
      PROCEDURE Pack;
      PROCEDURE FreeAll;
      PROCEDURE DeleteAll;
      PROCEDURE Free (Item: Pointer);
      PROCEDURE Insert (Item: Pointer); Virtual;
      PROCEDURE Delete (Item: Pointer);
      PROCEDURE AtFree (Index: Sw_Integer);
      PROCEDURE FreeItem (Item: Pointer); Virtual;
      PROCEDURE AtDelete (Index: Sw_Integer);
      PROCEDURE ForEach (Action: Pointer);
      PROCEDURE SetLimit (ALimit: Sw_Integer); Virtual;
      PROCEDURE Error (Code, Info: Integer); Virtual;
      PROCEDURE AtPut (Index: Sw_Integer; Item: Pointer);
      PROCEDURE AtInsert (Index: Sw_Integer; Item: Pointer);
      PROCEDURE Store (Var S: TStream);
      PROCEDURE PutItem (Var S: TStream; Item: Pointer); Virtual;
   END;
   PCollection = ^TCollection;
\end{verbatim}

\section{TSortedCollection}
\label{se:TSortedCollection}

\begin{verbatim}
TYPE
   TSortedCollection = OBJECT (TCollection)
         Duplicates: Boolean; { Duplicates flag }
      CONSTRUCTOR Init (ALimit, ADelta: Sw_Integer);
      CONSTRUCTOR Load (Var S: TStream);
      FUNCTION KeyOf (Item: Pointer): Pointer; Virtual;
      FUNCTION IndexOf (Item: Pointer): Sw_Integer; Virtual;
      FUNCTION Compare (Key1, Key2: Pointer): Sw_Integer; Virtual;
      FUNCTION Search (Key: Pointer; Var Index: Sw_Integer): Boolean;Virtual;
      PROCEDURE Insert (Item: Pointer); Virtual;
      PROCEDURE Store (Var S: TStream);
   END;
   PSortedCollection = ^TSortedCollection;
\end{verbatim}

\section{TStringCollection}
\label{se:TStringCollection}

\begin{verbatim}
TYPE
   TStringCollection = OBJECT (TSortedCollection)
      FUNCTION GetItem (Var S: TStream): Pointer; Virtual;
      FUNCTION Compare (Key1, Key2: Pointer): Sw_Integer; Virtual;
      PROCEDURE FreeItem (Item: Pointer); Virtual;
      PROCEDURE PutItem (Var S: TStream; Item: Pointer); Virtual;
   END;
   PStringCollection = ^TStringCollection;
\end{verbatim}

\section{TStrCollection}
\label{se:TStrCollection}

\begin{verbatim}
TYPE
   TStrCollection = OBJECT (TSortedCollection)
      FUNCTION Compare (Key1, Key2: Pointer): Sw_Integer; Virtual;
      FUNCTION GetItem (Var S: TStream): Pointer; Virtual;
      PROCEDURE FreeItem (Item: Pointer); Virtual;
      PROCEDURE PutItem (Var S: TStream; Item: Pointer); Virtual;
   END;
   PStrCollection = ^TStrCollection;
\end{verbatim}


\section{TUnSortedStrCollection}
\label{se:TUnSortedStrCollection}

\begin{verbatim}
TYPE
   TUnSortedStrCollection = OBJECT (TStringCollection)
      PROCEDURE Insert (Item: Pointer); Virtual;
   END;
   PUnSortedStrCollection = ^TUnSortedStrCollection;
\end{verbatim}

\section{TResourceCollection}
\label{se:TResourceCollection}

\begin{verbatim}
TYPE
   TResourceCollection = OBJECT (TStringCollection)
      FUNCTION KeyOf (Item: Pointer): Pointer; Virtual;
      FUNCTION GetItem (Var S: TStream): Pointer; Virtual;
      PROCEDURE FreeItem (Item: Pointer); Virtual;
      PROCEDURE PutItem (Var S: TStream; Item: Pointer); Virtual;
   END;
   PResourceCollection = ^TResourceCollection;
\end{verbatim}

\section{TResourceFile}
\label{se:TResourceFile}

\begin{verbatim}
TYPE
   TResourceFile = OBJECT (TObject)
         Stream  : PStream; { File as a stream }
         Modified: Boolean; { Modified flag }
      CONSTRUCTOR Init (AStream: PStream);
      DESTRUCTOR Done; Virtual;
      FUNCTION Count: Sw_Integer;
      FUNCTION KeyAt (I: Sw_Integer): String;
      FUNCTION Get (Key: String): PObject;
      FUNCTION SwitchTo (AStream: PStream; Pack: Boolean): PStream;
      PROCEDURE Flush;
      PROCEDURE Delete (Key: String);
      PROCEDURE Put (Item: PObject; Key: String);
   END;
   PResourceFile = ^TResourceFile;
\end{verbatim}

\section{TStringList}
\label{se:TStringList}

\begin{verbatim}
TYPE
   TStrIndexRec = Packed RECORD
      Key, Count, Offset: Word;
   END;

   TStrIndex = Array [0..9999] Of TStrIndexRec;
   PStrIndex = ^TStrIndex;

   TStringList = OBJECT (TObject)
      CONSTRUCTOR Load (Var S: TStream);
      DESTRUCTOR Done; Virtual;
      FUNCTION Get (Key: Sw_Word): String;
   END;
   PStringList = ^TStringList;
\end{verbatim}

\section{TStrListMaker}
\label{se:TStrListMaker}

\begin{verbatim}
TYPE
   TStrListMaker = OBJECT (TObject)
      CONSTRUCTOR Init (AStrSize, AIndexSize: Sw_Word);
      DESTRUCTOR Done; Virtual;
      PROCEDURE Put (Key: Sw_Word; S: String);
      PROCEDURE Store (Var S: TStream);
   END;
   PStrListMaker = ^TStrListMaker;
\end{verbatim}

\begin{verbatim}
FUNCTION NewStr (Const S: String): PString;
PROCEDURE DisposeStr (P: PString);
PROCEDURE Abstract;
PROCEDURE RegisterObjects;
\end{verbatim}
\begin{procedure}{RegisterType}
\Declaration
PROCEDURE RegisterType (Var S: TStreamRec);
\end{procedure}
\begin{verbatim}
FUNCTION LongMul (X, Y: Integer): LongInt;
FUNCTION LongDiv (X: Longint; Y: Integer): Integer;

CONST
   StreamError: Pointer = Nil;                        { Stream error ptr }
   DosStreamError: Word = $0;                      { Dos stream error }

CONST
   RCollection: TStreamRec = (
     ObjType: 50;
     VmtLink: Ofs(TypeOf(TCollection)^);
     Load: @TCollection.Load;
     Store: @TCollection.Store);

   RStringCollection: TStreamRec = (
     ObjType: 51;
     VmtLink: Ofs(TypeOf(TStringCollection)^);
     Load: @TStringCollection.Load;
     Store: @TStringCollection.Store);

   RStrCollection: TStreamRec = (
     ObjType: 69;
     VmtLink: Ofs(TypeOf(TStrCollection)^);
     Load:    @TStrCollection.Load;
     Store:   @TStrCollection.Store);

   RStringList: TStreamRec = (
     ObjType: 52;
     VmtLink: Ofs(TypeOf(TStringList)^);
     Load: @TStringList.Load;
     Store: Nil);

   RStrListMaker: TStreamRec = (
     ObjType: 52;
     VmtLink: Ofs(TypeOf(TStrListMaker)^);
     Load: Nil;
     Store: @TStrListMaker.Store);
\end{verbatim}