Subversion Repositories decoder

Rev

Blame | Last modification | View Log | RSS feed

  1. {Copyright:      Hagen Reddmann  HaReddmann at T-Online dot de
  2.  Author:         Hagen Reddmann
  3.  Remarks:        Public Domain, this Copyright must be included
  4.  known Problems: none
  5.  Version:        5.1, Delphi Encryption Compendium
  6.                  Delphi 2-7, BCB 3-4, designed and testet under D3-7
  7.  Description:    threadsafe CRC Checksum functions as single unit.
  8.                  Implementation of Cyclic Redundance Checking.
  9.                  Supports ALL possible CRC's, per default are follow
  10.                  Standard CRC's supported:
  11.                    CRC-8, CRC-10, CRC-12 (Mobil Telephone),
  12.                    CRC-16, CRC-16-CCITT, CRC-16-ZModem,
  13.                    CRC-24 (PGP's MIME64 Armor CRC),
  14.                    CRC-32, CRC-32-CCITT and CRC-32-ZModem.
  15.  
  16.  Remarks:
  17.    - this unit should be fully PIC safe, means Kylix compatible
  18.    - this unit consume only 728 - max. 952 Bytes code if all functions are used
  19.    - 2 * 4 Bytes in Datasegment (BSS) are used
  20.    - on runtime it need two memoryblocks of size 2x1056 bytes if
  21.      CRC16() and CRC32() are called, if none of both is used no memory are need
  22.    - on multithread application and the use of CRC16() or CRC32() You should call
  23.      CRCInitThreadSafe at initialization of the application or before threaded
  24.      use of CRC16() or CRC32().
  25.    - yes, we could it realy more speedup, as example loop unrolling, but then the
  26.      code grows and i wanted a good compromiss between speed and size.
  27.  
  28.  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
  29.  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  30.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  31.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
  32.  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  33.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  34.  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  35.  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  36.  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  37.  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  38.  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  39.  }
  40. unit CRC;
  41. {$I VER.INC}
  42. interface
  43.  
  44. type
  45. // CRC Definitions Structure
  46.   PCRCDef = ^TCRCDef;
  47.   TCRCDef = packed record                // don't reorder or change this structure
  48.     Table: array[0..255] of Cardinal;    // Lookuptable, precomputed in CRCSetup
  49.     CRC: Cardinal;                       // intermediate CRC
  50.     Inverse: LongBool;                   // is this Polynomial a inverse function
  51.     Shift: Cardinal;                     // Shift Value for CRCCode, more speed
  52.     InitVector: Cardinal;                // Startvalue of CRC Computation
  53.     FinalVector: Cardinal;               // final XOR Vector of computed CRC
  54.     Mask: Cardinal;                      // precomputed AND Mask of computed CRC
  55.     Bits: Cardinal;                      // Bitsize of CRC
  56.     Polynomial: Cardinal;                // used Polynomial
  57.   end;                                   // SizeOf(TCRCDef) = 1056 = 0420h
  58.  
  59. // predefined Standard CRC Types
  60.   TCRCType = (CRC_8, CRC_10, CRC_12, CRC_16, CRC_16CCITT, CRC_16XModem, CRC_24,
  61.               CRC_32, CRC_32CCITT, CRC_32ZModem);
  62. type
  63.   TReadMethod = function(var Buffer; Count: LongInt): LongInt of object;
  64.  
  65. // calculates a CRC over Buffer with Size Bytes Length, used Algo in CRCType, all is done in one Step
  66. function CRCCalc(CRCType: TCRCType; const Buffer; Size: Cardinal): Cardinal;
  67. // use a callback
  68. function CRCCalcEx(CRCType: TCRCType; ReadMethod: TReadMethod; Size: Cardinal{$IFDEF VER_D4H} = $FFFFFFFF{$ENDIF}): Cardinal;
  69. // initialize CRC Definition with CRCType Standard CRC
  70. function CRCInit(var CRCDef: TCRCDef; CRCType: TCRCType): Boolean;
  71. // initilaize CRC Definition with a custom Algorithm
  72. function CRCSetup(var CRCDef: TCRCDef; Polynomial, Bits, InitVector, FinalVector: Cardinal; Inverse: LongBool): Boolean;
  73. // process over Buffer with Size Bytes Length a CRC definied in CRCDef.
  74. // Result is actual computed CRC with correction, same as CRCDone(),
  75. // CRCDef.CRC holds the actual computed CRC, a second/more call to CRCCode
  76. // computes than both/more buffers as one buffer.
  77. function CRCCode(var CRCDef: TCRCDef; const Buffer; Size: Cardinal): Cardinal;
  78. // use a callback, eg. TStream.Read(). I hate D4 because ther don't love here overloaded procedures
  79. function CRCCodeEx(var CRCDef: TCRCDef; ReadMethod: TReadMethod; Size: Cardinal{$IFDEF VER_D4H} = $FFFFFFFF{$ENDIF}): Cardinal;
  80. // retruns corrected CRC as definied in CRCDef, and reset CRCDef.CRC to InitVector
  81. function CRCDone(var CRCDef: TCRCDef): Cardinal;
  82. // predefined CRC16-Standard, call CRC := CRC16(0, Data, SizeOf(Data));
  83. function CRC16(CRC: Word; const Buffer; Size: Cardinal): Word;
  84. // predefined CRC32-CCITT, call CRC := CRC32(0, Data, SizeOf(Data));
  85. function CRC32(CRC: Cardinal; const Buffer; Size: Cardinal): Cardinal;
  86. // make it threadsafe
  87. procedure CRCInitThreadSafe;
  88.  
  89. { how to use:
  90.  
  91. var
  92.   CRC16: Word;
  93. begin
  94.   CRC16 := CRCCalc(CRC_16, Data, SizeOf(Data)); // all in one
  95. end;
  96.  
  97. var
  98.   CRC: TCRCDef;
  99.   CRC32: Cardinal;
  100. begin
  101.   CRCInit(CRC, CRC_32);                         // setup CRC data structure
  102.   CRCCode(CRC, Data, SizeOf(Data));             // returns correct CRC32 for this Data
  103.   CRCCode(CRC, PChar(String)^, Length(String)); // returns correct CRC32 for String AND CRC.CRC holds intermediate
  104.   CRC32 := CRCDone(CRC);                        // returns correct CRC32 for Data + String
  105. // after CRCDone we can restart a new calculation  
  106. end;
  107.  
  108.   above examples are fully threadsafe and requiere ~ $0420 Bytes Stackspace.
  109. }
  110.  
  111. implementation
  112.  
  113. function CRCSetup(var CRCDef: TCRCDef; Polynomial, Bits, InitVector, FinalVector: Cardinal; Inverse: LongBool): Boolean; register;
  114. asm // initialize CRCDef according to the parameters, calculate the lookup table
  115.        CMP   ECX,8
  116.        JB    @@8
  117.        PUSH  EBX
  118.        PUSH  EDI
  119.        PUSH  ESI
  120.        MOV   [EAX].TCRCDef.Polynomial,EDX
  121.        MOV   [EAX].TCRCDef.Bits,ECX
  122.        MOV   EBX,InitVector
  123.        MOV   EDI,FinalVector
  124.        MOV   ESI,Inverse
  125.        MOV   [EAX].TCRCDef.CRC,EBX
  126.        MOV   [EAX].TCRCDef.InitVector,EBX
  127.        MOV   [EAX].TCRCDef.FinalVector,EDI
  128.        MOV   [EAX].TCRCDef.Inverse,ESI
  129.        XOR   EDI,EDI
  130.        LEA   EBX,[ECX - 8]
  131.        SUB   ECX,32
  132.        DEC   EDI
  133.        NEG   ECX
  134.        SHR   EDI,CL
  135.        MOV   [EAX].TCRCDef.Shift,EBX
  136.        MOV   [EAX].TCRCDef.Mask,EDI
  137.        TEST  ESI,ESI
  138.        JZ    @@5
  139.        XOR   EBX,EBX
  140.        MOV   ECX,[EAX].TCRCDef.Bits
  141. @@1:   SHR   EDX,1
  142.        ADC   EBX,EBX
  143.        DEC   ECX
  144.        JNZ   @@1
  145.        NOP
  146.        MOV   ECX,255
  147.        NOP
  148. @@20:  MOV   EDX,ECX
  149.        SHR   EDX,1
  150.        JNC   @@21
  151.        XOR   EDX,EBX
  152. @@21:  SHR   EDX,1
  153.        JNC   @@22
  154.        XOR   EDX,EBX
  155. @@22:  SHR   EDX,1
  156.        JNC   @@23
  157.        XOR   EDX,EBX
  158. @@23:  SHR   EDX,1
  159.        JNC   @@24
  160.        XOR   EDX,EBX
  161. @@24:  SHR   EDX,1
  162.        JNC   @@25
  163.        XOR   EDX,EBX
  164. @@25:  SHR   EDX,1
  165.        JNC   @@26
  166.        XOR   EDX,EBX
  167. @@26:  SHR   EDX,1
  168.        JNC   @@27
  169.        XOR   EDX,EBX
  170. @@27:  SHR   EDX,1
  171.        JNC   @@28
  172.        XOR   EDX,EBX
  173. @@28:  MOV   [EAX + ECX * 4],EDX
  174.        DEC   ECX
  175.        JNL   @@20
  176.        JMP   @@7
  177. @@5:   AND   EDX,EDI
  178.        ROL   EDX,CL
  179.        MOV   EBX,255
  180. // can be coded branchfree      
  181. @@60:  MOV   ESI,EBX
  182.        SHL   ESI,25
  183.        JNC   @@61
  184.        XOR   ESI,EDX
  185. @@61:  ADD   ESI,ESI
  186.        JNC   @@62
  187.        XOR   ESI,EDX
  188. @@62:  ADD   ESI,ESI
  189.        JNC   @@63
  190.        XOR   ESI,EDX
  191. @@63:  ADD   ESI,ESI
  192.        JNC   @@64
  193.        XOR   ESI,EDX
  194. @@64:  ADD   ESI,ESI
  195.        JNC   @@65
  196.        XOR   ESI,EDX
  197. @@65:  ADD   ESI,ESI
  198.        JNC   @@66
  199.        XOR   ESI,EDX
  200. @@66:  ADD   ESI,ESI
  201.        JNC   @@67
  202.        XOR   ESI,EDX
  203. @@67:  ADD   ESI,ESI
  204.        JNC   @@68
  205.        XOR   ESI,EDX
  206. @@68:  ROR   ESI,CL
  207.        MOV   [EAX + EBX * 4],ESI
  208.        DEC   EBX
  209.        JNL   @@60
  210. @@7:   POP   ESI
  211.        POP   EDI
  212.        POP   EBX
  213. @@8:   CMC
  214.        SBB   EAX,EAX
  215.        NEG   EAX
  216. end;
  217.  
  218. function CRCCode(var CRCDef: TCRCDef; const Buffer; Size: Cardinal): Cardinal; register;
  219. asm // do the CRC computation
  220.        JECXZ @@5
  221.        TEST  EDX,EDX
  222.        JZ    @@5
  223.        PUSH  ESI
  224.        PUSH  EBX
  225.        MOV   ESI,EAX
  226.        CMP   [EAX].TCRCDef.Inverse,0
  227.        MOV   EAX,[ESI].TCRCDef.CRC
  228.        JZ    @@2
  229.        XOR   EBX,EBX
  230. @@1:   MOV   BL,[EDX]
  231.        XOR   BL,AL
  232.        SHR   EAX,8
  233.        INC   EDX
  234.        XOR   EAX,[ESI + EBX * 4]
  235.        DEC   ECX
  236.        JNZ   @@1
  237.        JMP   @@4
  238. @@2:   PUSH  EDI
  239.        MOV   EBX,EAX
  240.        MOV   EDI,ECX
  241.        MOV   ECX,[ESI].TCRCDef.Shift
  242.        MOV   EBX,EAX
  243. @@3:   SHR   EBX,CL
  244.        SHL   EAX,8
  245.        XOR   BL,[EDX]
  246.        INC   EDX
  247.        MOVZX EBX,BL
  248.        XOR   EAX,[ESI + EBX * 4]
  249.        DEC   EDI
  250.        MOV   EBX,EAX
  251.        JNZ   @@3
  252.        POP   EDI
  253. @@4:   MOV   [ESI].TCRCDef.CRC,EAX
  254.        XOR   EAX,[ESI].TCRCDef.FinalVector
  255.        AND   EAX,[ESI].TCRCDef.Mask
  256.        POP   EBX
  257.        POP   ESI
  258.        RET
  259. @@5:   MOV   EAX,[EAX].TCRCDef.CRC
  260. end;
  261.  
  262. function CRCCodeEx(var CRCDef: TCRCDef; ReadMethod: TReadMethod; Size: Cardinal): Cardinal;
  263. var
  264.   Buffer: array[0..1023] of Char;
  265.   Count: LongInt;
  266. begin
  267.   repeat
  268.     if Size > SizeOf(Buffer) then Count := SizeOf(Buffer) else Count := Size;
  269.     Count := ReadMethod(Buffer, Count);
  270.     Result := CRCCode(CRCDef, Buffer, Count);
  271.     Dec(Size, Count);
  272.   until (Size = 0) or (Count = 0);
  273. end;
  274.  
  275. function CRCInit(var CRCDef: TCRCDef; CRCType: TCRCType): Boolean; register;
  276. type
  277.   PCRCTab = ^TCRCTab;
  278.   TCRCTab = array[TCRCType] of packed record
  279.     Poly,Bits,Init,FInit: Cardinal;
  280.     Inverse: LongBool;
  281.   end;
  282.  
  283. {$IFOPT O-}{$O+}{$DEFINE NoOpt}{$ENDIF}
  284.   procedure CRCTab;          
  285.   asm
  286. //           Polynom   Bits  InitVec    FinitVec  Inverse
  287.        DD    $000000D1,  8, $00000000, $00000000, -1   // CRC_8  GSM/ERR
  288.        DD    $00000233, 10, $00000000, $00000000, -1   // CRC_10 ATM/OAM Cell
  289.        DD    $0000080F, 12, $00000000, $00000000, -1   // CRC_12
  290.        DD    $00008005, 16, $00000000, $00000000, -1   // CRC_16 ARC,IBM
  291.        DD    $00001021, 16, $00001D0F, $00000000,  0   // CRC_16 CCITT ITU
  292.        DD    $00008408, 16, $00000000, $00000000, -1   // CRC_16 XModem
  293.        DD    $00864CFB, 24, $00B704CE, $00000000,  0   // CRC_24
  294.        DD    $9DB11213, 32, $FFFFFFFF, $FFFFFFFF, -1   // CRC_32
  295.        DD    $04C11DB7, 32, $FFFFFFFF, $FFFFFFFF, -1   // CRC_32CCITT
  296.        DD    $04C11DB7, 32, $FFFFFFFF, $00000000, -1   // CRC_32ZModem
  297.  
  298. // some other CRC's, not all yet verfied
  299. //     DD    $00000007,  8, $00000000, $00000000, -1   // CRC_8  ATM/HEC
  300. //     DD    $00000007,  8, $00000000, $00000000,  0   // CRC_8 the SMBus Working Group
  301. //     DD    $00004599, 15, $00000000, $00000000, -1   // CRC_15 CANBus
  302. //     DD    $00001021, 16, $00000000, $00000000,  0   // CRC_16ZModem
  303. //     DD    $00001021, 16, $0000FFFF, $00000000,  0   // CRC_16 CCITT British Aerospace
  304. //     DD    $00004003, 16, $00000000, $00000000, -1   // CRC_16 reversed
  305. //     DD    $00001005, 16, $00000000, $00000000, -1   // CRC_16 X25
  306. //     DD    $00000053, 16, $00000000, $00000000, -1   // BasicCard 16Bit CRC (sparse poly for Crypto MCU)
  307. //     DD    $000000C5, 32, $00000000, $00000000, -1   // BasicCard 32Bit CRC
  308.  
  309. // http://dbforums.com/showthread.php?threadid=122012
  310.   end;
  311. {$IFDEF NoOpt}{$O-}{$ENDIF}
  312.  
  313. begin
  314.   with PCRCTab(@CRCTab)[CRCType] do
  315.     Result := CRCSetup(CRCDef, Poly, Bits, Init, FInit, Inverse);
  316. end;
  317.  
  318. function CRCDone(var CRCDef: TCRCDef): Cardinal; register;
  319. asm // finalize CRCDef after a computation
  320.        MOV   EDX,[EAX].TCRCDef.CRC
  321.        MOV   ECX,[EAX].TCRCDef.InitVector
  322.        XOR   EDX,[EAX].TCRCDef.FinalVector
  323.        MOV   [EAX].TCRCDef.CRC,ECX
  324.        AND   EDX,[EAX].TCRCDef.Mask
  325.        MOV   EAX,EDX
  326. end;
  327.  
  328. function CRCCalc(CRCType: TCRCType; const Buffer; Size: Cardinal): Cardinal;
  329. // inplace calculation
  330. var
  331.   CRC: TCRCDef;
  332. begin
  333.   CRCInit(CRC, CRCType);
  334.   Result := CRCCode(CRC, Buffer, Size);
  335. end;
  336.  
  337. function CRCCalcEx(CRCType: TCRCType; ReadMethod: TReadMethod; Size: Cardinal): Cardinal;
  338. var
  339.   CRC: TCRCDef;
  340. begin
  341.   CRCInit(CRC, CRCType);
  342.   Result := CRCCodeEx(CRC, ReadMethod, Size);
  343. end;
  344.  
  345. // predefined CRC16/CRC32CCITT, avoid slower lookuptable computation by use of precomputation
  346. var
  347.   FCRC16: PCRCDef = nil;
  348.   FCRC32: PCRCDef = nil;
  349.  
  350. function CRC16Init: Pointer;
  351. begin
  352.   GetMem(FCRC16, SizeOf(TCRCDef));
  353.   CRCInit(FCRC16^, CRC_16);
  354.   Result := FCRC16;
  355. end;
  356.  
  357. function CRC16(CRC: Word; const Buffer; Size: Cardinal): Word;
  358. asm
  359.        JECXZ @@2
  360.        PUSH  EDI
  361.        PUSH  ESI
  362.        MOV   EDI,ECX
  363. {$IFDEF PIC}
  364.        MOV   ESI,[EBX].FCRC16
  365. {$ELSE}
  366.        MOV   ESI,FCRC16
  367. {$ENDIF}
  368.        XOR   ECX,ECX
  369.        TEST  ESI,ESI
  370.        JZ    @@3
  371. @@1:   MOV    CL,[EDX]
  372.        XOR    CL,AL
  373.        SHR   EAX,8
  374.        INC   EDX
  375.        XOR   EAX,[ESI + ECX * 4]
  376.        DEC   EDI
  377.        JNZ   @@1
  378.        POP   ESI
  379.        POP   EDI
  380. @@2:   RET
  381. @@3:   PUSH  EAX
  382.        PUSH  EDX
  383.        CALL  CRC16Init
  384.        MOV   ESI,EAX
  385.        XOR   ECX,ECX
  386.        POP   EDX
  387.        POP   EAX
  388.        JMP   @@1
  389. end;
  390.  
  391. function CRC32Init: Pointer;
  392. begin
  393.   GetMem(FCRC32, SizeOf(TCRCDef));
  394.   CRCInit(FCRC32^, CRC_32CCITT);
  395.   Result := FCRC32;
  396. end;
  397.  
  398. function CRC32(CRC: Cardinal; const Buffer; Size: Cardinal): Cardinal;
  399. asm
  400.        JECXZ @@2
  401.        PUSH  EDI
  402.        PUSH  ESI
  403.        NOT   EAX                    // inverse Input CRC
  404.        MOV   EDI,ECX
  405. {$IFDEF PIC}
  406.        MOV   ESI,[EBX].FCRC32
  407. {$ELSE}
  408.        MOV   ESI,FCRC32
  409. {$ENDIF}
  410.        XOR   ECX,ECX
  411.        TEST  ESI,ESI
  412.        JZ    @@3
  413. @@1:   MOV    CL,[EDX]
  414.        XOR    CL,AL
  415.        SHR   EAX,8
  416.        INC   EDX
  417.        XOR   EAX,[ESI + ECX * 4]
  418.        DEC   EDI
  419.        JNZ   @@1
  420.        NOT   EAX                    // inverse Output CRC
  421.        POP   ESI
  422.        POP   EDI
  423. @@2:   RET
  424. @@3:   PUSH  EAX
  425.        PUSH  EDX
  426.        CALL  CRC32Init
  427.        MOV   ESI,EAX
  428.        XOR   ECX,ECX
  429.        POP   EDX
  430.        POP   EAX
  431.        JMP   @@1
  432. end;
  433.  
  434. procedure CRCInitThreadSafe;
  435. begin
  436.   CRC16Init;
  437.   CRC32Init;
  438. end;
  439.  
  440. initialization
  441. finalization
  442.   if FCRC16 <> nil then FreeMem(FCRC16);
  443.   if FCRC32 <> nil then FreeMem(FCRC32);
  444. end.
  445.