-
Notifications
You must be signed in to change notification settings - Fork 2
/
SZCRC32.pas
143 lines (116 loc) · 2.96 KB
/
SZCRC32.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
{$O+} // Optimization must be ON
unit SZCRC32;
{ Version 1.0.0 }
interface
uses Types, SysUtils, Classes;
function SZCRC32Update(P: Pointer; ByteCount: LongInt; CurCrc : DWORD): DWORD;
function SZCRC32Full (P: Pointer; ByteCount: LongInt): DWORD;
function SZCRC32UpdateStream(Stream : TStream; CurCrc : DWORD) : DWORD;
function SZCRC32FullStream (Stream : TStream) : DWORD;
function SZCRC32File(FileName : AnsiString) : DWORD;
function SZCRC32Test: Boolean;
implementation
const
CRC32BASE: DWORD = $FFFFFFFF;
Var
CRC32Table: array[0..255] of DWORD;
procedure SZCRC32MakeTable;
// Making the 32-bit CRC table
var
i,j: integer;
r: DWORD;
begin
for i:= 0 to 255 do
begin
r := i;
for j:=1 to 8 do
if (r and 1) = 1 then
r := (r shr 1) xor DWORD($EDB88320)
else
r := (r shr 1);
CRC32Table[i] := r
end;
end;
function SZCRC32Update(P: Pointer; ByteCount: LongInt; CurCrc : DWORD): DWORD;
// Updating existed 32-bit CRC with new calaculated
var
CRCValue: DWORD;
i: LongInt;
b: ^Byte;
begin
b := p;
CRCValue := CurCrc;
for i := 1 to ByteCount do
begin
CRCvalue := (CRCvalue shr 8) xor
CRC32Table[b^ xor byte(CRCvalue and $FF)];
inc(b);
end;
Result := CRCValue;
end;
function SZCRC32Full(P: Pointer; ByteCount: LongInt): DWORD;
// PKzip compatible - results with inverted bits
begin
Result := not DWORD(SZCRC32Update(P, ByteCount, CRC32BASE));
end;
function SZCRC32UpdateStream(Stream : TStream; CurCrc : DWORD) : DWORD;
// Calculates the 32-bit CRC of a stream
// For PKZip compatibility, result need to be inverted manually only for finally CRC value
const
CRC32BUFSIZE = 2048;
var
BufArray : array[0..(CRC32BUFSIZE-1)] of Byte;
Res : LongInt;
CRC32 : DWORD;
begin
// Initialize 32-bit CRC
CRC32 := CurCrc;
repeat
Res := Stream.Read(BufArray, CRC32BUFSIZE);
CRC32 := SZCRC32Update(@BufArray, Res, CRC32);
until (Res <> LongInt(CRC32BUFSIZE));
Result:=CRC32
end;
function SZCRC32FullStream(Stream : TStream) : DWORD;
// Calculates the 32-bit CRC of a stream
// PKZip compatible, result is inverted
begin
Result := not DWORD(SZCRC32UpdateStream(Stream, CRC32BASE));
end;
function SZCRC32File(FileName : AnsiString) : DWORD;
// Calculates the 32-bit CRC of a file
// PKZip compatible
var
FileStream: TFileStream;
begin
FileStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
Result := not DWORD(SZCRC32UpdateStream(FileStream, CRC32BASE));
finally
FileStream.Free;
end;
end;
function SZCRC32Test: Boolean;
// Testing the 32-bit CRC algorithm
const
CRC: DWORD =$29058C73;
var
TestCRC: DWORD;
TestData : Pointer;
i: integer;
begin
TestData:= GetMemory(256);
for i:=0 to 255 do
pbyte(pchar(TestData) +i)^:=i;
TestCRC := SZCRC32Full(TestData, 256);
FreeMemory(TestData);
if (TestCRC<>CRC)
then
Result := false
else
Result := true;
end;
initialization
// Making the 32-bit CRC table
SZCRC32MakeTable;
end.