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