0
|
1 /*
|
|
2 * ConnectBot: simple, powerful, open-source SSH client for Android
|
|
3 * Copyright 2007 Kenny Root, Jeffrey Sharkey
|
|
4 *
|
|
5 * Licensed under the Apache License, Version 2.0 (the "License");
|
|
6 * you may not use this file except in compliance with the License.
|
|
7 * You may obtain a copy of the License at
|
|
8 *
|
|
9 * http://www.apache.org/licenses/LICENSE-2.0
|
|
10 *
|
|
11 * Unless required by applicable law or agreed to in writing, software
|
|
12 * distributed under the License is distributed on an "AS IS" BASIS,
|
|
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14 * See the License for the specific language governing permissions and
|
|
15 * limitations under the License.
|
|
16 */
|
|
17
|
|
18 package com.five_ten_sg.connectbot.service;
|
|
19
|
|
20 import java.io.IOException;
|
|
21 import java.nio.ByteBuffer;
|
|
22 import java.nio.CharBuffer;
|
|
23 import java.nio.charset.Charset;
|
|
24 import java.nio.charset.CharsetDecoder;
|
|
25 import java.nio.charset.CoderResult;
|
|
26 import java.nio.charset.CodingErrorAction;
|
|
27
|
|
28 import org.apache.harmony.niochar.charset.additional.IBM437;
|
|
29
|
|
30 import com.five_ten_sg.connectbot.transport.AbsTransport;
|
|
31 import android.graphics.Paint;
|
|
32 import android.text.AndroidCharacter;
|
|
33 import android.util.Log;
|
|
34 import de.mud.terminal.vt320;
|
|
35
|
|
36 /**
|
|
37 * @author Kenny Root
|
|
38 */
|
|
39 public class Relay implements Runnable {
|
|
40 private static final String TAG = "ConnectBot.Relay";
|
|
41
|
|
42 private static final int BUFFER_SIZE = 4096;
|
|
43
|
|
44 private TerminalBridge bridge;
|
|
45
|
|
46 private Charset currentCharset;
|
|
47 private CharsetDecoder decoder;
|
|
48
|
|
49 private AbsTransport transport;
|
|
50
|
|
51 private vt320 buffer;
|
|
52
|
|
53 private ByteBuffer byteBuffer;
|
|
54 private CharBuffer charBuffer;
|
|
55
|
|
56 private byte[] byteArray;
|
|
57 private char[] charArray;
|
|
58
|
|
59 private void eastAsianWidthMeasure(char[] charArray, int start, int end,
|
|
60 byte[] wideAttribute, Paint paint, int charWidth) {
|
|
61 AndroidCharacter.getEastAsianWidths(charArray, start, end - start, wideAttribute);
|
|
62 }
|
|
63
|
|
64 public Relay(TerminalBridge bridge, AbsTransport transport, vt320 buffer, String encoding) {
|
|
65 setCharset(encoding);
|
|
66 this.bridge = bridge;
|
|
67 this.transport = transport;
|
|
68 this.buffer = buffer;
|
|
69 }
|
|
70
|
|
71 public void setCharset(String encoding) {
|
|
72 Log.d("ConnectBot.Relay", "changing charset to " + encoding);
|
|
73 Charset charset;
|
|
74
|
|
75 if (encoding.equals("CP437"))
|
|
76 charset = new IBM437("IBM437",
|
|
77 new String[] { "IBM437", "CP437" });
|
|
78 else
|
|
79 charset = Charset.forName(encoding);
|
|
80
|
|
81 if (charset == currentCharset || charset == null)
|
|
82 return;
|
|
83
|
|
84 CharsetDecoder newCd = charset.newDecoder();
|
|
85 newCd.onUnmappableCharacter(CodingErrorAction.REPLACE);
|
|
86 newCd.onMalformedInput(CodingErrorAction.REPLACE);
|
|
87 currentCharset = charset;
|
|
88
|
|
89 synchronized (this) {
|
|
90 decoder = newCd;
|
|
91 }
|
|
92 }
|
|
93
|
|
94 public Charset getCharset() {
|
|
95 return currentCharset;
|
|
96 }
|
|
97
|
|
98 public void run() {
|
|
99 byteBuffer = ByteBuffer.allocate(BUFFER_SIZE);
|
|
100 charBuffer = CharBuffer.allocate(BUFFER_SIZE);
|
|
101 /* for East Asian character widths */
|
|
102 byte[] wideAttribute = new byte[BUFFER_SIZE];
|
|
103 byteArray = byteBuffer.array();
|
|
104 charArray = charBuffer.array();
|
|
105 CoderResult result;
|
|
106 int bytesRead = 0;
|
|
107 byteBuffer.limit(0);
|
|
108 int bytesToRead;
|
|
109 int offset;
|
|
110 int charWidth;
|
|
111
|
|
112 try {
|
|
113 while (true) {
|
|
114 charWidth = bridge.charWidth;
|
|
115 bytesToRead = byteBuffer.capacity() - byteBuffer.limit();
|
|
116 offset = byteBuffer.arrayOffset() + byteBuffer.limit();
|
112
|
117
|
0
|
118 if (transport.willBlock()) buffer.testChanged();
|
112
|
119
|
0
|
120 bytesRead = transport.read(byteArray, offset, bytesToRead);
|
|
121
|
|
122 if (bytesRead > 0) {
|
|
123 byteBuffer.limit(byteBuffer.limit() + bytesRead);
|
|
124
|
|
125 synchronized (this) {
|
|
126 result = decoder.decode(byteBuffer, charBuffer, false);
|
|
127 }
|
|
128
|
|
129 if (result.isUnderflow() &&
|
|
130 byteBuffer.limit() == byteBuffer.capacity()) {
|
|
131 byteBuffer.compact();
|
|
132 byteBuffer.limit(byteBuffer.position());
|
|
133 byteBuffer.position(0);
|
|
134 }
|
|
135
|
|
136 offset = charBuffer.position();
|
|
137 eastAsianWidthMeasure(charArray, 0, offset, wideAttribute, bridge.defaultPaint, charWidth);
|
|
138 buffer.putString(charArray, wideAttribute, 0, charBuffer.position());
|
|
139 bridge.propagateConsoleText(charArray, charBuffer.position());
|
|
140 charBuffer.clear();
|
|
141 bridge.redraw();
|
|
142 }
|
|
143 }
|
|
144 }
|
|
145 catch (IOException e) {
|
|
146 Log.e(TAG, "Problem while handling incoming data in relay thread", e);
|
|
147 }
|
|
148 }
|
|
149 }
|