• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 org.connectbot.service;
19 
20 import com.googlecode.android_scripting.Log;
21 
22 import de.mud.terminal.vt320;
23 
24 import org.apache.harmony.niochar.charset.additional.IBM437;
25 import org.connectbot.transport.AbsTransport;
26 import org.connectbot.util.EastAsianWidth;
27 
28 import java.io.IOException;
29 import java.nio.ByteBuffer;
30 import java.nio.CharBuffer;
31 import java.nio.charset.Charset;
32 import java.nio.charset.CharsetDecoder;
33 import java.nio.charset.CoderResult;
34 import java.nio.charset.CodingErrorAction;
35 
36 /**
37  * @author Kenny Root
38  */
39 public class Relay implements Runnable {
40 
41   private static final int BUFFER_SIZE = 4096;
42 
43   private static boolean useJNI = true;
44 
45   private TerminalBridge bridge;
46 
47   private Charset currentCharset;
48   private CharsetDecoder decoder;
49   private boolean isLegacyEastAsian = false;
50 
51   private AbsTransport transport;
52 
53   private vt320 buffer;
54 
55   private ByteBuffer byteBuffer;
56   private CharBuffer charBuffer;
57 
58   private byte[] byteArray;
59   private char[] charArray;
60 
61   static {
62     useJNI = EastAsianWidth.useJNI;
63   }
64 
Relay(TerminalBridge bridge, AbsTransport transport, vt320 buffer, String encoding)65   public Relay(TerminalBridge bridge, AbsTransport transport, vt320 buffer, String encoding) {
66     setCharset(encoding);
67     this.bridge = bridge;
68     this.transport = transport;
69     this.buffer = buffer;
70   }
71 
setCharset(String encoding)72   public void setCharset(String encoding) {
73     Log.d("changing charset to " + encoding);
74     Charset charset;
75     if (encoding.equals("CP437")) {
76       charset = new IBM437("IBM437", new String[] { "IBM437", "CP437" });
77     } else {
78       charset = Charset.forName(encoding);
79     }
80 
81     if (charset == currentCharset || charset == null) {
82       return;
83     }
84 
85     CharsetDecoder newCd = charset.newDecoder();
86     newCd.onUnmappableCharacter(CodingErrorAction.REPLACE);
87     newCd.onMalformedInput(CodingErrorAction.REPLACE);
88 
89     currentCharset = charset;
90     synchronized (this) {
91       decoder = newCd;
92     }
93   }
94 
run()95   public void run() {
96     byteBuffer = ByteBuffer.allocate(BUFFER_SIZE);
97     charBuffer = CharBuffer.allocate(BUFFER_SIZE);
98 
99     /* for both JNI and non-JNI method */
100     byte[] wideAttribute = new byte[BUFFER_SIZE];
101 
102     /* non-JNI fallback method */
103     float[] widths = null;
104 
105     if (!useJNI) {
106       widths = new float[BUFFER_SIZE];
107     }
108 
109     byteArray = byteBuffer.array();
110     charArray = charBuffer.array();
111 
112     CoderResult result;
113 
114     int bytesRead = 0;
115     byteBuffer.limit(0);
116     int bytesToRead;
117     int offset;
118     int charWidth;
119 
120     try {
121       while (true) {
122         charWidth = bridge.charWidth;
123         bytesToRead = byteBuffer.capacity() - byteBuffer.limit();
124         offset = byteBuffer.arrayOffset() + byteBuffer.limit();
125         bytesRead = transport.read(byteArray, offset, bytesToRead);
126 
127         if (bytesRead > 0) {
128           byteBuffer.limit(byteBuffer.limit() + bytesRead);
129 
130           synchronized (this) {
131             result = decoder.decode(byteBuffer, charBuffer, false);
132           }
133 
134           if (result.isUnderflow() && byteBuffer.limit() == byteBuffer.capacity()) {
135             byteBuffer.compact();
136             byteBuffer.limit(byteBuffer.position());
137             byteBuffer.position(0);
138           }
139 
140           offset = charBuffer.position();
141 
142           if (!useJNI) {
143             bridge.getPaint().getTextWidths(charArray, 0, offset, widths);
144             for (int i = 0; i < offset; i++) {
145               wideAttribute[i] = (byte) (((int) widths[i] != charWidth) ? 1 : 0);
146             }
147           } else {
148             EastAsianWidth.measure(charArray, 0, charBuffer.position(), wideAttribute,
149                 isLegacyEastAsian);
150           }
151           buffer.putString(charArray, wideAttribute, 0, charBuffer.position());
152           charBuffer.clear();
153           bridge.redraw();
154         }
155       }
156     } catch (IOException e) {
157       Log.e("Problem while handling incoming data in relay thread", e);
158     }
159   }
160 }
161