{ The execute part of the script engine } unit ifps3; {$I ifps3_def.inc} { Innerfuse Pascal Script III Copyright (C) 2000-2002 by Carlo Kok (ck@carlo-kok.com) } interface uses SysUtils, ifps3utl, ifps3common; type TIFPSExec = class; { TIFError contains all possible errors } TIFError = (ErNoError, erCannotImport, erInvalidType, ErInternalError, erInvalidHeader, erInvalidOpcode, erInvalidOpcodeParameter, erNoMainProc, erOutOfGlobalVarsRange, erOutOfProcRange, ErOutOfRange, erOutOfStackRange, ErTypeMismatch, erUnexpectedEof, erVersionError, ErDivideByZero, ErMathError, erCouldNotCallProc, erOutofRecordRange, erOutOfMemory, erException, erNullPointerException, erNullVariantError, erCustomError); { The current status of the script } TIFStatus = (isNotLoaded, isLoaded, isRunning, isPaused); {Pointer to array of bytes} PByteArray = ^TByteArray; {Array of bytes} TByteArray = array[0..1023] of Byte; {Pointer to array of words} PDWordArray = ^TDWordArray; {Array of dwords} TDWordArray = array[0..1023] of Cardinal; { Pointer to @link(TIFTypeRec)} PIFTypeRec = ^TIFTypeRec; {TIFTypeRec is used to store all types inside the script} TIFTypeRec = record {Ext is used in a typecopy or array to store more information} Ext: Pointer; BaseType: TIFPSBaseType; ExportName: string; ExportNameHash: Longint; end; {TIFArrayType is a pointer to an other type} TIFArrayType = PIFTypeRec; {PIFRecordType is a pointer to record information} PIFRecordType = ^TIFRecordType; {TIFRecordType is used to store information about records} TIFRecordType = record Data: string; end; {@link(TProcRec) PProcRec is pointer to a TProcRec record} PProcRec = ^TProcRec; {@link(TIFProcRec) PIFProcRec is a pointer to a TIProcRec record} PIFProcRec = ^TIFProcRec; { @link(TIFPSExec) @link(PIFProcRec) @link(TIfList) TIFProc is is the procedure definition of all external functions } TIFProc = function(Caller: TIFPSExec; p: PIFProcRec; Global, Stack: TIfList): Boolean; { @link(PProcRec) FreeProc is called when a PProcRec is freed} TIFFreeProc = procedure (Caller: TIFPSExec; p: PProcRec); {TIFProcRec contains a currently used internal or external function} TIFProcRec = record {True means the procedure is external} ExternalProc: Boolean; {The exportname/decl used to identify the procedure} ExportName, ExportDecl: string; {ExportNameHash is used to quickly find an ExportName} ExportNameHash: Longint; case Boolean of False: (Data: PByteArray; Length: Cardinal); True: (ProcPtr: TIFProc; Name: ShortString; Ext1, Ext2: Pointer); // ExportDecl will contain Params in case of importing with Flags := 3; end; {TProcrec is used to store an external function that could be used by the script executer} TProcRec = record Name: ShortString; Hash: Longint; ProcPtr: TIFProc; FreeProc: TIFFreeProc; Ext1, Ext2: Pointer; end; {@link(TBTReturnAddress) PBTReturnAddress is a pointer to an TBTReturnAddress record} PBTReturnAddress = ^TBTReturnAddress; {TBTReturnAddress is a record used to store return information} TBTReturnAddress = record ProcNo: PIFProcRec; Position, StackBase: Cardinal; end; {@link(PIFVariant) PPIFVariant is a pointer to a PIFVariant} PPIFVariant = ^PIfVariant; {@link(TIFVariant) PIFVariant is a pointer to a TIFVariant} PIFVariant = ^TIfVariant; {@link(TVariantResourceFreeProc) TVRMode is used to when the scriptengine needs to free or duplicate a resourcepointer} TVRFMode = (vrfFree, vrfDuplicate); {@link(TVRMode) TVariantResourceFreeProc is used when the scriptengine needs to free or duplicate a resourcepointer} TVariantResourceFreeProc = function (FMode: TVRFMode; P, IntoP: PIFVariant): Boolean; {PBTRecord is a pointer to a @link(TbtRecord) record} pbtrecord = ^TbtRecord; {TIFvariant is variant used for storing all variables used by the script engine} TIFVariant = packed record {The type of the variant} FType: PIFTypeRec; {The number of pointers referencing this variant} RefCount: Cardinal; // 0 = Freeable case Byte of 1: (tu8: TbtU8); 2: (tS8: TbtS8); 3: (tu16: TbtU16); 4: (ts16: TbtS16); 5: (tu32: TbtU32); 6: (ts32: TbtS32); 7: (tsingle: TbtSingle); 8: (tdouble: TbtDouble); 9: (textended: TbtExtended); 10: (tstring: Pointer); 11: (treturnaddress: TBTReturnAddress); 12: (trecord: pbtrecord); 13: (tArray: pbtrecord); 14: (tPointer: PIfVariant); 15: (tResourceP1, tResourceP2: Pointer; tResourceFreeProc: TVariantResourceFreeProc); 16: (tvariant: PIFVariant); {$IFNDEF NOINT64} 17: (ts64: Tbts64); {$ENDIF} 19: (tchar: tbtChar); {$IFNDEF NOWIDESTRING} 18: (twidestring: Pointer); 20: (twidechar: tbtwidechar); {$ENDIF} end; {TbtRecord is used to store the fields in a record or array} TbtRecord = packed record FieldCount: Cardinal; Fields: array[0..10000] of PIfVariant; end; {TIFPSResourceFreeProc is called when a resource needs to be freed} TIFPSResourceFreeProc = procedure (Sender: TIFPSExec; P: Pointer); {@link(TIFPSResource) PIFPSResource is a pointer to a TIFPSResource record } PIFPSResource = ^TIFPSResource; { A resource in IFPS3 is stored as a pointer to the proc and a tag (p) } TIFPSResource = record Proc: Pointer; P: Pointer; end; {@link(pbtrecord) PBTRecord} PBTArray = pbtrecord; {@link(TbtRecord) tbtrecord} TBTArray = TbtRecord; {See TIFPSExec.OnRunLine} TIFPSOnLineEvent = procedure(Sender: TIFPSExec); {See TIFPSExec.AddSpecialProcImport} TIFPSOnSpecialProcImport = function (Sender: TIFPSExec; p: PIFProcRec; Tag: Pointer): Boolean; {TIFPSExec is the core of the script engine executer} TIFPSExec = class(TObject) Private FId: Pointer; FJumpFlag: Boolean; FCallCleanup: Boolean; function ReadData(var Data; Len: Cardinal): Boolean; function ReadByte(var b: Cardinal): Boolean; function ReadLong(var b: Cardinal): Boolean; function DoCalc(var1, Var2: PIfVariant; CalcType: Cardinal): Boolean; function DoBooleanCalc(var1, Var2: PIfVariant; Into: PIfVariant; Cmd: Cardinal): Boolean; function SetVariantValue(dest, Src: PIfVariant): Boolean; function ReadVariable(var NeedToFree: LongBool; UsePointer: LongBool): PIfVariant; procedure DoBooleanNot(Vd: PIfVariant); procedure DoMinus(Vd: PIfVariant); procedure DoIntegerNot(Vd: PIfVariant); function BuildArray(Dest, Src: PIFVariant): boolean; Protected {MM is the memory manager used internally. It's needed to create and destroy variants} {$IFNDEF NOSMARTMM}MM: Pointer; {$ENDIF} {The exception stack} FExceptionStack: TIFList; {The list of resources} FResources: TIFList; {The list of exported variables} FExportedVars: TIfList; {FTypes contains all types used by the script} FTypes: TIfList; {FProcs contains all script procedures} FProcs: TIfList; {FGlobalVars contains the global variables of the current script} FGlobalVars: TIfList; {The current stack} FStack: TIfList; {The main proc no or -1 (no main proc)} FMainProc: Cardinal; {The current status of the script engine} FStatus: TIFStatus; {The current proc} FCurrProc: PIFProcRec; {The current position in the current proc} FCurrentPosition: Cardinal; {Current stack base} FCurrStackBase: Cardinal; {FOnRunLine event} FOnRunLine: TIFPSOnLineEvent; {List of SpecialProcs; See TIFPSExec.AddSpecialProc} FSpecialProcList: TIfList; {List of all registered external functions} FRegProcs: TIfList; {The proc where the last error occured} ExProc: Cardinal; {The position of the last error} ExPos: Cardinal; {The error code} ExEx: TIFError; {The optional parameter for the error} ExParam: string; {RunLine function} procedure RunLine; virtual; {ImportProc is called when the script needs to import an external function} function ImportProc(const Name: ShortString; var proc: TIFProcRec): Boolean; Virtual; {ExceptionProc is called when an error occurs} procedure ExceptionProc(proc, Position: Cardinal; Ex: TIFError; const s: string); Virtual; Public {Call CMD_Err to cause an error and stop the script} procedure CMD_Err(EC: TIFError); {Call CMD_Err2 to cause an error and stop the script} procedure CMD_Err2(EC: TIFError; const Param: string); {Optional tag of the script engine} property Id: Pointer read FID write FID; {The MemoryManager used when calling CreateVariant/DestroyVariant} {$IFNDEF NOSMARTMM}property MemoryManager: Pointer Read MM;{$ENDIF} {This function will return about information} class function About: string; {Use RunProc to call a script function. The Params will not be freed after the call} function RunProc(Params: TIfList; ProcNo: Cardinal): Boolean; {Search for a type (l is the starting position)} function FindType(StartAt: Cardinal; BaseType: TIFPSBaseType; var l: Cardinal): PIFTypeRec; {Search for a type} function FindType2(BaseType: TIFPSBaseType): PIFTypeRec; {Return type no L} function GetTypeNo(l: Cardinal): PIFTypeRec; {Create an integer variant} function CreateIntegerVariant(FType: PIFTypeRec; Value: Longint): PIfVariant; {create a string variant} function CreateStringVariant(FType: PIFTypeRec; const Value: string): PIfVariant; {Create a float variant} function CreateFloatVariant(FType: PIFTypeRec; Value: Extended): PIfVariant; {Get Type that has been compiled with a name} function GetType(const Name: string): Cardinal; {Get function that has been compiled with a name} function GetProc(const Name: string): Cardinal; {Get variable that has been compiled with a name} function GetVar(const Name: string): Cardinal; {Get variable compiled with a name as a variant} function GetVar2(const Name: string): PIFVariant; {Get variable no (C)} function GetVarNo(C: Cardinal): PIFVariant; {Get Proc no (C)} function GetProcNo(C: Cardinal): PIFProcRec; {Create an instance of the executer} constructor Create; {Destroy this instance of the executer} destructor Destroy; Override; {Run the current script} function RunScript: Boolean; {Load data into the script engine} function LoadData(const s: string): Boolean; virtual; {Clear the currently loaded script} procedure Clear; Virtual; {Reset all variables in the script to zero} procedure Cleanup; Virtual; {Stop the script engine} procedure Stop; Virtual; {Pause the script engine} procedure Pause; Virtual; {Set CallCleanup to false when you don't want the script engine to cleanup all variables after RunScript} property CallCleanup: Boolean read FCallCleanup write FCallCleanup; {Status contains the current status of the scriptengine} property Status: TIFStatus Read FStatus; {The OnRunLine event is called after each executed script line} property OnRunLine: TIFPSOnLineEvent Read FOnRunLine Write FOnRunLine; {Add a special proc import; this is used for the dll and class library} procedure AddSpecialProcImport(const FName: string; P: TIFPSOnSpecialProcImport; Tag: Pointer); {Register a function by name} function RegisterFunctionName(const Name: ShortString; ProcPtr: TIFProc; Ext1, Ext2: Pointer): PProcRec; {Clear the function list} procedure ClearFunctionList; {Contains the last error proc} property ExceptionProcNo: Cardinal Read ExProc; {Contains the last error position} property ExceptionPos: Cardinal Read ExPos; {Contains the last error code} property ExceptionCode: TIFError Read ExEx; {Contains the last error string} property ExceptionString: string read ExParam; {Add a resource} procedure AddResource(Proc, P: Pointer); {Check if P is a valid resource for Proc} function IsValidResource(Proc, P: Pointer): Boolean; {Delete a resource} procedure DeleteResource(P: Pointer); {Find a resource} function FindProcResource(Proc: Pointer): Pointer; {Find a resource} function FindProcResource2(Proc: Pointer; var StartAt: Longint): Pointer; end; {Decrease the variant's refcount and free it if it's 0} procedure DisposeVariant({$IFNDEF NOSMARTMM}MM: Pointer; {$ENDIF}p: PIfVariant); {Create a variant} function CreateVariant({$IFNDEF NOSMARTMM}MM: Pointer; {$ENDIF}n: PIFTypeRec): PIfVariant; {Convert an error to a string} function TIFErrorToString(x: TIFError; const Param: string): string; {Get the value of a variant (as Cardinal/Longword)} function GetUInt(Src: PIfVariant; var s: Boolean): Cardinal; {Get the value of a variant (as Longint)} function GetInt(Src: PIfVariant; var s: Boolean): Longint; {Get the value of a variant (as Extended)} function GetReal(Src: PIfVariant; var s: Boolean): Extended; {Get the value of a variant (as String)} function GetString(Src: PIfVariant; var s: Boolean): string; {Set the value of an Integer variant in a list} procedure LSetInt(List: TIfList; Pos: Cardinal; Val: Longint); {Set the value of an unsigned integer variant in a list} procedure LSetUInt(List: TIfList; Pos: Cardinal; Val: Cardinal); {Get the value of an Integer variant in a list} function LGetInt(List: TIfList; Pos: Cardinal): Longint; {Get the value of an unsigned integer variant in a list} function LGetUInt(List: TIfList; Pos: Cardinal): Cardinal; {Set the value of a string variant in a list} procedure LSetStr(List: TIfList; Pos: Cardinal; const s: string); {Get the value of a string variant in a list} function LGetStr(List: TIfList; Pos: Cardinal): string; {Set the value of a real variant in a list} procedure LSetReal(List: TIfList; Pos: Cardinal; const Val: Extended); {Get the value of a real variant in a list} function LGetReal(List: TIfList; Pos: Cardinal): Extended; {Get the length of a variant array} function GetIFPSArrayLength(SE: TIFPSExec; p: PIfVariant): Cardinal; {Set the length of a variant array} function SetIFPSArrayLength(SE: TIFPSExec; p: PIfVariant; NewLength: Cardinal): Boolean; {Convert a variant to a string} function IFPSVariantToString(p: PIfVariant): string; {Free a list of variants and also the list} procedure FreePIFVariantList({$IFNDEF NOSMARTMM}MM: Pointer; {$ENDIF}List: TIfList); function VGetString(P: PIFVariant): string; function VGetFloat(P: PIFVariant): Extended; function VGetInt(P: PIFVariant): Longint; {$IFNDEF NOINT64} function VGetInt64(P: PIFVariant): Int64; {$ENDIF} procedure VSetString(P: PIFVariant; const d: string); procedure VSetFloat(P: PIFVariant; const d: Extended); procedure VSetInt(P: PIFVariant; const d: Longint); {$IFNDEF NOINT64} procedure VSetInt64(P: PIFVariant; const d: Int64); {$ENDIF} function RP(P: PIFVariant): PIFVariant; // Makes sure that P is not a pointer. const ENoError = ERNoError; ecCustomError = erCustomError; procedure ChangeVariantType({$IFNDEF NOSMARTMM}MM: Pointer; {$ENDIF}p: PIFVariant; n: PIFTypeRec); implementation function RP(P: PIFVariant): PIFVariant; begin if (p <> nil) and (p^.FType^.BaseType = btPointer) then Result:= p^.tPointer else Result := p; end; function VGetString(P: PIFVariant): string; begin p := RP(p); if p = nil then begin Result := ''; exit; end; case p^.FType^.BaseType of btString: Result := TbtString(p^.tstring); btChar: Result := p.tchar; {$IFNDEF NOWIDESTRING} btWideString: Result := tbtWideString(p^.twidestring); btWideChar: Result := tbtWideChar(p^.twidechar); {$ENDIF} else Result := ''; end; end; function VGetFloat(P: PIFVariant): Extended; begin p := RP(p); if p = nil then begin Result := 0; exit; end; case p^.FType^.BaseType of btSingle: Result := p^.tsingle; btDouble: Result := p^.tdouble; btExtended: Result := p^.textended; else Result := 0; end; end; function VGetInt(P: PIFVariant): Longint; begin p := RP(p); if p = nil then begin Result := 0; exit; end; case p^.FType^.BaseType of btu8: Result := p^.tu8; bts8: Result := p^.ts8; btu16: Result := p^.tu16; bts16: Result := p^.ts16; btu32, btProcPtr: Result := p^.tu32; bts32: Result := p^.ts32; else Result := 0; end; end; {$IFNDEF NOINT64} function VGetInt64(P: PIFVariant): Int64; begin p := RP(p); if p = nil then begin Result := 0; exit; end; case p^.FType^.BaseType of btu8: Result := p^.tu8; bts8: Result := p^.ts8; btu16: Result := p^.tu16; bts16: Result := p^.ts16; btu32, btProcPtr: Result := p^.tu32; bts32: Result := p^.ts32; btS64: Result := p^.ts64; else Result := 0; end; end; {$ENDIF} procedure VSetString(P: PIFVariant; const d: string); begin p := RP(p); if p = nil then begin exit; end; case p^.FType^.BaseType of btString: TbtString(p^.tstring) := d; {$IFNDEF NOWIDESTRING} btWideString: tbtWideString(p^.twidestring) := d; {$ENDIF} end; end; procedure VSetFloat(P: PIFVariant; const d: Extended); begin p := RP(p); if p = nil then begin exit; end; case p^.FType^.BaseType of btSingle: p^.tsingle := d; btDouble: p^.tdouble := d; btExtended: p^.textended := d; end; end; procedure VSetInt(P: PIFVariant; const d: Longint); begin p := RP(p); if p = nil then begin exit; end; case p^.FType^.BaseType of btu8: p^.tu8 := d; bts8: p^.ts8 := d; btu16: p^.tu16 := d; bts16: p^.ts16 := d; btu32, btProcPtr: p^.tu32 := d; bts32: p^.ts32 := d; btChar: p^.tchar:= char(d); end; end; {$IFNDEF NOINT64} procedure VSetInt64(P: PIFVariant; const d: Int64); begin p := RP(p); if p = nil then begin exit; end; case p^.FType^.BaseType of btu8: p^.tu8 := d; bts8: p^.ts8 := d; btu16: p^.tu16 := d; bts16: p^.ts16 := d; btu32, btProcPtr: p^.tu32 := d; bts32: p^.ts32 := d; btS64: p^.ts64 := d; btChar: p^.tchar := char(d); end; end; {$ENDIF} {$IFNDEF NOWIDESTRING} function MakeWString(const s: widestring): string; var i: Longint; e: string; b: boolean; begin Result := s; i := 1; b := false; while i <= length(result) do begin if Result[i] = '''' then begin if not b then begin b := true; Insert('''', Result, i); inc(i); end; Insert('''', Result, i); inc(i, 2); end else if (Result[i] < #32) or (Result[i] > #255) then begin e := '#'+inttostr(ord(Result[i])); Delete(Result, i, 1); if b then begin b := false; Insert('''', Result, i); inc(i); end; Insert(e, Result, i); inc(i, length(e)); end else begin if not b then begin b := true; Insert('''', Result, i); inc(i, 2); end else inc(i); end; end; if b then begin Result := Result + ''''; end; if Result = '' then Result := ''''''; end; {$ENDIF} function MakeString(const s: string): string; var i: Longint; e: string; b: boolean; begin Result := s; i := 1; b := false; while i <= length(result) do begin if Result[i] = '''' then begin if not b then begin b := true; Insert('''', Result, i); inc(i); end; Insert('''', Result, i); inc(i, 2); end else if (Result[i] < #32) then begin e := '#'+inttostr(ord(Result[i])); Delete(Result, i, 1); if b then begin b := false; Insert('''', Result, i); inc(i); end; Insert(e, Result, i); inc(i, length(e)); end else begin if not b then begin b := true; Insert('''', Result, i); inc(i, 2); end else inc(i); end; end; if b then begin Result := Result + ''''; end; if Result = '' then Result := ''''''; end; function IFPSVariantToString(p: PIfVariant): string; var I: Longint; begin while p^.FType^.BaseType = btPointer do begin if p^.tPointer <> nil then p := p^.tPointer else break; end; if p^.FType^.BaseType = btVariant then P := p^.tvariant; case p^.FType^.BaseType of btProcptr: begin str(p^.tu32, Result); Result := 'Proc: '+result; end; btU8: str(p^.tu8, Result); btS8: str(p^.ts8, Result); btU16: str(p^.tu16, Result); btS16: str(p^.ts16, Result); btU32: str(p^.tu32, Result); btS32: str(p^.ts32, Result); btSingle: str(p^.tsingle, Result); btDouble: str(p^.tdouble, Result); btExtended: str(p^.textended, Result); btString, btPChar: Result := makestring(string(p^.tString)); btchar: Result := MakeString(p^.tchar); {$IFNDEF NOWIDESTRING} btwidechar: Result := MakeWString(p^.tchar); btWideString: Result := MakeWString(tbtwidestring(p^.tstring)); {$ENDIF} {$IFNDEF NOINT64}btS64: str(p^.ts64, Result);{$ENDIF} btRecord, btArray: begin Result := '['; if p^.tArray <>nil then begin for i := 0 to pbtRecord(p^.tarray)^.FieldCount -1 do begin if i <> 0 then Result := Result + ', '; Result := Result + IFPSVariantToString(pbtRecord(p^.tarray)^.Fields[i]); end; end; Result := Result + ']'; end; btPointer: Result := 'Nil'; btResourcePointer: Result := '[ResourcePointer]'; else Result := '[Invalid]'; end; end; function GetIFPSArrayLength(SE: TIFPSExec; p: PIfVariant): Cardinal; begin p := rp(p); if p^.FType^.BaseType = btVariant then begin p := p^.tvariant; if p^.ftype = nil then begin result := 0; exit; end; end; if p^.FType^.BaseType <> btArray then begin Result := 0; exit; end; if p^.tArray = nil then Result := 0 else Result := pbtrecord(p^.tArray)^.FieldCount; end; function Min(const x, Y: Integer): Integer; begin if x < Y then Result := x else Result := Y; end; function SetIFPSArrayLength(SE: TIFPSExec; p: PIfVariant; NewLength: Cardinal): Boolean; var I, oldl: Integer; r: pbtrecord; begin p := rp(p); if p^.FType^.BaseType = btVariant then begin p := p^.tvariant; if p^.ftype = nil then begin result := False; exit; end; end; if p^.FType^.BaseType <> btArray then begin Result := False; exit;end; if p^.tArray = nil then begin I := NewLength; if I > 0 then begin try GetMem(r, 4 + I * 4); except Result := False; exit; end; r^.FieldCount := I; p^.tArray := r; Dec(I); while I >= 0 do begin r^.Fields[I] := CreateVariant({$IFNDEF NOSMARTMM}SE.MemoryManager, {$ENDIF}SE.GetTypeNo(Cardinal(p^.FType^.Ext))); if r^.Fields[I] = nil then begin while I < Longint(NewLength) do begin DisposeVariant({$IFNDEF NOSMARTMM}SE.MemoryManager, {$ENDIF}r.Fields[I]); Inc(I); end; Result := False; exit; end; Dec(I); end; end; end else begin r := p^.tArray; oldl := NewLength; for I := oldl to r^.FieldCount - 1 do begin DisposeVariant({$IFNDEF NOSMARTMM}SE.MemoryManager, {$ENDIF}r^.Fields[I]); end; if oldl = 0 then begin FreeMem(r, 4 + 4 * r^.FieldCount); p^.tArray := nil; end else begin I := oldl; oldl := r^.FieldCount; try ReallocMem(r, 4 + 4 * I); except for I := 0 to Min(NewLength, oldl) - 1 do begin DisposeVariant({$IFNDEF NOSMARTMM}SE.MemoryManager, {$ENDIF}r^.Fields[I]); end; FreeMem(r, 4 + 4 * NewLength); p^.tArray := nil; Result := False; exit; end; p^.tArray := r; r^.FieldCount := I; for I := r^.FieldCount - 1 downto oldl do begin r^.Fields[I] := CreateVariant({$IFNDEF NOSMARTMM}SE.MemoryManager, {$ENDIF}SE.GetTypeNo(Cardinal(p^.FType^.Ext))); if r^.Fields[I] = nil then begin oldl := I; while oldl < Longint(NewLength) do begin DisposeVariant({$IFNDEF NOSMARTMM}SE.MemoryManager, {$ENDIF}r.Fields[oldl]); Inc(oldl); end; FreeMem(r, 4 + 4 * r^.FieldCount); p^.TArray := nil; Result := False; exit; end; end; end; end; Result := True; end; function SafeStr(const s: string): string; var i : Longint; begin Result := s; for i := 1 to length(s) do begin if s[i] in [#0..#31] then begin Result := Copy(s, 1, i-1); exit; end; end; end; function TIFErrorToString(x: TIFError; const Param: string): string; begin case x of ErNoError: Result := 'No Error'; erCannotImport: Result := 'Cannot Import '+Safestr(Param); erInvalidType: Result := 'Invalid Type'; ErInternalError: Result := 'Internal error'; erInvalidHeader: Result := 'Invalid Header'; erInvalidOpcode: Result := 'Invalid Opcode'; erInvalidOpcodeParameter: Result := 'Invalid Opcode Parameter'; erNoMainProc: Result := 'no Main Proc'; erOutOfGlobalVarsRange: Result := 'Out of Global Vars range'; erOutOfProcRange: Result := 'Out of Proc Range'; ErOutOfRange: Result := 'Out Of Range'; erOutOfStackRange: Result := 'Out Of Stack Range'; ErTypeMismatch: Result := 'Type Mismatch'; erUnexpectedEof: Result := 'Unexpected End Of File'; erVersionError: Result := 'Version error'; ErDivideByZero: Result := 'divide by Zero'; erMathError: Result := 'Math error'; erCouldNotCallProc: Result := 'Could not call proc'; erOutofRecordRange: Result := 'Out of Record Fields Range'; erNullPointerException: Result := 'Null Pointer Exception'; erNullVariantError: Result := 'Null variant error'; erOutOfMemory: Result := 'Out Of Memory'; erException: Result := 'Exception: '+ Param; erCustomError: Result := Param; else Result := 'Unknown error'; end; // end; {$IFNDEF NOSMARTMM} const Count = 50; type TFreeIFVariant = packed record NextFreeItem: Longint; DummyData: array[0..SizeOf(TIfVariant) - SizeOf(Longint) - 1 + SizeOf(Pointer)] of Byte; end; PPageData = ^TPageData; TMyIFVariant = packed record Page: PPageData; p: TIfVariant; end; TPageData = packed record ItemCount, FirstFreeItem: Longint; PrevPage, NextPage, PrevFreeItemsPage, NextFreeItemsPage: PPageData; case Byte of 0: (BLOCK: array[0..Count - 1] of TMyIFVariant); 1: (FREELIST: array[0..Count - 1] of TFreeIFVariant); end; type TIFVariantMemoryManager = class Private FFirstFreeItemsPage, FFirstPage: PPageData; procedure CleanItem(Page: PPageData); function AllocItem: Boolean; Public constructor Create; destructor Destroy; Override; procedure Clear; function Alloc: PIfVariant; procedure DisposeItem(p: PIfVariant); end; type TPointingInteger = Longint; // same size as Pointer function TIFVariantMemoryManager.Alloc: PIfVariant; var CB: PPageData; I: Integer; begin if FFirstFreeItemsPage = nil then begin if not AllocItem then begin Result := nil; exit; end; end; CB := FFirstFreeItemsPage; Inc(CB^.ItemCount); I := CB^.FirstFreeItem; CB^.FirstFreeItem := CB^.FREELIST[I].NextFreeItem; Result := @CB^.BLOCK[I].p; CB^.BLOCK[I].Page := CB; if CB^.FirstFreeItem = -1 then begin // remove from freeitemspage list if CB^.PrevFreeItemsPage <> nil then CB^.PrevFreeItemsPage^.NextFreeItemsPage := CB^.NextFreeItemsPage; if CB^.NextFreeItemsPage <> nil then CB^.NextFreeItemsPage^.PrevFreeItemsPage := CB^.PrevFreeItemsPage; if FFirstFreeItemsPage = CB then FFirstFreeItemsPage := CB^.NextFreeItemsPage; end; end; function TIFVariantMemoryManager.AllocItem: Boolean; var NewItem: PPageData; I: Longint; begin try New(NewItem); except Result := False; exit; end; NewItem^.ItemCount := 0; NewItem^.FirstFreeItem := Count - 1; NewItem^.PrevPage := nil; NewItem^.NextPage := FFirstPage; NewItem^.PrevFreeItemsPage := nil; NewItem^.NextFreeItemsPage := FFirstFreeItemsPage; for I := Count - 1 downto 0 do begin NewItem^.FREELIST[I].NextFreeItem := I - 1; end; if FFirstPage <> nil then FFirstPage^.PrevPage := NewItem; if FFirstFreeItemsPage <> nil then FFirstFreeItemsPage^.PrevPage := NewItem; FFirstPage := NewItem; FFirstFreeItemsPage := NewItem; Result := True; end; procedure TIFVariantMemoryManager.CleanItem(Page: PPageData); begin if Page^.PrevPage <> nil then Page^.PrevPage^.NextPage := Page^.NextPage; if Page^.NextPage <> nil then Page^.NextPage^.PrevPage := Page^.PrevPage; if Page^.PrevFreeItemsPage <> nil then Page^.PrevFreeItemsPage^.NextFreeItemsPage := Page^.NextFreeItemsPage; if Page^.NextFreeItemsPage <> nil then Page^.NextFreeItemsPage^.PrevFreeItemsPage := Page^.PrevFreeItemsPage; if FFirstPage = Page then FFirstPage := Page^.NextPage; if FFirstFreeItemsPage = Page then FFirstFreeItemsPage := Page^.NextFreeItemsPage; Dispose(Page); end; procedure TIFVariantMemoryManager.Clear; var CB, NB: PPageData; begin CB := FFirstPage; while CB <> nil do begin NB := CB^.NextPage; Dispose(CB); CB := NB; end; FFirstPage := nil; FFirstFreeItemsPage := nil; end; constructor TIFVariantMemoryManager.Create; begin inherited Create; FFirstFreeItemsPage := nil; FFirstPage := nil; end; destructor TIFVariantMemoryManager.Destroy; begin Clear; inherited Destroy; end; procedure TIFVariantMemoryManager.DisposeItem(p: PIfVariant); var Page: PPageData; I: Longint; begin Page := PPageData(Pointer(TPointingInteger(p) - SizeOf(Pointer))^); I := (TPointingInteger(p) - TPointingInteger(@Page^.BLOCK) - SizeOf(Pointer)) div SizeOf(TMyIFVariant); Dec(Page^.ItemCount); Page^.FREELIST[I].NextFreeItem := Page^.FirstFreeItem; Page^.FirstFreeItem := I; if Page^.ItemCount = 0 then begin CleanItem(Page); end else if Page^.ItemCount = Count - 1 then begin // insert into list if FFirstFreeItemsPage <> nil then FFirstFreeItemsPage^.PrevFreeItemsPage := Page; Page^.PrevFreeItemsPage := nil; Page^.NextFreeItemsPage := FFirstFreeItemsPage; FFirstFreeItemsPage := Page; end; end; {$ENDIF} const ReturnAddressType: TIFTypeRec = (Ext: nil; BaseType: btReturnAddress); type PIFPSExceptionHandler =^TIFPSExceptionHandler; TIFPSExceptionHandler = packed record BasePtr, StackSize: Cardinal; FinallyOffset, ExceptOffset, Finally2Offset, EndOfBlock: Cardinal; end; TIFPSHeader = packed record HDR: Cardinal; IFPSBuildNo: Cardinal; TypeCount: Cardinal; ProcCount: Cardinal; VarCount: Cardinal; MainProcNo: Cardinal; ImportTableSize: Cardinal; end; TIFPSExportItem = packed record ProcNo: Cardinal; NameLength: Cardinal; DeclLength: Cardinal; end; TIFPSType = packed record BaseType: TIFPSBaseType; end; TIFPSProc = packed record Flags: Byte; end; TIFPSVar = packed record TypeNo: Cardinal; Flags: Byte; end; PSpecialProc = ^TSpecialProc; TSpecialProc = record P: TIFPSOnSpecialProcImport; namehash: Longint; Name: string; tag: pointer; end; procedure DisposeType(p: PIFTypeRec); var x: PIFRecordType; begin if p^.BaseType = btRecord then begin x := p^.Ext; x^.Data := ''; Dispose(x); end; Dispose(p); end; procedure DisposeProc(SE: TIFPSExec; p: PIFProcRec); begin if not p^.ExternalProc then FreeMem(p^.Data, p^.Length); Dispose(p); end; function Initrecord({$IFNDEF NOSMARTMM}MM: Pointer; {$ENDIF}FType: PIFRecordType; var Rec: pbtrecord): Boolean; var I, J: Longint; begin I := (Length(FType^.Data) shr 2); try GetMem(Rec, 4 + 4 * I); except Result := False; exit; end; Rec.FieldCount := I; for I := 0 to Rec.FieldCount - 1 do begin Rec.Fields[I] := CreateVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}PIFTypeRec((@FType^.Data[I shl 2 + 1])^)); if Rec.Fields[I] = nil then begin for J := I - 1 downto 0 do begin DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Rec.Fields[J]); FreeMem(Rec, 4 * 4 * (Length(FType^.Data) shr 2)); Result := False; exit; end; end; end; Result := True; end; procedure FreeRecord({$IFNDEF NOSMARTMM}MM: Pointer; {$ENDIF}Rec: pbtrecord); var I: Longint; begin if Rec <> nil then begin for I := Rec.FieldCount - 1 downto 0 do DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Rec.Fields[I]); FreeMem(Rec, Rec.FieldCount * 4 + 4); end; end; procedure DisposeVariant({$IFNDEF NOSMARTMM}MM: Pointer; {$ENDIF}p: PIfVariant); begin if p <> nil then if p^.RefCount = 0 then begin if p^.FType <> nil then begin if (p^.FType^.BaseType = btPointer) and (p^.tPointer <> nil) then begin DisposeVariant({$IFNDEF NOSMARTMM}mm, {$ENDIF} p^.tPointer); end else if (p^.FType^.BaseType = btRecord) or (p^.FType^.BaseType = btArray) then FreeRecord({$IFNDEF NOSMARTMM}MM, {$ENDIF}p^.trecord) else if p^.FType^.BaseType = btString then Finalize(TbtString((@p^.tstring)^)) {$IFNDEF NOWIDESTRING} else if p^.FType^.BaseType = btWideString then Finalize(TbtwideString((@p^.twidestring)^)) {$ENDIF} else if p^.FType^.BaseType = btResourcePointer then begin if (@p^.tResourceFreeProc <> nil) then begin p^.tResourceFreeProc(vrfFree, p, nil); end; end else if p^.FType^.BaseType = btvariant then DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}p^.tvariant); end; {$IFNDEF NOSMARTMM} TIFVariantMemoryManager(MM).DisposeItem(p); {$ELSE} Dispose(p); {$ENDIF} end else Dec(p^.RefCount); end; procedure ChangeVariantType({$IFNDEF NOSMARTMM}MM: Pointer; {$ENDIF}p: PIFVariant; n: PIFTypeRec); begin if p^.FType <> nil then begin if (p^.FType^.BaseType = btRecord) or (p^.FType^.BaseType = btArray) then FreeRecord({$IFNDEF NOSMARTMM}MM, {$ENDIF}p^.trecord) else if p^.FType^.BaseType = btString then Finalize(TbtString((@p^.tstring)^)) {$IFNDEF NOWIDESTRING} else if p^.FType^.BaseType = btWideString then Finalize(TbtwideString((@p^.twidestring)^)) {$ENDIF} else if p^.FType^.BaseType = btResourcePointer then begin if (@p^.tResourceFreeProc <> nil) then begin p^.tResourceFreeProc(vrfFree, p, nil); end; end else if p^.FType^.BaseType = btvariant then DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}p^.tvariant); end; p^.FType := n; if n <> nil then begin if n^.BaseType = btVariant then begin {$IFDEF NOSMARTMM} try New(p^.tvariant); except p^.tvariant := nil; exit; end; {$ELSE} p^.TVariant := TIFVariantMemoryManager(MM).Alloc; {$ENDIF} p^.tVariant^.FType := nil; p^.tvariant^.refcount := 0; end else if (n^.BaseType = btRecord) then begin p^.RefCount := 0; if not Initrecord({$IFNDEF NOSMARTMM}MM, {$ENDIF}n^.Ext, pbtrecord(p^.trecord)) then begin p^.trecord := nil; DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}p); end; end else begin FillChar(p^.RefCount, SizeOf(TIfVariant) - SizeOf(Pointer), 0); end; end; end; function CreateVariant({$IFNDEF NOSMARTMM}MM: Pointer; {$ENDIF}n: PIFTypeRec): PIfVariant; var p: PIfVariant; begin if n = nil then begin Result := nil; exit; end; {$IFNDEF NOSMARTMM} p := TIFVariantMemoryManager(MM).Alloc; if p = nil then begin Result := nil; exit; end; {$ELSE} try New(p); except Result := nil; exit; end; {$ENDIF} p^.FType := n; if n^.BaseType = btVariant then begin {$IFDEF NOSMARTMM} try New(p^.tvariant); except p^.tvariant := nil; Result := nil; exit; end; {$ELSE} p^.TVariant := TIFVariantMemoryManager(MM).Alloc; {$ENDIF} p^.tVariant^.FType := nil; p^.tvariant^.RefCount := 0; end else if (n^.BaseType = btRecord) then begin p^.RefCount := 0; if not Initrecord({$IFNDEF NOSMARTMM}MM, {$ENDIF}n^.Ext, pbtrecord(p^.trecord)) then begin p^.trecord := nil; DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}p); end; end else begin FillChar(p^.RefCount, SizeOf(TIfVariant) - SizeOf(Pointer), 0); end; CreateVariant := p; end; procedure LSetReal(List: TIfList; Pos: Cardinal; const Val: Extended); var p: PIfVariant; begin p := List.GetItem(Pos); if (p <> nil) and (p^.FType^.BaseType = btPointer) then p := p^.tPointer; if p = nil then exit; case p^.FType^.BaseType of btSingle: p^.tsingle := Val; btDouble: p^.tdouble := Val; btExtended: p^.textended := Val; end; end; function LGetReal(List: TIfList; Pos: Cardinal): Extended; var p: PIfVariant; begin p := List.GetItem(Pos); if (p <> nil) and (p^.FType^.BaseType = btPointer) then p := p^.tPointer; if p = nil then begin result := 0; exit; end; case p^.FType^.BaseType of btSingle: Result := p^.tsingle; btDouble: Result := p^.tdouble; btExtended: Result := p^.textended; else Result := 0; end; end; function LGetStr(List: TIfList; Pos: Cardinal): string; var p: PIfVariant; begin p := List.GetItem(Pos); if (p <> nil) and (p^.FType^.BaseType = btPointer) then p := p^.tPointer; if p = nil then begin result := ''; exit; end; case p^.FType^.BaseType of btString: Result := TbtString(p^.tstring); btChar: Result := p.tchar; {$IFNDEF NOWIDESTRING} btWideString: Result := tbtWideString(p^.twidestring); btWideChar: Result := tbtWideChar(p^.twidechar); {$ENDIF} end; end; procedure LSetStr(List: TIfList; Pos: Cardinal; const s: string); var p: PIfVariant; begin p := List.GetItem(Pos); if (p <> nil) and (p^.FType^.BaseType = btPointer) then p := p^.tPointer; if p = nil then exit; case p^.FType^.BaseType of btstring: TbtString(p^.tstring) := s; {$IFNDEF NOWIDESTRING} btWideString: tbtwidestring(p^.twidestring) := s; {$ENDIF} end; end; function LGetUInt(List: TIfList; Pos: Cardinal): Cardinal; var p: PIfVariant; begin p := List.GetItem(Pos); if (p <> nil) and (p^.FType^.BaseType = btPointer) then p := p^.tPointer; if p = nil then begin result := 0; exit; end; case p^.FType^.BaseType of btU8: Result := p^.tu8; btS8: Result := p^.tS8; btU16: Result := p^.tu16; btS16: Result := p^.ts16; btU32, btProcPtr: Result := p^.tu32; btS32: Result := p^.ts32; {$IFNDEF NOINT64}btS64: Result := p^.ts64;{$ENDIF} btChar: Result := ord(p^.tchar); {$IFNDEF NOWIDESTRING} btwideChar: Result := ord(p^.twidechar); btwidestring: begin if Length(tbtwidestring(p^.twidestring)) =1 then begin Result := ord(tbtwidestring(p^.twidestring)[1]); end else Result := 0; end; {$ENDIF} btString: begin if Length(tbtstring(p^.tstring)) =1 then begin Result := ord(tbtstring(p^.tstring)[1]); end else Result := 0; end; else Result := 0; end; end; function LGetInt(List: TIfList; Pos: Cardinal): Longint; var p: PIfVariant; begin p := List.GetItem(Pos); if (p <> nil) and (p^.FType^.BaseType = btPointer) then p := p^.tPointer; if p = nil then begin result := 0; exit; end; case p^.FType^.BaseType of btU8: Result := p^.tu8; btS8: Result := p^.tS8; btU16: Result := p^.tu16; btS16: Result := p^.ts16; btU32, btProcPtr: Result := p^.tu32; btS32: Result := p^.ts32; {$IFNDEF NOINT64}btS64: Result := p^.ts64;{$ENDIF} btChar: Result := ord(p^.tchar); {$IFNDEF NOWIDESTRING} btwideChar: Result := ord(p^.twidechar); btwidestring: begin if Length(tbtwidestring(p^.twidestring)) =1 then begin Result := ord(tbtwidestring(p^.twidestring)[1]); end else Result := 0; end; {$ENDIF} btString: begin if Length(tbtstring(p^.tstring)) =1 then begin Result := ord(tbtstring(p^.tstring)[1]); end else Result := 0; end; else Result := 0; end; end; procedure LSetUInt(List: TIfList; Pos: Cardinal; Val: Cardinal); var Src: PIfVariant; begin Src := List.GetItem(Pos); if (Src <> nil) and (Src^.FType^.BaseType = btPointer) then Src := SRc^.tPointer; if Src = nil then exit; case Src^.FType^.BaseType of btU8: Src^.tu8 := Val; btS8: Src^.tS8 := Val; btU16: Src^.tu16 := Val; btS16: Src^.ts16 := Val; btU32, btProcPtr: Src^.tu32 := Val; btS32: Src^.ts32 := Val; {$IFNDEF NOINT64}btS64: src^.ts64 := Val;{$ENDIF} btString: tbtstring(src^.tstring) := chr(Val); btChar: src^.tchar := chr(val); {$IFNDEF NOWIDESTRING} btwideChar: src^.tchar := chr(val); btwidestring: tbtwidestring(src.twidestring) := widechar(val); {$ENDIF} end; end; procedure LSetInt(List: TIfList; Pos: Cardinal; Val: Longint); var Src: PIfVariant; begin Src := List.GetItem(Pos); if (Src <> nil) and (Src^.FType^.BaseType = btPointer) then Src := SRc^.tPointer; if Src = nil then exit; case Src^.FType^.BaseType of btU8: Src^.tu8 := Val; btS8: Src^.tS8 := Val; btU16: Src^.tu16 := Val; btS16: Src^.ts16 := Val; btU32, btProcPtr: Src^.tu32 := Val; btS32: Src^.ts32 := Val; {$IFNDEF NOINT64}btS64: src^.ts64 := Val;{$ENDIF} btString: tbtstring(src^.tstring) := chr(Val); btChar: src^.tchar := chr(val); {$IFNDEF NOWIDESTRING} btwideChar: src^.tchar := chr(val); btwidestring: tbtwidestrinG(src.twidestring) := widechar(val); {$ENDIF} end; end; {$IFNDEF NOINT64} function GetInt64(Src: PIfVariant; var s: Boolean): Int64; begin if (Src <> nil) and (Src^.FType^.BaseType = btPointer) then Src := SRc^.tPointer; if Src = nil then begin Result := 0; exit; end; case Src^.FType^.BaseType of btVariant: begin if src^.TVariant^.FType <> nil then Result := GetInt64(Src^.TVariant, s) else Result := 0; end; btU8: Result := Src^.tu8; btS8: Result := Src^.tS8; btU16: Result := Src^.tu16; btS16: Result := Src^.ts16; btU32, btProcPtr: Result := Src^.tu32; btS32: Result := Src^.ts32; btS64: Result := src^.ts64; btChar: Result := ord(src^.tchar); {$IFNDEF NOWIDESTRING} btwideChar: Result := ord(src^.twidechar); btwidestring: begin if Length(tbtwidestring(src^.twidestring)) =1 then begin Result := ord(tbtwidestring(src^.twidestring)[1]); end else begin Result := 0; s := false; end; end; {$ENDIF} btString: begin if Length(tbtstring(src^.tstring)) =1 then begin Result := ord(tbtstring(src^.tstring)[1]); end else begin Result := 0; s := False; end; end; else begin s := False; Result := 0; end; end; end; {$ENDIF} function GetUInt(Src: PIfVariant; var s: Boolean): Cardinal; begin if (Src <> nil) and (Src^.FType^.BaseType = btPointer) then Src := SRc^.tPointer; if Src = nil then begin Result := 0; exit; end; case Src^.FType^.BaseType of btVariant: begin if src^.TVariant^.FType <> nil then Result := GetUINT(Src^.TVariant, s) else Result := 0; end; btU8: Result := Src^.tu8; btS8: Result := Src^.tS8; btU16: Result := Src^.tu16; btS16: Result := Src^.ts16; btU32, btProcPtr: Result := Src^.tu32; btS32: Result := Src^.ts32; {$IFNDEF NOINT64}btS64: Result := src^.ts64;{$ENDIF} btChar: Result := ord(src^.tchar); {$IFNDEF NOWIDESTRING} btwideChar: Result := ord(src^.twidechar); btwidestring: begin if Length(tbtwidestring(src^.twidestring)) =1 then begin Result := ord(tbtwidestring(src^.twidestring)[1]); end else begin Result := 0; s:= false; end; end; {$ENDIF} btString: begin if Length(tbtstring(src^.tstring)) =1 then begin Result := ord(tbtstring(src^.tstring)[1]); end else begin Result := 0; s := False; end; end; else begin s := False; Result := 0; end; end; end; function GetInt(Src: PIfVariant; var s: Boolean): Longint; begin if (Src <> nil) and (Src^.FType^.BaseType = btPointer) then Src := SRc^.tPointer; if Src = nil then begin Result := 0; exit; end; case Src^.FType^.BaseType of btVariant: begin if src^.TVariant^.FType <> nil then Result := GetInt(Src^.TVariant, s) else Result := 0; end; btU8: Result := Src^.tu8; btS8: Result := Src^.tS8; btU16: Result := Src^.tu16; btS16: Result := Src^.ts16; btU32, btProcPtr: Result := Src^.tu32; btS32: Result := Src^.ts32; {$IFNDEF NOINT64}btS64: Result := src^.ts64;{$ENDIF} btChar: Result := ord(src^.tchar); {$IFNDEF NOWIDESTRING} btwideChar: Result := ord(src^.twidechar); btwidestring: begin if Length(tbtwidestring(src^.twidestring)) =1 then begin Result := ord(tbtwidestring(src^.twidestring)[1]); end else begin Result := 0; s := false; end; end; {$ENDIF} btString: begin if Length(tbtstring(src^.tstring)) =1 then begin Result := ord(tbtstring(src^.tstring)[1]); end else begin Result := 0; s := False; end; end; else begin s := False; Result := 0; end; end; end; function GetReal(Src: PIfVariant; var s: Boolean): Extended; begin if (Src <> nil) and (Src^.FType^.BaseType = btPointer) then Src := SRc^.tPointer; if Src = nil then begin Result := 0; exit; end; case Src^.FType^.BaseType of btVariant: begin if src^.TVariant^.FType <> nil then Result := GetReal(Src^.TVariant, s) else Result := 0; end; btU8: Result := Src^.tu8; btS8: Result := Src^.tS8; btU16: Result := Src^.tu16; btS16: Result := Src^.ts16; btU32, btProcPtr: Result := Src^.tu32; btS32: Result := Src^.ts32; btSingle: Result := Src^.tsingle; btDouble: Result := Src^.tdouble; btExtended: Result := Src^.textended; else begin s := False; Result := 0; end; end; end; function GetString(Src: PIfVariant; var s: Boolean): string; begin if (Src <> nil) and (Src^.FType^.BaseType = btPointer) then Src := SRc^.tPointer; if Src = nil then begin Result := ''; exit; end; case Src^.FType^.BaseType of btVariant: begin if src^.TVariant^.FType <> nil then Result := GetString(Src^.TVariant, s) else Result := ''; end; btchar: Result := src^.tchar; btPChar, btString: Result := TbtString((@Src^.tstring)^); {$IFNDEF NOWIDESTRING} btwidechar: Result := src^.twidechar; btwideString: Result := TbtwideString((@Src^.twidestring)^); {$ENDIF} else begin s := False; Result := ''; end; end; end; {$IFNDEF NOWIDESTRING} function GetWideString(Src: PIfVariant; var s: Boolean): widestring; begin if (Src <> nil) and (Src^.FType^.BaseType = btPointer) then Src := SRc^.tPointer; if Src = nil then begin Result := ''; exit; end; case Src^.FType^.BaseType of btVariant: begin if src^.TVariant^.FType <> nil then Result := GetString(Src^.TVariant, s) else Result := ''; end; btchar: Result := Src^.tchar; btPChar, btString: Result := TbtString((@Src^.tstring)^); btwidechar: Result := src^.twidechar; btwideString: Result := TbtwideString((@Src^.twidestring)^); else begin s := False; Result := ''; end; end; end; {$ENDIF} function LookupProc(List: TIfList; const Name: ShortString): PProcRec; var h, l: Longint; begin h := MakeHash(Name); for l := 0 to List.Count - 1 do begin if (PProcRec(List.GetItem(l))^.Hash = h) and (PProcRec(List.GetItem(l))^.Name = Name) then begin Result := List.GetItem(l); exit; end; end; Result := nil; end; { TIFPSExec } procedure TIFPSExec.ClearFunctionList; var x: PProcRec; l: Longint; begin for l := 0 to FRegProcs.Count - 1 do begin x := FRegProcs.GetItem(l); if @x^.FreeProc <> nil then x^.FreeProc(Self, x); Dispose(x); end; FRegProcs.Clear; end; class function TIFPSExec.About: string; begin Result := 'Innerfuse Pascal Script III ' + IFPSCurrentversion + '. Copyright (c) 2001-2002 by Carlo Kok'; end; procedure TIFPSExec.Cleanup; var I: Longint; p: PIfVariant; begin if FStatus <> isLoaded then exit; for I := 0 to Longint(FGlobalVars.Count) - 1 do begin p := FGlobalVars.GetItem(I); FGlobalVars.SetItem(I, CreateVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}p^.FType)); DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}p); end; end; type PIFPSExportedVar = ^TIFPSExportedVar; TIFPSExportedVar = record FName: string; FNameHash: Longint; FVarNo: Cardinal; end; procedure TIFPSExec.Clear; var I: Longint; temp: PIFPSResource; Proc: TIFPSResourceFreeProc; pp: PIFPSExceptionHandler; begin for i := Longint(FExceptionStack.Count) -1 downto 0 do begin pp := FExceptionStack.GetItem(i); Dispose(pp); end; for i := Longint(FResources.Count) -1 downto 0 do begin Temp := FResources.GetItem(i); Proc := Temp^.Proc; Proc(Self, Temp^.P); Dispose(Temp); end; for i := Longint(FExportedVars.Count) -1 downto 0 do begin Dispose(PIFPSExportedVar(FExportedVars.GetItem(I))); end; for I := 0 to Longint(FStack.Count) - 1 do begin DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}FStack.GetItem(I)); end; for I := 0 to Longint(FProcs.Count) - 1 do begin DisposeProc(Self, FProcs.GetItem(I)); end; for I := 0 to Longint(FGlobalVars.Count) - 1 do begin DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}FGlobalVars.GetItem(I)); end; for I := 0 to Longint(FTypes.Count) - 1 do begin DisposeType(FTypes.GetItem(I)); end; FStack.Clear; FProcs.Clear; FGlobalVars.Clear; FTypes.Clear; FStatus := isNotLoaded; FResources.Clear; FExportedVars.Clear; FExceptionStack.Clear; end; constructor TIFPSExec.Create; begin inherited Create; {$IFNDEF NOSMARTMM}MM := TIFVariantMemoryManager.Create; {$ENDIF} FExceptionStack := TIfList.Create; FCallCleanup := False; FResources := TIfList.Create; FTypes := TIfList.Create; FProcs := TIfList.Create; FGlobalVars := TIfList.Create; FStack := TIfList.Create; FMainProc := 0; FStatus := isNotLoaded; FRegProcs := TIfList.Create; FExportedVars := TIfList.create; FSpecialProcList := TIfList.Create; end; destructor TIFPSExec.Destroy; var I: Longint; P: PSpecialProc; begin Clear; for I := FSpecialProcList.Count -1 downto 0 do begin P := FSpecialProcList.GetItem(I); Dispose(p); end; FStack.Free; FResources.Free; FExportedVars.Free; FGlobalVars.Free; FProcs.Free; FTypes.Free; FSpecialProcList.Free; ClearFunctionList; FRegProcs.Free; FExceptionStack.Free; {$IFNDEF NOSMARTMM}TIFVariantMemoryManager(MM).Free; {$ENDIF} inherited Destroy; end; procedure TIFPSExec.ExceptionProc(proc, Position: Cardinal; Ex: TIFError; const s: string); var d, l: Longint; pp: PIFPSExceptionHandler; begin ExProc := proc; ExPos := Position; ExEx := Ex; ExParam := s; if Ex = eNoError then Exit; for d := FExceptionStack.Count -1 downto 0 do begin pp := FExceptionStack.GetItem(d); if FStack.Count > pp^.StackSize then begin for l := Longint(FStack.count) -1 downto Longint(pp^.StackSize) do begin DisposeVariant({$IFNDEF NOSMARTMM}mm, {$ENDIF}FStack.GetItem(l)); FStack.Delete(l); end; end; FCurrStackBase := pp^.BasePtr; if pp^.FinallyOffset <> cardinal(-1) then begin FCurrentPosition := pp^.FinallyOffset; pp^.FinallyOffset := cardinal(-1); Exit; end else if pp^.ExceptOffset <> cardinal(-1) then begin FCurrentPosition := pp^.ExceptOffset; pp^.ExceptOffset := cardinal(-1); Exit; end else if pp^.Finally2Offset <> Cardinal(-1) then begin FCurrentPosition := pp^.FinallyOffset; pp^.FinallyOffset := cardinal(-1); Exit; end; Dispose(pp); FExceptionStack.Delete(FExceptionStack.Count -1); end; // FStatus := isPaused; end; function TIFPSExec.ImportProc(const Name: ShortString; var proc: TIFProcRec): Boolean; var u: PProcRec; fname: string; I, fnh: Longint; P: PSpecialProc; begin if name = '' then begin fname := proc.ExportDecl; fname := copy(fname, 1, pos(':', fname)-1); fnh := MakeHash(fname); for I := FSpecialProcList.Count -1 downto 0 do begin p := FSpecialProcList.GetItem(I); IF (p^.name = '') or ((p^.namehash = fnh) and (p^.name = fname)) then begin if p^.P(Self, @Proc, p^.tag) then begin Result := True; exit; end; end; end; Result := FAlse; exit; end; u := LookupProc(FRegProcs, Name); if u = nil then begin Result := False; exit; end; proc.ProcPtr := u^.ProcPtr; proc.Ext1 := u^.Ext1; proc.Ext2 := u^.Ext2; Result := True; end; function TIFPSExec.RegisterFunctionName(const Name: ShortString; ProcPtr: TIFProc; Ext1, Ext2: Pointer): PProcRec; var p: PProcRec; begin if LookupProc(FRegProcs, Name) <> nil then begin Result := nil; exit; end; New(p); p^.Name := Name; p^.Hash := MakeHash(Name); p^.ProcPtr := ProcPtr; p^.FreeProc := nil; p^.Ext1 := Ext1; p^.Ext2 := Ext2; FRegProcs.Add(p); Result := P; end; function TIFPSExec.LoadData(const s: string): Boolean; var HDR: TIFPSHeader; Pos: Cardinal; function read(var Data; Len: Cardinal): Boolean; begin if Longint(Pos + Len) <= Length(s) then begin Move(s[Pos + 1], Data, Len); Pos := Pos + Len; read := True; end else read := False; end; {$WARNINGS OFF} function LoadTypes: Boolean; var currf: TIFPSType; Curr: PIFTypeRec; currr: PIFRecordType; fe: Boolean; l: Longint; d: Cardinal; function resolve(var s: string): Boolean; var l: Longint; p: PIFTypeRec; begin l := 1; while l < Length(s) do begin p := FTypes.GetItem(Cardinal(s[l])); if p = nil then begin Result := False; exit; end; PIFTypeRec((@s[l])^) := p; if p^.BaseType = btRecord then begin Delete(s, l, 4); insert(PIFRecordType(p^.Ext)^.Data, s, l); end; l := l + 4; end; Result := True; end; begin LoadTypes := True; for l := 0 to HDR.TypeCount - 1 do begin if not read(currf, SizeOf(currf)) then begin cmd_err(erUnexpectedEof); LoadTypes := False; exit; end; if (currf.BaseType and 128) <> 0 then begin fe := True; currf.BaseType := currf.BaseType - 128; end else fe := False; try New(Curr); except CMD_Err(erOutOfMemory); LoadTypes := False; exit; end; case currf.BaseType of {$IFNDEF NOINT64}bts64, {$ENDIF} btU8, btS8, btU16, btS16, btU32, btS32, btProcPtr,btSingle, btDouble, btExtended, btString, btPointer, btPChar, btResourcePointer, btVariant, btChar{$IFNDEF NOWIDESTRING}, btWideString, btWideChar{$ENDIF}: begin Curr^.BaseType := currf.BaseType; Curr^.Ext := nil; FTypes.Add(Curr); end; btArray: begin if not read(d, 4) then begin // Read type cmd_err(erUnexpectedEof); LoadTypes := False; exit; end; if (d >= FTypes.Count) then begin cmd_err(erTypeMismatch); LoadTypes := False; exit; end; Curr^.BaseType := currf.BaseType; Curr^.Ext := Pointer(d); FTypes.Add(Curr); end; btRecord: begin if not read(d, 4) or (d = 0) then begin cmd_err(erUnexpectedEof); LoadTypes := false; exit; end; try New(currr); except cmd_err(erOutOfMemory); LoadTypes := False; exit; end; SetLength(currr^.Data, d * 4); if not read(currr^.Data[1], d * 4) then begin currr^.Data := ''; Dispose(currr); cmd_err(erUnexpectedEof); LoadTypes := False; exit; end; if not resolve(currr^.Data) then begin currr^.Data := ''; Dispose(currr); cmd_err(erInvalidType); LoadTypes := False; exit; end; Curr^.BaseType := currf.BaseType; Curr^.Ext := currr; FTypes.Add(Curr); end; else begin LoadTypes := False; CMD_Err(erInvalidType); Dispose(Curr); exit; end; end; if fe then begin if not read(d, 4) then begin cmd_err(erUnexpectedEof); LoadTypes := False; exit; end; if d > IFPSAddrNegativeStackStart then begin cmd_err(erInvalidType); LoadTypes := False; exit; end; SetLength(Curr^.ExportName, d); if not read(Curr^.ExportName[1], d) then begin cmd_err(erUnexpectedEof); LoadTypes := False; exit; end; Curr^.ExportNameHash := MakeHash(Curr^.ExportName); end; end; end; function LoadProcs: Boolean; var Rec: TIFPSProc; n: string; b: Byte; l, L2, L3: Longint; Curr: PIFProcRec; begin LoadProcs := True; for l := 0 to HDR.ProcCount - 1 do begin if not read(Rec, SizeOf(Rec)) then begin cmd_err(erUnexpectedEof); LoadProcs := False; exit; end; try New(Curr); except cmd_err(erOutOfMemory); LoadProcs := False; exit; end; Curr^.ExternalProc := (Rec.Flags and 1) <> 0; if Curr^.ExternalProc then begin if not read(b, 1) then begin Dispose(Curr); cmd_err(erUnexpectedEof); LoadProcs := False; exit; end; SetLength(n, b); if not read(n[1], b) then begin Dispose(Curr); cmd_err(erUnexpectedEof); LoadProcs := False; exit; end; Curr^.Name := n; if (Rec.Flags and 3 = 3) then begin if (not Read(L2, 4)) or (L2 > Length(s) - Pos) then begin Dispose(Curr); cmd_err(erUnexpectedEof); LoadProcs := False; exit; end; SetLength(n, L2); Read(n[1], L2); // no check is needed Curr^.ExportDecl := n; end; if not ImportProc(Curr^.Name, Curr^) then begin if Curr^.Name <> '' then CMD_Err2(erCannotImport, Curr^.Name) else if Curr^.ExportDecl <> '' then CMD_Err2(erCannotImport, curr^.ExportDecl) else CMD_Err2(erCannotImport, curr^.ExportName); Dispose(Curr); LoadProcs := False; exit; end; end else begin if not read(L2, 4) then begin Dispose(Curr); cmd_err(erUnexpectedEof); LoadProcs := False; exit; end; if not read(L3, 4) then begin Dispose(Curr); cmd_err(erUnexpectedEof); LoadProcs := False; exit; end; if (L2 < 0) or (L2 >= Length(s)) or (L2 + L3 > Length(s)) or (L3 = 0) then begin Dispose(Curr); cmd_err(erUnexpectedEof); LoadProcs := False; exit; end; GetMem(Curr^.Data, L3); Move(s[L2 + 1], Curr^.Data^, L3); Curr^.Length := L3; if (Rec.Flags and 2) <> 0 then begin // exported if not read(L3, 4) then begin Dispose(Curr); cmd_err(erUnexpectedEof); LoadProcs := False; exit; end; if L3 > IFPSAddrNegativeStackStart then begin Dispose(Curr); cmd_err(erUnexpectedEof); LoadProcs := False; exit; end; SetLength(Curr^.ExportName, L3); if not read(Curr^.ExportName[1], L3) then begin Dispose(Curr); cmd_err(erUnexpectedEof); LoadProcs := False; exit; end; if not read(L3, 4) then begin Dispose(Curr); cmd_err(erUnexpectedEof); LoadProcs := False; exit; end; if L3 > IFPSAddrNegativeStackStart then begin Dispose(Curr); cmd_err(erUnexpectedEof); LoadProcs := False; exit; end; SetLength(Curr^.ExportDecl, L3); if not read(Curr^.ExportDecl[1], L3) then begin Dispose(Curr); cmd_err(erUnexpectedEof); LoadProcs := False; exit; end; Curr^.ExportNameHash := MakeHash(Curr^.ExportName); end; end; FProcs.Add(Curr); end; end; {$WARNINGS ON} function LoadVars: Boolean; var l, n: Longint; e: PIFPSExportedVar; Rec: TIFPSVar; Curr: PIfVariant; begin LoadVars := True; for l := 0 to HDR.VarCount - 1 do begin if not read(Rec, SizeOf(Rec)) then begin cmd_err(erUnexpectedEof); LoadVars := False; exit; end; if Rec.TypeNo >= HDR.TypeCount then begin cmd_err(erInvalidType); LoadVars := False; exit; end; Curr := CreateVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}FTypes.GetItem(Rec.TypeNo)); if Curr = nil then begin cmd_err(erInvalidType); LoadVars := False; exit; end; if (Rec.Flags and 1) <> 0then begin if not read(n, 4) then begin cmd_err(erUnexpectedEof); LoadVars := False; exit; end; new(e); try SetLength(e^.FName, n); if not Read(e^.FName[1], n) then begin dispose(e); cmd_err(erUnexpectedEof); LoadVars := False; exit; end; e^.FNameHash := MakeHash(e^.FName); e^.FVarNo := FGlobalVars.Count; FExportedVars.Add(E); except dispose(e); cmd_err(erInvalidType); LoadVars := False; exit; end; end; FGlobalVars.Add(Curr); end; end; begin Clear; Pos := 0; LoadData := False; if not read(HDR, SizeOf(HDR)) then begin CMD_Err(erInvalidHeader); exit; end; if HDR.HDR <> IFPSValidHeader then begin CMD_Err(erInvalidHeader); exit; end; if (HDR.IFPSBuildNo > IFPSCurrentBuildNo) or (HDR.IFPSBuildNo < IFPSLowBuildSupport) then begin CMD_Err(erInvalidHeader); exit; end; if not LoadTypes then begin Clear; exit; end; if not LoadProcs then begin Clear; exit; end; if not LoadVars then begin Clear; exit; end; if (HDR.MainProcNo >= FProcs.Count) and (HDR.MainProcNo <> Cardinal(-1))then begin CMD_Err(erNoMainProc); Clear; exit; end; // Load Import Table FMainProc := HDR.MainProcNo; FStatus := isLoaded; Result := True; end; procedure TIFPSExec.Pause; begin if FStatus = isRunning then FStatus := isPaused; end; function TIFPSExec.ReadData(var Data; Len: Cardinal): Boolean; begin if FCurrentPosition + Len <= FCurrProc.Length then begin Move(FCurrProc.Data^[FCurrentPosition], Data, Len); FCurrentPosition := FCurrentPosition + Len; Result := True; end else Result := False; end; procedure TIFPSExec.CMD_Err(EC: TIFError); // Error begin CMD_Err2(ec, ''); end; function TIFPSExec.BuildArray(Dest, Src: PIFVariant): boolean; var i, j: Longint; t: pbtrecord; begin if (Src^.FType^.BaseType = btVariant) and (Src^.TVariant^.FType <> nil) and (Src^.TVariant^.FType^.BaseType = btArray) then Src := Src^.TVariant; if (Src^.FType^.BaseType <> btArray) and (Src^.FType^.BaseType <> btRecord) then begin Result := False; exit; end; if Dest^.TArray <> nil then begin for i := 0 to pbtrecord(Dest^.Tarray)^.FieldCount -1 do begin DisposeVariant({$IFNDEF NOSMARTMM}MM ,{$ENDIF}pbtrecord(Dest^.Tarray)^.fields[i]); end; FreeMem(pbtrecord(Dest^.Tarray), pbtrecord(Dest^.Tarray)^.FieldCount * 4 + 4); end; if src^.TArray = nil then begin Dest^.TArray := nil; Result := true; exit; end; try getmem(t, pbtRecord(src^.Tarray)^.FieldCount * 4 +4); t.FieldCount := pbtRecord(src^.Tarray)^.FieldCount; except Dest^.TArray := nil; Result := False; exit; end; for i := pbtRecord(src^.Tarray)^.FieldCount -1 downto 0 do begin t^.Fields[i] := CreateVariant({$IFNDEF NOSMARTMM}mm, {$ENDIF} pbtRecord(src^.Tarray)^.Fields[i]^.FType); if t^.Fields[i] = nil then begin Freemem(t, t^.FieldCount * 4 + 4); for j := 0 to i -1 do begin DisposeVariant({$IFNDEF NOSMARTMM}mm, {$ENDIF} t^.Fields[j]); end; Dest^.TArray := nil; Result := False; exit; end; if not SetVariantValue(t^.Fields[i], pbtRecord(src^.Tarray)^.Fields[i]) then begin for j := pbtRecord(src^.Tarray)^.FieldCount -1 downto i do begin DisposeVariant({$IFNDEF NOSMARTMM}mm, {$ENDIF} t^.Fields[j]); end; Freemem(t, t^.FieldCount * 4 + 4); Dest^.TArray := nil; Result := False; exit; end; end; dest^.TArray := t; Result := True; end; function TIFPSExec.SetVariantValue(dest, Src: PIfVariant): Boolean; begin Result := True; case dest^.FType^.BaseType of btU8: dest^.tu8 := GetUInt(Src, Result); btS8: dest^.tS8 := GetInt(Src, Result); btU16: dest^.tu16 := GetUInt(Src, Result); btS16: dest^.ts16 := GetInt(Src, Result); btU32, btProcPtr: dest^.tu32 := GetUInt(Src, Result); btS32: dest^.ts32 := GetInt(Src, Result); {$IFNDEF NOINT64} btS64: dest^.ts64 := GetInt64(Src, Result); {$ENDIF} btSingle: dest^.tsingle := GetReal(Src, Result); btDouble: dest^.tdouble := GetReal(Src, Result); btExtended: dest^.textended := GetReal(Src, Result); btPChar,btString: TbtString((@dest^.tstring)^) := GetString(Src, Result); btChar: dest^.tchar := chr(GetUInt(Src, Result)); {$IFNDEF NOWIDESTRING} btWideChar: dest^.twidechar := widechar(GetUInt(Src, Result)); btWideString: tbtWideString(dest^.twidestring) := GetWideString(Src, Result); {$ENDIF} btArray, btRecord: Result := BuildArray(Dest, Src); btVariant: begin if Src^.FType^.BaseType = btVariant then ChangeVariantType({$IFNDEF NOSMARTMM}mm, {$ENDIF}Dest^.tVariant, src^.TVariant^.FType) else ChangeVariantType({$IFNDEF NOSMARTMM}mm, {$ENDIF}Dest^.tVariant, src^.FType); if Dest^.tvariant = nil then begin Result := False; end else begin if Dest^.TVariant^.FType <> nil then begin if Src^.FType^.BaseType = btVariant then Result := SetVariantValue(Dest^.TVariant, Src^.tvariant) else Result := SetVariantValue(Dest^.TVariant, Src); end; end; end; btResourcePointer: begin if src^.Ftype^.BaseType = btvariant then begin Src := src^.tvariant; if src^.FType = nil then begin Result := False; exit; end; end; if (Src^.FType^.BaseType <> btResourcePointer) or (Dest^.FType^.BaseType <> btResourcePointer) then begin Result := False; exit; end; if @Dest^.tResourceFreeProc <> nil then begin Dest^.tResourceFreeProc(vrfFree, dest, nil); end; if @Src^.tResourceFreeProc <> nil then begin Result := Src^.tResourceFreeProc(vrfDuplicate, Src, Dest); end else begin Dest^.TResourceFreeProc := nil; Dest^.TResourceP1 := nil; Dest^.TResourceP2 := nil; end; end; else begin Result := False; end; end; if Result = False then CMD_Err(ErTypeMismatch); end; function TIFPSExec.DoBooleanCalc(var1, Var2: PIfVariant; Into: PIfVariant; Cmd: Cardinal): Boolean; var b: Boolean; procedure SetBoolean(b: Boolean; var Ok: Boolean); begin Ok := True; case Into^.FType^.BaseType of btU8: Into^.tu8 := Cardinal(b); btS8: Into^.tS8 := Longint(b); btU16: Into^.tu16 := Cardinal(b); btS16: Into^.ts16 := Longint(b); btU32: Into^.tu32 := Cardinal(b); btS32: Into^.ts32 := Longint(b); else begin CMD_Err(ErTypeMismatch); Ok := False; end; end; end; begin Result := True; if (var1^.FType = nil) and (var1^.FType = nil) then {variants} begin case Cmd of 0,1,2,3: Result := False; 4: SetBoolean(False, Result); { <> } 5: SetBoolean(True, Result); { = } else begin Result := False; CMD_Err(erInvalidOpcodeParameter); exit; end; end; if not Result then begin CMD_Err(erTypeMismatch); exit; end; end else if (var1^.FType = nil) xor (var2^.FType = nil) then {variants} begin case Cmd of 0,1,2,3: Result := False; 4: SetBoolean(True, Result); { <> } 5: SetBoolean(False, Result); { = } else begin Result := False; CMD_Err(erInvalidOpcodeParameter); exit; end; end; if not Result then begin CMD_Err(erTypeMismatch); exit; end; end else case Cmd of 0: begin { >= } case var1^.FType^.BaseType of btU8: if (var2^.FType^.BaseType = btString) or (Var2^.Ftype^.BaseType = btPChar) then b := char(var1^.tu8) >= GetString(Var2, Result) else b := var1^.tu8 >= GetUInt(Var2, Result); btS8: b := var1^.tS8 >= GetInt(Var2, Result); btU16: b := var1^.tu16 >= GetUInt(Var2, Result); btS16: b := var1^.ts16 >= GetInt(Var2, Result); btU32, btProcPtr: b := var1^.tu32 >= GetUInt(Var2, Result); btS32: b := var1^.ts32 >= GetInt(Var2, Result); btSingle: b := var1^.tsingle >= GetReal(Var2, Result); btDouble: b := var1^.tdouble >= GetReal(Var2, Result); btExtended: b := var1^.textended >= GetReal(Var2, Result); {$IFNDEF NOINT64} btS64: b := var1^.ts64 >= GetInt64(Var2, Result); {$ENDIF} btPChar,btString: b := tbtstring(var1^.tstring) >= GetString(Var2, Result); btChar: b := Var1^.tchar >= GetString(Var2, Result); {$IFNDEF NOWIDESTRING} btWideChar: b := Var1^.twidechar >= GetWideString(Var2, Result); btWideString: b := tbtwidestring(Var1^.twidestring) >= GetWideString(Var2, Result); {$ENDIF} else begin CMD_Err(ErTypeMismatch); exit; end; end; if not Result then begin CMD_Err(ErTypeMismatch); exit; end; SetBoolean(b, Result); end; 1: begin { <= } case var1^.FType^.BaseType of btU8: if (var2^.FType^.BaseType = btString) or (Var2^.Ftype^.BaseType = btPChar) then b := char(var1^.tu8) <= GetString(Var2, Result) else b := var1^.tu8 <= GetUInt(Var2, Result); btS8: b := var1^.tS8 <= GetInt(Var2, Result); btU16: b := var1^.tu16 <= GetUInt(Var2, Result); btS16: b := var1^.ts16 <= GetInt(Var2, Result); btU32, btProcPtr: b := var1^.tu32 <= GetUInt(Var2, Result); btS32: b := var1^.ts32 <= GetInt(Var2, Result); btSingle: b := var1^.tsingle <= GetReal(Var2, Result); btDouble: b := var1^.tdouble <= GetReal(Var2, Result); btExtended: b := var1^.textended <= GetReal(Var2, Result); {$IFNDEF NOINT64} btS64: b := var1^.ts64 <= GetInt64(Var2, Result); {$ENDIF} btPChar,btString: b := tbtstring(var1^.tstring) <= GetString(Var2, Result); btChar: b := Var1^.tchar <= GetString(Var2, Result); {$IFNDEF NOWIDESTRING} btWideChar: b := Var1^.twidechar <= GetWideString(Var2, Result); btWideString: b := tbtwidestring(Var1^.twidestring) <= GetWideString(Var2, Result); {$ENDIF} else begin CMD_Err(ErTypeMismatch); exit; end; end; if not Result then begin CMD_Err(erTypeMismatch); exit; end; SetBoolean(b, Result); end; 2: begin { > } case var1^.FType^.BaseType of btU8: if (var2^.FType^.BaseType = btString) or (Var2^.Ftype^.BaseType = btPChar) then b := char(var1^.tu8) > GetString(Var2, Result) else b := var1^.tu8 > GetUInt(Var2, Result); btS8: b := var1^.tS8 > GetInt(Var2, Result); btU16: b := var1^.tu16 > GetUInt(Var2, Result); btS16: b := var1^.ts16 > GetInt(Var2, Result); btU32, btProcPtr: b := var1^.tu32 > GetUInt(Var2, Result); btS32: b := var1^.ts32 > GetInt(Var2, Result); btSingle: b := var1^.tsingle > GetReal(Var2, Result); btDouble: b := var1^.tdouble > GetReal(Var2, Result); btExtended: b := var1^.textended > GetReal(Var2, Result); {$IFNDEF NOINT64} btS64: b := var1^.ts64 > GetInt64(Var2, Result); {$ENDIF} btPChar,btString: b := tbtstring(var1^.tstring) > GetString(Var2, Result); btChar: b := Var1^.tchar > GetString(Var2, Result); {$IFNDEF NOWIDESTRING} btWideChar: b := Var1^.twidechar > GetWideString(Var2, Result); btWideString: b := tbtwidestring(Var1^.twidestring) > GetWideString(Var2, Result); {$ENDIF} else begin CMD_Err(erTypeMismatch); exit; end; end; if not Result then begin CMD_Err(erTypeMismatch); exit; end; SetBoolean(b, Result); end; 3: begin { < } case var1^.FType^.BaseType of btU8: if (var2^.FType^.BaseType = btString) or (Var2^.Ftype^.BaseType = btPChar) then b := char(var1^.tu8) < GetString(Var2, Result) else b := var1^.tu8 < GetUInt(Var2, Result); btS8: b := var1^.tS8 < GetInt(Var2, Result); btU16: b := var1^.tu16 < GetUInt(Var2, Result); btS16: b := var1^.ts16 < GetInt(Var2, Result); btU32, btProcPtr: b := var1^.tu32 < GetUInt(Var2, Result); btS32: b := var1^.ts32 < GetInt(Var2, Result); btSingle: b := var1^.tsingle < GetReal(Var2, Result); btDouble: b := var1^.tdouble < GetReal(Var2, Result); btExtended: b := var1^.textended < GetReal(Var2, Result); {$IFNDEF NOINT64} btS64: b := var1^.ts64 < GetInt64(Var2, Result); {$ENDIF} btPChar,btString: b := tbtstring(var1^.tstring) < GetString(Var2, Result); btChar: b := Var1^.tchar < GetString(Var2, Result); {$IFNDEF NOWIDESTRING} btWideChar: b := Var1^.twidechar < GetWideString(Var2, Result); btWideString: b := tbtwidestring(Var1^.twidestring) < GetWideString(Var2, Result); {$ENDIF} else begin CMD_Err(erTypeMismatch); exit; end; end; if not Result then begin CMD_Err(erTypeMismatch); exit; end; SetBoolean(b, Result); end; 4: begin { <> } case var1^.FType^.BaseType of btU8: if (var2^.FType^.BaseType = btString) or (Var2^.Ftype^.BaseType = btPChar) then b := char(var1^.tu8) <> GetString(Var2, Result) else b := var1^.tu8 <> GetUInt(Var2, Result); btS8: b := var1^.tS8 <> GetInt(Var2, Result); btU16: b := var1^.tu16 <> GetUInt(Var2, Result); btS16: b := var1^.ts16 <> GetInt(Var2, Result); btU32, btProcPtr: b := var1^.tu32 <> GetUInt(Var2, Result); btS32: b := var1^.ts32 <> GetInt(Var2, Result); btSingle: b := var1^.tsingle <> GetReal(Var2, Result); btDouble: b := var1^.tdouble <> GetReal(Var2, Result); btExtended: b := var1^.textended <> GetReal(Var2, Result); btPChar,btString: b := TbtString(var1^.tstring) <> GetString(Var2, Result); {$IFNDEF NOINT64} btS64: b := var1^.ts64 <> GetInt64(Var2, Result); {$ENDIF} btChar: b := Var1^.tchar <> GetString(Var2, Result); {$IFNDEF NOWIDESTRING} btWideChar: b := Var1^.twidechar <> GetWideString(Var2, Result); btWideString: b := tbtwidestring(Var1^.twidestring) <> GetWideString(Var2, Result); {$ENDIF} else begin CMD_Err(erTypeMismatch); exit; end; end; if not Result then begin CMD_Err(erTypeMismatch); exit; end; SetBoolean(b, Result); end; 5: begin { = } case var1^.FType^.BaseType of btU8: if (var2^.FType^.BaseType = btString) or (Var2^.Ftype^.BaseType = btPChar) then b := char(var1^.tu8) = GetString(Var2, Result) else b := var1^.tu8 = GetUInt(Var2, Result); btS8: b := var1^.tS8 = GetInt(Var2, Result); btU16: b := var1^.tu16 = GetUInt(Var2, Result); btS16: b := var1^.ts16 = GetInt(Var2, Result); btU32, btProcPtr: b := var1^.tu32 = GetUInt(Var2, Result); btS32: b := var1^.ts32 = GetInt(Var2, Result); btSingle: b := var1^.tsingle = GetReal(Var2, Result); btDouble: b := var1^.tdouble = GetReal(Var2, Result); btExtended: b := var1^.textended = GetReal(Var2, Result); btPchar, btString: b := TbtString(var1^.tstring) = GetString(Var2, Result); {$IFNDEF NOINT64} btS64: b := var1^.ts64 = GetInt64(Var2, Result); {$ENDIF} btChar: b := Var1^.tchar = GetString(Var2, Result); {$IFNDEF NOWIDESTRING} btWideChar: b := Var1^.twidechar = GetWideString(Var2, Result); btWideString: b := tbtwidestring(Var1^.twidestring) = GetWideString(Var2, Result); {$ENDIF} else begin CMD_Err(erTypeMismatch); exit; end; end; if not Result then begin CMD_Err(erTypeMismatch); exit; end; SetBoolean(b, Result); end; else begin Result := False; CMD_Err(erInvalidOpcodeParameter); exit; end; end; end; function TIFPSExec.DoCalc(var1, Var2: PIfVariant; CalcType: Cardinal): Boolean; { var1=dest, var2=src } begin try Result := True; case CalcType of 0: begin { + } case var1^.FType^.BaseType of btU8: var1^.tu8 := var1^.tu8 + GetUInt(Var2, Result); btS8: var1^.tS8 := var1^.tS8 + GetInt(Var2, Result); btU16: var1^.tu16 := var1^.tu16 + GetUInt(Var2, Result); btS16: var1^.ts16 := var1^.ts16 + GetInt(Var2, Result); btU32: var1^.tu32 := var1^.tu32 + GetUInt(Var2, Result); btS32: var1^.ts32 := var1^.ts32 + GetInt(Var2, Result); {$IFNDEF NOINT64} btS64: var1^.ts64 := var1^.ts64 + GetInt64(var2, Result); {$ENDIF} btSingle: var1^.tsingle := var1^.tsingle + GetReal(Var2, Result); btDouble: var1^.tdouble := var1^.tdouble + GetReal(Var2, Result); btExtended: var1^.textended := var1^.textended + GetReal(Var2, Result); btPchar, btString: TbtString((@var1^.tstring)^) := TbtString((@var1^.tstring)^) + GetString(Var2, Result); btChar: Var1^.tchar := char(ord(Var1^.tchar) + GetUInt(Var2, Result)); {$IFNDEF NOWIDESTRING} btWideChar: var1^.twidechar := widechar(ord(var1^.twidechar) + GetUInt(Var2, Result)); btWideString: tbtwidestring(var1^.twidestring) := tbtwidestring(var1^.twidestring) + GetWideString(Var2, Result); {$ENDIF} else begin CMD_Err(erTypeMismatch); exit; end; end; if not Result then begin CMD_Err(erTypeMismatch); exit; end; end; 1: begin { - } case var1^.FType^.BaseType of btU8: var1^.tu8 := var1^.tu8 - GetUInt(Var2, Result); btS8: var1^.tS8 := var1^.tS8 - GetInt(Var2, Result); btU16: var1^.tu16 := var1^.tu16 - GetUInt(Var2, Result); btS16: var1^.ts16 := var1^.ts16 - GetInt(Var2, Result); btU32: var1^.tu32 := var1^.tu32 - GetUInt(Var2, Result); btS32: var1^.ts32 := var1^.ts32 - GetInt(Var2, Result); {$IFNDEF NOINT64} btS64: var1^.ts64 := var1^.ts64 - GetInt64(var2, Result); {$ENDIF} btSingle: var1^.tsingle := var1^.tsingle - GetReal(Var2, Result); btDouble: var1^.tdouble := var1^.tdouble - GetReal(Var2, Result); btExtended: var1^.textended := var1^.textended - GetReal(Var2, Result); btChar: Var1^.tchar := char(ord(Var1^.tchar) - GetUInt(Var2, Result)); {$IFNDEF NOWIDESTRING} btWideChar: Var1^.twidechar := widechar(ord(Var1^.twidechar) - GetUInt(Var2, Result)); {$ENDIF} else begin CMD_Err(erTypeMismatch); exit; end; end; if not Result then begin CMD_Err(erTypeMismatch); exit; end; end; 2: begin { * } case var1^.FType^.BaseType of btU8: var1^.tu8 := var1^.tu8 * GetUInt(Var2, Result); btS8: var1^.tS8 := var1^.tS8 * GetInt(Var2, Result); btU16: var1^.tu16 := var1^.tu16 * GetUInt(Var2, Result); btS16: var1^.ts16 := var1^.ts16 * GetInt(Var2, Result); btU32: var1^.tu32 := var1^.tu32 * GetUInt(Var2, Result); btS32: var1^.ts32 := var1^.ts32 * GetInt(Var2, Result); {$IFNDEF NOINT64} btS64: var1^.ts64 := var1^.ts64 * GetInt64(var2, Result); {$ENDIF} btSingle: var1^.tsingle := var1^.tsingle * GetReal(Var2, Result); btDouble: var1^.tdouble := var1^.tdouble * GetReal(Var2, Result); btExtended: var1^.textended := var1^.textended * GetReal(Var2, Result); else begin CMD_Err(erTypeMismatch); exit; end; end; if not Result then begin CMD_Err(erTypeMismatch); exit; end; end; 3: begin { / } case var1^.FType^.BaseType of btU8: var1^.tu8 := var1^.tu8 div GetUInt(Var2, Result); btS8: var1^.tS8 := var1^.tS8 div GetInt(Var2, Result); btU16: var1^.tu16 := var1^.tu16 div GetUInt(Var2, Result); btS16: var1^.ts16 := var1^.ts16 div GetInt(Var2, Result); btU32: var1^.tu32 := var1^.tu32 div GetUInt(Var2, Result); btS32: var1^.ts32 := var1^.ts32 div GetInt(Var2, Result); {$IFNDEF NOINT64} btS64: var1^.ts64 := var1^.ts64 div GetInt64(var2, Result); {$ENDIF} btSingle: var1^.tsingle := var1^.tsingle / GetReal(Var2, Result); btDouble: var1^.tdouble := var1^.tdouble / GetReal(Var2, Result); btExtended: var1^.textended := var1^.textended / GetReal(Var2, Result); else begin CMD_Err(erTypeMismatch); exit; end; end; if not Result then begin CMD_Err(erTypeMismatch); exit; end; end; 4: begin { MOD } case var1^.FType^.BaseType of btU8: var1^.tu8 := var1^.tu8 mod GetUInt(Var2, Result); btS8: var1^.tS8 := var1^.tS8 mod GetInt(Var2, Result); btU16: var1^.tu16 := var1^.tu16 mod GetUInt(Var2, Result); btS16: var1^.ts16 := var1^.ts16 mod GetInt(Var2, Result); btU32: var1^.tu32 := var1^.tu32 mod GetUInt(Var2, Result); btS32: var1^.ts32 := var1^.ts32 mod GetInt(Var2, Result); {$IFNDEF NOINT64} btS64: var1^.ts64 := var1^.ts64 mod GetInt64(var2, Result); {$ENDIF} else begin CMD_Err(erTypeMismatch); exit; end; end; if not Result then begin CMD_Err(erTypeMismatch); exit; end; end; 5: begin { SHL } case var1^.FType^.BaseType of btU8: var1^.tu8 := var1^.tu8 shl GetUInt(Var2, Result); btS8: var1^.tS8 := var1^.tS8 shl GetInt(Var2, Result); btU16: var1^.tu16 := var1^.tu16 shl GetUInt(Var2, Result); btS16: var1^.ts16 := var1^.ts16 shl GetInt(Var2, Result); btU32: var1^.tu32 := var1^.tu32 shl GetUInt(Var2, Result); btS32: var1^.ts32 := var1^.ts32 shl GetInt(Var2, Result); {$IFNDEF NOINT64} btS64: var1^.ts64 := var1^.ts64 shl GetInt64(var2, Result); {$ENDIF} else begin CMD_Err(erTypeMismatch); exit; end; end; if not Result then begin CMD_Err(erTypeMismatch); exit; end; end; 6: begin { SHR } case var1^.FType^.BaseType of btU8: var1^.tu8 := var1^.tu8 shr GetUInt(Var2, Result); btS8: var1^.tS8 := var1^.tS8 shr GetInt(Var2, Result); btU16: var1^.tu16 := var1^.tu16 shr GetUInt(Var2, Result); btS16: var1^.ts16 := var1^.ts16 shr GetInt(Var2, Result); btU32: var1^.tu32 := var1^.tu32 shr GetUInt(Var2, Result); btS32: var1^.ts32 := var1^.ts32 shr GetInt(Var2, Result); {$IFNDEF NOINT64} btS64: var1^.ts64 := var1^.ts64 shr GetInt64(var2, Result); {$ENDIF} else begin CMD_Err(erTypeMismatch); exit; end; end; if not Result then begin CMD_Err(erTypeMismatch); exit; end; end; 7: begin { AND } case var1^.FType^.BaseType of btU8: var1^.tu8 := var1^.tu8 and GetUInt(Var2, Result); btS8: var1^.tS8 := var1^.tS8 and GetInt(Var2, Result); btU16: var1^.tu16 := var1^.tu16 and GetUInt(Var2, Result); btS16: var1^.ts16 := var1^.ts16 and GetInt(Var2, Result); btU32: var1^.tu32 := var1^.tu32 and GetUInt(Var2, Result); btS32: var1^.ts32 := var1^.ts32 and GetInt(Var2, Result); {$IFNDEF NOINT64} btS64: var1^.ts64 := var1^.ts64 and GetInt64(var2, Result); {$ENDIF} else begin CMD_Err(erTypeMismatch); exit; end; end; if not Result then begin CMD_Err(erTypeMismatch); exit; end; end; 8: begin { OR } case var1^.FType^.BaseType of btU8: var1^.tu8 := var1^.tu8 or GetUInt(Var2, Result); btS8: var1^.tS8 := var1^.tS8 or GetInt(Var2, Result); btU16: var1^.tu16 := var1^.tu16 or GetUInt(Var2, Result); btS16: var1^.ts16 := var1^.ts16 or GetInt(Var2, Result); btU32: var1^.tu32 := var1^.tu32 or GetUInt(Var2, Result); btS32: var1^.ts32 := var1^.ts32 or GetInt(Var2, Result); {$IFNDEF NOINT64} btS64: var1^.ts64 := var1^.ts64 or GetInt64(var2, Result); {$ENDIF} else begin CMD_Err(erTypeMismatch); exit; end; end; if not Result then begin CMD_Err(erTypeMismatch); exit; end; end; 9: begin { XOR } case var1^.FType^.BaseType of btU8: var1^.tu8 := var1^.tu8 xor GetUInt(Var2, Result); btS8: var1^.tS8 := var1^.tS8 xor GetInt(Var2, Result); btU16: var1^.tu16 := var1^.tu16 xor GetUInt(Var2, Result); btS16: var1^.ts16 := var1^.ts16 xor GetInt(Var2, Result); btU32: var1^.tu32 := var1^.tu32 xor GetUInt(Var2, Result); btS32: var1^.ts32 := var1^.ts32 xor GetInt(Var2, Result); {$IFNDEF NOINT64} btS64: var1^.ts64 := var1^.ts64 xor GetInt64(var2, Result); {$ENDIF} else begin CMD_Err(erTypeMismatch); exit; end; end; if not Result then begin CMD_Err(erTypeMismatch); exit; end; end; else begin Result := False; CMD_Err(erInvalidOpcodeParameter); exit; end; end; except on E: EDivByZero do begin Result := False; CMD_Err(erDivideByZero); Exit; end; on E: EZeroDivide do begin Result := False; CMD_Err(erDivideByZero); Exit; end; on E: EMathError do begin Result := False; CMD_Err(erMathError); Exit; end; on E: Exception do begin Result := False; CMD_Err2(erException, e.Message); exit; end; end; end; function TIFPSExec.ReadVariable(var NeedToFree: LongBool; UsePointer: LongBool): PIfVariant; var VarType: Cardinal; Param: Cardinal; Tmp: PIfVariant; begin if not (ReadByte(VarType) and ReadLong(Param)) then begin CMD_Err(erOutOfRange); Result := nil; exit; end; case VarType of 0: begin NeedToFree := False; if Param < IFPSAddrNegativeStackStart then begin Result := FGlobalVars.GetItem(Param); if Result = nil then begin CMD_Err(erOutOfGlobalVarsRange); exit; end; end else begin Result := FStack.GetItem(Cardinal(Longint(-IFPSAddrStackStart) + Longint(FCurrStackBase) + Longint(Param))); if Result = nil then begin CMD_Err(erOutOfStackRange); exit; end; end; if UsePointer then begin if Result^.FType^.BaseType = btPointer then begin Result := Result^.tPointer; if Result = nil then begin CMD_Err(erNullPointerException); exit; end; end; if Result^.FType^.BaseType = btVariant then begin Result := Result^.tvariant; if Result = nil then begin CMD_Err(erNullPointerException); exit; end; if Result^.FType = nil then begin Result := nil; CMD_Err(erNullVariantError); Exit; end; end; end; end; 1: begin NeedToFree := True; Result := CreateVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}FTypes.GetItem(Param)); if Result = nil then begin CMD_Err(erInvalidType); exit; end; case Result^.FType^.BaseType of bts8, btchar, btU8: if not ReadData(Result^.tu8, 1) then begin CMD_Err(erOutOfRange); DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Result); Result := nil; exit; end; bts16, {$IFNDEF NOWIDESTRING}btwidechar,{$ENDIF} btU16: if not ReadData((@Result^.tu16)^, SizeOf(TbtU16)) then begin CMD_Err(ErOutOfRange); DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Result); Result := nil; exit; end; bts32, btU32, btProcPtr: if not ReadLong(Result^.tu32) then begin CMD_Err(erOutOfRange); DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Result); Result := nil; exit; end; {$IFNDEF NOINT64} bts64: if not ReadData(Result^.ts64, sizeof(tbts64)) then begin CMD_Err(erOutOfRange); DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Result); Result := nil; exit; end; {$ENDIF} btSingle: if not ReadData((@Result^.tsingle)^, SizeOf(TbtSingle)) then begin CMD_Err(erOutOfRange); DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Result); Result := nil; exit; end; btDouble: if not ReadData((@Result^.tdouble)^, SizeOf(TbtDouble)) then begin CMD_Err(erOutOfRange); DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Result); Result := nil; exit; end; btExtended: if not ReadData((@Result^.textended)^, SizeOf(TbtExtended)) then begin CMD_Err(erOutOfRange); DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Result); Result := nil; exit; end; btPchar, btString: begin if not ReadLong(Param) then begin CMD_Err(erOutOfRange); DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Result); Result := nil; exit; end; SetLength(TbtString((@Result^.tstring)^), Param); if not ReadData(TbtString((@Result^.tstring)^)[1], Param) then begin CMD_Err(erOutOfRange); DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Result); Result := nil; exit; end; end; {$IFNDEF NOWIDESTRING} btWidestring: begin if not ReadLong(Param) then begin CMD_Err(erOutOfRange); DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Result); Result := nil; exit; end; SetLength(TbtwideString(Result^.twidestring), Param); if not ReadData(TbtwideString(Result^.twidestring)[1], Param*2) then begin CMD_Err(erOutOfRange); DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Result); Result := nil; exit; end; end; {$ENDIF} else begin CMD_Err(erInvalidType); DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Result); Result := nil; exit; end; end; end; 2: begin NeedToFree := False; if Param < IFPSAddrNegativeStackStart then begin Result := FGlobalVars.GetItem(Param); if Result = nil then begin CMD_Err(erOutOfGlobalVarsRange); exit; end; end else begin Result := FStack.GetItem(Cardinal(Longint(-IFPSAddrStackStart) + Longint(FCurrStackBase) + Longint(Param))); if Result = nil then begin CMD_Err(erOutOfStackRange); exit; end; end; if (Result^.FType^.BaseType = btPointer) then begin Result := Result^.tPointer; if Result = nil then begin CMD_Err(erNullPointerException); exit; end; end; if Result^.FType^.BaseType = btVariant then begin Result := Result^.tvariant; if Result = nil then begin CMD_Err(erNullPointerException); exit; end; if Result^.FType = nil then begin Result := nil; CMD_Err(erNullVariantError); Exit; end; end; if (Result^.FType^.BaseType <> btRecord) and (Result^.FType^.BaseType <> btArray) then begin CMD_Err(erInvalidType); Result := nil; exit; end; if not ReadLong(Param) then begin CMD_Err(erOutOfRange); Result := nil; exit; end; if (Result^.trecord = nil) or (Param >= pbtrecord(Result^.trecord)^.FieldCount) then begin CMD_Err(erOutofRecordRange); Result := nil; exit; end; Result := pbtrecord(Result^.trecord)^.Fields[Param]; if UsePointer then begin if Result^.FType^.BaseType = btPointer then begin Result := Result^.tPointer; if Result = nil then begin CMD_Err(erNullPointerException); exit; end; end; if Result^.FType^.BaseType = btVariant then begin Result := Result^.tvariant; if Result = nil then begin CMD_Err(erNullPointerException); exit; end; if Result^.FType = nil then begin Result := nil; CMD_Err(erNullVariantError); Exit; end; end; end; end; 3: begin NeedToFree := False; if Param < IFPSAddrNegativeStackStart then begin Result := FGlobalVars.GetItem(Param); if Result = nil then begin CMD_Err(erOutOfGlobalVarsRange); exit; end; end else begin Result := FStack.GetItem(Cardinal(Longint(-IFPSAddrStackStart) + Longint(FCurrStackBase) + Longint(Param))); if Result = nil then begin CMD_Err(erOutOfStackRange); exit; end; end; if (Result^.FType^.BaseType = btPointer) then begin Result := Result^.tPointer; if Result = nil then begin CMD_Err(erNullPointerException); exit; end; end; if Result^.FType^.BaseType = btVariant then begin Result := Result^.tvariant; if Result = nil then begin CMD_Err(erNullPointerException); exit; end; if Result^.FType = nil then begin Result := nil; CMD_Err(erNullVariantError); Exit; end; end; if (Result^.FType^.BaseType <> btRecord) and (Result^.FType^.BaseType <> btArray) then begin CMD_Err(erInvalidType); Result := nil; exit; end; if not ReadLong(Param) then begin CMD_Err(erOutOfRange); Result := nil; exit; end; if Param < IFPSAddrNegativeStackStart then begin Tmp := FGlobalVars.GetItem(Param); if Tmp = nil then begin CMD_Err(erOutOfGlobalVarsRange); exit; end; end else begin Tmp := FStack.GetItem(Cardinal(Longint(-IFPSAddrStackStart) + Longint(FCurrStackBase) + Longint(Param))); if Tmp = nil then begin CMD_Err(erOutOfStackRange); exit; end; end; case Tmp^.FType^.BaseType of btu8: Param := Tmp^.tu8; bts8: Param := Tmp^.ts8; btu16: Param := Tmp^.tu16; bts16: Param := Tmp^.ts16; btu32, btProcPtr: Param := Tmp^.tu32; bts32: Param := Tmp^.ts32; else CMD_Err(ErTypeMismatch); exit; end; if (Result^.trecord = nil) or (Param >= pbtrecord(Result^.trecord)^.FieldCount) then begin CMD_Err(erOutofRecordRange); Result := nil; exit; end; Result := pbtrecord(Result^.trecord)^.Fields[Param]; if UsePointer then begin if Result^.FType^.BaseType = btPointer then begin Result := Result^.tPointer; if Result = nil then begin CMD_Err(erNullPointerException); exit; end; end; if Result^.FType^.BaseType = btVariant then begin if Result = nil then begin CMD_Err(erNullPointerException); exit; end; if Result^.FType = nil then begin Result := nil; CMD_Err(erNullVariantError); Exit; end; end; end; end; else Result := nil; end; end; procedure TIFPSExec.DoMinus(Vd: PIfVariant); begin case Vd^.FType^.BaseType of btU8: Vd^.tu8 := -Vd^.tu8; btU16: Vd^.tu16 := -Vd^.tu16; btU32: Vd^.tu32 := -Vd^.tu32; btS8: Vd^.tS8 := -Vd^.tS8; btS16: Vd^.ts16 := -Vd^.ts16; btS32: Vd^.ts32 := -Vd^.ts32; btSingle: Vd^.tsingle := - vd^.tsingle; btDouble: Vd^.tdouble := -vd^.tdouble; btExtended: Vd^.textended := -vd^.textended; else CMD_Err(erTypeMismatch); end; end; procedure TIFPSExec.DoBooleanNot(Vd: PIfVariant); begin case Vd^.FType^.BaseType of btU8: Vd^.tu8 := TbtU8(Vd^.tu8 = 0); btS8: Vd^.tS8 := TbtS8(Vd^.tS8 = 0); btU16: Vd^.tu16 := TbtU16(Vd^.tu16 = 0); btS16: Vd^.ts16 := TbtS16(Vd^.ts16 = 0); btU32: Vd^.tu32 := TbtU32(Vd^.tu32 = 0); btS32: Vd^.ts32 := TbtS32(Vd^.ts32 = 0); else CMD_Err(erTypeMismatch); end; end; function TIFPSExec.RunScript: Boolean; var CalcType: Cardinal; Vd, Vs, v3: PIfVariant; vdFree, vsFree: LongBool; p: Cardinal; P2: Longint; u: PIFProcRec; Cmd: Cardinal; I: Longint; pp: PIFPSExceptionHandler; FExitPoint: Cardinal; FOldStatus: TIFStatus; begin FExitPoint := Cardinal(-1); if FStatus = isLoaded then begin for i := FExceptionStack.Count -1 downto 0 do begin pp := FExceptionStack.GetItem(i); Dispose(pp); end; FExceptionStack.Clear; end; ExceptionProc(Cardinal(-1), Cardinal(-1), erNoError, ''); RunScript := True; FOldStatus := FStatus; case FStatus of isLoaded: begin if FMainProc = Cardinal(-1) then begin RunScript := False; exit; end; FStatus := isRunning; FCurrProc := FProcs.GetItem(FMainProc); if FCurrProc^.ExternalProc then begin CMD_Err(erNoMainProc); FStatus := isLoaded; exit; end; FCurrStackBase := Cardinal(-1); FCurrentPosition := 0; end; isPaused: begin FStatus := isRunning; end; else begin RunScript := False; exit; end; end; RunLine; repeat FStatus := isRunning; while FStatus = isRunning do begin if not ReadByte(Cmd) then CMD_Err(erOutOfRange) // Error else begin if Cmd = CM_CA then begin // Calc and assigning are needed most and have priority if not ReadByte(CalcType) then begin CMD_Err(erOutOfRange); break; end; Vd := ReadVariable(vdFree, True); if Vd = nil then break; if vdFree then begin DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Vd); CMD_Err(erInvalidOpcodeParameter); break; end; Vs := ReadVariable(vsFree, True); if Vs = nil then break; if not DoCalc(Vd, Vs, CalcType) then Break; if vsFree then DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Vs); end else if Cmd = CM_A then begin // Calc and assigning are needed most and have priority Vd := ReadVariable(vdFree, False); if Vd = nil then break; if vdFree then begin DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Vd); CMD_Err(erInvalidOpcodeParameter); break; end; if vd^.FType^.BaseType = btPointer then begin vd := vd^.tPointer; if vd = nil then begin CMD_Err(erNullPointerException); Break; end; end; Vs := ReadVariable(vsFree, False); if Vs = nil then break; if vs^.FType^.BaseType = btPointer then begin v3 := vs^.tPointer; if v3 = nil then begin if vsFree then begin DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Vs); end; CMD_Err(erNullPointerException); Break; end; vs := v3; end; if not SetVariantValue(Vd, Vs) then begin if vsFree then DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Vs); cmd_err(erTypeMismatch); Break; end; if vsFree then DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Vs); end else case Cmd of CM_P: begin Vs := ReadVariable(vsFree, True); if Vs = nil then break; if vsFree then begin FStack.Add(Vs); end else begin Vd := CreateVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Vs^.FType); SetVariantValue(Vd, Vs); FStack.Add(Vd); end; end; CM_PV: begin Vs := ReadVariable(vsFree, False); if vs^.FType^.BaseType = btPointer then begin vs := vs^.tPointer; if vs = nil then begin CMD_Err(erNullPointerException); break; end; end; if Vs = nil then break; if vsFree then begin DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Vs); CMD_Err(erInvalidOpcodeParameter); break; end else begin Inc(Vs^.RefCount); FStack.Add(Vs); end; end; CM_PO: begin if FStack.Count = 0 then begin CMD_Err(erOutOfStackRange); break; end; Vs := FStack.GetItem(FStack.Count - 1); FStack.Delete(FStack.Count - 1); DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Vs); end; Cm_C: begin if not ReadLong(p) then begin CMD_Err(erOutOfRange); break; end; if p >= FProcs.Count then begin CMD_Err(erOutOfProcRange); break; end; u := FProcs.GetItem(p); if u^.ExternalProc then begin if not u^.ProcPtr(Self, u, FGlobalVars, FStack) then begin if ExEx = erNoError then CMD_Err(erCouldNotCallProc); Break; end; end else begin Vd := CreateVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}@ReturnAddressType); Vd^.treturnaddress.ProcNo := FCurrProc; Vd^.treturnaddress.Position := FCurrentPosition; Vd^.treturnaddress.StackBase := FCurrStackBase; FStack.Add(Vd); FCurrStackBase := FStack.Count - 1; FCurrProc := u; FCurrentPosition := 0; end; end; Cm_G: begin if not ReadLong(p) then begin CMD_Err(erOutOfRange); break; end; FCurrentPosition := FCurrentPosition + p; end; Cm_CG: begin if not ReadLong(p) then begin CMD_Err(erOutOfRange); break; end; Vs := ReadVariable(vsFree, True); if Vs = nil then break; if vsFree then begin CMD_Err(erInvalidOpcodeParameter); break; end; case Vs^.FType^.BaseType of btU8: vdFree := Vs^.tu8 <> 0; btS8: vdFree := Vs^.tS8 <> 0; btU16: vdFree := Vs^.tu16 <> 0; btS16: vdFree := Vs^.ts16 <> 0; btU32, btProcPtr: vdFree := Vs^.tu32 <> 0; btS32: vdFree := Vs^.ts32 <> 0; else begin CMD_Err(erInvalidType); break; end; end; if vdFree then FCurrentPosition := FCurrentPosition + p; end; Cm_CNG: begin if not ReadLong(p) then begin CMD_Err(erOutOfRange); break; end; Vs := ReadVariable(vsFree, True); if Vs = nil then break; if vsFree then begin CMD_Err(erInvalidOpcodeParameter); break; end; case Vs^.FType^.BaseType of btU8: vdFree := Vs^.tu8 = 0; btS8: vdFree := Vs^.tS8 = 0; btU16: vdFree := Vs^.tu16 = 0; btS16: vdFree := Vs^.ts16 = 0; btU32, btProcPtr: vdFree := Vs^.tu32 = 0; btS32: vdFree := Vs^.ts32 = 0; else begin CMD_Err(erInvalidType); break; end; end; if vdFree then FCurrentPosition := FCurrentPosition + p; end; Cm_R: begin FExitPoint := FCurrentPosition -1; P2 := 0; if FExceptionStack.Count > 0 then begin pp := FExceptionStack.GetItem(FExceptionStack.Count -1); if (pp^.BasePtr = FCurrStackBase) or ((pp^.BasePtr > FCurrStackBase) and (pp^.BasePtr <> Cardinal(-1))) then begin if pp^.StackSize < FStack.Count then begin for p := Longint(FStack.count) -1 downto Longint(pp^.StackSize) do begin DisposeVariant({$IFNDEF NOSMARTMM}mm, {$ENDIF}FStack.GetItem(p)); FStack.Delete(p); end; end; FCurrStackBase := pp^.BasePtr; if pp^.FinallyOffset <> Cardinal(-1) then begin FCurrentPosition := pp^.FinallyOffset; pp^.FinallyOffset := cardinal(-1); p2 := 1; end else if pp^.Finally2Offset <> Cardinal(-1) then begin FCurrentPosition := pp^.Finally2Offset; pp^.Finally2Offset := cardinal(-1); p2 := 1; end; end; end; if p2 = 0 then begin FExitPoint := Cardinal(-1); Vs := FStack.GetItem(FCurrStackBase); if Vs = nil then begin FStatus := FOldStatus; break; end; for P2 := FStack.Count - 1 downto FCurrStackBase + 1 do begin DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}FStack.GetItem(P2)); FStack.Delete(P2); end; FStack.Delete(FCurrStackBase); FCurrProc := Vs^.treturnaddress.ProcNo; FCurrentPosition := Vs^.treturnaddress.Position; FCurrStackBase := Vs^.treturnaddress.StackBase; DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Vs); if FCurrProc = nil then begin FStatus := FOldStatus; break; end; end; end; Cm_ST: begin if not ReadLong(p) or not ReadLong(Cardinal(P2)) then begin CMD_Err(erOutOfRange); break; end; Cardinal(P2) := FCurrStackBase + Cardinal(P2); if p >= FTypes.Count then begin CMD_Err(erInvalidType); break; end; if Cardinal(P2) >= FStack.Count then begin CMD_Err(erOutOfStackRange); break; end; Vs := FStack.GetItem(Cardinal(P2)); if Vs^.FType = @ReturnAddressType then begin CMD_Err(erInvalidType); break; end; DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Vs); Vs := CreateVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}FTypes.GetItem(p)); FStack.SetItem(Cardinal(P2), Vs); end; Cm_Pt: begin if not ReadLong(p) then begin CMD_Err(erInvalidType); break; end; Vs := CreateVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}FTypes.GetItem(p)); if Vs = nil then begin CMD_Err(erInvalidType); break; end; FStack.Add(Vs); end; CM_CO: begin if not ReadByte(CalcType) then begin CMD_Err(erOutOfRange); break; end; v3 := ReadVariable(vsFree, True); if v3 = nil then break; if vsFree then begin DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}v3); CMD_Err(erInvalidOpcodeParameter); break; end; Vs := ReadVariable(vsFree, False); if Vs = nil then break; if vs^.FType^.BaseType = btPointer then begin vs := vs^.tPointer; if vs = nil then begin CMD_Err(erNullPointerException); break; end; end; if vs^.FType^.BaseType = btVariant then begin vs := vs^.tvariant; end; Vd := ReadVariable(vdFree, False); if vd = nil then begin if vsFree then DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Vs); break; end; if vd^.FType^.BaseType = btPointer then begin vd := vd^.tPointer; if vd = nil then begin CMD_Err(erNullPointerException); break; end; end; if vd^.FType^.BaseType = btVariant then begin vd := vd^.tvariant; end; if Vd = nil then begin if vsFree then DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Vs); break; end; DoBooleanCalc(Vs, Vd, v3, CalcType); if vsFree then DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Vs); if vdFree then DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Vd); end; Cm_cv: begin Vd := ReadVariable(vdFree, True); if Vd = nil then break; if (Vd^.FType^.BaseType <> btU32) and (Vd^.FType^.BaseType <> btS32) and (vd^.FType^.BaseType <> btProcPtr) then begin if vdFree then DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Vd); CMD_Err(ErTypeMismatch); break; end; p := Vd^.tu32; if vdFree then DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Vd); if (p >= FProcs.Count) or (p = FMainProc) then begin CMD_Err(erOutOfProcRange); break; end; u := FProcs.GetItem(p); if u^.ExternalProc then begin if not u^.ProcPtr(Self, u, FGlobalVars, FStack) then CMD_Err(erCouldNotCallProc); end else begin Vs := CreateVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}@ReturnAddressType); Vs^.treturnaddress.ProcNo := FCurrProc; Vs^.treturnaddress.Position := FCurrentPosition; Vs^.treturnaddress.StackBase := FCurrStackBase; FStack.Add(Vs); FCurrStackBase := FStack.Count - 1; FCurrProc := u; FCurrentPosition := 0; end; end; cm_sp: begin Vd := ReadVariable(vdFree, False); if Vd = nil then begin cmd_err(erInvalidOpcodeParameter); break; end; if vdFree then begin DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Vd); CMD_Err(erInvalidOpcodeParameter); break; end; if Vd^.FType^.BaseType <> btPointer then begin CMD_Err(erInvalidOpcodeParameter); break; end; Vs := ReadVariable(vsFree, False); if Vs = nil then begin break; end else if vsFree then begin DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Vs); CMD_Err(erInvalidOpcodeParameter); break; end else begin if (Vd^.tPointer <> nil) then begin DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Vd^.tPointer); vd^.tPointer := nil; end; if vs^.FType^.BaseType = btPointer then begin vs := vs^.tPointer; end; Inc(Vs^.RefCount); Vd^.tPointer := Vs; end; end; cm_bn: begin Vd := ReadVariable(vdFree, True); if Vd = nil then break; if vdFree then begin DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Vd); CMD_Err(erInvalidOpcodeParameter); break; end; DoBooleanNot(Vd); end; cm_in: begin Vd := ReadVariable(vdFree, True); if Vd = nil then break; if vdFree then begin DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Vd); CMD_Err(erInvalidOpcodeParameter); break; end; DoIntegerNot(Vd); end; cm_vm: begin Vd := ReadVariable(vdFree, True); if Vd = nil then break; if vdFree then begin DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Vd); CMD_Err(erInvalidOpcodeParameter); break; end; DoMinus(Vd); end; cm_sf: begin vd := ReadVariable(vdFree, True); if vd = nil then break; if vdFree then begin DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}vd); CMD_Err(erInvalidOpcodeParameter); break; end; if not ReadByte(p) then begin CMD_Err(erOutOfRange); Break; end; case Vd^.FType^.BaseType of btU8: vdFree := Vd^.tu8 <> 0; btS8: vdFree := Vd^.tS8 <> 0; btU16: vdFree := Vd^.tu16 <> 0; btS16: vdFree := Vd^.ts16 <> 0; btU32, btProcPtr: vdFree := Vd^.tu32 <> 0; btS32: vdFree := Vd^.ts32 <> 0; else begin CMD_Err(erInvalidType); break; end; end; if p <> 0 then FJumpFlag := not vdFree else FJumpFlag := vdFree; end; cm_fg: begin if not ReadLong(p) then begin CMD_Err(erOutOfRange); break; end; if FJumpFlag then FCurrentPosition := FCurrentPosition + p; end; cm_puexh: begin New(pp); pp^.BasePtr :=FCurrStackBase; pp^.StackSize := FStack.Count; if not ReadLong(pp^.FinallyOffset) then begin CMD_Err(erOutOfRange); Dispose(pp); Break; end; if not ReadLong(pp^.ExceptOffset) then begin CMD_Err(erOutOfRange); Dispose(pp); Break; end; if not ReadLong(pp^.Finally2Offset) then begin CMD_Err(erOutOfRange); Dispose(pp); Break; end; if not ReadLong(pp^.EndOfBlock) then begin CMD_Err(erOutOfRange); Dispose(pp); Break; end; if pp^.FinallyOffset <> Cardinal(-1) then pp^.FinallyOffset := pp^.FinallyOffset + FCurrentPosition; if pp^.ExceptOffset <> Cardinal(-1) then pp^.ExceptOffset := pp^.ExceptOffset + FCurrentPosition; if pp^.Finally2Offset <> Cardinal(-1) then pp^.Finally2Offset := pp^.Finally2Offset + FCurrentPosition; if pp^.EndOfBlock <> Cardinal(-1) then pp^.EndOfBlock := pp^.EndOfBlock + FCurrentPosition; if ((pp^.FinallyOffset <> cardinal(-1)) and (pp^.FinallyOffset >= FCurrProc^.Length)) or ((pp^.ExceptOffset <> cardinal(-1)) and (pp^.ExceptOffset >= FCurrProc^.Length)) or ((pp^.Finally2Offset <> cardinal(-1)) and (pp^.Finally2Offset >= FCurrProc^.Length)) or ((pp^.EndOfBlock <> cardinal(-1)) and (pp^.EndOfBlock >= FCurrProc^.Length)) then begin CMD_Err(ErOutOfRange); Dispose(pp); Break; end; FExceptionStack.Add(pp); end; cm_poexh: begin if not ReadByte(p) then begin CMD_Err(ErOutOfRange); Break; end; case p of 2: begin ExceptionProc(Cardinal(-1), Cardinal(-1), erNoError, ''); pp := FExceptionStack.GetItem(FExceptionStack.Count -1); if pp = nil then begin cmd_err(ErOutOfRange); Break; end; if pp^.Finally2Offset <> cardinal(-1) then begin FCurrentPosition := pp^.Finally2Offset; pp^.Finally2Offset := cardinal(-1); end else begin p := pp^.EndOfBlock; Dispose(pp); FExceptionStack.Delete(FExceptionStack.Count -1); if FExitPoint <> Cardinal(-1) then begin FCurrentPosition := FExitPoint; end else begin FCurrentPosition := p; end; end; end; 0: begin pp := FExceptionStack.GetItem(FExceptionStack.Count -1); if pp = nil then begin cmd_err(ErOutOfRange); Break; end; if pp^.FinallyOffset <> cardinal(-1) then begin FCurrentPosition := pp^.FinallyOffset; pp^.FinallyOffset := cardinal(-1); end else if pp^.Finally2Offset <> cardinal(-1) then begin FCurrentPosition := pp^.Finally2Offset; pp^.ExceptOffset := cardinal(-1); end else begin p := pp^.EndOfBlock; Dispose(pp); FExceptionStack.Delete(FExceptionStack.Count -1); if ExEx <> eNoError then begin ExceptionProc(ExProc, ExPos, ExEx, ExParam); end else if FExitPoint <> Cardinal(-1) then begin FCurrentPosition := FExitPoint; end else begin FCurrentPosition := p; end; end; end; 1: begin pp := FExceptionStack.GetItem(FExceptionStack.Count -1); if pp = nil then begin cmd_err(ErOutOfRange); Break; end; if (ExEx <> ENoError) and (pp^.ExceptOffset <> cardinal(-1)) then begin FCurrentPosition := pp^.ExceptOffset; pp^.ExceptOffset := cardinal(-1); end else if (pp^.Finally2Offset <> cardinal(-1)) then begin FCurrentPosition := pp^.Finally2Offset; pp^.Finally2Offset := cardinal(-1); end else begin p := pp^.EndOfBlock; Dispose(pp); FExceptionStack.Delete(FExceptionStack.Count -1); if ExEx <> eNoError then begin ExceptionProc(ExProc, ExPos, ExEx, ExParam); end else if FExitPoint <> Cardinal(-1) then begin FCurrentPosition := FExitPoint; end else begin FCurrentPosition := p; end; end; end; 3: begin pp := FExceptionStack.GetItem(FExceptionStack.Count -1); if pp = nil then begin cmd_err(ErOutOfRange); Break; end; p := pp^.EndOfBlock; Dispose(pp); FExceptionStack.Delete(FExceptionStack.Count -1); if ExEx <> eNoError then begin ExceptionProc(ExProc, ExPos, ExEx, ExParam); end else if FExitPoint <> Cardinal(-1) then begin FCurrentPosition := FExitPoint; end else begin FCurrentPosition := p; end; end; end; end; else CMD_Err(erInvalidOpcode); // Error end; RunLine; end; end; if ExEx <> erNoError then FStatus := FOldStatus; until (FExceptionStack.Count = 0) or (Fstatus <> IsRunning); if FStatus = isLoaded then begin for I := 0 to Longint(FStack.Count) - 1 do begin DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}FStack.GetItem(I)); end; FStack.Clear; if FCallCleanup then Cleanup; end; Result := ExEx = erNoError; end; procedure TIFPSExec.Stop; var I: Longint; begin if FStatus = isRunning then FStatus := isLoaded else if FStatus = isPaused then begin FStatus := isLoaded; for I := 0 to Longint(FStack.Count) - 1 do begin DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}FStack.GetItem(I)); end; FStack.Clear; end; end; function TIFPSExec.ReadByte(var b: Cardinal): Boolean; begin if FCurrentPosition < FCurrProc.Length then begin b := FCurrProc.Data^[FCurrentPosition]; Inc(FCurrentPosition); Result := True; end else Result := False; end; function TIFPSExec.ReadLong(var b: Cardinal): Boolean; begin if FCurrentPosition + 3 < FCurrProc.Length then begin b := Cardinal((@FCurrProc.Data^[FCurrentPosition])^); Inc(FCurrentPosition, 4); Result := True; end else Result := False; end; function TIFPSExec.RunProc(Params: TIfList; ProcNo: Cardinal): Boolean; var I, I2: Integer; Vd: PIfVariant; Cp: PIFProcRec; oldStatus: TIFStatus; begin if FStatus <> isNotLoaded then begin if ProcNo >= FProcs.Count then begin Result := False; exit; end; if PIFProcRec(FProcs.GetItem(ProcNo))^.ExternalProc then begin Result := False; exit; end; for I := 0 to Params.Count - 1 do begin vd := Params.GetItem(I); if vd = nil then begin Result := False; exit; end; FStack.Add(Params.GetItem(I)); end; Vd := CreateVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}@ReturnAddressType); Cp := FCurrProc; Vd^.treturnaddress.ProcNo := nil; Vd^.treturnaddress.Position := FCurrentPosition; Vd^.treturnaddress.StackBase := FCurrStackBase; I := FStack.Count; FStack.Add(Vd); FCurrStackBase := FStack.Count - 1; FCurrProc := FProcs.GetItem(ProcNo); FCurrentPosition := 0; oldStatus := FStatus; FStatus := isPaused; Result := RunScript; if FStack.Count > Cardinal(I) then begin vd := FStack.GetItem(I); if (vd <> nil) and (vd^.FType = @ReturnAddressType) then begin for i2 := FStack.Count - 1 downto I + 1 do begin DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}FStack.GetItem(i2)); FStack.Delete(i2); end; FStack.Delete(I); FCurrentPosition := Vd^.treturnaddress.Position; FCurrStackBase := Vd^.treturnaddress.StackBase; DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}Vd); end; end; for I := Params.Count - 1 downto 0 do begin FStack.Delete(FStack.Count - 1); end; FStatus := oldStatus; FCurrProc := Cp; end else begin Result := False; end; end; function TIFPSExec.CreateIntegerVariant(FType: PIFTypeRec; Value: Longint): PIfVariant; begin Result := CreateVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}FType); if Result <> nil then begin case FType^.BaseType of btU8: Result^.tu8 := Value; btS8: Result^.tS8 := Value; btU16: Result^.tu16 := Value; btS16: Result^.ts16 := Value; btU32, btProcPtr: Result^.tu32 := Value; btS32: Result^.ts32 := Value; end; end; end; function TIFPSExec.CreateStringVariant(FType: PIFTypeRec; const Value: string): PIfVariant; begin Result := CreateVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}FType); if Result <> nil then begin case FType^.BaseType of btPChar, btString: begin TbtString(Result^.tstring) := Value; end; end; end; end; function TIFPSExec.CreateFloatVariant(FType: PIFTypeRec; Value: Extended): PIfVariant; begin Result := CreateVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}FType); if Result <> nil then begin case FType^.BaseType of btSingle: Result^.tsingle := Value; btDouble: Result^.tdouble := Value; btExtended: Result^.textended := Value; end; end; end; function TIFPSExec.FindType2(BaseType: TIFPSBaseType): PIFTypeRec; var l: Cardinal; begin FindType2 := FindType(0, BaseType, l); end; function TIFPSExec.FindType(StartAt: Cardinal; BaseType: TIFPSBaseType; var l: Cardinal): PIFTypeRec; var I: Integer; n: PIFTypeRec; begin for I := StartAt to FTypes.Count - 1 do begin n := FTypes.GetItem(I); if n^.BaseType = BaseType then begin l := I; Result := n; exit; end; end; Result := nil; end; function TIFPSExec.GetTypeNo(l: Cardinal): PIFTypeRec; begin Result := FTypes.GetItem(l); end; function TIFPSExec.GetProc(const Name: string): Cardinal; var MM, I: Longint; n: PIFProcRec; begin MM := MakeHash(Name); for I := 0 to FProcs.Count - 1 do begin n := FProcs.GetItem(I); if (not n^.ExternalProc) and (Length(n^.ExportName) <> 0) and (n^.ExportNameHash = MM) and (n^.ExportName = Name) then begin Result := I; exit; end; end; Result := Cardinal(-1); end; function TIFPSExec.GetType(const Name: string): Cardinal; var MM, I: Longint; n: PIFTypeRec; begin MM := MakeHash(Name); for I := 0 to FTypes.Count - 1 do begin n := FTypes.GetItem(I); if (Length(n^.ExportName) <> 0) and (n^.ExportNameHash = MM) and (n^.ExportName = Name) then begin Result := I; exit; end; end; Result := Cardinal(-1); end; procedure TIFPSExec.AddResource(Proc, P: Pointer); var Temp: PIFPSResource; begin New(Temp); Temp^.Proc := Proc; Temp^.P := p; FResources.Add(temp); end; procedure TIFPSExec.DeleteResource(P: Pointer); var i: Longint; begin for i := Longint(FResources.Count) -1 downto 0 do begin if PIFPSResource(FResources.GetItem(I))^.P = P then begin FResources.Delete(I); exit; end; end; end; function TIFPSExec.FindProcResource(Proc: Pointer): Pointer; var I: Longint; temp: PIFPSResource; begin for i := Longint(FResources.Count) -1 downto 0 do begin temp := FResources.GetItem(I); if temp^.Proc = proc then begin Result := Temp^.P; exit; end; end; Result := nil; end; function TIFPSExec.IsValidResource(Proc, P: Pointer): Boolean; var i: Longint; temp: PIFPSResource; begin for i := 0 to Longint(FResources.Count) -1 do begin temp := FResources.GetItem(i); if temp^.p = p then begin result := temp^.Proc = Proc; exit; end; end; result := false; end; function TIFPSExec.FindProcResource2(Proc: Pointer; var StartAt: Longint): Pointer; var I: Longint; temp: PIFPSResource; begin if StartAt > longint(FResources.Count) -1 then StartAt := longint(FResources.Count) -1; for i := StartAt downto 0 do begin temp := FResources.GetItem(I); if temp^.Proc = proc then begin Result := Temp^.P; StartAt := i -1; exit; end; end; StartAt := -1; Result := nil; end; procedure TIFPSExec.RunLine; begin if @FOnRunLine <> nil then FOnRunLine(Self); end; procedure TIFPSExec.CMD_Err2(EC: TIFError; const Param: string); var l: Longint; C: Cardinal; begin C := Cardinal(-1); for l := 0 to FProcs.Count - 1 do begin if FProcs.GetItem(l) = FCurrProc then begin C := l; break; end; end; ExceptionProc(C, FCurrentPosition, EC, Param); end; procedure FreePIFVariantList({$IFNDEF NOSMARTMM}MM: Pointer; {$ENDIF}List: TIfList); var I: Longint; begin for I := List.Count -1 downto 0 do begin DisposeVariant({$IFNDEF NOSMARTMM}MM, {$ENDIF}List.GetItem(I)); end; List.Free; end; procedure TIFPSExec.AddSpecialProcImport(const FName: string; P: TIFPSOnSpecialProcImport; Tag: Pointer); var N: PSpecialProc; begin New(n); n^.P := P; N^.Name := FName; n^.namehash := MakeHash(FName); n^.Tag := Tag; FSpecialProcList.Add(n); end; function TIFPSExec.GetVar(const Name: string): Cardinal; var l: Longint; h: longint; begin h := makehash(Name); for l := FExportedVars.Count - 1 downto 0 do begin if (PIFPSExportedVar(FexportedVars.GetItem(L))^.FNameHash = h) and(PIFPSExportedVar(FexportedVars.GetItem(L))^.FName=Name) then begin Result := L; exit; end; end; Result := Cardinal(-1); end; function TIFPSExec.GetVarNo(C: Cardinal): PIFVariant; begin Result := FGlobalVars.GetItem(c); end; function TIFPSExec.GetVar2(const Name: string): PIFVariant; begin Result := GetVarNo(GetVar(Name)); end; function TIFPSExec.GetProcNo(C: Cardinal): PIFProcRec; begin Result := FProcs.GetItem(c); end; procedure TIFPSExec.DoIntegerNot(Vd: PIfVariant); begin case Vd^.FType^.BaseType of btU8: Vd^.tu8 := not Vd^.tu8; btS8: Vd^.tS8 := not Vd^.tS8; btU16: Vd^.tu16 := not Vd^.tu16; btS16: Vd^.ts16 := not Vd^.ts16; btU32: Vd^.tu32 := not Vd^.tu32; btS32: Vd^.ts32 := not Vd^.ts32; {$IFNDEF NOINT64} btS64: vd^.ts64 := not vd^.ts64; {$ENDIF} else CMD_Err(erTypeMismatch); end; end; end.