You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by cu...@apache.org on 2011/03/31 23:16:49 UTC

svn commit: r1087439 [2/6] - in /avro/trunk: ./ lang/csharp/ lang/csharp/lib/ lang/csharp/lib/main/ lang/csharp/lib/test/ lang/csharp/src/ lang/csharp/src/apache/ lang/csharp/src/apache/codegen/ lang/csharp/src/apache/codegen/Properties/ lang/csharp/sr...

Added: avro/trunk/lang/csharp/src/apache/main/Generic/DatumReader.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Generic/DatumReader.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Generic/DatumReader.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Generic/DatumReader.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,325 @@
+/**
+ * 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 Avro.IO;
+
+namespace Avro.Generic
+{
+    public interface DatumReader<T>
+    {
+        Schema ReaderSchema { get; }
+        Schema WriterSchema { get; }
+
+        /// <summary>
+        /// Read a datum.  Traverse the schema, depth-first, reading all leaf values
+        /// in the schema into a datum that is returned.  If the provided datum is
+        /// non-null it may be reused and returned.
+        /// </summary>        
+        T Read(T reuse, Decoder decoder);
+    }
+
+    ///// <summary>
+    ///// Deserialize Avro-encoded data into a .net data structure.
+    ///// </summary>
+    //public class DatumReader
+    //{
+    //    public Schema WriterSchema { get; private set; }
+    //    public Schema ReaderSchema { get; private set; }
+
+    //    /// <summary>
+    //    /// As defined in the Avro specification, we call the schema encoded
+    //    /// in the data the "writer's schema", and the schema expected by the
+    //    /// reader the "reader's schema".
+    //    /// </summary>
+    //    /// <param name="writerSchema"></param>
+    //    /// <param name="readerSchema"></param>
+    //    public DatumReader(Schema writerSchema, Schema readerSchema)
+    //    {
+    //        if (null == writerSchema) throw new ArgumentNullException("writerSchema", "writerSchema cannot be null.");
+    //        if (null == readerSchema) throw new ArgumentNullException("readerSchema", "readerSchema cannot be null.");
+
+    //        this.WriterSchema = writerSchema;
+    //        this.ReaderSchema = readerSchema;
+    //    }
+
+
+    //    static bool checkProps(Schema a, Schema b, params string[] props)
+    //    {
+    //        foreach (string prop in props)
+    //        {
+    //            if (!string.Equals(a[prop], b[prop]))
+    //                return false;
+    //        }
+
+    //        return true;
+    //    }
+    //    //static bool CheckProps(Schema schema_one, Schema schema_two, IEnumerable<string> props)
+    //    //{
+
+    //    //}
+
+    //    static bool matchSchemas(Schema writers_schema, Schema readers_schema)
+    //    {
+    //        string w_type = writers_schema.Type, r_type = readers_schema.Type;
+
+    //        if (string.Equals(Schema.UNION, w_type) || string.Equals(Schema.UNION, r_type))
+    //            return true;
+    //        else if (PrimitiveSchema.PrimitiveKeyLookup.ContainsKey(w_type) && PrimitiveSchema.PrimitiveKeyLookup.ContainsKey(r_type) && w_type == r_type)
+    //            return true;
+    //        else if (w_type == Schema.RECORD && r_type == Schema.RECORD && DatumReader.checkProps(writers_schema, readers_schema, "fullname"))
+    //            return true;
+    //        else if (w_type == "error" && r_type == "error" && DatumReader.checkProps(writers_schema, readers_schema, "fullname"))
+    //            return true;
+    //        else if (w_type == "request" && r_type == "request")
+    //            return true;
+    //        else if (w_type == Schema.FIXED && r_type == Schema.FIXED && DatumReader.checkProps(writers_schema, readers_schema, "fullname", "size"))
+    //            return true;
+    //        else if (w_type == Schema.ENUM && r_type == Schema.ENUM && DatumReader.checkProps(writers_schema, readers_schema, "fullname"))
+    //            return true;
+    //        //else if (w_type == Schema.MAP && r_type == Schema.MAP && DatumReader.CheckProps(writers_schema.values, readers_schema.values, "type"))
+    //        //    return true;
+    //        //else if (w_type == Schema.ARRAY && r_type == Schema.ARRAY && DatumReader.check_props(writers_schema.items, readers_schema.items, "type"))
+    //        //    return true;
+    //        else if (w_type == Schema.INT && Util.checkIsValue(r_type, Schema.LONG, Schema.FLOAT, Schema.DOUBLE))
+    //            return true;
+    //        else if (w_type == Schema.LONG && Util.checkIsValue(r_type, Schema.FLOAT, Schema.DOUBLE))
+    //            return true;
+    //        else if (w_type == Schema.FLOAT && r_type == Schema.DOUBLE)
+    //            return true;
+
+    //        if (Util.checkIsValue(w_type, Schema.MAP, Schema.ARRAY))
+    //            throw new NotImplementedException(w_type);
+
+    //        return false;
+    //    }
+
+    //    public object Read(BinaryDecoder decoder)
+    //    {
+    //        if (null == this.ReaderSchema)
+    //            this.ReaderSchema = this.WriterSchema;
+
+    //        return ReadData(this.WriterSchema, this.ReaderSchema, decoder);
+
+    //    }
+
+    //    private object ReadData(Schema writers_schema, Schema readers_schema, BinaryDecoder decoder)
+    //    {
+    //        if (!matchSchemas(writers_schema, readers_schema))
+    //            throw new SchemaResolutionException("Schemas do not match.", writers_schema, readers_schema);
+
+    //        if (writers_schema.Type != Schema.UNION && readers_schema.Type == Schema.UNION)
+    //        {
+    //            foreach (Schema s in ((UnionSchema)readers_schema).Schemas)
+    //            {
+    //                if (DatumReader.matchSchemas(writers_schema, s))
+    //                {
+    //                    return ReadData(writers_schema, s, decoder);
+    //                }
+    //            }
+
+    //            throw new SchemaResolutionException("Schemas do not match.", writers_schema, readers_schema);
+    //        }
+
+    //        if (writers_schema.Type == Schema.NULL)
+    //            return decoder.ReadNull();
+    //        else if (writers_schema.Type == Schema.BOOLEAN)
+    //            return decoder.ReadBool();
+    //        else if (writers_schema.Type == Schema.STRING)
+    //            return decoder.ReadUTF8();
+    //        else if (writers_schema.Type == Schema.INT)
+    //            return decoder.ReadInt();
+    //        else if (writers_schema.Type == Schema.LONG)
+    //            return decoder.ReadLong();
+    //        else if (writers_schema.Type == Schema.FLOAT)
+    //            return decoder.ReadFloat();
+    //        else if (writers_schema.Type == Schema.DOUBLE)
+    //            return decoder.ReadDouble();
+    //        else if (writers_schema.Type == Schema.BYTES)
+    //            return decoder.ReadBytes();
+    //        else if (writers_schema.Type == Schema.FIXED)
+    //            return ReadFixed(writers_schema, readers_schema, decoder);
+    //        else if (writers_schema.Type == Schema.ENUM)
+    //            return ReadEnum(writers_schema, readers_schema, decoder);
+    //        else if (writers_schema.Type == Schema.ARRAY)
+    //            return ReadArray(writers_schema, readers_schema, decoder);
+    //        else if (writers_schema.Type == Schema.MAP)
+    //            return ReadMap(writers_schema, readers_schema, decoder);
+    //        else if (writers_schema.Type == Schema.UNION)
+    //            return ReadUnion(writers_schema, readers_schema, decoder);
+    //        else if (Util.checkIsValue(writers_schema.Type, Schema.RECORD, "error", "request"))
+    //            return ReadRecord(writers_schema, readers_schema, decoder);
+    //        else
+    //            throw new AvroException("Cannot Read unknown type type) " + writers_schema.Type);
+    //    }
+
+    //    public void SkipData(Schema writers_schema, BinaryDecoder decoder)
+    //    {
+    //        if (writers_schema.Type == Schema.NULL)
+    //            decoder.SkipNull();
+    //        else if (writers_schema.Type == Schema.BOOLEAN)
+    //            decoder.SkipBoolean();
+    //        else if (writers_schema.Type == Schema.STRING)
+    //            decoder.SkipUTF8();
+    //        else if (writers_schema.Type == Schema.INT)
+    //            decoder.SkipInt();
+    //        else if (writers_schema.Type == Schema.LONG)
+    //            decoder.SkipLong();
+    //        else if (writers_schema.Type == Schema.FLOAT)
+    //            decoder.SkipFloat();
+    //        else if (writers_schema.Type == Schema.DOUBLE)
+    //            decoder.SkipDouble();
+    //        else if (writers_schema.Type == Schema.BYTES)
+    //            decoder.ReadBytes();
+    //        else if (writers_schema.Type == Schema.FIXED)
+    //            SkipFixed(writers_schema as FixedSchema, decoder);
+    //        else if (writers_schema.Type == Schema.ENUM)
+    //            SkipEnum(writers_schema, decoder);
+    //        else if (writers_schema.Type == Schema.ARRAY)
+    //            SkipArray(writers_schema as ArraySchema, decoder);
+    //        else if (writers_schema.Type == Schema.MAP)
+    //            SkipMap(writers_schema as MapSchema, decoder);
+    //        else if (writers_schema.Type == Schema.UNION)
+    //            SkipUnion(writers_schema as UnionSchema, decoder);
+    //        else if (Util.checkIsValue(writers_schema.Type, Schema.RECORD, "error", "request"))
+    //            SkipRecord(writers_schema as RecordSchema, decoder);
+    //        else
+    //            throw new AvroException("Unknown type type: %s" + writers_schema.Type);
+
+    //    }
+
+    //    private void SkipRecord(RecordSchema writers_schema, BinaryDecoder decoder)
+    //    {
+    //        foreach (Field field in writers_schema.Fields)
+    //            SkipData(field.Schema, decoder);
+    //    }
+
+    //    private void SkipUnion(UnionSchema writers_schema, BinaryDecoder decoder)
+    //    {
+    //        int index_of_schema = (int)decoder.ReadLong();
+    //        SkipData(writers_schema.Schemas[index_of_schema], decoder);
+    //    }
+
+    //    private void SkipMap(MapSchema writers_schema, BinaryDecoder decoder)
+    //    {
+    //        long block_count = decoder.ReadLong();
+    //        while (block_count != 0)
+    //        {
+    //            if (block_count < 0)
+    //            {
+    //                long block_size = decoder.ReadLong();
+    //                decoder.skip(block_size);
+    //            }
+    //            else
+    //            {
+    //                for (int i = 0; i < block_count; i++)
+    //                {
+    //                    decoder.SkipUTF8();
+    //                    SkipData(writers_schema.Values, decoder);
+    //                    block_count = decoder.ReadLong();
+    //                }
+    //            }
+    //        }
+    //    }
+
+    //    private void SkipArray(ArraySchema writers_schema, BinaryDecoder decoder)
+    //    {
+    //        long block_count = decoder.ReadLong();
+    //        while (block_count != 0)
+    //        {
+    //            if (block_count < 0)
+    //            {
+    //                long block_size = decoder.ReadLong();
+    //                decoder.skip(block_size);
+    //            }
+    //            else
+    //            {
+    //                for (int i = 0; i < block_count; i++)
+    //                {
+    //                    decoder.SkipUTF8();
+    //                    SkipData(writers_schema.Items, decoder);
+    //                    block_count = decoder.ReadLong();
+    //                }
+    //            }
+    //        }
+    //    }
+
+    //    private void SkipEnum(Schema writers_schema, BinaryDecoder decoder)
+    //    {
+    //        decoder.SkipInt();
+    //    }
+
+    //    private void SkipFixed(FixedSchema writers_schema, BinaryDecoder decoder)
+    //    {
+    //        decoder.skip(writers_schema.Size);
+    //    }
+
+    //    /// <summary>
+    //    /// A record is encoded by encoding the values of its fields
+    //    /// in the order that they are declared. In other words, a record
+    //    /// is encoded as just the concatenation of the encodings of its fields.
+    //    /// Field values are encoded per their schema.
+
+    //    /// Schema Resolution:
+    //    ///  * the ordering of fields may be different: fields are matched by name.
+    //    ///  * schemas for fields with the same name in both records are resolved
+    //    ///    recursively.
+    //    ///  * if the writer's record contains a field with a name not present in the
+    //    ///    reader's record, the writer's value for that field is ignored.
+    //    ///  * if the reader's record schema has a field that contains a default value,
+    //    ///    and writer's schema does not have a field with the same name, then the
+    //    ///    reader should use the default value from its field.
+    //    ///  * if the reader's record schema has a field with no default value, and 
+    //    ///    writer's schema does not have a field with the same name, then the
+    //    ///    field's value is unset.
+    //    /// </summary>
+    //    /// <param name="writers_schema"></param>
+    //    /// <param name="readers_schema"></param>
+    //    /// <param name="decoder"></param>
+    //    /// <returns></returns>
+    //    private object ReadRecord(Schema writers_schema, Schema readers_schema, BinaryDecoder decoder)
+    //    {
+    //        throw new NotImplementedException();
+    //    }
+
+    //    private object ReadUnion(Schema writers_schema, Schema readers_schema, BinaryDecoder decoder)
+    //    {
+    //        throw new NotImplementedException();
+    //    }
+
+    //    private object ReadMap(Schema writers_schema, Schema readers_schema, BinaryDecoder decoder)
+    //    {
+    //        throw new NotImplementedException();
+    //    }
+
+    //    private object ReadArray(Schema writers_schema, Schema readers_schema, BinaryDecoder decoder)
+    //    {
+    //        throw new NotImplementedException();
+    //    }
+
+    //    private object ReadEnum(Schema writers_schema, Schema readers_schema, BinaryDecoder decoder)
+    //    {
+    //        throw new NotImplementedException();
+    //    }
+
+    //    private object ReadFixed(Schema writers_schema, Schema readers_schema, BinaryDecoder decoder)
+    //    {
+    //        throw new NotImplementedException();
+    //    }
+    //}
+}

Added: avro/trunk/lang/csharp/src/apache/main/Generic/DatumWriter.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Generic/DatumWriter.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Generic/DatumWriter.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Generic/DatumWriter.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,28 @@
+/**
+ * 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 Avro.IO;
+
+namespace Avro.Generic
+{
+    public interface DatumWriter<T>
+    {
+        Schema Schema { get; }
+        void Write(T datum, Encoder encoder);
+    }
+}

Added: avro/trunk/lang/csharp/src/apache/main/Generic/GenericEnum.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Generic/GenericEnum.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Generic/GenericEnum.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Generic/GenericEnum.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,63 @@
+/**
+ * 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.Text;
+
+namespace Avro.Generic
+{
+    /// <summary>
+    /// The defualt class to hold values for enum schema in GenericReader and GenericWriter.
+    /// </summary>
+    public class GenericEnum
+    {
+        public EnumSchema Schema { get; private set; }
+        private string value;
+        public string Value {
+            get { return value; }
+            set
+            {
+                if (! Schema.Contains(value)) throw new AvroException("Unknown value for enum: " + value + "(" + Schema + ")");
+                this.value = value;
+            }
+        }
+
+        public GenericEnum(EnumSchema schema, string value)
+        {
+            this.Schema = schema;
+            this.Value = value;
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (obj == this) return true;
+            return (obj != null && obj is GenericEnum) ? Value.Equals((obj as GenericEnum).Value) : false;
+        }
+
+        public override int GetHashCode()
+        {
+            return 17 * Value.GetHashCode();
+        }
+
+        public override string ToString()
+        {
+            return "Schema: " + Schema + ", value: " + Value;
+        }
+
+    }
+}

Added: avro/trunk/lang/csharp/src/apache/main/Generic/GenericFixed.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Generic/GenericFixed.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Generic/GenericFixed.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Generic/GenericFixed.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,109 @@
+/**
+ * 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.Linq;
+using System.Text;
+
+namespace Avro.Generic
+{
+    /// <summary>
+    /// The default type used by GenericReader and GenericWriter for objects for FixedSchema
+    /// </summary>
+    public class GenericFixed
+    {
+        protected readonly byte[] value;
+        private FixedSchema schema;
+
+        public FixedSchema Schema
+        {
+            get
+            {
+                return schema;
+            }
+
+            set
+            {
+                if (!(value is FixedSchema))
+                    throw new AvroException("Schema " + value.Name + " in set is not FixedSchema");
+
+                if ((value as FixedSchema).Size != this.value.Length)
+                    throw new AvroException("Schema " + value.Name + " Size " + (value as FixedSchema).Size + "is not equal to bytes length " + this.value.Length);
+
+                schema = value;
+            }
+        }
+
+        public GenericFixed(FixedSchema schema)
+        {
+            value = new byte[schema.Size];
+            this.Schema = schema;
+        }
+
+        public GenericFixed(FixedSchema schema, byte[] value)
+        {
+            this.value = new byte[schema.Size];
+            this.Schema = schema;
+            Value = value;
+        }
+
+        protected GenericFixed(uint size) 
+        {
+            this.value = new byte[size];
+        }
+
+        public byte[] Value
+        {
+            get { return this.value; }
+            set
+            {
+                if (value.Length == this.value.Length)
+                {
+                    Array.Copy(value, this.value, value.Length);
+                    return;
+                }
+                throw new AvroException("Invalid length for fixed: " + value.Length + ", (" + Schema + ")");
+            }
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (this == obj) return true;
+            if (obj != null && obj is GenericFixed)
+            {
+                GenericFixed that = obj as GenericFixed;
+                if (that.Schema.Equals(this.Schema))
+                {
+                    for (int i = 0; i < value.Length; i++) if (this.value[i] != that.value[i]) return false;
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public override int GetHashCode()
+        {
+            int result = Schema.GetHashCode();
+            foreach (byte b in value)
+            {
+                result += 23 * b;
+            }
+            return result;
+        }
+    }
+}

Added: avro/trunk/lang/csharp/src/apache/main/Generic/GenericReader.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Generic/GenericReader.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Generic/GenericReader.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Generic/GenericReader.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,632 @@
+/**
+ * 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 Avro.IO;
+using System.IO;
+
+namespace Avro.Generic
+{
+    public delegate T Reader<T>();
+
+    /// <summary>
+    /// A general purpose reader of data from avro streams. This can optionally resolve if the reader's and writer's
+    /// schemas are different. This class is a wrapper around DefaultReader and offers a little more type safety. The default reader
+    /// has the flexibility to return any type of object for each read call because the Read() method is generic. This
+    /// class on the other hand can only return a single type because the type is a parameter to the class. Any
+    /// user defined extension should, however, be done to DefaultReader. This class is sealed.
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    public sealed class GenericReader<T> : DatumReader<T>
+    {
+        private readonly DefaultReader reader;
+
+        /// <summary>
+        /// Constructs a generic reader for the given schemas using the DefaultReader. If the
+        /// reader's and writer's schemas are different this class performs the resolution.
+        /// </summary>
+        /// <param name="writerSchema">The schema used while generating the data</param>
+        /// <param name="readerSchema">The schema desired by the reader</param>
+        public GenericReader(Schema writerSchema, Schema readerSchema)
+            : this(new DefaultReader(writerSchema, readerSchema))
+        {
+        }
+
+        /// <summary>
+        /// Constructs a generic reader by directly using the given DefaultReader
+        /// </summary>
+        /// <param name="reader">The actual reader to use</param>
+        public GenericReader(DefaultReader reader)
+        {
+            this.reader = reader;
+        }
+
+        public Schema WriterSchema { get { return reader.WriterSchema; } }
+
+        public Schema ReaderSchema { get { return reader.ReaderSchema; } }
+
+        public T Read(T reuse, Decoder d)
+        {
+            return reader.Read(reuse, d);
+        }
+    }
+
+    /// <summary>
+    /// The default implementation for the generic reader. It constructs new .NET objects for avro objects on the
+    /// stream and returns the .NET object. Users can directly use this class or, if they want to customize the
+    /// object types for differnt Avro schema types, can derive from this class. There are enough hooks in this
+    /// class to allow customization.
+    /// </summary>
+    /// <remarks>
+    /// <list type="table">
+    /// <listheader><term>Avro Type</term><description>.NET Type</description></listheader>
+    /// <item><term>null</term><description>null reference</description></item>
+    /// </list>
+    /// </remarks>
+    public class DefaultReader
+    {
+        public Schema ReaderSchema { get; private set; }
+        public Schema WriterSchema { get; private set; }
+
+
+        /// <summary>
+        /// Constructs the default reader for the given schemas using the DefaultReader. If the
+        /// reader's and writer's schemas are different this class performs the resolution.
+        /// This default implemenation maps Avro types to .NET types as follows:
+        /// </summary>
+        /// <param name="writerSchema">The schema used while generating the data</param>
+        /// <param name="readerSchema">The schema desired by the reader</param>
+        public DefaultReader(Schema writerSchema, Schema readerSchema)
+        {
+            this.ReaderSchema = readerSchema;
+            this.WriterSchema = writerSchema;
+        }
+
+        /// <summary>
+        /// Reads an object off the stream.
+        /// </summary>
+        /// <typeparam name="T">The type of object to read. A single schema typically returns an object of a single .NET class.
+        /// The only exception is UnionSchema, which can return a object of different types based on the branch selected.
+        /// </typeparam>
+        /// <param name="reuse">If not null, the implemenation will try to use to return the object</param>
+        /// <param name="decoder">The decoder for deserialization</param>
+        /// <returns></returns>
+        public T Read<T>(T reuse, Decoder decoder)
+        {
+            if (!ReaderSchema.CanRead(WriterSchema))
+                throw new AvroException("Schema mismatch. Reader: " + ReaderSchema + ", writer: " + WriterSchema);
+
+            return (T)Read(reuse, WriterSchema, ReaderSchema, decoder);
+        }
+
+        public object Read(object reuse, Schema writerSchema, Schema readerSchema, Decoder d)
+        {
+            if (readerSchema.Tag == Schema.Type.Union && writerSchema.Tag != Schema.Type.Union)
+            {
+                readerSchema = findBranch(readerSchema as UnionSchema, writerSchema);
+            }
+            /*
+            if (!readerSchema.CanRead(writerSchema))
+            {
+                throw new AvroException("Schema mismatch. Reader: " + readerSchema + ", writer: " + writerSchema);
+            }
+            */
+            switch (writerSchema.Tag)
+            {
+                case Schema.Type.Null:
+                    return ReadNull(readerSchema, d);
+                case Schema.Type.Boolean:
+                    return Read<bool>(writerSchema.Tag, readerSchema, d.ReadBoolean);
+                case Schema.Type.Int:
+                    {
+                        int i = Read<int>(writerSchema.Tag, readerSchema, d.ReadInt);
+                        switch (readerSchema.Tag)
+                        {
+                            case Schema.Type.Long:
+                                return (long)i;
+                            case Schema.Type.Float:
+                                return (float)i;
+                            case Schema.Type.Double:
+                                return (double)i;
+                            default:
+                                return i;
+                        }
+                    }
+                case Schema.Type.Long:
+                    {
+                        long l = Read<long>(writerSchema.Tag, readerSchema, d.ReadLong);
+                        switch (readerSchema.Tag)
+                        {
+                            case Schema.Type.Float:
+                                return (float)l;
+                            case Schema.Type.Double:
+                                return (double)l;
+                            default:
+                                return l;
+                        }
+                    }
+                case Schema.Type.Float:
+                    {
+                        float f = Read<float>(writerSchema.Tag, readerSchema, d.ReadFloat);
+                        switch (readerSchema.Tag)
+                        {
+                            case Schema.Type.Double:
+                                return (double)f;
+                            default:
+                                return f;
+                        }
+                    }
+                case Schema.Type.Double:
+                    return Read<double>(writerSchema.Tag, readerSchema, d.ReadDouble);
+                case Schema.Type.String:
+                    return Read<string>(writerSchema.Tag, readerSchema, d.ReadString);
+                case Schema.Type.Bytes:
+                    return Read<byte[]>(writerSchema.Tag, readerSchema, d.ReadBytes);
+                case Schema.Type.Record:
+                    return ReadRecord(reuse, (RecordSchema)writerSchema, readerSchema, d);
+                case Schema.Type.Enumeration:
+                    return ReadEnum(reuse, (EnumSchema)writerSchema, readerSchema, d);
+                case Schema.Type.Fixed:
+                    return ReadFixed(reuse, (FixedSchema)writerSchema, readerSchema, d);
+                case Schema.Type.Array:
+                    return ReadArray(reuse, (ArraySchema)writerSchema, readerSchema, d);
+                case Schema.Type.Map:
+                    return ReadMap(reuse, (MapSchema)writerSchema, readerSchema, d);
+                case Schema.Type.Union:
+                    return ReadUnion(reuse, (UnionSchema)writerSchema, readerSchema, d);
+                default:
+                    throw new AvroException("Unknown schema type: " + writerSchema);
+            }
+        }
+
+        /// <summary>
+        /// Deserializes a null from the stream.
+        /// </summary>
+        /// <param name="readerSchema">Reader's schema, which should be a NullSchema</param>
+        /// <param name="d">The decoder for deserialization</param>
+        /// <returns></returns>
+        protected virtual object ReadNull(Schema readerSchema, Decoder d)
+        {
+            d.ReadNull();
+            return null;
+        }
+
+        /// <summary>
+        /// A generic function to read primitive types
+        /// </summary>
+        /// <typeparam name="S">The .NET type to read</typeparam>
+        /// <param name="tag">The Avro type tag for the object on the stream</param>
+        /// <param name="readerSchema">A schema compatible to the Avro type</param>
+        /// <param name="reader">A function that can read the avro type from the stream</param>
+        /// <returns>The primitive type just read</returns>
+        protected S Read<S>(Schema.Type tag, Schema readerSchema, Reader<S> reader)
+        {
+            return reader();
+        }
+
+        /// <summary>
+        /// Deserializes a record from the stream.
+        /// </summary>
+        /// <param name="reuse">If not null, a record object that could be reused for returning the result</param>
+        /// <param name="writerSchema">The writer's RecordSchema</param>
+        /// <param name="readerSchema">The reader's schema, must be RecordSchema too.</param>
+        /// <param name="dec">The decoder for deserialization</param>
+        /// <returns>The record object just read</returns>
+        protected virtual object ReadRecord(object reuse, RecordSchema writerSchema, Schema readerSchema, Decoder dec)
+        {
+            RecordSchema rs = (RecordSchema)readerSchema;
+
+            object rec = CreateRecord(reuse, rs);
+            foreach (Field wf in writerSchema)
+            {
+                try
+                {
+                    Field rf;
+                    if (rs.TryGetFieldAlias(wf.Name, out rf))
+                    {
+                        object obj = null;
+                        TryGetField(rec, wf.Name, rf.Pos, out obj);
+                        AddField(rec, wf.Name, rf.Pos, Read(obj, wf.Schema, rf.Schema, dec));
+                    }
+                    else
+                        Skip(wf.Schema, dec);
+                }
+                catch (Exception ex)
+                {
+                    throw new AvroException(ex.Message + " in field " + wf.Name);
+                }
+            }
+
+            var defaultStream = new MemoryStream();
+            var defaultEncoder = new BinaryEncoder(defaultStream);
+            var defaultDecoder = new BinaryDecoder(defaultStream);
+            foreach (Field rf in rs)
+            {
+                if (writerSchema.Contains(rf.Name)) continue;
+                
+                defaultStream.Position = 0; // reset for writing
+                Resolver.EncodeDefaultValue(defaultEncoder, rf.Schema, rf.DefaultValue);
+                defaultStream.Flush();
+                defaultStream.Position = 0; // reset for reading
+
+                object obj = null;
+                TryGetField(rec, rf.Name, rf.Pos, out obj);
+                AddField(rec, rf.Name, rf.Pos, Read(obj, rf.Schema, rf.Schema, defaultDecoder));
+            }
+
+            return rec;
+        }
+
+        /// <summary>
+        /// Creates a new record object. Derived classes can override this to return an object of their choice.
+        /// </summary>
+        /// <param name="reuse">If appropriate, will reuse this object instead of constructing a new one</param>
+        /// <param name="readerSchema">The schema the reader is using</param>
+        /// <returns></returns>
+        protected virtual object CreateRecord(object reuse, RecordSchema readerSchema)
+        {
+            GenericRecord ru = (reuse == null || !(reuse is GenericRecord) || !(reuse as GenericRecord).Schema.Equals(readerSchema)) ?
+                new GenericRecord(readerSchema) :
+                reuse as GenericRecord;
+            return ru;
+        }
+
+        /// <summary>
+        /// Used by the default implementation of ReadRecord() to get the existing field of a record object. The derived
+        /// classes can override this to make their own interpretation of the record object.
+        /// </summary>
+        /// <param name="record">The record object to be probed into. This is guaranteed to be one that was returned
+        /// by a previous call to CreateRecord.</param>
+        /// <param name="fieldName">The name of the field to probe.</param>
+        /// <param name="value">The value of the field, if found. Null otherwise.</param>
+        /// <returns>True if and only if a field with the given name is found.</returns>
+        protected virtual bool TryGetField(object record, string fieldName, int fieldPos, out object value)
+        {
+            return (record as GenericRecord).TryGetValue(fieldName, out value);
+        }
+
+        /// <summary>
+        /// Used by the default implementation of ReadRecord() to add a field to a record object. The derived
+        /// classes can override this to suit their own implementation of the record object.
+        /// </summary>
+        /// <param name="record">The record object to be probed into. This is guaranteed to be one that was returned
+        /// by a previous call to CreateRecord.</param>
+        /// <param name="fieldName">The name of the field to probe.</param>
+        /// <param name="fieldValue">The value to be added for the field</param>
+        protected virtual void AddField(object record, string fieldName, int fieldPos, object fieldValue)
+        {
+            (record as GenericRecord).Add(fieldName, fieldValue);
+        }
+
+        /// <summary>
+        /// Deserializes a enum. Uses CreateEnum to construct the new enum object.
+        /// </summary>
+        /// <param name="reuse">If appropirate, uses this instead of creating a new enum object.</param>
+        /// <param name="writerSchema">The schema the writer used while writing the enum</param>
+        /// <param name="readerSchema">The schema the reader is using</param>
+        /// <param name="d">The decoder for deserialization.</param>
+        /// <returns>An enum object.</returns>
+        protected virtual object ReadEnum(object reuse, EnumSchema writerSchema, Schema readerSchema, Decoder d)
+        {
+            EnumSchema es = readerSchema as EnumSchema;
+            return CreateEnum(reuse, readerSchema as EnumSchema, writerSchema[d.ReadEnum()]);
+        }
+
+        /// <summary>
+        /// Used by the default implementation of ReadEnum to construct a new enum object.
+        /// </summary>
+        /// <param name="reuse">If appropriate, use this enum object instead of a new one.</param>
+        /// <param name="es">The enum schema used by the reader.</param>
+        /// <param name="symbol">The symbol that needs to be used.</param>
+        /// <returns>The default implemenation returns a GenericEnum.</returns>
+        protected virtual object CreateEnum(object reuse, EnumSchema es, string symbol)
+        {
+            if (reuse is GenericEnum)
+            {
+                GenericEnum ge = reuse as GenericEnum;
+                if (ge.Schema.Equals(es))
+                {
+                    ge.Value = symbol;
+                    return ge;
+                }
+            }
+            return new GenericEnum(es, symbol);
+        }
+
+        /// <summary>
+        /// Deserializes an array and returns an array object. It uses CreateArray() and works on it before returning it.
+        /// It also uses GetArraySize(), ResizeArray(), SetArrayElement() and GetArrayElement() methods. Derived classes can
+        /// override these methods to customize their behavior.
+        /// </summary>
+        /// <param name="reuse">If appropriate, uses this instead of creating a new array object.</param>
+        /// <param name="writerSchema">The schema used by the writer.</param>
+        /// <param name="readerSchema">The schema that the reader uses.</param>
+        /// <param name="d">The decoder for deserialization.</param>
+        /// <returns>The deserialized array object.</returns>
+        protected virtual object ReadArray(object reuse, ArraySchema writerSchema, Schema readerSchema, Decoder d)
+        {
+
+            ArraySchema rs = (ArraySchema)readerSchema;
+            object result = CreateArray(reuse, rs);
+            int i = 0;
+            for (int n = (int)d.ReadArrayStart(); n != 0; n = (int)d.ReadArrayNext())
+            {
+                if (GetArraySize(result) < (i + n)) ResizeArray(ref result, i + n);
+                for (int j = 0; j < n; j++, i++)
+                {
+                    SetArrayElement(result, i, Read(GetArrayElement(result, i), writerSchema.ItemSchema, rs.ItemSchema, d));
+                }
+            }
+            if (GetArraySize(result) != i) ResizeArray(ref result, i);
+            return result;
+        }
+
+        /// <summary>
+        /// Creates a new array object. The initial size of the object could be anything. The users
+        /// should use GetArraySize() to determine the size. The default implementation creates an <c>object[]</c>.
+        /// </summary>
+        /// <param name="reuse">If appropriate use this instead of creating a new one.</param>
+        /// <returns>An object suitable to deserialize an avro array</returns>
+        protected virtual object CreateArray(object reuse, ArraySchema rs)
+        {
+            return (reuse != null && reuse is object[]) ? (object[])reuse : new object[0];
+        }
+
+        /// <summary>
+        /// Returns the size of the given array object.
+        /// </summary>
+        /// <param name="array">Array object whose size is required. This is guaranteed to be somthing returned by
+        /// a previous call to CreateArray().</param>
+        /// <returns>The size of the array</returns>
+        protected virtual int GetArraySize(object array)
+        {
+            return (array as object[]).Length;
+        }
+
+        /// <summary>
+        /// Resizes the array to the new value.
+        /// </summary>
+        /// <param name="array">Array object whose size is required. This is guaranteed to be somthing returned by
+        /// a previous call to CreateArray().</param>
+        /// <param name="n">The new size.</param>
+        protected virtual void ResizeArray(ref object array, int n)
+        {
+            object[] o = array as object[];
+            Array.Resize(ref o, n);
+            array = o;
+        }
+
+        /// <summary>
+        /// Assigns a new value to the object at the given index
+        /// </summary>
+        /// <param name="array">Array object whose size is required. This is guaranteed to be somthing returned by
+        /// a previous call to CreateArray().</param>
+        /// <param name="index">The index to reassign to.</param>
+        /// <param name="value">The value to assign.</param>
+        protected virtual void SetArrayElement(object array, int index, object value)
+        {
+            object[] a = array as object[];
+            a[index] = value;
+        }
+
+        /// <summary>
+        /// Returns the element at the given index.
+        /// </summary>
+        /// <param name="array">Array object whose size is required. This is guaranteed to be somthing returned by
+        /// a previous call to CreateArray().</param>
+        /// <param name="index">The index to look into.</param>
+        /// <returns>The object the given index. Null if no object has been assigned to that index.</returns>
+        protected virtual object GetArrayElement(object array, int index)
+        {
+            return (array as object[])[index];
+        }
+
+        /// <summary>
+        /// Deserialized an avro map. The default implemenation creats a new map using CreateMap() and then
+        /// adds elements to the map using AddMapEntry().
+        /// </summary>
+        /// <param name="reuse">If appropriate, use this instead of creating a new map object.</param>
+        /// <param name="writerSchema">The schema the writer used to write the map.</param>
+        /// <param name="readerSchema">The schema the reader is using.</param>
+        /// <param name="d">The decoder for serialization.</param>
+        /// <returns>The deserialized map object.</returns>
+        protected virtual object ReadMap(object reuse, MapSchema writerSchema, Schema readerSchema, Decoder d)
+        {
+            MapSchema rs = (MapSchema)readerSchema;
+            object result = CreateMap(reuse, rs);
+            for (int n = (int)d.ReadMapStart(); n != 0; n = (int)d.ReadMapNext())
+            {
+                for (int j = 0; j < n; j++)
+                {
+                    string k = d.ReadString();
+                    AddMapEntry(result, k, Read(null, writerSchema.ValueSchema, rs.ValueSchema, d));
+                }
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// Used by the default implementation of ReadMap() to create a fresh map object. The default
+        /// implementaion of this method returns a IDictionary<string, map>.
+        /// </summary>
+        /// <param name="reuse">If appropriate, use this map object instead of creating a new one.</param>
+        /// <returns>An empty map object.</returns>
+        protected virtual object CreateMap(object reuse, MapSchema ms)
+        {
+            if (reuse != null && reuse is IDictionary<string, object>)
+            {
+                IDictionary<string, object> result = reuse as IDictionary<string, object>;
+                result.Clear();
+                return result;
+            }
+            return new Dictionary<string, object>();
+        }
+
+        /// <summary>
+        /// Adds an entry to the map.
+        /// </summary>
+        /// <param name="map">A map object, which is guaranteed to be one returned by a previous call to CreateMap().</param>
+        /// <param name="key">The key to add.</param>
+        /// <param name="value">The value to add.</param>
+        protected virtual void AddMapEntry(object map, string key, object value)
+        {
+            (map as IDictionary<string, object>).Add(key, value);
+        }
+
+        /// <summary>
+        /// Deserialized an object based on the writer's uninon schema.
+        /// </summary>
+        /// <param name="reuse">If appropriate, uses this object instead of creating a new one.</param>
+        /// <param name="writerSchema">The UnionSchema that the writer used.</param>
+        /// <param name="readerSchema">The schema the reader uses.</param>
+        /// <param name="d">The decoder for serialization.</param>
+        /// <returns>The deserialized object.</returns>
+        protected virtual object ReadUnion(object reuse, UnionSchema writerSchema, Schema readerSchema, Decoder d)
+        {
+            int index = d.ReadUnionIndex();
+            Schema ws = writerSchema[index];
+
+            if (readerSchema is UnionSchema)
+                readerSchema = findBranch(readerSchema as UnionSchema, ws);
+            else
+                if (!readerSchema.CanRead(ws))
+                    throw new AvroException("Schema mismatch. Reader: " + ReaderSchema + ", writer: " + WriterSchema);
+
+            return Read(reuse, ws, readerSchema, d);
+        }
+
+        /// <summary>
+        /// Deserializes a fixed object and returns the object. The default implementation uses CreateFixed()
+        /// and GetFixedBuffer() and returns what CreateFixed() returned.
+        /// </summary>
+        /// <param name="reuse">If appropriate, uses this object instead of creating a new one.</param>
+        /// <param name="writerSchema">The FixedSchema the writer used during serialization.</param>
+        /// <param name="readerSchema">The schema that the readr uses. Must be a FixedSchema with the same
+        /// size as the writerSchema.</param>
+        /// <param name="d">The decoder for deserialization.</param>
+        /// <returns>The deserilized object.</returns>
+        protected virtual object ReadFixed(object reuse, FixedSchema writerSchema, Schema readerSchema, Decoder d)
+        {
+            FixedSchema rs = (FixedSchema)readerSchema;
+            if (rs.Size != writerSchema.Size)
+            {
+                throw new AvroException("Size mismatch between reader and writer fixed schemas. Writer: " + writerSchema +
+                    ", reader: " + readerSchema);
+            }
+
+            object ru = CreateFixed(reuse, rs);
+            byte[] bb = GetFixedBuffer(ru);
+            d.ReadFixed(bb);
+            return ru;
+        }
+
+        /// <summary>
+        /// Returns a fixed object.
+        /// </summary>
+        /// <param name="reuse">If appropriate, uses this object instead of creating a new one.</param>
+        /// <param name="rs">The reader's FixedSchema.</param>
+        /// <returns>A fixed object with an appropriate buffer.</returns>
+        protected virtual object CreateFixed(object reuse, FixedSchema rs)
+        {
+            return (reuse != null && reuse is GenericFixed && (reuse as GenericFixed).Schema.Equals(rs)) ?
+                (GenericFixed)reuse : new GenericFixed(rs);
+        }
+
+        /// <summary>
+        /// Returns a buffer of appropriate size to read data into.
+        /// </summary>
+        /// <param name="f">The fixed object. It is guaranteed that this is something that has been previously
+        /// returned by CreateFixed</param>
+        /// <returns>A byte buffer of fixed's size.</returns>
+        protected virtual byte[] GetFixedBuffer(object f)
+        {
+            return (f as GenericFixed).Value;
+        }
+
+        protected virtual void Skip(Schema writerSchema, Decoder d)
+        {
+            switch (writerSchema.Tag)
+            {
+                case Schema.Type.Null:
+                    d.SkipNull();
+                    break;
+                case Schema.Type.Boolean:
+                    d.SkipBoolean();
+                    break;
+                case Schema.Type.Int:
+                    d.SkipInt();
+                    break;
+                case Schema.Type.Long:
+                    d.SkipLong();
+                    break;
+                case Schema.Type.Float:
+                    d.SkipFloat();
+                    break;
+                case Schema.Type.Double:
+                    d.SkipDouble();
+                    break;
+                case Schema.Type.String:
+                    d.SkipString();
+                    break;
+                case Schema.Type.Bytes:
+                    d.SkipBytes();
+                    break;
+                case Schema.Type.Record:
+                    foreach (Field f in writerSchema as RecordSchema) Skip(f.Schema, d);
+                    break;
+                case Schema.Type.Enumeration:
+                    d.SkipEnum();
+                    break;
+                case Schema.Type.Fixed:
+                    d.SkipFixed((writerSchema as FixedSchema).Size);
+                    break;
+                case Schema.Type.Array:
+                    {
+                        Schema s = (writerSchema as ArraySchema).ItemSchema;
+                        for (long n = d.ReadArrayStart(); n != 0; n = d.ReadArrayNext())
+                        {
+                            for (long i = 0; i < n; i++) Skip(s, d);
+                        }
+                    }
+                    break;
+                case Schema.Type.Map:
+                    {
+                        Schema s = (writerSchema as MapSchema).ValueSchema;
+                        for (long n = d.ReadMapStart(); n != 0; n = d.ReadMapNext())
+                        {
+                            for (long i = 0; i < n; i++) { d.SkipString(); Skip(s, d); }
+                        }
+                    }
+                    break;
+                case Schema.Type.Union:
+                    Skip((writerSchema as UnionSchema)[d.ReadUnionIndex()], d);
+                    break;
+                default:
+                    throw new AvroException("Unknown schema type: " + writerSchema);
+            }
+        }
+
+        protected static Schema findBranch(UnionSchema us, Schema s)
+        {
+            int index = us.MatchingBranch(s);
+            if (index >= 0) return us[index];
+            throw new AvroException("No matching schema for " + s + " in " + us);
+        }
+
+    }
+}

Added: avro/trunk/lang/csharp/src/apache/main/Generic/GenericRecord.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Generic/GenericRecord.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Generic/GenericRecord.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Generic/GenericRecord.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,137 @@
+/**
+ * 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.Linq;
+using System.Text;
+using Avro;
+
+namespace Avro.Generic
+{
+    /// <summary>
+    /// The default type used by GenericReader and GenericWriter for RecordSchema.
+    /// </summary>
+    public class GenericRecord
+    {
+        public RecordSchema Schema { get; private set; }
+
+        private IDictionary<string, object> contents = new Dictionary<string, object>();
+        public GenericRecord(RecordSchema schema)
+        {
+            this.Schema = schema;
+        }
+
+        public object this[string fieldName]
+        {
+            get { return contents[fieldName]; }
+        }
+
+        public void Add(string fieldName, object fieldValue)
+        {
+            if (Schema.Contains(fieldName))
+            {
+                // TODO: Use a matcher to verify that object has the right type for the field.
+                //contents.Add(fieldName, fieldValue);
+                contents[fieldName] = fieldValue;
+                return;
+            }
+            throw new AvroException("No such field: " + fieldName);
+        }
+
+        public bool TryGetValue(string fieldName, out object result)
+        {
+            return contents.TryGetValue(fieldName, out result);
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (this == obj) return true;
+            if (obj != null && obj is GenericRecord)
+            {
+                GenericRecord other = obj as GenericRecord;
+                return Schema.Equals(other.Schema) && areEqual(contents, other.contents);
+            }
+            return false;
+        }
+
+        private static bool areEqual(IDictionary<string, object> d1, IDictionary<string, object> d2)
+        {
+            if (d1.Count == d2.Count)
+            {
+                foreach (KeyValuePair<string, object> kv in d1)
+                {
+                    object o;
+                    if (!d2.TryGetValue(kv.Key, out o)) return false;
+                    if (!areEqual(o, kv.Value)) return false;
+                }
+                return true;
+            }
+            return false;
+        }
+
+        private static bool areEqual(object o1, object o2)
+        {
+            if (o1 == null) return o2 == null;
+            if (o2 == null) return false;
+            if (o1 is Array)
+            {
+                if (!(o2 is Array)) return false;
+                return areEqual(o1 as Array, o1 as Array);
+            }
+            else if (o1 is IDictionary<string, object>)
+            {
+                if (!(o2 is IDictionary<string, object>)) return false;
+                return areEqual(o1 as IDictionary<string, object>, o1 as IDictionary<string, object>);
+            }
+            return o1.Equals(o2);
+        }
+
+        private static bool areEqual(Array a1, Array a2)
+        {
+            if (a1.Length != a2.Length) return false;
+            for (int i = 0; i < a1.Length; i++)
+            {
+                if (!areEqual(a1.GetValue(i), a2.GetValue(i))) return false;
+            }
+            return true;
+        }
+
+        public override int GetHashCode()
+        {
+            return 31 * contents.GetHashCode()/* + 29 * Schema.GetHashCode()*/;
+        }
+
+        public override string ToString()
+        {
+            StringBuilder sb = new StringBuilder();
+            sb.Append("Schema: ");
+            sb.Append(Schema);
+            sb.Append(", contents: ");
+            sb.Append("{ ");
+            foreach (KeyValuePair<string, object> kv in contents)
+            {
+                sb.Append(kv.Key);
+                sb.Append(": ");
+                sb.Append(kv.Value);
+                sb.Append(", ");
+            }
+            sb.Append("}");
+            return sb.ToString();
+        }
+    }
+}

Added: avro/trunk/lang/csharp/src/apache/main/Generic/GenericWriter.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Generic/GenericWriter.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Generic/GenericWriter.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Generic/GenericWriter.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,445 @@
+/**
+ * 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 Avro.IO;
+
+namespace Avro.Generic
+{
+    public delegate void Writer<T>(T t);
+    /// <summary>
+    /// A typesafe wrapper around DefaultWriter. While a specific object of DefaultWriter
+    /// allows the client to serialize a generic type, an object of this class allows
+    /// only a single type of object to be serialized through it.
+    /// </summary>
+    /// <typeparam name="T">The type of object to be serialized.</typeparam>
+    public class GenericWriter<T> : DatumWriter<T>
+    {
+        private readonly DefaultWriter writer;
+        public GenericWriter(Schema schema) : this(new DefaultWriter(schema))
+        {
+
+        }
+
+        public Schema Schema { get { return writer.Schema; } }
+
+        public GenericWriter(DefaultWriter writer)
+        {
+            this.writer = writer;
+        }
+
+        /// <summary>
+        /// Serializes the given object using this writer's schema.
+        /// </summary>
+        /// <param name="value">The value to be serialized</param>
+        /// <param name="encoder">The encoder to use for serializing</param>
+        public void Write(T value, Encoder encoder)
+        {
+            writer.Write(value, encoder);
+        }
+    }
+
+    /// <summary>
+    /// A General purpose writer for serializing objects into a Stream using
+    /// Avro. This class implements a default way of serializing objects. But
+    /// one can derive a class from this and override different methods to
+    /// acheive results that are different from the default implementation.
+    /// </summary>
+    public class DefaultWriter
+    {
+        public Schema Schema { get; private set; }
+
+        /// <summary>
+        /// Constructs a generic writer for the given schema.
+        /// </summary>
+        /// <param name="schema">The schema for the object to be serialized</param>
+        public DefaultWriter(Schema schema)
+        {
+            this.Schema = schema;
+        }
+
+        public void Write<T>(T value, Encoder encoder)
+        {
+            Write(Schema, value, encoder);
+        }
+        /// <summary>
+        /// Examines the schema and dispatches the actual work to one
+        /// of the other methods of this class. This allows the derived
+        /// classes to override specific methods and get custom results.
+        /// </summary>
+        /// <param name="schema">The schema to use for serializing</param>
+        /// <param name="value">The value to be serialized</param>
+        /// <param name="encoder">The encoder to use during serialization</param>
+        public virtual void Write(Schema schema, object value, Encoder encoder)
+        {
+            switch (schema.Tag)
+            {
+                case Schema.Type.Null:
+                    WriteNull(value, encoder);
+                    break;
+                case Schema.Type.Boolean:
+                    Write<bool>(value, schema.Tag, encoder.WriteBoolean);
+                    break;
+                case Schema.Type.Int:
+                    Write<int>(value, schema.Tag, encoder.WriteInt);
+                    break;
+                case Schema.Type.Long:
+                    Write<long>(value, schema.Tag, encoder.WriteLong);
+                    break;
+                case Schema.Type.Float:
+                    Write<float>(value, schema.Tag, encoder.WriteFloat);
+                    break;
+                case Schema.Type.Double:
+                    Write<double>(value, schema.Tag, encoder.WriteDouble);
+                    break;
+                case Schema.Type.String:
+                    Write<string>(value, schema.Tag, encoder.WriteString);
+                    break;
+                case Schema.Type.Bytes:
+                    Write<byte[]>(value, schema.Tag, encoder.WriteBytes);
+                    break;
+                case Schema.Type.Record:
+                    WriteRecord(schema as RecordSchema, value, encoder);
+                    break;
+                case Schema.Type.Enumeration:
+                    WriteEnum(schema as EnumSchema, value, encoder);
+                    break;
+                case Schema.Type.Fixed:
+                    WriteFixed(schema as FixedSchema, value, encoder);
+                    break;
+                case Schema.Type.Array:
+                    WriteArray(schema as ArraySchema, value, encoder);
+                    break;
+                case Schema.Type.Map:
+                    WriteMap(schema as MapSchema, value, encoder);
+                    break;
+                case Schema.Type.Union:
+                    WriteUnion(schema as UnionSchema, value, encoder);
+                    break;
+                default:
+                    error(schema, value);
+                    break;
+            }
+        }
+
+        /// <summary>
+        /// Serializes a "null"
+        /// </summary>
+        /// <param name="value">The object to be serialized using null schema</param>
+        /// <param name="encoder">The encoder to use while serialization</param>
+        protected virtual void WriteNull(object value, Encoder encoder)
+        {
+            if (value != null) throw TypeMismatch(value, "null", "null");
+        }
+
+        /// <summary>
+        /// A generic method to serialize primitive Avro types.
+        /// </summary>
+        /// <typeparam name="S">Type of the C# type to be serialized</typeparam>
+        /// <param name="value">The value to be serialized</param>
+        /// <param name="tag">The schema type tag</param>
+        /// <param name="writer">The writer which should be used to write the given type.</param>
+        protected virtual void Write<S>(object value, Schema.Type tag, Writer<S> writer)
+        {
+            if (!(value is S)) throw TypeMismatch(value, tag.ToString(), typeof(S).ToString());
+            writer((S)value);
+        }
+
+        /// <summary>
+        /// Serialized a record using the given RecordSchema. It uses GetField method
+        /// to extract the field value from the given object.
+        /// </summary>
+        /// <param name="schema">The RecordSchema to use for serialization</param>
+        /// <param name="value">The value to be serialized</param>
+        /// <param name="encoder">The Encoder for serialization</param>
+
+        protected virtual void WriteRecord(RecordSchema schema, object value, Encoder encoder)
+        {
+            EnsureRecordObject(schema, value);
+            foreach (Field field in schema)
+            {
+                try
+                {
+                    object obj = GetField(value, field.Name, field.Pos);
+                    Write(field.Schema, obj, encoder);
+                }
+                catch (Exception ex)
+                {
+                    throw new AvroException(ex.Message + " in field " + field.Name);
+                }
+            }
+        }
+
+        protected virtual void EnsureRecordObject(RecordSchema s, object value)
+        {
+            if (value == null || !(value is GenericRecord) || !((value as GenericRecord).Schema.Equals(s)))
+            {
+                throw TypeMismatch(value, "record", "GenericRecord");
+            }
+        }
+
+        /// <summary>
+        /// Extracts the field value from the given object. In this default implementation,
+        /// value should be of type GenericRecord.
+        /// </summary>
+        /// <param name="value">The record value from which the field needs to be extracted</param>
+        /// <param name="fieldName">The name of the field in the record</param>
+        /// <param name="fieldPos">The position of field in the record</param>
+        /// <returns></returns>
+        protected virtual object GetField(object value, string fieldName, int fieldPos)
+        {
+            GenericRecord d = value as GenericRecord;
+            return d[fieldName];
+        }
+
+        /// <summary>
+        /// Serializes an enumeration. The default implementation expectes the value to be string whose
+        /// value is the name of the enumeration.
+        /// </summary>
+        /// <param name="es">The EnumSchema for serialization</param>
+        /// <param name="value">Value to be written</param>
+        /// <param name="encoder">Encoder for serialization</param>
+        protected virtual void WriteEnum(EnumSchema es, object value, Encoder encoder)
+        {
+            if (value == null || !(value is GenericEnum) || !((value as GenericEnum).Schema.Equals(es)))
+                throw TypeMismatch(value, "enum", "GenericEnum");
+            encoder.WriteEnum(es.Ordinal((value as GenericEnum).Value));
+        }
+
+        /// <summary>
+        /// Serialized an array. The default implementation calls EnsureArrayObject() to ascertain that the
+        /// given value is an array. It then calls GetArrayLength() and GetArrayElement()
+        /// to access the members of the array and then serialize them.
+        /// </summary>
+        /// <param name="schema">The ArraySchema for serialization</param>
+        /// <param name="value">The value being serialized</param>
+        /// <param name="encoder">The encoder for serialization</param>
+        protected virtual void WriteArray(ArraySchema schema, object value, Encoder encoder)
+        {
+            EnsureArrayObject(value);
+            long l = GetArrayLength(value);
+            encoder.WriteArrayStart();
+            encoder.SetItemCount(l);
+            for (long i = 0; i < l; i++)
+            {
+                encoder.StartItem();
+                Write(schema.ItemSchema, GetArrayElement(value, i), encoder);
+            }
+            encoder.WriteArrayEnd();
+        }
+
+        /// <summary>
+        /// Checks if the given object is an array. If it is a valid array, this function returns normally. Otherwise,
+        /// it throws an exception. The default implementation checks if the value is an array.
+        /// </summary>
+        /// <param name="value"></param>
+        protected virtual void EnsureArrayObject(object value)
+        {
+            if (value == null || !(value is Array)) throw TypeMismatch(value, "array", "Array");
+        }
+
+        /// <summary>
+        /// Returns the length of an array. The default implementation requires the object
+        /// to be an array of objects and returns its length. The defaul implementation
+        /// gurantees that EnsureArrayObject() has been called on the value before this
+        /// function is called.
+        /// </summary>
+        /// <param name="value">The object whose array length is required</param>
+        /// <returns>The array length of the given object</returns>
+        protected virtual long GetArrayLength(object value)
+        {
+            return (value as Array).Length;
+        }
+
+        /// <summary>
+        /// Returns the element at the given index from the given array object. The default implementation
+        /// requires that the value is an object array and returns the element in that array. The defaul implementation
+        /// gurantees that EnsureArrayObject() has been called on the value before this
+        /// function is called.
+        /// </summary>
+        /// <param name="value">The array object</param>
+        /// <param name="index">The index to look for</param>
+        /// <returns>The array element at the index</returns>
+        protected virtual object GetArrayElement(object value, long index)
+        {
+            return (value as Array).GetValue(index);
+        }
+
+        /// <summary>
+        /// Serialized a map. The default implementation first ensure that the value is indeed a map and then uses
+        /// GetMapSize() and GetMapElements() to access the contents of the map.
+        /// </summary>
+        /// <param name="schema">The MapSchema for serialization</param>
+        /// <param name="value">The value to be serialized</param>
+        /// <param name="encoder">The encoder for serialization</param>
+        protected virtual void WriteMap(MapSchema schema, object value, Encoder encoder)
+        {
+            EnsureMapObject(value);
+            IDictionary<string, object> vv = (IDictionary<string, object>)value;
+            encoder.WriteMapStart();
+            encoder.SetItemCount(GetMapSize(value));
+            foreach (KeyValuePair<string, object> obj in GetMapValues(vv))
+            {
+                encoder.StartItem();
+                encoder.WriteString(obj.Key);
+                Write(schema.ValueSchema, obj.Value, encoder);
+            }
+            encoder.WriteMapEnd();
+        }
+
+        /// <summary>
+        /// Checks if the given object is a map. If it is a valid map, this function returns normally. Otherwise,
+        /// it throws an exception. The default implementation checks if the value is an IDictionary<string, object>.
+        /// </summary>
+        /// <param name="value"></param>
+        protected virtual void EnsureMapObject(object value)
+        {
+            if (value == null || !(value is IDictionary<string, object>)) throw TypeMismatch(value, "map", "IDictionary<string, object>");
+        }
+
+        /// <summary>
+        /// Returns the size of the map object. The default implementation gurantees that EnsureMapObject has been
+        /// successfully called with the given value. The default implementation requires the value
+        /// to be an IDictionary<string, object> and returns the number of elements in it.
+        /// </summary>
+        /// <param name="value">The map object whose size is desired</param>
+        /// <returns>The size of the given map object</returns>
+        protected virtual long GetMapSize(object value)
+        {
+            return (value as IDictionary<string, object>).Count;
+        }
+
+        /// <summary>
+        /// Returns the contents of the given map object. The default implementation guarantees that EnsureMapObject
+        /// has been called with the given value. The defualt implementation of this method requires that
+        /// the value is an IDictionary<string, object> and returns its contents.
+        /// </summary>
+        /// <param name="value">The map object whose size is desired</param>
+        /// <returns>The contents of the given map object</returns>
+        protected virtual IEnumerable<KeyValuePair<string, object>> GetMapValues(object value)
+        {
+            return value as IDictionary<string, object>;
+        }
+
+        /// <summary>
+        /// Resolves the given value against the given UnionSchema and serializes the object against
+        /// the resolved schema member. The default implementation of this method uses
+        /// ResolveUnion to find the member schema within the UnionSchema.
+        /// </summary>
+        /// <param name="us">The UnionSchema to resolve against</param>
+        /// <param name="value">The value to be serialized</param>
+        /// <param name="encoder">The encoder for serialization</param>
+        protected virtual void WriteUnion(UnionSchema us, object value, Encoder encoder)
+        {
+            int index = ResolveUnion(us, value);
+            encoder.WriteUnionIndex(index);
+            Write(us[index], value, encoder);
+        }
+
+        /// <summary>
+        /// Finds the branch within the given UnionSchema that matches the given object. The default implementation
+        /// calls Matches() method in the order of branches within the UnionSchema. If nothing matches, throws
+        /// an exception.
+        /// </summary>
+        /// <param name="us">The UnionSchema to resolve against</param>
+        /// <param name="obj">The object that should be used in matching</param>
+        /// <returns></returns>
+        protected virtual int ResolveUnion(UnionSchema us, object obj)
+        {
+            for (int i = 0; i < us.Count; i++)
+            {
+                if (Matches(us[i], obj)) return i;
+            }
+            throw new AvroException("Cannot find a match for " + obj.GetType() + " in " + us);
+        }
+
+        /// <summary>
+        /// Serialized a fixed object. The default implementation requires that the value is
+        /// a GenericFixed object with an identical schema as es.
+        /// </summary>
+        /// <param name="es">The schema for serialization</param>
+        /// <param name="value">The value to be serialized</param>
+        /// <param name="encoder">The encoder for serialization</param>
+        protected virtual void WriteFixed(FixedSchema es, object value, Encoder encoder)
+        {
+            if (value == null || !(value is GenericFixed) || !(value as GenericFixed).Schema.Equals(es))
+            {
+                throw TypeMismatch(value, "fixed", "GenericFixed");
+            }
+            GenericFixed ba = (GenericFixed)value;
+            encoder.WriteFixed(ba.Value);
+        }
+
+        protected AvroException TypeMismatch(object obj, string schemaType, string type)
+        {
+            return new AvroException(type + " required to write against " + schemaType + " schema but found " + (null == obj ? "null" : obj.GetType().ToString()) );
+        }
+
+        private void error(Schema schema, Object value)
+        {
+            throw new AvroTypeException("Not a " + schema + ": " + value);
+        }
+
+        /*
+         * FIXME: This method of determining the Union branch has problems. If the data is IDictionary<string, object>
+         * if there are two branches one with record schema and the other with map, it choose the first one. Similarly if
+         * the data is byte[] and there are fixed and bytes schemas as branches, it choose the first one that matches.
+         * Also it does not recognize the arrays of primitive types.
+         */
+        protected virtual bool Matches(Schema sc, object obj)
+        {
+            if (obj == null && sc.Tag != Avro.Schema.Type.Null) return false;
+            switch (sc.Tag)
+            {
+                case Schema.Type.Null:
+                    return obj == null;
+                case Schema.Type.Boolean:
+                    return obj is bool;
+                case Schema.Type.Int:
+                    return obj is int;
+                case Schema.Type.Long:
+                    return obj is long;
+                case Schema.Type.Float:
+                    return obj is float;
+                case Schema.Type.Double:
+                    return obj is double;
+                case Schema.Type.Bytes:
+                    return obj is byte[];
+                case Schema.Type.String:
+                    return obj is string;
+                case Schema.Type.Record:
+                    //return obj is GenericRecord && (obj as GenericRecord).Schema.Equals(s);
+                    return obj is GenericRecord && (obj as GenericRecord).Schema.SchemaName.Equals((sc as RecordSchema).SchemaName);
+                case Schema.Type.Enumeration:
+                    //return obj is GenericEnum && (obj as GenericEnum).Schema.Equals(s);
+                    return obj is GenericEnum && (obj as GenericEnum).Schema.SchemaName.Equals((sc as EnumSchema).SchemaName);
+                case Schema.Type.Array:
+                    return obj is Array && !(obj is byte[]);
+                case Schema.Type.Map:
+                    return obj is IDictionary<string, object>;
+                case Schema.Type.Union:
+                    return false;   // Union directly within another union not allowed!
+                case Schema.Type.Fixed:
+                    //return obj is GenericFixed && (obj as GenericFixed).Schema.Equals(s);
+                    return obj is GenericFixed && (obj as GenericFixed).Schema.SchemaName.Equals((sc as FixedSchema).SchemaName);
+                default:
+                    throw new AvroException("Unknown schema type: " + sc.Tag);
+            }
+        }
+    }
+}

Added: avro/trunk/lang/csharp/src/apache/main/IO/BinaryDecoder.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/IO/BinaryDecoder.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/IO/BinaryDecoder.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/IO/BinaryDecoder.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,299 @@
+/**
+ * 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
+{
+    /// <summary>
+    /// Decoder for Avro binary format
+    /// </summary>
+    public class BinaryDecoder : Decoder
+    {
+        private readonly Stream stream;
+
+        public BinaryDecoder(Stream stream)
+        {
+            this.stream = stream;
+        }
+
+        /// <summary>
+        /// null is written as zero bytes
+        /// </summary>
+        public void ReadNull()
+        {
+        }
+
+        /// <summary>
+        /// a boolean is written as a single byte 
+        /// whose value is either 0 (false) or 1 (true).
+        /// </summary>
+        /// <returns></returns>
+        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);
+        }
+
+        /// <summary>
+        /// int and long values are written using variable-length, zig-zag coding.
+        /// </summary>
+        /// <param name="?"></param>
+        /// <returns></returns>
+        public int ReadInt()
+        {
+            return (int)ReadLong();
+        }
+        /// <summary>
+        /// int and long values are written using variable-length, zig-zag coding.
+        /// </summary>
+        /// <param name="?"></param>
+        /// <returns></returns>
+        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);
+        }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        /// <returns></returns>
+        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);
+        }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        /// <param name="?"></param>
+        /// <returns></returns>
+        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);
+        }
+
+        /// <summary>
+        /// Bytes are encoded as a long followed by that many bytes of data. 
+        /// </summary>
+        /// <returns></returns>
+        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();
+        }
+
+    }
+}