svncommit
2008-09-18 d0b973cf6aed4a7cb705f706624d25b31d19ed52
commit | author | age
4e17e6 1 <?php
T 2
c8c1a3 3 /*
T 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  */ 
4e17e6 18
T 19
c8c1a3 20 /**
T 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)
4e17e6 29 {
c8c1a3 30   $Index_64 = array(
T 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   );
4e17e6 40
c8c1a3 41   $u7len = strlen($str);
0a5e6a 42   $str = strval($str);
c8c1a3 43   $p = $err = '';
4e17e6 44
c8c1a3 45   for ($i=0; $u7len > 0; $i++, $u7len--)
4e17e6 46   {
0a5e6a 47     $u7 = $str[$i];
c8c1a3 48     if ($u7 == '&')
4e17e6 49     {
c8c1a3 50       $i++;
T 51       $u7len--;
0a5e6a 52       $u7 = $str[$i];
c8c1a3 53       
T 54       if ($u7len && $u7 == '-')
4e17e6 55       {
c8c1a3 56         $p .= '&';
T 57         continue;
4e17e6 58       }
c8c1a3 59
T 60       $ch = 0;
61       $k = 10;
62       for (; $u7len > 0; $i++, $u7len--)
63       {
0a5e6a 64         $u7 = $str[$i];
c8c1a3 65
T 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 */
0a5e6a 110       if ($u7len > 2 && $str[$i+1] == '&' && $str[$i+2] != '-')
c8c1a3 111         return $err;
4e17e6 112     }
c8c1a3 113     /* Not printable US-ASCII */
T 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   {
0a5e6a 145     $u8 = $str[$i];
c8c1a3 146     $c = ord($u8);
T 147     
148     if ($c < 0x80)
4e17e6 149     {
c8c1a3 150       $ch = $c;
T 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     {
0a5e6a 191       $o = ord($str[$i+$j]);
c8c1a3 192       if (($o & 0xc0) != 0x80)
T 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)
4e17e6 206       {
c8c1a3 207         $p .= '&';
T 208         $base64 = 1;
209         $b = 0;
210         $k = 10;
4e17e6 211       }
c8c1a3 212       if ($ch & ~0xffff)
T 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;
4e17e6 222     }
T 223     else
224     {
c8c1a3 225       if ($base64)
4e17e6 226       {
c8c1a3 227         if ($k > 10)
T 228           $p .= $B64Chars[$b];
229         $p .= '-';
230         $base64 = 0;
4e17e6 231       }
c8c1a3 232       
T 233       $p .= chr($ch);
234       if (chr($ch) == '&')
235         $p .= '-';
4e17e6 236     }
T 237   }
238
c8c1a3 239   if ($base64)
4e17e6 240   {
c8c1a3 241     if ($k > 10)
T 242       $p .= $B64Chars[$b];
243     $p .= '-';
4e17e6 244   }
T 245
c8c1a3 246   return $p;
T 247 }
4e17e6 248
T 249 ?>