home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / w3_prog / stream11.arj / STREAMS.DOC < prev    next >
Encoding:
Text File  |  1992-03-31  |  20.3 KB  |  590 lines

  1. STREAMS - TP 6.0/TPW 1.0 unit to supplement TurboVision/ObjectWindows streams
  2.  
  3.      Copyright D.J. Murdoch (1992).
  4.  
  5. DESCRIPTION
  6.  
  7.      "Wierd Stream Tricks" might be a good name for this unit.  It
  8.      contains various doodads that I've written in the past, and a few
  9.      new things, all on a theme of adding functionality to the streams
  10.      in Borland's Turbo Pascal libraries TurboVision and ObjectWindows.
  11.  
  12. LICENSE
  13.  
  14.      This unit is *not* public domain code.  You may use it for
  15.      non-profit purposes at no charge if credit is granted to me, but
  16.      written permission must be obtained from me for use of this unit in
  17.      commercial products.
  18.  
  19.      This is the first release of the STREAMS unit.  There are probably
  20.      bugs; I would really appreciate reports of any, or other
  21.      suggestions for improvement.  Please send either one to me at one
  22.      of the following addresses:
  23.  
  24.        dmurdoch@watstat.waterloo.edu (Internet)
  25.        71631,122 (Compuserve)
  26.        DJ Murdoch at Fidonet node 1:221/177.40
  27.  
  28.        D. J. Murdoch
  29.        79 John St. W.
  30.        Waterloo, Ontario, Canada
  31.        N2L 1B7
  32.  
  33.  
  34. SUMMARY
  35.  
  36. Hierarchy
  37.  
  38.    TStream                  (from Objects)
  39.      TFilter                Base type for filters
  40.        TEncryptFilter       Encrypts as it writes; decrypts as it reads
  41.        TLZWFilter           Compresses as it writes; expands as it reads
  42.        TTextFilter          Provides text file interface to stream
  43.        TLogFilter           Provides logging of text file activity
  44.      TRAMStream             Stream in memory
  45.      TDOSStream             (from Objects)
  46.        TBufStream           (from Objects)
  47.          TNamedBufStream    Buffered file stream that knows its name
  48.            TTempBufStream   Buffered file stream that erases itself when done
  49.  
  50. Procedures & functions:
  51.  
  52.    TempStream      allocates a temporary stream
  53.    OvrInitStream   like OvrInitEMS, but buffers overlays on a stream
  54.                    May be called several times to buffer different
  55.                    segments on different streams.
  56.    OvrDetachStream detaches stream from overlay system
  57.    OvrDisposeStreams detaches all streams from overlay system and disposes of
  58.                    them
  59.    OvrSizeNeeded   Calculates the size needed to load the rest of the segments
  60.                    to a stream
  61.    OvrLoadAll      immediately copies as many overlay segments to the stream
  62.                    as will fit
  63.  
  64.  
  65. CONTENTS
  66.  
  67.      1.  TFilter
  68.              a generic object to act as a filter to a stream
  69.      2.  TEncryptFilter
  70.              a filter which does simple encryption/decryption
  71.      3.  TLZWFilter
  72.              a filter which does LZW compression/decompression
  73.      4.  TTextFilter
  74.              a filter to provide the Read/ReadLn/Write/WriteLn
  75.              interface to a stream
  76.      5.  TLogFilter
  77.              a filter to allow logging of activity on text files
  78.      6.  TRAMStream
  79.              a stream which resides entirely on the heap
  80.      7.  TNamedBufStream
  81.              a buffered file stream which knows its own name
  82.      8.  TTempBufStream
  83.              a temporary buffered file stream, which deletes itself when
  84.              done
  85.      9.  TempStream
  86.              a procedure to allocate a temporary stream, in RAM, EMS, or
  87.              on disk, according to a specified preference
  88.     10.  OvrInitStream and related procedures
  89.              procedures to allow overlays to be buffered on any
  90.              stream or combination of streams
  91.     11.  Miscellaneous constants and types
  92.  
  93. DEMO PROGRAMS
  94.  
  95.   Encrypt.pas   -  encryption program, using TEncryptFilter
  96.   Compress.pas  -  file compressor, using TLZWFilter
  97.   Logdemo.pas   -  simple demo of TLogFilter
  98.   Ovrdemo.pas   -  simple demo of multiple overlay files
  99.    ovr1.pas     -  one overlaid unit
  100.    ovr2.pas     -  a second overlaid unit
  101.  
  102. 1.  TFilter = object(TStream)
  103.  
  104.      "Filters" are programs which take a file as input and produce a new
  105.      file as output.  TFilter is an adaptation of this idea to streams.
  106.      Every TFilter has a base stream, which can be any kind of stream.
  107.      Every TFilter is itself a stream, which means you can read and
  108.      write to it.  When you do, it just relays your request to the base
  109.      stream.
  110.  
  111.      One use of this is in the fact that you can make descendants
  112.      of TFilter which massage the data on the way to and from the Base.
  113.      Just override the Read and Write (and possibly other) methods, and
  114.      you can make changes to the data flowing to or from *any* kind of
  115.      stream.  No need for special coding for an TEMSStream, or for a
  116.      TDOSStream, or whatever.  Your code can act on any of them.
  117.      Examples of things to do are in the Streams unit:  encryption
  118.      (TEncryptFilter) and LZW compression (TLZWFilter).
  119.  
  120.      The other main use is to add other kinds of functionality to a
  121.      stream.  You can't use the formatting capabilities of ReadLn and
  122.      WriteLn with standard streams, but if you use a TTextFilter (see
  123.      below) you can.
  124.  
  125.      FIELDS
  126.  
  127.      Base : PStream;
  128.  
  129.        TFilter.Base holds the pointer to the base stream.
  130.  
  131.      StartOfs : longint;
  132.  
  133.        TFilter.StartOfs holds the offset in the base stream of offset 0
  134.        in the filter.  This allows multiple filters to work on the same
  135.        stream; one could work at offset 0, another at offset 1000, etc.
  136.        Just position the base to the desired starting offset before
  137.        initializing the filter.
  138.  
  139.      METHODS
  140.  
  141.      Constructor Init(ABase: PStream);
  142.  
  143.        TFilter.Init sets Base to point to ABase^, and sets StartOfs to
  144.        the current position of the base stream.
  145.  
  146.      Destructor Done; virtual;
  147.  
  148.        If Base is not nil, then TFilter.Done disposes of the base
  149.        stream before calling TStream.Done for itself.
  150.  
  151.      Function CheckStatus : boolean; virtual;
  152.  
  153.        Returns true if status is stOK.  If it is, but the base status is
  154.        not stOK, then it assumes that someone has called a Reset for the
  155.        filter, so it calls Reset for the base stream.  Borland should
  156.        have made Reset virtual, and this kludge wouldn't have been
  157.        necessary!
  158.  
  159.      Procedure CheckBase;
  160.  
  161.        Checks the base stream for an error.  If Base^.status is not
  162.        stOK, then it calls Error with Code=stBaseError and
  163.        Info=Base^.status.
  164.  
  165.      Function GetPos  : longint; virtual;
  166.      Function GetSize : longint; virtual;
  167.      Procedure Read(var buf; count : word); virtual;
  168.      Procedure Seek(pos: longint); virtual;
  169.      Procedure Truncate; virtual;
  170.      Procedure Write(var buf; count: word); virtual;
  171.  
  172.        These methods all call the corresponding method in the base
  173.        stream.  Offsets are translated using StartOfs.  Before the call,
  174.        CheckStatus is called to propagate any Reset to the base; after
  175.        the call, CheckBase is called to propagate any errors to the
  176.        filter from the base.
  177.  
  178. 2.  TEncryptFilter = object(TFilter)
  179.  
  180.        This is a filter which does simple encryption/decryption on the
  181.        base stream.  The encryption method is to XOR each byte with a
  182.        Random(256) value; the starting RandSeed is the key for the
  183.        encryption.
  184.  
  185.      FIELD
  186.  
  187.      key : longint;
  188.  
  189.        The key is used as a Randseed replacement value.  Randseed itself
  190.        is left unmodified by Read and Write.
  191.  
  192.      METHODS
  193.  
  194.      Constructor Init(Akey:longint; ABase:PStream);
  195.  
  196.        The value AKey is used as the starting key for byte 0 of the
  197.        filter.  Anything read from ABase is decrypted using this key;
  198.        anything written to it is encrypted.
  199.  
  200.      Procedure Read(var buf; count : word); virtual;
  201.      Procedure Seek(pos : longint); virtual;
  202.      Procedure Write(var buf; count: word); virtual;
  203.  
  204.        These methods all encrypt/decrypt and update the value of Key to
  205.        correspond to the new position in the stream.  The encryption
  206.        method uses the same algorithm for encryption as for decryption.
  207.        TEncryptFilter.Seek is fairly slow, because it updates the Key
  208.        once for every byte difference between the current position and
  209.        the new position.  Moving backwards is slower, because the update
  210.        algorithm is written in Pascal, not assembler as is the forward
  211.        algorithm.
  212.  
  213. 3.  TLZWFilter = object(TFilter)
  214.  
  215.        This is a filter which does LZW compression as it writes to and
  216.        decompression as it reads from the base stream.  The LZW code is
  217.        an adaptation of Wilbert van Leijen's implementation of the 12
  218.        bit LZW algorithm.  It's quite fast, though not as fast as
  219.        Wilbert's version; it gets slowed down a lot by having to save
  220.        its state after every Read and Write operation.  You're best off
  221.        writing large chunks to it to take advantage of Wilbert's
  222.        excellent code.  (Historical note:  Trying to rewrite this was
  223.        what inspired me to write FULLDB, a program which allows source
  224.        level debugging of external .ASM files. -djm)
  225.  
  226.        Each TLZWFilter takes over 28700 bytes of memory, because it
  227.        keeps extensive tables to record the current state.
  228.  
  229.        One limitation of the TLZWFilter is that it can only be opened in
  230.        read or write mode, and Seek cannot be used in write mode.
  231.  
  232.      FIELDS
  233.  
  234.      Mode : word;
  235.  
  236.        One of stOpenRead or stOpenWrite; the mode under which this
  237.        filter was opened.
  238.  
  239.      Size : longint;
  240.  
  241.        The size of the expanded stream.  This is the size that users of
  242.        the filter will see; if compression is working, it will generally
  243.        be bigger than Base^.GetSize.
  244.  
  245.      Position : longint;
  246.  
  247.        This is the position in the expanded stream.
  248.  
  249.      Tables : PLZWTables;
  250.  
  251.        This is a pointer to the tables used by the compression engine.
  252.        They're automatically allocated on the heap.
  253.  
  254.      METHODS
  255.  
  256.      Constructor Init(ABase:PStream; AMode:TOpenMode);
  257.  
  258.        Allocates Tables from the heap, and opens the compressor in
  259.        a mode of either stOpenRead or stOpenWrite.  If reading, a
  260.        signature and record of the uncompressed filesize is read from
  261.        the base to confirm that it is compressed by LZW, and to prime
  262.        the Tables.  If writing, the signature is written to the stream.
  263.  
  264.      Destructor Done; virtual;
  265.  
  266.        Flushes all data to the stream, and writes the uncompressed
  267.        filesize to the head of it before calling TFilter.done.
  268.  
  269.      Procedure Flush; virtual;
  270.      Function  GetPos: longint; virtual;
  271.      Function  GetSize:longint; virtual;
  272.      Procedure Read(var buf; count:word); virtual;
  273.      Procedure Seek(pos:longint); virtual;
  274.      Procedure Truncate; virtual;
  275.      Procedure Write(var buf; count: word); virtual;
  276.  
  277.        These methods all override the basic filter methods and
  278.        compress/decompress the data.  They check whether the operation
  279.        requested can be performed in the current mode, and call Error
  280.        with Code=stBadMode and Info=Mode if the operation is not
  281.        supported.
  282.  
  283.        Seek is not supported at all in Write mode.  In Read mode, it is
  284.        slow for seeking forwards, and very slow for seeking backwards:
  285.        it rewinds the file to the start and seeks forward from there by
  286.        expanding everything.
  287.  
  288.        Truncate is not supported in either mode, and always causes a
  289.        call to Error.
  290.  
  291.        Flush may only be called once; it changes Mode to 0, so any
  292.        further operations will fail.
  293.  
  294. 4.  TTextFilter = object(TFilter)
  295.  
  296.        This is a filter which provides a Read/ReadLn/Write/WriteLn
  297.        interface to a stream through its Textfile field.  Once the
  298.        filter is initialized, Textfile acts exactly like a text file in
  299.        the standard I/O procedures, but reads come from the stream, and
  300.        writes go to it.
  301.  
  302.      FIELD
  303.  
  304.      Textfile : Text;
  305.  
  306.        This is the dummy text file to use in Read/ReadLn/Write/WriteLn.
  307.  
  308.      METHODS
  309.  
  310.      Constructor Init(ABase:PStream; AName:String);
  311.  
  312.        Initializes the filter with base ABase.  The name AName is stored
  313.        as the name in the Textfile variable.
  314.  
  315.      Destructor Done; virtual;
  316.  
  317.        Closes the TextFile variable to flush any remaining data to the
  318.        stream.
  319.  
  320. 5.  TLogFilter = object(TFilter)
  321.  
  322.        This filter allows logging of activity on text files to a stream.
  323.        Logging is done very transparently.  Once the TTextFilter is
  324.        initialized, you call the Log method to start logging a
  325.        particular text file, and the UnLog method to stop.  When logging
  326.        is in effect, any data read from or written to the text file is
  327.        copied to the stream.
  328.  
  329.        Multiple files may be logged to the same stream.  For example,
  330.        you can log both Input and Output, and keep a record of an
  331.        interactive session on the stream.
  332.  
  333.        It's also possible to log the same file to multiple streams.
  334.        Just create the different TLogFilter objects, and call their Log
  335.        methods with the same file as an argument.  If you then call
  336.        Unlog, you must do it in the *reverse* order to the order you
  337.        called Log, e.g.
  338.          S1^.log(output);
  339.          S2^.log(output);
  340.          S2^.unlog(output);
  341.          S1^.unlog(output);
  342.        is the correct order to log and unlog.
  343.  
  344.        One detail of the implementation may cause some trouble.  The
  345.        data is logged to the stream at the time it is written to disk by
  346.        the text file.  Since text files are buffered, this may not be
  347.        the time at which you write to the text file, and multiple text
  348.        files logged to the same stream may not have all data appearing
  349.        in the correct order.
  350.  
  351.      FIELD
  352.  
  353.      LogList : ^Text;
  354.  
  355.        This is a pointer to the first text file currently being logged.
  356.  
  357.      METHODS
  358.  
  359.      Destructor done; virtual;
  360.  
  361.        Stops logging all text files by calling UnLog for each, and
  362.        closes and disposes of the base stream.
  363.  
  364.      Procedure Log(var F:text);
  365.  
  366.        Starts logging the text file F.  Continues until the UnLog method
  367.        is called or the file is closed or Assign'd.
  368.  
  369.      Function UnLog(var F:text):boolean;
  370.  
  371.        Stops logging the text file F.  Returns true if successful, false
  372.        if not.  Will fail if an Assign has been done to F, or F has been
  373.        closed, or F has already been Unlogged, or another stream has
  374.        started logging F and hasn't been UnLog'd yet.
  375.  
  376. 6.  TRAMStream = object(TStream)
  377.  
  378.        A stream which resides entirely on the heap.  The maximum length
  379.        is 65520 bytes.
  380.  
  381.      FIELDS
  382.  
  383.      cp : word;
  384.  
  385.        The current pointer for the stream.
  386.  
  387.      size : word;
  388.  
  389.        The current size of the stream.
  390.  
  391.      alloc : word;
  392.  
  393.        The size of the allocated block of memory.
  394.  
  395.      buffer : Pbyte_array;
  396.  
  397.        A pointer to the block of memory holding the stream data.
  398.  
  399.      METHODS
  400.  
  401.      Constructor init(Asize : word);
  402.  
  403.        Attempt to initialize the stream to a block size of Asize;
  404.        initial stream size and position are 0.
  405.  
  406.      Destructor done; virtual;
  407.  
  408.        Dispose of the stream.
  409.  
  410.      Function getpos : longint; virtual;
  411.      Function getsize : longint; virtual;
  412.      Procedure read(var buf; count : word); virtual;
  413.      Procedure seek(pos: longint); virtual;
  414.      Procedure truncate; virtual;
  415.      Procedure write(var buf; count: word); virtual;
  416.  
  417.        Implement the basic stream functions.
  418.  
  419.  
  420. 7.  TNamedBufStream = object(TBufStream)
  421.  
  422.        A simple descendant of TBufStream which knows its own name.
  423.  
  424.      FIELD
  425.  
  426.      filename : PString  { PChar in TPW };
  427.  
  428.        The name of the stream.
  429.  
  430.      METHODS
  431.  
  432.      Constructor Init(name:FNameStr;mode:TOpenMode;abufsize:word);
  433.  
  434.        Open the file with the given name, and save the name.
  435.  
  436.      Destructor Done; virtual;
  437.  
  438.        Close the file.
  439.  
  440. 8.  TTempBufStream = object(TNamedBufStream)
  441.  
  442.        A temporary buffered file stream, which deletes itself when done.
  443.  
  444.      METHODS
  445.  
  446.      Constructor init(abufsize:word);
  447.  
  448.        Create a temporary file with a unique name, in the directory
  449.        pointed to by the environment varable TEMP or in the current
  450.        directory, and open it in read/write mode.
  451.  
  452.      Destructor done; virtual;
  453.  
  454.        Close and delete the temporary file.
  455.  
  456. 9.  Function TempStream(InitSize,MaxSize : longint;
  457.                         Preference:TStreamRanking):PStream;
  458.  
  459.        This procedure returns a pointer to a temporary stream from a
  460.        choice of 3, specified in the Preference array.  The first stream
  461.        type listed in the Preference array which can be successfully
  462.        created with the given sizes will be returned, or Nil if none can
  463.        be made.
  464.  
  465.      ARGUMENTS
  466.  
  467.      Initsize : longint;
  468.  
  469.        The initial size to allocate to the stream.
  470.  
  471.      MaxSize : longint;
  472.  
  473.        The maximum size to which the stream should be allowed to grow.
  474.  
  475.      Preference : TStreamRanking;
  476.  
  477.        An array of 3 entries specifying what sort of temporary stream is
  478.        desired.  Supplied constants include:
  479.  
  480.         ForSpeed = (RAMStream, EMSStream, FileStream);
  481.         ForSize  = (FileStream,EMSStream, RAMStream);
  482.         ForSizeInMem = (EMSStream, RAMStream, NoStream);
  483.         ForOverlays =  (EMSStream, FileStream,NoStream);
  484.  
  485. 10. Stream overlay procedures
  486.  
  487.        These procedures allow overlays to be buffered on any stream or
  488.        combination of streams.  Some overlays can be loaded into EMS,
  489.        others kept on disk, and others can be put onto any other
  490.        available stream.
  491.  
  492.      PROCEDURES/FUNCTIONS
  493.  
  494.      Procedure OvrInitStream(S:PStream);
  495.  
  496.        Copies overlay segment code to S as new segments are loaded, and
  497.        does reloads from there.  You may call OvrInitStream multiple
  498.        times, and different segments will be buffered on different
  499.        streams, depending on the order in which they are loaded by the
  500.        overlay loader.
  501.  
  502.        On the first call, an exit handler is installed which will call
  503.        OvrDisposeStreams upon program termination.
  504.  
  505.      Procedure OvrDetachStream(BadS:PStream);
  506.  
  507.        Makes sure that the overlay system makes no references to BadS.
  508.        Call this before disposing of a stream which has been passed to
  509.        OvrInitStream, or you're very likely to crash.
  510.  
  511.      Procedure OvrDisposeStreams;
  512.  
  513.        Detaches and disposes of all streams being used by the overlay
  514.        system.
  515.  
  516.      Function OvrSizeNeeded:longint;
  517.  
  518.        Returns the additional size required to load any segments which
  519.        still haven't been loaded to a stream.
  520.  
  521.      Function OvrLoadAll:boolean;
  522.  
  523.        Forces all overlay segments to be copied into the stream; if
  524.        successful (true) then no more references to the overlay file
  525.        will be made.
  526.  
  527.        Warning:  This function calls OvrClearBuf, so that any overlay
  528.        files which are already in the regular overlay buffer will need
  529.        to be reloaded.
  530.  
  531. 11.  Miscellaneous constants and types
  532.  
  533.      CONSTANTS
  534.  
  535.      stBadMode = 1;
  536.  
  537.        Error signalled when an operation is not permitted in the current
  538.        mode.
  539.  
  540.      stStreamFail = 2;
  541.  
  542.        Error signalled when a stream Init failed.
  543.  
  544.      stBaseError = 3;
  545.  
  546.        Error signalled by a TFilter when the base stream has an error;
  547.        the base stream's error number is put in the Info field.
  548.  
  549.      stMemError = 4;
  550.  
  551.        Not enough memory for operation.
  552.  
  553.      stSigError = 5;
  554.  
  555.        Problem with LZW file signature.
  556.  
  557.      BufSize : word = 2048;
  558.  
  559.        Buffer size to use when creating a buffered file stream in
  560.        TempStream.
  561.  
  562.      TYPES
  563.  
  564.      TOpenMode = $3C00..$3DFF;
  565.  
  566.        This is the widest possible range of open modes for a TDOSStream
  567.        descendant.  Values outside this range can cause very serious bugs in
  568.        programs, since the high byte is used as the DOS service number
  569.        when the file is opened.
  570.  
  571.      PLZWTables = ^TLZWTables;
  572.      TLZWTables = record ...
  573.  
  574.        These tables are used internally to maintain the state of a
  575.        TLZWFilter.
  576.  
  577.      PByte_Array = ^TByte_Array;
  578.      TByte_Array = array[0..65520] of byte;
  579.  
  580.        An array type used as a buffer in several places.
  581.  
  582.      TStreamType = (NoStream, RAMStream, EMSStream, FileStream);
  583.  
  584.        The types of streams that TempStream can create.
  585.  
  586.      TStreamRanking = array[1..NumTypes] of TStreamType;
  587.  
  588.        An array giving the order from most preferred to least preferred
  589.        for a temporary stream.
  590.