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 }