diff --git a/Makefile b/Makefile index 70b4d73..7662813 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ CXX=g++ -std=c++11 CAPNP_SOURCES=\ + src/capnp/AnyPointer.java\ src/capnp/FieldSize.java\ src/capnp/FromStructReader.java\ src/capnp/InputStreamMessageReader.java\ diff --git a/src/capnp/AnyPointer.java b/src/capnp/AnyPointer.java new file mode 100644 index 0000000..37fc2a0 --- /dev/null +++ b/src/capnp/AnyPointer.java @@ -0,0 +1,17 @@ +package capnp; + +public class AnyPointer { + + public static class Reader { + public PointerReader reader; + + public Reader(PointerReader reader) { + this.reader = reader; + } + + public T getAsStruct(FromStructReader factory) { + return factory.fromStructReader(this.reader.getStruct()); + } + } + +} diff --git a/src/capnp/InputStreamMessageReader.java b/src/capnp/InputStreamMessageReader.java index 9033b08..3060007 100644 --- a/src/capnp/InputStreamMessageReader.java +++ b/src/capnp/InputStreamMessageReader.java @@ -3,24 +3,75 @@ package capnp; import java.io.InputStream; import java.io.IOException; import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Vector; + public class InputStreamMessageReader { - static MessageReader create(InputStream is) throws IOException { - byte[] firstWord = new byte[8]; + + static byte[] readExact(InputStream is, int length) throws IOException { + byte[] bytes = new byte[length]; int bytesRead = 0; - while (bytesRead < 8) { - int n = is.read(firstWord, bytesRead, 8 - bytesRead); - if (n < 0) { + while (bytesRead < length) { + int r = is.read(bytes, bytesRead, length - bytesRead); + if (r < 0) { throw new IOException("premature EOF"); } - bytesRead += n; + bytesRead += r; } - ByteBuffer.wrap(firstWord); + return bytes; + } + static ByteBuffer makeByteBuffer(byte[] bytes) { + ByteBuffer result = ByteBuffer.wrap(bytes); + result.order(ByteOrder.LITTLE_ENDIAN); + return result; + } - throw new Error(); + public static MessageReader create(InputStream is) throws IOException { + ByteBuffer firstWord = makeByteBuffer(readExact(is, 8)); + + int segmentCount = 1 + firstWord.getInt(); + + int segment0Size = 0; + if (segmentCount > 0) { + segment0Size = firstWord.getInt(1); + } + + int totalWords = segment0Size; + + if (segmentCount > 512) { + throw new IOException("too many segments"); + } + + Vector moreSizes = new Vector(); + + if (segmentCount > 1) { + ByteBuffer moreSizesRaw = makeByteBuffer(readExact(is, 4 * (segmentCount & ~1))); + for(int ii = 0; ii < segmentCount - 1; ++ii) { + int size = moreSizesRaw.getInt(ii); + moreSizes.add(size); + totalWords += size; + } + } + + // TODO check that totalWords is reasonable + + byte[] allSegments = readExact(is, totalWords * 8); + + ByteBuffer[] segmentSlices = new ByteBuffer[segmentCount]; + + segmentSlices[0] = ByteBuffer.wrap(allSegments, 0, segment0Size); + int offset = segment0Size; + + for (int ii = 1; ii < segmentCount; ++ii) { + segmentSlices[ii] = ByteBuffer.wrap(allSegments, offset, moreSizes.get(ii - 1)); + offset += moreSizes.get(ii - 1); + } + + return new MessageReader(segmentSlices); } } diff --git a/src/capnp/MessageReader.java b/src/capnp/MessageReader.java index ec6edb8..2d1fa17 100644 --- a/src/capnp/MessageReader.java +++ b/src/capnp/MessageReader.java @@ -1,5 +1,20 @@ package capnp; -public class MessageReader { +import java.nio.ByteBuffer; +public class MessageReader { + ByteBuffer[] segmentSlices; + + public MessageReader(ByteBuffer[] segmentSlices) { + this.segmentSlices = segmentSlices; + } + + public T getRoot(FromStructReader factory) { + SegmentReader segment = new SegmentReader(this.segmentSlices[0]); + PointerReader pointerReader = PointerReader.getRoot(segment, + new WordPointer(this.segmentSlices[0], 0), + 0x7fffffff /* XXX */); + AnyPointer.Reader any = new AnyPointer.Reader(pointerReader); + return any.getAsStruct(factory); + } } diff --git a/src/capnp/PointerReader.java b/src/capnp/PointerReader.java index b84292d..47fc380 100644 --- a/src/capnp/PointerReader.java +++ b/src/capnp/PointerReader.java @@ -17,12 +17,27 @@ public class PointerReader { this.nestingLimit = nestingLimit; } + public static PointerReader getRoot(SegmentReader segment, + WordPointer location, + int nestingLimit) { + // TODO bounds check + return new PointerReader(segment, location.offset, nestingLimit); + } + + public StructReader getStruct() { + WirePointer ref = new WirePointer(this.segment.ptr, this.pointer); + return WireHelpers.readStructPointer(this.segment, + ref, + this.nestingLimit); + } + public ListReader getList(byte expectedElementSize) { // TODO check nullness WirePointer ref = new WirePointer(this.segment.ptr, this.pointer); return WireHelpers.readListPointer(this.segment, ref, - expectedElementSize); + expectedElementSize, + this.nestingLimit); } public Text.Reader getText() { diff --git a/src/capnp/SegmentReader.java b/src/capnp/SegmentReader.java index d9e6661..a9c6d9f 100644 --- a/src/capnp/SegmentReader.java +++ b/src/capnp/SegmentReader.java @@ -4,4 +4,8 @@ import java.nio.ByteBuffer; public class SegmentReader { ByteBuffer ptr; + + public SegmentReader(ByteBuffer ptr) { + this.ptr = ptr; + } } diff --git a/src/capnp/WireHelpers.java b/src/capnp/WireHelpers.java index eb5f0b4..92169ed 100644 --- a/src/capnp/WireHelpers.java +++ b/src/capnp/WireHelpers.java @@ -2,8 +2,30 @@ package capnp; class WireHelpers { + public static StructReader readStructPointer(SegmentReader segment, + WirePointer ref, + int nestingLimit) { + + // TODO error handling + + WordPointer ptr = ref.target(); + StructPointer structPtr = (StructPointer)ref; + int dataSizeWords = structPtr.dataSize(); + + return new StructReader(segment, + ptr.offset * 8, + (ptr.offset + dataSizeWords) * 8, + dataSizeWords * 64, + structPtr.ptrCount(), + (byte)0, + nestingLimit - 1); + + } + + public static ListReader readListPointer(SegmentReader segment, WirePointer ref, + byte expectedElementSize, int nestingLimit) { // TODO check for null, follow fars, nestingLimit @@ -30,7 +52,7 @@ class WireHelpers { // TODO check whether the size is compatible return new ListReader(segment, // TODO follow fars - ptr.offset, // + ptr.offset * 8, // size, wordsPerElement * 64, structPtr.dataSize() * 64,