UNIT Unit1_main;
INTERFACE
USES
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, StrUtils, Clipbrd, ExtCtrls, ComCtrls, Menus,
  Unit2_functions, Unit3_data, Unit5_preview;

TYPE
  TForm1 = Class(TForm)
    panel_all: TPanel;
    panel_left: TPanel;
    Splitter1: TSplitter;
    panel_files: TPanel;
    btn_extractallconvert: TButton;
    btn_extract: TButton;
    btn_extractconvert: TButton;
    list_files: TListBox;
    btn_extractall: TButton;
    list_extensions: TListBox;
    Splitter2: TSplitter;
    panel_right: TPanel;
    edit_data: TMemo;
    list_names: TListBox;
    Splitter3: TSplitter;
    panel_info: TPanel;
    lbl_info: TLabel;
    btn_load: TButton;
    btn_hexcopy: TButton;
    fopen: TOpenDialog;
    lbl_fileinfo: TLabel;
    group_progress: TGroupBox;
    progress: TProgressBar;
    lbl_progress: TLabel;
    menu: TMainMenu;
    menu_main: TMenuItem;
    menu_exit: TMenuItem;
    menu_preview: TMenuItem;
    btn_extractcancel: TButton;
    procedure btn_extractcancelClick(Sender: TObject);
    PROCEDURE menu_previewClick(Sender: TObject);
    PROCEDURE btn_extractallconvertClick(Sender: TObject);
    PROCEDURE Splitter2Moved(Sender: TObject);
    PROCEDURE Splitter1Moved(Sender: TObject);
    PROCEDURE FormClose(Sender: TObject; var Action: TCloseAction);
    PROCEDURE btn_hexcopyClick(Sender: TObject);
    PROCEDURE list_extensionsClick(Sender: TObject);
    PROCEDURE FormResize(Sender: TObject);
    PROCEDURE btn_extractconvertClick(Sender: TObject);
    PROCEDURE FormCreate(Sender: TObject);
    PROCEDURE list_filesDblClick(Sender: TObject);
    PROCEDURE btn_loadClick(Sender: TObject);
  PRIVATE
  PUBLIC
  END;

VAR
  Form1: TForm1;

IMPLEMENTATION
{$R *.dfm}

PROCEDURE DoAfterLoadOfADat;
  VAR
    i:LongWord;
    txt:Text;
    temp4:LongWord;
    temp2:Word;
    temp1:Byte;
  BEGIN
    IF NOT DirectoryExists(GetExtractPath) THEN
      CreateDir(GetExtractPath);
    AssignFile(txt,GetExtractPath+'\___TXMP-FILES___.TXT');
    ReWrite(txt);
    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
      IF (dat_extensionsmap[i].Extension[3]='T') AND
          (dat_extensionsmap[i].Extension[2]='X') AND
          (dat_extensionsmap[i].Extension[1]='M') AND
          (dat_extensionsmap[i].Extension[0]='P') THEN BEGIN
        WriteLn(txt, FormatNumber(dat_extensionsmap[i].ExtCount,4,'0')+' TXMP-Files');
        Break;
      END;
    END;
    WriteLn(txt,'FileName'+#9+'MipMap'+#9+'Depth'+#9+'ImgX'+#9+'ImgY'+#9+'StoreT');
    FOR i:=0 TO dat_header.Files-1 DO BEGIN
      IF dat_files[i].Extension='TXMP' THEN BEGIN
        Write(txt,dat_files[i].FileName+#9);
        LoadDatFilePart(i,$88,1,@temp1);
        Write(txt,IntToHex(temp1,2)+#9);
        LoadDatFilePart(i,$89,1,@temp1);
        Write(txt,IntToHex(temp1,2)+#9);
        LoadDatFilePart(i,$8C,2,@temp2);
        Write(txt,IntToHex(temp2,4)+#9);
        LoadDatFilePart(i,$8E,2,@temp2);
        Write(txt,IntToHex(temp2,4)+#9);
        LoadDatFilePart(i,$90,1,@temp1);
        Write(txt,IntToHex(temp1,2)+#9);
        WriteLn(txt,'');
      END;
    END;
    CloseFile(txt);

    IF NOT DirectoryExists(GetExtractPath) THEN
      CreateDir(GetExtractPath);
    AssignFile(txt,GetExtractPath+'\___TXAN-FILES___.TXT');
    ReWrite(txt);
    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
      IF (dat_extensionsmap[i].Extension[3]='T') AND
          (dat_extensionsmap[i].Extension[2]='X') AND
          (dat_extensionsmap[i].Extension[1]='A') AND
          (dat_extensionsmap[i].Extension[0]='N') THEN BEGIN
        WriteLn(txt, FormatNumber(dat_extensionsmap[i].ExtCount,4,'0')+' TXAN-Files');
        Break;
      END;
    END;
    WriteLn(txt,'FileName'+#9+'Loopspeed'+#9+'Unknown'+#9+'Links');
    FOR i:=0 TO dat_header.Files-1 DO BEGIN
      IF dat_files[i].Extension='TXAN' THEN BEGIN
        Write(txt,dat_files[i].FileName+#9);
        LoadDatFilePart(i,$14,2,@temp2);
        Write(txt,IntToHex(temp2,4)+#9);
        LoadDatFilePart(i,$16,2,@temp2);
        Write(txt,IntToHex(temp2,4)+#9);
        LoadDatFilePart(i,$1C,4,@temp4);
        Write(txt,IntToHex(temp4,8)+#9);
        WriteLn(txt,'');
      END;
    END;
    CloseFile(txt);
  END;

PROCEDURE TForm1.btn_loadClick(Sender: TObject);
  VAR i:LongWord;
  BEGIN
    fopen.InitialDir:=AppSettings.DatPath;
    IF fopen.Execute THEN BEGIN
      Form1.Caption:='Oni Un/Packer '+version+' ('+ExtractFileName(fopen.FileName)+')';
      AppSettings.DatPath:=ExtractFilepath(fopen.FileName);
      list_files.Items.Clear;
      list_extensions.Items.Clear;
      list_names.Items.Clear;
      IF LoadDatInfos(fopen.FileName) THEN BEGIN
        lbl_info.Caption:=
              '# of files: '+IntToStr(dat_header.Files)+CrLf+
              '# of named files: '+IntToStr(dat_header.NamedFiles)+CrLf+
              '# of extensions: '+IntToStr(dat_header.Extensions)+CrLf+
              'Address of Body: 0x'+IntToHex(dat_header.DataAddr,8)+CrLf+
              'Address of End: 0x'+IntToHex(dat_header.NamesAddr,8);
        list_extensions.Items.Add('_All files: '+FormatNumber(dat_header.Files,4,' '));
        FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
          WITH dat_extensionsmap[i] DO BEGIN
            list_extensions.Items.Add(
                Extension[3]+Extension[2]+Extension[1]+Extension[0]+': '+
                FormatNumber(ExtCount,4,' ')+' (Ident: 0x'+
                IntToHex(Ident[7],2)+IntToHex(Ident[6],2)+IntToHex(Ident[5],2)+IntToHex(Ident[4],2)+IntToHex(Ident[3],2)+IntToHex(Ident[2],2)+IntToHex(Ident[1],2)+IntToHex(Ident[0],2)+')');
          END;
        END;
        FOR i:=0 TO dat_header.namedFiles-1 DO BEGIN
          WITH dat_namedfilesmap[i] DO BEGIN
            list_names.Items.Add('0x'+IntToHex(filenumber,8)+': 0x'+IntToHex(blubb,8));
          END;
        END;
        Form1.list_extensions.ItemIndex:=0;
        Form1.list_extensionsClick(Form1);
        Form1.list_files.ItemIndex:=0;
        Form1.list_filesDblClick(Form1);

        DoAfterLoadOfADat;

      END ELSE BEGIN
        ShowMessage('Error while loading the file:'+CrLf+fopen.FileName+CrLf+'Perhaps not an Oni-.dat-file?');
      END;
    END;
  END;

PROCEDURE TForm1.list_filesDblClick(Sender: TObject);
  VAR
    id:LongWord;
    temp:Tdata;
  BEGIN
    id:=StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5));
    lbl_fileinfo.Caption:=
          'Filename: '+dat_files[id].FileName+CrLf+
          'Size: '+FormatFileSize(dat_files[id].Size)+' ('+IntToStr(dat_files[id].Size)+' Bytes)'+CrLf+
          'FileType: 0x'+IntToHex(dat_files[id].FileType,8)+CrLf+
          'Address in .dat: 0x'+IntTohex(dat_files[id].DatAddr,8);
    IF (dat_files[id].FileType AND $02)=0 THEN BEGIN
      temp:=LoadDatFile(id);
      edit_data.Text:=CreateHexString(temp,False);
      btn_hexcopy.Visible:=True;
      IF menu_preview.Checked THEN Form5.ShowPreview(id); 
    END ELSE BEGIN
      edit_data.Text:='Zero byte file.'+CrLf+'Oni will take the data for this file of level0_final.dat/raw';
      btn_hexcopy.Visible:=False;
    END;
  END;

PROCEDURE TForm1.FormCreate(Sender: TObject);
  BEGIN
    Form1.Caption:='Oni Un/Packer '+version;
    Form1.FormResize(Form1);

    panel_all.Align:=alClient;

    IF FileExists(ExtractFilepath(Application.EXEname)+'\oniunpacker.ini') THEN BEGIN
      AssignFile(AppSettingsFile,ExtractFilepath(Application.EXEname)+'\oniunpacker.ini');
      Reset(AppSettingsFile);
      Read(AppSettingsFile,AppSettings);
      CloseFile(AppSettingsFile);
    END ELSE BEGIN
      AppSettings.DatPath:='D:\Spiele\Oni\GameDataFolder';
      AppSettings.ExtractPath:='C:\Dokumente und Einstellungen\Administrator\Desktop';
    END;

    Form1.btn_loadClick(Form1);
  END;

PROCEDURE TForm1.btn_extractconvertClick(Sender: TObject);
  VAR
    result:Integer;
    id:LongWord;
  BEGIN
    id:=StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5));
    IF TComponent(Sender).Name='btn_extract' THEN
      result:=ExportFile(id,False)
    ELSE
      result:=ExportFile(id,True);
    CASE result OF
      0{export_noerror}: IF 1=2 THEN BEGIN END;
      1{export_nohandler}: ShowMessage('No export-handler for files with extension '+dat_files[id].Extension+'.');
      2{export_handlererror}: ShowMessage('Error while running data-handler for '+CrLf+dat_files[id].FileName);
      3{export_error}: ShowMessage('Error while exporting file '+CrLf+dat_files[id].FileName);
    ELSE ShowMessage('Couldn''t export file '+FormatNumber(id,5,'0')+CrLf+'(Unknown error)');
    END;
    Form1.list_files.SetFocus;
  END;

PROCEDURE TForm1.FormResize(Sender: TObject);
  CONST
    MinWidth:Integer=750;
    MinHeight:Integer=500;
  BEGIN
    IF NOT group_progress.Visible THEN BEGIN
      IF Form1.Width<MinWidth THEN Form1.Width:=MinWidth;
      IF Form1.Height<MinHeight THEN Form1.Height:=MinHeight;
    END;
  END;

PROCEDURE TForm1.list_extensionsClick(Sender: TObject);
  VAR
    Extension:String[4];
    i:LongWord;
  BEGIN
    Extension:=MidStr(list_extensions.Items.Strings[list_extensions.ItemIndex],1,4);
    list_files.Items.Clear;
    IF Extension='_All' THEN BEGIN
      FOR i:=0 TO dat_header.Files-1 DO
        list_files.Items.Add(dat_files[i].FileName);
    END ELSE BEGIN
      FOR i:=0 TO dat_header.Files-1 DO
        IF dat_files[i].Extension=Extension THEN
          list_files.Items.Add(dat_files[i].FileName);
    END;
  END;

PROCEDURE TForm1.btn_hexcopyClick(Sender: TObject);
  VAR
    temp:Tdata;
  BEGIN
    temp:=LoadDatFile(StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5)));
    Clipboard.SetTextBuf(PChar(CreateHexString(temp,True)));
  END;

PROCEDURE TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
  BEGIN
    AssignFile(AppSettingsFile,ExtractFilepath(Application.EXEname)+'\oniunpacker.ini');
    IF FileExists(ExtractFilepath(Application.EXEname)+'\oniunpacker.ini') THEN
      Reset(AppSettingsFile)
    ELSE
      Rewrite(AppSettingsFile);
    Write(AppSettingsFile,AppSettings);
    CloseFile(AppSettingsFile);
  END;

PROCEDURE TForm1.Splitter1Moved(Sender: TObject);
  BEGIN
    Form1.list_files.Height:=Form1.Splitter1.Top-32;
    Form1.btn_extractallconvert.Top:=Form1.Splitter1.Top-33;
    Form1.btn_extract.Top:=Form1.Splitter1.Top-33;
    Form1.btn_extractconvert.Top:=Form1.Splitter1.Top-33;
    Form1.btn_extractall.Top:=Form1.Splitter1.Top-33;
  END;

PROCEDURE TForm1.Splitter2Moved(Sender: TObject);
  BEGIN
    Form1.btn_extractall.Left:=Form1.Splitter2.Left-146;
    Form1.btn_extractallconvert.Left:=Form1.Splitter2.Left-83;
  END;

PROCEDURE TForm1.btn_extractallconvertClick(Sender: TObject);
  VAR
    convert:Boolean;
    i:LongWord;
    errors:LongWord;
    oldwidth,oldheight:Integer;
    oldstate:TWindowState;
  BEGIN
    panel_all.Visible:=False;
    panel_info.Visible:=False;
    group_progress.Visible:=True;
    FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=False;
    oldwidth:=Form1.Width;
    oldheight:=Form1.Height;
    oldstate:=Form1.WindowState;
    Form1.WindowState:=wsNormal;
    Form1.Width:=400;
    Form1.Height:=103;
    group_progress.Left:=0;
    group_progress.Top:=0;
    group_progress.Width:=Form1.Width-8;
    progress.Width:=group_progress.Width-80;
    progress.Max:=dat_header.files;
    btn_extractcancel.Left:=group_progress.Width-65;
    btn_extractcancel.Caption:='Cancel';
    btn_extractcancel.SetFocus;

    IF TComponent(Sender).Name='btn_extractall' THEN
      convert:=False
    ELSE
      convert:=True;
    errors:=0;
    FOR i:=0 TO High(dat_files) DO BEGIN
      IF ExportFile(i,convert)>0 THEN Inc(errors);
      IF (i MOD 25)=0 THEN BEGIN
        lbl_progress.Caption:=IntToStr(i)+'/'+IntToStr(dat_header.Files);
        progress.Position:=i;
        Application.ProcessMessages;
        IF btn_extractcancel.Caption='Cancel_' THEN BEGIN
          btn_extractcancel.Caption:='Cancel';
          Break;
        END;
      END;
    END;
    IF errors>0 THEN
      ShowMessage(IntToStr(errors)+' errors encountered.');

    Form1.Width:=oldwidth;
    Form1.Height:=oldheight;
    Form1.WindowState:=oldstate;
    FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=True;
    panel_all.Visible:=True;
    panel_info.Visible:=True;
    group_progress.Visible:=False;
  END;

PROCEDURE TForm1.menu_previewClick(Sender: TObject);
  BEGIN
    menu_preview.Checked:=NOT menu_preview.Checked;
    IF menu_preview.Checked THEN BEGIN
      Form5.Visible:=True;
    END ELSE BEGIN
      Form5.Visible:=False;
    END;
  END;

PROCEDURE TForm1.btn_extractcancelClick(Sender: TObject);
  BEGIN
    btn_extractcancel.Caption:='Cancel_';
  END;

END.
