Basics.pas
上传用户:yj_qiu
上传日期:2022-08-08
资源大小:23636k
文件大小:60k
源码类别:

游戏引擎

开发平台:

Delphi

  1. (*
  2.  @Abstract(Basic utilities unit)
  3.  (C) 2003-2007 George "Mirage" Bakhtadze. <a href="http://www.casteng.com">www.casteng.com</a> <br>
  4.  The source code may be used under either MPL 1.1 or LGPL 2.1 license. See included license.txt file <br>
  5.  Unit contains basic utilities, constants and types
  6. *)
  7. {$Include GDefines.inc}
  8. unit Basics;
  9. interface
  10. uses BaseMsg, BaseTypes, SysUtils;
  11. const
  12.   GeneralDecimalSeparator: Char = '.';
  13.   // Minimum capacity of reference counted container
  14.   MinRefCContainerLength = 8;
  15.   // Delimiter which separate strings in enumerations
  16.   StringDelimiter = '&';
  17.   // Short alias for StringDelimiter
  18.   StrDelim = StringDelimiter;
  19. //  feOK = 0; feNotFound = -1; feCannotRead = -2; feCannotWrite = -3; feInvalidFileFormat = -4; feCannotSeek = -5; feCannotOpen = -6;
  20.   // File usage: do not open
  21.   fuDoNotOpen = 0;
  22.   // File usage: open to read 
  23.   fuRead = 1;
  24.   // File usage: open to read and write
  25.   fuReadWrite = 2;
  26.   // File usage: open to write
  27.   fuWrite = 3;
  28.   // File usage: open to append
  29.   fuAppend = 4;
  30.   
  31.   // File sharing mode: allow all operations
  32.   smAllowAll = 0;
  33.   // File sharing mode: allow read
  34.   smAllowRead = 1;
  35.   // File sharing mode: do not allow anything (exlusive)
  36.   smExclusive = 2;
  37.   // 1.0 in integer representation
  38.   OneAsInt: LongWord = $3F800000;
  39.   OneAsInt2: LongWord = $3F800000 shl 1;
  40.   OneOver100 = 1/100;
  41.     // Pixel formats
  42.   // Number of supported pixel formats
  43.   TotalPixelFormats = 32;
  44.   pfUndefined    = 0;  pfR8G8B8   = 1;  pfA8R8G8B8 = 2;  pfX8R8G8B8 = 3;
  45.   pfR5G6B5       = 4;  pfX1R5G5B5 = 5;  pfA1R5G5B5 = 6;  pfA4R4G4B4 = 7;
  46.   pfA8           = 8;  pfX4R4G4B4 = 9;  pfA8P8     = 10; pfP8       = 11; pfL8     = 12; pfA8L8      = 13; pfA4L4 = 14;
  47.   pfV8U8         = 15; pfL6V5U5   = 16; pfX8L8V8U8 = 17; pfQ8W8V8U8 = 18; pfV16U16 = 19; pfW11V11U10 = 20;
  48.   pfD16_LOCKABLE = 21; pfD32      = 22; pfD15S1    = 23; pfD24S8    = 24; pfD16    = 25; pfD24X8     = 26; pfD24X4S4 = 27;
  49.   pfB8G8R8       = 28; pfA8B8G8R8 = 29;
  50.   pfATIDF16      = 30; pfATIDF24  = 31;
  51.   pfAuto         = $FFFFFFFF;
  52.   PixelFormatsEnum = 'Undefined&R8G8B8&A8R8G8B8&X8R8G8B8&' +
  53.                      'R5G6B5&X1R5G5B5&A1R5G5B5&A4R4G4B4&' +
  54.                      'A8&X4R4G4B4&A8P8&P8&L8&A8L8&A4L4&' +
  55.                      'V8U8&L6V5U5&X8L8V8U8&Q8W8V8U8&V16U16&W11V11U10&' +
  56.                      'D16(Lockable)&D32&D15S1&D24S8&D16&D24X8&D24X4S4&' +
  57.                      'B8G8R8&A8B8G8R8&' +
  58.                      'ATI_DF16&ATI_DF24';
  59.   OneOver255 = 1/255;
  60.   // IDF file format constants
  61.   icNone = 0; icRLE = 1; icLZW = 2; icHuffman = 3; icWavelet = 4;
  62.   IDFSignature = 'IDF';
  63. type
  64.   // IDF file header (deprecated)
  65.   TIDFHeader = record
  66.     Signature: array[0..2] of AnsiChar;
  67.     Compression, PixelFormat, MipLevels, Width, Height: Cardinal;
  68.   end;
  69.   // @Abstract(Base error class)
  70.   TError = class(TMessage)
  71.     // Error message text
  72.     ErrorMessage: string;
  73.     constructor Create(AErrorMessage: string);
  74.     // This function used as default error handler
  75.     function DefaultErrorHandler(const Error: TError): Boolean;
  76.   end;
  77.   { Error handler delegate. When an error occurs a delegate of this type is called (See @Link(ErrorHandler)).
  78.     If it returns @True the application should try to continue the operation which caused the error. }
  79.   TErrorHandler = function(const Error: TError): Boolean of object;
  80.   // Error class for streaming operations
  81.   TStreamError = class(TError)
  82.   end;
  83.   // Error class for invalid format errors
  84.   TInvalidFormat = class(TError)
  85.   end;
  86.   // Error class for invalid argument errors
  87.   TInvalidArgument = class(TError)
  88.   end;
  89.   // Error class for file operations
  90.   TFileError = class(TError)
  91.   end;
  92.   // A delegate with file name
  93.   TFileDelegate          = function(const FileName: string): Boolean of object;
  94.   // A delegate for string comparison
  95.   TStringCompareDelegate = function(const s1, s2: string): Integer of object;
  96.   { @Abstract(Reference-counted container of temporary objects and memory buffers )
  97.     Create an instance with @Link(CreateRefcountedContainer). The container can be used to accumulate temporary objects and buffers.
  98.     When no more references points to the container it destroys itself and all accumulated objects and buffers. }
  99.   IRefcountedContainer = interface
  100.     // Adds an object instance
  101.     function AddObject(Obj: TObject): TObject;
  102.     // Adds a memory buffer
  103.     function AddPointer(Ptr: Pointer): Pointer;
  104.     // Adds an array of object instances
  105.     procedure AddObjects(Objs: array of TObject);
  106.     // Adds an array of memory buffers
  107.     procedure AddPointers(Ptrs: array of Pointer);
  108.   end;
  109.   { @Abstract(Base class for streams)
  110.     Streams can read from and/or write to files (including text ones), memory, etc }
  111.   TStream = class
  112.   private
  113.     FPosition, FSize: Cardinal;
  114.     procedure SetPosition(const Value: Cardinal);
  115.   protected
  116.     // Changes current size of the stream
  117.     procedure SetSize(const Value: Cardinal); virtual;
  118.   public
  119.     // Changes the current position of the stream (if such changes are supported by particular stream class)
  120.     function Seek(const NewPos: Cardinal): Boolean; virtual;
  121.     // Reads <b>Count</b> bytes from the stream to <b>Buffer</b>, moves current position forward for number of bytes read and returns this number
  122.     function Read(out Buffer; const Count: Cardinal): Cardinal; virtual; abstract;
  123.     // Reads <b>Count</b> bytes from the stream to <b>Buffer</b>, moves current position forward for number of bytes read and returns @True if success
  124.     function ReadCheck(out Buffer; const Count: Cardinal): Boolean;
  125.     // Writes <b>Count</b> bytes from <b>Buffer</b> to the stream, moves current position forward for the number of bytes written and returns this number
  126.     function Write(const Buffer; const Count: Cardinal): Cardinal; virtual; abstract;
  127.     // Writes <b>Count</b> bytes from <b>Buffer</b> to the stream, moves current position forward for the number of bytes written and returns @True if success
  128.     function WriteCheck(const Buffer; const Count: Cardinal): Boolean;
  129.     // Current size of the stream in bytes
  130.     property Size: Cardinal read FSize write SetSize;
  131.     // Current position within the stream in bytes
  132.     property Position: Cardinal read FPosition write SetPosition;
  133.   end;
  134.   { @Abstract(File stream class)
  135.     Provides streaming implementation for binary files }
  136.   TFileStream = class(TStream)
  137.   private
  138.     Opened: Boolean;
  139.     FFileName: string;
  140.     F: file;
  141.   protected
  142.     // Changes current size of the stream
  143.     procedure SetSize(const Value: Cardinal); override;
  144.   public
  145.     // Creates a file stream associating it with file with the given file name
  146.     constructor Create(const AFileName: string; const Usage: Integer = fuReadWrite; const ShareMode: Integer = smAllowAll);
  147.     destructor Destroy; override;
  148.     // Open file with the specified usage and sharing mode
  149.     function Open(const Usage: Integer; const ShareMode: Integer): Boolean;
  150.     // Close file
  151.     procedure Close;
  152.     function Seek(const NewPos: Cardinal): Boolean; override;
  153.     function Read(out Buffer; const Count: Cardinal): Cardinal; override;
  154.     function Write(const Buffer; const Count: Cardinal): Cardinal; override;
  155.     // Associated file name
  156.     property Filename: string read FFileName;
  157.   end;
  158.   { @Abstract(Memory stream class)
  159.     Provides streaming implementation for buffers in memory }
  160.   TMemoryStream = class(TStream)
  161.   private
  162.     FData: Pointer;
  163.     FCapacity: Cardinal;
  164.     procedure SetCapacity(const NewCapacity: Cardinal);
  165.     procedure Allocate(const NewSize: Cardinal);
  166.   protected
  167.     // Changes current size of the stream
  168.     procedure SetSize(const Value: Cardinal); override;
  169. //    property Capacity: Cardinal read FCapacity;
  170.   public
  171.     // Creates a memory stream of the specified size associating it with the specified address in memory
  172.     constructor Create(AData: Pointer; const ASize: Cardinal);
  173.     destructor Destroy; override;
  174.     function Read(out Buffer; const Count: Cardinal): Cardinal; override;
  175.     function Write(const Buffer; const Count: Cardinal): Cardinal; override;
  176.     // Pointer to buffer in memory
  177.     property Data: Pointer read FData;
  178.   end;
  179.   { @Abstract(Non-unicode string stream class)
  180.     Provides streaming implementation for non-unicode strings }
  181.   TAnsiStringStream = class(TStream)
  182.     // string data container
  183.     Data: AnsiString;
  184.     // Carriage return character sequence. #13#10 for Windows.
  185.     ReturnSequence: TShortName;
  186.     constructor Create(AData: Pointer; const ASize: Cardinal; const AReturnsequence: TShortName = #13#10);
  187.     function Read(out Buffer; const Count: Cardinal): Cardinal; override;
  188.     function Write(const Buffer; const Count: Cardinal): Cardinal; override;
  189.     function Readln(out Buffer: AnsiString): Integer; virtual;
  190.     function Writeln(const Buffer: AnsiString): Integer; virtual;
  191.   end;
  192.   // Random numbers generator
  193.   TRandomGenerator = class
  194.   public
  195.     constructor Create;
  196.     // Initializes the current sequence with the specified chain value and the specified seed
  197.     procedure InitSequence(Chain, Seed: Longword);
  198.     // Generate a raw random number. Fastest method
  199.     function GenerateRaw: Longword; virtual;
  200.     // Generate a floating point random number within the given range
  201.     function Rnd(Range: Single): Single;
  202.     // Generate a floating point random number within the range [-<b>Range..Range</b>]
  203.     function RndSymm(Range: Single): Single;
  204.     // Generate an integer random number within the range [0..<b>Range</b>-1]
  205.     function RndI(Range: Integer): Integer;
  206.   protected
  207.     // Seeds for sequences
  208.     RandomSeed: array of Longword;
  209.     // Chain values for sequences
  210.     RandomChain: array of Longword;
  211.     // Current sequence
  212.     FCurrentSequence: Cardinal;
  213.     // Number of sequences
  214.     procedure SetMaxSequence(AMaxSequence: Integer);
  215.     procedure SetCurrentSequence(const Value: Cardinal);
  216.   public
  217.     // Current sequence
  218.     property CurrentSequence: Cardinal read FCurrentSequence write SetCurrentSequence;
  219.   end;
  220.   // Create an instance of reference counted container
  221.   function CreateRefcountedContainer: IRefcountedContainer;
  222.     // Some math routines
  223.   //
  224.   function Sign(x: Integer): Integer; overload;
  225.   function Sign(x: Single): Single; overload;
  226.   function Ceil(const X: Single): Integer;
  227.   function Floor(const X: Single): Integer;
  228.   function IsNan(const AValue: Single): Boolean;
  229.   function MaxS(V1, V2: Single): Single;
  230.   function MinS(V1, V2: Single): Single;
  231.   function ClampS(V, Min, Max: Single): Single;
  232.   function MaxI(V1, V2: Integer): Integer;
  233.   function MinI(V1, V2: Integer): Integer;
  234.   function MaxC(V1, V2: Cardinal): Cardinal;
  235.   function MinC(V1, V2: Cardinal): Cardinal;
  236.   function ClampI(V, Min, Max: Integer): Integer;
  237.   procedure SwapI(var a, b: Integer);
  238.   function BitTest(Data: Cardinal; BitIndex: Byte): Boolean;
  239.   function InterleaveBits(x, y: Smallint): Integer;
  240.   function PtrOffs(Base: Pointer; Offset: Integer): Pointer;
  241.   // Returns color max component value
  242.   function GetColor4SIntensity(const Color: TColor4s): Single;
  243.   function VectorToColor(const v: TVector3s): TColor;
  244.   function GetColorFrom4s(const ColorS: TColor4s): TColor;
  245.   
  246.   // Returns color max component value
  247.   function GetColorIntensity(const Color: TColor): Integer;
  248.   // Returns scale color. S is desired koefficient multiplied by 256
  249.   function ScaleColorI(const Color: TColor; S: Cardinal): TColor;
  250.   function ScaleColorS(const Color: TColor; S: Single): TColor;
  251.   function AddColorW(const Color1, Color2: TColor; W1, W2: Single): TColor;
  252.   function BlendColor(const Color1, Color2: TColor; K: Single): TColor;
  253.   function IsDepthFormat(Format: Integer): Boolean;
  254.   function PixelFormatToStr(Format: Integer): AnsiString;
  255.   function GetSteppedSize(CurrentSize, Step: Integer): Integer;
  256.   function CmpMem(P1, P2: Pointer; Size: Cardinal): Boolean;
  257.   procedure MoveReverse8(Src, Dest: Pointer; Count: Integer);
  258.   procedure MoveReverse16(Src, Dest: Pointer; Count: Integer);
  259.   procedure Swap(var V1, V2);
  260.   // Fast (if SSE optimization are allowed) implementation of Trunc(x)
  261.   function FastTrunc(X: Single): Integer;
  262.   procedure SinCos(a: Single; out OSin, OCos: Single);
  263.   // Fast (if assembler optimization are allowed) implementation of Sqrt(x) with accurasy ~0.25%
  264.   function FastSqrt(x: Single): Single;
  265.   // Fast (if assembler optimization are allowed) implementation of 1/Sqrt(x)
  266.   function InvSqrt(x: Single): Single;
  267.   function Log2I(x: Integer): Integer;
  268.   function IntPower(Base: Single; Exponent: Integer): Single;
  269.   function Power(const Base, Exponent: Single): Single;
  270.   function NextPowerOf2(x: Integer): Integer;
  271.   function PosEx(const substr : AnsiString; const s : AnsiString; const start: Integer ) : Integer ;
  272.   { Splits a string into array of strings using <b>Delim</b> as a delimiter
  273.     If <b>EmptyOK</b> is @True result strings can be empty. Returns number of strings in array }
  274.   function Split(const Str, Delim: string; out Res: TStringArray; EmptyOK: Boolean): Integer;
  275.   { Splits an ansi string into array of strings using <b>Delim</b> as a delimiter
  276.     If <b>EmptyOK</b> is @True result strings can be empty. Returns number of strings in array }
  277.   function SplitA(const Str, Delim: AnsiString; out Res: TAnsiStringArray; EmptyOK: Boolean): Integer;
  278.   { Returns an enumeration string which consists of all elements of strings separated by @Link(StringDelimiter)
  279.     If <b>EmptyOK</b> is @True empty elements are included in result }
  280.   function StringsToEnumA(Strings: array of TShortName; EmptyOK: Boolean): Ansistring;
  281.   procedure RectIntersect(const ARect1, ARect2: TRect; out Result: TRect);
  282.   function GetRectIntersect(const ARect1, ARect2: TRect): TRect;
  283.   function GetCorrectRect(ALeft, ATop, ARight, ABottom: Integer): TRect;
  284.   function IsInArea(const X, Y, X1, Y1, X2, Y2: Single): Boolean; overload;
  285.   function IsInArea(const X, Y: Single; const Area: TArea): Boolean; overload;
  286.   function GetFileName(const FileName: string): string;
  287.   procedure FillDWord(var Dest; Count: Cardinal; Value: LongWord);
  288.   function GetDefaultUVMap: TUVMap;
  289.   function CompareValues(v1, v2: Extended): Integer;
  290.   function CompareDates(ADate: TDateTime; Year, Month, Day: Integer): Integer;
  291.   function HexStrToIntDef(const s: string; Default: Longword): Longword;
  292.   function ColorStrToIntDef(const color: string; Default: Longword): Longword;
  293.   function IsDecimalInteger(const s: string): Boolean;
  294.   function IsFloat(const s: string): Boolean;                           // Tests with current decimal separator
  295.   function IsColor(const s: string): Boolean;
  296.   function IntToStrA(Value: Int64): AnsiString;
  297.   function IntToHexA(Value: Int64; Digits: Integer): AnsiString;
  298.   function FloatToStrA(Value: Extended): AnsiString;
  299.   function FormatA(const Format: string; const Args: array of const): AnsiString;
  300.   function StrToFloatDefA(const S: AnsiString; const Default: Extended): Extended;
  301.   function TrimSpacesA(ts: string): AnsiString;
  302.   function TrimSpaces(ts: string): string;
  303.   function GetLastCharPos(c: Char; const s: string): Integer;
  304.   function isSameGUID(GUID1, GUID2: TGUID): Boolean;
  305.   function GetBytesPerPixel(PixelFormat: Cardinal): Integer;
  306.   function GetBitsPerPixel(PixelFormat: Cardinal): Integer;
  307.     // Sorting via indices not affecting values itself
  308.   // Performs a quick sort on an array of strings and returns sorted indices not affecting the source array
  309.   procedure QuickSortStrInd(N: Integer; Values: TAnsiStringArray; Inds: TIndArray; Acc: Boolean);
  310.   // Performs a quick sort on an array of integers and returns sorted indices not affecting the source array
  311.   procedure QuickSortIntInd(N: Integer; Values, Inds: TIndArray; Acc: Boolean);
  312.   // Performs a quick sort on an array of floating point numbers and returns sorted indices not affecting the source array
  313.   procedure QuickSortSInd(N: Integer; Values: TSingleArray; Inds: TIndArray; Acc: Boolean);
  314.     // Sorting values
  315.   // Performs a quick sort on an array of strings
  316.   procedure QuickSortStr(N: Integer; Values: TAnsiStringArray);
  317.   // Performs a quick sort on an array of integers
  318.   procedure QuickSortInt(N: Integer; Values: TIndArray);
  319.   // Performs a quick sort on an array of floating point numbers
  320.   procedure QuickSortS(N: Integer; Values: TSingleArray);
  321.   function AssureFloatFormat(const s: string): string;
  322.   function StrFormat(const s: string; args: array of string): string;
  323.   function ExtractStr(s, Sig: string): string;
  324.   // Returns True if the spcefied character belongs to the specified set
  325.   function IsCharIn(C: AnsiChar; const CharSet: TSysCharSet): Boolean;
  326.   function IsReal(const s: string): Boolean;                            // Tests with general decimal separator
  327.   function StrToRealDef(const s: string; Default: Extended): Extended;
  328.   function RealToStr(Value: Extended): string;
  329.   // Saves a string to a stream. Returns @True if success
  330.   function SaveString(Stream: TStream; const s: AnsiString): Boolean; overload;
  331.   // Loads a string from a stream. Returns @True if success
  332.   function LoadString(Stream: TStream; out   s: AnsiString): Boolean; overload;
  333.   // Saves a wide string to a stream. Returns @True if success
  334.   function SaveString(Stream: TStream; const s: WideString): Boolean; overload;
  335.   // Loads a wide string from a stream. Returns @True if success
  336.   function LoadString(Stream: TStream; out   s: WideString): Boolean; overload;
  337.   { Calls the <b>Delegate</b> for each file passing the given mask and attribute filter and returns number of such files.
  338.     Stops if the delegate returns @False }
  339.   function ForEachFile(const PathAndMask: string; AttributeFilter: Integer; Delegate: TFileDelegate): Integer;
  340.   procedure CalcCRC32(Bytes: PByteBuffer; ByteCount: Cardinal; var CRCValue: Longword);
  341. var
  342.   { This handler caled when an error occurs. Default handler simply logs the error class.
  343.     Application can set its own handler to handle errors, raise exceptions, continue the workflow, etc.
  344.     To continue the normal workflow application's handler should call <b>Invalidate()</b> method of the error message. }
  345.   ErrorHandler: TErrorHandler;
  346.   // Key codes
  347.   //
  348.   IK_ESCAPE,
  349.   IK_1, IK_2, IK_3, IK_4, IK_5, IK_6, IK_7, IK_8, IK_9, IK_0,
  350.   IK_MINUS, IK_EQUALS, IK_BACK, IK_TAB,
  351.   IK_Q, IK_W, IK_E, IK_R, IK_T, IK_Y, IK_U, IK_I, IK_O, IK_P,
  352.   IK_LBRACKET, IK_RBRACKET,
  353.   IK_RETURN,
  354.   IK_LCONTROL,
  355.   IK_A, IK_S, IK_D, IK_F, IK_G, IK_H, IK_J, IK_K, IK_L,
  356.   IK_SEMICOLON, IK_APOSTROPHE, IK_GRAVE,
  357.   IK_LSHIFT,
  358.   IK_BACKSLASH,
  359.   IK_Z, IK_X, IK_C, IK_V, IK_B, IK_N, IK_M,
  360.   IK_COMMA, IK_PERIOD, IK_SLASH,
  361.   IK_RSHIFT,
  362.   IK_MULTIPLY,
  363.   IK_LMENU,
  364.   IK_SPACE,
  365.   IK_CAPITAL,
  366.   IK_F1, IK_F2, IK_F3, IK_F4, IK_F5, IK_F6, IK_F7, IK_F8, IK_F9, IK_F10,
  367.   IK_NUMLOCK, IK_SCROLL,
  368.   IK_NUMPAD7, IK_NUMPAD8, IK_NUMPAD9, IK_SUBTRACT, IK_NUMPAD4, IK_NUMPAD5, IK_NUMPAD6,
  369.   IK_ADD, IK_NUMPAD1, IK_NUMPAD2, IK_NUMPAD3, IK_NUMPAD0, IK_DECIMAL,
  370.   IK_OEM_102,
  371.   IK_F11, IK_F12,
  372.   IK_F13, IK_F14, IK_F15,
  373.   IK_KANA, IK_ABNT_C1,
  374.   IK_CONVERT, IK_NOCONVERT,
  375.   IK_YEN, IK_ABNT_C2,
  376.   IK_NUMPADEQUALS, IK_CIRCUMFLEX,
  377.   IK_AT, IK_COLON, IK_UNDERLINE, IK_KANJI,
  378.   IK_STOP,
  379.   IK_AX, IK_UNLABELED,
  380.   IK_NEXTTRACK,
  381.   IK_NUMPADENTER,
  382.   IK_RCONTROL,
  383.   IK_MUTE, IK_CALCULATOR, IK_PLAYPAUSE, IK_MEDIASTOP,
  384.   IK_VOLUMEDOWN, IK_VOLUMEUP,
  385.   IK_WEBHOME,
  386.   IK_NUMPADCOMMA, IK_DIVIDE,
  387.   IK_SYSRQ, IK_RMENU, IK_PAUSE,
  388.   IK_HOME, IK_UP, IK_PRIOR, IK_LEFT, IK_RIGHT, IK_END, IK_DOWN,
  389.   IK_NEXT, IK_INSERT, IK_DELETE,
  390.   IK_LWIN, IK_RWIN,
  391.   IK_APPS, IK_POWER, IK_SLEEP, IK_WAKE,
  392.   IK_WEBSEARCH, IK_WEBFAVORITES, IK_WEBREFRESH, IK_WEBSTOP, IK_WEBFORWARD, IK_WEBBACK,
  393.   IK_MYCOMPUTER, IK_MAIL, IK_MEDIASELECT,
  394.   //  Alternate names
  395.   //
  396.   IK_BACKSPACE, IK_NUMPADSTAR, IK_LALT, IK_CAPSLOCK,
  397.   IK_NUMPADMINUS, IK_NUMPADPLUS, IK_NUMPADPERIOD, IK_NUMPADSLASH,
  398.   IK_RALT,
  399.   IK_UPARROW, IK_PGUP, IK_LEFTARROW, IK_RIGHTARROW, IK_DOWNARROW, IK_PGDN,
  400.   IK_PREVTRACK, IK_MOUSELEFT, IK_MOUSERIGHT, IK_MOUSEMIDDLE,
  401.   IK_SHIFT, IK_CONTROL, IK_ALT: Integer;
  402. implementation
  403. uses TextFile {$IFDEF RUSSIAN} , FIOPadeg, Math {$ENDIF} ;
  404. type
  405.   TRefcountedContainer = class(TInterfacedObject, IRefcountedContainer)
  406.   private
  407.     ObjList: array of TObject;
  408.     PtrList: array of Pointer;
  409.     ObjCount, PtrCount: Integer;
  410.   public
  411.     destructor Destroy; override;
  412.     function AddObject(Obj: TObject): TObject;
  413.     function AddPointer(Ptr: Pointer): Pointer;
  414.     procedure AddObjects(Objs: array of TObject);
  415.     procedure AddPointers(Ptrs: array of Pointer);
  416.   end;
  417. { TError }
  418. constructor TError.Create(AErrorMessage: string);
  419. begin
  420.   ErrorMessage := AErrorMessage;
  421. end;
  422. function TError.DefaultErrorHandler(const Error: TError): Boolean;
  423. begin
  424.   Log.Log('An unhandled error of class "' + Error.ClassName + '": ' + Error.ErrorMessage, lkError);
  425.   Result := False;                    // Do not continue
  426. end;
  427. function CreateRefcountedContainer: IRefcountedContainer;
  428. begin
  429.   Result := TRefcountedContainer.Create;
  430. end;
  431. function Sign(x: Integer): Integer; overload;
  432. begin
  433.   Result := Ord(X > 0) - Ord(X < 0);
  434. //  if x > 0 then Result := 1 else if x < 0 then Result := -1 else Result := 0;
  435. end;
  436. function Sign(x: Single): Single; overload;
  437. begin
  438.   if x > 0 then Result := 1 else if x < 0 then Result := -1 else Result := 0;
  439. end;
  440. function IsNan(const AValue: Single): Boolean;
  441. begin
  442.   Result := ((Longword((@AValue)^) and $7F800000)  = $7F800000) and
  443.             ((Longword((@AValue)^) and $007FFFFF) <> $00000000);
  444. end;
  445. function Ceil(const X: Single): Integer;
  446. begin
  447.   Result := Integer(Trunc(X));
  448.   if Frac(X) > 0 then Inc(Result);
  449. end;
  450. function Floor(const X: Single): Integer;
  451. begin
  452.   Result := Integer(Trunc(X));
  453.   if Frac(X) < 0 then Dec(Result);
  454. end;
  455. //-----------------------------------------
  456. function MaxI(V1, V2: Integer): Integer;
  457. begin
  458. //  if V1 > V2 then Result := V1 else Result := V2;
  459.   Result := V1 * Ord(V1 >= V2) + V2 * Ord(V1 < V2);
  460.   Assert((Result >= V1) and (Result >= V2));
  461. end;
  462. function MinI(V1, V2: Integer): Integer;
  463. begin
  464. //  if V1 < V2 then Result := V1 else Result := V2;
  465.   Result := V1 * Ord(V1 <= V2) + V2 * Ord(V1 > V2);
  466.   Assert((Result <= V1) and (Result <= V2));
  467. end;
  468. {$IFDEF USEP6ASM}
  469. function MaxS(V1, V2: Single): Single; assembler;
  470. asm
  471.   fld     dword ptr [ebp+$08]
  472.   fld     dword ptr [ebp+$0c]
  473.   fcomi   st(0), st(1)
  474.   fcmovb  st(0), st(1)
  475.   ffree   st(1)
  476. end;
  477. function MinS(V1, V2: Single): Single; assembler;
  478. asm
  479.   fld     dword ptr [ebp+$08]
  480.   fld     dword ptr [ebp+$0c]
  481.   fcomi   st(0), st(1)
  482.   fcmovnb st(0), st(1)
  483.   ffree   st(1)
  484. end;
  485. {$ELSE}
  486. function MaxS(V1, V2: Single): Single;
  487. begin
  488.   if V1 > V2 then Result := V1 else Result := V2;
  489. end;
  490. function MinS(V1, V2: Single): Single;
  491. begin
  492.   if V1 < V2 then Result := V1 else Result := V2;
  493. end;
  494. {$ENDIF}
  495. function ClampS(V, Min, Max: Single): Single;
  496. begin
  497.   Result := MinS(MaxS(V, Min), Max);
  498. end;
  499. function MaxC(V1, V2: Cardinal): Cardinal;
  500. begin
  501.   Result := V1 * Cardinal(Ord(V1 >= V2)) + V2 * Cardinal(Ord(V1 < V2));
  502.   Assert((Result >= V1) and (Result >= V2));
  503. end;
  504. function MinC(V1, V2: Cardinal): Cardinal;
  505. begin
  506.   Result := V1 * Cardinal(Ord(V1 <= V2)) + V2 * Cardinal(Ord(V1 > V2));
  507.   Assert((Result <= V1) and (Result <= V2));
  508. end;
  509. function ClampI(V, Min, Max: Integer): Integer;
  510. begin
  511. //  if V < B1 then Result := B1 else if V > B2 then Result := B2 else Result := V;
  512.   Result := V + (Min - V) * Ord(V < Min) - (V - Max) * Ord(V > Max);
  513.   Assert((Result >= Min) and (Result <= Max));
  514. end;
  515. procedure SwapI(var a, b: Integer);
  516. begin
  517.   a := a xor b;
  518.   b := b xor a;
  519.   a := a xor b;
  520. end;
  521. function BitTest(Data: Cardinal; BitIndex: Byte): Boolean;
  522. begin
  523.   Result := Odd(Data shr BitIndex);
  524. end;
  525. function InterleaveBits(x, y: Smallint): Integer;
  526. var i: Integer;
  527. begin
  528.   Result := 0;
  529.   for i := 0 to SizeOf(x) * BitsInByte-1 do Result := Result or (x and (1 shl i)) shl i or (y and (1 shl i)) shl (i + 1);
  530. { Another (faster) way:
  531. x = (x | (x << S[3])) & B[3];
  532. x = (x | (x << S[2])) & B[2];
  533. x = (x | (x << S[1])) & B[1];
  534. x = (x | (x << S[0])) & B[0];
  535. y = (y | (y << S[3])) & B[3];
  536. y = (y | (y << S[2])) & B[2];
  537. y = (y | (y << S[1])) & B[1];
  538. y = (y | (y << S[0])) & B[0];
  539. z = x | (y << 1);}
  540. end;
  541. function PtrOffs(Base: Pointer; Offset: Integer): Pointer;
  542. begin
  543.   Result := Base;
  544.   Inc(PByte(Result), Offset);
  545. end;
  546. function GetColor4SIntensity(const Color: TColor4s): Single;
  547. begin
  548.   Result := MaxS(MaxS(Color.R, Color.G), Color.B);
  549. end;
  550. function VectorToColor(const v: TVector3s): TColor;
  551. begin
  552.   Result.r := Round(127.0 * v.x + 128.0);
  553.   Result.g := Round(127.0 * v.y + 128.0);
  554.   Result.b := Round(127.0 * v.z + 128.0);
  555. end;
  556. function GetColorFrom4s(const ColorS: TColor4s): TColor;
  557. begin
  558.   Result.A := Round(MinS(1, MaxS(0, ColorS.A))*255);
  559.   Result.R := Round(MinS(1, MaxS(0, ColorS.R))*255);
  560.   Result.G := Round(MinS(1, MaxS(0, ColorS.G))*255);
  561.   Result.B := Round(MinS(1, MaxS(0, ColorS.B))*255);
  562. end;
  563. function GetColorIntensity(const Color: TColor): Integer;
  564. begin
  565.   Result := MaxI(MaxI(Color.R, Color.G), Color.B);
  566. end;
  567. function ScaleColorI(const Color: TColor; S: Cardinal): TColor;
  568. begin
  569.   Result.C := MinI(255,  (Color.C and 255)        *S) shr 8 +
  570.               MinI(255, ((Color.C shr 8)  and 255)*S)       +
  571.               MinI(255, ((Color.C shr 16) and 255)*S) shl 8 +
  572.               MinI(255, ((Color.C shr 24) and 255)*S) shl 16;
  573. end;
  574. function ScaleColorS(const Color: TColor; S: Single): TColor;
  575. begin
  576.   Result.C := Cardinal(Round(MinS(255,  (Color.C and 255)        *S)))        +
  577.               Cardinal(Round(MinS(255, ((Color.C shr 8)  and 255)*S))) shl 8  +
  578.               Cardinal(Round(MinS(255, ((Color.C shr 16) and 255)*S))) shl 16 +
  579.               Cardinal(Round(MinS(255, ((Color.C shr 24) and 255)*S))) shl 24;
  580. end;
  581. function AddColorW(const Color1, Color2: TColor; W1, W2: Single): TColor;
  582. begin
  583.   Result.R := ClampI(Round(Color1.R * W1 + Color2.R * W2), 0, 255);
  584.   Result.G := ClampI(Round(Color1.G * W1 + Color2.G * W2), 0, 255);
  585.   Result.B := ClampI(Round(Color1.B * W1 + Color2.B * W2), 0, 255);
  586.   Result.A := ClampI(Round(Color1.A * W1 + Color2.A * W2), 0, 255);
  587. end;
  588. function BlendColor(const Color1, Color2: TColor; K: Single): TColor;
  589. begin
  590.   if K > 1 then K := 1; if K < 0 then K := 0;
  591.   Result := AddColorW(Color1, Color2, 1-K, K);
  592. end;
  593. function IsDepthFormat(Format: Integer): Boolean;
  594. begin
  595.   Result := (Format >= pfD16_LOCKABLE) and (Format <= pfD24X4S4) or
  596.             (Format = pfATIDF16) or (Format = pfATIDF24);
  597. end;
  598. function PixelFormatToStr(Format: Integer): AnsiString;
  599. var Strs: TAnsiStringArray;
  600. begin
  601.   Strs := nil;
  602.   if (Format < SplitA(PixelFormatsEnum, '&', Strs, True)) then
  603.     Result := Strs[Format] else
  604.       Result := 'Unknown';
  605.   SetLength(Strs, 0);
  606. end;
  607. function GetSteppedSize(CurrentSize, Step: Integer): Integer;
  608. begin
  609. //  Assert(get
  610. //  Result := MaxI(0, (CurrentSize-1)) and (Step-1) + Step)
  611.   Result := MaxI(0, (CurrentSize-1)) div Step * Step + Step;
  612. end;
  613. function CmpMem(P1, P2: Pointer; Size: Cardinal): Boolean;
  614. { TODO -cOptimization : Make an assembler version }
  615. var i: Integer;
  616. begin
  617.   Result := False;
  618.   for i := 0 to Size-1 do if TByteBuffer(P1^)[i] <> TByteBuffer(P2^)[i] then Exit;
  619.   Result := True;
  620. end;
  621. procedure MoveReverse8(Src, Dest: Pointer; Count: Integer);
  622. var i: Integer;
  623. begin
  624.   if Count <= 0 then Exit;
  625.   for i := 0 to Count-1 do PByteBuffer(Dest)^[i] := PByteBuffer(Src)^[Count-1 - i];
  626. end;
  627. procedure MoveReverse16(Src, Dest: Pointer; Count: Integer);
  628. var i: Integer;
  629. begin
  630.   if Count <= 0 then Exit;
  631.   for i := 0 to Count-1 do PWordBuffer(Dest)^[i] := PWordBuffer(Src)^[Count-1 - i];
  632. end;
  633. procedure Swap(var V1, V2);
  634. var T: Pointer;
  635. begin
  636.   T := Pointer(V1);
  637.   Pointer(V1) := Pointer(V2); Pointer(V2) := T;
  638. end;
  639. function FastTrunc(X: Single): Integer;
  640. {$IFDEF USESSE}
  641. asm
  642.   CVTTSS2SI  eax, [ebp+offset X]
  643. end;
  644. {$ELSE}
  645. begin
  646.   Result := Trunc(X);
  647. end;
  648. {$ENDIF}
  649. {$IFDEF PUREPASCAL}
  650. procedure SinCos(a: Single; out OSin, OCos: Single);
  651. begin
  652.   OSin := Sin(a);
  653.   OCos := Cos(a);
  654. end;
  655. {$ELSE}
  656. procedure SinCos(a: Single; out OSin, OCos: Single); assembler; register;
  657. // EAX contains address of OSin
  658. // EDX contains address of OCos
  659. // a is passed over the stack
  660. asm
  661.   FLD  a
  662.   FSINCOS
  663.   FSTP [OCos]
  664.   FSTP [OSin]
  665. //  FWAIT
  666. end;
  667. {$ENDIF}
  668. {$IFDEF PUREPASCAL}
  669. function FastSqrt(x: Single): Single;
  670. begin
  671.   Result := Sqrt(x);
  672. {$ELSE}
  673. function FastSqrt(x: Single): Single; assembler;
  674.   asm
  675.     MOV      EAX, x
  676.     SUB      EAX, 0C0800000H
  677.     TEST     EAX, 000800000H
  678.     MOV      ECX, EAX
  679.     JZ       @NoNeg
  680.     NEG      EAX
  681. @NoNeg:
  682.     AND      EAX, 000FFFFFFH
  683.     SHR      ECX, 1
  684.     MUL      EAX
  685.     NEG      EDX
  686.     LEA      EAX, [ECX+EDX*8]
  687.     LEA      EDX, [EDX+EDX*8]
  688.     LEA      EAX, [EAX+EDX*4]
  689.     mov      Result, eax
  690. {$ENDIF}
  691. end;
  692. function InvSqrt(x: Single): Single;
  693. {$IFDEF PUREPASCAL}
  694. begin
  695.   Result := 1/Sqrt(x);
  696. {$ELSE}
  697. var tmp: LongWord;
  698. begin
  699.   asm
  700.     mov        eax, OneAsInt
  701.     sub        eax, x
  702.     add        eax, OneAsInt2
  703.     shr        eax, 1
  704.     mov        tmp, eax
  705.   end;
  706.   Result := Single((@tmp)^) * (1.47 - 0.47 * x * Single((@tmp)^) * Single((@tmp)^));
  707. {$ENDIF}
  708. end;
  709. function Log2I(x: Integer): Integer;
  710. begin
  711.   Result := 0;
  712.   x := x shr 1;
  713.   while x > 0 do begin
  714.     x := x shr 1;
  715.     Inc(Result);
  716.   end;
  717. end;
  718. function IntPower(Base: Single; Exponent: Integer): Single;
  719. var a: Integer;
  720. begin
  721.   a := Abs(Exponent);
  722.   Result := 1;
  723.   while a > 0 do begin
  724.     while not Odd(a) do begin
  725.       Base := Sqr(Base);
  726.       a := a shr 1;
  727.     end;
  728.     Result := Result * Base;
  729.     Dec(a);
  730.   end;
  731.   if Exponent < 0 then Result := 1/Result
  732. end;
  733. function Power(const Base, Exponent: Single): Single;
  734. begin
  735.   if Exponent = 0.0 then
  736.     Result := 1.0 else
  737.       if (Base = 0.0) and (Exponent > 0.0) then
  738.         Result := 0.0 else
  739.           if (Frac(Exponent) = 0) and (Abs(Exponent) <= MaxInt) then
  740.             Result := IntPower(Base, Trunc(Exponent)) else
  741.               Result := Exp(Exponent * Ln(Base));
  742. end;
  743. function NextPowerOf2(x: Integer): Integer;
  744. begin
  745.   Result := x-1;
  746.   Result := Result or Result shr 1;
  747.   Result := Result or Result shr 2;
  748.   Result := Result or Result shr 4;
  749.   Result := Result or Result shr 8;
  750.   Result := Result or Result shr 16;
  751.   Inc(Result);
  752. end;
  753. function PosEx(const substr : AnsiString; const s : AnsiString; const start: Integer ) : Integer ; assembler;
  754. type StrRec = record allocSiz, refCnt, length: Longint; end;
  755. const skew = sizeof(StrRec);
  756. asm
  757. {     ->EAX     Pointer to substr               }
  758. {       EDX     Pointer to string               }
  759. {       ECX     Pointer to start      //cs      }
  760. {     <-EAX     Position of substr in s or 0    }
  761.         TEST    EAX,EAX
  762.         JE      @@noWork
  763.         TEST    EDX,EDX
  764.         JE      @@stringEmpty
  765.         TEST    ECX,ECX           //cs
  766.         JE      @@stringEmpty     //cs
  767.         PUSH    EBX
  768.         PUSH    ESI
  769.         PUSH    EDI
  770.         MOV     ESI,EAX                         { Point ESI to  }
  771.         MOV     EDI,EDX                         { Point EDI to  }
  772.         MOV     EBX,ECX        //cs save start
  773.         MOV     ECX,[EDI-skew].StrRec.length    { ECX =    }
  774.         PUSH    EDI                             { remember s position to calculate index }
  775.         CMP     EBX,ECX        //cs
  776.         JG      @@fail         //cs
  777.         MOV     EDX,[ESI-skew].StrRec.length    { EDX = bstr)          }
  778.         DEC     EDX                             { EDX = Length(substr) -   }
  779.         JS      @@fail                          { < 0 ? return             }
  780.         MOV     AL,[ESI]                        { AL = first char of       }
  781.         INC     ESI                             { Point ESI to 2'nd char of substr }
  782.         SUB     ECX,EDX                         { #positions in s to look  }
  783.                                                 { = Length(s) - Length(substr) + 1      }
  784.         JLE     @@fail
  785.         DEC     EBX       //cs
  786.         SUB     ECX,EBX   //cs
  787.         JLE     @@fail    //cs
  788.         ADD     EDI,EBX   //cs
  789. @@loop:
  790.         REPNE   SCASB
  791.         JNE     @@fail
  792.         MOV     EBX,ECX                         { save outer loop                }
  793.         PUSH    ESI                             { save outer loop substr pointer }
  794.         PUSH    EDI                             { save outer loop s              }
  795.         MOV     ECX,EDX
  796.         REPE    CMPSB
  797.         POP     EDI                             { restore outer loop s pointer      }
  798.         POP     ESI                             { restore outer loop substr pointer }
  799.         JE      @@found
  800.         MOV     ECX,EBX                         { restore outer loop nter    }
  801.         JMP     @@loop
  802. @@fail:
  803.         POP     EDX                             { get rid of saved s nter    }
  804.         XOR     EAX,EAX
  805.         JMP     @@exit
  806. @@stringEmpty:
  807.         XOR     EAX,EAX
  808.         JMP     @@noWork
  809. @@found:
  810.         POP     EDX                             { restore pointer to first char of s    }
  811.         MOV     EAX,EDI                         { EDI points of char after match        }
  812.         SUB     EAX,EDX                         { the difference is the correct index   }
  813. @@exit:
  814.         POP     EDI
  815.         POP     ESI
  816.         POP     EBX
  817. @@noWork:
  818. end;
  819. function Split(const Str, Delim: string; out Res: TStringArray; EmptyOK: Boolean): Integer;
  820. var i: Integer; s: string;
  821. begin
  822.   Result := 1;
  823.   s := Str;
  824.   while s <> '' do begin
  825.     i := Pos(Delim, s);
  826.     if i > 0 then begin
  827.       if (i > 1) or EmptyOK then begin
  828.         Inc(Result);
  829.         if Length(Res) < Result then SetLength(Res, Result);
  830.         Res[Result-2] := Copy(s, 1, i-1);
  831.       end;
  832.       s := Copy(s, i + Length(Delim), Length(s));
  833.     end else Break;
  834.   end;
  835.   if Length(Res) < Result then SetLength(Res, Result);
  836.   if EmptyOK or (s <> '') then Res[Result-1] := s else Dec(Result);
  837. end;
  838. function SplitA(const Str, Delim: AnsiString; out Res: TAnsiStringArray; EmptyOK: Boolean): Integer;
  839. // Splits s at all occurences of Delim. Res contains splitted strings; Returns number of parts
  840. { TODO -cOptimization : Optimize it }
  841. (*
  842. function explode(Delim: Char; const S: string): TStringArr; 
  843. var i, k, Len, Count: Integer; 
  844. begin 
  845.   Len := Length(S); 
  846.   Count := 0; 
  847.   for i := 1 to Len do 
  848.     if S[i] = Delim then Inc(Count); 
  849.   SetLength(Result, Count + 1); 
  850.   Count := 0; 
  851.   k := 1; 
  852.   for i := 1 to Len do 
  853.   begin 
  854.     if S[i] = Delim then 
  855.     begin 
  856.       Inc(Count); 
  857.       SetString(Result[Count-1], PChar(@S[k]), i-k); 
  858.       k := i + 1; 
  859.     end; 
  860.   end; // for i 
  861.   Inc(Count); 
  862.   SetString(Result[Count-1], PChar(@S[k]), Len-k+1);
  863. end;
  864. *)
  865. var i: Integer; s: AnsiString;
  866. begin
  867.   Result := 1;
  868.   s := Str;
  869.   while s <> '' do begin
  870.     i := Pos(Delim, s);
  871.     if i > 0 then begin
  872.       if (i > 1) or EmptyOK then begin
  873.         Inc(Result);
  874.         if Length(Res) < Result then SetLength(Res, Result);
  875.         Res[Result-2] := Copy(s, 1, i-1);
  876.       end;
  877.       s := Copy(s, i + Length(Delim), Length(s));
  878.     end else Break;
  879.   end;
  880.   if Length(Res) < Result then SetLength(Res, Result);
  881.   if EmptyOK or (s <> '') then Res[Result-1] := s else Dec(Result);
  882. end;
  883. function StringsToEnumA(Strings: array of TShortName; EmptyOK: Boolean): Ansistring;
  884. var i: Integer;
  885. begin                                                                       // Can be optimized
  886.   if Length(Strings) = 0 then
  887.     Result := ''
  888.   else begin
  889.     Result := Strings[0];
  890.     for i := 1 to High(Strings) do
  891.       if EmptyOK or (Strings[i] <> '') then
  892.         Result := Result + StringDelimiter + Strings[i];
  893.   end;  
  894. end;
  895. procedure RectIntersect(const ARect1, ARect2: TRect; out Result: TRect);
  896. begin
  897.   Result.Left   := MaxI(ARect1.Left,   ARect2.Left);
  898.   Result.Top    := MaxI(ARect1.Top,    ARect2.Top);
  899.   Result.Right  := MinI(ARect1.Right,  ARect2.Right);
  900.   Result.Bottom := MinI(ARect1.Bottom, ARect2.Bottom);
  901. end;
  902. function GetRectIntersect(const ARect1, ARect2: TRect): TRect;
  903. begin
  904.   RectIntersect(ARect1, ARect2, Result);
  905. end;
  906. function GetCorrectRect(ALeft, ATop, ARight, ABottom: Integer): TRect;
  907. begin
  908.   with Result do begin
  909.     Left := MinI(ALeft, ARight); Top := MinI(ATop, ABottom);
  910.     Right:= MaxI(ALeft, ARight); Bottom := MaxI(ATop, ABottom);
  911.   end;
  912. end;
  913. function IsInArea(const X, Y, X1, Y1, X2, Y2: Single): Boolean;
  914. begin
  915.   Result := (X >= X1) and (Y >= Y1) and (X < X2) and (Y < Y2);
  916. end;
  917. function IsInArea(const X, Y: Single; const Area: TArea): Boolean; overload;
  918. begin
  919.   Result := IsInArea(X, Y, Area.X1, Area.Y1, Area.X2, Area.Y2);
  920. end;
  921. function GetFileName(const FileName: string): string;
  922. var i: Integer;
  923. begin
  924.   if Pos('', FileName) = 0 then begin
  925.     if Pos(':', FileName) = 0 then Result := FileName else Result := Copy(FileName, Pos(':', FileName)+1, Length(FileName));
  926.   end else for i := Length(FileName) downto 1 do if FileName[i] = '' then begin
  927.     Result := Copy(FileName, i+1, Length(FileName)); Break;
  928.   end;
  929.   i := Pos('.', Result);
  930.   if i > 0 then Result := Copy(Result, 1, i-1);
  931. end;
  932. function GetDefaultUVMap: TUVMap;
  933. begin
  934.   Result := @DefaultUV;
  935. end;
  936. { TRefcountedContainer }
  937. destructor TRefcountedContainer.Destroy;
  938. var i: Integer;
  939. begin
  940.   for i := 0 to ObjCount-1 do if Assigned(ObjList[i]) then FreeAndNil(ObjList[i]);
  941.   for i := 0 to PtrCount-1 do if Assigned(PtrList[i]) then FreeMem(PtrList[i]);
  942.   ObjList := nil;
  943.   PtrList := nil;
  944.   inherited;
  945. end;
  946. function TRefcountedContainer.AddObject(Obj: TObject): TObject;
  947. begin
  948.   Inc(ObjCount);
  949.   if ObjCount > Length(ObjList) then SetLength(ObjList, MaxI(MinRefCContainerLength, Length(ObjList) * 2));
  950.   ObjList[ObjCount-1] := Obj;
  951.   Result := Obj;
  952. end;
  953. function TRefcountedContainer.AddPointer(Ptr: Pointer): Pointer;
  954. begin
  955.   Inc(PtrCount);
  956.   if PtrCount > Length(PtrList) then SetLength(PtrList, MaxI(MinRefCContainerLength, Length(PtrList) * 2));
  957.   PtrList[PtrCount-1] := Ptr;
  958.   Result := Ptr;
  959. end;
  960. procedure TRefcountedContainer.AddObjects(Objs: array of TObject);
  961. var i: Integer;
  962. begin
  963.   for i := Low(Objs) to High(Objs) do AddObject(Objs[i]);
  964. end;
  965. procedure TRefcountedContainer.AddPointers(Ptrs: array of Pointer);
  966. var i: Integer;
  967. begin
  968.   for i := Low(Ptrs) to High(Ptrs) do AddPointer(Ptrs[i]);
  969. end;
  970. { TStream }
  971. procedure TStream.SetPosition(const Value: Cardinal);
  972. begin
  973.   Seek(Value);
  974. end;
  975. procedure TStream.SetSize(const Value: Cardinal);
  976. begin
  977.   FSize := Value;
  978. end;
  979. function TStream.Seek(const NewPos: Cardinal): Boolean;
  980. begin
  981.   Result := NewPos <= Size;
  982.   if Result then FPosition := NewPos else ErrorHandler(TStreamError.Create('Invalid seek'));
  983. end;
  984. function TStream.ReadCheck(out Buffer; const Count: Cardinal): Boolean;
  985. begin
  986.   Result := Read(Buffer, Count) = Count;
  987. end;
  988. function TStream.WriteCheck(const Buffer; const Count: Cardinal): Boolean;
  989. begin
  990.   Result := Write(Buffer, Count) = Count;
  991. end;
  992. { TFileStream }
  993. constructor TFileStream.Create(const AFileName: string; const Usage: Integer; const ShareMode: Integer);
  994. begin
  995.   Opened := False;
  996.   if AFileName = '' then Exit;
  997.   FFileName := ExpandFileName(AFileName);
  998.   if Usage <> fuDoNotOpen then Open(Usage, ShareMode);
  999. end;
  1000. destructor TFileStream.Destroy;
  1001. begin
  1002.   Close;
  1003. end;
  1004. function TFileStream.Open(const Usage, ShareMode: Integer): Boolean;
  1005. var OldFileMode: Byte;
  1006. begin
  1007.   Opened := False;
  1008.   Result := False;
  1009.   OldFileMode := FileMode;
  1010. {$I-}
  1011.   case ShareMode of
  1012.     smAllowAll: FileMode := 0;
  1013.     smAllowRead: FileMode := fmShareDenyWrite;
  1014.     smExclusive: FileMode := fmShareExclusive;
  1015.   end;  
  1016.   AssignFile(F, FileName);
  1017.   case Usage of
  1018.     fuRead: begin
  1019.       FileMode := FileMode or fmOpenRead;
  1020.       Reset(F, 1);
  1021.     end;
  1022.     fuReadWrite: begin
  1023.       FileMode := FileMode or fmOpenReadWrite;
  1024.       Reset(F, 1);
  1025.       if (IOResult <> 0) and not FileExists(FFileName) then Rewrite(F, 1);
  1026.     end;
  1027.     fuWrite: Rewrite(F, 1);
  1028.     fuAppend: if FileExists(FileName) then begin
  1029.       FileMode := FileMode or fmOpenReadWrite;
  1030.       Reset(F, 1);
  1031.       FSize := FileSize(F);
  1032.       Seek(Size);
  1033.     end else Rewrite(F, 1);
  1034.   end;
  1035.   if IOResult <> 0 then Exit;
  1036.   FSize := FileSize(F);
  1037.   FileMode := OldFileMode;
  1038.   Opened := True;
  1039.   Result := True;
  1040. end;
  1041. procedure TFileStream.Close;
  1042. begin
  1043.   if Opened then CloseFile(F);
  1044.   Opened := False;
  1045. end;
  1046. function TFileStream.Seek(const NewPos: Cardinal): Boolean;
  1047. begin
  1048.   Result := False;
  1049.   if not Opened then if not ErrorHandler(TStreamError.Create('File stream is not opened')) then Exit;
  1050. {$I-}
  1051.   System.Seek(F, NewPos);
  1052.   Result := IOResult = 0;
  1053.   if Result then FPosition := NewPos;
  1054. end;
  1055. procedure TFileStream.SetSize(const Value: Cardinal);
  1056. begin
  1057.   if not Opened then if not ErrorHandler(TStreamError.Create('File stream is not opened')) then Exit;
  1058. {$I-}
  1059.   System.Seek(F, Value);
  1060.   if IOResult <> 0 then if not ErrorHandler(TStreamError.Create('Seek operation failed')) then Exit;
  1061.   System.Truncate(F);
  1062.   if IOResult <> 0 then if not ErrorHandler(TStreamError.Create('Truncate operation failed')) then Exit;
  1063.   Position := MinI(Value, FPosition);
  1064.   inherited;
  1065. end;
  1066. function TFileStream.Read(out Buffer; const Count: Cardinal): Cardinal;
  1067. begin
  1068.   Result := 0;
  1069.   if not Opened then if not ErrorHandler(TStreamError.Create('File stream is not opened')) then Exit;
  1070.   BlockRead(F, Buffer, Count, Result);
  1071.   if Result > 0 then FPosition := FPosition + Result;
  1072. end;
  1073. function TFileStream.Write(const Buffer; const Count: Cardinal): Cardinal;
  1074. begin
  1075.   Result := 0;
  1076.   if not Opened then if not ErrorHandler(TStreamError.Create('File stream is not opened')) then Exit;
  1077.   BlockWrite(F, Buffer, Count, Result);
  1078.   if Result > 0 then FPosition := FPosition + Result;
  1079.   FSize := FPosition;
  1080. end;
  1081. { TMemoryStream }
  1082. procedure TMemoryStream.SetCapacity(const NewCapacity: Cardinal);
  1083. begin
  1084.   if FCapacity = 0 then GetMem(FData, NewCapacity) else ReallocMem(FData, NewCapacity);
  1085.   FCapacity := NewCapacity;
  1086.   if FSize > FCapacity then FSize := FCapacity;
  1087.   Seek(FPosition);
  1088. end;
  1089. procedure TMemoryStream.Allocate(const NewSize: Cardinal);
  1090. const MinCap = $40; CapPower = 10; MaxCapStep = $10000;
  1091. var NewCapacity: Cardinal;
  1092. begin
  1093.   if NewSize > FCapacity then begin
  1094.     if NewSize < MinCap then
  1095.       NewCapacity := MinCap
  1096.     else if (NewSize < MaxCapStep) and (NewSize <= FCapacity*2) then
  1097.       NewCapacity := FCapacity*2
  1098.     else begin
  1099.       NewCapacity := (NewSize shr CapPower) shl CapPower;
  1100.       if NewCapacity < NewSize then Inc(NewCapacity, 1 shl CapPower);
  1101.     end;
  1102.     Assert(NewCapacity >= NewSize, ClassName + '.Allocate: Error');
  1103.     SetCapacity(NewCapacity);
  1104.   end;
  1105.   FSize := NewSize;
  1106. end;
  1107. procedure TMemoryStream.SetSize(const Value: Cardinal);
  1108. begin
  1109.   SetCapacity(Value);
  1110.   Position := MinI(Value, FPosition);
  1111.   inherited;
  1112. end;
  1113. constructor TMemoryStream.Create(AData: Pointer; const ASize: Cardinal);
  1114. begin
  1115.   FData := nil;
  1116.   if ASize > 0 then Allocate(ASize);
  1117.   if AData <> nil then Move(AData^, Data^, ASize);
  1118. end;
  1119. destructor TMemoryStream.Destroy;
  1120. begin
  1121.   FreeMem(Data);
  1122. end;
  1123. function TMemoryStream.Read(out Buffer; const Count: Cardinal): Cardinal;
  1124. begin
  1125.   Result := FSize - FPosition;
  1126.   if Result > Count then Result := Count;
  1127.   if Result > 0 then begin
  1128.     Move(Pointer(Cardinal(FData) + FPosition)^, Buffer, Result);
  1129.     Inc(FPosition, Result);
  1130.   end;
  1131. end;
  1132. function TMemoryStream.Write(const Buffer; const Count: Cardinal): Cardinal;
  1133. var NewPos: Cardinal;
  1134. begin
  1135.   NewPos := FPosition + Count;
  1136.   if NewPos > FSize then Allocate(NewPos);
  1137.   Move(Buffer, Pointer(Cardinal(FData) + FPosition)^, Count);
  1138.   FPosition := NewPos;
  1139.   Result := Count;
  1140. end;
  1141. { TStringStream }
  1142. constructor TAnsiStringStream.Create(AData: Pointer; const ASize: Cardinal; const AReturnsequence: TShortName = #13#10);
  1143. begin
  1144.   ReturnSequence := AReturnSequence;
  1145.   SetLength(Data, ASize);
  1146.   if (AData <> nil) and (ASize > 0) then Data := Copy(AnsiString(AData), 1, ASize);
  1147.   FSize := ASize;
  1148. end;
  1149. function TAnsiStringStream.Read(out Buffer; const Count: Cardinal): Cardinal;
  1150. begin
  1151.   Result := Count;
  1152.   AnsiString(Buffer) := Copy(Data, FPosition+1, Count);
  1153. end;
  1154. function TAnsiStringStream.Readln(out Buffer: AnsiString): Integer;
  1155. var i: Integer;
  1156. begin
  1157.   Result := 0;
  1158.   i := 0;
  1159.   Buffer := '';
  1160.   while (FPosition < Size) and (i < Length(ReturnSequence)) do begin
  1161.     if Data[FPosition+1] = ReturnSequence[i+1] then Inc(i) else begin
  1162.       if i > 0 then begin
  1163.         Buffer := Buffer + Copy(ReturnSequence, 1, i);
  1164.         i := 0;
  1165.         Buffer := Buffer + Data[FPosition+1];
  1166.       end else Buffer := Buffer + Data[FPosition+1];
  1167.     end;
  1168.     Inc(FPosition);
  1169.     Inc(Result);
  1170.   end;
  1171. end;
  1172. function TAnsiStringStream.Write(const Buffer; const Count: Cardinal): Cardinal;
  1173. begin
  1174.   Result := Count;
  1175.   SetLength(Data, FPosition);
  1176.   Data := Data + Copy(AnsiString(Buffer), 1, Count);
  1177.   FPosition := FPosition + Count;
  1178.   FSize := FPosition;
  1179. end;
  1180. function TAnsiStringStream.Writeln(const Buffer: AnsiString): Integer;
  1181. var p: Pointer; BufLen: Integer;
  1182. begin
  1183.   BufLen := Length(Buffer);
  1184.   Result := BufLen + Length(ReturnSequence);
  1185.   p := @Buffer[1];
  1186.   Write(p, BufLen);
  1187.   p := @ReturnSequence[1];
  1188.   Write(p, Length(ReturnSequence));
  1189. end;
  1190. { TRandomGenerator }
  1191. constructor TRandomGenerator.Create;
  1192. begin
  1193.   SetMaxSequence(8);
  1194.   CurrentSequence := 0;
  1195.   InitSequence(1, 1);
  1196. end;
  1197. procedure TRandomGenerator.InitSequence(Chain, Seed: Longword);
  1198. begin
  1199.   RandomChain[FCurrentSequence] := Chain;
  1200.   RandomSeed [FCurrentSequence] := Seed;
  1201. end;
  1202. function TRandomGenerator.GenerateRaw: Longword;
  1203. begin
  1204. {$Q-}
  1205.   RandomSeed[FCurrentSequence] := 97781173 * RandomSeed[FCurrentSequence] + RandomChain[FCurrentSequence];
  1206.   Result := RandomSeed[FCurrentSequence];
  1207. end;
  1208. function TRandomGenerator.Rnd(Range: Single): Single;
  1209. const RandomNorm = 1/$FFFFFFFF;
  1210. begin
  1211.   Result := GenerateRaw * RandomNorm * Range;
  1212. end;
  1213. function TRandomGenerator.RndSymm(Range: Single): Single;
  1214. begin
  1215.   Result := Rnd(2*Range) - Range;
  1216. end;
  1217. function TRandomGenerator.RndI(Range: Integer): Integer;
  1218. begin
  1219.   Result := Round(Rnd(MaxI(0, Range-1)));
  1220. end;
  1221. procedure TRandomGenerator.SetMaxSequence(AMaxSequence: Integer);
  1222. begin
  1223.   SetLength(RandomSeed, AMaxSequence);
  1224.   SetLength(RandomChain, AMaxSequence);
  1225. end;
  1226. procedure TRandomGenerator.SetCurrentSequence(const Value: Cardinal);
  1227. begin
  1228.   FCurrentSequence := Value;
  1229.   if Integer(Value) > High(RandomSeed) then SetMaxSequence(Value+1);
  1230. end;
  1231. {--------------------------}
  1232. procedure FillDWord(var Dest; Count: Cardinal; Value: LongWord);
  1233. {$IFDEF PUREPASCAL}
  1234. begin
  1235.   FillChar(Dest, Count * 4, Value);
  1236. {$ELSE}
  1237. assembler;
  1238. asm
  1239. {     ->EAX     Pointer to destination  }
  1240. {       EDX     count   }
  1241. {       CX      value   }
  1242.         PUSH    EDI
  1243.         MOV     EDI,EAX { Point EDI to destination              }
  1244.         MOV     EAX,ECX
  1245.         CLD
  1246.         MOV     ECX,EDX
  1247.         REP     STOSD   { Fill count dwords       }
  1248. @@exit:
  1249.         POP     EDI
  1250. {$ENDIF}
  1251. end;
  1252. function CompareValues(v1, v2: Extended): Integer;
  1253. begin
  1254.   if v1 > v2 then Result := 1 else
  1255.     if v1 < v2 then Result := -1 else
  1256.       Result := 0;
  1257. end;
  1258. function CompareDates(ADate: TDateTime; Year, Month, Day: Integer): Integer;
  1259. var AYear, AMonth, ADay: Word;
  1260. begin
  1261.   DecodeDate(ADate, AYear, AMonth, ADay);
  1262.   Result := CompareValues(AYear * 512 + AMonth * 32 + ADay, Year * 512 + Month * 32 + Day);
  1263. end;
  1264. function HexStrToIntDef(const s: string; Default: Longword): Longword;
  1265. var E: Integer;
  1266. begin
  1267.   Val('0x' + s, Result, E);
  1268.   if E <> 0 then Result := Default;
  1269. end;
  1270. function ColorStrToIntDef(const color: string; Default: Longword): Longword;
  1271. var E: Integer;
  1272. begin
  1273.   if (color <> '') and (color[1] = '#') then begin
  1274.     Val('0x' + Copy(color, 2, Length(color)), Result, E);
  1275.     if E <> 0 then Result := Default;
  1276.   end else Result := Default;  
  1277. end;
  1278. {$HINTS OFF}
  1279. function IsDecimalInteger(const s: string): Boolean;
  1280. var E, R: Integer;
  1281. begin
  1282.   Val(s, R, E);
  1283.   Result := E = 0;
  1284. end;
  1285. {$HINTS ON}
  1286. function IsFloat(const s: string): Boolean;
  1287. begin
  1288.   Result := Abs(StrToFloatDef(s, 0) - StrToFloatDef(s, 1)) < 0.5;
  1289. end;
  1290. {$HINTS OFF}
  1291. function IsColor(const s: string): Boolean;
  1292. var E, R: Integer;
  1293. begin
  1294.   Result := False;
  1295.   if (s = '') or (s[1] <> '#') then Exit;
  1296.   Val('0x' + Copy(s, 2, Length(s)), R, E);
  1297.   Result := E = 0;
  1298. end;
  1299. {$HINTS ON}
  1300. function isSameGUID(GUID1, GUID2: TGUID): Boolean;
  1301. begin
  1302.   Result := (GUID1.D1 = GUID2.D1) and (GUID1.D2 = GUID2.D2) and (GUID1.D3 = GUID2.D3) and
  1303.             (GUID1.D4[0] = GUID2.D4[0]) and (GUID1.D4[1] = GUID2.D4[1]) and (GUID1.D4[2] = GUID2.D4[2]) and (GUID1.D4[3] = GUID2.D4[3]) and
  1304.             (GUID1.D4[4] = GUID2.D4[4]) and (GUID1.D4[5] = GUID2.D4[5]) and (GUID1.D4[6] = GUID2.D4[6]) and (GUID1.D4[7] = GUID2.D4[7]);
  1305. end;
  1306. function GetBytesPerPixel(PixelFormat: Cardinal): Integer;
  1307. begin
  1308.   case PixelFormat of
  1309.     pfA8R8G8B8, pfX8R8G8B8, pfX8L8V8U8, pfQ8W8V8U8, pfV16U16, pfW11V11U10, pfD32, pfD24S8, pfD24X8, pfD24X4S4, pfA8B8G8R8: Result := 4;
  1310.     pfR8G8B8, pfB8G8R8: Result := 3;
  1311.     pfR5G6B5, pfX1R5G5B5, pfA1R5G5B5, pfA4R4G4B4, pfX4R4G4B4, pfA8P8, pfA8L8, pfV8U8, pfL6V5U5, pfD16_LOCKABLE, pfD15S1, pfD16: Result := 2;
  1312.     pfA8, pfP8, pfL8, pfA4L4: Result := 1;
  1313.     else Result := 0;
  1314.   end;
  1315. end;
  1316. function GetBitsPerPixel(PixelFormat: Cardinal): Integer;
  1317. begin
  1318.   Result := GetBytesPerPixel(PixelFormat) * 8;
  1319. end;
  1320. function IntToStrA(Value: Int64): AnsiString;
  1321. begin
  1322.   Result := AnsiString(IntToStr(Value));
  1323. end;
  1324. function IntToHexA(Value: Int64; Digits: Integer): AnsiString;
  1325. begin
  1326.   Result := AnsiString(IntToHex(Int64(Value), Digits));
  1327. end;
  1328. function FloatToStrA(Value: Extended): AnsiString;
  1329. begin
  1330.   Result := AnsiString(FloatToStr(Value));
  1331. end;
  1332. function FormatA(const Format: string; const Args: array of const): AnsiString;
  1333. begin
  1334.   Result := AnsiString(SysUtils.Format(Format, Args));
  1335. end;
  1336. function StrToFloatDefA(const S: AnsiString; const Default: Extended): Extended;
  1337. begin
  1338.   Result := StrToFloatDef(string(S), Default);
  1339. end;
  1340. function TrimSpacesA(ts: string): AnsiString;
  1341. begin
  1342.   Result := AnsiString(TrimSpaces(ts));
  1343. end;
  1344. function TrimSpaces(ts: string): string;
  1345. const CharsToTrim = ' '#9#0;
  1346. var LeadingSpaces, TrailingSpaces: Integer;
  1347. begin
  1348.   Result := '';
  1349.   LeadingSpaces := 0;
  1350.   while (LeadingSpaces < Length(ts)) and (Pos(ts[LeadingSpaces+1], CharsToTrim) > 0) do Inc(LeadingSpaces);
  1351.   TrailingSpaces := 0;
  1352.   while ((Length(ts)-TrailingSpaces) > LeadingSpaces) and (Pos(ts[Length(ts)-TrailingSpaces], CharsToTrim) > 0) do Inc(TrailingSpaces);
  1353.   Result := Copy(ts, LeadingSpaces+1, Length(ts) - LeadingSpaces - TrailingSpaces);
  1354. end;
  1355. function GetLastCharPos(c: Char; const s: string): Integer;
  1356. begin
  1357.   for Result := Length(s) downto 1 do if s[Result] = c then Exit;
  1358.   Result := -1;
  1359. end;
  1360. procedure QuickSortStrInd(N: Integer; Values: TAnsiStringArray; Inds: TIndArray; Acc: Boolean);
  1361. type _QSDataType = string;
  1362. {$DEFINE COMPARABLE}
  1363. {$I basics_quicksort_ind.inc}
  1364. {$IFNDEF ForCodeNavigationWork} begin end; {$ENDIF}
  1365. procedure QuickSortIntInd(N: Integer; Values, Inds: TIndArray; Acc: Boolean);
  1366. type _QSDataType = Integer;
  1367. {$DEFINE COMPARABLE}
  1368. {$I basics_quicksort_ind.inc}
  1369. {$IFNDEF ForCodeNavigationWork} begin end; {$ENDIF}
  1370. procedure QuickSortSInd(N: Integer; Values: TSingleArray; Inds: TIndArray; Acc: Boolean);
  1371. type _QSDataType = Single;
  1372. {$DEFINE COMPARABLE}
  1373. {$I basics_quicksort_ind.inc}
  1374. {$IFNDEF ForCodeNavigationWork} begin end; {$ENDIF}
  1375. procedure QuickSortStr(N: Integer; Values: TAnsiStringArray);
  1376. type _QSDataType = AnsiString;
  1377. {$DEFINE COMPARABLE}
  1378. {$I basics_quicksort.inc}
  1379. {$IFNDEF ForCodeNavigationWork} begin end; {$ENDIF}
  1380. procedure QuickSortInt(N: Integer; Values: TIndArray);
  1381. type _QSDataType = Integer;
  1382. {$DEFINE COMPARABLE}
  1383. {$I basics_quicksort.inc}
  1384. {$IFNDEF ForCodeNavigationWork} begin end; {$ENDIF}
  1385. procedure QuickSortS(N: Integer; Values: TSingleArray);
  1386. type _QSDataType = Single;
  1387. {$DEFINE COMPARABLE}
  1388. {$I basics_quicksort.inc}
  1389. {$IFNDEF ForCodeNavigationWork} begin end; {$ENDIF}
  1390. function AssureFloatFormat(const s: string): string;
  1391. var i: Integer;
  1392. begin
  1393.   SetLength(Result, Length(s));
  1394.   for i := 1 to Length(s) do
  1395.    if (s[i] <> '.') and (s[i] <> ',') then Result[i] := s[i] else Result[i] := DecimalSeparator;
  1396. end;
  1397. function StrFormat(const s: string; Args: array of string): string;
  1398. {$IFDEF RUSSIAN}
  1399. const GenderStr = '戽';
  1400. var GenderI  : Integer;
  1401. {$ENDIF}
  1402. var i, ArgI, PadegI: Integer; ArgState: Boolean;
  1403.   function ReadNumber: Integer;
  1404.   var rs: string;
  1405.   begin
  1406.     rs := '';
  1407.     Inc(i);
  1408.     while s[i] in ['0'..'9'] do begin
  1409.       rs := rs + s[i];
  1410.       Inc(i);
  1411.     end;
  1412.     Dec(i);
  1413.     Result := StrToIntDef(rs, -1);
  1414.   end;
  1415. begin
  1416.   ArgState := False;
  1417.   Result := '';
  1418.   ArgI := 1; PadegI := 1; {$IFDEF RUSSIAN} GenderI := 1; {$ENDIF}
  1419.   i := 1;
  1420.   while i <= Length(s) do begin
  1421.     if ArgState then begin
  1422.       case s[i] of
  1423.         'A': begin
  1424.           ArgI := ReadNumber;
  1425.           if (ArgI < 1) or (ArgI > Length(Args)) then ArgI := 1;
  1426.         end;
  1427. {$IFDEF RUSSIAN}
  1428.         'P': begin
  1429.           PadegI := ReadNumber;
  1430.           if (PadegI < 1) or (PadegI > MaxPadeg) then PadegI := 1;
  1431.         end;
  1432.         'G': begin
  1433.           GenderI := ReadNumber;
  1434.           if (GenderI < 1) or (GenderI > 2) then GenderI := 1;
  1435.         end;
  1436. {$ENDIF}
  1437.       end;
  1438.     end else if s[i] <> '%' then Result := Result + s[i];
  1439.     if s[i] = '%' then begin
  1440.       if ArgState and (ArgI > 0) and (ArgI <= Length(Args)) and (Length(Args[ArgI-1]) > 0) then begin
  1441.         if PadegI = 1 then Result := Result + Args[ArgI-1]
  1442. {$IFDEF RUSSIAN}
  1443.          else begin
  1444.            if Ord(Args[ArgI-1][Length(Args[ArgI-1])]) <= 127 then
  1445.             Result := Result + GetFIO('', Args[ArgI-1]+'''', '', GenderStr[GenderI], PadegI) else
  1446.              Result := Result + GetFIO('', Args[ArgI-1], '', GenderStr[GenderI], PadegI);
  1447.          end;
  1448. {$ENDIF};
  1449.         ArgI := MinI(ArgI+1, Length(Args));
  1450.       end;
  1451.       ArgState := not ArgState;
  1452.     end;
  1453.     Inc(i);
  1454.   end;
  1455. end;
  1456. function ExtractStr(s, Sig: string): string;
  1457. var p1, p2: Integer; s1: string;
  1458. begin
  1459.   Result := '';
  1460.   p1 := Pos(Sig, s);
  1461.   if p1 = 0 then Exit;
  1462.   s1 := Copy(s, p1 + Length(Sig), Length(s));
  1463.   p2 := Pos(#10, s1);
  1464.   if (p2 = 0) or ( (Pos(#13, s1) > 0) and (Pos(#13, s1) < p2) ) then p2 := Pos(#13, s1);
  1465.   if p2 = 0 then p2 := Length(s1)+1;
  1466.   if p2 < 2 then Exit;
  1467.   Result := TrimSpaces(Copy(s1, 1, p2-1));
  1468. end;
  1469. function IsCharIn(C: AnsiChar; const CharSet: TSysCharSet): Boolean;
  1470. begin
  1471.   Result := C in CharSet;
  1472. end;
  1473. function StrToRealDef(const s: string; Default: Extended): Extended;
  1474. var OldDecimalSeparator: Char;
  1475. begin
  1476.   OldDecimalSeparator := DecimalSeparator;
  1477.   DecimalSeparator := GeneralDecimalSeparator;
  1478.   Result := StrToFloatDef(s, Default);
  1479.   DecimalSeparator := OldDecimalSeparator;
  1480. end;
  1481. function RealToStr(Value: Extended): string;
  1482. var OldDecimalSeparator: Char;
  1483. begin
  1484.   OldDecimalSeparator := DecimalSeparator;
  1485.   DecimalSeparator := GeneralDecimalSeparator;
  1486.   Result := FloatToStrF(Value, ffGeneral, 7, 0);
  1487.   DecimalSeparator := OldDecimalSeparator;
  1488. end;
  1489. function IsReal(const s: string): Boolean;                           // Tests with current decimal separator
  1490. begin
  1491.   Result := Abs(StrToRealDef(s, 0) - StrToRealDef(s, 1)) < 0.5;
  1492. end;
  1493. function SaveString(Stream: TStream; const s: AnsiString): Boolean;
  1494. var l: Integer;
  1495. begin
  1496.   l := Length(s);
  1497.   Result := Stream.WriteCheck(l, SizeOf(l));
  1498.   if Result and (l > 0) then Result := Stream.WriteCheck(Pointer(s)^, l * SizeOf(AnsiChar));
  1499. end;
  1500. function SaveString(Stream: TStream; const s: WideString): Boolean;
  1501. var l: Integer;
  1502. begin
  1503.   l := Length(s);
  1504.   Result := Stream.WriteCheck(l, SizeOf(l));
  1505.   if Result and (l > 0) then Result := Stream.WriteCheck(Pointer(s)^, l * SizeOf(WideChar));
  1506. end;
  1507. function LoadString(Stream: TStream; out s: AnsiString): Boolean;
  1508. var l: Cardinal;
  1509. begin
  1510.   Result := Stream.Read(l, SizeOf(l)) = SizeOf(l);
  1511.   if Result then begin
  1512.     SetLength(s, l);
  1513.     if l > 0 then Result := Stream.Read(Pointer(s)^, l * SizeOf(AnsiChar)) = l * SizeOf(AnsiChar);
  1514.   end;
  1515. end;
  1516. function LoadString(Stream: TStream; out   s: WideString): Boolean;
  1517. var l: Cardinal;
  1518. begin
  1519.   Result := Stream.Read(l, SizeOf(l)) = SizeOf(l);
  1520.   if Result then begin
  1521.     SetLength(s, l);
  1522.     if l > 0 then Result := Stream.Read(Pointer(s)^, l * SizeOf(WideChar)) = l * SizeOf(WideChar);
  1523.   end;
  1524. end;
  1525. const CRCTable: array[0..255] of Longword =
  1526.      ($00000000, $77073096, $EE0E612C, $990951BA,
  1527.       $076DC419, $706AF48F, $E963A535, $9E6495A3,
  1528.       $0EDB8832, $79DCB8A4, $E0D5E91E, $97D2D988,
  1529.       $09B64C2B, $7EB17CBD, $E7B82D07, $90BF1D91,
  1530.       $1DB71064, $6AB020F2, $F3B97148, $84BE41DE,
  1531.       $1ADAD47D, $6DDDE4EB, $F4D4B551, $83D385C7,
  1532.       $136C9856, $646BA8C0, $FD62F97A, $8A65C9EC,
  1533.       $14015C4F, $63066CD9, $FA0F3D63, $8D080DF5,
  1534.       $3B6E20C8, $4C69105E, $D56041E4, $A2677172,
  1535.       $3C03E4D1, $4B04D447, $D20D85FD, $A50AB56B,
  1536.       $35B5A8FA, $42B2986C, $DBBBC9D6, $ACBCF940,
  1537.       $32D86CE3, $45DF5C75, $DCD60DCF, $ABD13D59,
  1538.       $26D930AC, $51DE003A, $C8D75180, $BFD06116,
  1539.       $21B4F4B5, $56B3C423, $CFBA9599, $B8BDA50F,
  1540.       $2802B89E, $5F058808, $C60CD9B2, $B10BE924,
  1541.       $2F6F7C87, $58684C11, $C1611DAB, $B6662D3D,
  1542.       $76DC4190, $01DB7106, $98D220BC, $EFD5102A,
  1543.       $71B18589, $06B6B51F, $9FBFE4A5, $E8B8D433,
  1544.       $7807C9A2, $0F00F934, $9609A88E, $E10E9818,
  1545.       $7F6A0DBB, $086D3D2D, $91646C97, $E6635C01,
  1546.       $6B6B51F4, $1C6C6162, $856530D8, $F262004E,
  1547.       $6C0695ED, $1B01A57B, $8208F4C1, $F50FC457,
  1548.       $65B0D9C6, $12B7E950, $8BBEB8EA, $FCB9887C,
  1549.       $62DD1DDF, $15DA2D49, $8CD37CF3, $FBD44C65,
  1550.       $4DB26158, $3AB551CE, $A3BC0074, $D4BB30E2,
  1551.       $4ADFA541, $3DD895D7, $A4D1C46D, $D3D6F4FB,
  1552.       $4369E96A, $346ED9FC, $AD678846, $DA60B8D0,
  1553.       $44042D73, $33031DE5, $AA0A4C5F, $DD0D7CC9,
  1554.       $5005713C, $270241AA, $BE0B1010, $C90C2086,
  1555.       $5768B525, $206F85B3, $B966D409, $CE61E49F,
  1556.       $5EDEF90E, $29D9C998, $B0D09822, $C7D7A8B4,
  1557.       $59B33D17, $2EB40D81, $B7BD5C3B, $C0BA6CAD,
  1558.       $EDB88320, $9ABFB3B6, $03B6E20C, $74B1D29A,
  1559.       $EAD54739, $9DD277AF, $04DB2615, $73DC1683,
  1560.       $E3630B12, $94643B84, $0D6D6A3E, $7A6A5AA8,
  1561.       $E40ECF0B, $9309FF9D, $0A00AE27, $7D079EB1,
  1562.       $F00F9344, $8708A3D2, $1E01F268, $6906C2FE,
  1563.       $F762575D, $806567CB, $196C3671, $6E6B06E7,
  1564.       $FED41B76, $89D32BE0, $10DA7A5A, $67DD4ACC,
  1565.       $F9B9DF6F, $8EBEEFF9, $17B7BE43, $60B08ED5,
  1566.       $D6D6A3E8, $A1D1937E, $38D8C2C4, $4FDFF252,
  1567.       $D1BB67F1, $A6BC5767, $3FB506DD, $48B2364B,
  1568.       $D80D2BDA, $AF0A1B4C, $36034AF6, $41047A60,
  1569.       $DF60EFC3, $A867DF55, $316E8EEF, $4669BE79,
  1570.       $CB61B38C, $BC66831A, $256FD2A0, $5268E236,
  1571.       $CC0C7795, $BB0B4703, $220216B9, $5505262F,
  1572.       $C5BA3BBE, $B2BD0B28, $2BB45A92, $5CB36A04,
  1573.       $C2D7FFA7, $B5D0CF31, $2CD99E8B, $5BDEAE1D,
  1574.       $9B64C2B0, $EC63F226, $756AA39C, $026D930A,
  1575.       $9C0906A9, $EB0E363F, $72076785, $05005713,
  1576.       $95BF4A82, $E2B87A14, $7BB12BAE, $0CB61B38,
  1577.       $92D28E9B, $E5D5BE0D, $7CDCEFB7, $0BDBDF21,
  1578.       $86D3D2D4, $F1D4E242, $68DDB3F8, $1FDA836E,
  1579.       $81BE16CD, $F6B9265B, $6FB077E1, $18B74777,
  1580.       $88085AE6, $FF0F6A70, $66063BCA, $11010B5C,
  1581.       $8F659EFF, $F862AE69, $616BFFD3, $166CCF45,
  1582.       $A00AE278, $D70DD2EE, $4E048354, $3903B3C2,
  1583.       $A7672661, $D06016F7, $4969474D, $3E6E77DB,
  1584.       $AED16A4A, $D9D65ADC, $40DF0B66, $37D83BF0,
  1585.       $A9BCAE53, $DEBB9EC5, $47B2CF7F, $30B5FFE9,
  1586.       $BDBDF21C, $CABAC28A, $53B39330, $24B4A3A6,
  1587.       $BAD03605, $CDD70693, $54DE5729, $23D967BF,
  1588.       $B3667A2E, $C4614AB8, $5D681B02, $2A6F2B94,
  1589.       $B40BBE37, $C30C8EA1, $5A05DF1B, $2D02EF8D);
  1590. procedure CalcCRC32(Bytes: PByteBuffer; ByteCount: Cardinal; var CRCValue: Longword);
  1591. var i: Cardinal;
  1592. begin
  1593.   for i := 0 to ByteCount - 1 do
  1594.     CRCvalue := (CRCvalue shr 8) xor CRCTable[Bytes^[i] xor (CRCvalue and $000000FF)];
  1595. end;
  1596. function ForEachFile(const PathAndMask: string; AttributeFilter: Integer; Delegate: TFileDelegate): Integer;
  1597. var SR: SysUtils.TSearchRec; Dir: string;
  1598. begin
  1599.   Result := 0;
  1600.   if SysUtils.FindFirst(PathAndMask, AttributeFilter, SR) = 0 then begin
  1601.     Dir := ExtractFilePath(PathAndMask);
  1602.     repeat
  1603.       Inc(Result);
  1604.       if not Delegate(Dir + SR.Name) then Break;
  1605.     until SysUtils.FindNext(SR) <> 0;
  1606.     SysUtils.FindClose(SR);
  1607.   end;
  1608. end;
  1609. var err: TError;
  1610. initialization
  1611.   ErrorHandler := {$IFDEF OBJFPCEnable}@{$ENDIF}Err.DefaultErrorHandler;
  1612. end.