]> git.somenet.org - irc/pjirc-ng.git/blob - src/main/java/irc/CodingHandler.java
Pjirc 2.2.1 as available on the net, reformatted and made it compile.
[irc/pjirc-ng.git] / src / main / java / irc / CodingHandler.java
1 /*****************************************************/
2 /*          This java file is a part of the          */
3 /*                                                   */
4 /*           -  Plouf's Java IRC Client  -           */
5 /*                                                   */
6 /*   Copyright (C)  2002 - 2004 Philippe Detournay   */
7 /*                                                   */
8 /*         All contacts : theplouf@yahoo.com         */
9 /*                                                   */
10 /*  PJIRC is free software; you can redistribute     */
11 /*  it and/or modify it under the terms of the GNU   */
12 /*  General Public License as published by the       */
13 /*  Free Software Foundation; version 2 or later of  */
14 /*  the License.                                     */
15 /*                                                   */
16 /*  PJIRC is distributed in the hope that it will    */
17 /*  be useful, but WITHOUT ANY WARRANTY; without     */
18 /*  even the implied warranty of MERCHANTABILITY or  */
19 /*  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   */
20 /*  General Public License for more details.         */
21 /*                                                   */
22 /*  You should have received a copy of the GNU       */
23 /*  General Public License along with PJIRC; if      */
24 /*  not, write to the Free Software Foundation,      */
25 /*  Inc., 59 Temple Place, Suite 330, Boston,        */
26 /*  MA  02111-1307  USA                              */
27 /*                                                   */
28 /*****************************************************/
29
30 package irc;
31
32 import java.io.BufferedReader;
33 import java.io.BufferedWriter;
34 import java.io.IOException;
35 import java.io.InputStream;
36 import java.io.InputStreamReader;
37 import java.io.OutputStream;
38 import java.io.OutputStreamWriter;
39
40 /**
41  * MyPushbackStream, because of a bug in JDK1.1.
42  */
43 class MyPushbackStream extends InputStream {
44         private InputStream _is;
45         private int _back;
46         private boolean _closed;
47
48         /**
49          * Create a new MyPushbackStream
50          * 
51          * @param is
52          *          source input stream.
53          */
54         public MyPushbackStream(InputStream is) {
55                 _is = is;
56                 _back = -1;
57                 _closed = false;
58         }
59
60         @Override
61         public void close() throws IOException {
62                 _is.close();
63                 _back = -1;
64                 _closed = true;
65         }
66
67         @Override
68         public int read() throws IOException {
69                 if (_back != -1) {
70                         int res = _back;
71                         _back = -1;
72                         return res;
73                 }
74                 return _is.read();
75         }
76
77         @Override
78         public int read(byte[] b) throws IOException {
79                 return read(b, 0, b.length);
80         }
81
82         @Override
83         public int read(byte[] b, int offset, int length) throws IOException {
84                 if (length == 0)
85                         return 0;
86                 if (_back != -1) {
87                         b[offset] = (byte) _back;
88                         _back = -1;
89                         return 1;
90                 }
91                 return _is.read(b, offset, length);
92         }
93
94         @Override
95         public int available() throws IOException {
96                 if (_back != -1)
97                         return 1 + _is.available();
98                 return _is.available();
99         }
100
101         /**
102          * Unread the last read byte.
103          * 
104          * @param b
105          *          last read byte value.
106          */
107         public void unread(byte b) {
108                 if (_closed)
109                         return;
110                 _back = b;
111         }
112 }
113
114 /**
115  * Coding handler for unicode to ascii transfert via socket streams.
116  */
117 public class CodingHandler extends IRCObject {
118         private MyPushbackStream _is;
119         private OutputStream _os;
120         private BufferedReader _reader;
121         private BufferedWriter _writer;
122         private int _coding;
123
124         /**
125          * ASCII coding.
126          */
127         public static final int CODING_ASCII = 0;
128         /**
129          * PJIRC proprietary coding format.
130          */
131         public static final int CODING_PUAP = 1;
132         /**
133          * UTF-8 coding.
134          */
135         public static final int CODING_UTF_8 = 2;
136         /**
137          * Local charset coding.
138          */
139         public static final int CODING_LOCAL_CHARSET = 3;
140
141         /**
142          * Create a new Coding handler, using the given input and output stream.
143          * 
144          * @param config
145          *          IRCConfiguration objet.
146          * @param is
147          *          inputstream for reading.
148          * @param os
149          *          outputstream for writing.
150          */
151         public CodingHandler(IRCConfiguration config, InputStream is, OutputStream os) {
152                 super(config);
153                 _coding = config.getI("coding");
154                 if (_coding != CODING_LOCAL_CHARSET) {
155                         _is = new MyPushbackStream(is);
156                         _os = os;
157                         _reader = null;
158                         _writer = null;
159                 } else {
160                         _is = null;
161                         _os = null;
162                         _reader = new BufferedReader(new InputStreamReader(is));
163                         _writer = new BufferedWriter(new OutputStreamWriter(os));
164                 }
165         }
166
167         /**
168          * Close the handler, and associated streams.
169          * 
170          * @throws IOException
171          */
172         public void close() throws IOException {
173                 if (_is != null)
174                         _is.close();
175                 if (_os != null)
176                         _os.close();
177                 if (_reader != null)
178                         _reader.close();
179                 if (_writer != null)
180                         _writer.close();
181                 _is = null;
182                 _os = null;
183                 _reader = null;
184                 _writer = null;
185         }
186
187         /**
188          * Read a single line from the input stream.
189          * 
190          * @return the read line.
191          * @throws IOException
192          */
193         public String read() throws IOException {
194                 if (_coding != CODING_LOCAL_CHARSET) {
195                         String ans = readUTF();
196                         return asciiToWide(ans);
197                 }
198                 return _reader.readLine();
199         }
200
201         /**
202          * Write a single line to the output stream.
203          * 
204          * @param s
205          *          the line to write.
206          * @throws IOException
207          */
208         public void write(String s) throws IOException {
209                 if (_coding == CODING_ASCII)
210                         writeASCII(s);
211                 else if (_coding == CODING_PUAP)
212                         writePUAP(s);
213                 else if (_coding == CODING_UTF_8)
214                         writeUTF(s);
215                 else if (_coding == CODING_LOCAL_CHARSET)
216                         writeCHARSET(s);
217                 else
218                         writePUAP(s);
219
220                 if (_os != null)
221                         _os.flush();
222                 if (_writer != null)
223                         _writer.flush();
224         }
225
226         private void writeCHARSET(String s) throws IOException {
227                 _writer.write(s, 0, s.length());
228                 _writer.newLine();
229         }
230
231         private void writeASCII(String s) throws IOException {
232                 for (int i = 0; i < s.length(); i++)
233                         _os.write((byte) s.charAt(i));
234                 _os.write(13);
235                 _os.write(10);
236         }
237
238         private void writePUAP(String s) throws IOException {
239                 writeASCII(wideToAscii(s));
240         }
241
242         private String readUTF() throws IOException {
243                 String ans = "";
244                 String nonUTFans = "";
245                 boolean utf = true;
246                 int c;
247                 char ch = 0;
248                 int expect = 0;
249                 boolean terminated = false;
250                 while (!terminated) {
251                         c = _is.read();
252                         if (((c == 10) || (c == 13)) && (nonUTFans.length() == 0))
253                                 continue;
254                         if (c == -1) {
255                                 if (nonUTFans.length() == 0)
256                                         throw new IOException("EOF reached");
257                                 if (expect != 0)
258                                         utf = false;
259                                 if (utf)
260                                         return ans;
261                                 return nonUTFans;
262                         }
263
264                         if ((c == 10) || (c == 13)) {
265                                 if (expect != 0)
266                                         utf = false;
267                                 if (_is.available() >= 1)
268                                         c = _is.read();
269                                 if ((c != 10) && (c != 13))
270                                         _is.unread((byte) c);
271                                 if (utf)
272                                         return ans;
273                                 return nonUTFans;
274                         }
275
276                         nonUTFans += (char) c;
277
278                         if (!utf)
279                                 continue;
280
281                         if (c < 128) {
282                                 if (expect != 0) {
283                                         utf = false;
284                                 } else {
285                                         ans += (char) c;
286                                 }
287                         } else if (c < 192) {
288                                 if (expect == 0) {
289                                         utf = false;
290                                 } else {
291                                         ch = (char) ((ch << 6) | ((c - 128) & 63));
292                                         expect--;
293                                         if (expect == 0) {
294                                                 ans += ch;
295                                                 ch = 0;
296                                         }
297                                 }
298                         } else if (c < 224) {
299                                 if (expect != 0)
300                                         utf = false;
301                                 else {
302                                         expect = 1;
303                                         ch = (char) (c - 192);
304                                 }
305                         } else {
306                                 if (expect != 0)
307                                         utf = false;
308                                 else {
309                                         expect = 2;
310                                         ch = (char) (c - 224);
311                                 }
312                         }
313                 }
314                 return null;
315         }
316
317         private void writeUTF(String str) throws IOException {
318                 for (int i = 0; i < str.length(); i++) {
319                         char ch = str.charAt(i);
320                         if (ch < 0x007F)
321                                 _os.write((byte) ch);
322                         else if (ch < 0x07FF) {
323                                 _os.write((byte) (192 + (ch >> 6)));
324                                 _os.write((byte) (128 + (ch & 63)));
325                         } else {
326                                 _os.write((byte) (224 + (ch >> 12)));
327                                 _os.write((byte) (128 + ((ch >> 6) & 63)));
328                                 _os.write((byte) (128 + (ch & 63)));
329                         }
330                 }
331                 _os.write(10);
332                 _os.write(13);
333         }
334
335         /**
336          * Convert an ascii string to a wide string, as defined in the PJIRC unicode
337          * transfert protocol.
338          * 
339          * @param str
340          *          ascii string.
341          * @return wide string.
342          */
343         private static String asciiToWide(String str) {
344                 try {
345                         String res = "";
346                         for (int i = 0; i < str.length(); i++) {
347                                 if (str.charAt(i) == (char) 30) {
348                                         String hex = str.substring(i + 1, i + 5);
349                                         i += 4;
350                                         int code = Integer.parseInt(hex, 16);
351                                         res += (char) code;
352                                 } else {
353                                         res += str.charAt(i);
354                                 }
355                         }
356                         return res;
357                 } catch (Exception ex) {
358                         return str;
359                 }
360         }
361
362         /**
363          * Convert a wide string to an ascii string, as defined in the PJIRC unicode
364          * transfert protocol.
365          * 
366          * @param str
367          *          wide string.
368          * @return ascii string.
369          */
370         private static String wideToAscii(String str) {
371                 String res = "";
372                 for (int i = 0; i < str.length(); i++) {
373                         int c = str.charAt(i);
374                         if (c > 255) {
375                                 res += (char) 30;
376                                 String v = Integer.toHexString(c);
377                                 while (v.length() < 4)
378                                         v = "0" + v;
379                                 res += v;
380                         } else {
381                                 res += (char) c;
382                         }
383                 }
384                 return res;
385         }
386 }