crc32.tcl

Go to the documentation of this file.
00001 /*  crc32.tcl -- Copyright (C) 2002 Pat Thoyts <patthoyts@users.sourceforge.net>*/
00002 /* */
00003 /*  CRC32 Cyclic Redundancy Check. */
00004 /*  (for algorithm see http://www.rad.com/networks/1994/err_con/crc.htm)*/
00005 /* */
00006 /*  From http://mini.net/tcl/2259.tcl*/
00007 /*  Written by Wayland Augur and Pat Thoyts.*/
00008 /* */
00009 /*  -------------------------------------------------------------------------*/
00010 /*  See the file "license.terms" for information on usage and redistribution*/
00011 /*  of this file, and for a DISCLAIMER OF ALL WARRANTIES.*/
00012 /*  -------------------------------------------------------------------------*/
00013 /*  $Id: crc32.tcl,v 1.21 2005/10/25 01:26:40 andreas_kupries Exp $*/
00014 
00015 package require Tcl 8.2
00016 
00017 namespace ::crc {
00018     variable crc32_version 1.3
00019     variable accel
00020     array  accel =  {critcl 0 trf 0}
00021 
00022     namespace export crc32
00023 
00024     variable crc32_tbl [list 0x00000000 0x77073096 0xEE0E612C 0x990951BA \
00025                            0x076DC419 0x706AF48F 0xE963A535 0x9E6495A3 \
00026                            0x0EDB8832 0x79DCB8A4 0xE0D5E91E 0x97D2D988 \
00027                            0x09B64C2B 0x7EB17CBD 0xE7B82D07 0x90BF1D91 \
00028                            0x1DB71064 0x6AB020F2 0xF3B97148 0x84BE41DE \
00029                            0x1ADAD47D 0x6DDDE4EB 0xF4D4B551 0x83D385C7 \
00030                            0x136C9856 0x646BA8C0 0xFD62F97A 0x8A65C9EC \
00031                            0x14015C4F 0x63066CD9 0xFA0F3D63 0x8D080DF5 \
00032                            0x3B6E20C8 0x4C69105E 0xD56041E4 0xA2677172 \
00033                            0x3C03E4D1 0x4B04D447 0xD20D85FD 0xA50AB56B \
00034                            0x35B5A8FA 0x42B2986C 0xDBBBC9D6 0xACBCF940 \
00035                            0x32D86CE3 0x45DF5C75 0xDCD60DCF 0xABD13D59 \
00036                            0x26D930AC 0x51DE003A 0xC8D75180 0xBFD06116 \
00037                            0x21B4F4B5 0x56B3C423 0xCFBA9599 0xB8BDA50F \
00038                            0x2802B89E 0x5F058808 0xC60CD9B2 0xB10BE924 \
00039                            0x2F6F7C87 0x58684C11 0xC1611DAB 0xB6662D3D \
00040                            0x76DC4190 0x01DB7106 0x98D220BC 0xEFD5102A \
00041                            0x71B18589 0x06B6B51F 0x9FBFE4A5 0xE8B8D433 \
00042                            0x7807C9A2 0x0F00F934 0x9609A88E 0xE10E9818 \
00043                            0x7F6A0DBB 0x086D3D2D 0x91646C97 0xE6635C01 \
00044                            0x6B6B51F4 0x1C6C6162 0x856530D8 0xF262004E \
00045                            0x6C0695ED 0x1B01A57B 0x8208F4C1 0xF50FC457 \
00046                            0x65B0D9C6 0x12B7E950 0x8BBEB8EA 0xFCB9887C \
00047                            0x62DD1DDF 0x15DA2D49 0x8CD37CF3 0xFBD44C65 \
00048                            0x4DB26158 0x3AB551CE 0xA3BC0074 0xD4BB30E2 \
00049                            0x4ADFA541 0x3DD895D7 0xA4D1C46D 0xD3D6F4FB \
00050                            0x4369E96A 0x346ED9FC 0xAD678846 0xDA60B8D0 \
00051                            0x44042D73 0x33031DE5 0xAA0A4C5F 0xDD0D7CC9 \
00052                            0x5005713C 0x270241AA 0xBE0B1010 0xC90C2086 \
00053                            0x5768B525 0x206F85B3 0xB966D409 0xCE61E49F \
00054                            0x5EDEF90E 0x29D9C998 0xB0D09822 0xC7D7A8B4 \
00055                            0x59B33D17 0x2EB40D81 0xB7BD5C3B 0xC0BA6CAD \
00056                            0xEDB88320 0x9ABFB3B6 0x03B6E20C 0x74B1D29A \
00057                            0xEAD54739 0x9DD277AF 0x04DB2615 0x73DC1683 \
00058                            0xE3630B12 0x94643B84 0x0D6D6A3E 0x7A6A5AA8 \
00059                            0xE40ECF0B 0x9309FF9D 0x0A00AE27 0x7D079EB1 \
00060                            0xF00F9344 0x8708A3D2 0x1E01F268 0x6906C2FE \
00061                            0xF762575D 0x806567CB 0x196C3671 0x6E6B06E7 \
00062                            0xFED41B76 0x89D32BE0 0x10DA7A5A 0x67DD4ACC \
00063                            0xF9B9DF6F 0x8EBEEFF9 0x17B7BE43 0x60B08ED5 \
00064                            0xD6D6A3E8 0xA1D1937E 0x38D8C2C4 0x4FDFF252 \
00065                            0xD1BB67F1 0xA6BC5767 0x3FB506DD 0x48B2364B \
00066                            0xD80D2BDA 0xAF0A1B4C 0x36034AF6 0x41047A60 \
00067                            0xDF60EFC3 0xA867DF55 0x316E8EEF 0x4669BE79 \
00068                            0xCB61B38C 0xBC66831A 0x256FD2A0 0x5268E236 \
00069                            0xCC0C7795 0xBB0B4703 0x220216B9 0x5505262F \
00070                            0xC5BA3BBE 0xB2BD0B28 0x2BB45A92 0x5CB36A04 \
00071                            0xC2D7FFA7 0xB5D0CF31 0x2CD99E8B 0x5BDEAE1D \
00072                            0x9B64C2B0 0xEC63F226 0x756AA39C 0x026D930A \
00073                            0x9C0906A9 0xEB0E363F 0x72076785 0x05005713 \
00074                            0x95BF4A82 0xE2B87A14 0x7BB12BAE 0x0CB61B38 \
00075                            0x92D28E9B 0xE5D5BE0D 0x7CDCEFB7 0x0BDBDF21 \
00076                            0x86D3D2D4 0xF1D4E242 0x68DDB3F8 0x1FDA836E \
00077                            0x81BE16CD 0xF6B9265B 0x6FB077E1 0x18B74777 \
00078                            0x88085AE6 0xFF0F6A70 0x66063BCA 0x11010B5C \
00079                            0x8F659EFF 0xF862AE69 0x616BFFD3 0x166CCF45 \
00080                            0xA00AE278 0xD70DD2EE 0x4E048354 0x3903B3C2 \
00081                            0xA7672661 0xD06016F7 0x4969474D 0x3E6E77DB \
00082                            0xAED16A4A 0xD9D65ADC 0x40DF0B66 0x37D83BF0 \
00083                            0xA9BCAE53 0xDEBB9EC5 0x47B2CF7F 0x30B5FFE9 \
00084                            0xBDBDF21C 0xCABAC28A 0x53B39330 0x24B4A3A6 \
00085                            0xBAD03605 0xCDD70693 0x54DE5729 0x23D967BF \
00086                            0xB3667A2E 0xC4614AB8 0x5D681B02 0x2A6F2B94 \
00087                            0xB40BBE37 0xC30C8EA1 0x5A05DF1B 0x2D02EF8D]
00088 
00089     /*  calculate the sign bit for the current platform.*/
00090     variable signbit
00091     if {![info exists signbit]} {
00092     variable v
00093         for { v =  1} {int($v) != 0} { signbit =  $v;  v =  [expr {$v<<1}]} {}
00094         un v = 
00095     }
00096     
00097     variable uid ; if {![info exists uid]} { uid =  0}
00098 }
00099 
00100 /*  -------------------------------------------------------------------------*/
00101 
00102 /*  crc::Crc32Init --*/
00103 /* */
00104 /*  Create and initialize a crc32 context. This is cleaned up*/
00105 /*  when we we call Crc32Final to obtain the result.*/
00106 /* */
00107 ret  ::crc::Crc32Init (optional seed =0xFFFFFFFF) {
00108     variable uid
00109     variable accel
00110     set token [namespace current]::[incr uid]
00111     upvar #0 $token state
00112     array set state [list sum $seed]
00113     # If the initial seed is set to some other value we cannot use Trf.
00114     if {$accel(trf) && $seed == 0xFFFFFFFF} {
00115         set s {}
00116         switch -exact -- $::tcl_platform(platform) {
00117             windows { set s [open NUL w] }
00118             unix    { set s [open /dev/null w] }
00119         }
00120         if {$s != {}} {
00121             fconfigure $s -translation binary -buffering none
00122             ::crc-zlib -attach $s -mode write \
00123                 -read-type variable \
00124                 -read-destination [subst $token](trfread) \
00125                 -write-type variable \
00126                 -write-destination [subst $token](trfwrite)
00127             array set state [list trfread 0 trfwrite 0 trf $s]
00128         }
00129     }
00130     return $token
00131 }
00132 
00133 /*  crc::Crc32Update --*/
00134 /* */
00135 /*  This is called to add more data into the checksum. You may*/
00136 /*  call this as many times as you require. Note that passing in*/
00137 /*  "ABC" is equivalent to passing these letters in as separate*/
00138 /*  calls -- hence this proc permits summing of chunked data.*/
00139 /* */
00140 /*  If we have a C-based implementation available, then we will*/
00141 /*  use it here in preference to the pure-Tcl implementation.*/
00142 /* */
00143 ret  ::crc::Crc32Update (type token , type data) {
00144     variable accel
00145     upvar #0 $token state
00146     set sum $state(sum)
00147     if {$accel(critcl)} {
00148         set sum [Crc32_c $data $sum]
00149     } elseif {[info exists state(trf)]} {
00150         puts -nonewline $state(trf) $data
00151         return
00152     } else {
00153         set sum [Crc32_tcl $data $sum]
00154     }
00155     set state(sum) [expr {$sum ^ 0xFFFFFFFF}]
00156     return
00157 }
00158 
00159 /*  crc::Crc32Final -- */
00160 /* */
00161 /*  This procedure is used to close the context and returns the*/
00162 /*  checksum value. Once this procedure has been called the checksum*/
00163 /*  context is freed and cannot be used again.  */
00164 /* */
00165 ret  ::crc::Crc32Final (type token) {
00166     upvar #0 $token state
00167     if {[info exists state(trf)]} {
00168         close $state(trf)
00169         binary scan $state(trfwrite) i sum
00170         set sum [expr {$sum & 0xFFFFFFFF}]
00171     } else {
00172         set sum [expr {($state(sum) ^ 0xFFFFFFFF) & 0xFFFFFFFF}]
00173     }
00174     unset state
00175     return $sum
00176 }
00177 
00178 /*  crc::Crc32_tcl --*/
00179 /* */
00180 /*  The pure-Tcl implementation of a table based CRC-32 checksum.*/
00181 /*  The seed should always be 0xFFFFFFFF to begin with, but for*/
00182 /*  successive chunks of data the seed should be set to the result*/
00183 /*  of the last chunk.*/
00184 /* */
00185 ret  ::crc::Crc32_tcl (type data , optional seed =0xFFFFFFFF) {
00186     variable crc32_tbl
00187     variable signbit
00188     set signmask [expr {~$signbit>>7}]
00189     set crcval $seed
00190 
00191     binary scan $data c* nums
00192     foreach {n} $nums {
00193         set ndx [expr {($crcval ^ $n) & 0xFF}]
00194         set lkp [lindex $crc32_tbl $ndx]
00195         set crcval [expr {($lkp ^ ($crcval >> 8 & $signmask)) & 0xFFFFFFFF}]
00196     }
00197     
00198     return [expr {$crcval ^ 0xFFFFFFFF}]
00199 }
00200 
00201 /*  crc::Crc32_c --*/
00202 /* */
00203 /*  A C version of the CRC-32 code using the same table. This is*/
00204 /*  designed to be compiled using critcl.*/
00205 /* */
00206 if {[package provide critcl] != {}} {
00207     namespace ::crc {
00208         critcl::ccommand Crc32_c {dummy interp objc objv} {
00209             int r = TCL_OK;
00210             unsigned long t = 0xFFFFFFFFL;
00211 
00212             if (objc < 2 || objc > 3) {
00213                 Tcl_WrongNumArgs(interp, 1, objv, "data ?seed?");
00214                 return TCL_ERROR;
00215             }
00216             
00217             if (objc == 3)
00218                 r = Tcl_GetLongFromObj(interp, objv[2], (long *)&t);
00219 
00220             if (r == TCL_OK) {
00221                 int cn, size, ndx;
00222                 unsigned char *data;
00223                 unsigned long lkp;
00224                 Tcl_Obj *tblPtr, *lkpPtr;
00225 
00226                 tblPtr = Tcl_GetVar2Ex(interp, "::crc::crc32_tbl", NULL,
00227                                        TCL_LEAVE_ERR_MSG );
00228                 if (tblPtr == NULL)
00229                     r = TCL_ERROR;
00230                 if (r == TCL_OK)
00231                     data = Tcl_GetByteArrayFromObj(objv[1], &size);
00232                 for (cn = 0; r == TCL_OK && cn < size; cn++) {
00233                     ndx = (t ^ data[cn]) & 0xFF;
00234                     r = Tcl_ListObjIndex(interp, tblPtr, ndx, &lkpPtr);
00235                     if (r == TCL_OK)
00236                         r = Tcl_GetLongFromObj(interp, lkpPtr, &lkp);
00237                     if (r == TCL_OK)
00238                         t = lkp ^ (t >> 8);
00239                 }
00240             }
00241 
00242             if (r == TCL_OK)
00243                 Tcl_SetLongObj(Tcl_GetObjResult(interp), t ^ 0xFFFFFFFF);
00244             return r;
00245         }
00246     }
00247 }
00248 
00249 /*  LoadAccelerator --*/
00250 /* */
00251 /*  This package can make use of a number of compiled extensions to*/
00252 /*  accelerate the digest computation. This procedure manages the*/
00253 /*  use of these extensions within the package. During normal usage*/
00254 /*  this should not be called, but the test package manipulates the*/
00255 /*  list of enabled accelerators.*/
00256 /* */
00257 ret  ::crc::LoadAccelerator (type name) {
00258     variable accel
00259     set r 0
00260     switch -exact -- $name {
00261         critcl {
00262             if {![catch {package require tcllibc}]
00263                 || ![catch {package require crcc}]} {
00264                 set r [expr {[info command ::crc::Crc32_c] != {}}]
00265             }
00266         }
00267         trf {
00268             if {![catch {package require Trf}]} {
00269                 set r [expr {![catch {::crc-zlib aa} msg]}]
00270             }
00271         }
00272         default {
00273             return -code error "invalid accelerator package:\
00274                 must be one of [join [array names accel] {, }]"
00275         }
00276     }
00277     set accel($name) $r
00278 }
00279 
00280 /*  crc::Pop --*/
00281 /* */
00282 /*  Pop the nth element off a list. Used in options processing.*/
00283 /* */
00284 ret  ::crc::Pop (type varname , optional nth =0) {
00285     upvar $varname args
00286     set r [lindex $args $nth]
00287     set args [lreplace $args $nth $nth]
00288     return $r
00289 }
00290 
00291 /*  crc::crc32 --*/
00292 /* */
00293 /*  Provide a Tcl implementation of a crc32 checksum similar to the*/
00294 /*  cksum and sum unix commands.*/
00295 /* */
00296 /*  Options:*/
00297 /*   -filename name - return a checksum for the specified file.*/
00298 /*   -format string - return the checksum using this format string.*/
00299 /*   -seed value    - seed the algorithm using value (default is 0xffffffff)*/
00300 /* */
00301 ret  ::crc::crc32 (type args) {
00302     array set opts [list -filename {} -format %u -seed 0xffffffff \
00303                         -channel {} -chunksize 4096 -timeout 30000]
00304     while {[string match -* [set option [lindex $args 0]]]} {
00305         switch -glob -- $option {
00306             -file*  { set opts(-filename) [Pop args 1] }
00307             -for*   { set opts(-format) [Pop args 1] }
00308             -chan*  { set opts(-channel) [Pop args 1] }
00309             -chunk* { set opts(-chunksize) [Pop args 1] }
00310             -time*  { set opts(-timeout) [Pop args 1] }
00311             -seed   { set opts(-seed) [Pop args 1] }
00312             -impl*  { set junk [Pop args 1] }
00313             default {
00314                 if {[llength $args] == 1} { break }
00315                 if {[string compare $option "--"] == 0} { Pop args; break }
00316                 set err [join [lsort [array names opts -*]] ", "]
00317                 return -code error "bad option \"$option\": must be $err"
00318             }
00319         }
00320         Pop args
00321     }
00322 
00323     # If a file was given - open it
00324     if {$opts(-filename) != {}} {
00325         set opts(-channel) [open $opts(-filename) r]
00326         fconfigure $opts(-channel) -translation binary
00327     }
00328 
00329     if {$opts(-channel) == {}} {
00330         
00331         if {[llength $args] != 1} {
00332             return -code error "wrong # args: should be \
00333                  \"crc32 ?-format string? ?-seed value? \
00334                  -channel chan | -file name | data\""
00335         }
00336         set tok [Crc32Init $opts(-seed)]
00337         Crc32Update $tok [lindex $args 0]
00338         set r [Crc32Final $tok]
00339 
00340     } else {
00341 
00342         set r $opts(-seed)
00343         set tok [Crc32Init $opts(-seed)]
00344         while {![eof $opts(-channel)]} {
00345             Crc32Update $tok [read $opts(-channel) $opts(-chunksize)]
00346         }
00347         set r [Crc32Final $tok]
00348 
00349         if {$opts(-filename) != {}} {
00350             close $opts(-channel)
00351         }
00352     }
00353 
00354     return [format $opts(-format) $r]
00355 }
00356 
00357 /*  -------------------------------------------------------------------------*/
00358 
00359 /*  Try and load a compiled extension to help (note - trf is fastest)*/
00360 namespace ::crc {
00361     foreach e {trf critcl} { if {[LoadAccelerator $e]} { break } }
00362 }
00363 
00364 package provide crc32 $::crc::crc32_version
00365 
00366 /*  -------------------------------------------------------------------------*/
00367 /* */
00368 /*  Local variables:*/
00369 /*    mode: tcl*/
00370 /*    indent-tabs-mode: nil*/
00371 /*  End:*/
00372 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1