private static void ProcessExtraData(SerializationContext read, int fieldTag, WireType wireType, SerializationContext write) { int len; switch (wireType) { case WireType.Variant: len = read.ReadRawVariant(); write.WriteBlock(read.Workspace, 0, len); break; case WireType.Fixed32: read.ReadBlock(4); write.WriteBlock(read.Workspace, 0, 4); break; case WireType.Fixed64: read.ReadBlock(8); write.WriteBlock(read.Workspace, 0, 8); break; case WireType.String: len = read.DecodeInt32(); write.EncodeInt32(len); read.WriteTo(write, len); break; case WireType.StartGroup: read.StartGroup(fieldTag); uint prefix; while (read.TryReadFieldPrefix(out prefix)) { write.EncodeUInt32(prefix); Serializer.ParseFieldToken(prefix, out wireType, out fieldTag); if (wireType == WireType.EndGroup) { read.EndGroup(fieldTag); break; } ProcessExtraData(read, fieldTag, wireType, write); } break; case WireType.EndGroup: throw new ProtoException("End-group not expected at this location"); default: throw new ProtoException("Unknown wire-type " + wireType); } }
/// <summary> /// Reads the given value(s) from the instance's stream; the serializer /// is inferred from TValue and format. For singletons, each occurrence /// is merged [only applies for sub-objects], and the composed /// value if yielded once; otherwise ("repeated") each occurrence /// is yielded separately. /// </summary> /// <remarks>Needs to be public to be callable thru reflection in Silverlight</remarks> public static IEnumerable <TValue> GetExtendedValuesTyped <TSource, TValue>( TSource instance, int tag, DataFormat format, bool singleton, bool allowDefinedTag) where TSource : class, IExtensible { if (instance == null) { throw new ArgumentNullException("instance"); } if (!allowDefinedTag) { Serializer <TSource> .CheckTagNotInUse(tag); } Property <TValue, TValue> prop = PropertyFactory.CreatePassThru <TValue>(tag, ref format); List <Property <TValue, TValue> > props = new List <Property <TValue, TValue> >(); foreach (Property <TValue, TValue> altProp in prop.GetCompatibleReaders()) { props.Add(altProp); } IExtension extn = instance.GetExtensionObject(false); if (extn == null) { yield break; } Stream stream = extn.BeginQuery(); TValue lastValue = default(TValue); bool hasValue = false; try { SerializationContext ctx = new SerializationContext(stream, null); uint fieldPrefix; while (ctx.TryReadFieldPrefix(out fieldPrefix)) { WireType a; int b; Serializer.ParseFieldToken(fieldPrefix, out a, out b); Property <TValue, TValue> actProp = null; if (fieldPrefix == prop.FieldPrefix) { actProp = prop; } else { foreach (Property <TValue, TValue> x in props) { if (x.FieldPrefix == fieldPrefix) { actProp = x; break; } } } if (actProp != null) { TValue value = actProp.DeserializeImpl(lastValue, ctx); hasValue = true; if (singleton) { // merge with later values before returning lastValue = value; } else { // return immediately; no merge yield return(value); } } else { int readTag; WireType wireType; Serializer.ParseFieldToken(fieldPrefix, out wireType, out readTag); if (readTag == tag) { // we can't deserialize data of that type - for example, // have received Fixed32 for a string, etc throw new ProtoException(string.Format( "Unexpected wire-type ({0}) found for tag {1}.", wireType, readTag)); } // skip all other tags Serializer.SkipData(ctx, readTag, wireType); } } } finally { extn.EndQuery(stream); } if (singleton && hasValue) { yield return(lastValue); } }
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 { Debug.WriteLine("Dropping:" + fieldTag); // 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 }