UNIT Unit2_functions; INTERFACE USES Classes, Dialogs, SysUtils, StrUtils, Math, SQLiteTable3, Unit3_data, Unit4_Exporters; FUNCTION GetFilesList(ext:String; pattern:String):TStringList; FUNCTION Decode_Int(buffer:Tdata):LongWord; FUNCTION Encode_Int(input:LongWord):Tdata; FUNCTION Decode_Float(buffer:Tdata):Single; FUNCTION Encode_Float(input:Single):Tdata; FUNCTION LoadDatInfos(filename:String):Boolean; FUNCTION LoadDatFile(fileid:LongWord):Tdata; PROCEDURE SaveDatFile(fileid:LongWord; data:Tdata); FUNCTION LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean; FUNCTION LoadRawFilePart(address,size:LongWord; target:Pointer):Boolean; FUNCTION FormatNumber(value:LongWord; width:Byte; leadingzeros:Char):String; FUNCTION FormatFileSize(size:LongWord):String; FUNCTION CreateHexString(data:Tdata; HexOnly:Boolean):String; FUNCTION ExportFile(fileid:LongWord; convert:Boolean):Integer; FUNCTION GetWinFileName(fileid:LongWord; substring:String):String; FUNCTION GetExtractPath:String; PROCEDURE OpenDatabase(FileName:String); IMPLEMENTATION TYPE TValueSwitcher=Record CASE IsFloat: Boolean OF True: (ValueFloat:Single); False: (ValueInt:LongWord); END; FUNCTION Decode_Int(buffer:Tdata):LongWord; BEGIN Result:=buffer[0]+buffer[1]*256+buffer[2]*256*256+buffer[3]*256*256*256; END; FUNCTION Encode_Int(input:LongWord):Tdata; BEGIN Result[0]:=input MOD 256; input:=input DIV 256; Result[1]:=input MOD 256; input:=input DIV 256; Result[2]:=input MOD 256; input:=input DIV 256; Result[3]:=input MOD 256; END; FUNCTION Decode_Float(buffer:Tdata):Single; VAR _valueswitcher:TValueSwitcher; BEGIN _valueswitcher.ValueInt:=Decode_Int(buffer); Result:=_valueswitcher.ValueFloat; END; FUNCTION Encode_Float(input:Single):Tdata; VAR _valueswitcher:TValueSwitcher; BEGIN _valueswitcher.ValueFloat:=input; Result:=Encode_Int(_valueswitcher.ValueInt); END; FUNCTION GetFilesList(ext:String; pattern:String):TStringList; VAR i:LongWord; BEGIN SetLength(Result,0); IF opened_state=opened_dat THEN BEGIN FOR i:=0 TO dat_header.Files-1 DO BEGIN IF (Length(ext)=0 OR dat_files[i].Extension=ext) AND (Length(pattern)=0 OR Pos(pattern,dat_files[i].FileName)>0) THEN BEGIN SetLength(Result,Length(Result)+1); Result[High(Result)]:=dat_files[i].FileName; END; END; END ELSE BEGIN END; END; FUNCTION LoadDatInfos(filename:String):Boolean; VAR i:LongWord; dat_file:TFileStream; BEGIN Result:=True; opened_state:=opened_dat; dat_filename:=filename; raw_filename:=MidStr(filename,1,Length(filename)-3)+'raw'; dat_file:=TFileStream.Create(filename, fmOpenRead); dat_file.Read(dat_header,SizeOf(dat_header)); FOR i:=0 TO High(dat_header.Ident) DO IF dat_header.Ident[i]<>header_ident1[i] THEN BEGIN Result:=False; Exit; END; { FOR i:=0 TO High(dat_header.Ident2) DO IF dat_header.Ident2[i]<>header_ident2[i] THEN BEGIN Result:=False; Exit; END; } SetLength(dat_filesmap,dat_header.Files); SetLength(dat_files,dat_header.Files); FOR i:=0 TO dat_header.Files-1 DO dat_file.Read(dat_filesmap[i],SizeOf(dat_filesmap[i])); FOR i:=0 TO dat_header.Files-1 DO BEGIN dat_files[i].Extension:=dat_filesmap[i].Extension; dat_files[i].Extension:=ReverseString(dat_files[i].Extension); dat_files[i].Size:=dat_filesmap[i].FileSize; dat_files[i].FileType:=dat_filesmap[i].FileType; dat_files[i].DatAddr:=dat_filesmap[i].DataAddr-8+dat_header.DataAddr; IF (dat_filesmap[i].FileType AND $01)=0 THEN BEGIN dat_file.Seek(dat_filesmap[i].NameAddr+dat_header.NamesAddr,soFromBeginning); SetLength(dat_files[i].Name,100); dat_file.Read(dat_files[i].Name[1],100); dat_files[i].Name:=MidStr(dat_files[i].Name,1+4,Pos(#0,dat_files[i].Name)-1-4); END ELSE BEGIN dat_files[i].Name:=''; END; dat_files[i].FileName:=FormatNumber(i,5,'0')+'-'+dat_files[i].Name+'.'+dat_files[i].Extension; END; dat_file.Seek($40+dat_header.Files*$14,soFromBeginning); SetLength(dat_namedfilesmap,dat_header.NamedFiles); FOR i:=0 TO dat_header.NamedFiles-1 DO dat_file.Read(dat_namedfilesmap[i],SizeOf(dat_namedfilesmap[i])); dat_file.Seek($40+dat_header.Files*$14+dat_header.NamedFiles*$8,soFromBeginning); SetLength(dat_extensionsmap,dat_header.Extensions); FOR i:=0 TO dat_header.Extensions-1 DO dat_file.Read(dat_extensionsmap[i],SizeOf(dat_extensionsmap[i])); dat_file.Free; END; FUNCTION LoadDatFile(fileid:LongWord):Tdata; VAR dat_file:TFileStream; BEGIN IF opened_state=opened_dat THEN BEGIN dat_file:=TFileStream.Create(dat_filename, fmOpenRead); dat_file.Seek(dat_files[fileid].DatAddr,soFromBeginning); SetLength(Result,dat_files[fileid].Size); dat_file.Read(Result[0],dat_files[fileid].Size); dat_file.Free; END; END; PROCEDURE SaveDatFile(fileid:LongWord; data:Tdata); VAR dat_file:TFileStream; BEGIN IF opened_state=opened_dat THEN BEGIN dat_file:=TFileStream.Create(dat_filename, fmOpenReadWrite); dat_file.Seek(dat_files[fileid].DatAddr,soFromBeginning); dat_file.Write(data[0],Length(data)); dat_file.Free; END; END; FUNCTION LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean; VAR dat_file:TFileStream; BEGIN IF opened_state=opened_dat THEN BEGIN dat_file:=TFileStream.Create(dat_filename, fmOpenRead); Result:=True; dat_file.Seek(dat_files[fileid].DatAddr+offset,soFromBeginning); dat_file.Read(target^,size); dat_file.Free; END; END; FUNCTION LoadRawFilePart(address,size:LongWord; target:Pointer):Boolean; VAR filestream:TFileStream; BEGIN IF opened_state=opened_dat THEN BEGIN Result:=True; filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenRead); filestream.Seek(address,soFromBeginning); filestream.Read(target^,size); filestream.Free; END; END; FUNCTION FormatNumber(value:LongWord; width:Byte; leadingzeros:Char):String; BEGIN Result:=AnsiReplaceStr(Format('%'+IntToStr(width)+'u',[value]),' ',leadingzeros); END; FUNCTION FormatFileSize(size:LongWord):String; BEGIN IF size>=1000*1024*1024 THEN BEGIN Result:=FloatToStrF(size/1024/1024/1024,ffFixed,5,1)+' GB'; END ELSE BEGIN IF size>=1000*1024 THEN BEGIN Result:=FloatToStrF(size/1024/1024,ffFixed,5,1)+' MB'; END ELSE BEGIN IF size>=1000 THEN BEGIN Result:=FloatToStrF(size/1024,ffFixed,5,1)+' KB'; END ELSE BEGIN Result:=IntToStr(size)+' B'; END; END; END; END; FUNCTION CreateHexString(data:Tdata; HexOnly:Boolean):String; VAR string_build,ascii_version:String; i:LongWord; BEGIN string_build:=''; ascii_version:=''; FOR i:=0 TO High(data) DO BEGIN IF NOT HexOnly THEN IF (i MOD 16)=0 THEN string_build:=string_build+'0x'+IntToHex(i,6)+' '; string_build:=string_build+IntToHex(data[i],2); IF NOT HexOnly THEN BEGIN IF data[i]>=32 THEN ascii_version:=ascii_version+Chr(data[i]) ELSE ascii_version:=ascii_version+'.'; IF ((i+1) MOD 2)=0 THEN string_build:=string_build+#32; IF ((i+1) MOD 16)=0 THEN BEGIN string_build:=string_build+#32+ascii_version+CrLf; ascii_version:=''; END; END; END; Result:=string_build; END; FUNCTION ExportFile(fileid:LongWord; convert:Boolean):Integer; VAR i:Byte; BEGIN IF opened_state=opened_dat THEN BEGIN Result:=export_noerror; //ExportDefFileHeader(fileid); IF (dat_files[fileid].FileType AND $02)=0 THEN BEGIN //ExportDatFile(fileid); FOR i:=1 TO Length(ExportHandlers)+1 DO BEGIN IF i<=Length(ExportHandlers) THEN BEGIN IF ExportHandlers[i].Ext=dat_files[fileid].Extension THEN BEGIN IF ExportHandlers[i].needed THEN BEGIN CASE ExportHandlers[i].Handler(fileid,convert) OF 0: Result:=0; ELSE Result:=export_handlererror; END; END; Break; END; END ELSE BEGIN Result:=export_nohandler; END; END; END; END; END; FUNCTION GetWinFileName(fileid:LongWord; substring:String):String; VAR name:String; BEGIN name:=dat_files[fileid].Name; name:=AnsiReplaceStr(name,'\','__'); name:=AnsiReplaceStr(name,'/','__'); name:=AnsiReplaceStr(name,'>','__'); name:=AnsiReplaceStr(name,'<','__'); Result:=FormatNumber(fileid,5,'0')+'-'+name+'.'+substring+'.'+dat_files[fileid].Extension; END; FUNCTION GetExtractPath:String; BEGIN Result:=ExtractFilePath(dat_filename)+'\extracted_'+ExtractFileName(dat_filename); END; PROCEDURE OpenDatabase(FileName:String); VAR i:Byte; data:Tdata; temps:String; Tbl: TSQLiteTable; BEGIN IF NOT FileExists(FileName) THEN BEGIN ShowMessage('File doesn''t exist!!!'); Exit; END; DB:=TSQLiteDatabase.Create(FileName); Tbl:=DB.GetTable('SELECT name,value FROM globals ORDER BY name ASC'); REPEAT IF Tbl.FieldAsString('name')='dbversion' THEN BEGIN IF Tbl.FieldAsString('value')<>DBversion THEN BEGIN ShowMessage('Database-file '+CrLf+'"'+FileName+'"'+CrLf+'has wrong version. (Required: '+DBversion+'; found: '+Tbl.FieldAsString('value')+')'); Exit; END; END; IF Tbl.FieldAsString('name')='lvl' THEN BEGIN database_level:=StrToInt(Tbl.FieldAsString('value')); END; IF Tbl.FieldAsString('name')='ident' THEN BEGIN temps:=Tbl.FieldAsString('value'); FOR i:=0 TO High(database_ident) DO BEGIN CASE temps[(i*2)+1+0] OF '0'..'9': database_ident[i]:=Ord(temps[(i*2)+1+0])-48; 'A'..'F': database_ident[i]:=Ord(temps[(i*2)+1+0])-55; END; database_ident[i]:=database_ident[i]*16; CASE temps[(i*2)+1+1] OF '0'..'9': database_ident[i]:=database_ident[i]+Ord(temps[(i*2)+1+0])-48; 'A'..'F': database_ident[i]:=database_ident[i]+Ord(temps[(i*2)+1+0])-55; END; END; END; Tbl.Next; UNTIL Tbl.EOF; Tbl.Free; opened_state:=opened_db; END; END.