Skip to content
Snippets Groups Projects
DecoderChannel.java 6.45 KiB
package se.lth.control.labcomm2014;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.EOFException;

public class DecoderChannel implements Decoder {

  private DataInputStream in;
  private DecoderRegistry def_registry = new DecoderRegistry();
  private DecoderRegistry ref_registry = new DecoderRegistry();

  public DecoderChannel(InputStream in) throws IOException {
    this.in = new DataInputStream(in);
  }

  private byte[] decodeBytes() throws IOException {
    int len = decodePacked32();
    byte result[] = new byte[len];

    for(int i=0; i<len; i++) {
      result[i] = decodeByte();
    }
    return result;
  }

  private String decodeIntentions() throws IOException {
    int numIntentions = decodePacked32();
    String name = "";
    for(int i = 0; i<numIntentions; i++) {
      byte key[] = decodeBytes();
      byte val[] = decodeBytes();

      if(key.length == 0) {
        name = new String(val);
      }
    }
    return name;
  }

  private void processSampleDef() throws IOException {
    int index = decodePacked32();
    String name = decodeIntentions();
    int signature_length = decodePacked32();
    byte[] signature = new byte[signature_length];
    ReadBytes(signature, signature_length);
    def_registry.add(index, name, signature);
  }

  private void processSampleRef() throws IOException {
    int index = decodePacked32();
    String name = decodeIntentions();
    int signature_length = decodePacked32();
    byte[] signature = new byte[signature_length];
    ReadBytes(signature, signature_length);
    ref_registry.add(index, name, signature);
  }

  private void processTypeDef(int len) throws IOException {
       try {
           processSample(Constant.TYPE_DEF);
      } catch(Exception ex) {
       int idx = decodePacked32();
       String name = decodeIntentions();
       int siglen = decodePacked32();
       for(int i=0; i<siglen; i++) {
           byte b = decodeByte();
       }
      }
  }

  private void processTypeBinding(int len) throws IOException {
      try {
           processSample(Constant.TYPE_BINDING);
      } catch(Exception ex) {
          for(int i=0; i<len; i++) {
              decodeByte();
          }
      }
  }

  private void processPragma(int len) throws IOException {
       for(int i=0; i<len; i++) {
           decodeByte();
       }
  }

  private void processSample(int tag) throws IOException {
	  DecoderRegistry.Entry e = def_registry.get(tag);
	  if (e == null) {
	    throw new IOException("Unhandled tag " + tag);
	  }
	  SampleDispatcher d = e.getDispatcher();
	  if (d == null) {
	    throw new IOException("No dispatcher for '" + e.getName() + "'");
	  }
	  SampleHandler h = e.getHandler();
	  if (h == null) {
	    throw new IOException("No handler for '" + e.getName() +"'");
	  }
      try {
        //XXX why does decodeAndHandle throw Exception and not IOException?
        d.decodeAndHandle(this, h);
      } catch (IOException ex) {
          throw ex;
      } catch (Exception ex) {
          ex.printStackTrace();
      }
  }

  public void runOne() throws Exception {
    boolean done = false;
    while (!done) {
      int tag = decodePacked32();
      int length = decodePacked32();
      switch (tag) {
        case Constant.VERSION: {
          String version = decodeString();
          if (! version.equals(Constant.CURRENT_VERSION)) {
            throw new IOException("LabComm version mismatch " +
			          version + " != " + Constant.CURRENT_VERSION);
          }
        } break;
        case Constant.SAMPLE_DEF: {
            processSampleDef();
        } break;
        case Constant.SAMPLE_REF: {
            processSampleRef();
        } break;
        case Constant.TYPE_DEF: {
            processTypeDef(length);
        } break;
        case Constant.TYPE_BINDING: {
            processTypeBinding(length);
        } break;
        case Constant.PRAGMA: {
            processPragma(length);
        } break;
        default: {
            processSample(tag);
            done = true;

        }
      }
    }
  }

  public void run() throws Exception {
    while (true) {
      runOne();
    }
  }

  public void register(SampleDispatcher dispatcher,
                       SampleHandler handler) throws IOException {
    def_registry.add(dispatcher, handler);
  }

  public void registerSampleRef(SampleDispatcher dispatcher) throws IOException {
    ref_registry.add(dispatcher, null);
  }

  private void ReadBytes(byte[] result, int length) throws IOException {
      int offset = 0;
      while (offset < length) {
	int count = in.read(result, offset, length - offset);
	if (count <= 0) {
	  throw new EOFException(
	    "End of stream reached with " +
            (length - offset) + " bytes left to read");
        }
	offset += count;
      }
    }

  public boolean decodeBoolean() throws IOException {
    return in.readBoolean();
  }

  public byte decodeByte() throws IOException {
    return in.readByte();
  }

  public short decodeShort() throws IOException {
    return in.readShort();
  }

  public int decodeInt() throws IOException {
    return in.readInt();
  }

  public long decodeLong() throws IOException {
    return in.readLong();
  }

  public float decodeFloat() throws IOException {
    return in.readFloat();
  }

  public double decodeDouble() throws IOException {
    return in.readDouble();
  }

  public String decodeString() throws IOException {
    //in.readShort(); // HACK
    //return in.readUTF();
    int len = decodePacked32() & 0xffffffff;
    byte[] chars = new byte[len];
    for(int i=0; i<len; i++) {
      chars[i] = in.readByte();
    }
    return new String(chars);
  }

  public int decodePacked32() throws IOException {
    long res=0;
    byte i=0;
    boolean cont=true;

    do {
      byte c = in.readByte();
      res = (res << 7) | (c & 0x7f);
      cont = (c & 0x80) != 0;
      i++;
    } while(cont);

    return (int) (res & 0xffffffff);
  }

  public Class decodeSampleRef() throws IOException {
    int index = in.readInt();
    try {
      DecoderRegistry.Entry e = ref_registry.get(index);
      return e.getDispatcher().getSampleClass();
    } catch (NullPointerException e) {
      return null;
    }

  }

  /* Package visible methods for use from TypeDefParser */

  String getSampleName(int idx) {
    DecoderRegistry.Entry e = def_registry.get(idx);
    return e.getName();
  }

  byte[] getSampleSignature(int idx) {
    DecoderRegistry.Entry e = def_registry.get(idx);
    return e.getSignature();
  }
}