Jo Shields 3c1f479b9d Imported Upstream version 4.0.0~alpha1
Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
2015-04-07 09:35:12 +01:00

1059 lines
26 KiB
C#

//
// System.Web.UI.ObjectStateFormatter
//
// Authors:
// Ben Maurer (bmaurer@users.sourceforge.net)
// Gonzalo Paniagua (gonzalo@ximian.com)
//
// (C) 2003 Ben Maurer
// (c) Copyright 2004-2010 Novell, Inc. (http://www.novell.com)
//
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//#define TRACE
using System.Collections;
using System.ComponentModel;
using System.Globalization;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.Text;
using System.Web.UI.WebControls;
using System.Web.Util;
using System.Diagnostics;
using System.Web.Configuration;
namespace System.Web.UI
{
public sealed class ObjectStateFormatter : IFormatter, IStateFormatter
{
const ushort SERIALIZED_STREAM_MAGIC = 0x01FF;
Page page;
MachineKeySection section;
public ObjectStateFormatter ()
{
}
internal ObjectStateFormatter (Page page)
{
this.page = page;
}
bool EnableMac {
get {
return (page == null) ? (section != null) : page.EnableViewStateMac;
}
}
bool NeedViewStateEncryption {
get {
return (page == null) ? false : page.NeedViewStateEncryption;
}
}
internal MachineKeySection Section {
get {
if (section == null)
section = (MachineKeySection) WebConfigurationManager.GetWebApplicationSection ("system.web/machineKey");
return section;
}
set {
section = value;
}
}
// There's no need to implement encryption support in this overload. Encryption is
// performed only when ObjectStateFormatter is created in the Page context, and that
// can happen only internally to System.Web. Since System.Web doesn't use this
// overload, the encryption code in here would be effectively dead.
public object Deserialize (Stream inputStream)
{
if (inputStream == null)
throw new ArgumentNullException ("inputStream");
BinaryReader reader = new BinaryReader (inputStream);
short magic = reader.ReadInt16 ();
if (magic != SERIALIZED_STREAM_MAGIC)
throw new ArgumentException ("The serialized data is invalid");
return DeserializeObject (reader);
}
public object Deserialize (string inputString)
{
if (inputString == null)
throw new ArgumentNullException ("inputString");
if (inputString.Length == 0)
throw new ArgumentNullException ("inputString");
byte [] data = Convert.FromBase64String (inputString);
if (data == null || (data.Length) == 0)
throw new ArgumentNullException ("inputString");
if (NeedViewStateEncryption) {
if (EnableMac) {
data = MachineKeySectionUtils.VerifyDecrypt (Section, data);
} else {
data = MachineKeySectionUtils.Decrypt (Section, data);
}
} else if (EnableMac) {
data = MachineKeySectionUtils.Verify (Section, data);
}
if (data == null)
throw new HttpException ("Unable to validate data.");
using (MemoryStream ms = new MemoryStream (data)) {
return Deserialize (ms);
}
}
public string Serialize (object stateGraph)
{
if (stateGraph == null)
return String.Empty;
byte[] data = null;
using (MemoryStream ms = new MemoryStream ()) {
Serialize (ms, stateGraph);
data = ms.GetBuffer ();
}
if (NeedViewStateEncryption) {
if (EnableMac) {
data = MachineKeySectionUtils.EncryptSign (Section, data);
} else {
data = MachineKeySectionUtils.Encrypt (Section, data);
}
} else if (EnableMac) {
data = MachineKeySectionUtils.Sign (Section, data);
}
return Convert.ToBase64String (data, 0, data.Length);
}
// There's no need to implement encryption support in this overload. Encryption is
// performed only when ObjectStateFormatter is created in the Page context, and that
// can happen only internally to System.Web. Since System.Web doesn't use this
// overload, the encryption code in here would be effectively dead.
public void Serialize (Stream outputStream, object stateGraph)
{
if (outputStream == null)
throw new ArgumentNullException ("outputStream");
if (stateGraph == null)
throw new ArgumentNullException ("stateGraph");
BinaryWriter writer = new BinaryWriter (outputStream);
writer.Write (SERIALIZED_STREAM_MAGIC);
SerializeValue (writer, stateGraph);
}
void SerializeValue (BinaryWriter w, object o)
{
ObjectFormatter.WriteObject (w, o, new WriterContext ());
}
object DeserializeObject (BinaryReader r)
{
return ObjectFormatter.ReadObject (r, new ReaderContext ());
}
#region IFormatter
object IFormatter.Deserialize (Stream serializationStream)
{
return Deserialize (serializationStream);
}
void IFormatter.Serialize (Stream serializationStream, object stateGraph)
{
Serialize (serializationStream, stateGraph);
}
SerializationBinder IFormatter.Binder {
get { return null; }
set { }
}
StreamingContext IFormatter.Context {
get { return new StreamingContext (StreamingContextStates.All); }
set { }
}
ISurrogateSelector IFormatter.SurrogateSelector {
get { return null; }
set { }
}
#endregion
#region Object Readers/Writers
sealed class WriterContext
{
Hashtable cache;
short nextKey = 0;
short key = 0;
public short Key {
get { return key; }
}
public bool RegisterCache (object o)
{
if (nextKey == short.MaxValue)
return false;
if (cache == null) {
cache = new Hashtable ();
cache.Add (o, key = nextKey++);
return false;
}
object posKey = cache [o];
if (posKey == null) {
cache.Add (o, key = nextKey++);
return false;
}
key = (short) posKey;
return true;
}
}
sealed class ReaderContext
{
ArrayList cache;
public void CacheItem (object o)
{
if (cache == null)
cache = new ArrayList ();
cache.Add (o);
}
public object GetCache (short key)
{
return cache [key];
}
}
abstract class ObjectFormatter
{
static readonly Hashtable writeMap = new Hashtable ();
static ObjectFormatter [] readMap = new ObjectFormatter [256];
static BinaryObjectFormatter binaryObjectFormatter;
static TypeFormatter typeFormatter;
static EnumFormatter enumFormatter;
static SingleRankArrayFormatter singleRankArrayFormatter;
static TypeConverterFormatter typeConverterFormatter;
static ObjectFormatter ()
{
new StringFormatter ().Register ();
new Int64Formatter ().Register ();
new Int32Formatter ().Register ();
new Int16Formatter ().Register ();
new ByteFormatter ().Register ();
new BooleanFormatter ().Register ();
new CharFormatter ().Register ();
new DateTimeFormatter ().Register ();
new PairFormatter ().Register ();
new TripletFormatter ().Register ();
new ArrayListFormatter ().Register ();
new HashtableFormatter ().Register ();
new ObjectArrayFormatter ().Register ();
new UnitFormatter ().Register ();
new FontUnitFormatter ().Register ();
new IndexedStringFormatter ().Register ();
new ColorFormatter ().Register ();
enumFormatter = new EnumFormatter ();
enumFormatter.Register ();
typeFormatter = new TypeFormatter ();
typeFormatter.Register ();
singleRankArrayFormatter = new SingleRankArrayFormatter ();
singleRankArrayFormatter.Register ();
typeConverterFormatter = new TypeConverterFormatter ();
typeConverterFormatter.Register ();
binaryObjectFormatter = new BinaryObjectFormatter ();
binaryObjectFormatter.Register ();
}
// 0 == null
static byte nextId = 1;
public ObjectFormatter ()
{
PrimaryId = nextId ++;
if (NumberOfIds == 1)
return;
SecondaryId = nextId ++;
if (NumberOfIds == 2)
return;
TertiaryId = nextId ++;
if (NumberOfIds == 3)
return;
throw new Exception ();
}
protected readonly byte PrimaryId, SecondaryId = 255, TertiaryId = 255;
protected abstract void Write (BinaryWriter w, object o, WriterContext ctx);
protected abstract object Read (byte token, BinaryReader r, ReaderContext ctx);
protected abstract Type Type { get; }
protected virtual int NumberOfIds { get { return 1; } }
public virtual void Register ()
{
writeMap [Type] = this;
readMap [PrimaryId] = this;
if (SecondaryId != 255) {
readMap [SecondaryId] = this;
if (TertiaryId != 255)
readMap [TertiaryId] = this;
}
}
public static void WriteObject (BinaryWriter w, object o, WriterContext ctx)
{
#if TRACE
if (o != null) {
Trace.WriteLine (String.Format ("Writing {0} (type: {1})", o, o.GetType ()));
Trace.Indent ();
} else {
Trace.WriteLine ("Writing null");
}
long pos = w.BaseStream.Position;
#endif
if (o == null) {
w.Write ((byte) 0);
return;
}
Type t = o.GetType ();
#if TRACE
Trace.WriteLine (String.Format ("Looking up formatter for type {0}", t));
#endif
ObjectFormatter fmt = writeMap [t] as ObjectFormatter;
#if TRACE
Trace.WriteLine (String.Format ("Formatter from writeMap: '{0}'", fmt));
#endif
if (fmt == null) {
// Handle abstract types here
if (o is Type)
fmt = typeFormatter;
else if (t.IsEnum)
fmt = enumFormatter;
else if (t.IsArray && ((Array) o).Rank == 1)
fmt = singleRankArrayFormatter;
else {
TypeConverter converter;
converter = TypeDescriptor.GetConverter (o);
#if TRACE
Trace.WriteLine (String.Format ("Type converter: '{0}' (to string: {1}; from {2}: {3})",
converter,
converter != null ? converter.CanConvertTo (typeof (string)) : false,
t,
converter != null ? converter.CanConvertFrom (t) : false));
#endif
// Do not use the converter if it's an instance of
// TypeConverter itself - it reports it is able to
// convert to string, but it's only a conversion
// consisting of a call to ToString() with no
// reverse conversion supported. This leads to
// problems when deserializing the object.
if (converter == null || converter.GetType () == typeof (TypeConverter) ||
!converter.CanConvertTo (typeof (string)) || !converter.CanConvertFrom (typeof (string)))
fmt = binaryObjectFormatter;
else {
typeConverterFormatter.Converter = converter;
fmt = typeConverterFormatter;
}
}
}
#if TRACE
Trace.WriteLine (String.Format ("Writing with formatter '{0}'", fmt.GetType ()));
#endif
fmt.Write (w, o, ctx);
#if TRACE
Trace.Unindent ();
Trace.WriteLine (String.Format ("Wrote {0} (type: {1}) {2} bytes", o, o.GetType (), w.BaseStream.Position - pos));
#endif
}
public static object ReadObject (BinaryReader r, ReaderContext ctx)
{
byte sig = r.ReadByte ();
if (sig == 0)
return null;
return readMap [sig].Read (sig, r, ctx);
}
protected void Write7BitEncodedInt (BinaryWriter w, int value)
{
do {
int high = (value >> 7) & 0x01ffffff;
byte b = (byte)(value & 0x7f);
if (high != 0)
b = (byte)(b | 0x80);
w.Write(b);
value = high;
} while(value != 0);
}
protected int Read7BitEncodedInt (BinaryReader r)
{
int ret = 0;
int shift = 0;
byte b;
do {
b = r.ReadByte();
ret = ret | ((b & 0x7f) << shift);
shift += 7;
} while ((b & 0x80) == 0x80);
return ret;
}
}
#region Primitive Formatters
class StringFormatter : ObjectFormatter
{
protected override void Write (BinaryWriter w, object o, WriterContext ctx)
{
if (ctx.RegisterCache (o)) {
w.Write (SecondaryId);
w.Write (ctx.Key);
} else {
w.Write (PrimaryId);
w.Write ((string)o);
}
}
protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
{
if (token == PrimaryId) {
string s = r.ReadString ();
ctx.CacheItem (s);
return s;
} else {
return ctx.GetCache (r.ReadInt16 ());
}
}
protected override Type Type {
get { return typeof (string); }
}
protected override int NumberOfIds {
get { return 2; }
}
}
class IndexedStringFormatter : StringFormatter
{
protected override void Write (BinaryWriter w, object o, WriterContext ctx)
{
IndexedString s = o as IndexedString;
if (s == null)
throw new InvalidOperationException ("object is not of the IndexedString type");
base.Write (w, s.Value, ctx);
}
protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
{
string s = base.Read (token, r, ctx) as string;
if (String.IsNullOrEmpty (s))
throw new InvalidOperationException ("string must not be null or empty.");
return new IndexedString (s);
}
protected override Type Type {
get { return typeof (IndexedString); }
}
protected override int NumberOfIds {
get { return 2; }
}
}
class Int64Formatter : ObjectFormatter
{
protected override void Write (BinaryWriter w, object o, WriterContext ctx)
{
w.Write (PrimaryId);
w.Write ((long)o);
}
protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
{
return r.ReadInt64 ();
}
protected override Type Type {
get { return typeof (long); }
}
}
class Int32Formatter : ObjectFormatter
{
protected override void Write (BinaryWriter w, object o, WriterContext ctx)
{
int i = (int) o;
if ((int)(byte) i == i) {
w.Write (SecondaryId);
w.Write ((byte) i);
} else {
w.Write (PrimaryId);
w.Write (i);
}
}
protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
{
if (token == PrimaryId)
return r.ReadInt32 ();
else
return (int) r.ReadByte ();
}
protected override Type Type {
get { return typeof (int); }
}
protected override int NumberOfIds {
get { return 2; }
}
}
class Int16Formatter : ObjectFormatter
{
protected override void Write (BinaryWriter w, object o, WriterContext ctx)
{
w.Write (PrimaryId);
w.Write ((short)o);
}
protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
{
return r.ReadInt16 ();
}
protected override Type Type {
get { return typeof (short); }
}
}
class ByteFormatter : ObjectFormatter
{
protected override void Write (BinaryWriter w, object o, WriterContext ctx)
{
w.Write (PrimaryId);
w.Write ((byte)o);
}
protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
{
return r.ReadByte ();
}
protected override Type Type {
get { return typeof (byte); }
}
}
class BooleanFormatter : ObjectFormatter
{
protected override void Write (BinaryWriter w, object o, WriterContext ctx)
{
if ((bool)o == true)
w.Write (PrimaryId);
else
w.Write (SecondaryId);
}
protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
{
return token == PrimaryId;
}
protected override Type Type {
get { return typeof (bool); }
}
protected override int NumberOfIds {
get { return 2; }
}
}
class CharFormatter : ObjectFormatter
{
protected override void Write (BinaryWriter w, object o, WriterContext ctx)
{
w.Write (PrimaryId);
w.Write ((char) o);
}
protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
{
return r.ReadChar ();
}
protected override Type Type {
get { return typeof (char); }
}
}
class DateTimeFormatter : ObjectFormatter
{
protected override void Write (BinaryWriter w, object o, WriterContext ctx)
{
w.Write (PrimaryId);
w.Write (((DateTime) o).Ticks);
}
protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
{
return new DateTime (r.ReadInt64 ());
}
protected override Type Type {
get { return typeof (DateTime); }
}
}
class PairFormatter : ObjectFormatter
{
protected override void Write (BinaryWriter w, object o, WriterContext ctx)
{
Pair p = (Pair) o;
w.Write (PrimaryId);
WriteObject (w, p.First, ctx);
WriteObject (w, p.Second, ctx);
}
protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
{
Pair p = new Pair ();
p.First = ReadObject (r, ctx);
p.Second = ReadObject (r, ctx);
return p;
}
protected override Type Type {
get { return typeof (Pair); }
}
}
class TripletFormatter : ObjectFormatter
{
protected override void Write (BinaryWriter w, object o, WriterContext ctx)
{
Triplet t = (Triplet) o;
w.Write (PrimaryId);
WriteObject (w, t.First, ctx);
WriteObject (w, t.Second, ctx);
WriteObject (w, t.Third, ctx);
}
protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
{
Triplet t = new Triplet ();
t.First = ReadObject (r, ctx);
t.Second = ReadObject (r, ctx);
t.Third = ReadObject (r, ctx);
return t;
}
protected override Type Type {
get { return typeof (Triplet); }
}
}
class ArrayListFormatter : ObjectFormatter
{
protected override void Write (BinaryWriter w, object o, WriterContext ctx)
{
ArrayList l = (ArrayList) o;
w.Write (PrimaryId);
Write7BitEncodedInt (w, l.Count);
for (int i = 0; i < l.Count; i++)
WriteObject (w, l [i], ctx);
}
protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
{
int len = Read7BitEncodedInt (r);
ArrayList l = new ArrayList (len);
for (int i = 0; i < len; i++)
l.Add (ReadObject (r, ctx));
return l;
}
protected override Type Type {
get { return typeof (ArrayList); }
}
}
class HashtableFormatter : ObjectFormatter
{
protected override void Write (BinaryWriter w, object o, WriterContext ctx)
{
Hashtable ht = (Hashtable) o;
w.Write (PrimaryId);
Write7BitEncodedInt (w, ht.Count);
foreach (DictionaryEntry de in ht) {
WriteObject (w, de.Key, ctx);
WriteObject (w, de.Value, ctx);
}
}
protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
{
int len = Read7BitEncodedInt (r);
Hashtable ht = new Hashtable (len);
for (int i = 0; i < len; i++) {
object key = ReadObject (r, ctx);
object val = ReadObject (r, ctx);
ht.Add (key, val);
}
return ht;
}
protected override Type Type {
get { return typeof (Hashtable); }
}
}
class ObjectArrayFormatter : ObjectFormatter
{
protected override void Write (BinaryWriter w, object o, WriterContext ctx)
{
object [] val = (object []) o;
w.Write (PrimaryId);
Write7BitEncodedInt (w, val.Length);
for (int i = 0; i < val.Length; i++)
WriteObject (w, val [i], ctx);
}
protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
{
int len = Read7BitEncodedInt (r);
object [] ret = new object [len];
for (int i = 0; i < len; i++)
ret [i] = ReadObject (r, ctx);
return ret;
}
protected override Type Type {
get { return typeof (object []); }
}
}
#endregion
#region System.Web Optimizations
class ColorFormatter : ObjectFormatter
{
protected override void Write (BinaryWriter w, object o, WriterContext ctx)
{
Color c = (Color) o;
if (c.IsEmpty || c.IsKnownColor) {
w.Write (SecondaryId);
if (c.IsEmpty)
w.Write (-1); //isempty marker
else
w.Write ((int) c.ToKnownColor ());
} else {
w.Write (PrimaryId);
w.Write (c.ToArgb ());
}
}
protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
{
int value = r.ReadInt32 ();
if (token == PrimaryId)
return Color.FromArgb (value);
else {
if (value == -1) //isempty marker
return Color.Empty;
return Color.FromKnownColor ((KnownColor)value);
}
}
protected override Type Type {
get { return typeof (Color); }
}
protected override int NumberOfIds {
get { return 2; }
}
}
#endregion
#region Special Formatters
class EnumFormatter : ObjectFormatter
{
protected override void Write (BinaryWriter w, object o, WriterContext ctx)
{
object value = Convert.ChangeType (o, ((Enum) o).GetTypeCode ());
w.Write (PrimaryId);
WriteObject (w, o.GetType (), ctx);
WriteObject (w, value, ctx);
}
protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
{
Type t = (Type) ReadObject (r, ctx);
object value = ReadObject (r, ctx);
return Enum.ToObject (t, value);
}
protected override Type Type {
get { return typeof (Enum); }
}
}
class TypeFormatter : ObjectFormatter
{
protected override void Write (BinaryWriter w, object o, WriterContext ctx)
{
if (ctx.RegisterCache (o)) {
w.Write (SecondaryId);
w.Write (ctx.Key);
} else {
w.Write (PrimaryId);
w.Write (((Type) o).FullName);
// We should cache the name of the assembly
w.Write (((Type) o).Assembly.FullName);
}
}
protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
{
if (token == PrimaryId) {
string type = r.ReadString ();
string assembly = r.ReadString ();
Type t = Assembly.Load (assembly).GetType (type);
ctx.CacheItem (t);
return t;
} else {
return ctx.GetCache (r.ReadInt16 ());
}
}
protected override Type Type {
get { return typeof (Type); }
}
protected override int NumberOfIds {
get { return 2; }
}
}
class SingleRankArrayFormatter : ObjectFormatter
{
readonly BinaryFormatter _binaryFormatter = new BinaryFormatter ();
protected override void Write (BinaryWriter w, object o, WriterContext ctx)
{
Array val = (Array) o;
if (val.GetType ().GetElementType ().IsPrimitive) {
w.Write (SecondaryId);
_binaryFormatter.Serialize (w.BaseStream, o);
return;
}
w.Write (PrimaryId);
WriteObject (w, val.GetType ().GetElementType (), ctx);
Write7BitEncodedInt (w, val.Length);
for (int i = 0; i < val.Length; i++)
WriteObject (w, val.GetValue (i), ctx);
}
protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
{
if (token == SecondaryId)
return _binaryFormatter.Deserialize (r.BaseStream);
Type t = (Type) ReadObject (r, ctx);
int len = Read7BitEncodedInt (r);
Array val = Array.CreateInstance (t, len);
for (int i = 0; i < len; i++)
val.SetValue (ReadObject (r, ctx), i);
return val;
}
protected override Type Type {
get { return typeof (Array); }
}
protected override int NumberOfIds {
get { return 2; }
}
}
class FontUnitFormatter : StringFormatter
{
protected override void Write (BinaryWriter w, object o, WriterContext ctx)
{
base.Write (w, o.ToString (), ctx);
}
protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
{
return FontUnit.Parse ((string) base.Read (token, r, ctx));
}
protected override Type Type {
get { return typeof (FontUnit); }
}
}
class UnitFormatter : StringFormatter
{
protected override void Write (BinaryWriter w, object o, WriterContext ctx)
{
base.Write (w, o.ToString (), ctx);
}
protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
{
return Unit.Parse ((string) base.Read (token, r, ctx));
}
protected override Type Type {
get { return typeof (Unit); }
}
}
class TypeConverterFormatter : StringFormatter
{
TypeConverter converter;
protected override void Write (BinaryWriter w, object o, WriterContext ctx)
{
w.Write (PrimaryId);
ObjectFormatter.WriteObject (w, o.GetType (), ctx);
string v = (string) converter.ConvertTo (null, Helpers.InvariantCulture,
o, typeof (string));
base.Write (w, v, ctx);
}
protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
{
Type t = (Type) ObjectFormatter.ReadObject (r, ctx);
converter = TypeDescriptor.GetConverter (t);
token = r.ReadByte ();
string v = (string) base.Read (token, r, ctx);
return converter.ConvertFrom (null, Helpers.InvariantCulture, v);
}
protected override Type Type {
get { return typeof (TypeConverter); }
}
public TypeConverter Converter {
set { converter = value; }
}
}
class BinaryObjectFormatter : ObjectFormatter
{
protected override void Write (BinaryWriter w, object o, WriterContext ctx)
{
w.Write (PrimaryId);
MemoryStream ms = new MemoryStream (128);
new BinaryFormatter ().Serialize (ms, o);
byte [] buf = ms.GetBuffer ();
Write7BitEncodedInt (w, buf.Length);
w.Write (buf, 0, buf.Length);
}
protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
{
int len = Read7BitEncodedInt (r);
byte [] buf = r.ReadBytes (len);
if (buf.Length != len)
throw new Exception ();
return new BinaryFormatter ().Deserialize (new MemoryStream (buf));
}
protected override Type Type {
get { return typeof (object); }
}
}
#endregion
#endregion
}
}