Int64Em.pas 6.2 KB

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