alecpl
2008-04-29 6ee5ed253b92593ac5784300ac425f34f7fd1728
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);
T 42   $p = $err = '';
4e17e6 43
c8c1a3 44   for ($i=0; $u7len > 0; $i++, $u7len--)
4e17e6 45   {
c8c1a3 46     $u7 = $str{$i};
T 47     if ($u7 == '&')
4e17e6 48     {
c8c1a3 49       $i++;
T 50       $u7len--;
51       $u7 = $str{$i};
52       
53       if ($u7len && $u7 == '-')
4e17e6 54       {
c8c1a3 55         $p .= '&';
T 56         continue;
4e17e6 57       }
c8c1a3 58
T 59       $ch = 0;
60       $k = 10;
61       for (; $u7len > 0; $i++, $u7len--)
62       {
63         $u7 = $str{$i};
64
65         if ((ord($u7) & 0x80) || ($b = $Index_64[ord($u7)]) == -1)
66           break;
67
68         if ($k > 0)
69         {
70           $ch |= $b << $k;
71           $k -= 6;
72         }
73         else
74         {
75           $ch |= $b >> (-$k);
76           if ($ch < 0x80)
77           {
78             /* Printable US-ASCII */
79             if (0x20 <= $ch && $ch < 0x7f)
80               return $err;
81            $p .= chr($ch);
82           }
83           else if ($ch < 0x800)
84           {
85             $p .= chr(0xc0 | ($ch >> 6));
86             $p .= chr(0x80 | ($ch & 0x3f));
87           }
88           else
89           {
90             $p .= chr(0xe0 | ($ch >> 12));
91             $p .= chr(0x80 | (($ch >> 6) & 0x3f));
92             $p .= chr(0x80 | ($ch & 0x3f));
93           }
94
95           $ch = ($b << (16 + $k)) & 0xffff;
96           $k += 10;
97         }
98       }
99
100       /* Non-zero or too many extra bits */
101       if ($ch || $k < 6)
102         return $err;
103         
104       /* BASE64 not properly terminated */
105       if (!$u7len || $u7 != '-')
106         return $err;
107         
108       /* Adjacent BASE64 sections */
109       if ($u7len > 2 && $str{$i+1} == '&' && $str{$i+2} != '-')
110         return $err;
4e17e6 111     }
c8c1a3 112     /* Not printable US-ASCII */
T 113     else if (ord($u7) < 0x20 || ord($u7) >= 0x7f)
114       return $err;
115     else
116       $p .= $u7;
117   }
118
119   return $p;
120 }
121
122
123 /**
124  * Convert the data ($str) from UTF-8 to RFC 2060's UTF-7.
125  * Unicode characters above U+FFFF are replaced by U+FFFE.
126  * If input data is invalid, return an empty string.
127  */
128 function utf8_to_utf7($str)
129 {
130   $B64Chars = array(
131     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
132     'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
133     'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
134     't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
135     '8', '9', '+', ','
136   );
137
138   $u8len = strlen($str);
139   $base64 = $i = 0;
140   $p = $err = '';
141
142   while ($u8len)
143   {
144     $u8 = $str{$i};
145     $c = ord($u8);
146     
147     if ($c < 0x80)
4e17e6 148     {
c8c1a3 149       $ch = $c;
T 150       $n = 0;
151     }
152     else if ($c < 0xc2)
153       return $err;
154     else if ($c < 0xe0)
155     {
156       $ch = $c & 0x1f;
157       $n = 1;
158     }
159     else if ($c < 0xf0)
160     {
161       $ch = $c & 0x0f;
162       $n = 2;
163     }
164     else if ($c < 0xf8)
165     {
166       $ch = $c & 0x07;
167       $n = 3;
168     }
169     else if ($c < 0xfc)
170     {
171       $ch = $c & 0x03;
172       $n = 4;
173     }
174     else if ($c < 0xfe)
175     {
176       $ch = $c & 0x01;
177       $n = 5;
178     }
179     else
180       return $err;
181
182     $i++;
183     $u8len--;
184
185     if ($n > $u8len)
186       return $err;
187
188     for ($j=0; $j < $n; $j++)
189     {
190       $o = ord($str{$i+$j});
191       if (($o & 0xc0) != 0x80)
192         return $err;
193       $ch = ($ch << 6) | ($o & 0x3f);
194     }
195     
196     if ($n > 1 && !($ch >> ($n * 5 + 1)))
197       return $err;
198     
199     $i += $n;
200     $u8len -= $n;
201
202     if ($ch < 0x20 || $ch >= 0x7f)
203     {
204       if (!$base64)
4e17e6 205       {
c8c1a3 206         $p .= '&';
T 207         $base64 = 1;
208         $b = 0;
209         $k = 10;
4e17e6 210       }
c8c1a3 211       if ($ch & ~0xffff)
T 212         $ch = 0xfffe;
213       
214       $p .= $B64Chars[($b | $ch >> $k)];
215       $k -= 6;
216       for (; $k >= 0; $k -= 6)
217         $p .= $B64Chars[(($ch >> $k) & 0x3f)];
218
219       $b = ($ch << (-$k)) & 0x3f;
220       $k += 16;
4e17e6 221     }
T 222     else
223     {
c8c1a3 224       if ($base64)
4e17e6 225       {
c8c1a3 226         if ($k > 10)
T 227           $p .= $B64Chars[$b];
228         $p .= '-';
229         $base64 = 0;
4e17e6 230       }
c8c1a3 231       
T 232       $p .= chr($ch);
233       if (chr($ch) == '&')
234         $p .= '-';
4e17e6 235     }
T 236   }
237
c8c1a3 238   if ($base64)
4e17e6 239   {
c8c1a3 240     if ($k > 10)
T 241       $p .= $B64Chars[$b];
242     $p .= '-';
4e17e6 243   }
T 244
c8c1a3 245   return $p;
T 246 }
4e17e6 247
T 248 ?>