Shared.Int64Em.pas 6.2 KB

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