UNIT Unit9_data_structures;
INTERFACE
USES SysUtils, ABSMain, DB, ABSDecUtil, Unit3_data;

TYPE
  Tstructure_entry=RECORD
      name:String;
      offset:LongWord;
      datatype:Word;  // 1..4: Integer[1..4] dec; 5..8: Integer[1..4] hex; 9: float; 10: bitset; 11: raw-addr; 10000+: string[0+]
      description:String;
    END;
  Tstructure_info=RECORD
      extension:String;
      typedesc:String;
      entries:Array OF Tstructure_entry;
    END;
  Tstructures=Array OF Tstructure_info;
  THandler=FUNCTION(fileid:LongWord):TRawList;
  TRawListHandlers=RECORD
    Ext:String[4];
    needed:Boolean;
    Handler:THandler;
  END;

VAR
  structure_infos:Tstructures;
  RawListHandlers:Array OF TRawListHandlers;


FUNCTION GetDataType(typeid:Word):String;
FUNCTION GetStructureInfoId(ext:String):Integer;
FUNCTION GetTypeDataLength(datatype:Word):Word;
FUNCTION GetRawInfo(fileid,dat_offset:LongWord):TRawInfo;
FUNCTION GetRawList(fileid:LongWord):TRawList;



IMPLEMENTATION
USES Unit2_functions;

FUNCTION GetTypeDataLength(datatype:Word):Word;
  BEGIN
    CASE datatype OF
      1..4: Result:=datatype;
      5..8: Result:=datatype-4;
      9: Result:=4;
      10: Result:=1;
      11: Result:=4;
      10000..65535: Result:=datatype-10000;
    END;
  END;


FUNCTION GetStructureInfoId(ext:String):Integer;
  VAR
    i:Integer;
  BEGIN
    FOR i:=0 TO High(structure_infos) DO BEGIN
      IF structure_infos[i].extension=ext THEN BEGIN
        Result:=i;
        Exit;
      END;
    END;
    Result:=-1;
  END;


FUNCTION GetDataType(typeid:Word):String;
  BEGIN
    CASE typeid OF
      1..4: Result:='Int'+IntToStr(typeid*8);
      5..8: Result:='Int'+IntToStr((typeid-4)*8);
      9: Result:='Float';
      10: Result:='BitSet';
      11: Result:='Raw-Address';
      10000..65535: Result:='String('+IntToStr(typeid-10000)+')';
    END;
  END;


FUNCTION GetRawInfo(fileid,dat_offset:LongWord):TRawInfo;
  VAR
    i:LongWord;
    raw_list:TRawList;
  BEGIN
    raw_list:=GetRawList(fileid);
    Result.src_id:=0;
    Result.src_offset:=0;
    Result.raw_addr:=0;
    Result.raw_size:=0;
    FOR i:=0 TO High(raw_list) DO BEGIN
      IF raw_list[i].src_offset=dat_offset THEN BEGIN
        Result.src_id:=fileid;
        Result.src_offset:=raw_list[i].src_offset;
        Result.raw_addr:=raw_list[i].raw_addr;
        Result.raw_size:=raw_list[i].raw_size;
        Result.loc_sep:=raw_list[i].loc_sep;
        Break;
      END;
    END;
  END;

FUNCTION GetRawList(fileid:LongWord):TRawList;
  VAR
    i:LongWord;
    Query:TABSQuery;
  BEGIN
    IF opened_state=opened_dat THEN BEGIN
      FOR i:=0 TO High(RawListHandlers) DO
        IF UpperCase(RawListHandlers[i].Ext)=UpperCase(dat_files[fileid].extension) THEN
          IF RawListHandlers[i].needed THEN BEGIN
            Result:=RawListHandlers[i].Handler(fileid);
            Break;
          END ELSE
            Break;
    END ELSE BEGIN
      SetLength(Result,0);
      Query.SQL.Text:='SELECT [src_link_offset],[size] FROM rawmap WHERE [src_id]='+IntToStr(fileid)+' ORDER BY src_link_offset ASC;';
      Query.Open;
      IF Query.RecordCount>0 THEN BEGIN
        Query.First;
        SetLength(Result,Query.RecordCount);
        i:=0;
        REPEAT
          Result[i].src_id:=fileid;
          Result[i].src_offset:=Query.FieldByName('src_link_offset').AsInteger;
          Result[i].raw_addr:=0;
          Result[i].raw_size:=Query.FieldByName('size').AsInteger;
          Inc(i);
          Query.Next;
        UNTIL Query.EOF;
      END;
      Query.Close;
    END;
  END;


FUNCTION AGDB(fileid:LongWord):TRawList;
  VAR
    link:LongWord;
    links:LongWord;
    i:LongWord;
  BEGIN
    IF NOT dat_os_mac THEN BEGIN
      LoadDatFilePart(fileid,$1C,4,@links);
      links:=links*2;
      SetLength(Result,links);
      FOR i:=0 TO links-1 DO BEGIN
        Result[i].src_offset:=$20+i*4;
        LoadDatFilePart(fileid,$20+i*4,4,@link);
        Result[i].raw_addr:=link;
        Result[i].raw_size:=0{????????????????????????????????};
        Result[i].loc_sep:=False;
      END;
    END;
  END;
FUNCTION BINA(fileid:LongWord):TRawList;
  VAR
    link:LongWord;
    datasize:LongWord;
  BEGIN
    LoadDatFilePart(fileid,$0C,4,@link);
    LoadDatFilePart(fileid,$08,4,@datasize);
    SetLength(Result,1);
    Result[0].src_offset:=$0C;
    Result[0].raw_addr:=link;
    Result[0].raw_size:=datasize;
    Result[0].loc_sep:=dat_os_mac;
  END;
FUNCTION OSBD(fileid:LongWord):TRawList;
  VAR
    link:LongWord;
    datasize:LongWord;
  BEGIN
    LoadDatFilePart(fileid,$08,4,@datasize);
    LoadDatFilePart(fileid,$0C,4,@link);
    SetLength(Result,1);
    Result[0].src_offset:=$0C;
    Result[0].raw_addr:=link;
    Result[0].raw_size:=datasize;
    Result[0].loc_sep:=dat_os_mac;
  END;
FUNCTION SNDD(fileid:LongWord):TRawList;
  VAR
    link:LongWord;
    datasize:LongWord;
  BEGIN
    LoadDatFilePart(fileid,$40,4,@datasize);
    LoadDatFilePart(fileid,$44,4,@link);
    SetLength(Result,1);
    Result[0].src_offset:=$44;
    Result[0].raw_addr:=link;
    Result[0].raw_size:=datasize;
  END;
FUNCTION SUBT(fileid:LongWord):TRawList;
  VAR
    baselink,link:LongWord;
    links:LongWord;
    i,j,k:LongWord;
    data:Tdata;
  BEGIN
    LoadDatFilePart(fileid,$18,4,@baselink);
    LoadDatFilePart(fileid,$1C,4,@links);
    IF links>0 THEN BEGIN
      LoadDatFilePart(fileid,$20+(links-1)*4,4,@link);
      SetLength(data,link+1024);
      LoadRawFile(fileid,$1C,baselink,link+1024,False,@data[0]);
      k:=0;
      FOR j:=0 TO 1024 DO BEGIN
        IF (data[link+j]=$00) OR (j=1024) THEN BEGIN
          IF j<1024 THEN BEGIN
            IF k=0 THEN BEGIN
              k:=1;
            END ELSE BEGIN
              SetLength(Result,1);
              Result[0].src_offset:=$18;
              Result[0].raw_addr:=baselink;
              Result[0].raw_size:=link+j;
              Break;
            END;
          END;
        END;
      END;
    END;
  END;
FUNCTION TRAM(fileid:LongWord):TRawList;
  VAR
    i:Byte;
    link:LongWord;
    frames:Word;
    tempb:Byte;
    tempw:Word;
    templ:LongWord;
    data:Tdata;
    offset:Word;
  BEGIN
    SetLength(Result,13);
    LoadDatFilePart(fileid,$16C,2,@frames);
    {y-pos}
    LoadDatFilePart(fileid,$0C,4,@link);
    Result[0].src_offset:=$0C;
    Result[0].raw_addr:=link;
    Result[0].raw_size:=frames*4;
    {x-z-pos}
    LoadDatFilePart(fileid,$10,4,@link);
    Result[1].src_offset:=$10;
    Result[1].raw_addr:=link;
    Result[1].raw_size:=frames*8;
    {attacks}
    LoadDatFilePart(fileid,$182,1,@tempb);
    LoadDatFilePart(fileid,$14,4,@link);
    Result[2].src_offset:=$14;
    Result[2].raw_addr:=link;
    Result[2].raw_size:=tempb*32;
    {damage}
    LoadDatFilePart(fileid,$183,1,@tempb);
    LoadDatFilePart(fileid,$18,4,@link);
    Result[3].src_offset:=$18;
    Result[3].raw_addr:=link;
    Result[3].raw_size:=tempb*8;
    {motionblur}
    LoadDatFilePart(fileid,$184,1,@tempb);
    LoadDatFilePart(fileid,$1C,4,@link);
    Result[4].src_offset:=$1C;
    Result[4].raw_addr:=link;
    Result[4].raw_size:=tempb*8;
    {shortcut}
    LoadDatFilePart(fileid,$185,1,@tempb);
    LoadDatFilePart(fileid,$20,4,@link);
    Result[5].src_offset:=$20;
    Result[5].raw_addr:=link;
    Result[5].raw_size:=tempb*8;
    {throw}
    LoadDatFilePart(fileid,$24,4,@link);
    Result[6].src_offset:=$24;
    Result[6].raw_addr:=link;
    IF link>0 THEN
      Result[6].raw_size:=24
    ELSE
      Result[6].raw_size:=0;
    {footstep}
    LoadDatFilePart(fileid,$186,1,@tempb);
    LoadDatFilePart(fileid,$28,4,@link);
    Result[7].src_offset:=$28;
    Result[7].raw_addr:=link;
    Result[7].raw_size:=tempb*4;
    {particle}
    LoadDatFilePart(fileid,$187,1,@tempb);
    LoadDatFilePart(fileid,$2C,4,@link);
    Result[8].src_offset:=$2C;
    Result[8].raw_addr:=link;
    Result[8].raw_size:=tempb*24;
    {position}
    LoadDatFilePart(fileid,$30,4,@link);
    Result[9].src_offset:=$30;
    Result[9].raw_addr:=link;
    Result[9].raw_size:=frames*8;
    {particle}
    LoadDatFilePart(fileid,$154,2,@tempw);
    LoadDatFilePart(fileid,$38,4,@link);
    Result[11].src_offset:=$38;
    Result[11].raw_addr:=link;
    Result[11].raw_size:=tempw*34;
    {extent}
    LoadDatFilePart(fileid,$138,1,@templ);
    LoadDatFilePart(fileid,$13C,4,@link);
    Result[12].src_offset:=$13C;
    Result[12].raw_addr:=link;
    Result[12].raw_size:=templ*12;

    LoadDatFilePart(fileid,$34,4,@link);
    tempw:=0;
    IF link>0 THEN BEGIN
      {BODY ANIMATIONS PART DECODE!!!}
      SetLength(data,$FFFF);
      LoadRawFile(fileid,$34,link,$FFFF,False,@data[0]);
      offset:=data[24]+data[25]*255;
      {}
    END;
    Result[10].src_offset:=$34;
    Result[10].raw_addr:=link;
    Result[10].raw_size:=tempw;
  END;
FUNCTION TXMP(fileid:LongWord):TRawList;
  VAR
    link_pc:LongWord;
    link_mac:LongWord;
    x,y:Word;
    storetype:Byte;
    datasize:LongWord;
  BEGIN
    LoadDatFilePart(fileid,$8C,SizeOf(x),@x);
    LoadDatFilePart(fileid,$8E,SizeOf(y),@y);
    LoadDatFilePart(fileid,$90,SizeOf(storetype),@storetype);
    LoadDatFilePart(fileid,$9C,4,@link_pc);
    LoadDatFilePart(fileid,$A0,4,@link_mac);
    CASE storetype OF
      0,1,2: datasize:=x*y*2;
      8: datasize:=x*y*4;
      9: datasize:=x*y DIV 2;
    END;
    SetLength(Result,1);
    IF NOT dat_os_mac THEN BEGIN
      Result[0].src_offset:=$9C;
      Result[0].raw_addr:=link_pc
    END ELSE BEGIN
      Result[0].src_offset:=$A0;
      Result[0].raw_addr:=link_mac;
    END;
    Result[0].raw_size:=datasize;
    Result[0].loc_sep:=dat_os_mac;
  END;



PROCEDURE AddEntry(_ext:String; _name:String; _offset:LongWord; _datatype:Word; _description:String);
  VAR
    sid:Integer;
  BEGIN
    sid:=GetStructureInfoId(_ext);
    IF sid>=0 THEN BEGIN
      WITH structure_infos[sid] DO BEGIN
        SetLength(entries,Length(entries)+1);
        WITH entries[High(entries)] DO BEGIN
          name:=_name;
          offset:=_offset;
          datatype:=_datatype;
          description:=_description;
        END;
      END;
    END;
  END;

PROCEDURE AddExtension(_ext:String; _typedesc:String);
  BEGIN
    IF GetStructureInfoId(_ext)<0 THEN BEGIN
      SetLength(structure_infos,Length(structure_infos)+1);
      WITH structure_infos[High(structure_infos)] DO BEGIN
        extension:=_ext;
        typedesc:=_typedesc;
      END;
    END;
  END;

PROCEDURE InsertRawListHandler(ext:String; needed:Boolean; handler:THandler);
  BEGIN
    SetLength(RawListHandlers,Length(RawListHandlers)+1);
    RawListHandlers[High(RawListHandlers)].Ext:=ext;
    RawListHandlers[High(RawListHandlers)].needed:=needed;
    RawListHandlers[High(RawListHandlers)].handler:=handler;
  END;


BEGIN
  AddExtension('SUBT','Subtitles');
  AddEntry('SUBT','ID',$00,4,'ID of this file');
  AddEntry('SUBT','LevelID',$04,8,'ID of the level this file is in');
  AddEntry('SUBT','Raw-Link',$18,11,'Address of the subtitle data in the .raw-file');
  AddEntry('SUBT','Subtitle count',$1C,4,'Number of subtitles in this file');
  AddExtension('TXMP','Texture');
  AddEntry('TXMP','ID',$00,4,'ID of this file');
  AddEntry('TXMP','LevelID',$04,8,'ID of the level this file is in');
  AddEntry('TXMP','FileName',$08,10128,'');
  AddEntry('TXMP','MIP Mapping',$88,10,'MIP Mapping Bitset');
  AddEntry('TXMP','Depth',$89,10,'Depth-Bitset');
  AddEntry('TXMP','Width',$8C,2,'x-resolution of image');
  AddEntry('TXMP','Height',$8E,2,'y-resolution of image');
  AddEntry('TXMP','Storetype',$90,10,'Storetype-Bitset');
  AddEntry('TXMP','TXAN-Link',$94,8,'Link to the TXAN-file (if this TXMP is the first image of an animation)');
  AddEntry('TXMP','TXMP-Link',$98,8,'Link to another TXMP-file');
  AddEntry('TXMP','Raw-Link',$9C,11,'Address of the image data in the .raw-file (only for PC-dat-files)');
  AddEntry('TXMP','Raw-Link',$A0,11,'Address of the image data in the .raw-file (only for MAC-dat-files)');

{$I Include_DataStructureDefs.pas}

//  InsertRawListHandler('AGDB',True,AGDB);
  InsertRawListHandler('BINA',True,BINA);
  InsertRawListHandler('OSBD',True,OSBD);
  InsertRawListHandler('SNDD',True,SNDD);
  InsertRawListHandler('SUBT',True,SUBT);
  InsertRawListHandler('TRAM',True,TRAM);
  InsertRawListHandler('TXMP',True,TXMP);
END.