1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors 2 // Licensed under the MIT License: 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 22 module capnproto.StructReader; 23 24 import std.string : startsWith; 25 import std.traits; 26 27 import java.nio.ByteBuffer; 28 29 import capnproto.AnyPointer; 30 import capnproto.Constants; 31 import capnproto.Data; 32 import capnproto.ElementSize; 33 import capnproto.SegmentReader; 34 import capnproto.StructList; 35 import capnproto.Text; 36 import capnproto.WireHelpers; 37 38 struct StructReader 39 { 40 public: //Variables. 41 SegmentReader* segment; 42 int data; //Byte offset to data section. 43 int pointers; //Word offset of pointer section. 44 int dataSize; //In bits. 45 short pointerCount; 46 int nestingLimit; 47 48 public: //Methods. 49 this(SegmentReader* segment, int data, int pointers, int dataSize, short pointerCount, int nestingLimit) 50 { 51 this.segment = segment; 52 this.data = data; 53 this.pointers = pointers; 54 this.dataSize = dataSize; 55 this.pointerCount = pointerCount; 56 this.nestingLimit = nestingLimit; 57 } 58 59 bool _getBoolField(int offset) 60 { 61 if(offset < this.dataSize) 62 { 63 ubyte b = this.segment.buffer.get!ubyte(this.data + offset / 8); 64 return (b & (1 << (offset % 8))) != 0; 65 } 66 return false; 67 } 68 69 bool _getBoolField(int offset, bool mask) 70 { 71 return this._getBoolField(offset) ^ mask; 72 } 73 74 byte _getByteField(int offset) 75 { 76 if((offset + 1) * 8 <= this.dataSize) 77 return this.segment.buffer.get!byte(this.data + offset); 78 return 0; 79 } 80 81 byte _getByteField(int offset, byte mask) 82 { 83 return cast(byte)(this._getByteField(offset) ^ mask); 84 } 85 86 ubyte _getUbyteField(int offset) 87 { 88 if((offset + 1) * 8 <= this.dataSize) 89 return this.segment.buffer.get!ubyte(this.data + offset); 90 return 0; 91 } 92 93 ubyte _getUbyteField(int offset, ubyte mask) 94 { 95 return cast(ubyte)(this._getByteField(offset) ^ mask); 96 } 97 98 short _getShortField(int offset) 99 { 100 if((offset + 1) * 16 <= this.dataSize) 101 return this.segment.buffer.get!short(this.data + offset * 2); 102 return 0; 103 } 104 105 short _getShortField(int offset, short mask) 106 { 107 return cast(short)(this._getShortField(offset) ^ mask); 108 } 109 110 ushort _getUshortField(int offset) 111 { 112 if((offset + 1) * 16 <= this.dataSize) 113 return cast(ushort)this.segment.buffer.get!short(this.data + offset * 2); 114 return 0; 115 } 116 117 ushort _getUshortField(int offset, ushort mask) 118 { 119 return cast(ushort)(this._getUshortField(offset) ^ mask); 120 } 121 122 int _getIntField(int offset) 123 { 124 if((offset + 1) * 32 <= this.dataSize) 125 return this.segment.buffer.get!int(this.data + offset * 4); 126 return 0; 127 } 128 129 int _getIntField(int offset, int mask) 130 { 131 return this._getIntField(offset) ^ mask; 132 } 133 134 uint _getUintField(int offset) 135 { 136 if((offset + 1) * 32 <= this.dataSize) 137 return cast(uint)this.segment.buffer.get!int(this.data + offset * 4); 138 return 0; 139 } 140 141 uint _getUintField(int offset, uint mask) 142 { 143 return this._getUintField(offset) ^ mask; 144 } 145 146 long _getLongField(int offset) 147 { 148 if((offset + 1) * 64 <= this.dataSize) 149 return this.segment.buffer.get!long(this.data + offset * 8); 150 return 0; 151 } 152 153 long _getLongField(int offset, long mask) 154 { 155 return this._getLongField(offset) ^ mask; 156 } 157 158 ulong _getUlongField(int offset) 159 { 160 if((offset + 1) * 64 <= this.dataSize) 161 return cast(ulong)this.segment.buffer.get!long(this.data + offset * 8); 162 return 0; 163 } 164 165 ulong _getUlongField(int offset, ulong mask) 166 { 167 return this._getUlongField(offset) ^ mask; 168 } 169 170 float _getFloatField(int offset) 171 { 172 if((offset + 1) * 32 <= this.dataSize) 173 return this.segment.buffer.get!float(this.data + offset * 4); 174 return 0; 175 } 176 177 float _getFloatField(int offset, int mask) 178 { 179 if((offset + 1) * 32 <= this.dataSize) 180 return intBitsToFloat(this.segment.buffer.get!int(this.data + offset * 4) ^ mask); 181 return intBitsToFloat(mask); 182 } 183 184 double _getDoubleField(int offset) 185 { 186 if((offset + 1) * 64 <= this.dataSize) 187 return this.segment.buffer.get!double(this.data + offset * 8); 188 return 0; 189 } 190 191 double _getDoubleField(int offset, long mask) 192 { 193 if((offset + 1) * 64 <= this.dataSize) 194 return longBitsToDouble(this.segment.buffer.get!long(this.data + offset * 8) ^ mask); 195 return longBitsToDouble(mask); 196 } 197 198 bool _pointerFieldIsNull(int ptrIndex) 199 { 200 return this.segment.buffer.get!long((this.pointers + ptrIndex) * Constants.BYTES_PER_WORD) == 0; 201 } 202 203 T.Reader _getPointerField(T)(int ptrIndex) 204 { 205 alias name = fullyQualifiedName!T; 206 auto segment = cast(SegmentReader*)&SegmentReader.EMPTY; 207 int pointer = 0; 208 if(ptrIndex < this.pointerCount) 209 { 210 segment = this.segment; 211 pointer = this.pointers + ptrIndex; 212 } 213 static if(is(T : AnyPointer)) 214 return T.Reader(segment, pointer, nestingLimit); 215 else static if(is(T : Data)) 216 return WireHelpers.readDataPointer(segment, pointer, null, 0, 0); 217 else static if(is(T : Text)) 218 return WireHelpers.readTextPointer(segment, pointer, null, 0, 0); 219 else static if(name.startsWith("capnproto.DataList") || name.startsWith("capnproto.EnumList") || name.startsWith("capnproto.PrimitiveList") || name.startsWith("capnproto.ListList") || name.startsWith("capnproto.StructList") || name.startsWith("capnproto.TextList")) 220 return WireHelpers.readListPointer!(T.Reader)(segment, pointer, null, 0, T.elementSize, this.nestingLimit); 221 else 222 return WireHelpers.readStructPointer!(T.Reader)(segment, pointer, null, 0, nestingLimit); 223 } 224 225 T.Reader _getPointerField(T)(int ptrIndex, SegmentReader* defaultSegment, int defaultOffset) 226 { 227 alias name = fullyQualifiedName!T; 228 229 auto segment = cast(SegmentReader*)&SegmentReader.EMPTY; 230 int pointer = 0; 231 if(ptrIndex < this.pointerCount) 232 { 233 segment = this.segment; 234 pointer = this.pointers + ptrIndex; 235 } 236 static if(name.startsWith("capnproto.DataList") || name.startsWith("capnproto.EnumList") || name.startsWith("capnproto.PrimitiveList") || name.startsWith("capnproto.ListList") || name.startsWith("capnproto.StructList") || name.startsWith("capnproto.TextList")) 237 return WireHelpers.readListPointer!(T.Reader)(segment, pointer, defaultSegment, defaultOffset, T.elementSize, this.nestingLimit); 238 else 239 return WireHelpers.readStructPointer!(T.Reader)(segment, pointer, defaultSegment, defaultOffset, this.nestingLimit); 240 } 241 242 StructList.Reader!(T.Reader) _getPointerListField(T)(int ptrIndex, SegmentReader* defaultSegment, int defaultOffset) 243 { 244 if(ptrIndex < this.pointerCount) 245 return WireHelpers.readListPointer!(StructList.Reader!(T.Reader))(this.segment, this.pointers + ptrIndex, defaultSegment, defaultOffset, ElementSize.INLINE_COMPOSITE, this.nestingLimit); 246 return WireHelpers.readListPointer!(StructList.Reader!(T.Reader))(cast(SegmentReader*)&SegmentReader.EMPTY, 0, defaultSegment, defaultOffset, ElementSize.INLINE_COMPOSITE, this.nestingLimit); 247 } 248 249 T.Reader _getPointerField(T)(int ptrIndex, ByteBuffer* defaultBuffer, int defaultOffset, int defaultSize) 250 { 251 auto segment = cast(SegmentReader*)&SegmentReader.EMPTY; 252 int pointer = 0; 253 if(ptrIndex < this.pointerCount) 254 { 255 segment = this.segment; 256 pointer = this.pointers + ptrIndex; 257 } 258 259 static if(is(T : Data)) 260 return WireHelpers.readDataPointer(segment, pointer, defaultBuffer, defaultOffset, defaultSize); 261 else static if(is(T : Text)) 262 return WireHelpers.readTextPointer(segment, pointer, defaultBuffer, defaultOffset, defaultSize); 263 else 264 static assert(0); 265 } 266 }