/// <summary> /// Stores the given value into the instance's stream; the serializer /// is inferred from TValue and format. /// </summary> /// <remarks>Needs to be public to be callable thru reflection in Silverlight</remarks> public static void AppendExtendValueTyped <TSource, TValue>( TSource instance, int tag, DataFormat format, TValue value) where TSource : class, IExtensible { Serializer <TSource> .CheckTagNotInUse(tag); Property <TValue, TValue> prop = PropertyFactory.CreatePassThru <TValue>(tag, ref format); IExtension extn = instance.GetExtensionObject(true); if (extn == null) { throw new InvalidOperationException("No extension object available; appended data would be lost."); } Stream stream = extn.BeginAppend(); try { SerializationContext ctx = new SerializationContext(stream, null); ctx.Push(instance); // for recursion detection prop.Serialize(value, ctx); ctx.Pop(instance); ctx.Flush(); extn.EndAppend(stream, true); } catch { extn.EndAppend(stream, false); throw; } }
public int Serialize(IExtension extension) { if (extension == null) return 0; Stream stream = extension.BeginAppend(); try { SerializationContext ctx = new SerializationContext(stream, null); int len = Serialize(ctx); ctx.Flush(); extension.EndAppend(stream, true); return len; } catch { extension.EndAppend(stream, false); throw; } }
internal static int SerializeChecked(T instance, SerializationContext destination) { if (readProps == null) { Build(); } if (instance == null) { throw new ArgumentNullException("instance"); } if (destination == null) { throw new ArgumentNullException("destination"); } int len = Serialize(instance, destination); destination.CheckStackClean(); destination.Flush(); return(len); }
/// <summary> /// As per the public ChangeType, but allows for workspace-sharing to reduce buffer overhead. /// </summary> internal static TNewType ChangeType <TOldType, TNewType>(TOldType instance, SerializationContext context) { if (instance == null) { return(default(TNewType)); // GIGO } using (MemoryStream ms = new MemoryStream()) { SerializationContext tmpCtx = new SerializationContext(ms, context); Serialize <TOldType>(ms, instance); tmpCtx.Flush(); ms.Position = 0; TNewType result = Deserialize <TNewType>(ms); if (context != null) { context.ReadFrom(tmpCtx); } return(result); } }
public int Serialize(IExtension extension) { if (extension == null) { return(0); } Stream stream = extension.BeginAppend(); try { SerializationContext ctx = new SerializationContext(stream, null); int len = Serialize(ctx); ctx.Flush(); extension.EndAppend(stream, true); return(len); } catch { extension.EndAppend(stream, false); throw; } }
internal static void Deserialize <TCreation>(ref T instance, SerializationContext context) where TCreation : class, T { uint prefix = 0; if (context == null) { throw new ArgumentNullException("context"); } #if !CF try { #endif if (instance != null) { Callback(CallbackType.BeforeDeserialization, instance); } context.Push(); int propCount = readProps.Length; //context.CheckSpace(); IExtensible extensible = instance as IExtensible; IExtension extn = null; Property <T> prop = propCount == 0 ? null : readProps[0]; int lastIndex = prop == null ? -1 : 0; uint lastPrefix = prop == null ? uint.MaxValue : prop.FieldPrefix; while (context.TryReadFieldPrefix(out prefix)) { // scan for the correct property bool foundTag = false; if (prefix == lastPrefix) { foundTag = true; } else if (prefix > lastPrefix) { for (int i = lastIndex + 1; i < propCount; i++) { if (readProps[i].FieldPrefix == prefix) { prop = readProps[i]; lastIndex = i; lastPrefix = prefix; foundTag = true; break; } if (readProps[i].FieldPrefix > prefix) { break; // too far } } } else { for (int i = lastIndex - 1; i >= 0; i--) { if (readProps[i].FieldPrefix == prefix) { prop = readProps[i]; lastIndex = i; lastPrefix = prefix; foundTag = true; break; } if (readProps[i].FieldPrefix < prefix) { break; // too far } } } if (!foundTag) { // check for subclass creation foreach (KeyValuePair <Type, Property <T, T> > subclass in subclasses) { // deserialize the nested data if (prefix == subclass.Value.FieldPrefix) { foundTag = true; instance = subclass.Value.DeserializeImpl(instance, context); break; } } if (foundTag) { continue; // nothing more to do for this... } } // not a sub-class, but *some* data there, so create an object if (instance == null) { instance = ObjectFactory <TCreation> .Create(); Callback(CallbackType.ObjectCreation, instance); extensible = instance as IExtensible; } if (foundTag) { // found it by seeking; deserialize and continue // ReSharper disable PossibleNullReferenceException try { prop.Deserialize(instance, context); } catch (UnexpectedDataException ex) { if (extensible != null) { if (extn == null) { extn = extensible.GetExtensionObject(true); } ex.Serialize(extn); } // DON'T re-throw; we've handled this } // ReSharper restore PossibleNullReferenceException continue; } WireType wireType; int fieldTag; Serializer.ParseFieldToken(prefix, out wireType, out fieldTag); if (wireType == WireType.EndGroup) { context.EndGroup(fieldTag); break; // this ends the entity, so stop the loop } // so we couldn't find it... if (extensible != null) { if (extn == null) { extn = extensible.GetExtensionObject(true); } Stream extraStream = extn.BeginAppend(); try { SerializationContext extraData = new SerializationContext(extraStream, null); // copy the data into the output stream // ReSharper disable PossibleNullReferenceException extraData.EncodeUInt32(prefix); // ReSharper restore PossibleNullReferenceException ProcessExtraData(context, fieldTag, wireType, extraData); extraData.Flush(); extn.EndAppend(extraStream, true); } catch { extn.EndAppend(extraStream, false); throw; } } else { // unexpected fields for an inextensible object; discard the data Serializer.SkipData(context, fieldTag, wireType); } } // final chance to create an instance - this only gets invoked for empty // messages (otherwise instance should already be non-null) if (instance == null) { instance = ObjectFactory <T> .Create(); Callback(CallbackType.ObjectCreation, instance); } context.Pop(); Callback(CallbackType.AfterDeserialization, instance); #if !CF } catch (Exception ex) { const string ErrorDataKey = "protoSource"; if (!ex.Data.Contains(ErrorDataKey)) { ex.Data.Add(ErrorDataKey, string.Format("tag={0}; wire-type={1}; offset={2}; depth={3}; type={4}", (int)(prefix >> 3), (WireType)(prefix & 7), context.Position, context.Depth, typeof(T).FullName)); } throw; } #endif }
internal int WriteLengthPrefixed <TValue>(TValue value, uint underEstimatedLength, ILengthProperty <TValue> property) { Flush(); // commit to the stream before monkeying with the buffers... MemoryStream ms = stream as MemoryStream; if (ms != null) { // we'll write to out current stream, optimising // for the case when the length-prefix is 1-byte; // if not we'll have to BlockCopy int startIndex = (int)ms.Position; uint guessLength = underEstimatedLength, guessPrefixLength = (uint)this.EncodeUInt32(guessLength), actualLength = (uint)property.Serialize(value, this); if (guessLength == actualLength) { // good guess! nothing to do... return((int)(guessPrefixLength + actualLength)); } uint actualPrefixLength = (uint)SerializationContext.GetLength(actualLength); Flush(); // commit to the stream before we start messing with it... if (actualPrefixLength < guessPrefixLength) { throw new ProtoException("Internal error; the serializer over-estimated the length. Sorry, but this shouldn't have happened."); } else if (actualPrefixLength > guessPrefixLength) { // our guess of the length turned out to be bad; we need to // fix things... // extend the buffer to ensure we have space for (uint i = actualPrefixLength - guessPrefixLength; i > 0; i--) { ms.WriteByte(0); position++; } // move the data // (note; we MUST call GetBuffer *after* extending it, // otherwise there the buffer might change if we extend // over a boundary) byte[] buffer = ms.GetBuffer(); Buffer.BlockCopy(buffer, (int)(startIndex + guessPrefixLength), buffer, (int)(startIndex + actualPrefixLength), (int)actualLength); } // back-fill the actual length into the buffer SerializationContext.EncodeUInt32(actualLength, ms.GetBuffer(), startIndex); return((int)(actualPrefixLength + actualLength)); } else { // create a temporary stream and write the final result using (ms = new MemoryStream()) { SerializationContext ctx = new SerializationContext(ms, this); int len = property.Serialize(value, ctx); ctx.Flush(); this.ReadFrom(ctx); int preambleLen = this.EncodeInt32(len); byte[] buffer = ms.GetBuffer(); this.WriteBlock(buffer, 0, len); return(preambleLen + len); } } }
public void WriteTo(SerializationContext destination, int length) { destination.Flush(); WriteTo(destination.stream, length); destination.position += length; }