yencode.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 catch {package require crc32};
00013 catch {package require tcllibc};
00014
00015 namespace ::yencode {
00016 variable version 1.1.1
00017 namespace export encode decode yencode ydecode
00018 }
00019
00020
00021
00022 ret ::yencode::Encode (type s) {
00023 set r {}
00024 binary scan $s c* d
00025 foreach {c} $d {
00026 set v [expr {($c + 42) % 256}]
00027 if {$v == 0x00 || $v == 0x09 || $v == 0x0A
00028 || $v == 0x0D || $v == 0x3D} {
00029 append r "="
00030 set v [expr {($v + 42) % 256}]
00031 }
00032 append r [format %c $v]
00033 }
00034 return $r
00035 }
00036
00037 ret ::yencode::Decode (type s) {
00038 if {[string length $s] == 0} {return ""}
00039 set r {}
00040 set esc 0
00041 binary scan $s c* d
00042 foreach c $d {
00043 if {$c == 61 && $esc == 0} {
00044 set esc 1
00045 continue
00046 }
00047 set v [expr {($c - 42) % 256}]
00048 if {$esc} {
00049 set v [expr {($v - 42) % 256}]
00050 set esc 0
00051 }
00052 append r [format %c $v]
00053 }
00054 return $r
00055 }
00056
00057
00058
00059
00060
00061 if {[package provide critcl] != {}} {
00062 namespace ::yencode {
00063 critcl::ccode {
00064
00065 }
00066 critcl::ccommand CEncode {dummy interp objc objv} {
00067 Tcl_Obj *inputPtr, *resultPtr;
00068 int len, rlen, xtra;
00069 unsigned char *input, *p, *r, v;
00070
00071 if (objc != 2) {
00072 Tcl_WrongNumArgs(interp, 1, objv, "data");
00073 return TCL_ERROR;
00074 }
00075
00076
00077 inputPtr = objv[1];
00078 input = Tcl_GetByteArrayFromObj(inputPtr, &len);
00079
00080
00081 rlen = len;
00082 for (p = input; p < input + len; p++) {
00083 v = (*p + 42) % 256;
00084 if (v == 0 || v == 9 || v == 0x0A || v == 0x0D || v == 0x3D)
00085 rlen++;
00086 }
00087
00088
00089 resultPtr = Tcl_GetObjResult(interp);
00090 if (Tcl_IsShared(resultPtr)) {
00091 resultPtr = Tcl_DuplicateObj(resultPtr);
00092 Tcl_SetObjResult(interp, resultPtr);
00093 }
00094 r = Tcl_SetByteArrayLength(resultPtr, rlen);
00095
00096
00097 for (p = input; p < input + len; p++) {
00098 v = (*p + 42) % 256;
00099 if (v == 0 || v == 9 || v == 0x0A || v == 0x0D || v == 0x3D) {
00100 *r++ = '=';
00101 v = (v + 42) % 256;
00102 }
00103 *r++ = v;
00104 }
00105
00106 return TCL_OK;
00107 }
00108
00109 critcl::ccommand CDecode {dummy interp objc objv} {
00110 Tcl_Obj *inputPtr, *resultPtr;
00111 int len, rlen, esc;
00112 unsigned char *input, *p, *r, v;
00113
00114 if (objc != 2) {
00115 Tcl_WrongNumArgs(interp, 1, objv, "data");
00116 return TCL_ERROR;
00117 }
00118
00119
00120 inputPtr = objv[1];
00121 input = Tcl_GetByteArrayFromObj(inputPtr, &len);
00122
00123
00124 resultPtr = Tcl_GetObjResult(interp);
00125 if (Tcl_IsShared(resultPtr)) {
00126 resultPtr = Tcl_DuplicateObj(resultPtr);
00127 Tcl_SetObjResult(interp, resultPtr);
00128 }
00129 r = Tcl_SetByteArrayLength(resultPtr, len);
00130
00131
00132 for (p = input, esc = 0, rlen = 0; p < input + len; p++) {
00133 if (*p == 61 && esc == 0) {
00134 esc = 1;
00135 continue;
00136 }
00137 v = (*p - 42) % 256;
00138 if (esc) {
00139 v = (v - 42) % 256;
00140 esc = 0;
00141 }
00142 *r++ = v;
00143 rlen++;
00144 }
00145 Tcl_SetByteArrayLength(resultPtr, rlen);
00146
00147 return TCL_OK;
00148 }
00149 }
00150 }
00151
00152 if {[info command ::yencode::CEncode] != {}} {
00153 interp alias {} ::yencode::encode {} ::yencode::CEncode
00154 interp alias {} ::yencode::decode {} ::yencode::CDecode
00155 } else {
00156 interp alias {} ::yencode::encode {} ::yencode::Encode
00157 interp alias {} ::yencode::decode {} ::yencode::Decode
00158 }
00159
00160
00161
00162
00163
00164 ret ::yencode::Pop (type varname , optional nth =0) {
00165 upvar $varname args
00166 set r [lindex $args $nth]
00167 set args [lreplace $args $nth $nth]
00168 return $r
00169 }
00170
00171
00172
00173 ret ::yencode::yencode (type args) {
00174 array set opts {mode 0644 filename {} name {} line 128 crc32 1}
00175 while {[string match -* [lindex $args 0]]} {
00176 switch -glob -- [lindex $args 0] {
00177 -f* { set opts(filename) [Pop args 1] }
00178 -m* { set opts(mode) [Pop args 1] }
00179 -n* { set opts(name) [Pop args 1] }
00180 -l* { set opts(line) [Pop args 1] }
00181 -c* { set opts(crc32) [Pop args 1] }
00182 -- { Pop args ; break }
00183 default {
00184 set options [join [lsort [array names opts]] ", -"]
00185 return -code error "bad option [lindex $args 0]:\
00186 must be -$options"
00187 }
00188 }
00189 Pop args
00190 }
00191
00192 if {$opts(name) == {}} {
00193 set opts(name) $opts(filename)
00194 }
00195 if {$opts(name) == {}} {
00196 set opts(name) "data.dat"
00197 }
00198 if {! [string is boolean $opts(crc32)]} {
00199 return -code error "bad option -crc32: argument must be true or false"
00200 }
00201
00202 if {$opts(filename) != {}} {
00203 set f [open $opts(filename) r]
00204 fconfigure $f -translation binary
00205 set data [read $f]
00206 close $f
00207 } else {
00208 if {[llength $args] != 1} {
00209 return -code error "wrong \# args: should be\
00210 \"yencode ?options? -file name | data\""
00211 }
00212 set data [lindex $args 0]
00213 }
00214
00215 set opts(size) [string length $data]
00216
00217 set r {}
00218 append r [format "=ybegin line=%d size=%d name=%s" \
00219 $opts(line) $opts(size) $opts(name)] "\n"
00220
00221 set ndx 0
00222 while {$ndx < $opts(size)} {
00223 set pln [string range $data $ndx [expr {$ndx + $opts(line) - 1}]]
00224 set enc [encode $pln]
00225 incr ndx [string length $pln]
00226 append r $enc "\r\n"
00227 }
00228
00229 append r [format "=yend size=%d" $ndx]
00230 if {$opts(crc32)} {
00231 append r " crc32=" [crc::crc32 -format %x $data]
00232 }
00233 return $r
00234 }
00235
00236
00237
00238
00239
00240
00241
00242
00243 ret ::yencode::ydecode (type args) {
00244 array set opts {mode 0644 filename {} name default.bin}
00245 while {[string match -* [lindex $args 0]]} {
00246 switch -glob -- [lindex $args 0] {
00247 -f* { set opts(filename) [Pop args 1] }
00248 -- { Pop args ; break; }
00249 default {
00250 set options [join [lsort [array names opts]] ", -"]
00251 return -code error "bad option [lindex $args 0]:\
00252 must be -$opts"
00253 }
00254 }
00255 Pop args
00256 }
00257
00258 if {$opts(filename) != {}} {
00259 set f [open $opts(filename) r]
00260 set data [read $f]
00261 close $f
00262 } else {
00263 if {[llength $args] != 1} {
00264 return -code error "wrong \# args: should be\
00265 \"ydecode ?options? -file name | data\""
00266 }
00267 set data [lindex $args 0]
00268 }
00269
00270 set state false
00271 set result {}
00272
00273 foreach {line} [split $data "\n"] {
00274 set line [string trimright $line "\r\n"]
00275 switch -exact -- $state {
00276 false {
00277 if {[string match "=ybegin*" $line]} {
00278 regexp {line=(\d+)} $line -> opts(line)
00279 regexp {size=(\d+)} $line -> opts(size)
00280 regexp {name=(\d+)} $line -> opts(name)
00281
00282 if {$opts(name) == {}} {
00283 set opts(name) default.bin
00284 }
00285
00286 set state true
00287 set r {}
00288 }
00289 }
00290
00291 true {
00292 if {[string match "=yend*" $line]} {
00293 set state false
00294 lappend result [list $opts(name) $opts(size) $r]
00295 } else {
00296 append r [decode $line]
00297 }
00298 }
00299 }
00300 }
00301
00302 return $result
00303 }
00304
00305
00306
00307 package provide yencode $::yencode::version
00308
00309
00310
00311
00312
00313
00314
00315
00316