--- Merging r32797 into '.':

U    packages/fcl-base/src/streamex.pp
--- Recording mergeinfo for merge of r32797 into '.':
 U   .

# revisions: 32797

git-svn-id: branches/fixes_3_0@33350 -
This commit is contained in:
marco 2016-03-27 18:49:43 +00:00
parent 1c6795bd6d
commit 6a42afd135

View File

@ -156,6 +156,28 @@ type
function ReadLine: string; override; overload;
end;
{ allows you to represent just a small window of a bigger stream as a substream.
also makes sure one is actually at the correct position before clobbering stuff. }
TWindowedStream = class(TOwnerStream)
private
fStart : Int64; // in the source.
fFrontier : Int64; // in the source.
fStartingPositionHere : Int64; // position in this Stream corresponding to Position = fStart in the source.
fPositionHere : Int64; // position in this Stream.
protected
//function GetPosition() : Int64; override; = Seek(0, soCurrent) already.
function GetSize() : Int64; override;
procedure SetSize(const NewSize: Int64); override; overload;
public
constructor Create(aStream : TStream; const aSize : Int64; const aPositionHere : Int64 = 0);
destructor Destroy(); override;
function Read(var aBuffer; aCount : longint) : longint; override;
function Write(const aBuffer; aCount : Longint): Longint; override;
function Seek(const aOffset: Int64; aOrigin: TSeekorigin): Int64; override;
end;
TStreamHelper = class helper for TStream
function ReadWordLE :word;
function ReadDWordLE:dword;
@ -183,6 +205,13 @@ type
Implementation
ResourceString
SErrCannotWriteOutsideWindow = 'Cannot write outside allocated window.';
SErrInvalidSeekWindow = 'Cannot seek outside allocated window.';
SErrInvalidSeekOrigin = 'Invalid seek origin.';
SErrCannotChangeWindowSize = 'Cannot change the size of a windowed stream';
{ TBidirBinaryObjectReader }
function TBidirBinaryObjectReader.GetPosition: Longint;
@ -607,4 +636,103 @@ begin
end;
{$endif}
{ TWindowedStream }
constructor TWindowedStream.Create(aStream : TStream; const aSize : Int64; const aPositionHere : Int64 = 0);
begin
inherited Create(aStream);
fStart := aStream.Position;
fFrontier := fStart + aSize;
fStartingPositionHere := aPositionHere;
fPositionHere := aPositionHere;
end;
destructor TWindowedStream.Destroy();
begin
inherited Destroy();
end;
function TWindowedStream.Read(var aBuffer; aCount : longint) : longint;
var
vSourcePosition : Int64;
vNewSourcePosition : Int64;
begin
vSourcePosition := Source.Position;
vNewSourcePosition := fStart + fPositionHere - fStartingPositionHere;
if vNewSourcePosition <> vSourcePosition then // someone modified the file position. Bad bad.
Source.Seek(vNewSourcePosition, 0);
if vNewSourcePosition + aCount > fFrontier then // trying to access outside.
aCount := fFrontier - vNewSourcePosition;
Result := Source.Read(aBuffer, aCount);
Inc(fPositionHere, Result);
end;
function TWindowedStream.Write(const aBuffer; aCount : Longint): Longint;
var
vSourcePosition : Int64;
vNewSourcePosition : Int64;
begin
vSourcePosition := Source.Position;
vNewSourcePosition := fStart + fPositionHere - fStartingPositionHere;
if vNewSourcePosition <> vSourcePosition then // someone modified the file position. Bad bad.
Source.Seek(vNewSourcePosition, 0);
if vNewSourcePosition + aCount > fFrontier then // trying to access outside.
Raise EWriteError.Create(SErrCannotWriteOutsideWindow);
//aCount := fFrontier - vNewSourcePosition;
Result := Source.Write(aBuffer, aCount);
Inc(fPositionHere, Result);
end;
function TWindowedStream.Seek(const aOffset: Int64; aOrigin: TSeekOrigin): Int64;
var
vNewPositionHere : Int64;
vSourcePosition : Int64;
begin
{
here there
fStartingPositionHere .... fStart
fPositionHere............. x
}
if (aOrigin = soCurrent) and (aOffset = 0) then begin // get position.
Result := fPositionHere;
Exit;
end;
if aOrigin = soBeginning then
vNewPositionHere := aOffset
else if aOrigin = soCurrent then
vNewPositionHere := fPositionHere + aOffset
else if aOrigin = soEnd then
vNewPositionHere := fStartingPositionHere + fFrontier - fStart + aOffset
else
raise EReadError.Create(SErrInvalidSeekOrigin);
vSourcePosition := fStart + vNewPositionHere - fStartingPositionHere;
if (vSourcePosition < 0) or (vSourcePosition >= fFrontier) then
raise EReadError.Create(SErrInvalidSeekWindow);
Result := Source.Seek(vSourcePosition, 0);
//if Result = -1 ??? can that happen?
Result := vNewPositionHere;
end;
function TWindowedStream.GetSize() : Int64;
begin
Result := fFrontier - fStart;
end;
procedure TWindowedStream.SetSize(const NewSize: Int64); overload;
begin
if NewSize = Self.GetSize() then
Exit;
raise EWriteError.Create(SErrCannotChangeWindowSize);
end;
end.