Martin Djernæs Web |
 |








|
 |
|
// ..................................................................
//
// mdFileStream
//
// Copyright © 2001-2002 by Martin Djernæs
//
// ..................................................................
// $Id: mdFileStream.pas,v 1.4 2002/10/25 02:28:04 martin Exp $
// ..................................................................
// Description:
// mdFileStream is a wrapper around the delphi TFileStream class,
// but uses a buffer for reading in parts of the file, when
// accessed. Also the the file can be accessed in a "pointer like"
// way.
//
// mdFileStream keep the position where the file was last read. All
// following reads in then done from the new position.
// ..................................................................
// Know issues:
// WARNING WARNING ... This have not been tested for general usage,
// but just been made for one single usage and the functionallity
// was only tested based on the ability to read semi-sequential
// from the beginning of a file.
// ..................................................................
// Initial Date: November 11th, 2001
// + We can read sequential through a file (also using big/little
// endian works)
// March 13th, 2002
// % Fixed a bug in seek (made the program crash!)
// October 24th, 2002
// + Added bounce check
// + Made seek virtual
// ..................................................................
unit mdFileStream;
interface
Uses
Windows, SysUtils, Classes;
Type
TEndian = (Little, Big);
TmdFileStream = class
Private
FName : String;
FStream : TFileStream;
FBufSize : Integer;
FBuf : PChar;
FBufStart : LongInt;
FBufUsed : LongInt;
FPos : LongInt;
FEndian : TEndian;
Procedure CheckBuffer(Index : LongInt);
function InBuffer(Index : LongInt) : Boolean;
function GetEOF : Boolean;
function GetData(Index : LongInt) : Byte;
Protected
Public
Constructor Create(Const FileName : String; Mode: Word);
Destructor Destroy; Override;
// Read bytes from the buffer
function Read(var Buffer; Count: Longint): Longint;
// Get one byte from the buffer (as byte or char)
Function GetByte : Byte;
Function GetChar : Char;
// Get a word from the buffer
Function GetWord : Word;
// Get a double word / integer from the buffer
Function GetInt : DWord;
// Seek a special position. This should
// be changed the match the normal file seek function.
Procedure Seek(Pos : LongInt); Virtual;
// Find the next occourance on a byte.
// Return true if it was found, and the next read will
// read that byte.
Function SeekByte(AByte : Byte) : Boolean;
// Are we at the end of the file (actually, are we
// after the end)
Property EOF : Boolean Read GetEOF;
// The current position, in bytes from the beginning
// (first = 0)
Property Position : LongInt Read FPos Write Seek;
// Access data in the file on position "index"
Property Data[Index : LongInt] : Byte read GetData;
// Select the endian format used the return words and
// integers. Default is big endian.
Property Endian : TEndian Read FEndian Write FEndian;
end;
implementation
//
// Construct our own object
//
Constructor TmdFileStream.Create(Const FileName : String; Mode: Word);
Begin
Inherited Create;
FBufSize := 1024; // Static 1 K byte of read buffer
FName := FileName;
FStream := TFileStream.Create(FName, Mode);
GetMem(FBuf, FBufSize);
FBufStart := FStream.Position;
FBufUsed := FStream.Read(FBuf^, FBufSize);
FPos := 0;
FEndian := Big;
end;
//
// Release our memory again
//
Destructor TmdFileStream.Destroy;
Begin
FreeMem(FBuf, FBufSize);
FStream.Free;
Inherited Destroy;
end;
//
// Check if we want to read a byte inside our current buffer.
// if it's not inside the buffer make sure that we actually
// have the right data in our buffer
//
Procedure TmdFileStream.CheckBuffer(Index : LongInt);
Begin
If NOT InBuffer(Index) Then
Begin
FStream.Seek(Index, soFromBeginning);
FBufStart := FStream.Position;
FBufUsed := FStream.Read(FBuf^, FBufSize);
end;
end;
//
// Check that Index is in the buffer
//
function TmdFileStream.InBuffer(Index : LongInt) : Boolean;
Begin
Result := (Index >= FBufStart) AND (Index < (FBufUsed+FBufStart));
end;
//
// Are we at the end of the File... ?
// (Not sure that this always work!)
//
function TmdFileStream.GetEOF : Boolean;
Begin
Result := FBufUsed = 0;
end;
//
// Read X bytes from the current position
//
function TmdFileStream.Read(var Buffer; Count: Longint): Longint;
Begin
Result := 0;
While (NOT EOF) AND (Result < Count) do
Begin
PChar(Buffer)[Result] := GetChar;
Inc(Result);
end;
end;
//
// Get One Byte from the buffer
//
Function TmdFileStream.GetData(Index : LongInt) : Byte;
Begin
CheckBuffer(Index);
If NOT EOF Then
Begin
Result := Byte(FBuf[Index-FBufStart]);
FPos := Index+1;
end
else
raise Exception.Create('Out of bounds');
end;
//
// Get next byte from the buffer
//
Function TmdFileStream.GetByte : Byte;
Begin
Result := GetData(FPos);
end;
//
// Get Next word from the buffer
//
Function TmdFileStream.GetWord : Word;
Begin
If FEndian = Big Then
Result := (GetByte SHL 8) OR (GetByte)
else
Result := (GetByte) OR (GetByte SHL 8);
end;
//
// Get next integer (Double Word)
//
Function TmdFileStream.GetInt : DWord;
Begin
If FEndian = Big Then
Result := (GetWord SHL 16) OR (GetWord)
else
Result := (GetWord) OR (GetWord SHL 16);
end;
//
// The same a GetByte, just returning a char!
//
Function TmdFileStream.GetChar : Char;
Begin
Result := Char(GetByte);
end;
//
// Seek to a new position
// (Change this to be more "standard like")
//
Procedure TmdFileStream.Seek(Pos : LongInt);
Begin
FPos := Pos;
end;
//
// Find the next occurance of a byte
//
Function TmdFileStream.SeekByte(AByte : Byte) : Boolean;
Begin
Result := False;
CheckBuffer(FPos);
While Byte(FBuf[FPos-FBufStart]) <> AByte do
Begin
Inc(FPos);
CheckBuffer(FPos);
If EOF Then
Exit;
end;
Result := True;
end;
end.
|
 |
Copyright © 1998-2003 by
Martin Djernæs,
all rights reserved.
|