home *** CD-ROM | disk | FTP | other *** search
/ H4CK3R 5 / hacker05 / 05_HACK_05.ISO / programacao / freewrap / TCLLIBsampleApp.exe / sample / tcllib / tcllib1.0 / base64 / base64.tcl next >
Encoding:
Text File  |  2001-08-17  |  8.8 KB  |  319 lines

  1. # base64.tcl --
  2. #
  3. # Encode/Decode base64 for a string
  4. # Stephen Uhler / Brent Welch (c) 1997 Sun Microsystems
  5. # The decoder was done for exmh by Chris Garrigues
  6. #
  7. # Copyright (c) 1998-2000 by Ajuba Solutions.
  8. # See the file "license.terms" for information on usage and redistribution
  9. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  10. # RCS: @(#) $Id: base64.tcl,v 1.12 2001/08/02 16:38:06 andreas_kupries Exp $
  11.  
  12. # Version 1.0 implemented Base64_Encode, Bae64_Decode
  13. # Version 2.0 uses the base64 namespace
  14. # Version 2.1 fixes various decode bugs and adds options to encode
  15. # Version 2.2 is much faster, Tcl8.0 compatible
  16.  
  17. package require Tcl 8
  18. namespace eval base64 {
  19. }
  20.  
  21. if {![catch {package require Trf 2.0}]} {
  22.     # Trf is available, so implement the functionality provided here
  23.     # in terms of calls to Trf for speed.
  24.  
  25.     # base64::encode --
  26.     #
  27.     #    Base64 encode a given string.
  28.     #
  29.     # Arguments:
  30.     #    args    ?-maxlen maxlen? ?-wrapchar wrapchar? string
  31.     #    
  32.     #        If maxlen is 0, the output is not wrapped.
  33.     #
  34.     # Results:
  35.     #    A Base64 encoded version of $string, wrapped at $maxlen characters
  36.     #    by $wrapchar.
  37.     
  38.     proc base64::encode {args} {
  39.     # Set the default wrapchar and maximum line length to match the output
  40.     # of GNU uuencode 4.2.  Various RFC's allow for different wrapping 
  41.     # characters and wraplengths, so these may be overridden by command line
  42.     # options.
  43.     set wrapchar "\n"
  44.     set maxlen 60
  45.  
  46.     if { [llength $args] == 0 } {
  47.         error "wrong # args: should be \"[lindex [info level 0] 0]\
  48.             ?-maxlen maxlen? ?-wrapchar wrapchar? string\""
  49.     }
  50.  
  51.     set optionStrings [list "-maxlen" "-wrapchar"]
  52.     for {set i 0} {$i < [llength $args] - 1} {incr i} {
  53.         set arg [lindex $args $i]
  54.         set index [lsearch -glob $optionStrings "${arg}*"]
  55.         if { $index == -1 } {
  56.         error "unknown option \"$arg\": must be -maxlen or -wrapchar"
  57.         }
  58.         incr i
  59.         if { $i >= [llength $args] - 1 } {
  60.         error "value for \"$arg\" missing"
  61.         }
  62.         set val [lindex $args $i]
  63.  
  64.         # The name of the variable to assign the value to is extracted
  65.         # from the list of known options, all of which have an
  66.         # associated variable of the same name as the option without
  67.         # a leading "-". The [string range] command is used to strip
  68.         # of the leading "-" from the name of the option.
  69.         #
  70.         # FRINK: nocheck
  71.         set [string range [lindex $optionStrings $index] 1 end] $val
  72.     }
  73.     
  74.     # [string is] requires Tcl8.2; this works with 8.0 too
  75.     if {[catch {expr {$maxlen % 2}}]} {
  76.         error "expected integer but got \"$maxlen\""
  77.     }
  78.  
  79.     set string [lindex $args end]
  80.     set result [::base64 -mode encode -- $string]
  81.     regsub -all -- \n $result {} result
  82.  
  83.     if {$maxlen > 0} {
  84.         set res ""
  85.         set edge [expr {$maxlen - 1}]
  86.         while {[string length $result] > $maxlen} {
  87.         append res [string range $result 0 $edge]$wrapchar
  88.         set result [string range $result $maxlen end]
  89.         }
  90.         if {[string length $result] > 0} {
  91.         append res $result
  92.         }
  93.         set result $res
  94.     }
  95.  
  96.     return $result
  97.     }
  98.  
  99.     # base64::decode --
  100.     #
  101.     #    Base64 decode a given string.
  102.     #
  103.     # Arguments:
  104.     #    string    The string to decode.  Characters not in the base64
  105.     #        alphabet are ignored (e.g., newlines)
  106.     #
  107.     # Results:
  108.     #    The decoded value.
  109.  
  110.     proc base64::decode {string} {
  111.     ::base64 -mode decode -- $string
  112.     }
  113.  
  114. } else {
  115.     # Without Trf use a pure tcl implementation
  116.  
  117.     namespace eval base64 {
  118.     variable base64 {}
  119.     variable base64_en {}
  120.  
  121.     # We create the auxiliary array base64_tmp, it will be unset later.
  122.  
  123.     set i 0
  124.     foreach char {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z \
  125.         a b c d e f g h i j k l m n o p q r s t u v w x y z \
  126.         0 1 2 3 4 5 6 7 8 9 + /} {
  127.         set base64_tmp($char) $i
  128.         lappend base64_en $char
  129.         incr i
  130.     }
  131.  
  132.     #
  133.     # Create base64 as list: to code for instance C<->3, specify
  134.     # that [lindex $base64 67] be 3 (C is 67 in ascii); non-coded
  135.     # ascii chars get a {}. we later use the fact that lindex on a
  136.     # non-existing index returns {}, and that [expr {} < 0] is true
  137.     #
  138.  
  139.     # the last ascii char is 'z'
  140.     scan z %c len
  141.     for {set i 0} {$i <= $len} {incr i} {
  142.         set char [format %c $i]
  143.         set val {}
  144.         if {[info exists base64_tmp($char)]} {
  145.         set val $base64_tmp($char)
  146.         } else {
  147.         set val {}
  148.         }
  149.         lappend base64 $val
  150.     }
  151.  
  152.     # code the character "=" as -1; used to signal end of message
  153.     scan = %c i
  154.     set base64 [lreplace $base64 $i $i -1]
  155.  
  156.     # remove unneeded variables
  157.     unset base64_tmp i char len val
  158.  
  159.     namespace export *
  160.     }
  161.  
  162.     # base64::encode --
  163.     #
  164.     #    Base64 encode a given string.
  165.     #
  166.     # Arguments:
  167.     #    args    ?-maxlen maxlen? ?-wrapchar wrapchar? string
  168.     #    
  169.     #        If maxlen is 0, the output is not wrapped.
  170.     #
  171.     # Results:
  172.     #    A Base64 encoded version of $string, wrapped at $maxlen characters
  173.     #    by $wrapchar.
  174.     
  175.     proc base64::encode {args} {
  176.     set base64_en $::base64::base64_en
  177.     
  178.     # Set the default wrapchar and maximum line length to match the output
  179.     # of GNU uuencode 4.2.  Various RFC's allow for different wrapping 
  180.     # characters and wraplengths, so these may be overridden by command line
  181.     # options.
  182.     set wrapchar "\n"
  183.     set maxlen 60
  184.  
  185.     if { [llength $args] == 0 } {
  186.         error "wrong # args: should be \"[lindex [info level 0] 0]\
  187.             ?-maxlen maxlen? ?-wrapchar wrapchar? string\""
  188.     }
  189.  
  190.     set optionStrings [list "-maxlen" "-wrapchar"]
  191.     for {set i 0} {$i < [llength $args] - 1} {incr i} {
  192.         set arg [lindex $args $i]
  193.         set index [lsearch -glob $optionStrings "${arg}*"]
  194.         if { $index == -1 } {
  195.         error "unknown option \"$arg\": must be -maxlen or -wrapchar"
  196.         }
  197.         incr i
  198.         if { $i >= [llength $args] - 1 } {
  199.         error "value for \"$arg\" missing"
  200.         }
  201.         set val [lindex $args $i]
  202.  
  203.         # The name of the variable to assign the value to is extracted
  204.         # from the list of known options, all of which have an
  205.         # associated variable of the same name as the option without
  206.         # a leading "-". The [string range] command is used to strip
  207.         # of the leading "-" from the name of the option.
  208.         #
  209.         # FRINK: nocheck
  210.         set [string range [lindex $optionStrings $index] 1 end] $val
  211.     }
  212.     
  213.     # [string is] requires Tcl8.2; this works with 8.0 too
  214.     if {[catch {expr {$maxlen % 2}}]} {
  215.         error "expected integer but got \"$maxlen\""
  216.     }
  217.  
  218.     set string [lindex $args end]
  219.  
  220.     set result {}
  221.     set state 0
  222.     set length 0
  223.  
  224.  
  225.     # Process the input bytes 3-by-3
  226.  
  227.     binary scan $string c* X
  228.     foreach {x y z} $X {
  229.         # Do the line length check before appending so that we don't get an
  230.         # extra newline if the output is a multiple of $maxlen chars long.
  231.         if {$maxlen && $length >= $maxlen} {
  232.         append result $wrapchar
  233.         set length 0
  234.         }
  235.     
  236.         append result [lindex $base64_en [expr {($x >>2) & 0x3F}]] 
  237.         if {$y != {}} {
  238.         append result [lindex $base64_en [expr {(($x << 4) & 0x30) | (($y >> 4) & 0xF)}]] 
  239.         if {$z != {}} {
  240.             append result \
  241.                 [lindex $base64_en [expr {(($y << 2) & 0x3C) | (($z >> 6) & 0x3)}]]
  242.             append result [lindex $base64_en [expr {($z & 0x3F)}]]
  243.         } else {
  244.             set state 2
  245.             break
  246.         }
  247.         } else {
  248.         set state 1
  249.         break
  250.         }
  251.         incr length 4
  252.     }
  253.     if {$state == 1} {
  254.         append result [lindex $base64_en [expr {(($x << 4) & 0x30)}]]== 
  255.     } elseif {$state == 2} {
  256.         append result [lindex $base64_en [expr {(($y << 2) & 0x3C)}]]=  
  257.     }
  258.     return $result
  259.     }
  260.  
  261.     # base64::decode --
  262.     #
  263.     #    Base64 decode a given string.
  264.     #
  265.     # Arguments:
  266.     #    string    The string to decode.  Characters not in the base64
  267.     #        alphabet are ignored (e.g., newlines)
  268.     #
  269.     # Results:
  270.     #    The decoded value.
  271.  
  272.     proc base64::decode {string} {
  273.     set base64 $::base64::base64
  274.  
  275.     binary scan $string c* X
  276.     foreach x $X {
  277.         set bits [lindex $base64 $x]
  278.         if {$bits >= 0} {
  279.         if {[llength [lappend nums $bits]] == 4} {
  280.             foreach {v w z y} $nums break
  281.             set a [expr {($v << 2) | ($w >> 4)}]
  282.             set b [expr {(($w & 0xF) << 4) | ($z >> 2)}]
  283.             set c [expr {(($z & 0x3) << 6) | $y}]
  284.             append output [binary format ccc $a $b $c]
  285.             set nums {}
  286.         }        
  287.         } elseif {$bits == -1} {
  288.         # = indicates end of data.  Output whatever chars are left.
  289.         # The encoding algorithm dictates that we can only have 1 or 2
  290.         # padding characters.  If x=={}, we have 12 bits of input 
  291.         # (enough for 1 8-bit output).  If x!={}, we have 18 bits of
  292.         # input (enough for 2 8-bit outputs).
  293.         
  294.         foreach {v w z} $nums break
  295.         set a [expr {($v << 2) | (($w & 0x30) >> 4)}]
  296.         
  297.         if {$z == {}} {
  298.             append output [binary format c $a ]
  299.         } else {
  300.             set b [expr {(($w & 0xF) << 4) | (($z & 0x3C) >> 2)}]
  301.             append output [binary format cc $a $b]
  302.         }        
  303.         break
  304.         } else {
  305.         # RFC 2045 says that line breaks and other characters not part
  306.         # of the Base64 alphabet must be ignored, and that the decoder
  307.         # can optionally emit a warning or reject the message.  We opt
  308.         # not to do so, but to just ignore the character. 
  309.         continue
  310.         }
  311.     }
  312.     return $output
  313.     }
  314. }
  315.  
  316. package provide base64 2.2
  317.  
  318.