]> gitweb.factorcode.org Git - factor.git/blob - basis/io/encodings/utf7/utf7.factor
40d4fe5490834ca7fe3e726d15652db153c0b427
[factor.git] / basis / io / encodings / utf7 / utf7.factor
1 ! Copyright (C) 2013-2014 Björn Lindqvist
2 ! See http://factorcode.org/license.txt for BSD license
3 USING: accessors ascii base64 fry grouping.extras io
4 io.encodings io.encodings.string io.encodings.utf16 kernel math
5 math.functions sequences splitting strings ;
6 IN: io.encodings.utf7
7
8 TUPLE: utf7codec dialect buffer ;
9
10 ! These words encodes the difference between standard utf7 and the
11 ! dialect used by IMAP which wants slashes replaced with commas when
12 ! encoding and uses '&' instead of '+' as the escaping character.
13 : utf7 ( -- utf7codec )
14     {
15         { { } { } }
16         { { CHAR: + } { CHAR: - } }
17     } V{ } utf7codec boa ;
18
19 : utf7imap4 ( -- utf7codec )
20     {
21         { { CHAR: / } { CHAR: , } }
22         { { CHAR: & } { CHAR: - } }
23     } V{ } utf7codec boa ;
24
25 : >raw-base64 ( bytes -- bytes' )
26     >string utf16be encode >base64 [ CHAR: = = ] trim-tail ;
27
28 : raw-base64> ( str -- str' )
29     dup length 4 / ceiling 4 * CHAR: = pad-tail base64> utf16be decode ;
30
31 : encode-chunk ( repl-pair surround-pair chunk ascii? -- bytes )
32     [ swap [ first ] [ concat ] bi replace nip ]
33     [ >raw-base64 -rot [ first2 replace ] [ first2 surround ] bi* ] if ;
34
35 : encode-utf7-string ( str codec -- bytes )
36     [ [ printable? ] group-by ] dip
37     dialect>> first2 '[ _ _ rot first2 swap encode-chunk ] map
38     B{ } concat-as ;
39
40 M: utf7codec encode-string ( str stream codec -- )
41     swapd encode-utf7-string swap stream-write ;
42
43 DEFER: emit-char
44
45 : decode-chunk ( dialect -- ch buffer )
46     dup first2 swap [ second read-until drop ] [ first2 swap replace ] bi*
47     [ second first first { } ] [ raw-base64> emit-char ] if-empty ;
48
49 : fill-buffer ( dialect -- ch buffer )
50     dup second first first read1 dup swapd = [
51         drop decode-chunk
52     ] [ nip { } ] if ;
53
54 : emit-char ( dialect buffer -- ch buffer' )
55     [ fill-buffer ] [ nip unclip swap ] if-empty ;
56
57 : replace-all! ( src dst -- )
58     [ delete-all ] keep push-all ;
59
60 M: utf7codec decode-char ( stream codec -- char/f )
61     swap [
62         [ dialect>> ] [ buffer>> ] bi [ emit-char ] keep replace-all!
63     ] with-input-stream ;