Version 3 of transform

Updated 2008-12-23 12:00:06 by PT

A channel transform is a mapping applied at the byte-level to a channel. Note that it does not operate on strings; Tcl converts to/from the channel's encoding at a level that is closer to the script level than transforms operate at.

The TLS extension uses transforms internally.

Transforms may be implemented in Tcl (from 8.6 onwards) with the help of chan push and chan pop.

PT: Here is an example of a base64 channel transform using Tcl 8.6 features. You push this transform onto any other sort of channel and it will base64 encode the data as it passes through.

 # A base64 channel transform.
 #
 # usage:  chan push $channel ::tcl::binary::transform_base64
 #
 package require Tcl 8.6

 proc ::tcl::binary::K {a b} {set a}

 proc ::tcl::binary::transform_base64 {cmd handle args} {
    upvar #0 [namespace current]::_transform_r_$handle rstate
    upvar #0 [namespace current]::_transform_w_$handle wstate
    switch -exact -- $cmd {
        initialize {
            set rstate ""; set wstate ""
            return [list initialize finalize read write flush drain]
        }
        finalize {
            unset rstate wstate
            return
        }
        write {
            foreach {buffer} $args break
            append wstate $buffer
            set len [string length $wstate]
            set end [expr {$len - ($len % 3)}]
            set edge [expr {$end - 1}]
            set res [binary encode base64 [string range $wstate 0 $edge]]
            set wstate [string range $wstate $end end]
            return $res
        }
        flush {
            set buffer [K $wstate [set wstate ""]]
            set res [binary encode base64 $buffer]
            return $res
        }
        read {
            foreach {buffer} $args break
            append rstate $buffer
            set len [string length $rstate]
            set end [expr {$len - ($len % 4)}]
            set edge [expr {$end - 1}]
            set res [string range $rstate 0 $edge]
            set rstate [string range $rstate $end end]
            set resx [binary decode base64 $res]
            if {[string length $resx]%3 != 0} { puts stderr "alert: $res" }
            return $resx
        }
        drain {
            set res [K [binary decode base64 $rstate] [set rstate ""]]
            return $res
        }
    }
 }

See also stacked channel.