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. |