I spent hours on this, and when I discovered the solution, I was about to fall from my chair...
I'm reading a 6Gb AVI file uncompressed.
Using this variable to handle the file, in Delphi 10.4:
VideoFile:THandleStream;
...
VideoFile := THandleStream.Create(FileHandle);
I realized when going from seeks below 0x7FFFFFFF
was OK, but above was not OK.
When I looked to the declarations, Offset
is an Int64
, OK:
function THandleStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
begin
Result := FileSeek(FHandle, Offset, Ord(Origin));
end;
Then FileSeek()
goes here with ... a 32-bit signed integer... That I did not go into at first glance. What a mistake!
function FileSeek(Handle: THandle; Offset, Origin: Integer): Integer;
begin
{$IFDEF MSWINDOWS}
Result := SetFilePointer(Handle, Offset, nil, Origin);
{$ENDIF MSWINDOWS}
{$IFDEF POSIX}
Result := lseek(Handle, Offset, Origin);
{$ENDIF POSIX}
end;
This is really nasty and very very bad... Why did Embarcadero choose this misleading implementation?
I have used VideoFile.Position := XXXX
to overcome the issue. But why leave Int64
in THandleStream.Seek()
?
CodePudding user response:
Your diagnosis is incorrect.
There are two versions of FileSeek()
- a 32bit version, and a 64bit version:
function FileSeek(Handle: THandle; Offset, Origin: Integer): Integer;
begin
{$IFDEF MSWINDOWS}
Result := SetFilePointer(Handle, Offset, nil, Origin);
{$ENDIF MSWINDOWS}
{$IFDEF POSIX}
Result := lseek(Handle, Offset, Origin);
{$ENDIF POSIX}
end;
function FileSeek(Handle: THandle; const Offset: Int64; Origin: Integer): Int64;
{$IFDEF MSWINDOWS}
begin
Result := Offset;
Int64Rec(Result).Lo := SetFilePointer(Handle, Int64Rec(Result).Lo,
@Int64Rec(Result).Hi, Origin);
if (Int64Rec(Result).Lo = $FFFFFFFF) and (GetLastError <> 0) then
Int64Rec(Result).Hi := $FFFFFFFF;
end;
{$ENDIF MSWINDOWS}
{$IFDEF POSIX}
begin
Result := lseek(Handle, Offset, Origin);
end;
{$ENDIF POSIX}
You are looking only at the 32bit version of FileSeek()
, but THandleStream
overrides the 64bit version of TStream.Seek()
to call the 64bit version of FileSeek()
instead.
THandleStream.Seek()
is passing a THandle
, an Int64
, and a Byte
to FileSeek()
, so which version do you think is going to be called? The 64bit version. The compiler can upsize a Byte
to an Integer
in both cases, but it is not going to downsize an Int64
to an Integer
when it can pass the Int64
as-is instead. So the 64bit version of FileSeek()
is a better match for what THandleStream.Seek()
is passing.
If that were not the case, then your claim that:
I have used
VideoFile.Position := XXXX
to overcome the issue.
would not be true, since the TStream.Position
setter method simply calls the same 64bit Seek()
method that you are claiming to be having trouble with:
procedure TStream.SetPosition(const Pos: Int64);
begin
Seek(Pos, soBeginning); // <-- soBeginning is from TSeekOrigin
end;
So, whatever trouble you are actually having, it is not due to the 64bit THandleStream.Seek()
calling the 32bit FileSeek()
. That is simply not how THandleStream
works.