void SerializeAutoSerializable(object instance, TypeSerializationArgs args) { TypeSerializationArgs callerArgs = args; args = args.Clone(); if (this.IsInline) { // Inline objects are serialized with only a 2-byte length prefix // No version info or anything else int length = 0; long lengthPosition = args.Writer.BaseStream.Position; long endPosition = -1; args.Writer.Write((byte)length); if (instance != null) { args.Header = new TypeSerializationHeader(); args.Header.DataVersion = 1; args.Header.DataMinVersion = 1; this.autoSerializeMethod(instance, args); endPosition = args.Writer.BaseStream.Position; length = (int)((endPosition - lengthPosition) - InlineHeaderSize); if (length > MaxInlineSize) { throw new NotSupportedException(string.Format( "Inline classes must be {0} bytes or less. Class {1} serialized to {2} bytes.", MaxInlineSize, instance.GetType().FullName, length )); } args.Writer.BaseStream.Position = lengthPosition; args.Writer.Write((byte)length); args.Writer.BaseStream.Position = endPosition; } } else if (instance == null) { args.Writer.Write(NullVersion); } else { args.Header = new TypeSerializationHeader(); args.Header.DataVersion = (byte)this.CurrentVersion; args.Header.DataMinVersion = (byte)this.MinVersion; // If min version is less than or equal legacy version then write // out legacy version + 1 as the min version in the data stream.This // is to prevent older class definitions from attempting to // deserialize the new data using IVersionSerializable if ((this.LegacyVersion > 0) && (this.LegacyVersion >= this.MinVersion)) { args.Header.DataMinVersion = (byte)(this.LegacyVersion + 1); } // If this isn't a base class invocation then make sure // SerializationInfo is initialized for the first time. // If it is a base class then get the base class info // from the parent's SerializationInfo if (callerArgs.IsBaseClass == false) { ISerializationInfo info = instance as ISerializationInfo; if (info != null) { args.SerializationInfo = info.SerializationInfo; } else { // SerializationInfo may not be null in this case // because this may be an object contained in a parent // class. We need to make sure the child object doesn't // use the serialization info from the container args.SerializationInfo = null; } } else if (args.SerializationInfo != null) { args.SerializationInfo = callerArgs.SerializationInfo.BaseClassInfo; } // Handled cached serialization info if original data // was newer than the class definition that deserialized it if ( (args.SerializationInfo != null) && (args.SerializationInfo.Version > this.CurrentVersion) ) { args.Header.DataVersion = (byte)args.SerializationInfo.Version; args.Header.DataMinVersion = (byte)args.SerializationInfo.MinVersion; } // Write a special version byte to indicate this serialized // data uses a header. Because this version is guaranteed to // be higher than actual object versions, older serialization // code will simply treat this is a higher unhandled version, // which is true. args.Writer.Write(HasHeaderVersion); // Write the header with placeholder data args.Header.Write(args.Writer); // Serialize the object this.autoSerializeMethod(instance, args); // Update the header with final data. Note that the // TypeSerializationHeader class takes care of the // stream position args.Header.Write(args.Writer); } }
bool DeserializeAutoSerializable(ref object instance, TypeSerializationArgs args) { byte dataVersion = 1; bool isSerializationInfoSupported = (instance == null) ? this.supportsSerializationInfo : (instance is ISerializationInfo); TypeSerializationArgs callerArgs = args; byte dataMinVersion = 0; // Create a local copy of args so we don't mess with caller's context args = args.Clone(); if (this.IsInline) { // Read length prefix. If length is 0 then object is null byte length = args.Reader.ReadByte(); if (length == 0) { dataVersion = NullVersion; } } else { dataVersion = args.Reader.ReadByte(); } if (dataVersion == NullVersion) { instance = null; return(false); } if (dataVersion == HasHeaderVersion) { args.Header = new TypeSerializationHeader(); args.Header.Read(args.Reader); dataVersion = args.Header.DataVersion; dataMinVersion = args.Header.DataMinVersion; } if ( // Version of the data is less than our supported minimum version // OR data is a lower version than the min version that can be deserialized // OR data is a higher version but this type isn't forward compatible // OR data has a min version that is higher than this current type definition (dataVersion < this.MinVersion) || (this.CurrentVersion < dataMinVersion) || (dataVersion < this.MinDeserializeVersion) || ((dataVersion > this.CurrentVersion) && (isSerializationInfoSupported == false)) || ((args.Header != null) && (args.Header.DataMinVersion > this.CurrentVersion)) ) { throw new UnhandledVersionException(this.CurrentVersion, dataVersion); } else { if (instance == null) { instance = CreateInstance(); } // If this is the derived class then create a new top-level // serialization info. If this is the base class then set // the base class serialization info if (callerArgs.IsBaseClass == false) { args.SerializationInfo = new SerializationInfo(); if (isSerializationInfoSupported == true) { ((ISerializationInfo)instance).SerializationInfo = args.SerializationInfo; } } else { callerArgs.SerializationInfo.BaseClassInfo = new SerializationInfo(); args.SerializationInfo = callerArgs.SerializationInfo.BaseClassInfo; } args.SerializationInfo.Version = dataVersion; if (args.Header != null) { args.SerializationInfo.MinVersion = args.Header.DataMinVersion; } this.autoDeserializeMethod(instance, dataVersion, args); if (args.Succeeded == false) { //this should never be hit, as it is a legacy of the volatile flag return(false); } if (isSerializationInfoSupported == true) { if (dataVersion > this.CurrentVersion) { int readDataLength = (int)(args.Reader.BaseStream.Position - args.Header.DataPosition); int unhandledDataLength = args.Header.DataLength - readDataLength; args.SerializationInfo.UnhandledData = args.Reader.ReadBytes(unhandledDataLength); } } } return(true); }