Shared.Int64Em.pas 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. unit Shared.Int64Em;
  2. {
  3. Inno Setup
  4. Copyright (C) 1997-2025 Jordan Russell
  5. Portions by Martijn Laan
  6. For conditions of distribution and use, see LICENSE.TXT.
  7. Declaration of the Integer64 type - which represents an *unsigned* 64-bit
  8. integer value - and functions for manipulating Integer64's.
  9. (We can't use the Int64 type since it's only available in Delphi 4 and
  10. later.)
  11. }
  12. interface
  13. type
  14. Integer64 = record
  15. Lo, Hi: LongWord;
  16. class operator Implicit(const A: Integer64): Int64;
  17. class operator Implicit(const A: Int64): Integer64;
  18. end;
  19. function Compare64(const N1, N2: Integer64): Integer;
  20. procedure Dec64(var X: Integer64; N: LongWord);
  21. procedure Dec6464(var X: Integer64; const N: Integer64);
  22. function Div64(var X: Integer64; const Divisor: LongWord): LongWord;
  23. function Inc64(var X: Integer64; N: LongWord): Boolean;
  24. function Inc6464(var X: Integer64; const N: Integer64): Boolean;
  25. function Integer64ToStr(X: Integer64): String;
  26. function Mod64(const X: Integer64; const Divisor: LongWord): LongWord;
  27. function Mul64(var X: Integer64; N: LongWord): Boolean;
  28. procedure Multiply32x32to64(N1, N2: LongWord; var X: Integer64);
  29. procedure Shr64(var X: Integer64; Count: LongWord);
  30. function StrToInteger64(const S: String; var X: Integer64): Boolean;
  31. function To64(const Lo: Longword): Integer64;
  32. implementation
  33. uses
  34. SysUtils;
  35. function Compare64(const N1, N2: Integer64): Integer;
  36. { If N1 = N2, returns 0.
  37. If N1 > N2, returns 1.
  38. If N1 < N2, returns -1. }
  39. asm
  40. { Compare high words }
  41. mov ecx, [eax+4]
  42. cmp ecx, [edx+4]
  43. ja @@return1
  44. jb @@returnminus1
  45. { High words equal; compare low words }
  46. mov ecx, [eax]
  47. cmp ecx, [edx]
  48. ja @@return1
  49. jb @@returnminus1
  50. jmp @@return0
  51. @@return1:
  52. xor eax, eax
  53. inc eax
  54. jmp @@exit
  55. @@returnminus1:
  56. or eax, -1
  57. jmp @@exit
  58. @@return0:
  59. xor eax,eax
  60. @@exit:
  61. end;
  62. procedure Dec64(var X: Integer64; N: LongWord);
  63. asm
  64. sub [eax], edx
  65. sbb dword ptr [eax+4], 0
  66. end;
  67. procedure Dec6464(var X: Integer64; const N: Integer64);
  68. asm
  69. mov ecx, [edx]
  70. sub [eax], ecx
  71. mov ecx, [edx+4]
  72. sbb [eax+4], ecx
  73. end;
  74. function Inc64(var X: Integer64; N: LongWord): Boolean;
  75. { Adds N to X. In case of overflow, False is returned. }
  76. asm
  77. add [eax], edx
  78. adc dword ptr [eax+4], 0
  79. setnc al
  80. end;
  81. function Inc6464(var X: Integer64; const N: Integer64): Boolean;
  82. { Adds N to X. In case of overflow, False is returned. }
  83. asm
  84. mov ecx, [edx]
  85. add [eax], ecx
  86. mov ecx, [edx+4]
  87. adc [eax+4], ecx
  88. setnc al
  89. end;
  90. procedure Multiply32x32to64(N1, N2: LongWord; var X: Integer64);
  91. { Multiplies two 32-bit unsigned integers together and places the result
  92. in X. }
  93. asm
  94. mul edx { Multiplies EAX by EDX, places 64-bit result in EDX:EAX }
  95. mov [ecx], eax
  96. mov [ecx+4], edx
  97. end;
  98. function Mul64(var X: Integer64; N: LongWord): Boolean;
  99. { Multiplies X by N, and overwrites X with the result. In case of overflow,
  100. False is returned (X is valid but truncated to 64 bits). }
  101. asm
  102. push esi
  103. push ebx
  104. mov esi, eax
  105. mov ecx, edx
  106. { Multiply high part }
  107. mov eax, [esi+4]
  108. mul ecx { CF set if resulting EDX <> 0 }
  109. setnc bl
  110. mov [esi+4], eax
  111. { Multiply low part, carry to high part }
  112. mov eax, [esi]
  113. mul ecx
  114. mov [esi], eax
  115. add [esi+4], edx { CF set on overflow }
  116. setnc al
  117. and al, bl
  118. pop ebx
  119. pop esi
  120. end;
  121. function Div64(var X: Integer64; const Divisor: LongWord): LongWord;
  122. { Divides X by Divisor, and overwrites X with the quotient. Returns the
  123. remainder. }
  124. asm
  125. push ebx
  126. push esi
  127. mov esi, eax
  128. mov ecx, edx
  129. mov eax, [esi]
  130. mov ebx, [esi+4]
  131. { Divide EBX:EAX by ECX. Quotient is stored in EBX:EAX, remainder in EDX. }
  132. xchg eax, ebx
  133. xor edx, edx
  134. div ecx
  135. xchg eax, ebx
  136. div ecx
  137. mov [esi], eax
  138. mov [esi+4], ebx
  139. mov eax, edx
  140. pop esi
  141. pop ebx
  142. end;
  143. function Mod64(const X: Integer64; const Divisor: LongWord): LongWord;
  144. { Divides X by Divisor and returns the remainder. Unlike Div64, X is left
  145. intact. }
  146. asm
  147. push ebx
  148. push esi
  149. mov esi, eax
  150. mov ecx, edx
  151. mov eax, [esi]
  152. mov ebx, [esi+4]
  153. { Divide EBX:EAX by ECX. Quotient is stored in EBX:EAX, remainder in EDX. }
  154. xchg eax, ebx
  155. xor edx, edx
  156. div ecx
  157. xchg eax, ebx
  158. div ecx
  159. mov eax, edx
  160. pop esi
  161. pop ebx
  162. end;
  163. procedure Shr64(var X: Integer64; Count: LongWord);
  164. { Unsigned SHR of an Integer64 }
  165. asm
  166. mov ecx, edx
  167. push esi
  168. mov esi, eax
  169. mov eax, [esi]
  170. mov edx, [esi+4]
  171. cmp ecx, 32
  172. jb @@below32
  173. cmp ecx, 64
  174. jb @@below64
  175. xor edx, edx
  176. xor eax, eax
  177. jmp @@exit
  178. @@below64:
  179. mov eax, edx
  180. xor edx, edx
  181. shr eax, cl
  182. jmp @@exit
  183. @@below32:
  184. shrd eax, edx, cl
  185. shr edx, cl
  186. @@exit:
  187. mov [esi], eax
  188. mov [esi+4], edx
  189. pop esi
  190. end;
  191. function StrToInteger64(const S: String; var X: Integer64): Boolean;
  192. { Converts a string containing an unsigned decimal number, or hexadecimal
  193. number prefixed with '$', into an Integer64. Returns True if successful,
  194. or False if invalid characters were encountered or an overflow occurred.
  195. Supports digits separators. }
  196. var
  197. Len, Base, StartIndex, I: Integer;
  198. V: Integer64;
  199. C: Char;
  200. begin
  201. Result := False;
  202. Len := Length(S);
  203. Base := 10;
  204. StartIndex := 1;
  205. if Len > 0 then begin
  206. if S[1] = '$' then begin
  207. Base := 16;
  208. Inc(StartIndex);
  209. end else if S[1] = '_' then
  210. Exit;
  211. end;
  212. if (StartIndex > Len) or (S[StartIndex] = '_') then
  213. Exit;
  214. V := To64(0);
  215. for I := StartIndex to Len do begin
  216. C := UpCase(S[I]);
  217. case C of
  218. '0'..'9':
  219. begin
  220. if not Mul64(V, Base) then
  221. Exit;
  222. if not Inc64(V, Ord(C) - Ord('0')) then
  223. Exit;
  224. end;
  225. 'A'..'F':
  226. begin
  227. if Base <> 16 then
  228. Exit;
  229. if not Mul64(V, Base) then
  230. Exit;
  231. if not Inc64(V, Ord(C) - (Ord('A') - 10)) then
  232. Exit;
  233. end;
  234. '_':
  235. { Ignore }
  236. else
  237. Exit;
  238. end;
  239. end;
  240. X := V;
  241. Result := True;
  242. end;
  243. function Integer64ToStr(X: Integer64): String;
  244. var
  245. I: Integer;
  246. Buf: array[0..31] of Char; { need at least 20 characters }
  247. begin
  248. I := High(Buf) + 1;
  249. repeat
  250. Dec(I);
  251. Buf[I] := Chr(Ord('0') + Div64(X, 10));
  252. until (X.Lo = 0) and (X.Hi = 0);
  253. SetString(Result, PChar(@Buf[I]), (High(Buf) + 1) - I);
  254. end;
  255. function To64(const Lo: Longword): Integer64;
  256. begin
  257. Result := Lo;
  258. end;
  259. { Integer64 }
  260. class operator Integer64.Implicit(const A: Int64): Integer64;
  261. begin
  262. Int64Rec(Result) := Int64Rec(A);
  263. end;
  264. class operator Integer64.Implicit(const A: Integer64): Int64;
  265. begin
  266. Int64Rec(Result) := Int64Rec(A);
  267. end;
  268. end.