//Return the offset for the nth member from an Array or Object type int GetNthOffset(int index) { int offset; byte head = TypeCode; if (head == 0x13 || head == 0x14) { // compact Array or Object offset = GetNthOffsetFromCompact(index); } else if (head == 0x01 || head == 0x0a) { // special case: empty Array or empty Object throw new IndexOutOfRangeException(); } else { long n; int offsetsize = ObjectArrayUtil.GetOffsetSize(head); long end = NumberUtil.ToLong(vpack, start + 1, offsetsize); int dataOffset = FindDataOffset(); if (head <= 0x05) { // array with no offset table or length VPackSlice first = new VPackSlice(vpack, start + dataOffset); n = (end - dataOffset) / first.GetByteSize(); } else if (offsetsize < 8) { n = NumberUtil.ToLong(vpack, start + 1 + offsetsize, offsetsize); } else { n = NumberUtil.ToLong(vpack, (int)(start + end - offsetsize), offsetsize); } if (index >= n) { throw new IndexOutOfRangeException(); } if (head <= 0x05 || n == 1) { // no index table, but all array items have the same length // or only one item is in the array // now fetch first item and determine its length if (dataOffset == 0) { dataOffset = FindDataOffset(); } offset = dataOffset + index * new VPackSlice(vpack, start + dataOffset).GetByteSize(); } else { long ieBase = end - n * offsetsize + index * offsetsize - (offsetsize == 8 ? 8 : 0); offset = (int)NumberUtil.ToLong(vpack, (int)(start + ieBase), offsetsize); } } return(offset); }
/// <exception cref="VPackException"/> public virtual VPackSlice Get(string attribute) { if (!this.IsObject) { throw new VPackValueTypeException(ValueType.OBJECT); } byte head = Head; VPackSlice result = new VPackSlice(); if (head == 0x0a) { // special case, empty object result = new VPackSlice(); } else { if (head == 0x14) { // compact Object result = this.GetFromCompactObject(attribute); } else { int offsetsize = ObjectArrayUtil.GetOffsetSize(head); long end = NumberUtil.ToLong(this.vpack, this.start + 1, offsetsize); long n; if (offsetsize < 8) { n = NumberUtil.ToLong(this.vpack, this.start + 1 + offsetsize, offsetsize); } else { n = NumberUtil.ToLong(this.vpack, (int)(this.start + end - offsetsize), offsetsize); } if (n == 1) { // Just one attribute, there is no index table! VPackSlice key = new VPackSlice(this.vpack, this.start + this.FindDataOffset()); if (key.IsString) { if (key.IsEqualString(attribute)) { result = new VPackSlice(this.vpack, key.start + key.ByteSize); } else { // no match result = new VPackSlice(); } } else { if (key.IsInteger) { // translate key if (attributeTranslator == null) { throw new VPackNeedAttributeTranslatorException(); } if (key.TranslateUnchecked().IsEqualString(attribute)) { result = new VPackSlice(this.vpack, key.start + key.ByteSize); } else { // no match result = new VPackSlice(); } } else { // no match result = new VPackSlice(); } } } else { long ieBase = end - n * offsetsize - (offsetsize == 8 ? 8 : 0); // only use binary search for attributes if we have at least // this many entries // otherwise we'll always use the linear search long sortedSearchEntriesThreshold = 4; bool sorted = head >= 0x0b && (sbyte)head <= 0x0e; if (sorted && n >= sortedSearchEntriesThreshold) { // This means, we have to handle the special case n == 1 // only in the linear search! result = this.SearchObjectKeyBinary(attribute, ieBase, offsetsize, n); } else { result = this.SearchObjectKeyLinear(attribute, ieBase, offsetsize, n); } } } } return(result); }
internal int GetByteSize() { long size; byte head = TypeCode; int valueLength = ValueLengthUtil.Get(head); if (valueLength != 0) { size = valueLength; } else { switch (Type) { case SliceType.Array: case SliceType.Object: if (head == 0x13 || head == 0x14) { // compact Array or Object size = NumberUtil.ReadVariableValueLength(vpack, start + 1, false); } else /* if (head <= 0x14) */ { size = NumberUtil.ToLong(vpack, start + 1, ObjectArrayUtil.GetOffsetSize(head)); } break; case SliceType.String: // long UTF-8 String size = GetLongStringLength() + 1 + 8; break; case SliceType.Binary: size = 1 + head - ((byte)0xbf) + GetBinaryLengthUnchecked(); break; case SliceType.Bcd: if (head <= 0xcf) { size = 1 + head + ((byte)0xc7) + NumberUtil.ToLong(vpack, start + 1, head - ((byte)0xc7)); } else { size = 1 + head - ((byte)0xcf) + NumberUtil.ToLong(vpack, start + 1, head - ((byte)0xcf)); } break; case SliceType.Custom: if (head == 0xf4 || head == 0xf5 || head == 0xf6) { size = 2 + NumberUtil.ToLong(vpack, start + 1, 1); } else if (head == 0xf7 || head == 0xf8 || head == 0xf9) { size = 3 + NumberUtil.ToLong(vpack, start + 1, 2); } else if (head == 0xfa || head == 0xfb || head == 0xfc) { size = 5 + NumberUtil.ToLong(vpack, start + 1, 4); } else /* if (head == 0xfd || head == 0xfe || head == 0xff) */ { size = 9 + NumberUtil.ToLong(vpack, start + 1, 8); } break; default: // TODO throw new Exception("Internal error"); } } return((int)size); }