uuencode.tcl
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 package require Tcl 8.2;
00012
00013
00014 if {[catch {package require tcllibc}]} {
00015 catch {package require Trf}
00016 }
00017
00018 namespace ::uuencode {
00019 variable version 1.1.4
00020
00021 namespace export encode decode uuencode uudecode
00022 }
00023
00024 ret ::uuencode::Enc (type c) {
00025 return [format %c [expr {($c != 0) ? (($c & 0x3f) + 0x20) : 0x60}]]
00026 }
00027
00028 ret ::uuencode::Encode (type s) {
00029 set r {}
00030 binary scan $s c* d
00031 foreach {c1 c2 c3} $d {
00032 if {$c1 == {}} {set c1 0}
00033 if {$c2 == {}} {set c2 0}
00034 if {$c3 == {}} {set c3 0}
00035 append r [Enc [expr {$c1 >> 2}]]
00036 append r [Enc [expr {(($c1 << 4) & 060) | (($c2 >> 4) & 017)}]]
00037 append r [Enc [expr {(($c2 << 2) & 074) | (($c3 >> 6) & 003)}]]
00038 append r [Enc [expr {($c3 & 077)}]]
00039 }
00040 return $r
00041 }
00042
00043
00044 ret ::uuencode::Decode (type s) {
00045 if {[string length $s] == 0} {return ""}
00046 set r {}
00047 binary scan [pad $s] c* d
00048
00049 foreach {c0 c1 c2 c3} $d {
00050 append r [format %c [expr {((($c0-0x20)&0x3F) << 2) & 0xFF
00051 | ((($c1-0x20)&0x3F) >> 4) & 0xFF}]]
00052 append r [format %c [expr {((($c1-0x20)&0x3F) << 4) & 0xFF
00053 | ((($c2-0x20)&0x3F) >> 2) & 0xFF}]]
00054 append r [format %c [expr {((($c2-0x20)&0x3F) << 6) & 0xFF
00055 | (($c3-0x20)&0x3F) & 0xFF}]]
00056 }
00057 return $r
00058 }
00059
00060
00061
00062
00063 if {[package provide critcl] != {}} {
00064 namespace ::uuencode {
00065 critcl::ccode {
00066
00067 static unsigned char Enc(unsigned char c) {
00068 return (c != 0) ? ((c & 0x3f) + 0x20) : 0x60;
00069 }
00070 }
00071 critcl::ccommand CEncode {dummy interp objc objv} {
00072 Tcl_Obj *inputPtr, *resultPtr;
00073 int len, rlen, xtra;
00074 unsigned char *input, *p, *r;
00075
00076 if (objc != 2) {
00077 Tcl_WrongNumArgs(interp, 1, objv, "data");
00078 return TCL_ERROR;
00079 }
00080
00081 inputPtr = objv[1];
00082 input = Tcl_GetByteArrayFromObj(inputPtr, &len);
00083 if ((xtra = (3 - (len % 3))) != 3) {
00084 if (Tcl_IsShared(inputPtr))
00085 inputPtr = Tcl_DuplicateObj(inputPtr);
00086 input = Tcl_SetByteArrayLength(inputPtr, len + xtra);
00087 mem(input = + len, 0, xtra);
00088 len += xtra;
00089 }
00090
00091 rlen = (len / 3) * 4;
00092 resultPtr = Tcl_GetObjResult(interp);
00093 if (Tcl_IsShared(resultPtr)) {
00094 resultPtr = Tcl_DuplicateObj(resultPtr);
00095 Tcl_SetObjResult(interp, resultPtr);
00096 }
00097 r = Tcl_SetByteArrayLength(resultPtr, rlen);
00098 mem(r = , 0, rlen);
00099
00100 for (p = input; p < input + len; p += 3) {
00101 char a, b, c;
00102 a = *p; b = *(p+1), c = *(p+2);
00103 *r++ = Enc(a >> 2);
00104 *r++ = Enc(((a << 4) & 060) | ((b >> 4) & 017));
00105 *r++ = Enc(((b << 2) & 074) | ((c >> 6) & 003));
00106 *r++ = Enc(c & 077);
00107 }
00108
00109 return TCL_OK;
00110 }
00111
00112 critcl::ccommand CDecode {dummy interp objc objv} {
00113 Tcl_Obj *inputPtr, *resultPtr;
00114 int len, rlen, xtra;
00115 unsigned char *input, *p, *r;
00116
00117 if (objc != 2) {
00118 Tcl_WrongNumArgs(interp, 1, objv, "data");
00119 return TCL_ERROR;
00120 }
00121
00122
00123 inputPtr = objv[1];
00124 input = Tcl_GetByteArrayFromObj(inputPtr, &len);
00125 if ((xtra = (4 - (len % 4))) != 4) {
00126 if (Tcl_IsShared(inputPtr))
00127 inputPtr = Tcl_DuplicateObj(inputPtr);
00128 input = Tcl_SetByteArrayLength(inputPtr, len + xtra);
00129 mem(input = + len, 0, xtra);
00130 len += xtra;
00131 }
00132
00133
00134 rlen = (len / 4) * 3;
00135 resultPtr = Tcl_GetObjResult(interp);
00136 if (Tcl_IsShared(resultPtr)) {
00137 resultPtr = Tcl_DuplicateObj(resultPtr);
00138 Tcl_SetObjResult(interp, resultPtr);
00139 }
00140 r = Tcl_SetByteArrayLength(resultPtr, rlen);
00141 mem(r = , 0, rlen);
00142
00143 for (p = input; p < input + len; p += 4) {
00144 char a, b, c, d;
00145 a = *p; b = *(p+1), c = *(p+2), d = *(p+3);
00146 *r++ = (((a - 0x20) & 0x3f) << 2) | (((b - 0x20) & 0x3f) >> 4);
00147 *r++ = (((b - 0x20) & 0x3f) << 4) | (((c - 0x20) & 0x3f) >> 2);
00148 *r++ = (((c - 0x20) & 0x3f) << 6) | (((d - 0x20) & 0x3f) );
00149 }
00150
00151 return TCL_OK;
00152 }
00153 }
00154 }
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164 ret ::uuencode::pad (type s) {
00165 if {[set mod [expr {[string length $s] % 4}]] != 0} {
00166 append s [string repeat "`" [expr {4 - $mod}]]
00167 }
00168 return $s
00169 }
00170
00171
00172
00173
00174
00175 if {[info command ::uuencode::CDecode] != {}} {
00176
00177 interp alias {} ::uuencode::encode {} ::uuencode::CEncode
00178 interp alias {} ::uuencode::decode {} ::uuencode::CDecode
00179 } elseif {[package provide Trf] != {}} {
00180 ret ::uuencode::encode (type s) {
00181 return [::uuencode -mode encode -- $s]
00182 }
00183 ret ::uuencode::decode (type s) {
00184 return [::uuencode -mode decode -- [pad $s]]
00185 }
00186 } else {
00187
00188 interp alias {} ::uuencode::encode {} ::uuencode::Encode
00189 interp alias {} ::uuencode::decode {} ::uuencode::Decode
00190 }
00191
00192
00193
00194 ret ::uuencode::uuencode (type args) {
00195 array set opts {mode 0644 filename {} name {}}
00196 set wrongargs "wrong \# args: should be\
00197 \"uuencode ?-name string? ?-mode octal?\
00198 (-file filename | ?--? string)\""
00199 while {[string match -* [lindex $args 0]]} {
00200 switch -glob -- [lindex $args 0] {
00201 -f* {
00202 if {[llength $args] < 2} {
00203 return -code error $wrongargs
00204 }
00205 set opts(filename) [lindex $args 1]
00206 set args [lreplace $args 0 0]
00207 }
00208 -m* {
00209 if {[llength $args] < 2} {
00210 return -code error $wrongargs
00211 }
00212 set opts(mode) [lindex $args 1]
00213 set args [lreplace $args 0 0]
00214 }
00215 -n* {
00216 if {[llength $args] < 2} {
00217 return -code error $wrongargs
00218 }
00219 set opts(name) [lindex $args 1]
00220 set args [lreplace $args 0 0]
00221 }
00222 -- {
00223 set args [lreplace $args 0 0]
00224 break
00225 }
00226 default {
00227 return -code error "bad option [lindex $args 0]:\
00228 must be -file, -mode, or -name"
00229 }
00230 }
00231 set args [lreplace $args 0 0]
00232 }
00233
00234 if {$opts(name) == {}} {
00235 set opts(name) $opts(filename)
00236 }
00237 if {$opts(name) == {}} {
00238 set opts(name) "data.dat"
00239 }
00240
00241 if {$opts(filename) != {}} {
00242 set f [open $opts(filename) r]
00243 fconfigure $f -translation binary
00244 set data [read $f]
00245 close $f
00246 } else {
00247 if {[llength $args] != 1} {
00248 return -code error $wrongargs
00249 }
00250 set data [lindex $args 0]
00251 }
00252
00253 set r {}
00254 append r [format "begin %o %s" $opts(mode) $opts(name)] "\n"
00255 for {set n 0} {$n < [string length $data]} {incr n 45} {
00256 set s [string range $data $n [expr {$n + 44}]]
00257 append r [Enc [string length $s]]
00258 append r [encode $s] "\n"
00259 }
00260 append r "`\nend"
00261 return $r
00262 }
00263
00264
00265
00266
00267
00268
00269
00270
00271 ret ::uuencode::uudecode (type args) {
00272 array set opts {mode 0644 filename {}}
00273 set wrongargs "wrong \# args: should be \"uudecode (-file filename | ?--? string)\""
00274 while {[string match -* [lindex $args 0]]} {
00275 switch -glob -- [lindex $args 0] {
00276 -f* {
00277 if {[llength $args] < 2} {
00278 return -code error $wrongargs
00279 }
00280 set opts(filename) [lindex $args 1]
00281 set args [lreplace $args 0 0]
00282 }
00283 -- {
00284 set args [lreplace $args 0 0]
00285 break
00286 }
00287 default {
00288 return -code error "bad option [lindex $args 0]:\
00289 must be -file"
00290 }
00291 }
00292 set args [lreplace $args 0 0]
00293 }
00294
00295 if {$opts(filename) != {}} {
00296 set f [open $opts(filename) r]
00297 set data [read $f]
00298 close $f
00299 } else {
00300 if {[llength $args] != 1} {
00301 return -code error $wrongargs
00302 }
00303 set data [lindex $args 0]
00304 }
00305
00306 set state false
00307 set result {}
00308
00309 foreach {line} [split $data "\n"] {
00310 switch -exact -- $state {
00311 false {
00312 if {[regexp {^begin ([0-7]+) ([^\s]*)} $line \
00313 -> opts(mode) opts(name)]} {
00314 set state true
00315 set r {}
00316 }
00317 }
00318
00319 true {
00320 if {[string match "end" $line]} {
00321 set state false
00322 lappend result [list $opts(name) $opts(mode) $r]
00323 } else {
00324 scan $line %c c
00325 set n [expr {($c - 0x21)}]
00326 append r [string range \
00327 [decode [string range $line 1 end]] 0 $n]
00328 }
00329 }
00330 }
00331 }
00332
00333 return $result
00334 }
00335
00336
00337
00338 package provide uuencode $::uuencode::version
00339
00340
00341
00342
00343
00344
00345
00346
00347