 
 SYMBOL: column
 
-: write1-lines ( ch -- )
-    write1
-    column get [
-        1 + [ 76 = [ B{ CHAR: \r CHAR: \n } write ] when ]
-        [ 76 mod column set ] bi
-    ] when* ;
+: write1-lines ( column/f ch stream -- column' )
+    [ stream-write1 ] keep swap [
+        1 + swap
+        '[ 76 = [ B{ CHAR: \r CHAR: \n } _ stream-write ] when ]
+        [ 76 mod ] bi
+    ] [ drop f ] if* ;
 
 : write-lines ( str -- )
-    [ write1-lines ] each ;
+    column output-stream get '[
+        swap [ _ write1-lines ] each
+    ] change ;
 
 : encode3 ( seq -- )
-    be> 4 iota <reversed> [
-        -6 * shift 0x3f bitand ch>base64 write1-lines
-    ] with each ; inline
+    column output-stream get '[
+        swap be> { 3 2 1 0 } [
+            -6 * shift 0x3f bitand ch>base64 _ write1-lines
+        ] with each
+    ] change ; inline
 
 : encode-pad ( seq n -- )
     [ 3 0 pad-tail binary [ encode3 ] with-byte-writer ]

: decode4 ( seq -- )
    [ 0 [ base64>ch swap 6 shift bitor ] reduce 3 >be ]
    [ [ CHAR: = = ] count ] bi head-slice*
    [ write1 ] each ; inline

PRIVATE>

: encode-base64 ( -- )
    3 read dup length {
        { 0 [ drop ] }
        { 3 [ encode3 encode-base64 ] }
        [ encode-pad encode-base64 ]
    } case ;

: encode-base64-lines ( -- )
    0 column [ encode-base64 ] with-variable ;

: decode-base64 ( -- )
    "\n\r" 4 read-ignoring dup length {
        { 0 [ drop ] }
        { 4 [ decode4 decode-base64 ] }
        [ malformed-base64 ]
    } case ;

: >base64 ( seq -- base64 )
    binary [ binary [ encode-base64 ] with-byte-reader ] with-byte-writer ;


<PRIVATE

: read1-ignoring ( ignoring stream -- ch )
    dup stream-read1 pick dupd member?
    [ drop read1-ignoring ] [ 2nip ] if ;

: read-ignoring ( n ignoring stream -- str )
    '[ _ _ read1-ignoring ] replicate
    [ { f 0 } member-eq? not ] "" filter-as
    [ f ] when-empty ;

: ch>base64 ( ch -- ch )
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
