IdHash.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. {
  2. $Project$
  3. $Workfile$
  4. $Revision$
  5. $DateUTC$
  6. $Id$
  7. This file is part of the Indy (Internet Direct) project, and is offered
  8. under the dual-licensing agreement described on the Indy website.
  9. (http://www.indyproject.org/)
  10. Copyright:
  11. (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  12. }
  13. {
  14. $Log$
  15. }
  16. {
  17. Rev 1.10 7/24/04 12:54:32 PM RLebeau
  18. Compiler fix for TIdHash128.HashValue()
  19. Rev 1.9 7/23/04 7:09:12 PM RLebeau
  20. Added extra exception handling to various HashValue() methods
  21. Rev 1.8 2004.05.20 11:37:06 AM czhower
  22. IdStreamVCL
  23. Rev 1.7 2004.03.03 11:54:30 AM czhower
  24. IdStream change
  25. Rev 1.6 2004.02.03 5:44:48 PM czhower
  26. Name changes
  27. Rev 1.5 1/27/2004 4:00:08 PM SPerry
  28. StringStream ->IdStringStream
  29. Rev 1.4 11/10/2003 7:39:22 PM BGooijen
  30. Did all todo's ( TStream to TIdStream mainly )
  31. Rev 1.3 2003.10.24 10:43:08 AM czhower
  32. TIdSTream to dos
  33. Rev 1.2 10/18/2003 4:28:30 PM BGooijen
  34. Removed the pchar for DotNet
  35. Rev 1.1 10/8/2003 10:15:10 PM GGrieve
  36. replace TIdReadMemoryStream (might be fast, but not compatible with DotNet)
  37. Rev 1.0 11/13/2002 08:30:24 AM JPMugaas
  38. Initial import from FTP VC.
  39. }
  40. unit IdHash;
  41. interface
  42. {$i IdCompilerDefines.inc}
  43. uses
  44. Classes,
  45. IdFIPS,
  46. IdGlobal;
  47. type
  48. TIdHash = class(TObject)
  49. protected
  50. function GetHashBytes(AStream: TStream; ASize: Int64): TIdBytes; virtual; abstract;
  51. function HashToHex(const AHash: TIdBytes): String; virtual; abstract;
  52. function UInt16HashToHex(const AHash: TIdBytes; const ACount: Integer): String;
  53. function UInt32HashToHex(const AHash: TIdBytes; const ACount: Integer): String;
  54. public
  55. constructor Create; virtual;
  56. class function IsAvailable : Boolean; virtual;
  57. function HashString(const ASrc: string; ADestEncoding: IIdTextEncoding = nil): TIdBytes;
  58. function HashStringAsHex(const AStr: String; ADestEncoding: IIdTextEncoding = nil): String;
  59. function HashBytes(const ASrc: TIdBytes): TIdBytes;
  60. function HashBytesAsHex(const ASrc: TIdBytes): String;
  61. function HashStream(AStream: TStream): TIdBytes; overload;
  62. function HashStreamAsHex(AStream: TStream): String; overload;
  63. function HashStream(AStream: TStream; const AStartPos, ASize: Int64): TIdBytes; overload;
  64. function HashStreamAsHex(AStream: TStream; const AStartPos, ASize: Int64): String; overload;
  65. end;
  66. TIdHash16 = class(TIdHash)
  67. protected
  68. function GetHashBytes(AStream: TStream; ASize: Int64): TIdBytes; override;
  69. function HashToHex(const AHash: TIdBytes): String; override;
  70. public
  71. function HashValue(const ASrc: string; ADestEncoding: IIdTextEncoding = nil): UInt16; overload;
  72. function HashValue(const ASrc: TIdBytes): UInt16; overload;
  73. function HashValue(AStream: TStream): UInt16; overload;
  74. function HashValue(AStream: TStream; const AStartPos, ASize: Int64): UInt16; overload;
  75. procedure HashStart(var VRunningHash : UInt16); virtual; abstract;
  76. procedure HashEnd(var VRunningHash : UInt16); virtual;
  77. procedure HashByte(var VRunningHash : UInt16; const AByte : Byte); virtual; abstract;
  78. end;
  79. TIdHash32 = class(TIdHash)
  80. protected
  81. function GetHashBytes(AStream: TStream; ASize: Int64): TIdBytes; override;
  82. function HashToHex(const AHash: TIdBytes): String; override;
  83. public
  84. function HashValue(const ASrc: string; ADestEncoding: IIdTextEncoding = nil): UInt32; overload;
  85. function HashValue(const ASrc: TIdBytes): UInt32; overload;
  86. function HashValue(AStream: TStream): UInt32; overload;
  87. function HashValue(AStream: TStream; const AStartPos, ASize: Int64): UInt32; overload;
  88. procedure HashStart(var VRunningHash : UInt32); virtual; abstract;
  89. procedure HashEnd(var VRunningHash : UInt32); virtual;
  90. procedure HashByte(var VRunningHash : UInt32; const AByte : Byte); virtual; abstract;
  91. end;
  92. TIdHashClass = class of TIdHash;
  93. TIdHashIntF = class(TIdHash)
  94. protected
  95. function HashToHex(const AHash: TIdBytes): String; override;
  96. function InitHash : TIdHashIntCtx; virtual; abstract;
  97. procedure UpdateHash(ACtx : TIdHashIntCtx; const AIn : TIdBytes);
  98. function FinalHash(ACtx : TIdHashIntCtx) : TIdBytes;
  99. function GetHashBytes(AStream: TStream; ASize: Int64): TIdBytes; override;
  100. public
  101. class function IsAvailable : Boolean; override;
  102. class function IsIntfAvailable : Boolean; virtual;
  103. end;
  104. TIdHashNativeAndIntF = class(TIdHashIntF)
  105. protected
  106. function NativeGetHashBytes(AStream: TStream; ASize: Int64): TIdBytes; virtual;
  107. function GetHashBytes(AStream: TStream; ASize: Int64): TIdBytes; override;
  108. end;
  109. implementation
  110. uses
  111. IdGlobalProtocols, SysUtils;
  112. { TIdHash }
  113. constructor TIdHash.Create;
  114. begin
  115. inherited Create;
  116. end;
  117. function TIdHash.HashString(const ASrc: string; ADestEncoding: IIdTextEncoding = nil): TIdBytes;
  118. var
  119. LStream: TStream;
  120. begin
  121. LStream := TMemoryStream.Create;
  122. try
  123. WriteStringToStream(LStream, ASrc, ADestEncoding);
  124. LStream.Position := 0;
  125. Result := HashStream(LStream);
  126. finally
  127. LStream.Free;
  128. end;
  129. end;
  130. function TIdHash.HashStringAsHex(const AStr: String; ADestEncoding: IIdTextEncoding = nil): String;
  131. begin
  132. Result := HashToHex(HashString(AStr, ADestEncoding));
  133. end;
  134. function TIdHash.HashBytes(const ASrc: TIdBytes): TIdBytes;
  135. var
  136. LStream: TStream;
  137. begin
  138. LStream := TIdReadOnlyMemoryBufferStream.Create(PByte(ASrc), Length(ASrc));
  139. try
  140. Result := HashStream(LStream);
  141. finally
  142. LStream.Free;
  143. end;
  144. end;
  145. function TIdHash.HashBytesAsHex(const ASrc: TIdBytes): String;
  146. begin
  147. Result := HashToHex(HashBytes(ASrc));
  148. end;
  149. function TIdHash.HashStream(AStream: TStream): TIdBytes;
  150. begin
  151. Result := HashStream(AStream, -1, -1);
  152. end;
  153. function TIdHash.HashStreamAsHex(AStream: TStream): String;
  154. begin
  155. Result := HashToHex(HashStream(AStream));
  156. end;
  157. function TIdHash.HashStream(AStream: TStream; const AStartPos, ASize: Int64): TIdBytes;
  158. var
  159. LSize, LAvailable: Int64;
  160. begin
  161. if AStartPos >= 0 then begin
  162. AStream.Position := AStartPos;
  163. end;
  164. LAvailable := AStream.Size - AStream.Position;
  165. if ASize < 0 then begin
  166. LSize := LAvailable;
  167. end else begin
  168. LSize := IndyMin(LAvailable, ASize);
  169. end;
  170. Result := GetHashBytes(AStream, LSize);
  171. end;
  172. function TIdHash.HashStreamAsHex(AStream: TStream; const AStartPos, ASize: Int64): String;
  173. begin
  174. Result := HashToHex(HashStream(AStream, AStartPos, ASize));
  175. end;
  176. function TIdHash.UInt16HashToHex(const AHash: TIdBytes; const ACount: Integer): String;
  177. var
  178. LValue: UInt16;
  179. I: Integer;
  180. begin
  181. Result := '';
  182. for I := 0 to ACount-1 do begin
  183. LValue := BytesToUInt16(AHash, SizeOf(UInt16)*I);
  184. Result := Result + IntToHex(LValue, 4);
  185. end;
  186. end;
  187. function TIdHash.UInt32HashToHex(const AHash: TIdBytes; const ACount: Integer): String;
  188. begin
  189. Result := ToHex(AHash, ACount*SizeOf(UInt32));
  190. end;
  191. class function TIdHash.IsAvailable : Boolean;
  192. begin
  193. Result := True;
  194. end;
  195. { TIdHash16 }
  196. function TIdHash16.GetHashBytes(AStream: TStream; ASize: Int64): TIdBytes;
  197. const
  198. cBufSize = 1024; // Keep it small for dotNet
  199. var
  200. I: Integer;
  201. LBuffer: TIdBytes;
  202. LSize: Integer;
  203. LHash: UInt16;
  204. begin
  205. Result := nil;
  206. HashStart(LHash);
  207. SetLength(LBuffer, cBufSize);
  208. while ASize > 0 do
  209. begin
  210. LSize := ReadTIdBytesFromStream(AStream, LBuffer, IndyMin(cBufSize, ASize));
  211. if LSize < 1 then begin
  212. Break; // TODO: throw a stream read exception instead?
  213. end;
  214. for i := 0 to LSize - 1 do begin
  215. HashByte(LHash, LBuffer[i]);
  216. end;
  217. Dec(ASize, LSize);
  218. end;
  219. HashEnd(LHash);
  220. SetLength(Result, SizeOf(UInt16));
  221. CopyTIdUInt16(LHash, Result, 0);
  222. end;
  223. function TIdHash16.HashToHex(const AHash: TIdBytes): String;
  224. begin
  225. Result := IntToHex(BytesToUInt16(AHash), 4);
  226. end;
  227. procedure TIdHash16.HashEnd(var VRunningHash : UInt16);
  228. begin
  229. end;
  230. function TIdHash16.HashValue(const ASrc: string; ADestEncoding: IIdTextEncoding = nil): UInt16;
  231. begin
  232. Result := BytesToUInt16(HashString(ASrc, ADestEncoding));
  233. end;
  234. function TIdHash16.HashValue(const ASrc: TIdBytes): UInt16;
  235. begin
  236. Result := BytesToUInt16(HashBytes(ASrc));
  237. end;
  238. function TIdHash16.HashValue(AStream: TStream): UInt16;
  239. begin
  240. Result := BytesToUInt16(HashStream(AStream));
  241. end;
  242. function TIdHash16.HashValue(AStream: TStream; const AStartPos, ASize: Int64): UInt16;
  243. begin
  244. Result := BytesToUInt16(HashStream(AStream, AStartPos, ASize));
  245. end;
  246. { TIdHash32 }
  247. function TIdHash32.GetHashBytes(AStream: TStream; ASize: Int64): TIdBytes;
  248. const
  249. cBufSize = 1024; // Keep it small
  250. var
  251. I: Integer;
  252. LBuffer: TIdBytes;
  253. LSize: Integer;
  254. LHash: UInt32;
  255. begin
  256. Result := nil;
  257. HashStart(LHash);
  258. SetLength(LBuffer, cBufSize);
  259. while ASize > 0 do
  260. begin
  261. LSize := ReadTIdBytesFromStream(AStream, LBuffer, IndyMin(cBufSize, ASize));
  262. if LSize < 1 then begin
  263. Break; // TODO: throw a stream read exception instead?
  264. end;
  265. for i := 0 to LSize - 1 do begin
  266. HashByte(LHash, LBuffer[i]);
  267. end;
  268. Dec(ASize, LSize);
  269. end;
  270. HashEnd(LHash); // RLebeau: TIdHashCRC32 uses this to XOR the hash with $FFFFFFFF
  271. SetLength(Result, SizeOf(UInt32));
  272. CopyTIdUInt32(LHash, Result, 0);
  273. end;
  274. function TIdHash32.HashToHex(const AHash: TIdBytes): String;
  275. begin
  276. Result := UInt32ToHex(BytesToUInt32(AHash));
  277. end;
  278. procedure TIdHash32.HashEnd(var VRunningHash : UInt32);
  279. begin
  280. end;
  281. function TIdHash32.HashValue(const ASrc: string; ADestEncoding: IIdTextEncoding = nil): UInt32;
  282. begin
  283. Result := BytesToUInt32(HashString(ASrc, ADestEncoding));
  284. end;
  285. function TIdHash32.HashValue(const ASrc: TIdBytes): UInt32;
  286. begin
  287. Result := BytesToUInt32(HashBytes(ASrc));
  288. end;
  289. function TIdHash32.HashValue(AStream: TStream) : UInt32;
  290. begin
  291. Result := BytesToUInt32(HashStream(AStream));
  292. end;
  293. function TIdHash32.HashValue(AStream: TStream; const AStartPos, ASize: Int64) : UInt32;
  294. begin
  295. Result := BytesToUInt32(HashStream(AStream, AStartPos, ASize));
  296. end;
  297. { TIdHashIntf }
  298. function TIdHashIntf.FinalHash(ACtx: TIdHashIntCtx): TIdBytes;
  299. begin
  300. Result := IdFIPS.FinalHashInst(ACtx);
  301. end;
  302. function TIdHashIntf.GetHashBytes(AStream: TStream; ASize: Int64): TIdBytes;
  303. const
  304. cBufSize = 2048; // Keep it small
  305. var
  306. LBuf : TIdBytes;
  307. LSize : Int64;
  308. LCtx : TIdHashIntCtx;
  309. begin
  310. LCtx := InitHash;
  311. try
  312. if ASize > 0 then begin
  313. SetLength(LBuf, cBufSize);
  314. repeat
  315. LSize := ReadTIdBytesFromStream(AStream, LBuf, IndyMin(ASize, cBufSize));
  316. if LSize < 1 then begin
  317. Break; // TODO: throw a stream read exception?
  318. end;
  319. if LSize < cBufSize then begin
  320. SetLength(LBuf, LSize);
  321. UpdateHash(LCtx, LBuf);
  322. Break;
  323. end;
  324. UpdateHash(LCtx, LBuf);
  325. Dec(ASize, LSize);
  326. until ASize = 0;
  327. end;
  328. finally
  329. Result := FinalHash(LCtx);
  330. end;
  331. end;
  332. function TIdHashIntf.HashToHex(const AHash: TIdBytes): String;
  333. begin
  334. Result := ToHex(AHash);
  335. end;
  336. //done this way so we can override IsAvailble if there is a native
  337. //implementation.
  338. class function TIdHashIntf.IsAvailable: Boolean;
  339. begin
  340. Result := IsIntfAvailable;
  341. end;
  342. class function TIdHashIntF.IsIntfAvailable: Boolean;
  343. begin
  344. Result := IsHashingIntfAvail;
  345. end;
  346. procedure TIdHashIntf.UpdateHash(ACtx: TIdHashIntCtx; const AIn: TIdBytes);
  347. begin
  348. IdFIPS.UpdateHashInst(ACtx,AIn);
  349. end;
  350. { TIdHashNativeAndIntF }
  351. function TIdHashNativeAndIntF.GetHashBytes(AStream: TStream; ASize: Int64): TIdBytes;
  352. begin
  353. if IsIntfAvailable then begin
  354. Result := inherited GetHashBytes(AStream, ASize);
  355. end else begin
  356. Result := NativeGetHashBytes(AStream, ASize);
  357. end;
  358. end;
  359. function TIdHashNativeAndIntF.NativeGetHashBytes(AStream: TStream; ASize: Int64): TIdBytes;
  360. begin
  361. Result := nil;
  362. end;
  363. end.