// Serializes our entry dictionary to a byte array public byte[] Serialize(bool IncludeHeader = true) { // Lock our dictionary to prevent race conditions lock (Entries) { // Begin by creating an empty output buffer byte[] Output = new byte[0]; // Write header to output buffer if specified if (IncludeHeader) { // Add signatures and version Output = Output.AppendBytes(STORAGE_SIGNATURE_A); Output = Output.AppendBytes(STORAGE_SIGNATURE_B); Output = Output.AppendBytes(STORAGE_VERSION); } // Add the number of entries our entry dictionary contains as a varint Output = Output.AppendBytes(PackP2pVarInt(Entries.Count)); // Iterate over and serialize each entry into our output buffer foreach (var Entry in Entries) { // Serialize entry object byte[] ObjectBytes = SerializeObject(Entry.Value); // Append to output buffer Output = Output.AppendInteger((byte)Entry.Key.Length); Output = Output.AppendString(Entry.Key); Output = Output.AppendBytes(ObjectBytes); } // Return output array return(Output); } }
// Serializes an object to a byte array private static byte[] SerializeObject(dynamic Value) { // Get object's type var Type = GetType(Value); byte[] Output = new[] { (byte)Type }; // Serialize object based on type switch (Type) { #region Integers case SerializationType.LONG: Output = Output.AppendInteger((long)Value); break; case SerializationType.INT: Output = Output.AppendInteger((int)Value); break; case SerializationType.SHORT: Output = Output.AppendInteger((short)Value); break; case SerializationType.SBYTE: Output = Output.AppendInteger((sbyte)Value); break; case SerializationType.ULONG: Output = Output.AppendInteger((ulong)Value); break; case SerializationType.UINT: Output = Output.AppendInteger((uint)Value); break; case SerializationType.USHORT: Output = Output.AppendInteger((ushort)Value); break; case SerializationType.BYTE: Output = Output.AppendInteger((byte)Value); break; case SerializationType.DOUBLE: Output = Output.AppendInteger((double)Value); break; case SerializationType.BOOL: Output = Output.AppendInteger((bool)Value ? (byte)0x01 : (byte)0x00); break; #endregion #region Others case SerializationType.STRING: // String size exceeds maximum length, default to nothing if (((string)Value).Length > MAX_STRING_LENGTH) { throw new ArgumentOutOfRangeException("Entry string was too long to serialize"); } // Append string length as a varint Output = Output.AppendBytes(PackP2pVarInt(((string)Value).Length)); // Append string bytes Output = Output.AppendString((string)Value); break; case SerializationType.BYTEARRAY: // Set serialization type to string Output = new byte[] { (byte)SerializationType.STRING }; // Byte size exceeds maximum length, default to nothing if (((byte[])Value).Length > MAX_STRING_LENGTH) { throw new ArgumentOutOfRangeException("Entry byte array was too long to serialize"); } // Append string length as a varint Output = Output.AppendBytes(PackP2pVarInt(((byte[])Value).Length)); // Append string bytes Output = Output.AppendBytes((byte[])Value); break; #endregion #region Not Implemented case SerializationType.OBJECT: // Object is a dictionary Type ValueType = Value.GetType(); if (ValueType.IsGenericType && ValueType.GetGenericTypeDefinition() == typeof(Dictionary <,>)) { // Create a portable storage from dictionary PortableStorage Storage = (Dictionary <string, dynamic>)Value; // Append bytes Output = Output.AppendBytes(Storage.Serialize(false)); break; } else { throw new NotImplementedException(); } case SerializationType.OBJECTARRAY: throw new NotImplementedException(); default: return(new byte[0]); #endregion } // Return resulting output buffer return(Output); }