Subversion Repositories decoder

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 daniel-mar 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.