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 */ 38 public class Relay implements Runnable { 39 40 private static final int BUFFER_SIZE = 4096; 41 42 private static boolean useJNI = true; 43 44 private TerminalBridge bridge; 45 46 private Charset currentCharset; 47 private CharsetDecoder decoder; 48 private boolean isLegacyEastAsian = false; 49 50 private AbsTransport transport; 51 52 private vt320 buffer; 53 54 private ByteBuffer byteBuffer; 55 private CharBuffer charBuffer; 56 57 private byte[] byteArray; 58 private char[] charArray; 59 60 static { 61 useJNI = EastAsianWidth.useJNI; 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("changing charset to " + encoding); 73 Charset charset; 74 if (encoding.equals("CP437")) { 75 charset = new IBM437("IBM437", new String[] { "IBM437", "CP437" }); 76 } else { 77 charset = Charset.forName(encoding); 78 } 79 80 if (charset == currentCharset || charset == null) { 81 return; 82 } 83 84 CharsetDecoder newCd = charset.newDecoder(); 85 newCd.onUnmappableCharacter(CodingErrorAction.REPLACE); 86 newCd.onMalformedInput(CodingErrorAction.REPLACE); 87 88 currentCharset = charset; 89 synchronized (this) { 90 decoder = newCd; 91 } 92 } 93 94 public void run() { 95 byteBuffer = ByteBuffer.allocate(BUFFER_SIZE); 96 charBuffer = CharBuffer.allocate(BUFFER_SIZE); 97 98 /* for both JNI and non-JNI method */ 99 byte[] wideAttribute = new byte[BUFFER_SIZE]; 100 101 /* non-JNI fallback method */ 102 float[] widths = null; 103 104 if (!useJNI) { 105 widths = new float[BUFFER_SIZE]; 106 } 107 108 byteArray = byteBuffer.array(); 109 charArray = charBuffer.array(); 110 111 CoderResult result; 112 113 int bytesRead = 0; 114 byteBuffer.limit(0); 115 int bytesToRead; 116 int offset; 117 int charWidth; 118 119 try { 120 while (true) { 121 charWidth = bridge.charWidth; 122 bytesToRead = byteBuffer.capacity() - byteBuffer.limit(); 123 offset = byteBuffer.arrayOffset() + byteBuffer.limit(); 124 bytesRead = transport.read(byteArray, offset, bytesToRead); 125 126 if (bytesRead > 0) { 127 byteBuffer.limit(byteBuffer.limit() + bytesRead); 128 129 synchronized (this) { 130 result = decoder.decode(byteBuffer, charBuffer, false); 131 } 132 133 if (result.isUnderflow() && byteBuffer.limit() == byteBuffer.capacity()) { 134 byteBuffer.compact(); 135 byteBuffer.limit(byteBuffer.position()); 136 byteBuffer.position(0); 137 } 138 139 offset = charBuffer.position(); 140 141 if (!useJNI) { 142 bridge.getPaint().getTextWidths(charArray, 0, offset, widths); 143 for (int i = 0; i < offset; i++) { 144 wideAttribute[i] = (byte) (((int) widths[i] != charWidth) ? 1 : 0); 145 } 146 } else { 147 EastAsianWidth.measure(charArray, 0, charBuffer.position(), wideAttribute, 148 isLegacyEastAsian); 149 } 150 buffer.putString(charArray, wideAttribute, 0, charBuffer.position()); 151 charBuffer.clear(); 152 bridge.redraw(); 153 } 154 } 155 } catch (IOException e) { 156 Log.e("Problem while handling incoming data in relay thread", e); 157 } 158 } 159 } 160