namespace se.lth.control.labcomm { using System; using System.IO; using System.Runtime.InteropServices; using System.Text; public class LabCommDecoderChannel : LabCommDecoder { private Stream stream; private LabCommDecoderRegistry registry = new LabCommDecoderRegistry(); byte[] buf = new byte[8]; public LabCommDecoderChannel(Stream stream) { this.stream = stream; } public void runOne() { bool done = false; while (!done) { int tag = decodePacked32(); switch (tag) { case LabComm.TYPEDEF: case LabComm.SAMPLE: { int index = decodePacked32(); String name = decodeString(); MemoryStream signature = new MemoryStream(); collectFlatSignature(new LabCommEncoderChannel(signature)); registry.add(index, name, signature.ToArray()); } break; default: { LabCommDecoderRegistry.Entry e = registry.get(tag); if (e == null) { throw new IOException("Unhandled tag " + tag); } LabCommDispatcher d = e.getDispatcher(); if (d == null) { throw new IOException("No dispatcher for '" + e.getName() + "'" + e.getSignature()); } LabCommHandler h = e.getHandler(); if (h == null) { throw new IOException("No handler for '" + e.getName() +"'"); } d.decodeAndHandle(this, h); done = true; } break; } } } public void run() { while (true) { runOne(); } } private void collectFlatSignature(LabCommEncoder e) { int type = decodePacked32(); e.encodePacked32(type); switch (type) { case LabComm.ARRAY: { int dimensions = decodePacked32(); e.encodePacked32(dimensions); for (int i = 0 ; i < dimensions ; i++) { e.encodePacked32(decodePacked32()); } collectFlatSignature(e); } break; case LabComm.STRUCT: { int fields = decodePacked32(); e.encodeInt(fields); for (int i = 0 ; i < fields ; i++) { e.encodeString(decodeString()); collectFlatSignature(e); } } break; case LabComm.BOOLEAN: case LabComm.BYTE: case LabComm.SHORT: case LabComm.INT: case LabComm.LONG: case LabComm.FLOAT: case LabComm.DOUBLE: case LabComm.STRING: { } break; default: { throw new IOException("Unimplemented type=" + type); } } e.end(null); } public void register(LabCommDispatcher dispatcher, LabCommHandler handler) { registry.add(dispatcher, handler); } private void ReadBytes(byte[] result, int length) { int offset = 0; while (offset < length) { int count = stream.Read(result, offset, length - offset); if (count <= 0) throw new EndOfStreamException( String.Format("End of stream reached with {0} bytes left to read", length - offset)); offset += count; } } private Int64 ReadInt(int length) { int result = 0; ReadBytes(buf, length); for (int i = 0 ; i < length ; i++) { result = (result << 8) + buf[i]; } return result; } public bool decodeBoolean() { return ReadInt(1) != 0; } public byte decodeByte() { return (byte)ReadInt(1); } public short decodeShort() { return (short)ReadInt(2); } public int decodeInt() { return (int)ReadInt(4); } public long decodeLong() { return (long)ReadInt(8); } [StructLayout(LayoutKind.Explicit)] private struct Int32SingleUnion { [FieldOffset(0)] public int AsInt; [FieldOffset(0)] public float AsFloat; }; public float decodeFloat() { Int32SingleUnion u; u.AsFloat = 0; // Avoid error messge u.AsInt = (int)ReadInt(4); return u.AsFloat; } public double decodeDouble() { return BitConverter.Int64BitsToDouble(ReadInt(8)); } public String decodeString() { //int length = (int)ReadInt(4); int length = decodePacked32(); byte[] buf = new byte[length]; ReadBytes(buf, length); return Encoding.UTF8.GetString(buf); } public int decodePacked32() { TODO: Correct byteorder Int64 res = 0; byte i = 0; bool cont = true; do { byte c = decodeByte(); res |= (uint) ((c & 0x7f) << 7*i); cont = (c & 0x80) != 0; i++; } while(cont); return (int) (res & 0xffffffff); } } }