home *** CD-ROM | disk | FTP | other *** search
/ Chip 2003 January / ChipCD_1.03.iso / zkuste / delphi / unity / d56 / FNDUTL.ZIP / Streams / cReaders.pas next >
Encoding:
Pascal/Delphi Source File  |  2002-10-29  |  53.9 KB  |  1,720 lines

  1. {$INCLUDE ..\cDefines.inc}
  2. unit cReaders;
  3.  
  4. {                                                                              }
  5. {                              Readers v3.06                                   }
  6. {                                                                              }
  7. {      This unit is copyright ⌐ 1999-2002 by David Butler (david@e.co.za)      }
  8. {                                                                              }
  9. {                  This unit is part of Delphi Fundamentals.                   }
  10. {                   Its original file name is cReaders.pas                     }
  11. {       The latest version is available from the Fundamentals home page        }
  12. {                     http://fundementals.sourceforge.net/                     }
  13. {                                                                              }
  14. {                I invite you to use this unit, free of charge.                }
  15. {        I invite you to distibute this unit, but it must be for free.         }
  16. {             I also invite you to contribute to its development,              }
  17. {             but do not distribute a modified copy of this file.              }
  18. {                                                                              }
  19. {          A forum is available on SourceForge for general discussion          }
  20. {             http://sourceforge.net/forum/forum.php?forum_id=2117             }
  21. {                                                                              }
  22. {                                                                              }
  23. { Revision history:                                                            }
  24. {   [ cStreams ]                                                               }
  25. {   01/03/1999  0.01  Initial version of TextParser                            }
  26. {   26/06/1999  1.02  Moved AStream from cDataStruct unit to cStreams.         }
  27. {   [ cReaders ]                                                               }
  28. {   03/05/2002  3.03  Created cReaders unit from cStreams.                     }
  29. {                     AReader, TMemoryReader, TStringReader, TFileReader.      }
  30. {   13/05/2002  3.04  Added TBufferedReader, TSplitBufferReader and            }
  31. {                     TTextReader.                                             }
  32. {   13/07/2002  3.05  Moved TTextReader functionality to AReaderEx.            }
  33. {   23/08/2002  3.06  Added SelfTest procedure.                                }
  34. {                                                                              }
  35.  
  36. interface
  37.  
  38. uses
  39.   // Delphi
  40.   SysUtils,
  41.  
  42.   // Fundamentals
  43.   cUtils;
  44.  
  45.  
  46.  
  47. {                                                                              }
  48. { AReader                                                                      }
  49. {   Abstract base class for a Reader.                                          }
  50. {                                                                              }
  51. {   Inherited classes must implement the abstract methods from AReader.        }
  52. {   Read returns the actual number of bytes copied to the buffer.              }
  53. {                                                                              }
  54. type
  55.   AReader = class
  56.     protected
  57.     Function  GetPosition : Int64; virtual; abstract;
  58.     Procedure SetPosition (const Position : Int64); virtual; abstract;
  59.     Function  GetSize : Int64; virtual; abstract;
  60.  
  61.     public
  62.     Function  Read (var Buffer; const Size : Integer) : Integer; virtual; abstract;
  63.  
  64.     Property  Position : Int64 read GetPosition write SetPosition;
  65.     Property  Size : Int64 read GetSize;
  66.     Function  EOF : Boolean; virtual; abstract;
  67.   end;
  68.   EReader = class (Exception);
  69.  
  70.  
  71.  
  72. {                                                                              }
  73. { AReaderEx                                                                    }
  74. {   Base class for Reader implementations. AReaderEx extends AReader with      }
  75. {   commonly used functions.                                                   }
  76. {                                                                              }
  77. {   All methods in AReaderEx is implemented using calls to the abstract        }
  78. {   methods in AReader. Reader implementations can override the virtual        }
  79. {   methods in AReaderEx with more efficient versions.                         }
  80. {                                                                              }
  81. {   Match functions return True when a match is found. Match leaves the        }
  82. {   reader's position unchanged except if a match is made and SkipOnMatch      }
  83. {   is True.                                                                   }
  84. {                                                                              }
  85. {   Locate returns the offset (relative to the current position) of the        }
  86. {   first match in the stream. Locate preserves the reader's position.         }
  87. {   Locate returns -1 if a match was not made.                                 }
  88. {                                                                              }
  89. type
  90.   AReaderEx = class (AReader)
  91.     protected
  92.     Procedure SkipLineTerminator;
  93.  
  94.     public
  95.     Procedure RaiseReadError (const Msg : String = '');
  96.  
  97.     Procedure ReadBuffer (var Buffer; const Size : Integer);
  98.     Function  ReadStr (const Size : Integer) : String; virtual;
  99.     Function  GetAsString : String; virtual;
  100.  
  101.     Function  ReadByte : Byte; virtual;
  102.     Function  ReadWord : Word;
  103.     Function  ReadLongWord : LongWord;
  104.     Function  ReadLongInt : LongInt;
  105.     Function  ReadInt64 : Int64;
  106.  
  107.     Function  Peek (var Buffer; const Size : Integer) : Integer; virtual;
  108.     Procedure PeekBuffer (var Buffer; const Size : Integer);
  109.     Function  PeekStr (const Size : Integer) : String; virtual;
  110.  
  111.     Function  PeekByte : Byte; virtual;
  112.     Function  PeekWord : Word;
  113.     Function  PeekLongWord : LongWord;
  114.     Function  PeekLongInt : LongInt;
  115.     Function  PeekInt64 : Int64;
  116.  
  117.     Function  Match (const Buffer; const Size : Integer;
  118.               const CaseSensitive : Boolean = True) : Integer; virtual;
  119.     Function  MatchBuffer (const Buffer; const Size : Integer;
  120.               const CaseSensitive : Boolean = True) : Boolean;
  121.     Function  MatchStr (const S : String; const CaseSensitive : Boolean = True) : Boolean; virtual;
  122.  
  123.     Function  MatchChar (const Ch : Char; const MatchNonMatch : Boolean = False;
  124.               const SkipOnMatch : Boolean = False) : Boolean; overload;
  125.     Function  MatchChar (const C : CharSet; var Ch : Char;
  126.               const MatchNonMatch : Boolean = False; const SkipOnMatch : Boolean = False) : Boolean; overload;
  127.  
  128.     Procedure Skip (const Count : Integer = 1); virtual;
  129.     Procedure SkipByte;
  130.  
  131.     Function  SkipAll (const Ch : Char; const MatchNonMatch : Boolean = False;
  132.               const MaxCount : Integer = -1) : Integer; overload;
  133.     Function  SkipAll (const C : CharSet; const MatchNonMatch : Boolean = False;
  134.               const MaxCount : Integer = -1) : Integer; overload;
  135.  
  136.     Function  Locate (const Ch : Char; const LocateNonMatch : Boolean = False;
  137.               const MaxOffset : Integer = -1) : Integer; overload; virtual;
  138.     Function  Locate (const C : CharSet; const LocateNonMatch : Boolean = False;
  139.               const MaxOffset : Integer = -1) : Integer; overload; virtual;
  140.     Function  LocateBuffer (const Buffer; const Size : Integer;
  141.               const MaxOffset : Integer = -1; const CaseSensitive : Boolean = True) : Integer; virtual;
  142.     Function  LocateStr (const S : String; const MaxOffset : Integer = -1;
  143.               const CaseSensitive : Boolean = True) : Integer; virtual;
  144.  
  145.     Function  ExtractAll (const C : CharSet; const ExtractNonMatch : Boolean = False;
  146.               const MaxCount : Integer = -1) : String;
  147.  
  148.     Function  ExtractLine (const MaxLineLength : Integer = -1;
  149.               const EOFIsEOL : Boolean = True) : String;
  150.     Function  SkipLine (const MaxLineLength : Integer = -1) : Boolean;
  151.   end;
  152.  
  153.  
  154.  
  155. {                                                                              }
  156. { TMemoryReader                                                                }
  157. {   Reader implementation for a memory block.                                  }
  158. {                                                                              }
  159. type
  160.   TMemoryReader = class (AReaderEx)
  161.     protected
  162.     FData : Pointer;
  163.     FSize : Integer;
  164.     FPos  : Integer;
  165.  
  166.     Function  GetPosition : Int64; override;
  167.     Procedure SetPosition (const Position : Int64); override;
  168.     Function  GetSize : Int64; override;
  169.  
  170.     public
  171.     Constructor Create (const Data : Pointer; const Size : Integer);
  172.  
  173.     Property  Data : Pointer read FData;
  174.     Property  Size : Integer read FSize;
  175.  
  176.     Function  Read (var Buffer; const Size : Integer) : Integer; override;
  177.     Function  EOF : Boolean; override;
  178.  
  179.     Function  ReadByte : Byte; override;
  180.     Function  PeekByte : Byte; override;
  181.     Function  Match (const Buffer; const Size : Integer;
  182.               const CaseSensitive : Boolean = True) : Integer; override;
  183.   end;
  184.   EMemoryReader = class (EReader);
  185.  
  186.  
  187.  
  188. {                                                                              }
  189. { TStringReader                                                                }
  190. {   Memory reader implementation for a reference counted string (long string). }
  191. {                                                                              }
  192. type
  193.   TStringReader = class (TMemoryReader)
  194.     protected
  195.     FDataString : String;
  196.  
  197.     public
  198.     Constructor Create (const Data : String);
  199.  
  200.     Property  DataString : String read FDataString;
  201.     
  202.     Function  GetAsString : String; override;
  203.   end;
  204.  
  205.  
  206.  
  207. {                                                                              }
  208. { TFileReader                                                                  }
  209. {   Reader implementation for a file.                                          }
  210. {                                                                              }
  211. type
  212.   TFileReader = class (AReaderEx)
  213.     protected
  214.     FHandle      : Integer;
  215.     FHandleOwner : Boolean;
  216.  
  217.     Function  GetPosition : Int64; override;
  218.     Procedure SetPosition (const Position : Int64); override;
  219.     Function  GetSize : Int64; override;
  220.  
  221.     public
  222.     Constructor Create (const FileName : String); overload;
  223.     Constructor Create (const FileHandle : Integer; const HandleOwner : Boolean = False); overload;
  224.     Destructor Destroy; override;
  225.  
  226.     Property  Handle : Integer read FHandle;
  227.     Property  HandleOwner : Boolean read FHandleOwner;
  228.  
  229.     Function  Read (var Buffer; const Size : Integer) : Integer; override;
  230.     Function  EOF : Boolean; override;
  231.   end;
  232.   EFileReader = class (EReader);
  233.  
  234. Function  ReadFileToStr (const FileName : String) : String;
  235.  
  236.  
  237.  
  238. {                                                                              }
  239. { AReaderProxy                                                                 }
  240. {   Base class for Reader Proxies.                                             }
  241. {                                                                              }
  242. type
  243.   AReaderProxy = class (AReaderEx)
  244.     protected
  245.     FReader      : AReaderEx;
  246.     FReaderOwner : Boolean;
  247.  
  248.     Function  GetPosition : Int64; override;
  249.     Procedure SetPosition (const Position : Int64); override;
  250.     Function  GetSize : Int64; override;
  251.  
  252.     public
  253.     Constructor Create (const Reader : AReaderEx; const ReaderOwner : Boolean = True);
  254.     Destructor Destroy; override;
  255.  
  256.     Function  Read (var Buffer; const Size : Integer) : Integer; override;
  257.     Function  EOF : Boolean; override;
  258.  
  259.     Property  Reader : AReaderEx read FReader;
  260.     Property  ReaderOwner : Boolean read FReaderOwner write FReaderOwner;
  261.   end;
  262.  
  263.  
  264.  
  265. {                                                                              }
  266. { TReaderProxy                                                                 }
  267. {   Reader Proxy implementation.                                               }
  268. {                                                                              }
  269. {   Proxies a block of data from Reader from the Reader's current position.    }
  270. {   Size specifies the size of the data to be proxied, or if Size = -1,        }
  271. {   all data up to EOF is proxied.                                             }
  272. {                                                                              }
  273. type
  274.   TReaderProxy = class (AReaderProxy)
  275.     protected
  276.     FOffset : Int64;
  277.     FSize   : Int64;
  278.  
  279.     Function  GetPosition : Int64; override;
  280.     Procedure SetPosition (const Position : Int64); override;
  281.     Function  GetSize : Int64; override;
  282.  
  283.     public
  284.     Constructor Create (const Reader : AReaderEx; const ReaderOwner : Boolean = True;
  285.                 const Size : Int64 = -1);
  286.  
  287.     Function  Read (var Buffer; const Size : Integer) : Integer; override;
  288.     Function  EOF : Boolean; override;
  289.   end;
  290.  
  291.  
  292.  
  293. {                                                                              }
  294. { TBufferedReader                                                              }
  295. {   ReaderProxy implementation for buffered reading.                           }
  296. {                                                                              }
  297. type
  298.   TBufferedReader = class (AReaderProxy)
  299.     protected
  300.     FBufferSize  : Integer;
  301.     FPos         : Int64;
  302.     FBuffer      : Pointer;
  303.     FBufUsed     : Integer;
  304.     FBufPos      : Integer;
  305.  
  306.     Function  GetPosition : Int64; override;
  307.     Procedure SetPosition (const Position : Int64); override;
  308.     Function  GetSize : Int64; override;
  309.  
  310.     Function  FillBuf : Boolean;
  311.     Procedure BufferByte;
  312.     Function  PosBuf (const C : CharSet; const LocateNonMatch : Boolean;
  313.               const MaxOffset : Integer) : Integer;
  314.  
  315.     public
  316.     Constructor Create (const Reader : AReaderEx; const BufferSize : Integer = 128;
  317.                 const ReaderOwner : Boolean = True);
  318.     Destructor Destroy; override;
  319.  
  320.     Function  Read (var Buffer; const Size : Integer) : Integer; override;
  321.     Function  EOF : Boolean; override;
  322.  
  323.     Function  ReadByte : Byte; override;
  324.     Function  PeekByte : Byte; override;
  325.     Procedure Skip (const Count : Integer = 1); override;
  326.  
  327.     Function  Locate (const C : CharSet; const LocateNonMatch : Boolean = False;
  328.               const MaxOffset : Integer = -1) : Integer; override;
  329.  
  330.     Property  BufferSize : Integer read FBufferSize;
  331.     Procedure InvalidateBuffer;
  332.   end;
  333.  
  334.  
  335.  
  336. {                                                                              }
  337. { TSplitBufferedReader                                                         }
  338. {   ReaderProxy implementation for split buffered reading.                     }
  339. {                                                                              }
  340. {   One buffer is used for read-ahead buffering, the other for seek-back       }
  341. {   buffering.                                                                 }
  342. {                                                                              }
  343. type
  344.   TSplitBufferedReader = class (AReaderProxy)
  345.     protected
  346.     FBufferSize  : Integer;
  347.  
  348.     FPos         : Int64;
  349.     FBuffer      : Array [0..1] of Pointer;
  350.     FBufUsed     : Array [0..1] of Integer;
  351.     FBufNr       : Integer;
  352.     FBufPos      : Integer;
  353.  
  354.     Function  GetPosition : Int64; override;
  355.     Procedure SetPosition (const Position : Int64); override;
  356.     Function  GetSize : Int64; override;
  357.  
  358.     Function  BufferStart : Integer;
  359.     Function  BufferRemaining : Integer;
  360.     Function  MoveBuf (var Dest : PByte; var Remaining : Integer) : Boolean;
  361.     Function  FillBuf (var Dest : PByte; var Remaining : Integer) : Boolean;
  362.  
  363.     public
  364.     Constructor Create (const Reader : AReaderEx; const BufferSize : Integer = 128;
  365.                 const ReaderOwner : Boolean = True);
  366.     Destructor Destroy; override;
  367.  
  368.     Property  BufferSize : Integer read FBufferSize;
  369.  
  370.     Function  Read (var Buffer; const Size : Integer) : Integer; override;
  371.     Function  EOF : Boolean; override;
  372.  
  373.     Procedure InvalidateBuffer;
  374.   end;
  375.  
  376.  
  377.  
  378. {                                                                              }
  379. { TBufferedFileReader                                                          }
  380. {   TBufferedReader instance using a TFileReader.                              }
  381. {                                                                              }
  382. type
  383.   TBufferedFileReader = class (TBufferedReader)
  384.     public
  385.     Constructor Create (const FileName : String; const BufferSize : Integer = 512); overload;
  386.     Constructor Create (const FileHandle : Integer; const HandleOwner : Boolean = False;
  387.                 const BufferSize : Integer = 512); overload;
  388.   end;
  389.  
  390.  
  391.  
  392. {                                                                              }
  393. { TSplitBufferedFileReader                                                     }
  394. {   TSplitBufferedReader instance using a TFileReader.                         }
  395. {                                                                              }
  396. type
  397.   TSplitBufferedFileReader = class (TSplitBufferedReader)
  398.     public
  399.     Constructor Create (const FileName : String; const BufferSize : Integer = 512);
  400.   end;
  401.  
  402.  
  403.  
  404. {                                                                              }
  405. { Self-testing code                                                            }
  406. {                                                                              }
  407. Procedure SelfTest;
  408.  
  409.  
  410.  
  411. implementation
  412.  
  413.  
  414.  
  415. {                                                                              }
  416. { AReaderEx                                                                    }
  417. {                                                                              }
  418. const
  419.   DefaultBufSize = 2048;
  420.  
  421. Procedure AReaderEx.RaiseReadError (const Msg : String);
  422. var S : String;
  423.   Begin
  424.     if Msg = '' then
  425.       S := 'Read error' else
  426.       S := Msg;
  427.     raise EReader.Create (S);
  428.   End;
  429.  
  430. Procedure AReaderEx.ReadBuffer (var Buffer; const Size : Integer);
  431.   Begin
  432.     if Size <= 0 then
  433.       exit;
  434.     if Read (Buffer, Size) <> Size then
  435.       RaiseReadError;
  436.   End;
  437.  
  438. Function AReaderEx.ReadStr (const Size : Integer) : String;
  439. var L : Integer;
  440.   Begin
  441.     if Size <= 0 then
  442.       begin
  443.         Result := '';
  444.         exit;
  445.       end;
  446.     SetLength (Result, Size);
  447.     L := Read (Pointer (Result)^, Size);
  448.     if L <= 0 then
  449.       begin
  450.         Result := '';
  451.         exit;
  452.       end;
  453.     if L < Size then
  454.       SetLength (Result, L);
  455.   End;
  456.  
  457. Function AReaderEx.GetAsString : String;
  458. var S : Int64;
  459.     B : String;
  460.     I : Integer;
  461.   Begin
  462.     SetPosition (0);
  463.     S := GetSize;
  464.     if S < 0 then
  465.       begin
  466.         Result := '';
  467.         While not EOF do
  468.           begin
  469.             SetLength (B, DefaultBufSize);
  470.             I := Read (Pointer (B)^, DefaultBufSize);
  471.             if I > 0 then
  472.               begin
  473.                 if I < DefaultBufSize then
  474.                   SetLength (B, I);
  475.                 Result := Result + B;
  476.               end else
  477.               if not EOF then
  478.                 RaiseReadError;
  479.           end;
  480.       end else
  481.       Result := ReadStr (S);
  482.   End;
  483.  
  484. Function AReaderEx.ReadByte : Byte;
  485.   Begin
  486.     ReadBuffer (Result, Sizeof (Byte));
  487.   End;
  488.  
  489. Function AReaderEx.ReadWord : Word;
  490.   Begin
  491.     ReadBuffer (Result, Sizeof (Word));
  492.   End;
  493.  
  494. Function AReaderEx.ReadLongWord : LongWord;
  495.   Begin
  496.     ReadBuffer (Result, Sizeof (LongInt));
  497.   End;
  498.  
  499. Function AReaderEx.ReadLongInt : LongInt;
  500.   Begin
  501.     ReadBuffer (Result, Sizeof (LongInt));
  502.   End;
  503.  
  504. Function AReaderEx.ReadInt64 : Int64;
  505.   Begin
  506.     ReadBuffer (Result, Sizeof (Int64));
  507.   End;
  508.  
  509. Function AReaderEx.Peek (var Buffer; const Size : Integer) : Integer;
  510. var P : Int64;
  511.   Begin
  512.     P := GetPosition;
  513.     Result := Read (Buffer, Size);
  514.     if Result > 0 then
  515.       SetPosition (P);
  516.   End;
  517.  
  518. Procedure AReaderEx.PeekBuffer (var Buffer; const Size : Integer);
  519.   Begin
  520.     if Size <= 0 then
  521.       exit;
  522.     if Peek (Buffer, Size) <> Size then
  523.       RaiseReadError;
  524.   End;
  525.  
  526. Function AReaderEx.PeekStr (const Size : Integer) : String;
  527. var L : Integer;
  528.   Begin
  529.     if Size <= 0 then
  530.       begin
  531.         Result := '';
  532.         exit;
  533.       end;
  534.     SetLength (Result, Size);
  535.     L := Peek (Pointer (Result)^, Size);
  536.     if L <= 0 then
  537.       begin
  538.         Result := '';
  539.         exit;
  540.       end;
  541.     if L < Size then
  542.       SetLength (Result, L);
  543.   End;
  544.  
  545. Function AReaderEx.PeekByte : Byte;
  546.   Begin
  547.     PeekBuffer (Result, Sizeof (Byte));
  548.   End;
  549.  
  550. Function AReaderEx.PeekWord : Word;
  551.   Begin
  552.     PeekBuffer (Result, Sizeof (Word));
  553.   End;
  554.  
  555. Function AReaderEx.PeekLongWord : LongWord;
  556.   Begin
  557.     PeekBuffer (Result, Sizeof (LongWord));
  558.   End;
  559.  
  560. Function AReaderEx.PeekLongInt : LongInt;
  561.   Begin
  562.     PeekBuffer (Result, Sizeof (LongInt));
  563.   End;
  564.  
  565. Function AReaderEx.PeekInt64 : Int64;
  566.   Begin
  567.     PeekBuffer (Result, Sizeof (Int64));
  568.   End;
  569.  
  570. Function AReaderEx.Match (const Buffer; const Size : Integer; const CaseSensitive : Boolean) : Integer;
  571. var B : Pointer;
  572.     R : Boolean;
  573.   Begin
  574.     if Size <= 0 then
  575.       begin
  576.         Result := -1;
  577.         exit;
  578.       end;
  579.     GetMem (B, Size);
  580.     try
  581.       Result := Peek (B^, Size);
  582.       if Result <= 0 then
  583.         exit;
  584.       if CaseSensitive then
  585.         R := CompareMem (Buffer, B^, Result) else
  586.         R := CompareMemNoCase (Buffer, B^, Result);
  587.       if not R then
  588.         Result := -1;
  589.     finally
  590.       FreeMem (B);
  591.     end;
  592.   End;
  593.  
  594. Function AReaderEx.MatchBuffer (const Buffer; const Size : Integer; const CaseSensitive : Boolean) : Boolean;
  595. var I : Integer;
  596.   Begin
  597.     I := Match (Buffer, Size, CaseSensitive);
  598.     if I = -1 then
  599.       begin
  600.         Result := False;
  601.         exit;
  602.       end;
  603.     if I < Size then
  604.       RaiseReadError;
  605.     Result := True;
  606.   End;
  607.  
  608. Function AReaderEx.MatchStr (const S : String; const CaseSensitive : Boolean) : Boolean;
  609.   Begin
  610.     Result := MatchBuffer (Pointer (S)^, Length (S), CaseSensitive);
  611.   End;
  612.  
  613. Function AReaderEx.MatchChar (const Ch : Char; const MatchNonMatch : Boolean; const SkipOnMatch : Boolean) : Boolean;
  614.   Begin
  615.     if EOF then
  616.       begin
  617.         Result := False;
  618.         exit;
  619.       end;
  620.     Result := (Char (PeekByte) = Ch) xor MatchNonMatch;
  621.     if Result and SkipOnMatch then
  622.       Skip (Sizeof (Byte));
  623.   End;
  624.  
  625. Function AReaderEx.MatchChar (const C : CharSet; var Ch : Char; const MatchNonMatch : Boolean; const SkipOnMatch : Boolean) : Boolean;
  626.   Begin
  627.     if EOF then
  628.       begin
  629.         Result := False;
  630.         exit;
  631.       end;
  632.     Ch := Char (PeekByte);
  633.     Result := (Ch in C) xor MatchNonMatch;
  634.     if Result and SkipOnMatch then
  635.       Skip (Sizeof (Byte));
  636.   End;
  637.  
  638. Procedure AReaderEx.Skip (const Count : Integer);
  639.   Begin
  640.     if Count < 0 then
  641.       raise EReader.Create ('Skip error');
  642.     if Count = 0 then
  643.       exit;
  644.     SetPosition (GetPosition + Count);
  645.   End;
  646.  
  647. Procedure AReaderEx.SkipByte;
  648.   Begin
  649.     Skip (Sizeof (Byte));
  650.   End;
  651.  
  652. Function AReaderEx.SkipAll (const Ch : Char; const MatchNonMatch : Boolean; const MaxCount : Integer) : Integer;
  653.   Begin
  654.     Result := 0;
  655.     While (MaxCount < 0) or (Result < MaxCount) do
  656.       if not MatchChar (Ch, MatchNonMatch, True) then
  657.         exit else
  658.         Inc (Result);
  659.   End;
  660.  
  661. Function AReaderEx.SkipAll (const C : CharSet; const MatchNonMatch : Boolean; const MaxCount : Integer) : Integer;
  662. var Ch : Char;
  663.   Begin
  664.     Result := 0;
  665.     While (MaxCount < 0) or (Result < MaxCount) do
  666.       if not MatchChar (C, Ch, MatchNonMatch, True) then
  667.         exit else
  668.         Inc (Result);
  669.   End;
  670.  
  671. Function AReaderEx.Locate (const Ch : Char; const LocateNonMatch : Boolean; const MaxOffset : Integer) : Integer;
  672. var P : Int64;
  673.     I : Integer;
  674.   Begin
  675.     P := GetPosition;
  676.     I := 0;
  677.     While not EOF and ((MaxOffset < 0) or (I <= MaxOffset)) do
  678.       if (Char (ReadByte) = Ch) xor LocateNonMatch then
  679.         begin
  680.           SetPosition (P);
  681.           Result := I;
  682.           exit;
  683.         end else
  684.         Inc (I);
  685.     SetPosition (P);
  686.     Result := -1;
  687.   End;
  688.  
  689. Function AReaderEx.Locate (const C : CharSet; const LocateNonMatch : Boolean; const MaxOffset : Integer) : Integer;
  690. var P : Int64;
  691.     I : Integer;
  692.   Begin
  693.     P := GetPosition;
  694.     I := 0;
  695.     While not EOF and ((MaxOffset < 0) or (I <= MaxOffset)) do
  696.       if (Char (ReadByte) in C) xor LocateNonMatch then
  697.         begin
  698.           SetPosition (P);
  699.           Result := I;
  700.           exit;
  701.         end else
  702.         Inc (I);
  703.     SetPosition (P);
  704.     Result := -1;
  705.   End;
  706.  
  707. Function AReaderEx.LocateBuffer (const Buffer; const Size : Integer; const MaxOffset : Integer; const CaseSensitive : Boolean) : Integer;
  708. var P : Int64;
  709.     I : Integer;
  710.     B : Pointer;
  711.     R : Boolean;
  712.   Begin
  713.     GetMem (B, Size);
  714.     try
  715.       P := GetPosition;
  716.       I := 0;
  717.       While not EOF and ((MaxOffset < 0) or (I <= MaxOffset)) do
  718.         begin
  719.           Result := Peek (B^, Size);
  720.           if Result <= 0 then
  721.             exit;
  722.           if CaseSensitive then
  723.             R := CompareMem (Buffer, B^, Result) else
  724.             R := CompareMemNoCase (Buffer, B^, Result);
  725.           if R then
  726.             begin
  727.               SetPosition (P);
  728.               Result := I;
  729.               exit;
  730.             end else
  731.             begin
  732.               Inc (I);
  733.               SetPosition (P + I);
  734.             end;
  735.         end;
  736.       SetPosition (P);
  737.       Result := -1;
  738.     finally
  739.       FreeMem (B);
  740.     end;
  741.   End;
  742.  
  743. Function AReaderEx.LocateStr (const S : String; const MaxOffset : Integer; const CaseSensitive : Boolean) : Integer;
  744.   Begin
  745.     Result := LocateBuffer (Pointer (S)^, Length (S), MaxOffset, CaseSensitive);
  746.   End;
  747.  
  748. Function AReaderEx.ExtractAll (const C : CharSet; const ExtractNonMatch : Boolean; const MaxCount : Integer) : String;
  749. var I : Integer;
  750.   Begin
  751.     I := Locate (C, not ExtractNonMatch, MaxCount);
  752.     if I = -1 then
  753.       if MaxCount = -1 then
  754.         begin
  755.           Result := '';
  756.           While not EOF do
  757.             Result := Result + ReadStr (1024);
  758.         end else
  759.         Result := ReadStr (MaxCount)
  760.     else
  761.       Result := ReadStr (I);
  762.   End;
  763.  
  764. Procedure AReaderEx.SkipLineTerminator;
  765. var C, D : Char;
  766.   Begin
  767.     if EOF then
  768.       exit;
  769.     C := Char (ReadByte);
  770.     if C = #26 then // EOF
  771.       exit;
  772.     if EOF then
  773.       exit;
  774.     D := Char (PeekByte);
  775.     if ((C = #13) and (D = #10)) or // CRLF
  776.        ((C = #10) and (D = #13)) then // LFCR
  777.       SkipByte;
  778.   End;
  779.  
  780. const
  781.   NewLineCharacters = [#10, #13, #26]; // LF, CR, EOF
  782.  
  783. Function AReaderEx.ExtractLine (const MaxLineLength : Integer; const EOFIsEOL : Boolean) : String;
  784.   Begin
  785.     Result := ExtractAll (NewLineCharacters, True, MaxLineLength);
  786.     if EOF then
  787.       if EOFIsEOL then
  788.         exit else
  789.         RaiseReadError;
  790.     SkipLineTerminator;
  791.   End;
  792.  
  793. Function AReaderEx.SkipLine (const MaxLineLength : Integer) : Boolean;
  794. var I : Integer;
  795.   Begin
  796.     I := Locate (NewLineCharacters, False, MaxLineLength);
  797.     Result := I >= 0;
  798.     if not Result then
  799.       exit;
  800.     Skip (I);
  801.     SkipLineTerminator;
  802.   End;
  803.  
  804.  
  805.  
  806. {                                                                              }
  807. { TMemoryReader                                                                }
  808. {                                                                              }
  809. Constructor TMemoryReader.Create (const Data : Pointer; const Size : Integer);
  810.   Begin
  811.     FData := Data;
  812.     FSize := Size;
  813.     FPos := 0;
  814.     inherited Create;
  815.   End;
  816.  
  817. Function TMemoryReader.GetPosition : Int64;
  818.   Begin
  819.     Result := FPos;
  820.   End;
  821.  
  822. Procedure TMemoryReader.SetPosition (const Position : Int64);
  823.   Begin
  824.     if (Position < 0) or (Position > FSize) then
  825.       raise EMemoryReader.Create ('Seek error');
  826.     FPos := Integer (Position);
  827.   End;
  828.  
  829. Function TMemoryReader.GetSize : Int64;
  830.   Begin
  831.     Result := FSize;
  832.   End;
  833.  
  834. Function TMemoryReader.Read (var Buffer; const Size : Integer) : Integer;
  835. var L : Integer;
  836.     P : PByte;
  837.   Begin
  838.     if (Size <= 0) or (FPos >= FSize) then
  839.       begin
  840.         Result := 0;
  841.         exit;
  842.       end;
  843.     L := FSize - FPos;
  844.     if Size < L then
  845.       L := Size;
  846.     P := FData;
  847.     Inc (P, FPos);
  848.     MoveMem (P^, Buffer, L);
  849.     Result := L;
  850.     Inc (FPos, L);
  851.   End;
  852.  
  853. Function TMemoryReader.ReadByte : Byte;
  854. var I : Integer;
  855.     P : PByte;
  856.   Begin
  857.     I := FPos;
  858.     if I >= FSize then
  859.       RaiseReadError;
  860.     P := FData;
  861.     Inc (P, I);
  862.     Result := P^;
  863.     Inc (FPos);
  864.   End;
  865.  
  866. Function TMemoryReader.PeekByte : Byte;
  867. var I : Integer;
  868.     P : PByte;
  869.   Begin
  870.     I := FPos;
  871.     if I >= FSize then
  872.       RaiseReadError;
  873.     P := FData;
  874.     Inc (P, I);
  875.     Result := P^;
  876.   End;
  877.  
  878. Function TMemoryReader.Match (const Buffer; const Size : Integer; const CaseSensitive : Boolean) : Integer;
  879. var I : Integer;
  880.     P : PByte;
  881.     R : Boolean;
  882.   Begin
  883.     I := FSize - FPos;
  884.     if I > Size then
  885.       I := Size;
  886.     if I <= 0 then
  887.       begin
  888.         Result := -1;
  889.         exit;
  890.       end;
  891.     P := FData;
  892.     Inc (P, FPos);
  893.     if CaseSensitive then
  894.       R := CompareMem (Buffer, P^, I) else
  895.       R := CompareMemNoCase (Buffer, P^, I);
  896.     if R then
  897.       Result := I else
  898.       Result := -1;
  899.   End;
  900.  
  901. Function TMemoryReader.EOF : Boolean;
  902.   Begin
  903.     Result := FPos >= FSize;
  904.   End;
  905.  
  906.  
  907.  
  908. {                                                                              }
  909. { TStringReader                                                                }
  910. {                                                                              }
  911. Constructor TStringReader.Create (const Data : String);
  912.   Begin
  913.     inherited Create (Pointer (Data), Length (Data));
  914.     FDataString := Data;
  915.   End;
  916.  
  917. Function TStringReader.GetAsString : String;
  918.   Begin
  919.     Result := FDataString;
  920.   End;
  921.  
  922.   
  923.  
  924. {                                                                              }
  925. { TFileReader                                                                  }
  926. {                                                                              }
  927. Constructor TFileReader.Create (const FileName : String);
  928.   Begin
  929.     inherited Create;
  930.     FHandle := FileOpen (FileName, fmOpenRead or fmShareDenyNone);
  931.     if FHandle = -1 then
  932.       raise EFileReader.Create ('File open error');
  933.     FHandleOwner := True;
  934.   End;
  935.  
  936. Constructor TFileReader.Create (const FileHandle : Integer; const HandleOwner : Boolean);
  937.   Begin
  938.     inherited Create;
  939.     FHandle := FileHandle;
  940.     FHandleOwner := HandleOwner;
  941.   End;
  942.  
  943. Destructor TFileReader.Destroy;
  944.   Begin
  945.     if FHandleOwner and (FHandle <> -1) and (FHandle <> 0) then
  946.       FileClose (FHandle);
  947.     inherited Destroy;
  948.   End;
  949.  
  950. Function TFileReader.GetPosition : Int64;
  951.   Begin
  952.     Result := FileSeek (FHandle, Int64 (0), 1);
  953.     if Result = -1 then
  954.       raise EFileReader.Create ('File error');
  955.   End;
  956.  
  957. Procedure TFileReader.SetPosition (const Position : Int64);
  958.   Begin
  959.     if FileSeek (FHandle, Position, 0) = -1 then
  960.       raise EFileReader.Create ('File seek error');
  961.   End;
  962.  
  963. Function TFileReader.GetSize : Int64;
  964. var I : Int64;
  965.   Begin
  966.     I := GetPosition;
  967.     Result := FileSeek (FHandle, Int64 (0), 2);
  968.     SetPosition (I);
  969.     if Result = -1 then
  970.       raise EFileReader.Create ('File error');
  971.   End;
  972.  
  973. Function TFileReader.Read (var Buffer; const Size : Integer) : Integer;
  974. var I : Integer;
  975.   Begin
  976.     if Size <= 0 then
  977.       begin
  978.         Result := 0;
  979.         exit;
  980.       end;
  981.     I := FileRead (FHandle, Buffer, Size);
  982.     if I <= 0 then
  983.       begin
  984.         Result := 0;
  985.         exit;
  986.       end;
  987.     Result := I;
  988.   End;
  989.  
  990. Function TFileReader.EOF : Boolean;
  991.   Begin
  992.     Result := GetPosition >= GetSize;
  993.   End;
  994.  
  995.  
  996.  
  997. { ReadFileToStr                                                                }
  998. Function ReadFileToStr (const FileName : String) : String;
  999. var F : TFileReader;
  1000.   Begin
  1001.     F := TFileReader.Create (FileName);
  1002.     try
  1003.       Result := F.GetAsString;
  1004.     finally
  1005.       F.Free;
  1006.     end;
  1007.   End;
  1008.  
  1009.  
  1010.  
  1011. {                                                                              }
  1012. { AReaderProxy                                                                 }
  1013. {                                                                              }
  1014. Constructor AReaderProxy.Create (const Reader : AReaderEx; const ReaderOwner : Boolean);
  1015.   Begin
  1016.     inherited Create;
  1017.     FReader := Reader;
  1018.     FReaderOwner := ReaderOwner;
  1019.   End;
  1020.  
  1021. Destructor AReaderProxy.Destroy;
  1022.   Begin
  1023.     if FReaderOwner then
  1024.       FreeAndNil (FReader);
  1025.     inherited Destroy;
  1026.   End;
  1027.  
  1028. Function AReaderProxy.Read (var Buffer; const Size : Integer) : Integer;
  1029.   Begin
  1030.     Result := FReader.Read (Buffer, Size);
  1031.   End;
  1032.  
  1033. Function AReaderProxy.EOF : Boolean;
  1034.   Begin
  1035.     Result := FReader.EOF;
  1036.   End;
  1037.  
  1038. Function AReaderProxy.GetPosition : Int64;
  1039.   Begin
  1040.     Result := FReader.GetPosition;
  1041.   End;
  1042.  
  1043. Procedure AReaderProxy.SetPosition (const Position : Int64);
  1044.   Begin
  1045.     FReader.SetPosition (Position);
  1046.   End;
  1047.  
  1048. Function AReaderProxy.GetSize : Int64;
  1049.   Begin
  1050.     Result := FReader.GetSize;
  1051.   End;
  1052.  
  1053.  
  1054.  
  1055. {                                                                              }
  1056. { TReaderProxy                                                                 }
  1057. {                                                                              }
  1058. Constructor TReaderProxy.Create (const Reader : AReaderEx; const ReaderOwner : Boolean; const Size : Int64);
  1059.   Begin
  1060.     inherited Create (Reader, ReaderOwner);
  1061.     FOffset := Reader.GetPosition;
  1062.     FSize := Size;
  1063.   End;
  1064.  
  1065. Function TReaderProxy.GetPosition : Int64;
  1066.   Begin
  1067.     Result := FReader.GetPosition - FOffset;
  1068.   End;
  1069.  
  1070. Procedure TReaderProxy.SetPosition (const Position : Int64);
  1071.   Begin
  1072.     if Position < 0 then
  1073.       raise EReader.Create ('Seek error');
  1074.     if (FSize >= 0) and (Position > FOffset + FSize) then
  1075.       raise EReader.Create ('Seek error');
  1076.     FReader.SetPosition (FOffset + Position);
  1077.   End;
  1078.  
  1079. Function TReaderProxy.GetSize : Int64;
  1080.   Begin
  1081.     Result := FReader.GetSize - FOffset;
  1082.     if (FSize >= 0) and (FSize < Result) then
  1083.       Result := FSize;
  1084.   End;
  1085.  
  1086. Function TReaderProxy.EOF : Boolean;
  1087.   Begin
  1088.     Result := FReader.EOF;
  1089.     if Result or (FSize < 0) then
  1090.       exit;
  1091.     Result := FReader.Position >= FOffset + FSize;
  1092.   End;
  1093.  
  1094. Function TReaderProxy.Read (var Buffer; const Size : Integer) : Integer;
  1095. var L : Integer;
  1096.     M : Int64;
  1097.   Begin
  1098.     L := Size;
  1099.     if FSize >= 0 then
  1100.       begin
  1101.         M := FSize - (FReader.Position - FOffset);
  1102.         if M < L then
  1103.           L := Integer (M);
  1104.       end;
  1105.     if L <= 0 then
  1106.       begin
  1107.         Result := 0;
  1108.         exit;
  1109.       end;
  1110.     Result := FReader.Read (Buffer, L);
  1111.   End;
  1112.  
  1113.  
  1114.  
  1115. {                                                                              }
  1116. { TBufferedReader                                                              }
  1117. {                                                                              }
  1118. Constructor TBufferedReader.Create (const Reader : AReaderEx; const BufferSize : Integer; const ReaderOwner : Boolean);
  1119.   Begin
  1120.     inherited Create (Reader, ReaderOwner);
  1121.     FBufferSize := BufferSize;
  1122.     GetMem (FBuffer, BufferSize);
  1123.     FPos := Reader.GetPosition;
  1124.   End;
  1125.  
  1126. Destructor TBufferedReader.Destroy;
  1127.   Begin
  1128.     if Assigned (FBuffer) then
  1129.       FreeMem (FBuffer);
  1130.     inherited Destroy;
  1131.   End;
  1132.  
  1133. Function TBufferedReader.GetPosition : Int64;
  1134.   Begin
  1135.     Result := FPos;
  1136.   End;
  1137.  
  1138. Function TBufferedReader.GetSize : Int64;
  1139.   Begin
  1140.     Result := FReader.GetSize;
  1141.   End;
  1142.  
  1143. Procedure TBufferedReader.SetPosition (const Position : Int64);
  1144. var B, C : Int64;
  1145.   Begin
  1146.     B := Position - FPos;
  1147.     if B = 0 then
  1148.       exit;
  1149.     C := B + FBufPos;
  1150.     if (C >= 0) and (C <= FBufUsed) then
  1151.       begin
  1152.         Inc (FBufPos, Integer (B));
  1153.         FPos := Position;
  1154.         exit;
  1155.       end;
  1156.     FReader.SetPosition (Position);
  1157.     FPos := Position;
  1158.     FBufPos := 0;
  1159.     FBufUsed := 0;
  1160.   End;
  1161.  
  1162. Procedure TBufferedReader.Skip (const Count : Integer);
  1163. var I : Integer;
  1164.     P : Int64;
  1165.   Begin
  1166.     if Count < 0 then
  1167.       raise EReader.Create ('Seek error');
  1168.     if Count = 0 then
  1169.       exit;
  1170.     I := FBufUsed - FBufPos;
  1171.     if I >= Count then
  1172.       begin
  1173.         Inc (FBufPos, Count);
  1174.         Inc (FPos, Count);
  1175.         exit;
  1176.       end;
  1177.     P := GetPosition + Count;
  1178.     FReader.SetPosition (P);
  1179.     FPos := P;
  1180.     FBufPos := 0;
  1181.     FBufUsed := 0;
  1182.   End;
  1183.  
  1184. // Internal function FillBuf
  1185. // Returns True if buffer was only partially filled
  1186. Function TBufferedReader.FillBuf : Boolean;
  1187. var P : PByte;
  1188.     L, N : Integer;
  1189.   Begin
  1190.     L := FBufferSize - FBufUsed;
  1191.     if L <= 0 then
  1192.       begin
  1193.         Result := False;
  1194.         exit;
  1195.       end;
  1196.     P := FBuffer;
  1197.     Inc (P, FBufPos);
  1198.     N := FReader.Read (P^, L);
  1199.     Inc (FBufUsed, N);
  1200.     Result := N < L;
  1201.   End;
  1202.  
  1203. Function TBufferedReader.Read (var Buffer; const Size : Integer) : Integer;
  1204. var L, M : Integer;
  1205.     P, Q : PByte;
  1206.     R : Boolean;
  1207.   Begin
  1208.     if Size <= 0 then
  1209.       begin
  1210.         Result := 0;
  1211.         exit;
  1212.       end;
  1213.     Q := @Buffer;
  1214.     M := Size;
  1215.     R := False;
  1216.     Repeat
  1217.       L := FBufUsed - FBufPos;
  1218.       if L > M then
  1219.         L := M;
  1220.       if L > 0 then
  1221.         begin
  1222.           P := FBuffer;
  1223.           Inc (P, FBufPos);
  1224.           MoveMem (P^, Q^, L);
  1225.           Inc (FBufPos, L);
  1226.           Inc (FPos, L);
  1227.           Dec (M, L);
  1228.           if M = 0 then
  1229.             begin
  1230.               Result := Size;
  1231.               exit;
  1232.             end;
  1233.           Inc (Q, L);
  1234.         end;
  1235.       FBufPos := 0;
  1236.       FBufUsed := 0;
  1237.       if R then
  1238.         begin
  1239.           Result := Size - M;
  1240.           exit;
  1241.         end;
  1242.       R := FillBuf;
  1243.     Until False;
  1244.   End;
  1245.  
  1246. Function TBufferedReader.EOF : Boolean;
  1247.   Begin
  1248.     if FBufUsed > FBufPos then
  1249.       Result := False else
  1250.       Result := FReader.EOF;
  1251.   End;
  1252.  
  1253. Procedure TBufferedReader.InvalidateBuffer;
  1254.   Begin
  1255.     FReader.SetPosition (FPos);
  1256.     FBufPos := 0;
  1257.     FBufUsed := 0;
  1258.   End;
  1259.  
  1260. // Internal function BufferByte
  1261. // Fills buffer with at least one character, otherwise raises an exception
  1262. Procedure TBufferedReader.BufferByte;
  1263. var I : Integer;
  1264.   Begin
  1265.     I := FBufUsed;
  1266.     if FBufPos < I then
  1267.       exit;
  1268.     if I >= FBufferSize then
  1269.       begin
  1270.         FBufPos := 0;
  1271.         FBufUsed := 0;
  1272.       end;
  1273.     FillBuf;
  1274.     if FBufPos >= FBufUsed then
  1275.       RaiseReadError;
  1276.   End;
  1277.  
  1278. Function TBufferedReader.ReadByte : Byte;
  1279. var P : PByte;
  1280.   Begin
  1281.     BufferByte;
  1282.     P := FBuffer;
  1283.     Inc (P, FBufPos);
  1284.     Result := P^;
  1285.     Inc (FBufPos);
  1286.     Inc (FPos);
  1287.   End;
  1288.  
  1289. Function TBufferedReader.PeekByte : Byte;
  1290. var P : PByte;
  1291.   Begin
  1292.     BufferByte;
  1293.     P := FBuffer;
  1294.     Inc (P, FBufPos);
  1295.     Result := P^;
  1296.   End;
  1297.  
  1298. Function TBufferedReader.PosBuf (const C : CharSet; const LocateNonMatch : Boolean; const MaxOffset : Integer) : Integer;
  1299. var P : PChar;
  1300.     L : Integer;
  1301.   Begin
  1302.     P := FBuffer;
  1303.     L := FBufPos;
  1304.     Inc (P, L);
  1305.     Result := 0;
  1306.     While (L < FBufUsed) and ((MaxOffset < 0) or (Result <= MaxOffset)) do
  1307.       if (P^ in C) xor LocateNonMatch then
  1308.         exit else
  1309.         begin
  1310.           Inc (P);
  1311.           Inc (L);
  1312.           Inc (Result);
  1313.         end;
  1314.     Result := -1;
  1315.   End;
  1316.  
  1317. Function TBufferedReader.Locate (const C : CharSet; const LocateNonMatch : Boolean; const MaxOffset : Integer) : Integer;
  1318. var I, J, M, K : Integer;
  1319.     P : Int64;
  1320.     R : Boolean;
  1321.   Begin
  1322.     P := GetPosition;
  1323.     M := MaxOffset;
  1324.     J := 0;
  1325.     R := False;
  1326.     Repeat
  1327.       K := FBufUsed - FBufPos;
  1328.       if K > 0 then
  1329.         begin
  1330.           I := PosBuf (C, LocateNonMatch, M);
  1331.           if I >= 0 then
  1332.             begin
  1333.               SetPosition (P);
  1334.               Result := J + I;
  1335.               exit;
  1336.             end;
  1337.         end;
  1338.       if R then
  1339.         begin
  1340.           SetPosition (P);
  1341.           Result := -1;
  1342.           exit;
  1343.         end;
  1344.       Inc (J, K);
  1345.       Inc (FPos, K);
  1346.       FBufPos := 0;
  1347.       FBufUsed := 0;
  1348.       if M >= 0 then
  1349.         begin
  1350.           Dec (M, K);
  1351.           if M < 0 then
  1352.             begin
  1353.               SetPosition (P);
  1354.               Result := -1;
  1355.               exit;
  1356.             end;
  1357.         end;
  1358.       R := FillBuf;
  1359.     Until False;
  1360.   End;
  1361.  
  1362.  
  1363.  
  1364. {                                                                              }
  1365. { TSplitBufferedReader                                                         }
  1366. {                                                                              }
  1367. Constructor TSplitBufferedReader.Create (const Reader : AReaderEx; const BufferSize : Integer; const ReaderOwner : Boolean);
  1368. var I : Integer;
  1369.   Begin
  1370.     inherited Create (Reader, ReaderOwner);
  1371.     FBufferSize := BufferSize;
  1372.     For I := 0 to 1 do
  1373.       GetMem (FBuffer [I], BufferSize);
  1374.     FPos := Reader.GetPosition;
  1375.   End;
  1376.  
  1377. Destructor TSplitBufferedReader.Destroy;
  1378. var I : Integer;
  1379.   Begin
  1380.     For I := 0 to 1 do
  1381.       if Assigned (FBuffer [I]) then
  1382.         FreeMem (FBuffer [I]);
  1383.     inherited Destroy;
  1384.   End;
  1385.  
  1386. Function TSplitBufferedReader.GetSize : Int64;
  1387.   Begin
  1388.     Result := FReader.GetSize;
  1389.   End;
  1390.  
  1391. Function TSplitBufferedReader.GetPosition : Int64;
  1392.   Begin
  1393.     Result := FPos;
  1394.   End;
  1395.  
  1396. // Internal function BufferStart used by SetPosition
  1397. // Returns the relative offset of the first buffered byte
  1398. Function TSplitBufferedReader.BufferStart : Integer;
  1399.   Begin
  1400.     Result := -FBufPos;
  1401.     if FBufNr = 1 then
  1402.       Dec (Result, FBufUsed [0]);
  1403.   End;
  1404.  
  1405. // Internal function BufferRemaining used by SetPosition
  1406. // Returns the length of the remaining buffered data
  1407. Function TSplitBufferedReader.BufferRemaining : Integer;
  1408.   Begin
  1409.     Result := FBufUsed [FBufNr] - FBufPos;
  1410.     if FBufNr = 0 then
  1411.       Inc (Result, FBufUsed [1]);
  1412.   End;
  1413.  
  1414. Procedure TSplitBufferedReader.SetPosition (const Position : Int64);
  1415. var D : Int64;
  1416.   Begin
  1417.     D := Position - FPos;
  1418.     if D = 0 then
  1419.       exit;
  1420.     if (D >= BufferStart) and (D <= BufferRemaining) then
  1421.       begin
  1422.         Inc (FBufPos, D);
  1423.         if (FBufNr = 1) and (FBufPos < 0) then // Set position from Buf1 to Buf0
  1424.           begin
  1425.             Inc (FBufPos, FBufUsed [0]);
  1426.             FBufNr := 0;
  1427.           end else
  1428.         if (FBufNr = 0) and (FBufPos > FBufUsed [0]) then // Set position from Buf0 to Buf1
  1429.           begin
  1430.             Dec (FBufPos, FBufUsed [0]);
  1431.             FBufNr := 1;
  1432.           end;
  1433.         FPos := Position;
  1434.         exit;
  1435.       end;
  1436.     FReader.SetPosition (Position);
  1437.     FPos := Position;
  1438.     FBufNr := 0;
  1439.     FBufPos := 0;
  1440.     FBufUsed [0] := 0;
  1441.     FBufUsed [1] := 0;
  1442.   End;
  1443.  
  1444. Procedure TSplitBufferedReader.InvalidateBuffer;
  1445.   Begin
  1446.     FReader.SetPosition (FPos);
  1447.     FBufNr := 0;
  1448.     FBufPos := 0;
  1449.     FBufUsed [0] := 0;
  1450.     FBufUsed [1] := 0;
  1451.   End;
  1452.  
  1453. // Internal function MoveBuf used by Read
  1454. // Moves remaining data from Buffer [BufNr]^[BufPos] to Dest
  1455. // Returns True if complete (Remaining=0)
  1456. Function TSplitBufferedReader.MoveBuf (var Dest : PByte; var Remaining : Integer) : Boolean;
  1457. var P : PByte;
  1458.     L, R, N, O : Integer;
  1459.   Begin
  1460.     N := FBufNr;
  1461.     O := FBufPos;
  1462.     L := FBufUsed [N] - O;
  1463.     if L <= 0 then
  1464.       begin
  1465.         Result := False;
  1466.         exit;
  1467.       end;
  1468.     P := FBuffer [N];
  1469.     Inc (P, O);
  1470.     R := Remaining;
  1471.     if R < L then
  1472.       L := R;
  1473.     MoveMem (P^, Dest^, L);
  1474.     Inc (Dest, L);
  1475.     Inc (FBufPos, L);
  1476.     Dec (R, L);
  1477.     if R <= 0 then
  1478.       Result := True else
  1479.       Result := False;
  1480.     Remaining := R;
  1481.   End;
  1482.  
  1483. // Internal function FillBuf used by Read
  1484. // Fill Buffer [BufNr]^[BufPos] with up to BufferSize bytes and moves
  1485. // the read data to Dest
  1486. // Returns True if complete (incomplete Read or Remaining=0)
  1487. Function TSplitBufferedReader.FillBuf (var Dest : PByte; var Remaining : Integer) : Boolean;
  1488. var P : PByte;
  1489.     I, L, N : Integer;
  1490.   Begin
  1491.     N := FBufNr;
  1492.     I := FBufUsed [N];
  1493.     L := FBufferSize - I;
  1494.     if L <= 0 then
  1495.       begin
  1496.         Result := False;
  1497.         exit;
  1498.       end;
  1499.     P := FBuffer [N];
  1500.     Inc (P, I);
  1501.     I := FReader.Read (P^, L);
  1502.     if I > 0 then
  1503.       begin
  1504.         Inc (FBufUsed [N], I);
  1505.         if MoveBuf (Dest, Remaining) then
  1506.           begin
  1507.             Result := True;
  1508.             exit;
  1509.           end;
  1510.       end;
  1511.     Result := I < L;
  1512.   End;
  1513.  
  1514. Function TSplitBufferedReader.Read (var Buffer; const Size : Integer) : Integer;
  1515. var Dest : PByte;
  1516.     Remaining : Integer;
  1517.   Begin
  1518.     if Size <= 0 then
  1519.       begin
  1520.         Result := 0;
  1521.         exit;
  1522.       end;
  1523.     Dest := @Buffer;
  1524.     Remaining := Size;
  1525.     Repeat
  1526.       if MoveBuf (Dest, Remaining) then
  1527.         begin
  1528.           Result := Size;
  1529.           Inc (FPos, Size);
  1530.           exit;
  1531.         end;
  1532.       if FillBuf (Dest, Remaining) then
  1533.         begin
  1534.           Result := Size - Remaining;
  1535.           Inc (FPos, Result);
  1536.           exit;
  1537.         end;
  1538.       if FBufNr = 0 then
  1539.         FBufNr := 1 else
  1540.         begin
  1541.           Swap (FBuffer [0], FBuffer [1]);
  1542.           FBufUsed [0] := FBufUsed [1];
  1543.           FBufUsed [1] := 0;
  1544.         end;
  1545.       FBufPos := 0;
  1546.     Until False;
  1547.   End;
  1548.  
  1549. Function TSplitBufferedReader.EOF : Boolean;
  1550.   Begin
  1551.     if FBufUsed [FBufNr] > FBufPos then
  1552.       Result := False else
  1553.       if FBufNr = 1 then
  1554.         Result := FReader.EOF else
  1555.         if FBufUsed [1] > 0 then
  1556.           Result := False else
  1557.           Result := FReader.EOF;
  1558.   End;
  1559.  
  1560.  
  1561.  
  1562. {                                                                              }
  1563. { TBufferedFileReader                                                          }
  1564. {                                                                              }
  1565. Constructor TBufferedFileReader.Create (const FileName : String; const BufferSize : Integer);
  1566.   Begin
  1567.     inherited Create (TFileReader.Create (FileName), BufferSize, True);
  1568.   End;
  1569.  
  1570. Constructor TBufferedFileReader.Create (const FileHandle : Integer; const HandleOwner : Boolean; const BufferSize : Integer);
  1571.   Begin
  1572.     inherited Create (TFileReader.Create (FileHandle, HandleOwner), BufferSize, True);
  1573.   End;
  1574.  
  1575.  
  1576.  
  1577. {                                                                              }
  1578. { TSplitBufferedFileReader                                                     }
  1579. {                                                                              }
  1580. Constructor TSplitBufferedFileReader.Create (const FileName : String; const BufferSize : Integer);
  1581.   Begin
  1582.     inherited Create (TFileReader.Create (FileName), BufferSize, True);
  1583.   End;
  1584.  
  1585.  
  1586.  
  1587. {                                                                              }
  1588. { Self-testing code                                                            }
  1589. {                                                                              }
  1590. Procedure TestReader (const Reader : AReaderEx; const FreeReader : Boolean);
  1591.   Begin
  1592.     try
  1593.       Reader.Position := 0;
  1594.       Assert (not Reader.EOF,                                  'Reader.EOF');
  1595.       Assert (Reader.Size = 26,                                'Reader.Size');
  1596.       Assert (Reader.PeekStr (0) = '',                         'Reader.PeekStr');
  1597.       Assert (Reader.PeekStr (-1) = '',                        'Reader.PeekStr');
  1598.       Assert (Reader.PeekStr (2) = '01',                       'Reader.PeekStr');
  1599.       Assert (Char (Reader.PeekByte) = '0',                    'Reader.PeekByte');
  1600.       Assert (Char (Reader.ReadByte) = '0',                    'Reader.ReadByte');
  1601.       Assert (Char (Reader.PeekByte) = '1',                    'Reader.PeekByte');
  1602.       Assert (Char (Reader.ReadByte) = '1',                    'Reader.ReadByte');
  1603.       Assert (Reader.ReadStr (0) = '',                         'Reader.ReadStr');
  1604.       Assert (Reader.ReadStr (-1) = '',                        'Reader.ReadStr');
  1605.       Assert (Reader.ReadStr (1) = '2',                        'Reader.ReadStr');
  1606.       Assert (Reader.MatchChar ('3'),                          'Reader.MatchChar');
  1607.       Assert (Reader.MatchStr ('3', True),                     'Reader.MatchStr');
  1608.       Assert (Reader.MatchStr ('345', True),                   'Reader.MatchStr');
  1609.       Assert (not Reader.MatchStr ('35', True),                'Reader.MatchStr');
  1610.       Assert (not Reader.MatchStr ('4', True),                 'Reader.MatchStr');
  1611.       Assert (not Reader.MatchStr ('', True),                  'Reader.MatchStr');
  1612.       Assert (Reader.ReadStr (2) = '34',                       'Reader.ReadStr');
  1613.       Assert (Reader.PeekStr (3) = '567',                      'Reader.PeekStr');
  1614.       Assert (Reader.Locate ('5', False, 0) = 0,               'Reader.Locate');
  1615.       Assert (Reader.Locate ('8', False, -1) = 3,              'Reader.Locate');
  1616.       Assert (Reader.Locate ('8', False, 3) = 3,               'Reader.Locate');
  1617.       Assert (Reader.Locate ('8', False, 2) = -1,              'Reader.Locate');
  1618.       Assert (Reader.Locate ('8', False, 4) = 3,               'Reader.Locate');
  1619.       Assert (Reader.Locate ('0', False, -1) = -1,             'Reader.Locate');
  1620.       Assert (Reader.Locate (['8'], False, -1) = 3,            'Reader.Locate');
  1621.       Assert (Reader.Locate (['8'], False, 3) = 3,             'Reader.Locate');
  1622.       Assert (Reader.Locate (['8'], False, 2) = -1,            'Reader.Locate');
  1623.       Assert (Reader.Locate (['0'], False, -1) = -1,           'Reader.Locate');
  1624.       Assert (Reader.LocateStr ('8', -1, True) = 3,            'Reader.LocateStr');
  1625.       Assert (Reader.LocateStr ('8', 3, True) = 3,             'Reader.LocateStr');
  1626.       Assert (Reader.LocateStr ('8', 2, True) = -1,            'Reader.LocateStr');
  1627.       Assert (Reader.LocateStr ('89', -1, True) = 3,           'Reader.LocateStr');
  1628.       Assert (Reader.LocateStr ('0', -1, True) = -1,           'Reader.LocateStr');
  1629.       Assert (not Reader.EOF,                                  'Reader.EOF');
  1630.       Assert (Reader.Position = 5,                             'Reader.Position');
  1631.       Reader.Position := 7;
  1632.       Reader.SkipByte;
  1633.       Assert (Reader.Position = 8,                             'Reader.Position');
  1634.       Reader.Skip (2);
  1635.       Assert (Reader.Position = 10,                            'Reader.Position');
  1636.       Assert (not Reader.EOF,                                  'Reader.EOF');
  1637.       Assert (Reader.MatchStr ('abcd', False),                 'Reader.MatchStr');
  1638.       Assert (not Reader.MatchStr ('abcd', True),              'Reader.MatchStr');
  1639.       Assert (Reader.LocateStr ('d', -1, True) = 3,            'Reader.LocateStr');
  1640.       Assert (Reader.LocateStr ('d', 3, False) = 3,            'Reader.LocateStr');
  1641.       Assert (Reader.LocateStr ('D', -1, True) = -1,           'Reader.LocateStr');
  1642.       Assert (Reader.LocateStr ('D', -1, False) = 3,           'Reader.LocateStr');
  1643.       Assert (Reader.SkipAll ('X', False, -1) = 0,             'Reader.SkipAll');
  1644.       Assert (Reader.SkipAll ('A', False, -1) = 1,             'Reader.SkipAll');
  1645.       Assert (Reader.SkipAll (['b', 'C'], False, -1) = 2,      'Reader.SkipAll');
  1646.       Assert (Reader.SkipAll (['d'], False, 0) = 0,            'Reader.SkipAll');
  1647.       Assert (Reader.ExtractAll (['d', 'E'], False, 1) = 'd',  'Reader.ExtractAll');
  1648.       Assert (Reader.ExtractAll (['*'], True, 1) = 'E',        'Reader.ExtractAll');
  1649.       Assert (Reader.ReadStr (2) = '*.',                       'Reader.ReadStr');
  1650.       Assert (Reader.ExtractAll (['X'], False, 1) = 'X',       'Reader.ExtractAll');
  1651.       Assert (Reader.ExtractAll (['X'], False, -1) = 'XX',     'Reader.ExtractAll');
  1652.       Assert (Reader.ExtractAll (['X', '*'], True, 1) = 'Y',   'Reader.ExtractAll');
  1653.       Assert (Reader.ExtractAll (['X', '*'], True, -1) = 'YYY','Reader.ExtractAll');
  1654.       Assert (Reader.ExtractAll (['X'], False, -1) = '',       'Reader.ExtractAll');
  1655.       Assert (Reader.ExtractAll (['X'], True, -1) = '*.',      'Reader.ExtractAll');
  1656.       Assert (Reader.EOF,                                      'Reader.EOF');
  1657.       Assert (Reader.Position = 26,                            'Reader.Position');
  1658.       Reader.Position := Reader.Position - 2;
  1659.       Assert (Reader.PeekStr (3) = '*.',                       'Reader.PeekStr');
  1660.       Assert (Reader.ReadStr (3) = '*.',                       'Reader.ReadStr');
  1661.     finally
  1662.       if FreeReader then
  1663.         Reader.Free;
  1664.     end;
  1665.   End;
  1666.  
  1667. Procedure TestLineReader (const Reader : AReaderEx; const FreeReader : Boolean);
  1668.   Begin
  1669.     try
  1670.       Reader.Position := 0;
  1671.       Assert (not Reader.EOF,                    'Reader.EOF');
  1672.       Assert (Reader.ExtractLine = '1',          'Reader.ExtractLine');
  1673.       Assert (Reader.ExtractLine = '23',         'Reader.ExtractLine');
  1674.       Assert (Reader.ExtractLine = '',           'Reader.ExtractLine');
  1675.       Assert (Reader.ExtractLine = '4',          'Reader.ExtractLine');
  1676.       Assert (Reader.ExtractLine = '5',          'Reader.ExtractLine');
  1677.       Assert (Reader.ExtractLine = '6',          'Reader.ExtractLine');
  1678.       Assert (Reader.EOF,                        'Reader.EOF');
  1679.     finally
  1680.       if FreeReader then
  1681.         Reader.Free;
  1682.     end;
  1683.   End;
  1684.  
  1685. Procedure SelfTest;
  1686. var S : TStringReader;
  1687.     I : Integer;
  1688.   Begin
  1689.     S := TStringReader.Create ('0123456789AbCdE*.XXXYYYY*.');
  1690.     try
  1691.       TestReader (TReaderProxy.Create (S, False, -1), True);
  1692.       TestReader (S, False);
  1693.       TestReader (TBufferedReader.Create (S, 128, False), True);
  1694.       For I := 1 to 16 do
  1695.         TestReader (TBufferedReader.Create (S, I, False), True);
  1696.       TestReader (TSplitBufferedReader.Create (S, 128, False), True);
  1697.       For I := 1 to 16 do
  1698.         TestReader (TSplitBufferedReader.Create (S, I, False), True);
  1699.     finally
  1700.       S.Free;
  1701.     end;
  1702.  
  1703.     S := TStringReader.Create ('1'#13#10'23'#13#13'4'#10'5'#10#13'6');
  1704.     try
  1705.       TestLineReader (TReaderProxy.Create (S, False, -1), True);
  1706.       For I := 1 to 32 do
  1707.         TestLineReader (TBufferedReader.Create (S, I, False), True);
  1708.       For I := 1 to 32 do
  1709.         TestLineReader (TSplitBufferedReader.Create (S, I, False), True);
  1710.       TestLineReader (S, False);
  1711.     finally
  1712.       S.Free;
  1713.     end;
  1714.   End;
  1715.  
  1716.  
  1717.  
  1718. end.
  1719.  
  1720.