From 9ec8a9b67ec870d3daacaaeb70e3d88a08ff427d Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Tue, 17 Jun 2014 19:41:19 -0400 Subject: [PATCH] followFars easy case --- .../java/org/capnproto/StructBuilder.java | 7 ++ .../main/java/org/capnproto/WireHelpers.java | 89 +++++++++++++------ 2 files changed, 70 insertions(+), 26 deletions(-) diff --git a/runtime/src/main/java/org/capnproto/StructBuilder.java b/runtime/src/main/java/org/capnproto/StructBuilder.java index 4cc8ec8..27734ce 100644 --- a/runtime/src/main/java/org/capnproto/StructBuilder.java +++ b/runtime/src/main/java/org/capnproto/StructBuilder.java @@ -19,6 +19,13 @@ public final class StructBuilder { this.bit0Offset = bit0Offset; } + public final StructReader asReader() { + return new StructReader(this.segment, + this.data, this.pointers, this.dataSize, + this.pointerCount, this.bit0Offset, + 0x7fffffff); + } + public final boolean getBooleanField(int offset) { int bitOffset = (offset == 0 ? this.bit0Offset : offset); int position = this.data + (bitOffset / 8); diff --git a/runtime/src/main/java/org/capnproto/WireHelpers.java b/runtime/src/main/java/org/capnproto/WireHelpers.java index a7f3ef5..f26bc1c 100644 --- a/runtime/src/main/java/org/capnproto/WireHelpers.java +++ b/runtime/src/main/java/org/capnproto/WireHelpers.java @@ -89,6 +89,8 @@ final class WireHelpers { return new FollowBuilderFarsResult(WirePointer.target(padOffset, pad), pad, resultSegment); } + //# Landing pad is another far pointer. It is followed by a + //# tag describing the pointed-to object. throw new Error("unimplemented"); } else { @@ -96,6 +98,27 @@ final class WireHelpers { } } + static class FollowFarsResult { + public final int ptr; + public final long ref; + public final SegmentReader segment; + FollowFarsResult(int ptr, long ref, SegmentReader segment) { + this.ptr = ptr; this.ref = ref; this.segment = segment; + } + } + + public static FollowFarsResult followFars(long ref, int refTarget, SegmentReader segment) { + //# If the segment is null, this is an unchecked message, + //# so there are no FAR pointers. + if (segment != null && WirePointer.kind(ref) == WirePointer.FAR) { + + throw new Error("unimplemented"); + + } else { + return new FollowFarsResult(refTarget, ref, segment); + } + } + public static StructBuilder initStructPointer(int refOffset, SegmentBuilder segment, StructSize size) { @@ -297,21 +320,29 @@ final class WireHelpers { int refOffset, int nestingLimit) { - // TODO error handling + // TODO error handling. is_null - if (nestingLimit < 0) { + if (nestingLimit <= 0) { throw new DecodeException("Message is too deeply nested or contains cycles."); } long ref = WirePointer.get(segment.buffer, refOffset); - int ptrOffset = WirePointer.target(refOffset, ref); - int dataSizeWords = StructPointer.dataSize(ref); + int refTarget = WirePointer.target(refOffset, ref); + FollowFarsResult resolved = followFars(ref, refTarget, segment); - return new StructReader(segment, - ptrOffset * 8, - (ptrOffset + dataSizeWords), - dataSizeWords * 64, - StructPointer.ptrCount(ref), + int dataSizeWords = StructPointer.dataSize(resolved.ref); + + if (WirePointer.kind(resolved.ref) != WirePointer.STRUCT) { + throw new DecodeException("Message contains non-struct pointer where struct pointer was expected."); + } + + // TODO "bounds_check" (read limiting) + + return new StructReader(resolved.segment, + resolved.ptr * Constants.BYTES_PER_WORD, + (resolved.ptr + dataSizeWords), + dataSizeWords * Constants.BITS_PER_WORD, + StructPointer.ptrCount(resolved.ref), (byte)0, nestingLimit - 1); @@ -325,21 +356,24 @@ final class WireHelpers { long ref = WirePointer.get(segment.buffer, refOffset); - // TODO check for null, follow fars, nestingLimit if (WirePointer.isNull(ref)) { return new ListReader(); } + if (nestingLimit <= 0) { + throw new Error("nesting limit exceeded"); + } - int ptrOffset = WirePointer.target(refOffset, ref); - long ptr = WirePointer.get(segment.buffer, ptrOffset); + int refTarget = WirePointer.target(refOffset, ref); - switch (ListPointer.elementSize(ref)) { + FollowFarsResult resolved = followFars(ref, refTarget, segment); + + switch (ListPointer.elementSize(resolved.ref)) { case FieldSize.INLINE_COMPOSITE : { - int wordCount = ListPointer.inlineCompositeWordCount(ref); + int wordCount = ListPointer.inlineCompositeWordCount(resolved.ref); - long tag = ptr; - ptrOffset += 1; + long tag = WirePointer.get(resolved.segment.buffer, resolved.ptr); + int ptr = resolved.ptr + 1; // TODO bounds check @@ -351,11 +385,11 @@ final class WireHelpers { // TODO check whether the size is compatible - return new ListReader(segment, // TODO follow fars - ptrOffset * 8, // + return new ListReader(resolved.segment, + ptr * Constants.BYTES_PER_WORD, size, - wordsPerElement * 64, - StructPointer.dataSize(tag) * 64, + wordsPerElement * Constants.BITS_PER_WORD, + StructPointer.dataSize(tag) * Constants.BITS_PER_WORD, StructPointer.ptrCount(tag), nestingLimit - 1); } @@ -376,23 +410,26 @@ final class WireHelpers { return new Text.Reader(java.nio.ByteBuffer.wrap(new byte[0]), 0, 0); } - int ptrOffset = WirePointer.target(refOffset, ref); - int size = ListPointer.elementCount(ref); + int refTarget = WirePointer.target(refOffset, ref); - if (WirePointer.kind(ref) != WirePointer.LIST) { + FollowFarsResult resolved = followFars(ref, refTarget, segment); + + int size = ListPointer.elementCount(resolved.ref); + + if (WirePointer.kind(resolved.ref) != WirePointer.LIST) { throw new DecodeException("Message contains non-list pointer where text was expected."); } - if (ListPointer.elementSize(ref) != FieldSize.BYTE) { + if (ListPointer.elementSize(resolved.ref) != FieldSize.BYTE) { throw new DecodeException("Message contains list pointer of non-bytes where text was expected."); } // TODO bounds check? - if (size == 0 || segment.buffer.get(8 * ptrOffset + size - 1) != 0) { + if (size == 0 || resolved.segment.buffer.get(8 * resolved.ptr + size - 1) != 0) { throw new DecodeException("Message contains text that is not NUL-terminated."); } - return new Text.Reader(segment.buffer, ptrOffset, size - 1); + return new Text.Reader(resolved.segment.buffer, resolved.ptr, size - 1); } }