//::///////////////////////////////////////////////
//:: NeverPas - Sound Set File Format
//:: nw_ssf.pas
//:: Copyright (c) 2003 Errant Logic.
//:://////////////////////////////////////////////
{
  Contains data types and classes for manipulating
  and reading .ssf (sound set) files.
}
//:://////////////////////////////////////////////
//:: Created By:   Rob Parton
//:: Created On:   October 08, 2003
//:://////////////////////////////////////////////



unit nw_ssf;

interface

uses
  nw_generic,
//  Dialogs,
  SysUtils,
  Classes;

type
  { SSF Header }
  nw_ssfHeader = packed record
    FileType:     array[0..3] of Char; // 'SSF '
    FileVersion:  array[0..3] of Char; // 'V1.0' currently
    EntryCount:   DWORD;
    TableOffset:  DWORD;
    Padding:      array[0..23] of Byte; // later revisions
  end;

  nw_ssfTableEntry = packed record
    ResRef:   array[0..15] of Char;
    StrRef:   DWORD;
  end;

  TSSFFile = class(TObject)
  private
    Header: nw_ssfHeader;
    EntryTable: array of Dword;
    DataTable: array of nw_ssfTableEntry;
    FFilename: String;
    FLoaded: Boolean;
    FChanged: Boolean;
  public
    constructor Create;
    destructor Destroy; override;

    function LoadFile(Filename: string): Boolean;
    function Verify(Filetype, FileVersion: string): Boolean;

    function GetEntryCount(): Integer;

    function GetSSFStrRef(Index: DWORD): DWORD;
    function GetSSFResRef(Index: DWORD): String;
  end;

implementation

{ Base Constructor }
constructor TSSFFile.Create;
begin
  FLoaded := False;
end;

{ Base Destructor }
destructor TSSFFile.Destroy;
begin
  inherited Destroy;
end;

{ Load SSF }
function TSSFFile.LoadFile(Filename: string): Boolean;
var
  SSF: TFileStream;
  i: DWORD;
begin
  Result := False;
  if Not(FileExists(Filename)) Then Exit;

  SSF := TFileStream.Create(Filename, fmOpenRead);
  try
    // Not a valid file. (not big enough)
    if SSF.Size < SizeOf(nw_ssfHeader) Then Exit;

    SSF.Seek(0,soFromBeginning);
    SSF.Read(Header,SizeOf(nw_ssfHeader));

    if Not(Verify('SSF ','V1.0')) then Exit;

    if SSF.Size <= Header.TableOffset Then Exit;

    SetLength(EntryTable,Header.EntryCount);
    SetLength(DataTable, Header.EntryCount);

    SSF.Seek(Header.TableOffset, soFromBeginning);
    for i := 0 to Header.EntryCount - 1 do
    begin
      SSF.Read(EntryTable[i],SizeOf(DWord));
    end;

    for i := 0 to Header.EntryCount - 1 do
    begin
      SSF.Seek(EntryTable[i], soFromBeginning);
      SSF.Read(DataTable[i],SizeOf(nw_ssfTableEntry));
    end;

    FFilename := Filename;
    FLoaded := True;
    Result := True;
  finally
    SSF.Free;
  end;

end;

// Verify the Header with given types.
function TSSFFile.Verify(Filetype,FileVersion: string): Boolean;
begin
  Result := False;
  if (Header.FileType = Filetype) and (Header.FileVersion = FileVersion) then
    Result := True;
end;

{ Returns the StrRef of the given SSF Entry }
function TSSFFile.GetSSFStrRef(Index: DWORD): DWORD;
begin
  Result := $FFFFFFFF;
  if Index > Length(DataTable) Then Exit;
  Result := DataTable[Index].StrRef;
end;

function TSSFFile.GetSSFResRef(Index: DWORD): String;
begin
  Result := '';
  if Index > Length(DataTable) Then Exit;
  Result := DataTable[Index].ResRef;
end;

function TSSFFile.GetEntryCount(): Integer;
begin
  Result := Length(DataTable);
end;

end.
