[Quote title="CRC32.pas"]// CRC32 calculates a cyclic redundancy code (CRC), known as CRC-32, using // a byte-wise algorithm. // // (C) Copyright 1989, 1995-1996, 1999 Earl F. Glynn, Overland Park, KS. // All Rights Reserved. // // This UNIT was derived from the CRCT FORTRAN 77 program given in // "Byte-wise CRC Calculations" by Aram Perez in IEEE Micro, June 1983, // pp. 40-50. The constants here are for the CRC-32 generator polynomial, // as defined in the Microsoft Systems Journal, March 1995, pp. 107-108 // // This CRC algorithm emphasizes speed at the expense of the 256-element // lookup table. // // Updated for Delphi 4 dynamic arrays and stream I/O. July 1999.
UNIT CRC32;
INTERFACE
USES Windows; // DWORD for D3/D4 compatibility
TYPE {$IFDEF VER130} // This is a bit awkward // 8-byte integer TInteger8 = Int64; // Delphi 5 {$ELSE} {$IFDEF VER120} TInteger8 = Int64; // Delphi 4 {$ELSE} TInteger8 = COMP; // Delphi 2 or 3 {$ENDIF} {$ENDIF}
PROCEDURE CalcCRC32 (p: pointer; ByteCount: DWORD; VAR CRCvalue: DWORD);
PROCEDURE CalcFileCRC32 (FromName: STRING; VAR CRCvalue: DWORD; VAR TotalBytes: TInteger8; VAR error: WORD);
// Use CalcCRC32 as a procedure so CRCValue can be passed in but // also returned. This allows multiple calls to CalcCRC32 for // the "same" CRC-32 calculation. PROCEDURE CalcCRC32 (p: pointer; ByteCount: DWORD; VAR CRCValue: DWORD); // The following is a little cryptic (but executes very quickly). // The algorithm is as follows: // 1. exclusive-or the input byte with the low-order byte of // the CRC register to get an INDEX // 2. shift the CRC register eight bits to the right // 3. exclusive-or the CRC register with the contents of // Table[INDEX] // 4. repeat steps 1 through 3 for all bytes
VAR i: DWORD; q: ^BYTE; BEGIN q := p; FOR i := 0 TO ByteCount-1 DO BEGIN CRCvalue := (CRCvalue SHR 8) XOR Table[ q^ XOR (CRCvalue AND $000000FF) ]; INC(q) END END {CalcCRC32};
{$IFDEF StreamIO} // Contemporary method using TMemoryStream
// The CRC-32 value calculated here matches the one from the PKZIP program. // Use MemoryStream to read file in binary mode. PROCEDURE CalcFileCRC32 (FromName: STRING; VAR CRCvalue: DWORD; VAR TotalBytes: TInteger8; VAR error: WORD); VAR Stream: TMemoryStream; BEGIN error := 0; CRCValue := $FFFFFFFF; Stream := TMemoryStream.Create; TRY TRY Stream.LoadFromFile(FromName); IF Stream.Size > 0 THEN CalcCRC32 (Stream.Memory, Stream.Size, CRCvalue) EXCEPT ON E: EReadError DO error := 1 END;
CRCvalue := NOT CRCvalue FINALLY Stream.Free END; END {CalcFileCRC32};
{$ELSE} // "older" BlockRead method
// The CRC-32 value calculated here matches the one from the PKZIP program. // Use BlockRead to read file in binary mode. PROCEDURE CalcFileCRC32 (FromName: STRING; VAR CRCvalue: DWORD; VAR TotalBytes: TInteger8; VAR error: WORD); CONST BufferSize = 32768;
TYPE BufferIndex = 0..BufferSize-1; TBuffer = ARRAY[BufferIndex] OF BYTE; pBuffer = ^TBuffer;
VAR BytesRead: INTEGER; FromFile : FILE; IOBuffer : pBuffer; BEGIN New(IOBuffer); TRY FileMode := 0; {Turbo default is 2 for R/W; 0 is for R/O} CRCValue := $FFFFFFFF; ASSIGN (FromFile,FromName); {$I-} RESET (FromFile,1); {$I+} error := IOResult; IF error = 0 THEN BEGIN TotalBytes := 0;
REPEAT {$I-} BlockRead (FromFile, IOBuffer^, BufferSize, BytesRead); {$I+} error := IOResult; IF (error = 0) AND (BytesRead > 0) THEN BEGIN CalcCRC32 (IOBuffer, BytesRead, CRCvalue); TotalBytes := TotalBytes + BytesRead; // can't use INC with COMP END UNTIL (BytesRead = 0) OR (error > 0);
CLOSE (FromFile) END; CRCvalue := NOT CRCvalue FINALLY Dispose(IOBuffer) END END {CalcFileCRC32};