ImagingUtility.pas 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597
  1. {
  2. $Id$
  3. Vampyre Imaging Library
  4. by Marek Mauder
  5. http://imaginglib.sourceforge.net
  6. The contents of this file are used with permission, subject to the Mozilla
  7. Public License Version 1.1 (the "License"); you may not use this file except
  8. in compliance with the License. You may obtain a copy of the License at
  9. http://www.mozilla.org/MPL/MPL-1.1.html
  10. Software distributed under the License is distributed on an "AS IS" basis,
  11. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
  12. the specific language governing rights and limitations under the License.
  13. Alternatively, the contents of this file may be used under the terms of the
  14. GNU Lesser General Public License (the "LGPL License"), in which case the
  15. provisions of the LGPL License are applicable instead of those above.
  16. If you wish to allow use of your version of this file only under the terms
  17. of the LGPL License and not to allow others to use your version of this file
  18. under the MPL, indicate your decision by deleting the provisions above and
  19. replace them with the notice and other provisions required by the LGPL
  20. License. If you do not delete the provisions above, a recipient may use
  21. your version of this file under either the MPL or the LGPL License.
  22. For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
  23. }
  24. { This unit contains utility functions and types for Imaging library.}
  25. unit ImagingUtility;
  26. {$I ImagingOptions.inc}
  27. interface
  28. uses
  29. SysUtils, Classes, Types;
  30. const
  31. STrue = 'True';
  32. SFalse = 'False';
  33. type
  34. TByteArray = array[0..MaxInt - 1] of Byte;
  35. PByteArray = ^TByteArray;
  36. TWordArray = array[0..MaxInt div 2 - 1] of Word;
  37. PWordArray = ^TWordArray;
  38. TLongIntArray = array[0..MaxInt div 4 - 1] of LongInt;
  39. PLongIntArray = ^TLongIntArray;
  40. TLongWordArray = array[0..MaxInt div 4 - 1] of LongWord;
  41. PLongWordArray = ^TLongWordArray;
  42. TInt64Array = array[0..MaxInt div 8 - 1] of Int64;
  43. PInt64Array = ^TInt64Array;
  44. TSingleArray = array[0..MaxInt div 4 - 1] of Single;
  45. PSingleArray = ^TSingleArray;
  46. TBooleanArray = array[0..MaxInt - 1] of Boolean;
  47. PBooleanArray = ^TBooleanArray;
  48. TDynIntegerArray = array of Integer;
  49. TDynBooleanArray = array of Boolean;
  50. TWordRec = packed record
  51. case Integer of
  52. 0: (WordValue: Word);
  53. 1: (Low, High: Byte);
  54. end;
  55. PWordRec = ^TWordRec;
  56. TWordRecArray = array[0..MaxInt div 2 - 1] of TWordRec;
  57. PWordRecArray = ^TWordRecArray;
  58. TLongWordRec = packed record
  59. case Integer of
  60. 0: (LongWordValue: LongWord);
  61. 1: (Low, High: Word);
  62. { Array variants - Index 0 means lowest significant byte (word, ...).}
  63. 2: (Words: array[0..1] of Word);
  64. 3: (Bytes: array[0..3] of Byte);
  65. end;
  66. PLongWordRec = ^TLongWordRec;
  67. TLongWordRecArray = array[0..MaxInt div 4 - 1] of TLongWordRec;
  68. PLongWordRecArray = ^TLongWordRecArray;
  69. TInt64Rec = packed record
  70. case Integer of
  71. 0: (Int64Value: Int64);
  72. 1: (Low, High: LongWord);
  73. { Array variants - Index 0 means lowest significant byte (word, ...).}
  74. 2: (Words: array[0..3] of Word);
  75. 3: (Bytes: array[0..7] of Byte);
  76. end;
  77. PInt64Rec = ^TInt64Rec;
  78. TInt64RecArray = array[0..MaxInt div 8 - 1] of TInt64Rec;
  79. PInt64RecArray = ^TInt64RecArray;
  80. TFloatHelper = record
  81. Data1: Int64;
  82. Data2: Int64;
  83. end;
  84. PFloatHelper = ^TFloatHelper;
  85. TChar2 = array[0..1] of Char;
  86. TChar3 = array[0..2] of Char;
  87. TChar4 = array[0..3] of Char;
  88. TChar8 = array[0..7] of Char;
  89. { Options for BuildFileList function:
  90. flFullNames - file names in result will have full path names
  91. (ExtractFileDir(Path) + FileName)
  92. flRelNames - file names in result will have names relative to
  93. ExtractFileDir(Path) dir
  94. flRecursive - adds files in subdirectories found in Path.}
  95. TFileListOption = (flFullNames, flRelNames, flRecursive);
  96. TFileListOptions = set of TFileListOption;
  97. { Frees class instance and sets its reference to nil.}
  98. procedure FreeAndNil(var Obj);
  99. { Frees pointer and sets it to nil.}
  100. procedure FreeMemNil(var P); {$IFDEF USE_INLINE}inline;{$ENDIF}
  101. { Replacement of standard System.FreeMem procedure which checks if P is nil
  102. (this is only needed for Free Pascal, Delphi makes checks in its FreeMem).}
  103. procedure FreeMem(P: Pointer); {$IFDEF USE_INLINE}inline;{$ENDIF}
  104. { Returns current exception object. Do not call outside exception handler.}
  105. function GetExceptObject: Exception; {$IFDEF USE_INLINE}inline;{$ENDIF}
  106. { Returns time value with microsecond resolution.}
  107. function GetTimeMicroseconds: Int64;
  108. { Returns time value with milisecond resolution.}
  109. function GetTimeMilliseconds: Int64;
  110. { Returns file extension (without "." dot)}
  111. function GetFileExt(const FileName: string): string;
  112. { Returns file name of application's executable.}
  113. function GetAppExe: string;
  114. { Returns directory where application's exceutable is located without
  115. path delimiter at the end.}
  116. function GetAppDir: string;
  117. { Returns True if FileName matches given Mask with optional case sensitivity.
  118. Mask can contain ? and * special characters: ? matches
  119. one character, * matches zero or more characters.}
  120. function MatchFileNameMask(const FileName, Mask: string; CaseSensitive: Boolean = False): Boolean;
  121. { This function fills Files string list with names of files found
  122. with FindFirst/FindNext functions (See details on Path/Atrr here).
  123. - BuildFileList('c:\*.*', faAnyFile, List, [flRecursive]) returns
  124. list of all files (only name.ext - no path) on C drive
  125. - BuildFileList('d:\*.*', faDirectory, List, [flFullNames]) returns
  126. list of all directories (d:\dirxxx) in root of D drive.}
  127. function BuildFileList(Path: string; Attr: LongInt; Files: TStrings;
  128. Options: TFileListOptions = []): Boolean;
  129. { Similar to RTL's Pos function but with optional Offset where search will start.
  130. This function is in the RTL StrUtils unit but }
  131. function PosEx(const SubStr, S: string; Offset: LongInt = 1): LongInt;
  132. { Same as PosEx but without case sensitivity.}
  133. function PosNoCase(const SubStr, S: string; Offset: LongInt = 1): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
  134. { Returns a sub-string from S which is followed by
  135. Sep separator and deletes the sub-string from S including the separator.}
  136. function StrToken(var S: string; Sep: Char): string;
  137. { Same as StrToken but searches from the end of S string.}
  138. function StrTokenEnd(var S: string; Sep: Char): string;
  139. { Returns string representation of integer number (with digit grouping).}
  140. function IntToStrFmt(const I: Int64): string;
  141. { Returns string representation of float number (with digit grouping).}
  142. function FloatToStrFmt(const F: Double; Precision: Integer = 2): string;
  143. { Clamps integer value to range <Min, Max>}
  144. function ClampInt(Number: LongInt; Min, Max: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
  145. { Clamps float value to range <Min, Max>}
  146. function ClampFloat(Number: Single; Min, Max: Single): Single; {$IFDEF USE_INLINE}inline;{$ENDIF}
  147. { Clamps integer value to Byte boundaries.}
  148. function ClampToByte(Value: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
  149. { Clamps integer value to Word boundaries.}
  150. function ClampToWord(Value: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
  151. { Returns True if Num is power of 2.}
  152. function IsPow2(Num: LongInt): Boolean; {$IFDEF USE_INLINE}inline;{$ENDIF}
  153. { Returns next power of 2 greater than or equal to Num
  154. (if Num itself is power of 2 then it retuns Num).}
  155. function NextPow2(Num: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
  156. { Raises 2 to the given integer power (in range [0, 30]).}
  157. function Pow2Int(Exponent: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
  158. { Raises Base to any power.}
  159. function Power(const Base, Exponent: Single): Single;
  160. { Returns log base 2 of integer X (max 2^30) or -1 if X is not power of 2.}
  161. function Log2Int(X: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
  162. { Returns log base 2 of X.}
  163. function Log2(X: Single): Single;
  164. { Returns largest integer <= Val (for 5.9 returns 5).}
  165. function Floor(Value: Single): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
  166. { Returns smallest integer >= Val (for 5.1 returns 6).}
  167. function Ceil(Value: Single): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
  168. { Returns lesser of two integer numbers.}
  169. function Min(A, B: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
  170. { Returns lesser of two float numbers.}
  171. function MinFloat(A, B: Single): Single; {$IFDEF USE_INLINE}inline;{$ENDIF}
  172. { Returns greater of two integer numbers.}
  173. function Max(A, B: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
  174. { Returns greater of two float numbers.}
  175. function MaxFloat(A, B: Single): Single; {$IFDEF USE_INLINE}inline;{$ENDIF}
  176. { Returns result from multiplying Number by Numerator and then dividing by Denominator.
  177. Denominator must be greater than 0.}
  178. function MulDiv(Number, Numerator, Denominator: Word): Word; {$IFDEF USE_INLINE}inline;{$ENDIF}
  179. { Switches Boolean value.}
  180. procedure Switch(var Value: Boolean); {$IFDEF USE_INLINE}inline;{$ENDIF}
  181. { If Condition is True then TruePart is retured, otherwise
  182. FalsePart is returned.}
  183. function Iff(Condition: Boolean; TruePart, FalsePart: LongInt): LongInt; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
  184. { If Condition is True then TruePart is retured, otherwise
  185. FalsePart is returned.}
  186. function IffUnsigned(Condition: Boolean; TruePart, FalsePart: LongWord): LongWord; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
  187. { If Condition is True then TruePart is retured, otherwise
  188. FalsePart is returned.}
  189. function Iff(Condition, TruePart, FalsePart: Boolean): Boolean; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
  190. { If Condition is True then TruePart is retured, otherwise
  191. FalsePart is returned.}
  192. function Iff(Condition: Boolean; const TruePart, FalsePart: string): string; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
  193. { If Condition is True then TruePart is retured, otherwise
  194. FalsePart is returned.}
  195. function Iff(Condition: Boolean; TruePart, FalsePart: Char): Char; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
  196. { If Condition is True then TruePart is retured, otherwise
  197. FalsePart is returned.}
  198. function Iff(Condition: Boolean; TruePart, FalsePart: Pointer): Pointer; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
  199. { If Condition is True then TruePart is retured, otherwise
  200. FalsePart is returned.}
  201. function Iff(Condition: Boolean; const TruePart, FalsePart: Int64): Int64; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
  202. { If Condition is True then TruePart is retured, otherwise
  203. FalsePart is returned.}
  204. function IffFloat(Condition: Boolean; TruePart, FalsePart: Single): Single; {$IFDEF USE_INLINE}inline;{$ENDIF}
  205. { Swaps two Byte values}
  206. procedure SwapValues(var A, B: Byte); overload;
  207. { Swaps two Word values}
  208. procedure SwapValues(var A, B: Word); overload;
  209. { Swaps two LongInt values}
  210. procedure SwapValues(var A, B: LongInt); overload;
  211. { Swaps two Single values}
  212. procedure SwapValues(var A, B: Single); overload;
  213. { Swaps two LongInt values if necessary to ensure that Min <= Max.}
  214. procedure SwapMin(var Min, Max: LongInt); {$IFDEF USE_INLINE}inline;{$ENDIF}
  215. { This function returns True if running on little endian machine.}
  216. function IsLittleEndian: Boolean; {$IFDEF USE_INLINE}inline;{$ENDIF}
  217. { Swaps byte order of Word value.}
  218. function SwapEndianWord(Value: Word): Word; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
  219. { Swaps byte order of multiple Word values.}
  220. procedure SwapEndianWord(P: PWordArray; Count: LongInt); overload;
  221. { Swaps byte order of LongWord value.}
  222. function SwapEndianLongWord(Value: LongWord): LongWord; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
  223. { Swaps byte order of multiple LongWord values.}
  224. procedure SwapEndianLongWord(P: PLongWord; Count: LongInt); overload;
  225. { Calculates CRC32 for the given data.}
  226. procedure CalcCrc32(var Crc: LongWord; Data: Pointer; Size: LongInt);
  227. { Fills given memory with given Byte value. Size is size of buffer in bytes.}
  228. procedure FillMemoryByte(Data: Pointer; Size: LongInt; Value: Byte);
  229. { Fills given memory with given Word value. Size is size of buffer in bytes.}
  230. procedure FillMemoryWord(Data: Pointer; Size: LongInt; Value: Word);
  231. { Fills given memory with given LongWord value. Size is size of buffer in bytes.}
  232. procedure FillMemoryLongWord(Data: Pointer; Size: LongInt; Value: LongWord);
  233. { Returns how many mipmap levels can be created for image of given size.}
  234. function GetNumMipMapLevels(Width, Height: LongInt): LongInt;
  235. { Returns total number of levels of volume texture with given depth and
  236. mipmap count (this is not depth * mipmaps!).}
  237. function GetVolumeLevelCount(Depth, MipMaps: LongInt): LongInt;
  238. { Returns rectangle (X, Y, X + Width, Y + Height).}
  239. function BoundsToRect(X, Y, Width, Height: LongInt): TRect; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
  240. { Returns rectangle (R.Left, R.Top, R.Left + R.Right, R.Top + R.Bottom).}
  241. function BoundsToRect(const R: TRect): TRect; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
  242. { Returns rectangle (R.Left, R.Top, R.Right - R.Left, R.Bottom - R.Top).}
  243. function RectToBounds(const R: TRect): TRect; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
  244. { Clips given bounds to Clip rectangle.}
  245. procedure ClipRectBounds(var X, Y, Width, Height: LongInt; const Clip: TRect);
  246. { Clips given source bounds and dest position. It is used by various CopyRect
  247. functions that copy rect from one image to another. It handles clipping the same way
  248. as Win32 BitBlt function. }
  249. procedure ClipCopyBounds(var SrcX, SrcY, Width, Height, DstX, DstY: LongInt;
  250. SrcImageWidth, SrcImageHeight: LongInt; const DstClip: TRect);
  251. { Clips given source bounds and dest bounds. It is used by various StretchRect
  252. functions that stretch rectangle of pixels from one image to another.
  253. It handles clipping the same way as Win32 StretchBlt function. }
  254. procedure ClipStretchBounds(var SrcX, SrcY, SrcWidth, SrcHeight, DstX, DstY,
  255. DstWidth, DstHeight: LongInt; SrcImageWidth, SrcImageHeight: LongInt; const DstClip: TRect);
  256. { Scales one rectangle to fit into another. Proportions are preserved so
  257. it could be used for 'Stretch To Fit Window' image drawing for instance.}
  258. function ScaleRectToRect(const SourceRect, TargetRect: TRect): TRect;
  259. { Returns True if R1 fits into R2.}
  260. function RectInRect(const R1, R2: TRect): Boolean;
  261. { Returns True if R1 and R2 intersects.}
  262. function RectIntersects(const R1, R2: TRect): Boolean;
  263. { Formats given message for usage in Exception.Create(..). Use only
  264. in except block - returned message contains message of last raised exception.}
  265. function FormatExceptMsg(const Msg: string; const Args: array of const): string;
  266. { Outputs debug message - shows message dialog in Windows and writes to console
  267. in Linux/Unix.}
  268. procedure DebugMsg(const Msg: string; const Args: array of const);
  269. implementation
  270. uses
  271. {$IFDEF MSWINDOWS}
  272. Windows;
  273. {$ENDIF}
  274. {$IFDEF UNIX}
  275. {$IFDEF KYLIX}
  276. Libc;
  277. {$ELSE}
  278. Dos, BaseUnix, Unix;
  279. {$ENDIF}
  280. {$ENDIF}
  281. procedure FreeAndNil(var Obj);
  282. var
  283. Temp: TObject;
  284. begin
  285. Temp := TObject(Obj);
  286. Pointer(Obj) := nil;
  287. Temp.Free;
  288. end;
  289. procedure FreeMemNil(var P);
  290. begin
  291. FreeMem(Pointer(P));
  292. Pointer(P) := nil;
  293. end;
  294. procedure FreeMem(P: Pointer);
  295. begin
  296. if P <> nil then
  297. System.FreeMem(P);
  298. end;
  299. function GetExceptObject: Exception;
  300. begin
  301. Result := Exception(ExceptObject);
  302. end;
  303. {$IFDEF MSWINDOWS}
  304. var
  305. PerfFrequency: Int64;
  306. InvPerfFrequency: Single;
  307. function GetTimeMicroseconds: Int64;
  308. var
  309. Time: Int64;
  310. begin
  311. QueryPerformanceCounter(Time);
  312. Result := Round(1000000 * InvPerfFrequency * Time);
  313. end;
  314. {$ENDIF}
  315. {$IFDEF UNIX}
  316. function GetTimeMicroseconds: Int64;
  317. var
  318. TimeVal: TTimeVal;
  319. begin
  320. {$IFDEF KYLIX}
  321. GetTimeOfDay(TimeVal, nil);
  322. {$ELSE}
  323. fpGetTimeOfDay(@TimeVal, nil);
  324. {$ENDIF}
  325. Result := Int64(TimeVal.tv_sec) * 1000000 + TimeVal.tv_usec;
  326. end;
  327. {$ENDIF}
  328. {$IFDEF MSDOS}
  329. function GetTimeMicroseconds: Int64;
  330. asm
  331. XOR EAX, EAX
  332. CLI
  333. OUT $43, AL
  334. MOV EDX, FS:[$46C]
  335. IN AL, $40
  336. DB $EB, 0, $EB, 0, $EB, 0
  337. MOV AH, AL
  338. IN AL, $40
  339. DB $EB, 0, $EB, 0, $EB, 0
  340. XCHG AL, AH
  341. NEG AX
  342. MOVZX EDI, AX
  343. STI
  344. MOV EBX, $10000
  345. MOV EAX, EDX
  346. XOR EDX, EDX
  347. MUL EBX
  348. ADD EAX, EDI
  349. ADC EDX, 0
  350. PUSH EDX
  351. PUSH EAX
  352. MOV ECX, $82BF1000
  353. MOVZX EAX, WORD PTR FS:[$470]
  354. MUL ECX
  355. MOV ECX, EAX
  356. POP EAX
  357. POP EDX
  358. ADD EAX, ECX
  359. ADC EDX, 0
  360. end;
  361. {$ENDIF}
  362. function GetTimeMilliseconds: Int64;
  363. begin
  364. Result := GetTimeMicroseconds div 1000;
  365. end;
  366. function GetFileExt(const FileName: string): string;
  367. begin
  368. Result := ExtractFileExt(FileName);
  369. if Length(Result) > 1 then
  370. Delete(Result, 1, 1);
  371. end;
  372. function GetAppExe: string;
  373. {$IFDEF MSWINDOWS}
  374. var
  375. FileName: array[0..MAX_PATH] of Char;
  376. begin
  377. SetString(Result, FileName,
  378. Windows.GetModuleFileName(MainInstance, FileName, SizeOf(FileName)));
  379. {$ENDIF}
  380. {$IFDEF UNIX}
  381. {$IFDEF KYLIX}
  382. var
  383. FileName: array[0..FILENAME_MAX] of Char;
  384. begin
  385. SetString(Result, FileName,
  386. System.GetModuleFileName(MainInstance, FileName, SizeOf(FileName)));
  387. {$ELSE}
  388. begin
  389. Result := FExpand(ParamStr(0));
  390. {$ENDIF}
  391. {$ENDIF}
  392. {$IFDEF MSDOS}
  393. begin
  394. Result := ParamStr(0);
  395. {$ENDIF}
  396. end;
  397. function GetAppDir: string;
  398. begin
  399. Result := ExtractFileDir(GetAppExe);
  400. end;
  401. function MatchFileNameMask(const FileName, Mask: string; CaseSensitive: Boolean): Boolean;
  402. var
  403. MaskLen, KeyLen : LongInt;
  404. function CharMatch(A, B: Char): Boolean;
  405. begin
  406. if CaseSensitive then
  407. Result := A = B
  408. else
  409. Result := UpCase(A) = UpCase(B);
  410. end;
  411. function MatchAt(MaskPos, KeyPos: LongInt): Boolean;
  412. begin
  413. while (MaskPos <= MaskLen) and (KeyPos <= KeyLen) do
  414. begin
  415. case Mask[MaskPos] of
  416. '?' :
  417. begin
  418. Inc(MaskPos);
  419. Inc(KeyPos);
  420. end;
  421. '*' :
  422. begin
  423. while (MaskPos <= MaskLen) and (Mask[MaskPos] = '*') do
  424. Inc(MaskPos);
  425. if MaskPos > MaskLen then
  426. begin
  427. Result := True;
  428. Exit;
  429. end;
  430. repeat
  431. if MatchAt(MaskPos, KeyPos) then
  432. begin
  433. Result := True;
  434. Exit;
  435. end;
  436. Inc(KeyPos);
  437. until KeyPos > KeyLen;
  438. Result := False;
  439. Exit;
  440. end;
  441. else
  442. if not CharMatch(Mask[MaskPos], FileName[KeyPos]) then
  443. begin
  444. Result := False;
  445. Exit;
  446. end
  447. else
  448. begin
  449. Inc(MaskPos);
  450. Inc(KeyPos);
  451. end;
  452. end;
  453. end;
  454. while (MaskPos <= MaskLen) and (Mask[MaskPos] in ['?', '*']) do
  455. Inc(MaskPos);
  456. if (MaskPos <= MaskLen) or (KeyPos <= KeyLen) then
  457. begin
  458. Result := False;
  459. Exit;
  460. end;
  461. Result := True;
  462. end;
  463. begin
  464. MaskLen := Length(Mask);
  465. KeyLen := Length(FileName);
  466. if MaskLen = 0 then
  467. begin
  468. Result := True;
  469. Exit;
  470. end;
  471. Result := MatchAt(1, 1);
  472. end;
  473. function BuildFileList(Path: string; Attr: LongInt;
  474. Files: TStrings; Options: TFileListOptions): Boolean;
  475. var
  476. FileMask: string;
  477. RootDir: string;
  478. Folders: TStringList;
  479. CurrentItem: LongInt;
  480. Counter: LongInt;
  481. LocAttr: LongInt;
  482. procedure BuildFolderList;
  483. var
  484. FindInfo: TSearchRec;
  485. Rslt: LongInt;
  486. begin
  487. Counter := Folders.Count - 1;
  488. CurrentItem := 0;
  489. while CurrentItem <= Counter do
  490. begin
  491. // Searching for subfolders
  492. Rslt := SysUtils.FindFirst(Folders[CurrentItem] + '*', faDirectory, FindInfo);
  493. try
  494. while Rslt = 0 do
  495. begin
  496. if (FindInfo.Name <> '.') and (FindInfo.Name <> '..') and
  497. (FindInfo.Attr and faDirectory = faDirectory) then
  498. Folders.Add(Folders[CurrentItem] + FindInfo.Name + PathDelim);
  499. Rslt := SysUtils.FindNext(FindInfo);
  500. end;
  501. finally
  502. SysUtils.FindClose(FindInfo);
  503. end;
  504. Counter := Folders.Count - 1;
  505. Inc(CurrentItem);
  506. end;
  507. end;
  508. procedure FillFileList(CurrentCounter: LongInt);
  509. var
  510. FindInfo: TSearchRec;
  511. Res: LongInt;
  512. CurrentFolder: string;
  513. begin
  514. CurrentFolder := Folders[CurrentCounter];
  515. Res := SysUtils.FindFirst(CurrentFolder + FileMask, LocAttr, FindInfo);
  516. if flRelNames in Options then
  517. CurrentFolder := ExtractRelativePath(RootDir, CurrentFolder);
  518. try
  519. while Res = 0 do
  520. begin
  521. if (FindInfo.Name <> '.') and (FindInfo.Name <> '..') then
  522. begin
  523. if (flFullNames in Options) or (flRelNames in Options) then
  524. Files.Add(CurrentFolder + FindInfo.Name)
  525. else
  526. Files.Add(FindInfo.Name);
  527. end;
  528. Res := SysUtils.FindNext(FindInfo);
  529. end;
  530. finally
  531. SysUtils.FindClose(FindInfo);
  532. end;
  533. end;
  534. begin
  535. FileMask := ExtractFileName(Path);
  536. RootDir := ExtractFilePath(Path);
  537. Folders := TStringList.Create;
  538. Folders.Add(RootDir);
  539. Files.Clear;
  540. {$IFDEF DCC}
  541. {$WARN SYMBOL_PLATFORM OFF}
  542. {$ENDIF}
  543. if Attr = faAnyFile then
  544. LocAttr := faSysFile or faHidden or faArchive or faReadOnly
  545. else
  546. LocAttr := Attr;
  547. {$IFDEF DCC}
  548. {$WARN SYMBOL_PLATFORM ON}
  549. {$ENDIF}
  550. // Here's the recursive search for nested folders
  551. if flRecursive in Options then
  552. BuildFolderList;
  553. if Attr <> faDirectory then
  554. for Counter := 0 to Folders.Count - 1 do
  555. FillFileList(Counter)
  556. else
  557. Files.AddStrings(Folders);
  558. Folders.Free;
  559. Result := True;
  560. end;
  561. function PosEx(const SubStr, S: string; Offset: LongInt = 1): LongInt;
  562. {$IFDEF USE_ASM}
  563. asm
  564. // The Original ASM Code is (C) Fastcode project.
  565. test eax, eax
  566. jz @Nil
  567. test edx, edx
  568. jz @Nil
  569. dec ecx
  570. jl @Nil
  571. push esi
  572. push ebx
  573. mov esi, [edx-4] //Length(Str)
  574. mov ebx, [eax-4] //Length(Substr)
  575. sub esi, ecx //effective length of Str
  576. add edx, ecx //addr of the first char at starting position
  577. cmp esi, ebx
  578. jl @Past //jump if EffectiveLength(Str)<Length(Substr)
  579. test ebx, ebx
  580. jle @Past //jump if Length(Substr)<=0
  581. add esp, -12
  582. add ebx, -1 //Length(Substr)-1
  583. add esi, edx //addr of the terminator
  584. add edx, ebx //addr of the last char at starting position
  585. mov [esp+8], esi //save addr of the terminator
  586. add eax, ebx //addr of the last char of Substr
  587. sub ecx, edx //-@Str[Length(Substr)]
  588. neg ebx //-(Length(Substr)-1)
  589. mov [esp+4], ecx //save -@Str[Length(Substr)]
  590. mov [esp], ebx //save -(Length(Substr)-1)
  591. movzx ecx, byte ptr [eax] //the last char of Substr
  592. @Loop:
  593. cmp cl, [edx]
  594. jz @Test0
  595. @AfterTest0:
  596. cmp cl, [edx+1]
  597. jz @TestT
  598. @AfterTestT:
  599. add edx, 4
  600. cmp edx, [esp+8]
  601. jb @Continue
  602. @EndLoop:
  603. add edx, -2
  604. cmp edx, [esp+8]
  605. jb @Loop
  606. @Exit:
  607. add esp, 12
  608. @Past:
  609. pop ebx
  610. pop esi
  611. @Nil:
  612. xor eax, eax
  613. ret
  614. @Continue:
  615. cmp cl, [edx-2]
  616. jz @Test2
  617. cmp cl, [edx-1]
  618. jnz @Loop
  619. @Test1:
  620. add edx, 1
  621. @Test2:
  622. add edx, -2
  623. @Test0:
  624. add edx, -1
  625. @TestT:
  626. mov esi, [esp]
  627. test esi, esi
  628. jz @Found
  629. @String:
  630. movzx ebx, word ptr [esi+eax]
  631. cmp bx, word ptr [esi+edx+1]
  632. jnz @AfterTestT
  633. cmp esi, -2
  634. jge @Found
  635. movzx ebx, word ptr [esi+eax+2]
  636. cmp bx, word ptr [esi+edx+3]
  637. jnz @AfterTestT
  638. add esi, 4
  639. jl @String
  640. @Found:
  641. mov eax, [esp+4]
  642. add edx, 2
  643. cmp edx, [esp+8]
  644. ja @Exit
  645. add esp, 12
  646. add eax, edx
  647. pop ebx
  648. pop esi
  649. end;
  650. {$ELSE}
  651. var
  652. I, X: LongInt;
  653. Len, LenSubStr: LongInt;
  654. begin
  655. I := Offset;
  656. LenSubStr := Length(SubStr);
  657. Len := Length(S) - LenSubStr + 1;
  658. while I <= Len do
  659. begin
  660. if S[I] = SubStr[1] then
  661. begin
  662. X := 1;
  663. while (X < LenSubStr) and (S[I + X] = SubStr[X + 1]) do
  664. Inc(X);
  665. if (X = LenSubStr) then
  666. begin
  667. Result := I;
  668. Exit;
  669. end;
  670. end;
  671. Inc(I);
  672. end;
  673. Result := 0;
  674. end;
  675. {$ENDIF}
  676. function PosNoCase(const SubStr, S: string; Offset: LongInt): LongInt;
  677. begin
  678. Result := PosEx(LowerCase(SubStr), LowerCase(S), Offset);
  679. end;
  680. function StrToken(var S: string; Sep: Char): string;
  681. var
  682. I: LongInt;
  683. begin
  684. I := Pos(Sep, S);
  685. if I <> 0 then
  686. begin
  687. Result := Copy(S, 1, I - 1);
  688. Delete(S, 1, I);
  689. end
  690. else
  691. begin
  692. Result := S;
  693. S := '';
  694. end;
  695. end;
  696. function StrTokenEnd(var S: string; Sep: Char): string;
  697. var
  698. I, J: LongInt;
  699. begin
  700. J := 0;
  701. I := Pos(Sep, S);
  702. while I <> 0 do
  703. begin
  704. J := I;
  705. I := PosEx(Sep, S, J + 1);
  706. end;
  707. if J <> 0 then
  708. begin
  709. Result := Copy(S, J + 1, MaxInt);
  710. Delete(S, J, MaxInt);
  711. end
  712. else
  713. begin
  714. Result := S;
  715. S := '';
  716. end;
  717. end;
  718. function IntToStrFmt(const I: Int64): string;
  719. begin
  720. Result := Format('%.0n', [I * 1.0]);
  721. end;
  722. function FloatToStrFmt(const F: Double; Precision: Integer): string;
  723. begin
  724. Result := Format('%.' + IntToStr(Precision) + 'n', [F]);
  725. end;
  726. function ClampInt(Number: LongInt; Min, Max: LongInt): LongInt;
  727. begin
  728. Result := Number;
  729. if Result < Min then
  730. Result := Min
  731. else
  732. if Result > Max then
  733. Result := Max;
  734. end;
  735. function ClampFloat(Number: Single; Min, Max: Single): Single;
  736. begin
  737. Result := Number;
  738. if Result < Min then
  739. Result := Min
  740. else
  741. if Result > Max then
  742. Result := Max;
  743. end;
  744. function ClampToByte(Value: LongInt): LongInt;
  745. begin
  746. Result := Value;
  747. if Result > 255 then
  748. Result := 255
  749. else if Result < 0 then
  750. Result := 0;
  751. end;
  752. function ClampToWord(Value: LongInt): LongInt;
  753. begin
  754. Result := Value;
  755. if Result > 65535 then
  756. Result := 65535
  757. else if Result < 0 then
  758. Result := 0;
  759. end;
  760. function IsPow2(Num: LongInt): Boolean;
  761. begin
  762. Result := (Num and -Num) = Num;
  763. end;
  764. function NextPow2(Num: LongInt): LongInt;
  765. begin
  766. Result := Num and -Num;
  767. while (Result < Num) do
  768. Result := Result shl 1;
  769. end;
  770. function Pow2Int(Exponent: LongInt): LongInt;
  771. begin
  772. Result := 1 shl Exponent;
  773. end;
  774. function Power(const Base, Exponent: Single): Single;
  775. begin
  776. if Exponent = 0.0 then
  777. Result := 1.0
  778. else if (Base = 0.0) and (Exponent > 0.0) then
  779. Result := 0.0
  780. else
  781. Result := Exp(Exponent * Ln(Base));
  782. end;
  783. function Log2Int(X: LongInt): LongInt;
  784. begin
  785. case X of
  786. 1: Result := 0;
  787. 2: Result := 1;
  788. 4: Result := 2;
  789. 8: Result := 3;
  790. 16: Result := 4;
  791. 32: Result := 5;
  792. 64: Result := 6;
  793. 128: Result := 7;
  794. 256: Result := 8;
  795. 512: Result := 9;
  796. 1024: Result := 10;
  797. 2048: Result := 11;
  798. 4096: Result := 12;
  799. 8192: Result := 13;
  800. 16384: Result := 14;
  801. 32768: Result := 15;
  802. 65536: Result := 16;
  803. 131072: Result := 17;
  804. 262144: Result := 18;
  805. 524288: Result := 19;
  806. 1048576: Result := 20;
  807. 2097152: Result := 21;
  808. 4194304: Result := 22;
  809. 8388608: Result := 23;
  810. 16777216: Result := 24;
  811. 33554432: Result := 25;
  812. 67108864: Result := 26;
  813. 134217728: Result := 27;
  814. 268435456: Result := 28;
  815. 536870912: Result := 29;
  816. 1073741824: Result := 30;
  817. else
  818. Result := -1;
  819. end;
  820. end;
  821. function Log2(X: Single): Single;
  822. const
  823. Ln2: Single = 0.6931471;
  824. begin
  825. Result := Ln(X) / Ln2;
  826. end;
  827. function Floor(Value: Single): LongInt;
  828. begin
  829. Result := Trunc(Value);
  830. if Frac(Value) < 0.0 then
  831. Dec(Result);
  832. end;
  833. function Ceil(Value: Single): LongInt;
  834. begin
  835. Result := Trunc(Value);
  836. if Frac(Value) > 0.0 then
  837. Inc(Result);
  838. end;
  839. procedure Switch(var Value: Boolean);
  840. begin
  841. Value := not Value;
  842. end;
  843. function Iff(Condition: Boolean; TruePart, FalsePart: LongInt): LongInt;
  844. begin
  845. if Condition then
  846. Result := TruePart
  847. else
  848. Result := FalsePart;
  849. end;
  850. function IffUnsigned(Condition: Boolean; TruePart, FalsePart: LongWord): LongWord;
  851. begin
  852. if Condition then
  853. Result := TruePart
  854. else
  855. Result := FalsePart;
  856. end;
  857. function Iff(Condition, TruePart, FalsePart: Boolean): Boolean;
  858. begin
  859. if Condition then
  860. Result := TruePart
  861. else
  862. Result := FalsePart;
  863. end;
  864. function Iff(Condition: Boolean; const TruePart, FalsePart: string): string;
  865. begin
  866. if Condition then
  867. Result := TruePart
  868. else
  869. Result := FalsePart;
  870. end;
  871. function Iff(Condition: Boolean; TruePart, FalsePart: Char): Char;
  872. begin
  873. if Condition then
  874. Result := TruePart
  875. else
  876. Result := FalsePart;
  877. end;
  878. function Iff(Condition: Boolean; TruePart, FalsePart: Pointer): Pointer;
  879. begin
  880. if Condition then
  881. Result := TruePart
  882. else
  883. Result := FalsePart;
  884. end;
  885. function Iff(Condition: Boolean; const TruePart, FalsePart: Int64): Int64;
  886. begin
  887. if Condition then
  888. Result := TruePart
  889. else
  890. Result := FalsePart;
  891. end;
  892. function IffFloat(Condition: Boolean; TruePart, FalsePart: Single): Single;
  893. begin
  894. if Condition then
  895. Result := TruePart
  896. else
  897. Result := FalsePart;
  898. end;
  899. procedure SwapValues(var A, B: Byte);
  900. var
  901. Tmp: Byte;
  902. begin
  903. Tmp := A;
  904. A := B;
  905. B := Tmp;
  906. end;
  907. procedure SwapValues(var A, B: Word);
  908. var
  909. Tmp: Word;
  910. begin
  911. Tmp := A;
  912. A := B;
  913. B := Tmp;
  914. end;
  915. procedure SwapValues(var A, B: LongInt);
  916. var
  917. Tmp: LongInt;
  918. begin
  919. Tmp := A;
  920. A := B;
  921. B := Tmp;
  922. end;
  923. procedure SwapValues(var A, B: Single);
  924. var
  925. Tmp: Single;
  926. begin
  927. Tmp := A;
  928. A := B;
  929. B := Tmp;
  930. end;
  931. procedure SwapMin(var Min, Max: LongInt);
  932. var
  933. Tmp: LongInt;
  934. begin
  935. if Min > Max then
  936. begin
  937. Tmp := Min;
  938. Min := Max;
  939. Max := Tmp;
  940. end;
  941. end;
  942. function Min(A, B: LongInt): LongInt;
  943. begin
  944. if A < B then
  945. Result := A
  946. else
  947. Result := B;
  948. end;
  949. function MinFloat(A, B: Single): Single;
  950. begin
  951. if A < B then
  952. Result := A
  953. else
  954. Result := B;
  955. end;
  956. function Max(A, B: LongInt): LongInt;
  957. begin
  958. if A > B then
  959. Result := A
  960. else
  961. Result := B;
  962. end;
  963. function MaxFloat(A, B: Single): Single;
  964. begin
  965. if A > B then
  966. Result := A
  967. else
  968. Result := B;
  969. end;
  970. function MulDiv(Number, Numerator, Denominator: Word): Word;
  971. {$IF Defined(USE_ASM) and (not Defined(USE_INLINE))}
  972. asm
  973. MUL DX
  974. DIV CX
  975. end;
  976. {$ELSE}
  977. begin
  978. Result := Number * Numerator div Denominator;
  979. end;
  980. {$IFEND}
  981. function IsLittleEndian: Boolean;
  982. var
  983. W: Word;
  984. begin
  985. W := $00FF;
  986. Result := PByte(@W)^ = $FF;
  987. end;
  988. function SwapEndianWord(Value: Word): Word;
  989. {$IF Defined(USE_ASM) and (not Defined(USE_INLINE))}
  990. asm
  991. XCHG AH, AL
  992. end;
  993. {$ELSE}
  994. begin
  995. TWordRec(Result).Low := TWordRec(Value).High;
  996. TWordRec(Result).High := TWordRec(Value).Low;
  997. end;
  998. {$IFEND}
  999. procedure SwapEndianWord(P: PWordArray; Count: LongInt);
  1000. {$IFDEF USE_ASM}
  1001. asm
  1002. @Loop:
  1003. MOV CX, [EAX]
  1004. XCHG CH, CL
  1005. MOV [EAX], CX
  1006. ADD EAX, 2
  1007. DEC EDX
  1008. JNZ @Loop
  1009. end;
  1010. {$ELSE}
  1011. var
  1012. I: LongInt;
  1013. Temp: Word;
  1014. begin
  1015. for I := 0 to Count - 1 do
  1016. begin
  1017. Temp := P[I];
  1018. TWordRec(P[I]).Low := TWordRec(Temp).High;
  1019. TWordRec(P[I]).High := TWordRec(Temp).Low;
  1020. end;
  1021. end;
  1022. {$ENDIF}
  1023. function SwapEndianLongWord(Value: LongWord): LongWord;
  1024. {$IF Defined(USE_ASM) and (not Defined(USE_INLINE))}
  1025. asm
  1026. BSWAP EAX
  1027. end;
  1028. {$ELSE}
  1029. begin
  1030. TLongWordRec(Result).Bytes[0] := TLongWordRec(Value).Bytes[3];
  1031. TLongWordRec(Result).Bytes[1] := TLongWordRec(Value).Bytes[2];
  1032. TLongWordRec(Result).Bytes[2] := TLongWordRec(Value).Bytes[1];
  1033. TLongWordRec(Result).Bytes[3] := TLongWordRec(Value).Bytes[0];
  1034. end;
  1035. {$IFEND}
  1036. procedure SwapEndianLongWord(P: PLongWord; Count: LongInt);
  1037. {$IFDEF USE_ASM}
  1038. asm
  1039. @Loop:
  1040. MOV ECX, [EAX]
  1041. BSWAP ECX
  1042. MOV [EAX], ECX
  1043. ADD EAX, 4
  1044. DEC EDX
  1045. JNZ @Loop
  1046. end;
  1047. {$ELSE}
  1048. var
  1049. I: LongInt;
  1050. Temp: LongWord;
  1051. begin
  1052. for I := 0 to Count - 1 do
  1053. begin
  1054. Temp := PLongWordArray(P)[I];
  1055. TLongWordRec(PLongWordArray(P)[I]).Bytes[0] := TLongWordRec(Temp).Bytes[3];
  1056. TLongWordRec(PLongWordArray(P)[I]).Bytes[1] := TLongWordRec(Temp).Bytes[2];
  1057. TLongWordRec(PLongWordArray(P)[I]).Bytes[2] := TLongWordRec(Temp).Bytes[1];
  1058. TLongWordRec(PLongWordArray(P)[I]).Bytes[3] := TLongWordRec(Temp).Bytes[0];
  1059. end;
  1060. end;
  1061. {$ENDIF}
  1062. type
  1063. TCrcTable = array[Byte] of LongWord;
  1064. var
  1065. CrcTable: TCrcTable;
  1066. procedure InitCrcTable;
  1067. const
  1068. Polynom = $EDB88320;
  1069. var
  1070. I, J: LongInt;
  1071. C: LongWord;
  1072. begin
  1073. for I := 0 to 255 do
  1074. begin
  1075. C := I;
  1076. for J := 0 to 7 do
  1077. begin
  1078. if (C and $01) <> 0 then
  1079. C := Polynom xor (C shr 1)
  1080. else
  1081. C := C shr 1;
  1082. end;
  1083. CrcTable[I] := C;
  1084. end;
  1085. end;
  1086. procedure CalcCrc32(var Crc: LongWord; Data: Pointer; Size: LongInt);
  1087. var
  1088. I: LongInt;
  1089. B: PByte;
  1090. begin
  1091. B := Data;
  1092. for I := 0 to Size - 1 do
  1093. begin
  1094. Crc := (Crc shr 8) xor CrcTable[B^ xor Byte(Crc)];
  1095. Inc(B);
  1096. end
  1097. end;
  1098. procedure FillMemoryByte(Data: Pointer; Size: LongInt; Value: Byte);
  1099. {$IFDEF USE_ASM}
  1100. asm
  1101. PUSH EDI
  1102. MOV EDI, EAX
  1103. MOV EAX, ECX
  1104. MOV AH, AL
  1105. MOV CX, AX
  1106. SHL EAX, 16
  1107. MOV AX, CX
  1108. MOV ECX, EDX
  1109. SAR ECX, 2
  1110. JS @Exit
  1111. REP STOSD
  1112. MOV ECX, EDX
  1113. AND ECX, 3
  1114. REP STOSB
  1115. POP EDI
  1116. @Exit:
  1117. end;
  1118. {$ELSE}
  1119. begin
  1120. FillChar(Data^, Size, Value);
  1121. end;
  1122. {$ENDIF}
  1123. procedure FillMemoryWord(Data: Pointer; Size: LongInt; Value: Word);
  1124. {$IFDEF USE_ASM}
  1125. asm
  1126. PUSH EDI
  1127. PUSH EBX
  1128. MOV EBX, EDX
  1129. MOV EDI, EAX
  1130. MOV EAX, ECX
  1131. MOV CX, AX
  1132. SHL EAX, 16
  1133. MOV AX, CX
  1134. MOV ECX, EDX
  1135. SHR ECX, 2
  1136. JZ @Word
  1137. REP STOSD
  1138. @Word:
  1139. MOV ECX, EBX
  1140. AND ECX, 2
  1141. JZ @Byte
  1142. MOV [EDI], AX
  1143. ADD EDI, 2
  1144. @Byte:
  1145. MOV ECX, EBX
  1146. AND ECX, 1
  1147. JZ @Exit
  1148. MOV [EDI], AL
  1149. @Exit:
  1150. POP EBX
  1151. POP EDI
  1152. end;
  1153. {$ELSE}
  1154. var
  1155. I, V: LongWord;
  1156. begin
  1157. V := Value * $10000 + Value;
  1158. for I := 0 to Size div 4 - 1 do
  1159. PLongWordArray(Data)[I] := V;
  1160. case Size mod 4 of
  1161. 1: PByteArray(Data)[Size - 1] := Lo(Value);
  1162. 2: PWordArray(Data)[Size div 2] := Value;
  1163. 3:
  1164. begin
  1165. PWordArray(Data)[Size div 2 - 1] := Value;
  1166. PByteArray(Data)[Size - 1] := Lo(Value);
  1167. end;
  1168. end;
  1169. end;
  1170. {$ENDIF}
  1171. procedure FillMemoryLongWord(Data: Pointer; Size: LongInt; Value: LongWord);
  1172. {$IFDEF USE_ASM}
  1173. asm
  1174. PUSH EDI
  1175. PUSH EBX
  1176. MOV EBX, EDX
  1177. MOV EDI, EAX
  1178. MOV EAX, ECX
  1179. MOV ECX, EDX
  1180. SHR ECX, 2
  1181. JZ @Word
  1182. REP STOSD
  1183. @Word:
  1184. MOV ECX, EBX
  1185. AND ECX, 2
  1186. JZ @Byte
  1187. MOV [EDI], AX
  1188. ADD EDI, 2
  1189. @Byte:
  1190. MOV ECX, EBX
  1191. AND ECX, 1
  1192. JZ @Exit
  1193. MOV [EDI], AL
  1194. @Exit:
  1195. POP EBX
  1196. POP EDI
  1197. end;
  1198. {$ELSE}
  1199. var
  1200. I: LongInt;
  1201. begin
  1202. for I := 0 to Size div 4 - 1 do
  1203. PLongWordArray(Data)[I] := Value;
  1204. case Size mod 4 of
  1205. 1: PByteArray(Data)[Size - 1] := TLongWordRec(Value).Bytes[0];
  1206. 2: PWordArray(Data)[Size div 2] := TLongWordRec(Value).Words[0];
  1207. 3:
  1208. begin
  1209. PWordArray(Data)[Size div 2 - 1] := TLongWordRec(Value).Words[0];
  1210. PByteArray(Data)[Size - 1] := TLongWordRec(Value).Bytes[0];
  1211. end;
  1212. end;
  1213. end;
  1214. {$ENDIF}
  1215. function GetNumMipMapLevels(Width, Height: LongInt): LongInt;
  1216. begin
  1217. Result := 0;
  1218. if (Width > 0) and (Height > 0) then
  1219. begin
  1220. Result := 1;
  1221. while (Width <> 1) or (Height <> 1) do
  1222. begin
  1223. Width := Width div 2;
  1224. Height := Height div 2;
  1225. if Width < 1 then Width := 1;
  1226. if Height < 1 then Height := 1;
  1227. Inc(Result);
  1228. end;
  1229. end;
  1230. end;
  1231. function GetVolumeLevelCount(Depth, MipMaps: LongInt): LongInt;
  1232. var
  1233. I: LongInt;
  1234. begin
  1235. Result := Depth;
  1236. for I := 1 to MipMaps - 1 do
  1237. Inc(Result, ClampInt(Depth shr I, 1, Depth));
  1238. end;
  1239. function BoundsToRect(X, Y, Width, Height: LongInt): TRect;
  1240. begin
  1241. Result.Left := X;
  1242. Result.Top := Y;
  1243. Result.Right := X + Width;
  1244. Result.Bottom := Y + Height;
  1245. end;
  1246. function BoundsToRect(const R: TRect): TRect;
  1247. begin
  1248. Result.Left := R.Left;
  1249. Result.Top := R.Top;
  1250. Result.Right := R.Left + R.Right;
  1251. Result.Bottom := R.Top + R.Bottom;
  1252. end;
  1253. function RectToBounds(const R: TRect): TRect;
  1254. begin
  1255. Result.Left := R.Left;
  1256. Result.Top := R.Top;
  1257. Result.Right := R.Right - R.Left;
  1258. Result.Bottom := R.Bottom - R.Top;
  1259. end;
  1260. procedure ClipRectBounds(var X, Y, Width, Height: LongInt; const Clip: TRect);
  1261. procedure ClipDim(var AStart, ALength: LongInt; ClipMin, ClipMax: LongInt);
  1262. begin
  1263. if AStart < ClipMin then
  1264. begin
  1265. ALength := ALength - (ClipMin - AStart);
  1266. AStart := ClipMin;
  1267. end;
  1268. if AStart + ALength > ClipMax then ALength := Max(0, ClipMax - AStart);
  1269. end;
  1270. begin
  1271. ClipDim(X, Width, Clip.Left, Clip.Right);
  1272. ClipDim(Y, Height, Clip.Top, Clip.Bottom);
  1273. end;
  1274. procedure ClipCopyBounds(var SrcX, SrcY, Width, Height, DstX, DstY: LongInt; SrcImageWidth, SrcImageHeight: LongInt; const DstClip: TRect);
  1275. procedure ClipDim(var SrcPos, DstPos, Size: LongInt; SrcClipMax,
  1276. DstClipMin, DstClipMax: LongInt);
  1277. var
  1278. OldDstPos: LongInt;
  1279. Diff: LongInt;
  1280. begin
  1281. OldDstPos := Iff(DstPos < 0, DstPos, 0);
  1282. if DstPos < DstClipMin then
  1283. begin
  1284. Diff := DstClipMin - DstPos;
  1285. Size := Size - Diff;
  1286. SrcPos := SrcPos + Diff;
  1287. DstPos := DstClipMin;
  1288. end;
  1289. if SrcPos < 0 then
  1290. begin
  1291. Size := Size + SrcPos - OldDstPos;
  1292. DstPos := DstPos - SrcPos + OldDstPos;
  1293. SrcPos := 0;
  1294. end;
  1295. if SrcPos + Size > SrcClipMax then Size := SrcClipMax - SrcPos;
  1296. if DstPos + Size > DstClipMax then Size := DstClipMax - DstPos;
  1297. end;
  1298. begin
  1299. ClipDim(SrcX, DstX, Width, SrcImageWidth, DstClip.Left, DstClip.Right);
  1300. ClipDim(SrcY, DstY, Height, SrcImageHeight, DstClip.Top, DstClip.Bottom);
  1301. end;
  1302. procedure ClipStretchBounds(var SrcX, SrcY, SrcWidth, SrcHeight, DstX, DstY,
  1303. DstWidth, DstHeight: LongInt; SrcImageWidth, SrcImageHeight: LongInt; const DstClip: TRect);
  1304. procedure ClipDim(var SrcPos, DstPos, SrcSize, DstSize: LongInt; SrcClipMax,
  1305. DstClipMin, DstClipMax: LongInt);
  1306. var
  1307. OldSize: LongInt;
  1308. Diff: LongInt;
  1309. Scale: Single;
  1310. begin
  1311. Scale := DstSize / SrcSize;
  1312. if DstPos < DstClipMin then
  1313. begin
  1314. Diff := DstClipMin - DstPos;
  1315. DstSize := DstSize - Diff;
  1316. SrcPos := SrcPos + Round(Diff / Scale);
  1317. SrcSize := SrcSize - Round(Diff / Scale);
  1318. DstPos := DstClipMin;
  1319. end;
  1320. if SrcPos < 0 then
  1321. begin
  1322. SrcSize := SrcSize + SrcPos;
  1323. DstPos := DstPos - Round(SrcPos * Scale);
  1324. DstSize := DstSize + Round(SrcPos * Scale);
  1325. SrcPos := 0;
  1326. end;
  1327. if SrcPos + SrcSize > SrcClipMax then
  1328. begin
  1329. OldSize := SrcSize;
  1330. SrcSize := SrcClipMax - SrcPos;
  1331. DstSize := Round(DstSize * (SrcSize / OldSize));
  1332. end;
  1333. if DstPos + DstSize > DstClipMax then
  1334. begin
  1335. OldSize := DstSize;
  1336. DstSize := DstClipMax - DstPos;
  1337. SrcSize := Round(SrcSize * (DstSize / OldSize));
  1338. end;
  1339. end;
  1340. begin
  1341. ClipDim(SrcX, DstX, SrcWidth, DstWidth, SrcImageWidth, DstClip.Left, DstClip.Right);
  1342. ClipDim(SrcY, DstY, SrcHeight, DstHeight, SrcImageHeight, DstClip.Top, DstClip.Bottom);
  1343. end;
  1344. function ScaleRectToRect(const SourceRect, TargetRect: TRect): TRect;
  1345. var
  1346. SourceWidth: LongInt;
  1347. SourceHeight: LongInt;
  1348. TargetWidth: LongInt;
  1349. TargetHeight: LongInt;
  1350. ScaledWidth: LongInt;
  1351. ScaledHeight: LongInt;
  1352. begin
  1353. SourceWidth := SourceRect.Right - SourceRect.Left;
  1354. SourceHeight := SourceRect.Bottom - SourceRect.Top;
  1355. TargetWidth := TargetRect.Right - TargetRect.Left;
  1356. TargetHeight := TargetRect.Bottom - TargetRect.Top;
  1357. if SourceWidth * TargetHeight < SourceHeight * TargetWidth then
  1358. begin
  1359. ScaledWidth := (SourceWidth * TargetHeight) div SourceHeight;
  1360. Result := BoundsToRect(TargetRect.Left + ((TargetWidth - ScaledWidth) div 2),
  1361. TargetRect.Top, ScaledWidth, TargetHeight);
  1362. end
  1363. else
  1364. begin
  1365. ScaledHeight := (SourceHeight * TargetWidth) div SourceWidth;
  1366. Result := BoundsToRect(TargetRect.Left, TargetRect.Top + ((TargetHeight - ScaledHeight) div 2),
  1367. TargetWidth, ScaledHeight);
  1368. end;
  1369. end;
  1370. function RectInRect(const R1, R2: TRect): Boolean;
  1371. begin
  1372. Result:=
  1373. (R1.Left >= R2.Left) and
  1374. (R1.Top >= R2.Top) and
  1375. (R1.Right <= R2.Right) and
  1376. (R1.Bottom <= R2.Bottom);
  1377. end;
  1378. function RectIntersects(const R1, R2: TRect): Boolean;
  1379. begin
  1380. Result :=
  1381. not (R1.Left > R2.Right) and
  1382. not (R1.Top > R2.Bottom) and
  1383. not (R1.Right < R2.Left) and
  1384. not (R1.Bottom < R2.Top);
  1385. end;
  1386. function FormatExceptMsg(const Msg: string; const Args: array of const): string;
  1387. begin
  1388. Result := Format(Msg + SLineBreak + 'Message: ' + GetExceptObject.Message, Args);
  1389. end;
  1390. procedure DebugMsg(const Msg: string; const Args: array of const);
  1391. var
  1392. FmtMsg: string;
  1393. begin
  1394. FmtMsg := Format(Msg, Args);
  1395. {$IFDEF MSWINDOWS}
  1396. if IsConsole then
  1397. WriteLn('DebugMsg: ' + FmtMsg)
  1398. else
  1399. MessageBox(GetActiveWindow, PChar(FmtMsg), 'DebugMsg', MB_OK);
  1400. {$ENDIF}
  1401. {$IFDEF UNIX}
  1402. WriteLn('DebugMsg: ' + FmtMsg);
  1403. {$ENDIF}
  1404. {$IFDEF MSDOS}
  1405. WriteLn('DebugMsg: ' + FmtMsg);
  1406. {$ENDIF}
  1407. end;
  1408. initialization
  1409. InitCrcTable;
  1410. {$IFDEF MSWINDOWS}
  1411. QueryPerformanceFrequency(PerfFrequency);
  1412. InvPerfFrequency := 1.0 / PerfFrequency;
  1413. {$ENDIF}
  1414. {$IFDEF MSDOS}
  1415. // reset PIT
  1416. asm
  1417. MOV EAX, $34
  1418. OUT $43, AL
  1419. XOR EAX, EAX
  1420. OUT $40, AL
  1421. OUT $40, AL
  1422. end;
  1423. {$ENDIF}
  1424. {
  1425. File Notes:
  1426. -- TODOS ----------------------------------------------------
  1427. - nothing now
  1428. -- 0.25.0 Changes/Bug Fixes -----------------------------------
  1429. - Fixed error in ClipCopyBounds which was causing ... bad clipping!
  1430. -- 0.24.3 Changes/Bug Fixes -----------------------------------
  1431. - Added GetTimeMilliseconds function.
  1432. - Added IntToStrFmt and FloatToStrFmt helper functions.
  1433. -- 0.23 Changes/Bug Fixes -----------------------------------
  1434. - Added RectInRect and RectIntersects functions
  1435. - Added some string utils: StrToken, StrTokenEnd, PosEx, PosNoCase.
  1436. - Moved BuildFileList here from DemoUtils.
  1437. -- 0.21 Changes/Bug Fixes -----------------------------------
  1438. - Moved GetVolumeLevelCount from ImagingDds here.
  1439. - Renamed FillMemory to FillMemoryByte to avoid name collision in C++ Builder.
  1440. - Added Iff function for Char, Pointer, and Int64 types.
  1441. - Added IsLittleEndian function.
  1442. - Added array types for TWordRec, TLongWordRec, and TInt64Rec.
  1443. - Added MatchFileNameMask function.
  1444. -- 0.19 Changes/Bug Fixes -----------------------------------
  1445. - added ScaleRectToRect (thanks to Paul Michell)
  1446. - added BoundsToRect, ClipBounds, ClipCopyBounds, ClipStretchBounds functions
  1447. - added MulDiv function
  1448. - FreeAndNil is not inline anymore - caused AV in one program
  1449. -- 0.17 Changes/Bug Fixes -----------------------------------
  1450. - GetAppExe didn't return absolute path in FreeBSD, fixed
  1451. - added debug message output
  1452. - fixed Unix compatibility issues (thanks to Ales Katona).
  1453. Imaging now compiles in FreeBSD and maybe in other Unixes as well.
  1454. -- 0.15 Changes/Bug Fixes -----------------------------------
  1455. - added some new utility functions
  1456. -- 0.13 Changes/Bug Fixes -----------------------------------
  1457. - added many new utility functions
  1458. - minor change in SwapEndian to avoid range check error
  1459. }
  1460. end.