(*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * http://www.opensource.org/licenses/cddl1.php.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * http://www.opensource.org/licenses/cddl1.php.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying * information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Andreas Schneider
 *)
unit UBufferedStreams;

{$mode objfpc}{$H+}

interface

uses
  SysUtils, Classes, UEnhancedMemoryStream;

type

  { TBufferedStream }

  TBufferedStream = class(TEnhancedMemoryStream)
    constructor Create(ABaseStream: TStream; AOwnsBaseStream: Boolean = false); virtual;
    destructor Destroy; override;
  protected
    FBaseStream: TStream;
    FOwnsBaseStream: Boolean;
  public
    procedure Refresh; virtual;
    procedure Flush; virtual;
    function GetSize: Int64; override;
  end;
  TBufferedReader = class(TBufferedStream)
    constructor Create(ABaseStream: TStream; AOwnsBaseStream: Boolean = false); override;
    destructor Destroy; override;
  protected
    FReadBuffer: TEnhancedMemoryStream;
  public
    function Write(const Buffer; Count: Longint): Longint; override;
    function Read(var Buffer; Count: Longint): Longint; override;
    function Seek(Offset: Longint; Origin: Word): Longint; override;
    procedure Refresh; override;
  end;

implementation

{ TBufferedStream }

constructor TBufferedStream.Create(ABaseStream: TStream;
  AOwnsBaseStream: Boolean);
begin
  inherited Create;
  FBaseStream := ABaseStream;
  FOwnsBaseStream := AOwnsBaseStream;
  Refresh;
end;

destructor TBufferedStream.Destroy;
begin
  if FOwnsBaseStream and Assigned(FBaseStream) then
    FreeAndNil(FBaseStream);
  inherited;
end;

procedure TBufferedStream.Flush;
begin
  FBaseStream.Size := Size;
  FBaseStream.Position := 0;
  FBaseStream.CopyFrom(Self, 0);
end;

function TBufferedStream.GetSize: Int64;
begin
  Result := FBaseStream.Size;
end;

procedure TBufferedStream.Refresh;
begin
  Size := FBaseStream.Size;
  Position := 0;  
  CopyFrom(FBaseStream, 0);
end;

{ TBufferedReader }

constructor TBufferedReader.Create(ABaseStream: TStream;
  AOwnsBaseStream: Boolean);
begin
  FReadBuffer := TEnhancedMemoryStream.Create;
  inherited;
end;

destructor TBufferedReader.Destroy;
begin
  if Assigned(FReadBuffer) then FreeAndNil(FReadBuffer);
  inherited;
end;

function TBufferedReader.Read(var Buffer; Count: Integer): Longint;
begin
  Result := FReadBuffer.Read(Buffer, Count);
end;

procedure TBufferedReader.Refresh;
begin
  FReadBuffer.Size := FBaseStream.Size;
  FReadBuffer.Position := 0;
  FReadBuffer.CopyFrom(FBaseStream, 0);
  FReadBuffer.Position := 0;
  FBaseStream.Position := 0;
end;

function TBufferedReader.Seek(Offset: Integer; Origin: Word): Longint;
begin
  FBaseStream.Seek(Offset, Origin);
  Result := FReadBuffer.Seek(Offset, Origin);
end;

function TBufferedReader.Write(const Buffer; Count: Integer): Longint;
begin
  FBaseStream.Position := FReadBuffer.Position;
  FBaseStream.Write(Buffer, Count);
  Result := FReadBuffer.Write(Buffer, Count);
end;

end.

