1 /*****************************************************/
2 /* This java file is a part of the */
4 /* - Plouf's Java IRC Client - */
6 /* Copyright (C) 2002 - 2004 Philippe Detournay */
8 /* All contacts : theplouf@yahoo.com */
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 */
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. */
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 */
28 /*****************************************************/
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;
41 * MyPushbackStream, because of a bug in JDK1.1.
43 class MyPushbackStream extends InputStream {
44 private InputStream _is;
46 private boolean _closed;
49 * Create a new MyPushbackStream
52 * source input stream.
54 public MyPushbackStream(InputStream is) {
61 public void close() throws IOException {
68 public int read() throws IOException {
78 public int read(byte[] b) throws IOException {
79 return read(b, 0, b.length);
83 public int read(byte[] b, int offset, int length) throws IOException {
87 b[offset] = (byte) _back;
91 return _is.read(b, offset, length);
95 public int available() throws IOException {
97 return 1 + _is.available();
98 return _is.available();
102 * Unread the last read byte.
105 * last read byte value.
107 public void unread(byte b) {
115 * Coding handler for unicode to ascii transfert via socket streams.
117 public class CodingHandler extends IRCObject {
118 private MyPushbackStream _is;
119 private OutputStream _os;
120 private BufferedReader _reader;
121 private BufferedWriter _writer;
127 public static final int CODING_ASCII = 0;
129 * PJIRC proprietary coding format.
131 public static final int CODING_PUAP = 1;
135 public static final int CODING_UTF_8 = 2;
137 * Local charset coding.
139 public static final int CODING_LOCAL_CHARSET = 3;
142 * Create a new Coding handler, using the given input and output stream.
145 * IRCConfiguration objet.
147 * inputstream for reading.
149 * outputstream for writing.
151 public CodingHandler(IRCConfiguration config, InputStream is, OutputStream os) {
153 _coding = config.getI("coding");
154 if (_coding != CODING_LOCAL_CHARSET) {
155 _is = new MyPushbackStream(is);
162 _reader = new BufferedReader(new InputStreamReader(is));
163 _writer = new BufferedWriter(new OutputStreamWriter(os));
168 * Close the handler, and associated streams.
170 * @throws IOException
172 public void close() throws IOException {
188 * Read a single line from the input stream.
190 * @return the read line.
191 * @throws IOException
193 public String read() throws IOException {
194 if (_coding != CODING_LOCAL_CHARSET) {
195 String ans = readUTF();
196 return asciiToWide(ans);
198 return _reader.readLine();
202 * Write a single line to the output stream.
206 * @throws IOException
208 public void write(String s) throws IOException {
209 if (_coding == CODING_ASCII)
211 else if (_coding == CODING_PUAP)
213 else if (_coding == CODING_UTF_8)
215 else if (_coding == CODING_LOCAL_CHARSET)
226 private void writeCHARSET(String s) throws IOException {
227 _writer.write(s, 0, s.length());
231 private void writeASCII(String s) throws IOException {
232 for (int i = 0; i < s.length(); i++)
233 _os.write((byte) s.charAt(i));
238 private void writePUAP(String s) throws IOException {
239 writeASCII(wideToAscii(s));
242 private String readUTF() throws IOException {
244 String nonUTFans = "";
249 boolean terminated = false;
250 while (!terminated) {
252 if (((c == 10) || (c == 13)) && (nonUTFans.length() == 0))
255 if (nonUTFans.length() == 0)
256 throw new IOException("EOF reached");
264 if ((c == 10) || (c == 13)) {
267 if (_is.available() >= 1)
269 if ((c != 10) && (c != 13))
270 _is.unread((byte) c);
276 nonUTFans += (char) c;
287 } else if (c < 192) {
291 ch = (char) ((ch << 6) | ((c - 128) & 63));
298 } else if (c < 224) {
303 ch = (char) (c - 192);
310 ch = (char) (c - 224);
317 private void writeUTF(String str) throws IOException {
318 for (int i = 0; i < str.length(); i++) {
319 char ch = str.charAt(i);
321 _os.write((byte) ch);
322 else if (ch < 0x07FF) {
323 _os.write((byte) (192 + (ch >> 6)));
324 _os.write((byte) (128 + (ch & 63)));
326 _os.write((byte) (224 + (ch >> 12)));
327 _os.write((byte) (128 + ((ch >> 6) & 63)));
328 _os.write((byte) (128 + (ch & 63)));
336 * Convert an ascii string to a wide string, as defined in the PJIRC unicode
337 * transfert protocol.
341 * @return wide string.
343 private static String asciiToWide(String str) {
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);
350 int code = Integer.parseInt(hex, 16);
353 res += str.charAt(i);
357 } catch (Exception ex) {
363 * Convert a wide string to an ascii string, as defined in the PJIRC unicode
364 * transfert protocol.
368 * @return ascii string.
370 private static String wideToAscii(String str) {
372 for (int i = 0; i < str.length(); i++) {
373 int c = str.charAt(i);
376 String v = Integer.toHexString(c);
377 while (v.length() < 4)