/**
* 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();
}
}
}