/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.IO; namespace Avro.IO { /// /// Decoder for Avro binary format /// public class BinaryDecoder : Decoder { private readonly Stream stream; public BinaryDecoder(Stream stream) { this.stream = stream; } /// /// null is written as zero bytes /// public void ReadNull() { } /// /// a boolean is written as a single byte /// whose value is either 0 (false) or 1 (true). /// /// public bool ReadBoolean() { byte b = read(); if (b == 0) return false; if (b == 1) return true; throw new AvroException("Not a boolean value in the stream: " + b); } /// /// int and long values are written using variable-length, zig-zag coding. /// /// /// public int ReadInt() { return (int)ReadLong(); } /// /// int and long values are written using variable-length, zig-zag coding. /// /// /// public long ReadLong() { byte b = read(); ulong n = b & 0x7FUL; int shift = 7; while ((b & 0x80) != 0) { b = read(); n |= (b & 0x7FUL) << shift; shift += 7; } long value = (long)n; return (-(value & 0x01L)) ^ ((value >> 1) & 0x7fffffffffffffffL); } /// /// A float is written as 4 bytes. /// The float is converted into a 32-bit integer using a method equivalent to /// Java's floatToIntBits and then encoded in little-endian format. /// /// public float ReadFloat() { byte[] buffer = read(4); if (!BitConverter.IsLittleEndian) Array.Reverse(buffer); return BitConverter.ToSingle(buffer, 0); //int bits = (Stream.ReadByte() & 0xff | //(Stream.ReadByte()) & 0xff << 8 | //(Stream.ReadByte()) & 0xff << 16 | //(Stream.ReadByte()) & 0xff << 24); //return intBitsToFloat(bits); } /// /// A double is written as 8 bytes. /// The double is converted into a 64-bit integer using a method equivalent to /// Java's doubleToLongBits and then encoded in little-endian format. /// /// /// public double ReadDouble() { long bits = (stream.ReadByte() & 0xffL) | (stream.ReadByte() & 0xffL) << 8 | (stream.ReadByte() & 0xffL) << 16 | (stream.ReadByte() & 0xffL) << 24 | (stream.ReadByte() & 0xffL) << 32 | (stream.ReadByte() & 0xffL) << 40 | (stream.ReadByte() & 0xffL) << 48 | (stream.ReadByte() & 0xffL) << 56; return BitConverter.Int64BitsToDouble(bits); } /// /// Bytes are encoded as a long followed by that many bytes of data. /// /// public byte[] ReadBytes() { return read(ReadLong()); } public string ReadString() { int length = ReadInt(); byte[] buffer = new byte[length]; //TODO: Fix this because it's lame; ReadFixed(buffer); return System.Text.Encoding.UTF8.GetString(buffer); } public int ReadEnum() { return ReadInt(); } public long ReadArrayStart() { return doReadItemCount(); } public long ReadArrayNext() { return doReadItemCount(); } public long ReadMapStart() { return doReadItemCount(); } public long ReadMapNext() { return doReadItemCount(); } public int ReadUnionIndex() { return ReadInt(); } public void ReadFixed(byte[] buffer) { ReadFixed(buffer, 0, buffer.Length); } public void ReadFixed(byte[] buffer, int start, int length) { Read(buffer, start, length); } public void SkipNull() { ReadNull(); } public void SkipBoolean() { ReadBoolean(); } public void SkipInt() { ReadInt(); } public void SkipLong() { ReadLong(); } public void SkipFloat() { Skip(4); } public void SkipDouble() { Skip(8); } public void SkipBytes() { Skip(ReadLong()); } public void SkipString() { SkipBytes(); } public void SkipEnum() { ReadLong(); } public void SkipUnionIndex() { ReadLong(); } public void SkipFixed(int len) { Skip(len); } // Read p bytes into a new byte buffer private byte[] read(long p) { byte[] buffer = new byte[p]; Read(buffer, 0, buffer.Length); return buffer; } private static float intBitsToFloat(int value) { return BitConverter.ToSingle(BitConverter.GetBytes(value), 0); } private byte read() { int n = stream.ReadByte(); if (n >= 0) return (byte)n; throw new AvroException("End of stream reached"); } private void Read(byte[] buffer, int start, int len) { while (len > 0) { int n = stream.Read(buffer, start, len); if (n <= 0) throw new AvroException("End of stream reached"); start += n; len -= n; } } private long doReadItemCount() { long result = ReadLong(); if (result < 0) { ReadLong(); // Consume byte-count if present result = -result; } return result; } private void Skip(int p) { stream.Seek(p, SeekOrigin.Current); } private void Skip(long p) { stream.Seek(p, SeekOrigin.Current); } internal void skip(long block_size) { throw new NotImplementedException(); } } }