package uc.protocols; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.channels.WritableByteChannel; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import logger.LoggerFactory; import org.apache.log4j.Logger; public class VarByteBuffer { private static Logger logger = LoggerFactory.make(); private byte[] current = new byte[1024]; private int readpos; private int writepos; private ByteBuffer wrapper = ByteBuffer.wrap(current); private final int maxSize; private InputStream decompression; /** * * @param wantedMaxSize recommended size buffer * will shrink if it gets larger.. * */ public VarByteBuffer(int wantedMaxSize) { this.maxSize = wantedMaxSize; } public int writeToChannel(WritableByteChannel wchan) throws IOException { wrapper.position(readpos); wrapper.limit(writepos); int written = wchan.write(wrapper); readpos = wrapper.position(); if (current.length > maxSize*2 && writepos-readpos < current.length/4) { shrinkBuffer(); } return written; } /* * @param addBytes - bytes that should be encrypted.. * @param engine - used for encryption.. * public SSLEngineResult encrypt(ByteBuffer addBytes, SSLEngine engine) throws SSLException { ensureWriteSize(Math.max(addBytes.remaining(), engine.getSession().getPacketBufferSize())); wrapper.limit(current.length); wrapper.position(writepos); SSLEngineResult ssler = engine.wrap(addBytes, wrapper); writepos = wrapper.position(); return ssler; } */ /* public SSLEngineResult decrypt(ByteBuffer encrypted, SSLEngine engine) throws SSLException { ByteBuffer helpdec = ByteBuffer.allocate(engine.getSession().getApplicationBufferSize()); SSLEngineResult ssler = engine.unwrap(encrypted, helpdec); helpdec.flip(); putBytes(helpdec); // ensureWriteSize(encrypted.remaining()+1000); // wrapper.limit(current.length); // wrapper.position(writepos); // SSLEngineResult ssler= engine.unwrap(encrypted, wrapper); // writepos = wrapper.position(); return ssler; } */ public boolean hasRemaining() { return readpos < writepos; } public int remaining() { return writepos - readpos; } public void clear() { current = new byte[1024]; wrapper = ByteBuffer.wrap(current); readpos = 0 ; writepos = 0; decompression = null; } public void putBytes(ByteBuffer bytes) { ensureWriteSize(bytes.remaining()); wrapper.limit(current.length); wrapper.position(writepos); wrapper.put(bytes); writepos = wrapper.position(); } /** * * @param bytes - where the bytes shall go to * @return number of bytes trnasferred */ public int getBytes(ByteBuffer bytes) { wrapper.position(readpos); int remaining = bytes.remaining(); int limit = Math.min( readpos+remaining , writepos); wrapper.limit( limit); bytes.put(wrapper); readpos = wrapper.position(); return remaining - bytes.remaining(); } private void ensureWriteSize(int size) { if (size >= current.length - writepos) { if (readpos + current.length - writepos > size) { //just move if total size allows it System.arraycopy(current, readpos, current, 0, writepos - readpos); } else { //create new byte[] newArray = new byte[Math.max(current.length*2,current.length+size+1)]; System.arraycopy(current, readpos, newArray, 0, writepos - readpos); current = newArray; wrapper = ByteBuffer.wrap(current); } writepos -= readpos; readpos = 0; } } private void shrinkBuffer() { byte[] newArray = new byte[Math.max(writepos - readpos,1024)]; System.arraycopy(current, readpos, newArray, 0, writepos-readpos); current = newArray; writepos-=readpos; readpos = 0; wrapper = ByteBuffer.wrap(current); } /** * * @param stopper - read until this char is reached .. * or everything available.. if not found.. * * @param decoder - used for decoding * @return the String read.. */ public byte[] readUntil(byte stopper) { if (decompression == null) { int limit = writepos; for (int i = readpos; i < writepos ; i++) { if (current[i] == stopper) { limit = i+1; break; } } wrapper.position(readpos); wrapper.limit(limit); byte[] read= new byte[limit-readpos]; wrapper.get(read); // CharBuffer cb = CharBuffer.allocate(limit-readpos); // decoder.decode(wrapper, cb, true); // cb.flip(); readpos = wrapper.position(); return read; } else { int read; ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { while ( -1 != (read = decompression.read())) { //System.out.print((char)read); baos.write(read); if (read == stopper) { break; } } if (read == -1) { decompression = null; // logger.warn("disabling ZPipe"); } } catch (IOException ioe) { ioe.printStackTrace(); } // ByteBuffer buf = ByteBuffer.wrap(baos.toByteArray()); // CharBuffer cb = CharBuffer.allocate(buf.remaining()); // decoder.decode(buf, cb, true); // cb.flip(); // if (decompression == null) { // // StringBuilder sb = new StringBuilder(); // for (int i = readpos ; i < writepos; i++) { // sb.append((char)(current[i] & 0xff)); // } // // logger.debug("last string read: "+cb.toString()+" nextin Buffer: "+sb ); // // } // if (cb.toString().equals("IZON")) { // logger.debug("used ZON for eof"); // decompression = null; // } // logger.debug("read compressed: "+cb); return baos.toByteArray(); } } public void setDecompression(Compression comp,final Lock lock,final Condition bytesChanged) throws IOException { if (comp == Compression.NONE) { decompression = null; } else { InputStream is = new InputStream() { @Override public int read() throws IOException { int i = 0; lock.lock(); try { while (!hasRemaining()) { try { i++; bytesChanged.await(100, TimeUnit.MILLISECONDS); logger.debug("wait" + i); } catch (InterruptedException ie) { } if (i > 120) { // 2 minutes timeout... logger.warn("timeout"); return -1; } } return current[readpos++] & 0xff; } finally { lock.unlock(); } } }; decompression = comp.wrapIncoming(is); } } /** * debug output of current contents */ public String toString() { return new String(current,readpos, writepos-readpos); } }