]> git.donarmstrong.com Git - roundcube.git/blob - program/lib/utf7.inc
Merge commit 'debian/0.1_beta2.2_dfsg-1' into debian
[roundcube.git] / program / lib / utf7.inc
1 <?php
2 //
3 //
4 //      utf7.inc - Routines to encode bytes to UTF7 and decode UTF7 strings
5 //
6 //      Copyright (C)  1999, 2002  Ziberex and Torben Rybner
7 //
8 //
9 //      Version 1.01    2002-06-08      19:00
10 //
11 //      - Adapted for use in IlohaMail (modified UTF-7 decoding)
12 //      - Converted from C to PHP4
13 //
14 //
15 //      Version 1.00    1999-09-03      19:00
16 //
17 //      - Encodes bytes to UTF7 strings
18 //          *OutString = '\0';
19 //          StartBase64Encode();
20 //          for (CP = InString;  *CP;  CP++)
21 //            strcat(OutString, Base64Encode(*CP));
22 //          strcat(OutString, StopBase64Encode());
23 //      - Decodes Base64 strings to bytes
24 //          StartBase64Decode();
25 //          for (CP1 = InString, CP2 = OutString;  *CP1 && (*CP1 != '=');  CP1++)
26 //            CP2 += Base64Decode(*CP1, CP2);
27 //          StopBase64Decode();
28 //
29
30 $BASE64LENGTH              =  60;
31
32 $BASE64DECODE_NO_DATA      = -1;
33 $BASE64DECODE_EMPTY_DATA   = -2;
34 $BASE64DECODE_INVALID_DATA = -3;
35
36
37 //
38 //
39 //      Used for conversion to UTF7
40 //
41 $_ToUTF7 = array
42 (
43  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
44  'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
45  'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
46  'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', ','
47 );
48
49 //
50 //
51 //      Used for conversion from UTF7
52 //      (0x80 => Illegal, 0x40 => CR/LF)
53 //
54 $_FromUTF7 = array
55 (
56   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,       // 00 - 07 - Ctrl -
57   0x80, 0x80, 0x40, 0x80, 0x80, 0x40, 0x80, 0x80,       // 08 - 0F - Ctrl -
58   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,       // 10 - 17 - Ctrl -
59   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,       // 18 - 1F - Ctrl -
60   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,       // 20 - 27  !"#$%&'
61   0x80, 0x80, 0x80, 0x3E, 0x3F, 0x80, 0x80, 0x3F,       // 28 - 2F ()*+,-./
62   0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,       // 30 - 37 01234567
63   0x3C, 0x3D, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80,       // 38 - 3F 89:;<=>?
64   0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,       // 40 - 47 @ABCDEFG
65   0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,       // 48 - 4F HIJKLMNO
66   0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,       // 50 - 57 PQRSTUVW
67   0x17, 0x18, 0x19, 0x80, 0x80, 0x80, 0x80, 0x80,       // 58 - 5F XYZ[\]^_
68   0x80, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,       // 60 - 67 `abcdefg
69   0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,       // 68 - 6F hijklmno
70   0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,       // 70 - 77 pqrstuvw
71   0x31, 0x32, 0x33, 0x80, 0x80, 0x80, 0x80, 0x80,       // 78 - 7F xyz{|}~
72 );
73
74
75 //
76 //
77 //      UTF7EncodeInit:
78 //
79 //      Start the encoding of bytes
80 //
81 function UTF7EncodeInit(&$Context)
82 {
83   $Context[ "Data" ]  = "";
84   $Context[ "Count" ] = 0;
85   $Context[ "Pos" ]   = 0;
86   $Context[ "State" ] = 0;
87 } // UTF7EncodeInit
88
89
90 //
91 //
92 //      UTF7EncodeByte:
93 //
94 //      Encodes one byte to UTF7
95 //
96 function UTF7EncodeByte(&$Context, $Byte)
97 {
98   global $_ToUTF7;
99
100   $Byte = ord($Byte);
101   switch ($Context[ "State" ])
102   {
103     case 0:
104       // Convert into a byte
105       $Context[ "Data" ] = $_ToUTF7[ $Byte >> 2 ];
106       $Context[ "Pos" ]++;
107       // Save residue for next converted byte
108       $Context[ "Residue" ] = ($Byte & 0x03) << 4;
109       // This is the first byte in this line
110       $Context[ "Count" ] = 1;
111       // Next state is 1
112       $Context[ "State" ] = 1;
113       break;
114  
115     case 1:
116       // Convert into a byte
117       $Context[ "Data" ] .= $_ToUTF7[ $Context[ "Residue" ] | ($Byte >> 4) ];
118       $Context[ "Pos" ]++;
119       // Save residue for next converted byte
120       $Context[ "Residue" ] = ($Byte & 0x0F) << 2;
121       // Bumb byte counter
122       $Context[ "Count" ]++;
123       // Next state is 2
124       $Context[ "State" ] = 2;
125       break;
126  
127     case 2:
128       // Convert into a byte
129       $Context[ "Data" ] .= $_ToUTF7[ $Context[ "Residue" ] | ($Byte >> 6) ];
130       $Context[ "Pos" ]++;
131       // Residue fits precisely into the next byte
132       $Context[ "Data" ] .= $_ToUTF7[ $Byte & 0x3F ];
133       $Context[ "Pos" ]++;
134       // Bumb byte counter
135       $Context[ "Count" ]++;
136       // Next state is 3
137       $Context[ "State" ] = 3;
138       break;
139
140     case 3:
141       // Convert into a byte
142       $Context[ "Data" ] .= $_ToUTF7[ $Byte >> 2 ];
143       $Context[ "Pos" ]++;
144       // Save residue for next converted byte
145       $Context[ "Residue" ] = ($Byte & 0x03) << 4;
146       // Bumb byte counter
147       $Context[ "Count" ]++;
148       // Next state is 1
149       $Context[ "State" ] = 1;
150       break;
151  
152     default:
153       // printf("Internal error in UTF7Encode: State is %d\n", $Context[ "State" ]);
154       // exit(1);
155       break;
156   }
157 } // UTF7EncodeByte
158
159
160 //
161 //
162 //      UTF7EncodeFinal:
163 //
164 //      Terminates the encoding of bytes
165 //
166 function UTF7EncodeFinal(&$Context)
167 {
168   if ($Context[ "State" ] == 0)
169     return "";
170   if ($Context[ "State" ] != 3)
171     UTF7EncodeByte($Context, "\0");
172   return $Context[ "Data" ];
173 } // UTF7EncodeFinal
174
175
176 //
177 //
178 //      UTF7EncodeString
179 //
180 //      Encodes a string to modified UTF-7 format
181 //
182 function UTF7EncodeString($String)
183 {
184   // Not during encoding, yet
185   $Encoding = false;
186   // Go through the string
187   for ($I = 0;  $I < strlen($String);  $I++)
188   {
189     $Ch = substr($String, $I, 1);
190     if (ord($Ch) > 0x7F)
191     {
192       if (! $Encoding)
193       {
194         $RetVal .= "&";
195         $Encoding = true;
196         // Initialise UTF7 context
197         UTF7EncodeInit($Context);
198       }
199       UTF7EncodeByte($Context, "\0");
200       UTF7EncodeByte($Context, $Ch);
201     }
202     elseif ($Ch == "&")
203     {
204       if (! $Encoding)
205       {
206         $RetVal .= "&";
207         $Encoding = true;
208         // Initialise UTF7 context
209         UTF7EncodeInit($Context);
210       }
211       else
212       {
213         UTF7EncodeByte($Context, "\0");
214         UTF7EncodeByte($Context, $Ch);
215       }
216     }
217     else
218     {
219       if ($Encoding)
220       {
221         $RetVal .= UTF7EncodeFinal($Context) . "-$Ch";
222         $Encoding = false;
223       }
224       else
225         $RetVal .= $Ch;
226     }
227   }
228   if ($Encoding)
229     $RetVal .= UTF7EncodeFinal($Context) . "-";
230   return $RetVal;
231 } // UTF7EncodeString
232
233
234 //
235 //
236 //      UTF7DecodeInit:
237 //
238 //      Start the decoding of bytes
239 //
240 function UTF7DecodeInit(&$Context)
241 {
242   $Context[ "Data" ]  = "";
243   $Context[ "State" ] = 0;
244   $Context[ "Pos" ]   = 0;
245 } // UTF7DecodeInit
246
247
248 //
249 //
250 //      UTF7DecodeByte:
251 //
252 //      Decodes one character from UTF7
253 //
254 function UTF7DecodeByte(&$Context, $Byte)
255 {
256   global $BASE64DECODE_INVALID_DATA;
257   global $_FromUTF7;
258
259   // Restore bits
260   $Byte = $_FromUTF7[ ord($Byte) ];
261   // Ignore carriage returns and linefeeds
262   if ($Byte == 0x40)
263     return "";
264   // Invalid byte - Tell caller!
265   if ($Byte == 0x80)
266     $Context[ "Count" ] = $BASE64DECODE_INVALID_DATA;
267   switch ($Context[ "State" ])
268   {
269     case 0:
270       // Save residue
271       $Context[ "Residue" ] = $Byte;
272       // Initialise count
273       $Context[ "Count" ] = 0;
274       // Next state
275       $Context[ "State" ] = 1;
276       break;
277
278     case 1:
279       // Store byte
280       $Context[ "Data" ] .= chr(($Context[ "Residue" ] << 2) | ($Byte >> 4));
281       $Context[ "Pos" ]++;
282       // Update count
283       $Context[ "Count" ]++;
284       // Save residue
285       $Context[ "Residue" ] = $Byte;
286       // Next state
287       $Context[ "State" ] = 2;
288       break;
289
290     case 2:
291       // Store byte
292       $Context[ "Data" ] .= chr(($Context[ "Residue" ] << 4) | ($Byte >> 2));
293       $Context[ "Pos" ]++;
294       // Update count
295       $Context[ "Count" ]++;
296       // Save residue
297       $Context[ "Residue" ] = $Byte;
298       // Next state
299       $Context[ "State" ] = 3;
300       break;
301
302     case 3:
303       // Store byte
304       $Context[ "Data" ] .= chr(($Context[ "Residue" ] << 6) | $Byte);
305       $Context[ "Pos" ]++;
306       // Update count
307       $Context[ "Count" ]++;
308       // Next state
309       $Context[ "State" ] = 4;
310       break;
311
312     case 4:
313       // Save residue
314       $Context[ "Residue" ] = $Byte;
315       // Next state
316       $Context[ "State" ] = 1;
317       break;
318   }
319 } // UTF7DecodeByte
320
321
322 //
323 //
324 //      UTF7DecodeFinal:
325 //
326 //      Decodes one character from UTF7
327 //
328 function UTF7DecodeFinal(&$Context)
329 {
330   // Buffer not empty - Return remainder!
331   if ($Context[ "Count" ])
332   {
333     $Context[ "Pos" ] = 0;
334     $Context[ "State" ] = 0;
335     return $Context[ "Data" ];
336   }
337   return "";
338 } // UTF7DecodeFinal
339
340
341 //
342 //
343 //      UTF7DecodeString
344 //
345 //      Converts a string encoded in modified UTF-7 encoding
346 //      to ISO 8859-1.
347 //      OBS: Works only for valid ISO 8859-1 characters in the
348 //      encoded data
349 //
350 function UTF7DecodeString($String)
351 {
352   $Decoding = false;
353   for ($I = 0;  $I < strlen($String);  $I++)
354   {
355     $Ch = substr($String, $I, 1);
356     if ($Decoding)
357     {
358       if ($Ch == "-")
359       {
360         $RetVal .= UTF7DecodeFinal($Context);
361         $Decoding = false;
362       }
363       else
364         UTF7DecodeByte($Context, $Ch);
365     }
366     elseif ($Ch == "&")
367     {
368       if (($I < strlen($String) - 1) && (substr($String, $I + 1, 1) == "-"))
369       {
370         $RetVal .= $Ch;
371         $I++;
372       }
373       else
374       {
375         UTF7DecodeInit($Context);
376         $Decoding = true;
377       }
378     }
379     else
380       $RetVal .= $Ch;
381   }
382   return str_replace("\0", "", $RetVal);
383 } // UTF7DecodeString
384 ?>