BinarySerializer

A declarative serialization framework for controlling formatting of data at the byte level.  Jump to docs for more info and a walkthrough.

Features

  • Field lengths/offset
  • Collections (implicit/explicit termination)
  • Bindings
  • Conditionals
  • Subtypes
  • Converters
  • Enum Support (string or value) 
  • Member Streams
  • MemberSerialized/MemberDeserialized events
  • Member-level Big/Little Endian Support
  • Non-seekable stream support
  • IBinarySerializable

Attributes

  Bindable Non-seek Support
Ignore   Yes
SerializeAs   Yes
SerializeAsEnum   Yes
FieldOffset Yes  
FieldLength Yes Yes
FieldCount Yes Yes
Subtype Yes Yes
SerializeWhen Yes Yes
SerializeUntil Yes  
ItemLength Yes Yes
ItemSerializeUntil Item Bindable Yes

Example

public class Cereal
{
    [SerializeAs(SerializedType.NullTerminatedString, Order=0)]
    public string IsLittleEndian { get; set; }

    [FieldLength(6)]
    public string Name { get; set; }

    [SerializeAs(SerializedType.NullTerminatedString, Order = 0)]
    public string Manufacturer { get; set; }

    public ushort OtherStuffCount { get; set; }

    [FieldOffset(1000)]
    public int Outlier { get; set; }

    public NutritionalInformation NutritionalInformation { get; set; }

    public double DoubleField;

    [FieldCount("OtherStuffCount")]
    [SerializeAs(SerializedType.SizedString)]
    [ItemLength(3)]
    public List<string> OtherStuff { get; set; }

    [FieldLength(4)]
    [SerializeAs(SerializedType.SizedString)]
    public CerealShape Shape { get; set; }

    public CerealShape DefinitelyNotTheShape { get; set; }

    [SerializeWhen("Shape", CerealShape.Square)]
    public string DontSerializeMe { get; set; }

    [SerializeWhen("Shape", CerealShape.Circular)]
    public string SerializeMe { get; set; }

    [SerializeUntil((byte)0)]
    public List<string> ExplicitlyTerminatedList { get; set; }

    [FieldLength(9)]
    public List<CerealShape> ImplicitlyTerminatedList { get; set; }

    [FieldCount(3)]
    public int[] ArrayOfInts { get; set; }

    [FieldLength]
    public string InvalidFieldLength { get; set; }
        
    public long DisclaimerLength { get; set; }

    [FieldLength("DisclaimerLength")]
    public Stream Disclaimer { get; set; }
}
public class NutritionalInformation
{
    public int Calories { get; set; }
    public float Fat { get; set; }
    public ushort Cholesterol { get; set; }

    [SerializeAs(Order=1)]
    public ushort VitaminA { get; set; }

    [SerializeAs(Order=0)]
    public uint VitaminB { get; set; }

    [FieldCount("OtherStuffCount", Mode = RelativeSourceMode.FindAncestor, AncestorType = "Cereal")]
    public List<string> OtherNestedStuff { get; set; }

    [FieldCount("OtherStuffCount", Mode = RelativeSourceMode.FindAncestor, AncestorLevel = 2)]
    public List<string> OtherNestedStuff2 { get; set; }

    [ItemSerializeUntil("Last", true)]
    public List<Toy> Toys { get; set; }

    [FieldLength("Outlier", ConverterType = typeof(DoubleOutlierConverter), Mode = RelativeSourceMode.FindAncestor, AncestorLevel = 2)]
    public string WeirdOutlierLengthedField { get; set; }

    public Ingredients Ingredients { get; set; }
}
using (var stream = new FileStream("cereal.dat", FileMode.Open, FileAccess.Read))
{
    var serializer = new BinarySerializer();
    var entry = serializer.Deserialize<IsoDirectoryRecord>(stream);
}

Notes

This framework was developed largely to enable interoperability with legacy systems.  While it could be used for data storage or hibernation, that was not the intention and there are likely better frameworks (and approaches, frankly) for that sort of thing.

See the iso9660 project or the unit tests for example usages.

Last edited Apr 21 at 10:26 PM by jefffhaynes, version 56