Delphi 为什么嵌入式CRC和当前CRC不同?
我找到了德尔菲·埃克萨姆勒。它应该嵌入CRC并检查当前CRC。两者应该匹配,但我得到的结果不同。如何修复它?如何加速呢 CRC32Calc.pasDelphi 为什么嵌入式CRC和当前CRC不同?,delphi,delphi-xe5,crc32,Delphi,Delphi Xe5,Crc32,我找到了德尔菲·埃克萨姆勒。它应该嵌入CRC并检查当前CRC。两者应该匹配,但我得到的结果不同。如何修复它?如何加速呢 CRC32Calc.pas unit CRC32Calc; interface uses Classes, SysUtils, windows, messages; type Long = record LoWord: Word; HiWord: Word; end; const CRCPOLY = $EDB88320; procedure
unit CRC32Calc;
interface
uses Classes, SysUtils, windows, messages;
type
Long = record
LoWord: Word;
HiWord: Word;
end;
const
CRCPOLY = $EDB88320;
procedure BuildCRCTable;
function RecountCRC(b: byte; CrcOld: LongWord): LongWord;
function GetCRC32(FileName: string; Full: boolean): string;
function SetEmbeddedCRC(FileName: string): string;
function GetEmbeddedCRC(FileName: string): string;
function BytesToHexStr(pB: PByte; BufSize: LongWord): String;
function HexStrToBytes(Str: String): String;
implementation
var
CRCTable: array [0 .. 512] Of LongWord;
// A helper routine that creates and initializes
// the lookup table that is used when calculating a CRC polynomial
procedure BuildCRCTable;
var
i, j: Word;
r: LongWord;
begin
FillChar(CRCTable, SizeOf(CRCTable), 0);
for i := 0 to 255 do
begin
r := i shl 1;
for j := 8 downto 0 do
if (r and 1) <> 0 then
r := (r Shr 1) xor CRCPOLY
else
r := r shr 1;
CRCTable[i] := r;
end;
end;
// A helper routine that recalculates polynomial relative to the specified byte
function RecountCRC(b: byte; CrcOld: LongWord): LongWord;
begin
RecountCRC := CRCTable[byte(CrcOld xor LongWord(b))
] xor ((CrcOld shr 8) and $00FFFFFF)
end;
// A helper routine that converts Word into String
function HextW(w: Word): string;
const
h: array [0 .. 15] Of char = '0123456789ABCDEF';
begin
HextW := '';
HextW := h[Hi(w) shr 4] + h[Hi(w) and $F] + h[Lo(w) shr 4] + h[Lo(w) and $F];
end;
// A helper routine that converts LongWord into String
function HextL(l: LongWord): string;
begin
with Long(l) do
HextL := HextW(HiWord) + HextW(LoWord);
end;
// Calculate CRC32 checksum for the specified file
function GetCRC32(FileName: string; Full: boolean): string;
var
f: TFileStream;
i, CRC: LongWord;
aBt: byte;
begin
// Build a CRC table
BuildCRCTable;
CRC := $FFFFFFFF;
// Open the file
f := TFileStream.Create(FileName, (fmOpenRead or fmShareDenyNone));
// To calculate CRC for the whole file use this loop boundaries
if Full then
for i := 0 to f.Size - 1 do
begin
f.Read(aBt, 1);
CRC := RecountCRC(aBt, CRC);
end
else
// To calculate CRC for the file excluding the last 4 bytes
// use these loop boundaries
for i := 0 to f.Size - 5 do
begin
f.Read(aBt, 1);
CRC := RecountCRC(aBt, CRC);
end;
f.Destroy;
CRC := Not CRC;
Result := HextL(CRC);
end;
// Calculate CRC and writes it to the end of file
function SetEmbeddedCRC(FileName: string): string;
var
f: TFileStream;
CRCOffset: LongWord;
CRC: string;
begin
f := TFileStream.Create(FileName, (fmOpenReadWrite or fmShareDenyNone));
CRCOffset := f.Size;
// Append a placeholder for actual CRC to the file
f.Seek(CRCOffset, TSeekOrigin.soBeginning);
f.Write(PByte(HexStrToBytes('FFFFFFFF'))^, 4);
// Obtain CRC
CRC := GetCRC32(FileName, True);
// Write CRC to the end of file
f.Seek(CRCOffset, TSeekOrigin.soBeginning);
f.Write(PByte(HexStrToBytes(CRC))^, 4);
f.Destroy;
Result := CRC;
end;
// Extract the CRC that was stored at last 4 bytes of a file
function GetEmbeddedCRC(FileName: string): string;
var
f: TFileStream;
CRCOffset: LongWord;
pB: PByte;
begin
GetMem(pB, 4);
// Open file
f := TFileStream.Create(FileName, (fmOpenRead or fmShareDenyNone));
// Proceed upto the end of file
CRCOffset := f.Size - 4;
f.Seek(CRCOffset, TSeekOrigin.soBeginning);
// Read the last four bytes where the CRC is stored
f.Read(pB^, 4);
f.Destroy;
Result := BytesToHexStr(pB, 4);
end;
// A helper routine that converts byte value to string with hexadecimal integer
function BytesToHexStr(pB: PByte; BufSize: LongWord): String;
var
i, j, b: LongWord;
begin
SetLength(Result, 2 * BufSize);
for i := 1 to BufSize do
begin
for j := 0 to 1 do
begin
if j = 1 then
b := pB^ div 16
else
b := pB^ - (pB^ div 16) * 16;
case b of
0:
Result[2 * i - j] := '0';
1:
Result[2 * i - j] := '1';
2:
Result[2 * i - j] := '2';
3:
Result[2 * i - j] := '3';
4:
Result[2 * i - j] := '4';
5:
Result[2 * i - j] := '5';
6:
Result[2 * i - j] := '6';
7:
Result[2 * i - j] := '7';
8:
Result[2 * i - j] := '8';
9:
Result[2 * i - j] := '9';
10:
Result[2 * i - j] := 'A';
11:
Result[2 * i - j] := 'B';
12:
Result[2 * i - j] := 'C';
13:
Result[2 * i - j] := 'D';
14:
Result[2 * i - j] := 'E';
15:
Result[2 * i - j] := 'F';
end;
end;
Inc(pB);
end;
end;
// A helper routine that converts string with hexadecimal integer to byte value
function HexStrToBytes(Str: String): String;
var
b, b2: byte;
lw, lw2, lw3: LongWord;
begin
lw := Length(Str) div 2;
SetLength(Result, lw);
for lw2 := 1 to lw do
begin
b := 0;
for lw3 := 0 to 1 do
begin
case Str[2 * lw2 - lw3] of
'0':
b2 := 0;
'1':
b2 := 1;
'2':
b2 := 2;
'3':
b2 := 3;
'4':
b2 := 4;
'5':
b2 := 5;
'6':
b2 := 6;
'7':
b2 := 7;
'8':
b2 := 8;
'9':
b2 := 9;
'a':
b2 := 10;
'b':
b2 := 11;
'c':
b2 := 12;
'd':
b2 := 13;
'e':
b2 := 14;
'f':
b2 := 15;
'A':
b2 := 10;
'B':
b2 := 11;
'C':
b2 := 12;
'D':
b2 := 13;
'E':
b2 := 14;
'F':
b2 := 15;
else
b2 := 0;
end;
if lw3 = 0 then
b := b2
else
b := b + 16 * b2;
end;
Result[lw2] := char(b);
end;
end;
end.
我的结果是:
AppendCRC.exe Hello_Delphi_World.exe
Full checksum (before): 1912DA64
Half checksum: 1912DA64
Full checksum (after): B3F0A43E
GetEmbeddedCRC: :4400A000
The checksum was successfully embedded.
我使用的是Delphi XE5。您应该了解此代码的工作原理。 总体思路是将CRC作为EXE结构之外的额外4个字节附加到文件末尾。(更好的办法是在开始时将CRC放入EXE头中的一个特殊字段) 然而,这引发了母鸡和鸡蛋的问题:在我们计算CRC并嵌入它之后,CRC文件被更改(附加CRC的值),并且更改文件的CRC也会更改 因此,您基本上必须实现CRC计算的两种模式/功能:整个文件和没有最后4个字节的文件。您应该使用后一种模式来计算附加后的CRC(您称之为嵌入),使用前一种模式在刚刚编译的程序上计算附加前的CRC GetCRC32函数总是从文件中剪切最后4个字节,因此在嵌入之前,它只计算文件的某个部分的CRC,而不是整个文件的CRC。但是必须有两种不同的模式 PS:您还可以将CRC“嵌入”到NTFS备用流中,比如将
MyApp.exe
程序和CRC存储为MyApp.exe:CRC
PPS。我认为在GetCRC32中使用无缓冲的逐字节读取应该非常慢。如果可能的话,最好使用TBytesStream将文件作为一个整体读入内存,然后以通常的循环方式扫描阵列。或者通过4096字节的块而不是字节变量来读取它。
对于最后一个不完整的缓冲区,您可以使用零来清除缓冲区的其余部分。我建议您将相关代码部分放在这里,从而解决这个问题。StackOverflow的设计目的是让答案和问题出现在网站上,而不是出现在任何时候都可能消失的外部链接中。让人们经历下载ZIP的麻烦会降低你得到正确答案的机会。我会修改SetEmbeddedCRC,使其不仅计算并在文件末尾添加CRC,还可以添加一个标记(或签名),以便GetEmbeddedCRC和SetEmbeddedCRC识别文件中是否存在CRC。如果已经存在CRC,则在计算CRC时将跳过该CRC。CRC签名可以是CRC的CRC的另一个4字节。添加到文件中的总字节数是8字节。这有什么意义?为什么不使用GetCRC32模式,忽略或不忽略最后字节?谢谢你的提议,但NTFS备用流不是我想要的。没有标记,GetCRC无法判断CRC是否错误或根本没有CRC。@fpiette我认为在实际意义上没有区别。EXE是否有“签名”之分
AppendCRC.exe Hello_Delphi_World.exe
Full checksum (before): 1912DA64
Half checksum: 1912DA64
Full checksum (after): B3F0A43E
GetEmbeddedCRC: :4400A000
The checksum was successfully embedded.