home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / STREAM15.ZIP / STREAMS.DOC < prev    next >
Encoding:
Text File  |  1993-03-28  |  54.3 KB  |  1,466 lines

  1. STREAMS - TP/BP/TPW unit to supplement TurboVision/ObjectWindows streams
  2.  
  3.      Version 1.5.  Copyright D.J. Murdoch (1992,1993).
  4.  
  5. DESCRIPTION
  6.  
  7.      "Wierd Stream Tricks" might be a good name for this unit.  It
  8.      contains a miscellaneous collection of objects and procedures, all
  9.      on a theme of adding functionality to the streams in Borland's
  10.      Turbo Pascal libraries TurboVision and ObjectWindows.
  11.  
  12.      Most of my testing has been in TP 6 and BP 7 real mode; the code
  13.      and demos also appear to work in BP 7 protected mode, and compile
  14.      under Windows, but use it with care in those "foreign"
  15.      environments.
  16.  
  17.  
  18. LICENSE
  19.  
  20.      This unit is *not* public domain code.  You may use it for
  21.      non-profit purposes at no charge if credit is granted, but written
  22.      permission must be obtained from me for use of this unit in
  23.      commercial products.
  24.  
  25.      A lot of the code in this unit is code that's been made freely
  26.      available by others, some of it under their copyright, other parts
  27.      public domain.  As far as I know, all code included here may be
  28.      used non-commercially for free.  See the list of credits at the end
  29.      for all the (known) authors.
  30.  
  31.      This is the third release of the STREAMS unit.  There are probably
  32.      still bugs; I would really appreciate reports of any, or other
  33.      suggestions for improvement.  Please send either one to me at one
  34.      of the following addresses:
  35.  
  36.        dmurdoch@mast.queensu.ca (Internet)
  37.        71631,122 (Compuserve)
  38.        DJ Murdoch at 1:249/99.5 (Fidonet)
  39.  
  40.        D. J. Murdoch
  41.        337 Willingdon Ave.
  42.        Kingston, Ontario, Canada
  43.        K7L 4J3
  44.  
  45.  
  46. SUMMARY
  47.  
  48. Hierarchy
  49.  
  50.    TStream                  (from Objects)
  51.      TFilter                Base type for filters
  52.        TEncryptFilter       Encrypts as it writes; decrypts as it reads
  53.        TLZWFilter           Compresses as it writes; expands as it reads
  54.        TTextFilter          Provides text file interface to stream
  55.        TLogFilter           Provides logging of text file activity
  56.        TBitFilter           Allows bit-oriented I/O
  57.        TDupFilter           Duplicates output, checks for matching input
  58.        TConcatFilter        Concatenates two streams together
  59.        TLimitFilter         Limits I/O to a certain byte range
  60.          TLoopFilter        Makes stream look like a tape loop
  61.        TReverseFilter       Reads and writes a stream in reverse order
  62.        TSequential          Filter that doesn't allow Seek
  63.          TChksumFilter      Calculates 8 or 16 bit checksum for reads/writes
  64.          TCRC16Filter       Calculates XMODEM style 16 bit CRC
  65.          TCRCARCFilter      Calculates ARC style 16 bit CRC
  66.          TCRC32Filter       Calculates ZIP & Zmodem style 32 bit CRC
  67.      TNulStream             Eats writes, returns constant on reads
  68.      TRAMStream             Stream in memory
  69.      TXMSStream             Stream in XMS (extended) memory
  70.      TDOSStream             (from Objects)
  71.        TBufStream           (from Objects)
  72.          TNamedBufStream    Buffered file stream that knows its name
  73.            TTempBufStream   Buffered file stream that erases itself when done
  74.      TWorkStream            Stream that grows as needed
  75.  
  76. Procedures & functions:
  77.  
  78.    TempStream      allocates a temporary stream
  79.    StreamName      returns a stream type name (for debugging)
  80.    OvrInitStream   like OvrInitEMS, but buffers overlays on a stream
  81.                    May be called several times to buffer different
  82.                    segments on different streams.
  83.    OvrDetachStream detaches stream from overlay system
  84.    OvrDisposeStreams detaches all streams from overlay system and disposes of
  85.                    them
  86.    OvrSizeNeeded   Calculates the size needed to load the rest of the segments
  87.                    to a stream
  88.    OvrLoadAll      immediately copies as many overlay segments to the stream
  89.                    as will fit
  90.    xms_MemAvail    returns the number of bytes of XMS memory available
  91.    xms_MaxAvail    returns size in bytes of the largest block of XMS memory
  92.    ems_MemAvail    returns the number of bytes of EMS memory available
  93.    ems_MaxAvail    returns size in bytes of the largest block of EMS memory
  94.    disk_MemAvail   returns the number of bytes of temp disk space available
  95.    disk_MaxAvail   returns size in bytes of the largest block of disk space
  96.  
  97.  
  98. Reassuring Note:
  99.  
  100.      One concern I've heard from people about using this unit:  it's
  101.      big. Won't 90K of source add a lot of code to my program, even if I
  102.      only need one little part of it?  The simple answer is no.  I've
  103.      tried very hard to write Streams so that cross-links between code
  104.      are minimized.  If all you need are the XMS routines, that's all
  105.      that TP's "smart linker" will link into your .EXE.  Same for most
  106.      of the other objects and functions. One exception is the TempStream
  107.      function (Chapter 17).  Because it makes explicit references to 4
  108.      types of streams, one call to it will necessarily pull in support
  109.      code for all 4 types.  That's only about 6K, though.  StreamName is
  110.      much worse: it pulls in code for *every* stream type.  It should
  111.      only be used for debugging.
  112.  
  113.  
  114. CONTENTS
  115.      0.  Files in archive
  116.              a list of the files that should accompany this one
  117.      1.  TFilter
  118.              a generic object to act as a filter to a stream
  119.      2.  TEncryptFilter
  120.              a filter which does simple encryption/decryption
  121.      3.  TLZWFilter
  122.              a filter which does LZW compression/decompression
  123.      4.  TTextFilter
  124.              a filter to provide the Read/ReadLn/Write/WriteLn
  125.              interface to a stream
  126.      5.  TLogFilter
  127.              a filter to allow logging of activity on text files
  128.      6.  TBitFilter
  129.              a filter to allow bit level I/O to a stream
  130.      7.  TDupFilter
  131.              a filter to duplicate output, check for duplicate input
  132.      8.  TConcatFilter
  133.              a filter to concatenate two streams
  134.      9.  TLimitFilter
  135.              a filter to limit I/O to a certain byte range
  136.     10.  TLoopFilter
  137.              a filter to make a stream look like a tape loop: things wrap
  138.              around when they reach the ends
  139.     11.  TReverseFilter and ReverseBytes
  140.              a filter to reverse the apparent byte order of a stream and
  141.              a procedure to reverse the byte order of a buffer
  142.     12.  TSequential
  143.              a generic filter that can't Seek
  144.     13.  Checksum/CRC filters:
  145.              a collection of filters which calculate checksums and CRC
  146.              values as the data goes by
  147.     14.  TNulStream
  148.              a stream which counts data written to it, and which
  149.              returns a constant if you read
  150.     15.  TRAMStream
  151.              a stream which resides entirely in RAM
  152.     16.  TXMSStream
  153.              a stream which keeps its data in XMS memory
  154.     17.  xxx_MemAvail and xxx_MaxAvail
  155.              procedures to show how much memory is free
  156.     18.  TNamedBufStream
  157.              a buffered file stream which knows its own name
  158.     19.  TTempBufStream
  159.              a temporary buffered file stream, which deletes itself when
  160.              done
  161.     20.  TempStream
  162.              a procedure to allocate a temporary stream, in RAM, EMS, or
  163.              on disk, according to a specified preference
  164.     21.  TWorkStream
  165.              a temporary stream, which allocates new blocks of mixed
  166.              types as it grows.
  167.     22.  OvrInitStream and related procedures
  168.              procedures to allow overlays to be buffered on any
  169.              stream or combination of streams
  170.     23.  Miscellaneous constants and types
  171.  
  172.     24.  Release history and credits
  173.  
  174. 0.  FILES IN ARCHIVE
  175.  
  176.   Streams.doc   - this file
  177.   Streams.pas   - main source file for unit
  178.   Lzwstrea.asm  - source for LZW compression
  179.   StDefine.inc  - a few conditional compiler defines
  180.   Xmsstrm.inc   - source for XMS stream
  181.   Crc16.asm     - source for 16 bit CRC
  182.   Crc32.asm     - source for 32 bit CRC
  183.   Crcarc.asm    - source for ARC-style 16 bit CRC
  184.   Lzwstrea.obj  - assembled code for external linking
  185.   Crc16.obj     -     "      "    "     "        "
  186.   Crcarc.obj    -     "      "    "     "        "
  187.   Crc32.obj     -     "      "    "     "        "
  188.  
  189.   Demo programs:
  190.  
  191.   Encrypt.pas   -  encryption program, using TEncryptFilter
  192.   Compress.pas  -  file compressor, using TLZWFilter
  193.   Huffman.pas   -  defines a Huffman encoding filter, using TBitFilter
  194.   HuffComp.pas  -  file compressor using THuffmanFilter
  195.   Logdemo.pas   -  simple demo of TLogFilter
  196.   Ovrdemo.pas   -  simple demo of multiple overlay files
  197.    ovr1.pas     -  one overlaid unit
  198.    ovr2.pas     -  a second overlaid unit
  199.   Textdemo.pas  -  simple demo of TTextFilter
  200.  
  201.  
  202. 1.  TFilter = object(TStream)
  203.  
  204.      "Filters" are programs which take a file as input and produce a new
  205.      file as output.  TFilter is an adaptation of this idea to streams.
  206.      Every TFilter has a base stream, which can be any kind of stream.
  207.      Every TFilter is itself a stream, which means you can read and
  208.      write to it.  When you do, it just relays your request to the base
  209.      stream.
  210.  
  211.      One use of this is in the fact that you can make descendants
  212.      of TFilter which massage the data on the way to and from the Base.
  213.      Just override the Read and Write (and possibly other) methods, and
  214.      you can make changes to the data flowing to or from *any* kind of
  215.      stream.  No need for special coding for an TEMSStream, or for a
  216.      TDOSStream, or whatever.  Your code can act on any of them.
  217.      Examples of things to do are in the Streams unit:  encryption
  218.      (TEncryptFilter) and LZW compression (TLZWFilter).
  219.  
  220.      The other main use is to add other kinds of functionality to a
  221.      stream.  You can't use the formatting capabilities of ReadLn and
  222.      WriteLn with standard streams, but if you use a TTextFilter (see
  223.      below) you can.
  224.  
  225.      FIELDS
  226.  
  227.      Base : PStream;
  228.  
  229.        TFilter.Base holds the pointer to the base stream.
  230.  
  231.      StartOfs : longint;
  232.  
  233.        TFilter.StartOfs holds the offset in the base stream of offset 0
  234.        in the filter.  This allows multiple filters to work on the same
  235.        stream; one could work at offset 0, another at offset 1000, etc.
  236.        Just position the base to the desired starting offset before
  237.        initializing the filter.
  238.  
  239.      OwnsBase: Boolean;
  240.  
  241.        If false, then the Base stream is assumed to be owned by some
  242.        other part of the program, so that when Done is called, it won't
  243.        be disposed of. Normally OwnsBase is true, and it's assumed
  244.        that all management of the Base stream will be done by the
  245.        TFilter.
  246.  
  247.      METHODS
  248.  
  249.      Constructor Init(ABase: PStream);
  250.  
  251.        TFilter.Init sets Base to point to ABase^, and sets StartOfs to
  252.        the current position of the base stream.  Sets ByReference to
  253.        false.
  254.  
  255.      Destructor Done; virtual;
  256.  
  257.        If Base is not nil, then TFilter.Done calls Flush, then if
  258.        OwnsBase is true, disposes of the base stream before calling
  259.        TStream.Done for itself.
  260.  
  261.      Function CheckStatus : boolean; virtual;
  262.  
  263.        Returns true if status is stOK.  If it is, but the base status is
  264.        not stOK, then it assumes that someone has called a Reset for the
  265.        filter, so it calls Reset for the base stream.  Borland should
  266.        have made Reset virtual, and this kludge wouldn't have been
  267.        necessary!
  268.  
  269.      Procedure CheckBase;
  270.  
  271.        Checks the base stream for an error.  If Base^.status is not
  272.        stOK, then it calls Error with Code=stBaseError and
  273.        Info=Base^.status.
  274.  
  275.      Function GetPos  : longint; virtual;
  276.      Function GetSize : longint; virtual;
  277.      Procedure Read(var buf; count : word); virtual;
  278.      Procedure Seek(pos: longint); virtual;
  279.      Procedure Truncate; virtual;
  280.      Procedure Write(var buf; count: word); virtual;
  281.      Procedure Flush; virtual;
  282.  
  283.        These methods all call the corresponding method in the base
  284.        stream.  Offsets are translated using StartOfs.  Before the call,
  285.        CheckStatus is called to propagate any Reset to the base; after
  286.        the call, CheckBase is called to propagate any errors to the
  287.        filter from the base.
  288.  
  289. 2.  TEncryptFilter = object(TFilter)
  290.  
  291.        This is a filter which does simple encryption/decryption on the
  292.        base stream.  The encryption method is to XOR each byte with a
  293.        Random(256) value; the starting RandSeed is the key for the
  294.        encryption.
  295.  
  296.      FIELD
  297.  
  298.      key : longint;
  299.  
  300.        The key is used as a Randseed replacement value.  Randseed itself
  301.        is left unmodified by Read and Write.
  302.  
  303.      METHODS
  304.  
  305.      Constructor Init(Akey:longint; ABase:PStream);
  306.  
  307.        The value AKey is used as the starting key for byte 0 of the
  308.        filter.  Anything read from ABase is decrypted using this key;
  309.        anything written to it is encrypted.
  310.  
  311.      Procedure Read(var buf; count : word); virtual;
  312.      Procedure Seek(pos : longint); virtual;
  313.      Procedure Write(var buf; count: word); virtual;
  314.  
  315.        These methods all encrypt/decrypt and update the value of Key to
  316.        correspond to the new position in the stream.  The encryption
  317.        method uses the same algorithm for encryption as for decryption.
  318.        TEncryptFilter.Seek is fairly slow, because it updates the Key
  319.        once for every byte difference between the current position and
  320.        the new position.  Moving backwards is slower, because the update
  321.        algorithm is written in Pascal, not assembler as is the forward
  322.        algorithm.
  323.  
  324. 3.  TLZWFilter = object(TFilter)
  325.  
  326.        This is a filter which does LZW compression as it writes to and
  327.        decompression as it reads from the base stream.  The LZW code is
  328.        an adaptation of Wilbert van Leijen's implementation of the 12
  329.        bit LZW algorithm.  It's quite fast, though not as fast as
  330.        Wilbert's version; it gets slowed down a lot by having to save
  331.        its state after every Read and Write operation.  You're best off
  332.        writing large chunks to it to take advantage of Wilbert's
  333.        excellent code.  (Historical note:  Trying to rewrite this was
  334.        what inspired me to write FULLDB, a program which allows source
  335.        level debugging of external .ASM files. -djm)
  336.  
  337.        Each TLZWFilter takes over 28700 bytes of memory, because it
  338.        keeps extensive tables to record the current state.
  339.  
  340.        One limitation of the TLZWFilter is that it can only be opened in
  341.        read or write mode, and Seek cannot be used in write mode.  If
  342.        this doesn't suit your application, you might want to flesh out
  343.        the demo Huffman encoder (HUFFMAN.PAS), since it does allow
  344.        random access.
  345.  
  346.      FIELDS
  347.  
  348.      Mode : word;
  349.  
  350.        One of stOpenRead or stOpenWrite; the mode under which this
  351.        filter was opened.
  352.  
  353.      Size : longint;
  354.  
  355.        The size of the expanded stream.  This is the size that users of
  356.        the filter will see; if compression is working, it will generally
  357.        be bigger than Base^.GetSize.
  358.  
  359.      Position : longint;
  360.  
  361.        This is the position in the expanded stream.
  362.  
  363.      Tables : PLZWTables;
  364.  
  365.        This is a pointer to the tables used by the compression engine.
  366.        They're automatically allocated on the heap.
  367.  
  368.      METHODS
  369.  
  370.      Constructor Init(ABase:PStream; AMode:TOpenMode);
  371.  
  372.        Allocates Tables from the heap, and opens the compressor in
  373.        a mode of either stOpenRead or stOpenWrite.  If reading, a
  374.        signature and record of the uncompressed filesize is read from
  375.        the base to confirm that it is compressed by LZW, and to prime
  376.        the Tables.  If writing, the signature is written to the stream.
  377.  
  378.      Destructor Done; virtual;
  379.  
  380.        Flushes all data to the stream, and writes the uncompressed
  381.        filesize to the head of it before calling TFilter.done.
  382.  
  383.      Procedure Flush; virtual;
  384.      Function  GetPos: longint; virtual;
  385.      Function  GetSize:longint; virtual;
  386.      Procedure Read(var buf; count:word); virtual;
  387.      Procedure Seek(pos:longint); virtual;
  388.      Procedure Truncate; virtual;
  389.      Procedure Write(var buf; count: word); virtual;
  390.  
  391.        These methods all override the basic filter methods and
  392.        compress/decompress the data.  They check whether the operation
  393.        requested can be performed in the current mode, and call Error
  394.        with Code=stBadMode and Info=Mode if the operation is not
  395.        supported.
  396.  
  397.        Seek is not supported at all in Write mode.  In Read mode, it is
  398.        slow for seeking forwards, and very slow for seeking backwards:
  399.        it rewinds the file to the start and seeks forward from there by
  400.        expanding everything.
  401.  
  402.        Truncate is not supported in either mode, and always causes a
  403.        call to Error.
  404.  
  405.        Flush may only be called once; it changes Mode to 0, so any
  406.        further operations will fail.
  407.  
  408. 4.  TTextFilter = object(TFilter)
  409.  
  410.        This is a filter which provides a Read/ReadLn/Write/WriteLn
  411.        interface to a stream through its Textfile field or through any
  412.        other Text variable.  Once the filter is initialized, Textfile acts
  413.        exactly like a text file in the standard I/O procedures, but reads come
  414.        from the stream, and writes go to it.  All of the standard stream
  415.        methods work as well, by flushing the Textfile variable first.
  416.        You can also use the AssignStream method to redirect I/O for another
  417.        Text variable (e.g. System.Input or System.Output) through the filter.
  418.  
  419.        Warning:  The mechanism for reporting errors on the stream uses
  420.        the standard Turbo run-time I/O errors.  I've tried to map the
  421.        stream errors onto corresponding file errors, but sometimes the
  422.        error message may be a little misleading.
  423.  
  424.      FIELD
  425.  
  426.      Textfile : Text;
  427.  
  428.        This is the dummy text file used by default in
  429.        Read/ReadLn/Write/WriteLn.
  430.  
  431.      TextPtr : ^Text;
  432.  
  433.        This points to the currently assigned text file; typically that
  434.        will be TextFile, but if you use the AssignStream method, it may
  435.        be different.
  436.  
  437.      METHODS
  438.  
  439.      Constructor Init(ABase:PStream; AName:String);
  440.  
  441.        Initializes the filter with base ABase.  The name AName is stored
  442.        as the name in the Textfile variable.
  443.  
  444.      Destructor Done; virtual;
  445.  
  446.        Closes the TextFile variable to flush any remaining data to the
  447.        stream, and then disposes of the base stream.
  448.  
  449.      Procedure AssignStream(var NewText:text; AName:string);
  450.  
  451.        Closes the current file attached to the stream, then assigns the
  452.        new one.  You'll still need to open it for reading or writing, as
  453.        with the standard Assign procedure.
  454.  
  455.      Procedure Flush; virtual;
  456.  
  457.        Flushes the TextPtr^ variable to the base stream, then flushes the
  458.        base stream.
  459.  
  460.      function GetPos : LongInt; virtual;
  461.      function GetSize : LongInt; virtual;
  462.      procedure Read(var Buf; Count : Word); virtual;
  463.      procedure Seek(Pos : LongInt); virtual;
  464.      procedure Truncate; virtual;
  465.      procedure Write(var Buf; Count : Word); virtual;
  466.  
  467.        Versions of the standard filter functions.  These may be
  468.        intermixed with text access to the Text variable.
  469.  
  470. 5.  TLogFilter = object(TFilter)
  471.  
  472.        This filter allows logging of activity on text files to a stream.
  473.        Logging is done very transparently.  Once the TTextFilter is
  474.        initialized, you call the Log method to start logging a
  475.        particular text file, and the UnLog method to stop.  When logging
  476.        is in effect, any data read from or written to the text file is
  477.        copied to the stream.
  478.  
  479.        Multiple files may be logged to the same stream.  For example,
  480.        you can log both Input and Output, and keep a record of an
  481.        interactive session on the stream.
  482.  
  483.        It's also possible to log the same file to multiple streams.
  484.        Just create the different TLogFilter objects, and call their Log
  485.        methods with the same file as an argument.  If you then call
  486.        Unlog, you must do it in the *reverse* order to the order you
  487.        called Log, e.g.
  488.          S1^.log(output);
  489.          S2^.log(output);
  490.          S2^.unlog(output);
  491.          S1^.unlog(output);
  492.        is the correct order to log and unlog.
  493.  
  494.        One detail of the implementation may cause some trouble.  The
  495.        data is logged to the stream at the time it is written to disk by
  496.        the text file.  Since text files are buffered, this may not be
  497.        the time at which you write to the text file, and multiple text
  498.        files logged to the same stream may not have all data appearing
  499.        in the correct order.
  500.  
  501.      FIELD
  502.  
  503.      LogList : ^Text;
  504.  
  505.        This is a pointer to the first text file currently being logged.
  506.  
  507.      METHODS
  508.  
  509.      Constructor Init(ABase:PStream);
  510.  
  511.        Initializes the filter with a LogList of nil.
  512.  
  513.      Destructor done; virtual;
  514.  
  515.        Stops logging all text files by calling UnLog for each, and
  516.        closes and disposes of the base stream.
  517.  
  518.      Procedure Log(var F:text);
  519.  
  520.        Starts logging the text file F.  Continues until the UnLog method
  521.        is called or the file is closed or Assign'd.
  522.  
  523.      Function UnLog(var F:text):boolean;
  524.  
  525.        Stops logging the text file F.  Returns true if successful, false
  526.        if not.  Will fail if an Assign has been done to F, or F has been
  527.        closed, or F has already been Unlogged, or another stream has
  528.        started logging F and hasn't been UnLog'd yet.
  529.  
  530. 6.  TBitFilter = object(TFilter)
  531.  
  532.        This filter allows you to do bit-oriented I/O to a stream,
  533.        instead of the usual byte-oriented I/O.  A typical use might be
  534.        for a compression scheme:  if a word only takes the values 0 or
  535.        1, you can use a TBitFilter to be sure that it only takes up one
  536.        bit of the output file.
  537.  
  538.        If you use this filter, you can mix standard byte-oriented I/O
  539.        (Read, Write) with bit-oriented I/O (GetBit, GetBits, ReadBits,
  540.        PutBit, PutBits, WriteBits).  There's a substantial performance
  541.        penalty however, if the bytes you write to the stream aren't
  542.        aligned with the actual bytes in the base stream.
  543.  
  544.        One arbitrary choice was made:  the order of bits in a byte.
  545.        This object follows the 80x86 convention of least significant
  546.        part first, and considers the least significant bit (low bit) to
  547.        come before the most significant bit (high bit) within a byte.
  548.  
  549.      FIELDS
  550.  
  551.      BitPos : shortint;
  552.  
  553.        Position of stream relative to base file.  Negative values signal
  554.        that the buffer is unchanged from the file, positive values signal
  555.        that the file needs to be updated.  Zero signals an empty buffer.
  556.  
  557.      Mask : byte;
  558.  
  559.        The mask to use to extract the next bit from the buffer.
  560.  
  561.      Buffer : byte;
  562.  
  563.        A buffer to hold 8 bits.
  564.  
  565.      AtEnd : boolean;
  566.  
  567.        This flag is an efficiency hack.  A TBitFilter can write a single
  568.        bit anywhere in a file; this means that it has to read the
  569.        existing byte before writing a new one.  If it's doing a lot of
  570.        small writes at the end of the file, this can be incredibly slow,
  571.        because every one of those reads will fail.  The AtEnd flag
  572.        signals that the current position of the stream is the end of the
  573.        file, and a read isn't necessary.
  574.  
  575.        Normally, AtEnd is maintained internally, and you don't need to
  576.        worry about it.  However, if you increase the length of the base
  577.        stream other than by writes through the TBitFilter, you
  578.        *must* set AtEnd to false, so that the bit buffer is properly
  579.        initialized.  Calling Flush on the TBitFilter is sufficient to do
  580.        this, and would probably be a good idea before you fiddled with
  581.        the base anyways.
  582.  
  583.      METHODS
  584.  
  585.      Function GetBit : TBit;
  586.  
  587.        Type TBit is a 0 or a 1.  This function reads a single bit from
  588.        the stream.
  589.  
  590.      Function GetBits(count : byte): longint;
  591.  
  592.        This function reads up to 32 bits, and returns them in the
  593.        longint value.  The first bit read ends up in the least
  594.        significant bit of the result, and bits higher than the count
  595.        are zeroed.
  596.  
  597.      Procedure ReadBits(var buf; count : longint);
  598.  
  599.        This procedure reads up to 524288 bits (64K bytes) from the
  600.        stream into the buffer.  Reads are faster when they start on a
  601.        byte boundary.  Only the bytes that are affected by the
  602.        read will be modified, with the high bits of the last byte zeroed
  603.        if necessary.  For example, if you read fewer than 9 bits into a
  604.        word variable, the high byte of the word will be left untouched.
  605.  
  606.      Procedure PutBit(ABit : TBit);
  607.  
  608.        Write one bit to the stream.
  609.  
  610.      Procedure PutBits(Abits : longint; count : byte);
  611.  
  612.        Writes up to 32 bits to the stream.  Since ABits is a value
  613.        parameter, you can write the value of an expression directly to
  614.        the stream without storing it in an intermediate variable.
  615.  
  616.      Procedure WriteBits(var buf; count : longint);
  617.  
  618.        This procedure writes up to 524288 bits (64K bytes) to the
  619.        stream.  Writes are *much* faster if the starting bit is byte
  620.        aligned.
  621.  
  622.      Procedure SeekBit(bitpos:longint);
  623.  
  624.        Seek to a particular bit in the stream.
  625.  
  626.      Function GetBitPos : longint;
  627.  
  628.        Get the current stream position accurate to the nearest bit.
  629.  
  630.      Procedure CopyBits(var S:TBitFilter; Count:longint);
  631.  
  632.        Like CopyFrom, but for bits:  copies Count bits from S.
  633.  
  634.      Procedure ByteAlign;
  635.  
  636.        Seeks forward to the next byte boundary.  If the last byte
  637.        of the stream is only partially filled, it will be padded with
  638.        zero bits.
  639.  
  640.      Procedure Read(var Buf; Count : Word); virtual;
  641.      Procedure Write(var Buf; Count : Word); virtual;
  642.      Procedure Seek(Pos : LongInt); virtual;
  643.      Procedure Flush; virtual;
  644.  
  645.        Implement the standard byte-oriented functions.  Note that if the
  646.        base stream is not byte-aligned at the start or a read/write,
  647.        they will split each byte between two in the output stream.
  648.  
  649.      Procedure PrepareBuffer(ForRead:boolean);
  650.  
  651.        Internal method to prepare the buffer for a read or a write.
  652.  
  653. 7.  TDupFilter = object(TFilter)
  654.  
  655.        A filter which duplicates writes to two base streams, and checks
  656.        that data read from the two base streams matches.  The match test
  657.        is a virtual method, so a descendant could implement a different
  658.        test if desired.
  659.  
  660.      FIELDS
  661.  
  662.      Base2 : PStream;
  663.  
  664.         This is a pointer to the second base stream.  I/O is done first
  665.         to Base^, then to Base2^.
  666.  
  667.      Startofs2 : Longint;
  668.  
  669.         Corresponds to TFilter.StartOfs, but applies to Base2^:  gives
  670.         the offset corresponding to the filter's offset of 0.
  671.  
  672.      METHODS
  673.  
  674.      constructor Init(ABase, Abase2 : PStream);
  675.  
  676.         Sets the two base streams and the start offset variables.
  677.  
  678.      destructor Done; virtual;
  679.  
  680.         Flushes the filter, then disposes of both bases if they're not
  681.         nil.
  682.  
  683.      function MisMatch(var buf1,buf2; count:word):word; virtual;
  684.  
  685.         Checks for a mismatch between the two buffers.  Returns
  686.         the byte number of the mismatch (1 based), or 0 if they
  687.         test equal.  This default method checks for an exact match.
  688.  
  689.      procedure Read(var Buf; Count : Word); virtual;
  690.  
  691.         Reads from Base into the buffer, then does a corresponding read
  692.         from Base2 into a local buffer calling MisMatch to check for a
  693.         mismatch.  If one is found, calls the Error method to signal an
  694.         stMisMatch error, with the Info word equal to the position of
  695.         the mismatch in the current buffer.
  696.  
  697.         Unless a base error occurs, the two bases will be left
  698.         synchronized at the position following the data just read.
  699.  
  700.       procedure Seek(Pos : LongInt); virtual;
  701.       procedure Truncate; virtual;
  702.       procedure Write(var Buf; Count : Word); virtual;
  703.       procedure Flush; virtual;
  704.  
  705.         Standard methods applied to both bases.
  706.  
  707.       function CheckStatus : Boolean; virtual;
  708.  
  709.         Checks the status of the filter, and assures that both bases are
  710.         okay if status is stOK.
  711.  
  712.       procedure CheckBase2;
  713.  
  714.         Like TFilter.CheckBase, but operates on base2 and signals
  715.         stBase2Error.
  716.  
  717. 8.  TConcatFilter = object(TFilter)
  718.  
  719.         This is another two-base filter.  Unlike TDupFilter, however,
  720.         instead of treating the two bases as overlapping, this one
  721.         treats Base2 as if it follows directly after the end of Base.
  722.         Both reads and writes are directed to the appropriate base
  723.         stream.
  724.  
  725.       FIELDS
  726.  
  727.       Base2 : PStream;
  728.  
  729.         This is a pointer to the second base stream, whose contents will
  730.         appear to follow those of the Base stream.
  731.  
  732.       Startofs2 : Longint;
  733.  
  734.         Corresponds to TFilter.StartOfs, but applies to Base2^:  gives
  735.         the offset corresponding to the filter's offset of 0.
  736.  
  737.       Position : Longint;
  738.  
  739.         This is the current position of the TConcatFilter.  The
  740.         corresponding base stream to this position is kept synchronized
  741.         with it.
  742.  
  743.       Base1Size : Longint;
  744.  
  745.         This is the size of the first base stream upon initialization,
  746.         and is used in determining when to switch.  The first base will
  747.         never change in size; all writes to positions bigger than
  748.         Base1Size will be directed to the second stream.
  749.  
  750.       METHODS
  751.  
  752.       constructor Init(ABase, Abase2 : PStream);
  753.  
  754.         Sets the two base streams and the fields.  The initial position
  755.         of the stream is set to the beginning of Base2.
  756.  
  757.       destructor Done; virtual;
  758.  
  759.         Flushes the filter, then disposes of both bases if they're not
  760.         nil.
  761.  
  762.       procedure Flush; virtual;
  763.       function GetPos:longint; virtual;
  764.       function GetSize:longint; virtual;
  765.       procedure Read(var Buf; Count : Word); virtual;
  766.       procedure Seek(Pos : LongInt); virtual;
  767.       procedure Truncate; virtual;
  768.       procedure Write(var Buf; Count : Word); virtual;
  769.  
  770.         These methods work directly on Base until its size is reached,
  771.         then switch over to Base2.  Base will *never* grow from the size
  772.         at stream initialization.
  773.  
  774.      function CheckStatus : Boolean; virtual;
  775.  
  776.         Checks the status of the filter, and assures that both bases are
  777.         okay if status is stOK.
  778.  
  779.       procedure CheckBase2;
  780.  
  781.         Like TFilter.CheckBase, but operates on base2 and signals
  782.         stBase2Error.
  783.  
  784. 9.  TLimitFilter
  785.  
  786.         This is a filter that applies upper and lower limits to the
  787.         bytes that may be accessed from the base stream.  You can use it
  788.         in debugging, to detect out of range access; in programs that
  789.         allocate workspace, to limit their impact on the system; and
  790.         in other situations where you want to undo stream
  791.         concatenations.
  792.  
  793.       FIELDS
  794.  
  795.         LoLimit, HiLimit : longint;
  796.  
  797.           These two fields define the limits for accesses.  The current
  798.           position of the filter will always satisfy
  799.               LoLimit <= GetPos <= HiLimit
  800.           attempt to move it outside these limits will cause an error.
  801.  
  802.       METHODS
  803.  
  804.       constructor Init(ABase:PStream; ALoLimit,AHiLimit:Longint);
  805.  
  806.         Does the usual TFilter.Init, sets the limits, then does a Seek
  807.         to ALoLimit if it is non-zero.
  808.  
  809.       function GetSize:Longint;
  810.  
  811.         Returns the smaller of HiLimit and TFilter.GetSize.
  812.  
  813.       procedure Read(var Buf; Count : Word); virtual;
  814.       procedure Seek(Pos : LongInt); virtual;
  815.       procedure Write(var Buf; Count : Word); virtual;
  816.  
  817.         These check that the request won't move the current position
  818.         outside the limits, and raise an error if so.  If not, the
  819.         request is passed on to the TFilter method.
  820.  
  821. 10.  TLoopFilter
  822.  
  823.         This filter makes a stream look like a tape loop:  if you read
  824.         or write beyond the end, it loops back to the beginning.  It's
  825.         descended from a TLimitFilter and uses the LoLimit and the
  826.         HiLimit as the ends of the part of the base stream that you can
  827.         see.
  828.  
  829.       METHODS
  830.  
  831.       function GetSize:Longint;
  832.  
  833.         Returns the smaller of the length between the limits, or the
  834.         length from the lower limit to the end of the base stream.
  835.  
  836.       procedure Read(var Buf; Count : Word); virtual;
  837.       procedure Seek(Pos : LongInt); virtual;
  838.       procedure Write(var Buf; Count : Word); virtual;
  839.  
  840.         These all act as though on an infinitely repeating stream, by
  841.         mapping all requests back into the stream range.
  842.  
  843. 11.  TReverseFilter and ReverseBytes
  844.  
  845.         This filter lets you read or write a stream in reverse order:
  846.         both Read and Write act on the block of bytes *before* the
  847.         current file position.  The GetPos and Seek methods also work in
  848.         the reversed byte order, i.e. counting bytes from the end of the
  849.         stream instead of from the beginning.
  850.  
  851.       FIELD
  852.  
  853.       ReverseBlocks : Boolean;
  854.  
  855.         When you use a TReverseFilter, the question comes up as to
  856.         whether you want to read structures in the order in which they
  857.         were written, or whether you actually want to reverse the byte
  858.         order within each structure.  This field is used to determine that.
  859.         If ReverseBlocks is true, then the byte order appears completely
  860.         reversed.  If it's false, then when you do a read of more than 1
  861.         byte, the buffer gets the bytes in their original order.
  862.  
  863.       METHODS
  864.  
  865.       constructor init(ABase:PStream; AReverseBlocks:boolean);
  866.  
  867.         The constructor calls the standard TFilter.Init constructor,
  868.         and initializes the AReverseBlocks field.
  869.  
  870.       function GetPos:longint;
  871.       procedure Read(var Buf; Count : Word);
  872.       procedure Write(var Buf; Count : Word);
  873.       procedure Seek(Pos : LongInt);
  874.  
  875.         These methods all act on the stream in the reverse byte order.
  876.         The action of Read and Write depends on the ReverseBlocks field
  877.         described above.
  878.  
  879.       procedure Truncate;
  880.  
  881.         Truncation is not supported, and a call to this method will
  882.         trigger an stUnsupported error.
  883.  
  884.       PROCEDURE
  885.  
  886.       procedure ReverseBytes(var Buf; Count : Word);
  887.  
  888.         This procedure reverses the byte order within the buffer Buf.
  889.         It's not a TReverseFilter method, just a standard procedure.
  890.  
  891. 12.  TSequential
  892.  
  893.         This is a very simple descendant of TFilter:  the only
  894.         difference is that it signals stUnsupported if the Seek method
  895.         is called.  It's used as a base for the filters below, which can
  896.         only work sequentially.
  897.  
  898.       METHOD
  899.  
  900.       procedure Seek(pos:longint); virtual;
  901.  
  902.         Signals stUnsupported by calling Error if ever called.
  903.  
  904. 13.  Checksum/CRC filters
  905.  
  906.         These are four filters, TChkSumFilter, TCRC16Filter,
  907.         TCRCARCFilter, and TCRC32Filter, which can be used to calculate
  908.         checksums and cyclic redundancy checks (CRCs) on the stream of
  909.         data passing through the filter in either reads or writes.
  910.  
  911.         All three CRC filters are based on code by a collection of
  912.         authors:  Stephen Satchell, Chuck Forsberg, Mark G. Mendel, R.
  913.         P. Byrne, J. R. Louvau and probably others.  Edwin T. Floyd
  914.         collected them together and translated them to TASM.  The
  915.         CRC*.ASM files include more comments about sources and usage.
  916.  
  917.         The basic calculations are also available in the interfaced
  918.         procedures UpdateChksum, UpdateCRC16, UpdateCRCARC, UpdateCRC32.
  919.         See the source code for the calling details.
  920.  
  921.       TChkSumFilter = object(TSequential)
  922.  
  923.         TChkSumFilter calculates a 16 bit sum of all the bytes read from
  924.         or written to the stream.
  925.  
  926.       TCRC16Filter = object(TSequential)
  927.  
  928.         This filter calculates the same 16 bit CRC as used in XModem and
  929.         its descendants.
  930.  
  931.       TCRCARCFilter = object(TSequential)
  932.  
  933.         This filter calculates the 16 bit CRC used by ARC.
  934.  
  935.       TCRC32Filter = object(TSequential)
  936.  
  937.         This filter calculates the 32 bit CRC used by PKZIP and ZModem.
  938.  
  939.       FIELDS
  940.  
  941.       TChkSumFilter.Chksum : word;
  942.  
  943.         The 16 bit sum of all bytes passing through the filter.  If an 8
  944.         bit checksum is required, get the low byte of Chksum by using
  945.         Byte(Chksum).
  946.  
  947.       TCRC16Filter.CRC16 : word;
  948.  
  949.         The XModem-style 16 bit CRC of all bytes passing through the
  950.         filter.
  951.  
  952.       TCRCARCFilter.CRCARC : word;
  953.  
  954.         The ARC-style 16 bit CRC of all bytes passing through the
  955.         filter.
  956.  
  957.       TCRC32Filter.CRC32 : longint;
  958.  
  959.         The PKZIP and ZModem-style 32 bit CRC of all bytes passing
  960.         through the filter.  Note that the value should be inverted
  961.         before use (i.e. use "not CRC32" rather than "CRC32") for
  962.         compatibility with those programs.
  963.  
  964.       METHODS
  965.  
  966.       constructor TChkSumFilter.Init(ABase : PStream;AChksum:word);
  967.       constructor  TCRC16Filter.Init(ABase : PStream;ACRC16:word);
  968.       constructor TCRCARCFilter.Init(ABase : PStream;ACRCARC:word);
  969.       constructor  TCRC32Filter.Init(ABase : PStream;ACRC32:word);
  970.  
  971.         These constructors all initialize the filter, and set the
  972.         sum or CRC to the given value.  Typically the first three would
  973.         start with a value of 0; PKZIP and ZModem start the 32 bit CRC
  974.         with a value of $FFFFFFFF.
  975.  
  976.       procedure Read(var Buf; Count : Word); virtual;
  977.       procedure Write(var Buf; Count : Word); virtual;
  978.  
  979.         All four filters override just these two methods.  Both update
  980.         the sum or CRC if the Read/Write is successful.
  981.  
  982. 14.  TNulStream = object(TStream)
  983.  
  984.        A stream which eats your writes, and returns a constant if you
  985.        read from it.  (Suggested by Stefan Boether.)
  986.  
  987.        I can see two uses for this stream.  Stefan suggested using it to
  988.        count bytes:  if you're not sure how much space something will
  989.        take when written out, write it to a TNulStream, and then read
  990.        the size to find out.  I use it differently in the TempStream
  991.        code:  there, it's used to initialize another stream to a fixed
  992.        value.  I just copy as many bytes as I need from a TNulStream.
  993.  
  994.      FIELDS
  995.  
  996.      position : longint;
  997.  
  998.        The current position of the stream.  This is increased by both
  999.        reads and writes.  It's also used as the current size of the
  1000.        stream.
  1001.  
  1002.      value : byte;
  1003.  
  1004.        The value which will be used to fill any read request.
  1005.  
  1006.      METHODS
  1007.  
  1008.      Constructor init(Avalue : byte);
  1009.  
  1010.        Initialize the stream with value=Avalue.
  1011.  
  1012.      Destructor done; virtual;
  1013.  
  1014.        Dispose of the stream.
  1015.  
  1016.      Function getpos : longint; virtual;
  1017.      Function getsize : longint; virtual;
  1018.      Procedure read(var buf; count : word); virtual;
  1019.      Procedure seek(pos: longint); virtual;
  1020.      Procedure write(var buf; count: word); virtual;
  1021.  
  1022.        Implement the basic stream functions.
  1023.  
  1024.  
  1025. 15.  TRAMStream = object(TStream)
  1026.  
  1027.        A stream which resides entirely in RAM, either maintaining its
  1028.        own buffer, or using a predefined buffer.  The maximum length
  1029.        is 65520 bytes.
  1030.  
  1031.      FIELDS
  1032.  
  1033.      cp : word;
  1034.  
  1035.        The current pointer for the stream.
  1036.  
  1037.      size : word;
  1038.  
  1039.        The current size of the stream.
  1040.  
  1041.      alloc : word;
  1042.  
  1043.        The size of the allocated block of memory.
  1044.  
  1045.      buffer : Pbyte_array;
  1046.  
  1047.        A pointer to the block of memory holding the stream data.
  1048.  
  1049.      OwnMem : Boolean;
  1050.  
  1051.        Indicates whether the stream "owns" the buffer, and should dispose
  1052.        of it in the Done destructor.
  1053.  
  1054.      METHODS
  1055.  
  1056.      Constructor init(ASize : word);
  1057.  
  1058.        Attempt to initialize the stream to a block size of Asize;
  1059.        initial stream size and position are 0.
  1060.  
  1061.      Constructor UseBuf(Abuffer : pointer; Asize : word);
  1062.  
  1063.        Set up the stream using the given buffer; OwnMem is set to false,
  1064.        so that the memory will not be disposed when done.  Initial
  1065.        position is 0 and size is Asize.
  1066.  
  1067.      Destructor done; virtual;
  1068.  
  1069.        Dispose of the stream, and if OwnMem is true, the data buffer.
  1070.  
  1071.      Function getpos : longint; virtual;
  1072.      Function getsize : longint; virtual;
  1073.      Procedure read(var buf; count : word); virtual;
  1074.      Procedure seek(pos: longint); virtual;
  1075.      Procedure truncate; virtual;
  1076.      Procedure write(var buf; count: word); virtual;
  1077.  
  1078.        Implement the basic stream functions.
  1079.  
  1080.  
  1081. 16.  TXMSStream = object(TStream)
  1082.  
  1083.        A stream which keeps its data in XMS (extended) memory.
  1084.  
  1085.      FIELDS
  1086.  
  1087.      Handle : word;
  1088.  
  1089.        The handle used by the XMS memory manager for the stream's block
  1090.        of data.
  1091.  
  1092.      MaxBlocks : word;
  1093.  
  1094.        The maximum number of 1K blocks of memory to allocate.
  1095.  
  1096.      BlocksUsed : word;
  1097.  
  1098.        The number of 1K blocks of memory currently allocated.  Always
  1099.        allocates at least 1 byte more than Size.
  1100.  
  1101.      Size : longint;
  1102.  
  1103.        The current size of the stream.
  1104.  
  1105.      Position : longint;
  1106.  
  1107.        The current position of the stream.
  1108.  
  1109.      METHODS
  1110.  
  1111.      Constructor init(MinSize,MaxSize : longint);
  1112.  
  1113.        Attempts to allocate a block of XMS memory of at least MinSize
  1114.        bytes.  MaxSize is treated like the MaxSize parameter of
  1115.        TEMSStream.Init:  the Init will try to allocate a block that can
  1116.        grow to MaxSize, but won't signal an error if it gets a smaller
  1117.        one.  If you definitely need a certain size, specify it as
  1118.        MinSize.
  1119.  
  1120.      Destructor done; virtual;
  1121.  
  1122.        Dispose of the stream, and release the XMS memory.
  1123.  
  1124.      Function getpos : longint; virtual;
  1125.      Function getsize : longint; virtual;
  1126.      Procedure read(var buf; count : word); virtual;
  1127.      Procedure seek(pos: longint); virtual;
  1128.      Procedure truncate; virtual;
  1129.      Procedure write(var buf; count: word); virtual;
  1130.  
  1131.        Implement the basic stream functions.
  1132.  
  1133.      Procedure NewBlock;
  1134.  
  1135.        Internal method to increase the stream's allocation by one block.
  1136.  
  1137.      Procedure FreeBlock;
  1138.  
  1139.        Internal method to decrease the stream's allocation by one block.
  1140.        Doesn't check if the allocated size falls below Size.
  1141.  
  1142.  
  1143. 17.  xms_MemAvail, xms_MaxAvail, ems_MemAvail, ems_MaxAvail,
  1144.      disk_MemAvail, disk_MaxAvail
  1145.  
  1146.        These procedures are analogous to the MemAvail and MaxAvail
  1147.        procedures in the System unit.  They report on available XMS and
  1148.        EMS memory, and disk space on the drives mentioned in the
  1149.        TempEnvVar directories.  As of release 1.4, they report in bytes,
  1150.        just as the standard functions do.
  1151.  
  1152. 18.  TNamedBufStream = object(TBufStream)
  1153.  
  1154.        A simple descendant of TBufStream which knows its own name.
  1155.  
  1156.      FIELD
  1157.  
  1158.      filename : PString  { PChar in TPW };
  1159.  
  1160.        The name of the stream.
  1161.  
  1162.      METHODS
  1163.  
  1164.      Constructor Init(name:FNameStr;mode:TOpenMode;abufsize:word);
  1165.  
  1166.        Open the file with the given name, and save the name.
  1167.  
  1168.      Destructor Done; virtual;
  1169.  
  1170.        Close the file.
  1171.  
  1172. 19.  TTempBufStream = object(TNamedBufStream)
  1173.  
  1174.        A temporary buffered file stream, which deletes itself when done.
  1175.        It's allocated in one of the directories specified by TempEnvVar.
  1176.  
  1177.      METHODS
  1178.  
  1179.      Constructor init(abufsize:word;InitSize,MaxSize : Longint);
  1180.  
  1181.        Create a temporary file with a unique name, in a directory
  1182.        pointed to by the environment variable named in TempEnvVar or in
  1183.        the current directory, and open it in read/write mode.  The
  1184.        constructor will only be successful if the file can be set to
  1185.        InitSize bytes.  The directory chosen will be the first with
  1186.        at least MaxSize bytes available, or, if none has that much
  1187.        space, the one with the largest space available.
  1188.  
  1189.      Destructor done; virtual;
  1190.  
  1191.        Close and delete the temporary file.
  1192.  
  1193. 20.  Function TempStream(InitSize,MaxSize : longint;
  1194.                         Preference:TStreamRanking):PStream;
  1195.  
  1196.        This procedure returns a pointer to a temporary stream from a
  1197.        choice of 4, specified in the Preference array.  The first stream
  1198.        type listed in the Preference array which can be successfully
  1199.        created with the given sizes will be returned, or Nil if none can
  1200.        be made.
  1201.  
  1202.      ARGUMENTS
  1203.  
  1204.      Initsize : longint;
  1205.  
  1206.        The initial size to allocate to the stream.  This many nulls will
  1207.        be written to the stream, and then the position will be set to
  1208.        byte 0.
  1209.  
  1210.      MaxSize : longint;
  1211.  
  1212.        The maximum size to which the stream should be allowed to grow.
  1213.        The stream will be allocated to a particular type only if there
  1214.        are at least MaxSize bytes available at the time of the call to
  1215.        TempStream.  However, the space isn't reserved; there's no
  1216.        guarantee that the space will still be available at the time your
  1217.        stream grows to that size.
  1218.  
  1219.      Preference : TStreamRanking;
  1220.  
  1221.        An array of 4 entries specifying what sort of temporary stream is
  1222.        desired.  Supplied constants include:
  1223.  
  1224.         ForSpeed = (RAMStream, EMSStream, XMSStream, FileStream);
  1225.         ForSize  = (FileStream,EMSStream, XMSStream, RAMStream);
  1226.         ForSizeInMem = (EMSStream, XMSStream, RAMStream, NoStream);
  1227.         ForOverlays =  (EMSStream, XMSStream, FileStream, NoStream);
  1228.  
  1229. 21. TWorkStream = object(TFilter)
  1230.  
  1231.        This is a stream that can grow as you write to it. You can
  1232.        allocate it small at first, and then if it turns out that you
  1233.        need more space, it'll allocate additional blocks.  The nice
  1234.        feature of this stream as compared to the other kinds of stream
  1235.        is that when it runs out of one kind of memory (RAM, EMS, XMS, or
  1236.        disk) it'll move continue in the next.
  1237.  
  1238.        Though a descendant of TFilter, this type is more of a stream
  1239.        than a filter, because it manages its own base.  It starts out by
  1240.        allocating one block of the size you specify (see the Init method
  1241.        for the details).  If it has a write error on that block, it
  1242.        allocates a new one, and uses a TConcatFilter to attach them
  1243.        together.  In effect, this creates a linked list of streams.
  1244.  
  1245.      FIELDS
  1246.  
  1247.      Allocate : TAllocator;
  1248.  
  1249.        This is a procedural parameter pointing to the function which
  1250.        will be used to allocate the next block.  Typically TempStream
  1251.        would be used for the allocations.
  1252.  
  1253.      BlockMin,
  1254.      BlockMax : longint;
  1255.      Preference : TStreamRanking;
  1256.  
  1257.        These are the parameters which will be passed to Allocate when a
  1258.        new block is needed.  If you don't use TempStream, your allocator
  1259.        can interpret them however it likes.
  1260.  
  1261.        The field Blockmax is also used by the TWorkStream when it does
  1262.        its writes.  It splits up any write that might cross offset
  1263.        Blockmax in the current block into two writes, one on either
  1264.        side.  This means that any stream like a TRamStream that really
  1265.        has a known physical size limit will be completely filled before
  1266.        a write fails and a new block needs to be allocated.
  1267.  
  1268.      BlockStart: longint;
  1269.  
  1270.        This is the offset in the stream where the last block (the only
  1271.        one which can be expanded) starts.
  1272.  
  1273.      METHODS
  1274.  
  1275.      constructor Init(Allocator:TAllocator;ABlockmin,ABlockMax:Longint;
  1276.                       APreference : TStreamRanking);
  1277.  
  1278.        The arguments to Init serve as initial values to the fields with
  1279.        corresponding names, described above.  After those are set, Init
  1280.        does the first allocation using Allocate, and sets the result as
  1281.        the base stream.
  1282.  
  1283.      procedure Write(var Buf; Count:Word); virtual;
  1284.  
  1285.        This is the only TFilter method which TWorkStream overrides.  It
  1286.        passes most writes through to the base stream, but if an error
  1287.        occurs, it allocates a new block, concatenates it on to the
  1288.        existing part of the stream using TConcatFilter, and does the
  1289.        write there.  The only writes which don't go directly to the Base
  1290.        first are those which would cross the ABlockMax byte of the
  1291.        current block; they're split up into two parts.
  1292.  
  1293. 22. Stream overlay procedures
  1294.  
  1295.        These procedures allow overlays to be buffered on any stream or
  1296.        combination of streams.  Some overlays can be loaded into EMS,
  1297.        others kept on disk, and others can be put onto any other
  1298.        available stream.
  1299.  
  1300.      PROCEDURES/FUNCTIONS
  1301.  
  1302.      Procedure OvrInitStream(S:PStream);
  1303.  
  1304.        Copies overlay segment code to S as new segments are loaded, and
  1305.        does reloads from there.  You may call OvrInitStream multiple
  1306.        times, and different segments will be buffered on different
  1307.        streams, depending on the order in which they are loaded by the
  1308.        overlay loader.
  1309.  
  1310.        On the first call, an exit handler is installed which will call
  1311.        OvrDisposeStreams upon program termination.
  1312.  
  1313.      Procedure OvrDetachStream(BadS:PStream);
  1314.  
  1315.        Makes sure that the overlay system makes no references to BadS.
  1316.        Call this before disposing of a stream which has been passed to
  1317.        OvrInitStream, or you're very likely to crash.
  1318.  
  1319.      Procedure OvrDisposeStreams;
  1320.  
  1321.        Detaches and disposes of all streams being used by the overlay
  1322.        system.
  1323.  
  1324.      Function OvrSizeNeeded:longint;
  1325.  
  1326.        Returns the additional size required to load any segments which
  1327.        still haven't been loaded to a stream.
  1328.  
  1329.      Function OvrLoadAll:boolean;
  1330.  
  1331.        Forces all overlay segments to be copied into the stream; if
  1332.        successful (true) then no more references to the overlay file
  1333.        will be made.
  1334.  
  1335.        Warning:  This function calls OvrClearBuf, so that any overlay
  1336.        files which are already in the regular overlay buffer will need
  1337.        to be reloaded.
  1338.  
  1339. 23.  Miscellaneous constants and types
  1340.  
  1341.      CONSTANTS
  1342.  
  1343.      stBadMode = 1;
  1344.  
  1345.        Error signalled when an operation is not permitted in the current
  1346.        mode.
  1347.  
  1348.      stStreamFail = 2;
  1349.  
  1350.        Error signalled when a stream Init failed.
  1351.  
  1352.      stBaseError = 3;
  1353.  
  1354.        Error signalled by a TFilter when the base stream has an error;
  1355.        the base stream's error number is put in the Info field.
  1356.  
  1357.      stMemError = 4;
  1358.  
  1359.        Not enough memory for operation.
  1360.  
  1361.      stSigError = 5;
  1362.  
  1363.        Problem with LZW file signature.
  1364.  
  1365.      stUsedAll = 6;
  1366.  
  1367.        XMS stream has used all of its allowed blocks.
  1368.  
  1369.      stUnsupported = 7;
  1370.  
  1371.        Operation unsupported in this stream.  TSequential signals this
  1372.        error if Seek is called.
  1373.  
  1374.      stBase2Error = 8;
  1375.  
  1376.        Error in second base in a TDupFilter; Info gets the Base2^.Error
  1377.        value.
  1378.  
  1379.      stMisMatch = 9;
  1380.  
  1381.        The two bases don't match on a read.  The Info field is set to
  1382.        the position of the mismatch in the current read buffer.
  1383.  
  1384.      BufSize : word = 2048;
  1385.  
  1386.        Buffer size to use when creating a buffered file stream in
  1387.        TempStream.
  1388.  
  1389.      TempEnvVar : String[12] = 'TEMP';
  1390.  
  1391.        This is the name of the environment variable to look in for a
  1392.        list of directories when creating a TTempBufStream, or when
  1393.        reporting on available space with disk_MaxAvail or disk_MemAvail.
  1394.        If the environment variable doesn't exist, all the procedures
  1395.        treat it as though it specifies the current directory.
  1396.  
  1397.  
  1398.      TYPES
  1399.  
  1400.      TOpenMode = $3C00..$3DFF;
  1401.  
  1402.        This is the widest possible range of open modes for a TDOSStream
  1403.        descendant.  Values outside this range can cause very serious bugs in
  1404.        programs, since the high byte is used as the DOS service number
  1405.        when the file is opened.
  1406.  
  1407.      PLZWTables = ^TLZWTables;
  1408.      TLZWTables = record ...
  1409.  
  1410.        These tables are used internally to maintain the state of a
  1411.        TLZWFilter.
  1412.  
  1413.      PByte_Array = ^TByte_Array;
  1414.      TByte_Array = array[0..65520] of byte;
  1415.  
  1416.        An array type used as a buffer in several places.
  1417.  
  1418.      TStreamType = (NoStream, RAMStream, EMSStream, XMSStream, FileStream);
  1419.  
  1420.        The types of streams that TempStream can create.
  1421.  
  1422.      TStreamRanking = array[1..NumTypes] of TStreamType;
  1423.  
  1424.        An array giving the order from most preferred to least preferred
  1425.        for a temporary stream.
  1426.  
  1427.      TAllocator = function (InitSize, MaxSize : LongInt;
  1428.                             Preference : TStreamRanking) : PStream;
  1429.  
  1430.        A function like TempStream which allocates new streams.  One of
  1431.        these is used by TWorkStream to allocate new blocks.  It should
  1432.        create a stream which is at least InitSize bytes, and likely
  1433.        capable of growing to MaxSize bytes, if condition don't change.
  1434.        The Preference array indicates the desired strategy for
  1435.        allocating.
  1436.  
  1437. 24.  Release history and credits
  1438.  
  1439.      1.0 - First release, missing LZW.  Immediately replaced by
  1440.      1.1 - First correct release: TFilter, TEncryptFilter, TTextFilter,
  1441.            TLogFilter, TRAMStream, TNamedBufStream, TTempBufStream,
  1442.            TempStream, overlay procedures (my ideas), TLZWFilter
  1443.            (from code by Wilbert van Leijen)
  1444.      1.2 - TNulStream, TXMSStream added (from Stefan Boether)
  1445.            TBitFilter added (suggestion of Rene Seguin)
  1446.            TFilter.Done calls Flush
  1447.            TRAMStream.UseBuf and OwnMem added.
  1448.      1.3 - TDupFilter, TSequential, TChksumFilter added (my ideas),
  1449.            TCRC16Filter, TCRCARCFilter, TCRC32Filter and related procedures
  1450.            added (from code by Edwin T. Floyd, Stephen Satchell, Chuck
  1451.            Forsberg, Mark G. Mendel, R. P. Byrne, J. R. Louvau and
  1452.            probably others); TFilter.Flush added; HUFFMAN demo added.
  1453.      1.4 - Recoded several of the TRAMStream methods in assembler for
  1454.            more speed; fixed numerous TTextFilter bugs and added
  1455.            TTextFilter.AssignStream and TextDemo.pas; fixed
  1456.            TXMSStream.Seek bug.  Changed xms_Memavail and xms_Maxavail
  1457.            to report in bytes, and added ems_Memavail and ems_Maxavail
  1458.            (based on code sent to me by Eyal Doron) and disk_Memavail
  1459.            and disk_Maxavail. Changed TXMSStream.Init to match
  1460.            TEMSStream.Init. Added TConcatFilter, TLimitFilter,
  1461.            TLoopFilter, TReverseFilter and TWorkStream.  Added OwnsBase
  1462.            field to TFilter.  Did some testing to assure that the unit
  1463.            works in BP 7 protected mode.  Thanks to Max Maschein, Eyal
  1464.            Doron, and others for bug fix help.
  1465.      1.5 - The first public release of the 1.4 enhancements.
  1466.