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 }