Beispiel #1
0
        private PacketDefinition(IFieldReader reader)
        {
            m_TypeName = reader.ReadString();
            m_Version  = reader.ReadInt32();
            int fieldCount = reader.ReadInt32();

            for (int i = 0; i < fieldCount; i++)
            {
                string    fieldName = reader.ReadString();
                FieldType fieldType = (FieldType)reader.ReadInt32();
                m_Fields.Add(new FieldDefinition(fieldName, fieldType));
            }

            // Handle the possiblity that a Packet aggregates lower level packets
            int subPacketCount = reader.ReadInt32();

            m_SubPackets = new List <PacketDefinition>();
            for (int i = 0; i < subPacketCount; i++)
            {
                // We need to call the static ReadPacketDefinition(reader) in order to
                // read and process the cacheable, version, and dynamic name fields which
                // also exist for each subPacket definition.  Fixed as part of Case #165
                PacketDefinition subPacket = ReadPacketDefinition(reader);
                m_SubPackets.Add(subPacket);
            }
        }
Beispiel #2
0
        /// <summary>
        /// Returns a PacketDefinition from the stream (including nested PacketDefinition
        /// objects for cases in which an IPacket is subclassed and has serialized state
        /// at multiple levels).
        /// </summary>
        /// <param name="reader">Stream to read data from</param>
        /// <returns>PacketDefinition (including nested definitions for subclassed packets)</returns>
        public static PacketDefinition ReadPacketDefinition(IFieldReader reader)
        {
            bool cachedPacket = reader.ReadBool();
            int  nestingDepth = reader.ReadInt32();

            if (nestingDepth < 1)
            {
                throw new GibraltarException(string.Format(CultureInfo.InvariantCulture, "While reading the definition of the next packet, the number of types in the definition was read as {0} which is less than 1.", nestingDepth));
            }


            string dynamicTypeName = reader.ReadString();

            PacketDefinition[] definitions = new PacketDefinition[nestingDepth];
            for (int i = 0; i < nestingDepth; i++)
            {
                definitions[i] = new PacketDefinition(reader);
                if (i > 0)
                {
                    definitions[i].m_BasePacket = definitions[i - 1];
                }
            }

            PacketDefinition topLevelDefinition = definitions[nestingDepth - 1];

            topLevelDefinition.m_IsCachable      = cachedPacket;
            topLevelDefinition.m_DynamicTypeName = dynamicTypeName;
            return(topLevelDefinition);
        }
        public void SetField(string fieldName, object value)
        {
            if (string.IsNullOrEmpty(fieldName))
            {
                throw new ArgumentNullException(nameof(fieldName));
            }

            if (m_ReadOnly)
            {
                throw new InvalidOperationException("The packet has been deserialized and is read-only");
            }

            //find the field index for the field name
            FieldDefinition fieldDefinition = m_Definition.Fields[fieldName];
            int             fieldIndex      = m_Definition.Fields.IndexOf(fieldDefinition);

            //now we need to check the value for sanity.
            if (value != null)
            {
                FieldType valueType = PacketDefinition.GetSerializableType(value.GetType());
                if (fieldDefinition.IsCompatible(valueType) == false)
                {
                    throw new ArgumentException("The provided value's type doesn't match the definition for the field.", nameof(value));
                }
            }

            //now that we know we're of the right type, store it away.
            m_Values[fieldIndex] = value;
        }
 /// <summary>
 /// Create a storage summary instance referencing a particualr PacketDefinition
 /// </summary>
 public PacketTypeStorageSummary(PacketDefinition packetDefinition)
 {
     QualifiedTypeName = packetDefinition.QualifiedTypeName;
     TypeName          = packetDefinition.TypeName;
     PacketCount       = packetDefinition.PacketCount;
     PacketSize        = packetDefinition.PacketSize;
 }
Beispiel #5
0
        /// <summary>
        /// Read and return the next IPacket from the stream
        /// </summary>
        public IPacket ReadPacket(Stream packetStream)
        {
            m_Reader.ReplaceStream(packetStream);

            PacketDefinition definition;
            int typeIndex = (int)m_Reader.ReadUInt32();

            if (typeIndex >= m_cachedTypes.Count)
            {
                definition = PacketDefinition.ReadPacketDefinition(m_Reader);
                if (string.IsNullOrEmpty(definition.TypeName))
                {
                    //we're hosed...  we won't be able to parse this packet.
                    throw new GibraltarSerializationException("The type name of the definition is null, which can't be correct.  The packet stream is corrupted.", true);
                }

                m_cachedTypes.Add(definition);
                m_cachedTypes.Commit();
            }
            else
            {
                definition = m_cachedTypes[typeIndex];
            }
            definition.PacketCount++;
            definition.PacketSize += packetStream.Length;

            IPacketFactory factory = m_PacketFactory.GetPacketFactory(definition.TypeName);
            IPacket        packet  = factory.CreatePacket(definition, m_Reader);

            return(packet);
        }
Beispiel #6
0
 public PacketDefinition(string typeName, int version, bool canHaveRequiredPackets)
 {
     m_TypeName               = typeName;
     m_Version                = version;
     m_BasePacket             = null;
     m_CanHaveRequiredPackets = canHaveRequiredPackets;
     m_SubPackets             = new List <PacketDefinition>();
 }
Beispiel #7
0
        /// <summary>
        /// Read and return the next IPacket from the stream
        /// </summary>
        public IPacket Read()
        {
#if ADD_GUARD_BYTES
            byte[] preamble = new byte[4];
            m_Stream.Read(preamble, 0, 4);

            //now compare it against the preamble.
            CompareArrays(preamble, PacketWriter.s_PreambleGuardPattern);
#endif

            int packetSize = (int)m_Reader.ReadUInt64();

            //if the packet size is less than one, that's obviously wrong
            if (packetSize < 1)
            {
                throw new GibraltarSerializationException("The size of the next packet is smaller than 1 byte or negative, which can't be correct.  The packet stream is corrupted.", true);
            }

            // TODO: There's got to be a more efficient way to get this done
            byte[] buffer = new byte[packetSize];
            m_Stream.Read(buffer, 0, packetSize);
            IFieldReader bufferReader = new FieldReader(new MemoryStream(buffer), m_Reader.Strings, m_MajorVersion, m_MinorVersion);

            PacketDefinition definition;
            int typeIndex = (int)bufferReader.ReadUInt32();
            if (typeIndex >= m_cachedTypes.Count)
            {
                definition = PacketDefinition.ReadPacketDefinition(bufferReader);
                if (string.IsNullOrEmpty(definition.TypeName))
                {
                    //we're hosed...  we won't be able to parse this packet.
                    throw new GibraltarSerializationException("The type name of the definition is null, which can't be correct.  The packet stream is corrupted.", true);
                }

                m_cachedTypes.Add(definition);
                m_cachedTypes.Commit();
            }
            else
            {
                definition = m_cachedTypes[typeIndex];
            }

            IPacketFactory factory = m_PacketFactory.GetPacketFactory(definition.TypeName);
            IPacket        packet  = factory.CreatePacket(definition, bufferReader);

            //we used to populate a packet cache here, but a cached packet should be read just once - it shouldn't be in the stream
            //(and I changed PacketWriter to enforce that)

#if ADD_GUARD_BYTES
            byte[] postamble = new byte[4];
            m_Stream.Read(postamble, 0, 4);

            //now compare it against the preamble.
            CompareArrays(postamble, PacketWriter.s_PostambleGuardPattern);
#endif

            return(packet);
        }
Beispiel #8
0
        /// <summary>
        /// Write an object to the stream as its serializable type
        /// </summary>
        /// <param name="value">The object (or boxed integral value) to write.</param>
        public void Write(object value)
        {
            //but what type are we going to use?
            FieldType serializedType = PacketDefinition.GetSerializableType(value.GetType());

            Write((Int32)serializedType); // cast to Int32 to match ReadFieldType()

            Write(value, serializedType);
        }
Beispiel #9
0
        /// <summary>
        /// Compare this PacketDefinition to another to verify that they are equivalent
        /// for purposes of order-dependant field deserialization.
        /// </summary>
        public bool Equals(PacketDefinition other)
        {
            // Verify that base packets are equivalent
            if (BasePacket == null)
            {
                if (other.BasePacket != null)
                {
                    return(false);
                }
            }
            else
            {
                if (other.BasePacket == null)
                {
                    return(false);
                }
                if (!BasePacket.Equals(other.BasePacket))
                {
                    return(false);
                }
            }

            // Verify that basic characteristics are equivalent
            if (TypeName != other.TypeName)
            {
                return(false);
            }
            if (Version != other.Version)
            {
                return(false);
            }
            if (Fields.Count != other.Fields.Count)
            {
                return(false);
            }

            // Verify that all fields are equivalent
            for (int i = 0; i < Fields.Count; i++)
            {
                if (Fields[i].Name != other.Fields[i].Name)
                {
                    return(false);
                }
                if (Fields[i].FieldType != other.Fields[i].FieldType)
                {
                    return(false);
                }
            }

            return(true);
        }
Beispiel #10
0
        /// <summary>
        /// Write the data needed to serialize the state of the packet
        /// </summary>
        /// <param name="packet">Object to be serialized, must implement IPacket</param>
        public void Write(IPacket packet)
        {
            //Before we do anything - is this a cached packet that's already been written out?
            ICachedPacket cachedPacket = packet as ICachedPacket;

            if (cachedPacket != null)
            {
                //it is cacheable - is it in the cache?
                if (m_PacketCache.Contains(cachedPacket))
                {
                    //good to go, we're done.
                    return;
                }
            }

            //First, we need to find out if there are any packets this guy depends on.  If there are,
            //they have to be serialized out first.  They may have been - they could be cached.
            //to do this, we'll need to get the definition.
            PacketDefinition previewDefinition;
            int previewTypeIndex = m_CachedTypes.IndexOf(packet);

            if (previewTypeIndex < 0)
            {
                //we're going to get the definition, BUT we're not going to cache it yet.
                //This is because we recurse on our self if there are required packets, and if one of those
                //packets is our same type, IT has to write out the definition so that it's on the stream
                //before the packet itself.
                previewDefinition = PacketDefinition.CreatePacketDefinition(packet);
            }
            else
            {
                previewDefinition = m_CachedTypes[previewTypeIndex];
            }

            Dictionary <IPacket, IPacket> requiredPackets = previewDefinition.GetRequiredPackets(packet);

            foreach (IPacket requiredPacket in requiredPackets.Values)
            {
                Write(requiredPacket); //this will handle if it's a cached packet and shouldn't be written out.
            }

            //Begin our "transactional" phase
            try
            {
                // This routine is written to either write a complete packet, or to write nothing.
                // As we build up the packet, we will write to a MemoryStream.  Only after we've
                // built up the complete packet will we write it to the actual stream.
                m_Buffer.SetLength(0);
                m_Buffer.Position = 0;

                // The first time a packet type is written, we send along a packet definition
                PacketDefinition definition;
                int typeIndex = m_CachedTypes.IndexOf(packet);
                if (typeIndex < 0)
                {
                    // Record that we've seen this type so we don't bother sending the PacketDefinition again
                    definition = PacketDefinition.CreatePacketDefinition(packet);
                    typeIndex  = m_CachedTypes.Count;
                    m_CachedTypes.Add(definition);

                    // Each packet always starts with a packet type index.  And the first time a new
                    // index is used, it is followed by the packet definition.
                    m_BufferWriter.Write((UInt32)typeIndex);
                    definition.WriteDefinition(m_BufferWriter);
                }
                else
                {
                    // If this type has been written before, just send the type index
                    m_BufferWriter.Write((UInt32)typeIndex);
                    definition = m_CachedTypes[typeIndex];
                }

                // if it's cacheable then we need to add it to our packet cache before we write it out
                if (definition.IsCachable)
                {
                    // In the case of an ICachedPacket, we need to add it to the cache.
                    // we'd have already bailed if it was in there.
                    // Note: Use previous cast for efficiency, but we must recast here *if* packet gets reassigned above
                    // Currently it does not get reassigned, so cachedPacket which we cast packet into above is still valid.
                    m_PacketCache.AddOrGet(cachedPacket);
                }

                //Finally, and it really is a long journey, we ask the definition to write out
                //the individual fields for the packet
                definition.WriteFields(packet, m_BufferWriter);
            }
            catch (Exception ex)
            {
                GC.KeepAlive(ex);
                Rollback();
                throw;
            }

#if ADD_GUARD_BYTES
            m_Stream.Write(s_PreambleGuardPattern, 0, s_PreambleGuardPattern.Length);
#endif

            // Write the data to the stream preceded by the length of this packet
            // NOTE: The logic below is careful to ensure that the length and payload is written in one call
            //       This is necessary to ensure that the GZipStream writes the whole packet in edge cases
            //       of writing the very last packet as an application is exiting.

            var          payloadLength = (int)m_Buffer.Position; // get the actual length of the payload
            MemoryStream encodedLength = FieldWriter.WriteLength(payloadLength);
            var          lengthLength  = (int)encodedLength.Length;

            var packetBytes = new byte[lengthLength + payloadLength];

            encodedLength.Position = 0; // reset the position in preparation to read the data back
            encodedLength.Read(packetBytes, 0, lengthLength);

            m_Buffer.Position = 0; // reset the position in preparation to read the data back
            m_Buffer.Read(packetBytes, lengthLength, payloadLength);

            m_Stream.Write(packetBytes, 0, packetBytes.Length);

#if ADD_GUARD_BYTES
            m_Stream.Write(s_PostambleGuardPattern, 0, s_PostambleGuardPattern.Length);
#endif

            Commit();
        }
Beispiel #11
0
 /// <summary>
 /// Read back the field values for the current packet.
 /// </summary>
 /// <param name="definition">The definition that was used to persist the packet.</param>
 /// <param name="packet">The serialized packet to read data from</param>
 void IPacket.ReadFields(PacketDefinition definition, SerializedPacket packet)
 {
     throw new System.NotImplementedException();
 }
Beispiel #12
0
        /// <summary>
        /// Read any packet based solely on its PacketDefinition
        /// </summary>
        /// <param name="definition">PacketDefinition describing the next packet in the stream</param>
        /// <param name="reader">Data stream to be read</param>
        public GenericPacket(PacketDefinition definition, IFieldReader reader)
        {
            if (definition.BasePacket != null)
            {
                m_BasePacket = new GenericPacket(definition.BasePacket, reader);
            }

            m_Definition  = definition;
            m_FieldValues = new object[definition.Fields.Count];

            for (int index = 0; index < definition.Fields.Count; index++)
            {
                switch (definition.Fields[index].FieldType)
                {
                case FieldType.Bool:
                    m_FieldValues[index] = reader.ReadBool();
                    break;

                case FieldType.BoolArray:
                    m_FieldValues[index] = reader.ReadBoolArray();
                    break;

                case FieldType.String:
                    m_FieldValues[index] = reader.ReadString();
                    break;

                case FieldType.StringArray:
                    m_FieldValues[index] = reader.ReadStringArray();
                    break;

                case FieldType.Int32:
                    m_FieldValues[index] = reader.ReadInt32();
                    break;

                case FieldType.Int32Array:
                    m_FieldValues[index] = reader.ReadInt32Array();
                    break;

                case FieldType.Int64:
                    m_FieldValues[index] = reader.ReadInt64();
                    break;

                case FieldType.Int64Array:
                    m_FieldValues[index] = reader.ReadInt64Array();
                    break;

                case FieldType.UInt32:
                    m_FieldValues[index] = reader.ReadUInt32();
                    break;

                case FieldType.UInt32Array:
                    m_FieldValues[index] = reader.ReadUInt32Array();
                    break;

                case FieldType.UInt64:
                    m_FieldValues[index] = reader.ReadUInt64();
                    break;

                case FieldType.UInt64Array:
                    m_FieldValues[index] = reader.ReadUInt64Array();
                    break;

                case FieldType.Double:
                    m_FieldValues[index] = reader.ReadDouble();
                    break;

                case FieldType.DoubleArray:
                    m_FieldValues[index] = reader.ReadDoubleArray();
                    break;

                case FieldType.TimeSpan:
                    m_FieldValues[index] = reader.ReadTimeSpan();
                    break;

                case FieldType.TimeSpanArray:
                    m_FieldValues[index] = reader.ReadTimeSpanArray();
                    break;

                case FieldType.DateTime:
                    m_FieldValues[index] = reader.ReadDateTime();
                    break;

                case FieldType.DateTimeArray:
                    m_FieldValues[index] = reader.ReadDateTimeArray();
                    break;

                case FieldType.Guid:
                    m_FieldValues[index] = reader.ReadGuid();
                    break;

                case FieldType.GuidArray:
                    m_FieldValues[index] = reader.ReadGuidArray();
                    break;

                case FieldType.DateTimeOffset:
                    m_FieldValues[index] = reader.ReadDateTimeOffset();
                    break;

                case FieldType.DateTimeOffsetArray:
                    m_FieldValues[index] = reader.ReadDateTimeOffsetArray();
                    break;

                default:
#if DEBUG
                    if (Debugger.IsAttached)
                    {
                        Debugger.Break();
                    }
#endif
                    throw new InvalidOperationException(string.Format("The field type {0} is unknown so we can't deserialize the packet ", definition.Fields[index].FieldType));
                }
            }
        }
Beispiel #13
0
        /// <summary>
        /// Write out all of the fields for the current packet
        /// </summary>
        /// <param name="definition">The definition that was used to persist the packet.</param>
        /// <param name="packet">The serialized packet to populate with data</param>
        void IPacket.WriteFields(PacketDefinition definition, SerializedPacket packet)
        {
            if (m_BasePacket != null)
            {
                ((IPacket)m_BasePacket).WriteFields(definition, packet);
            }

            for (int index = 0; index < m_Definition.Fields.Count; index++)
            {
                FieldDefinition fieldDefinition = m_Definition.Fields[index];
                switch (fieldDefinition.FieldType)
                {
                case FieldType.Bool:
                    packet.SetField(fieldDefinition.Name, (bool)m_FieldValues[index]);
                    break;

                case FieldType.BoolArray:
                    packet.SetField(fieldDefinition.Name, (bool[])m_FieldValues[index]);
                    break;

                case FieldType.String:
                    packet.SetField(fieldDefinition.Name, (string)m_FieldValues[index]);
                    break;

                case FieldType.StringArray:
                    packet.SetField(fieldDefinition.Name, (string[])m_FieldValues[index]);
                    break;

                case FieldType.Int32:
                    packet.SetField(fieldDefinition.Name, (Int32)m_FieldValues[index]);
                    break;

                case FieldType.Int32Array:
                    packet.SetField(fieldDefinition.Name, (Int32[])m_FieldValues[index]);
                    break;

                case FieldType.Int64:
                    packet.SetField(fieldDefinition.Name, (Int64)m_FieldValues[index]);
                    break;

                case FieldType.Int64Array:
                    packet.SetField(fieldDefinition.Name, (Int64[])m_FieldValues[index]);
                    break;

                case FieldType.UInt32:
                    packet.SetField(fieldDefinition.Name, (UInt32)m_FieldValues[index]);
                    break;

                case FieldType.UInt32Array:
                    packet.SetField(fieldDefinition.Name, (UInt32[])m_FieldValues[index]);
                    break;

                case FieldType.UInt64:
                    packet.SetField(fieldDefinition.Name, (UInt64)m_FieldValues[index]);
                    break;

                case FieldType.UInt64Array:
                    packet.SetField(fieldDefinition.Name, (UInt64[])m_FieldValues[index]);
                    break;

                case FieldType.Double:
                    packet.SetField(fieldDefinition.Name, (double)m_FieldValues[index]);
                    break;

                case FieldType.DoubleArray:
                    packet.SetField(fieldDefinition.Name, (double[])m_FieldValues[index]);
                    break;

                case FieldType.TimeSpan:
                    packet.SetField(fieldDefinition.Name, (TimeSpan)m_FieldValues[index]);
                    break;

                case FieldType.TimeSpanArray:
                    packet.SetField(fieldDefinition.Name, (TimeSpan[])m_FieldValues[index]);
                    break;

                case FieldType.DateTime:
                    packet.SetField(fieldDefinition.Name, (DateTime)m_FieldValues[index]);
                    break;

                case FieldType.DateTimeArray:
                    packet.SetField(fieldDefinition.Name, (DateTime[])m_FieldValues[index]);
                    break;

                case FieldType.Guid:
                    packet.SetField(fieldDefinition.Name, (Guid)m_FieldValues[index]);
                    break;

                case FieldType.GuidArray:
                    packet.SetField(fieldDefinition.Name, (Guid[])m_FieldValues[index]);
                    break;

                case FieldType.DateTimeOffset:
                    packet.SetField(fieldDefinition.Name, (DateTimeOffset)m_FieldValues[index]);
                    break;

                case FieldType.DateTimeOffsetArray:
                    packet.SetField(fieldDefinition.Name, (DateTimeOffset[])m_FieldValues[index]);
                    break;

                default:
#if DEBUG
                    if (Debugger.IsAttached)
                    {
                        Debugger.Break();
                    }
#endif
                    throw new InvalidOperationException(string.Format("The field type {0} is unknown so we can't serialize the packet ", definition.Fields[index].FieldType));
                }
            }
        }
 /// <summary>
 /// Create a new serailized packet for deserialization
 /// </summary>
 /// <param name="definition"></param>
 /// <param name="values"></param>
 internal SerializedPacket(PacketDefinition definition, object[] values)
 {
     m_Definition = definition;
     m_Values     = values;
     m_ReadOnly   = true;
 }
 public void Add(string fieldName, Type type)
 {
     Add(fieldName, PacketDefinition.GetSerializableType(type));
 }
 /// <summary>
 /// Create a new serialized packet for serialization
 /// </summary>
 /// <param name="definition"></param>
 internal SerializedPacket(PacketDefinition definition)
 {
     m_Definition = definition;
     m_Values     = new object[definition.Fields.Count];
     m_ReadOnly   = false;
 }
Beispiel #17
0
        /// <summary>
        /// Create a PacketDefinition describing the fields and serialization version information for the
        /// IPacket object passed by the caller.
        /// </summary>
        /// <param name="packet">IPacket object to generate a PacketDefinition for</param>
        /// <returns>PacketDefinition describing fields to be serialized, including nested types</returns>
        public static PacketDefinition CreatePacketDefinition(IPacket packet)
        {
            // These flags are used in the GetMethod call below.  The key flag is DeclaredOnly
            // which is needed because we want to support object hierarchies that implement
            // IPacket at multiple levels.  We accomplish this by called GetPacketDefinition
            // at each level in the hierarchy that implements IPacket.
            const BindingFlags flags = BindingFlags.DeclaredOnly |
                                       BindingFlags.Instance |
                                       BindingFlags.InvokeMethod |
                                       BindingFlags.NonPublic;

            // We iterate from the type we are passed down object hierarchy looking for
            // IPacket implementations.  Then, on the way back up, we link together
            // the m_BasePacket fields to that the PacketDefinition we return includes
            // a description of all the nested types.
            Stack <PacketDefinition> stack = new Stack <PacketDefinition>();
            Type type = packet.GetType();

            // walk down the hierarchy till we get to a base object that no longer implements IPacket
            while (typeof(IPacket).IsAssignableFrom(type))
            {
                // We push one PacketDefinition on the stack for each level in the hierarchy
                PacketDefinition definition;

                // Even though the current type implements IPacket, it may not have a GetPacketDefinition at this level
                MethodInfo method = GetIPacketMethod(type, "GetPacketDefinition", flags, Type.EmptyTypes);
                if (method != null)
                {
                    definition = (PacketDefinition)method.Invoke(packet, new object[0]);
                    definition.m_WriteMethod = GetIPacketMethod(type, "WriteFields", flags, new Type[] { typeof(PacketDefinition), typeof(SerializedPacket) });
                    if (definition.m_WriteMethod == null)
                    {
                        throw new GibraltarSerializationException("The current packet implements part but not all of the IPacket interface.  No Write Method could be found.  Did you implement IPacket explicitly?");
                    }

                    if (definition.CanHaveRequiredPackets)
                    {
                        definition.m_GetRequiredPacketsMethod = GetIPacketMethod(type, "GetRequiredPackets", flags, Type.EmptyTypes);
                        if (definition.m_GetRequiredPacketsMethod == null)
                        {
                            throw new GibraltarSerializationException("The current packet implements part but not all of the IPacket interface.  No GetRequiredPackets Method could be found.  Did you implement IPacket explicitly?");
                        }
                    }
                }
                else
                {
                    // If GetPacketDefinition isn't defined at this level,
                    // push an empty PacketDefinition on the stack as a placeholder
                    definition = new PacketDefinition(type.Name, -1, false);
                }

                // Push the PacketDefinition for this level on the stack
                // then iterate down to the next deeper level in the object hierarchy
                stack.Push(definition);
                type = type.GetTypeInfo().BaseType;
            }

            // At this point the top of the stack contains the mostly deeply nested base type.
            // While there are 2 or more elements on the stack, the deeper of the two
            // should reference the top element as a base type
            while (stack.Count >= 2)
            {
                // Pop off the deepest base type still in the stack
                PacketDefinition basePacket = stack.Pop();

                // The next element is now visible, so let's peek at it
                PacketDefinition derivedPacket = stack.Peek();

                // link the base type with its derived class
                derivedPacket.m_BasePacket = basePacket;
            }

            // At this point there should be exactly one element in the stack
            // which contains the return value for this method.
            PacketDefinition packetDefinition = stack.Pop();

            // Check if this is a DynamicPacket.  If so, it should have a unique dynamic type.
            // If the DynamicType field has not been assigned, assign a unique string.
            IDynamicPacket dynamicPacket = packet as IDynamicPacket;

            if (dynamicPacket != null)
            {
                if (dynamicPacket.DynamicTypeName == null)
                {
                    dynamicPacket.DynamicTypeName = Guid.NewGuid().ToString();
                }
                packetDefinition.m_DynamicTypeName = dynamicPacket.DynamicTypeName;
            }

            // Record whether or not this is a cachable packet.
            packetDefinition.m_IsCachable = packet is ICachedPacket;

            return(packetDefinition);
        }