]> git.donarmstrong.com Git - roundcube.git/blob - program/lib/utf7.inc
Imported Upstream version 0.7
[roundcube.git] / program / lib / utf7.inc
1 <?php
2
3 /*
4  *  Copyright (C) 2000 Edmund Grimley Evans <edmundo@rano.org>
5  * 
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  * 
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  Translated from C to PHP by Thomas Bruederli <roundcube@gmail.com>
17  */ 
18
19
20 /**
21  * Convert the data ($str) from RFC 2060's UTF-7 to UTF-8.
22  * If input data is invalid, return the original input string.
23  * RFC 2060 obviously intends the encoding to be unique (see
24  * point 5 in section 5.1.3), so we reject any non-canonical
25  * form, such as &ACY- (instead of &-) or &AMA-&AMA- (instead
26  * of &AMAAwA-).
27  */
28 function utf7_to_utf8($str)
29 {
30   $Index_64 = array(
31       -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
32       -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
33       -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, 63,-1,-1,-1,
34       52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
35       -1, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
36       15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
37       -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
38       41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
39   );
40
41   $u7len = strlen($str);
42   $str = strval($str);
43   $p = $err = '';
44
45   for ($i=0; $u7len > 0; $i++, $u7len--)
46   {
47     $u7 = $str[$i];
48     if ($u7 == '&')
49     {
50       $i++;
51       $u7len--;
52       $u7 = $str[$i];
53       
54       if ($u7len && $u7 == '-')
55       {
56         $p .= '&';
57         continue;
58       }
59
60       $ch = 0;
61       $k = 10;
62       for (; $u7len > 0; $i++, $u7len--)
63       {
64         $u7 = $str[$i];
65
66         if ((ord($u7) & 0x80) || ($b = $Index_64[ord($u7)]) == -1)
67           break;
68
69         if ($k > 0)
70         {
71           $ch |= $b << $k;
72           $k -= 6;
73         }
74         else
75         {
76           $ch |= $b >> (-$k);
77           if ($ch < 0x80)
78           {
79             /* Printable US-ASCII */
80             if (0x20 <= $ch && $ch < 0x7f)
81               return $err;
82            $p .= chr($ch);
83           }
84           else if ($ch < 0x800)
85           {
86             $p .= chr(0xc0 | ($ch >> 6));
87             $p .= chr(0x80 | ($ch & 0x3f));
88           }
89           else
90           {
91             $p .= chr(0xe0 | ($ch >> 12));
92             $p .= chr(0x80 | (($ch >> 6) & 0x3f));
93             $p .= chr(0x80 | ($ch & 0x3f));
94           }
95
96           $ch = ($b << (16 + $k)) & 0xffff;
97           $k += 10;
98         }
99       }
100
101       /* Non-zero or too many extra bits */
102       if ($ch || $k < 6)
103         return $err;
104         
105       /* BASE64 not properly terminated */
106       if (!$u7len || $u7 != '-')
107         return $err;
108         
109       /* Adjacent BASE64 sections */
110       if ($u7len > 2 && $str[$i+1] == '&' && $str[$i+2] != '-')
111         return $err;
112     }
113     /* Not printable US-ASCII */
114     else if (ord($u7) < 0x20 || ord($u7) >= 0x7f)
115       return $err;
116     else
117       $p .= $u7;
118   }
119
120   return $p;
121 }
122
123
124 /**
125  * Convert the data ($str) from UTF-8 to RFC 2060's UTF-7.
126  * Unicode characters above U+FFFF are replaced by U+FFFE.
127  * If input data is invalid, return an empty string.
128  */
129 function utf8_to_utf7($str)
130 {
131   $B64Chars = array(
132     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
133     'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
134     'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
135     't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
136     '8', '9', '+', ','
137   );
138
139   $u8len = strlen($str);
140   $base64 = $i = 0;
141   $p = $err = '';
142
143   while ($u8len)
144   {
145     $u8 = $str[$i];
146     $c = ord($u8);
147     
148     if ($c < 0x80)
149     {
150       $ch = $c;
151       $n = 0;
152     }
153     else if ($c < 0xc2)
154       return $err;
155     else if ($c < 0xe0)
156     {
157       $ch = $c & 0x1f;
158       $n = 1;
159     }
160     else if ($c < 0xf0)
161     {
162       $ch = $c & 0x0f;
163       $n = 2;
164     }
165     else if ($c < 0xf8)
166     {
167       $ch = $c & 0x07;
168       $n = 3;
169     }
170     else if ($c < 0xfc)
171     {
172       $ch = $c & 0x03;
173       $n = 4;
174     }
175     else if ($c < 0xfe)
176     {
177       $ch = $c & 0x01;
178       $n = 5;
179     }
180     else
181       return $err;
182
183     $i++;
184     $u8len--;
185
186     if ($n > $u8len)
187       return $err;
188
189     for ($j=0; $j < $n; $j++)
190     {
191       $o = ord($str[$i+$j]);
192       if (($o & 0xc0) != 0x80)
193         return $err;
194       $ch = ($ch << 6) | ($o & 0x3f);
195     }
196     
197     if ($n > 1 && !($ch >> ($n * 5 + 1)))
198       return $err;
199     
200     $i += $n;
201     $u8len -= $n;
202
203     if ($ch < 0x20 || $ch >= 0x7f)
204     {
205       if (!$base64)
206       {
207         $p .= '&';
208         $base64 = 1;
209         $b = 0;
210         $k = 10;
211       }
212       if ($ch & ~0xffff)
213         $ch = 0xfffe;
214       
215       $p .= $B64Chars[($b | $ch >> $k)];
216       $k -= 6;
217       for (; $k >= 0; $k -= 6)
218         $p .= $B64Chars[(($ch >> $k) & 0x3f)];
219
220       $b = ($ch << (-$k)) & 0x3f;
221       $k += 16;
222     }
223     else
224     {
225       if ($base64)
226       {
227         if ($k > 10)
228           $p .= $B64Chars[$b];
229         $p .= '-';
230         $base64 = 0;
231       }
232       
233       $p .= chr($ch);
234       if (chr($ch) == '&')
235         $p .= '-';
236     }
237   }
238
239   if ($base64)
240   {
241     if ($k > 10)
242       $p .= $B64Chars[$b];
243     $p .= '-';
244   }
245
246   return $p;
247 }
248
249 ?>