source: tol/tolsh/tolsh.vfs/lib/tcllib1.10/base64/uuencode.tcl @ 8597867d

1941-docker-image-to-testdevel
Last change on this file since 8597867d was 8597867d, checked in by Jorge Pérez <josp.jorge@…>, 16 years ago

closes #976, se incluye tcllib1.10, base64 debe eliminarse del raiz de lib ya que esta incluido en tcllib

git-svn-id: ​https://www.tol-project.org/svn/tolp/trunk@2556 be4846ae-f051-483a-831f-b64e7d08527f

  • Property mode set to 100644
File size: 11.3 KB
Line 
1# uuencode - Copyright (C) 2002 Pat Thoyts <patthoyts@users.sourceforge.net>
2#
3# Provide a Tcl only implementation of uuencode and uudecode.
4#
5# -------------------------------------------------------------------------
6# See the file "license.terms" for information on usage and redistribution
7# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
8# -------------------------------------------------------------------------
9# @(#)$Id: uuencode.tcl,v 1.21 2006/10/14 06:30:55 andreas_kupries Exp $
10
11package require Tcl 8.2;                # tcl minimum version
12
13# Try and get some compiled helper package.
14if {[catch {package require tcllibc}]} {
15    catch {package require Trf}
16}
17
18namespace eval ::uuencode {
19    variable version 1.1.4
20
21    namespace export encode decode uuencode uudecode
22}
23
24proc ::uuencode::Enc {c} {
25    return [format %c [expr {($c != 0) ? (($c & 0x3f) + 0x20) : 0x60}]]
26}
27
28proc ::uuencode::Encode {s} {
29    set r {}
30    binary scan $s c* d
31    foreach {c1 c2 c3} $d {
32        if {$c1 == {}} {set c1 0}
33        if {$c2 == {}} {set c2 0}
34        if {$c3 == {}} {set c3 0}
35        append r [Enc [expr {$c1 >> 2}]]
36        append r [Enc [expr {(($c1 << 4) & 060) | (($c2 >> 4) & 017)}]]
37        append r [Enc [expr {(($c2 << 2) & 074) | (($c3 >> 6) & 003)}]]
38        append r [Enc [expr {($c3 & 077)}]]
39    }
40    return $r
41}
42
43
44proc ::uuencode::Decode {s} {
45    if {[string length $s] == 0} {return ""}
46    set r {}
47    binary scan [pad $s] c* d
48       
49    foreach {c0 c1 c2 c3} $d {
50        append r [format %c [expr {((($c0-0x20)&0x3F) << 2) & 0xFF
51                                   | ((($c1-0x20)&0x3F) >> 4) & 0xFF}]]
52        append r [format %c [expr {((($c1-0x20)&0x3F) << 4) & 0xFF
53                                   | ((($c2-0x20)&0x3F) >> 2) & 0xFF}]]
54        append r [format %c [expr {((($c2-0x20)&0x3F) << 6) & 0xFF
55                                   | (($c3-0x20)&0x3F) & 0xFF}]]
56    }
57    return $r
58}
59
60# -------------------------------------------------------------------------
61# C coded version of the Encode/Decode functions for base64c package.
62# -------------------------------------------------------------------------
63if {[package provide critcl] != {}} {
64    namespace eval ::uuencode {
65        critcl::ccode {
66            #include <string.h>
67            static unsigned char Enc(unsigned char c) {
68                return (c != 0) ? ((c & 0x3f) + 0x20) : 0x60;
69            }
70        }
71        critcl::ccommand CEncode {dummy interp objc objv} {
72            Tcl_Obj *inputPtr, *resultPtr;
73            int len, rlen, xtra;
74            unsigned char *input, *p, *r;
75           
76            if (objc !=  2) {
77                Tcl_WrongNumArgs(interp, 1, objv, "data");
78                return TCL_ERROR;
79            }
80           
81            inputPtr = objv[1];
82            input = Tcl_GetByteArrayFromObj(inputPtr, &len);
83            if ((xtra = (3 - (len % 3))) != 3) {
84                if (Tcl_IsShared(inputPtr))
85                    inputPtr = Tcl_DuplicateObj(inputPtr);
86                input = Tcl_SetByteArrayLength(inputPtr, len + xtra);
87                memset(input + len, 0, xtra);
88                len += xtra;
89            }
90
91            rlen = (len / 3) * 4;
92            resultPtr = Tcl_GetObjResult(interp);
93            if (Tcl_IsShared(resultPtr)) {
94                resultPtr = Tcl_DuplicateObj(resultPtr);
95                Tcl_SetObjResult(interp, resultPtr);
96            }
97            r = Tcl_SetByteArrayLength(resultPtr, rlen);
98            memset(r, 0, rlen);
99           
100            for (p = input; p < input + len; p += 3) {
101                char a, b, c;
102                a = *p; b = *(p+1), c = *(p+2);
103                *r++ = Enc(a >> 2);
104                *r++ = Enc(((a << 4) & 060) | ((b >> 4) & 017));
105                *r++ = Enc(((b << 2) & 074) | ((c >> 6) & 003));
106                *r++ = Enc(c & 077);
107            }
108           
109            return TCL_OK;
110        }
111
112        critcl::ccommand CDecode {dummy interp objc objv} {
113            Tcl_Obj *inputPtr, *resultPtr;
114            int len, rlen, xtra;
115            unsigned char *input, *p, *r;
116           
117            if (objc !=  2) {
118                Tcl_WrongNumArgs(interp, 1, objv, "data");
119                return TCL_ERROR;
120            }
121           
122            /* if input is not mod 4, extend it with nuls */
123            inputPtr = objv[1];
124            input = Tcl_GetByteArrayFromObj(inputPtr, &len);
125            if ((xtra = (4 - (len % 4))) != 4) {
126                if (Tcl_IsShared(inputPtr))
127                    inputPtr = Tcl_DuplicateObj(inputPtr);
128                input = Tcl_SetByteArrayLength(inputPtr, len + xtra);
129                memset(input + len, 0, xtra);
130                len += xtra;
131            }
132
133            /* output will be 1/3 smaller than input and a multiple of 3 */
134            rlen = (len / 4) * 3;
135            resultPtr = Tcl_GetObjResult(interp);
136            if (Tcl_IsShared(resultPtr)) {
137                resultPtr = Tcl_DuplicateObj(resultPtr);
138                Tcl_SetObjResult(interp, resultPtr);
139            }
140            r = Tcl_SetByteArrayLength(resultPtr, rlen);
141            memset(r, 0, rlen);
142           
143            for (p = input; p < input + len; p += 4) {
144                char a, b, c, d;
145                a = *p; b = *(p+1), c = *(p+2), d = *(p+3);
146                *r++ = (((a - 0x20) & 0x3f) << 2) | (((b - 0x20) & 0x3f) >> 4);
147                *r++ = (((b - 0x20) & 0x3f) << 4) | (((c - 0x20) & 0x3f) >> 2);
148                *r++ = (((c - 0x20) & 0x3f) << 6) | (((d - 0x20) & 0x3f) );
149            }
150           
151            return TCL_OK;
152        }
153    }
154}
155
156# -------------------------------------------------------------------------
157
158# Description:
159#  Permit more tolerant decoding of invalid input strings by padding to
160#  a multiple of 4 bytes with nulls.
161# Result:
162#  Returns the input string - possibly padded with uuencoded null chars.
163#
164proc ::uuencode::pad {s} {
165    if {[set mod [expr {[string length $s] % 4}]] != 0} {
166        append s [string repeat "`" [expr {4 - $mod}]]
167    }
168    return $s
169}
170
171# -------------------------------------------------------------------------
172
173# If the Trf package is available then we shall use this by default but the
174# Tcllib implementations are always visible if needed (ie: for testing)
175if {[info command ::uuencode::CDecode] != {}} {   
176    # tcllib critcl package
177    interp alias {} ::uuencode::encode {} ::uuencode::CEncode
178    interp alias {} ::uuencode::decode {} ::uuencode::CDecode
179} elseif {[package provide Trf] != {}} {
180    proc ::uuencode::encode {s} {
181        return [::uuencode -mode encode -- $s]
182    }
183    proc ::uuencode::decode {s} {
184        return [::uuencode -mode decode -- [pad $s]]
185    }
186} else {
187    # pure-tcl then
188    interp alias {} ::uuencode::encode {} ::uuencode::Encode
189    interp alias {} ::uuencode::decode {} ::uuencode::Decode
190}
191
192# -------------------------------------------------------------------------
193
194proc ::uuencode::uuencode {args} {
195    array set opts {mode 0644 filename {} name {}}
196    set wrongargs "wrong \# args: should be\
197            \"uuencode ?-name string? ?-mode octal?\
198            (-file filename | ?--? string)\""
199    while {[string match -* [lindex $args 0]]} {
200        switch -glob -- [lindex $args 0] {
201            -f* {
202                if {[llength $args] < 2} {
203                    return -code error $wrongargs
204                }
205                set opts(filename) [lindex $args 1]
206                set args [lreplace $args 0 0]
207            }
208            -m* {
209                if {[llength $args] < 2} {
210                    return -code error $wrongargs
211                }
212                set opts(mode) [lindex $args 1]
213                set args [lreplace $args 0 0]
214            }
215            -n* {
216                if {[llength $args] < 2} {
217                    return -code error $wrongargs
218                }
219                set opts(name) [lindex $args 1]
220                set args [lreplace $args 0 0]
221            }
222            -- {
223                set args [lreplace $args 0 0]
224                break
225            }
226            default {
227                return -code error "bad option [lindex $args 0]:\
228                      must be -file, -mode, or -name"
229            }
230        }
231        set args [lreplace $args 0 0]
232    }
233
234    if {$opts(name) == {}} {
235        set opts(name) $opts(filename)
236    }
237    if {$opts(name) == {}} {
238        set opts(name) "data.dat"
239    }
240
241    if {$opts(filename) != {}} {
242        set f [open $opts(filename) r]
243        fconfigure $f -translation binary
244        set data [read $f]
245        close $f
246    } else {
247        if {[llength $args] != 1} {
248            return -code error $wrongargs
249        }
250        set data [lindex $args 0]
251    }
252
253    set r {}
254    append r [format "begin %o %s" $opts(mode) $opts(name)] "\n"
255    for {set n 0} {$n < [string length $data]} {incr n 45} {
256        set s [string range $data $n [expr {$n + 44}]]
257        append r [Enc [string length $s]]
258        append r [encode $s] "\n"
259    }
260    append r "`\nend"
261    return $r
262}
263
264# -------------------------------------------------------------------------
265# Description:
266#  Perform uudecoding of a file or data. A file may contain more than one
267#  encoded data section so the result is a list where each element is a
268#  three element list of the provided filename, the suggested mode and the
269#  data itself.
270#
271proc ::uuencode::uudecode {args} {
272    array set opts {mode 0644 filename {}}
273    set wrongargs "wrong \# args: should be \"uudecode (-file filename | ?--? string)\""
274    while {[string match -* [lindex $args 0]]} {
275        switch -glob -- [lindex $args 0] {
276            -f* {
277                if {[llength $args] < 2} {
278                    return -code error $wrongargs
279                }
280                set opts(filename) [lindex $args 1]
281                set args [lreplace $args 0 0]
282            }
283            -- {
284                set args [lreplace $args 0 0]
285                break
286            }
287            default {
288                return -code error "bad option [lindex $args 0]:\
289                      must be -file"
290            }
291        }
292        set args [lreplace $args 0 0]
293    }
294
295    if {$opts(filename) != {}} {
296        set f [open $opts(filename) r]
297        set data [read $f]
298        close $f
299    } else {
300        if {[llength $args] != 1} {
301            return -code error $wrongargs
302        }
303        set data [lindex $args 0]
304    }
305
306    set state false
307    set result {}
308
309    foreach {line} [split $data "\n"] {
310        switch -exact -- $state {
311            false {
312                if {[regexp {^begin ([0-7]+) ([^\s]*)} $line \
313                         -> opts(mode) opts(name)]} {
314                    set state true
315                    set r {}
316                }
317            }
318
319            true {
320                if {[string match "end" $line]} {
321                    set state false
322                    lappend result [list $opts(name) $opts(mode) $r]
323                } else {
324                    scan $line %c c
325                    set n [expr {($c - 0x21)}]
326                    append r [string range \
327                                  [decode [string range $line 1 end]] 0 $n]
328                }
329            }
330        }
331    }
332
333    return $result
334}
335
336# -------------------------------------------------------------------------
337
338package provide uuencode $::uuencode::version
339
340# -------------------------------------------------------------------------
341#
342# Local variables:
343#   mode: tcl
344#   indent-tabs-mode: nil
345# End:
346
Note: See TracBrowser for help on using the repository browser.