unit Exporters;

interface

uses Classes, Dialogs, StrUtils, SysUtils, Math, Data, OniImgClass, OniDataClass;

type
  TExportHandlers = record
    Ext:     String[4];
    needed:  Boolean;
    Handler: function(connection: TOniData; fileid: LongWord; filename: String): Integer;
  end;

procedure ExportDatFile(connection: TOniData; fileid: LongWord; filename: String);
procedure ExportRawFiles(connection: TOniData; fileid: LongWord; filename: String);
procedure ExportRawFile(connection: TOniData; fileid: LongWord; dat_offset: LongWord; filename: String);
function ExportConverted(connection: TOniData; fileid: LongWord; filename: String): Integer;

function ExportSNDD(connection: TOniData; fileid: LongWord; filename: String): Integer;
function ExportTRAC(connection: TOniData; fileid: LongWord; filename: String): Integer;
function ExportTXAN(connection: TOniData; fileid: LongWord; filename: String): Integer;
function ExportImage(connection: TOniData; fileid: LongWord; filename: String): Integer;

var
  ExportHandlers: array[1..3] of TExportHandlers = (
//    (Ext:'ABNA'; needed:False),
//    (Ext:'AGDB'; needed:False),
    (Ext: 'SNDD'; needed: True; Handler: ExportSNDD),
//    (Ext:'TRAC'; needed:True; Handler:ExportTRAC),
//    (Ext:'TXAN'; needed:True; Handler:ExportTXAN),
    (Ext:'TXMB'; needed:True; Handler:ExportImage),
    (Ext:'TXMP'; needed:True; Handler:ExportImage)
);



implementation

uses Functions, DataStructures;



procedure ExportDatFile(connection: TOniData; fileid: LongWord; filename: String);
var
  filestream: TFileStream;
  Data: Tdata;
begin
  Data := connection.LoadDatFile(fileid);
  if FileExists(filename) then
  begin
    filestream := TFileStream.Create(filename, fmOpenReadWrite);
    filestream.Seek(0, soFromEnd);
  end
  else
  begin
    filestream := TFileStream.Create(filename, fmCreate);
  end;
  filestream.Write(Data[0], Length(Data));
  filestream.Free;
end;


procedure ExportRawFiles(connection: TOniData; fileid: LongWord; filename: String);
var
  i: Integer;
  rawlist: TRawList;
begin
  rawlist := connection.GetRawList(fileid);
  if Length(rawlist) > 0 then
    for i := 0 to High(rawlist) do
      ExportRawFile(connection, fileid, rawlist[i].src_offset, filename);
end;

procedure ExportRawFile(connection: TOniData; fileid: LongWord; dat_offset: LongWord; filename: String);
var
  filestream: TFileStream;
  Data: Tdata;
begin
  SetLength(Data, connection.GetRawInfo(fileid, dat_offset).raw_size);
  connection.LoadRawFile(fileid, dat_offset, @Data[0]);
  if FileExists(filename + '.raw0x' + IntToHex(dat_offset, 8)) then
  begin
    filestream := TFileStream.Create(filename + '.raw0x' + IntToHex(
      dat_offset, 8), fmOpenReadWrite);
    filestream.Seek(0, soFromEnd);
  end
  else
  begin
    filestream := TFileStream.Create(filename + '.raw0x' + IntToHex(dat_offset, 8), fmCreate);
  end;
  filestream.Write(Data[0], Length(Data));
  filestream.Free;
end;

function ExportConverted(connection: TOniData; fileid: LongWord; filename: String): Integer;
var
  i: Integer;
  fileinfo: TFileInfo;
begin
  fileinfo := connection.GetFileInfo(fileid);
  if Length(ExportHandlers) > 0 then
    for i := 0 to High(ExportHandlers) do
      if ExportHandlers[i].Ext = fileinfo.Extension then
        ExportHandlers[i].Handler(connection, fileid, filename);
end;




function ExportSNDD;
type
  TDatData = packed record
    {0x00}
    _fileid:         LongWord;
    level:           LongWord;
    FormatSize:      LongWord;
    AudioFormat:     Word;
    NumChannels:     Word;
    {0x10}
    SampleRate:      LongWord;
    ByteRate:        LongWord;
    BlockAlign:      Word;
    BitsPerSample:   Word;
    {0x1C}
    SizeExtHeader:   Word;
    SamplesPerBlock: Word;
    NumCoefficients: Word;
    Coefficients:    array[0..6] of LongWord;
    {0x3E}
    Duration:        Word;
    {0x40}
    RawSize:         LongWord;
    RawPos:          LongWord;
  end;
var
  filestream: TFileStream;
  DatData:     TDatData;
  i: Integer;
  Data: Tdata;

  //Wave Header Stuff
  ASCII_RIFF:   LongWord; //"RIFF"
  WAVE_Len:     LongWord;
  ASCII_WAVE:   LongWord; //"WAVE"
  ASCII_FMT:    LongWord; //"fmt "
  WAVE_FMT_Len: LongWord;
  ASCII_DATA:   LongWord; //"data"
  WAVE_DataLen:  LongWord;
begin
  Result := export_noerror;
  connection.LoadDatFilePart(fileid, 0, SizeOf(DatData), @DatData);
  with DatData do
  begin
    //Initializing Header vars
    ASCII_RIFF   := 1179011410; // 'RIFF'
    WAVE_Len     := RAWSize + 70;
    ASCII_WAVE   := 1163280727;  // 'WAVE'
    ASCII_FMT    := 544501094;   // 'fmt '
    WAVE_FMT_Len := 50;          // 50 bytes
    ASCII_DATA   := 1635017060;  // 'data'
    WAVE_DataLen := RAWSize;
    SetLength(Data, RAWSize);
    connection.LoadRawFile(fileid, $44, Data);

    //Now start packing this into a neat wave...
    filestream := TFileStream.Create(filename + '.wav', fmCreate);
    filestream.Write(ASCII_RIFF, SizeOf(ASCII_RIFF));
    filestream.Write(WAVE_Len, SizeOf(WAVE_Len));
    filestream.Write(ASCII_WAVE, SizeOf(ASCII_WAVE));
    filestream.Write(ASCII_FMT, SizeOf(ASCII_FMT));
    filestream.Write(WAVE_FMT_Len, SizeOf(WAVE_FMT_Len));
    filestream.Write(AudioFormat, SizeOf(AudioFormat));
    filestream.Write(NumChannels, SizeOf(NumChannels));
    filestream.Write(Samplerate, SizeOf(Samplerate));
    filestream.Write(ByteRate, SizeOf(ByteRate));
    filestream.Write(BlockAlign, SizeOf(BlockAlign));
    filestream.Write(BitsPerSample, SizeOf(BitsPerSample));
    filestream.Write(SizeExtHeader, SizeOf(SizeExtHeader));
    filestream.Write(SamplesPerBlock, SizeOf(SamplesPerBlock));
    filestream.Write(NumCoefficients, SizeOf(NumCoefficients));
    for i := 0 to High(Coefficients) do
      filestream.Write(Coefficients[i], SizeOf(Coefficients[i]));
    filestream.Write(ASCII_DATA, SizeOf(ASCII_DATA));
    filestream.Write(WAVE_DataLen, SizeOf(WAVE_DataLen));
    filestream.Write(Data[0], Length(Data));
    filestream.Free;
  end;
end;




function ExportTRAC;
var
  link: LongWord;
  linkcount: Word;
  i: LongWord;
begin
  Result := export_noerror;

  connection.LoadDatFilePart(fileid, $18, SizeOf(link), @link);
  link := link div 256;

  connection.LoadDatFilePart(fileid, $1E, SizeOf(linkcount), @linkcount);
  for i := 1 to linkcount do
  begin
    connection.LoadDatFilePart(fileid, $20 + (i - 1) * 12 + 8, SizeOf(link), @link);
    link := link div 256;
  end;
end;




function ExportTXAN;
var
  loop_speed, unknown: Word;
  linkcount: LongWord;
  link: LongWord;
  i: Byte;
begin
  Result := export_noerror;

  connection.LoadDatFilePart(fileid, $14, SizeOf(loop_speed), @loop_speed);
  connection.LoadDatFilePart(fileid, $16, SizeOf(unknown), @unknown);

  connection.LoadDatFilePart(fileid, $1C, SizeOf(linkcount), @linkcount);
  for i := 0 to linkcount - 1 do
  begin
    connection.LoadDatFilePart(fileid, $20 + i * 4, SizeOf(link), @link);
    link := link div 256;
    if link = 0 then
      link := fileid - 1;
  end;
end;




function ExportImage;
var
  filestream: TFileStream;
  img: TOniImage;
  data: Tdata;
begin
  Result := export_noerror;

  img := TOniImage.Create;
  img.Load(connection, fileid);
  data := img.GetAsBMP;
  img.Free;

  filestream:=TFileStream.Create(filename+'.bmp',fmCreate);
  filestream.Write(data[0],Length(data));
  filestream.Free;
end;

end.