/// <summary> /// Copy a previously-encoded UTF-8 string value into this byte array. /// A call to this method must be preceded by a call to "encodeTag" /// or "encodeTagArray". The caller must ensure the byte array is a /// valid UTF-8 encoded string; no checking is performed. /// </summary> /// <param name="value">The byte array containing a UTF-8 string /// to be included in the output message.</param> /// <param name="offset">The offset in <paramref name="offset"/> /// where the encoded UTF-8 string begins.</param> /// <param name="length">The length of the UTF-8 encoded stirng, /// in bytes, to be written to the output message.</param> /// <returns>This builder.</returns> public BFlatBuilder encode(byte[] value, int offset, int length) { Leb128.encodeUnsigned(this, (uint)length); Array.Copy(value, offset, data, position, length); position += length; return(this); }
// Internal version just uses a "byte" as the first parameter. internal BFlatBuilder encodeTag(byte type, String tagName) { if (tagName.Length == 0) { throw new BFlatException("Zero length tags are not allowed."); } uint tagLen = (uint)tagName.Length; if (tagLen < 8) { // see if fit the tag len into the byte0 int byte0 = position++; uint actual = encodeString(tagName); if (actual < 8) { data[byte0] = (byte)(type | actual); } else { // since the tag <8 characters we know that the # of bytes // it will fit in is representable with a one byte leb128 data[byte0] = (byte)type; Array.Copy(data, byte0 + 1, data, byte0 + 2, actual); data[byte0 + 1] = (byte)actual; ++position; } } else { data[position++] = (byte)type; int start = position; int leblength = Leb128.encodeUnsigned(this, tagLen); uint actual = encodeString(tagName); if (actual != tagLen) { int end = position; position = start; int actual_leblength = Leb128.encodeUnsigned(this, actual); // do we need to reserialize the data? if (actual_leblength != leblength) { encodeString(tagName); } else { position = end; } } } return(this); }
/// <summary> /// Encode a string value into this byte array. A call to this method /// must be preceded by a call to "encodeTag" or "encodeTagArray." /// </summary> /// <param name="value">The value to encode into this array.</param> /// <returns>This builder.</returns> public BFlatBuilder encode(String value) { int charcount = value.Length; int start = position; int leblength = Leb128.encodeUnsigned(this, (uint)charcount); uint bytecount = encodeString(value); int end = position; if (bytecount != charcount) // non ascii { position = start; int actual_leblength = Leb128.encodeUnsigned(this, bytecount); if (actual_leblength != leblength) { //reserialize the string encodeString(value); } else { position = end; } } return(this); }
// Internal version of encodeTag takes a byte as the first parameter. internal BFlatBuilder encodeTag(byte type, byte[] tagName) { if (tagName.Length == 0) { throw new BFlatException("Zero length tags are not allowed."); } int tagLen = tagName.Length; if (tagLen < 8) { // fit the tag len into the byte0 data[position++] = (byte)((int)type | tagLen); Array.Copy(tagName, 0, data, position, tagLen); position += tagLen; } else { data[position++] = (byte)type; Leb128.encodeUnsigned(this, (uint)tagLen); Array.Copy(tagName, 0, data, position, tagLen); position += tagLen; } return(this); }
BFlatValue parseNext() { if (position >= _end) { return(null); } BFlatValue value = (_current != null && _current.isReuse()) ? _current.reset(data) : new BFlatValue(data); byte byte0 = data[position++]; byte type = (byte)(byte0 & BFlatEncoding.TypeMask); bool isArray = (byte0 & BFlatEncoding.ArrayMask) != 0; int tagLength = byte0 & BFlatEncoding.LengthMask; int tagStart = position; if (tagLength == 0) { tagLength = (int)(Leb128.decodeUnsigned(this)); if (tagLength == 0) { throw new BFlatException("zero-length tag", position); } tagStart = position; } value.setTag(tagStart, tagLength); position += tagLength; int dataStart = position; int elementCount = 1; if (isArray) { elementCount = (int)(Leb128.decodeUnsigned(this)); dataStart = position; } value.setData(position, byte0, elementCount); // for variable length types we have to parse the array contents switch ((BFlatEncoding.Type)type) { case BFlatEncoding.Type.String: case BFlatEncoding.Type.Binary: for (int i = 0; i < elementCount; ++i) { int length = (int)(Leb128.decodeUnsigned(this)); value.setStringOffsetAndLen(i, position, length); position += length; } break; case BFlatEncoding.Type.Leb128: for (int i = 0; i < elementCount; ++i) { long leb128 = Leb128.decodeSigned(this); value.setLeb128Value(i, leb128); } break; case BFlatEncoding.Type.Int8: position += elementCount; break; case BFlatEncoding.Type.Int16: position += elementCount * 2; break; case BFlatEncoding.Type.Int32: position += elementCount * 4; break; case BFlatEncoding.Type.Int64: case BFlatEncoding.Type.Double: case BFlatEncoding.Type.Datetime: position += elementCount * 8; break; case BFlatEncoding.Type.Null: break; default: throw new BFlatException("unknown value type", position); } return(value); }
encodeTagArray(BFlatEncoding.Type type, String tagName, int count) { encodeTag((byte)((byte)type | BFlatEncoding.ArrayMask), tagName); Leb128.encodeUnsigned(this, (uint)count); return(this); }