001 package org.crsh.term.spi.net; 002 003 import org.crsh.term.CodeType; 004 import org.crsh.term.spi.TermIO; 005 import org.crsh.util.AbstractSocketClient; 006 007 import java.io.IOException; 008 import java.io.InputStream; 009 import java.io.OutputStream; 010 import java.nio.ByteBuffer; 011 import java.nio.charset.Charset; 012 013 /** 014 * 015 * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> 016 */ 017 public class TermIOClient extends AbstractSocketClient implements TermIO { 018 019 /** . */ 020 private static final Charset UTF_8 = Charset.forName("UTF-8"); 021 022 /** . */ 023 private byte[] bytes = new byte[2000]; 024 025 /** . */ 026 private ByteBuffer buffer = ByteBuffer.wrap(bytes); 027 028 /** . */ 029 private InputStream in; 030 031 /** . */ 032 private OutputStream out; 033 034 public TermIOClient(int port) { 035 super(port); 036 } 037 038 @Override 039 protected void handle(InputStream in, OutputStream out) throws IOException { 040 this.in = in; 041 this.out = out; 042 } 043 044 private void put(byte b) { 045 if (buffer.remaining() == 0) { 046 byte[] bytesCopy = new byte[bytes.length * 2 + 1]; 047 System.arraycopy(bytes, 0, bytesCopy, 0, bytes.length); 048 ByteBuffer bufferCopy = ByteBuffer.wrap(bytesCopy); 049 bufferCopy.position(buffer.position()); 050 051 // 052 bytes = bytesCopy; 053 buffer = bufferCopy; 054 } 055 buffer.put(b); 056 } 057 058 059 private int _read(byte[] buffer, int off, int len) throws IOException, Done { 060 int b = in.read(buffer, off, len); 061 if (b == -1) { 062 throw new Done(); 063 } 064 return b; 065 } 066 067 private byte _read() throws IOException, Done { 068 int b = in.read(); 069 if (b == -1) { 070 throw new Done(); 071 } 072 return (byte)b; 073 } 074 075 public int read() throws IOException { 076 try { 077 out.write(0); 078 out.flush(); 079 byte b = _read(); 080 CodeType codeType = CodeType.valueOf(b); 081 if (codeType == null) { 082 throw new UnsupportedOperationException("todo " + b); 083 } else if (codeType == CodeType.CHAR) { 084 byte b1 = _read(); 085 byte b2 = _read(); 086 return (b1 << 8) + b2; 087 } else { 088 return codeType.ordinal() << 16; 089 } 090 } catch (Done done) { 091 throw new UnsupportedOperationException("implement me", done); 092 } 093 } 094 095 public int getWidth() { 096 String width = getProperty("width"); 097 return Integer.parseInt(width); 098 } 099 100 public String getProperty(String name) { 101 // We don't process empty name 102 if (name.length() == 0) { 103 return null; 104 } 105 byte[] bytes = name.getBytes(UTF_8); 106 int len = bytes.length; 107 if (len > 256) { 108 throw new IllegalArgumentException("Property name too long : " + name); 109 } 110 try { 111 out.write(8); 112 out.write(len - 1); 113 out.write(bytes); 114 out.flush(); 115 len = _read(); 116 if (len == 0) { 117 return null; 118 } else if (len == 1) { 119 return ""; 120 } else { 121 bytes = new byte[len - 1]; 122 _read(bytes, 0, bytes.length); 123 return new String(bytes, 0, bytes.length); 124 } 125 126 // 127 } catch (Done done) { 128 throw new UnsupportedOperationException("implement me", done); 129 } catch (IOException e) { 130 throw new UnsupportedOperationException("implement me", e); 131 } 132 } 133 134 public CodeType decode(int code) { 135 code &= 0xFFFF0000; 136 if (code == 0) { 137 return CodeType.CHAR; 138 } else { 139 code >>= 16; 140 return CodeType.valueOf(code); 141 } 142 } 143 144 public void flush() throws IOException { 145 put((byte)7); 146 out.write(bytes, 0, buffer.position()); 147 buffer.clear(); 148 } 149 150 public void write(char c) throws IOException { 151 put((byte)1); 152 put((byte)((c & 0xFF00) >> 8)); 153 put((byte)(c & 0xFF)); 154 } 155 156 public void write(String s) throws IOException { 157 int prev = 0; 158 int len = s.length(); 159 while (prev < len) { 160 int pos = Math.min(len, prev + 257); 161 int chunkLen = pos - prev; 162 if (chunkLen == 1) { 163 write(s.charAt(prev++)); 164 } else { 165 put((byte)2); 166 put((byte)(chunkLen - 2)); 167 while (prev < pos) { 168 char c = s.charAt(prev++); 169 put((byte)((c & 0xFF00) >> 8)); 170 put((byte)(c & 0xFF)); 171 } 172 } 173 } 174 } 175 176 public void writeDel() throws IOException { 177 put((byte)3); 178 } 179 180 public void writeCRLF() throws IOException { 181 put((byte)4); 182 } 183 184 public boolean moveRight(char c) throws IOException { 185 put((byte)5); 186 put((byte)((c & 0xFF00) >> 8)); 187 put((byte)(c & 0xFF)); 188 return true; 189 } 190 191 public boolean moveLeft() throws IOException { 192 put((byte)6); 193 return true; 194 } 195 }