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