public IDisposable OpenType(BarfTypeDefinition definition) { Definition = definition; SerializerBuilder = new BarfSerializerBuilder(definition); TesterBuilder = new BarfTesterBuilder(definition); TypeDefinition = Module.Types[Type.GetCecilFullName()]; BarfSerializer = new TypeDefinition( "AutoSerializer", TypeDefinition.Namespace, TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.NestedPrivate | TypeAttributes.BeforeFieldInit, Import(typeof(BarfSerializer <>).ResolveGenericType(Type))); BarfTester = new TypeDefinition( "BarfTester", TypeDefinition.Namespace, TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.NestedPrivate | TypeAttributes.BeforeFieldInit, Import(typeof(object))); return(new AnonymousDisposable(() => { Definition = null; SerializerBuilder = null; TesterBuilder = null; TypeDefinition = null; BarfSerializer = null; BarfTester = null; })); }
public BarfTesterBuilder(BarfTypeDefinition typeDefinition) { if (typeDefinition == null) { throw new ArgumentNullException("typeDefinition"); } _def = typeDefinition; }
public long BeginObject <T>() { var def = BarfTypeDefinition.Get <T>(true); return(BeginObject(def.CurrentVersion, def.MinVersion)); }
/// <summary> /// Instruments the specified assembly definition. /// </summary> /// <param name="assemblyDefinition">The assembly definition.</param> public void Instrument(AssemblyDefinition assemblyDefinition) { int eligibleTypeCount = 0; int validTypeCount = 0; var reflectionAssembly = GetAssembly(assemblyDefinition.Name.FullName); foreach (ModuleDefinition moduleDefinition in assemblyDefinition.Modules) { Module module = null; foreach (var mod in reflectionAssembly.GetModules(false)) { if (moduleDefinition.Name == moduleDefinition.Name) { module = mod; } } if (module == null) { throw new InvalidOperationException("Couldn't resolve module: " + moduleDefinition.Name); } try { _context = new InstrumentationContext(moduleDefinition); foreach (Type type in module.GetTypes()) { if (!type.IsClass) { continue; } if (!BarfFormatter.IsSerializable(type)) { continue; } var attribute = Attribute .GetCustomAttributes(type, typeof(SerializableClassAttribute), false) .OfType <SerializableClassAttribute>() .FirstOrDefault <SerializableClassAttribute>(); if (attribute.RuntimeOnly) { continue; } var barfTypeDef = BarfTypeDefinition.Get(type); if (barfTypeDef == null) { // todo - remove once everything is supported continue; } ++eligibleTypeCount; if (type.IsGenericType) { continue; } Trace.WriteLine("Instrumenting - " + type.Name); using (_context.OpenType(barfTypeDef)) { _context.BarfSerializer.CustomAttributes.Add(new CustomAttribute(_context.Import(typeof(CompilerGeneratedAttribute).GetConstructor(Type.EmptyTypes)))); _context.TypeDefinition.NestedTypes.Add(_context.BarfSerializer); _context.TypeDefinition.Module.Types.Add(_context.BarfSerializer); GenerateDefaultCtor(_context.BarfSerializer, _context.BaseBarfSerializer); GenerateCreateEmptyMethod(); GenerateSerializeMethod(); GenerateInnerDeserializeMethod(); _context.BarfTester.CustomAttributes.Add(new CustomAttribute(_context.Import(typeof(CompilerGeneratedAttribute).GetConstructor(Type.EmptyTypes)))); _context.BarfTester.Interfaces.Add(_context.BarfTesterInterface); _context.TypeDefinition.NestedTypes.Add(_context.BarfTester); _context.TypeDefinition.Module.Types.Add(_context.BarfTester); GenerateDefaultCtor(_context.BarfTester, typeof(object)); GenerateFillMethod(); GenerateAssertAreEqualMethod(); ++validTypeCount; } } } finally { _context = null; } } Trace.TraceInformation("{0} - {1} of {2} eligible types were generated in {3}", GetType().Name, validTypeCount, eligibleTypeCount, assemblyDefinition.Name.Name); }
private static BarfTypeDefinition Create(Type type) { var parts = new List <PartDefinition>(); var errors = new List <string>(); var result = new BarfTypeDefinition { Type = type, Errors = new ReadOnlyCollection <string>(errors), Parts = new ReadOnlyCollection <PartDefinition>(parts) }; try { var classAttribute = (SerializableClassAttribute)Attribute.GetCustomAttribute(type, typeof(SerializableClassAttribute), false); if (classAttribute == null) { errors.Add(type.Name + " does not define a " + typeof(SerializableAttribute).Name); return(result); } var typePartDef = PartDefinition.Create(type); if (typePartDef != null) { parts.Add(typePartDef); } const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly; parts.AddRange(PartDefinition.CreateInheritedParts(type)); foreach (var member in type.GetMembers(flags)) { if (member.DeclaringType != type) { continue; } if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field) { continue; } var partDefinition = PartDefinition.Create(member); if (partDefinition == null) { continue; } if (partDefinition.IsDynamic) { if (partDefinition.Type.IsValueType) { // value types may not be dynamic return(result); } } parts.Add(partDefinition); } parts.Sort(BarfPartInfoComparer.Default); result.CurrentVersion = result.Parts .Select(part => part.Version) .Concat(new[] { classAttribute.MinVersion }) .Max <int>(); // before we would guess the min version if it was zero // by taking the lowest property version. However // if an empty class defining no parts will be version // zero. If a property is added at version 1 min version // will then become 1 making it impossible to deserialize // the older empty class streams. result.MinVersion = classAttribute.MinVersion; result.MinDeserializeVersion = Math.Max(classAttribute.MinDeserializeVersion, 0); result.LegacyVersion = classAttribute.LegacyVersion; if (result.LegacyVersion >= 0) { var method = type.ResolveMethod("Deserialize", typeof(IPrimitiveReader), typeof(int)); if (method != null && method.IsStatic) { method = null; } if (method == null && result.LegacyVersion > 0) { errors.Add("LegacyVersion=" + result.LegacyVersion + " but no method void Deserialize(IPrimitiveReader, int) was defined."); } else { result.LegacyDeserializeMethod = method; } } result.IsForwardCompatible = typeof(ISerializationInfo).IsAssignableFrom(type); } catch (Exception ex) { errors.Add(ex.ToString()); return(result); } return(result); }
/// <summary> /// Begins a region of code that deserializes a barf type. /// </summary> public BarfObjectHeader BeginObject <T>() { var def = BarfTypeDefinition.Get <T>(true); bool deserializeTypeTable = false; if (StreamHeader == null) { StreamHeader = BarfStreamHeader.ReadFrom(Reader); if (StreamHeader.FrameworkVersion > BarfFormatter.MaxFrameworkVersion) { string message = string.Format( "Encountered a BARF formatted stream with FrameworkVersion=\"{0}\" but MaxFrameworkVersion=\"{1}\".", StreamHeader.FrameworkVersion, BarfFormatter.MaxFrameworkVersion); throw new UnhandledVersionException(message); } deserializeTypeTable = StreamHeader.Flags.IsSet(HeaderFlags.HasNameTable); } var objectHeader = BarfObjectHeader.ReadFrom(Reader); if (!objectHeader.IsNull) { if (objectHeader.Version < def.MinVersion) { var message = string.Format( "Binary data was encoded with Version=\"{0}\" but the current MinVersion=\"{1}\".", objectHeader.Version, def.MinVersion); throw new UnhandledVersionException(message); } if (def.CurrentVersion < objectHeader.MinVersion) { var message = string.Format( "Binary data was encoded with a MinVersion=\"{0}\" but CurrentVersion=\"{1}\" is less than that.", objectHeader.MinVersion, def.CurrentVersion); throw new UnhandledVersionException(message); } if (objectHeader.Version < def.MinDeserializeVersion) { var message = string.Format( "Binary data is Version=\"{0}\" but MinDeserializeVersion=\"{1}\".", objectHeader.Version, def.MinDeserializeVersion); throw new UnhandledVersionException(message); } } if (deserializeTypeTable) { var currentPosition = Reader.BaseStream.Position; Reader.BaseStream.Seek(objectHeader.Length, SeekOrigin.Current); TypeTable = BarfTypeTable.ReadFrom(Reader); _streamEnd = Reader.BaseStream.Position; Reader.BaseStream.Seek(currentPosition, SeekOrigin.Begin); } ++_objectDepth; return(objectHeader); }
public void RaiseInvalidData <T>(BarfObjectHeader header, string message) { var builder = new StringBuilder(); var w = XmlWriter.Create(builder, new XmlWriterSettings { Indent = true, IndentChars = "\t", OmitXmlDeclaration = true, ConformanceLevel = ConformanceLevel.Fragment, NewLineChars = Environment.NewLine, NewLineHandling = NewLineHandling.Entitize, NewLineOnAttributes = false }); w.WriteStartElement("Details"); { if (!string.IsNullOrEmpty(message)) { w.WriteElementString("Message", message); } w.WriteElementString("Type", typeof(T).ToString()); w.WriteElementString("Position", Reader.BaseStream.Position.ToString()); w.WriteElementString("ObjectDepth", _objectDepth.ToString()); if (header != null) { w.WriteStartElement("ObjectHeader"); { w.WriteElementString("IsNull", header.IsNull.ToString()); if (!header.IsNull) { w.WriteElementString("Version", header.Version.ToString()); w.WriteElementString("MinVersion", header.MinVersion.ToString()); w.WriteElementString("Length", header.Length.ToString()); w.WriteElementString("StartPosition", header.StartPosition.ToString()); w.WriteElementString("EndPosition", header.EndPosition.ToString()); } } w.WriteEndElement(); } w.WriteStartElement("CurrentDefinition"); { var def = BarfTypeDefinition.Get <T>(false); if (def == null || !def.IsValid) { w.WriteElementString("Error", "Couldn't load definition for type - " + typeof(T)); } else { w.WriteElementString("CurrentVersion", def.CurrentVersion.ToString()); w.WriteElementString("MinVersion", def.MinVersion.ToString()); w.WriteElementString("MinDeserializeVersion", def.MinDeserializeVersion.ToString()); } } w.WriteEndElement(); w.WriteStartElement("StreamHeader"); { w.WriteElementString("FrameworkVersion", StreamHeader.FrameworkVersion.ToString()); w.WriteElementString("Flags", StreamHeader.Flags.ToString()); w.WriteElementString("Length", StreamHeader.Length.ToString()); } w.WriteEndElement(); } w.WriteEndElement(); w.Flush(); throw new InvalidDataException(builder.ToString()); }